[DWNL] Localize the File Download utility (#853)

Also, changed header string to include a start time stamp similar to the one in wget.
CORE-14498
This commit is contained in:
Lee Schroeder 2018-09-18 15:55:44 -06:00 committed by Hermès BÉLUSCA - MAÏTO
parent 108991a6fb
commit 08be1648f9
5 changed files with 138 additions and 53 deletions

View file

@ -1,8 +1,11 @@
add_executable(dwnl dwnl.c) include_directories(${REACTOS_SOURCE_DIR}/sdk/lib/conutils)
add_executable(dwnl dwnl.c dwnl.rc)
set_module_type(dwnl win32cui UNICODE) set_module_type(dwnl win32cui UNICODE)
target_link_libraries(dwnl conutils ${PSEH_LIB})
target_link_libraries(dwnl uuid) target_link_libraries(dwnl uuid)
add_importlibs(dwnl urlmon wininet msvcrt kernel32) add_importlibs(dwnl urlmon wininet msvcrt user32 kernel32)
if(MSVC) if(MSVC)
add_importlibs(dwnl ntdll) add_importlibs(dwnl ntdll)

View file

@ -1,8 +1,11 @@
#define COBJMACROS #define COBJMACROS
#include <urlmon.h> #include <urlmon.h>
#include <wininet.h> #include <wininet.h>
#include <tchar.h> #include <wchar.h>
#include <strsafe.h> #include <strsafe.h>
#include <conutils.h>
#include "resource.h"
/* FIXME: add correct definitions to urlmon.idl */ /* FIXME: add correct definitions to urlmon.idl */
#ifdef UNICODE #ifdef UNICODE
@ -19,8 +22,8 @@ typedef struct
{ {
const IBindStatusCallbackVtbl* lpIBindStatusCallbackVtbl; const IBindStatusCallbackVtbl* lpIBindStatusCallbackVtbl;
LONG ref; LONG ref;
TCHAR szHostName[INTERNET_MAX_HOST_NAME_LENGTH + 1]; WCHAR szHostName[INTERNET_MAX_HOST_NAME_LENGTH + 1];
TCHAR szMimeType[128]; WCHAR szMimeType[128];
UINT64 Size; UINT64 Size;
UINT64 Progress; UINT64 Progress;
UINT bResolving : 1; UINT bResolving : 1;
@ -39,10 +42,10 @@ CBindStatusCallback_Destroy(CBindStatusCallback *This)
} }
static void static void
write_status(LPCTSTR lpFmt, ...) write_status(LPCWSTR lpFmt, ...)
{ {
va_list args; va_list args;
TCHAR szTxt[128]; WCHAR szTxt[128];
CONSOLE_SCREEN_BUFFER_INFO csbi; CONSOLE_SCREEN_BUFFER_INFO csbi;
va_start(args, lpFmt); va_start(args, lpFmt);
@ -51,17 +54,19 @@ write_status(LPCTSTR lpFmt, ...)
if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi)) if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi))
{ {
_tprintf(_T("\r%*.*s"), -(csbi.dwSize.X - 1), csbi.dwSize.X - 1, szTxt); ConPrintf(StdOut, L"\r%*.*s", -(csbi.dwSize.X - 1), csbi.dwSize.X - 1, szTxt);
} }
else else
{ {
_putts(szTxt); ConPuts(StdOut, szTxt);
} }
} }
static void static void
CBindStatusCallback_UpdateProgress(CBindStatusCallback *This) CBindStatusCallback_UpdateProgress(CBindStatusCallback *This)
{ {
WCHAR szMessage[MAX_PATH];
/* FIXME: better output */ /* FIXME: better output */
if (This->Size != 0) if (This->Size != 0)
{ {
@ -71,12 +76,16 @@ CBindStatusCallback_UpdateProgress(CBindStatusCallback *This)
if (Percentage > 99) if (Percentage > 99)
Percentage = 99; Percentage = 99;
write_status(_T("%2d%% (%I64u bytes downloaded)"), Percentage, This->Progress); LoadStringW(NULL, IDS_BYTES_DOWNLOADED_FULL, szMessage, ARRAYSIZE(szMessage));
write_status(szMessage, Percentage, This->Progress);
} }
else else
{ {
LoadStringW(NULL, IDS_BYTES_DOWNLOADED, szMessage, ARRAYSIZE(szMessage));
/* Unknown size */ /* Unknown size */
write_status(_T("%I64u bytes downloaded"), This->Progress); write_status(szMessage, This->Progress);
} }
} }
@ -168,10 +177,10 @@ CBindStatusCallback_OnProgress(IBindStatusCallback *iface,
case BINDSTATUS_FINDINGRESOURCE: case BINDSTATUS_FINDINGRESOURCE:
if (!This->bResolving) if (!This->bResolving)
{ {
_tcscpy(This->szHostName, szStatusText); wcscpy(This->szHostName, szStatusText);
This->bResolving = TRUE; This->bResolving = TRUE;
_tprintf(_T("Resolving %s... "), This->szHostName); ConResPrintf(StdOut, IDS_RESOLVING, This->szHostName);
} }
break; break;
@ -179,14 +188,16 @@ CBindStatusCallback_OnProgress(IBindStatusCallback *iface,
This->bConnecting = TRUE; This->bConnecting = TRUE;
This->bSendingReq = FALSE; This->bSendingReq = FALSE;
This->bBeginTransfer = FALSE; This->bBeginTransfer = FALSE;
This->szMimeType[0] = _T('\0'); This->szMimeType[0] = L'\0';
if (This->bResolving) if (This->bResolving)
{ {
_tprintf(_T("done.\n")); ConResPrintf(StdOut, IDS_DONE);
_tprintf(_T("Connecting to %s[%s]... "), This->szHostName, szStatusText); ConResPrintf(StdOut, IDS_CONNECTING_TO_FULL, This->szHostName, szStatusText);
} }
else else
_tprintf(_T("Connecting to %s... "), szStatusText); {
ConResPrintf(StdOut, IDS_CONNECTING_TO, szStatusText);
}
break; break;
case BINDSTATUS_REDIRECTING: case BINDSTATUS_REDIRECTING:
@ -194,24 +205,24 @@ CBindStatusCallback_OnProgress(IBindStatusCallback *iface,
This->bConnecting = FALSE; This->bConnecting = FALSE;
This->bSendingReq = FALSE; This->bSendingReq = FALSE;
This->bBeginTransfer = FALSE; This->bBeginTransfer = FALSE;
This->szMimeType[0] = _T('\0'); This->szMimeType[0] = L'\0';
_tprintf(_T("Redirecting to %s... "), szStatusText); ConResPrintf(StdOut, IDS_REDIRECTING_TO, szStatusText);
break; break;
case BINDSTATUS_SENDINGREQUEST: case BINDSTATUS_SENDINGREQUEST:
This->bBeginTransfer = FALSE; This->bBeginTransfer = FALSE;
This->szMimeType[0] = _T('\0'); This->szMimeType[0] = L'\0';
if (This->bResolving || This->bConnecting) if (This->bResolving || This->bConnecting)
_tprintf(_T("done.\n")); ConResPrintf(StdOut, IDS_DONE);
if (!This->bSendingReq) if (!This->bSendingReq)
_tprintf(_T("Sending request... ")); ConResPrintf(StdOut, IDS_SEND_REQUEST);
This->bSendingReq = TRUE; This->bSendingReq = TRUE;
break; break;
case BINDSTATUS_MIMETYPEAVAILABLE: case BINDSTATUS_MIMETYPEAVAILABLE:
_tcscpy(This->szMimeType, szStatusText); wcscpy(This->szMimeType, szStatusText);
break; break;
case BINDSTATUS_BEGINDOWNLOADDATA: case BINDSTATUS_BEGINDOWNLOADDATA:
@ -219,24 +230,23 @@ CBindStatusCallback_OnProgress(IBindStatusCallback *iface,
This->Size = (UINT64)ulProgressMax; This->Size = (UINT64)ulProgressMax;
if (This->bSendingReq) if (This->bSendingReq)
_tprintf(_T("done.\n")); ConResPrintf(StdOut, IDS_DONE);
if (!This->bBeginTransfer && This->Size != 0) if (!This->bBeginTransfer && This->Size != 0)
{ {
if (This->szMimeType[0] != _T('\0')) if (This->szMimeType[0] != L'\0')
_tprintf(_T("Length: %I64u [%s]\n"), This->Size, This->szMimeType); ConResPrintf(StdOut, IDS_LENGTH_FULL, This->Size, This->szMimeType);
else else
_tprintf(_T("Length: %I64u\n"), This->Size); ConResPrintf(StdOut, IDS_LENGTH, This->Size);
} }
_tprintf(_T("\n")); ConPuts(StdOut, L"\n");
This->bBeginTransfer = TRUE; This->bBeginTransfer = TRUE;
break; break;
case BINDSTATUS_ENDDOWNLOADDATA: case BINDSTATUS_ENDDOWNLOADDATA:
write_status(_T("File saved.")); ConResPrintf(StdOut, IDS_FILE_SAVED);
_tprintf(_T("\n"));
break; break;
case BINDSTATUS_DOWNLOADINGDATA: case BINDSTATUS_DOWNLOADINGDATA:
@ -319,7 +329,7 @@ CreateBindStatusCallback(void)
static int static int
get_display_url(IN LPURL_COMPONENTS purl, get_display_url(IN LPURL_COMPONENTS purl,
OUT TCHAR *szBuffer, OUT LPWSTR szBuffer,
IN PDWORD pdwBufferSize) IN PDWORD pdwBufferSize)
{ {
URL_COMPONENTS urlc; URL_COMPONENTS urlc;
@ -336,23 +346,24 @@ get_display_url(IN LPURL_COMPONENTS purl,
} }
static int static int
download_file(IN LPCTSTR pszUrl, download_file(IN LPCWSTR pszUrl,
IN LPCTSTR pszFile OPTIONAL) IN LPCWSTR pszFile OPTIONAL)
{ {
TCHAR szScheme[INTERNET_MAX_SCHEME_LENGTH + 1]; WCHAR szScheme[INTERNET_MAX_SCHEME_LENGTH + 1];
TCHAR szHostName[INTERNET_MAX_HOST_NAME_LENGTH + 1]; WCHAR szHostName[INTERNET_MAX_HOST_NAME_LENGTH + 1];
TCHAR szUserName[INTERNET_MAX_USER_NAME_LENGTH + 1]; WCHAR szUserName[INTERNET_MAX_USER_NAME_LENGTH + 1];
TCHAR szPassWord[INTERNET_MAX_PASSWORD_LENGTH + 1]; WCHAR szPassWord[INTERNET_MAX_PASSWORD_LENGTH + 1];
TCHAR szUrlPath[INTERNET_MAX_PATH_LENGTH + 1]; WCHAR szUrlPath[INTERNET_MAX_PATH_LENGTH + 1];
TCHAR szExtraInfo[INTERNET_MAX_PATH_LENGTH + 1]; WCHAR szExtraInfo[INTERNET_MAX_PATH_LENGTH + 1];
TCHAR szUrl[INTERNET_MAX_URL_LENGTH + 1]; WCHAR szUrl[INTERNET_MAX_URL_LENGTH + 1];
DWORD dwUrlLen; DWORD dwUrlLen;
LPTSTR pszFilePart; LPTSTR pszFilePart;
URL_COMPONENTS urlc; URL_COMPONENTS urlc;
IBindStatusCallback *pbsc; IBindStatusCallback *pbsc;
int iRet; int iRet;
SYSTEMTIME sysTime;
if (pszFile != NULL && pszFile[0] == _T('\0')) if (pszFile != NULL && pszFile[0] == L'\0')
pszFile = NULL; pszFile = NULL;
urlc.dwStructSize = sizeof(urlc); urlc.dwStructSize = sizeof(urlc);
@ -368,7 +379,7 @@ download_file(IN LPCTSTR pszUrl,
urlc.dwUrlPathLength = sizeof(szUrlPath) / sizeof(szUrlPath[0]); urlc.dwUrlPathLength = sizeof(szUrlPath) / sizeof(szUrlPath[0]);
urlc.lpszExtraInfo = szExtraInfo; urlc.lpszExtraInfo = szExtraInfo;
urlc.dwExtraInfoLength = sizeof(szExtraInfo) / sizeof(szExtraInfo[0]); urlc.dwExtraInfoLength = sizeof(szExtraInfo) / sizeof(szExtraInfo[0]);
if (!InternetCrackUrl(pszUrl, _tcslen(pszUrl), ICU_ESCAPE, &urlc)) if (!InternetCrackUrl(pszUrl, wcslen(pszUrl), ICU_ESCAPE, &urlc))
return DWNL_E_LASTERROR; return DWNL_E_LASTERROR;
if (urlc.nScheme != INTERNET_SCHEME_FTP && if (urlc.nScheme != INTERNET_SCHEME_FTP &&
@ -381,15 +392,15 @@ download_file(IN LPCTSTR pszUrl,
if (urlc.nScheme == INTERNET_SCHEME_FTP && urlc.dwUserNameLength == 0 && urlc.dwPasswordLength == 0) if (urlc.nScheme == INTERNET_SCHEME_FTP && urlc.dwUserNameLength == 0 && urlc.dwPasswordLength == 0)
{ {
_tcscpy(szUserName, _T("anonymous")); wcscpy(szUserName, L"anonymous");
urlc.dwUserNameLength = _tcslen(szUserName); urlc.dwUserNameLength = wcslen(szUserName);
} }
/* FIXME: Get file name from server */ /* FIXME: Get file name from server */
if (urlc.dwUrlPathLength == 0 && pszFile == NULL) if (urlc.dwUrlPathLength == 0 && pszFile == NULL)
return DWNL_E_NEEDTARGETFILENAME; return DWNL_E_NEEDTARGETFILENAME;
pszFilePart = _tcsrchr(szUrlPath, _T('/')); pszFilePart = wcsrchr(szUrlPath, L'/');
if (pszFilePart != NULL) if (pszFilePart != NULL)
pszFilePart++; pszFilePart++;
@ -411,7 +422,12 @@ download_file(IN LPCTSTR pszUrl,
if (iRet <= 0) if (iRet <= 0)
return iRet; return iRet;
_tprintf(_T("Download `%s\'\n\t=> `%s\'\n"), szUrl, pszFile); GetLocalTime(&sysTime);
ConPrintf(StdOut, L"--%d-%d-%d %d:%d:%d-- %s\n\t=> %s\n",
sysTime.wYear, sysTime.wMonth, sysTime.wDay,
sysTime.wHour, sysTime.wMinute, sysTime.wSecond,
szUrl, pszFile);
/* Generate the URL to download */ /* Generate the URL to download */
dwUrlLen = sizeof(szUrl) / sizeof(szUrl[0]); dwUrlLen = sizeof(szUrl) / sizeof(szUrl[0]);
@ -435,19 +451,19 @@ download_file(IN LPCTSTR pszUrl,
static int static int
print_err(int iErr) print_err(int iErr)
{ {
write_status(_T("")); write_status(L"");
if (iErr == DWNL_E_LASTERROR) if (iErr == DWNL_E_LASTERROR)
{ {
if (GetLastError() == ERROR_SUCCESS) if (GetLastError() == ERROR_SUCCESS)
{ {
/* File not found */ /* File not found */
_ftprintf(stderr, _T("\nERROR: Download failed.\n")); ConResPrintf(StdErr, IDS_ERROR_DOWNLOAD);
} }
else else
{ {
/* Display last error code */ /* Display last error code */
_ftprintf(stderr, _T("\nERROR: %u\n"), GetLastError()); ConResPrintf(StdErr, IDS_ERROR_CODE, GetLastError());
} }
} }
else else
@ -455,11 +471,11 @@ print_err(int iErr)
switch (iErr) switch (iErr)
{ {
case DWNL_E_NEEDTARGETFILENAME: case DWNL_E_NEEDTARGETFILENAME:
_ftprintf(stderr, _T("\nERROR: Cannot determine filename, please specify a destination file name.\n")); ConResPrintf(StdErr, IDS_ERROR_FILENAME);
break; break;
case DWNL_E_UNSUPPORTEDSCHEME: case DWNL_E_UNSUPPORTEDSCHEME:
_ftprintf(stderr, _T("\nERROR: Unsupported protocol.\n")); ConResPrintf(StdErr, IDS_ERROR_PROTOCOL);
break; break;
} }
} }
@ -467,13 +483,16 @@ print_err(int iErr)
return 1; return 1;
} }
int _tmain(int argc, TCHAR **argv) int wmain(int argc, WCHAR **argv)
{ {
int iErr, iRet = 0; int iErr, iRet = 0;
/* Initialize the Console Standard Streams */
ConInitStdStreams();
if(argc != 2 && argc != 3) if(argc != 2 && argc != 3)
{ {
_tprintf(_T("Usage: dwnl URL [DESTINATION]")); ConResPrintf(StdOut, IDS_USAGE);
return 2; return 2;
} }

View file

@ -0,0 +1,16 @@
#include <windef.h>
#include "resource.h"
LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
#define REACTOS_STR_FILE_DESCRIPTION "ReactOS File Download Utility"
#define REACTOS_STR_INTERNAL_NAME "dwnl"
#define REACTOS_STR_ORIGINAL_FILENAME "dwnl.exe"
#include <reactos/version.rc>
/* UTF-8 */
#pragma code_page(65001)
#ifdef LANGUAGE_EN_US
#include "lang/en-US.rc"
#endif

View file

@ -0,0 +1,25 @@
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
STRINGTABLE
BEGIN
IDS_USAGE "Usage: dwnl URL [DESTINATION]\n"
IDS_RESOLVING "Resolving %s... "
IDS_DONE "done.\n"
IDS_LENGTH_FULL "Length: %I64u [%s]\n"
IDS_LENGTH "Length: %I64u\n"
IDS_FILE_SAVED "\nFile saved.\n"
IDS_CONNECTING_TO_FULL "Connecting to %s [%s]... "
IDS_CONNECTING_TO "Connecting to %s... "
IDS_REDIRECTING_TO "Redirecting to %s... "
IDS_SEND_REQUEST "Sending request... "
IDS_BYTES_DOWNLOADED "%I64u bytes downloaded"
IDS_BYTES_DOWNLOADED_FULL "%2d%% (%I64u byte(s) downloaded)"
END
STRINGTABLE
BEGIN
IDS_ERROR_DOWNLOAD "\nERROR: Download failed.\n"
IDS_ERROR_CODE "\nERROR: %u\n"
IDS_ERROR_FILENAME "\nERROR: Cannot determine filename, please specify a destination file name.\n"
IDS_ERROR_PROTOCOL "\nERROR: Unsupported protocol.\n"
END

View file

@ -0,0 +1,22 @@
#ifndef RESOURCE_H
#define RESOURCE_H
#define IDS_USAGE 0
#define IDS_RESOLVING 1
#define IDS_DONE 2
#define IDS_LENGTH_FULL 3
#define IDS_LENGTH 4
#define IDS_FILE_SAVED 5
#define IDS_CONNECTING_TO_FULL 6
#define IDS_CONNECTING_TO 7
#define IDS_REDIRECTING_TO 8
#define IDS_SEND_REQUEST 9
#define IDS_BYTES_DOWNLOADED 10
#define IDS_BYTES_DOWNLOADED_FULL 11
#define IDS_ERROR_DOWNLOAD 12
#define IDS_ERROR_CODE 13
#define IDS_ERROR_FILENAME 14
#define IDS_ERROR_PROTOCOL 15
#endif /* RESOURCE_H */