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