3 * Bacula Gnome Tray Monitor
5 * Nicolas Boichat, August MMIV
11 Copyright (C) 2000-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"
38 #include "running.xpm"
42 /* Imported functions */
43 int authenticate_file_daemon(JCR *jcr, MONITOR *monitor, CLIENT* client);
45 /* Forward referenced functions */
46 void writecmd(const char* command);
48 /* Static variables */
49 static char *configfile = NULL;
50 static BSOCK *FD_sock = NULL;
51 static MONITOR *monitor;
56 /* UI variables and functions */
65 stateenum currentstatus = warn;
67 static gboolean fd_read(gpointer data);
68 void trayMessage(const char *fmt,...);
69 void changeIcon(stateenum status);
70 void writeToTextBuffer(GtkTextBuffer *buffer, const char *fmt,...);
73 static void TrayIconActivate(GtkWidget *widget, gpointer data);
74 static gboolean delete_event(GtkWidget *widget, GdkEvent *event, gpointer data);
77 static EggStatusIcon* mTrayIcon;
80 GtkTextBuffer *buffer;
82 #define CONFIG_FILE "./tray-monitor.conf" /* default configuration file */
87 "Copyright (C) 2000-2004 Kern Sibbald and John Walker\n"
88 "\nVersion: " VERSION " (" BDATE ") %s %s %s\n\n"
89 "Usage: tray-monitor [-s] [-c config_file] [-d debug_level]\n"
90 " -c <file> set configuration file to file\n"
91 " -dnn set debug level to nn\n"
93 " -t test - read configuration and exit\n"
94 " -? print this message.\n"
95 "\n"), HOST_OS, DISTNAME, DISTVER);
98 /*********************************************************************
100 * Main Bacula Tray Monitor -- User Interface Program
103 int main(int argc, char *argv[])
106 bool test_config = false;
109 my_name_is(argc, argv, "tray-monitor");
110 textdomain("bacula");
111 init_msg(NULL, NULL);
112 working_directory = "/tmp";
113 args = get_pool_memory(PM_FNAME);
115 while ((ch = getopt(argc, argv, "bc:d:r:st?")) != -1) {
117 case 'c': /* configuration file */
118 if (configfile != NULL) {
121 configfile = bstrdup(optarg);
125 debug_level = atoi(optarg);
126 if (debug_level <= 0) {
149 if (configfile == NULL) {
150 configfile = bstrdup(CONFIG_FILE);
153 parse_config(configfile);
157 foreach_res(filed, R_CLIENT) {
162 Emsg1(M_ERROR_TERM, 0, _("No Client resource defined in %s (or more than one)\n\
163 Without that I don't how to get status from the Client :-(\n"), configfile);
170 (void)WSA_Init(); /* Initialize Windows sockets */
173 monitor = (MONITOR*)GetNextRes(R_MONITOR, (RES *)NULL);
176 gtk_init (&argc, &argv);
178 GdkPixbuf* pixbuf = gdk_pixbuf_new_from_xpm_data(xpm_warn);
179 // This should be ideally replaced by a completely libpr0n-based icon rendering.
180 mTrayIcon = egg_status_icon_new_from_pixbuf(pixbuf);
181 g_signal_connect(G_OBJECT(mTrayIcon), "activate", G_CALLBACK(TrayIconActivate), NULL);
182 /* g_signal_connect(G_OBJECT(mTrayIcon), "popup-menu", G_CALLBACK(TrayIconPopupMenu), this);*/
183 g_object_unref(G_OBJECT(pixbuf));
185 timerTag = g_timeout_add( 5000, fd_read, NULL );
187 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
189 gtk_window_set_title(GTK_WINDOW(window), "Bacula tray monitor");
191 g_signal_connect(G_OBJECT(window), "delete_event", G_CALLBACK(delete_event), NULL);
192 //g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy), NULL);
194 gtk_container_set_border_width(GTK_CONTAINER(window), 10);
196 textview = gtk_text_view_new();
198 buffer = gtk_text_buffer_new(NULL);
200 gtk_text_buffer_set_text(buffer, "", -1);
202 PangoFontDescription *font_desc = pango_font_description_from_string ("Fixed 10");
203 gtk_widget_modify_font(textview, font_desc);
204 pango_font_description_free (font_desc);
206 gtk_text_view_set_editable(GTK_TEXT_VIEW(textview), FALSE);
208 gtk_text_view_set_buffer(GTK_TEXT_VIEW(textview), buffer);
210 gtk_container_add(GTK_CONTAINER (window), textview);
212 gtk_widget_show(textview);
220 bnet_sig(FD_sock, BNET_TERMINATE); /* send EOF */
224 free_pool_memory(args);
225 (void)WSACleanup(); /* Cleanup Windows sockets */
229 static gboolean delete_event( GtkWidget *widget,
232 gtk_widget_hide(window);
233 return TRUE; /* do not destroy the window */
236 static void TrayIconActivate(GtkWidget *widget, gpointer data) {
237 gtk_widget_show(window);
240 static gboolean fd_read(gpointer data) {
242 int statuschanged = 0;
243 GtkTextBuffer *newbuffer = gtk_text_buffer_new(NULL);
244 GtkTextIter start, stop, nstart, nstop;
246 gtk_text_buffer_set_text (newbuffer, "", -1);
250 filed = (CLIENT*)GetNextRes(R_CLIENT, NULL);
253 memset(&jcr, 0, sizeof(jcr));
255 writeToTextBuffer(newbuffer, "Connecting to Client %s:%d\n", filed->address, filed->FDport);
256 FD_sock = bnet_connect(NULL, 3, 3, "File daemon", filed->address,
257 NULL, filed->FDport, 0);
258 if (FD_sock == NULL) {
262 jcr.file_bsock = FD_sock;
264 if (!authenticate_file_daemon(&jcr, monitor, filed)) {
265 writeToTextBuffer(newbuffer, "ERR=%s", FD_sock->msg);
271 trayMessage("Opened connection with File daemon");
277 if ((stat = bnet_recv(FD_sock)) >= 0) {
278 writeToTextBuffer(newbuffer, FD_sock->msg);
279 if (strstr(FD_sock->msg, " is running.") != NULL) {
283 else if (strstr(FD_sock->msg, "No Jobs running.") != NULL) {
288 else if (stat == BNET_SIGNAL) {
289 if (FD_sock->msglen == BNET_EOD) {
290 if (statuschanged == 0) {
295 else if (FD_sock->msglen == BNET_HEARTBEAT) {
296 bnet_sig(FD_sock, BNET_HB_RESPONSE);
297 writeToTextBuffer(newbuffer, "<< Heartbeat signal received, answered. >>");
300 writeToTextBuffer(newbuffer, "<< Unexpected signal received : %s >>", bnet_sig_to_ascii(FD_sock));
303 else { /* BNET_HARDEOF || BNET_ERROR */
304 writeToTextBuffer(newbuffer, "<ERROR>\n");
310 if (is_bnet_stop(FD_sock)) {
311 writeToTextBuffer(newbuffer, "<STOP>\n");
314 break; /* error or term */
318 /* Keep the selection if necessary */
319 if (gtk_text_buffer_get_selection_bounds(buffer, &start, &stop)) {
320 gtk_text_buffer_get_iter_at_offset(newbuffer, &nstart, gtk_text_iter_get_offset(&start));
321 gtk_text_buffer_get_iter_at_offset(newbuffer, &nstop, gtk_text_iter_get_offset(&stop ));
322 gtk_text_buffer_select_range(newbuffer, &nstart, &nstop);
326 gtk_text_view_set_buffer(GTK_TEXT_VIEW(textview), buffer);
331 void writecmd(const char* command) {
333 FD_sock->msglen = strlen(command);
334 pm_strcpy(&FD_sock->msg, command);
339 /* Note: Does not seem to work either on Gnome nor KDE... */
340 void trayMessage(const char *fmt,...) {
344 va_start(arg_ptr, fmt);
345 bvsnprintf(buf, sizeof(buf), (char *)fmt, arg_ptr);
348 egg_tray_icon_send_message(egg_status_icon_get_tray_icon(mTrayIcon), 5000, (const char*)&buf, -1);
351 void changeIcon(stateenum status) {
352 if (status == currentstatus)
359 xpm = (const char**)&xpm_error;
362 xpm = (const char**)&xpm_idle;
365 xpm = (const char**)&xpm_running;
368 xpm = (const char**)&xpm_saving;
371 xpm = (const char**)&xpm_warn;
378 GdkPixbuf* pixbuf = gdk_pixbuf_new_from_xpm_data(xpm);
379 // This should be ideally replaced by a completely libpr0n-based icon rendering.
380 egg_status_icon_set_from_pixbuf(mTrayIcon, pixbuf);
382 currentstatus = status;
385 void writeToTextBuffer(GtkTextBuffer *buffer, const char *fmt,...) {
390 va_start(arg_ptr, fmt);
391 bvsnprintf(buf, sizeof(buf), (char *)fmt, arg_ptr);
394 gtk_text_buffer_get_end_iter(buffer, &iter);
395 gtk_text_buffer_insert(buffer, &iter, buf, -1);