[SHELL32_APITEST] Follow-up to #6796 (25e2f5f)
[reactos.git] / dll / win32 / urlmon / ftp.c
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
40 static inline FtpProtocol *impl_from_IUnknown(IUnknown *iface)
41 {
42 return CONTAINING_RECORD(iface, FtpProtocol, IUnknown_inner);
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 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
91 static HRESULT FtpProtocol_end_request(Protocol *prot)
92 {
93 return E_NOTIMPL;
94 }
95
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
111 static void FtpProtocol_close_connection(Protocol *prot)
112 {
113 }
114
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 }