mshtml: Use mime type reported by moniker if possible.
[wine] / dlls / mshtml / persist.c
1 /*
2  * Copyright 2005 Jacek Caban
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 "config.h"
20
21 #include <stdarg.h>
22 #include <stdio.h>
23
24 #define COBJMACROS
25 #define NONAMELESSUNION
26 #define NONAMELESSSTRUCT
27
28 #include "windef.h"
29 #include "winbase.h"
30 #include "winuser.h"
31 #include "ole2.h"
32 #include "shlguid.h"
33
34 #include "wine/debug.h"
35 #include "wine/unicode.h"
36
37 #include "mshtml_private.h"
38
39 WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
40
41 /**********************************************************
42  * IPersistMoniker implementation
43  */
44
45 #define PERSISTMON_THIS(iface) DEFINE_THIS(HTMLDocument, PersistMoniker, iface)
46
47 static HRESULT WINAPI PersistMoniker_QueryInterface(IPersistMoniker *iface, REFIID riid,
48                                                             void **ppvObject)
49 {
50     HTMLDocument *This = PERSISTMON_THIS(iface);
51     return IHTMLDocument2_QueryInterface(HTMLDOC(This), riid, ppvObject);
52 }
53
54 static ULONG WINAPI PersistMoniker_AddRef(IPersistMoniker *iface)
55 {
56     HTMLDocument *This = PERSISTMON_THIS(iface);
57     return IHTMLDocument2_AddRef(HTMLDOC(This));
58 }
59
60 static ULONG WINAPI PersistMoniker_Release(IPersistMoniker *iface)
61 {
62     HTMLDocument *This = PERSISTMON_THIS(iface);
63     return IHTMLDocument2_Release(HTMLDOC(This));
64 }
65
66 static HRESULT WINAPI PersistMoniker_GetClassID(IPersistMoniker *iface, CLSID *pClassID)
67 {
68     HTMLDocument *This = PERSISTMON_THIS(iface);
69     return IPersist_GetClassID(PERSIST(This), pClassID);
70 }
71
72 static HRESULT WINAPI PersistMoniker_IsDirty(IPersistMoniker *iface)
73 {
74     HTMLDocument *This = PERSISTMON_THIS(iface);
75     FIXME("(%p)\n", This);
76     return E_NOTIMPL;
77 }
78
79 static nsIInputStream *get_post_data_stream(IBindCtx *bctx)
80 {
81     nsIInputStream *ret = NULL;
82     IBindStatusCallback *callback;
83     IHttpNegotiate *http_negotiate;
84     BINDINFO bindinfo;
85     DWORD bindf = 0;
86     DWORD post_len = 0, headers_len = 0;
87     LPWSTR headers = NULL;
88     WCHAR emptystr[] = {0};
89     char *data;
90     HRESULT hres;
91
92     static WCHAR _BSCB_Holder_[] =
93         {'_','B','S','C','B','_','H','o','l','d','e','r','_',0};
94
95
96     /* FIXME: This should be done in URLMoniker */
97     if(!bctx)
98         return NULL;
99
100     hres = IBindCtx_GetObjectParam(bctx, _BSCB_Holder_, (IUnknown**)&callback);
101     if(FAILED(hres))
102         return NULL;
103
104     hres = IBindStatusCallback_QueryInterface(callback, &IID_IHttpNegotiate,
105                                               (void**)&http_negotiate);
106     if(SUCCEEDED(hres)) {
107         hres = IHttpNegotiate_BeginningTransaction(http_negotiate, emptystr,
108                                                    emptystr, 0, &headers);
109         IHttpNegotiate_Release(http_negotiate);
110
111         if(SUCCEEDED(hres) && headers)
112             headers_len = WideCharToMultiByte(CP_ACP, 0, headers, -1, NULL, 0, NULL, NULL);
113     }
114
115     memset(&bindinfo, 0, sizeof(bindinfo));
116     bindinfo.cbSize = sizeof(bindinfo);
117
118     hres = IBindStatusCallback_GetBindInfo(callback, &bindf, &bindinfo);
119
120     if(SUCCEEDED(hres) && bindinfo.dwBindVerb == BINDVERB_POST)
121         post_len = bindinfo.cbStgmedData;
122
123     if(headers_len || post_len) {
124         int len = headers_len ? headers_len-1 : 0;
125
126         static const char content_length[] = "Content-Length: %lu\r\n\r\n";
127
128         data = HeapAlloc(GetProcessHeap(), 0, headers_len+post_len+sizeof(content_length)+8);
129
130         if(headers_len) {
131             WideCharToMultiByte(CP_ACP, 0, headers, -1, data, -1, NULL, NULL);
132             CoTaskMemFree(headers);
133         }
134
135         if(post_len) {
136             sprintf(data+len, content_length, post_len);
137             len = strlen(data);
138
139             memcpy(data+len, bindinfo.stgmedData.u.hGlobal, post_len);
140         }
141
142         TRACE("data = %s\n", debugstr_an(data, len+post_len));
143
144         ret = create_nsstream(data, len+post_len);
145     }
146
147     ReleaseBindInfo(&bindinfo);
148     IBindStatusCallback_Release(callback);
149
150     return ret;
151 }
152
153 static HRESULT WINAPI PersistMoniker_Load(IPersistMoniker *iface, BOOL fFullyAvailable,
154         IMoniker *pimkName, LPBC pibc, DWORD grfMode)
155 {
156     HTMLDocument *This = PERSISTMON_THIS(iface);
157     BSCallback *bscallback;
158     LPOLESTR url;
159     HRESULT hres;
160     nsresult nsres;
161
162     TRACE("(%p)->(%x %p %p %08lx)\n", This, fFullyAvailable, pimkName, pibc, grfMode);
163
164     if(pibc) {
165         IUnknown *unk = NULL;
166
167         /* FIXME:
168          * Use params:
169          * "__PrecreatedObject"
170          * "BIND_CONTEXT_PARAM"
171          * "__HTMLLOADOPTIONS"
172          * "__DWNBINDINFO"
173          * "URL Context"
174          * "CBinding Context"
175          * "_ITransData_Object_"
176          * "_EnumFORMATETC_"
177          */
178
179         IBindCtx_GetObjectParam(pibc, (LPOLESTR)SZ_HTML_CLIENTSITE_OBJECTPARAM, &unk);
180         if(unk) {
181             IOleClientSite *client = NULL;
182
183             hres = IUnknown_QueryInterface(unk, &IID_IOleClientSite, (void**)&client);
184             if(SUCCEEDED(hres)) {
185                 TRACE("Got client site %p\n", client);
186                 IOleObject_SetClientSite(OLEOBJ(This), client);
187                 IOleClientSite_Release(client);
188             }
189
190             IUnknown_Release(unk);
191         }
192     }
193
194     HTMLDocument_LockContainer(This, TRUE);
195     
196     hres = IMoniker_GetDisplayName(pimkName, pibc, NULL, &url);
197     if(FAILED(hres)) {
198         WARN("GetDiaplayName failed: %08lx\n", hres);
199         return hres;
200     }
201
202     TRACE("got url: %s\n", debugstr_w(url));
203
204     if(This->client) {
205         IOleCommandTarget *cmdtrg = NULL;
206
207         hres = IOleClientSite_QueryInterface(This->client, &IID_IOleCommandTarget,
208                 (void**)&cmdtrg);
209         if(SUCCEEDED(hres)) {
210             VARIANT var;
211
212             V_VT(&var) = VT_I4;
213             V_I4(&var) = 0;
214             IOleCommandTarget_Exec(cmdtrg, &CGID_ShellDocView, 37, 0, &var, NULL);
215         }
216     }
217
218     bscallback = create_bscallback(This, url);
219
220     if(This->nscontainer) {
221         nsIInputStream *post_data_stream = get_post_data_stream(pibc);
222
223         This->nscontainer->bscallback = bscallback;
224         nsres = nsIWebNavigation_LoadURI(This->nscontainer->navigation, url,
225                 LOAD_FLAGS_NONE, NULL, post_data_stream, NULL);
226         This->nscontainer->bscallback = NULL;
227
228         if(post_data_stream)
229             nsIInputStream_Release(post_data_stream);
230
231         if(!bscallback->nschannel)
232             ERR("bscallback->nschannel == NULL\n");
233
234         if(NS_SUCCEEDED(nsres)) {
235             /* FIXME: don't return here (URL Moniker needs to be good enough) */
236
237             IBindStatusCallback_Release(STATUSCLB(bscallback));
238             CoTaskMemFree(url);
239             return S_OK;
240         }else {
241             WARN("LoadURI failed: %08lx\n", nsres);
242         }
243     }
244
245     /* FIXME: Use grfMode */
246
247     if(fFullyAvailable)
248         FIXME("not supported fFullyAvailable\n");
249     if(pibc)
250         FIXME("not supported pibc\n");
251
252     hres = start_binding(bscallback, pimkName);
253
254     IBindStatusCallback_Release(STATUSCLB(bscallback));
255     CoTaskMemFree(url);
256
257     return hres;
258 }
259
260 static HRESULT WINAPI PersistMoniker_Save(IPersistMoniker *iface, IMoniker *pimkName,
261         LPBC pbc, BOOL fRemember)
262 {
263     HTMLDocument *This = PERSISTMON_THIS(iface);
264     FIXME("(%p)->(%p %p %x)\n", This, pimkName, pbc, fRemember);
265     return E_NOTIMPL;
266 }
267
268 static HRESULT WINAPI PersistMoniker_SaveCompleted(IPersistMoniker *iface, IMoniker *pimkName, LPBC pibc)
269 {
270     HTMLDocument *This = PERSISTMON_THIS(iface);
271     FIXME("(%p)->(%p %p)\n", This, pimkName, pibc);
272     return E_NOTIMPL;
273 }
274
275 static HRESULT WINAPI PersistMoniker_GetCurMoniker(IPersistMoniker *iface, IMoniker **ppimkName)
276 {
277     HTMLDocument *This = PERSISTMON_THIS(iface);
278     FIXME("(%p)->(%p)\n", This, ppimkName);
279     return E_NOTIMPL;
280 }
281
282 static const IPersistMonikerVtbl PersistMonikerVtbl = {
283     PersistMoniker_QueryInterface,
284     PersistMoniker_AddRef,
285     PersistMoniker_Release,
286     PersistMoniker_GetClassID,
287     PersistMoniker_IsDirty,
288     PersistMoniker_Load,
289     PersistMoniker_Save,
290     PersistMoniker_SaveCompleted,
291     PersistMoniker_GetCurMoniker
292 };
293
294 /**********************************************************
295  * IMonikerProp implementation
296  */
297
298 #define MONPROP_THIS(iface) DEFINE_THIS(HTMLDocument, MonikerProp, iface)
299
300 static HRESULT WINAPI MonikerProp_QueryInterface(IMonikerProp *iface, REFIID riid, void **ppvObject)
301 {
302     HTMLDocument *This = MONPROP_THIS(iface);
303     return IHTMLDocument2_QueryInterface(HTMLDOC(This), riid, ppvObject);
304 }
305
306 static ULONG WINAPI MonikerProp_AddRef(IMonikerProp *iface)
307 {
308     HTMLDocument *This = MONPROP_THIS(iface);
309     return IHTMLDocument2_AddRef(HTMLDOC(This));
310 }
311
312 static ULONG WINAPI MonikerProp_Release(IMonikerProp *iface)
313 {
314     HTMLDocument *This = MONPROP_THIS(iface);
315     return IHTMLDocument_Release(HTMLDOC(This));
316 }
317
318 static HRESULT WINAPI MonikerProp_PutProperty(IMonikerProp *iface, MONIKERPROPERTY mkp, LPCWSTR val)
319 {
320     HTMLDocument *This = MONPROP_THIS(iface);
321     FIXME("(%p)->(%d %s)\n", This, mkp, debugstr_w(val));
322     return E_NOTIMPL;
323 }
324
325 static const IMonikerPropVtbl MonikerPropVtbl = {
326     MonikerProp_QueryInterface,
327     MonikerProp_AddRef,
328     MonikerProp_Release,
329     MonikerProp_PutProperty
330 };
331
332 /**********************************************************
333  * IPersistFile implementation
334  */
335
336 #define PERSISTFILE_THIS(iface) DEFINE_THIS(HTMLDocument, PersistFile, iface)
337
338 static HRESULT WINAPI PersistFile_QueryInterface(IPersistFile *iface, REFIID riid, void **ppvObject)
339 {
340     HTMLDocument *This = PERSISTFILE_THIS(iface);
341     return IHTMLDocument2_QueryInterface(HTMLDOC(This), riid, ppvObject);
342 }
343
344 static ULONG WINAPI PersistFile_AddRef(IPersistFile *iface)
345 {
346     HTMLDocument *This = PERSISTFILE_THIS(iface);
347     return IHTMLDocument2_AddRef(HTMLDOC(This));
348 }
349
350 static ULONG WINAPI PersistFile_Release(IPersistFile *iface)
351 {
352     HTMLDocument *This = PERSISTFILE_THIS(iface);
353     return IHTMLDocument2_Release(HTMLDOC(This));
354 }
355
356 static HRESULT WINAPI PersistFile_GetClassID(IPersistFile *iface, CLSID *pClassID)
357 {
358     HTMLDocument *This = PERSISTFILE_THIS(iface);
359
360     TRACE("(%p)->(%p)\n", This, pClassID);
361
362     if(!pClassID)
363         return E_INVALIDARG;
364
365     memcpy(pClassID, &CLSID_HTMLDocument, sizeof(CLSID));
366     return S_OK;
367 }
368
369 static HRESULT WINAPI PersistFile_IsDirty(IPersistFile *iface)
370 {
371     HTMLDocument *This = PERSISTFILE_THIS(iface);
372     FIXME("(%p)\n", This);
373     return E_NOTIMPL;
374 }
375
376 static HRESULT WINAPI PersistFile_Load(IPersistFile *iface, LPCOLESTR pszFileName, DWORD dwMode)
377 {
378     HTMLDocument *This = PERSISTFILE_THIS(iface);
379     FIXME("(%p)->(%s %08lx)\n", This, debugstr_w(pszFileName), dwMode);
380     return E_NOTIMPL;
381 }
382
383 static HRESULT WINAPI PersistFile_Save(IPersistFile *iface, LPCOLESTR pszFileName, BOOL fRemember)
384 {
385     HTMLDocument *This = PERSISTFILE_THIS(iface);
386     FIXME("(%p)->(%s %x)\n", This, debugstr_w(pszFileName), fRemember);
387     return E_NOTIMPL;
388 }
389
390 static HRESULT WINAPI PersistFile_SaveCompleted(IPersistFile *iface, LPCOLESTR pszFileName)
391 {
392     HTMLDocument *This = PERSISTFILE_THIS(iface);
393     FIXME("(%p)->(%s)\n", This, debugstr_w(pszFileName));
394     return E_NOTIMPL;
395 }
396
397 static HRESULT WINAPI PersistFile_GetCurFile(IPersistFile *iface, LPOLESTR *pszFileName)
398 {
399     HTMLDocument *This = PERSISTFILE_THIS(iface);
400     FIXME("(%p)->(%p)\n", This, pszFileName);
401     return E_NOTIMPL;
402 }
403
404 static const IPersistFileVtbl PersistFileVtbl = {
405     PersistFile_QueryInterface,
406     PersistFile_AddRef,
407     PersistFile_Release,
408     PersistFile_GetClassID,
409     PersistFile_IsDirty,
410     PersistFile_Load,
411     PersistFile_Save,
412     PersistFile_SaveCompleted,
413     PersistFile_GetCurFile
414 };
415
416 #define PERSTRINIT_THIS(iface) DEFINE_THIS(HTMLDocument, PersistStreamInit, iface);
417
418 static HRESULT WINAPI PersistStreamInit_QueryInterface(IPersistStreamInit *iface,
419                                                        REFIID riid, void **ppv)
420 {
421     HTMLDocument *This = PERSTRINIT_THIS(iface);
422     return IHTMLDocument2_QueryInterface(HTMLDOC(This), riid, ppv);
423 }
424
425 static ULONG WINAPI PersistStreamInit_AddRef(IPersistStreamInit *iface)
426 {
427     HTMLDocument *This = PERSTRINIT_THIS(iface);
428     return IHTMLDocument2_AddRef(HTMLDOC(This));
429 }
430
431 static ULONG WINAPI PersistStreamInit_Release(IPersistStreamInit *iface)
432 {
433     HTMLDocument *This = PERSTRINIT_THIS(iface);
434     return IHTMLDocument2_AddRef(HTMLDOC(This));
435 }
436
437 static HRESULT WINAPI PersistStreamInit_GetClassID(IPersistStreamInit *iface, CLSID *pClassID)
438 {
439     HTMLDocument *This = PERSTRINIT_THIS(iface);
440     return IPersist_GetClassID(PERSIST(This), pClassID);
441 }
442
443 static HRESULT WINAPI PersistStreamInit_IsDirty(IPersistStreamInit *iface)
444 {
445     HTMLDocument *This = PERSTRINIT_THIS(iface);
446     FIXME("(%p)\n", This);
447     return E_NOTIMPL;
448 }
449
450 static HRESULT WINAPI PersistStreamInit_Load(IPersistStreamInit *iface, LPSTREAM pStm)
451 {
452     HTMLDocument *This = PERSTRINIT_THIS(iface);
453     FIXME("(%p)->(%p)\n", This, pStm);
454     return E_NOTIMPL;
455 }
456
457 static HRESULT WINAPI PersistStreamInit_Save(IPersistStreamInit *iface, LPSTREAM pStm,
458                                              BOOL fClearDirty)
459 {
460     HTMLDocument *This = PERSTRINIT_THIS(iface);
461     FIXME("(%p)->(%p %x)\n", This, pStm, fClearDirty);
462     return E_NOTIMPL;
463 }
464
465 static HRESULT WINAPI PersistStreamInit_GetSizeMax(IPersistStreamInit *iface,
466                                                    ULARGE_INTEGER *pcbSize)
467 {
468     HTMLDocument *This = PERSTRINIT_THIS(iface);
469     FIXME("(%p)->(%p)\n", This, pcbSize);
470     return E_NOTIMPL;
471 }
472
473 static HRESULT WINAPI PersistStreamInit_InitNew(IPersistStreamInit *iface)
474 {
475     HTMLDocument *This = PERSTRINIT_THIS(iface);
476     FIXME("(%p)\n", This);
477     return E_NOTIMPL;
478 }
479
480 #undef PERSTRINIT_THIS
481
482 static const IPersistStreamInitVtbl PersistStreamInitVtbl = {
483     PersistStreamInit_QueryInterface,
484     PersistStreamInit_AddRef,
485     PersistStreamInit_Release,
486     PersistStreamInit_GetClassID,
487     PersistStreamInit_IsDirty,
488     PersistStreamInit_Load,
489     PersistStreamInit_Save,
490     PersistStreamInit_GetSizeMax,
491     PersistStreamInit_InitNew
492 };
493
494 void HTMLDocument_Persist_Init(HTMLDocument *This)
495 {
496     This->lpPersistMonikerVtbl = &PersistMonikerVtbl;
497     This->lpPersistFileVtbl = &PersistFileVtbl;
498     This->lpMonikerPropVtbl = &MonikerPropVtbl;
499     This->lpPersistStreamInitVtbl = &PersistStreamInitVtbl;
500 }