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