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