blob: 188ebfb8b45039bbaf3e497b52c03ca997162329 [file] [log] [blame]
Constantin Kaplinskyb30ae7f2006-05-25 05:04:46 +00001/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
2 *
3 * 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// VNC server configuration utility
20//
21
22#include <string.h>
23#include <stdio.h>
24#include <stdlib.h>
25#include <sys/time.h>
26#include <sys/types.h>
27#include <unistd.h>
28#include <errno.h>
29
30#include <signal.h>
31#include <X11/X.h>
32#include <X11/Xlib.h>
33#include <X11/Xatom.h>
34#include <X11/Xutil.h>
35#include <X11/keysym.h>
36#include "vncExt.h"
37#include <rdr/Exception.h>
38#include <rfb/Configuration.h>
39#include <rfb/Logger_stdio.h>
40#include <rfb/LogWriter.h>
Constantin Kaplinskyb30ae7f2006-05-25 05:04:46 +000041#include "TXWindow.h"
42#include "TXCheckbox.h"
43#include "TXLabel.h"
44#include "QueryConnectDialog.h"
45
46using namespace rfb;
47
48LogWriter vlog("vncconfig");
49
50StringParameter displayname("display", "The X display", "");
51BoolParameter noWindow("nowin", "Don't display a window", 0);
52BoolParameter iconic("iconic", "Start with window iconified", 0);
Constantin Kaplinskyb30ae7f2006-05-25 05:04:46 +000053
54#define ACCEPT_CUT_TEXT "AcceptCutText"
55#define SEND_CUT_TEXT "SendCutText"
56
57char* programName = 0;
58Display* dpy;
59int vncExtEventBase, vncExtErrorBase;
60
61static bool getBoolParam(Display* dpy, const char* param) {
62 char* data;
63 int len;
64 if (XVncExtGetParam(dpy, param, &data, &len)) {
65 if (strcmp(data,"1") == 0) return true;
66 }
67 return false;
68}
69
70class VncConfigWindow : public TXWindow, public TXEventHandler,
71 public TXDeleteWindowCallback,
72 public TXCheckboxCallback,
Constantin Kaplinskyb30ae7f2006-05-25 05:04:46 +000073 public QueryResultCallback {
74public:
75 VncConfigWindow(Display* dpy)
Pierre Ossmanbfd567a2016-01-12 18:57:37 +010076 : TXWindow(dpy, 300, 100),
Constantin Kaplinskyb30ae7f2006-05-25 05:04:46 +000077 acceptClipboard(dpy, "Accept clipboard from viewers", this, false, this),
78 sendClipboard(dpy, "Send clipboard to viewers", this, false, this),
Constantin Kaplinskyb30ae7f2006-05-25 05:04:46 +000079 queryConnectDialog(0)
80 {
Constantin Kaplinskyb30ae7f2006-05-25 05:04:46 +000081 int y = yPad;
82 acceptClipboard.move(xPad, y);
83 acceptClipboard.checked(getBoolParam(dpy, ACCEPT_CUT_TEXT));
84 y += acceptClipboard.height();
85 sendClipboard.move(xPad, y);
86 sendClipboard.checked(getBoolParam(dpy, SEND_CUT_TEXT));
87 y += sendClipboard.height();
Constantin Kaplinskyb30ae7f2006-05-25 05:04:46 +000088 setEventHandler(this);
89 toplevel("VNC config", this, 0, 0, 0, iconic);
Pierre Ossmanbfd567a2016-01-12 18:57:37 +010090 XVncExtSelectInput(dpy, win(), VncExtQueryConnectMask);
Constantin Kaplinskyb30ae7f2006-05-25 05:04:46 +000091 }
92
Pierre Ossmanbfd567a2016-01-12 18:57:37 +010093 // handleEvent()
Constantin Kaplinskyb30ae7f2006-05-25 05:04:46 +000094
95 virtual void handleEvent(TXWindow* w, XEvent* ev) {
Constantin Kaplinskyb30ae7f2006-05-25 05:04:46 +000096 if (ev->type == vncExtEventBase + VncExtQueryConnectNotify) {
97 vlog.debug("query connection event");
98 if (queryConnectDialog)
99 delete queryConnectDialog;
100 queryConnectDialog = 0;
101 char* qcAddress;
102 char* qcUser;
103 int qcTimeout;
104 if (XVncExtGetQueryConnect(dpy, &qcAddress, &qcUser,
105 &qcTimeout, &queryConnectId)) {
106 if (qcTimeout)
107 queryConnectDialog = new QueryConnectDialog(dpy, qcAddress,
108 qcUser, qcTimeout,
109 this);
110 if (queryConnectDialog)
111 queryConnectDialog->map();
112 XFree(qcAddress);
113 XFree(qcUser);
114 }
115 }
116 }
Constantin Kaplinskyb30ae7f2006-05-25 05:04:46 +0000117
118 // TXDeleteWindowCallback method
119 virtual void deleteWindow(TXWindow* w) {
120 exit(1);
121 }
122
123 // TXCheckboxCallback method
124 virtual void checkboxSelect(TXCheckbox* checkbox) {
125 if (checkbox == &acceptClipboard) {
126 XVncExtSetParam(dpy, (acceptClipboard.checked()
127 ? ACCEPT_CUT_TEXT "=1" : ACCEPT_CUT_TEXT "=0"));
128 } else if (checkbox == &sendClipboard) {
129 XVncExtSetParam(dpy, (sendClipboard.checked()
130 ? SEND_CUT_TEXT "=1" : SEND_CUT_TEXT "=0"));
Constantin Kaplinskyb30ae7f2006-05-25 05:04:46 +0000131 }
132 }
133
Constantin Kaplinskyb30ae7f2006-05-25 05:04:46 +0000134 // QueryResultCallback interface
135 virtual void queryApproved() {
136 XVncExtApproveConnect(dpy, queryConnectId, 1);
137 }
138 virtual void queryRejected() {
139 XVncExtApproveConnect(dpy, queryConnectId, 0);
140 }
141
142private:
Pierre Ossmanbfd567a2016-01-12 18:57:37 +0100143 TXCheckbox acceptClipboard, sendClipboard;
Constantin Kaplinskyb30ae7f2006-05-25 05:04:46 +0000144
145 QueryConnectDialog* queryConnectDialog;
146 void* queryConnectId;
147};
148
149static void usage()
150{
151 fprintf(stderr,"usage: %s [parameters]\n",
152 programName);
153 fprintf(stderr," %s [parameters] -connect <host>[:<port>]\n",
154 programName);
155 fprintf(stderr," %s [parameters] -disconnect\n", programName);
156 fprintf(stderr," %s [parameters] [-set] <Xvnc-param>=<value> ...\n",
157 programName);
158 fprintf(stderr," %s [parameters] -list\n", programName);
159 fprintf(stderr," %s [parameters] -get <param>\n", programName);
160 fprintf(stderr," %s [parameters] -desc <param>\n",programName);
161 fprintf(stderr,"\n"
162 "Parameters can be turned on with -<param> or off with -<param>=0\n"
163 "Parameters which take a value can be specified as "
164 "-<param> <value>\n"
165 "Other valid forms are <param>=<value> -<param>=<value> "
166 "--<param>=<value>\n"
167 "Parameter names are case-insensitive. The parameters are:\n\n");
168 Configuration::listParams(79, 14);
169 exit(1);
170}
171
172void removeArgs(int* argc, char** argv, int first, int n)
173{
174 if (first + n > *argc) return;
175 for (int i = first + n; i < *argc; i++)
176 argv[i-n] = argv[i];
177 *argc -= n;
178}
179
180int main(int argc, char** argv)
181{
182 programName = argv[0];
183 rfb::initStdIOLoggers();
184 rfb::LogWriter::setLogParams("*:stderr:30");
185
186 // Process vncconfig's own parameters first, then we process the
187 // other arguments when we have the X display.
188 int i;
189 for (i = 1; i < argc; i++) {
190 if (Configuration::setParam(argv[i]))
191 continue;
192
193 if (argv[i][0] == '-' && i+1 < argc &&
194 Configuration::setParam(&argv[i][1], argv[i+1])) {
195 i++;
196 continue;
197 }
198 break;
199 }
200
201 CharArray displaynameStr(displayname.getData());
202 if (!(dpy = XOpenDisplay(displaynameStr.buf))) {
203 fprintf(stderr,"%s: unable to open display \"%s\"\n",
204 programName, XDisplayName(displaynameStr.buf));
205 exit(1);
206 }
207
208 if (!XVncExtQueryExtension(dpy, &vncExtEventBase, &vncExtErrorBase)) {
209 fprintf(stderr,"No VNC extension on display %s\n",
210 XDisplayName(displaynameStr.buf));
211 exit(1);
212 }
213
214 if (i < argc) {
215 for (; i < argc; i++) {
216 if (strcmp(argv[i], "-connect") == 0) {
217 i++;
218 if (i >= argc) usage();
219 if (!XVncExtConnect(dpy, argv[i])) {
220 fprintf(stderr,"connecting to %s failed\n",argv[i]);
221 }
222 } else if (strcmp(argv[i], "-disconnect") == 0) {
223 if (!XVncExtConnect(dpy, "")) {
224 fprintf(stderr,"disconnecting all clients failed\n");
225 }
226 } else if (strcmp(argv[i], "-get") == 0) {
227 i++;
228 if (i >= argc) usage();
229 char* data;
230 int len;
231 if (XVncExtGetParam(dpy, argv[i], &data, &len)) {
232 printf("%.*s\n",len,data);
233 } else {
234 fprintf(stderr,"getting param %s failed\n",argv[i]);
235 }
236 XFree(data);
237 } else if (strcmp(argv[i], "-desc") == 0) {
238 i++;
239 if (i >= argc) usage();
240 char* desc = XVncExtGetParamDesc(dpy, argv[i]);
241 if (desc) {
242 printf("%s\n",desc);
243 } else {
244 fprintf(stderr,"getting description for param %s failed\n",argv[i]);
245 }
246 XFree(desc);
247 } else if (strcmp(argv[i], "-list") == 0) {
248 int nParams;
249 char** list = XVncExtListParams(dpy, &nParams);
250 for (int i = 0; i < nParams; i++) {
251 printf("%s\n",list[i]);
252 }
253 XVncExtFreeParamList(list);
254 } else if (strcmp(argv[i], "-set") == 0) {
255 i++;
256 if (i >= argc) usage();
257 if (!XVncExtSetParam(dpy, argv[i])) {
258 fprintf(stderr,"setting param %s failed\n",argv[i]);
259 }
260 } else if (XVncExtSetParam(dpy, argv[i])) {
261 fprintf(stderr,"set parameter %s\n",argv[i]);
262 } else {
263 usage();
264 }
265 }
266
267 return 0;
268 }
269
270 try {
271 TXWindow::init(dpy,"Vncconfig");
272
273 VncConfigWindow w(dpy);
274 if (!noWindow) w.map();
275
276 while (true) {
277 struct timeval tv;
278 struct timeval* tvp = 0;
279
280 // Process any incoming X events
281 TXWindow::handleXEvents(dpy);
282
283 // Process expired timers and get the time until the next one
284 int timeoutMs = Timer::checkTimeouts();
285 if (timeoutMs) {
286 tv.tv_sec = timeoutMs / 1000;
287 tv.tv_usec = (timeoutMs % 1000) * 1000;
288 tvp = &tv;
289 }
290
291 // If there are X requests pending then poll, don't wait!
292 if (XPending(dpy)) {
293 tv.tv_usec = tv.tv_sec = 0;
294 tvp = &tv;
295 }
296
297 // Wait for X events, VNC traffic, or the next timer expiry
298 fd_set rfds;
299 FD_ZERO(&rfds);
300 FD_SET(ConnectionNumber(dpy), &rfds);
301 int n = select(FD_SETSIZE, &rfds, 0, 0, tvp);
302 if (n < 0) throw rdr::SystemException("select",errno);
303 }
304
305 XCloseDisplay(dpy);
306
307 } catch (rdr::Exception &e) {
Pierre Ossmanad8609a2012-04-26 09:04:14 +0000308 vlog.error("%s", e.str());
Constantin Kaplinskyb30ae7f2006-05-25 05:04:46 +0000309 }
310
311 return 0;
312}