quartz: Sign-compare warnings fix.
[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     static char user[] = "USER ";
420     POP3Transport *This = (POP3Transport *)iface;
421     char *command;
422     int len;
423
424     TRACE("(%s)\n", username);
425
426     len = sizeof(user) + strlen(username) + 2; /* "\r\n" */
427     command = HeapAlloc(GetProcessHeap(), 0, len);
428
429     strcpy(command, user);
430     strcat(command, username);
431     strcat(command, "\r\n");
432
433     This->command = POP3_USER;
434     InternetTransport_DoCommand(&This->InetTransport, command, POP3Transport_CallbackRecvUSERResp);
435
436     HeapFree(GetProcessHeap(), 0, command);
437     return S_OK;
438 }
439
440 static HRESULT WINAPI POP3Transport_CommandPASS(IPOP3Transport *iface, LPSTR password)
441 {
442     static char pass[] = "PASS ";
443     POP3Transport *This = (POP3Transport *)iface;
444     char *command;
445     int len;
446
447     TRACE("(%p)\n", password);
448
449     len = sizeof(pass) + strlen(password) + 2; /* "\r\n" */
450     command = HeapAlloc(GetProcessHeap(), 0, len);
451
452     strcpy(command, pass);
453     strcat(command, password);
454     strcat(command, "\r\n");
455
456     This->command = POP3_PASS;
457     InternetTransport_DoCommand(&This->InetTransport, command, POP3Transport_CallbackRecvPASSResp);
458
459     HeapFree(GetProcessHeap(), 0, command);
460     return S_OK;
461 }
462
463 static HRESULT WINAPI POP3Transport_CommandLIST(
464     IPOP3Transport *iface, POP3CMDTYPE cmdtype, DWORD dwPopId)
465 {
466     static char list[] = "LIST\r\n";
467     POP3Transport *This = (POP3Transport *)iface;
468
469     TRACE("(%u, %u)\n", cmdtype, dwPopId);
470
471     This->command = POP3_LIST;
472     InternetTransport_DoCommand(&This->InetTransport, list, POP3Transport_CallbackRecvLISTResp);
473     return S_OK;
474 }
475
476 static HRESULT WINAPI POP3Transport_CommandTOP(
477     IPOP3Transport *iface, POP3CMDTYPE cmdtype, DWORD dwPopId, DWORD cPreviewLines)
478 {
479     FIXME("(%u, %u, %u)\n", cmdtype, dwPopId, cPreviewLines);
480     return E_NOTIMPL;
481 }
482
483 static HRESULT WINAPI POP3Transport_CommandQUIT(IPOP3Transport *iface)
484 {
485     static char command[] = "QUIT\r\n";
486     POP3Transport *This = (POP3Transport *)iface;
487
488     TRACE("()\n");
489
490     This->command = POP3_QUIT;
491     return InternetTransport_DoCommand(&This->InetTransport, command, POP3Transport_CallbackRecvQUITResp);
492 }
493
494 static HRESULT WINAPI POP3Transport_CommandSTAT(IPOP3Transport *iface)
495 {
496     static char stat[] = "STAT\r\n";
497     POP3Transport *This = (POP3Transport *)iface;
498
499     TRACE("\n");
500
501     This->command = POP3_STAT;
502     InternetTransport_DoCommand(&This->InetTransport, stat, POP3Transport_CallbackRecvSTATResp);
503     return S_OK;
504 }
505
506 static HRESULT WINAPI POP3Transport_CommandNOOP(IPOP3Transport *iface)
507 {
508     FIXME("()\n");
509     return E_NOTIMPL;
510 }
511
512 static HRESULT WINAPI POP3Transport_CommandRSET(IPOP3Transport *iface)
513 {
514     FIXME("()\n");
515     return E_NOTIMPL;
516 }
517
518 static HRESULT WINAPI POP3Transport_CommandUIDL(
519     IPOP3Transport *iface, POP3CMDTYPE cmdtype, DWORD dwPopId)
520 {
521     static char uidl[] = "UIDL\r\n";
522     POP3Transport *This = (POP3Transport *)iface;
523
524     TRACE("(%u, %u)\n", cmdtype, dwPopId);
525
526     This->command = POP3_UIDL;
527     InternetTransport_DoCommand(&This->InetTransport, uidl, POP3Transport_CallbackRecvUIDLResp);
528     return S_OK;
529 }
530
531 static HRESULT WINAPI POP3Transport_CommandDELE(
532     IPOP3Transport *iface, POP3CMDTYPE cmdtype, DWORD dwPopId)
533 {
534     FIXME("(%u, %u)\n", cmdtype, dwPopId);
535     return E_NOTIMPL;
536 }
537
538 static HRESULT WINAPI POP3Transport_CommandRETR(
539     IPOP3Transport *iface, POP3CMDTYPE cmdtype, DWORD dwPopId)
540 {
541     FIXME("(%u, %u)\n", cmdtype, dwPopId);
542     return E_NOTIMPL;
543 }
544
545 static const IPOP3TransportVtbl POP3TransportVtbl =
546 {
547     POP3Transport_QueryInterface,
548     POP3Transport_AddRef,
549     POP3Transport_Release,
550     POP3Transport_GetServerInfo,
551     POP3Transport_GetIXPType,
552     POP3Transport_IsState,
553     POP3Transport_InetServerFromAccount,
554     POP3Transport_Connect,
555     POP3Transport_HandsOffCallback,
556     POP3Transport_Disconnect,
557     POP3Transport_DropConnection,
558     POP3Transport_GetStatus,
559     POP3Transport_InitNew,
560     POP3Transport_MarkItem,
561     POP3Transport_CommandAUTH,
562     POP3Transport_CommandUSER,
563     POP3Transport_CommandPASS,
564     POP3Transport_CommandLIST,
565     POP3Transport_CommandTOP,
566     POP3Transport_CommandQUIT,
567     POP3Transport_CommandSTAT,
568     POP3Transport_CommandNOOP,
569     POP3Transport_CommandRSET,
570     POP3Transport_CommandUIDL,
571     POP3Transport_CommandDELE,
572     POP3Transport_CommandRETR
573 };
574
575 HRESULT WINAPI CreatePOP3Transport(IPOP3Transport **ppTransport)
576 {
577     HRESULT hr;
578     POP3Transport *This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
579     if (!This)
580         return E_OUTOFMEMORY;
581
582     This->InetTransport.u.vtblPOP3 = &POP3TransportVtbl;
583     This->refs = 0;
584     hr = InternetTransport_Init(&This->InetTransport);
585     if (FAILED(hr))
586     {
587         HeapFree(GetProcessHeap(), 0, This);
588         return hr;
589     }
590
591     *ppTransport = (IPOP3Transport *)&This->InetTransport.u.vtblPOP3;
592     IPOP3Transport_AddRef(*ppTransport);
593
594     return S_OK;
595 }
596
597 static HRESULT WINAPI POP3TransportCF_QueryInterface(LPCLASSFACTORY iface,
598     REFIID riid, LPVOID *ppv)
599 {
600     *ppv = NULL;
601     if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IClassFactory))
602     {
603         *ppv = iface;
604         IUnknown_AddRef(iface);
605         return S_OK;
606     }
607     return E_NOINTERFACE;
608 }
609
610 static ULONG WINAPI POP3TransportCF_AddRef(LPCLASSFACTORY iface)
611 {
612     return 2; /* non-heap based object */
613 }
614
615 static ULONG WINAPI POP3TransportCF_Release(LPCLASSFACTORY iface)
616 {
617     return 1; /* non-heap based object */
618 }
619
620 static HRESULT WINAPI POP3TransportCF_CreateInstance(LPCLASSFACTORY iface,
621     LPUNKNOWN pUnk, REFIID riid, LPVOID *ppv)
622 {
623     HRESULT hr;
624     IPOP3Transport *pPop3Transport;
625
626     TRACE("(%p, %s, %p)\n", pUnk, debugstr_guid(riid), ppv);
627
628     *ppv = NULL;
629
630     if (pUnk)
631         return CLASS_E_NOAGGREGATION;
632
633     hr = CreatePOP3Transport(&pPop3Transport);
634     if (FAILED(hr))
635         return hr;
636
637     hr = IPOP3Transport_QueryInterface(pPop3Transport, riid, ppv);
638     IPOP3Transport_Release(pPop3Transport);
639
640     return hr;
641 }
642
643 static HRESULT WINAPI POP3TransportCF_LockServer(LPCLASSFACTORY iface, BOOL fLock)
644 {
645     FIXME("(%d)\n",fLock);
646     return S_OK;
647 }
648
649 static const IClassFactoryVtbl POP3TransportCFVtbl =
650 {
651     POP3TransportCF_QueryInterface,
652     POP3TransportCF_AddRef,
653     POP3TransportCF_Release,
654     POP3TransportCF_CreateInstance,
655     POP3TransportCF_LockServer
656 };
657 static const IClassFactoryVtbl *POP3TransportCF = &POP3TransportCFVtbl;
658
659 HRESULT POP3TransportCF_Create(REFIID riid, LPVOID *ppv)
660 {
661     return IClassFactory_QueryInterface((IClassFactory *)&POP3TransportCF, riid, ppv);
662 }