Have "dissect_netbios_payload()" take as an argument a tvbuff containing
[obnox/wireshark/wip.git] / filters.c
1 /* filters.c
2  * Code for reading and writing the filters file.
3  *
4  * $Id: filters.c,v 1.9 2001/04/02 09:53:42 guy Exp $
5  *
6  * Ethereal - Network traffic analyzer
7  * By Gerald Combs <gerald@zing.org>
8  * Copyright 1998 Gerald Combs
9  *
10  * 
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  * 
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  * 
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24  */
25
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #include <stdio.h>
31 #include <string.h>
32 #include <ctype.h>
33 #include <errno.h>
34
35 #ifdef HAVE_SYS_STAT_H
36 #include <sys/stat.h>
37 #endif
38
39 #ifdef HAVE_UNISTD_H
40 #include <unistd.h>
41 #endif
42
43 #ifdef HAVE_DIRECT_H
44 #include <direct.h>             /* to declare "mkdir()" on Windows */
45 #endif
46
47 #include <glib.h>
48
49 #include <epan.h>
50 #include <filesystem.h>
51
52 #include "filters.h"
53
54 /*
55  * Old filter file name.
56  */
57 #define FILTER_FILE_NAME        "filters"
58
59 /*
60  * Capture filter file name.
61  */
62 #define CFILTER_FILE_NAME       "cfilters"
63
64 /*
65  * Display filter file name.
66  */
67 #define DFILTER_FILE_NAME       "dfilters"
68
69 /*
70  * List of capture filters.
71  */
72 static GList *capture_filters = NULL;
73
74 /*
75  * List of display filters.
76  */
77 static GList *display_filters = NULL;
78
79 /*
80  * Read in a list of filters.
81  *
82  * On success, "*pref_path_return" is set to NULL.
83  * On error, "*pref_path_return" is set to point to the pathname of
84  * the file we tried to read - it should be freed by our caller -
85  * and "*errno_return" is set to the error.
86  */
87
88 #define INIT_BUF_SIZE   128
89
90 void
91 read_filter_list(filter_list_type_t list, char **pref_path_return,
92     int *errno_return)
93 {
94   char       *ff_path, *ff_dir = PF_DIR, *ff_name;
95   FILE       *ff;
96   GList      **flp;
97   GList      *fl_ent;
98   filter_def *filt;
99   int         c;
100   char       *filt_name, *filt_expr;
101   int         filt_name_len, filt_expr_len;
102   int         filt_name_index, filt_expr_index;
103   int         line = 1;
104
105   *pref_path_return = NULL;     /* assume no error */
106
107   switch (list) {
108
109   case CFILTER_LIST:
110     ff_name = CFILTER_FILE_NAME;
111     flp = &capture_filters;
112     break;
113
114   case DFILTER_LIST:
115     ff_name = DFILTER_FILE_NAME;
116     flp = &display_filters;
117     break;
118
119   default:
120     g_assert_not_reached();
121     return;
122   }
123
124   /* To do: generalize this */
125   ff_path = (gchar *) g_malloc(strlen(get_home_dir()) + strlen(ff_dir) +  
126     strlen(ff_name) + 4);
127   sprintf(ff_path, "%s/%s/%s", get_home_dir(), ff_dir, ff_name);
128
129   if ((ff = fopen(ff_path, "r")) == NULL) {
130     /*
131      * Did that fail because we the file didn't exist?
132      */
133     if (errno != ENOENT) {
134       /*
135        * No.  Just give up.
136        */
137       *pref_path_return = ff_path;
138       *errno_return = errno;
139       return;
140     }
141
142     /*
143      * Yes.  See if there's a "filters" file; if so, read it.
144      * This means that a user will start out with their capture and
145      * display filter lists being identical; each list may contain
146      * filters that don't belong in that list.  The user can edit
147      * the filter lists, and delete the ones that don't belong in
148      * a particular list.
149      */
150     sprintf(ff_path, "%s/%s/%s", get_home_dir(), ff_dir, FILTER_FILE_NAME);
151     if ((ff = fopen(ff_path, "r")) == NULL) {
152       /*
153        * Well, that didn't work, either.  Just give up.
154        * Return an error if the file existed but we couldn't open it.
155        */
156       if (errno != ENOENT) {
157         *pref_path_return = ff_path;
158         *errno_return = errno;
159       }
160       return;
161     }
162   }
163
164   /* If we already have a list of filters, discard it. */
165   if (*flp != NULL) {
166     fl_ent = g_list_first(*flp);
167     while (fl_ent != NULL) {
168       filt = (filter_def *) fl_ent->data;
169       g_free(filt->name);
170       g_free(filt->strval);
171       g_free(filt);
172       fl_ent = fl_ent->next;
173     }
174     g_list_free(*flp);
175     *flp = NULL;
176   }
177
178   /* Allocate the filter name buffer. */
179   filt_name_len = INIT_BUF_SIZE;
180   filt_name = g_malloc(filt_name_len + 1);
181   filt_expr_len = INIT_BUF_SIZE;
182   filt_expr = g_malloc(filt_expr_len + 1);
183
184   for (line = 1; ; line++) {
185     /* Lines in a filter file are of the form
186
187         "name" expression
188
189        where "name" is a name, in quotes - backslashes in the name
190        escape the next character, so quotes and backslashes can appear
191        in the name - and "expression" is a filter expression, not in
192        quotes, running to the end of the line. */
193
194     /* Skip over leading white space, if any. */
195     while ((c = getc(ff)) != EOF && isspace(c)) {
196       if (c == '\n') {
197         /* Blank line. */
198         continue;
199       }
200     }
201
202     if (c == EOF)
203       break;    /* Nothing more to read */
204
205     /* "c" is the first non-white-space character.
206        If it's not a quote, it's an error. */
207     if (c != '"') {
208       g_warning("'%s' line %d doesn't have a quoted filter name.", ff_path,
209                 line);
210       while (c != '\n')
211         c = getc(ff);   /* skip to the end of the line */
212       continue;
213     }
214
215     /* Get the name of the filter. */
216     filt_name_index = 0;
217     for (;;) {
218       c = getc(ff);
219       if (c == EOF || c == '\n')
220         break;  /* End of line - or end of file */
221       if (c == '"') {
222         /* Closing quote. */
223         if (filt_name_index >= filt_name_len) {
224           /* Filter name buffer isn't long enough; double its length. */
225           filt_name_len *= 2;
226           filt_name = g_realloc(filt_name, filt_name_len + 1);
227         }
228         filt_name[filt_name_index] = '\0';
229         break;
230       }
231       if (c == '\\') {
232         /* Next character is escaped */
233         c = getc(ff);
234         if (c == EOF || c == '\n')
235           break;        /* End of line - or end of file */
236       }
237       /* Add this character to the filter name string. */
238       if (filt_name_index >= filt_name_len) {
239         /* Filter name buffer isn't long enough; double its length. */
240         filt_name_len *= 2;
241         filt_name = g_realloc(filt_name, filt_name_len + 1);
242       }
243       filt_name[filt_name_index] = c;
244       filt_name_index++;
245     }
246
247     if (c == EOF) {
248       if (!ferror(ff)) {
249         /* EOF, not error; no newline seen before EOF */
250         g_warning("'%s' line %d doesn't have a newline.", ff_path,
251                   line);
252       }
253       break;    /* nothing more to read */
254     }
255
256     if (c != '"') {
257       /* No newline seen before end-of-line */
258       g_warning("'%s' line %d doesn't have a closing quote.", ff_path,
259                 line);
260       continue;
261     }
262           
263     /* Skip over separating white space, if any. */
264     while ((c = getc(ff)) != EOF && isspace(c)) {
265       if (c == '\n')
266         break;
267     }
268
269     if (c == EOF) {
270       if (!ferror(ff)) {
271         /* EOF, not error; no newline seen before EOF */
272         g_warning("'%s' line %d doesn't have a newline.", ff_path,
273                   line);
274       }
275       break;    /* nothing more to read */
276     }
277
278     if (c == '\n') {
279       /* No filter expression */
280       g_warning("'%s' line %d doesn't have a filter expression.", ff_path,
281                 line);
282       continue;
283     }
284
285     /* "c" is the first non-white-space character; it's the first
286        character of the filter expression. */
287     filt_expr_index = 0;
288     for (;;) {
289       /* Add this character to the filter expression string. */
290       if (filt_expr_index >= filt_expr_len) {
291         /* Filter expressioin buffer isn't long enough; double its length. */
292         filt_expr_len *= 2;
293         filt_expr = g_realloc(filt_expr, filt_expr_len + 1);
294       }
295       filt_expr[filt_expr_index] = c;
296       filt_expr_index++;
297
298       /* Get the next character. */
299       c = getc(ff);
300       if (c == EOF || c == '\n')
301         break;
302     }
303
304     if (c == EOF) {
305       if (!ferror(ff)) {
306         /* EOF, not error; no newline seen before EOF */
307         g_warning("'%s' line %d doesn't have a newline.", ff_path,
308                   line);
309       }
310       break;    /* nothing more to read */
311     }
312
313     /* We saw the ending newline; terminate the filter expression string */
314     if (filt_expr_index >= filt_expr_len) {
315       /* Filter expressioin buffer isn't long enough; double its length. */
316       filt_expr_len *= 2;
317       filt_expr = g_realloc(filt_expr, filt_expr_len + 1);
318     }
319     filt_expr[filt_expr_index] = '\0';
320
321     /* Add the new filter to the list of filters */
322     filt         = (filter_def *) g_malloc(sizeof(filter_def));
323     filt->name   = g_strdup(filt_name);
324     filt->strval = g_strdup(filt_expr);
325     *flp = g_list_append(*flp, filt);
326   }
327   if (ferror(ff)) {
328     *pref_path_return = ff_path;
329     *errno_return = errno;
330   } else
331     g_free(ff_path);
332   fclose(ff);
333   g_free(filt_name);
334   g_free(filt_expr);
335 }
336
337 /*
338  * Get a pointer to a list of filters.
339  */
340 static GList **
341 get_filter_list(filter_list_type_t list)
342 {
343   GList **flp;
344
345   switch (list) {
346
347   case CFILTER_LIST:
348     flp = &capture_filters;
349     break;
350
351   case DFILTER_LIST:
352     flp = &display_filters;
353     break;
354
355   default:
356     g_assert_not_reached();
357     flp = NULL;
358   }
359   return flp;
360 }
361
362 /*
363  * Get a pointer to the first entry in a filter list.
364  */
365 GList *
366 get_filter_list_first(filter_list_type_t list)
367 {
368   GList      **flp;
369   
370   flp = get_filter_list(list);
371   return g_list_first(*flp);
372 }
373
374 /*
375  * Add a new filter to the end of a list.
376  * Returns a pointer to the newly-added entry.
377  */
378 GList *
379 add_to_filter_list(filter_list_type_t list, char *name, char *expression)
380 {
381   GList      **flp;
382   filter_def *filt;
383   
384   flp = get_filter_list(list);
385   filt = (filter_def *) g_malloc(sizeof(filter_def));
386   filt->name = g_strdup(name);
387   filt->strval = g_strdup(expression);
388   *flp = g_list_append(*flp, filt);
389   return g_list_last(*flp);
390 }
391
392 /*
393  * Remove a filter from a list.
394  */
395 void
396 remove_from_filter_list(filter_list_type_t list, GList *fl_entry)
397 {
398   GList      **flp;
399   filter_def *filt;
400   
401   flp = get_filter_list(list);
402   filt = (filter_def *) fl_entry->data;
403   g_free(filt->name);
404   g_free(filt->strval);
405   g_free(filt);
406   *flp = g_list_remove_link(*flp, fl_entry);
407 }
408
409 /*
410  * Write out a list of filters.
411  *
412  * On success, "*pref_path_return" is set to NULL.
413  * On error, "*pref_path_return" is set to point to the pathname of
414  * the file we tried to read - it should be freed by our caller -
415  * and "*errno_return" is set to the error.
416  */
417 void
418 save_filter_list(filter_list_type_t list, char **pref_path_return,
419     int *errno_return)
420 {
421   gchar      *ff_path, *ff_path_new, *ff_dir = PF_DIR, *ff_name;
422   int         path_length;
423   GList      *fl;
424   GList      *flp;
425   filter_def *filt;
426   FILE       *ff;
427   struct stat s_buf;
428   guchar     *p, c;
429   
430   *pref_path_return = NULL;     /* assume no error */
431
432   switch (list) {
433
434   case CFILTER_LIST:
435     ff_name = CFILTER_FILE_NAME;
436     fl = capture_filters;
437     break;
438
439   case DFILTER_LIST:
440     ff_name = DFILTER_FILE_NAME;
441     fl = display_filters;
442     break;
443
444   default:
445     g_assert_not_reached();
446     return;
447   }
448
449   path_length = strlen(get_home_dir()) + strlen(ff_dir) + strlen(ff_name)
450                 + 4 + 4;
451   ff_path = (gchar *) g_malloc(path_length);
452   sprintf(ff_path, "%s/%s", get_home_dir(), ff_dir);
453
454   if (stat(ff_path, &s_buf) != 0)
455 #ifdef WIN32
456     mkdir(ff_path);
457 #else
458     mkdir(ff_path, 0755);
459 #endif
460     
461   sprintf(ff_path, "%s/%s/%s", get_home_dir(), ff_dir, ff_name);
462
463   /* Write to "XXX.new", and rename if that succeeds.
464      That means we don't trash the file if we fail to write it out
465      completely. */
466   ff_path_new = (gchar *) g_malloc(path_length);
467   sprintf(ff_path_new, "%s/%s/%s.new", get_home_dir(), ff_dir, ff_name);
468
469   if ((ff = fopen(ff_path_new, "w")) == NULL) {
470     *pref_path_return = ff_path;
471     *errno_return = errno;
472     g_free(ff_path_new);
473     return;
474   }
475   flp = g_list_first(fl);
476   while (flp) {
477     filt = (filter_def *) flp->data;
478
479     /* Write out the filter name as a quoted string; escape any quotes
480        or backslashes. */
481     putc('"', ff);
482     for (p = (guchar *)filt->name; (c = *p) != '\0'; p++) {
483       if (c == '"' || c == '\\')
484         putc('\\', ff);
485       putc(c, ff);
486     }
487     putc('"', ff);
488
489     /* Separate the filter name and value with a space. */
490     putc(' ', ff);
491
492     /* Write out the filter expression and a newline. */
493     fprintf(ff, "%s\n", filt->strval);
494     if (ferror(ff)) {
495       *pref_path_return = ff_path;
496       *errno_return = errno;
497       fclose(ff);
498       unlink(ff_path_new);
499       g_free(ff_path_new);
500       return;
501     }
502     flp = flp->next;
503   }
504   if (fclose(ff) == EOF) {
505     *pref_path_return = ff_path;
506     *errno_return = errno;
507     unlink(ff_path_new);
508     g_free(ff_path_new);
509     return;
510   }
511
512 #ifdef WIN32
513   /* ANSI C doesn't say whether "rename()" removes the target if it
514      exists; the Win32 call to rename files doesn't do so, which I
515      infer is the reason why the MSVC++ "rename()" doesn't do so.
516      We must therefore remove the target file first, on Windows. */
517   if (remove(ff_path) < 0 && errno != ENOENT) {
518     /* It failed for some reason other than "it's not there"; if
519        it's not there, we don't need to remove it, so we just
520        drive on. */
521     *pref_path_return = ff_path;
522     *errno_return = errno;
523     unlink(ff_path_new);
524     g_free(ff_path_new);
525     return;
526   }
527 #endif
528
529   if (rename(ff_path_new, ff_path) < 0) {
530     *pref_path_return = ff_path;
531     *errno_return = errno;
532     unlink(ff_path_new);
533     g_free(ff_path_new);
534     return;
535   }
536   g_free(ff_path_new);
537   g_free(ff_path);
538 }