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