aboutsummaryrefslogtreecommitdiffstats
path: root/unix/xserver/hw/vnc/vncExtInit.cc
diff options
context:
space:
mode:
authorAdam Tkac <atkac@redhat.com>2008-03-21 18:56:48 +0000
committerAdam Tkac <atkac@redhat.com>2008-03-21 18:56:48 +0000
commit4c0427ffb370b5020a6f82456106774b6711ddd4 (patch)
tree20e0eb1d073746e04d953b488618573de14abbf6 /unix/xserver/hw/vnc/vncExtInit.cc
parentbee114ae5e69b10e132c5d6d680045d9165e5a90 (diff)
downloadtigervnc-4c0427ffb370b5020a6f82456106774b6711ddd4.tar.gz
tigervnc-4c0427ffb370b5020a6f82456106774b6711ddd4.zip
- moved Xvnc sources to unix/xserver/hw/vnc directory to affect current X tree
- replaced unix/xc.patch by unix/xserver.patch - completely deleted unneded unix/xc subtree (sources are in unix/xserver/hw/vnc) git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/branches/1.5-xserver@2439 3789f03b-4d11-0410-bbf8-ca57d06f2519
Diffstat (limited to 'unix/xserver/hw/vnc/vncExtInit.cc')
-rw-r--r--unix/xserver/hw/vnc/vncExtInit.cc866
1 files changed, 866 insertions, 0 deletions
diff --git a/unix/xserver/hw/vnc/vncExtInit.cc b/unix/xserver/hw/vnc/vncExtInit.cc
new file mode 100644
index 00000000..9cf9d21b
--- /dev/null
+++ b/unix/xserver/hw/vnc/vncExtInit.cc
@@ -0,0 +1,866 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+#include <stdio.h>
+
+extern "C" {
+#define class c_class
+#define NEED_EVENTS
+#include "X.h"
+#include "Xproto.h"
+#include "misc.h"
+#include "os.h"
+#include "dixstruct.h"
+#include "extnsionst.h"
+#include "scrnintstr.h"
+#include "selection.h"
+#define _VNCEXT_SERVER_
+#define _VNCEXT_PROTO_
+#include "vncExt.h"
+#undef class
+#undef xalloc
+}
+
+#include <rfb/Configuration.h>
+#include <rfb/Logger_stdio.h>
+#include <rfb/LogWriter.h>
+#include <rfb/util.h>
+#include <rfb/ServerCore.h>
+#include <rfb/SSecurityFactoryStandard.h>
+#include <rdr/HexOutStream.h>
+#include <rfb/LogWriter.h>
+#undef max
+#undef min
+#include <network/TcpSocket.h>
+
+#include "XserverDesktop.h"
+#include "vncHooks.h"
+#include "vncExtInit.h"
+
+extern "C" {
+
+ extern void vncExtensionInit();
+ static void vncResetProc(ExtensionEntry* extEntry);
+ static void vncBlockHandler(pointer data, OSTimePtr t, pointer readmask);
+ static void vncWakeupHandler(pointer data, int nfds, pointer readmask);
+ static void vncClientStateChange(CallbackListPtr*, pointer, pointer);
+ static void SendSelectionChangeEvent(Atom selection);
+ static int ProcVncExtDispatch(ClientPtr client);
+ static int SProcVncExtDispatch(ClientPtr client);
+
+ extern char *display;
+
+ extern Selection *CurrentSelections;
+ extern int NumCurrentSelections;
+}
+
+using namespace rfb;
+
+static rfb::LogWriter vlog("vncext");
+
+static unsigned long vncExtGeneration = 0;
+static bool initialised = false;
+static XserverDesktop* desktop[MAXSCREENS] = { 0, };
+void* vncFbptr[MAXSCREENS] = { 0, };
+
+static char* clientCutText = 0;
+static int clientCutTextLen = 0;
+
+static XserverDesktop* queryConnectDesktop = 0;
+static void* queryConnectId = 0;
+static int queryConnectTimeout = 0;
+static OsTimerPtr queryConnectTimer = 0;
+
+static struct VncInputSelect* vncInputSelectHead = 0;
+struct VncInputSelect {
+ VncInputSelect(ClientPtr c, Window w, int m) : client(c), window(w), mask(m)
+ {
+ next = vncInputSelectHead;
+ vncInputSelectHead = this;
+ }
+ ClientPtr client;
+ Window window;
+ int mask;
+ VncInputSelect* next;
+};
+
+static int nPrevSelections = 0;
+static TimeStamp* prevSelectionTimes = 0;
+
+static int vncErrorBase = 0;
+static int vncEventBase = 0;
+static char* vncPasswdFile = 0;
+int vncInetdSock = -1;
+
+rfb::AliasParameter rfbauth("rfbauth", "Alias for PasswordFile",
+ &SSecurityFactoryStandard::vncAuthPasswdFile);
+rfb::StringParameter httpDir("httpd",
+ "Directory containing files to serve via HTTP",
+ "");
+rfb::IntParameter httpPort("httpPort", "TCP port to listen for HTTP",0);
+rfb::AliasParameter rfbwait("rfbwait", "Alias for ClientWaitTimeMillis",
+ &rfb::Server::clientWaitTimeMillis);
+rfb::IntParameter rfbport("rfbport", "TCP port to listen for RFB protocol",0);
+rfb::StringParameter desktopName("desktop", "Name of VNC desktop","x11");
+rfb::BoolParameter localhostOnly("localhost",
+ "Only allow connections from localhost",
+ false);
+
+void vncExtensionInit()
+{
+ if (vncExtGeneration == serverGeneration) {
+ vlog.error("vncExtensionInit: called twice in same generation?");
+ return;
+ }
+ vncExtGeneration = serverGeneration;
+
+ ExtensionEntry* extEntry
+ = AddExtension(VNCEXTNAME, VncExtNumberEvents, VncExtNumberErrors,
+ ProcVncExtDispatch, SProcVncExtDispatch, vncResetProc,
+ StandardMinorOpcode);
+ if (!extEntry) {
+ ErrorF("vncExtInit: AddExtension failed\n");
+ return;
+ }
+
+ vncErrorBase = extEntry->errorBase;
+ vncEventBase = extEntry->eventBase;
+
+ vlog.info("VNC extension running!");
+
+ if (!AddCallback(&ClientStateCallback, vncClientStateChange, 0)) {
+ FatalError("AddCallback failed\n");
+ }
+
+ try {
+ if (!initialised) {
+ rfb::initStdIOLoggers();
+ initialised = true;
+ }
+
+ for (int scr = 0; scr < screenInfo.numScreens; scr++) {
+
+ if (!desktop[scr]) {
+ network::TcpListener* listener = 0;
+ network::TcpListener* httpListener = 0;
+ if (scr == 0 && vncInetdSock != -1) {
+ if (network::TcpSocket::isSocket(vncInetdSock) &&
+ !network::TcpSocket::isConnected(vncInetdSock))
+ {
+ listener = new network::TcpListener(0, 0, vncInetdSock, true);
+ vlog.info("inetd wait");
+ }
+ } else {
+ int port = rfbport;
+ if (port == 0) port = 5900 + atoi(display);
+ port += 1000 * scr;
+ listener = new network::TcpListener(port, localhostOnly);
+ vlog.info("Listening for VNC connections on port %d",port);
+ CharArray httpDirStr(httpDir.getData());
+ if (httpDirStr.buf[0]) {
+ port = httpPort;
+ if (port == 0) port = 5800 + atoi(display);
+ port += 1000 * scr;
+ httpListener = new network::TcpListener(port, localhostOnly);
+ vlog.info("Listening for HTTP connections on port %d",port);
+ }
+ }
+
+ CharArray desktopNameStr(desktopName.getData());
+ desktop[scr] = new XserverDesktop(screenInfo.screens[scr], listener,
+ httpListener,
+ desktopNameStr.buf,
+ vncFbptr[scr]);
+ vlog.info("created VNC server for screen %d", scr);
+
+ if (scr == 0 && vncInetdSock != -1 && !listener) {
+ network::Socket* sock = new network::TcpSocket(vncInetdSock);
+ desktop[scr]->addClient(sock, false);
+ vlog.info("added inetd sock");
+ }
+
+ } else {
+ desktop[scr]->serverReset(screenInfo.screens[scr]);
+ }
+
+ vncHooksInit(screenInfo.screens[scr], desktop[scr]);
+ }
+
+ RegisterBlockAndWakeupHandlers(vncBlockHandler, vncWakeupHandler, 0);
+
+ } catch (rdr::Exception& e) {
+ vlog.error("vncExtInit: %s",e.str());
+ }
+}
+
+static void vncResetProc(ExtensionEntry* extEntry)
+{
+}
+
+//
+// vncBlockHandler - called just before the X server goes into select(). Call
+// on to the block handler for each desktop. Then check whether any of the
+// selections have changed, and if so, notify any interested X clients.
+//
+
+static void vncBlockHandler(pointer data, OSTimePtr timeout, pointer readmask)
+{
+ fd_set* fds = (fd_set*)readmask;
+
+ for (int scr = 0; scr < screenInfo.numScreens; scr++) {
+ if (desktop[scr]) {
+ desktop[scr]->blockHandler(fds);
+ }
+ }
+
+ if (nPrevSelections != NumCurrentSelections) {
+ prevSelectionTimes
+ = (TimeStamp*)xnfrealloc(prevSelectionTimes,
+ NumCurrentSelections * sizeof(TimeStamp));
+ for (int i = nPrevSelections; i < NumCurrentSelections; i++) {
+ prevSelectionTimes[i].months = 0;
+ prevSelectionTimes[i].milliseconds = 0;
+ }
+ nPrevSelections = NumCurrentSelections;
+ }
+ for (int i = 0; i < NumCurrentSelections; i++) {
+ if (CurrentSelections[i].lastTimeChanged.months
+ != prevSelectionTimes[i].months ||
+ CurrentSelections[i].lastTimeChanged.milliseconds
+ != prevSelectionTimes[i].milliseconds)
+ {
+ SendSelectionChangeEvent(CurrentSelections[i].selection);
+ prevSelectionTimes[i] = CurrentSelections[i].lastTimeChanged;
+ }
+ }
+}
+
+static void vncWakeupHandler(pointer data, int nfds, pointer readmask)
+{
+ fd_set* fds = (fd_set*)readmask;
+
+ for (int scr = 0; scr < screenInfo.numScreens; scr++) {
+ if (desktop[scr]) {
+ desktop[scr]->wakeupHandler(fds, nfds);
+ }
+ }
+}
+
+static void vncClientStateChange(CallbackListPtr*, pointer, pointer p)
+{
+ ClientPtr client = ((NewClientInfoRec*)p)->client;
+ if (client->clientState == ClientStateGone) {
+ VncInputSelect** nextPtr = &vncInputSelectHead;
+ for (VncInputSelect* cur = vncInputSelectHead; cur; cur = *nextPtr) {
+ if (cur->client == client) {
+ *nextPtr = cur->next;
+ delete cur;
+ continue;
+ }
+ nextPtr = &cur->next;
+ }
+ }
+}
+
+void vncBell()
+{
+ for (int scr = 0; scr < screenInfo.numScreens; scr++) {
+ if (desktop[scr]) {
+ desktop[scr]->bell();
+ }
+ }
+}
+
+void vncClientGone(int fd)
+{
+ if (fd == vncInetdSock) {
+ fprintf(stderr,"inetdSock client gone\n");
+ GiveUp(0);
+ }
+}
+
+void vncClientCutText(const char* str, int len)
+{
+ delete [] clientCutText;
+ clientCutText = new char[len];
+ memcpy(clientCutText, str, len);
+ clientCutTextLen = len;
+ xVncExtClientCutTextNotifyEvent ev;
+ ev.type = vncEventBase + VncExtClientCutTextNotify;
+ for (VncInputSelect* cur = vncInputSelectHead; cur; cur = cur->next) {
+ if (cur->mask & VncExtClientCutTextMask) {
+ ev.sequenceNumber = cur->client->sequence;
+ ev.window = cur->window;
+ ev.time = GetTimeInMillis();
+ if (cur->client->swapped) {
+ int n;
+ swaps(&ev.sequenceNumber, n);
+ swapl(&ev.window, n);
+ swapl(&ev.time, n);
+ }
+ WriteToClient(cur->client, sizeof(xVncExtClientCutTextNotifyEvent),
+ (char *)&ev);
+ }
+ }
+}
+
+
+static CARD32 queryConnectTimerCallback(OsTimerPtr timer,
+ CARD32 now, pointer arg)
+{
+ if (queryConnectTimeout)
+ queryConnectDesktop->approveConnection(queryConnectId, false, "The attempt to prompt the user to accept the connection failed");
+ // Re-notify clients, causing them to discover that we're done
+ vncQueryConnect(queryConnectDesktop, queryConnectId);
+ return 0;
+}
+
+void vncQueryConnect(XserverDesktop* desktop, void* opaqueId)
+{
+ // Only one query can be processed at any one time
+ if (queryConnectTimeout && ((desktop != queryConnectDesktop) ||
+ (opaqueId != queryConnectId))) {
+ desktop->approveConnection(opaqueId, false,
+ "Another connection is currently being queried.");
+ return;
+ }
+
+ // Get the query timeout. If it's zero, there is no query.
+ queryConnectTimeout = desktop->getQueryTimeout(opaqueId);
+ queryConnectId = queryConnectTimeout ? opaqueId : 0;
+ queryConnectDesktop = queryConnectTimeout ? desktop : 0;
+
+ // Notify clients
+ bool notified = false;
+ xVncExtQueryConnectNotifyEvent ev;
+ ev.type = vncEventBase + VncExtQueryConnectNotify;
+ for (VncInputSelect* cur = vncInputSelectHead; cur; cur = cur->next) {
+ if (cur->mask & VncExtQueryConnectMask) {
+ ev.sequenceNumber = cur->client->sequence;
+ ev.window = cur->window;
+ if (cur->client->swapped) {
+ int n;
+ swaps(&ev.sequenceNumber, n);
+ swapl(&ev.window, n);
+ }
+ WriteToClient(cur->client, sizeof(xVncExtQueryConnectNotifyEvent),
+ (char *)&ev);
+ notified = true;
+ }
+ }
+
+ // If we're being asked to query a connection (rather than to cancel
+ // a query), and haven't been able to notify clients then reject it.
+ if (queryConnectTimeout && !notified) {
+ queryConnectTimeout = 0;
+ queryConnectId = 0;
+ queryConnectDesktop = 0;
+ desktop->approveConnection(opaqueId, false,
+ "Unable to query the local user to accept the connection.");
+ return;
+ }
+
+ // Set a timer so that if no-one ever responds, we will eventually
+ // reject the connection
+ // NB: We don't set a timer if sock is null, since that indicates
+ // that pending queries should be cancelled.
+ if (queryConnectDesktop)
+ queryConnectTimer = TimerSet(queryConnectTimer, 0,
+ queryConnectTimeout*2000,
+ queryConnectTimerCallback, 0);
+ else
+ TimerCancel(queryConnectTimer);
+}
+
+static void SendSelectionChangeEvent(Atom selection)
+{
+ xVncExtSelectionChangeNotifyEvent ev;
+ ev.type = vncEventBase + VncExtSelectionChangeNotify;
+ for (VncInputSelect* cur = vncInputSelectHead; cur; cur = cur->next) {
+ if (cur->mask & VncExtSelectionChangeMask) {
+ ev.sequenceNumber = cur->client->sequence;
+ ev.window = cur->window;
+ ev.selection = selection;
+ if (cur->client->swapped) {
+ int n;
+ swaps(&ev.sequenceNumber, n);
+ swapl(&ev.window, n);
+ swapl(&ev.selection, n);
+ }
+ WriteToClient(cur->client, sizeof(xVncExtSelectionChangeNotifyEvent),
+ (char *)&ev);
+ }
+ }
+}
+
+static int ProcVncExtSetParam(ClientPtr client)
+{
+ REQUEST(xVncExtSetParamReq);
+ REQUEST_FIXED_SIZE(xVncExtSetParamReq, stuff->paramLen);
+ CharArray param(stuff->paramLen+1);
+ strncpy(param.buf, (char*)&stuff[1], stuff->paramLen);
+ param.buf[stuff->paramLen] = 0;
+
+ xVncExtSetParamReply rep;
+ int n;
+ rep.type = X_Reply;
+ rep.length = 0;
+ rep.sequenceNumber = client->sequence;
+ rep.success = rfb::Configuration::setParam(param.buf);
+ if (client->swapped) {
+ swaps(&rep.sequenceNumber, n);
+ swapl(&rep.length, n);
+ }
+ WriteToClient(client, sizeof(xVncExtSetParamReply), (char *)&rep);
+ return (client->noClientException);
+}
+
+static int SProcVncExtSetParam(ClientPtr client)
+{
+ register char n;
+ REQUEST(xVncExtSetParamReq);
+ swaps(&stuff->length, n);
+ REQUEST_AT_LEAST_SIZE(xVncExtSetParamReq);
+ return ProcVncExtSetParam(client);
+}
+
+static int ProcVncExtGetParam(ClientPtr client)
+{
+ REQUEST(xVncExtGetParamReq);
+ REQUEST_FIXED_SIZE(xVncExtGetParamReq, stuff->paramLen);
+ CharArray param(stuff->paramLen+1);
+ strncpy(param.buf, (char*)&stuff[1], stuff->paramLen);
+ param.buf[stuff->paramLen] = 0;
+
+ xVncExtGetParamReply rep;
+ int n;
+ rep.type = X_Reply;
+ rep.sequenceNumber = client->sequence;
+ rep.success = 0;
+ int len = 0;
+ char* value = 0;
+ rfb::VoidParameter* p = rfb::Configuration::getParam(param.buf);
+ // Hack to avoid exposing password!
+ if (strcasecmp(param.buf, "Password") == 0)
+ p = 0;
+ if (p) {
+ value = p->getValueStr();
+ rep.success = 1;
+ len = value ? strlen(value) : 0;
+ }
+ rep.length = (len + 3) >> 2;
+ rep.valueLen = len;
+ if (client->swapped) {
+ swaps(&rep.sequenceNumber, n);
+ swapl(&rep.length, n);
+ swaps(&rep.valueLen, n);
+ }
+ WriteToClient(client, sizeof(xVncExtGetParamReply), (char *)&rep);
+ if (value)
+ WriteToClient(client, len, value);
+ delete [] value;
+ return (client->noClientException);
+}
+
+static int SProcVncExtGetParam(ClientPtr client)
+{
+ register char n;
+ REQUEST(xVncExtGetParamReq);
+ swaps(&stuff->length, n);
+ REQUEST_AT_LEAST_SIZE(xVncExtGetParamReq);
+ return ProcVncExtGetParam(client);
+}
+
+static int ProcVncExtGetParamDesc(ClientPtr client)
+{
+ REQUEST(xVncExtGetParamDescReq);
+ REQUEST_FIXED_SIZE(xVncExtGetParamDescReq, stuff->paramLen);
+ CharArray param(stuff->paramLen+1);
+ strncpy(param.buf, (char*)&stuff[1], stuff->paramLen);
+ param.buf[stuff->paramLen] = 0;
+
+ xVncExtGetParamDescReply rep;
+ int n;
+ rep.type = X_Reply;
+ rep.sequenceNumber = client->sequence;
+ rep.success = 0;
+ int len = 0;
+ const char* desc = 0;
+ rfb::VoidParameter* p = rfb::Configuration::getParam(param.buf);
+ if (p) {
+ desc = p->getDescription();
+ rep.success = 1;
+ len = desc ? strlen(desc) : 0;
+ }
+ rep.length = (len + 3) >> 2;
+ rep.descLen = len;
+ if (client->swapped) {
+ swaps(&rep.sequenceNumber, n);
+ swapl(&rep.length, n);
+ swaps(&rep.descLen, n);
+ }
+ WriteToClient(client, sizeof(xVncExtGetParamDescReply), (char *)&rep);
+ if (desc)
+ WriteToClient(client, len, (char*)desc);
+ return (client->noClientException);
+}
+
+static int SProcVncExtGetParamDesc(ClientPtr client)
+{
+ register char n;
+ REQUEST(xVncExtGetParamDescReq);
+ swaps(&stuff->length, n);
+ REQUEST_AT_LEAST_SIZE(xVncExtGetParamDescReq);
+ return ProcVncExtGetParamDesc(client);
+}
+
+static int ProcVncExtListParams(ClientPtr client)
+{
+ REQUEST(xVncExtListParamsReq);
+ REQUEST_SIZE_MATCH(xVncExtListParamsReq);
+
+ xVncExtListParamsReply rep;
+ int n;
+ rep.type = X_Reply;
+ rep.sequenceNumber = client->sequence;
+
+ int nParams = 0;
+ int len = 0;
+ for (ParameterIterator i(Configuration::global()); i.param; i.next()) {
+ int l = strlen(i.param->getName());
+ if (l <= 255) {
+ nParams++;
+ len += l + 1;
+ }
+ }
+ rep.length = (len + 3) >> 2;
+ rep.nParams = nParams;
+ if (client->swapped) {
+ swaps(&rep.sequenceNumber, n);
+ swapl(&rep.length, n);
+ swaps(&rep.nParams, n);
+ }
+ WriteToClient(client, sizeof(xVncExtListParamsReply), (char *)&rep);
+ rdr::U8* data = new rdr::U8[len];
+ rdr::U8* ptr = data;
+ for (ParameterIterator i(Configuration::global()); i.param; i.next()) {
+ int l = strlen(i.param->getName());
+ if (l <= 255) {
+ *ptr++ = l;
+ memcpy(ptr, i.param->getName(), l);
+ ptr += l;
+ }
+ }
+ WriteToClient(client, len, (char*)data);
+ delete [] data;
+ return (client->noClientException);
+}
+
+static int SProcVncExtListParams(ClientPtr client)
+{
+ register char n;
+ REQUEST(xVncExtListParamsReq);
+ swaps(&stuff->length, n);
+ REQUEST_SIZE_MATCH(xVncExtListParamsReq);
+ return ProcVncExtListParams(client);
+}
+
+static int ProcVncExtSetServerCutText(ClientPtr client)
+{
+ REQUEST(xVncExtSetServerCutTextReq);
+ REQUEST_FIXED_SIZE(xVncExtSetServerCutTextReq, stuff->textLen);
+ char* str = new char[stuff->textLen+1];
+ strncpy(str, (char*)&stuff[1], stuff->textLen);
+ str[stuff->textLen] = 0;
+ for (int scr = 0; scr < screenInfo.numScreens; scr++) {
+ if (desktop[scr]) {
+ desktop[scr]->serverCutText(str, stuff->textLen);
+ }
+ }
+ delete [] str;
+ return (client->noClientException);
+}
+
+static int SProcVncExtSetServerCutText(ClientPtr client)
+{
+ register char n;
+ REQUEST(xVncExtSetServerCutTextReq);
+ swaps(&stuff->length, n);
+ REQUEST_AT_LEAST_SIZE(xVncExtSetServerCutTextReq);
+ swapl(&stuff->textLen, n);
+ return ProcVncExtSetServerCutText(client);
+}
+
+static int ProcVncExtGetClientCutText(ClientPtr client)
+{
+ REQUEST(xVncExtGetClientCutTextReq);
+ REQUEST_SIZE_MATCH(xVncExtGetClientCutTextReq);
+
+ xVncExtGetClientCutTextReply rep;
+ int n;
+ rep.type = X_Reply;
+ rep.length = (clientCutTextLen + 3) >> 2;
+ rep.sequenceNumber = client->sequence;
+ rep.textLen = clientCutTextLen;
+ if (client->swapped) {
+ swaps(&rep.sequenceNumber, n);
+ swapl(&rep.length, n);
+ swapl(&rep.textLen, n);
+ }
+ WriteToClient(client, sizeof(xVncExtGetClientCutTextReply), (char *)&rep);
+ if (clientCutText)
+ WriteToClient(client, clientCutTextLen, clientCutText);
+ return (client->noClientException);
+}
+
+static int SProcVncExtGetClientCutText(ClientPtr client)
+{
+ register char n;
+ REQUEST(xVncExtGetClientCutTextReq);
+ swaps(&stuff->length, n);
+ REQUEST_SIZE_MATCH(xVncExtGetClientCutTextReq);
+ return ProcVncExtGetClientCutText(client);
+}
+
+static int ProcVncExtSelectInput(ClientPtr client)
+{
+ REQUEST(xVncExtSelectInputReq);
+ REQUEST_SIZE_MATCH(xVncExtSelectInputReq);
+ VncInputSelect** nextPtr = &vncInputSelectHead;
+ VncInputSelect* cur;
+ for (cur = vncInputSelectHead; cur; cur = *nextPtr) {
+ if (cur->client == client && cur->window == stuff->window) {
+ cur->mask = stuff->mask;
+ if (!cur->mask) {
+ *nextPtr = cur->next;
+ delete cur;
+ }
+ break;
+ }
+ nextPtr = &cur->next;
+ }
+ if (!cur) {
+ cur = new VncInputSelect(client, stuff->window, stuff->mask);
+ }
+ return (client->noClientException);
+}
+
+static int SProcVncExtSelectInput(ClientPtr client)
+{
+ register char n;
+ REQUEST(xVncExtSelectInputReq);
+ swaps(&stuff->length, n);
+ REQUEST_SIZE_MATCH(xVncExtSelectInputReq);
+ swapl(&stuff->window, n);
+ swapl(&stuff->mask, n);
+ return ProcVncExtSelectInput(client);
+}
+
+static int ProcVncExtConnect(ClientPtr client)
+{
+ REQUEST(xVncExtConnectReq);
+ REQUEST_FIXED_SIZE(xVncExtConnectReq, stuff->strLen);
+ CharArray str(stuff->strLen+1);
+ strncpy(str.buf, (char*)&stuff[1], stuff->strLen);
+ str.buf[stuff->strLen] = 0;
+
+ xVncExtConnectReply rep;
+ rep.success = 0;
+ if (desktop[0]) {
+ if (stuff->strLen == 0) {
+ try {
+ desktop[0]->disconnectClients();
+ rep.success = 1;
+ } catch (rdr::Exception& e) {
+ vlog.error("Disconnecting all clients: %s",e.str());
+ }
+ } else {
+ int port = 5500;
+ for (int i = 0; i < stuff->strLen; i++) {
+ if (str.buf[i] == ':') {
+ port = atoi(&str.buf[i+1]);
+ str.buf[i] = 0;
+ break;
+ }
+ }
+
+ try {
+ network::Socket* sock = new network::TcpSocket(str.buf, port);
+ desktop[0]->addClient(sock, true);
+ rep.success = 1;
+ } catch (rdr::Exception& e) {
+ vlog.error("Reverse connection: %s",e.str());
+ }
+ }
+ }
+
+ rep.type = X_Reply;
+ rep.length = 0;
+ rep.sequenceNumber = client->sequence;
+ if (client->swapped) {
+ int n;
+ swaps(&rep.sequenceNumber, n);
+ swapl(&rep.length, n);
+ }
+ WriteToClient(client, sizeof(xVncExtConnectReply), (char *)&rep);
+ return (client->noClientException);
+}
+
+static int SProcVncExtConnect(ClientPtr client)
+{
+ register char n;
+ REQUEST(xVncExtConnectReq);
+ swaps(&stuff->length, n);
+ REQUEST_AT_LEAST_SIZE(xVncExtConnectReq);
+ return ProcVncExtConnect(client);
+}
+
+
+static int ProcVncExtGetQueryConnect(ClientPtr client)
+{
+ REQUEST(xVncExtGetQueryConnectReq);
+ REQUEST_SIZE_MATCH(xVncExtGetQueryConnectReq);
+
+ const char *qcAddress=0, *qcUsername=0;
+ int qcTimeout;
+ if (queryConnectDesktop)
+ qcTimeout = queryConnectDesktop->getQueryTimeout(queryConnectId,
+ &qcAddress, &qcUsername);
+ else
+ qcTimeout = 0;
+
+ xVncExtGetQueryConnectReply rep;
+ int n;
+ rep.type = X_Reply;
+ rep.sequenceNumber = client->sequence;
+ rep.timeout = qcTimeout;
+ rep.addrLen = qcTimeout ? strlen(qcAddress) : 0;
+ rep.userLen = qcTimeout ? strlen(qcUsername) : 0;
+ rep.opaqueId = (CARD32)queryConnectId;
+ rep.length = (rep.userLen + rep.addrLen + 3) >> 2;
+ if (client->swapped) {
+ swaps(&rep.sequenceNumber, n);
+ swapl(&rep.userLen, n);
+ swapl(&rep.addrLen, n);
+ swapl(&rep.timeout, n);
+ swapl(&rep.opaqueId, n);
+ }
+ WriteToClient(client, sizeof(xVncExtGetQueryConnectReply), (char *)&rep);
+ if (qcTimeout)
+ WriteToClient(client, strlen(qcAddress), (char*)qcAddress);
+ if (qcTimeout)
+ WriteToClient(client, strlen(qcUsername), (char*)qcUsername);
+ return (client->noClientException);
+}
+
+static int SProcVncExtGetQueryConnect(ClientPtr client)
+{
+ register char n;
+ REQUEST(xVncExtGetQueryConnectReq);
+ swaps(&stuff->length, n);
+ REQUEST_SIZE_MATCH(xVncExtGetQueryConnectReq);
+ return ProcVncExtGetQueryConnect(client);
+}
+
+
+static int ProcVncExtApproveConnect(ClientPtr client)
+{
+ REQUEST(xVncExtApproveConnectReq);
+ REQUEST_SIZE_MATCH(xVncExtApproveConnectReq);
+ if (queryConnectId == (void*)stuff->opaqueId) {
+ for (int scr = 0; scr < screenInfo.numScreens; scr++) {
+ if (desktop[scr]) {
+ desktop[scr]->approveConnection(queryConnectId, stuff->approve,
+ "Connection rejected by local user");
+ }
+ }
+ // Inform other clients of the event and tidy up
+ vncQueryConnect(queryConnectDesktop, queryConnectId);
+ }
+ return (client->noClientException);
+}
+
+static int SProcVncExtApproveConnect(ClientPtr client)
+{
+ register char n;
+ REQUEST(xVncExtApproveConnectReq);
+ swaps(&stuff->length, n);
+ swapl(&stuff->opaqueId, n);
+ REQUEST_SIZE_MATCH(xVncExtApproveConnectReq);
+ return ProcVncExtApproveConnect(client);
+}
+
+
+static int ProcVncExtDispatch(ClientPtr client)
+{
+ REQUEST(xReq);
+ switch (stuff->data) {
+ case X_VncExtSetParam:
+ return ProcVncExtSetParam(client);
+ case X_VncExtGetParam:
+ return ProcVncExtGetParam(client);
+ case X_VncExtGetParamDesc:
+ return ProcVncExtGetParamDesc(client);
+ case X_VncExtListParams:
+ return ProcVncExtListParams(client);
+ case X_VncExtSetServerCutText:
+ return ProcVncExtSetServerCutText(client);
+ case X_VncExtGetClientCutText:
+ return ProcVncExtGetClientCutText(client);
+ case X_VncExtSelectInput:
+ return ProcVncExtSelectInput(client);
+ case X_VncExtConnect:
+ return ProcVncExtConnect(client);
+ case X_VncExtGetQueryConnect:
+ return ProcVncExtGetQueryConnect(client);
+ case X_VncExtApproveConnect:
+ return ProcVncExtApproveConnect(client);
+ default:
+ return BadRequest;
+ }
+}
+
+static int SProcVncExtDispatch(ClientPtr client)
+{
+ REQUEST(xReq);
+ switch (stuff->data) {
+ case X_VncExtSetParam:
+ return SProcVncExtSetParam(client);
+ case X_VncExtGetParam:
+ return SProcVncExtGetParam(client);
+ case X_VncExtGetParamDesc:
+ return SProcVncExtGetParamDesc(client);
+ case X_VncExtListParams:
+ return SProcVncExtListParams(client);
+ case X_VncExtSetServerCutText:
+ return SProcVncExtSetServerCutText(client);
+ case X_VncExtGetClientCutText:
+ return SProcVncExtGetClientCutText(client);
+ case X_VncExtSelectInput:
+ return SProcVncExtSelectInput(client);
+ case X_VncExtConnect:
+ return SProcVncExtConnect(client);
+ case X_VncExtGetQueryConnect:
+ return SProcVncExtGetQueryConnect(client);
+ case X_VncExtApproveConnect:
+ return SProcVncExtApproveConnect(client);
+ default:
+ return BadRequest;
+ }
+}
+