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