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