VirtualBox

source: vbox/trunk/src/VBox/GuestHost/SharedClipboard/clipboard-uri.cpp@ 79347

Last change on this file since 79347 was 79347, checked in by vboxsync, 5 years ago

Shared Clipboard/URI: Update.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 56.6 KB
Line 
1/* $Id: clipboard-uri.cpp 79347 2019-06-26 09:15:29Z vboxsync $ */
2/** @file
3 * Shared Clipboard: Common URI transfer handling code.
4 */
5
6/*
7 * Copyright (C) 2019 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#define LOG_GROUP LOG_GROUP_SHARED_CLIPBOARD
19#include <VBox/log.h>
20
21#include <iprt/path.h>
22
23#include <VBox/err.h>
24#include <VBox/GuestHost/SharedClipboard-uri.h>
25
26
27#ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
28static int sharedClipboardURITransferThreadCreate(PSHAREDCLIPBOARDURITRANSFER pTransfer);
29static int sharedClipboardURITransferThreadDestroy(PSHAREDCLIPBOARDURITRANSFER pTransfer, RTMSINTERVAL uTimeoutMs);
30static int sharedClipboardURITransferReadThread(RTTHREAD hThread, void *pvUser);
31static int sharedClipboardURITransferWriteThread(RTTHREAD hThread, void *pvUser);
32static PSHAREDCLIPBOARDURITRANSFER sharedClipboardURICtxGetTransferInternal(PSHAREDCLIPBOARDURICTX pURI, uint32_t uIdx);
33
34static void sharedClipboardURITransferMetaDataDestroyInternal(PSHAREDCLIPBOARDURITRANSFER pTransfer);
35#endif
36
37
38int SharedClipboardURIDataHdrAlloc(PVBOXCLIPBOARDDATAHDR *ppDataHdr)
39{
40 int rc;
41
42 PVBOXCLIPBOARDDATAHDR pDataHdr = (PVBOXCLIPBOARDDATAHDR)RTMemAllocZ(sizeof(VBOXCLIPBOARDDATAHDR));
43 if (pDataHdr)
44 {
45 PSHAREDCLIPBOARDMETADATAFMTDATA pMetaDataFmt
46 = (PSHAREDCLIPBOARDMETADATAFMTDATA)RTMemAllocZ(sizeof(SHAREDCLIPBOARDMETADATAFMTDATA));
47 if (pMetaDataFmt)
48 {
49 char *pszFmt = NULL;
50 rc = RTStrAAppend(&pszFmt, "VBoxShClURIList");
51 if (RT_SUCCESS(rc))
52 {
53 pMetaDataFmt->uVer = 1;
54 pMetaDataFmt->pvFmt = pszFmt;
55 pMetaDataFmt->cbFmt = (uint32_t)strlen(pszFmt) + 1 /* Include terminating zero */;
56
57 pDataHdr->pvMetaFmt = pMetaDataFmt;
58 pDataHdr->cbMetaFmt = sizeof(SHAREDCLIPBOARDMETADATAFMTDATA) + pMetaDataFmt->cbFmt;
59
60 *ppDataHdr = pDataHdr;
61 }
62 }
63 else
64 rc = VERR_NO_MEMORY;
65
66 if (RT_FAILURE(rc))
67 {
68 RTMemFree(pDataHdr);
69 pDataHdr = NULL;
70 }
71 }
72 else
73 rc = VERR_NO_MEMORY;
74
75 LogFlowFuncLeaveRC(rc);
76 return rc;
77}
78
79/**
80 * Frees a VBOXCLIPBOARDDATAHDR structure.
81 *
82 * @param pDataChunk VBOXCLIPBOARDDATAHDR structure to free.
83 */
84void SharedClipboardURIDataHdrFree(PVBOXCLIPBOARDDATAHDR pDataHdr)
85{
86 if (!pDataHdr)
87 return;
88
89 LogFlowFuncEnter();
90
91 SharedClipboardURIDataHdrDestroy(pDataHdr);
92
93 RTMemFree(pDataHdr);
94 pDataHdr = NULL;
95}
96
97/**
98 * Duplicates (allocates) a VBOXCLIPBOARDDATAHDR structure.
99 *
100 * @returns Duplicated VBOXCLIPBOARDDATAHDR structure on success.
101 * @param pDataHdr VBOXCLIPBOARDDATAHDR to duplicate.
102 */
103PVBOXCLIPBOARDDATAHDR SharedClipboardURIDataHdrDup(PVBOXCLIPBOARDDATAHDR pDataHdr)
104{
105 AssertPtrReturn(pDataHdr, NULL);
106
107 PVBOXCLIPBOARDDATAHDR pDataHdrDup = (PVBOXCLIPBOARDDATAHDR)RTMemAlloc(sizeof(VBOXCLIPBOARDDATAHDR));
108 if (pDataHdrDup)
109 {
110 *pDataHdrDup = *pDataHdr;
111
112 if (pDataHdr->pvMetaFmt)
113 {
114 pDataHdrDup->pvMetaFmt = RTMemDup(pDataHdr->pvMetaFmt, pDataHdr->cbMetaFmt);
115 pDataHdrDup->cbMetaFmt = pDataHdr->cbMetaFmt;
116 }
117
118 if (pDataHdr->pvChecksum)
119 {
120 pDataHdrDup->pvChecksum = RTMemDup(pDataHdr->pvChecksum, pDataHdr->cbChecksum);
121 pDataHdrDup->cbChecksum = pDataHdr->cbChecksum;
122 }
123 }
124
125 return pDataHdrDup;
126}
127
128/**
129 * Returns the size (in bytes) of the announced meta data.
130 *
131 * @returns Announced meta data size in bytes.
132 * @param pDataHdr Data header struct to get announced meta data size for.
133 */
134uint32_t SharedClipboardURIDataHdrGetMetaDataSize(PVBOXCLIPBOARDDATAHDR pDataHdr)
135{
136 AssertPtrReturn(pDataHdr, 0);
137
138 return pDataHdr->cbMeta;
139}
140
141/**
142 * Initializes an URI data header struct.
143 *
144 * @returns VBox status code.
145 * @param pDataHdr Data header struct to initialize.
146 */
147int SharedClipboardURIDataHdrInit(PVBOXCLIPBOARDDATAHDR pDataHdr)
148{
149 AssertPtrReturn(pDataHdr, VERR_INVALID_POINTER);
150
151 SharedClipboardURIDataHdrReset(pDataHdr);
152
153 return VINF_SUCCESS;
154}
155
156/**
157 * Destroys an URI data header struct.
158 *
159 * @param pDataHdr Data header struct to destroy.
160 */
161void SharedClipboardURIDataHdrDestroy(PVBOXCLIPBOARDDATAHDR pDataHdr)
162{
163 if (!pDataHdr)
164 return;
165
166 LogFlowFuncEnter();
167
168 if (pDataHdr->pvMetaFmt)
169 {
170 Assert(pDataHdr->cbMetaFmt);
171
172 RTMemFree(pDataHdr->pvMetaFmt);
173 pDataHdr->pvMetaFmt = NULL;
174 pDataHdr->cbMetaFmt = 0;
175 }
176
177 if (pDataHdr->pvChecksum)
178 {
179 Assert(pDataHdr->cbChecksum);
180
181 RTMemFree(pDataHdr->pvChecksum);
182 pDataHdr->pvChecksum = NULL;
183 pDataHdr->cbChecksum = 0;
184 }
185}
186
187/**
188 * Resets a VBOXCLIPBOARDDATAHDR structture.
189 *
190 * @returns VBox status code.
191 * @param pDataHdr VBOXCLIPBOARDDATAHDR structture to reset.
192 */
193void SharedClipboardURIDataHdrReset(PVBOXCLIPBOARDDATAHDR pDataHdr)
194{
195 AssertPtrReturnVoid(pDataHdr);
196
197 LogFlowFuncEnter();
198
199 RT_BZERO(pDataHdr, sizeof(VBOXCLIPBOARDDATAHDR));
200}
201
202/**
203 * Returns whether a given clipboard data header is valid or not.
204 *
205 * @returns \c true if valid, \c false if not.
206 * @param pDataHdr Clipboard data header to validate.
207 */
208bool SharedClipboardURIDataHdrIsValid(PVBOXCLIPBOARDDATAHDR pDataHdr)
209{
210 RT_NOREF(pDataHdr);
211 return true; /** @todo Implement this. */
212}
213
214/**
215 * Creates (allocates) and initializes a VBOXCLIPBOARDDATACHUNK structure.
216 *
217 * @param ppDirData Where to return the created VBOXCLIPBOARDDATACHUNK structure on success.
218 */
219int SharedClipboardURIDataChunkAlloc(PVBOXCLIPBOARDDATACHUNK *ppDataChunk)
220{
221 PVBOXCLIPBOARDDATACHUNK pDataChunk = (PVBOXCLIPBOARDDATACHUNK)RTMemAlloc(sizeof(VBOXCLIPBOARDDATACHUNK));
222 if (!pDataChunk)
223 return VERR_NO_MEMORY;
224
225 int rc = SharedClipboardURIDataChunkInit(pDataChunk);
226 if (RT_SUCCESS(rc))
227 *ppDataChunk = pDataChunk;
228
229 return rc;
230}
231
232/**
233 * Frees a VBOXCLIPBOARDDATACHUNK structure.
234 *
235 * @param pDataChunk VBOXCLIPBOARDDATACHUNK structure to free.
236 */
237void SharedClipboardURIDataChunkFree(PVBOXCLIPBOARDDATACHUNK pDataChunk)
238{
239 if (!pDataChunk)
240 return;
241
242 SharedClipboardURIDataChunkDestroy(pDataChunk);
243 RTMemFree(pDataChunk);
244}
245
246/**
247 * Initializes a VBOXCLIPBOARDDATACHUNK structure.
248 *
249 * @param pDataChunk VBOXCLIPBOARDDATACHUNK structure to initialize.
250 */
251int SharedClipboardURIDataChunkInit(PVBOXCLIPBOARDDATACHUNK pDataChunk)
252{
253 RT_BZERO(pDataChunk, sizeof(VBOXCLIPBOARDDATACHUNK));
254
255 return VINF_SUCCESS;
256}
257
258/**
259 * Initializes a VBOXCLIPBOARDDATACHUNK structure.
260 *
261 * @param pDataChunk VBOXCLIPBOARDDATACHUNK structure to destroy.
262 */
263void SharedClipboardURIDataChunkDestroy(PVBOXCLIPBOARDDATACHUNK pDataChunk)
264{
265 if (pDataChunk->pvData)
266 {
267 RTMemFree(pDataChunk->pvData);
268 pDataChunk->pvData = NULL;
269 pDataChunk->cbData = 0;
270 }
271
272 if (pDataChunk->pvChecksum)
273 {
274 RTMemFree(pDataChunk->pvChecksum);
275 pDataChunk->pvChecksum = NULL;
276 pDataChunk->cbChecksum = 0;
277 }
278}
279
280/**
281 * Returns whether a given clipboard data chunk is valid or not.
282 *
283 * @returns \c true if valid, \c false if not.
284 * @param pDataChunk Clipboard data chunk to validate.
285 */
286bool SharedClipboardURIDataChunkIsValid(PVBOXCLIPBOARDDATACHUNK pDataChunk)
287{
288 RT_NOREF(pDataChunk);
289
290 /** @todo Verify checksum. */
291
292 return true; /** @todo Implement this. */
293}
294
295/**
296 * Creates (allocates) and initializes a VBOXCLIPBOARDDIRDATA structure.
297 *
298 * @param ppDirData Where to return the created VBOXCLIPBOARDDIRDATA structure on success.
299 */
300int SharedClipboardURIDirDataAlloc(PVBOXCLIPBOARDDIRDATA *ppDirData)
301{
302 PVBOXCLIPBOARDDIRDATA pDirData = (PVBOXCLIPBOARDDIRDATA)RTMemAlloc(sizeof(VBOXCLIPBOARDDIRDATA));
303 if (!pDirData)
304 return VERR_NO_MEMORY;
305
306 int rc = SharedClipboardURIDirDataInit(pDirData);
307 if (RT_SUCCESS(rc))
308 *ppDirData = pDirData;
309
310 return rc;
311}
312
313/**
314 * Frees a VBOXCLIPBOARDDIRDATA structure.
315 *
316 * @param pDirData Where to return the created VBOXCLIPBOARDDIRDATA structure on success.
317 */
318void SharedClipboardURIDirDataFree(PVBOXCLIPBOARDDIRDATA pDirData)
319{
320 if (!pDirData)
321 return;
322
323 SharedClipboardURIDirDataDestroy(pDirData);
324 RTMemFree(pDirData);
325}
326
327/**
328 * Initializes a VBOXCLIPBOARDDIRDATA structure.
329 *
330 * @param pDirData VBOXCLIPBOARDDIRDATA structure to initialize.
331 */
332int SharedClipboardURIDirDataInit(PVBOXCLIPBOARDDIRDATA pDirData)
333{
334 RT_BZERO(pDirData, sizeof(VBOXCLIPBOARDDIRDATA));
335
336 return VINF_SUCCESS;
337}
338
339/**
340 * Destroys a VBOXCLIPBOARDDIRDATA structure.
341 *
342 * @param pDirData VBOXCLIPBOARDDIRDATA structure to destroy.
343 */
344void SharedClipboardURIDirDataDestroy(PVBOXCLIPBOARDDIRDATA pDirData)
345{
346 if (!pDirData)
347 return;
348
349 if (pDirData->pszPath)
350 {
351 Assert(pDirData->cbPath);
352 RTStrFree(pDirData->pszPath);
353 pDirData->pszPath = NULL;
354 }
355}
356
357/**
358 * Duplicates (allocates) a VBOXCLIPBOARDDIRDATA structure.
359 *
360 * @returns Duplicated VBOXCLIPBOARDDIRDATA structure on success.
361 * @param pDirData VBOXCLIPBOARDDIRDATA to duplicate.
362 */
363PVBOXCLIPBOARDDIRDATA SharedClipboardURIDirDataDup(PVBOXCLIPBOARDDIRDATA pDirData)
364{
365 AssertPtrReturn(pDirData, NULL);
366
367 PVBOXCLIPBOARDDIRDATA pDirDataDup = (PVBOXCLIPBOARDDIRDATA)RTMemAllocZ(sizeof(VBOXCLIPBOARDDIRDATA));
368 if (pDirDataDup)
369 {
370 *pDirDataDup = *pDirData;
371
372 if (pDirData->pszPath)
373 {
374 pDirDataDup->pszPath = RTStrDup(pDirData->pszPath);
375 if (pDirDataDup->pszPath)
376 pDirDataDup->cbPath = pDirData->cbPath;
377 }
378 }
379
380 return pDirDataDup;
381}
382
383/**
384 * Returns whether given clipboard directory data is valid or not.
385 *
386 * @returns \c true if valid, \c false if not.
387 * @param pDirData Clipboard directory data to validate.
388 */
389bool SharedClipboardURIDirDataIsValid(PVBOXCLIPBOARDDIRDATA pDirData)
390{
391 if ( !pDirData->cbPath
392 || pDirData->cbPath > RTPATH_MAX)
393 return false;
394
395 if (!RTStrIsValidEncoding(pDirData->pszPath))
396 return false;
397
398 return true;
399}
400
401/**
402 * Initializes a VBOXCLIPBOARDFILEHDR structure.
403 *
404 * @param pDirData VBOXCLIPBOARDFILEHDR structure to initialize.
405 */
406int SharedClipboardURIFileHdrInit(PVBOXCLIPBOARDFILEHDR pFileHdr)
407{
408 RT_BZERO(pFileHdr, sizeof(VBOXCLIPBOARDFILEHDR));
409
410 return VINF_SUCCESS;
411}
412
413/**
414 * Destroys a VBOXCLIPBOARDFILEHDR structure.
415 *
416 * @param pFileHdr VBOXCLIPBOARDFILEHDR structure to destroy.
417 */
418void SharedClipboardURIFileHdrDestroy(PVBOXCLIPBOARDFILEHDR pFileHdr)
419{
420 if (!pFileHdr)
421 return;
422
423 if (pFileHdr->pszFilePath)
424 {
425 Assert(pFileHdr->pszFilePath);
426 RTStrFree(pFileHdr->pszFilePath);
427 pFileHdr->pszFilePath = NULL;
428 }
429}
430
431/**
432 * Frees a VBOXCLIPBOARDFILEHDR structure.
433 *
434 * @param pFileHdr VBOXCLIPBOARDFILEHDR structure to free.
435 */
436void SharedClipboardURIFileHdrFree(PVBOXCLIPBOARDFILEHDR pFileHdr)
437{
438 if (!pFileHdr)
439 return;
440
441 SharedClipboardURIFileHdrDestroy(pFileHdr);
442
443 RTMemFree(pFileHdr);
444 pFileHdr = NULL;
445}
446
447/**
448 * Duplicates (allocates) a VBOXCLIPBOARDFILEHDR structure.
449 *
450 * @returns Duplicated VBOXCLIPBOARDFILEHDR structure on success.
451 * @param pFileHdr VBOXCLIPBOARDFILEHDR to duplicate.
452 */
453PVBOXCLIPBOARDFILEHDR SharedClipboardURIFileHdrDup(PVBOXCLIPBOARDFILEHDR pFileHdr)
454{
455 AssertPtrReturn(pFileHdr, NULL);
456
457 PVBOXCLIPBOARDFILEHDR pFileHdrDup = (PVBOXCLIPBOARDFILEHDR)RTMemAllocZ(sizeof(VBOXCLIPBOARDFILEHDR));
458 if (pFileHdrDup)
459 {
460 *pFileHdrDup = *pFileHdr;
461
462 if (pFileHdr->pszFilePath)
463 {
464 pFileHdrDup->pszFilePath = RTStrDup(pFileHdr->pszFilePath);
465 if (pFileHdrDup->pszFilePath)
466 pFileHdrDup->cbFilePath = pFileHdrDup->cbFilePath;
467 }
468 }
469
470 return pFileHdrDup;
471}
472
473/**
474 * Returns whether a given clipboard file header is valid or not.
475 *
476 * @returns \c true if valid, \c false if not.
477 * @param pFileHdr Clipboard file header to validate.
478 * @param pDataHdr Data header to use for validation.
479 */
480bool SharedClipboardURIFileHdrIsValid(PVBOXCLIPBOARDFILEHDR pFileHdr, PVBOXCLIPBOARDDATAHDR pDataHdr)
481{
482 if ( !pFileHdr->cbFilePath
483 || pFileHdr->cbFilePath > RTPATH_MAX)
484 return false;
485
486 if (!RTStrIsValidEncoding(pFileHdr->pszFilePath))
487 return false;
488
489 if (pFileHdr->cbSize > pDataHdr->cbTotal)
490 return false;
491
492 return true;
493}
494
495/**
496 * Destroys a VBOXCLIPBOARDFILEDATA structure.
497 *
498 * @param pFileData VBOXCLIPBOARDFILEDATA structure to destroy.
499 */
500void SharedClipboardURIFileDataDestroy(PVBOXCLIPBOARDFILEDATA pFileData)
501{
502 if (!pFileData)
503 return;
504
505 if (pFileData->pvData)
506 {
507 Assert(pFileData->cbData);
508 RTMemFree(pFileData->pvData);
509 pFileData->pvData = NULL;
510 }
511}
512
513/**
514 * Duplicates (allocates) a VBOXCLIPBOARDFILEDATA structure.
515 *
516 * @returns Duplicated VBOXCLIPBOARDFILEDATA structure on success.
517 * @param pFileData VBOXCLIPBOARDFILEDATA to duplicate.
518 */
519PVBOXCLIPBOARDFILEDATA SharedClipboardURIFileDataDup(PVBOXCLIPBOARDFILEDATA pFileData)
520{
521 AssertPtrReturn(pFileData, NULL);
522
523 PVBOXCLIPBOARDFILEDATA pFileDataDup = (PVBOXCLIPBOARDFILEDATA)RTMemAllocZ(sizeof(VBOXCLIPBOARDFILEDATA));
524 if (pFileDataDup)
525 {
526 *pFileDataDup = *pFileData;
527
528 if (pFileData->pvData)
529 {
530 pFileDataDup->pvData = RTMemDup(pFileData->pvData, pFileData->cbData);
531 if (pFileDataDup->pvData)
532 pFileDataDup->cbData = pFileDataDup->cbData;
533 }
534
535 if (pFileData->pvChecksum)
536 {
537 pFileDataDup->pvChecksum = RTMemDup(pFileData->pvChecksum, pFileData->cbChecksum);
538 if (pFileDataDup->pvChecksum)
539 pFileDataDup->cbChecksum = pFileData->cbChecksum;
540 }
541 }
542
543 return pFileDataDup;
544}
545
546/**
547 * Returns whether given clipboard file data is valid or not.
548 *
549 * @returns \c true if valid, \c false if not.
550 * @param pFileData Clipboard file data to validate.
551 * @param pDataHdr Data header to use for validation.
552 */
553bool SharedClipboardURIFileDataIsValid(PVBOXCLIPBOARDFILEDATA pFileData, PVBOXCLIPBOARDDATAHDR pDataHdr)
554{
555 RT_NOREF(pFileData, pDataHdr);
556 return true;
557}
558
559/**
560 * Initializes an URI object context.
561 *
562 * @returns VBox status code.
563 * @param pObjCtx URI object context to initialize.
564 */
565int SharedClipboardURIObjCtxInit(PSHAREDCLIPBOARDCLIENTURIOBJCTX pObjCtx)
566{
567 AssertPtrReturn(pObjCtx, VERR_INVALID_POINTER);
568
569 LogFlowFuncEnter();
570
571 pObjCtx->pObj = NULL;
572
573 return VINF_SUCCESS;
574}
575
576/**
577 * Destroys an URI object context.
578 *
579 * @param pObjCtx URI object context to destroy.
580 */
581void SharedClipboardURIObjCtxDestroy(PSHAREDCLIPBOARDCLIENTURIOBJCTX pObjCtx)
582{
583 AssertPtrReturnVoid(pObjCtx);
584
585 LogFlowFuncEnter();
586
587 if (pObjCtx->pObj)
588 {
589 pObjCtx->pObj->Close();
590 /* Note: Do *not* delete pObj here -- the associated URI list will do this. */
591 }
592
593 pObjCtx->pObj = NULL;
594}
595
596/**
597 * Returns the URI object context's URI object.
598 *
599 * @returns Pointer to the URI object context's URI object.
600 * @param pObjCtx URI object context to return the URI object for.
601 */
602SharedClipboardURIObject *SharedClipboardURIObjCtxGetObj(PSHAREDCLIPBOARDCLIENTURIOBJCTX pObjCtx)
603{
604 AssertPtrReturn(pObjCtx, NULL);
605 return pObjCtx->pObj;
606}
607
608/**
609 * Returns if an URI object context is valid or not.
610 *
611 * @returns \c true if valid, \c false if not.
612 * @param pObjCtx URI object context to check.
613 */
614bool SharedClipboardURIObjCtxIsValid(PSHAREDCLIPBOARDCLIENTURIOBJCTX pObjCtx)
615{
616 return ( pObjCtx
617 && pObjCtx->pObj
618 && pObjCtx->pObj->IsComplete() == false
619 && pObjCtx->pObj->IsOpen());
620}
621
622/**
623 * Initializes an URI clipboard transfer struct.
624 *
625 * @returns VBox status code.
626 * @param enmDir Specifies the transfer direction of this transfer.
627 * @param enmSource Specifies the data source of the transfer.
628 * @param ppTransfer Where to return the created URI transfer struct.
629 * Must be destroyed by SharedClipboardURITransferDestroy().
630 */
631int SharedClipboardURITransferCreate(SHAREDCLIPBOARDURITRANSFERDIR enmDir, SHAREDCLIPBOARDSOURCE enmSource,
632 PSHAREDCLIPBOARDURITRANSFER *ppTransfer)
633{
634 AssertPtrReturn(ppTransfer, VERR_INVALID_POINTER);
635
636 LogFlowFuncEnter();
637
638 PSHAREDCLIPBOARDURITRANSFER pTransfer = (PSHAREDCLIPBOARDURITRANSFER)RTMemAlloc(sizeof(SHAREDCLIPBOARDURITRANSFER));
639 if (!pTransfer)
640 return VERR_NO_MEMORY;
641
642 int rc = VINF_SUCCESS;
643
644 pTransfer->State.enmStatus = SHAREDCLIPBOARDURITRANSFERSTATUS_NONE;
645 pTransfer->State.enmDir = enmDir;
646 pTransfer->State.enmSource = enmSource;
647
648 LogFlowFunc(("enmDir=%RU32, enmSource=%RU32\n", pTransfer->State.enmDir, pTransfer->State.enmSource));
649
650 pTransfer->State.pHeader = NULL;
651 pTransfer->State.pMeta = NULL;
652 pTransfer->pArea = NULL; /* Will be created later if needed. */
653
654 pTransfer->Thread.hThread = NIL_RTTHREAD;
655 pTransfer->Thread.fCancelled = false;
656 pTransfer->Thread.fStarted = false;
657
658 pTransfer->pvUser = NULL;
659 pTransfer->cbUser = 0;
660
661 RT_ZERO(pTransfer->Callbacks);
662
663 pTransfer->pURIList = new SharedClipboardURIList();
664 if (!pTransfer->pURIList)
665 {
666 RTMemFree(pTransfer);
667 return VERR_NO_MEMORY;
668 }
669
670 rc = SharedClipboardURIObjCtxInit(&pTransfer->State.ObjCtx);
671 if (RT_SUCCESS(rc))
672 {
673 *ppTransfer = pTransfer;
674 }
675
676 LogFlowFuncLeaveRC(rc);
677 return rc;
678}
679
680/**
681 * Destroys an URI clipboard transfer context struct.
682 *
683 * @returns VBox status code.
684 * @param pURI URI clipboard transfer to destroy.
685 */
686int SharedClipboardURITransferDestroy(PSHAREDCLIPBOARDURITRANSFER pTransfer)
687{
688 if (!pTransfer)
689 return VINF_SUCCESS;
690
691 LogFlowFuncEnter();
692
693 int rc = sharedClipboardURITransferThreadDestroy(pTransfer, 30 * 1000 /* Timeout in ms */);
694 if (RT_FAILURE(rc))
695 return rc;
696
697 SharedClipboardURIDataHdrDestroy(pTransfer->State.pHeader);
698 SharedClipboardMetaDataDestroy(pTransfer->State.pMeta);
699
700 if (pTransfer->pURIList)
701 {
702 delete pTransfer->pURIList;
703 pTransfer->pURIList = NULL;
704 }
705
706 SharedClipboardURIObjCtxDestroy(&pTransfer->State.ObjCtx);
707
708 RTMemFree(pTransfer);
709 pTransfer = NULL;
710
711 LogFlowFuncLeave();
712
713 return VINF_SUCCESS;
714}
715
716/**
717 * Prepares everything needed for a read / write transfer to begin.
718 *
719 * @returns VBox status code.
720 * @param pTransfer URI clipboard transfer to prepare.
721 */
722int SharedClipboardURITransferPrepare(PSHAREDCLIPBOARDURITRANSFER pTransfer)
723{
724 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
725
726 LogFlowFuncEnter();
727
728 int rc = VINF_SUCCESS;
729
730 LogFlowFunc(("pTransfer=%p, enmDir=%RU32\n", pTransfer, pTransfer->State.enmDir));
731
732 if (pTransfer->Callbacks.pfnTransferPrepare)
733 {
734 SHAREDCLIPBOARDURITRANSFERCALLBACKDATA callbackData = { pTransfer, pTransfer->Callbacks.pvUser };
735 pTransfer->Callbacks.pfnTransferPrepare(&callbackData);
736 }
737
738 if (pTransfer->State.enmDir == SHAREDCLIPBOARDURITRANSFERDIR_READ)
739 {
740 if (pTransfer->ProviderIface.pfnPrepare)
741 rc = pTransfer->ProviderIface.pfnPrepare(&pTransfer->ProviderCtx);
742 #if 0
743 rc = pTransfer->pURIList->SetFromURIData(SharedClipboardMetaDataRaw(pMeta),
744 SharedClipboardMetaDataGetUsed(pMeta),
745 SHAREDCLIPBOARDURILIST_FLAGS_NONE);
746 /** @todo Verify pvMetaFmt. */
747 #endif
748
749 sharedClipboardURITransferMetaDataDestroyInternal(pTransfer);
750 }
751 else if (pTransfer->State.enmDir == SHAREDCLIPBOARDURITRANSFERDIR_WRITE)
752 {
753 if ( pTransfer->State.pMeta
754 && pTransfer->pURIList)
755 {
756 const PSHAREDCLIPBOARDMETADATA pMeta = pTransfer->State.pMeta;
757
758 rc = pTransfer->pURIList->AppendURIPathsFromList((char *)SharedClipboardMetaDataRaw(pMeta),
759 SharedClipboardMetaDataGetUsed(pMeta),
760 SHAREDCLIPBOARDURILIST_FLAGS_KEEP_OPEN);
761 if (RT_SUCCESS(rc))
762 {
763 PVBOXCLIPBOARDDATAHDR pHeader;
764 rc = SharedClipboardURIDataHdrAlloc(&pHeader);
765 if (RT_SUCCESS(rc))
766 {
767 /* The total size also contains the size of the meta data. */
768 uint64_t cbTotal = pMeta->cbUsed;
769 cbTotal += pTransfer->pURIList->GetTotalBytes();
770
771 pHeader->cbTotal = cbTotal;
772 pHeader->cbMeta = (uint32_t)SharedClipboardMetaDataGetUsed(pMeta);
773 pHeader->cObjects = pTransfer->pURIList->GetTotalCount();
774
775 SharedClipboardURIDataHdrDestroy(pTransfer->State.pHeader);
776
777 if (RT_SUCCESS(rc))
778 {
779 LogFlowFunc(("Writing cbTotal=%RU64, cbMeta=%RU32, cObj=%RU64\n",
780 pHeader->cbTotal, pHeader->cbMeta, pHeader->cObjects));
781
782 pTransfer->State.pHeader = pHeader;
783 }
784 else
785 SharedClipboardURIDataHdrFree(pHeader);
786 }
787 }
788 }
789 else
790 rc = VERR_WRONG_ORDER;
791 }
792 else
793 {
794 rc = VERR_NOT_IMPLEMENTED;
795 AssertFailed();
796 }
797
798 if (RT_SUCCESS(rc))
799 {
800 /** @todo Add checksum support. */
801 }
802
803 LogFlowFuncLeaveRC(rc);
804 return rc;
805}
806
807/**
808 * Creates an URI provider for a given transfer.
809 *
810 * @returns VBox status code.
811 * @param pTransfer Transfer to create URI provider for.
812 * @param pCreationCtx Provider creation context to use for provider creation.
813 */
814int SharedClipboardURITransferProviderCreate(PSHAREDCLIPBOARDURITRANSFER pTransfer,
815 PSHAREDCLIPBOARDPROVIDERCREATIONCTX pCreationCtx)
816{
817 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
818 AssertPtrReturn(pCreationCtx, VERR_INVALID_POINTER);
819
820 LogFlowFuncEnter();
821
822 int rc = VINF_SUCCESS;
823
824 pTransfer->ProviderIface = pCreationCtx->Interface;
825
826 pTransfer->ProviderCtx.pTransfer = pTransfer;
827 pTransfer->ProviderCtx.pvUser = pCreationCtx->pvUser;
828
829 LogFlowFuncLeaveRC(rc);
830 return rc;
831}
832
833/**
834 * Resets an clipboard URI transfer.
835 *
836 * @param pTransfer URI clipboard transfer to reset.
837 */
838void SharedClipboardURITransferReset(PSHAREDCLIPBOARDURITRANSFER pTransfer)
839{
840 AssertPtrReturnVoid(pTransfer);
841
842 LogFlowFuncEnter();
843
844 /** @todo Anything else to do here? */
845
846 if (pTransfer->pURIList)
847 pTransfer->pURIList->Clear();
848
849 SharedClipboardURIObjCtxDestroy(&pTransfer->State.ObjCtx);
850}
851
852/**
853 * Returns the clipboard area for a clipboard URI transfer.
854 *
855 * @returns Current clipboard area, or NULL if none.
856 * @param pTransfer URI clipboard transfer to return clipboard area for.
857 */
858SharedClipboardArea *SharedClipboardURITransferGetArea(PSHAREDCLIPBOARDURITRANSFER pTransfer)
859{
860 AssertPtrReturn(pTransfer, NULL);
861
862 return pTransfer->pArea;
863}
864
865/**
866 * Returns the current object context of a clipboard URI transfer.
867 *
868 * @returns Current object context, or NULL if none.
869 * @param pTransfer URI clipboard transfer to return object context for.
870 */
871PSHAREDCLIPBOARDCLIENTURIOBJCTX SharedClipboardURITransferGetCurrentObjCtx(PSHAREDCLIPBOARDURITRANSFER pTransfer)
872{
873 /* At the moment we only have one object context per transfer at a time. */
874 return &pTransfer->State.ObjCtx;
875}
876
877/**
878 * Returns the current URI object for a clipboard URI transfer.
879 *
880 * @returns Current URI object, or NULL if none.
881 * @param pTransfer URI clipboard transfer to return current URI object for.
882 */
883const SharedClipboardURIObject *SharedClipboardURITransferGetCurrentObject(PSHAREDCLIPBOARDURITRANSFER pTransfer)
884{
885 AssertPtrReturn(pTransfer, NULL);
886
887 if (pTransfer->pURIList)
888 return pTransfer->pURIList->First();
889
890 return NULL;
891}
892
893/**
894 * Returns the URI list for a clipboard URI transfer.
895 *
896 * @returns Pointer to URI list.
897 * @param pTransfer URI clipboard transfer to return URI list for.
898 */
899SharedClipboardURIList *SharedClipboardURITransferGetList(PSHAREDCLIPBOARDURITRANSFER pTransfer)
900{
901 AssertPtrReturn(pTransfer, NULL);
902
903 return pTransfer->pURIList;
904}
905
906/**
907 * Returns the current URI object for a clipboard URI transfer.
908 *
909 * @returns Pointer to URI object.
910 * @param pTransfer URI clipboard transfer to return URI object for.
911 */
912SharedClipboardURIObject *SharedClipboardURITransferGetObject(PSHAREDCLIPBOARDURITRANSFER pTransfer, uint64_t uIdx)
913{
914 AssertPtrReturn(pTransfer, NULL);
915
916 if (!pTransfer->pURIList)
917 return NULL;
918
919 return pTransfer->pURIList->At(uIdx);
920}
921
922SHAREDCLIPBOARDSOURCE SharedClipboardURITransferGetSource(PSHAREDCLIPBOARDURITRANSFER pTransfer)
923{
924 AssertPtrReturn(pTransfer, SHAREDCLIPBOARDSOURCE_INVALID);
925
926 return pTransfer->State.enmSource;
927}
928
929/**
930 * Returns the current transfer status.
931 *
932 * @returns Current transfer status.
933 * @param pTransfer URI clipboard transfer to return status for.
934 */
935SHAREDCLIPBOARDURITRANSFERSTATUS SharedClipboardURITransferGetStatus(PSHAREDCLIPBOARDURITRANSFER pTransfer)
936{
937 AssertPtrReturn(pTransfer, SHAREDCLIPBOARDURITRANSFERSTATUS_NONE);
938
939 return pTransfer->State.enmStatus;
940}
941
942/**
943 * Runs (starts) an URI transfer, either in synchronous or asynchronous (threaded) mode.
944 *
945 * @returns VBox status code.
946 * @param pTransfer URI clipboard transfer to run.
947 * @param fAsync Whether to run the transfer synchronously or asynchronously.
948 */
949int SharedClipboardURITransferRun(PSHAREDCLIPBOARDURITRANSFER pTransfer, bool fAsync)
950{
951 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
952
953 int rc;
954
955 LogFlowFunc(("fAsync=%RTbool\n", fAsync));
956
957 if (fAsync)
958 {
959 rc = sharedClipboardURITransferThreadCreate(pTransfer);
960 }
961 else
962 {
963 if (pTransfer->State.enmDir == SHAREDCLIPBOARDURITRANSFERDIR_READ)
964 rc = SharedClipboardURITransferRead(pTransfer);
965 else if (pTransfer->State.enmDir == SHAREDCLIPBOARDURITRANSFERDIR_WRITE)
966 rc = SharedClipboardURITransferWrite(pTransfer);
967 else
968 rc = VERR_NOT_IMPLEMENTED;
969 }
970
971 LogFlowFuncLeaveRC(rc);
972 return rc;
973}
974
975/**
976 * Sets or unsets the callback table to be used for a clipboard URI transfer.
977 *
978 * @returns VBox status code.
979 * @param pTransfer URI clipboard transfer to set callbacks for.
980 * @param pCallbacks Pointer to callback table to set.
981 */
982void SharedClipboardURITransferSetCallbacks(PSHAREDCLIPBOARDURITRANSFER pTransfer,
983 PSHAREDCLIPBOARDURITRANSFERCALLBACKS pCallbacks)
984{
985 AssertPtrReturnVoid(pTransfer);
986 AssertPtrReturnVoid(pCallbacks);
987
988 LogFlowFunc(("pCallbacks=%p\n", pCallbacks));
989
990#define SET_CALLBACK(a_pfnCallback) \
991 if (pCallbacks->a_pfnCallback) \
992 pTransfer->Callbacks.a_pfnCallback = pCallbacks->a_pfnCallback
993
994 SET_CALLBACK(pfnTransferPrepare);
995 SET_CALLBACK(pfnTransferStarted);
996 SET_CALLBACK(pfnDataHeaderComplete);
997 SET_CALLBACK(pfnDataComplete);
998 SET_CALLBACK(pfnTransferCanceled);
999 SET_CALLBACK(pfnTransferError);
1000 SET_CALLBACK(pfnTransferStarted);
1001
1002#undef SET_CALLBACK
1003
1004 pTransfer->Callbacks.pvUser = pCallbacks->pvUser;
1005}
1006
1007int SharedClipboardURITransferSetDataHeader(PSHAREDCLIPBOARDURITRANSFER pTransfer, PVBOXCLIPBOARDDATAHDR pDataHdr)
1008{
1009 AssertReturn(pTransfer->State.pHeader == NULL, VERR_WRONG_ORDER);
1010
1011 LogFlowFuncEnter();
1012
1013 int rc;
1014
1015 pTransfer->State.pHeader = SharedClipboardURIDataHdrDup(pDataHdr);
1016 if (pTransfer->State.pHeader)
1017 {
1018 LogFlowFunc(("Meta data size is %RU32, total size is %RU64, %RU64 objects\n",
1019 pTransfer->State.pHeader->cbMeta, pTransfer->State.pHeader->cbTotal,
1020 pTransfer->State.pHeader->cObjects));
1021
1022 rc = VINF_SUCCESS;
1023
1024 if (pTransfer->Callbacks.pfnDataHeaderComplete)
1025 {
1026 SHAREDCLIPBOARDURITRANSFERCALLBACKDATA callbackData = { pTransfer, pTransfer->Callbacks.pvUser };
1027 pTransfer->Callbacks.pfnDataHeaderComplete(&callbackData);
1028 }
1029 }
1030 else
1031 rc = VERR_NO_MEMORY;
1032
1033 LogFlowFuncLeaveRC(rc);
1034 return rc;
1035}
1036
1037int SharedClipboardURITransferSetDataChunk(PSHAREDCLIPBOARDURITRANSFER pTransfer, PVBOXCLIPBOARDDATACHUNK pDataChunk)
1038{
1039 LogFlowFuncEnter();
1040
1041 AssertPtrReturn(pTransfer->State.pHeader, VERR_WRONG_ORDER);
1042
1043 int rc = SharedClipboardURITransferMetaDataAdd(pTransfer, pDataChunk->pvData, pDataChunk->cbData);
1044
1045 LogFlowFuncLeaveRC(rc);
1046 return rc;
1047}
1048
1049/**
1050 * Creates a thread for a clipboard URI transfer.
1051 *
1052 * @returns VBox status code.
1053 * @param pTransfer URI clipboard transfer to create thread for.
1054 */
1055static int sharedClipboardURITransferThreadCreate(PSHAREDCLIPBOARDURITRANSFER pTransfer)
1056{
1057 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
1058
1059 PFNRTTHREAD pfnRTThread = NULL;
1060
1061 if (pTransfer->State.enmDir == SHAREDCLIPBOARDURITRANSFERDIR_READ)
1062 pfnRTThread = sharedClipboardURITransferReadThread;
1063 else if (pTransfer->State.enmDir == SHAREDCLIPBOARDURITRANSFERDIR_WRITE)
1064 pfnRTThread = sharedClipboardURITransferWriteThread;
1065
1066 AssertPtrReturn(pfnRTThread, VERR_NOT_SUPPORTED);
1067
1068 /* Spawn a worker thread, so that we don't block the window thread for too long. */
1069 int rc = RTThreadCreate(&pTransfer->Thread.hThread, pfnRTThread,
1070 pTransfer /* pvUser */, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE,
1071 "shclp");
1072 if (RT_SUCCESS(rc))
1073 {
1074 int rc2 = RTThreadUserWait(pTransfer->Thread.hThread, 30 * 1000 /* Timeout in ms */);
1075 AssertRC(rc2);
1076
1077 if (!pTransfer->Thread.fStarted) /* Did the thread fail to start? */
1078 rc = VERR_GENERAL_FAILURE; /** @todo Find a better rc. */
1079 }
1080
1081 LogFlowFuncLeaveRC(rc);
1082 return rc;
1083}
1084
1085/**
1086 * Destroys a thread of a clipboard URI transfer.
1087 *
1088 * @returns VBox status code.
1089 * @param pTransfer URI clipboard transfer to destroy thread for.
1090 * @param uTimeoutMs Timeout (in ms) to wait for thread creation.
1091 */
1092static int sharedClipboardURITransferThreadDestroy(PSHAREDCLIPBOARDURITRANSFER pTransfer, RTMSINTERVAL uTimeoutMs)
1093{
1094 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
1095
1096 if (pTransfer->Thread.hThread == NIL_RTTHREAD)
1097 return VINF_SUCCESS;
1098
1099 int rcThread = VERR_WRONG_ORDER;
1100 int rc = RTThreadWait(pTransfer->Thread.hThread, uTimeoutMs, &rcThread);
1101
1102 LogFlowFunc(("Waiting for thread resulted in %Rrc (thread exited with %Rrc)\n", rc, rcThread));
1103
1104 return rc;
1105}
1106
1107/**
1108 * Reads all URI objects using the connected provider.
1109 *
1110 * @returns VBox status code.
1111 * @param pTransfer Transfer to read objects for.
1112 */
1113int SharedClipboardURITransferRead(PSHAREDCLIPBOARDURITRANSFER pTransfer)
1114{
1115 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
1116
1117 LogFlowFuncEnter();
1118
1119 AssertMsgReturn(pTransfer->State.enmStatus == SHAREDCLIPBOARDURITRANSFERSTATUS_RUNNING,
1120 ("Transfer already is running\n"), VERR_WRONG_ORDER);
1121
1122 pTransfer->State.enmStatus = SHAREDCLIPBOARDURITRANSFERSTATUS_RUNNING;
1123
1124 if (pTransfer->Callbacks.pfnTransferStarted)
1125 {
1126 SHAREDCLIPBOARDURITRANSFERCALLBACKDATA callbackData = { pTransfer, pTransfer->Callbacks.pvUser };
1127 pTransfer->Callbacks.pfnTransferStarted(&callbackData);
1128 }
1129
1130 int rc = SharedClipboardURITransferMetaDataRead(pTransfer, NULL /* pcbRead */);
1131 if (RT_SUCCESS(rc))
1132 {
1133 rc = SharedClipboardURITransferReadObjects(pTransfer);
1134 if (RT_SUCCESS(rc))
1135 {
1136 if (pTransfer->Callbacks.pfnTransferComplete)
1137 {
1138 SHAREDCLIPBOARDURITRANSFERCALLBACKDATA callbackData = { pTransfer, pTransfer->Callbacks.pvUser };
1139 pTransfer->Callbacks.pfnTransferComplete(&callbackData, rc);
1140 }
1141 }
1142 }
1143
1144 if (RT_FAILURE(rc))
1145 {
1146 if (pTransfer->Callbacks.pfnTransferError)
1147 {
1148 SHAREDCLIPBOARDURITRANSFERCALLBACKDATA callbackData = { pTransfer, pTransfer->Callbacks.pvUser };
1149 pTransfer->Callbacks.pfnTransferError(&callbackData, rc);
1150 }
1151 }
1152
1153 pTransfer->State.enmStatus = SHAREDCLIPBOARDURITRANSFERSTATUS_NONE;
1154
1155 LogFlowFuncLeaveRC(rc);
1156 return rc;
1157}
1158
1159int SharedClipboardURITransferReadDir(PSHAREDCLIPBOARDURITRANSFER pTransfer, PSHAREDCLIPBOARDCLIENTURIOBJCTX pObjCtx)
1160{
1161 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
1162
1163 RT_NOREF(pObjCtx);
1164
1165 LogFlowFuncEnter();
1166
1167 PVBOXCLIPBOARDDIRDATA pDirData;
1168 int rc = pTransfer->ProviderIface.pfnReadDirectory(&pTransfer->ProviderCtx, &pDirData);
1169 if (RT_SUCCESS(rc))
1170 {
1171 SharedClipboardURIDirDataFree(pDirData);
1172 }
1173
1174 LogFlowFuncLeaveRC(rc);
1175 return rc;
1176}
1177
1178int SharedClipboardURITransferReadFile(PSHAREDCLIPBOARDURITRANSFER pTransfer, PSHAREDCLIPBOARDCLIENTURIOBJCTX pObjCtx)
1179{
1180 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
1181
1182 RT_NOREF(pObjCtx);
1183
1184 LogFlowFuncEnter();
1185
1186 PVBOXCLIPBOARDFILEHDR pFileHdr;
1187 int rc = pTransfer->ProviderIface.pfnReadFileHdr(&pTransfer->ProviderCtx, &pFileHdr);
1188 if (RT_SUCCESS(rc))
1189 {
1190 uint64_t cbToRead = pFileHdr->cbSize;
1191 uint32_t cbRead;
1192
1193 uint8_t pvBuf[_64K]; /** @todo Improve. */
1194 uint32_t cbBuf = _64K;
1195
1196 while (cbToRead)
1197 {
1198 rc = pTransfer->ProviderIface.pfnReadFileData(&pTransfer->ProviderCtx,
1199 pvBuf, cbBuf, 0 /* fFlags */, &cbRead);
1200 if (RT_FAILURE(rc))
1201 break;
1202
1203 /** @todo Validate data block checksum. */
1204
1205 Assert(cbToRead >= cbRead);
1206 cbToRead -= cbRead;
1207 }
1208
1209 SharedClipboardURIFileHdrFree(pFileHdr);
1210 }
1211
1212 LogFlowFuncLeaveRC(rc);
1213 return rc;
1214}
1215
1216int SharedClipboardURITransferReadObject(PSHAREDCLIPBOARDURITRANSFER pTransfer, PSHAREDCLIPBOARDCLIENTURIOBJCTX pObjCtx)
1217{
1218 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
1219
1220 RT_NOREF(pObjCtx);
1221
1222 LogFlowFuncEnter();
1223
1224 PVBOXCLIPBOARDOBJHDR pObjHdr;
1225 int rc = pTransfer->ProviderIface.pfnReadObjHdr(&pTransfer->ProviderCtx, &pObjHdr);
1226 if (RT_SUCCESS(rc))
1227 {
1228 switch (pObjHdr->enmType)
1229 {
1230#if 0
1231 case Dir:
1232 {
1233 SHAREDCLIPBOARDCLIENTURIOBJCTX objCtx;
1234 rc = SharedClipboardURITransferReadDir(pTransfer, &objCtx);
1235 break;
1236 }
1237
1238 case File:
1239 {
1240 SHAREDCLIPBOARDCLIENTURIOBJCTX objCtx;
1241 rc = SharedClipboardURITransferReadFile(pTransfer, &objCtx);
1242 break;
1243 }
1244#endif
1245 default:
1246 /** @todo Skip -- how? */
1247 break;
1248 }
1249 }
1250
1251 LogFlowFuncLeaveRC(rc);
1252 return rc;
1253}
1254
1255/**
1256 * Reads all URI objects using the connected provider.
1257 *
1258 * @returns VBox status code.
1259 * @param pTransfer Transfer to read objects for.
1260 */
1261int SharedClipboardURITransferReadObjects(PSHAREDCLIPBOARDURITRANSFER pTransfer)
1262{
1263 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
1264
1265 LogFlowFuncEnter();
1266
1267 const PVBOXCLIPBOARDDATAHDR pHdr = pTransfer->State.pHeader;
1268 AssertPtrReturn(pHdr, VERR_WRONG_ORDER);
1269
1270 int rc = VINF_SUCCESS;
1271
1272 for (uint64_t i = 0; i < pHdr->cObjects; i++)
1273 {
1274 SHAREDCLIPBOARDCLIENTURIOBJCTX objCtx;
1275 rc = SharedClipboardURITransferReadObject(pTransfer, &objCtx);
1276 if (RT_FAILURE(rc))
1277 break;
1278 }
1279
1280 LogFlowFuncLeaveRC(rc);
1281 return rc;
1282}
1283
1284/**
1285 * Thread for transferring (reading) URI objects from source to the target.
1286 * For target to source transfers we utilize our own IDataObject / IStream implementations.
1287 *
1288 * @returns VBox status code.
1289 * @param hThread Thread handle.
1290 * @param pvUser User arguments; is PSHAREDCLIPBOARDURITRANSFER.
1291 */
1292static int sharedClipboardURITransferReadThread(RTTHREAD hThread, void *pvUser)
1293{
1294 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
1295
1296 LogFlowFuncEnter();
1297
1298 /* At the moment we only support one transfer at a time. */
1299 PSHAREDCLIPBOARDURITRANSFER pTransfer = (PSHAREDCLIPBOARDURITRANSFER)pvUser;
1300 AssertPtr(pTransfer);
1301
1302 int rc = VINF_SUCCESS;
1303
1304 if (RT_SUCCESS(rc))
1305 pTransfer->Thread.fStarted = true;
1306
1307 int rc2 = RTThreadUserSignal(hThread);
1308 const bool fSignalled = RT_SUCCESS(rc2);
1309
1310 if (RT_SUCCESS(rc))
1311 rc = SharedClipboardURITransferRead(pTransfer);
1312
1313 if (!fSignalled)
1314 {
1315 rc2 = RTThreadUserSignal(hThread);
1316 AssertRC(rc2);
1317 }
1318
1319 LogFlowFuncLeaveRC(rc);
1320 return rc;
1321}
1322
1323/**
1324 * Creates the internal meta data buffer of an URI clipboard transfer.
1325 *
1326 * @returns VBox status code.
1327 * @param pTransfer URI clipboard transfer to create internal meta data for.
1328 * @param cbSize Size (in bytes) of meta data buffer to create. An existing meta data buffer
1329 * will be resized accordingly.
1330 */
1331static int sharedClipboardURITransferMetaDataCreateInternal(PSHAREDCLIPBOARDURITRANSFER pTransfer, uint32_t cbSize)
1332{
1333 int rc;
1334
1335 LogFlowFuncEnter();
1336
1337 if (pTransfer->State.pMeta == NULL)
1338 {
1339 pTransfer->State.pMeta = (PSHAREDCLIPBOARDMETADATA)RTMemAlloc(sizeof(SHAREDCLIPBOARDMETADATA));
1340 if (pTransfer->State.pMeta)
1341 {
1342 /** @todo Make meta data format handling more flexible. */
1343 rc = SharedClipboardMetaDataInit(pTransfer->State.pMeta, SHAREDCLIPBOARDMETADATAFMT_URI_LIST);
1344 }
1345 else
1346 rc = VERR_NO_MEMORY;
1347 }
1348 else
1349 rc = SharedClipboardMetaDataResize(pTransfer->State.pMeta, cbSize);
1350
1351 LogFlowFuncLeaveRC(rc);
1352 return rc;
1353}
1354
1355/**
1356 * Destroys a clipboard URI transfer's internal meta data.
1357 *
1358 * @param pTransfer URI clipboard transfer to destroy internal meta data of.
1359 */
1360static void sharedClipboardURITransferMetaDataDestroyInternal(PSHAREDCLIPBOARDURITRANSFER pTransfer)
1361{
1362 if (!pTransfer->State.pMeta)
1363 return;
1364
1365 LogFlowFuncEnter();
1366
1367 /* We're done processing the meta data, so just destroy it. */
1368 SharedClipboardMetaDataDestroy(pTransfer->State.pMeta);
1369
1370 RTMemFree(pTransfer->State.pMeta);
1371 pTransfer->State.pMeta = NULL;
1372}
1373
1374/**
1375 * Adds meta data for a clipboard URI transfer, internal version.
1376 *
1377 * @returns VBox status code.
1378 * @param pTransfer URI clipboard transfer to set meta data for.
1379 * @param pvMeta Pointer to meta data buffer.
1380 * @param cbMeta Size (in bytes) of meta data buffer.
1381 */
1382static int sharedClipboardURITransferMetaDataAddInternal(PSHAREDCLIPBOARDURITRANSFER pTransfer,
1383 const void *pvMeta, uint32_t cbMeta)
1384{
1385 LogFlowFunc(("pvMeta=%p, cbMeta=%RU32\n", pvMeta, cbMeta));
1386
1387 int rc = SharedClipboardMetaDataAdd(pTransfer->State.pMeta, pvMeta, cbMeta);
1388
1389 LogFlowFuncLeaveRC(rc);
1390 return rc;
1391}
1392
1393/**
1394 * Adds meta data for a clipboard URI transfer.
1395 *
1396 * @returns VBox status code.
1397 * @param pTransfer URI clipboard transfer to set meta data for.
1398 * @param pvMeta Pointer to meta data buffer.
1399 * @param cbMeta Size (in bytes) of meta data buffer.
1400 */
1401int SharedClipboardURITransferMetaDataAdd(PSHAREDCLIPBOARDURITRANSFER pTransfer, const void *pvMeta, uint32_t cbMeta)
1402{
1403 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
1404
1405 LogFlowFuncEnter();
1406
1407 int rc = sharedClipboardURITransferMetaDataCreateInternal(pTransfer, cbMeta);
1408 if (RT_SUCCESS(rc))
1409 rc = sharedClipboardURITransferMetaDataAddInternal(pTransfer, pvMeta, cbMeta);
1410
1411 LogFlowFuncLeaveRC(rc);
1412 return rc;
1413}
1414
1415/**
1416 * Returns whether the meta data is in a complete state (e.g. completetely read / written) or not.
1417 *
1418 * @returns \c true if meta data is complete, \c false if not.
1419 * @param pTransfer URI clipboard transfer to get completion status of meta data for.
1420 */
1421bool SharedClipboardURITransferMetaDataIsComplete(PSHAREDCLIPBOARDURITRANSFER pTransfer)
1422{
1423 AssertPtrReturn(pTransfer->State.pHeader, false);
1424 AssertPtrReturn(pTransfer->State.pMeta, false);
1425
1426 return SharedClipboardMetaDataGetUsed(pTransfer->State.pMeta) == pTransfer->State.pHeader->cbMeta;
1427}
1428
1429/**
1430 * Reads meta for a clipboard URI transfer.
1431 *
1432 * @returns VBox status code.
1433 * @param pTransfer URI clipboard transfer to read meta data for.
1434 * @param pcbRead How much meta data (in bytes) was read on success.
1435 */
1436int SharedClipboardURITransferMetaDataRead(PSHAREDCLIPBOARDURITRANSFER pTransfer, uint32_t *pcbRead)
1437{
1438 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
1439 /* pcbRead is optional. */
1440
1441 LogFlowFuncEnter();
1442
1443 /* Destroy any former meta data. */
1444 SharedClipboardMetaDataDestroy(pTransfer->State.pMeta);
1445
1446 uint32_t cbReadTotal = 0;
1447
1448 int rc = pTransfer->ProviderIface.pfnReadDataHdr(&pTransfer->ProviderCtx, &pTransfer->State.pHeader);
1449 if (RT_SUCCESS(rc))
1450 {
1451 uint32_t cbMeta = _4K; /** @todo Improve. */
1452 void *pvMeta = RTMemAlloc(cbMeta);
1453
1454 if (pvMeta)
1455 {
1456 AssertPtr(pTransfer->State.pHeader);
1457 uint32_t cbMetaToRead = pTransfer->State.pHeader->cbMeta;
1458 while (cbMetaToRead)
1459 {
1460 uint32_t cbMetaRead;
1461 rc = pTransfer->ProviderIface.pfnReadDataChunk(&pTransfer->ProviderCtx,
1462 pTransfer->State.pHeader, pvMeta, cbMeta, 0 /* fFlags */,
1463 &cbMetaRead);
1464 if (RT_SUCCESS(rc))
1465 rc = sharedClipboardURITransferMetaDataAddInternal(pTransfer, pvMeta, cbMeta);
1466
1467 if (RT_FAILURE(rc))
1468 break;
1469
1470 Assert(cbMetaToRead >= cbMetaRead);
1471 cbMetaToRead -= cbMetaRead;
1472
1473 cbReadTotal += cbReadTotal;
1474 }
1475
1476 RTMemFree(pvMeta);
1477
1478 if (RT_SUCCESS(rc))
1479 {
1480 if (pcbRead)
1481 *pcbRead = cbReadTotal;
1482 }
1483 }
1484 else
1485 rc = VERR_NO_MEMORY;
1486 }
1487
1488 LogFlowFuncLeaveRC(rc);
1489 return rc;
1490}
1491
1492/**
1493 * Writes the actual meta data.
1494 *
1495 * @returns IPRT status code.
1496 * @param pTransfer Transfer to write meta data for.
1497 * @param pcbWritten How much bytes were written on success. Optional.
1498 */
1499int SharedClipboardURITransferMetaDataWrite(PSHAREDCLIPBOARDURITRANSFER pTransfer, uint32_t *pcbWritten)
1500{
1501 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
1502 /* pcbWritten is optional. */
1503
1504 LogFlowFuncEnter();
1505
1506 AssertPtrReturn(pTransfer->State.pHeader, VERR_WRONG_ORDER);
1507 AssertPtrReturn(pTransfer->State.pMeta, VERR_WRONG_ORDER);
1508
1509 uint32_t cbWrittenTotal = 0;
1510
1511 int rc = pTransfer->ProviderIface.pfnWriteDataHdr(&pTransfer->ProviderCtx, pTransfer->State.pHeader);
1512 if (RT_SUCCESS(rc))
1513 {
1514 /* Sanity. */
1515 Assert(pTransfer->State.pHeader->cbMeta == pTransfer->State.pMeta->cbUsed);
1516
1517 uint32_t cbMetaToWrite = pTransfer->State.pHeader->cbMeta;
1518 while (cbMetaToWrite)
1519 {
1520 uint32_t cbMetaWritten;
1521 rc = pTransfer->ProviderIface.pfnWriteDataChunk(&pTransfer->ProviderCtx, pTransfer->State.pHeader,
1522 (uint8_t *)pTransfer->State.pMeta->pvMeta + cbWrittenTotal,
1523 cbMetaToWrite, 0 /* fFlags */, &cbMetaWritten);
1524 if (RT_FAILURE(rc))
1525 break;
1526
1527 Assert(cbMetaToWrite >= cbMetaWritten);
1528 cbMetaToWrite -= cbMetaWritten;
1529
1530 cbWrittenTotal += cbMetaWritten;
1531 Assert(cbWrittenTotal <= pTransfer->State.pHeader->cbMeta);
1532 }
1533
1534 if (RT_SUCCESS(rc))
1535 {
1536 if (pcbWritten)
1537 *pcbWritten = cbWrittenTotal;
1538
1539 if (pTransfer->Callbacks.pfnDataComplete)
1540 {
1541 SHAREDCLIPBOARDURITRANSFERCALLBACKDATA callbackData = { pTransfer, pTransfer->Callbacks.pvUser };
1542 pTransfer->Callbacks.pfnDataComplete(&callbackData);
1543 }
1544 }
1545 }
1546
1547 LogFlowFuncLeaveRC(rc);
1548 return rc;
1549}
1550
1551/**
1552 * Writes all URI objects using the connected provider.
1553 *
1554 * @returns VBox status code.
1555 * @param pTransfer Transfer to write objects for.
1556 */
1557int SharedClipboardURITransferWriteObjects(PSHAREDCLIPBOARDURITRANSFER pTransfer)
1558{
1559 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
1560
1561 LogFlowFuncEnter();
1562
1563 int rc = VINF_SUCCESS;
1564
1565 AssertPtrReturn(pTransfer->pURIList, VERR_WRONG_ORDER);
1566
1567 while (!pTransfer->pURIList->IsEmpty())
1568 {
1569 SharedClipboardURIObject *pObj = pTransfer->pURIList->First();
1570 AssertPtrBreakStmt(pObj, rc = VERR_INVALID_POINTER);
1571
1572 switch (pObj->GetType())
1573 {
1574 case SharedClipboardURIObject::Type_Directory:
1575 {
1576 RTCString strPath = pObj->GetDestPathAbs();
1577 LogFlowFunc(("strDir=%s (%zu), fMode=0x%x\n",
1578 strPath.c_str(), strPath.length(), pObj->GetMode()));
1579
1580 VBOXCLIPBOARDDIRDATA dirData;
1581 SharedClipboardURIDirDataInit(&dirData);
1582
1583 dirData.pszPath = RTStrDup(strPath.c_str());
1584 dirData.cbPath = (uint32_t)strlen(dirData.pszPath);
1585
1586 rc = pTransfer->ProviderIface.pfnWriteDirectory(&pTransfer->ProviderCtx, &dirData);
1587
1588 SharedClipboardURIDirDataDestroy(&dirData);
1589 break;
1590 }
1591
1592 case SharedClipboardURIObject::Type_File:
1593 {
1594 AssertBreakStmt(pObj->IsOpen(), rc = VERR_INVALID_STATE);
1595
1596 RTCString strPath = pObj->GetDestPathAbs();
1597
1598 LogFlowFunc(("strFile=%s (%zu), cbSize=%RU64, fMode=0x%x\n", strPath.c_str(), strPath.length(),
1599 pObj->GetSize(), pObj->GetMode()));
1600
1601 VBOXCLIPBOARDFILEHDR fileHdr;
1602 SharedClipboardURIFileHdrInit(&fileHdr);
1603
1604 fileHdr.pszFilePath = RTStrDup(strPath.c_str());
1605 fileHdr.cbFilePath = (uint32_t)strlen(fileHdr.pszFilePath);
1606 fileHdr.cbSize = pObj->GetSize();
1607 fileHdr.fFlags = 0;
1608 fileHdr.fMode = pObj->GetMode();
1609
1610 rc = pTransfer->ProviderIface.pfnWriteFileHdr(&pTransfer->ProviderCtx, &fileHdr);
1611 SharedClipboardURIFileHdrDestroy(&fileHdr);
1612
1613 if (RT_FAILURE(rc))
1614 break;
1615
1616 uint32_t cbData = _64K; /** @todo Improve. */
1617 void *pvData = RTMemAlloc(cbData);
1618
1619 AssertPtrBreakStmt(pvData, rc = VERR_NO_MEMORY);
1620
1621 while (!pObj->IsComplete())
1622 {
1623 uint32_t cbRead;
1624 rc = pObj->Read(pvData, cbData, &cbRead);
1625 if (RT_SUCCESS(rc))
1626 {
1627 uint32_t cbToRead = cbRead;
1628 rc = pTransfer->ProviderIface.pfnWriteFileData(&pTransfer->ProviderCtx,
1629 pvData, cbToRead, 0 /* fFlags */, &cbRead);
1630 }
1631
1632 if (RT_FAILURE(rc))
1633 break;
1634 }
1635
1636 RTMemFree(pvData);
1637 pvData = NULL;
1638 break;
1639 }
1640
1641 default:
1642 AssertFailed();
1643 break;
1644 }
1645
1646 if (RT_FAILURE(rc))
1647 break;
1648
1649 /* Only remove current object on success. */
1650 pTransfer->pURIList->RemoveFirst();
1651 }
1652
1653 LogFlowFuncLeaveRC(rc);
1654 return rc;
1655}
1656
1657/**
1658 * Thread for transferring (writing) URI objects from source to the target.
1659 * For target to source transfers we utilize our own IDataObject / IStream implementations.
1660 *
1661 * @returns VBox status code.
1662 * @param hThread Thread handle.
1663 * @param pvUser User arguments; is PSHAREDCLIPBOARDURITRANSFER.
1664 */
1665static int sharedClipboardURITransferWriteThread(RTTHREAD hThread, void *pvUser)
1666{
1667 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
1668
1669 LogFlowFuncEnter();
1670
1671 /* At the moment we only support one transfer at a time. */
1672 PSHAREDCLIPBOARDURITRANSFER pTransfer = (PSHAREDCLIPBOARDURITRANSFER)pvUser;
1673
1674 int rc = VINF_SUCCESS;
1675
1676 if (RT_SUCCESS(rc))
1677 pTransfer->Thread.fStarted = true;
1678
1679 int rc2 = RTThreadUserSignal(hThread);
1680 const bool fSignalled = RT_SUCCESS(rc2);
1681
1682 if (RT_SUCCESS(rc))
1683 rc = SharedClipboardURITransferWrite(pTransfer);
1684
1685 if (!fSignalled)
1686 {
1687 rc2 = RTThreadUserSignal(hThread);
1688 AssertRC(rc2);
1689 }
1690
1691 LogFlowFuncLeaveRC(rc);
1692 return rc;
1693}
1694
1695/**
1696 * Main function to write a clipboard URI transfer.
1697 *
1698 * @returns VBox status code.
1699 * @param pURI URI clipboard context to write.
1700 */
1701int SharedClipboardURITransferWrite(PSHAREDCLIPBOARDURITRANSFER pTransfer)
1702{
1703 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
1704
1705 LogFlowFuncEnter();
1706
1707 AssertMsgReturn(pTransfer->State.enmStatus == SHAREDCLIPBOARDURITRANSFERSTATUS_RUNNING,
1708 ("Transfer already is running\n"), VERR_WRONG_ORDER);
1709
1710 pTransfer->State.enmStatus = SHAREDCLIPBOARDURITRANSFERSTATUS_RUNNING;
1711
1712 if (pTransfer->Callbacks.pfnTransferStarted)
1713 {
1714 SHAREDCLIPBOARDURITRANSFERCALLBACKDATA callbackData = { pTransfer, pTransfer->Callbacks.pvUser };
1715 pTransfer->Callbacks.pfnTransferStarted(&callbackData);
1716 }
1717
1718 int rc = SharedClipboardURITransferMetaDataWrite(pTransfer, NULL /* pcbWritten */);
1719 if (RT_SUCCESS(rc))
1720 {
1721 rc = SharedClipboardURITransferWriteObjects(pTransfer);
1722 if (RT_SUCCESS(rc))
1723 {
1724 if (pTransfer->Callbacks.pfnTransferComplete)
1725 {
1726 SHAREDCLIPBOARDURITRANSFERCALLBACKDATA callbackData = { pTransfer, pTransfer->Callbacks.pvUser };
1727 pTransfer->Callbacks.pfnTransferComplete(&callbackData, rc);
1728 }
1729 }
1730 }
1731
1732 if (RT_FAILURE(rc))
1733 {
1734 if (pTransfer->Callbacks.pfnTransferError)
1735 {
1736 SHAREDCLIPBOARDURITRANSFERCALLBACKDATA callbackData = { pTransfer, pTransfer->Callbacks.pvUser };
1737 pTransfer->Callbacks.pfnTransferError(&callbackData, rc);
1738 }
1739 }
1740
1741 pTransfer->State.enmStatus = SHAREDCLIPBOARDURITRANSFERSTATUS_NONE;
1742
1743 LogFlowFuncLeaveRC(rc);
1744 return rc;
1745}
1746
1747/**
1748 * Initializes a clipboard URI transfer.
1749 *
1750 * @returns VBox status code.
1751 * @param pURI URI clipboard context to initialize.
1752 */
1753int SharedClipboardURICtxInit(PSHAREDCLIPBOARDURICTX pURI)
1754{
1755 AssertPtrReturn(pURI, VERR_INVALID_POINTER);
1756
1757 LogFlowFuncEnter();
1758
1759 int rc = RTCritSectInit(&pURI->CritSect);
1760 if (RT_SUCCESS(rc))
1761 {
1762 RTListInit(&pURI->List);
1763
1764 pURI->cRunning = 0;
1765 pURI->cMaxRunning = 1; /* For now we only support one transfer per client at a time. */
1766
1767#ifdef DEBUG_andy
1768 pURI->cMaxRunning = UINT32_MAX;
1769#endif
1770 SharedClipboardURICtxReset(pURI);
1771 }
1772
1773 return VINF_SUCCESS;
1774}
1775
1776/**
1777 * Destroys an URI clipboard information context struct.
1778 *
1779 * @param pURI URI clipboard context to destroy.
1780 */
1781void SharedClipboardURICtxDestroy(PSHAREDCLIPBOARDURICTX pURI)
1782{
1783 AssertPtrReturnVoid(pURI);
1784
1785 LogFlowFuncEnter();
1786
1787 RTCritSectDelete(&pURI->CritSect);
1788
1789 PSHAREDCLIPBOARDURITRANSFER pTransfer, pTransferNext;
1790 RTListForEachSafe(&pURI->List, pTransfer, pTransferNext, SHAREDCLIPBOARDURITRANSFER, Node)
1791 {
1792 SharedClipboardURITransferDestroy(pTransfer);
1793 RTListNodeRemove(&pTransfer->Node);
1794 }
1795
1796 pURI->cRunning = 0;
1797#ifdef DEBUG
1798 pURI->cTransfer = 0;
1799#endif
1800}
1801
1802/**
1803 * Resets an clipboard URI transfer.
1804 *
1805 * @param pURI URI clipboard context to reset.
1806 */
1807void SharedClipboardURICtxReset(PSHAREDCLIPBOARDURICTX pURI)
1808{
1809 AssertPtrReturnVoid(pURI);
1810
1811 LogFlowFuncEnter();
1812
1813 PSHAREDCLIPBOARDURITRANSFER pTransfer;
1814 RTListForEach(&pURI->List, pTransfer, SHAREDCLIPBOARDURITRANSFER, Node)
1815 SharedClipboardURITransferReset(pTransfer);
1816}
1817
1818/**
1819 * Adds a new URI transfer to an clipboard URI transfer.
1820 *
1821 * @returns VBox status code.
1822 * @param pURI URI clipboard context to add transfer to.
1823 * @param pTransfer Pointer to URI clipboard transfer to add.
1824 */
1825int SharedClipboardURICtxTransferAdd(PSHAREDCLIPBOARDURICTX pURI, PSHAREDCLIPBOARDURITRANSFER pTransfer)
1826{
1827 AssertPtrReturn(pURI, VERR_INVALID_POINTER);
1828 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
1829
1830 LogFlowFuncEnter();
1831
1832 if (pURI->cRunning == pURI->cMaxRunning)
1833 return VERR_SHCLPB_MAX_TRANSFERS_REACHED;
1834
1835 RTListAppend(&pURI->List, &pTransfer->Node);
1836
1837#ifdef DEBUG
1838 pURI->cTransfer++;
1839 LogFlowFunc(("cTransfers=%RU32, cRunning=%RU32\n", pURI->cTransfer, pURI->cRunning));
1840#endif
1841
1842 return VINF_SUCCESS;
1843}
1844
1845/**
1846 * Removes an URI transfer from a clipboard URI transfer.
1847 *
1848 * @returns VBox status code.
1849 * @param pURI URI clipboard context to remove transfer from.
1850 * @param pTransfer Pointer to URI clipboard transfer to remove.
1851 */
1852int SharedClipboardURICtxTransferRemove(PSHAREDCLIPBOARDURICTX pURI, PSHAREDCLIPBOARDURITRANSFER pTransfer)
1853{
1854 AssertPtrReturn(pURI, VERR_INVALID_POINTER);
1855 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
1856
1857 LogFlowFuncEnter();
1858
1859
1860 int rc = SharedClipboardURITransferDestroy(pTransfer);
1861 if (RT_SUCCESS(rc))
1862 {
1863 RTListNodeRemove(&pTransfer->Node);
1864 }
1865
1866 LogFlowFuncLeaveRC(rc);
1867 return rc;
1868}
1869
1870/**
1871 * Returns a specific URI transfer, internal version.
1872 *
1873 * @returns URI transfer, or NULL if not found.
1874 * @param pURI URI clipboard context to return transfer for.
1875 * @param uIdx Index of the transfer to return.
1876 */
1877static PSHAREDCLIPBOARDURITRANSFER sharedClipboardURICtxGetTransferInternal(PSHAREDCLIPBOARDURICTX pURI, uint32_t uIdx)
1878{
1879 AssertReturn(uIdx == 0, NULL); /* Only one transfer allowed at the moment. */
1880 return RTListGetFirst(&pURI->List, SHAREDCLIPBOARDURITRANSFER, Node);
1881}
1882
1883/**
1884 * Returns a specific URI transfer.
1885 *
1886 * @returns URI transfer, or NULL if not found.
1887 * @param pURI URI clipboard context to return transfer for.
1888 * @param uIdx Index of the transfer to return.
1889 */
1890PSHAREDCLIPBOARDURITRANSFER SharedClipboardURICtxGetTransfer(PSHAREDCLIPBOARDURICTX pURI, uint32_t uIdx)
1891{
1892 return sharedClipboardURICtxGetTransferInternal(pURI, uIdx);
1893}
1894
1895/**
1896 * Returns the number of running URI transfers.
1897 *
1898 * @returns VBox status code.
1899 * @param pURI URI clipboard context to return number for.
1900 */
1901uint32_t SharedClipboardURICtxGetRunningTransfers(PSHAREDCLIPBOARDURICTX pURI)
1902{
1903 AssertPtrReturn(pURI, 0);
1904 return pURI->cRunning;
1905}
1906
1907/**
1908 * Cleans up all associated transfers which are not needed (anymore).
1909 * This can be due to transfers which only have been announced but not / never being run.
1910 *
1911 * @param pURI URI clipboard context to cleanup transfers for.
1912 */
1913void SharedClipboardURICtxTransfersCleanup(PSHAREDCLIPBOARDURICTX pURI)
1914{
1915 AssertPtrReturnVoid(pURI);
1916
1917 LogFlowFunc(("cRunning=%RU32\n", pURI->cRunning));
1918
1919 /* Remove all transfers which are not in a running state (e.g. only announced). */
1920 PSHAREDCLIPBOARDURITRANSFER pTransfer, pTransferNext;
1921 RTListForEachSafe(&pURI->List, pTransfer, pTransferNext, SHAREDCLIPBOARDURITRANSFER, Node)
1922 {
1923 if (SharedClipboardURITransferGetStatus(pTransfer) != SHAREDCLIPBOARDURITRANSFERSTATUS_RUNNING)
1924 {
1925 SharedClipboardURITransferDestroy(pTransfer);
1926 RTListNodeRemove(&pTransfer->Node);
1927
1928#ifdef DEBUG
1929 Assert(pURI->cTransfer);
1930 pURI->cTransfer--;
1931
1932 LogFlowFunc(("cTransfers=%RU32\n", pURI->cTransfer));
1933#endif
1934 }
1935 }
1936}
1937
1938/**
1939 * Returns whether the maximum of concurrent transfers of a specific URI context has been reached or not.
1940 *
1941 * @returns \c if maximum has been reached, \c false if not.
1942 * @param pURI URI clipboard context to determine value for.
1943 */
1944bool SharedClipboardURICtxTransfersMaximumReached(PSHAREDCLIPBOARDURICTX pURI)
1945{
1946 AssertPtrReturn(pURI, true);
1947
1948 LogFlowFunc(("cRunning=%RU32\n", pURI->cRunning));
1949
1950 Assert(pURI->cRunning <= pURI->cMaxRunning);
1951 return pURI->cRunning == pURI->cMaxRunning;
1952}
1953
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette