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