remove MSVC compiler warning (required a type cast)
[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
34 #include "recent.h"
35 #include <epan/epan.h>
36 #include <epan/filesystem.h>
37 #include "menu.h"
38 #include "main.h"
39 #include "prefs.h"
40 #include "prefs-int.h"
41 #include "ui_util.h"
42 #include "dlg_utils.h"
43
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_PACKET_LIST_SHOW         "gui.packet_list_show"
48 #define RECENT_KEY_TREE_VIEW_SHOW           "gui.tree_view_show"
49 #define RECENT_KEY_BYTE_VIEW_SHOW           "gui.byte_view_show"
50 #define RECENT_KEY_STATUSBAR_SHOW           "gui.statusbar_show"
51 #define RECENT_GUI_TIME_FORMAT              "gui.time_format"
52 #define RECENT_GUI_ZOOM_LEVEL               "gui.zoom_level"
53 #define RECENT_GUI_GEOMETRY_MAIN_X          "gui.geometry_main_x"
54 #define RECENT_GUI_GEOMETRY_MAIN_Y          "gui.geometry_main_y"
55 #define RECENT_GUI_GEOMETRY_MAIN_WIDTH      "gui.geometry_main_width"
56 #define RECENT_GUI_GEOMETRY_MAIN_HEIGHT     "gui.geometry_main_height"
57 #define RECENT_GUI_GEOMETRY_MAIN_MAXIMIZED  "gui.geometry_main_maximized"
58 #define RECENT_GUI_GEOMETRY_MAIN_UPPER_PANE "gui.geometry_main_upper_pane"
59 #define RECENT_GUI_GEOMETRY_MAIN_LOWER_PANE "gui.geometry_main_lower_pane"
60 #define RECENT_GUI_GEOMETRY_STATUS_PANE     "gui.geometry_status_pane"
61 #define RECENT_GUI_FILEOPEN_REMEMBERED_DIR  "gui.fileopen_remembered_dir"
62 #define RECENT_GUI_GEOMETRY "gui.geom."
63
64 #define RECENT_FILE_NAME "recent"
65
66
67 /* #include "../menu.h" */
68 extern void add_menu_recent_capture_file(gchar *file);
69
70 recent_settings_t recent;
71
72 static char *ts_type_text[] =
73         { "RELATIVE", "ABSOLUTE", "ABSOLUTE_WITH_DATE", "DELTA", NULL };
74
75 /* Takes an string and a pointer to an array of strings, and a default int value.
76  * The array must be terminated by a NULL string. If the string is found in the array
77  * of strings, the index of that string in the array is returned. Otherwise, the
78  * default value that was passed as the third argument is returned.
79  */
80 static int
81 find_index_from_string_array(char *needle, char **haystack, int default_value)
82 {
83         int i = 0;
84
85         while (haystack[i] != NULL) {
86                 if (strcmp(needle, haystack[i]) == 0) {
87                         return i;
88                 }
89                 i++;
90         }
91         return default_value;
92 }
93
94 /* Write out "recent" to the user's recent file, and return 0.
95    If we got an error, stuff a pointer to the path of the recent file
96    into "*pf_path_return", and return the errno. */
97 int
98 write_recent(char **rf_path_return)
99 {
100   char        *rf_path;
101   FILE        *rf;
102
103   /* To do:
104    * - Split output lines longer than MAX_VAL_LEN
105    * - Create a function for the preference directory check/creation
106    *   so that duplication can be avoided with filter.c
107    */
108
109   rf_path = get_persconffile_path(RECENT_FILE_NAME, TRUE);
110   if ((rf = fopen(rf_path, "w")) == NULL) {
111     *rf_path_return = rf_path;
112     return errno;
113   }
114
115   fputs("# Recent settings file for Ethereal " VERSION ".\n"
116     "#\n"
117     "# This file is regenerated each time Ethereal is quit.\n"
118     "# So be careful, if you want to make manual changes here.\n"
119     "\n"
120     "######## Recent capture files (latest last) ########\n"
121     "\n", rf);
122
123   menu_recent_file_write_all(rf);
124
125   fputs("\n"
126     "######## Recent display filters (latest last) ########\n"
127     "\n", rf);
128
129   dfilter_recent_combo_write_all(rf);
130
131   fprintf(rf, "\n# Main Toolbar show (hide).\n");
132   fprintf(rf, "# TRUE or FALSE (case-insensitive).\n");
133   fprintf(rf, RECENT_KEY_MAIN_TOOLBAR_SHOW ": %s\n",
134                   recent.main_toolbar_show == TRUE ? "TRUE" : "FALSE");
135
136   fprintf(rf, "\n# Filter Toolbar show (hide).\n");
137   fprintf(rf, "# TRUE or FALSE (case-insensitive).\n");
138   fprintf(rf, RECENT_KEY_FILTER_TOOLBAR_SHOW ": %s\n",
139                   recent.filter_toolbar_show == TRUE ? "TRUE" : "FALSE");
140
141   fprintf(rf, "\n# Packet list show (hide).\n");
142   fprintf(rf, "# TRUE or FALSE (case-insensitive).\n");
143   fprintf(rf, RECENT_KEY_PACKET_LIST_SHOW ": %s\n",
144                   recent.packet_list_show == TRUE ? "TRUE" : "FALSE");
145
146   fprintf(rf, "\n# Tree view show (hide).\n");
147   fprintf(rf, "# TRUE or FALSE (case-insensitive).\n");
148   fprintf(rf, RECENT_KEY_TREE_VIEW_SHOW ": %s\n",
149                   recent.tree_view_show == TRUE ? "TRUE" : "FALSE");
150
151   fprintf(rf, "\n# Byte view show (hide).\n");
152   fprintf(rf, "# TRUE or FALSE (case-insensitive).\n");
153   fprintf(rf, RECENT_KEY_BYTE_VIEW_SHOW ": %s\n",
154                   recent.byte_view_show == TRUE ? "TRUE" : "FALSE");
155
156   fprintf(rf, "\n# Statusbar show (hide).\n");
157   fprintf(rf, "# TRUE or FALSE (case-insensitive).\n");
158   fprintf(rf, RECENT_KEY_STATUSBAR_SHOW ": %s\n",
159                   recent.statusbar_show == TRUE ? "TRUE" : "FALSE");
160
161   fprintf(rf, "\n# Timestamp display format.\n");
162   fprintf(rf, "# One of: RELATIVE, ABSOLUTE, ABSOLUTE_WITH_DATE, DELTA\n");
163   fprintf(rf, RECENT_GUI_TIME_FORMAT ": %s\n",
164           ts_type_text[recent.gui_time_format]);
165
166   fprintf(rf, "\n# Zoom level.\n");
167   fprintf(rf, "# A decimal number.\n");
168   fprintf(rf, RECENT_GUI_ZOOM_LEVEL ": %d\n",
169                   recent.gui_zoom_level);
170
171   fprintf(rf, "\n# Main window geometry.\n");
172   fprintf(rf, "# Decimal integers.\n");
173   fprintf(rf, RECENT_GUI_GEOMETRY_MAIN_X ": %d\n", recent.gui_geometry_main_x);
174   fprintf(rf, RECENT_GUI_GEOMETRY_MAIN_Y ": %d\n", recent.gui_geometry_main_y);
175   fprintf(rf, RECENT_GUI_GEOMETRY_MAIN_WIDTH ": %d\n",
176                   recent.gui_geometry_main_width);
177   fprintf(rf, RECENT_GUI_GEOMETRY_MAIN_HEIGHT ": %d\n",
178                   recent.gui_geometry_main_height);
179   
180   fprintf(rf, "\n# Main window maximized (GTK2 only).\n");
181   fprintf(rf, "# TRUE or FALSE (case-insensitive).\n");
182   fprintf(rf, RECENT_GUI_GEOMETRY_MAIN_MAXIMIZED ": %s\n",
183                   recent.gui_geometry_main_maximized == TRUE ? "TRUE" : "FALSE");
184
185   fprintf(rf, "\n# Main window panes (GTK2 only).\n");
186   fprintf(rf, "# Decimal numbers.\n");
187   if (recent.gui_geometry_main_upper_pane != 0) {
188     fprintf(rf, RECENT_GUI_GEOMETRY_MAIN_UPPER_PANE ": %d\n",
189                   recent.gui_geometry_main_upper_pane);
190   }
191   if (recent.gui_geometry_main_lower_pane != 0) {
192     fprintf(rf, RECENT_GUI_GEOMETRY_MAIN_LOWER_PANE ": %d\n",
193                   recent.gui_geometry_main_lower_pane);
194   }
195   if (recent.gui_geometry_status_pane != 0) {
196     fprintf(rf, RECENT_GUI_GEOMETRY_STATUS_PANE ": %d\n",
197                   recent.gui_geometry_status_pane);
198   }
199
200   if (get_last_open_dir() != NULL) {
201     fprintf(rf, "\n# Last directory navigated to in File Open dialog.\n");
202     fprintf(rf, RECENT_GUI_FILEOPEN_REMEMBERED_DIR ": %s\n", get_last_open_dir());
203   }
204
205   window_geom_recent_write_all(rf);
206
207   fclose(rf);
208
209   /* XXX - catch I/O errors (e.g. "ran out of disk space") and return
210      an error indication, or maybe write to a new preferences file and
211      rename that file on top of the old one only if there are not I/O
212      errors. */
213   return 0;
214 }
215
216
217 /* write the geometry values of a window to recent file */
218 void 
219 write_recent_geom(gpointer key _U_, gpointer value, gpointer rf)
220 {
221     window_geometry_t *geom = value;
222
223     fprintf(rf, "\n# Geometry and maximized state (GTK2 only) of %s window.\n", geom->key);
224     fprintf(rf, "# Decimal integers.\n");
225     fprintf(rf, RECENT_GUI_GEOMETRY "%s.x: %d\n", geom->key, geom->x);
226     fprintf(rf, RECENT_GUI_GEOMETRY "%s.y: %d\n", geom->key, geom->y);
227     fprintf(rf, RECENT_GUI_GEOMETRY "%s.width: %d\n", geom->key,
228               geom->width);
229     fprintf(rf, RECENT_GUI_GEOMETRY "%s.height: %d\n", geom->key,
230               geom->height);
231
232     fprintf(rf, "# TRUE or FALSE (case-insensitive).\n");
233     fprintf(rf, RECENT_GUI_GEOMETRY "%s.maximized: %s\n", geom->key,
234               geom->maximized == TRUE ? "TRUE" : "FALSE");
235
236 }
237
238
239 /* set one user's recent file key/value pair */
240 static int
241 read_set_recent_pair(gchar *key, gchar *value)
242 {
243   long num;
244   char *p;
245
246   if (strcmp(key, RECENT_KEY_CAPTURE_FILE) == 0) {
247         add_menu_recent_capture_file(value);
248   } else if (strcmp(key, RECENT_KEY_DISPLAY_FILTER) == 0) {
249         dfilter_combo_add_recent(value);
250   } else if (strcmp(key, RECENT_KEY_MAIN_TOOLBAR_SHOW) == 0) {
251     if (strcasecmp(value, "true") == 0) {
252         recent.main_toolbar_show = TRUE;
253     }
254     else {
255         recent.main_toolbar_show = FALSE;
256     }
257   } else if (strcmp(key, RECENT_KEY_FILTER_TOOLBAR_SHOW) == 0) {
258     if (strcasecmp(value, "true") == 0) {
259         recent.filter_toolbar_show = TRUE;
260     }
261     else {
262         recent.filter_toolbar_show = FALSE;
263     }
264   } else if (strcmp(key, RECENT_KEY_PACKET_LIST_SHOW) == 0) {
265     if (strcasecmp(value, "true") == 0) {
266         recent.packet_list_show = TRUE;
267     }
268     else {
269         recent.packet_list_show = FALSE;
270     }
271   } else if (strcmp(key, RECENT_KEY_TREE_VIEW_SHOW) == 0) {
272     if (strcasecmp(value, "true") == 0) {
273         recent.tree_view_show = TRUE;
274     }
275     else {
276         recent.tree_view_show = FALSE;
277     }
278   } else if (strcmp(key, RECENT_KEY_BYTE_VIEW_SHOW) == 0) {
279     if (strcasecmp(value, "true") == 0) {
280         recent.byte_view_show = TRUE;
281     }
282     else {
283         recent.byte_view_show = FALSE;
284     }
285   } else if (strcmp(key, RECENT_KEY_STATUSBAR_SHOW) == 0) {
286     if (strcasecmp(value, "true") == 0) {
287         recent.statusbar_show = TRUE;
288     }
289     else {
290         recent.statusbar_show = FALSE;
291     }
292   } else if (strcmp(key, RECENT_GUI_TIME_FORMAT) == 0) {
293     recent.gui_time_format =
294         find_index_from_string_array(value, ts_type_text, TS_RELATIVE);
295   } else if (strcmp(key, RECENT_GUI_ZOOM_LEVEL) == 0) {
296     num = strtol(value, &p, 0);
297     if (p == value || *p != '\0')
298       return PREFS_SET_SYNTAX_ERR;      /* number was bad */
299     recent.gui_zoom_level = num;
300   } else if (strcmp(key, RECENT_GUI_GEOMETRY_MAIN_MAXIMIZED) == 0) {
301     if (strcasecmp(value, "true") == 0) {
302         recent.gui_geometry_main_maximized = TRUE;
303     }
304     else {
305         recent.gui_geometry_main_maximized = FALSE;
306     }
307
308   } else if (strcmp(key, RECENT_GUI_GEOMETRY_MAIN_X) == 0) {
309     num = strtol(value, &p, 0);
310     if (p == value || *p != '\0')
311       return PREFS_SET_SYNTAX_ERR;      /* number was bad */
312     recent.gui_geometry_main_x = num;
313   } else if (strcmp(key, RECENT_GUI_GEOMETRY_MAIN_Y) == 0) {
314     num = strtol(value, &p, 0);
315     if (p == value || *p != '\0')
316       return PREFS_SET_SYNTAX_ERR;      /* number was bad */
317     recent.gui_geometry_main_y = num;
318   } else if (strcmp(key, RECENT_GUI_GEOMETRY_MAIN_WIDTH) == 0) {
319     num = strtol(value, &p, 0);
320     if (p == value || *p != '\0')
321       return PREFS_SET_SYNTAX_ERR;      /* number was bad */
322     if (num <= 0)
323       return PREFS_SET_SYNTAX_ERR;      /* number must be positive */
324     recent.gui_geometry_main_width = num;
325   } else if (strcmp(key, RECENT_GUI_GEOMETRY_MAIN_HEIGHT) == 0) {
326     num = strtol(value, &p, 0);
327     if (p == value || *p != '\0')
328       return PREFS_SET_SYNTAX_ERR;      /* number was bad */
329     if (num <= 0)
330       return PREFS_SET_SYNTAX_ERR;      /* number must be positive */
331     recent.gui_geometry_main_height = num;
332   } else if (strcmp(key, RECENT_GUI_GEOMETRY_MAIN_UPPER_PANE) == 0) {
333     num = strtol(value, &p, 0);
334     if (p == value || *p != '\0')
335       return PREFS_SET_SYNTAX_ERR;      /* number was bad */
336     if (num <= 0)
337       return PREFS_SET_SYNTAX_ERR;      /* number must be positive */
338     recent.gui_geometry_main_upper_pane = num;
339   } else if (strcmp(key, RECENT_GUI_GEOMETRY_MAIN_LOWER_PANE) == 0) {
340     num = strtol(value, &p, 0);
341     if (p == value || *p != '\0')
342       return PREFS_SET_SYNTAX_ERR;      /* number was bad */
343     if (num <= 0)
344       return PREFS_SET_SYNTAX_ERR;      /* number must be positive */
345     recent.gui_geometry_main_lower_pane = num;
346   } else if (strcmp(key, RECENT_GUI_GEOMETRY_STATUS_PANE) == 0) {
347     num = strtol(value, &p, 0);
348     if (p == value || *p != '\0')
349       return PREFS_SET_SYNTAX_ERR;      /* number was bad */
350     if (num <= 0)
351       return PREFS_SET_SYNTAX_ERR;      /* number must be positive */
352     recent.gui_geometry_status_pane = num;
353   } else if (strcmp(key, RECENT_GUI_FILEOPEN_REMEMBERED_DIR) == 0) {
354     set_last_open_dir(value);
355   } else if (strncmp(key, RECENT_GUI_GEOMETRY, sizeof(RECENT_GUI_GEOMETRY)-1) == 0) {
356     /* now have something like "gui.geom.main.x", split it into win and sub_key */
357     char *win = &key[sizeof(RECENT_GUI_GEOMETRY)-1];
358     char *sub_key = strchr(win, '.');
359     if(sub_key) {
360       *sub_key = '\0';
361       sub_key++;
362       window_geom_recent_read_pair(win, sub_key, value);
363     }
364   }
365
366   return PREFS_SET_OK;
367 }
368
369
370 /* opens the user's recent file and read it out */
371 void
372 read_recent(char **rf_path_return, int *rf_errno_return)
373 {
374   char       *rf_path;
375   FILE       *rf;
376
377
378   /* set defaults */
379   recent.main_toolbar_show      = TRUE;
380   recent.filter_toolbar_show    = TRUE;
381   recent.packet_list_show       = TRUE;
382   recent.tree_view_show         = TRUE;
383   recent.byte_view_show         = TRUE;
384   recent.statusbar_show         = TRUE;
385   recent.gui_time_format        = TS_RELATIVE;
386   recent.gui_zoom_level         = 0;
387
388   recent.gui_geometry_main_x        =        20;
389   recent.gui_geometry_main_y        =        20;
390   recent.gui_geometry_main_width    = DEF_WIDTH;
391   recent.gui_geometry_main_height   = DEF_HEIGHT;
392   recent.gui_geometry_main_maximized=     FALSE;
393
394   /* pane size of zero will autodetect */
395   recent.gui_geometry_main_upper_pane   = 0;
396   recent.gui_geometry_main_lower_pane   = 0;
397   recent.gui_geometry_status_pane       = 0;
398
399   /* Construct the pathname of the user's recent file. */
400   rf_path = get_persconffile_path(RECENT_FILE_NAME, FALSE);
401
402   /* Read the user's recent file, if it exists. */
403   *rf_path_return = NULL;
404   if ((rf = fopen(rf_path, "r")) != NULL) {
405     /* We succeeded in opening it; read it. */
406     read_prefs_file(rf_path, rf, read_set_recent_pair);
407         /* set dfilter combobox to have an empty line */
408     dfilter_combo_add_empty();
409     fclose(rf);
410     g_free(rf_path);
411     rf_path = NULL;
412   } else {
413     /* We failed to open it.  If we failed for some reason other than
414        "it doesn't exist", return the errno and the pathname, so our
415        caller can report the error. */
416     if (errno != ENOENT) {
417       *rf_errno_return = errno;
418       *rf_path_return = rf_path;
419     }
420   }
421 }
422
423