Fri Jul 15 2011 12:02:33

Asterisk developer's documentation


pbx_gtkconsole.c File Reference

GTK Console monitor -- very kludgy right now. More...

#include "asterisk.h"
#include <fcntl.h>
#include <signal.h>
#include <sys/time.h>
#include <gtk/gtk.h>
#include <glib.h>
#include "asterisk/pbx.h"
#include "asterisk/config.h"
#include "asterisk/module.h"
#include "asterisk/logger.h"
#include "asterisk/cli.h"
#include "asterisk/utils.h"
#include "asterisk/paths.h"
#include "asterisk/term.h"
Include dependency graph for pbx_gtkconsole.c:

Go to the source code of this file.

Functions

static void __reg_module (void)
static void __unreg_module (void)
static void __verboser (const char *_stuff)
static int add_mod (const char *module, const char *description, int usecount, const char *like)
static void add_module (void)
static int cleanup (void *useless)
static int cli_activate (void)
static void cliinput (void *data, int source, GdkInputCondition ic)
static void * consolethread (void *data)
static void exit_completely (GtkWidget *widget, gpointer data)
static void exit_nicely (GtkWidget *widget, gpointer data)
static void exit_now (GtkWidget *widget, gpointer data)
static void file_ok_sel (GtkWidget *w, GtkFileSelection *fs)
static int load_module (void)
static int mod_update (void)
static int reload (void)
static void remove_module (void)
static int show_console (void)
static int unload_module (void)
static void update_statusbar (char *msg)
static void verboser (const char *stuff)

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "GTK Console" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload, }
static struct ast_module_infoast_module_info = &__mod_info
static int cleanupid = -1
static GtkWidget * cli
static int clipipe [2]
static GtkWidget * closew
static pthread_t console_thread
static int inuse = 0
static struct timeval last
static GtkWidget * modules
static GtkWidget * quit
static GtkWidget * statusbar
static GtkWidget * verb
static ast_mutex_t verb_lock = ((ast_mutex_t) PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP )
static GtkWidget * window

Detailed Description

GTK Console monitor -- very kludgy right now.

Definition in file pbx_gtkconsole.c.


Function Documentation

static void __reg_module ( void  ) [static]

Definition at line 510 of file pbx_gtkconsole.c.

static void __unreg_module ( void  ) [static]

Definition at line 510 of file pbx_gtkconsole.c.

static void __verboser ( const char *  _stuff) [static]

Definition at line 100 of file pbx_gtkconsole.c.

References ast_strdupa, ast_tvdiff_ms(), ast_tvzero(), cleanup(), last, and term_strip().

Referenced by cliinput(), and verboser().

{
   char *s2[2];
   struct timeval tv;
   int ms;
   char *stuff;

   stuff = ast_strdupa(_stuff);
   term_strip(stuff, stuff, strlen(stuff) + 1);

   s2[0] = (char *)stuff;
   s2[1] = NULL;
   gtk_clist_freeze(GTK_CLIST(verb));
   gtk_clist_append(GTK_CLIST(verb), s2);
   if (!ast_tvzero(last)) {
      gdk_threads_leave();
      gettimeofday(&tv, NULL);
      if (cleanupid > -1)
         gtk_timeout_remove(cleanupid);
      ms = ast_tvdiff_ms(tv, last);
      if (ms < 100) {
         /* We just got a message within 100ms, so just schedule an update
            in the near future */
         cleanupid = gtk_timeout_add(200, cleanup, NULL);
      } else {
         cleanup(&cleanupid);
      }
      last = tv;
   } else {
      gettimeofday(&last, NULL);
   }
}
static int add_mod ( const char *  module,
const char *  description,
int  usecount,
const char *  like 
) [static]

Definition at line 277 of file pbx_gtkconsole.c.

References description, and pass.

Referenced by mod_update().

