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