replace *a lot* of file related calls by their GLib counterparts. This is necessary...
[obnox/wireshark/wip.git] / gtk / recent.c
index bf81510cd2d72ecb55aacc46929ab0399c88b5be..7e7c09ef6dd790ab9f212f560e95ff01cdf89e38 100644 (file)
@@ -2,7 +2,7 @@
  * Recent "preference" handling routines
  * Copyright 2004, Ulf Lamping <ulf.lamping@web.de>
  *
- * $Id: recent.c,v 1.17 2004/06/01 17:33:37 ulfl Exp $
+ * $Id$
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@ethereal.com>
 #include <gtk/gtk.h>
 #include <stdio.h>
 #include <string.h>
+#include <ctype.h>
 
 #include "recent.h"
 #include <epan/epan.h>
 #include <epan/filesystem.h>
 #include "menu.h"
 #include "main.h"
-#include "prefs.h"
-#include "prefs-int.h"
-#include "ui_util.h"
+#include <epan/prefs.h>
+#include <epan/prefs-int.h>
+#include "gui_utils.h"
 #include "dlg_utils.h"
-
+#include "cfilter_combo_utils.h"
+#include "simple_dialog.h"
+#include "file_util.h"
 
 #define RECENT_KEY_MAIN_TOOLBAR_SHOW        "gui.toolbar_main_show"
 #define RECENT_KEY_FILTER_TOOLBAR_SHOW      "gui.filter_toolbar_show"
@@ -48,7 +51,9 @@
 #define RECENT_KEY_TREE_VIEW_SHOW           "gui.tree_view_show"
 #define RECENT_KEY_BYTE_VIEW_SHOW           "gui.byte_view_show"
 #define RECENT_KEY_STATUSBAR_SHOW           "gui.statusbar_show"
+#define RECENT_KEY_PACKET_LIST_COLORIZE     "gui.packet_list_colorize"
 #define RECENT_GUI_TIME_FORMAT              "gui.time_format"
+#define RECENT_GUI_TIME_PRECISION           "gui.time_precision"
 #define RECENT_GUI_ZOOM_LEVEL               "gui.zoom_level"
 #define RECENT_GUI_GEOMETRY_MAIN_X          "gui.geometry_main_x"
 #define RECENT_GUI_GEOMETRY_MAIN_Y          "gui.geometry_main_y"
 
 #define RECENT_FILE_NAME "recent"
 
-
-/* #include "../menu.h" */
-extern void add_menu_recent_capture_file(gchar *file);
-
 recent_settings_t recent;
 
-static char *ts_type_text[] =
+static const char *ts_type_text[] =
        { "RELATIVE", "ABSOLUTE", "ABSOLUTE_WITH_DATE", "DELTA", NULL };
 
+static const char *ts_precision_text[] =
+       { "AUTO", "SEC", "DSEC", "CSEC", "MSEC", "USEC", "NSEC", NULL };
+
 /* Takes an string and a pointer to an array of strings, and a default int value.
  * The array must be terminated by a NULL string. If the string is found in the array
  * of strings, the index of that string in the array is returned. Otherwise, the
  * default value that was passed as the third argument is returned.
  */
 static int
-find_index_from_string_array(char *needle, char **haystack, int default_value)
+find_index_from_string_array(const char *needle, const char **haystack, int default_value)
 {
        int i = 0;
 
@@ -91,12 +95,13 @@ find_index_from_string_array(char *needle, char **haystack, int default_value)
        return default_value;
 }
 
-/* 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)
+/* Attempt to Write out "recent" to the user's recent file.
+   If we got an error report it with a dialog box and return FALSE,
+   otherwise return TRUE. */
+gboolean
+write_recent(void)
 {
+  char        *pf_dir_path;
   char        *rf_path;
   FILE        *rf;
 
@@ -106,10 +111,23 @@ write_recent(char **rf_path_return)
    *   so that duplication can be avoided with filter.c
    */
 
+  /* Create the directory that holds personal configuration files, if
+     necessary.  */
+  if (create_persconffile_dir(&pf_dir_path) == -1) {
+     simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
+      "Can't create directory\n\"%s\"\nfor recent file: %s.", pf_dir_path,
+      strerror(errno));
+     g_free(pf_dir_path);
+     return FALSE;
+  }
+
   rf_path = get_persconffile_path(RECENT_FILE_NAME, TRUE);
