do not call proto_tree_add_...() inside PROTO_ITEM_SET_HIDDEN() macro
[metze/wireshark/wip.git] / capture_ui_utils.c
1 /* capture_ui_utils.c
2  * Utilities for capture user interfaces
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 #ifdef HAVE_LIBPCAP
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <glib.h>
35
36 #include <epan/prefs.h>
37 #include "capture-pcap-util.h"
38 #include "capture_ui_utils.h"
39
40 /*
41  * Find user-specified capture device description that matches interface
42  * name, if any.
43  */
44 char *
45 capture_dev_user_descr_find(const gchar *if_name)
46 {
47         char    *p;
48         char    *p2 = NULL;
49         char    *descr = NULL;
50         int     lp = 0;
51         int     ct = 0;
52
53         if (prefs.capture_devices_descr == NULL) {
54                 /* There are no descriptions. */
55                 return NULL;
56         }
57
58         if ((p = strstr(prefs.capture_devices_descr, if_name)) == NULL) {
59                 /* There are, but there isn't one for this interface. */
60                 return NULL;
61         }
62
63         while (*p != '\0') {
64                 /* error: ran into next interface description */
65                 if (*p == ',')
66                         return NULL;
67                 /* found left parenthesis, start of description */
68                 else if (*p == '(') {
69                         ct = 0;
70                         lp++;
71                         /* skip over left parenthesis */
72                         p++;
73                         /* save pointer to beginning of description */
74                         p2 = p;
75                         continue;
76                 }
77                 else if (*p == ')') {
78                         /* end of description */
79                         break;
80                 }
81                 else {
82                         p++;
83                         ct++;
84                 }
85         }
86
87         if ((lp == 1) && (ct > 0) && (p2 != NULL)) {
88                 /* Allocate enough space to return the string,
89                    which runs from p2 to p, plus a terminating
90                    '\0'. */
91                 descr = g_malloc(p - p2 + 1);
92                 memcpy(descr, p2, p - p2);
93                 descr[p - p2] = '\0';
94                 return descr;
95         }
96         else
97                 return NULL;
98 }
99
100 gint
101 capture_dev_user_linktype_find(const gchar *if_name)
102 {
103         gchar *p, *next;
104         long linktype;
105
106         if (prefs.capture_devices_linktypes == NULL) {
107                 /* There are no link-layer header types */
108                 return -1;
109         }
110
111         if ((p = strstr(prefs.capture_devices_linktypes, if_name)) == NULL) {
112                 /* There are, but there isn't one for this interface. */
113                 return -1;
114         }
115
116         p += strlen(if_name) + 1;
117         linktype = strtol(p, &next, 10);
118         if (next == p || *next != ')' || linktype < 0) {
119                 /* Syntax error */
120                 return -1;
121         }
122         if (linktype > G_MAXINT) {
123                 /* Value doesn't fit in a gint */
124                 return -1;
125         }
126
127         return (gint)linktype;
128 }
129
130 /*
131  * Return as descriptive a name for an interface as we can get.
132  * If the user has specified a comment, use that.  Otherwise,
133  * if get_interface_list() supplies a description, use that,
134  * otherwise use the interface name.
135  *
136  * The result must be g_free()'d when you're done with it.
137  *
138  * Note: given that this calls get_interface_list(), which attempts to
139  * open all adapters it finds in order to check whether they can be
140  * captured on, this is an expensive routine to call, so don't call it
141  * frequently.
142  */
143 char *
144 get_interface_descriptive_name(const char *if_name)
145 {
146   char *descr;
147   GList *if_list;
148   GList *if_entry;
149   if_info_t *if_info;
150   int err;
151
152   /* Do we have a user-supplied description? */
153   descr = capture_dev_user_descr_find(if_name);
154   if (descr != NULL) {
155     /* Yes - make a copy of that. */
156     descr = g_strdup(descr);
157   } else {
158     /* No, we don't have a user-supplied description; did we get
159        one from the OS or libpcap? */
160     descr = NULL;
161     if_list = get_interface_list(&err, NULL);
162     if (if_list != NULL && if_name != NULL) {
163       if_entry = if_list;
164       do {
165         if_info = if_entry->data;
166         if (strcmp(if_info->name, if_name) == 0) {
167           if (if_info->description != NULL) {
168             /* Return a copy of that - when we free the interface
169                list, that'll also free up the strings to which
170                it refers. */
171             descr = g_strdup(if_info->description);
172           }
173           break;
174         }
175       } while ((if_entry = g_list_next(if_entry)) != NULL);
176     }
177     free_interface_list(if_list);
178
179     if (descr == NULL) {
180       /* The interface name is all we have, so just return a copy of that. */
181       descr = g_strdup(if_name);
182     }
183   }
184
185   return descr;
186 }
187
188
189 /* search interface info by interface name */
190 static if_info_t *
191 search_info(GList *if_list, gchar *if_name)
192 {
193     GList *if_entry;
194     if_info_t *if_info;
195
196
197     for (if_entry = if_list; if_entry != NULL; if_entry = g_list_next(if_entry)) {
198         if_info = if_entry->data;
199
200         if(strcmp(if_name, if_info->name) == 0) {
201             return if_info;
202         }
203     }
204
205     return NULL;
206 }
207
208
209 /* build the string to display in the combo box for the given interface */
210 char *
211 build_capture_combo_name(GList *if_list, gchar *if_name)
212 {
213     gchar *descr;
214     char *if_string;
215     if_info_t *if_info;
216
217
218         /* Do we have a user-supplied description? */
219         descr = capture_dev_user_descr_find(if_name);
220         if (descr != NULL) {
221           /* Yes, we have a user-supplied description; use it. */
222           if_string = g_strdup_printf("%s: %s", descr, if_name);
223           g_free(descr);
224         } else {
225           /* No, we don't have a user-supplied description; did we get
226              one from the OS or libpcap? */
227       if_info = search_info(if_list, if_name);
228           if (if_info && if_info->description != NULL) {
229             /* Yes - use it. */
230             if_string = g_strdup_printf("%s: %s", if_info->description,
231                                         if_info->name);
232           } else {
233             /* No. */
234             if_string = g_strdup(if_name);
235           }
236         }
237
238     return if_string;
239 }
240
241
242 GList *
243 build_capture_combo_list(GList *if_list, gboolean do_hide)
244 {
245   GList *combo_list;
246   GList *if_entry;
247   if_info_t *if_info;
248   char *if_string;
249   gchar *descr;
250
251   combo_list = NULL;
252   if (if_list != NULL) {
253     /* Scan through the list and build a list of strings to display. */
254     for (if_entry = if_list; if_entry != NULL;
255          if_entry = g_list_next(if_entry)) {
256       if_info = if_entry->data;
257
258       /* Is this interface hidden and, if so, should we include it
259          anyway? */
260       if (!prefs_is_capture_device_hidden(if_info->name) || !do_hide) {
261         /* It's not hidden, or it is but we should include it in the list. */
262
263         /* Do we have a user-supplied description? */
264         descr = capture_dev_user_descr_find(if_info->name);
265         if (descr != NULL) {
266           /* Yes, we have a user-supplied description; use it. */
267           if_string = g_strdup_printf("%s: %s", descr, if_info->name);
268           g_free(descr);
269         } else {
270           /* No, we don't have a user-supplied description; did we get
271              one from the OS or libpcap? */
272           if (if_info->description != NULL) {
273             /* Yes - use it. */
274             if_string = g_strdup_printf("%s: %s", if_info->description,
275                                         if_info->name);
276           } else {
277             /* No. */
278             if_string = g_strdup(if_info->name);
279           }
280         }
281         combo_list = g_list_append(combo_list, if_string);
282       }
283     }
284   }
285   return combo_list;
286 }
287
288 static void
289 free_if_string(gpointer data, gpointer user_data _U_)
290 {
291   g_free(data);
292 }
293
294 void
295 free_capture_combo_list(GList *combo_list)
296 {
297   if (combo_list != NULL) {
298     g_list_foreach(combo_list, free_if_string, NULL);
299     g_list_free(combo_list);
300   }
301 }
302
303 /*
304  * Given text that contains an interface name possibly prefixed by an
305  * interface description, extract the interface name.
306  */
307 const char *
308 get_if_name(const char *if_text)
309 {
310   const char *if_name;
311
312 #ifdef _WIN32
313   /*
314    * We cannot assume that the interface name doesn't contain a space;
315    * some names on Windows OT do.
316    *
317    * We also can't assume it begins with "\Device\", either, as, on
318    * Windows OT, WinPcap doesn't put "\Device\" in front of the name.
319    *
320    * As I remember, we can't assume that the interface description
321    * doesn't contain a colon, either; I think some do.
322    *
323    * We can probably assume that the interface *name* doesn't contain
324    * a colon, however; if any interface name does contain a colon on
325    * Windows, it'll be time to just get rid of the damn interface
326    * descriptions in the drop-down list, have just the names in the
327    * drop-down list, and have a "Browse..." button to browse for interfaces,
328    * with names, descriptions, IP addresses, blah blah blah available when
329    * possible.
330    *
331    * So we search backwards for a colon.  If we don't find it, just
332    * return the entire string; otherwise, skip the colon and any blanks
333    * after it, and return that string.
334    */
335    if_name = if_text + strlen(if_text);
336    for (;;) {
337      if (if_name == if_text) {
338        /* We're at the beginning of the string; return it. */
339        break;
340      }
341      if_name--;
342      if (*if_name == ':') {
343        /*
344         * We've found a colon.
345         * Unfortunately, a colon is used in the string "rpcap://",
346         * which is used in case of a remote capture.
347         * So we'll check to make sure the colon isn't followed by "//";
348         * it'll be followed by a blank if it separates the description
349         * and the interface name.  (We don't wire in "rpcap", in case we
350         * support other protocols in the same syntax.)
351         * Unfortunately, another colon can be used in "rpcap://host:port/"
352         * before port. Check if colon is followed by digit.
353         */
354        if ((strncmp(if_name, "://", 3) != 0) && !isdigit(if_name[1])) {
355          /*
356           * OK, we've found a colon followed neither by "//" nor by digit.  
357           * Skip blanks following it.
358           */
359          if_name++;
360          while (*if_name == ' ')
361            if_name++;
362          break;
363        }
364      }
365      /* Keep looking for a colon not followed by "//". */
366    }
367 #else
368   /*
369    * There's a space between the interface description and name, and
370    * the interface name shouldn't have a space in it (it doesn't, on
371    * UNIX systems); look backwards in the string for a space.
372    *
373    * (An interface name might, however, contain a colon in it, which
374    * is why we don't use the colon search on UNIX.)
375    */
376   if_name = strrchr(if_text, ' ');
377   if (if_name == NULL) {
378     if_name = if_text;
379   } else {
380     if_name++;
381   }
382 #endif
383   return if_name;
384 }
385
386 /*  Return capture_opts->iface_descr (after setting it if it is not set)
387  *  This is necessary because capture_opts.c can't set iface_descr (at least
388  *  not without adding significant dependencies there).
389  */
390 const char *
391 get_iface_description(capture_options *capture_opts)
392 {
393         if (!capture_opts->iface_descr && capture_opts->iface)
394                 capture_opts->iface_descr = get_interface_descriptive_name(capture_opts->iface);
395
396         return(capture_opts->iface_descr);
397
398 }
399 #endif /* HAVE_LIBPCAP */