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