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