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