toplevel.c

Go to the documentation of this file.
00001 /**
00002  *  @file
00003  *  Implementation for the main toplevel window.
00004  *
00005  *  @author Jeremy A. Mowery jmowery@tresys.com
00006  *  @author Jason Tang jtang@tresys.com
00007  *
00008  *  Copyright (C) 2003-2007 Tresys Technology, LLC
00009  *
00010  *  This program is free software; you can redistribute it and/or modify
00011  *  it under the terms of the GNU General Public License as published by
00012  *  the Free Software Foundation; either version 2 of the License, or
00013  *  (at your option) any later version.
00014  *
00015  *  This program is distributed in the hope that it will be useful,
00016  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  *  GNU General Public License for more details.
00019  *
00020  *  You should have received a copy of the GNU General Public License
00021  *  along with this program; if not, write to the Free Software
00022  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00023  */
00024 
00025 #include <config.h>
00026 
00027 #include "message_view.h"
00028 #include "open_policy_window.h"
00029 #include "policy_view.h"
00030 #include "preferences_view.h"
00031 #include "report_window.h"
00032 #include "toplevel.h"
00033 #include "utilgui.h"
00034 
00035 #include <assert.h>
00036 #include <errno.h>
00037 #include <string.h>
00038 #include <apol/util.h>
00039 #include <gdk-pixbuf/gdk-pixbuf.h>
00040 #include <gtk/gtk.h>
00041 #include <glade/glade.h>
00042 #include <seaudit/parse.h>
00043 
00044 struct toplevel
00045 {
00046         seaudit_t *s;
00047         policy_view_t *pv;
00048         progress_t *progress;
00049         /** vector of message_view_t that are in the toplevel's notebook */
00050         apol_vector_t *views;
00051         GladeXML *xml;
00052         /** filename for glade file */
00053         char *xml_filename;
00054         /** toplevel window widget */
00055         GtkWindow *w;
00056         GtkNotebook *notebook;
00057         /** non-zero if the log file should be polled for changes */
00058         int do_monitor_log;
00059         /** event id for the monitor callback */
00060         guint monitor_id;
00061         /** serial number for models created, such that new models
00062          * will be named Untitled <number> */
00063         int next_model_number;
00064         /** filename for most recently opened view */
00065         char *view_filename;
00066 };
00067 
00068 /**
00069  * Given a view, return its index within the toplevel notebook pages.
00070  *
00071  * @param top Toplevel containing the notebook.
00072  * @param view View to look up.
00073  *
00074  * @return Index of the view (zero-indexed), or -1 if not found.
00075  */
00076 static gint toplevel_notebook_find_view(toplevel_t * top, message_view_t * view)
00077 {
00078         gint num_pages = gtk_notebook_get_n_pages(top->notebook);
00079         while (num_pages >= 1) {
00080                 GtkWidget *child = gtk_notebook_get_nth_page(top->notebook, num_pages - 1);
00081                 GtkWidget *tab = gtk_notebook_get_tab_label(top->notebook, child);
00082                 message_view_t *v = g_object_get_data(G_OBJECT(tab), "view-object");
00083                 if (v == view) {
00084                         return num_pages - 1;
00085                 }
00086                 num_pages--;
00087         }
00088         return -1;
00089 }
00090 
00091 /**
00092  * Return the view on the page that is currently raised, or NULL if
00093  * there are no views.
00094  */
00095 static message_view_t *toplevel_get_current_view(toplevel_t * top)
00096 {
00097         gint current = gtk_notebook_get_current_page(top->notebook);
00098         if (current >= 0) {
00099                 GtkWidget *child = gtk_notebook_get_nth_page(top->notebook, current);
00100                 GtkWidget *tab = gtk_notebook_get_tab_label(top->notebook, child);
00101                 return g_object_get_data(G_OBJECT(tab), "view-object");
00102         }
00103         return NULL;
00104 }
00105 
00106 static void toplevel_on_notebook_switch_page(GtkNotebook * notebook __attribute__ ((unused)), GtkNotebookPage * page
00107                                              __attribute__ ((unused)), guint pagenum __attribute__ ((unused)), toplevel_t * top)
00108 {
00109         toplevel_update_selection_menu_item(top);
00110         toplevel_update_status_bar(top);
00111 }
00112 
00113 /**
00114  * Callback invoked when a tab close button is clicked.
00115  */
00116 static void toplevel_on_tab_close(GtkButton * button, toplevel_t * top)
00117 {
00118         /* disallow the close if this is the last tab */
00119         if (top->views == NULL || apol_vector_get_size(top->views) <= 1) {
00120                 return;
00121         } else {
00122                 message_view_t *view = g_object_get_data(G_OBJECT(button), "view-object");
00123                 gint idx = toplevel_notebook_find_view(top, view);
00124                 size_t i;
00125                 assert(idx >= 0);
00126                 gtk_notebook_remove_page(top->notebook, idx);
00127                 apol_vector_get_index(top->views, view, NULL, NULL, &i);
00128                 message_view_destroy(&view);
00129                 apol_vector_remove(top->views, i);
00130         }
00131 }
00132 
00133 /**
00134  * Create a new view associated with the given model, then create a
00135  * tab to place that view.  The newly created tab will then be raised.
00136  *
00137  * @param top Toplevel containing notebook to which add the view and tab.
00138  * @param model Model from which to create a view.
00139  * @param filename Initial filename for the view.
00140  */
00141 static void toplevel_add_new_view(toplevel_t * top, seaudit_model_t * model, const char *filename)
00142 {
00143         message_view_t *view;
00144         GtkWidget *tab, *button, *label, *image;
00145         gint idx;
00146         if ((view = message_view_create(top, model, filename)) == NULL) {
00147                 return;
00148         }
00149         if (apol_vector_append(top->views, view) < 0) {
00150                 toplevel_ERR(top, "%s", strerror(errno));
00151                 message_view_destroy(&view);
00152                 return;
00153         }
00154         tab = gtk_hbox_new(FALSE, 5);
00155         g_object_set_data(G_OBJECT(tab), "view-object", view);
00156         button = gtk_button_new();
00157         g_object_set_data(G_OBJECT(button), "view-object", view);
00158         image = gtk_image_new_from_stock(GTK_STOCK_CLOSE, GTK_ICON_SIZE_MENU);
00159         gtk_container_add(GTK_CONTAINER(button), image);
00160         gtk_widget_set_size_request(image, 8, 8);
00161         g_signal_connect(G_OBJECT(button), "pressed", G_CALLBACK(toplevel_on_tab_close), top);
00162         label = gtk_label_new(seaudit_model_get_name(model));
00163         g_object_set_data(G_OBJECT(tab), "label", label);
00164         gtk_box_pack_start(GTK_BOX(tab), label, TRUE, TRUE, 5);
00165         gtk_box_pack_end(GTK_BOX(tab), button, FALSE, FALSE, 5);
00166         gtk_widget_show(label);
00167         gtk_widget_show(button);
00168         gtk_widget_show(image);
00169         idx = gtk_notebook_append_page(top->notebook, message_view_get_view(view), tab);
00170         gtk_notebook_set_current_page(top->notebook, idx);
00171 }
00172 
00173 /**
00174  * Create a new model for the currently loaded log file (which could
00175  * be NULL), then create a view that watches that model.
00176  */
00177 static void toplevel_add_new_model(toplevel_t * top)
00178 {
00179         seaudit_log_t *log = seaudit_get_log(top->s);
00180         char *model_name = NULL;
00181         seaudit_model_t *model = NULL;
00182         if (asprintf(&model_name, "Untitled %d", top->next_model_number) < 0) {
00183                 toplevel_ERR(top, "%s", strerror(errno));
00184                 return;
00185         }
00186         model = seaudit_model_create(model_name, log);
00187         free(model_name);
00188         if (model == NULL) {
00189                 toplevel_ERR(top, "%s", strerror(errno));
00190                 return;
00191         } else {
00192                 top->next_model_number++;
00193                 toplevel_add_new_view(top, model, NULL);
00194         }
00195 }
00196 
00197 /**
00198  * Callback whenever an item from the recent logs submenu is activated.
00199  */
00200 static void toplevel_on_open_recent_log_activate(GtkWidget * widget, gpointer user_data)
00201 {
00202         GtkWidget *label = gtk_bin_get_child(GTK_BIN(widget));
00203         const char *path = gtk_label_get_text(GTK_LABEL(label));
00204         toplevel_t *top = (toplevel_t *) user_data;
00205         toplevel_open_log(top, path);
00206 }
00207 
00208 /**
00209  * Update the entries within recent logs submenu to match those in the
00210  * preferences object.
00211  */
00212 static void toplevel_set_recent_logs_submenu(toplevel_t * top)
00213 {
00214         GtkMenuItem *recent = GTK_MENU_ITEM(glade_xml_get_widget(top->xml, "OpenRecentLog"));
00215         apol_vector_t *paths = preferences_get_recent_logs(toplevel_get_prefs(top));
00216         GtkWidget *submenu, *submenu_item;
00217         size_t i;
00218 
00219         gtk_menu_item_remove_submenu(recent);
00220         submenu = gtk_menu_new();
00221         for (i = 0; i < apol_vector_get_size(paths); i++) {
00222                 char *path = (char *)apol_vector_get_element(paths, i);
00223                 submenu_item = gtk_menu_item_new_with_label(path);
00224                 gtk_menu_shell_prepend(GTK_MENU_SHELL(submenu), submenu_item);
00225                 gtk_widget_show(submenu_item);
00226                 g_signal_connect(G_OBJECT(submenu_item), "activate", G_CALLBACK(toplevel_on_open_recent_log_activate), top);
00227         }
00228         gtk_menu_item_set_submenu(GTK_MENU_ITEM(recent), submenu);
00229 }
00230 
00231 /**
00232  * Callback whenever an item from the recent policies submenu is
00233  * activated.
00234  */
00235 static void toplevel_on_open_recent_policy_activate(GtkMenuItem * menuitem, gpointer user_data)
00236 {
00237         apol_policy_path_t *path = g_object_get_data(G_OBJECT(menuitem), "path");
00238         toplevel_t *top = (toplevel_t *) user_data;
00239         apol_policy_path_t *dup_path = apol_policy_path_create_from_policy_path(path);
00240         if (dup_path == NULL) {
00241                 toplevel_ERR(top, "%s", strerror(errno));
00242                 return;
00243         }
00244         toplevel_open_policy(top, dup_path);
00245 }
00246 
00247 /**
00248  * Update the entries within recent policies submenu to match those in
00249  * the preferences object.
00250  */
00251 static void toplevel_set_recent_policies_submenu(toplevel_t * top)
00252 {
00253         GtkMenuItem *recent = GTK_MENU_ITEM(glade_xml_get_widget(top->xml, "OpenRecentPolicy"));
00254         apol_vector_t *paths = preferences_get_recent_policies(toplevel_get_prefs(top));
00255         GtkWidget *submenu, *submenu_item;
00256         size_t i;
00257 
00258         GtkTooltipsData *tips_data = gtk_tooltips_data_get(GTK_WIDGET(recent));
00259         assert(tips_data != NULL);
00260         GtkTooltips *tooltips = tips_data->tooltips;
00261 
00262         gtk_menu_item_remove_submenu(recent);
00263         submenu = gtk_menu_new();
00264         for (i = 0; i < apol_vector_get_size(paths); i++) {
00265                 apol_policy_path_t *path = apol_vector_get_element(paths, i);
00266                 char *menu_label = NULL;
00267                 const char *primary_path = apol_policy_path_get_primary(path);
00268                 GString *tip = g_string_new(NULL);
00269                 if ((menu_label = util_policy_path_to_string(path)) == NULL) {
00270                         toplevel_ERR(top, "%s", strerror(errno));
00271                         g_string_free(tip, TRUE);
00272                         break;
00273                 }
00274                 submenu_item = gtk_menu_item_new_with_label(menu_label);
00275                 free(menu_label);
00276                 if (apol_policy_path_get_type(path) == APOL_POLICY_PATH_TYPE_MONOLITHIC) {
00277                         g_string_append_printf(tip, "monolithic policy: %s", primary_path);
00278                 } else {
00279                         char *s = NULL;
00280                         const apol_vector_t *modules = apol_policy_path_get_modules(path);
00281                         size_t num_modules = apol_vector_get_size(modules);
00282                         g_string_append_printf(tip, "base policy: %s", primary_path);
00283                         if (num_modules > 0) {
00284                                 if ((s = apol_str_join(modules, "\n    ")) == NULL) {
00285                                         toplevel_ERR(top, "%s", strerror(errno));
00286                                         break;
00287                                 }
00288                                 g_string_append_printf(tip, "\n    %s", s);
00289                                 free(s);
00290                         }
00291                 }
00292                 gtk_tooltips_set_tip(tooltips, GTK_WIDGET(submenu_item), tip->str, "");
00293                 g_string_free(tip, TRUE);
00294                 g_object_set_data(G_OBJECT(submenu_item), "path", path);
00295                 gtk_menu_shell_prepend(GTK_MENU_SHELL(submenu), submenu_item);
00296                 gtk_widget_show(submenu_item);
00297                 g_signal_connect(G_OBJECT(submenu_item), "activate", G_CALLBACK(toplevel_on_open_recent_policy_activate), top);
00298         }
00299         gtk_menu_item_set_submenu(GTK_MENU_ITEM(recent), submenu);
00300 }
00301 
00302 /**
00303  * Enable/disable all items (menus and buttons) that depend upon if a
00304  * log is loaded.
00305  *
00306  * @param top Toplevel object containing menu items.
00307  * @param TRUE to enable items, FALSE to disable.
00308  */
00309 static void toplevel_enable_log_items(toplevel_t * top, gboolean sens)
00310 {
00311         static const char *items[] = {
00312                 "NewView", "OpenView", "SaveView", "SaveViewAs", "ModifyView",
00313                 "ExportAll", "ExportSelected", "ViewMessage",
00314                 "CreateReport", "MonitorLog", "ClearView",
00315                 "ModifyViewButton", "MonitorLogButton", "ClearViewButton",
00316                 NULL
00317         };
00318         size_t i;
00319         const char *s;
00320         for (i = 0, s = items[0]; s != NULL; s = items[++i]) {
00321                 GtkWidget *w = glade_xml_get_widget(top->xml, s);
00322                 assert(w != NULL);
00323                 gtk_widget_set_sensitive(w, sens);
00324         }
00325 }
00326 
00327 /**
00328  * Enable/disable all items (menus and buttons) that depend upon if a
00329  * policy is loaded.
00330  *
00331  * @param top Toplevel object containing widgets.
00332  * @param TRUE to enable items, FALSE to disable.
00333  */
00334 static void toplevel_enable_policy_items(toplevel_t * top, gboolean sens)
00335 {
00336         static const char *items[] = {
00337                 "FindTERules", "FindTERulesButton",
00338                 NULL
00339         };
00340         size_t i;
00341         const char *s;
00342         for (i = 0, s = items[0]; s != NULL; s = items[++i]) {
00343                 GtkWidget *w = glade_xml_get_widget(top->xml, s);
00344                 assert(w != NULL);
00345                 gtk_widget_set_sensitive(w, sens);
00346         }
00347 }
00348 
00349 /**
00350  * Update the toplevel's title bar to list the log and policy files
00351  * opened.
00352  *
00353  * @param top Toplevel to modify.
00354  */
00355 static void toplevel_update_title_bar(toplevel_t * top)
00356 {
00357         char *log_path = seaudit_get_log_path(top->s);
00358         apol_policy_path_t *policy_path = seaudit_get_policy_path(top->s);
00359         char *policy_type_str = "Policy";
00360         const char *primary_path;
00361         char *s;
00362 
00363         if (log_path == NULL) {
00364                 log_path = "No Log";
00365         }
00366         if (policy_path == NULL) {
00367                 primary_path = "No Policy";
00368         } else {
00369                 if (apol_policy_path_get_type(policy_path) == APOL_POLICY_PATH_TYPE_MODULAR) {
00370                         policy_type_str = "Base";
00371                 }
00372                 primary_path = apol_policy_path_get_primary(policy_path);
00373         }
00374         if (asprintf(&s, "seaudit - [Log file: %s] [%s file: %s]", log_path, policy_type_str, primary_path) < 0) {
00375                 toplevel_ERR(top, "%s", strerror(errno));
00376                 return;
00377         }
00378         gtk_window_set_title(top->w, s);
00379         free(s);
00380 }
00381 
00382 /**
00383  * Initialize the application icons for the program.  These icons are
00384  * the ones shown by the window manager within title bars and pagers.
00385  * The last icon listed in the array will be displayed in the About
00386  * dialog.
00387  *
00388  * @param top Toplevel whose icon to set.  All child windows will
00389  * inherit these icons.
00390  */
00391 static void init_icons(toplevel_t * top)
00392 {
00393         static const char *icon_names[] = { "seaudit-small.png", "seaudit.png" };
00394         GdkPixbuf *icon;
00395         char *path;
00396         GList *icon_list = NULL;
00397         size_t i;
00398         for (i = 0; i < sizeof(icon_names) / sizeof(icon_names[0]); i++) {
00399                 if ((path = apol_file_find_path(icon_names[i])) == NULL) {
00400                         continue;
00401                 }
00402                 icon = gdk_pixbuf_new_from_file(path, NULL);
00403                 free(path);
00404                 if (icon == NULL) {
00405                         continue;
00406                 }
00407                 icon_list = g_list_append(icon_list, icon);
00408         }
00409         gtk_window_set_default_icon_list(icon_list);
00410         gtk_window_set_icon_list(top->w, icon_list);
00411 }
00412 
00413 static void message_view_free(void *elem)
00414 {
00415         message_view_t *view = elem;
00416         message_view_destroy(&view);
00417 }
00418 
00419 toplevel_t *toplevel_create(seaudit_t * s)
00420 {
00421         toplevel_t *top;
00422         GtkWidget *vbox;
00423         int error = 0;
00424 
00425         if ((top = calloc(1, sizeof(*top))) == NULL || (top->views = apol_vector_create(message_view_free)) == NULL) {
00426                 error = errno;
00427                 goto cleanup;
00428         }
00429         top->s = s;
00430         top->next_model_number = 1;
00431 
00432         if ((top->xml_filename = apol_file_find_path("seaudit.glade")) == NULL ||
00433             (top->xml = glade_xml_new(top->xml_filename, "TopLevel", NULL)) == NULL) {
00434                 fprintf(stderr, "Could not open seaudit.glade.\n");
00435                 error = EIO;
00436                 goto cleanup;
00437         }
00438         top->w = GTK_WINDOW(glade_xml_get_widget(top->xml, "TopLevel"));
00439         g_object_set_data(G_OBJECT(top->w), "toplevel", top);
00440         init_icons(top);
00441         top->notebook = GTK_NOTEBOOK(gtk_notebook_new());
00442         g_signal_connect_after(G_OBJECT(top->notebook), "switch-page", G_CALLBACK(toplevel_on_notebook_switch_page), top);
00443         vbox = glade_xml_get_widget(top->xml, "NotebookVBox");
00444         gtk_container_add(GTK_CONTAINER(vbox), GTK_WIDGET(top->notebook));
00445         gtk_widget_show(GTK_WIDGET(top->notebook));
00446         gtk_widget_show(GTK_WIDGET(top->w));
00447         toplevel_set_recent_logs_submenu(top);
00448         toplevel_set_recent_policies_submenu(top);
00449 
00450         glade_xml_signal_autoconnect(top->xml);
00451 
00452         /* create initial blank tab for the notebook */
00453         toplevel_add_new_model(top);
00454 
00455         /* initialize sub-windows, now that glade XML file has been
00456          * read */
00457         if ((top->pv = policy_view_create(top)) == NULL || (top->progress = progress_create(top)) == NULL) {
00458                 error = errno;
00459                 goto cleanup;
00460         }
00461       cleanup:
00462         if (error != 0) {
00463                 toplevel_destroy(&top);
00464                 errno = error;
00465                 return NULL;
00466         }
00467         return top;
00468 }
00469 
00470 void toplevel_destroy(toplevel_t ** top)
00471 {
00472         if (top != NULL && *top != NULL) {
00473                 if ((*top)->monitor_id > 0) {
00474                         g_source_remove((*top)->monitor_id);
00475                 }
00476                 policy_view_destroy(&(*top)->pv);
00477                 apol_vector_destroy(&(*top)->views);
00478                 free((*top)->xml_filename);
00479                 g_free((*top)->view_filename);
00480                 progress_destroy(&(*top)->progress);
00481                 if ((*top)->w != NULL) {
00482                         gtk_widget_destroy(GTK_WIDGET((*top)->w));
00483                 }
00484                 free(*top);
00485                 *top = NULL;
00486         }
00487 }
00488 
00489 struct log_run_datum
00490 {
00491         toplevel_t *top;
00492         FILE *file;
00493         const char *filename;
00494         seaudit_log_t *log;
00495         int result;
00496 };
00497 
00498 /**
00499  * Update the seaudit log, then refresh all views as necessary.  Note
00500  * that this only works in a single-threaded environment; otherwise
00501  * there are two possible race conditions:
00502  *   - monitor is disabled while this function is being executed
00503  *   - a new log file is loaded while the function is being executed
00504  *
00505  * But what happens if this function is scheduled and then a new log
00506  * is opened?  In toplevel_open_log(), do_monitor_log is temporarily
00507  * disabled because that function is threaded.  It is then re-enabled
00508  * afterwards.
00509  *
00510  * To make this function fully thread-safe requires making this entire
00511  * function synchronized, and then employ locking every time
00512  * do_monitor_log and monitor_id are set.
00513  */
00514 static gboolean toplevel_monitor_log_timer(gpointer data)
00515 {
00516         toplevel_t *top = (toplevel_t *) data;
00517         if (top->do_monitor_log) {
00518                 int retval;
00519                 gint i = gtk_notebook_get_n_pages(top->notebook) - 1;
00520                 uint delay;
00521                 retval = seaudit_parse_log(top->s);
00522                 if (retval < 0) {
00523                         GtkCheckMenuItem *w;
00524                         toplevel_ERR(top, "Error while monitoring log: %s", strerror(errno));
00525                         w = GTK_CHECK_MENU_ITEM(glade_xml_get_widget(top->xml, "MonitorLog"));
00526                         top->monitor_id = 0;
00527                         gtk_check_menu_item_set_active(w, 0);
00528                         return FALSE;
00529                 }
00530                 while (i >= 0) {
00531                         GtkWidget *child = gtk_notebook_get_nth_page(top->notebook, i);
00532                         GtkWidget *tab = gtk_notebook_get_tab_label(top->notebook, child);
00533                         message_view_t *v = g_object_get_data(G_OBJECT(tab), "view-object");
00534                         message_view_update_rows(v);
00535                         i--;
00536                 }
00537 
00538                 /* reschedule another timer callback */
00539                 delay = preferences_get_real_time_interval(toplevel_get_prefs(top));
00540                 top->monitor_id = g_timeout_add(delay, toplevel_monitor_log_timer, top);
00541         } else {
00542                 top->monitor_id = 0;
00543         }
00544         return FALSE;
00545 }
00546 
00547 /**
00548  * Enable or disable the log monitoring feature.  While enabled, the
00549  * log file will be periodically polled; new lines will be parsed and
00550  * inserted into the seaudit log object.  All models and their views
00551  * will then be notified of the changes.
00552  *
00553  * @param top Toplevel object whose widgets to update.
00554  */
00555 static void toplevel_monitor_log(toplevel_t * top)
00556 {
00557         GtkLabel *label = GTK_LABEL(glade_xml_get_widget(top->xml, "MonitorLogLabel"));
00558         assert(label != NULL);
00559         if (top->do_monitor_log) {
00560                 gtk_label_set_markup(label, "Monitor Status: <span foreground=\"green\">ON</span>");
00561                 if (top->monitor_id == 0) {
00562                         uint delay = preferences_get_real_time_interval(toplevel_get_prefs(top));
00563                         top->monitor_id = g_timeout_add(delay, toplevel_monitor_log_timer, top);
00564                 }
00565         } else {
00566                 if (top->monitor_id > 0) {
00567                         g_source_remove(top->monitor_id);
00568                         top->monitor_id = 0;
00569                 }
00570                 gtk_label_set_markup(label, "Monitor Status: <span foreground=\"red\">OFF</span>");
00571         }
00572 }
00573 
00574 /**
00575  * Thread that loads and parses a log file.  It will write to
00576  * progress_seaudit_handle_func() its status during the load.  Note
00577  * that the file handle is not closed upon completion; it is left open
00578  * so that subsequent calls to seaudit_log_parse(), such as
00579  * forreal-time monitoring.
00580  *
00581  * @param data Pointer to a struct log_run_datum, for control
00582  * information.
00583  */
00584 static gpointer toplevel_open_log_runner(gpointer data)
00585 {
00586         struct log_run_datum *run = (struct log_run_datum *)data;
00587         progress_update(run->top->progress, "Parsing %s", run->filename);
00588         if ((run->file = fopen(run->filename, "r")) == NULL) {
00589                 progress_update(run->top->progress, "Could not open %s for reading.", run->filename);
00590                 run->result = -1;
00591                 goto cleanup;
00592         }
00593         if ((run->log = seaudit_log_create(progress_seaudit_handle_func, run->top->progress)) == NULL) {
00594                 progress_update(run->top->progress, "%s", strerror(errno));
00595                 run->result = -1;
00596                 goto cleanup;
00597         }
00598         run->result = seaudit_log_parse(run->log, run->file);
00599       cleanup:
00600         if (run->result < 0) {
00601                 if (run->file != NULL) {
00602                         fclose(run->file);
00603                 }
00604                 run->file = NULL;
00605                 seaudit_log_destroy(&run->log);
00606                 progress_abort(run->top->progress, NULL);
00607         } else if (run->result > 0) {
00608                 progress_warn(run->top->progress, NULL);
00609         } else {
00610                 progress_done(run->top->progress);
00611         }
00612         return NULL;
00613 }
00614 
00615 /**
00616  * Destroy all views and their notebook tabs.
00617  */
00618 static void toplevel_destroy_views(toplevel_t * top)
00619 {
00620         gint num_pages = gtk_notebook_get_n_pages(top->notebook);
00621         while (num_pages >= 1) {
00622                 message_view_t *view = apol_vector_get_element(top->views, num_pages - 1);
00623                 gtk_notebook_remove_page(top->notebook, num_pages - 1);
00624                 message_view_destroy(&view);
00625                 apol_vector_remove(top->views, num_pages - 1);
00626                 num_pages--;
00627         }
00628 }
00629 
00630 void toplevel_open_log(toplevel_t * top, const char *filename)
00631 {
00632         struct log_run_datum run = { top, NULL, filename, NULL, 0 };
00633         int was_monitor_running;
00634         GtkCheckMenuItem *w;
00635 
00636         /* disable monitoring during the threaded part of this code */
00637         was_monitor_running = top->do_monitor_log;
00638         top->do_monitor_log = 0;
00639         toplevel_monitor_log(top);
00640 
00641         util_cursor_wait(GTK_WIDGET(top->w));
00642         progress_show(top->progress, "Opening Log");
00643         g_thread_create(toplevel_open_log_runner, &run, FALSE, NULL);
00644         progress_wait(top->progress);
00645         progress_hide(top->progress);
00646         util_cursor_clear(GTK_WIDGET(top->w));
00647 
00648         if (run.result < 0) {
00649                 top->do_monitor_log = was_monitor_running;
00650                 toplevel_monitor_log(top);
00651                 return;
00652         }
00653 
00654         toplevel_destroy_views(top);
00655         top->next_model_number = 1;
00656         seaudit_set_log(top->s, run.log, run.file, filename);
00657         toplevel_set_recent_logs_submenu(top);
00658         toplevel_enable_log_items(top, TRUE);
00659         toplevel_add_new_model(top);
00660         toplevel_update_title_bar(top);
00661         toplevel_update_status_bar(top);
00662         toplevel_update_selection_menu_item(top);
00663         top->do_monitor_log = preferences_get_real_time_at_startup(toplevel_get_prefs(top));
00664 
00665         w = GTK_CHECK_MENU_ITEM(glade_xml_get_widget(top->xml, "MonitorLog"));
00666 
00667         gtk_check_menu_item_set_active(w, top->do_monitor_log);
00668         /* call this again because the check item could have already
00669          * been active, thus its handler would not run */
00670         toplevel_monitor_log(top);
00671 }
00672 
00673 struct policy_run_datum
00674 {
00675         toplevel_t *top;
00676         apol_policy_path_t *path;
00677         apol_policy_t *policy;
00678         int result;
00679 };
00680 
00681 /**
00682  * Thread that loads and parses a policy file.  It will write to
00683  * progress_seaudit_handle_func() its status during the load.
00684  *
00685  * @param data Pointer to a struct policy_run_datum, for control
00686  * information.
00687  */
00688 static gpointer toplevel_open_policy_runner(gpointer data)
00689 {
00690         struct policy_run_datum *run = (struct policy_run_datum *)data;
00691         progress_update(run->top->progress, "Opening policy.");
00692         run->policy =
00693                 apol_policy_create_from_policy_path(run->path, QPOL_POLICY_OPTION_NO_NEVERALLOWS, progress_apol_handle_func,
00694                                                     run->top->progress);
00695         if (run->policy == NULL) {
00696                 run->result = -1;
00697                 progress_abort(run->top->progress, NULL);
00698                 return NULL;
00699         }
00700         run->result = 0;
00701         progress_done(run->top->progress);
00702         return NULL;
00703 }
00704 
00705 int toplevel_open_policy(toplevel_t * top, apol_policy_path_t * path)
00706 {
00707         struct policy_run_datum run = { top, path, NULL, 0 };
00708 
00709         util_cursor_wait(GTK_WIDGET(top->w));
00710         progress_show(top->progress, apol_policy_path_get_primary(path));
00711         g_thread_create(toplevel_open_policy_runner, &run, FALSE, NULL);
00712         progress_wait(top->progress);
00713         progress_hide(top->progress);
00714         util_cursor_clear(GTK_WIDGET(top->w));
00715         if (run.result < 0) {
00716                 apol_policy_path_destroy(&path);
00717                 return run.result;
00718         }
00719         seaudit_set_policy(top->s, run.policy, path);
00720         toplevel_set_recent_policies_submenu(top);
00721         toplevel_enable_policy_items(top, TRUE);
00722         toplevel_update_title_bar(top);
00723         toplevel_update_status_bar(top);
00724         policy_view_update(top->pv, path);
00725         return 0;
00726 }
00727 
00728 void toplevel_update_status_bar(toplevel_t * top)
00729 {
00730         apol_policy_t *policy = seaudit_get_policy(top->s);
00731         GtkLabel *policy_version = (GtkLabel *) glade_xml_get_widget(top->xml, "PolicyVersionLabel");
00732         GtkLabel *log_num = (GtkLabel *) glade_xml_get_widget(top->xml, "LogNumLabel");
00733         GtkLabel *log_dates = (GtkLabel *) glade_xml_get_widget(top->xml, "LogDateLabel");
00734         seaudit_log_t *log = toplevel_get_log(top);
00735 
00736         if (policy == NULL) {
00737                 gtk_label_set_text(policy_version, "Policy: No policy");
00738         } else {
00739                 char *policy_str = apol_policy_get_version_type_mls_str(policy);
00740                 if (policy_str == NULL) {
00741                         toplevel_ERR(top, "%s", strerror(errno));
00742                 } else {
00743                         char *s;
00744                         if (asprintf(&s, "Policy: %s", policy_str) < 0) {
00745                                 toplevel_ERR(top, "%s", strerror(errno));
00746                         } else {
00747                                 gtk_label_set_text(policy_version, s);
00748                                 free(s);
00749                         }
00750                         free(policy_str);
00751                 }
00752         }
00753 
00754         if (log == NULL) {
00755                 gtk_label_set_text(log_num, "Log Messages: No log");
00756                 gtk_label_set_text(log_dates, "Dates: No log");
00757         } else {
00758                 message_view_t *view = toplevel_get_current_view(top);
00759                 size_t num_messages = seaudit_get_num_log_messages(top->s);
00760                 size_t num_view_messages;
00761                 const struct tm *first = seaudit_get_log_first(top->s);
00762                 const struct tm *last = seaudit_get_log_last(top->s);
00763                 assert(view != NULL);
00764                 num_view_messages = message_view_get_num_log_messages(view);
00765                 char *s, t1[256], t2[256];
00766                 if (asprintf(&s, "Log Messages: %zd/%zd", num_view_messages, num_messages) < 0) {
00767                         toplevel_ERR(top, "%s", strerror(errno));
00768                 } else {
00769                         gtk_label_set_text(log_num, s);
00770                         free(s);
00771                 }
00772                 if (first == NULL || last == NULL) {
00773                         gtk_label_set_text(log_dates, "Dates: No messages");
00774                 } else {
00775                         strftime(t1, 256, "%b %d %H:%M:%S", first);
00776                         strftime(t2, 256, "%b %d %H:%M:%S", last);
00777                         if (asprintf(&s, "Dates: %s - %s", t1, t2) < 0) {
00778                                 toplevel_ERR(top, "%s", strerror(errno));
00779                         } else {
00780                                 gtk_label_set_text(log_dates, s);
00781                                 free(s);
00782                         }
00783                 }
00784         }
00785 }
00786 
00787 void toplevel_update_tabs(toplevel_t * top)
00788 {
00789         gint i = gtk_notebook_get_n_pages(top->notebook) - 1;
00790         while (i >= 0) {
00791                 GtkWidget *child = gtk_notebook_get_nth_page(top->notebook, i);
00792                 GtkWidget *tab = gtk_notebook_get_tab_label(top->notebook, child);
00793                 GtkWidget *label = g_object_get_data(G_OBJECT(tab), "label");
00794                 message_view_t *v = g_object_get_data(G_OBJECT(tab), "view-object");
00795                 seaudit_model_t *model = message_view_get_model(v);
00796                 const char *name = seaudit_model_get_name(model);
00797                 gtk_label_set_text(GTK_LABEL(label), name);
00798                 i--;
00799         }
00800 }
00801 
00802 void toplevel_update_selection_menu_item(toplevel_t * top)
00803 {
00804         static const char *items[] = {
00805                 "ExportSelected", "ViewMessage",
00806                 NULL
00807         };
00808         message_view_t *view = toplevel_get_current_view(top);
00809         gboolean sens = FALSE;
00810         size_t i;
00811         const char *s;
00812         if (view != NULL) {
00813                 sens = message_view_is_message_selected(view);
00814         }
00815         for (i = 0, s = items[0]; s != NULL; s = items[++i]) {
00816                 GtkWidget *w = glade_xml_get_widget(top->xml, s);
00817                 assert(s != NULL);
00818                 gtk_widget_set_sensitive(w, sens);
00819         }
00820 }
00821 
00822 preferences_t *toplevel_get_prefs(toplevel_t * top)
00823 {
00824         return seaudit_get_prefs(top->s);
00825 }
00826 
00827 seaudit_log_t *toplevel_get_log(toplevel_t * top)
00828 {
00829         return seaudit_get_log(top->s);
00830 }
00831 
00832 apol_vector_t *toplevel_get_log_users(toplevel_t * top)
00833 {
00834         return seaudit_get_log_users(top->s);
00835 }
00836 
00837 apol_vector_t *toplevel_get_log_roles(toplevel_t * top)
00838 {
00839         return seaudit_get_log_roles(top->s);
00840 }
00841 
00842 apol_vector_t *toplevel_get_log_types(toplevel_t * top)
00843 {
00844         return seaudit_get_log_types(top->s);
00845 }
00846 
00847 apol_vector_t *toplevel_get_log_classes(toplevel_t * top)
00848 {
00849         return seaudit_get_log_classes(top->s);
00850 }
00851 
00852 apol_policy_t *toplevel_get_policy(toplevel_t * top)
00853 {
00854         return seaudit_get_policy(top->s);
00855 }
00856 
00857 char *toplevel_get_glade_xml(toplevel_t * top)
00858 {
00859         return top->xml_filename;
00860 }
00861 
00862 progress_t *toplevel_get_progress(toplevel_t * top)
00863 {
00864         return top->progress;
00865 }
00866 
00867 GtkWindow *toplevel_get_window(toplevel_t * top)
00868 {
00869         return top->w;
00870 }
00871 
00872 void toplevel_find_terules(toplevel_t * top, seaudit_message_t * message)
00873 {
00874         policy_view_find_terules(top->pv, message);
00875 }
00876 
00877 /**
00878  * Pop-up a dialog with a line of text and wait for the user to
00879  * dismiss the dialog.
00880  *
00881  * @param top Toplevel window; this message dialog will be centered
00882  * upon it.
00883  * @param msg_type Type of message being displayed.
00884  * @param fmt Format string to print, using syntax of printf(3).
00885  */
00886 static void toplevel_message(toplevel_t * top, GtkMessageType msg_type, const char *fmt, va_list ap)
00887 {
00888         GtkWidget *dialog;
00889         char *msg;
00890         if (vasprintf(&msg, fmt, ap) < 0) {
00891                 ERR(NULL, "%s", strerror(errno));
00892                 return;
00893         }
00894         dialog = gtk_message_dialog_new(top->w, GTK_DIALOG_DESTROY_WITH_PARENT, msg_type, GTK_BUTTONS_CLOSE, msg);
00895         free(msg);
00896         gtk_dialog_run(GTK_DIALOG(dialog));
00897         gtk_widget_destroy(dialog);
00898 }
00899 
00900 void toplevel_ERR(toplevel_t * top, const char *format, ...)
00901 {
00902         va_list(ap);
00903         va_start(ap, format);
00904         toplevel_message(top, GTK_MESSAGE_ERROR, format, ap);
00905         va_end(ap);
00906 }
00907 
00908 void toplevel_WARN(toplevel_t * top, const char *format, ...)
00909 {
00910         va_list(ap);
00911         va_start(ap, format);
00912         toplevel_message(top, GTK_MESSAGE_WARNING, format, ap);
00913         va_end(ap);
00914 }
00915 
00916 /************* below are callbacks for the toplevel menu items *************/
00917 
00918 void toplevel_on_destroy(gpointer user_data, GtkObject * object __attribute__ ((unused)))
00919 {
00920         toplevel_t *top = g_object_get_data(G_OBJECT(user_data), "toplevel");
00921         top->w = NULL;
00922         gtk_main_quit();
00923 }
00924 
00925 void toplevel_on_open_log_activate(gpointer user_data, GtkWidget * widget __attribute__ ((unused)))
00926 {
00927         toplevel_t *top = g_object_get_data(G_OBJECT(user_data), "toplevel");
00928         apol_vector_t *paths = util_open_file(top->w, "Open Log", seaudit_get_log_path(top->s), 0);
00929         if (paths != NULL) {
00930                 toplevel_open_log(top, apol_vector_get_element(paths, 0));
00931                 apol_vector_destroy(&paths);
00932         }
00933 }
00934 
00935 void toplevel_on_open_policy_activate(gpointer user_data, GtkWidget * widget __attribute__ ((unused)))
00936 {
00937         toplevel_t *top = g_object_get_data(G_OBJECT(user_data), "toplevel");
00938         open_policy_window_run(top, seaudit_get_policy_path(top->s), NULL);
00939 }
00940 
00941 void toplevel_on_preferences_activate(gpointer user_data, GtkWidget * widget __attribute__ ((unused)))
00942 {
00943         toplevel_t *top = g_object_get_data(G_OBJECT(user_data), "toplevel");
00944         if (preferences_view_run(top, seaudit_get_log_path(top->s), seaudit_get_policy_path(top->s))) {
00945                 size_t i;
00946                 for (i = 0; i < apol_vector_get_size(top->views); i++) {
00947                         message_view_t *v = apol_vector_get_element(top->views, i);
00948                         message_view_update_visible_columns(v);
00949                 }
00950         }
00951 }
00952 
00953 void toplevel_on_quit_activate(gpointer user_data, GtkWidget * widget __attribute__ ((unused)))
00954 {
00955         toplevel_t *top = g_object_get_data(G_OBJECT(user_data), "toplevel");
00956         top->w = NULL;
00957         gtk_main_quit();
00958 }
00959 
00960 void toplevel_on_new_view_activate(gpointer user_data, GtkWidget * widget __attribute__ ((unused)))
00961 {
00962         toplevel_t *top = g_object_get_data(G_OBJECT(user_data), "toplevel");
00963         toplevel_add_new_model(top);
00964 }
00965 
00966 void toplevel_on_open_view_activate(gpointer user_data, GtkWidget * widget __attribute__ ((unused)))
00967 {
00968         toplevel_t *top = g_object_get_data(G_OBJECT(user_data), "toplevel");
00969         apol_vector_t *paths = util_open_file(top->w, "Open View", top->view_filename, 0);
00970         seaudit_model_t *model = NULL;
00971         if (paths == NULL) {
00972                 return;
00973         }
00974         free(top->view_filename);
00975         top->view_filename = strdup(apol_vector_get_element(paths, 0));
00976         apol_vector_destroy(&paths);
00977         if (top->view_filename == NULL ||
00978             (model = seaudit_model_create_from_file(top->view_filename)) == NULL ||
00979             seaudit_model_append_log(model, seaudit_get_log(top->s)) < 0) {
00980                 toplevel_ERR(top, "Error opening view: %s", strerror(errno));
00981                 seaudit_model_destroy(&model);
00982         } else {
00983                 toplevel_add_new_view(top, model, top->view_filename);
00984         }
00985 }
00986 
00987 void toplevel_on_save_view_activate(gpointer user_data, GtkWidget * widget __attribute__ ((unused)))
00988 {
00989         toplevel_t *top = g_object_get_data(G_OBJECT(user_data), "toplevel");
00990         message_view_t *view = toplevel_get_current_view(top);
00991         assert(view != NULL);
00992         message_view_save(view);
00993 }
00994 
00995 void toplevel_on_save_viewas_activate(gpointer user_data, GtkWidget * widget __attribute__ ((unused)))
00996 {
00997         toplevel_t *top = g_object_get_data(G_OBJECT(user_data), "toplevel");
00998         message_view_t *view = toplevel_get_current_view(top);
00999         assert(view != NULL);
01000         message_view_saveas(view);
01001 }
01002 
01003 void toplevel_on_modify_view_activate(gpointer user_data, GtkWidget * widget __attribute__ ((unused)))
01004 {
01005         toplevel_t *top = g_object_get_data(G_OBJECT(user_data), "toplevel");
01006         message_view_t *view = toplevel_get_current_view(top);
01007         assert(view != NULL);
01008         message_view_modify(view);
01009 }
01010 
01011 void toplevel_on_export_all_messages_activate(gpointer user_data, GtkWidget * widget __attribute__ ((unused)))
01012 {
01013         toplevel_t *top = g_object_get_data(G_OBJECT(user_data), "toplevel");
01014         message_view_t *view = toplevel_get_current_view(top);
01015         assert(view != NULL);
01016         message_view_export_all_messages(view);
01017 }
01018 
01019 void toplevel_on_export_selected_messages_activate(gpointer user_data, GtkWidget * widget __attribute__ ((unused)))
01020 {
01021         toplevel_t *top = g_object_get_data(G_OBJECT(user_data), "toplevel");
01022         message_view_t *view = toplevel_get_current_view(top);
01023         assert(view != NULL);
01024         message_view_export_selected_messages(view);
01025 }
01026 
01027 void toplevel_on_view_entire_message_activate(gpointer user_data, GtkWidget * widget __attribute__ ((unused)))
01028 {
01029         toplevel_t *top = g_object_get_data(G_OBJECT(user_data), "toplevel");
01030         message_view_t *view = toplevel_get_current_view(top);
01031         assert(view != NULL);
01032         message_view_entire_message(view);
01033 }
01034 
01035 void toplevel_on_find_terules_activate(gpointer user_data, GtkWidget * widget __attribute__ ((unused)))
01036 {
01037         toplevel_t *top = g_object_get_data(G_OBJECT(user_data), "toplevel");
01038         toplevel_find_terules(top, NULL);
01039 }
01040 
01041 void toplevel_on_create_report_activate(gpointer user_data, GtkMenuItem * widget __attribute__ ((unused)))
01042 {
01043         toplevel_t *top = g_object_get_data(G_OBJECT(user_data), "toplevel");
01044         message_view_t *view = toplevel_get_current_view(top);
01045         assert(view != NULL);
01046         report_window_run(top, view);
01047 }
01048 
01049 void toplevel_on_monitor_log_activate(gpointer user_data, GtkMenuItem * widget)
01050 {
01051         toplevel_t *top = g_object_get_data(G_OBJECT(user_data), "toplevel");
01052         if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget))) {
01053                 top->do_monitor_log = 1;
01054         } else {
01055                 top->do_monitor_log = 0;
01056         }
01057         toplevel_monitor_log(top);
01058 }
01059 
01060 void toplevel_on_clear_view_activate(gpointer user_data, GtkMenuItem * widget __attribute__ ((unused)))
01061 {
01062         toplevel_t *top = g_object_get_data(G_OBJECT(user_data), "toplevel");
01063         message_view_t *view = toplevel_get_current_view(top);
01064         assert(view != NULL);
01065         message_view_clear(view);
01066 }
01067 
01068 void toplevel_on_help_activate(gpointer user_data, GtkMenuItem * widget __attribute__ ((unused)))
01069 {
01070         toplevel_t *top = g_object_get_data(G_OBJECT(user_data), "toplevel");
01071         GtkWidget *window;
01072         GtkWidget *scroll;
01073         GtkWidget *text_view;
01074         GtkTextBuffer *buffer;
01075         char *help_text = NULL;
01076         size_t len;
01077         int rt;
01078         char *dir;
01079 
01080         window = gtk_dialog_new_with_buttons("seaudit Help",
01081                                              GTK_WINDOW(top->w),
01082                                              GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, NULL);
01083         gtk_dialog_set_default_response(GTK_DIALOG(window), GTK_RESPONSE_CLOSE);
01084         g_signal_connect_swapped(window, "response", G_CALLBACK(gtk_widget_destroy), window);
01085         scroll = gtk_scrolled_window_new(NULL, NULL);
01086         text_view = gtk_text_view_new();
01087         gtk_window_set_default_size(GTK_WINDOW(window), 520, 300);
01088         gtk_container_add(GTK_CONTAINER(GTK_DIALOG(window)->vbox), scroll);
01089         gtk_container_add(GTK_CONTAINER(scroll), text_view);
01090         gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(text_view), GTK_WRAP_NONE);
01091         buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_view));
01092         dir = apol_file_find_path("seaudit_help.txt");
01093         if (!dir) {
01094                 toplevel_ERR(top, "Cannot find help file.");
01095                 return;
01096         }
01097         rt = apol_file_read_to_buffer(dir, &help_text, &len);
01098         free(dir);
01099         if (rt != 0) {
01100                 free(help_text);
01101                 return;
01102         }
01103         gtk_text_buffer_set_text(buffer, help_text, len);
01104         gtk_text_view_set_editable(GTK_TEXT_VIEW(text_view), FALSE);
01105         gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER_ON_PARENT);
01106         gtk_widget_show(text_view);
01107         gtk_widget_show(scroll);
01108         gtk_widget_show(window);
01109 }
01110 
01111 void toplevel_on_about_seaudit_activate(gpointer user_data, GtkMenuItem * widget __attribute__ ((unused)))
01112 {
01113         toplevel_t *top = g_object_get_data(G_OBJECT(user_data), "toplevel");
01114 #ifdef GTK_2_8
01115         gtk_show_about_dialog(top->w,
01116                               "comments", "Audit Log Analysis Tool for Security Enhanced Linux",
01117                               "copyright", COPYRIGHT_INFO,
01118                               "name", "seaudit", "version", VERSION, "website", "http://oss.tresys.com/projects/setools", NULL);
01119 #else
01120         GtkWidget *w = gtk_message_dialog_new(top->w,
01121                                               GTK_DIALOG_DESTROY_WITH_PARENT,
01122                                               GTK_MESSAGE_INFO,
01123                                               GTK_BUTTONS_CLOSE,
01124                                               "%s %s\n%s\n%s\n%s",
01125                                               "seaudit", VERSION,
01126                                               "Audit Log Analysis Tool for Security Enhanced Linux",
01127                                               COPYRIGHT_INFO,
01128                                               "http://oss.tresys.com/projects/setools");
01129         gtk_dialog_run(GTK_DIALOG(w));
01130         gtk_widget_destroy(w);
01131 #endif
01132 }
01133 
01134 void toplevel_on_find_terules_click(gpointer user_data, GtkWidget * widget __attribute__ ((unused)), GdkEvent * event
01135                                     __attribute__ ((unused)))
01136 {
01137         toplevel_t *top = g_object_get_data(G_OBJECT(user_data), "toplevel");
01138         toplevel_find_terules(top, NULL);
01139 }
01140 
01141 void toplevel_on_modify_view_click(gpointer user_data, GtkWidget * widget __attribute__ ((unused)), GdkEvent * event
01142                                    __attribute__ ((unused)))
01143 {
01144         toplevel_t *top = g_object_get_data(G_OBJECT(user_data), "toplevel");
01145         message_view_t *view = toplevel_get_current_view(top);
01146         assert(view != NULL);
01147         message_view_modify(view);
01148 }
01149 
01150 void toplevel_on_monitor_log_click(gpointer user_data, GtkWidget * widget __attribute__ ((unused)), GdkEvent * event
01151                                    __attribute__ ((unused)))
01152 {
01153         toplevel_t *top = g_object_get_data(G_OBJECT(user_data), "toplevel");
01154         GtkCheckMenuItem *w = GTK_CHECK_MENU_ITEM(glade_xml_get_widget(top->xml, "MonitorLog"));
01155         gboolean old_state;
01156         assert(w != NULL);
01157         old_state = gtk_check_menu_item_get_active(w);
01158         gtk_check_menu_item_set_active(w, !old_state);
01159 }
01160 
01161 void toplevel_on_clear_view_click(gpointer user_data, GtkWidget * widget __attribute__ ((unused)), GdkEvent * event
01162                                   __attribute__ ((unused)))
01163 {
01164         toplevel_t *top = g_object_get_data(G_OBJECT(user_data), "toplevel");
01165         message_view_t *view = toplevel_get_current_view(top);
01166         assert(view != NULL);
01167         message_view_clear(view);
01168 }