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