Commented out a left-over debug printf() statement.
[obnox/wireshark/wip.git] / filter.c
1 /* filter.c
2  * Routines for managing filter sets
3  *
4  * $Id: filter.c,v 1.6 1998/10/13 02:10:55 gerald Exp $
5  *
6  * Ethereal - Network traffic analyzer
7  * By Gerald Combs <gerald@zing.org>
8  * Copyright 1998 Gerald Combs
9  *
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
32 #include <string.h>
33 #include <sys/stat.h>
34 #include <unistd.h>
35 #include <ctype.h>
36
37 #include "ethereal.h"
38 #include "filter.h"
39 #include "packet.h"
40 #include "file.h"
41 #include "menu.h"
42 #include "prefs.h"
43
44 #define E_FILT_NAME_KEY "filter_name"
45 #define E_FILT_LBL_KEY  "filter_label"
46 #define E_FILT_CM_KEY   "in_cancel_mode"
47
48 GtkWidget   *filter_l, *chg_bt, *copy_bt, *del_bt, *name_te, *filter_te;
49 GList       *fl = NULL;
50
51 void get_filter_list();
52
53 void
54 get_filter_list() {
55   filter_def *filt;
56   FILE       *ff;
57   gchar      *ff_path, *ff_name = ".ethereal/filters", f_buf[256];
58   gchar      *name_begin, *name_end, *filt_begin;
59   int         len, line = 0;
60
61   if (fl) return;
62   
63   /* To do: generalize this */
64   ff_path = (gchar *) g_malloc(strlen(getenv("HOME")) + strlen(ff_name) +  4);
65   sprintf(ff_path, "%s/%s", getenv("HOME"), ff_name);
66
67   if ((ff = fopen(ff_path, "r")) == NULL) {
68     g_free(ff_path);
69     return;
70   }
71
72   while (fgets(f_buf, 256, ff)) {
73     line++;
74     len = strlen(f_buf);
75     if (f_buf[len - 1] == '\n') {
76       len--;
77       f_buf[len] = '\0';
78     }
79     name_begin = strchr(f_buf, '"');
80     /* Empty line */
81     if (name_begin == NULL)
82       continue;
83     name_end = strchr(name_begin + 1, '"');
84     /* No terminating quote */
85     if (name_end == NULL) {
86       g_warning("Malformed filter in '%s' line %d.", ff_path, line);
87       continue;
88     }
89     name_begin++;
90     name_end[0] = '\0';
91     filt_begin  = name_end + 1;
92     while(isspace(filt_begin[0])) filt_begin++;
93     /* No filter string */
94     if (filt_begin[0] == '\0') {
95       g_warning("Malformed filter in '%s' line %d.", ff_path, line);
96       continue;
97     }
98     filt         = (filter_def *) g_malloc(sizeof(filter_def));
99     filt->name   = g_strdup(name_begin);
100     filt->strval = g_strdup(filt_begin);
101     fl = g_list_append(fl, filt);
102   }
103   fclose(ff);
104   g_free(ff_path);
105 }
106
107 /* filter_sel_pg - Create and display the filter selection widgets. */
108 /* Called when the 'Filter' preference notebook page is selected. */
109 GtkWidget *
110 filter_prefs_show(GtkWidget *w) {
111   GtkWidget  *main_vb, *top_hb, *list_bb, *new_bt, *filter_sc,
112              *nl_item, *nl_lb, *middle_hb, *name_lb, *bottom_hb,
113              *filter_lb;
114   GtkWidget  *l_select = NULL;
115   GList      *flp = NULL;
116   filter_def *filt;
117   gchar      *filter_te_str = NULL;
118
119   /* Make sure everything is set up */  
120   get_filter_list();
121   if (w)
122     filter_te_str = gtk_entry_get_text(GTK_ENTRY(w));
123
124   /* Container for each row of widgets */
125   main_vb = gtk_vbox_new(FALSE, 5);
126   gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
127   gtk_widget_show(main_vb);
128   gtk_object_set_data(GTK_OBJECT(main_vb), E_FILT_CM_KEY, (gpointer)FALSE);
129   
130   /* Top row: Filter list and buttons */
131   top_hb = gtk_hbox_new(FALSE, 5);
132   gtk_container_add(GTK_CONTAINER(main_vb), top_hb);
133   gtk_widget_show(top_hb);
134   
135   list_bb = gtk_vbutton_box_new();
136   gtk_button_box_set_layout (GTK_BUTTON_BOX (list_bb), GTK_BUTTONBOX_START);
137   gtk_container_add(GTK_CONTAINER(top_hb), list_bb);
138   gtk_widget_show(list_bb);
139
140   new_bt = gtk_button_new_with_label ("New");
141   gtk_signal_connect(GTK_OBJECT(new_bt), "clicked",
142     GTK_SIGNAL_FUNC(filter_sel_new_cb), NULL);
143   gtk_container_add(GTK_CONTAINER(list_bb), new_bt);
144   gtk_widget_show(new_bt);
145   
146   chg_bt = gtk_button_new_with_label ("Change");
147   gtk_widget_set_sensitive(chg_bt, FALSE);
148   gtk_signal_connect(GTK_OBJECT(chg_bt), "clicked",
149     GTK_SIGNAL_FUNC(filter_sel_chg_cb), NULL);
150   gtk_container_add(GTK_CONTAINER(list_bb), chg_bt);
151   gtk_widget_show(chg_bt);
152   
153   copy_bt = gtk_button_new_with_label ("Copy");
154   gtk_widget_set_sensitive(copy_bt, FALSE);
155   gtk_signal_connect(GTK_OBJECT(copy_bt), "clicked",
156     GTK_SIGNAL_FUNC(filter_sel_copy_cb), NULL);
157   gtk_container_add(GTK_CONTAINER(list_bb), copy_bt);
158   gtk_widget_show(copy_bt);
159   
160   del_bt = gtk_button_new_with_label ("Delete");
161   gtk_widget_set_sensitive(del_bt, FALSE);
162   gtk_signal_connect(GTK_OBJECT(del_bt), "clicked",
163     GTK_SIGNAL_FUNC(filter_sel_del_cb), NULL);
164   gtk_container_add(GTK_CONTAINER(list_bb), del_bt);
165   gtk_widget_show(del_bt);
166   
167   filter_sc = gtk_scrolled_window_new(NULL, NULL);
168   gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(filter_sc),
169     GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
170   gtk_widget_set_usize(filter_sc, 250, 150);
171   gtk_container_add(GTK_CONTAINER(top_hb), filter_sc);
172   gtk_widget_show(filter_sc);
173
174   filter_l = gtk_list_new();
175   gtk_signal_connect(GTK_OBJECT(filter_l), "selection_changed",
176     GTK_SIGNAL_FUNC(filter_sel_list_cb), main_vb);
177   gtk_container_add(GTK_CONTAINER(filter_sc), filter_l);
178   gtk_widget_show(filter_l);
179
180   flp = g_list_first(fl);
181   while (flp) {
182     filt    = (filter_def *) flp->data;
183     nl_lb   = gtk_label_new(filt->name);
184     nl_item = gtk_list_item_new();
185     gtk_misc_set_alignment (GTK_MISC (nl_lb), 0.0, 0.5);
186     gtk_container_add(GTK_CONTAINER(nl_item), nl_lb);
187     gtk_widget_show(nl_lb);
188     gtk_container_add(GTK_CONTAINER(filter_l), nl_item);
189     gtk_widget_show(nl_item);
190     gtk_object_set_data(GTK_OBJECT(nl_item), E_FILT_LBL_KEY, nl_lb);
191     gtk_object_set_data(GTK_OBJECT(nl_item), E_FILT_NAME_KEY, flp);
192  
193     if (filter_te_str && filt->strval)
194       if (strcmp(filter_te_str, filt->strval) == 0)
195         l_select = nl_item;
196
197     flp = flp->next;
198   }
199   
200   /* Middle row: Filter name entry */
201   middle_hb = gtk_hbox_new(FALSE, 5);
202   gtk_container_add(GTK_CONTAINER(main_vb), middle_hb);
203   gtk_widget_show(middle_hb);
204   
205   name_lb = gtk_label_new("Filter name:");
206   gtk_box_pack_start(GTK_BOX(middle_hb), name_lb, FALSE, FALSE, 3);
207   gtk_widget_show(name_lb);
208   
209   name_te = gtk_entry_new();
210   gtk_box_pack_start(GTK_BOX(middle_hb), name_te, TRUE, TRUE, 3);
211   gtk_widget_show(name_te);
212
213   /* Bottom row: Filter text entry */
214   bottom_hb = gtk_hbox_new(FALSE, 5);
215   gtk_container_add(GTK_CONTAINER(main_vb), bottom_hb);
216   gtk_widget_show(bottom_hb);
217   
218   filter_lb = gtk_label_new("Filter string:");
219   gtk_box_pack_start(GTK_BOX(bottom_hb), filter_lb, FALSE, FALSE, 3);
220   gtk_widget_show(filter_lb);
221   
222   filter_te = gtk_entry_new();
223   gtk_box_pack_start(GTK_BOX(bottom_hb), filter_te, TRUE, TRUE, 3);
224   gtk_widget_show(filter_te);
225
226   if (l_select)
227     gtk_list_select_child(GTK_LIST(filter_l), l_select);
228     
229   return(main_vb);
230 }
231
232 void
233 filter_sel_list_cb(GtkWidget *l, gpointer data) {
234   filter_def *filt;
235   gchar      *name = "", *strval = "";
236   GList      *sl, *flp;
237   GtkObject  *l_item;
238   gint        sensitivity = FALSE;
239
240   sl = GTK_LIST(l)->selection;
241           
242   if (sl) {  /* Something was selected */
243     l_item = GTK_OBJECT(sl->data);
244     flp    = (GList *) gtk_object_get_data(l_item, E_FILT_NAME_KEY);
245     if (flp) {
246       filt   = (filter_def *) flp->data;
247       name   = filt->name;
248       strval = filt->strval;
249       sensitivity = TRUE;
250     }
251   }
252
253   /* Did you know that this function is called when the window is destroyed? */
254   /* Funny, that. */
255   if (!gtk_object_get_data(GTK_OBJECT(data), E_FILT_CM_KEY)) {
256     gtk_entry_set_text(GTK_ENTRY(name_te), name);
257     gtk_entry_set_text(GTK_ENTRY(filter_te), strval);
258     gtk_widget_set_sensitive(chg_bt, sensitivity);
259     gtk_widget_set_sensitive(copy_bt, sensitivity);
260     gtk_widget_set_sensitive(del_bt, sensitivity);
261   }
262 }
263
264 /* To do: add input checking to each of these callbacks */
265  
266 void
267 filter_sel_new_cb(GtkWidget *w, gpointer data) {
268   filter_def *filt;
269   gchar      *name, *strval;
270   GtkWidget  *nl_item, *nl_lb;
271   
272   name   = gtk_entry_get_text(GTK_ENTRY(name_te));
273   strval = gtk_entry_get_text(GTK_ENTRY(filter_te));
274   
275   if (strlen(name) > 0 && strlen(strval) > 0) {
276     filt         = (filter_def *) g_malloc(sizeof(filter_def));
277     filt->name   = g_strdup(name);
278     filt->strval = g_strdup(strval);
279     fl           = g_list_append(fl, filt);
280     nl_lb        = gtk_label_new(filt->name);
281     nl_item      = gtk_list_item_new();
282     gtk_misc_set_alignment (GTK_MISC (nl_lb), 0.0, 0.5);
283     gtk_container_add(GTK_CONTAINER(nl_item), nl_lb);
284     gtk_widget_show(nl_lb);
285     gtk_container_add(GTK_CONTAINER(filter_l), nl_item);
286     gtk_widget_show(nl_item);
287     gtk_object_set_data(GTK_OBJECT(nl_item), E_FILT_LBL_KEY, nl_lb);
288     gtk_object_set_data(GTK_OBJECT(nl_item), E_FILT_NAME_KEY, g_list_last(fl));
289     gtk_list_select_child(GTK_LIST(filter_l), nl_item);
290   }
291 }
292
293 void
294 filter_sel_chg_cb(GtkWidget *w, gpointer data) {
295   filter_def *filt;
296   gchar      *name = "", *strval = "";
297   GList      *sl, *flp;
298   GtkObject  *l_item;
299   GtkLabel   *nl_lb;
300
301   sl     = GTK_LIST(filter_l)->selection;
302   name   = gtk_entry_get_text(GTK_ENTRY(name_te));
303   strval = gtk_entry_get_text(GTK_ENTRY(filter_te));
304
305   if (sl) {  /* Something was selected */
306     l_item = GTK_OBJECT(sl->data);
307     flp    = (GList *) gtk_object_get_data(l_item, E_FILT_NAME_KEY);
308     nl_lb  = (GtkLabel *) gtk_object_get_data(l_item, E_FILT_LBL_KEY);
309     if (flp && nl_lb) {
310       filt = (filter_def *) flp->data;
311       
312       if (strlen(name) > 0 && strlen(strval) > 0 && filt) {
313         g_free(filt->name);
314         g_free(filt->strval);
315         filt->name   = g_strdup(name);
316         filt->strval = g_strdup(strval);
317         gtk_label_set(nl_lb, filt->name);
318       }
319     }
320   }
321 }
322
323 void
324 filter_sel_copy_cb(GtkWidget *w, gpointer data) {
325   GList      *sl, *flp;
326   filter_def *filt, *nfilt;
327   gchar      *prefix = "Copy of ";
328   GtkObject  *l_item;
329   GtkWidget  *nl_item, *nl_lb;
330   
331   sl     = GTK_LIST(filter_l)->selection;
332   if (sl) {  /* Something was selected */
333     l_item = GTK_OBJECT(sl->data);
334     flp    = (GList *) gtk_object_get_data(l_item, E_FILT_NAME_KEY);
335     if (flp) {
336       filt          = (filter_def *) flp->data;
337       nfilt         = (filter_def *) g_malloc(sizeof(filter_def));
338       nfilt->name   = g_malloc(strlen(prefix) + strlen(filt->name) + 1);
339       sprintf(nfilt->name, "%s%s", prefix, filt->name);
340       nfilt->strval = g_strdup(filt->strval);
341       fl            = g_list_append(fl, nfilt);
342       nl_lb         = gtk_label_new(nfilt->name);
343       nl_item       = gtk_list_item_new();
344       gtk_misc_set_alignment (GTK_MISC (nl_lb), 0.0, 0.5);
345       gtk_container_add(GTK_CONTAINER(nl_item), nl_lb);
346       gtk_widget_show(nl_lb);
347       gtk_container_add(GTK_CONTAINER(filter_l), nl_item);
348       gtk_widget_show(nl_item);
349       gtk_object_set_data(GTK_OBJECT(nl_item), E_FILT_LBL_KEY, nl_lb);
350       gtk_object_set_data(GTK_OBJECT(nl_item), E_FILT_NAME_KEY, g_list_last(fl));
351       gtk_list_select_child(GTK_LIST(filter_l), nl_item);
352     }
353   }
354 }
355
356 void
357 filter_sel_del_cb(GtkWidget *w, gpointer data) {
358   GList      *sl, *flp;
359   filter_def *filt;
360   GtkObject  *l_item;
361   gint        pos;
362   
363   sl = GTK_LIST(filter_l)->selection;
364   if (sl) {  /* Something was selected */
365     l_item = GTK_OBJECT(sl->data);
366     pos    = gtk_list_child_position(GTK_LIST(filter_l),
367       GTK_WIDGET(l_item));
368     flp    = (GList *) gtk_object_get_data(l_item, E_FILT_NAME_KEY);
369     if (flp) {
370       filt = (filter_def *) flp->data;
371       g_free(filt->name);
372       g_free(filt->strval);
373       g_free(filt);
374       fl = g_list_remove_link(fl, flp);
375       gtk_list_clear_items(GTK_LIST(filter_l), pos, pos + 1);
376     } 
377   }
378 }
379
380 void
381 filter_prefs_ok(GtkWidget *w) {
382   GList      *flp, *sl;
383   GtkObject  *l_item;
384   filter_def *filt;
385   GtkWidget  *mw_filt = gtk_object_get_data(GTK_OBJECT(w), E_FILT_TE_PTR_KEY);
386
387   sl = GTK_LIST(filter_l)->selection;
388   if (sl && mw_filt) {  /* Place something in the filter box. */
389     l_item = GTK_OBJECT(sl->data);
390     flp    = (GList *) gtk_object_get_data(l_item, E_FILT_NAME_KEY);
391     if (flp) {
392       filt = (filter_def *) flp->data;
393       gtk_entry_set_text(GTK_ENTRY(mw_filt), filt->strval);
394     }
395   }
396
397   filter_prefs_cancel(w);
398 }
399
400 void
401 filter_prefs_save(GtkWidget *w) {
402   GList       *flp;
403   filter_def  *filt;
404   gchar       *ff_path, *ff_dir = ".ethereal", *ff_name = "filters";
405   FILE        *ff;
406   struct stat  s_buf;
407   
408   ff_path = (gchar *) g_malloc(strlen(getenv("HOME")) + strlen(ff_dir) +  
409     strlen(ff_name) + 4);
410   sprintf(ff_path, "%s/%s", getenv("HOME"), ff_dir);
411
412   if (stat(ff_path, &s_buf) != 0)
413     mkdir(ff_path, 0755);
414     
415   sprintf(ff_path, "%s/%s/%s", getenv("HOME"), ff_dir, ff_name);
416
417   if ((ff = fopen(ff_path, "w")) != NULL) {
418     flp = g_list_first(fl);
419     while (flp) {
420       filt = (filter_def *) flp->data;
421       fprintf(ff, "\"%s\" %s\n", filt->name, filt->strval);
422       flp = flp->next;
423     }
424     fclose(ff);
425   }
426
427   g_free(ff_path);
428 }
429
430 void
431 filter_prefs_cancel(GtkWidget *w) {
432   filter_def *filt;
433   
434   /* Let the list cb know we're about to destroy the widget tree, so it */
435   /* doesn't operate on widgets that don't exist. */  
436   gtk_object_set_data(GTK_OBJECT(w), E_FILT_CM_KEY, (gpointer)TRUE);
437   gtk_widget_destroy(GTK_WIDGET(w));
438