98857ff79dd4562068729fbe0f42efddbafa2c20
[obnox/wireshark/wip.git] / gtk / recent.c
1 /* recent.c
2  * Recent "preference" handling routines
3  * Copyright 2004, Ulf Lamping <ulf.lamping@web.de>
4  *
5  * $Id$
6  *
7  * Wireshark - Network traffic analyzer
8  * By Gerald Combs <gerald@wireshark.org>
9  * Copyright 1998 Gerald Combs
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24  */
25
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29 #include <stdio.h>
30 #include <string.h>
31 #include <ctype.h>
32
33 #include <gtk/gtk.h>
34
35 #include <epan/epan.h>
36 #include <epan/filesystem.h>
37 #include <epan/emem.h>
38 #include <epan/prefs.h>
39 #include <epan/prefs-int.h>
40 #include <epan/column.h>
41
42 #include "../simple_dialog.h"
43 #include "../u3.h"
44 #include <wsutil/file_util.h>
45
46 #include "gtk/recent.h"
47 #include "gtk/main.h"
48 #include "gtk/menus.h"
49 #include "gtk/gui_utils.h"
50 #include "gtk/new_packet_list.h"
51 #include "gtk/file_dlg.h"
52 #include "gtk/cfilter_combo_utils.h"
53
54 #ifdef HAVE_PCAP_REMOTE
55 #include "gtk/capture_dlg.h"
56 #endif
57
58 #define RECENT_KEY_MAIN_TOOLBAR_SHOW        "gui.toolbar_main_show"
59 #define RECENT_KEY_FILTER_TOOLBAR_SHOW      "gui.filter_toolbar_show"
60 #define RECENT_KEY_AIRPCAP_TOOLBAR_SHOW     "gui.airpcap_toolbar_show"
61 #define RECENT_KEY_DRIVER_CHECK_SHOW        "gui.airpcap_driver_check_show"
62 #define RECENT_KEY_PACKET_LIST_SHOW         "gui.packet_list_show"
63 #define RECENT_KEY_TREE_VIEW_SHOW           "gui.tree_view_show"
64 #define RECENT_KEY_BYTE_VIEW_SHOW           "gui.byte_view_show"
65 #define RECENT_KEY_STATUSBAR_SHOW           "gui.statusbar_show"
66 #define RECENT_KEY_PACKET_LIST_COLORIZE     "gui.packet_list_colorize"
67 #define RECENT_GUI_TIME_FORMAT              "gui.time_format"
68 #define RECENT_GUI_TIME_PRECISION           "gui.time_precision"
69 #define RECENT_GUI_SECONDS_FORMAT           "gui.seconds_format"
70 #define RECENT_GUI_ZOOM_LEVEL               "gui.zoom_level"
71 #define RECENT_GUI_BYTES_VIEW               "gui.bytes_view"
72 #define RECENT_GUI_GEOMETRY_MAIN_X          "gui.geometry_main_x"
73 #define RECENT_GUI_GEOMETRY_MAIN_Y          "gui.geometry_main_y"
74 #define RECENT_GUI_GEOMETRY_MAIN_WIDTH      "gui.geometry_main_width"
75 #define RECENT_GUI_GEOMETRY_MAIN_HEIGHT     "gui.geometry_main_height"
76 #define RECENT_GUI_GEOMETRY_MAIN_MAXIMIZED  "gui.geometry_main_maximized"
77 #define RECENT_GUI_GEOMETRY_MAIN_UPPER_PANE "gui.geometry_main_upper_pane"
78 #define RECENT_GUI_GEOMETRY_MAIN_LOWER_PANE "gui.geometry_main_lower_pane"
79 #define RECENT_GUI_GEOMETRY_STATUS_PANE_LEFT  "gui.geometry_status_pane"
80 #define RECENT_GUI_GEOMETRY_STATUS_PANE_RIGHT "gui.geometry_status_pane_right"
81 #define RECENT_GUI_GEOMETRY_WLAN_STATS_PANE "gui.geometry_status_wlan_stats_pane"
82 #define RECENT_LAST_USED_PROFILE            "gui.last_used_profile"
83 #define RECENT_GUI_FILEOPEN_REMEMBERED_DIR  "gui.fileopen_remembered_dir"
84 #define RECENT_GUI_GEOMETRY                 "gui.geom."
85 #define RECENT_KEY_PRIVS_WARN_IF_ELEVATED   "privs.warn_if_elevated"
86 #define RECENT_KEY_PRIVS_WARN_IF_NO_NPF     "privs.warn_if_no_npf"
87
88 #define RECENT_FILE_NAME "recent"
89 #define RECENT_COMMON_FILE_NAME "recent_common"
90
91 recent_settings_t recent;
92
93 static const char *ts_type_text[] =
94   { "RELATIVE", "ABSOLUTE", "ABSOLUTE_WITH_DATE", "DELTA", "DELTA_DIS", "EPOCH", NULL };
95
96 static const char *ts_precision_text[] =
97         { "AUTO", "SEC", "DSEC", "CSEC", "MSEC", "USEC", "NSEC", NULL };
98
99 static const char *ts_seconds_text[] =
100   { "SECONDS", "HOUR_MIN_SEC", NULL };
101
102 /* Takes an string and a pointer to an array of strings, and a default int value.
103  * The array must be terminated by a NULL string. If the string is found in the array
104  * of strings, the index of that string in the array is returned. Otherwise, the
105  * default value that was passed as the third argument is returned.
106  */
107 static int
108 find_index_from_string_array(const char *needle, const char **haystack, int default_value)
109 {
110         int i = 0;
111
112         while (haystack[i] != NULL) {
113                 if (strcmp(needle, haystack[i]) == 0) {
114                         return i;
115                 }
116                 i++;
117         }
118         return default_value;
119 }
120
121 static void
122 free_col_width_info(recent_settings_t *rs)
123 {
124   col_width_data *cfmt;
125
126   while (rs->col_width_list != NULL) {
127     cfmt = rs->col_width_list->data;
128     g_free(cfmt->cfield);
129     g_free(cfmt);
130     rs->col_width_list = g_list_remove_link(rs->col_width_list, rs->col_width_list);
131   }
132   g_list_free(rs->col_width_list);
133   rs->col_width_list = NULL;
134 }
135
136 /* Attempt to Write out "recent common" to the user's recent common file.
137    If we got an error report it with a dialog box and return FALSE,
138    otherwise return TRUE. */
139 gboolean
140 write_recent(void)
141 {
142   char        *pf_dir_path;
143   char        *rf_path;
144   FILE        *rf;
145
146   /* To do:
147    * - Split output lines longer than MAX_VAL_LEN
148    * - Create a function for the preference directory check/creation
149    *   so that duplication can be avoided with filter.c
150    */
151
152   /* Create the directory that holds personal configuration files, if
153      necessary.  */
154   if (create_persconffile_dir(&pf_dir_path) == -1) {
155      simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
156       "Can't create directory\n\"%s\"\nfor recent file: %s.", pf_dir_path,
157       strerror(errno));
158      g_free(pf_dir_path);
159      return FALSE;
160   }
161
162   rf_path = get_persconffile_path(RECENT_COMMON_FILE_NAME, FALSE, TRUE);
163   if ((rf = ws_fopen(rf_path, "w")) == NULL) {
164      simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
165       "Can't open recent file\n\"%s\": %s.", rf_path,
166       strerror(errno));
167     g_free(rf_path);
168     return FALSE;
169   }
170   g_free(rf_path);
171
172   fputs("# Recent settings file for Wireshark " VERSION ".\n"
173     "#\n"
174     "# This file is regenerated each time Wireshark is quit.\n"
175     "# So be careful, if you want to make manual changes here.\n"
176     "\n"
177     "######## Recent capture files (latest last), cannot be altered through command line ########\n"
178     "\n", rf);
179
180   menu_recent_file_write_all(rf);
181
182   fputs("\n"
183     "######## Recent capture filters (latest last), cannot be altered through command line ########\n"
184     "\n", rf);
185
186   cfilter_combo_recent_write_all(rf);
187
188   fputs("\n"
189     "######## Recent display filters (latest last), cannot be altered through command line ########\n"
190     "\n", rf);
191
192   dfilter_recent_combo_write_all(rf);
193
194 #ifdef HAVE_PCAP_REMOTE
195   fputs("\n"
196     "######## Recent remote hosts, cannot be altered through command line ########\n"
197     "\n", rf);
198
199   capture_remote_combo_recent_write_all(rf);
200 #endif
201
202   fprintf(rf, "\n# Main window geometry.\n");
203   fprintf(rf, "# Decimal numbers.\n");
204   fprintf(rf, RECENT_GUI_GEOMETRY_MAIN_X ": %d\n", recent.gui_geometry_main_x);
205   fprintf(rf, RECENT_GUI_GEOMETRY_MAIN_Y ": %d\n", recent.gui_geometry_main_y);
206   fprintf(rf, RECENT_GUI_GEOMETRY_MAIN_WIDTH ": %d\n",
207                   recent.gui_geometry_main_width);
208   fprintf(rf, RECENT_GUI_GEOMETRY_MAIN_HEIGHT ": %d\n",
209                   recent.gui_geometry_main_height);
210
211   fprintf(rf, "\n# Main window maximized.\n");
212   fprintf(rf, "# TRUE or FALSE (case-insensitive).\n");
213   fprintf(rf, RECENT_GUI_GEOMETRY_MAIN_MAXIMIZED ": %s\n",
214                   recent.gui_geometry_main_maximized == TRUE ? "TRUE" : "FALSE");
215
216   fprintf(rf, "\n# Statusbar left pane size.\n");
217   fprintf(rf, "# Decimal number.\n");
218   if (recent.gui_geometry_status_pane_left != 0) {
219     fprintf(rf, RECENT_GUI_GEOMETRY_STATUS_PANE_LEFT ": %d\n",
220                   recent.gui_geometry_status_pane_left);
221   }
222   fprintf(rf, "\n# Statusbar middle pane size.\n");
223   fprintf(rf, "# Decimal number.\n");
224   if (recent.gui_geometry_status_pane_right != 0) {
225     fprintf(rf, RECENT_GUI_GEOMETRY_STATUS_PANE_RIGHT ": %d\n",
226                   recent.gui_geometry_status_pane_right);
227   }
228
229   fprintf(rf, "\n# Last used Configuration Profile.\n");
230   fprintf(rf, RECENT_LAST_USED_PROFILE ": %s\n", get_profile_name());
231
232   fprintf(rf, "\n# WLAN statistics upper pane size.\n");
233   fprintf(rf, "# Decimal number.\n");
234   fprintf(rf, RECENT_GUI_GEOMETRY_WLAN_STATS_PANE ": %d\n",
235           recent.gui_geometry_wlan_stats_pane);
236
237   fprintf(rf, "\n# Warn if running with elevated permissions (e.g. as root).\n");
238   fprintf(rf, "# TRUE or FALSE (case-insensitive).\n");
239   fprintf(rf, RECENT_KEY_PRIVS_WARN_IF_ELEVATED ": %s\n",
240                   recent.privs_warn_if_elevated == TRUE ? "TRUE" : "FALSE");
241
242   fprintf(rf, "\n# Warn if npf.sys isn't loaded on Windows >= 6.0.\n");
243   fprintf(rf, "# TRUE or FALSE (case-insensitive).\n");
244   fprintf(rf, RECENT_KEY_PRIVS_WARN_IF_NO_NPF ": %s\n",
245                   recent.privs_warn_if_no_npf == TRUE ? "TRUE" : "FALSE");
246
247   window_geom_recent_write_all(rf);
248
249   fclose(rf);
250
251   /* XXX - catch I/O errors (e.g. "ran out of disk space") and return
252      an error indication, or maybe write to a new recent file and
253      rename that file on top of the old one only if there are not I/O
254      errors. */
255   return TRUE;
256 }
257
258
259 /* Attempt to Write out profile "recent" to the user's profile recent file.
260    If we got an error report it with a dialog box and return FALSE,
261    otherwise return TRUE. */
262 gboolean
263 write_profile_recent(void)
264 {
265   char        *pf_dir_path;
266   char        *rf_path;
267   FILE        *rf;
268
269   /* To do:
270    * - Split output lines longer than MAX_VAL_LEN
271    * - Create a function for the preference directory check/creation
272    *   so that duplication can be avoided with filter.c
273    */
274
275   /* Create the directory that holds personal configuration files, if
276      necessary.  */
277   if (create_persconffile_dir(&pf_dir_path) == -1) {
278      simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
279       "Can't create directory\n\"%s\"\nfor recent file: %s.", pf_dir_path,
280       strerror(errno));
281      g_free(pf_dir_path);
282      return FALSE;
283   }
284
285   rf_path = get_persconffile_path(RECENT_FILE_NAME, TRUE, TRUE);
286   if ((rf = ws_fopen(rf_path, "w")) == NULL) {
287      simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
288       "Can't open recent file\n\"%s\": %s.", rf_path,
289       strerror(errno));
290     g_free(rf_path);
291     return FALSE;
292   }
293   g_free(rf_path);
294
295   fputs("# Recent settings file for Wireshark " VERSION ".\n"
296     "#\n"
297     "# This file is regenerated each time Wireshark is quit\n"
298     "# and when changing configuration profile.\n"
299     "# So be careful, if you want to make manual changes here.\n"
300     "\n", rf);
301
302   fprintf(rf, "\n# Main Toolbar show (hide).\n");
303   fprintf(rf, "# TRUE or FALSE (case-insensitive).\n");
304   fprintf(rf, RECENT_KEY_MAIN_TOOLBAR_SHOW ": %s\n",
305                   recent.main_toolbar_show == TRUE ? "TRUE" : "FALSE");
306
307   fprintf(rf, "\n# Filter Toolbar show (hide).\n");
308   fprintf(rf, "# TRUE or FALSE (case-insensitive).\n");
309   fprintf(rf, RECENT_KEY_FILTER_TOOLBAR_SHOW ": %s\n",
310                   recent.filter_toolbar_show == TRUE ? "TRUE" : "FALSE");
311
312 #ifdef HAVE_AIRPCAP
313   fprintf(rf, "\n# Wireless Settings Toolbar show (hide).\n");
314   fprintf(rf, "# TRUE or FALSE (case-insensitive).\n");
315   fprintf(rf, RECENT_KEY_AIRPCAP_TOOLBAR_SHOW ": %s\n",
316                   recent.airpcap_toolbar_show == TRUE ? "TRUE" : "FALSE");
317 #endif
318
319 #ifdef HAVE_AIRPCAP
320   fprintf(rf, "\n# Show (hide) old AirPcap driver warning dialog box.\n");
321   fprintf(rf, "# TRUE or FALSE (case-insensitive).\n");
322   fprintf(rf, RECENT_KEY_DRIVER_CHECK_SHOW ": %s\n",
323                   recent.airpcap_driver_check_show == TRUE ? "TRUE" : "FALSE");
324 #endif
325
326   fprintf(rf, "\n# Packet list show (hide).\n");
327   fprintf(rf, "# TRUE or FALSE (case-insensitive).\n");
328   fprintf(rf, RECENT_KEY_PACKET_LIST_SHOW ": %s\n",
329                   recent.packet_list_show == TRUE ? "TRUE" : "FALSE");
330
331   fprintf(rf, "\n# Tree view show (hide).\n");
332   fprintf(rf, "# TRUE or FALSE (case-insensitive).\n");
333   fprintf(rf, RECENT_KEY_TREE_VIEW_SHOW ": %s\n",
334                   recent.tree_view_show == TRUE ? "TRUE" : "FALSE");
335
336   fprintf(rf, "\n# Byte view show (hide).\n");
337   fprintf(rf, "# TRUE or FALSE (case-insensitive).\n");
338   fprintf(rf, RECENT_KEY_BYTE_VIEW_SHOW ": %s\n",
339                   recent.byte_view_show == TRUE ? "TRUE" : "FALSE");
340
341   fprintf(rf, "\n# Statusbar show (hide).\n");
342   fprintf(rf, "# TRUE or FALSE (case-insensitive).\n");
343   fprintf(rf, RECENT_KEY_STATUSBAR_SHOW ": %s\n",
344                   recent.statusbar_show == TRUE ? "TRUE" : "FALSE");
345
346   fprintf(rf, "\n# Packet list colorize (hide).\n");
347   fprintf(rf, "# TRUE or FALSE (case-insensitive).\n");
348   fprintf(rf, RECENT_KEY_PACKET_LIST_COLORIZE ": %s\n",
349                   recent.packet_list_colorize == TRUE ? "TRUE" : "FALSE");
350
351   fprintf(rf, "\n# Timestamp display format.\n");
352   fprintf(rf, "# One of: RELATIVE, ABSOLUTE, ABSOLUTE_WITH_DATE, DELTA, DELTA_DIS, EPOCH\n");
353   fprintf(rf, RECENT_GUI_TIME_FORMAT ": %s\n",
354           ts_type_text[recent.gui_time_format]);
355
356   fprintf(rf, "\n# Timestamp display precision.\n");
357   fprintf(rf, "# One of: AUTO, SEC, DSEC, CSEC, MSEC, USEC, NSEC\n");
358   fprintf(rf, RECENT_GUI_TIME_PRECISION ": %s\n",
359           ts_precision_text[recent.gui_time_precision]);
360
361   fprintf(rf, "\n# Seconds display format.\n");
362   fprintf(rf, "# One of: SECONDS, HOUR_MIN_SEC\n");
363   fprintf(rf, RECENT_GUI_SECONDS_FORMAT ": %s\n",
364           ts_seconds_text[recent.gui_seconds_format]);
365
366   fprintf(rf, "\n# Zoom level.\n");
367   fprintf(rf, "# A decimal number.\n");
368   fprintf(rf, RECENT_GUI_ZOOM_LEVEL ": %d\n",
369                   recent.gui_zoom_level);
370
371   fprintf(rf, "\n# Bytes view.\n");
372   fprintf(rf, "# A decimal number.\n");
373   fprintf(rf, RECENT_GUI_BYTES_VIEW ": %d\n",
374                   recent.gui_bytes_view);
375
376   fprintf(rf, "\n# Main window upper (or leftmost) pane size.\n");
377   fprintf(rf, "# Decimal number.\n");
378   if (recent.gui_geometry_main_upper_pane != 0) {
379     fprintf(rf, RECENT_GUI_GEOMETRY_MAIN_UPPER_PANE ": %d\n",
380                   recent.gui_geometry_main_upper_pane);
381   }
382   fprintf(rf, "\n# Main window middle pane size.\n");
383   fprintf(rf, "# Decimal number.\n");
384   if (recent.gui_geometry_main_lower_pane != 0) {
385     fprintf(rf, RECENT_GUI_GEOMETRY_MAIN_LOWER_PANE ": %d\n",
386                   recent.gui_geometry_main_lower_pane);
387   }
388
389   fprintf(rf, "\n# Packet list column pixel widths.\n");
390   fprintf(rf, "# Each pair of strings consists of a column format and its pixel width.\n");
391   new_packet_list_recent_write_all(rf);
392
393   if (get_last_open_dir() != NULL) {
394     fprintf(rf, "\n# Last directory navigated to in File Open dialog.\n");
395
396     if(u3_active())
397       fprintf(rf, RECENT_GUI_FILEOPEN_REMEMBERED_DIR ": %s\n", u3_contract_device_path(get_last_open_dir()));
398     else
399       fprintf(rf, RECENT_GUI_FILEOPEN_REMEMBERED_DIR ": %s\n", get_last_open_dir());
400   }
401
402   fclose(rf);
403
404   /* XXX - catch I/O errors (e.g. "ran out of disk space") and return
405      an error indication, or maybe write to a new recent file and
406      rename that file on top of the old one only if there are not I/O
407      errors. */
408   return TRUE;
409 }
410
411
412 /* write the geometry values of a window to recent file */
413 void
414 write_recent_geom(gpointer key _U_, gpointer value, gpointer rf)
415 {
416     window_geometry_t *geom = value;
417
418     fprintf(rf, "\n# Geometry and maximized state of %s window.\n", geom->key);
419     fprintf(rf, "# Decimal integers.\n");
420     fprintf(rf, RECENT_GUI_GEOMETRY "%s.x: %d\n", geom->key, geom->x);
421     fprintf(rf, RECENT_GUI_GEOMETRY "%s.y: %d\n", geom->key, geom->y);
422     fprintf(rf, RECENT_GUI_GEOMETRY "%s.width: %d\n", geom->key,
423               geom->width);
424     fprintf(rf, RECENT_GUI_GEOMETRY "%s.height: %d\n", geom->key,
425               geom->height);
426
427     fprintf(rf, "# TRUE or FALSE (case-insensitive).\n");
428     fprintf(rf, RECENT_GUI_GEOMETRY "%s.maximized: %s\n", geom->key,
429               geom->maximized == TRUE ? "TRUE" : "FALSE");
430
431 }
432
433 /* set one user's recent common file key/value pair */
434 static prefs_set_pref_e
435 read_set_recent_common_pair_static(gchar *key, gchar *value,
436                                    void *private_data _U_,
437                                    gboolean return_range_errors _U_)
438 {
439   long num;
440   char *p;
441
442   if (strcmp(key, RECENT_GUI_GEOMETRY_MAIN_MAXIMIZED) == 0) {
443     if (g_ascii_strcasecmp(value, "true") == 0) {
444         recent.gui_geometry_main_maximized = TRUE;
445     }
446     else {
447         recent.gui_geometry_main_maximized = FALSE;
448     }
449
450   } else if (strcmp(key, RECENT_GUI_GEOMETRY_MAIN_X) == 0) {
451     num = strtol(value, &p, 0);
452     if (p == value || *p != '\0')
453       return PREFS_SET_SYNTAX_ERR;      /* number was bad */
454     recent.gui_geometry_main_x = num;
455   } else if (strcmp(key, RECENT_GUI_GEOMETRY_MAIN_Y) == 0) {
456     num = strtol(value, &p, 0);
457     if (p == value || *p != '\0')
458       return PREFS_SET_SYNTAX_ERR;      /* number was bad */
459     recent.gui_geometry_main_y = num;
460   } else if (strcmp(key, RECENT_GUI_GEOMETRY_MAIN_WIDTH) == 0) {
461     num = strtol(value, &p, 0);
462     if (p == value || *p != '\0')
463       return PREFS_SET_SYNTAX_ERR;      /* number was bad */
464     if (num <= 0)
465       return PREFS_SET_SYNTAX_ERR;      /* number must be positive */
466     recent.gui_geometry_main_width = num;
467   } else if (strcmp(key, RECENT_GUI_GEOMETRY_MAIN_HEIGHT) == 0) {
468     num = strtol(value, &p, 0);
469     if (p == value || *p != '\0')
470       return PREFS_SET_SYNTAX_ERR;      /* number was bad */
471     if (num <= 0)
472       return PREFS_SET_SYNTAX_ERR;      /* number must be positive */
473     recent.gui_geometry_main_height = num;
474   } else if (strcmp(key, RECENT_GUI_GEOMETRY_STATUS_PANE_RIGHT) == 0) {
475     num = strtol(value, &p, 0);
476     if (p == value || *p != '\0')
477       return PREFS_SET_SYNTAX_ERR;      /* number was bad */
478     if (num <= 0)
479       return PREFS_SET_SYNTAX_ERR;      /* number must be positive */
480     recent.gui_geometry_status_pane_right = num;
481     recent.has_gui_geometry_status_pane = TRUE;
482   } else if (strcmp(key, RECENT_GUI_GEOMETRY_STATUS_PANE_LEFT) == 0) {
483     num = strtol(value, &p, 0);
484     if (p == value || *p != '\0')
485       return PREFS_SET_SYNTAX_ERR;      /* number was bad */
486     if (num <= 0)
487       return PREFS_SET_SYNTAX_ERR;      /* number must be positive */
488     recent.gui_geometry_status_pane_left = num;
489     recent.has_gui_geometry_status_pane = TRUE;
490   } else if (strcmp(key, RECENT_LAST_USED_PROFILE) == 0) {
491     if ((strcmp(value, DEFAULT_PROFILE) != 0) && profile_exists (value, FALSE)) {
492       set_profile_name (value);
493     }
494   } else if (strcmp(key, RECENT_GUI_GEOMETRY_WLAN_STATS_PANE) == 0) {
495     num = strtol(value, &p, 0);
496     if (p == value || *p != '\0')
497       return PREFS_SET_SYNTAX_ERR;      /* number was bad */
498     if (num <= 0)
499       return PREFS_SET_SYNTAX_ERR;      /* number must be positive */
500     recent.gui_geometry_wlan_stats_pane = num;
501   } else if (strncmp(key, RECENT_GUI_GEOMETRY, sizeof(RECENT_GUI_GEOMETRY)-1) == 0) {
502     /* now have something like "gui.geom.main.x", split it into win and sub_key */
503     char *win = &key[sizeof(RECENT_GUI_GEOMETRY)-1];
504     char *sub_key = strchr(win, '.');
505     if(sub_key) {
506       *sub_key = '\0';
507       sub_key++;
508       window_geom_recent_read_pair(win, sub_key, value);
509     }
510   } else if (strcmp(key, RECENT_KEY_PRIVS_WARN_IF_ELEVATED) == 0) {
511     if (g_ascii_strcasecmp(value, "true") == 0) {
512         recent.privs_warn_if_elevated = TRUE;
513     }
514     else {
515         recent.privs_warn_if_elevated = FALSE;
516     }
517   } else if (strcmp(key, RECENT_KEY_PRIVS_WARN_IF_NO_NPF) == 0) {
518     if (g_ascii_strcasecmp(value, "true") == 0) {
519         recent.privs_warn_if_no_npf = TRUE;
520     }
521     else {
522         recent.privs_warn_if_no_npf = FALSE;
523     }
524   }
525
526   return PREFS_SET_OK;
527 }
528
529 /* set one user's recent file key/value pair */
530 static prefs_set_pref_e
531 read_set_recent_pair_static(gchar *key, gchar *value, void *private_data _U_,
532                             gboolean return_range_errors _U_)
533 {
534   long num;
535   char *p;
536   GList *col_l, *col_l_elt;
537   col_width_data *cfmt;
538   const gchar *cust_format = col_format_to_string(COL_CUSTOM);
539   int cust_format_len = (int) strlen(cust_format);
540
541   if (strcmp(key, RECENT_KEY_MAIN_TOOLBAR_SHOW) == 0) {
542     if (g_ascii_strcasecmp(value, "true") == 0) {
543         recent.main_toolbar_show = TRUE;
544     }
545     else {
546         recent.main_toolbar_show = FALSE;
547     }
548   } else if (strcmp(key, RECENT_KEY_FILTER_TOOLBAR_SHOW) == 0) {
549     if (g_ascii_strcasecmp(value, "true") == 0) {
550         recent.filter_toolbar_show = TRUE;
551     }
552     else {
553         recent.filter_toolbar_show = FALSE;
554     }
555   } else if (strcmp(key, RECENT_KEY_AIRPCAP_TOOLBAR_SHOW) == 0) {
556     if (g_ascii_strcasecmp(value, "true") == 0) {
557         recent.airpcap_toolbar_show = TRUE;
558     }
559     else {
560         recent.airpcap_toolbar_show = FALSE;
561     }
562   } else if (strcmp(key, RECENT_KEY_DRIVER_CHECK_SHOW) == 0) {
563     if (g_ascii_strcasecmp(value, "true") == 0) {
564         recent.airpcap_driver_check_show = TRUE;
565     }
566     else {
567         recent.airpcap_driver_check_show = FALSE;
568     }
569   } else if (strcmp(key, RECENT_KEY_PACKET_LIST_SHOW) == 0) {
570     if (g_ascii_strcasecmp(value, "true") == 0) {
571         recent.packet_list_show = TRUE;
572     }
573     else {
574         recent.packet_list_show = FALSE;
575     }
576   } else if (strcmp(key, RECENT_KEY_TREE_VIEW_SHOW) == 0) {
577     if (g_ascii_strcasecmp(value, "true") == 0) {
578         recent.tree_view_show = TRUE;
579     }
580     else {
581         recent.tree_view_show = FALSE;
582     }
583   } else if (strcmp(key, RECENT_KEY_BYTE_VIEW_SHOW) == 0) {
584     if (g_ascii_strcasecmp(value, "true") == 0) {
585         recent.byte_view_show = TRUE;
586     }
587     else {
588         recent.byte_view_show = FALSE;
589     }
590   } else if (strcmp(key, RECENT_KEY_STATUSBAR_SHOW) == 0) {
591     if (g_ascii_strcasecmp(value, "true") == 0) {
592         recent.statusbar_show = TRUE;
593     }
594     else {
595         recent.statusbar_show = FALSE;
596     }
597   } else if (strcmp(key, RECENT_KEY_PACKET_LIST_COLORIZE) == 0) {
598     if (g_ascii_strcasecmp(value, "true") == 0) {
599         recent.packet_list_colorize = TRUE;
600     }
601     else {
602         recent.packet_list_colorize = FALSE;
603     }
604   } else if (strcmp(key, RECENT_GUI_TIME_FORMAT) == 0) {
605     recent.gui_time_format =
606         find_index_from_string_array(value, ts_type_text, TS_RELATIVE);
607   } else if (strcmp(key, RECENT_GUI_TIME_PRECISION) == 0) {
608     recent.gui_time_precision =
609         find_index_from_string_array(value, ts_precision_text, TS_PREC_AUTO);
610   } else if (strcmp(key, RECENT_GUI_SECONDS_FORMAT) == 0) {
611     recent.gui_seconds_format =
612         find_index_from_string_array(value, ts_seconds_text, TS_SECONDS_DEFAULT);
613   } else if (strcmp(key, RECENT_GUI_ZOOM_LEVEL) == 0) {
614     num = strtol(value, &p, 0);
615     if (p == value || *p != '\0')
616       return PREFS_SET_SYNTAX_ERR;      /* number was bad */
617     recent.gui_zoom_level = num;
618   } else if (strcmp(key, RECENT_GUI_BYTES_VIEW) == 0) {
619     num = strtol(value, &p, 0);
620     if (p == value || *p != '\0')
621       return PREFS_SET_SYNTAX_ERR;      /* number was bad */
622     recent.gui_bytes_view = num;
623   } else if (strcmp(key, RECENT_GUI_GEOMETRY_MAIN_MAXIMIZED) == 0) {
624     if (g_ascii_strcasecmp(value, "true") == 0) {
625         recent.gui_geometry_main_maximized = TRUE;
626     }
627     else {
628         recent.gui_geometry_main_maximized = FALSE;
629     }
630
631   } else if (strcmp(key, RECENT_GUI_GEOMETRY_MAIN_UPPER_PANE) == 0) {
632     num = strtol(value, &p, 0);
633     if (p == value || *p != '\0')
634       return PREFS_SET_SYNTAX_ERR;      /* number was bad */
635     if (num <= 0)
636       return PREFS_SET_SYNTAX_ERR;      /* number must be positive */
637     recent.gui_geometry_main_upper_pane = num;
638     recent.has_gui_geometry_main_upper_pane = TRUE;
639   } else if (strcmp(key, RECENT_GUI_GEOMETRY_MAIN_LOWER_PANE) == 0) {
640     num = strtol(value, &p, 0);
641     if (p == value || *p != '\0')
642       return PREFS_SET_SYNTAX_ERR;      /* number was bad */
643     if (num <= 0)
644       return PREFS_SET_SYNTAX_ERR;      /* number must be positive */
645     recent.gui_geometry_main_lower_pane = num;
646     recent.has_gui_geometry_main_lower_pane = TRUE;
647   }
648   else if (strcmp(key, RECENT_KEY_COL_WIDTH) == 0) {
649     col_l = prefs_get_string_list(value);
650     if (col_l == NULL)
651       return PREFS_SET_SYNTAX_ERR;
652     if ((g_list_length(col_l) % 2) != 0) {
653       /* A title didn't have a matching width.  */
654       prefs_clear_string_list(col_l);
655       return PREFS_SET_SYNTAX_ERR;
656     }
657     /* Check to make sure all column formats are valid.  */
658     col_l_elt = g_list_first(col_l);
659     while(col_l_elt) {
660       /* Make sure the format isn't empty.  */
661       if (strcmp(col_l_elt->data, "") == 0) {
662         /* It is.  */
663         prefs_clear_string_list(col_l);
664         return PREFS_SET_SYNTAX_ERR;
665       }
666
667       /* Check the format.  */
668       if (strncmp(col_l_elt->data, cust_format, cust_format_len) != 0) {
669         if (get_column_format_from_str(col_l_elt->data) == -1) {
670           /* It's not a valid column format.  */
671           prefs_clear_string_list(col_l);
672           return PREFS_SET_SYNTAX_ERR;
673         }
674       }
675
676       /* Go past the format.  */
677       col_l_elt = col_l_elt->next;
678
679       /* Go past the width.  */
680       col_l_elt = col_l_elt->next;
681     }
682     free_col_width_info(&recent);
683     recent.col_width_list = NULL;
684     col_l_elt = g_list_first(col_l);
685     while(col_l_elt) {
686       gchar *fmt = g_strdup(col_l_elt->data);
687       cfmt = (col_width_data *) g_malloc(sizeof(col_width_data));
688       if (strncmp(fmt, cust_format, cust_format_len) != 0) {
689         cfmt->cfmt   = get_column_format_from_str(fmt);
690         cfmt->cfield = NULL;
691       } else {
692         cfmt->cfmt   = COL_CUSTOM;
693         cfmt->cfield = g_strdup(&fmt[cust_format_len+1]);  /* add 1 for ':' */
694       }
695       g_free (fmt);
696       if (cfmt->cfmt == -1) {
697         g_free(cfmt->cfield);
698         g_free(cfmt);
699         return PREFS_SET_SYNTAX_ERR;   /* string was bad */
700       }
701
702       col_l_elt      = col_l_elt->next;
703       cfmt->width    = strtol(col_l_elt->data, &p, 0);
704       if (p == col_l_elt->data || (*p != '\0' && *p != ':')) {
705         g_free(cfmt->cfield);
706         g_free(cfmt);
707         return PREFS_SET_SYNTAX_ERR;    /* number was bad */
708       }
709
710       if (*p == ':') {
711         cfmt->xalign = *(++p);
712       } else {
713         cfmt->xalign = COLUMN_XALIGN_DEFAULT;
714       }
715
716       col_l_elt      = col_l_elt->next;
717       recent.col_width_list = g_list_append(recent.col_width_list, cfmt);
718     }
719     prefs_clear_string_list(col_l);
720   } else if (strcmp(key, RECENT_GUI_FILEOPEN_REMEMBERED_DIR) == 0) {
721     if (recent.gui_fileopen_remembered_dir) {
722       g_free (recent.gui_fileopen_remembered_dir);
723     }
724     recent.gui_fileopen_remembered_dir = g_strdup(value);
725   }
726
727   return PREFS_SET_OK;
728 }
729
730
731 /* set one user's recent file key/value pair */
732 static prefs_set_pref_e
733 read_set_recent_pair_dynamic(gchar *key, gchar *value, void *private_data _U_,
734                              gboolean return_range_errors _U_)
735 {
736   if (strcmp(key, RECENT_KEY_CAPTURE_FILE) == 0) {
737     if(u3_active())
738       add_menu_recent_capture_file(u3_expand_device_path(value));
739     else
740       add_menu_recent_capture_file(value);
741   } else if (strcmp(key, RECENT_KEY_DISPLAY_FILTER) == 0) {
742         dfilter_combo_add_recent(value);
743   } else if (strcmp(key, RECENT_KEY_CAPTURE_FILTER) == 0) {
744         cfilter_combo_add_recent(value);
745 #ifdef HAVE_PCAP_REMOTE
746   } else if (strcmp(key, RECENT_KEY_REMOTE_HOST) == 0) {
747         capture_remote_combo_add_recent(value);
748 #endif
749   }
750
751   return PREFS_SET_OK;
752 }
753
754
755 /*
756  * Given a string of the form "<recent name>:<recent value>", as might appear
757  * as an argument to a "-o" option, parse it and set the recent value in
758  * question.  Return an indication of whether it succeeded or failed
759  * in some fashion.
760  */
761 int
762 recent_set_arg(char *prefarg)
763 {
764         gchar *p, *colonp;
765         int ret;
766
767         colonp = strchr(prefarg, ':');
768         if (colonp == NULL)
769                 return PREFS_SET_SYNTAX_ERR;
770
771         p = colonp;
772         *p++ = '\0';
773
774         /*
775          * Skip over any white space (there probably won't be any, but
776          * as we allow it in the preferences file, we might as well
777          * allow it here).
778          */
779         while (isspace((guchar)*p))
780                 p++;
781         if (*p == '\0') {
782                 /*
783                  * Put the colon back, so if our caller uses, in an
784                  * error message, the string they passed us, the message
785                  * looks correct.
786                  */
787                 *colonp = ':';
788                 return PREFS_SET_SYNTAX_ERR;
789         }
790
791         ret = read_set_recent_pair_static(prefarg, p, NULL, TRUE);
792         *colonp = ':';  /* put the colon back */
793         return ret;
794 }
795
796
797 /* opens the user's recent common file and read the first part */
798 void
799 recent_read_static(char **rf_path_return, int *rf_errno_return)
800 {
801   char       *rf_path;
802   FILE       *rf;
803
804   /* set defaults */
805   recent.gui_geometry_main_x        =        20;
806   recent.gui_geometry_main_y        =        20;
807   recent.gui_geometry_main_width    = DEF_WIDTH;
808   recent.gui_geometry_main_height   = DEF_HEIGHT;
809   recent.gui_geometry_main_maximized=     FALSE;
810
811   recent.gui_geometry_status_pane_left  = (DEF_WIDTH/3);
812   recent.gui_geometry_status_pane_right = (DEF_WIDTH/3);
813   recent.gui_geometry_wlan_stats_pane = 200;
814
815   recent.privs_warn_if_elevated = TRUE;
816   recent.privs_warn_if_no_npf = TRUE;
817
818   recent.col_width_list = NULL;
819   recent.gui_fileopen_remembered_dir = NULL;
820
821   /* Construct the pathname of the user's recent common file. */
822   rf_path = get_persconffile_path(RECENT_COMMON_FILE_NAME, FALSE, FALSE);
823
824   /* Read the user's recent common file, if it exists. */
825   *rf_path_return = NULL;
826   if ((rf = ws_fopen(rf_path, "r")) != NULL) {
827     /* We succeeded in opening it; read it. */
828     read_prefs_file(rf_path, rf, read_set_recent_common_pair_static, NULL);
829
830     fclose(rf);
831     g_free(rf_path);
832     rf_path = NULL;
833   } else {
834     /* We failed to open it.  If we failed for some reason other than
835        "it doesn't exist", return the errno and the pathname, so our
836        caller can report the error. */
837     if (errno != ENOENT) {
838       *rf_errno_return = errno;
839       *rf_path_return = rf_path;
840     }
841   }
842 }
843
844
845
846 /* opens the user's recent file and read the first part */
847 void
848 recent_read_profile_static(char **rf_path_return, int *rf_errno_return)
849 {
850   char       *rf_path, *rf_common_path;
851   FILE       *rf;
852
853   /* set defaults */
854   recent.main_toolbar_show      = TRUE;
855   recent.filter_toolbar_show    = TRUE;
856   recent.airpcap_toolbar_show   = FALSE;
857   recent.airpcap_driver_check_show   = TRUE;
858   recent.packet_list_show       = TRUE;
859   recent.tree_view_show         = TRUE;
860   recent.byte_view_show         = TRUE;
861   recent.statusbar_show         = TRUE;
862   recent.packet_list_colorize   = TRUE;
863   recent.gui_time_format        = TS_RELATIVE;
864   recent.gui_time_precision     = TS_PREC_AUTO;
865   recent.gui_seconds_format     = TS_SECONDS_DEFAULT;
866   recent.gui_zoom_level         = 0;
867   recent.gui_bytes_view         = 0;
868
869   /* pane size of zero will autodetect */
870   recent.gui_geometry_main_upper_pane   = 0;
871   recent.gui_geometry_main_lower_pane   = 0;
872
873   recent.has_gui_geometry_main_upper_pane = TRUE;
874   recent.has_gui_geometry_main_lower_pane = TRUE;
875   recent.has_gui_geometry_status_pane = TRUE;
876
877   if (recent.col_width_list) {
878     free_col_width_info(&recent);
879   }
880
881   if (recent.gui_fileopen_remembered_dir) {
882     g_free (recent.gui_fileopen_remembered_dir);
883     recent.gui_fileopen_remembered_dir = NULL;
884   }
885
886   /* Construct the pathname of the user's profile recent file. */
887   rf_path = get_persconffile_path(RECENT_FILE_NAME, TRUE, FALSE);
888
889   /* Read the user's recent file, if it exists. */
890   *rf_path_return = NULL;
891   if ((rf = ws_fopen(rf_path, "r")) != NULL) {
892     /* We succeeded in opening it; read it. */
893     read_prefs_file(rf_path, rf, read_set_recent_pair_static, NULL);
894     fclose(rf);
895
896     /* XXX: The following code doesn't actually do anything since
897      *  the "recent common file" always exists. Presumably the
898      *  "if (!file_exists())" should actually be "if (file_exists())".
899      *  However, I've left the code as is because this
900      *  behaviour has existed for quite some time and I don't
901      *  know what's supposed to happen at this point.
902      *  ToDo: Determine if the "recent common file" should be read at this point
903      */
904     rf_common_path = get_persconffile_path(RECENT_COMMON_FILE_NAME, FALSE, FALSE);
905     if (!file_exists(rf_common_path)) {
906       /* Read older common settings from recent file */
907       rf = ws_fopen(rf_path, "r");
908       read_prefs_file(rf_path, rf, read_set_recent_common_pair_static, NULL);
909       fclose(rf);
910     }
911     g_free(rf_common_path);
912     g_free(rf_path);
913     rf_path = NULL;
914   } else {
915     /* We failed to open it.  If we failed for some reason other than
916        "it doesn't exist", return the errno and the pathname, so our
917        caller can report the error. */
918     if (errno != ENOENT) {
919       *rf_errno_return = errno;
920       *rf_path_return = rf_path;
921     }
922   }
923 }
924
925 /* opens the user's recent file and read it out */
926 void
927 recent_read_dynamic(char **rf_path_return, int *rf_errno_return)
928 {
929   char       *rf_path;
930   FILE       *rf;
931
932
933   /* Construct the pathname of the user's recent common file. */
934   rf_path = get_persconffile_path(RECENT_COMMON_FILE_NAME, FALSE, FALSE);
935   if (!file_exists (rf_path)) {
936     /* Recent common file does not exist, read from default recent */
937     g_free (rf_path);
938     rf_path = get_persconffile_path(RECENT_FILE_NAME, FALSE, FALSE);
939   }
940
941   /* Read the user's recent file, if it exists. */
942   *rf_path_return = NULL;
943   if ((rf = ws_fopen(rf_path, "r")) != NULL) {
944     /* We succeeded in opening it; read it. */
945     read_prefs_file(rf_path, rf, read_set_recent_pair_dynamic, NULL);
946 #if 0
947     /* set dfilter combobox to have an empty line */
948     dfilter_combo_add_empty();
949 #endif
950     fclose(rf);
951     g_free(rf_path);
952     rf_path = NULL;
953   } else {
954     /* We failed to open it.  If we failed for some reason other than
955        "it doesn't exist", return the errno and the pathname, so our
956        caller can report the error. */
957     if (errno != ENOENT) {
958       *rf_errno_return = errno;
959       *rf_path_return = rf_path;
960     }
961   }
962 }
963
964 gint
965 recent_get_column_width(gint col)
966 {
967   GList *col_l;
968   col_width_data *col_w;
969   gint cfmt;
970   const gchar *cfield = NULL;
971
972   cfmt = get_column_format(col);
973   if (cfmt == COL_CUSTOM) {
974     cfield = get_column_custom_field(col);
975   }
976
977   col_l = g_list_first(recent.col_width_list);
978   while (col_l) {
979     col_w = (col_width_data *) col_l->data;
980     if (col_w->cfmt == cfmt) {
981       if (cfmt != COL_CUSTOM || strcmp (cfield, col_w->cfield) == 0) {
982         return col_w->width;
983       }
984     }
985     col_l = col_l->next;
986   }
987
988   return -1;
989 }
990
991 void
992 recent_set_column_width(gint col, gint width)
993 {
994   GList *col_l;
995   col_width_data *col_w;
996   gint cfmt;
997   const gchar *cfield = NULL;
998   gboolean found = FALSE;
999
1000   cfmt = get_column_format(col);
1001   if (cfmt == COL_CUSTOM) {
1002     cfield = get_column_custom_field(col);
1003   }
1004
1005   col_l = g_list_first(recent.col_width_list);
1006   while (col_l) {
1007     col_w = (col_width_data *) col_l->data;
1008     if (col_w->cfmt == cfmt) {
1009       if (cfmt != COL_CUSTOM || strcmp (cfield, col_w->cfield) == 0) {
1010         col_w->width = width;
1011         found = TRUE;
1012         break;
1013       }
1014     }
1015     col_l = col_l->next;
1016   }
1017
1018   if (!found) {
1019     col_w = (col_width_data *) g_malloc(sizeof(col_width_data));
1020     col_w->cfmt = cfmt;
1021     if (cfield) {
1022       col_w->cfield = g_strdup(cfield);
1023     } else {
1024       col_w->cfield = NULL;
1025     }
1026     col_w->width = width;
1027     col_w->xalign = COLUMN_XALIGN_DEFAULT;
1028     recent.col_width_list = g_list_append(recent.col_width_list, col_w);
1029   }
1030 }
1031
1032 gchar
1033 recent_get_column_xalign(gint col)
1034 {
1035   GList *col_l;
1036   col_width_data *col_w;
1037   gint cfmt;
1038   const gchar *cfield = NULL;
1039
1040   cfmt = get_column_format(col);
1041   if (cfmt == COL_CUSTOM) {
1042     cfield = get_column_custom_field(col);
1043   }
1044
1045   col_l = g_list_first(recent.col_width_list);
1046   while (col_l) {
1047     col_w = (col_width_data *) col_l->data;
1048     if (col_w->cfmt == cfmt) {
1049       if (cfmt != COL_CUSTOM || strcmp (cfield, col_w->cfield) == 0) {
1050         return col_w->xalign;
1051       }
1052     }
1053     col_l = col_l->next;
1054   }
1055
1056   return 0;
1057 }
1058
1059 void
1060 recent_set_column_xalign(gint col, gchar xalign)
1061 {
1062   GList *col_l;
1063   col_width_data *col_w;
1064   gint cfmt;
1065   const gchar *cfield = NULL;
1066   gboolean found = FALSE;
1067
1068   cfmt = get_column_format(col);
1069   if (cfmt == COL_CUSTOM) {
1070     cfield = get_column_custom_field(col);
1071   }
1072
1073   col_l = g_list_first(recent.col_width_list);
1074   while (col_l) {
1075     col_w = (col_width_data *) col_l->data;
1076     if (col_w->cfmt == cfmt) {
1077       if (cfmt != COL_CUSTOM || strcmp (cfield, col_w->cfield) == 0) {
1078         col_w->xalign = xalign;
1079         found = TRUE;
1080         break;
1081       }
1082     }
1083     col_l = col_l->next;
1084   }
1085
1086   if (!found) {
1087     col_w = (col_width_data *) g_malloc(sizeof(col_width_data));
1088     col_w->cfmt = cfmt;
1089     if (cfield) {
1090       col_w->cfield = g_strdup(cfield);
1091     } else {
1092       col_w->cfield = NULL;
1093     }
1094     col_w->width = 40;
1095     col_w->xalign = xalign;
1096     recent.col_width_list = g_list_append(recent.col_width_list, col_w);
1097   }
1098 }
1099