[Diameter] Add a couple of command codes from IANA.
[metze/wireshark/wip.git] / extcap_parser.c
1 /* extcap_parser.c
2  *
3  * Routines for extcap external capture
4  * Copyright 2013, Mike Ryan <mikeryan@lacklustre.net>
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 <glib.h>
29 #include <string.h>
30
31 #include "ui/iface_toolbar.h"
32 #include "wsutil/strtoi.h"
33
34 #include "extcap.h"
35 #include "extcap_parser.h"
36
37 void extcap_printf_complex(extcap_complex *comp) {
38     gchar *ret = extcap_get_complex_as_string(comp);
39     printf("%s", ret);
40     g_free(ret);
41 }
42
43 gchar *extcap_get_complex_as_string(extcap_complex *comp) {
44     return (comp ? g_strdup(comp->_val) : NULL);
45 }
46
47 extcap_complex *extcap_parse_complex(extcap_arg_type complex_type,
48                                      const gchar *data) {
49
50     extcap_complex *rc = g_new0(extcap_complex, 1);
51
52     rc->_val = g_strdup(data);
53     rc->complex_type = complex_type;
54
55     return rc;
56 }
57
58 gboolean extcap_compare_is_default(extcap_arg *element, extcap_complex *test) {
59     if (element == NULL || element->default_complex == NULL || test == NULL)
60         return FALSE;
61
62     if (g_strcmp0(element->default_complex->_val, test->_val) == 0)
63         return TRUE;
64
65     return FALSE;
66 }
67
68 void extcap_free_complex(extcap_complex *comp) {
69     if (comp)
70         g_free(comp->_val);
71     g_free(comp);
72 }
73
74 gint extcap_complex_get_int(extcap_complex *comp) {
75     if (comp == NULL || comp->_val == NULL || comp->complex_type != EXTCAP_ARG_INTEGER)
76         return (gint)0;
77
78     return (gint) g_ascii_strtoll(comp->_val, NULL, 10);
79 }
80
81 guint extcap_complex_get_uint(extcap_complex *comp) {
82     if (comp == NULL || comp->_val == NULL || comp->complex_type != EXTCAP_ARG_UNSIGNED)
83         return (guint)0;
84     return (guint) g_ascii_strtoull(comp->_val, NULL, 10);
85 }
86
87 gint64 extcap_complex_get_long(extcap_complex *comp) {
88     if (comp == NULL || comp->_val == NULL || comp->complex_type != EXTCAP_ARG_LONG)
89         return (gint64)0;
90     return g_ascii_strtoll(comp->_val, NULL, 10);
91 }
92
93 gdouble extcap_complex_get_double(extcap_complex *comp) {
94     if (comp == NULL || comp->_val == NULL || comp->complex_type != EXTCAP_ARG_DOUBLE)
95         return (gdouble)0;
96     return g_strtod(comp->_val, NULL);
97 }
98
99 gboolean extcap_complex_get_bool(extcap_complex *comp) {
100     if (comp == NULL || comp->_val == NULL)
101         return FALSE;
102
103     if (comp->complex_type != EXTCAP_ARG_BOOLEAN && comp->complex_type != EXTCAP_ARG_BOOLFLAG)
104         return FALSE;
105
106     return g_regex_match_simple(EXTCAP_BOOLEAN_REGEX, comp->_val, G_REGEX_CASELESS, (GRegexMatchFlags)0);
107 }
108
109 gchar *extcap_complex_get_string(extcap_complex *comp) {
110     /* Not checking for argument type, to use this method as fallback if only strings are needed */
111     return comp != NULL ? comp->_val : NULL;
112 }
113
114 static extcap_token_sentence *extcap_tokenize_sentence(const gchar *s) {
115     GRegex *regex = NULL;
116     GMatchInfo *match_info = NULL;
117     GError *error = NULL;
118     gchar *param_value = NULL;
119     guint param_type = EXTCAP_PARAM_UNKNOWN;
120
121     extcap_token_sentence *rs = g_new0(extcap_token_sentence, 1);
122
123     rs->sentence = NULL;
124
125     /* Regex for catching just the allowed values for sentences */
126     if ((regex = g_regex_new("^[\\t| ]*(arg|value|interface|extcap|dlt|control)(?=[\\t| ]+\\{)",
127                              (GRegexCompileFlags) G_REGEX_CASELESS, (GRegexMatchFlags) 0, NULL)) != NULL) {
128         g_regex_match(regex, s, (GRegexMatchFlags) 0, &match_info);
129
130         if (g_match_info_matches(match_info))
131             rs->sentence = g_match_info_fetch(match_info, 0);
132
133         g_match_info_free(match_info);
134         g_regex_unref(regex);
135     }
136     /* No valid sentence found, exiting here */
137     if (rs->sentence == NULL) {
138         g_free(rs);
139         return NULL;
140     }
141
142     rs->param_list = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, g_free);
143
144     /* Capture the argument and the value of the list. This will ensure,
145      * that regex patterns given to {validation=} are parsed correctly,
146      * as long as }{ does not occur within the pattern */
147     regex = g_regex_new("\\{([a-zA-Z_-]*?)\\=(.*?)\\}(?=\\{|$|\\s)",
148                         (GRegexCompileFlags) G_REGEX_CASELESS, (GRegexMatchFlags) 0, NULL);
149     if (regex != NULL) {
150         g_regex_match_full(regex, s, -1, 0, (GRegexMatchFlags) 0, &match_info, &error);
151         while (g_match_info_matches(match_info)) {
152             gchar *arg = g_match_info_fetch(match_info, 1);
153
154             if (arg == NULL)
155                 break;
156
157             param_value = g_match_info_fetch(match_info, 2);
158
159             if (g_ascii_strcasecmp(arg, "number") == 0) {
160                 param_type = EXTCAP_PARAM_ARGNUM;
161             } else if (g_ascii_strcasecmp(arg, "call") == 0) {
162                 param_type = EXTCAP_PARAM_CALL;
163             } else if (g_ascii_strcasecmp(arg, "display") == 0) {
164                 param_type = EXTCAP_PARAM_DISPLAY;
165             } else if (g_ascii_strcasecmp(arg, "type") == 0) {
166                 param_type = EXTCAP_PARAM_TYPE;
167             } else if (g_ascii_strcasecmp(arg, "arg") == 0) {
168                 param_type = EXTCAP_PARAM_ARG;
169             } else if (g_ascii_strcasecmp(arg, "default") == 0) {
170                 param_type = EXTCAP_PARAM_DEFAULT;
171             } else if (g_ascii_strcasecmp(arg, "value") == 0) {
172                 param_type = EXTCAP_PARAM_VALUE;
173             } else if (g_ascii_strcasecmp(arg, "range") == 0) {
174                 param_type = EXTCAP_PARAM_RANGE;
175             } else if (g_ascii_strcasecmp(arg, "tooltip") == 0) {
176                 param_type = EXTCAP_PARAM_TOOLTIP;
177             } else if (g_ascii_strcasecmp(arg, "placeholder") == 0) {
178                 param_type = EXTCAP_PARAM_PLACEHOLDER;
179             } else if (g_ascii_strcasecmp(arg, "mustexist") == 0) {
180                 param_type = EXTCAP_PARAM_FILE_MUSTEXIST;
181             } else if (g_ascii_strcasecmp(arg, "fileext") == 0) {
182                 param_type = EXTCAP_PARAM_FILE_EXTENSION;
183             } else if (g_ascii_strcasecmp(arg, "name") == 0) {
184                 param_type = EXTCAP_PARAM_NAME;
185             } else if (g_ascii_strcasecmp(arg, "enabled") == 0) {
186                 param_type = EXTCAP_PARAM_ENABLED;
187             } else if (g_ascii_strcasecmp(arg, "parent") == 0) {
188                 param_type = EXTCAP_PARAM_PARENT;
189             } else if (g_ascii_strcasecmp(arg, "required") == 0) {
190                 param_type = EXTCAP_PARAM_REQUIRED;
191             } else if (g_ascii_strcasecmp(arg, "save") == 0) {
192                 param_type = EXTCAP_PARAM_SAVE;
193             } else if (g_ascii_strcasecmp(arg, "validation") == 0) {
194                 param_type = EXTCAP_PARAM_VALIDATION;
195             } else if (g_ascii_strcasecmp(arg, "version") == 0) {
196                 param_type = EXTCAP_PARAM_VERSION;
197             } else if (g_ascii_strcasecmp(arg, "help") == 0) {
198                 param_type = EXTCAP_PARAM_HELP;
199             } else if (g_ascii_strcasecmp(arg, "control") == 0) {
200                 param_type = EXTCAP_PARAM_CONTROL;
201             } else if (g_ascii_strcasecmp(arg, "role") == 0) {
202                 param_type = EXTCAP_PARAM_ROLE;
203             } else {
204                 param_type = EXTCAP_PARAM_UNKNOWN;
205             }
206
207             g_hash_table_insert(rs->param_list, ENUM_KEY(param_type), param_value);
208
209             g_match_info_next(match_info, &error);
210             g_free(arg);
211         }
212         g_match_info_free(match_info);
213         g_regex_unref(regex);
214     }
215
216     return rs;
217 }
218
219 static GList *extcap_tokenize_sentences(const gchar *s) {
220
221     GList *sentences = NULL;
222     extcap_token_sentence *item = NULL;
223     gchar **list, **list_iter;
224
225     list_iter = list = g_strsplit(s, "\n", 0);
226     while (*list_iter != NULL) {
227         item = extcap_tokenize_sentence(*list_iter);
228         if (item)
229             sentences = g_list_append(sentences, item);
230         list_iter++;
231     }
232
233     g_strfreev(list);
234
235     return sentences;
236 }
237
238 static void extcap_free_value(extcap_value *v) {
239     if (v == NULL)
240         return;
241
242     g_free(v->call);
243     g_free(v->display);
244
245     g_free(v);
246 }
247
248 static void extcap_free_valuelist(gpointer data, gpointer user_data _U_) {
249     extcap_free_value((extcap_value *) data);
250 }
251
252 void extcap_free_arg(extcap_arg *a) {
253
254     if (a == NULL)
255         return;
256
257     g_free(a->call);
258     g_free(a->display);
259     g_free(a->tooltip);
260     g_free(a->placeholder);
261     g_free(a->fileextension);
262     g_free(a->regexp);
263     g_free(a->device_name);
264
265     if (a->range_start != NULL)
266         extcap_free_complex(a->range_start);
267
268     if (a->range_end != NULL)
269         extcap_free_complex(a->range_end);
270
271     if (a->default_complex != NULL)
272         extcap_free_complex(a->default_complex);
273
274     g_list_foreach(a->values, (GFunc) extcap_free_valuelist, NULL);
275     g_list_free(a->values);
276     g_free(a);
277 }
278
279 static void extcap_free_toolbar_value(iface_toolbar_value *v) {
280     if (v == NULL)
281         return;
282
283     g_free(v->value);
284     g_free(v->display);
285 }
286
287 static void extcap_free_toolbar_control(iface_toolbar_control *c) {
288     if (c == NULL)
289         return;
290
291     g_free(c->display);
292     g_free(c->validation);
293     g_free(c->tooltip);
294     g_free(c->placeholder);
295 }
296
297 void extcap_free_arg_list(GList *a) {
298     g_list_foreach(a, (GFunc)extcap_free_arg, NULL);
299     g_list_free(a);
300 }
301
302 static gint glist_find_numbered_arg(gconstpointer listelem, gconstpointer needle) {
303     if (((const extcap_arg *) listelem)->arg_num == *((const int *) needle))
304         return 0;
305     return 1;
306 }
307
308 static gint glist_find_numbered_control(gconstpointer listelem, gconstpointer needle) {
309     if (((const iface_toolbar_control *) listelem)->num == *((const int *) needle))
310         return 0;
311     return 1;
312 }
313
314 static void extcap_free_tokenized_sentence(gpointer s, gpointer user_data _U_) {
315     extcap_token_sentence *t = (extcap_token_sentence *)s;
316
317     if (t == NULL)
318         return;
319
320     g_free(t->sentence);
321     g_hash_table_destroy(t->param_list);
322     g_free(t);
323 }
324
325 static void extcap_free_tokenized_sentences(GList *sentences) {
326     if (sentences == NULL)
327         return;
328
329     g_list_foreach(sentences, extcap_free_tokenized_sentence, NULL);
330     g_list_free(sentences);
331 }
332
333 static extcap_arg *extcap_parse_arg_sentence(GList *args, extcap_token_sentence *s) {
334     gchar *param_value = NULL;
335
336     extcap_arg *target_arg = NULL;
337     extcap_value *value = NULL;
338     GList *entry = NULL;
339     int tint;
340     extcap_sentence_type sent = EXTCAP_SENTENCE_UNKNOWN;
341
342     if (s == NULL)
343         return target_arg;
344
345     if (g_ascii_strcasecmp(s->sentence, "arg") == 0) {
346         sent = EXTCAP_SENTENCE_ARG;
347         /* printf("ARG sentence\n"); */
348     } else if (g_ascii_strcasecmp(s->sentence, "value") == 0) {
349         sent = EXTCAP_SENTENCE_VALUE;
350         /* printf("VALUE sentence\n"); */
351     }
352
353     if (sent == EXTCAP_SENTENCE_ARG) {
354         target_arg = g_new0(extcap_arg, 1);
355         target_arg->arg_type = EXTCAP_ARG_UNKNOWN;
356         target_arg->save = TRUE;
357
358
359         if ((param_value = (gchar *)g_hash_table_lookup(s->param_list, ENUM_KEY(EXTCAP_PARAM_ARGNUM))) == NULL) {
360             extcap_free_arg(target_arg);
361             return NULL;
362         }
363
364         if (sscanf(param_value, "%d", &(target_arg->arg_num)) != 1) {
365             extcap_free_arg(target_arg);
366             return NULL;
367         }
368
369         if ((param_value = (gchar *)g_hash_table_lookup(s->param_list, ENUM_KEY(EXTCAP_PARAM_CALL))) == NULL) {
370             extcap_free_arg(target_arg);
371             return NULL;
372         }
373         target_arg->call = g_strdup(param_value);
374
375         /* No value only parameters allowed */
376         if (strlen(target_arg->call) == 0) {
377             extcap_free_arg(target_arg);
378             return NULL;
379         }
380
381         if ((param_value = (gchar *)g_hash_table_lookup(s->param_list, ENUM_KEY(EXTCAP_PARAM_DISPLAY))) == NULL) {
382             extcap_free_arg(target_arg);
383             return NULL;
384         }
385         target_arg->display = g_strdup(param_value);
386
387         if ((param_value = (gchar *)g_hash_table_lookup(s->param_list, ENUM_KEY(EXTCAP_PARAM_TOOLTIP)))
388                 != NULL) {
389             target_arg->tooltip = g_strdup(param_value);
390         }
391
392         if ((param_value = (gchar *)g_hash_table_lookup(s->param_list, ENUM_KEY(EXTCAP_PARAM_PLACEHOLDER)))
393                 != NULL) {
394             target_arg->placeholder = g_strdup(param_value);
395         }
396
397         if ((param_value = (gchar *)g_hash_table_lookup(s->param_list, ENUM_KEY(EXTCAP_PARAM_FILE_MUSTEXIST)))
398                 != NULL) {
399             target_arg->fileexists = g_regex_match_simple(EXTCAP_BOOLEAN_REGEX, param_value, G_REGEX_CASELESS, (GRegexMatchFlags)0);
400         }
401
402         if ((param_value = (gchar *)g_hash_table_lookup(s->param_list, ENUM_KEY(EXTCAP_PARAM_FILE_EXTENSION)))
403                 != NULL) {
404             target_arg->fileextension = g_strdup(param_value);
405         }
406
407         if ((param_value = (gchar *)g_hash_table_lookup(s->param_list, ENUM_KEY(EXTCAP_PARAM_VALIDATION)))
408                 != NULL) {
409             target_arg->regexp = g_strdup(param_value);
410         }
411
412         if ((param_value = (gchar *)g_hash_table_lookup(s->param_list, ENUM_KEY(EXTCAP_PARAM_REQUIRED)))
413                 != NULL) {
414             target_arg->is_required = g_regex_match_simple(EXTCAP_BOOLEAN_REGEX, param_value, G_REGEX_CASELESS, (GRegexMatchFlags)0);
415         }
416
417         if ((param_value = (gchar *)g_hash_table_lookup(s->param_list, ENUM_KEY(EXTCAP_PARAM_TYPE)))
418                 == NULL) {
419             /* printf("no type in ARG sentence\n"); */
420             extcap_free_arg(target_arg);
421             return NULL;
422         }
423
424         if (g_ascii_strcasecmp(param_value, "integer") == 0) {
425             target_arg->arg_type = EXTCAP_ARG_INTEGER;
426         } else if (g_ascii_strcasecmp(param_value, "unsigned") == 0) {
427             target_arg->arg_type = EXTCAP_ARG_UNSIGNED;
428         } else if (g_ascii_strcasecmp(param_value, "long") == 0) {
429             target_arg->arg_type = EXTCAP_ARG_LONG;
430         } else if (g_ascii_strcasecmp(param_value, "double") == 0) {
431             target_arg->arg_type = EXTCAP_ARG_DOUBLE;
432         } else if (g_ascii_strcasecmp(param_value, "boolean") == 0) {
433             target_arg->arg_type = EXTCAP_ARG_BOOLEAN;
434         } else if (g_ascii_strcasecmp(param_value, "boolflag") == 0) {
435             target_arg->arg_type = EXTCAP_ARG_BOOLFLAG;
436         } else if (g_ascii_strcasecmp(param_value, "selector") == 0) {
437             target_arg->arg_type = EXTCAP_ARG_SELECTOR;
438         } else if (g_ascii_strcasecmp(param_value, "radio") == 0) {
439             target_arg->arg_type = EXTCAP_ARG_RADIO;
440         } else if (g_ascii_strcasecmp(param_value, "string") == 0) {
441             target_arg->arg_type = EXTCAP_ARG_STRING;
442         } else if (g_ascii_strcasecmp(param_value, "password") == 0) {
443             target_arg->arg_type = EXTCAP_ARG_PASSWORD;
444             /* default setting is to not save passwords */
445             target_arg->save = FALSE;
446         } else if (g_ascii_strcasecmp(param_value, "fileselect") == 0) {
447             target_arg->arg_type = EXTCAP_ARG_FILESELECT;
448         } else if (g_ascii_strcasecmp(param_value, "multicheck") == 0) {
449             target_arg->arg_type = EXTCAP_ARG_MULTICHECK;
450         } else if (g_ascii_strcasecmp(param_value, "timestamp") == 0) {
451             target_arg->arg_type = EXTCAP_ARG_TIMESTAMP;
452         } else {
453             printf("invalid type %s in ARG sentence\n", param_value);
454             extcap_free_arg(target_arg);
455             return NULL;
456         }
457
458         if ((param_value = (gchar *)g_hash_table_lookup(s->param_list, ENUM_KEY(EXTCAP_PARAM_SAVE)))
459                 != NULL) {
460             target_arg->save = g_regex_match_simple(EXTCAP_BOOLEAN_REGEX, param_value, G_REGEX_CASELESS, (GRegexMatchFlags)0);
461         }
462
463         if ((param_value = (gchar *)g_hash_table_lookup(s->param_list, ENUM_KEY(EXTCAP_PARAM_RANGE)))
464                 != NULL) {
465             gchar *cp = g_strstr_len(param_value, -1, ",");
466
467             if (cp == NULL) {
468                 printf("invalid range, expected value,value got %s\n",
469                        param_value);
470                 extcap_free_arg(target_arg);
471                 return NULL;
472             }
473
474             if ((target_arg->range_start = extcap_parse_complex(
475                                                target_arg->arg_type, param_value)) == NULL) {
476                 printf("invalid range, expected value,value got %s\n",
477                        param_value);
478                 extcap_free_arg(target_arg);
479                 return NULL;
480             }
481
482             if ((target_arg->range_end = extcap_parse_complex(
483                                              target_arg->arg_type, cp + 1)) == NULL) {
484                 printf("invalid range, expected value,value got %s\n",
485                        param_value);
486                 extcap_free_arg(target_arg);
487                 return NULL;
488             }
489         }
490
491         if ((param_value = (gchar *)g_hash_table_lookup(s->param_list, ENUM_KEY(EXTCAP_PARAM_DEFAULT)))
492                 != NULL) {
493             if (target_arg->arg_type != EXTCAP_ARG_MULTICHECK && target_arg->arg_type != EXTCAP_ARG_SELECTOR)
494             {
495                 if ((target_arg->default_complex = extcap_parse_complex(
496                                                        target_arg->arg_type, param_value)) == NULL) {
497                     printf("invalid default, couldn't parse %s\n", param_value);
498                 }
499             }
500         }
501
502     } else if (sent == EXTCAP_SENTENCE_VALUE) {
503         if ((param_value = (gchar *)g_hash_table_lookup(s->param_list, ENUM_KEY(EXTCAP_PARAM_ARG)))
504                 == NULL) {
505             printf("no arg in VALUE sentence\n");
506             return NULL;
507         }
508
509         if (sscanf(param_value, "%d", &tint) != 1) {
510             printf("invalid arg in VALUE sentence\n");
511             return NULL;
512         }
513
514         if ((entry = g_list_find_custom(args, &tint, glist_find_numbered_arg))
515                 == NULL) {
516             printf("couldn't find arg %d in list for VALUE sentence\n", tint);
517             return NULL;
518         }
519
520         value = g_new0(extcap_value, 1);
521         value->arg_num = tint;
522
523         if ((param_value = (gchar *)g_hash_table_lookup(s->param_list, ENUM_KEY(EXTCAP_PARAM_VALUE)))
524                 == NULL) {
525             /* printf("no value in VALUE sentence\n"); */
526             extcap_free_value(value);
527             return NULL;
528         }
529         value->call = g_strdup(param_value);
530
531         if ((param_value = (gchar *)g_hash_table_lookup(s->param_list, ENUM_KEY(EXTCAP_PARAM_DISPLAY)))
532                 == NULL) {
533             /* printf("no display in VALUE sentence\n"); */
534             extcap_free_value(value);
535             return NULL;
536         }
537         value->display = g_strdup(param_value);
538
539         if ((param_value = (gchar *)g_hash_table_lookup(s->param_list, ENUM_KEY(EXTCAP_PARAM_PARENT)))
540                 != NULL) {
541             value->parent = g_strdup(param_value);
542         }
543
544         if ((param_value = (gchar *)g_hash_table_lookup(s->param_list, ENUM_KEY(EXTCAP_PARAM_DEFAULT)))
545                 != NULL) {
546             /* printf("found default value\n"); */
547             value->is_default = g_regex_match_simple(EXTCAP_BOOLEAN_REGEX, param_value, G_REGEX_CASELESS, (GRegexMatchFlags)0);
548         }
549
550         if ((param_value = (gchar *)g_hash_table_lookup(s->param_list, ENUM_KEY(EXTCAP_PARAM_ENABLED)))
551                 != NULL) {
552             value->enabled = g_regex_match_simple(EXTCAP_BOOLEAN_REGEX, param_value, G_REGEX_CASELESS, (GRegexMatchFlags)0);
553         }
554
555         ((extcap_arg *) entry->data)->values = g_list_append(
556                 ((extcap_arg *) entry->data)->values, value);
557
558         return NULL;
559     }
560
561     return target_arg;
562 }
563
564 GList *extcap_parse_args(gchar *output) {
565     GList *result = NULL;
566     GList *walker = NULL;
567     GList *temp = NULL;
568
569     walker = extcap_tokenize_sentences(output);
570     temp = walker;
571
572     while (walker) {
573         extcap_arg *ra = NULL;
574         extcap_token_sentence *sentence = (extcap_token_sentence *)walker->data;
575
576         if ((ra = extcap_parse_arg_sentence(result, sentence)) != NULL)
577             result = g_list_append(result, (gpointer) ra);
578
579         walker = g_list_next(walker);
580     }
581
582     extcap_free_tokenized_sentences(temp);
583
584     return result;
585 }
586
587 static extcap_interface *extcap_parse_interface_sentence(extcap_token_sentence *s) {
588     extcap_sentence_type sent = EXTCAP_SENTENCE_UNKNOWN;
589     gchar *param_value = NULL;
590     extcap_interface *ri = NULL;
591
592     if (s == NULL)
593         return NULL;
594
595     if (g_ascii_strcasecmp(s->sentence, "interface") == 0) {
596         sent = EXTCAP_SENTENCE_INTERFACE;
597     } else if (g_ascii_strcasecmp(s->sentence, "extcap") == 0) {
598         sent = EXTCAP_SENTENCE_EXTCAP;
599     }
600
601     if (sent == EXTCAP_SENTENCE_UNKNOWN)
602         return NULL;
603
604     ri = g_new0(extcap_interface, 1);
605
606     ri->if_type = sent;
607
608     if ((param_value = (gchar *)g_hash_table_lookup(s->param_list, ENUM_KEY(EXTCAP_PARAM_VALUE)))
609             == NULL && sent == EXTCAP_SENTENCE_INTERFACE) {
610         printf("No value in INTERFACE sentence\n");
611         g_free(ri);
612         return NULL;
613     }
614     ri->call = g_strdup(param_value);
615
616     if ((param_value = (gchar *)g_hash_table_lookup(s->param_list, ENUM_KEY(EXTCAP_PARAM_DISPLAY)))
617             == NULL && sent == EXTCAP_SENTENCE_INTERFACE) {
618         printf("No display in INTERFACE sentence\n");
619         g_free(ri->call);
620         g_free(ri);
621         return NULL;
622     }
623     ri->display = g_strdup(param_value);
624
625     if ((param_value = (gchar *)g_hash_table_lookup(s->param_list, ENUM_KEY(EXTCAP_PARAM_VERSION)))
626             != NULL) {
627         ri->version = g_strdup(param_value);
628     }
629
630     if ((param_value = (gchar *)g_hash_table_lookup(s->param_list, ENUM_KEY(EXTCAP_PARAM_HELP)))
631             != NULL) {
632         ri->help = g_strdup(param_value);
633     }
634
635     return ri;
636 }
637
638 static iface_toolbar_control *extcap_parse_control_sentence(GList *control_items, extcap_token_sentence *s)
639 {
640     extcap_sentence_type sent = EXTCAP_SENTENCE_UNKNOWN;
641     gchar *param_value = NULL;
642     iface_toolbar_control *control = NULL;
643     iface_toolbar_value *value = NULL;
644     GList *entry = NULL;
645     guint32 num = 0;
646
647     if (s == NULL)
648         return NULL;
649
650     if (g_ascii_strcasecmp(s->sentence, "control") == 0) {
651         sent = EXTCAP_SENTENCE_CONTROL;
652     } else if (g_ascii_strcasecmp(s->sentence, "value") == 0) {
653         sent = EXTCAP_SENTENCE_VALUE;
654     }
655
656     if (sent == EXTCAP_SENTENCE_UNKNOWN)
657         return NULL;
658
659     if (sent == EXTCAP_SENTENCE_CONTROL) {
660         control = g_new0(iface_toolbar_control, 1);
661         control->ctrl_type = INTERFACE_TYPE_UNKNOWN;
662
663         param_value = (gchar *)g_hash_table_lookup(s->param_list, ENUM_KEY(EXTCAP_PARAM_ARGNUM));
664         if (param_value == NULL) {
665             extcap_free_toolbar_control(control);
666             return NULL;
667         }
668
669         if (!ws_strtou32(param_value, NULL, &num)) {
670             extcap_free_toolbar_control(control);
671             return NULL;
672         }
673         control->num = (int)num;
674
675         param_value = (gchar *)g_hash_table_lookup(s->param_list, ENUM_KEY(EXTCAP_PARAM_DISPLAY));
676         if (param_value == NULL) {
677             extcap_free_toolbar_control(control);
678             return NULL;
679         }
680         control->display = g_strdup(param_value);
681
682         if ((param_value = (gchar *)g_hash_table_lookup(s->param_list, ENUM_KEY(EXTCAP_PARAM_VALIDATION)))
683             != NULL) {
684             control->validation = g_strdup(param_value);
685         }
686
687         if ((param_value = (gchar *)g_hash_table_lookup(s->param_list, ENUM_KEY(EXTCAP_PARAM_REQUIRED)))
688             != NULL) {
689             control->is_required = g_regex_match_simple(EXTCAP_BOOLEAN_REGEX, param_value, G_REGEX_CASELESS, (GRegexMatchFlags)0);
690         }
691
692         param_value = (gchar *)g_hash_table_lookup(s->param_list, ENUM_KEY(EXTCAP_PARAM_TOOLTIP));
693         if (param_value != NULL) {
694             control->tooltip = g_strdup(param_value);
695         }
696
697         param_value = (gchar *)g_hash_table_lookup(s->param_list, ENUM_KEY(EXTCAP_PARAM_PLACEHOLDER));
698         if (param_value != NULL) {
699             control->placeholder = g_strdup(param_value);
700         }
701
702         param_value = (gchar *)g_hash_table_lookup(s->param_list, ENUM_KEY(EXTCAP_PARAM_TYPE));
703         if (param_value == NULL) {
704             extcap_free_toolbar_control(control);
705             return NULL;
706         }
707
708         extcap_arg_type arg_type = EXTCAP_ARG_UNKNOWN;
709         if (g_ascii_strcasecmp(param_value, "boolean") == 0) {
710             control->ctrl_type = INTERFACE_TYPE_BOOLEAN;
711             arg_type = EXTCAP_ARG_BOOLEAN;
712         } else if (g_ascii_strcasecmp(param_value, "button") == 0) {
713             control->ctrl_type = INTERFACE_TYPE_BUTTON;
714         } else if (g_ascii_strcasecmp(param_value, "selector") == 0) {
715             control->ctrl_type = INTERFACE_TYPE_SELECTOR;
716         } else if (g_ascii_strcasecmp(param_value, "string") == 0) {
717             control->ctrl_type = INTERFACE_TYPE_STRING;
718             arg_type = EXTCAP_ARG_STRING;
719         } else {
720             printf("invalid type %s in CONTROL sentence\n", param_value);
721             extcap_free_toolbar_control(control);
722             return NULL;
723         }
724
725         param_value = (gchar *)g_hash_table_lookup(s->param_list, ENUM_KEY(EXTCAP_PARAM_ROLE));
726         if (param_value != NULL) {
727             if (g_ascii_strcasecmp(param_value, "control") == 0) {
728                 control->ctrl_role = INTERFACE_ROLE_CONTROL;
729             } else if (g_ascii_strcasecmp(param_value, "help") == 0) {
730                 control->ctrl_role = INTERFACE_ROLE_HELP;
731             } else if (g_ascii_strcasecmp(param_value, "logger") == 0) {
732                 control->ctrl_role = INTERFACE_ROLE_LOGGER;
733             } else if (g_ascii_strcasecmp(param_value, "restore") == 0) {
734                 control->ctrl_role = INTERFACE_ROLE_RESTORE;
735             } else {
736                 printf("invalid role %s in CONTROL sentence\n", param_value);
737                 control->ctrl_role = INTERFACE_ROLE_UNKNOWN;
738             }
739         } else {
740             /* Default role */
741             control->ctrl_role = INTERFACE_ROLE_CONTROL;
742         }
743
744         param_value = (gchar *)g_hash_table_lookup(s->param_list, ENUM_KEY(EXTCAP_PARAM_DEFAULT));
745         if (param_value != NULL) {
746             if (arg_type != EXTCAP_ARG_UNKNOWN) {
747                 extcap_complex *complex = extcap_parse_complex(arg_type, param_value);
748                 if (complex != NULL) {
749                     if (arg_type == EXTCAP_ARG_BOOLEAN) {
750                         control->default_value.boolean = extcap_complex_get_bool(complex);
751                     } else if (arg_type == EXTCAP_ARG_STRING) {
752                         control->default_value.string = g_strdup(complex->_val);
753                     }
754                     extcap_free_complex(complex);
755                 } else {
756                     printf("invalid default, couldn't parse %s\n", param_value);
757                 }
758             }
759         }
760
761     } else if (sent == EXTCAP_SENTENCE_VALUE) {
762         param_value = (gchar *)g_hash_table_lookup(s->param_list, ENUM_KEY(EXTCAP_PARAM_CONTROL));
763         if (param_value == NULL) {
764             printf("no control in VALUE sentence\n");
765             return NULL;
766         }
767
768         if (!ws_strtou32(param_value, NULL, &num)) {
769             extcap_free_toolbar_control(control);
770             return NULL;
771         }
772
773         entry = g_list_find_custom(control_items, &num, glist_find_numbered_control);
774         if (entry == NULL) {
775             printf("couldn't find control %u in list for VALUE sentence\n", num);
776             return NULL;
777         }
778
779         value = g_new0(iface_toolbar_value, 1);
780         value->num = (int)num;
781
782         param_value = (gchar *)g_hash_table_lookup(s->param_list, ENUM_KEY(EXTCAP_PARAM_VALUE));
783         if (param_value == NULL) {
784             extcap_free_toolbar_value(value);
785             return NULL;
786         }
787         value->value = g_strdup(param_value);
788
789         param_value = (gchar *)g_hash_table_lookup(s->param_list, ENUM_KEY(EXTCAP_PARAM_DISPLAY));
790         if (param_value == NULL) {
791             extcap_free_toolbar_value(value);
792             return NULL;
793         }
794         value->display = g_strdup(param_value);
795
796         param_value = (gchar *)g_hash_table_lookup(s->param_list, ENUM_KEY(EXTCAP_PARAM_DEFAULT));
797         if (param_value != NULL) {
798             value->is_default = g_regex_match_simple(EXTCAP_BOOLEAN_REGEX, param_value, G_REGEX_CASELESS, (GRegexMatchFlags)0);
799         }
800
801         control = (iface_toolbar_control *)entry->data;
802         control->values = g_list_append(control->values, value);
803
804         return NULL;
805     }
806
807     return control;
808 }
809
810 GList *extcap_parse_interfaces(gchar *output, GList **control_items) {
811
812     GList *result = NULL;
813     GList *tokens = NULL;
814     GList *walker = extcap_tokenize_sentences(output);
815     tokens = walker;
816
817     while (walker) {
818         extcap_interface *ri = NULL;
819         iface_toolbar_control *ti = NULL;
820         extcap_token_sentence *if_sentence = (extcap_token_sentence *) walker->data;
821
822         if (if_sentence) {
823             if ((g_ascii_strcasecmp(if_sentence->sentence, "interface") == 0) ||
824                 (g_ascii_strcasecmp(if_sentence->sentence, "extcap") == 0))
825             {
826                 if ((ri = extcap_parse_interface_sentence(if_sentence))) {
827                     result = g_list_append(result, ri);
828                 }
829             } else if (control_items &&
830                        ((g_ascii_strcasecmp(if_sentence->sentence, "control") == 0) ||
831                         (g_ascii_strcasecmp(if_sentence->sentence, "value") == 0)))
832             {
833                 if ((ti = extcap_parse_control_sentence(*control_items, if_sentence))) {
834                     *control_items = g_list_append(*control_items, ti);
835                 }
836             }
837         }
838
839         walker = g_list_next(walker);
840     }
841
842     extcap_free_tokenized_sentences(tokens);
843
844     return result;
845 }
846
847 /* Parse a tokenized set of sentences and validate, looking for DLT definitions */
848 static extcap_dlt *extcap_parse_dlt_sentence(extcap_token_sentence *s) {
849     gchar *param_value = NULL;
850     extcap_sentence_type sent = EXTCAP_SENTENCE_UNKNOWN;
851     extcap_dlt *result = NULL;
852
853     if (s == NULL)
854         return result;
855
856     if (g_ascii_strcasecmp(s->sentence, "dlt") == 0) {
857         sent = EXTCAP_SENTENCE_DLT;
858     }
859
860     if (sent == EXTCAP_SENTENCE_UNKNOWN)
861         return result;
862
863     result = g_new0(extcap_dlt, 1);
864
865     result->number = -1;
866     result->name = NULL;
867     result->display = NULL;
868
869     if ((param_value = (gchar *)g_hash_table_lookup(s->param_list, ENUM_KEY(EXTCAP_PARAM_ARGNUM)))
870             == NULL) {
871         printf("No number in DLT sentence\n");
872         g_free(result);
873         return NULL;
874     }
875     if (sscanf(param_value, "%d", &(result->number)) != 1) {
876         printf("Invalid number in DLT sentence\n");
877         g_free(result);
878         return NULL;
879     }
880
881     if ((param_value = (gchar *)g_hash_table_lookup(s->param_list, ENUM_KEY(EXTCAP_PARAM_NAME)))
882             == NULL) {
883         printf("No name in DLT sentence\n");
884         g_free(result);
885         return NULL;
886     }
887     result->name = g_strdup(param_value);
888
889     if ((param_value = (gchar *)g_hash_table_lookup(s->param_list, ENUM_KEY(EXTCAP_PARAM_DISPLAY)))
890             == NULL) {
891         printf("No display in DLT sentence\n");
892         g_free(result->name);
893         g_free(result);
894         return NULL;
895     }
896     result->display = g_strdup(param_value);
897
898     return result;
899 }
900
901 GList *extcap_parse_dlts(gchar *output) {
902
903     GList *walker = NULL;
904     GList *temp = NULL;
905     GList *result = NULL;
906
907     walker = extcap_tokenize_sentences(output);
908
909     temp = walker;
910
911     while (walker) {
912         extcap_dlt *data = NULL;
913
914         if ((data = extcap_parse_dlt_sentence((extcap_token_sentence *)walker->data)) != NULL)
915             result = g_list_append(result, data);
916
917         walker = g_list_next(walker);
918     }
919
920     extcap_free_tokenized_sentences(temp);
921
922     return result;
923 }
924
925 /*
926  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
927  *
928  * Local variables:
929  * c-basic-offset: 4
930  * tab-width: 8
931  * indent-tabs-mode: nil
932  * End:
933  *
934  * vi: set shiftwidth=4 tabstop=8 expandtab:
935  * :indentSize=4:tabSize=8:noTabs=true:
936  */