Synchronize with trunk r58606.
[reactos.git] / dll / win32 / inetcomm / smtptransport.c
1 /*
2 * SMTP Transport
3 *
4 * Copyright 2006 Robert Shearman for CodeWeavers
5 * Copyright 2008 Hans Leidekker for CodeWeavers
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 *
21 */
22
23 #define WIN32_NO_STATUS
24 #define _INC_WINDOWS
25 #define COM_NO_WINDOWS_H
26
27 #define COBJMACROS
28
29 //#include <stdarg.h>
30 #include <stdio.h>
31
32 #include <windef.h>
33 #include <winbase.h>
34 //#include "winnt.h"
35 //#include "winuser.h"
36 #include <objbase.h>
37 #include <mimeole.h>
38 #include <wine/debug.h>
39
40 #include "inetcomm_private.h"
41
42 WINE_DEFAULT_DEBUG_CHANNEL(inetcomm);
43
44 typedef struct
45 {
46 InternetTransport InetTransport;
47 ULONG refs;
48 BOOL fESMTP;
49 SMTPMESSAGE pending_message;
50 INETADDR *addrlist;
51 ULONG ulCurrentAddressIndex;
52 } SMTPTransport;
53
54 static HRESULT SMTPTransport_ParseResponse(SMTPTransport *This, char *pszResponse, SMTPRESPONSE *pResponse)
55 {
56 HRESULT hrServerError;
57
58 TRACE("response: %s\n", debugstr_a(pszResponse));
59
60 if (!isdigit(*pszResponse))
61 return IXP_E_SMTP_RESPONSE_ERROR;
62 pResponse->pTransport = (ISMTPTransport *)&This->InetTransport.u.vtblSMTP2;
63 pResponse->rIxpResult.pszResponse = pszResponse;
64 pResponse->rIxpResult.dwSocketError = 0;
65 pResponse->rIxpResult.uiServerError = strtol(pszResponse, &pszResponse, 10);
66 if (*pszResponse == '-')
67 {
68 pResponse->fDone = FALSE;
69 pszResponse++;
70 }
71 else
72 pResponse->fDone = TRUE;
73
74 switch (pResponse->rIxpResult.uiServerError)
75 {
76 case 211: hrServerError = IXP_E_SMTP_211_SYSTEM_STATUS; break;
77 case 214: hrServerError = IXP_E_SMTP_214_HELP_MESSAGE; break;
78 case 220: hrServerError = IXP_E_SMTP_220_READY; break;
79 case 221: hrServerError = IXP_E_SMTP_221_CLOSING; break;
80 case 245: hrServerError = IXP_E_SMTP_245_AUTH_SUCCESS; break;
81 case 250: hrServerError = IXP_E_SMTP_250_MAIL_ACTION_OKAY; break;
82 case 251: hrServerError = IXP_E_SMTP_251_FORWARDING_MAIL; break;
83 case 334: hrServerError = IXP_E_SMTP_334_AUTH_READY_RESPONSE; break;
84 case 354: hrServerError = IXP_E_SMTP_354_START_MAIL_INPUT; break;
85 case 421: hrServerError = IXP_E_SMTP_421_NOT_AVAILABLE; break;
86 case 450: hrServerError = IXP_E_SMTP_450_MAILBOX_BUSY; break;
87 case 451: hrServerError = IXP_E_SMTP_451_ERROR_PROCESSING; break;
88 case 452: hrServerError = IXP_E_SMTP_452_NO_SYSTEM_STORAGE; break;
89 case 454: hrServerError = IXP_E_SMTP_454_STARTTLS_FAILED; break;
90 case 500: hrServerError = IXP_E_SMTP_500_SYNTAX_ERROR; break;
91 case 501: hrServerError = IXP_E_SMTP_501_PARAM_SYNTAX; break;
92 case 502: hrServerError = IXP_E_SMTP_502_COMMAND_NOTIMPL; break;
93 case 503: hrServerError = IXP_E_SMTP_503_COMMAND_SEQ; break;
94 case 504: hrServerError = IXP_E_SMTP_504_COMMAND_PARAM_NOTIMPL; break;
95 case 530: hrServerError = IXP_E_SMTP_530_STARTTLS_REQUIRED; break;
96 case 550: hrServerError = IXP_E_SMTP_550_MAILBOX_NOT_FOUND; break;
97 case 551: hrServerError = IXP_E_SMTP_551_USER_NOT_LOCAL; break;
98 case 552: hrServerError = IXP_E_SMTP_552_STORAGE_OVERFLOW; break;
99 case 553: hrServerError = IXP_E_SMTP_553_MAILBOX_NAME_SYNTAX; break;
100 case 554: hrServerError = IXP_E_SMTP_554_TRANSACT_FAILED; break;
101 default:
102 hrServerError = IXP_E_SMTP_RESPONSE_ERROR;
103 break;
104 }
105 pResponse->rIxpResult.hrResult = hrServerError;
106 pResponse->rIxpResult.hrServerError = hrServerError;
107
108 if (This->InetTransport.pCallback && This->InetTransport.fCommandLogging)
109 {
110 ITransportCallback_OnCommand(This->InetTransport.pCallback, CMD_RESP,
111 pResponse->rIxpResult.pszResponse, hrServerError,
112 (IInternetTransport *)&This->InetTransport.u.vtbl);
113 }
114 return S_OK;
115 }
116
117 static void SMTPTransport_CallbackDoNothing(IInternetTransport *iface, char *pBuffer, int cbBuffer)
118 {
119 TRACE("\n");
120 }
121
122 static void SMTPTransport_CallbackReadResponseDoNothing(IInternetTransport *iface, char *pBuffer, int cbBuffer)
123 {
124 SMTPTransport *This = (SMTPTransport *)iface;
125
126 TRACE("\n");
127 InternetTransport_ReadLine(&This->InetTransport, SMTPTransport_CallbackDoNothing);
128 }
129
130 static void SMTPTransport_CallbackProcessDATAResponse(IInternetTransport *iface, char *pBuffer, int cbBuffer)
131 {
132 SMTPTransport *This = (SMTPTransport *)iface;
133 SMTPRESPONSE response = { 0 };
134 HRESULT hr;
135
136 TRACE("\n");
137
138 hr = SMTPTransport_ParseResponse(This, pBuffer, &response);
139 if (FAILED(hr))
140 {
141 /* FIXME: handle error */
142 return;
143 }
144
145 response.command = SMTP_DATA;
146 ISMTPCallback_OnResponse((ISMTPCallback *)This->InetTransport.pCallback, &response);
147
148 if (FAILED(response.rIxpResult.hrServerError))
149 {
150 ERR("server error: %s\n", debugstr_a(pBuffer));
151 /* FIXME: handle error */
152 return;
153 }
154 }
155
156 static void SMTPTransport_CallbackReadDATAResponse(IInternetTransport *iface, char *pBuffer, int cbBuffer)
157 {
158 SMTPTransport *This = (SMTPTransport *)iface;
159
160 TRACE("\n");
161 InternetTransport_ReadLine(&This->InetTransport, SMTPTransport_CallbackProcessDATAResponse);
162 }
163
164 static void SMTPTransport_CallbackProcessMAILResponse(IInternetTransport *iface, char *pBuffer, int cbBuffer)
165 {
166 SMTPTransport *This = (SMTPTransport *)iface;
167 SMTPRESPONSE response = { 0 };
168 HRESULT hr;
169
170 TRACE("\n");
171
172 hr = SMTPTransport_ParseResponse(This, pBuffer, &response);
173 if (FAILED(hr))
174 {
175 /* FIXME: handle error */
176 return;
177 }
178
179 response.command = SMTP_MAIL;
180 ISMTPCallback_OnResponse((ISMTPCallback *)This->InetTransport.pCallback, &response);
181
182 if (FAILED(response.rIxpResult.hrServerError))
183 {
184 ERR("server error: %s\n", debugstr_a(pBuffer));
185 /* FIXME: handle error */
186 return;
187 }
188 }
189
190 static void SMTPTransport_CallbackReadMAILResponse(IInternetTransport *iface, char *pBuffer, int cbBuffer)
191 {
192 SMTPTransport *This = (SMTPTransport *)iface;
193
194 TRACE("\n");
195 InternetTransport_ReadLine(&This->InetTransport, SMTPTransport_CallbackProcessMAILResponse);
196 }
197
198 static void SMTPTransport_CallbackProcessRCPTResponse(IInternetTransport *iface, char *pBuffer, int cbBuffer)
199 {
200 SMTPTransport *This = (SMTPTransport *)iface;
201 SMTPRESPONSE response = { 0 };
202 HRESULT hr;
203
204 TRACE("\n");
205
206 HeapFree(GetProcessHeap(), 0, This->addrlist);
207 This->addrlist = NULL;
208
209 hr = SMTPTransport_ParseResponse(This, pBuffer, &response);
210 if (FAILED(hr))
211 {
212 /* FIXME: handle error */
213 return;
214 }
215
216 response.command = SMTP_RCPT;
217 ISMTPCallback_OnResponse((ISMTPCallback *)This->InetTransport.pCallback, &response);
218
219 if (FAILED(response.rIxpResult.hrServerError))
220 {
221 ERR("server error: %s\n", debugstr_a(pBuffer));
222 /* FIXME: handle error */
223 return;
224 }
225 }
226
227 static void SMTPTransport_CallbackReadRCPTResponse(IInternetTransport *iface, char *pBuffer, int cbBuffer)
228 {
229 SMTPTransport *This = (SMTPTransport *)iface;
230
231 TRACE("\n");
232 InternetTransport_ReadLine(&This->InetTransport, SMTPTransport_CallbackProcessRCPTResponse);
233 }
234
235 static void SMTPTransport_CallbackProcessHelloResp(IInternetTransport *iface, char *pBuffer, int cbBuffer)
236 {
237 SMTPTransport *This = (SMTPTransport *)iface;
238 SMTPRESPONSE response = { 0 };
239 HRESULT hr;
240
241 TRACE("\n");
242
243 hr = SMTPTransport_ParseResponse(This, pBuffer, &response);
244 if (FAILED(hr))
245 {
246 /* FIXME: handle error */
247 return;
248 }
249
250 response.command = This->fESMTP ? SMTP_EHLO : SMTP_HELO;
251 ISMTPCallback_OnResponse((ISMTPCallback *)This->InetTransport.pCallback, &response);
252
253 if (FAILED(response.rIxpResult.hrServerError))
254 {
255 ERR("server error: %s\n", debugstr_a(pBuffer));
256 /* FIXME: handle error */
257 return;
258 }
259
260 if (!response.fDone)
261 {
262 InternetTransport_ReadLine(&This->InetTransport,
263 SMTPTransport_CallbackProcessHelloResp);
264 return;
265 }
266
267 /* FIXME: try to authorize */
268
269 /* always changed to this status, even if authorization not support on server */
270 InternetTransport_ChangeStatus(&This->InetTransport, IXP_AUTHORIZED);
271 InternetTransport_ChangeStatus(&This->InetTransport, IXP_CONNECTED);
272
273 memset(&response, 0, sizeof(response));
274 response.command = SMTP_CONNECTED;
275 response.fDone = TRUE;
276 ISMTPCallback_OnResponse((ISMTPCallback *)This->InetTransport.pCallback, &response);
277 }
278
279 static void SMTPTransport_CallbackRecvHelloResp(IInternetTransport *iface, char *pBuffer, int cbBuffer)
280 {
281 SMTPTransport *This = (SMTPTransport *)iface;
282
283 TRACE("\n");
284 InternetTransport_ReadLine(&This->InetTransport, SMTPTransport_CallbackProcessHelloResp);
285 }
286
287 static void SMTPTransport_CallbackSendHello(IInternetTransport *iface, char *pBuffer, int cbBuffer)
288 {
289 SMTPTransport *This = (SMTPTransport *)iface;
290 SMTPRESPONSE response = { 0 };
291 HRESULT hr;
292 const char *pszHello;
293 char *pszCommand;
294 const char szHostName[] = "localhost"; /* FIXME */
295
296 TRACE("\n");
297
298 hr = SMTPTransport_ParseResponse(This, pBuffer, &response);
299 if (FAILED(hr))
300 {
301 /* FIXME: handle error */
302 return;
303 }
304
305 response.command = SMTP_BANNER;
306 ISMTPCallback_OnResponse((ISMTPCallback *)This->InetTransport.pCallback, &response);
307
308 if (FAILED(response.rIxpResult.hrServerError))
309 {
310 ERR("server error: %s\n", debugstr_a(pBuffer));
311 /* FIXME: handle error */
312 return;
313 }
314
315 TRACE("(%s)\n", pBuffer);
316
317 This->fESMTP = strstr(response.rIxpResult.pszResponse, "ESMTP") &&
318 This->InetTransport.ServerInfo.dwFlags & (ISF_SSLONSAMEPORT|ISF_QUERYDSNSUPPORT|ISF_QUERYAUTHSUPPORT);
319
320 if (This->fESMTP)
321 pszHello = "EHLO ";
322 else
323 pszHello = "HELO ";
324
325 pszCommand = HeapAlloc(GetProcessHeap(), 0, strlen(pszHello) + strlen(szHostName) + 2);
326 strcpy(pszCommand, pszHello);
327 strcat(pszCommand, szHostName);
328 pszCommand[strlen(pszCommand)+1] = '\0';
329 pszCommand[strlen(pszCommand)] = '\n';
330
331 InternetTransport_DoCommand(&This->InetTransport, pszCommand,
332 SMTPTransport_CallbackRecvHelloResp);
333
334 HeapFree(GetProcessHeap(), 0, pszCommand);
335 }
336
337 static void SMTPTransport_CallbackDisconnect(IInternetTransport *iface, char *pBuffer, int cbBuffer)
338 {
339 SMTPTransport *This = (SMTPTransport *)iface;
340 SMTPRESPONSE response;
341 HRESULT hr;
342
343 TRACE("\n");
344
345 if (pBuffer)
346 {
347 hr = SMTPTransport_ParseResponse(This, pBuffer, &response);
348 if (FAILED(hr))
349 {
350 /* FIXME: handle error */
351 return;
352 }
353
354 if (FAILED(response.rIxpResult.hrServerError))
355 {
356 ERR("server error: %s\n", debugstr_a(pBuffer));
357 /* FIXME: handle error */
358 return;
359 }
360 }
361 InternetTransport_DropConnection(&This->InetTransport);
362 }
363
364 static void SMTPTransport_CallbackMessageProcessResponse(IInternetTransport *iface, char *pBuffer, int cbBuffer)
365 {
366 SMTPTransport *This = (SMTPTransport *)iface;
367 SMTPRESPONSE response = { 0 };
368 HRESULT hr;
369
370 TRACE("\n");
371
372 hr = SMTPTransport_ParseResponse(This, pBuffer, &response);
373 if (FAILED(hr))
374 {
375 /* FIXME: handle error */
376 return;
377 }
378
379 if (FAILED(response.rIxpResult.hrServerError))
380 {
381 ERR("server error: %s\n", debugstr_a(pBuffer));
382 /* FIXME: handle error */
383 return;
384 }
385
386 response.command = SMTP_SEND_MESSAGE;
387 response.rIxpResult.hrResult = S_OK;
388 ISMTPCallback_OnResponse((ISMTPCallback *)This->InetTransport.pCallback, &response);
389 }
390
391 static void SMTPTransport_CallbackMessageReadResponse(IInternetTransport *iface, char *pBuffer, int cbBuffer)
392 {
393 SMTPTransport *This = (SMTPTransport *)iface;
394 InternetTransport_ReadLine(&This->InetTransport, SMTPTransport_CallbackMessageProcessResponse);
395 }
396
397 static void SMTPTransport_CallbackMessageSendDOT(IInternetTransport *iface, char *pBuffer, int cbBuffer)
398 {
399 SMTPTransport *This = (SMTPTransport *)iface;
400
401 IStream_Release(This->pending_message.pstmMsg);
402 InternetTransport_DoCommand(&This->InetTransport, "\n.\n",
403 SMTPTransport_CallbackMessageReadResponse);
404 }
405
406 static void SMTPTransport_CallbackMessageSendDataStream(IInternetTransport *iface, char *pBuffer, int cbBuffer)
407 {
408 SMTPTransport *This = (SMTPTransport *)iface;
409 SMTPRESPONSE response;
410 HRESULT hr;
411 char *pszBuffer;
412 ULONG cbSize;
413
414 TRACE("\n");
415
416 hr = SMTPTransport_ParseResponse(This, pBuffer, &response);
417 if (FAILED(hr))
418 {
419 /* FIXME: handle error */
420 return;
421 }
422
423 if (FAILED(response.rIxpResult.hrServerError))
424 {
425 ERR("server error: %s\n", debugstr_a(pBuffer));
426 /* FIXME: handle error */
427 return;
428 }
429
430 pszBuffer = HeapAlloc(GetProcessHeap(), 0, This->pending_message.cbSize);
431 hr = IStream_Read(This->pending_message.pstmMsg, pszBuffer, This->pending_message.cbSize, NULL);
432 if (FAILED(hr))
433 {
434 /* FIXME: handle error */
435 return;
436 }
437 cbSize = This->pending_message.cbSize;
438
439 /* FIXME: map "\n.\n" to "\n..\n", reallocate memory, update cbSize */
440
441 /* FIXME: properly stream the message rather than writing it all at once */
442
443 hr = InternetTransport_Write(&This->InetTransport, pszBuffer, cbSize,
444 SMTPTransport_CallbackMessageSendDOT);
445
446 HeapFree(GetProcessHeap(), 0, pszBuffer);
447 }
448
449 static void SMTPTransport_CallbackMessageReadDataResponse(IInternetTransport *iface, char *pBuffer, int cbBuffer)
450 {
451 SMTPTransport *This = (SMTPTransport *)iface;
452
453 TRACE("\n");
454 InternetTransport_ReadLine(&This->InetTransport, SMTPTransport_CallbackMessageSendDataStream);
455 }
456
457 static void SMTPTransport_CallbackMessageSendTo(IInternetTransport *iface, char *pBuffer, int cbBuffer);
458
459 static void SMTPTransport_CallbackMessageReadToResponse(IInternetTransport *iface, char *pBuffer, int cbBuffer)
460 {
461 SMTPTransport *This = (SMTPTransport *)iface;
462
463 TRACE("\n");
464 InternetTransport_ReadLine(&This->InetTransport, SMTPTransport_CallbackMessageSendTo);
465 }
466
467 static void SMTPTransport_CallbackMessageSendTo(IInternetTransport *iface, char *pBuffer, int cbBuffer)
468 {
469 SMTPTransport *This = (SMTPTransport *)iface;
470 SMTPRESPONSE response;
471 HRESULT hr;
472
473 TRACE("\n");
474
475 hr = SMTPTransport_ParseResponse(This, pBuffer, &response);
476 if (FAILED(hr))
477 {
478 /* FIXME: handle error */
479 return;
480 }
481
482 if (FAILED(response.rIxpResult.hrServerError))
483 {
484 ERR("server error: %s\n", debugstr_a(pBuffer));
485 /* FIXME: handle error */
486 return;
487 }
488
489 for (; This->ulCurrentAddressIndex < This->pending_message.rAddressList.cAddress; This->ulCurrentAddressIndex++)
490 {
491 TRACE("address[%d]: %s\n", This->ulCurrentAddressIndex,
492 This->pending_message.rAddressList.prgAddress[This->ulCurrentAddressIndex].szEmail);
493
494 if ((This->pending_message.rAddressList.prgAddress[This->ulCurrentAddressIndex].addrtype & ADDR_TOFROM_MASK) == ADDR_TO)
495 {
496 const char szCommandFormat[] = "RCPT TO: <%s>\n";
497 char *szCommand;
498 int len = sizeof(szCommandFormat) - 2 /* "%s" */ +
499 strlen(This->pending_message.rAddressList.prgAddress[This->ulCurrentAddressIndex].szEmail);
500
501 szCommand = HeapAlloc(GetProcessHeap(), 0, len);
502 if (!szCommand)
503 return;
504
505 sprintf(szCommand, szCommandFormat,
506 This->pending_message.rAddressList.prgAddress[This->ulCurrentAddressIndex].szEmail);
507
508 This->ulCurrentAddressIndex++;
509 hr = InternetTransport_DoCommand(&This->InetTransport, szCommand,
510 SMTPTransport_CallbackMessageReadToResponse);
511
512 HeapFree(GetProcessHeap(), 0, szCommand);
513 return;
514 }
515 }
516
517 hr = InternetTransport_DoCommand(&This->InetTransport, "DATA\n",
518 SMTPTransport_CallbackMessageReadDataResponse);
519 }
520
521 static void SMTPTransport_CallbackMessageReadFromResponse(IInternetTransport *iface, char *pBuffer, int cbBuffer)
522 {
523 SMTPTransport *This = (SMTPTransport *)iface;
524
525 TRACE("\n");
526 InternetTransport_ReadLine(&This->InetTransport, SMTPTransport_CallbackMessageSendTo);
527 }
528
529 static HRESULT WINAPI SMTPTransport_QueryInterface(ISMTPTransport2 *iface, REFIID riid, void **ppv)
530 {
531 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
532
533 if (IsEqualIID(riid, &IID_IUnknown) ||
534 IsEqualIID(riid, &IID_IInternetTransport) ||
535 IsEqualIID(riid, &IID_ISMTPTransport) ||
536 IsEqualIID(riid, &IID_ISMTPTransport2))
537 {
538 *ppv = iface;
539 IUnknown_AddRef(iface);
540 return S_OK;
541 }
542 *ppv = NULL;
543 FIXME("no interface for %s\n", debugstr_guid(riid));
544 return E_NOINTERFACE;
545 }
546
547 static ULONG WINAPI SMTPTransport_AddRef(ISMTPTransport2 *iface)
548 {
549 SMTPTransport *This = (SMTPTransport *)iface;
550 return InterlockedIncrement((LONG *)&This->refs);
551 }
552
553 static ULONG WINAPI SMTPTransport_Release(ISMTPTransport2 *iface)
554 {
555 SMTPTransport *This = (SMTPTransport *)iface;
556 ULONG refs = InterlockedDecrement((LONG *)&This->refs);
557 if (!refs)
558 {
559 TRACE("destroying %p\n", This);
560 if (This->InetTransport.Status != IXP_DISCONNECTED)
561 InternetTransport_DropConnection(&This->InetTransport);
562
563 if (This->InetTransport.pCallback) ITransportCallback_Release(This->InetTransport.pCallback);
564 HeapFree(GetProcessHeap(), 0, This->addrlist);
565 HeapFree(GetProcessHeap(), 0, This);
566 }
567 return refs;
568 }
569
570 static HRESULT WINAPI SMTPTransport_GetServerInfo(ISMTPTransport2 *iface,
571 LPINETSERVER pInetServer)
572 {
573 SMTPTransport *This = (SMTPTransport *)iface;
574
575 TRACE("(%p)\n", pInetServer);
576 return InternetTransport_GetServerInfo(&This->InetTransport, pInetServer);
577 }
578
579 static IXPTYPE WINAPI SMTPTransport_GetIXPType(ISMTPTransport2 *iface)
580 {
581 TRACE("()\n");
582 return IXP_SMTP;
583 }
584
585 static HRESULT WINAPI SMTPTransport_IsState(ISMTPTransport2 *iface,
586 IXPISSTATE isstate)
587 {
588 FIXME("(%d): stub\n", isstate);
589 return E_NOTIMPL;
590 }
591
592 static HRESULT WINAPI SMTPTransport_InetServerFromAccount(
593 ISMTPTransport2 *iface, IImnAccount *pAccount, LPINETSERVER pInetServer)
594 {
595 SMTPTransport *This = (SMTPTransport *)iface;
596
597 TRACE("(%p, %p)\n", pAccount, pInetServer);
598 return InternetTransport_InetServerFromAccount(&This->InetTransport, pAccount, pInetServer);
599 }
600
601 static HRESULT WINAPI SMTPTransport_Connect(ISMTPTransport2 *iface,
602 LPINETSERVER pInetServer, boolean fAuthenticate, boolean fCommandLogging)
603 {
604 SMTPTransport *This = (SMTPTransport *)iface;
605 HRESULT hr;
606
607 TRACE("(%p, %s, %s)\n", pInetServer, fAuthenticate ? "TRUE" : "FALSE", fCommandLogging ? "TRUE" : "FALSE");
608
609 hr = InternetTransport_Connect(&This->InetTransport, pInetServer, fAuthenticate, fCommandLogging);
610 if (FAILED(hr))
611 return hr;
612
613 /* this starts the state machine, which continues in SMTPTransport_CallbackSendHELO */
614 return InternetTransport_ReadLine(&This->InetTransport, SMTPTransport_CallbackSendHello);
615 }
616
617 static HRESULT WINAPI SMTPTransport_HandsOffCallback(ISMTPTransport2 *iface)
618 {
619 SMTPTransport *This = (SMTPTransport *)iface;
620
621 TRACE("()\n");
622 return InternetTransport_HandsOffCallback(&This->InetTransport);
623 }
624
625 static HRESULT WINAPI SMTPTransport_Disconnect(ISMTPTransport2 *iface)
626 {
627 TRACE("()\n");
628 return ISMTPTransport2_CommandQUIT(iface);
629 }
630
631 static HRESULT WINAPI SMTPTransport_DropConnection(ISMTPTransport2 *iface)
632 {
633 SMTPTransport *This = (SMTPTransport *)iface;
634
635 TRACE("()\n");
636 return InternetTransport_DropConnection(&This->InetTransport);
637 }
638
639 static HRESULT WINAPI SMTPTransport_GetStatus(ISMTPTransport2 *iface,
640 IXPSTATUS *pCurrentStatus)
641 {
642 SMTPTransport *This = (SMTPTransport *)iface;
643
644 TRACE("()\n");
645 return InternetTransport_GetStatus(&This->InetTransport, pCurrentStatus);
646 }
647
648 static HRESULT WINAPI SMTPTransport_InitNew(ISMTPTransport2 *iface,
649 LPSTR pszLogFilePath, ISMTPCallback *pCallback)
650 {
651 SMTPTransport *This = (SMTPTransport *)iface;
652
653 TRACE("(%s, %p)\n", debugstr_a(pszLogFilePath), pCallback);
654
655 if (!pCallback)
656 return E_INVALIDARG;
657
658 if (pszLogFilePath)
659 FIXME("not using log file of %s, use Wine debug logging instead\n",
660 debugstr_a(pszLogFilePath));
661
662 ISMTPCallback_AddRef(pCallback);
663 This->InetTransport.pCallback = (ITransportCallback *)pCallback;
664 This->InetTransport.fInitialised = TRUE;
665
666 return S_OK;
667 }
668
669 static HRESULT WINAPI SMTPTransport_SendMessage(ISMTPTransport2 *iface,
670 LPSMTPMESSAGE pMessage)
671 {
672 SMTPTransport *This = (SMTPTransport *)iface;
673 ULONG i, size;
674 LPSTR pszFromAddress = NULL;
675 const char szCommandFormat[] = "MAIL FROM: <%s>\n";
676 char *szCommand;
677 int len;
678 HRESULT hr;
679
680 TRACE("(%p)\n", pMessage);
681
682 This->pending_message = *pMessage;
683 IStream_AddRef(pMessage->pstmMsg);
684
685 size = pMessage->rAddressList.cAddress * sizeof(INETADDR);
686 This->addrlist = HeapAlloc(GetProcessHeap(), 0, size);
687 if (!This->addrlist)
688 return E_OUTOFMEMORY;
689
690 memcpy(This->addrlist, pMessage->rAddressList.prgAddress, size);
691 This->pending_message.rAddressList.prgAddress = This->addrlist;
692 This->ulCurrentAddressIndex = 0;
693
694 for (i = 0; i < pMessage->rAddressList.cAddress; i++)
695 {
696 if ((pMessage->rAddressList.prgAddress[i].addrtype & ADDR_TOFROM_MASK) == ADDR_FROM)
697 {
698 TRACE("address[%d]: ADDR_FROM, %s\n", i,
699 pMessage->rAddressList.prgAddress[i].szEmail);
700 pszFromAddress = pMessage->rAddressList.prgAddress[i].szEmail;
701 }
702 else if ((pMessage->rAddressList.prgAddress[i].addrtype & ADDR_TOFROM_MASK) == ADDR_TO)
703 {
704 TRACE("address[%d]: ADDR_TO, %s\n", i,
705 pMessage->rAddressList.prgAddress[i].szEmail);
706 }
707 }
708
709 if (!pszFromAddress)
710 {
711 SMTPRESPONSE response;
712 memset(&response, 0, sizeof(response));
713 response.command = SMTP_SEND_MESSAGE;
714 response.fDone = TRUE;
715 response.pTransport = (ISMTPTransport *)&This->InetTransport.u.vtblSMTP2;
716 response.rIxpResult.hrResult = IXP_E_SMTP_NO_SENDER;
717 ISMTPCallback_OnResponse((ISMTPCallback *)This->InetTransport.pCallback, &response);
718 return S_OK;
719 }
720 len = sizeof(szCommandFormat) - 2 /* "%s" */ + strlen(pszFromAddress);
721
722 szCommand = HeapAlloc(GetProcessHeap(), 0, len);
723 if (!szCommand)
724 return E_OUTOFMEMORY;
725
726 sprintf(szCommand, szCommandFormat, pszFromAddress);
727
728 hr = InternetTransport_DoCommand(&This->InetTransport, szCommand,
729 SMTPTransport_CallbackMessageReadFromResponse);
730
731 return hr;
732 }
733
734 static HRESULT WINAPI SMTPTransport_CommandMAIL(ISMTPTransport2 *iface, LPSTR pszEmailFrom)
735 {
736 SMTPTransport *This = (SMTPTransport *)iface;
737 const char szCommandFormat[] = "MAIL FROM: <%s>\n";
738 char *szCommand;
739 int len;
740 HRESULT hr;
741
742 TRACE("(%s)\n", debugstr_a(pszEmailFrom));
743
744 if (!pszEmailFrom)
745 return E_INVALIDARG;
746
747 len = sizeof(szCommandFormat) - 2 /* "%s" */ + strlen(pszEmailFrom);
748 szCommand = HeapAlloc(GetProcessHeap(), 0, len);
749 if (!szCommand)
750 return E_OUTOFMEMORY;
751
752 sprintf(szCommand, szCommandFormat, pszEmailFrom);
753
754 hr = InternetTransport_DoCommand(&This->InetTransport, szCommand,
755 SMTPTransport_CallbackReadMAILResponse);
756
757 HeapFree(GetProcessHeap(), 0, szCommand);
758 return hr;
759 }
760
761 static HRESULT WINAPI SMTPTransport_CommandRCPT(ISMTPTransport2 *iface, LPSTR pszEmailTo)
762 {
763 SMTPTransport *This = (SMTPTransport *)iface;
764 const char szCommandFormat[] = "RCPT TO: <%s>\n";
765 char *szCommand;
766 int len;
767 HRESULT hr;
768
769 TRACE("(%s)\n", debugstr_a(pszEmailTo));
770
771 if (!pszEmailTo)
772 return E_INVALIDARG;
773
774 len = sizeof(szCommandFormat) - 2 /* "%s" */ + strlen(pszEmailTo);
775 szCommand = HeapAlloc(GetProcessHeap(), 0, len);
776 if (!szCommand)
777 return E_OUTOFMEMORY;
778
779 sprintf(szCommand, szCommandFormat, pszEmailTo);
780
781 hr = InternetTransport_DoCommand(&This->InetTransport, szCommand,
782 SMTPTransport_CallbackReadRCPTResponse);
783
784 HeapFree(GetProcessHeap(), 0, szCommand);
785 return hr;
786 }
787
788 static HRESULT WINAPI SMTPTransport_CommandEHLO(ISMTPTransport2 *iface)
789 {
790 SMTPTransport *This = (SMTPTransport *)iface;
791 const char szCommandFormat[] = "EHLO %s\n";
792 const char szHostname[] = "localhost"; /* FIXME */
793 char *szCommand;
794 int len = sizeof(szCommandFormat) - 2 /* "%s" */ + sizeof(szHostname);
795 HRESULT hr;
796
797 TRACE("\n");
798
799 szCommand = HeapAlloc(GetProcessHeap(), 0, len);
800 if (!szCommand)
801 return E_OUTOFMEMORY;
802
803 sprintf(szCommand, szCommandFormat, szHostname);
804
805 hr = InternetTransport_DoCommand(&This->InetTransport, szCommand,
806 SMTPTransport_CallbackReadResponseDoNothing);
807
808 HeapFree(GetProcessHeap(), 0, szCommand);
809 return hr;
810 }
811
812 static HRESULT WINAPI SMTPTransport_CommandHELO(ISMTPTransport2 *iface)
813 {
814 SMTPTransport *This = (SMTPTransport *)iface;
815 const char szCommandFormat[] = "HELO %s\n";
816 const char szHostname[] = "localhost"; /* FIXME */
817 char *szCommand;
818 int len = sizeof(szCommandFormat) - 2 /* "%s" */ + sizeof(szHostname);
819 HRESULT hr;
820
821 TRACE("()\n");
822
823 szCommand = HeapAlloc(GetProcessHeap(), 0, len);
824 if (!szCommand)
825 return E_OUTOFMEMORY;
826
827 sprintf(szCommand, szCommandFormat, szHostname);
828
829 hr = InternetTransport_DoCommand(&This->InetTransport, szCommand,
830 SMTPTransport_CallbackReadResponseDoNothing);
831
832 HeapFree(GetProcessHeap(), 0, szCommand);
833 return hr;
834 }
835
836 static HRESULT WINAPI SMTPTransport_CommandAUTH(ISMTPTransport2 *iface,
837 LPSTR pszAuthType)
838 {
839 SMTPTransport *This = (SMTPTransport *)iface;
840 const char szCommandFormat[] = "AUTH %s\n";
841 char *szCommand;
842 int len;
843 HRESULT hr;
844
845 TRACE("(%s)\n", debugstr_a(pszAuthType));
846
847 if (!pszAuthType)
848 return E_INVALIDARG;
849
850 len = sizeof(szCommandFormat) - 2 /* "%s" */ + strlen(pszAuthType);
851 szCommand = HeapAlloc(GetProcessHeap(), 0, len);
852 if (!szCommand)
853 return E_OUTOFMEMORY;
854
855 sprintf(szCommand, szCommandFormat, pszAuthType);
856
857 hr = InternetTransport_DoCommand(&This->InetTransport, szCommand,
858 SMTPTransport_CallbackReadResponseDoNothing);
859
860 HeapFree(GetProcessHeap(), 0, szCommand);
861 return hr;
862 }
863
864 static HRESULT WINAPI SMTPTransport_CommandQUIT(ISMTPTransport2 *iface)
865 {
866 SMTPTransport *This = (SMTPTransport *)iface;
867
868 TRACE("()\n");
869
870 InternetTransport_ChangeStatus(&This->InetTransport, IXP_DISCONNECTING);
871 return InternetTransport_DoCommand(&This->InetTransport, "QUIT\n",
872 SMTPTransport_CallbackDisconnect);
873 }
874
875 static HRESULT WINAPI SMTPTransport_CommandRSET(ISMTPTransport2 *iface)
876 {
877 SMTPTransport *This = (SMTPTransport *)iface;
878
879 TRACE("()\n");
880
881 return InternetTransport_DoCommand(&This->InetTransport, "RSET\n",
882 SMTPTransport_CallbackReadResponseDoNothing);
883 }
884
885 static HRESULT WINAPI SMTPTransport_CommandDATA(ISMTPTransport2 *iface)
886 {
887 SMTPTransport *This = (SMTPTransport *)iface;
888
889 TRACE("()\n");
890
891 return InternetTransport_DoCommand(&This->InetTransport, "DATA\n",
892 SMTPTransport_CallbackReadDATAResponse);
893 }
894
895 static HRESULT WINAPI SMTPTransport_CommandDOT(ISMTPTransport2 *iface)
896 {
897 FIXME("()\n");
898 return E_NOTIMPL;
899 }
900
901 static HRESULT WINAPI SMTPTransport_SendDataStream(ISMTPTransport2 *iface,
902 IStream *pStream, ULONG cbSize)
903 {
904 FIXME("(%p, %d)\n", pStream, cbSize);
905 return E_NOTIMPL;
906 }
907
908 static HRESULT WINAPI SMTPTransport_SetWindow(ISMTPTransport2 *iface)
909 {
910 FIXME("()\n");
911 return E_NOTIMPL;
912 }
913
914 static HRESULT WINAPI SMTPTransport_ResetWindow(ISMTPTransport2 *iface)
915 {
916 FIXME("()\n");
917 return E_NOTIMPL;
918 }
919
920 static HRESULT WINAPI SMTPTransport_SendMessage2(ISMTPTransport2 *iface, LPSMTPMESSAGE2 pMessage)
921 {
922 FIXME("(%p)\n", pMessage);
923 return E_NOTIMPL;
924 }
925
926 static HRESULT WINAPI SMTPTransport_CommandRCPT2(ISMTPTransport2 *iface, LPSTR pszEmailTo,
927 INETADDRTYPE atDSN)
928 {
929 FIXME("(%s, %u)\n", pszEmailTo, atDSN);
930 return E_NOTIMPL;
931 }
932
933 static const ISMTPTransport2Vtbl SMTPTransport2Vtbl =
934 {
935 SMTPTransport_QueryInterface,
936 SMTPTransport_AddRef,
937 SMTPTransport_Release,
938 SMTPTransport_GetServerInfo,
939 SMTPTransport_GetIXPType,
940 SMTPTransport_IsState,
941 SMTPTransport_InetServerFromAccount,
942 SMTPTransport_Connect,
943 SMTPTransport_HandsOffCallback,
944 SMTPTransport_Disconnect,
945 SMTPTransport_DropConnection,
946 SMTPTransport_GetStatus,
947 SMTPTransport_InitNew,
948 SMTPTransport_SendMessage,
949 SMTPTransport_CommandMAIL,
950 SMTPTransport_CommandRCPT,
951 SMTPTransport_CommandEHLO,
952 SMTPTransport_CommandHELO,
953 SMTPTransport_CommandAUTH,
954 SMTPTransport_CommandQUIT,
955 SMTPTransport_CommandRSET,
956 SMTPTransport_CommandDATA,
957 SMTPTransport_CommandDOT,
958 SMTPTransport_SendDataStream,
959 SMTPTransport_SetWindow,
960 SMTPTransport_ResetWindow,
961 SMTPTransport_SendMessage2,
962 SMTPTransport_CommandRCPT2
963 };
964
965 HRESULT WINAPI CreateSMTPTransport(ISMTPTransport **ppTransport)
966 {
967 HRESULT hr;
968 SMTPTransport *This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
969 if (!This)
970 return E_OUTOFMEMORY;
971
972 This->InetTransport.u.vtblSMTP2 = &SMTPTransport2Vtbl;
973 This->refs = 0;
974 This->fESMTP = FALSE;
975 hr = InternetTransport_Init(&This->InetTransport);
976 if (FAILED(hr))
977 {
978 HeapFree(GetProcessHeap(), 0, This);
979 return hr;
980 }
981
982 *ppTransport = (ISMTPTransport *)&This->InetTransport.u.vtblSMTP2;
983 ISMTPTransport_AddRef(*ppTransport);
984
985 return S_OK;
986 }
987
988
989 static HRESULT WINAPI SMTPTransportCF_QueryInterface(LPCLASSFACTORY iface,
990 REFIID riid, LPVOID *ppv)
991 {
992 *ppv = NULL;
993 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IClassFactory))
994 {
995 *ppv = iface;
996 IUnknown_AddRef(iface);
997 return S_OK;
998 }
999 return E_NOINTERFACE;
1000 }
1001
1002 static ULONG WINAPI SMTPTransportCF_AddRef(LPCLASSFACTORY iface)
1003 {
1004 return 2; /* non-heap based object */
1005 }
1006
1007 static ULONG WINAPI SMTPTransportCF_Release(LPCLASSFACTORY iface)
1008 {
1009 return 1; /* non-heap based object */
1010 }
1011
1012 static HRESULT WINAPI SMTPTransportCF_CreateInstance(LPCLASSFACTORY iface,
1013 LPUNKNOWN pUnk, REFIID riid, LPVOID *ppv)
1014 {
1015 HRESULT hr;
1016 ISMTPTransport *pSmtpTransport;
1017
1018 TRACE("(%p, %s, %p)\n", pUnk, debugstr_guid(riid), ppv);
1019
1020 *ppv = NULL;
1021
1022 if (pUnk)
1023 return CLASS_E_NOAGGREGATION;
1024
1025 hr = CreateSMTPTransport(&pSmtpTransport);
1026 if (FAILED(hr))
1027 return hr;
1028
1029 hr = ISMTPTransport_QueryInterface(pSmtpTransport, riid, ppv);
1030 ISMTPTransport_Release(pSmtpTransport);
1031
1032 return hr;
1033 }
1034
1035 static HRESULT WINAPI SMTPTransportCF_LockServer(LPCLASSFACTORY iface, BOOL fLock)
1036 {
1037 FIXME("(%d)\n",fLock);
1038 return S_OK;
1039 }
1040
1041 static const IClassFactoryVtbl SMTPTransportCFVtbl =
1042 {
1043 SMTPTransportCF_QueryInterface,
1044 SMTPTransportCF_AddRef,
1045 SMTPTransportCF_Release,
1046 SMTPTransportCF_CreateInstance,
1047 SMTPTransportCF_LockServer
1048 };
1049 static const IClassFactoryVtbl *SMTPTransportCF = &SMTPTransportCFVtbl;
1050
1051 HRESULT SMTPTransportCF_Create(REFIID riid, LPVOID *ppv)
1052 {
1053 return IClassFactory_QueryInterface((IClassFactory *)&SMTPTransportCF, riid, ppv);
1054 }