Version 0.1.0 from FTP
[asterisk/asterisk.git] / pbx / pbx_gtkconsole.c
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * GTK Console monitor -- very kludgy right now
5  * 
6  * Copyright (C) 1999, Adtran Inc. and Linux Support Services, LLC
7  *
8  * Mark Spencer <markster@linux-support.net>
9  *
10  * This program is free software, distributed under the terms of
11  * the GNU General Public License
12  */
13
14 /* 
15  * I know this might seem somewhat pointless in its current phase, but one
16  * of the most important parts of this module is demonstrate that modules
17  * can require other external libraries and still be loaded (in this
18  * case, a host of libraries involving gtk), so long as they are properly
19  * linked (see the Makefile)
20  */
21
22
23 #include <asterisk/pbx.h>
24 #include <asterisk/config.h>
25 #include <asterisk/module.h>
26 #include <asterisk/logger.h>
27 #include <asterisk/options.h>
28 #include <stdlib.h>
29 #include <fcntl.h>
30 #include <unistd.h>
31 #include <stdio.h>
32 #include <string.h>
33 #include <stdarg.h>
34
35 #include <gtk/gtk.h>
36 #include <glib.h>
37 /* For where to put dynamic tables */
38 #include "../asterisk.h"
39
40 static pthread_mutex_t verb_lock = PTHREAD_MUTEX_INITIALIZER;
41
42 static pthread_t console_thread;
43
44 static int inuse=0;
45 static char *dtext = "Asterisk PBX Console (GTK Version)";
46
47 static GtkWidget *window;
48 static GtkWidget *quit;
49 static GtkWidget *closew;
50 static GtkWidget *verb;
51 static GtkWidget *modules;
52 static GtkWidget *statusbar;
53
54 static void update_statusbar(char *msg)
55 {
56         gtk_statusbar_pop(GTK_STATUSBAR(statusbar), 1);
57         gtk_statusbar_push(GTK_STATUSBAR(statusbar), 1, msg);
58 }
59
60 int unload_module(void)
61 {
62         if (inuse) {
63                 /* Kill off the main thread */
64                 pthread_cancel(console_thread);
65                 gdk_threads_enter();
66                 gtk_widget_destroy(window);
67                 gdk_threads_leave();
68         }
69         return 0;
70 }
71
72
73 static void verboser(char *stuff, int opos, int replacelast, int complete)
74 {
75         char *s2[2];
76         pthread_mutex_lock(&verb_lock);
77         s2[0] = stuff;
78         s2[1] = NULL;
79         gdk_threads_enter();
80         if (replacelast) 
81                 gtk_clist_remove(GTK_CLIST(verb), GTK_CLIST(verb)->rows - 1);
82         gtk_clist_append(GTK_CLIST(verb), s2);
83         gtk_clist_moveto(GTK_CLIST(verb), GTK_CLIST(verb)->rows - 1, 0, 0, 0);
84         gdk_threads_leave();
85         pthread_mutex_unlock(&verb_lock);
86 }
87
88 static void remove_module()
89 {
90         int res;
91         char *module;
92         char buf[256];
93         if (GTK_CLIST(modules)->selection) {
94                 module= (char *)gtk_clist_get_row_data(GTK_CLIST(modules), (int) GTK_CLIST(modules)->selection->data);
95                 gdk_threads_leave();
96                 res = ast_unload_resource(module, 0);
97                 gdk_threads_enter();
98                 if (res) {
99                         snprintf(buf, sizeof(buf), "Module '%s' is in use", module);
100                         update_statusbar(buf);
101                 } else {
102                         snprintf(buf, sizeof(buf), "Module '%s' removed", module);
103                         update_statusbar(buf);
104                 }
105         }
106 }
107 static void reload_module()
108 {
109         int res, x;
110         char *module;
111         char buf[256];
112         if (GTK_CLIST(modules)->selection) {
113                 module= (char *)gtk_clist_get_row_data(GTK_CLIST(modules), (int) GTK_CLIST(modules)->selection->data);
114                 module = strdup(module);
115                 if (module) {
116                         gdk_threads_leave();
117                         res = ast_unload_resource(module, 0);
118                         gdk_threads_enter();
119                         if (res) {
120                                 snprintf(buf, sizeof(buf), "Module '%s' is in use", module);
121                                 update_statusbar(buf);
122                         } else {
123                                 gdk_threads_leave();
124                                 res = ast_load_resource(module);
125                                 gdk_threads_enter();
126                                 if (res) {
127                                         snprintf(buf, sizeof(buf), "Error reloading module '%s'", module);
128                                 } else {
129                                         snprintf(buf, sizeof(buf), "Module '%s' reloaded", module);
130                                 }
131                                 for (x=0; x < GTK_CLIST(modules)->rows; x++) {
132                                         if (!strcmp((char *)gtk_clist_get_row_data(GTK_CLIST(modules), x), module)) {
133                                                 gtk_clist_select_row(GTK_CLIST(modules), x, -1);
134                                                 break;
135                                         }
136                                 }
137                                 update_statusbar(buf);
138                                 
139                         }
140                         free(module);
141                 }
142         }
143 }
144
145 static void file_ok_sel(GtkWidget *w, GtkFileSelection *fs)
146 {
147         char *module = gtk_file_selection_get_filename(fs);
148         char buf[256];
149         if (!strncmp(module, AST_MODULE_DIR "/", strlen(AST_MODULE_DIR "/"))) 
150                 module += strlen(AST_MODULE_DIR "/");
151         gdk_threads_leave();
152         if (ast_load_resource(module)) {
153                 snprintf(buf, sizeof(buf), "Error loading module '%s'.", module);
154                 update_statusbar(buf);
155         } else {
156                 snprintf(buf, sizeof(buf), "Module '%s' loaded", module);
157                 update_statusbar(buf);
158         }
159         gdk_threads_enter();
160         gtk_widget_destroy(GTK_WIDGET(fs));
161 }
162
163 static void add_module()
164 {
165         GtkWidget *filew;
166         filew = gtk_file_selection_new("Load Module");
167         gtk_signal_connect(GTK_OBJECT (GTK_FILE_SELECTION(filew)->ok_button),
168                                         "clicked", GTK_SIGNAL_FUNC(file_ok_sel), filew);
169         gtk_signal_connect_object(GTK_OBJECT (GTK_FILE_SELECTION(filew)->cancel_button),
170                                         "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(filew));
171         gtk_file_selection_set_filename(GTK_FILE_SELECTION(filew), AST_MODULE_DIR "/*.so");
172         gtk_widget_show(filew);
173 }
174
175 static int add_mod(char *module, char *description, int usecount)
176 {
177         char use[10];
178         char *pass[4];
179         int row;
180         snprintf(use, sizeof(use), "%d", usecount);
181         pass[0] = module;
182         pass[1] = description;
183         pass[2] = use;
184         pass[3] = NULL;
185         row = gtk_clist_append(GTK_CLIST(modules), pass);
186         gtk_clist_set_row_data(GTK_CLIST(modules), row, module);
187         return 0;       
188 }
189
190 static int mod_update(void)
191 {
192         char *module= NULL;
193         /* Update the mod stuff */
194         if (GTK_CLIST(modules)->selection) {
195                 module= (char *)gtk_clist_get_row_data(GTK_CLIST(modules), (int) GTK_CLIST(modules)->selection->data);
196         }
197         gdk_threads_enter();
198         gtk_clist_freeze(GTK_CLIST(modules));
199         gtk_clist_clear(GTK_CLIST(modules));
200         ast_update_module_list(add_mod);
201         if (module)
202                 gtk_clist_select_row(GTK_CLIST(modules), gtk_clist_find_row_from_data(GTK_CLIST(modules), module), -1);
203         gtk_clist_thaw(GTK_CLIST(modules));
204         gdk_threads_leave();
205         return 1;
206 }
207
208 static void exit_now(GtkWidget *widget, gpointer data)
209 {
210         ast_loader_unregister(mod_update);
211         gtk_main_quit();
212         inuse--;
213         ast_update_use_count();
214         ast_unregister_verbose(verboser);
215         ast_unload_resource("pbx_gtkconsole", 0);
216         if (option_verbose > 1)
217                 ast_verbose(VERBOSE_PREFIX_2 "GTK Console Monitor Exiting\n");
218                 
219 }
220
221 static void exit_completely(GtkWidget *widget, gpointer data)
222 {
223         /* This is the wrong way to do this.  We need an ast_clean_exit() routine */
224         exit(0);
225 }
226
227 static void exit_nicely(GtkWidget *widget, gpointer data)
228 {
229         fflush(stdout);
230         gtk_widget_destroy(window);
231 }
232
233 static void *consolethread(void *data)
234 {
235         gtk_widget_show(window);
236         gdk_threads_enter();
237         gtk_main();
238         gdk_threads_leave();
239         return NULL;
240 }
241
242 static int show_console()
243 {
244         GtkWidget *hbox;
245         GtkWidget *wbox;
246         GtkWidget *notebook;
247         GtkWidget *sw;
248         GtkWidget *bbox, *hbbox, *add, *removew, *reloadw;
249         char *modtitles[3] = { "Module", "Description", "Use Count" };
250         window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
251         
252         statusbar = gtk_statusbar_new();
253         gtk_widget_show(statusbar);
254         
255         gtk_signal_connect(GTK_OBJECT(window), "delete_event",
256                         GTK_SIGNAL_FUNC (exit_nicely), window);
257         gtk_signal_connect(GTK_OBJECT(window), "destroy",
258                         GTK_SIGNAL_FUNC (exit_now), window);
259         gtk_container_set_border_width(GTK_CONTAINER(window), 10);
260
261         quit = gtk_button_new_with_label("Quit Asterisk");
262         gtk_signal_connect(GTK_OBJECT(quit), "clicked",
263                         GTK_SIGNAL_FUNC (exit_completely), window);
264         gtk_widget_show(quit);
265
266         closew = gtk_button_new_with_label("Close Window");
267         gtk_signal_connect(GTK_OBJECT(closew), "clicked",
268                         GTK_SIGNAL_FUNC (exit_nicely), window);
269         gtk_widget_show(closew);
270
271         notebook = gtk_notebook_new();
272         verb = gtk_clist_new(1);
273         gtk_clist_columns_autosize(GTK_CLIST(verb));
274         sw = gtk_scrolled_window_new(NULL, NULL);
275         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
276         gtk_container_add(GTK_CONTAINER(sw), verb);
277         gtk_widget_show(verb);
278         gtk_widget_show(sw);
279         gtk_widget_set_usize(verb, 600, 400);
280         gtk_notebook_append_page(GTK_NOTEBOOK(notebook), sw, gtk_label_new("Verbose Status"));
281
282         
283         modules = gtk_clist_new_with_titles(3, modtitles);
284         gtk_clist_columns_autosize(GTK_CLIST(modules));
285         gtk_clist_set_column_auto_resize(GTK_CLIST(modules), 0, TRUE);
286         gtk_clist_set_column_auto_resize(GTK_CLIST(modules), 1, TRUE);
287         gtk_clist_set_column_auto_resize(GTK_CLIST(modules), 2, TRUE);
288         gtk_clist_set_sort_column(GTK_CLIST(modules), 0);
289         gtk_clist_set_auto_sort(GTK_CLIST(modules), TRUE);
290         gtk_clist_column_titles_passive(GTK_CLIST(modules));
291         sw = gtk_scrolled_window_new(NULL, NULL);
292         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
293         gtk_container_add(GTK_CONTAINER(sw), modules);
294         gtk_clist_set_selection_mode(GTK_CLIST(modules), GTK_SELECTION_BROWSE);
295         gtk_widget_show(modules);
296         gtk_widget_show(sw);
297
298         add = gtk_button_new_with_label("Load...");
299         gtk_widget_show(add);
300         removew = gtk_button_new_with_label("Unload");
301         gtk_widget_show(removew);
302         reloadw = gtk_button_new_with_label("Reload");
303         gtk_widget_show(reloadw);
304         gtk_signal_connect(GTK_OBJECT(removew), "clicked",
305                         GTK_SIGNAL_FUNC (remove_module), window);
306         gtk_signal_connect(GTK_OBJECT(add), "clicked",
307                         GTK_SIGNAL_FUNC (add_module), window);
308         gtk_signal_connect(GTK_OBJECT(reloadw), "clicked",
309                         GTK_SIGNAL_FUNC (reload_module), window);
310                 
311         bbox = gtk_vbox_new(FALSE, 5);
312         gtk_widget_show(bbox);
313
314         gtk_widget_set_usize(bbox, 100, -1);
315         gtk_box_pack_start(GTK_BOX(bbox), add, FALSE, FALSE, 5);
316         gtk_box_pack_start(GTK_BOX(bbox), removew, FALSE, FALSE, 5);
317         gtk_box_pack_start(GTK_BOX(bbox), reloadw, FALSE, FALSE, 5);
318
319         hbbox = gtk_hbox_new(FALSE, 5);
320         gtk_widget_show(hbbox);
321         
322         gtk_box_pack_start(GTK_BOX(hbbox), sw, TRUE, TRUE, 5);
323         gtk_box_pack_start(GTK_BOX(hbbox), bbox, FALSE, FALSE, 5);
324
325         gtk_notebook_append_page(GTK_NOTEBOOK(notebook), hbbox, gtk_label_new("Module Information"));
326
327         gtk_widget_show(notebook);
328
329         wbox = gtk_hbox_new(FALSE, 5);
330         gtk_widget_show(wbox);
331         gtk_box_pack_end(GTK_BOX(wbox), quit, FALSE, FALSE, 5);
332         gtk_box_pack_end(GTK_BOX(wbox), closew, FALSE, FALSE, 5);
333
334         hbox = gtk_vbox_new(FALSE, 0);
335         gtk_widget_show(hbox);
336
337         gtk_box_pack_start(GTK_BOX(hbox), notebook, TRUE, TRUE, 5);
338         gtk_box_pack_start(GTK_BOX(hbox), wbox, FALSE, FALSE, 5);
339         gtk_box_pack_start(GTK_BOX(hbox), statusbar, FALSE, FALSE, 0);
340
341
342         gtk_container_add(GTK_CONTAINER(window), hbox);
343         gtk_window_set_title(GTK_WINDOW(window), "Asterisk Console");
344         pthread_create(&console_thread, NULL, consolethread, NULL);
345         /* XXX Okay, seriously fix me! XXX */
346         usleep(100000);
347         ast_register_verbose(verboser);
348         gtk_clist_freeze(GTK_CLIST(verb));
349         ast_loader_register(mod_update);
350         gtk_clist_thaw(GTK_CLIST(verb));
351         mod_update();
352         update_statusbar("Asterisk Console Ready");
353         return 0;
354 }
355
356
357 int load_module(void)
358 {
359         g_thread_init(NULL);
360         if (gtk_init_check(NULL, NULL))  {
361                 /* XXX Do we need to call this twice? XXX */
362                 gtk_init(NULL, NULL);
363                 if (!show_console()) {
364                         inuse++;
365                         ast_update_use_count();
366                         if (option_verbose > 1)
367                                 ast_verbose( VERBOSE_PREFIX_2 "Launched GTK Console monitor\n");                
368                 } else
369                         ast_log(LOG_WARNING, "Unable to start GTK console\n");
370         } else {
371                 if (option_debug)
372                         ast_log(LOG_DEBUG, "Unable to start GTK console monitor -- ignoring\n");
373                 else if (option_verbose > 1)
374                         ast_verbose( VERBOSE_PREFIX_2 "GTK is not available -- skipping monitor\n");
375         }
376         return 0;
377 }
378
379 int usecount(void)
380 {
381         return inuse;
382 }
383
384 char *description(void)
385 {
386         return dtext;
387 }