hidclass.sys: Support parsing of explicit usage page.
[wine.git] / dlls / inetcomm / smtptransport.c
blobd71061ed6b2de31e45e79e5a3f6ab14ca5d78a9e
1 /*
2 * SMTP Transport
4 * Copyright 2006 Robert Shearman for CodeWeavers
5 * Copyright 2008 Hans Leidekker for CodeWeavers
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.
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.
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
23 #define COBJMACROS
25 #include <stdarg.h>
26 #include <stdio.h>
28 #include "windef.h"
29 #include "winbase.h"
30 #include "winnt.h"
31 #include "winuser.h"
32 #include "objbase.h"
33 #include "mimeole.h"
34 #include "wine/debug.h"
36 #include "inetcomm_private.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(inetcomm);
40 typedef struct
42 InternetTransport InetTransport;
43 ULONG refs;
44 BOOL fESMTP;
45 SMTPMESSAGE pending_message;
46 INETADDR *addrlist;
47 ULONG ulCurrentAddressIndex;
48 } SMTPTransport;
50 static HRESULT SMTPTransport_ParseResponse(SMTPTransport *This, char *pszResponse, SMTPRESPONSE *pResponse)
52 HRESULT hrServerError;
54 TRACE("response: %s\n", debugstr_a(pszResponse));
56 if (!isdigit(*pszResponse))
57 return IXP_E_SMTP_RESPONSE_ERROR;
58 pResponse->pTransport = (ISMTPTransport *)&This->InetTransport.u.vtblSMTP2;
59 pResponse->rIxpResult.pszResponse = pszResponse;
60 pResponse->rIxpResult.dwSocketError = 0;
61 pResponse->rIxpResult.uiServerError = strtol(pszResponse, &pszResponse, 10);
62 pResponse->fDone = (*pszResponse != '-');
64 switch (pResponse->rIxpResult.uiServerError)
66 case 211: hrServerError = IXP_E_SMTP_211_SYSTEM_STATUS; break;
67 case 214: hrServerError = IXP_E_SMTP_214_HELP_MESSAGE; break;
68 case 220: hrServerError = IXP_E_SMTP_220_READY; break;
69 case 221: hrServerError = IXP_E_SMTP_221_CLOSING; break;
70 case 245: hrServerError = IXP_E_SMTP_245_AUTH_SUCCESS; break;
71 case 250: hrServerError = IXP_E_SMTP_250_MAIL_ACTION_OKAY; break;
72 case 251: hrServerError = IXP_E_SMTP_251_FORWARDING_MAIL; break;
73 case 334: hrServerError = IXP_E_SMTP_334_AUTH_READY_RESPONSE; break;
74 case 354: hrServerError = IXP_E_SMTP_354_START_MAIL_INPUT; break;
75 case 421: hrServerError = IXP_E_SMTP_421_NOT_AVAILABLE; break;
76 case 450: hrServerError = IXP_E_SMTP_450_MAILBOX_BUSY; break;
77 case 451: hrServerError = IXP_E_SMTP_451_ERROR_PROCESSING; break;
78 case 452: hrServerError = IXP_E_SMTP_452_NO_SYSTEM_STORAGE; break;
79 case 454: hrServerError = IXP_E_SMTP_454_STARTTLS_FAILED; break;
80 case 500: hrServerError = IXP_E_SMTP_500_SYNTAX_ERROR; break;
81 case 501: hrServerError = IXP_E_SMTP_501_PARAM_SYNTAX; break;
82 case 502: hrServerError = IXP_E_SMTP_502_COMMAND_NOTIMPL; break;
83 case 503: hrServerError = IXP_E_SMTP_503_COMMAND_SEQ; break;
84 case 504: hrServerError = IXP_E_SMTP_504_COMMAND_PARAM_NOTIMPL; break;
85 case 530: hrServerError = IXP_E_SMTP_530_STARTTLS_REQUIRED; break;
86 case 550: hrServerError = IXP_E_SMTP_550_MAILBOX_NOT_FOUND; break;
87 case 551: hrServerError = IXP_E_SMTP_551_USER_NOT_LOCAL; break;
88 case 552: hrServerError = IXP_E_SMTP_552_STORAGE_OVERFLOW; break;
89 case 553: hrServerError = IXP_E_SMTP_553_MAILBOX_NAME_SYNTAX; break;
90 case 554: hrServerError = IXP_E_SMTP_554_TRANSACT_FAILED; break;
91 default:
92 hrServerError = IXP_E_SMTP_RESPONSE_ERROR;
93 break;
95 pResponse->rIxpResult.hrResult = hrServerError;
96 pResponse->rIxpResult.hrServerError = hrServerError;
98 if (This->InetTransport.pCallback && This->InetTransport.fCommandLogging)
100 ITransportCallback_OnCommand(This->InetTransport.pCallback, CMD_RESP,
101 pResponse->rIxpResult.pszResponse, hrServerError,
102 (IInternetTransport *)&This->InetTransport.u.vtbl);
104 return S_OK;
107 static void SMTPTransport_CallbackDoNothing(IInternetTransport *iface, char *pBuffer, int cbBuffer)
109 TRACE("\n");
112 static void SMTPTransport_CallbackReadResponseDoNothing(IInternetTransport *iface, char *pBuffer, int cbBuffer)
114 SMTPTransport *This = (SMTPTransport *)iface;
116 TRACE("\n");
117 InternetTransport_ReadLine(&This->InetTransport, SMTPTransport_CallbackDoNothing);
120 static void SMTPTransport_CallbackProcessDATAResponse(IInternetTransport *iface, char *pBuffer, int cbBuffer)
122 SMTPTransport *This = (SMTPTransport *)iface;
123 SMTPRESPONSE response = { 0 };
124 HRESULT hr;
126 TRACE("\n");
128 hr = SMTPTransport_ParseResponse(This, pBuffer, &response);
129 if (FAILED(hr))
131 /* FIXME: handle error */
132 return;
135 response.command = SMTP_DATA;
136 ISMTPCallback_OnResponse((ISMTPCallback *)This->InetTransport.pCallback, &response);
138 if (FAILED(response.rIxpResult.hrServerError))
140 ERR("server error: %s\n", debugstr_a(pBuffer));
141 /* FIXME: handle error */
142 return;
146 static void SMTPTransport_CallbackReadDATAResponse(IInternetTransport *iface, char *pBuffer, int cbBuffer)
148 SMTPTransport *This = (SMTPTransport *)iface;
150 TRACE("\n");
151 InternetTransport_ReadLine(&This->InetTransport, SMTPTransport_CallbackProcessDATAResponse);
154 static void SMTPTransport_CallbackProcessMAILResponse(IInternetTransport *iface, char *pBuffer, int cbBuffer)
156 SMTPTransport *This = (SMTPTransport *)iface;
157 SMTPRESPONSE response = { 0 };
158 HRESULT hr;
160 TRACE("\n");
162 hr = SMTPTransport_ParseResponse(This, pBuffer, &response);
163 if (FAILED(hr))
165 /* FIXME: handle error */
166 return;
169 response.command = SMTP_MAIL;
170 ISMTPCallback_OnResponse((ISMTPCallback *)This->InetTransport.pCallback, &response);
172 if (FAILED(response.rIxpResult.hrServerError))
174 ERR("server error: %s\n", debugstr_a(pBuffer));
175 /* FIXME: handle error */
176 return;
180 static void SMTPTransport_CallbackReadMAILResponse(IInternetTransport *iface, char *pBuffer, int cbBuffer)
182 SMTPTransport *This = (SMTPTransport *)iface;
184 TRACE("\n");
185 InternetTransport_ReadLine(&This->InetTransport, SMTPTransport_CallbackProcessMAILResponse);
188 static void SMTPTransport_CallbackProcessRCPTResponse(IInternetTransport *iface, char *pBuffer, int cbBuffer)
190 SMTPTransport *This = (SMTPTransport *)iface;
191 SMTPRESPONSE response = { 0 };
192 HRESULT hr;
194 TRACE("\n");
196 HeapFree(GetProcessHeap(), 0, This->addrlist);
197 This->addrlist = NULL;
199 hr = SMTPTransport_ParseResponse(This, pBuffer, &response);
200 if (FAILED(hr))
202 /* FIXME: handle error */
203 return;
206 response.command = SMTP_RCPT;
207 ISMTPCallback_OnResponse((ISMTPCallback *)This->InetTransport.pCallback, &response);
209 if (FAILED(response.rIxpResult.hrServerError))
211 ERR("server error: %s\n", debugstr_a(pBuffer));
212 /* FIXME: handle error */
213 return;
217 static void SMTPTransport_CallbackReadRCPTResponse(IInternetTransport *iface, char *pBuffer, int cbBuffer)
219 SMTPTransport *This = (SMTPTransport *)iface;
221 TRACE("\n");
222 InternetTransport_ReadLine(&This->InetTransport, SMTPTransport_CallbackProcessRCPTResponse);
225 static void SMTPTransport_CallbackProcessHelloResp(IInternetTransport *iface, char *pBuffer, int cbBuffer)
227 SMTPTransport *This = (SMTPTransport *)iface;
228 SMTPRESPONSE response = { 0 };
229 HRESULT hr;
231 TRACE("\n");
233 hr = SMTPTransport_ParseResponse(This, pBuffer, &response);
234 if (FAILED(hr))
236 /* FIXME: handle error */
237 return;
240 response.command = This->fESMTP ? SMTP_EHLO : SMTP_HELO;
241 ISMTPCallback_OnResponse((ISMTPCallback *)This->InetTransport.pCallback, &response);
243 if (FAILED(response.rIxpResult.hrServerError))
245 ERR("server error: %s\n", debugstr_a(pBuffer));
246 /* FIXME: handle error */
247 return;
250 if (!response.fDone)
252 InternetTransport_ReadLine(&This->InetTransport,
253 SMTPTransport_CallbackProcessHelloResp);
254 return;
257 /* FIXME: try to authorize */
259 /* always changed to this status, even if authorization not support on server */
260 InternetTransport_ChangeStatus(&This->InetTransport, IXP_AUTHORIZED);
261 InternetTransport_ChangeStatus(&This->InetTransport, IXP_CONNECTED);
263 memset(&response, 0, sizeof(response));
264 response.command = SMTP_CONNECTED;
265 response.fDone = TRUE;
266 ISMTPCallback_OnResponse((ISMTPCallback *)This->InetTransport.pCallback, &response);
269 static void SMTPTransport_CallbackRecvHelloResp(IInternetTransport *iface, char *pBuffer, int cbBuffer)
271 SMTPTransport *This = (SMTPTransport *)iface;
273 TRACE("\n");
274 InternetTransport_ReadLine(&This->InetTransport, SMTPTransport_CallbackProcessHelloResp);
277 static void SMTPTransport_CallbackSendHello(IInternetTransport *iface, char *pBuffer, int cbBuffer)
279 SMTPTransport *This = (SMTPTransport *)iface;
280 SMTPRESPONSE response = { 0 };
281 HRESULT hr;
282 const char *pszHello;
283 char *pszCommand;
284 static const char szHostName[] = "localhost"; /* FIXME */
286 TRACE("\n");
288 hr = SMTPTransport_ParseResponse(This, pBuffer, &response);
289 if (FAILED(hr))
291 /* FIXME: handle error */
292 return;
295 response.command = SMTP_BANNER;
296 ISMTPCallback_OnResponse((ISMTPCallback *)This->InetTransport.pCallback, &response);
298 if (FAILED(response.rIxpResult.hrServerError))
300 ERR("server error: %s\n", debugstr_a(pBuffer));
301 /* FIXME: handle error */
302 return;
305 TRACE("(%s)\n", pBuffer);
307 This->fESMTP = strstr(response.rIxpResult.pszResponse, "ESMTP") &&
308 This->InetTransport.ServerInfo.dwFlags & (ISF_SSLONSAMEPORT|ISF_QUERYDSNSUPPORT|ISF_QUERYAUTHSUPPORT);
310 if (This->fESMTP)
311 pszHello = "EHLO ";
312 else
313 pszHello = "HELO ";
315 pszCommand = HeapAlloc(GetProcessHeap(), 0, strlen(pszHello) + strlen(szHostName) + 2);
316 strcpy(pszCommand, pszHello);
317 strcat(pszCommand, szHostName);
318 pszCommand[strlen(pszCommand)+1] = '\0';
319 pszCommand[strlen(pszCommand)] = '\n';
321 InternetTransport_DoCommand(&This->InetTransport, pszCommand,
322 SMTPTransport_CallbackRecvHelloResp);
324 HeapFree(GetProcessHeap(), 0, pszCommand);
327 static void SMTPTransport_CallbackDisconnect(IInternetTransport *iface, char *pBuffer, int cbBuffer)
329 SMTPTransport *This = (SMTPTransport *)iface;
330 SMTPRESPONSE response;
331 HRESULT hr;
333 TRACE("\n");
335 if (pBuffer)
337 hr = SMTPTransport_ParseResponse(This, pBuffer, &response);
338 if (FAILED(hr))
340 /* FIXME: handle error */
341 return;
344 if (FAILED(response.rIxpResult.hrServerError))
346 ERR("server error: %s\n", debugstr_a(pBuffer));
347 /* FIXME: handle error */
348 return;
351 InternetTransport_DropConnection(&This->InetTransport);
354 static void SMTPTransport_CallbackMessageProcessResponse(IInternetTransport *iface, char *pBuffer, int cbBuffer)
356 SMTPTransport *This = (SMTPTransport *)iface;
357 SMTPRESPONSE response = { 0 };
358 HRESULT hr;
360 TRACE("\n");
362 hr = SMTPTransport_ParseResponse(This, pBuffer, &response);
363 if (FAILED(hr))
365 /* FIXME: handle error */
366 return;
369 if (FAILED(response.rIxpResult.hrServerError))
371 ERR("server error: %s\n", debugstr_a(pBuffer));
372 /* FIXME: handle error */
373 return;
376 response.command = SMTP_SEND_MESSAGE;
377 response.rIxpResult.hrResult = S_OK;
378 ISMTPCallback_OnResponse((ISMTPCallback *)This->InetTransport.pCallback, &response);
381 static void SMTPTransport_CallbackMessageReadResponse(IInternetTransport *iface, char *pBuffer, int cbBuffer)
383 SMTPTransport *This = (SMTPTransport *)iface;
384 InternetTransport_ReadLine(&This->InetTransport, SMTPTransport_CallbackMessageProcessResponse);
387 static void SMTPTransport_CallbackMessageSendDOT(IInternetTransport *iface, char *pBuffer, int cbBuffer)
389 SMTPTransport *This = (SMTPTransport *)iface;
391 IStream_Release(This->pending_message.pstmMsg);
392 InternetTransport_DoCommand(&This->InetTransport, "\n.\n",
393 SMTPTransport_CallbackMessageReadResponse);
396 static void SMTPTransport_CallbackMessageSendDataStream(IInternetTransport *iface, char *pBuffer, int cbBuffer)
398 SMTPTransport *This = (SMTPTransport *)iface;
399 SMTPRESPONSE response;
400 HRESULT hr;
401 char *pszBuffer;
402 ULONG cbSize;
404 TRACE("\n");
406 hr = SMTPTransport_ParseResponse(This, pBuffer, &response);
407 if (FAILED(hr))
409 /* FIXME: handle error */
410 return;
413 if (FAILED(response.rIxpResult.hrServerError))
415 ERR("server error: %s\n", debugstr_a(pBuffer));
416 /* FIXME: handle error */
417 return;
420 pszBuffer = HeapAlloc(GetProcessHeap(), 0, This->pending_message.cbSize);
421 hr = IStream_Read(This->pending_message.pstmMsg, pszBuffer, This->pending_message.cbSize, NULL);
422 if (FAILED(hr))
424 /* FIXME: handle error */
425 return;
427 cbSize = This->pending_message.cbSize;
429 /* FIXME: map "\n.\n" to "\n..\n", reallocate memory, update cbSize */
431 /* FIXME: properly stream the message rather than writing it all at once */
433 hr = InternetTransport_Write(&This->InetTransport, pszBuffer, cbSize,
434 SMTPTransport_CallbackMessageSendDOT);
436 HeapFree(GetProcessHeap(), 0, pszBuffer);
439 static void SMTPTransport_CallbackMessageReadDataResponse(IInternetTransport *iface, char *pBuffer, int cbBuffer)
441 SMTPTransport *This = (SMTPTransport *)iface;
443 TRACE("\n");
444 InternetTransport_ReadLine(&This->InetTransport, SMTPTransport_CallbackMessageSendDataStream);
447 static void SMTPTransport_CallbackMessageSendTo(IInternetTransport *iface, char *pBuffer, int cbBuffer);
449 static void SMTPTransport_CallbackMessageReadToResponse(IInternetTransport *iface, char *pBuffer, int cbBuffer)
451 SMTPTransport *This = (SMTPTransport *)iface;
453 TRACE("\n");
454 InternetTransport_ReadLine(&This->InetTransport, SMTPTransport_CallbackMessageSendTo);
457 static void SMTPTransport_CallbackMessageSendTo(IInternetTransport *iface, char *pBuffer, int cbBuffer)
459 SMTPTransport *This = (SMTPTransport *)iface;
460 SMTPRESPONSE response;
461 HRESULT hr;
463 TRACE("\n");
465 hr = SMTPTransport_ParseResponse(This, pBuffer, &response);
466 if (FAILED(hr))
468 /* FIXME: handle error */
469 return;
472 if (FAILED(response.rIxpResult.hrServerError))
474 ERR("server error: %s\n", debugstr_a(pBuffer));
475 /* FIXME: handle error */
476 return;
479 for (; This->ulCurrentAddressIndex < This->pending_message.rAddressList.cAddress; This->ulCurrentAddressIndex++)
481 TRACE("address[%d]: %s\n", This->ulCurrentAddressIndex,
482 This->pending_message.rAddressList.prgAddress[This->ulCurrentAddressIndex].szEmail);
484 if ((This->pending_message.rAddressList.prgAddress[This->ulCurrentAddressIndex].addrtype & ADDR_TOFROM_MASK) == ADDR_TO)
486 static const char szCommandFormat[] = "RCPT TO: <%s>\n";
487 char *szCommand;
488 int len = sizeof(szCommandFormat) - 2 /* "%s" */ +
489 strlen(This->pending_message.rAddressList.prgAddress[This->ulCurrentAddressIndex].szEmail);
491 szCommand = HeapAlloc(GetProcessHeap(), 0, len);
492 if (!szCommand)
493 return;
495 sprintf(szCommand, szCommandFormat,
496 This->pending_message.rAddressList.prgAddress[This->ulCurrentAddressIndex].szEmail);
498 This->ulCurrentAddressIndex++;
499 hr = InternetTransport_DoCommand(&This->InetTransport, szCommand,
500 SMTPTransport_CallbackMessageReadToResponse);
502 HeapFree(GetProcessHeap(), 0, szCommand);
503 return;
507 hr = InternetTransport_DoCommand(&This->InetTransport, "DATA\n",
508 SMTPTransport_CallbackMessageReadDataResponse);
511 static void SMTPTransport_CallbackMessageReadFromResponse(IInternetTransport *iface, char *pBuffer, int cbBuffer)
513 SMTPTransport *This = (SMTPTransport *)iface;
515 TRACE("\n");
516 InternetTransport_ReadLine(&This->InetTransport, SMTPTransport_CallbackMessageSendTo);
519 static HRESULT WINAPI SMTPTransport_QueryInterface(ISMTPTransport2 *iface, REFIID riid, void **ppv)
521 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
523 if (IsEqualIID(riid, &IID_IUnknown) ||
524 IsEqualIID(riid, &IID_IInternetTransport) ||
525 IsEqualIID(riid, &IID_ISMTPTransport) ||
526 IsEqualIID(riid, &IID_ISMTPTransport2))
528 *ppv = iface;
529 ISMTPTransport2_AddRef(iface);
530 return S_OK;
532 *ppv = NULL;
533 FIXME("no interface for %s\n", debugstr_guid(riid));
534 return E_NOINTERFACE;
537 static ULONG WINAPI SMTPTransport_AddRef(ISMTPTransport2 *iface)
539 SMTPTransport *This = (SMTPTransport *)iface;
540 return InterlockedIncrement((LONG *)&This->refs);
543 static ULONG WINAPI SMTPTransport_Release(ISMTPTransport2 *iface)
545 SMTPTransport *This = (SMTPTransport *)iface;
546 ULONG refs = InterlockedDecrement((LONG *)&This->refs);
547 if (!refs)
549 TRACE("destroying %p\n", This);
550 if (This->InetTransport.Status != IXP_DISCONNECTED)
551 InternetTransport_DropConnection(&This->InetTransport);
553 if (This->InetTransport.pCallback) ITransportCallback_Release(This->InetTransport.pCallback);
554 HeapFree(GetProcessHeap(), 0, This->addrlist);
555 HeapFree(GetProcessHeap(), 0, This);
557 return refs;
560 static HRESULT WINAPI SMTPTransport_GetServerInfo(ISMTPTransport2 *iface,
561 LPINETSERVER pInetServer)
563 SMTPTransport *This = (SMTPTransport *)iface;
565 TRACE("(%p)\n", pInetServer);
566 return InternetTransport_GetServerInfo(&This->InetTransport, pInetServer);
569 static IXPTYPE WINAPI SMTPTransport_GetIXPType(ISMTPTransport2 *iface)
571 TRACE("()\n");
572 return IXP_SMTP;
575 static HRESULT WINAPI SMTPTransport_IsState(ISMTPTransport2 *iface,
576 IXPISSTATE isstate)
578 FIXME("(%d): stub\n", isstate);
579 return E_NOTIMPL;
582 static HRESULT WINAPI SMTPTransport_InetServerFromAccount(
583 ISMTPTransport2 *iface, IImnAccount *pAccount, LPINETSERVER pInetServer)
585 SMTPTransport *This = (SMTPTransport *)iface;
587 TRACE("(%p, %p)\n", pAccount, pInetServer);
588 return InternetTransport_InetServerFromAccount(&This->InetTransport, pAccount, pInetServer);
591 static HRESULT WINAPI SMTPTransport_Connect(ISMTPTransport2 *iface,
592 LPINETSERVER pInetServer, boolean fAuthenticate, boolean fCommandLogging)
594 SMTPTransport *This = (SMTPTransport *)iface;
595 HRESULT hr;
597 TRACE("(%p, %s, %s)\n", pInetServer, fAuthenticate ? "TRUE" : "FALSE", fCommandLogging ? "TRUE" : "FALSE");
599 hr = InternetTransport_Connect(&This->InetTransport, pInetServer, fAuthenticate, fCommandLogging);
600 if (FAILED(hr))
601 return hr;
603 /* this starts the state machine, which continues in SMTPTransport_CallbackSendHELO */
604 return InternetTransport_ReadLine(&This->InetTransport, SMTPTransport_CallbackSendHello);
607 static HRESULT WINAPI SMTPTransport_HandsOffCallback(ISMTPTransport2 *iface)
609 SMTPTransport *This = (SMTPTransport *)iface;
611 TRACE("()\n");
612 return InternetTransport_HandsOffCallback(&This->InetTransport);
615 static HRESULT WINAPI SMTPTransport_Disconnect(ISMTPTransport2 *iface)
617 TRACE("()\n");
618 return ISMTPTransport2_CommandQUIT(iface);
621 static HRESULT WINAPI SMTPTransport_DropConnection(ISMTPTransport2 *iface)
623 SMTPTransport *This = (SMTPTransport *)iface;
625 TRACE("()\n");
626 return InternetTransport_DropConnection(&This->InetTransport);
629 static HRESULT WINAPI SMTPTransport_GetStatus(ISMTPTransport2 *iface,
630 IXPSTATUS *pCurrentStatus)
632 SMTPTransport *This = (SMTPTransport *)iface;
634 TRACE("()\n");
635 return InternetTransport_GetStatus(&This->InetTransport, pCurrentStatus);
638 static HRESULT WINAPI SMTPTransport_InitNew(ISMTPTransport2 *iface,
639 LPSTR pszLogFilePath, ISMTPCallback *pCallback)
641 SMTPTransport *This = (SMTPTransport *)iface;
643 TRACE("(%s, %p)\n", debugstr_a(pszLogFilePath), pCallback);
645 if (!pCallback)
646 return E_INVALIDARG;
648 if (pszLogFilePath)
649 FIXME("not using log file of %s, use Wine debug logging instead\n",
650 debugstr_a(pszLogFilePath));
652 ISMTPCallback_AddRef(pCallback);
653 This->InetTransport.pCallback = (ITransportCallback *)pCallback;
654 This->InetTransport.fInitialised = TRUE;
656 return S_OK;
659 static HRESULT WINAPI SMTPTransport_SendMessage(ISMTPTransport2 *iface,
660 LPSMTPMESSAGE pMessage)
662 static const char szCommandFormat[] = "MAIL FROM: <%s>\n";
663 SMTPTransport *This = (SMTPTransport *)iface;
664 ULONG i, size;
665 LPSTR pszFromAddress = NULL;
666 char *szCommand;
667 int len;
668 HRESULT hr;
670 TRACE("(%p)\n", pMessage);
672 This->pending_message = *pMessage;
673 IStream_AddRef(pMessage->pstmMsg);
675 size = pMessage->rAddressList.cAddress * sizeof(INETADDR);
676 This->addrlist = HeapAlloc(GetProcessHeap(), 0, size);
677 if (!This->addrlist)
678 return E_OUTOFMEMORY;
680 memcpy(This->addrlist, pMessage->rAddressList.prgAddress, size);
681 This->pending_message.rAddressList.prgAddress = This->addrlist;
682 This->ulCurrentAddressIndex = 0;
684 for (i = 0; i < pMessage->rAddressList.cAddress; i++)
686 if ((pMessage->rAddressList.prgAddress[i].addrtype & ADDR_TOFROM_MASK) == ADDR_FROM)
688 TRACE("address[%d]: ADDR_FROM, %s\n", i,
689 pMessage->rAddressList.prgAddress[i].szEmail);
690 pszFromAddress = pMessage->rAddressList.prgAddress[i].szEmail;
692 else if ((pMessage->rAddressList.prgAddress[i].addrtype & ADDR_TOFROM_MASK) == ADDR_TO)
694 TRACE("address[%d]: ADDR_TO, %s\n", i,
695 pMessage->rAddressList.prgAddress[i].szEmail);
699 if (!pszFromAddress)
701 SMTPRESPONSE response;
702 memset(&response, 0, sizeof(response));
703 response.command = SMTP_SEND_MESSAGE;
704 response.fDone = TRUE;
705 response.pTransport = (ISMTPTransport *)&This->InetTransport.u.vtblSMTP2;
706 response.rIxpResult.hrResult = IXP_E_SMTP_NO_SENDER;
707 ISMTPCallback_OnResponse((ISMTPCallback *)This->InetTransport.pCallback, &response);
708 return S_OK;
710 len = sizeof(szCommandFormat) - 2 /* "%s" */ + strlen(pszFromAddress);
712 szCommand = HeapAlloc(GetProcessHeap(), 0, len);
713 if (!szCommand)
714 return E_OUTOFMEMORY;
716 sprintf(szCommand, szCommandFormat, pszFromAddress);
718 hr = InternetTransport_DoCommand(&This->InetTransport, szCommand,
719 SMTPTransport_CallbackMessageReadFromResponse);
721 return hr;
724 static HRESULT WINAPI SMTPTransport_CommandMAIL(ISMTPTransport2 *iface, LPSTR pszEmailFrom)
726 static const char szCommandFormat[] = "MAIL FROM: <%s>\n";
727 SMTPTransport *This = (SMTPTransport *)iface;
728 char *szCommand;
729 int len;
730 HRESULT hr;
732 TRACE("(%s)\n", debugstr_a(pszEmailFrom));
734 if (!pszEmailFrom)
735 return E_INVALIDARG;
737 len = sizeof(szCommandFormat) - 2 /* "%s" */ + strlen(pszEmailFrom);
738 szCommand = HeapAlloc(GetProcessHeap(), 0, len);
739 if (!szCommand)
740 return E_OUTOFMEMORY;
742 sprintf(szCommand, szCommandFormat, pszEmailFrom);
744 hr = InternetTransport_DoCommand(&This->InetTransport, szCommand,
745 SMTPTransport_CallbackReadMAILResponse);
747 HeapFree(GetProcessHeap(), 0, szCommand);
748 return hr;
751 static HRESULT WINAPI SMTPTransport_CommandRCPT(ISMTPTransport2 *iface, LPSTR pszEmailTo)
753 static const char szCommandFormat[] = "RCPT TO: <%s>\n";
754 SMTPTransport *This = (SMTPTransport *)iface;
755 char *szCommand;
756 int len;
757 HRESULT hr;
759 TRACE("(%s)\n", debugstr_a(pszEmailTo));
761 if (!pszEmailTo)
762 return E_INVALIDARG;
764 len = sizeof(szCommandFormat) - 2 /* "%s" */ + strlen(pszEmailTo);
765 szCommand = HeapAlloc(GetProcessHeap(), 0, len);
766 if (!szCommand)
767 return E_OUTOFMEMORY;
769 sprintf(szCommand, szCommandFormat, pszEmailTo);
771 hr = InternetTransport_DoCommand(&This->InetTransport, szCommand,
772 SMTPTransport_CallbackReadRCPTResponse);
774 HeapFree(GetProcessHeap(), 0, szCommand);
775 return hr;
778 static HRESULT WINAPI SMTPTransport_CommandEHLO(ISMTPTransport2 *iface)
780 static const char szCommandFormat[] = "EHLO %s\n";
781 static const char szHostname[] = "localhost"; /* FIXME */
782 SMTPTransport *This = (SMTPTransport *)iface;
783 char *szCommand;
784 int len = sizeof(szCommandFormat) - 2 /* "%s" */ + sizeof(szHostname);
785 HRESULT hr;
787 TRACE("\n");
789 szCommand = HeapAlloc(GetProcessHeap(), 0, len);
790 if (!szCommand)
791 return E_OUTOFMEMORY;
793 sprintf(szCommand, szCommandFormat, szHostname);
795 hr = InternetTransport_DoCommand(&This->InetTransport, szCommand,
796 SMTPTransport_CallbackReadResponseDoNothing);
798 HeapFree(GetProcessHeap(), 0, szCommand);
799 return hr;
802 static HRESULT WINAPI SMTPTransport_CommandHELO(ISMTPTransport2 *iface)
804 static const char szCommandFormat[] = "HELO %s\n";
805 static const char szHostname[] = "localhost"; /* FIXME */
806 SMTPTransport *This = (SMTPTransport *)iface;
807 char *szCommand;
808 int len = sizeof(szCommandFormat) - 2 /* "%s" */ + sizeof(szHostname);
809 HRESULT hr;
811 TRACE("()\n");
813 szCommand = HeapAlloc(GetProcessHeap(), 0, len);
814 if (!szCommand)
815 return E_OUTOFMEMORY;
817 sprintf(szCommand, szCommandFormat, szHostname);
819 hr = InternetTransport_DoCommand(&This->InetTransport, szCommand,
820 SMTPTransport_CallbackReadResponseDoNothing);
822 HeapFree(GetProcessHeap(), 0, szCommand);
823 return hr;
826 static HRESULT WINAPI SMTPTransport_CommandAUTH(ISMTPTransport2 *iface,
827 LPSTR pszAuthType)
829 static const char szCommandFormat[] = "AUTH %s\n";
830 SMTPTransport *This = (SMTPTransport *)iface;
831 char *szCommand;
832 int len;
833 HRESULT hr;
835 TRACE("(%s)\n", debugstr_a(pszAuthType));
837 if (!pszAuthType)
838 return E_INVALIDARG;
840 len = sizeof(szCommandFormat) - 2 /* "%s" */ + strlen(pszAuthType);
841 szCommand = HeapAlloc(GetProcessHeap(), 0, len);
842 if (!szCommand)
843 return E_OUTOFMEMORY;
845 sprintf(szCommand, szCommandFormat, pszAuthType);
847 hr = InternetTransport_DoCommand(&This->InetTransport, szCommand,
848 SMTPTransport_CallbackReadResponseDoNothing);
850 HeapFree(GetProcessHeap(), 0, szCommand);
851 return hr;
854 static HRESULT WINAPI SMTPTransport_CommandQUIT(ISMTPTransport2 *iface)
856 SMTPTransport *This = (SMTPTransport *)iface;
858 TRACE("()\n");
860 InternetTransport_ChangeStatus(&This->InetTransport, IXP_DISCONNECTING);
861 return InternetTransport_DoCommand(&This->InetTransport, "QUIT\n",
862 SMTPTransport_CallbackDisconnect);
865 static HRESULT WINAPI SMTPTransport_CommandRSET(ISMTPTransport2 *iface)
867 SMTPTransport *This = (SMTPTransport *)iface;
869 TRACE("()\n");
871 return InternetTransport_DoCommand(&This->InetTransport, "RSET\n",
872 SMTPTransport_CallbackReadResponseDoNothing);
875 static HRESULT WINAPI SMTPTransport_CommandDATA(ISMTPTransport2 *iface)
877 SMTPTransport *This = (SMTPTransport *)iface;
879 TRACE("()\n");
881 return InternetTransport_DoCommand(&This->InetTransport, "DATA\n",
882 SMTPTransport_CallbackReadDATAResponse);
885 static HRESULT WINAPI SMTPTransport_CommandDOT(ISMTPTransport2 *iface)
887 FIXME("()\n");
888 return E_NOTIMPL;
891 static HRESULT WINAPI SMTPTransport_SendDataStream(ISMTPTransport2 *iface,
892 IStream *pStream, ULONG cbSize)
894 FIXME("(%p, %d)\n", pStream, cbSize);
895 return E_NOTIMPL;
898 static HRESULT WINAPI SMTPTransport_SetWindow(ISMTPTransport2 *iface)
900 FIXME("()\n");
901 return E_NOTIMPL;
904 static HRESULT WINAPI SMTPTransport_ResetWindow(ISMTPTransport2 *iface)
906 FIXME("()\n");
907 return E_NOTIMPL;
910 static HRESULT WINAPI SMTPTransport_SendMessage2(ISMTPTransport2 *iface, LPSMTPMESSAGE2 pMessage)
912 FIXME("(%p)\n", pMessage);
913 return E_NOTIMPL;
916 static HRESULT WINAPI SMTPTransport_CommandRCPT2(ISMTPTransport2 *iface, LPSTR pszEmailTo,
917 INETADDRTYPE atDSN)
919 FIXME("(%s, %u)\n", pszEmailTo, atDSN);
920 return E_NOTIMPL;
923 static const ISMTPTransport2Vtbl SMTPTransport2Vtbl =
925 SMTPTransport_QueryInterface,
926 SMTPTransport_AddRef,
927 SMTPTransport_Release,
928 SMTPTransport_GetServerInfo,
929 SMTPTransport_GetIXPType,
930 SMTPTransport_IsState,
931 SMTPTransport_InetServerFromAccount,
932 SMTPTransport_Connect,
933 SMTPTransport_HandsOffCallback,
934 SMTPTransport_Disconnect,
935 SMTPTransport_DropConnection,
936 SMTPTransport_GetStatus,
937 SMTPTransport_InitNew,
938 SMTPTransport_SendMessage,
939 SMTPTransport_CommandMAIL,
940 SMTPTransport_CommandRCPT,
941 SMTPTransport_CommandEHLO,
942 SMTPTransport_CommandHELO,
943 SMTPTransport_CommandAUTH,
944 SMTPTransport_CommandQUIT,
945 SMTPTransport_CommandRSET,
946 SMTPTransport_CommandDATA,
947 SMTPTransport_CommandDOT,
948 SMTPTransport_SendDataStream,
949 SMTPTransport_SetWindow,
950 SMTPTransport_ResetWindow,
951 SMTPTransport_SendMessage2,
952 SMTPTransport_CommandRCPT2
955 HRESULT WINAPI CreateSMTPTransport(ISMTPTransport **ppTransport)
957 HRESULT hr;
958 SMTPTransport *This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
959 if (!This)
960 return E_OUTOFMEMORY;
962 This->InetTransport.u.vtblSMTP2 = &SMTPTransport2Vtbl;
963 This->refs = 0;
964 This->fESMTP = FALSE;
965 hr = InternetTransport_Init(&This->InetTransport);
966 if (FAILED(hr))
968 HeapFree(GetProcessHeap(), 0, This);
969 return hr;
972 *ppTransport = (ISMTPTransport *)&This->InetTransport.u.vtblSMTP2;
973 ISMTPTransport_AddRef(*ppTransport);
975 return S_OK;
979 static HRESULT WINAPI SMTPTransportCF_QueryInterface(LPCLASSFACTORY iface,
980 REFIID riid, LPVOID *ppv)
982 *ppv = NULL;
983 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IClassFactory))
985 *ppv = iface;
986 IClassFactory_AddRef(iface);
987 return S_OK;
989 return E_NOINTERFACE;
992 static ULONG WINAPI SMTPTransportCF_AddRef(LPCLASSFACTORY iface)
994 return 2; /* non-heap based object */
997 static ULONG WINAPI SMTPTransportCF_Release(LPCLASSFACTORY iface)
999 return 1; /* non-heap based object */
1002 static HRESULT WINAPI SMTPTransportCF_CreateInstance(LPCLASSFACTORY iface,
1003 LPUNKNOWN pUnk, REFIID riid, LPVOID *ppv)
1005 HRESULT hr;
1006 ISMTPTransport *pSmtpTransport;
1008 TRACE("(%p, %s, %p)\n", pUnk, debugstr_guid(riid), ppv);
1010 *ppv = NULL;
1012 if (pUnk)
1013 return CLASS_E_NOAGGREGATION;
1015 hr = CreateSMTPTransport(&pSmtpTransport);
1016 if (FAILED(hr))
1017 return hr;
1019 hr = ISMTPTransport_QueryInterface(pSmtpTransport, riid, ppv);
1020 ISMTPTransport_Release(pSmtpTransport);
1022 return hr;
1025 static HRESULT WINAPI SMTPTransportCF_LockServer(LPCLASSFACTORY iface, BOOL fLock)
1027 FIXME("(%d)\n",fLock);
1028 return S_OK;
1031 static const IClassFactoryVtbl SMTPTransportCFVtbl =
1033 SMTPTransportCF_QueryInterface,
1034 SMTPTransportCF_AddRef,
1035 SMTPTransportCF_Release,
1036 SMTPTransportCF_CreateInstance,
1037 SMTPTransportCF_LockServer
1039 static const IClassFactoryVtbl *SMTPTransportCF = &SMTPTransportCFVtbl;
1041 HRESULT SMTPTransportCF_Create(REFIID riid, LPVOID *ppv)
1043 return IClassFactory_QueryInterface((IClassFactory *)&SMTPTransportCF, riid, ppv);