From 2f2b3303d75a516877c88319f83a9a680464fe72 Mon Sep 17 00:00:00 2001 From: Dan Hipschman Date: Thu, 13 Mar 2008 15:57:19 -0700 Subject: [PATCH] qmgr: Transfer files given by URL (including HTTP, etc). --- dlls/qmgr/Makefile.in | 2 +- dlls/qmgr/file.c | 39 +++++++++++++++++++--- dlls/qmgr/tests/job.c | 77 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 113 insertions(+), 5 deletions(-) diff --git a/dlls/qmgr/Makefile.in b/dlls/qmgr/Makefile.in index 30c699b093f..de636dbfe8d 100644 --- a/dlls/qmgr/Makefile.in +++ b/dlls/qmgr/Makefile.in @@ -3,7 +3,7 @@ TOPOBJDIR = ../.. SRCDIR = @srcdir@ VPATH = @srcdir@ MODULE = qmgr.dll -IMPORTS = advpack ole32 advapi32 kernel32 +IMPORTS = advpack wininet urlmon ole32 advapi32 kernel32 EXTRALIBS = -luuid C_SRCS = \ diff --git a/dlls/qmgr/file.c b/dlls/qmgr/file.c index a874062c6c0..fea84ecef2b 100644 --- a/dlls/qmgr/file.c +++ b/dlls/qmgr/file.c @@ -1,7 +1,7 @@ /* * Queue Manager (BITS) File * - * Copyright 2007 Google (Roy Shea) + * Copyright 2007, 2008 Google (Roy Shea, Dan Hipschman) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -18,6 +18,16 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include + +#include "windef.h" +#include "winbase.h" +#include "winuser.h" +#include "winreg.h" +#include "ole2.h" +#include "urlmon.h" +#include "wininet.h" + #include "qmgr.h" #include "wine/debug.h" @@ -204,6 +214,7 @@ BOOL processFile(BackgroundCopyFileImpl *file, BackgroundCopyJobImpl *job) static WCHAR prefix[] = {'B','I','T', 0}; WCHAR tmpDir[MAX_PATH]; WCHAR tmpName[MAX_PATH]; + HRESULT hr; if (!GetTempPathW(MAX_PATH, tmpDir)) { @@ -233,10 +244,30 @@ BOOL processFile(BackgroundCopyFileImpl *file, BackgroundCopyJobImpl *job) debugstr_w(file->info.LocalName)); transitionJobState(job, BG_JOB_STATE_QUEUED, BG_JOB_STATE_TRANSFERRING); - if (!CopyFileExW(file->info.RemoteName, tmpName, copyProgressCallback, - file, NULL, 0)) + + DeleteUrlCacheEntryW(file->info.RemoteName); + hr = URLDownloadToFileW(NULL, file->info.RemoteName, tmpName, 0, NULL); + if (SUCCEEDED(hr)) { - ERR("Local file copy failed: error %d\n", GetLastError()); + FIXME("Do progress updates correctly with IBindStatusCallback\n"); + EnterCriticalSection(&job->cs); + file->fileProgress.BytesTotal = 0; + LeaveCriticalSection(&job->cs); + } + else if (hr == INET_E_DOWNLOAD_FAILURE) + { + TRACE("URLDownload failed, trying local file copy\n"); + if (!CopyFileExW(file->info.RemoteName, tmpName, copyProgressCallback, + file, NULL, 0)) + { + ERR("Local file copy failed: error %d\n", GetLastError()); + transitionJobState(job, BG_JOB_STATE_TRANSFERRING, BG_JOB_STATE_ERROR); + return FALSE; + } + } + else + { + ERR("URLDownload failed: eh 0x%08x\n", hr); transitionJobState(job, BG_JOB_STATE_TRANSFERRING, BG_JOB_STATE_ERROR); return FALSE; } diff --git a/dlls/qmgr/tests/job.c b/dlls/qmgr/tests/job.c index 726624abf22..971d885d092 100644 --- a/dlls/qmgr/tests/job.c +++ b/dlls/qmgr/tests/job.c @@ -377,6 +377,82 @@ static void test_CompleteLocal(void) ok(DeleteFileW(test_remotePathB), "DeleteFile\n"); } +/* Test a complete transfer for local files */ +static void test_CompleteLocalURL(void) +{ + static const WCHAR prot[] = {'f','i','l','e',':','/','/', 0}; + static const int timeout_sec = 30; + WCHAR *urlA, *urlB; + HRESULT hres; + BG_JOB_STATE state; + int i; + + DeleteFileW(test_localPathA); + DeleteFileW(test_localPathB); + makeFile(test_remotePathA, "This is a WINE test file for BITS\n"); + makeFile(test_remotePathB, "This is another WINE test file for BITS\n"); + + urlA = HeapAlloc(GetProcessHeap(), 0, + (7 + lstrlenW(test_remotePathA) + 1) * sizeof urlA[0]); + urlB = HeapAlloc(GetProcessHeap(), 0, + (7 + lstrlenW(test_remotePathB) + 1) * sizeof urlB[0]); + if (!urlA || !urlB) + { + skip("Unable to allocate memory for URLs\n"); + return; + } + + lstrcpyW(urlA, prot); + lstrcatW(urlA, test_remotePathA); + lstrcpyW(urlB, prot); + lstrcatW(urlB, test_remotePathB); + + hres = IBackgroundCopyJob_AddFile(test_job, urlA, test_localPathA); + if (hres != S_OK) + { + skip("Unable to add file to job\n"); + return; + } + + hres = IBackgroundCopyJob_AddFile(test_job, urlB, test_localPathB); + if (hres != S_OK) + { + skip("Unable to add file to job\n"); + return; + } + + hres = IBackgroundCopyJob_Resume(test_job); + ok(hres == S_OK, "IBackgroundCopyJob_Resume\n"); + + for (i = 0; i < timeout_sec; ++i) + { + hres = IBackgroundCopyJob_GetState(test_job, &state); + ok(hres == S_OK, "IBackgroundCopyJob_GetState\n"); + ok(state == BG_JOB_STATE_QUEUED || state == BG_JOB_STATE_CONNECTING + || state == BG_JOB_STATE_TRANSFERRING || state == BG_JOB_STATE_TRANSFERRED, + "Bad state: %d\n", state); + if (state == BG_JOB_STATE_TRANSFERRED) + break; + Sleep(1000); + } + + ok(i < timeout_sec, "BITS jobs timed out\n"); + hres = IBackgroundCopyJob_Complete(test_job); + ok(hres == S_OK, "IBackgroundCopyJob_Complete\n"); + hres = IBackgroundCopyJob_GetState(test_job, &state); + ok(hres == S_OK, "IBackgroundCopyJob_GetState\n"); + ok(state == BG_JOB_STATE_ACKNOWLEDGED, "Bad state: %d\n", state); + + compareFiles(test_remotePathA, test_localPathA); + compareFiles(test_remotePathB, test_localPathB); + + ok(DeleteFileW(test_remotePathA), "DeleteFile\n"); + ok(DeleteFileW(test_remotePathB), "DeleteFile\n"); + + HeapFree(GetProcessHeap(), 0, urlA); + HeapFree(GetProcessHeap(), 0, urlB); +} + typedef void (*test_t)(void); START_TEST(job) @@ -391,6 +467,7 @@ START_TEST(job) test_GetState, test_ResumeEmpty, test_CompleteLocal, + test_CompleteLocalURL, 0 }; const test_t *test;