LibreOffice Module tools (master) 1
inetstrm.cxx
Go to the documentation of this file.
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/config.h>
21
22#include <cassert>
23
24#include <sal/types.h>
25#include <tools/inetmsg.hxx>
26#include <tools/inetstrm.hxx>
27
28int INetMIMEMessageStream::GetHeaderLine(char* pData, sal_uInt32 nSize)
29{
30 char* pWBuf = pData;
31
32 sal_uInt32 i, n;
33
34 if (maMsgBuffer.Tell() == 0)
35 {
36 // Insert formatted header into buffer.
37 n = pSourceMsg->GetHeaderCount();
38 for (i = 0; i < n; i++)
39 {
40 INetMessageHeader aHeader (pSourceMsg->GetHeaderField(i));
41 if (aHeader.GetValue().getLength())
42 {
43 // NYI: Folding long lines.
44 maMsgBuffer.WriteOString( aHeader.GetName() );
45 maMsgBuffer.WriteOString( ": " );
46 maMsgBuffer.WriteOString( aHeader.GetValue() );
47 maMsgBuffer.WriteOString( "\r\n" );
48 }
49 }
50
51 pMsgWrite = const_cast<char *>(static_cast<char const *>(maMsgBuffer.GetData()));
52 pMsgRead = pMsgWrite + maMsgBuffer.Tell();
53 }
54
55 n = pMsgRead - pMsgWrite;
56 if (n > 0)
57 {
58 // Move to caller.
59 if (nSize < n) n = nSize;
60 for (i = 0; i < n; i++) *pWBuf++ = *pMsgWrite++;
61 }
62 else
63 {
64 // Reset buffer.
65 maMsgBuffer.Seek(STREAM_SEEK_TO_BEGIN);
66 }
67
68 return (pWBuf - pData);
69}
70
71int INetMIMEMessageStream::GetBodyLine(char* pData, sal_uInt32 nSize)
72{
73 char* pWBuf = pData;
74 char* pWEnd = pData + nSize;
75
76 if (pSourceMsg->GetDocumentLB())
77 {
78 if (pMsgStrm == nullptr)
79 pMsgStrm.reset(new SvStream (pSourceMsg->GetDocumentLB()));
80
81 sal_uInt32 nRead = pMsgStrm->ReadBytes(pWBuf, (pWEnd - pWBuf));
82 pWBuf += nRead;
83 }
84
85 return (pWBuf - pData);
86}
87
88int INetMIMEMessageStream::GetMsgLine(char* pData, sal_uInt32 nSize)
89{
90 // Check for header or body.
91 if (!bHeaderGenerated)
92 {
93 if (!done)
94 {
95 // Prepare special header fields.
96 if (pSourceMsg->GetParent())
97 {
98 OUString aPCT(pSourceMsg->GetParent()->GetContentType());
99 if (aPCT.startsWithIgnoreAsciiCase("message/rfc822"))
100 pSourceMsg->SetMIMEVersion("1.0");
101 else
102 pSourceMsg->SetMIMEVersion(OUString());
103 }
104 else
105 {
106 pSourceMsg->SetMIMEVersion("1.0");
107 }
108
109 // Check ContentType.
110 OUString aContentType(pSourceMsg->GetContentType());
111 if (!aContentType.isEmpty())
112 {
113 // Determine default Content-Type.
114 OUString aDefaultType = pSourceMsg->GetDefaultContentType();
115
116 if (aDefaultType.equalsIgnoreAsciiCase(aContentType))
117 {
118 // No need to specify default.
119 pSourceMsg->SetContentType(OUString());
120 }
121 }
122
123 // No need to specify default.
124 pSourceMsg->SetContentTransferEncoding(OUString());
125
126 // Mark we're done.
127 done = true;
128 }
129
130 // Generate the message header.
131 int nRead = GetHeaderLine(pData, nSize);
132 if (nRead <= 0)
133 {
134 // Reset state.
135 done = false;
136 }
137 return nRead;
138 }
139 else
140 {
141 // Generate the message body.
142 if (pSourceMsg->IsContainer())
143 {
144 // Encapsulated message body.
145 while (!done)
146 {
147 if (pChildStrm == nullptr)
148 {
149 INetMIMEMessage *pChild = pSourceMsg->GetChild(nChildIndex);
150 if (pChild)
151 {
152 // Increment child index.
153 nChildIndex++;
154
155 // Create child stream.
156 pChildStrm.reset(new INetMIMEMessageStream(pChild, false));
157
158 if (pSourceMsg->IsMultipart())
159 {
160 // Insert multipart delimiter.
161 OString aDelim = "--" +
162 pSourceMsg->GetMultipartBoundary() +
163 "\r\n";
164
165 memcpy(pData, aDelim.getStr(),
166 aDelim.getLength());
167 return aDelim.getLength();
168 }
169 }
170 else
171 {
172 // No more parts. Mark we're done.
173 done = true;
174 nChildIndex = 0;
175
176 if (pSourceMsg->IsMultipart())
177 {
178 // Insert close delimiter.
179 OString aDelim = "--" +
180 pSourceMsg->GetMultipartBoundary() +
181 "--\r\n";
182
183 memcpy(pData, aDelim.getStr(),
184 aDelim.getLength());
185 return aDelim.getLength();
186 }
187 }
188 }
189 else
190 {
191 // Read current child stream.
192 int nRead = pChildStrm->Read(pData, nSize);
193 if (nRead > 0)
194 {
195 return nRead;
196 }
197 else
198 {
199 // Cleanup exhausted child stream.
200 pChildStrm.reset();
201 }
202 }
203 }
204 return 0;
205 }
206 else
207 {
208 // Single part message body.
209 if (pSourceMsg->GetDocumentLB() == nullptr)
210 {
211 // Empty message body.
212 return 0;
213 }
214
215 // No Encoding.
216 return GetBodyLine(pData, nSize);
217 }
218 }
219}
220
221namespace
222{
223
224const int BUFFER_SIZE = 2048;
225
226}
227
228INetMIMEMessageStream::INetMIMEMessageStream(
229 INetMIMEMessage *pMsg, bool headerGenerated):
230 pSourceMsg(pMsg),
231 bHeaderGenerated(headerGenerated),
232 mvBuffer(BUFFER_SIZE),
233 pMsgRead(nullptr),
234 pMsgWrite(nullptr),
235 done(false),
236 nChildIndex(0)
237{
238 assert(pMsg != nullptr);
239 maMsgBuffer.SetStreamCharSet(RTL_TEXTENCODING_ASCII_US);
240 pRead = pWrite = mvBuffer.data();
241}
242
243INetMIMEMessageStream::~INetMIMEMessageStream()
244{
245 pChildStrm.reset();
246}
247
248int INetMIMEMessageStream::Read(char* pData, sal_uInt32 nSize)
249{
250 char* pWBuf = pData;
251 char* pWEnd = pData + nSize;
252
253 while (pWBuf < pWEnd)
254 {
255 // Caller's buffer not yet filled.
256 sal_uInt32 n = pRead - pWrite;
257 if (n > 0)
258 {
259 // Bytes still in buffer.
260 sal_uInt32 m = pWEnd - pWBuf;
261 if (m < n) n = m;
262 for (sal_uInt32 i = 0; i < n; i++) *pWBuf++ = *pWrite++;
263 }
264 else
265 {
266 // Buffer empty. Reset to <Begin-of-Buffer>.
267 pRead = pWrite = mvBuffer.data();
268
269 // Read next message line.
270 int nRead = GetMsgLine(mvBuffer.data(), mvBuffer.size());
271 if (nRead > 0)
272 {
273 // Set read pointer.
274 pRead = mvBuffer.data() + nRead;
275 }
276 else
277 {
278 if (!bHeaderGenerated)
279 {
280 // Header generated. Insert empty line.
281 bHeaderGenerated = true;
282 *pRead++ = '\r';
283 *pRead++ = '\n';
284 }
285 else
286 {
287 // Body generated.
288 return (pWBuf - pData);
289 }
290 }
291 }
292 }
293 return (pWBuf - pData);
294}
295
296/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
sal_Int64 n
std::unique_ptr< sal_Int32[]> pData
int i
m
#define STREAM_SEEK_TO_BEGIN
Definition: stream.hxx:72
#define BUFFER_SIZE