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