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