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(dird, R_DIRECTOR) {
195 items[nitems].type = R_DIRECTOR;
196 items[nitems].resource = dird;
197 items[nitems].D_sock = NULL;
198 items[nitems].state = warn;
201 foreach_res(filed, R_CLIENT) {
202 items[nitems].type = R_CLIENT;
203 items[nitems].resource = filed;
204 items[nitems].D_sock = NULL;
205 items[nitems].state = warn;
208 foreach_res(stored, R_STORAGE) {
209 items[nitems].type = R_STORAGE;
210 items[nitems].resource = stored;
211 items[nitems].D_sock = NULL;
212 items[nitems].state = warn;
218 Emsg1(M_ERROR_TERM, 0, _("No Client nor Storage resource defined in %s\n\
219 Without that I don't how to get status from the File or Storage Daemon :-(\n"), configfile);
226 //Copy the content of xpm_generic in xpm_generic_var to be able to modify it
227 xpm_generic_var = (char**)g_malloc(sizeof(xpm_generic));
228 for (i = 0; i < (int)(sizeof(xpm_generic)/sizeof(const char*)); i++) {
229 xpm_generic_var[i] = (char*)g_malloc(strlen(xpm_generic[i])*sizeof(char));
230 strcpy(xpm_generic_var[i], xpm_generic[i]);
233 (void)WSA_Init(); /* Initialize Windows sockets */
236 monitor = (MONITOR*)GetNextRes(R_MONITOR, (RES *)NULL);
239 gtk_init (&argc, &argv);
241 GdkPixbuf* pixbuf = gdk_pixbuf_new_from_xpm_data(generateXPM(warn, warn));
242 // This should be ideally replaced by a completely libpr0n-based icon rendering.
243 mTrayIcon = egg_status_icon_new_from_pixbuf(pixbuf);
244 g_signal_connect(G_OBJECT(mTrayIcon), "activate", G_CALLBACK(TrayIconActivate), NULL);
245 g_signal_connect(G_OBJECT(mTrayIcon), "popup-menu", G_CALLBACK(TrayIconPopupMenu), NULL);
246 g_object_unref(G_OBJECT(pixbuf));
248 mTrayMenu = gtk_menu_new();
252 entry = gtk_menu_item_new_with_label("Open status window...");
253 g_signal_connect(G_OBJECT(entry), "activate", G_CALLBACK(TrayIconActivate), NULL);
254 gtk_menu_shell_append(GTK_MENU_SHELL(mTrayMenu), entry);
256 gtk_menu_shell_append(GTK_MENU_SHELL(mTrayMenu), gtk_separator_menu_item_new());
258 entry = gtk_menu_item_new_with_label("Exit");
259 g_signal_connect(G_OBJECT(entry), "activate", G_CALLBACK(TrayIconExit), NULL);
260 gtk_menu_shell_append(GTK_MENU_SHELL(mTrayMenu), entry);
262 gtk_widget_show_all(mTrayMenu);
264 timerTag = g_timeout_add( 2000, fd_read, NULL );
266 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
268 gtk_window_set_title(GTK_WINDOW(window), "Bacula tray monitor");
270 g_signal_connect(G_OBJECT(window), "delete_event", G_CALLBACK(delete_event), NULL);
271 //g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy), NULL);
273 gtk_container_set_border_width(GTK_CONTAINER(window), 10);
275 GtkWidget* vbox = gtk_vbox_new(FALSE, 10);
277 GtkWidget* daemon_table = gtk_table_new((nitems*2)+2, 3, FALSE);
279 gtk_table_set_col_spacings(GTK_TABLE(daemon_table), 8);
281 GtkWidget* separator = gtk_hseparator_new();
282 gtk_table_attach_defaults(GTK_TABLE(daemon_table), separator, 0, 3, 0, 1);
285 GSList *group = NULL;
289 for (int i = 0; i < nitems; i++) {
290 switch (items[i].type) {
292 str = g_string_new(((DIRRES*)(items[i].resource))->hdr.name);
293 g_string_append(str, _(" (DIR)"));
296 str = g_string_new(((CLIENT*)(items[i].resource))->hdr.name);
297 g_string_append(str, _(" (FD)"));
300 str = g_string_new(((STORE*)(items[i].resource))->hdr.name);
301 g_string_append(str, _(" (SD)"));
307 radio = gtk_radio_button_new_with_label(group, str->str);
308 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio), i == 0);
309 g_signal_connect(G_OBJECT(radio), "toggled", G_CALLBACK(DaemonChanged), &(items[i]));
311 pixbuf = gdk_pixbuf_new_from_xpm_data(generateXPM(warn, warn));
312 items[i].image = gtk_image_new_from_pixbuf(pixbuf);
314 items[i].label = gtk_label_new(_("Unknown status."));
315 align = gtk_alignment_new(0.0, 0.5, 0.0, 1.0);
316 gtk_container_add(GTK_CONTAINER(align), items[i].label);
318 gtk_table_attach(GTK_TABLE(daemon_table), radio, 0, 1, (i*2)+1, (i*2)+2,
319 GTK_FILL, (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), 0, 0);
320 gtk_table_attach(GTK_TABLE(daemon_table), items[i].image, 1, 2, (i*2)+1, (i*2)+2,
321 GTK_FILL, (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), 0, 0);
322 gtk_table_attach(GTK_TABLE(daemon_table), align, 2, 3, (i*2)+1, (i*2)+2,
323 (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), 0, 0);
325 separator = gtk_hseparator_new();
326 gtk_table_attach_defaults(GTK_TABLE(daemon_table), separator, 0, 3, (i*2)+2, (i*2)+3);
328 group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(radio));
331 gtk_box_pack_start(GTK_BOX(vbox), daemon_table, FALSE, FALSE, 0);
333 textview = gtk_text_view_new();
335 buffer = gtk_text_buffer_new(NULL);
337 gtk_text_buffer_set_text(buffer, "", -1);
339 PangoFontDescription *font_desc = pango_font_description_from_string ("Fixed 10");
340 gtk_widget_modify_font(textview, font_desc);
341 pango_font_description_free(font_desc);
343 gtk_text_view_set_left_margin(GTK_TEXT_VIEW(textview), 20);
344 gtk_text_view_set_right_margin(GTK_TEXT_VIEW(textview), 20);
346 gtk_text_view_set_editable(GTK_TEXT_VIEW(textview), FALSE);
348 gtk_text_view_set_buffer(GTK_TEXT_VIEW(textview), buffer);
350 gtk_box_pack_start(GTK_BOX(vbox), textview, TRUE, TRUE, 0);
352 GtkWidget* hbox = gtk_hbox_new(FALSE, 10);
354 GtkWidget* hbox2 = gtk_hbox_new(FALSE, 0);
355 GtkWidget* label = gtk_label_new(_("Refresh interval in seconds: "));
356 gtk_box_pack_start(GTK_BOX(hbox2), label, TRUE, FALSE, 0);
357 GtkAdjustment *spinner_adj = (GtkAdjustment *) gtk_adjustment_new (nitems*2, nitems, 120.0, 1.0, 5.0, 5.0);
358 timeoutspinner = gtk_spin_button_new (spinner_adj, 1.0, 0);
359 g_signal_connect(G_OBJECT(timeoutspinner), "value-changed", G_CALLBACK(IntervalChanged), NULL);
360 gtk_box_pack_start(GTK_BOX(hbox2), timeoutspinner, TRUE, FALSE, 0);
361 gtk_box_pack_start(GTK_BOX(hbox), hbox2, TRUE, FALSE, 0);
363 GtkWidget* button = new_image_button("gtk-refresh", _("Refresh now"));
364 g_signal_connect_swapped(G_OBJECT(button), "clicked", G_CALLBACK(MonitorRefresh), NULL);
365 gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, FALSE, 0);
367 button = new_image_button("gtk-help", _("About"));
368 g_signal_connect_swapped(G_OBJECT(button), "clicked", G_CALLBACK(MonitorAbout), NULL);
369 gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, FALSE, 0);
371 button = new_image_button("gtk-close", _("Close"));
372 g_signal_connect_swapped(G_OBJECT(button), "clicked", G_CALLBACK(gtk_widget_hide), G_OBJECT(window));
373 gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, FALSE, 0);
375 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
377 gtk_container_add(GTK_CONTAINER (window), vbox);
379 gtk_widget_show_all(vbox);
383 for (i = 0; i < nitems; i++) {
384 if (items[i].D_sock) {
385 writecmd(&items[i], "quit");
386 bnet_sig(items[i].D_sock, BNET_TERMINATE); /* send EOF */
387 bnet_close(items[i].D_sock);
391 free_pool_memory(args);
392 (void)WSACleanup(); /* Cleanup Windows sockets */
394 //Free xpm_generic_var
395 for (i = 0; i < (int)(sizeof(xpm_generic)/sizeof(const char*)); i++) {
396 g_free(xpm_generic_var[i]);
398 g_free(xpm_generic_var);
403 static void MonitorAbout(GtkWidget *widget, gpointer data) {
405 GtkWidget* about = gtk_message_dialog_new_with_markup(GTK_WINDOW(window),GTK_DIALOG_MODAL, GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE, _(
406 "<span size='x-large' weight='bold'>Bacula Tray Monitor</span>\n\n"
407 "Copyright (C) 2004 Kern Sibbald and John Walker\n"
408 "Written by Nicolas Boichat\n"
409 "\n<small>Version: " VERSION " (" BDATE ") %s %s %s</small>"
410 ), HOST_OS, DISTNAME, DISTVER);
412 GtkWidget* about = gtk_message_dialog_new(GTK_WINDOW(window),GTK_DIALOG_MODAL, GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE, _(
413 "Bacula Tray Monitor\n\n"
414 "Copyright (C) 2004 Kern Sibbald and John Walker\n"
415 "Written by Nicolas Boichat\n"
416 "\nVersion: " VERSION " (" BDATE ") %s %s %s"
417 ), HOST_OS, DISTNAME, DISTVER);
419 gtk_dialog_run(GTK_DIALOG(about));
420 gtk_widget_destroy(about);
423 static void MonitorRefresh(GtkWidget *widget, gpointer data) {
424 for (int i = 0; i < nitems; i++) {
429 static gboolean delete_event( GtkWidget *widget,
432 gtk_widget_hide(window);
433 return TRUE; /* do not destroy the window */
436 static void TrayIconActivate(GtkWidget *widget, gpointer data) {
437 gtk_widget_show(window);
440 static void TrayIconPopupMenu(unsigned int activateTime, unsigned int button) {
441 gtk_menu_popup(GTK_MENU(mTrayMenu), NULL, NULL, NULL, NULL, 1, 0);
442 gtk_widget_show_all(mTrayMenu);
445 static void TrayIconExit(unsigned int activateTime, unsigned int button) {
449 static void IntervalChanged(GtkWidget *widget, gpointer data) {
450 g_source_remove(timerTag);
451 timerTag = g_timeout_add(
453 gtk_spin_button_get_value(GTK_SPIN_BUTTON(timeoutspinner))*1000/nitems
457 static void DaemonChanged(GtkWidget *widget, monitoritem* data) {
458 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
460 for (int i = 0; i < nitems; i++) {
461 if (data == &(items[i])) {
466 g_return_if_fail(fullitem != -1);
468 int oldlastupdated = lastupdated;
469 lastupdated = fullitem-1;
471 lastupdated = oldlastupdated;
475 static int authenticate_daemon(monitoritem* item, JCR *jcr) {
476 switch (item->type) {
478 return authenticate_director(jcr, monitor, (DIRRES*)item->resource);
481 return authenticate_file_daemon(jcr, monitor, (CLIENT*)item->resource);
484 return authenticate_storage_daemon(jcr, monitor, (STORE*)item->resource);
487 printf("Error, currentitem is not a Client or a Storage..\n");
493 static gboolean fd_read(gpointer data) {
494 GtkTextBuffer *newbuffer = gtk_text_buffer_new(NULL);
495 GtkTextIter start, stop, nstart, nstop;
499 GString *strlast, *strcurrent;
502 if (lastupdated == nitems) {
506 if (lastupdated == fullitem) {
507 if (items[lastupdated].type == R_DIRECTOR)
508 docmd(&items[lastupdated], "status Director\n", &list);
510 docmd(&items[lastupdated], "status\n", &list);
514 gtk_text_buffer_get_end_iter(newbuffer, &stop);
515 gtk_text_buffer_insert (newbuffer, &stop, ((GString*)it->data)->str, -1);
516 if (it->data) g_string_free((GString*)it->data, TRUE);
517 } while ((it = it->next) != NULL);
519 /* Keep the selection if necessary */
520 if (gtk_text_buffer_get_selection_bounds(buffer, &start, &stop)) {
521 gtk_text_buffer_get_iter_at_offset(newbuffer, &nstart, gtk_text_iter_get_offset(&start));
522 gtk_text_buffer_get_iter_at_offset(newbuffer, &nstop, gtk_text_iter_get_offset(&stop ));
525 gtk_text_buffer_select_range(newbuffer, &nstart, &nstop);
527 gtk_text_buffer_move_mark(newbuffer, gtk_text_buffer_get_mark(newbuffer, "insert"), &nstart);
528 gtk_text_buffer_move_mark(newbuffer, gtk_text_buffer_get_mark(newbuffer, "selection_bound"), &nstop);
532 g_object_unref(buffer);
535 gtk_text_view_set_buffer(GTK_TEXT_VIEW(textview), buffer);
538 getstatus(&items[lastupdated], 1, &strcurrent);
539 getstatus(&items[lastupdated], 0, &strlast);
540 updateStatusIcon(&items[lastupdated]);
542 changeStatusMessage(&items[lastupdated], "Current job: %s\nLast job: %s", strcurrent->str, strlast->str);
544 updateStatusIcon(NULL);
546 g_string_free(strcurrent, TRUE);
547 g_string_free(strlast, TRUE);
552 void getstatus(monitoritem* item, int current, GString** str) {
554 stateenum ret = error;
555 int jobid = 0, joberrors = 0;
556 char jobstatus = JS_ErrorTerminated;
560 *str = g_string_sized_new(128);
563 if (item->type == R_DIRECTOR)
564 docmd(&items[lastupdated], ".status dir current\n", &list);
566 docmd(&items[lastupdated], ".status current\n", &list);
569 if (item->type == R_DIRECTOR)
570 docmd(&items[lastupdated], ".status dir last\n", &list);
572 docmd(&items[lastupdated], ".status last\n", &list);
576 if ((it == NULL) || (sscanf(((GString*)it->data)->str, OKqstatus, &num) != 1)) {
577 g_string_append_printf(*str, ".status error : %s", (it == NULL) ? "" : ((GString*)it->data)->str);
580 else if ((it = it->next) == NULL) {
582 g_string_append(*str, _("No current job."));
585 g_string_append(*str, _("No last job."));
589 else if ((k = sscanf(((GString*)it->data)->str, DotStatusJob, &jobid, &jobstatus, &joberrors)) == 3) {
592 ret = (joberrors > 0) ? warn : running;
593 g_string_append_printf(*str, _("Job status: Created (%d error%s)"), joberrors, (joberrors > 1) ? "s" : "");
596 ret = (joberrors > 0) ? warn : running;
597 g_string_append_printf(*str, _("Job status: Running (%d error%s)"), joberrors, (joberrors > 1) ? "s" : "");
600 ret = (joberrors > 0) ? warn : running;
601 g_string_append_printf(*str, _("Job status: Error (%d error%s)"), joberrors, (joberrors > 1) ? "s" : "");
604 g_string_append_printf(*str, _("Job status: Terminated (%d error%s)"), joberrors, (joberrors > 1) ? "s" : "");
605 ret = (joberrors > 0) ? warn : idle;
607 case JS_ErrorTerminated:
608 g_string_append_printf(*str, _("Job status: Terminated in error (%d error%s)"), joberrors, (joberrors > 1) ? "s" : "");
612 g_string_append_printf(*str, _("Job status: Fatal error (%d error%s)"), joberrors, (joberrors > 1) ? "s" : "");
616 g_string_append_printf(*str, _("Job status: Blocked (%d error%s)"), joberrors, (joberrors > 1) ? "s" : "");
620 g_string_append_printf(*str, _("Job status: Canceled (%d error%s)"), joberrors, (joberrors > 1) ? "s" : "");
624 g_string_append_printf(*str, _("Job status: Unknown(%c) (%d error%s)"), jobstatus, joberrors, (joberrors > 1) ? "s" : "");
630 fprintf(stderr, "Bad scan : '%s' %d\n", (it == NULL) ? "" : ((GString*)it->data)->str, k);
636 if (it->data) g_string_free((GString*)it->data, TRUE);
637 } while ((it = it->next) != NULL);
645 item->oldstate = ret;
649 int docmd(monitoritem* item, const char* command, GSList** list) {
653 *list = g_slist_alloc();
655 //str = g_string_sized_new(64);
658 memset(&jcr, 0, sizeof(jcr));
664 switch (item->type) {
666 dird = (DIRRES*)item->resource;
667 trayMessage("Connecting to Director %s:%d\n", dird->address, dird->DIRport);
668 changeStatusMessage(item, "Connecting to Director %s:%d", dird->address, dird->DIRport);
669 item->D_sock = bnet_connect(NULL, 0, 0, "Director daemon", dird->address, NULL, dird->DIRport, 0);
670 jcr.dir_bsock = item->D_sock;
673 filed = (CLIENT*)item->resource;
674 trayMessage("Connecting to Client %s:%d\n", filed->address, filed->FDport);
675 changeStatusMessage(item, "Connecting to Client %s:%d", filed->address, filed->FDport);
676 item->D_sock = bnet_connect(NULL, 0, 0, "File daemon", filed->address, NULL, filed->FDport, 0);
677 jcr.file_bsock = item->D_sock;
680 stored = (STORE*)item->resource;
681 trayMessage("Connecting to Storage %s:%d\n", stored->address, stored->SDport);
682 changeStatusMessage(item, "Connecting to Storage %s:%d", stored->address, stored->SDport);
683 item->D_sock = bnet_connect(NULL, 0, 0, "Storage daemon", stored->address, NULL, stored->SDport, 0);
684 jcr.store_bsock = item->D_sock;
687 printf("Error, currentitem is not a Client, a Storage or a Director..\n");
692 if (item->D_sock == NULL) {
693 g_slist_append(*list, g_string_new("Cannot connect to daemon.\n"));
694 changeStatusMessage(item, "Cannot connect to daemon.");
696 item->oldstate = error;
700 if (!authenticate_daemon(item, &jcr)) {
701 str = g_string_sized_new(64);
702 g_string_printf(str, "ERR=%s\n", item->D_sock->msg);
703 g_slist_append(*list, str);
705 item->oldstate = error;
706 changeStatusMessage(item, "Authentication error : %s", item->D_sock->msg);
711 switch (item->type) {
713 trayMessage("Opened connection with Director daemon.\n");
714 changeStatusMessage(item, "Opened connection with Director daemon.");
717 trayMessage("Opened connection with File daemon.\n");
718 changeStatusMessage(item, "Opened connection with File daemon.");
721 trayMessage("Opened connection with Storage daemon.\n");
722 changeStatusMessage(item, "Opened connection with Storage daemon.");
725 printf("Error, currentitem is not a Client, a Storage or a Director..\n");
731 if (item->type == R_DIRECTOR) { /* Read connection messages... */
733 docmd(item, "", &list); /* Usually invalid, but no matter */
736 if (it->data) g_string_free((GString*)it->data, TRUE);
737 } while ((it = it->next) != NULL);
744 writecmd(item, command);
747 if ((stat = bnet_recv(item->D_sock)) >= 0) {
748 g_slist_append(*list, g_string_new(item->D_sock->msg));
750 else if (stat == BNET_SIGNAL) {
751 if (item->D_sock->msglen == BNET_EOD) {
752 //fprintf(stderr, "<< EOD >>\n");
755 else if (item->D_sock->msglen == BNET_PROMPT) {
756 //fprintf(stderr, "<< PROMPT >>\n");
757 g_slist_append(*list, g_string_new("<< Error: BNET_PROMPT signal received. >>\n"));
760 else if (item->D_sock->msglen == BNET_HEARTBEAT) {
761 bnet_sig(item->D_sock, BNET_HB_RESPONSE);
762 g_slist_append(*list, g_string_new("<< Heartbeat signal received, answered. >>\n"));
765 str = g_string_sized_new(64);
766 g_string_printf(str, "<< Unexpected signal received : %s >>\n", bnet_sig_to_ascii(item->D_sock));
767 g_slist_append(*list, str);
770 else { /* BNET_HARDEOF || BNET_ERROR */
771 g_slist_append(*list, g_string_new("<ERROR>\n"));
774 item->oldstate = error;
775 changeStatusMessage(item, "Error : BNET_HARDEOF or BNET_ERROR");
776 //fprintf(stderr, "<< ERROR >>\n");
780 if (is_bnet_stop(item->D_sock)) {
781 g_string_append_printf(str, "<STOP>\n");
784 item->oldstate = error;
785 changeStatusMessage(item, "Error : Connection closed.");
786 //fprintf(stderr, "<< STOP >>\n");
787 return 0; /* error or term */
792 void writecmd(monitoritem* item, const char* command) {
794 item->D_sock->msglen = strlen(command);
795 pm_strcpy(&item->D_sock->msg, command);
796 bnet_send(item->D_sock);
800 /* Note: Does not seem to work either on Gnome nor KDE... */
801 void trayMessage(const char *fmt,...) {
805 va_start(arg_ptr, fmt);
806 bvsnprintf(buf, sizeof(buf), (char *)fmt, arg_ptr);
809 fprintf(stderr, buf);
811 egg_tray_icon_send_message(egg_status_icon_get_tray_icon(mTrayIcon), 5000, (const char*)&buf, -1);
814 void changeStatusMessage(monitoritem* item, const char *fmt,...) {
818 va_start(arg_ptr, fmt);
819 bvsnprintf(buf, sizeof(buf), (char *)fmt, arg_ptr);
822 gtk_label_set_text(GTK_LABEL(item->label), buf);
825 void updateStatusIcon(monitoritem* item) {
829 stateenum state, oldstate;
832 for (int i = 0; i < nitems; i++) {
833 if (items[i].state > state) state = items[i].state;
834 if (items[i].oldstate > oldstate) oldstate = items[i].oldstate;
836 xpm = generateXPM(state, oldstate);
839 xpm = generateXPM(item->state, item->oldstate);
842 GdkPixbuf* pixbuf = gdk_pixbuf_new_from_xpm_data(xpm);
844 egg_status_icon_set_from_pixbuf(mTrayIcon, pixbuf);
845 gtk_window_set_icon(GTK_WINDOW(window), pixbuf);
848 gtk_image_set_from_pixbuf(GTK_IMAGE(item->image), pixbuf);
852 /* Note: result should not be stored, as it is a reference to xpm_generic_var */
853 static const char** generateXPM(stateenum newstate, stateenum oldstate) {
854 char* address = &xpm_generic_var[xpm_generic_first_color][xpm_generic_column];
857 strcpy(address, "ff0000");
860 strcpy(address, "ffffff");
863 strcpy(address, "00ff00");
866 strcpy(address, "ffff00");
870 address = &xpm_generic_var[xpm_generic_second_color][xpm_generic_column];
873 strcpy(address, "ff0000");
876 strcpy(address, "ffffff");
879 strcpy(address, "00ff00");
882 strcpy(address, "ffff00");
886 return (const char**)xpm_generic_var;