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