kernel32: Don't clear WINEDEBUG in the debugger process if +winedbg is set.
[wine.git] / dlls / inetcomm / protocol.c
blobc6a59fee7c3ff1ec9073c5c6f485a3e7cb819861
1 /*
2 * Copyright 2017 Jacek Caban for CodeWeavers
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.
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.
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
19 #define COBJMACROS
20 #define NONAMELESSUNION
22 #include <assert.h>
24 #include "mimeole.h"
25 #include "inetcomm_private.h"
27 #include "wine/debug.h"
28 #include "wine/heap.h"
29 #include "wine/unicode.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(inetcomm);
33 typedef struct {
34 IUnknown IUnknown_inner;
35 IInternetProtocol IInternetProtocol_iface;
36 IInternetProtocolInfo IInternetProtocolInfo_iface;
38 LONG ref;
39 IUnknown *outer_unk;
41 WCHAR *location;
42 IStream *stream;
43 IInternetProtocolSink *sink;
44 } MimeHtmlProtocol;
46 typedef struct {
47 const WCHAR *mhtml;
48 size_t mhtml_len;
49 const WCHAR *location;
50 } mhtml_url_t;
52 typedef struct {
53 IBindStatusCallback IBindStatusCallback_iface;
55 LONG ref;
57 MimeHtmlProtocol *protocol;
58 HRESULT status;
59 IStream *stream;
60 WCHAR url[1];
61 } MimeHtmlBinding;
63 static const WCHAR mhtml_prefixW[] = {'m','h','t','m','l',':'};
64 static const WCHAR mhtml_separatorW[] = {'!','x','-','u','s','c',':'};
66 static inline LPWSTR heap_strdupW(LPCWSTR str)
68 LPWSTR ret = NULL;
70 if(str) {
71 DWORD size;
73 size = (strlenW(str)+1)*sizeof(WCHAR);
74 ret = heap_alloc(size);
75 if(ret)
76 memcpy(ret, str, size);
79 return ret;
82 static HRESULT parse_mhtml_url(const WCHAR *url, mhtml_url_t *r)
84 const WCHAR *p;
86 if(strncmpiW(url, mhtml_prefixW, ARRAY_SIZE(mhtml_prefixW)))
87 return E_FAIL;
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);
102 r->location = p;
103 return S_OK;
106 static HRESULT report_result(MimeHtmlProtocol *protocol, HRESULT result)
108 if(protocol->sink) {
109 IInternetProtocolSink_ReportResult(protocol->sink, result, ERROR_SUCCESS, NULL);
110 IInternetProtocolSink_Release(protocol->sink);
111 protocol->sink = NULL;
114 return result;
117 static HRESULT on_mime_message_available(MimeHtmlProtocol *protocol, IMimeMessage *mime_message)
119 FINDBODY find = {NULL};
120 IMimeBody *mime_body;
121 PROPVARIANT value;
122 HBODY body;
123 HRESULT hres;
125 hres = IMimeMessage_FindFirst(mime_message, &find, &body);
126 if(FAILED(hres))
127 return report_result(protocol, hres);
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);
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);
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);
156 hres = IMimeMessage_BindToObject(mime_message, body, &IID_IMimeBody, (void**)&mime_body);
157 if(FAILED(hres))
158 return report_result(protocol, hres);
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);
167 /* FIXME: Create and report cache file. */
169 hres = IMimeBody_GetData(mime_body, IET_DECODED, &protocol->stream);
170 if(FAILED(hres))
171 return report_result(protocol, hres);
173 IInternetProtocolSink_ReportData(protocol->sink, BSCF_FIRSTDATANOTIFICATION
174 | BSCF_INTERMEDIATEDATANOTIFICATION
175 | BSCF_LASTDATANOTIFICATION
176 | BSCF_DATAFULLYAVAILABLE
177 | BSCF_AVAILABLEDATASIZEUNKNOWN, 0, 0);
179 return report_result(protocol, S_OK);
182 static HRESULT load_mime_message(IStream *stream, IMimeMessage **ret)
184 IMimeMessage *mime_message;
185 HRESULT hres;
187 hres = MimeMessage_create(NULL, (void**)&mime_message);
188 if(FAILED(hres))
189 return hres;
191 IMimeMessage_InitNew(mime_message);
193 hres = IMimeMessage_Load(mime_message, stream);
194 if(FAILED(hres)) {
195 IMimeMessage_Release(mime_message);
196 return hres;
199 *ret = mime_message;
200 return S_OK;
203 static inline MimeHtmlBinding *impl_from_IBindStatusCallback(IBindStatusCallback *iface)
205 return CONTAINING_RECORD(iface, MimeHtmlBinding, IBindStatusCallback_iface);
208 static HRESULT WINAPI BindStatusCallback_QueryInterface(IBindStatusCallback *iface,
209 REFIID riid, void **ppv)
211 MimeHtmlBinding *This = impl_from_IBindStatusCallback(iface);
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;
225 IUnknown_AddRef((IUnknown*)*ppv);
226 return S_OK;
229 static ULONG WINAPI BindStatusCallback_AddRef(IBindStatusCallback *iface)
231 MimeHtmlBinding *This = impl_from_IBindStatusCallback(iface);
232 LONG ref = InterlockedIncrement(&This->ref);
234 TRACE("(%p) ref=%d\n", This, ref);
236 return ref;
239 static ULONG WINAPI BindStatusCallback_Release(IBindStatusCallback *iface)
241 MimeHtmlBinding *This = impl_from_IBindStatusCallback(iface);
242 LONG ref = InterlockedDecrement(&This->ref);
244 TRACE("(%p) ref=%d\n", This, ref);
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);
254 return ref;
257 static HRESULT WINAPI BindStatusCallback_OnStartBinding(IBindStatusCallback *iface,
258 DWORD dwReserved, IBinding *pib)
260 MimeHtmlBinding *This = impl_from_IBindStatusCallback(iface);
262 TRACE("(%p)->(%x %p)\n", This, dwReserved, pib);
264 assert(!This->stream);
265 return CreateStreamOnHGlobal(NULL, TRUE, &This->stream);
268 static HRESULT WINAPI BindStatusCallback_GetPriority(IBindStatusCallback *iface, LONG *pnPriority)
270 return E_NOTIMPL;
273 static HRESULT WINAPI BindStatusCallback_OnLowResource(IBindStatusCallback *iface, DWORD dwReserved)
275 return E_NOTIMPL;
278 static HRESULT WINAPI BindStatusCallback_OnProgress(IBindStatusCallback *iface, ULONG ulProgress,
279 ULONG ulProgressMax, ULONG ulStatusCode, LPCWSTR szStatusText)
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;
286 static HRESULT WINAPI BindStatusCallback_OnStopBinding(IBindStatusCallback *iface, HRESULT hresult, LPCWSTR szError)
288 MimeHtmlBinding *This = impl_from_IBindStatusCallback(iface);
289 IMimeMessage *mime_message = NULL;
291 TRACE("(%p)->(%x %s)\n", This, hresult, debugstr_w(szError));
293 if(SUCCEEDED(hresult)) {
294 hresult = load_mime_message(This->stream, &mime_message);
295 IStream_Release(This->stream);
296 This->stream = NULL;
299 This->status = hresult;
301 if(mime_message)
302 on_mime_message_available(This->protocol, mime_message);
303 else
304 report_result(This->protocol, hresult);
306 if(mime_message)
307 IMimeMessage_Release(mime_message);
308 IInternetProtocol_Release(&This->protocol->IInternetProtocol_iface);
309 This->protocol = NULL;
310 return S_OK;
313 static HRESULT WINAPI BindStatusCallback_GetBindInfo(IBindStatusCallback *iface,
314 DWORD* grfBINDF, BINDINFO* pbindinfo)
316 MimeHtmlBinding *This = impl_from_IBindStatusCallback(iface);
318 TRACE("(%p)\n", This);
320 *grfBINDF = BINDF_ASYNCHRONOUS;
321 return S_OK;
324 static HRESULT WINAPI BindStatusCallback_OnDataAvailable(IBindStatusCallback *iface, DWORD grfBSCF,
325 DWORD dwSize, FORMATETC* pformatetc, STGMEDIUM* pstgmed)
327 MimeHtmlBinding *This = impl_from_IBindStatusCallback(iface);
328 BYTE buf[4*1024];
329 DWORD read;
330 HRESULT hres;
332 TRACE("(%p)\n", This);
334 assert(pstgmed->tymed == TYMED_ISTREAM);
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;
346 return S_OK;
349 static HRESULT WINAPI BindStatusCallback_OnObjectAvailable(IBindStatusCallback *iface,
350 REFIID riid, IUnknown* punk)
352 ERR("\n");
353 return E_NOTIMPL;
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
370 static inline MimeHtmlProtocol *impl_from_IUnknown(IUnknown *iface)
372 return CONTAINING_RECORD(iface, MimeHtmlProtocol, IUnknown_inner);
375 static HRESULT WINAPI MimeHtmlProtocol_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
377 MimeHtmlProtocol *This = impl_from_IUnknown(iface);
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;
397 IUnknown_AddRef((IUnknown*)*ppv);
398 return S_OK;
401 static ULONG WINAPI MimeHtmlProtocol_AddRef(IUnknown *iface)
403 MimeHtmlProtocol *This = impl_from_IUnknown(iface);
404 ULONG ref = InterlockedIncrement(&This->ref);
406 TRACE("(%p) ref=%d\n", This, ref);
408 return ref;
411 static ULONG WINAPI MimeHtmlProtocol_Release(IUnknown *iface)
413 MimeHtmlProtocol *This = impl_from_IUnknown(iface);
414 ULONG ref = InterlockedDecrement(&This->ref);
416 TRACE("(%p) ref=%x\n", This, ref);
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);
427 return ref;
430 static const IUnknownVtbl MimeHtmlProtocolInnerVtbl = {
431 MimeHtmlProtocol_QueryInterface,
432 MimeHtmlProtocol_AddRef,
433 MimeHtmlProtocol_Release
436 static inline MimeHtmlProtocol *impl_from_IInternetProtocol(IInternetProtocol *iface)
438 return CONTAINING_RECORD(iface, MimeHtmlProtocol, IInternetProtocol_iface);
441 static HRESULT WINAPI InternetProtocol_QueryInterface(IInternetProtocol *iface, REFIID riid, void **ppv)
443 MimeHtmlProtocol *This = impl_from_IInternetProtocol(iface);
444 return IUnknown_QueryInterface(This->outer_unk, riid, ppv);
447 static ULONG WINAPI InternetProtocol_AddRef(IInternetProtocol *iface)
449 MimeHtmlProtocol *This = impl_from_IInternetProtocol(iface);
450 return IUnknown_AddRef(This->outer_unk);
453 static ULONG WINAPI InternetProtocol_Release(IInternetProtocol *iface)
455 MimeHtmlProtocol *This = impl_from_IInternetProtocol(iface);
456 return IUnknown_Release(This->outer_unk);
459 static HRESULT WINAPI MimeHtmlProtocol_Start(IInternetProtocol *iface, const WCHAR *szUrl,
460 IInternetProtocolSink* pOIProtSink, IInternetBindInfo* pOIBindInfo,
461 DWORD grfPI, HANDLE_PTR dwReserved)
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;
473 TRACE("(%p)->(%s %p %p %08x %lx)\n", This, debugstr_w(szUrl), pOIProtSink, pOIBindInfo, grfPI, dwReserved);
475 hres = parse_mhtml_url(szUrl, &url);
476 if(FAILED(hres))
477 return hres;
479 if(url.location && !(This->location = heap_strdupW(url.location)))
480 return E_OUTOFMEMORY;
482 hres = IInternetBindInfo_GetBindInfo(pOIBindInfo, &bindf, &bindinfo);
483 if(FAILED(hres)) {
484 WARN("GetBindInfo failed: %08x\n", hres);
485 return hres;
487 if((bindf & (BINDF_ASYNCHRONOUS|BINDF_FROMURLMON|BINDF_NEEDFILE)) != (BINDF_ASYNCHRONOUS|BINDF_FROMURLMON|BINDF_NEEDFILE))
488 FIXME("unsupported bindf %x\n", bindf);
490 IInternetProtocolSink_AddRef(This->sink = pOIProtSink);
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;
498 hres = CreateURLMoniker(NULL, binding->url, &mon);
499 if(FAILED(hres)) {
500 heap_free(binding);
501 return hres;
504 binding->IBindStatusCallback_iface.lpVtbl = &BindStatusCallbackVtbl;
505 binding->ref = 1;
506 binding->status = E_PENDING;
507 binding->stream = NULL;
508 binding->protocol = NULL;
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;
517 IInternetProtocol_AddRef(&This->IInternetProtocol_iface);
518 binding->protocol = This;
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;
532 static HRESULT WINAPI MimeHtmlProtocol_Continue(IInternetProtocol *iface, PROTOCOLDATA *pProtocolData)
534 MimeHtmlProtocol *This = impl_from_IInternetProtocol(iface);
535 FIXME("(%p)->(%p)\n", This, pProtocolData);
536 return E_NOTIMPL;
539 static HRESULT WINAPI MimeHtmlProtocol_Abort(IInternetProtocol *iface, HRESULT hrReason, DWORD dwOptions)
541 MimeHtmlProtocol *This = impl_from_IInternetProtocol(iface);
542 FIXME("(%p)->(%08x %08x)\n", This, hrReason, dwOptions);
543 return E_NOTIMPL;
546 static HRESULT WINAPI MimeHtmlProtocol_Terminate(IInternetProtocol *iface, DWORD dwOptions)
548 MimeHtmlProtocol *This = impl_from_IInternetProtocol(iface);
549 TRACE("(%p)->(%08x)\n", This, dwOptions);
550 return S_OK;
553 static HRESULT WINAPI MimeHtmlProtocol_Suspend(IInternetProtocol *iface)
555 MimeHtmlProtocol *This = impl_from_IInternetProtocol(iface);
556 FIXME("(%p)\n", This);
557 return E_NOTIMPL;
560 static HRESULT WINAPI MimeHtmlProtocol_Resume(IInternetProtocol *iface)
562 MimeHtmlProtocol *This = impl_from_IInternetProtocol(iface);
563 FIXME("(%p)\n", This);
564 return E_NOTIMPL;
567 static HRESULT WINAPI MimeHtmlProtocol_Read(IInternetProtocol *iface, void* pv, ULONG cb, ULONG* pcbRead)
569 MimeHtmlProtocol *This = impl_from_IInternetProtocol(iface);
570 ULONG read = 0;
571 HRESULT hres;
573 TRACE("(%p)->(%p %u %p)\n", This, pv, cb, pcbRead);
575 hres = IStream_Read(This->stream, pv, cb, &read);
576 if(pcbRead)
577 *pcbRead = read;
578 if(hres != S_OK)
579 return hres;
581 return read ? S_OK : S_FALSE;
584 static HRESULT WINAPI MimeHtmlProtocol_Seek(IInternetProtocol *iface, LARGE_INTEGER dlibMove,
585 DWORD dwOrigin, ULARGE_INTEGER* plibNewPosition)
587 MimeHtmlProtocol *This = impl_from_IInternetProtocol(iface);
588 FIXME("(%p)->(%d %d %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
589 return E_NOTIMPL;
592 static HRESULT WINAPI MimeHtmlProtocol_LockRequest(IInternetProtocol *iface, DWORD dwOptions)
594 MimeHtmlProtocol *This = impl_from_IInternetProtocol(iface);
595 FIXME("(%p)->(%d)\n", This, dwOptions);
596 return S_OK;
599 static HRESULT WINAPI MimeHtmlProtocol_UnlockRequest(IInternetProtocol *iface)
601 MimeHtmlProtocol *This = impl_from_IInternetProtocol(iface);
602 FIXME("(%p)\n", This);
603 return S_OK;
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
622 static inline MimeHtmlProtocol *impl_from_IInternetProtocolInfo(IInternetProtocolInfo *iface)
624 return CONTAINING_RECORD(iface, MimeHtmlProtocol, IInternetProtocolInfo_iface);
627 static HRESULT WINAPI MimeHtmlProtocolInfo_QueryInterface(IInternetProtocolInfo *iface, REFIID riid, void **ppv)
629 MimeHtmlProtocol *This = impl_from_IInternetProtocolInfo(iface);
630 return IUnknown_QueryInterface(This->outer_unk, riid, ppv);
633 static ULONG WINAPI MimeHtmlProtocolInfo_AddRef(IInternetProtocolInfo *iface)
635 MimeHtmlProtocol *This = impl_from_IInternetProtocolInfo(iface);
636 return IUnknown_AddRef(This->outer_unk);
639 static ULONG WINAPI MimeHtmlProtocolInfo_Release(IInternetProtocolInfo *iface)
641 MimeHtmlProtocol *This = impl_from_IInternetProtocolInfo(iface);
642 return IUnknown_Release(This->outer_unk);
645 static HRESULT WINAPI MimeHtmlProtocolInfo_ParseUrl(IInternetProtocolInfo *iface, LPCWSTR pwzUrl,
646 PARSEACTION ParseAction, DWORD dwParseFlags, LPWSTR pwzResult, DWORD cchResult,
647 DWORD* pcchResult, DWORD dwReserved)
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;
655 static HRESULT WINAPI MimeHtmlProtocolInfo_CombineUrl(IInternetProtocolInfo *iface,
656 LPCWSTR pwzBaseUrl, LPCWSTR pwzRelativeUrl, DWORD dwCombineFlags, LPWSTR pwzResult,
657 DWORD cchResult, DWORD* pcchResult, DWORD dwReserved)
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;
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);
669 hres = parse_mhtml_url(pwzBaseUrl, &url);
670 if(FAILED(hres))
671 return hres;
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;
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;
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;
698 *pcchResult = len;
699 return S_OK;
702 static HRESULT WINAPI MimeHtmlProtocolInfo_CompareUrl(IInternetProtocolInfo *iface, LPCWSTR pwzUrl1,
703 LPCWSTR pwzUrl2, DWORD dwCompareFlags)
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;
710 static HRESULT WINAPI MimeHtmlProtocolInfo_QueryInfo(IInternetProtocolInfo *iface, LPCWSTR pwzUrl,
711 QUERYOPTION QueryOption, DWORD dwQueryFlags, LPVOID pBuffer, DWORD cbBuffer, DWORD* pcbBuf,
712 DWORD dwReserved)
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;
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
730 HRESULT MimeHtmlProtocol_create(IUnknown *outer, void **obj)
732 MimeHtmlProtocol *protocol;
734 protocol = heap_alloc(sizeof(*protocol));
735 if(!protocol)
736 return E_OUTOFMEMORY;
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;
747 *obj = &protocol->IUnknown_inner;
748 return S_OK;