2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2005, Digium, Inc.
6 * Mark Spencer <markster@digium.com>
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
21 * \brief GTK Console monitor -- very kludgy right now
27 <defaultenabled>no</defaultenabled>
32 ASTERISK_FILE_VERSION(__FILE__
, "$Revision$")
34 #include <sys/types.h>
47 #include "asterisk/pbx.h"
48 #include "asterisk/config.h"
49 #include "asterisk/module.h"
50 #include "asterisk/logger.h"
51 #include "asterisk/options.h"
52 #include "asterisk/cli.h"
53 #include "asterisk/utils.h"
54 #include "asterisk/paths.h"
55 #include "asterisk/term.h"
57 AST_MUTEX_DEFINE_STATIC(verb_lock
);
59 static pthread_t console_thread
;
62 static int clipipe
[2];
63 static int cleanupid
= -1;
65 static GtkWidget
*window
;
66 static GtkWidget
*quit
;
67 static GtkWidget
*closew
;
68 static GtkWidget
*verb
;
69 static GtkWidget
*modules
;
70 static GtkWidget
*statusbar
;
71 static GtkWidget
*cli
;
73 static struct timeval last
;
75 static void update_statusbar(char *msg
)
77 gtk_statusbar_pop(GTK_STATUSBAR(statusbar
), 1);
78 gtk_statusbar_push(GTK_STATUSBAR(statusbar
), 1, msg
);
81 static int unload_module(void)
84 /* Kill off the main thread */
85 pthread_cancel(console_thread
);
87 gtk_widget_destroy(window
);
95 static int cleanup(void *useless
)
98 gtk_clist_thaw(GTK_CLIST(verb
));
99 gtk_widget_queue_resize(verb
->parent
);
100 gtk_clist_moveto(GTK_CLIST(verb
), GTK_CLIST(verb
)->rows
- 1, 0, 0, 0);
107 static void __verboser(const char *_stuff
)
114 stuff
= ast_strdupa(_stuff
);
115 term_strip(stuff
, stuff
, strlen(stuff
) + 1);
117 s2
[0] = (char *)stuff
;
119 gtk_clist_freeze(GTK_CLIST(verb
));
120 gtk_clist_append(GTK_CLIST(verb
), s2
);
121 if (!ast_tvzero(last
)) {
123 gettimeofday(&tv
, NULL
);
125 gtk_timeout_remove(cleanupid
);
126 ms
= ast_tvdiff_ms(tv
, last
);
128 /* We just got a message within 100ms, so just schedule an update
129 in the near future */
130 cleanupid
= gtk_timeout_add(200, cleanup
, NULL
);
136 gettimeofday(&last
, NULL
);
140 static void verboser(const char *stuff
)
142 ast_mutex_lock(&verb_lock
);
143 /* Lock appropriately if we're really being called in verbose mode */
145 ast_mutex_unlock(&verb_lock
);
148 static void cliinput(void *data
, int source
, GdkInputCondition ic
)
150 static char buf
[256];
151 static int offset
= 0;
156 /* Read as much stuff is there */
157 res
= read(source
, buf
+ offset
, sizeof(buf
) - 1 - offset
);
159 buf
[res
+ offset
] = '\0';
160 /* make sure we've null terminated whatever we have so far */
165 /* Keep the trailing \n */
177 /* We have some left over */
178 memmove(buf
, l
, strlen(l
) + 1);
179 offset
= strlen(buf
);
186 static void remove_module(void)
191 if (GTK_CLIST(modules
)->selection
) {
192 module
= (char *) gtk_clist_get_row_data(GTK_CLIST(modules
), (long) GTK_CLIST(modules
)->selection
->data
);
194 res
= ast_unload_resource(module
, 0);
197 snprintf(buf
, sizeof(buf
), "Module '%s' is in use", module
);
198 update_statusbar(buf
);
200 snprintf(buf
, sizeof(buf
), "Module '%s' removed", module
);
201 update_statusbar(buf
);
206 static int reload(void)
211 if (GTK_CLIST(modules
)->selection
) {
212 module
= (char *)gtk_clist_get_row_data(GTK_CLIST(modules
), (long) GTK_CLIST(modules
)->selection
->data
);
213 module
= strdup(module
);
216 res
= ast_unload_resource(module
, 0);
219 snprintf(buf
, sizeof(buf
), "Module '%s' is in use", module
);
220 update_statusbar(buf
);
223 res
= ast_load_resource(module
);
226 snprintf(buf
, sizeof(buf
), "Error reloading module '%s'", module
);
228 snprintf(buf
, sizeof(buf
), "Module '%s' reloaded", module
);
230 for (x
=0; x
< GTK_CLIST(modules
)->rows
; x
++) {
231 if (!strcmp((char *)gtk_clist_get_row_data(GTK_CLIST(modules
), x
), module
)) {
232 gtk_clist_select_row(GTK_CLIST(modules
), x
, -1);
236 update_statusbar(buf
);
246 static void file_ok_sel(GtkWidget
*w
, GtkFileSelection
*fs
)
249 char *module
= gtk_file_selection_get_filename(fs
);
251 snprintf(tmp
, sizeof(tmp
), "%s/", ast_config_AST_MODULE_DIR
);
252 if (!strncmp(module
, (char *)tmp
, strlen(tmp
)))
253 module
+= strlen(tmp
);
255 if (ast_load_resource(module
)) {
256 snprintf(buf
, sizeof(buf
), "Error loading module '%s'.", module
);
257 update_statusbar(buf
);
259 snprintf(buf
, sizeof(buf
), "Module '%s' loaded", module
);
260 update_statusbar(buf
);
263 gtk_widget_destroy(GTK_WIDGET(fs
));
266 static void add_module(void)
270 snprintf(tmp
, sizeof(tmp
), "%s/*.so", ast_config_AST_MODULE_DIR
);
271 filew
= gtk_file_selection_new("Load Module");
272 gtk_signal_connect(GTK_OBJECT (GTK_FILE_SELECTION(filew
)->ok_button
),
273 "clicked", GTK_SIGNAL_FUNC(file_ok_sel
), filew
);
274 gtk_signal_connect_object(GTK_OBJECT (GTK_FILE_SELECTION(filew
)->cancel_button
),
275 "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy
), GTK_OBJECT(filew
));
276 gtk_file_selection_set_filename(GTK_FILE_SELECTION(filew
), (char *)tmp
);
277 gtk_widget_show(filew
);
280 static int add_mod(const char *module
, const char *description
, int usecount
, const char *like
)
285 snprintf(use
, sizeof(use
), "%d", usecount
);
287 pass
[1] = description
;
290 row
= gtk_clist_append(GTK_CLIST(modules
), (char **) pass
);
291 gtk_clist_set_row_data(GTK_CLIST(modules
), row
, (char *) module
);
295 static int mod_update(void)
298 /* Update the mod stuff */
299 if (GTK_CLIST(modules
)->selection
) {
300 module
= (char *)gtk_clist_get_row_data(GTK_CLIST(modules
), (long) GTK_CLIST(modules
)->selection
->data
);
302 gtk_clist_freeze(GTK_CLIST(modules
));
303 gtk_clist_clear(GTK_CLIST(modules
));
304 ast_update_module_list(add_mod
, NULL
);
306 gtk_clist_select_row(GTK_CLIST(modules
), gtk_clist_find_row_from_data(GTK_CLIST(modules
), module
), -1);
307 gtk_clist_thaw(GTK_CLIST(modules
));
311 static void exit_now(GtkWidget
*widget
, gpointer data
)
313 ast_loader_unregister(mod_update
);
316 ast_update_use_count();
317 ast_unregister_verbose(verboser
);
318 ast_unload_resource("pbx_gtkconsole", 0);
319 if (option_verbose
> 1)
320 ast_verbose(VERBOSE_PREFIX_2
"GTK Console Monitor Exiting\n");
321 /* XXX Trying to quit after calling this makes asterisk segfault XXX */
324 static void exit_completely(GtkWidget
*widget
, gpointer data
)
328 ast_cli_command(clipipe
[1], "quit");
330 kill(getpid(), SIGTERM
);
334 static void exit_nicely(GtkWidget
*widget
, gpointer data
)
337 gtk_widget_destroy(window
);
340 static void *consolethread(void *data
)
342 gtk_widget_show(window
);
349 static int cli_activate(void)
352 strncpy(buf
, gtk_entry_get_text(GTK_ENTRY(cli
)), sizeof(buf
) - 1);
353 gtk_entry_set_text(GTK_ENTRY(cli
), "");
355 ast_cli_command(clipipe
[1], buf
);
360 static int show_console(void)
366 GtkWidget
*bbox
, *hbbox
, *add
, *removew
, *reloadw
;
367 char *modtitles
[3] = { "Module", "Description", "Use Count" };
368 window
= gtk_window_new(GTK_WINDOW_TOPLEVEL
);
370 statusbar
= gtk_statusbar_new();
371 gtk_widget_show(statusbar
);
373 gtk_signal_connect(GTK_OBJECT(window
), "delete_event",
374 GTK_SIGNAL_FUNC (exit_nicely
), window
);
375 gtk_signal_connect(GTK_OBJECT(window
), "destroy",
376 GTK_SIGNAL_FUNC (exit_now
), window
);
377 gtk_container_set_border_width(GTK_CONTAINER(window
), 10);
379 quit
= gtk_button_new_with_label("Quit Asterisk");
380 gtk_signal_connect(GTK_OBJECT(quit
), "clicked",
381 GTK_SIGNAL_FUNC (exit_completely
), window
);
382 gtk_widget_show(quit
);
384 closew
= gtk_button_new_with_label("Close Window");
385 gtk_signal_connect(GTK_OBJECT(closew
), "clicked",
386 GTK_SIGNAL_FUNC (exit_nicely
), window
);
387 gtk_widget_show(closew
);
389 notebook
= gtk_notebook_new();
390 verb
= gtk_clist_new(1);
391 gtk_clist_columns_autosize(GTK_CLIST(verb
));
392 sw
= gtk_scrolled_window_new(NULL
, NULL
);
393 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw
), GTK_POLICY_AUTOMATIC
, GTK_POLICY_ALWAYS
);
394 gtk_container_add(GTK_CONTAINER(sw
), verb
);
395 gtk_widget_show(verb
);
397 gtk_widget_set_usize(verb
, 640, 400);
398 gtk_notebook_append_page(GTK_NOTEBOOK(notebook
), sw
, gtk_label_new("Verbose Status"));
401 modules
= gtk_clist_new_with_titles(3, modtitles
);
402 gtk_clist_columns_autosize(GTK_CLIST(modules
));
403 gtk_clist_set_column_auto_resize(GTK_CLIST(modules
), 0, TRUE
);
404 gtk_clist_set_column_auto_resize(GTK_CLIST(modules
), 1, TRUE
);
405 gtk_clist_set_column_auto_resize(GTK_CLIST(modules
), 2, TRUE
);
406 gtk_clist_set_sort_column(GTK_CLIST(modules
), 0);
407 gtk_clist_set_auto_sort(GTK_CLIST(modules
), TRUE
);
408 gtk_clist_column_titles_passive(GTK_CLIST(modules
));
409 sw
= gtk_scrolled_window_new(NULL
, NULL
);
410 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw
), GTK_POLICY_AUTOMATIC
, GTK_POLICY_ALWAYS
);
411 gtk_container_add(GTK_CONTAINER(sw
), modules
);
412 gtk_clist_set_selection_mode(GTK_CLIST(modules
), GTK_SELECTION_BROWSE
);
413 gtk_widget_show(modules
);
416 add
= gtk_button_new_with_label("Load...");
417 gtk_widget_show(add
);
418 removew
= gtk_button_new_with_label("Unload");
419 gtk_widget_show(removew
);
420 reloadw
= gtk_button_new_with_label("Reload");
421 gtk_widget_show(reloadw
);
422 gtk_signal_connect(GTK_OBJECT(removew
), "clicked",
423 GTK_SIGNAL_FUNC (remove_module
), window
);
424 gtk_signal_connect(GTK_OBJECT(add
), "clicked",
425 GTK_SIGNAL_FUNC (add_module
), window
);
426 gtk_signal_connect(GTK_OBJECT(reloadw
), "clicked",
427 GTK_SIGNAL_FUNC (reload
), window
);
429 bbox
= gtk_vbox_new(FALSE
, 5);
430 gtk_widget_show(bbox
);
432 gtk_widget_set_usize(bbox
, 100, -1);
433 gtk_box_pack_start(GTK_BOX(bbox
), add
, FALSE
, FALSE
, 5);
434 gtk_box_pack_start(GTK_BOX(bbox
), removew
, FALSE
, FALSE
, 5);
435 gtk_box_pack_start(GTK_BOX(bbox
), reloadw
, FALSE
, FALSE
, 5);
437 hbbox
= gtk_hbox_new(FALSE
, 5);
438 gtk_widget_show(hbbox
);
440 gtk_box_pack_start(GTK_BOX(hbbox
), sw
, TRUE
, TRUE
, 5);
441 gtk_box_pack_start(GTK_BOX(hbbox
), bbox
, FALSE
, FALSE
, 5);
443 gtk_notebook_append_page(GTK_NOTEBOOK(notebook
), hbbox
, gtk_label_new("Module Information"));
445 gtk_widget_show(notebook
);
447 wbox
= gtk_hbox_new(FALSE
, 5);
448 gtk_widget_show(wbox
);
449 gtk_box_pack_end(GTK_BOX(wbox
), quit
, FALSE
, FALSE
, 5);
450 gtk_box_pack_end(GTK_BOX(wbox
), closew
, FALSE
, FALSE
, 5);
452 hbox
= gtk_vbox_new(FALSE
, 0);
453 gtk_widget_show(hbox
);
456 cli
= gtk_entry_new();
457 gtk_widget_show(cli
);
459 gtk_signal_connect(GTK_OBJECT(cli
), "activate",
460 GTK_SIGNAL_FUNC (cli_activate
), NULL
);
462 gtk_box_pack_start(GTK_BOX(hbox
), notebook
, TRUE
, TRUE
, 5);
463 gtk_box_pack_start(GTK_BOX(hbox
), wbox
, FALSE
, FALSE
, 5);
464 gtk_box_pack_start(GTK_BOX(hbox
), cli
, FALSE
, FALSE
, 0);
465 gtk_box_pack_start(GTK_BOX(hbox
), statusbar
, FALSE
, FALSE
, 0);
466 gtk_container_add(GTK_CONTAINER(window
), hbox
);
467 gtk_window_set_title(GTK_WINDOW(window
), "Asterisk Console");
468 gtk_widget_grab_focus(cli
);
469 ast_pthread_create(&console_thread
, NULL
, consolethread
, NULL
);
470 /* XXX Okay, seriously fix me! XXX */
472 ast_register_verbose(verboser
);
473 gtk_clist_freeze(GTK_CLIST(verb
));
474 ast_loader_register(mod_update
);
475 gtk_clist_thaw(GTK_CLIST(verb
));
476 gdk_input_add(clipipe
[0], GDK_INPUT_READ
, cliinput
, NULL
);
478 update_statusbar("Asterisk Console Ready");
483 static int load_module(void)
486 ast_log(LOG_WARNING
, "Unable to create CLI pipe\n");
490 if (gtk_init_check(NULL
, NULL
)) {
491 if (!show_console()) {
493 ast_update_use_count();
494 if (option_verbose
> 1)
495 ast_verbose( VERBOSE_PREFIX_2
"Launched GTK Console monitor\n");
497 ast_log(LOG_WARNING
, "Unable to start GTK console\n");
500 ast_log(LOG_DEBUG
, "Unable to start GTK console monitor -- ignoring\n");
501 else if (option_verbose
> 1)
502 ast_verbose( VERBOSE_PREFIX_2
"GTK is not available -- skipping monitor\n");
507 AST_MODULE_INFO(ASTERISK_GPL_KEY
, AST_MODFLAG_DEFAULT
, "GTK Console",
509 .unload
= unload_module
,