]> git.sur5r.net Git - bacula/bacula/blobdiff - bacula/src/gnome2-console/console.c
This commit was manufactured by cvs2svn to create tag
[bacula/bacula] / bacula / src / gnome2-console / console.c
index 1fb76c08d4eded258c87f46eaadb72d6675e585b..38fc765ac94be74363b44cdf143044cdb991fd9b 100644 (file)
@@ -3,26 +3,22 @@
  *   Bacula GNOME Console interface to the Director
  *
  *     Kern Sibbald, March MMII
- *     
+ *
  *     Version $Id$
  */
-
 /*
-   Copyright (C) 2002 Kern Sibbald and John Walker
+   Copyright (C) 2002-2005 Kern Sibbald
 
    This program 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.
+   version 2 as amended with additional clauses defined in the
+   file LICENSE in the main source directory.
 
    This program 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.
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
+   the file LICENSE for additional details.
 
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  */
 
 #include "bacula.h"
 #include "support.h"
 
 /* Imported functions */
-int authenticate_director(JCR *jcr, DIRRES *director);
-       
+int authenticate_director(JCR *jcr, DIRRES *director, CONRES *cons);
+void select_restore_setup();
+
+/* Dummy functions */
+int generate_daemon_event(JCR *jcr, const char *event) { return 1; }
+
 /* Exported variables */
-GtkWidget *app1;            /* application window */
-GtkWidget *text1;           /* text window */
-GtkWidget *entry1;          /* entry box */
-GtkWidget *status1;         /* status bar */
-GtkWidget *combo1;          /* director combo */
-GtkWidget *scroll1;         /* main scroll bar */
-GtkWidget *run_dialog;      /* run dialog */
-GtkWidget *dir_dialog;      /* director selection dialog */
+GtkWidget *console;   /* application window */
+GtkWidget *text1;            /* text window */
+GtkWidget *entry1;           /* entry box */
+GtkWidget *status1;          /* status bar */
+GtkWidget *combo1;           /* director combo */
+GtkWidget *scroll1;          /* main scroll bar */
+GtkWidget *run_dialog;       /* run dialog */
+GtkWidget *dir_dialog;       /* director selection dialog */
 GtkWidget *restore_dialog;   /* restore dialog */
-GtkWidget *restore_files;    /* restore files dialog */
+GtkWidget *restore_file_selection;
 GtkWidget *dir_select;
-GtkWidget *about1;          /* about box */
+GtkWidget *about1;           /* about box */
 GtkWidget *label_dialog;
-GdkFont   *text_font = NULL;
 PangoFontDescription *font_desc;
+PangoFontDescription *console_font_desc = NULL;
 pthread_mutex_t cmd_mutex = PTHREAD_MUTEX_INITIALIZER;
-pthread_cond_t cmd_wait;
+pthread_cond_t  cmd_wait;
 char cmd[1000];
 int reply;
 BSOCK *UA_sock = NULL;
@@ -60,43 +60,135 @@ GList *messages_list, *pool_list, *storage_list;
 GList *type_list, *level_list;
 
 /* Forward referenced functions */
-static void terminate_console(int sig);
-static gint message_handler(gpointer data);
-static int initial_connect_to_director(gpointer data);
+void terminate_console(int sig);
+
+extern "C" {
+    static gint message_handler(gpointer data);
+    static int initial_connect_to_director(gpointer data);
+}
+
 static void set_scroll_bar_to_end(void);
 
 /* Static variables */
 static char *configfile = NULL;
-static DIRRES *dir; 
-static CONRES *con; 
+static DIRRES *dir;
 static int ndir;
-static int director_reader_running = FALSE;
+static bool director_reader_running = false;
 static bool at_prompt = false;
 static bool ready = false;
 static bool quit = false;
 static guint initial;
