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