![]() |
Home page |
Mailing list |
Docs
Asterisk developer's documentation :: Codename Pineapple
pbx_gtkconsole.c
Go to the documentation of this file.
00001 /* 00002 * Asterisk -- An open source telephony toolkit. 00003 * 00004 * Copyright (C) 1999 - 2005, Digium, Inc. 00005 * 00006 * Mark Spencer <markster@digium.com> 00007 * 00008 * See http://www.asterisk.org for more information about 00009 * the Asterisk project. Please do not directly contact 00010 * any of the maintainers of this project for assistance; 00011 * the project provides a web site, mailing lists and IRC 00012 * channels for your use. 00013 * 00014 * This program is free software, distributed under the terms of 00015 * the GNU General Public License Version 2. See the LICENSE file 00016 * at the top of the source tree. 00017 */ 00018 00019 /*! \file 00020 * 00021 * \brief GTK Console monitor -- very kludgy right now 00022 * 00023 */ 00024 00025 /*** MODULEINFO 00026 <depend>gtk</depend> 00027 <defaultenabled>no</defaultenabled> 00028 ***/ 00029 00030 #include "asterisk.h" 00031 00032 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 43294 $") 00033 00034 #include <sys/types.h> 00035 #include <stdlib.h> 00036 #include <fcntl.h> 00037 #include <unistd.h> 00038 #include <stdio.h> 00039 #include <string.h> 00040 #include <stdarg.h> 00041 #include <signal.h> 00042 #include <sys/time.h> 00043 00044 #include <gtk/gtk.h> 00045 #include <glib.h> 00046 00047 #include "asterisk/pbx.h" 00048 #include "asterisk/config.h" 00049 #include "asterisk/module.h" 00050 #include "asterisk/logger.h" 00051 #include "asterisk/options.h" 00052 #include "asterisk/cli.h" 00053 #include "asterisk/utils.h" 00054 00055 AST_MUTEX_DEFINE_STATIC(verb_lock); 00056 00057 static pthread_t console_thread; 00058 00059 static int inuse=0; 00060 static int clipipe[2]; 00061 static int cleanupid = -1; 00062 00063 static char *dtext = "Asterisk PBX Console (GTK Version)"; 00064 00065 static GtkWidget *window; 00066 static GtkWidget *quit; 00067 static GtkWidget *closew; 00068 static GtkWidget *verb; 00069 static GtkWidget *modules; 00070 static GtkWidget *statusbar; 00071 static GtkWidget *cli; 00072 00073 static struct timeval last; 00074 00075 static void update_statusbar(char *msg) 00076 { 00077 gtk_statusbar_pop(GTK_STATUSBAR(statusbar), 1); 00078 gtk_statusbar_push(GTK_STATUSBAR(statusbar), 1, msg); 00079 } 00080 00081 static int unload_module(void *mod) 00082 { 00083 if (inuse) { 00084 /* Kill off the main thread */ 00085 pthread_cancel(console_thread); 00086 gdk_threads_enter(); 00087 gtk_widget_destroy(window); 00088 gdk_threads_leave(); 00089 close(clipipe[0]); 00090 close(clipipe[1]); 00091 } 00092 return 0; 00093 } 00094 00095 static int cleanup(void *useless) 00096 { 00097 gdk_threads_enter(); 00098 gtk_clist_thaw(GTK_CLIST(verb)); 00099 gtk_widget_queue_resize(verb->parent); 00100 gtk_clist_moveto(GTK_CLIST(verb), GTK_CLIST(verb)->rows - 1, 0, 0, 0); 00101 cleanupid = -1; 00102 gdk_threads_leave(); 00103 return 0; 00104 } 00105 00106 00107 static void __verboser(const char *stuff, int opos, int replacelast, int complete) 00108 { 00109 char *s2[2]; 00110 struct timeval tv; 00111 int ms; 00112 s2[0] = (char *)stuff; 00113 s2[1] = NULL; 00114 gtk_clist_freeze(GTK_CLIST(verb)); 00115 if (replacelast) 00116 gtk_clist_remove(GTK_CLIST(verb), GTK_CLIST(verb)->rows - 1); 00117 gtk_clist_append(GTK_CLIST(verb), s2); 00118 if (!ast_tvzero(last)) { 00119 gdk_threads_leave(); 00120 gettimeofday(&tv, NULL); 00121 if (cleanupid > -1) 00122 gtk_timeout_remove(cleanupid); 00123 ms = ast_tvdiff_ms(tv, last); 00124 if (ms < 100) { 00125 /* We just got a message within 100ms, so just schedule an update 00126 in the near future */ 00127 cleanupid = gtk_timeout_add(200, cleanup, NULL); 00128 } else { 00129 cleanup(&cleanupid); 00130 } 00131 last = tv; 00132 } else { 00133 gettimeofday(&last, NULL); 00134 } 00135 } 00136 00137 static void verboser(const char *stuff, int opos, int replacelast, int complete) 00138 { 00139 ast_mutex_lock(&verb_lock); 00140 /* Lock appropriately if we're really being called in verbose mode */ 00141 __verboser(stuff, opos, replacelast, complete); 00142 ast_mutex_unlock(&verb_lock); 00143 } 00144 00145 static void cliinput(void *data, int source, GdkInputCondition ic) 00146 { 00147 static char buf[256]; 00148 static int offset = 0; 00149 int res; 00150 char *c; 00151 char *l; 00152 char n; 00153 /* Read as much stuff is there */ 00154 res = read(source, buf + offset, sizeof(buf) - 1 - offset); 00155 if (res > -1) 00156 buf[res + offset] = '\0'; 00157 /* make sure we've null terminated whatever we have so far */ 00158 c = buf; 00159 l = buf; 00160 while(*c) { 00161 if (*c == '\n') { 00162 /* Keep the trailing \n */ 00163 c++; 00164 n = *c; 00165 *c = '\0'; 00166 __verboser(l, 0, 0, 1); 00167 *(c - 1) = '\0'; 00168 *c = n; 00169 l = c; 00170 } else 00171 c++; 00172 } 00173 if (strlen(l)) { 00174 /* We have some left over */ 00175 memmove(buf, l, strlen(l) + 1); 00176 offset = strlen(buf); 00177 } else { 00178 offset = 0; 00179 } 00180 00181 } 00182 00183 00184 static void remove_module(void) 00185 { 00186 int res; 00187 char *module; 00188 char buf[256]; 00189 if (GTK_CLIST(modules)->selection) { 00190 module= (char *)gtk_clist_get_row_data(GTK_CLIST(modules), (int) GTK_CLIST(modules)->selection->data); 00191 gdk_threads_leave(); 00192 res = ast_unload_resource(module, 0); 00193 gdk_threads_enter(); 00194 if (res) { 00195 snprintf(buf, sizeof(buf), "Module '%s' is in use", module); 00196 update_statusbar(buf); 00197 } else { 00198 snprintf(buf, sizeof(buf), "Module '%s' removed", module); 00199 update_statusbar(buf); 00200 } 00201 } 00202 } 00203 static int reload_module(void *mod) 00204 { 00205 int res, x; 00206 char *module; 00207 char buf[256]; 00208 if (GTK_CLIST(modules)->selection) { 00209 module= (char *)gtk_clist_get_row_data(GTK_CLIST(modules), (int) GTK_CLIST(modules)->selection->data); 00210 module = strdup(module); 00211 if (module) { 00212 gdk_threads_leave(); 00213 res = ast_unload_resource(module, 0); 00214 gdk_threads_enter(); 00215 if (res) { 00216 snprintf(buf, sizeof(buf), "Module '%s' is in use", module); 00217 update_statusbar(buf); 00218 } else { 00219 gdk_threads_leave(); 00220 res = ast_load_resource(module); 00221 gdk_threads_enter(); 00222 if (res) { 00223 snprintf(buf, sizeof(buf), "Error reloading module '%s'", module); 00224 } else { 00225 snprintf(buf, sizeof(buf), "Module '%s' reloaded", module); 00226 } 00227 for (x=0; x < GTK_CLIST(modules)->rows; x++) { 00228 if (!strcmp((char *)gtk_clist_get_row_data(GTK_CLIST(modules), x), module)) { 00229 gtk_clist_select_row(GTK_CLIST(modules), x, -1); 00230 break; 00231 } 00232 } 00233 update_statusbar(buf); 00234 00235 } 00236 free(module); 00237 } 00238 } 00239 00240 return 0; 00241 } 00242 00243 static void file_ok_sel(GtkWidget *w, GtkFileSelection *fs) 00244 { 00245 char tmp[PATH_MAX]; 00246 char *module = gtk_file_selection_get_filename(fs); 00247 char buf[256]; 00248 snprintf(tmp, sizeof(tmp), "%s/", ast_config_AST_MODULE_DIR); 00249 if (!strncmp(module, (char *)tmp, strlen(tmp))) 00250 module += strlen(tmp); 00251 gdk_threads_leave(); 00252 if (ast_load_resource(module)) { 00253 snprintf(buf, sizeof(buf), "Error loading module '%s'.", module); 00254 update_statusbar(buf); 00255 } else { 00256 snprintf(buf, sizeof(buf), "Module '%s' loaded", module); 00257 update_statusbar(buf); 00258 } 00259 gdk_threads_enter(); 00260 gtk_widget_destroy(GTK_WIDGET(fs)); 00261 } 00262 00263 static void add_module(void) 00264 { 00265 char tmp[PATH_MAX]; 00266 GtkWidget *filew; 00267 snprintf(tmp, sizeof(tmp), "%s/*.so", ast_config_AST_MODULE_DIR); 00268 filew = gtk_file_selection_new("Load Module"); 00269 gtk_signal_connect(GTK_OBJECT (GTK_FILE_SELECTION(filew)->ok_button), 00270 "clicked", GTK_SIGNAL_FUNC(file_ok_sel), filew); 00271 gtk_signal_connect_object(GTK_OBJECT (GTK_FILE_SELECTION(filew)->cancel_button), 00272 "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(filew)); 00273 gtk_file_selection_set_filename(GTK_FILE_SELECTION(filew), (char *)tmp); 00274 gtk_widget_show(filew); 00275 } 00276 00277 static int add_mod(const char *module, const char *description, int usecount, const char *like) 00278 { 00279 char use[10]; 00280 const char *pass[4]; 00281 int row; 00282 snprintf(use, sizeof(use), "%d", usecount); 00283 pass[0] = module; 00284 pass[1] = description; 00285 pass[2] = use; 00286 pass[3] = NULL; 00287 row = gtk_clist_append(GTK_CLIST(modules), (char **) pass); 00288 gtk_clist_set_row_data(GTK_CLIST(modules), row, (char *) module); 00289 return 0; 00290 } 00291 00292 static int mod_update(void) 00293 { 00294 char *module= NULL; 00295 /* Update the mod stuff */ 00296 if (GTK_CLIST(modules)->selection) { 00297 module= (char *)gtk_clist_get_row_data(GTK_CLIST(modules), (int) GTK_CLIST(modules)->selection->data); 00298 } 00299 gtk_clist_freeze(GTK_CLIST(modules)); 00300 gtk_clist_clear(GTK_CLIST(modules)); 00301 ast_update_module_list(add_mod, NULL); 00302 if (module) 00303 gtk_clist_select_row(GTK_CLIST(modules), gtk_clist_find_row_from_data(GTK_CLIST(modules), module), -1); 00304 gtk_clist_thaw(GTK_CLIST(modules)); 00305 return 1; 00306 } 00307 00308 static void exit_now(GtkWidget *widget, gpointer data) 00309 { 00310 ast_loader_unregister(mod_update); 00311 gtk_main_quit(); 00312 inuse--; 00313 ast_update_use_count(); 00314 ast_unregister_verbose(verboser); 00315 ast_unload_resource("pbx_gtkconsole", 0); 00316 if (option_verbose > 1) 00317 ast_verbose(VERBOSE_PREFIX_2 "GTK Console Monitor Exiting\n"); 00318 /* XXX Trying to quit after calling this makes asterisk segfault XXX */ 00319 } 00320 00321 static void exit_completely(GtkWidget *widget, gpointer data) 00322 { 00323 #if 0 00324 /* Clever... */ 00325 ast_cli_command(clipipe[1], "quit"); 00326 #else 00327 kill(getpid(), SIGTERM); 00328 #endif 00329 } 00330 00331 static void exit_nicely(GtkWidget *widget, gpointer data) 00332 { 00333 fflush(stdout); 00334 gtk_widget_destroy(window); 00335 } 00336 00337 static void *consolethread(void *data) 00338 { 00339 gtk_widget_show(window); 00340 gdk_threads_enter(); 00341 gtk_main(); 00342 gdk_threads_leave(); 00343 return NULL; 00344 } 00345 00346 static int cli_activate(void) 00347 { 00348 char buf[256] = ""; 00349 strncpy(buf, gtk_entry_get_text(GTK_ENTRY(cli)), sizeof(buf) - 1); 00350 gtk_entry_set_text(GTK_ENTRY(cli), ""); 00351 if (strlen(buf)) { 00352 ast_cli_command(clipipe[1], buf); 00353 } 00354 return TRUE; 00355 } 00356 00357 static int show_console(void) 00358 { 00359 GtkWidget *hbox; 00360 GtkWidget *wbox; 00361 GtkWidget *notebook; 00362 GtkWidget *sw; 00363 GtkWidget *bbox, *hbbox, *add, *removew, *reloadw; 00364 char *modtitles[3] = { "Module", "Description", "Use Count" }; 00365 window = gtk_window_new(GTK_WINDOW_TOPLEVEL); 00366 00367 statusbar = gtk_statusbar_new(); 00368 gtk_widget_show(statusbar); 00369 00370 gtk_signal_connect(GTK_OBJECT(window), "delete_event", 00371 GTK_SIGNAL_FUNC (exit_nicely), window); 00372 gtk_signal_connect(GTK_OBJECT(window), "destroy", 00373 GTK_SIGNAL_FUNC (exit_now), window); 00374 gtk_container_set_border_width(GTK_CONTAINER(window), 10); 00375 00376 quit = gtk_button_new_with_label("Quit Asterisk"); 00377 gtk_signal_connect(GTK_OBJECT(quit), "clicked", 00378 GTK_SIGNAL_FUNC (exit_completely), window); 00379 gtk_widget_show(quit); 00380 00381 closew = gtk_button_new_with_label("Close Window"); 00382 gtk_signal_connect(GTK_OBJECT(closew), "clicked", 00383 GTK_SIGNAL_FUNC (exit_nicely), window); 00384 gtk_widget_show(closew); 00385 00386 notebook = gtk_notebook_new(); 00387 verb = gtk_clist_new(1); 00388 gtk_clist_columns_autosize(GTK_CLIST(verb)); 00389 sw = gtk_scrolled_window_new(NULL, NULL); 00390 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); 00391 gtk_container_add(GTK_CONTAINER(sw), verb); 00392 gtk_widget_show(verb); 00393 gtk_widget_show(sw); 00394 gtk_widget_set_usize(verb, 640, 400); 00395 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), sw, gtk_label_new("Verbose Status")); 00396 00397 00398 modules = gtk_clist_new_with_titles(3, modtitles); 00399 gtk_clist_columns_autosize(GTK_CLIST(modules)); 00400 gtk_clist_set_column_auto_resize(GTK_CLIST(modules), 0, TRUE); 00401 gtk_clist_set_column_auto_resize(GTK_CLIST(modules), 1, TRUE); 00402 gtk_clist_set_column_auto_resize(GTK_CLIST(modules), 2, TRUE); 00403 gtk_clist_set_sort_column(GTK_CLIST(modules), 0); 00404 gtk_clist_set_auto_sort(GTK_CLIST(modules), TRUE); 00405 gtk_clist_column_titles_passive(GTK_CLIST(modules)); 00406 sw = gtk_scrolled_window_new(NULL, NULL); 00407 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); 00408 gtk_container_add(GTK_CONTAINER(sw), modules); 00409 gtk_clist_set_selection_mode(GTK_CLIST(modules), GTK_SELECTION_BROWSE); 00410 gtk_widget_show(modules); 00411 gtk_widget_show(sw); 00412 00413 add = gtk_button_new_with_label("Load..."); 00414 gtk_widget_show(add); 00415 removew = gtk_button_new_with_label("Unload"); 00416 gtk_widget_show(removew); 00417 reloadw = gtk_button_new_with_label("Reload"); 00418 gtk_widget_show(reloadw); 00419 gtk_signal_connect(GTK_OBJECT(removew), "clicked", 00420 GTK_SIGNAL_FUNC (remove_module), window); 00421 gtk_signal_connect(GTK_OBJECT(add), "clicked", 00422 GTK_SIGNAL_FUNC (add_module), window); 00423 gtk_signal_connect(GTK_OBJECT(reloadw), "clicked", 00424 GTK_SIGNAL_FUNC (reload_module), window); 00425 00426 bbox = gtk_vbox_new(FALSE, 5); 00427 gtk_widget_show(bbox); 00428 00429 gtk_widget_set_usize(bbox, 100, -1); 00430 gtk_box_pack_start(GTK_BOX(bbox), add, FALSE, FALSE, 5); 00431 gtk_box_pack_start(GTK_BOX(bbox), removew, FALSE, FALSE, 5); 00432 gtk_box_pack_start(GTK_BOX(bbox), reloadw, FALSE, FALSE, 5); 00433 00434 hbbox = gtk_hbox_new(FALSE, 5); 00435 gtk_widget_show(hbbox); 00436 00437 gtk_box_pack_start(GTK_BOX(hbbox), sw, TRUE, TRUE, 5); 00438 gtk_box_pack_start(GTK_BOX(hbbox), bbox, FALSE, FALSE, 5); 00439 00440 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), hbbox, gtk_label_new("Module Information")); 00441 00442 gtk_widget_show(notebook); 00443 00444 wbox = gtk_hbox_new(FALSE, 5); 00445 gtk_widget_show(wbox); 00446 gtk_box_pack_end(GTK_BOX(wbox), quit, FALSE, FALSE, 5); 00447 gtk_box_pack_end(GTK_BOX(wbox), closew, FALSE, FALSE, 5); 00448 00449 hbox = gtk_vbox_new(FALSE, 0); 00450 gtk_widget_show(hbox); 00451 00452 /* Command line */ 00453 cli = gtk_entry_new(); 00454 gtk_widget_show(cli); 00455 00456 gtk_signal_connect(GTK_OBJECT(cli), "activate", 00457 GTK_SIGNAL_FUNC (cli_activate), NULL); 00458 00459 gtk_box_pack_start(GTK_BOX(hbox), notebook, TRUE, TRUE, 5); 00460 gtk_box_pack_start(GTK_BOX(hbox), wbox, FALSE, FALSE, 5); 00461 gtk_box_pack_start(GTK_BOX(hbox), cli, FALSE, FALSE, 0); 00462 gtk_box_pack_start(GTK_BOX(hbox), statusbar, FALSE, FALSE, 0); 00463 gtk_container_add(GTK_CONTAINER(window), hbox); 00464 gtk_window_set_title(GTK_WINDOW(window), "Asterisk Console"); 00465 gtk_widget_grab_focus(cli); 00466 ast_pthread_create(&console_thread, NULL, consolethread, NULL); 00467 /* XXX Okay, seriously fix me! XXX */ 00468 usleep(100000); 00469 ast_register_verbose(verboser); 00470 gtk_clist_freeze(GTK_CLIST(verb)); 00471 ast_loader_register(mod_update); 00472 gtk_clist_thaw(GTK_CLIST(verb)); 00473 gdk_input_add(clipipe[0], GDK_INPUT_READ, cliinput, NULL); 00474 mod_update(); 00475 update_statusbar("Asterisk Console Ready"); 00476 return 0; 00477 } 00478 00479 00480 static int load_module(void *mod) 00481 { 00482 if (pipe(clipipe)) { 00483 ast_log(LOG_WARNING, "Unable to create CLI pipe\n"); 00484 return -1; 00485 } 00486 g_thread_init(NULL); 00487 if (gtk_init_check(NULL, NULL)) { 00488 if (!show_console()) { 00489 inuse++; 00490 ast_update_use_count(); 00491 if (option_verbose > 1) 00492 ast_verbose( VERBOSE_PREFIX_2 "Launched GTK Console monitor\n"); 00493 } else 00494 ast_log(LOG_WARNING, "Unable to start GTK console\n"); 00495 } else { 00496 if (option_debug) 00497 ast_log(LOG_DEBUG, "Unable to start GTK console monitor -- ignoring\n"); 00498 else if (option_verbose > 1) 00499 ast_verbose( VERBOSE_PREFIX_2 "GTK is not available -- skipping monitor\n"); 00500 } 00501 return 0; 00502 } 00503 00504 static const char *description(void) 00505 { 00506 return dtext; 00507 } 00508 00509 static const char *key(void) 00510 { 00511 return ASTERISK_GPL_KEY; 00512 } 00513 00514 STD_MOD(MOD_0, reload_module, NULL, NULL);