inetcomm: Implement IPOP3Transport::Disconnect.
[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 typedef struct
39 {
40     InternetTransport InetTransport;
41     ULONG refs;
42     INETSERVER server;
43     POP3COMMAND command;
44 } POP3Transport;
45
46 static HRESULT POP3Transport_ParseResponse(POP3Transport *This, char *pszResponse, POP3RESPONSE *pResponse)
47 {
48     TRACE("response: %s\n", debugstr_a(pszResponse));
49
50     pResponse->command = This->command;
51     pResponse->fDone = TRUE; /* FIXME */
52
53     if (!memcmp(pszResponse, "+OK", 3))
54         pResponse->rIxpResult.hrResult = S_OK;
55     else
56         pResponse->rIxpResult.hrResult = S_FALSE;
57
58     pResponse->rIxpResult.pszResponse = pszResponse;
59     pResponse->rIxpResult.uiServerError = 0;
60     pResponse->rIxpResult.hrServerError = pResponse->rIxpResult.hrResult;
61     pResponse->rIxpResult.dwSocketError = 0;
62     pResponse->pTransport = (IPOP3Transport *)&This->InetTransport.u.vtblPOP3;
63     pResponse->fValidInfo = FALSE; /* FIXME */
64
65     if (This->InetTransport.pCallback && This->InetTransport.fCommandLogging)
66     {
67         ITransportCallback_OnCommand(This->InetTransport.pCallback, CMD_RESP,
68             pResponse->rIxpResult.pszResponse, pResponse->rIxpResult.hrServerError,
69             (IInternetTransport *)&This->InetTransport.u.vtbl);
70     }
71     return S_OK;
72 }
73
74 static void POP3Transport_CallbackProcessLISTResp(IInternetTransport *iface, char *pBuffer, int cbBuffer)
75 {
76     POP3Transport *This = (POP3Transport *)iface;
77     POP3RESPONSE response;
78     HRESULT hr;
79
80     TRACE("\n");
81
82     hr = POP3Transport_ParseResponse(This, pBuffer, &response);
83     if (FAILED(hr))
84     {
85         /* FIXME: handle error */
86         return;
87     }
88
89     IPOP3Callback_OnResponse((IPOP3Callback *)This->InetTransport.pCallback, &response);
90 }
91
92 static void POP3Transport_CallbackRecvLISTResp(IInternetTransport *iface, char *pBuffer, int cbBuffer)
93 {
94     POP3Transport *This = (POP3Transport *)iface;
95
96     TRACE("\n");
97     InternetTransport_ReadLine(&This->InetTransport, POP3Transport_CallbackProcessLISTResp);
98 }
99
100 static void POP3Transport_CallbackProcessUIDLResp(IInternetTransport *iface, char *pBuffer, int cbBuffer)
101 {
102     POP3Transport *This = (POP3Transport *)iface;
103     POP3RESPONSE response;
104     HRESULT hr;
105
106     TRACE("\n");
107
108     hr = POP3Transport_ParseResponse(This, pBuffer, &response);
109     if (FAILED(hr))
110     {
111         /* FIXME: handle error */
112         return;
113     }
114
115     IPOP3Callback_OnResponse((IPOP3Callback *)This->InetTransport.pCallback, &response);
116 }
117
118 static void POP3Transport_CallbackRecvUIDLResp(IInternetTransport *iface, char *pBuffer, int cbBuffer)
119 {
120     POP3Transport *This = (POP3Transport *)iface;
121
122     TRACE("\n");
123     InternetTransport_ReadLine(&This->InetTransport, POP3Transport_CallbackProcessUIDLResp);
124 }
125
126 static void POP3Transport_CallbackProcessSTATResp(IInternetTransport *iface, char *pBuffer, int cbBuffer)
127 {
128     POP3Transport *This = (POP3Transport *)iface;
129     POP3RESPONSE response;
130     HRESULT hr;
131
132     TRACE("\n");
133
134     hr = POP3Transport_ParseResponse(This, pBuffer, &response);
135     if (FAILED(hr))
136     {
137         /* FIXME: handle error */
138         return;
139     }
140
141     IPOP3Callback_OnResponse((IPOP3Callback *)This->InetTransport.pCallback, &response);
142 }
143
144 static void POP3Transport_CallbackRecvSTATResp(IInternetTransport *iface, char *pBuffer, int cbBuffer)
145 {
146     POP3Transport *This = (POP3Transport *)iface;
147
148     TRACE("\n");
149     InternetTransport_ReadLine(&This->InetTransport, POP3Transport_CallbackProcessSTATResp);
150 }
151
152 static void POP3Transport_CallbackProcessPASSResp(IInternetTransport *iface, char *pBuffer, int cbBuffer)
153 {
154     POP3Transport *This = (POP3Transport *)iface;
155     POP3RESPONSE response;
156     HRESULT hr;
157
158     TRACE("\n");
159
160     hr = POP3Transport_ParseResponse(This, pBuffer, &response);
161     if (FAILED(hr))
162     {
163         /* FIXME: handle error */
164         return;
165     }
166
167     InternetTransport_ChangeStatus(&This->InetTransport, IXP_AUTHORIZED);
168     InternetTransport_ChangeStatus(&This->InetTransport, IXP_CONNECTED);
169
170     IPOP3Callback_OnResponse((IPOP3Callback *)This->InetTransport.pCallback, &response);
171 }
172
173 static void POP3Transport_CallbackRecvPASSResp(IInternetTransport *iface, char *pBuffer, int cbBuffer)
174 {
175     POP3Transport *This = (POP3Transport *)iface;
176
177     TRACE("\n");
178     InternetTransport_ReadLine(&This->InetTransport, POP3Transport_CallbackProcessPASSResp);
179 }
180
181 static void POP3Transport_CallbackProcessUSERResp(IInternetTransport *iface, char *pBuffer, int cbBuffer)
182 {
183     static char pass[] = "PASS ";
184     POP3Transport *This = (POP3Transport *)iface;
185     POP3RESPONSE response;
186     char *command;
187     int len;
188     HRESULT hr;
189
190     TRACE("\n");
191
192     hr = POP3Transport_ParseResponse(This, pBuffer, &response);
193     if (FAILED(hr))
194     {
195         /* FIXME: handle error */
196         return;
197     }
198
199     IPOP3Callback_OnResponse((IPOP3Callback *)This->InetTransport.pCallback, &response);
200
201     len = sizeof(pass) + strlen(This->server.szPassword) + 2; /* "\r\n" */
202     command = HeapAlloc(GetProcessHeap(), 0, len);
203
204     strcpy(command, pass);
205     strcat(command, This->server.szPassword);
206     strcat(command, "\r\n");
207
208     InternetTransport_DoCommand(&This->InetTransport, command, POP3Transport_CallbackRecvPASSResp);
209     HeapFree(GetProcessHeap(), 0, command);
210 }
211
212 static void POP3Transport_CallbackRecvUSERResp(IInternetTransport *iface, char *pBuffer, int cbBuffer)
213 {
214     POP3Transport *This = (POP3Transport *)iface;
215
216     TRACE("\n");
217     InternetTransport_ReadLine(&This->InetTransport, POP3Transport_CallbackProcessUSERResp);
218 }
219
220 static void POP3Transport_CallbackSendUSERCmd(IInternetTransport *iface, char *pBuffer, int cbBuffer)
221 {
222     static char user[] = "USER ";
223     POP3Transport *This = (POP3Transport *)iface;
224     char *command;
225     int len;
226
227     TRACE("\n");
228
229     len = sizeof(user) + strlen(This->server.szUserName) + 2; /* "\r\n" */
230     command = HeapAlloc(GetProcessHeap(), 0, len);
231
232     strcpy(command, user);
233     strcat(command, This->server.szUserName);
234     strcat(command, "\r\n");
235     InternetTransport_DoCommand(&This->InetTransport, command, POP3Transport_CallbackRecvUSERResp);
236
237     HeapFree(GetProcessHeap(), 0, command);
238 }
239
240 static void POP3Transport_CallbackProcessQUITResponse(IInternetTransport *iface, char *pBuffer, int cbBuffer)
241 {
242     POP3Transport *This = (POP3Transport *)iface;
243     POP3RESPONSE response;
244     HRESULT hr;
245
246     TRACE("%s\n", debugstr_an(pBuffer, cbBuffer));
247
248     hr = POP3Transport_ParseResponse(This, pBuffer, &response);
249     if (FAILED(hr))
250     {
251         /* FIXME: handle error */
252         return;
253     }
254
255     IPOP3Callback_OnResponse((IPOP3Callback *)This->InetTransport.pCallback, &response);
256     InternetTransport_DropConnection(&This->InetTransport);
257 }
258
259 static void POP3Transport_CallbackRecvQUITResp(IInternetTransport *iface, char *pBuffer, int cbBuffer)
260 {
261     POP3Transport *This = (POP3Transport *)iface;
262
263     TRACE("\n");
264     InternetTransport_ReadLine(&This->InetTransport, POP3Transport_CallbackProcessQUITResponse);
265 }
266
267 static HRESULT WINAPI POP3Transport_QueryInterface(IPOP3Transport *iface, REFIID riid, void **ppv)
268 {
269     TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
270
271     if (IsEqualIID(riid, &IID_IUnknown) ||
272         IsEqualIID(riid, &IID_IInternetTransport) ||
273         IsEqualIID(riid, &IID_IPOP3Transport))
274     {
275         *ppv = iface;
276         IUnknown_AddRef(iface);
277         return S_OK;
278     }
279     *ppv = NULL;
280     FIXME("no interface for %s\n", debugstr_guid(riid));
281     return E_NOINTERFACE;
282 }
283
284 static ULONG WINAPI POP3Transport_AddRef(IPOP3Transport *iface)
285 {
286     POP3Transport *This = (POP3Transport *)iface;
287     return InterlockedIncrement((LONG *)&This->refs);
288 }
289
290 static ULONG WINAPI POP3Transport_Release(IPOP3Transport *iface)
291 {
292     POP3Transport *This = (POP3Transport *)iface;
293     ULONG refs = InterlockedDecrement((LONG *)&This->refs);
294     if (!refs)
295     {
296         TRACE("destroying %p\n", This);
297         if (This->InetTransport.Status != IXP_DISCONNECTED)
298             InternetTransport_DropConnection(&This->InetTransport);
299         if (This->InetTransport.pCallback) ITransportCallback_Release(This->InetTransport.pCallback);
300         HeapFree(GetProcessHeap(), 0, This);
301     }
302     return refs;
303 }
304
305 static HRESULT WINAPI POP3Transport_GetServerInfo(IPOP3Transport *iface,
306     LPINETSERVER pInetServer)
307 {
308     POP3Transport *This = (POP3Transport *)iface;
309
310     TRACE("(%p)\n", pInetServer);
311     return InternetTransport_GetServerInfo(&This->InetTransport, pInetServer);
312 }
313
314 static IXPTYPE WINAPI POP3Transport_GetIXPType(IPOP3Transport *iface)
315 {
316     TRACE("()\n");
317     return IXP_POP3;
318 }
319
320 static HRESULT WINAPI POP3Transport_IsState(IPOP3Transport *iface, IXPISSTATE isstate)
321 {
322     FIXME("(%u)\n", isstate);
323     return E_NOTIMPL;
324 }
325
326 static HRESULT WINAPI POP3Transport_InetServerFromAccount(
327     IPOP3Transport *iface, IImnAccount *pAccount, LPINETSERVER pInetServer)
328 {
329     POP3Transport *This = (POP3Transport *)iface;
330
331     TRACE("(%p, %p)\n", pAccount, pInetServer);
332     return InternetTransport_InetServerFromAccount(&This->InetTransport, pAccount, pInetServer);
333 }
334
335 static HRESULT WINAPI POP3Transport_Connect(IPOP3Transport *iface,
336     LPINETSERVER pInetServer, boolean fAuthenticate, boolean fCommandLogging)
337 {
338     POP3Transport *This = (POP3Transport *)iface;
339     HRESULT hr;
340
341     TRACE("(%p, %s, %s)\n", pInetServer, fAuthenticate ? "TRUE" : "FALSE", fCommandLogging ? "TRUE" : "FALSE");
342
343     hr = InternetTransport_Connect(&This->InetTransport, pInetServer, fAuthenticate, fCommandLogging);
344     if (FAILED(hr))
345         return hr;
346
347     This->command = POP3_USER;
348     This->server = *pInetServer;
349     return InternetTransport_ReadLine(&This->InetTransport, POP3Transport_CallbackSendUSERCmd);
350 }
351
352 static HRESULT WINAPI POP3Transport_HandsOffCallback(IPOP3Transport *iface)
353 {
354     POP3Transport *This = (POP3Transport *)iface;
355
356     TRACE("()\n");
357     return InternetTransport_HandsOffCallback(&This->InetTransport);
358 }
359
360 static HRESULT WINAPI POP3Transport_Disconnect(IPOP3Transport *iface)
361 {
362     TRACE("()\n");
363     return IPOP3Transport_CommandQUIT(iface);
364 }
365
366 static HRESULT WINAPI POP3Transport_DropConnection(IPOP3Transport *iface)
367 {
368     POP3Transport *This = (POP3Transport *)iface;
369
370     TRACE("()\n");
371     return InternetTransport_DropConnection(&This->InetTransport);
372 }
373
374 static HRESULT WINAPI POP3Transport_GetStatus(IPOP3Transport *iface,
375     IXPSTATUS *pCurrentStatus)
376 {
377     POP3Transport *This = (POP3Transport *)iface;
378
379     TRACE("()\n");
380     return InternetTransport_GetStatus(&This->InetTransport, pCurrentStatus);
381 }
382
383 static HRESULT WINAPI POP3Transport_InitNew(IPOP3Transport *iface,
384     LPSTR pszLogFilePath, IPOP3Callback *pCallback)
385 {
386     POP3Transport *This = (POP3Transport *)iface;
387
388     TRACE("(%s, %p)\n", debugstr_a(pszLogFilePath), pCallback);
389
390     if (!pCallback)
391         return E_INVALIDARG;
392
393     if (pszLogFilePath)
394         FIXME("not using log file of %s, use Wine debug logging instead\n",
395             debugstr_a(pszLogFilePath));
396
397     IPOP3Callback_AddRef(pCallback);
398     This->InetTransport.pCallback = (ITransportCallback *)pCallback;
399     This->InetTransport.fInitialised = TRUE;
400
401     return S_OK;
402 }
403
404 static HRESULT WINAPI POP3Transport_MarkItem(IPOP3Transport *iface, POP3MARKTYPE marktype,
405     DWORD dwPopId, boolean fMarked)
406 {
407     FIXME("(%u, %u, %d)\n", marktype, dwPopId, fMarked);
408     return E_NOTIMPL;
409 }
410
411 static HRESULT WINAPI POP3Transport_CommandAUTH(IPOP3Transport *iface, LPSTR pszAuthType)
412 {
413     FIXME("(%s)\n", pszAuthType);
414     return E_NOTIMPL;
415 }
416
417 static HRESULT WINAPI POP3Transport_CommandUSER(IPOP3Transport *iface, LPSTR username)
418 {
419     FIXME("(%s)\n", username);
420     return E_NOTIMPL;
421 }
422
423 static HRESULT WINAPI POP3Transport_CommandPASS(IPOP3Transport *iface, LPSTR password)
424 {
425     FIXME("(%s)\n", password);
426     return E_NOTIMPL;
427 }
428
429 static HRESULT WINAPI POP3Transport_CommandLIST(
430     IPOP3Transport *iface, POP3CMDTYPE cmdtype, DWORD dwPopId)
431 {
432     static char list[] = "LIST\r\n";
433     POP3Transport *This = (POP3Transport *)iface;
434
435     TRACE("(%u, %u)\n", cmdtype, dwPopId);
436
437     This->command = POP3_LIST;
438     InternetTransport_DoCommand(&This->InetTransport, list, POP3Transport_CallbackRecvLISTResp);
439     return S_OK;
440 }
441
442 static HRESULT WINAPI POP3Transport_CommandTOP(
443     IPOP3Transport *iface, POP3CMDTYPE cmdtype, DWORD dwPopId, DWORD cPreviewLines)
444 {
445     FIXME("(%u, %u, %u)\n", cmdtype, dwPopId, cPreviewLines);
446     return E_NOTIMPL;
447 }
448
449 static HRESULT WINAPI POP3Transport_CommandQUIT(IPOP3Transport *iface)
450 {
451     static char command[] = "QUIT\r\n";
452     POP3Transport *This = (POP3Transport *)iface;
453
454     TRACE("()\n");
455
456     This->command = POP3_QUIT;
457     return InternetTransport_DoCommand(&This->InetTransport, command, POP3Transport_CallbackRecvQUITResp);
458 }
459
460 static HRESULT WINAPI POP3Transport_CommandSTAT(IPOP3Transport *iface)
461 {
462     static char stat[] = "STAT\r\n";
463     POP3Transport *This = (POP3Transport *)iface;
464
465     TRACE("\n");
466
467     This->command = POP3_STAT;
468     InternetTransport_DoCommand(&This->InetTransport, stat, POP3Transport_CallbackRecvSTATResp);
469     return S_OK;
470 }
471
472 static HRESULT WINAPI POP3Transport_CommandNOOP(IPOP3Transport *iface)
473 {
474     FIXME("()\n");
475     return E_NOTIMPL;
476 }
477
478 static HRESULT WINAPI POP3Transport_CommandRSET(IPOP3Transport *iface)
479 {
480     FIXME("()\n");
481     return E_NOTIMPL;
482 }
483
484 static HRESULT WINAPI POP3Transport_CommandUIDL(
485     IPOP3Transport *iface, POP3CMDTYPE cmdtype, DWORD dwPopId)
486 {
487     static char uidl[] = "UIDL\r\n";
488     POP3Transport *This = (POP3Transport *)iface;
489
490     TRACE("(%u, %u)\n", cmdtype, dwPopId);
491
492     This->command = POP3_UIDL;
493     InternetTransport_DoCommand(&This->InetTransport, uidl, POP3Transport_CallbackRecvUIDLResp);
494     return S_OK;
495 }
496
497 static HRESULT WINAPI POP3Transport_CommandDELE(
498     IPOP3Transport *iface, POP3CMDTYPE cmdtype, DWORD dwPopId)
499 {
500     FIXME("(%u, %u)\n", cmdtype, dwPopId);
501     return E_NOTIMPL;
502 }
503
504 static HRESULT WINAPI POP3Transport_CommandRETR(
505     IPOP3Transport *iface, POP3CMDTYPE cmdtype, DWORD dwPopId)
506 {
507     FIXME("(%u, %u)\n", cmdtype, dwPopId);
508     return E_NOTIMPL;
509 }
510
511 static const IPOP3TransportVtbl POP3TransportVtbl =
512 {
513     POP3Transport_QueryInterface,
514     POP3Transport_AddRef,
515     POP3Transport_Release,
516     POP3Transport_GetServerInfo,
517     POP3Transport_GetIXPType,
518     POP3Transport_IsState,
519     POP3Transport_InetServerFromAccount,
520     POP3Transport_Connect,
521     POP3Transport_HandsOffCallback,
522     POP3Transport_Disconnect,
523     POP3Transport_DropConnection,
524     POP3Transport_GetStatus,
525     POP3Transport_InitNew,
526     POP3Transport_MarkItem,
527     POP3Transport_CommandAUTH,
528     POP3Transport_CommandUSER,
529     POP3Transport_CommandPASS,
530     POP3Transport_CommandLIST,
531     POP3Transport_CommandTOP,
532     POP3Transport_CommandQUIT,
533     POP3Transport_CommandSTAT,
534     POP3Transport_CommandNOOP,
535     POP3Transport_CommandRSET,
536     POP3Transport_CommandUIDL,
537     POP3Transport_CommandDELE,
538     POP3Transport_CommandRETR
539 };
540
541 HRESULT WINAPI CreatePOP3Transport(IPOP3Transport **ppTransport)
542 {
543     HRESULT hr;
544     POP3Transport *This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
545     if (!This)
546         return E_OUTOFMEMORY;
547
548     This->InetTransport.u.vtblPOP3 = &POP3TransportVtbl;
549     This->refs = 0;
550     hr = InternetTransport_Init(&This->InetTransport);
551     if (FAILED(hr))
552     {
553         HeapFree(GetProcessHeap(), 0, This);
554         return hr;
555     }
556
557     *ppTransport = (IPOP3Transport *)&This->InetTransport.u.vtblPOP3;
558     IPOP3Transport_AddRef(*ppTransport);
559
560     return S_OK;
561 }
562
563 static HRESULT WINAPI POP3TransportCF_QueryInterface(LPCLASSFACTORY iface,
564     REFIID riid, LPVOID *ppv)
565 {
566     *ppv = NULL;
567     if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IClassFactory))
568     {
569         *ppv = iface;
570         IUnknown_AddRef(iface);
571         return S_OK;
572     }
573     return E_NOINTERFACE;
574 }
575
576 static ULONG WINAPI POP3TransportCF_AddRef(LPCLASSFACTORY iface)
577 {
578     return 2; /* non-heap based object */
579 }
580
581 static ULONG WINAPI POP3TransportCF_Release(LPCLASSFACTORY iface)
582 {
583     return 1; /* non-heap based object */
584 }
585
586 static HRESULT WINAPI POP3TransportCF_CreateInstance(LPCLASSFACTORY iface,
587     LPUNKNOWN pUnk, REFIID riid, LPVOID *ppv)
588 {
589     HRESULT hr;
590     IPOP3Transport *pPop3Transport;
591
592     TRACE("(%p, %s, %p)\n", pUnk, debugstr_guid(riid), ppv);
593
594     *ppv = NULL;
595
596     if (pUnk)
597         return CLASS_E_NOAGGREGATION;
598
599     hr = CreatePOP3Transport(&pPop3Transport);
600     if (FAILED(hr))
601         return hr;
602
603     hr = IPOP3Transport_QueryInterface(pPop3Transport, riid, ppv);
604     IPOP3Transport_Release(pPop3Transport);
605
606     return hr;
607 }
608
609 static HRESULT WINAPI POP3TransportCF_LockServer(LPCLASSFACTORY iface, BOOL fLock)
610 {
611     FIXME("(%d)\n",fLock);
612     return S_OK;
613 }
614
615 static const IClassFactoryVtbl POP3TransportCFVtbl =
616 {
617     POP3TransportCF_QueryInterface,
618     POP3TransportCF_AddRef,
619     POP3TransportCF_Release,
620     POP3TransportCF_CreateInstance,
621     POP3TransportCF_LockServer
622 };
623 static const IClassFactoryVtbl *POP3TransportCF = &POP3TransportCFVtbl;
624
625 HRESULT POP3TransportCF_Create(REFIID riid, LPVOID *ppv)
626 {
627     return IClassFactory_QueryInterface((IClassFactory *)&POP3TransportCF, riid, ppv);
628 }