blob: 13ad7cddaa4d972939c324d6d89c62d256ca80df [file] [log] [blame]
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +00001/* Copyright (C) 2002-2004 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/CViewOptions.h>
20#include <rfb/Configuration.h>
21#include <rfb/encodings.h>
22#include <rfb/vncAuth.h>
23#include <rfb/LogWriter.h>
24#include <rfb_win32/Win32Util.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
Peter Åstrand3e3c75e2005-01-03 13:32:28 +000033static StringParameter passwordFile("PasswordFile",
34 "Password file for VNC authentication", "");
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +000035
36static BoolParameter useLocalCursor("UseLocalCursor", "Render the mouse cursor locally", true);
37static BoolParameter useDesktopResize("UseDesktopResize", "Support dynamic desktop resizing", true);
38
Peter Åstrandc81a6522004-12-30 11:32:08 +000039static BoolParameter fullColour("FullColor",
40 "Use full color", true);
41static AliasParameter fullColourAlias("FullColour", "Alias for FullColor", &fullColour);
42
43static IntParameter lowColourLevel("LowColorLevel",
44 "Color level to use on slow connections. "
45 "0 = Very Low (8 colors), 1 = Low (64 colors), 2 = Medium (256 colors)",
Peter Åstranddd747d82004-12-21 15:54:44 +000046 2);
Peter Åstrandc81a6522004-12-30 11:32:08 +000047static AliasParameter lowColourLevelAlias("LowColourLevel", "Alias for LowColorLevel", &lowColourLevel);
48
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +000049static BoolParameter fullScreen("FullScreen",
50 "Use the whole display to show the remote desktop."
51 "(Press F8 to access the viewer menu)",
52 false);
53static StringParameter preferredEncoding("PreferredEncoding",
Peter Åstrand55855d52005-01-03 12:01:45 +000054 "Preferred encoding to use (Tight, ZRLE, Hextile or"
55 " Raw)", "Tight");
56static BoolParameter autoSelect("AutoSelect",
57 "Auto select pixel format and encoding. "
58 "Default if PreferredEncoding and FullColor are not specified.",
59 true);
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +000060static BoolParameter sharedConnection("Shared",
61 "Allow existing connections to the server to continue."
62 "(Default is to disconnect all other clients)",
63 false);
64
65static BoolParameter sendPtrEvents("SendPointerEvents",
66 "Send pointer (mouse) events to the server.", true);
67static BoolParameter sendKeyEvents("SendKeyEvents",
68 "Send key presses (and releases) to the server.", true);
69
70static BoolParameter clientCutText("ClientCutText",
71 "Send clipboard changes to the server.", true);
72static BoolParameter serverCutText("ServerCutText",
73 "Accept clipboard changes from the server.", true);
74
75static BoolParameter protocol3_3("Protocol3.3",
76 "Only use protocol version 3.3", false);
77
78static IntParameter ptrEventInterval("PointerEventInterval",
79 "The interval to delay between sending one pointer event "
80 "and the next.", 0);
81static BoolParameter emulate3("Emulate3",
82 "Emulate middle mouse button when left and right buttons "
83 "are used simulatenously.", false);
84
85static BoolParameter acceptBell("AcceptBell",
86 "Produce a system beep when requested to by the server.",
87 true);
88
89static StringParameter monitor("Monitor", "The monitor to open the VNC Viewer window on, if available.", "");
90static StringParameter menuKey("MenuKey", "The key which brings up the popup menu", "F8");
91
Peter Åstrand365427a2004-12-29 10:59:03 +000092static BoolParameter customCompressLevel("CustomCompressLevel",
Peter Åstrand55855d52005-01-03 12:01:45 +000093 "Use custom compression level. "
94 "Default if CompressLevel is specified.", false);
Peter Åstrand365427a2004-12-29 10:59:03 +000095
96static IntParameter compressLevel("CompressLevel",
97 "Use specified compression level"
98 "0 = Low, 9 = High",
99 6);
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000100
Peter Åstrand0b870262004-12-28 15:55:46 +0000101static BoolParameter noJpeg("NoJPEG",
102 "Disable lossy JPEG compression in Tight encoding.",
103 false);
104
Peter Åstrand365427a2004-12-29 10:59:03 +0000105static IntParameter qualityLevel("QualityLevel",
106 "JPEG quality level. "
107 "0 = Low, 9 = High",
108 6);
109
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000110CViewOptions::CViewOptions()
111: useLocalCursor(::useLocalCursor), useDesktopResize(::useDesktopResize),
112autoSelect(::autoSelect), fullColour(::fullColour), fullScreen(::fullScreen),
113shared(::sharedConnection), sendPtrEvents(::sendPtrEvents), sendKeyEvents(::sendKeyEvents),
114preferredEncoding(encodingZRLE), clientCutText(::clientCutText), serverCutText(::serverCutText),
115protocol3_3(::protocol3_3), acceptBell(::acceptBell), lowColourLevel(::lowColourLevel),
Peter Åstranded9d4ae2004-12-07 11:59:14 +0000116pointerEventInterval(ptrEventInterval), emulate3(::emulate3), monitor(::monitor.getData()),
Peter Åstrand365427a2004-12-29 10:59:03 +0000117customCompressLevel(::customCompressLevel), compressLevel(::compressLevel),
Peter Åstrand3e3c75e2005-01-03 13:32:28 +0000118noJpeg(::noJpeg), qualityLevel(::qualityLevel), passwordFile(::passwordFile.getData())
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000119{
120 CharArray encodingName(::preferredEncoding.getData());
121 preferredEncoding = encodingNum(encodingName.buf);
122 setMenuKey(CharArray(::menuKey.getData()).buf);
Peter Åstrand55855d52005-01-03 12:01:45 +0000123
124 if (!::autoSelect.hasBeenSet()) {
125 // Default to AutoSelect=0 if -PreferredEncoding or -FullColor is used
126 autoSelect = (!::preferredEncoding.hasBeenSet()
127 && !::fullColour.hasBeenSet()
128 && !::fullColourAlias.hasBeenSet());
129 }
130 if (!::customCompressLevel.hasBeenSet()) {
131 // Default to CustomCompressLevel=1 if CompressLevel is used.
132 customCompressLevel = ::compressLevel.hasBeenSet();
133 }
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000134}
135
136
137void CViewOptions::readFromFile(const char* filename) {
138 FILE* f = fopen(filename, "r");
139 if (!f)
140 throw rdr::Exception("Failed to read configuration file");
141
142 try {
143 char line[4096];
144 CharArray section;
145
146 CharArray hostTmp;
147 int portTmp = 0;
148
149 while (!feof(f)) {
150 // Read the next line
151 if (!fgets(line, sizeof(line), f)) {
152 if (feof(f))
153 break;
154 throw rdr::SystemException("fgets", ferror(f));
155 }
156 int len=strlen(line);
157 if (line[len-1] == '\n') {
158 line[len-1] = 0;
159 len--;
160 }
161
162 // Process the line
163 if (line[0] == ';') {
164 // Comment
165 } else if (line[0] == '[') {
166 // Entering a new section
167 if (!strSplit(&line[1], ']', &section.buf, 0))
168 throw rdr::Exception("bad Section");
169 } else {
170 // Reading an option
171 CharArray name;
172 CharArray value;
173 if (!strSplit(line, '=', &name.buf, &value.buf))
174 throw rdr::Exception("bad Name/Value pair");
175
176 if (stricmp(section.buf, "Connection") == 0) {
177 if (stricmp(name.buf, "Host") == 0) {
178 hostTmp.replaceBuf(value.takeBuf());
179 } else if (stricmp(name.buf, "Port") == 0) {
180 portTmp = atoi(value.buf);
181 } else if (stricmp(name.buf, "UserName") == 0) {
182 userName.replaceBuf(value.takeBuf());
183 } else if (stricmp(name.buf, "Password") == 0) {
184 int len = 0;
185 CharArray obfuscated;
186 rdr::HexInStream::hexStrToBin(value.buf, &obfuscated.buf, &len);
187 if (len == 8) {
188 password.replaceBuf(new char[9]);
189 memcpy(password.buf, obfuscated.buf, 8);
190 vncAuthUnobfuscatePasswd(password.buf);
191 password.buf[8] = 0;
192 }
193 }
194 } else if (stricmp(section.buf, "Options") == 0) {
195 // V4 options
196 if (stricmp(name.buf, "UseLocalCursor") == 0) {
197 useLocalCursor = atoi(value.buf);
198 } else if (stricmp(name.buf, "UseDesktopResize") == 0) {
199 useDesktopResize = atoi(value.buf);
200 } else if (stricmp(name.buf, "FullScreen") == 0) {
201 fullScreen = atoi(value.buf);
202 } else if (stricmp(name.buf, "FullColour") == 0) {
203 fullColour = atoi(value.buf);
204 } else if (stricmp(name.buf, "LowColourLevel") == 0) {
205 lowColourLevel = atoi(value.buf);
206 } else if (stricmp(name.buf, "PreferredEncoding") == 0) {
207 preferredEncoding = encodingNum(value.buf);
208 } else if ((stricmp(name.buf, "AutoDetect") == 0) ||
209 (stricmp(name.buf, "AutoSelect") == 0)) {
210 autoSelect = atoi(value.buf);
211 } else if (stricmp(name.buf, "Shared") == 0) {
212 shared = atoi(value.buf);
213 } else if (stricmp(name.buf, "SendPtrEvents") == 0) {
214 sendPtrEvents = atoi(value.buf);
215 } else if (stricmp(name.buf, "SendKeyEvents") == 0) {
216 sendKeyEvents = atoi(value.buf);
217 } else if (stricmp(name.buf, "SendCutText") == 0) {
218 clientCutText = atoi(value.buf);
219 } else if (stricmp(name.buf, "AcceptCutText") == 0) {
220 serverCutText = atoi(value.buf);
221 } else if (stricmp(name.buf, "Emulate3") == 0) {
222 emulate3 = atoi(value.buf);
223 } else if (stricmp(name.buf, "PointerEventInterval") == 0) {
224 pointerEventInterval = atoi(value.buf);
225 } else if (stricmp(name.buf, "Monitor") == 0) {
226 monitor.replaceBuf(value.takeBuf());
227 } else if (stricmp(name.buf, "MenuKey") == 0) {
228 setMenuKey(value.buf);
Peter Åstrand365427a2004-12-29 10:59:03 +0000229 } else if (stricmp(name.buf, "CustomCompressLevel") == 0) {
230 customCompressLevel = atoi(value.buf);
231 } else if (stricmp(name.buf, "CompressLevel") == 0) {
232 compressLevel = atoi(value.buf);
Peter Åstrand0b870262004-12-28 15:55:46 +0000233 } else if (stricmp(name.buf, "NoJPEG") == 0) {
234 noJpeg = atoi(value.buf);
Peter Åstrand365427a2004-12-29 10:59:03 +0000235 } else if (stricmp(name.buf, "QualityLevel") == 0) {
236 qualityLevel = atoi(value.buf);
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000237 // Legacy options
238 } else if (stricmp(name.buf, "Preferred_Encoding") == 0) {
239 preferredEncoding = atoi(value.buf);
240 } else if (stricmp(name.buf, "8bit") == 0) {
241 fullColour = !atoi(value.buf);
242 } else if (stricmp(name.buf, "FullScreen") == 0) {
243 fullScreen = atoi(value.buf);
244 } else if (stricmp(name.buf, "ViewOnly") == 0) {
245 sendPtrEvents = sendKeyEvents = !atoi(value.buf);
246 } else if (stricmp(name.buf, "DisableClipboard") == 0) {
247 clientCutText = serverCutText = !atoi(value.buf);
248 }
249 }
250 }
251 }
252 fclose(f); f=0;
253
254 // Process the Host and Port
255 if (hostTmp.buf) {
256 int hostLen = strlen(hostTmp.buf) + 2 + 17;
257 host.replaceBuf(new char[hostLen]);
258 strCopy(host.buf, hostTmp.buf, hostLen);
259 if (portTmp) {
260 strncat(host.buf, "::", hostLen-1);
261 char tmp[16];
262 sprintf(tmp, "%d", portTmp);
263 strncat(host.buf, tmp, hostLen-1);
264 }
265 }
266
267 setConfigFileName(filename);
268 } catch (rdr::Exception&) {
269 if (f) fclose(f);
270 throw;
271 }
272}
273
274void CViewOptions::writeToFile(const char* filename) {
275 FILE* f = fopen(filename, "w");
276 if (!f)
277 throw rdr::Exception("Failed to write configuration file");
278
279 try {
280 // - Split server into host and port and save
281 fprintf(f, "[Connection]\n");
282
283 fprintf(f, "Host=%s\n", host.buf);
284 if (userName.buf)
285 fprintf(f, "UserName=%s\n", userName.buf);
286 if (password.buf) {
287 // - Warn the user before saving the password
288 if (MsgBox(0, _T("Do you want to include the VNC Password in this configuration file?\n")
289 _T("Storing the password is more convenient but poses a security risk."),
290 MB_YESNO | MB_DEFBUTTON2 | MB_ICONWARNING) == IDYES) {
291 char obfuscated[9];
292 memset(obfuscated, 0, sizeof(obfuscated));
293 strCopy(obfuscated, password.buf, sizeof(obfuscated));
294 vncAuthObfuscatePasswd(obfuscated);
295 CharArray obfuscatedHex = rdr::HexOutStream::binToHexStr(obfuscated, 8);
296 fprintf(f, "Password=%s\n", obfuscatedHex.buf);
297 }
298 }
299
300 // - Save the other options
301 fprintf(f, "[Options]\n");
302
303 fprintf(f, "UseLocalCursor=%d\n", (int)useLocalCursor);
304 fprintf(f, "UseDesktopResize=%d\n", (int)useDesktopResize);
305 fprintf(f, "FullScreen=%d\n", (int)fullScreen);
306 fprintf(f, "FullColour=%d\n", (int)fullColour);
307 fprintf(f, "LowColourLevel=%d\n", lowColourLevel);
308 fprintf(f, "PreferredEncoding=%s\n", encodingName(preferredEncoding));
309 fprintf(f, "AutoSelect=%d\n", (int)autoSelect);
310 fprintf(f, "Shared=%d\n", (int)shared);
311 fprintf(f, "SendPtrEvents=%d\n", (int)sendPtrEvents);
312 fprintf(f, "SendKeyEvents=%d\n", (int)sendKeyEvents);
313 fprintf(f, "SendCutText=%d\n", (int)clientCutText);
314 fprintf(f, "AcceptCutText=%d\n", (int)serverCutText);
315 fprintf(f, "Emulate3=%d\n", (int)emulate3);
316 fprintf(f, "PointerEventInterval=%d\n", pointerEventInterval);
317 if (monitor.buf)
318 fprintf(f, "Monitor=%s\n", monitor.buf);
319 fprintf(f, "MenuKey=%s\n", CharArray(menuKeyName()).buf);
Peter Åstrand365427a2004-12-29 10:59:03 +0000320 fprintf(f, "CustomCompressLevel=%d\n", customCompressLevel);
321 fprintf(f, "CompressLevel=%d\n", compressLevel);
Peter Åstrand0b870262004-12-28 15:55:46 +0000322 fprintf(f, "NoJPEG=%d\n", noJpeg);
Peter Åstrand365427a2004-12-29 10:59:03 +0000323 fprintf(f, "QualityLevel=%d\n", qualityLevel);
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000324 fclose(f); f=0;
325
326 setConfigFileName(filename);
327 } catch (rdr::Exception&) {
328 if (f) fclose(f);
329 throw;
330 }
331}
332
333
334void CViewOptions::writeDefaults() {
335 RegKey key;
Peter Åstrand9fb4e0e2004-12-30 10:03:00 +0000336 key.createKey(HKEY_CURRENT_USER, _T("Software\\TightVNC\\VNCviewer4"));
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000337 key.setBool(_T("UseLocalCursor"), useLocalCursor);
338 key.setBool(_T("UseDesktopResize"), useDesktopResize);
339 key.setBool(_T("FullScreen"), fullScreen);
340 key.setBool(_T("FullColour"), fullColour);
341 key.setInt(_T("LowColourLevel"), lowColourLevel);
342 key.setString(_T("PreferredEncoding"), TStr(encodingName(preferredEncoding)));
343 key.setBool(_T("AutoSelect"), autoSelect);
344 key.setBool(_T("Shared"), shared);
345 key.setBool(_T("SendPointerEvents"), sendPtrEvents);
346 key.setBool(_T("SendKeyEvents"), sendKeyEvents);
347 key.setBool(_T("ClientCutText"), clientCutText);
348 key.setBool(_T("ServerCutText"), serverCutText);
349 key.setBool(_T("Protocol3.3"), protocol3_3);
350 key.setBool(_T("AcceptBell"), acceptBell);
351 key.setBool(_T("Emulate3"), emulate3);
352 key.setInt(_T("PointerEventInterval"), pointerEventInterval);
353 if (monitor.buf)
354 key.setString(_T("Monitor"), TStr(monitor.buf));
355 key.setString(_T("MenuKey"), TCharArray(menuKeyName()).buf);
Peter Åstrand365427a2004-12-29 10:59:03 +0000356 key.setInt(_T("CustomCompressLevel"), customCompressLevel);
357 key.setInt(_T("CompressLevel"), compressLevel);
Peter Åstrand0b870262004-12-28 15:55:46 +0000358 key.setInt(_T("NoJPEG"), noJpeg);
Peter Åstrand365427a2004-12-29 10:59:03 +0000359 key.setInt(_T("QualityLevel"), qualityLevel);
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000360}
361
362
363void CViewOptions::setUserName(const char* user) {userName.replaceBuf(strDup(user));}
364void CViewOptions::setPassword(const char* pwd) {password.replaceBuf(strDup(pwd));}
365void CViewOptions::setConfigFileName(const char* cfn) {configFileName.replaceBuf(strDup(cfn));}
366void CViewOptions::setHost(const char* h) {host.replaceBuf(strDup(h));}
367void CViewOptions::setMonitor(const char* m) {monitor.replaceBuf(strDup(m));}
368
369void CViewOptions::setMenuKey(const char* keyName) {
370 if (!keyName[0]) {
371 menuKey = 0;
372 } else {
373 menuKey = VK_F8;
374 if (keyName[0] == 'F') {
375 UINT fKey = atoi(&keyName[1]);
376 if (fKey >= 1 && fKey <= 12)
377 menuKey = fKey-1 + VK_F1;
378 }
379 }
380}
381char* CViewOptions::menuKeyName() {
382 int fNum = (menuKey-VK_F1)+1;
383 if (fNum<1 || fNum>12)
384 return strDup("");
385 CharArray menuKeyStr(4);
386 sprintf(menuKeyStr.buf, "F%d", fNum);
387 return menuKeyStr.takeBuf();
388}
389
390
391CViewOptions& CViewOptions::operator=(const CViewOptions& o) {
392 useLocalCursor = o.useLocalCursor;
393 useDesktopResize = o.useDesktopResize;
394 fullScreen = o.fullScreen;
395 fullColour = o.fullColour;
396 lowColourLevel = o.lowColourLevel;
397 preferredEncoding = o.preferredEncoding;
398 autoSelect = o.autoSelect;
399 shared = o.shared;
400 sendPtrEvents = o.sendPtrEvents;
401 sendKeyEvents = o.sendKeyEvents;
402 clientCutText = o.clientCutText;
403 serverCutText = o.serverCutText;
404 emulate3 = o.emulate3;
405 pointerEventInterval = o.pointerEventInterval;
406 protocol3_3 = o.protocol3_3;
407 acceptBell = o.acceptBell;
408 setUserName(o.userName.buf);
409 setPassword(o.password.buf);
410 setConfigFileName(o.configFileName.buf);
411 setHost(o.host.buf);
412 setMonitor(o.monitor.buf);
413 menuKey = o.menuKey;
Peter Åstrand365427a2004-12-29 10:59:03 +0000414 customCompressLevel = o.customCompressLevel;
415 compressLevel = o.compressLevel;
Peter Åstrand0b870262004-12-28 15:55:46 +0000416 noJpeg = o.noJpeg;
Peter Åstrand365427a2004-12-29 10:59:03 +0000417 qualityLevel = o.qualityLevel;
418
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000419 return *this;
Peter Åstranded9d4ae2004-12-07 11:59:14 +0000420}