Fix a typo; Remove a dup.
[obnox/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
53 #define RECENT_KEY_MAIN_TOOLBAR_SHOW        "gui.toolbar_main_show"
54 #define RECENT_KEY_FILTER_TOOLBAR_SHOW      "gui.filter_toolbar_show"
55 #define RECENT_KEY_AIRPCAP_TOOLBAR_SHOW     "gui.airpcap_toolbar_show"
56 #define RECENT_KEY_DRIVER_CHECK_SHOW        "gui.airpcap_driver_check_show"
57 #define RECENT_KEY_PACKET_LIST_SHOW         "gui.packet_list_show"
58 #define RECENT_KEY_TREE_VIEW_SHOW           "gui.tree_view_show"
59 #define RECENT_KEY_BYTE_VIEW_SHOW           "gui.byte_view_show"
60 #define RECENT_KEY_STATUSBAR_SHOW           "gui.statusbar_show"
61 #define RECENT_KEY_PACKET_LIST_COLORIZE     "gui.packet_list_colorize"
62 #define RECENT_GUI_TIME_FORMAT              "gui.time_format"
63 #define RECENT_GUI_TIME_PRECISION           "gui.time_precision"
64 #define RECENT_GUI_SECONDS_FORMAT           "gui.seconds_format"
65 #define RECENT_GUI_ZOOM_LEVEL               "gui.zoom_level"
66 #define RECENT_GUI_BYTES_VIEW               "gui.bytes_view"
67 #define RECENT_GUI_GEOMETRY_MAIN_X          "gui.geometry_main_x"
68 #define RECENT_GUI_GEOMETRY_MAIN_Y          "gui.geometry_main_y"
69 #define RECENT_GUI_GEOMETRY_MAIN_WIDTH      "gui.geometry_main_width"
70 #define RECENT_GUI_GEOMETRY_MAIN_HEIGHT     "gui.geometry_main_height"
71 #define RECENT_GUI_GEOMETRY_MAIN_MAXIMIZED  "gui.geometry_main_maximized"
72 #define RECENT_GUI_GEOMETRY_MAIN_UPPER_PANE "gui.geometry_main_upper_pane"
73 #define RECENT_GUI_GEOMETRY_MAIN_LOWER_PANE "gui.geometry_main_lower_pane"
74 #define RECENT_GUI_GEOMETRY_STATUS_PANE_LEFT  "gui.geometry_status_pane"
75 #define RECENT_GUI_GEOMETRY_STATUS_PANE_RIGHT "gui.geometry_status_pane_right"
76 #define RECENT_GUI_GEOMETRY_WLAN_STATS_PANE "gui.geometry_status_wlan_stats_pane"
77 #define RECENT_LAST_USED_PROFILE            "gui.last_used_profile"
78 #define RECENT_GUI_FILEOPEN_REMEMBERED_DIR  "gui.fileopen_remembered_dir"
79 #define RECENT_GUI_GEOMETRY                 "gui.geom."
80 #define RECENT_KEY_PRIVS_WARN_IF_ELEVATED   "privs.warn_if_elevated"
81 #define RECENT_KEY_PRIVS_WARN_IF_NO_NPF     "privs.warn_if_no_npf"
82
83 #define RECENT_FILE_NAME "recent"
84 #define RECENT_COMMON_FILE_NAME "recent_common"
85
86 recent_settings_t recent;
87
88 static const char *ts_type_text[] =
89   { "RELATIVE", "ABSOLUTE", "ABSOLUTE_WITH_DATE", "DELTA", "DELTA_DIS", "EPOCH", "UTC", "UTC_WITH_DATE", NULL };
90
91 static const char *ts_precision_text[] =
92         { "AUTO", "SEC", "DSEC", "CSEC", "MSEC", "USEC", "NSEC", NULL };
93
94 static const char *ts_seconds_text[] =
95   { "SECONDS", "HOUR_MIN_SEC", 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 common" to the user's recent common 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       g_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       g_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 profile 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       g_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       g_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, UTC, UTC_WITH_DATE\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# Seconds display format.\n");
357   fprintf(rf, "# One of: SECONDS, HOUR_MIN_SEC\n");
358   fprintf(rf, RECENT_GUI_SECONDS_FORMAT ": %s\n",
359           ts_seconds_text[recent.gui_seconds_format]);
360
361   fprintf(rf, "\n# Zoom level.\n");
362   fprintf(rf, "# A decimal number.\n");
363   fprintf(rf, RECENT_GUI_ZOOM_LEVEL ": %d\n",
364                   recent.gui_zoom_level);
365
366   fprintf(rf, "\n# Bytes view.\n");
367   fprintf(rf, "# A decimal number.\n");
368   fprintf(rf, RECENT_GUI_BYTES_VIEW ": %d\n",
369                   recent.gui_bytes_view);
370
371   fprintf(rf, "\n# Main window upper (or leftmost) pane size.\n");
372   fprintf(rf, "# Decimal number.\n");
373   if (recent.gui_geometry_main_upper_pane != 0) {
374     fprintf(rf, RECENT_GUI_GEOMETRY_MAIN_UPPER_PANE ": %d\n",
375                   recent.gui_geometry_main_upper_pane);
376   }
377   fprintf(rf, "\n# Main window middle pane size.\n");
378   fprintf(rf, "# Decimal number.\n");
379   if (recent.gui_geometry_main_lower_pane != 0) {
380     fprintf(rf, RECENT_GUI_GEOMETRY_MAIN_LOWER_PANE ": %d\n",
381                   recent.gui_geometry_main_lower_pane);
382   }
383
384   fprintf(rf, "\n# Packet list column pixel widths.\n");
385   fprintf(rf, "# Each pair of strings consists of a column format and its pixel width.\n");
386   new_packet_list_recent_write_all(rf);
387
388   if (get_last_open_dir() != NULL) {
389     fprintf(rf, "\n# Last directory navigated to in File Open dialog.\n");
390
391     if(u3_active())
392       fprintf(rf, RECENT_GUI_FILEOPEN_REMEMBERED_DIR ": %s\n", u3_contract_device_path(get_last_open_dir()));
393     else
394       fprintf(rf, RECENT_GUI_FILEOPEN_REMEMBERED_DIR ": %s\n", get_last_open_dir());
395   }
396
397   fclose(rf);
398
399   /* XXX - catch I/O errors (e.g. "ran out of disk space") and return
400      an error indication, or maybe write to a new recent file and
401      rename that file on top of the old one only if there are not I/O
402      errors. */
403   return TRUE;
404 }
405
406
407 /* write the geometry values of a window to recent file */
408 void
409 write_recent_geom(gpointer key _U_, gpointer value, gpointer rf)
410 {
411     window_geometry_t *geom = value;
412
413     fprintf(rf, "\n# Geometry and maximized state of %s window.\n", geom->key);
414     fprintf(rf, "# Decimal integers.\n");
415     fprintf(rf, RECENT_GUI_GEOMETRY "%s.x: %d\n", geom->key, geom->x);
416     fprintf(rf, RECENT_GUI_GEOMETRY "%s.y: %d\n", geom->key, geom->y);
417     fprintf(rf, RECENT_GUI_GEOMETRY "%s.width: %d\n", geom->key,
418               geom->width);
419     fprintf(rf, RECENT_GUI_GEOMETRY "%s.height: %d\n", geom->key,
420               geom->height);
421
422     fprintf(rf, "# TRUE or FALSE (case-insensitive).\n");
423     fprintf(rf, RECENT_GUI_GEOMETRY "%s.maximized: %s\n", geom->key,
424               geom->maximized == TRUE ? "TRUE" : "FALSE");
425
426 }
427
428 /* set one user's recent common file key/value pair */
429 static prefs_set_pref_e
430 read_set_recent_common_pair_static(gchar *key, gchar *value,
431                                    void *private_data _U_,
432                                    gboolean return_range_errors _U_)
433 {
434   long num;
435   char *p;
436
437   if (strcmp(key, RECENT_GUI_GEOMETRY_MAIN_MAXIMIZED) == 0) {
438     if (g_ascii_strcasecmp(value, "true") == 0) {
439         recent.gui_geometry_main_maximized = TRUE;
440     }
441     else {
442         recent.gui_geometry_main_maximized = FALSE;
443     }
444
445   } else if (strcmp(key, RECENT_GUI_GEOMETRY_MAIN_X) == 0) {
446     num = strtol(value, &p, 0);
447     if (p == value || *p != '\0')
448       return PREFS_SET_SYNTAX_ERR;      /* number was bad */
449     recent.gui_geometry_main_x = num;
450   } else if (strcmp(key, RECENT_GUI_GEOMETRY_MAIN_Y) == 0) {
451     num = strtol(value, &p, 0);
452     if (p == value || *p != '\0')
453       return PREFS_SET_SYNTAX_ERR;      /* number was bad */
454     recent.gui_geometry_main_y = num;
455   } else if (strcmp(key, RECENT_GUI_GEOMETRY_MAIN_WIDTH) == 0) {
456     num = strtol(value, &p, 0);
457     if (p == value || *p != '\0')
458       return PREFS_SET_SYNTAX_ERR;      /* number was bad */
459     if (num <= 0)
460       return PREFS_SET_SYNTAX_ERR;      /* number must be positive */
461     recent.gui_geometry_main_width = num;
462   } else if (strcmp(key, RECENT_GUI_GEOMETRY_MAIN_HEIGHT) == 0) {
463     num = strtol(value, &p, 0);
464     if (p == value || *p != '\0')
465       return PREFS_SET_SYNTAX_ERR;      /* number was bad */
466     if (num <= 0)
467       return PREFS_SET_SYNTAX_ERR;      /* number must be positive */
468     recent.gui_geometry_main_height = num;
469   } else if (strcmp(key, RECENT_GUI_GEOMETRY_STATUS_PANE_RIGHT) == 0) {
470     num = strtol(value, &p, 0);
471     if (p == value || *p != '\0')
472       return PREFS_SET_SYNTAX_ERR;      /* number was bad */
473     if (num <= 0)
474       return PREFS_SET_SYNTAX_ERR;      /* number must be positive */
475     recent.gui_geometry_status_pane_right = num;
476     recent.has_gui_geometry_status_pane = TRUE;
477   } else if (strcmp(key, RECENT_GUI_GEOMETRY_STATUS_PANE_LEFT) == 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_status_pane_left = num;
484     recent.has_gui_geometry_status_pane = TRUE;
485   } else if (strcmp(key, RECENT_LAST_USED_PROFILE) == 0) {
486     if ((strcmp(value, DEFAULT_PROFILE) != 0) && profile_exists (value, FALSE)) {
487       set_profile_name (value);
488     }
489   } else if (strcmp(key, RECENT_GUI_GEOMETRY_WLAN_STATS_PANE) == 0) {
490     num = strtol(value, &p, 0);
491     if (p == value || *p != '\0')
492       return PREFS_SET_SYNTAX_ERR;      /* number was bad */
493     if (num <= 0)
494       return PREFS_SET_SYNTAX_ERR;      /* number must be positive */
495     recent.gui_geometry_wlan_stats_pane = num;
496   } else if (strncmp(key, RECENT_GUI_GEOMETRY, sizeof(RECENT_GUI_GEOMETRY)-1) == 0) {
497     /* now have something like "gui.geom.main.x", split it into win and sub_key */
498     char *win = &key[sizeof(RECENT_GUI_GEOMETRY)-1];
499     char *sub_key = strchr(win, '.');
500     if(sub_key) {
501       *sub_key = '\0';
502       sub_key++;
503       window_geom_recent_read_pair(win, sub_key, value);
504     }
505   } else if (strcmp(key, RECENT_KEY_PRIVS_WARN_IF_ELEVATED) == 0) {
506     if (g_ascii_strcasecmp(value, "true") == 0) {
507         recent.privs_warn_if_elevated = TRUE;
508     }
509     else {
510         recent.privs_warn_if_elevated = FALSE;
511     }
512   } else if (strcmp(key, RECENT_KEY_PRIVS_WARN_IF_NO_NPF) == 0) {
513     if (g_ascii_strcasecmp(value, "true") == 0) {
514         recent.privs_warn_if_no_npf = TRUE;
515     }
516     else {
517         recent.privs_warn_if_no_npf = FALSE;
518     }
519   }
520
521   return PREFS_SET_OK;
522 }
523
524 /* set one user's recent file key/value pair */
525 static prefs_set_pref_e
526 read_set_recent_pair_static(gchar *key, gchar *value, void *private_data _U_,
527                             gboolean return_range_errors _U_)
528 {
529   long num;
530   char *p;
531   GList *col_l, *col_l_elt;
532   col_width_data *cfmt;
533   const gchar *cust_format = col_format_to_string(COL_CUSTOM);
534   int cust_format_len = (int) strlen(cust_format);
535
536   if (strcmp(key, RECENT_KEY_MAIN_TOOLBAR_SHOW) == 0) {
537     if (g_ascii_strcasecmp(value, "true") == 0) {
538         recent.main_toolbar_show = TRUE;
539     }
540     else {
541         recent.main_toolbar_show = FALSE;
542     }
543   } else if (strcmp(key, RECENT_KEY_FILTER_TOOLBAR_SHOW) == 0) {
544     if (g_ascii_strcasecmp(value, "true") == 0) {
545         recent.filter_toolbar_show = TRUE;
546     }
547     else {
548         recent.filter_toolbar_show = FALSE;
549     }
550   } else if (strcmp(key, RECENT_KEY_AIRPCAP_TOOLBAR_SHOW) == 0) {
551     if (g_ascii_strcasecmp(value, "true") == 0) {
552         recent.airpcap_toolbar_show = TRUE;
553     }
554     else {
555         recent.airpcap_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 (strcmp(key, RECENT_KEY_CAPTURE_FILE) == 0) {
732     if(u3_active())
733       add_menu_recent_capture_file(u3_expand_device_path(value));
734     else
735       add_menu_recent_capture_file(value);
736   } else if (strcmp(key, RECENT_KEY_DISPLAY_FILTER) == 0) {
737         dfilter_combo_add_recent(value);
738   } else if (strcmp(key, RECENT_KEY_CAPTURE_FILTER) == 0) {
739         cfilter_combo_add_recent(value);
740 #ifdef HAVE_PCAP_REMOTE
741   } else if (strcmp(key, RECENT_KEY_REMOTE_HOST) == 0) {
742         capture_remote_combo_add_recent(value);
743 #endif
744   }
745
746   return PREFS_SET_OK;
747 }
748
749
750 /*
751  * Given a string of the form "<recent name>:<recent value>", as might appear
752  * as an argument to a "-o" option, parse it and set the recent value in
753  * question.  Return an indication of whether it succeeded or failed
754  * in some fashion.
755  */
756 int
757 recent_set_arg(char *prefarg)
758 {
759         gchar *p, *colonp;
760         int ret;
761
762         colonp = strchr(prefarg, ':');
763         if (colonp == NULL)
764                 return PREFS_SET_SYNTAX_ERR;
765
766         p = colonp;
767         *p++ = '\0';
768
769         /*
770          * Skip over any white space (there probably won't be any, but
771          * as we allow it in the preferences file, we might as well
772          * allow it here).
773          */
774         while (isspace((guchar)*p))
775                 p++;
776         if (*p == '\0') {
777                 /*
778                  * Put the colon back, so if our caller uses, in an
779                  * error message, the string they passed us, the message
780                  * looks correct.
781                  */
782                 *colonp = ':';
783                 return PREFS_SET_SYNTAX_ERR;
784         }
785
786         ret = read_set_recent_pair_static(prefarg, p, NULL, TRUE);
787         *colonp = ':';  /* put the colon back */
788         return ret;
789 }
790
791
792 /* opens the user's recent common file and read the first part */
793 void
794 recent_read_static(char **rf_path_return, int *rf_errno_return)
795 {
796   char       *rf_path;
797   FILE       *rf;
798
799   /* set defaults */
800   recent.gui_geometry_main_x        =        20;
801   recent.gui_geometry_main_y        =        20;
802   recent.gui_geometry_main_width    = DEF_WIDTH;
803   recent.gui_geometry_main_height   = DEF_HEIGHT;
804   recent.gui_geometry_main_maximized=     FALSE;
805
806   recent.gui_geometry_status_pane_left  = (DEF_WIDTH/3);
807   recent.gui_geometry_status_pane_right = (DEF_WIDTH/3);
808   recent.gui_geometry_wlan_stats_pane = 200;
809
810   recent.privs_warn_if_elevated = TRUE;
811   recent.privs_warn_if_no_npf = TRUE;
812
813   recent.col_width_list = NULL;
814   recent.gui_fileopen_remembered_dir = NULL;
815
816   /* Construct the pathname of the user's recent common file. */
817   rf_path = get_persconffile_path(RECENT_COMMON_FILE_NAME, FALSE, FALSE);
818
819   /* Read the user's recent common file, if it exists. */
820   *rf_path_return = NULL;
821   if ((rf = ws_fopen(rf_path, "r")) != NULL) {
822     /* We succeeded in opening it; read it. */
823     read_prefs_file(rf_path, rf, read_set_recent_common_pair_static, NULL);
824
825     fclose(rf);
826     g_free(rf_path);
827     rf_path = NULL;
828   } else {
829     /* We failed to open it.  If we failed for some reason other than
830        "it doesn't exist", return the errno and the pathname, so our
831        caller can report the error. */
832     if (errno != ENOENT) {
833       *rf_errno_return = errno;
834       *rf_path_return = rf_path;
835     }
836   }
837 }
838
839
840
841 /* opens the user's recent file and read the first part */
842 void
843 recent_read_profile_static(char **rf_path_return, int *rf_errno_return)
844 {
845   char       *rf_path, *rf_common_path;
846   FILE       *rf;
847
848   /* set defaults */
849   recent.main_toolbar_show      = TRUE;
850   recent.filter_toolbar_show    = TRUE;
851   recent.airpcap_toolbar_show   = FALSE;
852   recent.airpcap_driver_check_show   = TRUE;
853   recent.packet_list_show       = TRUE;
854   recent.tree_view_show         = TRUE;
855   recent.byte_view_show         = TRUE;
856   recent.statusbar_show         = TRUE;
857   recent.packet_list_colorize   = TRUE;
858   recent.gui_time_format        = TS_RELATIVE;
859   recent.gui_time_precision     = TS_PREC_AUTO;
860   recent.gui_seconds_format     = TS_SECONDS_DEFAULT;
861   recent.gui_zoom_level         = 0;
862   recent.gui_bytes_view         = 0;
863
864   /* pane size of zero will autodetect */
865   recent.gui_geometry_main_upper_pane   = 0;
866   recent.gui_geometry_main_lower_pane   = 0;
867
868   recent.has_gui_geometry_main_upper_pane = TRUE;
869   recent.has_gui_geometry_main_lower_pane = TRUE;
870   recent.has_gui_geometry_status_pane = TRUE;
871
872   if (recent.col_width_list) {
873     free_col_width_info(&recent);
874   }
875
876   if (recent.gui_fileopen_remembered_dir) {
877     g_free (recent.gui_fileopen_remembered_dir);
878     recent.gui_fileopen_remembered_dir = NULL;
879   }
880
881   /* Construct the pathname of the user's profile recent file. */
882   rf_path = get_persconffile_path(RECENT_FILE_NAME, TRUE, FALSE);
883
884   /* Read the user's recent file, if it exists. */
885   *rf_path_return = NULL;
886   if ((rf = ws_fopen(rf_path, "r")) != NULL) {
887     /* We succeeded in opening it; read it. */
888     read_prefs_file(rf_path, rf, read_set_recent_pair_static, NULL);
889     fclose(rf);
890
891     /* XXX: The following code doesn't actually do anything since
892      *  the "recent common file" always exists. Presumably the
893      *  "if (!file_exists())" should actually be "if (file_exists())".
894      *  However, I've left the code as is because this
895      *  behaviour has existed for quite some time and I don't
896      *  know what's supposed to happen at this point.
897      *  ToDo: Determine if the "recent common file" should be read at this point
898      */
899     rf_common_path = get_persconffile_path(RECENT_COMMON_FILE_NAME, FALSE, FALSE);
900     if (!file_exists(rf_common_path)) {
901       /* Read older common settings from recent file */
902       rf = ws_fopen(rf_path, "r");
903       read_prefs_file(rf_path, rf, read_set_recent_common_pair_static, NULL);
904       fclose(rf);
905     }
906     g_free(rf_common_path);
907     g_free(rf_path);
908     rf_path = NULL;
909   } else {
910     /* We failed to open it.  If we failed for some reason other than
911        "it doesn't exist", return the errno and the pathname, so our
912        caller can report the error. */
913     if (errno != ENOENT) {
914       *rf_errno_return = errno;
915       *rf_path_return = rf_path;
916     }
917   }
918 }
919
920 /* opens the user's recent file and read it out */
921 void
922 recent_read_dynamic(char **rf_path_return, int *rf_errno_return)
923 {
924   char       *rf_path;
925   FILE       *rf;
926
927
928   /* Construct the pathname of the user's recent common file. */
929   rf_path = get_persconffile_path(RECENT_COMMON_FILE_NAME, FALSE, FALSE);
930   if (!file_exists (rf_path)) {
931     /* Recent common file does not exist, read from default recent */
932     g_free (rf_path);
933     rf_path = get_persconffile_path(RECENT_FILE_NAME, FALSE, FALSE);
934   }
935
936   /* Read the user's recent file, if it exists. */
937   *rf_path_return = NULL;
938   if ((rf = ws_fopen(rf_path, "r")) != NULL) {
939     /* We succeeded in opening it; read it. */
940     read_prefs_file(rf_path, rf, read_set_recent_pair_dynamic, NULL);
941 #if 0
942     /* set dfilter combobox to have an empty line */
943     dfilter_combo_add_empty();
944 #endif
945     fclose(rf);
946     g_free(rf_path);
947     rf_path = NULL;
948   } else {
949     /* We failed to open it.  If we failed for some reason other than
950        "it doesn't exist", return the errno and the pathname, so our
951        caller can report the error. */
952     if (errno != ENOENT) {
953       *rf_errno_return = errno;
954       *rf_path_return = rf_path;
955     }
956   }
957 }
958
959 gint
960 recent_get_column_width(gint col)
961 {
962   GList *col_l;
963   col_width_data *col_w;
964   gint cfmt;
965   const gchar *cfield = NULL;
966
967   cfmt = get_column_format(col);
968   if (cfmt == COL_CUSTOM) {
969     cfield = get_column_custom_field(col);
970   }
971
972   col_l = g_list_first(recent.col_width_list);
973   while (col_l) {
974     col_w = (col_width_data *) col_l->data;
975     if (col_w->cfmt == cfmt) {
976       if (cfmt != COL_CUSTOM || strcmp (cfield, col_w->cfield) == 0) {
977         return col_w->width;
978       }
979     }
980     col_l = col_l->next;
981   }
982
983   return -1;
984 }
985
986 void
987 recent_set_column_width(gint col, gint width)
988 {
989   GList *col_l;
990   col_width_data *col_w;
991   gint cfmt;
992   const gchar *cfield = NULL;
993   gboolean found = FALSE;
994
995   cfmt = get_column_format(col);
996   if (cfmt == COL_CUSTOM) {
997     cfield = get_column_custom_field(col);
998   }
999
1000   col_l = g_list_first(recent.col_width_list);
1001   while (col_l) {
1002     col_w = (col_width_data *) col_l->data;
1003     if (col_w->cfmt == cfmt) {
1004       if (cfmt != COL_CUSTOM || strcmp (cfield, col_w->cfield) == 0) {
1005         col_w->width = width;
1006         found = TRUE;
1007         break;
1008       }
1009     }
1010     col_l = col_l->next;
1011   }
1012
1013   if (!found) {
1014     col_w = (col_width_data *) g_malloc(sizeof(col_width_data));
1015     col_w->cfmt = cfmt;
1016     if (cfield) {
1017       col_w->cfield = g_strdup(cfield);
1018     } else {
1019       col_w->cfield = NULL;
1020     }
1021     col_w->width = width;
1022     col_w->xalign = COLUMN_XALIGN_DEFAULT;
1023     recent.col_width_list = g_list_append(recent.col_width_list, col_w);
1024   }
1025 }
1026
1027 gchar
1028 recent_get_column_xalign(gint col)
1029 {
1030   GList *col_l;
1031   col_width_data *col_w;
1032   gint cfmt;
1033   const gchar *cfield = NULL;
1034
1035   cfmt = get_column_format(col);
1036   if (cfmt == COL_CUSTOM) {
1037     cfield = get_column_custom_field(col);
1038   }
1039
1040   col_l = g_list_first(recent.col_width_list);
1041   while (col_l) {
1042     col_w = (col_width_data *) col_l->data;
1043     if (col_w->cfmt == cfmt) {
1044       if (cfmt != COL_CUSTOM || strcmp (cfield, col_w->cfield) == 0) {
1045         return col_w->xalign;
1046       }
1047     }
1048     col_l = col_l->next;
1049   }
1050
1051   return 0;
1052 }
1053
1054 void
1055 recent_set_column_xalign(gint col, gchar xalign)
1056 {
1057   GList *col_l;
1058   col_width_data *col_w;
1059   gint cfmt;
1060   const gchar *cfield = NULL;
1061   gboolean found = FALSE;
1062
1063   cfmt = get_column_format(col);
1064   if (cfmt == COL_CUSTOM) {
1065     cfield = get_column_custom_field(col);
1066   }
1067
1068   col_l = g_list_first(recent.col_width_list);
1069   while (col_l) {
1070     col_w = (col_width_data *) col_l->data;
1071     if (col_w->cfmt == cfmt) {
1072       if (cfmt != COL_CUSTOM || strcmp (cfield, col_w->cfield) == 0) {
1073         col_w->xalign = xalign;
1074         found = TRUE;
1075         break;
1076       }
1077     }
1078     col_l = col_l->next;
1079   }
1080
1081   if (!found) {
1082     col_w = (col_width_data *) g_malloc(sizeof(col_width_data));
1083     col_w->cfmt = cfmt;
1084     if (cfield) {
1085       col_w->cfield = g_strdup(cfield);
1086     } else {
1087       col_w->cfield = NULL;
1088     }
1089     col_w->width = 40;
1090     col_w->xalign = xalign;
1091     recent.col_width_list = g_list_append(recent.col_width_list, col_w);
1092   }
1093 }