Add a pointer to the start frame of each gop in the gog's tree
[obnox/wireshark/wip.git] / color_filters.c
1 /* color_filters.c
2  * Routines for color filters
3  *
4  * $Id$
5  *
6  * Ethereal - Network traffic analyzer
7  * By Gerald Combs <gerald@ethereal.com>
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  * Updated 1 Dec 10 jjm
26  */
27  
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #include <glib.h>
33 #include <ctype.h>
34 #include <string.h>
35
36 #include <epan/filesystem.h>
37
38 #include <epan/packet.h>
39 #include "color.h"
40 #include "color_filters.h"
41 #include "file.h"
42 #include <epan/dfilter/dfilter.h>
43 #include "simple_dialog.h"
44
45 static gboolean read_filters(void);
46 static gboolean read_global_filters(void);
47
48 /* Variables and routines defined in color.h */
49
50 GSList *filter_list = NULL;
51 GSList *removed_filter_list = NULL;
52
53 /* Remove the specified filter from the list of existing color filters,
54  * and add it to the list of removed color filters.
55  * This way, unmarking and marking a packet which matches a now removed
56  * color filter will still be colored correctly as the color filter is
57  * still reachable. */
58 void remove_color_filter(color_filter_t *colorf)
59 {
60         /* Remove colorf from the list of color filters */
61         filter_list = g_slist_remove(filter_list, colorf);
62         /* Add colorf to the list of removed color filters */
63         removed_filter_list = g_slist_prepend(removed_filter_list, colorf);
64 }
65
66 /* delete the specified filter */
67 static void
68 delete_color_filter(color_filter_t *colorf)
69 {
70         if (colorf->filter_name != NULL)
71                 g_free(colorf->filter_name);
72         if (colorf->filter_text != NULL)
73                 g_free(colorf->filter_text);
74         if (colorf->c_colorfilter != NULL)
75                 dfilter_free(colorf->c_colorfilter);
76         g_free(colorf);
77 }
78
79 /* delete the specified filter as an iterator */
80 static void
81 delete_color_filter_it(gpointer filter_arg, gpointer unused _U_)
82 {
83         color_filter_t *colorf = filter_arg;
84         delete_color_filter(colorf);
85 }
86
87 /* delete all the filters */
88 static void
89 delete_all_color_filters (void)
90 {
91         g_slist_foreach(filter_list, delete_color_filter_it, NULL);
92         g_slist_free(filter_list);
93         filter_list = NULL;
94         g_slist_foreach(removed_filter_list, delete_color_filter_it, NULL);
95         g_slist_free(removed_filter_list);
96         removed_filter_list = NULL;
97 }
98
99 /* Initialize the filter structures (reading from file) for general running, including app startup */
100 void
101 colfilter_init(void)
102 {
103         delete_all_color_filters();
104         if (!read_filters())
105                 read_global_filters();
106 }
107
108 /* Create a new filter */
109 color_filter_t *
110 new_color_filter(gchar *name,          /* The name of the filter to create */
111                  gchar *filter_string, /* The string representing the filter */
112                  color_t *bg_color,    /* The background color */
113                  color_t *fg_color)    /* The foreground color */
114 {
115         color_filter_t *colorf;
116
117         colorf = g_malloc(sizeof (color_filter_t));
118         colorf->filter_name = g_strdup(name);
119         colorf->filter_text = g_strdup(filter_string);
120         colorf->bg_color = *bg_color;
121         colorf->fg_color = *fg_color;
122         colorf->c_colorfilter = NULL;
123         colorf->edit_dialog = NULL;
124         colorf->marked = FALSE;
125         filter_list = g_slist_append(filter_list, colorf);
126         return colorf;
127 }
128
129 static void
130 prime_edt(gpointer data, gpointer user_data)
131 {
132         color_filter_t  *colorf = data;
133         epan_dissect_t   *edt = user_data;
134
135         if (colorf->c_colorfilter != NULL)
136                 epan_dissect_prime_dfilter(edt, colorf->c_colorfilter);
137 }
138
139 /* Prime the epan_dissect_t with all the compiler
140  * color filters in 'filter_list'. */
141 void
142 filter_list_prime_edt(epan_dissect_t *edt)
143 {
144         g_slist_foreach(filter_list, prime_edt, edt);
145 }
146
147 /* read filters from the given file */
148
149 /* XXX - Would it make more sense to use GStrings here instead of reallocing
150    our buffers? */
151 static gboolean
152 read_filters_file(FILE *f, gpointer arg)
153 {
154 #define INIT_BUF_SIZE 128
155         gchar  *name = NULL;
156         gchar  *filter_exp = NULL;
157         guint32 name_len = INIT_BUF_SIZE;
158         guint32 filter_exp_len = INIT_BUF_SIZE;
159         guint32 i = 0;
160         gint32  c;
161         guint16 fg_r, fg_g, fg_b, bg_r, bg_g, bg_b;
162         gboolean skip_end_of_line = FALSE;
163
164         name = g_malloc(name_len + 1);
165         filter_exp = g_malloc(filter_exp_len + 1);
166
167         while (1) {
168
169                 if (skip_end_of_line) {
170                         do {
171                                 c = getc(f);
172                         } while (c != EOF && c != '\n');
173                         if (c == EOF)
174                                 break;
175                         skip_end_of_line = FALSE;
176                 }
177
178                 while ((c = getc(f)) != EOF && isspace(c)) {
179                         if (c == '\n') {
180                                 continue;
181                         }
182                 }
183
184                 if (c == EOF)
185                         break;
186
187                 /* skip # comments and invalid lines */
188                 if (c != '@') { 
189                         skip_end_of_line = TRUE;
190                         continue;
191                 }
192
193                 /* we get the @ delimiter.
194                  * Format is:
195                  * @name@filter expression@[background r,g,b][foreground r,g,b]
196                  */
197
198                 /* retrieve name */
199                 i = 0;
200                 while (1) {
201                         c = getc(f);
202                         if (c == EOF || c == '@')
203                                 break;
204                         if (i >= name_len) {
205                                 /* buffer isn't long enough; double its length.*/
206                                 name_len *= 2;
207                                 name = g_realloc(name, name_len + 1);
208                         }
209                         name[i++] = c;            
210                 }
211                 name[i] = '\0';
212
213                 if (c == EOF) {
214                         break;
215                 } else if (i == 0) {
216                         skip_end_of_line = TRUE;
217                         continue;
218                 }
219
220                 /* retrieve filter expression */
221                 i = 0;
222                 while (1) {
223                         c = getc(f);
224                         if (c == EOF || c == '@')
225                                 break;
226                         if (i >= filter_exp_len) {
227                                 /* buffer isn't long enough; double its length.*/
228                                 filter_exp_len *= 2;
229                                 filter_exp = g_realloc(filter_exp, filter_exp_len + 1);
230                         }
231                         filter_exp[i++] = c;
232                 }
233                 filter_exp[i] = '\0';
234
235                 if (c == EOF) {
236                         break;
237                 } else if (i == 0) {
238                         skip_end_of_line = TRUE;
239                         continue;
240                 }
241
242                 /* retrieve background and foreground colors */
243                 if (fscanf(f,"[%hu,%hu,%hu][%hu,%hu,%hu]",
244                         &bg_r, &bg_g, &bg_b, &fg_r, &fg_g, &fg_b) == 6) {
245
246                         /* we got a complete color filter */
247
248                         color_t bg_color, fg_color;
249                         color_filter_t *colorf;
250                         dfilter_t *temp_dfilter;
251
252                         if (!dfilter_compile(filter_exp, &temp_dfilter)) {
253                                 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
254                                 "Could not compile color filter %s from saved filters.\n%s",
255                                               name, dfilter_error_msg);
256                                 skip_end_of_line = TRUE;
257                                 continue;
258                         }
259
260                         if (!initialize_color(&fg_color, fg_r, fg_g, fg_b)) {
261                                 /* oops */
262                                 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
263                                     "Could not allocate foreground color "
264                                     "specified in input file for %s.", name);
265                                 dfilter_free(temp_dfilter);
266                                 skip_end_of_line = TRUE;
267                                 continue;
268                         }
269                         if (!initialize_color(&bg_color, bg_r, bg_g, bg_b)) {
270                                 /* oops */
271                                 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
272                                     "Could not allocate background color "
273                                     "specified in input file for %s.", name);
274                                 dfilter_free(temp_dfilter);
275                                 skip_end_of_line = TRUE;
276                                 continue;
277                         }
278
279                         colorf = new_color_filter(name, filter_exp, &bg_color,
280                             &fg_color);
281                         colorf->c_colorfilter = temp_dfilter;
282
283                         if (arg != NULL)
284                                 color_add_filter_cb (colorf, arg);
285                 }    /* if sscanf */
286
287                 skip_end_of_line = TRUE;
288         }
289
290         g_free(name);
291         g_free(filter_exp);
292         return TRUE;
293 }
294
295 /* read filters from the user's filter file */
296 static gboolean
297 read_filters(void)
298 {
299         gchar *path;
300         FILE *f;
301         gboolean ret;
302
303         /* decide what file to open (from dfilter code) */
304         path = get_persconffile_path("colorfilters", FALSE);
305         if ((f = fopen(path, "r")) == NULL) {
306                 if (errno != ENOENT) {
307                         simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
308                             "Could not open filter file\n\"%s\": %s.", path,
309                             strerror(errno));
310                 }
311                 g_free(path);
312                 return FALSE;
313         }
314         g_free(path);
315         path = NULL;
316
317         ret = read_filters_file(f, NULL);
318         fclose(f);
319         return ret;
320 }
321
322 /* read filters from the filter file */
323 static gboolean
324 read_global_filters(void)
325 {
326         gchar *path;
327         FILE *f;
328         gboolean ret;
329
330         /* decide what file to open (from dfilter code) */
331         path = get_datafile_path("colorfilters");
332         if ((f = fopen(path, "r")) == NULL) {
333                 if (errno != ENOENT) {
334                         simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
335                             "Could not open global filter file\n\"%s\": %s.", path,
336                             strerror(errno));
337                 }
338                 g_free(path);
339                 return FALSE;
340         }
341         g_free(path);
342         path = NULL;
343
344         ret = read_filters_file(f, NULL);
345         fclose(f);
346         return ret;
347 }
348
349 /* read filters from some other filter file (import) */
350 gboolean
351 read_other_filters(gchar *path, gpointer arg)
352 {
353         FILE *f;
354         gboolean ret;
355
356         if ((f = fopen(path, "r")) == NULL) {
357                 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
358                     "Could not open\n%s\nfor reading: %s.",
359                     path, strerror(errno));
360                 return FALSE;
361         }
362
363         ret = read_filters_file(f, arg);
364         fclose(f);
365         return ret;
366 }
367
368 struct write_filter_data
369 {
370   FILE * f;
371   gboolean only_marked;
372 };
373
374 /* save a single filter */
375 static void
376 write_filter(gpointer filter_arg, gpointer data_arg)
377 {
378         struct write_filter_data *data = data_arg;
379         color_filter_t *colorf = filter_arg;
380         FILE *f = data->f;
381
382         if (colorf->marked || !data->only_marked) {
383                 fprintf(f,"@%s@%s@[%d,%d,%d][%d,%d,%d]\n",
384                     colorf->filter_name,
385                     colorf->filter_text,
386                     colorf->bg_color.red,
387                     colorf->bg_color.green,
388                     colorf->bg_color.blue,
389                     colorf->fg_color.red,
390                     colorf->fg_color.green,
391                     colorf->fg_color.blue);
392         }
393 }
394
395 /* save filters in a filter file */
396 gboolean
397 write_filters_file(FILE *f, gboolean only_marked)
398 {
399         struct write_filter_data data;
400
401         data.f = f;
402         data.only_marked = only_marked;
403   
404         fprintf(f,"# DO NOT EDIT THIS FILE!  It was created by Ethereal\n");
405         g_slist_foreach(filter_list, write_filter, &data);
406         return TRUE;
407 }
408
409 /* save filters in users filter file */
410 gboolean
411 write_filters(void)
412 {
413         gchar *pf_dir_path;
414         const gchar *path;
415         FILE *f;
416
417         /* Create the directory that holds personal configuration files,
418            if necessary.  */
419         if (create_persconffile_dir(&pf_dir_path) == -1) {
420                 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
421                     "Can't create directory\n\"%s\"\nfor color files: %s.",
422                     pf_dir_path, strerror(errno));
423                 g_free(pf_dir_path);
424                 return FALSE;
425         }
426
427         path = get_persconffile_path("colorfilters", TRUE);
428         if ((f = fopen(path, "w+")) == NULL) {
429                 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
430                     "Could not open\n%s\nfor writing: %s.",
431                     path, strerror(errno));
432                 return FALSE;
433         }
434         write_filters_file(f, FALSE);
435         fclose(f);
436         return TRUE;
437 }
438
439 /* delete users filter file and reload global filters */
440 gboolean
441 revert_filters(void)
442 {
443         gchar *pf_dir_path;
444         gchar *path;
445
446         /* Create the directory that holds personal configuration files,
447            if necessary.  */
448         if (create_persconffile_dir(&pf_dir_path) == -1) {
449                 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
450                     "Can't create directory\n\"%s\"\nfor color files: %s.",
451                     pf_dir_path, strerror(errno));
452                 g_free(pf_dir_path);
453                 return FALSE;
454         }
455
456         path = get_persconffile_path("colorfilters", TRUE);
457         if (!deletefile(path)) {
458                 g_free(path);
459                 return FALSE;
460         }
461
462         g_free(path);
463
464         /* Reload the (global) filters - Note: this does not update the dialog. */
465         colfilter_init();
466         return TRUE;
467 }
468
469
470 /* save filters in some other filter file (export) */
471 gboolean
472 write_other_filters(gchar *path, gboolean only_marked)
473 {
474         FILE *f;
475
476         if ((f = fopen(path, "w+")) == NULL) {
477                 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
478                     "Could not open\n%s\nfor writing: %s.",
479                     path, strerror(errno));
480                 return FALSE;
481         }
482         write_filters_file(f, only_marked);
483         fclose(f);
484         return TRUE;
485 }