user: Fix SPI_SETICONTITLELOGFONT to check for LOGFONTW size.
[wine] / dlls / urlmon / urlmon_main.c
1 /*
2  * UrlMon
3  *
4  * Copyright (c) 2000 Patrik Stridvall
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include <stdarg.h>
22
23 #define COBJMACROS
24
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winreg.h"
28
29 #define NO_SHLWAPI_REG
30 #include "shlwapi.h"
31 #include "wine/debug.h"
32 #include "wine/unicode.h"
33
34 #include "winuser.h"
35 #include "urlmon.h"
36 #include "urlmon_main.h"
37 #include "ole2.h"
38
39 WINE_DEFAULT_DEBUG_CHANNEL(urlmon);
40
41 LONG URLMON_refCount = 0;
42
43 HINSTANCE URLMON_hInstance = 0;
44 static HMODULE hCabinet = NULL;
45
46 DWORD urlmon_tls = 0;
47
48 static void init_session(BOOL);
49
50 /***********************************************************************
51  *              DllMain (URLMON.init)
52  */
53 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad)
54 {
55     TRACE("%p 0x%lx %p\n", hinstDLL, fdwReason, fImpLoad);
56
57     switch(fdwReason) {
58     case DLL_PROCESS_ATTACH:
59         DisableThreadLibraryCalls(hinstDLL);
60         URLMON_hInstance = hinstDLL;
61         init_session(TRUE);
62         break;
63
64     case DLL_PROCESS_DETACH:
65         if(urlmon_tls)
66             TlsFree(urlmon_tls);
67         if (hCabinet)
68             FreeLibrary(hCabinet);
69         hCabinet = NULL;
70         init_session(FALSE);
71         URLMON_hInstance = 0;
72         break;
73     }
74     return TRUE;
75 }
76
77
78 /***********************************************************************
79  *              DllInstall (URLMON.@)
80  */
81 HRESULT WINAPI DllInstall(BOOL bInstall, LPCWSTR cmdline)
82 {
83   FIXME("(%s, %s): stub\n", bInstall?"TRUE":"FALSE",
84         debugstr_w(cmdline));
85
86   return S_OK;
87 }
88
89 /***********************************************************************
90  *              DllCanUnloadNow (URLMON.@)
91  */
92 HRESULT WINAPI DllCanUnloadNow(void)
93 {
94     return URLMON_refCount != 0 ? S_FALSE : S_OK;
95 }
96
97
98
99 /******************************************************************************
100  * Urlmon ClassFactory
101  */
102 typedef struct {
103     const IClassFactoryVtbl *lpClassFactoryVtbl;
104
105     HRESULT (*pfnCreateInstance)(IUnknown *pUnkOuter, LPVOID *ppObj);
106 } ClassFactory;
107
108 #define CLASSFACTORY(x)  ((IClassFactory*)  &(x)->lpClassFactoryVtbl)
109
110 static HRESULT WINAPI CF_QueryInterface(IClassFactory *iface, REFIID riid, LPVOID *ppv)
111 {
112     *ppv = NULL;
113
114     if(IsEqualGUID(riid, &IID_IUnknown)) {
115         TRACE("(%p)->(IID_IUnknown %p)\n", iface, ppv);
116         *ppv = iface;
117     }else if(IsEqualGUID(riid, &IID_IClassFactory)) {
118         TRACE("(%p)->(IID_IClassFactory %p)\n", iface, ppv);
119         *ppv = iface;
120     }
121
122     if(*ppv) {
123         IUnknown_AddRef((IUnknown*)*ppv);
124         return S_OK;
125     }
126
127     WARN("(%p)->(%s,%p),not found\n", iface, debugstr_guid(riid), ppv);
128     return E_NOINTERFACE;
129 }
130
131 static ULONG WINAPI CF_AddRef(IClassFactory *iface)
132 {
133     URLMON_LockModule();
134     return 2;
135 }
136
137 static ULONG WINAPI CF_Release(IClassFactory *iface)
138 {
139     URLMON_UnlockModule();
140     return 1;
141 }
142
143
144 static HRESULT WINAPI CF_CreateInstance(IClassFactory *iface, IUnknown *pOuter,
145                                         REFIID riid, LPVOID *ppobj)
146 {
147     ClassFactory *This = (ClassFactory*)iface;
148     HRESULT hres;
149     LPUNKNOWN punk;
150     
151     TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj);
152
153     *ppobj = NULL;
154     if(SUCCEEDED(hres = This->pfnCreateInstance(pOuter, (LPVOID *) &punk))) {
155         hres = IUnknown_QueryInterface(punk, riid, ppobj);
156         IUnknown_Release(punk);
157     }
158     return hres;
159 }
160
161 static HRESULT WINAPI CF_LockServer(LPCLASSFACTORY iface,BOOL dolock)
162 {
163     TRACE("(%d)\n", dolock);
164
165     if (dolock)
166            URLMON_LockModule();
167     else
168            URLMON_UnlockModule();
169
170     return S_OK;
171 }
172
173 static const IClassFactoryVtbl ClassFactoryVtbl =
174 {
175     CF_QueryInterface,
176     CF_AddRef,
177     CF_Release,
178     CF_CreateInstance,
179     CF_LockServer
180 };
181
182 static const ClassFactory FileProtocolCF =
183     { &ClassFactoryVtbl, FileProtocol_Construct};
184 static const ClassFactory FtpProtocolCF =
185     { &ClassFactoryVtbl, FtpProtocol_Construct};
186 static const ClassFactory HttpProtocolCF =
187     { &ClassFactoryVtbl, HttpProtocol_Construct};
188 static const ClassFactory SecurityManagerCF =
189     { &ClassFactoryVtbl, SecManagerImpl_Construct};
190 static const ClassFactory ZoneManagerCF =
191     { &ClassFactoryVtbl, ZoneMgrImpl_Construct};
192  
193 struct object_creation_info
194 {
195     const CLSID *clsid;
196     IClassFactory *cf;
197     LPCWSTR protocol;
198 };
199
200 static const WCHAR wszFile[] = {'f','i','l','e',0};
201 static const WCHAR wszFtp[]  = {'f','t','p',0};
202 static const WCHAR wszHttp[] = {'h','t','t','p',0};
203
204 static const struct object_creation_info object_creation[] =
205 {
206     { &CLSID_FileProtocol,            CLASSFACTORY(&FileProtocolCF),    wszFile },
207     { &CLSID_FtpProtocol,             CLASSFACTORY(&FtpProtocolCF),     wszFtp  },
208     { &CLSID_HttpProtocol,            CLASSFACTORY(&HttpProtocolCF),    wszHttp },
209     { &CLSID_InternetSecurityManager, CLASSFACTORY(&SecurityManagerCF), NULL    },
210     { &CLSID_InternetZoneManager,     CLASSFACTORY(&ZoneManagerCF),     NULL    }
211 };
212
213 static void init_session(BOOL init)
214 {
215     IInternetSession *session;
216     int i;
217
218     CoInternetGetSession(0, &session, 0);
219
220     for(i=0; i < sizeof(object_creation)/sizeof(object_creation[0]); i++) {
221         if(object_creation[i].protocol) {
222             if(init)
223                 IInternetSession_RegisterNameSpace(session, object_creation[i].cf,
224                         object_creation[i].clsid, object_creation[i].protocol, 0, NULL, 0);
225             else
226                 IInternetSession_UnregisterNameSpace(session, object_creation[i].cf,
227                         object_creation[i].protocol);
228         }
229     }
230
231     IInternetSession_Release(session);
232 }
233
234 /*******************************************************************************
235  * DllGetClassObject [URLMON.@]
236  * Retrieves class object from a DLL object
237  *
238  * NOTES
239  *    Docs say returns STDAPI
240  *
241  * PARAMS
242  *    rclsid [I] CLSID for the class object
243  *    riid   [I] Reference to identifier of interface for class object
244  *    ppv    [O] Address of variable to receive interface pointer for riid
245  *
246  * RETURNS
247  *    Success: S_OK
248  *    Failure: CLASS_E_CLASSNOTAVAILABLE, E_OUTOFMEMORY, E_INVALIDARG,
249  *             E_UNEXPECTED
250  */
251
252 HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
253 {
254     int i;
255     
256     TRACE("(%s,%s,%p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
257     
258     for (i=0; i < sizeof(object_creation)/sizeof(object_creation[0]); i++)
259     {
260         if (IsEqualGUID(object_creation[i].clsid, rclsid))
261             return IClassFactory_QueryInterface(object_creation[i].cf, riid, ppv);
262     }
263
264     FIXME("%s: no class found.\n", debugstr_guid(rclsid));
265     return CLASS_E_CLASSNOTAVAILABLE;
266 }
267
268
269 /***********************************************************************
270  *              DllRegisterServerEx (URLMON.@)
271  */
272 HRESULT WINAPI DllRegisterServerEx(void)
273 {
274     FIXME("(void): stub\n");
275
276     return E_FAIL;
277 }
278
279 /**************************************************************************
280  *                 UrlMkSetSessionOption (URLMON.@)
281  */
282 HRESULT WINAPI UrlMkSetSessionOption(DWORD dwOption, LPVOID pBuffer, DWORD dwBufferLength,
283                                         DWORD Reserved)
284 {
285     FIXME("(%#lx, %p, %#lx): stub\n", dwOption, pBuffer, dwBufferLength);
286
287     return S_OK;
288 }
289
290 static const CHAR Agent[] = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)";
291
292 /**************************************************************************
293  *                 ObtainUserAgentString (URLMON.@)
294  */
295 HRESULT WINAPI ObtainUserAgentString(DWORD dwOption, LPSTR pcszUAOut, DWORD *cbSize)
296 {
297     FIXME("(%ld, %p, %p): stub\n", dwOption, pcszUAOut, cbSize);
298
299     if(dwOption) {
300       ERR("dwOption: %ld, must be zero\n", dwOption);
301     }
302
303     if (sizeof(Agent) < *cbSize)
304         *cbSize = sizeof(Agent);
305     lstrcpynA(pcszUAOut, Agent, *cbSize); 
306
307     return S_OK;
308 }
309
310 HRESULT WINAPI CoInternetCompareUrl(LPCWSTR pwzUrl1, LPCWSTR pwzUrl2, DWORD dwCompareFlags)
311 {
312     TRACE("(%s,%s,%08lx)\n", debugstr_w(pwzUrl1), debugstr_w(pwzUrl2), dwCompareFlags);
313     return UrlCompareW(pwzUrl1, pwzUrl2, dwCompareFlags)==0?S_OK:S_FALSE;
314 }
315
316 /**************************************************************************
317  *                 IsValidURL (URLMON.@)
318  * 
319  * Determines if a specified string is a valid URL.
320  *
321  * PARAMS
322  *  pBC        [I] ignored, must be NULL.
323  *  szURL      [I] string that represents the URL in question.
324  *  dwReserved [I] reserved and must be zero.
325  *
326  * RETURNS
327  *  Success: S_OK.
328  *  Failure: S_FALSE.
329  *  returns E_INVALIDARG if one or more of the args is invalid.
330  *
331  * TODO:
332  *  test functionality against windows to see what a valid URL is.
333  */
334 HRESULT WINAPI IsValidURL(LPBC pBC, LPCWSTR szURL, DWORD dwReserved)
335 {
336     FIXME("(%p, %s, %ld): stub\n", pBC, debugstr_w(szURL), dwReserved);
337     
338     if (pBC != NULL || dwReserved != 0)
339         return E_INVALIDARG;
340     
341     return S_OK;
342 }
343
344 /**************************************************************************
345  *                 FaultInIEFeature (URLMON.@)
346  *
347  *  Undocumented.  Appears to be used by native shdocvw.dll.
348  */
349 HRESULT WINAPI FaultInIEFeature( HWND hwnd, uCLSSPEC * pClassSpec,
350                                  QUERYCONTEXT *pQuery, DWORD flags )
351 {
352     FIXME("%p %p %p %08lx\n", hwnd, pClassSpec, pQuery, flags);
353     return E_NOTIMPL;
354 }
355
356 /**************************************************************************
357  *                 CoGetClassObjectFromURL (URLMON.@)
358  */
359 HRESULT WINAPI CoGetClassObjectFromURL( REFCLSID rclsid, LPCWSTR szCodeURL, DWORD dwFileVersionMS,
360                                         DWORD dwFileVersionLS, LPCWSTR szContentType,
361                                         LPBINDCTX pBindCtx, DWORD dwClsContext, LPVOID pvReserved,
362                                         REFIID riid, LPVOID *ppv )
363 {
364     FIXME("(%s %s %ld %ld %s %p %ld %p %s %p) Stub!\n", debugstr_guid(rclsid), debugstr_w(szCodeURL),
365         dwFileVersionMS, dwFileVersionLS, debugstr_w(szContentType), pBindCtx, dwClsContext, pvReserved,
366         debugstr_guid(riid), ppv);
367     return E_NOINTERFACE;
368 }
369
370 /***********************************************************************
371  *           ReleaseBindInfo (URLMON.@)
372  *
373  * Release the resources used by the specified BINDINFO structure.
374  *
375  * PARAMS
376  *  pbindinfo [I] BINDINFO to release.
377  *
378  * RETURNS
379  *  Nothing.
380  */
381 void WINAPI ReleaseBindInfo(BINDINFO* pbindinfo)
382 {
383     DWORD size;
384
385     TRACE("(%p)\n", pbindinfo);
386
387     if(!pbindinfo || !(size = pbindinfo->cbSize))
388         return;
389
390     CoTaskMemFree(pbindinfo->szExtraInfo);
391     ReleaseStgMedium(&pbindinfo->stgmedData);
392
393     if(offsetof(BINDINFO, szExtraInfo) < size)
394         CoTaskMemFree(pbindinfo->szCustomVerb);
395
396
397     if(pbindinfo->pUnk && offsetof(BINDINFO, pUnk) < size)
398         IUnknown_Release(pbindinfo->pUnk);
399
400     memset(pbindinfo, 0, size);
401     pbindinfo->cbSize = size;
402 }
403
404 /***********************************************************************
405  *           FindMimeFromData (URLMON.@)
406  *
407  * Determines the Multipurpose Internet Mail Extensions (MIME) type from the data provided.
408  */
409 static BOOL text_html_filter(LPVOID buf, DWORD size)
410 {
411     const char *b = buf;
412     int i;
413
414     if(size < 5)
415         return FALSE;
416
417     for(i=0; i < size-5; i++) {
418         if(b[i] == '<'
419            && (b[i+1] == 'h' || b[i+1] == 'H')
420            && (b[i+2] == 't' || b[i+2] == 'T')
421            && (b[i+3] == 'm' || b[i+3] == 'M')
422            && (b[i+4] == 'l' || b[i+4] == 'L'))
423             return TRUE;
424     }
425
426     return FALSE;
427 }
428
429 static BOOL image_gif_filter(LPVOID buf, DWORD size)
430 {
431     const BYTE const *b = buf;
432
433     return size >= 6
434         && (b[0] == 'G' || b[0] == 'g')
435         && (b[1] == 'I' || b[1] == 'i')
436         && (b[2] == 'F' || b[2] == 'f')
437         &&  b[3] == '8'
438         && (b[4] == '7' || b[4] == '9')
439         && (b[5] == 'A' || b[5] == 'a');
440 }
441
442 static BOOL image_pjpeg_filter(LPVOID buf, DWORD size)
443 {
444     return size > 2 && *(BYTE*)buf == 0xff && *((BYTE*)buf+1) == 0xd8;
445 }
446
447 static BOOL image_xpng_filter(LPVOID buf, DWORD size)
448 {
449     static const BYTE xpng_header[] = {0x89,'P','N','G',0x0d,0x0a,0x1a,0x0a};
450     return size > sizeof(xpng_header) && !memcmp(buf, xpng_header, sizeof(xpng_header));
451 }
452
453 static BOOL image_bmp_filter(LPVOID buf, DWORD size)
454 {
455     return size >= 14
456         && *(BYTE*)buf == 0x42
457         && *((BYTE*)buf+1) == 0x4d
458         && *(DWORD*)((BYTE*)buf+6) == 0;
459 }
460
461 static BOOL text_plain_filter(LPVOID buf, DWORD size)
462 {
463     UCHAR *ptr;
464
465     for(ptr = buf; ptr < (UCHAR*)buf+size-1; ptr++) {
466         if(*ptr < 0x20 && *ptr != '\n' && *ptr != '\r' && *ptr != '\t')
467             return FALSE;
468     }
469
470     return TRUE;
471 }
472
473 static BOOL application_octet_stream_filter(LPVOID buf, DWORD size)
474 {
475     return TRUE;
476 }
477
478 HRESULT WINAPI FindMimeFromData(LPBC pBC, LPCWSTR pwzUrl, LPVOID pBuffer,
479         DWORD cbSize, LPCWSTR pwzMimeProposed, DWORD dwMimeFlags,
480         LPWSTR* ppwzMimeOut, DWORD dwReserved)
481 {
482     TRACE("(%p,%s,%p,%ld,%s,0x%lx,%p,0x%lx)\n", pBC, debugstr_w(pwzUrl), pBuffer, cbSize,
483             debugstr_w(pwzMimeProposed), dwMimeFlags, ppwzMimeOut, dwReserved);
484
485     if(dwMimeFlags)
486         WARN("dwMimeFlags=%08lx\n", dwMimeFlags);
487     if(dwReserved)
488         WARN("dwReserved=%ld\n", dwReserved);
489
490     /* pBC seams to not be used */
491
492     if(!ppwzMimeOut || (!pwzUrl && !pBuffer))
493         return E_INVALIDARG;
494
495     if(pwzMimeProposed && (!pBuffer || (pBuffer && !cbSize))) {
496         DWORD len;
497
498         if(!pwzMimeProposed)
499             return E_FAIL;
500
501         len = strlenW(pwzMimeProposed)+1;
502         *ppwzMimeOut = CoTaskMemAlloc(len*sizeof(WCHAR));
503         memcpy(*ppwzMimeOut, pwzMimeProposed, len*sizeof(WCHAR));
504         return S_OK;
505     }
506
507     if(pBuffer) {
508         DWORD len;
509         LPCWSTR ret = NULL;
510         int i;
511
512         static const WCHAR wszTextHtml[] = {'t','e','x','t','/','h','t','m','l',0};
513         static const WCHAR wszImageGif[] = {'i','m','a','g','e','/','g','i','f',0};
514         static const WCHAR wszImagePjpeg[] = {'i','m','a','g','e','/','p','j','p','e','g',0};
515         static const WCHAR wszImageXPng[] = {'i','m','a','g','e','/','x','-','p','n','g',0};
516         static const WCHAR wszImageBmp[] = {'i','m','a','g','e','/','b','m','p',0};
517         static const WCHAR wszTextPlain[] = {'t','e','x','t','/','p','l','a','i','n','\0'};
518         static const WCHAR wszAppOctetStream[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
519             'o','c','t','e','t','-','s','t','r','e','a','m','\0'};
520
521         static const struct {
522             LPCWSTR mime;
523             BOOL (*filter)(LPVOID,DWORD);
524         } mime_filters[] = {
525             {wszTextHtml,       text_html_filter},
526             {wszImageGif,       image_gif_filter},
527             {wszImagePjpeg,     image_pjpeg_filter},
528             {wszImageXPng,      image_xpng_filter},
529             {wszImageBmp,       image_bmp_filter},
530             {wszTextPlain,      text_plain_filter},
531             {wszAppOctetStream, application_octet_stream_filter}
532         };
533
534         if(!cbSize)
535             return E_FAIL;
536
537         if(pwzMimeProposed && strcmpW(pwzMimeProposed, wszAppOctetStream)) {
538             for(i=0; i < sizeof(mime_filters)/sizeof(*mime_filters); i++) {
539                 if(!strcmpW(pwzMimeProposed, mime_filters[i].mime))
540                     break;
541             }
542
543             if(i == sizeof(mime_filters)/sizeof(*mime_filters)
544                     || mime_filters[i].filter(pBuffer, cbSize)) {
545                 len = strlenW(pwzMimeProposed)+1;
546                 *ppwzMimeOut = CoTaskMemAlloc(len*sizeof(WCHAR));
547                 memcpy(*ppwzMimeOut, pwzMimeProposed, len*sizeof(WCHAR));
548                 return S_OK;
549             }
550         }
551
552         i=0;
553         while(!ret) {
554             if(mime_filters[i].filter(pBuffer, cbSize))
555                 ret = mime_filters[i].mime;
556             i++;
557         }
558
559         if(pwzMimeProposed) {
560             if(i == sizeof(mime_filters)/sizeof(*mime_filters))
561                 ret = pwzMimeProposed;
562
563             /* text/html is a special case */
564            if(!strcmpW(pwzMimeProposed, wszTextHtml) && !strcmpW(ret, wszTextPlain))
565                 ret = wszTextHtml;
566         }
567
568         len = strlenW(ret)+1;
569         *ppwzMimeOut = CoTaskMemAlloc(len*sizeof(WCHAR));
570         memcpy(*ppwzMimeOut, ret, len*sizeof(WCHAR));
571         return S_OK;
572     }
573
574     if(pwzUrl) {
575         HKEY hkey;
576         DWORD res, size;
577         LPCWSTR ptr;
578         WCHAR mime[64];
579
580         static const WCHAR wszContentType[] =
581                 {'C','o','n','t','e','n','t',' ','T','y','p','e','\0'};
582
583         ptr = strrchrW(pwzUrl, '.');
584         if(!ptr)
585             return E_FAIL;
586
587         res = RegOpenKeyW(HKEY_CLASSES_ROOT, ptr, &hkey);
588         if(res != ERROR_SUCCESS)
589             return E_FAIL;
590
591         size = sizeof(mime);
592         res = RegQueryValueExW(hkey, wszContentType, NULL, NULL, (LPBYTE)mime, &size);
593         RegCloseKey(hkey);
594         if(res != ERROR_SUCCESS)
595             return E_FAIL;
596
597         *ppwzMimeOut = CoTaskMemAlloc(size);
598         memcpy(*ppwzMimeOut, mime, size);
599         return S_OK;
600     }
601
602     return E_FAIL;
603 }
604
605 /***********************************************************************
606  * Extract (URLMON.@)
607  */
608 HRESULT WINAPI Extract(void *dest, LPCSTR szCabName)
609 {
610     HRESULT (WINAPI *pExtract)(void *, LPCSTR);
611
612     if (!hCabinet)
613         hCabinet = LoadLibraryA("cabinet.dll");
614
615     if (!hCabinet) return HRESULT_FROM_WIN32(GetLastError());
616     pExtract = (void *)GetProcAddress(hCabinet, "Extract");
617     if (!pExtract) return HRESULT_FROM_WIN32(GetLastError());
618
619     return pExtract(dest, szCabName);
620 }