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( 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( 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 tools::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 : tools::Time aDiff( tools::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 : tools::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( 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 : : INetRFC822Message (rMsg)
681 0 : , pParent(NULL)
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 = CONTAINER_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("message/rfc822");
948 0 : break;
949 :
950 : case INETMSG_MULTIPART_ALTERNATIVE:
951 0 : aContentType.append("multipart/alternative");
952 0 : break;
953 :
954 : case INETMSG_MULTIPART_DIGEST:
955 0 : aContentType.append("multipart/digest");
956 0 : break;
957 :
958 : case INETMSG_MULTIPART_PARALLEL:
959 0 : aContentType.append("multipart/parallel");
960 0 : break;
961 :
962 : case INETMSG_MULTIPART_RELATED:
963 0 : aContentType.append("multipart/related");
964 0 : break;
965 :
966 : case INETMSG_MULTIPART_FORM_DATA:
967 0 : aContentType.append("multipart/form-data");
968 0 : break;
969 :
970 : default:
971 0 : aContentType.append("multipart/mixed");
972 0 : break;
973 : }
974 :
975 : // Setup boundary for multipart types.
976 0 : if (aContentType.toString().equalsIgnoreAsciiCase("multipart/"))
977 : {
978 : // Generate a unique boundary from current time.
979 : sal_Char sTail[16 + 1];
980 0 : tools::Time aCurTime( tools::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("; 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.WriteUInt32( m_nIndex[i] );
1021 :
1022 0 : write_uInt16_lenPrefixed_uInt8s_FromOString(rStrm, m_aBoundary);
1023 0 : rStrm.WriteUInt32( 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.ReadUInt32( nTemp );
1036 0 : m_nIndex[i] = nTemp;
1037 : }
1038 :
1039 0 : m_aBoundary = read_uInt16_lenPrefixed_uInt8s_ToOString(rStrm);
1040 :
1041 0 : rStrm.ReadUInt32( nTemp );
1042 :
1043 0 : return rStrm;
1044 : }
1045 :
1046 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|