| /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. |
| * |
| * This is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation; either version 2 of the License, or |
| * (at your option) any later version. |
| * |
| * This software is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this software; if not, write to the Free Software |
| * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
| * USA. |
| */ |
| |
| #include <vncviewer/CConnOptions.h> |
| #include <rfb/Configuration.h> |
| #include <rfb/encodings.h> |
| #include <rfb/LogWriter.h> |
| #include <rfb/ScaleFilters.h> |
| #include <rfb_win32/MsgBox.h> |
| #include <rfb_win32/Registry.h> |
| #include <rfb/SecurityClient.h> |
| #include <rdr/HexInStream.h> |
| #include <rdr/HexOutStream.h> |
| #include <stdlib.h> |
| |
| using namespace rfb; |
| using namespace rfb::win32; |
| |
| static StringParameter passwordFile("PasswordFile", |
| "Password file for VNC authentication", ""); |
| |
| // - Settings stored in the registry & in .vnc files, by Save Defaults and |
| // Save Configuration respectively. |
| |
| static BoolParameter useLocalCursor("UseLocalCursor", "Render the mouse cursor locally", true); |
| static BoolParameter useDesktopResize("UseDesktopResize", "Support dynamic desktop resizing", true); |
| |
| static BoolParameter fullColour("FullColor", |
| "Use full color", true); |
| static AliasParameter fullColourAlias("FullColour", "Alias for FullColor", &fullColour); |
| |
| static IntParameter lowColourLevel("LowColorLevel", |
| "Color level to use on slow connections. " |
| "0 = Very Low (8 colors), 1 = Low (64 colors), 2 = Medium (256 colors)", |
| 2); |
| static AliasParameter lowColourLevelAlias("LowColourLevel", "Alias for LowColorLevel", &lowColourLevel); |
| |
| static BoolParameter fullScreen("FullScreen", |
| "Use the whole display to show the remote desktop." |
| "(Press F8 to access the viewer menu)", |
| false); |
| static StringParameter preferredEncoding("PreferredEncoding", |
| "Preferred encoding to use (Tight, ZRLE, Hextile or" |
| " Raw)", "Tight"); |
| static BoolParameter autoSelect("AutoSelect", |
| "Auto select pixel format and encoding. " |
| "Default if PreferredEncoding and FullColor are not specified.", |
| true); |
| static BoolParameter sharedConnection("Shared", |
| "Allow existing connections to the server to continue." |
| "(Default is to disconnect all other clients)", |
| false); |
| |
| StringParameter desktopSize("DesktopSize", |
| "Reconfigure desktop size on the server on " |
| "connect (if possible)", ""); |
| |
| static BoolParameter sendPtrEvents("SendPointerEvents", |
| "Send pointer (mouse) events to the server.", true); |
| static BoolParameter sendKeyEvents("SendKeyEvents", |
| "Send key presses (and releases) to the server.", true); |
| |
| static BoolParameter clientCutText("ClientCutText", |
| "Send clipboard changes to the server.", true); |
| static BoolParameter serverCutText("ServerCutText", |
| "Accept clipboard changes from the server.", true); |
| |
| static BoolParameter disableWinKeys("DisableWinKeys", |
| "Pass special Windows keys directly to the server.", true); |
| |
| static BoolParameter protocol3_3("Protocol3.3", |
| "Only use protocol version 3.3", false); |
| |
| static IntParameter ptrEventInterval("PointerEventInterval", |
| "The interval to delay between sending one pointer event " |
| "and the next.", 0); |
| static BoolParameter emulate3("Emulate3", |
| "Emulate middle mouse button when left and right buttons " |
| "are used simulatenously.", false); |
| |
| static BoolParameter acceptBell("AcceptBell", |
| "Produce a system beep when requested to by the server.", |
| true); |
| |
| static BoolParameter showToolbar("ShowToolbar", "Show toolbar by default.", true); |
| |
| static StringParameter monitor("Monitor", "The monitor to open the VNC Viewer window on, if available.", ""); |
| static StringParameter menuKey("MenuKey", "The key which brings up the popup menu", "F8"); |
| static BoolParameter autoReconnect("AutoReconnect", "Offer to reconnect to the remote server if the connection" |
| "is dropped because an error occurs.", true); |
| |
| static BoolParameter customCompressLevel("CustomCompressLevel", |
| "Use custom compression level. " |
| "Default if CompressLevel is specified.", false); |
| |
| static IntParameter compressLevel("CompressLevel", |
| "Use specified compression level" |
| "0 = Low, 9 = High", |
| 6); |
| |
| static BoolParameter noJpeg("NoJPEG", |
| "Disable lossy JPEG compression in Tight encoding.", |
| false); |
| |
| static IntParameter qualityLevel("QualityLevel", |
| "JPEG quality level. " |
| "0 = Low, 9 = High", |
| 8); |
| |
| static BoolParameter autoScaling("AutoScaling", |
| "Auto rescale local copy of the remote desktop to the client window.", |
| false); |
| static IntParameter scale("Scale", |
| "Scale local copy of the remote desktop, in percent", |
| 100); |
| |
| CConnOptions::CConnOptions() |
| : useLocalCursor (::useLocalCursor), |
| useDesktopResize(::useDesktopResize), |
| fullScreen(::fullScreen), |
| fullColour(::fullColour), |
| lowColourLevel(::lowColourLevel), |
| preferredEncoding(encodingTight), |
| autoSelect(::autoSelect), |
| shared(::sharedConnection), |
| desktopSize(::desktopSize.getData()), |
| sendPtrEvents(::sendPtrEvents), |
| sendKeyEvents(::sendKeyEvents), |
| showToolbar(::showToolbar), |
| clientCutText(::clientCutText), |
| serverCutText(::serverCutText), |
| disableWinKeys(::disableWinKeys), |
| emulate3(::emulate3), |
| pointerEventInterval(ptrEventInterval), |
| protocol3_3(::protocol3_3), |
| acceptBell(::acceptBell), |
| autoScaling(::autoScaling), |
| scale(::scale), |
| monitor(::monitor.getData()), |
| autoReconnect(::autoReconnect), |
| customCompressLevel(::customCompressLevel), |
| compressLevel(::compressLevel), |
| noJpeg(::noJpeg), |
| qualityLevel(::qualityLevel), |
| passwordFile(::passwordFile.getData()) |
| { |
| char *sectypes; |
| |
| if (autoSelect) { |
| preferredEncoding = encodingTight; |
| } else { |
| CharArray encodingName(::preferredEncoding.getData()); |
| preferredEncoding = encodingNum(encodingName.buf); |
| } |
| setMenuKey(CharArray(::menuKey.getData()).buf); |
| |
| if (!::autoSelect.hasBeenSet()) { |
| // Default to AutoSelect=0 if -PreferredEncoding or -FullColor is used |
| autoSelect = (!::preferredEncoding.hasBeenSet() |
| && !::fullColour.hasBeenSet() |
| && !::fullColourAlias.hasBeenSet()); |
| } |
| if (!::customCompressLevel.hasBeenSet()) { |
| // Default to CustomCompressLevel=1 if CompressLevel is used. |
| customCompressLevel = ::compressLevel.hasBeenSet(); |
| } |
| |
| sectypes = SecurityClient::secTypes.getDefaultStr(); |
| secTypes = parseSecTypes(sectypes); |
| delete [] sectypes; |
| } |
| |
| |
| void CConnOptions::readFromFile(const char* filename) { |
| FILE* f = fopen(filename, "r"); |
| if (!f) |
| throw rdr::Exception("Failed to read configuration file"); |
| |
| try { |
| char line[4096]; |
| CharArray section; |
| |
| CharArray hostTmp; |
| int portTmp = 0; |
| |
| while (!feof(f)) { |
| // Read the next line |
| if (!fgets(line, sizeof(line), f)) { |
| if (feof(f)) |
| break; |
| throw rdr::SystemException("fgets", ferror(f)); |
| } |
| int len=strlen(line); |
| if (line[len-1] == '\n') { |
| line[len-1] = 0; |
| len--; |
| } |
| |
| // Process the line |
| if (line[0] == ';') { |
| // Comment |
| } else if (line[0] == '[') { |
| // Entering a new section |
| if (!strSplit(&line[1], ']', §ion.buf, 0)) |
| throw rdr::Exception("bad Section"); |
| } else { |
| // Reading an option |
| CharArray name; |
| CharArray value; |
| if (!strSplit(line, '=', &name.buf, &value.buf)) |
| throw rdr::Exception("bad Name/Value pair"); |
| |
| if (stricmp(section.buf, "Connection") == 0) { |
| if (stricmp(name.buf, "Host") == 0) { |
| hostTmp.replaceBuf(value.takeBuf()); |
| } else if (stricmp(name.buf, "Port") == 0) { |
| portTmp = atoi(value.buf); |
| } else if (stricmp(name.buf, "UserName") == 0) { |
| userName.replaceBuf(value.takeBuf()); |
| } else if (stricmp(name.buf, "Password") == 0) { |
| ObfuscatedPasswd obfPwd; |
| rdr::HexInStream::hexStrToBin(value.buf, (char**)&obfPwd.buf, &obfPwd.length); |
| PlainPasswd passwd(obfPwd); |
| password.replaceBuf(passwd.takeBuf()); |
| } |
| } else if (stricmp(section.buf, "Options") == 0) { |
| // V4 options |
| if (stricmp(name.buf, "UseLocalCursor") == 0) { |
| useLocalCursor = atoi(value.buf); |
| } else if (stricmp(name.buf, "UseDesktopResize") == 0) { |
| useDesktopResize = atoi(value.buf); |
| } else if (stricmp(name.buf, "FullScreen") == 0) { |
| fullScreen = atoi(value.buf); |
| } else if (stricmp(name.buf, "FullColour") == 0) { |
| fullColour = atoi(value.buf); |
| } else if (stricmp(name.buf, "LowColourLevel") == 0) { |
| lowColourLevel = atoi(value.buf); |
| } else if (stricmp(name.buf, "PreferredEncoding") == 0) { |
| preferredEncoding = encodingNum(value.buf); |
| } else if ((stricmp(name.buf, "AutoDetect") == 0) || |
| (stricmp(name.buf, "AutoSelect") == 0)) { |
| autoSelect = atoi(value.buf); |
| } else if (stricmp(name.buf, "Shared") == 0) { |
| shared = atoi(value.buf); |
| } else if (stricmp(name.buf, "SendPtrEvents") == 0) { |
| sendPtrEvents = atoi(value.buf); |
| } else if (stricmp(name.buf, "SendKeyEvents") == 0) { |
| sendKeyEvents = atoi(value.buf); |
| } else if (stricmp(name.buf, "SendCutText") == 0) { |
| clientCutText = atoi(value.buf); |
| } else if (stricmp(name.buf, "AcceptCutText") == 0) { |
| serverCutText = atoi(value.buf); |
| } else if (stricmp(name.buf, "DisableWinKeys") == 0) { |
| disableWinKeys = atoi(value.buf); |
| } else if (stricmp(name.buf, "AcceptBell") == 0) { |
| acceptBell = atoi(value.buf); |
| } else if (stricmp(name.buf, "Emulate3") == 0) { |
| emulate3 = atoi(value.buf); |
| } else if (stricmp(name.buf, "ShowToolbar") == 0) { |
| showToolbar = atoi(value.buf); |
| } else if (stricmp(name.buf, "PointerEventInterval") == 0) { |
| pointerEventInterval = atoi(value.buf); |
| } else if (stricmp(name.buf, "Monitor") == 0) { |
| monitor.replaceBuf(value.takeBuf()); |
| } else if (stricmp(name.buf, "MenuKey") == 0) { |
| setMenuKey(value.buf); |
| } else if (stricmp(name.buf, "AutoReconnect") == 0) { |
| autoReconnect = atoi(value.buf); |
| |
| } else if (stricmp(name.buf, "CustomCompressLevel") == 0) { |
| customCompressLevel = atoi(value.buf); |
| } else if (stricmp(name.buf, "CompressLevel") == 0) { |
| compressLevel = atoi(value.buf); |
| } else if (stricmp(name.buf, "NoJPEG") == 0) { |
| noJpeg = atoi(value.buf); |
| } else if (stricmp(name.buf, "QualityLevel") == 0) { |
| qualityLevel = atoi(value.buf); |
| // Legacy options |
| } else if (stricmp(name.buf, "Preferred_Encoding") == 0) { |
| preferredEncoding = atoi(value.buf); |
| } else if (stricmp(name.buf, "8bit") == 0) { |
| fullColour = !atoi(value.buf); |
| } else if (stricmp(name.buf, "FullScreen") == 0) { |
| fullScreen = atoi(value.buf); |
| } else if (stricmp(name.buf, "ViewOnly") == 0) { |
| sendPtrEvents = sendKeyEvents = !atoi(value.buf); |
| } else if (stricmp(name.buf, "DisableClipboard") == 0) { |
| clientCutText = serverCutText = !atoi(value.buf); |
| } else if (stricmp(name.buf, "AutoScaling") == 0) { |
| autoScaling = atoi(value.buf); |
| } else if (stricmp(name.buf, "Scale") == 0) { |
| scale = atoi(value.buf); |
| } else if (stricmp(name.buf, "SecurityTypes") == 0) { |
| secTypes = parseSecTypes(value.buf); |
| } |
| } |
| } |
| } |
| fclose(f); f=0; |
| |
| // Process the Host and Port |
| if (hostTmp.buf) { |
| int hostLen = strlen(hostTmp.buf) + 2 + 17; |
| host.replaceBuf(new char[hostLen]); |
| strCopy(host.buf, hostTmp.buf, hostLen); |
| if (portTmp) { |
| strncat(host.buf, "::", hostLen-1); |
| char tmp[16]; |
| sprintf(tmp, "%d", portTmp); |
| strncat(host.buf, tmp, hostLen-1); |
| } |
| } |
| |
| // If AutoSelect is enabled then override the preferred encoding |
| if (autoSelect) |
| preferredEncoding = encodingZRLE; |
| |
| setConfigFileName(filename); |
| } catch (rdr::Exception&) { |
| if (f) fclose(f); |
| throw; |
| } |
| } |
| |
| void CConnOptions::writeToFile(const char* filename) { |
| FILE* f = fopen(filename, "w"); |
| if (!f) |
| throw rdr::Exception("Failed to write configuration file"); |
| |
| try { |
| // - Split server into host and port and save |
| fprintf(f, "[Connection]\n"); |
| |
| fprintf(f, "Host=%s\n", host.buf); |
| if (userName.buf) |
| fprintf(f, "UserName=%s\n", userName.buf); |
| if (password.buf) { |
| // - Warn the user before saving the password |
| if (MsgBox(0, _T("Do you want to include the VNC Password in this configuration file?\n") |
| _T("Storing the password is more convenient but poses a security risk."), |
| MB_YESNO | MB_DEFBUTTON2 | MB_ICONWARNING) == IDYES) { |
| ObfuscatedPasswd obfPwd(password); |
| CharArray obfuscatedHex(rdr::HexOutStream::binToHexStr(obfPwd.buf, obfPwd.length)); |
| fprintf(f, "Password=%s\n", obfuscatedHex.buf); |
| } |
| } |
| |
| // - Save the other options |
| fprintf(f, "[Options]\n"); |
| |
| fprintf(f, "UseLocalCursor=%d\n", (int)useLocalCursor); |
| fprintf(f, "UseDesktopResize=%d\n", (int)useDesktopResize); |
| fprintf(f, "FullScreen=%d\n", (int)fullScreen); |
| fprintf(f, "FullColour=%d\n", (int)fullColour); |
| fprintf(f, "LowColourLevel=%d\n", lowColourLevel); |
| fprintf(f, "PreferredEncoding=%s\n", encodingName(preferredEncoding)); |
| fprintf(f, "AutoSelect=%d\n", (int)autoSelect); |
| fprintf(f, "Shared=%d\n", (int)shared); |
| fprintf(f, "SendPtrEvents=%d\n", (int)sendPtrEvents); |
| fprintf(f, "SendKeyEvents=%d\n", (int)sendKeyEvents); |
| fprintf(f, "SendCutText=%d\n", (int)clientCutText); |
| fprintf(f, "AcceptCutText=%d\n", (int)serverCutText); |
| fprintf(f, "DisableWinKeys=%d\n", (int)disableWinKeys); |
| fprintf(f, "AcceptBell=%d\n", (int)acceptBell); |
| fprintf(f, "Emulate3=%d\n", (int)emulate3); |
| fprintf(f, "ShowToolbar=%d\n", (int)showToolbar); |
| fprintf(f, "PointerEventInterval=%d\n", pointerEventInterval); |
| if (monitor.buf) |
| fprintf(f, "Monitor=%s\n", monitor.buf); |
| fprintf(f, "MenuKey=%s\n", CharArray(menuKeyName()).buf); |
| fprintf(f, "AutoReconnect=%d\n", (int)autoReconnect); |
| fprintf(f, "CustomCompressLevel=%d\n", customCompressLevel); |
| fprintf(f, "CompressLevel=%d\n", compressLevel); |
| fprintf(f, "NoJPEG=%d\n", noJpeg); |
| fprintf(f, "QualityLevel=%d\n", qualityLevel); |
| fprintf(f, "AutoScaling=%d\n", (int)autoScaling); |
| fprintf(f, "Scale=%d\n", scale); |
| |
| fprintf(f, "SecurityTypes="); |
| std::list<rdr::U32>::iterator i; |
| for (i = secTypes.begin(); i != secTypes.end(); i++) |
| fprintf(f, "%s,", secTypeName(*i)); |
| fprintf(f, "\n"); |
| |
| fclose(f); f=0; |
| |
| setConfigFileName(filename); |
| } catch (rdr::Exception&) { |
| if (f) fclose(f); |
| throw; |
| } |
| } |
| |
| |
| void CConnOptions::writeDefaults() { |
| RegKey key; |
| key.createKey(HKEY_CURRENT_USER, _T("Software\\TigerVNC\\VNCviewer4")); |
| key.setBool(_T("UseLocalCursor"), useLocalCursor); |
| key.setBool(_T("UseDesktopResize"), useDesktopResize); |
| key.setBool(_T("FullScreen"), fullScreen); |
| key.setBool(_T("FullColour"), fullColour); |
| key.setInt(_T("LowColourLevel"), lowColourLevel); |
| key.setString(_T("PreferredEncoding"), TStr(encodingName(preferredEncoding))); |
| key.setBool(_T("AutoSelect"), autoSelect); |
| key.setBool(_T("Shared"), shared); |
| key.setBool(_T("SendPointerEvents"), sendPtrEvents); |
| key.setBool(_T("SendKeyEvents"), sendKeyEvents); |
| key.setBool(_T("ClientCutText"), clientCutText); |
| key.setBool(_T("ServerCutText"), serverCutText); |
| key.setBool(_T("DisableWinKeys"), disableWinKeys); |
| key.setBool(_T("Protocol3.3"), protocol3_3); |
| key.setBool(_T("AcceptBell"), acceptBell); |
| key.setBool(_T("ShowToolbar"), showToolbar); |
| key.setBool(_T("Emulate3"), emulate3); |
| key.setInt(_T("PointerEventInterval"), pointerEventInterval); |
| if (monitor.buf) |
| key.setString(_T("Monitor"), TStr(monitor.buf)); |
| key.setString(_T("MenuKey"), TCharArray(menuKeyName()).buf); |
| key.setBool(_T("AutoReconnect"), autoReconnect); |
| key.setInt(_T("CustomCompressLevel"), customCompressLevel); |
| key.setInt(_T("CompressLevel"), compressLevel); |
| key.setInt(_T("NoJPEG"), noJpeg); |
| key.setInt(_T("QualityLevel"), qualityLevel); |
| key.setBool(_T("AutoScaling"), autoScaling); |
| key.setInt(_T("Scale"), scale); |
| } |
| |
| |
| void CConnOptions::setUserName(const char* user) {userName.replaceBuf(strDup(user));} |
| void CConnOptions::setPassword(const char* pwd) {password.replaceBuf(strDup(pwd));} |
| void CConnOptions::setConfigFileName(const char* cfn) {configFileName.replaceBuf(strDup(cfn));} |
| void CConnOptions::setHost(const char* h) {host.replaceBuf(strDup(h));} |
| void CConnOptions::setMonitor(const char* m) {monitor.replaceBuf(strDup(m));} |
| |
| void CConnOptions::setMenuKey(const char* keyName) { |
| if (!keyName[0]) { |
| menuKey = 0; |
| } else { |
| menuKey = VK_F8; |
| if (keyName[0] == 'F') { |
| UINT fKey = atoi(&keyName[1]); |
| if (fKey >= 1 && fKey <= 12) |
| menuKey = fKey-1 + VK_F1; |
| } |
| } |
| } |
| char* CConnOptions::menuKeyName() { |
| int fNum = (menuKey-VK_F1)+1; |
| if (fNum<1 || fNum>12) |
| return strDup(""); |
| CharArray menuKeyStr(4); |
| sprintf(menuKeyStr.buf, "F%d", fNum); |
| return menuKeyStr.takeBuf(); |
| } |
| |
| |
| CConnOptions& CConnOptions::operator=(const CConnOptions& o) { |
| useLocalCursor = o.useLocalCursor; |
| useDesktopResize = o.useDesktopResize; |
| fullScreen = o.fullScreen; |
| fullColour = o.fullColour; |
| lowColourLevel = o.lowColourLevel; |
| preferredEncoding = o.preferredEncoding; |
| autoSelect = o.autoSelect; |
| shared = o.shared; |
| sendPtrEvents = o.sendPtrEvents; |
| sendKeyEvents = o.sendKeyEvents; |
| clientCutText = o.clientCutText; |
| serverCutText = o.serverCutText; |
| disableWinKeys = o.disableWinKeys; |
| emulate3 = o.emulate3; |
| pointerEventInterval = o.pointerEventInterval; |
| protocol3_3 = o.protocol3_3; |
| acceptBell = o.acceptBell; |
| showToolbar = o.showToolbar; |
| setUserName(o.userName.buf); |
| setPassword(o.password.buf); |
| setConfigFileName(o.configFileName.buf); |
| setHost(o.host.buf); |
| setMonitor(o.monitor.buf); |
| menuKey = o.menuKey; |
| autoReconnect = o.autoReconnect; |
| customCompressLevel = o.customCompressLevel; |
| compressLevel = o.compressLevel; |
| noJpeg = o.noJpeg; |
| qualityLevel = o.qualityLevel; |
| autoScaling = o.autoScaling; |
| scale = o.scale; |
| secTypes = o.secTypes; |
| |
| return *this; |
| } |