+static int numdir = 0;
 
 #define CONFIG_FILE "./gnome-console.conf"   /* default configuration file */
 
 static void usage()
 {
    fprintf(stderr, _(
-"\nVersion: " VERSION " (" BDATE ") %s %s %s\n\n"
+"Copyright (C) 2002-2005 Kern Sibbald\n"
+"\nVersion: %s (%s) %s %s %s\n\n"
 "Usage: gnome-console [-s] [-c config_file] [-d debug_level] [config_file]\n"
 "       -c <file>   set configuration file to file\n"
 "       -dnn        set debug level to nn\n"
 "       -s          no signals\n"
 "       -t          test - read configuration and exit\n"
 "       -?          print this message.\n"
-"\n"), HOST_OS, DISTNAME, DISTVER);
+"\n"), VERSION, BDATE, HOST_OS, DISTNAME, DISTVER);
 
    exit(1);
 }
 
+/*
+ * Call-back for reading a passphrase for an encrypted PEM file
+ * This function uses getpass(), which uses a static buffer and is NOT thread-safe.
+ */
+static int tls_pem_callback(char *buf, int size, const void *userdata)
+{
+#ifdef HAVE_TLS
+   const char *prompt = (const char *) userdata;
+   char *passwd;
+
+   passwd = getpass(prompt);
+   bstrncpy(buf, passwd, size);
+   return (strlen(buf));
+#else
+   buf[0] = 0;
+   return 0;
+#endif
+}
+
+
+/*
+ * Make a quick check to see that we have all the
+ * resources needed.
+ */
+static int check_resources()
+{
+   int xOK = true;
+   DIRRES *director;
+
+   LockRes();
+
+   numdir = 0;
+   foreach_res(director, R_DIRECTOR) {
+      numdir++;
+      /* tls_require implies tls_enable */
+      if (director->tls_require) {
+         if (have_tls) {
+            director->tls_enable = true;
+         } else {
+            Jmsg(NULL, M_FATAL, 0, _("TLS required but not configured in Bacula.\n"));
+            xOK = false;
+            continue;
+         }
+      }
+
+      if ((!director->tls_ca_certfile && !director->tls_ca_certdir) && director->tls_enable) {
+         Emsg2(M_FATAL, 0, _("Neither \"TLS CA Certificate\""
+                             " or \"TLS CA Certificate Dir\" are defined for Director \"%s\" in %s."
+                             " At least one CA certificate store is required.\n"),
+                             director->hdr.name, configfile);
+         xOK = false;
+      }
+   }
+   
+   if (numdir == 0) {
+      Emsg1(M_FATAL, 0, _("No Director resource defined in %s\n"
+                          "Without that I don't how to speak to the Director :-(\n"), configfile);
+      xOK = false;
+   }
+
+   CONRES *cons;
+   /* Loop over Consoles */
+   foreach_res(cons, R_CONSOLE) {
+      /* tls_require implies tls_enable */
+      if (cons->tls_require) {
+         if (have_tls) {
+            cons->tls_enable = true;
+         } else {
+            Jmsg(NULL, M_FATAL, 0, _("TLS required but not configured in Bacula.\n"));
+            xOK = false;
+            continue;
+         }
+      }
+
+      if ((!cons->tls_ca_certfile && !cons->tls_ca_certdir) && cons->tls_enable) {
+         Emsg2(M_FATAL, 0, _("Neither \"TLS CA Certificate\""
+                             " or \"TLS CA Certificate Dir\" are defined for Console \"%s\" in %s.\n"),
+                             cons->hdr.name, configfile);
+         xOK = false;
+      }
+   }
+
+   UnlockRes();
+
+   return xOK;
+}
+
 
 /*********************************************************************
  *
- *        Main Bacula GNOME Console -- User Interface Program
+ *         Main Bacula GNOME Console -- User Interface Program
  *
  */
 int main(int argc, char *argv[])
@@ -105,7 +197,12 @@ int main(int argc, char *argv[])
    int no_signals = TRUE;
    int test_config = FALSE;
    int gargc = 1;
-   char *gargv[2] = {"gnome-console", NULL};
+   const char *gargv[2] = {"gnome-console", NULL};
+   CONFONTRES *con_font;
+
+   setlocale(LC_ALL, "");
+   bindtextdomain("bacula", LOCALEDIR);
+   textdomain("bacula");
 
    init_stack_dump();
    my_name_is(argc, argv, "gnome-console");
