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