midimap: Perform stricter error-checking.
[wine] / dlls / 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 <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 }