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