1 /* 2 * Copyright 2017 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 #define COBJMACROS 20 #define NONAMELESSUNION 21 22 #include <assert.h> 23 24 #include "mimeole.h" 25 #include "inetcomm_private.h" 26 27 #include "wine/debug.h" 28 #include "wine/heap.h" 29 30 WINE_DEFAULT_DEBUG_CHANNEL(inetcomm); 31 32 typedef struct { 33 IUnknown IUnknown_inner; 34 IInternetProtocol IInternetProtocol_iface; 35 IInternetProtocolInfo IInternetProtocolInfo_iface; 36 37 LONG ref; 38 IUnknown *outer_unk; 39 40 WCHAR *location; 41 IStream *stream; 42 IInternetProtocolSink *sink; 43 } MimeHtmlProtocol; 44 45 typedef struct { 46 const WCHAR *mhtml; 47 size_t mhtml_len; 48 const WCHAR *location; 49 } mhtml_url_t; 50 51 typedef struct { 52 IBindStatusCallback IBindStatusCallback_iface; 53 54 LONG ref; 55 56 MimeHtmlProtocol *protocol; 57 HRESULT status; 58 IStream *stream; 59 WCHAR url[1]; 60 } MimeHtmlBinding; 61 62 static const WCHAR mhtml_prefixW[] = {'m','h','t','m','l',':'}; 63 static const WCHAR mhtml_separatorW[] = {'!','x','-','u','s','c',':'}; 64 65 static inline LPWSTR heap_strdupW(LPCWSTR str) 66 { 67 LPWSTR ret = NULL; 68 69 if(str) { 70 DWORD size; 71 72 size = (lstrlenW(str)+1)*sizeof(WCHAR); 73 ret = heap_alloc(size); 74 if(ret) 75 memcpy(ret, str, size); 76 } 77 78 return ret; 79 } 80 81 static HRESULT parse_mhtml_url(const WCHAR *url, mhtml_url_t *r) 82 { 83 const WCHAR *p; 84 85 if(_wcsnicmp(url, mhtml_prefixW, ARRAY_SIZE(mhtml_prefixW))) 86 return E_FAIL; 87 88 r->mhtml = url + ARRAY_SIZE(mhtml_prefixW); 89 p = wcschr(r->mhtml, '!'); 90 if(p) { 91 r->mhtml_len = p - r->mhtml; 92 /* FIXME: We handle '!' and '!x-usc:' in URLs as the same thing. Those should not be the same. */ 93 if(!wcsncmp(p, mhtml_separatorW, ARRAY_SIZE(mhtml_separatorW))) 94 p += ARRAY_SIZE(mhtml_separatorW); 95 else 96 p++; 97 }else { 98 r->mhtml_len = lstrlenW(r->mhtml); 99 } 100 101 r->location = p; 102 return S_OK; 103 } 104 105 static HRESULT report_result(MimeHtmlProtocol *protocol, HRESULT result) 106 { 107 if(protocol->sink) { 108 IInternetProtocolSink_ReportResult(protocol->sink, result, ERROR_SUCCESS, NULL); 109 IInternetProtocolSink_Release(protocol->sink); 110 protocol->sink = NULL; 111 } 112 113 return result; 114 } 115 116 static HRESULT on_mime_message_available(MimeHtmlProtocol *protocol, IMimeMessage *mime_message) 117 { 118 FINDBODY find = {NULL}; 119 IMimeBody *mime_body; 120 PROPVARIANT value; 121 HBODY body; 122 HRESULT hres; 123 124 hres = IMimeMessage_FindFirst(mime_message, &find, &body); 125 if(FAILED(hres)) 126 return report_result(protocol, hres); 127 128 if(protocol->location) { 129 BOOL found = FALSE; 130 do { 131 hres = IMimeMessage_FindNext(mime_message, &find, &body); 132 if(FAILED(hres)) { 133 WARN("location %s not found\n", debugstr_w(protocol->location)); 134 return report_result(protocol, hres); 135 } 136 137 value.vt = VT_LPWSTR; 138 hres = IMimeMessage_GetBodyProp(mime_message, body, "content-location", 0, &value); 139 if(hres == MIME_E_NOT_FOUND) 140 continue; 141 if(FAILED(hres)) 142 return report_result(protocol, hres); 143 144 found = !lstrcmpW(protocol->location, value.u.pwszVal); 145 PropVariantClear(&value); 146 }while(!found); 147 }else { 148 hres = IMimeMessage_FindNext(mime_message, &find, &body); 149 if(FAILED(hres)) { 150 WARN("location %s not found\n", debugstr_w(protocol->location)); 151 return report_result(protocol, hres); 152 } 153 } 154 155 hres = IMimeMessage_BindToObject(mime_message, body, &IID_IMimeBody, (void**)&mime_body); 156 if(FAILED(hres)) 157 return report_result(protocol, hres); 158 159 value.vt = VT_LPWSTR; 160 hres = IMimeBody_GetProp(mime_body, "content-type", 0, &value); 161 if(SUCCEEDED(hres)) { 162 hres = IInternetProtocolSink_ReportProgress(protocol->sink, BINDSTATUS_MIMETYPEAVAILABLE, value.u.pwszVal); 163 PropVariantClear(&value); 164 } 165 166 /* FIXME: Create and report cache file. */ 167 168 hres = IMimeBody_GetData(mime_body, IET_DECODED, &protocol->stream); 169 if(FAILED(hres)) 170 return report_result(protocol, hres); 171 172 IInternetProtocolSink_ReportData(protocol->sink, BSCF_FIRSTDATANOTIFICATION 173 | BSCF_INTERMEDIATEDATANOTIFICATION 174 | BSCF_LASTDATANOTIFICATION 175 | BSCF_DATAFULLYAVAILABLE 176 | BSCF_AVAILABLEDATASIZEUNKNOWN, 0, 0); 177 178 return report_result(protocol, S_OK); 179 } 180 181 static HRESULT load_mime_message(IStream *stream, IMimeMessage **ret) 182 { 183 IMimeMessage *mime_message; 184 HRESULT hres; 185 186 hres = MimeMessage_create(NULL, (void**)&mime_message); 187 if(FAILED(hres)) 188 return hres; 189 190 IMimeMessage_InitNew(mime_message); 191 192 hres = IMimeMessage_Load(mime_message, stream); 193 if(FAILED(hres)) { 194 IMimeMessage_Release(mime_message); 195 return hres; 196 } 197 198 *ret = mime_message; 199 return S_OK; 200 } 201 202 static inline MimeHtmlBinding *impl_from_IBindStatusCallback(IBindStatusCallback *iface) 203 { 204 return CONTAINING_RECORD(iface, MimeHtmlBinding, IBindStatusCallback_iface); 205 } 206 207 static HRESULT WINAPI BindStatusCallback_QueryInterface(IBindStatusCallback *iface, 208 REFIID riid, void **ppv) 209 { 210 MimeHtmlBinding *This = impl_from_IBindStatusCallback(iface); 211 212 if(IsEqualGUID(&IID_IUnknown, riid)) { 213 TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv); 214 *ppv = &This->IBindStatusCallback_iface; 215 }else if(IsEqualGUID(&IID_IBindStatusCallback, riid)) { 216 TRACE("(%p)->(IID_IBindStatusCallback %p)\n", This, ppv); 217 *ppv = &This->IBindStatusCallback_iface; 218 }else { 219 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv); 220 *ppv = NULL; 221 return E_NOINTERFACE; 222 } 223 224 IUnknown_AddRef((IUnknown*)*ppv); 225 return S_OK; 226 } 227 228 static ULONG WINAPI BindStatusCallback_AddRef(IBindStatusCallback *iface) 229 { 230 MimeHtmlBinding *This = impl_from_IBindStatusCallback(iface); 231 LONG ref = InterlockedIncrement(&This->ref); 232 233 TRACE("(%p) ref=%d\n", This, ref); 234 235 return ref; 236 } 237 238 static ULONG WINAPI BindStatusCallback_Release(IBindStatusCallback *iface) 239 { 240 MimeHtmlBinding *This = impl_from_IBindStatusCallback(iface); 241 LONG ref = InterlockedDecrement(&This->ref); 242 243 TRACE("(%p) ref=%d\n", This, ref); 244 245 if(!ref) { 246 if(This->protocol) 247 IInternetProtocol_Release(&This->protocol->IInternetProtocol_iface); 248 if(This->stream) 249 IStream_Release(This->stream); 250 heap_free(This); 251 } 252 253 return ref; 254 } 255 256 static HRESULT WINAPI BindStatusCallback_OnStartBinding(IBindStatusCallback *iface, 257 DWORD dwReserved, IBinding *pib) 258 { 259 MimeHtmlBinding *This = impl_from_IBindStatusCallback(iface); 260 261 TRACE("(%p)->(%x %p)\n", This, dwReserved, pib); 262 263 assert(!This->stream); 264 return CreateStreamOnHGlobal(NULL, TRUE, &This->stream); 265 } 266 267 static HRESULT WINAPI BindStatusCallback_GetPriority(IBindStatusCallback *iface, LONG *pnPriority) 268 { 269 return E_NOTIMPL; 270 } 271 272 static HRESULT WINAPI BindStatusCallback_OnLowResource(IBindStatusCallback *iface, DWORD dwReserved) 273 { 274 return E_NOTIMPL; 275 } 276 277 static HRESULT WINAPI BindStatusCallback_OnProgress(IBindStatusCallback *iface, ULONG ulProgress, 278 ULONG ulProgressMax, ULONG ulStatusCode, LPCWSTR szStatusText) 279 { 280 MimeHtmlBinding *This = impl_from_IBindStatusCallback(iface); 281 TRACE("(%p)->(%u/%u %u %s)\n", This, ulProgress, ulProgressMax, ulStatusCode, debugstr_w(szStatusText)); 282 return S_OK; 283 } 284 285 static HRESULT WINAPI BindStatusCallback_OnStopBinding(IBindStatusCallback *iface, HRESULT hresult, LPCWSTR szError) 286 { 287 MimeHtmlBinding *This = impl_from_IBindStatusCallback(iface); 288 IMimeMessage *mime_message = NULL; 289 290 TRACE("(%p)->(%x %s)\n", This, hresult, debugstr_w(szError)); 291 292 if(SUCCEEDED(hresult)) { 293 hresult = load_mime_message(This->stream, &mime_message); 294 IStream_Release(This->stream); 295 This->stream = NULL; 296 } 297 298 This->status = hresult; 299 300 if(mime_message) 301 on_mime_message_available(This->protocol, mime_message); 302 else 303 report_result(This->protocol, hresult); 304 305 if(mime_message) 306 IMimeMessage_Release(mime_message); 307 IInternetProtocol_Release(&This->protocol->IInternetProtocol_iface); 308 This->protocol = NULL; 309 return S_OK; 310 } 311 312 static HRESULT WINAPI BindStatusCallback_GetBindInfo(IBindStatusCallback *iface, 313 DWORD* grfBINDF, BINDINFO* pbindinfo) 314 { 315 MimeHtmlBinding *This = impl_from_IBindStatusCallback(iface); 316 317 TRACE("(%p)\n", This); 318 319 *grfBINDF = BINDF_ASYNCHRONOUS; 320 return S_OK; 321 } 322 323 static HRESULT WINAPI BindStatusCallback_OnDataAvailable(IBindStatusCallback *iface, DWORD grfBSCF, 324 DWORD dwSize, FORMATETC* pformatetc, STGMEDIUM* pstgmed) 325 { 326 MimeHtmlBinding *This = impl_from_IBindStatusCallback(iface); 327 BYTE buf[4*1024]; 328 DWORD read; 329 HRESULT hres; 330 331 TRACE("(%p)\n", This); 332 333 assert(pstgmed->tymed == TYMED_ISTREAM); 334 335 while(1) { 336 hres = IStream_Read(pstgmed->u.pstm, buf, sizeof(buf), &read); 337 if(FAILED(hres)) 338 return hres; 339 if(!read) 340 break; 341 hres = IStream_Write(This->stream, buf, read, NULL); 342 if(FAILED(hres)) 343 return hres; 344 } 345 return S_OK; 346 } 347 348 static HRESULT WINAPI BindStatusCallback_OnObjectAvailable(IBindStatusCallback *iface, 349 REFIID riid, IUnknown* punk) 350 { 351 ERR("\n"); 352 return E_NOTIMPL; 353 } 354 355 static const IBindStatusCallbackVtbl BindStatusCallbackVtbl = { 356 BindStatusCallback_QueryInterface, 357 BindStatusCallback_AddRef, 358 BindStatusCallback_Release, 359 BindStatusCallback_OnStartBinding, 360 BindStatusCallback_GetPriority, 361 BindStatusCallback_OnLowResource, 362 BindStatusCallback_OnProgress, 363 BindStatusCallback_OnStopBinding, 364 BindStatusCallback_GetBindInfo, 365 BindStatusCallback_OnDataAvailable, 366 BindStatusCallback_OnObjectAvailable 367 }; 368 369 static inline MimeHtmlProtocol *impl_from_IUnknown(IUnknown *iface) 370 { 371 return CONTAINING_RECORD(iface, MimeHtmlProtocol, IUnknown_inner); 372 } 373 374 static HRESULT WINAPI MimeHtmlProtocol_QueryInterface(IUnknown *iface, REFIID riid, void **ppv) 375 { 376 MimeHtmlProtocol *This = impl_from_IUnknown(iface); 377 378 if(IsEqualGUID(&IID_IUnknown, riid)) { 379 TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv); 380 *ppv = &This->IInternetProtocol_iface; 381 }else if(IsEqualGUID(&IID_IInternetProtocolRoot, riid)) { 382 TRACE("(%p)->(IID_IInternetProtocolRoot %p)\n", This, ppv); 383 *ppv = &This->IInternetProtocol_iface; 384 }else if(IsEqualGUID(&IID_IInternetProtocol, riid)) { 385 TRACE("(%p)->(IID_IInternetProtocol %p)\n", This, ppv); 386 *ppv = &This->IInternetProtocol_iface; 387 }else if(IsEqualGUID(&IID_IInternetProtocolInfo, riid)) { 388 TRACE("(%p)->(IID_IInternetProtocolInfo %p)\n", This, ppv); 389 *ppv = &This->IInternetProtocolInfo_iface; 390 }else { 391 FIXME("unknown interface %s\n", debugstr_guid(riid)); 392 *ppv = NULL; 393 return E_NOINTERFACE; 394 } 395 396 IUnknown_AddRef((IUnknown*)*ppv); 397 return S_OK; 398 } 399 400 static ULONG WINAPI MimeHtmlProtocol_AddRef(IUnknown *iface) 401 { 402 MimeHtmlProtocol *This = impl_from_IUnknown(iface); 403 ULONG ref = InterlockedIncrement(&This->ref); 404 405 TRACE("(%p) ref=%d\n", This, ref); 406 407 return ref; 408 } 409 410 static ULONG WINAPI MimeHtmlProtocol_Release(IUnknown *iface) 411 { 412 MimeHtmlProtocol *This = impl_from_IUnknown(iface); 413 ULONG ref = InterlockedDecrement(&This->ref); 414 415 TRACE("(%p) ref=%x\n", This, ref); 416 417 if(!ref) { 418 if(This->sink) 419 IInternetProtocolSink_Release(This->sink); 420 if(This->stream) 421 IStream_Release(This->stream); 422 heap_free(This->location); 423 heap_free(This); 424 } 425 426 return ref; 427 } 428 429 static const IUnknownVtbl MimeHtmlProtocolInnerVtbl = { 430 MimeHtmlProtocol_QueryInterface, 431 MimeHtmlProtocol_AddRef, 432 MimeHtmlProtocol_Release 433 }; 434 435 static inline MimeHtmlProtocol *impl_from_IInternetProtocol(IInternetProtocol *iface) 436 { 437 return CONTAINING_RECORD(iface, MimeHtmlProtocol, IInternetProtocol_iface); 438 } 439 440 static HRESULT WINAPI InternetProtocol_QueryInterface(IInternetProtocol *iface, REFIID riid, void **ppv) 441 { 442 MimeHtmlProtocol *This = impl_from_IInternetProtocol(iface); 443 return IUnknown_QueryInterface(This->outer_unk, riid, ppv); 444 } 445 446 static ULONG WINAPI InternetProtocol_AddRef(IInternetProtocol *iface) 447 { 448 MimeHtmlProtocol *This = impl_from_IInternetProtocol(iface); 449 return IUnknown_AddRef(This->outer_unk); 450 } 451 452 static ULONG WINAPI InternetProtocol_Release(IInternetProtocol *iface) 453 { 454 MimeHtmlProtocol *This = impl_from_IInternetProtocol(iface); 455 return IUnknown_Release(This->outer_unk); 456 } 457 458 static HRESULT WINAPI MimeHtmlProtocol_Start(IInternetProtocol *iface, const WCHAR *szUrl, 459 IInternetProtocolSink* pOIProtSink, IInternetBindInfo* pOIBindInfo, 460 DWORD grfPI, HANDLE_PTR dwReserved) 461 { 462 MimeHtmlProtocol *This = impl_from_IInternetProtocol(iface); 463 BINDINFO bindinfo = { sizeof(bindinfo) }; 464 MimeHtmlBinding *binding; 465 IBindCtx *bind_ctx; 466 IStream *stream; 467 mhtml_url_t url; 468 DWORD bindf = 0; 469 IMoniker *mon; 470 HRESULT hres; 471 472 TRACE("(%p)->(%s %p %p %08x %lx)\n", This, debugstr_w(szUrl), pOIProtSink, pOIBindInfo, grfPI, dwReserved); 473 474 hres = parse_mhtml_url(szUrl, &url); 475 if(FAILED(hres)) 476 return hres; 477 478 if(url.location && !(This->location = heap_strdupW(url.location))) 479 return E_OUTOFMEMORY; 480 481 hres = IInternetBindInfo_GetBindInfo(pOIBindInfo, &bindf, &bindinfo); 482 if(FAILED(hres)) { 483 WARN("GetBindInfo failed: %08x\n", hres); 484 return hres; 485 } 486 if((bindf & (BINDF_ASYNCHRONOUS|BINDF_FROMURLMON|BINDF_NEEDFILE)) != (BINDF_ASYNCHRONOUS|BINDF_FROMURLMON|BINDF_NEEDFILE)) 487 FIXME("unsupported bindf %x\n", bindf); 488 489 IInternetProtocolSink_AddRef(This->sink = pOIProtSink); 490 491 binding = heap_alloc(FIELD_OFFSET(MimeHtmlBinding, url[url.mhtml_len+1])); 492 if(!binding) 493 return E_OUTOFMEMORY; 494 memcpy(binding->url, url.mhtml, url.mhtml_len*sizeof(WCHAR)); 495 binding->url[url.mhtml_len] = 0; 496 497 hres = CreateURLMoniker(NULL, binding->url, &mon); 498 if(FAILED(hres)) { 499 heap_free(binding); 500 return hres; 501 } 502 503 binding->IBindStatusCallback_iface.lpVtbl = &BindStatusCallbackVtbl; 504 binding->ref = 1; 505 binding->status = E_PENDING; 506 binding->stream = NULL; 507 binding->protocol = NULL; 508 509 hres = CreateAsyncBindCtx(0, &binding->IBindStatusCallback_iface, NULL, &bind_ctx); 510 if(FAILED(hres)) { 511 IMoniker_Release(mon); 512 IBindStatusCallback_Release(&binding->IBindStatusCallback_iface); 513 return hres; 514 } 515 516 IInternetProtocol_AddRef(&This->IInternetProtocol_iface); 517 binding->protocol = This; 518 519 hres = IMoniker_BindToStorage(mon, bind_ctx, NULL, &IID_IStream, (void**)&stream); 520 IBindCtx_Release(bind_ctx); 521 IMoniker_Release(mon); 522 if(stream) 523 IStream_Release(stream); 524 hres = binding->status; 525 IBindStatusCallback_Release(&binding->IBindStatusCallback_iface); 526 if(FAILED(hres) && hres != E_PENDING) 527 report_result(This, hres); 528 return hres; 529 } 530 531 static HRESULT WINAPI MimeHtmlProtocol_Continue(IInternetProtocol *iface, PROTOCOLDATA *pProtocolData) 532 { 533 MimeHtmlProtocol *This = impl_from_IInternetProtocol(iface); 534 FIXME("(%p)->(%p)\n", This, pProtocolData); 535 return E_NOTIMPL; 536 } 537 538 static HRESULT WINAPI MimeHtmlProtocol_Abort(IInternetProtocol *iface, HRESULT hrReason, DWORD dwOptions) 539 { 540 MimeHtmlProtocol *This = impl_from_IInternetProtocol(iface); 541 FIXME("(%p)->(%08x %08x)\n", This, hrReason, dwOptions); 542 return E_NOTIMPL; 543 } 544 545 static HRESULT WINAPI MimeHtmlProtocol_Terminate(IInternetProtocol *iface, DWORD dwOptions) 546 { 547 MimeHtmlProtocol *This = impl_from_IInternetProtocol(iface); 548 TRACE("(%p)->(%08x)\n", This, dwOptions); 549 return S_OK; 550 } 551 552 static HRESULT WINAPI MimeHtmlProtocol_Suspend(IInternetProtocol *iface) 553 { 554 MimeHtmlProtocol *This = impl_from_IInternetProtocol(iface); 555 FIXME("(%p)\n", This); 556 return E_NOTIMPL; 557 } 558 559 static HRESULT WINAPI MimeHtmlProtocol_Resume(IInternetProtocol *iface) 560 { 561 MimeHtmlProtocol *This = impl_from_IInternetProtocol(iface); 562 FIXME("(%p)\n", This); 563 return E_NOTIMPL; 564 } 565 566 static HRESULT WINAPI MimeHtmlProtocol_Read(IInternetProtocol *iface, void* pv, ULONG cb, ULONG* pcbRead) 567 { 568 MimeHtmlProtocol *This = impl_from_IInternetProtocol(iface); 569 ULONG read = 0; 570 HRESULT hres; 571 572 TRACE("(%p)->(%p %u %p)\n", This, pv, cb, pcbRead); 573 574 hres = IStream_Read(This->stream, pv, cb, &read); 575 if(pcbRead) 576 *pcbRead = read; 577 if(hres != S_OK) 578 return hres; 579 580 return read ? S_OK : S_FALSE; 581 } 582 583 static HRESULT WINAPI MimeHtmlProtocol_Seek(IInternetProtocol *iface, LARGE_INTEGER dlibMove, 584 DWORD dwOrigin, ULARGE_INTEGER* plibNewPosition) 585 { 586 MimeHtmlProtocol *This = impl_from_IInternetProtocol(iface); 587 FIXME("(%p)->(%d %d %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition); 588 return E_NOTIMPL; 589 } 590 591 static HRESULT WINAPI MimeHtmlProtocol_LockRequest(IInternetProtocol *iface, DWORD dwOptions) 592 { 593 MimeHtmlProtocol *This = impl_from_IInternetProtocol(iface); 594 FIXME("(%p)->(%d)\n", This, dwOptions); 595 return S_OK; 596 } 597 598 static HRESULT WINAPI MimeHtmlProtocol_UnlockRequest(IInternetProtocol *iface) 599 { 600 MimeHtmlProtocol *This = impl_from_IInternetProtocol(iface); 601 FIXME("(%p)\n", This); 602 return S_OK; 603 } 604 605 static const IInternetProtocolVtbl MimeHtmlProtocolVtbl = { 606 InternetProtocol_QueryInterface, 607 InternetProtocol_AddRef, 608 InternetProtocol_Release, 609 MimeHtmlProtocol_Start, 610 MimeHtmlProtocol_Continue, 611 MimeHtmlProtocol_Abort, 612 MimeHtmlProtocol_Terminate, 613 MimeHtmlProtocol_Suspend, 614 MimeHtmlProtocol_Resume, 615 MimeHtmlProtocol_Read, 616 MimeHtmlProtocol_Seek, 617 MimeHtmlProtocol_LockRequest, 618 MimeHtmlProtocol_UnlockRequest 619 }; 620 621 static inline MimeHtmlProtocol *impl_from_IInternetProtocolInfo(IInternetProtocolInfo *iface) 622 { 623 return CONTAINING_RECORD(iface, MimeHtmlProtocol, IInternetProtocolInfo_iface); 624 } 625 626 static HRESULT WINAPI MimeHtmlProtocolInfo_QueryInterface(IInternetProtocolInfo *iface, REFIID riid, void **ppv) 627 { 628 MimeHtmlProtocol *This = impl_from_IInternetProtocolInfo(iface); 629 return IUnknown_QueryInterface(This->outer_unk, riid, ppv); 630 } 631 632 static ULONG WINAPI MimeHtmlProtocolInfo_AddRef(IInternetProtocolInfo *iface) 633 { 634 MimeHtmlProtocol *This = impl_from_IInternetProtocolInfo(iface); 635 return IUnknown_AddRef(This->outer_unk); 636 } 637 638 static ULONG WINAPI MimeHtmlProtocolInfo_Release(IInternetProtocolInfo *iface) 639 { 640 MimeHtmlProtocol *This = impl_from_IInternetProtocolInfo(iface); 641 return IUnknown_Release(This->outer_unk); 642 } 643 644 static HRESULT WINAPI MimeHtmlProtocolInfo_ParseUrl(IInternetProtocolInfo *iface, LPCWSTR pwzUrl, 645 PARSEACTION ParseAction, DWORD dwParseFlags, LPWSTR pwzResult, DWORD cchResult, 646 DWORD* pcchResult, DWORD dwReserved) 647 { 648 MimeHtmlProtocol *This = impl_from_IInternetProtocolInfo(iface); 649 FIXME("(%p)->(%s %d %x %p %d %p %d)\n", This, debugstr_w(pwzUrl), ParseAction, 650 dwParseFlags, pwzResult, cchResult, pcchResult, dwReserved); 651 return INET_E_DEFAULT_ACTION; 652 } 653 654 static HRESULT WINAPI MimeHtmlProtocolInfo_CombineUrl(IInternetProtocolInfo *iface, 655 LPCWSTR pwzBaseUrl, LPCWSTR pwzRelativeUrl, DWORD dwCombineFlags, LPWSTR pwzResult, 656 DWORD cchResult, DWORD* pcchResult, DWORD dwReserved) 657 { 658 MimeHtmlProtocol *This = impl_from_IInternetProtocolInfo(iface); 659 size_t len = ARRAY_SIZE(mhtml_prefixW); 660 mhtml_url_t url; 661 WCHAR *p; 662 HRESULT hres; 663 664 TRACE("(%p)->(%s %s %08x %p %d %p %d)\n", This, debugstr_w(pwzBaseUrl), 665 debugstr_w(pwzRelativeUrl), dwCombineFlags, pwzResult, cchResult, 666 pcchResult, dwReserved); 667 668 hres = parse_mhtml_url(pwzBaseUrl, &url); 669 if(FAILED(hres)) 670 return hres; 671 672 if(!_wcsnicmp(pwzRelativeUrl, mhtml_prefixW, ARRAY_SIZE(mhtml_prefixW))) { 673 FIXME("Relative URL is mhtml protocol\n"); 674 return INET_E_USE_DEFAULT_PROTOCOLHANDLER; 675 } 676 677 len += url.mhtml_len; 678 if(*pwzRelativeUrl) 679 len += lstrlenW(pwzRelativeUrl) + ARRAY_SIZE(mhtml_separatorW); 680 if(len >= cchResult) { 681 *pcchResult = 0; 682 return E_FAIL; 683 } 684 685 memcpy(pwzResult, mhtml_prefixW, sizeof(mhtml_prefixW)); 686 p = pwzResult + ARRAY_SIZE(mhtml_prefixW); 687 memcpy(p, url.mhtml, url.mhtml_len*sizeof(WCHAR)); 688 p += url.mhtml_len; 689 if(*pwzRelativeUrl) { 690 memcpy(p, mhtml_separatorW, sizeof(mhtml_separatorW)); 691 p += ARRAY_SIZE(mhtml_separatorW); 692 lstrcpyW(p, pwzRelativeUrl); 693 }else { 694 *p = 0; 695 } 696 697 *pcchResult = len; 698 return S_OK; 699 } 700 701 static HRESULT WINAPI MimeHtmlProtocolInfo_CompareUrl(IInternetProtocolInfo *iface, LPCWSTR pwzUrl1, 702 LPCWSTR pwzUrl2, DWORD dwCompareFlags) 703 { 704 MimeHtmlProtocol *This = impl_from_IInternetProtocolInfo(iface); 705 FIXME("(%p)->(%s %s %08x)\n", This, debugstr_w(pwzUrl1), debugstr_w(pwzUrl2), dwCompareFlags); 706 return E_NOTIMPL; 707 } 708 709 static HRESULT WINAPI MimeHtmlProtocolInfo_QueryInfo(IInternetProtocolInfo *iface, LPCWSTR pwzUrl, 710 QUERYOPTION QueryOption, DWORD dwQueryFlags, LPVOID pBuffer, DWORD cbBuffer, DWORD* pcbBuf, 711 DWORD dwReserved) 712 { 713 MimeHtmlProtocol *This = impl_from_IInternetProtocolInfo(iface); 714 FIXME("(%p)->(%s %08x %08x %p %d %p %d)\n", This, debugstr_w(pwzUrl), QueryOption, dwQueryFlags, pBuffer, 715 cbBuffer, pcbBuf, dwReserved); 716 return INET_E_USE_DEFAULT_PROTOCOLHANDLER; 717 } 718 719 static const IInternetProtocolInfoVtbl MimeHtmlProtocolInfoVtbl = { 720 MimeHtmlProtocolInfo_QueryInterface, 721 MimeHtmlProtocolInfo_AddRef, 722 MimeHtmlProtocolInfo_Release, 723 MimeHtmlProtocolInfo_ParseUrl, 724 MimeHtmlProtocolInfo_CombineUrl, 725 MimeHtmlProtocolInfo_CompareUrl, 726 MimeHtmlProtocolInfo_QueryInfo 727 }; 728 729 HRESULT MimeHtmlProtocol_create(IUnknown *outer, void **obj) 730 { 731 MimeHtmlProtocol *protocol; 732 733 protocol = heap_alloc(sizeof(*protocol)); 734 if(!protocol) 735 return E_OUTOFMEMORY; 736 737 protocol->IUnknown_inner.lpVtbl = &MimeHtmlProtocolInnerVtbl; 738 protocol->IInternetProtocol_iface.lpVtbl = &MimeHtmlProtocolVtbl; 739 protocol->IInternetProtocolInfo_iface.lpVtbl = &MimeHtmlProtocolInfoVtbl; 740 protocol->ref = 1; 741 protocol->outer_unk = outer ? outer : &protocol->IUnknown_inner; 742 protocol->location = NULL; 743 protocol->stream = NULL; 744 protocol->sink = NULL; 745 746 *obj = &protocol->IUnknown_inner; 747 return S_OK; 748 } 749