A small fix from Andrew Bartlett. The Short File Name is always in UNICODE.
[metze/wireshark/wip.git] / util.c
1 /* util.c
2  * Utility routines
3  *
4  * $Id: util.c,v 1.75 2003/12/21 12:19:39 ulfl Exp $
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 #ifdef HAVE_CONFIG_H
26 # include "config.h"
27 #endif
28
29 #ifdef HAVE_LIBPCAP
30 #include <pcap.h>
31 #endif /* HAVE_LIBPCAP */
32
33 #include <glib.h>
34
35 #include <stdlib.h>
36 #include <string.h>
37 #include <stdio.h>
38 #include <errno.h>
39
40 #ifdef HAVE_UNISTD_H
41 #include <unistd.h>
42 #endif
43
44 #ifdef HAVE_SYS_STAT_H
45 #include <sys/stat.h>
46 #endif
47
48 #ifdef NEED_SNPRINTF_H
49 # include "snprintf.h"
50 #endif
51
52 #ifdef NEED_MKSTEMP
53 #include "mkstemp.h"
54 #endif
55
56 #ifdef HAVE_IO_H
57 #include <io.h>
58 #ifndef __MINGW32__
59 typedef int mode_t;     /* for win32 */
60 #endif /* __MINGW32__ */
61 #endif /* HAVE_IO_H */
62
63 #ifdef HAVE_LIBZ
64 #include <zlib.h>       /* to get the libz version number */
65 #endif
66
67 #ifdef HAVE_LIBPCRE
68 #include <pcre.h>       /* to get the libpcre version number */
69 #endif /* HAVE_LIBPCRE */
70
71 /*
72  * This has to come after the include of <pcap.h>, as the include of
73  * <pcap.h> might cause <winsock2.h> to be included, and if we've
74  * already included <winsock.h> as a result of including <windows.h>,
75  * we get a bunch of redefinitions.
76  */
77 #ifdef HAVE_WINDOWS_H
78 #include <windows.h>
79 #endif
80
81 #ifdef HAVE_SOME_SNMP
82
83 #ifdef HAVE_NET_SNMP
84 #include <net-snmp/version.h>
85 #endif /* HAVE_NET_SNMP */
86
87 #ifdef HAVE_UCD_SNMP
88 #include <ucd-snmp/version.h>
89 #endif /* HAVE_UCD_SNMP */
90
91 #endif /* HAVE_SOME_SNMP */
92
93 #ifdef HAVE_SYS_UTSNAME_H
94 #include <sys/utsname.h>
95 #endif
96
97 #include "util.h"
98 #include "pcap-util.h"
99
100 /*
101  * See whether the last line in the string goes past column 80; if so,
102  * replace the blank at the specified point with a newline.
103  */
104 static void
105 do_word_wrap(GString *str, gint point)
106 {
107         char *line_begin;
108
109         line_begin = strrchr(str->str, '\n');
110         if (line_begin == NULL)
111                 line_begin = str->str;
112         else
113                 line_begin++;
114         if (strlen(line_begin) > 80) {
115                 g_assert(str->str[point] == ' ');
116                 str->str[point] = '\n';
117         }
118 }       
119
120 /*
121  * Get various library compile-time versions and append them to
122  * the specified GString.
123  */
124 void
125 get_compiled_version_info(GString *str)
126 {
127         gint break_point;
128
129         g_string_append(str, "with ");
130         g_string_sprintfa(str,
131 #ifdef GLIB_MAJOR_VERSION
132             "GLib %d.%d.%d,", GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION,
133             GLIB_MICRO_VERSION);
134 #else
135             "GLib (version unknown),");
136 #endif
137
138         g_string_append(str, " ");
139         break_point = str->len - 1;
140         get_compiled_pcap_version(str);
141         g_string_append(str, ",");
142         do_word_wrap(str, break_point);
143
144         g_string_append(str, " ");
145         break_point = str->len - 1;
146 #ifdef HAVE_LIBZ
147         g_string_append(str, "with libz ");
148 #ifdef ZLIB_VERSION
149         g_string_append(str, ZLIB_VERSION);
150 #else /* ZLIB_VERSION */
151         g_string_append(str, "(version unknown)");
152 #endif /* ZLIB_VERSION */
153 #else /* HAVE_LIBZ */
154         g_string_append(str, "without libz");
155 #endif /* HAVE_LIBZ */
156         g_string_append(str, ",");
157         do_word_wrap(str, break_point);
158
159         g_string_append(str, " ");
160         break_point = str->len - 1;
161 #ifdef HAVE_LIBPCRE
162         g_string_append(str, "with libpcre ");
163 #ifdef PCRE_MAJOR
164 #ifdef PCRE_MINOR
165         g_string_sprintfa(str, "%u.%u", PCRE_MAJOR, PCRE_MINOR);
166 #else                   /* PCRE_MINOR */
167         g_string_sprintfa(str, "%u", PCRE_MAJOR);
168 #endif                  /* PCRE_MINOR */
169 #else           /* PCRE_MAJOR */
170         g_string_append(str, "(version unknown)");
171 #endif          /* PCRE_MAJOR */
172 #else   /* HAVE_LIBPCRE */
173         g_string_append(str, "without libpcre");
174 #endif  /* HAVE_LIBPCRE */
175
176         g_string_append(str, ",");
177         do_word_wrap(str, break_point);
178
179 /* Oh, this is pretty. */
180 /* Oh, ha.  you think that was pretty.  Try this:! --Wes */
181         g_string_append(str, " ");
182         break_point = str->len - 1;
183 #ifdef HAVE_SOME_SNMP
184
185 #ifdef HAVE_UCD_SNMP
186         g_string_append(str, "with UCD-SNMP ");
187         g_string_append(str, VersionInfo);
188 #endif /* HAVE_UCD_SNMP */
189
190 #ifdef HAVE_NET_SNMP
191         g_string_append(str, "with Net-SNMP ");
192         g_string_append(str, netsnmp_get_version());
193 #endif /* HAVE_NET_SNMP */
194
195 #else /* no SNMP library */
196         g_string_append(str, "without UCD-SNMP or Net-SNMP");
197 #endif /* HAVE_SOME_SNMP */
198         g_string_append(str, ",");
199         do_word_wrap(str, break_point);
200
201         g_string_append(str, " ");
202         break_point = str->len - 1;
203 #ifdef HAVE_GNU_ADNS
204         g_string_append(str, "with ADNS");
205 #else
206         g_string_append(str, "without ADNS");
207 #endif /* HAVE_GNU_ADNS */
208
209         g_string_append(str, ".");
210         do_word_wrap(str, break_point);
211
212 #ifndef HAVE_LIBPCRE
213         break_point = str->len - 1;
214         g_string_append(str,
215                         "\nNOTE: this build does not support the \"matches\" operator"
216                         "\nfor Ethereal filter syntax.\n");
217         do_word_wrap(str, break_point);
218 #endif  /* HAVE_LIBPCRE */
219 }
220
221 /*
222  * Get various library run-time versions, and the OS version, and append
223  * them to the specified GString.
224  */
225 void
226 get_runtime_version_info(GString *str)
227 {
228 #if defined(WIN32)
229         OSVERSIONINFO info;
230 #elif defined(HAVE_SYS_UTSNAME_H)
231         struct utsname name;
232 #endif
233
234         get_runtime_pcap_version(str);
235
236         g_string_append(str, "on ");
237 #if defined(WIN32)
238         info.dwOSVersionInfoSize = sizeof info;
239         if (!GetVersionEx(&info)) {
240                 /*
241                  * XXX - get the failure reason.
242                  */
243                 g_string_append(str, "unknown Windows version");
244                 return;
245         }
246         switch (info.dwPlatformId) {
247
248         case VER_PLATFORM_WIN32s:
249                 /* Shyeah, right. */
250                 g_string_sprintfa(str, "Windows 3.1 with Win32s");
251                 break;
252
253         case VER_PLATFORM_WIN32_WINDOWS:
254                 /* Windows OT */
255                 switch (info.dwMajorVersion) {
256
257                 case 4:
258                         /* 3 cheers for Microsoft marketing! */
259                         switch (info.dwMinorVersion) {
260
261                         case 0:
262                                 g_string_sprintfa(str, "Windows 95");
263                                 break;
264
265                         case 10:
266                                 g_string_sprintfa(str, "Windows 98");
267                                 break;
268
269                         case 90:
270                                 g_string_sprintfa(str, "Windows Me");
271                                 break;
272
273                         default:
274                                 g_string_sprintfa(str, "Windows OT, unknown version %lu.%lu",
275                                     info.dwMajorVersion, info.dwMinorVersion);
276                                 break;
277                         }
278                         break;
279
280                 default:
281                         g_string_sprintfa(str, "Windows OT, unknown version %lu.%lu",
282                             info.dwMajorVersion, info.dwMinorVersion);
283                         break;
284                 }
285                 break;
286
287         case VER_PLATFORM_WIN32_NT:
288                 /* Windows NT */
289                 switch (info.dwMajorVersion) {
290
291                 case 3:
292                 case 4:
293                         g_string_sprintfa(str, "Windows NT %lu.%lu",
294                             info.dwMajorVersion, info.dwMinorVersion);
295                         break;
296
297                 case 5:
298                         /* 3 cheers for Microsoft marketing! */
299                         switch (info.dwMinorVersion) {
300
301                         case 0:
302                                 g_string_sprintfa(str, "Windows 2000");
303                                 break;
304
305                         case 1:
306                                 g_string_sprintfa(str, "Windows XP");
307                                 break;
308
309                         case 2:
310                                 g_string_sprintfa(str, "Windows Server 2003");
311                                 break;
312
313                         default:
314                                 g_string_sprintfa(str, "Windows NT, unknown version %lu.%lu",
315                                     info.dwMajorVersion, info.dwMinorVersion);
316                                 break;
317                         }
318                         break;
319
320                 default:
321                         g_string_sprintfa(str, "Windows NT, unknown version %lu.%lu",
322                             info.dwMajorVersion, info.dwMinorVersion);
323                         break;
324                 }
325                 break;
326
327         default:
328                 g_string_sprintfa(str, "Unknown Windows platform %lu version %lu.%lu",
329                     info.dwPlatformId, info.dwMajorVersion, info.dwMinorVersion);
330                 break;
331         }
332         if (info.szCSDVersion[0] != '\0')
333                 g_string_sprintfa(str, " %s", info.szCSDVersion);
334         g_string_sprintfa(str, ", build %lu", info.dwBuildNumber);
335 #elif defined(HAVE_SYS_UTSNAME_H)
336         /*
337          * We have <sys/utsname.h>, so we assume we have "uname()".
338          */
339         if (uname(&name) < 0) {
340                 g_string_sprintfa(str, "unknown OS version (uname failed - %s)",
341                     strerror(errno));
342                 return;
343         }
344
345         if (strcmp(name.sysname, "AIX") == 0) {
346                 /*
347                  * Yay, IBM!  Thanks for doing something different
348                  * from most of the other UNIXes out there, and
349                  * making "name.version" apparently be the major
350                  * version number and "name.release" be the minor
351                  * version number.
352                  */
353                 g_string_sprintfa(str, "%s %s.%s", name.sysname, name.version,
354                     name.release);
355         } else {
356                 /*
357                  * XXX - get "version" on any other platforms?
358                  *
359                  * On Digital/Tru65 UNIX, it's something unknown.
360                  * On Solaris, it's some kind of build information.
361                  * On HP-UX, it appears to be some sort of subrevision
362                  * thing.
363                  */
364                 g_string_sprintfa(str, "%s %s", name.sysname, name.release);
365         }
366 #else
367         g_string_append(str, "an unknown OS");
368 #endif
369 }
370
371 /*
372  * Collect command-line arguments as a string consisting of the arguments,
373  * separated by spaces.
374  */
375 char *
376 get_args_as_string(int argc, char **argv, int optind)
377 {
378         int len;
379         int i;
380         char *argstring;
381
382         /*
383          * Find out how long the string will be.
384          */
385         len = 0;
386         for (i = optind; i < argc; i++) {
387                 len += strlen(argv[i]);
388                 len++;  /* space, or '\0' if this is the last argument */
389         }
390
391         /*
392          * Allocate the buffer for the string.
393          */
394         argstring = g_malloc(len);
395
396         /*
397          * Now construct the string.
398          */
399         strcpy(argstring, "");
400         i = optind;
401         for (;;) {
402                 strcat(argstring, argv[i]);
403                 i++;
404                 if (i == argc)
405                         break;
406                 strcat(argstring, " ");
407         }
408         return argstring;
409 }
410
411 static char *
412 setup_tmpdir(char *dir)
413 {
414         int len = strlen(dir);
415         char *newdir;
416
417         /* Append slash if necessary */
418         if (dir[len - 1] == '/') {
419                 newdir = dir;
420         }
421         else {
422                 newdir = g_malloc(len + 2);
423                 strcpy(newdir, dir);
424                 strcat(newdir, "/");
425         }
426         return newdir;
427 }
428
429 static int
430 try_tempfile(char *namebuf, int namebuflen, const char *dir, const char *pfx)
431 {
432         static const char suffix[] = "XXXXXXXXXX";
433         int namelen = strlen(dir) + strlen(pfx) + sizeof suffix;
434         mode_t old_umask;
435         int tmp_fd;
436
437         if (namebuflen < namelen) {
438                 /* Stick in a truncated name, so that if this error is
439                    reported with the file name, you at least get
440                    something. */
441                 snprintf(namebuf, namebuflen, "%s%s%s", dir, pfx, suffix);
442                 errno = ENAMETOOLONG;
443                 return -1;
444         }
445         strcpy(namebuf, dir);
446         strcat(namebuf, pfx);
447         strcat(namebuf, suffix);
448
449         /* The Single UNIX Specification doesn't say that "mkstemp()"
450            creates the temporary file with mode rw-------, so we
451            won't assume that all UNIXes will do so; instead, we set
452            the umask to 0077 to take away all group and other
453            permissions, attempt to create the file, and then put
454            the umask back. */
455         old_umask = umask(0077);
456         tmp_fd = mkstemp(namebuf);
457         umask(old_umask);
458         return tmp_fd;
459 }
460
461 static char *tmpdir = NULL;
462 #ifdef WIN32
463 static char *temp = NULL;
464 #endif
465 static char *E_tmpdir;
466
467 #ifndef P_tmpdir
468 #define P_tmpdir "/var/tmp"
469 #endif
470
471 int
472 create_tempfile(char *namebuf, int namebuflen, const char *pfx)
473 {
474         char *dir;
475         int fd;
476         static gboolean initialized;
477
478         if (!initialized) {
479                 if ((dir = getenv("TMPDIR")) != NULL)
480                         tmpdir = setup_tmpdir(dir);
481 #ifdef WIN32
482                 if ((dir = getenv("TEMP")) != NULL)
483                         temp = setup_tmpdir(dir);
484 #endif
485
486                 E_tmpdir = setup_tmpdir(P_tmpdir);
487                 initialized = TRUE;
488         }
489
490         if (tmpdir != NULL) {
491                 fd = try_tempfile(namebuf, namebuflen, tmpdir, pfx);
492                 if (fd != -1)
493                         return fd;
494         }
495
496 #ifdef WIN32
497         if (temp != NULL) {
498                 fd = try_tempfile(namebuf, namebuflen, temp, pfx);
499                 if (fd != -1)
500                         return fd;
501         }
502 #endif
503
504         fd = try_tempfile(namebuf, namebuflen, E_tmpdir, pfx);
505         if (fd != -1)
506                 return fd;
507
508         return try_tempfile(namebuf, namebuflen, "/tmp", pfx);
509 }
510
511 /* ASCII/EBCDIC conversion tables from
512  * http://www.room42.com/store/computer_center/code_tables.shtml
513  */
514 #if 0
515 static guint8 ASCII_translate_EBCDIC [ 256 ] = {
516     0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
517     0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
518     0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
519     0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
520     0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D, 0x4D,
521     0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61,
522     0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8,
523     0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F,
524     0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8,
525     0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6,
526     0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7,
527     0xE8, 0xE9, 0xAD, 0xE0, 0xBD, 0x5F, 0x6D,
528     0x7D, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88,
529     0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96,
530     0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7,
531     0xA8, 0xA9, 0xC0, 0x6A, 0xD0, 0xA1, 0x4B,
532     0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
533     0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
534     0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
535     0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
536     0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
537     0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
538     0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
539     0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
540     0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
541     0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
542     0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
543     0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
544     0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
545     0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
546     0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
547     0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B
548 };
549
550 void
551 ASCII_to_EBCDIC(guint8 *buf, guint bytes)
552 {
553         guint   i;
554         guint8  *bufptr;
555
556         bufptr = buf;
557
558         for (i = 0; i < bytes; i++, bufptr++) {
559                 *bufptr = ASCII_translate_EBCDIC[*bufptr];
560         }
561 }
562
563 guint8
564 ASCII_to_EBCDIC1(guint8 c)
565 {
566         return ASCII_translate_EBCDIC[c];
567 }
568 #endif
569
570 static guint8 EBCDIC_translate_ASCII [ 256 ] = {
571     0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
572     0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
573     0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
574     0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
575     0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
576     0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
577     0x2E, 0x2E, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
578     0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x2E, 0x3F,
579     0x20, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E,
580     0x2E, 0x2E, 0x2E, 0x3C, 0x28, 0x2B, 0x7C,
581     0x26, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E,
582     0x2E, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0x5E,
583     0x2D, 0x2F, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E,
584     0x2E, 0x7C, 0x2C, 0x25, 0x5F, 0x3E, 0x3F,
585     0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E,
586     0x2E, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22,
587     0x2E, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
588     0x69, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E,
589     0x2E, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71,
590     0x72, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E,
591     0x2E, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
592     0x7A, 0x2E, 0x2E, 0x2E, 0x5B, 0x2E, 0x2E,
593     0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E,
594     0x2E, 0x2E, 0x2E, 0x2E, 0x5D, 0x2E, 0x2E,
595     0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
596     0x49, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E,
597     0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51,
598     0x52, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E,
599     0x5C, 0x2E, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
600     0x5A, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E,
601     0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
602     0x39, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E
603 };
604
605 void
606 EBCDIC_to_ASCII(guint8 *buf, guint bytes)
607 {
608         guint   i;
609         guint8  *bufptr;
610
611         bufptr = buf;
612
613         for (i = 0; i < bytes; i++, bufptr++) {
614                 *bufptr = EBCDIC_translate_ASCII[*bufptr];
615         }
616 }
617
618 guint8
619 EBCDIC_to_ASCII1(guint8 c)
620 {
621         return EBCDIC_translate_ASCII[c];
622 }
623
624 /* Compute the difference between two seconds/microseconds time stamps. */
625 void
626 compute_timestamp_diff(gint *diffsec, gint *diffusec,
627         guint32 sec1, guint32 usec1, guint32 sec2, guint32 usec2)
628 {
629   if (sec1 == sec2) {
630     /* The seconds part of the first time is the same as the seconds
631        part of the second time, so if the microseconds part of the first
632        time is less than the microseconds part of the second time, the
633        first time is before the second time.  The microseconds part of
634        the delta should just be the difference between the microseconds
635        part of the first time and the microseconds part of the second
636        time; don't adjust the seconds part of the delta, as it's OK if
637        the microseconds part is negative. */
638
639     *diffsec = sec1 - sec2;
640     *diffusec = usec1 - usec2;
641   } else if (sec1 <= sec2) {
642     /* The seconds part of the first time is less than the seconds part
643        of the second time, so the first time is before the second time.
644
645        Both the "seconds" and "microseconds" value of the delta
646        should have the same sign, so if the difference between the
647        microseconds values would be *positive*, subtract 1,000,000
648        from it, and add one to the seconds value. */
649     *diffsec = sec1 - sec2;
650     if (usec2 >= usec1) {
651       *diffusec = usec1 - usec2;
652     } else {
653       *diffusec = (usec1 - 1000000) - usec2;
654       (*diffsec)++;
655     }
656   } else {
657     /* Oh, good, we're not caught in a chronosynclastic infindibulum. */
658     *diffsec = sec1 - sec2;
659     if (usec2 <= usec1) {
660       *diffusec = usec1 - usec2;
661     } else {
662       *diffusec = (usec1 + 1000000) - usec2;
663       (*diffsec)--;
664     }
665   }
666 }
667
668 /* Decode a base64 string in-place - simple and slow algorithm.
669    Return length of result. Taken from rproxy/librsync/base64.c by
670    Andrew Tridgell. */
671
672 size_t base64_decode(char *s)
673 {
674         static const char b64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
675         int bit_offset, byte_offset, idx, i, n;
676         unsigned char *d = (unsigned char *)s;
677         char *p;
678
679         n=i=0;
680
681         while (*s && (p=strchr(b64, *s))) {
682                 idx = (int)(p - b64);
683                 byte_offset = (i*6)/8;
684                 bit_offset = (i*6)%8;
685                 d[byte_offset] &= ~((1<<(8-bit_offset))-1);
686                 if (bit_offset < 3) {
687                         d[byte_offset] |= (idx << (2-bit_offset));
688                         n = byte_offset+1;
689                 } else {
690                         d[byte_offset] |= (idx >> (bit_offset-2));
691                         d[byte_offset+1] = 0;
692                         d[byte_offset+1] |= (idx << (8-(bit_offset-2))) & 0xFF;
693                         n = byte_offset+2;
694                 }
695                 s++; i++;
696         }
697
698         return n;
699 }
700
701 /* Try to figure out if we're remotely connected, e.g. via ssh or
702    Terminal Server, and create a capture filter that matches aspects of the
703    connection.  We match the following environment variables:
704    
705    SSH_CONNECTION (ssh): <remote IP> <remote port> <local IP> <local port>
706    SSH_CLIENT (ssh): <remote IP> <remote port> <local port>
707    REMOTEHOST (tcsh, others?): <remote name>
708    DISPLAY (x11): [remote name]:<display num>
709    CLIENTNAME (terminal server): <remote name>
710  */
711
712 gchar *get_conn_cfilter(void) {
713         static GString *filter_str = NULL;
714         gchar *env, **tokens;
715         
716         if (filter_str == NULL) {
717                 filter_str = g_string_new("");
718         }
719         if ((env = getenv("SSH_CONNECTION")) != NULL) {
720                 tokens = g_strsplit(env, " ", 4);
721                 if (tokens[3]) {
722                         g_string_sprintf(filter_str, "not (tcp port %s and ip host %s "
723                                 "and tcp port %s and ip host %s)", tokens[1], tokens[0],
724                                 tokens[3], tokens[2]);
725                         return filter_str->str;
726                 }
727         } else if ((env = getenv("SSH_CLIENT")) != NULL) {
728                 tokens = g_strsplit(env, " ", 3);
729                 g_string_sprintf(filter_str, "not (tcp port %s and ip host %s "
730                         "and tcp port %s)", tokens[1], tokens[0], tokens[2]);
731                 return filter_str->str;
732         } else if ((env = getenv("REMOTEHOST")) != NULL) {
733                 g_string_sprintf(filter_str, "not ip host %s", env);
734                 return filter_str->str;
735         } else if ((env = getenv("DISPLAY")) != NULL) {
736                 tokens = g_strsplit(env, ":", 2);
737                 if (tokens[0] && tokens[0][0] != 0) {
738                         g_string_sprintf(filter_str, "not ip host %s", 
739                                 tokens[0]);
740                         return filter_str->str;
741                 }
742         } else if ((env = getenv("CLIENTNAME")) != NULL) {
743                 if (g_strcasecmp("console", env) != 0) {
744                         g_string_sprintf(filter_str, "not ip host %s", env);
745                         return filter_str->str;
746                 }
747         }
748         return "";
749 }               
750