1 | // |
2 | // MailMessageTest.cpp |
3 | // |
4 | // Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH. |
5 | // and Contributors. |
6 | // |
7 | // SPDX-License-Identifier: BSL-1.0 |
8 | // |
9 | |
10 | |
11 | #include "MailMessageTest.h" |
12 | #include "Poco/CppUnit/TestCaller.h" |
13 | #include "Poco/CppUnit/TestSuite.h" |
14 | #include "Poco/Net/MailMessage.h" |
15 | #include "Poco/Net/MailRecipient.h" |
16 | #include "Poco/Net/PartHandler.h" |
17 | #include "Poco/Net/StringPartSource.h" |
18 | #include "Poco/Net/PartStore.h" |
19 | #include "Poco/Net/MediaType.h" |
20 | #include "Poco/Timestamp.h" |
21 | #include "Poco/FileStream.h" |
22 | #include "Poco/String.h" |
23 | #include <sstream> |
24 | #include <vector> |
25 | |
26 | |
27 | using Poco::Net::MailMessage; |
28 | using Poco::Net::MailRecipient; |
29 | using Poco::Net::MessageHeader; |
30 | using Poco::Net::PartHandler; |
31 | using Poco::Net::MediaType; |
32 | using Poco::Net::StringPartSource; |
33 | using Poco::Net::FilePartStoreFactory; |
34 | using Poco::Net::FilePartStore; |
35 | using Poco::Timestamp; |
36 | using Poco::FileInputStream; |
37 | using Poco::replaceInPlace; |
38 | using Poco::icompare; |
39 | |
40 | |
41 | namespace |
42 | { |
43 | class StringPartHandler: public PartHandler |
44 | { |
45 | public: |
46 | StringPartHandler() |
47 | { |
48 | } |
49 | |
50 | void handlePart(const MessageHeader& , std::istream& stream) |
51 | { |
52 | _disp.push_back(header["Content-Disposition" ]); |
53 | _type.push_back(header["Content-Type" ]); |
54 | std::string data; |
55 | int ch = stream.get(); |
56 | while (ch > 0) |
57 | { |
58 | data += (char) ch; |
59 | ch = stream.get(); |
60 | } |
61 | _data.push_back(data); |
62 | } |
63 | |
64 | const std::vector<std::string>& data() const |
65 | { |
66 | return _data; |
67 | } |
68 | |
69 | const std::vector<std::string>& disp() const |
70 | { |
71 | return _disp; |
72 | } |
73 | |
74 | const std::vector<std::string>& type() const |
75 | { |
76 | return _type; |
77 | } |
78 | |
79 | private: |
80 | std::vector<std::string> _data; |
81 | std::vector<std::string> _disp; |
82 | std::vector<std::string> _type; |
83 | }; |
84 | } |
85 | |
86 | |
87 | MailMessageTest::MailMessageTest(const std::string& name): CppUnit::TestCase(name) |
88 | { |
89 | } |
90 | |
91 | |
92 | MailMessageTest::~MailMessageTest() |
93 | { |
94 | } |
95 | |
96 | |
97 | void MailMessageTest::testWriteQP() |
98 | { |
99 | MailMessage message; |
100 | MailRecipient r1(MailRecipient::PRIMARY_RECIPIENT, "john.doe@no.where" , "John Doe" ); |
101 | MailRecipient r2(MailRecipient::CC_RECIPIENT, "jane.doe@no.where" , "Jane Doe" ); |
102 | MailRecipient r3(MailRecipient::BCC_RECIPIENT, "walter.foo@no.where" , "Frank Foo" ); |
103 | MailRecipient r4(MailRecipient::BCC_RECIPIENT, "bernie.bar@no.where" , "Bernie Bar" ); |
104 | message.addRecipient(r1); |
105 | message.addRecipient(r2); |
106 | message.addRecipient(r3); |
107 | message.addRecipient(r4); |
108 | message.setSubject("Test Message" ); |
109 | message.setSender("poco@appinf.com" ); |
110 | message.setContent( |
111 | "Hello, world!\r\n" |
112 | "This is a test for the MailMessage class.\r\n" |
113 | "To test the quoted-printable encoding, we'll put an extra long line here. This should be enough.\r\n" |
114 | "And here is some more =fe.\r\n" |
115 | ); |
116 | Timestamp ts(0); |
117 | message.setDate(ts); |
118 | |
119 | assertTrue (!message.isMultipart()); |
120 | |
121 | std::ostringstream str; |
122 | message.write(str); |
123 | std::string s = str.str(); |
124 | |
125 | assertTrue (s == |
126 | "Date: Thu, 1 Jan 1970 00:00:00 GMT\r\n" |
127 | "Content-Type: text/plain\r\n" |
128 | "Subject: Test Message\r\n" |
129 | "From: poco@appinf.com\r\n" |
130 | "Content-Transfer-Encoding: quoted-printable\r\n" |
131 | "To: John Doe <john.doe@no.where>\r\n" |
132 | "CC: Jane Doe <jane.doe@no.where>\r\n" |
133 | "\r\n" |
134 | "Hello, world!\r\n" |
135 | "This is a test for the MailMessage class.\r\n" |
136 | "To test the quoted-printable encoding, we'll put an extra long line here. T=\r\n" |
137 | "his should be enough.\r\n" |
138 | "And here is some more =3Dfe.\r\n" |
139 | ); |
140 | } |
141 | |
142 | |
143 | void MailMessageTest::testWrite8Bit() |
144 | { |
145 | MailMessage message; |
146 | MailRecipient r1(MailRecipient::PRIMARY_RECIPIENT, "john.doe@no.where" , "John Doe" ); |
147 | message.addRecipient(r1); |
148 | message.setSubject("Test Message" ); |
149 | message.setSender("poco@appinf.com" ); |
150 | message.setContent( |
151 | "Hello, world!\r\n" |
152 | "This is a test for the MailMessage class.\r\n" , |
153 | MailMessage::ENCODING_8BIT |
154 | ); |
155 | Timestamp ts(0); |
156 | message.setDate(ts); |
157 | |
158 | std::ostringstream str; |
159 | message.write(str); |
160 | std::string s = str.str(); |
161 | assertTrue (s == |
162 | "Date: Thu, 1 Jan 1970 00:00:00 GMT\r\n" |
163 | "Content-Type: text/plain\r\n" |
164 | "Subject: Test Message\r\n" |
165 | "From: poco@appinf.com\r\n" |
166 | "Content-Transfer-Encoding: 8bit\r\n" |
167 | "To: John Doe <john.doe@no.where>\r\n" |
168 | "\r\n" |
169 | "Hello, world!\r\n" |
170 | "This is a test for the MailMessage class.\r\n" |
171 | ); |
172 | } |
173 | |
174 | |
175 | void MailMessageTest::testWriteBase64() |
176 | { |
177 | MailMessage message; |
178 | MailRecipient r1(MailRecipient::PRIMARY_RECIPIENT, "john.doe@no.where" , "John Doe" ); |
179 | message.addRecipient(r1); |
180 | message.setSubject("Test Message" ); |
181 | message.setSender("poco@appinf.com" ); |
182 | message.setContent( |
183 | "Hello, world!\r\n" |
184 | "This is a test for the MailMessage class.\r\n" , |
185 | MailMessage::ENCODING_BASE64 |
186 | ); |
187 | Timestamp ts(0); |
188 | message.setDate(ts); |
189 | |
190 | std::ostringstream str; |
191 | message.write(str); |
192 | std::string s = str.str(); |
193 | assertTrue (s == |
194 | "Date: Thu, 1 Jan 1970 00:00:00 GMT\r\n" |
195 | "Content-Type: text/plain\r\n" |
196 | "Subject: Test Message\r\n" |
197 | "From: poco@appinf.com\r\n" |
198 | "Content-Transfer-Encoding: base64\r\n" |
199 | "To: John Doe <john.doe@no.where>\r\n" |
200 | "\r\n" |
201 | "SGVsbG8sIHdvcmxkIQ0KVGhpcyBpcyBhIHRlc3QgZm9yIHRoZSBNYWlsTWVzc2FnZSBjbGFz\r\n" |
202 | "cy4NCg==" |
203 | ); |
204 | } |
205 | |
206 | |
207 | void MailMessageTest::testWriteManyRecipients() |
208 | { |
209 | MailMessage message; |
210 | MailRecipient r1(MailRecipient::PRIMARY_RECIPIENT, "john.doe@no.where" , "John Doe" ); |
211 | MailRecipient r2(MailRecipient::PRIMARY_RECIPIENT, "jane.doe@no.where" , "Jane Doe" ); |
212 | MailRecipient r3(MailRecipient::PRIMARY_RECIPIENT, "walter.foo@no.where" , "Frank Foo" ); |
213 | MailRecipient r4(MailRecipient::PRIMARY_RECIPIENT, "bernie.bar@no.where" , "Bernie Bar" ); |
214 | MailRecipient r5(MailRecipient::PRIMARY_RECIPIENT, "joe.spammer@no.where" , "Joe Spammer" ); |
215 | message.addRecipient(r1); |
216 | message.addRecipient(r2); |
217 | message.addRecipient(r3); |
218 | message.addRecipient(r4); |
219 | message.addRecipient(r5); |
220 | message.setSubject("Test Message" ); |
221 | message.setSender("poco@appinf.com" ); |
222 | message.setContent( |
223 | "Hello, world!\r\n" |
224 | "This is a test for the MailMessage class.\r\n" , |
225 | MailMessage::ENCODING_8BIT |
226 | ); |
227 | Timestamp ts(0); |
228 | message.setDate(ts); |
229 | |
230 | std::ostringstream str; |
231 | message.write(str); |
232 | std::string s = str.str(); |
233 | assertTrue (s == |
234 | "Date: Thu, 1 Jan 1970 00:00:00 GMT\r\n" |
235 | "Content-Type: text/plain\r\n" |
236 | "Subject: Test Message\r\n" |
237 | "From: poco@appinf.com\r\n" |
238 | "Content-Transfer-Encoding: 8bit\r\n" |
239 | "To: John Doe <john.doe@no.where>, Jane Doe <jane.doe@no.where>, \r\n" |
240 | "\tFrank Foo <walter.foo@no.where>, Bernie Bar <bernie.bar@no.where>, \r\n" |
241 | "\tJoe Spammer <joe.spammer@no.where>\r\n" |
242 | "\r\n" |
243 | "Hello, world!\r\n" |
244 | "This is a test for the MailMessage class.\r\n" |
245 | ); |
246 | |
247 | const Poco::Net::MailMessage::Recipients& recipients = message.recipients(); |
248 | assertTrue (recipients.size() == 5); |
249 | assertTrue (recipients[0].getAddress() == "john.doe@no.where" ); |
250 | assertTrue (recipients[0].getRealName() == "John Doe" ); |
251 | assertTrue (recipients[1].getAddress() == "jane.doe@no.where" ); |
252 | assertTrue (recipients[1].getRealName() == "Jane Doe" ); |
253 | assertTrue (recipients[2].getAddress() == "walter.foo@no.where" ); |
254 | assertTrue (recipients[2].getRealName() == "Frank Foo" ); |
255 | assertTrue (recipients[3].getAddress() == "bernie.bar@no.where" ); |
256 | assertTrue (recipients[3].getRealName() == "Bernie Bar" ); |
257 | assertTrue (recipients[4].getAddress() == "joe.spammer@no.where" ); |
258 | assertTrue (recipients[4].getRealName() == "Joe Spammer" ); |
259 | } |
260 | |
261 | |
262 | void MailMessageTest::testWriteMultiPart() |
263 | { |
264 | MailMessage message; |
265 | MailRecipient r1(MailRecipient::PRIMARY_RECIPIENT, "john.doe@no.where" , "John Doe" ); |
266 | message.addRecipient(r1); |
267 | message.setSubject("Test Message" ); |
268 | message.setSender("poco@appinf.com" ); |
269 | Timestamp ts(0); |
270 | message.setDate(ts); |
271 | message.addContent(new StringPartSource("Hello World!\r\n" , "text/plain" ), MailMessage::ENCODING_8BIT); |
272 | StringPartSource* pSPS = new StringPartSource("This is some binary data. Really." , "application/octet-stream" , "sample.dat" ); |
273 | pSPS->headers().set("Content-ID" , "abcd1234" ); |
274 | message.addAttachment("sample" , pSPS); |
275 | |
276 | assertTrue (message.isMultipart()); |
277 | |
278 | std::ostringstream str; |
279 | message.write(str); |
280 | std::string s = str.str(); |
281 | std::string rawMsg( |
282 | "Date: Thu, 1 Jan 1970 00:00:00 GMT\r\n" |
283 | "Content-Type: multipart/mixed; boundary=$\r\n" |
284 | "Subject: Test Message\r\n" |
285 | "From: poco@appinf.com\r\n" |
286 | "To: John Doe <john.doe@no.where>\r\n" |
287 | "Mime-Version: 1.0\r\n" |
288 | "\r\n" |
289 | "--$\r\n" |
290 | "Content-Type: text/plain\r\n" |
291 | "Content-Transfer-Encoding: 8bit\r\n" |
292 | "Content-Disposition: inline\r\n" |
293 | "\r\n" |
294 | "Hello World!\r\n" |
295 | "\r\n" |
296 | "--$\r\n" |
297 | "Content-ID: abcd1234\r\n" |
298 | "Content-Type: application/octet-stream; name=sample\r\n" |
299 | "Content-Transfer-Encoding: base64\r\n" |
300 | "Content-Disposition: attachment; filename=sample.dat\r\n" |
301 | "\r\n" |
302 | "VGhpcyBpcyBzb21lIGJpbmFyeSBkYXRhLiBSZWFsbHku\r\n" |
303 | "--$--\r\n" |
304 | ); |
305 | std::string::size_type p1 = s.find('=') + 1; |
306 | std::string::size_type p2 = s.find('\r', p1); |
307 | std::string boundary(s, p1, p2 - p1); |
308 | std::string msg; |
309 | for (std::string::const_iterator it = rawMsg.begin(); it != rawMsg.end(); ++it) |
310 | { |
311 | if (*it == '$') |
312 | msg += boundary; |
313 | else |
314 | msg += *it; |
315 | } |
316 | |
317 | assertTrue (s == msg); |
318 | } |
319 | |
320 | |
321 | void MailMessageTest::testReadQP() |
322 | { |
323 | std::istringstream istr( |
324 | "Content-Transfer-Encoding: quoted-printable\r\n" |
325 | "Content-Type: text/plain\r\n" |
326 | "Date: Thu, 1 Jan 1970 00:00:00 GMT\r\n" |
327 | "From: poco@appinf.com\r\n" |
328 | "Subject: Test Message\r\n" |
329 | "To: John Doe <john.doe@no.where>\r\n" |
330 | "\r\n" |
331 | "Hello, world!\r\n" |
332 | "This is a test for the MailMessage class.\r\n" |
333 | "To test the quoted-printable encoding, we'll put an extra long line here. T=\r\n" |
334 | "his should be enough.\r\n" |
335 | "And here is some more =3Dfe.\r\n" |
336 | ); |
337 | |
338 | MailMessage message; |
339 | message.read(istr); |
340 | |
341 | assertTrue (message.getSender() == "poco@appinf.com" ); |
342 | assertTrue (message.getContentType() == "text/plain" ); |
343 | assertTrue (message.getContent() == |
344 | "Hello, world!\r\n" |
345 | "This is a test for the MailMessage class.\r\n" |
346 | "To test the quoted-printable encoding, we'll put an extra long line here. This should be enough.\r\n" |
347 | "And here is some more =fe.\r\n" |
348 | ); |
349 | } |
350 | |
351 | |
352 | void MailMessageTest::testReadDefaultTransferEncoding() |
353 | { |
354 | std::istringstream istr( |
355 | "Content-Type: text/plain\r\n" |
356 | "Date: Thu, 1 Jan 1970 00:00:00 GMT\r\n" |
357 | "From: poco@appinf.com\r\n" |
358 | "Subject: Test Message\r\n" |
359 | "To: John Doe <john.doe@no.where>\r\n" |
360 | "\r\n" |
361 | "Hello, world!\r\n" |
362 | "This is a test for the MailMessage class.\r\n" |
363 | ); |
364 | |
365 | MailMessage message; |
366 | message.read(istr); |
367 | |
368 | assertTrue (message.getSender() == "poco@appinf.com" ); |
369 | assertTrue (message.getContentType() == "text/plain" ); |
370 | assertTrue (message.getContent() == |
371 | "Hello, world!\r\n" |
372 | "This is a test for the MailMessage class.\r\n" |
373 | ); |
374 | } |
375 | |
376 | |
377 | void MailMessageTest::testReadDefaultContentType() |
378 | { |
379 | std::istringstream istr("Date: Thu, 1 Jan 1970 00:00:00 GMT\r\n" |
380 | "From: poco@appinf.com\r\n" |
381 | "Subject: Test Message\r\n" |
382 | "To: John Doe <john.doe@no.where>\r\n" |
383 | "\r\n" |
384 | "Hello, world!\r\n" |
385 | "This is a test for the MailMessage class.\r\n" |
386 | ); |
387 | |
388 | MailMessage message; |
389 | message.read(istr); |
390 | |
391 | assertTrue (message.getSender() == "poco@appinf.com" ); |
392 | assertTrue (message.getContentType() == "text/plain" ); |
393 | assertTrue (message.getContent() == "Hello, world!\r\n" |
394 | "This is a test for the MailMessage class.\r\n" |
395 | ); |
396 | } |
397 | |
398 | |
399 | void MailMessageTest::testRead8Bit() |
400 | { |
401 | std::istringstream istr( |
402 | "Content-Transfer-Encoding: 8bit\r\n" |
403 | "Content-Type: text/plain\r\n" |
404 | "Date: Thu, 1 Jan 1970 00:00:00 GMT\r\n" |
405 | "From: poco@appinf.com\r\n" |
406 | "Subject: Test Message\r\n" |
407 | "To: John Doe <john.doe@no.where>\r\n" |
408 | "\r\n" |
409 | "Hello, world!\r\n" |
410 | "This is a test for the MailMessage class.\r\n" |
411 | ); |
412 | |
413 | MailMessage message; |
414 | message.read(istr); |
415 | |
416 | assertTrue (message.getSender() == "poco@appinf.com" ); |
417 | assertTrue (message.getContentType() == "text/plain" ); |
418 | assertTrue (message.getContent() == |
419 | "Hello, world!\r\n" |
420 | "This is a test for the MailMessage class.\r\n" |
421 | ); |
422 | } |
423 | |
424 | |
425 | void MailMessageTest::testReadMultiPart() |
426 | { |
427 | std::istringstream istr( |
428 | "Content-Type: multipart/mixed; boundary=MIME_boundary_01234567\r\n" |
429 | "Date: Thu, 1 Jan 1970 00:00:00 GMT\r\n" |
430 | "From: poco@appinf.com\r\n" |
431 | "Mime-Version: 1.0\r\n" |
432 | "Subject: Test Message\r\n" |
433 | "To: John Doe <john.doe@no.where>\r\n" |
434 | "\r\n" |
435 | "\r\n" |
436 | "--MIME_boundary_01234567\r\n" |
437 | "Content-Disposition: inline\r\n" |
438 | "Content-Transfer-Encoding: 8bit\r\n" |
439 | "Content-Type: text/plain\r\n" |
440 | "\r\n" |
441 | "Hello World!\r\n" |
442 | "\r\n" |
443 | "--MIME_boundary_01234567\r\n" |
444 | "Content-Disposition: attachment; filename=sample.dat\r\n" |
445 | "Content-Transfer-Encoding: base64\r\n" |
446 | "Content-Type: application/octet-stream; name=sample\r\n" |
447 | "\r\n" |
448 | "VGhpcyBpcyBzb21lIGJpbmFyeSBkYXRhLiBSZWFsbHku\r\n" |
449 | "--MIME_boundary_01234567--\r\n" |
450 | ); |
451 | |
452 | StringPartHandler handler; |
453 | MailMessage message; |
454 | message.read(istr, handler); |
455 | |
456 | assertTrue (handler.data().size() == 2); |
457 | assertTrue (handler.data()[0] == "Hello World!\r\n" ); |
458 | assertTrue (handler.type()[0] == "text/plain" ); |
459 | assertTrue (handler.disp()[0] == "inline" ); |
460 | |
461 | assertTrue (handler.data()[1] == "This is some binary data. Really." ); |
462 | assertTrue (handler.type()[1] == "application/octet-stream; name=sample" ); |
463 | assertTrue (handler.disp()[1] == "attachment; filename=sample.dat" ); |
464 | } |
465 | |
466 | |
467 | void MailMessageTest::testReadMultiPartWithAttachmentNames() |
468 | { |
469 | std::istringstream istr( |
470 | "Content-Type: multipart/mixed; boundary=MIME_boundary_01234567\r\n" |
471 | "Date: Thu, 1 Jan 1970 00:00:00 GMT\r\n" |
472 | "From: poco@appinf.com\r\n" |
473 | "Mime-Version: 1.0\r\n" |
474 | "Subject: Test Message\r\n" |
475 | "To: John Doe <john.doe@no.where>\r\n" |
476 | "\r\n" |
477 | "\r\n" |
478 | "--MIME_boundary_01234567\r\n" |
479 | "Content-Disposition: inline\r\n" |
480 | "Content-Transfer-Encoding: 8bit\r\n" |
481 | "Content-Type: text/plain\r\n" |
482 | "\r\n" |
483 | "Hello World!\r\n" |
484 | "\r\n" |
485 | "--MIME_boundary_01234567\r\n" |
486 | "Content-Disposition: attachment; filename=sample.dat\r\n" |
487 | "Content-Transfer-Encoding: base64\r\n" |
488 | "Content-Type: application/octet-stream; name=sample\r\n" |
489 | "\r\n" |
490 | "VGhpcyBpcyBzb21lIGJpbmFyeSBkYXRhLiBSZWFsbHku\r\n" |
491 | "--MIME_boundary_01234567--\r\n" |
492 | ); |
493 | |
494 | MailMessage message; |
495 | message.read(istr); |
496 | |
497 | assertTrue (message.parts().size() == 2); |
498 | assertTrue (message.parts()[1].name == "sample" ); |
499 | assertTrue (message.parts()[1].pSource->filename() == "sample.dat" ); |
500 | } |
501 | |
502 | |
503 | void MailMessageTest::testReadMultiPartDefaultTransferEncoding() |
504 | { |
505 | std::istringstream istr( |
506 | "Content-Type: multipart/mixed; boundary=MIME_boundary_01234567\r\n" |
507 | "Date: Thu, 1 Jan 1970 00:00:00 GMT\r\n" |
508 | "From: poco@appinf.com\r\n" |
509 | "Mime-Version: 1.0\r\n" |
510 | "Subject: Test Message\r\n" |
511 | "To: John Doe <john.doe@no.where>\r\n" |
512 | "\r\n" |
513 | "\r\n" |
514 | "--MIME_boundary_01234567\r\n" |
515 | "Content-Disposition: inline\r\n" |
516 | "Content-Type: text/plain\r\n" |
517 | "\r\n" |
518 | "Hello World!\r\n" |
519 | "\r\n" |
520 | "--MIME_boundary_01234567\r\n" |
521 | "Content-Disposition: attachment; filename=sample.dat\r\n" |
522 | "Content-Transfer-Encoding: base64\r\n" |
523 | "Content-Type: application/octet-stream; name=sample\r\n" |
524 | "\r\n" |
525 | "VGhpcyBpcyBzb21lIGJpbmFyeSBkYXRhLiBSZWFsbHku\r\n" |
526 | "--MIME_boundary_01234567--\r\n" |
527 | ); |
528 | |
529 | StringPartHandler handler; |
530 | MailMessage message; |
531 | message.read(istr, handler); |
532 | |
533 | assertTrue (handler.data().size() == 2); |
534 | assertTrue (handler.data()[0] == "Hello World!\r\n" ); |
535 | assertTrue (handler.type()[0] == "text/plain" ); |
536 | assertTrue (handler.disp()[0] == "inline" ); |
537 | |
538 | assertTrue (handler.data()[1] == "This is some binary data. Really." ); |
539 | assertTrue (handler.type()[1] == "application/octet-stream; name=sample" ); |
540 | assertTrue (handler.disp()[1] == "attachment; filename=sample.dat" ); |
541 | } |
542 | |
543 | |
544 | void MailMessageTest::testReadWriteMultiPart() |
545 | { |
546 | std::string msgin( |
547 | "Content-Type: multipart/mixed; boundary=MIME_boundary_31E8A8D61DF53389\r\n" |
548 | "Date: Thu, 1 Jan 1970 00:00:00 GMT\r\n" |
549 | "From: poco@appinf.com\r\n" |
550 | "Mime-Version: 1.0\r\n" |
551 | "Subject: Test Message\r\n" |
552 | "To: John Doe <john.doe@no.where>\r\n" |
553 | "\r\n" |
554 | "--MIME_boundary_31E8A8D61DF53389\r\n" |
555 | "Content-Disposition: inline\r\n" |
556 | "Content-Transfer-Encoding: 8bit\r\n" |
557 | "Content-Type: text/plain\r\n" |
558 | "\r\n" |
559 | "Hello World!\r\n" |
560 | "\r\n" |
561 | "--MIME_boundary_31E8A8D61DF53389\r\n" |
562 | "Content-Disposition: attachment; filename=sample.dat\r\n" |
563 | "Content-ID: abcd1234\r\n" |
564 | "Content-Transfer-Encoding: base64\r\n" |
565 | "Content-Type: application/octet-stream; name=sample\r\n" |
566 | "\r\n" |
567 | "VGhpcyBpcyBzb21lIGJpbmFyeSBkYXRhLiBSZWFsbHku\r\n" |
568 | "--MIME_boundary_31E8A8D61DF53389--\r\n" |
569 | ); |
570 | |
571 | std::istringstream istr(msgin); |
572 | std::ostringstream ostr; |
573 | MailMessage message; |
574 | |
575 | message.read(istr); |
576 | message.write(ostr); |
577 | |
578 | std::string msgout(ostr.str()); |
579 | assertTrue (msgout == msgin); |
580 | } |
581 | |
582 | |
583 | void MailMessageTest::testReadWriteMultiPartStore() |
584 | { |
585 | std::string msgin( |
586 | "Content-Type: multipart/mixed; boundary=MIME_boundary_31E8A8D61DF53389\r\n" |
587 | "Date: Thu, 1 Jan 1970 00:00:00 GMT\r\n" |
588 | "From: poco@appinf.com\r\n" |
589 | "Mime-Version: 1.0\r\n" |
590 | "Subject: Test Message\r\n" |
591 | "To: John Doe <john.doe@no.where>\r\n" |
592 | "\r\n" |
593 | "--MIME_boundary_31E8A8D61DF53389\r\n" |
594 | "Content-Disposition: inline\r\n" |
595 | "Content-Transfer-Encoding: 8bit\r\n" |
596 | "Content-Type: text/plain\r\n" |
597 | "\r\n" |
598 | "Hello World!\r\n" |
599 | "\r\n" |
600 | "--MIME_boundary_31E8A8D61DF53389\r\n" |
601 | "Content-Disposition: attachment; filename=sample.dat\r\n" |
602 | "Content-ID: abcd1234\r\n" |
603 | "Content-Transfer-Encoding: base64\r\n" |
604 | "Content-Type: application/octet-stream; name=sample\r\n" |
605 | "\r\n" |
606 | "VGhpcyBpcyBzb21lIGJpbmFyeSBkYXRhLiBSZWFsbHku\r\n" |
607 | "--MIME_boundary_31E8A8D61DF53389--\r\n" |
608 | ); |
609 | |
610 | std::istringstream istr(msgin); |
611 | std::ostringstream ostr; |
612 | FilePartStoreFactory pfsf; |
613 | MailMessage message(&pfsf); |
614 | |
615 | message.read(istr); |
616 | |
617 | MailMessage::PartVec::const_iterator it = message.parts().begin(); |
618 | MailMessage::PartVec::const_iterator end = message.parts().end(); |
619 | for (; it != end; ++it) |
620 | { |
621 | Poco::SharedPtr<FilePartStore> fps = it->pSource.cast<FilePartStore>(); |
622 | if (fps && fps->filename().size()) |
623 | { |
624 | std::string filename = fps->filename(); |
625 | assertTrue (filename == "sample.dat" ); |
626 | std::string path = fps->path(); |
627 | // for security reasons, the filesystem temporary |
628 | // filename is not the same as attachment name |
629 | std::size_t sz = (path.size() > filename.size()) ? filename.size() : path.size(); |
630 | assertTrue (0 != icompare(path, path.size() - sz, sz, path)); |
631 | |
632 | Poco::FileInputStream fis(path); |
633 | assertTrue (fis.good()); |
634 | std::string read; |
635 | std::string line; |
636 | while (std::getline(fis, line)) read += line; |
637 | |
638 | assertTrue (!read.empty()); |
639 | assertTrue (read == "This is some binary data. Really." ); |
640 | } |
641 | } |
642 | |
643 | message.write(ostr); |
644 | std::string msgout(ostr.str()); |
645 | assertTrue (msgout == msgin); |
646 | } |
647 | |
648 | |
649 | void MailMessageTest::testEncodeWord() |
650 | { |
651 | std::string plain("this is pure ASCII" ); |
652 | std::string encoded = MailMessage::encodeWord(plain, "ISO-8859-1" ); |
653 | assertTrue (encoded == plain); |
654 | |
655 | plain = "This text contains German Umlauts: \xC4\xD6" ; |
656 | encoded = MailMessage::encodeWord(plain, "ISO-8859-1" ); |
657 | assertTrue (encoded == "=?ISO-8859-1?q?This_text_contains_German_Umlauts=3A_=C4=D6?=" ); |
658 | |
659 | plain = "This text contains German Umlauts: \xC4\xD6. " |
660 | "It is also a very long text. Longer than 75 " |
661 | "characters. Long enough to become three lines " |
662 | "after being word-encoded." ; |
663 | encoded = MailMessage::encodeWord(plain, "ISO-8859-1" ); |
664 | assertTrue (encoded == "=?ISO-8859-1?q?This_text_contains_German_Umlauts=3A_=C4=D6=2E_It_?=\r\n" |
665 | " =?ISO-8859-1?q?is_also_a_very_long_text=2E_Longer_than_75_characters=2E_?=\r\n" |
666 | " =?ISO-8859-1?q?Long_enough_to_become_three_lines_after_being_word-encode?=\r\n" |
667 | " =?ISO-8859-1?q?d=2E?=" ); |
668 | |
669 | plain = "If you can read this yo" ; |
670 | encoded = MailMessage::encodeWord(plain, "ISO-8859-1" , 'B'); |
671 | assertTrue (encoded == "=?ISO-8859-1?B?SWYgeW91IGNhbiByZWFkIHRoaXMgeW8=?=" ); |
672 | |
673 | plain = "u understand the example." ; |
674 | encoded = MailMessage::encodeWord(plain, "ISO-8859-2" , 'B'); |
675 | assertTrue (encoded == "=?ISO-8859-2?B?dSB1bmRlcnN0YW5kIHRoZSBleGFtcGxlLg==?=" ); |
676 | |
677 | plain = "This text contains German Umlauts: \xC4\xD6. " |
678 | "It is also a very long text. Longer than 75 " |
679 | "characters. Long enough to become three lines " |
680 | "after being word-encoded." ; |
681 | encoded = MailMessage::encodeWord(plain, "ISO-8859-1" , 'B'); |
682 | assertTrue (encoded == |
683 | "=?ISO-8859-1?B?VGhpcyB0ZXh0IGNvbnRhaW5zIEdlcm1hbiBVbWxhdXRzOiDE1i4gSQ==?=\r\n" |
684 | "=?ISO-8859-1?B?dCBpcyBhbHNvIGEgdmVyeSBsb25nIHRleHQuIExvbmdlciB0aGFuIA==?=\r\n" |
685 | "=?ISO-8859-1?B?NzUgY2hhcmFjdGVycy4gTG9uZyBlbm91Z2ggdG8gYmVjb21lIHRocg==?=\r\n" |
686 | "=?ISO-8859-1?B?ZWUgbGluZXMgYWZ0ZXIgYmVpbmcgd29yZC1lbmNvZGVkLg==?=" ); |
687 | |
688 | std::string decoded = MailMessage::decodeWord(encoded); |
689 | assertTrue (decoded == plain); |
690 | } |
691 | |
692 | |
693 | void MailMessageTest::testDecodeWord() |
694 | { |
695 | std::string encoded = "=?ISO-8859-1?q?=C4=D6?=" ; |
696 | std::string decoded = MailMessage::decodeWord(encoded); |
697 | assertTrue (decoded == "\xC4\xD6" ); |
698 | |
699 | encoded = "=?ISO-8859-1?q?=C4=D6?=abc=?ISO-8859-1?q?=C4=D6?=" ; |
700 | decoded = MailMessage::decodeWord(encoded); |
701 | assertTrue (decoded == "\xC4\xD6" "abc" "\xC4\xD6" ); |
702 | |
703 | decoded = MailMessage::decodeWord(encoded, "UTF-8" ); |
704 | assertTrue (decoded == "\xC3\x84\xC3\x96" "abc" "\xC3\x84\xC3\x96" ); |
705 | |
706 | try |
707 | { |
708 | MailMessage::decodeWord("=?ISO-8859-1?q?=C4 =D6?=" ); |
709 | fail("must fail" ); |
710 | } |
711 | catch (Poco::InvalidArgumentException&) {} |
712 | |
713 | try |
714 | { |
715 | MailMessage::decodeWord("=?ISO-8859-1?q?=C4?=D6?=\r\n" ); |
716 | fail("must fail" ); |
717 | } |
718 | catch (Poco::InvalidArgumentException&) {} |
719 | |
720 | encoded = "=?ISO-8859-1?q?=C4=D6_It_?=\r\n=?ISO-8859-1?q?is?=" ; |
721 | decoded = MailMessage::decodeWord(encoded); |
722 | assertTrue (decoded == "\xC4\xD6 It is" ); |
723 | |
724 | encoded = "=?ISO-8859-1?q?This_text_contains_German_Umlauts=3A_=C4=D6?=" ; |
725 | decoded = MailMessage::decodeWord(encoded); |
726 | assertTrue (decoded == "This text contains German Umlauts: \xC4\xD6" ); |
727 | |
728 | decoded = MailMessage::decodeWord(encoded, "UTF-8" ); |
729 | assertTrue (decoded == "This text contains German Umlauts: \xC3\x84\xC3\x96" ); |
730 | |
731 | encoded = "=?ISO-8859-1?q?This_text_contains_German_Umlauts=3A_=C4=D6=2E_It_?=\r\n" |
732 | "=?ISO-8859-1?q?is_also_a_very_long_text=2E_Longer_than_75_characters=2E_?=\r\n" |
733 | "=?ISO-8859-1?q?Long_enough_to_become_three_lines_after_being_word-encode?=\r\n" |
734 | "=?ISO-8859-1?q?d=2E?=" ; |
735 | decoded = MailMessage::decodeWord(encoded); |
736 | assertTrue (decoded == "This text contains German Umlauts: \xC4\xD6. It " |
737 | "is also a very long text. Longer than 75 characters. " |
738 | "Long enough to become three lines after being word-encode" |
739 | "d." ); |
740 | |
741 | decoded = MailMessage::decodeWord(encoded, "UTF-8" ); |
742 | assertTrue (decoded == "This text contains German Umlauts: \xC3\x84\xC3\x96. It " |
743 | "is also a very long text. Longer than 75 characters. " |
744 | "Long enough to become three lines after being word-encode" |
745 | "d." ); |
746 | |
747 | encoded = "=?ISO-8859-1?Q?=F8=E9?=" ; |
748 | decoded = MailMessage::decodeWord(encoded); |
749 | assertTrue (decoded == "\xF8\xE9" ); |
750 | |
751 | encoded = "From: =?US-ASCII?Q?Keith_Moore?= <moore@cs.utk.edu>\r\n" |
752 | "To: =?ISO-8859-1?Q?Keld_J=F8rn_Simonsen?= <keld@dkuug.dk>\r\n" |
753 | "CC: =?ISO-8859-1?Q?Andr=E9?= Pirard <PIRARD@vm1.ulg.ac.be>\r\n" |
754 | "Subject: =?ISO-8859-1?B?SWYgeW91IGNhbiByZWFkIHRoaXMgeW8=?=\r\n" |
755 | "=?ISO-8859-2?B?dSB1bmRlcnN0YW5kIHRoZSBleGFtcGxlLg==?=" ; |
756 | decoded = MailMessage::decodeWord(encoded); |
757 | assertTrue (decoded == "From: Keith Moore <moore@cs.utk.edu>\r\n" |
758 | "To: Keld J\xF8rn Simonsen <keld@dkuug.dk>\r\n" |
759 | "CC: Andr\xE9 Pirard <PIRARD@vm1.ulg.ac.be>\r\n" |
760 | "Subject: If you can read this you understand the example." ); |
761 | |
762 | encoded = "From: =?ISO-8859-1?Q?Olle_J=E4rnefors?= <ojarnef@admin.kth.se>\r\n" |
763 | "To: ietf-822@dimacs.rutgers.edu, ojarnef@admin.kth.se\r\n" |
764 | "Subject: Time for ISO 10646?" ; |
765 | decoded = MailMessage::decodeWord(encoded); |
766 | assertTrue (decoded == "From: Olle J\xE4rnefors <ojarnef@admin.kth.se>\r\n" |
767 | "To: ietf-822@dimacs.rutgers.edu, ojarnef@admin.kth.se\r\n" |
768 | "Subject: Time for ISO 10646?" ); |
769 | |
770 | encoded = "To: Dave Crocker <dcrocker@mordor.stanford.edu>\r\n" |
771 | "Cc: ietf-822@dimacs.rutgers.edu, paf@comsol.se\r\n" |
772 | "From: =?ISO-8859-1?Q?Patrik_F=E4ltstr=F6m?= <paf@nada.kth.se>\r\n" |
773 | "Subject: Re: RFC-HDR care and feeding" ; |
774 | decoded = MailMessage::decodeWord(encoded); |
775 | assertTrue (decoded == "To: Dave Crocker <dcrocker@mordor.stanford.edu>\r\n" |
776 | "Cc: ietf-822@dimacs.rutgers.edu, paf@comsol.se\r\n" |
777 | "From: Patrik F\xE4ltstr\xF6m <paf@nada.kth.se>\r\n" |
778 | "Subject: Re: RFC-HDR care and feeding" ); |
779 | |
780 | // encoded chars cannot be broken between lines |
781 | try |
782 | { |
783 | encoded = "=?ISO-8859-1?Q?=?=\r\n=?ISO-8859-1?Q?AB?=" ; |
784 | decoded = MailMessage::decodeWord(encoded); |
785 | fail("must fail" ); |
786 | } |
787 | catch (Poco::InvalidArgumentException&) {} |
788 | |
789 | // comments and spaces therein |
790 | encoded = "(=?ISO-8859-1?Q?a?=)" ; |
791 | decoded = MailMessage::decodeWord(encoded); |
792 | assertTrue (decoded == "(a)" ); |
793 | |
794 | encoded = "(=?ISO-8859-1?Q?a?= b =?ISO-8859-1?Q?c?=)" ; |
795 | decoded = MailMessage::decodeWord(encoded); |
796 | assertTrue (decoded == "(a b c)" ); |
797 | |
798 | encoded = "(=?ISO-8859-1?Q?a?= =?ISO-8859-1?Q?b?=)" ; |
799 | decoded = MailMessage::decodeWord(encoded); |
800 | assertTrue (decoded == "(ab)" ); |
801 | |
802 | encoded = "(=?ISO-8859-1?Q?a?=\r\n\t=?ISO-8859-1?Q?b?=)" ; |
803 | decoded = MailMessage::decodeWord(encoded); |
804 | assertTrue (decoded == "(ab)" ); |
805 | |
806 | encoded = "(=?ISO-8859-1?Q?a_b?=)" ; |
807 | decoded = MailMessage::decodeWord(encoded); |
808 | assertTrue (decoded == "(a b)" ); |
809 | |
810 | encoded = "(=?ISO-8859-1?Q?a?= =?ISO-8859-2?Q?_b?=)" ; |
811 | decoded = MailMessage::decodeWord(encoded); |
812 | assertTrue (decoded == "(a b)" ); |
813 | } |
814 | |
815 | |
816 | void MailMessageTest::setUp() |
817 | { |
818 | } |
819 | |
820 | |
821 | void MailMessageTest::tearDown() |
822 | { |
823 | } |
824 | |
825 | |
826 | CppUnit::Test* MailMessageTest::suite() |
827 | { |
828 | CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("MailMessageTest" ); |
829 | |
830 | CppUnit_addTest(pSuite, MailMessageTest, testWriteQP); |
831 | CppUnit_addTest(pSuite, MailMessageTest, testWrite8Bit); |
832 | CppUnit_addTest(pSuite, MailMessageTest, testWriteBase64); |
833 | CppUnit_addTest(pSuite, MailMessageTest, testWriteManyRecipients); |
834 | CppUnit_addTest(pSuite, MailMessageTest, testWriteMultiPart); |
835 | CppUnit_addTest(pSuite, MailMessageTest, testReadQP); |
836 | CppUnit_addTest(pSuite, MailMessageTest, testReadDefaultTransferEncoding); |
837 | CppUnit_addTest(pSuite, MailMessageTest, testReadDefaultContentType); |
838 | CppUnit_addTest(pSuite, MailMessageTest, testRead8Bit); |
839 | CppUnit_addTest(pSuite, MailMessageTest, testReadMultiPart); |
840 | CppUnit_addTest(pSuite, MailMessageTest, testReadMultiPartWithAttachmentNames); |
841 | CppUnit_addTest(pSuite, MailMessageTest, testReadMultiPartDefaultTransferEncoding); |
842 | CppUnit_addTest(pSuite, MailMessageTest, testReadWriteMultiPart); |
843 | CppUnit_addTest(pSuite, MailMessageTest, testReadWriteMultiPartStore); |
844 | CppUnit_addTest(pSuite, MailMessageTest, testEncodeWord); |
845 | CppUnit_addTest(pSuite, MailMessageTest, testDecodeWord); |
846 | |
847 | return pSuite; |
848 | } |
849 | |