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