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