winecoreaudio: Remove GetAudioSessionWrapper.
[wine.git] / dlls / inetcomm / protocol.c
blob155adace482d9889942b9a6dd9058ef21ea9e614
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
21 #include <assert.h>
23 #include "mimeole.h"
24 #include "inetcomm_private.h"
26 #include "wine/debug.h"
28 WINE_DEFAULT_DEBUG_CHANNEL(inetcomm);
30 typedef struct {
31 IUnknown IUnknown_inner;
32 IInternetProtocol IInternetProtocol_iface;
33 IInternetProtocolInfo IInternetProtocolInfo_iface;
35 LONG ref;
36 IUnknown *outer_unk;
38 WCHAR *location;
39 IStream *stream;
40 IInternetProtocolSink *sink;
41 } MimeHtmlProtocol;
43 typedef struct {
44 const WCHAR *mhtml;
45 size_t mhtml_len;
46 const WCHAR *location;
47 } mhtml_url_t;
49 typedef struct {
50 IBindStatusCallback IBindStatusCallback_iface;
52 LONG ref;
54 MimeHtmlProtocol *protocol;
55 HRESULT status;
56 IStream *stream;
57 WCHAR url[1];
58 } MimeHtmlBinding;
60 static const WCHAR mhtml_prefixW[] = L"mhtml:";
61 static const WCHAR mhtml_separatorW[] = L"!x-usc:";
63 static HRESULT parse_mhtml_url(const WCHAR *url, mhtml_url_t *r)
65 const WCHAR *p;
67 if(wcsnicmp(url, mhtml_prefixW, lstrlenW(mhtml_prefixW)))
68 return E_FAIL;
70 r->mhtml = url + lstrlenW(mhtml_prefixW);
71 p = wcschr(r->mhtml, '!');
72 if(p) {
73 r->mhtml_len = p - r->mhtml;
74 /* FIXME: We handle '!' and '!x-usc:' in URLs as the same thing. Those should not be the same. */
75 if(!wcsncmp(p, mhtml_separatorW, lstrlenW(mhtml_separatorW)))
76 p += lstrlenW(mhtml_separatorW);
77 else
78 p++;
79 }else {
80 r->mhtml_len = lstrlenW(r->mhtml);
83 r->location = p;
84 return S_OK;
87 static HRESULT report_result(MimeHtmlProtocol *protocol, HRESULT result)
89 if(protocol->sink) {
90 IInternetProtocolSink_ReportResult(protocol->sink, result, ERROR_SUCCESS, NULL);
91 IInternetProtocolSink_Release(protocol->sink);
92 protocol->sink = NULL;
95 return result;
98 static HRESULT on_mime_message_available(MimeHtmlProtocol *protocol, IMimeMessage *mime_message)
100 FINDBODY find = {NULL};
101 IMimeBody *mime_body;
102 PROPVARIANT value;
103 HBODY body;
104 HRESULT hres;
106 hres = IMimeMessage_FindFirst(mime_message, &find, &body);
107 if(FAILED(hres))
108 return report_result(protocol, hres);
110 if(protocol->location) {
111 BOOL found = FALSE;
112 do {
113 hres = IMimeMessage_FindNext(mime_message, &find, &body);
114 if(FAILED(hres)) {
115 WARN("location %s not found\n", debugstr_w(protocol->location));
116 return report_result(protocol, hres);
119 value.vt = VT_LPWSTR;
120 hres = IMimeMessage_GetBodyProp(mime_message, body, "content-location", 0, &value);
121 if(hres == MIME_E_NOT_FOUND)
122 continue;
123 if(FAILED(hres))
124 return report_result(protocol, hres);
126 found = !lstrcmpW(protocol->location, value.pwszVal);
127 PropVariantClear(&value);
128 }while(!found);
129 }else {
130 hres = IMimeMessage_FindNext(mime_message, &find, &body);
131 if(FAILED(hres)) {
132 WARN("location %s not found\n", debugstr_w(protocol->location));
133 return report_result(protocol, hres);
137 hres = IMimeMessage_BindToObject(mime_message, body, &IID_IMimeBody, (void**)&mime_body);
138 if(FAILED(hres))
139 return report_result(protocol, hres);
141 value.vt = VT_LPWSTR;
142 hres = IMimeBody_GetProp(mime_body, "content-type", 0, &value);
143 if(SUCCEEDED(hres)) {
144 hres = IInternetProtocolSink_ReportProgress(protocol->sink, BINDSTATUS_MIMETYPEAVAILABLE, value.pwszVal);
145 PropVariantClear(&value);
148 /* FIXME: Create and report cache file. */
150 hres = IMimeBody_GetData(mime_body, IET_DECODED, &protocol->stream);
151 if(FAILED(hres))
152 return report_result(protocol, hres);
154 IInternetProtocolSink_ReportData(protocol->sink, BSCF_FIRSTDATANOTIFICATION
155 | BSCF_INTERMEDIATEDATANOTIFICATION
156 | BSCF_LASTDATANOTIFICATION
157 | BSCF_DATAFULLYAVAILABLE
158 | BSCF_AVAILABLEDATASIZEUNKNOWN, 0, 0);
160 return report_result(protocol, S_OK);
163 static HRESULT load_mime_message(IStream *stream, IMimeMessage **ret)
165 IMimeMessage *mime_message;
166 HRESULT hres;
168 hres = MimeMessage_create(NULL, (void**)&mime_message);
169 if(FAILED(hres))
170 return hres;
172 IMimeMessage_InitNew(mime_message);
174 hres = IMimeMessage_Load(mime_message, stream);
175 if(FAILED(hres)) {
176 IMimeMessage_Release(mime_message);
177 return hres;
180 *ret = mime_message;
181 return S_OK;
184 static inline MimeHtmlBinding *impl_from_IBindStatusCallback(IBindStatusCallback *iface)
186 return CONTAINING_RECORD(iface, MimeHtmlBinding, IBindStatusCallback_iface);
189 static HRESULT WINAPI BindStatusCallback_QueryInterface(IBindStatusCallback *iface,
190 REFIID riid, void **ppv)
192 MimeHtmlBinding *This = impl_from_IBindStatusCallback(iface);
194 if(IsEqualGUID(&IID_IUnknown, riid)) {
195 TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
196 *ppv = &This->IBindStatusCallback_iface;
197 }else if(IsEqualGUID(&IID_IBindStatusCallback, riid)) {
198 TRACE("(%p)->(IID_IBindStatusCallback %p)\n", This, ppv);
199 *ppv = &This->IBindStatusCallback_iface;
200 }else {
201 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
202 *ppv = NULL;
203 return E_NOINTERFACE;
206 IUnknown_AddRef((IUnknown*)*ppv);
207 return S_OK;
210 static ULONG WINAPI BindStatusCallback_AddRef(IBindStatusCallback *iface)
212 MimeHtmlBinding *This = impl_from_IBindStatusCallback(iface);
213 LONG ref = InterlockedIncrement(&This->ref);
215 TRACE("(%p) ref=%ld\n", This, ref);
217 return ref;
220 static ULONG WINAPI BindStatusCallback_Release(IBindStatusCallback *iface)
222 MimeHtmlBinding *This = impl_from_IBindStatusCallback(iface);
223 LONG ref = InterlockedDecrement(&This->ref);
225 TRACE("(%p) ref=%ld\n", This, ref);
227 if(!ref) {
228 if(This->protocol)
229 IInternetProtocol_Release(&This->protocol->IInternetProtocol_iface);
230 if(This->stream)
231 IStream_Release(This->stream);
232 free(This);
235 return ref;
238 static HRESULT WINAPI BindStatusCallback_OnStartBinding(IBindStatusCallback *iface,
239 DWORD dwReserved, IBinding *pib)
241 MimeHtmlBinding *This = impl_from_IBindStatusCallback(iface);
243 TRACE("(%p)->(%lx %p)\n", This, dwReserved, pib);
245 assert(!This->stream);
246 return CreateStreamOnHGlobal(NULL, TRUE, &This->stream);
249 static HRESULT WINAPI BindStatusCallback_GetPriority(IBindStatusCallback *iface, LONG *pnPriority)
251 return E_NOTIMPL;
254 static HRESULT WINAPI BindStatusCallback_OnLowResource(IBindStatusCallback *iface, DWORD dwReserved)
256 return E_NOTIMPL;
259 static HRESULT WINAPI BindStatusCallback_OnProgress(IBindStatusCallback *iface, ULONG ulProgress,
260 ULONG ulProgressMax, ULONG ulStatusCode, LPCWSTR szStatusText)
262 MimeHtmlBinding *This = impl_from_IBindStatusCallback(iface);
263 TRACE("(%p)->(%lu/%lu %lu %s)\n", This, ulProgress, ulProgressMax, ulStatusCode, debugstr_w(szStatusText));
264 return S_OK;
267 static HRESULT WINAPI BindStatusCallback_OnStopBinding(IBindStatusCallback *iface, HRESULT hresult, LPCWSTR szError)
269 MimeHtmlBinding *This = impl_from_IBindStatusCallback(iface);
270 IMimeMessage *mime_message = NULL;
272 TRACE("(%p)->(%lx %s)\n", This, hresult, debugstr_w(szError));
274 if(SUCCEEDED(hresult)) {
275 hresult = load_mime_message(This->stream, &mime_message);
276 IStream_Release(This->stream);
277 This->stream = NULL;
280 This->status = hresult;
282 if(mime_message)
283 on_mime_message_available(This->protocol, mime_message);
284 else
285 report_result(This->protocol, hresult);
287 if(mime_message)
288 IMimeMessage_Release(mime_message);
289 IInternetProtocol_Release(&This->protocol->IInternetProtocol_iface);
290 This->protocol = NULL;
291 return S_OK;
294 static HRESULT WINAPI BindStatusCallback_GetBindInfo(IBindStatusCallback *iface,
295 DWORD* grfBINDF, BINDINFO* pbindinfo)
297 MimeHtmlBinding *This = impl_from_IBindStatusCallback(iface);
299 TRACE("(%p)\n", This);
301 *grfBINDF = BINDF_ASYNCHRONOUS;
302 return S_OK;
305 static HRESULT WINAPI BindStatusCallback_OnDataAvailable(IBindStatusCallback *iface, DWORD grfBSCF,
306 DWORD dwSize, FORMATETC* pformatetc, STGMEDIUM* pstgmed)
308 MimeHtmlBinding *This = impl_from_IBindStatusCallback(iface);
309 BYTE buf[4*1024];
310 DWORD read;
311 HRESULT hres;
313 TRACE("(%p)\n", This);
315 assert(pstgmed->tymed == TYMED_ISTREAM);
317 while(1) {
318 hres = IStream_Read(pstgmed->pstm, buf, sizeof(buf), &read);
319 if(FAILED(hres))
320 return hres;
321 if(!read)
322 break;
323 hres = IStream_Write(This->stream, buf, read, NULL);
324 if(FAILED(hres))
325 return hres;
327 return S_OK;
330 static HRESULT WINAPI BindStatusCallback_OnObjectAvailable(IBindStatusCallback *iface,
331 REFIID riid, IUnknown* punk)
333 ERR("\n");
334 return E_NOTIMPL;
337 static const IBindStatusCallbackVtbl BindStatusCallbackVtbl = {
338 BindStatusCallback_QueryInterface,
339 BindStatusCallback_AddRef,
340 BindStatusCallback_Release,
341 BindStatusCallback_OnStartBinding,
342 BindStatusCallback_GetPriority,
343 BindStatusCallback_OnLowResource,
344 BindStatusCallback_OnProgress,
345 BindStatusCallback_OnStopBinding,
346 BindStatusCallback_GetBindInfo,
347 BindStatusCallback_OnDataAvailable,
348 BindStatusCallback_OnObjectAvailable
351 static inline MimeHtmlProtocol *impl_from_IUnknown(IUnknown *iface)
353 return CONTAINING_RECORD(iface, MimeHtmlProtocol, IUnknown_inner);
356 static HRESULT WINAPI MimeHtmlProtocol_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
358 MimeHtmlProtocol *This = impl_from_IUnknown(iface);
360 if(IsEqualGUID(&IID_IUnknown, riid)) {
361 TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
362 *ppv = &This->IInternetProtocol_iface;
363 }else if(IsEqualGUID(&IID_IInternetProtocolRoot, riid)) {
364 TRACE("(%p)->(IID_IInternetProtocolRoot %p)\n", This, ppv);
365 *ppv = &This->IInternetProtocol_iface;
366 }else if(IsEqualGUID(&IID_IInternetProtocol, riid)) {
367 TRACE("(%p)->(IID_IInternetProtocol %p)\n", This, ppv);
368 *ppv = &This->IInternetProtocol_iface;
369 }else if(IsEqualGUID(&IID_IInternetProtocolInfo, riid)) {
370 TRACE("(%p)->(IID_IInternetProtocolInfo %p)\n", This, ppv);
371 *ppv = &This->IInternetProtocolInfo_iface;
372 }else {
373 FIXME("unknown interface %s\n", debugstr_guid(riid));
374 *ppv = NULL;
375 return E_NOINTERFACE;
378 IUnknown_AddRef((IUnknown*)*ppv);
379 return S_OK;
382 static ULONG WINAPI MimeHtmlProtocol_AddRef(IUnknown *iface)
384 MimeHtmlProtocol *This = impl_from_IUnknown(iface);
385 ULONG ref = InterlockedIncrement(&This->ref);
387 TRACE("(%p) ref=%ld\n", This, ref);
389 return ref;
392 static ULONG WINAPI MimeHtmlProtocol_Release(IUnknown *iface)
394 MimeHtmlProtocol *This = impl_from_IUnknown(iface);
395 ULONG ref = InterlockedDecrement(&This->ref);
397 TRACE("(%p) ref=%lx\n", This, ref);
399 if(!ref) {
400 if(This->sink)
401 IInternetProtocolSink_Release(This->sink);
402 if(This->stream)
403 IStream_Release(This->stream);
404 free(This->location);
405 free(This);
408 return ref;
411 static const IUnknownVtbl MimeHtmlProtocolInnerVtbl = {
412 MimeHtmlProtocol_QueryInterface,
413 MimeHtmlProtocol_AddRef,
414 MimeHtmlProtocol_Release
417 static inline MimeHtmlProtocol *impl_from_IInternetProtocol(IInternetProtocol *iface)
419 return CONTAINING_RECORD(iface, MimeHtmlProtocol, IInternetProtocol_iface);
422 static HRESULT WINAPI InternetProtocol_QueryInterface(IInternetProtocol *iface, REFIID riid, void **ppv)
424 MimeHtmlProtocol *This = impl_from_IInternetProtocol(iface);
425 return IUnknown_QueryInterface(This->outer_unk, riid, ppv);
428 static ULONG WINAPI InternetProtocol_AddRef(IInternetProtocol *iface)
430 MimeHtmlProtocol *This = impl_from_IInternetProtocol(iface);
431 return IUnknown_AddRef(This->outer_unk);
434 static ULONG WINAPI InternetProtocol_Release(IInternetProtocol *iface)
436 MimeHtmlProtocol *This = impl_from_IInternetProtocol(iface);
437 return IUnknown_Release(This->outer_unk);
440 static HRESULT WINAPI MimeHtmlProtocol_Start(IInternetProtocol *iface, const WCHAR *szUrl,
441 IInternetProtocolSink* pOIProtSink, IInternetBindInfo* pOIBindInfo,
442 DWORD grfPI, HANDLE_PTR dwReserved)
444 MimeHtmlProtocol *This = impl_from_IInternetProtocol(iface);
445 BINDINFO bindinfo = { sizeof(bindinfo) };
446 MimeHtmlBinding *binding;
447 IBindCtx *bind_ctx;
448 IStream *stream;
449 mhtml_url_t url;
450 DWORD bindf = 0;
451 IMoniker *mon;
452 HRESULT hres;
454 TRACE("(%p)->(%s %p %p %08lx %Ix)\n", This, debugstr_w(szUrl), pOIProtSink, pOIBindInfo, grfPI, dwReserved);
456 hres = parse_mhtml_url(szUrl, &url);
457 if(FAILED(hres))
458 return hres;
460 if(url.location && !(This->location = wcsdup(url.location)))
461 return E_OUTOFMEMORY;
463 hres = IInternetBindInfo_GetBindInfo(pOIBindInfo, &bindf, &bindinfo);
464 if(FAILED(hres)) {
465 WARN("GetBindInfo failed: %08lx\n", hres);
466 return hres;
468 if((bindf & (BINDF_ASYNCHRONOUS|BINDF_FROMURLMON|BINDF_NEEDFILE)) != (BINDF_ASYNCHRONOUS|BINDF_FROMURLMON|BINDF_NEEDFILE))
469 FIXME("unsupported bindf %lx\n", bindf);
471 IInternetProtocolSink_AddRef(This->sink = pOIProtSink);
473 binding = malloc(FIELD_OFFSET(MimeHtmlBinding, url[url.mhtml_len+1]));
474 if(!binding)
475 return E_OUTOFMEMORY;
476 memcpy(binding->url, url.mhtml, url.mhtml_len*sizeof(WCHAR));
477 binding->url[url.mhtml_len] = 0;
479 hres = CreateURLMoniker(NULL, binding->url, &mon);
480 if(FAILED(hres)) {
481 free(binding);
482 return hres;
485 binding->IBindStatusCallback_iface.lpVtbl = &BindStatusCallbackVtbl;
486 binding->ref = 1;
487 binding->status = E_PENDING;
488 binding->stream = NULL;
489 binding->protocol = NULL;
491 hres = CreateAsyncBindCtx(0, &binding->IBindStatusCallback_iface, NULL, &bind_ctx);
492 if(FAILED(hres)) {
493 IMoniker_Release(mon);
494 IBindStatusCallback_Release(&binding->IBindStatusCallback_iface);
495 return hres;
498 IInternetProtocol_AddRef(&This->IInternetProtocol_iface);
499 binding->protocol = This;
501 hres = IMoniker_BindToStorage(mon, bind_ctx, NULL, &IID_IStream, (void**)&stream);
502 IBindCtx_Release(bind_ctx);
503 IMoniker_Release(mon);
504 if(stream)
505 IStream_Release(stream);
506 hres = binding->status;
507 IBindStatusCallback_Release(&binding->IBindStatusCallback_iface);
508 if(FAILED(hres) && hres != E_PENDING)
509 report_result(This, hres);
510 return hres;
513 static HRESULT WINAPI MimeHtmlProtocol_Continue(IInternetProtocol *iface, PROTOCOLDATA *pProtocolData)
515 MimeHtmlProtocol *This = impl_from_IInternetProtocol(iface);
516 FIXME("(%p)->(%p)\n", This, pProtocolData);
517 return E_NOTIMPL;
520 static HRESULT WINAPI MimeHtmlProtocol_Abort(IInternetProtocol *iface, HRESULT hrReason, DWORD dwOptions)
522 MimeHtmlProtocol *This = impl_from_IInternetProtocol(iface);
523 FIXME("(%p)->(%08lx %08lx)\n", This, hrReason, dwOptions);
524 return E_NOTIMPL;
527 static HRESULT WINAPI MimeHtmlProtocol_Terminate(IInternetProtocol *iface, DWORD dwOptions)
529 MimeHtmlProtocol *This = impl_from_IInternetProtocol(iface);
530 TRACE("(%p)->(%08lx)\n", This, dwOptions);
531 return S_OK;
534 static HRESULT WINAPI MimeHtmlProtocol_Suspend(IInternetProtocol *iface)
536 MimeHtmlProtocol *This = impl_from_IInternetProtocol(iface);
537 FIXME("(%p)\n", This);
538 return E_NOTIMPL;
541 static HRESULT WINAPI MimeHtmlProtocol_Resume(IInternetProtocol *iface)
543 MimeHtmlProtocol *This = impl_from_IInternetProtocol(iface);
544 FIXME("(%p)\n", This);
545 return E_NOTIMPL;
548 static HRESULT WINAPI MimeHtmlProtocol_Read(IInternetProtocol *iface, void* pv, ULONG cb, ULONG* pcbRead)
550 MimeHtmlProtocol *This = impl_from_IInternetProtocol(iface);
551 ULONG read = 0;
552 HRESULT hres;
554 TRACE("(%p)->(%p %lu %p)\n", This, pv, cb, pcbRead);
556 hres = IStream_Read(This->stream, pv, cb, &read);
557 if(pcbRead)
558 *pcbRead = read;
559 if(hres != S_OK)
560 return hres;
562 return read ? S_OK : S_FALSE;
565 static HRESULT WINAPI MimeHtmlProtocol_Seek(IInternetProtocol *iface, LARGE_INTEGER dlibMove,
566 DWORD dwOrigin, ULARGE_INTEGER* plibNewPosition)
568 MimeHtmlProtocol *This = impl_from_IInternetProtocol(iface);
569 FIXME("(%p)->(%ld %ld %p)\n", This, dlibMove.LowPart, dwOrigin, plibNewPosition);
570 return E_NOTIMPL;
573 static HRESULT WINAPI MimeHtmlProtocol_LockRequest(IInternetProtocol *iface, DWORD dwOptions)
575 MimeHtmlProtocol *This = impl_from_IInternetProtocol(iface);
576 FIXME("(%p)->(%ld)\n", This, dwOptions);
577 return S_OK;
580 static HRESULT WINAPI MimeHtmlProtocol_UnlockRequest(IInternetProtocol *iface)
582 MimeHtmlProtocol *This = impl_from_IInternetProtocol(iface);
583 FIXME("(%p)\n", This);
584 return S_OK;
587 static const IInternetProtocolVtbl MimeHtmlProtocolVtbl = {
588 InternetProtocol_QueryInterface,
589 InternetProtocol_AddRef,
590 InternetProtocol_Release,
591 MimeHtmlProtocol_Start,
592 MimeHtmlProtocol_Continue,
593 MimeHtmlProtocol_Abort,
594 MimeHtmlProtocol_Terminate,
595 MimeHtmlProtocol_Suspend,
596 MimeHtmlProtocol_Resume,
597 MimeHtmlProtocol_Read,
598 MimeHtmlProtocol_Seek,
599 MimeHtmlProtocol_LockRequest,
600 MimeHtmlProtocol_UnlockRequest
603 static inline MimeHtmlProtocol *impl_from_IInternetProtocolInfo(IInternetProtocolInfo *iface)
605 return CONTAINING_RECORD(iface, MimeHtmlProtocol, IInternetProtocolInfo_iface);
608 static HRESULT WINAPI MimeHtmlProtocolInfo_QueryInterface(IInternetProtocolInfo *iface, REFIID riid, void **ppv)
610 MimeHtmlProtocol *This = impl_from_IInternetProtocolInfo(iface);
611 return IUnknown_QueryInterface(This->outer_unk, riid, ppv);
614 static ULONG WINAPI MimeHtmlProtocolInfo_AddRef(IInternetProtocolInfo *iface)
616 MimeHtmlProtocol *This = impl_from_IInternetProtocolInfo(iface);
617 return IUnknown_AddRef(This->outer_unk);
620 static ULONG WINAPI MimeHtmlProtocolInfo_Release(IInternetProtocolInfo *iface)
622 MimeHtmlProtocol *This = impl_from_IInternetProtocolInfo(iface);
623 return IUnknown_Release(This->outer_unk);
626 static HRESULT WINAPI MimeHtmlProtocolInfo_ParseUrl(IInternetProtocolInfo *iface, LPCWSTR pwzUrl,
627 PARSEACTION ParseAction, DWORD dwParseFlags, LPWSTR pwzResult, DWORD cchResult,
628 DWORD* pcchResult, DWORD dwReserved)
630 MimeHtmlProtocol *This = impl_from_IInternetProtocolInfo(iface);
631 FIXME("(%p)->(%s %d %lx %p %ld %p %ld)\n", This, debugstr_w(pwzUrl), ParseAction,
632 dwParseFlags, pwzResult, cchResult, pcchResult, dwReserved);
633 return INET_E_DEFAULT_ACTION;
636 static HRESULT WINAPI MimeHtmlProtocolInfo_CombineUrl(IInternetProtocolInfo *iface,
637 LPCWSTR pwzBaseUrl, LPCWSTR pwzRelativeUrl, DWORD dwCombineFlags, LPWSTR pwzResult,
638 DWORD cchResult, DWORD* pcchResult, DWORD dwReserved)
640 MimeHtmlProtocol *This = impl_from_IInternetProtocolInfo(iface);
641 size_t len = lstrlenW(mhtml_prefixW);
642 mhtml_url_t url;
643 WCHAR *p;
644 HRESULT hres;
646 TRACE("(%p)->(%s %s %08lx %p %ld %p %ld)\n", This, debugstr_w(pwzBaseUrl),
647 debugstr_w(pwzRelativeUrl), dwCombineFlags, pwzResult, cchResult,
648 pcchResult, dwReserved);
650 hres = parse_mhtml_url(pwzBaseUrl, &url);
651 if(FAILED(hres))
652 return hres;
654 if(!wcsnicmp(pwzRelativeUrl, mhtml_prefixW, len)) {
655 FIXME("Relative URL is mhtml protocol\n");
656 return INET_E_USE_DEFAULT_PROTOCOLHANDLER;
659 len += url.mhtml_len;
660 if(*pwzRelativeUrl)
661 len += lstrlenW(pwzRelativeUrl) + lstrlenW(mhtml_separatorW);
662 if(len >= cchResult) {
663 *pcchResult = 0;
664 return E_FAIL;
667 lstrcpyW(pwzResult, mhtml_prefixW);
668 p = pwzResult + lstrlenW(mhtml_prefixW);
669 memcpy(p, url.mhtml, url.mhtml_len*sizeof(WCHAR));
670 p += url.mhtml_len;
671 if(*pwzRelativeUrl) {
672 lstrcpyW(p, mhtml_separatorW);
673 lstrcatW(p, pwzRelativeUrl);
674 }else {
675 *p = 0;
678 *pcchResult = len;
679 return S_OK;
682 static HRESULT WINAPI MimeHtmlProtocolInfo_CompareUrl(IInternetProtocolInfo *iface, LPCWSTR pwzUrl1,
683 LPCWSTR pwzUrl2, DWORD dwCompareFlags)
685 MimeHtmlProtocol *This = impl_from_IInternetProtocolInfo(iface);
686 FIXME("(%p)->(%s %s %08lx)\n", This, debugstr_w(pwzUrl1), debugstr_w(pwzUrl2), dwCompareFlags);
687 return E_NOTIMPL;
690 static HRESULT WINAPI MimeHtmlProtocolInfo_QueryInfo(IInternetProtocolInfo *iface, LPCWSTR pwzUrl,
691 QUERYOPTION QueryOption, DWORD dwQueryFlags, LPVOID pBuffer, DWORD cbBuffer, DWORD* pcbBuf,
692 DWORD dwReserved)
694 MimeHtmlProtocol *This = impl_from_IInternetProtocolInfo(iface);
695 FIXME("(%p)->(%s %08x %08lx %p %ld %p %ld)\n", This, debugstr_w(pwzUrl), QueryOption, dwQueryFlags, pBuffer,
696 cbBuffer, pcbBuf, dwReserved);
697 return INET_E_USE_DEFAULT_PROTOCOLHANDLER;
700 static const IInternetProtocolInfoVtbl MimeHtmlProtocolInfoVtbl = {
701 MimeHtmlProtocolInfo_QueryInterface,
702 MimeHtmlProtocolInfo_AddRef,
703 MimeHtmlProtocolInfo_Release,
704 MimeHtmlProtocolInfo_ParseUrl,
705 MimeHtmlProtocolInfo_CombineUrl,
706 MimeHtmlProtocolInfo_CompareUrl,
707 MimeHtmlProtocolInfo_QueryInfo
710 HRESULT MimeHtmlProtocol_create(IUnknown *outer, void **obj)
712 MimeHtmlProtocol *protocol;
714 protocol = malloc(sizeof(*protocol));
715 if(!protocol)
716 return E_OUTOFMEMORY;
718 protocol->IUnknown_inner.lpVtbl = &MimeHtmlProtocolInnerVtbl;
719 protocol->IInternetProtocol_iface.lpVtbl = &MimeHtmlProtocolVtbl;
720 protocol->IInternetProtocolInfo_iface.lpVtbl = &MimeHtmlProtocolInfoVtbl;
721 protocol->ref = 1;
722 protocol->outer_unk = outer ? outer : &protocol->IUnknown_inner;
723 protocol->location = NULL;
724 protocol->stream = NULL;
725 protocol->sink = NULL;
727 *obj = &protocol->IUnknown_inner;
728 return S_OK;