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