diff --git a/src/net.c b/src/net.c index c2fdef8b..6118e3d2 100644 --- a/src/net.c +++ b/src/net.c @@ -388,16 +388,24 @@ HANDLE DownloadFileThreaded(const char* url, const char* file, HWND hProgressDia return CreateThread(NULL, 0, _DownloadFileThread, NULL, 0, NULL); } +static __inline uint64_t to_uint64_t(uint16_t x[4]) { + int i; + uint64_t ret = 0; + for (i=0; i<4; i++) + ret = (ret<<16) + x[i]; + return ret; +} /* * Background thread to check for updates */ static DWORD WINAPI CheckForUpdatesThread(LPVOID param) { - BOOL force = (BOOL)param; + BOOL releases_only, force = (BOOL)param, found_new_version = FALSE; const char* server_url = RUFUS_URL "/"; - int i, j, verbose = 2, verpos[4]; - static char* archname[] = {"win_x86", "win_x64"}; + int i, j, k, verbose = 0, verpos[4]; + static const char* archname[] = {"win_x86", "win_x64"}; + static const char* channel[] = {"release", "beta"}; // release channel DWORD dwFlags, dwSize, dwDownloaded, dwTotalSize, dwStatus; char* buf = NULL; char agent[64], hostname[64], urlpath[128], mime[32]; @@ -415,11 +423,10 @@ static DWORD WINAPI CheckForUpdatesThread(LPVOID param) // Wait a while before checking for updates // TODO: Also check on inactivity do { - Sleep(10000); - } while (iso_op_in_progress || format_op_in_progress); + Sleep(15000); + } while (iso_op_in_progress || format_op_in_progress || (dialog_showing>0)); - // TODO: reenable this - // verbose = ReadRegistryKey32(REGKEY_VERBOSE_UPDATES); + verbose = ReadRegistryKey32(REGKEY_VERBOSE_UPDATES); if ((ReadRegistryKey32(REGKEY_UPDATE_INTERVAL) == -1)) { vuprintf("Check for updates disabled, as per registry settings.\n"); goto out; @@ -471,97 +478,124 @@ static DWORD WINAPI CheckForUpdatesThread(LPVOID param) if (hConnection == NULL) goto out; - // At this stage we can query the server for various update version files. - // We first try to lookup for "___.ver" - // and then remove each each of the components until we find our match. For instance, we may first - // look for rufus_win_x64_6.2.ver (Win8 x64) but only get a match for rufus_win_x64_6.ver (Vista x64 or later) - // This allows sunsetting OS versions (eg XP) or providing different downloads for different archs/groups. + releases_only = !GetRegistryKeyBool(REGKEY_INCLUDE_BETAS); - safe_sprintf(urlpath, sizeof(urlpath), "%s_%s_%d.%d.ver", APPLICATION_NAME, - archname[is_x64?1:0], os_version.dwMajorVersion, os_version.dwMinorVersion); - vuprintf("Base update check: %s\n", urlpath); - for (i=0, j=(int)safe_strlen(urlpath)-5; (j>0)&&(i___.ver" + // and then remove each each of the components until we find our match. For instance, we may first + // look for rufus_win_x64_6.2.ver (Win8 x64) but only get a match for rufus_win_x64_6.ver (Vista x64 or later) + // This allows sunsetting OS versions (eg XP) or providing different downloads for different archs/groups. + safe_sprintf(urlpath, sizeof(urlpath), "%s%s%s_%s_%d.%d.ver", APPLICATION_NAME, (k==0)?"":"_", + (k==0)?"":channel[k], archname[is_x64?1:0], os_version.dwMajorVersion, os_version.dwMinorVersion); + vuprintf("Base update check: %s\n", urlpath); + for (i=0, j=(int)safe_strlen(urlpath)-5; (j>0)&&(i= ARRAYSIZE(channel))) + goto out; + continue; + } + vuprintf("Found match for %s on server %s.", urlpath, server_url); + + dwSize = sizeof(mime); + HttpQueryInfoA(hRequest, HTTP_QUERY_CONTENT_TYPE, (LPVOID)&mime, &dwSize, NULL); + if (strcmp(mime, "text/plain") != 0) goto out; - // Ensure that we get a text file - dwSize = sizeof(dwStatus); - dwStatus = 404; - HttpQueryInfoA(hRequest, HTTP_QUERY_STATUS_CODE|HTTP_QUERY_FLAG_NUMBER, (LPVOID)&dwStatus, &dwSize, NULL); - if (dwStatus == 200) - break; - InternetCloseHandle(hRequest); - hRequest = NULL; - safe_strcpy(&urlpath[verpos[i]], 5, ".ver"); - } - if (dwStatus != 200) { - vuprintf("Could not find a version file on server %s", server_url); - goto out; - } - vuprintf("Found match for %s on server %s.", urlpath, server_url); - - dwSize = sizeof(mime); - HttpQueryInfoA(hRequest, HTTP_QUERY_CONTENT_TYPE, (LPVOID)&mime, &dwSize, NULL); - if (strcmp(mime, "text/plain") != 0) - goto out; - // We also get a date from Apache, which we'll use to avoid out of sync check, - // in case some set their clock way into the future and back. - // On the other hand, if local clock is set way back in the past, we will never check. - dwSize = sizeof(ServerTime); - // If we can't get a date we can trust, don't bother... - if ( (!HttpQueryInfoA(hRequest, HTTP_QUERY_DATE|HTTP_QUERY_FLAG_SYSTEMTIME, (LPVOID)&ServerTime, &dwSize, NULL)) - || (!SystemTimeToFileTime(&ServerTime, &FileTime)) ) - goto out; - server_time = ((((int64_t)FileTime.dwHighDateTime)<<32) + FileTime.dwLowDateTime) / 10000000; - vvuprintf("Server time: %" PRId64 "\n", server_time); - // Always store the server response time - the only clock we trust! - WriteRegistryKey64(REGKEY_LAST_UPDATE, server_time); - // Might as well let the user know - if (!force) { - if (local_time > server_time + 600) { - uprintf("Your local clock appears more than 10 minutes early - You ought to fix that...\n"); - } - if (local_time < server_time - 600) { - uprintf("Your local clock appears more than 10 minutes late - you ought to fix that...\n"); + // We also get a date from Apache, which we'll use to avoid out of sync check, + // in case some set their clock way into the future and back. + // On the other hand, if local clock is set way back in the past, we will never check. + dwSize = sizeof(ServerTime); + // If we can't get a date we can trust, don't bother... + if ( (!HttpQueryInfoA(hRequest, HTTP_QUERY_DATE|HTTP_QUERY_FLAG_SYSTEMTIME, (LPVOID)&ServerTime, &dwSize, NULL)) + || (!SystemTimeToFileTime(&ServerTime, &FileTime)) ) + goto out; + server_time = ((((int64_t)FileTime.dwHighDateTime)<<32) + FileTime.dwLowDateTime) / 10000000; + vvuprintf("Server time: %" PRId64 "\n", server_time); + // Always store the server response time - the only clock we trust! + WriteRegistryKey64(REGKEY_LAST_UPDATE, server_time); + // Might as well let the user know + if (!force) { + if (local_time > server_time + 600) { + uprintf("Your local clock appears more than 10 minutes early - You ought to fix that...\n"); + } + if (local_time < server_time - 600) { + uprintf("Your local clock appears more than 10 minutes late - you ought to fix that...\n"); + } } + + dwSize = sizeof(dwTotalSize); + if (!HttpQueryInfoA(hRequest, HTTP_QUERY_CONTENT_LENGTH|HTTP_QUERY_FLAG_NUMBER, (LPVOID)&dwTotalSize, &dwSize, NULL)) + goto out; + + safe_free(buf); + // Make sure the file is NUL terminated + buf = (char*)calloc(dwTotalSize+1, 1); + if (buf == NULL) goto out; + // This is a version file - we should be able to gulp it down in one go + if (!InternetReadFile(hRequest, buf, dwTotalSize, &dwDownloaded) || (dwDownloaded != dwTotalSize)) + goto out; + + vuprintf("Successfully downloaded version file (%d bytes)\n", dwTotalSize); + + parse_update(buf, dwTotalSize+1); + + vuprintf("UPDATE DATA:\n"); + vuprintf(" version: %d.%d.%d.%d (%s)\n", update.version[0], update.version[1], + update.version[2], update.version[3], channel[k]); + vuprintf(" platform_min: %d.%d\n", update.platform_min[0], update.platform_min[1]); + vuprintf(" url: %s\n", update.download_url); + + found_new_version = (to_uint64_t(update.version) > to_uint64_t(rufus_version)) + && ( (os_version.dwMajorVersion > update.platform_min[0]) + || ( (os_version.dwMajorVersion == update.platform_min[0]) && (os_version.dwMinorVersion >= update.platform_min[1])) ); + uprintf("N%sew %s version found%c\n", found_new_version?"":"o n", channel[k], found_new_version?'!':'.'); } - dwSize = sizeof(dwTotalSize); - if (!HttpQueryInfoA(hRequest, HTTP_QUERY_CONTENT_LENGTH|HTTP_QUERY_FLAG_NUMBER, (LPVOID)&dwTotalSize, &dwSize, NULL)) - goto out; - - // Make sure the file is NUL terminated - buf = (char*)calloc(dwTotalSize+1, 1); - if (buf == NULL) goto out; - // This is a version file, so we should be able to do it in one go - if (!InternetReadFile(hRequest, buf, dwTotalSize, &dwDownloaded) || (dwDownloaded != dwTotalSize)) - goto out; - - vuprintf("Successfully downloaded version file (%d bytes)\n", dwTotalSize); - - parse_update(buf, dwTotalSize+1); - out: safe_free(buf); if (hRequest) InternetCloseHandle(hRequest); if (hConnection) InternetCloseHandle(hConnection); if (hSession) InternetCloseHandle(hSession); + // Start the new download after cleanup + if (found_new_version) { + // User may have started an operation while we were checking + while (iso_op_in_progress || format_op_in_progress || (dialog_showing>0)) { + Sleep(3000); + } + DownloadNewVersion(); + } update_check_in_progress = FALSE; ExitThread(0); } diff --git a/src/parser.c b/src/parser.c index f40a3ed6..805d5983 100644 --- a/src/parser.c +++ b/src/parser.c @@ -214,7 +214,7 @@ void parse_update(char* buf, size_t len) if ((buf == NULL) || (len < 2) || (len > 65536) || (buf[len-1] != 0) || (buf[len-2] == '\\')) return; // Sanitize the data - Not a silver bullet, but it helps - len = safe_strlen(buf)+1; // Someone may be inserting NULs + len = safe_strlen(buf)+1; // Someone may be inserting NULs for (i=0; ilpVtbl->Release(pfod); + dialog_showing--; return; } fallback: if (pfod != NULL) { pfod->lpVtbl->Release(pfod); } +#else + dialog_showing++; #endif INIT_XP_SHELL32; memset(&bi, 0, sizeof(BROWSEINFOW)); @@ -359,6 +363,7 @@ fallback: if (pidl != NULL) { CoTaskMemFree(pidl); } + dialog_showing--; } /* @@ -455,6 +460,7 @@ char* FileDialog(BOOL save, char* path, char* filename, char* ext, char* ext_des wchar_t *wpath = NULL, *wfilename = NULL; IShellItem *si_path = NULL; // Automatically freed + dialog_showing++; INIT_VISTA_SHELL32; if (IS_VISTA_SHELL32_AVAILABLE) { // Setup the file extension filter table @@ -519,6 +525,7 @@ char* FileDialog(BOOL save, char* path, char* filename, char* ext, char* ext_des goto fallback; } pfd->lpVtbl->Release(pfd); + dialog_showing--; return filepath; } @@ -526,6 +533,8 @@ fallback: if (pfd != NULL) { pfd->lpVtbl->Release(pfd); } +#else + dialog_showing++; #endif memset(&ofn, 0, sizeof(ofn)); @@ -564,6 +573,7 @@ fallback: } } safe_free(ext_string); + dialog_showing--; return filepath; } @@ -715,7 +725,11 @@ INT_PTR CALLBACK AboutCallback(HWND hDlg, UINT message, WPARAM wParam, LPARAM lP INT_PTR CreateAboutBox(void) { - return DialogBoxA(hMainInstance, MAKEINTRESOURCEA(IDD_ABOUTBOX), hMainDialog, AboutCallback); + INT_PTR r; + dialog_showing++; + r = DialogBoxA(hMainInstance, MAKEINTRESOURCEA(IDD_ABOUTBOX), hMainDialog, AboutCallback); + dialog_showing--; + return r; } /* @@ -800,6 +814,8 @@ BOOL Notification(int type, const notification_info* more_info, char* title, cha { BOOL ret; va_list args; + + dialog_showing++; szMessageText = (char*)malloc(MAX_PATH); if (szMessageText == NULL) return FALSE; szMessageTitle = title; @@ -828,6 +844,7 @@ BOOL Notification(int type, const notification_info* more_info, char* title, cha } ret = (DialogBox(hMainInstance, MAKEINTRESOURCE(IDD_NOTIFICATION), hMainDialog, NotificationCallback) == IDYES); safe_free(szMessageText); + dialog_showing--; return ret; } @@ -1117,6 +1134,7 @@ INT_PTR CALLBACK UpdateCallback(HWND hDlg, UINT message, WPARAM wParam, LPARAM l { HWND hPolicy; static HWND hFrequency, hBeta; + uint32_t freq; switch (message) { case WM_INITDIALOG: @@ -1127,11 +1145,30 @@ INT_PTR CALLBACK UpdateCallback(HWND hDlg, UINT message, WPARAM wParam, LPARAM l IGNORE_RETVAL(ComboBox_SetItemData(hFrequency, ComboBox_AddStringU(hFrequency, "Daily (Default)"), 86400)); IGNORE_RETVAL(ComboBox_SetItemData(hFrequency, ComboBox_AddStringU(hFrequency, "Weekly"), 604800)); IGNORE_RETVAL(ComboBox_SetItemData(hFrequency, ComboBox_AddStringU(hFrequency, "Monthly"), 2629800)); - IGNORE_RETVAL(ComboBox_SetCurSel(hFrequency, 1)); + freq = ReadRegistryKey32(REGKEY_UPDATE_INTERVAL); + switch(freq) { + case -1: + IGNORE_RETVAL(ComboBox_SetCurSel(hFrequency, 0)); + break; + case 0: + case 86400: + IGNORE_RETVAL(ComboBox_SetCurSel(hFrequency, 1)); + break; + case 604800: + IGNORE_RETVAL(ComboBox_SetCurSel(hFrequency, 2)); + break; + case 2629800: + IGNORE_RETVAL(ComboBox_SetCurSel(hFrequency, 3)); + break; + default: + IGNORE_RETVAL(ComboBox_SetItemData(hFrequency, ComboBox_AddStringU(hFrequency, "Custom"), freq)); + IGNORE_RETVAL(ComboBox_SetCurSel(hFrequency, 4)); + break; + } hBeta = GetDlgItem(hDlg, IDC_INCLUDE_BETAS); IGNORE_RETVAL(ComboBox_AddStringU(hBeta, "Yes")); IGNORE_RETVAL(ComboBox_AddStringU(hBeta, "No")); - IGNORE_RETVAL(ComboBox_SetCurSel(hBeta, 1)); + IGNORE_RETVAL(ComboBox_SetCurSel(hBeta, GetRegistryKeyBool(REGKEY_INCLUDE_BETAS)?0:1)); hPolicy = GetDlgItem(hDlg, IDC_POLICY); SendMessage(hPolicy, EM_AUTOURLDETECT, 1, 0); SendMessageA(hPolicy, EM_SETTEXTEX, (WPARAM)&friggin_microsoft_unicode_amateurs, (LPARAM)update_policy);