And finally (I hope) the last part from the patch
[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 <epan/prefs.h>
40 #include <epan/prefs-int.h>
41 #include "ui_util.h"
42 #include "dlg_utils.h"
43 #include "cfilter_combo_utils.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_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 capture filters (latest last) ########\n"
127     "\n", rf);
128
129   cfilter_combo_recent_write_all(rf);
130
131   fputs("\n"
132     "######## Recent display filters (latest last) ########\n"
133     "\n", rf);
134
135   dfilter_recent_combo_write_all(rf);
136
137   fprintf(rf, "\n# Main Toolbar show (hide).\n");
138   fprintf(rf, "# TRUE or FALSE (case-insensitive).\n");
139   fprintf(rf, RECENT_KEY_MAIN_TOOLBAR_SHOW ": %s\n",
140                   recent.main_toolbar_show == TRUE ? "TRUE" : "FALSE");
141
142   fprintf(rf, "\n# Filter Toolbar show (hide).\n");
143   fprintf(rf, "# TRUE or FALSE (case-insensitive).\n");
144   fprintf(rf, RECENT_KEY_FILTER_TOOLBAR_SHOW ": %s\n",
145                   recent.filter_toolbar_show == TRUE ? "TRUE" : "FALSE");
146
147   fprintf(rf, "\n# Packet list show (hide).\n");
148   fprintf(rf, "# TRUE or FALSE (case-insensitive).\n");
149   fprintf(rf, RECENT_KEY_PACKET_LIST_SHOW ": %s\n",
150                   recent.packet_list_show == TRUE ? "TRUE" : "FALSE");
151
152   fprintf(rf, "\n# Tree view show (hide).\n");
153   fprintf(rf, "# TRUE or FALSE (case-insensitive).\n");
154   fprintf(rf, RECENT_KEY_TREE_VIEW_SHOW ": %s\n",
155                   recent.tree_view_show == TRUE ? "TRUE" : "FALSE");
156
157   fprintf(rf, "\n# Byte view show (hide).\n");
158   fprintf(rf, "# TRUE or FALSE (case-insensitive).\n");
159   fprintf(rf, RECENT_KEY_BYTE_VIEW_SHOW ": %s\n",
160                   recent.byte_view_show == TRUE ? "TRUE" : "FALSE");
161
162   fprintf(rf, "\n# Statusbar show (hide).\n");
163   fprintf(rf, "# TRUE or FALSE (case-insensitive).\n");
164   fprintf(rf, RECENT_KEY_STATUSBAR_SHOW ": %s\n",
165                   recent.statusbar_show == TRUE ? "TRUE" : "FALSE");
166
167   fprintf(rf, "\n# Timestamp display format.\n");
168   fprintf(rf, "# One of: RELATIVE, ABSOLUTE, ABSOLUTE_WITH_DATE, DELTA\n");
169   fprintf(rf, RECENT_GUI_TIME_FORMAT ": %s\n",
170           ts_type_text[recent.gui_time_format]);
171
172   fprintf(rf, "\n# Zoom level.\n");
173   fprintf(rf, "# A decimal number.\n");
174   fprintf(rf, RECENT_GUI_ZOOM_LEVEL ": %d\n",
175                   recent.gui_zoom_level);
176
177   fprintf(rf, "\n# Main window geometry.\n");
178   fprintf(rf, "# Decimal integers.\n");
179   fprintf(rf, RECENT_GUI_GEOMETRY_MAIN_X ": %d\n", recent.gui_geometry_main_x);
180   fprintf(rf, RECENT_GUI_GEOMETRY_MAIN_Y ": %d\n", recent.gui_geometry_main_y);
181   fprintf(rf, RECENT_GUI_GEOMETRY_MAIN_WIDTH ": %d\n",
182                   recent.gui_geometry_main_width);
183   fprintf(rf, RECENT_GUI_GEOMETRY_MAIN_HEIGHT ": %d\n",
184                   recent.gui_geometry_main_height);
185   
186   fprintf(rf, "\n# Main window maximized (GTK2 only).\n");
187   fprintf(rf, "# TRUE or FALSE (case-insensitive).\n");
188   fprintf(rf, RECENT_GUI_GEOMETRY_MAIN_MAXIMIZED ": %s\n",
189                   recent.gui_geometry_main_maximized == TRUE ? "TRUE" : "FALSE");
190
191   fprintf(rf, "\n# Main window panes (GTK2 only).\n");
192   fprintf(rf, "# Decimal numbers.\n");
193   if (recent.gui_geometry_main_upper_pane != 0) {
194     fprintf(rf, RECENT_GUI_GEOMETRY_MAIN_UPPER_PANE ": %d\n",
195                   recent.gui_geometry_main_upper_pane);
196   }
197   if (recent.gui_geometry_main_lower_pane != 0) {
198     fprintf(rf, RECENT_GUI_GEOMETRY_MAIN_LOWER_PANE ": %d\n",
199                   recent.gui_geometry_main_lower_pane);
200   }
201   if (recent.gui_geometry_status_pane != 0) {
202     fprintf(rf, RECENT_GUI_GEOMETRY_STATUS_PANE ": %d\n",
203                   recent.gui_geometry_status_pane);
204   }
205
206   if (get_last_open_dir() != NULL) {
207     fprintf(rf, "\n# Last directory navigated to in File Open dialog.\n");
208     fprintf(rf, RECENT_GUI_FILEOPEN_REMEMBERED_DIR ": %s\n", get_last_open_dir());
209   }
210
211   window_geom_recent_write_all(rf);
212
213   fclose(rf);
214
215   /* XXX - catch I/O errors (e.g. "ran out of disk space") and return
216      an error indication, or maybe write to a new preferences file and
217      rename that file on top of the old one only if there are not I/O
218      errors. */
219   return 0;
220 }
221
222
223 /* write the geometry values of a window to recent file */
224 void 
225 write_recent_geom(gpointer key _U_, gpointer value, gpointer rf)
226 {
227     window_geometry_t *geom = value;
228
229     fprintf(rf, "\n# Geometry and maximized state (GTK2 only) of %s window.\n", geom->key);
230     fprintf(rf, "# Decimal integers.\n");
231     fprintf(rf, RECENT_GUI_GEOMETRY "%s.x: %d\n", geom->key, geom->x);
232     fprintf(rf, RECENT_GUI_GEOMETRY "%s.y: %d\n", geom->key, geom->y);
233     fprintf(rf, RECENT_GUI_GEOMETRY "%s.width: %d\n", geom->key,
234               geom->width);
235     fprintf(rf, RECENT_GUI_GEOMETRY "%s.height: %d\n", geom->key,
236               geom->height);
237
238     fprintf(rf, "# TRUE or FALSE (case-insensitive).\n");
239     fprintf(rf, RECENT_GUI_GEOMETRY "%s.maximized: %s\n", geom->key,
240               geom->maximized == TRUE ? "TRUE" : "FALSE");
241
242 }
243
244
245 /* set one user's recent file key/value pair */
246 static int
247 read_set_recent_pair(gchar *key, gchar *value)
248 {
249   long num;
250   char *p;
251
252   if (strcmp(key, RECENT_KEY_CAPTURE_FILE) == 0) {
253         add_menu_recent_capture_file(value);
254   } else if (strcmp(key, RECENT_KEY_DISPLAY_FILTER) == 0) {
255         dfilter_combo_add_recent(value);
256   } else if (strcmp(key, RECENT_KEY_CAPTURE_FILTER) == 0) {
257         cfilter_combo_add_recent(value);
258   } else if (strcmp(key, RECENT_KEY_MAIN_TOOLBAR_SHOW) == 0) {
259     if (strcasecmp(value, "true") == 0) {
260         recent.main_toolbar_show = TRUE;
261     }
262     else {
263         recent.main_toolbar_show = FALSE;
264     }
265   } else if (strcmp(key, RECENT_KEY_FILTER_TOOLBAR_SHOW) == 0) {
266     if (strcasecmp(value, "true") == 0) {
267         recent.filter_toolbar_show = TRUE;
268     }
269     else {
270         recent.filter_toolbar_show = FALSE;
271     }
272   } else if (strcmp(key, RECENT_KEY_PACKET_LIST_SHOW) == 0) {
273     if (strcasecmp(value, "true") == 0) {
274         recent.packet_list_show = TRUE;
275     }
276     else {
277         recent.packet_list_show = FALSE;
278     }
279   } else if (strcmp(key, RECENT_KEY_TREE_VIEW_SHOW) == 0) {
280     if (strcasecmp(value, "true") == 0) {
281         recent.tree_view_show = TRUE;
282     }
283     else {
284         recent.tree_view_show = FALSE;
285     }
286   } else if (strcmp(key, RECENT_KEY_BYTE_VIEW_SHOW) == 0) {
287     if (strcasecmp(value, "true") == 0) {
288         recent.byte_view_show = TRUE;
289     }
290     else {
291         recent.byte_view_show = FALSE;
292     }
293   } else if (strcmp(key, RECENT_KEY_STATUSBAR_SHOW) == 0) {
294     if (strcasecmp(value, "true") == 0) {
295         recent.statusbar_show = TRUE;
296     }
297     else {
298         recent.statusbar_show = FALSE;
299     }
300   } else if (strcmp(key, RECENT_GUI_TIME_FORMAT) == 0) {
301     recent.gui_time_format =
302         find_index_from_string_array(value, ts_type_text, TS_RELATIVE);
303   } else if (strcmp(key, RECENT_GUI_ZOOM_LEVEL) == 0) {
304     num = strtol(value, &p, 0);
305     if (p == value || *p != '\0')
306       return PREFS_SET_SYNTAX_ERR;      /* number was bad */
307     recent.gui_zoom_level = num;
308   } else if (strcmp(key, RECENT_GUI_GEOMETRY_MAIN_MAXIMIZED) == 0) {
309     if (strcasecmp(value, "true") == 0) {
310         recent.gui_geometry_main_maximized = TRUE;
311     }
312     else {
313         recent.gui_geometry_main_maximized = FALSE;
314     }
315
316   } else if (strcmp(key, RECENT_GUI_GEOMETRY_MAIN_X) == 0) {
317     num = strtol(value, &p, 0);
318     if (p == value || *p != '\0')
319       return PREFS_SET_SYNTAX_ERR;      /* number was bad */
320     recent.gui_geometry_main_x = num;
321   } else if (strcmp(key, RECENT_GUI_GEOMETRY_MAIN_Y) == 0) {
322     num = strtol(value, &p, 0);
323     if (p == value || *p != '\0')
324       return PREFS_SET_SYNTAX_ERR;      /* number was bad */
325     recent.gui_geometry_main_y = num;
326   } else if (strcmp(key, RECENT_GUI_GEOMETRY_MAIN_WIDTH) == 0) {
327     num = strtol(value, &p, 0);
328     if (p == value || *p != '\0')
329       return PREFS_SET_SYNTAX_ERR;      /* number was bad */
330     if (num <= 0)
331       return PREFS_SET_SYNTAX_ERR;      /* number must be positive */
332     recent.gui_geometry_main_width = num;
333   } else if (strcmp(key, RECENT_GUI_GEOMETRY_MAIN_HEIGHT) == 0) {
334     num = strtol(value, &p, 0);
335     if (p == value || *p != '\0')
336       return PREFS_SET_SYNTAX_ERR;      /* number was bad */
337     if (num <= 0)
338       return PREFS_SET_SYNTAX_ERR;      /* number must be positive */
339     recent.gui_geometry_main_height = num;
340   } else if (strcmp(key, RECENT_GUI_GEOMETRY_MAIN_UPPER_PANE) == 0) {
341     num = strtol(value, &p, 0);
342     if (p == value || *p != '\0')
343       return PREFS_SET_SYNTAX_ERR;      /* number was bad */
344     if (num <= 0)
345       return PREFS_SET_SYNTAX_ERR;      /* number must be positive */
346     recent.gui_geometry_main_upper_pane = num;
347   } else if (strcmp(key, RECENT_GUI_GEOMETRY_MAIN_LOWER_PANE) == 0) {
348     num = strtol(value, &p, 0);
349     if (p == value || *p != '\0')
350       return PREFS_SET_SYNTAX_ERR;      /* number was bad */
351     if (num <= 0)
352       return PREFS_SET_SYNTAX_ERR;      /* number must be positive */
353     recent.gui_geometry_main_lower_pane = num;
354   } else if (strcmp(key, RECENT_GUI_GEOMETRY_STATUS_PANE) == 0) {
355     num = strtol(value, &p, 0);
356     if (p == value || *p != '\0')
357       return PREFS_SET_SYNTAX_ERR;      /* number was bad */
358     if (num <= 0)
359       return PREFS_SET_SYNTAX_ERR;      /* number must be positive */
360     recent.gui_geometry_status_pane = num;
361   } else if (strcmp(key, RECENT_GUI_FILEOPEN_REMEMBERED_DIR) == 0) {
362     set_last_open_dir(value);
363   } else if (strncmp(key, RECENT_GUI_GEOMETRY, sizeof(RECENT_GUI_GEOMETRY)-1) == 0) {
364     /* now have something like "gui.geom.main.x", split it into win and sub_key */
365     char *win = &key[sizeof(RECENT_GUI_GEOMETRY)-1];
366     char *sub_key = strchr(win, '.');
367     if(sub_key) {
368       *sub_key = '\0';
369       sub_key++;
370       window_geom_recent_read_pair(win, sub_key, value);
371     }
372   }
373
374   return PREFS_SET_OK;
375 }
376
377
378 /* opens the user's recent file and read it out */
379 void
380 read_recent(char **rf_path_return, int *rf_errno_return)
381 {
382   char       *rf_path;
383   FILE       *rf;
384
385
386   /* set defaults */
387   recent.main_toolbar_show      = TRUE;
388   recent.filter_toolbar_show    = TRUE;
389   recent.packet_list_show       = TRUE;
390   recent.tree_view_show         = TRUE;
391   recent.byte_view_show         = TRUE;
392   recent.statusbar_show         = TRUE;
393   recent.gui_time_format        = TS_RELATIVE;
394   recent.gui_zoom_level         = 0;
395
396   recent.gui_geometry_main_x        =        20;
397   recent.gui_geometry_main_y        =        20;
398   recent.gui_geometry_main_width    = DEF_WIDTH;
399   recent.gui_geometry_main_height   = DEF_HEIGHT;
400   recent.gui_geometry_main_maximized=     FALSE;
401
402   /* pane size of zero will autodetect */
403   recent.gui_geometry_main_upper_pane   = 0;
404   recent.gui_geometry_main_lower_pane   = 0;
405   recent.gui_geometry_status_pane       = 0;
406
407   /* Construct the pathname of the user's recent file. */
408   rf_path = get_persconffile_path(RECENT_FILE_NAME, FALSE);
409
410   /* Read the user's recent file, if it exists. */
411   *rf_path_return = NULL;
412   if ((rf = fopen(rf_path, "r")) != NULL) {
413     /* We succeeded in opening it; read it. */
414     read_prefs_file(rf_path, rf, read_set_recent_pair);
415         /* set dfilter combobox to have an empty line */
416     dfilter_combo_add_empty();
417     fclose(rf);
418     g_free(rf_path);
419     rf_path = NULL;
420   } else {
421     /* We failed to open it.  If we failed for some reason other than
422        "it doesn't exist", return the errno and the pathname, so our
423        caller can report the error. */
424     if (errno != ENOENT) {
425       *rf_errno_return = errno;
426       *rf_path_return = rf_path;
427     }
428   }
429 }
430
431