Qt: Add version check for setTextInteractionFlags
[metze/wireshark/wip.git] / ui / util.c
1 /* util.c
2  * Utility routines
3  *
4  * Wireshark - Network traffic analyzer
5  * By Gerald Combs <gerald@wireshark.org>
6  * Copyright 1998 Gerald Combs
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21  */
22
23 #include "config.h"
24
25 #include <glib.h>
26
27 #include <stdlib.h>
28 #include <string.h>
29 #include <errno.h>
30
31 #ifdef HAVE_UNISTD_H
32 #include <unistd.h>
33 #endif
34
35 #ifdef HAVE_WINDOWS_H
36 #include <windows.h>
37 #endif
38
39 #include "epan/address.h"
40 #include "epan/addr_resolv.h"
41 #include "epan/strutil.h"
42
43 #include "ui/util.h"
44
45 /*
46  * Collect command-line arguments as a string consisting of the arguments,
47  * separated by spaces.
48  */
49 char *
50 get_args_as_string(int argc, char **argv, int optindex)
51 {
52     int len;
53     int i;
54     char *argstring;
55
56     /*
57      * Find out how long the string will be.
58      */
59     len = 0;
60     for (i = optindex; i < argc; i++) {
61         len += (int) strlen(argv[i]);
62         len++;    /* space, or '\0' if this is the last argument */
63     }
64
65     /*
66      * Allocate the buffer for the string.
67      */
68     argstring = (char *)g_malloc(len);
69
70     /*
71      * Now construct the string.
72      */
73     argstring[0] = '\0';
74     i = optindex;
75     for (;;) {
76         g_strlcat(argstring, argv[i], len);
77         i++;
78         if (i == argc)
79             break;
80         g_strlcat(argstring, " ", len);
81     }
82     return argstring;
83 }
84
85 /* Compute the difference between two seconds/microseconds time stamps. */
86 void
87 compute_timestamp_diff(gint *diffsec, gint *diffusec,
88     guint32 sec1, guint32 usec1, guint32 sec2, guint32 usec2)
89 {
90   if (sec1 == sec2) {
91     /* The seconds part of the first time is the same as the seconds
92        part of the second time, so if the microseconds part of the first
93        time is less than the microseconds part of the second time, the
94        first time is before the second time.  The microseconds part of
95        the delta should just be the difference between the microseconds
96        part of the first time and the microseconds part of the second
97        time; don't adjust the seconds part of the delta, as it's OK if
98        the microseconds part is negative. */
99
100     *diffsec = sec1 - sec2;
101     *diffusec = usec1 - usec2;
102   } else if (sec1 <= sec2) {
103     /* The seconds part of the first time is less than the seconds part
104        of the second time, so the first time is before the second time.
105
106        Both the "seconds" and "microseconds" value of the delta
107        should have the same sign, so if the difference between the
108        microseconds values would be *positive*, subtract 1,000,000
109        from it, and add one to the seconds value. */
110     *diffsec = sec1 - sec2;
111     if (usec2 >= usec1) {
112       *diffusec = usec1 - usec2;
113     } else {
114       *diffusec = (usec1 - 1000000) - usec2;
115       (*diffsec)++;
116     }
117   } else {
118     /* Oh, good, we're not caught in a chronosynclastic infindibulum. */
119     *diffsec = sec1 - sec2;
120     if (usec2 <= usec1) {
121       *diffusec = usec1 - usec2;
122     } else {
123       *diffusec = (usec1 + 1000000) - usec2;
124       (*diffsec)--;
125     }
126   }
127 }
128
129 /* Remove any %<interface_name> from an IP address. */
130 static char *sanitize_filter_ip(char *hostname) {
131     gchar *end;
132     gchar *ret;
133
134     ret = g_strdup(hostname);
135     if (!ret)
136         return NULL;
137
138     end = strchr(ret, '%');
139     if (end)
140         *end = '\0';
141     return ret;
142 }
143
144 /* Try to figure out if we're remotely connected, e.g. via ssh or
145    Terminal Server, and create a capture filter that matches aspects of the
146    connection.  We match the following environment variables:
147
148    SSH_CONNECTION (ssh): <remote IP> <remote port> <local IP> <local port>
149    SSH_CLIENT (ssh): <remote IP> <remote port> <local port>
150    REMOTEHOST (tcsh, others?): <remote name>
151    DISPLAY (x11): [remote name]:<display num>
152    SESSIONNAME (terminal server): <remote name>
153  */
154
155 const gchar *get_conn_cfilter(void) {
156     static GString *filter_str = NULL;
157     gchar *env, **tokens;
158     char *lastp, *lastc, *p;
159     char *pprotocol = NULL;
160     char *phostname = NULL;
161     size_t hostlen;
162     char *remip, *locip;
163
164     if (filter_str == NULL) {
165         filter_str = g_string_new("");
166     }
167     if ((env = getenv("SSH_CONNECTION")) != NULL) {
168         tokens = g_strsplit(env, " ", 4);
169         if (g_strv_length(tokens) == 4) {
170             remip = sanitize_filter_ip(tokens[0]);
171             locip = sanitize_filter_ip(tokens[2]);
172             g_string_printf(filter_str, "not (tcp port %s and host %s "
173                              "and tcp port %s and host %s)", tokens[1], remip,
174                 tokens[3], locip);
175             g_free(remip);
176             g_free(locip);
177         }
178         g_strfreev(tokens);
179     } else if ((env = getenv("SSH_CLIENT")) != NULL) {
180         tokens = g_strsplit(env, " ", 3);
181         if (g_strv_length(tokens) == 3) {
182             remip = sanitize_filter_ip(tokens[2]);
183             g_string_printf(filter_str, "not (tcp port %s and host %s "
184                 "and tcp port %s)", tokens[1], tokens[0], remip);
185             g_free(remip);
186         }
187         g_strfreev(tokens);
188     } else if ((env = getenv("REMOTEHOST")) != NULL) {
189         /* FreeBSD 7.0 sets REMOTEHOST to an empty string */
190         if (g_ascii_strcasecmp(env, "localhost") == 0 ||
191             strcmp(env, "127.0.0.1") == 0 ||
192             strcmp(env, "") == 0) {
193             return "";
194         }
195         remip = sanitize_filter_ip(env);
196         g_string_printf(filter_str, "not host %s", remip);
197         g_free(remip);
198     } else if ((env = getenv("DISPLAY")) != NULL) {
199         /*
200          * This mirrors what _X11TransConnectDisplay() does.
201          * Note that, on some systems, the hostname can
202          * begin with "/", which means that it's a pathname
203          * of a UNIX domain socket to connect to.
204          *
205          * The comments mirror those in _X11TransConnectDisplay(),
206          * too. :-)
207          *
208          * Display names may be of the following format:
209          *
210          *    [protoco./] [hostname] : [:] displaynumber [.screennumber]
211          *
212          * A string with exactly two colons separating hostname
213          * from the display indicates a DECnet style name.  Colons
214          * in the hostname may occur if an IPv6 numeric address
215          * is used as the hostname.  An IPv6 numeric address may
216          * also end in a double colon, so three colons in a row
217          * indicates an IPv6 address ending in :: followed by
218          * :display.  To make it easier for people to read, an
219          * IPv6 numeric address hostname may be surrounded by []
220          * in a similar fashion to the IPv6 numeric address URL
221          * syntax defined by IETF RFC 2732.
222          *
223          * If no hostname and no protocol is specified, the string
224          * is interpreted as the most efficient local connection
225          * to a server on the same machine.  This is usually:
226          *
227          *    o shared memory
228          *    o local stream
229          *    o UNIX domain socket
230          *    o TCP to local host.
231          */
232
233         p = env;
234
235         /*
236          * Step 0, find the protocol.  This is delimited by
237          * the optional slash ('/').
238          */
239         for (lastp = p; *p != '\0' && *p != ':' && *p != '/'; p++)
240             ;
241         if (*p == '\0')
242             return "";    /* must have a colon */
243
244         if (p != lastp && *p != ':') {    /* protocol given? */
245             /* Yes */
246             pprotocol = p;
247
248             /* Is it TCP? */
249             if (p - lastp != 3 || g_ascii_strncasecmp(lastp, "tcp", 3) != 0)
250                 return "";    /* not TCP */
251             p++;            /* skip the '/' */
252         } else
253             p = env;        /* reset the pointer in
254                            case no protocol was given */
255
256         /*
257          * Step 1, find the hostname.  This is delimited either by
258          * one colon, or two colons in the case of DECnet (DECnet
259          * Phase V allows a single colon in the hostname).  (See
260          * note above regarding IPv6 numeric addresses with
261          * triple colons or [] brackets.)
262          */
263         lastp = p;
264         lastc = NULL;
265         for (; *p != '\0'; p++)
266             if (*p == ':')
267                 lastc = p;
268
269         if (lastc == NULL)
270             return "";        /* must have a colon */
271
272         if ((lastp != lastc) && (*(lastc - 1) == ':')
273             && (((lastc - 1) == lastp) || (*(lastc - 2) != ':'))) {
274                 /* DECnet display specified */
275                 return "";
276         } else
277             hostlen = lastc - lastp;
278
279         if (hostlen == 0)
280             return "";    /* no hostname supplied */
281
282         phostname = (char *)g_malloc(hostlen + 1);
283         memcpy(phostname, lastp, hostlen);
284         phostname[hostlen] = '\0';
285
286         if (pprotocol == NULL) {
287             /*
288              * No protocol was explicitly specified, so it
289              * could be a local connection over a transport
290              * that we won't see.
291              *
292              * Does the host name refer to the local host?
293              * If so, the connection would probably be a
294              * local connection.
295              *
296              * XXX - compare against our host name?
297              * _X11TransConnectDisplay() does.
298              */
299             if (g_ascii_strcasecmp(phostname, "localhost") == 0 ||
300                 strcmp(phostname, "127.0.0.1") == 0) {
301                     g_free(phostname);
302                 return "";
303             }
304
305             /*
306              * A host name of "unix" (case-sensitive) also
307              * causes a local connection.
308              */
309             if (strcmp(phostname, "unix") == 0) {
310                     g_free(phostname);
311                 return "";
312             }
313
314             /*
315              * Does the host name begin with "/"?  If so,
316              * it's presumed to be the pathname of a
317              * UNIX domain socket.
318              */
319             if (phostname[0] == '/') {
320                 g_free(phostname);
321                 return "";
322             }
323         }
324
325         g_string_printf(filter_str, "not host %s", phostname);
326         g_free(phostname);
327 #ifdef _WIN32
328     } else if (GetSystemMetrics(SM_REMOTESESSION)) {
329         /* We have a remote session: http://msdn.microsoft.com/en-us/library/aa380798%28VS.85%29.aspx */
330         g_string_printf(filter_str, "not port 3389");
331 #endif /* _WIN32 */
332     } else {
333         return "";
334     }
335     return filter_str->str;
336 }
337
338 gboolean display_is_remote(void)
339 {
340     static gboolean remote_display_checked;
341     static gboolean is_remote;
342
343     if (!remote_display_checked) {
344         is_remote = (strlen(get_conn_cfilter()) > 0);
345     }
346     return is_remote;
347 }
348
349 /*
350  * Editor modelines
351  *
352  * Local Variables:
353  * c-basic-offset: 4
354  * tab-width: 8
355  * indent-tabs-mode: nil
356  * End:
357  *
358  * ex: set shiftwidth=4 tabstop=8 expandtab:
359  * :indentSize=4:tabSize=8:noTabs=true:
360  */