From Evan Huus in bug 7295:
[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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, 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_AIRPCAP_TOOLBAR_SHOW     "gui.airpcap_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 #ifdef HAVE_AIRPCAP
309   fprintf(rf, "\n# Wireless Settings Toolbar show (hide).\n");
310   fprintf(rf, "# TRUE or FALSE (case-insensitive).\n");
311   fprintf(rf, RECENT_KEY_AIRPCAP_TOOLBAR_SHOW ": %s\n",
312                   recent.airpcap_toolbar_show == TRUE ? "TRUE" : "FALSE");
313 #endif
314
315 #ifdef HAVE_AIRPCAP
316   fprintf(rf, "\n# Show (hide) old AirPcap driver warning dialog box.\n");
317   fprintf(rf, "# TRUE or FALSE (case-insensitive).\n");
318   fprintf(rf, RECENT_KEY_DRIVER_CHECK_SHOW ": %s\n",
319                   recent.airpcap_driver_check_show == TRUE ? "TRUE" : "FALSE");
320 #endif
321
322   fprintf(rf, "\n# Packet list show (hide).\n");
323   fprintf(rf, "# TRUE or FALSE (case-insensitive).\n");
324   fprintf(rf, RECENT_KEY_PACKET_LIST_SHOW ": %s\n",
325                   recent.packet_list_show == TRUE ? "TRUE" : "FALSE");
326
327   fprintf(rf, "\n# Tree view show (hide).\n");
328   fprintf(rf, "# TRUE or FALSE (case-insensitive).\n");
329   fprintf(rf, RECENT_KEY_TREE_VIEW_SHOW ": %s\n",
330                   recent.tree_view_show == TRUE ? "TRUE" : "FALSE");
331
332   fprintf(rf, "\n# Byte view show (hide).\n");
333   fprintf(rf, "# TRUE or FALSE (case-insensitive).\n");
334   fprintf(rf, RECENT_KEY_BYTE_VIEW_SHOW ": %s\n",
335                   recent.byte_view_show == TRUE ? "TRUE" : "FALSE");
336
337   fprintf(rf, "\n# Statusbar show (hide).\n");
338   fprintf(rf, "# TRUE or FALSE (case-insensitive).\n");
339   fprintf(rf, RECENT_KEY_STATUSBAR_SHOW ": %s\n",
340                   recent.statusbar_show == TRUE ? "TRUE" : "FALSE");
341
342   fprintf(rf, "\n# Packet list colorize (hide).\n");
343   fprintf(rf, "# TRUE or FALSE (case-insensitive).\n");
344   fprintf(rf, RECENT_KEY_PACKET_LIST_COLORIZE ": %s\n",
345                   recent.packet_list_colorize == TRUE ? "TRUE" : "FALSE");
346
347   fprintf(rf, "\n# Timestamp display format.\n");
348   fprintf(rf, "# One of: RELATIVE, ABSOLUTE, ABSOLUTE_WITH_DATE, DELTA, DELTA_DIS, EPOCH, UTC, UTC_WITH_DATE\n");
349   fprintf(rf, RECENT_GUI_TIME_FORMAT ": %s\n",
350           ts_type_text[recent.gui_time_format]);
351
352   fprintf(rf, "\n# Timestamp display precision.\n");
353   fprintf(rf, "# One of: AUTO, SEC, DSEC, CSEC, MSEC, USEC, NSEC\n");
354   fprintf(rf, RECENT_GUI_TIME_PRECISION ": %s\n",
355           ts_precision_text[recent.gui_time_precision]);
356
357   fprintf(rf, "\n# Seconds display format.\n");
358   fprintf(rf, "# One of: SECONDS, HOUR_MIN_SEC\n");
359   fprintf(rf, RECENT_GUI_SECONDS_FORMAT ": %s\n",
360           ts_seconds_text[recent.gui_seconds_format]);
361
362   fprintf(rf, "\n# Zoom level.\n");
363   fprintf(rf, "# A decimal number.\n");
364   fprintf(rf, RECENT_GUI_ZOOM_LEVEL ": %d\n",
365                   recent.gui_zoom_level);
366
367   fprintf(rf, "\n# Bytes view.\n");
368   fprintf(rf, "# A decimal number.\n");
369   fprintf(rf, RECENT_GUI_BYTES_VIEW ": %d\n",
370                   recent.gui_bytes_view);
371
372   fprintf(rf, "\n# Main window upper (or leftmost) pane size.\n");
373   fprintf(rf, "# Decimal number.\n");
374   if (recent.gui_geometry_main_upper_pane != 0) {
375     fprintf(rf, RECENT_GUI_GEOMETRY_MAIN_UPPER_PANE ": %d\n",
376                   recent.gui_geometry_main_upper_pane);
377   }
378   fprintf(rf, "\n# Main window middle pane size.\n");
379   fprintf(rf, "# Decimal number.\n");
380   if (recent.gui_geometry_main_lower_pane != 0) {
381     fprintf(rf, RECENT_GUI_GEOMETRY_MAIN_LOWER_PANE ": %d\n",
382                   recent.gui_geometry_main_lower_pane);
383   }
384
385   fprintf(rf, "\n# Packet list column pixel widths.\n");
386   fprintf(rf, "# Each pair of strings consists of a column format and its pixel width.\n");
387   new_packet_list_recent_write_all(rf);
388
389   if (get_last_open_dir() != NULL) {
390     fprintf(rf, "\n# Last directory navigated to in File Open dialog.\n");
391
392     if(u3_active())
393       fprintf(rf, RECENT_GUI_FILEOPEN_REMEMBERED_DIR ": %s\n", u3_contract_device_path(get_last_open_dir()));
394     else
395       fprintf(rf, RECENT_GUI_FILEOPEN_REMEMBERED_DIR ": %s\n", get_last_open_dir());
396   }
397
398   fclose(rf);
399
400   /* XXX - catch I/O errors (e.g. "ran out of disk space") and return
401      an error indication, or maybe write to a new recent file and
402      rename that file on top of the old one only if there are not I/O
403      errors. */
404   return TRUE;
405 }
406
407
408 /* write the geometry values of a window to recent file */
409 void
410 write_recent_geom(gpointer key _U_, gpointer value, gpointer rf)
411 {
412     window_geometry_t *geom = value;
413
414     fprintf(rf, "\n# Geometry and maximized state of %s window.\n", geom->key);
415     fprintf(rf, "# Decimal integers.\n");
416     fprintf(rf, RECENT_GUI_GEOMETRY "%s.x: %d\n", geom->key, geom->x);
417     fprintf(rf, RECENT_GUI_GEOMETRY "%s.y: %d\n", geom->key, geom->y);
418     fprintf(rf, RECENT_GUI_GEOMETRY "%s.width: %d\n", geom->key,
419               geom->width);
420     fprintf(rf, RECENT_GUI_GEOMETRY "%s.height: %d\n", geom->key,
421               geom->height);
422
423     fprintf(rf, "# TRUE or FALSE (case-insensitive).\n");
424     fprintf(rf, RECENT_GUI_GEOMETRY "%s.maximized: %s\n", geom->key,
425               geom->maximized == TRUE ? "TRUE" : "FALSE");
426
427 }
428
429 /* set one user's recent common file key/value pair */
430 static prefs_set_pref_e
431 read_set_recent_common_pair_static(gchar *key, gchar *value,
432                                    void *private_data _U_,
433                                    gboolean return_range_errors _U_)
434 {
435   long num;
436   char *p;
437
438   if (strcmp(key, RECENT_GUI_GEOMETRY_MAIN_MAXIMIZED) == 0) {
439     if (g_ascii_strcasecmp(value, "true") == 0) {
440         recent.gui_geometry_main_maximized = TRUE;
441     }
442     else {
443         recent.gui_geometry_main_maximized = FALSE;
444     }
445
446   } else if (strcmp(key, RECENT_GUI_GEOMETRY_MAIN_X) == 0) {
447     num = strtol(value, &p, 0);
448     if (p == value || *p != '\0')
449       return PREFS_SET_SYNTAX_ERR;      /* number was bad */
450     recent.gui_geometry_main_x = num;
451   } else if (strcmp(key, RECENT_GUI_GEOMETRY_MAIN_Y) == 0) {
452     num = strtol(value, &p, 0);
453     if (p == value || *p != '\0')
454       return PREFS_SET_SYNTAX_ERR;      /* number was bad */
455     recent.gui_geometry_main_y = num;
456   } else if (strcmp(key, RECENT_GUI_GEOMETRY_MAIN_WIDTH) == 0) {
457     num = strtol(value, &p, 0);
458     if (p == value || *p != '\0')
459       return PREFS_SET_SYNTAX_ERR;      /* number was bad */
460     if (num <= 0)
461       return PREFS_SET_SYNTAX_ERR;      /* number must be positive */
462     recent.gui_geometry_main_width = num;
463   } else if (strcmp(key, RECENT_GUI_GEOMETRY_MAIN_HEIGHT) == 0) {
464     num = strtol(value, &p, 0);
465     if (p == value || *p != '\0')
466       return PREFS_SET_SYNTAX_ERR;      /* number was bad */
467     if (num <= 0)
468       return PREFS_SET_SYNTAX_ERR;      /* number must be positive */
469     recent.gui_geometry_main_height = num;
470   } else if (strcmp(key, RECENT_GUI_GEOMETRY_STATUS_PANE_RIGHT) == 0) {
471     num = strtol(value, &p, 0);
472     if (p == value || *p != '\0')
473       return PREFS_SET_SYNTAX_ERR;      /* number was bad */
474     if (num <= 0)
475       return PREFS_SET_SYNTAX_ERR;      /* number must be positive */
476     recent.gui_geometry_status_pane_right = num;
477     recent.has_gui_geometry_status_pane = TRUE;
478   } else if (strcmp(key, RECENT_GUI_GEOMETRY_STATUS_PANE_LEFT) == 0) {
479     num = strtol(value, &p, 0);
480     if (p == value || *p != '\0')
481       return PREFS_SET_SYNTAX_ERR;      /* number was bad */
482     if (num <= 0)
483       return PREFS_SET_SYNTAX_ERR;      /* number must be positive */
484     recent.gui_geometry_status_pane_left = num;
485     recent.has_gui_geometry_status_pane = TRUE;
486   } else if (strcmp(key, RECENT_LAST_USED_PROFILE) == 0) {
487     if ((strcmp(value, DEFAULT_PROFILE) != 0) && profile_exists (value, FALSE)) {
488       set_profile_name (value);
489     }
490   } else if (strcmp(key, RECENT_GUI_GEOMETRY_WLAN_STATS_PANE) == 0) {
491     num = strtol(value, &p, 0);
492     if (p == value || *p != '\0')
493       return PREFS_SET_SYNTAX_ERR;      /* number was bad */
494     if (num <= 0)
495       return PREFS_SET_SYNTAX_ERR;      /* number must be positive */
496     recent.gui_geometry_wlan_stats_pane = num;
497   } else if (strncmp(key, RECENT_GUI_GEOMETRY, sizeof(RECENT_GUI_GEOMETRY)-1) == 0) {
498     /* now have something like "gui.geom.main.x", split it into win and sub_key */
499     char *win = &key[sizeof(RECENT_GUI_GEOMETRY)-1];
500     char *sub_key = strchr(win, '.');
501     if(sub_key) {
502       *sub_key = '\0';
503       sub_key++;
504       window_geom_recent_read_pair(win, sub_key, value);
505     }
506   } else if (strcmp(key, RECENT_KEY_PRIVS_WARN_IF_ELEVATED) == 0) {
507     if (g_ascii_strcasecmp(value, "true") == 0) {
508         recent.privs_warn_if_elevated = TRUE;
509     }
510     else {
511         recent.privs_warn_if_elevated = FALSE;
512     }
513   } else if (strcmp(key, RECENT_KEY_PRIVS_WARN_IF_NO_NPF) == 0) {
514     if (g_ascii_strcasecmp(value, "true") == 0) {
515         recent.privs_warn_if_no_npf = TRUE;
516     }
517     else {
518         recent.privs_warn_if_no_npf = FALSE;
519     }
520   }
521
522   return PREFS_SET_OK;
523 }
524
525 /* set one user's recent file key/value pair */
526 static prefs_set_pref_e
527 read_set_recent_pair_static(gchar *key, gchar *value, void *private_data _U_,
528                             gboolean return_range_errors _U_)
529 {
530   long num;
531   char *p;
532   GList *col_l, *col_l_elt;
533   col_width_data *cfmt;
534   const gchar *cust_format = col_format_to_string(COL_CUSTOM);
535   int cust_format_len = (int) strlen(cust_format);
536
537   if (strcmp(key, RECENT_KEY_MAIN_TOOLBAR_SHOW) == 0) {
538     if (g_ascii_strcasecmp(value, "true") == 0) {
539         recent.main_toolbar_show = TRUE;
540     }
541     else {
542         recent.main_toolbar_show = FALSE;
543     }
544   } else if (strcmp(key, RECENT_KEY_FILTER_TOOLBAR_SHOW) == 0) {
545     if (g_ascii_strcasecmp(value, "true") == 0) {
546         recent.filter_toolbar_show = TRUE;
547     }
548     else {
549         recent.filter_toolbar_show = FALSE;
550     }
551   } else if (strcmp(key, RECENT_KEY_AIRPCAP_TOOLBAR_SHOW) == 0) {
552     if (g_ascii_strcasecmp(value, "true") == 0) {
553         recent.airpcap_toolbar_show = TRUE;
554     }
555     else {
556         recent.airpcap_toolbar_show = FALSE;
557     }
558   } else if (strcmp(key, RECENT_KEY_DRIVER_CHECK_SHOW) == 0) {
559     if (g_ascii_strcasecmp(value, "true") == 0) {
560         recent.airpcap_driver_check_show = TRUE;
561     }
562     else {
563         recent.airpcap_driver_check_show = FALSE;
564     }
565   } else if (strcmp(key, RECENT_KEY_PACKET_LIST_SHOW) == 0) {
566     if (g_ascii_strcasecmp(value, "true") == 0) {
567         recent.packet_list_show = TRUE;
568     }
569     else {
570         recent.packet_list_show = FALSE;
571     }
572   } else if (strcmp(key, RECENT_KEY_TREE_VIEW_SHOW) == 0) {
573     if (g_ascii_strcasecmp(value, "true") == 0) {
574         recent.tree_view_show = TRUE;
575     }
576     else {
577         recent.tree_view_show = FALSE;
578     }
579   } else if (strcmp(key, RECENT_KEY_BYTE_VIEW_SHOW) == 0) {
580     if (g_ascii_strcasecmp(value, "true") == 0) {
581         recent.byte_view_show = TRUE;
582     }
583     else {
584         recent.byte_view_show = FALSE;
585     }
586   } else if (strcmp(key, RECENT_KEY_STATUSBAR_SHOW) == 0) {
587     if (g_ascii_strcasecmp(value, "true") == 0) {
588         recent.statusbar_show = TRUE;
589     }
590     else {
591         recent.statusbar_show = FALSE;
592     }
593   } else if (strcmp(key, RECENT_KEY_PACKET_LIST_COLORIZE) == 0) {
594     if (g_ascii_strcasecmp(value, "true") == 0) {
595         recent.packet_list_colorize = TRUE;
596     }
597     else {
598         recent.packet_list_colorize = FALSE;
599     }
600   } else if (strcmp(key, RECENT_GUI_TIME_FORMAT) == 0) {
601     recent.gui_time_format =
602         find_index_from_string_array(value, ts_type_text, TS_RELATIVE);
603   } else if (strcmp(key, RECENT_GUI_TIME_PRECISION) == 0) {
604     recent.gui_time_precision =
605         find_index_from_string_array(value, ts_precision_text, TS_PREC_AUTO);
606   } else if (strcmp(key, RECENT_GUI_SECONDS_FORMAT) == 0) {
607     recent.gui_seconds_format =
608         find_index_from_string_array(value, ts_seconds_text, TS_SECONDS_DEFAULT);
609   } else if (strcmp(key, RECENT_GUI_ZOOM_LEVEL) == 0) {
610     num = strtol(value, &p, 0);
611     if (p == value || *p != '\0')
612       return PREFS_SET_SYNTAX_ERR;      /* number was bad */
613     recent.gui_zoom_level = num;
614   } else if (strcmp(key, RECENT_GUI_BYTES_VIEW) == 0) {
615     num = strtol(value, &p, 0);
616     if (p == value || *p != '\0')
617       return PREFS_SET_SYNTAX_ERR;      /* number was bad */
618     recent.gui_bytes_view = num;
619   } else if (strcmp(key, RECENT_GUI_GEOMETRY_MAIN_MAXIMIZED) == 0) {
620     if (g_ascii_strcasecmp(value, "true") == 0) {
621         recent.gui_geometry_main_maximized = TRUE;
622     }
623     else {
624         recent.gui_geometry_main_maximized = FALSE;
625     }
626
627   } else if (strcmp(key, RECENT_GUI_GEOMETRY_MAIN_UPPER_PANE) == 0) {
628     num = strtol(value, &p, 0);
629     if (p == value || *p != '\0')
630       return PREFS_SET_SYNTAX_ERR;      /* number was bad */
631     if (num <= 0)
632       return PREFS_SET_SYNTAX_ERR;      /* number must be positive */
633     recent.gui_geometry_main_upper_pane = num;
634     recent.has_gui_geometry_main_upper_pane = TRUE;
635   } else if (strcmp(key, RECENT_GUI_GEOMETRY_MAIN_LOWER_PANE) == 0) {
636     num = strtol(value, &p, 0);
637     if (p == value || *p != '\0')
638       return PREFS_SET_SYNTAX_ERR;      /* number was bad */
639     if (num <= 0)
640       return PREFS_SET_SYNTAX_ERR;      /* number must be positive */
641     recent.gui_geometry_main_lower_pane = num;
642     recent.has_gui_geometry_main_lower_pane = TRUE;
643   }
644   else if (strcmp(key, RECENT_KEY_COL_WIDTH) == 0) {
645     col_l = prefs_get_string_list(value);
646     if (col_l == NULL)
647       return PREFS_SET_SYNTAX_ERR;
648     if ((g_list_length(col_l) % 2) != 0) {
649       /* A title didn't have a matching width.  */
650       prefs_clear_string_list(col_l);
651       return PREFS_SET_SYNTAX_ERR;
652     }
653     /* Check to make sure all column formats are valid.  */
654     col_l_elt = g_list_first(col_l);
655     while(col_l_elt) {
656       /* Make sure the format isn't empty.  */
657       if (strcmp(col_l_elt->data, "") == 0) {
658         /* It is.  */
659         prefs_clear_string_list(col_l);
660         return PREFS_SET_SYNTAX_ERR;
661       }
662
663       /* Check the format.  */
664       if (strncmp(col_l_elt->data, cust_format, cust_format_len) != 0) {
665         if (get_column_format_from_str(col_l_elt->data) == -1) {
666           /* It's not a valid column format.  */
667           prefs_clear_string_list(col_l);
668           return PREFS_SET_SYNTAX_ERR;
669         }
670       }
671
672       /* Go past the format.  */
673       col_l_elt = col_l_elt->next;
674
675       /* Go past the width.  */
676       col_l_elt = col_l_elt->next;
677     }
678     free_col_width_info(&recent);
679     recent.col_width_list = NULL;
680     col_l_elt = g_list_first(col_l);
681     while(col_l_elt) {
682       gchar *fmt = g_strdup(col_l_elt->data);
683       cfmt = (col_width_data *) g_malloc(sizeof(col_width_data));
684       if (strncmp(fmt, cust_format, cust_format_len) != 0) {
685         cfmt->cfmt   = get_column_format_from_str(fmt);
686         cfmt->cfield = NULL;
687       } else {
688         cfmt->cfmt   = COL_CUSTOM;
689         cfmt->cfield = g_strdup(&fmt[cust_format_len+1]);  /* add 1 for ':' */
690       }
691       g_free (fmt);
692       if (cfmt->cfmt == -1) {
693         g_free(cfmt->cfield);
694         g_free(cfmt);
695         return PREFS_SET_SYNTAX_ERR;   /* string was bad */
696       }
697
698       col_l_elt      = col_l_elt->next;
699       cfmt->width    = strtol(col_l_elt->data, &p, 0);
700       if (p == col_l_elt->data || (*p != '\0' && *p != ':')) {
701         g_free(cfmt->cfield);
702         g_free(cfmt);
703         return PREFS_SET_SYNTAX_ERR;    /* number was bad */
704       }
705
706       if (*p == ':') {
707         cfmt->xalign = *(++p);
708       } else {
709         cfmt->xalign = COLUMN_XALIGN_DEFAULT;
710       }
711
712       col_l_elt      = col_l_elt->next;
713       recent.col_width_list = g_list_append(recent.col_width_list, cfmt);
714     }
715     prefs_clear_string_list(col_l);
716   } else if (strcmp(key, RECENT_GUI_FILEOPEN_REMEMBERED_DIR) == 0) {
717     if (recent.gui_fileopen_remembered_dir) {
718       g_free (recent.gui_fileopen_remembered_dir);
719     }
720     recent.gui_fileopen_remembered_dir = g_strdup(value);
721   }
722
723   return PREFS_SET_OK;
724 }
725
726
727 /* set one user's recent file key/value pair */
728 static prefs_set_pref_e
729 read_set_recent_pair_dynamic(gchar *key, gchar *value, void *private_data _U_,
730                              gboolean return_range_errors _U_)
731 {
732   if (!isprint_string(value)) {
733     return PREFS_SET_SYNTAX_ERR;
734   }
735   if (strcmp(key, RECENT_KEY_CAPTURE_FILE) == 0) {
736     if(u3_active())
737       add_menu_recent_capture_file(u3_expand_device_path(value));
738     else
739       add_menu_recent_capture_file(value);
740   } else if (strcmp(key, RECENT_KEY_DISPLAY_FILTER) == 0) {
741         dfilter_combo_add_recent(value);
742   } else if (strcmp(key, RECENT_KEY_CAPTURE_FILTER) == 0) {
743         cfilter_combo_add_recent(value);
744 #ifdef HAVE_PCAP_REMOTE
745   } else if (strcmp(key, RECENT_KEY_REMOTE_HOST) == 0) {
746         capture_remote_combo_add_recent(value);
747 #endif
748   }
749
750   return PREFS_SET_OK;
751 }
752
753
754 /*
755  * Given a string of the form "<recent name>:<recent value>", as might appear
756  * as an argument to a "-o" option, parse it and set the recent value in
757  * question.  Return an indication of whether it succeeded or failed
758  * in some fashion.
759  */
760 int
761 recent_set_arg(char *prefarg)
762 {
763         gchar *p, *colonp;
764         int ret;
765
766         colonp = strchr(prefarg, ':');
767         if (colonp == NULL)
768                 return PREFS_SET_SYNTAX_ERR;
769
770         p = colonp;
771         *p++ = '\0';
772
773         /*
774          * Skip over any white space (there probably won't be any, but
775          * as we allow it in the preferences file, we might as well
776          * allow it here).
777          */
778         while (isspace((guchar)*p))
779                 p++;
780         if (*p == '\0') {
781                 /*
782                  * Put the colon back, so if our caller uses, in an
783                  * error message, the string they passed us, the message
784                  * looks correct.
785                  */
786                 *colonp = ':';
787                 return PREFS_SET_SYNTAX_ERR;
788         }
789
790         ret = read_set_recent_pair_static(prefarg, p, NULL, TRUE);
791         *colonp = ':';  /* put the colon back */
792         return ret;
793 }
794
795
796 /* opens the user's recent common file and read the first part */
797 void
798 recent_read_static(char **rf_path_return, int *rf_errno_return)
799 {
800   char       *rf_path;
801   FILE       *rf;
802
803   /* set defaults */
804   recent.gui_geometry_main_x        =        20;
805   recent.gui_geometry_main_y        =        20;
806   recent.gui_geometry_main_width    = DEF_WIDTH;
807   recent.gui_geometry_main_height   = DEF_HEIGHT;
808   recent.gui_geometry_main_maximized=     FALSE;
809
810   recent.gui_geometry_status_pane_left  = (DEF_WIDTH/3);
811   recent.gui_geometry_status_pane_right = (DEF_WIDTH/3);
812   recent.gui_geometry_wlan_stats_pane = 200;
813
814   recent.privs_warn_if_elevated = TRUE;
815   recent.privs_warn_if_no_npf = TRUE;
816
817   recent.col_width_list = NULL;
818   recent.gui_fileopen_remembered_dir = NULL;
819
820   /* Construct the pathname of the user's recent common file. */
821   rf_path = get_persconffile_path(RECENT_COMMON_FILE_NAME, FALSE, FALSE);
822
823   /* Read the user's recent common file, if it exists. */
824   *rf_path_return = NULL;
825   if ((rf = ws_fopen(rf_path, "r")) != NULL) {
826     /* We succeeded in opening it; read it. */
827     read_prefs_file(rf_path, rf, read_set_recent_common_pair_static, NULL);
828
829     fclose(rf);
830     g_free(rf_path);
831     rf_path = NULL;
832   } else {
833     /* We failed to open it.  If we failed for some reason other than
834        "it doesn't exist", return the errno and the pathname, so our
835        caller can report the error. */
836     if (errno != ENOENT) {
837       *rf_errno_return = errno;
838       *rf_path_return = rf_path;
839     }
840   }
841 }
842
843
844
845 /* opens the user's recent file and read the first part */
846 void
847 recent_read_profile_static(char **rf_path_return, int *rf_errno_return)
848 {
849   char       *rf_path, *rf_common_path;
850   FILE       *rf;
851
852   /* set defaults */
853   recent.main_toolbar_show      = TRUE;
854   recent.filter_toolbar_show    = TRUE;
855   recent.airpcap_toolbar_show   = FALSE;
856   recent.airpcap_driver_check_show   = TRUE;
857   recent.packet_list_show       = TRUE;
858   recent.tree_view_show         = TRUE;
859   recent.byte_view_show         = TRUE;
860   recent.statusbar_show         = TRUE;
861   recent.packet_list_colorize   = TRUE;
862   recent.gui_time_format        = TS_RELATIVE;
863   recent.gui_time_precision     = TS_PREC_AUTO;
864   recent.gui_seconds_format     = TS_SECONDS_DEFAULT;
865   recent.gui_zoom_level         = 0;
866   recent.gui_bytes_view         = 0;
867
868   /* pane size of zero will autodetect */
869   recent.gui_geometry_main_upper_pane   = 0;
870   recent.gui_geometry_main_lower_pane   = 0;
871
872   recent.has_gui_geometry_main_upper_pane = TRUE;
873   recent.has_gui_geometry_main_lower_pane = TRUE;
874   recent.has_gui_geometry_status_pane = TRUE;
875
876   if (recent.col_width_list) {
877     free_col_width_info(&recent);
878   }
879
880   if (recent.gui_fileopen_remembered_dir) {
881     g_free (recent.gui_fileopen_remembered_dir);
882     recent.gui_fileopen_remembered_dir = NULL;
883   }
884
885   /* Construct the pathname of the user's profile recent file. */
886   rf_path = get_persconffile_path(RECENT_FILE_NAME, TRUE, FALSE);
887
888   /* Read the user's recent file, if it exists. */
889   *rf_path_return = NULL;
890   if ((rf = ws_fopen(rf_path, "r")) != NULL) {
891     /* We succeeded in opening it; read it. */
892     read_prefs_file(rf_path, rf, read_set_recent_pair_static, NULL);
893     fclose(rf);
894
895     /* XXX: The following code doesn't actually do anything since
896      *  the "recent common file" always exists. Presumably the
897      *  "if (!file_exists())" should actually be "if (file_exists())".
898      *  However, I've left the code as is because this
899      *  behaviour has existed for quite some time and I don't
900      *  know what's supposed to happen at this point.
901      *  ToDo: Determine if the "recent common file" should be read at this point
902      */
903     rf_common_path = get_persconffile_path(RECENT_COMMON_FILE_NAME, FALSE, FALSE);
904     if (!file_exists(rf_common_path)) {
905       /* Read older common settings from recent file */
906       rf = ws_fopen(rf_path, "r");
907       read_prefs_file(rf_path, rf, read_set_recent_common_pair_static, NULL);
908       fclose(rf);
909     }
910     g_free(rf_common_path);
911     g_free(rf_path);
912     rf_path = NULL;
913   } else {
914     /* We failed to open it.  If we failed for some reason other than
915        "it doesn't exist", return the errno and the pathname, so our
916        caller can report the error. */
917     if (errno != ENOENT) {
918       *rf_errno_return = errno;
919       *rf_path_return = rf_path;
920     }
921   }
922 }
923
924 /* opens the user's recent file and read it out */
925 void
926 recent_read_dynamic(char **rf_path_return, int *rf_errno_return)
927 {
928   char       *rf_path;
929   FILE       *rf;
930
931
932   /* Construct the pathname of the user's recent common file. */
933   rf_path = get_persconffile_path(RECENT_COMMON_FILE_NAME, FALSE, FALSE);
934   if (!file_exists (rf_path)) {
935     /* Recent common file does not exist, read from default recent */
936     g_free (rf_path);
937     rf_path = get_persconffile_path(RECENT_FILE_NAME, FALSE, FALSE);
938   }
939
940   /* Read the user's recent file, if it exists. */
941   *rf_path_return = NULL;
942   if ((rf = ws_fopen(rf_path, "r")) != NULL) {
943     /* We succeeded in opening it; read it. */
944     read_prefs_file(rf_path, rf, read_set_recent_pair_dynamic, NULL);
945 #if 0
946     /* set dfilter combobox to have an empty line */
947     dfilter_combo_add_empty();
948 #endif
949     fclose(rf);
950     g_free(rf_path);
951     rf_path = NULL;
952   } else {
953     /* We failed to open it.  If we failed for some reason other than
954        "it doesn't exist", return the errno and the pathname, so our
955        caller can report the error. */
956     if (errno != ENOENT) {
957       *rf_errno_return = errno;
958       *rf_path_return = rf_path;
959     }
960   }
961 }
962
963 gint
964 recent_get_column_width(gint col)
965 {
966   GList *col_l;
967   col_width_data *col_w;
968   gint cfmt;
969   const gchar *cfield = NULL;
970
971   cfmt = get_column_format(col);
972   if (cfmt == COL_CUSTOM) {
973     cfield = get_column_custom_field(col);
974   }
975
976   col_l = g_list_first(recent.col_width_list);
977   while (col_l) {
978     col_w = (col_width_data *) col_l->data;
979     if (col_w->cfmt == cfmt) {
980       if (cfmt != COL_CUSTOM || strcmp (cfield, col_w->cfield) == 0) {
981         return col_w->width;
982       }
983     }
984     col_l = col_l->next;
985   }
986
987   return -1;
988 }
989
990 void
991 recent_set_column_width(gint col, gint width)
992 {
993   GList *col_l;
994   col_width_data *col_w;
995   gint cfmt;
996   const gchar *cfield = NULL;
997   gboolean found = FALSE;
998
999   cfmt = get_column_format(col);
1000   if (cfmt == COL_CUSTOM) {
1001     cfield = get_column_custom_field(col);
1002   }
1003
1004   col_l = g_list_first(recent.col_width_list);
1005   while (col_l) {
1006     col_w = (col_width_data *) col_l->data;
1007     if (col_w->cfmt == cfmt) {
1008       if (cfmt != COL_CUSTOM || strcmp (cfield, col_w->cfield) == 0) {
1009         col_w->width = width;
1010         found = TRUE;
1011         break;
1012       }
1013     }
1014     col_l = col_l->next;
1015   }
1016
1017   if (!found) {
1018     col_w = (col_width_data *) g_malloc(sizeof(col_width_data));
1019     col_w->cfmt = cfmt;
1020     if (cfield) {
1021       col_w->cfield = g_strdup(cfield);
1022     } else {
1023       col_w->cfield = NULL;
1024     }
1025     col_w->width = width;
1026     col_w->xalign = COLUMN_XALIGN_DEFAULT;
1027     recent.col_width_list = g_list_append(recent.col_width_list, col_w);
1028   }
1029 }
1030
1031 gchar
1032 recent_get_column_xalign(gint col)
1033 {
1034   GList *col_l;
1035   col_width_data *col_w;
1036   gint cfmt;
1037   const gchar *cfield = NULL;
1038
1039   cfmt = get_column_format(col);
1040   if (cfmt == COL_CUSTOM) {
1041     cfield = get_column_custom_field(col);
1042   }
1043
1044   col_l = g_list_first(recent.col_width_list);
1045   while (col_l) {
1046     col_w = (col_width_data *) col_l->data;
1047     if (col_w->cfmt == cfmt) {
1048       if (cfmt != COL_CUSTOM || strcmp (cfield, col_w->cfield) == 0) {
1049         return col_w->xalign;
1050       }
1051     }
1052     col_l = col_l->next;
1053   }
1054
1055   return 0;
1056 }
1057
1058 void
1059 recent_set_column_xalign(gint col, gchar xalign)
1060 {
1061   GList *col_l;
1062   col_width_data *col_w;
1063   gint cfmt;
1064   const gchar *cfield = NULL;
1065   gboolean found = FALSE;
1066
1067   cfmt = get_column_format(col);
1068   if (cfmt == COL_CUSTOM) {
1069     cfield = get_column_custom_field(col);
1070   }
1071
1072   col_l = g_list_first(recent.col_width_list);
1073   while (col_l) {
1074     col_w = (col_width_data *) col_l->data;
1075     if (col_w->cfmt == cfmt) {
1076       if (cfmt != COL_CUSTOM || strcmp (cfield, col_w->cfield) == 0) {
1077         col_w->xalign = xalign;
1078         found = TRUE;
1079         break;
1080       }
1081     }
1082     col_l = col_l->next;
1083   }
1084
1085   if (!found) {
1086     col_w = (col_width_data *) g_malloc(sizeof(col_width_data));
1087     col_w->cfmt = cfmt;
1088     if (cfield) {
1089       col_w->cfield = g_strdup(cfield);
1090     } else {
1091       col_w->cfield = NULL;
1092     }
1093     col_w->width = 40;
1094     col_w->xalign = xalign;
1095     recent.col_width_list = g_list_append(recent.col_width_list, col_w);
1096   }
1097 }