Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

vncviewer.cxx 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396
  1. /* Copyright (C) 2002-2005 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. // All-new VNC viewer for X.
  20. //
  21. #include <string.h>
  22. #include <stdio.h>
  23. #include <ctype.h>
  24. #include <stdlib.h>
  25. #include <sys/time.h>
  26. #include <sys/types.h>
  27. #include <sys/stat.h>
  28. #include <sys/wait.h>
  29. #include <unistd.h>
  30. #include <errno.h>
  31. #include <signal.h>
  32. #include <rfb/Logger_stdio.h>
  33. #include <rfb/LogWriter.h>
  34. #include <network/TcpSocket.h>
  35. #include "TXWindow.h"
  36. #include "TXMsgBox.h"
  37. #include "CConn.h"
  38. #include <intl/gettext.h>
  39. #define _(String) gettext (String)
  40. #define gettext_noop(String) String
  41. #define N_(String) gettext_noop (String)
  42. rfb::LogWriter vlog("main");
  43. using namespace network;
  44. using namespace rfb;
  45. using namespace std;
  46. IntParameter pointerEventInterval("PointerEventInterval",
  47. "Time in milliseconds to rate-limit"
  48. " successive pointer events", 0);
  49. IntParameter wmDecorationWidth("WMDecorationWidth", "Width of window manager "
  50. "decoration around a window", 6);
  51. IntParameter wmDecorationHeight("WMDecorationHeight", "Height of window "
  52. "manager decoration around a window", 24);
  53. StringParameter passwordFile("PasswordFile",
  54. "Password file for VNC authentication", "");
  55. AliasParameter rfbauth("passwd", "Alias for PasswordFile", &passwordFile);
  56. BoolParameter useLocalCursor("UseLocalCursor",
  57. "Render the mouse cursor locally", true);
  58. BoolParameter dotWhenNoCursor("DotWhenNoCursor",
  59. "Show the dot cursor when the server sends an "
  60. "invisible cursor", true);
  61. BoolParameter autoSelect("AutoSelect",
  62. "Auto select pixel format and encoding. "
  63. "Default if PreferredEncoding and FullColor are not specified.",
  64. true);
  65. BoolParameter fullColour("FullColor",
  66. "Use full color", true);
  67. AliasParameter fullColourAlias("FullColour", "Alias for FullColor", &fullColour);
  68. IntParameter lowColourLevel("LowColorLevel",
  69. "Color level to use on slow connections. "
  70. "0 = Very Low (8 colors), 1 = Low (64 colors), "
  71. "2 = Medium (256 colors)", 2);
  72. AliasParameter lowColourLevelAlias("LowColourLevel", "Alias for LowColorLevel", &lowColourLevel);
  73. StringParameter preferredEncoding("PreferredEncoding",
  74. "Preferred encoding to use (Tight, ZRLE, Hextile or"
  75. " Raw)", "Tight");
  76. BoolParameter fullScreen("FullScreen", "Full screen mode", false);
  77. BoolParameter viewOnly("ViewOnly",
  78. "Don't send any mouse or keyboard events to the server",
  79. false);
  80. BoolParameter shared("Shared",
  81. "Don't disconnect other viewers upon connection - "
  82. "share the desktop instead",
  83. false);
  84. BoolParameter acceptClipboard("AcceptClipboard",
  85. "Accept clipboard changes from the server",
  86. true);
  87. BoolParameter sendClipboard("SendClipboard",
  88. "Send clipboard changes to the server", true);
  89. BoolParameter sendPrimary("SendPrimary",
  90. "Send the primary selection and cut buffer to the "
  91. "server as well as the clipboard selection",
  92. true);
  93. BoolParameter listenMode("listen", "Listen for connections from VNC servers",
  94. false);
  95. StringParameter geometry("geometry", "X geometry specification", "");
  96. StringParameter displayname("display", "The X display", "");
  97. StringParameter via("via", "Gateway to tunnel via", "");
  98. BoolParameter customCompressLevel("CustomCompressLevel",
  99. "Use custom compression level. "
  100. "Default if CompressLevel is specified.", false);
  101. IntParameter compressLevel("CompressLevel",
  102. "Use specified compression level"
  103. "0 = Low, 9 = High",
  104. 6);
  105. BoolParameter noJpeg("NoJPEG",
  106. "Disable lossy JPEG compression in Tight encoding.",
  107. false);
  108. IntParameter qualityLevel("QualityLevel",
  109. "JPEG quality level. "
  110. "0 = Low, 9 = High",
  111. 6);
  112. char aboutText[1024];
  113. char* programName;
  114. extern char buildtime[];
  115. static void CleanupSignalHandler(int sig)
  116. {
  117. // CleanupSignalHandler allows C++ object cleanup to happen because it calls
  118. // exit() rather than the default which is to abort.
  119. vlog.info("CleanupSignalHandler called");
  120. exit(1);
  121. }
  122. // XLoginIconifier is a class which iconifies the XDM login window when it has
  123. // grabbed the keyboard, thus releasing the grab, allowing the viewer to use
  124. // the keyboard. It remaps the xlogin window on exit.
  125. class XLoginIconifier {
  126. public:
  127. Display* dpy;
  128. Window xlogin;
  129. XLoginIconifier() : dpy(0), xlogin(0) {}
  130. void iconify(Display* dpy_) {
  131. dpy = dpy_;
  132. if (XGrabKeyboard(dpy, DefaultRootWindow(dpy), False, GrabModeSync,
  133. GrabModeSync, CurrentTime) == GrabSuccess) {
  134. XUngrabKeyboard(dpy, CurrentTime);
  135. } else {
  136. xlogin = TXWindow::windowWithName(dpy, DefaultRootWindow(dpy), "xlogin");
  137. if (xlogin) {
  138. XIconifyWindow(dpy, xlogin, DefaultScreen(dpy));
  139. XSync(dpy, False);
  140. }
  141. }
  142. }
  143. ~XLoginIconifier() {
  144. if (xlogin) {
  145. fprintf(stderr,"~XLoginIconifier remapping xlogin\n");
  146. XMapWindow(dpy, xlogin);
  147. XFlush(dpy);
  148. sleep(1);
  149. }
  150. }
  151. };
  152. static XLoginIconifier xloginIconifier;
  153. static void usage()
  154. {
  155. fprintf(stderr,
  156. "\nusage: %s [parameters] [host:displayNum] [parameters]\n"
  157. " %s [parameters] -listen [port] [parameters]\n",
  158. programName,programName);
  159. fprintf(stderr,"\n"
  160. "Parameters can be turned on with -<param> or off with -<param>=0\n"
  161. "Parameters which take a value can be specified as "
  162. "-<param> <value>\n"
  163. "Other valid forms are <param>=<value> -<param>=<value> "
  164. "--<param>=<value>\n"
  165. "Parameter names are case-insensitive. The parameters are:\n\n");
  166. Configuration::listParams(79, 14);
  167. exit(1);
  168. }
  169. /* Tunnelling support. */
  170. static void
  171. interpretViaParam (char **gatewayHost, char **remoteHost,
  172. int *remotePort, char **vncServerName,
  173. int localPort)
  174. {
  175. const int SERVER_PORT_OFFSET = 5900;
  176. char *pos = strchr (*vncServerName, ':');
  177. if (pos == NULL)
  178. *remotePort = SERVER_PORT_OFFSET;
  179. else {
  180. int portOffset = SERVER_PORT_OFFSET;
  181. size_t len;
  182. *pos++ = '\0';
  183. len = strlen (pos);
  184. if (*pos == ':') {
  185. /* Two colons is an absolute port number, not an offset. */
  186. pos++;
  187. len--;
  188. portOffset = 0;
  189. }
  190. if (!len || strspn (pos, "-0123456789") != len )
  191. usage ();
  192. *remotePort = atoi (pos) + portOffset;
  193. }
  194. if (**vncServerName != '\0')
  195. *remoteHost = *vncServerName;
  196. *gatewayHost = strDup (via.getValueStr ());
  197. *vncServerName = new char[50];
  198. sprintf (*vncServerName, "localhost::%d", localPort);
  199. }
  200. #ifndef HAVE_SETENV
  201. int
  202. setenv(const char *envname, const char * envval, int overwrite)
  203. {
  204. if (envname && envval) {
  205. char * envp = NULL;
  206. envp = (char*)malloc(strlen(envname) + strlen(envval) + 2);
  207. if (envp) {
  208. // The putenv API guarantees memory leaks when
  209. // changing environment variables repeatedly.
  210. sprintf(envp, "%s=%s", envname, envval);
  211. // Cannot free envp
  212. putenv(envp);
  213. return(0);
  214. }
  215. }
  216. return(-1);
  217. }
  218. #endif
  219. static void
  220. createTunnel (const char *gatewayHost, const char *remoteHost,
  221. int remotePort, int localPort)
  222. {
  223. char *cmd = getenv ("VNC_VIA_CMD");
  224. char *percent;
  225. char lport[10], rport[10];
  226. sprintf (lport, "%d", localPort);
  227. sprintf (rport, "%d", remotePort);
  228. setenv ("G", gatewayHost, 1);
  229. setenv ("H", remoteHost, 1);
  230. setenv ("R", rport, 1);
  231. setenv ("L", lport, 1);
  232. if (!cmd)
  233. cmd = "/usr/bin/ssh -f -L \"$L\":\"$H\":\"$R\" \"$G\" sleep 20";
  234. /* Compatibility with TightVNC's method. */
  235. while ((percent = strchr (cmd, '%')) != NULL)
  236. *percent = '$';
  237. system (cmd);
  238. }
  239. int main(int argc, char** argv)
  240. {
  241. setlocale(LC_ALL, "");
  242. bindtextdomain(PACKAGE, LOCALEDIR);
  243. textdomain(PACKAGE);
  244. snprintf(aboutText, sizeof(aboutText),
  245. _("TightVNC viewer for X version 1.5 - built %s\n"
  246. "Copyright (C) 2002-2005 RealVNC Ltd.\n"
  247. "Copyright (C) 2000-2004 Constantin Kaplinsky\n"
  248. "Copyright (C) 2004-2005 Peter Astrand, Cendio AB\n"
  249. "See http://www.tightvnc.com for information on TightVNC."),
  250. buildtime);
  251. fprintf(stderr,"\n%s\n", aboutText);
  252. bind_textdomain_codeset(PACKAGE, "iso-8859-1");
  253. rfb::initStdIOLoggers();
  254. rfb::LogWriter::setLogParams("*:stderr:30");
  255. signal(SIGHUP, CleanupSignalHandler);
  256. signal(SIGINT, CleanupSignalHandler);
  257. signal(SIGTERM, CleanupSignalHandler);
  258. programName = argv[0];
  259. char* vncServerName = 0;
  260. Display* dpy = 0;
  261. for (int i = 1; i < argc; i++) {
  262. if (Configuration::setParam(argv[i]))
  263. continue;
  264. if (argv[i][0] == '-') {
  265. if (i+1 < argc) {
  266. if (Configuration::setParam(&argv[i][1], argv[i+1])) {
  267. i++;
  268. continue;
  269. }
  270. }
  271. usage();
  272. }
  273. vncServerName = argv[i];
  274. }
  275. // Create .vnc in the user's home directory if it doesn't already exist
  276. char* homeDir = getenv("HOME");
  277. if (homeDir) {
  278. CharArray vncDir(strlen(homeDir)+6);
  279. sprintf(vncDir.buf, "%s/.vnc", homeDir);
  280. int result = mkdir(vncDir.buf, 0755);
  281. if (result == -1 && errno != EEXIST)
  282. vlog.error("Could not create .vnc directory: %s.", strerror(errno));
  283. } else
  284. vlog.error("Could not create .vnc directory: environment variable $HOME not set.");
  285. if (!::autoSelect.hasBeenSet()) {
  286. // Default to AutoSelect=0 if -PreferredEncoding or -FullColor is used
  287. ::autoSelect.setParam(!::preferredEncoding.hasBeenSet()
  288. && !::fullColour.hasBeenSet()
  289. && !::fullColourAlias.hasBeenSet());
  290. }
  291. if (!::customCompressLevel.hasBeenSet()) {
  292. // Default to CustomCompressLevel=1 if CompressLevel is used.
  293. ::customCompressLevel.setParam(::compressLevel.hasBeenSet());
  294. }
  295. try {
  296. /* Tunnelling support. */
  297. if (strlen (via.getValueStr ()) > 0) {
  298. char *gatewayHost = "";
  299. char *remoteHost = "localhost";
  300. int localPort = findFreeTcpPort ();
  301. int remotePort;
  302. if (!vncServerName)
  303. usage();
  304. interpretViaParam (&gatewayHost, &remoteHost, &remotePort,
  305. &vncServerName, localPort);
  306. createTunnel (gatewayHost, remoteHost, remotePort, localPort);
  307. }
  308. Socket* sock = 0;
  309. if (listenMode) {
  310. int port = 5500;
  311. if (vncServerName && isdigit(vncServerName[0]))
  312. port = atoi(vncServerName);
  313. TcpListener listener(port);
  314. vlog.info("Listening on port %d\n",port);
  315. while (true) {
  316. sock = listener.accept();
  317. int pid = fork();
  318. if (pid < 0) { perror("fork"); exit(1); }
  319. if (pid == 0) break; // child
  320. delete sock;
  321. int status;
  322. while (wait3(&status, WNOHANG, 0) > 0) ;
  323. }
  324. }
  325. CharArray displaynameStr(displayname.getData());
  326. if (!(dpy = XOpenDisplay(TXWindow::strEmptyToNull(displaynameStr.buf)))) {
  327. fprintf(stderr,"%s: unable to open display \"%s\"\n",
  328. programName, XDisplayName(displaynameStr.buf));
  329. exit(1);
  330. }
  331. TXWindow::init(dpy, "Vncviewer");
  332. xloginIconifier.iconify(dpy);
  333. CConn cc(dpy, argc, argv, sock, vncServerName, listenMode);
  334. // X events are processed whenever reading from the socket would block.
  335. while (true) {
  336. cc.getInStream()->check(1);
  337. cc.processMsg();
  338. }
  339. } catch (rdr::EndOfStream& e) {
  340. vlog.info(e.str());
  341. } catch (rdr::Exception& e) {
  342. vlog.error(e.str());
  343. if (dpy) {
  344. TXMsgBox msgBox(dpy, e.str(), MB_OK, "VNC Viewer: Information");
  345. msgBox.show();
  346. }
  347. return 1;
  348. }
  349. return 0;
  350. }