blob: 9cf9d21b82d272a418b1e6fa3bcc5d65dfee3c5c [file] [log] [blame]
/* 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;
}
}