[5/6] qmgr: Transfer files given by URL (including HTTP, etc).

Dan Hipschman dsh at linux.ucla.edu
Thu Mar 13 17:57:19 CDT 2008


This implements file transfers, where the remote file is given by URL, using
URLDownloadToFile.  This works with local files (test included) and HTTP (no
automated test yet, but verified manually), so BITS can now do true remote
background file downloads.  This patch doesn't implement progress updates
since it involves imlpementing an IBindStatusCallback object and is easily
broken off into another patch (the next one in fact).

---
 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 30c699b..0e609ac 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 ole32 advapi32 kernel32 urlmon wininet
 EXTRALIBS = -luuid
 
 C_SRCS = \
diff --git a/dlls/qmgr/file.c b/dlls/qmgr/file.c
index a874062..fea84ec 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 <stdarg.h>
+
+#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))
+    {
+        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("Local file copy failed: error %d\n", GetLastError());
+        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 726624a..971d885 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;



More information about the wine-patches mailing list