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
)
146 ast_mutex_lock(&verb_lock
);
147 /* Lock appropriately if we're really being called in verbose mode */
149 ast_mutex_unlock(&verb_lock
);
152 static void cliinput(void *data
, int source
, GdkInputCondition ic
)
154 static char buf
[256];
155 static int offset
= 0;
160 /* Read as much stuff is there */
161 res
= read(source
, buf
+ offset
, sizeof(buf
) - 1 - offset
);
163 buf
[res
+ offset
] = '\0';
164 /* make sure we've null terminated whatever we have so far */
169 /* Keep the trailing \n */
181 /* We have some left over */
182 memmove(buf
, l
, strlen(l
) + 1);
183 offset
= strlen(buf
);
190 static void remove_module(void)
195 if (GTK_CLIST(modules
)->selection
) {
196 module
= (char *) gtk_clist_get_row_data(GTK_CLIST(modules
), (long) GTK_CLIST(modules
)->selection
->data
);
198 res
= ast_unload_resource(module
, 0);
201 snprintf(buf
, sizeof(buf
), "Module '%s' is in use", module
);
202 update_statusbar(buf
);
204 snprintf(buf
, sizeof(buf
), "Module '%s' removed", module
);
205 update_statusbar(buf
);
210 static int reload(void)
215 if (GTK_CLIST(modules
)->selection
) {
216 module
= (char *)gtk_clist_get_row_data(GTK_CLIST(modules
), (long) GTK_CLIST(modules
)->selection
->data
);
217 module
= strdup(module
);
220 res
= ast_unload_resource(module
, 0);
223 snprintf(buf
, sizeof(buf
), "Module '%s' is in use", module
);
224 update_statusbar(buf
);
227 res
= ast_load_resource(module
);
230 snprintf(buf
, sizeof(buf
), "Error reloading module '%s'", module
);
232 snprintf(buf
, sizeof(buf
), "Module '%s' reloaded", module
);
234 for (x
=0; x
< GTK_CLIST(modules
)->rows
; x
++) {
235 if (!strcmp((char *)gtk_clist_get_row_data(GTK_CLIST(modules
), x
), module
)) {
236 gtk_clist_select_row(GTK_CLIST(modules
), x
, -1);
240 update_statusbar(buf
);
250 static void file_ok_sel(GtkWidget
*w
, GtkFileSelection
*fs
)
253 char *module
= gtk_file_selection_get_filename(fs
);
255 snprintf(tmp
, sizeof(tmp
), "%s/", ast_config_AST_MODULE_DIR
);
256 if (!strncmp(module
, (char *)tmp
, strlen(tmp
)))
257 module
+= strlen(tmp
);
259 if (ast_load_resource(module
)) {
260 snprintf(buf
, sizeof(buf
), "Error loading module '%s'.", module
);
261 update_statusbar(buf
);
263 snprintf(buf
, sizeof(buf
), "Module '%s' loaded", module
);
264 update_statusbar(buf
);
267 gtk_widget_destroy(GTK_WIDGET(fs
));
270 static void add_module(void)
274 snprintf(tmp
, sizeof(tmp
), "%s/*.so", ast_config_AST_MODULE_DIR
);
275 filew
= gtk_file_selection_new("Load Module");
276 gtk_signal_connect(GTK_OBJECT (GTK_FILE_SELECTION(filew
)->ok_button
),
277 "clicked", GTK_SIGNAL_FUNC(file_ok_sel
), filew
);
278 gtk_signal_connect_object(GTK_OBJECT (GTK_FILE_SELECTION(filew
)->cancel_button
),
279 "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy
), GTK_OBJECT(filew
));
280 gtk_file_selection_set_filename(GTK_FILE_SELECTION(filew
), (char *)tmp
);
281 gtk_widget_show(filew
);
284 static int add_mod(const char *module
, const char *description
, int usecount
, const char *like
)
289 snprintf(use
, sizeof(use
), "%d", usecount
);
291 pass
[1] = description
;
294 row
= gtk_clist_append(GTK_CLIST(modules
), (char **) pass
);
295 gtk_clist_set_row_data(GTK_CLIST(modules
), row
, (char *) module
);
299 static int mod_update(void)
302 /* Update the mod stuff */
303 if (GTK_CLIST(modules
)->selection
) {
304 module
= (char *)gtk_clist_get_row_data(GTK_CLIST(modules
), (long) GTK_CLIST(modules
)->selection
->data
);
306 gtk_clist_freeze(GTK_CLIST(modules
));
307 gtk_clist_clear(GTK_CLIST(modules
));
308 ast_update_module_list(add_mod
, NULL
);
310 gtk_clist_select_row(GTK_CLIST(modules
), gtk_clist_find_row_from_data(GTK_CLIST(modules
), module
), -1);
311 gtk_clist_thaw(GTK_CLIST(modules
));
315 static void exit_now(GtkWidget
*widget
, gpointer data
)
317 ast_loader_unregister(mod_update
);
320 ast_update_use_count();
321 ast_unregister_verbose(verboser
);
322 ast_unload_resource("pbx_gtkconsole", 0);
323 if (option_verbose
> 1)
324 ast_verbose(VERBOSE_PREFIX_2
"GTK Console Monitor Exiting\n");
325 /* XXX Trying to quit after calling this makes asterisk segfault XXX */
328 static void exit_completely(GtkWidget
*widget
, gpointer data
)
332 ast_cli_command(clipipe
[1], "quit");
334 kill(getpid(), SIGTERM
);
338 static void exit_nicely(GtkWidget
*widget
, gpointer data
)
341 gtk_widget_destroy(window
);
344 static void *consolethread(void *data
)
346 gtk_widget_show(window
);
353 static int cli_activate(void)
356 strncpy(buf
, gtk_entry_get_text(GTK_ENTRY(cli
)), sizeof(buf
) - 1);
357 gtk_entry_set_text(GTK_ENTRY(cli
), "");
359 ast_cli_command(clipipe
[1], buf
);
364 static int show_console(void)
370 GtkWidget
*bbox
, *hbbox
, *add
, *removew
, *reloadw
;
371 char *modtitles
[3] = { "Module", "Description", "Use Count" };
372 window
= gtk_window_new(GTK_WINDOW_TOPLEVEL
);
374 statusbar
= gtk_statusbar_new();
375 gtk_widget_show(statusbar
);
377 gtk_signal_connect(GTK_OBJECT(window
), "delete_event",
378 GTK_SIGNAL_FUNC (exit_nicely
), window
);
379 gtk_signal_connect(GTK_OBJECT(window
), "destroy",
380 GTK_SIGNAL_FUNC (exit_now
), window
);
381 gtk_container_set_border_width(GTK_CONTAINER(window
), 10);
383 quit
= gtk_button_new_with_label("Quit Asterisk");
384 gtk_signal_connect(GTK_OBJECT(quit
), "clicked",
385 GTK_SIGNAL_FUNC (exit_completely
), window
);
386 gtk_widget_show(quit
);
388 closew
= gtk_button_new_with_label("Close Window");
389 gtk_signal_connect(GTK_OBJECT(closew
), "clicked",
390 GTK_SIGNAL_FUNC (exit_nicely
), window
);
391 gtk_widget_show(closew
);
393 notebook
= gtk_notebook_new();
394 verb
= gtk_clist_new(1);
395 gtk_clist_columns_autosize(GTK_CLIST(verb
));
396 sw
= gtk_scrolled_window_new(NULL
, NULL
);
397 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw
), GTK_POLICY_AUTOMATIC
, GTK_POLICY_ALWAYS
);
398 gtk_container_add(GTK_CONTAINER(sw
), verb
);
399 gtk_widget_show(verb
);
401 gtk_widget_set_usize(verb
, 640, 400);
402 gtk_notebook_append_page(GTK_NOTEBOOK(notebook
), sw
, gtk_label_new("Verbose Status"));
405 modules
= gtk_clist_new_with_titles(3, modtitles
);
406 gtk_clist_columns_autosize(GTK_CLIST(modules
));
407 gtk_clist_set_column_auto_resize(GTK_CLIST(modules
), 0, TRUE
);
408 gtk_clist_set_column_auto_resize(GTK_CLIST(modules
), 1, TRUE
);
409 gtk_clist_set_column_auto_resize(GTK_CLIST(modules
), 2, TRUE
);
410 gtk_clist_set_sort_column(GTK_CLIST(modules
), 0);
411 gtk_clist_set_auto_sort(GTK_CLIST(modules
), TRUE
);
412 gtk_clist_column_titles_passive(GTK_CLIST(modules
));
413 sw
= gtk_scrolled_window_new(NULL
, NULL
);
414 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw
), GTK_POLICY_AUTOMATIC
, GTK_POLICY_ALWAYS
);
415 gtk_container_add(GTK_CONTAINER(sw
), modules
);
416 gtk_clist_set_selection_mode(GTK_CLIST(modules
), GTK_SELECTION_BROWSE
);
417 gtk_widget_show(modules
);
420 add
= gtk_button_new_with_label("Load...");
421 gtk_widget_show(add
);
422 removew
= gtk_button_new_with_label("Unload");
423 gtk_widget_show(removew
);
424 reloadw
= gtk_button_new_with_label("Reload");
425 gtk_widget_show(reloadw
);
426 gtk_signal_connect(GTK_OBJECT(removew
), "clicked",
427 GTK_SIGNAL_FUNC (remove_module
), window
);
428 gtk_signal_connect(GTK_OBJECT(add
), "clicked",
429 GTK_SIGNAL_FUNC (add_module
), window
);
430 gtk_signal_connect(GTK_OBJECT(reloadw
), "clicked",
431 GTK_SIGNAL_FUNC (reload
), window
);
433 bbox
= gtk_vbox_new(FALSE
, 5);
434 gtk_widget_show(bbox
);
436 gtk_widget_set_usize(bbox
, 100, -1);
437 gtk_box_pack_start(GTK_BOX(bbox
), add
, FALSE
, FALSE
, 5);
438 gtk_box_pack_start(GTK_BOX(bbox
), removew
, FALSE
, FALSE
, 5);
439 gtk_box_pack_start(GTK_BOX(bbox
), reloadw
, FALSE
, FALSE
, 5);
441 hbbox
= gtk_hbox_new(FALSE
, 5);
442 gtk_widget_show(hbbox
);
444 gtk_box_pack_start(GTK_BOX(hbbox
), sw
, TRUE
, TRUE
, 5);
445 gtk_box_pack_start(GTK_BOX(hbbox
), bbox
, FALSE
, FALSE
, 5);
447 gtk_notebook_append_page(GTK_NOTEBOOK(notebook
), hbbox
, gtk_label_new("Module Information"));
449 gtk_widget_show(notebook
);
451 wbox
= gtk_hbox_new(FALSE
, 5);
452 gtk_widget_show(wbox
);
453 gtk_box_pack_end(GTK_BOX(wbox
), quit
, FALSE
, FALSE
, 5);
454 gtk_box_pack_end(GTK_BOX(wbox
), closew
, FALSE
, FALSE
, 5);
456 hbox
= gtk_vbox_new(FALSE
, 0);
457 gtk_widget_show(hbox
);
460 cli
= gtk_entry_new();
461 gtk_widget_show(cli
);
463 gtk_signal_connect(GTK_OBJECT(cli
), "activate",
464 GTK_SIGNAL_FUNC (cli_activate
), NULL
);
466 gtk_box_pack_start(GTK_BOX(hbox
), notebook
, TRUE
, TRUE
, 5);
467 gtk_box_pack_start(GTK_BOX(hbox
), wbox
, FALSE
, FALSE
, 5);
468 gtk_box_pack_start(GTK_BOX(hbox
), cli
, FALSE
, FALSE
, 0);
469 gtk_box_pack_start(GTK_BOX(hbox
), statusbar
, FALSE
, FALSE
, 0);
470 gtk_container_add(GTK_CONTAINER(window
), hbox
);
471 gtk_window_set_title(GTK_WINDOW(window
), "Asterisk Console");
472 gtk_widget_grab_focus(cli
);
473 ast_pthread_create(&console_thread
, NULL
, consolethread
, NULL
);
474 /* XXX Okay, seriously fix me! XXX */
476 ast_register_verbose(verboser
);
477 gtk_clist_freeze(GTK_CLIST(verb
));
478 ast_loader_register(mod_update
);
479 gtk_clist_thaw(GTK_CLIST(verb
));
480 gdk_input_add(clipipe
[0], GDK_INPUT_READ
, cliinput
, NULL
);
482 update_statusbar("Asterisk Console Ready");
487 static int load_module(void)
490 ast_log(LOG_WARNING
, "Unable to create CLI pipe\n");
494 if (gtk_init_check(NULL
, NULL
)) {
495 if (!show_console()) {
497 ast_update_use_count();
498 if (option_verbose
> 1)
499 ast_verbose( VERBOSE_PREFIX_2
"Launched GTK Console monitor\n");
501 ast_log(LOG_WARNING
, "Unable to start GTK console\n");
504 ast_log(LOG_DEBUG
, "Unable to start GTK console monitor -- ignoring\n");
505 else if (option_verbose
> 1)
506 ast_verbose( VERBOSE_PREFIX_2
"GTK is not available -- skipping monitor\n");
511 AST_MODULE_INFO(ASTERISK_GPL_KEY
, AST_MODFLAG_DEFAULT
, "GTK Console",
513 .unload
= unload_module
,