summaryrefslogtreecommitdiff
path: root/indra/win_updater/updater.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/win_updater/updater.cpp')
-rwxr-xr-xindra/win_updater/updater.cpp516
1 files changed, 0 insertions, 516 deletions
diff --git a/indra/win_updater/updater.cpp b/indra/win_updater/updater.cpp
deleted file mode 100755
index aeab5a3b13..0000000000
--- a/indra/win_updater/updater.cpp
+++ /dev/null
@@ -1,516 +0,0 @@
-/**
- * @file updater.cpp
- * @brief Windows auto-updater
- *
- * $LicenseInfo:firstyear=2002&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-//
-// Usage: updater -url <url>
-//
-
-// We use dangerous fopen, strtok, mbstowcs, sprintf
-// which generates warnings on VC2005.
-// *TODO: Switch to fopen_s, strtok_s, etc.
-#define _CRT_SECURE_NO_DEPRECATE
-
-#include <windows.h>
-#include <wininet.h>
-#include <stdio.h>
-#include <string>
-#include <iostream>
-#include <stdexcept>
-#include <sstream>
-#include <fstream>
-
-#define BUFSIZE 8192
-
-int gTotalBytesRead = 0;
-DWORD gTotalBytes = -1;
-HWND gWindow = NULL;
-WCHAR gProgress[256];
-char* gUpdateURL = NULL;
-
-#if _DEBUG
-std::ofstream logfile;
-#define DEBUG(expr) logfile << expr << std::endl
-#else
-#define DEBUG(expr) /**/
-#endif
-
-char* wchars_to_utf8chars(const WCHAR* in_chars)
-{
- int tlen = 0;
- const WCHAR* twc = in_chars;
- while (*twc++ != 0)
- {
- tlen++;
- }
- char* outchars = new char[tlen];
- char* res = outchars;
- for (int i=0; i<tlen; i++)
- {
- int cur_char = (int)(*in_chars++);
- if (cur_char < 0x80)
- {
- *outchars++ = (char)cur_char;
- }
- else
- {
- *outchars++ = '?';
- }
- }
- *outchars = 0;
- return res;
-}
-
-class Fetcher
-{
-public:
- Fetcher(const std::wstring& uri)
- {
- // These actions are broken out as separate methods not because it
- // makes the code clearer, but to avoid triggering AntiVir and
- // McAfee-GW-Edition virus scanners (DEV-31680).
- mInet = openInet();
- mDownload = openUrl(uri);
- }
-
- ~Fetcher()
- {
- DEBUG("Calling InternetCloseHandle");
- InternetCloseHandle(mDownload);
- InternetCloseHandle(mInet);
- }
-
- unsigned long read(char* buffer, size_t bufflen) const;
-
- DWORD getTotalBytes() const
- {
- DWORD totalBytes;
- DWORD sizeof_total_bytes = sizeof(totalBytes);
- HttpQueryInfo(mDownload, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER,
- &totalBytes, &sizeof_total_bytes, NULL);
- return totalBytes;
- }
-
- struct InetError: public std::runtime_error
- {
- InetError(const std::string& what): std::runtime_error(what) {}
- };
-
-private:
- // We test results from a number of different MS functions with different
- // return types -- but the common characteristic is that 0 (i.e. (! result))
- // means an error of some kind.
- template <typename RESULT>
- static RESULT check(const std::string& desc, RESULT result)
- {
- if (result)
- {
- // success, show caller
- return result;
- }
- DWORD err = GetLastError();
- std::ostringstream out;
- out << desc << " Failed: " << err;
- DEBUG(out.str());
- throw InetError(out.str());
- }
-
- HINTERNET openUrl(const std::wstring& uri) const;
- HINTERNET openInet() const;
-
- HINTERNET mInet, mDownload;
-};
-
-HINTERNET Fetcher::openInet() const
-{
- DEBUG("Calling InternetOpen");
- // Init wininet subsystem
- return check("InternetOpen",
- InternetOpen(L"LindenUpdater", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0));
-}
-
-HINTERNET Fetcher::openUrl(const std::wstring& uri) const
-{
- DEBUG("Calling InternetOpenUrl: " << wchars_to_utf8chars(uri.c_str()));
- return check("InternetOpenUrl",
- InternetOpenUrl(mInet, uri.c_str(), NULL, 0, INTERNET_FLAG_NEED_FILE, NULL));
-}
-
-unsigned long Fetcher::read(char* buffer, size_t bufflen) const
-{
- unsigned long bytes_read = 0;
- DEBUG("Calling InternetReadFile");
- check("InternetReadFile",
- InternetReadFile(mDownload, buffer, bufflen, &bytes_read));
- return bytes_read;
-}
-
-int WINAPI get_url_into_file(const std::wstring& uri, const std::string& path, int *cancelled)
-{
- int success = FALSE;
- *cancelled = FALSE;
-
- DEBUG("Opening '" << path << "'");
-
- FILE* fp = fopen(path.c_str(), "wb"); /* Flawfinder: ignore */
-
- if (!fp)
- {
- DEBUG("Failed to open '" << path << "'");
- return success;
- }
-
- // Note, ctor can throw, since it uses check() function.
- Fetcher fetcher(uri);
- gTotalBytes = fetcher.getTotalBytes();
-
-/*==========================================================================*|
- // nobody uses total_bytes?!? What's this doing here?
- DWORD total_bytes = 0;
- success = check("InternetQueryDataAvailable",
- InternetQueryDataAvailable(hdownload, &total_bytes, 0, 0));
-|*==========================================================================*/
-
- success = FALSE;
- while(!success && !(*cancelled))
- {
- char data[BUFSIZE]; /* Flawfinder: ignore */
- unsigned long bytes_read = fetcher.read(data, sizeof(data));
-
- if (!bytes_read)
- {
- DEBUG("InternetReadFile Read " << bytes_read << " bytes.");
- }
-
- DEBUG("Reading Data, bytes_read = " << bytes_read);
-
- if (bytes_read == 0)
- {
- // If InternetFileRead returns TRUE AND bytes_read == 0
- // we've successfully downloaded the entire file
- wsprintf(gProgress, L"Download complete.");
- success = TRUE;
- }
- else
- {
- // write what we've got, then continue
- fwrite(data, sizeof(char), bytes_read, fp);
-
- gTotalBytesRead += int(bytes_read);
-
- if (gTotalBytes != -1)
- wsprintf(gProgress, L"Downloaded: %d%%", 100 * gTotalBytesRead / gTotalBytes);
- else
- wsprintf(gProgress, L"Downloaded: %dK", gTotalBytesRead / 1024);
-
- }
-
- DEBUG("Calling InvalidateRect");
-
- // Mark the window as needing redraw (of the whole thing)
- InvalidateRect(gWindow, NULL, TRUE);
-
- // Do the redraw
- DEBUG("Calling UpdateWindow");
- UpdateWindow(gWindow);
-
- DEBUG("Calling PeekMessage");
- MSG msg;
- while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
- {
- TranslateMessage(&msg);
- DispatchMessage(&msg);
-
- if (msg.message == WM_QUIT)
- {
- // bail out, user cancelled
- *cancelled = TRUE;
- }
- }
- }
-
- fclose(fp);
- return success;
-}
-
-LRESULT CALLBACK WinProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
-{
- HDC hdc; // Drawing context
- PAINTSTRUCT ps;
-
- switch(message)
- {
- case WM_PAINT:
- {
- hdc = BeginPaint(hwnd, &ps);
-
- RECT rect;
- GetClientRect(hwnd, &rect);
- DrawText(hdc, gProgress, -1, &rect,
- DT_SINGLELINE | DT_CENTER | DT_VCENTER);
-
- EndPaint(hwnd, &ps);
- return 0;
- }
- case WM_CLOSE:
- case WM_DESTROY:
- // Get out of full screen
- // full_screen_mode(false);
- PostQuitMessage(0);
- return 0;
- }
- return DefWindowProc(hwnd, message, wparam, lparam);
-}
-
-#define win_class_name L"FullScreen"
-
-int parse_args(int argc, char **argv)
-{
- int j;
-
- for (j = 1; j < argc; j++)
- {
- if ((!strcmp(argv[j], "-url")) && (++j < argc))
- {
- gUpdateURL = argv[j];
- }
- }
-
- // If nothing was set, let the caller know.
- if (!gUpdateURL)
- {
- return 1;
- }
- return 0;
-}
-
-int WINAPI
-WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
-{
- // Parse the command line.
- LPSTR cmd_line_including_exe_name = GetCommandLineA();
-
- const int MAX_ARGS = 100;
- int argc = 0;
- char* argv[MAX_ARGS]; /* Flawfinder: ignore */
-
-#if _DEBUG
- logfile.open("updater.log", std::ios_base::out);
- DEBUG("Parsing command arguments");
-#endif
-
- char *token = NULL;
- if( cmd_line_including_exe_name[0] == '\"' )
- {
- // Exe name is enclosed in quotes
- token = strtok( cmd_line_including_exe_name, "\"" );
- argv[argc++] = token;
- token = strtok( NULL, " \t," );
- }
- else
- {
- // Exe name is not enclosed in quotes
- token = strtok( cmd_line_including_exe_name, " \t," );
- }
-
- while( (token != NULL) && (argc < MAX_ARGS) )
- {
- argv[argc++] = token;
- /* Get next token: */
- if (*(token + strlen(token) + 1) == '\"') /* Flawfinder: ignore */
- {
- token = strtok( NULL, "\"");
- }
- else
- {
- token = strtok( NULL, " \t," );
- }
- }
-
- gUpdateURL = NULL;
-
- /////////////////////////////////////////
- //
- // Process command line arguments
- //
-
- DEBUG("Processing command arguments");
-
- //
- // Parse the command line arguments
- //
- int parse_args_result = parse_args(argc, argv);
-
- WNDCLASSEX wndclassex = { 0 };
- //DEVMODE dev_mode = { 0 };
-
- const int WINDOW_WIDTH = 250;
- const int WINDOW_HEIGHT = 100;
-
- wsprintf(gProgress, L"Connecting...");
-
- /* Init the WNDCLASSEX */
- wndclassex.cbSize = sizeof(WNDCLASSEX);
- wndclassex.style = CS_HREDRAW | CS_VREDRAW;
- wndclassex.hInstance = hInstance;
- wndclassex.lpfnWndProc = WinProc;
- wndclassex.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
- wndclassex.lpszClassName = win_class_name;
-
- RegisterClassEx(&wndclassex);
-
- // Get the size of the screen
- //EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode);
-
- gWindow = CreateWindowEx(NULL, win_class_name,
- L"Second Life Updater",
- WS_OVERLAPPEDWINDOW,
- CW_USEDEFAULT,
- CW_USEDEFAULT,
- WINDOW_WIDTH,
- WINDOW_HEIGHT,
- NULL, NULL, hInstance, NULL);
-
- ShowWindow(gWindow, nShowCmd);
- UpdateWindow(gWindow);
-
- if (parse_args_result)
- {
- MessageBox(gWindow,
- L"Usage: updater -url <url> [-name <window_title>] [-program <program_name>] [-silent]",
- L"Usage", MB_OK);
- return parse_args_result;
- }
-
- // Did we get a userserver to work with?
- if (!gUpdateURL)
- {
- MessageBox(gWindow, L"Please specify the download url from the command line",
- L"Error", MB_OK);
- return 1;
- }
-
- // Can't feed GetTempPath into GetTempFile directly
- char temp_path[MAX_PATH]; /* Flawfinder: ignore */
- if (0 == GetTempPathA(sizeof(temp_path), temp_path))
- {
- MessageBox(gWindow, L"Problem with GetTempPath()",
- L"Error", MB_OK);
- return 1;
- }
- std::string update_exec_path(temp_path);
- update_exec_path.append("Second_Life_Updater.exe");
-
- WCHAR update_uri[4096];
- mbstowcs(update_uri, gUpdateURL, sizeof(update_uri));
-
- int success = 0;
- int cancelled = 0;
-
- // Actually do the download
- try
- {
- DEBUG("Calling get_url_into_file");
- success = get_url_into_file(update_uri, update_exec_path, &cancelled);
- }
- catch (const Fetcher::InetError& e)
- {
- (void)e;
- success = FALSE;
- DEBUG("Caught: " << e.what());
- }
-
- // WinInet can't tell us if we got a 404 or not. Therefor, we check
- // for the size of the downloaded file, and assume that our installer
- // will always be greater than 1MB.
- if (gTotalBytesRead < (1024 * 1024) && ! cancelled)
- {
- MessageBox(gWindow,
- L"The Second Life auto-update has failed.\n"
- L"The problem may be caused by other software installed \n"
- L"on your computer, such as a firewall.\n"
- L"Please visit http://secondlife.com/download/ \n"
- L"to download the latest version of Second Life.\n",
- NULL, MB_OK);
- return 1;
- }
-
- if (cancelled)
- {
- // silently exit
- return 0;
- }
-
- if (!success)
- {
- MessageBox(gWindow,
- L"Second Life download failed.\n"
- L"Please try again later.",
- NULL, MB_OK);
- return 1;
- }
-
- // TODO: Make updates silent (with /S to NSIS)
- //char params[256]; /* Flawfinder: ignore */
- //sprintf(params, "/S"); /* Flawfinder: ignore */
- //MessageBox(gWindow,
- // L"Updating Second Life.\n\nSecond Life will automatically start once the update is complete. This may take a minute...",
- // L"Download Complete",
- // MB_OK);
-
-/*==========================================================================*|
- // DEV-31680: ShellExecuteA() causes McAfee-GW-Edition and AntiVir
- // scanners to flag this executable as a probable virus vector.
- // Less than or equal to 32 means failure
- if (32 >= (int) ShellExecuteA(gWindow, "open", update_exec_path.c_str(), NULL,
- "C:\\", SW_SHOWDEFAULT))
-|*==========================================================================*/
- // from http://msdn.microsoft.com/en-us/library/ms682512(VS.85).aspx
- STARTUPINFOA si;
- PROCESS_INFORMATION pi;
- ZeroMemory(&si, sizeof(si));
- si.cb = sizeof(si);
- ZeroMemory(&pi, sizeof(pi));
-
- if (! CreateProcessA(update_exec_path.c_str(), // executable file
- NULL, // command line
- NULL, // process cannot be inherited
- NULL, // thread cannot be inherited
- FALSE, // do not inherit existing handles
- 0, // process creation flags
- NULL, // inherit parent's environment
- NULL, // inherit parent's current dir
- &si, // STARTUPINFO
- &pi)) // PROCESS_INFORMATION
- {
- MessageBox(gWindow, L"Update failed. Please try again later.", NULL, MB_OK);
- return 1;
- }
-
- // Give installer some time to open a window
- Sleep(1000);
-
- return 0;
-}