Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include <sal/types.h>
21 : #include <tools/datetime.hxx>
22 : #include <tools/inetmime.hxx>
23 : #include <tools/inetmsg.hxx>
24 : #include <tools/inetstrm.hxx>
25 : #include <tools/contnr.hxx>
26 : #include <rtl/instance.hxx>
27 : #include <rtl/strbuf.hxx>
28 : #include <comphelper/string.hxx>
29 :
30 : #include <stdio.h>
31 :
32 0 : inline bool ascii_isDigit( sal_Unicode ch )
33 : {
34 0 : return ((ch >= 0x0030) && (ch <= 0x0039));
35 : }
36 :
37 0 : inline bool ascii_isLetter( sal_Unicode ch )
38 : {
39 0 : return (( (ch >= 0x0041) && (ch <= 0x005A)) || ((ch >= 0x0061) && (ch <= 0x007A)));
40 : }
41 :
42 0 : inline sal_Unicode ascii_toLowerCase( sal_Unicode ch )
43 : {
44 0 : if ( (ch >= 0x0041) && (ch <= 0x005A) )
45 0 : return ch + 0x20;
46 : else
47 0 : return ch;
48 : }
49 :
50 : #define CONSTASCII_STRINGPARAM(a) (a), RTL_TEXTENCODING_ASCII_US
51 :
52 0 : INetMessage::~INetMessage()
53 : {
54 0 : ListCleanup_Impl();
55 0 : }
56 :
57 0 : void INetMessage::ListCleanup_Impl()
58 : {
59 : // Cleanup.
60 0 : sal_uIntPtr i, n = m_aHeaderList.size();
61 0 : for (i = 0; i < n; i++)
62 0 : delete m_aHeaderList[ i ];
63 0 : m_aHeaderList.clear();
64 0 : }
65 :
66 0 : void INetMessage::ListCopy (const INetMessage &rMsg)
67 : {
68 0 : if (!(this == &rMsg))
69 : {
70 : // Cleanup.
71 0 : ListCleanup_Impl();
72 :
73 : // Copy.
74 0 : sal_uIntPtr i, n = rMsg.GetHeaderCount();
75 0 : for (i = 0; i < n; i++)
76 : {
77 0 : INetMessageHeader *p = rMsg.m_aHeaderList[ i ];
78 0 : m_aHeaderList.push_back( new INetMessageHeader(*p) );
79 : }
80 : }
81 0 : }
82 :
83 0 : void INetMessage::SetHeaderField_Impl (
84 : INetMIME::HeaderFieldType eType,
85 : const OString &rName,
86 : const OUString &rValue,
87 : sal_uIntPtr &rnIndex)
88 : {
89 0 : INetMIMEStringOutputSink aSink (0, STRING_MAXLEN);
90 : INetMIME::writeHeaderFieldBody (
91 0 : aSink, eType, rValue, osl_getThreadTextEncoding(), false);
92 : SetHeaderField_Impl (
93 0 : INetMessageHeader (rName, aSink.takeBuffer()), rnIndex);
94 0 : }
95 :
96 0 : sal_uIntPtr INetMessage::SetHeaderField (
97 : const INetMessageHeader &rHeader, sal_uIntPtr nIndex)
98 : {
99 0 : sal_uIntPtr nResult = nIndex;
100 0 : SetHeaderField_Impl (rHeader, nResult);
101 0 : return nResult;
102 : }
103 :
104 0 : SvStream& INetMessage::operator<< (SvStream& rStrm) const
105 : {
106 0 : rStrm << static_cast<sal_uInt32>(m_nDocSize);
107 0 : write_lenPrefixed_uInt8s_FromOUString<sal_uInt16>(rStrm, m_aDocName, RTL_TEXTENCODING_UTF8);
108 :
109 0 : sal_uIntPtr i, n = m_aHeaderList.size();
110 0 : rStrm << static_cast<sal_uInt32>(n);
111 :
112 0 : for (i = 0; i < n; i++)
113 0 : rStrm << *( m_aHeaderList[ i ] );
114 :
115 0 : return rStrm;
116 : }
117 :
118 0 : SvStream& INetMessage::operator>> (SvStream& rStrm)
119 : {
120 : // Cleanup.
121 0 : m_nDocSize = 0;
122 0 : m_xDocLB.Clear();
123 0 : ListCleanup_Impl();
124 :
125 : sal_uInt32 nTemp;
126 :
127 : // Copy.
128 0 : rStrm >> nTemp;
129 0 : m_nDocSize = nTemp;
130 0 : m_aDocName = read_lenPrefixed_uInt8s_ToOUString<sal_uInt16>(rStrm, RTL_TEXTENCODING_UTF8);
131 :
132 0 : sal_uIntPtr i, n = 0;
133 0 : rStrm >> nTemp;
134 0 : n = nTemp;
135 :
136 0 : for (i = 0; i < n; i++)
137 : {
138 0 : INetMessageHeader *p = new INetMessageHeader();
139 0 : rStrm >> *p;
140 0 : m_aHeaderList.push_back( p );
141 : }
142 :
143 : // Done.
144 0 : return rStrm;
145 : }
146 :
147 : namespace
148 : {
149 : struct ImplINetRFC822MessageHeaderDataImpl
150 : {
151 0 : const OString* operator()()
152 : {
153 : static const OString _ImplINetRFC822MessageHeaderData[] =
154 : {
155 : OString(RTL_CONSTASCII_STRINGPARAM("BCC")),
156 : OString(RTL_CONSTASCII_STRINGPARAM("CC")),
157 : OString(RTL_CONSTASCII_STRINGPARAM("Comments")),
158 : OString(RTL_CONSTASCII_STRINGPARAM("Date")),
159 : OString(RTL_CONSTASCII_STRINGPARAM("From")),
160 : OString(RTL_CONSTASCII_STRINGPARAM("In-Reply-To")),
161 : OString(RTL_CONSTASCII_STRINGPARAM("Keywords")),
162 : OString(RTL_CONSTASCII_STRINGPARAM("Message-ID")),
163 : OString(RTL_CONSTASCII_STRINGPARAM("References")),
164 : OString(RTL_CONSTASCII_STRINGPARAM("Reply-To")),
165 : OString(RTL_CONSTASCII_STRINGPARAM("Return-Path")),
166 : OString(RTL_CONSTASCII_STRINGPARAM("Subject")),
167 : OString(RTL_CONSTASCII_STRINGPARAM("Sender")),
168 : OString(RTL_CONSTASCII_STRINGPARAM("To")),
169 : OString(RTL_CONSTASCII_STRINGPARAM("X-Mailer")),
170 : OString(RTL_CONSTASCII_STRINGPARAM("Return-Receipt-To"))
171 0 : };
172 0 : return &_ImplINetRFC822MessageHeaderData[0];
173 : }
174 : };
175 :
176 : struct ImplINetRFC822MessageHeaderData
177 : : public rtl::StaticAggregate< const OString, ImplINetRFC822MessageHeaderDataImpl > {};
178 : }
179 :
180 : #define HDR(n) ImplINetRFC822MessageHeaderData::get()[(n)]
181 :
182 : enum _ImplINetRFC822MessageHeaderState
183 : {
184 : INETMSG_RFC822_BEGIN,
185 : INETMSG_RFC822_CHECK,
186 : INETMSG_RFC822_OK,
187 : INETMSG_RFC822_JUNK,
188 :
189 : INETMSG_RFC822_TOKEN_RE,
190 : INETMSG_RFC822_TOKEN_RETURNMINUS,
191 : INETMSG_RFC822_TOKEN_XMINUS,
192 : INETMSG_RFC822_LETTER_C,
193 : INETMSG_RFC822_LETTER_S
194 : };
195 :
196 0 : INetRFC822Message::INetRFC822Message()
197 0 : : INetMessage()
198 : {
199 0 : for (sal_uInt16 i = 0; i < INETMSG_RFC822_NUMHDR; i++)
200 0 : m_nIndex[i] = CONTAINER_ENTRY_NOTFOUND;
201 0 : }
202 :
203 0 : INetRFC822Message::INetRFC822Message (const INetRFC822Message& rMsg)
204 0 : : INetMessage (rMsg)
205 : {
206 0 : for (sal_uInt16 i = 0; i < INETMSG_RFC822_NUMHDR; i++)
207 0 : m_nIndex[i] = rMsg.m_nIndex[i];
208 0 : }
209 :
210 0 : INetRFC822Message& INetRFC822Message::operator= (const INetRFC822Message& rMsg)
211 : {
212 0 : if (this != &rMsg)
213 : {
214 0 : INetMessage::operator= (rMsg);
215 :
216 0 : for (sal_uInt16 i = 0; i < INETMSG_RFC822_NUMHDR; i++)
217 0 : m_nIndex[i] = rMsg.m_nIndex[i];
218 : }
219 0 : return *this;
220 : }
221 :
222 0 : INetRFC822Message::~INetRFC822Message()
223 : {
224 0 : }
225 :
226 : /* ParseDateField and local helper functions.
227 : *
228 : * Parses a String in (implied) GMT format into class Date and Time objects.
229 : * Four formats are accepted:
230 : *
231 : * [Wkd,] 1*2DIGIT Mon 2*4DIGIT 00:00:00 [GMT] (rfc1123)
232 : * [Wkd,] 00 Mon 0000 00:00:00 [GMT]) (rfc822, rfc1123)
233 : * Weekday, 00-Mon-00 00:00:00 [GMT] (rfc850, rfc1036)
234 : * Wkd Mon 00 00:00:00 0000 [GMT] (ctime)
235 : * 1*DIGIT (delta seconds)
236 : */
237 :
238 : static const sal_Char *months[12] =
239 : {
240 : "Jan", "Feb", "Mar", "Apr", "May", "Jun",
241 : "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
242 : };
243 :
244 0 : static sal_uInt16 ParseNumber(const OString& rStr, sal_uInt16& nIndex)
245 : {
246 0 : sal_uInt16 n = nIndex;
247 0 : while ((n < rStr.getLength()) && ascii_isDigit(rStr[n])) n++;
248 :
249 0 : OString aNum(rStr.copy(nIndex, (n - nIndex)));
250 0 : nIndex = n;
251 :
252 0 : return (sal_uInt16)(aNum.toInt32());
253 : }
254 :
255 0 : static sal_uInt16 ParseMonth(const OString& rStr, sal_uInt16& nIndex)
256 : {
257 0 : sal_uInt16 n = nIndex;
258 0 : while ((n < rStr.getLength()) && ascii_isLetter(rStr[n])) n++;
259 :
260 0 : OString aMonth(rStr.copy(nIndex, 3));
261 0 : nIndex = n;
262 :
263 : sal_uInt16 i;
264 0 : for (i = 0; i < 12; i++)
265 0 : if (aMonth.equalsIgnoreAsciiCase(months[i])) break;
266 0 : return (i + 1);
267 : }
268 :
269 0 : bool INetRFC822Message::ParseDateField (
270 : const OUString& rDateFieldW, DateTime& rDateTime)
271 : {
272 : OString aDateField(OUStringToOString(rDateFieldW,
273 0 : RTL_TEXTENCODING_ASCII_US));
274 :
275 0 : if (aDateField.isEmpty()) return false;
276 :
277 0 : if (aDateField.indexOf(':') != -1)
278 : {
279 : // Some DateTime format.
280 0 : sal_uInt16 nIndex = 0;
281 :
282 : // Skip over <Wkd> or <Weekday>, leading and trailing space.
283 0 : while ((nIndex < aDateField.getLength()) &&
284 0 : (aDateField[nIndex] == ' '))
285 0 : nIndex++;
286 :
287 0 : while (
288 0 : (nIndex < aDateField.getLength()) &&
289 0 : (ascii_isLetter (aDateField[nIndex]) ||
290 0 : (aDateField[nIndex] == ',') ))
291 0 : nIndex++;
292 :
293 0 : while ((nIndex < aDateField.getLength()) &&
294 0 : (aDateField[nIndex] == ' '))
295 0 : nIndex++;
296 :
297 0 : if (ascii_isLetter (aDateField[nIndex]))
298 : {
299 : // Format: ctime().
300 0 : if ((aDateField.getLength() - nIndex) < 20) return false;
301 :
302 0 : rDateTime.SetMonth (ParseMonth (aDateField, nIndex)); nIndex++;
303 0 : rDateTime.SetDay (ParseNumber (aDateField, nIndex)); nIndex++;
304 :
305 0 : rDateTime.SetHour (ParseNumber (aDateField, nIndex)); nIndex++;
306 0 : rDateTime.SetMin (ParseNumber (aDateField, nIndex)); nIndex++;
307 0 : rDateTime.SetSec (ParseNumber (aDateField, nIndex)); nIndex++;
308 0 : rDateTime.Set100Sec (0);
309 :
310 0 : sal_uInt16 nYear = ParseNumber (aDateField, nIndex);
311 0 : if (nYear < 100) nYear += 1900;
312 0 : rDateTime.SetYear (nYear);
313 : }
314 : else
315 : {
316 : // Format: RFC1036 or RFC1123.
317 0 : if ((aDateField.getLength() - nIndex) < 17) return false;
318 :
319 0 : rDateTime.SetDay (ParseNumber (aDateField, nIndex)); nIndex++;
320 0 : rDateTime.SetMonth (ParseMonth (aDateField, nIndex)); nIndex++;
321 :
322 0 : sal_uInt16 nYear = ParseNumber (aDateField, nIndex); nIndex++;
323 0 : if (nYear < 100) nYear += 1900;
324 0 : rDateTime.SetYear (nYear);
325 :
326 0 : rDateTime.SetHour (ParseNumber (aDateField, nIndex)); nIndex++;
327 0 : rDateTime.SetMin (ParseNumber (aDateField, nIndex)); nIndex++;
328 0 : rDateTime.SetSec (ParseNumber (aDateField, nIndex)); nIndex++;
329 0 : rDateTime.Set100Sec (0);
330 :
331 0 : if ((aDateField[nIndex] == '+') ||
332 0 : (aDateField[nIndex] == '-') )
333 : {
334 : // Offset from GMT: "(+|-)HHMM".
335 0 : bool bEast = (aDateField[nIndex++] == '+');
336 0 : sal_uInt16 nOffset = ParseNumber (aDateField, nIndex);
337 0 : if (nOffset > 0)
338 : {
339 0 : Time aDiff( Time::EMPTY );
340 0 : aDiff.SetHour (nOffset / 100);
341 0 : aDiff.SetMin (nOffset % 100);
342 0 : aDiff.SetSec (0);
343 0 : aDiff.Set100Sec (0);
344 :
345 0 : if (bEast)
346 0 : rDateTime -= aDiff;
347 : else
348 0 : rDateTime += aDiff;
349 : }
350 : }
351 : }
352 : }
353 0 : else if (comphelper::string::isdigitAsciiString(aDateField))
354 : {
355 : // Format: delta seconds.
356 0 : Time aDelta (0);
357 0 : aDelta.SetTime (aDateField.toInt32() * 100);
358 :
359 0 : DateTime aNow( DateTime::SYSTEM );
360 0 : aNow += aDelta;
361 0 : aNow.ConvertToUTC();
362 :
363 0 : rDateTime.SetDate (aNow.GetDate());
364 0 : rDateTime.SetTime (aNow.GetTime());
365 : }
366 : else
367 : {
368 : // Junk.
369 0 : return false;
370 : }
371 :
372 0 : return (rDateTime.IsValidAndGregorian() &&
373 0 : !((rDateTime.GetSec() > 59) ||
374 0 : (rDateTime.GetMin() > 59) ||
375 0 : (rDateTime.GetHour() > 23) ));
376 : }
377 :
378 : // Header Field Parser
379 0 : sal_uIntPtr INetRFC822Message::SetHeaderField (
380 : const INetMessageHeader &rHeader, sal_uIntPtr nNewIndex)
381 : {
382 0 : OString aName (rHeader.GetName());
383 0 : const sal_Char *pData = aName.getStr();
384 0 : const sal_Char *pStop = pData + aName.getLength() + 1;
385 0 : const sal_Char *check = "";
386 :
387 0 : sal_uIntPtr nIdx = LIST_APPEND;
388 0 : int eState = INETMSG_RFC822_BEGIN;
389 0 : int eOkState = INETMSG_RFC822_OK;
390 :
391 0 : while (pData < pStop)
392 : {
393 0 : switch (eState)
394 : {
395 : case INETMSG_RFC822_BEGIN:
396 0 : eState = INETMSG_RFC822_CHECK;
397 0 : eOkState = INETMSG_RFC822_OK;
398 :
399 0 : switch (ascii_toLowerCase (*pData))
400 : {
401 : case 'b':
402 0 : check = "cc";
403 0 : nIdx = INETMSG_RFC822_BCC;
404 0 : break;
405 :
406 : case 'c':
407 0 : eState = INETMSG_RFC822_LETTER_C;
408 0 : break;
409 :
410 : case 'd':
411 0 : check = "ate";
412 0 : nIdx = INETMSG_RFC822_DATE;
413 0 : break;
414 :
415 : case 'f':
416 0 : check = "rom";
417 0 : nIdx = INETMSG_RFC822_FROM;
418 0 : break;
419 :
420 : case 'i':
421 0 : check = "n-reply-to";
422 0 : nIdx = INETMSG_RFC822_IN_REPLY_TO;
423 0 : break;
424 :
425 : case 'k':
426 0 : check = "eywords";
427 0 : nIdx = INETMSG_RFC822_KEYWORDS;
428 0 : break;
429 :
430 : case 'm':
431 0 : check = "essage-id";
432 0 : nIdx = INETMSG_RFC822_MESSAGE_ID;
433 0 : break;
434 :
435 : case 'r':
436 0 : check = "e";
437 0 : eOkState = INETMSG_RFC822_TOKEN_RE;
438 0 : break;
439 :
440 : case 's':
441 0 : eState = INETMSG_RFC822_LETTER_S;
442 0 : break;
443 :
444 : case 't':
445 0 : check = "o";
446 0 : nIdx = INETMSG_RFC822_TO;
447 0 : break;
448 :
449 : case 'x':
450 0 : check = "-";
451 0 : eOkState = INETMSG_RFC822_TOKEN_XMINUS;
452 0 : break;
453 :
454 : default:
455 0 : eState = INETMSG_RFC822_JUNK;
456 0 : break;
457 : }
458 0 : pData++;
459 0 : break;
460 :
461 : case INETMSG_RFC822_TOKEN_RE:
462 0 : eState = INETMSG_RFC822_CHECK;
463 0 : eOkState = INETMSG_RFC822_OK;
464 :
465 0 : switch (ascii_toLowerCase (*pData))
466 : {
467 : case 'f':
468 0 : check = "erences";
469 0 : nIdx = INETMSG_RFC822_REFERENCES;
470 0 : break;
471 :
472 : case 'p':
473 0 : check = "ly-to";
474 0 : nIdx = INETMSG_RFC822_REPLY_TO;
475 0 : break;
476 :
477 : case 't':
478 0 : check = "urn-";
479 0 : eOkState = INETMSG_RFC822_TOKEN_RETURNMINUS;
480 0 : break;
481 :
482 : default:
483 0 : eState = INETMSG_RFC822_JUNK;
484 0 : break;
485 : }
486 0 : pData++;
487 0 : break;
488 :
489 : case INETMSG_RFC822_TOKEN_RETURNMINUS:
490 0 : eState = INETMSG_RFC822_CHECK;
491 0 : eOkState = INETMSG_RFC822_OK;
492 :
493 0 : switch (ascii_toLowerCase (*pData))
494 : {
495 : case 'p':
496 0 : check = "ath";
497 0 : nIdx = INETMSG_RFC822_RETURN_PATH;
498 0 : break;
499 :
500 : case 'r':
501 0 : check = "eceipt-to";
502 0 : nIdx = INETMSG_RFC822_RETURN_RECEIPT_TO;
503 0 : break;
504 :
505 : default:
506 0 : eState = INETMSG_RFC822_JUNK;
507 0 : break;
508 : }
509 0 : pData++;
510 0 : break;
511 :
512 : case INETMSG_RFC822_TOKEN_XMINUS:
513 0 : eState = INETMSG_RFC822_CHECK;
514 0 : eOkState = INETMSG_RFC822_OK;
515 :
516 0 : switch (ascii_toLowerCase (*pData))
517 : {
518 : case 'm':
519 0 : check = "ailer";
520 0 : nIdx = INETMSG_RFC822_X_MAILER;
521 0 : break;
522 :
523 : default:
524 0 : eState = INETMSG_RFC822_JUNK;
525 0 : break;
526 : }
527 0 : pData++;
528 0 : break;
529 :
530 : case INETMSG_RFC822_LETTER_C:
531 0 : eState = INETMSG_RFC822_CHECK;
532 0 : eOkState = INETMSG_RFC822_OK;
533 :
534 0 : switch (ascii_toLowerCase (*pData))
535 : {
536 : case 'c':
537 0 : check = "";
538 0 : nIdx = INETMSG_RFC822_CC;
539 0 : break;
540 :
541 : case 'o':
542 0 : check = "mments";
543 0 : nIdx = INETMSG_RFC822_COMMENTS;
544 0 : break;
545 :
546 : default:
547 0 : eState = INETMSG_RFC822_JUNK;
548 0 : break;
549 : }
550 0 : pData++;
551 0 : break;
552 :
553 : case INETMSG_RFC822_LETTER_S:
554 0 : eState = INETMSG_RFC822_CHECK;
555 0 : eOkState = INETMSG_RFC822_OK;
556 :
557 0 : switch (ascii_toLowerCase (*pData))
558 : {
559 : case 'e':
560 0 : check = "nder";
561 0 : nIdx = INETMSG_RFC822_SENDER;
562 0 : break;
563 :
564 : case 'u':
565 0 : check = "bject";
566 0 : nIdx = INETMSG_RFC822_SUBJECT;
567 0 : break;
568 :
569 : default:
570 0 : eState = INETMSG_RFC822_JUNK;
571 0 : break;
572 : }
573 0 : pData++;
574 0 : break;
575 :
576 : case INETMSG_RFC822_CHECK:
577 0 : if (*check)
578 : {
579 0 : while (*pData && *check &&
580 0 : (ascii_toLowerCase (*pData) == *check))
581 : {
582 0 : pData++;
583 0 : check++;
584 : }
585 : }
586 : else
587 : {
588 0 : check = pData;
589 : }
590 0 : eState = (*check == '\0') ? eOkState : INETMSG_RFC822_JUNK;
591 0 : break;
592 :
593 : case INETMSG_RFC822_OK:
594 0 : pData = pStop;
595 : SetHeaderField_Impl (
596 0 : INetMessageHeader (HDR(nIdx), rHeader.GetValue()),
597 0 : m_nIndex[nIdx]);
598 0 : nNewIndex = m_nIndex[nIdx];
599 0 : break;
600 :
601 : default: // INETMSG_RFC822_JUNK
602 0 : pData = pStop;
603 0 : nNewIndex = INetMessage::SetHeaderField (rHeader, nNewIndex);
604 0 : break;
605 : }
606 : }
607 0 : return nNewIndex;
608 : }
609 :
610 0 : SvStream& INetRFC822Message::operator<< (SvStream& rStrm) const
611 : {
612 0 : INetMessage::operator<< (rStrm);
613 :
614 0 : for (sal_uInt16 i = 0; i < INETMSG_RFC822_NUMHDR; i++)
615 0 : rStrm << static_cast<sal_uInt32>(m_nIndex[i]);
616 :
617 0 : return rStrm;
618 : }
619 :
620 0 : SvStream& INetRFC822Message::operator>> (SvStream& rStrm)
621 : {
622 0 : INetMessage::operator>> (rStrm);
623 :
624 : sal_uInt32 nTemp;
625 0 : for (sal_uInt16 i = 0; i < INETMSG_RFC822_NUMHDR; i++)
626 : {
627 0 : rStrm >> nTemp;
628 0 : m_nIndex[i] = nTemp;
629 : }
630 :
631 0 : return rStrm;
632 : }
633 :
634 : namespace
635 : {
636 : struct ImplINetMIMEMessageHeaderDataImpl
637 : {
638 0 : const OString* operator()()
639 : {
640 : static const OString _ImplINetMIMEMessageHeaderData[] =
641 : {
642 : OString(RTL_CONSTASCII_STRINGPARAM("MIME-Version")),
643 : OString(RTL_CONSTASCII_STRINGPARAM("Content-Description")),
644 : OString(RTL_CONSTASCII_STRINGPARAM("Content-Disposition")),
645 : OString(RTL_CONSTASCII_STRINGPARAM("Content-ID")),
646 : OString(RTL_CONSTASCII_STRINGPARAM("Content-Type")),
647 : OString(RTL_CONSTASCII_STRINGPARAM("Content-Transfer-Encoding"))
648 0 : };
649 0 : return &_ImplINetMIMEMessageHeaderData[0];
650 : }
651 : };
652 :
653 : struct ImplINetMIMEMessageHeaderData
654 : : public rtl::StaticAggregate< const OString, ImplINetMIMEMessageHeaderDataImpl > {};
655 : }
656 :
657 : #define MIMEHDR(n) ImplINetMIMEMessageHeaderData::get()[(n)]
658 :
659 : enum _ImplINetMIMEMessageHeaderState
660 : {
661 : INETMSG_MIME_BEGIN,
662 : INETMSG_MIME_CHECK,
663 : INETMSG_MIME_OK,
664 : INETMSG_MIME_JUNK,
665 :
666 : INETMSG_MIME_TOKEN_CONTENT,
667 : INETMSG_MIME_TOKEN_CONTENT_D,
668 : INETMSG_MIME_TOKEN_CONTENT_T
669 : };
670 :
671 0 : INetMIMEMessage::INetMIMEMessage()
672 : : INetRFC822Message (),
673 : pParent (NULL),
674 0 : bHeaderParsed (false)
675 : {
676 0 : for (sal_uInt16 i = 0; i < INETMSG_MIME_NUMHDR; i++)
677 0 : m_nIndex[i] = CONTAINER_ENTRY_NOTFOUND;
678 0 : }
679 :
680 0 : INetMIMEMessage::INetMIMEMessage (const INetMIMEMessage& rMsg)
681 0 : : INetRFC822Message (rMsg)
682 : {
683 0 : CopyImp (rMsg);
684 0 : }
685 :
686 0 : INetMIMEMessage& INetMIMEMessage::operator= (
687 : const INetMIMEMessage& rMsg)
688 : {
689 0 : if (this != &rMsg)
690 : {
691 : // Assign base.
692 0 : INetRFC822Message::operator= (rMsg);
693 :
694 0 : CleanupImp();
695 0 : CopyImp (rMsg);
696 : }
697 0 : return *this;
698 : }
699 :
700 0 : INetMIMEMessage::~INetMIMEMessage()
701 : {
702 0 : CleanupImp();
703 0 : }
704 :
705 0 : void INetMIMEMessage::CleanupImp()
706 : {
707 0 : for( size_t i = 0, n = aChildren.size(); i < n; ++i ) {
708 0 : delete aChildren[ i ];
709 : }
710 0 : aChildren.clear();
711 0 : }
712 :
713 0 : void INetMIMEMessage::CopyImp (const INetMIMEMessage& rMsg)
714 : {
715 0 : bHeaderParsed = rMsg.bHeaderParsed;
716 :
717 : size_t i;
718 0 : for (i = 0; i < INETMSG_MIME_NUMHDR; i++)
719 0 : m_nIndex[i] = rMsg.m_nIndex[i];
720 :
721 0 : m_aBoundary = rMsg.m_aBoundary;
722 :
723 0 : for (i = 0; i < rMsg.aChildren.size(); i++)
724 : {
725 0 : INetMIMEMessage *pChild = rMsg.aChildren[ i ];
726 :
727 0 : if (pChild->pParent == &rMsg)
728 : {
729 0 : pChild = pChild->CreateMessage (*pChild);
730 0 : pChild->pParent = this;
731 : }
732 0 : aChildren.push_back( pChild );
733 : }
734 0 : }
735 :
736 0 : INetMIMEMessage *INetMIMEMessage::CreateMessage (
737 : const INetMIMEMessage& rMsg) const
738 : {
739 0 : return (new INetMIMEMessage (rMsg));
740 : }
741 :
742 : // Header Field Parser
743 0 : sal_uIntPtr INetMIMEMessage::SetHeaderField (
744 : const INetMessageHeader &rHeader, sal_uIntPtr nNewIndex)
745 : {
746 0 : OString aName (rHeader.GetName());
747 0 : const sal_Char *pData = aName.getStr();
748 0 : const sal_Char *pStop = pData + aName.getLength() + 1;
749 0 : const sal_Char *check = "";
750 :
751 0 : sal_uIntPtr nIdx = LIST_APPEND;
752 0 : int eState = INETMSG_MIME_BEGIN;
753 0 : int eOkState = INETMSG_MIME_OK;
754 :
755 0 : while (pData < pStop)
756 : {
757 0 : switch (eState)
758 : {
759 : case INETMSG_MIME_BEGIN:
760 0 : eState = INETMSG_MIME_CHECK;
761 0 : eOkState = INETMSG_MIME_OK;
762 :
763 0 : switch (ascii_toLowerCase (*pData))
764 : {
765 : case 'c':
766 0 : check = "ontent-";
767 0 : eOkState = INETMSG_MIME_TOKEN_CONTENT;
768 0 : break;
769 :
770 : case 'm':
771 0 : check = "ime-version";
772 0 : nIdx = INETMSG_MIME_VERSION;
773 0 : break;
774 :
775 : default:
776 0 : eState = INETMSG_MIME_JUNK;
777 0 : break;
778 : }
779 0 : pData++;
780 0 : break;
781 :
782 : case INETMSG_MIME_TOKEN_CONTENT:
783 0 : eState = INETMSG_MIME_CHECK;
784 0 : eOkState = INETMSG_MIME_OK;
785 :
786 0 : switch (ascii_toLowerCase (*pData))
787 : {
788 : case 'd':
789 0 : eState = INETMSG_MIME_TOKEN_CONTENT_D;
790 0 : break;
791 :
792 : case 'i':
793 0 : check = "d";
794 0 : nIdx = INETMSG_MIME_CONTENT_ID;
795 0 : break;
796 :
797 : case 't':
798 0 : eState = INETMSG_MIME_TOKEN_CONTENT_T;
799 0 : break;
800 :
801 : default:
802 0 : eState = INETMSG_MIME_JUNK;
803 0 : break;
804 : }
805 0 : pData++;
806 0 : break;
807 :
808 : case INETMSG_MIME_TOKEN_CONTENT_D:
809 0 : eState = INETMSG_MIME_CHECK;
810 0 : eOkState = INETMSG_MIME_OK;
811 :
812 0 : switch (ascii_toLowerCase (*pData))
813 : {
814 : case 'e':
815 0 : check = "scription";
816 0 : nIdx = INETMSG_MIME_CONTENT_DESCRIPTION;
817 0 : break;
818 :
819 : case 'i':
820 0 : check = "sposition";
821 0 : nIdx = INETMSG_MIME_CONTENT_DISPOSITION;
822 0 : break;
823 :
824 : default:
825 0 : eState = INETMSG_MIME_JUNK;
826 0 : break;
827 : }
828 0 : pData++;
829 0 : break;
830 :
831 : case INETMSG_MIME_TOKEN_CONTENT_T:
832 0 : eState = INETMSG_MIME_CHECK;
833 0 : eOkState = INETMSG_MIME_OK;
834 :
835 0 : switch (ascii_toLowerCase (*pData))
836 : {
837 : case 'r':
838 0 : check = "ansfer-encoding";
839 0 : nIdx = INETMSG_MIME_CONTENT_TRANSFER_ENCODING;
840 0 : break;
841 :
842 : case 'y':
843 0 : check = "pe";
844 0 : nIdx = INETMSG_MIME_CONTENT_TYPE;
845 0 : break;
846 :
847 : default:
848 0 : eState = INETMSG_MIME_JUNK;
849 0 : break;
850 : }
851 0 : pData++;
852 0 : break;
853 :
854 : case INETMSG_MIME_CHECK:
855 0 : if (*check)
856 : {
857 0 : while (*pData && *check &&
858 0 : (ascii_toLowerCase (*pData) == *check))
859 : {
860 0 : pData++;
861 0 : check++;
862 : }
863 : }
864 : else
865 : {
866 0 : check = pData;
867 : }
868 0 : eState = (*check == '\0') ? eOkState : INETMSG_MIME_JUNK;
869 0 : break;
870 :
871 : case INETMSG_MIME_OK:
872 0 : pData = pStop;
873 : SetHeaderField_Impl (
874 0 : INetMessageHeader (MIMEHDR(nIdx), rHeader.GetValue()),
875 0 : m_nIndex[nIdx]);
876 0 : nNewIndex = m_nIndex[nIdx];
877 0 : break;
878 :
879 : default: // INETMSG_MIME_JUNK
880 0 : pData = pStop;
881 : nNewIndex = INetRFC822Message::SetHeaderField (
882 0 : rHeader, nNewIndex);
883 0 : break;
884 : }
885 : }
886 0 : return nNewIndex;
887 : }
888 :
889 0 : void INetMIMEMessage::SetMIMEVersion (const OUString& rVersion)
890 : {
891 : SetHeaderField_Impl (
892 : INetMIME::HEADER_FIELD_TEXT,
893 0 : MIMEHDR(INETMSG_MIME_VERSION), rVersion,
894 0 : m_nIndex[INETMSG_MIME_VERSION]);
895 0 : }
896 :
897 0 : void INetMIMEMessage::SetContentDisposition (const OUString& rDisposition)
898 : {
899 : SetHeaderField_Impl (
900 : INetMIME::HEADER_FIELD_TEXT,
901 0 : MIMEHDR(INETMSG_MIME_CONTENT_DISPOSITION), rDisposition,
902 0 : m_nIndex[INETMSG_MIME_CONTENT_DISPOSITION]);
903 0 : }
904 :
905 0 : void INetMIMEMessage::SetContentType (const OUString& rType)
906 : {
907 : SetHeaderField_Impl (
908 : INetMIME::HEADER_FIELD_TEXT,
909 0 : MIMEHDR(INETMSG_MIME_CONTENT_TYPE), rType,
910 0 : m_nIndex[INETMSG_MIME_CONTENT_TYPE]);
911 0 : }
912 :
913 0 : void INetMIMEMessage::SetContentTransferEncoding (
914 : const OUString& rEncoding)
915 : {
916 : SetHeaderField_Impl (
917 : INetMIME::HEADER_FIELD_TEXT,
918 0 : MIMEHDR(INETMSG_MIME_CONTENT_TRANSFER_ENCODING), rEncoding,
919 0 : m_nIndex[INETMSG_MIME_CONTENT_TRANSFER_ENCODING]);
920 0 : }
921 :
922 0 : OUString INetMIMEMessage::GetDefaultContentType()
923 : {
924 0 : if (pParent != NULL)
925 : {
926 0 : OUString aParentCT (pParent->GetContentType());
927 0 : if (aParentCT.isEmpty())
928 0 : aParentCT = pParent->GetDefaultContentType();
929 :
930 0 : if (aParentCT.equalsIgnoreAsciiCase("multipart/digest"))
931 0 : return OUString("message/rfc822");
932 : }
933 0 : return OUString("text/plain; charset=us-ascii");
934 : }
935 :
936 0 : bool INetMIMEMessage::EnableAttachChild (INetMessageContainerType eType)
937 : {
938 : // Check context.
939 0 : if (IsContainer())
940 0 : return false;
941 :
942 : // Setup Content-Type header field.
943 0 : OStringBuffer aContentType;
944 0 : switch (eType)
945 : {
946 : case INETMSG_MESSAGE_RFC822:
947 0 : aContentType.append(RTL_CONSTASCII_STRINGPARAM("message/rfc822"));
948 0 : break;
949 :
950 : case INETMSG_MULTIPART_ALTERNATIVE:
951 0 : aContentType.append(RTL_CONSTASCII_STRINGPARAM("multipart/alternative"));
952 0 : break;
953 :
954 : case INETMSG_MULTIPART_DIGEST:
955 0 : aContentType.append(RTL_CONSTASCII_STRINGPARAM("multipart/digest"));
956 0 : break;
957 :
958 : case INETMSG_MULTIPART_PARALLEL:
959 0 : aContentType.append(RTL_CONSTASCII_STRINGPARAM("multipart/parallel"));
960 0 : break;
961 :
962 : case INETMSG_MULTIPART_RELATED:
963 0 : aContentType.append(RTL_CONSTASCII_STRINGPARAM("multipart/related"));
964 0 : break;
965 :
966 : case INETMSG_MULTIPART_FORM_DATA:
967 0 : aContentType.append(RTL_CONSTASCII_STRINGPARAM("multipart/form-data"));
968 0 : break;
969 :
970 : default:
971 0 : aContentType.append(RTL_CONSTASCII_STRINGPARAM("multipart/mixed"));
972 0 : break;
973 : }
974 :
975 : // Setup boundary for multipart types.
976 0 : if (aContentType.toString().equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("multipart/")))
977 : {
978 : // Generate a unique boundary from current time.
979 : sal_Char sTail[16 + 1];
980 0 : Time aCurTime( Time::SYSTEM );
981 0 : sal_uInt64 nThis = reinterpret_cast< sal_uIntPtr >( this ); // we can be on a 64bit architecture
982 0 : nThis = ( ( nThis >> 32 ) ^ nThis ) & SAL_MAX_UINT32;
983 : sprintf (sTail, "%08X%08X",
984 0 : static_cast< unsigned int >(aCurTime.GetTime()),
985 0 : static_cast< unsigned int >(nThis));
986 0 : m_aBoundary = "------------_4D48";
987 0 : m_aBoundary += sTail;
988 :
989 : // Append boundary as ContentType parameter.
990 0 : aContentType.append(RTL_CONSTASCII_STRINGPARAM("; boundary="));
991 0 : aContentType.append(m_aBoundary);
992 : }
993 :
994 : // Set header fields.
995 0 : SetMIMEVersion(OUString("1.0"));
996 0 : SetContentType(OStringToOUString(aContentType.makeStringAndClear(), RTL_TEXTENCODING_ASCII_US));
997 0 : SetContentTransferEncoding(OUString("7bit"));
998 :
999 : // Done.
1000 0 : return true;
1001 : }
1002 :
1003 0 : bool INetMIMEMessage::AttachChild(INetMIMEMessage& rChildMsg, bool bOwner)
1004 : {
1005 0 : if (IsContainer())
1006 : {
1007 0 : if (bOwner) rChildMsg.pParent = this;
1008 0 : aChildren.push_back( &rChildMsg );
1009 :
1010 0 : return true;
1011 : }
1012 0 : return false;
1013 : }
1014 :
1015 0 : SvStream& INetMIMEMessage::operator<< (SvStream& rStrm) const
1016 : {
1017 0 : INetRFC822Message::operator<< (rStrm);
1018 :
1019 0 : for (sal_uInt16 i = 0; i < INETMSG_MIME_NUMHDR; i++)
1020 0 : rStrm << static_cast<sal_uInt32>(m_nIndex[i]);
1021 :
1022 0 : write_lenPrefixed_uInt8s_FromOString<sal_uInt16>(rStrm, m_aBoundary);
1023 0 : rStrm << static_cast<sal_uInt32>(aChildren.size());
1024 :
1025 0 : return rStrm;
1026 : }
1027 :
1028 0 : SvStream& INetMIMEMessage::operator>> (SvStream& rStrm)
1029 : {
1030 0 : INetRFC822Message::operator>> (rStrm);
1031 :
1032 : sal_uInt32 nTemp;
1033 0 : for (sal_uInt16 i = 0; i < INETMSG_MIME_NUMHDR; i++)
1034 : {
1035 0 : rStrm >> nTemp;
1036 0 : m_nIndex[i] = nTemp;
1037 : }
1038 :
1039 0 : m_aBoundary = read_lenPrefixed_uInt8s_ToOString<sal_uInt16>(rStrm);
1040 :
1041 0 : rStrm >> nTemp;
1042 :
1043 0 : return rStrm;
1044 : }
1045 :
1046 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|