/* 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. */ #ifdef HAVE_DIX_CONFIG_H #include #endif #include extern "C" { #define class c_class #define NEED_EVENTS #include #include #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 #include #include #include #include #include #include #include #undef max #undef min #include #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); static void vncSelectionCallback(CallbackListPtr *callbacks, pointer data, pointer args); extern char *display; } 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, }; int vncFbstride[MAXSCREENS]; 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 vncErrorBase = 0; static int vncEventBase = 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); static PixelFormat vncGetPixelFormat(ScreenPtr pScreen) { int depth, bpp; int trueColour, bigEndian; int redShift, greenShift, blueShift; int redMax, greenMax, blueMax; int i; VisualPtr vis = NULL; depth = pScreen->rootDepth; for (i = 0; i < screenInfo.numPixmapFormats; i++) { if (screenInfo.formats[i].depth == depth) { bpp = screenInfo.formats[i].bitsPerPixel; break; } } if (i == screenInfo.numPixmapFormats) { fprintf(stderr,"no pixmap format for root depth???\n"); abort(); } bigEndian = (screenInfo.imageByteOrder == MSBFirst); for (i = 0; i < pScreen->numVisuals; i++) { if (pScreen->visuals[i].vid == pScreen->rootVisual) { vis = &pScreen->visuals[i]; break; } } if (i == pScreen->numVisuals) { fprintf(stderr,"no visual rec for root visual???\n"); abort(); } trueColour = (vis->c_class == TrueColor); if (!trueColour && bpp != 8) throw rfb::Exception("X server uses unsupported visual"); redShift = ffs(vis->redMask) - 1; greenShift = ffs(vis->greenMask) - 1; blueShift = ffs(vis->blueMask) - 1; redMax = vis->redMask >> redShift; greenMax = vis->greenMask >> greenShift; blueMax = vis->blueMask >> blueShift; return PixelFormat(bpp, depth, bigEndian, trueColour, redMax, greenMax, blueMax, redShift, greenShift, blueShift); } 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("Add ClientStateCallback failed\n"); } if (!AddCallback(&SelectionCallback, vncSelectionCallback, 0)) { FatalError("Add SelectionCallback 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()); PixelFormat pf = vncGetPixelFormat(screenInfo.screens[scr]); desktop[scr] = new XserverDesktop(screenInfo.screens[scr], listener, httpListener, desktopNameStr.buf, pf, vncFbptr[scr], vncFbstride[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) { } static void vncSelectionCallback(CallbackListPtr *callbacks, pointer data, pointer args) { SelectionInfoRec *info = (SelectionInfoRec *) args; Selection *selection = info->selection; SendSelectionChangeEvent(selection->selection); } // // 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); } 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; // Retrieve desktop name before setting char* value1 = 0; rfb::VoidParameter* desktop1 = rfb::Configuration::getParam("desktop"); if (desktop1) value1 = desktop1->getValueStr(); rep.success = rfb::Configuration::setParam(param.buf); // Send DesktopName update if desktop name has been changed char* value2 = 0; rfb::VoidParameter* desktop2 = rfb::Configuration::getParam("desktop"); if (desktop2) value2 = desktop2->getValueStr(); if (value1 && value2 && strcmp(value1, value2)) { for (int scr = 0; scr < screenInfo.numScreens; scr++) { if (desktop[scr]) { desktop[scr]->setDesktopName(value2); } } } if (value1) delete [] value1; if (value2) delete [] value2; 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)(long)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; } }