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