3 * Bacula GNOME Console interface to the Director
5 * Kern Sibbald, March MMII
11 Copyright (C) 2002 Kern Sibbald and John Walker
13 This program is free software; you can redistribute it and/or
14 modify it under the terms of the GNU General Public License
15 as published by the Free Software Foundation; either version 2
16 of the License, or (at your option) any later version.
18 This program is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software
25 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
31 #include "interface.h"
34 /* Imported functions */
35 int authenticate_director(JCR *jcr, DIRRES *director);
37 /* Exported variables */
38 GtkWidget *app1; /* application window */
39 GtkWidget *text1; /* text window */
40 GtkWidget *entry1; /* entry box */
41 GtkWidget *status1; /* status bar */
42 GtkWidget *combo1; /* director combo */
43 GtkWidget *run_dialog; /* run dialog */
44 GtkWidget *dir_dialog; /* director selection dialog */
45 GtkWidget *restore_dialog; /* restore dialog */
46 GtkWidget *restore_files; /* restore files dialog */
47 GtkWidget *dir_select;
48 GtkWidget *about1; /* about box */
49 GtkWidget *label_dialog;
50 GdkFont *text_font = NULL;
51 pthread_mutex_t cmd_mutex = PTHREAD_MUTEX_INITIALIZER;
52 pthread_cond_t cmd_wait;
54 int cmd_ready = FALSE;
56 BSOCK *UA_sock = NULL;
57 GList *job_list, *client_list, *fileset_list;
58 GList *messages_list, *pool_list, *storage_list;
59 GList *type_list, *level_list;
61 /* Forward referenced functions */
62 static void terminate_console(int sig);
63 static gint message_handler(gpointer data);
64 static int initial_connect_to_director(gpointer data);
66 /* Static variables */
67 static char *configfile = NULL;
71 static int director_reader_running = FALSE;
72 static int at_prompt = FALSE;
73 static int ready = FALSE;
74 static int quit = FALSE;
77 #define CONFIG_FILE "./gnome-console.conf" /* default configuration file */
82 "\nVersion: " VERSION " (" BDATE ")\n\n"
83 "Usage: gnome-console [-s] [-c config_file] [-d debug_level] [config_file]\n"
84 " -c <file> set configuration file to file\n"
85 " -dnn set debug level to nn\n"
87 " -t test - read configuration and exit\n"
88 " -? print this message.\n"
95 /*********************************************************************
97 * Main Bacula GNOME Console -- User Interface Program
100 int main(int argc, char *argv[])
103 int no_signals = TRUE;
104 int test_config = FALSE;
106 char *gargv[2] = {"gnome-console", NULL};
109 my_name_is(argc, argv, "gnome-console");
110 init_msg(NULL, NULL);
111 working_directory = "/tmp";
113 struct sigaction sigignore;
114 sigignore.sa_flags = 0;
115 sigignore.sa_handler = SIG_IGN;
116 sigfillset(&sigignore.sa_mask);
117 sigaction(SIGPIPE, &sigignore, NULL);
119 if ((stat=pthread_cond_init(&cmd_wait, NULL)) != 0) {
120 Emsg1(M_ABORT, 0, _("Pthread cond init error = %s\n"),
124 gnome_init("bacula", VERSION, gargc, (char **)&gargv);
126 while ((ch = getopt(argc, argv, "bc:d:r:st?")) != -1) {
128 case 'c': /* configuration file */
129 if (configfile != NULL)
131 configfile = bstrdup(optarg);
135 debug_level = atoi(optarg);
136 if (debug_level <= 0)
140 case 's': /* turn off signals */
159 init_signals(terminate_console);
166 if (configfile == NULL) {
167 configfile = bstrdup(CONFIG_FILE);
170 parse_config(configfile);
174 for (dir=NULL; (dir = (DIRRES *)GetNextRes(R_DIRECTOR, (RES *)dir)); ) {
179 Emsg1(M_ERROR_TERM, 0, _("No director resource defined in %s\n\
180 Without that I don't how to speak to the Director :-(\n"), configfile);
184 terminate_console(0);
189 app1 = create_app1();
190 gtk_window_set_default_size(GTK_WINDOW(app1), 500, 700);
191 run_dialog = create_RunDialog();
192 label_dialog = create_label_dialog();
193 restore_dialog = create_restore_dialog();
194 restore_files = create_restore_files();
195 about1 = create_about1();
197 gtk_widget_show(app1);
199 text1 = lookup_widget(app1, "text1");
200 entry1 = lookup_widget(app1, "entry1");
201 status1 = lookup_widget(app1, "status1");
204 * Thanks to Phil Stracchino for providing the font configuration code.
206 text_font = gdk_font_load("-misc-fixed-medium-r-normal-*-*-130-*-*-c-*-koi8-r");
208 text_font = gdk_font_load("-Bigelow & Holmes-lucida console-medium-r-semi condensed-*-12-0-100-100-m-0-iso8859-1");
209 * and, new automagic:font specification!
213 for (con = NULL; (con = (CONRES *)GetNextRes(R_CONSOLE, (RES *)con)); ) {
214 text_font = gdk_font_load(con->fontface);
215 if (text_font == NULL) {
216 Dmsg2(404, "Load of requested ConsoleFont \"%s\" (%s) failed!\n",
217 con->hdr.name, con->fontface);
219 Dmsg2(404, "ConsoleFont \"%s\" (%s) loaded.\n",
220 con->hdr.name, con->fontface);
226 if (text_font == NULL) {
227 Dmsg1(100, "Attempting to load fallback font %s\n",
228 "-misc-fixed-medium-r-normal-*-*-130-*-*-c-*-iso8859-1");
229 text_font = gdk_font_load("-misc-fixed-medium-r-normal-*-*-130-*-*-c-*-iso8859-1");
232 initial = gtk_timeout_add(100, initial_connect_to_director, (gpointer)NULL);
236 disconnect_from_director((gpointer)NULL);
241 * Every 5 seconds, ask the Director for our
244 static gint message_handler(gpointer data)
246 if (ready && UA_sock) {
247 bnet_fsend(UA_sock, ".messages");
252 int disconnect_from_director(gpointer data)
255 set_status(_(" Not Connected"));
257 bnet_sig(UA_sock, BNET_TERMINATE); /* send EOF */
265 * Called just after the main loop is started to allow
266 * us to connect to the Director.
268 static int initial_connect_to_director(gpointer data)
270 gtk_timeout_remove(initial);
271 if (connect_to_director(data)) {
272 start_director_reader(data);
274 gtk_timeout_add(5000, message_handler, (gpointer)NULL);
278 static GList *get_list(char *cmd)
285 while (bnet_recv(UA_sock) > 0) {
286 strip_trailing_junk(UA_sock->msg);
287 msg = (char *)malloc(strlen(UA_sock->msg) + 1);
288 strcpy(msg, UA_sock->msg);
289 options = g_list_append(options, msg);
295 static GList *get_and_fill_combo(GtkWidget *dialog, char *combo_name, char *cmd)
300 combo = lookup_widget(dialog, combo_name);
301 options = get_list(cmd);
302 if (combo && options) {
303 gtk_combo_set_popdown_strings(GTK_COMBO(combo), options);
308 static void fill_combo(GtkWidget *dialog, char *combo_name, GList *options)
312 combo = lookup_widget(dialog, combo_name);
314 gtk_combo_set_popdown_strings(GTK_COMBO(combo), options);
321 * Connect to Director. If there are more than one, put up
322 * a modal dialog so that the user chooses one.
324 int connect_to_director(gpointer data)
338 for (dir = NULL; (dir = (DIRRES *)GetNextRes(R_DIRECTOR, (RES *)dir)); ) {
339 sprintf(buf, "%s at %s:%d", dir->hdr.name, dir->address,
342 dirs = g_list_append(dirs, dir->hdr.name);
345 dir_dialog = create_SelectDirectorDialog();
346 combo = lookup_widget(dir_dialog, "combo1");
347 dir_select = lookup_widget(dir_dialog, "dirselect");
348 gtk_combo_set_popdown_strings(GTK_COMBO(combo), dirs);
349 printf("dialog run\n");
350 gtk_widget_show(dir_dialog);
354 gchar *ecmd = gtk_editable_get_chars((GtkEditable *)dir_select, 0, -1);
355 dir = (DIRRES *)GetResWithName(R_DIRECTOR, ecmd);
357 g_free(ecmd); /* release director name string */
363 gtk_widget_destroy(dir_dialog);
366 /* Just take the first Director */
368 dir = (DIRRES *)GetNextRes(R_DIRECTOR, NULL);
373 printf("dir is NULL\n");
377 memset(&jcr, 0, sizeof(jcr));
379 set_statusf(_(" Connecting to Director %s:%d\n"), dir->address,dir->DIRport);
380 set_textf(_("Connecting to Director %s:%d\n"), dir->address,dir->DIRport);
382 // while (gtk_events_pending()) { /* fully paint screen */
383 // gtk_main_iteration();
385 UA_sock = bnet_connect(NULL, 5, 15, "Director daemon", dir->address,
386 NULL, dir->DIRport, 0);
387 if (UA_sock == NULL) {
391 jcr.dir_bsock = UA_sock;
392 if (!authenticate_director(&jcr, dir)) {
393 set_text(UA_sock->msg, UA_sock->msglen);
397 set_status(" Initializing ...");
399 bnet_fsend(UA_sock, "autodisplay on");
401 /* Read and display all initial messages */
402 while (bnet_recv(UA_sock) > 0) {
403 set_text(UA_sock->msg, UA_sock->msglen);
407 while (gtk_events_pending()) {
408 gtk_main_iteration();
411 /* Fill the run_dialog combo boxes */
412 job_list = get_and_fill_combo(run_dialog, "combo_job", ".jobs");
413 client_list = get_and_fill_combo(run_dialog, "combo_client", ".clients");
414 fileset_list = get_and_fill_combo(run_dialog, "combo_fileset", ".filesets");
415 messages_list = get_and_fill_combo(run_dialog, "combo_messages", ".msgs");
416 pool_list = get_and_fill_combo(run_dialog, "combo_pool", ".pools");
417 storage_list = get_and_fill_combo(run_dialog, "combo_storage", ".storage");
418 type_list = get_and_fill_combo(run_dialog, "combo_type", ".types");
419 level_list = get_and_fill_combo(run_dialog, "combo_level", ".levels");
421 fill_combo(label_dialog, "label_combo_storage", storage_list);
422 fill_combo(label_dialog, "label_combo_pool", pool_list);
424 set_status(" Connected");
428 void write_director(gchar *msg)
432 set_status(_(" Processing command ..."));
433 UA_sock->msglen = strlen(msg);
434 pm_strcpy(&UA_sock->msg, msg);
437 if (strcmp(msg, ".quit") == 0 || strcmp(msg, ".exit") == 0) {
438 disconnect_from_director((gpointer)NULL);
443 void read_director(gpointer data, gint fd, GdkInputCondition condition)
447 if (!UA_sock || UA_sock->fd != fd) {
450 stat = bnet_recv(UA_sock);
456 set_text(UA_sock->msg, UA_sock->msglen);
459 if (is_bnet_stop(UA_sock)) { /* error or term request */
463 /* Must be a signal -- either do something or ignore it */
464 if (UA_sock->msglen == BNET_PROMPT) {
466 set_status(_(" At prompt waiting for input ..."));
468 if (UA_sock->msglen == BNET_EOD) {
476 void start_director_reader(gpointer data)
479 if (director_reader_running || !UA_sock) {
482 director_reader_running = TRUE;
484 tag = gdk_input_add(UA_sock->fd, GDK_INPUT_READ, read_director, NULL);
487 void stop_director_reader(gpointer data)
489 if (!director_reader_running) {
492 gdk_input_remove(tag);
493 director_reader_running = FALSE;
498 /* Cleanup and then exit */
499 static void terminate_console(int sig)
501 static int already_here = FALSE;
503 if (already_here) /* avoid recursive temination problems */
506 disconnect_from_director((gpointer)NULL);
512 /* Buffer approx 2000 lines -- assume 60 chars/line */
513 #define MAX_TEXT_CHARS (2000 * 60)
514 static int text_chars = 0;
516 static void truncate_text_chars()
518 int del_chars = MAX_TEXT_CHARS / 4;
519 gtk_text_set_point(GTK_TEXT(text1), del_chars);
520 gtk_text_backward_delete(GTK_TEXT(text1), del_chars);
521 text_chars -= del_chars;
522 gtk_text_set_point(GTK_TEXT(text1), text_chars);
525 void set_textf(char *fmt, ...)
530 va_start(arg_ptr, fmt);
531 len = bvsnprintf(buf, sizeof(buf), fmt, arg_ptr);
535 void set_text(char *buf, int len)
537 gtk_text_insert(GTK_TEXT(text1), text_font, NULL, NULL, buf, -1);
539 if (text_chars > MAX_TEXT_CHARS) {
540 truncate_text_chars();
544 void set_statusf(char *fmt, ...)
549 va_start(arg_ptr, fmt);
550 len = bvsnprintf(buf, sizeof(buf), fmt, arg_ptr);
551 gtk_label_set_text(GTK_LABEL(status1), buf);
555 void set_status_ready()
557 gtk_label_set_text(GTK_LABEL(status1), " Ready");
561 void set_status(char *buf)
563 gtk_label_set_text(GTK_LABEL(status1), buf);