@@ -114,44 +211,43 @@ int main(int argc, char *argv[])
 
    struct sigaction sigignore;
    sigignore.sa_flags = 0;
-   sigignore.sa_handler = SIG_IGN;      
+   sigignore.sa_handler = SIG_IGN;
    sigfillset(&sigignore.sa_mask);
    sigaction(SIGPIPE, &sigignore, NULL);
 
    if ((stat=pthread_cond_init(&cmd_wait, NULL)) != 0) {
       Emsg1(M_ABORT, 0, _("Pthread cond init error = %s\n"),
-        strerror(stat));
+         strerror(stat));
    }
 
    gnome_init("bacula", VERSION, gargc, (char **)&gargv);
 
    while ((ch = getopt(argc, argv, "bc:d:r:st?")) != -1) {
       switch (ch) {
-         case 'c':                    /* configuration file */
-           if (configfile != NULL)
-              free(configfile);
-           configfile = bstrdup(optarg);
-           break;
-
-         case 'd':
-           debug_level = atoi(optarg);
-           if (debug_level <= 0)
-              debug_level = 1;
-           break;
-
-         case 's':                    /* turn off signals */
-           no_signals = TRUE;
-           break;
-
-         case 't':
-           test_config = TRUE;
-           break;
-
-         case '?':
-        default:
-           usage();
-
-      }  
+      case 'c':                    /* configuration file */
+         if (configfile != NULL)
+            free(configfile);
+         configfile = bstrdup(optarg);
+         break;
+
+      case 'd':
+         debug_level = atoi(optarg);
+         if (debug_level <= 0)
+            debug_level = 1;
+         break;
+
+      case 's':                    /* turn off signals */
+         no_signals = TRUE;
+         break;
+
+      case 't':
+         test_config = TRUE;
+         break;
+
+      case '?':
+      default:
+         usage();
+      }
    }
    argc -= optind;
    argv += optind;
@@ -171,73 +267,69 @@ int main(int argc, char *argv[])
 
    parse_config(configfile);
 
