cards: Fix description of cdtTerm.
[wine] / dlls / appwiz.cpl / addons.c
1 /*
2  * Copyright 2006-2010 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 "config.h"
20
21 #include <stdarg.h>
22 #include <fcntl.h>
23 #include <stdio.h>
24 #ifdef HAVE_UNISTD_H
25 # include <unistd.h>
26 #endif
27
28 #define COBJMACROS
29 #define NONAMELESSUNION
30 #define NONAMELESSSTRUCT
31
32 #include "windef.h"
33 #include "winbase.h"
34 #include "winuser.h"
35 #include "cpl.h"
36 #include "winreg.h"
37 #include "ole2.h"
38 #include "commctrl.h"
39 #include "advpub.h"
40 #include "wininet.h"
41 #include "shellapi.h"
42 #include "urlmon.h"
43
44 #include "appwiz.h"
45 #include "res.h"
46
47 #include "wine/debug.h"
48 #include "wine/unicode.h"
49 #include "wine/library.h"
50
51 WINE_DEFAULT_DEBUG_CHANNEL(appwizcpl);
52
53 #define GECKO_VERSION "1.1.0"
54
55 #ifdef __i386__
56 #define ARCH_STRING "x86"
57 #define GECKO_SHA "1b6c637207b6f032ae8a52841db9659433482714"
58 #elif defined(__x86_64__)
59 #define ARCH_STRING "x86_64"
60 #define GECKO_SHA "55b4b60cd2a48631d6236fb411c3a94d806d9906"
61 #else
62 #define ARCH_STRING ""
63 #define GECKO_SHA "???"
64 #endif
65
66 #define GECKO_FILE_NAME "wine_gecko-" GECKO_VERSION "-" ARCH_STRING ".cab"
67
68 static const WCHAR mshtml_keyW[] =
69     {'S','o','f','t','w','a','r','e',
70      '\\','W','i','n','e',
71      '\\','M','S','H','T','M','L',0};
72
73 static HWND install_dialog = NULL;
74 static LPWSTR url = NULL;
75
76 static inline char *heap_strdupWtoA(LPCWSTR str)
77 {
78     char *ret = NULL;
79
80     if(str) {
81         DWORD size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
82         ret = heap_alloc(size);
83         WideCharToMultiByte(CP_ACP, 0, str, -1, ret, size, NULL, NULL);
84     }
85
86     return ret;
87 }
88
89 /* SHA definitions are copied from advapi32. They aren't available in headers. */
90
91 typedef struct {
92    ULONG Unknown[6];
93    ULONG State[5];
94    ULONG Count[2];
95    UCHAR Buffer[64];
96 } SHA_CTX, *PSHA_CTX;
97
98 void WINAPI A_SHAInit(PSHA_CTX);
99 void WINAPI A_SHAUpdate(PSHA_CTX,const unsigned char*,UINT);
100 void WINAPI A_SHAFinal(PSHA_CTX,PULONG);
101
102 static BOOL sha_check(const WCHAR *file_name)
103 {
104     const unsigned char *file_map;
105     HANDLE file, map;
106     ULONG sha[5];
107     char buf[2*sizeof(sha)+1];
108     SHA_CTX ctx;
109     DWORD size, i;
110
111     file = CreateFileW(file_name, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL);
112     if(file == INVALID_HANDLE_VALUE)
113         return FALSE;
114
115     size = GetFileSize(file, NULL);
116
117     map = CreateFileMappingW(file, NULL, PAGE_READONLY, 0, 0, NULL);
118     CloseHandle(file);
119     if(!map)
120         return FALSE;
121
122     file_map = MapViewOfFile(map, FILE_MAP_READ, 0, 0, 0);
123     CloseHandle(map);
124     if(!file_map)
125         return FALSE;
126
127     A_SHAInit(&ctx);
128     A_SHAUpdate(&ctx, file_map, size);
129     A_SHAFinal(&ctx, sha);
130
131     UnmapViewOfFile(file_map);
132
133     for(i=0; i < sizeof(sha); i++)
134         sprintf(buf + i*2, "%02x", *((unsigned char*)sha+i));
135
136     if(strcmp(buf, GECKO_SHA)) {
137         WCHAR message[256];
138
139         WARN("Got %s, expected %s\n", buf, GECKO_SHA);
140
141         if(LoadStringW(hInst, IDS_INVALID_SHA, message, sizeof(message)/sizeof(WCHAR)))
142             MessageBoxW(NULL, message, NULL, MB_ICONERROR);
143
144         return FALSE;
145     }
146
147     return TRUE;
148 }
149
150 static void set_status(DWORD id)
151 {
152     HWND status = GetDlgItem(install_dialog, ID_DWL_STATUS);
153     WCHAR buf[64];
154
155     LoadStringW(hInst, id, buf, sizeof(buf)/sizeof(WCHAR));
156     SendMessageW(status, WM_SETTEXT, 0, (LPARAM)buf);
157 }
158
159 static void set_registry(const WCHAR *install_dir)
160 {
161     WCHAR mshtml_key[100];
162     LPWSTR gecko_path;
163     HKEY hkey;
164     DWORD res, len;
165
166     static const WCHAR wszGeckoPath[] = {'G','e','c','k','o','P','a','t','h',0};
167     static const WCHAR wszWineGecko[] = {'w','i','n','e','_','g','e','c','k','o',0};
168
169     memcpy(mshtml_key, mshtml_keyW, sizeof(mshtml_keyW));
170     mshtml_key[sizeof(mshtml_keyW)/sizeof(WCHAR)-1] = '\\';
171     MultiByteToWideChar(CP_ACP, 0, GECKO_VERSION, sizeof(GECKO_VERSION),
172             mshtml_key+sizeof(mshtml_keyW)/sizeof(WCHAR),
173             (sizeof(mshtml_key)-sizeof(mshtml_keyW))/sizeof(WCHAR));
174
175     /* @@ Wine registry key: HKCU\Software\Wine\MSHTML\<version> */
176     res = RegCreateKeyW(HKEY_CURRENT_USER, mshtml_key, &hkey);
177     if(res != ERROR_SUCCESS) {
178         ERR("Faild to create MSHTML key: %d\n", res);
179         return;
180     }
181
182     len = strlenW(install_dir);
183     gecko_path = heap_alloc((len+1)*sizeof(WCHAR)+sizeof(wszWineGecko));
184     memcpy(gecko_path, install_dir, len*sizeof(WCHAR));
185
186     if (len && gecko_path[len-1] != '\\')
187         gecko_path[len++] = '\\';
188
189     memcpy(gecko_path+len, wszWineGecko, sizeof(wszWineGecko));
190
191     res = RegSetValueExW(hkey, wszGeckoPath, 0, REG_SZ, (LPVOID)gecko_path,
192                        len*sizeof(WCHAR)+sizeof(wszWineGecko));
193     heap_free(gecko_path);
194     RegCloseKey(hkey);
195     if(res != ERROR_SUCCESS)
196         ERR("Failed to set GeckoPath value: %08x\n", res);
197 }
198
199 static BOOL install_cab(LPCWSTR file_name)
200 {
201     char *install_dir_a, *file_name_a;
202     WCHAR install_dir[MAX_PATH];
203     DWORD res, len;
204     HRESULT hres;
205
206     static const WCHAR gecko_subdirW[] = {'\\','g','e','c','k','o','\\',0};
207
208     TRACE("(%s)\n", debugstr_w(file_name));
209
210     GetSystemDirectoryW(install_dir, sizeof(install_dir)/sizeof(WCHAR));
211     strcatW(install_dir, gecko_subdirW);
212     res = CreateDirectoryW(install_dir, NULL);
213     if(!res && GetLastError() != ERROR_ALREADY_EXISTS) {
214         ERR("Could not create directory: %08u\n", GetLastError());
215         return FALSE;
216     }
217
218     len = strlenW(install_dir);
219     MultiByteToWideChar(CP_ACP, 0, GECKO_VERSION, -1, install_dir+len, sizeof(install_dir)/sizeof(WCHAR)-len);
220     res = CreateDirectoryW(install_dir, NULL);
221     if(!res && GetLastError() != ERROR_ALREADY_EXISTS) {
222         ERR("Could not create directory: %08u\n", GetLastError());
223         return FALSE;
224     }
225
226
227     /* FIXME: Use ExtractFilesW once it's implemented */
228     file_name_a = heap_strdupWtoA(file_name);
229     install_dir_a = heap_strdupWtoA(install_dir);
230     if(file_name_a && install_dir_a)
231         hres = ExtractFilesA(file_name_a, install_dir_a, 0, NULL, NULL, 0);
232     else
233         hres = E_OUTOFMEMORY;
234     heap_free(file_name_a);
235     heap_free(install_dir_a);
236     if(FAILED(hres)) {
237         ERR("Could not extract package: %08x\n", hres);
238         return FALSE;
239     }
240
241     set_registry(install_dir);
242     return TRUE;
243 }
244
245 static BOOL install_from_unix_file(const char *file_name)
246 {
247     LPWSTR dos_file_name;
248     int fd;
249     BOOL ret;
250
251     static WCHAR * (CDECL *wine_get_dos_file_name)(const char*);
252     static const WCHAR kernel32W[] = {'k','e','r','n','e','l','3','2','.','d','l','l',0};
253
254     fd = open(file_name, O_RDONLY);
255     if(fd == -1) {
256         TRACE("%s not found\n", debugstr_a(file_name));
257         return FALSE;
258     }
259
260     close(fd);
261
262     if(!wine_get_dos_file_name)
263         wine_get_dos_file_name = (void*)GetProcAddress(GetModuleHandleW(kernel32W), "wine_get_dos_file_name");
264
265     if(wine_get_dos_file_name) { /* Wine UNIX mode */
266         dos_file_name = wine_get_dos_file_name(file_name);
267         if(!dos_file_name) {
268             ERR("Could not get dos file name of %s\n", debugstr_a(file_name));
269             return FALSE;
270         }
271     } else { /* Windows mode */
272         UINT res;
273         WARN("Could not get wine_get_dos_file_name function, calling install_cab directly.\n");
274         res = MultiByteToWideChar( CP_ACP, 0, file_name, -1, 0, 0);
275         dos_file_name = heap_alloc (res*sizeof(WCHAR));
276         MultiByteToWideChar( CP_ACP, 0, file_name, -1, dos_file_name, res);
277     }
278
279     ret = install_cab(dos_file_name);
280
281     heap_free(dos_file_name);
282     return ret;
283 }
284
285 static BOOL install_from_registered_dir(void)
286 {
287     char *file_name;
288     HKEY hkey;
289     DWORD res, type, size = MAX_PATH;
290     BOOL ret;
291
292     /* @@ Wine registry key: HKCU\Software\Wine\MSHTML */
293     res = RegOpenKeyW(HKEY_CURRENT_USER, mshtml_keyW, &hkey);
294     if(res != ERROR_SUCCESS)
295         return FALSE;
296
297     file_name = heap_alloc(size+sizeof(GECKO_FILE_NAME));
298     res = RegGetValueA(hkey, NULL, "GeckoCabDir", RRF_RT_ANY, &type, (PBYTE)file_name, &size);
299     if(res == ERROR_MORE_DATA) {
300         file_name = heap_realloc(file_name, size+sizeof(GECKO_FILE_NAME));
301         res = RegGetValueA(hkey, NULL, "GeckoCabDir", RRF_RT_ANY, &type, (PBYTE)file_name, &size);
302     }
303     RegCloseKey(hkey);
304     if(res != ERROR_SUCCESS || (type != REG_SZ && type != REG_EXPAND_SZ)) {
305         heap_free(file_name);
306         return FALSE;
307     }
308
309     strcat(file_name, GECKO_FILE_NAME);
310
311     TRACE("Trying %s\n", debugstr_a(file_name));
312
313     ret = install_from_unix_file(file_name);
314
315     heap_free(file_name);
316     return ret;
317 }
318
319 static BOOL install_from_default_dir(void)
320 {
321     const char *data_dir, *subdir;
322     char *file_name;
323     int len, len2;
324     BOOL ret;
325
326     if((data_dir = wine_get_data_dir()))
327         subdir = "/gecko/";
328     else if((data_dir = wine_get_build_dir()))
329         subdir = "/../gecko/";
330     else
331         return FALSE;
332
333     len = strlen(data_dir);
334     len2 = strlen(subdir);
335
336     file_name = heap_alloc(len+len2+sizeof(GECKO_FILE_NAME));
337     memcpy(file_name, data_dir, len);
338     memcpy(file_name+len, subdir, len2);
339     memcpy(file_name+len+len2, GECKO_FILE_NAME, sizeof(GECKO_FILE_NAME));
340
341     ret = install_from_unix_file(file_name);
342
343     heap_free(file_name);
344
345     if (!ret)
346         ret = install_from_unix_file(INSTALL_DATADIR "/wine/gecko/" GECKO_FILE_NAME);
347     if (!ret && strcmp(INSTALL_DATADIR, "/usr/share"))
348         ret = install_from_unix_file("/usr/share/wine/gecko/" GECKO_FILE_NAME);
349     return ret;
350 }
351
352 static HRESULT WINAPI InstallCallback_QueryInterface(IBindStatusCallback *iface,
353         REFIID riid, void **ppv)
354 {
355     if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IBindStatusCallback, riid)) {
356         *ppv = iface;
357         return S_OK;
358     }
359
360     return E_INVALIDARG;
361 }
362
363 static ULONG WINAPI InstallCallback_AddRef(IBindStatusCallback *iface)
364 {
365     return 2;
366 }
367
368 static ULONG WINAPI InstallCallback_Release(IBindStatusCallback *iface)
369 {
370     return 1;
371 }
372
373 static HRESULT WINAPI InstallCallback_OnStartBinding(IBindStatusCallback *iface,
374         DWORD dwReserved, IBinding *pib)
375 {
376     set_status(IDS_DOWNLOADING);
377     return S_OK;
378 }
379
380 static HRESULT WINAPI InstallCallback_GetPriority(IBindStatusCallback *iface,
381         LONG *pnPriority)
382 {
383     return E_NOTIMPL;
384 }
385
386 static HRESULT WINAPI InstallCallback_OnLowResource(IBindStatusCallback *iface,
387        DWORD dwReserved)
388 {
389     return E_NOTIMPL;
390 }
391
392 static HRESULT WINAPI InstallCallback_OnProgress(IBindStatusCallback *iface, ULONG ulProgress,
393         ULONG ulProgressMax, ULONG ulStatusCode, LPCWSTR szStatusText)
394 {
395     HWND progress = GetDlgItem(install_dialog, ID_DWL_PROGRESS);
396
397     if(ulProgressMax)
398         SendMessageW(progress, PBM_SETRANGE32, 0, ulProgressMax);
399     if(ulProgress)
400         SendMessageW(progress, PBM_SETPOS, ulProgress, 0);
401
402     return S_OK;
403 }
404
405 static HRESULT WINAPI InstallCallback_OnStopBinding(IBindStatusCallback *iface,
406         HRESULT hresult, LPCWSTR szError)
407 {
408     if(FAILED(hresult)) {
409         ERR("Binding failed %08x\n", hresult);
410         return S_OK;
411     }
412
413     set_status(IDS_INSTALLING);
414     return S_OK;
415 }
416
417 static HRESULT WINAPI InstallCallback_GetBindInfo(IBindStatusCallback *iface,
418         DWORD* grfBINDF, BINDINFO* pbindinfo)
419 {
420     /* FIXME */
421     *grfBINDF = 0;
422     return S_OK;
423 }
424
425 static HRESULT WINAPI InstallCallback_OnDataAvailable(IBindStatusCallback *iface, DWORD grfBSCF,
426         DWORD dwSize, FORMATETC* pformatetc, STGMEDIUM* pstgmed)
427 {
428     ERR("\n");
429     return E_NOTIMPL;
430 }
431
432 static HRESULT WINAPI InstallCallback_OnObjectAvailable(IBindStatusCallback *iface,
433         REFIID riid, IUnknown* punk)
434 {
435     ERR("\n");
436     return E_NOTIMPL;
437 }
438
439 static const IBindStatusCallbackVtbl InstallCallbackVtbl = {
440     InstallCallback_QueryInterface,
441     InstallCallback_AddRef,
442     InstallCallback_Release,
443     InstallCallback_OnStartBinding,
444     InstallCallback_GetPriority,
445     InstallCallback_OnLowResource,
446     InstallCallback_OnProgress,
447     InstallCallback_OnStopBinding,
448     InstallCallback_GetBindInfo,
449     InstallCallback_OnDataAvailable,
450     InstallCallback_OnObjectAvailable
451 };
452
453 static IBindStatusCallback InstallCallback = { &InstallCallbackVtbl };
454
455 static LPWSTR get_url(void)
456 {
457     HKEY hkey;
458     DWORD res, type;
459     DWORD size = INTERNET_MAX_URL_LENGTH*sizeof(WCHAR);
460     DWORD returned_size;
461     LPWSTR url;
462
463     static const WCHAR wszGeckoUrl[] = {'G','e','c','k','o','U','r','l',0};
464     static const WCHAR httpW[] = {'h','t','t','p'};
465     static const WCHAR arch_formatW[] = {'?','a','r','c','h','='};
466     static const WCHAR v_formatW[] = {'&','v','='};
467
468     /* @@ Wine registry key: HKCU\Software\Wine\MSHTML */
469     res = RegOpenKeyW(HKEY_CURRENT_USER, mshtml_keyW, &hkey);
470     if(res != ERROR_SUCCESS)
471         return NULL;
472
473     url = heap_alloc(size);
474     returned_size = size;
475
476     res = RegQueryValueExW(hkey, wszGeckoUrl, NULL, &type, (LPBYTE)url, &returned_size);
477     RegCloseKey(hkey);
478     if(res != ERROR_SUCCESS || type != REG_SZ) {
479         heap_free(url);
480         return NULL;
481     }
482
483     if(returned_size > sizeof(httpW) && !memcmp(url, httpW, sizeof(httpW))) {
484         DWORD len;
485
486         len = strlenW(url);
487         memcpy(url+len, arch_formatW, sizeof(arch_formatW));
488         len += sizeof(arch_formatW)/sizeof(WCHAR);
489         len += MultiByteToWideChar(CP_ACP, 0, ARCH_STRING, sizeof(ARCH_STRING), url+len, size/sizeof(WCHAR)-len)-1;
490         memcpy(url+len, v_formatW, sizeof(v_formatW));
491         len += sizeof(v_formatW)/sizeof(WCHAR);
492         MultiByteToWideChar(CP_ACP, 0, GECKO_VERSION, -1, url+len, size/sizeof(WCHAR)-len);
493     }
494
495     TRACE("Got URL %s\n", debugstr_w(url));
496     return url;
497 }
498
499 static DWORD WINAPI download_proc(PVOID arg)
500 {
501     WCHAR tmp_dir[MAX_PATH], tmp_file[MAX_PATH];
502     HRESULT hres;
503
504     GetTempPathW(sizeof(tmp_dir)/sizeof(WCHAR), tmp_dir);
505     GetTempFileNameW(tmp_dir, NULL, 0, tmp_file);
506
507     TRACE("using temp file %s\n", debugstr_w(tmp_file));
508
509     hres = URLDownloadToFileW(NULL, url, tmp_file, 0, &InstallCallback);
510     if(FAILED(hres)) {
511         ERR("URLDownloadToFile failed: %08x\n", hres);
512         return 0;
513     }
514
515     if(sha_check(tmp_file))
516         install_cab(tmp_file);
517     DeleteFileW(tmp_file);
518     EndDialog(install_dialog, 0);
519     return 0;
520 }
521
522 static INT_PTR CALLBACK installer_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
523 {
524     switch(msg) {
525     case WM_INITDIALOG:
526         ShowWindow(GetDlgItem(hwnd, ID_DWL_PROGRESS), SW_HIDE);
527         install_dialog = hwnd;
528         return TRUE;
529
530     case WM_COMMAND:
531         switch(wParam) {
532         case IDCANCEL:
533             EndDialog(hwnd, 0);
534             return FALSE;
535
536         case ID_DWL_INSTALL:
537             ShowWindow(GetDlgItem(hwnd, ID_DWL_PROGRESS), SW_SHOW);
538             EnableWindow(GetDlgItem(hwnd, ID_DWL_INSTALL), 0);
539             EnableWindow(GetDlgItem(hwnd, IDCANCEL), 0); /* FIXME */
540             CreateThread(NULL, 0, download_proc, NULL, 0, NULL);
541             return FALSE;
542         }
543     }
544
545     return FALSE;
546 }
547
548 BOOL install_wine_gecko(void)
549 {
550     if(!*ARCH_STRING)
551         return FALSE;
552
553     /*
554      * Try to find Gecko .cab file in following order:
555      * - directory stored in GeckoCabDir value of HKCU/Wine/Software/MSHTML key
556      * - $datadir/gecko/
557      * - $INSTALL_DATADIR/wine/gecko/
558      * - /usr/share/wine/gecko/
559      * - download from URL stored in GeckoUrl value of HKCU/Wine/Software/MSHTML key
560      */
561     if(!install_from_registered_dir()
562        && !install_from_default_dir()
563        && (url = get_url()))
564         DialogBoxW(hInst, MAKEINTRESOURCEW(ID_DWL_DIALOG), 0, installer_proc);
565
566     heap_free(url);
567     url = NULL;
568     return TRUE;
569 }