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