66174442e65da4284cdab91eb105c37029727f8d
[obnox/wireshark/wip.git] / filters.c
1 /* filters.c
2  * Code for reading and writing the filters file.
3  *
4  * $Id$
5  *
6  * Ethereal - Network traffic analyzer
7  * By Gerald Combs <gerald@ethereal.com>
8  * Copyright 1998 Gerald Combs
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
23  */
24
25 #ifdef HAVE_CONFIG_H
26 # include "config.h"
27 #endif
28
29 #include <stdio.h>
30 #include <string.h>
31 #include <ctype.h>
32 #include <errno.h>
33
34 #ifdef HAVE_UNISTD_H
35 #include <unistd.h>
36 #endif
37
38 #include <glib.h>
39
40 #include <epan/filesystem.h>
41
42 #include "filters.h"
43
44 /*
45  * Old filter file name.
46  */
47 #define FILTER_FILE_NAME        "filters"
48
49 /*
50  * Capture filter file name.
51  */
52 #define CFILTER_FILE_NAME       "cfilters"
53
54 /*
55  * Display filter file name.
56  */
57 #define DFILTER_FILE_NAME       "dfilters"
58
59 /*
60  * List of capture filters.
61  */
62 static GList *capture_filters = NULL;
63
64 /*
65  * List of display filters.
66  */
67 static GList *display_filters = NULL;
68
69 /*
70  * Read in a list of filters.
71  *
72  * On success, "*pref_path_return" is set to NULL.
73  * On error, "*pref_path_return" is set to point to the pathname of
74  * the file we tried to read - it should be freed by our caller -
75  * and "*errno_return" is set to the error.
76  */
77
78 #define INIT_BUF_SIZE   128
79
80 void
81 read_filter_list(filter_list_type_t list, char **pref_path_return,
82     int *errno_return)
83 {
84   char       *ff_path, *ff_name;
85   FILE       *ff;
86   GList      **flp;
87   GList      *fl_ent;
88   filter_def *filt;
89   int         c;
90   char       *filt_name, *filt_expr;
91   int         filt_name_len, filt_expr_len;
92   int         filt_name_index, filt_expr_index;
93   int         line = 1;
94
95   *pref_path_return = NULL;     /* assume no error */
96
97   switch (list) {
98
99   case CFILTER_LIST:
100     ff_name = CFILTER_FILE_NAME;
101     flp = &capture_filters;
102     break;
103
104   case DFILTER_LIST:
105     ff_name = DFILTER_FILE_NAME;
106     flp = &display_filters;
107     break;
108
109   default:
110     g_assert_not_reached();
111     return;
112   }
113
114   /* try to open personal "cfilters"/"dfilters" file */
115   ff_path = get_persconffile_path(ff_name, FALSE);
116   if ((ff = fopen(ff_path, "r")) == NULL) {
117     /*
118      * Did that fail because the file didn't exist?
119      */
120     if (errno != ENOENT) {
121       /*
122        * No.  Just give up.
123        */
124       *pref_path_return = ff_path;
125       *errno_return = errno;
126       return;
127     }
128
129     /*
130      * Yes.  See if there's an "old style" personal "filters" file; if so, read it.
131      * This means that a user will start out with their capture and
132      * display filter lists being identical; each list may contain
133      * filters that don't belong in that list.  The user can edit
134      * the filter lists, and delete the ones that don't belong in
135      * a particular list.
136      */
137     g_free(ff_path);
138     ff_path = get_persconffile_path(FILTER_FILE_NAME, FALSE);
139     if ((ff = fopen(ff_path, "r")) == NULL) {
140     /*
141      * Did that fail because the file didn't exist?
142      */
143       if (errno != ENOENT) {
144       /*
145        * No.  Just give up.
146        */
147         *pref_path_return = ff_path;
148         *errno_return = errno;
149     return;
150       }
151
152     /*
153      * Try to open the global "cfilters/dfilters" file */
154     ff_path = get_datafile_path(ff_name);
155     if ((ff = fopen(ff_path, "r")) == NULL) {
156
157       /*
158        * Well, that didn't work, either.  Just give up.
159        * Return an error if the file existed but we couldn't open it.
160        */
161       if (errno != ENOENT) {
162         *pref_path_return = ff_path;
163         *errno_return = errno;
164     }
165     return;
166     }
167     }
168   }
169
170   /* If we already have a list of filters, discard it. */
171   if (*flp != NULL) {
172     fl_ent = g_list_first(*flp);
173     while (fl_ent != NULL) {
174       filt = (filter_def *) fl_ent->data;
175       g_free(filt->name);
176       g_free(filt->strval);
177       g_free(filt);
178       fl_ent = fl_ent->next;
179     }
180     g_list_free(*flp);
181     *flp = NULL;
182   }
183
184   /* Allocate the filter name buffer. */
185   filt_name_len = INIT_BUF_SIZE;
186   filt_name = g_malloc(filt_name_len + 1);
187   filt_expr_len = INIT_BUF_SIZE;
188   filt_expr = g_malloc(filt_expr_len + 1);
189
190   for (line = 1; ; line++) {
191     /* Lines in a filter file are of the form
192
193         "name" expression
194
195        where "name" is a name, in quotes - backslashes in the name
196        escape the next character, so quotes and backslashes can appear
197        in the name - and "expression" is a filter expression, not in
198        quotes, running to the end of the line. */
199
200     /* Skip over leading white space, if any. */
201     while ((c = getc(ff)) != EOF && isspace(c)) {
202       if (c == '\n') {
203         /* Blank line. */
204         continue;
205       }
206     }
207
208     if (c == EOF)
209       break;    /* Nothing more to read */
210
211     /* "c" is the first non-white-space character.
212        If it's not a quote, it's an error. */
213     if (c != '"') {
214       g_warning("'%s' line %d doesn't have a quoted filter name.", ff_path,
215                 line);
216       while (c != '\n')
217         c = getc(ff);   /* skip to the end of the line */
218       continue;
219     }
220
221     /* Get the name of the filter. */
222     filt_name_index = 0;
223     for (;;) {
224       c = getc(ff);
225       if (c == EOF || c == '\n')
226         break;  /* End of line - or end of file */
227       if (c == '"') {
228         /* Closing quote. */
229         if (filt_name_index >= filt_name_len) {
230           /* Filter name buffer isn't long enough; double its length. */
231           filt_name_len *= 2;
232           filt_name = g_realloc(filt_name, filt_name_len + 1);
233         }
234         filt_name[filt_name_index] = '\0';
235         break;
236       }
237       if (c == '\\') {
238         /* Next character is escaped */
239         c = getc(ff);
240         if (c == EOF || c == '\n')
241           break;        /* End of line - or end of file */
242       }
243       /* Add this character to the filter name string. */
244       if (filt_name_index >= filt_name_len) {
245         /* Filter name buffer isn't long enough; double its length. */
246         filt_name_len *= 2;
247         filt_name = g_realloc(filt_name, filt_name_len + 1);
248       }
249       filt_name[filt_name_index] = c;
250       filt_name_index++;
251     }
252
253     if (c == EOF) {
254       if (!ferror(ff)) {
255         /* EOF, not error; no newline seen before EOF */
256         g_warning("'%s' line %d doesn't have a newline.", ff_path,
257                   line);
258       }
259       break;    /* nothing more to read */
260     }
261
262     if (c != '"') {
263       /* No newline seen before end-of-line */
264       g_warning("'%s' line %d doesn't have a closing quote.", ff_path,
265                 line);
266       continue;
267     }
268
269     /* Skip over separating white space, if any. */
270     while ((c = getc(ff)) != EOF && isspace(c)) {
271       if (c == '\n')
272         break;
273     }
274
275     if (c == EOF) {
276       if (!ferror(ff)) {
277         /* EOF, not error; no newline seen before EOF */
278         g_warning("'%s' line %d doesn't have a newline.", ff_path,
279                   line);
280       }
281       break;    /* nothing more to read */
282     }
283
284     if (c == '\n') {
285       /* No filter expression */
286       g_warning("'%s' line %d doesn't have a filter expression.", ff_path,
287                 line);
288       continue;
289     }
290
291     /* "c" is the first non-white-space character; it's the first
292        character of the filter expression. */
293     filt_expr_index = 0;
294     for (;;) {
295       /* Add this character to the filter expression string. */
296       if (filt_expr_index >= filt_expr_len) {
297         /* Filter expressioin buffer isn't long enough; double its length. */
298         filt_expr_len *= 2;
299         filt_expr = g_realloc(filt_expr, filt_expr_len + 1);
300       }
301       filt_expr[filt_expr_index] = c;
302       filt_expr_index++;
303
304       /* Get the next character. */
305       c = getc(ff);
306       if (c == EOF || c == '\n')
307         break;
308     }
309
310     if (c == EOF) {
311       if (!ferror(ff)) {
312         /* EOF, not error; no newline seen before EOF */
313         g_warning("'%s' line %d doesn't have a newline.", ff_path,
314                   line);
315       }
316       break;    /* nothing more to read */
317     }
318
319     /* We saw the ending newline; terminate the filter expression string */
320     if (filt_expr_index >= filt_expr_len) {
321       /* Filter expressioin buffer isn't long enough; double its length. */
322       filt_expr_len *= 2;
323       filt_expr = g_realloc(filt_expr, filt_expr_len + 1);
324     }
325     filt_expr[filt_expr_index] = '\0';
326
327     /* Add the new filter to the list of filters */
328     filt         = (filter_def *) g_malloc(sizeof(filter_def));
329     filt->name   = g_strdup(filt_name);
330     filt->strval = g_strdup(filt_expr);
331     *flp = g_list_append(*flp, filt);
332   }
333   if (ferror(ff)) {
334     *pref_path_return = ff_path;
335     *errno_return = errno;
336   } else
337     g_free(ff_path);
338   fclose(ff);
339   g_free(filt_name);
340   g_free(filt_expr);
341 }
342
343 /*
344  * Get a pointer to a list of filters.
345  */
346 static GList **
347 get_filter_list(filter_list_type_t list)
348 {
349   GList **flp;
350
351   switch (list) {
352
353   case CFILTER_LIST:
354     flp = &capture_filters;
355     break;
356
357   case DFILTER_LIST:
358     flp = &display_filters;
359     break;
360
361   default:
362     g_assert_not_reached();
363     flp = NULL;
364   }
365   return flp;
366 }
367
368 /*
369  * Get a pointer to the first entry in a filter list.
370  */
371 GList *
372 get_filter_list_first(filter_list_type_t list)
373 {
374   GList      **flp;
375
376   flp = get_filter_list(list);
377   return g_list_first(*flp);
378 }
379
380 /*
381  * Add a new filter to the end of a list.
382  * Returns a pointer to the newly-added entry.
383  */
384 GList *
385 add_to_filter_list(filter_list_type_t list, const char *name,
386     const char *expression)
387 {
388   GList      **flp;
389   filter_def *filt;
390
391   flp = get_filter_list(list);
392   filt = (filter_def *) g_malloc(sizeof(filter_def));
393   filt->name = g_strdup(name);
394   filt->strval = g_strdup(expression);
395   *flp = g_list_append(*flp, filt);
396   return g_list_last(*flp);
397 }
398
399 /*
400  * Remove a filter from a list.
401  */
402 void
403 remove_from_filter_list(filter_list_type_t list, GList *fl_entry)
404 {
405   GList      **flp;
406   filter_def *filt;
407
408   flp = get_filter_list(list);
409   filt = (filter_def *) fl_entry->data;
410   g_free(filt->name);
411   g_free(filt->strval);
412   g_free(filt);
413   *flp = g_list_remove_link(*flp, fl_entry);
414 }
415
416 /*
417  * Write out a list of filters.
418  *
419  * On success, "*pref_path_return" is set to NULL.
420  * On error, "*pref_path_return" is set to point to the pathname of
421  * the file we tried to read - it should be freed by our caller -
422  * and "*errno_return" is set to the error.
423  */
424 void
425 save_filter_list(filter_list_type_t list, char **pref_path_return,
426     int *errno_return)
427 {
428   gchar      *ff_path, *ff_path_new, *ff_name;
429   GList      *fl;
430   GList      *flp;
431   filter_def *filt;
432   FILE       *ff;
433   guchar     *p, c;
434
435   *pref_path_return = NULL;     /* assume no error */
436
437   switch (list) {
438
439   case CFILTER_LIST:
440     ff_name = CFILTER_FILE_NAME;
441     fl = capture_filters;
442     break;
443
444   case DFILTER_LIST:
445     ff_name = DFILTER_FILE_NAME;
446     fl = display_filters;
447     break;
448
449   default:
450     g_assert_not_reached();
451     return;
452   }
453
454   ff_path = get_persconffile_path(ff_name, TRUE);
455
456   /* Write to "XXX.new", and rename if that succeeds.
457      That means we don't trash the file if we fail to write it out
458      completely. */
459   ff_path_new = (gchar *) g_malloc(strlen(ff_path) + 5);
460   sprintf(ff_path_new, "%s.new", ff_path);
461
462   if ((ff = fopen(ff_path_new, "w")) == NULL) {
463     *pref_path_return = ff_path;
464     *errno_return = errno;
465     g_free(ff_path_new);
466     return;
467   }
468   flp = g_list_first(fl);
469   while (flp) {
470     filt = (filter_def *) flp->data;
471
472     /* Write out the filter name as a quoted string; escape any quotes
473        or backslashes. */
474     putc('"', ff);
475     for (p = (guchar *)filt->name; (c = *p) != '\0'; p++) {
476       if (c == '"' || c == '\\')
477         putc('\\', ff);
478       putc(c, ff);
479     }
480     putc('"', ff);
481
482     /* Separate the filter name and value with a space. */
483     putc(' ', ff);
484
485     /* Write out the filter expression and a newline. */
486     fprintf(ff, "%s\n", filt->strval);
487     if (ferror(ff)) {
488       *pref_path_return = ff_path;
489       *errno_return = errno;
490       fclose(ff);
491       unlink(ff_path_new);
492       g_free(ff_path_new);
493       return;
494     }
495     flp = flp->next;
496   }
497   if (fclose(ff) == EOF) {
498     *pref_path_return = ff_path;
499     *errno_return = errno;
500     unlink(ff_path_new);
501     g_free(ff_path_new);
502     return;
503   }
504
505 #ifdef _WIN32
506   /* ANSI C doesn't say whether "rename()" removes the target if it
507      exists; the Win32 call to rename files doesn't do so, which I
508      infer is the reason why the MSVC++ "rename()" doesn't do so.
509      We must therefore remove the target file first, on Windows. */
510   if (remove(ff_path) < 0 && errno != ENOENT) {
511     /* It failed for some reason other than "it's not there"; if
512        it's not there, we don't need to remove it, so we just
513        drive on. */
514     *pref_path_return = ff_path;
515     *errno_return = errno;
516     unlink(ff_path_new);
517     g_free(ff_path_new);
518     return;
519   }
520 #endif
521
522   if (rename(ff_path_new, ff_path) < 0) {
523     *pref_path_return = ff_path;
524     *errno_return = errno;
525     unlink(ff_path_new);
526     g_free(ff_path_new);
527     return;
528   }
529   g_free(ff_path_new);
530   g_free(ff_path);
531 }