Also allow the user to edit the capture-file comment if there is one (not
[metze/wireshark/wip.git] / filters.c
1 /* filters.c
2  * Code for reading and writing the filters file.
3  *
4  * $Id$
5  *
6  * Wireshark - Network traffic analyzer
7  * By Gerald Combs <gerald@wireshark.org>
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 #include <wsutil/file_util.h>
44
45 /*
46  * Old filter file name.
47  */
48 #define FILTER_FILE_NAME        "filters"
49
50 /*
51  * Capture filter file name.
52  */
53 #define CFILTER_FILE_NAME       "cfilters"
54
55 /*
56  * Display filter file name.
57  */
58 #define DFILTER_FILE_NAME       "dfilters"
59
60 /*
61  * List of capture filters - saved.
62  */
63 static GList *capture_filters = NULL;
64
65 /*
66  * List of display filters - saved.
67  */
68 static GList *display_filters = NULL;
69
70 /*
71  * List of capture filters - currently edited.
72  */
73 static GList *capture_edited_filters = NULL;
74
75 /*
76  * List of display filters - currently edited.
77  */
78 static GList *display_edited_filters = NULL;
79
80 /*
81  * Read in a list of filters.
82  *
83  * On success, "*pref_path_return" is set to NULL.
84  * On error, "*pref_path_return" is set to point to the pathname of
85  * the file we tried to read - it should be freed by our caller -
86  * and "*errno_return" is set to the error.
87  */
88
89 #define INIT_BUF_SIZE   128
90
91 static GList *
92 add_filter_entry(GList *fl, const char *filt_name, const char *filt_expr)
93 {
94     filter_def *filt;
95
96     filt         = (filter_def *) g_malloc(sizeof(filter_def));
97     filt->name   = g_strdup(filt_name);
98     filt->strval = g_strdup(filt_expr);
99     return g_list_append(fl, filt);
100 }
101
102 static GList *
103 remove_filter_entry(GList *fl, GList *fl_entry)
104 {
105   filter_def *filt;
106
107   filt = (filter_def *) fl_entry->data;
108   g_free(filt->name);
109   g_free(filt->strval);
110   g_free(filt);
111   return g_list_remove_link(fl, fl_entry);
112 }
113
114 void
115 read_filter_list(filter_list_type_t list_type, char **pref_path_return,
116     int *errno_return)
117 {
118   const char *ff_name;
119   char       *ff_path;
120   FILE       *ff;
121   GList      **flpp;
122   int         c;
123   char       *filt_name, *filt_expr;
124   int         filt_name_len, filt_expr_len;
125   int         filt_name_index, filt_expr_index;
126   int         line = 1;
127
128   *pref_path_return = NULL;     /* assume no error */
129
130   switch (list_type) {
131
132   case CFILTER_LIST:
133     ff_name = CFILTER_FILE_NAME;
134     flpp = &capture_filters;
135     break;
136
137   case DFILTER_LIST:
138     ff_name = DFILTER_FILE_NAME;
139     flpp = &display_filters;
140     break;
141
142   default:
143     g_assert_not_reached();
144     return;
145   }
146
147   /* try to open personal "cfilters"/"dfilters" file */
148   ff_path = get_persconffile_path(ff_name, TRUE, FALSE);
149   if ((ff = ws_fopen(ff_path, "r")) == NULL) {
150     /*
151      * Did that fail because the file didn't exist?
152      */
153     if (errno != ENOENT) {
154       /*
155        * No.  Just give up.
156        */
157       *pref_path_return = ff_path;
158       *errno_return = errno;
159       return;
160     }
161
162     /*
163      * Yes.  See if there's an "old style" personal "filters" file; if so, read it.
164      * This means that a user will start out with their capture and
165      * display filter lists being identical; each list may contain
166      * filters that don't belong in that list.  The user can edit
167      * the filter lists, and delete the ones that don't belong in
168      * a particular list.
169      */
170     g_free(ff_path);
171     ff_path = get_persconffile_path(FILTER_FILE_NAME, FALSE, FALSE);
172     if ((ff = ws_fopen(ff_path, "r")) == NULL) {
173       /*
174        * Did that fail because the file didn't exist?
175        */
176         if (errno != ENOENT) {
177         /*
178          * No.  Just give up.
179          */
180           *pref_path_return = ff_path;
181           *errno_return = errno;
182           return;
183         }
184
185       /*
186        * Try to open the global "cfilters/dfilters" file */
187       g_free(ff_path);
188       ff_path = get_datafile_path(ff_name);
189       if ((ff = ws_fopen(ff_path, "r")) == NULL) {
190
191         /*
192          * Well, that didn't work, either.  Just give up.
193          * Return an error if the file existed but we couldn't open it.
194          */
195         if (errno != ENOENT) {
196           *pref_path_return = ff_path;
197           *errno_return = errno;
198         } else {
199           g_free(ff_path);
200         }
201         return;
202       }
203     }
204   }
205
206   /* If we already have a list of filters, discard it. */
207   /* this should never happen - this function is called only once for each list! */
208   while(*flpp) {
209     *flpp = remove_filter_entry(*flpp, g_list_first(*flpp));
210   }
211
212   /* Allocate the filter name buffer. */
213   filt_name_len = INIT_BUF_SIZE;
214   filt_name = (char *)g_malloc(filt_name_len + 1);
215   filt_expr_len = INIT_BUF_SIZE;
216   filt_expr = (char *)g_malloc(filt_expr_len + 1);
217
218   for (line = 1; ; line++) {
219     /* Lines in a filter file are of the form
220
221         "name" expression
222
223        where "name" is a name, in quotes - backslashes in the name
224        escape the next character, so quotes and backslashes can appear
225        in the name - and "expression" is a filter expression, not in
226        quotes, running to the end of the line. */
227
228     /* Skip over leading white space, if any. */
229     while ((c = getc(ff)) != EOF && isspace(c)) {
230       if (c == '\n') {
231         /* Blank line. */
232         continue;
233       }
234     }
235
236     if (c == EOF)
237       break;    /* Nothing more to read */
238
239     /* "c" is the first non-white-space character.
240        If it's not a quote, it's an error. */
241     if (c != '"') {
242       g_warning("'%s' line %d doesn't have a quoted filter name.", ff_path,
243                 line);
244       while (c != '\n')
245         c = getc(ff);   /* skip to the end of the line */
246       continue;
247     }
248
249     /* Get the name of the filter. */
250     filt_name_index = 0;
251     for (;;) {
252       c = getc(ff);
253       if (c == EOF || c == '\n')
254         break;  /* End of line - or end of file */
255       if (c == '"') {
256         /* Closing quote. */
257         if (filt_name_index >= filt_name_len) {
258           /* Filter name buffer isn't long enough; double its length. */
259           filt_name_len *= 2;
260           filt_name = (char *)g_realloc(filt_name, filt_name_len + 1);
261         }
262         filt_name[filt_name_index] = '\0';
263         break;
264       }
265       if (c == '\\') {
266         /* Next character is escaped */
267         c = getc(ff);
268         if (c == EOF || c == '\n')
269           break;        /* End of line - or end of file */
270       }
271       /* Add this character to the filter name string. */
272       if (filt_name_index >= filt_name_len) {
273         /* Filter name buffer isn't long enough; double its length. */
274         filt_name_len *= 2;
275         filt_name = (char *)g_realloc(filt_name, filt_name_len + 1);
276       }
277       filt_name[filt_name_index] = c;
278       filt_name_index++;
279     }
280
281     if (c == EOF) {
282       if (!ferror(ff)) {
283         /* EOF, not error; no newline seen before EOF */
284         g_warning("'%s' line %d doesn't have a newline.", ff_path,
285                   line);
286       }
287       break;    /* nothing more to read */
288     }
289
290     if (c != '"') {
291       /* No newline seen before end-of-line */
292       g_warning("'%s' line %d doesn't have a closing quote.", ff_path,
293                 line);
294       continue;
295     }
296
297     /* Skip over separating white space, if any. */
298     while ((c = getc(ff)) != EOF && isspace(c)) {
299       if (c == '\n')
300         break;
301     }
302
303     if (c == EOF) {
304       if (!ferror(ff)) {
305         /* EOF, not error; no newline seen before EOF */
306         g_warning("'%s' line %d doesn't have a newline.", ff_path,
307                   line);
308       }
309       break;    /* nothing more to read */
310     }
311
312     if (c == '\n') {
313       /* No filter expression */
314       g_warning("'%s' line %d doesn't have a filter expression.", ff_path,
315                 line);
316       continue;
317     }
318
319     /* "c" is the first non-white-space character; it's the first
320        character of the filter expression. */
321     filt_expr_index = 0;
322     for (;;) {
323       /* Add this character to the filter expression string. */
324       if (filt_expr_index >= filt_expr_len) {
325         /* Filter expressioin buffer isn't long enough; double its length. */
326         filt_expr_len *= 2;
327         filt_expr = (char *)g_realloc(filt_expr, filt_expr_len + 1);
328       }
329       filt_expr[filt_expr_index] = c;
330       filt_expr_index++;
331
332       /* Get the next character. */
333       c = getc(ff);
334       if (c == EOF || c == '\n')
335         break;
336     }
337
338     if (c == EOF) {
339       if (!ferror(ff)) {
340         /* EOF, not error; no newline seen before EOF */
341         g_warning("'%s' line %d doesn't have a newline.", ff_path,
342                   line);
343       }
344       break;    /* nothing more to read */
345     }
346
347     /* We saw the ending newline; terminate the filter expression string */
348     if (filt_expr_index >= filt_expr_len) {
349       /* Filter expressioin buffer isn't long enough; double its length. */
350       filt_expr_len *= 2;
351       filt_expr = (char *)g_realloc(filt_expr, filt_expr_len + 1);
352     }
353     filt_expr[filt_expr_index] = '\0';
354
355     /* Add the new filter to the list of filters */
356     *flpp = add_filter_entry(*flpp, filt_name, filt_expr);
357   }
358   if (ferror(ff)) {
359     *pref_path_return = ff_path;
360     *errno_return = errno;
361   } else
362     g_free(ff_path);
363   fclose(ff);
364   g_free(filt_name);
365   g_free(filt_expr);
366
367   /* init the corresponding edited list */
368   switch (list_type) {
369   case CFILTER_LIST:
370     copy_filter_list(CFILTER_EDITED_LIST, CFILTER_LIST);
371     break;
372   case DFILTER_LIST:
373     copy_filter_list(DFILTER_EDITED_LIST, DFILTER_LIST);
374     break;
375   default:
376     g_assert_not_reached();
377     return;
378   }
379 }
380
381 /*
382  * Get a pointer to a list of filters.
383  */
384 static GList **
385 get_filter_list(filter_list_type_t list_type)
386 {
387   GList **flpp;
388
389   switch (list_type) {
390
391   case CFILTER_LIST:
392     flpp = &capture_filters;
393     break;
394
395   case DFILTER_LIST:
396     flpp = &display_filters;
397     break;
398
399   case CFILTER_EDITED_LIST:
400     flpp = &capture_edited_filters;
401     break;
402
403   case DFILTER_EDITED_LIST:
404     flpp = &display_edited_filters;
405     break;
406
407   default:
408     g_assert_not_reached();
409     flpp = NULL;
410   }
411   return flpp;
412 }
413
414 /*
415  * Get a pointer to the first entry in a filter list.
416  */
417 GList *
418 get_filter_list_first(filter_list_type_t list_type)
419 {
420   GList      **flpp;
421
422   flpp = get_filter_list(list_type);
423   return g_list_first(*flpp);
424 }
425
426 /*
427  * Add a new filter to the end of a list.
428  * Returns a pointer to the newly-added entry.
429  */
430 GList *
431 add_to_filter_list(filter_list_type_t list_type, const char *name,
432     const char *expression)
433 {
434   GList      **flpp;
435
436   flpp = get_filter_list(list_type);
437   *flpp = add_filter_entry(*flpp, name, expression);
438
439   return g_list_last(*flpp);
440 }
441
442 /*
443  * Remove a filter from a list.
444  */
445 void
446 remove_from_filter_list(filter_list_type_t list_type, GList *fl_entry)
447 {
448   GList      **flpp;
449
450   flpp = get_filter_list(list_type);
451   *flpp = remove_filter_entry(*flpp, fl_entry);
452 }
453
454 /*
455  * Write out a list of filters.
456  *
457  * On success, "*pref_path_return" is set to NULL.
458  * On error, "*pref_path_return" is set to point to the pathname of
459  * the file we tried to read - it should be freed by our caller -
460  * and "*errno_return" is set to the error.
461  */
462 void
463 save_filter_list(filter_list_type_t list_type, char **pref_path_return,
464     int *errno_return)
465 {
466   const gchar *ff_name;
467   gchar      *ff_path, *ff_path_new;
468   GList      *fl;
469   GList      *flpp;
470   filter_def *filt;
471   FILE       *ff;
472   guchar     *p, c;
473
474   *pref_path_return = NULL;     /* assume no error */
475
476   switch (list_type) {
477
478   case CFILTER_LIST:
479     ff_name = CFILTER_FILE_NAME;
480     fl = capture_filters;
481     break;
482
483   case DFILTER_LIST:
484     ff_name = DFILTER_FILE_NAME;
485     fl = display_filters;
486     break;
487
488   default:
489     g_assert_not_reached();
490     return;
491   }
492
493   ff_path = get_persconffile_path(ff_name, TRUE, TRUE);
494
495   /* Write to "XXX.new", and rename if that succeeds.
496      That means we don't trash the file if we fail to write it out
497      completely. */
498   ff_path_new = g_strdup_printf("%s.new", ff_path);
499
500   if ((ff = ws_fopen(ff_path_new, "w")) == NULL) {
501     *pref_path_return = ff_path;
502     *errno_return = errno;
503     g_free(ff_path_new);
504     return;
505   }
506   flpp = g_list_first(fl);
507   while (flpp) {
508     filt = (filter_def *) flpp->data;
509
510     /* Write out the filter name as a quoted string; escape any quotes
511        or backslashes. */
512     putc('"', ff);
513     for (p = (guchar *)filt->name; (c = *p) != '\0'; p++) {
514       if (c == '"' || c == '\\')
515         putc('\\', ff);
516       putc(c, ff);
517     }
518     putc('"', ff);
519
520     /* Separate the filter name and value with a space. */
521     putc(' ', ff);
522
523     /* Write out the filter expression and a newline. */
524     fprintf(ff, "%s\n", filt->strval);
525     if (ferror(ff)) {
526       *pref_path_return = ff_path;
527       *errno_return = errno;
528       fclose(ff);
529       ws_unlink(ff_path_new);
530       g_free(ff_path_new);
531       return;
532     }
533     flpp = flpp->next;
534   }
535   if (fclose(ff) == EOF) {
536     *pref_path_return = ff_path;
537     *errno_return = errno;
538     ws_unlink(ff_path_new);
539     g_free(ff_path_new);
540     return;
541   }
542
543 #ifdef _WIN32
544   /* ANSI C doesn't say whether "rename()" removes the target if it
545      exists; the Win32 call to rename files doesn't do so, which I
546      infer is the reason why the MSVC++ "rename()" doesn't do so.
547      We must therefore remove the target file first, on Windows.
548
549      XXX - ws_rename() should be ws_stdio_rename() on Windows,
550      and ws_stdio_rename() uses MoveFileEx() with MOVEFILE_REPLACE_EXISTING,
551      so it should remove the target if it exists, so this stuff
552      shouldn't be necessary.  Perhaps it dates back to when we were
553      calling rename(), with that being a wrapper around Microsoft's
554      _rename(), which didn't remove the target. */
555   if (ws_remove(ff_path) < 0 && errno != ENOENT) {
556     /* It failed for some reason other than "it's not there"; if
557        it's not there, we don't need to remove it, so we just
558        drive on. */
559     *pref_path_return = ff_path;
560     *errno_return = errno;
561     ws_unlink(ff_path_new);
562     g_free(ff_path_new);
563     return;
564   }
565 #endif
566
567   if (ws_rename(ff_path_new, ff_path) < 0) {
568     *pref_path_return = ff_path;
569     *errno_return = errno;
570     ws_unlink(ff_path_new);
571     g_free(ff_path_new);
572     return;
573   }
574   g_free(ff_path_new);
575   g_free(ff_path);
576 }
577
578 /*
579  * Copy a filter list into another.
580  */
581 void copy_filter_list(filter_list_type_t dest_type, filter_list_type_t src_type)
582 {
583     GList      **flpp_dest;
584     GList      **flpp_src;
585     GList      *flp_src;
586     filter_def *filt;
587
588     g_assert(dest_type != src_type);
589
590     flpp_dest = get_filter_list(dest_type);
591     flpp_src = get_filter_list(src_type);
592     /* throw away the "old" destination list - a NULL list is ok here */
593     while(*flpp_dest) {
594         *flpp_dest = remove_filter_entry(*flpp_dest, g_list_first(*flpp_dest));
595     }
596     g_assert(g_list_length(*flpp_dest) == 0);
597
598     /* copy the list entries */
599     for(flp_src = g_list_first(*flpp_src); flp_src; flp_src = g_list_next(flp_src)) {
600         filt = (filter_def *)(flp_src->data);
601
602         *flpp_dest = add_filter_entry(*flpp_dest, filt->name, filt->strval);
603     }
604 }
605