qt: show marker when capture file comment has changed
[metze/wireshark/wip.git] / ui / recent.c
1 /* recent.c
2  * Recent "preference" handling routines
3  * Copyright 2004, Ulf Lamping <ulf.lamping@web.de>
4  *
5  * Wireshark - Network traffic analyzer
6  * By Gerald Combs <gerald@wireshark.org>
7  * Copyright 1998 Gerald Combs
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License
11  * as published by the Free Software Foundation; either version 2
12  * of the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22  */
23
24 #include "config.h"
25
26 #include <stdlib.h>
27 #include <string.h>
28 #include <errno.h>
29
30 #include "capture_opts.h"
31 #include <wsutil/filesystem.h>
32 #include <epan/prefs.h>
33 #include <epan/prefs-int.h>
34 #include <epan/column.h>
35 #include <epan/value_string.h>
36
37 #include "ui/last_open_dir.h"
38 #include "ui/recent.h"
39 #include "ui/recent_utils.h"
40 #include "ui/simple_dialog.h"
41
42 #include <wsutil/u3.h>
43 #include <wsutil/file_util.h>
44
45 #define RECENT_KEY_MAIN_TOOLBAR_SHOW          "gui.toolbar_main_show"
46 #define RECENT_KEY_FILTER_TOOLBAR_SHOW        "gui.filter_toolbar_show"
47 #define RECENT_KEY_WIRELESS_TOOLBAR_SHOW      "gui.wireless_toolbar_show"
48 #define RECENT_KEY_DRIVER_CHECK_SHOW          "gui.airpcap_driver_check_show"
49 #define RECENT_KEY_PACKET_LIST_SHOW           "gui.packet_list_show"
50 #define RECENT_KEY_TREE_VIEW_SHOW             "gui.tree_view_show"
51 #define RECENT_KEY_BYTE_VIEW_SHOW             "gui.byte_view_show"
52 #define RECENT_KEY_STATUSBAR_SHOW             "gui.statusbar_show"
53 #define RECENT_KEY_PACKET_LIST_COLORIZE       "gui.packet_list_colorize"
54 #define RECENT_GUI_TIME_FORMAT                "gui.time_format"
55 #define RECENT_GUI_TIME_PRECISION             "gui.time_precision"
56 #define RECENT_GUI_SECONDS_FORMAT             "gui.seconds_format"
57 #define RECENT_GUI_ZOOM_LEVEL                 "gui.zoom_level"
58 #define RECENT_GUI_BYTES_VIEW                 "gui.bytes_view"
59 #define RECENT_GUI_GEOMETRY_MAIN_X            "gui.geometry_main_x"
60 #define RECENT_GUI_GEOMETRY_MAIN_Y            "gui.geometry_main_y"
61 #define RECENT_GUI_GEOMETRY_MAIN_WIDTH        "gui.geometry_main_width"
62 #define RECENT_GUI_GEOMETRY_MAIN_HEIGHT       "gui.geometry_main_height"
63 #define RECENT_GUI_GEOMETRY_MAIN_MAXIMIZED    "gui.geometry_main_maximized"
64 #define RECENT_GUI_GEOMETRY_MAIN_UPPER_PANE   "gui.geometry_main_upper_pane"
65 #define RECENT_GUI_GEOMETRY_MAIN_LOWER_PANE   "gui.geometry_main_lower_pane"
66 #define RECENT_GUI_GEOMETRY_STATUS_PANE_LEFT  "gui.geometry_status_pane"
67 #define RECENT_GUI_GEOMETRY_STATUS_PANE_RIGHT "gui.geometry_status_pane_right"
68 #define RECENT_GUI_GEOMETRY_WLAN_STATS_PANE   "gui.geometry_status_wlan_stats_pane"
69 #define RECENT_LAST_USED_PROFILE              "gui.last_used_profile"
70 #define RECENT_GUI_FILEOPEN_REMEMBERED_DIR    "gui.fileopen_remembered_dir"
71 #define RECENT_GUI_CONVERSATION_TABS          "gui.conversation_tabs"
72 #define RECENT_GUI_ENDPOINT_TABS              "gui.endpoint_tabs"
73 #define RECENT_GUI_RLC_PDUS_FROM_MAC_FRAMES   "gui.rlc_pdus_from_mac_frames"
74 #define RECENT_GUI_CUSTOM_COLORS              "gui.custom_colors"
75
76 #define RECENT_GUI_GEOMETRY                   "gui.geom."
77
78 #define RECENT_KEY_PRIVS_WARN_IF_ELEVATED     "privs.warn_if_elevated"
79 #define RECENT_KEY_PRIVS_WARN_IF_NO_NPF       "privs.warn_if_no_npf"
80
81 #define RECENT_FILE_NAME "recent"
82 #define RECENT_COMMON_FILE_NAME "recent_common"
83
84 recent_settings_t recent;
85
86 static const value_string ts_type_values[] = {
87   { TS_RELATIVE,             "RELATIVE"           },
88   { TS_ABSOLUTE,             "ABSOLUTE"           },
89   { TS_ABSOLUTE_WITH_YMD,    "ABSOLUTE_WITH_YMD"  },
90   { TS_ABSOLUTE_WITH_YDOY,   "ABSOLUTE_WITH_YDOY" },
91   { TS_ABSOLUTE_WITH_YMD,    "ABSOLUTE_WITH_DATE" },  /* Backward compability */
92   { TS_DELTA,                "DELTA"              },
93   { TS_DELTA_DIS,            "DELTA_DIS"          },
94   { TS_EPOCH,                "EPOCH"              },
95   { TS_UTC,                  "UTC"                },
96   { TS_UTC_WITH_YMD,         "UTC_WITH_YMD"       },
97   { TS_UTC_WITH_YDOY,        "UTC_WITH_YDOY"      },
98   { TS_UTC_WITH_YMD,         "UTC_WITH_DATE"      },  /* Backward compability */
99   { 0, NULL }
100 };
101
102 static const value_string ts_precision_values[] = {
103   { TS_PREC_AUTO,            "AUTO" },
104   { TS_PREC_FIXED_SEC,       "SEC"  },
105   { TS_PREC_FIXED_DSEC,      "DSEC" },
106   { TS_PREC_FIXED_CSEC,      "CSEC" },
107   { TS_PREC_FIXED_MSEC,      "MSEC" },
108   { TS_PREC_FIXED_USEC,      "USEC" },
109   { TS_PREC_FIXED_NSEC,      "NSEC" },
110   { 0, NULL }
111 };
112
113 static const value_string ts_seconds_values[] = {
114   { TS_SECONDS_DEFAULT,      "SECONDS"      },
115   { TS_SECONDS_HOUR_MIN_SEC, "HOUR_MIN_SEC" },
116   { 0, NULL }
117 };
118
119 static void
120 free_col_width_info(recent_settings_t *rs)
121 {
122   col_width_data *cfmt;
123
124   while (rs->col_width_list != NULL) {
125     cfmt = (col_width_data *)rs->col_width_list->data;
126     g_free(cfmt->cfield);
127     g_free(cfmt);
128     rs->col_width_list = g_list_remove_link(rs->col_width_list, rs->col_width_list);
129   }
130   g_list_free(rs->col_width_list);
131   rs->col_width_list = NULL;
132 }
133
134 /** Write the geometry values of a single window to the recent file.
135  *
136  * @param key unused
137  * @param value the geometry values
138  * @param rfh recent file handle (FILE)
139  */
140 static void
141 write_recent_geom(gpointer key _U_, gpointer value, gpointer rfh)
142 {
143   window_geometry_t *geom = (window_geometry_t *)value;
144   FILE *rf = (FILE *)rfh;
145
146   fprintf(rf, "\n# Geometry and maximized state of %s window.\n", geom->key);
147   fprintf(rf, "# Decimal integers.\n");
148   fprintf(rf, RECENT_GUI_GEOMETRY "%s.x: %d\n", geom->key, geom->x);
149   fprintf(rf, RECENT_GUI_GEOMETRY "%s.y: %d\n", geom->key, geom->y);
150   fprintf(rf, RECENT_GUI_GEOMETRY "%s.width: %d\n", geom->key,
151           geom->width);
152   fprintf(rf, RECENT_GUI_GEOMETRY "%s.height: %d\n", geom->key,
153           geom->height);
154
155   fprintf(rf, "# TRUE or FALSE (case-insensitive).\n");
156   fprintf(rf, RECENT_GUI_GEOMETRY "%s.maximized: %s\n", geom->key,
157           geom->maximized == TRUE ? "TRUE" : "FALSE");
158
159 }
160
161 /* the geometry hashtable for all known window classes,
162  * the window name is the key, and the geometry struct is the value */
163 static GHashTable *window_geom_hash = NULL;
164
165 /* save the window and its current geometry into the geometry hashtable */
166 void
167 window_geom_save(const gchar *name, window_geometry_t *geom)
168 {
169   gchar *key;
170   window_geometry_t *work;
171
172   /* init hashtable, if not already done */
173   if (!window_geom_hash) {
174     window_geom_hash = g_hash_table_new(g_str_hash, g_str_equal);
175   }
176   /* if we have an old one, remove and free it first */
177   work = (window_geometry_t *)g_hash_table_lookup(window_geom_hash, name);
178   if (work) {
179     g_hash_table_remove(window_geom_hash, name);
180     g_free(work->key);
181     g_free(work);
182   }
183
184   /* g_malloc and insert the new one */
185   work = (window_geometry_t *)g_malloc(sizeof(window_geometry_t));
186   *work = *geom;
187   key = g_strdup(name);
188   work->key = key;
189   g_hash_table_insert(window_geom_hash, key, work);
190 }
191
192 /* load the desired geometry for this window from the geometry hashtable */
193 gboolean
194 window_geom_load(const gchar       *name,
195                  window_geometry_t *geom)
196 {
197   window_geometry_t *p;
198
199   /* init hashtable, if not already done */
200   if (!window_geom_hash) {
201     window_geom_hash = g_hash_table_new(g_str_hash, g_str_equal);
202   }
203
204   p = (window_geometry_t *)g_hash_table_lookup(window_geom_hash, name);
205   if (p) {
206     *geom = *p;
207     return TRUE;
208   } else {
209     return FALSE;
210   }
211 }
212
213 /* parse values of particular types */
214 static void
215 parse_recent_boolean(const gchar *val_str, gboolean *valuep)
216 {
217     if (g_ascii_strcasecmp(val_str, "true") == 0) {
218         *valuep = TRUE;
219     }
220     else {
221         *valuep = FALSE;
222     }
223 }
224
225 /** Read in a single geometry key value pair from the recent file.
226  *
227  * @param name the geom_name of the window
228  * @param key the subkey of this pair (e.g. "x")
229  * @param value the new value (e.g. "123")
230  */
231 static void
232 window_geom_recent_read_pair(const char *name,
233                              const char *key,
234                              const char *value)
235 {
236   window_geometry_t geom;
237
238   /* find window geometry maybe already in hashtable */
239   if (!window_geom_load(name, &geom)) {
240     /* not in table, init geom with "basic" values */
241     geom.key        = NULL;    /* Will be set in window_geom_save() */
242     geom.set_pos    = FALSE;
243     geom.x          = -1;
244     geom.y          = -1;
245     geom.set_size   = FALSE;
246     geom.width      = -1;
247     geom.height     = -1;
248
249     geom.set_maximized = FALSE;/* this is valid in GTK2 only */
250     geom.maximized  = FALSE;   /* this is valid in GTK2 only */
251   }
252
253   if (strcmp(key, "x") == 0) {
254     geom.x = (gint)strtol(value, NULL, 10);
255     geom.set_pos = TRUE;
256   } else if (strcmp(key, "y") == 0) {
257     geom.y = (gint)strtol(value, NULL, 10);
258     geom.set_pos = TRUE;
259   } else if (strcmp(key, "width") == 0) {
260     geom.width = (gint)strtol(value, NULL, 10);
261     geom.set_size = TRUE;
262   } else if (strcmp(key, "height") == 0) {
263     geom.height = (gint)strtol(value, NULL, 10);
264     geom.set_size = TRUE;
265   } else if (strcmp(key, "maximized") == 0) {
266     parse_recent_boolean(value, &geom.maximized);
267     geom.set_maximized = TRUE;
268   } else {
269     /*
270      * Silently ignore the bogus key.  We shouldn't abort here,
271      * as this could be due to a corrupt recent file.
272      *
273      * XXX - should we print a message about this?
274      */
275     return;
276   }
277
278   /* save / replace geometry in hashtable */
279   window_geom_save(name, &geom);
280 }
281
282 /** Write all geometry values of all windows to the recent file.
283  * Will call write_recent_geom() for every existing window type.
284  *
285  * @param rf recent file handle from caller
286  */
287 static void
288 window_geom_recent_write_all(FILE *rf)
289 {
290   /* init hashtable, if not already done */
291   if (!window_geom_hash) {
292     window_geom_hash = g_hash_table_new(g_str_hash, g_str_equal);
293   }
294
295   g_hash_table_foreach(window_geom_hash, write_recent_geom, rf);
296 }
297
298 /* Global list of recent capture filters. */
299 static GList *recent_cfilter_list;
300
301 /*
302  * Per-interface lists of recent capture filters; stored in a hash
303  * table indexed by interface name.
304  */
305 static GHashTable *per_interface_cfilter_lists_hash;
306
307 /* XXX: use a preference for this setting! */
308 static guint cfilter_combo_max_recent = 20;
309
310 /**
311  * Returns a list of recent capture filters.
312  *
313  * @param ifname interface name; NULL refers to the global list.
314  */
315 GList *
316 recent_get_cfilter_list(const gchar *ifname)
317 {
318   if (ifname == NULL)
319     return recent_cfilter_list;
320   if (per_interface_cfilter_lists_hash == NULL) {
321     /* No such lists exist. */
322     return NULL;
323   }
324   return (GList *)g_hash_table_lookup(per_interface_cfilter_lists_hash, ifname);
325 }
326
327 /**
328  * Add a capture filter to the global recent capture filter list or
329  * the recent capture filter list for an interface.
330  *
331  * @param ifname interface name; NULL refers to the global list.
332  * @param s text of capture filter
333  */
334 void
335 recent_add_cfilter(const gchar *ifname, const gchar *s)
336 {
337   GList     *cfilter_list;
338   GList     *li;
339   gchar     *li_filter, *newfilter = NULL;
340
341   /* Don't add empty filters to the list. */
342   if (s[0] == '\0')
343     return;
344
345   if (ifname == NULL)
346     cfilter_list = recent_cfilter_list;
347   else {
348     /* If we don't yet have a hash table for per-interface recent
349        capture filter lists, create one.  Have it free the new key
350        if we're updating an entry rather than creating it below. */
351     if (per_interface_cfilter_lists_hash == NULL)
352       per_interface_cfilter_lists_hash = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
353     cfilter_list = (GList *)g_hash_table_lookup(per_interface_cfilter_lists_hash, ifname);
354   }
355
356   li = g_list_first(cfilter_list);
357   while (li) {
358     /* If the filter is already in the list, remove the old one and
359      * append the new one at the latest position (at g_list_append() below) */
360     li_filter = (char *)li->data;
361     if (strcmp(s, li_filter) == 0) {
362       /* No need to copy the string, we're just moving it. */
363       newfilter = li_filter;
364       cfilter_list = g_list_remove(cfilter_list, li->data);
365       break;
366     }
367     li = li->next;
368   }
369   if (newfilter == NULL) {
370     /* The filter wasn't already in the list; make a copy to add. */
371     newfilter = g_strdup(s);
372   }
373   cfilter_list = g_list_append(cfilter_list, newfilter);
374
375   if (ifname == NULL)
376     recent_cfilter_list = cfilter_list;
377   else
378     g_hash_table_insert(per_interface_cfilter_lists_hash, g_strdup(ifname), cfilter_list);
379 }
380
381 #ifdef HAVE_PCAP_REMOTE
382 static GHashTable *remote_host_list=NULL;
383
384 int recent_get_remote_host_list_size(void)
385 {
386   return g_hash_table_size (remote_host_list);
387 }
388
389 void recent_add_remote_host(gchar *host, struct remote_host *rh)
390 {
391   if (remote_host_list == NULL) {
392     remote_host_list = g_hash_table_new (g_str_hash, g_str_equal);
393   }
394   g_hash_table_insert (remote_host_list, g_strdup(host), rh);
395 }
396
397 static gboolean
398 free_remote_host (gpointer key _U_, gpointer value, gpointer user _U_)
399 {
400   struct remote_host *rh = value;
401
402   g_free (rh->r_host);
403   g_free (rh->remote_port);
404   g_free (rh->auth_username);
405   g_free (rh->auth_password);
406
407   return TRUE;
408 }
409
410 GHashTable *get_remote_host_list(void)
411 {
412   return remote_host_list;
413 }
414
415 static void
416 recent_print_remote_host (gpointer key _U_, gpointer value, gpointer user)
417 {
418   FILE *rf = user;
419   struct remote_host_info *ri = value;
420
421   fprintf (rf, RECENT_KEY_REMOTE_HOST ": %s,%s,%d\n", ri->remote_host, ri->remote_port, ri->auth_type);
422 }
423
424 void
425 capture_remote_combo_recent_write_all(FILE *rf)
426 {
427   if (remote_host_list && g_hash_table_size (remote_host_list) > 0) {
428     /* Write all remote interfaces to the recent file */
429     g_hash_table_foreach (remote_host_list, recent_print_remote_host, rf);
430   }
431 }
432
433
434 void free_remote_host_list(void)
435 {
436   g_hash_table_foreach_remove(remote_host_list, free_remote_host, NULL);
437 }
438
439 struct remote_host *
440 recent_get_remote_host(const gchar *host)
441 {
442   if (host == NULL)
443     return NULL;
444   if (remote_host_list == NULL) {
445     /* No such host exist. */
446     return NULL;
447   }
448   return (struct remote_host *)g_hash_table_lookup(remote_host_list, host);
449 }
450
451 gboolean
452 capture_remote_combo_add_recent(const gchar *s)
453 {
454   GList *vals = prefs_get_string_list (s);
455   GList *valp = vals;
456   gint   auth_type;
457   char  *p;
458   struct remote_host *rh;
459
460   if (valp == NULL)
461     return FALSE;
462
463   if (remote_host_list == NULL) {
464     remote_host_list = g_hash_table_new (g_str_hash, g_str_equal);
465   }
466
467   rh = g_malloc (sizeof (*rh));
468
469   /* First value is the host */
470   rh->r_host = g_strdup (valp->data);
471   if (strlen(rh->r_host) == 0) {
472     /* Empty remote host */
473     g_free(rh->r_host);
474     g_free(rh);
475     return FALSE;
476   }
477   rh->auth_type = CAPTURE_AUTH_NULL;
478   valp = valp->next;
479
480   if (valp) {
481     /* Found value 2, this is the port number */
482     rh->remote_port = g_strdup (valp->data);
483     valp = valp->next;
484   } else {
485     /* Did not find a port number */
486     rh->remote_port = g_strdup ("");
487   }
488
489   if (valp) {
490     /* Found value 3, this is the authentication type */
491     auth_type = strtol(valp->data, &p, 0);
492     if (p != valp->data && *p == '\0') {
493       rh->auth_type = auth_type;
494     }
495   }
496
497   /* Do not store username and password */
498   rh->auth_username = g_strdup ("");
499   rh->auth_password = g_strdup ("");
500
501   prefs_clear_string_list(vals);
502
503   g_hash_table_insert (remote_host_list, g_strdup(rh->r_host), rh);
504
505   return TRUE;
506 }
507 #endif
508
509 static void
510 cfilter_recent_write_all_list(FILE *rf, const gchar *ifname, GList *cfilter_list)
511 {
512   guint      max_count = 0;
513   GList     *li;
514
515   /* write all non empty capture filter strings to the recent file (until max count) */
516   li = g_list_first(cfilter_list);
517   while (li && (max_count++ <= cfilter_combo_max_recent) ) {
518     if (li->data && strlen((const char *)li->data)) {
519       if (ifname == NULL)
520         fprintf (rf, RECENT_KEY_CAPTURE_FILTER ": %s\n", (char *)li->data);
521       else
522         fprintf (rf, RECENT_KEY_CAPTURE_FILTER ".%s: %s\n", ifname, (char *)li->data);
523     }
524     li = li->next;
525   }
526 }
527
528 static void
529 cfilter_recent_write_all_hash_callback(gpointer key, gpointer value, gpointer user_data)
530 {
531   cfilter_recent_write_all_list((FILE *)user_data, (const gchar *)key, (GList *)value);
532 }
533
534 /** Write all capture filter values to the recent file.
535  *
536  * @param rf recent file handle from caller
537  */
538 static void
539 cfilter_recent_write_all(FILE *rf)
540 {
541   /* Write out the global list. */
542   cfilter_recent_write_all_list(rf, NULL, recent_cfilter_list);
543
544   /* Write out all the per-interface lists. */
545   if (per_interface_cfilter_lists_hash != NULL) {
546     g_hash_table_foreach(per_interface_cfilter_lists_hash, cfilter_recent_write_all_hash_callback, (gpointer)rf);
547   }
548 }
549
550 /* Write out recent settings of particular types. */
551 static void
552 write_recent_boolean(FILE *rf, const char *description, const char *name,
553                      gboolean value)
554 {
555   fprintf(rf, "\n# %s.\n", description);
556   fprintf(rf, "# TRUE or FALSE (case-insensitive).\n");
557   fprintf(rf, "%s: %s\n", name, value == TRUE ? "TRUE" : "FALSE");
558 }
559
560 static void
561 write_recent_enum(FILE *rf, const char *description, const char *name,
562                   const value_string *values, guint value)
563 {
564   const char *if_invalid = NULL;
565   const value_string *valp;
566
567   fprintf(rf, "\n# %s.\n", description);
568   fprintf(rf, "# One of: ");
569   valp = values;
570   while (valp->strptr != NULL) {
571     if (if_invalid == NULL)
572       if_invalid = valp->strptr;
573     fprintf(rf, "%s", valp->strptr);
574     valp++;
575     if (valp->strptr != NULL)
576       fprintf(rf, ", ");
577   }
578   fprintf(rf, "\n");
579   fprintf(rf, "%s: %s\n", name,
580           val_to_str(value, values, if_invalid != NULL ? if_invalid : "Unknown"));
581 }
582
583 /* Attempt to write out "recent common" to the user's recent common file.
584    If we got an error report it with a dialog box and return FALSE,
585    otherwise return TRUE. */
586 gboolean
587 write_recent(void)
588 {
589   char        *pf_dir_path;
590   char        *rf_path;
591   FILE        *rf;
592   char        *string_list;
593
594   /* To do:
595    * - Split output lines longer than MAX_VAL_LEN
596    * - Create a function for the preference directory check/creation
597    *   so that duplication can be avoided with filter.c
598    */
599
600   /* Create the directory that holds personal configuration files, if
601      necessary.  */
602   if (create_persconffile_dir(&pf_dir_path) == -1) {
603      simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
604       "Can't create directory\n\"%s\"\nfor recent file: %s.", pf_dir_path,
605       g_strerror(errno));
606      g_free(pf_dir_path);
607      return FALSE;
608   }
609
610   rf_path = get_persconffile_path(RECENT_COMMON_FILE_NAME, FALSE);
611   if ((rf = ws_fopen(rf_path, "w")) == NULL) {
612      simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
613       "Can't open recent file\n\"%s\": %s.", rf_path,
614       g_strerror(errno));
615     g_free(rf_path);
616     return FALSE;
617   }
618   g_free(rf_path);
619
620   fputs("# Recent settings file for Wireshark " VERSION ".\n"
621     "#\n"
622     "# This file is regenerated each time Wireshark is quit.\n"
623     "# So be careful, if you want to make manual changes here.\n"
624     "\n"
625     "######## Recent capture files (latest last), cannot be altered through command line ########\n"
626     "\n", rf);
627
628   menu_recent_file_write_all(rf);
629
630   fputs("\n"
631     "######## Recent capture filters (latest last), cannot be altered through command line ########\n"
632     "\n", rf);
633
634   cfilter_recent_write_all(rf);
635
636   fputs("\n"
637     "######## Recent display filters (latest last), cannot be altered through command line ########\n"
638     "\n", rf);
639
640   dfilter_recent_combo_write_all(rf);
641
642 #ifdef HAVE_PCAP_REMOTE
643   fputs("\n"
644     "######## Recent remote hosts, cannot be altered through command line ########\n"
645     "\n", rf);
646
647   capture_remote_combo_recent_write_all(rf);
648 #endif
649
650   fprintf(rf, "\n# Main window geometry.\n");
651   fprintf(rf, "# Decimal numbers.\n");
652   fprintf(rf, RECENT_GUI_GEOMETRY_MAIN_X ": %d\n", recent.gui_geometry_main_x);
653   fprintf(rf, RECENT_GUI_GEOMETRY_MAIN_Y ": %d\n", recent.gui_geometry_main_y);
654   fprintf(rf, RECENT_GUI_GEOMETRY_MAIN_WIDTH ": %d\n",
655           recent.gui_geometry_main_width);
656   fprintf(rf, RECENT_GUI_GEOMETRY_MAIN_HEIGHT ": %d\n",
657           recent.gui_geometry_main_height);
658
659   write_recent_boolean(rf, "Main window maximized",
660                        RECENT_GUI_GEOMETRY_MAIN_MAXIMIZED,
661                        recent.gui_geometry_main_maximized);
662
663   fprintf(rf, "\n# Statusbar left pane size.\n");
664   fprintf(rf, "# Decimal number.\n");
665   if (recent.gui_geometry_status_pane_left != 0) {
666     fprintf(rf, RECENT_GUI_GEOMETRY_STATUS_PANE_LEFT ": %d\n",
667             recent.gui_geometry_status_pane_left);
668   }
669   fprintf(rf, "\n# Statusbar middle pane size.\n");
670   fprintf(rf, "# Decimal number.\n");
671   if (recent.gui_geometry_status_pane_right != 0) {
672     fprintf(rf, RECENT_GUI_GEOMETRY_STATUS_PANE_RIGHT ": %d\n",
673             recent.gui_geometry_status_pane_right);
674   }
675
676   fprintf(rf, "\n# Last used Configuration Profile.\n");
677   fprintf(rf, RECENT_LAST_USED_PROFILE ": %s\n", get_profile_name());
678
679   fprintf(rf, "\n# WLAN statistics upper pane size.\n");
680   fprintf(rf, "# Decimal number.\n");
681   fprintf(rf, RECENT_GUI_GEOMETRY_WLAN_STATS_PANE ": %d\n",
682           recent.gui_geometry_wlan_stats_pane);
683
684   write_recent_boolean(rf, "Warn if running with elevated permissions (e.g. as root)",
685                        RECENT_KEY_PRIVS_WARN_IF_ELEVATED,
686                        recent.privs_warn_if_elevated);
687
688   write_recent_boolean(rf, "Warn if npf.sys isn't loaded on Windows >= 6.0",
689                        RECENT_KEY_PRIVS_WARN_IF_NO_NPF,
690                        recent.privs_warn_if_no_npf);
691
692   window_geom_recent_write_all(rf);
693
694   fprintf(rf, "\n# Custom colors.\n");
695   fprintf(rf, "# List of custom colors selected in Qt color picker.\n");
696   string_list = join_string_list(recent.custom_colors);
697   fprintf(rf, RECENT_GUI_CUSTOM_COLORS ": %s\n", string_list);
698   g_free(string_list);
699
700   fclose(rf);
701
702   /* XXX - catch I/O errors (e.g. "ran out of disk space") and return
703      an error indication, or maybe write to a new recent file and
704      rename that file on top of the old one only if there are not I/O
705      errors. */
706   return TRUE;
707 }
708
709
710 /* Attempt to Write out profile "recent" to the user's profile recent file.
711    If we got an error report it with a dialog box and return FALSE,
712    otherwise return TRUE. */
713 gboolean
714 write_profile_recent(void)
715 {
716   char        *pf_dir_path;
717   char        *rf_path;
718   char        *string_list;
719   FILE        *rf;
720
721   /* To do:
722    * - Split output lines longer than MAX_VAL_LEN
723    * - Create a function for the preference directory check/creation
724    *   so that duplication can be avoided with filter.c
725    */
726
727   /* Create the directory that holds personal configuration files, if
728      necessary.  */
729   if (create_persconffile_dir(&pf_dir_path) == -1) {
730      simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
731       "Can't create directory\n\"%s\"\nfor recent file: %s.", pf_dir_path,
732       g_strerror(errno));
733      g_free(pf_dir_path);
734      return FALSE;
735   }
736
737   rf_path = get_persconffile_path(RECENT_FILE_NAME, TRUE);
738   if ((rf = ws_fopen(rf_path, "w")) == NULL) {
739      simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
740       "Can't open recent file\n\"%s\": %s.", rf_path,
741       g_strerror(errno));
742     g_free(rf_path);
743     return FALSE;
744   }
745   g_free(rf_path);
746
747   fputs("# Recent settings file for Wireshark " VERSION ".\n"
748     "#\n"
749     "# This file is regenerated each time Wireshark is quit\n"
750     "# and when changing configuration profile.\n"
751     "# So be careful, if you want to make manual changes here.\n"
752     "\n", rf);
753
754   write_recent_boolean(rf, "Main Toolbar show (hide)",
755                        RECENT_KEY_MAIN_TOOLBAR_SHOW,
756                        recent.main_toolbar_show);
757
758   write_recent_boolean(rf, "Filter Toolbar show (hide)",
759                        RECENT_KEY_FILTER_TOOLBAR_SHOW,
760                        recent.filter_toolbar_show);
761
762   write_recent_boolean(rf, "Wireless Settings Toolbar show (hide)",
763                        RECENT_KEY_WIRELESS_TOOLBAR_SHOW,
764                        recent.wireless_toolbar_show);
765
766 #ifdef HAVE_AIRPCAP
767   write_recent_boolean(rf, "Show (hide) old AirPcap driver warning dialog box",
768                        RECENT_KEY_DRIVER_CHECK_SHOW,
769                        recent.airpcap_driver_check_show);
770 #endif
771
772   write_recent_boolean(rf, "Packet list show (hide)",
773                        RECENT_KEY_PACKET_LIST_SHOW,
774                        recent.packet_list_show);
775
776   write_recent_boolean(rf, "Tree view show (hide)",
777                        RECENT_KEY_TREE_VIEW_SHOW,
778                        recent.tree_view_show);
779
780   write_recent_boolean(rf, "Byte view show (hide)",
781                        RECENT_KEY_BYTE_VIEW_SHOW,
782                        recent.byte_view_show);
783
784   write_recent_boolean(rf, "Statusbar show (hide)",
785                        RECENT_KEY_STATUSBAR_SHOW,
786                        recent.statusbar_show);
787
788   write_recent_boolean(rf, "Packet list colorize (hide)",
789                        RECENT_KEY_PACKET_LIST_COLORIZE,
790                        recent.packet_list_colorize);
791
792   write_recent_enum(rf, "Timestamp display format",
793                     RECENT_GUI_TIME_FORMAT, ts_type_values,
794                     recent.gui_time_format);
795
796   write_recent_enum(rf, "Timestamp display precision",
797                     RECENT_GUI_TIME_PRECISION, ts_precision_values,
798                     recent.gui_time_precision);
799
800   write_recent_enum(rf, "Seconds display format",
801                     RECENT_GUI_SECONDS_FORMAT, ts_seconds_values,
802                     recent.gui_seconds_format);
803
804   fprintf(rf, "\n# Zoom level.\n");
805   fprintf(rf, "# A decimal number.\n");
806   fprintf(rf, RECENT_GUI_ZOOM_LEVEL ": %d\n",
807           recent.gui_zoom_level);
808
809   fprintf(rf, "\n# Bytes view.\n");
810   fprintf(rf, "# A decimal number.\n");
811   fprintf(rf, RECENT_GUI_BYTES_VIEW ": %d\n",
812           recent.gui_bytes_view);
813
814   fprintf(rf, "\n# Main window upper (or leftmost) pane size.\n");
815   fprintf(rf, "# Decimal number.\n");
816   if (recent.gui_geometry_main_upper_pane != 0) {
817     fprintf(rf, RECENT_GUI_GEOMETRY_MAIN_UPPER_PANE ": %d\n",
818             recent.gui_geometry_main_upper_pane);
819   }
820   fprintf(rf, "\n# Main window middle pane size.\n");
821   fprintf(rf, "# Decimal number.\n");
822   if (recent.gui_geometry_main_lower_pane != 0) {
823     fprintf(rf, RECENT_GUI_GEOMETRY_MAIN_LOWER_PANE ": %d\n",
824             recent.gui_geometry_main_lower_pane);
825   }
826
827   fprintf(rf, "\n# Packet list column pixel widths.\n");
828   fprintf(rf, "# Each pair of strings consists of a column format and its pixel width.\n");
829   packet_list_recent_write_all(rf);
830
831   fprintf(rf, "\n# Open conversation dialog tabs.\n");
832   fprintf(rf, "# List of conversation names, e.g. \"TCP\", \"IPv6\".\n");
833   string_list = join_string_list(recent.conversation_tabs);
834   fprintf(rf, RECENT_GUI_CONVERSATION_TABS ": %s\n", string_list);
835   g_free(string_list);
836
837   fprintf(rf, "\n# Open endpoint dialog tabs.\n");
838   fprintf(rf, "# List of endpoint names, e.g. \"TCP\", \"IPv6\".\n");
839   string_list = join_string_list(recent.endpoint_tabs);
840   fprintf(rf, RECENT_GUI_ENDPOINT_TABS ": %s\n", string_list);
841   g_free(string_list);
842
843   write_recent_boolean(rf, "For RLC stats, whether to use RLC PDUs found inside MAC frames",
844                        RECENT_GUI_RLC_PDUS_FROM_MAC_FRAMES,
845                        recent.gui_rlc_use_pdus_from_mac);
846
847   if (get_last_open_dir() != NULL) {
848     fprintf(rf, "\n# Last directory navigated to in File Open dialog.\n");
849
850     if (u3_active())
851       fprintf(rf, RECENT_GUI_FILEOPEN_REMEMBERED_DIR ": %s\n", u3_contract_device_path(get_last_open_dir()));
852     else
853       fprintf(rf, RECENT_GUI_FILEOPEN_REMEMBERED_DIR ": %s\n", get_last_open_dir());
854   }
855
856   fclose(rf);
857
858   /* XXX - catch I/O errors (e.g. "ran out of disk space") and return
859      an error indication, or maybe write to a new recent file and
860      rename that file on top of the old one only if there are not I/O
861      errors. */
862   return TRUE;
863 }
864
865 /* set one user's recent common file key/value pair */
866 static prefs_set_pref_e
867 read_set_recent_common_pair_static(gchar *key, const gchar *value,
868                                    void *private_data _U_,
869                                    gboolean return_range_errors _U_)
870 {
871   long num;
872   char *p;
873
874   if (strcmp(key, RECENT_GUI_GEOMETRY_MAIN_MAXIMIZED) == 0) {
875     parse_recent_boolean(value, &recent.gui_geometry_main_maximized);
876   } else if (strcmp(key, RECENT_GUI_GEOMETRY_MAIN_X) == 0) {
877     num = strtol(value, &p, 0);
878     if (p == value || *p != '\0')
879       return PREFS_SET_SYNTAX_ERR;      /* number was bad */
880     recent.gui_geometry_main_x = (gint)num;
881   } else if (strcmp(key, RECENT_GUI_GEOMETRY_MAIN_Y) == 0) {
882     num = strtol(value, &p, 0);
883     if (p == value || *p != '\0')
884       return PREFS_SET_SYNTAX_ERR;      /* number was bad */
885     recent.gui_geometry_main_y = (gint)num;
886   } else if (strcmp(key, RECENT_GUI_GEOMETRY_MAIN_WIDTH) == 0) {
887     num = strtol(value, &p, 0);
888     if (p == value || *p != '\0')
889       return PREFS_SET_SYNTAX_ERR;      /* number was bad */
890     if (num <= 0)
891       return PREFS_SET_SYNTAX_ERR;      /* number must be positive */
892     recent.gui_geometry_main_width = (gint)num;
893   } else if (strcmp(key, RECENT_GUI_GEOMETRY_MAIN_HEIGHT) == 0) {
894     num = strtol(value, &p, 0);
895     if (p == value || *p != '\0')
896       return PREFS_SET_SYNTAX_ERR;      /* number was bad */
897     if (num <= 0)
898       return PREFS_SET_SYNTAX_ERR;      /* number must be positive */
899     recent.gui_geometry_main_height = (gint)num;
900   } else if (strcmp(key, RECENT_GUI_GEOMETRY_STATUS_PANE_RIGHT) == 0) {
901     num = strtol(value, &p, 0);
902     if (p == value || *p != '\0')
903       return PREFS_SET_SYNTAX_ERR;      /* number was bad */
904     if (num <= 0)
905       return PREFS_SET_SYNTAX_ERR;      /* number must be positive */
906     recent.gui_geometry_status_pane_right = (gint)num;
907     recent.has_gui_geometry_status_pane = TRUE;
908   } else if (strcmp(key, RECENT_GUI_GEOMETRY_STATUS_PANE_LEFT) == 0) {
909     num = strtol(value, &p, 0);
910     if (p == value || *p != '\0')
911       return PREFS_SET_SYNTAX_ERR;      /* number was bad */
912     if (num <= 0)
913       return PREFS_SET_SYNTAX_ERR;      /* number must be positive */
914     recent.gui_geometry_status_pane_left = (gint)num;
915     recent.has_gui_geometry_status_pane = TRUE;
916   } else if (strcmp(key, RECENT_LAST_USED_PROFILE) == 0) {
917     if ((strcmp(value, DEFAULT_PROFILE) != 0) && profile_exists (value, FALSE)) {
918       set_profile_name (value);
919     }
920   } else if (strcmp(key, RECENT_GUI_GEOMETRY_WLAN_STATS_PANE) == 0) {
921     num = strtol(value, &p, 0);
922     if (p == value || *p != '\0')
923       return PREFS_SET_SYNTAX_ERR;      /* number was bad */
924     if (num <= 0)
925       return PREFS_SET_SYNTAX_ERR;      /* number must be positive */
926     recent.gui_geometry_wlan_stats_pane = (gint)num;
927   } else if (strncmp(key, RECENT_GUI_GEOMETRY, sizeof(RECENT_GUI_GEOMETRY)-1) == 0) {
928     /* now have something like "gui.geom.main.x", split it into win and sub_key */
929     char *win = &key[sizeof(RECENT_GUI_GEOMETRY)-1];
930     char *sub_key = strchr(win, '.');
931     if (sub_key) {
932       *sub_key = '\0';
933       sub_key++;
934       window_geom_recent_read_pair(win, sub_key, value);
935     }
936   } else if (strcmp(key, RECENT_KEY_PRIVS_WARN_IF_ELEVATED) == 0) {
937     parse_recent_boolean(value, &recent.privs_warn_if_elevated);
938   } else if (strcmp(key, RECENT_KEY_PRIVS_WARN_IF_NO_NPF) == 0) {
939     parse_recent_boolean(value, &recent.privs_warn_if_no_npf);
940   } else if (strcmp(key, RECENT_GUI_CUSTOM_COLORS) == 0) {
941     recent.custom_colors = prefs_get_string_list(value);
942   }
943
944   return PREFS_SET_OK;
945 }
946
947 /* set one user's recent file key/value pair */
948 static prefs_set_pref_e
949 read_set_recent_pair_static(gchar *key, const gchar *value,
950                             void *private_data _U_,
951                             gboolean return_range_errors _U_)
952 {
953   long num;
954   char *p;
955   GList *col_l, *col_l_elt;
956   col_width_data *cfmt;
957   const gchar *cust_format = col_format_to_string(COL_CUSTOM);
958   int cust_format_len = (int) strlen(cust_format);
959
960   if (strcmp(key, RECENT_KEY_MAIN_TOOLBAR_SHOW) == 0) {
961     parse_recent_boolean(value, &recent.main_toolbar_show);
962   } else if (strcmp(key, RECENT_KEY_FILTER_TOOLBAR_SHOW) == 0) {
963     parse_recent_boolean(value, &recent.filter_toolbar_show);
964   /* check both the old and the new keyword */
965   } else if (strcmp(key, RECENT_KEY_WIRELESS_TOOLBAR_SHOW) == 0 || (strcmp(key, "gui.airpcap_toolbar_show") == 0)) {
966     parse_recent_boolean(value, &recent.wireless_toolbar_show);
967   } else if (strcmp(key, RECENT_KEY_DRIVER_CHECK_SHOW) == 0) {
968     parse_recent_boolean(value, &recent.airpcap_driver_check_show);
969   } else if (strcmp(key, RECENT_KEY_PACKET_LIST_SHOW) == 0) {
970     parse_recent_boolean(value, &recent.packet_list_show);
971   } else if (strcmp(key, RECENT_KEY_TREE_VIEW_SHOW) == 0) {
972     parse_recent_boolean(value, &recent.tree_view_show);
973   } else if (strcmp(key, RECENT_KEY_BYTE_VIEW_SHOW) == 0) {
974     parse_recent_boolean(value, &recent.byte_view_show);
975   } else if (strcmp(key, RECENT_KEY_STATUSBAR_SHOW) == 0) {
976     parse_recent_boolean(value, &recent.statusbar_show);
977   } else if (strcmp(key, RECENT_KEY_PACKET_LIST_COLORIZE) == 0) {
978     parse_recent_boolean(value, &recent.packet_list_colorize);
979   } else if (strcmp(key, RECENT_GUI_TIME_FORMAT) == 0) {
980     recent.gui_time_format =
981       (ts_type)str_to_val(value, ts_type_values, TS_RELATIVE);
982   } else if (strcmp(key, RECENT_GUI_TIME_PRECISION) == 0) {
983     recent.gui_time_precision =
984       (ts_precision)str_to_val(value, ts_precision_values, TS_PREC_AUTO);
985   } else if (strcmp(key, RECENT_GUI_SECONDS_FORMAT) == 0) {
986     recent.gui_seconds_format =
987       (ts_seconds_type)str_to_val(value, ts_seconds_values, TS_SECONDS_DEFAULT);
988   } else if (strcmp(key, RECENT_GUI_ZOOM_LEVEL) == 0) {
989     num = strtol(value, &p, 0);
990     if (p == value || *p != '\0')
991       return PREFS_SET_SYNTAX_ERR;      /* number was bad */
992     recent.gui_zoom_level = (gint)num;
993   } else if (strcmp(key, RECENT_GUI_BYTES_VIEW) == 0) {
994     num = strtol(value, &p, 0);
995     if (p == value || *p != '\0')
996       return PREFS_SET_SYNTAX_ERR;      /* number was bad */
997     recent.gui_bytes_view = (bytes_view_type)num;
998   } else if (strcmp(key, RECENT_GUI_GEOMETRY_MAIN_MAXIMIZED) == 0) {
999     parse_recent_boolean(value, &recent.gui_geometry_main_maximized);
1000   } else if (strcmp(key, RECENT_GUI_GEOMETRY_MAIN_UPPER_PANE) == 0) {
1001     num = strtol(value, &p, 0);
1002     if (p == value || *p != '\0')
1003       return PREFS_SET_SYNTAX_ERR;      /* number was bad */
1004     if (num <= 0)
1005       return PREFS_SET_SYNTAX_ERR;      /* number must be positive */
1006     recent.gui_geometry_main_upper_pane = (gint)num;
1007     recent.has_gui_geometry_main_upper_pane = TRUE;
1008   } else if (strcmp(key, RECENT_GUI_GEOMETRY_MAIN_LOWER_PANE) == 0) {
1009     num = strtol(value, &p, 0);
1010     if (p == value || *p != '\0')
1011       return PREFS_SET_SYNTAX_ERR;      /* number was bad */
1012     if (num <= 0)
1013       return PREFS_SET_SYNTAX_ERR;      /* number must be positive */
1014     recent.gui_geometry_main_lower_pane = (gint)num;
1015     recent.has_gui_geometry_main_lower_pane = TRUE;
1016   } else if (strcmp(key, RECENT_GUI_CONVERSATION_TABS) == 0) {
1017     recent.conversation_tabs = prefs_get_string_list(value);
1018   } else if (strcmp(key, RECENT_GUI_ENDPOINT_TABS) == 0) {
1019     recent.endpoint_tabs = prefs_get_string_list(value);
1020   } else if (strcmp(key, RECENT_GUI_RLC_PDUS_FROM_MAC_FRAMES) == 0) {
1021     parse_recent_boolean(value, &recent.gui_rlc_use_pdus_from_mac);
1022   } else if (strcmp(key, RECENT_KEY_COL_WIDTH) == 0) {
1023     col_l = prefs_get_string_list(value);
1024     if (col_l == NULL)
1025       return PREFS_SET_SYNTAX_ERR;
1026     if ((g_list_length(col_l) % 2) != 0) {
1027       /* A title didn't have a matching width.  */
1028       prefs_clear_string_list(col_l);
1029       return PREFS_SET_SYNTAX_ERR;
1030     }
1031     /* Check to make sure all column formats are valid.  */
1032     col_l_elt = g_list_first(col_l);
1033     while (col_l_elt) {
1034       /* Make sure the format isn't empty.  */
1035       if (strcmp((const char *)col_l_elt->data, "") == 0) {
1036         /* It is.  */
1037         prefs_clear_string_list(col_l);
1038         return PREFS_SET_SYNTAX_ERR;
1039       }
1040
1041       /* Check the format.  */
1042       if (strncmp((const char *)col_l_elt->data, cust_format, cust_format_len) != 0) {
1043         if (get_column_format_from_str((const gchar *)col_l_elt->data) == -1) {
1044           /* It's not a valid column format.  */
1045           prefs_clear_string_list(col_l);
1046           return PREFS_SET_SYNTAX_ERR;
1047         }
1048       }
1049
1050       /* Go past the format.  */
1051       col_l_elt = col_l_elt->next;
1052
1053       /* Go past the width.  */
1054       col_l_elt = col_l_elt->next;
1055     }
1056     free_col_width_info(&recent);
1057     recent.col_width_list = NULL;
1058     col_l_elt = g_list_first(col_l);
1059     while (col_l_elt) {
1060       gchar *fmt = g_strdup((const gchar *)col_l_elt->data);
1061       cfmt = (col_width_data *) g_malloc(sizeof(col_width_data));
1062       if (strncmp(fmt, cust_format, cust_format_len) != 0) {
1063         cfmt->cfmt   = get_column_format_from_str(fmt);
1064         cfmt->cfield = NULL;
1065       } else {
1066         cfmt->cfmt   = COL_CUSTOM;
1067         cfmt->cfield = g_strdup(&fmt[cust_format_len+1]);  /* add 1 for ':' */
1068       }
1069       g_free (fmt);
1070       if (cfmt->cfmt == -1) {
1071         g_free(cfmt->cfield);
1072         g_free(cfmt);
1073         return PREFS_SET_SYNTAX_ERR;   /* string was bad */
1074       }
1075
1076       col_l_elt      = col_l_elt->next;
1077       cfmt->width    = (gint)strtol((const char *)col_l_elt->data, &p, 0);
1078       if (p == col_l_elt->data || (*p != '\0' && *p != ':')) {
1079         g_free(cfmt->cfield);
1080         g_free(cfmt);
1081         return PREFS_SET_SYNTAX_ERR;    /* number was bad */
1082       }
1083
1084       if (*p == ':') {
1085         cfmt->xalign = *(++p);
1086       } else {
1087         cfmt->xalign = COLUMN_XALIGN_DEFAULT;
1088       }
1089
1090       col_l_elt      = col_l_elt->next;
1091       recent.col_width_list = g_list_append(recent.col_width_list, cfmt);
1092     }
1093     prefs_clear_string_list(col_l);
1094   } else if (strcmp(key, RECENT_GUI_FILEOPEN_REMEMBERED_DIR) == 0) {
1095     if (recent.gui_fileopen_remembered_dir) {
1096       g_free (recent.gui_fileopen_remembered_dir);
1097     }
1098     recent.gui_fileopen_remembered_dir = g_strdup(value);
1099   }
1100
1101   return PREFS_SET_OK;
1102 }
1103
1104
1105 /* set one user's recent file key/value pair */
1106 static prefs_set_pref_e
1107 read_set_recent_pair_dynamic(gchar *key, const gchar *value,
1108                              void *private_data _U_,
1109                              gboolean return_range_errors _U_)
1110 {
1111   if (!g_utf8_validate(value, -1, NULL)) {
1112     return PREFS_SET_SYNTAX_ERR;
1113   }
1114   if (strcmp(key, RECENT_KEY_CAPTURE_FILE) == 0) {
1115     if (u3_active())
1116       add_menu_recent_capture_file(u3_expand_device_path(value));
1117     else
1118       add_menu_recent_capture_file(value);
1119   } else if (strcmp(key, RECENT_KEY_DISPLAY_FILTER) == 0) {
1120     dfilter_combo_add_recent(value);
1121   } else if (strcmp(key, RECENT_KEY_CAPTURE_FILTER) == 0) {
1122     recent_add_cfilter(NULL, value);
1123   } else if (g_str_has_prefix(key, RECENT_KEY_CAPTURE_FILTER ".")) {
1124     /* strrchr() can't fail - string has a prefix that ends with a "." */
1125     recent_add_cfilter(strrchr(key, '.') + 1, value);
1126 #ifdef HAVE_PCAP_REMOTE
1127   } else if (strcmp(key, RECENT_KEY_REMOTE_HOST) == 0) {
1128     capture_remote_combo_add_recent(value);
1129 #endif
1130   }
1131
1132   return PREFS_SET_OK;
1133 }
1134
1135
1136 /*
1137  * Given a string of the form "<recent name>:<recent value>", as might appear
1138  * as an argument to a "-o" option, parse it and set the recent value in
1139  * question.  Return an indication of whether it succeeded or failed
1140  * in some fashion.
1141  */
1142 int
1143 recent_set_arg(char *prefarg)
1144 {
1145   gchar *p, *colonp;
1146   int ret;
1147
1148   colonp = strchr(prefarg, ':');
1149   if (colonp == NULL)
1150     return PREFS_SET_SYNTAX_ERR;
1151
1152   p = colonp;
1153   *p++ = '\0';
1154
1155   /*
1156    * Skip over any white space (there probably won't be any, but
1157    * as we allow it in the preferences file, we might as well
1158    * allow it here).
1159    */
1160   while (g_ascii_isspace(*p))
1161     p++;
1162   if (*p == '\0') {
1163     /*
1164      * Put the colon back, so if our caller uses, in an
1165      * error message, the string they passed us, the message
1166      * looks correct.
1167      */
1168     *colonp = ':';
1169     return PREFS_SET_SYNTAX_ERR;
1170   }
1171
1172   ret = read_set_recent_pair_static(prefarg, p, NULL, TRUE);
1173   *colonp = ':';     /* put the colon back */
1174   return ret;
1175 }
1176
1177
1178 /* opens the user's recent common file and read the first part */
1179 gboolean
1180 recent_read_static(char **rf_path_return, int *rf_errno_return)
1181 {
1182   char       *rf_path;
1183   FILE       *rf;
1184
1185   /* set defaults */
1186   recent.gui_geometry_main_x        =        20;
1187   recent.gui_geometry_main_y        =        20;
1188   recent.gui_geometry_main_width    = DEF_WIDTH;
1189   recent.gui_geometry_main_height   = DEF_HEIGHT;
1190   recent.gui_geometry_main_maximized=     FALSE;
1191
1192   recent.gui_geometry_status_pane_left  = (DEF_WIDTH/3);
1193   recent.gui_geometry_status_pane_right = (DEF_WIDTH/3);
1194   recent.gui_geometry_wlan_stats_pane   = 200;
1195
1196   recent.privs_warn_if_elevated = TRUE;
1197   recent.privs_warn_if_no_npf = TRUE;
1198
1199   recent.col_width_list = NULL;
1200   recent.gui_fileopen_remembered_dir = NULL;
1201
1202   /* Construct the pathname of the user's recent common file. */
1203   rf_path = get_persconffile_path(RECENT_COMMON_FILE_NAME, FALSE);
1204
1205   /* Read the user's recent common file, if it exists. */
1206   *rf_path_return = NULL;
1207   if ((rf = ws_fopen(rf_path, "r")) != NULL) {
1208     /* We succeeded in opening it; read it. */
1209     read_prefs_file(rf_path, rf, read_set_recent_common_pair_static, NULL);
1210
1211     fclose(rf);
1212   } else {
1213     /* We failed to open it.  If we failed for some reason other than
1214        "it doesn't exist", return the errno and the pathname, so our
1215        caller can report the error. */
1216     if (errno != ENOENT) {
1217       *rf_errno_return = errno;
1218       *rf_path_return = rf_path;
1219       return FALSE;
1220     }
1221   }
1222   g_free(rf_path);
1223   return TRUE;
1224 }
1225
1226
1227
1228 /* opens the user's recent file and read the first part */
1229 gboolean
1230 recent_read_profile_static(char **rf_path_return, int *rf_errno_return)
1231 {
1232   char       *rf_path, *rf_common_path;
1233   FILE       *rf;
1234
1235   /* set defaults */
1236   recent.main_toolbar_show         = TRUE;
1237   recent.filter_toolbar_show       = TRUE;
1238   recent.wireless_toolbar_show     = FALSE;
1239   recent.airpcap_driver_check_show = TRUE;
1240   recent.packet_list_show          = TRUE;
1241   recent.tree_view_show            = TRUE;
1242   recent.byte_view_show            = TRUE;
1243   recent.statusbar_show            = TRUE;
1244   recent.packet_list_colorize      = TRUE;
1245   recent.gui_time_format           = TS_RELATIVE;
1246   recent.gui_time_precision        = TS_PREC_AUTO;
1247   recent.gui_seconds_format        = TS_SECONDS_DEFAULT;
1248   recent.gui_zoom_level            = 0;
1249   recent.gui_bytes_view            = BYTES_HEX;
1250
1251   /* pane size of zero will autodetect */
1252   recent.gui_geometry_main_upper_pane   = 0;
1253   recent.gui_geometry_main_lower_pane   = 0;
1254
1255   recent.has_gui_geometry_main_upper_pane = TRUE;
1256   recent.has_gui_geometry_main_lower_pane = TRUE;
1257   recent.has_gui_geometry_status_pane     = TRUE;
1258
1259   if (recent.col_width_list) {
1260     free_col_width_info(&recent);
1261   }
1262
1263   if (recent.gui_fileopen_remembered_dir) {
1264     g_free (recent.gui_fileopen_remembered_dir);
1265     recent.gui_fileopen_remembered_dir = NULL;
1266   }
1267
1268   /* Construct the pathname of the user's profile recent file. */
1269   rf_path = get_persconffile_path(RECENT_FILE_NAME, TRUE);
1270
1271   /* Read the user's recent file, if it exists. */
1272   *rf_path_return = NULL;
1273   if ((rf = ws_fopen(rf_path, "r")) != NULL) {
1274     /* We succeeded in opening it; read it. */
1275     read_prefs_file(rf_path, rf, read_set_recent_pair_static, NULL);
1276     fclose(rf);
1277
1278     /* XXX: The following code doesn't actually do anything since
1279      *  the "recent common file" always exists. Presumably the
1280      *  "if (!file_exists())" should actually be "if (file_exists())".
1281      *  However, I've left the code as is because this
1282      *  behaviour has existed for quite some time and I don't
1283      *  know what's supposed to happen at this point.
1284      *  ToDo: Determine if the "recent common file" should be read at this point
1285      */
1286     rf_common_path = get_persconffile_path(RECENT_COMMON_FILE_NAME, FALSE);
1287     if (!file_exists(rf_common_path)) {
1288       /* Read older common settings from recent file */
1289       rf = ws_fopen(rf_path, "r");
1290       read_prefs_file(rf_path, rf, read_set_recent_common_pair_static, NULL);
1291       fclose(rf);
1292     }
1293     g_free(rf_common_path);
1294   } else {
1295     /* We failed to open it.  If we failed for some reason other than
1296        "it doesn't exist", return the errno and the pathname, so our
1297        caller can report the error. */
1298     if (errno != ENOENT) {
1299       *rf_errno_return = errno;
1300       *rf_path_return = rf_path;
1301       return FALSE;
1302     }
1303   }
1304   g_free(rf_path);
1305   return TRUE;
1306 }
1307
1308 /* opens the user's recent file and read it out */
1309 gboolean
1310 recent_read_dynamic(char **rf_path_return, int *rf_errno_return)
1311 {
1312   char       *rf_path;
1313   FILE       *rf;
1314
1315
1316   /* Construct the pathname of the user's recent common file. */
1317   rf_path = get_persconffile_path(RECENT_COMMON_FILE_NAME, FALSE);
1318   if (!file_exists (rf_path)) {
1319     /* Recent common file does not exist, read from default recent */
1320     g_free (rf_path);
1321     rf_path = get_persconffile_path(RECENT_FILE_NAME, FALSE);
1322   }
1323
1324   /* Read the user's recent file, if it exists. */
1325   *rf_path_return = NULL;
1326   if ((rf = ws_fopen(rf_path, "r")) != NULL) {
1327     /* We succeeded in opening it; read it. */
1328     read_prefs_file(rf_path, rf, read_set_recent_pair_dynamic, NULL);
1329 #if 0
1330     /* set dfilter combobox to have an empty line */
1331     dfilter_combo_add_empty();
1332 #endif
1333     fclose(rf);
1334   } else {
1335     /* We failed to open it.  If we failed for some reason other than
1336        "it doesn't exist", return the errno and the pathname, so our
1337        caller can report the error. */
1338     if (errno != ENOENT) {
1339       *rf_errno_return = errno;
1340       *rf_path_return = rf_path;
1341       return FALSE;
1342     }
1343   }
1344   g_free(rf_path);
1345   return TRUE;
1346 }
1347
1348 gint
1349 recent_get_column_width(gint col)
1350 {
1351   GList *col_l;
1352   col_width_data *col_w;
1353   gint cfmt;
1354   const gchar *cfield = NULL;
1355
1356   cfmt = get_column_format(col);
1357   if (cfmt == COL_CUSTOM) {
1358     cfield = get_column_custom_fields(col);
1359   }
1360
1361   col_l = g_list_first(recent.col_width_list);
1362   while (col_l) {
1363     col_w = (col_width_data *) col_l->data;
1364     if (col_w->cfmt == cfmt) {
1365       if (cfmt != COL_CUSTOM || strcmp (cfield, col_w->cfield) == 0) {
1366         return col_w->width;
1367       }
1368     }
1369     col_l = col_l->next;
1370   }
1371
1372   return -1;
1373 }
1374
1375 void
1376 recent_set_column_width(gint col, gint width)
1377 {
1378   GList *col_l;
1379   col_width_data *col_w;
1380   gint cfmt;
1381   const gchar *cfield = NULL;
1382   gboolean found = FALSE;
1383
1384   cfmt = get_column_format(col);
1385   if (cfmt == COL_CUSTOM) {
1386     cfield = get_column_custom_fields(col);
1387   }
1388
1389   col_l = g_list_first(recent.col_width_list);
1390   while (col_l) {
1391     col_w = (col_width_data *) col_l->data;
1392     if (col_w->cfmt == cfmt) {
1393       if (cfmt != COL_CUSTOM || strcmp (cfield, col_w->cfield) == 0) {
1394         col_w->width = width;
1395         found = TRUE;
1396         break;
1397       }
1398     }
1399     col_l = col_l->next;
1400   }
1401
1402   if (!found) {
1403     col_w = (col_width_data *) g_malloc(sizeof(col_width_data));
1404     col_w->cfmt = cfmt;
1405     if (cfield) {
1406       col_w->cfield = g_strdup(cfield);
1407     } else {
1408       col_w->cfield = NULL;
1409     }
1410     col_w->width = width;
1411     col_w->xalign = COLUMN_XALIGN_DEFAULT;
1412     recent.col_width_list = g_list_append(recent.col_width_list, col_w);
1413   }
1414 }
1415
1416 gchar
1417 recent_get_column_xalign(gint col)
1418 {
1419   GList *col_l;
1420   col_width_data *col_w;
1421   gint cfmt;
1422   const gchar *cfield = NULL;
1423
1424   cfmt = get_column_format(col);
1425   if (cfmt == COL_CUSTOM) {
1426     cfield = get_column_custom_fields(col);
1427   }
1428
1429   col_l = g_list_first(recent.col_width_list);
1430   while (col_l) {
1431     col_w = (col_width_data *) col_l->data;
1432     if (col_w->cfmt == cfmt) {
1433       if (cfmt != COL_CUSTOM || strcmp (cfield, col_w->cfield) == 0) {
1434         return col_w->xalign;
1435       }
1436     }
1437     col_l = col_l->next;
1438   }
1439
1440   return 0;
1441 }
1442
1443 void
1444 recent_set_column_xalign(gint col, gchar xalign)
1445 {
1446   GList *col_l;
1447   col_width_data *col_w;
1448   gint cfmt;
1449   const gchar *cfield = NULL;
1450   gboolean found = FALSE;
1451
1452   cfmt = get_column_format(col);
1453   if (cfmt == COL_CUSTOM) {
1454     cfield = get_column_custom_fields(col);
1455   }
1456
1457   col_l = g_list_first(recent.col_width_list);
1458   while (col_l) {
1459     col_w = (col_width_data *) col_l->data;
1460     if (col_w->cfmt == cfmt) {
1461       if (cfmt != COL_CUSTOM || strcmp (cfield, col_w->cfield) == 0) {
1462         col_w->xalign = xalign;
1463         found = TRUE;
1464         break;
1465       }
1466     }
1467     col_l = col_l->next;
1468   }
1469
1470   if (!found) {
1471     col_w = (col_width_data *) g_malloc(sizeof(col_width_data));
1472     col_w->cfmt = cfmt;
1473     if (cfield) {
1474       col_w->cfield = g_strdup(cfield);
1475     } else {
1476       col_w->cfield = NULL;
1477     }
1478     col_w->width = 40;
1479     col_w->xalign = xalign;
1480     recent.col_width_list = g_list_append(recent.col_width_list, col_w);
1481   }
1482 }
1483
1484 /*
1485  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
1486  *
1487  * Local Variables:
1488  * c-basic-offset: 2
1489  * tab-width: 8
1490  * indent-tabs-mode: nil
1491  * End:
1492  *
1493  * ex: set shiftwidth=2 tabstop=8 expandtab:
1494  * :indentSize=2:tabSize=8:noTabs=true:
1495  */