00001
00032
00033
00034
00035
00036 #include "linden_common.h"
00037
00038 #include <windows.h>
00039 #include <wininet.h>
00040
00041 #define BUFSIZE 8192
00042
00043 int gTotalBytesRead = 0;
00044 HWND gWindow = NULL;
00045 WCHAR gProgress[256];
00046 char* gUpdateURL;
00047 char* gProgramName;
00048 char* gProductName;
00049 bool gIsSilent;
00050
00051 #if _DEBUG
00052 FILE* logfile = 0;
00053 #endif
00054
00055 char* wchars_to_utf8chars(WCHAR* in_chars)
00056 {
00057 int tlen = 0;
00058 WCHAR* twc = in_chars;
00059 while (*twc++ != 0)
00060 {
00061 tlen++;
00062 }
00063 char* outchars = new char[tlen];
00064 char* res = outchars;
00065 for (int i=0; i<tlen; i++)
00066 {
00067 int cur_char = (int)(*in_chars++);
00068 if (cur_char < 0x80)
00069 {
00070 *outchars++ = (char)cur_char;
00071 }
00072 else
00073 {
00074 *outchars++ = '?';
00075 }
00076 }
00077 *outchars = 0;
00078 return res;
00079 }
00080
00081 int WINAPI get_url_into_file(WCHAR *uri, char *path, int *cancelled)
00082 {
00083 int success = FALSE;
00084 *cancelled = FALSE;
00085
00086 HINTERNET hinet, hdownload;
00087 char data[BUFSIZE];
00088 unsigned long bytes_read;
00089
00090 #if _DEBUG
00091 fprintf(logfile,"Opening '%s'\n",path);
00092 fflush(logfile);
00093 #endif
00094
00095 FILE* fp = fopen(path, "wb");
00096
00097 if (!fp)
00098 {
00099 #if _DEBUG
00100 fprintf(logfile,"Failed to open '%s'\n",path);
00101 fflush(logfile);
00102 #endif
00103 return success;
00104 }
00105
00106 #if _DEBUG
00107 fprintf(logfile,"Calling InternetOpen\n");
00108 fflush(logfile);
00109 #endif
00110
00111 hinet = InternetOpen(L"DaleGlassUpdater", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
00112 if (hinet == NULL)
00113 {
00114 return success;
00115 }
00116
00117 #if _DEBUG
00118 fprintf(logfile,"Calling InternetOpenUrl: %s\n",wchars_to_utf8chars(uri));
00119 fflush(logfile);
00120 #endif
00121 hdownload = InternetOpenUrl(hinet, uri, NULL, 0, INTERNET_FLAG_NEED_FILE, NULL);
00122 if (hdownload == NULL)
00123 {
00124 #if _DEBUG
00125 DWORD err = GetLastError();
00126 fprintf(logfile,"InternetOpenUrl Failed: %d\n",err);
00127 fflush(logfile);
00128 #endif
00129 return success;
00130 }
00131
00132 DWORD total_bytes = 0;
00133 success = InternetQueryDataAvailable(hdownload, &total_bytes, 0, 0);
00134 if (success == FALSE)
00135 {
00136 #if _DEBUG
00137 DWORD err = GetLastError();
00138 fprintf(logfile,"InternetQueryDataAvailable Failed: %d bytes Err:%d\n",total_bytes,err);
00139 fflush(logfile);
00140 #endif
00141 return success;
00142 }
00143
00144 success = FALSE;
00145 while(!success && !(*cancelled))
00146 {
00147 MSG msg;
00148
00149 #if _DEBUG
00150 fprintf(logfile,"Calling InternetReadFile\n");
00151 fflush(logfile);
00152 #endif
00153 if (!InternetReadFile(hdownload, data, BUFSIZE, &bytes_read))
00154 {
00155 #if _DEBUG
00156 fprintf(logfile,"InternetReadFile Failed.\n");
00157 fflush(logfile);
00158 #endif
00159
00160 return FALSE;
00161 }
00162
00163 #if _DEBUG
00164 if (!bytes_read)
00165 {
00166 fprintf(logfile,"InternetReadFile Read 0 bytes.\n");
00167 fflush(logfile);
00168 }
00169 #endif
00170
00171 #if _DEBUG
00172 fprintf(logfile,"Reading Data, bytes_read = %d\n",bytes_read);
00173 fflush(logfile);
00174 #endif
00175
00176 if (bytes_read == 0)
00177 {
00178
00179
00180 wsprintf(gProgress, L"Download complete.");
00181 success = TRUE;
00182 }
00183 else
00184 {
00185
00186 fwrite(data, sizeof(char), bytes_read, fp);
00187
00188 gTotalBytesRead += int(bytes_read);
00189
00190 wsprintf(gProgress, L"Downloaded: %dK", gTotalBytesRead / 1024);
00191 }
00192
00193 #if _DEBUG
00194 fprintf(logfile,"Calling InvalidateRect\n");
00195 fflush(logfile);
00196 #endif
00197
00198
00199 InvalidateRect(gWindow, NULL, TRUE);
00200
00201
00202 #if _DEBUG
00203 fprintf(logfile,"Calling UpdateWindow\n");
00204 fflush(logfile);
00205 #endif
00206 UpdateWindow(gWindow);
00207
00208 #if _DEBUG
00209 fprintf(logfile,"Calling PeekMessage\n");
00210 fflush(logfile);
00211 #endif
00212 if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
00213 {
00214 TranslateMessage(&msg);
00215 DispatchMessage(&msg);
00216
00217 if (msg.message == WM_QUIT)
00218 {
00219
00220 *cancelled = TRUE;
00221 }
00222 }
00223 }
00224
00225 #if _DEBUG
00226 fprintf(logfile,"Calling InternetCloseHandle\n");
00227 fclose(logfile);
00228 #endif
00229
00230 fclose(fp);
00231 InternetCloseHandle(hdownload);
00232 InternetCloseHandle(hinet);
00233
00234 return success;
00235 }
00236
00237 LRESULT CALLBACK WinProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
00238 {
00239 HDC hdc;
00240 PAINTSTRUCT ps;
00241
00242 switch(message)
00243 {
00244 case WM_PAINT:
00245 {
00246 hdc = BeginPaint(hwnd, &ps);
00247
00248 RECT rect;
00249 GetClientRect(hwnd, &rect);
00250 DrawText(hdc, gProgress, -1, &rect,
00251 DT_SINGLELINE | DT_CENTER | DT_VCENTER);
00252
00253 EndPaint(hwnd, &ps);
00254 return 0;
00255 }
00256 case WM_CLOSE:
00257 case WM_DESTROY:
00258
00259
00260 PostQuitMessage(0);
00261 return 0;
00262 }
00263 return DefWindowProc(hwnd, message, wparam, lparam);
00264 }
00265
00266 #define win_class_name L"FullScreen"
00267
00268 int parse_args(int argc, char **argv)
00269 {
00270 int j;
00271
00272 for (j = 1; j < argc; j++)
00273 {
00274 if ((!strcmp(argv[j], "-name")) && (++j < argc))
00275 {
00276 gProductName = argv[j];
00277 }
00278 else if ((!strcmp(argv[j], "-url")) && (++j < argc))
00279 {
00280 gUpdateURL = argv[j];
00281 }
00282 else if ((!strcmp(argv[j], "-program")) && (++j < argc))
00283 {
00284 gProgramName = argv[j];
00285 }
00286 else if (!strcmp(argv[j], "-silent"))
00287 {
00288 gIsSilent = true;
00289 }
00290 }
00291
00292
00293 if (!gProductName && !gProgramName && !gIsSilent && !gUpdateURL)
00294 {
00295 return 1;
00296 }
00297 return 0;
00298 }
00299
00300 int WINAPI
00301 WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
00302 {
00303
00304 LPSTR cmd_line_including_exe_name = GetCommandLineA();
00305
00306 const int MAX_ARGS = 100;
00307 int argc = 0;
00308 char* argv[MAX_ARGS];
00309
00310 #if _DEBUG
00311 logfile = _wfopen(TEXT("updater.log"),TEXT("wt"));
00312 fprintf(logfile,"Parsing command arguments\n");
00313 fflush(logfile);
00314 #endif
00315
00316 char *token = NULL;
00317 if( cmd_line_including_exe_name[0] == '\"' )
00318 {
00319
00320 token = strtok( cmd_line_including_exe_name, "\"" );
00321 argv[argc++] = token;
00322 token = strtok( NULL, " \t," );
00323 }
00324 else
00325 {
00326
00327 token = strtok( cmd_line_including_exe_name, " \t," );
00328 }
00329
00330 while( (token != NULL) && (argc < MAX_ARGS) )
00331 {
00332 argv[argc++] = token;
00333
00334 if (*(token + strlen(token) + 1) == '\"')
00335 {
00336 token = strtok( NULL, "\"");
00337 }
00338 else
00339 {
00340 token = strtok( NULL, " \t," );
00341 }
00342 }
00343
00344 gUpdateURL = NULL;
00345 gProgramName = NULL;
00346 gProductName = NULL;
00347 gIsSilent = false;
00348
00350
00351
00352
00353
00354 #if _DEBUG
00355 fprintf(logfile,"Processing command arguments\n");
00356 fflush(logfile);
00357 #endif
00358
00359
00360
00361
00362 int parse_args_result = parse_args(argc, argv);
00363 WCHAR window_title[2048];
00364 if (gProductName)
00365 {
00366 mbstowcs(window_title, gProductName, 2048);
00367 wcscat(window_title, L" Updater");
00368 }
00369 else
00370 {
00371 mbstowcs(window_title, "Second Life Updater", 2048);
00372 }
00373
00374 WNDCLASSEX wndclassex = { 0 };
00375 DEVMODE dev_mode = { 0 };
00376 char update_exec_path[MAX_PATH];
00377 char *ptr;
00378
00379 const int WINDOW_WIDTH = 250;
00380 const int WINDOW_HEIGHT = 100;
00381
00382 wsprintf(gProgress, L"Connecting...");
00383
00384
00385 wndclassex.cbSize = sizeof(WNDCLASSEX);
00386 wndclassex.style = CS_HREDRAW | CS_VREDRAW;
00387 wndclassex.hInstance = hInstance;
00388 wndclassex.lpfnWndProc = WinProc;
00389 wndclassex.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
00390 wndclassex.lpszClassName = win_class_name;
00391
00392 RegisterClassEx(&wndclassex);
00393
00394
00395 EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode);
00396
00397 gWindow = CreateWindowEx(NULL, win_class_name,
00398 window_title,
00399 WS_OVERLAPPEDWINDOW,
00400 CW_USEDEFAULT,
00401 CW_USEDEFAULT,
00402 WINDOW_WIDTH,
00403 WINDOW_HEIGHT,
00404 NULL, NULL, hInstance, NULL);
00405
00406 ShowWindow(gWindow, nShowCmd);
00407 UpdateWindow(gWindow);
00408
00409 if (parse_args_result)
00410 {
00411 MessageBox(gWindow,
00412 L"Usage: updater -url <url> [-name <window_title>] [-program <program_name>] [-silent]",
00413 L"Usage", MB_OK);
00414 return parse_args_result;
00415 }
00416
00417
00418 if (!gUpdateURL)
00419 {
00420 MessageBox(gWindow, L"Please specify the download url from the command line",
00421 L"Error", MB_OK);
00422 return 1;
00423 }
00424
00425
00426 if (0 == GetTempPathA(MAX_PATH - 14, update_exec_path))
00427 {
00428 MessageBox(gWindow, L"Problem with GetTempPath()",
00429 L"Error", MB_OK);
00430 return 1;
00431 }
00432 if (0 == GetTempFileNameA(update_exec_path, NULL, 0, update_exec_path))
00433 {
00434 MessageBox(gWindow, L"Problem with GetTempFileName()",
00435 L"Error", MB_OK);
00436 return 1;
00437 }
00438
00439 ptr = strrchr(update_exec_path, '.');
00440 *(ptr + 1) = 'e';
00441 *(ptr + 2) = 'x';
00442 *(ptr + 3) = 'e';
00443 *(ptr + 4) = 0;
00444
00445 WCHAR update_uri[4096];
00446 mbstowcs(update_uri, gUpdateURL, 4096);
00447
00448 int success;
00449 int cancelled;
00450
00451
00452 #if _DEBUG
00453 fprintf(logfile,"Calling get_url_into_file\n");
00454 fflush(logfile);
00455 #endif
00456 success = get_url_into_file(update_uri, update_exec_path, &cancelled);
00457
00458
00459
00460
00461 if (gTotalBytesRead < (64 * 1024) && ! cancelled)
00462 {
00463 MessageBox(gWindow,
00464 L"The auto-update has failed.\n"
00465 L"The problem may be caused by other software installed \n"
00466 L"on your computer, such as a firewall.\n"
00467 L"Please visit http://sl.daleglass.net/download \n"
00468 L"to download the latest version of the viewer.\n",
00469 NULL, MB_OK);
00470 return 1;
00471 }
00472
00473 if (cancelled)
00474 {
00475
00476 return 0;
00477 }
00478
00479 if (!success)
00480 {
00481 MessageBox(gWindow,
00482 L"Viewer download failed.\n"
00483 L"Please try again later.",
00484 NULL, MB_OK);
00485 return 1;
00486 }
00487
00488
00489 char params[2048];
00490 if (gIsSilent && gProgramName)
00491 {
00492 _snprintf(params, sizeof(params), "/S /P=\"%s\"", gProgramName);
00493 params[2047] = '\0';
00494 }
00495 else if (gProgramName)
00496 {
00497 _snprintf(params, sizeof(params), "/P=\"%s\"", gProgramName);
00498 params[2047] = '\0';
00499 }
00500 else if (gIsSilent)
00501 {
00502 sprintf(params, "/S");
00503 }
00504 else
00505 {
00506 params[0] = '\0';
00507 }
00508
00509 if (32 >= (int) ShellExecuteA(gWindow, "open", update_exec_path, params,
00510 "C:\\", SW_SHOWDEFAULT))
00511 {
00512
00513 MessageBox(gWindow, L"ShellExecute failed. Please try again later.", NULL, MB_OK);
00514 return 1;
00515 }
00516
00517 if (gIsSilent && gProductName)
00518 {
00519 WCHAR message[2048];
00520 WCHAR wproduct[2048];
00521 mbstowcs(wproduct, gProductName, 2048);
00522
00523 wsprintf(message,
00524 L"Updating %s. %s will automatically start once the update is complete. This may take a minute...",
00525 wproduct, wproduct);
00526
00527 MessageBox(gWindow, message, L"Download Complete", MB_OK);
00528 }
00529
00530 return 0;
00531 }