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