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