Make the routines internal to the filter-editing dialog box static.
[obnox/wireshark/wip.git] / gtk / filter_prefs.c
1 /* filter_prefs.c
2  * Dialog boxes for filter editing
3  * (This used to be a notebook page under "Preferences", hence the
4  * "prefs" in the file name.)
5  *
6  * $Id: filter_prefs.c,v 1.9 2000/02/12 06:46:52 guy Exp $
7  *
8  * Ethereal - Network traffic analyzer
9  * By Gerald Combs <gerald@zing.org>
10  * Copyright 1998 Gerald Combs
11  *
12  * 
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  * 
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  * 
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
26  */
27
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #include <gtk/gtk.h>
33
34 #include <stdlib.h>
35 #include <string.h>
36 #include <sys/stat.h>
37 #ifdef HAVE_UNISTD_H
38 #include <unistd.h>
39 #endif
40 #include <ctype.h>
41 #ifdef HAVE_DIRECT_H
42 #include <direct.h>
43 #endif
44
45 #include "gtk/main.h"
46 #include "filter_prefs.h"
47 #include "packet.h"
48 #include "file.h"
49 #include "util.h"
50 #include "prefs_dlg.h"
51
52 #define E_FILT_NAME_KEY "filter_name"
53 #define E_FILT_LBL_KEY  "filter_label"
54 #define E_FILT_CM_KEY   "in_cancel_mode"
55 #define E_FILTER_WIDGET_KEY "filter_widget"
56
57 typedef struct _filter_def {
58   char *name;
59   char *strval;
60 } filter_def;
61
62 typedef struct _filter_cb_data {
63   GList     *fl;
64   GtkWidget *win;
65 } filter_cb_data;
66
67
68 static GtkWidget   *filter_l, *chg_bt, *copy_bt, *del_bt, *name_te, *filter_te, *apply_bt;
69 static GList       *fl = NULL;
70
71 static void get_filter_list(void);
72 static void filter_dlg_ok(GtkWidget *ok_bt, gpointer parent_w);
73 static void filter_dlg_save(GtkWidget *save_bt, gpointer parent_w);
74 static void filter_dlg_cancel(GtkWidget *cancel_bt, gpointer parent_w);
75 static void filter_sel_apply_cb(GtkWidget *cancel_bt, gpointer parent_w);
76
77 static GtkWidget *filter_prefs_show(GtkWidget *);
78 static void       filter_sel_list_cb(GtkWidget *, gpointer);
79 static void       filter_sel_new_cb(GtkWidget *, gpointer);
80 static void       filter_sel_chg_cb(GtkWidget *, gpointer);
81 static void       filter_sel_copy_cb(GtkWidget *, gpointer);
82 static void       filter_sel_del_cb(GtkWidget *, gpointer);
83 static void       filter_prefs_ok(GtkWidget *);
84 static void       filter_prefs_save(GtkWidget *);
85 static void       filter_prefs_cancel(GtkWidget *);
86 static void       filter_prefs_delete(GtkWidget *);
87
88 static void
89 get_filter_list(void)
90 {
91   filter_def *filt;
92   FILE       *ff;
93   gchar      *ff_path, *ff_name = PF_DIR "/filters", f_buf[256];
94   gchar      *name_begin, *name_end, *filt_begin;
95   int         len, line = 0;
96
97   if (fl) return;
98   
99   /* To do: generalize this */
100   ff_path = (gchar *) g_malloc(strlen(get_home_dir()) + strlen(ff_name) +  4);
101   sprintf(ff_path, "%s/%s", get_home_dir(), ff_name);
102
103   if ((ff = fopen(ff_path, "r")) == NULL) {
104     g_free(ff_path);
105     return;
106   }
107
108   while (fgets(f_buf, 256, ff)) {
109     line++;
110     len = strlen(f_buf);
111     if (f_buf[len - 1] == '\n') {
112       len--;
113       f_buf[len] = '\0';
114     }
115     name_begin = strchr(f_buf, '"');
116     /* Empty line */
117     if (name_begin == NULL)
118       continue;
119     name_end = strchr(name_begin + 1, '"');
120     /* No terminating quote */
121     if (name_end == NULL) {
122       g_warning("Malformed filter in '%s' line %d.", ff_path, line);
123       continue;
124     }
125     name_begin++;
126     name_end[0] = '\0';
127     filt_begin  = name_end + 1;
128     while(isspace(filt_begin[0])) filt_begin++;
129     /* No filter string */
130     if (filt_begin[0] == '\0') {
131       g_warning("Malformed filter in '%s' line %d.", ff_path, line);
132       continue;
133     }
134     filt         = (filter_def *) g_malloc(sizeof(filter_def));
135     filt->name   = g_strdup(name_begin);
136     filt->strval = g_strdup(filt_begin);
137     fl = g_list_append(fl, filt);
138   }
139   fclose(ff);
140   g_free(ff_path);
141 }
142
143 /* the window that pops up for filter editing/applying */
144 void
145 filter_dialog_cb(GtkWidget *w)
146 {
147         GtkWidget       *main_w,        /* main window */
148                         *main_vb,       /* main container */
149                         *bbox,          /* button container */
150                         *ok_bt,         /* ok button */
151                         *save_bt,       /* save button */
152                         *cancel_bt;     /* cancel button */ 
153         GtkWidget *filter_te = NULL;    /* filter text entry */
154         GtkWidget *filter_pg = NULL;    /* filter settings box */
155
156         /* get the text entry widget from the caller */
157         if(w != NULL) {
158                 filter_te = gtk_object_get_data(GTK_OBJECT(w), E_FILT_TE_PTR_KEY);
159         }
160
161         main_w = gtk_window_new(GTK_WINDOW_TOPLEVEL);
162         gtk_window_set_title(GTK_WINDOW(main_w), "Ethereal: Filters");
163
164         main_vb = gtk_vbox_new(FALSE, 5);
165         gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
166         gtk_container_add(GTK_CONTAINER(main_w), main_vb);
167         gtk_widget_show(main_vb);
168
169         filter_pg = filter_prefs_show(filter_te);
170         gtk_box_pack_start(GTK_BOX(main_vb), filter_pg, TRUE, TRUE, 0);
171         gtk_object_set_data(GTK_OBJECT(filter_pg), E_FILT_TE_PTR_KEY, filter_te);
172         gtk_object_set_data(GTK_OBJECT(main_w), E_FILTER_WIDGET_KEY, filter_pg);
173         gtk_widget_show(filter_te);
174
175         bbox = gtk_hbutton_box_new();
176         gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_END);
177         gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 5);
178         gtk_container_add(GTK_CONTAINER(main_vb), bbox);
179         gtk_widget_show(bbox);
180
181         ok_bt = gtk_button_new_with_label ("OK");
182         gtk_signal_connect(GTK_OBJECT(ok_bt), "clicked",
183                 GTK_SIGNAL_FUNC(filter_dlg_ok), GTK_OBJECT(main_w));
184         GTK_WIDGET_SET_FLAGS(ok_bt, GTK_CAN_DEFAULT);
185         gtk_box_pack_start(GTK_BOX(bbox), ok_bt, TRUE, TRUE, 0);
186         gtk_widget_grab_default(ok_bt);
187         gtk_widget_show(ok_bt);
188
189         save_bt = gtk_button_new_with_label ("Save");
190         gtk_signal_connect(GTK_OBJECT(save_bt), "clicked",
191                 GTK_SIGNAL_FUNC(filter_dlg_save), GTK_OBJECT(main_w));
192         GTK_WIDGET_SET_FLAGS(save_bt, GTK_CAN_DEFAULT);
193         gtk_box_pack_start(GTK_BOX(bbox), save_bt, TRUE, TRUE, 0);
194         gtk_widget_show(save_bt);
195
196         cancel_bt = gtk_button_new_with_label ("Cancel");
197         gtk_signal_connect(GTK_OBJECT(cancel_bt), "clicked",
198                 GTK_SIGNAL_FUNC(filter_dlg_cancel), GTK_OBJECT(main_w));
199         GTK_WIDGET_SET_FLAGS(cancel_bt, GTK_CAN_DEFAULT);
200         gtk_box_pack_start(GTK_BOX(bbox), cancel_bt, TRUE, TRUE, 0);
201         gtk_widget_show(cancel_bt);
202
203
204         gtk_widget_show(main_w);
205 }
206
207 static void
208 filter_dlg_ok(GtkWidget *ok_bt, gpointer parent_w)
209 {
210         filter_prefs_ok(gtk_object_get_data(GTK_OBJECT(parent_w), E_FILTER_WIDGET_KEY));
211         gtk_widget_destroy(GTK_WIDGET(parent_w));
212 }
213
214 static void
215 filter_dlg_save(GtkWidget *save_bt, gpointer parent_w)
216 {
217         filter_prefs_save(gtk_object_get_data(GTK_OBJECT(parent_w), E_FILTER_WIDGET_KEY));
218 }
219
220 static void
221 filter_dlg_cancel(GtkWidget *cancel_bt, gpointer parent_w)
222 {
223         filter_prefs_cancel(gtk_object_get_data(GTK_OBJECT(parent_w),  E_FILTER_WIDGET_KEY));
224         gtk_widget_destroy(GTK_WIDGET(parent_w));
225 }
226         
227 /* Create and display the filter selection widgets. */
228 static GtkWidget *
229 filter_prefs_show(GtkWidget *w) {
230   GtkWidget  *main_vb, *top_hb, *list_bb, *new_bt, *filter_sc,
231              *nl_item, *nl_lb, *middle_hb, *name_lb, *bottom_hb,
232              *filter_lb;
233   GtkWidget  *l_select = NULL;
234   GList      *flp = NULL;
235   filter_def *filt;
236   gchar      *filter_te_str = NULL;
237
238   /* Make sure everything is set up */  
239   get_filter_list();
240   if (w)
241     filter_te_str = gtk_entry_get_text(GTK_ENTRY(w));
242
243   /* Container for each row of widgets */
244   main_vb = gtk_vbox_new(FALSE, 5);
245   gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
246   gtk_widget_show(main_vb);
247   gtk_object_set_data(GTK_OBJECT(main_vb), E_FILT_CM_KEY, (gpointer)FALSE);
248   
249   /* Top row: Filter list and buttons */
250   top_hb = gtk_hbox_new(FALSE, 5);
251   gtk_container_add(GTK_CONTAINER(main_vb), top_hb);
252   gtk_widget_show(top_hb);
253   
254   list_bb = gtk_vbutton_box_new();
255   gtk_button_box_set_layout (GTK_BUTTON_BOX (list_bb), GTK_BUTTONBOX_START);
256   gtk_container_add(GTK_CONTAINER(top_hb), list_bb);
257   gtk_widget_show(list_bb);
258
259   new_bt = gtk_button_new_with_label ("New");
260   gtk_signal_connect(GTK_OBJECT(new_bt), "clicked",
261     GTK_SIGNAL_FUNC(filter_sel_new_cb), NULL);
262   gtk_container_add(GTK_CONTAINER(list_bb), new_bt);
263   gtk_widget_show(new_bt);
264   
265   chg_bt = gtk_button_new_with_label ("Change");
266   gtk_widget_set_sensitive(chg_bt, FALSE);
267   gtk_signal_connect(GTK_OBJECT(chg_bt), "clicked",
268     GTK_SIGNAL_FUNC(filter_sel_chg_cb), NULL);
269   gtk_container_add(GTK_CONTAINER(list_bb), chg_bt);
270   gtk_widget_show(chg_bt);
271   
272   copy_bt = gtk_button_new_with_label ("Copy");
273   gtk_widget_set_sensitive(copy_bt, FALSE);
274   gtk_signal_connect(GTK_OBJECT(copy_bt), "clicked",
275     GTK_SIGNAL_FUNC(filter_sel_copy_cb), NULL);
276   gtk_container_add(GTK_CONTAINER(list_bb), copy_bt);
277   gtk_widget_show(copy_bt);
278   
279   del_bt = gtk_button_new_with_label ("Delete");
280   gtk_widget_set_sensitive(del_bt, FALSE);
281   gtk_signal_connect(GTK_OBJECT(del_bt), "clicked",
282     GTK_SIGNAL_FUNC(filter_sel_del_cb), NULL);
283   gtk_container_add(GTK_CONTAINER(list_bb), del_bt);
284   gtk_widget_show(del_bt);
285
286   apply_bt = gtk_button_new_with_label("Apply");
287   gtk_widget_set_sensitive(apply_bt, FALSE);
288   gtk_signal_connect(GTK_OBJECT(apply_bt), "clicked",
289     GTK_SIGNAL_FUNC(filter_sel_apply_cb), w);
290   gtk_container_add(GTK_CONTAINER(list_bb), apply_bt);
291   gtk_widget_show(apply_bt);
292
293   filter_sc = gtk_scrolled_window_new(NULL, NULL);
294   gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(filter_sc),
295     GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
296   gtk_widget_set_usize(filter_sc, 250, 150);
297   gtk_container_add(GTK_CONTAINER(top_hb), filter_sc);
298   gtk_widget_show(filter_sc);
299
300   filter_l = gtk_list_new();
301   gtk_list_set_selection_mode(GTK_LIST(filter_l), GTK_SELECTION_SINGLE);
302   gtk_signal_connect(GTK_OBJECT(filter_l), "selection_changed",
303     GTK_SIGNAL_FUNC(filter_sel_list_cb), main_vb);
304   gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(filter_sc),
305     filter_l);
306   gtk_widget_show(filter_l);
307
308   flp = g_list_first(fl);
309   while (flp) {
310     filt    = (filter_def *) flp->data;
311     nl_lb   = gtk_label_new(filt->name);
312     nl_item = gtk_list_item_new();
313     gtk_misc_set_alignment (GTK_MISC (nl_lb), 0.0, 0.5);
314     gtk_container_add(GTK_CONTAINER(nl_item), nl_lb);
315     gtk_widget_show(nl_lb);
316     gtk_container_add(GTK_CONTAINER(filter_l), nl_item);
317     gtk_widget_show(nl_item);
318     gtk_object_set_data(GTK_OBJECT(nl_item), E_FILT_LBL_KEY, nl_lb);
319     gtk_object_set_data(GTK_OBJECT(nl_item), E_FILT_NAME_KEY, flp);
320  
321     if (filter_te_str && filt->strval)
322       if (strcmp(filter_te_str, filt->strval) == 0)
323         l_select = nl_item;
324
325     flp = flp->next;
326   }
327   
328   /* Middle row: Filter name entry */
329   middle_hb = gtk_hbox_new(FALSE, 5);
330   gtk_container_add(GTK_CONTAINER(main_vb), middle_hb);
331   gtk_widget_show(middle_hb);
332   
333   name_lb = gtk_label_new("Filter name:");
334   gtk_box_pack_start(GTK_BOX(middle_hb), name_lb, FALSE, FALSE, 3);
335   gtk_widget_show(name_lb);
336   
337   name_te = gtk_entry_new();
338   gtk_box_pack_start(GTK_BOX(middle_hb), name_te, TRUE, TRUE, 3);
339   gtk_widget_show(name_te);
340
341   /* Bottom row: Filter text entry */
342   bottom_hb = gtk_hbox_new(FALSE, 5);
343   gtk_container_add(GTK_CONTAINER(main_vb), bottom_hb);
344   gtk_widget_show(bottom_hb);
345   
346   filter_lb = gtk_label_new("Filter string:");
347   gtk_box_pack_start(GTK_BOX(bottom_hb), filter_lb, FALSE, FALSE, 3);
348   gtk_widget_show(filter_lb);
349   
350   filter_te = gtk_entry_new();
351   gtk_box_pack_start(GTK_BOX(bottom_hb), filter_te, TRUE, TRUE, 3);
352   gtk_widget_show(filter_te);
353
354   if (l_select)
355   {
356     gtk_list_select_child(GTK_LIST(filter_l), l_select);
357   } else if (filter_te_str && filter_te_str[0]) {
358     gtk_entry_set_text(GTK_ENTRY(name_te), "New filter");
359     gtk_entry_set_text(GTK_ENTRY(filter_te), filter_te_str);
360   }
361     
362   return(main_vb);
363 }
364
365 static void
366 filter_sel_list_cb(GtkWidget *l, gpointer data) {
367   filter_def *filt;
368   gchar      *name = "", *strval = "";
369   GList      *sl, *flp;
370   GtkObject  *l_item;
371   gint        sensitivity = FALSE;
372
373   if (l)
374           sl = GTK_LIST(l)->selection;
375   else
376           sl = NULL;
377           
378   if (sl) {  /* Something was selected */
379     l_item = GTK_OBJECT(sl->data);
380     flp    = (GList *) gtk_object_get_data(l_item, E_FILT_NAME_KEY);
381     if (flp) {
382       filt   = (filter_def *) flp->data;
383       name   = filt->name;
384       strval = filt->strval;
385       sensitivity = TRUE;
386     }
387   }
388
389   /* Did you know that this function is called when the window is destroyed? */
390   /* Funny, that. */
391   if (!gtk_object_get_data(GTK_OBJECT(data), E_FILT_CM_KEY)) {
392     gtk_entry_set_text(GTK_ENTRY(name_te), name);
393     gtk_entry_set_text(GTK_ENTRY(filter_te), strval);
394     gtk_widget_set_sensitive(chg_bt, sensitivity);
395     gtk_widget_set_sensitive(copy_bt, sensitivity);
396     gtk_widget_set_sensitive(del_bt, sensitivity);
397     gtk_widget_set_sensitive(apply_bt, sensitivity);
398   }
399 }
400
401 /* To do: add input checking to each of these callbacks */
402  
403 static void
404 filter_sel_new_cb(GtkWidget *w, gpointer data) {
405   filter_def *filt;
406   gchar      *name, *strval;
407   GtkWidget  *nl_item, *nl_lb;
408   
409   name   = gtk_entry_get_text(GTK_ENTRY(name_te));
410   strval = gtk_entry_get_text(GTK_ENTRY(filter_te));
411   
412   if (strlen(name) > 0 && strlen(strval) > 0) {
413     filt         = (filter_def *) g_malloc(sizeof(filter_def));
414     filt->name   = g_strdup(name);
415     filt->strval = g_strdup(strval);
416     fl           = g_list_append(fl, filt);
417     nl_lb        = gtk_label_new(filt->name);
418     nl_item      = gtk_list_item_new();
419     gtk_misc_set_alignment (GTK_MISC (nl_lb), 0.0, 0.5);
420     gtk_container_add(GTK_CONTAINER(nl_item), nl_lb);
421     gtk_widget_show(nl_lb);
422     gtk_container_add(GTK_CONTAINER(filter_l), nl_item);
423     gtk_widget_show(nl_item);
424     gtk_object_set_data(GTK_OBJECT(nl_item), E_FILT_LBL_KEY, nl_lb);
425     gtk_object_set_data(GTK_OBJECT(nl_item), E_FILT_NAME_KEY, g_list_last(fl));
426     gtk_list_select_child(GTK_LIST(filter_l), nl_item);
427   }
428 }
429
430 static void
431 filter_sel_chg_cb(GtkWidget *w, gpointer data) {
432   filter_def *filt;
433   gchar      *name = "", *strval = "";
434   GList      *sl, *flp;
435   GtkObject  *l_item;
436   GtkLabel   *nl_lb;
437
438   sl     = GTK_LIST(filter_l)->selection;
439   name   = gtk_entry_get_text(GTK_ENTRY(name_te));
440   strval = gtk_entry_get_text(GTK_ENTRY(filter_te));
441
442   if (sl) {  /* Something was selected */
443     l_item = GTK_OBJECT(sl->data);
444     flp    = (GList *) gtk_object_get_data(l_item, E_FILT_NAME_KEY);
445     nl_lb  = (GtkLabel *) gtk_object_get_data(l_item, E_FILT_LBL_KEY);
446     if (flp && nl_lb) {
447       filt = (filter_def *) flp->data;
448       
449       if (strlen(name) > 0 && strlen(strval) > 0 && filt) {
450         g_free(filt->name);
451         g_free(filt->strval);
452         filt->name   = g_strdup(name);
453         filt->strval = g_strdup(strval);
454         gtk_label_set(nl_lb, filt->name);
455       }
456     }
457   }
458 }
459
460 static void
461 filter_sel_copy_cb(GtkWidget *w, gpointer data) {
462   GList      *sl, *flp;
463   filter_def *filt, *nfilt;
464   gchar      *prefix = "Copy of ";
465   GtkObject  *l_item;
466   GtkWidget  *nl_item, *nl_lb;
467   
468   sl     = GTK_LIST(filter_l)->selection;
469   if (sl) {  /* Something was selected */
470     l_item = GTK_OBJECT(sl->data);
471     flp    = (GList *) gtk_object_get_data(l_item, E_FILT_NAME_KEY);
472     if (flp) {
473       filt          = (filter_def *) flp->data;
474       nfilt         = (filter_def *) g_malloc(sizeof(filter_def));
475       nfilt->name   = g_malloc(strlen(prefix) + strlen(filt->name) + 1);
476       sprintf(nfilt->name, "%s%s", prefix, filt->name);
477       nfilt->strval = g_strdup(filt->strval);
478       fl            = g_list_append(fl, nfilt);
479       nl_lb         = gtk_label_new(nfilt->name);
480       nl_item       = gtk_list_item_new();
481       gtk_misc_set_alignment (GTK_MISC (nl_lb), 0.0, 0.5);
482       gtk_container_add(GTK_CONTAINER(nl_item), nl_lb);
483       gtk_widget_show(nl_lb);
484       gtk_container_add(GTK_CONTAINER(filter_l), nl_item);
485       gtk_widget_show(nl_item);
486       gtk_object_set_data(GTK_OBJECT(nl_item), E_FILT_LBL_KEY, nl_lb);
487       gtk_object_set_data(GTK_OBJECT(nl_item), E_FILT_NAME_KEY, g_list_last(fl));
488       gtk_list_select_child(GTK_LIST(filter_l), nl_item);
489     }
490   }
491 }
492
493 static void
494 filter_sel_del_cb(GtkWidget *w, gpointer data) {
495   GList      *sl, *flp;
496   filter_def *filt;
497   GtkObject  *l_item;
498   gint        pos;
499   
500   sl = GTK_LIST(filter_l)->selection;
501   if (sl) {  /* Something was selected */
502     l_item = GTK_OBJECT(sl->data);
503     pos    = gtk_list_child_position(GTK_LIST(filter_l),
504       GTK_WIDGET(l_item));
505     flp    = (GList *) gtk_object_get_data(l_item, E_FILT_NAME_KEY);
506     if (flp) {
507       filt = (filter_def *) flp->data;
508       g_free(filt->name);
509       g_free(filt->strval);
510       g_free(filt);
511       fl = g_list_remove_link(fl, flp);
512       gtk_list_clear_items(GTK_LIST(filter_l), pos, pos + 1);
513     } 
514   }
515 }
516
517 void
518 filter_sel_apply_cb(GtkWidget *w, gpointer data)
519 {
520         GList      *flp, *sl;
521         GtkObject  *l_item;
522         filter_def *filt;
523         GtkWidget  *mw_filt = data;
524         
525         sl = GTK_LIST(filter_l)->selection;
526         if (sl != NULL && mw_filt != NULL) {  /* Place something in the filter box. */
527                 l_item = GTK_OBJECT(sl->data);
528                 flp    = (GList *) gtk_object_get_data(l_item, E_FILT_NAME_KEY);
529                 if (flp) {
530                         filt = (filter_def *) flp->data;
531                         gtk_entry_set_text(GTK_ENTRY(mw_filt), filt->strval);
532                         gtk_signal_emit_by_name(GTK_OBJECT(mw_filt), "activate");
533                 }
534         }
535 }
536
537 static void
538 filter_prefs_ok(GtkWidget *w) {
539   GList      *flp, *sl;
540   GtkObject  *l_item;
541   filter_def *filt;
542   GtkWidget  *mw_filt = gtk_object_get_data(GTK_OBJECT(w), E_FILT_TE_PTR_KEY);
543
544   sl = GTK_LIST(filter_l)->selection;
545   if (sl && mw_filt) {  /* Place something in the filter box. */
546     l_item = GTK_OBJECT(sl->data);
547     flp    = (GList *) gtk_object_get_data(l_item, E_FILT_NAME_KEY);
548     if (flp) {
549       filt = (filter_def *) flp->data;
550       gtk_entry_set_text(GTK_ENTRY(mw_filt), filt->strval);
551     }
552   }
553
554   filter_prefs_delete(w);
555 }
556
557 static void
558 filter_prefs_save(GtkWidget *w) {
559   GList       *flp;
560   filter_def  *filt;
561   gchar       *ff_path, *ff_dir = PF_DIR, *ff_name = "filters";
562   FILE        *ff;
563   struct stat  s_buf;
564   
565   ff_path = (gchar *) g_malloc(strlen(get_home_dir()) + strlen(ff_dir) +  
566     strlen(ff_name) + 4);
567   sprintf(ff_path, "%s/%s", get_home_dir(), ff_dir);
568
569   if (stat(ff_path, &s_buf) != 0)
570 #ifdef WIN32
571     mkdir(ff_path);
572 #else
573     mkdir(ff_path, 0755);
574 #endif
575     
576   sprintf(ff_path, "%s/%s/%s", get_home_dir(), ff_dir, ff_name);
577
578   if ((ff = fopen(ff_path, "w")) != NULL) {
579     flp = g_list_first(fl);
580     while (flp) {
581       filt = (filter_def *) flp->data;
582       fprintf(ff, "\"%s\" %s\n", filt->name, filt->strval);
583       flp = flp->next;
584     }
585     fclose(ff);
586   }
587
588   g_free(ff_path);
589 }
590
591 static void
592 filter_prefs_cancel(GtkWidget *w) {
593
594   filter_prefs_delete(w);
595 }
596
597 static void
598 filter_prefs_delete(GtkWidget *w) {
599  
600   /* Let the list cb know we're about to destroy the widget tree, so it */
601   /* doesn't operate on widgets that don't exist. */  
602   gtk_object_set_data(GTK_OBJECT(w), E_FILT_CM_KEY, (gpointer)TRUE);
603   gtk_widget_destroy(GTK_WIDGET(w));
604