File indexing completed on 2024-04-28 16:37:52
0001 0002 #include "kmime_headers.h" 0003 #include "kmime_header_parsing.h" 0004 0005 #include <QFile> 0006 #include <QByteArray> 0007 #include <QMap> 0008 #include <iostream> 0009 #include <cstdlib> 0010 #include <cassert> 0011 0012 #include <getopt.h> 0013 0014 using namespace KMime::HeaderParsing; 0015 using namespace std; 0016 0017 static const char *tokenTypes[] = { 0018 "encoded-word", 0019 "atom", 0020 "token", 0021 "quoted-string", 0022 "domain-literal", 0023 "comment", 0024 "phrase", 0025 "dot-atom", 0026 "domain", 0027 "obs-route", 0028 "addr-spec", 0029 "angle-addr", 0030 "mailbox", 0031 "group", 0032 "address", 0033 "address-list", 0034 "parameter-list", 0035 "time", 0036 "date-time" 0037 }; 0038 static const int tokenTypesLen = sizeof tokenTypes / sizeof * tokenTypes; 0039 0040 void usage(const char *msg = nullptr) 0041 { 0042 if (msg && *msg) { 0043 cerr << msg << endl; 0044 } 0045 cerr << 0046 "usage: test_kmime_header_parsing " 0047 "(--token <tokentype>|--headerfield <fieldtype>|--header)\n" 0048 "\n" 0049 " --token <tokentype> interpret input as <tokentype> and output\n" 0050 " (-t) in parsed form. Currently defined values of\n" 0051 " <tokentype> are:" << endl; 0052 for (int i = 0 ; i < tokenTypesLen ; ++i) { 0053 cerr << " " << tokenTypes[i] 0054 << endl; 0055 } 0056 cerr << "\n" 0057 " --headerfield <fieldtype> interpret input as header field <fieldtype>\n" 0058 " (-f) and output in parsed form.\n" 0059 "\n" 0060 " --header parse an RFC2822 header. Iterates over all\n" 0061 " (-h) header fields and outputs them in parsed form." 0062 << endl; 0063 exit(1); 0064 } 0065 0066 ostream &operator<<(ostream &stream, const QString &str) 0067 { 0068 return stream << str.toUtf8().data(); 0069 } 0070 0071 int main(int argc, char *argv[]) 0072 { 0073 if (argc == 1 || argc > 3) { 0074 usage(); 0075 } 0076 // 0077 // process options: 0078 // 0079 enum { None, Token, HeaderField, Header } action = None; 0080 const char *argument = nullptr; 0081 bool withCRLF = false; 0082 while (true) { 0083 int option_index = 0; 0084 static const struct option long_options[] = { 0085 // actions: 0086 { "token", 1, nullptr, 't' }, 0087 { "headerfield", 1, nullptr, 'f' }, 0088 { "header", 0, nullptr, 'h' }, 0089 { "crlf", 0, nullptr, 'c' }, 0090 { nullptr, 0, nullptr, 0 } 0091 }; 0092 0093 int c = getopt_long(argc, argv, "cf:ht:", long_options, &option_index); 0094 if (c == -1) { 0095 break; 0096 } 0097 0098 switch (c) { 0099 case 'c': // --crlf 0100 withCRLF = true; 0101 break; 0102 case 't': // --token <tokentype> 0103 action = Token; 0104 argument = optarg; 0105 break; 0106 case 'f': // --headerfield <headertype> 0107 usage("--headerfield is not yet implemented!"); 0108 break; 0109 case 'h': // --header 0110 usage("--header is not yet implemented!"); 0111 break; 0112 default: 0113 usage("unknown option encountered!"); 0114 } 0115 } 0116 0117 if (optind < argc) { 0118 usage("non-option argument encountered!"); 0119 } 0120 0121 assert(action == Token); 0122 Q_UNUSED(action) // avoid warning in release mode 0123 0124 int index; 0125 for (index = 0 ; index < tokenTypesLen ; ++index) { 0126 if (!qstricmp(tokenTypes[index], argument)) { 0127 break; 0128 } 0129 } 0130 0131 if (index >= tokenTypesLen) { 0132 usage("unknown token type"); 0133 } 0134 0135 //QT5 KComponentData componentData( "test_kmime_header_parsing" ); 0136 0137 QFile stdIn; 0138 stdIn.open(stdin, QIODevice::ReadOnly); 0139 const QByteArray indata = stdIn.readAll(); 0140 stdIn.close(); 0141 QByteArray::ConstIterator iit = indata.begin(); 0142 const QByteArray::ConstIterator iend = indata.end(); 0143 0144 switch (index) { 0145 case 0: { 0146 // encoded-word 0147 QString result; 0148 QByteArray language; 0149 QByteArray charset; 0150 // must have checked for initial '=' already: 0151 bool ok = indata.size() >= 1 && *iit++ == '=' && 0152 parseEncodedWord(iit, iend, result, language, charset); 0153 0154 cout << (ok ? "OK" : "BAD") << endl 0155 << "result:\n" << result << endl 0156 << "language:\n" << language.data() << endl; 0157 } 0158 break; 0159 case 1: { 0160 // atom 0161 cout << "with 8bit: " << endl; 0162 QByteArray result; 0163 bool ok = parseAtom(iit, iend, result, true); 0164 0165 cout << (ok ? "OK" : "BAD") << endl 0166 << "result:\n" << result.constData() 0167 << endl; 0168 0169 cout << "without 8bit: " << endl; 0170 #ifdef COMPILE_FAIL 0171 ok = parseAtom(indata.begin(), iend, result, false); 0172 #else 0173 iit = indata.begin(); 0174 ok = parseAtom(iit, iend, result, false); 0175 #endif 0176 0177 cout << (ok ? "OK" : "BAD") << endl 0178 << "result:\n" << result.constData() 0179 << endl; 0180 } 0181 break; 0182 case 2: { 0183 // token 0184 cout << "with 8bit: " << endl; 0185 QByteArray result; 0186 bool ok = parseToken(iit, iend, result, ParseTokenAllow8Bit); 0187 0188 cout << (ok ? "OK" : "BAD") << endl 0189 << "result:\n" << result.constData() 0190 << endl; 0191 0192 cout << "without 8bit: " << endl; 0193 #ifdef COMPILE_FAIL 0194 ok = parseToken(indata.begin(), iend, result, ParseTokenNoFlag); 0195 #else 0196 iit = indata.begin(); 0197 ok = parseToken(iit, iend, result, ParseTokenNoFlag); 0198 #endif 0199 0200 cout << (ok ? "OK" : "BAD") << endl 0201 << "result:\n" << result.constData() 0202 << endl; 0203 } 0204 break; 0205 case 3: { 0206 // quoted-string 0207 QString result; 0208 // must have checked for initial '"' already: 0209 bool ok = *iit++ == '"' && 0210 parseGenericQuotedString(iit, iend, result, withCRLF, '"', '"'); 0211 0212 cout << (ok ? "OK" : "BAD") << endl 0213 << "result:\n" << result 0214 << endl; 0215 } 0216 break; 0217 case 4: { 0218 // domain-literal 0219 QString result; 0220 // must have checked for initial '[' already: 0221 bool ok = *iit++ == '[' && 0222 parseGenericQuotedString(iit, iend, result, withCRLF, '[', ']'); 0223 0224 cout << (ok ? "OK" : "BAD") << endl 0225 << "result:\n" << result 0226 << endl; 0227 } 0228 break; 0229 case 5: { 0230 // comment 0231 QString result; 0232 // must have checked for initial '(' already: 0233 bool ok = *iit++ == '(' && 0234 parseComment(iit, iend, result, withCRLF, true); 0235 0236 cout << (ok ? "OK" : "BAD") << endl 0237 << "result:\n" << result 0238 << endl; 0239 } 0240 break; 0241 case 6: { 0242 // phrase 0243 QString result; 0244 bool ok = parsePhrase(iit, iend, result, withCRLF); 0245 0246 cout << (ok ? "OK" : "BAD") << endl 0247 << "result:\n" << result 0248 << endl; 0249 } 0250 break; 0251 case 7: { 0252 // dot-atom 0253 QByteArray result; 0254 bool ok = parseDotAtom(iit, iend, result, withCRLF); 0255 0256 cout << (ok ? "OK" : "BAD") << endl 0257 << "result:\n" << result.constData() 0258 << endl; 0259 } 0260 break; 0261 case 8: { 0262 // domain 0263 QString result; 0264 bool ok = parseDomain(iit, iend, result, withCRLF); 0265 0266 cout << (ok ? "OK" : "BAD") << endl 0267 << "result:\n" << result 0268 << endl; 0269 } 0270 break; 0271 case 9: { 0272 // obs-route 0273 QStringList result; 0274 bool ok = parseObsRoute(iit, iend, result, withCRLF, true /*save*/); 0275 0276 cout << (ok ? "OK" : "BAD") << endl 0277 << "result: " << result.count() << " domains:" 0278 << endl; 0279 for (QStringList::ConstIterator it = result.constBegin() ; 0280 it != result.constEnd() ; ++it) { 0281 cout << (*it) << endl; 0282 } 0283 } 0284 break; 0285 case 10: { 0286 // addr-spec 0287 KMime::Types::AddrSpec result; 0288 bool ok = parseAddrSpec(iit, iend, result, withCRLF); 0289 0290 cout << (ok ? "OK" : "BAD") << endl 0291 << "result.localPart:\n" << result.localPart << endl 0292 << "result.domain:\n" << result.domain 0293 << endl; 0294 } 0295 break; 0296 case 11: { 0297 // angle-addr 0298 KMime::Types::AddrSpec result; 0299 bool ok = parseAngleAddr(iit, iend, result, withCRLF); 0300 0301 cout << (ok ? "OK" : "BAD") << endl 0302 << "result.localPart:\n" << result.localPart << endl 0303 << "result.domain:\n" << result.domain 0304 << endl; 0305 } 0306 break; 0307 case 12: { 0308 // mailbox 0309 KMime::Types::Mailbox result; 0310 bool ok = parseMailbox(iit, iend, result, withCRLF); 0311 0312 cout << (ok ? "OK" : "BAD") << endl 0313 << "result.displayName:\n" << result.name() << endl 0314 << "result.addrSpec.localPart:\n" << result.addrSpec().localPart << endl 0315 << "result.addrSpec.domain:\n" << result.addrSpec().domain 0316 << endl; 0317 } 0318 break; 0319 case 13: { 0320 // group 0321 KMime::Types::Address result; 0322 bool ok = parseGroup(iit, iend, result, withCRLF); 0323 0324 cout << (ok ? "OK" : "BAD") << endl 0325 << "result.displayName:\n" << result.displayName 0326 << endl; 0327 int i = 0; 0328 for (const auto &it : std::as_const(result.mailboxList)) { 0329 cout << "result.mailboxList[" << i << "].displayName:\n" 0330 << (it).name() << endl 0331 << "result.mailboxList[" << i << "].addrSpec.localPart:\n" 0332 << (it).addrSpec().localPart << endl 0333 << "result.mailboxList[" << i << "].addrSpec.domain:\n" 0334 << (it).addrSpec().domain << endl; 0335 ++i; 0336 } 0337 } 0338 break; 0339 case 14: { 0340 // address 0341 KMime::Types::Address result; 0342 bool ok = parseAddress(iit, iend, result, withCRLF); 0343 0344 cout << (ok ? "OK" : "BAD") << endl 0345 << "result.displayName:\n" 0346 << endl; 0347 int i = 0; 0348 const auto mailboxList = result.mailboxList; 0349 for (const auto &it : mailboxList) { 0350 cout << "result.mailboxList[" << i << "].displayName:\n" 0351 << (it).name() << endl 0352 << "result.mailboxList[" << i << "].addrSpec.localPart:\n" 0353 << (it).addrSpec().localPart << endl 0354 << "result.mailboxList[" << i << "].addrSpec.domain:\n" 0355 << (it).addrSpec().domain 0356 << endl; 0357 ++i; 0358 } 0359 } 0360 break; 0361 case 15: { 0362 // address-list 0363 KMime::Types::AddressList result; 0364 bool ok = parseAddressList(iit, iend, result, withCRLF); 0365 0366 cout << (ok ? "OK" : "BAD") << endl; 0367 int j = 0; 0368 for (const auto &jt : std::as_const(result)) { 0369 cout << "result[" << j << "].displayName:\n" 0370 << (jt).displayName 0371 << endl; 0372 int i = 0; 0373 const auto mailboxList = (jt).mailboxList; 0374 for (const auto &it : mailboxList) { 0375 cout << "result[" << j << "].mailboxList[" << i << "].displayName:\n" 0376 << (it).name() << endl 0377 << "result[" << j << "].mailboxList[" << i << "].addrSpec.localPart:\n" 0378 << (it).addrSpec().localPart << endl 0379 << "result[" << j << "].mailboxList[" << i << "].addrSpec.domain:\n" 0380 << (it).addrSpec().domain 0381 << endl; 0382 ++i; 0383 } 0384 ++j; 0385 } 0386 } 0387 break; 0388 case 16: { 0389 // parameter-list 0390 QMap<QString, QString> result; 0391 bool ok = parseParameterList(iit, iend, result, withCRLF); 0392 0393 cout << (ok ? "OK" : "BAD") << endl 0394 << "result: " << result.count() << " parameters:" 0395 << endl; 0396 int i = 0; 0397 for (QMap<QString, QString>::Iterator it = result.begin() ; 0398 it != result.end() ; ++it, ++i) { 0399 cout << "result[" << i << "].key() (attribute):\n" 0400 << it.key() << endl 0401 << "result[" << i << "].data() (value):\n" 0402 << it.value() 0403 << endl; 0404 } 0405 } 0406 break; 0407 case 17: { 0408 // time 0409 int hour; 0410 int mins; 0411 int secs; 0412 long int secsEastOfGMT; 0413 bool timeZoneKnown = true; 0414 0415 bool ok = parseTime(iit, iend, hour, mins, secs, 0416 secsEastOfGMT, timeZoneKnown, withCRLF); 0417 0418 cout << (ok ? "OK" : "BAD") << endl 0419 << "result.hour: " << hour << endl 0420 << "result.mins: " << mins << endl 0421 << "result.secs: " << secs << endl 0422 << "result.secsEastOfGMT: " << secsEastOfGMT << endl 0423 << "result.timeZoneKnown: " << timeZoneKnown 0424 << endl; 0425 } 0426 break; 0427 case 18: { 0428 // date-time 0429 QDateTime result; 0430 bool ok = parseDateTime(iit, iend, result, withCRLF); 0431 time_t timet = result.toSecsSinceEpoch(); 0432 0433 cout << (ok ? "OK" : "BAD") << endl 0434 << "result.time (in local timezone): " << ctime(&timet) 0435 << "result.secsEastOfGMT: " << result.offsetFromUtc() 0436 << " (" << result.offsetFromUtc() / 60 << "mins)" 0437 << endl; 0438 } 0439 break; 0440 default: 0441 assert(0); 0442 } 0443 }