-   LockRes();
-   ndir = 0;
-   for (dir=NULL; (dir = (DIRRES *)GetNextRes(R_DIRECTOR, (RES *)dir)); ) {
-      ndir++;
-   }
-   UnlockRes();
-   if (ndir == 0) {
-      Emsg1(M_ERROR_TERM, 0, _("No director resource defined in %s\n\
-Without that I don't how to speak to the Director :-(\n"), configfile);
+   if (init_tls() != 0) {
+      Emsg0(M_ERROR_TERM, 0, _("TLS library initialization failed.\n"));
    }
 
-   if (test_config) {
-      terminate_console(0);
-      exit(0);
+   if (!check_resources()) {
+      Emsg1(M_ERROR_TERM, 0, _("Please correct configuration file: %s\n"), configfile);
    }
 
-
-   app1 = create_app1();
-   gtk_window_set_default_size(GTK_WINDOW(app1), 800, 700);
+   console = create_console();
+   gtk_window_set_default_size(GTK_WINDOW(console), 800, 700);
    run_dialog = create_RunDialog();
    label_dialog = create_label_dialog();
-   restore_dialog = create_restore_dialog();
-   restore_files  = create_restore_files();
+   restore_dialog = create_RestoreDialog();
    about1 = create_about1();
 
-   gtk_widget_show(app1);
+   text1 = lookup_widget(console, "text1");
+   entry1 = lookup_widget(console, "entry1");
+   status1 = lookup_widget(console, "status1");
+   scroll1 = lookup_widget(console, "scroll1");
+
+   select_restore_setup();
 
-   text1 = lookup_widget(app1, "text1");
-   entry1 = lookup_widget(app1, "entry1");
-   status1 = lookup_widget(app1, "status1");
-   scroll1 = lookup_widget(app1, "scroll1");
+   gtk_widget_show(console);
 
 /*
- * Thanks to Phil Stracchino for providing the font configuration code.
- * original default:
-   text_font = gdk_font_load("-misc-fixed-medium-r-normal-*-*-130-*-*-c-*-koi8-r");
- * this works for me:
-   text_font = gdk_font_load("-Bigelow & Holmes-lucida console-medium-r-semi condensed-*-12-0-100-100-m-0-iso8859-1");
- * and, new automagic:font specification!
+ * Gtk2/pango have different font names. Gnome2 comes with "Monospace 10"
  */
 
    LockRes();
-   for (con = NULL; (con = (CONRES *)GetNextRes(R_CONSOLE, (RES *)con)); ) {
-       text_font = gdk_font_load(con->fontface);
-       if (text_font == NULL) {
-           Dmsg2(404, "Load of requested ConsoleFont \"%s\" (%s) failed!\n",
-                 con->hdr.name, con->fontface);
+   foreach_res(con_font, R_CONSOLE_FONT) {
+       if (!con_font->fontface) {
+          Dmsg1(400, "No fontface for %s\n", con_font->hdr.name);
+          continue;
+       }
+       Dmsg1(100, "Now loading: %s\n",con_font->fontface);
+        console_font_desc = pango_font_description_from_string(con_font->fontface);
+       if (console_font_desc == NULL) {
+           Dmsg2(400, "Load of requested ConsoleFont \"%s\" (%s) failed!\n",
+                  con_font->hdr.name, con_font->fontface);
        } else {
-           Dmsg2(404, "ConsoleFont \"%s\" (%s) loaded.\n",
-                 con->hdr.name, con->fontface);
-          break;
-       }          
+           Dmsg2(400, "ConsoleFont \"%s\" (%s) loaded.\n",
+                  con_font->hdr.name, con_font->fontface);
+           break;
+       }
    }
    UnlockRes();
 
-   if (text_font == NULL) {
-       Dmsg1(100, "Attempting to load fallback font %s\n",
-              "-misc-fixed-medium-r-normal-*-*-130-*-*-c-*-iso8859-1");
-       text_font = gdk_font_load("-misc-fixed-medium-r-normal-*-*-130-*-*-c-*-iso8859-1");
-   }
    font_desc = pango_font_description_from_string("LucidaTypewriter 9");
-   gtk_widget_modify_font (app1, font_desc);
-   gtk_widget_modify_font (text1, font_desc);
-   gtk_widget_modify_font (entry1, font_desc);
-   gtk_widget_modify_font (status1, font_desc);
-   pango_font_description_free (font_desc);
+   gtk_widget_modify_font(console, font_desc);
+   gtk_widget_modify_font(entry1, font_desc);
+   gtk_widget_modify_font(status1, font_desc);
+   if (console_font_desc) {
+      gtk_widget_modify_font(text1, console_font_desc);
+      pango_font_description_free(console_font_desc);
+   } else {
+      gtk_widget_modify_font(text1, font_desc);
+   }
+   pango_font_description_free(font_desc);
 
+   if (test_config) {
+      terminate_console(0);
+      exit(0);
+   }
 
    initial = gtk_timeout_add(100, initial_connect_to_director, (gpointer)NULL);
 
@@ -261,8 +353,9 @@ static gint message_handler(gpointer data)
 
 int disconnect_from_director(gpointer data)
 {
-   if (!quit)
+   if (!quit) {
       set_status(_(" Not Connected"));
+   }
    if (UA_sock) {
       bnet_sig(UA_sock, BNET_TERMINATE); /* send EOF */
       bnet_close(UA_sock);
@@ -299,28 +392,28 @@ static GList *get_list(char *cmd)
       options = g_list_append(options, msg);
    }
    return options;
-   
+
 }
 
-static GList *get_and_fill_combo(GtkWidget *dialog, char *combo_name, char *cmd)
+static GList *get_and_fill_combo(GtkWidget *dialog, const char *combo_name, const char *dircmd)
 {
    GtkWidget *combo;
    GList *options;
 
    combo = lookup_widget(dialog, combo_name);
-   options = get_list(cmd);
+   options = get_list((char *)dircmd);
    if (combo && options) {
       gtk_combo_set_popdown_strings(GTK_COMBO(combo), options);
    }
    return options;
 }
 
-static void fill_combo(GtkWidget *dialog, char *combo_name, GList *options)
+static void fill_combo(GtkWidget *dialog, const char *combo_name, GList *options)
 {
    GtkWidget *combo;
 
    combo = lookup_widget(dialog, combo_name);
-   if (combo) {
+   if (combo && options) {
       gtk_combo_set_popdown_strings(GTK_COMBO(combo), options);
    }
    return;
@@ -335,7 +428,6 @@ int connect_to_director(gpointer data)
 {
    GList *dirs = NULL;
    GtkWidget *combo;
-   char buf[1000];
    JCR jcr;
 
 
@@ -345,30 +437,28 @@ int connect_to_director(gpointer data)
 
    if (ndir > 1) {
       LockRes();
-      for (dir = NULL; (dir = (DIRRES *)GetNextRes(R_DIRECTOR, (RES *)dir)); ) {
-         sprintf(buf, "%s at %s:%d", dir->hdr.name, dir->address,
-           dir->DIRport);
-         printf("%s\n", buf);
-        dirs = g_list_append(dirs, dir->hdr.name);
+      foreach_res(dir, R_DIRECTOR) {
+         dirs = g_list_append(dirs, dir->hdr.name);
       }
       UnlockRes();
       dir_dialog = create_SelectDirectorDialog();
       combo = lookup_widget(dir_dialog, "combo1");
       dir_select = lookup_widget(dir_dialog, "dirselect");
-      gtk_combo_set_popdown_strings(GTK_COMBO(combo), dirs);   
-      printf("dialog run\n");
+      if (dirs) {
+         gtk_combo_set_popdown_strings(GTK_COMBO(combo), dirs);
+      }
       gtk_widget_show(dir_dialog);
       gtk_main();
 
       if (reply == OK) {
-        gchar *ecmd = gtk_editable_get_chars((GtkEditable *)dir_select, 0, -1);
-        dir = (DIRRES *)GetResWithName(R_DIRECTOR, ecmd);
-        if (ecmd) {
-           g_free(ecmd);             /* release director name string */
-        }
+         gchar *ecmd = gtk_editable_get_chars((GtkEditable *)dir_select, 0, -1);
+         dir = (DIRRES *)GetResWithName(R_DIRECTOR, ecmd);
+         if (ecmd) {
+            g_free(ecmd);             /* release director name string */
+         }
       }
       if (dirs) {
-        g_free(dirs);
+         g_free(dirs);
       }
       gtk_widget_destroy(dir_dialog);
       dir_dialog = NULL;
@@ -380,31 +470,81 @@ int connect_to_director(gpointer data)
    }
 
    if (!dir) {
-      printf("dir is NULL\n");
       return 0;
    }
 
    memset(&jcr, 0, sizeof(jcr));
-   
+
    set_statusf(_(" Connecting to Director %s:%d"), dir->address,dir->DIRport);
    set_textf(_("Connecting to Director %s:%d\n\n"), dir->address,dir->DIRport);
 
    while (gtk_events_pending()) {     /* fully paint screen */
       gtk_main_iteration();
    }
-   UA_sock = bnet_connect(NULL, 5, 15, "Director daemon", dir->address, 
-                         NULL, dir->DIRport, 0);
+
+   LockRes();
+   /* If cons==NULL, default console will be used */
+   CONRES *cons = (CONRES *)GetNextRes(R_CONSOLE, (RES *)NULL);
+   UnlockRes();
+
+   char buf[1024];
+   /* Initialize Console TLS context */
+   if (cons && (cons->tls_enable || cons->tls_require)) {
+      /* Generate passphrase prompt */
+      bsnprintf(buf, sizeof(buf), _("Passphrase for Console \"%s\" TLS private key: "), cons->hdr.name);
+
+      /* Initialize TLS context:
+       * Args: CA certfile, CA certdir, Certfile, Keyfile,
+       * Keyfile PEM Callback, Keyfile CB Userdata, DHfile, Verify Peer */
+      cons->tls_ctx = new_tls_context(cons->tls_ca_certfile,
+         cons->tls_ca_certdir, cons->tls_certfile,
+         cons->tls_keyfile, tls_pem_callback, &buf, NULL, true);
+
+      if (!cons->tls_ctx) {
+         bsnprintf(buf, sizeof(buf), _("Failed to initialize TLS context for Console \"%s\".\n"),
+            dir->hdr.name);
+         set_text(buf, strlen(buf));
+         terminate_console(0);
+         return 1;
+      }
+
+   }
+
+   /* Initialize Director TLS context */
+   if (dir->tls_enable || dir->tls_require) {
+      /* Generate passphrase prompt */
+      bsnprintf(buf, sizeof(buf), _("Passphrase for Director \"%s\" TLS private key: "), dir->hdr.name);
+
+      /* Initialize TLS context:
+       * Args: CA certfile, CA certdir, Certfile, Keyfile,
+       * Keyfile PEM Callback, Keyfile CB Userdata, DHfile, Verify Peer */
+      dir->tls_ctx = new_tls_context(dir->tls_ca_certfile,
+         dir->tls_ca_certdir, dir->tls_certfile,
+         dir->tls_keyfile, tls_pem_callback, &buf, NULL, true);
+
+      if (!dir->tls_ctx) {
+         bsnprintf(buf, sizeof(buf), _("Failed to initialize TLS context for Director \"%s\".\n"),
+            dir->hdr.name);
+         set_text(buf, strlen(buf));
+         terminate_console(0);
+         return 1;
+      }
+   }
+
+
+   UA_sock = bnet_connect(NULL, 5, 15, _("Director daemon"), dir->address,
+                          NULL, dir->DIRport, 0);
    if (UA_sock == NULL) {
       return 0;
    }
-   
+
    jcr.dir_bsock = UA_sock;
-   if (!authenticate_director(&jcr, dir)) {
+   if (!authenticate_director(&jcr, dir, cons)) {
       set_text(UA_sock->msg, UA_sock->msglen);
       return 0;
    }
 
-   set_status(" Initializing ...");
+   set_status(_(" Initializing ..."));
 
    bnet_fsend(UA_sock, "autodisplay on");
 
@@ -428,14 +568,23 @@ int connect_to_director(gpointer data)
    type_list     = get_and_fill_combo(run_dialog, "combo_type", ".types");
    level_list    = get_and_fill_combo(run_dialog, "combo_level", ".levels");
 
+   /* Fill the label dialog combo boxes */
    fill_combo(label_dialog, "label_combo_storage", storage_list);
    fill_combo(label_dialog, "label_combo_pool", pool_list);
 
-   set_status(" Connected");
+
+   /* Fill the restore_dialog combo boxes */
+   fill_combo(restore_dialog, "combo_restore_job", job_list);
+   fill_combo(restore_dialog, "combo_restore_client", client_list);
+   fill_combo(restore_dialog, "combo_restore_fileset", fileset_list);
+   fill_combo(restore_dialog, "combo_restore_pool", pool_list);
+   fill_combo(restore_dialog, "combo_restore_storage", storage_list);
+
+   set_status(_(" Connected"));
    return 1;
 }
 
-void write_director(gchar *msg)
+void write_director(const gchar *msg)
 {
    if (UA_sock) {
       at_prompt = false;
@@ -450,6 +599,7 @@ void write_director(gchar *msg)
    }
 }
 
+extern "C"
 void read_director(gpointer data, gint fd, GdkInputCondition condition)
 {
    int stat;
@@ -461,12 +611,12 @@ void read_director(gpointer data, gint fd, GdkInputCondition condition)
    if (stat >= 0) {
       if (at_prompt) {
          set_text("\n", 1);
-        at_prompt = false;
+         at_prompt = false;
       }
       set_text(UA_sock->msg, UA_sock->msglen);
       return;
    }
-   if (is_bnet_stop(UA_sock)) {        /* error or term request */
+   if (is_bnet_stop(UA_sock)) {         /* error or term request */
       gtk_main_quit();
       return;
    }
@@ -489,9 +639,8 @@ void start_director_reader(gpointer data)
    if (director_reader_running || !UA_sock) {
       return;
    }
-   director_reader_running = TRUE;
-
    tag = gdk_input_add(UA_sock->fd, GDK_INPUT_READ, read_director, NULL);
+   director_reader_running = true;
 }
 
 void stop_director_reader(gpointer data)
@@ -500,19 +649,30 @@ void stop_director_reader(gpointer data)
       return;
    }
    gdk_input_remove(tag);
-   director_reader_running = FALSE;
+   gdk_input_remove(tag);
+   gdk_input_remove(tag);
+   gdk_input_remove(tag);
+   gdk_input_remove(tag);
+   gdk_input_remove(tag);
+   gdk_input_remove(tag);
+   gdk_input_remove(tag);
+   gdk_input_remove(tag);
+   gdk_input_remove(tag);
+   gdk_input_remove(tag);
+   director_reader_running = false;
 }
 
 
 
 /* Cleanup and then exit */
-static void terminate_console(int sig)
+void terminate_console(int sig)
 {
-   static int already_here = FALSE;
+   static bool already_here = false;
 
-   if (already_here)                 /* avoid recursive temination problems */
+   if (already_here)                  /* avoid recursive temination problems */
       exit(1);
-   already_here = TRUE;
+   already_here = true;
+   cleanup_tls();
    disconnect_from_director((gpointer)NULL);
    gtk_main_quit();
    exit(0);
@@ -520,7 +680,7 @@ static void terminate_console(int sig)
 
 
 /* Buffer approx 2000 lines -- assume 60 chars/line */
-#define MAX_TEXT_CHARS  (2000 * 60)
+#define MAX_TEXT_CHARS   (2000 * 60)
 static int text_chars = 0;
 
 static void truncate_text_chars()
@@ -540,7 +700,7 @@ static void truncate_text_chars()
    gtk_text_iter_set_offset(&iter, len);
 }
 
-void set_textf(char *fmt, ...)
+void set_textf(const char *fmt, ...)
 {
    va_list arg_ptr;
    char buf[1000];
@@ -551,7 +711,7 @@ void set_textf(char *fmt, ...)
    set_text(buf, len);
 }
 
-void set_text(char *buf, int len)
+void set_text(const char *buf, int len)
 {
    GtkTextBuffer *textbuf;
    GtkTextIter iter;
@@ -568,7 +728,7 @@ void set_text(char *buf, int len)
    set_scroll_bar_to_end();
 }
 
-void set_statusf(char *fmt, ...)
+void set_statusf(const char *fmt, ...)
 {
    va_list arg_ptr;
    char buf[1000];
@@ -581,14 +741,14 @@ void set_statusf(char *fmt, ...)
    ready = false;
 }
 
-void set_status_ready()    
+void set_status_ready()
 {
-   gtk_label_set_text(GTK_LABEL(status1), " Ready");
+   gtk_label_set_text(GTK_LABEL(status1), _(" Ready"));
    ready = true;
 // set_scroll_bar_to_end();
 }
 
-void set_status(char *buf)
+void set_status(const char *buf)
 {
    gtk_label_set_text(GTK_LABEL(status1), buf);
 // set_scroll_bar_to_end();
@@ -607,6 +767,6 @@ static void set_scroll_bar_to_end(void)
    gtk_text_iter_set_offset(&iter, buf_len);
    gtk_text_buffer_place_cursor(textbuf, &iter);
    gtk_text_view_scroll_to_mark(GTK_TEXT_VIEW(text1),
-              gtk_text_buffer_get_mark(textbuf, "insert"), 
-             0, TRUE, 0.0, 1.0);
+              gtk_text_buffer_get_mark(textbuf, "insert"),
+              0, TRUE, 0.0, 1.0);
 }