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) 315 { 316 This->state = STATE_NONE; 317 This->command = command; 318 } 319 320 static HRESULT POP3Transport_ParseResponse(POP3Transport *This, char *pszResponse, POP3RESPONSE *pResponse) 321 { 322 HRESULT hr; 323 324 TRACE("response: %s\n", debugstr_a(pszResponse)); 325 326 This->response = pszResponse; 327 This->valid_info = FALSE; 328 TRACE("state %u\n", This->state); 329 330 if (SUCCEEDED((hr = parse_response(This)))) 331 { 332 switch (This->command) 333 { 334 case POP3_UIDL: hr = parse_uidl_response(This, &pResponse->u.rUidlInfo); break; 335 case POP3_STAT: hr = parse_stat_response(This, &pResponse->u.rStatInfo); break; 336 case POP3_LIST: hr = parse_list_response(This, &pResponse->u.rListInfo); break; 337 case POP3_DELE: hr = parse_dele_response(This, &pResponse->u.dwPopId); break; 338 case POP3_RETR: hr = parse_retr_response(This, &pResponse->u.rRetrInfo); break; 339 case POP3_TOP: hr = parse_top_response(This, &pResponse->u.rTopInfo); break; 340 default: 341 This->state = STATE_DONE; 342 break; 343 } 344 } 345 pResponse->command = This->command; 346 pResponse->fDone = (This->state == STATE_DONE); 347 pResponse->fValidInfo = This->valid_info; 348 pResponse->rIxpResult.hrResult = hr; 349 pResponse->rIxpResult.pszResponse = pszResponse; 350 pResponse->rIxpResult.uiServerError = 0; 351 pResponse->rIxpResult.hrServerError = pResponse->rIxpResult.hrResult; 352 pResponse->rIxpResult.dwSocketError = WSAGetLastError(); 353 pResponse->rIxpResult.pszProblem = NULL; 354 pResponse->pTransport = (IPOP3Transport *)&This->InetTransport.u.vtblPOP3; 355 356 if (This->InetTransport.pCallback && This->InetTransport.fCommandLogging) 357 { 358 ITransportCallback_OnCommand(This->InetTransport.pCallback, CMD_RESP, 359 pResponse->rIxpResult.pszResponse, pResponse->rIxpResult.hrServerError, 360 (IInternetTransport *)&This->InetTransport.u.vtbl); 361 } 362 return S_OK; 363 } 364 365 static void POP3Transport_CallbackProcessDELEResp(IInternetTransport *iface, char *pBuffer, int cbBuffer) 366 { 367 POP3Transport *This = (POP3Transport *)iface; 368 POP3RESPONSE response; 369 HRESULT hr; 370 371 TRACE("\n"); 372 373 hr = POP3Transport_ParseResponse(This, pBuffer, &response); 374 if (FAILED(hr)) 375 { 376 /* FIXME: handle error */ 377 return; 378 } 379 380 IPOP3Callback_OnResponse((IPOP3Callback *)This->InetTransport.pCallback, &response); 381 } 382 383 static void POP3Transport_CallbackRecvDELEResp(IInternetTransport *iface, char *pBuffer, int cbBuffer) 384 { 385 POP3Transport *This = (POP3Transport *)iface; 386 387 TRACE("\n"); 388 InternetTransport_ReadLine(&This->InetTransport, POP3Transport_CallbackProcessDELEResp); 389 } 390 391 static void POP3Transport_CallbackProcessNOOPResp(IInternetTransport *iface, char *pBuffer, int cbBuffer) 392 { 393 POP3Transport *This = (POP3Transport *)iface; 394 POP3RESPONSE response; 395 HRESULT hr; 396 397 TRACE("\n"); 398 399 hr = POP3Transport_ParseResponse(This, pBuffer, &response); 400 if (FAILED(hr)) 401 { 402 /* FIXME: handle error */ 403 return; 404 } 405 406 IPOP3Callback_OnResponse((IPOP3Callback *)This->InetTransport.pCallback, &response); 407 } 408 409 static void POP3Transport_CallbackRecvNOOPResp(IInternetTransport *iface, char *pBuffer, int cbBuffer) 410 { 411 POP3Transport *This = (POP3Transport *)iface; 412 413 TRACE("\n"); 414 InternetTransport_ReadLine(&This->InetTransport, POP3Transport_CallbackProcessNOOPResp); 415 } 416 417 static void POP3Transport_CallbackProcessRSETResp(IInternetTransport *iface, char *pBuffer, int cbBuffer) 418 { 419 POP3Transport *This = (POP3Transport *)iface; 420 POP3RESPONSE response; 421 HRESULT hr; 422 423 TRACE("\n"); 424 425 hr = POP3Transport_ParseResponse(This, pBuffer, &response); 426 if (FAILED(hr)) 427 { 428 /* FIXME: handle error */ 429 return; 430 } 431 432 IPOP3Callback_OnResponse((IPOP3Callback *)This->InetTransport.pCallback, &response); 433 } 434 435 static void POP3Transport_CallbackRecvRSETResp(IInternetTransport *iface, char *pBuffer, int cbBuffer) 436 { 437 POP3Transport *This = (POP3Transport *)iface; 438 439 TRACE("\n"); 440 InternetTransport_ReadLine(&This->InetTransport, POP3Transport_CallbackProcessRSETResp); 441 } 442 443 static void POP3Transport_CallbackProcessRETRResp(IInternetTransport *iface, char *pBuffer, int cbBuffer) 444 { 445 POP3Transport *This = (POP3Transport *)iface; 446 POP3RESPONSE response; 447 HRESULT hr; 448 449 TRACE("\n"); 450 451 hr = POP3Transport_ParseResponse(This, pBuffer, &response); 452 if (FAILED(hr)) 453 { 454 /* FIXME: handle error */ 455 return; 456 } 457 458 IPOP3Callback_OnResponse((IPOP3Callback *)This->InetTransport.pCallback, &response); 459 460 if (!response.fDone) 461 { 462 InternetTransport_ReadLine(&This->InetTransport, POP3Transport_CallbackProcessRETRResp); 463 return; 464 } 465 466 IPOP3Callback_OnResponse((IPOP3Callback *)This->InetTransport.pCallback, &response); 467 } 468 469 static void POP3Transport_CallbackRecvRETRResp(IInternetTransport *iface, char *pBuffer, int cbBuffer) 470 { 471 POP3Transport *This = (POP3Transport *)iface; 472 473 TRACE("\n"); 474 InternetTransport_ReadLine(&This->InetTransport, POP3Transport_CallbackProcessRETRResp); 475 } 476 477 static void POP3Transport_CallbackProcessTOPResp(IInternetTransport *iface, char *pBuffer, int cbBuffer) 478 { 479 POP3Transport *This = (POP3Transport *)iface; 480 POP3RESPONSE response; 481 HRESULT hr; 482 483 TRACE("\n"); 484 485 hr = POP3Transport_ParseResponse(This, pBuffer, &response); 486 if (FAILED(hr)) 487 { 488 /* FIXME: handle error */ 489 return; 490 } 491 492 IPOP3Callback_OnResponse((IPOP3Callback *)This->InetTransport.pCallback, &response); 493 494 if (!response.fDone) 495 { 496 InternetTransport_ReadLine(&This->InetTransport, POP3Transport_CallbackProcessTOPResp); 497 return; 498 } 499 500 IPOP3Callback_OnResponse((IPOP3Callback *)This->InetTransport.pCallback, &response); 501 } 502 503 static void POP3Transport_CallbackRecvTOPResp(IInternetTransport *iface, char *pBuffer, int cbBuffer) 504 { 505 POP3Transport *This = (POP3Transport *)iface; 506 507 TRACE("\n"); 508 InternetTransport_ReadLine(&This->InetTransport, POP3Transport_CallbackProcessTOPResp); 509 } 510 511 static void POP3Transport_CallbackProcessLISTResp(IInternetTransport *iface, char *pBuffer, int cbBuffer) 512 { 513 POP3Transport *This = (POP3Transport *)iface; 514 POP3RESPONSE response; 515 HRESULT hr; 516 517 TRACE("\n"); 518 519 hr = POP3Transport_ParseResponse(This, pBuffer, &response); 520 if (FAILED(hr)) 521 { 522 /* FIXME: handle error */ 523 return; 524 } 525 526 IPOP3Callback_OnResponse((IPOP3Callback *)This->InetTransport.pCallback, &response); 527 528 if (!response.fDone) 529 { 530 InternetTransport_ReadLine(&This->InetTransport, POP3Transport_CallbackProcessLISTResp); 531 return; 532 } 533 534 IPOP3Callback_OnResponse((IPOP3Callback *)This->InetTransport.pCallback, &response); 535 } 536 537 static void POP3Transport_CallbackRecvLISTResp(IInternetTransport *iface, char *pBuffer, int cbBuffer) 538 { 539 POP3Transport *This = (POP3Transport *)iface; 540 541 TRACE("\n"); 542 InternetTransport_ReadLine(&This->InetTransport, POP3Transport_CallbackProcessLISTResp); 543 } 544 545 static void POP3Transport_CallbackProcessUIDLResp(IInternetTransport *iface, char *pBuffer, int cbBuffer) 546 { 547 POP3Transport *This = (POP3Transport *)iface; 548 POP3RESPONSE response; 549 HRESULT hr; 550 551 TRACE("\n"); 552 553 hr = POP3Transport_ParseResponse(This, pBuffer, &response); 554 if (FAILED(hr)) 555 { 556 /* FIXME: handle error */ 557 return; 558 } 559 560 IPOP3Callback_OnResponse((IPOP3Callback *)This->InetTransport.pCallback, &response); 561 562 if (!response.fDone) 563 { 564 InternetTransport_ReadLine(&This->InetTransport, POP3Transport_CallbackProcessUIDLResp); 565 return; 566 } 567 568 IPOP3Callback_OnResponse((IPOP3Callback *)This->InetTransport.pCallback, &response); 569 } 570 571 static void POP3Transport_CallbackRecvUIDLResp(IInternetTransport *iface, char *pBuffer, int cbBuffer) 572 { 573 POP3Transport *This = (POP3Transport *)iface; 574 575 TRACE("\n"); 576 InternetTransport_ReadLine(&This->InetTransport, POP3Transport_CallbackProcessUIDLResp); 577 } 578 579 static void POP3Transport_CallbackProcessSTATResp(IInternetTransport *iface, char *pBuffer, int cbBuffer) 580 { 581 POP3Transport *This = (POP3Transport *)iface; 582 POP3RESPONSE response; 583 HRESULT hr; 584 585 TRACE("\n"); 586 587 hr = POP3Transport_ParseResponse(This, pBuffer, &response); 588 if (FAILED(hr)) 589 { 590 /* FIXME: handle error */ 591 return; 592 } 593 594 IPOP3Callback_OnResponse((IPOP3Callback *)This->InetTransport.pCallback, &response); 595 } 596 597 static void POP3Transport_CallbackRecvSTATResp(IInternetTransport *iface, char *pBuffer, int cbBuffer) 598 { 599 POP3Transport *This = (POP3Transport *)iface; 600 601 TRACE("\n"); 602 InternetTransport_ReadLine(&This->InetTransport, POP3Transport_CallbackProcessSTATResp); 603 } 604 605 static void POP3Transport_CallbackProcessPASSResp(IInternetTransport *iface, char *pBuffer, int cbBuffer) 606 { 607 POP3Transport *This = (POP3Transport *)iface; 608 POP3RESPONSE response; 609 HRESULT hr; 610 611 TRACE("\n"); 612 613 hr = POP3Transport_ParseResponse(This, pBuffer, &response); 614 if (FAILED(hr)) 615 { 616 /* FIXME: handle error */ 617 return; 618 } 619 620 InternetTransport_ChangeStatus(&This->InetTransport, IXP_AUTHORIZED); 621 InternetTransport_ChangeStatus(&This->InetTransport, IXP_CONNECTED); 622 623 IPOP3Callback_OnResponse((IPOP3Callback *)This->InetTransport.pCallback, &response); 624 } 625 626 static void POP3Transport_CallbackRecvPASSResp(IInternetTransport *iface, char *pBuffer, int cbBuffer) 627 { 628 POP3Transport *This = (POP3Transport *)iface; 629 630 TRACE("\n"); 631 InternetTransport_ReadLine(&This->InetTransport, POP3Transport_CallbackProcessPASSResp); 632 } 633 634 static void POP3Transport_CallbackProcessUSERResp(IInternetTransport *iface, char *pBuffer, int cbBuffer) 635 { 636 static const char pass[] = "PASS "; 637 POP3Transport *This = (POP3Transport *)iface; 638 POP3RESPONSE response; 639 char *command; 640 int len; 641 HRESULT hr; 642 643 TRACE("\n"); 644 645 hr = POP3Transport_ParseResponse(This, pBuffer, &response); 646 if (FAILED(hr)) 647 { 648 /* FIXME: handle error */ 649 return; 650 } 651 652 IPOP3Callback_OnResponse((IPOP3Callback *)This->InetTransport.pCallback, &response); 653 654 len = sizeof(pass) + strlen(This->InetTransport.ServerInfo.szPassword) + 2; /* "\r\n" */ 655 command = HeapAlloc(GetProcessHeap(), 0, len); 656 657 strcpy(command, pass); 658 strcat(command, This->InetTransport.ServerInfo.szPassword); 659 strcat(command, "\r\n"); 660 661 init_parser(This, POP3_PASS); 662 663 InternetTransport_DoCommand(&This->InetTransport, command, POP3Transport_CallbackRecvPASSResp); 664 HeapFree(GetProcessHeap(), 0, command); 665 } 666 667 static void POP3Transport_CallbackRecvUSERResp(IInternetTransport *iface, char *pBuffer, int cbBuffer) 668 { 669 POP3Transport *This = (POP3Transport *)iface; 670 671 TRACE("\n"); 672 InternetTransport_ReadLine(&This->InetTransport, POP3Transport_CallbackProcessUSERResp); 673 } 674 675 static void POP3Transport_CallbackSendUSERCmd(IInternetTransport *iface, char *pBuffer, int cbBuffer) 676 { 677 static const char user[] = "USER "; 678 POP3Transport *This = (POP3Transport *)iface; 679 char *command; 680 int len; 681 682 TRACE("\n"); 683 684 len = sizeof(user) + strlen(This->InetTransport.ServerInfo.szUserName) + 2; /* "\r\n" */ 685 command = HeapAlloc(GetProcessHeap(), 0, len); 686 687 strcpy(command, user); 688 strcat(command, This->InetTransport.ServerInfo.szUserName); 689 strcat(command, "\r\n"); 690 InternetTransport_DoCommand(&This->InetTransport, command, POP3Transport_CallbackRecvUSERResp); 691 692 HeapFree(GetProcessHeap(), 0, command); 693 } 694 695 static void POP3Transport_CallbackProcessQUITResponse(IInternetTransport *iface, char *pBuffer, int cbBuffer) 696 { 697 POP3Transport *This = (POP3Transport *)iface; 698 POP3RESPONSE response; 699 HRESULT hr; 700 701 TRACE("%s\n", debugstr_an(pBuffer, cbBuffer)); 702 703 hr = POP3Transport_ParseResponse(This, pBuffer, &response); 704 if (FAILED(hr)) 705 { 706 /* FIXME: handle error */ 707 return; 708 } 709 710 IPOP3Callback_OnResponse((IPOP3Callback *)This->InetTransport.pCallback, &response); 711 InternetTransport_DropConnection(&This->InetTransport); 712 } 713 714 static void POP3Transport_CallbackRecvQUITResp(IInternetTransport *iface, char *pBuffer, int cbBuffer) 715 { 716 POP3Transport *This = (POP3Transport *)iface; 717 718 TRACE("\n"); 719 InternetTransport_ReadLine(&This->InetTransport, POP3Transport_CallbackProcessQUITResponse); 720 } 721 722 static HRESULT WINAPI POP3Transport_QueryInterface(IPOP3Transport *iface, REFIID riid, void **ppv) 723 { 724 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv); 725 726 if (IsEqualIID(riid, &IID_IUnknown) || 727 IsEqualIID(riid, &IID_IInternetTransport) || 728 IsEqualIID(riid, &IID_IPOP3Transport)) 729 { 730 *ppv = iface; 731 IPOP3Transport_AddRef(iface); 732 return S_OK; 733 } 734 *ppv = NULL; 735 FIXME("no interface for %s\n", debugstr_guid(riid)); 736 return E_NOINTERFACE; 737 } 738 739 static ULONG WINAPI POP3Transport_AddRef(IPOP3Transport *iface) 740 { 741 POP3Transport *This = (POP3Transport *)iface; 742 return InterlockedIncrement((LONG *)&This->refs); 743 } 744 745 static ULONG WINAPI POP3Transport_Release(IPOP3Transport *iface) 746 { 747 POP3Transport *This = (POP3Transport *)iface; 748 ULONG refs = InterlockedDecrement((LONG *)&This->refs); 749 if (!refs) 750 { 751 TRACE("destroying %p\n", This); 752 if (This->InetTransport.Status != IXP_DISCONNECTED) 753 InternetTransport_DropConnection(&This->InetTransport); 754 if (This->InetTransport.pCallback) ITransportCallback_Release(This->InetTransport.pCallback); 755 HeapFree(GetProcessHeap(), 0, This); 756 } 757 return refs; 758 } 759 760 static HRESULT WINAPI POP3Transport_GetServerInfo(IPOP3Transport *iface, 761 LPINETSERVER pInetServer) 762 { 763 POP3Transport *This = (POP3Transport *)iface; 764 765 TRACE("(%p)\n", pInetServer); 766 return InternetTransport_GetServerInfo(&This->InetTransport, pInetServer); 767 } 768 769 static IXPTYPE WINAPI POP3Transport_GetIXPType(IPOP3Transport *iface) 770 { 771 TRACE("()\n"); 772 return IXP_POP3; 773 } 774 775 static HRESULT WINAPI POP3Transport_IsState(IPOP3Transport *iface, IXPISSTATE isstate) 776 { 777 FIXME("(%u)\n", isstate); 778 return E_NOTIMPL; 779 } 780 781 static HRESULT WINAPI POP3Transport_InetServerFromAccount( 782 IPOP3Transport *iface, IImnAccount *pAccount, LPINETSERVER pInetServer) 783 { 784 POP3Transport *This = (POP3Transport *)iface; 785 786 TRACE("(%p, %p)\n", pAccount, pInetServer); 787 return InternetTransport_InetServerFromAccount(&This->InetTransport, pAccount, pInetServer); 788 } 789 790 static HRESULT WINAPI POP3Transport_Connect(IPOP3Transport *iface, 791 LPINETSERVER pInetServer, boolean fAuthenticate, boolean fCommandLogging) 792 { 793 POP3Transport *This = (POP3Transport *)iface; 794 HRESULT hr; 795 796 TRACE("(%p, %s, %s)\n", pInetServer, fAuthenticate ? "TRUE" : "FALSE", fCommandLogging ? "TRUE" : "FALSE"); 797 798 hr = InternetTransport_Connect(&This->InetTransport, pInetServer, fAuthenticate, fCommandLogging); 799 if (FAILED(hr)) 800 return hr; 801 802 init_parser(This, POP3_USER); 803 return InternetTransport_ReadLine(&This->InetTransport, POP3Transport_CallbackSendUSERCmd); 804 } 805 806 static HRESULT WINAPI POP3Transport_HandsOffCallback(IPOP3Transport *iface) 807 { 808 POP3Transport *This = (POP3Transport *)iface; 809 810 TRACE("()\n"); 811 return InternetTransport_HandsOffCallback(&This->InetTransport); 812 } 813 814 static HRESULT WINAPI POP3Transport_Disconnect(IPOP3Transport *iface) 815 { 816 TRACE("()\n"); 817 return IPOP3Transport_CommandQUIT(iface); 818 } 819 820 static HRESULT WINAPI POP3Transport_DropConnection(IPOP3Transport *iface) 821 { 822 POP3Transport *This = (POP3Transport *)iface; 823 824 TRACE("()\n"); 825 return InternetTransport_DropConnection(&This->InetTransport); 826 } 827 828 static HRESULT WINAPI POP3Transport_GetStatus(IPOP3Transport *iface, 829 IXPSTATUS *pCurrentStatus) 830 { 831 POP3Transport *This = (POP3Transport *)iface; 832 833 TRACE("()\n"); 834 return InternetTransport_GetStatus(&This->InetTransport, pCurrentStatus); 835 } 836 837 static HRESULT WINAPI POP3Transport_InitNew(IPOP3Transport *iface, 838 LPSTR pszLogFilePath, IPOP3Callback *pCallback) 839 { 840 POP3Transport *This = (POP3Transport *)iface; 841 842 TRACE("(%s, %p)\n", debugstr_a(pszLogFilePath), pCallback); 843 844 if (!pCallback) 845 return E_INVALIDARG; 846 847 if (pszLogFilePath) 848 FIXME("not using log file of %s, use Wine debug logging instead\n", 849 debugstr_a(pszLogFilePath)); 850 851 IPOP3Callback_AddRef(pCallback); 852 This->InetTransport.pCallback = (ITransportCallback *)pCallback; 853 This->InetTransport.fInitialised = TRUE; 854 855 return S_OK; 856 } 857 858 static HRESULT WINAPI POP3Transport_MarkItem(IPOP3Transport *iface, POP3MARKTYPE marktype, 859 DWORD dwPopId, boolean fMarked) 860 { 861 FIXME("(%u, %u, %d)\n", marktype, dwPopId, fMarked); 862 return E_NOTIMPL; 863 } 864 865 static HRESULT WINAPI POP3Transport_CommandAUTH(IPOP3Transport *iface, LPSTR pszAuthType) 866 { 867 FIXME("(%s)\n", pszAuthType); 868 return E_NOTIMPL; 869 } 870 871 static HRESULT WINAPI POP3Transport_CommandUSER(IPOP3Transport *iface, LPSTR username) 872 { 873 static const char user[] = "USER "; 874 POP3Transport *This = (POP3Transport *)iface; 875 char *command; 876 int len; 877 878 TRACE("(%s)\n", username); 879 880 len = sizeof(user) + strlen(username) + 2; /* "\r\n" */ 881 if (!(command = HeapAlloc(GetProcessHeap(), 0, len))) return S_FALSE; 882 883 strcpy(command, user); 884 strcat(command, username); 885 strcat(command, "\r\n"); 886 887 init_parser(This, POP3_USER); 888 InternetTransport_DoCommand(&This->InetTransport, command, POP3Transport_CallbackRecvUSERResp); 889 890 HeapFree(GetProcessHeap(), 0, command); 891 return S_OK; 892 } 893 894 static HRESULT WINAPI POP3Transport_CommandPASS(IPOP3Transport *iface, LPSTR password) 895 { 896 static const char pass[] = "PASS "; 897 POP3Transport *This = (POP3Transport *)iface; 898 char *command; 899 int len; 900 901 TRACE("(%p)\n", password); 902 903 len = sizeof(pass) + strlen(password) + 2; /* "\r\n" */ 904 if (!(command = HeapAlloc(GetProcessHeap(), 0, len))) return S_FALSE; 905 906 strcpy(command, pass); 907 strcat(command, password); 908 strcat(command, "\r\n"); 909 910 init_parser(This, POP3_PASS); 911 InternetTransport_DoCommand(&This->InetTransport, command, POP3Transport_CallbackRecvPASSResp); 912 913 HeapFree(GetProcessHeap(), 0, command); 914 return S_OK; 915 } 916 917 static HRESULT WINAPI POP3Transport_CommandLIST( 918 IPOP3Transport *iface, POP3CMDTYPE cmdtype, DWORD dwPopId) 919 { 920 static const char list[] = "LIST %u\r\n"; 921 static char list_all[] = "LIST\r\n"; 922 POP3Transport *This = (POP3Transport *)iface; 923 char *command; 924 int len; 925 926 TRACE("(%u, %u)\n", cmdtype, dwPopId); 927 928 if (dwPopId) 929 { 930 len = sizeof(list) + 10 + 2; /* "4294967296" + "\r\n" */ 931 if (!(command = HeapAlloc(GetProcessHeap(), 0, len))) return S_FALSE; 932 sprintf(command, list, dwPopId); 933 } 934 else command = list_all; 935 936 init_parser(This, POP3_LIST); 937 This->type = 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 const 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); 960 This->type = cmdtype; 961 InternetTransport_DoCommand(&This->InetTransport, command, POP3Transport_CallbackRecvTOPResp); 962 963 HeapFree(GetProcessHeap(), 0, command); 964 return S_OK; 965 } 966 967 static HRESULT WINAPI POP3Transport_CommandQUIT(IPOP3Transport *iface) 968 { 969 static const char command[] = "QUIT\r\n"; 970 POP3Transport *This = (POP3Transport *)iface; 971 972 TRACE("()\n"); 973 974 InternetTransport_ChangeStatus(&This->InetTransport, IXP_DISCONNECTING); 975 976 init_parser(This, POP3_QUIT); 977 return InternetTransport_DoCommand(&This->InetTransport, command, POP3Transport_CallbackRecvQUITResp); 978 } 979 980 static HRESULT WINAPI POP3Transport_CommandSTAT(IPOP3Transport *iface) 981 { 982 static const char stat[] = "STAT\r\n"; 983 POP3Transport *This = (POP3Transport *)iface; 984 985 TRACE("\n"); 986 987 init_parser(This, POP3_STAT); 988 InternetTransport_DoCommand(&This->InetTransport, stat, POP3Transport_CallbackRecvSTATResp); 989 return S_OK; 990 } 991 992 static HRESULT WINAPI POP3Transport_CommandNOOP(IPOP3Transport *iface) 993 { 994 static const char noop[] = "NOOP\r\n"; 995 POP3Transport *This = (POP3Transport *)iface; 996 997 TRACE("\n"); 998 999 init_parser(This, POP3_NOOP); 1000 InternetTransport_DoCommand(&This->InetTransport, noop, POP3Transport_CallbackRecvNOOPResp); 1001 return S_OK; 1002 } 1003 1004 static HRESULT WINAPI POP3Transport_CommandRSET(IPOP3Transport *iface) 1005 { 1006 static const char rset[] = "RSET\r\n"; 1007 POP3Transport *This = (POP3Transport *)iface; 1008 1009 TRACE("\n"); 1010 1011 init_parser(This, POP3_RSET); 1012 InternetTransport_DoCommand(&This->InetTransport, rset, POP3Transport_CallbackRecvRSETResp); 1013 return S_OK; 1014 } 1015 1016 static HRESULT WINAPI POP3Transport_CommandUIDL( 1017 IPOP3Transport *iface, POP3CMDTYPE cmdtype, DWORD dwPopId) 1018 { 1019 static const char uidl[] = "UIDL %u\r\n"; 1020 static char uidl_all[] = "UIDL\r\n"; 1021 POP3Transport *This = (POP3Transport *)iface; 1022 char *command; 1023 int len; 1024 1025 TRACE("(%u, %u)\n", cmdtype, dwPopId); 1026 1027 if (dwPopId) 1028 { 1029 len = sizeof(uidl) + 10 + 2; /* "4294967296" + "\r\n" */ 1030 if (!(command = HeapAlloc(GetProcessHeap(), 0, len))) return S_FALSE; 1031 sprintf(command, uidl, dwPopId); 1032 } 1033 else command = uidl_all; 1034 1035 init_parser(This, POP3_UIDL); 1036 This->type = cmdtype; 1037 InternetTransport_DoCommand(&This->InetTransport, command, POP3Transport_CallbackRecvUIDLResp); 1038 1039 if (dwPopId) HeapFree(GetProcessHeap(), 0, command); 1040 return S_OK; 1041 } 1042 1043 static HRESULT WINAPI POP3Transport_CommandDELE( 1044 IPOP3Transport *iface, POP3CMDTYPE cmdtype, DWORD dwPopId) 1045 { 1046 static const char dele[] = "DELE %u\r\n"; 1047 POP3Transport *This = (POP3Transport *)iface; 1048 char *command; 1049 int len; 1050 1051 TRACE("(%u, %u)\n", cmdtype, dwPopId); 1052 1053 len = sizeof(dele) + 10 + 2; /* "4294967296" + "\r\n" */ 1054 if (!(command = HeapAlloc(GetProcessHeap(), 0, len))) return S_FALSE; 1055 sprintf(command, dele, dwPopId); 1056 1057 init_parser(This, POP3_DELE); 1058 This->type = cmdtype; 1059 InternetTransport_DoCommand(&This->InetTransport, command, POP3Transport_CallbackRecvDELEResp); 1060 1061 HeapFree(GetProcessHeap(), 0, command); 1062 return S_OK; 1063 } 1064 1065 static HRESULT WINAPI POP3Transport_CommandRETR( 1066 IPOP3Transport *iface, POP3CMDTYPE cmdtype, DWORD dwPopId) 1067 { 1068 static const char retr[] = "RETR %u\r\n"; 1069 POP3Transport *This = (POP3Transport *)iface; 1070 char *command; 1071 int len; 1072 1073 TRACE("(%u, %u)\n", cmdtype, dwPopId); 1074 1075 len = sizeof(retr) + 10 + 2; /* "4294967296" + "\r\n" */ 1076 if (!(command = HeapAlloc(GetProcessHeap(), 0, len))) return S_FALSE; 1077 sprintf(command, retr, dwPopId); 1078 1079 init_parser(This, POP3_RETR); 1080 This->type = cmdtype; 1081 InternetTransport_DoCommand(&This->InetTransport, command, POP3Transport_CallbackRecvRETRResp); 1082 1083 HeapFree(GetProcessHeap(), 0, command); 1084 return S_OK; 1085 } 1086 1087 static const IPOP3TransportVtbl POP3TransportVtbl = 1088 { 1089 POP3Transport_QueryInterface, 1090 POP3Transport_AddRef, 1091 POP3Transport_Release, 1092 POP3Transport_GetServerInfo, 1093 POP3Transport_GetIXPType, 1094 POP3Transport_IsState, 1095 POP3Transport_InetServerFromAccount, 1096 POP3Transport_Connect, 1097 POP3Transport_HandsOffCallback, 1098 POP3Transport_Disconnect, 1099 POP3Transport_DropConnection, 1100 POP3Transport_GetStatus, 1101 POP3Transport_InitNew, 1102 POP3Transport_MarkItem, 1103 POP3Transport_CommandAUTH, 1104 POP3Transport_CommandUSER, 1105 POP3Transport_CommandPASS, 1106 POP3Transport_CommandLIST, 1107 POP3Transport_CommandTOP, 1108 POP3Transport_CommandQUIT, 1109 POP3Transport_CommandSTAT, 1110 POP3Transport_CommandNOOP, 1111 POP3Transport_CommandRSET, 1112 POP3Transport_CommandUIDL, 1113 POP3Transport_CommandDELE, 1114 POP3Transport_CommandRETR 1115 }; 1116 1117 HRESULT WINAPI CreatePOP3Transport(IPOP3Transport **ppTransport) 1118 { 1119 HRESULT hr; 1120 POP3Transport *This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This)); 1121 if (!This) 1122 return E_OUTOFMEMORY; 1123 1124 This->InetTransport.u.vtblPOP3 = &POP3TransportVtbl; 1125 This->refs = 0; 1126 hr = InternetTransport_Init(&This->InetTransport); 1127 if (FAILED(hr)) 1128 { 1129 HeapFree(GetProcessHeap(), 0, This); 1130 return hr; 1131 } 1132 1133 *ppTransport = (IPOP3Transport *)&This->InetTransport.u.vtblPOP3; 1134 IPOP3Transport_AddRef(*ppTransport); 1135 1136 return S_OK; 1137 } 1138 1139 static HRESULT WINAPI POP3TransportCF_QueryInterface(LPCLASSFACTORY iface, 1140 REFIID riid, LPVOID *ppv) 1141 { 1142 *ppv = NULL; 1143 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IClassFactory)) 1144 { 1145 *ppv = iface; 1146 IClassFactory_AddRef(iface); 1147 return S_OK; 1148 } 1149 return E_NOINTERFACE; 1150 } 1151 1152 static ULONG WINAPI POP3TransportCF_AddRef(LPCLASSFACTORY iface) 1153 { 1154 return 2; /* non-heap based object */ 1155 } 1156 1157 static ULONG WINAPI POP3TransportCF_Release(LPCLASSFACTORY iface) 1158 { 1159 return 1; /* non-heap based object */ 1160 } 1161 1162 static HRESULT WINAPI POP3TransportCF_CreateInstance(LPCLASSFACTORY iface, 1163 LPUNKNOWN pUnk, REFIID riid, LPVOID *ppv) 1164 { 1165 HRESULT hr; 1166 IPOP3Transport *pPop3Transport; 1167 1168 TRACE("(%p, %s, %p)\n", pUnk, debugstr_guid(riid), ppv); 1169 1170 *ppv = NULL; 1171 1172 if (pUnk) 1173 return CLASS_E_NOAGGREGATION; 1174 1175 hr = CreatePOP3Transport(&pPop3Transport); 1176 if (FAILED(hr)) 1177 return hr; 1178 1179 hr = IPOP3Transport_QueryInterface(pPop3Transport, riid, ppv); 1180 IPOP3Transport_Release(pPop3Transport); 1181 1182 return hr; 1183 } 1184 1185 static HRESULT WINAPI POP3TransportCF_LockServer(LPCLASSFACTORY iface, BOOL fLock) 1186 { 1187 FIXME("(%d)\n",fLock); 1188 return S_OK; 1189 } 1190 1191 static const IClassFactoryVtbl POP3TransportCFVtbl = 1192 { 1193 POP3TransportCF_QueryInterface, 1194 POP3TransportCF_AddRef, 1195 POP3TransportCF_Release, 1196 POP3TransportCF_CreateInstance, 1197 POP3TransportCF_LockServer 1198 }; 1199 static const IClassFactoryVtbl *POP3TransportCF = &POP3TransportCFVtbl; 1200 1201 HRESULT POP3TransportCF_Create(REFIID riid, LPVOID *ppv) 1202 { 1203 return IClassFactory_QueryInterface((IClassFactory *)&POP3TransportCF, riid, ppv); 1204 } 1205