-  if ((rf = fopen(rf_path, "w")) == NULL) {
-    *rf_path_return = rf_path;
-    return errno;
+  if ((rf = eth_fopen(rf_path, "w")) == NULL) {
+     simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
+      "Can't open recent file\n\"%s\": %s.", rf_path,
+      strerror(errno));
+    g_free(rf_path);
+    return FALSE;
   }
 
   fputs("# Recent settings file for Ethereal " VERSION ".\n"
@@ -117,13 +135,19 @@ write_recent(char **rf_path_return)
     "# 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 last) ########\n"
+    "######## Recent capture files (latest last), cannot be altered through command line ########\n"
     "\n", rf);
 
   menu_recent_file_write_all(rf);
 
   fputs("\n"
-    "######## Recent display filters (latest last) ########\n"
+    "######## Recent capture filters (latest last), cannot be altered through command line ########\n"
+    "\n", rf);
+
+  cfilter_combo_recent_write_all(rf);
+
+  fputs("\n"
+    "######## Recent display filters (latest last), cannot be altered through command line ########\n"
     "\n", rf);
 
   dfilter_recent_combo_write_all(rf);
@@ -158,18 +182,28 @@ write_recent(char **rf_path_return)
   fprintf(rf, RECENT_KEY_STATUSBAR_SHOW ": %s\n",
                  recent.statusbar_show == TRUE ? "TRUE" : "FALSE");
 
+  fprintf(rf, "\n# Packet list colorize (hide).\n");
+  fprintf(rf, "# TRUE or FALSE (case-insensitive).\n");
+  fprintf(rf, RECENT_KEY_PACKET_LIST_COLORIZE ": %s\n",
+                 recent.packet_list_colorize == TRUE ? "TRUE" : "FALSE");
+
   fprintf(rf, "\n# Timestamp display format.\n");
   fprintf(rf, "# One of: RELATIVE, ABSOLUTE, ABSOLUTE_WITH_DATE, DELTA\n");
   fprintf(rf, RECENT_GUI_TIME_FORMAT ": %s\n",
           ts_type_text[recent.gui_time_format]);
 
+  fprintf(rf, "\n# Timestamp display precision.\n");
+  fprintf(rf, "# One of: AUTO, SEC, DSEC, CSEC, MSEC, USEC, NSEC\n");
+  fprintf(rf, RECENT_GUI_TIME_PRECISION ": %s\n",
+          ts_precision_text[recent.gui_time_precision]);
+
   fprintf(rf, "\n# Zoom level.\n");
   fprintf(rf, "# A decimal number.\n");
   fprintf(rf, RECENT_GUI_ZOOM_LEVEL ": %d\n",
                  recent.gui_zoom_level);
 
   fprintf(rf, "\n# Main window geometry.\n");
