[IMM32_WINETEST] Sync with Wine Staging 4.18. CORE-16441
[reactos.git] / dll / win32 / inetcomm / protocol.c
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 }