{
   char use[10];
   const char *pass[4];
   int row;
   snprintf(use, sizeof(use), "%d", usecount);
   pass[0] = module;
   pass[1] = description;
   pass[2] = use;
   pass[3] = NULL;
   row = gtk_clist_append(GTK_CLIST(modules), (char **) pass);
   gtk_clist_set_row_data(GTK_CLIST(modules), row, (char *) module);
   return 0;   
}
static void add_module ( void  ) [static]

Definition at line 263 of file pbx_gtkconsole.c.

References ast_config_AST_MODULE_DIR, and file_ok_sel().

Referenced by show_console().

{
   char tmp[PATH_MAX];
   GtkWidget *filew;
   snprintf(tmp, sizeof(tmp), "%s/*.so", ast_config_AST_MODULE_DIR);
   filew = gtk_file_selection_new("Load Module");
   gtk_signal_connect(GTK_OBJECT (GTK_FILE_SELECTION(filew)->ok_button),
               "clicked", GTK_SIGNAL_FUNC(file_ok_sel), filew);
   gtk_signal_connect_object(GTK_OBJECT (GTK_FILE_SELECTION(filew)->cancel_button),
               "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(filew));
   gtk_file_selection_set_filename(GTK_FILE_SELECTION(filew), (char *)tmp);
   gtk_widget_show(filew);
}
static int cleanup ( void *  useless) [static]

Definition at line 88 of file pbx_gtkconsole.c.

Referenced by __verboser(), _sip_tcp_helper_thread(), build_user(), and handle_uri().

{
   gdk_threads_enter();
   gtk_clist_thaw(GTK_CLIST(verb));
   gtk_widget_queue_resize(verb->parent);
   gtk_clist_moveto(GTK_CLIST(verb), GTK_CLIST(verb)->rows - 1, 0, 0, 0);
   cleanupid = -1;
   gdk_threads_leave();
   return 0;
}
static int cli_activate ( void  ) [static]

Definition at line 347 of file pbx_gtkconsole.c.

References ast_cli_command, buf, and TRUE.

Referenced by show_console().

{
   char buf[256] = "";
   strncpy(buf, gtk_entry_get_text(GTK_ENTRY(cli)), sizeof(buf) - 1);
   gtk_entry_set_text(GTK_ENTRY(cli), "");
   if (strlen(buf)) {
      ast_cli_command(clipipe[1], buf);
   }
   return TRUE;
}
static void cliinput ( void *  data,
int  source,
GdkInputCondition  ic 
) [static]

Definition at line 145 of file pbx_gtkconsole.c.

References __verboser(), and buf.

Referenced by show_console().

{
   static char buf[256];
   static int offset = 0;
   int res;
   char *c;
   char *l;
   char n;
   /* Read as much stuff is there */
   res = read(source, buf + offset, sizeof(buf) - 1 - offset);
   if (res > -1)
      buf[res + offset] = '\0';
   /* make sure we've null terminated whatever we have so far */
   c = buf;
   l = buf;
   while(*c) {
      if (*c == '\n') {
         /* Keep the trailing \n */
         c++;
         n = *c;
         *c = '\0';
         __verboser(l);
         *(c - 1) = '\0';
         *c = n;
         l = c;
      } else
      c++;
   }
   if (strlen(l)) {
      /* We have some left over */
      memmove(buf, l, strlen(l) + 1);
      offset = strlen(buf);
   } else {
      offset = 0;
   }

}
static void* consolethread ( void *  data) [static]

Definition at line 338 of file pbx_gtkconsole.c.

Referenced by show_console().

{
   gtk_widget_show(window);
   gdk_threads_enter();
   gtk_main();
   gdk_threads_leave();
   return NULL;
}
static void exit_completely ( GtkWidget *  widget,
gpointer  data 
) [static]

Definition at line 322 of file pbx_gtkconsole.c.

References ast_cli_command.

Referenced by show_console().

{
#if 0
   /* Clever... */
   ast_cli_command(clipipe[1], "quit");
#else
   kill(getpid(), SIGTERM);
#endif
}
static void exit_nicely ( GtkWidget *  widget,
gpointer  data 
) [static]

Definition at line 332 of file pbx_gtkconsole.c.

Referenced by show_console().

{
   fflush(stdout);
   gtk_widget_destroy(window);
}
static void exit_now ( GtkWidget *  widget,
gpointer  data 
) [static]

Definition at line 308 of file pbx_gtkconsole.c.

References ast_loader_unregister(), ast_unload_resource(), ast_unregister_verbose(), ast_update_use_count(), ast_verb, mod_update(), and verboser().

Referenced by show_console().

{
   int res;

   ast_loader_unregister(mod_update);
   gtk_main_quit();
   inuse--;
   ast_update_use_count();
   res = ast_unregister_verbose(verboser);
   ast_unload_resource("pbx_gtkconsole", 0);
   ast_verb(2, "GTK Console Monitor Exiting\n");
   /* XXX Trying to quit after calling this makes asterisk segfault XXX */
}
static void file_ok_sel ( GtkWidget *  w,
GtkFileSelection *  fs 
) [static]

Definition at line 243 of file pbx_gtkconsole.c.

References ast_config_AST_MODULE_DIR, ast_load_resource(), buf, and update_statusbar().

Referenced by add_module().

{
   char tmp[PATH_MAX];
   char *module = gtk_file_selection_get_filename(fs);
   char buf[256];
   snprintf(tmp, sizeof(tmp), "%s/", ast_config_AST_MODULE_DIR);
   if (!strncmp(module, (char *)tmp, strlen(tmp))) 
      module += strlen(tmp);
   gdk_threads_leave();
   if (ast_load_resource(module)) {
      snprintf(buf, sizeof(buf), "Error loading module '%s'.", module);
      update_statusbar(buf);
   } else {
      snprintf(buf, sizeof(buf), "Module '%s' loaded", module);
      update_statusbar(buf);
   }
   gdk_threads_enter();
   gtk_widget_destroy(GTK_WIDGET(fs));
}
static int load_module ( void  ) [static]

Definition at line 483 of file pbx_gtkconsole.c.

References ast_log(), AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_SUCCESS, ast_update_use_count(), ast_verb, LOG_DEBUG, LOG_WARNING, option_debug, and show_console().

{
   if (pipe(clipipe)) {
      ast_log(LOG_WARNING, "Unable to create CLI pipe\n");
      return AST_MODULE_LOAD_FAILURE;
   }
   g_thread_init(NULL);
   if (gtk_init_check(NULL, NULL))  {
      if (!show_console()) {
         inuse++;
         ast_update_use_count();
         ast_verb(2, "Launched GTK Console monitor\n");
      } else
         ast_log(LOG_WARNING, "Unable to start GTK console\n");
   } else {
      if (option_debug)
         ast_log(LOG_DEBUG, "Unable to start GTK console monitor -- ignoring\n");
      else
         ast_verb(2, "GTK is not available -- skipping monitor\n");
   }
   return AST_MODULE_LOAD_SUCCESS;
}
static int mod_update ( void  ) [static]

Definition at line 292 of file pbx_gtkconsole.c.

References add_mod(), and ast_update_module_list().

Referenced by exit_now(), and show_console().

{
   char *module= NULL;
   /* Update the mod stuff */
   if (GTK_CLIST(modules)->selection) {
      module= (char *)gtk_clist_get_row_data(GTK_CLIST(modules), (long) GTK_CLIST(modules)->selection->data);
   }
   gtk_clist_freeze(GTK_CLIST(modules));
   gtk_clist_clear(GTK_CLIST(modules));
   ast_update_module_list(add_mod, NULL);
   if (module)
      gtk_clist_select_row(GTK_CLIST(modules), gtk_clist_find_row_from_data(GTK_CLIST(modules), module), -1);
   gtk_clist_thaw(GTK_CLIST(modules));
   return 1;
}
static int reload ( void  ) [static]

Definition at line 203 of file pbx_gtkconsole.c.

References ast_load_resource(), AST_MODULE_LOAD_SUCCESS, ast_unload_resource(), buf, free, strdup, and update_statusbar().

{
   int res, x;
   char *module;
   char buf[256];
   if (GTK_CLIST(modules)->selection) {
      module= (char *)gtk_clist_get_row_data(GTK_CLIST(modules), (long) GTK_CLIST(modules)->selection->data);
      module = strdup(module);
      if (module) {
         gdk_threads_leave();
         res = ast_unload_resource(module, 0);
         gdk_threads_enter();
         if (res) {
            snprintf(buf, sizeof(buf), "Module '%s' is in use", module);
            update_statusbar(buf);
         } else {
            gdk_threads_leave();
            res = ast_load_resource(module);
            gdk_threads_enter();
            if (res) {
               snprintf(buf, sizeof(buf), "Error reloading module '%s'", module);
            } else {
               snprintf(buf, sizeof(buf), "Module '%s' reloaded", module);
            }
            for (x=0; x < GTK_CLIST(modules)->rows; x++) {
               if (!strcmp((char *)gtk_clist_get_row_data(GTK_CLIST(modules), x), module)) {
                  gtk_clist_select_row(GTK_CLIST(modules), x, -1);
                  break;
               }
            }
            update_statusbar(buf);
            
         }
         free(module);
      }
   }

   return AST_MODULE_LOAD_SUCCESS;
}
static void remove_module ( void  ) [static]

Definition at line 183 of file pbx_gtkconsole.c.

References ast_unload_resource(), buf, and update_statusbar().

Referenced by show_console().

{
   int res;
   char *module;
   char buf[256];
   if (GTK_CLIST(modules)->selection) {
      module = (char *) gtk_clist_get_row_data(GTK_CLIST(modules), (long) GTK_CLIST(modules)->selection->data);
      gdk_threads_leave();
      res = ast_unload_resource(module, 0);
      gdk_threads_enter();
      if (res) {
         snprintf(buf, sizeof(buf), "Module '%s' is in use", module);
         update_statusbar(buf);
      } else {
         snprintf(buf, sizeof(buf), "Module '%s' removed", module);
         update_statusbar(buf);
      }
   }
}
static int show_console ( void  ) [static]

Definition at line 358 of file pbx_gtkconsole.c.

References add_module(), ast_loader_register(), ast_pthread_create, ast_register_verbose(), cli_activate(), cliinput(), consolethread(), exit_completely(), exit_nicely(), exit_now(), FALSE, mod_update(), reload, remove_module(), TRUE, update_statusbar(), and verboser().

Referenced by load_module().

{
   GtkWidget *hbox;
   GtkWidget *wbox;
   GtkWidget *notebook;
   GtkWidget *sw;
   GtkWidget *bbox, *hbbox, *add, *removew, *reloadw;
   char *modtitles[3] = { "Module", "Description", "Use Count" };
   int res;

   window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
   
   statusbar = gtk_statusbar_new();
   gtk_widget_show(statusbar);
   
   gtk_signal_connect(GTK_OBJECT(window), "delete_event",
         GTK_SIGNAL_FUNC (exit_nicely), window);
   gtk_signal_connect(GTK_OBJECT(window), "destroy",
         GTK_SIGNAL_FUNC (exit_now), window);
   gtk_container_set_border_width(GTK_CONTAINER(window), 10);

   quit = gtk_button_new_with_label("Quit Asterisk");
   gtk_signal_connect(GTK_OBJECT(quit), "clicked",
         GTK_SIGNAL_FUNC (exit_completely), window);
   gtk_widget_show(quit);

   closew = gtk_button_new_with_label("Close Window");
   gtk_signal_connect(GTK_OBJECT(closew), "clicked",
         GTK_SIGNAL_FUNC (exit_nicely), window);
   gtk_widget_show(closew);

   notebook = gtk_notebook_new();
   verb = gtk_clist_new(1);
   gtk_clist_columns_autosize(GTK_CLIST(verb));
   sw = gtk_scrolled_window_new(NULL, NULL);
   gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
   gtk_container_add(GTK_CONTAINER(sw), verb);
   gtk_widget_show(verb);
   gtk_widget_show(sw);
   gtk_widget_set_usize(verb, 640, 400);
   gtk_notebook_append_page(GTK_NOTEBOOK(notebook), sw, gtk_label_new("Verbose Status"));

   
   modules = gtk_clist_new_with_titles(3, modtitles);
   gtk_clist_columns_autosize(GTK_CLIST(modules));
   gtk_clist_set_column_auto_resize(GTK_CLIST(modules), 0, TRUE);
   gtk_clist_set_column_auto_resize(GTK_CLIST(modules), 1, TRUE);
   gtk_clist_set_column_auto_resize(GTK_CLIST(modules), 2, TRUE);
   gtk_clist_set_sort_column(GTK_CLIST(modules), 0);
   gtk_clist_set_auto_sort(GTK_CLIST(modules), TRUE);
   gtk_clist_column_titles_passive(GTK_CLIST(modules));
   sw = gtk_scrolled_window_new(NULL, NULL);
   gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
   gtk_container_add(GTK_CONTAINER(sw), modules);
   gtk_clist_set_selection_mode(GTK_CLIST(modules), GTK_SELECTION_BROWSE);
   gtk_widget_show(modules);
   gtk_widget_show(sw);

   add = gtk_button_new_with_label("Load...");
   gtk_widget_show(add);
   removew = gtk_button_new_with_label("Unload");
   gtk_widget_show(removew);
   reloadw = gtk_button_new_with_label("Reload");
   gtk_widget_show(reloadw);
   gtk_signal_connect(GTK_OBJECT(removew), "clicked",
         GTK_SIGNAL_FUNC (remove_module), window);
   gtk_signal_connect(GTK_OBJECT(add), "clicked",
         GTK_SIGNAL_FUNC (add_module), window);
   gtk_signal_connect(GTK_OBJECT(reloadw), "clicked",
         GTK_SIGNAL_FUNC (reload), window);
      
   bbox = gtk_vbox_new(FALSE, 5);
   gtk_widget_show(bbox);

   gtk_widget_set_usize(bbox, 100, -1);
   gtk_box_pack_start(GTK_BOX(bbox), add, FALSE, FALSE, 5);
   gtk_box_pack_start(GTK_BOX(bbox), removew, FALSE, FALSE, 5);
   gtk_box_pack_start(GTK_BOX(bbox), reloadw, FALSE, FALSE, 5);

   hbbox = gtk_hbox_new(FALSE, 5);
   gtk_widget_show(hbbox);
   
   gtk_box_pack_start(GTK_BOX(hbbox), sw, TRUE, TRUE, 5);
   gtk_box_pack_start(GTK_BOX(hbbox), bbox, FALSE, FALSE, 5);

   gtk_notebook_append_page(GTK_NOTEBOOK(notebook), hbbox, gtk_label_new("Module Information"));

   gtk_widget_show(notebook);

   wbox = gtk_hbox_new(FALSE, 5);
   gtk_widget_show(wbox);
   gtk_box_pack_end(GTK_BOX(wbox), quit, FALSE, FALSE, 5);
   gtk_box_pack_end(GTK_BOX(wbox), closew, FALSE, FALSE, 5);

   hbox = gtk_vbox_new(FALSE, 0);
   gtk_widget_show(hbox);
   
   /* Command line */
   cli = gtk_entry_new();
   gtk_widget_show(cli);

   gtk_signal_connect(GTK_OBJECT(cli), "activate",
         GTK_SIGNAL_FUNC (cli_activate), NULL);

   gtk_box_pack_start(GTK_BOX(hbox), notebook, TRUE, TRUE, 5);
   gtk_box_pack_start(GTK_BOX(hbox), wbox, FALSE, FALSE, 5);
   gtk_box_pack_start(GTK_BOX(hbox), cli, FALSE, FALSE, 0);
   gtk_box_pack_start(GTK_BOX(hbox), statusbar, FALSE, FALSE, 0);
   gtk_container_add(GTK_CONTAINER(window), hbox);
   gtk_window_set_title(GTK_WINDOW(window), "Asterisk Console");
   gtk_widget_grab_focus(cli);
   ast_pthread_create(&console_thread, NULL, consolethread, NULL);
   /* XXX Okay, seriously fix me! XXX */
   usleep(100000);
   res = ast_register_verbose(verboser);
   gtk_clist_freeze(GTK_CLIST(verb));
   ast_loader_register(mod_update);
   gtk_clist_thaw(GTK_CLIST(verb));
   gdk_input_add(clipipe[0], GDK_INPUT_READ, cliinput, NULL);
   mod_update();
   update_statusbar("Asterisk Console Ready");
   return 0;
}
static int unload_module ( void  ) [static]

Definition at line 74 of file pbx_gtkconsole.c.

{
   if (inuse) {
      /* Kill off the main thread */
      pthread_cancel(console_thread);
      gdk_threads_enter();
      gtk_widget_destroy(window);
      gdk_threads_leave();
      close(clipipe[0]);
      close(clipipe[1]);
   }
   return 0;
}
static void update_statusbar ( char *  msg) [static]

Definition at line 68 of file pbx_gtkconsole.c.

Referenced by file_ok_sel(), reload(), remove_module(), and show_console().

{
   gtk_statusbar_pop(GTK_STATUSBAR(statusbar), 1);
   gtk_statusbar_push(GTK_STATUSBAR(statusbar), 1, msg);
}
static void verboser ( const char *  stuff) [static]

Definition at line 133 of file pbx_gtkconsole.c.

References __verboser(), ast_mutex_lock(), ast_mutex_unlock(), and verb_lock.

Referenced by exit_now(), and show_console().

{
   if (*stuff == 127) {
      stuff++;
   }

   ast_mutex_lock(&verb_lock);
   /* Lock appropriately if we're really being called in verbose mode */
   __verboser(stuff);
   ast_mutex_unlock(&verb_lock);
}

Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "GTK Console" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload, } [static]