-  fprintf(rf, "# Decimal integers.\n");
+  fprintf(rf, "# Decimal numbers.\n");
   fprintf(rf, RECENT_GUI_GEOMETRY_MAIN_X ": %d\n", recent.gui_geometry_main_x);
   fprintf(rf, RECENT_GUI_GEOMETRY_MAIN_Y ": %d\n", recent.gui_geometry_main_y);
   fprintf(rf, RECENT_GUI_GEOMETRY_MAIN_WIDTH ": %d\n",
@@ -177,19 +211,32 @@ write_recent(char **rf_path_return)
   fprintf(rf, RECENT_GUI_GEOMETRY_MAIN_HEIGHT ": %d\n",
                  recent.gui_geometry_main_height);
   
-  fprintf(rf, "\n# Main window maximized (GTK2 only).\n");
+  fprintf(rf, "\n# Main window maximized (GTK2 only!).\n");
   fprintf(rf, "# TRUE or FALSE (case-insensitive).\n");
   fprintf(rf, RECENT_GUI_GEOMETRY_MAIN_MAXIMIZED ": %s\n",
                  recent.gui_geometry_main_maximized == TRUE ? "TRUE" : "FALSE");
 
-  fprintf(rf, "\n# Main window panes (GTK2 only).\n");
-  fprintf(rf, "# Decimal numbers.\n");
-  fprintf(rf, RECENT_GUI_GEOMETRY_MAIN_UPPER_PANE ": %d\n",
+  fprintf(rf, "\n# Main window upper (or leftmost) pane size.\n");
+  fprintf(rf, "# (GTK1: has no effect here, command line -o usage only).\n");
+  fprintf(rf, "# Decimal number.\n");
+  if (recent.gui_geometry_main_upper_pane != 0) {
+    fprintf(rf, RECENT_GUI_GEOMETRY_MAIN_UPPER_PANE ": %d\n",
                  recent.gui_geometry_main_upper_pane);
-  fprintf(rf, RECENT_GUI_GEOMETRY_MAIN_LOWER_PANE ": %d\n",
+  }
+  fprintf(rf, "\n# Main window middle pane size.\n");
+  fprintf(rf, "# (GTK1: has no effect here, command line -o usage only).\n");
+  fprintf(rf, "# Decimal number.\n");
+  if (recent.gui_geometry_main_lower_pane != 0) {
+    fprintf(rf, RECENT_GUI_GEOMETRY_MAIN_LOWER_PANE ": %d\n",
                  recent.gui_geometry_main_lower_pane);
-  fprintf(rf, RECENT_GUI_GEOMETRY_STATUS_PANE ": %d\n",
+  }
+  fprintf(rf, "\n# Statusbar left pane size.\n");
+  fprintf(rf, "# (GTK1: has no effect here, command line -o usage only).\n");
+  fprintf(rf, "# Decimal number.\n");
+  if (recent.gui_geometry_status_pane != 0) {
+    fprintf(rf, RECENT_GUI_GEOMETRY_STATUS_PANE ": %d\n",
                  recent.gui_geometry_status_pane);
+  }
 
   if (get_last_open_dir() != NULL) {
     fprintf(rf, "\n# Last directory navigated to in File Open dialog.\n");
@@ -201,10 +248,10 @@ write_recent(char **rf_path_return)
   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
+     an error indication, or maybe write to a new recent file and
      rename that file on top of the old one only if there are not I/O
      errors. */
-  return 0;
+  return TRUE;
 }
 
 
@@ -232,14 +279,12 @@ write_recent_geom(gpointer key _U_, gpointer value, gpointer rf)
 
 /* set one user's recent file key/value pair */
 static int
-read_set_recent_pair(gchar *key, gchar *value)
+read_set_recent_pair_static(gchar *key, gchar *value)
 {
+  long num;
+  char *p;
 
-  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);
-  } else if (strcmp(key, RECENT_KEY_MAIN_TOOLBAR_SHOW) == 0) {
+  if (strcmp(key, RECENT_KEY_MAIN_TOOLBAR_SHOW) == 0) {
     if (strcasecmp(value, "true") == 0) {
         recent.main_toolbar_show = TRUE;
     }
@@ -281,12 +326,24 @@ read_set_recent_pair(gchar *key, gchar *value)
     else {
         recent.statusbar_show = FALSE;
     }
+  } else if (strcmp(key, RECENT_KEY_PACKET_LIST_COLORIZE) == 0) {
+    if (strcasecmp(value, "true") == 0) {
+        recent.packet_list_colorize = TRUE;
+    }
+    else {
+        recent.packet_list_colorize = FALSE;
+    }
   } else if (strcmp(key, RECENT_GUI_TIME_FORMAT) == 0) {
     recent.gui_time_format =
        find_index_from_string_array(value, ts_type_text, TS_RELATIVE);
+  } else if (strcmp(key, RECENT_GUI_TIME_PRECISION) == 0) {
+    recent.gui_time_precision =
+       find_index_from_string_array(value, ts_precision_text, TS_PREC_AUTO);
   } else if (strcmp(key, RECENT_GUI_ZOOM_LEVEL) == 0) {
-    recent.gui_zoom_level = strtol(value, NULL, 0);
-
+    num = strtol(value, &p, 0);
+    if (p == value || *p != '\0')
+      return PREFS_SET_SYNTAX_ERR;     /* number was bad */
+    recent.gui_zoom_level = num;
   } else if (strcmp(key, RECENT_GUI_GEOMETRY_MAIN_MAXIMIZED) == 0) {
     if (strcasecmp(value, "true") == 0) {
         recent.gui_geometry_main_maximized = TRUE;
@@ -296,21 +353,53 @@ read_set_recent_pair(gchar *key, gchar *value)
     }
 
   } else if (strcmp(key, RECENT_GUI_GEOMETRY_MAIN_X) == 0) {
-    recent.gui_geometry_main_x = strtol(value, NULL, 10);
+    num = strtol(value, &p, 0);
+    if (p == value || *p != '\0')
+      return PREFS_SET_SYNTAX_ERR;     /* number was bad */
+    recent.gui_geometry_main_x = num;
   } else if (strcmp(key, RECENT_GUI_GEOMETRY_MAIN_Y) == 0) {
-    recent.gui_geometry_main_y = strtol(value, NULL, 10);
+    num = strtol(value, &p, 0);
+    if (p == value || *p != '\0')
+      return PREFS_SET_SYNTAX_ERR;     /* number was bad */
+    recent.gui_geometry_main_y = num;
   } else if (strcmp(key, RECENT_GUI_GEOMETRY_MAIN_WIDTH) == 0) {
-    recent.gui_geometry_main_width = strtol(value, NULL, 10);
+    num = strtol(value, &p, 0);
+    if (p == value || *p != '\0')
+      return PREFS_SET_SYNTAX_ERR;     /* number was bad */
+    if (num <= 0)
+      return PREFS_SET_SYNTAX_ERR;     /* number must be positive */
+    recent.gui_geometry_main_width = num;
   } else if (strcmp(key, RECENT_GUI_GEOMETRY_MAIN_HEIGHT) == 0) {
-    recent.gui_geometry_main_height = strtol(value, NULL, 10);
-
+    num = strtol(value, &p, 0);
+    if (p == value || *p != '\0')
+      return PREFS_SET_SYNTAX_ERR;     /* number was bad */
+    if (num <= 0)
+      return PREFS_SET_SYNTAX_ERR;     /* number must be positive */
+    recent.gui_geometry_main_height = num;
   } else if (strcmp(key, RECENT_GUI_GEOMETRY_MAIN_UPPER_PANE) == 0) {
-    recent.gui_geometry_main_upper_pane = strtol(value, NULL, 10);
+    num = strtol(value, &p, 0);
+    if (p == value || *p != '\0')
+      return PREFS_SET_SYNTAX_ERR;     /* number was bad */
+    if (num <= 0)
+      return PREFS_SET_SYNTAX_ERR;     /* number must be positive */
+    recent.gui_geometry_main_upper_pane = num;
+    recent.has_gui_geometry_main_upper_pane = TRUE;
   } else if (strcmp(key, RECENT_GUI_GEOMETRY_MAIN_LOWER_PANE) == 0) {
-    recent.gui_geometry_main_lower_pane = strtol(value, NULL, 10);
+    num = strtol(value, &p, 0);
+    if (p == value || *p != '\0')
+      return PREFS_SET_SYNTAX_ERR;     /* number was bad */
+    if (num <= 0)
+      return PREFS_SET_SYNTAX_ERR;     /* number must be positive */
+    recent.gui_geometry_main_lower_pane = num;
+    recent.has_gui_geometry_main_lower_pane = TRUE;
   } else if (strcmp(key, RECENT_GUI_GEOMETRY_STATUS_PANE) == 0) {
-    recent.gui_geometry_status_pane = strtol(value, NULL, 10);
-
+    num = strtol(value, &p, 0);
+    if (p == value || *p != '\0')
+      return PREFS_SET_SYNTAX_ERR;     /* number was bad */
+    if (num <= 0)
+      return PREFS_SET_SYNTAX_ERR;     /* number must be positive */
+    recent.gui_geometry_status_pane = num;
+    recent.has_gui_geometry_status_pane = TRUE;
   } else if (strcmp(key, RECENT_GUI_FILEOPEN_REMEMBERED_DIR) == 0) {
     set_last_open_dir(value);
   } else if (strncmp(key, RECENT_GUI_GEOMETRY, sizeof(RECENT_GUI_GEOMETRY)-1) == 0) {
@@ -328,9 +417,67 @@ read_set_recent_pair(gchar *key, gchar *value)
 }
 
 
-/* opens the user's recent file and read it out */
+/* set one user's recent file key/value pair */
+static int
+read_set_recent_pair_dynamic(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);
+  } else if (strcmp(key, RECENT_KEY_CAPTURE_FILTER) == 0) {
+       cfilter_combo_add_recent(value);
+  }
+
+  return PREFS_SET_OK;
+}
+
+
+/*
+ * Given a string of the form "<recent name>:<recent value>", as might appear
+ * as an argument to a "-o" option, parse it and set the recent value in
+ * question.  Return an indication of whether it succeeded or failed
+ * in some fashion.
+ */
+int
+recent_set_arg(char *prefarg)
+{
+       guchar *p, *colonp;
+       int ret;
+
+       colonp = strchr(prefarg, ':');
+       if (colonp == NULL)
+               return PREFS_SET_SYNTAX_ERR;
+
+       p = colonp;
+       *p++ = '\0';
+
+       /*
+        * Skip over any white space (there probably won't be any, but
+        * as we allow it in the preferences file, we might as well
+        * allow it here).
+        */
+       while (isspace(*p))
+               p++;
+       if (*p == '\0') {
+               /*
+                * Put the colon back, so if our caller uses, in an
+                * error message, the string they passed us, the message
+                * looks correct.
+                */
+               *colonp = ':';
+               return PREFS_SET_SYNTAX_ERR;
+       }
+
+       ret = read_set_recent_pair_static(prefarg, p);
+       *colonp = ':';  /* put the colon back */
+       return ret;
+}
+
+
+/* opens the user's recent file and read the first part */
 void
-read_recent(char **rf_path_return, int *rf_errno_return)
+recent_read_static(char **rf_path_return, int *rf_errno_return)
 {
   char       *rf_path;
   FILE       *rf;
@@ -343,13 +490,15 @@ read_recent(char **rf_path_return, int *rf_errno_return)
   recent.tree_view_show         = TRUE;
   recent.byte_view_show         = TRUE;
   recent.statusbar_show         = TRUE;
+  recent.packet_list_colorize   = TRUE;
   recent.gui_time_format        = TS_RELATIVE;
+  recent.gui_time_precision     = TS_PREC_AUTO;
   recent.gui_zoom_level         = 0;
 
   recent.gui_geometry_main_x        =        20;
   recent.gui_geometry_main_y        =        20;
   recent.gui_geometry_main_width    = DEF_WIDTH;
-  recent.gui_geometry_main_height   =        -1;
+  recent.gui_geometry_main_height   = DEF_HEIGHT;
   recent.gui_geometry_main_maximized=     FALSE;
 
   /* pane size of zero will autodetect */
@@ -357,14 +506,58 @@ read_recent(char **rf_path_return, int *rf_errno_return)
   recent.gui_geometry_main_lower_pane   = 0;
   recent.gui_geometry_status_pane       = 0;
 
+  /* the following are only used if GTK2 is used (as GTK1 cannot read these geometry values) */
+  /* or if set through command line */
+#if GTK_MAJOR_VERSION >= 2
+  recent.has_gui_geometry_main_upper_pane = TRUE;
+  recent.has_gui_geometry_main_lower_pane = TRUE;
+  recent.has_gui_geometry_status_pane = TRUE;
+#else
+  recent.has_gui_geometry_main_upper_pane = FALSE;
+  recent.has_gui_geometry_main_lower_pane = FALSE;
+  recent.has_gui_geometry_status_pane = FALSE;
+#endif
+
+  /* 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 = eth_fopen(rf_path, "r")) != NULL) {
+    /* We succeeded in opening it; read it. */
+    read_prefs_file(rf_path, rf, read_set_recent_pair_static);
+    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;
+    }
+  }
+}
+
+
+
+/* opens the user's recent file and read it out */
+void
+recent_read_dynamic(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) {
+  if ((rf = eth_fopen(rf_path, "r")) != NULL) {
     /* We succeeded in opening it; read it. */
-    read_prefs_file(rf_path, rf, read_set_recent_pair);
+    read_prefs_file(rf_path, rf, read_set_recent_pair_dynamic);
        /* set dfilter combobox to have an empty line */
     dfilter_combo_add_empty();
     fclose(rf);