85e505cdb34113b54893259f32ece3516ec367c3
[obnox/wireshark/wip.git] / gtk / recent.c
1 /* recent.c
2  * Recent "preference" handling routines
3  * Copyright 2004, Ulf Lamping <ulf.lamping@web.de>
4  *
5  * $Id$
6  *
7  * Ethereal - Network traffic analyzer
8  * By Gerald Combs <gerald@ethereal.com>
9  * Copyright 1998 Gerald Combs
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24  */
25
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #include <gtk/gtk.h>
31 #include <stdio.h>
32 #include <string.h>
33 #include <ctype.h>
34
35 #include "recent.h"
36 #include <epan/epan.h>
37 #include <epan/filesystem.h>
38 #include "menu.h"
39 #include "main.h"
40 #include <epan/prefs.h>
41 #include <epan/prefs-int.h>
42 #include "gui_utils.h"
43 #include "dlg_utils.h"
44 #include "cfilter_combo_utils.h"
45 #include "simple_dialog.h"
46
47 #define RECENT_KEY_MAIN_TOOLBAR_SHOW        "gui.toolbar_main_show"
48 #define RECENT_KEY_FILTER_TOOLBAR_SHOW      "gui.filter_toolbar_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_ZOOM_LEVEL               "gui.zoom_level"
57 #define RECENT_GUI_GEOMETRY_MAIN_X          "gui.geometry_main_x"
58 #define RECENT_GUI_GEOMETRY_MAIN_Y          "gui.geometry_main_y"
59 #define RECENT_GUI_GEOMETRY_MAIN_WIDTH      "gui.geometry_main_width"
60 #define RECENT_GUI_GEOMETRY_MAIN_HEIGHT     "gui.geometry_main_height"
61 #define RECENT_GUI_GEOMETRY_MAIN_MAXIMIZED  "gui.geometry_main_maximized"
62 #define RECENT_GUI_GEOMETRY_MAIN_UPPER_PANE "gui.geometry_main_upper_pane"
63 #define RECENT_GUI_GEOMETRY_MAIN_LOWER_PANE "gui.geometry_main_lower_pane"
64 #define RECENT_GUI_GEOMETRY_STATUS_PANE     "gui.geometry_status_pane"
65 #define RECENT_GUI_FILEOPEN_REMEMBERED_DIR  "gui.fileopen_remembered_dir"
66 #define RECENT_GUI_GEOMETRY "gui.geom."
67
68 #define RECENT_FILE_NAME "recent"
69
70 recent_settings_t recent;
71
72 static const char *ts_type_text[] =
73         { "RELATIVE", "ABSOLUTE", "ABSOLUTE_WITH_DATE", "DELTA", NULL };
74
75 static const char *ts_precision_text[] =
76         { "AUTO", "SEC", "DSEC", "CSEC", "MSEC", "USEC", "NSEC", NULL };
77
78 /* Takes an string and a pointer to an array of strings, and a default int value.
79  * The array must be terminated by a NULL string. If the string is found in the array
80  * of strings, the index of that string in the array is returned. Otherwise, the
81  * default value that was passed as the third argument is returned.
82  */
83 static int
84 find_index_from_string_array(const char *needle, const char **haystack, int default_value)
85 {
86         int i = 0;
87
88         while (haystack[i] != NULL) {
89                 if (strcmp(needle, haystack[i]) == 0) {
90                         return i;
91                 }
92                 i++;
93         }
94         return default_value;
95 }
96
97 /* Attempt to Write out "recent" to the user's recent file.
98    If we got an error report it with a dialog box and return FALSE,
99    otherwise return TRUE. */
100 gboolean
101 write_recent(void)
102 {
103   char        *pf_dir_path;
104   char        *rf_path;
105   FILE        *rf;
106
107   /* To do:
108    * - Split output lines longer than MAX_VAL_LEN
109    * - Create a function for the preference directory check/creation
110    *   so that duplication can be avoided with filter.c
111    */
112
113   /* Create the directory that holds personal configuration files, if
114      necessary.  */
115   if (create_persconffile_dir(&pf_dir_path) == -1) {
116      simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
117       "Can't create directory\n\"%s\"\nfor recent file: %s.", pf_dir_path,
118       strerror(errno));
119      g_free(pf_dir_path);
120      return FALSE;
121   }
122
123   rf_path = get_persconffile_path(RECENT_FILE_NAME, TRUE);
124   if ((rf = fopen(rf_path, "w")) == NULL) {
125      simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
126       "Can't open recent file\n\"%s\": %s.", rf_path,
127       strerror(errno));
128     g_free(rf_path);
129     return FALSE;
130   }
131
132   fputs("# Recent settings file for Ethereal " VERSION ".\n"
133     "#\n"
134     "# This file is regenerated each time Ethereal is quit.\n"
135     "# So be careful, if you want to make manual changes here.\n"
136     "\n"
137     "######## Recent capture files (latest last), cannot be altered through command line ########\n"
138     "\n", rf);
139
140   menu_recent_file_write_all(rf);
141
142   fputs("\n"
143     "######## Recent capture filters (latest last), cannot be altered through command line ########\n"
144     "\n", rf);
145
146   cfilter_combo_recent_write_all(rf);
147
148   fputs("\n"
149     "######## Recent display filters (latest last), cannot be altered through command line ########\n"
150     "\n", rf);
151
152   dfilter_recent_combo_write_all(rf);
153
154   fprintf(rf, "\n# Main Toolbar show (hide).\n");
155   fprintf(rf, "# TRUE or FALSE (case-insensitive).\n");
156   fprintf(rf, RECENT_KEY_MAIN_TOOLBAR_SHOW ": %s\n",
157                   recent.main_toolbar_show == TRUE ? "TRUE" : "FALSE");
158
159   fprintf(rf, "\n# Filter Toolbar show (hide).\n");
160   fprintf(rf, "# TRUE or FALSE (case-insensitive).\n");
161   fprintf(rf, RECENT_KEY_FILTER_TOOLBAR_SHOW ": %s\n",
162                   recent.filter_toolbar_show == TRUE ? "TRUE" : "FALSE");
163
164   fprintf(rf, "\n# Packet list show (hide).\n");
165   fprintf(rf, "# TRUE or FALSE (case-insensitive).\n");
166   fprintf(rf, RECENT_KEY_PACKET_LIST_SHOW ": %s\n",
167                   recent.packet_list_show == TRUE ? "TRUE" : "FALSE");
168
169   fprintf(rf, "\n# Tree view show (hide).\n");
170   fprintf(rf, "# TRUE or FALSE (case-insensitive).\n");
171   fprintf(rf, RECENT_KEY_TREE_VIEW_SHOW ": %s\n",
172                   recent.tree_view_show == TRUE ? "TRUE" : "FALSE");
173
174   fprintf(rf, "\n# Byte view show (hide).\n");
175   fprintf(rf, "# TRUE or FALSE (case-insensitive).\n");
176   fprintf(rf, RECENT_KEY_BYTE_VIEW_SHOW ": %s\n",
177                   recent.byte_view_show == TRUE ? "TRUE" : "FALSE");
178
179   fprintf(rf, "\n# Statusbar show (hide).\n");
180   fprintf(rf, "# TRUE or FALSE (case-insensitive).\n");
181   fprintf(rf, RECENT_KEY_STATUSBAR_SHOW ": %s\n",
182                   recent.statusbar_show == TRUE ? "TRUE" : "FALSE");
183
184   fprintf(rf, "\n# Packet list colorize (hide).\n");
185   fprintf(rf, "# TRUE or FALSE (case-insensitive).\n");
186   fprintf(rf, RECENT_KEY_PACKET_LIST_COLORIZE ": %s\n",
187                   recent.packet_list_colorize == TRUE ? "TRUE" : "FALSE");
188
189   fprintf(rf, "\n# Timestamp display format.\n");
190   fprintf(rf, "# One of: RELATIVE, ABSOLUTE, ABSOLUTE_WITH_DATE, DELTA\n");
191   fprintf(rf, RECENT_GUI_TIME_FORMAT ": %s\n",
192           ts_type_text[recent.gui_time_format]);
193
194   fprintf(rf, "\n# Timestamp display precision.\n");
195   fprintf(rf, "# One of: AUTO, SEC, DSEC, CSEC, MSEC, USEC, NSEC\n");
196   fprintf(rf, RECENT_GUI_TIME_PRECISION ": %s\n",
197           ts_precision_text[recent.gui_time_precision]);
198
199   fprintf(rf, "\n# Zoom level.\n");
200   fprintf(rf, "# A decimal number.\n");
201   fprintf(rf, RECENT_GUI_ZOOM_LEVEL ": %d\n",
202                   recent.gui_zoom_level);
203
204   fprintf(rf, "\n# Main window geometry.\n");
205   fprintf(rf, "# Decimal numbers.\n");
206   fprintf(rf, RECENT_GUI_GEOMETRY_MAIN_X ": %d\n", recent.gui_geometry_main_x);
207   fprintf(rf, RECENT_GUI_GEOMETRY_MAIN_Y ": %d\n", recent.gui_geometry_main_y);
208   fprintf(rf, RECENT_GUI_GEOMETRY_MAIN_WIDTH ": %d\n",
209                   recent.gui_geometry_main_width);
210   fprintf(rf, RECENT_GUI_GEOMETRY_MAIN_HEIGHT ": %d\n",
211                   recent.gui_geometry_main_height);
212   
213   fprintf(rf, "\n# Main window maximized (GTK2 only!).\n");
214   fprintf(rf, "# TRUE or FALSE (case-insensitive).\n");
215   fprintf(rf, RECENT_GUI_GEOMETRY_MAIN_MAXIMIZED ": %s\n",
216                   recent.gui_geometry_main_maximized == TRUE ? "TRUE" : "FALSE");
217
218   fprintf(rf, "\n# Main window upper (or leftmost) pane size.\n");
219   fprintf(rf, "# (GTK1: has no effect here, command line -o usage only).\n");
220   fprintf(rf, "# Decimal number.\n");
221   if (recent.gui_geometry_main_upper_pane != 0) {
222     fprintf(rf, RECENT_GUI_GEOMETRY_MAIN_UPPER_PANE ": %d\n",
223                   recent.gui_geometry_main_upper_pane);
224   }
225   fprintf(rf, "\n# Main window middle pane size.\n");
226   fprintf(rf, "# (GTK1: has no effect here, command line -o usage only).\n");
227   fprintf(rf, "# Decimal number.\n");
228   if (recent.gui_geometry_main_lower_pane != 0) {
229     fprintf(rf, RECENT_GUI_GEOMETRY_MAIN_LOWER_PANE ": %d\n",
230                   recent.gui_geometry_main_lower_pane);
231   }
232   fprintf(rf, "\n# Statusbar left pane size.\n");
233   fprintf(rf, "# (GTK1: has no effect here, command line -o usage only).\n");
234   fprintf(rf, "# Decimal number.\n");
235   if (recent.gui_geometry_status_pane != 0) {
236     fprintf(rf, RECENT_GUI_GEOMETRY_STATUS_PANE ": %d\n",
237                   recent.gui_geometry_status_pane);
238   }
239
240   if (get_last_open_dir() != NULL) {
241     fprintf(rf, "\n# Last directory navigated to in File Open dialog.\n");
242     fprintf(rf, RECENT_GUI_FILEOPEN_REMEMBERED_DIR ": %s\n", get_last_open_dir());
243   }
244
245   window_geom_recent_write_all(rf);
246
247   fclose(rf);
248
249   /* XXX - catch I/O errors (e.g. "ran out of disk space") and return
250      an error indication, or maybe write to a new recent file and
251      rename that file on top of the old one only if there are not I/O
252      errors. */
253   return TRUE;
254 }
255
256
257 /* write the geometry values of a window to recent file */
258 void 
259 write_recent_geom(gpointer key _U_, gpointer value, gpointer rf)
260 {
261     window_geometry_t *geom = value;
262
263     fprintf(rf, "\n# Geometry and maximized state (GTK2 only) of %s window.\n", geom->key);
264     fprintf(rf, "# Decimal integers.\n");
265     fprintf(rf, RECENT_GUI_GEOMETRY "%s.x: %d\n", geom->key, geom->x);
266     fprintf(rf, RECENT_GUI_GEOMETRY "%s.y: %d\n", geom->key, geom->y);
267     fprintf(rf, RECENT_GUI_GEOMETRY "%s.width: %d\n", geom->key,
268               geom->width);
269     fprintf(rf, RECENT_GUI_GEOMETRY "%s.height: %d\n", geom->key,
270               geom->height);
271
272     fprintf(rf, "# TRUE or FALSE (case-insensitive).\n");
273     fprintf(rf, RECENT_GUI_GEOMETRY "%s.maximized: %s\n", geom->key,
274               geom->maximized == TRUE ? "TRUE" : "FALSE");
275
276 }
277
278
279 /* set one user's recent file key/value pair */
280 static int
281 read_set_recent_pair_static(gchar *key, gchar *value)
282 {
283   long num;
284   char *p;
285
286   if (strcmp(key, RECENT_KEY_MAIN_TOOLBAR_SHOW) == 0) {
287     if (strcasecmp(value, "true") == 0) {
288         recent.main_toolbar_show = TRUE;
289     }
290     else {
291         recent.main_toolbar_show = FALSE;
292     }
293   } else if (strcmp(key, RECENT_KEY_FILTER_TOOLBAR_SHOW) == 0) {
294     if (strcasecmp(value, "true") == 0) {
295         recent.filter_toolbar_show = TRUE;
296     }
297     else {
298         recent.filter_toolbar_show = FALSE;
299     }
300   } else if (strcmp(key, RECENT_KEY_PACKET_LIST_SHOW) == 0) {
301     if (strcasecmp(value, "true") == 0) {
302         recent.packet_list_show = TRUE;
303     }
304     else {
305         recent.packet_list_show = FALSE;
306     }
307   } else if (strcmp(key, RECENT_KEY_TREE_VIEW_SHOW) == 0) {
308     if (strcasecmp(value, "true") == 0) {
309         recent.tree_view_show = TRUE;
310     }
311     else {
312         recent.tree_view_show = FALSE;
313     }
314   } else if (strcmp(key, RECENT_KEY_BYTE_VIEW_SHOW) == 0) {
315     if (strcasecmp(value, "true") == 0) {
316         recent.byte_view_show = TRUE;
317     }
318     else {
319         recent.byte_view_show = FALSE;
320     }
321   } else if (strcmp(key, RECENT_KEY_STATUSBAR_SHOW) == 0) {
322     if (strcasecmp(value, "true") == 0) {
323         recent.statusbar_show = TRUE;
324     }
325     else {
326         recent.statusbar_show = FALSE;
327     }
328   } else if (strcmp(key, RECENT_KEY_PACKET_LIST_COLORIZE) == 0) {
329     if (strcasecmp(value, "true") == 0) {
330         recent.packet_list_colorize = TRUE;
331     }
332     else {
333         recent.packet_list_colorize = FALSE;
334     }
335   } else if (strcmp(key, RECENT_GUI_TIME_FORMAT) == 0) {
336     recent.gui_time_format =
337         find_index_from_string_array(value, ts_type_text, TS_RELATIVE);
338   } else if (strcmp(key, RECENT_GUI_TIME_PRECISION) == 0) {
339     recent.gui_time_precision =
340         find_index_from_string_array(value, ts_precision_text, TS_PREC_AUTO);
341   } else if (strcmp(key, RECENT_GUI_ZOOM_LEVEL) == 0) {
342     num = strtol(value, &p, 0);
343     if (p == value || *p != '\0')
344       return PREFS_SET_SYNTAX_ERR;      /* number was bad */
345     recent.gui_zoom_level = num;
346   } else if (strcmp(key, RECENT_GUI_GEOMETRY_MAIN_MAXIMIZED) == 0) {
347     if (strcasecmp(value, "true") == 0) {
348         recent.gui_geometry_main_maximized = TRUE;
349     }
350     else {
351         recent.gui_geometry_main_maximized = FALSE;
352     }
353
354   } else if (strcmp(key, RECENT_GUI_GEOMETRY_MAIN_X) == 0) {
355     num = strtol(value, &p, 0);
356     if (p == value || *p != '\0')
357       return PREFS_SET_SYNTAX_ERR;      /* number was bad */
358     recent.gui_geometry_main_x = num;
359   } else if (strcmp(key, RECENT_GUI_GEOMETRY_MAIN_Y) == 0) {
360     num = strtol(value, &p, 0);
361     if (p == value || *p != '\0')
362       return PREFS_SET_SYNTAX_ERR;      /* number was bad */
363     recent.gui_geometry_main_y = num;
364   } else if (strcmp(key, RECENT_GUI_GEOMETRY_MAIN_WIDTH) == 0) {
365     num = strtol(value, &p, 0);
366     if (p == value || *p != '\0')
367       return PREFS_SET_SYNTAX_ERR;      /* number was bad */
368     if (num <= 0)
369       return PREFS_SET_SYNTAX_ERR;      /* number must be positive */
370     recent.gui_geometry_main_width = num;
371   } else if (strcmp(key, RECENT_GUI_GEOMETRY_MAIN_HEIGHT) == 0) {
372     num = strtol(value, &p, 0);
373     if (p == value || *p != '\0')
374       return PREFS_SET_SYNTAX_ERR;      /* number was bad */
375     if (num <= 0)
376       return PREFS_SET_SYNTAX_ERR;      /* number must be positive */
377     recent.gui_geometry_main_height = num;
378   } else if (strcmp(key, RECENT_GUI_GEOMETRY_MAIN_UPPER_PANE) == 0) {
379     num = strtol(value, &p, 0);
380     if (p == value || *p != '\0')
381       return PREFS_SET_SYNTAX_ERR;      /* number was bad */
382     if (num <= 0)
383       return PREFS_SET_SYNTAX_ERR;      /* number must be positive */
384     recent.gui_geometry_main_upper_pane = num;
385     recent.has_gui_geometry_main_upper_pane = TRUE;
386   } else if (strcmp(key, RECENT_GUI_GEOMETRY_MAIN_LOWER_PANE) == 0) {
387     num = strtol(value, &p, 0);
388     if (p == value || *p != '\0')
389       return PREFS_SET_SYNTAX_ERR;      /* number was bad */
390     if (num <= 0)
391       return PREFS_SET_SYNTAX_ERR;      /* number must be positive */
392     recent.gui_geometry_main_lower_pane = num;
393     recent.has_gui_geometry_main_lower_pane = TRUE;
394   } else if (strcmp(key, RECENT_GUI_GEOMETRY_STATUS_PANE) == 0) {
395     num = strtol(value, &p, 0);
396     if (p == value || *p != '\0')
397       return PREFS_SET_SYNTAX_ERR;      /* number was bad */
398     if (num <= 0)
399       return PREFS_SET_SYNTAX_ERR;      /* number must be positive */
400     recent.gui_geometry_status_pane = num;
401     recent.has_gui_geometry_status_pane = TRUE;
402   } else if (strcmp(key, RECENT_GUI_FILEOPEN_REMEMBERED_DIR) == 0) {
403     set_last_open_dir(value);
404   } else if (strncmp(key, RECENT_GUI_GEOMETRY, sizeof(RECENT_GUI_GEOMETRY)-1) == 0) {
405     /* now have something like "gui.geom.main.x", split it into win and sub_key */
406     char *win = &key[sizeof(RECENT_GUI_GEOMETRY)-1];
407     char *sub_key = strchr(win, '.');
408     if(sub_key) {
409       *sub_key = '\0';
410       sub_key++;
411       window_geom_recent_read_pair(win, sub_key, value);
412     }
413   }
414
415   return PREFS_SET_OK;
416 }
417
418
419 /* set one user's recent file key/value pair */
420 static int
421 read_set_recent_pair_dynamic(gchar *key, gchar *value)
422 {
423   if (strcmp(key, RECENT_KEY_CAPTURE_FILE) == 0) {
424         add_menu_recent_capture_file(value);
425   } else if (strcmp(key, RECENT_KEY_DISPLAY_FILTER) == 0) {
426         dfilter_combo_add_recent(value);
427   } else if (strcmp(key, RECENT_KEY_CAPTURE_FILTER) == 0) {
428         cfilter_combo_add_recent(value);
429   }
430
431   return PREFS_SET_OK;
432 }
433
434
435 /*
436  * Given a string of the form "<recent name>:<recent value>", as might appear
437  * as an argument to a "-o" option, parse it and set the recent value in
438  * question.  Return an indication of whether it succeeded or failed
439  * in some fashion.
440  */
441 int
442 recent_set_arg(char *prefarg)
443 {
444         guchar *p, *colonp;
445         int ret;
446
447         colonp = strchr(prefarg, ':');
448         if (colonp == NULL)
449                 return PREFS_SET_SYNTAX_ERR;
450
451         p = colonp;
452         *p++ = '\0';
453
454         /*
455          * Skip over any white space (there probably won't be any, but
456          * as we allow it in the preferences file, we might as well
457          * allow it here).
458          */
459         while (isspace(*p))
460                 p++;
461         if (*p == '\0') {
462                 /*
463                  * Put the colon back, so if our caller uses, in an
464                  * error message, the string they passed us, the message
465                  * looks correct.
466                  */
467                 *colonp = ':';
468                 return PREFS_SET_SYNTAX_ERR;
469         }
470
471         ret = read_set_recent_pair_static(prefarg, p);
472         *colonp = ':';  /* put the colon back */
473         return ret;
474 }
475
476
477 /* opens the user's recent file and read the first part */
478 void
479 recent_read_static(char **rf_path_return, int *rf_errno_return)
480 {
481   char       *rf_path;
482   FILE       *rf;
483
484
485   /* set defaults */
486   recent.main_toolbar_show      = TRUE;
487   recent.filter_toolbar_show    = TRUE;
488   recent.packet_list_show       = TRUE;
489   recent.tree_view_show         = TRUE;
490   recent.byte_view_show         = TRUE;
491   recent.statusbar_show         = TRUE;
492   recent.packet_list_colorize   = TRUE;
493   recent.gui_time_format        = TS_RELATIVE;
494   recent.gui_time_precision     = TS_PREC_AUTO;
495   recent.gui_zoom_level         = 0;
496
497   recent.gui_geometry_main_x        =        20;
498   recent.gui_geometry_main_y        =        20;
499   recent.gui_geometry_main_width    = DEF_WIDTH;
500   recent.gui_geometry_main_height   = DEF_HEIGHT;
501   recent.gui_geometry_main_maximized=     FALSE;
502
503   /* pane size of zero will autodetect */
504   recent.gui_geometry_main_upper_pane   = 0;
505   recent.gui_geometry_main_lower_pane   = 0;
506   recent.gui_geometry_status_pane       = 0;
507
508   /* the following are only used if GTK2 is used (as GTK1 cannot read these geometry values) */
509   /* or if set through command line */
510 #if GTK_MAJOR_VERSION >= 2
511   recent.has_gui_geometry_main_upper_pane = TRUE;
512   recent.has_gui_geometry_main_lower_pane = TRUE;
513   recent.has_gui_geometry_status_pane = TRUE;
514 #else
515   recent.has_gui_geometry_main_upper_pane = FALSE;
516   recent.has_gui_geometry_main_lower_pane = FALSE;
517   recent.has_gui_geometry_status_pane = FALSE;
518 #endif
519
520   /* Construct the pathname of the user's recent file. */
521   rf_path = get_persconffile_path(RECENT_FILE_NAME, FALSE);
522
523   /* Read the user's recent file, if it exists. */
524   *rf_path_return = NULL;
525   if ((rf = fopen(rf_path, "r")) != NULL) {
526     /* We succeeded in opening it; read it. */
527     read_prefs_file(rf_path, rf, read_set_recent_pair_static);
528     fclose(rf);
529     g_free(rf_path);
530     rf_path = NULL;
531   } else {
532     /* We failed to open it.  If we failed for some reason other than
533        "it doesn't exist", return the errno and the pathname, so our
534        caller can report the error. */
535     if (errno != ENOENT) {
536       *rf_errno_return = errno;
537       *rf_path_return = rf_path;
538     }
539   }
540 }
541
542
543
544 /* opens the user's recent file and read it out */
545 void
546 recent_read_dynamic(char **rf_path_return, int *rf_errno_return)
547 {
548   char       *rf_path;
549   FILE       *rf;
550
551
552   /* Construct the pathname of the user's recent file. */
553   rf_path = get_persconffile_path(RECENT_FILE_NAME, FALSE);
554
555   /* Read the user's recent file, if it exists. */
556   *rf_path_return = NULL;
557   if ((rf = fopen(rf_path, "r")) != NULL) {
558     /* We succeeded in opening it; read it. */
559     read_prefs_file(rf_path, rf, read_set_recent_pair_dynamic);
560         /* set dfilter combobox to have an empty line */
561     dfilter_combo_add_empty();
562     fclose(rf);
563     g_free(rf_path);
564     rf_path = NULL;
565   } else {
566     /* We failed to open it.  If we failed for some reason other than
567        "it doesn't exist", return the errno and the pathname, so our
568        caller can report the error. */
569     if (errno != ENOENT) {
570       *rf_errno_return = errno;
571       *rf_path_return = rf_path;
572     }
573   }
574 }
575
576