Include <direct.h>, if we have it, to declare "mkdir()" on Windows.
[obnox/wireshark/wip.git] / filters.c
1 /* filters.c
2  * Code for reading and writing the filters file.
3  *
4  * $Id: filters.c,v 1.4 2001/01/28 22:28:31 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 <stdio.h>
31 #include <string.h>
32 #include <ctype.h>
33 #include <errno.h>
34
35 #ifdef HAVE_SYS_STAT_H
36 #include <sys/stat.h>
37 #endif
38
39 #ifdef HAVE_UNISTD_H
40 #include <unistd.h>
41 #endif
42
43 #ifdef HAVE_DIRECT_H
44 #include <direct.h>             /* to declare "mkdir()" on Windows */
45 #endif
46
47 #include <glib.h>
48
49 #include <epan.h>
50
51 #include "filters.h"
52 #include "util.h"
53
54 /*
55  * Old filter file name.
56  */
57 #define FILTER_FILE_NAME        "filters"
58
59 /*
60  * Capture filter file name.
61  */
62 #define CFILTER_FILE_NAME       "cfilters"
63
64 /*
65  * Display filter file name.
66  */
67 #define DFILTER_FILE_NAME       "dfilters"
68
69 #define FILTER_LINE_SIZE        2048
70
71 /*
72  * List of capture filters.
73  */
74 static GList *capture_filters = NULL;
75
76 /*
77  * List of display filters.
78  */
79 static GList *display_filters = NULL;
80
81 /*
82  * Read in a list of filters.
83  *
84  * On success, "*pref_path_return" is set to NULL.
85  * On error, "*pref_path_return" is set to point to the pathname of
86  * the file we tried to read - it should be freed by our caller -
87  * and "*errno_return" is set to the error.
88  */
89 void
90 read_filter_list(filter_list_type_t list, char **pref_path_return,
91     int *errno_return)
92 {
93   char       *ff_path, *ff_dir = PF_DIR, *ff_name;
94   FILE       *ff;
95   GList      **flp;
96   GList      *fl_ent;
97   filter_def *filt;
98   char       f_buf[FILTER_LINE_SIZE];
99   char       *name_begin, *name_end, *filt_begin;
100   int         len, line = 0;
101
102   *pref_path_return = NULL;     /* assume no error */
103
104   switch (list) {
105
106   case CFILTER_LIST:
107     ff_name = CFILTER_FILE_NAME;
108     flp = &capture_filters;
109     break;
110
111   case DFILTER_LIST:
112     ff_name = DFILTER_FILE_NAME;
113     flp = &display_filters;
114     break;
115
116   default:
117     g_assert_not_reached();
118     return;
119   }
120
121   /* To do: generalize this */
122   ff_path = (gchar *) g_malloc(strlen(get_home_dir()) + strlen(ff_dir) +  
123     strlen(ff_name) + 4);
124   sprintf(ff_path, "%s/%s/%s", get_home_dir(), ff_dir, ff_name);
125
126   if ((ff = fopen(ff_path, "r")) == NULL) {
127     /*
128      * Did that fail because we the file didn't exist?
129      */
130     if (errno != ENOENT) {
131       /*
132        * No.  Just give up.
133        */
134       *pref_path_return = ff_path;
135       *errno_return = errno;
136       return;
137     }
138
139     /*
140      * Yes.  See if there's a "filters" file; if so, read it.
141      * This means that a user will start out with their capture and
142      * display filter lists being identical; each list may contain
143      * filters that don't belong in that list.  The user can edit
144      * the filter lists, and delete the ones that don't belong in
145      * a particular list.
146      */
147     sprintf(ff_path, "%s/%s/%s", get_home_dir(), ff_dir, FILTER_FILE_NAME);
148     if ((ff = fopen(ff_path, "r")) == NULL) {
149       /*
150        * Well, that didn't work, either.  Just give up.
151        * Return an error if the file existed but we couldn't open it.
152        */
153       if (errno != ENOENT) {
154         *pref_path_return = ff_path;
155         *errno_return = errno;
156       }
157       return;
158     }
159   }
160
161   /* If we already have a list of filters, discard it. */
162   if (*flp != NULL) {
163     fl_ent = g_list_first(*flp);
164     while (fl_ent != NULL) {
165       filt = (filter_def *) fl_ent->data;
166       g_free(filt->name);
167       g_free(filt->strval);
168       g_free(filt);
169       fl_ent = fl_ent->next;
170     }
171     g_list_free(*flp);
172     *flp = NULL;
173   }
174
175   while (fgets(f_buf, FILTER_LINE_SIZE, ff)) {
176     line++;
177     len = strlen(f_buf);
178     if (f_buf[len - 1] == '\n') {
179       len--;
180       f_buf[len] = '\0';
181     }
182     name_begin = strchr(f_buf, '"');
183     /* Empty line */
184     if (name_begin == NULL)
185       continue;
186     name_end = strchr(name_begin + 1, '"');
187     /* No terminating quote */
188     if (name_end == NULL) {
189       g_warning("Malformed filter in '%s' line %d.", ff_path, line);
190       continue;
191     }
192     name_begin++;
193     name_end[0] = '\0';
194     filt_begin  = name_end + 1;
195     while(isspace((guchar)filt_begin[0])) filt_begin++;
196     /* No filter string */
197     if (filt_begin[0] == '\0') {
198       g_warning("Malformed filter in '%s' line %d.", ff_path, line);
199       continue;
200     }
201     filt         = (filter_def *) g_malloc(sizeof(filter_def));
202     filt->name   = g_strdup(name_begin);
203     filt->strval = g_strdup(filt_begin);
204     *flp = g_list_append(*flp, filt);
205   }
206   if (ferror(ff)) {
207     *pref_path_return = ff_path;
208     *errno_return = errno;
209   } else
210     g_free(ff_path);
211   fclose(ff);
212 }
213
214 /*
215  * Get a pointer to a list of filters.
216  */
217 static GList **
218 get_filter_list(filter_list_type_t list)
219 {
220   GList **flp;
221
222   switch (list) {
223
224   case CFILTER_LIST:
225     flp = &capture_filters;
226     break;
227
228   case DFILTER_LIST:
229     flp = &display_filters;
230     break;
231
232   default:
233     g_assert_not_reached();
234     flp = NULL;
235   }
236   return flp;
237 }
238
239 /*
240  * Get a pointer to the first entry in a filter list.
241  */
242 GList *
243 get_filter_list_first(filter_list_type_t list)
244 {
245   GList      **flp;
246   
247   flp = get_filter_list(list);
248   return g_list_first(*flp);
249 }
250
251 /*
252  * Add a new filter to the end of a list.
253  * Returns a pointer to the newly-added entry.
254  */
255 GList *
256 add_to_filter_list(filter_list_type_t list, char *name, char *expression)
257 {
258   GList      **flp;
259   filter_def *filt;
260   
261   flp = get_filter_list(list);
262   filt = (filter_def *) g_malloc(sizeof(filter_def));
263   filt->name = g_strdup(name);
264   filt->strval = g_strdup(expression);
265   *flp = g_list_append(*flp, filt);
266   return g_list_last(*flp);
267 }
268
269 /*
270  * Remove a filter from a list.
271  */
272 void
273 remove_from_filter_list(filter_list_type_t list, GList *fl_entry)
274 {
275   GList      **flp;
276   filter_def *filt;
277   
278   flp = get_filter_list(list);
279   filt = (filter_def *) fl_entry->data;
280   g_free(filt->name);
281   g_free(filt->strval);
282   g_free(filt);
283   *flp = g_list_remove_link(*flp, fl_entry);
284 }
285
286 /*
287  * Write out a list of filters.
288  *
289  * On success, "*pref_path_return" is set to NULL.
290  * On error, "*pref_path_return" is set to point to the pathname of
291  * the file we tried to read - it should be freed by our caller -
292  * and "*errno_return" is set to the error.
293  */
294 void
295 save_filter_list(filter_list_type_t list, char **pref_path_return,
296     int *errno_return)
297 {
298   gchar      *ff_path, *ff_path_new, *ff_dir = PF_DIR, *ff_name;
299   int         path_length;
300   GList      *fl;
301   GList      *flp;
302   filter_def *filt;
303   FILE       *ff;
304   struct stat s_buf;
305   
306   *pref_path_return = NULL;     /* assume no error */
307
308   switch (list) {
309
310   case CFILTER_LIST:
311     ff_name = CFILTER_FILE_NAME;
312     fl = capture_filters;
313     break;
314
315   case DFILTER_LIST:
316     ff_name = DFILTER_FILE_NAME;
317     fl = display_filters;
318     break;
319
320   default:
321     g_assert_not_reached();
322     return;
323   }
324
325   path_length = strlen(get_home_dir()) + strlen(ff_dir) + strlen(ff_name)
326                 + 4 + 4;
327   ff_path = (gchar *) g_malloc(path_length);
328   sprintf(ff_path, "%s/%s", get_home_dir(), ff_dir);
329
330   if (stat(ff_path, &s_buf) != 0)
331 #ifdef WIN32
332     mkdir(ff_path);
333 #else
334     mkdir(ff_path, 0755);
335 #endif
336     
337   sprintf(ff_path, "%s/%s/%s", get_home_dir(), ff_dir, ff_name);
338
339   /* Write to "XXX.new", and rename if that succeeds.
340      That means we don't trash the file if we fail to write it out
341      completely. */
342   ff_path_new = (gchar *) g_malloc(path_length);
343   sprintf(ff_path_new, "%s/%s/%s.new", get_home_dir(), ff_dir, ff_name);
344
345   if ((ff = fopen(ff_path_new, "w")) == NULL) {
346     *pref_path_return = ff_path;
347     *errno_return = errno;
348     g_free(ff_path_new);
349     return;
350   }
351   flp = g_list_first(fl);
352   while (flp) {
353     filt = (filter_def *) flp->data;
354     fprintf(ff, "\"%s\" %s\n", filt->name, filt->strval);
355     if (ferror(ff)) {
356       *pref_path_return = ff_path;
357       *errno_return = errno;
358       fclose(ff);
359       unlink(ff_path_new);
360       g_free(ff_path_new);
361       return;
362     }
363     flp = flp->next;
364   }
365   if (fclose(ff) == EOF) {
366     *pref_path_return = ff_path;
367     *errno_return = errno;
368     unlink(ff_path_new);
369     g_free(ff_path_new);
370     return;
371   }
372
373   /* XXX - does "rename()" exist on Win32?  If so, does it remove the
374      target first?  If so, does that mean it's not atomic? */
375   if (rename(ff_path_new, ff_path) < 0) {
376     *pref_path_return = ff_path;
377     *errno_return = errno;
378     unlink(ff_path_new);
379     g_free(ff_path);
380     g_free(ff_path_new);
381     return;
382   }
383   g_free(ff_path_new);
384   g_free(ff_path);
385 }