#define HasGcc3 YES
#endif
+#define HasFreetype2 NO
#define BuildVNCExt YES
#define VNCExtDefines -DVNCEXT
#define SiteExtensionDefines VNCExtDefines
-.TH Xvnc 1 "30 December 2004" "TightVNC" "Virtual Network Computing"
+.TH Xvnc 1 "17 Apr 2006" "TightVNC" "Virtual Network Computing"
.SH NAME
Xvnc \- the X VNC server
.SH SYNOPSIS
The number of seconds after which an idle VNC connection will be dropped
(default is 0, which means that idle connections will never be dropped).
+.TP
+.B \-QueryConnect
+Prompts the user of the desktop to explicitly accept or reject incoming
+connections. This is most useful when using the vnc.so module or
+\fBx0vncserver\fP(1) program to access an existing X desktop via VNC.
+
+The \fBvncconfig\fP(1) program must be running on the desktop in order for
+QueryConnect to be supported by the \fBvnc.so\fP(1) module or
+\fBXvnc\fP(1) program. The \fBx0vncserver\fP(1) program does not require
+\fBvncconfig\fP(1) to be running.
+
.TP
.B \-localhost
Only allow connections from the same machine. Useful if you use SSH and want to
specific source file if you know the name of its "LogWriter". Default is
\fB*:stderr:30\fP.
+.TP
+.B \-RemapKeys \fImapping
+Sets up a keyboard mapping.
+.I mapping
+is a comma-separated string of character mappings, each of the form
+.IR char -> char ,
+or
+.IR char <> char ,
+where
+.I char
+is a hexadecimal keysym. For example, to exchange the " and @ symbols you would specify the following:
+.IP "" 10
+RemapKeys=0x22<>0x40
+
.SH USAGE WITH INETD
By configuring the \fBinetd\fP(1) service appropriately, Xvnc can be launched
on demand when a connection comes in, rather than having to be started
-/* Copyright (C) 2002-2003 RealVNC Ltd. All Rights Reserved.
- *
+/* 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
// automatically freeing them in the destructor. It also fixes a problem with
// REGION_INIT when given an empty rectangle.
+// REGION_NULL was introduced in the Xorg tree as the way to initialise an
+// empty region. If it's not already defined do it the old way. Note that the
+// old way causes a segfault in the new tree...
+#ifndef REGION_NULL
+#define REGION_NULL(pScreen,pReg) REGION_INIT(pScreen,pReg,NullBox,0)
+#endif
+
class RegionHelper {
public:
void init(BoxPtr rect, int size) {
reg = ®Rec;
- if (!rect || (rect->x2 == rect->x1 || rect->y2 == rect->y1)) {
+ if (!rect || (rect && (rect->x2 == rect->x1 || rect->y2 == rect->y1))) {
REGION_NULL(pScreen, reg);
} else {
REGION_INIT(pScreen, reg, rect, size);
-/* Copyright (C) 2002-2004 RealVNC Ltd. All Rights Reserved.
- *
+/* 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
rfb::BoolParameter alwaysSetDeferUpdateTimer("AlwaysSetDeferUpdateTimer",
"Always reset the defer update timer on every change",false);
+IntParameter queryConnectTimeout("QueryConnectTimeout",
+ "Number of seconds to show the Accept Connection dialog before "
+ "rejecting the connection",
+ 10);
+
static KeyCode KeysymToKeycode(KeySymsPtr keymap, KeySym ks, int* col);
static rdr::U8 reverseBits[] = {
};
-class MyHTTPServer : public rfb::HTTPServer {
+class FileHTTPServer : public rfb::HTTPServer {
public:
- MyHTTPServer(XserverDesktop* d) : desktop(d) {}
- virtual ~MyHTTPServer() {}
+ FileHTTPServer(XserverDesktop* d) : desktop(d) {}
+ virtual ~FileHTTPServer() {}
- virtual rdr::InStream* getFile(const char* name, const char** contentType) {
+ virtual rdr::InStream* getFile(const char* name, const char** contentType,
+ int* contentLength, time_t* lastModified)
+ {
if (name[0] != '/' || strstr(name, "..") != 0) {
vlog.info("http request was for invalid file name");
return 0;
sprintf(fname.buf, "%s%s", httpDirStr.buf, name);
int fd = open(fname.buf, O_RDONLY);
if (fd < 0) return 0;
-
rdr::InStream* is = new rdr::FdInStream(fd, -1, 0, true);
*contentType = guessContentType(name, *contentType);
if (strlen(name) > 4 && strcasecmp(&name[strlen(name)-4], ".vnc") == 0) {
is = new rdr::SubstitutingInStream(is, desktop, 20);
*contentType = "text/html";
+ } else {
+ struct stat st;
+ if (fstat(fd, &st) == 0) {
+ *contentLength = st.st_size;
+ *lastModified = st.st_mtime;
+ }
}
return is;
}
listener(listener_), httpListener(httpListener_),
cmap(0), deferredUpdateTimerSet(false),
grabbing(false), ignoreHooks_(false), directFbptr(fbptr != 0),
- oldButtonMask(0), cursorX(0), cursorY(0),
- oldCursorX(0), oldCursorY(0)
+ oldButtonMask(0),
+ queryConnectId(0)
{
int i;
format.depth = pScreen->rootDepth;
server = new VNCServerST(name, this);
server->setPixelBuffer(this);
+ server->setQueryConnectionHandler(this);
if (httpListener)
- httpServer = new MyHTTPServer(this);
+ httpServer = new FileHTTPServer(this);
}
XserverDesktop::~XserverDesktop()
return 0;
}
+rfb::VNCServerST::queryResult
+XserverDesktop::queryConnection(network::Socket* sock,
+ const char* userName,
+ char** reason) {
+ if (queryConnectId) {
+ *reason = strDup("Another connection is currently being queried.");
+ return rfb::VNCServerST::REJECT;
+ }
+ queryConnectAddress.replaceBuf(sock->getPeerAddress());
+ if (!userName)
+ userName = "(anonymous)";
+ queryConnectUsername.replaceBuf(strDup(userName));
+ queryConnectId = sock;
+ vncQueryConnect(this, sock);
+ return rfb::VNCServerST::PENDING;
+}
+
+
void XserverDesktop::setColormap(ColormapPtr cmap_)
{
if (cmap != cmap_) {
}
server->setCursor(cursor->bits->width, cursor->bits->height,
- cursor->bits->xhot, cursor->bits->yhot,
+ Point(cursor->bits->xhot, cursor->bits->yhot),
cursorData, cursorMask);
server->tryUpdate();
delete [] cursorData;
return 0;
}
+void XserverDesktop::deferUpdate()
+{
+ if (deferUpdateTime != 0) {
+ if (!deferredUpdateTimerSet || alwaysSetDeferUpdateTimer) {
+ deferredUpdateTimerSet = true;
+ deferredUpdateTimer = TimerSet(deferredUpdateTimer, 0,
+ deferUpdateTime,
+ deferredUpdateTimerCallback, this);
+ }
+ } else {
+ server->tryUpdate();
+ }
+}
+
void XserverDesktop::add_changed(RegionPtr reg)
{
if (ignoreHooks_) return;
REGION_NUM_RECTS(reg),
(ShortRect*)REGION_RECTS(reg));
server->add_changed(rfbReg);
- if (!deferredUpdateTimerSet || alwaysSetDeferUpdateTimer) {
- deferredUpdateTimer = TimerSet(deferredUpdateTimer, 0,
- deferUpdateTime,
- deferredUpdateTimerCallback, this);
- deferredUpdateTimerSet = true;
- }
+ deferUpdate();
} catch (rdr::Exception& e) {
vlog.error("XserverDesktop::add_changed: %s",e.str());
}
REGION_NUM_RECTS(dst),
(ShortRect*)REGION_RECTS(dst));
server->add_copied(rfbReg, rfb::Point(dx, dy));
- if (!deferredUpdateTimerSet || alwaysSetDeferUpdateTimer) {
- deferredUpdateTimer = TimerSet(deferredUpdateTimer, 0,
- deferUpdateTime,
- deferredUpdateTimerCallback, this);
- deferredUpdateTimerSet = true;
- }
+ deferUpdate();
} catch (rdr::Exception& e) {
vlog.error("XserverDesktop::add_copied: %s",e.str());
}
void XserverDesktop::positionCursor()
{
- if (cursorX != oldCursorX || cursorY != oldCursorY) {
- oldCursorX = cursorX;
- oldCursorY = cursorY;
- (*pScreen->SetCursorPosition) (pScreen, cursorX, cursorY, FALSE);
- server->setCursorPos(cursorX, cursorY);
+ if (!cursorPos.equals(oldCursorPos)) {
+ oldCursorPos = cursorPos;
+ (*pScreen->SetCursorPosition) (pScreen, cursorPos.x, cursorPos.y, FALSE);
+ server->setCursorPos(cursorPos);
server->tryUpdate();
}
}
if (screenWithCursor == pScreen) {
int x, y;
GetSpritePosition(&x, &y);
- if (x != cursorX || y != cursorY) {
- cursorX = oldCursorX = x;
- cursorY = oldCursorY = y;
- server->setCursorPos(x, y);
+ if (x != cursorPos.x || y != cursorPos.y) {
+ cursorPos = oldCursorPos = Point(x, y);
+ server->setCursorPos(cursorPos);
server->tryUpdate();
}
}
server->getSockets(&sockets);
std::list<Socket*>::iterator i;
for (i = sockets.begin(); i != sockets.end(); i++) {
- FD_SET((*i)->getFd(), fds);
+ int fd = (*i)->getFd();
+ if ((*i)->isShutdown()) {
+ vlog.debug("client gone, sock %d",fd);
+ server->removeSocket(*i);
+ vncClientGone(fd);
+ delete (*i);
+ } else {
+ FD_SET(fd, fds);
+ }
}
if (httpServer) {
httpServer->getSockets(&sockets);
for (i = sockets.begin(); i != sockets.end(); i++) {
- FD_SET((*i)->getFd(), fds);
+ int fd = (*i)->getFd();
+ if ((*i)->isShutdown()) {
+ vlog.debug("http client gone, sock %d",fd);
+ httpServer->removeSocket(*i);
+ delete (*i);
+ } else {
+ FD_SET(fd, fds);
+ }
}
}
} catch (rdr::Exception& e) {
if (FD_ISSET(listener->getFd(), fds)) {
FD_CLR(listener->getFd(), fds);
Socket* sock = listener->accept();
- server->addClient(sock);
+ server->addSocket(sock);
vlog.debug("new client, sock %d",sock->getFd());
}
}
if (FD_ISSET(httpListener->getFd(), fds)) {
FD_CLR(httpListener->getFd(), fds);
Socket* sock = httpListener->accept();
- httpServer->addClient(sock);
+ httpServer->addSocket(sock);
vlog.debug("new http client, sock %d",sock->getFd());
}
}
int fd = (*i)->getFd();
if (FD_ISSET(fd, fds)) {
FD_CLR(fd, fds);
- if (!server->processSocketEvent(*i)) {
- vlog.debug("client gone, sock %d",fd);
- vncClientGone(fd);
- }
+ server->processSocketEvent(*i);
}
}
int fd = (*i)->getFd();
if (FD_ISSET(fd, fds)) {
FD_CLR(fd, fds);
- if (!httpServer->processSocketEvent(*i)) {
- vlog.debug("http client gone, sock %d",fd);
- }
+ httpServer->processSocketEvent(*i);
}
}
}
void XserverDesktop::addClient(Socket* sock, bool reverse)
{
vlog.debug("new client, sock %d reverse %d",sock->getFd(),reverse);
- server->addClient(sock, reverse);
+ server->addSocket(sock, reverse);
}
void XserverDesktop::disconnectClients()
}
+int XserverDesktop::getQueryTimeout(void* opaqueId,
+ const char** address,
+ const char** username)
+{
+ if (opaqueId && queryConnectId == opaqueId) {
+ vlog.info("address=%s, username=%s, timeout=%d",
+ queryConnectAddress.buf, queryConnectUsername.buf,
+ (int)queryConnectTimeout);
+ if (address) *address = queryConnectAddress.buf;
+ if (username) *username = queryConnectUsername.buf;
+ return queryConnectTimeout;
+ }
+ return 0;
+}
+
+void XserverDesktop::approveConnection(void* opaqueId, bool accept,
+ const char* rejectMsg)
+{
+ if (queryConnectId == opaqueId) {
+ server->approveConnection((network::Socket*)opaqueId, accept, rejectMsg);
+ queryConnectId = 0;
+ }
+}
+
///////////////////////////////////////////////////////////////////////////
//
// SDesktop callbacks
-void XserverDesktop::pointerEvent(const Point& pos, rdr::U8 buttonMask)
+void XserverDesktop::pointerEvent(const Point& pos, int buttonMask)
{
xEvent ev;
DevicePtr dev = LookupPointerDevice();
ev.u.keyButtonPointer.rootY = pos.y;
ev.u.keyButtonPointer.time = GetTimeInMillis();
- if (pos.x != cursorX || pos.y != cursorY)
+ if (!pos.equals(cursorPos))
(*dev->processInputProc)(&ev, (DeviceIntPtr)dev, 1);
for (int i = 0; i < 5; i++) {
}
}
- cursorX = pos.x;
- cursorY = pos.y;
+ cursorPos = pos;
oldButtonMask = buttonMask;
}
void XserverDesktop::lookup(int index, int* r, int* g, int* b)
{
- EntryPtr pent;
- pent = (EntryPtr)&cmap->red[index];
- if (pent->fShared) {
- *r = pent->co.shco.red->color;
- *g = pent->co.shco.green->color;
- *b = pent->co.shco.blue->color;
+ if ((cmap->c_class | DynamicClass) == DirectColor) {
+ VisualPtr v = cmap->pVisual;
+ *r = cmap->red [(index & v->redMask ) >> v->offsetRed ].co.local.red;
+ *g = cmap->green[(index & v->greenMask) >> v->offsetGreen].co.local.green;
+ *b = cmap->blue [(index & v->blueMask ) >> v->offsetBlue ].co.local.blue;
} else {
- *r = pent->co.local.red;
- *g = pent->co.local.green;
- *b = pent->co.local.blue;
+ EntryPtr pent;
+ pent = (EntryPtr)&cmap->red[index];
+ if (pent->fShared) {
+ *r = pent->co.shco.red->color;
+ *g = pent->co.shco.green->color;
+ *b = pent->co.shco.blue->color;
+ } else {
+ *r = pent->co.local.red;
+ *g = pent->co.local.green;
+ *b = pent->co.local.blue;
+ }
}
}
-/* Copyright (C) 2002-2004 RealVNC Ltd. All Rights Reserved.
- *
+/* 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
#define __XSERVERDESKTOP_H__
#include <rfb/SDesktop.h>
+#include <rfb/HTTPServer.h>
#include <rfb/PixelBuffer.h>
#include <rfb/Configuration.h>
+#include <rfb/VNCServerST.h>
#include <rdr/SubstitutingInStream.h>
extern "C" {
}
namespace network { class TcpListener; class Socket; }
-class MyHTTPServer;
class XserverDesktop : public rfb::SDesktop, public rfb::FullFramePixelBuffer,
- public rfb::ColourMap, public rdr::Substitutor {
+ public rfb::ColourMap, public rdr::Substitutor,
+ public rfb::VNCServerST::QueryConnectionHandler {
public:
XserverDesktop(ScreenPtr pScreen, network::TcpListener* listener,
void addClient(network::Socket* sock, bool reverse);
void disconnectClients();
+ // QueryConnect methods called from X server code
+ // getQueryTimeout()
+ // Returns the timeout associated with a particular
+ // connection, identified by an opaque Id passed to the
+ // X code earlier. Also optionally gets the address and
+ // name associated with that connection.
+ // Returns zero if the Id is not recognised.
+ int getQueryTimeout(void* opaqueId,
+ const char** address=0,
+ const char** username=0);
+
+ // approveConnection()
+ // Used by X server code to supply the result of a query.
+ void approveConnection(void* opaqueId, bool accept,
+ const char* rejectMsg=0);
+
// rfb::SDesktop callbacks
- virtual void pointerEvent(const rfb::Point& pos, rdr::U8 buttonMask);
+ virtual void pointerEvent(const rfb::Point& pos, int buttonMask);
virtual void keyEvent(rdr::U32 key, bool down);
virtual void clientCutText(const char* str, int len);
virtual rfb::Point getFbSize() { return rfb::Point(width(), height()); }
// rdr::Substitutor callback
virtual char* substitute(const char* varName);
+ // rfb::VNCServerST::QueryConnectionHandler callback
+ virtual rfb::VNCServerST::queryResult queryConnection(network::Socket* sock,
+ const char* userName,
+ char** reason);
+
private:
void setColourMapEntries(int firstColour, int nColours);
static CARD32 deferredUpdateTimerCallback(OsTimerPtr timer, CARD32 now,
pointer arg);
+ void deferUpdate();
ScreenPtr pScreen;
OsTimerPtr deferredUpdateTimer, dummyTimer;
rfb::VNCServerST* server;
- MyHTTPServer* httpServer;
+ rfb::HTTPServer* httpServer;
network::TcpListener* listener;
network::TcpListener* httpListener;
ColormapPtr cmap;
bool ignoreHooks_;
bool directFbptr;
int oldButtonMask;
- int cursorX, cursorY, oldCursorX, oldCursorY;
+ rfb::Point cursorPos, oldCursorPos;
+
+ void* queryConnectId;
+ rfb::CharArray queryConnectAddress;
+ rfb::CharArray queryConnectUsername;
};
#endif
VNCLIBS = VncExtLibs
VNCINCLUDE = -I$(VNCTOP) -I$(VNCTOP)/vncconfig_unix
+#if defined(XFree86Version) && XFree86Version < 4000
+ VNCDEFINES = -DNO_INIT_BACKING_STORE
+#endif
+
#define CplusplusSource
#include <Server.tmpl>
DEFINES = $(OS_DEFINES) $(SHMDEF) $(MMAPDEF) $(FB_DEFINES) \
$(VENDOR_STRING) $(VENDOR_RELEASE) $(STD_DEFINES) ServerOSDefines \
- -UXFree86LOADER
+ $(VNCDEFINES) -UXFree86LOADER
#ifdef XFree86Version
/*
* Make sure XINPUT, XF86VidTune, etc arent defined for the miinitext.o
* used by Xvnc
*/
-EXT_DEFINES = ExtensionDefines -UXINPUT -UXF86VIDMODE -UXFreeXDGA -UXF86MISC
+EXT_DEFINES = ExtensionDefines -UXF86VIDMODE -UXFreeXDGA -UXF86MISC
#endif
SpecialCplusplusObjectRule(xvnc,$(ICONFIGFILES) xvnc,$(EXT_DEFINES) $(NO_OPERATOR_NAMES))
LinkSourceFile(miinitext.c,$(SERVERSRC)/mi)
-SpecialCObjectRule(miinitext,$(ICONFIGFILES),$(EXT_DEFINES) $(PAN_DEFINES) -DNO_HW_ONLY_EXTS -DNO_MODULE_EXTS $(EXT_MODULE_DEFINES) -UXFree86LOADER)
+SpecialCObjectRule(miinitext,$(ICONFIGFILES),$(EXT_DEFINES) $(PAN_DEFINES) -DNO_MODULE_EXTS $(EXT_MODULE_DEFINES) -UXFree86LOADER)
/* InstallManPage(Xvfb,$(MANDIR)) */
DependTarget()
-/* Copyright (C) 2002-2003 RealVNC Ltd. All Rights Reserved.
- *
+/* 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
-/* Copyright (C) 2002-2004 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.
- */
-
-/*
-
-Copyright (c) 1993 X Consortium
+/* Copyright (c) 1993 X Consortium
+ Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
#undef and
}
-#define XVNCVERSION "4.0"
+#define XVNCVERSION "Free Edition 4.1.1"
+#define XVNCCOPYRIGHT ("Copyright (C) 2002-2005 RealVNC Ltd.\n" \
+ "See http://www.realvnc.com for information on VNC.\n")
+
extern char *display;
extern int monitorResolution;
else return 32;
}
+
extern "C" {
-void
-ddxGiveUp()
-{
+
+ /* ddxInitGlobals - called by |InitGlobals| from os/util.c in XOrg */
+ void ddxInitGlobals(void)
+ {
+ }
+
+ void ddxGiveUp()
+ {
int i;
/* clean up the framebuffers */
void
ddxUseMsg()
{
- ErrorF("\nXvnc version %s - built %s\n", XVNCVERSION, buildtime);
+ ErrorF("\nXvnc %s - built %s\n%s", XVNCVERSION, buildtime, XVNCCOPYRIGHT);
ErrorF("Underlying X server release %d, %s\n\n", VENDOR_RELEASE,
VENDOR_STRING);
ErrorF("-screen scrn WxHxD set screen's width, height, depth\n");
pvfb->closeScreen = pScreen->CloseScreen;
pScreen->CloseScreen = vfbCloseScreen;
- return ret;
+#ifndef NO_INIT_BACKING_STORE
+ miInitializeBackingStore(pScreen);
+ pScreen->backingStoreSupport = Always;
+#endif
+
+ return ret;
} /* end vfbScreenInit */
void
InitOutput(ScreenInfo *screenInfo, int argc, char **argv)
{
- ErrorF("\nXvnc version %s - built %s\n", XVNCVERSION, buildtime);
- ErrorF("Underlying X server release %d, %s\n\n", VENDOR_RELEASE,
- VENDOR_STRING);
+ ErrorF("\nXvnc %s - built %s\n%s", XVNCVERSION, buildtime, XVNCCOPYRIGHT);
+ ErrorF("Underlying X server release %d, %s\n\n", VENDOR_RELEASE,
+ VENDOR_STRING);
int i;
int NumFormats = 0;
-/* Copyright (C) 2002-2004 RealVNC Ltd. All Rights Reserved.
- *
+/* 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
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)
static char* vncPasswdFile = 0;
int vncInetdSock = -1;
-rfb::VncAuthPasswdFileParameter vncAuthPasswdFile;
rfb::AliasParameter rfbauth("rfbauth", "Alias for PasswordFile",
- &vncAuthPasswdFile.param);
+ &SSecurityFactoryStandard::vncAuthPasswdFile);
rfb::StringParameter httpDir("httpd",
"Directory containing files to serve via HTTP",
"");
}
}
+
+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;
int nParams = 0;
int len = 0;
- rfb::VoidParameter* current = rfb::Configuration::head;
- while (current) {
- int l = strlen(current->getName());
+ for (ParameterIterator i(Configuration::global()); i.param; i.next()) {
+ int l = strlen(i.param->getName());
if (l <= 255) {
nParams++;
len += l + 1;
}
- current = current->_next;
}
rep.length = (len + 3) >> 2;
rep.nParams = nParams;
WriteToClient(client, sizeof(xVncExtListParamsReply), (char *)&rep);
rdr::U8* data = new rdr::U8[len];
rdr::U8* ptr = data;
- current = rfb::Configuration::head;
- while (current) {
- int l = strlen(current->getName());
+ for (ParameterIterator i(Configuration::global()); i.param; i.next()) {
+ int l = strlen(i.param->getName());
if (l <= 255) {
*ptr++ = l;
- memcpy(ptr, current->getName(), l);
+ memcpy(ptr, i.param->getName(), l);
ptr += l;
}
- current = current->_next;
}
WriteToClient(client, len, (char*)data);
delete [] data;
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);
return ProcVncExtSelectInput(client);
case X_VncExtConnect:
return ProcVncExtConnect(client);
+ case X_VncExtGetQueryConnect:
+ return ProcVncExtGetQueryConnect(client);
+ case X_VncExtApproveConnect:
+ return ProcVncExtApproveConnect(client);
default:
return BadRequest;
}
return SProcVncExtSelectInput(client);
case X_VncExtConnect:
return SProcVncExtConnect(client);
+ case X_VncExtGetQueryConnect:
+ return SProcVncExtGetQueryConnect(client);
+ case X_VncExtApproveConnect:
+ return SProcVncExtApproveConnect(client);
default:
return BadRequest;
}
-/* Copyright (C) 2002-2003 RealVNC Ltd. All Rights Reserved.
- *
+/* 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
#define __VNCEXTINIT_H__
#include <rfb/Configuration.h>
+#include "XserverDesktop.h"
extern void vncClientCutText(const char* str, int len);
+extern void vncQueryConnect(XserverDesktop* desktop, void* opaqueId);
extern void vncClientGone(int fd);
extern void vncBell();
extern void* vncFbptr[];
-/* Copyright (C) 2002-2003 RealVNC Ltd. All Rights Reserved.
- *
+/* 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
static void GetTextBoundingRect(DrawablePtr pDrawable, FontPtr font, int x,
int y, int nchars, BoxPtr box)
{
- int ascent = max(FONTASCENT(font), FONTMAXBOUNDS(font, ascent));
- int descent = max(FONTDESCENT(font), FONTMAXBOUNDS(font, descent));
- int charWidth = max(FONTMAXBOUNDS(font,rightSideBearing),
- FONTMAXBOUNDS(font,characterWidth));
+ int ascent = __rfbmax(FONTASCENT(font), FONTMAXBOUNDS(font, ascent));
+ int descent = __rfbmax(FONTDESCENT(font), FONTMAXBOUNDS(font, descent));
+ int charWidth = __rfbmax(FONTMAXBOUNDS(font,rightSideBearing),
+ FONTMAXBOUNDS(font,characterWidth));
box->x1 = pDrawable->x + x;
box->y1 = pDrawable->y + y - ascent;
-/* Copyright (C) 2002-2003 RealVNC Ltd. All Rights Reserved.
- *
+/* 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
-/* Copyright (C) 2002-2003 RealVNC Ltd. All Rights Reserved.
- *
+/* 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
#undef bool
#undef new
+using namespace rfb;
+
extern void vncExtensionInit();
static void vncExtensionInitWithParams(INITARGS);
for (int scr = 0; scr < screenInfo.numScreens; scr++) {
ScrnInfoPtr pScrn = xf86Screens[scr];
- rfb::VoidParameter* p;
- for (p = rfb::Configuration::head; p; p = p->_next) {
- char* val = xf86FindOptionValue(pScrn->options, p->getName());
+ for (ParameterIterator i(Configuration::global()); i.param; i.next()) {
+ char* val = xf86FindOptionValue(pScrn->options, i.param->getName());
if (val)
- p->setParam(val);
+ i.param->setParam(val);
}
}