VirtualBox

source: vbox/trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc-uri.cpp@ 80848

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

Shared Clipboard/URI: More renaming (typos).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 83.4 KB
Line 
1/* $Id: VBoxSharedClipboardSvc-uri.cpp 80848 2019-09-17 09:43:53Z vboxsync $ */
2/** @file
3 * Shared Clipboard Service - Internal code for URI (list) handling.
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
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define LOG_GROUP LOG_GROUP_SHARED_CLIPBOARD
23#include <VBox/log.h>
24
25#include <VBox/err.h>
26
27#include <VBox/GuestHost/clipboard-helper.h>
28#include <VBox/HostServices/VBoxClipboardSvc.h>
29#include <VBox/HostServices/VBoxClipboardExt.h>
30
31#include <iprt/dir.h>
32#include <iprt/file.h>
33#include <iprt/path.h>
34
35#include "VBoxSharedClipboardSvc-internal.h"
36#include "VBoxSharedClipboardSvc-uri.h"
37
38
39/*********************************************************************************************************************************
40* Externals *
41*********************************************************************************************************************************/
42extern SHCLEXTSTATE g_ExtState;
43extern PVBOXHGCMSVCHELPERS g_pHelpers;
44extern ClipboardClientQueue g_listClientsDeferred;
45
46
47/*********************************************************************************************************************************
48* Prototypes *
49*********************************************************************************************************************************/
50static int sharedClipboardSvcURISetListOpen(uint32_t cParms, VBOXHGCMSVCPARM paParms[],
51 PSHCLMSGCTX pMsgCtx, PSHCLLISTOPENPARMS pOpenParms);
52static int sharedClipboardSvcURISetListClose(uint32_t cParms, VBOXHGCMSVCPARM paParms[],
53 PSHCLMSGCTX pMsgCtx, SHCLLISTHANDLE hList);
54
55
56/*********************************************************************************************************************************
57* Provider implementation *
58*********************************************************************************************************************************/
59
60DECLCALLBACK(int) sharedClipboardSvcURITransferOpen(PSHCLPROVIDERCTX pCtx)
61{
62 RT_NOREF(pCtx);
63
64 LogFlowFuncLeave();
65 return VINF_SUCCESS;
66}
67
68DECLCALLBACK(int) sharedClipboardSvcURITransferClose(PSHCLPROVIDERCTX pCtx)
69{
70 RT_NOREF(pCtx);
71
72 LogFlowFuncLeave();
73 return VINF_SUCCESS;
74}
75
76DECLCALLBACK(int) sharedClipboardSvcURIGetRoots(PSHCLPROVIDERCTX pCtx, PSHCLROOTLIST *ppRootList)
77{
78 LogFlowFuncEnter();
79
80 PSHCLCLIENT pClient = (PSHCLCLIENT)pCtx->pvUser;
81 AssertPtr(pClient);
82
83 int rc;
84
85 PSHCLCLIENTMSG pMsgHdr = sharedClipboardSvcMsgAlloc(VBOX_SHCL_HOST_MSG_URI_ROOT_LIST_HDR_READ,
86 VBOX_SHCL_CPARMS_ROOT_LIST_HDR_READ);
87 if (pMsgHdr)
88 {
89 SHCLEVENTID uEvent = SharedClipboardEventIDGenerate(&pCtx->pTransfer->Events);
90
91 HGCMSvcSetU32(&pMsgHdr->paParms[0], VBOX_SHCL_CONTEXTID_MAKE(pClient->State.uSessionID,
92 pCtx->pTransfer->State.uID, uEvent));
93 HGCMSvcSetU32(&pMsgHdr->paParms[1], 0 /* fRoots */);
94
95 rc = sharedClipboardSvcMsgAdd(pClient, pMsgHdr, true /* fAppend */);
96 if (RT_SUCCESS(rc))
97 {
98 int rc2 = SharedClipboardEventRegister(&pCtx->pTransfer->Events, uEvent);
99 AssertRC(rc2);
100
101 rc = sharedClipboardSvcClientWakeup(pClient);
102 if (RT_SUCCESS(rc))
103 {
104 PSHCLEVENTPAYLOAD pPayloadHdr;
105 rc = SharedClipboardEventWait(&pCtx->pTransfer->Events, uEvent,
106 pCtx->pTransfer->uTimeoutMs, &pPayloadHdr);
107 if (RT_SUCCESS(rc))
108 {
109 PSHCLROOTLISTHDR pSrcRootListHdr = (PSHCLROOTLISTHDR)pPayloadHdr->pvData;
110 Assert(pPayloadHdr->cbData == sizeof(SHCLROOTLISTHDR));
111
112 LogFlowFunc(("cRoots=%RU32, fRoots=0x%x\n", pSrcRootListHdr->cRoots, pSrcRootListHdr->fRoots));
113
114 PSHCLROOTLIST pRootList = SharedClipboardURIRootListAlloc();
115 if (pRootList)
116 {
117 if (pSrcRootListHdr->cRoots)
118 {
119 pRootList->paEntries =
120 (PSHCLROOTLISTENTRY)RTMemAllocZ(pSrcRootListHdr->cRoots * sizeof(SHCLROOTLISTENTRY));
121
122 if (pRootList->paEntries)
123 {
124 for (uint32_t i = 0; i < pSrcRootListHdr->cRoots; i++)
125 {
126 PSHCLCLIENTMSG pMsgEntry = sharedClipboardSvcMsgAlloc(VBOX_SHCL_HOST_MSG_URI_ROOT_LIST_ENTRY_READ,
127 VBOX_SHCL_CPARMS_ROOT_LIST_ENTRY_READ_REQ);
128
129 uEvent = SharedClipboardEventIDGenerate(&pCtx->pTransfer->Events);
130
131 HGCMSvcSetU32(&pMsgEntry->paParms[0],
132 VBOX_SHCL_CONTEXTID_MAKE(pClient->State.uClientID,
133 pCtx->pTransfer->State.uID, uEvent));
134 HGCMSvcSetU32(&pMsgEntry->paParms[1], 0 /* fRoots */);
135 HGCMSvcSetU32(&pMsgEntry->paParms[2], i /* uIndex */);
136
137 rc2 = SharedClipboardEventRegister(&pCtx->pTransfer->Events, uEvent);
138 AssertRC(rc2);
139
140 rc = sharedClipboardSvcMsgAdd(pClient, pMsgEntry, true /* fAppend */);
141 if (RT_FAILURE(rc))
142 break;
143
144 PSHCLEVENTPAYLOAD pPayloadEntry;
145 rc = SharedClipboardEventWait(&pCtx->pTransfer->Events, uEvent,
146 pCtx->pTransfer->uTimeoutMs, &pPayloadEntry);
147 if (RT_FAILURE(rc))
148 break;
149
150 PSHCLROOTLISTENTRY pSrcRootListEntry = (PSHCLROOTLISTENTRY)pPayloadEntry->pvData;
151 Assert(pPayloadEntry->cbData == sizeof(SHCLROOTLISTENTRY));
152
153 rc = SharedClipboardURIListEntryCopy(&pRootList->paEntries[i], pSrcRootListEntry);
154
155 SharedClipboardPayloadFree(pPayloadEntry);
156
157 SharedClipboardEventUnregister(&pCtx->pTransfer->Events, uEvent);
158
159 if (RT_FAILURE(rc))
160 break;
161 }
162 }
163 else
164 rc = VERR_NO_MEMORY;
165 }
166
167 if (RT_SUCCESS(rc))
168 {
169 pRootList->Hdr.cRoots = pSrcRootListHdr->cRoots;
170 pRootList->Hdr.fRoots = 0; /** @todo Implement this. */
171
172 *ppRootList = pRootList;
173 }
174 else
175 SharedClipboardURIRootListFree(pRootList);
176
177 SharedClipboardPayloadFree(pPayloadHdr);
178 }
179 else
180 rc = VERR_NO_MEMORY;
181 }
182 }
183
184 SharedClipboardEventUnregister(&pCtx->pTransfer->Events, uEvent);
185 }
186 }
187 else
188 rc = VERR_NO_MEMORY;
189
190 LogFlowFuncLeave();
191 return rc;
192}
193
194DECLCALLBACK(int) sharedClipboardSvcURIListOpen(PSHCLPROVIDERCTX pCtx,
195 PSHCLLISTOPENPARMS pOpenParms, PSHCLLISTHANDLE phList)
196{
197 LogFlowFuncEnter();
198
199 PSHCLCLIENT pClient = (PSHCLCLIENT)pCtx->pvUser;
200 AssertPtr(pClient);
201
202 int rc;
203
204 PSHCLCLIENTMSG pMsg = sharedClipboardSvcMsgAlloc(VBOX_SHCL_HOST_MSG_URI_LIST_OPEN,
205 VBOX_SHCL_CPARMS_LIST_OPEN);
206 if (pMsg)
207 {
208 const SHCLEVENTID uEvent = SharedClipboardEventIDGenerate(&pCtx->pTransfer->Events);
209
210 pMsg->Ctx.uContextID = VBOX_SHCL_CONTEXTID_MAKE(pClient->State.uSessionID, pCtx->pTransfer->State.uID,
211 uEvent);
212
213 rc = sharedClipboardSvcURISetListOpen(pMsg->cParms, pMsg->paParms, &pMsg->Ctx, pOpenParms);
214 if (RT_SUCCESS(rc))
215 {
216 rc = sharedClipboardSvcMsgAdd(pClient, pMsg, true /* fAppend */);
217 if (RT_SUCCESS(rc))
218 {
219 int rc2 = SharedClipboardEventRegister(&pCtx->pTransfer->Events, uEvent);
220 AssertRC(rc2);
221
222 rc = sharedClipboardSvcClientWakeup(pClient);
223 if (RT_SUCCESS(rc))
224 {
225 PSHCLEVENTPAYLOAD pPayload;
226 rc = SharedClipboardEventWait(&pCtx->pTransfer->Events, uEvent, pCtx->pTransfer->uTimeoutMs, &pPayload);
227 if (RT_SUCCESS(rc))
228 {
229 Assert(pPayload->cbData == sizeof(SHCLREPLY));
230
231 PSHCLREPLY pReply = (PSHCLREPLY)pPayload->pvData;
232 AssertPtr(pReply);
233
234 Assert(pReply->uType == VBOX_SHCL_REPLYMSGTYPE_LIST_OPEN);
235
236 *phList = pReply->u.ListOpen.uHandle;
237
238 SharedClipboardPayloadFree(pPayload);
239 }
240 }
241
242 SharedClipboardEventUnregister(&pCtx->pTransfer->Events, uEvent);
243 }
244 }
245 }
246 else
247 rc = VERR_NO_MEMORY;
248
249 LogFlowFuncLeaveRC(rc);
250 return rc;
251}
252
253DECLCALLBACK(int) sharedClipboardSvcURIListClose(PSHCLPROVIDERCTX pCtx, SHCLLISTHANDLE hList)
254{
255 LogFlowFuncEnter();
256
257 PSHCLCLIENT pClient = (PSHCLCLIENT)pCtx->pvUser;
258 AssertPtr(pClient);
259
260 int rc;
261
262 PSHCLCLIENTMSG pMsg = sharedClipboardSvcMsgAlloc(VBOX_SHCL_HOST_MSG_URI_LIST_CLOSE,
263 VBOX_SHCL_CPARMS_LIST_CLOSE);
264 if (pMsg)
265 {
266 const SHCLEVENTID uEvent = SharedClipboardEventIDGenerate(&pCtx->pTransfer->Events);
267
268 pMsg->Ctx.uContextID = VBOX_SHCL_CONTEXTID_MAKE(pClient->State.uSessionID, pCtx->pTransfer->State.uID,
269 uEvent);
270
271 rc = sharedClipboardSvcURISetListClose(pMsg->cParms, pMsg->paParms, &pMsg->Ctx, hList);
272 if (RT_SUCCESS(rc))
273 {
274 rc = sharedClipboardSvcMsgAdd(pClient, pMsg, true /* fAppend */);
275 if (RT_SUCCESS(rc))
276 {
277 int rc2 = SharedClipboardEventRegister(&pCtx->pTransfer->Events, uEvent);
278 AssertRC(rc2);
279
280 rc = sharedClipboardSvcClientWakeup(pClient);
281 if (RT_SUCCESS(rc))
282 {
283 PSHCLEVENTPAYLOAD pPayload;
284 rc = SharedClipboardEventWait(&pCtx->pTransfer->Events, uEvent, pCtx->pTransfer->uTimeoutMs, &pPayload);
285 if (RT_SUCCESS(rc))
286 SharedClipboardPayloadFree(pPayload);
287 }
288
289 SharedClipboardEventUnregister(&pCtx->pTransfer->Events, uEvent);
290 }
291 }
292 }
293 else
294 rc = VERR_NO_MEMORY;
295
296 LogFlowFuncLeaveRC(rc);
297 return rc;
298}
299
300DECLCALLBACK(int) sharedClipboardSvcURIListHdrRead(PSHCLPROVIDERCTX pCtx,
301 SHCLLISTHANDLE hList, PSHCLLISTHDR pListHdr)
302{
303 LogFlowFuncEnter();
304
305 PSHCLCLIENT pClient = (PSHCLCLIENT)pCtx->pvUser;
306 AssertPtr(pClient);
307
308 int rc;
309
310 PSHCLCLIENTMSG pMsg = sharedClipboardSvcMsgAlloc(VBOX_SHCL_HOST_MSG_URI_LIST_HDR_READ,
311 VBOX_SHCL_CPARMS_LIST_HDR_READ_REQ);
312 if (pMsg)
313 {
314 const SHCLEVENTID uEvent = SharedClipboardEventIDGenerate(&pCtx->pTransfer->Events);
315
316 HGCMSvcSetU32(&pMsg->paParms[0], VBOX_SHCL_CONTEXTID_MAKE(pClient->State.uSessionID,
317 pCtx->pTransfer->State.uID, uEvent));
318 HGCMSvcSetU64(&pMsg->paParms[1], hList);
319 HGCMSvcSetU32(&pMsg->paParms[2], 0 /* fFlags */);
320
321 rc = sharedClipboardSvcMsgAdd(pClient, pMsg, true /* fAppend */);
322 if (RT_SUCCESS(rc))
323 {
324 int rc2 = SharedClipboardEventRegister(&pCtx->pTransfer->Events, uEvent);
325 AssertRC(rc2);
326
327 rc = sharedClipboardSvcClientWakeup(pClient);
328 if (RT_SUCCESS(rc))
329 {
330 PSHCLEVENTPAYLOAD pPayload;
331 rc = SharedClipboardEventWait(&pCtx->pTransfer->Events, uEvent,
332 pCtx->pTransfer->uTimeoutMs, &pPayload);
333 if (RT_SUCCESS(rc))
334 {
335 Assert(pPayload->cbData == sizeof(SHCLLISTHDR));
336
337 *pListHdr = *(PSHCLLISTHDR)pPayload->pvData;
338
339 SharedClipboardPayloadFree(pPayload);
340 }
341 }
342 }
343 }
344 else
345 rc = VERR_NO_MEMORY;
346
347 LogFlowFuncLeaveRC(rc);
348 return rc;
349}
350
351DECLCALLBACK(int) sharedClipboardSvcURIListHdrWrite(PSHCLPROVIDERCTX pCtx,
352 SHCLLISTHANDLE hList, PSHCLLISTHDR pListHdr)
353{
354 RT_NOREF(pCtx, hList, pListHdr);
355
356 LogFlowFuncEnter();
357
358 return VERR_NOT_IMPLEMENTED;
359}
360
361DECLCALLBACK(int) sharedClipboardSvcURIListEntryRead(PSHCLPROVIDERCTX pCtx,
362 SHCLLISTHANDLE hList, PSHCLLISTENTRY pListEntry)
363{
364 LogFlowFuncEnter();
365
366 PSHCLCLIENT pClient = (PSHCLCLIENT)pCtx->pvUser;
367 AssertPtr(pClient);
368
369 int rc;
370
371 PSHCLCLIENTMSG pMsg = sharedClipboardSvcMsgAlloc(VBOX_SHCL_HOST_MSG_URI_LIST_ENTRY_READ,
372 VBOX_SHCL_CPARMS_LIST_ENTRY_READ);
373 if (pMsg)
374 {
375 const SHCLEVENTID uEvent = SharedClipboardEventIDGenerate(&pCtx->pTransfer->Events);
376
377 HGCMSvcSetU32(&pMsg->paParms[0], VBOX_SHCL_CONTEXTID_MAKE(pClient->State.uSessionID,
378 pCtx->pTransfer->State.uID, uEvent));
379 HGCMSvcSetU64(&pMsg->paParms[1], hList);
380 HGCMSvcSetU32(&pMsg->paParms[2], 0 /* fInfo */);
381
382 rc = sharedClipboardSvcMsgAdd(pClient, pMsg, true /* fAppend */);
383 if (RT_SUCCESS(rc))
384 {
385 int rc2 = SharedClipboardEventRegister(&pCtx->pTransfer->Events, uEvent);
386 AssertRC(rc2);
387
388 rc = sharedClipboardSvcClientWakeup(pClient);
389 if (RT_SUCCESS(rc))
390 {
391 PSHCLEVENTPAYLOAD pPayload;
392 rc = SharedClipboardEventWait(&pCtx->pTransfer->Events, uEvent, pCtx->pTransfer->uTimeoutMs, &pPayload);
393 if (RT_SUCCESS(rc))
394 {
395 Assert(pPayload->cbData == sizeof(SHCLLISTENTRY));
396
397 rc = SharedClipboardURIListEntryCopy(pListEntry, (PSHCLLISTENTRY)pPayload->pvData);
398
399 SharedClipboardPayloadFree(pPayload);
400 }
401 }
402 }
403 }
404 else
405 rc = VERR_NO_MEMORY;
406
407 LogFlowFuncLeaveRC(rc);
408 return rc;
409}
410
411DECLCALLBACK(int) sharedClipboardSvcURIListEntryWrite(PSHCLPROVIDERCTX pCtx,
412 SHCLLISTHANDLE hList, PSHCLLISTENTRY pListEntry)
413{
414 RT_NOREF(pCtx, hList, pListEntry);
415
416 LogFlowFuncEnter();
417
418 return VERR_NOT_IMPLEMENTED;
419}
420
421int sharedClipboardSvcURIObjOpen(PSHCLPROVIDERCTX pCtx, PSHCLOBJOPENCREATEPARMS pCreateParms,
422 PSHCLOBJHANDLE phObj)
423{
424 LogFlowFuncEnter();
425
426 PSHCLCLIENT pClient = (PSHCLCLIENT)pCtx->pvUser;
427 AssertPtr(pClient);
428
429 int rc;
430
431 PSHCLCLIENTMSG pMsg = sharedClipboardSvcMsgAlloc(VBOX_SHCL_HOST_MSG_URI_OBJ_OPEN,
432 VBOX_SHCL_CPARMS_OBJ_OPEN);
433 if (pMsg)
434 {
435 const SHCLEVENTID uEvent = SharedClipboardEventIDGenerate(&pCtx->pTransfer->Events);
436
437 LogFlowFunc(("pszPath=%s, fCreate=0x%x\n", pCreateParms->pszPath, pCreateParms->fCreate));
438
439 const uint32_t cbPath = (uint32_t)strlen(pCreateParms->pszPath) + 1; /* Include terminating zero */
440
441 HGCMSvcSetU32(&pMsg->paParms[0], VBOX_SHCL_CONTEXTID_MAKE(pClient->State.uSessionID,
442 pCtx->pTransfer->State.uID, uEvent));
443 HGCMSvcSetU64(&pMsg->paParms[1], 0); /* uHandle */
444 HGCMSvcSetU32(&pMsg->paParms[2], cbPath);
445 HGCMSvcSetPv (&pMsg->paParms[3], pCreateParms->pszPath, cbPath);
446 HGCMSvcSetU32(&pMsg->paParms[4], pCreateParms->fCreate);
447
448 rc = sharedClipboardSvcMsgAdd(pClient, pMsg, true /* fAppend */);
449 if (RT_SUCCESS(rc))
450 {
451 int rc2 = SharedClipboardEventRegister(&pCtx->pTransfer->Events, uEvent);
452 AssertRC(rc2);
453
454 rc = sharedClipboardSvcClientWakeup(pClient);
455 if (RT_SUCCESS(rc))
456 {
457 PSHCLEVENTPAYLOAD pPayload;
458 rc = SharedClipboardEventWait(&pCtx->pTransfer->Events, uEvent, pCtx->pTransfer->uTimeoutMs, &pPayload);
459 if (RT_SUCCESS(rc))
460 {
461 Assert(pPayload->cbData == sizeof(SHCLREPLY));
462
463 PSHCLREPLY pReply = (PSHCLREPLY)pPayload->pvData;
464 AssertPtr(pReply);
465
466 Assert(pReply->uType == VBOX_SHCL_REPLYMSGTYPE_OBJ_OPEN);
467
468 *phObj = pReply->u.ObjOpen.uHandle;
469
470 SharedClipboardPayloadFree(pPayload);
471 }
472 }
473 }
474 }
475 else
476 rc = VERR_NO_MEMORY;
477
478 LogFlowFuncLeaveRC(rc);
479 return rc;
480}
481
482int sharedClipboardSvcURIObjClose(PSHCLPROVIDERCTX pCtx, SHCLOBJHANDLE hObj)
483{
484 LogFlowFuncEnter();
485
486 PSHCLCLIENT pClient = (PSHCLCLIENT)pCtx->pvUser;
487 AssertPtr(pClient);
488
489 int rc;
490
491 PSHCLCLIENTMSG pMsg = sharedClipboardSvcMsgAlloc(VBOX_SHCL_HOST_MSG_URI_OBJ_CLOSE,
492 VBOX_SHCL_CPARMS_OBJ_CLOSE);
493 if (pMsg)
494 {
495 const SHCLEVENTID uEvent = SharedClipboardEventIDGenerate(&pCtx->pTransfer->Events);
496
497 HGCMSvcSetU32(&pMsg->paParms[0], VBOX_SHCL_CONTEXTID_MAKE(pClient->State.uSessionID,
498 pCtx->pTransfer->State.uID, uEvent));
499 HGCMSvcSetU64(&pMsg->paParms[1], hObj);
500
501 rc = sharedClipboardSvcMsgAdd(pClient, pMsg, true /* fAppend */);
502 if (RT_SUCCESS(rc))
503 {
504 int rc2 = SharedClipboardEventRegister(&pCtx->pTransfer->Events, uEvent);
505 AssertRC(rc2);
506
507 rc = sharedClipboardSvcClientWakeup(pClient);
508 if (RT_SUCCESS(rc))
509 {
510 PSHCLEVENTPAYLOAD pPayload;
511 rc = SharedClipboardEventWait(&pCtx->pTransfer->Events, uEvent, pCtx->pTransfer->uTimeoutMs, &pPayload);
512 if (RT_SUCCESS(rc))
513 {
514 Assert(pPayload->cbData == sizeof(SHCLREPLY));
515
516#ifdef VBOX_STRICT
517 PSHCLREPLY pReply = (PSHCLREPLY)pPayload->pvData;
518 AssertPtr(pReply);
519
520 Assert(pReply->uType == VBOX_SHCL_REPLYMSGTYPE_OBJ_CLOSE);
521#endif
522
523 SharedClipboardPayloadFree(pPayload);
524 }
525 }
526 }
527 }
528 else
529 rc = VERR_NO_MEMORY;
530
531 LogFlowFuncLeaveRC(rc);
532 return rc;
533}
534
535int sharedClipboardSvcURIObjRead(PSHCLPROVIDERCTX pCtx, SHCLOBJHANDLE hObj,
536 void *pvData, uint32_t cbData, uint32_t fFlags, uint32_t *pcbRead)
537{
538 LogFlowFuncEnter();
539
540 PSHCLCLIENT pClient = (PSHCLCLIENT)pCtx->pvUser;
541 AssertPtr(pClient);
542
543 int rc;
544
545 PSHCLCLIENTMSG pMsg = sharedClipboardSvcMsgAlloc(VBOX_SHCL_HOST_MSG_URI_OBJ_READ,
546 VBOX_SHCL_CPARMS_OBJ_READ_REQ);
547 if (pMsg)
548 {
549 const SHCLEVENTID uEvent = SharedClipboardEventIDGenerate(&pCtx->pTransfer->Events);
550
551 HGCMSvcSetU32(&pMsg->paParms[0], VBOX_SHCL_CONTEXTID_MAKE(pClient->State.uSessionID,
552 pCtx->pTransfer->State.uID, uEvent));
553 HGCMSvcSetU64(&pMsg->paParms[1], hObj);
554 HGCMSvcSetU32(&pMsg->paParms[2], cbData);
555 HGCMSvcSetU32(&pMsg->paParms[3], fFlags);
556
557 rc = sharedClipboardSvcMsgAdd(pClient, pMsg, true /* fAppend */);
558 if (RT_SUCCESS(rc))
559 {
560 int rc2 = SharedClipboardEventRegister(&pCtx->pTransfer->Events, uEvent);
561 AssertRC(rc2);
562
563 rc = sharedClipboardSvcClientWakeup(pClient);
564 if (RT_SUCCESS(rc))
565 {
566 PSHCLEVENTPAYLOAD pPayload;
567 rc = SharedClipboardEventWait(&pCtx->pTransfer->Events, uEvent, pCtx->pTransfer->uTimeoutMs, &pPayload);
568 if (RT_SUCCESS(rc))
569 {
570 Assert(pPayload->cbData == sizeof(SHCLOBJDATACHUNK));
571
572 PSHCLOBJDATACHUNK pDataChunk = (PSHCLOBJDATACHUNK)pPayload->pvData;
573 AssertPtr(pDataChunk);
574
575 const uint32_t cbRead = RT_MIN(cbData, pDataChunk->cbData);
576
577 memcpy(pvData, pDataChunk->pvData, cbRead);
578
579 if (pcbRead)
580 *pcbRead = cbRead;
581
582 SharedClipboardPayloadFree(pPayload);
583 }
584 }
585 }
586 }
587 else
588 rc = VERR_NO_MEMORY;
589
590 LogFlowFuncLeaveRC(rc);
591 return rc;
592}
593
594int sharedClipboardSvcURIObjWrite(PSHCLPROVIDERCTX pCtx, SHCLOBJHANDLE hObj,
595 void *pvData, uint32_t cbData, uint32_t fFlags, uint32_t *pcbWritten)
596{
597 LogFlowFuncEnter();
598
599 PSHCLCLIENT pClient = (PSHCLCLIENT)pCtx->pvUser;
600 AssertPtr(pClient);
601
602 int rc;
603
604 PSHCLCLIENTMSG pMsg = sharedClipboardSvcMsgAlloc(VBOX_SHCL_HOST_MSG_URI_OBJ_WRITE,
605 VBOX_SHCL_CPARMS_OBJ_WRITE);
606 if (pMsg)
607 {
608 const SHCLEVENTID uEvent = SharedClipboardEventIDGenerate(&pCtx->pTransfer->Events);
609
610 HGCMSvcSetU32(&pMsg->paParms[0], VBOX_SHCL_CONTEXTID_MAKE(pClient->State.uSessionID,
611 pCtx->pTransfer->State.uID, uEvent));
612 HGCMSvcSetU64(&pMsg->paParms[1], hObj);
613 HGCMSvcSetU64(&pMsg->paParms[2], cbData);
614 HGCMSvcSetU64(&pMsg->paParms[3], fFlags);
615
616 rc = sharedClipboardSvcMsgAdd(pClient, pMsg, true /* fAppend */);
617 if (RT_SUCCESS(rc))
618 {
619 int rc2 = SharedClipboardEventRegister(&pCtx->pTransfer->Events, uEvent);
620 AssertRC(rc2);
621
622 rc = sharedClipboardSvcClientWakeup(pClient);
623 if (RT_SUCCESS(rc))
624 {
625 PSHCLEVENTPAYLOAD pPayload;
626 rc = SharedClipboardEventWait(&pCtx->pTransfer->Events, uEvent, pCtx->pTransfer->uTimeoutMs, &pPayload);
627 if (RT_SUCCESS(rc))
628 {
629 const uint32_t cbRead = RT_MIN(cbData, pPayload->cbData);
630
631 memcpy(pvData, pPayload->pvData, cbRead);
632
633 if (pcbWritten)
634 *pcbWritten = cbRead;
635
636 SharedClipboardPayloadFree(pPayload);
637 }
638 }
639 }
640 }
641 else
642 rc = VERR_NO_MEMORY;
643
644 LogFlowFuncLeaveRC(rc);
645 return rc;
646}
647
648
649/*********************************************************************************************************************************
650* URI callbacks *
651*********************************************************************************************************************************/
652
653DECLCALLBACK(void) VBoxSvcClipboardURITransferPrepareCallback(PSHCLURITRANSFERCALLBACKDATA pData)
654{
655 RT_NOREF(pData);
656
657 LogFlowFuncEnter();
658}
659
660DECLCALLBACK(void) VBoxSvcClipboardURITransferCompleteCallback(PSHCLURITRANSFERCALLBACKDATA pData, int rc)
661{
662 RT_NOREF(pData, rc);
663
664 LogFlowFuncEnter();
665
666 LogRel2(("Shared Clipboard: Transfer complete\n"));
667}
668
669DECLCALLBACK(void) VBoxSvcClipboardURITransferCanceledCallback(PSHCLURITRANSFERCALLBACKDATA pData)
670{
671 LogFlowFuncEnter();
672
673 RT_NOREF(pData);
674
675 LogRel2(("Shared Clipboard: Transfer canceled\n"));
676}
677
678DECLCALLBACK(void) VBoxSvcClipboardURITransferErrorCallback(PSHCLURITRANSFERCALLBACKDATA pData, int rc)
679{
680 LogFlowFuncEnter();
681
682 RT_NOREF(pData, rc);
683
684 LogRel(("Shared Clipboard: Transfer failed with %Rrc\n", rc));
685}
686
687
688/*********************************************************************************************************************************
689* HGCM getters / setters *
690*********************************************************************************************************************************/
691
692/**
693 * Gets an URI message reply from HGCM service parameters.
694 *
695 * @returns VBox status code.
696 * @param cParms Number of HGCM parameters supplied in \a paParms.
697 * @param paParms Array of HGCM parameters.
698 * @param pReply Where to store the reply.
699 */
700static int sharedClipboardSvcURIGetReply(uint32_t cParms, VBOXHGCMSVCPARM paParms[],
701 PSHCLREPLY pReply)
702{
703 int rc;
704
705 if (cParms >= VBOX_SHCL_CPARMS_REPLY_MIN)
706 {
707 uint32_t cbPayload = 0;
708
709 /* paParms[0] has the context ID. */
710 rc = HGCMSvcGetU32(&paParms[1], &pReply->uType);
711 if (RT_SUCCESS(rc))
712 rc = HGCMSvcGetU32(&paParms[2], &pReply->rc);
713 if (RT_SUCCESS(rc))
714 rc = HGCMSvcGetU32(&paParms[3], &cbPayload);
715 if (RT_SUCCESS(rc))
716 {
717 rc = HGCMSvcGetPv(&paParms[4], &pReply->pvPayload, &pReply->cbPayload);
718 AssertReturn(cbPayload == pReply->cbPayload, VERR_INVALID_PARAMETER);
719 }
720
721 if (RT_SUCCESS(rc))
722 {
723 rc = VERR_INVALID_PARAMETER; /* Play safe. */
724
725 switch (pReply->uType)
726 {
727 case VBOX_SHCL_REPLYMSGTYPE_TRANSFER_STATUS:
728 {
729 if (cParms >= 6)
730 rc = HGCMSvcGetU32(&paParms[5], &pReply->u.TransferStatus.uStatus);
731 break;
732 }
733
734 case VBOX_SHCL_REPLYMSGTYPE_LIST_OPEN:
735 {
736 if (cParms >= 6)
737 rc = HGCMSvcGetU64(&paParms[5], &pReply->u.ListOpen.uHandle);
738 break;
739 }
740
741 case VBOX_SHCL_REPLYMSGTYPE_OBJ_OPEN:
742 {
743 if (cParms >= 6)
744 rc = HGCMSvcGetU64(&paParms[5], &pReply->u.ObjOpen.uHandle);
745 break;
746 }
747
748 case VBOX_SHCL_REPLYMSGTYPE_OBJ_CLOSE:
749 {
750 if (cParms >= 6)
751 rc = HGCMSvcGetU64(&paParms[5], &pReply->u.ObjClose.uHandle);
752 break;
753 }
754
755 default:
756 rc = VERR_NOT_SUPPORTED;
757 break;
758 }
759 }
760 }
761 else
762 rc = VERR_INVALID_PARAMETER;
763
764 LogFlowFuncLeaveRC(rc);
765 return rc;
766}
767
768/**
769 * Gets an URI root list header from HGCM service parameters.
770 *
771 * @returns VBox status code.
772 * @param cParms Number of HGCM parameters supplied in \a paParms.
773 * @param paParms Array of HGCM parameters.
774 * @param pRootLstHdr Where to store the URI root list header on success.
775 */
776static int sharedClipboardSvcURIGetRootListHdr(uint32_t cParms, VBOXHGCMSVCPARM paParms[],
777 PSHCLROOTLISTHDR pRootLstHdr)
778{
779 int rc;
780
781 if (cParms == VBOX_SHCL_CPARMS_ROOT_LIST_HDR)
782 {
783 rc = HGCMSvcGetU32(&paParms[1], &pRootLstHdr->fRoots);
784 if (RT_SUCCESS(rc))
785 rc = HGCMSvcGetU32(&paParms[2], &pRootLstHdr->cRoots);
786 }
787 else
788 rc = VERR_INVALID_PARAMETER;
789
790 LogFlowFuncLeaveRC(rc);
791 return rc;
792}
793
794/**
795 * Gets an URI root list entry from HGCM service parameters.
796 *
797 * @returns VBox status code.
798 * @param cParms Number of HGCM parameters supplied in \a paParms.
799 * @param paParms Array of HGCM parameters.
800 * @param pListEntry Where to store the root list entry.
801 */
802static int sharedClipboardSvcURIGetRootListEntry(uint32_t cParms, VBOXHGCMSVCPARM paParms[],
803 PSHCLROOTLISTENTRY pListEntry)
804{
805 int rc;
806
807 if (cParms == VBOX_SHCL_CPARMS_ROOT_LIST_ENTRY)
808 {
809 rc = HGCMSvcGetU32(&paParms[1], &pListEntry->fInfo);
810 /* Note: paParms[2] contains the entry index, currently being ignored. */
811 if (RT_SUCCESS(rc))
812 rc = HGCMSvcGetPv(&paParms[3], (void **)&pListEntry->pszName, &pListEntry->cbName);
813 if (RT_SUCCESS(rc))
814 {
815 uint32_t cbInfo;
816 rc = HGCMSvcGetU32(&paParms[4], &cbInfo);
817 if (RT_SUCCESS(rc))
818 {
819 rc = HGCMSvcGetPv(&paParms[5], &pListEntry->pvInfo, &pListEntry->cbInfo);
820 AssertReturn(cbInfo == pListEntry->cbInfo, VERR_INVALID_PARAMETER);
821 }
822 }
823 }
824 else
825 rc = VERR_INVALID_PARAMETER;
826
827 LogFlowFuncLeaveRC(rc);
828 return rc;
829}
830
831/**
832 * Gets an URI list open request from HGCM service parameters.
833 *
834 * @returns VBox status code.
835 * @param cParms Number of HGCM parameters supplied in \a paParms.
836 * @param paParms Array of HGCM parameters.
837 * @param pOpenParms Where to store the open parameters of the request.
838 */
839static int sharedClipboardSvcURIGetListOpen(uint32_t cParms, VBOXHGCMSVCPARM paParms[],
840 PSHCLLISTOPENPARMS pOpenParms)
841{
842 int rc;
843
844 if (cParms == VBOX_SHCL_CPARMS_LIST_OPEN)
845 {
846 uint32_t cbPath = 0;
847 uint32_t cbFilter = 0;
848
849 rc = HGCMSvcGetU32(&paParms[1], &pOpenParms->fList);
850 if (RT_SUCCESS(rc))
851 rc = HGCMSvcGetU32(&paParms[2], &cbPath);
852 if (RT_SUCCESS(rc))
853 {
854 rc = HGCMSvcGetStr(&paParms[3], &pOpenParms->pszPath, &pOpenParms->cbPath);
855 AssertReturn(cbPath == pOpenParms->cbPath, VERR_INVALID_PARAMETER);
856 }
857 if (RT_SUCCESS(rc))
858 rc = HGCMSvcGetU32(&paParms[4], &cbFilter);
859 if (RT_SUCCESS(rc))
860 {
861 rc = HGCMSvcGetStr(&paParms[5], &pOpenParms->pszFilter, &pOpenParms->cbFilter);
862 AssertReturn(cbFilter == pOpenParms->cbFilter, VERR_INVALID_PARAMETER);
863 }
864
865 if (RT_SUCCESS(rc))
866 {
867 /** @todo Some more validation. */
868 }
869 }
870 else
871 rc = VERR_INVALID_PARAMETER;
872
873 LogFlowFuncLeaveRC(rc);
874 return rc;
875}
876
877/**
878 * Sets an URI list open request to HGCM service parameters.
879 *
880 * @returns VBox status code.
881 * @param cParms Number of HGCM parameters supplied in \a paParms.
882 * @param paParms Array of HGCM parameters.
883 * @param pMsgCtx Message context to use.
884 * @param pOpenParms List open parameters to set.
885 */
886static int sharedClipboardSvcURISetListOpen(uint32_t cParms, VBOXHGCMSVCPARM paParms[],
887 PSHCLMSGCTX pMsgCtx, PSHCLLISTOPENPARMS pOpenParms)
888{
889 int rc;
890
891 if (cParms == VBOX_SHCL_CPARMS_LIST_OPEN)
892 {
893 HGCMSvcSetU32(&paParms[0], pMsgCtx->uContextID);
894 HGCMSvcSetU32(&paParms[1], pOpenParms->fList);
895 HGCMSvcSetU32(&paParms[2], pOpenParms->cbFilter);
896 HGCMSvcSetPv (&paParms[3], pOpenParms->pszFilter, pOpenParms->cbFilter);
897 HGCMSvcSetU32(&paParms[4], pOpenParms->cbPath);
898 HGCMSvcSetPv (&paParms[5], pOpenParms->pszPath, pOpenParms->cbPath);
899 HGCMSvcSetU64(&paParms[6], 0); /* OUT: uHandle */
900
901 rc = VINF_SUCCESS;
902 }
903 else
904 rc = VERR_INVALID_PARAMETER;
905
906 LogFlowFuncLeaveRC(rc);
907 return rc;
908}
909
910/**
911 * Sets an URI list close request to HGCM service parameters.
912 *
913 * @returns VBox status code.
914 * @param cParms Number of HGCM parameters supplied in \a paParms.
915 * @param paParms Array of HGCM parameters.
916 * @param pMsgCtx Message context to use.
917 * @param hList Handle of list to close.
918 */
919static int sharedClipboardSvcURISetListClose(uint32_t cParms, VBOXHGCMSVCPARM paParms[],
920 PSHCLMSGCTX pMsgCtx, SHCLLISTHANDLE hList)
921{
922 int rc;
923
924 if (cParms == VBOX_SHCL_CPARMS_LIST_CLOSE)
925 {
926 HGCMSvcSetU32(&paParms[0], pMsgCtx->uContextID);
927 HGCMSvcSetU64(&paParms[1], hList);
928
929 rc = VINF_SUCCESS;
930 }
931 else
932 rc = VERR_INVALID_PARAMETER;
933
934 LogFlowFuncLeaveRC(rc);
935 return rc;
936}
937
938/**
939 * Gets an URI list header from HGCM service parameters.
940 *
941 * @returns VBox status code.
942 * @param cParms Number of HGCM parameters supplied in \a paParms.
943 * @param paParms Array of HGCM parameters.
944 * @param phList Where to store the list handle.
945 * @param pListHdr Where to store the list header.
946 */
947static int sharedClipboardSvcURIGetListHdr(uint32_t cParms, VBOXHGCMSVCPARM paParms[],
948 PSHCLLISTHANDLE phList, PSHCLLISTHDR pListHdr)
949{
950 int rc;
951
952 if (cParms == VBOX_SHCL_CPARMS_LIST_HDR)
953 {
954 rc = HGCMSvcGetU64(&paParms[1], phList);
955 /* Note: Flags (paParms[2]) not used here. */
956 if (RT_SUCCESS(rc))
957 rc = HGCMSvcGetU32(&paParms[3], &pListHdr->fFeatures);
958 if (RT_SUCCESS(rc))
959 rc = HGCMSvcGetU64(&paParms[4], &pListHdr->cTotalObjects);
960 if (RT_SUCCESS(rc))
961 rc = HGCMSvcGetU64(&paParms[5], &pListHdr->cbTotalSize);
962
963 if (RT_SUCCESS(rc))
964 {
965 /** @todo Validate pvMetaFmt + cbMetaFmt. */
966 /** @todo Validate header checksum. */
967 }
968 }
969 else
970 rc = VERR_INVALID_PARAMETER;
971
972 LogFlowFuncLeaveRC(rc);
973 return rc;
974}
975
976#if 0
977/**
978 * Sets an URI list header to HGCM service parameters.
979 *
980 * @returns VBox status code.
981 * @param cParms Number of HGCM parameters supplied in \a paParms.
982 * @param paParms Array of HGCM parameters.
983 * @param pMsgCtx Message context to use.
984 * @param pListHdr Pointer to data to set to the HGCM parameters.
985 */
986static int sharedClipboardSvcURISetListHdr(uint32_t cParms, VBOXHGCMSVCPARM paParms[],
987 PVBOXSHCLMSGCTX pMsgCtx, PSHCLLISTHDR pListHdr)
988{
989 int rc;
990
991 if (cParms == VBOX_SHCL_CPARMS_LIST_HDR)
992 {
993 /** @todo Set pvMetaFmt + cbMetaFmt. */
994 /** @todo Calculate header checksum. */
995
996 HGCMSvcSetU32(&paParms[0], pMsgCtx->uContextID);
997 HGCMSvcSetU32(&paParms[1], pListHdr->fFeatures);
998 HGCMSvcSetU32(&paParms[2], 0 /* Features, will be returned on success */);
999 HGCMSvcSetU64(&paParms[3], pListHdr->cTotalObjects);
1000 HGCMSvcSetU64(&paParms[4], pListHdr->cbTotalSize);
1001
1002 rc = VINF_SUCCESS;
1003 }
1004 else
1005 rc = VERR_INVALID_PARAMETER;
1006
1007 LogFlowFuncLeaveRC(rc);
1008 return rc;
1009}
1010#endif
1011
1012/**
1013 * Gets an URI list entry from HGCM service parameters.
1014 *
1015 * @returns VBox status code.
1016 * @param cParms Number of HGCM parameters supplied in \a paParms.
1017 * @param paParms Array of HGCM parameters.
1018 * @param phList Where to store the list handle.
1019 * @param pListEntry Where to store the list entry.
1020 */
1021static int sharedClipboardSvcURIGetListEntry(uint32_t cParms, VBOXHGCMSVCPARM paParms[],
1022 PSHCLLISTHANDLE phList, PSHCLLISTENTRY pListEntry)
1023{
1024 int rc;
1025
1026 if (cParms == VBOX_SHCL_CPARMS_LIST_ENTRY)
1027 {
1028 rc = HGCMSvcGetU64(&paParms[1], phList);
1029 if (RT_SUCCESS(rc))
1030 rc = HGCMSvcGetU32(&paParms[2], &pListEntry->fInfo);
1031 if (RT_SUCCESS(rc))
1032 rc = HGCMSvcGetPv(&paParms[3], (void **)&pListEntry->pszName, &pListEntry->cbName);
1033 if (RT_SUCCESS(rc))
1034 {
1035 uint32_t cbInfo;
1036 rc = HGCMSvcGetU32(&paParms[4], &cbInfo);
1037 if (RT_SUCCESS(rc))
1038 {
1039 rc = HGCMSvcGetPv(&paParms[5], &pListEntry->pvInfo, &pListEntry->cbInfo);
1040 AssertReturn(cbInfo == pListEntry->cbInfo, VERR_INVALID_PARAMETER);
1041 }
1042 }
1043
1044 if (RT_SUCCESS(rc))
1045 {
1046 if (!SharedClipboardURIListEntryIsValid(pListEntry))
1047 rc = VERR_INVALID_PARAMETER;
1048 }
1049 }
1050 else
1051 rc = VERR_INVALID_PARAMETER;
1052
1053 LogFlowFuncLeaveRC(rc);
1054 return rc;
1055}
1056
1057#if 0
1058/**
1059 * Sets an URI data chunk to HGCM service parameters.
1060 *
1061 * @returns VBox status code.
1062 * @param cParms Number of HGCM parameters supplied in \a paParms.
1063 * @param paParms Array of HGCM parameters.
1064 * @param pMsgCtx Message context to use.
1065 * @param pListEntry Pointer to data to set to the HGCM parameters.
1066 */
1067static int sharedClipboardSvcURISetListEntry(uint32_t cParms, VBOXHGCMSVCPARM paParms[],
1068 PVBOXSHCLMSGCTX pMsgCtx, PSHCLLISTENTRY pListEntry)
1069{
1070 int rc;
1071
1072 if (cParms == VBOX_SHCL_CPARMS_LIST_ENTRY)
1073 {
1074 /** @todo Calculate chunk checksum. */
1075
1076 HGCMSvcSetU32(&paParms[0], pMsgCtx->uContextID);
1077 HGCMSvcSetU32(&paParms[1], pListEntry->fInfo);
1078 HGCMSvcSetU32(&paParms[2], pListEntry->cbInfo);
1079 HGCMSvcSetPv (&paParms[3], pListEntry->pvInfo, pListEntry->cbInfo);
1080
1081 rc = VINF_SUCCESS;
1082 }
1083 else
1084 rc = VERR_INVALID_PARAMETER;
1085
1086 LogFlowFuncLeaveRC(rc);
1087 return rc;
1088}
1089#endif
1090
1091/**
1092 * Gets an URI object data chunk from HGCM service parameters.
1093 *
1094 * @returns VBox status code.
1095 * @param cParms Number of HGCM parameters supplied in \a paParms.
1096 * @param paParms Array of HGCM parameters.
1097 * @param pDataChunk Where to store the object data chunk data.
1098 */
1099static int sharedClipboardSvcURIGetObjDataChunk(uint32_t cParms, VBOXHGCMSVCPARM paParms[], PSHCLOBJDATACHUNK pDataChunk)
1100{
1101 AssertPtrReturn(paParms, VERR_INVALID_PARAMETER);
1102 AssertPtrReturn(pDataChunk, VERR_INVALID_PARAMETER);
1103
1104 int rc;
1105
1106 if (cParms == VBOX_SHCL_CPARMS_OBJ_WRITE)
1107 {
1108 rc = HGCMSvcGetU64(&paParms[1], &pDataChunk->uHandle);
1109 if (RT_SUCCESS(rc))
1110 {
1111 uint32_t cbData;
1112 rc = HGCMSvcGetU32(&paParms[2], &cbData);
1113 if (RT_SUCCESS(rc))
1114 {
1115 rc = HGCMSvcGetPv(&paParms[3], &pDataChunk->pvData, &pDataChunk->cbData);
1116 AssertReturn(cbData == pDataChunk->cbData, VERR_INVALID_PARAMETER);
1117
1118 /** @todo Implement checksum handling. */
1119 }
1120 }
1121 }
1122 else
1123 rc = VERR_INVALID_PARAMETER;
1124
1125 LogFlowFuncLeaveRC(rc);
1126 return rc;
1127}
1128
1129/**
1130 * Gets an URI error from HGCM service parameters.
1131 *
1132 * @returns VBox status code.
1133 * @param cParms Number of HGCM parameters supplied in \a paParms.
1134 * @param paParms Array of HGCM parameters.
1135 * @param pRc Where to store the received error code.
1136 */
1137static int sharedClipboardSvcURIGetError(uint32_t cParms, VBOXHGCMSVCPARM paParms[], int *pRc)
1138{
1139 AssertPtrReturn(paParms, VERR_INVALID_PARAMETER);
1140 AssertPtrReturn(pRc, VERR_INVALID_PARAMETER);
1141
1142 int rc;
1143
1144 if (cParms == VBOX_SHCL_CPARMS_ERROR)
1145 {
1146 rc = HGCMSvcGetU32(&paParms[1], (uint32_t *)pRc); /** @todo int vs. uint32_t !!! */
1147 }
1148 else
1149 rc = VERR_INVALID_PARAMETER;
1150
1151 LogFlowFuncLeaveRC(rc);
1152 return rc;
1153}
1154
1155/**
1156 * Handles a guest reply (VBOX_SHCL_GUEST_FN_REPLY) message.
1157 *
1158 * @returns VBox status code.
1159 * @param pClient Pointer to associated client.
1160 * @param pTransfer Pointer to transfer to handle guest reply for.
1161 * @param cParms Number of function parameters supplied.
1162 * @param paParms Array function parameters supplied.
1163 */
1164static int sharedClipboardSvcURITransferHandleReply(PSHCLCLIENT pClient, PSHCLURITRANSFER pTransfer,
1165 uint32_t cParms, VBOXHGCMSVCPARM paParms[])
1166{
1167 RT_NOREF(pClient);
1168
1169 int rc;
1170
1171 uint32_t cbReply = sizeof(SHCLREPLY);
1172 PSHCLREPLY pReply = (PSHCLREPLY)RTMemAlloc(cbReply);
1173 if (pReply)
1174 {
1175 rc = sharedClipboardSvcURIGetReply(cParms, paParms, pReply);
1176 if (RT_SUCCESS(rc))
1177 {
1178 PSHCLEVENTPAYLOAD pPayload
1179 = (PSHCLEVENTPAYLOAD)RTMemAlloc(sizeof(SHCLEVENTPAYLOAD));
1180 if (pPayload)
1181 {
1182 pPayload->pvData = pReply;
1183 pPayload->cbData = cbReply;
1184
1185 switch (pReply->uType)
1186 {
1187 case VBOX_SHCL_REPLYMSGTYPE_TRANSFER_STATUS:
1188 RT_FALL_THROUGH();
1189 case VBOX_SHCL_REPLYMSGTYPE_LIST_OPEN:
1190 RT_FALL_THROUGH();
1191 case VBOX_SHCL_REPLYMSGTYPE_LIST_CLOSE:
1192 RT_FALL_THROUGH();
1193 case VBOX_SHCL_REPLYMSGTYPE_OBJ_OPEN:
1194 RT_FALL_THROUGH();
1195 case VBOX_SHCL_REPLYMSGTYPE_OBJ_CLOSE:
1196 {
1197 uint32_t uCID;
1198 rc = HGCMSvcGetU32(&paParms[0], &uCID);
1199 if (RT_SUCCESS(rc))
1200 {
1201 const SHCLEVENTID uEvent = VBOX_SHCL_CONTEXTID_GET_EVENT(uCID);
1202
1203 LogFlowFunc(("uCID=%RU32 -> uEvent=%RU32\n", uCID, uEvent));
1204
1205 rc = SharedClipboardEventSignal(&pTransfer->Events, uEvent, pPayload);
1206 }
1207 break;
1208 }
1209
1210 default:
1211 rc = VERR_NOT_FOUND;
1212 break;
1213 }
1214
1215 if (RT_FAILURE(rc))
1216 {
1217 if (pPayload)
1218 RTMemFree(pPayload);
1219 }
1220 }
1221 else
1222 rc = VERR_NO_MEMORY;
1223 }
1224 }
1225 else
1226 rc = VERR_NO_MEMORY;
1227
1228 if (RT_FAILURE(rc))
1229 {
1230 if (pReply)
1231 RTMemFree(pReply);
1232 }
1233
1234 LogFlowFuncLeaveRC(rc);
1235 return rc;
1236}
1237
1238/**
1239 * URI client (guest) handler for the Shared Clipboard host service.
1240 *
1241 * @returns VBox status code.
1242 * @param pClient Pointer to associated client.
1243 * @param callHandle The client's call handle of this call.
1244 * @param u32Function Function number being called.
1245 * @param cParms Number of function parameters supplied.
1246 * @param paParms Array function parameters supplied.
1247 * @param tsArrival Timestamp of arrival.
1248 */
1249int sharedClipboardSvcURIHandler(PSHCLCLIENT pClient,
1250 VBOXHGCMCALLHANDLE callHandle,
1251 uint32_t u32Function,
1252 uint32_t cParms,
1253 VBOXHGCMSVCPARM paParms[],
1254 uint64_t tsArrival)
1255{
1256 RT_NOREF(paParms, tsArrival);
1257
1258 LogFlowFunc(("uClient=%RU32, u32Function=%RU32 (%s), cParms=%RU32, g_ExtState.pfnExtension=%p\n",
1259 pClient->State.uClientID, u32Function, VBoxShClGuestMsgToStr(u32Function), cParms, g_ExtState.pfnExtension));
1260
1261#if 0
1262 /* Check if we've the right mode set. */
1263 if (!sharedClipboardSvcURIMsgIsAllowed(sharedClipboardSvcGetMode(), u32Function))
1264 {
1265 LogFunc(("Wrong clipboard mode, denying access\n"));
1266 return VERR_ACCESS_DENIED;
1267 }
1268#endif
1269
1270 /* A (valid) service extension is needed because VBoxSVC needs to keep track of the
1271 * clipboard areas cached on the host. */
1272 if (!g_ExtState.pfnExtension)
1273 {
1274#ifdef DEBUG_andy
1275 AssertPtr(g_ExtState.pfnExtension);
1276#endif
1277 LogFunc(("Invalid / no service extension set, skipping URI handling\n"));
1278 return VERR_NOT_SUPPORTED;
1279 }
1280
1281 int rc = VERR_INVALID_PARAMETER; /* Play safe by default. */
1282
1283 /*
1284 * Pre-check: For certain messages we need to make sure that a (right) transfer is present.
1285 */
1286 uint32_t uCID = 0; /* Context ID */
1287 PSHCLURITRANSFER pTransfer = NULL;
1288
1289 switch (u32Function)
1290 {
1291 case VBOX_SHCL_GUEST_FN_STATUS:
1292 break;
1293 default:
1294 {
1295 if (!SharedClipboardURICtxGetTotalTransfers(&pClient->URI))
1296 {
1297 LogFunc(("No transfers found\n"));
1298 rc = VERR_SHCLPB_TRANSFER_ID_NOT_FOUND;
1299 break;
1300 }
1301
1302 if (cParms < 1)
1303 break;
1304
1305 rc = HGCMSvcGetU32(&paParms[0], &uCID);
1306 if (RT_FAILURE(rc))
1307 break;
1308
1309 const SHCLURITRANSFERID uTransferID = VBOX_SHCL_CONTEXTID_GET_TRANSFER(uCID);
1310
1311 pTransfer = SharedClipboardURICtxGetTransfer(&pClient->URI, uTransferID);
1312 if (!pTransfer)
1313 {
1314 LogFunc(("Transfer with ID %RU32 not found\n", uTransferID));
1315 rc = VERR_SHCLPB_TRANSFER_ID_NOT_FOUND;
1316 }
1317 break;
1318 }
1319 }
1320
1321 if (RT_FAILURE(rc))
1322 return rc;
1323
1324 rc = VERR_INVALID_PARAMETER; /* Play safe. */
1325
1326 bool fDoCallComplete = true;
1327
1328 switch (u32Function)
1329 {
1330#if 0
1331 case VBOX_SHCL_GUEST_FN_STATUS:
1332 {
1333 if (cParms != VBOX_SHCL_CPARMS_STATUS)
1334 break;
1335
1336 SHCLURITRANSFERSTATUS uStatus = SHCLURITRANSFERSTATUS_NONE;
1337 rc = HGCMSvcGetU32(&paParms[1], &uStatus);
1338 if (RT_FAILURE(rc))
1339 break;
1340
1341 LogFlowFunc(("uStatus: %RU32\n", uStatus));
1342
1343 SharedClipboardURICtxTransfersCleanup(&pClient->URI);
1344
1345 if (SharedClipboardURICtxTransfersMaximumReached(&pClient->URI))
1346 {
1347 rc = VERR_SHCLPB_MAX_TRANSFERS_REACHED;
1348 break;
1349 }
1350
1351 if (uStatus == SHCLURITRANSFERSTATUS_RUNNING)
1352 {
1353 const SHCLURITRANSFERDIR enmDir = SHCLURITRANSFERDIR_READ;
1354
1355 PSHCLURITRANSFER pTransfer;
1356 rc = SharedClipboardURITransferCreate(enmDir,
1357 SHCLSOURCE_REMOTE, &pTransfer);
1358 if (RT_SUCCESS(rc))
1359 {
1360 rc = sharedClipboardSvcURIAreaRegister(&pClient->State, pTransfer);
1361 if (RT_SUCCESS(rc))
1362 {
1363 SHCLPROVIDERCREATIONCTX creationCtx;
1364 RT_ZERO(creationCtx);
1365
1366 creationCtx.enmSource = pClient->State.enmSource;
1367
1368 creationCtx.Interface.pfnTransferOpen = sharedClipboardSvcURITransferOpen;
1369 creationCtx.Interface.pfnTransferClose = sharedClipboardSvcURITransferClose;
1370 creationCtx.Interface.pfnListOpen = sharedClipboardSvcURIListOpen;
1371 creationCtx.Interface.pfnListClose = sharedClipboardSvcURIListClose;
1372 creationCtx.Interface.pfnObjOpen = sharedClipboardSvcURIObjOpen;
1373 creationCtx.Interface.pfnObjClose = sharedClipboardSvcURIObjClose;
1374
1375 if (enmDir == SHCLURITRANSFERDIR_READ)
1376 {
1377 creationCtx.Interface.pfnGetRoots = sharedClipboardSvcURIGetRoots;
1378 creationCtx.Interface.pfnListHdrRead = sharedClipboardSvcURIListHdrRead;
1379 creationCtx.Interface.pfnListEntryRead = sharedClipboardSvcURIListEntryRead;
1380 creationCtx.Interface.pfnObjRead = sharedClipboardSvcURIObjRead;
1381 }
1382 else
1383 {
1384 AssertFailed();
1385 }
1386
1387 creationCtx.pvUser = pClient;
1388
1389 /* Register needed callbacks so that we can wait for the meta data to arrive here. */
1390 SHCLURITRANSFERCALLBACKS Callbacks;
1391 RT_ZERO(Callbacks);
1392
1393 Callbacks.pvUser = pClient;
1394
1395 Callbacks.pfnTransferPrepare = VBoxSvcClipboardURITransferPrepareCallback;
1396 Callbacks.pfnTransferComplete = VBoxSvcClipboardURITransferCompleteCallback;
1397 Callbacks.pfnTransferCanceled = VBoxSvcClipboardURITransferCanceledCallback;
1398 Callbacks.pfnTransferError = VBoxSvcClipboardURITransferErrorCallback;
1399
1400 SharedClipboardURITransferSetCallbacks(pTransfer, &Callbacks);
1401
1402 rc = SharedClipboardURITransferSetInterface(pTransfer, &creationCtx);
1403 if (RT_SUCCESS(rc))
1404 rc = SharedClipboardURICtxTransferAdd(&pClient->URI, pTransfer);
1405 }
1406
1407 if (RT_SUCCESS(rc))
1408 {
1409 rc = SharedClipboardSvcImplURITransferCreate(pClient, pTransfer);
1410 if (RT_SUCCESS(rc))
1411 rc = SharedClipboardSvcImplFormatAnnounce(pClient, VBOX_SHCL_FMT_URI_LIST);
1412 }
1413
1414 if (RT_FAILURE(rc))
1415 {
1416 SharedClipboardSvcImplURITransferDestroy(pClient, pTransfer);
1417 SharedClipboardURITransferDestroy(pTransfer);
1418 }
1419 }
1420 }
1421
1422 LogFlowFunc(("[Client %RU32] VBOX_SHCL_GUEST_FN_STATUS: %Rrc\n", pClient->uClientID, rc));
1423
1424 if (RT_FAILURE(rc))
1425 LogRel(("Shared Clipboard: Initializing transfer failed with %Rrc\n", rc));
1426
1427 break;
1428 }
1429#endif
1430
1431 case VBOX_SHCL_GUEST_FN_REPLY:
1432 {
1433 rc = sharedClipboardSvcURITransferHandleReply(pClient, pTransfer, cParms, paParms);
1434
1435 /* This message does not need any completion, as it can happen at any time from the guest side. */
1436 fDoCallComplete = false;
1437 break;
1438 }
1439
1440 case VBOX_SHCL_GUEST_FN_ROOT_LIST_HDR_READ:
1441 {
1442 break;
1443 }
1444
1445 case VBOX_SHCL_GUEST_FN_ROOT_LIST_HDR_WRITE:
1446 {
1447 SHCLROOTLISTHDR lstHdr;
1448 rc = sharedClipboardSvcURIGetRootListHdr(cParms, paParms, &lstHdr);
1449 if (RT_SUCCESS(rc))
1450 {
1451 void *pvData = SharedClipboardURIRootListHdrDup(&lstHdr);
1452 uint32_t cbData = sizeof(SHCLROOTLISTHDR);
1453
1454 const SHCLEVENTID uEvent = VBOX_SHCL_CONTEXTID_GET_EVENT(uCID);
1455
1456 PSHCLEVENTPAYLOAD pPayload;
1457 rc = SharedClipboardPayloadAlloc(uEvent, pvData, cbData, &pPayload);
1458 if (RT_SUCCESS(rc))
1459 {
1460 rc = SharedClipboardEventSignal(&pTransfer->Events, uEvent, pPayload);
1461 if (RT_FAILURE(rc))
1462 SharedClipboardPayloadFree(pPayload);
1463 }
1464 }
1465 break;
1466 }
1467
1468 case VBOX_SHCL_GUEST_FN_ROOT_LIST_ENTRY_READ:
1469 {
1470 #if 0
1471 SHCLROOTLISTENTRY lstEntry;
1472 rc = VBoxSvcClipboardURIGetRootListEntry(cParms, paParms, &lstEntry);
1473 if (RT_SUCCESS(rc))
1474 {
1475 void *pvData = SharedClipboardURIRootListEntryDup(&lstEntry);
1476 uint32_t cbData = sizeof(SHCLROOTLISTENTRY);
1477
1478 PSHCLURITRANSFERPAYLOAD pPayload;
1479 rc = SharedClipboardURITransferPayloadAlloc(SHCLURITRANSFEREVENTTYPE_ROOT_LIST_HDR_READ,
1480 pvData, cbData, &pPayload);
1481 if (RT_SUCCESS(rc))
1482 rc = SharedClipboardURITransferEventSignal(pTransfer, SHCLURITRANSFEREVENTTYPE_ROOT_LIST_HDR_READ,
1483 pPayload);
1484 }
1485 break;
1486 #endif
1487 }
1488
1489 case VBOX_SHCL_GUEST_FN_ROOT_LIST_ENTRY_WRITE:
1490 {
1491 SHCLROOTLISTENTRY lstEntry;
1492 rc = sharedClipboardSvcURIGetRootListEntry(cParms, paParms, &lstEntry);
1493 if (RT_SUCCESS(rc))
1494 {
1495 void *pvData = SharedClipboardURIRootListEntryDup(&lstEntry);
1496 uint32_t cbData = sizeof(SHCLROOTLISTENTRY);
1497
1498 const SHCLEVENTID uEvent = VBOX_SHCL_CONTEXTID_GET_EVENT(uCID);
1499
1500 PSHCLEVENTPAYLOAD pPayload;
1501 rc = SharedClipboardPayloadAlloc(uEvent, pvData, cbData, &pPayload);
1502 if (RT_SUCCESS(rc))
1503 {
1504 rc = SharedClipboardEventSignal(&pTransfer->Events, uEvent, pPayload);
1505 if (RT_FAILURE(rc))
1506 SharedClipboardPayloadFree(pPayload);
1507 }
1508 }
1509 break;
1510 }
1511
1512 case VBOX_SHCL_GUEST_FN_LIST_OPEN:
1513 {
1514 SHCLLISTOPENPARMS listOpenParms;
1515 rc = sharedClipboardSvcURIGetListOpen(cParms, paParms, &listOpenParms);
1516 if (RT_SUCCESS(rc))
1517 {
1518 SHCLLISTHANDLE hList;
1519 rc = SharedClipboardURITransferListOpen(pTransfer, &listOpenParms, &hList);
1520 if (RT_SUCCESS(rc))
1521 {
1522 /* Return list handle. */
1523 HGCMSvcSetU32(&paParms[1], hList);
1524 }
1525 }
1526 break;
1527 }
1528
1529 case VBOX_SHCL_GUEST_FN_LIST_CLOSE:
1530 {
1531 if (cParms != VBOX_SHCL_CPARMS_LIST_CLOSE)
1532 break;
1533
1534 SHCLLISTHANDLE hList;
1535 rc = HGCMSvcGetU64(&paParms[1], &hList);
1536 if (RT_SUCCESS(rc))
1537 {
1538 rc = SharedClipboardURITransferListClose(pTransfer, hList);
1539 }
1540 break;
1541 }
1542
1543 case VBOX_SHCL_GUEST_FN_LIST_HDR_READ:
1544 {
1545 if (cParms != VBOX_SHCL_CPARMS_LIST_HDR)
1546 break;
1547
1548 SHCLLISTHANDLE hList;
1549 rc = HGCMSvcGetU64(&paParms[1], &hList); /* Get list handle. */
1550 if (RT_SUCCESS(rc))
1551 {
1552 SHCLLISTHDR hdrList;
1553 rc = SharedClipboardURITransferListGetHeader(pTransfer, hList, &hdrList);
1554 /*if (RT_SUCCESS(rc))
1555 rc = sharedClipboardSvcURISetListHdr(cParms, paParms, &hdrList);*/
1556 }
1557 break;
1558 }
1559
1560 case VBOX_SHCL_GUEST_FN_LIST_HDR_WRITE:
1561 {
1562 SHCLLISTHDR hdrList;
1563 rc = SharedClipboardURIListHdrInit(&hdrList);
1564 if (RT_SUCCESS(rc))
1565 {
1566 SHCLLISTHANDLE hList;
1567 rc = sharedClipboardSvcURIGetListHdr(cParms, paParms, &hList, &hdrList);
1568 if (RT_SUCCESS(rc))
1569 {
1570 void *pvData = SharedClipboardURIListHdrDup(&hdrList);
1571 uint32_t cbData = sizeof(SHCLLISTHDR);
1572
1573 const SHCLEVENTID uEvent = VBOX_SHCL_CONTEXTID_GET_EVENT(uCID);
1574
1575 PSHCLEVENTPAYLOAD pPayload;
1576 rc = SharedClipboardPayloadAlloc(uEvent, pvData, cbData, &pPayload);
1577 if (RT_SUCCESS(rc))
1578 {
1579 rc = SharedClipboardEventSignal(&pTransfer->Events, uEvent, pPayload);
1580 if (RT_FAILURE(rc))
1581 SharedClipboardPayloadFree(pPayload);
1582 }
1583 }
1584 }
1585 break;
1586 }
1587
1588 case VBOX_SHCL_GUEST_FN_LIST_ENTRY_READ:
1589 {
1590 if (cParms != VBOX_SHCL_CPARMS_LIST_ENTRY)
1591 break;
1592
1593 SHCLLISTHANDLE hList;
1594 rc = HGCMSvcGetU64(&paParms[1], &hList); /* Get list handle. */
1595 if (RT_SUCCESS(rc))
1596 {
1597 SHCLLISTENTRY entryList;
1598 rc = SharedClipboardURITransferListRead(pTransfer, hList, &entryList);
1599 }
1600 break;
1601 }
1602
1603 case VBOX_SHCL_GUEST_FN_LIST_ENTRY_WRITE:
1604 {
1605 SHCLLISTENTRY entryList;
1606 rc = SharedClipboardURIListEntryInit(&entryList);
1607 if (RT_SUCCESS(rc))
1608 {
1609 SHCLLISTHANDLE hList;
1610 rc = sharedClipboardSvcURIGetListEntry(cParms, paParms, &hList, &entryList);
1611 if (RT_SUCCESS(rc))
1612 {
1613 void *pvData = SharedClipboardURIListEntryDup(&entryList);
1614 uint32_t cbData = sizeof(SHCLLISTENTRY);
1615
1616 const SHCLEVENTID uEvent = VBOX_SHCL_CONTEXTID_GET_EVENT(uCID);
1617
1618 PSHCLEVENTPAYLOAD pPayload;
1619 rc = SharedClipboardPayloadAlloc(uEvent, pvData, cbData, &pPayload);
1620 if (RT_SUCCESS(rc))
1621 {
1622 rc = SharedClipboardEventSignal(&pTransfer->Events, uEvent, pPayload);
1623 if (RT_FAILURE(rc))
1624 SharedClipboardPayloadFree(pPayload);
1625 }
1626 }
1627 }
1628 break;
1629 }
1630
1631 #if 0
1632 case VBOX_SHCL_GUEST_FN_OBJ_OPEN:
1633 {
1634 break;
1635 }
1636
1637 case VBOX_SHCL_GUEST_FN_OBJ_CLOSE:
1638 {
1639 break;
1640 }
1641
1642 case VBOX_SHCL_GUEST_FN_OBJ_READ:
1643 {
1644 break;
1645 }
1646 #endif
1647
1648 case VBOX_SHCL_GUEST_FN_OBJ_WRITE:
1649 {
1650 SHCLOBJDATACHUNK dataChunk;
1651 rc = sharedClipboardSvcURIGetObjDataChunk(cParms, paParms, &dataChunk);
1652 if (RT_SUCCESS(rc))
1653 {
1654 void *pvData = SharedClipboardURIObjectDataChunkDup(&dataChunk);
1655 uint32_t cbData = sizeof(SHCLOBJDATACHUNK);
1656
1657 const SHCLEVENTID uEvent = VBOX_SHCL_CONTEXTID_GET_EVENT(uCID);
1658
1659 PSHCLEVENTPAYLOAD pPayload;
1660 rc = SharedClipboardPayloadAlloc(uEvent, pvData, cbData, &pPayload);
1661 if (RT_SUCCESS(rc))
1662 {
1663 rc = SharedClipboardEventSignal(&pTransfer->Events, uEvent, pPayload);
1664 if (RT_FAILURE(rc))
1665 SharedClipboardPayloadFree(pPayload);
1666 }
1667 }
1668
1669 break;
1670 }
1671
1672 #if 0
1673 case VBOX_SHCL_GUEST_FN_WRITE_DIR:
1674 {
1675 LogFlowFunc(("VBOX_SHCL_GUEST_FN_WRITE_DIR\n"));
1676
1677 SHCLDIRDATA dirData;
1678 rc = VBoxSvcClipboardURIGetDir(cParms, paParms, &dirData);
1679 if (RT_SUCCESS(rc))
1680 {
1681 SharedClipboardArea *pArea = SharedClipboardURITransferGetArea(pTransfer);
1682 AssertPtrBreakStmt(pArea, rc = VERR_INVALID_POINTER);
1683
1684 const char *pszCacheDir = pArea->GetDirAbs();
1685 char *pszDir = RTPathJoinA(pszCacheDir, dirData.pszPath);
1686 if (pszDir)
1687 {
1688 LogFlowFunc(("pszDir=%s\n", pszDir));
1689
1690 rc = RTDirCreateFullPath(pszDir, dirData.fMode);
1691 if (RT_SUCCESS(rc))
1692 {
1693 SHCLAREAOBJ Obj = { SHCLAREAOBJTYPE_DIR, SHCLAREAOBJSTATE_COMPLETE };
1694 int rc2 = pArea->AddObject(pszDir, Obj);
1695 AssertRC(rc2);
1696 }
1697
1698 RTStrFree(pszDir);
1699 }
1700 else
1701 rc = VERR_NO_MEMORY;
1702 }
1703 break;
1704 }
1705
1706 case VBOX_SHCL_GUEST_FN_READ_FILE_HDR:
1707 {
1708 LogFlowFunc(("VBOX_SHCL_GUEST_FN_READ_FILE_HDR\n"));
1709
1710 SHCLFILEHDR fileHdr;
1711 rc = VBoxSvcClipboardURISetFileHdr(cParms, paParms, &fileHdr);
1712 break;
1713 }
1714
1715 case VBOX_SHCL_GUEST_FN_WRITE_FILE_HDR:
1716 {
1717 LogFlowFunc(("VBOX_SHCL_GUEST_FN_WRITE_FILE_HDR\n"));
1718
1719 if (!SharedClipboardURIObjCtxIsValid(SharedClipboardURITransferGetCurrentObjCtx(pTransfer)))
1720 {
1721 pTransfer->State.ObjCtx.pObj = new SharedClipboardURIObject(SharedClipboardURIObject::Type_File);
1722 if (pTransfer->State.ObjCtx.pObj) /** @todo Can this throw? */
1723 {
1724 rc = VINF_SUCCESS;
1725 }
1726 else
1727 rc = VERR_NO_MEMORY;
1728 }
1729 else /* There still is another object being processed? */
1730 rc = VERR_WRONG_ORDER;
1731
1732 if (RT_FAILURE(rc))
1733 break;
1734
1735 SHCLFILEHDR fileHdr;
1736 rc = VBoxSvcClipboardURIGetFileHdr(cParms, paParms, &fileHdr);
1737 if (RT_SUCCESS(rc))
1738 {
1739 SharedClipboardArea *pArea = SharedClipboardURITransferGetArea(pTransfer);
1740 AssertPtrBreakStmt(pArea, rc = VERR_WRONG_ORDER);
1741
1742 const char *pszCacheDir = pArea->GetDirAbs();
1743
1744 char pszPathAbs[RTPATH_MAX];
1745 rc = RTPathJoin(pszPathAbs, sizeof(pszPathAbs), pszCacheDir, fileHdr.pszFilePath);
1746 if (RT_SUCCESS(rc))
1747 {
1748 rc = SharedClipboardPathSanitize(pszPathAbs, sizeof(pszPathAbs));
1749 if (RT_SUCCESS(rc))
1750 {
1751 PSHCLCLIENTURIOBJCTX pObjCtx = SharedClipboardURITransferGetCurrentObjCtx(pTransfer);
1752 AssertPtrBreakStmt(pObjCtx, VERR_INVALID_POINTER);
1753
1754 SharedClipboardURIObject *pObj = pObjCtx->pObj;
1755 AssertPtrBreakStmt(pObj, VERR_INVALID_POINTER);
1756
1757 LogFlowFunc(("pszFile=%s\n", pszPathAbs));
1758
1759 /** @todo Add sparse file support based on fFlags? (Use Open(..., fFlags | SPARSE). */
1760 rc = pObj->OpenFileEx(pszPathAbs, SharedClipboardURIObject::View_Target,
1761 RTFILE_O_CREATE_REPLACE | RTFILE_O_WRITE | RTFILE_O_DENY_WRITE,
1762 (fileHdr.fMode & RTFS_UNIX_MASK) | RTFS_UNIX_IRUSR | RTFS_UNIX_IWUSR);
1763 if (RT_SUCCESS(rc))
1764 {
1765 rc = pObj->SetSize(fileHdr.cbSize);
1766
1767 /** @todo Unescape path before printing. */
1768 LogRel2(("Clipboard: Transferring guest file '%s' to host (%RU64 bytes, mode 0x%x)\n",
1769 pObj->GetDestPathAbs().c_str(), pObj->GetSize(), pObj->GetMode()));
1770
1771 if (pObj->IsComplete()) /* 0-byte file? We're done already. */
1772 {
1773 /** @todo Sanitize path. */
1774 LogRel2(("Clipboard: Transferring guest file '%s' (0 bytes) to host complete\n",
1775 pObj->GetDestPathAbs().c_str()));
1776
1777 SharedClipboardURIObjCtxDestroy(&pTransfer->State.ObjCtx);
1778 }
1779
1780 SHCLAREAOBJ Obj = { SHCLAREAOBJTYPE_FILE, SHCLAREAOBJSTATE_NONE };
1781 int rc2 = pArea->AddObject(pszPathAbs, Obj);
1782 AssertRC(rc2);
1783 }
1784 else
1785 LogRel(("Clipboard: Error opening/creating guest file '%s' on host, rc=%Rrc\n", pszPathAbs, rc));
1786 }
1787 }
1788 }
1789 break;
1790 }
1791
1792 case VBOX_SHCL_GUEST_FN_READ_FILE_DATA:
1793 {
1794 LogFlowFunc(("VBOX_SHCL_FN_READ_FILE_DATA\n"));
1795
1796 SHCLFILEDATA fileData;
1797 rc = VBoxSvcClipboardURISetFileData(cParms, paParms, &fileData);
1798 break;
1799 }
1800
1801 case VBOX_SHCL_GUEST_FN_WRITE_FILE_DATA:
1802 {
1803 LogFlowFunc(("VBOX_SHCL_FN_WRITE_FILE_DATA\n"));
1804
1805 if (!SharedClipboardURIObjCtxIsValid(&pTransfer->State.ObjCtx))
1806 {
1807 rc = VERR_WRONG_ORDER;
1808 break;
1809 }
1810
1811 SHCLFILEDATA fileData;
1812 rc = VBoxSvcClipboardURIGetFileData(cParms, paParms, &fileData);
1813 if (RT_SUCCESS(rc))
1814 {
1815 PSHCLCLIENTURIOBJCTX pObjCtx = SharedClipboardURITransferGetCurrentObjCtx(pTransfer);
1816 AssertPtrBreakStmt(pObjCtx, VERR_INVALID_POINTER);
1817
1818 SharedClipboardURIObject *pObj = pObjCtx->pObj;
1819 AssertPtrBreakStmt(pObj, VERR_INVALID_POINTER);
1820
1821 uint32_t cbWritten;
1822 rc = pObj->Write(fileData.pvData, fileData.cbData, &cbWritten);
1823 if (RT_SUCCESS(rc))
1824 {
1825 Assert(cbWritten <= fileData.cbData);
1826 if (cbWritten < fileData.cbData)
1827 {
1828 /** @todo What to do when the host's disk is full? */
1829 rc = VERR_DISK_FULL;
1830 }
1831
1832 if ( pObj->IsComplete()
1833 || RT_FAILURE(rc))
1834 SharedClipboardURIObjCtxDestroy(&pTransfer->State.ObjCtx);
1835 }
1836 else
1837 LogRel(("Clipboard: Error writing guest file data for '%s', rc=%Rrc\n", pObj->GetDestPathAbs().c_str(), rc));
1838 }
1839 break;
1840 }
1841#endif
1842 case VBOX_SHCL_GUEST_FN_CANCEL:
1843 {
1844 LogRel2(("Shared Clipboard: Transfer canceled\n"));
1845 break;
1846 }
1847
1848 case VBOX_SHCL_GUEST_FN_ERROR:
1849 {
1850 int rcGuest;
1851 rc = sharedClipboardSvcURIGetError(cParms,paParms, &rcGuest);
1852 if (RT_SUCCESS(rc))
1853 LogRel(("Shared Clipboard: Transfer error: %Rrc\n", rcGuest));
1854 break;
1855 }
1856
1857 default:
1858 LogFunc(("Not implemented\n"));
1859 break;
1860 }
1861
1862 if (fDoCallComplete)
1863 {
1864 /* Tell the client that the call is complete (unblocks waiting). */
1865 LogFlowFunc(("[Client %RU32] Calling pfnCallComplete w/ rc=%Rrc\n", pClient->State.uClientID, rc));
1866 AssertPtr(g_pHelpers);
1867 g_pHelpers->pfnCallComplete(callHandle, rc);
1868 }
1869
1870 LogFlowFunc(("[Client %RU32] Returning rc=%Rrc\n", pClient->State.uClientID, rc));
1871 return rc;
1872}
1873
1874/**
1875 * URI host handler for the Shared Clipboard host service.
1876 *
1877 * @returns VBox status code.
1878 * @param u32Function Function number being called.
1879 * @param cParms Number of function parameters supplied.
1880 * @param paParms Array function parameters supplied.
1881 */
1882int sharedClipboardSvcURIHostHandler(uint32_t u32Function,
1883 uint32_t cParms,
1884 VBOXHGCMSVCPARM paParms[])
1885{
1886 RT_NOREF(cParms, paParms);
1887
1888 int rc = VERR_NOT_IMPLEMENTED; /* Play safe. */
1889
1890 switch (u32Function)
1891 {
1892 case VBOX_SHCL_HOST_FN_CANCEL: /** @todo Implement this. */
1893 break;
1894
1895 case VBOX_SHCL_HOST_FN_ERROR: /** @todo Implement this. */
1896 break;
1897
1898 default:
1899 break;
1900
1901 }
1902
1903 LogFlowFuncLeaveRC(rc);
1904 return rc;
1905}
1906
1907/**
1908 * Registers an URI clipboard area.
1909 *
1910 * @returns VBox status code.
1911 * @param pClientState Client state to use.
1912 * @param pTransfer URI transfer to register a clipboard area for.
1913 */
1914int sharedClipboardSvcURIAreaRegister(PSHCLCLIENTSTATE pClientState, PSHCLURITRANSFER pTransfer)
1915{
1916 RT_NOREF(pClientState);
1917
1918 LogFlowFuncEnter();
1919
1920 AssertMsgReturn(pTransfer->pArea == NULL, ("An area already is registered for this transfer\n"),
1921 VERR_WRONG_ORDER);
1922
1923 pTransfer->pArea = new SharedClipboardArea();
1924 if (!pTransfer->pArea)
1925 return VERR_NO_MEMORY;
1926
1927 int rc;
1928
1929 if (g_ExtState.pfnExtension)
1930 {
1931 SHCLEXTAREAPARMS parms;
1932 RT_ZERO(parms);
1933
1934 parms.uID = NIL_SHCLAREAID;
1935
1936 /* As the meta data is now complete, register a new clipboard on the host side. */
1937 rc = g_ExtState.pfnExtension(g_ExtState.pvExtension, VBOX_CLIPBOARD_EXT_FN_AREA_REGISTER, &parms, sizeof(parms));
1938 if (RT_SUCCESS(rc))
1939 {
1940 /* Note: Do *not* specify SHCLAREA_OPEN_FLAGS_MUST_NOT_EXIST as flags here, as VBoxSVC took care of the
1941 * clipboard area creation already. */
1942 rc = pTransfer->pArea->OpenTemp(parms.uID /* Area ID */,
1943 SHCLAREA_OPEN_FLAGS_NONE);
1944 }
1945
1946 LogFlowFunc(("Registered new clipboard area (%RU32) by client %RU32 with rc=%Rrc\n",
1947 parms.uID, pClientState->uClientID, rc));
1948 }
1949 else
1950 rc = VERR_NOT_SUPPORTED;
1951
1952 LogFlowFuncLeaveRC(rc);
1953 return rc;
1954}
1955
1956/**
1957 * Unregisters an URI clipboard area.
1958 *
1959 * @returns VBox status code.
1960 * @param pClientState Client state to use.
1961 * @param pTransfer URI transfer to unregister a clipboard area from.
1962 */
1963int sharedClipboardSvcURIAreaUnregister(PSHCLCLIENTSTATE pClientState, PSHCLURITRANSFER pTransfer)
1964{
1965 RT_NOREF(pClientState);
1966
1967 LogFlowFuncEnter();
1968
1969 if (!pTransfer->pArea)
1970 return VINF_SUCCESS;
1971
1972 int rc = VINF_SUCCESS;
1973
1974 if (g_ExtState.pfnExtension)
1975 {
1976 SHCLEXTAREAPARMS parms;
1977 RT_ZERO(parms);
1978
1979 parms.uID = pTransfer->pArea->GetID();
1980
1981 rc = g_ExtState.pfnExtension(g_ExtState.pvExtension, VBOX_CLIPBOARD_EXT_FN_AREA_UNREGISTER, &parms, sizeof(parms));
1982 if (RT_SUCCESS(rc))
1983 {
1984 rc = pTransfer->pArea->Close();
1985 if (RT_SUCCESS(rc))
1986 {
1987 delete pTransfer->pArea;
1988 pTransfer->pArea = NULL;
1989 }
1990 }
1991
1992 LogFlowFunc(("Unregistered clipboard area (%RU32) by client %RU32 with rc=%Rrc\n",
1993 parms.uID, pClientState->uClientID, rc));
1994 }
1995
1996 delete pTransfer->pArea;
1997 pTransfer->pArea = NULL;
1998
1999 LogFlowFuncLeaveRC(rc);
2000 return rc;
2001}
2002
2003/**
2004 * Attaches to an existing (registered) URI clipboard area.
2005 *
2006 * @returns VBox status code.
2007 * @param pClientState Client state to use.
2008 * @param pTransfer URI transfer to attach a clipboard area to.
2009 * @param uID ID of clipboard area to to attach to. Specify 0 to attach to the most recent one.
2010 */
2011int sharedClipboardSvcURIAreaAttach(PSHCLCLIENTSTATE pClientState, PSHCLURITRANSFER pTransfer,
2012 SHCLAREAID uID)
2013{
2014 RT_NOREF(pClientState);
2015
2016 LogFlowFuncEnter();
2017
2018 AssertMsgReturn(pTransfer->pArea == NULL, ("An area already is attached to this transfer\n"),
2019 VERR_WRONG_ORDER);
2020
2021 pTransfer->pArea = new SharedClipboardArea();
2022 if (!pTransfer->pArea)
2023 return VERR_NO_MEMORY;
2024
2025 int rc = VINF_SUCCESS;
2026
2027 if (g_ExtState.pfnExtension)
2028 {
2029 SHCLEXTAREAPARMS parms;
2030 RT_ZERO(parms);
2031
2032 parms.uID = uID; /* 0 means most recent clipboard area. */
2033
2034 /* The client now needs to attach to the most recent clipboard area
2035 * to keep a reference to it. The host does the actual book keeping / cleanup then.
2036 *
2037 * This might fail if the host does not have a most recent clipboard area (yet). */
2038 rc = g_ExtState.pfnExtension(g_ExtState.pvExtension, VBOX_CLIPBOARD_EXT_FN_AREA_ATTACH, &parms, sizeof(parms));
2039 if (RT_SUCCESS(rc))
2040 rc = pTransfer->pArea->OpenTemp(parms.uID /* Area ID */);
2041
2042 LogFlowFunc(("Attached client %RU32 to clipboard area %RU32 with rc=%Rrc\n",
2043 pClientState->uClientID, parms.uID, rc));
2044 }
2045 else
2046 rc = VERR_NOT_SUPPORTED;
2047
2048 LogFlowFuncLeaveRC(rc);
2049 return rc;
2050}
2051
2052/**
2053 * Detaches from an URI clipboard area.
2054 *
2055 * @returns VBox status code.
2056 * @param pClientState Client state to use.
2057 * @param pTransfer URI transfer to detach a clipboard area from.
2058 */
2059int sharedClipboardSvcURIAreaDetach(PSHCLCLIENTSTATE pClientState, PSHCLURITRANSFER pTransfer)
2060{
2061 RT_NOREF(pClientState);
2062
2063 LogFlowFuncEnter();
2064
2065 if (!pTransfer->pArea)
2066 return VINF_SUCCESS;
2067
2068 const uint32_t uAreaID = pTransfer->pArea->GetID();
2069
2070 int rc = VINF_SUCCESS;
2071
2072 if (g_ExtState.pfnExtension)
2073 {
2074 SHCLEXTAREAPARMS parms;
2075 RT_ZERO(parms);
2076 parms.uID = uAreaID;
2077
2078 rc = g_ExtState.pfnExtension(g_ExtState.pvExtension, VBOX_CLIPBOARD_EXT_FN_AREA_DETACH, &parms, sizeof(parms));
2079
2080 LogFlowFunc(("Detached client %RU32 from clipboard area %RU32 with rc=%Rrc\n",
2081 pClientState->uClientID, uAreaID, rc));
2082 }
2083
2084 delete pTransfer->pArea;
2085 pTransfer->pArea = NULL;
2086
2087 LogFlowFuncLeaveRC(rc);
2088 return rc;
2089}
2090
2091/**
2092 * Reports a transfer status to the guest.
2093 *
2094 * @returns VBox status code.
2095 * @param pClient Client that owns the transfer.
2096 * @param pTransfer Transfer to report status for.
2097 * @param uStatus Status to report.
2098 * @param rcTransfer Result code to report. Optional and depending on status.
2099 * @param puEvent Where to store the created wait event. Optional.
2100 */
2101int sharedClipboardSvcURITransferSendStatus(PSHCLCLIENT pClient, PSHCLURITRANSFER pTransfer, SHCLURITRANSFERSTATUS uStatus,
2102 int rcTransfer, PSHCLEVENTID puEvent)
2103{
2104 AssertPtrReturn(pClient, VERR_INVALID_POINTER);
2105 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
2106 /* puEvent is optional. */
2107
2108 PSHCLCLIENTMSG pMsgReadData = sharedClipboardSvcMsgAlloc(VBOX_SHCL_HOST_MSG_URI_TRANSFER_STATUS,
2109 VBOX_SHCL_CPARMS_TRANSFER_STATUS);
2110 if (!pMsgReadData)
2111 return VERR_NO_MEMORY;
2112
2113 const SHCLEVENTID uEvent = SharedClipboardEventIDGenerate(&pTransfer->Events);
2114
2115 HGCMSvcSetU32(&pMsgReadData->paParms[0], VBOX_SHCL_CONTEXTID_MAKE(pClient->State.uSessionID,
2116 pTransfer->State.uID, uEvent));
2117 HGCMSvcSetU32(&pMsgReadData->paParms[1], pTransfer->State.enmDir);
2118 HGCMSvcSetU32(&pMsgReadData->paParms[2], uStatus);
2119 HGCMSvcSetU32(&pMsgReadData->paParms[3], (uint32_t)rcTransfer); /** @todo uint32_t vs. int. */
2120 HGCMSvcSetU32(&pMsgReadData->paParms[4], 0 /* fFlags, unused */);
2121
2122 int rc = sharedClipboardSvcMsgAdd(pClient, pMsgReadData, true /* fAppend */);
2123 if (RT_SUCCESS(rc))
2124 {
2125 rc = SharedClipboardEventRegister(&pTransfer->Events, uEvent);
2126 if (RT_SUCCESS(rc))
2127 {
2128 rc = sharedClipboardSvcClientWakeup(pClient);
2129 if (RT_SUCCESS(rc))
2130 {
2131 LogRel2(("Shared Clipboard: Reported status %s (rc=%Rrc) of transfer %RU32 to guest\n",
2132 VBoxShClTransferStatusToStr(uStatus), rcTransfer, pTransfer->State.uID));
2133
2134 if (puEvent)
2135 *puEvent = uEvent;
2136 }
2137 else
2138 SharedClipboardEventUnregister(&pTransfer->Events, uEvent);
2139 }
2140 }
2141
2142 LogFlowFuncLeaveRC(rc);
2143 return rc;
2144}
2145
2146/**
2147 * Starts a new transfer, waiting for acknowledgement by the guest side.
2148 *
2149 * @returns VBox status code.
2150 * @param pClient Client that owns the transfer.
2151 * @param enmDir Transfer direction to start.
2152 * @param enmSource Transfer source to start.
2153 * @param ppTransfer Where to return the created transfer on success. Optional.
2154 */
2155int sharedClipboardSvcURITransferStart(PSHCLCLIENT pClient,
2156 SHCLURITRANSFERDIR enmDir, SHCLSOURCE enmSource,
2157 PSHCLURITRANSFER *ppTransfer)
2158{
2159 AssertPtrReturn(pClient, VERR_INVALID_POINTER);
2160 /* ppTransfer is optional. */
2161
2162 LogFlowFuncEnter();
2163
2164 SharedClipboardURICtxTransfersCleanup(&pClient->URI);
2165
2166 int rc;
2167
2168 if (!SharedClipboardURICtxTransfersMaximumReached(&pClient->URI))
2169 {
2170 LogRel2(("Shared Clipboard: Starting %s transfer ...\n", enmDir == SHCLURITRANSFERDIR_READ ? "read" : "write"));
2171
2172 PSHCLURITRANSFER pTransfer;
2173 rc = SharedClipboardURITransferCreate(&pTransfer);
2174 if (RT_SUCCESS(rc))
2175 {
2176 SHCLPROVIDERCREATIONCTX creationCtx;
2177 RT_ZERO(creationCtx);
2178
2179 if (enmDir == SHCLURITRANSFERDIR_READ)
2180 {
2181 rc = sharedClipboardSvcURIAreaRegister(&pClient->State, pTransfer);
2182 if (RT_SUCCESS(rc))
2183 {
2184 creationCtx.Interface.pfnTransferOpen = sharedClipboardSvcURITransferOpen;
2185 creationCtx.Interface.pfnTransferClose = sharedClipboardSvcURITransferClose;
2186 creationCtx.Interface.pfnListOpen = sharedClipboardSvcURIListOpen;
2187 creationCtx.Interface.pfnListClose = sharedClipboardSvcURIListClose;
2188 creationCtx.Interface.pfnObjOpen = sharedClipboardSvcURIObjOpen;
2189 creationCtx.Interface.pfnObjClose = sharedClipboardSvcURIObjClose;
2190
2191 creationCtx.Interface.pfnGetRoots = sharedClipboardSvcURIGetRoots;
2192 creationCtx.Interface.pfnListHdrRead = sharedClipboardSvcURIListHdrRead;
2193 creationCtx.Interface.pfnListEntryRead = sharedClipboardSvcURIListEntryRead;
2194 creationCtx.Interface.pfnObjRead = sharedClipboardSvcURIObjRead;
2195 }
2196 }
2197 else if (enmDir == SHCLURITRANSFERDIR_WRITE)
2198 {
2199 creationCtx.Interface.pfnListHdrWrite = sharedClipboardSvcURIListHdrWrite;
2200 creationCtx.Interface.pfnListEntryWrite = sharedClipboardSvcURIListEntryWrite;
2201 creationCtx.Interface.pfnObjWrite = sharedClipboardSvcURIObjWrite;
2202 }
2203 else
2204 AssertFailed();
2205
2206 creationCtx.enmSource = pClient->State.enmSource;
2207 creationCtx.pvUser = pClient;
2208
2209 /* Register needed callbacks so that we can wait for the meta data to arrive here. */
2210 SHCLURITRANSFERCALLBACKS Callbacks;
2211 RT_ZERO(Callbacks);
2212
2213 Callbacks.pvUser = pClient;
2214
2215 Callbacks.pfnTransferPrepare = VBoxSvcClipboardURITransferPrepareCallback;
2216 Callbacks.pfnTransferComplete = VBoxSvcClipboardURITransferCompleteCallback;
2217 Callbacks.pfnTransferCanceled = VBoxSvcClipboardURITransferCanceledCallback;
2218 Callbacks.pfnTransferError = VBoxSvcClipboardURITransferErrorCallback;
2219
2220 SharedClipboardURITransferSetCallbacks(pTransfer, &Callbacks);
2221
2222 uint32_t uTransferID = 0;
2223
2224 rc = SharedClipboardURITransferSetInterface(pTransfer, &creationCtx);
2225 if (RT_SUCCESS(rc))
2226 {
2227 rc = SharedClipboardSvcImplURITransferCreate(pClient, pTransfer);
2228 if (RT_SUCCESS(rc))
2229 {
2230 rc = SharedClipboardURICtxTransferRegister(&pClient->URI, pTransfer, &uTransferID);
2231 if (RT_SUCCESS(rc))
2232 {
2233 rc = SharedClipboardURITransferInit(pTransfer, uTransferID, enmDir, enmSource);
2234 if (RT_SUCCESS(rc))
2235 {
2236 SHCLEVENTID uEvent;
2237 rc = sharedClipboardSvcURITransferSendStatus(pClient, pTransfer,
2238 SHCLURITRANSFERSTATUS_READY, VINF_SUCCESS,
2239 &uEvent);
2240 if (RT_SUCCESS(rc))
2241 {
2242 LogRel2(("Shared Clipboard: Waiting for start of transfer %RU32 on guest ...\n",
2243 pTransfer->State.uID));
2244
2245 PSHCLEVENTPAYLOAD pPayload;
2246 rc = SharedClipboardEventWait(&pTransfer->Events, uEvent, pTransfer->uTimeoutMs, &pPayload);
2247 if (RT_SUCCESS(rc))
2248 {
2249 Assert(pPayload->cbData == sizeof(SHCLREPLY));
2250 PSHCLREPLY pReply = (PSHCLREPLY)pPayload->pvData;
2251 AssertPtr(pReply);
2252
2253 Assert(pReply->uType == VBOX_SHCL_REPLYMSGTYPE_TRANSFER_STATUS);
2254
2255 if (pReply->u.TransferStatus.uStatus)
2256 {
2257 LogRel2(("Shared Clipboard: Started transfer %RU32 on guest\n", pTransfer->State.uID));
2258 }
2259 else
2260 LogRel(("Shared Clipboard: Guest reported status %s (error %Rrc) while starting transfer %RU32\n",
2261 VBoxShClTransferStatusToStr(pReply->u.TransferStatus.uStatus),
2262 pReply->rc, pTransfer->State.uID));
2263 }
2264 else
2265 LogRel(("Shared Clipboard: Unable to start transfer %RU32 on guest, rc=%Rrc\n",
2266 pTransfer->State.uID, rc));
2267 }
2268 }
2269 }
2270 }
2271 }
2272
2273 if (RT_FAILURE(rc))
2274 {
2275 SharedClipboardURICtxTransferUnregister(&pClient->URI, uTransferID);
2276
2277 SharedClipboardURITransferDestroy(pTransfer);
2278
2279 RTMemFree(pTransfer);
2280 pTransfer = NULL;
2281 }
2282 else
2283 {
2284 if (ppTransfer)
2285 *ppTransfer = pTransfer;
2286 }
2287 }
2288
2289 if (RT_FAILURE(rc))
2290 LogRel(("Shared Clipboard: Starting transfer failed with %Rrc\n", rc));
2291 }
2292 else
2293 rc = VERR_SHCLPB_MAX_TRANSFERS_REACHED;
2294
2295 LogFlowFuncLeaveRC(rc);
2296 return rc;
2297}
2298
2299/**
2300 * Stops a transfer, communicating the status to the guest side.
2301 *
2302 * @returns VBox status code.
2303 * @param pClient Client that owns the transfer.
2304 * @param pTransfer Transfer to stop.
2305 */
2306int sharedClipboardSvcURITransferStop(PSHCLCLIENT pClient, PSHCLURITRANSFER pTransfer)
2307{
2308 int rc = SharedClipboardURITransferClose(pTransfer);
2309 if (RT_SUCCESS(rc))
2310 {
2311 SHCLEVENTID uEvent;
2312 rc = sharedClipboardSvcURITransferSendStatus(pClient, pTransfer,
2313 SHCLURITRANSFERSTATUS_STOPPED, VINF_SUCCESS,
2314 &uEvent);
2315 if (RT_SUCCESS(rc))
2316 {
2317 LogRel2(("Shared Clipboard: Waiting for stop of transfer %RU32 on guest ...\n", pTransfer->State.uID));
2318
2319 rc = SharedClipboardEventWait(&pTransfer->Events, uEvent, pTransfer->uTimeoutMs, NULL);
2320 if (RT_SUCCESS(rc))
2321 {
2322 rc = SharedClipboardURICtxTransferUnregister(&pClient->URI, SharedClipboardURITransferGetID(pTransfer));
2323
2324 LogRel2(("Shared Clipboard: Stopped transfer %RU32 on guest\n", pTransfer->State.uID));
2325 }
2326 else
2327 LogRel(("Shared Clipboard: Unable to stop transfer %RU32 on guest, rc=%Rrc\n",
2328 pTransfer->State.uID, rc));
2329 }
2330 }
2331
2332 LogFlowFuncLeaveRC(rc);
2333 return rc;
2334}
2335
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