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 26 #include "qmgr.h" 27 #include "wine/debug.h" 28 29 WINE_DEFAULT_DEBUG_CHANNEL(qmgr); 30 31 static void BackgroundCopyJobDestructor(BackgroundCopyJobImpl *This) 32 { 33 DeleteCriticalSection(&This->cs); 34 HeapFree(GetProcessHeap(), 0, This->displayName); 35 HeapFree(GetProcessHeap(), 0, This); 36 } 37 38 static ULONG WINAPI BITS_IBackgroundCopyJob_AddRef(IBackgroundCopyJob2 *iface) 39 { 40 BackgroundCopyJobImpl *This = (BackgroundCopyJobImpl *) iface; 41 return InterlockedIncrement(&This->ref); 42 } 43 44 static HRESULT WINAPI BITS_IBackgroundCopyJob_QueryInterface( 45 IBackgroundCopyJob2 *iface, REFIID riid, LPVOID *ppvObject) 46 { 47 BackgroundCopyJobImpl *This = (BackgroundCopyJobImpl *) iface; 48 TRACE("IID: %s\n", debugstr_guid(riid)); 49 50 if (IsEqualGUID(riid, &IID_IUnknown) 51 || IsEqualGUID(riid, &IID_IBackgroundCopyJob) 52 || IsEqualGUID(riid, &IID_IBackgroundCopyJob2)) 53 { 54 *ppvObject = &This->lpVtbl; 55 BITS_IBackgroundCopyJob_AddRef(iface); 56 return S_OK; 57 } 58 59 *ppvObject = NULL; 60 return E_NOINTERFACE; 61 } 62 63 static ULONG WINAPI BITS_IBackgroundCopyJob_Release(IBackgroundCopyJob2 *iface) 64 { 65 BackgroundCopyJobImpl *This = (BackgroundCopyJobImpl *) iface; 66 ULONG ref = InterlockedDecrement(&This->ref); 67 68 if (ref == 0) 69 BackgroundCopyJobDestructor(This); 70 71 return ref; 72 } 73 74 /*** IBackgroundCopyJob methods ***/ 75 76 static HRESULT WINAPI BITS_IBackgroundCopyJob_AddFileSet( 77 IBackgroundCopyJob2 *iface, 78 ULONG cFileCount, 79 BG_FILE_INFO *pFileSet) 80 { 81 ULONG i; 82 for (i = 0; i < cFileCount; ++i) 83 { 84 HRESULT hr = IBackgroundCopyJob_AddFile(iface, pFileSet[i].RemoteName, 85 pFileSet[i].LocalName); 86 if (FAILED(hr)) 87 return hr; 88 } 89 return S_OK; 90 } 91 92 static HRESULT WINAPI BITS_IBackgroundCopyJob_AddFile( 93 IBackgroundCopyJob2 *iface, 94 LPCWSTR RemoteUrl, 95 LPCWSTR LocalName) 96 { 97 BackgroundCopyJobImpl *This = (BackgroundCopyJobImpl *) iface; 98 IBackgroundCopyFile *pFile; 99 BackgroundCopyFileImpl *file; 100 HRESULT res; 101 102 /* We should return E_INVALIDARG in these cases. */ 103 FIXME("Check for valid filenames and supported protocols\n"); 104 105 res = BackgroundCopyFileConstructor(This, RemoteUrl, LocalName, (LPVOID *) &pFile); 106 if (res != S_OK) 107 return res; 108 109 /* Add a reference to the file to file list */ 110 IBackgroundCopyFile_AddRef(pFile); 111 file = (BackgroundCopyFileImpl *) pFile; 112 EnterCriticalSection(&This->cs); 113 list_add_head(&This->files, &file->entryFromJob); 114 This->jobProgress.BytesTotal = BG_SIZE_UNKNOWN; 115 ++This->jobProgress.FilesTotal; 116 LeaveCriticalSection(&This->cs); 117 118 return S_OK; 119 } 120 121 static HRESULT WINAPI BITS_IBackgroundCopyJob_EnumFiles( 122 IBackgroundCopyJob2 *iface, 123 IEnumBackgroundCopyFiles **ppEnum) 124 { 125 TRACE("\n"); 126 return EnumBackgroundCopyFilesConstructor((LPVOID *) ppEnum, iface); 127 } 128 129 static HRESULT WINAPI BITS_IBackgroundCopyJob_Suspend( 130 IBackgroundCopyJob2 *iface) 131 { 132 FIXME("Not implemented\n"); 133 return E_NOTIMPL; 134 } 135 136 static HRESULT WINAPI BITS_IBackgroundCopyJob_Resume( 137 IBackgroundCopyJob2 *iface) 138 { 139 BackgroundCopyJobImpl *This = (BackgroundCopyJobImpl *) iface; 140 HRESULT rv = S_OK; 141 142 EnterCriticalSection(&globalMgr.cs); 143 if (This->state == BG_JOB_STATE_CANCELLED 144 || This->state == BG_JOB_STATE_ACKNOWLEDGED) 145 { 146 rv = BG_E_INVALID_STATE; 147 } 148 else if (This->jobProgress.FilesTransferred == This->jobProgress.FilesTotal) 149 { 150 rv = BG_E_EMPTY; 151 } 152 else if (This->state != BG_JOB_STATE_CONNECTING 153 && This->state != BG_JOB_STATE_TRANSFERRING) 154 { 155 This->state = BG_JOB_STATE_QUEUED; 156 SetEvent(globalMgr.jobEvent); 157 } 158 LeaveCriticalSection(&globalMgr.cs); 159 160 return rv; 161 } 162 163 static HRESULT WINAPI BITS_IBackgroundCopyJob_Cancel( 164 IBackgroundCopyJob2 *iface) 165 { 166 FIXME("Not implemented\n"); 167 return E_NOTIMPL; 168 } 169 170 static HRESULT WINAPI BITS_IBackgroundCopyJob_Complete( 171 IBackgroundCopyJob2 *iface) 172 { 173 BackgroundCopyJobImpl *This = (BackgroundCopyJobImpl *) iface; 174 HRESULT rv = S_OK; 175 176 EnterCriticalSection(&This->cs); 177 178 if (This->state == BG_JOB_STATE_CANCELLED 179 || This->state == BG_JOB_STATE_ACKNOWLEDGED) 180 { 181 rv = BG_E_INVALID_STATE; 182 } 183 else 184 { 185 BackgroundCopyFileImpl *file; 186 LIST_FOR_EACH_ENTRY(file, &This->files, BackgroundCopyFileImpl, entryFromJob) 187 { 188 if (file->fileProgress.Completed) 189 { 190 if (!MoveFileExW(file->tempFileName, file->info.LocalName, 191 (MOVEFILE_COPY_ALLOWED 192 | MOVEFILE_REPLACE_EXISTING 193 | MOVEFILE_WRITE_THROUGH))) 194 { 195 ERR("Couldn't rename file %s -> %s\n", 196 debugstr_w(file->tempFileName), 197 debugstr_w(file->info.LocalName)); 198 rv = BG_S_PARTIAL_COMPLETE; 199 } 200 } 201 else 202 rv = BG_S_PARTIAL_COMPLETE; 203 } 204 } 205 206 This->state = BG_JOB_STATE_ACKNOWLEDGED; 207 LeaveCriticalSection(&This->cs); 208 209 return rv; 210 } 211 212 static HRESULT WINAPI BITS_IBackgroundCopyJob_GetId( 213 IBackgroundCopyJob2 *iface, 214 GUID *pVal) 215 { 216 BackgroundCopyJobImpl *This = (BackgroundCopyJobImpl *) iface; 217 *pVal = This->jobId; 218 return S_OK; 219 } 220 221 static HRESULT WINAPI BITS_IBackgroundCopyJob_GetType( 222 IBackgroundCopyJob2 *iface, 223 BG_JOB_TYPE *pVal) 224 { 225 BackgroundCopyJobImpl *This = (BackgroundCopyJobImpl *) iface; 226 227 if (!pVal) 228 return E_INVALIDARG; 229 230 *pVal = This->type; 231 return S_OK; 232 } 233 234 static HRESULT WINAPI BITS_IBackgroundCopyJob_GetProgress( 235 IBackgroundCopyJob2 *iface, 236 BG_JOB_PROGRESS *pVal) 237 { 238 BackgroundCopyJobImpl *This = (BackgroundCopyJobImpl *) iface; 239 240 if (!pVal) 241 return E_INVALIDARG; 242 243 EnterCriticalSection(&This->cs); 244 pVal->BytesTotal = This->jobProgress.BytesTotal; 245 pVal->BytesTransferred = This->jobProgress.BytesTransferred; 246 pVal->FilesTotal = This->jobProgress.FilesTotal; 247 pVal->FilesTransferred = This->jobProgress.FilesTransferred; 248 LeaveCriticalSection(&This->cs); 249 250 return S_OK; 251 } 252 253 static HRESULT WINAPI BITS_IBackgroundCopyJob_GetTimes( 254 IBackgroundCopyJob2 *iface, 255 BG_JOB_TIMES *pVal) 256 { 257 FIXME("Not implemented\n"); 258 return E_NOTIMPL; 259 } 260 261 static HRESULT WINAPI BITS_IBackgroundCopyJob_GetState( 262 IBackgroundCopyJob2 *iface, 263 BG_JOB_STATE *pVal) 264 { 265 BackgroundCopyJobImpl *This = (BackgroundCopyJobImpl *) iface; 266 267 if (!pVal) 268 return E_INVALIDARG; 269 270 /* Don't think we need a critical section for this */ 271 *pVal = This->state; 272 return S_OK; 273 } 274 275 static HRESULT WINAPI BITS_IBackgroundCopyJob_GetError( 276 IBackgroundCopyJob2 *iface, 277 IBackgroundCopyError **ppError) 278 { 279 FIXME("Not implemented\n"); 280 return E_NOTIMPL; 281 } 282 283 static HRESULT WINAPI BITS_IBackgroundCopyJob_GetOwner( 284 IBackgroundCopyJob2 *iface, 285 LPWSTR *pVal) 286 { 287 FIXME("Not implemented\n"); 288 return E_NOTIMPL; 289 } 290 291 static HRESULT WINAPI BITS_IBackgroundCopyJob_SetDisplayName( 292 IBackgroundCopyJob2 *iface, 293 LPCWSTR Val) 294 { 295 FIXME("Not implemented\n"); 296 return E_NOTIMPL; 297 } 298 299 static HRESULT WINAPI BITS_IBackgroundCopyJob_GetDisplayName( 300 IBackgroundCopyJob2 *iface, 301 LPWSTR *pVal) 302 { 303 BackgroundCopyJobImpl *This = (BackgroundCopyJobImpl *) iface; 304 int n; 305 306 if (!pVal) 307 return E_INVALIDARG; 308 309 n = (lstrlenW(This->displayName) + 1) * sizeof **pVal; 310 *pVal = CoTaskMemAlloc(n); 311 if (*pVal == NULL) 312 return E_OUTOFMEMORY; 313 memcpy(*pVal, This->displayName, n); 314 return S_OK; 315 } 316 317 static HRESULT WINAPI BITS_IBackgroundCopyJob_SetDescription( 318 IBackgroundCopyJob2 *iface, 319 LPCWSTR Val) 320 { 321 FIXME("Not implemented\n"); 322 return E_NOTIMPL; 323 } 324 325 static HRESULT WINAPI BITS_IBackgroundCopyJob_GetDescription( 326 IBackgroundCopyJob2 *iface, 327 LPWSTR *pVal) 328 { 329 FIXME("Not implemented\n"); 330 return E_NOTIMPL; 331 } 332 333 static HRESULT WINAPI BITS_IBackgroundCopyJob_SetPriority( 334 IBackgroundCopyJob2 *iface, 335 BG_JOB_PRIORITY Val) 336 { 337 FIXME("(%p,0x%08x) stub\n", iface, Val); 338 return S_OK; 339 } 340 341 static HRESULT WINAPI BITS_IBackgroundCopyJob_GetPriority( 342 IBackgroundCopyJob2 *iface, 343 BG_JOB_PRIORITY *pVal) 344 { 345 FIXME("Not implemented\n"); 346 return E_NOTIMPL; 347 } 348 349 static HRESULT WINAPI BITS_IBackgroundCopyJob_SetNotifyFlags( 350 IBackgroundCopyJob2 *iface, 351 ULONG Val) 352 { 353 FIXME("Not implemented\n"); 354 return E_NOTIMPL; 355 } 356 357 static HRESULT WINAPI BITS_IBackgroundCopyJob_GetNotifyFlags( 358 IBackgroundCopyJob2 *iface, 359 ULONG *pVal) 360 { 361 FIXME("Not implemented\n"); 362 return E_NOTIMPL; 363 } 364 365 static HRESULT WINAPI BITS_IBackgroundCopyJob_SetNotifyInterface( 366 IBackgroundCopyJob2 *iface, 367 IUnknown *Val) 368 { 369 FIXME("Not implemented\n"); 370 return E_NOTIMPL; 371 } 372 373 static HRESULT WINAPI BITS_IBackgroundCopyJob_GetNotifyInterface( 374 IBackgroundCopyJob2 *iface, 375 IUnknown **pVal) 376 { 377 FIXME("Not implemented\n"); 378 return E_NOTIMPL; 379 } 380 381 static HRESULT WINAPI BITS_IBackgroundCopyJob_SetMinimumRetryDelay( 382 IBackgroundCopyJob2 *iface, 383 ULONG Seconds) 384 { 385 FIXME("%u\n", Seconds); 386 return S_OK; 387 } 388 389 static HRESULT WINAPI BITS_IBackgroundCopyJob_GetMinimumRetryDelay( 390 IBackgroundCopyJob2 *iface, 391 ULONG *Seconds) 392 { 393 FIXME("%p\n", Seconds); 394 *Seconds = 30; 395 return S_OK; 396 } 397 398 static HRESULT WINAPI BITS_IBackgroundCopyJob_SetNoProgressTimeout( 399 IBackgroundCopyJob2 *iface, 400 ULONG Seconds) 401 { 402 FIXME("%u\n", Seconds); 403 return S_OK; 404 } 405 406 static HRESULT WINAPI BITS_IBackgroundCopyJob_GetNoProgressTimeout( 407 IBackgroundCopyJob2 *iface, 408 ULONG *Seconds) 409 { 410 FIXME("%p\n", Seconds); 411 *Seconds = 900; 412 return S_OK; 413 } 414 415 static HRESULT WINAPI BITS_IBackgroundCopyJob_GetErrorCount( 416 IBackgroundCopyJob2 *iface, 417 ULONG *Errors) 418 { 419 FIXME("Not implemented\n"); 420 return E_NOTIMPL; 421 } 422 423 static HRESULT WINAPI BITS_IBackgroundCopyJob_SetProxySettings( 424 IBackgroundCopyJob2 *iface, 425 BG_JOB_PROXY_USAGE ProxyUsage, 426 const WCHAR *ProxyList, 427 const WCHAR *ProxyBypassList) 428 { 429 FIXME("Not implemented\n"); 430 return E_NOTIMPL; 431 } 432 433 static HRESULT WINAPI BITS_IBackgroundCopyJob_GetProxySettings( 434 IBackgroundCopyJob2 *iface, 435 BG_JOB_PROXY_USAGE *pProxyUsage, 436 LPWSTR *pProxyList, 437 LPWSTR *pProxyBypassList) 438 { 439 FIXME("Not implemented\n"); 440 return E_NOTIMPL; 441 } 442 443 static HRESULT WINAPI BITS_IBackgroundCopyJob_TakeOwnership( 444 IBackgroundCopyJob2 *iface) 445 { 446 FIXME("Not implemented\n"); 447 return E_NOTIMPL; 448 } 449 450 static HRESULT WINAPI BITS_IBackgroundCopyJob_SetNotifyCmdLine( 451 IBackgroundCopyJob2 *iface, 452 LPCWSTR prog, 453 LPCWSTR params) 454 { 455 FIXME("Not implemented\n"); 456 return E_NOTIMPL; 457 } 458 459 static HRESULT WINAPI BITS_IBackgroundCopyJob_GetNotifyCmdLine( 460 IBackgroundCopyJob2 *iface, 461 LPWSTR *prog, 462 LPWSTR *params) 463 { 464 FIXME("Not implemented\n"); 465 return E_NOTIMPL; 466 } 467 468 static HRESULT WINAPI BITS_IBackgroundCopyJob_GetReplyProgress( 469 IBackgroundCopyJob2 *iface, 470 BG_JOB_REPLY_PROGRESS *progress) 471 { 472 FIXME("Not implemented\n"); 473 return E_NOTIMPL; 474 } 475 476 static HRESULT WINAPI BITS_IBackgroundCopyJob_GetReplyData( 477 IBackgroundCopyJob2 *iface, 478 byte **pBuffer, 479 UINT64 *pLength) 480 { 481 FIXME("Not implemented\n"); 482 return E_NOTIMPL; 483 } 484 485 static HRESULT WINAPI BITS_IBackgroundCopyJob_SetReplyFileName( 486 IBackgroundCopyJob2 *iface, 487 LPCWSTR filename) 488 { 489 FIXME("Not implemented\n"); 490 return E_NOTIMPL; 491 } 492 493 static HRESULT WINAPI BITS_IBackgroundCopyJob_GetReplyFileName( 494 IBackgroundCopyJob2 *iface, 495 LPWSTR *pFilename) 496 { 497 FIXME("Not implemented\n"); 498 return E_NOTIMPL; 499 } 500 501 static HRESULT WINAPI BITS_IBackgroundCopyJob_SetCredentials( 502 IBackgroundCopyJob2 *iface, 503 BG_AUTH_CREDENTIALS *cred) 504 { 505 FIXME("Not implemented\n"); 506 return S_OK; 507 } 508 509 static HRESULT WINAPI BITS_IBackgroundCopyJob_RemoveCredentials( 510 IBackgroundCopyJob2 *iface, 511 BG_AUTH_TARGET target, 512 BG_AUTH_SCHEME scheme) 513 { 514 FIXME("Not implemented\n"); 515 return S_OK; 516 } 517 518 static const IBackgroundCopyJob2Vtbl BITS_IBackgroundCopyJob_Vtbl = 519 { 520 BITS_IBackgroundCopyJob_QueryInterface, 521 BITS_IBackgroundCopyJob_AddRef, 522 BITS_IBackgroundCopyJob_Release, 523 BITS_IBackgroundCopyJob_AddFileSet, 524 BITS_IBackgroundCopyJob_AddFile, 525 BITS_IBackgroundCopyJob_EnumFiles, 526 BITS_IBackgroundCopyJob_Suspend, 527 BITS_IBackgroundCopyJob_Resume, 528 BITS_IBackgroundCopyJob_Cancel, 529 BITS_IBackgroundCopyJob_Complete, 530 BITS_IBackgroundCopyJob_GetId, 531 BITS_IBackgroundCopyJob_GetType, 532 BITS_IBackgroundCopyJob_GetProgress, 533 BITS_IBackgroundCopyJob_GetTimes, 534 BITS_IBackgroundCopyJob_GetState, 535 BITS_IBackgroundCopyJob_GetError, 536 BITS_IBackgroundCopyJob_GetOwner, 537 BITS_IBackgroundCopyJob_SetDisplayName, 538 BITS_IBackgroundCopyJob_GetDisplayName, 539 BITS_IBackgroundCopyJob_SetDescription, 540 BITS_IBackgroundCopyJob_GetDescription, 541 BITS_IBackgroundCopyJob_SetPriority, 542 BITS_IBackgroundCopyJob_GetPriority, 543 BITS_IBackgroundCopyJob_SetNotifyFlags, 544 BITS_IBackgroundCopyJob_GetNotifyFlags, 545 BITS_IBackgroundCopyJob_SetNotifyInterface, 546 BITS_IBackgroundCopyJob_GetNotifyInterface, 547 BITS_IBackgroundCopyJob_SetMinimumRetryDelay, 548 BITS_IBackgroundCopyJob_GetMinimumRetryDelay, 549 BITS_IBackgroundCopyJob_SetNoProgressTimeout, 550 BITS_IBackgroundCopyJob_GetNoProgressTimeout, 551 BITS_IBackgroundCopyJob_GetErrorCount, 552 BITS_IBackgroundCopyJob_SetProxySettings, 553 BITS_IBackgroundCopyJob_GetProxySettings, 554 BITS_IBackgroundCopyJob_TakeOwnership, 555 BITS_IBackgroundCopyJob_SetNotifyCmdLine, 556 BITS_IBackgroundCopyJob_GetNotifyCmdLine, 557 BITS_IBackgroundCopyJob_GetReplyProgress, 558 BITS_IBackgroundCopyJob_GetReplyData, 559 BITS_IBackgroundCopyJob_SetReplyFileName, 560 BITS_IBackgroundCopyJob_GetReplyFileName, 561 BITS_IBackgroundCopyJob_SetCredentials, 562 BITS_IBackgroundCopyJob_RemoveCredentials 563 }; 564 565 HRESULT BackgroundCopyJobConstructor(LPCWSTR displayName, BG_JOB_TYPE type, 566 GUID *pJobId, LPVOID *ppObj) 567 { 568 HRESULT hr; 569 BackgroundCopyJobImpl *This; 570 int n; 571 572 TRACE("(%s,%d,%p)\n", debugstr_w(displayName), type, ppObj); 573 574 This = HeapAlloc(GetProcessHeap(), 0, sizeof *This); 575 if (!This) 576 return E_OUTOFMEMORY; 577 578 This->lpVtbl = &BITS_IBackgroundCopyJob_Vtbl; 579 InitializeCriticalSection(&This->cs); 580 This->ref = 1; 581 This->type = type; 582 583 n = (lstrlenW(displayName) + 1) * sizeof *displayName; 584 This->displayName = HeapAlloc(GetProcessHeap(), 0, n); 585 if (!This->displayName) 586 { 587 DeleteCriticalSection(&This->cs); 588 HeapFree(GetProcessHeap(), 0, This); 589 return E_OUTOFMEMORY; 590 } 591 memcpy(This->displayName, displayName, n); 592 593 hr = CoCreateGuid(&This->jobId); 594 if (FAILED(hr)) 595 { 596 DeleteCriticalSection(&This->cs); 597 HeapFree(GetProcessHeap(), 0, This->displayName); 598 HeapFree(GetProcessHeap(), 0, This); 599 return hr; 600 } 601 *pJobId = This->jobId; 602 603 list_init(&This->files); 604 This->jobProgress.BytesTotal = 0; 605 This->jobProgress.BytesTransferred = 0; 606 This->jobProgress.FilesTotal = 0; 607 This->jobProgress.FilesTransferred = 0; 608 609 This->state = BG_JOB_STATE_SUSPENDED; 610 611 *ppObj = &This->lpVtbl; 612 return S_OK; 613 } 614 615 void processJob(BackgroundCopyJobImpl *job) 616 { 617 for (;;) 618 { 619 BackgroundCopyFileImpl *file; 620 BOOL done = TRUE; 621 622 EnterCriticalSection(&job->cs); 623 LIST_FOR_EACH_ENTRY(file, &job->files, BackgroundCopyFileImpl, entryFromJob) 624 if (!file->fileProgress.Completed) 625 { 626 done = FALSE; 627 break; 628 } 629 LeaveCriticalSection(&job->cs); 630 if (done) 631 { 632 transitionJobState(job, BG_JOB_STATE_QUEUED, BG_JOB_STATE_TRANSFERRED); 633 return; 634 } 635 636 if (!processFile(file, job)) 637 return; 638 } 639 } 640