1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <sal/config.h>
24 #include <sal/types.h>
25 #include <rtl/strbuf.hxx>
26 #include <tools/inetmsg.hxx>
27 #include <tools/inetstrm.hxx>
29 int INetMIMEMessageStream::GetHeaderLine(sal_Char
* pData
, sal_uInt32 nSize
)
31 sal_Char
* pWBuf
= pData
;
35 if (maMsgBuffer
.Tell() == 0)
37 // Insert formatted header into buffer.
38 n
= pSourceMsg
->GetHeaderCount();
39 for (i
= 0; i
< n
; i
++)
41 INetMessageHeader
aHeader (pSourceMsg
->GetHeaderField(i
));
42 if (aHeader
.GetValue().getLength())
44 // NYI: Folding long lines.
45 maMsgBuffer
.WriteOString( aHeader
.GetName() );
46 maMsgBuffer
.WriteCharPtr( ": " );
47 maMsgBuffer
.WriteOString( aHeader
.GetValue() );
48 maMsgBuffer
.WriteCharPtr( "\r\n" );
52 pMsgWrite
= const_cast<char *>(static_cast<sal_Char
const *>(maMsgBuffer
.GetData()));
53 pMsgRead
= pMsgWrite
+ maMsgBuffer
.Tell();
56 n
= pMsgRead
- pMsgWrite
;
60 if (nSize
< n
) n
= nSize
;
61 for (i
= 0; i
< n
; i
++) *pWBuf
++ = *pMsgWrite
++;
66 maMsgBuffer
.Seek(STREAM_SEEK_TO_BEGIN
);
69 return (pWBuf
- pData
);
72 int INetMIMEMessageStream::GetBodyLine(sal_Char
* pData
, sal_uInt32 nSize
)
74 sal_Char
* pWBuf
= pData
;
75 sal_Char
* pWEnd
= pData
+ nSize
;
77 if (pSourceMsg
->GetDocumentLB())
79 if (pMsgStrm
== nullptr)
80 pMsgStrm
.reset(new SvStream (pSourceMsg
->GetDocumentLB()));
82 sal_uInt32 nRead
= pMsgStrm
->ReadBytes(pWBuf
, (pWEnd
- pWBuf
));
86 return (pWBuf
- pData
);
89 int INetMIMEMessageStream::GetMsgLine(sal_Char
* pData
, sal_uInt32 nSize
)
91 // Check for header or body.
92 if (!bHeaderGenerated
)
96 // Prepare special header fields.
97 if (pSourceMsg
->GetParent())
99 OUString
aPCT(pSourceMsg
->GetParent()->GetContentType());
100 if (aPCT
.startsWithIgnoreAsciiCase("message/rfc822"))
101 pSourceMsg
->SetMIMEVersion("1.0");
103 pSourceMsg
->SetMIMEVersion(OUString());
107 pSourceMsg
->SetMIMEVersion("1.0");
110 // Check ContentType.
111 OUString
aContentType(pSourceMsg
->GetContentType());
112 if (!aContentType
.isEmpty())
114 // Determine default Content-Type.
115 OUString aDefaultType
= pSourceMsg
->GetDefaultContentType();
117 if (aDefaultType
.equalsIgnoreAsciiCase(aContentType
))
119 // No need to specify default.
120 pSourceMsg
->SetContentType(OUString());
124 // No need to specify default.
125 pSourceMsg
->SetContentTransferEncoding(OUString());
131 // Generate the message header.
132 int nRead
= GetHeaderLine(pData
, nSize
);
142 // Generate the message body.
143 if (pSourceMsg
->IsContainer())
145 // Encapsulated message body.
148 if (pChildStrm
== nullptr)
150 INetMIMEMessage
*pChild
= pSourceMsg
->GetChild(nChildIndex
);
153 // Increment child index.
156 // Create child stream.
157 pChildStrm
.reset(new INetMIMEMessageStream(pChild
, false));
159 if (pSourceMsg
->IsMultipart())
161 // Insert multipart delimiter.
162 OStringBuffer
aDelim("--");
163 aDelim
.append(pSourceMsg
->GetMultipartBoundary());
164 aDelim
.append("\r\n");
166 memcpy(pData
, aDelim
.getStr(),
168 return aDelim
.getLength();
173 // No more parts. Mark we're done.
177 if (pSourceMsg
->IsMultipart())
179 // Insert close delimiter.
180 OStringBuffer
aDelim("--");
181 aDelim
.append(pSourceMsg
->GetMultipartBoundary());
182 aDelim
.append("--\r\n");
184 memcpy(pData
, aDelim
.getStr(),
186 return aDelim
.getLength();
192 // Read current child stream.
193 int nRead
= pChildStrm
->Read(pData
, nSize
);
200 // Cleanup exhausted child stream.
209 // Single part message body.
210 if (pSourceMsg
->GetDocumentLB() == nullptr)
212 // Empty message body.
217 return GetBodyLine(pData
, nSize
);
225 const int BUFFER_SIZE
= 2048;
229 INetMIMEMessageStream::INetMIMEMessageStream(
230 INetMIMEMessage
*pMsg
, bool headerGenerated
):
232 bHeaderGenerated(headerGenerated
),
233 mvBuffer(BUFFER_SIZE
),
239 assert(pMsg
!= nullptr);
240 maMsgBuffer
.SetStreamCharSet(RTL_TEXTENCODING_ASCII_US
);
241 pRead
= pWrite
= mvBuffer
.data();
244 INetMIMEMessageStream::~INetMIMEMessageStream()
249 int INetMIMEMessageStream::Read(sal_Char
* pData
, sal_uInt32 nSize
)
251 sal_Char
* pWBuf
= pData
;
252 sal_Char
* pWEnd
= pData
+ nSize
;
254 while (pWBuf
< pWEnd
)
256 // Caller's buffer not yet filled.
257 sal_uInt32 n
= pRead
- pWrite
;
260 // Bytes still in buffer.
261 sal_uInt32 m
= pWEnd
- pWBuf
;
263 for (sal_uInt32 i
= 0; i
< n
; i
++) *pWBuf
++ = *pWrite
++;
267 // Buffer empty. Reset to <Begin-of-Buffer>.
268 pRead
= pWrite
= mvBuffer
.data();
270 // Read next message line.
271 int nRead
= GetMsgLine(mvBuffer
.data(), mvBuffer
.size());
275 pRead
= mvBuffer
.data() + nRead
;
279 if (!bHeaderGenerated
)
281 // Header generated. Insert empty line.
282 bHeaderGenerated
= true;
289 return (pWBuf
- pData
);
294 return (pWBuf
- pData
);
297 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */