[QMGR] Sync with Wine Staging 1.7.47. CORE-9924
authorAmine Khaldi <amine.khaldi@reactos.org>
Mon, 20 Jul 2015 22:48:28 +0000 (22:48 +0000)
committerAmine Khaldi <amine.khaldi@reactos.org>
Mon, 20 Jul 2015 22:48:28 +0000 (22:48 +0000)
svn path=/trunk/; revision=68490

reactos/dll/win32/qmgr/CMakeLists.txt
reactos/dll/win32/qmgr/enum_files.c
reactos/dll/win32/qmgr/enum_jobs.c
reactos/dll/win32/qmgr/file.c
reactos/dll/win32/qmgr/job.c
reactos/dll/win32/qmgr/qmgr.c
reactos/dll/win32/qmgr/qmgr.h
reactos/dll/win32/qmgr/qmgr_local.idl
reactos/media/doc/README.WINE

index c1695c2..8d962e5 100644 (file)
@@ -25,7 +25,7 @@ set_source_files_properties(rsrc.rc PROPERTIES OBJECT_DEPENDS ${CMAKE_CURRENT_SO
 add_idl_headers(qmgr_idlheader qmgr_local.idl)
 set_module_type(qmgr win32dll)
 target_link_libraries(qmgr uuid wine)
 add_idl_headers(qmgr_idlheader qmgr_local.idl)
 set_module_type(qmgr win32dll)
 target_link_libraries(qmgr uuid wine)
-add_importlibs(qmgr ole32 wininet urlmon advapi32 msvcrt kernel32 ntdll)
+add_importlibs(qmgr winhttp ole32 advapi32 msvcrt kernel32 ntdll)
 add_pch(qmgr qmgr.h SOURCE)
 add_cd_file(TARGET qmgr DESTINATION reactos/system32 FOR all)
 add_dependencies(qmgr qmgr_idlheader)
 add_pch(qmgr qmgr.h SOURCE)
 add_cd_file(TARGET qmgr DESTINATION reactos/system32 FOR all)
 add_dependencies(qmgr qmgr_idlheader)
index c7648a7..8945370 100644 (file)
@@ -24,7 +24,7 @@ typedef struct
 {
     IEnumBackgroundCopyFiles IEnumBackgroundCopyFiles_iface;
     LONG ref;
 {
     IEnumBackgroundCopyFiles IEnumBackgroundCopyFiles_iface;
     LONG ref;
-    IBackgroundCopyFile **files;
+    IBackgroundCopyFile2 **files;
     ULONG numFiles;
     ULONG indexFiles;
 } EnumBackgroundCopyFilesImpl;
     ULONG numFiles;
     ULONG indexFiles;
 } EnumBackgroundCopyFilesImpl;
@@ -72,7 +72,7 @@ static ULONG WINAPI EnumBackgroundCopyFiles_Release(IEnumBackgroundCopyFiles *if
     if (ref == 0)
     {
         for(i = 0; i < This->numFiles; i++)
     if (ref == 0)
     {
         for(i = 0; i < This->numFiles; i++)
-            IBackgroundCopyFile_Release(This->files[i]);
+            IBackgroundCopyFile2_Release(This->files[i]);
         HeapFree(GetProcessHeap(), 0, This->files);
         HeapFree(GetProcessHeap(), 0, This);
     }
         HeapFree(GetProcessHeap(), 0, This->files);
         HeapFree(GetProcessHeap(), 0, This);
     }
@@ -87,7 +87,7 @@ static HRESULT WINAPI EnumBackgroundCopyFiles_Next(IEnumBackgroundCopyFiles *ifa
     EnumBackgroundCopyFilesImpl *This = impl_from_IEnumBackgroundCopyFiles(iface);
     ULONG fetched;
     ULONG i;
     EnumBackgroundCopyFilesImpl *This = impl_from_IEnumBackgroundCopyFiles(iface);
     ULONG fetched;
     ULONG i;
-    IBackgroundCopyFile *file;
+    IBackgroundCopyFile2 *file;
 
     TRACE("(%p)->(%d %p %p)\n", This, celt, rgelt, pceltFetched);
 
 
     TRACE("(%p)->(%d %p %p)\n", This, celt, rgelt, pceltFetched);
 
@@ -113,8 +113,8 @@ static HRESULT WINAPI EnumBackgroundCopyFiles_Next(IEnumBackgroundCopyFiles *ifa
     for (i = 0; i < fetched; i++)
     {
         file = This->files[This->indexFiles++];
     for (i = 0; i < fetched; i++)
     {
         file = This->files[This->indexFiles++];
-        IBackgroundCopyFile_AddRef(file);
-        rgelt[i] = file;
+        IBackgroundCopyFile2_AddRef(file);
+        rgelt[i] = (IBackgroundCopyFile *)file;
     }
 
     return fetched == celt ? S_OK : S_FALSE;
     }
 
     return fetched == celt ? S_OK : S_FALSE;
@@ -212,8 +212,8 @@ HRESULT EnumBackgroundCopyFilesConstructor(BackgroundCopyJobImpl *job, IEnumBack
     i = 0;
     LIST_FOR_EACH_ENTRY(file, &job->files, BackgroundCopyFileImpl, entryFromJob)
     {
     i = 0;
     LIST_FOR_EACH_ENTRY(file, &job->files, BackgroundCopyFileImpl, entryFromJob)
     {
-        IBackgroundCopyFile_AddRef(&file->IBackgroundCopyFile_iface);
-        This->files[i] = &file->IBackgroundCopyFile_iface;
+        IBackgroundCopyFile2_AddRef(&file->IBackgroundCopyFile2_iface);
+        This->files[i] = &file->IBackgroundCopyFile2_iface;
         ++i;
     }
     LeaveCriticalSection(&job->cs);
         ++i;
     }
     LeaveCriticalSection(&job->cs);
index 5dd5d3b..c942547 100644 (file)
@@ -24,7 +24,7 @@ typedef struct
 {
     IEnumBackgroundCopyJobs IEnumBackgroundCopyJobs_iface;
     LONG ref;
 {
     IEnumBackgroundCopyJobs IEnumBackgroundCopyJobs_iface;
     LONG ref;
-    IBackgroundCopyJob **jobs;
+    IBackgroundCopyJob3 **jobs;
     ULONG numJobs;
     ULONG indexJobs;
 } EnumBackgroundCopyJobsImpl;
     ULONG numJobs;
     ULONG indexJobs;
 } EnumBackgroundCopyJobsImpl;
@@ -72,7 +72,7 @@ static ULONG WINAPI EnumBackgroundCopyJobs_Release(IEnumBackgroundCopyJobs *ifac
 
     if (ref == 0) {
         for(i = 0; i < This->numJobs; i++)
 
     if (ref == 0) {
         for(i = 0; i < This->numJobs; i++)
-            IBackgroundCopyJob_Release(This->jobs[i]);
+            IBackgroundCopyJob3_Release(This->jobs[i]);
         HeapFree(GetProcessHeap(), 0, This->jobs);
         HeapFree(GetProcessHeap(), 0, This);
     }
         HeapFree(GetProcessHeap(), 0, This->jobs);
         HeapFree(GetProcessHeap(), 0, This);
     }
@@ -86,7 +86,7 @@ static HRESULT WINAPI EnumBackgroundCopyJobs_Next(IEnumBackgroundCopyJobs *iface
     EnumBackgroundCopyJobsImpl *This = impl_from_IEnumBackgroundCopyJobs(iface);
     ULONG fetched;
     ULONG i;
     EnumBackgroundCopyJobsImpl *This = impl_from_IEnumBackgroundCopyJobs(iface);
     ULONG fetched;
     ULONG i;
-    IBackgroundCopyJob *job;
+    IBackgroundCopyJob3 *job;
 
     TRACE("(%p)->(%d %p %p)\n", This, celt, rgelt, pceltFetched);
 
 
     TRACE("(%p)->(%d %p %p)\n", This, celt, rgelt, pceltFetched);
 
@@ -109,8 +109,8 @@ static HRESULT WINAPI EnumBackgroundCopyJobs_Next(IEnumBackgroundCopyJobs *iface
     for (i = 0; i < fetched; ++i)
     {
         job = This->jobs[This->indexJobs++];
     for (i = 0; i < fetched; ++i)
     {
         job = This->jobs[This->indexJobs++];
-        IBackgroundCopyJob_AddRef(job);
-        rgelt[i] = job;
+        IBackgroundCopyJob3_AddRef(job);
+        rgelt[i] = (IBackgroundCopyJob *)job;
     }
 
     return fetched == celt ? S_OK : S_FALSE;
     }
 
     return fetched == celt ? S_OK : S_FALSE;
@@ -210,9 +210,8 @@ HRESULT enum_copy_job_create(BackgroundCopyManagerImpl *qmgr, IEnumBackgroundCop
     i = 0;
     LIST_FOR_EACH_ENTRY(job, &qmgr->jobs, BackgroundCopyJobImpl, entryFromQmgr)
     {
     i = 0;
     LIST_FOR_EACH_ENTRY(job, &qmgr->jobs, BackgroundCopyJobImpl, entryFromQmgr)
     {
-        IBackgroundCopyJob *job_iface = (IBackgroundCopyJob*)&job->IBackgroundCopyJob2_iface;
-        IBackgroundCopyJob_AddRef(job_iface);
-        This->jobs[i++] = job_iface;
+        IBackgroundCopyJob3_AddRef(&job->IBackgroundCopyJob3_iface);
+        This->jobs[i++] = &job->IBackgroundCopyJob3_iface;
     }
     LeaveCriticalSection(&qmgr->cs);
 
     }
     LeaveCriticalSection(&qmgr->cs);
 
index 1aee9b8..cb4c3a4 100644 (file)
 #include "qmgr.h"
 
 #include <urlmon.h>
 #include "qmgr.h"
 
 #include <urlmon.h>
-#include <wininet.h>
+#include <winhttp.h>
 
 
-static inline BackgroundCopyFileImpl *impl_from_IBackgroundCopyFile(IBackgroundCopyFile *iface)
+static inline BackgroundCopyFileImpl *impl_from_IBackgroundCopyFile2(
+    IBackgroundCopyFile2 *iface)
 {
 {
-    return CONTAINING_RECORD(iface, BackgroundCopyFileImpl, IBackgroundCopyFile_iface);
+    return CONTAINING_RECORD(iface, BackgroundCopyFileImpl, IBackgroundCopyFile2_iface);
 }
 
 static HRESULT WINAPI BackgroundCopyFile_QueryInterface(
 }
 
 static HRESULT WINAPI BackgroundCopyFile_QueryInterface(
-    IBackgroundCopyFileiface,
+    IBackgroundCopyFile2 *iface,
     REFIID riid,
     void **obj)
 {
     REFIID riid,
     void **obj)
 {
-    BackgroundCopyFileImpl *This = impl_from_IBackgroundCopyFile(iface);
+    BackgroundCopyFileImpl *file = impl_from_IBackgroundCopyFile2(iface);
 
 
-    TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
+    TRACE("(%p)->(%s %p)\n", file, debugstr_guid(riid), obj);
 
 
-    if (IsEqualGUID(riid, &IID_IUnknown)
-        || IsEqualGUID(riid, &IID_IBackgroundCopyFile))
+    if (IsEqualGUID(riid, &IID_IUnknown) ||
+        IsEqualGUID(riid, &IID_IBackgroundCopyFile) ||
+        IsEqualGUID(riid, &IID_IBackgroundCopyFile2))
     {
         *obj = iface;
     {
         *obj = iface;
-        IBackgroundCopyFile_AddRef(iface);
-        return S_OK;
+    }
+    else
+    {
+        *obj = NULL;
+        return E_NOINTERFACE;
     }
 
     }
 
-    *obj = NULL;
-    return E_NOINTERFACE;
+    IBackgroundCopyFile2_AddRef(iface);
+    return S_OK;
 }
 
 }
 
-static ULONG WINAPI BackgroundCopyFile_AddRef(IBackgroundCopyFile* iface)
+static ULONG WINAPI BackgroundCopyFile_AddRef(
+    IBackgroundCopyFile2 *iface)
 {
 {
-    BackgroundCopyFileImpl *This = impl_from_IBackgroundCopyFile(iface);
-    ULONG ref = InterlockedIncrement(&This->ref);
-    TRACE("(%p)->(%d)\n", This, ref);
+    BackgroundCopyFileImpl *file = impl_from_IBackgroundCopyFile2(iface);
+    ULONG ref = InterlockedIncrement(&file->ref);
+    TRACE("(%p)->(%d)\n", file, ref);
     return ref;
 }
 
 static ULONG WINAPI BackgroundCopyFile_Release(
     return ref;
 }
 
 static ULONG WINAPI BackgroundCopyFile_Release(
-    IBackgroundCopyFileiface)
+    IBackgroundCopyFile2 *iface)
 {
 {
-    BackgroundCopyFileImpl *This = impl_from_IBackgroundCopyFile(iface);
-    ULONG ref = InterlockedDecrement(&This->ref);
+    BackgroundCopyFileImpl *file = impl_from_IBackgroundCopyFile2(iface);
+    ULONG ref = InterlockedDecrement(&file->ref);
 
 
-    TRACE("(%p)->(%d)\n", This, ref);
+    TRACE("(%p)->(%d)\n", file, ref);
 
     if (ref == 0)
     {
 
     if (ref == 0)
     {
-        IBackgroundCopyJob2_Release(&This->owner->IBackgroundCopyJob2_iface);
-        HeapFree(GetProcessHeap(), 0, This->info.LocalName);
-        HeapFree(GetProcessHeap(), 0, This->info.RemoteName);
-        HeapFree(GetProcessHeap(), 0, This);
+        IBackgroundCopyJob3_Release(&file->owner->IBackgroundCopyJob3_iface);
+        HeapFree(GetProcessHeap(), 0, file->info.LocalName);
+        HeapFree(GetProcessHeap(), 0, file->info.RemoteName);
+        HeapFree(GetProcessHeap(), 0, file);
     }
 
     return ref;
     }
 
     return ref;
@@ -78,52 +84,71 @@ static ULONG WINAPI BackgroundCopyFile_Release(
 
 /* Get the remote name of a background copy file */
 static HRESULT WINAPI BackgroundCopyFile_GetRemoteName(
 
 /* Get the remote name of a background copy file */
 static HRESULT WINAPI BackgroundCopyFile_GetRemoteName(
-    IBackgroundCopyFileiface,
+    IBackgroundCopyFile2 *iface,
     LPWSTR *pVal)
 {
     LPWSTR *pVal)
 {
-    BackgroundCopyFileImpl *This = impl_from_IBackgroundCopyFile(iface);
+    BackgroundCopyFileImpl *file = impl_from_IBackgroundCopyFile2(iface);
 
 
-    TRACE("(%p)->(%p)\n", This, pVal);
+    TRACE("(%p)->(%p)\n", file, pVal);
 
 
-    return return_strval(This->info.RemoteName, pVal);
+    return return_strval(file->info.RemoteName, pVal);
 }
 
 static HRESULT WINAPI BackgroundCopyFile_GetLocalName(
 }
 
 static HRESULT WINAPI BackgroundCopyFile_GetLocalName(
-    IBackgroundCopyFileiface,
+    IBackgroundCopyFile2 *iface,
     LPWSTR *pVal)
 {
     LPWSTR *pVal)
 {
-    BackgroundCopyFileImpl *This = impl_from_IBackgroundCopyFile(iface);
+    BackgroundCopyFileImpl *file = impl_from_IBackgroundCopyFile2(iface);
 
 
-    TRACE("(%p)->(%p)\n", This, pVal);
+    TRACE("(%p)->(%p)\n", file, pVal);
 
 
-    return return_strval(This->info.LocalName, pVal);
+    return return_strval(file->info.LocalName, pVal);
 }
 
 static HRESULT WINAPI BackgroundCopyFile_GetProgress(
 }
 
 static HRESULT WINAPI BackgroundCopyFile_GetProgress(
-    IBackgroundCopyFileiface,
+    IBackgroundCopyFile2 *iface,
     BG_FILE_PROGRESS *pVal)
 {
     BG_FILE_PROGRESS *pVal)
 {
-    BackgroundCopyFileImpl *This = impl_from_IBackgroundCopyFile(iface);
+    BackgroundCopyFileImpl *file = impl_from_IBackgroundCopyFile2(iface);
 
 
-    TRACE("(%p)->(%p)\n", This, pVal);
+    TRACE("(%p)->(%p)\n", file, pVal);
 
 
-    EnterCriticalSection(&This->owner->cs);
-    pVal->BytesTotal = This->fileProgress.BytesTotal;
-    pVal->BytesTransferred = This->fileProgress.BytesTransferred;
-    pVal->Completed = This->fileProgress.Completed;
-    LeaveCriticalSection(&This->owner->cs);
+    EnterCriticalSection(&file->owner->cs);
+    *pVal = file->fileProgress;
+    LeaveCriticalSection(&file->owner->cs);
 
     return S_OK;
 }
 
 
     return S_OK;
 }
 
-static const IBackgroundCopyFileVtbl BackgroundCopyFileVtbl =
+static HRESULT WINAPI BackgroundCopyFile_GetFileRanges(
+    IBackgroundCopyFile2 *iface,
+    DWORD *RangeCount,
+    BG_FILE_RANGE **Ranges)
+{
+    BackgroundCopyFileImpl *file = impl_from_IBackgroundCopyFile2(iface);
+    FIXME("(%p)->(%p %p)\n", file, RangeCount, Ranges);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI BackgroundCopyFile_SetRemoteName(
+    IBackgroundCopyFile2 *iface,
+    LPCWSTR Val)
+{
+    BackgroundCopyFileImpl *file = impl_from_IBackgroundCopyFile2(iface);
+    FIXME("(%p)->(%s)\n", file, debugstr_w(Val));
+    return E_NOTIMPL;
+}
+
+static const IBackgroundCopyFile2Vtbl BackgroundCopyFile2Vtbl =
 {
     BackgroundCopyFile_QueryInterface,
     BackgroundCopyFile_AddRef,
     BackgroundCopyFile_Release,
     BackgroundCopyFile_GetRemoteName,
     BackgroundCopyFile_GetLocalName,
 {
     BackgroundCopyFile_QueryInterface,
     BackgroundCopyFile_AddRef,
     BackgroundCopyFile_Release,
     BackgroundCopyFile_GetRemoteName,
     BackgroundCopyFile_GetLocalName,
-    BackgroundCopyFile_GetProgress
+    BackgroundCopyFile_GetProgress,
+    BackgroundCopyFile_GetFileRanges,
+    BackgroundCopyFile_SetRemoteName
 };
 
 HRESULT BackgroundCopyFileConstructor(BackgroundCopyJobImpl *owner,
 };
 
 HRESULT BackgroundCopyFileConstructor(BackgroundCopyJobImpl *owner,
@@ -131,7 +156,6 @@ HRESULT BackgroundCopyFileConstructor(BackgroundCopyJobImpl *owner,
                                       BackgroundCopyFileImpl **file)
 {
     BackgroundCopyFileImpl *This;
                                       BackgroundCopyFileImpl **file)
 {
     BackgroundCopyFileImpl *This;
-    int n;
 
     TRACE("(%s, %s, %p)\n", debugstr_w(remoteName), debugstr_w(localName), file);
 
 
     TRACE("(%s, %s, %p)\n", debugstr_w(remoteName), debugstr_w(localName), file);
 
@@ -139,233 +163,314 @@ HRESULT BackgroundCopyFileConstructor(BackgroundCopyJobImpl *owner,
     if (!This)
         return E_OUTOFMEMORY;
 
     if (!This)
         return E_OUTOFMEMORY;
 
-    n = (lstrlenW(remoteName) + 1) * sizeof(WCHAR);
-    This->info.RemoteName = HeapAlloc(GetProcessHeap(), 0, n);
+    This->info.RemoteName = strdupW(remoteName);
     if (!This->info.RemoteName)
     {
         HeapFree(GetProcessHeap(), 0, This);
         return E_OUTOFMEMORY;
     }
     if (!This->info.RemoteName)
     {
         HeapFree(GetProcessHeap(), 0, This);
         return E_OUTOFMEMORY;
     }
-    memcpy(This->info.RemoteName, remoteName, n);
 
 
-    n = (lstrlenW(localName) + 1) * sizeof(WCHAR);
-    This->info.LocalName = HeapAlloc(GetProcessHeap(), 0, n);
+    This->info.LocalName = strdupW(localName);
     if (!This->info.LocalName)
     {
         HeapFree(GetProcessHeap(), 0, This->info.RemoteName);
         HeapFree(GetProcessHeap(), 0, This);
         return E_OUTOFMEMORY;
     }
     if (!This->info.LocalName)
     {
         HeapFree(GetProcessHeap(), 0, This->info.RemoteName);
         HeapFree(GetProcessHeap(), 0, This);
         return E_OUTOFMEMORY;
     }
-    memcpy(This->info.LocalName, localName, n);
 
 
-    This->IBackgroundCopyFile_iface.lpVtbl = &BackgroundCopyFileVtbl;
+    This->IBackgroundCopyFile2_iface.lpVtbl = &BackgroundCopyFile2Vtbl;
     This->ref = 1;
 
     This->fileProgress.BytesTotal = BG_SIZE_UNKNOWN;
     This->fileProgress.BytesTransferred = 0;
     This->fileProgress.Completed = FALSE;
     This->owner = owner;
     This->ref = 1;
 
     This->fileProgress.BytesTotal = BG_SIZE_UNKNOWN;
     This->fileProgress.BytesTransferred = 0;
     This->fileProgress.Completed = FALSE;
     This->owner = owner;
-    IBackgroundCopyJob2_AddRef(&owner->IBackgroundCopyJob2_iface);
+    This->read_size = 0;
+    This->tempFileName[0] = 0;
+    IBackgroundCopyJob3_AddRef(&owner->IBackgroundCopyJob3_iface);
 
     *file = This;
     return S_OK;
 }
 
 
     *file = This;
     return S_OK;
 }
 
-static DWORD CALLBACK copyProgressCallback(LARGE_INTEGER totalSize,
-                                           LARGE_INTEGER totalTransferred,
-                                           LARGE_INTEGER streamSize,
-                                           LARGE_INTEGER streamTransferred,
-                                           DWORD streamNum,
-                                           DWORD reason,
-                                           HANDLE srcFile,
-                                           HANDLE dstFile,
-                                           LPVOID obj)
+static HRESULT error_from_http_response(DWORD code)
 {
 {
-    BackgroundCopyFileImpl *file = obj;
-    BackgroundCopyJobImpl *job = file->owner;
-    ULONG64 diff;
-
-    EnterCriticalSection(&job->cs);
-    diff = (file->fileProgress.BytesTotal == BG_SIZE_UNKNOWN
-            ? totalTransferred.QuadPart
-            : totalTransferred.QuadPart - file->fileProgress.BytesTransferred);
-    file->fileProgress.BytesTotal = totalSize.QuadPart;
-    file->fileProgress.BytesTransferred = totalTransferred.QuadPart;
-    job->jobProgress.BytesTransferred += diff;
-    LeaveCriticalSection(&job->cs);
-
-    return (job->state == BG_JOB_STATE_TRANSFERRING
-            ? PROGRESS_CONTINUE
-            : PROGRESS_CANCEL);
+    switch (code)
+    {
+    case 200: return S_OK;
+    case 400: return BG_E_HTTP_ERROR_400;
+    case 401: return BG_E_HTTP_ERROR_401;
+    case 404: return BG_E_HTTP_ERROR_404;
+    case 407: return BG_E_HTTP_ERROR_407;
+    case 414: return BG_E_HTTP_ERROR_414;
+    case 501: return BG_E_HTTP_ERROR_501;
+    case 503: return BG_E_HTTP_ERROR_503;
+    case 504: return BG_E_HTTP_ERROR_504;
+    case 505: return BG_E_HTTP_ERROR_505;
+    default:
+        FIXME("unhandled response code %u\n", code);
+        return S_OK;
+    }
 }
 
 }
 
-typedef struct
+static void CALLBACK progress_callback_http(HINTERNET handle, DWORD_PTR context, DWORD status,
+                                            LPVOID buf, DWORD buflen)
 {
 {
-    IBindStatusCallback IBindStatusCallback_iface;
-    BackgroundCopyFileImpl *file;
-    LONG ref;
-} DLBindStatusCallback;
+    BackgroundCopyFileImpl *file = (BackgroundCopyFileImpl *)context;
+    BackgroundCopyJobImpl *job = file->owner;
 
 
-static inline DLBindStatusCallback *impl_from_IBindStatusCallback(IBindStatusCallback *iface)
-{
-    return CONTAINING_RECORD(iface, DLBindStatusCallback, IBindStatusCallback_iface);
-}
+    TRACE("%p, %p, %x, %p, %u\n", handle, file, status, buf, buflen);
 
 
-static HRESULT WINAPI DLBindStatusCallback_QueryInterface(
-    IBindStatusCallback *iface,
-    REFIID riid,
-    void **ppvObject)
-{
-    DLBindStatusCallback *This = impl_from_IBindStatusCallback(iface);
+    switch (status)
+    {
+    case WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE:
+    {
+        DWORD code, len, size;
 
 
-    if (IsEqualGUID(riid, &IID_IUnknown)
-        || IsEqualGUID(riid, &IID_IBindStatusCallback))
+        size = sizeof(code);
+        if (WinHttpQueryHeaders(handle, WINHTTP_QUERY_STATUS_CODE|WINHTTP_QUERY_FLAG_NUMBER,
+                                NULL, &code, &size, NULL))
+        {
+            if ((job->error.code = error_from_http_response(code)))
+            {
+                EnterCriticalSection(&job->cs);
+
+                job->error.context = BG_ERROR_CONTEXT_REMOTE_FILE;
+                if (job->error.file) IBackgroundCopyFile2_Release(job->error.file);
+                job->error.file = &file->IBackgroundCopyFile2_iface;
+                IBackgroundCopyFile2_AddRef(job->error.file);
+
+                LeaveCriticalSection(&job->cs);
+                transitionJobState(job, BG_JOB_STATE_TRANSFERRING, BG_JOB_STATE_ERROR);
+            }
+            else
+            {
+                EnterCriticalSection(&job->cs);
+
+                job->error.context = 0;
+                if (job->error.file)
+                {
+                    IBackgroundCopyFile2_Release(job->error.file);
+                    job->error.file = NULL;
+                }
+
+                LeaveCriticalSection(&job->cs);
+            }
+        }
+        size = sizeof(len);
+        if (WinHttpQueryHeaders(handle, WINHTTP_QUERY_CONTENT_LENGTH|WINHTTP_QUERY_FLAG_NUMBER,
+                                NULL, &len, &size, NULL))
+        {
+            file->fileProgress.BytesTotal = len;
+        }
+        break;
+    }
+    case WINHTTP_CALLBACK_STATUS_READ_COMPLETE:
     {
     {
-        *ppvObject = &This->IBindStatusCallback_iface;
-        IBindStatusCallback_AddRef(iface);
-        return S_OK;
+        file->read_size = buflen;
+        break;
+    }
+    case WINHTTP_CALLBACK_STATUS_REQUEST_ERROR:
+    {
+        WINHTTP_ASYNC_RESULT *result = (WINHTTP_ASYNC_RESULT *)buf;
+        job->error.code = result->dwError;
+        transitionJobState(job, BG_JOB_STATE_TRANSFERRING, BG_JOB_STATE_ERROR);
+        break;
+    }
+    default: break;
     }
 
     }
 
-    *ppvObject = NULL;
-    return E_NOINTERFACE;
-}
-
-static ULONG WINAPI DLBindStatusCallback_AddRef(IBindStatusCallback *iface)
-{
-    DLBindStatusCallback *This = impl_from_IBindStatusCallback(iface);
-    return InterlockedIncrement(&This->ref);
+    SetEvent(job->wait);
 }
 
 }
 
-static ULONG WINAPI DLBindStatusCallback_Release(IBindStatusCallback *iface)
+static DWORD wait_for_completion(BackgroundCopyJobImpl *job)
 {
 {
-    DLBindStatusCallback *This = impl_from_IBindStatusCallback(iface);
-    ULONG ref = InterlockedDecrement(&This->ref);
+    HANDLE handles[2] = {job->wait, job->cancel};
+    DWORD error = ERROR_SUCCESS;
 
 
-    if (ref == 0)
+    switch (WaitForMultipleObjects(2, handles, FALSE, INFINITE))
     {
     {
-        IBackgroundCopyFile_Release(&This->file->IBackgroundCopyFile_iface);
-        HeapFree(GetProcessHeap(), 0, This);
+    case WAIT_OBJECT_0:
+        break;
+
+    case WAIT_OBJECT_0 + 1:
+        error = ERROR_CANCELLED;
+        transitionJobState(job, BG_JOB_STATE_TRANSFERRING, BG_JOB_STATE_CANCELLED);
+        break;
+
+    default:
+        error = GetLastError();
+        transitionJobState(job, BG_JOB_STATE_TRANSFERRING, BG_JOB_STATE_ERROR);
+        break;
     }
 
     }
 
-    return ref;
+    return error;
 }
 
 }
 
-static HRESULT WINAPI DLBindStatusCallback_GetBindInfo(
-    IBindStatusCallback *iface,
-    DWORD *grfBINDF,
-    BINDINFO *pbindinfo)
+static UINT target_from_index(UINT index)
 {
 {
-    return E_NOTIMPL;
+    switch (index)
+    {
+    case 0: return WINHTTP_AUTH_TARGET_SERVER;
+    case 1: return WINHTTP_AUTH_TARGET_PROXY;
+    default:
+        ERR("unhandled index %u\n", index);
+        break;
+    }
+    return 0;
 }
 
 }
 
-static HRESULT WINAPI DLBindStatusCallback_GetPriority(
-    IBindStatusCallback *iface,
-    LONG *pnPriority)
+static UINT scheme_from_index(UINT index)
 {
 {
-    return E_NOTIMPL;
+    switch (index)
+    {
+    case 0: return WINHTTP_AUTH_SCHEME_BASIC;
+    case 1: return WINHTTP_AUTH_SCHEME_NTLM;
+    case 2: return WINHTTP_AUTH_SCHEME_PASSPORT;
+    case 3: return WINHTTP_AUTH_SCHEME_DIGEST;
+    case 4: return WINHTTP_AUTH_SCHEME_NEGOTIATE;
+    default:
+        ERR("unhandled index %u\n", index);
+        break;
+    }
+    return 0;
 }
 
 }
 
-static HRESULT WINAPI DLBindStatusCallback_OnDataAvailable(
-    IBindStatusCallback *iface,
-    DWORD grfBSCF,
-    DWORD dwSize,
-    FORMATETC *pformatetc,
-    STGMEDIUM *pstgmed)
+static BOOL set_request_credentials(HINTERNET req, BackgroundCopyJobImpl *job)
 {
 {
-    return E_NOTIMPL;
-}
+    UINT i, j;
 
 
-static HRESULT WINAPI DLBindStatusCallback_OnLowResource(
-    IBindStatusCallback *iface,
-    DWORD reserved)
-{
-    return E_NOTIMPL;
+    for (i = 0; i < BG_AUTH_TARGET_PROXY; i++)
+    {
+        UINT target = target_from_index(i);
+        for (j = 0; j < BG_AUTH_SCHEME_PASSPORT; j++)
+        {
+            UINT scheme = scheme_from_index(j);
+            const WCHAR *username = job->http_options.creds[i][j].Credentials.Basic.UserName;
+            const WCHAR *password = job->http_options.creds[i][j].Credentials.Basic.Password;
+
+            if (!username) continue;
+            if (!WinHttpSetCredentials(req, target, scheme, username, password, NULL)) return FALSE;
+        }
+    }
+    return TRUE;
 }
 
 }
 
-static HRESULT WINAPI DLBindStatusCallback_OnObjectAvailable(
-    IBindStatusCallback *iface,
-    REFIID riid,
-    IUnknown *punk)
+static BOOL transfer_file_http(BackgroundCopyFileImpl *file, URL_COMPONENTSW *uc,
+                               const WCHAR *tmpfile)
 {
 {
-    return E_NOTIMPL;
+    BackgroundCopyJobImpl *job = file->owner;
+    HANDLE handle;
+    HINTERNET ses, con = NULL, req = NULL;
+    DWORD flags = (uc->nScheme == INTERNET_SCHEME_HTTPS) ? WINHTTP_FLAG_SECURE : 0;
+    char buf[4096];
+    BOOL ret = FALSE;
+
+    transitionJobState(job, BG_JOB_STATE_QUEUED, BG_JOB_STATE_CONNECTING);
+
+    if (!(ses = WinHttpOpen(NULL, 0, NULL, NULL, WINHTTP_FLAG_ASYNC))) return FALSE;
+    WinHttpSetStatusCallback(ses, progress_callback_http, WINHTTP_CALLBACK_FLAG_ALL_COMPLETIONS, 0);
+    if (!WinHttpSetOption(ses, WINHTTP_OPTION_CONTEXT_VALUE, &file, sizeof(file))) goto done;
+
+    if (!(con = WinHttpConnect(ses, uc->lpszHostName, uc->nPort, 0))) goto done;
+    if (!(req = WinHttpOpenRequest(con, NULL, uc->lpszUrlPath, NULL, NULL, NULL, flags))) goto done;
+    if (!set_request_credentials(req, job)) goto done;
+
+    if (!(WinHttpSendRequest(req, job->http_options.headers, ~0u, NULL, 0, 0, (DWORD_PTR)file))) goto done;
+    if (wait_for_completion(job) || job->error.code) goto done;
+
+    if (!(WinHttpReceiveResponse(req, NULL))) goto done;
+    if (wait_for_completion(job) || job->error.code) goto done;
+
+    transitionJobState(job, BG_JOB_STATE_CONNECTING, BG_JOB_STATE_TRANSFERRING);
+
+    handle = CreateFileW(tmpfile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+    if (handle == INVALID_HANDLE_VALUE) goto done;
+
+    for (;;)
+    {
+        file->read_size = 0;
+        if (!(ret = WinHttpReadData(req, buf, sizeof(buf), NULL))) break;
+        if (wait_for_completion(job) || job->error.code)
+        {
+            ret = FALSE;
+            break;
+        }
+        if (!file->read_size) break;
+        if (!(ret = WriteFile(handle, buf, file->read_size, NULL, NULL))) break;
+
+        EnterCriticalSection(&job->cs);
+        file->fileProgress.BytesTransferred += file->read_size;
+        job->jobProgress.BytesTransferred += file->read_size;
+        LeaveCriticalSection(&job->cs);
+    }
+
+    CloseHandle(handle);
+
+done:
+    WinHttpCloseHandle(req);
+    WinHttpCloseHandle(con);
+    WinHttpCloseHandle(ses);
+    if (!ret) DeleteFileW(tmpfile);
+
+    SetEvent(job->done);
+    return ret;
 }
 
 }
 
-static HRESULT WINAPI DLBindStatusCallback_OnProgress(
-    IBindStatusCallback *iface,
-    ULONG progress,
-    ULONG progressMax,
-    ULONG statusCode,
-    LPCWSTR statusText)
+static DWORD CALLBACK progress_callback_local(LARGE_INTEGER totalSize, LARGE_INTEGER totalTransferred,
+                                              LARGE_INTEGER streamSize, LARGE_INTEGER streamTransferred,
+                                              DWORD streamNum, DWORD reason, HANDLE srcFile,
+                                              HANDLE dstFile, LPVOID obj)
 {
 {
-    DLBindStatusCallback *This = impl_from_IBindStatusCallback(iface);
-    BackgroundCopyFileImpl *file = This->file;
+    BackgroundCopyFileImpl *file = obj;
     BackgroundCopyJobImpl *job = file->owner;
     ULONG64 diff;
 
     EnterCriticalSection(&job->cs);
     diff = (file->fileProgress.BytesTotal == BG_SIZE_UNKNOWN
     BackgroundCopyJobImpl *job = file->owner;
     ULONG64 diff;
 
     EnterCriticalSection(&job->cs);
     diff = (file->fileProgress.BytesTotal == BG_SIZE_UNKNOWN
-            ? progress
-            : progress - file->fileProgress.BytesTransferred);
-    file->fileProgress.BytesTotal = progressMax ? progressMax : BG_SIZE_UNKNOWN;
-    file->fileProgress.BytesTransferred = progress;
+            ? totalTransferred.QuadPart
+            : totalTransferred.QuadPart - file->fileProgress.BytesTransferred);
+    file->fileProgress.BytesTotal = totalSize.QuadPart;
+    file->fileProgress.BytesTransferred = totalTransferred.QuadPart;
     job->jobProgress.BytesTransferred += diff;
     LeaveCriticalSection(&job->cs);
 
     job->jobProgress.BytesTransferred += diff;
     LeaveCriticalSection(&job->cs);
 
-    return S_OK;
+    return (job->state == BG_JOB_STATE_TRANSFERRING
+            ? PROGRESS_CONTINUE
+            : PROGRESS_CANCEL);
 }
 
 }
 
-static HRESULT WINAPI DLBindStatusCallback_OnStartBinding(
-    IBindStatusCallback *iface,
-    DWORD dwReserved,
-    IBinding *pib)
+static BOOL transfer_file_local(BackgroundCopyFileImpl *file, const WCHAR *tmpname)
 {
 {
-    return E_NOTIMPL;
-}
+    static const WCHAR fileW[] = {'f','i','l','e',':','/','/',0};
+    BackgroundCopyJobImpl *job = file->owner;
+    const WCHAR *ptr;
+    BOOL ret;
 
 
-static HRESULT WINAPI DLBindStatusCallback_OnStopBinding(
-    IBindStatusCallback *iface,
-    HRESULT hresult,
-    LPCWSTR szError)
-{
-    return E_NOTIMPL;
-}
+    transitionJobState(job, BG_JOB_STATE_QUEUED, BG_JOB_STATE_TRANSFERRING);
 
 
-static const IBindStatusCallbackVtbl DLBindStatusCallback_Vtbl =
-{
-    DLBindStatusCallback_QueryInterface,
-    DLBindStatusCallback_AddRef,
-    DLBindStatusCallback_Release,
-    DLBindStatusCallback_OnStartBinding,
-    DLBindStatusCallback_GetPriority,
-    DLBindStatusCallback_OnLowResource,
-    DLBindStatusCallback_OnProgress,
-    DLBindStatusCallback_OnStopBinding,
-    DLBindStatusCallback_GetBindInfo,
-    DLBindStatusCallback_OnDataAvailable,
-    DLBindStatusCallback_OnObjectAvailable
-};
+    if (strlenW(file->info.RemoteName) > 7 && !memicmpW(file->info.RemoteName, fileW, 7))
+        ptr = file->info.RemoteName + 7;
+    else
+        ptr = file->info.RemoteName;
 
 
-static DLBindStatusCallback *DLBindStatusCallbackConstructor(
-    BackgroundCopyFileImpl *file)
-{
-    DLBindStatusCallback *This = HeapAlloc(GetProcessHeap(), 0, sizeof *This);
-    if (!This)
-        return NULL;
+    if (!(ret = CopyFileExW(ptr, tmpname, progress_callback_local, file, NULL, 0)))
+    {
+        WARN("Local file copy failed: error %u\n", GetLastError());
+        transitionJobState(job, BG_JOB_STATE_TRANSFERRING, BG_JOB_STATE_ERROR);
+    }
 
 
-    This->IBindStatusCallback_iface.lpVtbl = &DLBindStatusCallback_Vtbl;
-    IBackgroundCopyFile_AddRef(&file->IBackgroundCopyFile_iface);
-    This->file = file;
-    This->ref = 1;
-    return This;
+    SetEvent(job->done);
+    return ret;
 }
 
 BOOL processFile(BackgroundCopyFileImpl *file, BackgroundCopyJobImpl *job)
 {
     static const WCHAR prefix[] = {'B','I','T', 0};
 }
 
 BOOL processFile(BackgroundCopyFileImpl *file, BackgroundCopyJobImpl *job)
 {
     static const WCHAR prefix[] = {'B','I','T', 0};
-    DLBindStatusCallback *callbackObj;
-    WCHAR tmpDir[MAX_PATH];
-    WCHAR tmpName[MAX_PATH];
-    HRESULT hr;
+    WCHAR tmpDir[MAX_PATH], tmpName[MAX_PATH];
+    WCHAR host[MAX_PATH], path[MAX_PATH];
+    URL_COMPONENTSW uc;
+    BOOL ret;
 
     if (!GetTempPathW(MAX_PATH, tmpDir))
     {
 
     if (!GetTempPathW(MAX_PATH, tmpDir))
     {
@@ -383,14 +488,6 @@ BOOL processFile(BackgroundCopyFileImpl *file, BackgroundCopyJobImpl *job)
         return FALSE;
     }
 
         return FALSE;
     }
 
-    callbackObj = DLBindStatusCallbackConstructor(file);
-    if (!callbackObj)
-    {
-        ERR("Out of memory\n");
-        transitionJobState(job, BG_JOB_STATE_QUEUED, BG_JOB_STATE_TRANSIENT_ERROR);
-        return FALSE;
-    }
-
     EnterCriticalSection(&job->cs);
     file->fileProgress.BytesTotal = BG_SIZE_UNKNOWN;
     file->fileProgress.BytesTransferred = 0;
     EnterCriticalSection(&job->cs);
     file->fileProgress.BytesTotal = BG_SIZE_UNKNOWN;
     file->fileProgress.BytesTransferred = 0;
@@ -402,31 +499,35 @@ BOOL processFile(BackgroundCopyFileImpl *file, BackgroundCopyJobImpl *job)
           debugstr_w(tmpName),
           debugstr_w(file->info.LocalName));
 
           debugstr_w(tmpName),
           debugstr_w(file->info.LocalName));
 
-    transitionJobState(job, BG_JOB_STATE_QUEUED, BG_JOB_STATE_TRANSFERRING);
-
-    DeleteUrlCacheEntryW(file->info.RemoteName);
-    hr = URLDownloadToFileW(NULL, file->info.RemoteName, tmpName, 0,
-                            &callbackObj->IBindStatusCallback_iface);
-    IBindStatusCallback_Release(&callbackObj->IBindStatusCallback_iface);
-    if (hr == INET_E_DOWNLOAD_FAILURE)
+    uc.dwStructSize      = sizeof(uc);
+    uc.nScheme           = 0;
+    uc.lpszScheme        = NULL;
+    uc.dwSchemeLength    = 0;
+    uc.lpszUserName      = NULL;
+    uc.dwUserNameLength  = 0;
+    uc.lpszPassword      = NULL;
+    uc.dwPasswordLength  = 0;
+    uc.lpszHostName      = host;
+    uc.dwHostNameLength  = sizeof(host)/sizeof(host[0]);
+    uc.nPort             = 0;
+    uc.lpszUrlPath       = path;
+    uc.dwUrlPathLength   = sizeof(path)/sizeof(path[0]);
+    uc.lpszExtraInfo     = NULL;
+    uc.dwExtraInfoLength = 0;
+    ret = WinHttpCrackUrl(file->info.RemoteName, 0, 0, &uc);
+    if (!ret)
     {
     {
-        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;
-        }
+        TRACE("WinHttpCrackUrl failed, trying local file copy\n");
+        if (!transfer_file_local(file, tmpName)) return FALSE;
     }
     }
-    else if (FAILED(hr))
+    else if (!transfer_file_http(file, &uc, tmpName))
     {
     {
-        ERR("URLDownload failed: eh 0x%08x\n", hr);
-        transitionJobState(job, BG_JOB_STATE_TRANSFERRING, BG_JOB_STATE_ERROR);
+        WARN("HTTP transfer failed\n");
         return FALSE;
     }
 
         return FALSE;
     }
 
-    if (transitionJobState(job, BG_JOB_STATE_TRANSFERRING, BG_JOB_STATE_QUEUED))
+    if (transitionJobState(job, BG_JOB_STATE_CONNECTING, BG_JOB_STATE_QUEUED) ||
+        transitionJobState(job, BG_JOB_STATE_TRANSFERRING, BG_JOB_STATE_QUEUED))
     {
         lstrcpyW(file->tempFileName, tmpName);
 
     {
         lstrcpyW(file->tempFileName, tmpName);
 
index 911def7..a9351c7 100644 (file)
 
 #include "qmgr.h"
 
 
 #include "qmgr.h"
 
+BOOL transitionJobState(BackgroundCopyJobImpl *job, BG_JOB_STATE from, BG_JOB_STATE to)
+{
+    BOOL ret = FALSE;
+
+    EnterCriticalSection(&globalMgr.cs);
+    if (job->state == from)
+    {
+        job->state = to;
+        ret = TRUE;
+    }
+    LeaveCriticalSection(&globalMgr.cs);
+    return ret;
+}
+
+struct copy_error
+{
+    IBackgroundCopyError  IBackgroundCopyError_iface;
+    LONG                  refs;
+    BG_ERROR_CONTEXT      context;
+    HRESULT               code;
+    IBackgroundCopyFile2 *file;
+};
+
+static inline struct copy_error *impl_from_IBackgroundCopyError(IBackgroundCopyError *iface)
+{
+    return CONTAINING_RECORD(iface, struct copy_error, IBackgroundCopyError_iface);
+}
+
+static HRESULT WINAPI copy_error_QueryInterface(
+    IBackgroundCopyError *iface,
+    REFIID riid,
+    void **obj)
+{
+    struct copy_error *error = impl_from_IBackgroundCopyError(iface);
+
+    TRACE("(%p)->(%s %p)\n", error, debugstr_guid(riid), obj);
+
+    if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IBackgroundCopyError))
+    {
+        *obj = &error->IBackgroundCopyError_iface;
+    }
+    else
+    {
+        *obj = NULL;
+        WARN("interface %s not supported\n", debugstr_guid(riid));
+        return E_NOINTERFACE;
+    }
+
+    IBackgroundCopyError_AddRef(iface);
+    return S_OK;
+}
+
+static ULONG WINAPI copy_error_AddRef(
+    IBackgroundCopyError *iface)
+{
+    struct copy_error *error = impl_from_IBackgroundCopyError(iface);
+    LONG refs = InterlockedIncrement(&error->refs);
+    TRACE("(%p)->(%d)\n", error, refs);
+    return refs;
+}
+
+static ULONG WINAPI copy_error_Release(
+    IBackgroundCopyError *iface)
+{
+    struct copy_error *error = impl_from_IBackgroundCopyError(iface);
+    LONG refs = InterlockedDecrement(&error->refs);
+
+    TRACE("(%p)->(%d)\n", error, refs);
+
+    if (!refs)
+    {
+        if (error->file) IBackgroundCopyFile2_Release(error->file);
+        HeapFree(GetProcessHeap(), 0, error);
+    }
+    return refs;
+}
+
+static HRESULT WINAPI copy_error_GetError(
+    IBackgroundCopyError *iface,
+    BG_ERROR_CONTEXT *pContext,
+    HRESULT *pCode)
+{
+    struct copy_error *error = impl_from_IBackgroundCopyError(iface);
+
+    TRACE("(%p)->(%p %p)\n", error, pContext, pCode);
+
+    *pContext = error->context;
+    *pCode = error->code;
+
+    TRACE("returning context %u error code 0x%08x\n", error->context, error->code);
+    return S_OK;
+}
+
+static HRESULT WINAPI copy_error_GetFile(
+    IBackgroundCopyError *iface,
+    IBackgroundCopyFile **pVal)
+{
+    struct copy_error *error = impl_from_IBackgroundCopyError(iface);
+
+    TRACE("(%p)->(%p)\n", error, pVal);
+
+    if (error->file)
+    {
+        IBackgroundCopyFile2_AddRef(error->file);
+        *pVal = (IBackgroundCopyFile *)error->file;
+        return S_OK;
+    }
+    *pVal = NULL;
+    return BG_E_FILE_NOT_AVAILABLE;
+}
+
+static HRESULT WINAPI copy_error_GetErrorDescription(
+    IBackgroundCopyError *iface,
+    DWORD LanguageId,
+    LPWSTR *pErrorDescription)
+{
+    struct copy_error *error = impl_from_IBackgroundCopyError(iface);
+    FIXME("(%p)->(%p)\n", error, pErrorDescription);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI copy_error_GetErrorContextDescription(
+    IBackgroundCopyError *iface,
+    DWORD LanguageId,
+    LPWSTR *pContextDescription)
+{
+    struct copy_error *error = impl_from_IBackgroundCopyError(iface);
+    FIXME("(%p)->(%p)\n", error, pContextDescription);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI copy_error_GetProtocol(
+    IBackgroundCopyError *iface,
+    LPWSTR *pProtocol)
+{
+    struct copy_error *error = impl_from_IBackgroundCopyError(iface);
+    FIXME("(%p)->(%p)\n", error, pProtocol);
+    return E_NOTIMPL;
+}
+
+static const IBackgroundCopyErrorVtbl copy_error_vtbl =
+{
+    copy_error_QueryInterface,
+    copy_error_AddRef,
+    copy_error_Release,
+    copy_error_GetError,
+    copy_error_GetFile,
+    copy_error_GetErrorDescription,
+    copy_error_GetErrorContextDescription,
+    copy_error_GetProtocol
+};
+
+static HRESULT create_copy_error(
+    BG_ERROR_CONTEXT context,
+    HRESULT code,
+    IBackgroundCopyFile2 *file,
+    IBackgroundCopyError **obj)
+{
+    struct copy_error *error;
+
+    TRACE("context %u code %08x file %p\n", context, code, file);
+
+    if (!(error = HeapAlloc(GetProcessHeap(), 0, sizeof(*error) ))) return E_OUTOFMEMORY;
+    error->IBackgroundCopyError_iface.lpVtbl = &copy_error_vtbl;
+    error->refs    = 1;
+    error->context = context;
+    error->code    = code;
+    error->file    = file;
+    if (error->file) IBackgroundCopyFile2_AddRef(error->file);
+
+    *obj = &error->IBackgroundCopyError_iface;
+    TRACE("returning iface %p\n", *obj);
+    return S_OK;
+}
+
 static inline BOOL is_job_done(const BackgroundCopyJobImpl *job)
 {
     return job->state == BG_JOB_STATE_CANCELLED || job->state == BG_JOB_STATE_ACKNOWLEDGED;
 }
 
 static inline BOOL is_job_done(const BackgroundCopyJobImpl *job)
 {
     return job->state == BG_JOB_STATE_CANCELLED || job->state == BG_JOB_STATE_ACKNOWLEDGED;
 }
 
-static inline BackgroundCopyJobImpl *impl_from_IBackgroundCopyJob2(IBackgroundCopyJob2 *iface)
+static inline BackgroundCopyJobImpl *impl_from_IBackgroundCopyJob3(IBackgroundCopyJob3 *iface)
 {
 {
-    return CONTAINING_RECORD(iface, BackgroundCopyJobImpl, IBackgroundCopyJob2_iface);
+    return CONTAINING_RECORD(iface, BackgroundCopyJobImpl, IBackgroundCopyJob3_iface);
 }
 
 static HRESULT WINAPI BackgroundCopyJob_QueryInterface(
 }
 
 static HRESULT WINAPI BackgroundCopyJob_QueryInterface(
-    IBackgroundCopyJob2 *iface, REFIID riid, void **obj)
+    IBackgroundCopyJob3 *iface, REFIID riid, void **obj)
 {
 {
-    BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob2(iface);
+    BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob3(iface);
 
     TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
 
 
     TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
 
-    if (IsEqualGUID(riid, &IID_IUnknown)
-        || IsEqualGUID(riid, &IID_IBackgroundCopyJob)
-        || IsEqualGUID(riid, &IID_IBackgroundCopyJob2))
+    if (IsEqualGUID(riid, &IID_IUnknown) ||
+        IsEqualGUID(riid, &IID_IBackgroundCopyJob) ||
+        IsEqualGUID(riid, &IID_IBackgroundCopyJob2) ||
+        IsEqualGUID(riid, &IID_IBackgroundCopyJob3))
     {
     {
-        *obj = iface;
-        IBackgroundCopyJob2_AddRef(iface);
-        return S_OK;
+        *obj = &This->IBackgroundCopyJob3_iface;
+    }
+    else if (IsEqualGUID(riid, &IID_IBackgroundCopyJobHttpOptions))
+    {
+        *obj = &This->IBackgroundCopyJobHttpOptions_iface;
+    }
+    else
+    {
+        *obj = NULL;
+        return E_NOINTERFACE;
     }
 
     }
 
-    *obj = NULL;
-    return E_NOINTERFACE;
+    IBackgroundCopyJob3_AddRef(iface);
+    return S_OK;
 }
 
 }
 
-static ULONG WINAPI BackgroundCopyJob_AddRef(IBackgroundCopyJob2 *iface)
+static ULONG WINAPI BackgroundCopyJob_AddRef(IBackgroundCopyJob3 *iface)
 {
 {
-    BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob2(iface);
+    BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob3(iface);
     ULONG ref = InterlockedIncrement(&This->ref);
     TRACE("(%p)->(%d)\n", This, ref);
     return ref;
 }
 
     ULONG ref = InterlockedIncrement(&This->ref);
     TRACE("(%p)->(%d)\n", This, ref);
     return ref;
 }
 
-static ULONG WINAPI BackgroundCopyJob_Release(IBackgroundCopyJob2 *iface)
+static ULONG WINAPI BackgroundCopyJob_Release(IBackgroundCopyJob3 *iface)
 {
 {
-    BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob2(iface);
-    ULONG ref = InterlockedDecrement(&This->ref);
+    BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob3(iface);
+    ULONG i, j, ref = InterlockedDecrement(&This->ref);
 
     TRACE("(%p)->(%d)\n", This, ref);
 
 
     TRACE("(%p)->(%d)\n", This, ref);
 
@@ -73,6 +256,19 @@ static ULONG WINAPI BackgroundCopyJob_Release(IBackgroundCopyJob2 *iface)
             IBackgroundCopyCallback2_Release(This->callback);
         HeapFree(GetProcessHeap(), 0, This->displayName);
         HeapFree(GetProcessHeap(), 0, This->description);
             IBackgroundCopyCallback2_Release(This->callback);
         HeapFree(GetProcessHeap(), 0, This->displayName);
         HeapFree(GetProcessHeap(), 0, This->description);
+        HeapFree(GetProcessHeap(), 0, This->http_options.headers);
+        for (i = 0; i < BG_AUTH_TARGET_PROXY; i++)
+        {
+            for (j = 0; j < BG_AUTH_SCHEME_PASSPORT; j++)
+            {
+                BG_AUTH_CREDENTIALS *cred = &This->http_options.creds[i][j];
+                HeapFree(GetProcessHeap(), 0, cred->Credentials.Basic.UserName);
+                HeapFree(GetProcessHeap(), 0, cred->Credentials.Basic.Password);
+            }
+        }
+        CloseHandle(This->wait);
+        CloseHandle(This->cancel);
+        CloseHandle(This->done);
         HeapFree(GetProcessHeap(), 0, This);
     }
 
         HeapFree(GetProcessHeap(), 0, This);
     }
 
@@ -82,11 +278,11 @@ static ULONG WINAPI BackgroundCopyJob_Release(IBackgroundCopyJob2 *iface)
 /*** IBackgroundCopyJob methods ***/
 
 static HRESULT WINAPI BackgroundCopyJob_AddFileSet(
 /*** IBackgroundCopyJob methods ***/
 
 static HRESULT WINAPI BackgroundCopyJob_AddFileSet(
-    IBackgroundCopyJob2 *iface,
+    IBackgroundCopyJob3 *iface,
     ULONG cFileCount,
     BG_FILE_INFO *pFileSet)
 {
     ULONG cFileCount,
     BG_FILE_INFO *pFileSet)
 {
-    BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob2(iface);
+    BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob3(iface);
     HRESULT hr = S_OK;
     ULONG i;
 
     HRESULT hr = S_OK;
     ULONG i;
 
@@ -116,41 +312,41 @@ static HRESULT WINAPI BackgroundCopyJob_AddFileSet(
 }
 
 static HRESULT WINAPI BackgroundCopyJob_AddFile(
 }
 
 static HRESULT WINAPI BackgroundCopyJob_AddFile(
-    IBackgroundCopyJob2 *iface,
+    IBackgroundCopyJob3 *iface,
     LPCWSTR RemoteUrl,
     LPCWSTR LocalName)
 {
     LPCWSTR RemoteUrl,
     LPCWSTR LocalName)
 {
-    BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob2(iface);
+    BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob3(iface);
     BG_FILE_INFO file;
 
     TRACE("(%p)->(%s %s)\n", This, debugstr_w(RemoteUrl), debugstr_w(LocalName));
 
     file.RemoteName = (LPWSTR)RemoteUrl;
     file.LocalName = (LPWSTR)LocalName;
     BG_FILE_INFO file;
 
     TRACE("(%p)->(%s %s)\n", This, debugstr_w(RemoteUrl), debugstr_w(LocalName));
 
     file.RemoteName = (LPWSTR)RemoteUrl;
     file.LocalName = (LPWSTR)LocalName;
-    return IBackgroundCopyJob2_AddFileSet(iface, 1, &file);
+    return IBackgroundCopyJob3_AddFileSet(iface, 1, &file);
 }
 
 static HRESULT WINAPI BackgroundCopyJob_EnumFiles(
 }
 
 static HRESULT WINAPI BackgroundCopyJob_EnumFiles(
-    IBackgroundCopyJob2 *iface,
+    IBackgroundCopyJob3 *iface,
     IEnumBackgroundCopyFiles **enum_files)
 {
     IEnumBackgroundCopyFiles **enum_files)
 {
-    BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob2(iface);
+    BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob3(iface);
     TRACE("(%p)->(%p)\n", This, enum_files);
     return EnumBackgroundCopyFilesConstructor(This, enum_files);
 }
 
 static HRESULT WINAPI BackgroundCopyJob_Suspend(
     TRACE("(%p)->(%p)\n", This, enum_files);
     return EnumBackgroundCopyFilesConstructor(This, enum_files);
 }
 
 static HRESULT WINAPI BackgroundCopyJob_Suspend(
-    IBackgroundCopyJob2 *iface)
+    IBackgroundCopyJob3 *iface)
 {
 {
-    BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob2(iface);
+    BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob3(iface);
     FIXME("(%p): stub\n", This);
     return E_NOTIMPL;
 }
 
 static HRESULT WINAPI BackgroundCopyJob_Resume(
     FIXME("(%p): stub\n", This);
     return E_NOTIMPL;
 }
 
 static HRESULT WINAPI BackgroundCopyJob_Resume(
-    IBackgroundCopyJob2 *iface)
+    IBackgroundCopyJob3 *iface)
 {
 {
-    BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob2(iface);
+    BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob3(iface);
     HRESULT rv = S_OK;
 
     TRACE("(%p)\n", This);
     HRESULT rv = S_OK;
 
     TRACE("(%p)\n", This);
@@ -176,17 +372,57 @@ static HRESULT WINAPI BackgroundCopyJob_Resume(
 }
 
 static HRESULT WINAPI BackgroundCopyJob_Cancel(
 }
 
 static HRESULT WINAPI BackgroundCopyJob_Cancel(
-    IBackgroundCopyJob2 *iface)
+    IBackgroundCopyJob3 *iface)
 {
 {
-    BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob2(iface);
-    FIXME("(%p): stub\n", This);
-    return E_NOTIMPL;
+    BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob3(iface);
+    HRESULT rv = S_OK;
+
+    TRACE("(%p)\n", This);
+
+    EnterCriticalSection(&This->cs);
+
+    if (is_job_done(This))
+    {
+        rv = BG_E_INVALID_STATE;
+    }
+    else
+    {
+        BackgroundCopyFileImpl *file;
+
+        if (This->state == BG_JOB_STATE_CONNECTING || This->state == BG_JOB_STATE_TRANSFERRING)
+        {
+            This->state = BG_JOB_STATE_CANCELLED;
+            SetEvent(This->cancel);
+
+            LeaveCriticalSection(&This->cs);
+            WaitForSingleObject(This->done, INFINITE);
+            EnterCriticalSection(&This->cs);
+        }
+
+        LIST_FOR_EACH_ENTRY(file, &This->files, BackgroundCopyFileImpl, entryFromJob)
+        {
+            if (file->tempFileName[0] && !DeleteFileW(file->tempFileName))
+            {
+                WARN("Couldn't delete %s (%u)\n", debugstr_w(file->tempFileName), GetLastError());
+                rv = BG_S_UNABLE_TO_DELETE_FILES;
+            }
+            if (file->info.LocalName && !DeleteFileW(file->info.LocalName))
+            {
+                WARN("Couldn't delete %s (%u)\n", debugstr_w(file->info.LocalName), GetLastError());
+                rv = BG_S_UNABLE_TO_DELETE_FILES;
+            }
+        }
+        This->state = BG_JOB_STATE_CANCELLED;
+    }
+
+    LeaveCriticalSection(&This->cs);
+    return rv;
 }
 
 static HRESULT WINAPI BackgroundCopyJob_Complete(
 }
 
 static HRESULT WINAPI BackgroundCopyJob_Complete(
-    IBackgroundCopyJob2 *iface)
+    IBackgroundCopyJob3 *iface)
 {
 {
-    BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob2(iface);
+    BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob3(iface);
     HRESULT rv = S_OK;
 
     TRACE("(%p)\n", This);
     HRESULT rv = S_OK;
 
     TRACE("(%p)\n", This);
@@ -227,20 +463,20 @@ static HRESULT WINAPI BackgroundCopyJob_Complete(
 }
 
 static HRESULT WINAPI BackgroundCopyJob_GetId(
 }
 
 static HRESULT WINAPI BackgroundCopyJob_GetId(
-    IBackgroundCopyJob2 *iface,
+    IBackgroundCopyJob3 *iface,
     GUID *pVal)
 {
     GUID *pVal)
 {
-    BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob2(iface);
+    BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob3(iface);
     TRACE("(%p)->(%p)\n", This, pVal);
     *pVal = This->jobId;
     return S_OK;
 }
 
 static HRESULT WINAPI BackgroundCopyJob_GetType(
     TRACE("(%p)->(%p)\n", This, pVal);
     *pVal = This->jobId;
     return S_OK;
 }
 
 static HRESULT WINAPI BackgroundCopyJob_GetType(
-    IBackgroundCopyJob2 *iface,
+    IBackgroundCopyJob3 *iface,
     BG_JOB_TYPE *pVal)
 {
     BG_JOB_TYPE *pVal)
 {
-    BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob2(iface);
+    BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob3(iface);
 
     TRACE("(%p)->(%p)\n", This, pVal);
 
 
     TRACE("(%p)->(%p)\n", This, pVal);
 
@@ -252,10 +488,10 @@ static HRESULT WINAPI BackgroundCopyJob_GetType(
 }
 
 static HRESULT WINAPI BackgroundCopyJob_GetProgress(
 }
 
 static HRESULT WINAPI BackgroundCopyJob_GetProgress(
-    IBackgroundCopyJob2 *iface,
+    IBackgroundCopyJob3 *iface,
     BG_JOB_PROGRESS *pVal)
 {
     BG_JOB_PROGRESS *pVal)
 {
-    BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob2(iface);
+    BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob3(iface);
 
     TRACE("(%p)->(%p)\n", This, pVal);
 
 
     TRACE("(%p)->(%p)\n", This, pVal);
 
@@ -263,29 +499,26 @@ static HRESULT WINAPI BackgroundCopyJob_GetProgress(
         return E_INVALIDARG;
 
     EnterCriticalSection(&This->cs);
         return E_INVALIDARG;
 
     EnterCriticalSection(&This->cs);
-    pVal->BytesTotal = This->jobProgress.BytesTotal;
-    pVal->BytesTransferred = This->jobProgress.BytesTransferred;
-    pVal->FilesTotal = This->jobProgress.FilesTotal;
-    pVal->FilesTransferred = This->jobProgress.FilesTransferred;
+    *pVal = This->jobProgress;
     LeaveCriticalSection(&This->cs);
 
     return S_OK;
 }
 
 static HRESULT WINAPI BackgroundCopyJob_GetTimes(
     LeaveCriticalSection(&This->cs);
 
     return S_OK;
 }
 
 static HRESULT WINAPI BackgroundCopyJob_GetTimes(
-    IBackgroundCopyJob2 *iface,
+    IBackgroundCopyJob3 *iface,
     BG_JOB_TIMES *pVal)
 {
     BG_JOB_TIMES *pVal)
 {
-    BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob2(iface);
+    BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob3(iface);
     FIXME("(%p)->(%p): stub\n", This, pVal);
     return E_NOTIMPL;
 }
 
 static HRESULT WINAPI BackgroundCopyJob_GetState(
     FIXME("(%p)->(%p): stub\n", This, pVal);
     return E_NOTIMPL;
 }
 
 static HRESULT WINAPI BackgroundCopyJob_GetState(
-    IBackgroundCopyJob2 *iface,
+    IBackgroundCopyJob3 *iface,
     BG_JOB_STATE *pVal)
 {
     BG_JOB_STATE *pVal)
 {
-    BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob2(iface);
+    BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob3(iface);
 
     TRACE("(%p)->(%p)\n", This, pVal);
 
 
     TRACE("(%p)->(%p)\n", This, pVal);
 
@@ -298,37 +531,41 @@ static HRESULT WINAPI BackgroundCopyJob_GetState(
 }
 
 static HRESULT WINAPI BackgroundCopyJob_GetError(
 }
 
 static HRESULT WINAPI BackgroundCopyJob_GetError(
-    IBackgroundCopyJob2 *iface,
+    IBackgroundCopyJob3 *iface,
     IBackgroundCopyError **ppError)
 {
     IBackgroundCopyError **ppError)
 {
-    BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob2(iface);
-    FIXME("(%p)->(%p): stub\n", This, ppError);
-    return E_NOTIMPL;
+    BackgroundCopyJobImpl *job = impl_from_IBackgroundCopyJob3(iface);
+
+    TRACE("(%p)->(%p)\n", job, ppError);
+
+    if (!job->error.context) return BG_E_ERROR_INFORMATION_UNAVAILABLE;
+
+    return create_copy_error(job->error.context, job->error.code, job->error.file, ppError);
 }
 
 static HRESULT WINAPI BackgroundCopyJob_GetOwner(
 }
 
 static HRESULT WINAPI BackgroundCopyJob_GetOwner(
-    IBackgroundCopyJob2 *iface,
+    IBackgroundCopyJob3 *iface,
     LPWSTR *pVal)
 {
     LPWSTR *pVal)
 {
-    BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob2(iface);
+    BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob3(iface);
     FIXME("(%p)->(%p): stub\n", This, pVal);
     return E_NOTIMPL;
 }
 
 static HRESULT WINAPI BackgroundCopyJob_SetDisplayName(
     FIXME("(%p)->(%p): stub\n", This, pVal);
     return E_NOTIMPL;
 }
 
 static HRESULT WINAPI BackgroundCopyJob_SetDisplayName(
-    IBackgroundCopyJob2 *iface,
+    IBackgroundCopyJob3 *iface,
     LPCWSTR Val)
 {
     LPCWSTR Val)
 {
-    BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob2(iface);
+    BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob3(iface);
     FIXME("(%p)->(%s): stub\n", This, debugstr_w(Val));
     return E_NOTIMPL;
 }
 
 static HRESULT WINAPI BackgroundCopyJob_GetDisplayName(
     FIXME("(%p)->(%s): stub\n", This, debugstr_w(Val));
     return E_NOTIMPL;
 }
 
 static HRESULT WINAPI BackgroundCopyJob_GetDisplayName(
-    IBackgroundCopyJob2 *iface,
+    IBackgroundCopyJob3 *iface,
     LPWSTR *pVal)
 {
     LPWSTR *pVal)
 {
-    BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob2(iface);
+    BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob3(iface);
 
     TRACE("(%p)->(%p)\n", This, pVal);
 
 
     TRACE("(%p)->(%p)\n", This, pVal);
 
@@ -336,10 +573,10 @@ static HRESULT WINAPI BackgroundCopyJob_GetDisplayName(
 }
 
 static HRESULT WINAPI BackgroundCopyJob_SetDescription(
 }
 
 static HRESULT WINAPI BackgroundCopyJob_SetDescription(
-    IBackgroundCopyJob2 *iface,
+    IBackgroundCopyJob3 *iface,
     LPCWSTR Val)
 {
     LPCWSTR Val)
 {
-    BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob2(iface);
+    BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob3(iface);
     static const int max_description_len = 1024;
     HRESULT hr = S_OK;
     int len;
     static const int max_description_len = 1024;
     HRESULT hr = S_OK;
     int len;
@@ -372,10 +609,10 @@ static HRESULT WINAPI BackgroundCopyJob_SetDescription(
 }
 
 static HRESULT WINAPI BackgroundCopyJob_GetDescription(
 }
 
 static HRESULT WINAPI BackgroundCopyJob_GetDescription(
-    IBackgroundCopyJob2 *iface,
+    IBackgroundCopyJob3 *iface,
     LPWSTR *pVal)
 {
     LPWSTR *pVal)
 {
-    BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob2(iface);
+    BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob3(iface);
 
     TRACE("(%p)->(%p)\n", This, pVal);
 
 
     TRACE("(%p)->(%p)\n", This, pVal);
 
@@ -383,28 +620,28 @@ static HRESULT WINAPI BackgroundCopyJob_GetDescription(
 }
 
 static HRESULT WINAPI BackgroundCopyJob_SetPriority(
 }
 
 static HRESULT WINAPI BackgroundCopyJob_SetPriority(
-    IBackgroundCopyJob2 *iface,
+    IBackgroundCopyJob3 *iface,
     BG_JOB_PRIORITY Val)
 {
     BG_JOB_PRIORITY Val)
 {
-    BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob2(iface);
+    BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob3(iface);
     FIXME("(%p)->(%d): stub\n", This, Val);
     return S_OK;
 }
 
 static HRESULT WINAPI BackgroundCopyJob_GetPriority(
     FIXME("(%p)->(%d): stub\n", This, Val);
     return S_OK;
 }
 
 static HRESULT WINAPI BackgroundCopyJob_GetPriority(
-    IBackgroundCopyJob2 *iface,
+    IBackgroundCopyJob3 *iface,
     BG_JOB_PRIORITY *pVal)
 {
     BG_JOB_PRIORITY *pVal)
 {
-    BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob2(iface);
+    BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob3(iface);
     FIXME("(%p)->(%p): stub\n", This, pVal);
     return E_NOTIMPL;
 }
 
 static HRESULT WINAPI BackgroundCopyJob_SetNotifyFlags(
     FIXME("(%p)->(%p): stub\n", This, pVal);
     return E_NOTIMPL;
 }
 
 static HRESULT WINAPI BackgroundCopyJob_SetNotifyFlags(
-    IBackgroundCopyJob2 *iface,
+    IBackgroundCopyJob3 *iface,
     ULONG Val)
 {
     ULONG Val)
 {
-    BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob2(iface);
+    BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob3(iface);
     static const ULONG valid_flags = BG_NOTIFY_JOB_TRANSFERRED |
                                      BG_NOTIFY_JOB_ERROR |
                                      BG_NOTIFY_DISABLE |
     static const ULONG valid_flags = BG_NOTIFY_JOB_TRANSFERRED |
                                      BG_NOTIFY_JOB_ERROR |
                                      BG_NOTIFY_DISABLE |
@@ -420,10 +657,10 @@ static HRESULT WINAPI BackgroundCopyJob_SetNotifyFlags(
 }
 
 static HRESULT WINAPI BackgroundCopyJob_GetNotifyFlags(
 }
 
 static HRESULT WINAPI BackgroundCopyJob_GetNotifyFlags(
-    IBackgroundCopyJob2 *iface,
+    IBackgroundCopyJob3 *iface,
     ULONG *pVal)
 {
     ULONG *pVal)
 {
-    BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob2(iface);
+    BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob3(iface);
 
     TRACE("(%p)->(%p)\n", This, pVal);
 
 
     TRACE("(%p)->(%p)\n", This, pVal);
 
@@ -435,10 +672,10 @@ static HRESULT WINAPI BackgroundCopyJob_GetNotifyFlags(
 }
 
 static HRESULT WINAPI BackgroundCopyJob_SetNotifyInterface(
 }
 
 static HRESULT WINAPI BackgroundCopyJob_SetNotifyInterface(
-    IBackgroundCopyJob2 *iface,
+    IBackgroundCopyJob3 *iface,
     IUnknown *Val)
 {
     IUnknown *Val)
 {
-    BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob2(iface);
+    BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob3(iface);
     HRESULT hr = S_OK;
 
     TRACE("(%p)->(%p)\n", This, Val);
     HRESULT hr = S_OK;
 
     TRACE("(%p)->(%p)\n", This, Val);
@@ -465,10 +702,10 @@ static HRESULT WINAPI BackgroundCopyJob_SetNotifyInterface(
 }
 
 static HRESULT WINAPI BackgroundCopyJob_GetNotifyInterface(
 }
 
 static HRESULT WINAPI BackgroundCopyJob_GetNotifyInterface(
-    IBackgroundCopyJob2 *iface,
+    IBackgroundCopyJob3 *iface,
     IUnknown **pVal)
 {
     IUnknown **pVal)
 {
-    BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob2(iface);
+    BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob3(iface);
 
     TRACE("(%p)->(%p)\n", This, pVal);
 
 
     TRACE("(%p)->(%p)\n", This, pVal);
 
@@ -482,7 +719,7 @@ static HRESULT WINAPI BackgroundCopyJob_GetNotifyInterface(
 }
 
 static HRESULT WINAPI BackgroundCopyJob_SetMinimumRetryDelay(
 }
 
 static HRESULT WINAPI BackgroundCopyJob_SetMinimumRetryDelay(
-    IBackgroundCopyJob2 *iface,
+    IBackgroundCopyJob3 *iface,
     ULONG Seconds)
 {
     FIXME("%u\n", Seconds);
     ULONG Seconds)
 {
     FIXME("%u\n", Seconds);
@@ -490,150 +727,244 @@ static HRESULT WINAPI BackgroundCopyJob_SetMinimumRetryDelay(
 }
 
 static HRESULT WINAPI BackgroundCopyJob_GetMinimumRetryDelay(
 }
 
 static HRESULT WINAPI BackgroundCopyJob_GetMinimumRetryDelay(
-    IBackgroundCopyJob2 *iface,
+    IBackgroundCopyJob3 *iface,
     ULONG *Seconds)
 {
     ULONG *Seconds)
 {
-    BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob2(iface);
+    BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob3(iface);
     FIXME("(%p)->(%p): stub\n", This, Seconds);
     *Seconds = 30;
     return S_OK;
 }
 
 static HRESULT WINAPI BackgroundCopyJob_SetNoProgressTimeout(
     FIXME("(%p)->(%p): stub\n", This, Seconds);
     *Seconds = 30;
     return S_OK;
 }
 
 static HRESULT WINAPI BackgroundCopyJob_SetNoProgressTimeout(
-    IBackgroundCopyJob2 *iface,
+    IBackgroundCopyJob3 *iface,
     ULONG Seconds)
 {
     ULONG Seconds)
 {
-    BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob2(iface);
+    BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob3(iface);
     FIXME("(%p)->(%d): stub\n", This, Seconds);
     return S_OK;
 }
 
 static HRESULT WINAPI BackgroundCopyJob_GetNoProgressTimeout(
     FIXME("(%p)->(%d): stub\n", This, Seconds);
     return S_OK;
 }
 
 static HRESULT WINAPI BackgroundCopyJob_GetNoProgressTimeout(
-    IBackgroundCopyJob2 *iface,
+    IBackgroundCopyJob3 *iface,
     ULONG *Seconds)
 {
     ULONG *Seconds)
 {
-    BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob2(iface);
+    BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob3(iface);
     FIXME("(%p)->(%p): stub\n", This, Seconds);
     *Seconds = 900;
     return S_OK;
 }
 
 static HRESULT WINAPI BackgroundCopyJob_GetErrorCount(
     FIXME("(%p)->(%p): stub\n", This, Seconds);
     *Seconds = 900;
     return S_OK;
 }
 
 static HRESULT WINAPI BackgroundCopyJob_GetErrorCount(
-    IBackgroundCopyJob2 *iface,
+    IBackgroundCopyJob3 *iface,
     ULONG *Errors)
 {
     ULONG *Errors)
 {
-    BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob2(iface);
+    BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob3(iface);
     FIXME("(%p)->(%p): stub\n", This, Errors);
     return E_NOTIMPL;
 }
 
 static HRESULT WINAPI BackgroundCopyJob_SetProxySettings(
     FIXME("(%p)->(%p): stub\n", This, Errors);
     return E_NOTIMPL;
 }
 
 static HRESULT WINAPI BackgroundCopyJob_SetProxySettings(
-    IBackgroundCopyJob2 *iface,
+    IBackgroundCopyJob3 *iface,
     BG_JOB_PROXY_USAGE ProxyUsage,
     const WCHAR *ProxyList,
     const WCHAR *ProxyBypassList)
 {
     BG_JOB_PROXY_USAGE ProxyUsage,
     const WCHAR *ProxyList,
     const WCHAR *ProxyBypassList)
 {
-    BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob2(iface);
+    BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob3(iface);
     FIXME("(%p)->(%d %s %s): stub\n", This, ProxyUsage, debugstr_w(ProxyList), debugstr_w(ProxyBypassList));
     return E_NOTIMPL;
 }
 
 static HRESULT WINAPI BackgroundCopyJob_GetProxySettings(
     FIXME("(%p)->(%d %s %s): stub\n", This, ProxyUsage, debugstr_w(ProxyList), debugstr_w(ProxyBypassList));
     return E_NOTIMPL;
 }
 
 static HRESULT WINAPI BackgroundCopyJob_GetProxySettings(
-    IBackgroundCopyJob2 *iface,
+    IBackgroundCopyJob3 *iface,
     BG_JOB_PROXY_USAGE *pProxyUsage,
     LPWSTR *pProxyList,
     LPWSTR *pProxyBypassList)
 {
     BG_JOB_PROXY_USAGE *pProxyUsage,
     LPWSTR *pProxyList,
     LPWSTR *pProxyBypassList)
 {
-    BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob2(iface);
+    BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob3(iface);
     FIXME("(%p)->(%p %p %p): stub\n", This, pProxyUsage, pProxyList, pProxyBypassList);
     return E_NOTIMPL;
 }
 
 static HRESULT WINAPI BackgroundCopyJob_TakeOwnership(
     FIXME("(%p)->(%p %p %p): stub\n", This, pProxyUsage, pProxyList, pProxyBypassList);
     return E_NOTIMPL;
 }
 
 static HRESULT WINAPI BackgroundCopyJob_TakeOwnership(
-    IBackgroundCopyJob2 *iface)
+    IBackgroundCopyJob3 *iface)
 {
 {
-    BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob2(iface);
+    BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob3(iface);
     FIXME("(%p): stub\n", This);
     return E_NOTIMPL;
 }
 
 static HRESULT WINAPI BackgroundCopyJob_SetNotifyCmdLine(
     FIXME("(%p): stub\n", This);
     return E_NOTIMPL;
 }
 
 static HRESULT WINAPI BackgroundCopyJob_SetNotifyCmdLine(
-    IBackgroundCopyJob2 *iface,
+    IBackgroundCopyJob3 *iface,
     LPCWSTR prog,
     LPCWSTR params)
 {
     LPCWSTR prog,
     LPCWSTR params)
 {
-    BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob2(iface);
+    BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob3(iface);
     FIXME("(%p)->(%s %s): stub\n", This, debugstr_w(prog), debugstr_w(params));
     return E_NOTIMPL;
 }
 
 static HRESULT WINAPI BackgroundCopyJob_GetNotifyCmdLine(
     FIXME("(%p)->(%s %s): stub\n", This, debugstr_w(prog), debugstr_w(params));
     return E_NOTIMPL;
 }
 
 static HRESULT WINAPI BackgroundCopyJob_GetNotifyCmdLine(
-    IBackgroundCopyJob2 *iface,
+    IBackgroundCopyJob3 *iface,
     LPWSTR *prog,
     LPWSTR *params)
 {
     LPWSTR *prog,
     LPWSTR *params)
 {
-    BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob2(iface);
+    BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob3(iface);
     FIXME("(%p)->(%p %p): stub\n", This, prog, params);
     return E_NOTIMPL;
 }
 
 static HRESULT WINAPI BackgroundCopyJob_GetReplyProgress(
     FIXME("(%p)->(%p %p): stub\n", This, prog, params);
     return E_NOTIMPL;
 }
 
 static HRESULT WINAPI BackgroundCopyJob_GetReplyProgress(
-    IBackgroundCopyJob2 *iface,
+    IBackgroundCopyJob3 *iface,
     BG_JOB_REPLY_PROGRESS *progress)
 {
     BG_JOB_REPLY_PROGRESS *progress)
 {
-    BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob2(iface);
+    BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob3(iface);
     FIXME("(%p)->(%p): stub\n", This, progress);
     return E_NOTIMPL;
 }
 
 static HRESULT WINAPI BackgroundCopyJob_GetReplyData(
     FIXME("(%p)->(%p): stub\n", This, progress);
     return E_NOTIMPL;
 }
 
 static HRESULT WINAPI BackgroundCopyJob_GetReplyData(
-    IBackgroundCopyJob2 *iface,
+    IBackgroundCopyJob3 *iface,
     byte **pBuffer,
     UINT64 *pLength)
 {
     byte **pBuffer,
     UINT64 *pLength)
 {
-    BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob2(iface);
+    BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob3(iface);
     FIXME("(%p)->(%p %p): stub\n", This, pBuffer, pLength);
     return E_NOTIMPL;
 }
 
 static HRESULT WINAPI BackgroundCopyJob_SetReplyFileName(
     FIXME("(%p)->(%p %p): stub\n", This, pBuffer, pLength);
     return E_NOTIMPL;
 }
 
 static HRESULT WINAPI BackgroundCopyJob_SetReplyFileName(
-    IBackgroundCopyJob2 *iface,
+    IBackgroundCopyJob3 *iface,
     LPCWSTR filename)
 {
     LPCWSTR filename)
 {
-    BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob2(iface);
+    BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob3(iface);
     FIXME("(%p)->(%s): stub\n", This, debugstr_w(filename));
     return E_NOTIMPL;
 }
 
 static HRESULT WINAPI BackgroundCopyJob_GetReplyFileName(
     FIXME("(%p)->(%s): stub\n", This, debugstr_w(filename));
     return E_NOTIMPL;
 }
 
 static HRESULT WINAPI BackgroundCopyJob_GetReplyFileName(
-    IBackgroundCopyJob2 *iface,
+    IBackgroundCopyJob3 *iface,
     LPWSTR *pFilename)
 {
     LPWSTR *pFilename)
 {
-    BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob2(iface);
+    BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob3(iface);
     FIXME("(%p)->(%p): stub\n", This, pFilename);
     return E_NOTIMPL;
 }
 
     FIXME("(%p)->(%p): stub\n", This, pFilename);
     return E_NOTIMPL;
 }
 
+static int index_from_target(BG_AUTH_TARGET target)
+{
+    if (!target || target > BG_AUTH_TARGET_PROXY) return -1;
+    return target - 1;
+}
+
+static int index_from_scheme(BG_AUTH_SCHEME scheme)
+{
+    if (!scheme || scheme > BG_AUTH_SCHEME_PASSPORT) return -1;
+    return scheme - 1;
+}
+
 static HRESULT WINAPI BackgroundCopyJob_SetCredentials(
 static HRESULT WINAPI BackgroundCopyJob_SetCredentials(
-    IBackgroundCopyJob2 *iface,
+    IBackgroundCopyJob3 *iface,
     BG_AUTH_CREDENTIALS *cred)
 {
     BG_AUTH_CREDENTIALS *cred)
 {
-    BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob2(iface);
-    FIXME("(%p)->(%p): stub\n", This, cred);
+    BackgroundCopyJobImpl *job = impl_from_IBackgroundCopyJob3(iface);
+    BG_AUTH_CREDENTIALS *new_cred;
+    int idx_target, idx_scheme;
+
+    TRACE("(%p)->(%p)\n", job, cred);
+
+    if ((idx_target = index_from_target(cred->Target)) < 0) return BG_E_INVALID_AUTH_TARGET;
+    if ((idx_scheme = index_from_scheme(cred->Scheme)) < 0) return BG_E_INVALID_AUTH_SCHEME;
+    new_cred = &job->http_options.creds[idx_target][idx_scheme];
+
+    EnterCriticalSection(&job->cs);
+
+    new_cred->Target = cred->Target;
+    new_cred->Scheme = cred->Scheme;
+
+    if (cred->Credentials.Basic.UserName)
+    {
+        HeapFree(GetProcessHeap(), 0, new_cred->Credentials.Basic.UserName);
+        new_cred->Credentials.Basic.UserName = strdupW(cred->Credentials.Basic.UserName);
+    }
+    if (cred->Credentials.Basic.Password)
+    {
+        HeapFree(GetProcessHeap(), 0, new_cred->Credentials.Basic.Password);
+        new_cred->Credentials.Basic.Password = strdupW(cred->Credentials.Basic.Password);
+    }
+
+    LeaveCriticalSection(&job->cs);
     return S_OK;
 }
 
 static HRESULT WINAPI BackgroundCopyJob_RemoveCredentials(
     return S_OK;
 }
 
 static HRESULT WINAPI BackgroundCopyJob_RemoveCredentials(
-    IBackgroundCopyJob2 *iface,
+    IBackgroundCopyJob3 *iface,
     BG_AUTH_TARGET target,
     BG_AUTH_SCHEME scheme)
 {
     BG_AUTH_TARGET target,
     BG_AUTH_SCHEME scheme)
 {
-    BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob2(iface);
-    FIXME("(%p)->(%d %d): stub\n", This, target, scheme);
+    BackgroundCopyJobImpl *job = impl_from_IBackgroundCopyJob3(iface);
+    BG_AUTH_CREDENTIALS *new_cred;
+    int idx_target, idx_scheme;
+
+    TRACE("(%p)->(%u %u)\n", job, target, scheme);
+
+    if ((idx_target = index_from_target(target)) < 0) return BG_E_INVALID_AUTH_TARGET;
+    if ((idx_scheme = index_from_scheme(scheme)) < 0) return BG_E_INVALID_AUTH_SCHEME;
+    new_cred = &job->http_options.creds[idx_target][idx_scheme];
+
+    EnterCriticalSection(&job->cs);
+
+    new_cred->Target = new_cred->Scheme = 0;
+    HeapFree(GetProcessHeap(), 0, new_cred->Credentials.Basic.UserName);
+    new_cred->Credentials.Basic.UserName = NULL;
+    HeapFree(GetProcessHeap(), 0, new_cred->Credentials.Basic.Password);
+    new_cred->Credentials.Basic.Password = NULL;
+
+    LeaveCriticalSection(&job->cs);
+    return S_OK;
+}
+
+static HRESULT WINAPI BackgroundCopyJob_ReplaceRemotePrefix(
+    IBackgroundCopyJob3 *iface,
+    LPCWSTR OldPrefix,
+    LPCWSTR NewPrefix)
+{
+    BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob3(iface);
+    FIXME("(%p)->(%s %s): stub\n", This, debugstr_w(OldPrefix), debugstr_w(NewPrefix));
+    return S_OK;
+}
+
+static HRESULT WINAPI BackgroundCopyJob_AddFileWithRanges(
+    IBackgroundCopyJob3 *iface,
+    LPCWSTR RemoteUrl,
+    LPCWSTR LocalName,
+    DWORD RangeCount,
+    BG_FILE_RANGE Ranges[])
+{
+    BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob3(iface);
+    FIXME("(%p)->(%s %s %u %p): stub\n", This, debugstr_w(RemoteUrl), debugstr_w(LocalName), RangeCount, Ranges);
+    return S_OK;
+}
+
+static HRESULT WINAPI BackgroundCopyJob_SetFileACLFlags(
+    IBackgroundCopyJob3 *iface,
+    DWORD Flags)
+{
+    BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob3(iface);
+    FIXME("(%p)->(%x): stub\n", This, Flags);
     return S_OK;
 }
 
     return S_OK;
 }
 
-static const IBackgroundCopyJob2Vtbl BackgroundCopyJobVtbl =
+static HRESULT WINAPI BackgroundCopyJob_GetFileACLFlags(
+    IBackgroundCopyJob3 *iface,
+    DWORD *Flags)
+{
+    BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob3(iface);
+    FIXME("(%p)->(%p): stub\n", This, Flags);
+    return S_OK;
+}
+
+static const IBackgroundCopyJob3Vtbl BackgroundCopyJob3Vtbl =
 {
     BackgroundCopyJob_QueryInterface,
     BackgroundCopyJob_AddRef,
 {
     BackgroundCopyJob_QueryInterface,
     BackgroundCopyJob_AddRef,
@@ -677,14 +1008,182 @@ static const IBackgroundCopyJob2Vtbl BackgroundCopyJobVtbl =
     BackgroundCopyJob_SetReplyFileName,
     BackgroundCopyJob_GetReplyFileName,
     BackgroundCopyJob_SetCredentials,
     BackgroundCopyJob_SetReplyFileName,
     BackgroundCopyJob_GetReplyFileName,
     BackgroundCopyJob_SetCredentials,
-    BackgroundCopyJob_RemoveCredentials
+    BackgroundCopyJob_RemoveCredentials,
+    BackgroundCopyJob_ReplaceRemotePrefix,
+    BackgroundCopyJob_AddFileWithRanges,
+    BackgroundCopyJob_SetFileACLFlags,
+    BackgroundCopyJob_GetFileACLFlags
+};
+
+static inline BackgroundCopyJobImpl *impl_from_IBackgroundCopyJobHttpOptions(
+    IBackgroundCopyJobHttpOptions *iface)
+{
+    return CONTAINING_RECORD(iface, BackgroundCopyJobImpl, IBackgroundCopyJobHttpOptions_iface);
+}
+
+static HRESULT WINAPI http_options_QueryInterface(
+    IBackgroundCopyJobHttpOptions *iface,
+    REFIID riid,
+    void **ppvObject)
+{
+    BackgroundCopyJobImpl *job = impl_from_IBackgroundCopyJobHttpOptions(iface);
+    return IBackgroundCopyJob3_QueryInterface(&job->IBackgroundCopyJob3_iface, riid, ppvObject);
+}
+
+static ULONG WINAPI http_options_AddRef(
+    IBackgroundCopyJobHttpOptions *iface)
+{
+    BackgroundCopyJobImpl *job = impl_from_IBackgroundCopyJobHttpOptions(iface);
+    return IBackgroundCopyJob3_AddRef(&job->IBackgroundCopyJob3_iface);
+}
+
+static ULONG WINAPI http_options_Release(
+    IBackgroundCopyJobHttpOptions *iface)
+{
+    BackgroundCopyJobImpl *job = impl_from_IBackgroundCopyJobHttpOptions(iface);
+    return IBackgroundCopyJob3_Release(&job->IBackgroundCopyJob3_iface);
+}
+
+static HRESULT WINAPI http_options_SetClientCertificateByID(
+    IBackgroundCopyJobHttpOptions *iface,
+    BG_CERT_STORE_LOCATION StoreLocation,
+    LPCWSTR StoreName,
+    BYTE *pCertHashBlob)
+{
+    FIXME("\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI http_options_SetClientCertificateByName(
+    IBackgroundCopyJobHttpOptions *iface,
+    BG_CERT_STORE_LOCATION StoreLocation,
+    LPCWSTR StoreName,
+    LPCWSTR SubjectName)
+{
+    FIXME("\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI http_options_RemoveClientCertificate(
+    IBackgroundCopyJobHttpOptions *iface)
+{
+    FIXME("\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI http_options_GetClientCertificate(
+    IBackgroundCopyJobHttpOptions *iface,
+    BG_CERT_STORE_LOCATION *pStoreLocation,
+    LPWSTR *pStoreName,
+    BYTE **ppCertHashBlob,
+    LPWSTR *pSubjectName)
+{
+    FIXME("\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI http_options_SetCustomHeaders(
+    IBackgroundCopyJobHttpOptions *iface,
+    LPCWSTR RequestHeaders)
+{
+    BackgroundCopyJobImpl *job = impl_from_IBackgroundCopyJobHttpOptions(iface);
+
+    TRACE("(%p)->(%s)\n", iface, debugstr_w(RequestHeaders));
+
+    EnterCriticalSection(&job->cs);
+
+    if (RequestHeaders)
+    {
+        WCHAR *headers = strdupW(RequestHeaders);
+        if (!headers)
+        {
+            LeaveCriticalSection(&job->cs);
+            return E_OUTOFMEMORY;
+        }
+        HeapFree(GetProcessHeap(), 0, job->http_options.headers);
+        job->http_options.headers = headers;
+    }
+    else
+    {
+        HeapFree(GetProcessHeap(), 0, job->http_options.headers);
+        job->http_options.headers = NULL;
+    }
+
+    LeaveCriticalSection(&job->cs);
+    return S_OK;
+}
+
+static HRESULT WINAPI http_options_GetCustomHeaders(
+    IBackgroundCopyJobHttpOptions *iface,
+    LPWSTR *pRequestHeaders)
+{
+    BackgroundCopyJobImpl *job = impl_from_IBackgroundCopyJobHttpOptions(iface);
+
+    TRACE("(%p)->(%p)\n", iface, pRequestHeaders);
+
+    EnterCriticalSection(&job->cs);
+
+    if (job->http_options.headers)
+    {
+        WCHAR *headers = co_strdupW(job->http_options.headers);
+        if (!headers)
+        {
+            LeaveCriticalSection(&job->cs);
+            return E_OUTOFMEMORY;
+        }
+        *pRequestHeaders = headers;
+        LeaveCriticalSection(&job->cs);
+        return S_OK;
+    }
+
+    *pRequestHeaders = NULL;
+    LeaveCriticalSection(&job->cs);
+    return S_FALSE;
+}
+
+static HRESULT WINAPI http_options_SetSecurityFlags(
+    IBackgroundCopyJobHttpOptions *iface,
+    ULONG Flags)
+{
+    BackgroundCopyJobImpl *job = impl_from_IBackgroundCopyJobHttpOptions(iface);
+
+    TRACE("(%p)->(0x%08x)\n", iface, Flags);
+
+    job->http_options.flags = Flags;
+    return S_OK;
+}
+
+static HRESULT WINAPI http_options_GetSecurityFlags(
+    IBackgroundCopyJobHttpOptions *iface,
+    ULONG *pFlags)
+{
+    BackgroundCopyJobImpl *job = impl_from_IBackgroundCopyJobHttpOptions(iface);
+
+    TRACE("(%p)->(%p)\n", iface, pFlags);
+
+    *pFlags = job->http_options.flags;
+    return S_OK;
+}
+
+static const IBackgroundCopyJobHttpOptionsVtbl http_options_vtbl =
+{
+    http_options_QueryInterface,
+    http_options_AddRef,
+    http_options_Release,
+    http_options_SetClientCertificateByID,
+    http_options_SetClientCertificateByName,
+    http_options_RemoveClientCertificate,
+    http_options_GetClientCertificate,
+    http_options_SetCustomHeaders,
+    http_options_GetCustomHeaders,
+    http_options_SetSecurityFlags,
+    http_options_GetSecurityFlags
 };
 
 HRESULT BackgroundCopyJobConstructor(LPCWSTR displayName, BG_JOB_TYPE type, GUID *job_id, BackgroundCopyJobImpl **job)
 {
     HRESULT hr;
     BackgroundCopyJobImpl *This;
 };
 
 HRESULT BackgroundCopyJobConstructor(LPCWSTR displayName, BG_JOB_TYPE type, GUID *job_id, BackgroundCopyJobImpl **job)
 {
     HRESULT hr;
     BackgroundCopyJobImpl *This;
-    int n;
 
     TRACE("(%s,%d,%p)\n", debugstr_w(displayName), type, job);
 
 
     TRACE("(%s,%d,%p)\n", debugstr_w(displayName), type, job);
 
@@ -692,15 +1191,15 @@ HRESULT BackgroundCopyJobConstructor(LPCWSTR displayName, BG_JOB_TYPE type, GUID
     if (!This)
         return E_OUTOFMEMORY;
 
     if (!This)
         return E_OUTOFMEMORY;
 
-    This->IBackgroundCopyJob2_iface.lpVtbl = &BackgroundCopyJobVtbl;
+    This->IBackgroundCopyJob3_iface.lpVtbl = &BackgroundCopyJob3Vtbl;
+    This->IBackgroundCopyJobHttpOptions_iface.lpVtbl = &http_options_vtbl;
     InitializeCriticalSection(&This->cs);
     This->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": BackgroundCopyJobImpl.cs");
 
     This->ref = 1;
     This->type = type;
 
     InitializeCriticalSection(&This->cs);
     This->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": BackgroundCopyJobImpl.cs");
 
     This->ref = 1;
     This->type = type;
 
-    n = (strlenW(displayName) + 1) *  sizeof *displayName;
-    This->displayName = HeapAlloc(GetProcessHeap(), 0, n);
+    This->displayName = strdupW(displayName);
     if (!This->displayName)
     {
         This->cs.DebugInfo->Spare[0] = 0;
     if (!This->displayName)
     {
         This->cs.DebugInfo->Spare[0] = 0;
@@ -708,7 +1207,6 @@ HRESULT BackgroundCopyJobConstructor(LPCWSTR displayName, BG_JOB_TYPE type, GUID
         HeapFree(GetProcessHeap(), 0, This);
         return E_OUTOFMEMORY;
     }
         HeapFree(GetProcessHeap(), 0, This);
         return E_OUTOFMEMORY;
     }
-    memcpy(This->displayName, displayName, n);
 
     hr = CoCreateGuid(&This->jobId);
     if (FAILED(hr))
 
     hr = CoCreateGuid(&This->jobId);
     if (FAILED(hr))
@@ -733,6 +1231,16 @@ HRESULT BackgroundCopyJobConstructor(LPCWSTR displayName, BG_JOB_TYPE type, GUID
     This->callback = NULL;
     This->callback2 = FALSE;
 
     This->callback = NULL;
     This->callback2 = FALSE;
 
+    This->error.context = 0;
+    This->error.code = 0;
+    This->error.file = NULL;
+
+    memset(&This->http_options, 0, sizeof(This->http_options));
+
+    This->wait   = CreateEventW(NULL, FALSE, FALSE, NULL);
+    This->cancel = CreateEventW(NULL, FALSE, FALSE, NULL);
+    This->done   = CreateEventW(NULL, FALSE, FALSE, NULL);
+
     *job = This;
 
     TRACE("created job %s:%p\n", debugstr_guid(&This->jobId), This);
     *job = This;
 
     TRACE("created job %s:%p\n", debugstr_guid(&This->jobId), This);
index 69c5c3a..f0c8462 100644 (file)
@@ -63,7 +63,7 @@ static HRESULT WINAPI BackgroundCopyManager_CreateJob(IBackgroundCopyManager *if
         return hres;
 
     /* Add a reference to the job to job list */
         return hres;
 
     /* Add a reference to the job to job list */
-    *ppJob = (IBackgroundCopyJob*)&job->IBackgroundCopyJob2_iface;
+    *ppJob = (IBackgroundCopyJob *)&job->IBackgroundCopyJob3_iface;
     IBackgroundCopyJob_AddRef(*ppJob);
     EnterCriticalSection(&globalMgr.cs);
     list_add_head(&globalMgr.jobs, &job->entryFromQmgr);
     IBackgroundCopyJob_AddRef(*ppJob);
     EnterCriticalSection(&globalMgr.cs);
     list_add_head(&globalMgr.jobs, &job->entryFromQmgr);
@@ -90,8 +90,8 @@ static HRESULT WINAPI BackgroundCopyManager_GetJob(IBackgroundCopyManager *iface
     {
         if (IsEqualGUID(&cur->jobId, jobID))
         {
     {
         if (IsEqualGUID(&cur->jobId, jobID))
         {
-            *job = (IBackgroundCopyJob*)&cur->IBackgroundCopyJob2_iface;
-            IBackgroundCopyJob2_AddRef(&cur->IBackgroundCopyJob2_iface);
+            *job = (IBackgroundCopyJob *)&cur->IBackgroundCopyJob3_iface;
+            IBackgroundCopyJob3_AddRef(&cur->IBackgroundCopyJob3_iface);
             hr = S_OK;
             break;
         }
             hr = S_OK;
             break;
         }
@@ -161,7 +161,7 @@ DWORD WINAPI fileTransfer(void *param)
             LIST_FOR_EACH_ENTRY_SAFE(job, jobCur, &qmgr->jobs, BackgroundCopyJobImpl, entryFromQmgr)
             {
                 list_remove(&job->entryFromQmgr);
             LIST_FOR_EACH_ENTRY_SAFE(job, jobCur, &qmgr->jobs, BackgroundCopyJobImpl, entryFromQmgr)
             {
                 list_remove(&job->entryFromQmgr);
-                IBackgroundCopyJob2_Release(&job->IBackgroundCopyJob2_iface);
+                IBackgroundCopyJob3_Release(&job->IBackgroundCopyJob3_iface);
             }
             return 0;
         }
             }
             return 0;
         }
@@ -176,7 +176,7 @@ DWORD WINAPI fileTransfer(void *param)
             if (job->state == BG_JOB_STATE_ACKNOWLEDGED || job->state == BG_JOB_STATE_CANCELLED)
             {
                 list_remove(&job->entryFromQmgr);
             if (job->state == BG_JOB_STATE_ACKNOWLEDGED || job->state == BG_JOB_STATE_CANCELLED)
             {
                 list_remove(&job->entryFromQmgr);
-                IBackgroundCopyJob2_Release(&job->IBackgroundCopyJob2_iface);
+                IBackgroundCopyJob3_Release(&job->IBackgroundCopyJob3_iface);
             }
             else if (job->state == BG_JOB_STATE_QUEUED)
             {
             }
             else if (job->state == BG_JOB_STATE_QUEUED)
             {
index ae86685..4615e13 100644 (file)
@@ -34,6 +34,8 @@
 #include <winsvc.h>
 #include <objbase.h>
 #include <bits1_5.h>
 #include <winsvc.h>
 #include <objbase.h>
 #include <bits1_5.h>
+#include <bits2_0.h>
+#include <bits2_5.h>
 #include <bits3_0.h>
 
 #include <wine/list.h>
 #include <bits3_0.h>
 
 #include <wine/list.h>
@@ -45,7 +47,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(qmgr);
 /* Background copy job vtbl and related data */
 typedef struct
 {
 /* Background copy job vtbl and related data */
 typedef struct
 {
-    IBackgroundCopyJob2 IBackgroundCopyJob2_iface;
+    IBackgroundCopyJob3 IBackgroundCopyJob3_iface;
+    IBackgroundCopyJobHttpOptions IBackgroundCopyJobHttpOptions_iface;
     LONG ref;
     LPWSTR displayName;
     LPWSTR description;
     LONG ref;
     LPWSTR displayName;
     LPWSTR description;
@@ -60,18 +63,34 @@ typedef struct
     /* Protects file list, and progress */
     CRITICAL_SECTION cs;
     struct list entryFromQmgr;
     /* Protects file list, and progress */
     CRITICAL_SECTION cs;
     struct list entryFromQmgr;
+    struct
+    {
+        WCHAR              *headers;
+        ULONG               flags;
+        BG_AUTH_CREDENTIALS creds[BG_AUTH_TARGET_PROXY][BG_AUTH_SCHEME_PASSPORT];
+    } http_options;
+    struct
+    {
+        BG_ERROR_CONTEXT      context;
+        HRESULT               code;
+        IBackgroundCopyFile2 *file;
+    } error;
+    HANDLE wait;
+    HANDLE cancel;
+    HANDLE done;
 } BackgroundCopyJobImpl;
 
 /* Background copy file vtbl and related data */
 typedef struct
 {
 } BackgroundCopyJobImpl;
 
 /* Background copy file vtbl and related data */
 typedef struct
 {
-    IBackgroundCopyFile IBackgroundCopyFile_iface;
+    IBackgroundCopyFile2 IBackgroundCopyFile2_iface;
     LONG ref;
     BG_FILE_INFO info;
     BG_FILE_PROGRESS fileProgress;
     WCHAR tempFileName[MAX_PATH];
     struct list entryFromJob;
     BackgroundCopyJobImpl *owner;
     LONG ref;
     BG_FILE_INFO info;
     BG_FILE_PROGRESS fileProgress;
     WCHAR tempFileName[MAX_PATH];
     struct list entryFromJob;
     BackgroundCopyJobImpl *owner;
+    DWORD read_size;
 } BackgroundCopyFileImpl;
 
 /* Background copy manager vtbl and related data */
 } BackgroundCopyFileImpl;
 
 /* Background copy manager vtbl and related data */
@@ -105,14 +124,21 @@ HRESULT EnumBackgroundCopyFilesConstructor(BackgroundCopyJobImpl*, IEnumBackgrou
 DWORD WINAPI fileTransfer(void *param) DECLSPEC_HIDDEN;
 void processJob(BackgroundCopyJobImpl *job) DECLSPEC_HIDDEN;
 BOOL processFile(BackgroundCopyFileImpl *file, BackgroundCopyJobImpl *job) DECLSPEC_HIDDEN;
 DWORD WINAPI fileTransfer(void *param) DECLSPEC_HIDDEN;
 void processJob(BackgroundCopyJobImpl *job) DECLSPEC_HIDDEN;
 BOOL processFile(BackgroundCopyFileImpl *file, BackgroundCopyJobImpl *job) DECLSPEC_HIDDEN;
+BOOL transitionJobState(BackgroundCopyJobImpl *job, BG_JOB_STATE from, BG_JOB_STATE to) DECLSPEC_HIDDEN;
 
 /* Little helper functions */
 
 /* Little helper functions */
-static inline char *
-qmgr_strdup(const char *s)
+static inline WCHAR *strdupW(const WCHAR *src)
+{
+    WCHAR *dst = HeapAlloc(GetProcessHeap(), 0, (strlenW(src) + 1) * sizeof(WCHAR));
+    if (dst) strcpyW(dst, src);
+    return dst;
+}
+
+static inline WCHAR *co_strdupW(const WCHAR *src)
 {
 {
-    size_t n = strlen(s) + 1;
-    char *d = HeapAlloc(GetProcessHeap(), 0, n);
-    return d ? memcpy(d, s, n) : NULL;
+    WCHAR *dst = CoTaskMemAlloc((strlenW(src) + 1) * sizeof(WCHAR));
+    if (dst) strcpyW(dst, src);
+    return dst;
 }
 
 static inline HRESULT return_strval(const WCHAR *str, WCHAR **ret)
 }
 
 static inline HRESULT return_strval(const WCHAR *str, WCHAR **ret)
@@ -128,19 +154,4 @@ static inline HRESULT return_strval(const WCHAR *str, WCHAR **ret)
     return S_OK;
 }
 
     return S_OK;
 }
 
-static inline BOOL
-transitionJobState(BackgroundCopyJobImpl *job, BG_JOB_STATE fromState,
-                   BG_JOB_STATE toState)
-{
-    BOOL rv = FALSE;
-    EnterCriticalSection(&globalMgr.cs);
-    if (job->state == fromState)
-    {
-        job->state = toState;
-        rv = TRUE;
-    }
-    LeaveCriticalSection(&globalMgr.cs);
-    return rv;
-}
-
 #endif /* __QMGR_H__ */
 #endif /* __QMGR_H__ */
index edbe71e..110d479 100644 (file)
@@ -22,4 +22,6 @@
 
 #define DO_NO_IMPORTS
 #include "bits1_5.idl"
 
 #define DO_NO_IMPORTS
 #include "bits1_5.idl"
+#include "bits2_0.idl"
+#include "bits2_5.idl"
 #include "bits3_0.idl"
 #include "bits3_0.idl"
index d626ca0..e7d6ce4 100644 (file)
@@ -159,7 +159,7 @@ reactos/dll/win32/powrprof            # Forked at Wine-1.0rc5
 reactos/dll/win32/printui             # Synced to WineStaging-1.7.37
 reactos/dll/win32/propsys             # Synced to WineStaging-1.7.37
 reactos/dll/win32/pstorec             # Synced to WineStaging-1.7.37
 reactos/dll/win32/printui             # Synced to WineStaging-1.7.37
 reactos/dll/win32/propsys             # Synced to WineStaging-1.7.37
 reactos/dll/win32/pstorec             # Synced to WineStaging-1.7.37
-reactos/dll/win32/qmgr                # Synced to WineStaging-1.7.37
+reactos/dll/win32/qmgr                # Synced to WineStaging-1.7.47
 reactos/dll/win32/qmgrprxy            # Synced to WineStaging-1.7.37
 reactos/dll/win32/query               # Synced to WineStaging-1.7.37
 reactos/dll/win32/rasapi32            # Synced to WineStaging-1.7.37
 reactos/dll/win32/qmgrprxy            # Synced to WineStaging-1.7.37
 reactos/dll/win32/query               # Synced to WineStaging-1.7.37
 reactos/dll/win32/rasapi32            # Synced to WineStaging-1.7.37