xref: /reactos/dll/win32/qmgr/job.c (revision e3bf8410)
1 /*
2  * Background Copy Job Interface for BITS
3  *
4  * Copyright 2007 Google (Roy Shea)
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20 
21 #include <stdarg.h>
22 
23 #include "windef.h"
24 #include "winbase.h"
25 #include "qmgr.h"
26 #include "wine/debug.h"
27 
28 WINE_DEFAULT_DEBUG_CHANNEL(qmgr);
29 
transitionJobState(BackgroundCopyJobImpl * job,BG_JOB_STATE from,BG_JOB_STATE to)30 BOOL transitionJobState(BackgroundCopyJobImpl *job, BG_JOB_STATE from, BG_JOB_STATE to)
31 {
32     BOOL ret = FALSE;
33 
34     EnterCriticalSection(&globalMgr.cs);
35     if (job->state == from)
36     {
37         job->state = to;
38         ret = TRUE;
39     }
40     LeaveCriticalSection(&globalMgr.cs);
41     return ret;
42 }
43 
44 struct copy_error
45 {
46     IBackgroundCopyError  IBackgroundCopyError_iface;
47     LONG                  refs;
48     BG_ERROR_CONTEXT      context;
49     HRESULT               code;
50     IBackgroundCopyFile2 *file;
51 };
52 
impl_from_IBackgroundCopyError(IBackgroundCopyError * iface)53 static inline struct copy_error *impl_from_IBackgroundCopyError(IBackgroundCopyError *iface)
54 {
55     return CONTAINING_RECORD(iface, struct copy_error, IBackgroundCopyError_iface);
56 }
57 
copy_error_QueryInterface(IBackgroundCopyError * iface,REFIID riid,void ** obj)58 static HRESULT WINAPI copy_error_QueryInterface(
59     IBackgroundCopyError *iface,
60     REFIID riid,
61     void **obj)
62 {
63     struct copy_error *error = impl_from_IBackgroundCopyError(iface);
64 
65     TRACE("(%p)->(%s %p)\n", error, debugstr_guid(riid), obj);
66 
67     if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IBackgroundCopyError))
68     {
69         *obj = &error->IBackgroundCopyError_iface;
70     }
71     else
72     {
73         *obj = NULL;
74         WARN("interface %s not supported\n", debugstr_guid(riid));
75         return E_NOINTERFACE;
76     }
77 
78     IBackgroundCopyError_AddRef(iface);
79     return S_OK;
80 }
81 
copy_error_AddRef(IBackgroundCopyError * iface)82 static ULONG WINAPI copy_error_AddRef(
83     IBackgroundCopyError *iface)
84 {
85     struct copy_error *error = impl_from_IBackgroundCopyError(iface);
86     LONG refs = InterlockedIncrement(&error->refs);
87     TRACE("(%p)->(%d)\n", error, refs);
88     return refs;
89 }
90 
copy_error_Release(IBackgroundCopyError * iface)91 static ULONG WINAPI copy_error_Release(
92     IBackgroundCopyError *iface)
93 {
94     struct copy_error *error = impl_from_IBackgroundCopyError(iface);
95     LONG refs = InterlockedDecrement(&error->refs);
96 
97     TRACE("(%p)->(%d)\n", error, refs);
98 
99     if (!refs)
100     {
101         if (error->file) IBackgroundCopyFile2_Release(error->file);
102         HeapFree(GetProcessHeap(), 0, error);
103     }
104     return refs;
105 }
106 
copy_error_GetError(IBackgroundCopyError * iface,BG_ERROR_CONTEXT * pContext,HRESULT * pCode)107 static HRESULT WINAPI copy_error_GetError(
108     IBackgroundCopyError *iface,
109     BG_ERROR_CONTEXT *pContext,
110     HRESULT *pCode)
111 {
112     struct copy_error *error = impl_from_IBackgroundCopyError(iface);
113 
114     TRACE("(%p)->(%p %p)\n", error, pContext, pCode);
115 
116     *pContext = error->context;
117     *pCode = error->code;
118 
119     TRACE("returning context %u error code 0x%08x\n", error->context, error->code);
120     return S_OK;
121 }
122 
copy_error_GetFile(IBackgroundCopyError * iface,IBackgroundCopyFile ** pVal)123 static HRESULT WINAPI copy_error_GetFile(
124     IBackgroundCopyError *iface,
125     IBackgroundCopyFile **pVal)
126 {
127     struct copy_error *error = impl_from_IBackgroundCopyError(iface);
128 
129     TRACE("(%p)->(%p)\n", error, pVal);
130 
131     if (error->file)
132     {
133         IBackgroundCopyFile2_AddRef(error->file);
134         *pVal = (IBackgroundCopyFile *)error->file;
135         return S_OK;
136     }
137     *pVal = NULL;
138     return BG_E_FILE_NOT_AVAILABLE;
139 }
140 
copy_error_GetErrorDescription(IBackgroundCopyError * iface,DWORD LanguageId,LPWSTR * pErrorDescription)141 static HRESULT WINAPI copy_error_GetErrorDescription(
142     IBackgroundCopyError *iface,
143     DWORD LanguageId,
144     LPWSTR *pErrorDescription)
145 {
146     struct copy_error *error = impl_from_IBackgroundCopyError(iface);
147     FIXME("(%p)->(%p)\n", error, pErrorDescription);
148     return E_NOTIMPL;
149 }
150 
copy_error_GetErrorContextDescription(IBackgroundCopyError * iface,DWORD LanguageId,LPWSTR * pContextDescription)151 static HRESULT WINAPI copy_error_GetErrorContextDescription(
152     IBackgroundCopyError *iface,
153     DWORD LanguageId,
154     LPWSTR *pContextDescription)
155 {
156     struct copy_error *error = impl_from_IBackgroundCopyError(iface);
157     FIXME("(%p)->(%p)\n", error, pContextDescription);
158     return E_NOTIMPL;
159 }
160 
copy_error_GetProtocol(IBackgroundCopyError * iface,LPWSTR * pProtocol)161 static HRESULT WINAPI copy_error_GetProtocol(
162     IBackgroundCopyError *iface,
163     LPWSTR *pProtocol)
164 {
165     struct copy_error *error = impl_from_IBackgroundCopyError(iface);
166     FIXME("(%p)->(%p)\n", error, pProtocol);
167     return E_NOTIMPL;
168 }
169 
170 static const IBackgroundCopyErrorVtbl copy_error_vtbl =
171 {
172     copy_error_QueryInterface,
173     copy_error_AddRef,
174     copy_error_Release,
175     copy_error_GetError,
176     copy_error_GetFile,
177     copy_error_GetErrorDescription,
178     copy_error_GetErrorContextDescription,
179     copy_error_GetProtocol
180 };
181 
create_copy_error(BG_ERROR_CONTEXT context,HRESULT code,IBackgroundCopyFile2 * file,IBackgroundCopyError ** obj)182 static HRESULT create_copy_error(
183     BG_ERROR_CONTEXT context,
184     HRESULT code,
185     IBackgroundCopyFile2 *file,
186     IBackgroundCopyError **obj)
187 {
188     struct copy_error *error;
189 
190     TRACE("context %u code %08x file %p\n", context, code, file);
191 
192     if (!(error = HeapAlloc(GetProcessHeap(), 0, sizeof(*error) ))) return E_OUTOFMEMORY;
193     error->IBackgroundCopyError_iface.lpVtbl = &copy_error_vtbl;
194     error->refs    = 1;
195     error->context = context;
196     error->code    = code;
197     error->file    = file;
198     if (error->file) IBackgroundCopyFile2_AddRef(error->file);
199 
200     *obj = &error->IBackgroundCopyError_iface;
201     TRACE("returning iface %p\n", *obj);
202     return S_OK;
203 }
204 
is_job_done(const BackgroundCopyJobImpl * job)205 static inline BOOL is_job_done(const BackgroundCopyJobImpl *job)
206 {
207     return job->state == BG_JOB_STATE_CANCELLED || job->state == BG_JOB_STATE_ACKNOWLEDGED;
208 }
209 
impl_from_IBackgroundCopyJob3(IBackgroundCopyJob3 * iface)210 static inline BackgroundCopyJobImpl *impl_from_IBackgroundCopyJob3(IBackgroundCopyJob3 *iface)
211 {
212     return CONTAINING_RECORD(iface, BackgroundCopyJobImpl, IBackgroundCopyJob3_iface);
213 }
214 
BackgroundCopyJob_QueryInterface(IBackgroundCopyJob3 * iface,REFIID riid,void ** obj)215 static HRESULT WINAPI BackgroundCopyJob_QueryInterface(
216     IBackgroundCopyJob3 *iface, REFIID riid, void **obj)
217 {
218     BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob3(iface);
219 
220     TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
221 
222     if (IsEqualGUID(riid, &IID_IUnknown) ||
223         IsEqualGUID(riid, &IID_IBackgroundCopyJob) ||
224         IsEqualGUID(riid, &IID_IBackgroundCopyJob2) ||
225         IsEqualGUID(riid, &IID_IBackgroundCopyJob3))
226     {
227         *obj = &This->IBackgroundCopyJob3_iface;
228     }
229     else if (IsEqualGUID(riid, &IID_IBackgroundCopyJobHttpOptions))
230     {
231         *obj = &This->IBackgroundCopyJobHttpOptions_iface;
232     }
233     else
234     {
235         *obj = NULL;
236         return E_NOINTERFACE;
237     }
238 
239     IBackgroundCopyJob3_AddRef(iface);
240     return S_OK;
241 }
242 
BackgroundCopyJob_AddRef(IBackgroundCopyJob3 * iface)243 static ULONG WINAPI BackgroundCopyJob_AddRef(IBackgroundCopyJob3 *iface)
244 {
245     BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob3(iface);
246     ULONG ref = InterlockedIncrement(&This->ref);
247     TRACE("(%p)->(%d)\n", This, ref);
248     return ref;
249 }
250 
BackgroundCopyJob_Release(IBackgroundCopyJob3 * iface)251 static ULONG WINAPI BackgroundCopyJob_Release(IBackgroundCopyJob3 *iface)
252 {
253     BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob3(iface);
254     ULONG i, j, ref = InterlockedDecrement(&This->ref);
255 
256     TRACE("(%p)->(%d)\n", This, ref);
257 
258     if (ref == 0)
259     {
260         This->cs.DebugInfo->Spare[0] = 0;
261         DeleteCriticalSection(&This->cs);
262         if (This->callback)
263             IBackgroundCopyCallback2_Release(This->callback);
264         HeapFree(GetProcessHeap(), 0, This->displayName);
265         HeapFree(GetProcessHeap(), 0, This->description);
266         HeapFree(GetProcessHeap(), 0, This->http_options.headers);
267         for (i = 0; i < BG_AUTH_TARGET_PROXY; i++)
268         {
269             for (j = 0; j < BG_AUTH_SCHEME_PASSPORT; j++)
270             {
271                 BG_AUTH_CREDENTIALS *cred = &This->http_options.creds[i][j];
272                 HeapFree(GetProcessHeap(), 0, cred->Credentials.Basic.UserName);
273                 HeapFree(GetProcessHeap(), 0, cred->Credentials.Basic.Password);
274             }
275         }
276         CloseHandle(This->wait);
277         CloseHandle(This->cancel);
278         CloseHandle(This->done);
279         HeapFree(GetProcessHeap(), 0, This);
280     }
281 
282     return ref;
283 }
284 
285 /*** IBackgroundCopyJob methods ***/
286 
BackgroundCopyJob_AddFileSet(IBackgroundCopyJob3 * iface,ULONG cFileCount,BG_FILE_INFO * pFileSet)287 static HRESULT WINAPI BackgroundCopyJob_AddFileSet(
288     IBackgroundCopyJob3 *iface,
289     ULONG cFileCount,
290     BG_FILE_INFO *pFileSet)
291 {
292     BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob3(iface);
293     HRESULT hr = S_OK;
294     ULONG i;
295 
296     TRACE("(%p)->(%d %p)\n", This, cFileCount, pFileSet);
297 
298     EnterCriticalSection(&This->cs);
299 
300     for (i = 0; i < cFileCount; ++i)
301     {
302         BackgroundCopyFileImpl *file;
303 
304         /* We should return E_INVALIDARG in these cases. */
305         FIXME("Check for valid filenames and supported protocols\n");
306 
307         hr = BackgroundCopyFileConstructor(This, pFileSet[i].RemoteName, pFileSet[i].LocalName, &file);
308         if (hr != S_OK) break;
309 
310         /* Add a reference to the file to file list */
311         list_add_head(&This->files, &file->entryFromJob);
312         This->jobProgress.BytesTotal = BG_SIZE_UNKNOWN;
313         ++This->jobProgress.FilesTotal;
314     }
315 
316     LeaveCriticalSection(&This->cs);
317 
318     return hr;
319 }
320 
BackgroundCopyJob_AddFile(IBackgroundCopyJob3 * iface,LPCWSTR RemoteUrl,LPCWSTR LocalName)321 static HRESULT WINAPI BackgroundCopyJob_AddFile(
322     IBackgroundCopyJob3 *iface,
323     LPCWSTR RemoteUrl,
324     LPCWSTR LocalName)
325 {
326     BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob3(iface);
327     BG_FILE_INFO file;
328 
329     TRACE("(%p)->(%s %s)\n", This, debugstr_w(RemoteUrl), debugstr_w(LocalName));
330 
331     file.RemoteName = (LPWSTR)RemoteUrl;
332     file.LocalName = (LPWSTR)LocalName;
333     return IBackgroundCopyJob3_AddFileSet(iface, 1, &file);
334 }
335 
BackgroundCopyJob_EnumFiles(IBackgroundCopyJob3 * iface,IEnumBackgroundCopyFiles ** enum_files)336 static HRESULT WINAPI BackgroundCopyJob_EnumFiles(
337     IBackgroundCopyJob3 *iface,
338     IEnumBackgroundCopyFiles **enum_files)
339 {
340     BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob3(iface);
341     TRACE("(%p)->(%p)\n", This, enum_files);
342     return EnumBackgroundCopyFilesConstructor(This, enum_files);
343 }
344 
BackgroundCopyJob_Suspend(IBackgroundCopyJob3 * iface)345 static HRESULT WINAPI BackgroundCopyJob_Suspend(
346     IBackgroundCopyJob3 *iface)
347 {
348     BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob3(iface);
349     FIXME("(%p): stub\n", This);
350     return E_NOTIMPL;
351 }
352 
BackgroundCopyJob_Resume(IBackgroundCopyJob3 * iface)353 static HRESULT WINAPI BackgroundCopyJob_Resume(
354     IBackgroundCopyJob3 *iface)
355 {
356     BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob3(iface);
357     HRESULT rv = S_OK;
358 
359     TRACE("(%p)\n", This);
360 
361     EnterCriticalSection(&globalMgr.cs);
362     if (is_job_done(This))
363     {
364         rv = BG_E_INVALID_STATE;
365     }
366     else if (This->jobProgress.FilesTransferred == This->jobProgress.FilesTotal)
367     {
368         rv = BG_E_EMPTY;
369     }
370     else if (This->state != BG_JOB_STATE_CONNECTING
371              && This->state != BG_JOB_STATE_TRANSFERRING)
372     {
373         This->state = BG_JOB_STATE_QUEUED;
374         This->error.context = 0;
375         This->error.code = S_OK;
376         if (This->error.file)
377         {
378             IBackgroundCopyFile2_Release(This->error.file);
379             This->error.file = NULL;
380         }
381         SetEvent(globalMgr.jobEvent);
382     }
383     LeaveCriticalSection(&globalMgr.cs);
384 
385     return rv;
386 }
387 
BackgroundCopyJob_Cancel(IBackgroundCopyJob3 * iface)388 static HRESULT WINAPI BackgroundCopyJob_Cancel(
389     IBackgroundCopyJob3 *iface)
390 {
391     BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob3(iface);
392     HRESULT rv = S_OK;
393 
394     TRACE("(%p)\n", This);
395 
396     EnterCriticalSection(&This->cs);
397 
398     if (is_job_done(This))
399     {
400         rv = BG_E_INVALID_STATE;
401     }
402     else
403     {
404         BackgroundCopyFileImpl *file;
405 
406         if (This->state == BG_JOB_STATE_CONNECTING || This->state == BG_JOB_STATE_TRANSFERRING)
407         {
408             This->state = BG_JOB_STATE_CANCELLED;
409             SetEvent(This->cancel);
410 
411             LeaveCriticalSection(&This->cs);
412             WaitForSingleObject(This->done, INFINITE);
413             EnterCriticalSection(&This->cs);
414         }
415 
416         LIST_FOR_EACH_ENTRY(file, &This->files, BackgroundCopyFileImpl, entryFromJob)
417         {
418             if (file->tempFileName[0] && !DeleteFileW(file->tempFileName))
419             {
420                 WARN("Couldn't delete %s (%u)\n", debugstr_w(file->tempFileName), GetLastError());
421                 rv = BG_S_UNABLE_TO_DELETE_FILES;
422             }
423             if (file->info.LocalName && !DeleteFileW(file->info.LocalName))
424             {
425                 WARN("Couldn't delete %s (%u)\n", debugstr_w(file->info.LocalName), GetLastError());
426                 rv = BG_S_UNABLE_TO_DELETE_FILES;
427             }
428         }
429         This->state = BG_JOB_STATE_CANCELLED;
430     }
431 
432     LeaveCriticalSection(&This->cs);
433     return rv;
434 }
435 
BackgroundCopyJob_Complete(IBackgroundCopyJob3 * iface)436 static HRESULT WINAPI BackgroundCopyJob_Complete(
437     IBackgroundCopyJob3 *iface)
438 {
439     BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob3(iface);
440     HRESULT rv = S_OK;
441 
442     TRACE("(%p)\n", This);
443 
444     EnterCriticalSection(&This->cs);
445 
446     if (is_job_done(This))
447     {
448         rv = BG_E_INVALID_STATE;
449     }
450     else
451     {
452         BackgroundCopyFileImpl *file;
453         LIST_FOR_EACH_ENTRY(file, &This->files, BackgroundCopyFileImpl, entryFromJob)
454         {
455             if (file->fileProgress.Completed)
456             {
457                 if (!MoveFileExW(file->tempFileName, file->info.LocalName,
458                                  (MOVEFILE_COPY_ALLOWED
459                                   | MOVEFILE_REPLACE_EXISTING
460                                   | MOVEFILE_WRITE_THROUGH)))
461                 {
462                     ERR("Couldn't rename file %s -> %s\n",
463                         debugstr_w(file->tempFileName),
464                         debugstr_w(file->info.LocalName));
465                     rv = BG_S_PARTIAL_COMPLETE;
466                 }
467             }
468             else
469                 rv = BG_S_PARTIAL_COMPLETE;
470         }
471     }
472 
473     This->state = BG_JOB_STATE_ACKNOWLEDGED;
474     LeaveCriticalSection(&This->cs);
475 
476     return rv;
477 }
478 
BackgroundCopyJob_GetId(IBackgroundCopyJob3 * iface,GUID * pVal)479 static HRESULT WINAPI BackgroundCopyJob_GetId(
480     IBackgroundCopyJob3 *iface,
481     GUID *pVal)
482 {
483     BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob3(iface);
484     TRACE("(%p)->(%p)\n", This, pVal);
485     *pVal = This->jobId;
486     return S_OK;
487 }
488 
BackgroundCopyJob_GetType(IBackgroundCopyJob3 * iface,BG_JOB_TYPE * pVal)489 static HRESULT WINAPI BackgroundCopyJob_GetType(
490     IBackgroundCopyJob3 *iface,
491     BG_JOB_TYPE *pVal)
492 {
493     BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob3(iface);
494 
495     TRACE("(%p)->(%p)\n", This, pVal);
496 
497     if (!pVal)
498         return E_INVALIDARG;
499 
500     *pVal = This->type;
501     return S_OK;
502 }
503 
BackgroundCopyJob_GetProgress(IBackgroundCopyJob3 * iface,BG_JOB_PROGRESS * pVal)504 static HRESULT WINAPI BackgroundCopyJob_GetProgress(
505     IBackgroundCopyJob3 *iface,
506     BG_JOB_PROGRESS *pVal)
507 {
508     BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob3(iface);
509 
510     TRACE("(%p)->(%p)\n", This, pVal);
511 
512     if (!pVal)
513         return E_INVALIDARG;
514 
515     EnterCriticalSection(&This->cs);
516     *pVal = This->jobProgress;
517     LeaveCriticalSection(&This->cs);
518 
519     return S_OK;
520 }
521 
BackgroundCopyJob_GetTimes(IBackgroundCopyJob3 * iface,BG_JOB_TIMES * pVal)522 static HRESULT WINAPI BackgroundCopyJob_GetTimes(
523     IBackgroundCopyJob3 *iface,
524     BG_JOB_TIMES *pVal)
525 {
526     BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob3(iface);
527     FIXME("(%p)->(%p): stub\n", This, pVal);
528     return E_NOTIMPL;
529 }
530 
BackgroundCopyJob_GetState(IBackgroundCopyJob3 * iface,BG_JOB_STATE * pVal)531 static HRESULT WINAPI BackgroundCopyJob_GetState(
532     IBackgroundCopyJob3 *iface,
533     BG_JOB_STATE *pVal)
534 {
535     BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob3(iface);
536 
537     TRACE("(%p)->(%p)\n", This, pVal);
538 
539     if (!pVal)
540         return E_INVALIDARG;
541 
542     /* Don't think we need a critical section for this */
543     *pVal = This->state;
544     return S_OK;
545 }
546 
BackgroundCopyJob_GetError(IBackgroundCopyJob3 * iface,IBackgroundCopyError ** ppError)547 static HRESULT WINAPI BackgroundCopyJob_GetError(
548     IBackgroundCopyJob3 *iface,
549     IBackgroundCopyError **ppError)
550 {
551     BackgroundCopyJobImpl *job = impl_from_IBackgroundCopyJob3(iface);
552 
553     TRACE("(%p)->(%p)\n", job, ppError);
554 
555     if (!job->error.context) return BG_E_ERROR_INFORMATION_UNAVAILABLE;
556 
557     return create_copy_error(job->error.context, job->error.code, job->error.file, ppError);
558 }
559 
BackgroundCopyJob_GetOwner(IBackgroundCopyJob3 * iface,LPWSTR * pVal)560 static HRESULT WINAPI BackgroundCopyJob_GetOwner(
561     IBackgroundCopyJob3 *iface,
562     LPWSTR *pVal)
563 {
564     BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob3(iface);
565     FIXME("(%p)->(%p): stub\n", This, pVal);
566     return E_NOTIMPL;
567 }
568 
BackgroundCopyJob_SetDisplayName(IBackgroundCopyJob3 * iface,LPCWSTR Val)569 static HRESULT WINAPI BackgroundCopyJob_SetDisplayName(
570     IBackgroundCopyJob3 *iface,
571     LPCWSTR Val)
572 {
573     BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob3(iface);
574     FIXME("(%p)->(%s): stub\n", This, debugstr_w(Val));
575     return E_NOTIMPL;
576 }
577 
BackgroundCopyJob_GetDisplayName(IBackgroundCopyJob3 * iface,LPWSTR * pVal)578 static HRESULT WINAPI BackgroundCopyJob_GetDisplayName(
579     IBackgroundCopyJob3 *iface,
580     LPWSTR *pVal)
581 {
582     BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob3(iface);
583 
584     TRACE("(%p)->(%p)\n", This, pVal);
585 
586     return return_strval(This->displayName, pVal);
587 }
588 
BackgroundCopyJob_SetDescription(IBackgroundCopyJob3 * iface,LPCWSTR Val)589 static HRESULT WINAPI BackgroundCopyJob_SetDescription(
590     IBackgroundCopyJob3 *iface,
591     LPCWSTR Val)
592 {
593     BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob3(iface);
594     static const int max_description_len = 1024;
595     HRESULT hr = S_OK;
596     int len;
597 
598     TRACE("(%p)->(%s)\n", This, debugstr_w(Val));
599 
600     if (!Val) return E_INVALIDARG;
601 
602     len = lstrlenW(Val);
603     if (len > max_description_len) return BG_E_STRING_TOO_LONG;
604 
605     EnterCriticalSection(&This->cs);
606 
607     if (is_job_done(This))
608     {
609         hr = BG_E_INVALID_STATE;
610     }
611     else
612     {
613         HeapFree(GetProcessHeap(), 0, This->description);
614         if ((This->description = HeapAlloc(GetProcessHeap(), 0, (len+1)*sizeof(WCHAR))))
615             lstrcpyW(This->description, Val);
616         else
617             hr = E_OUTOFMEMORY;
618     }
619 
620     LeaveCriticalSection(&This->cs);
621 
622     return hr;
623 }
624 
BackgroundCopyJob_GetDescription(IBackgroundCopyJob3 * iface,LPWSTR * pVal)625 static HRESULT WINAPI BackgroundCopyJob_GetDescription(
626     IBackgroundCopyJob3 *iface,
627     LPWSTR *pVal)
628 {
629     BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob3(iface);
630 
631     TRACE("(%p)->(%p)\n", This, pVal);
632 
633     return return_strval(This->description, pVal);
634 }
635 
BackgroundCopyJob_SetPriority(IBackgroundCopyJob3 * iface,BG_JOB_PRIORITY Val)636 static HRESULT WINAPI BackgroundCopyJob_SetPriority(
637     IBackgroundCopyJob3 *iface,
638     BG_JOB_PRIORITY Val)
639 {
640     BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob3(iface);
641     FIXME("(%p)->(%d): stub\n", This, Val);
642     return S_OK;
643 }
644 
BackgroundCopyJob_GetPriority(IBackgroundCopyJob3 * iface,BG_JOB_PRIORITY * pVal)645 static HRESULT WINAPI BackgroundCopyJob_GetPriority(
646     IBackgroundCopyJob3 *iface,
647     BG_JOB_PRIORITY *pVal)
648 {
649     BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob3(iface);
650     FIXME("(%p)->(%p): stub\n", This, pVal);
651     return E_NOTIMPL;
652 }
653 
BackgroundCopyJob_SetNotifyFlags(IBackgroundCopyJob3 * iface,ULONG Val)654 static HRESULT WINAPI BackgroundCopyJob_SetNotifyFlags(
655     IBackgroundCopyJob3 *iface,
656     ULONG Val)
657 {
658     BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob3(iface);
659     static const ULONG valid_flags = BG_NOTIFY_JOB_TRANSFERRED |
660                                      BG_NOTIFY_JOB_ERROR |
661                                      BG_NOTIFY_DISABLE |
662                                      BG_NOTIFY_JOB_MODIFICATION |
663                                      BG_NOTIFY_FILE_TRANSFERRED;
664 
665     TRACE("(%p)->(0x%x)\n", This, Val);
666 
667     if (is_job_done(This)) return BG_E_INVALID_STATE;
668     if (Val & ~valid_flags) return E_NOTIMPL;
669     This->notify_flags = Val;
670     return S_OK;
671 }
672 
BackgroundCopyJob_GetNotifyFlags(IBackgroundCopyJob3 * iface,ULONG * pVal)673 static HRESULT WINAPI BackgroundCopyJob_GetNotifyFlags(
674     IBackgroundCopyJob3 *iface,
675     ULONG *pVal)
676 {
677     BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob3(iface);
678 
679     TRACE("(%p)->(%p)\n", This, pVal);
680 
681     if (!pVal) return E_INVALIDARG;
682 
683     *pVal = This->notify_flags;
684 
685     return S_OK;
686 }
687 
BackgroundCopyJob_SetNotifyInterface(IBackgroundCopyJob3 * iface,IUnknown * Val)688 static HRESULT WINAPI BackgroundCopyJob_SetNotifyInterface(
689     IBackgroundCopyJob3 *iface,
690     IUnknown *Val)
691 {
692     BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob3(iface);
693     HRESULT hr = S_OK;
694 
695     TRACE("(%p)->(%p)\n", This, Val);
696 
697     if (is_job_done(This)) return BG_E_INVALID_STATE;
698 
699     if (This->callback)
700     {
701         IBackgroundCopyCallback2_Release(This->callback);
702         This->callback = NULL;
703         This->callback2 = FALSE;
704     }
705 
706     if (Val)
707     {
708         hr = IUnknown_QueryInterface(Val, &IID_IBackgroundCopyCallback2, (void**)&This->callback);
709         if (FAILED(hr))
710             hr = IUnknown_QueryInterface(Val, &IID_IBackgroundCopyCallback, (void**)&This->callback);
711         else
712             This->callback2 = TRUE;
713     }
714 
715     return hr;
716 }
717 
BackgroundCopyJob_GetNotifyInterface(IBackgroundCopyJob3 * iface,IUnknown ** pVal)718 static HRESULT WINAPI BackgroundCopyJob_GetNotifyInterface(
719     IBackgroundCopyJob3 *iface,
720     IUnknown **pVal)
721 {
722     BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob3(iface);
723 
724     TRACE("(%p)->(%p)\n", This, pVal);
725 
726     if (!pVal) return E_INVALIDARG;
727 
728     *pVal = (IUnknown*)This->callback;
729     if (*pVal)
730         IUnknown_AddRef(*pVal);
731 
732     return S_OK;
733 }
734 
BackgroundCopyJob_SetMinimumRetryDelay(IBackgroundCopyJob3 * iface,ULONG Seconds)735 static HRESULT WINAPI BackgroundCopyJob_SetMinimumRetryDelay(
736     IBackgroundCopyJob3 *iface,
737     ULONG Seconds)
738 {
739     FIXME("%u\n", Seconds);
740     return S_OK;
741 }
742 
BackgroundCopyJob_GetMinimumRetryDelay(IBackgroundCopyJob3 * iface,ULONG * Seconds)743 static HRESULT WINAPI BackgroundCopyJob_GetMinimumRetryDelay(
744     IBackgroundCopyJob3 *iface,
745     ULONG *Seconds)
746 {
747     BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob3(iface);
748     FIXME("(%p)->(%p): stub\n", This, Seconds);
749     *Seconds = 30;
750     return S_OK;
751 }
752 
BackgroundCopyJob_SetNoProgressTimeout(IBackgroundCopyJob3 * iface,ULONG Seconds)753 static HRESULT WINAPI BackgroundCopyJob_SetNoProgressTimeout(
754     IBackgroundCopyJob3 *iface,
755     ULONG Seconds)
756 {
757     BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob3(iface);
758     FIXME("(%p)->(%d): stub\n", This, Seconds);
759     return S_OK;
760 }
761 
BackgroundCopyJob_GetNoProgressTimeout(IBackgroundCopyJob3 * iface,ULONG * Seconds)762 static HRESULT WINAPI BackgroundCopyJob_GetNoProgressTimeout(
763     IBackgroundCopyJob3 *iface,
764     ULONG *Seconds)
765 {
766     BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob3(iface);
767     FIXME("(%p)->(%p): stub\n", This, Seconds);
768     *Seconds = 900;
769     return S_OK;
770 }
771 
BackgroundCopyJob_GetErrorCount(IBackgroundCopyJob3 * iface,ULONG * Errors)772 static HRESULT WINAPI BackgroundCopyJob_GetErrorCount(
773     IBackgroundCopyJob3 *iface,
774     ULONG *Errors)
775 {
776     BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob3(iface);
777     FIXME("(%p)->(%p): stub\n", This, Errors);
778     return E_NOTIMPL;
779 }
780 
BackgroundCopyJob_SetProxySettings(IBackgroundCopyJob3 * iface,BG_JOB_PROXY_USAGE ProxyUsage,const WCHAR * ProxyList,const WCHAR * ProxyBypassList)781 static HRESULT WINAPI BackgroundCopyJob_SetProxySettings(
782     IBackgroundCopyJob3 *iface,
783     BG_JOB_PROXY_USAGE ProxyUsage,
784     const WCHAR *ProxyList,
785     const WCHAR *ProxyBypassList)
786 {
787     BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob3(iface);
788     FIXME("(%p)->(%d %s %s): stub\n", This, ProxyUsage, debugstr_w(ProxyList), debugstr_w(ProxyBypassList));
789     return E_NOTIMPL;
790 }
791 
BackgroundCopyJob_GetProxySettings(IBackgroundCopyJob3 * iface,BG_JOB_PROXY_USAGE * pProxyUsage,LPWSTR * pProxyList,LPWSTR * pProxyBypassList)792 static HRESULT WINAPI BackgroundCopyJob_GetProxySettings(
793     IBackgroundCopyJob3 *iface,
794     BG_JOB_PROXY_USAGE *pProxyUsage,
795     LPWSTR *pProxyList,
796     LPWSTR *pProxyBypassList)
797 {
798     BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob3(iface);
799     FIXME("(%p)->(%p %p %p): stub\n", This, pProxyUsage, pProxyList, pProxyBypassList);
800     return E_NOTIMPL;
801 }
802 
BackgroundCopyJob_TakeOwnership(IBackgroundCopyJob3 * iface)803 static HRESULT WINAPI BackgroundCopyJob_TakeOwnership(
804     IBackgroundCopyJob3 *iface)
805 {
806     BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob3(iface);
807     FIXME("(%p): stub\n", This);
808     return E_NOTIMPL;
809 }
810 
BackgroundCopyJob_SetNotifyCmdLine(IBackgroundCopyJob3 * iface,LPCWSTR prog,LPCWSTR params)811 static HRESULT WINAPI BackgroundCopyJob_SetNotifyCmdLine(
812     IBackgroundCopyJob3 *iface,
813     LPCWSTR prog,
814     LPCWSTR params)
815 {
816     BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob3(iface);
817     FIXME("(%p)->(%s %s): stub\n", This, debugstr_w(prog), debugstr_w(params));
818     return E_NOTIMPL;
819 }
820 
BackgroundCopyJob_GetNotifyCmdLine(IBackgroundCopyJob3 * iface,LPWSTR * prog,LPWSTR * params)821 static HRESULT WINAPI BackgroundCopyJob_GetNotifyCmdLine(
822     IBackgroundCopyJob3 *iface,
823     LPWSTR *prog,
824     LPWSTR *params)
825 {
826     BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob3(iface);
827     FIXME("(%p)->(%p %p): stub\n", This, prog, params);
828     return E_NOTIMPL;
829 }
830 
BackgroundCopyJob_GetReplyProgress(IBackgroundCopyJob3 * iface,BG_JOB_REPLY_PROGRESS * progress)831 static HRESULT WINAPI BackgroundCopyJob_GetReplyProgress(
832     IBackgroundCopyJob3 *iface,
833     BG_JOB_REPLY_PROGRESS *progress)
834 {
835     BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob3(iface);
836     FIXME("(%p)->(%p): stub\n", This, progress);
837     return E_NOTIMPL;
838 }
839 
BackgroundCopyJob_GetReplyData(IBackgroundCopyJob3 * iface,byte ** pBuffer,UINT64 * pLength)840 static HRESULT WINAPI BackgroundCopyJob_GetReplyData(
841     IBackgroundCopyJob3 *iface,
842     byte **pBuffer,
843     UINT64 *pLength)
844 {
845     BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob3(iface);
846     FIXME("(%p)->(%p %p): stub\n", This, pBuffer, pLength);
847     return E_NOTIMPL;
848 }
849 
BackgroundCopyJob_SetReplyFileName(IBackgroundCopyJob3 * iface,LPCWSTR filename)850 static HRESULT WINAPI BackgroundCopyJob_SetReplyFileName(
851     IBackgroundCopyJob3 *iface,
852     LPCWSTR filename)
853 {
854     BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob3(iface);
855     FIXME("(%p)->(%s): stub\n", This, debugstr_w(filename));
856     return E_NOTIMPL;
857 }
858 
BackgroundCopyJob_GetReplyFileName(IBackgroundCopyJob3 * iface,LPWSTR * pFilename)859 static HRESULT WINAPI BackgroundCopyJob_GetReplyFileName(
860     IBackgroundCopyJob3 *iface,
861     LPWSTR *pFilename)
862 {
863     BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob3(iface);
864     FIXME("(%p)->(%p): stub\n", This, pFilename);
865     return E_NOTIMPL;
866 }
867 
index_from_target(BG_AUTH_TARGET target)868 static int index_from_target(BG_AUTH_TARGET target)
869 {
870     if (!target || target > BG_AUTH_TARGET_PROXY) return -1;
871     return target - 1;
872 }
873 
index_from_scheme(BG_AUTH_SCHEME scheme)874 static int index_from_scheme(BG_AUTH_SCHEME scheme)
875 {
876     if (!scheme || scheme > BG_AUTH_SCHEME_PASSPORT) return -1;
877     return scheme - 1;
878 }
879 
BackgroundCopyJob_SetCredentials(IBackgroundCopyJob3 * iface,BG_AUTH_CREDENTIALS * cred)880 static HRESULT WINAPI BackgroundCopyJob_SetCredentials(
881     IBackgroundCopyJob3 *iface,
882     BG_AUTH_CREDENTIALS *cred)
883 {
884     BackgroundCopyJobImpl *job = impl_from_IBackgroundCopyJob3(iface);
885     BG_AUTH_CREDENTIALS *new_cred;
886     int idx_target, idx_scheme;
887 
888     TRACE("(%p)->(%p)\n", job, cred);
889 
890     if ((idx_target = index_from_target(cred->Target)) < 0) return BG_E_INVALID_AUTH_TARGET;
891     if ((idx_scheme = index_from_scheme(cred->Scheme)) < 0) return BG_E_INVALID_AUTH_SCHEME;
892     new_cred = &job->http_options.creds[idx_target][idx_scheme];
893 
894     EnterCriticalSection(&job->cs);
895 
896     new_cred->Target = cred->Target;
897     new_cred->Scheme = cred->Scheme;
898 
899     if (cred->Credentials.Basic.UserName)
900     {
901         HeapFree(GetProcessHeap(), 0, new_cred->Credentials.Basic.UserName);
902         new_cred->Credentials.Basic.UserName = strdupW(cred->Credentials.Basic.UserName);
903     }
904     if (cred->Credentials.Basic.Password)
905     {
906         HeapFree(GetProcessHeap(), 0, new_cred->Credentials.Basic.Password);
907         new_cred->Credentials.Basic.Password = strdupW(cred->Credentials.Basic.Password);
908     }
909 
910     LeaveCriticalSection(&job->cs);
911     return S_OK;
912 }
913 
BackgroundCopyJob_RemoveCredentials(IBackgroundCopyJob3 * iface,BG_AUTH_TARGET target,BG_AUTH_SCHEME scheme)914 static HRESULT WINAPI BackgroundCopyJob_RemoveCredentials(
915     IBackgroundCopyJob3 *iface,
916     BG_AUTH_TARGET target,
917     BG_AUTH_SCHEME scheme)
918 {
919     BackgroundCopyJobImpl *job = impl_from_IBackgroundCopyJob3(iface);
920     BG_AUTH_CREDENTIALS *new_cred;
921     int idx_target, idx_scheme;
922 
923     TRACE("(%p)->(%u %u)\n", job, target, scheme);
924 
925     if ((idx_target = index_from_target(target)) < 0) return BG_E_INVALID_AUTH_TARGET;
926     if ((idx_scheme = index_from_scheme(scheme)) < 0) return BG_E_INVALID_AUTH_SCHEME;
927     new_cred = &job->http_options.creds[idx_target][idx_scheme];
928 
929     EnterCriticalSection(&job->cs);
930 
931     new_cred->Target = new_cred->Scheme = 0;
932     HeapFree(GetProcessHeap(), 0, new_cred->Credentials.Basic.UserName);
933     new_cred->Credentials.Basic.UserName = NULL;
934     HeapFree(GetProcessHeap(), 0, new_cred->Credentials.Basic.Password);
935     new_cred->Credentials.Basic.Password = NULL;
936 
937     LeaveCriticalSection(&job->cs);
938     return S_OK;
939 }
940 
BackgroundCopyJob_ReplaceRemotePrefix(IBackgroundCopyJob3 * iface,LPCWSTR OldPrefix,LPCWSTR NewPrefix)941 static HRESULT WINAPI BackgroundCopyJob_ReplaceRemotePrefix(
942     IBackgroundCopyJob3 *iface,
943     LPCWSTR OldPrefix,
944     LPCWSTR NewPrefix)
945 {
946     BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob3(iface);
947     FIXME("(%p)->(%s %s): stub\n", This, debugstr_w(OldPrefix), debugstr_w(NewPrefix));
948     return S_OK;
949 }
950 
BackgroundCopyJob_AddFileWithRanges(IBackgroundCopyJob3 * iface,LPCWSTR RemoteUrl,LPCWSTR LocalName,DWORD RangeCount,BG_FILE_RANGE Ranges[])951 static HRESULT WINAPI BackgroundCopyJob_AddFileWithRanges(
952     IBackgroundCopyJob3 *iface,
953     LPCWSTR RemoteUrl,
954     LPCWSTR LocalName,
955     DWORD RangeCount,
956     BG_FILE_RANGE Ranges[])
957 {
958     BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob3(iface);
959     FIXME("(%p)->(%s %s %u %p): stub\n", This, debugstr_w(RemoteUrl), debugstr_w(LocalName), RangeCount, Ranges);
960     return S_OK;
961 }
962 
BackgroundCopyJob_SetFileACLFlags(IBackgroundCopyJob3 * iface,DWORD Flags)963 static HRESULT WINAPI BackgroundCopyJob_SetFileACLFlags(
964     IBackgroundCopyJob3 *iface,
965     DWORD Flags)
966 {
967     BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob3(iface);
968     FIXME("(%p)->(%x): stub\n", This, Flags);
969     return S_OK;
970 }
971 
BackgroundCopyJob_GetFileACLFlags(IBackgroundCopyJob3 * iface,DWORD * Flags)972 static HRESULT WINAPI BackgroundCopyJob_GetFileACLFlags(
973     IBackgroundCopyJob3 *iface,
974     DWORD *Flags)
975 {
976     BackgroundCopyJobImpl *This = impl_from_IBackgroundCopyJob3(iface);
977     FIXME("(%p)->(%p): stub\n", This, Flags);
978     return S_OK;
979 }
980 
981 static const IBackgroundCopyJob3Vtbl BackgroundCopyJob3Vtbl =
982 {
983     BackgroundCopyJob_QueryInterface,
984     BackgroundCopyJob_AddRef,
985     BackgroundCopyJob_Release,
986     BackgroundCopyJob_AddFileSet,
987     BackgroundCopyJob_AddFile,
988     BackgroundCopyJob_EnumFiles,
989     BackgroundCopyJob_Suspend,
990     BackgroundCopyJob_Resume,
991     BackgroundCopyJob_Cancel,
992     BackgroundCopyJob_Complete,
993     BackgroundCopyJob_GetId,
994     BackgroundCopyJob_GetType,
995     BackgroundCopyJob_GetProgress,
996     BackgroundCopyJob_GetTimes,
997     BackgroundCopyJob_GetState,
998     BackgroundCopyJob_GetError,
999     BackgroundCopyJob_GetOwner,
1000     BackgroundCopyJob_SetDisplayName,
1001     BackgroundCopyJob_GetDisplayName,
1002     BackgroundCopyJob_SetDescription,
1003     BackgroundCopyJob_GetDescription,
1004     BackgroundCopyJob_SetPriority,
1005     BackgroundCopyJob_GetPriority,
1006     BackgroundCopyJob_SetNotifyFlags,
1007     BackgroundCopyJob_GetNotifyFlags,
1008     BackgroundCopyJob_SetNotifyInterface,
1009     BackgroundCopyJob_GetNotifyInterface,
1010     BackgroundCopyJob_SetMinimumRetryDelay,
1011     BackgroundCopyJob_GetMinimumRetryDelay,
1012     BackgroundCopyJob_SetNoProgressTimeout,
1013     BackgroundCopyJob_GetNoProgressTimeout,
1014     BackgroundCopyJob_GetErrorCount,
1015     BackgroundCopyJob_SetProxySettings,
1016     BackgroundCopyJob_GetProxySettings,
1017     BackgroundCopyJob_TakeOwnership,
1018     BackgroundCopyJob_SetNotifyCmdLine,
1019     BackgroundCopyJob_GetNotifyCmdLine,
1020     BackgroundCopyJob_GetReplyProgress,
1021     BackgroundCopyJob_GetReplyData,
1022     BackgroundCopyJob_SetReplyFileName,
1023     BackgroundCopyJob_GetReplyFileName,
1024     BackgroundCopyJob_SetCredentials,
1025     BackgroundCopyJob_RemoveCredentials,
1026     BackgroundCopyJob_ReplaceRemotePrefix,
1027     BackgroundCopyJob_AddFileWithRanges,
1028     BackgroundCopyJob_SetFileACLFlags,
1029     BackgroundCopyJob_GetFileACLFlags
1030 };
1031 
impl_from_IBackgroundCopyJobHttpOptions(IBackgroundCopyJobHttpOptions * iface)1032 static inline BackgroundCopyJobImpl *impl_from_IBackgroundCopyJobHttpOptions(
1033     IBackgroundCopyJobHttpOptions *iface)
1034 {
1035     return CONTAINING_RECORD(iface, BackgroundCopyJobImpl, IBackgroundCopyJobHttpOptions_iface);
1036 }
1037 
http_options_QueryInterface(IBackgroundCopyJobHttpOptions * iface,REFIID riid,void ** ppvObject)1038 static HRESULT WINAPI http_options_QueryInterface(
1039     IBackgroundCopyJobHttpOptions *iface,
1040     REFIID riid,
1041     void **ppvObject)
1042 {
1043     BackgroundCopyJobImpl *job = impl_from_IBackgroundCopyJobHttpOptions(iface);
1044     return IBackgroundCopyJob3_QueryInterface(&job->IBackgroundCopyJob3_iface, riid, ppvObject);
1045 }
1046 
http_options_AddRef(IBackgroundCopyJobHttpOptions * iface)1047 static ULONG WINAPI http_options_AddRef(
1048     IBackgroundCopyJobHttpOptions *iface)
1049 {
1050     BackgroundCopyJobImpl *job = impl_from_IBackgroundCopyJobHttpOptions(iface);
1051     return IBackgroundCopyJob3_AddRef(&job->IBackgroundCopyJob3_iface);
1052 }
1053 
http_options_Release(IBackgroundCopyJobHttpOptions * iface)1054 static ULONG WINAPI http_options_Release(
1055     IBackgroundCopyJobHttpOptions *iface)
1056 {
1057     BackgroundCopyJobImpl *job = impl_from_IBackgroundCopyJobHttpOptions(iface);
1058     return IBackgroundCopyJob3_Release(&job->IBackgroundCopyJob3_iface);
1059 }
1060 
http_options_SetClientCertificateByID(IBackgroundCopyJobHttpOptions * iface,BG_CERT_STORE_LOCATION StoreLocation,LPCWSTR StoreName,BYTE * pCertHashBlob)1061 static HRESULT WINAPI http_options_SetClientCertificateByID(
1062     IBackgroundCopyJobHttpOptions *iface,
1063     BG_CERT_STORE_LOCATION StoreLocation,
1064     LPCWSTR StoreName,
1065     BYTE *pCertHashBlob)
1066 {
1067     FIXME("\n");
1068     return E_NOTIMPL;
1069 }
1070 
http_options_SetClientCertificateByName(IBackgroundCopyJobHttpOptions * iface,BG_CERT_STORE_LOCATION StoreLocation,LPCWSTR StoreName,LPCWSTR SubjectName)1071 static HRESULT WINAPI http_options_SetClientCertificateByName(
1072     IBackgroundCopyJobHttpOptions *iface,
1073     BG_CERT_STORE_LOCATION StoreLocation,
1074     LPCWSTR StoreName,
1075     LPCWSTR SubjectName)
1076 {
1077     FIXME("\n");
1078     return E_NOTIMPL;
1079 }
1080 
http_options_RemoveClientCertificate(IBackgroundCopyJobHttpOptions * iface)1081 static HRESULT WINAPI http_options_RemoveClientCertificate(
1082     IBackgroundCopyJobHttpOptions *iface)
1083 {
1084     FIXME("\n");
1085     return E_NOTIMPL;
1086 }
1087 
http_options_GetClientCertificate(IBackgroundCopyJobHttpOptions * iface,BG_CERT_STORE_LOCATION * pStoreLocation,LPWSTR * pStoreName,BYTE ** ppCertHashBlob,LPWSTR * pSubjectName)1088 static HRESULT WINAPI http_options_GetClientCertificate(
1089     IBackgroundCopyJobHttpOptions *iface,
1090     BG_CERT_STORE_LOCATION *pStoreLocation,
1091     LPWSTR *pStoreName,
1092     BYTE **ppCertHashBlob,
1093     LPWSTR *pSubjectName)
1094 {
1095     FIXME("\n");
1096     return E_NOTIMPL;
1097 }
1098 
http_options_SetCustomHeaders(IBackgroundCopyJobHttpOptions * iface,LPCWSTR RequestHeaders)1099 static HRESULT WINAPI http_options_SetCustomHeaders(
1100     IBackgroundCopyJobHttpOptions *iface,
1101     LPCWSTR RequestHeaders)
1102 {
1103     BackgroundCopyJobImpl *job = impl_from_IBackgroundCopyJobHttpOptions(iface);
1104 
1105     TRACE("(%p)->(%s)\n", iface, debugstr_w(RequestHeaders));
1106 
1107     EnterCriticalSection(&job->cs);
1108 
1109     if (RequestHeaders)
1110     {
1111         WCHAR *headers = strdupW(RequestHeaders);
1112         if (!headers)
1113         {
1114             LeaveCriticalSection(&job->cs);
1115             return E_OUTOFMEMORY;
1116         }
1117         HeapFree(GetProcessHeap(), 0, job->http_options.headers);
1118         job->http_options.headers = headers;
1119     }
1120     else
1121     {
1122         HeapFree(GetProcessHeap(), 0, job->http_options.headers);
1123         job->http_options.headers = NULL;
1124     }
1125 
1126     LeaveCriticalSection(&job->cs);
1127     return S_OK;
1128 }
1129 
http_options_GetCustomHeaders(IBackgroundCopyJobHttpOptions * iface,LPWSTR * pRequestHeaders)1130 static HRESULT WINAPI http_options_GetCustomHeaders(
1131     IBackgroundCopyJobHttpOptions *iface,
1132     LPWSTR *pRequestHeaders)
1133 {
1134     BackgroundCopyJobImpl *job = impl_from_IBackgroundCopyJobHttpOptions(iface);
1135 
1136     TRACE("(%p)->(%p)\n", iface, pRequestHeaders);
1137 
1138     EnterCriticalSection(&job->cs);
1139 
1140     if (job->http_options.headers)
1141     {
1142         WCHAR *headers = co_strdupW(job->http_options.headers);
1143         if (!headers)
1144         {
1145             LeaveCriticalSection(&job->cs);
1146             return E_OUTOFMEMORY;
1147         }
1148         *pRequestHeaders = headers;
1149         LeaveCriticalSection(&job->cs);
1150         return S_OK;
1151     }
1152 
1153     *pRequestHeaders = NULL;
1154     LeaveCriticalSection(&job->cs);
1155     return S_FALSE;
1156 }
1157 
http_options_SetSecurityFlags(IBackgroundCopyJobHttpOptions * iface,ULONG Flags)1158 static HRESULT WINAPI http_options_SetSecurityFlags(
1159     IBackgroundCopyJobHttpOptions *iface,
1160     ULONG Flags)
1161 {
1162     BackgroundCopyJobImpl *job = impl_from_IBackgroundCopyJobHttpOptions(iface);
1163 
1164     TRACE("(%p)->(0x%08x)\n", iface, Flags);
1165 
1166     job->http_options.flags = Flags;
1167     return S_OK;
1168 }
1169 
http_options_GetSecurityFlags(IBackgroundCopyJobHttpOptions * iface,ULONG * pFlags)1170 static HRESULT WINAPI http_options_GetSecurityFlags(
1171     IBackgroundCopyJobHttpOptions *iface,
1172     ULONG *pFlags)
1173 {
1174     BackgroundCopyJobImpl *job = impl_from_IBackgroundCopyJobHttpOptions(iface);
1175 
1176     TRACE("(%p)->(%p)\n", iface, pFlags);
1177 
1178     *pFlags = job->http_options.flags;
1179     return S_OK;
1180 }
1181 
1182 static const IBackgroundCopyJobHttpOptionsVtbl http_options_vtbl =
1183 {
1184     http_options_QueryInterface,
1185     http_options_AddRef,
1186     http_options_Release,
1187     http_options_SetClientCertificateByID,
1188     http_options_SetClientCertificateByName,
1189     http_options_RemoveClientCertificate,
1190     http_options_GetClientCertificate,
1191     http_options_SetCustomHeaders,
1192     http_options_GetCustomHeaders,
1193     http_options_SetSecurityFlags,
1194     http_options_GetSecurityFlags
1195 };
1196 
BackgroundCopyJobConstructor(LPCWSTR displayName,BG_JOB_TYPE type,GUID * job_id,BackgroundCopyJobImpl ** job)1197 HRESULT BackgroundCopyJobConstructor(LPCWSTR displayName, BG_JOB_TYPE type, GUID *job_id, BackgroundCopyJobImpl **job)
1198 {
1199     HRESULT hr;
1200     BackgroundCopyJobImpl *This;
1201 
1202     TRACE("(%s,%d,%p)\n", debugstr_w(displayName), type, job);
1203 
1204     This = HeapAlloc(GetProcessHeap(), 0, sizeof *This);
1205     if (!This)
1206         return E_OUTOFMEMORY;
1207 
1208     This->IBackgroundCopyJob3_iface.lpVtbl = &BackgroundCopyJob3Vtbl;
1209     This->IBackgroundCopyJobHttpOptions_iface.lpVtbl = &http_options_vtbl;
1210     InitializeCriticalSection(&This->cs);
1211     This->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": BackgroundCopyJobImpl.cs");
1212 
1213     This->ref = 1;
1214     This->type = type;
1215 
1216     This->displayName = strdupW(displayName);
1217     if (!This->displayName)
1218     {
1219         This->cs.DebugInfo->Spare[0] = 0;
1220         DeleteCriticalSection(&This->cs);
1221         HeapFree(GetProcessHeap(), 0, This);
1222         return E_OUTOFMEMORY;
1223     }
1224 
1225     hr = CoCreateGuid(&This->jobId);
1226     if (FAILED(hr))
1227     {
1228         This->cs.DebugInfo->Spare[0] = 0;
1229         DeleteCriticalSection(&This->cs);
1230         HeapFree(GetProcessHeap(), 0, This->displayName);
1231         HeapFree(GetProcessHeap(), 0, This);
1232         return hr;
1233     }
1234     *job_id = This->jobId;
1235 
1236     list_init(&This->files);
1237     This->jobProgress.BytesTotal = 0;
1238     This->jobProgress.BytesTransferred = 0;
1239     This->jobProgress.FilesTotal = 0;
1240     This->jobProgress.FilesTransferred = 0;
1241 
1242     This->state = BG_JOB_STATE_SUSPENDED;
1243     This->description = NULL;
1244     This->notify_flags = BG_NOTIFY_JOB_ERROR | BG_NOTIFY_JOB_TRANSFERRED;
1245     This->callback = NULL;
1246     This->callback2 = FALSE;
1247 
1248     This->error.context = 0;
1249     This->error.code = S_OK;
1250     This->error.file = NULL;
1251 
1252     memset(&This->http_options, 0, sizeof(This->http_options));
1253 
1254     This->wait   = CreateEventW(NULL, FALSE, FALSE, NULL);
1255     This->cancel = CreateEventW(NULL, FALSE, FALSE, NULL);
1256     This->done   = CreateEventW(NULL, FALSE, FALSE, NULL);
1257 
1258     *job = This;
1259 
1260     TRACE("created job %s:%p\n", debugstr_guid(&This->jobId), This);
1261 
1262     return S_OK;
1263 }
1264 
processJob(BackgroundCopyJobImpl * job)1265 void processJob(BackgroundCopyJobImpl *job)
1266 {
1267     for (;;)
1268     {
1269         BackgroundCopyFileImpl *file;
1270         BOOL done = TRUE;
1271 
1272         EnterCriticalSection(&job->cs);
1273         LIST_FOR_EACH_ENTRY(file, &job->files, BackgroundCopyFileImpl, entryFromJob)
1274             if (!file->fileProgress.Completed)
1275             {
1276                 done = FALSE;
1277                 break;
1278             }
1279         LeaveCriticalSection(&job->cs);
1280         if (done)
1281         {
1282             transitionJobState(job, BG_JOB_STATE_QUEUED, BG_JOB_STATE_TRANSFERRED);
1283             return;
1284         }
1285 
1286         if (!processFile(file, job))
1287           return;
1288     }
1289 }
1290