xref: /reactos/dll/win32/urlmon/ftp.c (revision 58aee30e)
1 /*
2  * Copyright 2005-2009 Jacek Caban for CodeWeavers
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18 
19 #include "urlmon_main.h"
20 
21 #define NO_SHLWAPI_REG
22 #include "shlwapi.h"
23 
24 #include "wine/debug.h"
25 
26 WINE_DEFAULT_DEBUG_CHANNEL(urlmon);
27 
28 typedef struct {
29     Protocol base;
30 
31     IUnknown            IUnknown_outer;
32     IInternetProtocolEx IInternetProtocolEx_iface;
33     IInternetPriority   IInternetPriority_iface;
34     IWinInetHttpInfo    IWinInetHttpInfo_iface;
35 
36     LONG ref;
37     IUnknown *outer;
38 } FtpProtocol;
39 
40 static inline FtpProtocol *impl_from_IUnknown(IUnknown *iface)
41 {
42     return CONTAINING_RECORD(iface, FtpProtocol, IUnknown_outer);
43 }
44 
45 static inline FtpProtocol *impl_from_IInternetProtocolEx(IInternetProtocolEx *iface)
46 {
47     return CONTAINING_RECORD(iface, FtpProtocol, IInternetProtocolEx_iface);
48 }
49 
50 static inline FtpProtocol *impl_from_IInternetPriority(IInternetPriority *iface)
51 {
52     return CONTAINING_RECORD(iface, FtpProtocol, IInternetPriority_iface);
53 }
54 static inline FtpProtocol *impl_from_IWinInetHttpInfo(IWinInetHttpInfo *iface)
55 
56 {
57     return CONTAINING_RECORD(iface, FtpProtocol, IWinInetHttpInfo_iface);
58 }
59 
60 static inline FtpProtocol *impl_from_Protocol(Protocol *prot)
61 {
62     return CONTAINING_RECORD(prot, FtpProtocol, base);
63 }
64 
65 static HRESULT FtpProtocol_open_request(Protocol *prot, IUri *uri, DWORD request_flags,
66         HINTERNET internet_session, IInternetBindInfo *bind_info)
67 {
68     FtpProtocol *This = impl_from_Protocol(prot);
69     BSTR url;
70     HRESULT hres;
71 
72     hres = IUri_GetAbsoluteUri(uri, &url);
73     if(FAILED(hres))
74         return hres;
75 
76     This->base.request = InternetOpenUrlW(internet_session, url, NULL, 0,
77             request_flags|INTERNET_FLAG_EXISTING_CONNECT|INTERNET_FLAG_PASSIVE,
78             (DWORD_PTR)&This->base);
79     SysFreeString(url);
80     if (!This->base.request && GetLastError() != ERROR_IO_PENDING) {
81         WARN("InternetOpenUrl failed: %d\n", GetLastError());
82         return INET_E_RESOURCE_NOT_FOUND;
83     }
84 
85     return S_OK;
86 }
87 
88 static HRESULT FtpProtocol_end_request(Protocol *prot)
89 {
90     return E_NOTIMPL;
91 }
92 
93 static HRESULT FtpProtocol_start_downloading(Protocol *prot)
94 {
95     FtpProtocol *This = impl_from_Protocol(prot);
96     DWORD size;
97     BOOL res;
98 
99     res = FtpGetFileSize(This->base.request, &size);
100     if(res)
101         This->base.content_length = size;
102     else
103         WARN("FtpGetFileSize failed: %d\n", GetLastError());
104 
105     return S_OK;
106 }
107 
108 static void FtpProtocol_close_connection(Protocol *prot)
109 {
110 }
111 
112 static void FtpProtocol_on_error(Protocol *prot, DWORD error)
113 {
114     FIXME("(%p) %d - stub\n", prot, error);
115 }
116 
117 static const ProtocolVtbl AsyncProtocolVtbl = {
118     FtpProtocol_open_request,
119     FtpProtocol_end_request,
120     FtpProtocol_start_downloading,
121     FtpProtocol_close_connection,
122     FtpProtocol_on_error
123 };
124 
125 static HRESULT WINAPI FtpProtocolUnk_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
126 {
127     FtpProtocol *This = impl_from_IUnknown(iface);
128 
129     if(IsEqualGUID(&IID_IUnknown, riid)) {
130         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
131         *ppv = &This->IUnknown_outer;
132     }else if(IsEqualGUID(&IID_IInternetProtocolRoot, riid)) {
133         TRACE("(%p)->(IID_IInternetProtocolRoot %p)\n", This, ppv);
134         *ppv = &This->IInternetProtocolEx_iface;
135     }else if(IsEqualGUID(&IID_IInternetProtocol, riid)) {
136         TRACE("(%p)->(IID_IInternetProtocol %p)\n", This, ppv);
137         *ppv = &This->IInternetProtocolEx_iface;
138     }else if(IsEqualGUID(&IID_IInternetProtocolEx, riid)) {
139         TRACE("(%p)->(IID_IInternetProtocolEx %p)\n", This, ppv);
140         *ppv = &This->IInternetProtocolEx_iface;
141     }else if(IsEqualGUID(&IID_IInternetPriority, riid)) {
142         TRACE("(%p)->(IID_IInternetPriority %p)\n", This, ppv);
143         *ppv = &This->IInternetPriority_iface;
144     }else if(IsEqualGUID(&IID_IWinInetInfo, riid)) {
145         TRACE("(%p)->(IID_IWinInetInfo %p)\n", This, ppv);
146         *ppv = &This->IWinInetHttpInfo_iface;
147     }else if(IsEqualGUID(&IID_IWinInetHttpInfo, riid)) {
148         TRACE("(%p)->(IID_IWinInetHttpInfo %p)\n", This, ppv);
149         *ppv = &This->IWinInetHttpInfo_iface;
150     }else {
151         *ppv = NULL;
152         WARN("not supported interface %s\n", debugstr_guid(riid));
153         return E_NOINTERFACE;
154     }
155 
156     IUnknown_AddRef((IUnknown*)*ppv);
157     return S_OK;
158 }
159 
160 static ULONG WINAPI FtpProtocolUnk_AddRef(IUnknown *iface)
161 {
162     FtpProtocol *This = impl_from_IUnknown(iface);
163     LONG ref = InterlockedIncrement(&This->ref);
164     TRACE("(%p) ref=%d\n", This, ref);
165     return ref;
166 }
167 
168 static ULONG WINAPI FtpProtocolUnk_Release(IUnknown *iface)
169 {
170     FtpProtocol *This = impl_from_IUnknown(iface);
171     LONG ref = InterlockedDecrement(&This->ref);
172 
173     TRACE("(%p) ref=%d\n", This, ref);
174 
175     if(!ref) {
176         protocol_close_connection(&This->base);
177         heap_free(This);
178 
179         URLMON_UnlockModule();
180     }
181 
182     return ref;
183 }
184 
185 static const IUnknownVtbl FtpProtocolUnkVtbl = {
186     FtpProtocolUnk_QueryInterface,
187     FtpProtocolUnk_AddRef,
188     FtpProtocolUnk_Release
189 };
190 
191 static HRESULT WINAPI FtpProtocol_QueryInterface(IInternetProtocolEx *iface, REFIID riid, void **ppv)
192 {
193     FtpProtocol *This = impl_from_IInternetProtocolEx(iface);
194     TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
195     return IUnknown_QueryInterface(This->outer, riid, ppv);
196 }
197 
198 static ULONG WINAPI FtpProtocol_AddRef(IInternetProtocolEx *iface)
199 {
200     FtpProtocol *This = impl_from_IInternetProtocolEx(iface);
201     TRACE("(%p)\n", This);
202     return IUnknown_AddRef(This->outer);
203 }
204 
205 static ULONG WINAPI FtpProtocol_Release(IInternetProtocolEx *iface)
206 {
207     FtpProtocol *This = impl_from_IInternetProtocolEx(iface);
208     TRACE("(%p)\n", This);
209     return IUnknown_Release(This->outer);
210 }
211 
212 static HRESULT WINAPI FtpProtocol_Start(IInternetProtocolEx *iface, LPCWSTR szUrl,
213         IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo,
214         DWORD grfPI, HANDLE_PTR dwReserved)
215 {
216     FtpProtocol *This = impl_from_IInternetProtocolEx(iface);
217     IUri *uri;
218     HRESULT hres;
219 
220     TRACE("(%p)->(%s %p %p %08x %lx)\n", This, debugstr_w(szUrl), pOIProtSink,
221           pOIBindInfo, grfPI, dwReserved);
222 
223     hres = CreateUri(szUrl, 0, 0, &uri);
224     if(FAILED(hres))
225         return hres;
226 
227     hres = IInternetProtocolEx_StartEx(&This->IInternetProtocolEx_iface, uri, pOIProtSink,
228             pOIBindInfo, grfPI, (HANDLE*)dwReserved);
229 
230     IUri_Release(uri);
231     return hres;
232 }
233 
234 static HRESULT WINAPI FtpProtocol_Continue(IInternetProtocolEx *iface, PROTOCOLDATA *pProtocolData)
235 {
236     FtpProtocol *This = impl_from_IInternetProtocolEx(iface);
237 
238     TRACE("(%p)->(%p)\n", This, pProtocolData);
239 
240     return protocol_continue(&This->base, pProtocolData);
241 }
242 
243 static HRESULT WINAPI FtpProtocol_Abort(IInternetProtocolEx *iface, HRESULT hrReason,
244         DWORD dwOptions)
245 {
246     FtpProtocol *This = impl_from_IInternetProtocolEx(iface);
247 
248     TRACE("(%p)->(%08x %08x)\n", This, hrReason, dwOptions);
249 
250     return protocol_abort(&This->base, hrReason);
251 }
252 
253 static HRESULT WINAPI FtpProtocol_Terminate(IInternetProtocolEx *iface, DWORD dwOptions)
254 {
255     FtpProtocol *This = impl_from_IInternetProtocolEx(iface);
256 
257     TRACE("(%p)->(%08x)\n", This, dwOptions);
258 
259     protocol_close_connection(&This->base);
260     return S_OK;
261 }
262 
263 static HRESULT WINAPI FtpProtocol_Suspend(IInternetProtocolEx *iface)
264 {
265     FtpProtocol *This = impl_from_IInternetProtocolEx(iface);
266     FIXME("(%p)\n", This);
267     return E_NOTIMPL;
268 }
269 
270 static HRESULT WINAPI FtpProtocol_Resume(IInternetProtocolEx *iface)
271 {
272     FtpProtocol *This = impl_from_IInternetProtocolEx(iface);
273     FIXME("(%p)\n", This);
274     return E_NOTIMPL;
275 }
276 
277 static HRESULT WINAPI FtpProtocol_Read(IInternetProtocolEx *iface, void *pv,
278         ULONG cb, ULONG *pcbRead)
279 {
280     FtpProtocol *This = impl_from_IInternetProtocolEx(iface);
281 
282     TRACE("(%p)->(%p %u %p)\n", This, pv, cb, pcbRead);
283 
284     return protocol_read(&This->base, pv, cb, pcbRead);
285 }
286 
287 static HRESULT WINAPI FtpProtocol_Seek(IInternetProtocolEx *iface, LARGE_INTEGER dlibMove,
288         DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
289 {
290     FtpProtocol *This = impl_from_IInternetProtocolEx(iface);
291     FIXME("(%p)->(%d %d %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
292     return E_NOTIMPL;
293 }
294 
295 static HRESULT WINAPI FtpProtocol_LockRequest(IInternetProtocolEx *iface, DWORD dwOptions)
296 {
297     FtpProtocol *This = impl_from_IInternetProtocolEx(iface);
298 
299     TRACE("(%p)->(%08x)\n", This, dwOptions);
300 
301     return protocol_lock_request(&This->base);
302 }
303 
304 static HRESULT WINAPI FtpProtocol_UnlockRequest(IInternetProtocolEx *iface)
305 {
306     FtpProtocol *This = impl_from_IInternetProtocolEx(iface);
307 
308     TRACE("(%p)\n", This);
309 
310     return protocol_unlock_request(&This->base);
311 }
312 
313 static HRESULT WINAPI FtpProtocol_StartEx(IInternetProtocolEx *iface, IUri *pUri,
314         IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo,
315         DWORD grfPI, HANDLE *dwReserved)
316 {
317     FtpProtocol *This = impl_from_IInternetProtocolEx(iface);
318     DWORD scheme = 0;
319     HRESULT hres;
320 
321     TRACE("(%p)->(%p %p %p %08x %p)\n", This, pUri, pOIProtSink,
322             pOIBindInfo, grfPI, dwReserved);
323 
324     hres = IUri_GetScheme(pUri, &scheme);
325     if(FAILED(hres))
326         return hres;
327     if(scheme != URL_SCHEME_FTP)
328         return MK_E_SYNTAX;
329 
330     return protocol_start(&This->base, (IInternetProtocol*)&This->IInternetProtocolEx_iface, pUri,
331                           pOIProtSink, pOIBindInfo);
332 }
333 
334 static const IInternetProtocolExVtbl FtpProtocolVtbl = {
335     FtpProtocol_QueryInterface,
336     FtpProtocol_AddRef,
337     FtpProtocol_Release,
338     FtpProtocol_Start,
339     FtpProtocol_Continue,
340     FtpProtocol_Abort,
341     FtpProtocol_Terminate,
342     FtpProtocol_Suspend,
343     FtpProtocol_Resume,
344     FtpProtocol_Read,
345     FtpProtocol_Seek,
346     FtpProtocol_LockRequest,
347     FtpProtocol_UnlockRequest,
348     FtpProtocol_StartEx
349 };
350 
351 static HRESULT WINAPI FtpPriority_QueryInterface(IInternetPriority *iface, REFIID riid, void **ppv)
352 {
353     FtpProtocol *This = impl_from_IInternetPriority(iface);
354     return IInternetProtocolEx_QueryInterface(&This->IInternetProtocolEx_iface, riid, ppv);
355 }
356 
357 static ULONG WINAPI FtpPriority_AddRef(IInternetPriority *iface)
358 {
359     FtpProtocol *This = impl_from_IInternetPriority(iface);
360     return IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface);
361 }
362 
363 static ULONG WINAPI FtpPriority_Release(IInternetPriority *iface)
364 {
365     FtpProtocol *This = impl_from_IInternetPriority(iface);
366     return IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface);
367 }
368 
369 static HRESULT WINAPI FtpPriority_SetPriority(IInternetPriority *iface, LONG nPriority)
370 {
371     FtpProtocol *This = impl_from_IInternetPriority(iface);
372 
373     TRACE("(%p)->(%d)\n", This, nPriority);
374 
375     This->base.priority = nPriority;
376     return S_OK;
377 }
378 
379 static HRESULT WINAPI FtpPriority_GetPriority(IInternetPriority *iface, LONG *pnPriority)
380 {
381     FtpProtocol *This = impl_from_IInternetPriority(iface);
382 
383     TRACE("(%p)->(%p)\n", This, pnPriority);
384 
385     *pnPriority = This->base.priority;
386     return S_OK;
387 }
388 
389 static const IInternetPriorityVtbl FtpPriorityVtbl = {
390     FtpPriority_QueryInterface,
391     FtpPriority_AddRef,
392     FtpPriority_Release,
393     FtpPriority_SetPriority,
394     FtpPriority_GetPriority
395 };
396 
397 static HRESULT WINAPI HttpInfo_QueryInterface(IWinInetHttpInfo *iface, REFIID riid, void **ppv)
398 {
399     FtpProtocol *This = impl_from_IWinInetHttpInfo(iface);
400     return IInternetProtocolEx_QueryInterface(&This->IInternetProtocolEx_iface, riid, ppv);
401 }
402 
403 static ULONG WINAPI HttpInfo_AddRef(IWinInetHttpInfo *iface)
404 {
405     FtpProtocol *This = impl_from_IWinInetHttpInfo(iface);
406     return IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface);
407 }
408 
409 static ULONG WINAPI HttpInfo_Release(IWinInetHttpInfo *iface)
410 {
411     FtpProtocol *This = impl_from_IWinInetHttpInfo(iface);
412     return IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface);
413 }
414 
415 static HRESULT WINAPI HttpInfo_QueryOption(IWinInetHttpInfo *iface, DWORD dwOption,
416         void *pBuffer, DWORD *pcbBuffer)
417 {
418     FtpProtocol *This = impl_from_IWinInetHttpInfo(iface);
419     TRACE("(%p)->(%x %p %p)\n", This, dwOption, pBuffer, pcbBuffer);
420 
421     if(!This->base.request)
422         return E_FAIL;
423 
424     if(!InternetQueryOptionW(This->base.request, dwOption, pBuffer, pcbBuffer))
425         return S_FALSE;
426     return S_OK;
427 }
428 
429 static HRESULT WINAPI HttpInfo_QueryInfo(IWinInetHttpInfo *iface, DWORD dwOption,
430         void *pBuffer, DWORD *pcbBuffer, DWORD *pdwFlags, DWORD *pdwReserved)
431 {
432     FtpProtocol *This = impl_from_IWinInetHttpInfo(iface);
433     TRACE("(%p)->(%x %p %p %p %p)\n", This, dwOption, pBuffer, pcbBuffer, pdwFlags, pdwReserved);
434 
435     if(!This->base.request)
436         return E_FAIL;
437 
438     if(!HttpQueryInfoW(This->base.request, dwOption, pBuffer, pcbBuffer, pdwFlags))
439         return S_FALSE;
440     return S_OK;
441 }
442 
443 static const IWinInetHttpInfoVtbl WinInetHttpInfoVtbl = {
444     HttpInfo_QueryInterface,
445     HttpInfo_AddRef,
446     HttpInfo_Release,
447     HttpInfo_QueryOption,
448     HttpInfo_QueryInfo
449 };
450 
451 HRESULT FtpProtocol_Construct(IUnknown *outer, void **ppv)
452 {
453     FtpProtocol *ret;
454 
455     TRACE("(%p %p)\n", outer, ppv);
456 
457     URLMON_LockModule();
458 
459     ret = heap_alloc_zero(sizeof(FtpProtocol));
460 
461     ret->base.vtbl = &AsyncProtocolVtbl;
462     ret->IUnknown_outer.lpVtbl            = &FtpProtocolUnkVtbl;
463     ret->IInternetProtocolEx_iface.lpVtbl = &FtpProtocolVtbl;
464     ret->IInternetPriority_iface.lpVtbl   = &FtpPriorityVtbl;
465     ret->IWinInetHttpInfo_iface.lpVtbl    = &WinInetHttpInfoVtbl;
466     ret->ref = 1;
467     ret->outer = outer ? outer : &ret->IUnknown_outer;
468 
469     *ppv = &ret->IUnknown_outer;
470     return S_OK;
471 }
472