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