[INETCOMM] 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
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 }