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