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