File indexing completed on 2024-04-21 05:18:09
0001 /* 0002 SPDX-FileCopyrightText: 2006 Volker Krause <vkrause@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "headertest.h" 0008 0009 #include <QTest> 0010 0011 #include "kmime_headers.h" 0012 0013 using namespace KMime; 0014 using namespace KMime::Headers; 0015 using namespace KMime::Headers::Generics; 0016 0017 // the following test cases are taken from KDE mailinglists, bug reports, RFC 2045, 0018 // RFC 2183 and RFC 2822, Appendix A 0019 0020 QTEST_MAIN(HeaderTest) 0021 0022 void HeaderTest::testIdentHeader() 0023 { 0024 // empty header 0025 auto h = new Headers::Generics::Ident(); 0026 QVERIFY(h->isEmpty()); 0027 0028 // parse single identifier 0029 h->from7BitString(QByteArray("<1162746587.784559.5038.nullmailer@svn.kde.org>")); 0030 QCOMPARE(h->identifiers().count(), 1); 0031 QCOMPARE(h->identifiers().first(), QByteArray("1162746587.784559.5038.nullmailer@svn.kde.org")); 0032 QCOMPARE(h->asUnicodeString(), QString::fromLatin1("<1162746587.784559.5038.nullmailer@svn.kde.org>")); 0033 QVERIFY(!h->isEmpty()); 0034 0035 // clearing a header 0036 h->clear(); 0037 QVERIFY(h->isEmpty()); 0038 QVERIFY(h->identifiers().isEmpty()); 0039 delete h; 0040 0041 // parse multiple identifiers 0042 h = new Headers::Generics::Ident(); 0043 h->from7BitString(QByteArray("<1234@local.machine.example> <3456@example.net>")); 0044 QCOMPARE(h->identifiers().count(), 2); 0045 auto ids = h->identifiers(); 0046 QCOMPARE(ids.takeFirst(), QByteArray("1234@local.machine.example")); 0047 QCOMPARE(ids.first(), QByteArray("3456@example.net")); 0048 delete h; 0049 0050 // parse multiple identifiers with folded headers 0051 h = new Headers::Generics::Ident(); 0052 h->from7BitString(QByteArray("<1234@local.machine.example>\n <3456@example.net>")); 0053 QCOMPARE(h->identifiers().count(), 2); 0054 ids = h->identifiers(); 0055 QCOMPARE(ids.takeFirst(), QByteArray("1234@local.machine.example")); 0056 QCOMPARE(ids.first(), QByteArray("3456@example.net")); 0057 0058 // appending of new identifiers (with and without angle-brackets) 0059 h->appendIdentifier("<abcd.1234@local.machine.tld>"); 0060 h->appendIdentifier("78910@example.net"); 0061 QCOMPARE(h->identifiers().count(), 4); 0062 0063 // assemble the final header 0064 QCOMPARE(h->as7BitString(false), QByteArray("<1234@local.machine.example> <3456@example.net> <abcd.1234@local.machine.tld> <78910@example.net>")); 0065 delete h; 0066 0067 // parsing of ident with literal domain 0068 h = new Headers::Generics::Ident(); 0069 const QByteArray ident = QByteArray("<O55F3Y9E5MmKFwBN@[127.0.0.1]>"); 0070 h->appendIdentifier(ident); 0071 QEXPECT_FAIL("", "Parsing strips square brackets.", Continue); 0072 QCOMPARE(h->as7BitString(false), QByteArray(ident)); 0073 delete h; 0074 } 0075 0076 void HeaderTest::testAddressListHeader() 0077 { 0078 // empty header 0079 auto h = new Headers::Generics::AddressList(); 0080 QVERIFY(h->isEmpty()); 0081 0082 // parse single simple address 0083 h->from7BitString("joe@where.test"); 0084 QVERIFY(!h->isEmpty()); 0085 QCOMPARE(h->addresses().count(), 1); 0086 QCOMPARE(h->addresses().first(), QByteArray("joe@where.test")); 0087 QCOMPARE(h->displayNames().count(), 1); 0088 QCOMPARE(h->displayNames().first(), QLatin1StringView("joe@where.test")); 0089 QCOMPARE(h->displayString(), QLatin1StringView("joe@where.test")); 0090 QCOMPARE(h->asUnicodeString(), QLatin1StringView("joe@where.test")); 0091 0092 // clearing a header 0093 h->clear(); 0094 QVERIFY(h->isEmpty()); 0095 delete h; 0096 0097 // parsing and re-assembling a single address with display name 0098 h = new Headers::Generics::AddressList(); 0099 h->from7BitString("Pete <pete@silly.example>"); 0100 QCOMPARE(h->addresses().count(), 1); 0101 QCOMPARE(h->addresses().first(), QByteArray("pete@silly.example")); 0102 QCOMPARE(h->displayNames().first(), QLatin1StringView("Pete")); 0103 QCOMPARE(h->displayString(), QLatin1StringView("Pete")); 0104 QCOMPARE(h->asUnicodeString(), 0105 QLatin1StringView("Pete <pete@silly.example>")); 0106 QCOMPARE(h->as7BitString(false), QByteArray("Pete <pete@silly.example>")); 0107 delete h; 0108 0109 // parsing a single address with legacy comment style display name 0110 h = new Headers::Generics::AddressList(); 0111 h->from7BitString("jdoe@machine.example (John Doe)"); 0112 QCOMPARE(h->addresses().count(), 1); 0113 QCOMPARE(h->addresses().first(), QByteArray("jdoe@machine.example")); 0114 QCOMPARE(h->displayNames().first(), QLatin1StringView("John Doe")); 0115 QCOMPARE(h->asUnicodeString(), 0116 QLatin1StringView("John Doe <jdoe@machine.example>")); 0117 delete h; 0118 0119 // parsing and re-assembling list of different addresses 0120 h = new Headers::Generics::AddressList(); 0121 h->from7BitString("Mary Smith <mary@x.test>, jdoe@example.org, Who? <one@y.test>"); 0122 QCOMPARE(h->addresses().count(), 3); 0123 QStringList names = h->displayNames(); 0124 QCOMPARE(names.takeFirst(), QLatin1StringView("Mary Smith")); 0125 QCOMPARE(names.takeFirst(), QLatin1StringView("jdoe@example.org")); 0126 QCOMPARE(names.takeFirst(), QLatin1StringView("Who?")); 0127 QCOMPARE(h->displayString(), 0128 QLatin1StringView("Mary Smith, jdoe@example.org, Who?")); 0129 QCOMPARE(h->as7BitString(false), QByteArray("Mary Smith <mary@x.test>, jdoe@example.org, Who? <one@y.test>")); 0130 delete h; 0131 0132 // same again with some interesting quoting 0133 h = new Headers::Generics::AddressList(); 0134 h->from7BitString(R"("Joe Q. Public" <john.q.public@example.com>, <boss@nil.test>, "Giant; \"Big\" Box" <sysservices@example.net>)"); 0135 QCOMPARE(h->addresses().count(), 3); 0136 names = h->displayNames(); 0137 QCOMPARE(names.takeFirst(), QLatin1StringView("Joe Q. Public")); 0138 QCOMPARE(names.takeFirst(), QLatin1StringView("boss@nil.test")); 0139 QCOMPARE(names.takeFirst(), QLatin1StringView("Giant; \"Big\" Box")); 0140 QCOMPARE(h->as7BitString(false), QByteArray("\"Joe Q. Public\" <john.q.public@example.com>, boss@nil.test, \"Giant; \\\"Big\\\" Box\" <sysservices@example.net>")); 0141 delete h; 0142 0143 // a display name with non-latin1 content 0144 h = new Headers::Generics::AddressList(); 0145 h->from7BitString("Ingo =?iso-8859-15?q?Kl=F6cker?= <kloecker@kde.org>"); 0146 QCOMPARE(h->addresses().count(), 1); 0147 QCOMPARE(h->addresses().first(), QByteArray("kloecker@kde.org")); 0148 QCOMPARE(h->displayNames().first(), QString::fromUtf8("Ingo Klöcker")); 0149 QCOMPARE(h->asUnicodeString(), QString::fromUtf8("Ingo Klöcker <kloecker@kde.org>")); 0150 QCOMPARE(h->as7BitString(false), QByteArray("Ingo =?ISO-8859-1?Q?Kl=F6cker?= <kloecker@kde.org>")); 0151 delete h; 0152 0153 0154 // a display name with non-latin1 content in both name components 0155 h = new Headers::Generics::AddressList(); 0156 const QString testAddress = QString::fromUtf8("Ingö Klöcker <kloecker@kde.org>"); 0157 h->fromUnicodeString(testAddress, "utf-8"); 0158 QCOMPARE(h->asUnicodeString(), testAddress); 0159 delete h; 0160 0161 { 0162 // a display name with non-latin1 content in both name components 0163 h = new Headers::Generics::AddressList(); 0164 const QString testAddress = QString::fromUtf8("\"Rüedi-Huser, Thomas\" <test@test.org>"); 0165 h->fromUnicodeString(testAddress, "utf-8"); 0166 QEXPECT_FAIL("", "AddressList::prettyAddresses() does not quote the mailbox correctly", Continue); 0167 QCOMPARE(h->asUnicodeString(), testAddress); 0168 delete h; 0169 } 0170 0171 // again, this time legacy style 0172 h = new Headers::Generics::AddressList(); 0173 h->from7BitString("kloecker@kde.org (Ingo =?iso-8859-15?q?Kl=F6cker?=)"); 0174 QCOMPARE(h->addresses().count(), 1); 0175 QCOMPARE(h->addresses().first(), QByteArray("kloecker@kde.org")); 0176 QCOMPARE(h->displayNames().first(), QString::fromUtf8("Ingo Klöcker")); 0177 delete h; 0178 0179 // parsing a empty group 0180 h = new Headers::Generics::AddressList(); 0181 h->from7BitString("Undisclosed recipients:;"); 0182 QCOMPARE(h->addresses().count(), 0); 0183 delete h; 0184 0185 // parsing and re-assembling a address list with a group 0186 h = new Headers::Generics::AddressList(); 0187 h->from7BitString("A Group:Chris Jones <c@a.test>,joe@where.test,John <jdoe@one.test>;"); 0188 QCOMPARE(h->addresses().count(), 3); 0189 names = h->displayNames(); 0190 QCOMPARE(names.takeFirst(), QLatin1StringView("Chris Jones")); 0191 QCOMPARE(names.takeFirst(), QLatin1StringView("joe@where.test")); 0192 QCOMPARE(names.takeFirst(), QLatin1StringView("John")); 0193 QCOMPARE(h->as7BitString(false), QByteArray("Chris Jones <c@a.test>, joe@where.test, John <jdoe@one.test>")); 0194 delete h; 0195 0196 // modifying a header 0197 h = new Headers::Generics::AddressList(); 0198 h->from7BitString("John <jdoe@one.test>"); 0199 h->addAddress("<kloecker@kde.org>", QString::fromUtf8("Ingo Klöcker")); 0200 h->addAddress("c@a.test"); 0201 QCOMPARE(h->addresses().count(), 3); 0202 QCOMPARE(h->asUnicodeString(), QString::fromUtf8("John <jdoe@one.test>, Ingo Klöcker <kloecker@kde.org>, c@a.test")); 0203 QCOMPARE(h->as7BitString(false), QByteArray("John <jdoe@one.test>, Ingo =?ISO-8859-1?Q?Kl=F6cker?= <kloecker@kde.org>, c@a.test")); 0204 delete h; 0205 0206 // parsing from utf-8 0207 h = new Headers::Generics::AddressList(); 0208 h->fromUnicodeString(QString::fromUtf8("Ingo Klöcker <kloecker@kde.org>"), "utf-8"); 0209 QCOMPARE(h->addresses().count(), 1); 0210 QCOMPARE(h->addresses().first(), QByteArray("kloecker@kde.org")); 0211 QCOMPARE(h->displayNames().first(), QString::fromUtf8("Ingo Klöcker")); 0212 delete h; 0213 0214 // based on bug #137033, a header broken in various ways: ';' as list separator, 0215 // unquoted '.' in display name 0216 h = new Headers::Generics::AddressList(); 0217 h->from7BitString("Vice@censored.serverkompetenz.net,\n President@mail2.censored.net;\"Int\\\\\\\\\\\\\\\\\\\\'l\" Lotto Commission. <censored@yahoo.fr>"); 0218 QCOMPARE(h->addresses().count(), 3); 0219 names = h->displayNames(); 0220 QCOMPARE(names.takeFirst(), 0221 QLatin1StringView("Vice@censored.serverkompetenz.net")); 0222 QCOMPARE(names.takeFirst(), 0223 QLatin1StringView("President@mail2.censored.net")); 0224 // there is an wrong ' ' after the name, but since the header is completely 0225 // broken we can be happy it parses at all... 0226 QCOMPARE(names.takeFirst(), 0227 QLatin1StringView("Int\\\\\\\\\\'l Lotto Commission. ")); 0228 auto addrs = h->addresses(); 0229 QCOMPARE(addrs.takeFirst(), QByteArray("Vice@censored.serverkompetenz.net")); 0230 QCOMPARE(addrs.takeFirst(), QByteArray("President@mail2.censored.net")); 0231 QCOMPARE(addrs.takeFirst(), QByteArray("censored@yahoo.fr")); 0232 delete h; 0233 0234 // based on bug #102010, a display name containing '<' 0235 h = new Headers::Generics::AddressList(); 0236 h->from7BitString("\"|<onrad\" <censored@censored.dy>"); 0237 QCOMPARE(h->addresses().count(), 1); 0238 QCOMPARE(h->addresses().first(), QByteArray("censored@censored.dy")); 0239 QCOMPARE(h->displayNames().first(), QLatin1StringView("|<onrad")); 0240 QCOMPARE(h->as7BitString(false), QByteArray("\"|<onrad\" <censored@censored.dy>")); 0241 delete h; 0242 0243 // based on bug #93790 (legacy display name with nested comments) 0244 h = new Headers::Generics::AddressList(); 0245 h->from7BitString("first.name@domain.tld (first name (nickname))"); 0246 QCOMPARE(h->displayNames().count(), 1); 0247 QCOMPARE(h->displayNames().first(), 0248 QLatin1StringView("first name (nickname)")); 0249 QCOMPARE(h->as7BitString(false), QByteArray("\"first name (nickname)\" <first.name@domain.tld>")); 0250 delete h; 0251 0252 // rfc 2047 encoding in quoted name (it is not allowed there as per the RFC, but it happens) 0253 // some software == current KMail (v1.12.90) ... 0254 h = new Headers::Generics::AddressList(); 0255 h->from7BitString(QByteArray("\"Ingo =?iso-8859-15?q?Kl=F6cker?=\" <kloecker@kde.org>")); 0256 QCOMPARE(h->mailboxes().count(), 1); 0257 QCOMPARE(h->asUnicodeString(), QString::fromUtf8("Ingo Klöcker <kloecker@kde.org>")); 0258 delete h; 0259 0260 // corner case of almost-rfc2047 encoded string in quoted string but not 0261 h = new Headers::Generics::AddressList(); 0262 h->from7BitString("\"Some =Use ?r\" <user@example.com>"); 0263 QCOMPARE(h->mailboxes().count(), 1); 0264 QCOMPARE(h->as7BitString(false), QByteArray("\"Some =Use ?r\" <user@example.com>")); 0265 delete h; 0266 0267 // corner case of almost-rfc2047 encoded string in quoted string but not 0268 h = new Headers::Generics::AddressList(); 0269 h->from7BitString("\"Some ?=U=?se =?r\" <user@example.com>"); 0270 QCOMPARE(h->mailboxes().count(), 1); 0271 QCOMPARE(h->as7BitString(false), QByteArray("\"Some ?=U=?se =?r\" <user@example.com>")); 0272 delete h; 0273 0274 // based on bug #139477, trailing '.' in domain name (RFC 3696, section 2 - https://tools.ietf.org/html/rfc3696#page-4) 0275 h = new Headers::Generics::AddressList(); 0276 h->from7BitString("joe@where.test."); 0277 QVERIFY(!h->isEmpty()); 0278 QCOMPARE(h->addresses().count(), 1); 0279 QCOMPARE(h->addresses().first(), QByteArray("joe@where.test.")); 0280 QCOMPARE(h->displayNames().count(), 1); 0281 QCOMPARE(h->displayNames().first(), QLatin1StringView("joe@where.test.")); 0282 QCOMPARE(h->asUnicodeString(), QLatin1StringView("joe@where.test.")); 0283 delete h; 0284 0285 h = new Headers::Generics::AddressList(); 0286 h->from7BitString("Mary Smith <mary@x.test>, jdoe@example.org., Who? <one@y.test>"); 0287 QCOMPARE(h->addresses().count(), 3); 0288 names = h->displayNames(); 0289 QCOMPARE(names.takeFirst(), QLatin1StringView("Mary Smith")); 0290 QCOMPARE(names.takeFirst(), QLatin1StringView("jdoe@example.org.")); 0291 QCOMPARE(names.takeFirst(), QLatin1StringView("Who?")); 0292 QCOMPARE(h->as7BitString(false), QByteArray("Mary Smith <mary@x.test>, jdoe@example.org., Who? <one@y.test>")); 0293 delete h; 0294 0295 //Bug 421251 0296 // a display name with non-latin1 content 0297 h = new Headers::Generics::AddressList(); 0298 h->from7BitString("=?iso-8859-1?Q?=22I=F1igo_Salvador_Azurmendi=22?= <xalba@clientes.euskaltel.es>"); 0299 QCOMPARE(h->addresses().count(), 1); 0300 QCOMPARE(h->addresses().first(), QByteArray("xalba@clientes.euskaltel.es")); 0301 QCOMPARE(h->displayNames().first(), QString::fromUtf8("I\u00F1igo Salvador Azurmendi")); 0302 QCOMPARE(h->asUnicodeString(), QString::fromUtf8("I\u00F1igo Salvador Azurmendi <xalba@clientes.euskaltel.es>")); 0303 QCOMPARE(h->as7BitString(false), QByteArray("=?ISO-8859-1?Q?I=F1igo?= Salvador Azurmendi <xalba@clientes.euskaltel.es>")); 0304 delete h; 0305 } 0306 0307 void HeaderTest::testMailboxListHeader() 0308 { 0309 // empty header 0310 auto h = new Headers::Generics::MailboxList(); 0311 QVERIFY(h->isEmpty()); 0312 0313 // parse single simple address 0314 h->from7BitString("joe_smith@where.test"); 0315 QVERIFY(!h->isEmpty()); 0316 QCOMPARE(h->mailboxes().count(), 1); 0317 QCOMPARE(h->addresses().count(), 1); 0318 QCOMPARE(h->addresses().first(), QByteArray("joe_smith@where.test")); 0319 QCOMPARE(h->displayNames().count(), 1); 0320 QCOMPARE(h->displayNames().first(), 0321 QLatin1StringView("joe_smith@where.test")); 0322 QCOMPARE(h->displayString(), QLatin1StringView("joe_smith@where.test")); 0323 QCOMPARE(h->asUnicodeString(), QLatin1StringView("joe_smith@where.test")); 0324 0325 // https://bugzilla.novell.com/show_bug.cgi?id=421057 (but apparently this was not the cause of the bug) 0326 h->from7BitString("fr...@ce.sco (Francesco)"); 0327 QVERIFY(!h->isEmpty()); 0328 QCOMPARE(h->mailboxes().count(), 1); 0329 QCOMPARE(h->displayString(), QLatin1StringView("Francesco")); 0330 QCOMPARE(h->asUnicodeString(), 0331 QLatin1StringView("Francesco <fr...@ce.sco>")); 0332 0333 delete h; 0334 } 0335 0336 void HeaderTest::testSingleMailboxHeader() 0337 { 0338 // empty header 0339 auto h = new Headers::Generics::SingleMailbox(); 0340 QVERIFY(h->isEmpty()); 0341 0342 // parse single simple address 0343 h->from7BitString("joe_smith@where.test"); 0344 QVERIFY(!h->isEmpty()); 0345 QCOMPARE(h->addresses().count(), 1); 0346 QCOMPARE(h->addresses().first(), QByteArray("joe_smith@where.test")); 0347 QCOMPARE(h->displayNames().count(), 1); 0348 QCOMPARE(h->displayNames().first(), 0349 QLatin1StringView("joe_smith@where.test")); 0350 QCOMPARE(h->asUnicodeString(), QLatin1StringView("joe_smith@where.test")); 0351 0352 // parse single simple address with display name 0353 h->from7BitString("John Smith <joe_smith@where.test>"); 0354 QVERIFY(!h->isEmpty()); 0355 QCOMPARE(h->addresses().count(), 1); 0356 QCOMPARE(h->addresses().first(), QByteArray("joe_smith@where.test")); 0357 QCOMPARE(h->displayNames().count(), 1); 0358 QCOMPARE(h->displayNames().first(), QLatin1StringView("John Smith")); 0359 QCOMPARE(h->asUnicodeString(), 0360 QLatin1StringView("John Smith <joe_smith@where.test>")); 0361 QCOMPARE(h->mailboxes().first().prettyAddress(Types::Mailbox::QuoteAlways), 0362 QLatin1StringView("\"John Smith\" <joe_smith@where.test>")); 0363 0364 // parse quoted display name with \ in it 0365 h->from7BitString(R"("Lastname\, Firstname" <firstname.lastname@example.com>)"); 0366 QVERIFY(!h->isEmpty()); 0367 QCOMPARE(h->addresses().count(), 1); 0368 QCOMPARE(h->addresses().first(), QByteArray("firstname.lastname@example.com")); 0369 QCOMPARE(h->displayNames().count(), 1); 0370 QCOMPARE(h->displayNames().first(), 0371 QLatin1StringView("Lastname, Firstname")); 0372 QCOMPARE(h->asUnicodeString().toLatin1().data(), 0373 "Lastname, Firstname <firstname.lastname@example.com>"); 0374 QCOMPARE(h->mailboxes().first().prettyAddress().toLatin1().data(), 0375 "Lastname, Firstname <firstname.lastname@example.com>"); 0376 QCOMPARE(h->mailboxes().first().prettyAddress(Types::Mailbox::QuoteWhenNecessary).toLatin1().data(), 0377 "\"Lastname, Firstname\" <firstname.lastname@example.com>"); 0378 0379 // parse quoted display name with " in it 0380 h->from7BitString(R"("John \"the guru\" Smith" <john.smith@mail.domain>)"); 0381 QVERIFY(!h->isEmpty()); 0382 QCOMPARE(h->addresses().count(), 1); 0383 QCOMPARE(h->addresses().first().data(), "john.smith@mail.domain"); 0384 QCOMPARE(h->displayNames().first().toLatin1().data(), "John \"the guru\" Smith"); 0385 QCOMPARE(h->mailboxes().first().prettyAddress(Types::Mailbox::QuoteWhenNecessary).toLatin1().data(), 0386 "\"John \\\"the guru\\\" Smith\" <john.smith@mail.domain>"); 0387 QCOMPARE(h->as7BitString(false).data(), 0388 "\"John \\\"the guru\\\" Smith\" <john.smith@mail.domain>"); 0389 0390 // The following tests are for broken clients that by accident add quotes inside of encoded words that enclose the 0391 // display name. We strip away those quotes, which is not strictly correct, but much nicer. 0392 h->from7BitString("=?iso-8859-1?Q?=22Andre_Woebbeking=22?= <woebbeking@example.com>"); 0393 QVERIFY(!h->isEmpty()); 0394 QCOMPARE(h->addresses().count(), 1); 0395 QCOMPARE(h->mailboxes().first().name().toLatin1().data(), "Andre Woebbeking"); 0396 h->from7BitString("=?iso-8859-1?Q?=22Andre_=22Mr._Tall=22_Woebbeking=22?= <woebbeking@example.com>"); 0397 QVERIFY(!h->isEmpty()); 0398 QCOMPARE(h->addresses().count(), 1); 0399 QCOMPARE(h->mailboxes().first().name().toLatin1().data(), "Andre \"Mr. Tall\" Woebbeking"); 0400 h->from7BitString("=?iso-8859-1?Q?=22Andre_=22?= =?iso-8859-1?Q?Mr._Tall?= =?iso-8859-1?Q?=22_Woebbeking=22?= <woebbeking@example.com>"); 0401 QVERIFY(!h->isEmpty()); 0402 QCOMPARE(h->addresses().count(), 1); 0403 QCOMPARE(h->mailboxes().first().name().toLatin1().data(), "Andre \"Mr. Tall\" Woebbeking"); 0404 0405 delete h; 0406 } 0407 0408 void HeaderTest::testMailCopiesToHeader() 0409 { 0410 Headers::MailCopiesTo *h; 0411 0412 // empty header 0413 h = new Headers::MailCopiesTo(); 0414 QVERIFY(h->isEmpty()); 0415 QVERIFY(!h->alwaysCopy()); 0416 QVERIFY(!h->neverCopy()); 0417 0418 // set to always copy to poster 0419 h->setAlwaysCopy(); 0420 QVERIFY(!h->isEmpty()); 0421 QVERIFY(h->alwaysCopy()); 0422 QVERIFY(!h->neverCopy()); 0423 QCOMPARE(h->as7BitString(), QByteArray("Mail-Copies-To: poster")); 0424 0425 // set to never copy 0426 h->setNeverCopy(); 0427 QVERIFY(!h->isEmpty()); 0428 QVERIFY(!h->alwaysCopy()); 0429 QVERIFY(h->neverCopy()); 0430 QCOMPARE(h->as7BitString(), QByteArray("Mail-Copies-To: nobody")); 0431 0432 // clear header 0433 h->clear(); 0434 QVERIFY(h->isEmpty()); 0435 delete h; 0436 0437 // parse copy to poster 0438 h = new MailCopiesTo; 0439 h->from7BitString("always"); 0440 QVERIFY(h->addresses().isEmpty()); 0441 QVERIFY(!h->isEmpty()); 0442 QVERIFY(h->alwaysCopy()); 0443 delete h; 0444 0445 h = new MailCopiesTo; 0446 h->from7BitString("poster"); 0447 QVERIFY(h->addresses().isEmpty()); 0448 QVERIFY(!h->isEmpty()); 0449 QVERIFY(h->alwaysCopy()); 0450 delete h; 0451 0452 // parse never copy 0453 h = new MailCopiesTo; 0454 h->from7BitString("never"); 0455 QVERIFY(h->addresses().isEmpty()); 0456 QVERIFY(!h->isEmpty()); 0457 QVERIFY(h->neverCopy()); 0458 delete h; 0459 0460 h = new MailCopiesTo; 0461 h->from7BitString("nobody"); 0462 QVERIFY(h->addresses().isEmpty()); 0463 QVERIFY(!h->isEmpty()); 0464 QVERIFY(h->neverCopy()); 0465 delete h; 0466 0467 // parsing is case-insensitive 0468 h = new MailCopiesTo; 0469 h->from7BitString("AlWays"); 0470 QVERIFY(h->alwaysCopy()); 0471 delete h; 0472 0473 // parse address 0474 h = new MailCopiesTo; 0475 h->from7BitString("vkrause@kde.org"); 0476 QVERIFY(!h->addresses().isEmpty()); 0477 QVERIFY(h->alwaysCopy()); 0478 QVERIFY(!h->neverCopy()); 0479 QCOMPARE(h->as7BitString(), QByteArray("Mail-Copies-To: vkrause@kde.org")); 0480 delete h; 0481 } 0482 0483 void HeaderTest::testParametrizedHeader() 0484 { 0485 Parametrized *h; 0486 0487 // empty header 0488 h = new Parametrized(); 0489 QVERIFY(h->isEmpty()); 0490 QVERIFY(!h->hasParameter(QLatin1StringView("foo"))); 0491 0492 // add a parameter 0493 h->setParameter(QStringLiteral("filename"), QStringLiteral("bla.jpg")); 0494 QVERIFY(!h->isEmpty()); 0495 QVERIFY(h->hasParameter(QLatin1StringView("filename"))); 0496 QVERIFY(h->hasParameter(QLatin1StringView("FiLeNaMe"))); 0497 QVERIFY(!h->hasParameter(QLatin1StringView("bla.jpg"))); 0498 QCOMPARE(h->parameter(QLatin1StringView("filename")), 0499 QLatin1StringView("bla.jpg")); 0500 QCOMPARE(h->as7BitString(false), QByteArray("filename=\"bla.jpg\"")); 0501 0502 // clear again 0503 h->clear(); 0504 QVERIFY(h->isEmpty()); 0505 delete h; 0506 0507 // parse a parameter list 0508 h = new Parametrized; 0509 h->from7BitString("filename=genome.jpeg;\n modification-date=\"Wed, 12 Feb 1997 16:29:51 -0500\""); 0510 QCOMPARE(h->parameter(QLatin1StringView("filename")), 0511 QLatin1StringView("genome.jpeg")); 0512 QCOMPARE(h->parameter(QLatin1StringView("modification-date")), 0513 QLatin1StringView("Wed, 12 Feb 1997 16:29:51 -0500")); 0514 QCOMPARE(h->as7BitString(false), QByteArray("filename=\"genome.jpeg\"; modification-date=\"Wed, 12 Feb 1997 16:29:51 -0500\"")); 0515 delete h; 0516 0517 // quoting of whitespaces in parameter value 0518 h = new Parametrized(); 0519 h->setParameter(QLatin1StringView("boundary"), 0520 QLatin1StringView("simple boundary")); 0521 QCOMPARE(h->as7BitString(false), QByteArray("boundary=\"simple boundary\"")); 0522 delete h; 0523 0524 // TODO: test RFC 2047 encoded values 0525 // TODO: test case-insensitive key-names 0526 } 0527 0528 void HeaderTest::testContentDispositionHeader() 0529 { 0530 ContentDisposition *h; 0531 0532 // empty header 0533 h = new ContentDisposition(); 0534 QVERIFY(h->isEmpty()); 0535 0536 // set some values 0537 h->setFilename(QLatin1StringView("test.jpg")); 0538 QVERIFY(h->isEmpty()); 0539 QVERIFY(h->as7BitString(false).isEmpty()); 0540 h->setDisposition(CDattachment); 0541 QVERIFY(!h->isEmpty()); 0542 QCOMPARE(h->as7BitString(false), QByteArray("attachment; filename=\"test.jpg\"")); 0543 delete h; 0544 0545 // parse parameter-less header 0546 h = new ContentDisposition; 0547 h->from7BitString("inline"); 0548 QCOMPARE(h->disposition(), CDinline); 0549 QVERIFY(h->filename().isEmpty()); 0550 QCOMPARE(h->as7BitString(true), QByteArray("Content-Disposition: inline")); 0551 delete h; 0552 0553 // parse header with parameter 0554 h = new ContentDisposition; 0555 h->from7BitString("attachment; filename=genome.jpeg;\n modification-date=\"Wed, 12 Feb 1997 16:29:51 -0500\";"); 0556 QCOMPARE(h->disposition(), CDattachment); 0557 QCOMPARE(h->filename(), QLatin1StringView("genome.jpeg")); 0558 delete h; 0559 0560 // TODO: test for case-insensitive disposition value 0561 0562 // Bug 362650 0563 h = new ContentDisposition; 0564 h->from7BitString("attachment;\n" 0565 "filename*0*=UTF-8''%D0%AD%D1%82%D0%BE%D0%92%D0%BB%D0%BE%D0%B6%D0%B5%D0%BD;" 0566 "filename*1*=%D0%B8%D0%B5%D0%A1%D0%94%D0%BB%D0%B8%D0%BD%D0%BD%D1%8B%D0%BC;" 0567 "filename*2*=%D0%98%D0%BC%D0%B5%D0%BC%D0%A4%D0%B0%D0%B9%D0%BB%D0%B0%D0%A1;" 0568 "filename*3*=%D0%BE%D0%B2%D1%81%D0%B5%D0%BC%D0%91%D0%B5%D0%B7%D0%9F%D1%80;" 0569 "filename*4*=%D0%BE%D0%B1%D0%B5%D0%BB%D0%BE%D0%B2%D0%98%D0%95%D1%89%D1%91;" 0570 "filename*5*=%D0%A0%D0%B0%D0%B7%D0%AD%D1%82%D0%BE%D0%92%D0%BB%D0%BE%D0%B6;" 0571 "filename*6*=%D0%B5%D0%BD%D0%B8%D0%B5%D0%A1%D0%94%D0%BB%D0%B8%D0%BD%D0%BD;" 0572 "filename*7*=%D1%8B%D0%BC%D0%98%D0%BC%D0%B5%D0%BC%D0%A4%D0%B0%D0%B9%D0%BB;" 0573 "filename*8*=%D0%B0%D0%A1%D0%BE%D0%B2%D1%81%D0%B5%D0%BC%D0%91%D0%B5%D0%B7;" 0574 "filename*9*=%D0%9F%D1%80%D0%BE%D0%B1%D0%B5%D0%BB%D0%BE%D0%B2%2E%74%78%74"); 0575 QCOMPARE(h->disposition(), CDattachment); 0576 QCOMPARE(h->filename(), QString::fromUtf8("ЭтоВложениеСДлиннымИмемФайлаСовсемБезПробеловИЕщёРазЭтоВложениеСДлиннымИмемФайлаСовсемБезПробелов.txt")); 0577 delete h; 0578 0579 h = new ContentDisposition; 0580 h->from7BitString("attachment; filename*=UTF-8''%D0%AD%D1%82%D0%BE%D0%92%D0%BB%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5%D0%A1%D0%94%D0%BB%D0%B8%D0%BD%D0%BD%D1%8B%D0%BC%D0%98%D0%BC%D0%B5%D0%BC%D0%A4%D0%B0%D0%B9%D0%BB%D0%B0%D0%A1%D0%BE%D0%B2%D1%81%D0%B5%D0%BC%D0%91%D0%B5%D0%B7%D0%9F%D1%80%D0%BE%D0%B1%D0%B5%D0%BB%D0%BE%D0%B2%D0%98%D0%95%D1%89%D1%91%D0%A0%D0%B0%D0%B7%D0%AD%D1%82%D0%BE%D0%92%D0%BB%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5%D0%A1%D0%94%D0%BB%D0%B8%D0%BD%D0%BD%D1%8B%D0%BC%D0%98%D0%BC%D0%B5%D0%BC%D0%A4%D0%B0%D0%B9%D0%BB%D0%B0%D0%A1%D0%BE%D0%B2%D1%81%D0%B5%D0%BC%D0%91%D0%B5%D0%B7%D0%9F%D1%80%D0%BE%D0%B1%D0%B5%D0%BB%D0%BE%D0%B2%2Etxt"); 0581 QCOMPARE(h->disposition(), CDattachment); 0582 QCOMPARE(h->filename(), QString::fromUtf8("ЭтоВложениеСДлиннымИмемФайлаСовсемБезПробеловИЕщёРазЭтоВложениеСДлиннымИмемФайлаСовсемБезПробелов.txt")); 0583 delete h; 0584 } 0585 0586 void HeaderTest::testContentTypeHeader() 0587 { 0588 ContentType *h; 0589 0590 //Bug 362650 (test is without space => ok) 0591 h = new ContentType; 0592 h->from7BitString("text/plain;\n name=\"=?UTF-8?B?0K3RgtC+0JLQu9C+0LbQtdC90LjQtdCh0JTQu9C40L3QvdGL0LzQmNC8?=" 0593 "=?UTF-8?B?0LXQvNCk0LDQudC70LDQodC+0LLRgdC10LzQkdC10LfQn9GA0L7QsdC1?=" 0594 "=?UTF-8?B?0LvQvtCy0JjQldGJ0ZHQoNCw0LfQrdGC0L7QktC70L7QttC10L3QuNC1?=" 0595 "=?UTF-8?B?0KHQlNC70LjQvdC90YvQvNCY0LzQtdC80KTQsNC50LvQsNCh0L7QstGB?=" 0596 "=?UTF-8?B?0LXQvNCR0LXQt9Cf0YDQvtCx0LXQu9C+0LIudHh0?=\""); 0597 QCOMPARE(h->name(), QString::fromUtf8("ЭтоВложениеСДлиннымИмемФайлаСовсемБезПробеловИЕщёРазЭтоВложениеСДлиннымИмемФайлаСовсемБезПробелов.txt")); 0598 delete h; 0599 h = new ContentType; 0600 h->from7BitString("text/plain;\n name=\"=?UTF-8?B?0K3RgtC+0JLQu9C+0LbQtdC90LjQtdCh0JTQu9C40L3QvdGL0LzQmNC8?=" 0601 " =?UTF-8?B?0LXQvNCk0LDQudC70LDQodC+0LLRgdC10LzQkdC10LfQn9GA0L7QsdC1?=" 0602 " =?UTF-8?B?0LvQvtCy0JjQldGJ0ZHQoNCw0LfQrdGC0L7QktC70L7QttC10L3QuNC1?=" 0603 " =?UTF-8?B?0KHQlNC70LjQvdC90YvQvNCY0LzQtdC80KTQsNC50LvQsNCh0L7QstGB?=" 0604 " =?UTF-8?B?0LXQvNCR0LXQt9Cf0YDQvtCx0LXQu9C+0LIudHh0?=\""); 0605 QCOMPARE(h->name(), QString::fromUtf8("ЭтоВложениеСДлиннымИмемФайлаСовсемБезПробеловИЕщёРазЭтоВложениеСДлиннымИмемФайлаСовсемБезПробелов.txt")); 0606 delete h; 0607 0608 // empty header 0609 h = new ContentType(); 0610 QVERIFY(h->isEmpty()); 0611 0612 // Empty content-type means text/plain (RFC 2045 §5.2) 0613 QVERIFY(h->isPlainText()); 0614 QVERIFY(h->isText()); 0615 0616 // set a mimetype 0617 h->setMimeType("text/plain"); 0618 QVERIFY(!h->isEmpty()); 0619 QCOMPARE(h->mimeType(), QByteArray("text/plain")); 0620 QCOMPARE(h->mediaType(), QByteArray("text")); 0621 QCOMPARE(h->subType(), QByteArray("plain")); 0622 QVERIFY(h->isText()); 0623 QVERIFY(h->isPlainText()); 0624 QVERIFY(!h->isMultipart()); 0625 QVERIFY(!h->isPartial()); 0626 QVERIFY(h->isMediatype("text")); 0627 QVERIFY(h->isSubtype("plain")); 0628 QCOMPARE(h->as7BitString(true), QByteArray("Content-Type: text/plain")); 0629 0630 // add some parameters 0631 h->setId("bla"); 0632 h->setCharset("us-ascii"); 0633 QCOMPARE(h->as7BitString(false), QByteArray("text/plain; charset=\"us-ascii\"; id=\"bla\"")); 0634 0635 // clear header 0636 h->clear(); 0637 QVERIFY(h->isEmpty()); 0638 delete h; 0639 0640 // parse a complete header 0641 h = new ContentType; 0642 h->from7BitString("text/plain; charset=us-ascii (Plain text)"); 0643 QVERIFY(h->isPlainText()); 0644 QCOMPARE(h->charset(), QByteArray("us-ascii")); 0645 delete h; 0646 0647 // bug #136631 (name with rfc 2231 style parameter wrapping) 0648 h = new ContentType; 0649 h->from7BitString("text/plain;\n name*0=\"PIN_Brief_box1@xx.xxx.censored_Konfigkarte.confi\";\n name*1=\"guration.txt\""); 0650 QVERIFY(h->isPlainText()); 0651 QCOMPARE( 0652 h->name(), 0653 QLatin1StringView( 0654 "PIN_Brief_box1@xx.xxx.censored_Konfigkarte.configuration.txt")); 0655 delete h; 0656 0657 // bug #197958 (name of Content-Type sent by Mozilla Thunderbird are not parsed -- test case generated with v2.0.0.22) 0658 h = new ContentType; 0659 h->from7BitString("text/plain;\n name=\"=?ISO-8859-1?Q?lor=E9m_ipsum=2Etxt?=\""); 0660 QCOMPARE(h->name(), QString::fromUtf8("lorém ipsum.txt")); 0661 delete h; 0662 0663 // bug #197958 (name of Content-Type sent by Mozilla Thunderbird are not parsed -- test case generated with v2.0.0.22) 0664 // But with unquoted string 0665 QEXPECT_FAIL("", "Unquoted rfc2047 strings are not supported as of now", Continue); 0666 h = new ContentType; 0667 h->from7BitString("text/plain;\n name==?ISO-8859-1?Q?lor=E9m_ipsum=2Etxt?="); 0668 QCOMPARE(h->name(), QString::fromUtf8("lorém ipsum.txt")); 0669 delete h; 0670 0671 // make ervin's unit test happy 0672 h = new ContentType; 0673 h->setMimeType("MULTIPART/MIXED"); 0674 QVERIFY(h->isMultipart()); 0675 QVERIFY(h->isMediatype("multipart")); 0676 QVERIFY(h->isMediatype("Multipart")); 0677 QVERIFY(h->isMediatype("MULTIPART")); 0678 QVERIFY(h->isSubtype("mixed")); 0679 QVERIFY(h->isSubtype("Mixed")); 0680 QVERIFY(h->isSubtype("MIXED")); 0681 QCOMPARE(h->mimeType(), QByteArray("MULTIPART/MIXED")); 0682 QCOMPARE(h->mediaType(), QByteArray("MULTIPART")); 0683 QCOMPARE(h->subType(), QByteArray("MIXED")); 0684 delete h; 0685 0686 } 0687 0688 void HeaderTest::testTokenHeader() 0689 { 0690 Token *h; 0691 0692 // empty header 0693 h = new Token(); 0694 QVERIFY(h->isEmpty()); 0695 0696 // set a token 0697 h->setToken("bla"); 0698 QVERIFY(!h->isEmpty()); 0699 QCOMPARE(h->as7BitString(false), QByteArray("bla")); 0700 0701 // clear it again 0702 h->clear(); 0703 QVERIFY(h->isEmpty()); 0704 delete h; 0705 0706 // parse a header 0707 h = new Token; 0708 h->from7BitString("value (comment)"); 0709 QCOMPARE(h->token(), QByteArray("value")); 0710 QCOMPARE(h->as7BitString(false), QByteArray("value")); 0711 delete h; 0712 } 0713 0714 void HeaderTest::testContentTransferEncoding() 0715 { 0716 ContentTransferEncoding *h; 0717 0718 // empty header 0719 h = new ContentTransferEncoding(); 0720 QVERIFY(h->isEmpty()); 0721 0722 // set an encoding 0723 h->setEncoding(CEbinary); 0724 QVERIFY(!h->isEmpty()); 0725 QCOMPARE(h->as7BitString(true), QByteArray("Content-Transfer-Encoding: binary")); 0726 0727 // clear again 0728 h->clear(); 0729 QVERIFY(h->isEmpty()); 0730 delete h; 0731 0732 // parse a header 0733 h = new ContentTransferEncoding; 0734 h->from7BitString("(comment) base64"); 0735 QCOMPARE(h->encoding(), CEbase64); 0736 QCOMPARE(h->as7BitString(false), QByteArray("base64")); 0737 delete h; 0738 } 0739 0740 void HeaderTest::testPhraseListHeader() 0741 { 0742 PhraseList *h; 0743 0744 // empty header 0745 h = new PhraseList(); 0746 QVERIFY(h->isEmpty()); 0747 delete h; 0748 0749 // parse a simple phrase list 0750 h = new PhraseList; 0751 h->from7BitString("foo,\n bar"); 0752 QVERIFY(!h->isEmpty()); 0753 QCOMPARE(h->phrases().count(), 2); 0754 QStringList phrases = h->phrases(); 0755 QCOMPARE(phrases.takeFirst(), QLatin1StringView("foo")); 0756 QCOMPARE(phrases.takeFirst(), QLatin1StringView("bar")); 0757 QCOMPARE(h->as7BitString(false), QByteArray("foo, bar")); 0758 0759 // clear header 0760 h->clear(); 0761 QVERIFY(h->isEmpty()); 0762 delete h; 0763 0764 // TODO: encoded/quoted phrases 0765 } 0766 0767 void HeaderTest::testDotAtomHeader() 0768 { 0769 DotAtom *h; 0770 0771 // empty header 0772 h = new DotAtom; 0773 QVERIFY(h->isEmpty()); 0774 0775 // parse a simple dot atom 0776 h->from7BitString("1.0 (mime version)"); 0777 QVERIFY(!h->isEmpty()); 0778 QCOMPARE(h->asUnicodeString(), QLatin1StringView("1.0")); 0779 0780 // clear again 0781 h->clear(); 0782 QVERIFY(h->isEmpty()); 0783 delete h; 0784 0785 // TODO: more complex atoms 0786 } 0787 0788 void HeaderTest::testDateHeader() 0789 { 0790 Date *h; 0791 0792 // empty header 0793 h = new Date(); 0794 QVERIFY(h->isEmpty()); 0795 0796 // parse a simple date 0797 h->from7BitString("Fri, 21 Nov 1997 09:55:06 -0600"); 0798 QVERIFY(!h->isEmpty()); 0799 QCOMPARE(h->dateTime().date(), QDate(1997, 11, 21)); 0800 QCOMPARE(h->dateTime().time(), QTime(9, 55, 6)); 0801 QCOMPARE(h->dateTime().offsetFromUtc(), -6 * 3600); 0802 QCOMPARE(h->as7BitString(), QByteArray("Date: Fri, 21 Nov 1997 09:55:06 -0600")); 0803 0804 // clear it again 0805 h->clear(); 0806 QVERIFY(h->isEmpty()); 0807 delete h; 0808 0809 // white spaces and comment (from RFC 2822, Appendix A.5) 0810 h = new Date; 0811 h->from7BitString("Thu,\n 13\n Feb\n 1969\n 23:32\n -0330 (Newfoundland Time)"); 0812 QVERIFY(!h->isEmpty()); 0813 QCOMPARE(h->dateTime().date(), QDate(1969, 2, 13)); 0814 QCOMPARE(h->dateTime().time(), QTime(23, 32)); 0815 QCOMPARE(h->dateTime().offsetFromUtc(), -12600); 0816 QCOMPARE(h->as7BitString(false), QByteArray("Thu, 13 Feb 1969 23:32:00 -0330")); 0817 delete h; 0818 0819 // obsolete date format (from RFC 2822, Appendix A.6.2) 0820 h = new Date; 0821 h->from7BitString("21 Nov 97 09:55:06 GMT"); 0822 QVERIFY(!h->isEmpty()); 0823 QCOMPARE(h->dateTime().date(), QDate(1997, 11, 21)); 0824 QCOMPARE(h->dateTime().time(), QTime(9, 55, 6)); 0825 QCOMPARE(h->dateTime().offsetFromUtc(), 0); 0826 delete h; 0827 0828 // obsolete whitespaces and commnets (from RFC 2822, Appendix A.6.3) 0829 h = new Date; 0830 h->from7BitString("Fri, 21 Nov 1997 09(comment): 55 : 06 -0600"); 0831 QVERIFY(!h->isEmpty()); 0832 QCOMPARE(h->dateTime().date(), QDate(1997, 11, 21)); 0833 QCOMPARE(h->dateTime().time(), QTime(9, 55, 6)); 0834 QCOMPARE(h->dateTime().offsetFromUtc(), -6 * 3600); 0835 delete h; 0836 0837 // Make sure uppercase OCT is parsed correctly - bug 150620 0838 h = new Date; 0839 h->from7BitString("08 OCT 08 16:54:05 +0000"); 0840 QVERIFY(!h->isEmpty()); 0841 QCOMPARE(h->dateTime().date(), QDate(2008, 10, 8)); 0842 QCOMPARE(h->dateTime().time(), QTime(16, 54, 05)); 0843 QCOMPARE(h->dateTime().offsetFromUtc(), 0); 0844 delete h; 0845 0846 // Test for bug 111633, year < 1970 0847 h = new Date; 0848 h->from7BitString("Mon, 27 Aug 1956 21:31:46 +0200"); 0849 QVERIFY(!h->isEmpty()); 0850 QCOMPARE(h->dateTime().date(), QDate(1956, 8, 27)); 0851 QCOMPARE(h->dateTime().time(), QTime(21, 31, 46)); 0852 QCOMPARE(h->dateTime().offsetFromUtc(), +2 * 3600); 0853 delete h; 0854 0855 // Test for bug 207766 0856 h = new Date; 0857 h->from7BitString("Fri, 18 Sep 2009 04:44:55 -0400"); 0858 QVERIFY(!h->isEmpty()); 0859 QCOMPARE(h->dateTime().date(), QDate(2009, 9, 18)); 0860 QCOMPARE(h->dateTime().time(), QTime(4, 44, 55)); 0861 QCOMPARE(h->dateTime().offsetFromUtc(), -4 * 3600); 0862 delete h; 0863 0864 // Test for bug 260761 0865 h = new Date; 0866 h->from7BitString("Sat, 18 Dec 2010 14:01:21 \"GMT\""); 0867 QVERIFY(!h->isEmpty()); 0868 QCOMPARE(h->dateTime().date(), QDate(2010, 12, 18)); 0869 QCOMPARE(h->dateTime().time(), QTime(14, 1, 21)); 0870 QCOMPARE(h->dateTime().offsetFromUtc(), 0); 0871 delete h; 0872 0873 // old asctime()-like formatted date; regression to KDE3; see bug 117848 0874 h = new Date; 0875 h->from7BitString("Thu Mar 30 18:36:28 CEST 2006"); 0876 QVERIFY(!h->isEmpty()); 0877 QCOMPARE(h->dateTime().date(), QDate(2006, 3, 30)); 0878 QCOMPARE(h->dateTime().time(), QTime(18, 36, 28)); 0879 QCOMPARE(h->dateTime().offsetFromUtc(), 2 * 3600); 0880 delete h; 0881 0882 h = new Date; 0883 h->from7BitString("Thu Mar 30 18:36:28 2006"); 0884 QVERIFY(!h->isEmpty()); 0885 QCOMPARE(h->dateTime().date(), QDate(2006, 3, 30)); 0886 QCOMPARE(h->dateTime().time(), QTime(18, 36, 28)); 0887 QCOMPARE(h->dateTime().offsetFromUtc(), 0); 0888 delete h; 0889 0890 // regression to KDE3; see bug 54098 0891 h = new Date; 0892 h->from7BitString("Tue, Feb 04, 2003 00:01:20 +0000"); 0893 QVERIFY(!h->isEmpty()); 0894 QCOMPARE(h->dateTime().date(), QDate(2003, 2, 4)); 0895 QCOMPARE(h->dateTime().time(), QTime(0, 1, 20)); 0896 QCOMPARE(h->dateTime().offsetFromUtc(), 0); 0897 delete h; 0898 0899 // date in a DST change to the future so in a time that doesn't exist 0900 // unless you take the timezone into account 0901 h = new Date; 0902 h->from7BitString("Sun, 31 Mar 2013 02:29:44 -0500"); 0903 QVERIFY(!h->isEmpty()); 0904 QCOMPARE(h->dateTime().date(), QDate(2013, 3, 31)); 0905 QCOMPARE(h->dateTime().time(), QTime(2, 29, 44)); 0906 QCOMPARE(h->dateTime().offsetFromUtc(), -18000); 0907 delete h; 0908 0909 // Bug Date: 13/10/20 12:51:47 0910 h = new Date; 0911 h->from7BitString("13/10/20 12:51:47"); 0912 QVERIFY(!h->isEmpty()); 0913 QCOMPARE(h->dateTime().date(), QDate(2020, 10, 13)); 0914 QCOMPARE(h->dateTime().time(), QTime(12, 51, 47)); 0915 delete h; 0916 0917 //28/09/23 16:05:54 0918 h = new Date; 0919 h->from7BitString("28/09/23 16:05:54"); 0920 QVERIFY(!h->isEmpty()); 0921 QCOMPARE(h->dateTime().date(), QDate(2023, 9, 28)); 0922 QCOMPARE(h->dateTime().time(), QTime(16, 05, 54)); 0923 delete h; 0924 0925 // Wed, 12 Apr 2030 0926 h = new Date; 0927 h->from7BitString("Wed, 12 Apr 2030"); 0928 QVERIFY(!h->isEmpty()); 0929 QCOMPARE(h->dateTime().date(), QDate(2030, 4, 12)); 0930 QCOMPARE(h->dateTime().time(), QTime(0, 0, 0)); 0931 delete h; 0932 } 0933 0934 void HeaderTest::testLinesHeader() 0935 { 0936 Lines *h; 0937 0938 // empty header 0939 h = new Lines(); 0940 QVERIFY(h->isEmpty()); 0941 QVERIFY(h->as7BitString().isEmpty()); 0942 0943 // set some content 0944 h->setNumberOfLines(5); 0945 QVERIFY(!h->isEmpty()); 0946 QCOMPARE(h->as7BitString(), QByteArray("Lines: 5")); 0947 0948 // clear again 0949 h->clear(); 0950 QVERIFY(h->isEmpty()); 0951 delete h; 0952 0953 // parse header with comment 0954 h = new Lines; 0955 h->from7BitString("(this is a comment) 10 (and yet another comment)"); 0956 QVERIFY(!h->isEmpty()); 0957 QCOMPARE(h->numberOfLines(), 10); 0958 delete h; 0959 } 0960 0961 void HeaderTest::testNewsgroupsHeader() 0962 { 0963 Newsgroups *h; 0964 0965 // empty header 0966 h = new Newsgroups(); 0967 QVERIFY(h->isEmpty()); 0968 QVERIFY(h->as7BitString().isEmpty()); 0969 0970 // set newsgroups 0971 QList<QByteArray> groups; 0972 groups << "gmane.comp.kde.devel.core" << "gmane.comp.kde.devel.buildsystem"; 0973 h->setGroups(groups); 0974 QVERIFY(!h->isEmpty()); 0975 QCOMPARE(h->as7BitString(), QByteArray("Newsgroups: gmane.comp.kde.devel.core,gmane.comp.kde.devel.buildsystem")); 0976 0977 // and clear again 0978 h->clear(); 0979 QVERIFY(h->isEmpty()); 0980 delete h; 0981 0982 // parse a header 0983 h = new Newsgroups; 0984 h->from7BitString("gmane.comp.kde.devel.core,gmane.comp.kde.devel.buildsystem"); 0985 groups = h->groups(); 0986 QCOMPARE(groups.count(), 2); 0987 QCOMPARE(groups.takeFirst(), QByteArray("gmane.comp.kde.devel.core")); 0988 QCOMPARE(groups.takeFirst(), QByteArray("gmane.comp.kde.devel.buildsystem")); 0989 delete h; 0990 0991 // same again, this time with whitespaces and comments 0992 h = new Newsgroups(); 0993 h->from7BitString("(comment) gmane.comp.kde.devel.core (second comment),\n gmane.comp.kde.devel.buildsystem (that all)"); 0994 groups = h->groups(); 0995 QCOMPARE(groups.count(), 2); 0996 QCOMPARE(groups.takeFirst(), QByteArray("gmane.comp.kde.devel.core")); 0997 QCOMPARE(groups.takeFirst(), QByteArray("gmane.comp.kde.devel.buildsystem")); 0998 delete h; 0999 } 1000 1001 void HeaderTest::testControlHeader() 1002 { 1003 Control *h; 1004 1005 // empty header 1006 h = new Control(); 1007 QVERIFY(h->isEmpty()); 1008 QVERIFY(h->as7BitString().isEmpty()); 1009 1010 // set some content 1011 h->setCancel("<foo@bar>"); 1012 QVERIFY(!h->isEmpty()); 1013 QVERIFY(h->isCancel()); 1014 QCOMPARE(h->as7BitString(), QByteArray("Control: cancel <foo@bar>")); 1015 1016 // clear again 1017 h->clear(); 1018 QVERIFY(h->isEmpty()); 1019 delete h; 1020 1021 // parse a control header 1022 h = new Control; 1023 h->from7BitString("cancel <foo@bar>"); 1024 QVERIFY(!h->isEmpty()); 1025 QCOMPARE(h->parameter(), QByteArray("<foo@bar>")); 1026 QVERIFY(h->isCancel()); 1027 QCOMPARE(h->controlType(), QByteArray("cancel")); 1028 delete h; 1029 } 1030 1031 void HeaderTest::testReturnPath() 1032 { 1033 ReturnPath *h; 1034 1035 h = new ReturnPath(); 1036 QVERIFY(h->isEmpty()); 1037 QVERIFY(h->as7BitString().isEmpty()); 1038 1039 h->from7BitString("<foo@bar>"); 1040 QVERIFY(!h->isEmpty()); 1041 QCOMPARE(h->as7BitString(true), QByteArray("Return-Path: <foo@bar>")); 1042 1043 delete h; 1044 } 1045 1046 void HeaderTest::noAbstractHeaders() 1047 { 1048 From *h2 = new From(); delete h2; 1049 auto h3 = new Sender(); delete h3; 1050 To *h4 = new To(); delete h4; 1051 Cc *h5 = new Cc(); delete h5; 1052 Bcc *h6 = new Bcc(); delete h6; 1053 auto h7 = new ReplyTo(); delete h7; 1054 auto h8 = new Keywords(); delete h8; 1055 auto h9 = new MIMEVersion(); delete h9; 1056 auto h10 = new MessageID(); delete h10; 1057 auto h11 = new ContentID(); delete h11; 1058 auto h12 = new Supersedes(); delete h12; 1059 auto h13 = new InReplyTo(); delete h13; 1060 auto h14 = new References(); delete h14; 1061 auto h15 = new Generic(); delete h15; 1062 auto h16 = new Subject(); delete h16; 1063 auto h17 = new Organization(); delete h17; 1064 auto h18 = new ContentDescription(); delete h18; 1065 auto h22 = new FollowUpTo(); delete h22; 1066 auto h24 = new UserAgent(); delete h24; 1067 } 1068 1069 void HeaderTest::testInvalidButOkQEncoding() 1070 { 1071 // A stray '?' should not confuse the parser 1072 Subject subject; 1073 subject.from7BitString("=?us-ascii?q?Why?_Why_do_some_clients_violate_the_RFC?" "?="); 1074 QCOMPARE(subject.as7BitString(false), QByteArray("Why? Why do some clients violate the RFC?")); 1075 } 1076 1077 void HeaderTest::testInvalidQEncoding_data() 1078 { 1079 QTest::addColumn<QString>("encodedWord"); 1080 1081 // All examples below should not be treated as invalid encoded strings, since the '?=' is missing 1082 QTest::newRow("") << QString::fromLatin1("=?us-ascii?q?Why?_Why_do_some_clients_violate_the_RFC??"); 1083 QTest::newRow("") << QString::fromLatin1("=?us-ascii?q?Why?_Why_do_some_clients_violate_the_RFC?"); 1084 QTest::newRow("") << QString::fromLatin1("=?us-ascii?q?Why?_Why_do_some_clients_violate_the_RFC"); 1085 } 1086 1087 void HeaderTest::testInvalidQEncoding() 1088 { 1089 using namespace HeaderParsing; 1090 QFETCH(QString, encodedWord); 1091 1092 QByteArray tmp = encodedWord.toLatin1(); 1093 const char *data = tmp.data(); 1094 const char *start = data + 1; 1095 const char *end = data + strlen(data); 1096 QString result; 1097 QByteArray language; 1098 QByteArray usedCS; 1099 QVERIFY(!parseEncodedWord(start, end, result, language, usedCS)); 1100 } 1101 1102 void HeaderTest::testMissingQuotes() 1103 { 1104 QByteArray str = "multipart/signed; boundary=nextPart22807781.u8zn2zYrSU; micalg=pgp-sha1; protocol=application/pgp-signature"; 1105 1106 Headers::ContentType ct; 1107 ct.from7BitString(str); 1108 QCOMPARE(ct.mimeType(), QByteArray{ "multipart/signed" }); 1109 QCOMPARE(ct.boundary(), QByteArray{ "nextPart22807781.u8zn2zYrSU" }); 1110 QCOMPARE(ct.parameter(QStringLiteral("micalg")), QStringLiteral("pgp-sha1")); 1111 QCOMPARE(ct.parameter(QStringLiteral("protocol")), QStringLiteral("application/pgp-signature")); 1112 1113 } 1114 1115 void HeaderTest::testBug271192() 1116 { 1117 QFETCH(QString, displayName); 1118 QFETCH(bool, quote); 1119 1120 const QString addrSpec = QLatin1StringView("example@example.com"); 1121 const QString mailbox = 1122 (quote ? QLatin1StringView("\"") : QString()) + displayName + 1123 (quote ? QLatin1StringView("\"") : QString()) + 1124 QLatin1StringView(" <") + addrSpec + QLatin1StringView(">"); 1125 1126 auto h = new Headers::Generics::SingleMailbox(); 1127 h->fromUnicodeString(mailbox, "utf-8"); 1128 QCOMPARE(h->displayNames().size(), 1); 1129 QCOMPARE(h->displayNames().first().toUtf8(), 1130 displayName.remove(QLatin1StringView("\\")).toUtf8()); 1131 delete h; 1132 h = nullptr; 1133 1134 auto h2 = new Headers::Generics::MailboxList(); 1135 h2->fromUnicodeString(mailbox + QLatin1StringView(",") + mailbox, "utf-8"); 1136 QCOMPARE(h2->displayNames().size(), 2); 1137 QCOMPARE(h2->displayNames()[0].toUtf8(), 1138 displayName.remove(QLatin1StringView("\\")).toUtf8()); 1139 QCOMPARE(h2->displayNames()[1].toUtf8(), 1140 displayName.remove(QLatin1StringView("\\")).toUtf8()); 1141 delete h2; 1142 h2 = nullptr; 1143 } 1144 1145 void HeaderTest::testBug271192_data() 1146 { 1147 QTest::addColumn<QString>("displayName"); 1148 QTest::addColumn<bool>("quote"); 1149 1150 QTest::newRow("Plain") << QString::fromUtf8("John Doe") << false; 1151 QTest::newRow("Firstname_1") << QString::fromUtf8("Marc-André Lastname") << false; 1152 QTest::newRow("Firstname_2") << QString::fromUtf8("Интернет-компания Lastname") << false; 1153 QTest::newRow("Lastname") << QString::fromUtf8("Tobias König") << false; 1154 QTest::newRow("Firstname_Lastname") << QString::fromUtf8("Интернет-компания König") << false; 1155 QTest::newRow("Quotemarks") << QString::fromUtf8(R"(John \"Rocky\" Doe)") << true; 1156 QTest::newRow("Quotemarks_nonascii") << QString::fromUtf8("Jöhn \\\"Röcky\\\" Döe") << true; 1157 1158 QTest::newRow("quote_Plain") << QString::fromUtf8("John Doe") << true; 1159 QTest::newRow("quote_Firstname_1") << QString::fromUtf8("Marc-André Lastname") << true; 1160 QTest::newRow("quote_Firstname_2") << QString::fromUtf8("Интернет-компания Lastname") << true; 1161 QTest::newRow("quote_Lastname") << QString::fromUtf8("Tobias König") << true; 1162 QTest::newRow("quote_Firstname_Lastname") << QString::fromUtf8("Интернет-компания König") << true; 1163 QTest::newRow("quote_LastName_comma_Firstname") << QString::fromUtf8("König, Интернет-компания") << true; 1164 } 1165 1166 void HeaderTest::testParseNextHeader() 1167 { 1168 QByteArray data("From: konqi@kde.org\nTo: katie@kde.org\n\n"); 1169 QByteArrayView dataView(data); 1170 1171 auto header = KMime::HeaderParsing::parseNextHeader(dataView); 1172 QVERIFY(header); 1173 QCOMPARE(header->type(), "From"); 1174 QVERIFY(dataView.startsWith("To:")); 1175 1176 header = KMime::HeaderParsing::parseNextHeader(dataView); 1177 QVERIFY(header); 1178 QCOMPARE(header->type(), "To"); 1179 1180 QVERIFY(!KMime::HeaderParsing::parseNextHeader(dataView)); 1181 QVERIFY(dataView.isEmpty()); 1182 } 1183 1184 #include "moc_headertest.cpp"