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