Move the file utility functions from wiretap to libwsutil so that
[obnox/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 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 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 = g_malloc(filt_name_len + 1);
215   filt_expr_len = INIT_BUF_SIZE;
216   filt_expr = 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 = 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 = 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 = 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 = 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   if (ws_remove(ff_path) < 0 && errno != ENOENT) {
549     /* It failed for some reason other than "it's not there"; if
550        it's not there, we don't need to remove it, so we just
551        drive on. */
552     *pref_path_return = ff_path;
553     *errno_return = errno;
554     ws_unlink(ff_path_new);
555     g_free(ff_path_new);
556     return;
557   }
558 #endif
559
560   if (ws_rename(ff_path_new, ff_path) < 0) {
561     *pref_path_return = ff_path;
562     *errno_return = errno;
563     ws_unlink(ff_path_new);
564     g_free(ff_path_new);
565     return;
566   }
567   g_free(ff_path_new);
568   g_free(ff_path);
569 }
570
571 /*
572  * Copy a filter list into another.
573  */
574 void copy_filter_list(filter_list_type_t dest_type, filter_list_type_t src_type)
575 {
576     GList      **flpp_dest;
577     GList      **flpp_src;
578     GList      *flp_src;
579     filter_def *filt;
580
581     g_assert(dest_type != src_type);
582
583     flpp_dest = get_filter_list(dest_type);
584     flpp_src = get_filter_list(src_type);
585     flp_src = *flpp_src;
586
587     /* throw away the "old" destination list - a NULL list is ok here */
588     while(*flpp_dest) {
589         *flpp_dest = remove_filter_entry(*flpp_dest, g_list_first(*flpp_dest));
590     }
591     g_assert(g_list_length(*flpp_dest) == 0);
592
593     /* copy the list entries */
594     while(flp_src) {
595         filt = (flp_src)->data;
596
597         *flpp_dest = add_filter_entry(*flpp_dest, filt->name, filt->strval);
598         flp_src = g_list_next(flp_src);
599     }
600 }
601