VirtualBox

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

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