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"
55 AST_MUTEX_DEFINE_STATIC(verb_lock
);
57 static pthread_t console_thread
;
60 static int clipipe
[2];
61 static int cleanupid
= -1;
63 static char *dtext
= "Asterisk PBX Console (GTK Version)";
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 *mod
)
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
, int opos
, int replacelast
, int complete
)
112 s2
[0] = (char *)stuff
;
114 gtk_clist_freeze(GTK_CLIST(verb
));
116 gtk_clist_remove(GTK_CLIST(verb
), GTK_CLIST(verb
)->rows
- 1);
117 gtk_clist_append(GTK_CLIST(verb
), s2
);
118 if (!ast_tvzero(last
)) {
120 gettimeofday(&tv
, NULL
);
122 gtk_timeout_remove(cleanupid
);
123 ms
= ast_tvdiff_ms(tv
, last
);
125 /* We just got a message within 100ms, so just schedule an update
126 in the near future */
127 cleanupid
= gtk_timeout_add(200, cleanup
, NULL
);
133 gettimeofday(&last
, NULL
);
137 static void verboser(const char *stuff
, int opos
, int replacelast
, int complete
)
139 ast_mutex_lock(&verb_lock
);
140 /* Lock appropriately if we're really being called in verbose mode */
141 __verboser(stuff
, opos
, replacelast
, complete
);
142 ast_mutex_unlock(&verb_lock
);
145 static void cliinput(void *data
, int source
, GdkInputCondition ic
)
147 static char buf
[256];
148 static int offset
= 0;
153 /* Read as much stuff is there */
154 res
= read(source
, buf
+ offset
, sizeof(buf
) - 1 - offset
);
156 buf
[res
+ offset
] = '\0';
157 /* make sure we've null terminated whatever we have so far */
162 /* Keep the trailing \n */
166 __verboser(l
, 0, 0, 1);
174 /* We have some left over */
175 memmove(buf
, l
, strlen(l
) + 1);
176 offset
= strlen(buf
);
184 static void remove_module(void)
189 if (GTK_CLIST(modules
)->selection
) {
190 module
= (char *)gtk_clist_get_row_data(GTK_CLIST(modules
), (int) GTK_CLIST(modules
)->selection
->data
);
192 res
= ast_unload_resource(module
, 0);
195 snprintf(buf
, sizeof(buf
), "Module '%s' is in use", module
);
196 update_statusbar(buf
);
198 snprintf(buf
, sizeof(buf
), "Module '%s' removed", module
);
199 update_statusbar(buf
);
203 static int reload_module(void *mod
)
208 if (GTK_CLIST(modules
)->selection
) {
209 module
= (char *)gtk_clist_get_row_data(GTK_CLIST(modules
), (int) GTK_CLIST(modules
)->selection
->data
);
210 module
= strdup(module
);
213 res
= ast_unload_resource(module
, 0);
216 snprintf(buf
, sizeof(buf
), "Module '%s' is in use", module
);
217 update_statusbar(buf
);
220 res
= ast_load_resource(module
);
223 snprintf(buf
, sizeof(buf
), "Error reloading module '%s'", module
);
225 snprintf(buf
, sizeof(buf
), "Module '%s' reloaded", module
);
227 for (x
=0; x
< GTK_CLIST(modules
)->rows
; x
++) {
228 if (!strcmp((char *)gtk_clist_get_row_data(GTK_CLIST(modules
), x
), module
)) {
229 gtk_clist_select_row(GTK_CLIST(modules
), x
, -1);
233 update_statusbar(buf
);
243 static void file_ok_sel(GtkWidget
*w
, GtkFileSelection
*fs
)
246 char *module
= gtk_file_selection_get_filename(fs
);
248 snprintf(tmp
, sizeof(tmp
), "%s/", ast_config_AST_MODULE_DIR
);
249 if (!strncmp(module
, (char *)tmp
, strlen(tmp
)))
250 module
+= strlen(tmp
);
252 if (ast_load_resource(module
)) {
253 snprintf(buf
, sizeof(buf
), "Error loading module '%s'.", module
);
254 update_statusbar(buf
);
256 snprintf(buf
, sizeof(buf
), "Module '%s' loaded", module
);
257 update_statusbar(buf
);
260 gtk_widget_destroy(GTK_WIDGET(fs
));
263 static void add_module(void)
267 snprintf(tmp
, sizeof(tmp
), "%s/*.so", ast_config_AST_MODULE_DIR
);
268 filew
= gtk_file_selection_new("Load Module");
269 gtk_signal_connect(GTK_OBJECT (GTK_FILE_SELECTION(filew
)->ok_button
),
270 "clicked", GTK_SIGNAL_FUNC(file_ok_sel
), filew
);
271 gtk_signal_connect_object(GTK_OBJECT (GTK_FILE_SELECTION(filew
)->cancel_button
),
272 "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy
), GTK_OBJECT(filew
));
273 gtk_file_selection_set_filename(GTK_FILE_SELECTION(filew
), (char *)tmp
);
274 gtk_widget_show(filew
);
277 static int add_mod(const char *module
, const char *description
, int usecount
, const char *like
)
282 snprintf(use
, sizeof(use
), "%d", usecount
);
284 pass
[1] = description
;
287 row
= gtk_clist_append(GTK_CLIST(modules
), (char **) pass
);
288 gtk_clist_set_row_data(GTK_CLIST(modules
), row
, (char *) module
);
292 static int mod_update(void)
295 /* Update the mod stuff */
296 if (GTK_CLIST(modules
)->selection
) {
297 module
= (char *)gtk_clist_get_row_data(GTK_CLIST(modules
), (int) GTK_CLIST(modules
)->selection
->data
);
299 gtk_clist_freeze(GTK_CLIST(modules
));
300 gtk_clist_clear(GTK_CLIST(modules
));
301 ast_update_module_list(add_mod
, NULL
);
303 gtk_clist_select_row(GTK_CLIST(modules
), gtk_clist_find_row_from_data(GTK_CLIST(modules
), module
), -1);
304 gtk_clist_thaw(GTK_CLIST(modules
));
308 static void exit_now(GtkWidget
*widget
, gpointer data
)
310 ast_loader_unregister(mod_update
);
313 ast_update_use_count();
314 ast_unregister_verbose(verboser
);
315 ast_unload_resource("pbx_gtkconsole", 0);
316 if (option_verbose
> 1)
317 ast_verbose(VERBOSE_PREFIX_2
"GTK Console Monitor Exiting\n");
318 /* XXX Trying to quit after calling this makes asterisk segfault XXX */
321 static void exit_completely(GtkWidget
*widget
, gpointer data
)
325 ast_cli_command(clipipe
[1], "quit");
327 kill(getpid(), SIGTERM
);
331 static void exit_nicely(GtkWidget
*widget
, gpointer data
)
334 gtk_widget_destroy(window
);
337 static void *consolethread(void *data
)
339 gtk_widget_show(window
);
346 static int cli_activate(void)
349 strncpy(buf
, gtk_entry_get_text(GTK_ENTRY(cli
)), sizeof(buf
) - 1);
350 gtk_entry_set_text(GTK_ENTRY(cli
), "");
352 ast_cli_command(clipipe
[1], buf
);
357 static int show_console(void)
363 GtkWidget
*bbox
, *hbbox
, *add
, *removew
, *reloadw
;
364 char *modtitles
[3] = { "Module", "Description", "Use Count" };
365 window
= gtk_window_new(GTK_WINDOW_TOPLEVEL
);
367 statusbar
= gtk_statusbar_new();
368 gtk_widget_show(statusbar
);
370 gtk_signal_connect(GTK_OBJECT(window
), "delete_event",
371 GTK_SIGNAL_FUNC (exit_nicely
), window
);
372 gtk_signal_connect(GTK_OBJECT(window
), "destroy",
373 GTK_SIGNAL_FUNC (exit_now
), window
);
374 gtk_container_set_border_width(GTK_CONTAINER(window
), 10);
376 quit
= gtk_button_new_with_label("Quit Asterisk");
377 gtk_signal_connect(GTK_OBJECT(quit
), "clicked",
378 GTK_SIGNAL_FUNC (exit_completely
), window
);
379 gtk_widget_show(quit
);
381 closew
= gtk_button_new_with_label("Close Window");
382 gtk_signal_connect(GTK_OBJECT(closew
), "clicked",
383 GTK_SIGNAL_FUNC (exit_nicely
), window
);
384 gtk_widget_show(closew
);
386 notebook
= gtk_notebook_new();
387 verb
= gtk_clist_new(1);
388 gtk_clist_columns_autosize(GTK_CLIST(verb
));
389 sw
= gtk_scrolled_window_new(NULL
, NULL
);
390 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw
), GTK_POLICY_AUTOMATIC
, GTK_POLICY_ALWAYS
);
391 gtk_container_add(GTK_CONTAINER(sw
), verb
);
392 gtk_widget_show(verb
);
394 gtk_widget_set_usize(verb
, 640, 400);
395 gtk_notebook_append_page(GTK_NOTEBOOK(notebook
), sw
, gtk_label_new("Verbose Status"));
398 modules
= gtk_clist_new_with_titles(3, modtitles
);
399 gtk_clist_columns_autosize(GTK_CLIST(modules
));
400 gtk_clist_set_column_auto_resize(GTK_CLIST(modules
), 0, TRUE
);
401 gtk_clist_set_column_auto_resize(GTK_CLIST(modules
), 1, TRUE
);
402 gtk_clist_set_column_auto_resize(GTK_CLIST(modules
), 2, TRUE
);
403 gtk_clist_set_sort_column(GTK_CLIST(modules
), 0);
404 gtk_clist_set_auto_sort(GTK_CLIST(modules
), TRUE
);
405 gtk_clist_column_titles_passive(GTK_CLIST(modules
));
406 sw
= gtk_scrolled_window_new(NULL
, NULL
);
407 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw
), GTK_POLICY_AUTOMATIC
, GTK_POLICY_ALWAYS
);
408 gtk_container_add(GTK_CONTAINER(sw
), modules
);
409 gtk_clist_set_selection_mode(GTK_CLIST(modules
), GTK_SELECTION_BROWSE
);
410 gtk_widget_show(modules
);
413 add
= gtk_button_new_with_label("Load...");
414 gtk_widget_show(add
);
415 removew
= gtk_button_new_with_label("Unload");
416 gtk_widget_show(removew
);
417 reloadw
= gtk_button_new_with_label("Reload");
418 gtk_widget_show(reloadw
);
419 gtk_signal_connect(GTK_OBJECT(removew
), "clicked",
420 GTK_SIGNAL_FUNC (remove_module
), window
);
421 gtk_signal_connect(GTK_OBJECT(add
), "clicked",
422 GTK_SIGNAL_FUNC (add_module
), window
);
423 gtk_signal_connect(GTK_OBJECT(reloadw
), "clicked",
424 GTK_SIGNAL_FUNC (reload_module
), window
);
426 bbox
= gtk_vbox_new(FALSE
, 5);
427 gtk_widget_show(bbox
);
429 gtk_widget_set_usize(bbox
, 100, -1);
430 gtk_box_pack_start(GTK_BOX(bbox
), add
, FALSE
, FALSE
, 5);
431 gtk_box_pack_start(GTK_BOX(bbox
), removew
, FALSE
, FALSE
, 5);
432 gtk_box_pack_start(GTK_BOX(bbox
), reloadw
, FALSE
, FALSE
, 5);
434 hbbox
= gtk_hbox_new(FALSE
, 5);
435 gtk_widget_show(hbbox
);
437 gtk_box_pack_start(GTK_BOX(hbbox
), sw
, TRUE
, TRUE
, 5);
438 gtk_box_pack_start(GTK_BOX(hbbox
), bbox
, FALSE
, FALSE
, 5);
440 gtk_notebook_append_page(GTK_NOTEBOOK(notebook
), hbbox
, gtk_label_new("Module Information"));
442 gtk_widget_show(notebook
);
444 wbox
= gtk_hbox_new(FALSE
, 5);
445 gtk_widget_show(wbox
);
446 gtk_box_pack_end(GTK_BOX(wbox
), quit
, FALSE
, FALSE
, 5);
447 gtk_box_pack_end(GTK_BOX(wbox
), closew
, FALSE
, FALSE
, 5);
449 hbox
= gtk_vbox_new(FALSE
, 0);
450 gtk_widget_show(hbox
);
453 cli
= gtk_entry_new();
454 gtk_widget_show(cli
);
456 gtk_signal_connect(GTK_OBJECT(cli
), "activate",
457 GTK_SIGNAL_FUNC (cli_activate
), NULL
);
459 gtk_box_pack_start(GTK_BOX(hbox
), notebook
, TRUE
, TRUE
, 5);
460 gtk_box_pack_start(GTK_BOX(hbox
), wbox
, FALSE
, FALSE
, 5);
461 gtk_box_pack_start(GTK_BOX(hbox
), cli
, FALSE
, FALSE
, 0);
462 gtk_box_pack_start(GTK_BOX(hbox
), statusbar
, FALSE
, FALSE
, 0);
463 gtk_container_add(GTK_CONTAINER(window
), hbox
);
464 gtk_window_set_title(GTK_WINDOW(window
), "Asterisk Console");
465 gtk_widget_grab_focus(cli
);
466 ast_pthread_create(&console_thread
, NULL
, consolethread
, NULL
);
467 /* XXX Okay, seriously fix me! XXX */
469 ast_register_verbose(verboser
);
470 gtk_clist_freeze(GTK_CLIST(verb
));
471 ast_loader_register(mod_update
);
472 gtk_clist_thaw(GTK_CLIST(verb
));
473 gdk_input_add(clipipe
[0], GDK_INPUT_READ
, cliinput
, NULL
);
475 update_statusbar("Asterisk Console Ready");
480 static int load_module(void *mod
)
483 ast_log(LOG_WARNING
, "Unable to create CLI pipe\n");
487 if (gtk_init_check(NULL
, NULL
)) {
488 if (!show_console()) {
490 ast_update_use_count();
491 if (option_verbose
> 1)
492 ast_verbose( VERBOSE_PREFIX_2
"Launched GTK Console monitor\n");
494 ast_log(LOG_WARNING
, "Unable to start GTK console\n");
497 ast_log(LOG_DEBUG
, "Unable to start GTK console monitor -- ignoring\n");
498 else if (option_verbose
> 1)
499 ast_verbose( VERBOSE_PREFIX_2
"GTK is not available -- skipping monitor\n");
504 static const char *description(void)
509 static const char *key(void)
511 return ASTERISK_GPL_KEY
;
514 STD_MOD(MOD_0
, reload_module
, NULL
, NULL
);