blob: 6fea19928db80d03e4488c0f05ccc8debf30b9b1 [file] [log] [blame]
Pierre Ossman5156d5e2011-03-09 09:42:34 +00001/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
2 * Copyright 2011 Pierre Ossman <ossman@cendio.se> for Cendio AB
DRCb65bb932011-06-24 03:17:00 +00003 * Copyright (C) 2011 D. R. Commander. All Rights Reserved.
Pierre Ossman5156d5e2011-03-09 09:42:34 +00004 *
5 * This is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This software is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this software; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
18 * USA.
19 */
20
Peter Åstrandc359f362011-08-23 12:04:46 +000021#ifdef HAVE_CONFIG_H
22#include <config.h>
23#endif
24
Pierre Ossman5156d5e2011-03-09 09:42:34 +000025#include <string.h>
26#include <stdio.h>
27#include <stdlib.h>
28#include <errno.h>
29#include <signal.h>
30#include <locale.h>
31#include <sys/stat.h>
32
33#ifdef WIN32
34#include <direct.h>
35#define mkdir(path, mode) _mkdir(path)
36#endif
37
38#include <os/os.h>
39#include <rfb/Logger_stdio.h>
40#include <rfb/SecurityClient.h>
41#include <rfb/Security.h>
42#ifdef HAVE_GNUTLS
43#include <rfb/CSecurityTLS.h>
44#endif
45#include <rfb/LogWriter.h>
46#include <rfb/Timer.h>
47#include <network/TcpSocket.h>
48
49#include <FL/Fl.H>
50#include <FL/Fl_Widget.H>
51#include <FL/fl_ask.H>
Pierre Ossmanb8858222011-04-29 11:51:38 +000052#include <FL/x.H>
Pierre Ossman5156d5e2011-03-09 09:42:34 +000053
54#include "i18n.h"
55#include "parameters.h"
56#include "CConn.h"
Pierre Ossman561ff0c2011-05-13 14:04:59 +000057#include "ServerDialog.h"
Pierre Ossman5156d5e2011-03-09 09:42:34 +000058#include "UserDialog.h"
59
DRCb65bb932011-06-24 03:17:00 +000060#ifdef WIN32
61#include "win32.h"
62#endif
63
Pierre Ossman5156d5e2011-03-09 09:42:34 +000064rfb::LogWriter vlog("main");
65
66using namespace network;
67using namespace rfb;
68using namespace std;
69
Pierre Ossmanb8858222011-04-29 11:51:38 +000070static char aboutText[1024];
DRCd8e93dc2011-07-28 22:13:40 +000071extern const char* buildTime;
Pierre Ossman5156d5e2011-03-09 09:42:34 +000072
73static bool exitMainloop = false;
Pierre Ossmane2ef5c12011-07-12 16:56:34 +000074static const char *exitError = NULL;
Pierre Ossman5156d5e2011-03-09 09:42:34 +000075
Pierre Ossmane2ef5c12011-07-12 16:56:34 +000076void exit_vncviewer(const char *error)
Pierre Ossman5156d5e2011-03-09 09:42:34 +000077{
Pierre Ossmane2ef5c12011-07-12 16:56:34 +000078 // Prioritise the first error we get as that is probably the most
79 // relevant one.
80 if ((error != NULL) && (exitError == NULL))
81 exitError = strdup(error);
82
Pierre Ossman5156d5e2011-03-09 09:42:34 +000083 exitMainloop = true;
84}
85
Pierre Ossmanb8858222011-04-29 11:51:38 +000086void about_vncviewer()
87{
88 fl_message_title(_("About TigerVNC Viewer"));
89 fl_message(aboutText);
90}
91
92static void about_callback(Fl_Widget *widget, void *data)
93{
94 about_vncviewer();
95}
96
Pierre Ossman5156d5e2011-03-09 09:42:34 +000097static void CleanupSignalHandler(int sig)
98{
99 // CleanupSignalHandler allows C++ object cleanup to happen because it calls
100 // exit() rather than the default which is to abort.
101 vlog.info("CleanupSignalHandler called");
102 exit(1);
103}
104
105static void init_fltk()
106{
107 // Basic text size (10pt @ 96 dpi => 13px)
108 FL_NORMAL_SIZE = 13;
109
110#ifndef __APPLE__
111 // Select a FLTK scheme and background color that looks somewhat
112 // close to modern Linux and Windows.
113 Fl::scheme("gtk+");
114 Fl::background(220, 220, 220);
115#else
116 // On Mac OS X there is another scheme that fits better though.
117 Fl::scheme("plastic");
118#endif
119
120 // This makes the "icon" in dialogs rounded, which fits better
121 // with the above schemes.
122 fl_message_icon()->box(FL_UP_BOX);
123
124 // Turn off the annoying behaviour where popups track the mouse.
125 fl_message_hotspot(false);
126
127 // Avoid empty titles for popups
128 fl_message_title_default(_("TigerVNC Viewer"));
129
130#ifdef WIN32
131 // Most "normal" Windows apps use this font for UI elements.
132 Fl::set_font(FL_HELVETICA, "Tahoma");
133#endif
134
135 // FLTK exposes these so that we can translate them.
136 fl_no = _("No");
137 fl_yes = _("Yes");
138 fl_ok = _("OK");
139 fl_cancel = _("Cancel");
140 fl_close = _("Close");
Pierre Ossmanb8858222011-04-29 11:51:38 +0000141
142#ifdef __APPLE__
Pierre Ossman41ba6032011-06-16 11:09:31 +0000143 Fl_Mac_App_Menu::about = _("About ");
144 Fl_Mac_App_Menu::print = ""; // Don't want the print item
145 Fl_Mac_App_Menu::services = _("Services");
146 Fl_Mac_App_Menu::hide = _("Hide ");
147 Fl_Mac_App_Menu::hide_others = _("Hide Others");
148 Fl_Mac_App_Menu::show = _("Show All");
149 Fl_Mac_App_Menu::quit = _("Quit ");
150
Pierre Ossmanb8858222011-04-29 11:51:38 +0000151 fl_mac_set_about(about_callback, NULL);
152#endif
Pierre Ossman5156d5e2011-03-09 09:42:34 +0000153}
154
155static void mkvnchomedir()
156{
157 // Create .vnc in the user's home directory if it doesn't already exist
158 char* homeDir = NULL;
159
160 if (getvnchomedir(&homeDir) == -1) {
161 vlog.error(_("Could not create VNC home directory: can't obtain home "
162 "directory path."));
163 } else {
164 int result = mkdir(homeDir, 0755);
165 if (result == -1 && errno != EEXIST)
166 vlog.error(_("Could not create VNC home directory: %s."), strerror(errno));
167 delete [] homeDir;
168 }
169}
170
171static void usage(const char *programName)
172{
173 fprintf(stderr,
174 "\nusage: %s [parameters] [host:displayNum] [parameters]\n"
175 " %s [parameters] -listen [port] [parameters]\n",
176 programName, programName);
177 fprintf(stderr,"\n"
178 "Parameters can be turned on with -<param> or off with -<param>=0\n"
179 "Parameters which take a value can be specified as "
180 "-<param> <value>\n"
181 "Other valid forms are <param>=<value> -<param>=<value> "
182 "--<param>=<value>\n"
183 "Parameter names are case-insensitive. The parameters are:\n\n");
184 Configuration::listParams(79, 14);
185 exit(1);
186}
187
188int main(int argc, char** argv)
189{
Pierre Ossman561ff0c2011-05-13 14:04:59 +0000190 const char* vncServerName = NULL;
Pierre Ossman5156d5e2011-03-09 09:42:34 +0000191 UserDialog dlg;
192
DRCd8e93dc2011-07-28 22:13:40 +0000193 const char englishAbout[] = N_("TigerVNC Viewer %d-bit v%s (%s)\n"
194 "%s\n"
DRC07baad72011-06-28 05:42:30 +0000195 "Copyright (C) 1999-2011 TigerVNC Team and many others (see README.txt)\n"
Pierre Ossman5156d5e2011-03-09 09:42:34 +0000196 "See http://www.tigervnc.org for information on TigerVNC.");
197
198 setlocale(LC_ALL, "");
199 bindtextdomain(PACKAGE_NAME, LOCALEDIR);
200 textdomain(PACKAGE_NAME);
201
202 rfb::SecurityClient::setDefaults();
203
204 // Write about text to console, still using normal locale codeset
205 snprintf(aboutText, sizeof(aboutText),
DRCd8e93dc2011-07-28 22:13:40 +0000206 gettext(englishAbout), (int)sizeof(size_t)*8, PACKAGE_VERSION,
207 __BUILD__, buildTime);
Pierre Ossman5156d5e2011-03-09 09:42:34 +0000208 fprintf(stderr,"\n%s\n", aboutText);
209
210 // Set gettext codeset to what our GUI toolkit uses. Since we are
211 // passing strings from strerror/gai_strerror to the GUI, these must
212 // be in GUI codeset as well.
213 bind_textdomain_codeset(PACKAGE_NAME, "UTF-8");
214 bind_textdomain_codeset("libc", "UTF-8");
215
216 // Re-create the aboutText for the GUI, now using GUI codeset
217 snprintf(aboutText, sizeof(aboutText),
DRCd8e93dc2011-07-28 22:13:40 +0000218 gettext(englishAbout), (int)sizeof(size_t)*8, PACKAGE_VERSION,
219 __BUILD__, buildTime);
Pierre Ossman5156d5e2011-03-09 09:42:34 +0000220
221 rfb::initStdIOLoggers();
222 rfb::LogWriter::setLogParams("*:stderr:30");
223
224#ifdef SIGHUP
225 signal(SIGHUP, CleanupSignalHandler);
226#endif
227 signal(SIGINT, CleanupSignalHandler);
228 signal(SIGTERM, CleanupSignalHandler);
229
230 init_fltk();
231
232 Configuration::enableViewerParams();
233
DRC5aa06502011-06-23 22:04:46 +0000234 int i = 1;
235 if (!Fl::args(argc, argv, i) || i < argc)
236 for (; i < argc; i++) {
237 if (Configuration::setParam(argv[i]))
238 continue;
Pierre Ossman5156d5e2011-03-09 09:42:34 +0000239
DRC5aa06502011-06-23 22:04:46 +0000240 if (argv[i][0] == '-') {
241 if (i+1 < argc) {
242 if (Configuration::setParam(&argv[i][1], argv[i+1])) {
243 i++;
244 continue;
245 }
Pierre Ossman5156d5e2011-03-09 09:42:34 +0000246 }
DRC5aa06502011-06-23 22:04:46 +0000247 usage(argv[0]);
Pierre Ossman5156d5e2011-03-09 09:42:34 +0000248 }
Pierre Ossman5156d5e2011-03-09 09:42:34 +0000249
DRC5aa06502011-06-23 22:04:46 +0000250 vncServerName = argv[i];
251 }
Pierre Ossman5156d5e2011-03-09 09:42:34 +0000252
253 if (!::autoSelect.hasBeenSet()) {
254 // Default to AutoSelect=0 if -PreferredEncoding or -FullColor is used
255 ::autoSelect.setParam(!::preferredEncoding.hasBeenSet() &&
256 !::fullColour.hasBeenSet() &&
257 !::fullColourAlias.hasBeenSet());
258 }
259 if (!::fullColour.hasBeenSet() && !::fullColourAlias.hasBeenSet()) {
260 // Default to FullColor=0 if AutoSelect=0 && LowColorLevel is set
261 if (!::autoSelect && (::lowColourLevel.hasBeenSet() ||
262 ::lowColourLevelAlias.hasBeenSet())) {
263 ::fullColour.setParam(false);
264 }
265 }
266 if (!::customCompressLevel.hasBeenSet()) {
267 // Default to CustomCompressLevel=1 if CompressLevel is used.
268 ::customCompressLevel.setParam(::compressLevel.hasBeenSet());
269 }
270
271 mkvnchomedir();
272
273 CSecurity::upg = &dlg;
274#ifdef HAVE_GNUTLS
275 CSecurityTLS::msg = &dlg;
276#endif
277
Pierre Ossman561ff0c2011-05-13 14:04:59 +0000278 if (vncServerName == NULL) {
279 vncServerName = ServerDialog::run();
280 if ((vncServerName == NULL) || (vncServerName[0] == '\0'))
281 return 1;
282 }
283
Pierre Ossmane2ef5c12011-07-12 16:56:34 +0000284 CConn *cc = new CConn(vncServerName);
Pierre Ossman5156d5e2011-03-09 09:42:34 +0000285
286 while (!exitMainloop) {
287 int next_timer;
288
289 next_timer = Timer::checkTimeouts();
290 if (next_timer == 0)
291 next_timer = INT_MAX;
292
293 if (Fl::wait((double)next_timer / 1000.0) < 0.0) {
294 vlog.error(_("Internal FLTK error. Exiting."));
295 break;
296 }
297 }
298
Pierre Ossmane2ef5c12011-07-12 16:56:34 +0000299 delete cc;
300
301 if (exitError != NULL)
302 fl_alert(exitError);
303
Pierre Ossman5156d5e2011-03-09 09:42:34 +0000304 return 0;
305}