1 /* 2 * POP3 Transport 3 * 4 * Copyright 2008 Hans Leidekker for CodeWeavers 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 19 */ 20 21 #define COBJMACROS 22 #define NONAMELESSUNION 23 24 #include <stdarg.h> 25 #include <stdio.h> 26 27 #include "windef.h" 28 #include "winbase.h" 29 #include "winnt.h" 30 #include "winuser.h" 31 #include "objbase.h" 32 #include "mimeole.h" 33 #include "wine/debug.h" 34 35 #include "inetcomm_private.h" 36 37 WINE_DEFAULT_DEBUG_CHANNEL(inetcomm); 38 39 enum parse_state 40 { 41 STATE_NONE, 42 STATE_OK, 43 STATE_MULTILINE, 44 STATE_DONE 45 }; 46 47 typedef struct 48 { 49 InternetTransport InetTransport; 50 ULONG refs; 51 POP3COMMAND command; 52 POP3CMDTYPE type; 53 char *response; 54 char *ptr; 55 enum parse_state state; 56 BOOL valid_info; 57 DWORD msgid; 58 DWORD preview_lines; 59 } POP3Transport; 60 61 static HRESULT parse_response(POP3Transport *This) 62 { 63 switch (This->state) 64 { 65 case STATE_NONE: 66 if (strlen(This->response) < 3) 67 { 68 WARN("parse error\n"); 69 This->state = STATE_DONE; 70 return S_FALSE; 71 } 72 if (!memcmp(This->response, "+OK", 3)) 73 { 74 This->ptr = This->response + 3; 75 This->state = STATE_OK; 76 return S_OK; 77 } 78 This->state = STATE_DONE; 79 return S_FALSE; 80 81 default: return S_OK; 82 } 83 } 84 85 static HRESULT parse_uidl_response(POP3Transport *This, POP3UIDL *uidl) 86 { 87 char *p; 88 89 uidl->dwPopId = 0; 90 uidl->pszUidl = NULL; 91 switch (This->state) 92 { 93 case STATE_OK: 94 if (This->type == POP3CMD_GET_POPID) 95 { 96 if ((p = strchr(This->ptr, ' '))) 97 { 98 while (*p == ' ') p++; 99 sscanf(p, "%u", &uidl->dwPopId); 100 if ((p = strchr(p, ' '))) 101 { 102 while (*p == ' ') p++; 103 uidl->pszUidl = p; 104 This->valid_info = TRUE; 105 } 106 } 107 This->state = STATE_DONE; 108 return S_OK; 109 } 110 This->state = STATE_MULTILINE; 111 return S_OK; 112 113 case STATE_MULTILINE: 114 if (This->response[0] == '.' && !This->response[1]) 115 { 116 This->valid_info = FALSE; 117 This->state = STATE_DONE; 118 return S_OK; 119 } 120 sscanf(This->response, "%u", &uidl->dwPopId); 121 if ((p = strchr(This->response, ' '))) 122 { 123 while (*p == ' ') p++; 124 uidl->pszUidl = p; 125 This->valid_info = TRUE; 126 return S_OK; 127 } 128 129 default: 130 WARN("parse error\n"); 131 This->state = STATE_DONE; 132 return S_FALSE; 133 } 134 } 135 136 static HRESULT parse_stat_response(POP3Transport *This, POP3STAT *stat) 137 { 138 char *p; 139 140 stat->cMessages = 0; 141 stat->cbMessages = 0; 142 switch (This->state) 143 { 144 case STATE_OK: 145 if ((p = strchr(This->ptr, ' '))) 146 { 147 while (*p == ' ') p++; 148 sscanf(p, "%u %u", &stat->cMessages, &stat->cbMessages); 149 This->valid_info = TRUE; 150 This->state = STATE_DONE; 151 return S_OK; 152 } 153 154 default: 155 WARN("parse error\n"); 156 This->state = STATE_DONE; 157 return S_FALSE; 158 } 159 } 160 161 static HRESULT parse_list_response(POP3Transport *This, POP3LIST *list) 162 { 163 char *p; 164 165 list->dwPopId = 0; 166 list->cbSize = 0; 167 switch (This->state) 168 { 169 case STATE_OK: 170 if (This->type == POP3CMD_GET_POPID) 171 { 172 if ((p = strchr(This->ptr, ' '))) 173 { 174 while (*p == ' ') p++; 175 sscanf(p, "%u %u", &list->dwPopId, &list->cbSize); 176 This->valid_info = TRUE; 177 } 178 This->state = STATE_DONE; 179 return S_OK; 180 } 181 This->state = STATE_MULTILINE; 182 return S_OK; 183 184 case STATE_MULTILINE: 185 if (This->response[0] == '.' && !This->response[1]) 186 { 187 This->valid_info = FALSE; 188 This->state = STATE_DONE; 189 return S_OK; 190 } 191 sscanf(This->response, "%u", &list->dwPopId); 192 if ((p = strchr(This->response, ' '))) 193 { 194 while (*p == ' ') p++; 195 sscanf(p, "%u", &list->cbSize); 196 This->valid_info = TRUE; 197 return S_OK; 198 } 199 200 default: 201 WARN("parse error\n"); 202 This->state = STATE_DONE; 203 return S_FALSE; 204 } 205 } 206 207 static HRESULT parse_dele_response(POP3Transport *This, DWORD *dwPopId) 208 { 209 switch (This->state) 210 { 211 case STATE_OK: 212 *dwPopId = 0; /* FIXME */ 213 This->state = STATE_DONE; 214 return S_OK; 215 216 default: 217 WARN("parse error\n"); 218 This->state = STATE_DONE; 219 return S_FALSE; 220 } 221 } 222 223 static HRESULT parse_retr_response(POP3Transport *This, POP3RETR *retr) 224 { 225 switch (This->state) 226 { 227 case STATE_OK: 228 retr->fHeader = FALSE; 229 retr->fBody = FALSE; 230 retr->dwPopId = This->msgid; 231 retr->cbSoFar = 0; 232 retr->pszLines = This->response; 233 retr->cbLines = 0; 234 235 This->state = STATE_MULTILINE; 236 This->valid_info = FALSE; 237 return S_OK; 238 239 case STATE_MULTILINE: 240 { 241 int len; 242 243 if (This->response[0] == '.' && !This->response[1]) 244 { 245 retr->cbLines = retr->cbSoFar; 246 This->state = STATE_DONE; 247 return S_OK; 248 } 249 retr->fHeader = TRUE; 250 if (!This->response[0]) retr->fBody = TRUE; 251 252 len = strlen(This->response); 253 retr->cbSoFar += len; 254 retr->pszLines = This->response; 255 retr->cbLines = len; 256 257 This->valid_info = TRUE; 258 return S_OK; 259 } 260 261 default: 262 WARN("parse error\n"); 263 This->state = STATE_DONE; 264 return S_FALSE; 265 } 266 } 267 268 static HRESULT parse_top_response(POP3Transport *This, POP3TOP *top) 269 { 270 switch (This->state) 271 { 272 case STATE_OK: 273 top->fHeader = FALSE; 274 top->fBody = FALSE; 275 top->dwPopId = This->msgid; 276 top->cPreviewLines = This->preview_lines; 277 top->cbSoFar = 0; 278 top->pszLines = This->response; 279 top->cbLines = 0; 280 281 This->state = STATE_MULTILINE; 282 This->valid_info = FALSE; 283 return S_OK; 284 285 case STATE_MULTILINE: 286 { 287 int len; 288 289 if (This->response[0] == '.' && !This->response[1]) 290 { 291 top->cbLines = top->cbSoFar; 292 This->state = STATE_DONE; 293 return S_OK; 294 } 295 top->fHeader = TRUE; 296 if (!This->response[0]) top->fBody = TRUE; 297 298 len = strlen(This->response); 299 top->cbSoFar += len; 300 top->pszLines = This->response; 301 top->cbLines = len; 302 303 This->valid_info = TRUE; 304 return S_OK; 305 } 306 307 default: 308 WARN("parse error\n"); 309 This->state = STATE_DONE; 310 return S_FALSE; 311 } 312 } 313 314 static void init_parser(POP3Transport *This, POP3COMMAND command, POP3CMDTYPE type) 315 { 316 This->state = STATE_NONE; 317 This->command = command; 318 This->type = type; 319 } 320 321 static HRESULT POP3Transport_ParseResponse(POP3Transport *This, char *pszResponse, POP3RESPONSE *pResponse) 322 { 323 HRESULT hr; 324 325 TRACE("response: %s\n", debugstr_a(pszResponse)); 326 327 This->response = pszResponse; 328 This->valid_info = FALSE; 329 TRACE("state %u\n", This->state); 330 331 if (SUCCEEDED((hr = parse_response(This)))) 332 { 333 switch (This->command) 334 { 335 case POP3_UIDL: hr = parse_uidl_response(This, &pResponse->u.rUidlInfo); break; 336 case POP3_STAT: hr = parse_stat_response(This, &pResponse->u.rStatInfo); break; 337 case POP3_LIST: hr = parse_list_response(This, &pResponse->u.rListInfo); break; 338 case POP3_DELE: hr = parse_dele_response(This, &pResponse->u.dwPopId); break; 339 case POP3_RETR: hr = parse_retr_response(This, &pResponse->u.rRetrInfo); break; 340 case POP3_TOP: hr = parse_top_response(This, &pResponse->u.rTopInfo); break; 341 default: 342 This->state = STATE_DONE; 343 break; 344 } 345 } 346 pResponse->command = This->command; 347 pResponse->fDone = (This->state == STATE_DONE); 348 pResponse->fValidInfo = This->valid_info; 349 pResponse->rIxpResult.hrResult = hr; 350 pResponse->rIxpResult.pszResponse = pszResponse; 351 pResponse->rIxpResult.uiServerError = 0; 352 pResponse->rIxpResult.hrServerError = pResponse->rIxpResult.hrResult; 353 pResponse->rIxpResult.dwSocketError = WSAGetLastError(); 354 pResponse->rIxpResult.pszProblem = NULL; 355 pResponse->pTransport = (IPOP3Transport *)&This->InetTransport.u.vtblPOP3; 356 357 if (This->InetTransport.pCallback && This->InetTransport.fCommandLogging) 358 { 359 ITransportCallback_OnCommand(This->InetTransport.pCallback, CMD_RESP, 360 pResponse->rIxpResult.pszResponse, pResponse->rIxpResult.hrServerError, 361 (IInternetTransport *)&This->InetTransport.u.vtbl); 362 } 363 return S_OK; 364 } 365 366 static void POP3Transport_CallbackProcessDELEResp(IInternetTransport *iface, char *pBuffer, int cbBuffer) 367 { 368 POP3Transport *This = (POP3Transport *)iface; 369 POP3RESPONSE response; 370 HRESULT hr; 371 372 TRACE("\n"); 373 374 hr = POP3Transport_ParseResponse(This, pBuffer, &response); 375 if (FAILED(hr)) 376 { 377 /* FIXME: handle error */ 378 return; 379 } 380 381 IPOP3Callback_OnResponse((IPOP3Callback *)This->InetTransport.pCallback, &response); 382 } 383 384 static void POP3Transport_CallbackRecvDELEResp(IInternetTransport *iface, char *pBuffer, int cbBuffer) 385 { 386 POP3Transport *This = (POP3Transport *)iface; 387 388 TRACE("\n"); 389 InternetTransport_ReadLine(&This->InetTransport, POP3Transport_CallbackProcessDELEResp); 390 } 391 392 static void POP3Transport_CallbackProcessNOOPResp(IInternetTransport *iface, char *pBuffer, int cbBuffer) 393 { 394 POP3Transport *This = (POP3Transport *)iface; 395 POP3RESPONSE response; 396 HRESULT hr; 397 398 TRACE("\n"); 399 400 hr = POP3Transport_ParseResponse(This, pBuffer, &response); 401 if (FAILED(hr)) 402 { 403 /* FIXME: handle error */ 404 return; 405 } 406 407 IPOP3Callback_OnResponse((IPOP3Callback *)This->InetTransport.pCallback, &response); 408 } 409 410 static void POP3Transport_CallbackRecvNOOPResp(IInternetTransport *iface, char *pBuffer, int cbBuffer) 411 { 412 POP3Transport *This = (POP3Transport *)iface; 413 414 TRACE("\n"); 415 InternetTransport_ReadLine(&This->InetTransport, POP3Transport_CallbackProcessNOOPResp); 416 } 417 418 static void POP3Transport_CallbackProcessRSETResp(IInternetTransport *iface, char *pBuffer, int cbBuffer) 419 { 420 POP3Transport *This = (POP3Transport *)iface; 421 POP3RESPONSE response; 422 HRESULT hr; 423 424 TRACE("\n"); 425 426 hr = POP3Transport_ParseResponse(This, pBuffer, &response); 427 if (FAILED(hr)) 428 { 429 /* FIXME: handle error */ 430 return; 431 } 432 433 IPOP3Callback_OnResponse((IPOP3Callback *)This->InetTransport.pCallback, &response); 434 } 435 436 static void POP3Transport_CallbackRecvRSETResp(IInternetTransport *iface, char *pBuffer, int cbBuffer) 437 { 438 POP3Transport *This = (POP3Transport *)iface; 439 440 TRACE("\n"); 441 InternetTransport_ReadLine(&This->InetTransport, POP3Transport_CallbackProcessRSETResp); 442 } 443 444 static void POP3Transport_CallbackProcessRETRResp(IInternetTransport *iface, char *pBuffer, int cbBuffer) 445 { 446 POP3Transport *This = (POP3Transport *)iface; 447 POP3RESPONSE response; 448 HRESULT hr; 449 450 TRACE("\n"); 451 452 hr = POP3Transport_ParseResponse(This, pBuffer, &response); 453 if (FAILED(hr)) 454 { 455 /* FIXME: handle error */ 456 return; 457 } 458 459 IPOP3Callback_OnResponse((IPOP3Callback *)This->InetTransport.pCallback, &response); 460 461 if (!response.fDone) 462 { 463 InternetTransport_ReadLine(&This->InetTransport, POP3Transport_CallbackProcessRETRResp); 464 return; 465 } 466 467 IPOP3Callback_OnResponse((IPOP3Callback *)This->InetTransport.pCallback, &response); 468 } 469 470 static void POP3Transport_CallbackRecvRETRResp(IInternetTransport *iface, char *pBuffer, int cbBuffer) 471 { 472 POP3Transport *This = (POP3Transport *)iface; 473 474 TRACE("\n"); 475 InternetTransport_ReadLine(&This->InetTransport, POP3Transport_CallbackProcessRETRResp); 476 } 477 478 static void POP3Transport_CallbackProcessTOPResp(IInternetTransport *iface, char *pBuffer, int cbBuffer) 479 { 480 POP3Transport *This = (POP3Transport *)iface; 481 POP3RESPONSE response; 482 HRESULT hr; 483 484 TRACE("\n"); 485 486 hr = POP3Transport_ParseResponse(This, pBuffer, &response); 487 if (FAILED(hr)) 488 { 489 /* FIXME: handle error */ 490 return; 491 } 492 493 IPOP3Callback_OnResponse((IPOP3Callback *)This->InetTransport.pCallback, &response); 494 495 if (!response.fDone) 496 { 497 InternetTransport_ReadLine(&This->InetTransport, POP3Transport_CallbackProcessTOPResp); 498 return; 499 } 500 501 IPOP3Callback_OnResponse((IPOP3Callback *)This->InetTransport.pCallback, &response); 502 } 503 504 static void POP3Transport_CallbackRecvTOPResp(IInternetTransport *iface, char *pBuffer, int cbBuffer) 505 { 506 POP3Transport *This = (POP3Transport *)iface; 507 508 TRACE("\n"); 509 InternetTransport_ReadLine(&This->InetTransport, POP3Transport_CallbackProcessTOPResp); 510 } 511 512 static void POP3Transport_CallbackProcessLISTResp(IInternetTransport *iface, char *pBuffer, int cbBuffer) 513 { 514 POP3Transport *This = (POP3Transport *)iface; 515 POP3RESPONSE response; 516 HRESULT hr; 517 518 TRACE("\n"); 519 520 hr = POP3Transport_ParseResponse(This, pBuffer, &response); 521 if (FAILED(hr)) 522 { 523 /* FIXME: handle error */ 524 return; 525 } 526 527 IPOP3Callback_OnResponse((IPOP3Callback *)This->InetTransport.pCallback, &response); 528 529 if (!response.fDone) 530 { 531 InternetTransport_ReadLine(&This->InetTransport, POP3Transport_CallbackProcessLISTResp); 532 return; 533 } 534 535 IPOP3Callback_OnResponse((IPOP3Callback *)This->InetTransport.pCallback, &response); 536 } 537 538 static void POP3Transport_CallbackRecvLISTResp(IInternetTransport *iface, char *pBuffer, int cbBuffer) 539 { 540 POP3Transport *This = (POP3Transport *)iface; 541 542 TRACE("\n"); 543 InternetTransport_ReadLine(&This->InetTransport, POP3Transport_CallbackProcessLISTResp); 544 } 545 546 static void POP3Transport_CallbackProcessUIDLResp(IInternetTransport *iface, char *pBuffer, int cbBuffer) 547 { 548 POP3Transport *This = (POP3Transport *)iface; 549 POP3RESPONSE response; 550 HRESULT hr; 551 552 TRACE("\n"); 553 554 hr = POP3Transport_ParseResponse(This, pBuffer, &response); 555 if (FAILED(hr)) 556 { 557 /* FIXME: handle error */ 558 return; 559 } 560 561 IPOP3Callback_OnResponse((IPOP3Callback *)This->InetTransport.pCallback, &response); 562 563 if (!response.fDone) 564 { 565 InternetTransport_ReadLine(&This->InetTransport, POP3Transport_CallbackProcessUIDLResp); 566 return; 567 } 568 569 IPOP3Callback_OnResponse((IPOP3Callback *)This->InetTransport.pCallback, &response); 570 } 571 572 static void POP3Transport_CallbackRecvUIDLResp(IInternetTransport *iface, char *pBuffer, int cbBuffer) 573 { 574 POP3Transport *This = (POP3Transport *)iface; 575 576 TRACE("\n"); 577 InternetTransport_ReadLine(&This->InetTransport, POP3Transport_CallbackProcessUIDLResp); 578 } 579 580 static void POP3Transport_CallbackProcessSTATResp(IInternetTransport *iface, char *pBuffer, int cbBuffer) 581 { 582 POP3Transport *This = (POP3Transport *)iface; 583 POP3RESPONSE response; 584 HRESULT hr; 585 586 TRACE("\n"); 587 588 hr = POP3Transport_ParseResponse(This, pBuffer, &response); 589 if (FAILED(hr)) 590 { 591 /* FIXME: handle error */ 592 return; 593 } 594 595 IPOP3Callback_OnResponse((IPOP3Callback *)This->InetTransport.pCallback, &response); 596 } 597 598 static void POP3Transport_CallbackRecvSTATResp(IInternetTransport *iface, char *pBuffer, int cbBuffer) 599 { 600 POP3Transport *This = (POP3Transport *)iface; 601 602 TRACE("\n"); 603 InternetTransport_ReadLine(&This->InetTransport, POP3Transport_CallbackProcessSTATResp); 604 } 605 606 static void POP3Transport_CallbackProcessPASSResp(IInternetTransport *iface, char *pBuffer, int cbBuffer) 607 { 608 POP3Transport *This = (POP3Transport *)iface; 609 POP3RESPONSE response; 610 HRESULT hr; 611 612 TRACE("\n"); 613 614 hr = POP3Transport_ParseResponse(This, pBuffer, &response); 615 if (FAILED(hr)) 616 { 617 /* FIXME: handle error */ 618 return; 619 } 620 621 InternetTransport_ChangeStatus(&This->InetTransport, IXP_AUTHORIZED); 622 InternetTransport_ChangeStatus(&This->InetTransport, IXP_CONNECTED); 623 624 IPOP3Callback_OnResponse((IPOP3Callback *)This->InetTransport.pCallback, &response); 625 } 626 627 static void POP3Transport_CallbackRecvPASSResp(IInternetTransport *iface, char *pBuffer, int cbBuffer) 628 { 629 POP3Transport *This = (POP3Transport *)iface; 630 631 TRACE("\n"); 632 InternetTransport_ReadLine(&This->InetTransport, POP3Transport_CallbackProcessPASSResp); 633 } 634 635 static void POP3Transport_CallbackProcessUSERResp(IInternetTransport *iface, char *pBuffer, int cbBuffer) 636 { 637 static char pass[] = "PASS "; 638 POP3Transport *This = (POP3Transport *)iface; 639 POP3RESPONSE response; 640 char *command; 641 int len; 642 HRESULT hr; 643 644 TRACE("\n"); 645 646 hr = POP3Transport_ParseResponse(This, pBuffer, &response); 647 if (FAILED(hr)) 648 { 649 /* FIXME: handle error */ 650 return; 651 } 652 653 IPOP3Callback_OnResponse((IPOP3Callback *)This->InetTransport.pCallback, &response); 654 655 len = sizeof(pass) + strlen(This->InetTransport.ServerInfo.szPassword) + 2; /* "\r\n" */ 656 command = HeapAlloc(GetProcessHeap(), 0, len); 657 658 strcpy(command, pass); 659 strcat(command, This->InetTransport.ServerInfo.szPassword); 660 strcat(command, "\r\n"); 661 662 init_parser(This, POP3_PASS, POP3_NONE); 663 664 InternetTransport_DoCommand(&This->InetTransport, command, POP3Transport_CallbackRecvPASSResp); 665 HeapFree(GetProcessHeap(), 0, command); 666 } 667 668 static void POP3Transport_CallbackRecvUSERResp(IInternetTransport *iface, char *pBuffer, int cbBuffer) 669 { 670 POP3Transport *This = (POP3Transport *)iface; 671 672 TRACE("\n"); 673 InternetTransport_ReadLine(&This->InetTransport, POP3Transport_CallbackProcessUSERResp); 674 } 675 676 static void POP3Transport_CallbackSendUSERCmd(IInternetTransport *iface, char *pBuffer, int cbBuffer) 677 { 678 static char user[] = "USER "; 679 POP3Transport *This = (POP3Transport *)iface; 680 char *command; 681 int len; 682 683 TRACE("\n"); 684 685 len = sizeof(user) + strlen(This->InetTransport.ServerInfo.szUserName) + 2; /* "\r\n" */ 686 command = HeapAlloc(GetProcessHeap(), 0, len); 687 688 strcpy(command, user); 689 strcat(command, This->InetTransport.ServerInfo.szUserName); 690 strcat(command, "\r\n"); 691 InternetTransport_DoCommand(&This->InetTransport, command, POP3Transport_CallbackRecvUSERResp); 692 693 HeapFree(GetProcessHeap(), 0, command); 694 } 695 696 static void POP3Transport_CallbackProcessQUITResponse(IInternetTransport *iface, char *pBuffer, int cbBuffer) 697 { 698 POP3Transport *This = (POP3Transport *)iface; 699 POP3RESPONSE response; 700 HRESULT hr; 701 702 TRACE("%s\n", debugstr_an(pBuffer, cbBuffer)); 703 704 hr = POP3Transport_ParseResponse(This, pBuffer, &response); 705 if (FAILED(hr)) 706 { 707 /* FIXME: handle error */ 708 return; 709 } 710 711 IPOP3Callback_OnResponse((IPOP3Callback *)This->InetTransport.pCallback, &response); 712 InternetTransport_DropConnection(&This->InetTransport); 713 } 714 715 static void POP3Transport_CallbackRecvQUITResp(IInternetTransport *iface, char *pBuffer, int cbBuffer) 716 { 717 POP3Transport *This = (POP3Transport *)iface; 718 719 TRACE("\n"); 720 InternetTransport_ReadLine(&This->InetTransport, POP3Transport_CallbackProcessQUITResponse); 721 } 722 723 static HRESULT WINAPI POP3Transport_QueryInterface(IPOP3Transport *iface, REFIID riid, void **ppv) 724 { 725 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv); 726 727 if (IsEqualIID(riid, &IID_IUnknown) || 728 IsEqualIID(riid, &IID_IInternetTransport) || 729 IsEqualIID(riid, &IID_IPOP3Transport)) 730 { 731 *ppv = iface; 732 IUnknown_AddRef(iface); 733 return S_OK; 734 } 735 *ppv = NULL; 736 FIXME("no interface for %s\n", debugstr_guid(riid)); 737 return E_NOINTERFACE; 738 } 739 740 static ULONG WINAPI POP3Transport_AddRef(IPOP3Transport *iface) 741 { 742 POP3Transport *This = (POP3Transport *)iface; 743 return InterlockedIncrement((LONG *)&This->refs); 744 } 745 746 static ULONG WINAPI POP3Transport_Release(IPOP3Transport *iface) 747 { 748 POP3Transport *This = (POP3Transport *)iface; 749 ULONG refs = InterlockedDecrement((LONG *)&This->refs); 750 if (!refs) 751 { 752 TRACE("destroying %p\n", This); 753 if (This->InetTransport.Status != IXP_DISCONNECTED) 754 InternetTransport_DropConnection(&This->InetTransport); 755 if (This->InetTransport.pCallback) ITransportCallback_Release(This->InetTransport.pCallback); 756 HeapFree(GetProcessHeap(), 0, This); 757 } 758 return refs; 759 } 760 761 static HRESULT WINAPI POP3Transport_GetServerInfo(IPOP3Transport *iface, 762 LPINETSERVER pInetServer) 763 { 764 POP3Transport *This = (POP3Transport *)iface; 765 766 TRACE("(%p)\n", pInetServer); 767 return InternetTransport_GetServerInfo(&This->InetTransport, pInetServer); 768 } 769 770 static IXPTYPE WINAPI POP3Transport_GetIXPType(IPOP3Transport *iface) 771 { 772 TRACE("()\n"); 773 return IXP_POP3; 774 } 775 776 static HRESULT WINAPI POP3Transport_IsState(IPOP3Transport *iface, IXPISSTATE isstate) 777 { 778 FIXME("(%u)\n", isstate); 779 return E_NOTIMPL; 780 } 781 782 static HRESULT WINAPI POP3Transport_InetServerFromAccount( 783 IPOP3Transport *iface, IImnAccount *pAccount, LPINETSERVER pInetServer) 784 { 785 POP3Transport *This = (POP3Transport *)iface; 786 787 TRACE("(%p, %p)\n", pAccount, pInetServer); 788 return InternetTransport_InetServerFromAccount(&This->InetTransport, pAccount, pInetServer); 789 } 790 791 static HRESULT WINAPI POP3Transport_Connect(IPOP3Transport *iface, 792 LPINETSERVER pInetServer, boolean fAuthenticate, boolean fCommandLogging) 793 { 794 POP3Transport *This = (POP3Transport *)iface; 795 HRESULT hr; 796 797 TRACE("(%p, %s, %s)\n", pInetServer, fAuthenticate ? "TRUE" : "FALSE", fCommandLogging ? "TRUE" : "FALSE"); 798 799 hr = InternetTransport_Connect(&This->InetTransport, pInetServer, fAuthenticate, fCommandLogging); 800 if (FAILED(hr)) 801 return hr; 802 803 init_parser(This, POP3_USER, POP3_NONE); 804 return InternetTransport_ReadLine(&This->InetTransport, POP3Transport_CallbackSendUSERCmd); 805 } 806 807 static HRESULT WINAPI POP3Transport_HandsOffCallback(IPOP3Transport *iface) 808 { 809 POP3Transport *This = (POP3Transport *)iface; 810 811 TRACE("()\n"); 812 return InternetTransport_HandsOffCallback(&This->InetTransport); 813 } 814 815 static HRESULT WINAPI POP3Transport_Disconnect(IPOP3Transport *iface) 816 { 817 TRACE("()\n"); 818 return IPOP3Transport_CommandQUIT(iface); 819 } 820 821 static HRESULT WINAPI POP3Transport_DropConnection(IPOP3Transport *iface) 822 { 823 POP3Transport *This = (POP3Transport *)iface; 824 825 TRACE("()\n"); 826 return InternetTransport_DropConnection(&This->InetTransport); 827 } 828 829 static HRESULT WINAPI POP3Transport_GetStatus(IPOP3Transport *iface, 830 IXPSTATUS *pCurrentStatus) 831 { 832 POP3Transport *This = (POP3Transport *)iface; 833 834 TRACE("()\n"); 835 return InternetTransport_GetStatus(&This->InetTransport, pCurrentStatus); 836 } 837 838 static HRESULT WINAPI POP3Transport_InitNew(IPOP3Transport *iface, 839 LPSTR pszLogFilePath, IPOP3Callback *pCallback) 840 { 841 POP3Transport *This = (POP3Transport *)iface; 842 843 TRACE("(%s, %p)\n", debugstr_a(pszLogFilePath), pCallback); 844 845 if (!pCallback) 846 return E_INVALIDARG; 847 848 if (pszLogFilePath) 849 FIXME("not using log file of %s, use Wine debug logging instead\n", 850 debugstr_a(pszLogFilePath)); 851 852 IPOP3Callback_AddRef(pCallback); 853 This->InetTransport.pCallback = (ITransportCallback *)pCallback; 854 This->InetTransport.fInitialised = TRUE; 855 856 return S_OK; 857 } 858 859 static HRESULT WINAPI POP3Transport_MarkItem(IPOP3Transport *iface, POP3MARKTYPE marktype, 860 DWORD dwPopId, boolean fMarked) 861 { 862 FIXME("(%u, %u, %d)\n", marktype, dwPopId, fMarked); 863 return E_NOTIMPL; 864 } 865 866 static HRESULT WINAPI POP3Transport_CommandAUTH(IPOP3Transport *iface, LPSTR pszAuthType) 867 { 868 FIXME("(%s)\n", pszAuthType); 869 return E_NOTIMPL; 870 } 871 872 static HRESULT WINAPI POP3Transport_CommandUSER(IPOP3Transport *iface, LPSTR username) 873 { 874 static char user[] = "USER "; 875 POP3Transport *This = (POP3Transport *)iface; 876 char *command; 877 int len; 878 879 TRACE("(%s)\n", username); 880 881 len = sizeof(user) + strlen(username) + 2; /* "\r\n" */ 882 if (!(command = HeapAlloc(GetProcessHeap(), 0, len))) return S_FALSE; 883 884 strcpy(command, user); 885 strcat(command, username); 886 strcat(command, "\r\n"); 887 888 init_parser(This, POP3_USER, POP3_NONE); 889 InternetTransport_DoCommand(&This->InetTransport, command, POP3Transport_CallbackRecvUSERResp); 890 891 HeapFree(GetProcessHeap(), 0, command); 892 return S_OK; 893 } 894 895 static HRESULT WINAPI POP3Transport_CommandPASS(IPOP3Transport *iface, LPSTR password) 896 { 897 static char pass[] = "PASS "; 898 POP3Transport *This = (POP3Transport *)iface; 899 char *command; 900 int len; 901 902 TRACE("(%p)\n", password); 903 904 len = sizeof(pass) + strlen(password) + 2; /* "\r\n" */ 905 if (!(command = HeapAlloc(GetProcessHeap(), 0, len))) return S_FALSE; 906 907 strcpy(command, pass); 908 strcat(command, password); 909 strcat(command, "\r\n"); 910 911 init_parser(This, POP3_PASS, POP3_NONE); 912 InternetTransport_DoCommand(&This->InetTransport, command, POP3Transport_CallbackRecvPASSResp); 913 914 HeapFree(GetProcessHeap(), 0, command); 915 return S_OK; 916 } 917 918 static HRESULT WINAPI POP3Transport_CommandLIST( 919 IPOP3Transport *iface, POP3CMDTYPE cmdtype, DWORD dwPopId) 920 { 921 static char list[] = "LIST %u\r\n"; 922 static char list_all[] = "LIST\r\n"; 923 POP3Transport *This = (POP3Transport *)iface; 924 char *command; 925 int len; 926 927 TRACE("(%u, %u)\n", cmdtype, dwPopId); 928 929 if (dwPopId) 930 { 931 len = sizeof(list) + 10 + 2; /* "4294967296" + "\r\n" */ 932 if (!(command = HeapAlloc(GetProcessHeap(), 0, len))) return S_FALSE; 933 sprintf(command, list, dwPopId); 934 } 935 else command = list_all; 936 937 init_parser(This, POP3_LIST, cmdtype); 938 InternetTransport_DoCommand(&This->InetTransport, command, POP3Transport_CallbackRecvLISTResp); 939 940 if (dwPopId) HeapFree(GetProcessHeap(), 0, command); 941 return S_OK; 942 } 943 944 static HRESULT WINAPI POP3Transport_CommandTOP( 945 IPOP3Transport *iface, POP3CMDTYPE cmdtype, DWORD dwPopId, DWORD cPreviewLines) 946 { 947 static char top[] = "TOP %u %u\r\n"; 948 POP3Transport *This = (POP3Transport *)iface; 949 char *command; 950 int len; 951 952 TRACE("(%u, %u, %u)\n", cmdtype, dwPopId, cPreviewLines); 953 954 len = sizeof(top) + 20 + 2; /* 2 * "4294967296" + "\r\n" */ 955 if (!(command = HeapAlloc(GetProcessHeap(), 0, len))) return S_FALSE; 956 sprintf(command, top, dwPopId, cPreviewLines); 957 958 This->preview_lines = cPreviewLines; 959 init_parser(This, POP3_TOP, cmdtype); 960 InternetTransport_DoCommand(&This->InetTransport, command, POP3Transport_CallbackRecvTOPResp); 961 962 HeapFree(GetProcessHeap(), 0, command); 963 return S_OK; 964 } 965 966 static HRESULT WINAPI POP3Transport_CommandQUIT(IPOP3Transport *iface) 967 { 968 static char command[] = "QUIT\r\n"; 969 POP3Transport *This = (POP3Transport *)iface; 970 971 TRACE("()\n"); 972 973 InternetTransport_ChangeStatus(&This->InetTransport, IXP_DISCONNECTING); 974 975 init_parser(This, POP3_QUIT, POP3_NONE); 976 return InternetTransport_DoCommand(&This->InetTransport, command, POP3Transport_CallbackRecvQUITResp); 977 } 978 979 static HRESULT WINAPI POP3Transport_CommandSTAT(IPOP3Transport *iface) 980 { 981 static char stat[] = "STAT\r\n"; 982 POP3Transport *This = (POP3Transport *)iface; 983 984 TRACE("\n"); 985 986 init_parser(This, POP3_STAT, POP3_NONE); 987 InternetTransport_DoCommand(&This->InetTransport, stat, POP3Transport_CallbackRecvSTATResp); 988 return S_OK; 989 } 990 991 static HRESULT WINAPI POP3Transport_CommandNOOP(IPOP3Transport *iface) 992 { 993 static char noop[] = "NOOP\r\n"; 994 POP3Transport *This = (POP3Transport *)iface; 995 996 TRACE("\n"); 997 998 init_parser(This, POP3_NOOP, POP3_NONE); 999 InternetTransport_DoCommand(&This->InetTransport, noop, POP3Transport_CallbackRecvNOOPResp); 1000 return S_OK; 1001 } 1002 1003 static HRESULT WINAPI POP3Transport_CommandRSET(IPOP3Transport *iface) 1004 { 1005 static char rset[] = "RSET\r\n"; 1006 POP3Transport *This = (POP3Transport *)iface; 1007 1008 TRACE("\n"); 1009 1010 init_parser(This, POP3_RSET, POP3_NONE); 1011 InternetTransport_DoCommand(&This->InetTransport, rset, POP3Transport_CallbackRecvRSETResp); 1012 return S_OK; 1013 } 1014 1015 static HRESULT WINAPI POP3Transport_CommandUIDL( 1016 IPOP3Transport *iface, POP3CMDTYPE cmdtype, DWORD dwPopId) 1017 { 1018 static char uidl[] = "UIDL %u\r\n"; 1019 static char uidl_all[] = "UIDL\r\n"; 1020 POP3Transport *This = (POP3Transport *)iface; 1021 char *command; 1022 int len; 1023 1024 TRACE("(%u, %u)\n", cmdtype, dwPopId); 1025 1026 if (dwPopId) 1027 { 1028 len = sizeof(uidl) + 10 + 2; /* "4294967296" + "\r\n" */ 1029 if (!(command = HeapAlloc(GetProcessHeap(), 0, len))) return S_FALSE; 1030 sprintf(command, uidl, dwPopId); 1031 } 1032 else command = uidl_all; 1033 1034 init_parser(This, POP3_UIDL, cmdtype); 1035 InternetTransport_DoCommand(&This->InetTransport, command, POP3Transport_CallbackRecvUIDLResp); 1036 1037 if (dwPopId) HeapFree(GetProcessHeap(), 0, command); 1038 return S_OK; 1039 } 1040 1041 static HRESULT WINAPI POP3Transport_CommandDELE( 1042 IPOP3Transport *iface, POP3CMDTYPE cmdtype, DWORD dwPopId) 1043 { 1044 static char dele[] = "DELE %u\r\n"; 1045 POP3Transport *This = (POP3Transport *)iface; 1046 char *command; 1047 int len; 1048 1049 TRACE("(%u, %u)\n", cmdtype, dwPopId); 1050 1051 len = sizeof(dele) + 10 + 2; /* "4294967296" + "\r\n" */ 1052 if (!(command = HeapAlloc(GetProcessHeap(), 0, len))) return S_FALSE; 1053 sprintf(command, dele, dwPopId); 1054 1055 init_parser(This, POP3_DELE, cmdtype); 1056 InternetTransport_DoCommand(&This->InetTransport, command, POP3Transport_CallbackRecvDELEResp); 1057 1058 HeapFree(GetProcessHeap(), 0, command); 1059 return S_OK; 1060 } 1061 1062 static HRESULT WINAPI POP3Transport_CommandRETR( 1063 IPOP3Transport *iface, POP3CMDTYPE cmdtype, DWORD dwPopId) 1064 { 1065 static char retr[] = "RETR %u\r\n"; 1066 POP3Transport *This = (POP3Transport *)iface; 1067 char *command; 1068 int len; 1069 1070 TRACE("(%u, %u)\n", cmdtype, dwPopId); 1071 1072 len = sizeof(retr) + 10 + 2; /* "4294967296" + "\r\n" */ 1073 if (!(command = HeapAlloc(GetProcessHeap(), 0, len))) return S_FALSE; 1074 sprintf(command, retr, dwPopId); 1075 1076 init_parser(This, POP3_RETR, cmdtype); 1077 InternetTransport_DoCommand(&This->InetTransport, command, POP3Transport_CallbackRecvRETRResp); 1078 1079 HeapFree(GetProcessHeap(), 0, command); 1080 return S_OK; 1081 } 1082 1083 static const IPOP3TransportVtbl POP3TransportVtbl = 1084 { 1085 POP3Transport_QueryInterface, 1086 POP3Transport_AddRef, 1087 POP3Transport_Release, 1088 POP3Transport_GetServerInfo, 1089 POP3Transport_GetIXPType, 1090 POP3Transport_IsState, 1091 POP3Transport_InetServerFromAccount, 1092 POP3Transport_Connect, 1093 POP3Transport_HandsOffCallback, 1094 POP3Transport_Disconnect, 1095 POP3Transport_DropConnection, 1096 POP3Transport_GetStatus, 1097 POP3Transport_InitNew, 1098 POP3Transport_MarkItem, 1099 POP3Transport_CommandAUTH, 1100 POP3Transport_CommandUSER, 1101 POP3Transport_CommandPASS, 1102 POP3Transport_CommandLIST, 1103 POP3Transport_CommandTOP, 1104 POP3Transport_CommandQUIT, 1105 POP3Transport_CommandSTAT, 1106 POP3Transport_CommandNOOP, 1107 POP3Transport_CommandRSET, 1108 POP3Transport_CommandUIDL, 1109 POP3Transport_CommandDELE, 1110 POP3Transport_CommandRETR 1111 }; 1112 1113 HRESULT WINAPI CreatePOP3Transport(IPOP3Transport **ppTransport) 1114 { 1115 HRESULT hr; 1116 POP3Transport *This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This)); 1117 if (!This) 1118 return E_OUTOFMEMORY; 1119 1120 This->InetTransport.u.vtblPOP3 = &POP3TransportVtbl; 1121 This->refs = 0; 1122 hr = InternetTransport_Init(&This->InetTransport); 1123 if (FAILED(hr)) 1124 { 1125 HeapFree(GetProcessHeap(), 0, This); 1126 return hr; 1127 } 1128 1129 *ppTransport = (IPOP3Transport *)&This->InetTransport.u.vtblPOP3; 1130 IPOP3Transport_AddRef(*ppTransport); 1131 1132 return S_OK; 1133 } 1134 1135 static HRESULT WINAPI POP3TransportCF_QueryInterface(LPCLASSFACTORY iface, 1136 REFIID riid, LPVOID *ppv) 1137 { 1138 *ppv = NULL; 1139 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IClassFactory)) 1140 { 1141 *ppv = iface; 1142 IUnknown_AddRef(iface); 1143 return S_OK; 1144 } 1145 return E_NOINTERFACE; 1146 } 1147 1148 static ULONG WINAPI POP3TransportCF_AddRef(LPCLASSFACTORY iface) 1149 { 1150 return 2; /* non-heap based object */ 1151 } 1152 1153 static ULONG WINAPI POP3TransportCF_Release(LPCLASSFACTORY iface) 1154 { 1155 return 1; /* non-heap based object */ 1156 } 1157 1158 static HRESULT WINAPI POP3TransportCF_CreateInstance(LPCLASSFACTORY iface, 1159 LPUNKNOWN pUnk, REFIID riid, LPVOID *ppv) 1160 { 1161 HRESULT hr; 1162 IPOP3Transport *pPop3Transport; 1163 1164 TRACE("(%p, %s, %p)\n", pUnk, debugstr_guid(riid), ppv); 1165 1166 *ppv = NULL; 1167 1168 if (pUnk) 1169 return CLASS_E_NOAGGREGATION; 1170 1171 hr = CreatePOP3Transport(&pPop3Transport); 1172 if (FAILED(hr)) 1173 return hr; 1174 1175 hr = IPOP3Transport_QueryInterface(pPop3Transport, riid, ppv); 1176 IPOP3Transport_Release(pPop3Transport); 1177 1178 return hr; 1179 } 1180 1181 static HRESULT WINAPI POP3TransportCF_LockServer(LPCLASSFACTORY iface, BOOL fLock) 1182 { 1183 FIXME("(%d)\n",fLock); 1184 return S_OK; 1185 } 1186 1187 static const IClassFactoryVtbl POP3TransportCFVtbl = 1188 { 1189 POP3TransportCF_QueryInterface, 1190 POP3TransportCF_AddRef, 1191 POP3TransportCF_Release, 1192 POP3TransportCF_CreateInstance, 1193 POP3TransportCF_LockServer 1194 }; 1195 static const IClassFactoryVtbl *POP3TransportCF = &POP3TransportCFVtbl; 1196 1197 HRESULT POP3TransportCF_Create(REFIID riid, LPVOID *ppv) 1198 { 1199 return IClassFactory_QueryInterface((IClassFactory *)&POP3TransportCF, riid, ppv); 1200 } 1201