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