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