aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--file.c11
-rw-r--r--gtk/main.c187
-rw-r--r--gtk/main.h8
-rw-r--r--gtk/menu.c137
-rw-r--r--gtk/menu.h5
-rw-r--r--menu.h7
6 files changed, 349 insertions, 6 deletions
diff --git a/file.c b/file.c
index 678ca11f97..9aadbe9ddd 100644
--- a/file.c
+++ b/file.c
@@ -1,7 +1,7 @@
/* file.c
* File I/O routines
*
- * $Id: file.c,v 1.329 2003/12/09 22:41:06 ulfl Exp $
+ * $Id: file.c,v 1.330 2003/12/13 18:01:29 ulfl Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
@@ -297,6 +297,12 @@ set_display_filename(capture_file *cf)
gchar *win_name;
name_ptr = cf_get_display_name(cf);
+
+ if (!cf->is_tempfile) {
+ /* Add this filename to the list of recent files in the "Recent Files" submenu */
+ add_menu_recent_capture_file(cf->filename);
+ }
+
if (cf->drops_known) {
msg_len = strlen(name_ptr) + strlen(done_fmt_drops) + 64;
done_msg = g_malloc(msg_len);
@@ -640,6 +646,9 @@ cf_get_display_name(capture_file *cf)
/* Get the last component of the file name, and use that. */
if (cf->filename){
displayname = get_basename(cf->filename);
+
+ /* Add this filename to the list of recent files in the "Recent Files" submenu */
+ add_menu_recent_capture_file(cf->filename);
} else {
displayname="<no file>";
}
diff --git a/gtk/main.c b/gtk/main.c
index b9aec0214c..1b00978696 100644
--- a/gtk/main.c
+++ b/gtk/main.c
@@ -1,6 +1,6 @@
/* main.c
*
- * $Id: main.c,v 1.340 2003/12/13 16:30:10 ulfl Exp $
+ * $Id: main.c,v 1.341 2003/12/13 18:01:30 ulfl Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
@@ -111,6 +111,7 @@
#include "colors.h"
#include <epan/strutil.h>
#include "register.h"
+#include <prefs-int.h>
#include "ringbuffer.h"
#include "ui_util.h"
#include "toolbar.h"
@@ -606,6 +607,177 @@ prepare_selected_cb_or_plist_not(GtkWidget *w _U_, gpointer data)
get_text_from_packet_list(data));
}
+
+#define RECENT_FILE_NAME "recent"
+
+
+/* Write out "recent" to the user's recent file, and return 0.
+ If we got an error, stuff a pointer to the path of the recent file
+ into "*pf_path_return", and return the errno. */
+int
+write_recent(char **rf_path_return)
+{
+ char *rf_path;
+ FILE *rf;
+
+ /* To do:
+ * - Split output lines longer than MAX_VAL_LEN
+ * - Create a function for the preference directory check/creation
+ * so that duplication can be avoided with filter.c
+ */
+
+ rf_path = get_persconffile_path(RECENT_FILE_NAME, TRUE);
+ if ((rf = fopen(rf_path, "w")) == NULL) {
+ *rf_path_return = rf_path;
+ return errno;
+ }
+
+ fputs("# Recent settings file for Ethereal " VERSION ".\n"
+ "#\n"
+ "# This file is regenerated each time Ethereal is quit.\n"
+ "# So be careful, if you want to make manual changes here.\n"
+ "\n"
+ "######## Recent capture files (latest first) ########\n"
+ "\n", rf);
+
+ menu_recent_file_write_all(rf);
+
+ fputs("\n"
+ "######## Recent display filters (latest last) ########\n"
+ "\n", rf);
+
+ dfilter_combo_write_all(rf);
+
+ fclose(rf);
+
+ /* XXX - catch I/O errors (e.g. "ran out of disk space") and return
+ an error indication, or maybe write to a new preferences file and
+ rename that file on top of the old one only if there are not I/O
+ errors. */
+ return 0;
+}
+
+
+/* set one user's recent file key/value pair */
+static int
+set_recent_pair(gchar *key, gchar *value)
+{
+
+
+ if (strcmp(key, RECENT_KEY_CAPTURE_FILE) == 0) {
+ add_menu_recent_capture_file(value);
+ } else if (strcmp(key, RECENT_KEY_DISPLAY_FILTER) == 0) {
+ dfilter_combo_add_recent(value);
+ }
+
+ return PREFS_SET_OK;
+}
+
+
+/* opens the user's recent file and read it out */
+void
+read_recent(char **rf_path_return, int *rf_errno_return)
+{
+ char *rf_path;
+ FILE *rf;
+
+
+ /* Construct the pathname of the user's recent file. */
+ rf_path = get_persconffile_path(RECENT_FILE_NAME, FALSE);
+
+ /* Read the user's recent file, if it exists. */
+ *rf_path_return = NULL;
+ if ((rf = fopen(rf_path, "r")) != NULL) {
+ /* We succeeded in opening it; read it. */
+ read_prefs_file(rf_path, rf, set_recent_pair);
+ /* set dfilter combobox to have one empty line at the current position */
+ dfilter_combo_add_recent("");
+ fclose(rf);
+ g_free(rf_path);
+ rf_path = NULL;
+ } else {
+ /* We failed to open it. If we failed for some reason other than
+ "it doesn't exist", return the errno and the pathname, so our
+ caller can report the error. */
+ if (errno != ENOENT) {
+ *rf_errno_return = errno;
+ *rf_path_return = rf_path;
+ }
+ }
+}
+
+
+
+static guint dfilter_combo_max_recent = 10;
+
+/* add a display filter to the combo box */
+/* Note: a new filter string will replace an old identical one */
+static gboolean
+dfilter_combo_add(GtkWidget *filter_cm, char *s) {
+ GList *li;
+ GList *filter_list = gtk_object_get_data(GTK_OBJECT(filter_cm), E_DFILTER_FL_KEY);
+
+
+ /* GtkCombos don't let us get at their list contents easily, so we maintain
+ our own filter list, and feed it to gtk_combo_set_popdown_strings when
+ a new filter is added. */
+ li = g_list_first(filter_list);
+ while (li) {
+ /* If the filter is already in the list, remove the old one and
+ * append the new one at the latest position (at g_list_append() below) */
+ if (li->data && strcmp(s, li->data) == 0) {
+ filter_list = g_list_remove(filter_list, li->data);
+ break;
+ }
+ li = li->next;
+ }
+
+ filter_list = g_list_append(filter_list, s);
+ gtk_object_set_data(GTK_OBJECT(filter_cm), E_DFILTER_FL_KEY, filter_list);
+ gtk_combo_set_popdown_strings(GTK_COMBO(filter_cm), filter_list);
+ gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(filter_cm)->entry), g_list_last(filter_list)->data);
+
+ return TRUE;
+}
+
+
+/* write all non empty display filters (until maximum count)
+ * of the combo box GList to the user's recent file */
+void
+dfilter_combo_write_all(FILE *rf) {
+ GtkWidget *filter_cm = OBJECT_GET_DATA(top_level, E_DFILTER_CM_KEY);
+ GList *filter_list = gtk_object_get_data(GTK_OBJECT(filter_cm), E_DFILTER_FL_KEY);
+ GList *li;
+ gint max_count = 0;
+
+
+ /* write all non empty display filter strings to the recent file (until max count) */
+ li = g_list_first(filter_list);
+ while ( li && (max_count++ <= dfilter_combo_max_recent) ) {
+ if (strlen(li->data)) {
+ fprintf (rf, RECENT_KEY_DISPLAY_FILTER ": %s\n", li->data);
+ }
+ li = li->next;
+ }
+}
+
+
+/* add a display filter coming from the user's recent file to the dfilter combo box */
+gboolean
+dfilter_combo_add_recent(gchar *s) {
+ GtkWidget *filter_cm = OBJECT_GET_DATA(top_level, E_DFILTER_CM_KEY);
+ char *dup;
+
+ dup = g_strdup(s);
+ if (!dfilter_combo_add(filter_cm, dup)) {
+ g_free(dup);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
/* Run the current display filter on the current packet set, and
redisplay. */
static void
@@ -1181,6 +1353,13 @@ statusbar_pop_field_msg(void)
static gboolean
do_quit(void)
{
+ gchar *rec_path;
+
+
+ /* write user's recent file to disk
+ * It is no problem to write this file, even if we do not quit */
+ write_recent(&rec_path);
+
/* XXX - should we check whether the capture file is an
unsaved temporary file for a live capture and, if so,
pop up a "do you want to exit without saving the capture
@@ -1575,6 +1754,8 @@ main(int argc, char *argv[])
WSADATA wsaData;
#endif /* WIN32 */
+ char *rf_path;
+ int rf_open_errno;
char *gpf_path, *pf_path;
char *cf_path, *df_path, *dp_path;
int gpf_open_errno, gpf_read_errno;
@@ -2394,6 +2575,9 @@ main(int argc, char *argv[])
we were told to. */
create_main_window(pl_size, tv_size, bv_size, prefs);
+ /* Read the recent file, as we have the gui now ready for it. */
+ read_recent(&rf_path, &rf_open_errno);
+
colors_init();
colfilter_init();
@@ -3000,6 +3184,7 @@ create_main_window (gint pl_size, gint tv_size, gint bv_size, e_prefs *prefs)
main_display_filter_widget=filter_te;
OBJECT_SET_DATA(filter_bt, E_FILT_TE_PTR_KEY, filter_te);
OBJECT_SET_DATA(filter_te, E_DFILTER_CM_KEY, filter_cm);
+ OBJECT_SET_DATA(top_level, E_DFILTER_CM_KEY, filter_cm);
gtk_box_pack_start(GTK_BOX(stat_hbox), filter_cm, TRUE, TRUE, 3);
SIGNAL_CONNECT(filter_te, "activate", filter_activate_cb, filter_te);
gtk_widget_show(filter_cm);
diff --git a/gtk/main.h b/gtk/main.h
index 5d20f1099a..8a96ecfe21 100644
--- a/gtk/main.h
+++ b/gtk/main.h
@@ -1,7 +1,7 @@
/* main.h
* Global defines, etc.
*
- * $Id: main.h,v 1.33 2003/12/09 22:41:07 ulfl Exp $
+ * $Id: main.h,v 1.34 2003/12/13 18:01:30 ulfl Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
@@ -100,6 +100,12 @@ void mark_all_frames_cb(GtkWidget *w, gpointer);
void unmark_all_frames_cb(GtkWidget *w, gpointer);
void update_marked_frames(void);
+#define RECENT_KEY_CAPTURE_FILE "recent.capture_file"
+#define RECENT_KEY_DISPLAY_FILTER "recent.display_filter"
+
+gboolean dfilter_combo_add_recent(gchar *s);
+void dfilter_combo_write_all(FILE *rf);
+
char *boldify(const char *);
#if GTK_MAJOR_VERSION < 2
void set_fonts(GdkFont *regular, GdkFont *bold);
diff --git a/gtk/menu.c b/gtk/menu.c
index 2e03715487..64c02f1ea8 100644
--- a/gtk/menu.c
+++ b/gtk/menu.c
@@ -1,7 +1,7 @@
/* menu.c
* Menu routines
*
- * $Id: menu.c,v 1.123 2003/12/09 22:41:07 ulfl Exp $
+ * $Id: menu.c,v 1.124 2003/12/13 18:01:30 ulfl Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
@@ -29,6 +29,7 @@
#include <gtk/gtk.h>
#include <string.h>
+#include <stdio.h>
#include "main.h"
#include "menu.h"
@@ -106,6 +107,7 @@ static GtkItemFactoryEntry menu_items[] =
ITEM_FACTORY_ENTRY("/_File", NULL, NULL, 0, "<Branch>", NULL),
ITEM_FACTORY_STOCK_ENTRY("/File/_Open...", "<control>O", file_open_cmd_cb,
0, GTK_STOCK_OPEN),
+ ITEM_FACTORY_ENTRY("/File/Open _Recent", NULL, NULL, 0, "<Branch>", NULL),
ITEM_FACTORY_STOCK_ENTRY("/File/_Close", "<control>W", file_close_cmd_cb,
0, GTK_STOCK_CLOSE),
ITEM_FACTORY_ENTRY("/File/<separator>", NULL, NULL, 0, "<Separator>", NULL),
@@ -659,6 +661,139 @@ set_menu_object_data (gchar *path, gchar *key, gpointer data) {
}
}
+
+/* Recently used capture files submenu:
+ * Submenu containing the recently used capture files.
+ * The capture filenames are always kept with the absolute path, to be independant
+ * of the current path.
+ * They are only stored inside the labels of the submenu (no separate list). */
+
+/* the maximum number of entries in the recent capture files list */
+static guint recent_files_count_max = 10;
+
+#define MENU_RECENT_FILES_PATH "/File/Open Recent"
+
+/* callback, if the user pushed a recent file submenu item */
+void
+menu_open_recent_file_cmd_cb(GtkWidget *w, gpointer data _U_)
+{
+ int err;
+ GtkWidget *menu_item_child;
+ gchar *cf_name;
+
+
+ /* get capture filename from the menu item label */
+ menu_item_child = (GTK_BIN(w))->child;
+ gtk_label_get(GTK_LABEL(menu_item_child), &cf_name);
+
+ /* open and read the capture file (this will close an existing file) */
+ if ((err = cf_open(cf_name, FALSE, &cfile)) == 0) {
+ cf_read(&cfile, &err);
+ }
+}
+
+
+/* add the capture filename (with an absolute path) to the "Recent Files" menu */
+void
+add_menu_recent_capture_file_absolute(gchar *cf_name) {
+ GtkWidget *submenu_recent_files;
+ GList *menu_item_list;
+ GList *li;
+ gchar *widget_cf_name;
+ GtkWidget *menu_item;
+ guint cnt;
+
+
+ /* get the submenu container item */
+ submenu_recent_files = gtk_item_factory_get_widget(main_menu_factory, MENU_RECENT_FILES_PATH);
+
+ /* convert container to a GList */
+ menu_item_list = gtk_container_children(GTK_CONTAINER(submenu_recent_files));
+
+ /* iterate through list items of menu_item_list,
+ * removing a maybe duplicate entry and every item above count_max */
+ li = g_list_first(menu_item_list);
+ for (cnt = 1; li; li = li->next, cnt++) {
+ /* get capture filename from the menu item label */
+ menu_item = (GtkWidget *) li->data;
+ gtk_label_get(GTK_LABEL(GTK_BIN(menu_item)->child), &widget_cf_name);
+
+ /* if this element string is already in the list, or
+ * this element is above maximum count (too old), remove it */
+ if (strncmp(widget_cf_name, cf_name, 1000) == 0 ||
+ cnt >= recent_files_count_max) {
+ /* XXX: is this all we need to do, to destroy the menu item and its label? */
+ gtk_container_remove(GTK_CONTAINER(submenu_recent_files), li->data);
+ gtk_widget_destroy(li->data);
+ cnt--;
+ }
+ }
+
+ g_list_free(menu_item_list);
+
+ /* add new item at latest position */
+ menu_item = gtk_menu_item_new_with_label(cf_name);
+ gtk_menu_prepend (GTK_MENU(submenu_recent_files), menu_item);
+
+ gtk_signal_connect_object(GTK_OBJECT(menu_item), "activate",
+ menu_open_recent_file_cmd_cb, (GtkObject *) menu_item);
+ gtk_widget_show (menu_item);
+}
+
+
+/* add the capture filename to the "Recent Files" menu */
+/* (will change nothing, if this filename is already in the menu) */
+void
+add_menu_recent_capture_file(gchar *cf_name) {
+ gchar *curr;
+ gchar *absolute;
+
+
+ /* if this filename is an absolute path, we can use it directly */
+ if (g_path_is_absolute(cf_name)) {
+ add_menu_recent_capture_file_absolute(cf_name);
+ return;
+ }
+
+ /* this filename is not an absolute path, prepend the current dir */
+ curr = g_get_current_dir();
+ absolute = g_strdup_printf("%s%s%s", curr, G_DIR_SEPARATOR_S, cf_name);
+ add_menu_recent_capture_file_absolute(absolute);
+ g_free(curr);
+ g_free(absolute);
+}
+
+
+
+/* write a single menu item widget label to the user's recent file */
+/* helper, for menu_recent_file_write_all() */
+void menu_recent_file_write(GtkWidget *widget, gpointer data) {
+ GtkWidget *menu_item_child;
+ gchar *cf_name;
+ FILE *rf = (FILE *) data;
+
+
+ /* get capture filename from the menu item label */
+ menu_item_child = (GTK_BIN(widget))->child;
+ gtk_label_get(GTK_LABEL(menu_item_child), &cf_name);
+
+ fprintf (rf, RECENT_KEY_CAPTURE_FILE ": %s\n", cf_name);
+}
+
+
+/* write all capture filenames of the menu to the user's recent file */
+void
+menu_recent_file_write_all(FILE *rf) {
+ GtkWidget *submenu_recent_files;
+
+
+ submenu_recent_files = gtk_item_factory_get_widget(main_menu_factory, MENU_RECENT_FILES_PATH);
+
+ gtk_container_foreach(GTK_CONTAINER(submenu_recent_files),
+ menu_recent_file_write, rf);
+}
+
+
gint
popup_menu_handler(GtkWidget *widget, GdkEvent *event, gpointer data)
{
diff --git a/gtk/menu.h b/gtk/menu.h
index 6bef198aa5..a215f9d9bc 100644
--- a/gtk/menu.h
+++ b/gtk/menu.h
@@ -1,7 +1,7 @@
/* menu.h
* Menu definitions
*
- * $Id: menu.h,v 1.11 2003/09/24 02:36:35 guy Exp $
+ * $Id: menu.h,v 1.12 2003/12/13 18:01:30 ulfl Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
@@ -29,6 +29,9 @@
extern "C" {
#endif /* __cplusplus */
+/* Write all recent capture filenames to the user's recent file */
+void menu_recent_file_write_all(FILE *rf);
+
void get_main_menu (GtkWidget **, GtkAccelGroup **);
void set_menu_object_data (gchar *path, gchar *key, gpointer data);
gint popup_menu_handler(GtkWidget *widget, GdkEvent *event, gpointer data);
diff --git a/menu.h b/menu.h
index 27fd1ddaf7..9ee8247ea5 100644
--- a/menu.h
+++ b/menu.h
@@ -2,7 +2,7 @@
* Definitions for menu routines with toolkit-independent APIs but
* toolkit-dependent implementations.
*
- * $Id: menu.h,v 1.11 2003/09/24 02:36:33 guy Exp $
+ * $Id: menu.h,v 1.12 2003/12/13 18:01:29 ulfl Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
@@ -30,6 +30,11 @@
extern "C" {
#endif /* __cplusplus */
+
+/* Add a new recent capture filename to the "Recent Files" submenu
+ (duplicates will be ignored) */
+void add_menu_recent_capture_file(gchar *file);
+
/* Routines to enable or disable sets of menu items. */
/* Enable or disable menu items based on whether you have a capture file