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 <comphelper/string.hxx>
21 : #include <sal/types.h>
22 : #include <rtl/strbuf.hxx>
23 : #include <tools/cachestr.hxx>
24 : #include <tools/inetmsg.hxx>
25 : #include <tools/inetstrm.hxx>
26 :
27 : #include <ctype.h> // toupper
28 :
29 0 : inline sal_Bool SAL_CALL ascii_isWhitespace( sal_Unicode ch )
30 : {
31 0 : return ((ch <= 0x20) && ch);
32 : }
33 :
34 : #define CONSTASCII_STRINGPARAM(a) (a), RTL_TEXTENCODING_ASCII_US
35 :
36 : /** Quoted-Printable Encoding */
37 : class INetMessageEncodeQPStream_Impl : public INetMessageIStream
38 : {
39 : SvStream *pMsgStrm;
40 :
41 : sal_uIntPtr nMsgBufSiz;
42 : sal_Char *pMsgBuffer;
43 : sal_Char *pMsgRead;
44 : sal_Char *pMsgWrite;
45 :
46 : sal_uIntPtr nTokBufSiz;
47 : sal_Char *pTokBuffer;
48 : sal_Char *pTokRead;
49 : sal_Char *pTokWrite;
50 :
51 : INetMessageStreamState eState;
52 : sal_Bool bDone;
53 :
54 : virtual int GetMsgLine (sal_Char *pData, sal_uIntPtr nSize);
55 :
56 : public:
57 : INetMessageEncodeQPStream_Impl (sal_uIntPtr nMsgBufferSize = 1024);
58 : virtual ~INetMessageEncodeQPStream_Impl (void);
59 : };
60 :
61 : /** Quoted-Printable Decoding */
62 : class INetMessageDecodeQPStream_Impl : public INetMessageOStream
63 : {
64 : INetMessageStreamState eState;
65 : SvMemoryStream *pMsgBuffer;
66 :
67 : sal_uIntPtr nTokBufLen;
68 : sal_Char pTokBuffer[4];
69 :
70 : virtual int PutMsgLine (const sal_Char *pData, sal_uIntPtr nSize);
71 :
72 : public:
73 : INetMessageDecodeQPStream_Impl (void);
74 : virtual ~INetMessageDecodeQPStream_Impl (void);
75 : };
76 :
77 : /** Base64 Encoding */
78 : class INetMessageEncode64Stream_Impl : public INetMessageIStream
79 : {
80 : SvStream *pMsgStrm;
81 :
82 : sal_uIntPtr nMsgBufSiz;
83 : sal_uInt8 *pMsgBuffer;
84 : sal_uInt8 *pMsgRead;
85 : sal_uInt8 *pMsgWrite;
86 :
87 : sal_uIntPtr nTokBufSiz;
88 : sal_Char *pTokBuffer;
89 : sal_Char *pTokRead;
90 : sal_Char *pTokWrite;
91 :
92 : sal_Bool bDone;
93 :
94 : virtual int GetMsgLine (sal_Char *pData, sal_uIntPtr nSize);
95 :
96 : public:
97 : INetMessageEncode64Stream_Impl (sal_uIntPtr nMsgBufferSize = 2048);
98 : virtual ~INetMessageEncode64Stream_Impl (void);
99 : };
100 :
101 : /** Base64 Decoding */
102 : class INetMessageDecode64Stream_Impl : public INetMessageOStream
103 : {
104 : INetMessageStreamState eState;
105 :
106 : sal_uIntPtr nMsgBufSiz;
107 : sal_Char *pMsgBuffer;
108 : sal_Char *pMsgRead;
109 : sal_Char *pMsgWrite;
110 :
111 : virtual int PutMsgLine (const sal_Char *pData, sal_uIntPtr nSize);
112 :
113 : public:
114 : INetMessageDecode64Stream_Impl (sal_uIntPtr nMsgBufferSize = 128);
115 : virtual ~INetMessageDecode64Stream_Impl (void);
116 : };
117 :
118 : // INetIStream
119 :
120 0 : INetIStream::INetIStream ()
121 : {
122 0 : }
123 :
124 0 : INetIStream::~INetIStream (void)
125 : {
126 0 : }
127 :
128 0 : int INetIStream::Read (sal_Char *pData, sal_uIntPtr nSize)
129 : {
130 0 : return GetData (pData, nSize);
131 : }
132 :
133 : // INetOStream
134 :
135 0 : INetOStream::INetOStream ()
136 : {
137 0 : }
138 :
139 0 : INetOStream::~INetOStream (void)
140 : {
141 0 : }
142 :
143 0 : int INetOStream::Write (const sal_Char *pData, sal_uIntPtr nSize)
144 : {
145 0 : return PutData (pData, nSize);
146 : }
147 :
148 : // INetMessageIStream
149 :
150 0 : INetMessageIStream::INetMessageIStream (sal_uIntPtr nBufferSize)
151 : : pSourceMsg (NULL),
152 : bHeaderGenerated (sal_False),
153 : nBufSiz (nBufferSize),
154 : pMsgStrm (NULL),
155 0 : pMsgBuffer (new SvMemoryStream)
156 : {
157 0 : pMsgBuffer->SetStreamCharSet (RTL_TEXTENCODING_ASCII_US);
158 0 : pBuffer = new sal_Char[nBufSiz];
159 0 : pRead = pWrite = pBuffer;
160 0 : }
161 :
162 0 : INetMessageIStream::~INetMessageIStream (void)
163 : {
164 0 : delete [] pBuffer;
165 0 : delete pMsgBuffer;
166 0 : delete pMsgStrm;
167 0 : }
168 :
169 0 : int INetMessageIStream::GetData (sal_Char *pData, sal_uIntPtr nSize)
170 : {
171 0 : if (pSourceMsg == NULL) return INETSTREAM_STATUS_ERROR;
172 :
173 0 : sal_Char *pWBuf = pData;
174 0 : sal_Char *pWEnd = pData + nSize;
175 :
176 0 : while (pWBuf < pWEnd)
177 : {
178 : // Caller's buffer not yet filled.
179 0 : sal_uIntPtr n = pRead - pWrite;
180 0 : if (n > 0)
181 : {
182 : // Bytes still in buffer.
183 0 : sal_uIntPtr m = pWEnd - pWBuf;
184 0 : if (m < n) n = m;
185 0 : for (sal_uIntPtr i = 0; i < n; i++) *pWBuf++ = *pWrite++;
186 : }
187 : else
188 : {
189 : // Buffer empty. Reset to <Begin-of-Buffer>.
190 0 : pRead = pWrite = pBuffer;
191 :
192 : // Read next message line.
193 0 : int nRead = GetMsgLine (pBuffer, nBufSiz);
194 0 : if (nRead > 0)
195 : {
196 : // Set read pointer.
197 0 : pRead = pBuffer + nRead;
198 : }
199 : else
200 : {
201 0 : if (!bHeaderGenerated)
202 : {
203 : // Header generated. Insert empty line.
204 0 : bHeaderGenerated = sal_True;
205 0 : *pRead++ = '\r';
206 0 : *pRead++ = '\n';
207 : }
208 : else
209 : {
210 : // Body generated.
211 0 : return (pWBuf - pData);
212 : }
213 : }
214 : }
215 : }
216 0 : return (pWBuf - pData);
217 : }
218 :
219 0 : int INetMessageIStream::GetMsgLine (sal_Char *pData, sal_uIntPtr nSize)
220 : {
221 0 : if (pSourceMsg == NULL) return INETSTREAM_STATUS_ERROR;
222 :
223 0 : sal_Char *pWBuf = pData;
224 0 : sal_Char *pWEnd = pData + nSize;
225 :
226 0 : if (!bHeaderGenerated)
227 : {
228 : sal_uIntPtr i, n;
229 :
230 0 : if (pMsgBuffer->Tell() == 0)
231 : {
232 : // Insert formatted header into buffer.
233 0 : n = pSourceMsg->GetHeaderCount();
234 0 : for (i = 0; i < n; i++)
235 : {
236 0 : INetMessageHeader aHeader (pSourceMsg->GetHeaderField(i));
237 0 : if (aHeader.GetValue().getLength())
238 : {
239 : // NYI: Folding long lines.
240 0 : *pMsgBuffer << aHeader.GetName().getStr();
241 0 : *pMsgBuffer << ": ";
242 0 : *pMsgBuffer << aHeader.GetValue().getStr();
243 0 : *pMsgBuffer << "\r\n";
244 : }
245 0 : }
246 :
247 0 : pMsgWrite = (sal_Char *)(pMsgBuffer->GetData());
248 0 : pMsgRead = pMsgWrite + pMsgBuffer->Tell();
249 : }
250 :
251 0 : n = pMsgRead - pMsgWrite;
252 0 : if (n > 0)
253 : {
254 : // Move to caller.
255 0 : if (nSize < n) n = nSize;
256 0 : for (i = 0; i < n; i++) *pWBuf++ = *pMsgWrite++;
257 : }
258 : else
259 : {
260 : // Reset buffer.
261 0 : pMsgBuffer->Seek (STREAM_SEEK_TO_BEGIN);
262 : }
263 : }
264 : else
265 : {
266 0 : if (pSourceMsg->GetDocumentLB())
267 : {
268 0 : if (pMsgStrm == NULL)
269 0 : pMsgStrm = new SvStream (pSourceMsg->GetDocumentLB());
270 :
271 0 : sal_uIntPtr nRead = pMsgStrm->Read (pWBuf, (pWEnd - pWBuf));
272 0 : pWBuf += nRead;
273 : }
274 : }
275 0 : return (pWBuf - pData);
276 : }
277 :
278 : // INetMessageOStream
279 :
280 0 : INetMessageOStream::INetMessageOStream (void)
281 : : pTargetMsg (NULL),
282 : bHeaderParsed (sal_False),
283 : eOState (INETMSG_EOL_BEGIN),
284 0 : pMsgBuffer (new SvMemoryStream)
285 : {
286 0 : }
287 :
288 0 : INetMessageOStream::~INetMessageOStream (void)
289 : {
290 0 : if (pMsgBuffer->Tell() > 0)
291 0 : PutMsgLine ((const sal_Char *) pMsgBuffer->GetData(), pMsgBuffer->Tell());
292 0 : delete pMsgBuffer;
293 :
294 0 : if (pTargetMsg)
295 : {
296 : SvOpenLockBytes *pLB =
297 0 : PTR_CAST (SvOpenLockBytes, pTargetMsg->GetDocumentLB());
298 0 : if (pLB)
299 : {
300 0 : pLB->Flush();
301 0 : pLB->Terminate();
302 : }
303 : }
304 0 : }
305 :
306 : /// Simple Field Parsing (RFC822, Appendix B)
307 0 : int INetMessageOStream::PutData (const sal_Char *pData, sal_uIntPtr nSize)
308 : {
309 0 : if (pTargetMsg == NULL) return INETSTREAM_STATUS_ERROR;
310 :
311 0 : const sal_Char *pStop = (pData + nSize);
312 :
313 0 : while (!bHeaderParsed && (pData < pStop))
314 : {
315 0 : if (eOState == INETMSG_EOL_BEGIN)
316 : {
317 0 : if ((*pData == '\r') || (*pData == '\n'))
318 : {
319 : /*
320 : * Empty Line. Separates header fields from message body.
321 : * Skip this and any 2nd line break character (if any).
322 : */
323 0 : pData++;
324 0 : if ((pData < pStop) && ((*pData == '\r') || (*pData == '\n')))
325 0 : pData++;
326 :
327 : // Emit any buffered last header field.
328 0 : if (pMsgBuffer->Tell() > 0)
329 : {
330 0 : *pMsgBuffer << '\0';
331 : int status = PutMsgLine (
332 0 : (const sal_Char *) pMsgBuffer->GetData(),
333 0 : pMsgBuffer->Tell());
334 0 : if (status != INETSTREAM_STATUS_OK) return status;
335 : }
336 :
337 : // Reset to begin.
338 0 : eOState = INETMSG_EOL_BEGIN;
339 0 : pMsgBuffer->Seek (STREAM_SEEK_TO_BEGIN);
340 :
341 : // Mark header parsed.
342 0 : bHeaderParsed = sal_True;
343 : }
344 0 : else if ((*pData == ' ') || (*pData == '\t'))
345 : {
346 : // Continuation line. Unfold multi-line field-body.
347 0 : *pMsgBuffer << ' ';
348 0 : pData++;
349 : }
350 : else
351 : {
352 : // Begin of new header field.
353 0 : if (pMsgBuffer->Tell() > 0)
354 : {
355 : // Emit buffered header field now.
356 0 : *pMsgBuffer << '\0';
357 : int status = PutMsgLine (
358 0 : (const sal_Char *) pMsgBuffer->GetData(),
359 0 : pMsgBuffer->Tell());
360 0 : if (status != INETSTREAM_STATUS_OK) return status;
361 : }
362 :
363 : // Reset to begin of buffer.
364 0 : pMsgBuffer->Seek (STREAM_SEEK_TO_BEGIN);
365 :
366 : // Insert current character into buffer.
367 0 : *pMsgBuffer << *pData++;
368 : }
369 :
370 : // Search for next line break character.
371 0 : if (!bHeaderParsed) eOState = INETMSG_EOL_SCR;
372 : }
373 0 : else if (eOState == INETMSG_EOL_FCR)
374 : {
375 : // Skip line break character.
376 0 : pData++;
377 :
378 : // Mark begin of line.
379 0 : eOState = INETMSG_EOL_BEGIN;
380 : }
381 0 : else if ((*pData == '\r') || (*pData == '\n'))
382 : {
383 0 : if (*pData == '\r') pData++;
384 0 : eOState = INETMSG_EOL_FCR;
385 : }
386 0 : else if (ascii_isWhitespace (*pData & 0x7f))
387 : {
388 : // Any <LWS> is folded into a single <SP> character.
389 0 : sal_Char c = *((const sal_Char *) pMsgBuffer->GetData() + pMsgBuffer->Tell() - 1);
390 0 : if (!ascii_isWhitespace (c & 0x7f)) *pMsgBuffer << ' ';
391 :
392 : // Skip over this <LWS> character.
393 0 : pData++;
394 : }
395 : else
396 : {
397 : // Any other character is inserted into line buffer.
398 0 : *pMsgBuffer << *pData++;
399 : }
400 : }
401 :
402 0 : if (bHeaderParsed && (pData < pStop))
403 : {
404 : // Put message body down-stream.
405 0 : return PutMsgLine (pData, (pStop - pData));
406 : }
407 :
408 0 : return INETSTREAM_STATUS_OK;
409 : }
410 :
411 0 : int INetMessageOStream::PutMsgLine (const sal_Char *pData, sal_uIntPtr nSize)
412 : {
413 : // Check for message container.
414 0 : if (pTargetMsg == NULL) return INETSTREAM_STATUS_ERROR;
415 :
416 : // Check for header or body.
417 0 : if (!IsHeaderParsed())
418 : {
419 0 : rtl::OString aField(pData);
420 0 : sal_Int32 nPos = aField.indexOf(':');
421 0 : if (nPos != -1)
422 : {
423 : rtl::OString aName(
424 0 : aField.copy(0, nPos));
425 : rtl::OString aValue(
426 0 : aField.copy(nPos + 1, aField.getLength() - nPos + 1));
427 0 : aValue = comphelper::string::stripStart(aValue, ' ');
428 :
429 : pTargetMsg->SetHeaderField (
430 0 : INetMessageHeader (aName, aValue));
431 0 : }
432 : }
433 : else
434 : {
435 : SvOpenLockBytes *pLB =
436 0 : PTR_CAST(SvOpenLockBytes, pTargetMsg->GetDocumentLB());
437 0 : if (pLB == NULL)
438 0 : return INETSTREAM_STATUS_WOULDBLOCK;
439 :
440 0 : sal_Size nDocSiz = pTargetMsg->GetDocumentSize();
441 0 : sal_Size nWrite = 0;
442 :
443 0 : pLB->FillAppend ((sal_Char *)pData, nSize, &nWrite);
444 0 : pTargetMsg->SetDocumentSize (nDocSiz + nWrite);
445 :
446 0 : if (nWrite < nSize) return INETSTREAM_STATUS_ERROR;
447 : }
448 0 : return INETSTREAM_STATUS_OK;
449 : }
450 :
451 : // INetMessageIOStream
452 :
453 0 : INetMessageIOStream::INetMessageIOStream (sal_uIntPtr nBufferSize)
454 : : INetMessageIStream (nBufferSize),
455 0 : INetMessageOStream ()
456 : {
457 0 : }
458 :
459 0 : INetMessageIOStream::~INetMessageIOStream (void)
460 : {
461 0 : }
462 :
463 : // INetMessageEncodeQPStream_Impl
464 :
465 : static const sal_Char hex2pr[16] = {
466 : '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
467 : 'A', 'B', 'C', 'D', 'E', 'F'
468 : };
469 :
470 : static const sal_Char ebcdic[] = {
471 : '!', '"', '#', '$', '@', '[', '\\', ']', '^', '`', '{', '|', '}', '~'
472 : };
473 :
474 0 : INetMessageEncodeQPStream_Impl::INetMessageEncodeQPStream_Impl( sal_uIntPtr nMsgBufferSize)
475 : : INetMessageIStream (),
476 : pMsgStrm (NULL),
477 : nMsgBufSiz (nMsgBufferSize),
478 : nTokBufSiz (80),
479 : eState (INETMSG_EOL_SCR),
480 0 : bDone (sal_False)
481 : {
482 0 : GenerateHeader (sal_False);
483 :
484 0 : pMsgBuffer = new sal_Char[nMsgBufSiz];
485 0 : pMsgRead = pMsgWrite = pMsgBuffer;
486 :
487 0 : pTokBuffer = new sal_Char[nTokBufSiz];
488 0 : pTokRead = pTokWrite = pTokBuffer;
489 0 : }
490 :
491 0 : INetMessageEncodeQPStream_Impl::~INetMessageEncodeQPStream_Impl (void)
492 : {
493 0 : delete pMsgStrm;
494 0 : delete [] pMsgBuffer;
495 0 : delete [] pTokBuffer;
496 0 : }
497 :
498 0 : int INetMessageEncodeQPStream_Impl::GetMsgLine (sal_Char *pData, sal_uIntPtr nSize)
499 : {
500 0 : INetMessage *pMsg = GetSourceMessage ();
501 0 : if (pMsg == NULL) return INETSTREAM_STATUS_ERROR;
502 :
503 0 : if (pMsg->GetDocumentLB() == NULL) return 0;
504 0 : if (pMsgStrm == NULL) pMsgStrm = new SvStream (pMsg->GetDocumentLB());
505 :
506 0 : sal_Char *pWBuf = pData;
507 0 : while (pWBuf < (pData + nSize))
508 : {
509 : // Caller's buffer not yet filled.
510 0 : if ((pMsgRead - pMsgWrite) > 0)
511 : {
512 : // Bytes still in message buffer.
513 0 : if ((eState != INETMSG_EOL_BEGIN) &&
514 : ((pTokRead - pTokBuffer) < 72))
515 : {
516 : // Token buffer not yet filled.
517 0 : if (eState == INETMSG_EOL_FCR)
518 : {
519 0 : eState = INETMSG_EOL_BEGIN;
520 0 : if (*pMsgWrite != '\n')
521 : {
522 : // Convert orphant <CR> into <CR><LF> sequence.
523 0 : *pTokRead++ = '\n';
524 : }
525 0 : *pTokRead++ = *pMsgWrite++;
526 : }
527 0 : else if ((*pMsgWrite == ' ') || (*pMsgWrite == '\t'))
528 : {
529 0 : eState = INETMSG_EOL_FSP;
530 0 : *pTokRead++ = *pMsgWrite++;
531 : }
532 0 : else if (*pMsgWrite == '\r')
533 : {
534 : // Found <CR>.
535 0 : if (eState == INETMSG_EOL_FSP)
536 : {
537 : // Encode last (trailing space) character.
538 0 : sal_uInt8 c = (sal_uInt8)(*(--pTokRead));
539 0 : *pTokRead++ = '=';
540 0 : *pTokRead++ = hex2pr[((c & 0xf0) >> 4)];
541 0 : *pTokRead++ = hex2pr[((c & 0x0f) )];
542 : }
543 0 : eState = INETMSG_EOL_FCR;
544 0 : *pTokRead++ = *pMsgWrite++;
545 : }
546 0 : else if (*pMsgWrite == '\n')
547 : {
548 : // Found <LF> only.
549 0 : if (eState == INETMSG_EOL_FSP)
550 : {
551 : // Encode last (trailing space) character.
552 0 : sal_uInt8 c = (sal_uInt8)(*(--pTokRead));
553 0 : *pTokRead++ = '=';
554 0 : *pTokRead++ = hex2pr[((c & 0xf0) >> 4)];
555 0 : *pTokRead++ = hex2pr[((c & 0x0f) )];
556 : }
557 0 : eState = INETMSG_EOL_BEGIN;
558 :
559 : // Convert orphant <LF> into <CR><LF> sequence.
560 0 : *pTokRead++ = '\r';
561 0 : *pTokRead++ = *pMsgWrite++;
562 : }
563 0 : else if (*pMsgWrite == '=')
564 : {
565 : // Escape character itself MUST be encoded, of course.
566 0 : sal_uInt8 c = (sal_uInt8)(*pMsgWrite++);
567 0 : *pTokRead++ = '=';
568 0 : *pTokRead++ = hex2pr[((c & 0xf0) >> 4)];
569 0 : *pTokRead++ = hex2pr[((c & 0x0f) )];
570 :
571 0 : eState = INETMSG_EOL_SCR;
572 : }
573 0 : else if (((sal_uInt8)(*pMsgWrite) > 0x20) &&
574 : ((sal_uInt8)(*pMsgWrite) < 0x7f) )
575 : {
576 : /*
577 : * Some printable ASCII character.
578 : * (Encode EBCDIC special characters (NYI)).
579 : */
580 0 : *pTokRead++ = *pMsgWrite++;
581 0 : eState = INETMSG_EOL_SCR;
582 : }
583 : else
584 : {
585 : // Encode any other character.
586 0 : sal_uInt8 c = (sal_uInt8)(*pMsgWrite++);
587 0 : *pTokRead++ = '=';
588 0 : *pTokRead++ = hex2pr[((c & 0xf0) >> 4)];
589 0 : *pTokRead++ = hex2pr[((c & 0x0f) )];
590 :
591 0 : eState = INETMSG_EOL_SCR;
592 0 : }
593 : }
594 : else
595 : {
596 : // Check for maximum line length.
597 0 : if (eState != INETMSG_EOL_BEGIN)
598 : {
599 : // Insert soft line break.
600 0 : *pTokRead++ = '=';
601 0 : *pTokRead++ = '\r';
602 0 : *pTokRead++ = '\n';
603 :
604 0 : eState = INETMSG_EOL_BEGIN;
605 : }
606 :
607 : // Copy to caller's buffer.
608 0 : if ((pTokRead - pTokWrite) > 0)
609 : {
610 : // Bytes still in token buffer.
611 0 : *pWBuf++ = *pTokWrite++;
612 : }
613 : else
614 : {
615 : // Token buffer empty. Reset to <Begin-of-Buffer>.
616 0 : pTokRead = pTokWrite = pTokBuffer;
617 0 : eState = INETMSG_EOL_SCR;
618 : }
619 : }
620 : }
621 : else
622 : {
623 : // Message buffer empty. Reset to <Begin-of-Buffer>.
624 0 : pMsgRead = pMsgWrite = pMsgBuffer;
625 :
626 : // Read next message block.
627 0 : sal_uIntPtr nRead = pMsgStrm->Read (pMsgBuffer, nMsgBufSiz);
628 0 : if (nRead > 0)
629 : {
630 : // Set read pointer.
631 0 : pMsgRead = (pMsgBuffer + nRead);
632 : }
633 : else
634 : {
635 : // Nothing more ro read.
636 0 : if (!bDone)
637 : {
638 : // Append final <CR><LF> and mark we're done.
639 0 : *pTokRead++ = '\r';
640 0 : *pTokRead++ = '\n';
641 :
642 0 : bDone = sal_True;
643 : }
644 : else
645 : {
646 : // Already done all encoding.
647 0 : if ((pTokRead - pTokWrite) > 0)
648 : {
649 : // Bytes still in token buffer.
650 0 : *pWBuf++ = *pTokWrite++;
651 : }
652 : else
653 : {
654 : // Token buffer empty. Reset to <Begin-of-Buffer>.
655 0 : pTokRead = pTokWrite = pTokBuffer;
656 :
657 : // Return.
658 0 : return (pWBuf - pData);
659 : }
660 : }
661 : }
662 : }
663 : }
664 0 : return (pWBuf - pData);
665 : }
666 :
667 : // INetMessageDecodeQPStream_Impl
668 :
669 : static const sal_uInt8 pr2hex[128] = {
670 : 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
671 : 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
672 : 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
673 : 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
674 :
675 : 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
676 : 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
677 : 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
678 : 0x08, 0x09, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
679 :
680 : 0x10, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10,
681 : 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
682 : 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
683 : 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
684 :
685 : 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
686 : 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
687 : 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
688 : 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10
689 : };
690 :
691 0 : INetMessageDecodeQPStream_Impl::INetMessageDecodeQPStream_Impl (void)
692 : : INetMessageOStream (),
693 : eState (INETMSG_EOL_BEGIN),
694 0 : pMsgBuffer (new SvMemoryStream),
695 0 : nTokBufLen (0)
696 : {
697 0 : ParseHeader (sal_False);
698 0 : }
699 :
700 0 : INetMessageDecodeQPStream_Impl::~INetMessageDecodeQPStream_Impl (void)
701 : {
702 0 : delete pMsgBuffer;
703 0 : }
704 :
705 0 : int INetMessageDecodeQPStream_Impl::PutMsgLine (
706 : const sal_Char *pData, sal_uIntPtr nSize)
707 : {
708 0 : INetMessage *pMsg = GetTargetMessage();
709 0 : if (pMsg == NULL) return INETSTREAM_STATUS_ERROR;
710 :
711 0 : SvOpenLockBytes * pLB = PTR_CAST(SvOpenLockBytes, pMsg->GetDocumentLB());
712 0 : if (pLB == NULL) return INETSTREAM_STATUS_WOULDBLOCK;
713 :
714 0 : const sal_Char *pStop = pData + nSize;
715 0 : while (pData < pStop)
716 : {
717 0 : if (eState == INETMSG_EOL_FESC)
718 : {
719 0 : *(pTokBuffer + nTokBufLen++) = static_cast< char >(toupper(*pData));
720 0 : pData++;
721 0 : if (nTokBufLen == 2)
722 : {
723 0 : if ((*pTokBuffer == '\r') || (*pTokBuffer == '\n'))
724 : {
725 : // Soft line break (=<CR><LF>). Emit buffer now.
726 0 : eState = INETMSG_EOL_BEGIN;
727 : }
728 : else
729 : {
730 : // Decode token.
731 : *pMsgBuffer << sal_uInt8 (
732 0 : (pr2hex[(int)(pTokBuffer[0] & 0x7f)] << 4) |
733 0 : (pr2hex[(int)(pTokBuffer[1] & 0x7f)] & 15) );
734 :
735 : // Search for next <CR>.
736 0 : eState = INETMSG_EOL_SCR;
737 : }
738 :
739 : // Reset token buffer.
740 0 : nTokBufLen = 0;
741 : }
742 : }
743 0 : else if (*pData == '=')
744 : {
745 : // Found escape character.
746 0 : pData++;
747 0 : eState = INETMSG_EOL_FESC;
748 : }
749 0 : else if (eState == INETMSG_EOL_FCR)
750 : {
751 0 : *pMsgBuffer << *pData++;
752 0 : eState = INETMSG_EOL_BEGIN;
753 : }
754 0 : else if (*pData == '\r')
755 : {
756 0 : *pMsgBuffer << *pData++;
757 0 : eState = INETMSG_EOL_FCR;
758 : }
759 : else
760 : {
761 0 : *pMsgBuffer << *pData++;
762 : }
763 :
764 0 : if (eState == INETMSG_EOL_BEGIN)
765 : {
766 0 : sal_Size nRead = pMsgBuffer->Tell();
767 0 : if (nRead > 0)
768 : {
769 : // Emit buffer.
770 0 : sal_Size nDocSiz = pMsg->GetDocumentSize();
771 0 : sal_Size nWrite = 0;
772 :
773 : pLB->FillAppend (
774 0 : (sal_Char *)(pMsgBuffer->GetData()), nRead, &nWrite);
775 0 : pMsg->SetDocumentSize (nDocSiz + nWrite);
776 :
777 0 : if (nWrite < nRead) return INETSTREAM_STATUS_ERROR;
778 :
779 0 : pMsgBuffer->Seek (STREAM_SEEK_TO_BEGIN);
780 : }
781 0 : eState = INETMSG_EOL_SCR;
782 : }
783 : }
784 0 : return INETSTREAM_STATUS_OK;
785 : }
786 :
787 : // INetMessageEncode64Stream_Impl
788 :
789 : static const sal_Char six2pr[64] = {
790 : 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
791 : 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
792 : 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
793 : 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
794 : '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
795 : };
796 :
797 0 : INetMessageEncode64Stream_Impl::INetMessageEncode64Stream_Impl (
798 : sal_uIntPtr nMsgBufferSize)
799 : : INetMessageIStream (),
800 : pMsgStrm (NULL),
801 : nMsgBufSiz (nMsgBufferSize),
802 : nTokBufSiz (80),
803 0 : bDone (sal_False)
804 : {
805 0 : GenerateHeader (sal_False);
806 :
807 0 : pMsgBuffer = new sal_uInt8[nMsgBufSiz];
808 0 : pMsgRead = pMsgWrite = pMsgBuffer;
809 :
810 0 : pTokBuffer = new sal_Char[nTokBufSiz];
811 0 : pTokRead = pTokWrite = pTokBuffer;
812 0 : }
813 :
814 0 : INetMessageEncode64Stream_Impl::~INetMessageEncode64Stream_Impl (void)
815 : {
816 0 : delete pMsgStrm;
817 0 : delete [] pMsgBuffer;
818 0 : delete [] pTokBuffer;
819 0 : }
820 :
821 0 : int INetMessageEncode64Stream_Impl::GetMsgLine (sal_Char *pData, sal_uIntPtr nSize)
822 : {
823 0 : INetMessage *pMsg = GetSourceMessage ();
824 0 : if (pMsg == NULL) return INETSTREAM_STATUS_ERROR;
825 :
826 0 : if (pMsg->GetDocumentLB() == NULL) return 0;
827 0 : if (pMsgStrm == NULL) pMsgStrm = new SvStream (pMsg->GetDocumentLB());
828 :
829 0 : sal_Char *pWBuf = pData;
830 0 : while (pWBuf < (pData + nSize))
831 : {
832 : // Caller's buffer not yet filled.
833 0 : if ((pMsgRead - pMsgWrite) > 0)
834 : {
835 : // Bytes still in message buffer.
836 0 : if ((pTokRead - pTokBuffer) < 72)
837 : {
838 : // Token buffer not yet filled.
839 0 : switch ((pTokRead - pTokBuffer) % 4)
840 : {
841 : case 0:
842 0 : *pTokRead++ = six2pr[(int)(*pMsgWrite >> 2)];
843 0 : break;
844 :
845 : case 1:
846 : *pTokRead++ = six2pr[
847 : (int)(((*pMsgWrite << 4) & 060) |
848 0 : (((*(pMsgWrite + 1)) >> 4) & 017))];
849 0 : pMsgWrite++;
850 0 : break;
851 :
852 : case 2:
853 : *pTokRead++ = six2pr[
854 : (int)(((*pMsgWrite << 2) & 074) |
855 0 : (((*(pMsgWrite + 1)) >> 6) & 003))];
856 0 : pMsgWrite++;
857 0 : break;
858 :
859 : default: // == case 3
860 0 : *pTokRead++ = six2pr[(int)(*pMsgWrite & 077)];
861 0 : pMsgWrite++;
862 0 : break;
863 : }
864 : }
865 0 : else if ((pTokRead - pTokBuffer) == 72)
866 : {
867 : // Maximum line length. Append <CR><LF>.
868 0 : *pTokRead++ = '\r';
869 0 : *pTokRead++ = '\n';
870 : }
871 : else
872 : {
873 0 : if ((pTokRead - pTokWrite) > 0)
874 : {
875 : // Bytes still in token buffer.
876 0 : *pWBuf++ = *pTokWrite++;
877 : }
878 : else
879 : {
880 : // Token buffer empty. Reset to <Begin-of-Buffer>.
881 0 : pTokRead = pTokWrite = pTokBuffer;
882 : }
883 : }
884 : }
885 : else
886 : {
887 : // Message buffer empty. Reset to <Begin-of-Buffer>.
888 0 : pMsgRead = pMsgWrite = pMsgBuffer;
889 :
890 : // Read next message block.
891 0 : sal_uIntPtr nRead = pMsgStrm->Read (pMsgBuffer, nMsgBufSiz);
892 0 : if (nRead > 0)
893 : {
894 : // Set read pointer.
895 0 : pMsgRead = (pMsgBuffer + nRead);
896 : }
897 : else
898 : {
899 : // Nothing more to read.
900 0 : if (!bDone)
901 : {
902 : // Append pad character(s) and final <CR><LF>.
903 0 : switch ((pTokRead - pTokBuffer) % 4)
904 : {
905 : case 2:
906 0 : *pTokRead++ = '=';
907 : // Fall through for 2nd pad character.
908 :
909 : case 3:
910 0 : *pTokRead++ = '=';
911 0 : break;
912 :
913 : default:
914 0 : break;
915 : }
916 0 : *pTokRead++ = '\r';
917 0 : *pTokRead++ = '\n';
918 :
919 : // Mark we're done.
920 0 : bDone = sal_True;
921 : }
922 : else
923 : {
924 : // Already done all encoding.
925 0 : if ((pTokRead - pTokWrite) > 0)
926 : {
927 : // Bytes still in token buffer.
928 0 : *pWBuf++ = *pTokWrite++;
929 : }
930 : else
931 : {
932 : // Token buffer empty. Reset to <Begin-of-Buffer>.
933 0 : pTokRead = pTokWrite = pTokBuffer;
934 :
935 : // Reset done flag, if everything has been done.
936 : // if (pWBuf == pData) bDone = sal_False;
937 :
938 : // Return.
939 0 : return (pWBuf - pData);
940 : }
941 : }
942 : }
943 : }
944 : } // while (pWBuf < (pData + nSize))
945 0 : return (pWBuf - pData);
946 : }
947 :
948 : // INetMessageDecode64Stream_Impl
949 :
950 : static const sal_uInt8 pr2six[256] = {
951 : 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
952 : 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
953 : 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
954 : 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
955 :
956 : 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
957 : 0x40, 0x40, 0x40, 0x3E, 0x40, 0x40, 0x40, 0x3F,
958 : 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B,
959 : 0x3C, 0x3D, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
960 :
961 : 0x40, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
962 : 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
963 : 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
964 : 0x17, 0x18, 0x19, 0x40, 0x40, 0x40, 0x40, 0x40,
965 :
966 : 0x40, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20,
967 : 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
968 : 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30,
969 : 0x31, 0x32, 0x33, 0x40, 0x40, 0x40, 0x40, 0x40,
970 :
971 : 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
972 : 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
973 : 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
974 : 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
975 :
976 : 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
977 : 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
978 : 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
979 : 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
980 :
981 : 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
982 : 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
983 : 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
984 : 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
985 :
986 : 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
987 : 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
988 : 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
989 : 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40
990 : };
991 :
992 0 : INetMessageDecode64Stream_Impl::INetMessageDecode64Stream_Impl (
993 : sal_uIntPtr nMsgBufferSize)
994 : : INetMessageOStream (),
995 : eState (INETMSG_EOL_SCR),
996 0 : nMsgBufSiz (nMsgBufferSize)
997 : {
998 0 : ParseHeader (sal_False);
999 :
1000 0 : pMsgBuffer = new sal_Char[nMsgBufSiz];
1001 0 : pMsgRead = pMsgWrite = pMsgBuffer;
1002 0 : }
1003 :
1004 0 : INetMessageDecode64Stream_Impl::~INetMessageDecode64Stream_Impl (void)
1005 : {
1006 0 : delete [] pMsgBuffer;
1007 0 : }
1008 :
1009 0 : int INetMessageDecode64Stream_Impl::PutMsgLine (
1010 : const sal_Char *pData, sal_uIntPtr nSize)
1011 : {
1012 0 : INetMessage *pMsg = GetTargetMessage ();
1013 0 : if (pMsg == NULL) return INETSTREAM_STATUS_ERROR;
1014 :
1015 0 : SvOpenLockBytes * pLB = PTR_CAST(SvOpenLockBytes, pMsg->GetDocumentLB());
1016 0 : if (pLB == NULL) return INETSTREAM_STATUS_WOULDBLOCK;
1017 :
1018 0 : const sal_Char *pStop = (pData + nSize);
1019 0 : while (pData < pStop)
1020 : {
1021 0 : if (pr2six[(int)(*pData)] > 63)
1022 : {
1023 : /*
1024 : * Character not in base64 alphabet.
1025 : * Check for <End-of-Stream> or Junk.
1026 : */
1027 0 : if (*pData == '=')
1028 : {
1029 : // Final pad character -> Done.
1030 0 : sal_Size nDocSiz = pMsg->GetDocumentSize();
1031 0 : sal_Size nRead = pMsgWrite - pMsgBuffer;
1032 0 : sal_Size nWrite = 0;
1033 :
1034 0 : pLB->FillAppend (pMsgBuffer, nRead, &nWrite);
1035 0 : pMsg->SetDocumentSize (nDocSiz + nWrite);
1036 :
1037 0 : if (nWrite < nRead)
1038 0 : return INETSTREAM_STATUS_ERROR;
1039 : else
1040 0 : return INETSTREAM_STATUS_LOADED;
1041 : }
1042 0 : else if (eState == INETMSG_EOL_FCR)
1043 : {
1044 : // Skip any line break character.
1045 0 : if ((*pData == '\r') || (*pData == '\n')) pData++;
1046 :
1047 : // Store decoded message buffer contents.
1048 0 : sal_Size nDocSiz = pMsg->GetDocumentSize();
1049 0 : sal_Size nRead = pMsgWrite - pMsgBuffer;
1050 0 : sal_Size nWrite = 0;
1051 :
1052 0 : pLB->FillAppend (pMsgBuffer, nRead, &nWrite);
1053 0 : pMsg->SetDocumentSize (nDocSiz + nWrite);
1054 :
1055 0 : if (nWrite < nRead) return INETSTREAM_STATUS_ERROR;
1056 :
1057 : // Reset to <Begin-of-Buffer>.
1058 0 : pMsgWrite = pMsgBuffer;
1059 0 : eState = INETMSG_EOL_SCR;
1060 : }
1061 0 : else if ((*pData == '\r') || (*pData == '\n'))
1062 : {
1063 : // Skip any line break character.
1064 0 : pData++;
1065 0 : eState = INETMSG_EOL_FCR;
1066 : }
1067 : else
1068 : {
1069 : // Skip any junk character (may be transmission error).
1070 0 : pData++;
1071 : }
1072 : }
1073 : else
1074 : {
1075 : // Decode any other character into message buffer.
1076 0 : switch ((pMsgRead - pMsgBuffer) % 4)
1077 : {
1078 : case 0:
1079 0 : *pMsgWrite = (pr2six[(int)(*pData++)] << 2);
1080 0 : pMsgRead++;
1081 0 : break;
1082 :
1083 : case 1:
1084 0 : *pMsgWrite++ |= (pr2six[(int)(*pData )] >> 4);
1085 0 : *pMsgWrite = (pr2six[(int)(*pData++)] << 4);
1086 0 : pMsgRead++;
1087 0 : break;
1088 :
1089 : case 2:
1090 0 : *pMsgWrite++ |= (pr2six[(int)(*pData )] >> 2);
1091 0 : *pMsgWrite = (pr2six[(int)(*pData++)] << 6);
1092 0 : pMsgRead++;
1093 0 : break;
1094 :
1095 : default: // == case 3
1096 0 : *pMsgWrite++ |= (pr2six[(int)(*pData++)]);
1097 0 : pMsgRead = pMsgBuffer;
1098 0 : break;
1099 : } // switch ((pMsgRead - pMsgBuffer) % 4)
1100 : }
1101 : } // while (pData < pStop)
1102 0 : return INETSTREAM_STATUS_OK;
1103 : }
1104 :
1105 : // INetMIMEMessageStream
1106 :
1107 0 : INetMIMEMessageStream::INetMIMEMessageStream (sal_uIntPtr nBufferSize)
1108 : : INetMessageIOStream (nBufferSize),
1109 : eState (INETMSG_EOL_BEGIN),
1110 : nChildIndex (0),
1111 : pChildStrm (NULL),
1112 : eEncoding (INETMSG_ENCODING_BINARY),
1113 : pEncodeStrm (NULL),
1114 : pDecodeStrm (NULL),
1115 0 : pMsgBuffer (NULL)
1116 : {
1117 0 : }
1118 :
1119 0 : INetMIMEMessageStream::~INetMIMEMessageStream (void)
1120 : {
1121 0 : delete pChildStrm;
1122 0 : delete pEncodeStrm;
1123 0 : delete pDecodeStrm;
1124 0 : delete pMsgBuffer;
1125 0 : }
1126 :
1127 : INetMessageEncoding
1128 0 : INetMIMEMessageStream::GetMsgEncoding (const String& rContentType)
1129 : {
1130 0 : if ((rContentType.CompareIgnoreCaseToAscii ("message" , 7) == 0) ||
1131 0 : (rContentType.CompareIgnoreCaseToAscii ("multipart", 9) == 0) )
1132 0 : return INETMSG_ENCODING_7BIT;
1133 :
1134 0 : if (rContentType.CompareIgnoreCaseToAscii ("text", 4) == 0)
1135 : {
1136 0 : if (rContentType.CompareIgnoreCaseToAscii ("text/plain", 10) == 0)
1137 : {
1138 0 : if (comphelper::string::getTokenCount(rContentType, '=') > 1)
1139 : {
1140 0 : String aCharset (rContentType.GetToken (1, '='));
1141 0 : aCharset = comphelper::string::stripStart(aCharset, ' ');
1142 0 : aCharset = comphelper::string::stripStart(aCharset, '"');
1143 :
1144 0 : if (aCharset.CompareIgnoreCaseToAscii ("us-ascii", 8) == 0)
1145 0 : return INETMSG_ENCODING_7BIT;
1146 : else
1147 0 : return INETMSG_ENCODING_QUOTED;
1148 : }
1149 : else
1150 0 : return INETMSG_ENCODING_7BIT;
1151 : }
1152 : else
1153 0 : return INETMSG_ENCODING_QUOTED;
1154 : }
1155 :
1156 0 : return INETMSG_ENCODING_BASE64;
1157 : }
1158 :
1159 : /// Message Generator
1160 0 : int INetMIMEMessageStream::GetMsgLine (sal_Char *pData, sal_uIntPtr nSize)
1161 : {
1162 : // Check for message container.
1163 0 : INetMIMEMessage *pMsg = GetSourceMessage();
1164 0 : if (pMsg == NULL) return INETSTREAM_STATUS_ERROR;
1165 :
1166 : // Check for header or body.
1167 0 : if (!IsHeaderGenerated())
1168 : {
1169 0 : if (eState == INETMSG_EOL_BEGIN)
1170 : {
1171 : // Prepare special header fields.
1172 0 : if (pMsg->GetParent())
1173 : {
1174 0 : String aPCT (pMsg->GetParent()->GetContentType());
1175 0 : if (aPCT.CompareIgnoreCaseToAscii ("message/rfc822", 14) == 0)
1176 : pMsg->SetMIMEVersion (
1177 0 : String(CONSTASCII_STRINGPARAM("1.0")));
1178 : else
1179 0 : pMsg->SetMIMEVersion (String());
1180 : }
1181 : else
1182 : {
1183 0 : pMsg->SetMIMEVersion (String(CONSTASCII_STRINGPARAM("1.0")));
1184 : }
1185 :
1186 : // Check ContentType.
1187 0 : String aContentType (pMsg->GetContentType());
1188 0 : if (aContentType.Len())
1189 : {
1190 : // Determine default Content-Type.
1191 0 : UniString aDefaultType = pMsg->GetDefaultContentType();
1192 :
1193 0 : if (aDefaultType.CompareIgnoreCaseToAscii (
1194 0 : aContentType, aContentType.Len()) == 0)
1195 : {
1196 : // No need to specify default.
1197 0 : pMsg->SetContentType (String());
1198 0 : }
1199 : }
1200 :
1201 : // Check Encoding.
1202 0 : String aEncoding (pMsg->GetContentTransferEncoding());
1203 0 : if (aEncoding.Len())
1204 : {
1205 : // Use given Encoding.
1206 0 : if (aEncoding.CompareIgnoreCaseToAscii (
1207 0 : "base64", 6) == 0)
1208 0 : eEncoding = INETMSG_ENCODING_BASE64;
1209 0 : else if (aEncoding.CompareIgnoreCaseToAscii (
1210 0 : "quoted-printable", 16) == 0)
1211 0 : eEncoding = INETMSG_ENCODING_QUOTED;
1212 : else
1213 0 : eEncoding = INETMSG_ENCODING_7BIT;
1214 : }
1215 : else
1216 : {
1217 : // Use default Encoding for (given|default) Content-Type.
1218 0 : if (aContentType.Len() == 0)
1219 : {
1220 : // Determine default Content-Type.
1221 0 : aContentType = pMsg->GetDefaultContentType();
1222 : }
1223 0 : eEncoding = GetMsgEncoding (aContentType);
1224 : }
1225 :
1226 : // Set Content-Transfer-Encoding header.
1227 0 : if (eEncoding == INETMSG_ENCODING_BASE64)
1228 : {
1229 : // Base64.
1230 : pMsg->SetContentTransferEncoding (
1231 0 : String(CONSTASCII_STRINGPARAM("base64")));
1232 : }
1233 0 : else if (eEncoding == INETMSG_ENCODING_QUOTED)
1234 : {
1235 : // Quoted-Printable.
1236 : pMsg->SetContentTransferEncoding (
1237 0 : String(CONSTASCII_STRINGPARAM("quoted-printable")));
1238 : }
1239 : else
1240 : {
1241 : // No need to specify default.
1242 0 : pMsg->SetContentTransferEncoding (String());
1243 : }
1244 :
1245 : // Mark we're done.
1246 0 : eState = INETMSG_EOL_DONE;
1247 : }
1248 :
1249 : // Generate the message header.
1250 0 : int nRead = INetMessageIOStream::GetMsgLine (pData, nSize);
1251 0 : if (nRead <= 0)
1252 : {
1253 : // Reset state.
1254 0 : eState = INETMSG_EOL_BEGIN;
1255 : }
1256 0 : return nRead;
1257 : }
1258 : else
1259 : {
1260 : // Generate the message body.
1261 0 : if (pMsg->IsContainer())
1262 : {
1263 : // Encapsulated message body.
1264 0 : while (eState == INETMSG_EOL_BEGIN)
1265 : {
1266 0 : if (pChildStrm == NULL)
1267 : {
1268 0 : INetMIMEMessage *pChild = pMsg->GetChild (nChildIndex);
1269 0 : if (pChild)
1270 : {
1271 : // Increment child index.
1272 0 : nChildIndex++;
1273 :
1274 : // Create child stream.
1275 0 : pChildStrm = new INetMIMEMessageStream;
1276 0 : pChildStrm->SetSourceMessage (pChild);
1277 :
1278 0 : if (pMsg->IsMultipart())
1279 : {
1280 : // Insert multipart delimiter.
1281 : rtl::OStringBuffer aDelim(
1282 0 : RTL_CONSTASCII_STRINGPARAM("--"));
1283 0 : aDelim.append(pMsg->GetMultipartBoundary());
1284 0 : aDelim.append(RTL_CONSTASCII_STRINGPARAM("\r\n"));
1285 :
1286 0 : memcpy(pData, aDelim.getStr(),
1287 0 : aDelim.getLength());
1288 0 : return aDelim.getLength();
1289 : }
1290 : }
1291 : else
1292 : {
1293 : // No more parts. Mark we're done.
1294 0 : eState = INETMSG_EOL_DONE;
1295 0 : nChildIndex = 0;
1296 :
1297 0 : if (pMsg->IsMultipart())
1298 : {
1299 : // Insert close delimiter.
1300 : rtl::OStringBuffer aDelim(
1301 0 : RTL_CONSTASCII_STRINGPARAM("--"));
1302 0 : aDelim.append(pMsg->GetMultipartBoundary());
1303 0 : aDelim.append(RTL_CONSTASCII_STRINGPARAM("--\r\n"));
1304 :
1305 0 : memcpy (pData, aDelim.getStr(),
1306 0 : aDelim.getLength());
1307 0 : return aDelim.getLength();
1308 : }
1309 : }
1310 : }
1311 : else
1312 : {
1313 : // Read current child stream.
1314 0 : int nRead = pChildStrm->Read (pData, nSize);
1315 0 : if (nRead > 0)
1316 : {
1317 0 : return nRead;
1318 : }
1319 : else
1320 : {
1321 : // Cleanup exhausted child stream.
1322 0 : delete pChildStrm;
1323 0 : pChildStrm = NULL;
1324 : }
1325 : }
1326 : }
1327 0 : return 0;
1328 : }
1329 : else
1330 : {
1331 : // Single part message body.
1332 0 : if (pMsg->GetDocumentLB() == NULL)
1333 : {
1334 : // Empty message body.
1335 0 : return 0;
1336 : }
1337 : else
1338 : {
1339 : // Check whether message body needs to be encoded.
1340 0 : if (eEncoding == INETMSG_ENCODING_7BIT)
1341 : {
1342 : // No Encoding.
1343 0 : return INetMessageIOStream::GetMsgLine (pData, nSize);
1344 : }
1345 : else
1346 : {
1347 : // Apply appropriate Encoding.
1348 0 : while (eState == INETMSG_EOL_BEGIN)
1349 : {
1350 0 : if (pEncodeStrm == NULL)
1351 : {
1352 : // Create encoder stream.
1353 0 : if (eEncoding == INETMSG_ENCODING_QUOTED)
1354 : {
1355 : // Quoted-Printable Encoding.
1356 : pEncodeStrm
1357 0 : = new INetMessageEncodeQPStream_Impl;
1358 : }
1359 : else
1360 : {
1361 : // Base64 Encoding.
1362 : pEncodeStrm
1363 0 : = new INetMessageEncode64Stream_Impl;
1364 : }
1365 0 : pEncodeStrm->SetSourceMessage (pMsg);
1366 : }
1367 :
1368 : // Read encoded message.
1369 0 : int nRead = pEncodeStrm->Read (pData, nSize);
1370 0 : if (nRead > 0)
1371 : {
1372 0 : return nRead;
1373 : }
1374 : else
1375 : {
1376 : // Cleanup exhausted encoder stream.
1377 0 : delete pEncodeStrm;
1378 0 : pEncodeStrm = NULL;
1379 :
1380 : // Mark we're done.
1381 0 : eState = INETMSG_EOL_DONE;
1382 : }
1383 : }
1384 0 : return 0;
1385 : }
1386 : }
1387 : }
1388 : }
1389 : }
1390 :
1391 : /// Message Parser
1392 0 : int INetMIMEMessageStream::PutMsgLine (const sal_Char *pData, sal_uIntPtr nSize)
1393 : {
1394 : // Check for message container.
1395 0 : INetMIMEMessage *pMsg = GetTargetMessage();
1396 0 : if (pMsg == NULL) return INETSTREAM_STATUS_ERROR;
1397 :
1398 : // Check for header or body.
1399 0 : if (!IsHeaderParsed())
1400 : {
1401 : // Parse the message header.
1402 0 : int nRet = INetMessageIOStream::PutMsgLine (pData, nSize);
1403 0 : return nRet;
1404 : }
1405 : else
1406 : {
1407 0 : pMsg->SetHeaderParsed();
1408 : // Parse the message body.
1409 0 : if (pMsg->IsContainer())
1410 : {
1411 :
1412 : // Content-Transfer-Encoding MUST be "7bit" (RFC1521).
1413 0 : if (pMsg->IsMessage())
1414 : {
1415 0 : if( !pChildStrm )
1416 : {
1417 : // Encapsulated message.
1418 0 : INetMIMEMessage* pNewMessage = new INetMIMEMessage;
1419 : pNewMessage->SetDocumentLB (
1420 0 : new SvAsyncLockBytes(new SvCacheStream, sal_False));
1421 0 : pMsg->AttachChild( *pNewMessage, sal_True );
1422 :
1423 : // Encapsulated message body. Create message parser stream.
1424 0 : pChildStrm = new INetMIMEMessageStream;
1425 0 : pChildStrm->SetTargetMessage ( pNewMessage );
1426 :
1427 : // Initialize control variables.
1428 0 : eState = INETMSG_EOL_BEGIN;
1429 : }
1430 0 : if ( nSize > 0)
1431 : {
1432 : // Bytes still in buffer. Put message down-stream.
1433 0 : int status = pChildStrm->Write( pData, nSize );
1434 0 : if (status != INETSTREAM_STATUS_OK)
1435 0 : return status;
1436 : }
1437 :
1438 0 : return INetMessageIOStream::PutMsgLine (pData, nSize);
1439 : }
1440 : else
1441 : {
1442 :
1443 : // Multipart message body. Initialize multipart delimiters.
1444 : // Multipart message.
1445 0 : if (pMsg->GetMultipartBoundary().getLength() == 0)
1446 : {
1447 : // Determine boundary.
1448 : rtl::OString aType(rtl::OUStringToOString(
1449 0 : pMsg->GetContentType(), RTL_TEXTENCODING_ASCII_US));
1450 0 : rtl::OString aLowerType(aType.toAsciiLowerCase());
1451 :
1452 : sal_Int32 nPos = aLowerType.indexOfL(
1453 0 : RTL_CONSTASCII_STRINGPARAM("boundary="));
1454 0 : rtl::OString aBoundary(aType.copy(nPos + 9));
1455 :
1456 0 : aBoundary = comphelper::string::strip(aBoundary, ' ');
1457 0 : aBoundary = comphelper::string::strip(aBoundary, '"');
1458 :
1459 : // Save boundary.
1460 0 : pMsg->SetMultipartBoundary (aBoundary);
1461 : }
1462 :
1463 0 : rtl::OString aPlainDelim (pMsg->GetMultipartBoundary());
1464 : rtl::OString aDelim = rtl::OStringBuffer(
1465 : RTL_CONSTASCII_STRINGPARAM("--")).
1466 0 : append(aPlainDelim).
1467 0 : makeStringAndClear();
1468 : rtl::OString aPlainClose = rtl::OStringBuffer(
1469 : aPlainDelim).
1470 0 : append(RTL_CONSTASCII_STRINGPARAM("--")).
1471 0 : makeStringAndClear();
1472 : rtl::OString aClose = rtl::OStringBuffer(
1473 : aDelim).
1474 0 : append(RTL_CONSTASCII_STRINGPARAM("--")).
1475 0 : makeStringAndClear();
1476 :
1477 0 : if (pMsgBuffer == NULL) pMsgBuffer = new SvMemoryStream;
1478 0 : pMsgBuffer->Write (pData, nSize);
1479 0 : sal_uIntPtr nBufSize = pMsgBuffer->Tell();
1480 :
1481 : const sal_Char* pChar;
1482 : const sal_Char* pOldPos;
1483 0 : for( pOldPos = pChar = (const sal_Char *) pMsgBuffer->GetData(); nBufSize--;
1484 : pChar++ )
1485 : {
1486 : int status;
1487 0 : if( *pChar == '\r' || *pChar == '\n' )
1488 : {
1489 0 : if( aDelim.compareTo(pOldPos, aDelim.getLength())
1490 : != -1 &&
1491 0 : aClose.compareTo(pOldPos, aClose.getLength())
1492 : != -1 &&
1493 0 : aPlainDelim.compareTo(pOldPos, aPlainDelim.getLength())
1494 : != -1 &&
1495 0 : aPlainClose.compareTo(pOldPos, aPlainClose.getLength())
1496 : != -1 )
1497 : {
1498 0 : if( nBufSize &&
1499 0 : ( pChar[1] == '\r' || pChar[1] == '\n' ) )
1500 0 : nBufSize--, pChar++;
1501 0 : if( pChildStrm )
1502 : {
1503 : status = pChildStrm->Write(
1504 0 : pOldPos, pChar - pOldPos + 1 );
1505 0 : if( status != INETSTREAM_STATUS_OK )
1506 0 : return status;
1507 : }
1508 : else {
1509 : SAL_WARN( "tools.stream", "Boundary not found." );
1510 : }
1511 : status = INetMessageIOStream::PutMsgLine(
1512 0 : pOldPos, pChar - pOldPos + 1 );
1513 0 : if( status != INETSTREAM_STATUS_OK )
1514 0 : return status;
1515 0 : pOldPos = pChar + 1;
1516 : }
1517 : else
1518 : {
1519 0 : if( nBufSize &&
1520 0 : ( pChar[1] == '\r' || pChar[1] == '\n' ) )
1521 0 : nBufSize--, pChar++;
1522 0 : pOldPos = pChar + 1;
1523 0 : DELETEZ( pChildStrm );
1524 :
1525 0 : if (aClose.compareTo(pOldPos, aClose.getLength())
1526 : != -1 &&
1527 0 : aPlainClose.compareTo(pOldPos, aClose.getLength())
1528 : != -1 )
1529 : {
1530 : // Encapsulated message.
1531 : INetMIMEMessage* pNewMessage =
1532 0 : new INetMIMEMessage;
1533 : pNewMessage->SetDocumentLB (
1534 : new SvAsyncLockBytes (
1535 0 : new SvCacheStream, sal_False));
1536 :
1537 0 : pMsg->AttachChild( *pNewMessage, sal_True );
1538 :
1539 : // Encapsulated message body. Create message parser stream.
1540 0 : pChildStrm = new INetMIMEMessageStream;
1541 0 : pChildStrm->SetTargetMessage ( pNewMessage );
1542 :
1543 : // Initialize control variables.
1544 : }
1545 0 : eState = INETMSG_EOL_BEGIN;
1546 : status = INetMessageIOStream::PutMsgLine(
1547 0 : pOldPos, pChar - pOldPos + 1 );
1548 0 : if( status != INETSTREAM_STATUS_OK )
1549 0 : return status;
1550 : }
1551 : }
1552 : }
1553 0 : if( pOldPos < pChar )
1554 : {
1555 0 : SvMemoryStream* pNewStream = new SvMemoryStream;
1556 0 : pNewStream->Write( pOldPos, pChar - pOldPos );
1557 0 : SvMemoryStream* pTmp = pMsgBuffer;
1558 0 : pMsgBuffer = pNewStream;
1559 0 : delete pTmp;
1560 : }
1561 : else
1562 : {
1563 0 : pMsgBuffer->Seek( 0L );
1564 0 : pMsgBuffer->SetStreamSize( 0 );
1565 : }
1566 0 : return INETSTREAM_STATUS_OK;
1567 : }
1568 : }
1569 : else
1570 : {
1571 : /*
1572 : * Single part message.
1573 : * Remove any ContentTransferEncoding.
1574 : */
1575 0 : if (pMsg->GetContentType().isEmpty())
1576 : {
1577 0 : pMsg->SetContentType(pMsg->GetDefaultContentType());
1578 : }
1579 :
1580 0 : if (eEncoding == INETMSG_ENCODING_BINARY)
1581 : {
1582 0 : String aEncoding (pMsg->GetContentTransferEncoding());
1583 0 : if (aEncoding.CompareIgnoreCaseToAscii (
1584 0 : "base64", 6) == COMPARE_EQUAL)
1585 0 : eEncoding = INETMSG_ENCODING_BASE64;
1586 0 : else if (aEncoding.CompareIgnoreCaseToAscii (
1587 0 : "quoted-printable", 16) == COMPARE_EQUAL)
1588 0 : eEncoding = INETMSG_ENCODING_QUOTED;
1589 : else
1590 0 : eEncoding = INETMSG_ENCODING_7BIT;
1591 : }
1592 :
1593 0 : if (eEncoding == INETMSG_ENCODING_7BIT)
1594 : {
1595 : // No decoding necessary.
1596 0 : return INetMessageIOStream::PutMsgLine (pData, nSize);
1597 : }
1598 : else
1599 : {
1600 0 : if (pDecodeStrm == NULL)
1601 : {
1602 0 : if (eEncoding == INETMSG_ENCODING_QUOTED)
1603 0 : pDecodeStrm = new INetMessageDecodeQPStream_Impl;
1604 : else
1605 0 : pDecodeStrm = new INetMessageDecode64Stream_Impl;
1606 :
1607 0 : pDecodeStrm->SetTargetMessage (pMsg);
1608 : }
1609 0 : return pDecodeStrm->Write (pData, nSize);
1610 : }
1611 : }
1612 : }
1613 : }
1614 :
1615 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|