blob: 2f889dd0b1405cea9a8dad816a61fa9d020791b3 [file] [log] [blame]
Constantin Kaplinsky729598c2006-05-25 05:12:25 +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#include <vncviewer/CConnOptions.h>
20#include <rfb/Configuration.h>
21#include <rfb/encodings.h>
22#include <rfb/LogWriter.h>
george82c439ebb2007-04-30 05:21:41 +000023#include <rfb/ScaleFilters.h>
Constantin Kaplinsky729598c2006-05-25 05:12:25 +000024#include <rfb_win32/MsgBox.h>
25#include <rfb_win32/Registry.h>
26#include <rdr/HexInStream.h>
27#include <rdr/HexOutStream.h>
28#include <stdlib.h>
29
30using namespace rfb;
31using namespace rfb::win32;
32
33static StringParameter passwordFile("PasswordFile",
34 "Password file for VNC authentication", "");
35
36// - Settings stored in the registry & in .vnc files, by Save Defaults and
37// Save Configuration respectively.
38
39static BoolParameter useLocalCursor("UseLocalCursor", "Render the mouse cursor locally", true);
40static BoolParameter useDesktopResize("UseDesktopResize", "Support dynamic desktop resizing", true);
41
42static BoolParameter fullColour("FullColor",
43 "Use full color", true);
44static AliasParameter fullColourAlias("FullColour", "Alias for FullColor", &fullColour);
45
46static IntParameter lowColourLevel("LowColorLevel",
47 "Color level to use on slow connections. "
48 "0 = Very Low (8 colors), 1 = Low (64 colors), 2 = Medium (256 colors)",
49 2);
50static AliasParameter lowColourLevelAlias("LowColourLevel", "Alias for LowColorLevel", &lowColourLevel);
51
52static BoolParameter fullScreen("FullScreen",
53 "Use the whole display to show the remote desktop."
54 "(Press F8 to access the viewer menu)",
55 false);
56static StringParameter preferredEncoding("PreferredEncoding",
57 "Preferred encoding to use (Tight, ZRLE, Hextile or"
58 " Raw)", "Tight");
59static BoolParameter autoSelect("AutoSelect",
60 "Auto select pixel format and encoding. "
61 "Default if PreferredEncoding and FullColor are not specified.",
62 true);
63static BoolParameter sharedConnection("Shared",
64 "Allow existing connections to the server to continue."
65 "(Default is to disconnect all other clients)",
66 false);
67
Pierre Ossmand6d19942009-03-24 12:29:50 +000068StringParameter desktopSize("DesktopSize",
69 "Reconfigure desktop size on the server on "
70 "connect (if possible)", "");
71
Constantin Kaplinsky729598c2006-05-25 05:12:25 +000072static BoolParameter sendPtrEvents("SendPointerEvents",
73 "Send pointer (mouse) events to the server.", true);
74static BoolParameter sendKeyEvents("SendKeyEvents",
75 "Send key presses (and releases) to the server.", true);
76
77static BoolParameter clientCutText("ClientCutText",
78 "Send clipboard changes to the server.", true);
79static BoolParameter serverCutText("ServerCutText",
80 "Accept clipboard changes from the server.", true);
81
82static BoolParameter disableWinKeys("DisableWinKeys",
83 "Pass special Windows keys directly to the server.", true);
84
85static BoolParameter protocol3_3("Protocol3.3",
86 "Only use protocol version 3.3", false);
87
88static IntParameter ptrEventInterval("PointerEventInterval",
89 "The interval to delay between sending one pointer event "
90 "and the next.", 0);
91static BoolParameter emulate3("Emulate3",
92 "Emulate middle mouse button when left and right buttons "
93 "are used simulatenously.", false);
94
95static BoolParameter acceptBell("AcceptBell",
96 "Produce a system beep when requested to by the server.",
97 true);
98
99static BoolParameter showToolbar("ShowToolbar", "Show toolbar by default.", true);
100
101static StringParameter monitor("Monitor", "The monitor to open the VNC Viewer window on, if available.", "");
102static StringParameter menuKey("MenuKey", "The key which brings up the popup menu", "F8");
103static BoolParameter autoReconnect("AutoReconnect", "Offer to reconnect to the remote server if the connection"
104 "is dropped because an error occurs.", true);
105
106static BoolParameter customCompressLevel("CustomCompressLevel",
107 "Use custom compression level. "
108 "Default if CompressLevel is specified.", false);
109
110static IntParameter compressLevel("CompressLevel",
111 "Use specified compression level"
112 "0 = Low, 9 = High",
113 6);
114
115static BoolParameter noJpeg("NoJPEG",
116 "Disable lossy JPEG compression in Tight encoding.",
117 false);
118
119static IntParameter qualityLevel("QualityLevel",
120 "JPEG quality level. "
121 "0 = Low, 9 = High",
Pierre Ossman7dfa22e2009-03-12 13:03:22 +0000122 8);
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000123
george82444e8862006-05-27 10:21:28 +0000124static BoolParameter autoScaling("AutoScaling",
125 "Auto rescale local copy of the remote desktop to the client window.",
126 false);
127static IntParameter scale("Scale",
128 "Scale local copy of the remote desktop, in percent",
129 100);
130
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000131CConnOptions::CConnOptions()
Peter Åstranda850e642008-12-11 09:04:02 +0000132: useLocalCursor (::useLocalCursor),
133useDesktopResize(::useDesktopResize),
134fullScreen(::fullScreen),
135fullColour(::fullColour),
136lowColourLevel(::lowColourLevel),
Pierre Ossman7dfa22e2009-03-12 13:03:22 +0000137preferredEncoding(encodingTight),
Peter Åstranda850e642008-12-11 09:04:02 +0000138autoSelect(::autoSelect),
139shared(::sharedConnection),
Pierre Ossmand6d19942009-03-24 12:29:50 +0000140desktopSize(::desktopSize.getData()),
Peter Åstranda850e642008-12-11 09:04:02 +0000141sendPtrEvents(::sendPtrEvents),
142sendKeyEvents(::sendKeyEvents),
143showToolbar(::showToolbar),
144clientCutText(::clientCutText),
145serverCutText(::serverCutText),
146disableWinKeys(::disableWinKeys),
147emulate3(::emulate3),
148pointerEventInterval(ptrEventInterval),
149protocol3_3(::protocol3_3),
150acceptBell(::acceptBell),
151autoScaling(::autoScaling),
152scale(::scale),
153monitor(::monitor.getData()),
154autoReconnect(::autoReconnect),
155customCompressLevel(::customCompressLevel),
156compressLevel(::compressLevel),
157noJpeg(::noJpeg),
Peter Åstrandf7d04362008-12-11 10:13:02 +0000158qualityLevel(::qualityLevel),
159passwordFile(::passwordFile.getData())
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000160{
161 if (autoSelect) {
Pierre Ossman7dfa22e2009-03-12 13:03:22 +0000162 preferredEncoding = encodingTight;
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000163 } else {
164 CharArray encodingName(::preferredEncoding.getData());
165 preferredEncoding = encodingNum(encodingName.buf);
166 }
167 setMenuKey(CharArray(::menuKey.getData()).buf);
168
169 if (!::autoSelect.hasBeenSet()) {
170 // Default to AutoSelect=0 if -PreferredEncoding or -FullColor is used
171 autoSelect = (!::preferredEncoding.hasBeenSet()
172 && !::fullColour.hasBeenSet()
173 && !::fullColourAlias.hasBeenSet());
174 }
175 if (!::customCompressLevel.hasBeenSet()) {
176 // Default to CustomCompressLevel=1 if CompressLevel is used.
177 customCompressLevel = ::compressLevel.hasBeenSet();
178 }
179}
180
181
182void CConnOptions::readFromFile(const char* filename) {
183 FILE* f = fopen(filename, "r");
184 if (!f)
185 throw rdr::Exception("Failed to read configuration file");
186
187 try {
188 char line[4096];
189 CharArray section;
190
191 CharArray hostTmp;
192 int portTmp = 0;
193
194 while (!feof(f)) {
195 // Read the next line
196 if (!fgets(line, sizeof(line), f)) {
197 if (feof(f))
198 break;
199 throw rdr::SystemException("fgets", ferror(f));
200 }
201 int len=strlen(line);
202 if (line[len-1] == '\n') {
203 line[len-1] = 0;
204 len--;
205 }
206
207 // Process the line
208 if (line[0] == ';') {
209 // Comment
210 } else if (line[0] == '[') {
211 // Entering a new section
212 if (!strSplit(&line[1], ']', &section.buf, 0))
213 throw rdr::Exception("bad Section");
214 } else {
215 // Reading an option
216 CharArray name;
217 CharArray value;
218 if (!strSplit(line, '=', &name.buf, &value.buf))
219 throw rdr::Exception("bad Name/Value pair");
220
221 if (stricmp(section.buf, "Connection") == 0) {
222 if (stricmp(name.buf, "Host") == 0) {
223 hostTmp.replaceBuf(value.takeBuf());
224 } else if (stricmp(name.buf, "Port") == 0) {
225 portTmp = atoi(value.buf);
226 } else if (stricmp(name.buf, "UserName") == 0) {
227 userName.replaceBuf(value.takeBuf());
228 } else if (stricmp(name.buf, "Password") == 0) {
229 ObfuscatedPasswd obfPwd;
230 rdr::HexInStream::hexStrToBin(value.buf, (char**)&obfPwd.buf, &obfPwd.length);
231 PlainPasswd passwd(obfPwd);
232 password.replaceBuf(passwd.takeBuf());
233 }
234 } else if (stricmp(section.buf, "Options") == 0) {
235 // V4 options
236 if (stricmp(name.buf, "UseLocalCursor") == 0) {
237 useLocalCursor = atoi(value.buf);
238 } else if (stricmp(name.buf, "UseDesktopResize") == 0) {
239 useDesktopResize = atoi(value.buf);
240 } else if (stricmp(name.buf, "FullScreen") == 0) {
241 fullScreen = atoi(value.buf);
242 } else if (stricmp(name.buf, "FullColour") == 0) {
243 fullColour = atoi(value.buf);
244 } else if (stricmp(name.buf, "LowColourLevel") == 0) {
245 lowColourLevel = atoi(value.buf);
246 } else if (stricmp(name.buf, "PreferredEncoding") == 0) {
247 preferredEncoding = encodingNum(value.buf);
248 } else if ((stricmp(name.buf, "AutoDetect") == 0) ||
249 (stricmp(name.buf, "AutoSelect") == 0)) {
250 autoSelect = atoi(value.buf);
251 } else if (stricmp(name.buf, "Shared") == 0) {
252 shared = atoi(value.buf);
253 } else if (stricmp(name.buf, "SendPtrEvents") == 0) {
254 sendPtrEvents = atoi(value.buf);
255 } else if (stricmp(name.buf, "SendKeyEvents") == 0) {
256 sendKeyEvents = atoi(value.buf);
257 } else if (stricmp(name.buf, "SendCutText") == 0) {
258 clientCutText = atoi(value.buf);
259 } else if (stricmp(name.buf, "AcceptCutText") == 0) {
260 serverCutText = atoi(value.buf);
261 } else if (stricmp(name.buf, "DisableWinKeys") == 0) {
262 disableWinKeys = atoi(value.buf);
263 } else if (stricmp(name.buf, "AcceptBell") == 0) {
264 acceptBell = atoi(value.buf);
265 } else if (stricmp(name.buf, "Emulate3") == 0) {
266 emulate3 = atoi(value.buf);
267 } else if (stricmp(name.buf, "ShowToolbar") == 0) {
268 showToolbar = atoi(value.buf);
269 } else if (stricmp(name.buf, "PointerEventInterval") == 0) {
270 pointerEventInterval = atoi(value.buf);
271 } else if (stricmp(name.buf, "Monitor") == 0) {
272 monitor.replaceBuf(value.takeBuf());
273 } else if (stricmp(name.buf, "MenuKey") == 0) {
274 setMenuKey(value.buf);
275 } else if (stricmp(name.buf, "AutoReconnect") == 0) {
276 autoReconnect = atoi(value.buf);
277
278 } else if (stricmp(name.buf, "CustomCompressLevel") == 0) {
279 customCompressLevel = atoi(value.buf);
280 } else if (stricmp(name.buf, "CompressLevel") == 0) {
281 compressLevel = atoi(value.buf);
282 } else if (stricmp(name.buf, "NoJPEG") == 0) {
283 noJpeg = atoi(value.buf);
284 } else if (stricmp(name.buf, "QualityLevel") == 0) {
285 qualityLevel = atoi(value.buf);
286 // Legacy options
287 } else if (stricmp(name.buf, "Preferred_Encoding") == 0) {
288 preferredEncoding = atoi(value.buf);
289 } else if (stricmp(name.buf, "8bit") == 0) {
290 fullColour = !atoi(value.buf);
291 } else if (stricmp(name.buf, "FullScreen") == 0) {
292 fullScreen = atoi(value.buf);
293 } else if (stricmp(name.buf, "ViewOnly") == 0) {
294 sendPtrEvents = sendKeyEvents = !atoi(value.buf);
295 } else if (stricmp(name.buf, "DisableClipboard") == 0) {
296 clientCutText = serverCutText = !atoi(value.buf);
george82444e8862006-05-27 10:21:28 +0000297 } else if (stricmp(name.buf, "AutoScaling") == 0) {
298 autoScaling = atoi(value.buf);
299 } else if (stricmp(name.buf, "Scale") == 0) {
300 scale = atoi(value.buf);
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000301 }
302 }
303 }
304 }
305 fclose(f); f=0;
306
307 // Process the Host and Port
308 if (hostTmp.buf) {
309 int hostLen = strlen(hostTmp.buf) + 2 + 17;
310 host.replaceBuf(new char[hostLen]);
311 strCopy(host.buf, hostTmp.buf, hostLen);
312 if (portTmp) {
313 strncat(host.buf, "::", hostLen-1);
314 char tmp[16];
315 sprintf(tmp, "%d", portTmp);
316 strncat(host.buf, tmp, hostLen-1);
317 }
318 }
319
320 // If AutoSelect is enabled then override the preferred encoding
321 if (autoSelect)
322 preferredEncoding = encodingZRLE;
323
324 setConfigFileName(filename);
325 } catch (rdr::Exception&) {
326 if (f) fclose(f);
327 throw;
328 }
329}
330
331void CConnOptions::writeToFile(const char* filename) {
332 FILE* f = fopen(filename, "w");
333 if (!f)
334 throw rdr::Exception("Failed to write configuration file");
335
336 try {
337 // - Split server into host and port and save
338 fprintf(f, "[Connection]\n");
339
340 fprintf(f, "Host=%s\n", host.buf);
341 if (userName.buf)
342 fprintf(f, "UserName=%s\n", userName.buf);
343 if (password.buf) {
344 // - Warn the user before saving the password
345 if (MsgBox(0, _T("Do you want to include the VNC Password in this configuration file?\n")
346 _T("Storing the password is more convenient but poses a security risk."),
347 MB_YESNO | MB_DEFBUTTON2 | MB_ICONWARNING) == IDYES) {
348 ObfuscatedPasswd obfPwd(password);
Peter Åstrandb22dbef2008-12-09 14:57:53 +0000349 CharArray obfuscatedHex(rdr::HexOutStream::binToHexStr(obfPwd.buf, obfPwd.length));
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000350 fprintf(f, "Password=%s\n", obfuscatedHex.buf);
351 }
352 }
353
354 // - Save the other options
355 fprintf(f, "[Options]\n");
356
357 fprintf(f, "UseLocalCursor=%d\n", (int)useLocalCursor);
358 fprintf(f, "UseDesktopResize=%d\n", (int)useDesktopResize);
359 fprintf(f, "FullScreen=%d\n", (int)fullScreen);
360 fprintf(f, "FullColour=%d\n", (int)fullColour);
361 fprintf(f, "LowColourLevel=%d\n", lowColourLevel);
362 fprintf(f, "PreferredEncoding=%s\n", encodingName(preferredEncoding));
363 fprintf(f, "AutoSelect=%d\n", (int)autoSelect);
364 fprintf(f, "Shared=%d\n", (int)shared);
365 fprintf(f, "SendPtrEvents=%d\n", (int)sendPtrEvents);
366 fprintf(f, "SendKeyEvents=%d\n", (int)sendKeyEvents);
367 fprintf(f, "SendCutText=%d\n", (int)clientCutText);
368 fprintf(f, "AcceptCutText=%d\n", (int)serverCutText);
369 fprintf(f, "DisableWinKeys=%d\n", (int)disableWinKeys);
370 fprintf(f, "AcceptBell=%d\n", (int)acceptBell);
371 fprintf(f, "Emulate3=%d\n", (int)emulate3);
372 fprintf(f, "ShowToolbar=%d\n", (int)showToolbar);
373 fprintf(f, "PointerEventInterval=%d\n", pointerEventInterval);
374 if (monitor.buf)
375 fprintf(f, "Monitor=%s\n", monitor.buf);
376 fprintf(f, "MenuKey=%s\n", CharArray(menuKeyName()).buf);
377 fprintf(f, "AutoReconnect=%d\n", (int)autoReconnect);
378 fprintf(f, "CustomCompressLevel=%d\n", customCompressLevel);
379 fprintf(f, "CompressLevel=%d\n", compressLevel);
380 fprintf(f, "NoJPEG=%d\n", noJpeg);
381 fprintf(f, "QualityLevel=%d\n", qualityLevel);
george82444e8862006-05-27 10:21:28 +0000382 fprintf(f, "AutoScaling=%d\n", (int)autoScaling);
383 fprintf(f, "Scale=%d\n", scale);
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000384 fclose(f); f=0;
385
386 setConfigFileName(filename);
387 } catch (rdr::Exception&) {
388 if (f) fclose(f);
389 throw;
390 }
391}
392
393
394void CConnOptions::writeDefaults() {
395 RegKey key;
Peter Åstrand4eacc022009-02-27 10:12:14 +0000396 key.createKey(HKEY_CURRENT_USER, _T("Software\\TigerVNC\\VNCviewer4"));
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000397 key.setBool(_T("UseLocalCursor"), useLocalCursor);
398 key.setBool(_T("UseDesktopResize"), useDesktopResize);
399 key.setBool(_T("FullScreen"), fullScreen);
400 key.setBool(_T("FullColour"), fullColour);
401 key.setInt(_T("LowColourLevel"), lowColourLevel);
402 key.setString(_T("PreferredEncoding"), TStr(encodingName(preferredEncoding)));
403 key.setBool(_T("AutoSelect"), autoSelect);
404 key.setBool(_T("Shared"), shared);
405 key.setBool(_T("SendPointerEvents"), sendPtrEvents);
406 key.setBool(_T("SendKeyEvents"), sendKeyEvents);
407 key.setBool(_T("ClientCutText"), clientCutText);
408 key.setBool(_T("ServerCutText"), serverCutText);
409 key.setBool(_T("DisableWinKeys"), disableWinKeys);
410 key.setBool(_T("Protocol3.3"), protocol3_3);
411 key.setBool(_T("AcceptBell"), acceptBell);
412 key.setBool(_T("ShowToolbar"), showToolbar);
413 key.setBool(_T("Emulate3"), emulate3);
414 key.setInt(_T("PointerEventInterval"), pointerEventInterval);
415 if (monitor.buf)
416 key.setString(_T("Monitor"), TStr(monitor.buf));
417 key.setString(_T("MenuKey"), TCharArray(menuKeyName()).buf);
418 key.setBool(_T("AutoReconnect"), autoReconnect);
419 key.setInt(_T("CustomCompressLevel"), customCompressLevel);
420 key.setInt(_T("CompressLevel"), compressLevel);
421 key.setInt(_T("NoJPEG"), noJpeg);
422 key.setInt(_T("QualityLevel"), qualityLevel);
george82444e8862006-05-27 10:21:28 +0000423 key.setBool(_T("AutoScaling"), autoScaling);
424 key.setInt(_T("Scale"), scale);
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000425}
426
427
428void CConnOptions::setUserName(const char* user) {userName.replaceBuf(strDup(user));}
429void CConnOptions::setPassword(const char* pwd) {password.replaceBuf(strDup(pwd));}
430void CConnOptions::setConfigFileName(const char* cfn) {configFileName.replaceBuf(strDup(cfn));}
431void CConnOptions::setHost(const char* h) {host.replaceBuf(strDup(h));}
432void CConnOptions::setMonitor(const char* m) {monitor.replaceBuf(strDup(m));}
433
434void CConnOptions::setMenuKey(const char* keyName) {
435 if (!keyName[0]) {
436 menuKey = 0;
437 } else {
438 menuKey = VK_F8;
439 if (keyName[0] == 'F') {
440 UINT fKey = atoi(&keyName[1]);
441 if (fKey >= 1 && fKey <= 12)
442 menuKey = fKey-1 + VK_F1;
443 }
444 }
445}
446char* CConnOptions::menuKeyName() {
447 int fNum = (menuKey-VK_F1)+1;
448 if (fNum<1 || fNum>12)
449 return strDup("");
450 CharArray menuKeyStr(4);
451 sprintf(menuKeyStr.buf, "F%d", fNum);
452 return menuKeyStr.takeBuf();
453}
454
455
456CConnOptions& CConnOptions::operator=(const CConnOptions& o) {
457 useLocalCursor = o.useLocalCursor;
458 useDesktopResize = o.useDesktopResize;
459 fullScreen = o.fullScreen;
460 fullColour = o.fullColour;
461 lowColourLevel = o.lowColourLevel;
462 preferredEncoding = o.preferredEncoding;
463 autoSelect = o.autoSelect;
464 shared = o.shared;
465 sendPtrEvents = o.sendPtrEvents;
466 sendKeyEvents = o.sendKeyEvents;
467 clientCutText = o.clientCutText;
468 serverCutText = o.serverCutText;
469 disableWinKeys = o.disableWinKeys;
470 emulate3 = o.emulate3;
471 pointerEventInterval = o.pointerEventInterval;
472 protocol3_3 = o.protocol3_3;
473 acceptBell = o.acceptBell;
474 showToolbar = o.showToolbar;
475 setUserName(o.userName.buf);
476 setPassword(o.password.buf);
477 setConfigFileName(o.configFileName.buf);
478 setHost(o.host.buf);
479 setMonitor(o.monitor.buf);
480 menuKey = o.menuKey;
481 autoReconnect = o.autoReconnect;
482 customCompressLevel = o.customCompressLevel;
483 compressLevel = o.compressLevel;
484 noJpeg = o.noJpeg;
485 qualityLevel = o.qualityLevel;
george82444e8862006-05-27 10:21:28 +0000486 autoScaling = o.autoScaling;
487 scale = o.scale;
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000488
489 return *this;
490}