2012-03-11 01:55:25 +00:00
|
|
|
/*
|
|
|
|
* Rufus: The Reliable USB Formatting Utility
|
2012-11-08 01:20:48 +00:00
|
|
|
* Networking functionality (web file download, check for update, etc.)
|
2012-03-11 01:55:25 +00:00
|
|
|
* Copyright (c) 2012 Pete Batard <pete@akeo.ie>
|
|
|
|
*
|
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program 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 General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* Memory leaks detection - define _CRTDBG_MAP_ALLOC as preprocessor macro */
|
|
|
|
#ifdef _CRTDBG_MAP_ALLOC
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <crtdbg.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <windows.h>
|
2012-11-08 01:20:48 +00:00
|
|
|
#include <wininet.h>
|
2012-03-11 01:55:25 +00:00
|
|
|
#include <stdio.h>
|
2012-11-08 01:20:48 +00:00
|
|
|
#include <malloc.h>
|
2012-03-11 01:55:25 +00:00
|
|
|
#include <string.h>
|
2012-11-08 01:20:48 +00:00
|
|
|
#include <inttypes.h>
|
2012-03-11 01:55:25 +00:00
|
|
|
|
|
|
|
#include "msapi_utf8.h"
|
|
|
|
#include "rufus.h"
|
2012-11-08 01:20:48 +00:00
|
|
|
#include "registry.h"
|
2012-03-11 01:55:25 +00:00
|
|
|
#include "resource.h"
|
2012-11-08 01:20:48 +00:00
|
|
|
|
|
|
|
/* Maximum download chunk size, in bytes */
|
|
|
|
#define DOWNLOAD_BUFFER_SIZE 10240
|
|
|
|
/* Default delay between update checks (1 day) */
|
|
|
|
#define DEFAULT_UPDATE_INTERVAL (24*3600)
|
|
|
|
|
|
|
|
|
|
|
|
/* Globals */
|
|
|
|
DWORD error_code;
|
|
|
|
|
|
|
|
/* MinGW is missing some of those */
|
|
|
|
#if !defined(ERROR_INTERNET_DISCONNECTED)
|
|
|
|
#define ERROR_INTERNET_DISCONNECTED (INTERNET_ERROR_BASE + 163)
|
|
|
|
#endif
|
|
|
|
#if !defined(ERROR_INTERNET_SERVER_UNREACHABLE)
|
|
|
|
#define ERROR_INTERNET_SERVER_UNREACHABLE (INTERNET_ERROR_BASE + 164)
|
|
|
|
#endif
|
|
|
|
#if !defined(ERROR_INTERNET_PROXY_SERVER_UNREACHABLE)
|
|
|
|
#define ERROR_INTERNET_PROXY_SERVER_UNREACHABLE (INTERNET_ERROR_BASE + 165)
|
|
|
|
#endif
|
|
|
|
#if !defined(ERROR_INTERNET_BAD_AUTO_PROXY_SCRIPT)
|
|
|
|
#define ERROR_INTERNET_BAD_AUTO_PROXY_SCRIPT (INTERNET_ERROR_BASE + 166)
|
|
|
|
#endif
|
|
|
|
#if !defined(ERROR_INTERNET_UNABLE_TO_DOWNLOAD_SCRIPT)
|
|
|
|
#define ERROR_INTERNET_UNABLE_TO_DOWNLOAD_SCRIPT (INTERNET_ERROR_BASE + 167)
|
|
|
|
#endif
|
|
|
|
#if !defined(ERROR_INTERNET_FAILED_DUETOSECURITYCHECK)
|
|
|
|
#define ERROR_INTERNET_FAILED_DUETOSECURITYCHECK (INTERNET_ERROR_BASE + 171)
|
|
|
|
#endif
|
|
|
|
#if !defined(ERROR_INTERNET_NOT_INITIALIZED)
|
|
|
|
#define ERROR_INTERNET_NOT_INITIALIZED (INTERNET_ERROR_BASE + 172)
|
|
|
|
#endif
|
|
|
|
#if !defined(ERROR_INTERNET_NEED_MSN_SSPI_PKG)
|
|
|
|
#define ERROR_INTERNET_NEED_MSN_SSPI_PKG (INTERNET_ERROR_BASE + 173)
|
|
|
|
#endif
|
|
|
|
#if !defined(ERROR_INTERNET_LOGIN_FAILURE_DISPLAY_ENTITY_BODY)
|
|
|
|
#define ERROR_INTERNET_LOGIN_FAILURE_DISPLAY_ENTITY_BODY (INTERNET_ERROR_BASE + 174)
|
|
|
|
#endif
|
2012-03-11 01:55:25 +00:00
|
|
|
|
|
|
|
/*
|
2012-11-08 01:20:48 +00:00
|
|
|
* FormatMessage does not handle internet errors
|
|
|
|
* http://support.microsoft.com/kb/193625
|
2012-03-11 01:55:25 +00:00
|
|
|
*/
|
2012-11-08 01:20:48 +00:00
|
|
|
const char* WinInetErrorString(void)
|
2012-03-11 01:55:25 +00:00
|
|
|
{
|
2012-11-08 01:20:48 +00:00
|
|
|
static char error_string[256];
|
|
|
|
DWORD size = sizeof(error_string);
|
2012-03-11 01:55:25 +00:00
|
|
|
|
|
|
|
error_code = GetLastError();
|
|
|
|
|
2012-11-08 01:20:48 +00:00
|
|
|
if ((error_code < INTERNET_ERROR_BASE) || (error_code > INTERNET_ERROR_LAST))
|
2012-03-11 01:55:25 +00:00
|
|
|
return WindowsErrorString();
|
|
|
|
|
|
|
|
switch(error_code) {
|
2012-11-08 01:20:48 +00:00
|
|
|
case ERROR_INTERNET_OUT_OF_HANDLES:
|
2012-03-11 01:55:25 +00:00
|
|
|
return "No more handles could be generated at this time.";
|
2012-11-08 01:20:48 +00:00
|
|
|
case ERROR_INTERNET_TIMEOUT:
|
2012-03-11 01:55:25 +00:00
|
|
|
return "The request has timed out.";
|
2012-11-08 01:20:48 +00:00
|
|
|
case ERROR_INTERNET_INTERNAL_ERROR:
|
2012-03-11 01:55:25 +00:00
|
|
|
return "An internal error has occurred.";
|
2012-11-08 01:20:48 +00:00
|
|
|
case ERROR_INTERNET_INVALID_URL:
|
2012-03-11 01:55:25 +00:00
|
|
|
return "The URL is invalid.";
|
2012-11-08 01:20:48 +00:00
|
|
|
case ERROR_INTERNET_UNRECOGNIZED_SCHEME:
|
2012-03-11 01:55:25 +00:00
|
|
|
return "The URL scheme could not be recognized or is not supported.";
|
2012-11-08 01:20:48 +00:00
|
|
|
case ERROR_INTERNET_NAME_NOT_RESOLVED:
|
2012-03-11 01:55:25 +00:00
|
|
|
return "The server name could not be resolved.";
|
2012-11-08 01:20:48 +00:00
|
|
|
case ERROR_INTERNET_PROTOCOL_NOT_FOUND:
|
|
|
|
return "The requested protocol could not be located.";
|
|
|
|
case ERROR_INTERNET_INVALID_OPTION:
|
|
|
|
return "A request specified an invalid option value.";
|
|
|
|
case ERROR_INTERNET_BAD_OPTION_LENGTH:
|
|
|
|
return "The length of an option supplied is incorrect for the type of option specified.";
|
|
|
|
case ERROR_INTERNET_OPTION_NOT_SETTABLE:
|
2012-03-11 01:55:25 +00:00
|
|
|
return "The request option cannot be set, only queried.";
|
2012-11-08 01:20:48 +00:00
|
|
|
case ERROR_INTERNET_SHUTDOWN:
|
|
|
|
return "The Win32 Internet function support is being shut down or unloaded.";
|
|
|
|
case ERROR_INTERNET_INCORRECT_USER_NAME:
|
|
|
|
return "The request to connect and log on to an FTP server could not be completed because the supplied user name is incorrect.";
|
|
|
|
case ERROR_INTERNET_INCORRECT_PASSWORD:
|
|
|
|
return "The request to connect and log on to an FTP server could not be completed because the supplied password is incorrect.";
|
|
|
|
case ERROR_INTERNET_LOGIN_FAILURE:
|
|
|
|
return "The request to connect to and log on to an FTP server failed.";
|
|
|
|
case ERROR_INTERNET_INVALID_OPERATION:
|
|
|
|
return "The requested operation is invalid.";
|
|
|
|
case ERROR_INTERNET_OPERATION_CANCELLED:
|
|
|
|
return "The operation was canceled, usually because the handle on which the request was operating was closed before the operation completed.";
|
|
|
|
case ERROR_INTERNET_INCORRECT_HANDLE_TYPE:
|
2012-03-11 01:55:25 +00:00
|
|
|
return "The type of handle supplied is incorrect for this operation.";
|
2012-11-08 01:20:48 +00:00
|
|
|
case ERROR_INTERNET_INCORRECT_HANDLE_STATE:
|
2012-03-11 01:55:25 +00:00
|
|
|
return "The requested operation cannot be carried out because the handle supplied is not in the correct state.";
|
2012-11-08 01:20:48 +00:00
|
|
|
case ERROR_INTERNET_NOT_PROXY_REQUEST:
|
|
|
|
return "The request cannot be made via a proxy.";
|
|
|
|
case ERROR_INTERNET_REGISTRY_VALUE_NOT_FOUND:
|
|
|
|
return "A required registry value could not be located.";
|
|
|
|
case ERROR_INTERNET_BAD_REGISTRY_PARAMETER:
|
|
|
|
return "A required registry value was located but is an incorrect type or has an invalid value.";
|
|
|
|
case ERROR_INTERNET_NO_DIRECT_ACCESS:
|
|
|
|
return "Direct network access cannot be made at this time.";
|
|
|
|
case ERROR_INTERNET_NO_CONTEXT:
|
|
|
|
return "An asynchronous request could not be made because a zero context value was supplied.";
|
|
|
|
case ERROR_INTERNET_NO_CALLBACK:
|
|
|
|
return "An asynchronous request could not be made because a callback function has not been set.";
|
|
|
|
case ERROR_INTERNET_REQUEST_PENDING:
|
|
|
|
return "The required operation could not be completed because one or more requests are pending.";
|
|
|
|
case ERROR_INTERNET_INCORRECT_FORMAT:
|
|
|
|
return "The format of the request is invalid.";
|
|
|
|
case ERROR_INTERNET_ITEM_NOT_FOUND:
|
|
|
|
return "The requested item could not be located.";
|
|
|
|
case ERROR_INTERNET_CANNOT_CONNECT:
|
2012-03-11 01:55:25 +00:00
|
|
|
return "The attempt to connect to the server failed.";
|
2012-11-08 01:20:48 +00:00
|
|
|
case ERROR_INTERNET_CONNECTION_ABORTED:
|
2012-03-11 01:55:25 +00:00
|
|
|
return "The connection with the server has been terminated.";
|
2012-11-08 01:20:48 +00:00
|
|
|
case ERROR_INTERNET_CONNECTION_RESET:
|
|
|
|
return "The connection with the server has been reset.";
|
|
|
|
case ERROR_INTERNET_FORCE_RETRY:
|
|
|
|
return "Calls for the Win32 Internet function to redo the request.";
|
|
|
|
case ERROR_INTERNET_INVALID_PROXY_REQUEST:
|
|
|
|
return "The request to the proxy was invalid.";
|
|
|
|
case ERROR_INTERNET_HANDLE_EXISTS:
|
|
|
|
return "The request failed because the handle already exists.";
|
|
|
|
case ERROR_INTERNET_SEC_CERT_DATE_INVALID:
|
|
|
|
return "SSL certificate date that was received from the server is bad. The certificate is expired.";
|
|
|
|
case ERROR_INTERNET_SEC_CERT_CN_INVALID:
|
2012-03-11 01:55:25 +00:00
|
|
|
return "SSL certificate common name (host name field) is incorrect.";
|
2012-11-08 01:20:48 +00:00
|
|
|
case ERROR_INTERNET_HTTP_TO_HTTPS_ON_REDIR:
|
|
|
|
return "The application is moving from a non-SSL to an SSL connection because of a redirect.";
|
|
|
|
case ERROR_INTERNET_HTTPS_TO_HTTP_ON_REDIR:
|
|
|
|
return "The application is moving from an SSL to an non-SSL connection because of a redirect.";
|
|
|
|
case ERROR_INTERNET_MIXED_SECURITY:
|
|
|
|
return "Some of the content being viewed may have come from unsecured servers.";
|
|
|
|
case ERROR_INTERNET_CHG_POST_IS_NON_SECURE:
|
|
|
|
return "The application is posting and attempting to change multiple lines of text on a server that is not secure.";
|
|
|
|
case ERROR_INTERNET_POST_IS_NON_SECURE:
|
|
|
|
return "The application is posting data to a server that is not secure.";
|
|
|
|
case ERROR_FTP_TRANSFER_IN_PROGRESS:
|
|
|
|
return "The requested operation cannot be made on the FTP session handle because an operation is already in progress.";
|
|
|
|
case ERROR_FTP_DROPPED:
|
|
|
|
return "The FTP operation was not completed because the session was aborted.";
|
|
|
|
case ERROR_GOPHER_PROTOCOL_ERROR:
|
|
|
|
case ERROR_GOPHER_NOT_FILE:
|
|
|
|
case ERROR_GOPHER_DATA_ERROR:
|
|
|
|
case ERROR_GOPHER_END_OF_DATA:
|
|
|
|
case ERROR_GOPHER_INVALID_LOCATOR:
|
|
|
|
case ERROR_GOPHER_INCORRECT_LOCATOR_TYPE:
|
|
|
|
case ERROR_GOPHER_NOT_GOPHER_PLUS:
|
|
|
|
case ERROR_GOPHER_ATTRIBUTE_NOT_FOUND:
|
|
|
|
case ERROR_GOPHER_UNKNOWN_LOCATOR:
|
|
|
|
return "Gopher? Really??? What is this? 1994?";
|
|
|
|
case ERROR_HTTP_HEADER_NOT_FOUND:
|
|
|
|
return "The requested header could not be located.";
|
|
|
|
case ERROR_HTTP_DOWNLEVEL_SERVER:
|
|
|
|
return "The server did not return any headers.";
|
|
|
|
case ERROR_HTTP_INVALID_SERVER_RESPONSE:
|
|
|
|
return "The server response could not be parsed.";
|
|
|
|
case ERROR_HTTP_INVALID_HEADER:
|
|
|
|
return "The supplied header is invalid.";
|
|
|
|
case ERROR_HTTP_INVALID_QUERY_REQUEST:
|
|
|
|
return "The request made to HttpQueryInfo is invalid.";
|
|
|
|
case ERROR_HTTP_HEADER_ALREADY_EXISTS:
|
|
|
|
return "The header could not be added because it already exists.";
|
|
|
|
case ERROR_HTTP_REDIRECT_FAILED:
|
|
|
|
return "The redirection failed because either the scheme changed or all attempts made to redirect failed.";
|
|
|
|
case ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED:
|
2012-03-11 01:55:25 +00:00
|
|
|
return "Client Authentication certificate needed";
|
2012-11-08 01:20:48 +00:00
|
|
|
case ERROR_INTERNET_BAD_AUTO_PROXY_SCRIPT:
|
2012-03-11 01:55:25 +00:00
|
|
|
return "Bad auto proxy script.";
|
2012-11-08 01:20:48 +00:00
|
|
|
case ERROR_INTERNET_UNABLE_TO_DOWNLOAD_SCRIPT:
|
2012-03-11 01:55:25 +00:00
|
|
|
return "Unable to download script.";
|
2012-11-08 01:20:48 +00:00
|
|
|
case ERROR_INTERNET_NOT_INITIALIZED:
|
|
|
|
return "Internet has not be initialized.";
|
|
|
|
case ERROR_INTERNET_UNABLE_TO_CACHE_FILE:
|
|
|
|
return "Unable to cache the file.";
|
|
|
|
case ERROR_INTERNET_TCPIP_NOT_INSTALLED:
|
|
|
|
return "TPC/IP not installed.";
|
|
|
|
case ERROR_INTERNET_DISCONNECTED:
|
|
|
|
return "Internet is disconnected.";
|
|
|
|
case ERROR_INTERNET_SERVER_UNREACHABLE:
|
|
|
|
return "Server could not be reached.";
|
|
|
|
case ERROR_INTERNET_PROXY_SERVER_UNREACHABLE:
|
|
|
|
return "Proxy server could not be reached.";
|
|
|
|
case ERROR_INTERNET_FAILED_DUETOSECURITYCHECK:
|
|
|
|
return "A security check prevented internet connection.";
|
|
|
|
case ERROR_INTERNET_NEED_MSN_SSPI_PKG:
|
|
|
|
return "This connection requires an MSN Security Support Provider Interface package.";
|
|
|
|
case ERROR_INTERNET_LOGIN_FAILURE_DISPLAY_ENTITY_BODY:
|
|
|
|
return "Please ask Microsoft about that one!";
|
|
|
|
case ERROR_INTERNET_EXTENDED_ERROR:
|
|
|
|
InternetGetLastResponseInfoA(&error_code, error_string, &size);
|
|
|
|
return error_string;
|
2012-03-11 01:55:25 +00:00
|
|
|
default:
|
2012-11-08 01:20:48 +00:00
|
|
|
safe_sprintf(error_string, sizeof(error_string), "Unknown internet error 0x%08X", error_code);
|
|
|
|
return error_string;
|
2012-03-11 01:55:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Download a file from an URL
|
2012-11-08 01:20:48 +00:00
|
|
|
* Mostly taken from http://support.microsoft.com/kb/234913
|
2012-03-11 01:55:25 +00:00
|
|
|
*/
|
|
|
|
BOOL DownloadFile(const char* url, const char* file)
|
|
|
|
{
|
2012-11-08 01:20:48 +00:00
|
|
|
BOOL r = FALSE;
|
|
|
|
DWORD dwFlags, dwSize, dwDownloaded, dwTotalSize, dwStatus;
|
|
|
|
FILE* fd = NULL;
|
2012-03-11 01:55:25 +00:00
|
|
|
LONG progress_style;
|
2012-11-08 01:20:48 +00:00
|
|
|
unsigned char buf[DOWNLOAD_BUFFER_SIZE];
|
|
|
|
char agent[64], hostname[64], urlpath[128];
|
|
|
|
HINTERNET hSession = NULL, hConnection = NULL, hRequest = NULL;
|
|
|
|
URL_COMPONENTSA UrlParts = {sizeof(URL_COMPONENTSA), NULL, 1, (INTERNET_SCHEME)0,
|
|
|
|
hostname, sizeof(hostname), 0, NULL, 1, urlpath, sizeof(urlpath), NULL, 1};
|
|
|
|
int i;
|
2012-03-11 01:55:25 +00:00
|
|
|
|
|
|
|
// We reuse the ISO progress dialog for download progress
|
|
|
|
SetWindowTextU(hISOProgressDlg, "Downloading file...");
|
|
|
|
SetWindowTextU(hISOFileName, url);
|
|
|
|
progress_style = GetWindowLong(hISOProgressBar, GWL_STYLE);
|
|
|
|
SetWindowLong(hISOProgressBar, GWL_STYLE, progress_style & (~PBS_MARQUEE));
|
|
|
|
SendMessage(hISOProgressBar, PBM_SETPOS, 0, 0);
|
|
|
|
ShowWindow(hISOProgressDlg, SW_SHOW);
|
|
|
|
UpdateWindow(hISOProgressDlg);
|
|
|
|
|
|
|
|
PrintStatus(0, FALSE, "Downloading %s: Connecting...\n", file);
|
|
|
|
uprintf("Downloading %s from %s\n", file, url);
|
|
|
|
|
2012-11-08 01:20:48 +00:00
|
|
|
if (!InternetCrackUrlA(url, safe_strlen(url), 0, &UrlParts)) {
|
|
|
|
uprintf("Unable to decode URL: %s\n", WindowsErrorString());
|
2012-03-11 01:55:25 +00:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2012-11-08 01:20:48 +00:00
|
|
|
// Open an Internet session
|
|
|
|
for (i=5; (i>0) && (!InternetGetConnectedState(&dwFlags, 0)); i--) {
|
|
|
|
Sleep(1000);
|
|
|
|
}
|
|
|
|
if (i <= 0) {
|
|
|
|
// http://msdn.microsoft.com/en-us/library/windows/desktop/aa384702.aspx is wrong...
|
|
|
|
SetLastError(ERROR_INTERNET_NOT_INITIALIZED);
|
|
|
|
uprintf("Network is unavailable: %s\n", WinInetErrorString());
|
2012-03-11 01:55:25 +00:00
|
|
|
goto out;
|
|
|
|
}
|
2012-11-08 01:20:48 +00:00
|
|
|
_snprintf(agent, ARRAYSIZE(agent), "Rufus/%d.%d.%d.%d", rufus_version[0], rufus_version[1], rufus_version[2], rufus_version[3]);
|
|
|
|
hSession = InternetOpenA(agent, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
|
|
|
|
if (hSession == NULL) {
|
|
|
|
uprintf("Could not open internet session: %s\n", WinInetErrorString());
|
2012-03-11 01:55:25 +00:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2012-11-08 01:20:48 +00:00
|
|
|
hConnection = InternetConnectA(hSession, UrlParts.lpszHostName, UrlParts.nPort, NULL, NULL, INTERNET_SERVICE_HTTP, 0, (DWORD_PTR)NULL);
|
|
|
|
if (hConnection == NULL) {
|
|
|
|
uprintf("Could not connect to server %s:%d: %s\n", UrlParts.lpszHostName, UrlParts.nPort, WinInetErrorString());
|
2012-03-11 01:55:25 +00:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2012-11-08 01:20:48 +00:00
|
|
|
hRequest = HttpOpenRequestA(hConnection, "GET", UrlParts.lpszUrlPath, NULL, NULL, (const char**)"*/*\0",
|
|
|
|
INTERNET_FLAG_HYPERLINK|INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTP|INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTPS|INTERNET_FLAG_NO_COOKIES|
|
|
|
|
INTERNET_FLAG_NO_UI|INTERNET_FLAG_NO_CACHE_WRITE, (DWORD_PTR)NULL);
|
|
|
|
if (hRequest == NULL) {
|
|
|
|
uprintf("Could not open url %s: %s\n", url, WindowsErrorString());
|
2012-03-11 01:55:25 +00:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2012-11-08 01:20:48 +00:00
|
|
|
if (!HttpSendRequest(hRequest, NULL, 0, NULL, 0)) {
|
|
|
|
uprintf("Unable to send request: %s\n", WinInetErrorString());
|
2012-03-11 01:55:25 +00:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2012-11-08 01:20:48 +00:00
|
|
|
// Get the file size
|
|
|
|
dwSize = sizeof(dwStatus);
|
|
|
|
dwStatus = 404;
|
|
|
|
HttpQueryInfoA(hRequest, HTTP_QUERY_STATUS_CODE|HTTP_QUERY_FLAG_NUMBER, (LPVOID)&dwStatus, &dwSize, NULL);
|
|
|
|
if (dwStatus != 200) {
|
|
|
|
error_code = ERROR_INTERNET_ITEM_NOT_FOUND;
|
|
|
|
uprintf("Unable to acess file. Server status %d\n", dwStatus);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
dwSize = sizeof(dwTotalSize);
|
|
|
|
if (!HttpQueryInfoA(hRequest, HTTP_QUERY_CONTENT_LENGTH|HTTP_QUERY_FLAG_NUMBER, (LPVOID)&dwTotalSize, &dwSize, NULL)) {
|
|
|
|
uprintf("Unable to retrieve file length: %s\n", WinInetErrorString());
|
2012-03-11 01:55:25 +00:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
uprintf("File length: %d bytes\n", dwTotalSize);
|
|
|
|
|
|
|
|
fd = fopen(file, "wb");
|
|
|
|
if (fd == NULL) {
|
2012-11-08 01:20:48 +00:00
|
|
|
uprintf("Unable to create file %s: %s\n", file, WinInetErrorString());
|
2012-03-11 01:55:25 +00:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Keep checking for data until there is nothing left.
|
2012-11-08 01:20:48 +00:00
|
|
|
dwSize = 0;
|
|
|
|
while (1) {
|
2012-03-11 01:55:25 +00:00
|
|
|
if (IS_ERROR(FormatStatus))
|
|
|
|
goto out;
|
|
|
|
|
2012-11-08 01:20:48 +00:00
|
|
|
if (!InternetReadFile(hRequest, buf, sizeof(buf), &dwDownloaded) || (dwDownloaded == 0))
|
2012-03-11 01:55:25 +00:00
|
|
|
break;
|
2012-11-08 01:20:48 +00:00
|
|
|
dwSize += dwDownloaded;
|
|
|
|
SendMessage(hISOProgressBar, PBM_SETPOS, (WPARAM)(MAX_PROGRESS*((1.0f*dwSize)/(1.0f*dwTotalSize))), 0);
|
|
|
|
PrintStatus(0, FALSE, "Downloading %s: %0.1f%%\n", file, (100.0f*dwSize)/(1.0f*dwTotalSize));
|
|
|
|
if (fwrite(buf, 1, dwDownloaded, fd) != dwDownloaded) {
|
|
|
|
uprintf("Error writing file %s: %s\n", file, WinInetErrorString());
|
2012-03-11 01:55:25 +00:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
}
|
2012-11-08 01:20:48 +00:00
|
|
|
|
|
|
|
if (dwSize != dwTotalSize) {
|
|
|
|
uprintf("Could not download complete file - read: %d bytes, expected: %d bytes\n", dwSize, dwTotalSize);
|
|
|
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_WRITE_FAULT;
|
|
|
|
goto out;
|
|
|
|
} else {
|
|
|
|
r = TRUE;
|
2012-03-11 01:55:25 +00:00
|
|
|
uprintf("Successfully downloaded %s\n", file);
|
2012-11-08 01:20:48 +00:00
|
|
|
}
|
2012-03-11 01:55:25 +00:00
|
|
|
|
|
|
|
out:
|
|
|
|
ShowWindow(hISOProgressDlg, SW_HIDE);
|
|
|
|
if (fd != NULL) fclose(fd);
|
|
|
|
if (!r) {
|
|
|
|
_unlink(file);
|
|
|
|
PrintStatus(0, FALSE, "Failed to download file.");
|
2012-11-08 01:20:48 +00:00
|
|
|
SetLastError(error_code);
|
|
|
|
MessageBoxA(hMainDialog, IS_ERROR(FormatStatus)?StrError(FormatStatus):WinInetErrorString(),
|
2012-03-11 01:55:25 +00:00
|
|
|
"File download", MB_OK|MB_ICONERROR);
|
|
|
|
}
|
2012-11-08 01:20:48 +00:00
|
|
|
if (hRequest) InternetCloseHandle(hRequest);
|
|
|
|
if (hConnection) InternetCloseHandle(hConnection);
|
|
|
|
if (hSession) InternetCloseHandle(hSession);
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define uuprintf if(verbose) uprintf
|
|
|
|
#define uuuprintf if(verbose>1) uprintf
|
|
|
|
// TODO: call this from a thread that will launch the download if successful
|
|
|
|
BOOL CheckForUpdates(const char* url)
|
|
|
|
{
|
|
|
|
BOOL r = FALSE;
|
|
|
|
int verbose = 2;
|
|
|
|
DWORD dwFlags, dwSize, dwDownloaded, dwTotalSize, dwStatus;
|
|
|
|
char* buf = NULL;
|
|
|
|
char agent[64], hostname[64], urlpath[128], mime[32];
|
|
|
|
HINTERNET hSession = NULL, hConnection = NULL, hRequest = NULL;
|
|
|
|
URL_COMPONENTSA UrlParts = {sizeof(URL_COMPONENTSA), NULL, 1, (INTERNET_SCHEME)0,
|
|
|
|
hostname, sizeof(hostname), 0, NULL, 1, urlpath, sizeof(urlpath), NULL, 1};
|
|
|
|
SYSTEMTIME ServerTime, LocalTime;
|
|
|
|
FILETIME FileTime;
|
|
|
|
int64_t local_time, reg_time, server_time, update_interval;
|
|
|
|
|
|
|
|
verbose = ReadRegistryKey32(REGKEY_VERBOSE_UPDATES);
|
|
|
|
if (GetRegistryKeyBool(REGKEY_DISABLE_UPDATES)) {
|
|
|
|
uuprintf("Check for updates disabled, as per registry settings.\n");
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
reg_time = ReadRegistryKey64(REGKEY_LAST_UPDATE);
|
|
|
|
update_interval = (int64_t)ReadRegistryKey32(REGKEY_UPDATE_INTERVAL);
|
|
|
|
if (update_interval == 0) {
|
|
|
|
WriteRegistryKey32(REGKEY_UPDATE_INTERVAL, DEFAULT_UPDATE_INTERVAL);
|
|
|
|
update_interval = DEFAULT_UPDATE_INTERVAL;
|
|
|
|
}
|
|
|
|
GetSystemTime(&LocalTime);
|
|
|
|
if (!SystemTimeToFileTime(&LocalTime, &FileTime))
|
|
|
|
goto out;
|
|
|
|
local_time = ((((int64_t)FileTime.dwHighDateTime)<<32) + FileTime.dwLowDateTime) / 10000000;
|
|
|
|
uuuprintf("Local time: %" PRId64 "\n", local_time);
|
|
|
|
if (local_time < reg_time + update_interval) {
|
|
|
|
uuprintf("Next update check in %" PRId64 " seconds.\n", reg_time + update_interval - local_time);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
PrintStatus(3000, FALSE, "Checking for Rufus updates...\n");
|
|
|
|
|
|
|
|
if ((!InternetCrackUrlA(url, safe_strlen(url), 0, &UrlParts)) || (!InternetGetConnectedState(&dwFlags, 0)))
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
_snprintf(agent, ARRAYSIZE(agent), "Rufus/%d.%d.%d.%d", rufus_version[0], rufus_version[1], rufus_version[2], rufus_version[3]);
|
|
|
|
hSession = InternetOpenA(agent, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
|
|
|
|
if (hSession == NULL)
|
|
|
|
goto out;
|
|
|
|
hConnection = InternetConnectA(hSession, UrlParts.lpszHostName, UrlParts.nPort, NULL, NULL, INTERNET_SERVICE_HTTP, 0, (DWORD_PTR)NULL);
|
|
|
|
if (hConnection == NULL)
|
|
|
|
goto out;
|
2012-03-11 01:55:25 +00:00
|
|
|
|
2012-11-08 01:20:48 +00:00
|
|
|
hRequest = HttpOpenRequestA(hConnection, "GET", UrlParts.lpszUrlPath, NULL, NULL, (const char**)"*/*\0",
|
|
|
|
INTERNET_FLAG_HYPERLINK|INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTP|INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTPS|INTERNET_FLAG_NO_COOKIES|
|
|
|
|
INTERNET_FLAG_NO_UI|INTERNET_FLAG_NO_CACHE_WRITE, (DWORD_PTR)NULL);
|
|
|
|
if ((hRequest == NULL) || (!HttpSendRequest(hRequest, NULL, 0, NULL, 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) goto out;
|
|
|
|
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;
|
|
|
|
uuuprintf("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 (local_time > server_time + 600) {
|
|
|
|
uprintf("Your local clock seems more than 10 minutes early - You probably want to fix that...\n");
|
|
|
|
}
|
|
|
|
if (local_time < server_time - 600) {
|
|
|
|
uprintf("Your local clock seems more than 10 minutes late - you probably want to fix that...\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
dwSize = sizeof(dwTotalSize);
|
|
|
|
if (!HttpQueryInfoA(hRequest, HTTP_QUERY_CONTENT_LENGTH|HTTP_QUERY_FLAG_NUMBER, (LPVOID)&dwTotalSize, &dwSize, NULL))
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
buf = (char*)calloc(dwTotalSize+1, 1);
|
|
|
|
// Our buffer is always supposed to be large enough, and our read is always supposed to be in one go
|
|
|
|
if (!InternetReadFile(hRequest, buf, dwTotalSize, &dwDownloaded) || (dwDownloaded != dwTotalSize))
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
uuprintf("Successfully downloaded version file %s (%d bytes)\n", url, dwTotalSize);
|
|
|
|
uuprintf("%s\n", buf);
|
|
|
|
r = TRUE;
|
|
|
|
|
|
|
|
out:
|
|
|
|
safe_free(buf);
|
|
|
|
if (hRequest) InternetCloseHandle(hRequest);
|
|
|
|
if (hConnection) InternetCloseHandle(hConnection);
|
|
|
|
if (hSession) InternetCloseHandle(hSession);
|
2012-03-11 01:55:25 +00:00
|
|
|
return r;
|
|
|
|
}
|