hlink: Use ifaces instead of vtbl pointers in ExtensionService.
[wine] / dlls / urlmon / gopher.c
1 /*
2  * Copyright 2009 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 "urlmon_main.h"
20 #include "wine/debug.h"
21
22 WINE_DEFAULT_DEBUG_CHANNEL(urlmon);
23
24 typedef struct {
25     Protocol base;
26
27     const IInternetProtocolVtbl  *lpIInternetProtocolVtbl;
28     const IInternetPriorityVtbl  *lpInternetPriorityVtbl;
29
30     LONG ref;
31 } GopherProtocol;
32
33 #define PRIORITY(x)  ((IInternetPriority*)  &(x)->lpInternetPriorityVtbl)
34
35 static inline GopherProtocol *impl_from_Protocol(Protocol *prot)
36 {
37     return CONTAINING_RECORD(prot, GopherProtocol, base);
38 }
39
40 static HRESULT GopherProtocol_open_request(Protocol *prot, IUri *uri, DWORD request_flags,
41         HINTERNET internet_session, IInternetBindInfo *bind_info)
42 {
43     GopherProtocol *This = impl_from_Protocol(prot);
44     BSTR url;
45     HRESULT hres;
46
47     hres = IUri_GetAbsoluteUri(uri, &url);
48     if(FAILED(hres))
49         return hres;
50
51     This->base.request = InternetOpenUrlW(internet_session, url, NULL, 0,
52             request_flags, (DWORD_PTR)&This->base);
53     SysFreeString(url);
54     if (!This->base.request && GetLastError() != ERROR_IO_PENDING) {
55         WARN("InternetOpenUrl failed: %d\n", GetLastError());
56         return INET_E_RESOURCE_NOT_FOUND;
57     }
58
59     return S_OK;
60 }
61
62 static HRESULT GopherProtocol_end_request(Protocol *prot)
63 {
64     return E_NOTIMPL;
65 }
66
67 static HRESULT GopherProtocol_start_downloading(Protocol *prot)
68 {
69     return S_OK;
70 }
71
72 static void GopherProtocol_close_connection(Protocol *prot)
73 {
74 }
75
76 static void GopherProtocol_on_error(Protocol *prot, DWORD error)
77 {
78     FIXME("(%p) %d - stub\n", prot, error);
79 }
80
81 static const ProtocolVtbl AsyncProtocolVtbl = {
82     GopherProtocol_open_request,
83     GopherProtocol_end_request,
84     GopherProtocol_start_downloading,
85     GopherProtocol_close_connection,
86     GopherProtocol_on_error
87 };
88
89 #define PROTOCOL_THIS(iface) DEFINE_THIS(GopherProtocol, IInternetProtocol, iface)
90
91 static HRESULT WINAPI GopherProtocol_QueryInterface(IInternetProtocol *iface, REFIID riid, void **ppv)
92 {
93     GopherProtocol *This = PROTOCOL_THIS(iface);
94
95     *ppv = NULL;
96     if(IsEqualGUID(&IID_IUnknown, riid)) {
97         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
98         *ppv = PROTOCOL(This);
99     }else if(IsEqualGUID(&IID_IInternetProtocolRoot, riid)) {
100         TRACE("(%p)->(IID_IInternetProtocolRoot %p)\n", This, ppv);
101         *ppv = PROTOCOL(This);
102     }else if(IsEqualGUID(&IID_IInternetProtocol, riid)) {
103         TRACE("(%p)->(IID_IInternetProtocol %p)\n", This, ppv);
104         *ppv = PROTOCOL(This);
105     }else if(IsEqualGUID(&IID_IInternetPriority, riid)) {
106         TRACE("(%p)->(IID_IInternetPriority %p)\n", This, ppv);
107         *ppv = PRIORITY(This);
108     }
109
110     if(*ppv) {
111         IInternetProtocol_AddRef(iface);
112         return S_OK;
113     }
114
115     WARN("not supported interface %s\n", debugstr_guid(riid));
116     return E_NOINTERFACE;
117 }
118
119 static ULONG WINAPI GopherProtocol_AddRef(IInternetProtocol *iface)
120 {
121     GopherProtocol *This = PROTOCOL_THIS(iface);
122     LONG ref = InterlockedIncrement(&This->ref);
123     TRACE("(%p) ref=%d\n", This, ref);
124     return ref;
125 }
126
127 static ULONG WINAPI GopherProtocol_Release(IInternetProtocol *iface)
128 {
129     GopherProtocol *This = PROTOCOL_THIS(iface);
130     LONG ref = InterlockedDecrement(&This->ref);
131
132     TRACE("(%p) ref=%d\n", This, ref);
133
134     if(!ref) {
135         heap_free(This);
136
137         URLMON_UnlockModule();
138     }
139
140     return ref;
141 }
142
143 static HRESULT WINAPI GopherProtocol_Start(IInternetProtocol *iface, LPCWSTR szUrl,
144         IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo,
145         DWORD grfPI, HANDLE_PTR dwReserved)
146 {
147     GopherProtocol *This = PROTOCOL_THIS(iface);
148     IUri *uri;
149     HRESULT hres;
150
151     TRACE("(%p)->(%s %p %p %08x %lx)\n", This, debugstr_w(szUrl), pOIProtSink,
152           pOIBindInfo, grfPI, dwReserved);
153
154     hres = CreateUri(szUrl, 0, 0, &uri);
155     if(FAILED(hres))
156         return hres;
157
158     hres = protocol_start(&This->base, PROTOCOL(This), uri, pOIProtSink, pOIBindInfo);
159
160     IUri_Release(uri);
161     return hres;
162 }
163
164 static HRESULT WINAPI GopherProtocol_Continue(IInternetProtocol *iface, PROTOCOLDATA *pProtocolData)
165 {
166     GopherProtocol *This = PROTOCOL_THIS(iface);
167
168     TRACE("(%p)->(%p)\n", This, pProtocolData);
169
170     return protocol_continue(&This->base, pProtocolData);
171 }
172
173 static HRESULT WINAPI GopherProtocol_Abort(IInternetProtocol *iface, HRESULT hrReason,
174         DWORD dwOptions)
175 {
176     GopherProtocol *This = PROTOCOL_THIS(iface);
177
178     TRACE("(%p)->(%08x %08x)\n", This, hrReason, dwOptions);
179
180     return protocol_abort(&This->base, hrReason);
181 }
182
183 static HRESULT WINAPI GopherProtocol_Terminate(IInternetProtocol *iface, DWORD dwOptions)
184 {
185     GopherProtocol *This = PROTOCOL_THIS(iface);
186
187     TRACE("(%p)->(%08x)\n", This, dwOptions);
188
189     protocol_close_connection(&This->base);
190     return S_OK;
191 }
192
193 static HRESULT WINAPI GopherProtocol_Suspend(IInternetProtocol *iface)
194 {
195     GopherProtocol *This = PROTOCOL_THIS(iface);
196     FIXME("(%p)\n", This);
197     return E_NOTIMPL;
198 }
199
200 static HRESULT WINAPI GopherProtocol_Resume(IInternetProtocol *iface)
201 {
202     GopherProtocol *This = PROTOCOL_THIS(iface);
203     FIXME("(%p)\n", This);
204     return E_NOTIMPL;
205 }
206
207 static HRESULT WINAPI GopherProtocol_Read(IInternetProtocol *iface, void *pv,
208         ULONG cb, ULONG *pcbRead)
209 {
210     GopherProtocol *This = PROTOCOL_THIS(iface);
211
212     TRACE("(%p)->(%p %u %p)\n", This, pv, cb, pcbRead);
213
214     return protocol_read(&This->base, pv, cb, pcbRead);
215 }
216
217 static HRESULT WINAPI GopherProtocol_Seek(IInternetProtocol *iface, LARGE_INTEGER dlibMove,
218         DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
219 {
220     GopherProtocol *This = PROTOCOL_THIS(iface);
221     FIXME("(%p)->(%d %d %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
222     return E_NOTIMPL;
223 }
224
225 static HRESULT WINAPI GopherProtocol_LockRequest(IInternetProtocol *iface, DWORD dwOptions)
226 {
227     GopherProtocol *This = PROTOCOL_THIS(iface);
228
229     TRACE("(%p)->(%08x)\n", This, dwOptions);
230
231     return protocol_lock_request(&This->base);
232 }
233
234 static HRESULT WINAPI GopherProtocol_UnlockRequest(IInternetProtocol *iface)
235 {
236     GopherProtocol *This = PROTOCOL_THIS(iface);
237
238     TRACE("(%p)\n", This);
239
240     return protocol_unlock_request(&This->base);
241 }
242
243 #undef PROTOCOL_THIS
244
245 static const IInternetProtocolVtbl GopherProtocolVtbl = {
246     GopherProtocol_QueryInterface,
247     GopherProtocol_AddRef,
248     GopherProtocol_Release,
249     GopherProtocol_Start,
250     GopherProtocol_Continue,
251     GopherProtocol_Abort,
252     GopherProtocol_Terminate,
253     GopherProtocol_Suspend,
254     GopherProtocol_Resume,
255     GopherProtocol_Read,
256     GopherProtocol_Seek,
257     GopherProtocol_LockRequest,
258     GopherProtocol_UnlockRequest
259 };
260
261 #define PRIORITY_THIS(iface) DEFINE_THIS(GopherProtocol, InternetPriority, iface)
262
263 static HRESULT WINAPI GopherPriority_QueryInterface(IInternetPriority *iface, REFIID riid, void **ppv)
264 {
265     GopherProtocol *This = PRIORITY_THIS(iface);
266     return IInternetProtocol_QueryInterface(PROTOCOL(This), riid, ppv);
267 }
268
269 static ULONG WINAPI GopherPriority_AddRef(IInternetPriority *iface)
270 {
271     GopherProtocol *This = PRIORITY_THIS(iface);
272     return IInternetProtocol_AddRef(PROTOCOL(This));
273 }
274
275 static ULONG WINAPI GopherPriority_Release(IInternetPriority *iface)
276 {
277     GopherProtocol *This = PRIORITY_THIS(iface);
278     return IInternetProtocol_Release(PROTOCOL(This));
279 }
280
281 static HRESULT WINAPI GopherPriority_SetPriority(IInternetPriority *iface, LONG nPriority)
282 {
283     GopherProtocol *This = PRIORITY_THIS(iface);
284
285     TRACE("(%p)->(%d)\n", This, nPriority);
286
287     This->base.priority = nPriority;
288     return S_OK;
289 }
290
291 static HRESULT WINAPI GopherPriority_GetPriority(IInternetPriority *iface, LONG *pnPriority)
292 {
293     GopherProtocol *This = PRIORITY_THIS(iface);
294
295     TRACE("(%p)->(%p)\n", This, pnPriority);
296
297     *pnPriority = This->base.priority;
298     return S_OK;
299 }
300
301 #undef PRIORITY_THIS
302
303 static const IInternetPriorityVtbl GopherPriorityVtbl = {
304     GopherPriority_QueryInterface,
305     GopherPriority_AddRef,
306     GopherPriority_Release,
307     GopherPriority_SetPriority,
308     GopherPriority_GetPriority
309 };
310
311 HRESULT GopherProtocol_Construct(IUnknown *pUnkOuter, LPVOID *ppobj)
312 {
313     GopherProtocol *ret;
314
315     TRACE("(%p %p)\n", pUnkOuter, ppobj);
316
317     URLMON_LockModule();
318
319     ret = heap_alloc_zero(sizeof(GopherProtocol));
320
321     ret->base.vtbl = &AsyncProtocolVtbl;
322     ret->lpIInternetProtocolVtbl = &GopherProtocolVtbl;
323     ret->lpInternetPriorityVtbl  = &GopherPriorityVtbl;
324     ret->ref = 1;
325
326     *ppobj = PROTOCOL(ret);
327
328     return S_OK;
329 }