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