|
ferencd@0
|
1 //
|
|
ferencd@0
|
2 // VMime library (http://www.vmime.org)
|
|
ferencd@0
|
3 // Copyright (C) 2002-2013 Vincent Richard <vincent@vmime.org>
|
|
ferencd@0
|
4 //
|
|
ferencd@0
|
5 // This program is free software; you can redistribute it and/or
|
|
ferencd@0
|
6 // modify it under the terms of the GNU General Public License as
|
|
ferencd@0
|
7 // published by the Free Software Foundation; either version 3 of
|
|
ferencd@0
|
8 // the License, or (at your option) any later version.
|
|
ferencd@0
|
9 //
|
|
ferencd@0
|
10 // This program is distributed in the hope that it will be useful,
|
|
ferencd@0
|
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
ferencd@0
|
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
ferencd@0
|
13 // General Public License for more details.
|
|
ferencd@0
|
14 //
|
|
ferencd@0
|
15 // You should have received a copy of the GNU General Public License along
|
|
ferencd@0
|
16 // with this program; if not, write to the Free Software Foundation, Inc.,
|
|
ferencd@0
|
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
ferencd@0
|
18 //
|
|
ferencd@0
|
19 // Linking this library statically or dynamically with other modules is making
|
|
ferencd@0
|
20 // a combined work based on this library. Thus, the terms and conditions of
|
|
ferencd@0
|
21 // the GNU General Public License cover the whole combination.
|
|
ferencd@0
|
22 //
|
|
ferencd@0
|
23
|
|
ferencd@0
|
24
|
|
ferencd@0
|
25 /** Accepts connection and fails on greeting.
|
|
ferencd@0
|
26 */
|
|
ferencd@0
|
27 class greetingErrorSMTPTestSocket : public lineBasedTestSocket
|
|
ferencd@0
|
28 {
|
|
ferencd@0
|
29 public:
|
|
ferencd@0
|
30
|
|
ferencd@0
|
31 void onConnected()
|
|
ferencd@0
|
32 {
|
|
ferencd@0
|
33 localSend("421 test.vmime.org Service not available, closing transmission channel\r\n");
|
|
ferencd@0
|
34 disconnect();
|
|
ferencd@0
|
35 }
|
|
ferencd@0
|
36
|
|
ferencd@0
|
37 void processCommand()
|
|
ferencd@0
|
38 {
|
|
ferencd@0
|
39 if (!haveMoreLines())
|
|
ferencd@0
|
40 return;
|
|
ferencd@0
|
41
|
|
ferencd@0
|
42 getNextLine();
|
|
ferencd@0
|
43
|
|
ferencd@0
|
44 localSend("502 Command not implemented\r\n");
|
|
ferencd@0
|
45 processCommand();
|
|
ferencd@0
|
46 }
|
|
ferencd@0
|
47 };
|
|
ferencd@0
|
48
|
|
ferencd@0
|
49
|
|
ferencd@0
|
50 /** SMTP test server 1.
|
|
ferencd@0
|
51 *
|
|
ferencd@0
|
52 * Test send().
|
|
ferencd@0
|
53 * Ensure MAIL and RCPT commands are sent correctly.
|
|
ferencd@0
|
54 */
|
|
ferencd@0
|
55 class MAILandRCPTSMTPTestSocket : public lineBasedTestSocket
|
|
ferencd@0
|
56 {
|
|
ferencd@0
|
57 public:
|
|
ferencd@0
|
58
|
|
ferencd@0
|
59 MAILandRCPTSMTPTestSocket()
|
|
ferencd@0
|
60 {
|
|
ferencd@0
|
61 m_recipients.insert("recipient1@test.vmime.org");
|
|
ferencd@0
|
62 m_recipients.insert("recipient2@test.vmime.org");
|
|
ferencd@0
|
63 m_recipients.insert("recipient3@test.vmime.org");
|
|
ferencd@0
|
64
|
|
ferencd@0
|
65 m_state = STATE_NOT_CONNECTED;
|
|
ferencd@0
|
66 m_ehloSent = m_heloSent = m_mailSent = m_rcptSent = m_dataSent = m_quitSent = false;
|
|
ferencd@0
|
67 }
|
|
ferencd@0
|
68
|
|
ferencd@0
|
69 ~MAILandRCPTSMTPTestSocket()
|
|
ferencd@0
|
70 {
|
|
ferencd@0
|
71 VASSERT("Client must send the DATA command", m_dataSent);
|
|
ferencd@0
|
72 VASSERT("Client must send the QUIT command", m_quitSent);
|
|
ferencd@0
|
73 }
|
|
ferencd@0
|
74
|
|
ferencd@0
|
75 void onConnected()
|
|
ferencd@0
|
76 {
|
|
ferencd@0
|
77 localSend("220 test.vmime.org Service ready\r\n");
|
|
ferencd@0
|
78 processCommand();
|
|
ferencd@0
|
79
|
|
ferencd@0
|
80 m_state = STATE_COMMAND;
|
|
ferencd@0
|
81 }
|
|
ferencd@0
|
82
|
|
ferencd@0
|
83 void processCommand()
|
|
ferencd@0
|
84 {
|
|
ferencd@0
|
85 if (!haveMoreLines())
|
|
ferencd@0
|
86 return;
|
|
ferencd@0
|
87
|
|
ferencd@0
|
88 vmime::string line = getNextLine();
|
|
ferencd@0
|
89 std::istringstream iss(line);
|
|
ferencd@0
|
90
|
|
ferencd@0
|
91 switch (m_state)
|
|
ferencd@0
|
92 {
|
|
ferencd@0
|
93 case STATE_NOT_CONNECTED:
|
|
ferencd@0
|
94
|
|
ferencd@0
|
95 localSend("451 Requested action aborted: invalid state\r\n");
|
|
ferencd@0
|
96 break;
|
|
ferencd@0
|
97
|
|
ferencd@0
|
98 case STATE_COMMAND:
|
|
ferencd@0
|
99 {
|
|
ferencd@0
|
100 std::string cmd;
|
|
ferencd@0
|
101 iss >> cmd;
|
|
ferencd@0
|
102
|
|
ferencd@0
|
103 if (cmd.empty())
|
|
ferencd@0
|
104 {
|
|
ferencd@0
|
105 localSend("500 Syntax error, command unrecognized\r\n");
|
|
ferencd@0
|
106 }
|
|
ferencd@0
|
107 else if (cmd == "EHLO")
|
|
ferencd@0
|
108 {
|
|
ferencd@0
|
109 localSend("502 Command not implemented\r\n");
|
|
ferencd@0
|
110
|
|
ferencd@0
|
111 m_ehloSent = true;
|
|
ferencd@0
|
112 }
|
|
ferencd@0
|
113 else if (cmd == "HELO")
|
|
ferencd@0
|
114 {
|
|
ferencd@0
|
115 VASSERT("Client must send the EHLO command before HELO", m_ehloSent);
|
|
ferencd@0
|
116
|
|
ferencd@0
|
117 localSend("250 OK\r\n");
|
|
ferencd@0
|
118
|
|
ferencd@0
|
119 m_heloSent = true;
|
|
ferencd@0
|
120 }
|
|
ferencd@0
|
121 else if (cmd == "MAIL")
|
|
ferencd@0
|
122 {
|
|
ferencd@0
|
123 VASSERT("Client must send the HELO command", m_heloSent);
|
|
ferencd@0
|
124 VASSERT("The MAIL command must be sent only one time", !m_mailSent);
|
|
ferencd@0
|
125
|
|
ferencd@0
|
126 VASSERT_EQ("MAIL", std::string("MAIL FROM:<expeditor@test.vmime.org>"), line);
|
|
ferencd@0
|
127
|
|
ferencd@0
|
128 localSend("250 OK\r\n");
|
|
ferencd@0
|
129
|
|
ferencd@0
|
130 m_mailSent = true;
|
|
ferencd@0
|
131 }
|
|
ferencd@0
|
132 else if (cmd == "RCPT")
|
|
ferencd@0
|
133 {
|
|
ferencd@0
|
134 const vmime::size_t lt = line.find('<');
|
|
ferencd@0
|
135 const vmime::size_t gt = line.find('>');
|
|
ferencd@0
|
136
|
|
ferencd@0
|
137 VASSERT("RCPT <", lt != vmime::string::npos);
|
|
ferencd@0
|
138 VASSERT("RCPT >", gt != vmime::string::npos);
|
|
ferencd@0
|
139 VASSERT("RCPT ><", gt >= lt);
|
|
ferencd@0
|
140
|
|
ferencd@0
|
141 const vmime::string recip = vmime::string
|
|
ferencd@0
|
142 (line.begin() + lt + 1, line.begin() + gt);
|
|
ferencd@0
|
143
|
|
ferencd@0
|
144 std::set <vmime::string>::iterator it =
|
|
ferencd@0
|
145 m_recipients.find(recip);
|
|
ferencd@0
|
146
|
|
ferencd@0
|
147 VASSERT(std::string("Recipient not found: '") + recip + "'",
|
|
ferencd@0
|
148 it != m_recipients.end());
|
|
ferencd@0
|
149
|
|
ferencd@0
|
150 m_recipients.erase(it);
|
|
ferencd@0
|
151
|
|
ferencd@0
|
152 localSend("250 OK, recipient accepted\r\n");
|
|
ferencd@0
|
153
|
|
ferencd@0
|
154 m_rcptSent = true;
|
|
ferencd@0
|
155 }
|
|
ferencd@0
|
156 else if (cmd == "DATA")
|
|
ferencd@0
|
157 {
|
|
ferencd@0
|
158 VASSERT("Client must send the MAIL command", m_mailSent);
|
|
ferencd@0
|
159 VASSERT("Client must send the RCPT command", m_rcptSent);
|
|
ferencd@0
|
160 VASSERT("All recipients", m_recipients.empty());
|
|
ferencd@0
|
161
|
|
ferencd@0
|
162 localSend("354 Ready to accept data; end with <CRLF>.<CRLF>\r\n");
|
|
ferencd@0
|
163
|
|
ferencd@0
|
164 m_state = STATE_DATA;
|
|
ferencd@0
|
165 m_msgData.clear();
|
|
ferencd@0
|
166
|
|
ferencd@0
|
167 m_dataSent = true;
|
|
ferencd@0
|
168 }
|
|
ferencd@0
|
169 else if (cmd == "NOOP")
|
|
ferencd@0
|
170 {
|
|
ferencd@0
|
171 localSend("250 Completed\r\n");
|
|
ferencd@0
|
172 }
|
|
ferencd@0
|
173 else if (cmd == "QUIT")
|
|
ferencd@0
|
174 {
|
|
ferencd@0
|
175 m_quitSent = true;
|
|
ferencd@0
|
176
|
|
ferencd@0
|
177 localSend("221 test.vmime.org Service closing transmission channel\r\n");
|
|
ferencd@0
|
178 }
|
|
ferencd@0
|
179 else
|
|
ferencd@0
|
180 {
|
|
ferencd@0
|
181 localSend("502 Command not implemented\r\n");
|
|
ferencd@0
|
182 }
|
|
ferencd@0
|
183
|
|
ferencd@0
|
184 break;
|
|
ferencd@0
|
185 }
|
|
ferencd@0
|
186 case STATE_DATA:
|
|
ferencd@0
|
187 {
|
|
ferencd@0
|
188 if (line == ".")
|
|
ferencd@0
|
189 {
|
|
ferencd@0
|
190 VASSERT_EQ("Data", "Message data\r\n", m_msgData);
|
|
ferencd@0
|
191
|
|
ferencd@0
|
192 localSend("250 Message accepted for delivery\r\n");
|
|
ferencd@0
|
193 m_state = STATE_COMMAND;
|
|
ferencd@0
|
194 }
|
|
ferencd@0
|
195 else
|
|
ferencd@0
|
196 {
|
|
ferencd@0
|
197 m_msgData += line + "\r\n";
|
|
ferencd@0
|
198 }
|
|
ferencd@0
|
199
|
|
ferencd@0
|
200 break;
|
|
ferencd@0
|
201 }
|
|
ferencd@0
|
202
|
|
ferencd@0
|
203 }
|
|
ferencd@0
|
204
|
|
ferencd@0
|
205 processCommand();
|
|
ferencd@0
|
206 }
|
|
ferencd@0
|
207
|
|
ferencd@0
|
208 private:
|
|
ferencd@0
|
209
|
|
ferencd@0
|
210 enum State
|
|
ferencd@0
|
211 {
|
|
ferencd@0
|
212 STATE_NOT_CONNECTED,
|
|
ferencd@0
|
213 STATE_COMMAND,
|
|
ferencd@0
|
214 STATE_DATA
|
|
ferencd@0
|
215 };
|
|
ferencd@0
|
216
|
|
ferencd@0
|
217 int m_state;
|
|
ferencd@0
|
218
|
|
ferencd@0
|
219 std::set <vmime::string> m_recipients;
|
|
ferencd@0
|
220
|
|
ferencd@0
|
221 std::string m_msgData;
|
|
ferencd@0
|
222
|
|
ferencd@0
|
223 bool m_ehloSent, m_heloSent, m_mailSent, m_rcptSent,
|
|
ferencd@0
|
224 m_dataSent, m_quitSent;
|
|
ferencd@0
|
225 };
|
|
ferencd@0
|
226
|
|
ferencd@0
|
227
|
|
ferencd@0
|
228
|
|
ferencd@0
|
229 /** SMTP test server 2.
|
|
ferencd@0
|
230 *
|
|
ferencd@0
|
231 * Test CHUNKING extension/BDAT command.
|
|
ferencd@0
|
232 */
|
|
ferencd@0
|
233 class chunkingSMTPTestSocket : public testSocket
|
|
ferencd@0
|
234 {
|
|
ferencd@0
|
235 public:
|
|
ferencd@0
|
236
|
|
ferencd@0
|
237 chunkingSMTPTestSocket()
|
|
ferencd@0
|
238 {
|
|
ferencd@0
|
239 m_state = STATE_NOT_CONNECTED;
|
|
ferencd@0
|
240 m_bdatChunkCount = 0;
|
|
ferencd@0
|
241 m_ehloSent = m_mailSent = m_rcptSent = m_quitSent = false;
|
|
ferencd@0
|
242 }
|
|
ferencd@0
|
243
|
|
ferencd@0
|
244 ~chunkingSMTPTestSocket()
|
|
ferencd@0
|
245 {
|
|
ferencd@0
|
246 VASSERT_EQ("BDAT chunk count", 3, m_bdatChunkCount);
|
|
ferencd@0
|
247 VASSERT("Client must send the QUIT command", m_quitSent);
|
|
ferencd@0
|
248 }
|
|
ferencd@0
|
249
|
|
ferencd@0
|
250 void onConnected()
|
|
ferencd@0
|
251 {
|
|
ferencd@0
|
252 localSend("220 test.vmime.org Service ready\r\n");
|
|
ferencd@0
|
253 processCommand();
|
|
ferencd@0
|
254
|
|
ferencd@0
|
255 m_state = STATE_COMMAND;
|
|
ferencd@0
|
256 }
|
|
ferencd@0
|
257
|
|
ferencd@0
|
258 void onDataReceived()
|
|
ferencd@0
|
259 {
|
|
ferencd@0
|
260 if (m_state == STATE_DATA)
|
|
ferencd@0
|
261 {
|
|
ferencd@0
|
262 if (m_bdatChunkReceived != m_bdatChunkSize)
|
|
ferencd@0
|
263 {
|
|
ferencd@0
|
264 const size_t remaining = m_bdatChunkSize - m_bdatChunkReceived;
|
|
ferencd@0
|
265 const size_t received = localReceiveRaw(NULL, remaining);
|
|
ferencd@0
|
266
|
|
ferencd@0
|
267 m_bdatChunkReceived += received;
|
|
ferencd@0
|
268 }
|
|
ferencd@0
|
269
|
|
ferencd@0
|
270 if (m_bdatChunkReceived == m_bdatChunkSize)
|
|
ferencd@0
|
271 {
|
|
ferencd@0
|
272 m_state = STATE_COMMAND;
|
|
ferencd@0
|
273 }
|
|
ferencd@0
|
274 }
|
|
ferencd@0
|
275
|
|
ferencd@0
|
276 processCommand();
|
|
ferencd@0
|
277 }
|
|
ferencd@0
|
278
|
|
ferencd@0
|
279 void processCommand()
|
|
ferencd@0
|
280 {
|
|
ferencd@0
|
281 vmime::string line;
|
|
ferencd@0
|
282
|
|
ferencd@0
|
283 if (!localReceiveLine(line))
|
|
ferencd@0
|
284 return;
|
|
ferencd@0
|
285
|
|
ferencd@0
|
286 std::istringstream iss(line);
|
|
ferencd@0
|
287
|
|
ferencd@0
|
288 switch (m_state)
|
|
ferencd@0
|
289 {
|
|
ferencd@0
|
290 case STATE_NOT_CONNECTED:
|
|
ferencd@0
|
291
|
|
ferencd@0
|
292 localSend("451 Requested action aborted: invalid state\r\n");
|
|
ferencd@0
|
293 break;
|
|
ferencd@0
|
294
|
|
ferencd@0
|
295 case STATE_COMMAND:
|
|
ferencd@0
|
296 {
|
|
ferencd@0
|
297 std::string cmd;
|
|
ferencd@0
|
298 iss >> cmd;
|
|
ferencd@0
|
299
|
|
ferencd@0
|
300 if (cmd == "EHLO")
|
|
ferencd@0
|
301 {
|
|
ferencd@0
|
302 localSend("250-test.vmime.org says hello\r\n");
|
|
ferencd@0
|
303 localSend("250 CHUNKING\r\n");
|
|
ferencd@0
|
304
|
|
ferencd@0
|
305 m_ehloSent = true;
|
|
ferencd@0
|
306 }
|
|
ferencd@0
|
307 else if (cmd == "HELO")
|
|
ferencd@0
|
308 {
|
|
ferencd@0
|
309 VASSERT("Client must not send the HELO command, as EHLO succeeded", false);
|
|
ferencd@0
|
310 }
|
|
ferencd@0
|
311 else if (cmd == "MAIL")
|
|
ferencd@0
|
312 {
|
|
ferencd@0
|
313 VASSERT("The MAIL command must be sent only one time", !m_mailSent);
|
|
ferencd@0
|
314
|
|
ferencd@0
|
315 localSend("250 OK\r\n");
|
|
ferencd@0
|
316
|
|
ferencd@0
|
317 m_mailSent = true;
|
|
ferencd@0
|
318 }
|
|
ferencd@0
|
319 else if (cmd == "RCPT")
|
|
ferencd@0
|
320 {
|
|
ferencd@0
|
321 localSend("250 OK, recipient accepted\r\n");
|
|
ferencd@0
|
322
|
|
ferencd@0
|
323 m_rcptSent = true;
|
|
ferencd@0
|
324 }
|
|
ferencd@0
|
325 else if (cmd == "DATA")
|
|
ferencd@0
|
326 {
|
|
ferencd@0
|
327 VASSERT("BDAT must be used here!", false);
|
|
ferencd@0
|
328 }
|
|
ferencd@0
|
329 else if (cmd == "BDAT")
|
|
ferencd@0
|
330 {
|
|
ferencd@0
|
331 VASSERT("Client must send the MAIL command", m_mailSent);
|
|
ferencd@0
|
332 VASSERT("Client must send the RCPT command", m_rcptSent);
|
|
ferencd@0
|
333
|
|
ferencd@0
|
334 unsigned long chunkSize = 0;
|
|
ferencd@0
|
335 iss >> chunkSize;
|
|
ferencd@0
|
336
|
|
ferencd@0
|
337 std::string last;
|
|
ferencd@0
|
338 iss >> last;
|
|
ferencd@0
|
339
|
|
ferencd@0
|
340 if (m_bdatChunkCount == 0)
|
|
ferencd@0
|
341 {
|
|
ferencd@0
|
342 VASSERT_EQ("BDAT chunk1 size", 262144, chunkSize);
|
|
ferencd@0
|
343 VASSERT_EQ("BDAT chunk1 last", "", last);
|
|
ferencd@0
|
344 }
|
|
ferencd@0
|
345 else if (m_bdatChunkCount == 1)
|
|
ferencd@0
|
346 {
|
|
ferencd@0
|
347 VASSERT_EQ("BDAT chunk2 size", 262144, chunkSize);
|
|
ferencd@0
|
348 VASSERT_EQ("BDAT chunk2 last", "", last);
|
|
ferencd@0
|
349 }
|
|
ferencd@0
|
350 else if (m_bdatChunkCount == 2)
|
|
ferencd@0
|
351 {
|
|
ferencd@0
|
352 VASSERT_EQ("BDAT chunk3 size", 4712, chunkSize);
|
|
ferencd@0
|
353 VASSERT_EQ("BDAT chunk3 last", "LAST", last);
|
|
ferencd@0
|
354 }
|
|
ferencd@0
|
355 else
|
|
ferencd@0
|
356 {
|
|
ferencd@0
|
357 VASSERT("No more BDAT command should be issued!", false);
|
|
ferencd@0
|
358 }
|
|
ferencd@0
|
359
|
|
ferencd@0
|
360 m_bdatChunkSize = chunkSize;
|
|
ferencd@0
|
361 m_bdatChunkReceived = 0;
|
|
ferencd@0
|
362 m_bdatChunkCount++;
|
|
ferencd@0
|
363 m_state = STATE_DATA;
|
|
ferencd@0
|
364
|
|
ferencd@0
|
365 localSend("250 chunk received\r\n");
|
|
ferencd@0
|
366 }
|
|
ferencd@0
|
367 else if (cmd == "NOOP")
|
|
ferencd@0
|
368 {
|
|
ferencd@0
|
369 localSend("250 Completed\r\n");
|
|
ferencd@0
|
370 }
|
|
ferencd@0
|
371 else if (cmd == "QUIT")
|
|
ferencd@0
|
372 {
|
|
ferencd@0
|
373 localSend("221 test.vmime.org Service closing transmission channel\r\n");
|
|
ferencd@0
|
374
|
|
ferencd@0
|
375 m_quitSent = true;
|
|
ferencd@0
|
376 }
|
|
ferencd@0
|
377 else
|
|
ferencd@0
|
378 {
|
|
ferencd@0
|
379 localSend("502 Command not implemented\r\n");
|
|
ferencd@0
|
380 }
|
|
ferencd@0
|
381
|
|
ferencd@0
|
382 break;
|
|
ferencd@0
|
383 }
|
|
ferencd@0
|
384
|
|
ferencd@0
|
385 }
|
|
ferencd@0
|
386
|
|
ferencd@0
|
387 processCommand();
|
|
ferencd@0
|
388 }
|
|
ferencd@0
|
389
|
|
ferencd@0
|
390 private:
|
|
ferencd@0
|
391
|
|
ferencd@0
|
392 enum State
|
|
ferencd@0
|
393 {
|
|
ferencd@0
|
394 STATE_NOT_CONNECTED,
|
|
ferencd@0
|
395 STATE_COMMAND,
|
|
ferencd@0
|
396 STATE_DATA
|
|
ferencd@0
|
397 };
|
|
ferencd@0
|
398
|
|
ferencd@0
|
399 int m_state;
|
|
ferencd@0
|
400 int m_bdatChunkCount;
|
|
ferencd@0
|
401 int m_bdatChunkSize, m_bdatChunkReceived;
|
|
ferencd@0
|
402
|
|
ferencd@0
|
403 bool m_ehloSent, m_mailSent, m_rcptSent, m_quitSent;
|
|
ferencd@0
|
404 };
|
|
ferencd@0
|
405
|
|
ferencd@0
|
406
|
|
ferencd@0
|
407 class SMTPTestMessage : public vmime::message
|
|
ferencd@0
|
408 {
|
|
ferencd@0
|
409 public:
|
|
ferencd@0
|
410
|
|
ferencd@0
|
411 vmime::size_t getChunkBufferSize() const
|
|
ferencd@0
|
412 {
|
|
ferencd@0
|
413 static vmime::net::smtp::SMTPChunkingOutputStreamAdapter chunkStream(vmime::null, 0, NULL);
|
|
ferencd@0
|
414 return chunkStream.getBlockSize();
|
|
ferencd@0
|
415 }
|
|
ferencd@0
|
416
|
|
ferencd@0
|
417 const std::vector <vmime::string>& getChunks() const
|
|
ferencd@0
|
418 {
|
|
ferencd@0
|
419 static std::vector <vmime::string> chunks;
|
|
ferencd@0
|
420
|
|
ferencd@0
|
421 if (chunks.size() == 0)
|
|
ferencd@0
|
422 {
|
|
ferencd@0
|
423 chunks.push_back(vmime::string(1000, 'A'));
|
|
ferencd@0
|
424 chunks.push_back(vmime::string(3000, 'B'));
|
|
ferencd@0
|
425 chunks.push_back(vmime::string(500000, 'C'));
|
|
ferencd@0
|
426 chunks.push_back(vmime::string(25000, 'D'));
|
|
ferencd@0
|
427 }
|
|
ferencd@0
|
428
|
|
ferencd@0
|
429 return chunks;
|
|
ferencd@0
|
430 }
|
|
ferencd@0
|
431
|
|
ferencd@0
|
432 void generateImpl
|
|
ferencd@0
|
433 (const vmime::generationContext& /* ctx */, vmime::utility::outputStream& outputStream,
|
|
ferencd@0
|
434 const size_t /* curLinePos */ = 0, size_t* /* newLinePos */ = NULL) const
|
|
ferencd@0
|
435 {
|
|
ferencd@0
|
436 for (unsigned int i = 0, n = getChunks().size() ; i < n ; ++i)
|
|
ferencd@0
|
437 {
|
|
ferencd@0
|
438 const vmime::string& chunk = getChunks()[i];
|
|
ferencd@0
|
439 outputStream.write(chunk.data(), chunk.size());
|
|
ferencd@0
|
440 }
|
|
ferencd@0
|
441 }
|
|
ferencd@0
|
442 };
|
|
ferencd@0
|
443
|
|
ferencd@0
|
444
|
|
ferencd@0
|
445
|
|
ferencd@0
|
446 /** SMTP test server 3.
|
|
ferencd@0
|
447 *
|
|
ferencd@0
|
448 * Test SIZE extension.
|
|
ferencd@0
|
449 */
|
|
ferencd@0
|
450 template <bool WITH_CHUNKING>
|
|
ferencd@0
|
451 class bigMessageSMTPTestSocket : public testSocket
|
|
ferencd@0
|
452 {
|
|
ferencd@0
|
453 public:
|
|
ferencd@0
|
454
|
|
ferencd@0
|
455 bigMessageSMTPTestSocket()
|
|
ferencd@0
|
456 {
|
|
ferencd@0
|
457 m_state = STATE_NOT_CONNECTED;
|
|
ferencd@0
|
458 m_ehloSent = m_mailSent = m_rcptSent = m_quitSent = false;
|
|
ferencd@0
|
459 }
|
|
ferencd@0
|
460
|
|
ferencd@0
|
461 ~bigMessageSMTPTestSocket()
|
|
ferencd@0
|
462 {
|
|
ferencd@0
|
463 VASSERT("Client must send the QUIT command", m_quitSent);
|
|
ferencd@0
|
464 }
|
|
ferencd@0
|
465
|
|
ferencd@0
|
466 void onConnected()
|
|
ferencd@0
|
467 {
|
|
ferencd@0
|
468 localSend("220 test.vmime.org Service ready\r\n");
|
|
ferencd@0
|
469 processCommand();
|
|
ferencd@0
|
470
|
|
ferencd@0
|
471 m_state = STATE_COMMAND;
|
|
ferencd@0
|
472 }
|
|
ferencd@0
|
473
|
|
ferencd@0
|
474 void onDataReceived()
|
|
ferencd@0
|
475 {
|
|
ferencd@0
|
476 processCommand();
|
|
ferencd@0
|
477 }
|
|
ferencd@0
|
478
|
|
ferencd@0
|
479 void processCommand()
|
|
ferencd@0
|
480 {
|
|
ferencd@0
|
481 vmime::string line;
|
|
ferencd@0
|
482
|
|
ferencd@0
|
483 if (!localReceiveLine(line))
|
|
ferencd@0
|
484 return;
|
|
ferencd@0
|
485
|
|
ferencd@0
|
486 std::istringstream iss(line);
|
|
ferencd@0
|
487
|
|
ferencd@0
|
488 switch (m_state)
|
|
ferencd@0
|
489 {
|
|
ferencd@0
|
490 case STATE_NOT_CONNECTED:
|
|
ferencd@0
|
491
|
|
ferencd@0
|
492 localSend("451 Requested action aborted: invalid state\r\n");
|
|
ferencd@0
|
493 break;
|
|
ferencd@0
|
494
|
|
ferencd@0
|
495 case STATE_COMMAND:
|
|
ferencd@0
|
496 {
|
|
ferencd@0
|
497 std::string cmd;
|
|
ferencd@0
|
498 iss >> cmd;
|
|
ferencd@0
|
499
|
|
ferencd@0
|
500 if (cmd == "EHLO")
|
|
ferencd@0
|
501 {
|
|
ferencd@0
|
502 localSend("250-test.vmime.org says hello\r\n");
|
|
ferencd@0
|
503
|
|
ferencd@0
|
504 if (WITH_CHUNKING)
|
|
ferencd@0
|
505 localSend("250-CHUNKING\r\n");
|
|
ferencd@0
|
506
|
|
ferencd@0
|
507 localSend("250 SIZE 1000000\r\n");
|
|
ferencd@0
|
508
|
|
ferencd@0
|
509 m_ehloSent = true;
|
|
ferencd@0
|
510 }
|
|
ferencd@0
|
511 else if (cmd == "HELO")
|
|
ferencd@0
|
512 {
|
|
ferencd@0
|
513 VASSERT("Client must not send the HELO command, as EHLO succeeded", false);
|
|
ferencd@0
|
514 }
|
|
ferencd@0
|
515 else if (cmd == "MAIL")
|
|
ferencd@0
|
516 {
|
|
ferencd@0
|
517 VASSERT("The MAIL command must be sent only one time", !m_mailSent);
|
|
ferencd@0
|
518
|
|
ferencd@0
|
519 std::string address;
|
|
ferencd@0
|
520 iss >> address;
|
|
ferencd@0
|
521
|
|
ferencd@0
|
522 VASSERT_EQ("MAIL/address", "FROM:<expeditor@test.vmime.org>", address);
|
|
ferencd@0
|
523
|
|
ferencd@0
|
524 std::string option;
|
|
ferencd@0
|
525 iss >> option;
|
|
ferencd@0
|
526
|
|
ferencd@0
|
527 VASSERT_EQ("MAIL/size", "SIZE=4194304", option);
|
|
ferencd@0
|
528
|
|
ferencd@0
|
529 localSend("552 Channel size limit exceeded\r\n");
|
|
ferencd@0
|
530
|
|
ferencd@0
|
531 m_mailSent = true;
|
|
ferencd@0
|
532 }
|
|
ferencd@0
|
533 else if (cmd == "NOOP")
|
|
ferencd@0
|
534 {
|
|
ferencd@0
|
535 localSend("250 Completed\r\n");
|
|
ferencd@0
|
536 }
|
|
ferencd@0
|
537 else if (cmd == "QUIT")
|
|
ferencd@0
|
538 {
|
|
ferencd@0
|
539 localSend("221 test.vmime.org Service closing transmission channel\r\n");
|
|
ferencd@0
|
540
|
|
ferencd@0
|
541 m_quitSent = true;
|
|
ferencd@0
|
542 }
|
|
ferencd@0
|
543 else
|
|
ferencd@0
|
544 {
|
|
ferencd@0
|
545 VASSERT("No other command should be sent", false);
|
|
ferencd@0
|
546
|
|
ferencd@0
|
547 localSend("502 Command not implemented\r\n");
|
|
ferencd@0
|
548 }
|
|
ferencd@0
|
549
|
|
ferencd@0
|
550 break;
|
|
ferencd@0
|
551 }
|
|
ferencd@0
|
552
|
|
ferencd@0
|
553 }
|
|
ferencd@0
|
554
|
|
ferencd@0
|
555 processCommand();
|
|
ferencd@0
|
556 }
|
|
ferencd@0
|
557
|
|
ferencd@0
|
558 private:
|
|
ferencd@0
|
559
|
|
ferencd@0
|
560 enum State
|
|
ferencd@0
|
561 {
|
|
ferencd@0
|
562 STATE_NOT_CONNECTED,
|
|
ferencd@0
|
563 STATE_COMMAND,
|
|
ferencd@0
|
564 STATE_DATA
|
|
ferencd@0
|
565 };
|
|
ferencd@0
|
566
|
|
ferencd@0
|
567 int m_state;
|
|
ferencd@0
|
568
|
|
ferencd@0
|
569 bool m_ehloSent, m_mailSent, m_rcptSent, m_quitSent;
|
|
ferencd@0
|
570 };
|
|
ferencd@0
|
571
|
|
ferencd@0
|
572
|
|
ferencd@0
|
573 template <unsigned long SIZE>
|
|
ferencd@0
|
574 class SMTPBigTestMessage : public vmime::message
|
|
ferencd@0
|
575 {
|
|
ferencd@0
|
576 public:
|
|
ferencd@0
|
577
|
|
ferencd@0
|
578 size_t getGeneratedSize(const vmime::generationContext& /* ctx */)
|
|
ferencd@0
|
579 {
|
|
ferencd@0
|
580 return SIZE;
|
|
ferencd@0
|
581 }
|
|
ferencd@0
|
582
|
|
ferencd@0
|
583 void generateImpl(const vmime::generationContext& /* ctx */,
|
|
ferencd@0
|
584 vmime::utility::outputStream& outputStream,
|
|
ferencd@0
|
585 const vmime::size_t /* curLinePos */ = 0,
|
|
ferencd@0
|
586 vmime::size_t* /* newLinePos */ = NULL) const
|
|
ferencd@0
|
587 {
|
|
ferencd@0
|
588 for (unsigned int i = 0, n = SIZE ; i < n ; ++i)
|
|
ferencd@0
|
589 outputStream.write("X", 1);
|
|
ferencd@0
|
590 }
|
|
ferencd@0
|
591 };
|
|
ferencd@0
|
592
|
|
ferencd@0
|
593 typedef SMTPBigTestMessage <4194304> SMTPBigTestMessage4MB;
|