3 * Bacula Gnome Tray Monitor
5 * Nicolas Boichat, August MMIV
11 Copyright (C) 2004 Kern Sibbald and John Walker
13 This library is free software; you can redistribute it and/or
14 modify it under the terms of the GNU Lesser General Public
15 License as published by the Free Software Foundation; either
16 version 2.1 of the License, or (at your option) any later version.
18 This library 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 GNU
21 Lesser General Public License for more details.
23 You should have received a copy of the GNU Lesser General Public
24 License along with this library; if not, write to the Free
25 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
31 #include "tray-monitor.h"
33 #include "eggstatusicon.h"
35 #include "generic.xpm"
37 /* Imported functions */
38 int authenticate_director(JCR *jcr, MONITOR *monitor, DIRRES *director);
39 int authenticate_file_daemon(JCR *jcr, MONITOR *monitor, CLIENT* client);
40 int authenticate_storage_daemon(JCR *jcr, MONITOR *monitor, STORE* store);
42 /* Forward referenced functions */
43 void writecmd(monitoritem* item, const char* command);
44 int docmd(monitoritem* item, const char* command, GSList** list);
45 void getstatus(monitoritem* item, int current, GString** str);
47 /* Static variables */
48 static char *configfile = NULL;
49 static MONITOR *monitor;
52 static int nitems = 0;
53 static int fullitem = 0; //Item to be display in detailled status window
54 static int lastupdated = -1; //Last item updated
55 static monitoritem items[32];
57 /* Data received from DIR/FD/SD */
58 static char OKqstatus[] = "%c000 OK .status\n";
59 static char DotStatusJob[] = "JobId=%d JobStatus=%c JobErrors=%d\n";
61 /* UI variables and functions */
63 static gboolean fd_read(gpointer data);
64 void trayMessage(const char *fmt,...);
65 void updateStatusIcon(monitoritem* item);
66 void changeStatusMessage(monitoritem* item, const char *fmt,...);
67 static const char** generateXPM(stateenum newstate, stateenum oldstate);
70 static void TrayIconActivate(GtkWidget *widget, gpointer data);
71 static void TrayIconExit(unsigned int activateTime, unsigned int button);
72 static void TrayIconPopupMenu(unsigned int button, unsigned int activateTime);
73 static void MonitorAbout(GtkWidget *widget, gpointer data);
74 static void MonitorRefresh(GtkWidget *widget, gpointer data);
75 static void IntervalChanged(GtkWidget *widget, gpointer data);
76 static void DaemonChanged(GtkWidget *widget, monitoritem* data);
77 static gboolean delete_event(GtkWidget *widget, GdkEvent *event, gpointer data);
79 static guint timerTag;
80 static EggStatusIcon *mTrayIcon;
81 static GtkWidget *mTrayMenu;
82 static GtkWidget *window;
83 static GtkWidget *textview;
84 static GtkTextBuffer *buffer;
85 static GtkWidget *timeoutspinner;
86 char** xpm_generic_var;
88 #define CONFIG_FILE "./tray-monitor.conf" /* default configuration file */
93 "Copyright (C) 2000-2004 Kern Sibbald and John Walker\n"
94 "Written by Nicolas Boichat (2004)\n"
95 "\nVersion: " VERSION " (" BDATE ") %s %s %s\n\n"
96 "Usage: tray-monitor [-c config_file] [-d debug_level]\n"
97 " -c <file> set configuration file to file\n"
98 " -dnn set debug level to nn\n"
99 " -t test - read configuration and exit\n"
100 " -? print this message.\n"
101 "\n"), HOST_OS, DISTNAME, DISTVER);
104 static GtkWidget *new_image_button(const gchar *stock_id,
105 const gchar *label_text) {
111 button = gtk_button_new();
113 box = gtk_hbox_new(FALSE, 0);
114 gtk_container_set_border_width(GTK_CONTAINER(box), 2);
115 image = gtk_image_new_from_stock(stock_id, GTK_ICON_SIZE_BUTTON);
116 label = gtk_label_new(label_text);
118 gtk_box_pack_start(GTK_BOX(box), image, FALSE, FALSE, 3);
119 gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 3);
121 gtk_widget_show(image);
122 gtk_widget_show(label);
124 gtk_widget_show(box);
126 gtk_container_add(GTK_CONTAINER(button), box);
131 /*********************************************************************
133 * Main Bacula Tray Monitor -- User Interface Program
136 int main(int argc, char *argv[])
139 bool test_config = false;
145 my_name_is(argc, argv, "tray-monitor");
146 textdomain("bacula");
147 init_msg(NULL, NULL);
148 working_directory = "/tmp";
149 args = get_pool_memory(PM_FNAME);
151 while ((ch = getopt(argc, argv, "bc:d:th?f:s:")) != -1) {
153 case 'c': /* configuration file */
154 if (configfile != NULL) {
157 configfile = bstrdup(optarg);
161 debug_level = atoi(optarg);
162 if (debug_level <= 0) {
186 if (configfile == NULL) {
187 configfile = bstrdup(CONFIG_FILE);
190 parse_config(configfile);
194 foreach_res(monitor, R_MONITOR) {
199 Emsg2(M_ERROR_TERM, 0,
200 _("Error: %d Monitor resource defined in %s. You must define one and only one Monitor resource.\n"), nitems, configfile);
204 foreach_res(dird, R_DIRECTOR) {
205 items[nitems].type = R_DIRECTOR;
206 items[nitems].resource = dird;
207 items[nitems].D_sock = NULL;
208 items[nitems].state = warn;
211 foreach_res(filed, R_CLIENT) {
212 items[nitems].type = R_CLIENT;
213 items[nitems].resource = filed;
214 items[nitems].D_sock = NULL;
215 items[nitems].state = warn;
218 foreach_res(stored, R_STORAGE) {
219 items[nitems].type = R_STORAGE;
220 items[nitems].resource = stored;
221 items[nitems].D_sock = NULL;
222 items[nitems].state = warn;
228 Emsg1(M_ERROR_TERM, 0, _("No Client, Storage nor Director resource defined in %s\n\
229 Without that I don't how to get status from the File, Storage or Director Daemon :-(\n"), configfile);
236 //Copy the content of xpm_generic in xpm_generic_var to be able to modify it
237 g_assert((xpm_generic_var = (char**)g_malloc(sizeof(xpm_generic))));
238 for (i = 0; i < (int)(sizeof(xpm_generic)/sizeof(const char*)); i++) {
239 g_assert((xpm_generic_var[i] = (char*)g_malloc(strlen(xpm_generic[i])*sizeof(char))));
240 strcpy(xpm_generic_var[i], xpm_generic[i]);
243 (void)WSA_Init(); /* Initialize Windows sockets */
246 monitor = (MONITOR*)GetNextRes(R_MONITOR, (RES *)NULL);
249 if ((monitor->RefreshInterval < 1) || (monitor->RefreshInterval > 600)) {
250 Emsg2(M_ERROR_TERM, 0, _("Invalid refresh interval defined in %s\n\
251 This value must be greater or equal to 1 second and less or equal to 10 minutes (read value: %d).\n"), configfile, monitor->RefreshInterval);
254 gtk_init (&argc, &argv);
256 GdkPixbuf* pixbuf = gdk_pixbuf_new_from_xpm_data(generateXPM(warn, warn));
257 // This should be ideally replaced by a completely libpr0n-based icon rendering.
258 mTrayIcon = egg_status_icon_new_from_pixbuf(pixbuf);
259 g_signal_connect(G_OBJECT(mTrayIcon), "activate", G_CALLBACK(TrayIconActivate), NULL);
260 g_signal_connect(G_OBJECT(mTrayIcon), "popup-menu", G_CALLBACK(TrayIconPopupMenu), NULL);
261 g_object_unref(G_OBJECT(pixbuf));
263 mTrayMenu = gtk_menu_new();
267 entry = gtk_menu_item_new_with_label("Open status window...");
268 g_signal_connect(G_OBJECT(entry), "activate", G_CALLBACK(TrayIconActivate), NULL);
269 gtk_menu_shell_append(GTK_MENU_SHELL(mTrayMenu), entry);
271 gtk_menu_shell_append(GTK_MENU_SHELL(mTrayMenu), gtk_separator_menu_item_new());
273 entry = gtk_menu_item_new_with_label("Exit");
274 g_signal_connect(G_OBJECT(entry), "activate", G_CALLBACK(TrayIconExit), NULL);
275 gtk_menu_shell_append(GTK_MENU_SHELL(mTrayMenu), entry);
277 gtk_widget_show_all(mTrayMenu);
279 timerTag = g_timeout_add( monitor->RefreshInterval/nitems, fd_read, NULL );
281 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
283 gtk_window_set_title(GTK_WINDOW(window), "Bacula tray monitor");
285 g_signal_connect(G_OBJECT(window), "delete_event", G_CALLBACK(delete_event), NULL);
286 //g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy), NULL);
288 gtk_container_set_border_width(GTK_CONTAINER(window), 10);
290 GtkWidget* vbox = gtk_vbox_new(FALSE, 10);
292 GtkWidget* daemon_table = gtk_table_new((nitems*2)+2, 3, FALSE);
294 gtk_table_set_col_spacings(GTK_TABLE(daemon_table), 8);
296 GtkWidget* separator = gtk_hseparator_new();
297 gtk_table_attach_defaults(GTK_TABLE(daemon_table), separator, 0, 3, 0, 1);
300 GSList *group = NULL;
304 for (int i = 0; i < nitems; i++) {
305 switch (items[i].type) {
307 str = g_string_new(((DIRRES*)(items[i].resource))->hdr.name);
308 g_string_append(str, _(" (DIR)"));
311 str = g_string_new(((CLIENT*)(items[i].resource))->hdr.name);
312 g_string_append(str, _(" (FD)"));
315 str = g_string_new(((STORE*)(items[i].resource))->hdr.name);
316 g_string_append(str, _(" (SD)"));
322 radio = gtk_radio_button_new_with_label(group, str->str);
323 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio), i == 0);
324 g_signal_connect(G_OBJECT(radio), "toggled", G_CALLBACK(DaemonChanged), &(items[i]));
326 pixbuf = gdk_pixbuf_new_from_xpm_data(generateXPM(warn, warn));
327 items[i].image = gtk_image_new_from_pixbuf(pixbuf);
329 items[i].label = gtk_label_new(_("Unknown status."));
330 align = gtk_alignment_new(0.0, 0.5, 0.0, 1.0);
331 gtk_container_add(GTK_CONTAINER(align), items[i].label);
333 gtk_table_attach(GTK_TABLE(daemon_table), radio, 0, 1, (i*2)+1, (i*2)+2,
334 GTK_FILL, (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), 0, 0);
335 gtk_table_attach(GTK_TABLE(daemon_table), items[i].image, 1, 2, (i*2)+1, (i*2)+2,
336 GTK_FILL, (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), 0, 0);
337 gtk_table_attach(GTK_TABLE(daemon_table), align, 2, 3, (i*2)+1, (i*2)+2,
338 (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), 0, 0);
340 separator = gtk_hseparator_new();
341 gtk_table_attach_defaults(GTK_TABLE(daemon_table), separator, 0, 3, (i*2)+2, (i*2)+3);
343 group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(radio));
346 gtk_box_pack_start(GTK_BOX(vbox), daemon_table, FALSE, FALSE, 0);
348 textview = gtk_text_view_new();
350 buffer = gtk_text_buffer_new(NULL);
352 gtk_text_buffer_set_text(buffer, "", -1);
354 PangoFontDescription *font_desc = pango_font_description_from_string ("Fixed 10");
355 gtk_widget_modify_font(textview, font_desc);
356 pango_font_description_free(font_desc);
358 gtk_text_view_set_left_margin(GTK_TEXT_VIEW(textview), 20);
359 gtk_text_view_set_right_margin(GTK_TEXT_VIEW(textview), 20);
361 gtk_text_view_set_editable(GTK_TEXT_VIEW(textview), FALSE);
363 gtk_text_view_set_buffer(GTK_TEXT_VIEW(textview), buffer);
365 gtk_box_pack_start(GTK_BOX(vbox), textview, TRUE, TRUE, 0);
367 GtkWidget* hbox = gtk_hbox_new(FALSE, 10);
369 GtkWidget* hbox2 = gtk_hbox_new(FALSE, 0);
370 GtkWidget* label = gtk_label_new(_("Refresh interval in seconds: "));
371 gtk_box_pack_start(GTK_BOX(hbox2), label, TRUE, FALSE, 0);
372 GtkAdjustment *spinner_adj = (GtkAdjustment *) gtk_adjustment_new (monitor->RefreshInterval, 1.0, 600.0, 1.0, 5.0, 5.0);
373 timeoutspinner = gtk_spin_button_new (spinner_adj, 1.0, 0);
374 g_signal_connect(G_OBJECT(timeoutspinner), "value-changed", G_CALLBACK(IntervalChanged), NULL);
375 gtk_box_pack_start(GTK_BOX(hbox2), timeoutspinner, TRUE, FALSE, 0);
376 gtk_box_pack_start(GTK_BOX(hbox), hbox2, TRUE, FALSE, 0);
378 GtkWidget* button = new_image_button("gtk-refresh", _("Refresh now"));
379 g_signal_connect_swapped(G_OBJECT(button), "clicked", G_CALLBACK(MonitorRefresh), NULL);
380 gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, FALSE, 0);
382 button = new_image_button("gtk-help", _("About"));
383 g_signal_connect_swapped(G_OBJECT(button), "clicked", G_CALLBACK(MonitorAbout), NULL);
384 gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, FALSE, 0);
386 button = new_image_button("gtk-close", _("Close"));
387 g_signal_connect_swapped(G_OBJECT(button), "clicked", G_CALLBACK(gtk_widget_hide), G_OBJECT(window));
388 gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, FALSE, 0);
390 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
392 gtk_container_add(GTK_CONTAINER (window), vbox);
394 gtk_widget_show_all(vbox);
398 for (i = 0; i < nitems; i++) {
399 if (items[i].D_sock) {
400 writecmd(&items[i], "quit");
401 bnet_sig(items[i].D_sock, BNET_TERMINATE); /* send EOF */
402 bnet_close(items[i].D_sock);
406 free_pool_memory(args);
407 (void)WSACleanup(); /* Cleanup Windows sockets */
409 //Free xpm_generic_var
410 for (i = 0; i < (int)(sizeof(xpm_generic)/sizeof(const char*)); i++) {
411 g_free(xpm_generic_var[i]);
413 g_free(xpm_generic_var);
418 static void MonitorAbout(GtkWidget *widget, gpointer data) {
420 GtkWidget* about = gtk_message_dialog_new_with_markup(GTK_WINDOW(window),GTK_DIALOG_MODAL, GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE, _(
421 "<span size='x-large' weight='bold'>Bacula Tray Monitor</span>\n\n"
422 "Copyright (C) 2004 Kern Sibbald and John Walker\n"
423 "Written by Nicolas Boichat\n"
424 "\n<small>Version: " VERSION " (" BDATE ") %s %s %s</small>"
425 ), HOST_OS, DISTNAME, DISTVER);
427 GtkWidget* about = gtk_message_dialog_new(GTK_WINDOW(window),GTK_DIALOG_MODAL, GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE, _(
428 "Bacula Tray Monitor\n\n"
429 "Copyright (C) 2004 Kern Sibbald and John Walker\n"
430 "Written by Nicolas Boichat\n"
431 "\nVersion: " VERSION " (" BDATE ") %s %s %s"
432 ), HOST_OS, DISTNAME, DISTVER);
434 gtk_dialog_run(GTK_DIALOG(about));
435 gtk_widget_destroy(about);
438 static void MonitorRefresh(GtkWidget *widget, gpointer data) {
439 for (int i = 0; i < nitems; i++) {
444 static gboolean delete_event( GtkWidget *widget,
447 gtk_widget_hide(window);
448 return TRUE; /* do not destroy the window */
451 static void TrayIconActivate(GtkWidget *widget, gpointer data) {
452 gtk_widget_show(window);
455 static void TrayIconPopupMenu(unsigned int activateTime, unsigned int button) {
456 gtk_menu_popup(GTK_MENU(mTrayMenu), NULL, NULL, NULL, NULL, 1, 0);
457 gtk_widget_show_all(mTrayMenu);
460 static void TrayIconExit(unsigned int activateTime, unsigned int button) {
464 static void IntervalChanged(GtkWidget *widget, gpointer data) {
465 g_source_remove(timerTag);
466 timerTag = g_timeout_add(
468 gtk_spin_button_get_value(GTK_SPIN_BUTTON(timeoutspinner))*1000/nitems
472 static void DaemonChanged(GtkWidget *widget, monitoritem* data) {
473 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
475 for (int i = 0; i < nitems; i++) {
476 if (data == &(items[i])) {
481 g_return_if_fail(fullitem != -1);
483 int oldlastupdated = lastupdated;
484 lastupdated = fullitem-1;
486 lastupdated = oldlastupdated;
490 static int authenticate_daemon(monitoritem* item, JCR *jcr) {
491 switch (item->type) {
493 return authenticate_director(jcr, monitor, (DIRRES*)item->resource);
496 return authenticate_file_daemon(jcr, monitor, (CLIENT*)item->resource);
499 return authenticate_storage_daemon(jcr, monitor, (STORE*)item->resource);
502 printf("Error, currentitem is not a Client or a Storage..\n");
508 static gboolean fd_read(gpointer data) {
509 GtkTextBuffer *newbuffer = gtk_text_buffer_new(NULL);
510 GtkTextIter start, stop, nstart, nstop;
514 GString *strlast, *strcurrent;
517 if (lastupdated == nitems) {
521 if (lastupdated == fullitem) {
522 if (items[lastupdated].type == R_DIRECTOR)
523 docmd(&items[lastupdated], "status Director\n", &list);
525 docmd(&items[lastupdated], "status\n", &list);
529 gtk_text_buffer_get_end_iter(newbuffer, &stop);
530 gtk_text_buffer_insert (newbuffer, &stop, ((GString*)it->data)->str, -1);
531 if (it->data) g_string_free((GString*)it->data, TRUE);
532 } while ((it = it->next) != NULL);
534 /* Keep the selection if necessary */
535 if (gtk_text_buffer_get_selection_bounds(buffer, &start, &stop)) {
536 gtk_text_buffer_get_iter_at_offset(newbuffer, &nstart, gtk_text_iter_get_offset(&start));
537 gtk_text_buffer_get_iter_at_offset(newbuffer, &nstop, gtk_text_iter_get_offset(&stop ));
540 gtk_text_buffer_select_range(newbuffer, &nstart, &nstop);
542 gtk_text_buffer_move_mark(newbuffer, gtk_text_buffer_get_mark(newbuffer, "insert"), &nstart);
543 gtk_text_buffer_move_mark(newbuffer, gtk_text_buffer_get_mark(newbuffer, "selection_bound"), &nstop);
547 g_object_unref(buffer);
550 gtk_text_view_set_buffer(GTK_TEXT_VIEW(textview), buffer);
553 getstatus(&items[lastupdated], 1, &strcurrent);
554 getstatus(&items[lastupdated], 0, &strlast);
555 updateStatusIcon(&items[lastupdated]);
557 changeStatusMessage(&items[lastupdated], "Current job: %s\nLast job: %s", strcurrent->str, strlast->str);
559 updateStatusIcon(NULL);
561 g_string_free(strcurrent, TRUE);
562 g_string_free(strlast, TRUE);
567 void getstatus(monitoritem* item, int current, GString** str) {
569 stateenum ret = error;
570 int jobid = 0, joberrors = 0;
571 char jobstatus = JS_ErrorTerminated;
575 *str = g_string_sized_new(128);
578 if (item->type == R_DIRECTOR)
579 docmd(&items[lastupdated], ".status dir current\n", &list);
581 docmd(&items[lastupdated], ".status current\n", &list);
584 if (item->type == R_DIRECTOR)
585 docmd(&items[lastupdated], ".status dir last\n", &list);
587 docmd(&items[lastupdated], ".status last\n", &list);
591 if ((it == NULL) || (sscanf(((GString*)it->data)->str, OKqstatus, &num) != 1)) {
592 g_string_append_printf(*str, ".status error : %s", (it == NULL) ? "" : ((GString*)it->data)->str);
595 else if ((it = it->next) == NULL) {
597 g_string_append(*str, _("No current job."));
600 g_string_append(*str, _("No last job."));
604 else if ((k = sscanf(((GString*)it->data)->str, DotStatusJob, &jobid, &jobstatus, &joberrors)) == 3) {
607 ret = (joberrors > 0) ? warn : running;
608 g_string_append_printf(*str, _("Job status: Created (%d error%s)"), joberrors, (joberrors > 1) ? "s" : "");
611 ret = (joberrors > 0) ? warn : running;
612 g_string_append_printf(*str, _("Job status: Running (%d error%s)"), joberrors, (joberrors > 1) ? "s" : "");
615 ret = (joberrors > 0) ? warn : running;
616 g_string_append_printf(*str, _("Job status: Error (%d error%s)"), joberrors, (joberrors > 1) ? "s" : "");
619 g_string_append_printf(*str, _("Job status: Terminated (%d error%s)"), joberrors, (joberrors > 1) ? "s" : "");
620 ret = (joberrors > 0) ? warn : idle;
622 case JS_ErrorTerminated:
623 g_string_append_printf(*str, _("Job status: Terminated in error (%d error%s)"), joberrors, (joberrors > 1) ? "s" : "");
627 g_string_append_printf(*str, _("Job status: Fatal error (%d error%s)"), joberrors, (joberrors > 1) ? "s" : "");
631 g_string_append_printf(*str, _("Job status: Blocked (%d error%s)"), joberrors, (joberrors > 1) ? "s" : "");
635 g_string_append_printf(*str, _("Job status: Canceled (%d error%s)"), joberrors, (joberrors > 1) ? "s" : "");
639 g_string_append_printf(*str, _("Job status: Unknown(%c) (%d error%s)"), jobstatus, joberrors, (joberrors > 1) ? "s" : "");
645 fprintf(stderr, "Bad scan : '%s' %d\n", (it == NULL) ? "" : ((GString*)it->data)->str, k);
651 if (it->data) g_string_free((GString*)it->data, TRUE);
652 } while ((it = it->next) != NULL);
660 item->oldstate = ret;
664 int docmd(monitoritem* item, const char* command, GSList** list) {
668 *list = g_slist_alloc();
670 //str = g_string_sized_new(64);
673 memset(&jcr, 0, sizeof(jcr));
679 switch (item->type) {
681 dird = (DIRRES*)item->resource;
682 trayMessage("Connecting to Director %s:%d\n", dird->address, dird->DIRport);
683 changeStatusMessage(item, "Connecting to Director %s:%d", dird->address, dird->DIRport);
684 item->D_sock = bnet_connect(NULL, 0, 0, "Director daemon", dird->address, NULL, dird->DIRport, 0);
685 jcr.dir_bsock = item->D_sock;
688 filed = (CLIENT*)item->resource;
689 trayMessage("Connecting to Client %s:%d\n", filed->address, filed->FDport);
690 changeStatusMessage(item, "Connecting to Client %s:%d", filed->address, filed->FDport);
691 item->D_sock = bnet_connect(NULL, 0, 0, "File daemon", filed->address, NULL, filed->FDport, 0);
692 jcr.file_bsock = item->D_sock;
695 stored = (STORE*)item->resource;
696 trayMessage("Connecting to Storage %s:%d\n", stored->address, stored->SDport);
697 changeStatusMessage(item, "Connecting to Storage %s:%d", stored->address, stored->SDport);
698 item->D_sock = bnet_connect(NULL, 0, 0, "Storage daemon", stored->address, NULL, stored->SDport, 0);
699 jcr.store_bsock = item->D_sock;
702 printf("Error, currentitem is not a Client, a Storage or a Director..\n");
707 if (item->D_sock == NULL) {
708 g_slist_append(*list, g_string_new("Cannot connect to daemon.\n"));
709 changeStatusMessage(item, "Cannot connect to daemon.");
711 item->oldstate = error;
715 if (!authenticate_daemon(item, &jcr)) {
716 str = g_string_sized_new(64);
717 g_string_printf(str, "ERR=%s\n", item->D_sock->msg);
718 g_slist_append(*list, str);
720 item->oldstate = error;
721 changeStatusMessage(item, "Authentication error : %s", item->D_sock->msg);
726 switch (item->type) {
728 trayMessage("Opened connection with Director daemon.\n");
729 changeStatusMessage(item, "Opened connection with Director daemon.");
732 trayMessage("Opened connection with File daemon.\n");
733 changeStatusMessage(item, "Opened connection with File daemon.");
736 trayMessage("Opened connection with Storage daemon.\n");
737 changeStatusMessage(item, "Opened connection with Storage daemon.");
740 printf("Error, currentitem is not a Client, a Storage or a Director..\n");
746 if (item->type == R_DIRECTOR) { /* Read connection messages... */
748 docmd(item, "", &list); /* Usually invalid, but no matter */
751 if (it->data) g_string_free((GString*)it->data, TRUE);
752 } while ((it = it->next) != NULL);
759 writecmd(item, command);
762 if ((stat = bnet_recv(item->D_sock)) >= 0) {
763 g_slist_append(*list, g_string_new(item->D_sock->msg));
765 else if (stat == BNET_SIGNAL) {
766 if (item->D_sock->msglen == BNET_EOD) {
767 //fprintf(stderr, "<< EOD >>\n");
770 else if (item->D_sock->msglen == BNET_PROMPT) {
771 //fprintf(stderr, "<< PROMPT >>\n");
772 g_slist_append(*list, g_string_new("<< Error: BNET_PROMPT signal received. >>\n"));
775 else if (item->D_sock->msglen == BNET_HEARTBEAT) {
776 bnet_sig(item->D_sock, BNET_HB_RESPONSE);
777 g_slist_append(*list, g_string_new("<< Heartbeat signal received, answered. >>\n"));
780 str = g_string_sized_new(64);
781 g_string_printf(str, "<< Unexpected signal received : %s >>\n", bnet_sig_to_ascii(item->D_sock));
782 g_slist_append(*list, str);
785 else { /* BNET_HARDEOF || BNET_ERROR */
786 g_slist_append(*list, g_string_new("<ERROR>\n"));
789 item->oldstate = error;
790 changeStatusMessage(item, "Error : BNET_HARDEOF or BNET_ERROR");
791 //fprintf(stderr, "<< ERROR >>\n");
795 if (is_bnet_stop(item->D_sock)) {
796 g_string_append_printf(str, "<STOP>\n");
799 item->oldstate = error;
800 changeStatusMessage(item, "Error : Connection closed.");
801 //fprintf(stderr, "<< STOP >>\n");
802 return 0; /* error or term */
807 void writecmd(monitoritem* item, const char* command) {
809 item->D_sock->msglen = strlen(command);
810 pm_strcpy(&item->D_sock->msg, command);
811 bnet_send(item->D_sock);
815 /* Note: Does not seem to work either on Gnome nor KDE... */
816 void trayMessage(const char *fmt,...) {
820 va_start(arg_ptr, fmt);
821 bvsnprintf(buf, sizeof(buf), (char *)fmt, arg_ptr);
824 fprintf(stderr, buf);
826 egg_tray_icon_send_message(egg_status_icon_get_tray_icon(mTrayIcon), 5000, (const char*)&buf, -1);
829 void changeStatusMessage(monitoritem* item, const char *fmt,...) {
833 va_start(arg_ptr, fmt);
834 bvsnprintf(buf, sizeof(buf), (char *)fmt, arg_ptr);
837 gtk_label_set_text(GTK_LABEL(item->label), buf);
840 void updateStatusIcon(monitoritem* item) {
844 stateenum state, oldstate;
847 for (int i = 0; i < nitems; i++) {
848 if (items[i].state > state) state = items[i].state;
849 if (items[i].oldstate > oldstate) oldstate = items[i].oldstate;
851 xpm = generateXPM(state, oldstate);
854 xpm = generateXPM(item->state, item->oldstate);
857 GdkPixbuf* pixbuf = gdk_pixbuf_new_from_xpm_data(xpm);
859 egg_status_icon_set_from_pixbuf(mTrayIcon, pixbuf);
860 gtk_window_set_icon(GTK_WINDOW(window), pixbuf);
863 gtk_image_set_from_pixbuf(GTK_IMAGE(item->image), pixbuf);
867 /* Note: result should not be stored, as it is a reference to xpm_generic_var */
868 static const char** generateXPM(stateenum newstate, stateenum oldstate) {
869 char* address = &xpm_generic_var[xpm_generic_first_color][xpm_generic_column];
872 strcpy(address, "ff0000");
875 strcpy(address, "ffffff");
878 strcpy(address, "00ff00");
881 strcpy(address, "ffff00");
885 address = &xpm_generic_var[xpm_generic_second_color][xpm_generic_column];
888 strcpy(address, "ff0000");
891 strcpy(address, "ffffff");
894 strcpy(address, "00ff00");
897 strcpy(address, "ffff00");
901 return (const char**)xpm_generic_var;