blob: 9cf9d21b82d272a418b1e6fa3bcc5d65dfee3c5c [file] [log] [blame]
Constantin Kaplinsky95f6f7a2006-04-17 04:17:23 +00001/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
2 *
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +00003 * This is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This software is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this software; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
16 * USA.
17 */
18
19#include <stdio.h>
20
21extern "C" {
22#define class c_class
23#define NEED_EVENTS
24#include "X.h"
25#include "Xproto.h"
26#include "misc.h"
27#include "os.h"
28#include "dixstruct.h"
29#include "extnsionst.h"
30#include "scrnintstr.h"
31#include "selection.h"
32#define _VNCEXT_SERVER_
33#define _VNCEXT_PROTO_
34#include "vncExt.h"
35#undef class
36#undef xalloc
37}
38
39#include <rfb/Configuration.h>
40#include <rfb/Logger_stdio.h>
41#include <rfb/LogWriter.h>
42#include <rfb/util.h>
43#include <rfb/ServerCore.h>
44#include <rfb/SSecurityFactoryStandard.h>
45#include <rdr/HexOutStream.h>
46#include <rfb/LogWriter.h>
47#undef max
48#undef min
49#include <network/TcpSocket.h>
50
51#include "XserverDesktop.h"
52#include "vncHooks.h"
53#include "vncExtInit.h"
54
55extern "C" {
56
57 extern void vncExtensionInit();
58 static void vncResetProc(ExtensionEntry* extEntry);
59 static void vncBlockHandler(pointer data, OSTimePtr t, pointer readmask);
60 static void vncWakeupHandler(pointer data, int nfds, pointer readmask);
61 static void vncClientStateChange(CallbackListPtr*, pointer, pointer);
62 static void SendSelectionChangeEvent(Atom selection);
63 static int ProcVncExtDispatch(ClientPtr client);
64 static int SProcVncExtDispatch(ClientPtr client);
65
66 extern char *display;
67
68 extern Selection *CurrentSelections;
69 extern int NumCurrentSelections;
70}
71
72using namespace rfb;
73
74static rfb::LogWriter vlog("vncext");
75
76static unsigned long vncExtGeneration = 0;
77static bool initialised = false;
78static XserverDesktop* desktop[MAXSCREENS] = { 0, };
79void* vncFbptr[MAXSCREENS] = { 0, };
80
81static char* clientCutText = 0;
82static int clientCutTextLen = 0;
83
Constantin Kaplinsky95f6f7a2006-04-17 04:17:23 +000084static XserverDesktop* queryConnectDesktop = 0;
85static void* queryConnectId = 0;
86static int queryConnectTimeout = 0;
87static OsTimerPtr queryConnectTimer = 0;
88
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +000089static struct VncInputSelect* vncInputSelectHead = 0;
90struct VncInputSelect {
91 VncInputSelect(ClientPtr c, Window w, int m) : client(c), window(w), mask(m)
92 {
93 next = vncInputSelectHead;
94 vncInputSelectHead = this;
95 }
96 ClientPtr client;
97 Window window;
98 int mask;
99 VncInputSelect* next;
100};
101
102static int nPrevSelections = 0;
103static TimeStamp* prevSelectionTimes = 0;
104
105static int vncErrorBase = 0;
106static int vncEventBase = 0;
107static char* vncPasswdFile = 0;
108int vncInetdSock = -1;
109
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000110rfb::AliasParameter rfbauth("rfbauth", "Alias for PasswordFile",
Constantin Kaplinsky95f6f7a2006-04-17 04:17:23 +0000111 &SSecurityFactoryStandard::vncAuthPasswdFile);
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000112rfb::StringParameter httpDir("httpd",
113 "Directory containing files to serve via HTTP",
114 "");
115rfb::IntParameter httpPort("httpPort", "TCP port to listen for HTTP",0);
116rfb::AliasParameter rfbwait("rfbwait", "Alias for ClientWaitTimeMillis",
117 &rfb::Server::clientWaitTimeMillis);
118rfb::IntParameter rfbport("rfbport", "TCP port to listen for RFB protocol",0);
119rfb::StringParameter desktopName("desktop", "Name of VNC desktop","x11");
120rfb::BoolParameter localhostOnly("localhost",
121 "Only allow connections from localhost",
122 false);
123
124void vncExtensionInit()
125{
126 if (vncExtGeneration == serverGeneration) {
127 vlog.error("vncExtensionInit: called twice in same generation?");
128 return;
129 }
130 vncExtGeneration = serverGeneration;
131
132 ExtensionEntry* extEntry
133 = AddExtension(VNCEXTNAME, VncExtNumberEvents, VncExtNumberErrors,
134 ProcVncExtDispatch, SProcVncExtDispatch, vncResetProc,
135 StandardMinorOpcode);
136 if (!extEntry) {
137 ErrorF("vncExtInit: AddExtension failed\n");
138 return;
139 }
140
141 vncErrorBase = extEntry->errorBase;
142 vncEventBase = extEntry->eventBase;
143
144 vlog.info("VNC extension running!");
145
146 if (!AddCallback(&ClientStateCallback, vncClientStateChange, 0)) {
147 FatalError("AddCallback failed\n");
148 }
149
150 try {
151 if (!initialised) {
152 rfb::initStdIOLoggers();
153 initialised = true;
154 }
155
156 for (int scr = 0; scr < screenInfo.numScreens; scr++) {
157
158 if (!desktop[scr]) {
159 network::TcpListener* listener = 0;
160 network::TcpListener* httpListener = 0;
161 if (scr == 0 && vncInetdSock != -1) {
162 if (network::TcpSocket::isSocket(vncInetdSock) &&
163 !network::TcpSocket::isConnected(vncInetdSock))
164 {
165 listener = new network::TcpListener(0, 0, vncInetdSock, true);
166 vlog.info("inetd wait");
167 }
168 } else {
169 int port = rfbport;
170 if (port == 0) port = 5900 + atoi(display);
171 port += 1000 * scr;
172 listener = new network::TcpListener(port, localhostOnly);
173 vlog.info("Listening for VNC connections on port %d",port);
174 CharArray httpDirStr(httpDir.getData());
175 if (httpDirStr.buf[0]) {
176 port = httpPort;
177 if (port == 0) port = 5800 + atoi(display);
178 port += 1000 * scr;
179 httpListener = new network::TcpListener(port, localhostOnly);
180 vlog.info("Listening for HTTP connections on port %d",port);
181 }
182 }
183
184 CharArray desktopNameStr(desktopName.getData());
185 desktop[scr] = new XserverDesktop(screenInfo.screens[scr], listener,
186 httpListener,
187 desktopNameStr.buf,
188 vncFbptr[scr]);
189 vlog.info("created VNC server for screen %d", scr);
190
191 if (scr == 0 && vncInetdSock != -1 && !listener) {
192 network::Socket* sock = new network::TcpSocket(vncInetdSock);
193 desktop[scr]->addClient(sock, false);
194 vlog.info("added inetd sock");
195 }
196
197 } else {
198 desktop[scr]->serverReset(screenInfo.screens[scr]);
199 }
200
201 vncHooksInit(screenInfo.screens[scr], desktop[scr]);
202 }
203
204 RegisterBlockAndWakeupHandlers(vncBlockHandler, vncWakeupHandler, 0);
205
206 } catch (rdr::Exception& e) {
207 vlog.error("vncExtInit: %s",e.str());
208 }
209}
210
211static void vncResetProc(ExtensionEntry* extEntry)
212{
213}
214
215//
216// vncBlockHandler - called just before the X server goes into select(). Call
217// on to the block handler for each desktop. Then check whether any of the
218// selections have changed, and if so, notify any interested X clients.
219//
220
221static void vncBlockHandler(pointer data, OSTimePtr timeout, pointer readmask)
222{
223 fd_set* fds = (fd_set*)readmask;
224
225 for (int scr = 0; scr < screenInfo.numScreens; scr++) {
226 if (desktop[scr]) {
227 desktop[scr]->blockHandler(fds);
228 }
229 }
230
231 if (nPrevSelections != NumCurrentSelections) {
232 prevSelectionTimes
233 = (TimeStamp*)xnfrealloc(prevSelectionTimes,
234 NumCurrentSelections * sizeof(TimeStamp));
235 for (int i = nPrevSelections; i < NumCurrentSelections; i++) {
236 prevSelectionTimes[i].months = 0;
237 prevSelectionTimes[i].milliseconds = 0;
238 }
239 nPrevSelections = NumCurrentSelections;
240 }
241 for (int i = 0; i < NumCurrentSelections; i++) {
242 if (CurrentSelections[i].lastTimeChanged.months
243 != prevSelectionTimes[i].months ||
244 CurrentSelections[i].lastTimeChanged.milliseconds
245 != prevSelectionTimes[i].milliseconds)
246 {
247 SendSelectionChangeEvent(CurrentSelections[i].selection);
248 prevSelectionTimes[i] = CurrentSelections[i].lastTimeChanged;
249 }
250 }
251}
252
253static void vncWakeupHandler(pointer data, int nfds, pointer readmask)
254{
255 fd_set* fds = (fd_set*)readmask;
256
257 for (int scr = 0; scr < screenInfo.numScreens; scr++) {
258 if (desktop[scr]) {
259 desktop[scr]->wakeupHandler(fds, nfds);
260 }
261 }
262}
263
264static void vncClientStateChange(CallbackListPtr*, pointer, pointer p)
265{
266 ClientPtr client = ((NewClientInfoRec*)p)->client;
267 if (client->clientState == ClientStateGone) {
268 VncInputSelect** nextPtr = &vncInputSelectHead;
269 for (VncInputSelect* cur = vncInputSelectHead; cur; cur = *nextPtr) {
270 if (cur->client == client) {
271 *nextPtr = cur->next;
272 delete cur;
273 continue;
274 }
275 nextPtr = &cur->next;
276 }
277 }
278}
279
280void vncBell()
281{
282 for (int scr = 0; scr < screenInfo.numScreens; scr++) {
283 if (desktop[scr]) {
284 desktop[scr]->bell();
285 }
286 }
287}
288
289void vncClientGone(int fd)
290{
291 if (fd == vncInetdSock) {
292 fprintf(stderr,"inetdSock client gone\n");
293 GiveUp(0);
294 }
295}
296
297void vncClientCutText(const char* str, int len)
298{
299 delete [] clientCutText;
300 clientCutText = new char[len];
301 memcpy(clientCutText, str, len);
302 clientCutTextLen = len;
303 xVncExtClientCutTextNotifyEvent ev;
304 ev.type = vncEventBase + VncExtClientCutTextNotify;
305 for (VncInputSelect* cur = vncInputSelectHead; cur; cur = cur->next) {
306 if (cur->mask & VncExtClientCutTextMask) {
307 ev.sequenceNumber = cur->client->sequence;
308 ev.window = cur->window;
309 ev.time = GetTimeInMillis();
310 if (cur->client->swapped) {
311 int n;
312 swaps(&ev.sequenceNumber, n);
313 swapl(&ev.window, n);
314 swapl(&ev.time, n);
315 }
316 WriteToClient(cur->client, sizeof(xVncExtClientCutTextNotifyEvent),
317 (char *)&ev);
318 }
319 }
320}
321
Constantin Kaplinsky95f6f7a2006-04-17 04:17:23 +0000322
323static CARD32 queryConnectTimerCallback(OsTimerPtr timer,
324 CARD32 now, pointer arg)
325{
326 if (queryConnectTimeout)
327 queryConnectDesktop->approveConnection(queryConnectId, false, "The attempt to prompt the user to accept the connection failed");
328 // Re-notify clients, causing them to discover that we're done
329 vncQueryConnect(queryConnectDesktop, queryConnectId);
330 return 0;
331}
332
333void vncQueryConnect(XserverDesktop* desktop, void* opaqueId)
334{
335 // Only one query can be processed at any one time
336 if (queryConnectTimeout && ((desktop != queryConnectDesktop) ||
337 (opaqueId != queryConnectId))) {
338 desktop->approveConnection(opaqueId, false,
339 "Another connection is currently being queried.");
340 return;
341 }
342
343 // Get the query timeout. If it's zero, there is no query.
344 queryConnectTimeout = desktop->getQueryTimeout(opaqueId);
345 queryConnectId = queryConnectTimeout ? opaqueId : 0;
346 queryConnectDesktop = queryConnectTimeout ? desktop : 0;
347
348 // Notify clients
349 bool notified = false;
350 xVncExtQueryConnectNotifyEvent ev;
351 ev.type = vncEventBase + VncExtQueryConnectNotify;
352 for (VncInputSelect* cur = vncInputSelectHead; cur; cur = cur->next) {
353 if (cur->mask & VncExtQueryConnectMask) {
354 ev.sequenceNumber = cur->client->sequence;
355 ev.window = cur->window;
356 if (cur->client->swapped) {
357 int n;
358 swaps(&ev.sequenceNumber, n);
359 swapl(&ev.window, n);
360 }
361 WriteToClient(cur->client, sizeof(xVncExtQueryConnectNotifyEvent),
362 (char *)&ev);
363 notified = true;
364 }
365 }
366
367 // If we're being asked to query a connection (rather than to cancel
368 // a query), and haven't been able to notify clients then reject it.
369 if (queryConnectTimeout && !notified) {
370 queryConnectTimeout = 0;
371 queryConnectId = 0;
372 queryConnectDesktop = 0;
373 desktop->approveConnection(opaqueId, false,
374 "Unable to query the local user to accept the connection.");
375 return;
376 }
377
378 // Set a timer so that if no-one ever responds, we will eventually
379 // reject the connection
380 // NB: We don't set a timer if sock is null, since that indicates
381 // that pending queries should be cancelled.
382 if (queryConnectDesktop)
383 queryConnectTimer = TimerSet(queryConnectTimer, 0,
384 queryConnectTimeout*2000,
385 queryConnectTimerCallback, 0);
386 else
387 TimerCancel(queryConnectTimer);
388}
389
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000390static void SendSelectionChangeEvent(Atom selection)
391{
392 xVncExtSelectionChangeNotifyEvent ev;
393 ev.type = vncEventBase + VncExtSelectionChangeNotify;
394 for (VncInputSelect* cur = vncInputSelectHead; cur; cur = cur->next) {
395 if (cur->mask & VncExtSelectionChangeMask) {
396 ev.sequenceNumber = cur->client->sequence;
397 ev.window = cur->window;
398 ev.selection = selection;
399 if (cur->client->swapped) {
400 int n;
401 swaps(&ev.sequenceNumber, n);
402 swapl(&ev.window, n);
403 swapl(&ev.selection, n);
404 }
405 WriteToClient(cur->client, sizeof(xVncExtSelectionChangeNotifyEvent),
406 (char *)&ev);
407 }
408 }
409}
410
411static int ProcVncExtSetParam(ClientPtr client)
412{
413 REQUEST(xVncExtSetParamReq);
414 REQUEST_FIXED_SIZE(xVncExtSetParamReq, stuff->paramLen);
415 CharArray param(stuff->paramLen+1);
416 strncpy(param.buf, (char*)&stuff[1], stuff->paramLen);
417 param.buf[stuff->paramLen] = 0;
418
419 xVncExtSetParamReply rep;
420 int n;
421 rep.type = X_Reply;
422 rep.length = 0;
423 rep.sequenceNumber = client->sequence;
424 rep.success = rfb::Configuration::setParam(param.buf);
425 if (client->swapped) {
426 swaps(&rep.sequenceNumber, n);
427 swapl(&rep.length, n);
428 }
429 WriteToClient(client, sizeof(xVncExtSetParamReply), (char *)&rep);
430 return (client->noClientException);
431}
432
433static int SProcVncExtSetParam(ClientPtr client)
434{
435 register char n;
436 REQUEST(xVncExtSetParamReq);
437 swaps(&stuff->length, n);
438 REQUEST_AT_LEAST_SIZE(xVncExtSetParamReq);
439 return ProcVncExtSetParam(client);
440}
441
442static int ProcVncExtGetParam(ClientPtr client)
443{
444 REQUEST(xVncExtGetParamReq);
445 REQUEST_FIXED_SIZE(xVncExtGetParamReq, stuff->paramLen);
446 CharArray param(stuff->paramLen+1);
447 strncpy(param.buf, (char*)&stuff[1], stuff->paramLen);
448 param.buf[stuff->paramLen] = 0;
449
450 xVncExtGetParamReply rep;
451 int n;
452 rep.type = X_Reply;
453 rep.sequenceNumber = client->sequence;
454 rep.success = 0;
455 int len = 0;
456 char* value = 0;
457 rfb::VoidParameter* p = rfb::Configuration::getParam(param.buf);
458 // Hack to avoid exposing password!
459 if (strcasecmp(param.buf, "Password") == 0)
460 p = 0;
461 if (p) {
462 value = p->getValueStr();
463 rep.success = 1;
464 len = value ? strlen(value) : 0;
465 }
466 rep.length = (len + 3) >> 2;
467 rep.valueLen = len;
468 if (client->swapped) {
469 swaps(&rep.sequenceNumber, n);
470 swapl(&rep.length, n);
471 swaps(&rep.valueLen, n);
472 }
473 WriteToClient(client, sizeof(xVncExtGetParamReply), (char *)&rep);
474 if (value)
475 WriteToClient(client, len, value);
476 delete [] value;
477 return (client->noClientException);
478}
479
480static int SProcVncExtGetParam(ClientPtr client)
481{
482 register char n;
483 REQUEST(xVncExtGetParamReq);
484 swaps(&stuff->length, n);
485 REQUEST_AT_LEAST_SIZE(xVncExtGetParamReq);
486 return ProcVncExtGetParam(client);
487}
488
489static int ProcVncExtGetParamDesc(ClientPtr client)
490{
491 REQUEST(xVncExtGetParamDescReq);
492 REQUEST_FIXED_SIZE(xVncExtGetParamDescReq, stuff->paramLen);
493 CharArray param(stuff->paramLen+1);
494 strncpy(param.buf, (char*)&stuff[1], stuff->paramLen);
495 param.buf[stuff->paramLen] = 0;
496
497 xVncExtGetParamDescReply rep;
498 int n;
499 rep.type = X_Reply;
500 rep.sequenceNumber = client->sequence;
501 rep.success = 0;
502 int len = 0;
503 const char* desc = 0;
504 rfb::VoidParameter* p = rfb::Configuration::getParam(param.buf);
505 if (p) {
506 desc = p->getDescription();
507 rep.success = 1;
508 len = desc ? strlen(desc) : 0;
509 }
510 rep.length = (len + 3) >> 2;
511 rep.descLen = len;
512 if (client->swapped) {
513 swaps(&rep.sequenceNumber, n);
514 swapl(&rep.length, n);
515 swaps(&rep.descLen, n);
516 }
517 WriteToClient(client, sizeof(xVncExtGetParamDescReply), (char *)&rep);
518 if (desc)
519 WriteToClient(client, len, (char*)desc);
520 return (client->noClientException);
521}
522
523static int SProcVncExtGetParamDesc(ClientPtr client)
524{
525 register char n;
526 REQUEST(xVncExtGetParamDescReq);
527 swaps(&stuff->length, n);
528 REQUEST_AT_LEAST_SIZE(xVncExtGetParamDescReq);
529 return ProcVncExtGetParamDesc(client);
530}
531
532static int ProcVncExtListParams(ClientPtr client)
533{
534 REQUEST(xVncExtListParamsReq);
535 REQUEST_SIZE_MATCH(xVncExtListParamsReq);
536
537 xVncExtListParamsReply rep;
538 int n;
539 rep.type = X_Reply;
540 rep.sequenceNumber = client->sequence;
541
542 int nParams = 0;
543 int len = 0;
Constantin Kaplinsky95f6f7a2006-04-17 04:17:23 +0000544 for (ParameterIterator i(Configuration::global()); i.param; i.next()) {
545 int l = strlen(i.param->getName());
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000546 if (l <= 255) {
547 nParams++;
548 len += l + 1;
549 }
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000550 }
551 rep.length = (len + 3) >> 2;
552 rep.nParams = nParams;
553 if (client->swapped) {
554 swaps(&rep.sequenceNumber, n);
555 swapl(&rep.length, n);
556 swaps(&rep.nParams, n);
557 }
558 WriteToClient(client, sizeof(xVncExtListParamsReply), (char *)&rep);
559 rdr::U8* data = new rdr::U8[len];
560 rdr::U8* ptr = data;
Constantin Kaplinsky95f6f7a2006-04-17 04:17:23 +0000561 for (ParameterIterator i(Configuration::global()); i.param; i.next()) {
562 int l = strlen(i.param->getName());
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000563 if (l <= 255) {
564 *ptr++ = l;
Constantin Kaplinsky95f6f7a2006-04-17 04:17:23 +0000565 memcpy(ptr, i.param->getName(), l);
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000566 ptr += l;
567 }
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000568 }
569 WriteToClient(client, len, (char*)data);
570 delete [] data;
571 return (client->noClientException);
572}
573
574static int SProcVncExtListParams(ClientPtr client)
575{
576 register char n;
577 REQUEST(xVncExtListParamsReq);
578 swaps(&stuff->length, n);
579 REQUEST_SIZE_MATCH(xVncExtListParamsReq);
580 return ProcVncExtListParams(client);
581}
582
583static int ProcVncExtSetServerCutText(ClientPtr client)
584{
585 REQUEST(xVncExtSetServerCutTextReq);
586 REQUEST_FIXED_SIZE(xVncExtSetServerCutTextReq, stuff->textLen);
587 char* str = new char[stuff->textLen+1];
588 strncpy(str, (char*)&stuff[1], stuff->textLen);
589 str[stuff->textLen] = 0;
590 for (int scr = 0; scr < screenInfo.numScreens; scr++) {
591 if (desktop[scr]) {
592 desktop[scr]->serverCutText(str, stuff->textLen);
593 }
594 }
595 delete [] str;
596 return (client->noClientException);
597}
598
599static int SProcVncExtSetServerCutText(ClientPtr client)
600{
601 register char n;
602 REQUEST(xVncExtSetServerCutTextReq);
603 swaps(&stuff->length, n);
604 REQUEST_AT_LEAST_SIZE(xVncExtSetServerCutTextReq);
605 swapl(&stuff->textLen, n);
606 return ProcVncExtSetServerCutText(client);
607}
608
609static int ProcVncExtGetClientCutText(ClientPtr client)
610{
611 REQUEST(xVncExtGetClientCutTextReq);
612 REQUEST_SIZE_MATCH(xVncExtGetClientCutTextReq);
613
614 xVncExtGetClientCutTextReply rep;
615 int n;
616 rep.type = X_Reply;
617 rep.length = (clientCutTextLen + 3) >> 2;
618 rep.sequenceNumber = client->sequence;
619 rep.textLen = clientCutTextLen;
620 if (client->swapped) {
621 swaps(&rep.sequenceNumber, n);
622 swapl(&rep.length, n);
623 swapl(&rep.textLen, n);
624 }
625 WriteToClient(client, sizeof(xVncExtGetClientCutTextReply), (char *)&rep);
626 if (clientCutText)
627 WriteToClient(client, clientCutTextLen, clientCutText);
628 return (client->noClientException);
629}
630
631static int SProcVncExtGetClientCutText(ClientPtr client)
632{
633 register char n;
634 REQUEST(xVncExtGetClientCutTextReq);
635 swaps(&stuff->length, n);
636 REQUEST_SIZE_MATCH(xVncExtGetClientCutTextReq);
637 return ProcVncExtGetClientCutText(client);
638}
639
640static int ProcVncExtSelectInput(ClientPtr client)
641{
642 REQUEST(xVncExtSelectInputReq);
643 REQUEST_SIZE_MATCH(xVncExtSelectInputReq);
644 VncInputSelect** nextPtr = &vncInputSelectHead;
645 VncInputSelect* cur;
646 for (cur = vncInputSelectHead; cur; cur = *nextPtr) {
647 if (cur->client == client && cur->window == stuff->window) {
648 cur->mask = stuff->mask;
649 if (!cur->mask) {
650 *nextPtr = cur->next;
651 delete cur;
652 }
653 break;
654 }
655 nextPtr = &cur->next;
656 }
657 if (!cur) {
658 cur = new VncInputSelect(client, stuff->window, stuff->mask);
659 }
660 return (client->noClientException);
661}
662
663static int SProcVncExtSelectInput(ClientPtr client)
664{
665 register char n;
666 REQUEST(xVncExtSelectInputReq);
667 swaps(&stuff->length, n);
668 REQUEST_SIZE_MATCH(xVncExtSelectInputReq);
669 swapl(&stuff->window, n);
670 swapl(&stuff->mask, n);
671 return ProcVncExtSelectInput(client);
672}
673
674static int ProcVncExtConnect(ClientPtr client)
675{
676 REQUEST(xVncExtConnectReq);
677 REQUEST_FIXED_SIZE(xVncExtConnectReq, stuff->strLen);
678 CharArray str(stuff->strLen+1);
679 strncpy(str.buf, (char*)&stuff[1], stuff->strLen);
680 str.buf[stuff->strLen] = 0;
681
682 xVncExtConnectReply rep;
683 rep.success = 0;
684 if (desktop[0]) {
685 if (stuff->strLen == 0) {
686 try {
687 desktop[0]->disconnectClients();
688 rep.success = 1;
689 } catch (rdr::Exception& e) {
690 vlog.error("Disconnecting all clients: %s",e.str());
691 }
692 } else {
693 int port = 5500;
694 for (int i = 0; i < stuff->strLen; i++) {
695 if (str.buf[i] == ':') {
696 port = atoi(&str.buf[i+1]);
697 str.buf[i] = 0;
698 break;
699 }
700 }
701
702 try {
703 network::Socket* sock = new network::TcpSocket(str.buf, port);
704 desktop[0]->addClient(sock, true);
705 rep.success = 1;
706 } catch (rdr::Exception& e) {
707 vlog.error("Reverse connection: %s",e.str());
708 }
709 }
710 }
711
712 rep.type = X_Reply;
713 rep.length = 0;
714 rep.sequenceNumber = client->sequence;
715 if (client->swapped) {
716 int n;
717 swaps(&rep.sequenceNumber, n);
718 swapl(&rep.length, n);
719 }
720 WriteToClient(client, sizeof(xVncExtConnectReply), (char *)&rep);
721 return (client->noClientException);
722}
723
724static int SProcVncExtConnect(ClientPtr client)
725{
726 register char n;
727 REQUEST(xVncExtConnectReq);
728 swaps(&stuff->length, n);
729 REQUEST_AT_LEAST_SIZE(xVncExtConnectReq);
730 return ProcVncExtConnect(client);
731}
732
Constantin Kaplinsky95f6f7a2006-04-17 04:17:23 +0000733
734static int ProcVncExtGetQueryConnect(ClientPtr client)
735{
736 REQUEST(xVncExtGetQueryConnectReq);
737 REQUEST_SIZE_MATCH(xVncExtGetQueryConnectReq);
738
739 const char *qcAddress=0, *qcUsername=0;
740 int qcTimeout;
741 if (queryConnectDesktop)
742 qcTimeout = queryConnectDesktop->getQueryTimeout(queryConnectId,
743 &qcAddress, &qcUsername);
744 else
745 qcTimeout = 0;
746
747 xVncExtGetQueryConnectReply rep;
748 int n;
749 rep.type = X_Reply;
750 rep.sequenceNumber = client->sequence;
751 rep.timeout = qcTimeout;
752 rep.addrLen = qcTimeout ? strlen(qcAddress) : 0;
753 rep.userLen = qcTimeout ? strlen(qcUsername) : 0;
754 rep.opaqueId = (CARD32)queryConnectId;
755 rep.length = (rep.userLen + rep.addrLen + 3) >> 2;
756 if (client->swapped) {
757 swaps(&rep.sequenceNumber, n);
758 swapl(&rep.userLen, n);
759 swapl(&rep.addrLen, n);
760 swapl(&rep.timeout, n);
761 swapl(&rep.opaqueId, n);
762 }
763 WriteToClient(client, sizeof(xVncExtGetQueryConnectReply), (char *)&rep);
764 if (qcTimeout)
765 WriteToClient(client, strlen(qcAddress), (char*)qcAddress);
766 if (qcTimeout)
767 WriteToClient(client, strlen(qcUsername), (char*)qcUsername);
768 return (client->noClientException);
769}
770
771static int SProcVncExtGetQueryConnect(ClientPtr client)
772{
773 register char n;
774 REQUEST(xVncExtGetQueryConnectReq);
775 swaps(&stuff->length, n);
776 REQUEST_SIZE_MATCH(xVncExtGetQueryConnectReq);
777 return ProcVncExtGetQueryConnect(client);
778}
779
780
781static int ProcVncExtApproveConnect(ClientPtr client)
782{
783 REQUEST(xVncExtApproveConnectReq);
784 REQUEST_SIZE_MATCH(xVncExtApproveConnectReq);
785 if (queryConnectId == (void*)stuff->opaqueId) {
786 for (int scr = 0; scr < screenInfo.numScreens; scr++) {
787 if (desktop[scr]) {
788 desktop[scr]->approveConnection(queryConnectId, stuff->approve,
789 "Connection rejected by local user");
790 }
791 }
792 // Inform other clients of the event and tidy up
793 vncQueryConnect(queryConnectDesktop, queryConnectId);
794 }
795 return (client->noClientException);
796}
797
798static int SProcVncExtApproveConnect(ClientPtr client)
799{
800 register char n;
801 REQUEST(xVncExtApproveConnectReq);
802 swaps(&stuff->length, n);
803 swapl(&stuff->opaqueId, n);
804 REQUEST_SIZE_MATCH(xVncExtApproveConnectReq);
805 return ProcVncExtApproveConnect(client);
806}
807
808
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000809static int ProcVncExtDispatch(ClientPtr client)
810{
811 REQUEST(xReq);
812 switch (stuff->data) {
813 case X_VncExtSetParam:
814 return ProcVncExtSetParam(client);
815 case X_VncExtGetParam:
816 return ProcVncExtGetParam(client);
817 case X_VncExtGetParamDesc:
818 return ProcVncExtGetParamDesc(client);
819 case X_VncExtListParams:
820 return ProcVncExtListParams(client);
821 case X_VncExtSetServerCutText:
822 return ProcVncExtSetServerCutText(client);
823 case X_VncExtGetClientCutText:
824 return ProcVncExtGetClientCutText(client);
825 case X_VncExtSelectInput:
826 return ProcVncExtSelectInput(client);
827 case X_VncExtConnect:
828 return ProcVncExtConnect(client);
Constantin Kaplinsky95f6f7a2006-04-17 04:17:23 +0000829 case X_VncExtGetQueryConnect:
830 return ProcVncExtGetQueryConnect(client);
831 case X_VncExtApproveConnect:
832 return ProcVncExtApproveConnect(client);
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000833 default:
834 return BadRequest;
835 }
836}
837
838static int SProcVncExtDispatch(ClientPtr client)
839{
840 REQUEST(xReq);
841 switch (stuff->data) {
842 case X_VncExtSetParam:
843 return SProcVncExtSetParam(client);
844 case X_VncExtGetParam:
845 return SProcVncExtGetParam(client);
846 case X_VncExtGetParamDesc:
847 return SProcVncExtGetParamDesc(client);
848 case X_VncExtListParams:
849 return SProcVncExtListParams(client);
850 case X_VncExtSetServerCutText:
851 return SProcVncExtSetServerCutText(client);
852 case X_VncExtGetClientCutText:
853 return SProcVncExtGetClientCutText(client);
854 case X_VncExtSelectInput:
855 return SProcVncExtSelectInput(client);
856 case X_VncExtConnect:
857 return SProcVncExtConnect(client);
Constantin Kaplinsky95f6f7a2006-04-17 04:17:23 +0000858 case X_VncExtGetQueryConnect:
859 return SProcVncExtGetQueryConnect(client);
860 case X_VncExtApproveConnect:
861 return SProcVncExtApproveConnect(client);
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000862 default:
863 return BadRequest;
864 }
865}
866