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 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 53 static inline struct copy_error *impl_from_IBackgroundCopyError(IBackgroundCopyError *iface) 54 { 55 return CONTAINING_RECORD(iface, struct copy_error, IBackgroundCopyError_iface); 56 } 57 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 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 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 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 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 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 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 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 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 = ©_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 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 210 static inline BackgroundCopyJobImpl *impl_from_IBackgroundCopyJob3(IBackgroundCopyJob3 *iface) 211 { 212 return CONTAINING_RECORD(iface, BackgroundCopyJobImpl, IBackgroundCopyJob3_iface); 213 } 214 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 = strlenW(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 strcpyW(This->description, Val); 616 else 617 hr = E_OUTOFMEMORY; 618 } 619 620 LeaveCriticalSection(&This->cs); 621 622 return hr; 623 } 624 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 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 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 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 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 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 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 735 static HRESULT WINAPI BackgroundCopyJob_SetMinimumRetryDelay( 736 IBackgroundCopyJob3 *iface, 737 ULONG Seconds) 738 { 739 FIXME("%u\n", Seconds); 740 return S_OK; 741 } 742 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 1032 static inline BackgroundCopyJobImpl *impl_from_IBackgroundCopyJobHttpOptions( 1033 IBackgroundCopyJobHttpOptions *iface) 1034 { 1035 return CONTAINING_RECORD(iface, BackgroundCopyJobImpl, IBackgroundCopyJobHttpOptions_iface); 1036 } 1037 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 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 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 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 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 1081 static HRESULT WINAPI http_options_RemoveClientCertificate( 1082 IBackgroundCopyJobHttpOptions *iface) 1083 { 1084 FIXME("\n"); 1085 return E_NOTIMPL; 1086 } 1087 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 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 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 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 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 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 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