inetcomm: Add an implementation of IPOP3Transport::CommandRSET.
[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
23 #include <stdarg.h>
24 #include <stdio.h>
25
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winnt.h"
29 #include "winuser.h"
30 #include "objbase.h"
31 #include "mimeole.h"
32 #include "wine/debug.h"
33
34 #include "inetcomm_private.h"
35
36 WINE_DEFAULT_DEBUG_CHANNEL(inetcomm);
37
38 enum parse_state
39 {
40     STATE_NONE,
41     STATE_OK,
42     STATE_MULTILINE,
43     STATE_DONE
44 };
45
46 typedef struct
47 {
48     InternetTransport InetTransport;
49     ULONG refs;
50     INETSERVER server;
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->rUidlInfo); break;
355         case POP3_STAT: hr = parse_stat_response(This, &pResponse->rStatInfo); break;
356         case POP3_LIST: hr = parse_list_response(This, &pResponse->rListInfo); break;
357         case POP3_DELE: hr = parse_dele_response(This, &pResponse->dwPopId); break;
358         case POP3_RETR: hr = parse_retr_response(This, &pResponse->rRetrInfo); break;
359         case POP3_TOP: hr = parse_top_response(This, &pResponse->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_CallbackProcessLISTResp(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
481 static void POP3Transport_CallbackRecvLISTResp(IInternetTransport *iface, char *pBuffer, int cbBuffer)
482 {
483     POP3Transport *This = (POP3Transport *)iface;
484
485     TRACE("\n");
486     InternetTransport_ReadLine(&This->InetTransport, POP3Transport_CallbackProcessLISTResp);
487 }
488
489 static void POP3Transport_CallbackProcessUIDLResp(IInternetTransport *iface, char *pBuffer, int cbBuffer)
490 {
491     POP3Transport *This = (POP3Transport *)iface;
492     POP3RESPONSE response;
493     HRESULT hr;
494
495     TRACE("\n");
496
497     hr = POP3Transport_ParseResponse(This, pBuffer, &response);
498     if (FAILED(hr))
499     {
500         /* FIXME: handle error */
501         return;
502     }
503
504     IPOP3Callback_OnResponse((IPOP3Callback *)This->InetTransport.pCallback, &response);
505 }
506
507 static void POP3Transport_CallbackRecvUIDLResp(IInternetTransport *iface, char *pBuffer, int cbBuffer)
508 {
509     POP3Transport *This = (POP3Transport *)iface;
510
511     TRACE("\n");
512     InternetTransport_ReadLine(&This->InetTransport, POP3Transport_CallbackProcessUIDLResp);
513 }
514
515 static void POP3Transport_CallbackProcessSTATResp(IInternetTransport *iface, char *pBuffer, int cbBuffer)
516 {
517     POP3Transport *This = (POP3Transport *)iface;
518     POP3RESPONSE response;
519     HRESULT hr;
520
521     TRACE("\n");
522
523     hr = POP3Transport_ParseResponse(This, pBuffer, &response);
524     if (FAILED(hr))
525     {
526         /* FIXME: handle error */
527         return;
528     }
529
530     IPOP3Callback_OnResponse((IPOP3Callback *)This->InetTransport.pCallback, &response);
531 }
532
533 static void POP3Transport_CallbackRecvSTATResp(IInternetTransport *iface, char *pBuffer, int cbBuffer)
534 {
535     POP3Transport *This = (POP3Transport *)iface;
536
537     TRACE("\n");
538     InternetTransport_ReadLine(&This->InetTransport, POP3Transport_CallbackProcessSTATResp);
539 }
540
541 static void POP3Transport_CallbackProcessPASSResp(IInternetTransport *iface, char *pBuffer, int cbBuffer)
542 {
543     POP3Transport *This = (POP3Transport *)iface;
544     POP3RESPONSE response;
545     HRESULT hr;
546
547     TRACE("\n");
548
549     hr = POP3Transport_ParseResponse(This, pBuffer, &response);
550     if (FAILED(hr))
551     {
552         /* FIXME: handle error */
553         return;
554     }
555
556     InternetTransport_ChangeStatus(&This->InetTransport, IXP_AUTHORIZED);
557     InternetTransport_ChangeStatus(&This->InetTransport, IXP_CONNECTED);
558
559     IPOP3Callback_OnResponse((IPOP3Callback *)This->InetTransport.pCallback, &response);
560 }
561
562 static void POP3Transport_CallbackRecvPASSResp(IInternetTransport *iface, char *pBuffer, int cbBuffer)
563 {
564     POP3Transport *This = (POP3Transport *)iface;
565
566     TRACE("\n");
567     InternetTransport_ReadLine(&This->InetTransport, POP3Transport_CallbackProcessPASSResp);
568 }
569
570 static void POP3Transport_CallbackProcessUSERResp(IInternetTransport *iface, char *pBuffer, int cbBuffer)
571 {
572     static char pass[] = "PASS ";
573     POP3Transport *This = (POP3Transport *)iface;
574     POP3RESPONSE response;
575     char *command;
576     int len;
577     HRESULT hr;
578
579     TRACE("\n");
580
581     hr = POP3Transport_ParseResponse(This, pBuffer, &response);
582     if (FAILED(hr))
583     {
584         /* FIXME: handle error */
585         return;
586     }
587
588     IPOP3Callback_OnResponse((IPOP3Callback *)This->InetTransport.pCallback, &response);
589
590     len = sizeof(pass) + strlen(This->server.szPassword) + 2; /* "\r\n" */
591     command = HeapAlloc(GetProcessHeap(), 0, len);
592
593     strcpy(command, pass);
594     strcat(command, This->server.szPassword);
595     strcat(command, "\r\n");
596
597     init_parser(This, POP3_PASS, POP3_NONE);
598
599     InternetTransport_DoCommand(&This->InetTransport, command, POP3Transport_CallbackRecvPASSResp);
600     HeapFree(GetProcessHeap(), 0, command);
601 }
602
603 static void POP3Transport_CallbackRecvUSERResp(IInternetTransport *iface, char *pBuffer, int cbBuffer)
604 {
605     POP3Transport *This = (POP3Transport *)iface;
606
607     TRACE("\n");
608     InternetTransport_ReadLine(&This->InetTransport, POP3Transport_CallbackProcessUSERResp);
609 }
610
611 static void POP3Transport_CallbackSendUSERCmd(IInternetTransport *iface, char *pBuffer, int cbBuffer)
612 {
613     static char user[] = "USER ";
614     POP3Transport *This = (POP3Transport *)iface;
615     char *command;
616     int len;
617
618     TRACE("\n");
619
620     len = sizeof(user) + strlen(This->server.szUserName) + 2; /* "\r\n" */
621     command = HeapAlloc(GetProcessHeap(), 0, len);
622
623     strcpy(command, user);
624     strcat(command, This->server.szUserName);
625     strcat(command, "\r\n");
626     InternetTransport_DoCommand(&This->InetTransport, command, POP3Transport_CallbackRecvUSERResp);
627
628     HeapFree(GetProcessHeap(), 0, command);
629 }
630
631 static void POP3Transport_CallbackProcessQUITResponse(IInternetTransport *iface, char *pBuffer, int cbBuffer)
632 {
633     POP3Transport *This = (POP3Transport *)iface;
634     POP3RESPONSE response;
635     HRESULT hr;
636
637     TRACE("%s\n", debugstr_an(pBuffer, cbBuffer));
638
639     hr = POP3Transport_ParseResponse(This, pBuffer, &response);
640     if (FAILED(hr))
641     {
642         /* FIXME: handle error */
643         return;
644     }
645
646     IPOP3Callback_OnResponse((IPOP3Callback *)This->InetTransport.pCallback, &response);
647     InternetTransport_DropConnection(&This->InetTransport);
648 }
649
650 static void POP3Transport_CallbackRecvQUITResp(IInternetTransport *iface, char *pBuffer, int cbBuffer)
651 {
652     POP3Transport *This = (POP3Transport *)iface;
653
654     TRACE("\n");
655     InternetTransport_ReadLine(&This->InetTransport, POP3Transport_CallbackProcessQUITResponse);
656 }
657
658 static HRESULT WINAPI POP3Transport_QueryInterface(IPOP3Transport *iface, REFIID riid, void **ppv)
659 {
660     TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
661
662     if (IsEqualIID(riid, &IID_IUnknown) ||
663         IsEqualIID(riid, &IID_IInternetTransport) ||
664         IsEqualIID(riid, &IID_IPOP3Transport))
665     {
666         *ppv = iface;
667         IUnknown_AddRef(iface);
668         return S_OK;
669     }
670     *ppv = NULL;
671     FIXME("no interface for %s\n", debugstr_guid(riid));
672     return E_NOINTERFACE;
673 }
674
675 static ULONG WINAPI POP3Transport_AddRef(IPOP3Transport *iface)
676 {
677     POP3Transport *This = (POP3Transport *)iface;
678     return InterlockedIncrement((LONG *)&This->refs);
679 }
680
681 static ULONG WINAPI POP3Transport_Release(IPOP3Transport *iface)
682 {
683     POP3Transport *This = (POP3Transport *)iface;
684     ULONG refs = InterlockedDecrement((LONG *)&This->refs);
685     if (!refs)
686     {
687         TRACE("destroying %p\n", This);
688         if (This->InetTransport.Status != IXP_DISCONNECTED)
689             InternetTransport_DropConnection(&This->InetTransport);
690         if (This->InetTransport.pCallback) ITransportCallback_Release(This->InetTransport.pCallback);
691         HeapFree(GetProcessHeap(), 0, This);
692     }
693     return refs;
694 }
695
696 static HRESULT WINAPI POP3Transport_GetServerInfo(IPOP3Transport *iface,
697     LPINETSERVER pInetServer)
698 {
699     POP3Transport *This = (POP3Transport *)iface;
700
701     TRACE("(%p)\n", pInetServer);
702     return InternetTransport_GetServerInfo(&This->InetTransport, pInetServer);
703 }
704
705 static IXPTYPE WINAPI POP3Transport_GetIXPType(IPOP3Transport *iface)
706 {
707     TRACE("()\n");
708     return IXP_POP3;
709 }
710
711 static HRESULT WINAPI POP3Transport_IsState(IPOP3Transport *iface, IXPISSTATE isstate)
712 {
713     FIXME("(%u)\n", isstate);
714     return E_NOTIMPL;
715 }
716
717 static HRESULT WINAPI POP3Transport_InetServerFromAccount(
718     IPOP3Transport *iface, IImnAccount *pAccount, LPINETSERVER pInetServer)
719 {
720     POP3Transport *This = (POP3Transport *)iface;
721
722     TRACE("(%p, %p)\n", pAccount, pInetServer);
723     return InternetTransport_InetServerFromAccount(&This->InetTransport, pAccount, pInetServer);
724 }
725
726 static HRESULT WINAPI POP3Transport_Connect(IPOP3Transport *iface,
727     LPINETSERVER pInetServer, boolean fAuthenticate, boolean fCommandLogging)
728 {
729     POP3Transport *This = (POP3Transport *)iface;
730     HRESULT hr;
731
732     TRACE("(%p, %s, %s)\n", pInetServer, fAuthenticate ? "TRUE" : "FALSE", fCommandLogging ? "TRUE" : "FALSE");
733
734     hr = InternetTransport_Connect(&This->InetTransport, pInetServer, fAuthenticate, fCommandLogging);
735     if (FAILED(hr))
736         return hr;
737
738     init_parser(This, POP3_USER, POP3_NONE);
739
740     This->server = *pInetServer;
741     return InternetTransport_ReadLine(&This->InetTransport, POP3Transport_CallbackSendUSERCmd);
742 }
743
744 static HRESULT WINAPI POP3Transport_HandsOffCallback(IPOP3Transport *iface)
745 {
746     POP3Transport *This = (POP3Transport *)iface;
747
748     TRACE("()\n");
749     return InternetTransport_HandsOffCallback(&This->InetTransport);
750 }
751
752 static HRESULT WINAPI POP3Transport_Disconnect(IPOP3Transport *iface)
753 {
754     TRACE("()\n");
755     return IPOP3Transport_CommandQUIT(iface);
756 }
757
758 static HRESULT WINAPI POP3Transport_DropConnection(IPOP3Transport *iface)
759 {
760     POP3Transport *This = (POP3Transport *)iface;
761
762     TRACE("()\n");
763     return InternetTransport_DropConnection(&This->InetTransport);
764 }
765
766 static HRESULT WINAPI POP3Transport_GetStatus(IPOP3Transport *iface,
767     IXPSTATUS *pCurrentStatus)
768 {
769     POP3Transport *This = (POP3Transport *)iface;
770
771     TRACE("()\n");
772     return InternetTransport_GetStatus(&This->InetTransport, pCurrentStatus);
773 }
774
775 static HRESULT WINAPI POP3Transport_InitNew(IPOP3Transport *iface,
776     LPSTR pszLogFilePath, IPOP3Callback *pCallback)
777 {
778     POP3Transport *This = (POP3Transport *)iface;
779
780     TRACE("(%s, %p)\n", debugstr_a(pszLogFilePath), pCallback);
781
782     if (!pCallback)
783         return E_INVALIDARG;
784
785     if (pszLogFilePath)
786         FIXME("not using log file of %s, use Wine debug logging instead\n",
787             debugstr_a(pszLogFilePath));
788
789     IPOP3Callback_AddRef(pCallback);
790     This->InetTransport.pCallback = (ITransportCallback *)pCallback;
791     This->InetTransport.fInitialised = TRUE;
792
793     return S_OK;
794 }
795
796 static HRESULT WINAPI POP3Transport_MarkItem(IPOP3Transport *iface, POP3MARKTYPE marktype,
797     DWORD dwPopId, boolean fMarked)
798 {
799     FIXME("(%u, %u, %d)\n", marktype, dwPopId, fMarked);
800     return E_NOTIMPL;
801 }
802
803 static HRESULT WINAPI POP3Transport_CommandAUTH(IPOP3Transport *iface, LPSTR pszAuthType)
804 {
805     FIXME("(%s)\n", pszAuthType);
806     return E_NOTIMPL;
807 }
808
809 static HRESULT WINAPI POP3Transport_CommandUSER(IPOP3Transport *iface, LPSTR username)
810 {
811     static char user[] = "USER ";
812     POP3Transport *This = (POP3Transport *)iface;
813     char *command;
814     int len;
815
816     TRACE("(%s)\n", username);
817
818     len = sizeof(user) + strlen(username) + 2; /* "\r\n" */
819     command = HeapAlloc(GetProcessHeap(), 0, len);
820
821     strcpy(command, user);
822     strcat(command, username);
823     strcat(command, "\r\n");
824
825     init_parser(This, POP3_USER, POP3_NONE);
826     InternetTransport_DoCommand(&This->InetTransport, command, POP3Transport_CallbackRecvUSERResp);
827
828     HeapFree(GetProcessHeap(), 0, command);
829     return S_OK;
830 }
831
832 static HRESULT WINAPI POP3Transport_CommandPASS(IPOP3Transport *iface, LPSTR password)
833 {
834     static char pass[] = "PASS ";
835     POP3Transport *This = (POP3Transport *)iface;
836     char *command;
837     int len;
838
839     TRACE("(%p)\n", password);
840
841     len = sizeof(pass) + strlen(password) + 2; /* "\r\n" */
842     command = HeapAlloc(GetProcessHeap(), 0, len);
843
844     strcpy(command, pass);
845     strcat(command, password);
846     strcat(command, "\r\n");
847
848     init_parser(This, POP3_PASS, POP3_NONE);
849     InternetTransport_DoCommand(&This->InetTransport, command, POP3Transport_CallbackRecvPASSResp);
850
851     HeapFree(GetProcessHeap(), 0, command);
852     return S_OK;
853 }
854
855 static HRESULT WINAPI POP3Transport_CommandLIST(
856     IPOP3Transport *iface, POP3CMDTYPE cmdtype, DWORD dwPopId)
857 {
858     static char list[] = "LIST\r\n";
859     POP3Transport *This = (POP3Transport *)iface;
860
861     TRACE("(%u, %u)\n", cmdtype, dwPopId);
862
863     init_parser(This, POP3_LIST, cmdtype);
864     InternetTransport_DoCommand(&This->InetTransport, list, POP3Transport_CallbackRecvLISTResp);
865     return S_OK;
866 }
867
868 static HRESULT WINAPI POP3Transport_CommandTOP(
869     IPOP3Transport *iface, POP3CMDTYPE cmdtype, DWORD dwPopId, DWORD cPreviewLines)
870 {
871     FIXME("(%u, %u, %u)\n", cmdtype, dwPopId, cPreviewLines);
872     return E_NOTIMPL;
873 }
874
875 static HRESULT WINAPI POP3Transport_CommandQUIT(IPOP3Transport *iface)
876 {
877     static char command[] = "QUIT\r\n";
878     POP3Transport *This = (POP3Transport *)iface;
879
880     TRACE("()\n");
881
882     init_parser(This, POP3_QUIT, POP3_NONE);
883     return InternetTransport_DoCommand(&This->InetTransport, command, POP3Transport_CallbackRecvQUITResp);
884 }
885
886 static HRESULT WINAPI POP3Transport_CommandSTAT(IPOP3Transport *iface)
887 {
888     static char stat[] = "STAT\r\n";
889     POP3Transport *This = (POP3Transport *)iface;
890
891     TRACE("\n");
892
893     init_parser(This, POP3_STAT, POP3_NONE);
894     InternetTransport_DoCommand(&This->InetTransport, stat, POP3Transport_CallbackRecvSTATResp);
895     return S_OK;
896 }
897
898 static HRESULT WINAPI POP3Transport_CommandNOOP(IPOP3Transport *iface)
899 {
900     static char noop[] = "NOOP\r\n";
901     POP3Transport *This = (POP3Transport *)iface;
902
903     TRACE("\n");
904
905     init_parser(This, POP3_NOOP, POP3_NONE);
906     InternetTransport_DoCommand(&This->InetTransport, noop, POP3Transport_CallbackRecvNOOPResp);
907     return S_OK;
908 }
909
910 static HRESULT WINAPI POP3Transport_CommandRSET(IPOP3Transport *iface)
911 {
912     static char rset[] = "RSET\r\n";
913     POP3Transport *This = (POP3Transport *)iface;
914
915     TRACE("\n");
916
917     init_parser(This, POP3_RSET, POP3_NONE);
918     InternetTransport_DoCommand(&This->InetTransport, rset, POP3Transport_CallbackRecvRSETResp);
919     return S_OK;
920 }
921
922 static HRESULT WINAPI POP3Transport_CommandUIDL(
923     IPOP3Transport *iface, POP3CMDTYPE cmdtype, DWORD dwPopId)
924 {
925     static char uidl[] = "UIDL\r\n";
926     POP3Transport *This = (POP3Transport *)iface;
927
928     TRACE("(%u, %u)\n", cmdtype, dwPopId);
929
930     init_parser(This, POP3_UIDL, cmdtype);
931     InternetTransport_DoCommand(&This->InetTransport, uidl, POP3Transport_CallbackRecvUIDLResp);
932     return S_OK;
933 }
934
935 static HRESULT WINAPI POP3Transport_CommandDELE(
936     IPOP3Transport *iface, POP3CMDTYPE cmdtype, DWORD dwPopId)
937 {
938     static char dele[] = "DELE %u\r\n";
939     POP3Transport *This = (POP3Transport *)iface;
940     char *command;
941     int len;
942
943     TRACE("(%u, %u)\n", cmdtype, dwPopId);
944
945     len = sizeof(dele) + 10 + 2; /* "4294967296" + "\r\n" */
946     if (!(command = HeapAlloc(GetProcessHeap(), 0, len))) return S_FALSE;
947     sprintf(command, dele, dwPopId);
948
949     init_parser(This, POP3_DELE, cmdtype);
950     InternetTransport_DoCommand(&This->InetTransport, command, POP3Transport_CallbackRecvDELEResp);
951
952     HeapFree(GetProcessHeap(), 0, command);
953     return S_OK;
954 }
955
956 static HRESULT WINAPI POP3Transport_CommandRETR(
957     IPOP3Transport *iface, POP3CMDTYPE cmdtype, DWORD dwPopId)
958 {
959     FIXME("(%u, %u)\n", cmdtype, dwPopId);
960     return E_NOTIMPL;
961 }
962
963 static const IPOP3TransportVtbl POP3TransportVtbl =
964 {
965     POP3Transport_QueryInterface,
966     POP3Transport_AddRef,
967     POP3Transport_Release,
968     POP3Transport_GetServerInfo,
969     POP3Transport_GetIXPType,
970     POP3Transport_IsState,
971     POP3Transport_InetServerFromAccount,
972     POP3Transport_Connect,
973     POP3Transport_HandsOffCallback,
974     POP3Transport_Disconnect,
975     POP3Transport_DropConnection,
976     POP3Transport_GetStatus,
977     POP3Transport_InitNew,
978     POP3Transport_MarkItem,
979     POP3Transport_CommandAUTH,
980     POP3Transport_CommandUSER,
981     POP3Transport_CommandPASS,
982     POP3Transport_CommandLIST,
983     POP3Transport_CommandTOP,
984     POP3Transport_CommandQUIT,
985     POP3Transport_CommandSTAT,
986     POP3Transport_CommandNOOP,
987     POP3Transport_CommandRSET,
988     POP3Transport_CommandUIDL,
989     POP3Transport_CommandDELE,
990     POP3Transport_CommandRETR
991 };
992
993 HRESULT WINAPI CreatePOP3Transport(IPOP3Transport **ppTransport)
994 {
995     HRESULT hr;
996     POP3Transport *This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
997     if (!This)
998         return E_OUTOFMEMORY;
999
1000     This->InetTransport.u.vtblPOP3 = &POP3TransportVtbl;
1001     This->refs = 0;
1002     hr = InternetTransport_Init(&This->InetTransport);
1003     if (FAILED(hr))
1004     {
1005         HeapFree(GetProcessHeap(), 0, This);
1006         return hr;
1007     }
1008
1009     *ppTransport = (IPOP3Transport *)&This->InetTransport.u.vtblPOP3;
1010     IPOP3Transport_AddRef(*ppTransport);
1011
1012     return S_OK;
1013 }
1014
1015 static HRESULT WINAPI POP3TransportCF_QueryInterface(LPCLASSFACTORY iface,
1016     REFIID riid, LPVOID *ppv)
1017 {
1018     *ppv = NULL;
1019     if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IClassFactory))
1020     {
1021         *ppv = iface;
1022         IUnknown_AddRef(iface);
1023         return S_OK;
1024     }
1025     return E_NOINTERFACE;
1026 }
1027
1028 static ULONG WINAPI POP3TransportCF_AddRef(LPCLASSFACTORY iface)
1029 {
1030     return 2; /* non-heap based object */
1031 }
1032
1033 static ULONG WINAPI POP3TransportCF_Release(LPCLASSFACTORY iface)
1034 {
1035     return 1; /* non-heap based object */
1036 }
1037
1038 static HRESULT WINAPI POP3TransportCF_CreateInstance(LPCLASSFACTORY iface,
1039     LPUNKNOWN pUnk, REFIID riid, LPVOID *ppv)
1040 {
1041     HRESULT hr;
1042     IPOP3Transport *pPop3Transport;
1043
1044     TRACE("(%p, %s, %p)\n", pUnk, debugstr_guid(riid), ppv);
1045
1046     *ppv = NULL;
1047
1048     if (pUnk)
1049         return CLASS_E_NOAGGREGATION;
1050
1051     hr = CreatePOP3Transport(&pPop3Transport);
1052     if (FAILED(hr))
1053         return hr;
1054
1055     hr = IPOP3Transport_QueryInterface(pPop3Transport, riid, ppv);
1056     IPOP3Transport_Release(pPop3Transport);
1057
1058     return hr;
1059 }
1060
1061 static HRESULT WINAPI POP3TransportCF_LockServer(LPCLASSFACTORY iface, BOOL fLock)
1062 {
1063     FIXME("(%d)\n",fLock);
1064     return S_OK;
1065 }
1066
1067 static const IClassFactoryVtbl POP3TransportCFVtbl =
1068 {
1069     POP3TransportCF_QueryInterface,
1070     POP3TransportCF_AddRef,
1071     POP3TransportCF_Release,
1072     POP3TransportCF_CreateInstance,
1073     POP3TransportCF_LockServer
1074 };
1075 static const IClassFactoryVtbl *POP3TransportCF = &POP3TransportCFVtbl;
1076
1077 HRESULT POP3TransportCF_Create(REFIID riid, LPVOID *ppv)
1078 {
1079     return IClassFactory_QueryInterface((IClassFactory *)&POP3TransportCF, riid, ppv);
1080 }