Definition at line 510 of file pbx_gtkconsole.c.

Definition at line 510 of file pbx_gtkconsole.c.

int cleanupid = -1 [static]

Definition at line 56 of file pbx_gtkconsole.c.

GtkWidget* cli [static]

Definition at line 64 of file pbx_gtkconsole.c.

int clipipe[2] [static]

Definition at line 55 of file pbx_gtkconsole.c.

GtkWidget* closew [static]

Definition at line 60 of file pbx_gtkconsole.c.

pthread_t console_thread [static]

Definition at line 52 of file pbx_gtkconsole.c.

int inuse = 0 [static]

Definition at line 54 of file pbx_gtkconsole.c.

struct timeval last [static]

Definition at line 66 of file pbx_gtkconsole.c.

GtkWidget* modules [static]

Definition at line 62 of file pbx_gtkconsole.c.

GtkWidget* quit [static]

Definition at line 59 of file pbx_gtkconsole.c.

Referenced by launch_asyncagi(), mwi_send_process_buffer(), mwi_thread(), and ss_thread().

GtkWidget* statusbar [static]

Definition at line 63 of file pbx_gtkconsole.c.

GtkWidget* verb [static]

Definition at line 61 of file pbx_gtkconsole.c.

Referenced by ast_register_verbose().

ast_mutex_t verb_lock = ((ast_mutex_t) PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP ) [static]

Definition at line 50 of file pbx_gtkconsole.c.

Referenced by verboser().

GtkWidget* window [static]

Definition at line 58 of file pbx_gtkconsole.c.