1
/*********************************************************
2
* Copyright (C) 2010 VMware, Inc. All rights reserved.
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.
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.
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.
17
*********************************************************/
22
* Guest-host integration functions.
26
#include "ghIntegration.h"
31
#include "vmware/tools/guestrpc.h"
34
#include "guest_msg_def.h"
39
#include "unityCommon.h"
44
#include "guestrpc/ghiGetBinaryHandlers.h"
45
#include "guestrpc/ghiGetExecInfoHash.h"
46
#include "guestrpc/ghiProtocolHandler.h"
47
#include "guestrpc/ghiSetFocusedWindow.h"
48
#include "guestrpc/ghiSetGuestHandler.h"
49
#include "guestrpc/ghiSetOutlookTempFolder.h"
50
#include "guestrpc/ghiShellAction.h"
51
#include "guestrpc/ghiStartMenu.h"
52
#include "guestrpc/ghiTrayIcon.h"
53
#include "vmware/guestrpc/capabilities.h"
55
static DynBuf gTcloUpdate;
58
* Overhead of encoding the icon data in a dynbuf - used to make sure we don't
59
* exceed GUEST_MSG_MAX_IN_SIZE when serializing the icons for an app.
61
static const int GHI_ICON_OVERHEAD = 1024;
65
*----------------------------------------------------------------------------
69
* Initialize the global state (a Dynbuf) used to handle the TCLO parsing
78
*----------------------------------------------------------------------------
84
DynBuf_Init(&gTcloUpdate);
89
*----------------------------------------------------------------------------
93
* Cleanup the global state (a Dynbuf) used to handle the TCLO parsing
102
*----------------------------------------------------------------------------
108
DynBuf_Destroy(&gTcloUpdate);
113
*----------------------------------------------------------------------------
115
* GHITcloGetBinaryInfo --
117
* RPC handler for 'unity.get.binary.info'. Get required binary info
118
* and send it back to the VMX.
121
* TRUE if everything is successful.
127
*----------------------------------------------------------------------------
131
GHITcloGetBinaryInfo(RpcInData *data) // IN/OUT
133
char *binaryPathUtf8;
134
DynBuf *buf = &gTcloUpdate;
136
unsigned int index = 0;
138
std::string friendlyName;
139
std::list<GHIBinaryIconInfo> iconList;
140
char temp[128]; // Used to hold sizes and indices as strings
141
uint32 serializedIconCount = 0;
143
/* Check our arguments. */
152
if (!data->name || !data->args) {
153
Debug("%s: Invalid arguments.\n", __FUNCTION__);
154
return RPCIN_SETRETVALS(data, "Invalid arguments.", FALSE);
157
Debug("%s name:%s args:'%s'\n", __FUNCTION__, data->name, data->args);
159
/* Skip the leading space. */
162
/* The binary path provided by the VMX is in UTF8. */
163
binaryPathUtf8 = StrUtil_GetNextToken(&index, data->args, "");
165
if (!binaryPathUtf8) {
166
Debug("%s: Invalid RPC arguments.\n", __FUNCTION__);
167
ret = RPCIN_SETRETVALS(data,
168
"Invalid arguments. Expected \"binary_path\"",
173
DynBuf_SetSize(buf, 0);
175
if (!GHI_GetBinaryInfo(binaryPathUtf8, friendlyName, iconList)) {
176
Debug("%s: Could not get binary info.\n", __FUNCTION__);
177
ret = RPCIN_SETRETVALS(data,
178
"Could not get binary info",
184
* Append the name to the output buffer now. If we fail to get the
185
* icons, we still want to return the app name. Then the UI can display
186
* the default icon and correct app name.
188
* The output buffer should look like this:
189
* <name>\0<icon count>\0<width>\0<height>\0<size>\0<bgraData>\0...
191
* Note that the icon data is in BGRA format. An alpha channel value of 255 means
192
* "fully opaque", and an alpha channel value of 0 means "fully transparent".
195
DynBuf_AppendString(buf, friendlyName.c_str());
197
if (iconList.size() <= 0) {
198
Debug("%s: Could not find any icons for path: %s", __FUNCTION__, binaryPathUtf8);
201
DynBuf_Init(&iconDataBuf);
202
/* Copy icon info to the output buffer. */
203
for (std::list<GHIBinaryIconInfo>::const_iterator it = iconList.begin();
204
it != iconList.end();
207
* XXX: The backdoor has a maximum RPC data size of 64K - don't attempt to send
208
* icons larger than this size.
210
if ((DynBuf_GetSize(&iconDataBuf) + it->dataBGRA.size()) <
211
GUESTMSG_MAX_IN_SIZE - GHI_ICON_OVERHEAD) {
212
Str_Sprintf(temp, sizeof temp, "%u", it->width);
213
DynBuf_AppendString(&iconDataBuf, temp);
215
Str_Sprintf(temp, sizeof temp, "%u", it->height);
216
DynBuf_AppendString(&iconDataBuf, temp);
218
Str_Sprintf(temp, sizeof temp, "%u", (int32) it->dataBGRA.size());
219
DynBuf_AppendString(&iconDataBuf, temp);
221
DynBuf_Append(&iconDataBuf, &(it->dataBGRA[0]),
222
it->dataBGRA.size());
223
DynBuf_AppendString(&iconDataBuf, "");
225
serializedIconCount++;
229
Str_Sprintf(temp, sizeof temp, "%d", serializedIconCount);
230
DynBuf_AppendString(buf, temp);
232
/* Append the icon data */
233
DynBuf_Append(buf, DynBuf_Get(&iconDataBuf), DynBuf_GetSize(&iconDataBuf));
234
DynBuf_Destroy(&iconDataBuf);
237
* Write the final result into the result out parameters and return!
239
data->result = (char *)DynBuf_Get(buf);
240
data->resultLen = DynBuf_GetSize(buf);
243
free(binaryPathUtf8);
249
*----------------------------------------------------------------------------
251
* GHITcloGetBinaryHandlers --
253
* RPC handler for 'unity.get.binary.handlers'. Get filetypes supported
254
* by the binary and send it back to the VMX.
257
* TRUE if everything is successful.
263
*----------------------------------------------------------------------------
267
GHITcloGetBinaryHandlers(RpcInData *data) // IN/OUT
269
char *binaryPathUtf8;
271
unsigned int index = 0;
273
GHIBinaryHandlersList *handlersList = NULL;
275
/* Check our arguments. */
284
if (!data->name || !data->args) {
285
Debug("%s: Invalid arguments.\n", __FUNCTION__);
286
return RPCIN_SETRETVALS(data, "Invalid arguments.", FALSE);
289
Debug("%s name:%s args:'%s'\n", __FUNCTION__, data->name, data->args);
291
/* Skip the leading space. */
294
/* The binary path provided by the VMX is in UTF8. */
295
binaryPathUtf8 = StrUtil_GetNextToken(&index, data->args, "");
297
if (!binaryPathUtf8) {
298
Debug("%s: Invalid RPC arguments.\n", __FUNCTION__);
299
return RPCIN_SETRETVALS(data, "Invalid arguments. Expected \"binary_path\"", FALSE);
302
handlersList = (GHIBinaryHandlersList *) Util_SafeCalloc(1, sizeof *handlersList);
303
ASSERT_MEM_ALLOC(DynXdr_Create(&xdrs));
305
#if !defined(OPEN_VM_TOOLS)
306
FileTypeList::const_iterator fileTypeIterator;
307
FileTypeList aFileTypeList;
309
aFileTypeList = GHI_GetBinaryHandlers(binaryPathUtf8);
312
* Take the list of filetypes handled by this application and convert it into
313
* the XDR based structure that we'll then serialize
317
for (fileTypeIterator = aFileTypeList.begin(), fileTypeCount = 0;
318
(fileTypeIterator != aFileTypeList.end()) &&
319
(fileTypeCount < GHI_MAX_NUM_BINARY_HANDLERS);
320
++fileTypeIterator, ++fileTypeCount)
322
std::string extension = (*fileTypeIterator)->Extension();
323
size_t extensionStringLength = strlen(extension.c_str()) + 1;
324
std::string actionURI = (*fileTypeIterator)->GetActionURIList().front();
325
size_t actionURILength = strlen(actionURI.c_str()) + 1;
328
* Copy the handlers suffix/extension string.
330
GHIBinaryHandlersDetails *aHandler = (GHIBinaryHandlersDetails *)
331
XDRUTIL_ARRAYAPPEND(handlersList,
334
ASSERT_MEM_ALLOC(aHandler);
335
aHandler->suffix = (char *) Util_SafeCalloc(extensionStringLength,
336
sizeof *aHandler->suffix);
337
Str_Strcpy(aHandler->suffix, extension.c_str(), extensionStringLength);
340
* Empty strings for all the other 'type' fields. Note that we cannot leave the
341
* string pointer as NULL, we must encode an empty string for XDR to work.
343
aHandler->mimetype = (char *) Util_SafeCalloc(1, sizeof *aHandler->mimetype);
344
aHandler->mimetype[0] = '\0';
345
aHandler->UTI = (char *) Util_SafeCalloc(1, sizeof *aHandler->UTI);
346
aHandler->UTI[0] = '\0';
349
* Set the Action URI and friendly name for this type
351
GHIBinaryHandlersActionURIPair *anActionPair = (GHIBinaryHandlersActionURIPair *)
352
XDRUTIL_ARRAYAPPEND(aHandler,
355
ASSERT_MEM_ALLOC(anActionPair);
356
anActionPair->actionURI = (char *) Util_SafeCalloc(actionURILength,
357
sizeof *anActionPair->actionURI);
358
Str_Strcpy(anActionPair->actionURI, actionURI.c_str(), actionURILength);
359
anActionPair->verb = Util_SafeStrdup("run");
361
std::string friendlyName = (*fileTypeIterator)->FriendlyName();
362
size_t friendlyNameLength = strlen(friendlyName.c_str()) + 1;
363
aHandler->friendlyName = (char *) Util_SafeCalloc(friendlyNameLength,
364
sizeof *aHandler->friendlyName);
365
Str_Strcpy(aHandler->friendlyName, friendlyName.c_str(), friendlyNameLength);
368
* Store the list of icon dimensions and URIs.
369
* TODO: Retrieve the list of icons and their dimensions for this filetype.
372
#endif // OPEN_VM_TOOLS
374
GHIBinaryHandlers message;
375
message.ver = GHI_BINARY_HANDLERS_V1;
376
message.GHIBinaryHandlers_u.handlersV1 = handlersList;
378
ret = xdr_GHIBinaryHandlers(&xdrs, &message);
380
Debug("%s: Failed to serialize binary handlers list.\n", __FUNCTION__);
381
ret = RPCIN_SETRETVALS(data, "Failed to serialize binary handlers list.", FALSE);
382
goto exitWithXDRCleanup;
386
* If the serialized data exceeds our maximum message size we have little choice
387
* but to fail the request and log the oversize message.
389
if (xdr_getpos(&xdrs) > GUESTMSG_MAX_IN_SIZE) {
390
ret = RPCIN_SETRETVALS(data, "Filetype list too large", FALSE);
391
goto exitWithXDRCleanup;
395
* Write the final result into the result out parameters and return!
397
data->result = reinterpret_cast<char *>(DynXdr_Get(&xdrs));
398
data->resultLen = xdr_getpos(&xdrs);
399
data->freeResult = TRUE;
403
VMX_XDR_FREE(xdr_GHIBinaryHandlers, &message);
405
* Destroy the XDR structure but leave the data buffer alone since it will be
406
* freed by the RpcIn layer.
408
DynXdr_Destroy(&xdrs, FALSE);
409
free(binaryPathUtf8);
415
*----------------------------------------------------------------------------
417
* GHITcloOpenStartMenu --
419
* RPC handler for 'unity.launchmenu.open'. Get the start menu sub-tree
420
* for a given item, save it in the array so it can be accessed
421
* later when the VMX needs to iterate over the items. Return the count
422
* of the items in the sub-tree and a handle to this sub-tree. The handle
423
* will be used by the VMX to iterate over the sub-items.
426
* TRUE if everything is successful.
432
*----------------------------------------------------------------------------
436
GHITcloOpenStartMenu(RpcInData *data) // IN/OUT
438
char *rootUtf8 = NULL;
439
DynBuf *buf = &gTcloUpdate;
444
/* Check our arguments. */
453
if (!data->name || !data->args) {
454
Debug("%s: Invalid arguments.\n", __FUNCTION__);
455
return RPCIN_SETRETVALS(data, "Invalid arguments.", FALSE);
458
Debug("%s name:%s args:'%s'\n", __FUNCTION__, data->name, data->args);
460
/* Skip the leading space. */
463
/* The start menu root provided by the VMX is in UTF8. */
464
rootUtf8 = StrUtil_GetNextToken(&index, data->args, "");
467
Debug("%s: Invalid RPC arguments.\n", __FUNCTION__);
468
ret = RPCIN_SETRETVALS(data,
469
"Invalid arguments. Expected \"root\"",
475
* Skip the NULL after the root, and look for the flags. Old versions of
476
* the VMX don't send this parameter, so it's not an error if it is not
477
* present in the RPC.
479
if (++index < data->argsSize && sscanf(data->args + index, "%u", &flags) != 1) {
480
Debug("%s: Invalid RPC arguments.\n", __FUNCTION__);
481
ret = RPCIN_SETRETVALS(data,
482
"Invalid arguments. Expected flags",
487
DynBuf_SetSize(buf, 0);
488
if (!GHI_OpenStartMenuTree(rootUtf8, flags, buf)) {
489
Debug("%s: Could not open start menu.\n", __FUNCTION__);
490
ret = RPCIN_SETRETVALS(data,
491
"Could not get start menu count",
497
* Write the final result into the result out parameters and return!
499
data->result = (char *)DynBuf_Get(buf);
500
data->resultLen = DynBuf_GetSize(buf);
509
*----------------------------------------------------------------------------
511
* GHITcloGetStartMenuItem --
513
* RPC handler for 'unity.launchmenu.next'. Get the start menu item
514
* at the given index for the tree with a given handle.
515
* If there's no item at the given index, return FALSE.
518
* TRUE if the item was found.
519
* FALSE otherwise (i.e. if the VMX provides a wrong handle or if there's
525
*----------------------------------------------------------------------------
529
GHITcloGetStartMenuItem(RpcInData *data) // IN/OUT
531
DynBuf *buf = &gTcloUpdate;
534
uint32 itemIndex = 0;
537
/* Check our arguments. */
546
if (!data->name || !data->args) {
547
Debug("%s: Invalid arguments.\n", __FUNCTION__);
548
return RPCIN_SETRETVALS(data, "Invalid arguments.", FALSE);
551
Debug("%s name:%s args:'%s'\n", __FUNCTION__, data->name, data->args);
553
/* Parse the handle of the menu tree that VMX wants. */
554
if (!StrUtil_GetNextUintToken(&handle, &index, data->args, " ")) {
555
Debug("%s: Invalid RPC arguments.\n", __FUNCTION__);
556
return RPCIN_SETRETVALS(data,
557
"Invalid arguments. Expected handle index",
561
/* The index of the menu item to be send back. */
562
if (!StrUtil_GetNextUintToken(&itemIndex, &index, data->args, " ")) {
563
Debug("%s: Invalid RPC arguments.\n", __FUNCTION__);
564
return RPCIN_SETRETVALS(data,
565
"Invalid arguments. Expected handle index",
569
DynBuf_SetSize(buf, 0);
570
if (!GHI_GetStartMenuItem(handle, itemIndex, buf)) {
571
Debug("%s: Could not get start menu item.\n", __FUNCTION__);
572
return RPCIN_SETRETVALS(data,
573
"Could not get start menu item",
578
* Write the final result into the result out parameters and return!
580
data->result = (char *)DynBuf_Get(buf);
581
data->resultLen = DynBuf_GetSize(buf);
588
*----------------------------------------------------------------------------
590
* GHITcloCloseStartMenu --
592
* RPC handler for 'unity.launchmenu.close'. The VMX is done with this
593
* particular start menu tree. Free all memory and cleanup.
599
* Memory allocated when the start menu tree was opened is finally freed.
601
*----------------------------------------------------------------------------
605
GHITcloCloseStartMenu(RpcInData *data) // IN/OUT
610
/* Check our arguments. */
619
if (!data->name || !data->args) {
620
Debug("%s: Invalid arguments.\n", __FUNCTION__);
621
return RPCIN_SETRETVALS(data, "Invalid arguments.", FALSE);
624
Debug("%s name:%s args:'%s'\n", __FUNCTION__, data->name, data->args);
626
/* Parse the handle of the menu tree that VMX wants. */
627
if (!StrUtil_GetNextIntToken(&handle, &index, data->args, " ")) {
628
Debug("%s: Invalid RPC arguments.\n", __FUNCTION__);
629
return RPCIN_SETRETVALS(data,
630
"Invalid arguments. Expected handle",
634
GHI_CloseStartMenuTree(handle);
636
return RPCIN_SETRETVALS(data, "", TRUE);
641
*----------------------------------------------------------------------------
643
* GHITcloShellOpen --
645
* RPC handler for 'unity.shell.open'. Open the specified file with the
646
* default shell handler. Note that the file path may be either a URI
647
* (originated with Tools >= NNNNN), or a regular path (originated with
651
* TRUE if everything is successful.
657
*----------------------------------------------------------------------------
661
GHITcloShellOpen(RpcInData *data) // IN/OUT
663
char *fileUtf8 = NULL;
665
unsigned int index = 0;
667
/* Check our arguments. */
676
if (!data->name || !data->args) {
677
Debug("%s: Invalid arguments.\n", __FUNCTION__);
678
return RPCIN_SETRETVALS(data, "Invalid arguments.", FALSE);
681
Debug("%s: name: '%s', args: '%s'\n", __FUNCTION__, data->name, data->args);
683
/* Skip the leading space. */
686
/* The file path provided by the VMX is in UTF8. */
687
fileUtf8 = StrUtil_GetNextToken(&index, data->args, "");
690
Debug("%s: Invalid RPC arguments.\n", __FUNCTION__);
691
return RPCIN_SETRETVALS(data,
692
"Invalid arguments. Expected file_name",
696
ret = GHI_ShellOpen(fileUtf8);
700
Debug("%s: Could not perform the requested shell open action.\n", __FUNCTION__);
701
return RPCIN_SETRETVALS(data,
702
"Could not perform the requested shell open action.",
706
return RPCIN_SETRETVALS(data, "", TRUE);
711
*----------------------------------------------------------------------------
713
* GHITcloShellAction --
715
* RPC handler for "ghi.guest.shell.action". The action command has three
716
* arguments: an action URI, a target URI, and an array of location URIs.
717
* Action URIs are in the form: "x-vmware-action://<verb>", where <verb> is
718
* the name of a specific action to perform.
719
* The target URI is a guest-specific URI that was previously given to the
720
* host (usually a path to an application to run). Note that this may be
721
* either a URI (new Tools) or a regular path (old Tools).
722
* The locations can be files or URLs. Files are typically specified as
723
* HGFS shared folder locations (see below), but can potentially use the
724
* "file://<path>" URIs as well.
725
* Each guest can specify the features it supports using capability flags:
727
* Capability Description
729
* GHI_CAP_CMD_SHELL_ACTION Guest allows 'ghi.guest.shell.action'.
730
* This encompasses this entire command
731
* and the rest of the capabilities.
733
* GHI_CAP_SHELL_ACTION_BROWSE Guest supports the 'browse' action verb,
734
* used to open a file browser window with
735
* a given set of locations.
737
* GHI_CAP_SHELL_ACTION_RUN Guest supports the 'run' action verb,
738
* used for running applications as well
739
* as opening file or URL locations.
741
* GHI_CAP_SHELL_LOCATION_HGFS Guest supports HGFS share location URIs:
742
* "x-vmware-share://<path>", where <path>
743
* specifies a shared folder name and an
744
* optional path within the shared folder.
747
* TRUE if everything is successful.
753
*----------------------------------------------------------------------------
757
GHITcloShellAction(RpcInData *data) // IN/OUT
760
GHIShellAction shellActionMsg;
761
GHIShellActionV1 *shellActionV1Ptr;
762
memset(&shellActionMsg, 0, sizeof shellActionMsg);
764
/* Check our arguments. */
773
if (!data->name || !data->args) {
774
Debug("%s: Invalid arguments.\n", __FUNCTION__);
775
return RPCIN_SETRETVALS(data, "Invalid arguments.", FALSE);
779
* Build an XDR Stream from the argument data which begins are args + 1
780
* since there is a space separator between the RPC name and the XDR serialization.
782
if (!XdrUtil_Deserialize((char *)data->args + 1, data->argsSize - 1,
783
(void *)xdr_GHIShellAction, &shellActionMsg)) {
784
Debug("%s: Failed to deserialize data\n", __FUNCTION__);
785
ret = RPCIN_SETRETVALS(data,
786
"Failed to deserialize data.",
791
ASSERT(shellActionMsg.ver == GHI_SHELL_ACTION_V1);
792
if (shellActionMsg.ver != GHI_SHELL_ACTION_V1) {
793
Debug("%s: Unexpected XDR version = %d\n", __FUNCTION__, shellActionMsg.ver);
794
ret = RPCIN_SETRETVALS(data,
795
"Unexpected XDR version.",
800
shellActionV1Ptr = shellActionMsg.GHIShellAction_u.actionV1;
801
ret = GHI_ShellAction(shellActionV1Ptr->actionURI,
802
shellActionV1Ptr->targetURI,
803
(const char **)shellActionV1Ptr->locations.locations_val,
804
shellActionV1Ptr->locations.locations_len);
806
Debug("%s: Could not perform the requested shell action.\n", __FUNCTION__);
807
ret = RPCIN_SETRETVALS(data,
808
"Could not perform the requested shell action.",
813
ret = RPCIN_SETRETVALS(data, "", TRUE);
816
VMX_XDR_FREE(xdr_GHIShellAction, &shellActionMsg);
823
*----------------------------------------------------------------------------
825
* GHITcloSetGuestHandler --
827
* RPC handler for 'ghi.guest.handler.set'. Changes the nominated handlerType
828
* to use the VMwareHostOpen proxy app to open files or URLs in the host.
831
* TRUE if everything is successful.
837
*----------------------------------------------------------------------------
841
GHITcloSetGuestHandler(RpcInData *data) // IN/OUT
846
/* Check our arguments. */
855
if (!data->name || !data->args) {
856
Debug("%s: Invalid arguments.\n", __FUNCTION__);
857
return RPCIN_SETRETVALS(data, "Invalid arguments.", FALSE);
860
Debug("%s name:%s args length: %"FMTSZ"u\n", __FUNCTION__, data->name, data->argsSize);
863
* Build an XDR Stream from the argument data which beings are args + 1
864
* since there is a space separator between the RPC name and the XDR serialization.
866
xdrmem_create(&xdrs, (char *) data->args + 1, data->argsSize - 1, XDR_DECODE);
868
GHISetGuestHandler setGuestHandlerMsg;
869
GHISetGuestHandlerV1 *setGuestHandlerV1Ptr;
870
GHISetGuestHandlerAction *aHandlerAction;
872
memset(&setGuestHandlerMsg, 0, sizeof setGuestHandlerMsg);
873
if (!xdr_GHISetGuestHandler(&xdrs, &setGuestHandlerMsg)) {
874
Debug("%s: Unable to deserialize data\n", __FUNCTION__);
875
ret = RPCIN_SETRETVALS(data, "Unable to deserialize data.", FALSE);
876
goto exitWithXDRCleanup;
879
ASSERT(setGuestHandlerMsg.ver == GHI_SET_GUEST_HANDLER_V1);
880
setGuestHandlerV1Ptr = setGuestHandlerMsg.GHISetGuestHandler_u.guestHandlerV1;
881
aHandlerAction = setGuestHandlerV1Ptr->actionURIs.actionURIs_val;
883
ret = GHI_SetGuestHandler(setGuestHandlerV1Ptr->suffix,
884
setGuestHandlerV1Ptr->mimetype,
885
setGuestHandlerV1Ptr->UTI,
886
aHandlerAction->actionURI,
887
aHandlerAction->targetURI);
890
Debug("%s: Unable to set guest handler\n", __FUNCTION__);
891
ret = RPCIN_SETRETVALS(data, "Unable to set guest handler", FALSE);
892
goto exitWithXDRCleanup;
895
* Write the final result into the result out parameters and return!
899
data->freeResult = FALSE;
903
VMX_XDR_FREE(xdr_GHISetGuestHandler, &setGuestHandlerMsg);
910
*----------------------------------------------------------------------------
912
* GHITcloRestoreDefaultGuestHandler --
914
* RPC handler for 'ghi.guest.handler.restoreDefault'. Changes the nominated
915
* handlerType back to the value in use prior to any changes by tools.
918
* TRUE if everything is successful.
924
*----------------------------------------------------------------------------
928
GHITcloRestoreDefaultGuestHandler(RpcInData *data) // IN/OUT
933
/* Check our arguments. */
942
if (!data->name || !data->args) {
943
Debug("%s: Invalid arguments.\n", __FUNCTION__);
944
return RPCIN_SETRETVALS(data, "Invalid arguments.", FALSE);
947
Debug("%s name:%s args length: %"FMTSZ"u\n", __FUNCTION__, data->name, data->argsSize);
950
* Build an XDR Stream from the argument data which beings are args + 1
951
* since there is a space separator between the RPC name and the XDR serialization.
953
xdrmem_create(&xdrs, (char *) data->args + 1, data->argsSize - 1, XDR_DECODE);
955
GHIRestoreDefaultGuestHandler restoreMsg;
956
GHIRestoreDefaultGuestHandlerV1 *restoreV1Ptr = NULL;
958
memset(&restoreMsg, 0, sizeof restoreMsg);
959
if (!xdr_GHIRestoreDefaultGuestHandler(&xdrs, &restoreMsg)) {
960
Debug("%s: Unable to deserialize data\n", __FUNCTION__);
961
ret = RPCIN_SETRETVALS(data, "Unable to deserialize data", FALSE);
965
ASSERT(restoreMsg.ver == GHI_SET_GUEST_HANDLER_V1);
966
restoreV1Ptr = restoreMsg.GHIRestoreDefaultGuestHandler_u.defaultHandlerV1;
968
ret = GHI_RestoreDefaultGuestHandler(restoreV1Ptr->suffix,
969
restoreV1Ptr->mimetype,
972
Debug("%s: Unable to restore guest handler\n", __FUNCTION__);
973
ret = RPCIN_SETRETVALS(data, "Unable to restore guest handler", FALSE);
977
* Write the final result into the result out parameters and return!
981
data->freeResult = FALSE;
986
VMX_XDR_FREE(xdr_GHIRestoreDefaultGuestHandler, &restoreMsg);
992
*----------------------------------------------------------------------------
994
* GHILaunchMenuChangeRPC --
996
* Informs host that one or more Launch Menu changes have been detected.
1005
*----------------------------------------------------------------------------
1009
GHILaunchMenuChangeRPC(int numFolderKeys, // IN
1010
const char **folderKeysChanged) // IN
1012
/* +1 for the space separator */
1013
char request[sizeof GHI_RPC_LAUNCHMENU_CHANGE + 1];
1015
GHIStartMenuChanged startMenuChanged;
1016
GHIStartMenuChangedV1 smcv1;
1020
* Note: The primary contents of the startMenuChanged - the folder keys,
1021
* are allocated and tracked outside of this function, there's no need to call
1022
* VMX_XDR_FREE here for the XDR contents, in fact if called it will delete memory
1023
* from other parts of the system.
1026
memset(&startMenuChanged, 0, sizeof startMenuChanged);
1027
memset(&smcv1, 0, sizeof smcv1);
1029
ASSERT_MEM_ALLOC(DynXdr_Create(&xdrs));
1031
smcv1.keys.keys_len = numFolderKeys;
1032
smcv1.keys.keys_val = (char **) folderKeysChanged;
1034
startMenuChanged.ver = GHI_STARTMENU_CHANGED_V1;
1035
startMenuChanged.GHIStartMenuChanged_u.ghiStartMenuChangedV1 = &smcv1;
1037
Str_Sprintf(request,
1040
GHI_RPC_LAUNCHMENU_CHANGE);
1042
/* Write preamble and serialized changed folder keys to XDR stream. */
1043
if (!DynXdr_AppendRaw(&xdrs, request, strlen(request)) ||
1044
!xdr_GHIStartMenuChanged(&xdrs, &startMenuChanged)) {
1045
Debug("%s: could not serialize protocol handler info\n", __FUNCTION__);
1046
DynXdr_Destroy(&xdrs, TRUE);
1050
status = RpcOut_SendOneRaw(DynXdr_Get(&xdrs),
1054
DynXdr_Destroy(&xdrs, TRUE);
1057
Debug("%s: could not send unity launchmenu change\n", __FUNCTION__);
1064
*----------------------------------------------------------------------------
1066
* GHITcloSetOutlookTempFolder --
1068
* Handler for the 'ghi.guest.outlook.set.tempFolder' RPC.
1071
* If the RPC fails, return FALSE. Otherwise, returns TRUE.
1076
*----------------------------------------------------------------------------
1080
GHITcloSetOutlookTempFolder(RpcInData *data) // IN/OUT: RPC data
1085
Debug("%s: Enter.\n", __FUNCTION__);
1087
/* Check our arguments. */
1096
if (!data->name || !data->args) {
1097
Debug("%s: Invalid arguments.\n", __FUNCTION__);
1098
return RPCIN_SETRETVALS(data, "Invalid arguments.", FALSE);
1101
Debug("%s: Got RPC, name: \"%s\", argument length: %"FMTSZ"u.\n",
1102
__FUNCTION__, data->name, data->argsSize);
1105
* Build an XDR stream from the argument data.
1107
* Note that the argument data begins with args + 1 since there is a space
1108
* between the RPC name and the XDR serialization.
1110
xdrmem_create(&xdrs, (char*) data->args + 1, data->argsSize - 1, XDR_DECODE);
1112
/* Deserialize the XDR into a GHISetOutlookTempFolder struct. */
1113
GHISetOutlookTempFolder folderMsg;
1114
GHISetOutlookTempFolderV1 *folderV1Ptr = NULL;
1116
memset(&folderMsg, 0, sizeof folderMsg);
1117
if (!xdr_GHISetOutlookTempFolder(&xdrs, &folderMsg)) {
1118
Debug("%s: Unable to deserialize data\n", __FUNCTION__);
1119
ret = RPCIN_SETRETVALS(data, "Unable to deserialize data", FALSE);
1124
* Get the structure for v1 of the GHISetOutlookTempFolder XDR from the union
1125
* in the GHISetOutlookTempFolder struct.
1127
ASSERT(folderMsg.ver == GHI_SET_OUTLOOK_TEMP_FOLDER_V1);
1128
folderV1Ptr = folderMsg.GHISetOutlookTempFolder_u.setOutlookTempFolderV1;
1130
// Call the platform implementation of our RPC.
1131
ret = GHI_SetOutlookTempFolder(folderV1Ptr->targetURI);
1133
Debug("%s: Failed to set Outlook temporary folder.\n", __FUNCTION__);
1134
ret = RPCIN_SETRETVALS(data, "Failed to set Outlook temporary folder", FALSE);
1139
* We don't have any out parameters, so we write empty values into the
1140
* result fields of the RpcInData structure.
1142
RPCIN_SETRETVALS(data, "", FALSE);
1144
// Set our return value and return to the caller.
1148
// Destroy the XDR stream.
1150
VMX_XDR_FREE(xdr_GHISetOutlookTempFolder, &folderMsg);
1151
Debug("%s: Exit.\n", __FUNCTION__);
1157
*----------------------------------------------------------------------------
1159
* GHITcloRestoreOutlookTempFolder --
1161
* Handler for the 'ghi.guest.outlook.restore.tempFolder' RPC.
1164
* If the RPC fails, return FALSE. Otherwise, returns TRUE.
1169
*----------------------------------------------------------------------------
1173
GHITcloRestoreOutlookTempFolder(RpcInData *data) // IN/OUT: RPC data
1177
Debug("%s: Enter.\n", __FUNCTION__);
1180
* XXX: This RPC is no longer used/required - the RPC handler is left here
1181
* for compatibility with older hosts.
1185
* We don't have any out parameters, so we write empty values into the
1186
* result fields of the RpcInData structure.
1188
RPCIN_SETRETVALS(data, "", FALSE);
1190
// Set our return value and return to the caller.
1193
Debug("%s: Exit.\n", __FUNCTION__);
1199
*-----------------------------------------------------------------------------
1201
* GHITcloTrayIconSendEvent --
1203
* Send a mouse or keyboard event to a tray icon.
1206
* TRUE on success, FALSE on failure.
1211
*-----------------------------------------------------------------------------
1215
GHITcloTrayIconSendEvent(RpcInData *data) // IN/OUT: XXX
1218
GHITrayIconEventV1 *v1ptr = NULL;
1219
GHITrayIconEvent eventMsg;
1221
memset(&eventMsg, 0, sizeof eventMsg);
1222
Debug("%s: Enter.\n", __FUNCTION__);
1224
/* Check our arguments. */
1227
ASSERT(data->argsSize > 0);
1229
if (!(data && data->name && data->argsSize > 0)) {
1230
Debug("%s: Invalid arguments.\n", __FUNCTION__);
1234
Debug("%s: Got RPC, name: \"%s\", argument length: %"FMTSZ"u.\n",
1235
__FUNCTION__, data->name, data->argsSize);
1238
* Deserialize the XDR data. Note that the data begins with args + 1 since
1239
* there is a space between the RPC name and the XDR serialization.
1241
if (!XdrUtil_Deserialize((char *)data->args + 1, data->argsSize - 1,
1242
(void *)xdr_GHITrayIconEvent, &eventMsg)) {
1243
Debug("%s: Failed to deserialize data\n", __FUNCTION__);
1244
ret = RPCIN_SETRETVALS(data, "Failed to deserialize data.", FALSE);
1247
ASSERT(eventMsg.ver == GHI_TRAY_ICON_EVENT_V1);
1248
v1ptr = eventMsg.GHITrayIconEvent_u.trayIconEventV1;
1250
/* Call the platform implementation of our RPC. */
1251
ret = GHI_TrayIconSendEvent(v1ptr->iconID,
1257
Debug("%s: RPC failed.\n", __FUNCTION__);
1258
RPCIN_SETRETVALS(data, "RPC failed", FALSE);
1261
* We don't have any out parameters, so we write empty values into the
1262
* result fields of the RpcInData structure.
1264
RPCIN_SETRETVALS(data, "", TRUE);
1266
/* Set our return value and return to the caller. */
1271
VMX_XDR_FREE(xdr_GHITrayIconEvent, &eventMsg);
1272
Debug("%s: Exit.\n", __FUNCTION__);
1278
*-----------------------------------------------------------------------------
1280
* GHITclOTrayIconStartUpdates --
1282
* Start sending tray icon updates to the VMX.
1285
* TRUE on success, FALSE on failure.
1290
*-----------------------------------------------------------------------------
1294
GHITcloTrayIconStartUpdates(RpcInData *data) // IN/OUT: XXX
1298
Debug("%s: Enter.\n", __FUNCTION__);
1300
/* Check our arguments. */
1304
if (!(data && data->name)) {
1305
Debug("%s: Invalid arguments.\n", __FUNCTION__);
1309
Debug("%s: Got RPC, name: \"%s\", argument length: %"FMTSZ"u.\n",
1310
__FUNCTION__, data->name, data->argsSize);
1312
if (!GHI_TrayIconStartUpdates()) {
1313
Debug("%s: Failed to start tray icon updates.\n", __FUNCTION__);
1314
RPCIN_SETRETVALS(data, "Failed to start tray icon updates", FALSE);
1319
* Write the result into the RPC out parameters.
1321
ret = RPCIN_SETRETVALS(data, "", TRUE);
1324
Debug("%s: Exit.\n", __FUNCTION__);
1330
*-----------------------------------------------------------------------------
1332
* GHITcloTrayIconStopUpdates --
1334
* Stop sending tray icon updates to the VMX.
1337
* TRUE on success, FALSE on failure.
1342
*-----------------------------------------------------------------------------
1346
GHITcloTrayIconStopUpdates(RpcInData *data) // IN/OUT:
1350
Debug("%s: Enter.\n", __FUNCTION__);
1352
/* Check our arguments. */
1356
if (!(data && data->name)) {
1357
Debug("%s: Invalid arguments.\n", __FUNCTION__);
1361
Debug("%s: Got RPC, name: \"%s\", argument length: %"FMTSZ"u.\n",
1362
__FUNCTION__, data->name, data->argsSize);
1364
if (!GHI_TrayIconStopUpdates()) {
1365
Debug("%s: Failed to start tray icon updates.\n", __FUNCTION__);
1366
RPCIN_SETRETVALS(data, "Failed to start tray icon updates", FALSE);
1371
* Write the result into the RPC out parameters.
1373
ret = RPCIN_SETRETVALS(data, "", TRUE);
1381
*-----------------------------------------------------------------------------
1383
* GHISendTrayIconUpdateRPC --
1385
* Send the ghi.guest.trayIcon.update RPC to the host.
1388
* TRUE if sent, FALSE otherwise.
1393
*-----------------------------------------------------------------------------
1397
GHISendTrayIconUpdateRpc(XDR *xdrs) // XXX
1402
Debug("%s: Enter.\n", __FUNCTION__);
1404
/* Check our arguments. */
1407
Debug("%s: Invalid parameter.\n", __FUNCTION__);
1411
/* Append our RPC name and a space to the DynBuf. */
1412
DynBuf_Init(&outBuf);
1413
if (!DynBuf_Append(&outBuf,
1414
GHI_RPC_TRAY_ICON_UPDATE,
1415
strlen(GHI_RPC_TRAY_ICON_UPDATE))) {
1416
Debug("%s: Failed to append RPC name to DynBuf.\n", __FUNCTION__);
1420
if (!DynBuf_Append(&outBuf, " ", 1)) {
1421
Debug("%s: Failed to append space to DynBuf.\n", __FUNCTION__);
1425
/* Append the XDR serialized data to the DynBuf. */
1426
if (!DynBuf_Append(&outBuf, DynXdr_Get(xdrs), xdr_getpos(xdrs)) )
1428
Debug("%s: Failed to append XDR serialized data to DynBuf.\n",
1433
if (!RpcOut_SendOneRaw(DynBuf_Get(&outBuf),
1434
DynBuf_GetSize(&outBuf),
1437
Debug("%s: Failed to send RPC to host!\n", __FUNCTION__);
1444
DynBuf_Destroy(&outBuf);
1445
Debug("%s: Exit.\n", __FUNCTION__);
1451
*-----------------------------------------------------------------------------
1453
* GHITcloSetFocusedWindow --
1455
* Set the specified window to be focused (NULL or zero window ID indicates
1456
* that no window should be focused).
1459
* TRUE on success, FALSE otherwise.
1464
*-----------------------------------------------------------------------------
1468
GHITcloSetFocusedWindow(RpcInData *data)
1473
Debug("%s: Enter.\n", __FUNCTION__);
1475
/* Check our arguments. */
1479
if (!(data && data->name)) {
1480
Debug("%s: Invalid arguments.\n", __FUNCTION__);
1484
Debug("%s: Got RPC, name: \"%s\", argument length: %"FMTSZ"u.\n",
1485
__FUNCTION__, data->name, data->argsSize);
1488
* Build an XDR stream from the argument data.
1490
* Note that the argument data begins with args + 1 since there is a space
1491
* between the RPC name and the XDR serialization.
1493
xdrmem_create(&xdrs, (char*) data->args + 1, data->argsSize - 1, XDR_DECODE);
1495
GHISetFocusedWindow setFocusedWindowMsg;
1496
GHISetFocusedWindowV1 *setFocusedWindowV1Ptr;
1498
memset(&setFocusedWindowMsg, 0, sizeof setFocusedWindowMsg);
1499
if (!xdr_GHISetFocusedWindow((XDR *)&xdrs, &setFocusedWindowMsg)) {
1500
goto exitWithXDRCleanup;
1503
ASSERT(setFocusedWindowMsg.ver == GHI_SET_FOCUSED_WINDOW_V1);
1504
if (setFocusedWindowMsg.ver != GHI_SET_FOCUSED_WINDOW_V1) {
1505
Debug("%s: Unexpected XDR version = %d\n", __FUNCTION__, setFocusedWindowMsg.ver);
1506
ret = RPCIN_SETRETVALS(data,
1507
"Unexpected XDR version.",
1509
goto exitWithXDRCleanup;
1512
setFocusedWindowV1Ptr = setFocusedWindowMsg.GHISetFocusedWindow_u.setFocusedWindowV1;
1514
/* Call the platform implementation of our RPC. */
1515
ret = GHI_SetFocusedWindow(setFocusedWindowV1Ptr->windowId);
1518
* Write the result into the RPC out parameters.
1520
ret = RPCIN_SETRETVALS(data, "", TRUE);
1523
/* Destroy the XDR stream. */
1525
VMX_XDR_FREE(xdr_GHISetFocusedWindow, &setFocusedWindowMsg);
1532
*-----------------------------------------------------------------------------
1534
* GHITcloGetExecInfoHash --
1536
* Get the hash (or timestamp) of information returned by
1537
* GHITcloGetBinaryInfo.
1540
* TRUE on success, FALSE on failure.
1545
*-----------------------------------------------------------------------------
1549
GHITcloGetExecInfoHash(RpcInData *data) // IN/OUT:
1552
GHIGetExecInfoHashRequest requestMsg;
1553
GHIGetExecInfoHashReply replyMsg;
1555
GHIGetExecInfoHashRequestV1 *requestV1;
1556
GHIGetExecInfoHashReplyV1 replyV1;
1557
char *execHash = NULL;
1559
memset(&requestMsg, 0, sizeof requestMsg);
1560
memset(&replyMsg, 0, sizeof replyMsg);
1562
/* Check our arguments. */
1567
if (!(data && data->name && data->args)) {
1568
Debug("%s: Invalid arguments.\n", __FUNCTION__);
1569
ret = RPCIN_SETRETVALS(data, "Invalid arguments.", FALSE);
1573
Debug("%s: Got RPC, name: \"%s\", argument length: %"FMTSZ"u.\n",
1574
__FUNCTION__, data->name, data->argsSize);
1577
* Deserialize the XDR data. Note that the data begins with args + 1 since
1578
* there is a space between the RPC name and the XDR serialization.
1580
if (!XdrUtil_Deserialize((char *)data->args + 1, data->argsSize - 1,
1581
(void *)xdr_GHIGetExecInfoHashRequest, &requestMsg)) {
1582
Debug("%s: Failed to deserialize data\n", __FUNCTION__);
1583
ret = RPCIN_SETRETVALS(data, "Failed to deserialize data.", FALSE);
1587
ASSERT(requestMsg.ver == GHI_GET_EXEC_INFO_HASH_V1);
1588
if (requestMsg.ver != GHI_GET_EXEC_INFO_HASH_V1) {
1589
Debug("%s: Unexpected XDR version = %d\n", __FUNCTION__, requestMsg.ver);
1590
ret = RPCIN_SETRETVALS(data, "Unexpected XDR version.", FALSE);
1594
requestV1 = requestMsg.GHIGetExecInfoHashRequest_u.requestV1;
1597
* Call the platform implementation of the RPC handler.
1599
if (!GHI_GetExecInfoHash(requestV1->execPath, &execHash)) {
1600
ret = RPCIN_SETRETVALS(data, "Could not get executable info hash.", FALSE);
1604
replyV1.execHash = execHash;
1605
replyMsg.ver = GHI_GET_EXEC_INFO_HASH_V1;
1606
replyMsg.GHIGetExecInfoHashReply_u.replyV1 = &replyV1;
1609
* Serialize the result data and return.
1611
ASSERT_MEM_ALLOC(DynXdr_Create(&xdrs));
1613
if (!xdr_GHIGetExecInfoHashReply(&xdrs, &replyMsg)) {
1614
ret = RPCIN_SETRETVALS(data, "Failed to serialize data", FALSE);
1615
DynXdr_Destroy(&xdrs, TRUE);
1619
data->result = reinterpret_cast<char *>(DynXdr_Get(&xdrs));
1620
data->resultLen = xdr_getpos(&xdrs);
1621
data->freeResult = TRUE;
1624
* Destroy the serialized XDR structure but leave the data buffer alone
1625
* since it will be freed by the RpcIn layer.
1627
DynXdr_Destroy(&xdrs, FALSE);
1630
VMX_XDR_FREE(xdr_GHIGetExecInfoHashRequest, &requestMsg);
1632
/* Free the memory allocated in the platform layer for the hash */