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 } 475