urlmon: Implement HttpProtocol::Terminate.
[wine] / dlls / urlmon / mk.c
1 /*
2  * Copyright 2007 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 #include <stdarg.h>
20
21 #define COBJMACROS
22
23 #include "windef.h"
24 #include "winbase.h"
25 #include "winuser.h"
26 #include "ole2.h"
27 #include "urlmon.h"
28 #include "urlmon_main.h"
29
30 #include "wine/debug.h"
31 #include "wine/unicode.h"
32
33 WINE_DEFAULT_DEBUG_CHANNEL(urlmon);
34
35 typedef struct {
36     const IInternetProtocolVtbl  *lpInternetProtocolVtbl;
37
38     LONG ref;
39
40     IStream *stream;
41 } MkProtocol;
42
43 #define PROTOCOL_THIS(iface) DEFINE_THIS(MkProtocol, InternetProtocol, iface)
44
45 #define PROTOCOL(x)  ((IInternetProtocol*)  &(x)->lpInternetProtocolVtbl)
46
47 static HRESULT WINAPI MkProtocol_QueryInterface(IInternetProtocol *iface, REFIID riid, void **ppv)
48 {
49     MkProtocol *This = PROTOCOL_THIS(iface);
50
51     *ppv = NULL;
52     if(IsEqualGUID(&IID_IUnknown, riid)) {
53         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
54         *ppv = PROTOCOL(This);
55     }else if(IsEqualGUID(&IID_IInternetProtocolRoot, riid)) {
56         TRACE("(%p)->(IID_IInternetProtocolRoot %p)\n", This, ppv);
57         *ppv = PROTOCOL(This);
58     }else if(IsEqualGUID(&IID_IInternetProtocol, riid)) {
59         TRACE("(%p)->(IID_IInternetProtocol %p)\n", This, ppv);
60         *ppv = PROTOCOL(This);
61     }
62
63     if(*ppv) {
64         IInternetProtocol_AddRef(iface);
65         return S_OK;
66     }
67
68     WARN("not supported interface %s\n", debugstr_guid(riid));
69     return E_NOINTERFACE;
70 }
71
72 static ULONG WINAPI MkProtocol_AddRef(IInternetProtocol *iface)
73 {
74     MkProtocol *This = PROTOCOL_THIS(iface);
75     LONG ref = InterlockedIncrement(&This->ref);
76     TRACE("(%p) ref=%d\n", This, ref);
77     return ref;
78 }
79
80 static ULONG WINAPI MkProtocol_Release(IInternetProtocol *iface)
81 {
82     MkProtocol *This = PROTOCOL_THIS(iface);
83     LONG ref = InterlockedDecrement(&This->ref);
84
85     TRACE("(%p) ref=%d\n", This, ref);
86
87     if(!ref) {
88         if(This->stream)
89             IStream_Release(This->stream);
90
91         HeapFree(GetProcessHeap(), 0, This);
92
93         URLMON_UnlockModule();
94     }
95
96     return ref;
97 }
98
99 static HRESULT report_result(IInternetProtocolSink *sink, HRESULT hres, DWORD dwError)
100 {
101     IInternetProtocolSink_ReportResult(sink, hres, dwError, NULL);
102     return hres;
103 }
104
105 static HRESULT WINAPI MkProtocol_Start(IInternetProtocol *iface, LPCWSTR szUrl,
106         IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo,
107         DWORD grfPI, DWORD dwReserved)
108 {
109     MkProtocol *This = PROTOCOL_THIS(iface);
110     IParseDisplayName *pdn;
111     IMoniker *mon;
112     LPWSTR mime, progid, display_name;
113     LPCWSTR ptr, ptr2;
114     BINDINFO bindinfo;
115     STATSTG statstg;
116     DWORD bindf=0, eaten=0, len;
117     CLSID clsid;
118     HRESULT hres;
119
120     static const WCHAR wszMK[] = {'m','k',':'};
121
122     TRACE("(%p)->(%s %p %p %08x %d)\n", This, debugstr_w(szUrl), pOIProtSink,
123             pOIBindInfo, grfPI, dwReserved);
124
125     memset(&bindinfo, 0, sizeof(bindinfo));
126     bindinfo.cbSize = sizeof(BINDINFO);
127     hres = IInternetBindInfo_GetBindInfo(pOIBindInfo, &bindf, &bindinfo);
128     if(FAILED(hres)) {
129         WARN("GetBindInfo failed: %08x\n", hres);
130         return hres;
131     }
132
133     ReleaseBindInfo(&bindinfo);
134
135     if(strncmpiW(szUrl, wszMK, sizeof(wszMK)/sizeof(WCHAR)))
136         return MK_E_SYNTAX;
137
138     IInternetProtocolSink_ReportProgress(pOIProtSink, BINDSTATUS_DIRECTBIND, NULL);
139     IInternetProtocolSink_ReportProgress(pOIProtSink, BINDSTATUS_SENDINGREQUEST, NULL);
140
141     hres = FindMimeFromData(NULL, szUrl, NULL, 0, NULL, 0, &mime, 0);
142     if(SUCCEEDED(hres)) {
143         IInternetProtocolSink_ReportProgress(pOIProtSink, BINDSTATUS_MIMETYPEAVAILABLE, mime);
144         CoTaskMemFree(mime);
145     }
146
147     ptr2 = szUrl + sizeof(wszMK)/sizeof(WCHAR);
148     if(*ptr2 != '@')
149         return report_result(pOIProtSink, INET_E_RESOURCE_NOT_FOUND, ERROR_INVALID_PARAMETER);
150     ptr2++;
151
152     ptr = strchrW(ptr2, ':');
153     if(!ptr)
154         return report_result(pOIProtSink, INET_E_RESOURCE_NOT_FOUND, ERROR_INVALID_PARAMETER);
155
156     progid = HeapAlloc(GetProcessHeap(), 0, (ptr-ptr2+1)*sizeof(WCHAR));
157     memcpy(progid, ptr2, (ptr-ptr2)*sizeof(WCHAR));
158     progid[ptr-ptr2] = 0;
159     hres = CLSIDFromProgID(progid, &clsid);
160     HeapFree(GetProcessHeap(), 0, progid);
161     if(FAILED(hres))
162         return report_result(pOIProtSink, INET_E_RESOURCE_NOT_FOUND, ERROR_INVALID_PARAMETER);
163
164     hres = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER,
165             &IID_IParseDisplayName, (void**)&pdn);
166     if(FAILED(hres)) {
167         WARN("Could not create object %s\n", debugstr_guid(&clsid));
168         return report_result(pOIProtSink, hres, ERROR_INVALID_PARAMETER);
169     }
170
171     len = strlenW(--ptr2);
172     display_name = HeapAlloc(GetProcessHeap(), 0, (len+1)*sizeof(WCHAR));
173     memcpy(display_name, ptr2, (len+1)*sizeof(WCHAR));
174     hres = IParseDisplayName_ParseDisplayName(pdn, NULL /* FIXME */, display_name, &eaten, &mon);
175     HeapFree(GetProcessHeap(), 0, display_name);
176     IParseDisplayName_Release(pdn);
177     if(FAILED(hres)) {
178         WARN("ParseDisplayName failed: %08x\n", hres);
179         return report_result(pOIProtSink, hres, ERROR_INVALID_PARAMETER);
180     }
181
182     if(This->stream) {
183         IStream_Release(This->stream);
184         This->stream = NULL;
185     }
186
187     hres = IMoniker_BindToStorage(mon, NULL /* FIXME */, NULL, &IID_IStream, (void**)&This->stream);
188     IMoniker_Release(mon);
189     if(FAILED(hres)) {
190         WARN("BindToStorage failed: %08x\n", hres);
191         return report_result(pOIProtSink, hres, ERROR_INVALID_PARAMETER);
192     }
193
194     hres = IStream_Stat(This->stream, &statstg, STATFLAG_NONAME);
195     if(FAILED(hres)) {
196         WARN("Stat failed: %08x\n", hres);
197         return report_result(pOIProtSink, hres, ERROR_INVALID_PARAMETER);
198     }
199
200     IInternetProtocolSink_ReportData(pOIProtSink,
201             BSCF_FIRSTDATANOTIFICATION | BSCF_LASTDATANOTIFICATION,
202             statstg.cbSize.u.LowPart, statstg.cbSize.u.LowPart);
203
204     return report_result(pOIProtSink, S_OK, ERROR_SUCCESS);
205 }
206
207 static HRESULT WINAPI MkProtocol_Continue(IInternetProtocol *iface, PROTOCOLDATA *pProtocolData)
208 {
209     MkProtocol *This = PROTOCOL_THIS(iface);
210     FIXME("(%p)->(%p)\n", This, pProtocolData);
211     return E_NOTIMPL;
212 }
213
214 static HRESULT WINAPI MkProtocol_Abort(IInternetProtocol *iface, HRESULT hrReason,
215         DWORD dwOptions)
216 {
217     MkProtocol *This = PROTOCOL_THIS(iface);
218     FIXME("(%p)->(%08x %08x)\n", This, hrReason, dwOptions);
219     return E_NOTIMPL;
220 }
221
222 static HRESULT WINAPI MkProtocol_Terminate(IInternetProtocol *iface, DWORD dwOptions)
223 {
224     MkProtocol *This = PROTOCOL_THIS(iface);
225
226     TRACE("(%p)->(%08x)\n", This, dwOptions);
227
228     return S_OK;
229 }
230
231 static HRESULT WINAPI MkProtocol_Suspend(IInternetProtocol *iface)
232 {
233     MkProtocol *This = PROTOCOL_THIS(iface);
234     FIXME("(%p)\n", This);
235     return E_NOTIMPL;
236 }
237
238 static HRESULT WINAPI MkProtocol_Resume(IInternetProtocol *iface)
239 {
240     MkProtocol *This = PROTOCOL_THIS(iface);
241     FIXME("(%p)\n", This);
242     return E_NOTIMPL;
243 }
244
245 static HRESULT WINAPI MkProtocol_Read(IInternetProtocol *iface, void *pv,
246         ULONG cb, ULONG *pcbRead)
247 {
248     MkProtocol *This = PROTOCOL_THIS(iface);
249
250     TRACE("(%p)->(%p %u %p)\n", This, pv, cb, pcbRead);
251
252     if(!This->stream)
253         return E_FAIL;
254
255     return IStream_Read(This->stream, pv, cb, pcbRead);
256 }
257
258 static HRESULT WINAPI MkProtocol_Seek(IInternetProtocol *iface, LARGE_INTEGER dlibMove,
259         DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
260 {
261     MkProtocol *This = PROTOCOL_THIS(iface);
262     FIXME("(%p)->(%d %d %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
263     return E_NOTIMPL;
264 }
265
266 static HRESULT WINAPI MkProtocol_LockRequest(IInternetProtocol *iface, DWORD dwOptions)
267 {
268     MkProtocol *This = PROTOCOL_THIS(iface);
269
270     TRACE("(%p)->(%08x)\n", This, dwOptions);
271
272     return S_OK;
273 }
274
275 static HRESULT WINAPI MkProtocol_UnlockRequest(IInternetProtocol *iface)
276 {
277     MkProtocol *This = PROTOCOL_THIS(iface);
278
279     TRACE("(%p)\n", This);
280
281     return S_OK;
282 }
283
284 #undef PROTOCOL_THIS
285
286 static const IInternetProtocolVtbl MkProtocolVtbl = {
287     MkProtocol_QueryInterface,
288     MkProtocol_AddRef,
289     MkProtocol_Release,
290     MkProtocol_Start,
291     MkProtocol_Continue,
292     MkProtocol_Abort,
293     MkProtocol_Terminate,
294     MkProtocol_Suspend,
295     MkProtocol_Resume,
296     MkProtocol_Read,
297     MkProtocol_Seek,
298     MkProtocol_LockRequest,
299     MkProtocol_UnlockRequest
300 };
301
302 HRESULT MkProtocol_Construct(IUnknown *pUnkOuter, LPVOID *ppobj)
303 {
304     MkProtocol *ret;
305
306     TRACE("(%p %p)\n", pUnkOuter, ppobj);
307
308     URLMON_LockModule();
309
310     ret = HeapAlloc(GetProcessHeap(), 0, sizeof(MkProtocol));
311
312     ret->lpInternetProtocolVtbl = &MkProtocolVtbl;
313     ret->ref = 1;
314     ret->stream = NULL;
315
316     /* NOTE:
317      * Native returns NULL ppobj and S_OK in CreateInstance if called with IID_IUnknown riid.
318      */
319     *ppobj = PROTOCOL(ret);
320
321     return S_OK;
322 }