~ubuntu-branches/ubuntu/quantal/open-vm-tools/quantal-201210021442

« back to all changes in this revision

Viewing changes to services/plugins/dndcp/copyPasteDnDWrapper.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Serge Hallyn
  • Date: 2011-03-31 14:20:05 UTC
  • mfrom: (1.4.3 upstream)
  • Revision ID: james.westby@ubuntu.com-20110331142005-3n9red91p7ogkweo
Tags: 2011.03.28-387002-0ubuntu1
* Merge latest upstream git tag.  This has the unlocked_ioctl change
  needed to fix dkms build failures (LP: #727342)
* Changes in debian/rules:
  - work around a bug in toolbox/Makefile, where install-exec-hook is
    not happening.  This needs to get fixed the right way.
  - don't install 'vmware-user' which seems to no longer exist
  - move /etc/xdg into open-vm-toolbox (which should be done using .install)
* debian/open-vm-tools.init: add 'modprobe [-r] vmblock'. (LP: #332323)
* debian/rules and debian/open-vm-toolbox.lintian-overrides:
  - Make vmware-user-suid-wrapper suid-root (LP: #332323)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*********************************************************
 
2
 * Copyright (C) 2010 VMware, Inc. All rights reserved.
 
3
 *
 
4
 * This program is free software; you can redistribute it and/or modify it
 
5
 * under the terms of the GNU Lesser General Public License as published
 
6
 * by the Free Software Foundation version 2.1 and no later version.
 
7
 *
 
8
 * This program is distributed in the hope that it will be useful, but
 
9
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 
10
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the Lesser GNU General Public
 
11
 * License for more details.
 
12
 *
 
13
 * You should have received a copy of the GNU Lesser General Public License
 
14
 * along with this program; if not, write to the Free Software Foundation, Inc.,
 
15
 * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA.
 
16
 *
 
17
 *********************************************************/
 
18
 
 
19
/**
 
20
 * @file copyPasteDnDWrapper.cpp
 
21
 *
 
22
 * This singleton class implements a wrapper around various versions of
 
23
 * copy and paste and dnd protocols, and provides some convenience functions
 
24
 * that help to make VMwareUser a bit cleaner.
 
25
 */
 
26
 
 
27
#define G_LOG_DOMAIN "dndcp"
 
28
 
 
29
#if defined(HAVE_GTKMM)
 
30
#include "copyPasteDnDX11.h"
 
31
#endif
 
32
 
 
33
#if defined(WIN32)
 
34
#include "copyPasteDnDWin32.h"
 
35
#endif
 
36
 
 
37
#if defined(__APPLE__)
 
38
#include "copyPasteDnDMac.h"
 
39
#endif
 
40
 
 
41
#include "copyPasteDnDWrapper.h"
 
42
#include "guestDnDCPMgr.hh"
 
43
 
 
44
extern "C" {
 
45
#include "vmware.h"
 
46
#include "rpcout.h"
 
47
#include "vmware/guestrpc/tclodefs.h"
 
48
#include "vmware/tools/plugin.h"
 
49
#include "vmware/tools/utils.h"
 
50
#include <string.h>
 
51
}
 
52
 
 
53
/**
 
54
 * CopyPasteDnDWrapper is a singleton, here is a pointer to its only instance.
 
55
 */
 
56
 
 
57
CopyPasteDnDWrapper *CopyPasteDnDWrapper::m_instance = NULL;
 
58
 
 
59
/**
 
60
 *
 
61
 * Get an instance of CopyPasteDnDWrapper, which is an application singleton.
 
62
 *
 
63
 * @return a pointer to the singleton CopyPasteDnDWrapper object, or NULL if
 
64
 * for some reason it could not be allocated.
 
65
 */
 
66
 
 
67
CopyPasteDnDWrapper *
 
68
CopyPasteDnDWrapper::GetInstance()
 
69
{
 
70
   if (!m_instance) {
 
71
      m_instance = new CopyPasteDnDWrapper;
 
72
   }
 
73
   ASSERT(m_instance);
 
74
   return m_instance;
 
75
}
 
76
 
 
77
 
 
78
/**
 
79
 *
 
80
 * Destroy the singleton object.
 
81
 */
 
82
 
 
83
void
 
84
CopyPasteDnDWrapper::Destroy()
 
85
{
 
86
   if (m_instance) {
 
87
      g_debug("%s: destroying self\n", __FUNCTION__);
 
88
      delete m_instance;
 
89
      m_instance = NULL;
 
90
   }
 
91
}
 
92
 
 
93
 
 
94
/**
 
95
 *
 
96
 * Constructor.
 
97
 */
 
98
 
 
99
CopyPasteDnDWrapper::CopyPasteDnDWrapper() :
 
100
   m_isCPEnabled(FALSE),
 
101
   m_isDnDEnabled(FALSE),
 
102
   m_isCPRegistered(FALSE),
 
103
   m_isDnDRegistered(FALSE),
 
104
   m_cpVersion(0),
 
105
   m_dndVersion(0),
 
106
   m_ctx(NULL),
 
107
   m_pimpl(NULL)
 
108
{
 
109
}
 
110
 
 
111
 
 
112
/**
 
113
 *
 
114
 * Call the implementation class pointer/grab initialization code. See
 
115
 * the implementation code for further details.
 
116
 */
 
117
 
 
118
void
 
119
CopyPasteDnDWrapper::PointerInit()
 
120
{
 
121
   ASSERT(m_pimpl);
 
122
 
 
123
   m_pimpl->PointerInit();
 
124
}
 
125
 
 
126
 
 
127
/**
 
128
 *
 
129
 * Initialize the wrapper by instantiating the platform specific impl
 
130
 * class. Effectively, this function is a factory that produces a
 
131
 * platform implementation of the DnD/Copy Paste UI layer.
 
132
 *
 
133
 * @param[in] ctx tools app context.
 
134
 */
 
135
 
 
136
void
 
137
CopyPasteDnDWrapper::Init(ToolsAppCtx *ctx)
 
138
{
 
139
   m_ctx = ctx;
 
140
 
 
141
   /*
 
142
    * We only support DnD/CP V3 and greater.
 
143
    */
 
144
   GuestDnDCPMgr *p = GuestDnDCPMgr::GetInstance();
 
145
   ASSERT(p);
 
146
   if (GetDnDVersion() >= 3 && GetCPVersion() >= 3 || GetCPVersion() == 1) {
 
147
      p->Init(ctx);
 
148
   }
 
149
 
 
150
   if (!m_pimpl) {
 
151
#if defined(HAVE_GTKMM)
 
152
      m_pimpl = new CopyPasteDnDX11();
 
153
#endif
 
154
#if defined(WIN32)
 
155
      m_pimpl = new CopyPasteDnDWin32();
 
156
#endif
 
157
#if defined(__APPLE__)
 
158
      m_pimpl = new CopyPasteDnDMac();
 
159
#endif
 
160
      if (m_pimpl) {
 
161
         m_pimpl->Init(ctx);
 
162
         /*
 
163
          * Tell the Guest DnD Manager what capabilities we support.
 
164
          */
 
165
         p->SetCaps(m_pimpl->GetCaps());
 
166
      }
 
167
   }
 
168
}
 
169
 
 
170
 
 
171
/**
 
172
 *
 
173
 * Destructor.
 
174
 */
 
175
 
 
176
CopyPasteDnDWrapper::~CopyPasteDnDWrapper()
 
177
{
 
178
   g_debug("%s: enter\n", __FUNCTION__);
 
179
   if (m_pimpl) {
 
180
      if (IsCPRegistered()) {
 
181
         m_pimpl->UnregisterCP();
 
182
      }
 
183
      if (IsDnDRegistered()) {
 
184
         m_pimpl->UnregisterDnD();
 
185
      }
 
186
      delete m_pimpl;
 
187
   }
 
188
   GuestDnDCPMgr::Destroy();
 
189
}
 
190
 
 
191
 
 
192
/**
 
193
 *
 
194
 * Register copy and paste capabilities with the VMX. Try newest version
 
195
 * first, then fall back to the legacy implementation.
 
196
 *
 
197
 * @return TRUE on success, FALSE on failure
 
198
 */
 
199
 
 
200
gboolean
 
201
CopyPasteDnDWrapper::RegisterCP()
 
202
{
 
203
   g_debug("%s: enter\n", __FUNCTION__);
 
204
   ASSERT(m_pimpl);
 
205
   if (IsCPEnabled()) {
 
206
      return m_pimpl->RegisterCP();
 
207
   }
 
208
   return false;
 
209
}
 
210
 
 
211
 
 
212
/**
 
213
 *
 
214
 * Register DnD capabilities with the VMX. Handled by the platform layer.
 
215
 *
 
216
 * @return TRUE on success, FALSE on failure
 
217
 */
 
218
 
 
219
gboolean
 
220
CopyPasteDnDWrapper::RegisterDnD()
 
221
{
 
222
   g_debug("%s: enter\n", __FUNCTION__);
 
223
   ASSERT(m_pimpl);
 
224
   if (IsDnDEnabled()) {
 
225
      return m_pimpl->RegisterDnD();
 
226
   }
 
227
   return false;
 
228
}
 
229
 
 
230
 
 
231
/**
 
232
 *
 
233
 * Unregister copy paste capabilities. Handled by platform layer.
 
234
 */
 
235
 
 
236
void
 
237
CopyPasteDnDWrapper::UnregisterCP()
 
238
{
 
239
   g_debug("%s: enter\n", __FUNCTION__);
 
240
   ASSERT(m_pimpl);
 
241
   return m_pimpl->UnregisterCP();
 
242
}
 
243
 
 
244
 
 
245
/**
 
246
 *
 
247
 * Unregister DnD capabilities. Handled by platform layer.
 
248
 */
 
249
 
 
250
void
 
251
CopyPasteDnDWrapper::UnregisterDnD()
 
252
{
 
253
   g_debug("%s: enter\n", __FUNCTION__);
 
254
   ASSERT(m_pimpl);
 
255
   return m_pimpl->UnregisterDnD();
 
256
}
 
257
 
 
258
 
 
259
/**
 
260
 *
 
261
 * Get the version of the copy paste protocol being wrapped.
 
262
 *
 
263
 * @return copy paste protocol version.
 
264
 */
 
265
 
 
266
int
 
267
CopyPasteDnDWrapper::GetCPVersion()
 
268
{
 
269
   g_debug("%s: enter\n", __FUNCTION__);
 
270
   if (IsCPRegistered()) {
 
271
      char *reply = NULL;
 
272
      size_t replyLen;
 
273
 
 
274
      ToolsAppCtx *ctx = GetToolsAppCtx();
 
275
      if (!RpcChannel_Send(ctx->rpc, QUERY_VMX_COPYPASTE_VERSION,
 
276
                           strlen(QUERY_VMX_COPYPASTE_VERSION), &reply, &replyLen)) {
 
277
         g_debug("%s: could not get VMX copyPaste "
 
278
               "version capability: %s\n", __FUNCTION__, reply ? reply : "NULL");
 
279
         m_cpVersion = 1;
 
280
      } else {
 
281
         m_cpVersion = atoi(reply);
 
282
      }
 
283
      free(reply);
 
284
   }
 
285
   g_debug("%s: got version %d\n", __FUNCTION__, m_cpVersion);
 
286
   return m_cpVersion;
 
287
}
 
288
 
 
289
 
 
290
/**
 
291
 *
 
292
 * Get the version of the DnD protocol being wrapped.
 
293
 *
 
294
 * @return DnD protocol version.
 
295
 */
 
296
 
 
297
int
 
298
CopyPasteDnDWrapper::GetDnDVersion()
 
299
{
 
300
   g_debug("%s: enter\n", __FUNCTION__);
 
301
   if (IsDnDRegistered()) {
 
302
      char *reply = NULL;
 
303
      size_t replyLen;
 
304
 
 
305
      ToolsAppCtx *ctx = GetToolsAppCtx();
 
306
      if (!RpcChannel_Send(ctx->rpc, QUERY_VMX_DND_VERSION,
 
307
                           strlen(QUERY_VMX_DND_VERSION), &reply, &replyLen)) {
 
308
         g_debug("%s: could not get VMX dnd "
 
309
               "version capability: %s\n", __FUNCTION__, reply ? reply : "NULL");
 
310
         m_dndVersion = 1;
 
311
      } else {
 
312
         m_dndVersion = atoi(reply);
 
313
      }
 
314
      free(reply);
 
315
   }
 
316
   g_debug("%s: got version %d\n", __FUNCTION__, m_dndVersion);
 
317
   return m_dndVersion;
 
318
}
 
319
 
 
320
 
 
321
/**
 
322
 *
 
323
 * Set a flag indicating that we are wrapping an initialized and registered
 
324
 * copy paste implementation, or not.
 
325
 *
 
326
 * @param[in] isRegistered If TRUE, protocol is registered, otherwise FALSE.
 
327
 */
 
328
 
 
329
void
 
330
CopyPasteDnDWrapper::SetCPIsRegistered(gboolean isRegistered)
 
331
{
 
332
   g_debug("%s: enter\n", __FUNCTION__);
 
333
   m_isCPRegistered = isRegistered;
 
334
}
 
335
 
 
336
 
 
337
/**
 
338
 *
 
339
 * Get the flag indicating that we are wrapping an initialized and registered
 
340
 * copy paste implementation, or not.
 
341
 *
 
342
 * @return TRUE if copy paste is initialized, otherwise FALSE.
 
343
 */
 
344
 
 
345
gboolean
 
346
CopyPasteDnDWrapper::IsCPRegistered()
 
347
{
 
348
   g_debug("%s: enter\n", __FUNCTION__);
 
349
   return m_isCPRegistered;
 
350
}
 
351
 
 
352
 
 
353
/**
 
354
 *
 
355
 * Set a flag indicating that we are wrapping an initialized and registered
 
356
 * DnD implementation, or not.
 
357
 *
 
358
 * @param[in] isRegistered If TRUE, protocol is registered, otherwise FALSE.
 
359
 */
 
360
 
 
361
void
 
362
CopyPasteDnDWrapper::SetDnDIsRegistered(gboolean isRegistered)
 
363
{
 
364
   m_isDnDRegistered = isRegistered;
 
365
}
 
366
 
 
367
 
 
368
/**
 
369
 *
 
370
 * Get the flag indicating that we are wrapping an initialized and registered
 
371
 * DnD implementation, or not.
 
372
 *
 
373
 * @return TRUE if DnD is initialized, otherwise FALSE.
 
374
 */
 
375
 
 
376
gboolean
 
377
CopyPasteDnDWrapper::IsDnDRegistered()
 
378
{
 
379
   return m_isDnDRegistered;
 
380
}
 
381
 
 
382
 
 
383
/**
 
384
 *
 
385
 * Set a flag indicating that copy paste is enabled, or not. This is called
 
386
 * in response to SetOption RPC being received.
 
387
 *
 
388
 * @param[in] isEnabled If TRUE, copy paste is enabled, otherwise FALSE.
 
389
 */
 
390
 
 
391
void
 
392
CopyPasteDnDWrapper::SetCPIsEnabled(gboolean isEnabled)
 
393
{
 
394
   g_debug("%s: enter\n", __FUNCTION__);
 
395
   m_isCPEnabled = isEnabled;
 
396
   if (!isEnabled && IsCPRegistered()) {
 
397
      UnregisterCP();
 
398
   } else if (isEnabled && !IsCPRegistered()) {
 
399
      RegisterCP();
 
400
   }
 
401
}
 
402
 
 
403
 
 
404
/**
 
405
 *
 
406
 * Get the flag indicating that copy paste was enabled (via SetOption RPC).
 
407
 *
 
408
 * @return TRUE if copy paste is enabled, otherwise FALSE.
 
409
 */
 
410
 
 
411
gboolean
 
412
CopyPasteDnDWrapper::IsCPEnabled()
 
413
{
 
414
   return m_isCPEnabled;
 
415
}
 
416
 
 
417
 
 
418
/**
 
419
 *
 
420
 * Set a flag indicating that DnD is enabled, or not. This is called
 
421
 * in response to SetOption RPC being received.
 
422
 *
 
423
 * @param[in] isEnabled If TRUE, DnD is enabled, otherwise FALSE.
 
424
 */
 
425
 
 
426
void
 
427
CopyPasteDnDWrapper::SetDnDIsEnabled(gboolean isEnabled)
 
428
{
 
429
   m_isDnDEnabled = isEnabled;
 
430
   if (!isEnabled && IsDnDRegistered()) {
 
431
      UnregisterDnD();
 
432
   } else if (isEnabled && !IsDnDRegistered()) {
 
433
      RegisterDnD();
 
434
   }
 
435
}
 
436
 
 
437
 
 
438
/**
 
439
 *
 
440
 * Get the flag indicating that DnD was enabled (via SetOption) or not.
 
441
 *
 
442
 * @return TRUE if DnD is enabled, otherwise FALSE.
 
443
 */
 
444
 
 
445
gboolean
 
446
CopyPasteDnDWrapper::IsDnDEnabled()
 
447
{
 
448
   return m_isDnDEnabled;
 
449
}
 
450
 
 
451
 
 
452
/**
 
453
 *
 
454
 * Timer callback for reset. Handle it by calling the member function
 
455
 * that handles reset.
 
456
 *
 
457
 * @param[in] clientData pointer to the CopyPasteDnDWrapper instance that
 
458
 * issued the timer.
 
459
 *
 
460
 * @return FALSE always.
 
461
 */
 
462
 
 
463
static gboolean
 
464
DnDPluginResetSent(void *clientData)
 
465
{
 
466
   CopyPasteDnDWrapper *p = reinterpret_cast<CopyPasteDnDWrapper *>(clientData);
 
467
 
 
468
   ASSERT(p);
 
469
   p->OnResetInternal();
 
470
   return FALSE;
 
471
}
 
472
 
 
473
 
 
474
/**
 
475
 *
 
476
 * Handle reset.
 
477
 */
 
478
 
 
479
void
 
480
CopyPasteDnDWrapper::OnResetInternal()
 
481
{
 
482
   g_debug("%s: enter\n", __FUNCTION__);
 
483
   if (IsDnDRegistered()) {
 
484
      UnregisterDnD();
 
485
   }
 
486
   if (IsCPRegistered()) {
 
487
      UnregisterCP();
 
488
   }
 
489
   if (IsCPEnabled() && !IsCPRegistered()) {
 
490
      RegisterCP();
 
491
   }
 
492
   if (IsDnDEnabled() && !IsDnDRegistered()) {
 
493
      /*
 
494
       * Reset DnD/Copy/Paste only if vmx said we can. The reason is that
 
495
       * we may also get reset request from vmx when user is taking snapshot
 
496
       * or recording. If there is an ongoing DnD/copy/paste, we should not
 
497
       * reset here. For details please refer to bug 375928.
 
498
       */
 
499
 
 
500
      char *reply = NULL;
 
501
      size_t replyLen;
 
502
      ToolsAppCtx *ctx = GetToolsAppCtx();
 
503
      if (!RpcChannel_Send(ctx->rpc, "dnd.is.active",
 
504
                           strlen("dnd.is.active"), &reply, &replyLen) ||
 
505
          (0 == atoi(reply))) {
 
506
         RegisterDnD();
 
507
      }
 
508
   }
 
509
   if (!IsDnDRegistered() || !IsCPRegistered()) {
 
510
      g_debug("%s: unable to reset fully DnD %d CP %d!\n",
 
511
            __FUNCTION__, IsDnDRegistered(), IsCPRegistered());
 
512
   }
 
513
}
 
514
 
 
515
 
 
516
/**
 
517
 *
 
518
 * Handle reset.
 
519
 *
 
520
 * Schedule the post-reset actions to happen a little after one cycle of the
 
521
 * RpcIn loop. This will give vmware a chance to receive the ATR
 
522
 * reinitialize the channel if appropriate.
 
523
 */
 
524
 
 
525
void
 
526
CopyPasteDnDWrapper::OnReset()
 
527
{
 
528
   GSource *src;
 
529
 
 
530
   g_debug("%s: enter\n", __FUNCTION__);
 
531
   src = VMTools_CreateTimer(RPC_POLL_TIME * 30);
 
532
   if (src) {
 
533
      VMTOOLSAPP_ATTACH_SOURCE(m_ctx, src, DnDPluginResetSent, this, NULL);
 
534
      g_source_unref(src);
 
535
   }
 
536
}
 
537
 
 
538
 
 
539
/**
 
540
 *
 
541
 * Handle cap reg. This is cross-platform so handle here instead of the
 
542
 * platform implementation.
 
543
 */
 
544
 
 
545
void
 
546
CopyPasteDnDWrapper::OnCapReg(gboolean set)
 
547
{
 
548
   g_debug("%s: enter\n", __FUNCTION__);
 
549
   char *reply;
 
550
   size_t replyLen;
 
551
   const char *toolsDnDVersion = TOOLS_DND_VERSION_4;
 
552
   char *toolsCopyPasteVersion = NULL;
 
553
   int version;
 
554
 
 
555
   ToolsAppCtx *ctx = GetToolsAppCtx();
 
556
   if (ctx) {
 
557
      /*
 
558
       * First DnD.
 
559
       */
 
560
      if (!RpcChannel_Send(ctx->rpc, toolsDnDVersion, strlen(toolsDnDVersion),
 
561
                           NULL, NULL)) {
 
562
         g_debug("%s: could not set guest dnd version capability\n",
 
563
               __FUNCTION__);
 
564
         version = 1;
 
565
         SetDnDVersion(version);
 
566
      } else {
 
567
         char const *vmxDnDVersion = QUERY_VMX_DND_VERSION;
 
568
 
 
569
         if (!RpcChannel_Send(ctx->rpc, vmxDnDVersion,
 
570
                              strlen(vmxDnDVersion), &reply, &replyLen)) {
 
571
            g_debug("%s: could not get VMX dnd version capability, assuming v1\n",
 
572
                  __FUNCTION__);
 
573
            version = 1;
 
574
            SetDnDVersion(version);
 
575
         } else {
 
576
            int version = atoi(reply);
 
577
            ASSERT(version >= 1);
 
578
            SetDnDVersion(version);
 
579
            g_debug("%s: VMX is dnd version %d\n", __FUNCTION__, GetDnDVersion());
 
580
            if (version == 3) {
 
581
               /*
 
582
                * VMDB still has version 4 in it, which will cause a V3
 
583
                * host to fail. So, change to version 3. Since we don't
 
584
                * support any other version, we only do this for V3.
 
585
                */
 
586
               toolsDnDVersion = TOOLS_DND_VERSION_3;
 
587
               if (!RpcChannel_Send(ctx->rpc, toolsDnDVersion,
 
588
                                    strlen(toolsDnDVersion), NULL, NULL)) {
 
589
 
 
590
                  g_debug("%s: could not set VMX dnd version capability, assuming v1\n",
 
591
                           __FUNCTION__);
 
592
                  version = 1;
 
593
                  SetDnDVersion(version);
 
594
               }
 
595
            }
 
596
         }
 
597
         vm_free(reply);
 
598
       }
 
599
 
 
600
      /*
 
601
       * Now CopyPaste.
 
602
       */
 
603
 
 
604
      toolsCopyPasteVersion = g_strdup_printf(TOOLS_COPYPASTE_VERSION" %d", 4);
 
605
      if (!RpcChannel_Send(ctx->rpc, toolsCopyPasteVersion,
 
606
                           strlen(toolsCopyPasteVersion),
 
607
                           NULL, NULL)) {
 
608
         g_debug("%s: could not set guest copypaste version capability\n",
 
609
               __FUNCTION__);
 
610
         version = 1;
 
611
         SetCPVersion(version);
 
612
      } else {
 
613
         char const *vmxCopyPasteVersion = QUERY_VMX_COPYPASTE_VERSION;
 
614
 
 
615
         if (!RpcChannel_Send(ctx->rpc, vmxCopyPasteVersion,
 
616
                              strlen(vmxCopyPasteVersion), &reply, &replyLen)) {
 
617
            g_debug("%s: could not get VMX copypaste version capability, assuming v1\n",
 
618
                  __FUNCTION__);
 
619
            version = 1;
 
620
            SetCPVersion(version);
 
621
         } else {
 
622
            version = atoi(reply);
 
623
            ASSERT(version >= 1);
 
624
            SetCPVersion(version);
 
625
            g_debug("%s: VMX is copypaste version %d\n", __FUNCTION__,
 
626
                  GetCPVersion());
 
627
            if (version == 3) {
 
628
               /*
 
629
                * VMDB still has version 4 in it, which will cause a V3
 
630
                * host to fail. So, change to version 3. Since we don't
 
631
                * support any other version, we only do this for V3.
 
632
                */
 
633
               g_free(toolsCopyPasteVersion);
 
634
               toolsCopyPasteVersion = g_strdup_printf(TOOLS_COPYPASTE_VERSION" %d", 3);
 
635
               if (!RpcChannel_Send(ctx->rpc, toolsCopyPasteVersion,
 
636
                                    strlen(toolsCopyPasteVersion), NULL, NULL)) {
 
637
 
 
638
                  g_debug("%s: could not set VMX copypaste version, assuming v1\n",
 
639
                           __FUNCTION__);
 
640
                  version = 1;
 
641
                  SetCPVersion(version);
 
642
               }
 
643
            }
 
644
         }
 
645
         vm_free(reply);
 
646
      }
 
647
      g_free(toolsCopyPasteVersion);
 
648
   }
 
649
}
 
650
 
 
651
 
 
652
/**
 
653
 *
 
654
 * Handle SetOption
 
655
 */
 
656
 
 
657
gboolean
 
658
CopyPasteDnDWrapper::OnSetOption(const char *option, const char *value)
 
659
{
 
660
   gboolean ret = false;
 
661
   bool bEnable;
 
662
 
 
663
   ASSERT(option);
 
664
   ASSERT(value);
 
665
 
 
666
   bEnable = strcmp(value, "1") ? false : true;
 
667
   g_debug("%s: setting option '%s' to '%s'\n", __FUNCTION__, option, value);
 
668
   if (strcmp(option, TOOLSOPTION_ENABLEDND) == 0) {
 
669
      SetDnDIsEnabled(bEnable);
 
670
      ret = true;
 
671
   } else if (strcmp(option, TOOLSOPTION_COPYPASTE) == 0) {
 
672
      SetCPIsEnabled(bEnable);
 
673
      ret = true;
 
674
   }
 
675
 
 
676
   return ret;
 
677
}
 
678
 
 
679
 
 
680
/**
 
681
 * Get capabilities by calling platform implementation.
 
682
 *
 
683
 * @return 32-bit mask of DnD/CP capabilities.
 
684
 */
 
685
 
 
686
uint32
 
687
CopyPasteDnDWrapper::GetCaps()
 
688
{
 
689
   ASSERT(m_pimpl);
 
690
 
 
691
   return m_pimpl->GetCaps();
 
692
}