[RAPPS]
[reactos.git] / reactos / base / applications / rapps / loaddlg.c
1 /* PROJECT: ReactOS Applications Manager
2 * LICENSE: GPL - See COPYING in the top level directory
3 * FILE: base/applications/rapps/loaddlg.c
4 * PURPOSE: Displaying a download dialog
5 * COPYRIGHT: Copyright 2001 John R. Sheets (for CodeWeavers)
6 * Copyright 2004 Mike McCormack (for CodeWeavers)
7 * Copyright 2005 Ge van Geldorp (gvg@reactos.org)
8 * Copyright 2009 Dmitry Chapyshev (dmitry@reactos.org)
9 */
10 /*
11 * Based on Wine dlls/shdocvw/shdocvw_main.c
12 *
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Lesser General Public
15 * License as published by the Free Software Foundation; either
16 * version 2.1 of the License, or (at your option) any later version.
17 *
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Lesser General Public License for more details.
22 *
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with this library; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
26 */
27
28 #include "rapps.h"
29 #include <wininet.h>
30 #include <shellapi.h>
31
32 static PAPPLICATION_INFO AppInfo;
33 static HICON hIcon = NULL;
34
35 typedef struct _IBindStatusCallbackImpl
36 {
37 const IBindStatusCallbackVtbl *vtbl;
38 LONG ref;
39 HWND hDialog;
40 BOOL *pbCancelled;
41 } IBindStatusCallbackImpl;
42
43 static
44 HRESULT WINAPI
45 dlQueryInterface(IBindStatusCallback* This, REFIID riid, void** ppvObject)
46 {
47 if (!ppvObject) return E_POINTER;
48
49 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IBindStatusCallback))
50 {
51 IBindStatusCallback_AddRef(This);
52 *ppvObject = This;
53 return S_OK;
54 }
55
56 return E_NOINTERFACE;
57 }
58
59 static
60 ULONG WINAPI
61 dlAddRef(IBindStatusCallback* iface)
62 {
63 IBindStatusCallbackImpl *This = (IBindStatusCallbackImpl*) iface;
64 return InterlockedIncrement(&This->ref);
65 }
66
67 static
68 ULONG WINAPI
69 dlRelease(IBindStatusCallback* iface)
70 {
71 IBindStatusCallbackImpl *This = (IBindStatusCallbackImpl*) iface;
72 DWORD ref = InterlockedDecrement(&This->ref);
73
74 if (!ref)
75 {
76 DestroyWindow(This->hDialog);
77 HeapFree(GetProcessHeap(), 0, This);
78 }
79
80 return ref;
81 }
82
83 static
84 HRESULT WINAPI
85 dlOnStartBinding(IBindStatusCallback* iface, DWORD dwReserved, IBinding* pib)
86 {
87 return S_OK;
88 }
89
90 static
91 HRESULT WINAPI
92 dlGetPriority(IBindStatusCallback* iface, LONG* pnPriority)
93 {
94 return S_OK;
95 }
96
97 static
98 HRESULT WINAPI
99 dlOnLowResource( IBindStatusCallback* iface, DWORD reserved)
100 {
101 return S_OK;
102 }
103
104 static
105 HRESULT WINAPI
106 dlOnProgress(IBindStatusCallback* iface,
107 ULONG ulProgress,
108 ULONG ulProgressMax,
109 ULONG ulStatusCode,
110 LPCWSTR szStatusText)
111 {
112 IBindStatusCallbackImpl *This = (IBindStatusCallbackImpl *) iface;
113 HWND Item;
114 LONG r;
115 WCHAR OldText[100];
116
117 Item = GetDlgItem(This->hDialog, IDC_DOWNLOAD_PROGRESS);
118 if (Item && ulProgressMax)
119 {
120 SendMessageW(Item, PBM_SETPOS, ((ULONGLONG)ulProgress * 100) / ulProgressMax, 0);
121 }
122
123 Item = GetDlgItem(This->hDialog, IDC_DOWNLOAD_STATUS);
124 if (Item && szStatusText)
125 {
126 SendMessageW(Item, WM_GETTEXT, sizeof(OldText) / sizeof(OldText[0]), (LPARAM) OldText);
127 if (sizeof(OldText) / sizeof(OldText[0]) - 1 <= wcslen(OldText) || 0 != wcscmp(OldText, szStatusText))
128 {
129 SendMessageW(Item, WM_SETTEXT, 0, (LPARAM) szStatusText);
130 }
131 }
132
133 SetLastError(0);
134 r = GetWindowLongPtrW(This->hDialog, GWLP_USERDATA);
135 if (0 != r || 0 != GetLastError())
136 {
137 *This->pbCancelled = TRUE;
138 return E_ABORT;
139 }
140
141 return S_OK;
142 }
143
144 static
145 HRESULT WINAPI
146 dlOnStopBinding(IBindStatusCallback* iface, HRESULT hresult, LPCWSTR szError)
147 {
148 return S_OK;
149 }
150
151 static
152 HRESULT WINAPI
153 dlGetBindInfo(IBindStatusCallback* iface, DWORD* grfBINDF, BINDINFO* pbindinfo)
154 {
155 return S_OK;
156 }
157
158 static
159 HRESULT WINAPI
160 dlOnDataAvailable(IBindStatusCallback* iface, DWORD grfBSCF,
161 DWORD dwSize, FORMATETC* pformatetc, STGMEDIUM* pstgmed)
162 {
163 return S_OK;
164 }
165
166 static
167 HRESULT WINAPI
168 dlOnObjectAvailable(IBindStatusCallback* iface, REFIID riid, IUnknown* punk)
169 {
170 return S_OK;
171 }
172
173 static const IBindStatusCallbackVtbl dlVtbl =
174 {
175 dlQueryInterface,
176 dlAddRef,
177 dlRelease,
178 dlOnStartBinding,
179 dlGetPriority,
180 dlOnLowResource,
181 dlOnProgress,
182 dlOnStopBinding,
183 dlGetBindInfo,
184 dlOnDataAvailable,
185 dlOnObjectAvailable
186 };
187
188 static IBindStatusCallback*
189 CreateDl(HWND Dlg, BOOL *pbCancelled)
190 {
191 IBindStatusCallbackImpl *This;
192
193 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IBindStatusCallbackImpl));
194 if (!This)
195 return NULL;
196
197 This->vtbl = &dlVtbl;
198 This->ref = 1;
199 This->hDialog = Dlg;
200 This->pbCancelled = pbCancelled;
201
202 return (IBindStatusCallback*) This;
203 }
204
205 static
206 DWORD WINAPI
207 ThreadFunc(LPVOID Context)
208 {
209 IBindStatusCallback *dl = NULL;
210 WCHAR path[MAX_PATH];
211 LPWSTR p;
212 HWND Dlg = (HWND) Context;
213 DWORD dwContentLen, dwBytesWritten, dwBytesRead, dwStatus;
214 DWORD dwCurrentBytesRead = 0;
215 DWORD dwStatusLen = sizeof(dwStatus);
216 BOOL bCancelled = FALSE;
217 BOOL bTempfile = FALSE;
218 BOOL bCab = FALSE;
219 HINTERNET hOpen = NULL;
220 HINTERNET hFile = NULL;
221 HANDLE hOut = INVALID_HANDLE_VALUE;
222 unsigned char lpBuffer[4096];
223 const LPWSTR lpszAgent = L"RApps/1.0";
224 URL_COMPONENTS urlComponents;
225 size_t urlLength;
226
227 /* built the path for the download */
228 p = wcsrchr(AppInfo->szUrlDownload, L'/');
229
230 if (!p)
231 goto end;
232
233 if (wcscmp(AppInfo->szUrlDownload, APPLICATION_DATABASE_URL) == 0)
234 {
235 bCab = TRUE;
236 if (!GetStorageDirectory(path, sizeof(path) / sizeof(path[0])))
237 goto end;
238 }
239 else
240 {
241 if (FAILED(StringCbCopyW(path, sizeof(path), SettingsInfo.szDownloadDir)))
242 goto end;
243 }
244
245
246 if (GetFileAttributesW(path) == INVALID_FILE_ATTRIBUTES)
247 {
248 if (!CreateDirectoryW(path, NULL))
249 goto end;
250 }
251
252 if (FAILED(StringCbCatW(path, sizeof(path), L"\\")))
253 goto end;
254 if (FAILED(StringCbCatW(path, sizeof(path), p + 1)))
255 goto end;
256
257 /* download it */
258 bTempfile = TRUE;
259 dl = CreateDl(Context, &bCancelled);
260
261 if (dl == NULL)
262 goto end;
263
264 switch(SettingsInfo.Proxy)
265 {
266 case 0: /* preconfig */
267 hOpen = InternetOpenW(lpszAgent, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
268 break;
269 case 1: /* direct (no proxy) */
270 hOpen = InternetOpenW(lpszAgent, INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);
271 break;
272 case 2: /* use proxy */
273 hOpen = InternetOpenW(lpszAgent, INTERNET_OPEN_TYPE_PROXY, SettingsInfo.szProxyServer, SettingsInfo.szNoProxyFor, 0);
274 break;
275 default: /* preconfig */
276 hOpen = InternetOpenW(lpszAgent, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
277 break;
278 }
279
280 if (!hOpen)
281 goto end;
282
283 hFile = InternetOpenUrlW(hOpen, AppInfo->szUrlDownload, NULL, 0, INTERNET_FLAG_PRAGMA_NOCACHE|INTERNET_FLAG_KEEP_CONNECTION, 0);
284 if (!hFile)
285 goto end;
286
287 if (!HttpQueryInfoW(hFile, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, &dwStatus, &dwStatusLen, NULL))
288 goto end;
289
290 if(dwStatus != HTTP_STATUS_OK)
291 {
292 WCHAR szMsgText[MAX_STR_LEN];
293
294 if (!LoadStringW(hInst, IDS_UNABLE_TO_DOWNLOAD, szMsgText, sizeof(szMsgText) / sizeof(WCHAR)))
295 goto end;
296
297 MessageBoxW(hMainWnd, szMsgText, NULL, MB_OK | MB_ICONERROR);
298 goto end;
299 }
300
301 dwStatusLen = sizeof(dwStatus);
302
303 memset(&urlComponents, 0, sizeof(urlComponents));
304 urlComponents.dwStructSize = sizeof(urlComponents);
305
306 if(FAILED(StringCbLengthW(AppInfo->szUrlDownload, sizeof(AppInfo->szUrlDownload), &urlLength)))
307 goto end;
308
309 urlComponents.dwSchemeLength = urlLength*sizeof(WCHAR);
310 urlComponents.lpszScheme = malloc(urlComponents.dwSchemeLength);
311
312 if(!InternetCrackUrlW(AppInfo->szUrlDownload, urlLength+1, ICU_DECODE | ICU_ESCAPE, &urlComponents))
313 goto end;
314
315 if(urlComponents.nScheme == INTERNET_SCHEME_HTTP || urlComponents.nScheme == INTERNET_SCHEME_HTTPS)
316 HttpQueryInfo(hFile, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER, &dwContentLen, &dwStatus, 0);
317
318 if(urlComponents.nScheme == INTERNET_SCHEME_FTP)
319 dwContentLen = FtpGetFileSize(hFile, &dwStatus);
320
321 free(urlComponents.lpszScheme);
322
323 hOut = CreateFileW(path, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, NULL);
324
325 if (hOut == INVALID_HANDLE_VALUE)
326 goto end;
327
328 do
329 {
330 if (!InternetReadFile(hFile, lpBuffer, _countof(lpBuffer), &dwBytesRead)) goto end;
331 if (!WriteFile(hOut, &lpBuffer[0], dwBytesRead, &dwBytesWritten, NULL)) goto end;
332 dwCurrentBytesRead += dwBytesRead;
333 IBindStatusCallback_OnProgress(dl, dwCurrentBytesRead, dwContentLen, 0, AppInfo->szUrlDownload);
334 }
335 while (dwBytesRead);
336
337 CloseHandle(hOut);
338 hOut = INVALID_HANDLE_VALUE;
339
340 if (bCancelled)
341 goto end;
342
343 ShowWindow(Dlg, SW_HIDE);
344
345 /* run it */
346 if (!bCab)
347 ShellExecuteW( NULL, L"open", path, NULL, NULL, SW_SHOWNORMAL );
348
349 end:
350 if (hOut != INVALID_HANDLE_VALUE)
351 CloseHandle(hOut);
352
353 InternetCloseHandle(hFile);
354 InternetCloseHandle(hOpen);
355
356 if (dl)
357 IBindStatusCallback_Release(dl);
358
359 if (bTempfile)
360 {
361 if (bCancelled || (SettingsInfo.bDelInstaller && !bCab))
362 DeleteFileW(path);
363 }
364
365 EndDialog(Dlg, 0);
366
367 return 0;
368 }
369
370 static
371 INT_PTR CALLBACK
372 DownloadDlgProc(HWND Dlg, UINT Msg, WPARAM wParam, LPARAM lParam)
373 {
374 HANDLE Thread;
375 DWORD ThreadId;
376 HWND Item;
377
378 switch (Msg)
379 {
380 case WM_INITDIALOG:
381
382 hIcon = LoadIconW(hInst, MAKEINTRESOURCEW(IDI_MAIN));
383 if (hIcon)
384 {
385 SendMessageW(Dlg, WM_SETICON, ICON_BIG, (LPARAM) hIcon);
386 SendMessageW(Dlg, WM_SETICON, ICON_SMALL, (LPARAM) hIcon);
387 }
388
389 SetWindowLongPtrW(Dlg, GWLP_USERDATA, 0);
390 Item = GetDlgItem(Dlg, IDC_DOWNLOAD_PROGRESS);
391 if (Item)
392 {
393 SendMessageW(Item, PBM_SETRANGE, 0, MAKELPARAM(0, 100));
394 SendMessageW(Item, PBM_SETPOS, 0, 0);
395 }
396
397 Thread = CreateThread(NULL, 0, ThreadFunc, Dlg, 0, &ThreadId);
398 if (!Thread) return FALSE;
399 CloseHandle(Thread);
400 return TRUE;
401
402 case WM_COMMAND:
403 if (wParam == IDCANCEL)
404 {
405 SetWindowLongPtrW(Dlg, GWLP_USERDATA, 1);
406 PostMessageW(Dlg, WM_CLOSE, 0, 0);
407 }
408 return FALSE;
409
410 case WM_CLOSE:
411 if (hIcon) DestroyIcon(hIcon);
412 EndDialog(Dlg, 0);
413 return TRUE;
414
415 default:
416 return FALSE;
417 }
418 }
419
420 BOOL
421 DownloadApplication(INT Index)
422 {
423 if (!IS_AVAILABLE_ENUM(SelectedEnumType))
424 return FALSE;
425
426 AppInfo = (PAPPLICATION_INFO) ListViewGetlParam(Index);
427 if (!AppInfo) return FALSE;
428
429 WriteLogMessage(EVENTLOG_SUCCESS, MSG_SUCCESS_INSTALL, AppInfo->szName);
430
431 DialogBoxW(hInst,
432 MAKEINTRESOURCEW(IDD_DOWNLOAD_DIALOG),
433 hMainWnd,
434 DownloadDlgProc);
435
436 return TRUE;
437 }
438
439 VOID
440 DownloadApplicationsDB(LPWSTR lpUrl)
441 {
442 APPLICATION_INFO IntInfo;
443
444 ZeroMemory(&IntInfo, sizeof(APPLICATION_INFO));
445 if (FAILED(StringCbCopyW(IntInfo.szUrlDownload,
446 sizeof(IntInfo.szUrlDownload),
447 lpUrl)))
448 {
449 return;
450 }
451
452 AppInfo = &IntInfo;
453
454 DialogBoxW(hInst,
455 MAKEINTRESOURCEW(IDD_DOWNLOAD_DIALOG),
456 hMainWnd,
457 DownloadDlgProc);
458 }
459