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
34 #include "wine/debug.h"
36 #include "inetcomm_private.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(inetcomm
);
42 InternetTransport InetTransport
;
47 static HRESULT
SMTPTransport_ParseResponse(SMTPTransport
*This
, char *pszResponse
, SMTPRESPONSE
*pResponse
)
49 HRESULT hrServerError
;
51 TRACE("response: %s\n", debugstr_a(pszResponse
));
53 if (!isdigit(*pszResponse
))
54 return IXP_E_SMTP_RESPONSE_ERROR
;
55 pResponse
->pTransport
= (ISMTPTransport
*)&This
->InetTransport
.u
.vtblSMTP2
;
56 pResponse
->rIxpResult
.pszResponse
= pszResponse
;
57 pResponse
->rIxpResult
.dwSocketError
= 0;
58 pResponse
->rIxpResult
.uiServerError
= strtol(pszResponse
, &pszResponse
, 10);
59 if (*pszResponse
== '-')
61 pResponse
->fDone
= FALSE
;
65 pResponse
->fDone
= TRUE
;
67 switch (pResponse
->rIxpResult
.uiServerError
)
69 case 211: hrServerError
= IXP_E_SMTP_211_SYSTEM_STATUS
; break;
70 case 214: hrServerError
= IXP_E_SMTP_214_HELP_MESSAGE
; break;
71 case 220: hrServerError
= IXP_E_SMTP_220_READY
; break;
72 case 221: hrServerError
= IXP_E_SMTP_221_CLOSING
; break;
73 case 245: hrServerError
= IXP_E_SMTP_245_AUTH_SUCCESS
; break;
74 case 250: hrServerError
= IXP_E_SMTP_250_MAIL_ACTION_OKAY
; break;
75 case 251: hrServerError
= IXP_E_SMTP_251_FORWARDING_MAIL
; break;
76 case 334: hrServerError
= IXP_E_SMTP_334_AUTH_READY_RESPONSE
; break;
77 case 354: hrServerError
= IXP_E_SMTP_354_START_MAIL_INPUT
; break;
78 case 421: hrServerError
= IXP_E_SMTP_421_NOT_AVAILABLE
; break;
79 case 450: hrServerError
= IXP_E_SMTP_450_MAILBOX_BUSY
; break;
80 case 451: hrServerError
= IXP_E_SMTP_451_ERROR_PROCESSING
; break;
81 case 452: hrServerError
= IXP_E_SMTP_452_NO_SYSTEM_STORAGE
; break;
82 case 454: hrServerError
= IXP_E_SMTP_454_STARTTLS_FAILED
; break;
83 case 500: hrServerError
= IXP_E_SMTP_500_SYNTAX_ERROR
; break;
84 case 501: hrServerError
= IXP_E_SMTP_501_PARAM_SYNTAX
; break;
85 case 502: hrServerError
= IXP_E_SMTP_502_COMMAND_NOTIMPL
; break;
86 case 503: hrServerError
= IXP_E_SMTP_503_COMMAND_SEQ
; break;
87 case 504: hrServerError
= IXP_E_SMTP_504_COMMAND_PARAM_NOTIMPL
; break;
88 case 530: hrServerError
= IXP_E_SMTP_530_STARTTLS_REQUIRED
; break;
89 case 550: hrServerError
= IXP_E_SMTP_550_MAILBOX_NOT_FOUND
; break;
90 case 551: hrServerError
= IXP_E_SMTP_551_USER_NOT_LOCAL
; break;
91 case 552: hrServerError
= IXP_E_SMTP_552_STORAGE_OVERFLOW
; break;
92 case 553: hrServerError
= IXP_E_SMTP_553_MAILBOX_NAME_SYNTAX
; break;
93 case 554: hrServerError
= IXP_E_SMTP_554_TRANSACT_FAILED
; break;
95 hrServerError
= IXP_E_SMTP_RESPONSE_ERROR
;
98 pResponse
->rIxpResult
.hrResult
= hrServerError
;
99 pResponse
->rIxpResult
.hrServerError
= hrServerError
;
101 if (This
->InetTransport
.pCallback
&& This
->InetTransport
.fCommandLogging
)
103 ITransportCallback_OnCommand(This
->InetTransport
.pCallback
, CMD_RESP
,
104 pResponse
->rIxpResult
.pszResponse
, hrServerError
,
105 (IInternetTransport
*)&This
->InetTransport
.u
.vtbl
);
110 static void SMTPTransport_CallbackProcessHelloResp(IInternetTransport
*iface
, char *pBuffer
, int cbBuffer
)
112 SMTPTransport
*This
= (SMTPTransport
*)iface
;
113 SMTPRESPONSE response
= { 0 };
118 hr
= SMTPTransport_ParseResponse(This
, pBuffer
, &response
);
121 /* FIXME: handle error */
125 response
.command
= This
->fESMTP
? SMTP_EHLO
: SMTP_HELO
;
126 ISMTPCallback_OnResponse((ISMTPCallback
*)This
->InetTransport
.pCallback
, &response
);
128 if (FAILED(response
.rIxpResult
.hrServerError
))
130 ERR("server error: %s\n", debugstr_a(pBuffer
));
131 /* FIXME: handle error */
137 InternetTransport_ReadLine(&This
->InetTransport
,
138 SMTPTransport_CallbackProcessHelloResp
);
142 /* FIXME: try to authorize */
144 /* always changed to this status, even if authorization not support on server */
145 InternetTransport_ChangeStatus(&This
->InetTransport
, IXP_AUTHORIZED
);
146 InternetTransport_ChangeStatus(&This
->InetTransport
, IXP_CONNECTED
);
148 memset(&response
, 0, sizeof(response
));
149 response
.command
= SMTP_CONNECTED
;
150 response
.fDone
= TRUE
;
151 ISMTPCallback_OnResponse((ISMTPCallback
*)This
->InetTransport
.pCallback
, &response
);
154 static void SMTPTransport_CallbackRecvHelloResp(IInternetTransport
*iface
, char *pBuffer
, int cbBuffer
)
156 SMTPTransport
*This
= (SMTPTransport
*)iface
;
159 InternetTransport_ReadLine(&This
->InetTransport
, SMTPTransport_CallbackProcessHelloResp
);
162 static void SMTPTransport_CallbackSendHello(IInternetTransport
*iface
, char *pBuffer
, int cbBuffer
)
164 SMTPTransport
*This
= (SMTPTransport
*)iface
;
165 SMTPRESPONSE response
= { 0 };
167 const char *pszHello
;
169 const char szHostName
[] = "localhost"; /* FIXME */
173 hr
= SMTPTransport_ParseResponse(This
, pBuffer
, &response
);
176 /* FIXME: handle error */
180 response
.command
= SMTP_BANNER
;
181 ISMTPCallback_OnResponse((ISMTPCallback
*)This
->InetTransport
.pCallback
, &response
);
183 if (FAILED(response
.rIxpResult
.hrServerError
))
185 ERR("server error: %s\n", debugstr_a(pBuffer
));
186 /* FIXME: handle error */
190 TRACE("(%s)\n", pBuffer
);
192 This
->fESMTP
= strstr(response
.rIxpResult
.pszResponse
, "ESMTP") &&
193 This
->InetTransport
.ServerInfo
.dwFlags
& (ISF_SSLONSAMEPORT
|ISF_QUERYDSNSUPPORT
|ISF_QUERYAUTHSUPPORT
);
200 pszCommand
= HeapAlloc(GetProcessHeap(), 0, strlen(pszHello
) + strlen(szHostName
) + 2);
201 strcpy(pszCommand
, pszHello
);
202 strcat(pszCommand
, szHostName
);
203 pszCommand
[strlen(pszCommand
)+1] = '\0';
204 pszCommand
[strlen(pszCommand
)] = '\n';
206 InternetTransport_DoCommand(&This
->InetTransport
, pszCommand
,
207 SMTPTransport_CallbackRecvHelloResp
);
209 HeapFree(GetProcessHeap(), 0, pszCommand
);
212 static HRESULT WINAPI
SMTPTransport_QueryInterface(ISMTPTransport2
*iface
, REFIID riid
, void **ppv
)
214 TRACE("(%s, %p)\n", debugstr_guid(riid
), ppv
);
216 if (IsEqualIID(riid
, &IID_IUnknown
) ||
217 IsEqualIID(riid
, &IID_IInternetTransport
) ||
218 IsEqualIID(riid
, &IID_ISMTPTransport
) ||
219 IsEqualIID(riid
, &IID_ISMTPTransport2
))
222 IUnknown_AddRef(iface
);
226 FIXME("no interface for %s\n", debugstr_guid(riid
));
227 return E_NOINTERFACE
;
230 static ULONG WINAPI
SMTPTransport_AddRef(ISMTPTransport2
*iface
)
232 SMTPTransport
*This
= (SMTPTransport
*)iface
;
233 return InterlockedIncrement((LONG
*)&This
->refs
);
236 static ULONG WINAPI
SMTPTransport_Release(ISMTPTransport2
*iface
)
238 SMTPTransport
*This
= (SMTPTransport
*)iface
;
239 ULONG refs
= InterlockedDecrement((LONG
*)&This
->refs
);
242 TRACE("destroying %p\n", This
);
243 if (This
->InetTransport
.Status
!= IXP_DISCONNECTED
)
244 InternetTransport_DropConnection(&This
->InetTransport
);
246 if (This
->InetTransport
.pCallback
) ITransportCallback_Release(This
->InetTransport
.pCallback
);
247 HeapFree(GetProcessHeap(), 0, This
);
252 static HRESULT WINAPI
SMTPTransport_GetServerInfo(ISMTPTransport2
*iface
,
253 LPINETSERVER pInetServer
)
255 SMTPTransport
*This
= (SMTPTransport
*)iface
;
257 TRACE("(%p)\n", pInetServer
);
258 return InternetTransport_GetServerInfo(&This
->InetTransport
, pInetServer
);
261 static IXPTYPE WINAPI
SMTPTransport_GetIXPType(ISMTPTransport2
*iface
)
267 static HRESULT WINAPI
SMTPTransport_IsState(ISMTPTransport2
*iface
,
270 FIXME("(%d): stub\n", isstate
);
274 static HRESULT WINAPI
SMTPTransport_InetServerFromAccount(
275 ISMTPTransport2
*iface
, IImnAccount
*pAccount
, LPINETSERVER pInetServer
)
277 SMTPTransport
*This
= (SMTPTransport
*)iface
;
279 TRACE("(%p, %p)\n", pAccount
, pInetServer
);
280 return InternetTransport_InetServerFromAccount(&This
->InetTransport
, pAccount
, pInetServer
);
283 static HRESULT WINAPI
SMTPTransport_Connect(ISMTPTransport2
*iface
,
284 LPINETSERVER pInetServer
, boolean fAuthenticate
, boolean fCommandLogging
)
286 SMTPTransport
*This
= (SMTPTransport
*)iface
;
289 TRACE("(%p, %s, %s)\n", pInetServer
, fAuthenticate
? "TRUE" : "FALSE", fCommandLogging
? "TRUE" : "FALSE");
291 hr
= InternetTransport_Connect(&This
->InetTransport
, pInetServer
, fAuthenticate
, fCommandLogging
);
293 /* this starts the state machine, which continues in SMTPTransport_CallbackSendHELO */
294 return InternetTransport_ReadLine(&This
->InetTransport
, SMTPTransport_CallbackSendHello
);
297 static HRESULT WINAPI
SMTPTransport_HandsOffCallback(ISMTPTransport2
*iface
)
299 SMTPTransport
*This
= (SMTPTransport
*)iface
;
302 return InternetTransport_HandsOffCallback(&This
->InetTransport
);
305 static HRESULT WINAPI
SMTPTransport_Disconnect(ISMTPTransport2
*iface
)
311 static HRESULT WINAPI
SMTPTransport_DropConnection(ISMTPTransport2
*iface
)
313 SMTPTransport
*This
= (SMTPTransport
*)iface
;
316 return InternetTransport_DropConnection(&This
->InetTransport
);
319 static HRESULT WINAPI
SMTPTransport_GetStatus(ISMTPTransport2
*iface
,
320 IXPSTATUS
*pCurrentStatus
)
322 SMTPTransport
*This
= (SMTPTransport
*)iface
;
325 return InternetTransport_GetStatus(&This
->InetTransport
, pCurrentStatus
);
328 static HRESULT WINAPI
SMTPTransport_InitNew(ISMTPTransport2
*iface
,
329 LPSTR pszLogFilePath
, ISMTPCallback
*pCallback
)
331 SMTPTransport
*This
= (SMTPTransport
*)iface
;
333 TRACE("(%s, %p)\n", debugstr_a(pszLogFilePath
), pCallback
);
339 FIXME("not using log file of %s, use Wine debug logging instead\n",
340 debugstr_a(pszLogFilePath
));
342 ISMTPCallback_AddRef(pCallback
);
343 This
->InetTransport
.pCallback
= (ITransportCallback
*)pCallback
;
344 This
->InetTransport
.fInitialised
= TRUE
;
349 static HRESULT WINAPI
SMTPTransport_SendMessage(ISMTPTransport2
*iface
,
350 LPSMTPMESSAGE pMessage
)
352 FIXME("(%p)\n", pMessage
);
356 static HRESULT WINAPI
SMTPTransport_CommandMAIL(ISMTPTransport2
*iface
, LPSTR pszEmailFrom
)
358 FIXME("(%s)\n", pszEmailFrom
);
362 static HRESULT WINAPI
SMTPTransport_CommandRCPT(ISMTPTransport2
*iface
, LPSTR pszEmailTo
)
364 FIXME("(%s)\n", pszEmailTo
);
368 static HRESULT WINAPI
SMTPTransport_CommandEHLO(ISMTPTransport2
*iface
)
374 static HRESULT WINAPI
SMTPTransport_CommandHELO(ISMTPTransport2
*iface
)
380 static HRESULT WINAPI
SMTPTransport_CommandAUTH(ISMTPTransport2
*iface
,
383 FIXME("(%s)\n", pszAuthType
);
387 static HRESULT WINAPI
SMTPTransport_CommandQUIT(ISMTPTransport2
*iface
)
393 static HRESULT WINAPI
SMTPTransport_CommandRSET(ISMTPTransport2
*iface
)
399 static HRESULT WINAPI
SMTPTransport_CommandDATA(ISMTPTransport2
*iface
)
405 static HRESULT WINAPI
SMTPTransport_CommandDOT(ISMTPTransport2
*iface
)
411 static HRESULT WINAPI
SMTPTransport_SendDataStream(ISMTPTransport2
*iface
,
412 IStream
*pStream
, ULONG cbSize
)
414 FIXME("(%p, %d)\n", pStream
, cbSize
);
418 static HRESULT WINAPI
SMTPTransport_SetWindow(ISMTPTransport2
*iface
)
424 static HRESULT WINAPI
SMTPTransport_ResetWindow(ISMTPTransport2
*iface
)
430 static HRESULT WINAPI
SMTPTransport_SendMessage2(ISMTPTransport2
*iface
, LPSMTPMESSAGE2 pMessage
)
432 FIXME("(%p)\n", pMessage
);
436 static HRESULT WINAPI
SMTPTransport_CommandRCPT2(ISMTPTransport2
*iface
, LPSTR pszEmailTo
,
439 FIXME("(%s, %u)\n", pszEmailTo
, atDSN
);
443 static const ISMTPTransport2Vtbl SMTPTransport2Vtbl
=
445 SMTPTransport_QueryInterface
,
446 SMTPTransport_AddRef
,
447 SMTPTransport_Release
,
448 SMTPTransport_GetServerInfo
,
449 SMTPTransport_GetIXPType
,
450 SMTPTransport_IsState
,
451 SMTPTransport_InetServerFromAccount
,
452 SMTPTransport_Connect
,
453 SMTPTransport_HandsOffCallback
,
454 SMTPTransport_Disconnect
,
455 SMTPTransport_DropConnection
,
456 SMTPTransport_GetStatus
,
457 SMTPTransport_InitNew
,
458 SMTPTransport_SendMessage
,
459 SMTPTransport_CommandMAIL
,
460 SMTPTransport_CommandRCPT
,
461 SMTPTransport_CommandEHLO
,
462 SMTPTransport_CommandHELO
,
463 SMTPTransport_CommandAUTH
,
464 SMTPTransport_CommandQUIT
,
465 SMTPTransport_CommandRSET
,
466 SMTPTransport_CommandDATA
,
467 SMTPTransport_CommandDOT
,
468 SMTPTransport_SendDataStream
,
469 SMTPTransport_SetWindow
,
470 SMTPTransport_ResetWindow
,
471 SMTPTransport_SendMessage2
,
472 SMTPTransport_CommandRCPT2
475 HRESULT WINAPI
CreateSMTPTransport(ISMTPTransport
**ppTransport
)
478 SMTPTransport
*This
= HeapAlloc(GetProcessHeap(), 0, sizeof(*This
));
480 return E_OUTOFMEMORY
;
482 This
->InetTransport
.u
.vtblSMTP2
= &SMTPTransport2Vtbl
;
484 This
->fESMTP
= FALSE
;
485 hr
= InternetTransport_Init(&This
->InetTransport
);
488 HeapFree(GetProcessHeap(), 0, This
);
492 *ppTransport
= (ISMTPTransport
*)&This
->InetTransport
.u
.vtblSMTP2
;
493 ISMTPTransport_AddRef(*ppTransport
);
499 static HRESULT WINAPI
SMTPTransportCF_QueryInterface(LPCLASSFACTORY iface
,
500 REFIID riid
, LPVOID
*ppv
)
503 if (IsEqualIID(riid
, &IID_IUnknown
) || IsEqualIID(riid
, &IID_IClassFactory
))
506 IUnknown_AddRef(iface
);
509 return E_NOINTERFACE
;
512 static ULONG WINAPI
SMTPTransportCF_AddRef(LPCLASSFACTORY iface
)
514 return 2; /* non-heap based object */
517 static ULONG WINAPI
SMTPTransportCF_Release(LPCLASSFACTORY iface
)
519 return 1; /* non-heap based object */
522 static HRESULT WINAPI
SMTPTransportCF_CreateInstance(LPCLASSFACTORY iface
,
523 LPUNKNOWN pUnk
, REFIID riid
, LPVOID
*ppv
)
526 ISMTPTransport
*pSmtpTransport
;
528 TRACE("(%p, %s, %p)\n", pUnk
, debugstr_guid(riid
), ppv
);
533 return CLASS_E_NOAGGREGATION
;
535 hr
= CreateSMTPTransport(&pSmtpTransport
);
539 hr
= ISMTPTransport_QueryInterface(pSmtpTransport
, riid
, ppv
);
540 ISMTPTransport_Release(pSmtpTransport
);
545 static HRESULT WINAPI
SMTPTransportCF_LockServer(LPCLASSFACTORY iface
, BOOL fLock
)
547 FIXME("(%d)\n",fLock
);
551 static const IClassFactoryVtbl SMTPTransportCFVtbl
=
553 SMTPTransportCF_QueryInterface
,
554 SMTPTransportCF_AddRef
,
555 SMTPTransportCF_Release
,
556 SMTPTransportCF_CreateInstance
,
557 SMTPTransportCF_LockServer
559 static const IClassFactoryVtbl
*SMTPTransportCF
= &SMTPTransportCFVtbl
;
561 HRESULT
SMTPTransportCF_Create(REFIID riid
, LPVOID
*ppv
)
563 return IClassFactory_QueryInterface((IClassFactory
*)&SMTPTransportCF
, riid
, ppv
);