]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/tray-monitor/tray-monitor.c
First working version
[bacula/bacula] / bacula / src / tray-monitor / tray-monitor.c
1 /*
2  *
3  *   Bacula Gnome Tray Monitor
4  *
5  *     Nicolas Boichat, August MMIV
6  *
7  *     Version $Id$
8  */
9
10 /*
11    Copyright (C) 2000-2004 Kern Sibbald and John Walker
12
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.
17
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.
22
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,
26    MA 02111-1307, USA.
27
28  */
29
30 #include "bacula.h"
31 #include "tray-monitor.h"
32
33 #include "eggstatusicon.h"
34 #include <gtk/gtk.h>
35
36 #include "idle.xpm"
37 #include "error.xpm"
38 #include "running.xpm"
39 #include "saving.xpm"
40 #include "warn.xpm"
41
42 /* Imported functions */
43 int authenticate_file_daemon(JCR *jcr, MONITOR *monitor, CLIENT* client);
44
45 /* Forward referenced functions */
46 void writecmd(const char* command);
47
48 /* Static variables */
49 static char *configfile = NULL;
50 static BSOCK *FD_sock = NULL;
51 static MONITOR *monitor;
52 static POOLMEM *args;
53 static JCR jcr;
54 static CLIENT* filed;
55
56 /* UI variables and functions */
57 enum stateenum {
58    error,
59    idle,
60    running,
61    saving,
62    warn
63 };
64
65 stateenum currentstatus = warn;
66
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,...);
71
72 /* Callbacks */
73 static void TrayIconActivate(GtkWidget *widget, gpointer data);
74 static gboolean delete_event(GtkWidget *widget, GdkEvent  *event, gpointer   data);
75
76 static gint timerTag;
77 static EggStatusIcon* mTrayIcon;
78 GtkWidget *window;
79 GtkWidget *textview;
80 GtkTextBuffer *buffer;
81
82 #define CONFIG_FILE "./tray-monitor.conf"   /* default configuration file */
83
84 static void usage()
85 {
86    fprintf(stderr, _(
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"
92 "       -s          no signals\n"
93 "       -t          test - read configuration and exit\n"
94 "       -?          print this message.\n"  
95 "\n"), HOST_OS, DISTNAME, DISTVER);
96 }
97
98 /*********************************************************************
99  *
100  *         Main Bacula Tray Monitor -- User Interface Program
101  *
102  */
103 int main(int argc, char *argv[])
104 {
105    int ch, nfiled;
106    bool test_config = false;
107
108    init_stack_dump();
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);
114
115    while ((ch = getopt(argc, argv, "bc:d:r:st?")) != -1) {
116       switch (ch) {
117       case 'c':                    /* configuration file */
118          if (configfile != NULL) {
119             free(configfile);
120          }
121          configfile = bstrdup(optarg);
122          break;
123
124       case 'd':
125          debug_level = atoi(optarg);
126          if (debug_level <= 0) {
127             debug_level = 1;
128          }
129          break;
130
131       case 't':
132          test_config = true;
133          break;
134
135       case '?':
136       default:
137          usage();
138          exit(1);
139       }  
140    }
141    argc -= optind;
142    argv += optind;
143
144    if (argc) {
145       usage();
146       exit(1);
147    }
148
149    if (configfile == NULL) {
150       configfile = bstrdup(CONFIG_FILE);
151    }
152
153    parse_config(configfile);
154
155    LockRes();
156    nfiled = 0;
157    foreach_res(filed, R_CLIENT) {
158       nfiled++;
159    }
160    UnlockRes();
161    if (nfiled != 1) {
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);
164    }
165
166    if (test_config) {
167       exit(0);
168    }
169    
170    (void)WSA_Init();                        /* Initialize Windows sockets */
171
172    LockRes();
173    monitor = (MONITOR*)GetNextRes(R_MONITOR, (RES *)NULL);
174    UnlockRes();
175    
176    gtk_init (&argc, &argv);
177    
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));
184
185    timerTag = g_timeout_add( 5000, fd_read, NULL );
186         
187    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
188    
189    gtk_window_set_title(GTK_WINDOW(window), "Bacula tray monitor");
190    
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);
193    
194    gtk_container_set_border_width(GTK_CONTAINER(window), 10);
195       
196    textview = gtk_text_view_new();
197
198    buffer = gtk_text_buffer_new(NULL);
199
200    gtk_text_buffer_set_text(buffer, "", -1);
201
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);
205    
206    gtk_text_view_set_editable(GTK_TEXT_VIEW(textview), FALSE);
207    
208    gtk_text_view_set_buffer(GTK_TEXT_VIEW(textview), buffer);
209       
210    gtk_container_add(GTK_CONTAINER (window), textview);
211    
212    gtk_widget_show(textview);
213    
214    fd_read(NULL);
215    
216    gtk_main();
217       
218    if (FD_sock) {
219       writecmd("status");
220       bnet_sig(FD_sock, BNET_TERMINATE); /* send EOF */
221       bnet_close(FD_sock);
222    }
223
224    free_pool_memory(args);
225    (void)WSACleanup();               /* Cleanup Windows sockets */
226    return 0;
227 }
228
229 static gboolean delete_event( GtkWidget *widget,
230                               GdkEvent  *event,
231                               gpointer   data ) {
232    gtk_widget_hide(window);
233    return TRUE; /* do not destroy the window */
234 }
235
236 static void TrayIconActivate(GtkWidget *widget, gpointer data) {
237     gtk_widget_show(window);
238 }
239
240 static gboolean fd_read(gpointer data) {
241    int stat;
242    int statuschanged = 0;
243    GtkTextBuffer *newbuffer = gtk_text_buffer_new(NULL);
244    GtkTextIter start, stop, nstart, nstop;
245    
246    gtk_text_buffer_set_text (newbuffer, "", -1);
247       
248    if (!FD_sock) {
249       LockRes();
250       filed = (CLIENT*)GetNextRes(R_CLIENT, NULL);
251       UnlockRes();
252    
253       memset(&jcr, 0, sizeof(jcr));
254             
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) {
259          changeIcon(error);
260          return 1;
261       }
262       jcr.file_bsock = FD_sock;
263       
264       if (!authenticate_file_daemon(&jcr, monitor, filed)) {
265          writeToTextBuffer(newbuffer, "ERR=%s", FD_sock->msg);
266          FD_sock = NULL;
267          changeIcon(error);
268          return 0;
269       }
270    
271       trayMessage("Opened connection with File daemon");
272    }
273       
274    writecmd("status");
275    
276    while(1) {
277       if ((stat = bnet_recv(FD_sock)) >= 0) {
278          writeToTextBuffer(newbuffer, FD_sock->msg);
279          if (strstr(FD_sock->msg, " is running.") != NULL) {
280             changeIcon(running);
281             statuschanged = 1;
282          }
283          else if (strstr(FD_sock->msg, "No Jobs running.") != NULL) {
284             changeIcon(idle);
285             statuschanged = 1;
286          }
287       }
288       else if (stat == BNET_SIGNAL) {
289          if (FD_sock->msglen == BNET_EOD) {
290             if (statuschanged == 0) {
291                changeIcon(warn);
292             }
293             break;
294          }
295          else if (FD_sock->msglen == BNET_HEARTBEAT) {
296             bnet_sig(FD_sock, BNET_HB_RESPONSE);
297             writeToTextBuffer(newbuffer, "<< Heartbeat signal received, answered. >>");
298          }
299          else {
300             writeToTextBuffer(newbuffer, "<< Unexpected signal received : %s >>", bnet_sig_to_ascii(FD_sock));
301          }
302       }
303       else { /* BNET_HARDEOF || BNET_ERROR */
304          writeToTextBuffer(newbuffer, "<ERROR>\n");
305          FD_sock = NULL;
306          changeIcon(error);
307          break;
308       }
309            
310       if (is_bnet_stop(FD_sock)) {
311          writeToTextBuffer(newbuffer, "<STOP>\n");
312          FD_sock = NULL;
313          changeIcon(error);
314          break;            /* error or term */
315       }
316    }
317    
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);
323    }
324
325    buffer = newbuffer;
326    gtk_text_view_set_buffer(GTK_TEXT_VIEW(textview), buffer);
327       
328    return 1;
329 }
330
331 void writecmd(const char* command) {
332    if (FD_sock) {
333       FD_sock->msglen = strlen(command);
334       pm_strcpy(&FD_sock->msg, command);
335       bnet_send(FD_sock);
336    }
337 }
338
339 /* Note: Does not seem to work either on Gnome nor KDE... */
340 void trayMessage(const char *fmt,...) {
341    char buf[3000];
342    va_list arg_ptr;
343    
344    va_start(arg_ptr, fmt);
345    bvsnprintf(buf, sizeof(buf), (char *)fmt, arg_ptr);
346    va_end(arg_ptr);
347    
348    egg_tray_icon_send_message(egg_status_icon_get_tray_icon(mTrayIcon), 5000, (const char*)&buf, -1);
349 }
350
351 void changeIcon(stateenum status) {
352    if (status == currentstatus)
353       return;
354
355    const char** xpm;
356
357    switch (status) {
358    case error:
359       xpm = (const char**)&xpm_error;
360       break;
361    case idle:
362       xpm = (const char**)&xpm_idle;
363       break;
364    case running:
365       xpm = (const char**)&xpm_running;
366       break;
367    case saving:
368       xpm = (const char**)&xpm_saving;
369       break;
370    case warn:
371       xpm = (const char**)&xpm_warn;
372       break;
373    default:
374       xpm = NULL;
375       break;
376    }
377    
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);
381    
382    currentstatus = status;
383 }
384
385 void writeToTextBuffer(GtkTextBuffer *buffer, const char *fmt,...) {
386    char buf[3000];
387    va_list arg_ptr;
388    GtkTextIter iter;
389    
390    va_start(arg_ptr, fmt);
391    bvsnprintf(buf, sizeof(buf), (char *)fmt, arg_ptr);
392    va_end(arg_ptr);
393    
394    gtk_text_buffer_get_end_iter(buffer, &iter);
395    gtk_text_buffer_insert(buffer, &iter, buf, -1);
396 }
397