comdlg32: Correct title of "Save As" dialog.
[wine] / dlls / mshtml / htmllocation.c
1 /*
2  * Copyright 2008 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 "winreg.h"
27 #include "ole2.h"
28 #include "wininet.h"
29 #include "shlwapi.h"
30
31 #include "wine/debug.h"
32
33 #include "mshtml_private.h"
34 #include "resource.h"
35
36 WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
37
38 static HRESULT get_url(HTMLLocation *This, const WCHAR **ret)
39 {
40     if(!This->window || !This->window->url) {
41         FIXME("No current URL\n");
42         return E_NOTIMPL;
43     }
44
45     *ret = This->window->url;
46     return S_OK;
47 }
48
49 static HRESULT get_url_components(HTMLLocation *This, URL_COMPONENTSW *url)
50 {
51     const WCHAR *doc_url;
52     HRESULT hres;
53
54     hres = get_url(This, &doc_url);
55     if(FAILED(hres))
56         return hres;
57
58     if(!InternetCrackUrlW(doc_url, 0, 0, url)) {
59         FIXME("InternetCrackUrlW failed: 0x%08x\n", GetLastError());
60         SetLastError(0);
61         return E_FAIL;
62     }
63
64     return S_OK;
65 }
66
67 static inline HTMLLocation *impl_from_IHTMLLocation(IHTMLLocation *iface)
68 {
69     return CONTAINING_RECORD(iface, HTMLLocation, IHTMLLocation_iface);
70 }
71
72 static HRESULT WINAPI HTMLLocation_QueryInterface(IHTMLLocation *iface, REFIID riid, void **ppv)
73 {
74     HTMLLocation *This = impl_from_IHTMLLocation(iface);
75
76     *ppv = NULL;
77
78     if(IsEqualGUID(&IID_IUnknown, riid)) {
79         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
80         *ppv = &This->IHTMLLocation_iface;
81     }else if(IsEqualGUID(&IID_IHTMLLocation, riid)) {
82         TRACE("(%p)->(IID_IHTMLLocation %p)\n", This, ppv);
83         *ppv = &This->IHTMLLocation_iface;
84     }else if(dispex_query_interface(&This->dispex, riid, ppv)) {
85         return *ppv ? S_OK : E_NOINTERFACE;
86     }
87
88     if(*ppv) {
89         IUnknown_AddRef((IUnknown*)*ppv);
90         return S_OK;
91     }
92
93     WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
94     return E_NOINTERFACE;
95 }
96
97 static ULONG WINAPI HTMLLocation_AddRef(IHTMLLocation *iface)
98 {
99     HTMLLocation *This = impl_from_IHTMLLocation(iface);
100     LONG ref = InterlockedIncrement(&This->ref);
101
102     TRACE("(%p) ref=%d\n", This, ref);
103
104     return ref;
105 }
106
107 static ULONG WINAPI HTMLLocation_Release(IHTMLLocation *iface)
108 {
109     HTMLLocation *This = impl_from_IHTMLLocation(iface);
110     LONG ref = InterlockedDecrement(&This->ref);
111
112     TRACE("(%p) ref=%d\n", This, ref);
113
114     if(!ref) {
115         if(This->window)
116             This->window->location = NULL;
117         release_dispex(&This->dispex);
118         heap_free(This);
119     }
120
121     return ref;
122 }
123
124 static HRESULT WINAPI HTMLLocation_GetTypeInfoCount(IHTMLLocation *iface, UINT *pctinfo)
125 {
126     HTMLLocation *This = impl_from_IHTMLLocation(iface);
127     return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo);
128 }
129
130 static HRESULT WINAPI HTMLLocation_GetTypeInfo(IHTMLLocation *iface, UINT iTInfo,
131                                               LCID lcid, ITypeInfo **ppTInfo)
132 {
133     HTMLLocation *This = impl_from_IHTMLLocation(iface);
134     return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo);
135 }
136
137 static HRESULT WINAPI HTMLLocation_GetIDsOfNames(IHTMLLocation *iface, REFIID riid,
138                                                 LPOLESTR *rgszNames, UINT cNames,
139                                                 LCID lcid, DISPID *rgDispId)
140 {
141     HTMLLocation *This = impl_from_IHTMLLocation(iface);
142     return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface, riid, rgszNames, cNames,
143             lcid, rgDispId);
144 }
145
146 static HRESULT WINAPI HTMLLocation_Invoke(IHTMLLocation *iface, DISPID dispIdMember,
147                             REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
148                             VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
149 {
150     HTMLLocation *This = impl_from_IHTMLLocation(iface);
151     return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface, dispIdMember, riid, lcid,
152             wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
153 }
154
155 static HRESULT WINAPI HTMLLocation_put_href(IHTMLLocation *iface, BSTR v)
156 {
157     HTMLLocation *This = impl_from_IHTMLLocation(iface);
158
159     TRACE("(%p)->(%s)\n", This, debugstr_w(v));
160
161     if(!This->window) {
162         FIXME("No window available\n");
163         return E_FAIL;
164     }
165
166     return navigate_url(This->window, v, This->window->url);
167 }
168
169 static HRESULT WINAPI HTMLLocation_get_href(IHTMLLocation *iface, BSTR *p)
170 {
171     HTMLLocation *This = impl_from_IHTMLLocation(iface);
172     URL_COMPONENTSW url = {sizeof(URL_COMPONENTSW)};
173     WCHAR *buf = NULL, *url_path = NULL;
174     HRESULT hres, ret;
175     DWORD len = 0;
176     int i;
177
178     TRACE("(%p)->(%p)\n", This, p);
179
180     if(!p)
181         return E_POINTER;
182
183     url.dwSchemeLength = 1;
184     url.dwHostNameLength = 1;
185     url.dwUrlPathLength = 1;
186     url.dwExtraInfoLength = 1;
187     hres = get_url_components(This, &url);
188     if(FAILED(hres))
189         return hres;
190
191     switch(url.nScheme) {
192     case INTERNET_SCHEME_FILE:
193         {
194             /* prepend a slash */
195             url_path = HeapAlloc(GetProcessHeap(), 0, (url.dwUrlPathLength + 1) * sizeof(WCHAR));
196             if(!url_path)
197                 return E_OUTOFMEMORY;
198             url_path[0] = '/';
199             memcpy(url_path + 1, url.lpszUrlPath, url.dwUrlPathLength * sizeof(WCHAR));
200             url.lpszUrlPath = url_path;
201             url.dwUrlPathLength = url.dwUrlPathLength + 1;
202         }
203         break;
204
205     case INTERNET_SCHEME_HTTP:
206     case INTERNET_SCHEME_HTTPS:
207     case INTERNET_SCHEME_FTP:
208         if(!url.dwUrlPathLength) {
209             /* add a slash if it's blank */
210             url_path = url.lpszUrlPath = HeapAlloc(GetProcessHeap(), 0, 1 * sizeof(WCHAR));
211             if(!url.lpszUrlPath)
212                 return E_OUTOFMEMORY;
213             url.lpszUrlPath[0] = '/';
214             url.dwUrlPathLength = 1;
215         }
216         break;
217
218     default:
219         break;
220     }
221
222     /* replace \ with / */
223     for(i = 0; i < url.dwUrlPathLength; ++i)
224         if(url.lpszUrlPath[i] == '\\')
225             url.lpszUrlPath[i] = '/';
226
227     if(InternetCreateUrlW(&url, ICU_ESCAPE, NULL, &len)) {
228         FIXME("InternetCreateUrl succeeded with NULL buffer?\n");
229         ret = E_FAIL;
230         goto cleanup;
231     }
232
233     if(GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
234         FIXME("InternetCreateUrl failed with error: %08x\n", GetLastError());
235         SetLastError(0);
236         ret = E_FAIL;
237         goto cleanup;
238     }
239     SetLastError(0);
240
241     buf = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
242     if(!buf) {
243         ret = E_OUTOFMEMORY;
244         goto cleanup;
245     }
246
247     if(!InternetCreateUrlW(&url, ICU_ESCAPE, buf, &len)) {
248         FIXME("InternetCreateUrl failed with error: %08x\n", GetLastError());
249         SetLastError(0);
250         ret = E_FAIL;
251         goto cleanup;
252     }
253
254     *p = SysAllocStringLen(buf, len);
255     if(!*p) {
256         ret = E_OUTOFMEMORY;
257         goto cleanup;
258     }
259
260     ret = S_OK;
261
262 cleanup:
263     HeapFree(GetProcessHeap(), 0, buf);
264     HeapFree(GetProcessHeap(), 0, url_path);
265
266     return ret;
267 }
268
269 static HRESULT WINAPI HTMLLocation_put_protocol(IHTMLLocation *iface, BSTR v)
270 {
271     HTMLLocation *This = impl_from_IHTMLLocation(iface);
272     FIXME("(%p)->(%s)\n", This, debugstr_w(v));
273     return E_NOTIMPL;
274 }
275
276 static HRESULT WINAPI HTMLLocation_get_protocol(IHTMLLocation *iface, BSTR *p)
277 {
278     HTMLLocation *This = impl_from_IHTMLLocation(iface);
279     URL_COMPONENTSW url = {sizeof(URL_COMPONENTSW)};
280     HRESULT hres;
281
282     TRACE("(%p)->(%p)\n", This, p);
283
284     if(!p)
285         return E_POINTER;
286
287     url.dwSchemeLength = 1;
288     hres = get_url_components(This, &url);
289     if(FAILED(hres))
290         return hres;
291
292     if(!url.dwSchemeLength) {
293         FIXME("Unexpected blank protocol\n");
294         return E_NOTIMPL;
295     }else {
296         WCHAR *buf;
297         buf = *p = SysAllocStringLen(NULL, url.dwSchemeLength + 1);
298         memcpy(buf, url.lpszScheme, url.dwSchemeLength * sizeof(WCHAR));
299         buf[url.dwSchemeLength] = ':';
300     }
301     if(!*p)
302         return E_OUTOFMEMORY;
303     return S_OK;
304 }
305
306 static HRESULT WINAPI HTMLLocation_put_host(IHTMLLocation *iface, BSTR v)
307 {
308     HTMLLocation *This = impl_from_IHTMLLocation(iface);
309     FIXME("(%p)->(%s)\n", This, debugstr_w(v));
310     return E_NOTIMPL;
311 }
312
313 static HRESULT WINAPI HTMLLocation_get_host(IHTMLLocation *iface, BSTR *p)
314 {
315     HTMLLocation *This = impl_from_IHTMLLocation(iface);
316     URL_COMPONENTSW url = {sizeof(URL_COMPONENTSW)};
317     HRESULT hres;
318
319     TRACE("(%p)->(%p)\n", This, p);
320
321     if(!p)
322         return E_POINTER;
323
324     url.dwHostNameLength = 1;
325     hres = get_url_components(This, &url);
326     if(FAILED(hres))
327         return hres;
328
329     if(!url.dwHostNameLength){
330         *p = NULL;
331         return S_OK;
332     }
333
334     if(url.nPort) {
335         /* <hostname>:<port> */
336         const WCHAR format[] = {'%','u',0};
337         DWORD len = url.dwHostNameLength + 1 + 5;
338         WCHAR *buf;
339
340         buf = *p = SysAllocStringLen(NULL, len);
341         memcpy(buf, url.lpszHostName, url.dwHostNameLength * sizeof(WCHAR));
342         buf[url.dwHostNameLength] = ':';
343         snprintfW(buf + url.dwHostNameLength + 1, 6, format, url.nPort);
344     }else
345         *p = SysAllocStringLen(url.lpszHostName, url.dwHostNameLength);
346
347     if(!*p)
348         return E_OUTOFMEMORY;
349     return S_OK;
350 }
351
352 static HRESULT WINAPI HTMLLocation_put_hostname(IHTMLLocation *iface, BSTR v)
353 {
354     HTMLLocation *This = impl_from_IHTMLLocation(iface);
355     FIXME("(%p)->(%s)\n", This, debugstr_w(v));
356     return E_NOTIMPL;
357 }
358
359 static HRESULT WINAPI HTMLLocation_get_hostname(IHTMLLocation *iface, BSTR *p)
360 {
361     HTMLLocation *This = impl_from_IHTMLLocation(iface);
362     BSTR hostname;
363     HRESULT hres;
364
365     TRACE("(%p)->(%p)\n", This, p);
366
367     if(!p)
368         return E_POINTER;
369
370     if(!This->window || !This->window->uri) {
371         FIXME("No current URI\n");
372         return E_NOTIMPL;
373     }
374
375     hres = IUri_GetHost(This->window->uri, &hostname);
376     if(hres == S_OK) {
377         *p = hostname;
378     }else if(hres == S_FALSE) {
379         SysFreeString(hostname);
380         *p = NULL;
381     }else {
382         return hres;
383     }
384
385     return S_OK;
386 }
387
388 static HRESULT WINAPI HTMLLocation_put_port(IHTMLLocation *iface, BSTR v)
389 {
390     HTMLLocation *This = impl_from_IHTMLLocation(iface);
391     FIXME("(%p)->(%s)\n", This, debugstr_w(v));
392     return E_NOTIMPL;
393 }
394
395 static HRESULT WINAPI HTMLLocation_get_port(IHTMLLocation *iface, BSTR *p)
396 {
397     HTMLLocation *This = impl_from_IHTMLLocation(iface);
398     URL_COMPONENTSW url = {sizeof(URL_COMPONENTSW)};
399     HRESULT hres;
400
401     TRACE("(%p)->(%p)\n", This, p);
402
403     if(!p)
404         return E_POINTER;
405
406     hres = get_url_components(This, &url);
407     if(FAILED(hres))
408         return hres;
409
410     if(url.nPort) {
411         const WCHAR format[] = {'%','u',0};
412         WCHAR buf[6];
413         snprintfW(buf, 6, format, url.nPort);
414         *p = SysAllocString(buf);
415     }else {
416         const WCHAR empty[] = {0};
417         *p = SysAllocString(empty);
418     }
419
420     if(!*p)
421         return E_OUTOFMEMORY;
422     return S_OK;
423 }
424
425 static HRESULT WINAPI HTMLLocation_put_pathname(IHTMLLocation *iface, BSTR v)
426 {
427     HTMLLocation *This = impl_from_IHTMLLocation(iface);
428     FIXME("(%p)->(%s)\n", This, debugstr_w(v));
429     return E_NOTIMPL;
430 }
431
432 static HRESULT WINAPI HTMLLocation_get_pathname(IHTMLLocation *iface, BSTR *p)
433 {
434     HTMLLocation *This = impl_from_IHTMLLocation(iface);
435     URL_COMPONENTSW url = {sizeof(URL_COMPONENTSW)};
436     HRESULT hres;
437
438     TRACE("(%p)->(%p)\n", This, p);
439
440     if(!p)
441         return E_POINTER;
442
443     url.dwUrlPathLength = 1;
444     url.dwExtraInfoLength = 1;
445     hres = get_url_components(This, &url);
446     if(FAILED(hres))
447         return hres;
448
449     if(url.dwUrlPathLength && url.lpszUrlPath[0] == '/')
450         *p = SysAllocStringLen(url.lpszUrlPath + 1, url.dwUrlPathLength - 1);
451     else
452         *p = SysAllocStringLen(url.lpszUrlPath, url.dwUrlPathLength);
453
454     if(!*p)
455         return E_OUTOFMEMORY;
456     return S_OK;
457 }
458
459 static HRESULT WINAPI HTMLLocation_put_search(IHTMLLocation *iface, BSTR v)
460 {
461     HTMLLocation *This = impl_from_IHTMLLocation(iface);
462     FIXME("(%p)->(%s)\n", This, debugstr_w(v));
463     return E_NOTIMPL;
464 }
465
466 static HRESULT WINAPI HTMLLocation_get_search(IHTMLLocation *iface, BSTR *p)
467 {
468     HTMLLocation *This = impl_from_IHTMLLocation(iface);
469     URL_COMPONENTSW url = {sizeof(URL_COMPONENTSW)};
470     HRESULT hres;
471     const WCHAR hash[] = {'#',0};
472
473     TRACE("(%p)->(%p)\n", This, p);
474
475     if(!p)
476         return E_POINTER;
477
478     url.dwExtraInfoLength = 1;
479     hres = get_url_components(This, &url);
480     if(FAILED(hres))
481         return hres;
482
483     if(!url.dwExtraInfoLength){
484         *p = NULL;
485         return S_OK;
486     }
487
488     url.dwExtraInfoLength = strcspnW(url.lpszExtraInfo, hash);
489
490     *p = SysAllocStringLen(url.lpszExtraInfo, url.dwExtraInfoLength);
491
492     if(!*p)
493         return E_OUTOFMEMORY;
494     return S_OK;
495 }
496
497 static HRESULT WINAPI HTMLLocation_put_hash(IHTMLLocation *iface, BSTR v)
498 {
499     HTMLLocation *This = impl_from_IHTMLLocation(iface);
500     FIXME("(%p)->(%s)\n", This, debugstr_w(v));
501     return E_NOTIMPL;
502 }
503
504 static HRESULT WINAPI HTMLLocation_get_hash(IHTMLLocation *iface, BSTR *p)
505 {
506     HTMLLocation *This = impl_from_IHTMLLocation(iface);
507     URL_COMPONENTSW url = {sizeof(URL_COMPONENTSW)};
508     const WCHAR hash[] = {'#',0};
509     DWORD hash_pos = 0;
510     HRESULT hres;
511
512     TRACE("(%p)->(%p)\n", This, p);
513
514     if(!p)
515         return E_POINTER;
516
517     url.dwExtraInfoLength = 1;
518     hres = get_url_components(This, &url);
519     if(FAILED(hres))
520         return hres;
521
522     if(!url.dwExtraInfoLength){
523         *p = NULL;
524         return S_OK;
525     }
526
527     hash_pos = strcspnW(url.lpszExtraInfo, hash);
528     url.dwExtraInfoLength -= hash_pos;
529
530     *p = SysAllocStringLen(url.lpszExtraInfo + hash_pos, url.dwExtraInfoLength);
531
532     if(!*p)
533         return E_OUTOFMEMORY;
534     return S_OK;
535 }
536
537 static HRESULT WINAPI HTMLLocation_reload(IHTMLLocation *iface, VARIANT_BOOL flag)
538 {
539     HTMLLocation *This = impl_from_IHTMLLocation(iface);
540     FIXME("(%p)->(%x)\n", This, flag);
541     return E_NOTIMPL;
542 }
543
544 static HRESULT WINAPI HTMLLocation_replace(IHTMLLocation *iface, BSTR bstr)
545 {
546     HTMLLocation *This = impl_from_IHTMLLocation(iface);
547
548     TRACE("(%p)->(%s)\n", This, debugstr_w(bstr));
549
550     if(!This->window) {
551         FIXME("No window available\n");
552         return E_FAIL;
553     }
554
555     return navigate_url(This->window, bstr, This->window->url);
556 }
557
558 static HRESULT WINAPI HTMLLocation_assign(IHTMLLocation *iface, BSTR bstr)
559 {
560     HTMLLocation *This = impl_from_IHTMLLocation(iface);
561     FIXME("(%p)->(%s)\n", This, debugstr_w(bstr));
562     return E_NOTIMPL;
563 }
564
565 static HRESULT WINAPI HTMLLocation_toString(IHTMLLocation *iface, BSTR *String)
566 {
567     HTMLLocation *This = impl_from_IHTMLLocation(iface);
568     FIXME("(%p)->(%p)\n", This, String);
569     return E_NOTIMPL;
570 }
571
572 static const IHTMLLocationVtbl HTMLLocationVtbl = {
573     HTMLLocation_QueryInterface,
574     HTMLLocation_AddRef,
575     HTMLLocation_Release,
576     HTMLLocation_GetTypeInfoCount,
577     HTMLLocation_GetTypeInfo,
578     HTMLLocation_GetIDsOfNames,
579     HTMLLocation_Invoke,
580     HTMLLocation_put_href,
581     HTMLLocation_get_href,
582     HTMLLocation_put_protocol,
583     HTMLLocation_get_protocol,
584     HTMLLocation_put_host,
585     HTMLLocation_get_host,
586     HTMLLocation_put_hostname,
587     HTMLLocation_get_hostname,
588     HTMLLocation_put_port,
589     HTMLLocation_get_port,
590     HTMLLocation_put_pathname,
591     HTMLLocation_get_pathname,
592     HTMLLocation_put_search,
593     HTMLLocation_get_search,
594     HTMLLocation_put_hash,
595     HTMLLocation_get_hash,
596     HTMLLocation_reload,
597     HTMLLocation_replace,
598     HTMLLocation_assign,
599     HTMLLocation_toString
600 };
601
602 static const tid_t HTMLLocation_iface_tids[] = {
603     IHTMLLocation_tid,
604     0
605 };
606 static dispex_static_data_t HTMLLocation_dispex = {
607     NULL,
608     DispHTMLLocation_tid,
609     NULL,
610     HTMLLocation_iface_tids
611 };
612
613
614 HRESULT HTMLLocation_Create(HTMLWindow *window, HTMLLocation **ret)
615 {
616     HTMLLocation *location;
617
618     location = heap_alloc(sizeof(*location));
619     if(!location)
620         return E_OUTOFMEMORY;
621
622     location->IHTMLLocation_iface.lpVtbl = &HTMLLocationVtbl;
623     location->ref = 1;
624     location->window = window;
625
626     init_dispex(&location->dispex, (IUnknown*)&location->IHTMLLocation_iface, &HTMLLocation_dispex);
627
628     *ret = location;
629     return S_OK;
630 }