Move some more stuff into wsutil.
[metze/wireshark/wip.git] / ui / qt / main.cpp
1 /* main.cpp
2  *
3  * Wireshark - Network traffic analyzer
4  * By Gerald Combs <gerald@wireshark.org>
5  * Copyright 1998 Gerald Combs
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20  */
21
22 #include "config.h"
23
24 #include "wireshark_application.h"
25 #include "main_window.h"
26
27 #include <ctype.h>
28 #include "globals.h"
29
30 #include <glib.h>
31
32 #include <signal.h>
33
34 #ifdef HAVE_LIBZ
35 #include <zlib.h>       /* to get the libz version number */
36 #endif
37
38 #ifndef HAVE_GETOPT
39 #  include "wsutil/wsgetopt.h"
40 #else
41 #  include <getopt.h>
42 #endif
43
44 #include <wsutil/clopts_common.h>
45 #include <wsutil/cmdarg_err.h>
46 #include <wsutil/crash_info.h>
47 #include <wsutil/filesystem.h>
48 #include <wsutil/file_util.h>
49 #include <wsutil/privileges.h>
50 #ifdef HAVE_PLUGINS
51 #include <wsutil/plugins.h>
52 #endif
53 #include <wsutil/report_err.h>
54 #include <wsutil/u3.h>
55 #include <wsutil/copyright_info.h>
56 #include <wsutil/ws_version_info.h>
57
58 #include <wiretap/merge.h>
59
60 #include <epan/epan.h>
61 #include <epan/epan_dissect.h>
62 #include <epan/timestamp.h>
63 #include <epan/packet.h>
64 #include <epan/dfilter/dfilter.h>
65 #include <epan/strutil.h>
66 #include <epan/addr_resolv.h>
67 #include <epan/emem.h>
68 #include <epan/ex-opt.h>
69 #include <epan/funnel.h>
70 #include <epan/expert.h>
71 #include <epan/frequency-utils.h>
72 #include <epan/prefs.h>
73 #include <epan/prefs-int.h>
74 #include <epan/tap.h>
75 #include <epan/stat_cmd_args.h>
76 #include <epan/uat.h>
77 #include <epan/column.h>
78 #include <epan/disabled_protos.h>
79 #include <epan/print.h>
80
81 #ifdef HAVE_PLUGINS
82 #include <codecs/codecs.h>
83 #endif
84
85 /* general (not Qt specific) */
86 #include "file.h"
87 #include "summary.h"
88 #include "color.h"
89 #include "color_filters.h"
90 #include "register.h"
91 #include "ringbuffer.h"
92 #include "ui/util.h"
93 #include "version_info.h"
94 #include "log.h"
95
96 #include "ui/alert_box.h"
97 #include "ui/capture_globals.h"
98 #include "ui/iface_lists.h"
99 #include "ui/main_statusbar.h"
100 #include "ui/persfilepath_opt.h"
101 #include "ui/recent.h"
102 #include "ui/simple_dialog.h"
103 #include "ui/ui_util.h"
104
105 #ifdef HAVE_LIBPCAP
106 #  include "capture_ui_utils.h"
107 #  include "capture-pcap-util.h"
108 #  include <capchild/capture_ifinfo.h>
109 #  include "capture.h"
110 #  include <capchild/capture_sync.h>
111 #endif
112
113 #ifdef _WIN32
114 #  include "capture-wpcap.h"
115 #  include "capture_wpcap_packet.h"
116 #  include <tchar.h> /* Needed for Unicode */
117 #  include <wsutil/unicode-utils.h>
118 #  include <commctrl.h>
119 #  include <shellapi.h>
120 #  include <conio.h>
121 #  include "ui/win32/console_win32.h"
122 #endif /* _WIN32 */
123
124 #ifdef HAVE_AIRPCAP
125 #  include <airpcap.h>
126 #  include "airpcap_loader.h"
127 //#  include "airpcap_dlg.h"
128 //#  include "airpcap_gui_utils.h"
129 #endif
130
131 #include <epan/crypt/airpdcap_ws.h>
132
133 #include <QDebug>
134 #include <QDateTime>
135 #if (QT_VERSION < QT_VERSION_CHECK(5, 0, 0))
136 #include <QTextCodec>
137 #endif
138 #include <qtranslator.h>
139 #include <qlocale.h>
140 #include <qlibraryinfo.h>
141
142 #ifdef HAVE_LIBPCAP
143 capture_options global_capture_opts;
144 capture_session global_capture_session;
145 #endif
146
147 capture_file cfile;
148
149 #ifdef HAVE_AIRPCAP
150 int    airpcap_dll_ret_val = -1;
151 #endif
152
153 GString *comp_info_str, *runtime_info_str;
154
155 //static gboolean have_capture_file = FALSE; /* XXX - is there an equivalent in cfile? */
156
157 static void console_log_handler(const char *log_domain,
158     GLogLevelFlags log_level, const char *message, gpointer user_data);
159
160
161 #ifdef HAVE_LIBPCAP
162 extern capture_options global_capture_opts;
163
164 static void
165 main_capture_callback(gint event, capture_session *cap_session, gpointer user_data )
166 {
167     Q_UNUSED(user_data);
168     wsApp->captureCallback(event, cap_session);
169 }
170 #endif // HAVE_LIBPCAP
171
172 static void
173 main_cf_callback(gint event, gpointer data, gpointer user_data )
174 {
175     Q_UNUSED(user_data);
176     wsApp->captureFileCallback(event, data);
177 }
178
179 /* update the main window */
180 void main_window_update(void)
181 {
182     WiresharkApplication::processEvents();
183 }
184
185 #ifdef HAVE_LIBPCAP
186
187 /* quit a nested main window */
188 void main_window_nested_quit(void)
189 {
190 //    if (gtk_main_level() > 0)
191     wsApp->quit();
192 }
193
194 /* quit the main window */
195 void main_window_quit(void)
196 {
197     wsApp->quit();
198 }
199
200 #endif /* HAVE_LIBPCAP */
201
202
203 // xxx copied from ../gtk/main.c
204 static void
205 print_usage(gboolean print_ver) {
206     FILE *output;
207
208 #ifdef _WIN32
209     create_console();
210 #endif
211
212     if (print_ver) {
213         output = stdout;
214         fprintf(output, "Wireshark %s\n"
215                 "Interactively dump and analyze network traffic.\n"
216                 "See http://www.wireshark.org for more information.\n"
217                 "\n"
218                 "%s",
219                 get_ws_vcs_version_info(), get_copyright_info());
220     } else {
221         output = stderr;
222     }
223     fprintf(output, "\n");
224     fprintf(output, "Usage: wireshark [options] ... [ <infile> ]\n");
225     fprintf(output, "\n");
226
227 #ifdef HAVE_LIBPCAP
228     fprintf(output, "Capture interface:\n");
229     fprintf(output, "  -i <interface>           name or idx of interface (def: first non-loopback)\n");
230     fprintf(output, "  -f <capture filter>      packet filter in libpcap filter syntax\n");
231     fprintf(output, "  -s <snaplen>             packet snapshot length (def: 65535)\n");
232     fprintf(output, "  -p                       don't capture in promiscuous mode\n");
233     fprintf(output, "  -k                       start capturing immediately (def: do nothing)\n");
234     fprintf(output, "  -Q                       quit Wireshark after capturing\n");
235     fprintf(output, "  -S                       update packet display when new packets are captured\n");
236     fprintf(output, "  -l                       turn on automatic scrolling while -S is in use\n");
237 #if defined(_WIN32) || defined(HAVE_PCAP_CREATE)
238     fprintf(output, "  -B <buffer size>         size of kernel buffer (def: %dMB)\n", DEFAULT_CAPTURE_BUFFER_SIZE);
239 #endif
240     fprintf(output, "  -y <link type>           link layer type (def: first appropriate)\n");
241     fprintf(output, "  -D                       print list of interfaces and exit\n");
242     fprintf(output, "  -L                       print list of link-layer types of iface and exit\n");
243     fprintf(output, "\n");
244     fprintf(output, "Capture stop conditions:\n");
245     fprintf(output, "  -c <packet count>        stop after n packets (def: infinite)\n");
246     fprintf(output, "  -a <autostop cond.> ...  duration:NUM - stop after NUM seconds\n");
247     fprintf(output, "                           filesize:NUM - stop this file after NUM KB\n");
248     fprintf(output, "                              files:NUM - stop after NUM files\n");
249     /*fprintf(output, "\n");*/
250     fprintf(output, "Capture output:\n");
251     fprintf(output, "  -b <ringbuffer opt.> ... duration:NUM - switch to next file after NUM secs\n");
252     fprintf(output, "                           filesize:NUM - switch to next file after NUM KB\n");
253     fprintf(output, "                              files:NUM - ringbuffer: replace after NUM files\n");
254 #endif  /* HAVE_LIBPCAP */
255
256     /*fprintf(output, "\n");*/
257     fprintf(output, "Input file:\n");
258     fprintf(output, "  -r <infile>              set the filename to read from (no pipes or stdin!)\n");
259
260     fprintf(output, "\n");
261     fprintf(output, "Processing:\n");
262     fprintf(output, "  -R <read filter>         packet filter in Wireshark display filter syntax\n");
263     fprintf(output, "  -n                       disable all name resolutions (def: all enabled)\n");
264     fprintf(output, "  -N <name resolve flags>  enable specific name resolution(s): \"mntC\"\n");
265
266     fprintf(output, "\n");
267     fprintf(output, "User interface:\n");
268     fprintf(output, "  -C <config profile>      start with specified configuration profile\n");
269     fprintf(output, "  -g <packet number>       go to specified packet number after \"-r\"\n");
270     fprintf(output, "  -J <jump filter>         jump to the first packet matching the (display)\n");
271     fprintf(output, "                           filter\n");
272     fprintf(output, "  -j                       search backwards for a matching packet after \"-J\"\n");
273     fprintf(output, "  -m <font>                set the font name used for most text\n");
274     fprintf(output, "  -t ad|a|r|d|dd|e         output format of time stamps (def: r: rel. to first)\n");
275     fprintf(output, "  -u s|hms                 output format of seconds (def: s: seconds)\n");
276     fprintf(output, "  -X <key>:<value>         eXtension options, see man page for details\n");
277     fprintf(output, "  -z <statistics>          show various statistics, see man page for details\n");
278
279     fprintf(output, "\n");
280     fprintf(output, "Output:\n");
281     fprintf(output, "  -w <outfile|->           set the output filename (or '-' for stdout)\n");
282
283     fprintf(output, "\n");
284     fprintf(output, "Miscellaneous:\n");
285     fprintf(output, "  -h                       display this help and exit\n");
286     fprintf(output, "  -v                       display version info and exit\n");
287     fprintf(output, "  -P <key>:<path>          persconf:path - personal configuration files\n");
288     fprintf(output, "                           persdata:path - personal data files\n");
289     fprintf(output, "  -o <name>:<value> ...    override preference or recent setting\n");
290     fprintf(output, "  -K <keytab>              keytab file to use for kerberos decryption\n");
291 #ifndef _WIN32
292     fprintf(output, "  --display=DISPLAY        X display to use\n");
293 #endif
294
295 #ifdef _WIN32
296     destroy_console();
297 #endif
298 }
299
300 // xxx copied from ../gtk/main.c
301 static void
302 show_version(void)
303 {
304     printf(PACKAGE " %s\n"
305            "\n"
306            "%s"
307            "\n"
308            "%s"
309            "\n"
310            "%s",
311            get_ws_vcs_version_info(), get_copyright_info(), comp_info_str->str,
312            runtime_info_str->str);
313 }
314
315 /*
316  * Report an error in command-line arguments.
317  * Creates a console on Windows.
318  */
319 // xxx copied from ../gtk/main.c
320 static void
321 wireshark_cmdarg_err(const char *fmt, va_list ap)
322 {
323 #ifdef _WIN32
324     create_console();
325 #endif
326     fprintf(stderr, "wireshark: ");
327     vfprintf(stderr, fmt, ap);
328     fprintf(stderr, "\n");
329 }
330
331 /*
332  * Report additional information for an error in command-line arguments.
333  * Creates a console on Windows.
334  * XXX - pop this up in a window of some sort on UNIX+X11 if the controlling
335  * terminal isn't the standard error?
336  */
337 // xxx copied from ../gtk/main.c
338 static void
339 wireshark_cmdarg_err_cont(const char *fmt, va_list ap)
340 {
341 #ifdef _WIN32
342     create_console();
343 #endif
344     vfprintf(stderr, fmt, ap);
345     fprintf(stderr, "\n");
346 }
347
348 static void
349 console_log_handler(const char *log_domain, GLogLevelFlags log_level,
350                     const char *message, gpointer user_data)
351 {
352     Q_UNUSED(user_data);
353     QString level;
354     QString hmsz = QDateTime::currentDateTime().toString("hh:mm:ss.zzz");
355
356 // xxx qtshark: We want all of the messages for now.
357 //    /* ignore log message, if log_level isn't interesting based
358 //     upon the console log preferences.
359 //     If the preferences haven't been loaded loaded yet, display the
360 //     message anyway.
361
362 //     The default console_log_level preference value is such that only
363 //       ERROR, CRITICAL and WARNING level messages are processed;
364 //       MESSAGE, INFO and DEBUG level messages are ignored.  */
365 //    if((log_level & G_LOG_LEVEL_MASK & prefs.console_log_level) == 0 &&
366 //       prefs.console_log_level != 0) {
367 //        return;
368
369         switch(log_level & G_LOG_LEVEL_MASK) {
370         case G_LOG_LEVEL_ERROR:
371             level = "Err ";
372             break;
373         case G_LOG_LEVEL_CRITICAL:
374             level = "Crit";
375             break;
376         case G_LOG_LEVEL_WARNING:
377             level = "Warn";
378             break;
379         case G_LOG_LEVEL_MESSAGE:
380             level = "Msg ";
381             break;
382         case G_LOG_LEVEL_INFO:
383             level = "Info";
384             break;
385         case G_LOG_LEVEL_DEBUG:
386             level = "Dbg ";
387             break;
388         default:
389             qDebug("%s unknown log_level %u", hmsz.toUtf8().constData(), log_level);
390             g_assert_not_reached();
391         }
392
393         qDebug("%s %s %s %s", hmsz.toUtf8().constData(), log_domain, level.toUtf8().constData(), message);
394     }
395
396 // xxx based from ../gtk/main.c:get_gtk_compiled_info
397 static void
398 get_qt_compiled_info(GString *str)
399 {
400     g_string_append(str, "with ");
401     g_string_append_printf(str,
402 #ifdef QT_VERSION
403                     "Qt %s ", QT_VERSION_STR);
404 #else
405                     "Qt (version unknown) ");
406 #endif
407 }
408
409 // xxx copied from ../gtk/main.c
410 static void
411 get_gui_compiled_info(GString *str)
412 {
413     epan_get_compiled_version_info(str);
414
415     g_string_append(str, ", ");
416     g_string_append(str, "without PortAudio");
417
418     g_string_append(str, ", ");
419 #ifdef HAVE_AIRPCAP
420     get_compiled_airpcap_version(str);
421 #else
422     g_string_append(str, "without AirPcap");
423 #endif
424 }
425
426 // xxx copied from ../gtk/main.c
427 static void
428 get_wireshark_runtime_info(GString *str)
429 {
430 #ifdef HAVE_LIBPCAP
431     /* Libpcap */
432     g_string_append(str, ", ");
433     get_runtime_pcap_version(str);
434 #endif
435
436     /* zlib */
437 #if defined(HAVE_LIBZ) && !defined(_WIN32)
438     g_string_append_printf(str, ", with libz %s", zlibVersion());
439 #endif
440
441     /* stuff used by libwireshark */
442     epan_get_runtime_version_info(str);
443
444 #ifdef HAVE_AIRPCAP
445     g_string_append(str, ", ");
446     get_runtime_airpcap_version(str);
447 #endif
448
449     if(u3_active()) {
450         g_string_append(str, ", ");
451         u3_runtime_info(str);
452     }
453 }
454
455 /* And now our feature presentation... [ fade to music ] */
456 int main(int argc, char *argv[])
457 {
458     WiresharkApplication ws_app(argc, argv);
459     MainWindow *main_w;
460
461     int                  opt;
462     gboolean             arg_error = FALSE;
463
464 #ifdef _WIN32
465     WSADATA            wsaData;
466 #endif  /* _WIN32 */
467
468     char                *rf_path;
469     int                  rf_open_errno;
470     char                *gdp_path, *dp_path;
471 #ifdef HAVE_LIBPCAP
472     int                  err;
473     gboolean             start_capture = FALSE;
474 //    gboolean             list_link_layer_types = FALSE;
475     GList               *if_list;
476     gchar               *err_str;
477 #else
478     gboolean             capture_option_specified = FALSE;
479 #ifdef _WIN32
480 #ifdef HAVE_AIRPCAP
481     gchar               *err_str;
482 #endif
483 #endif
484 #endif
485     e_prefs             *prefs_p;
486     GLogLevelFlags       log_flags;
487
488     cmdarg_err_init(wireshark_cmdarg_err, wireshark_cmdarg_err_cont);
489
490 #ifdef _WIN32
491     create_app_running_mutex();
492 #endif
493
494     QString locale;
495     QString *cf_name = NULL;
496     QString *display_filter = NULL;
497     int optind_initial;
498     unsigned int in_file_type = WTAP_TYPE_AUTO;
499
500     // In Qt 5, C strings are treated always as UTF-8 when converted to
501     // QStrings; in Qt 4, the codec must be set to make that happen
502 #if (QT_VERSION < QT_VERSION_CHECK(5, 0, 0))
503     // Hopefully we won't have to use QString::fromUtf8() in as many places.
504     QTextCodec *utf8codec = QTextCodec::codecForName("UTF-8");
505     QTextCodec::setCodecForCStrings(utf8codec);
506     // XXX - QObject doesn't *have* a tr method in 5.0, as far as I can see...
507     QTextCodec::setCodecForTr(utf8codec);
508 #endif
509
510
511     // XXX Should the remaining code be in WiresharkApplcation::WiresharkApplication?
512 #define OPTSTRING OPTSTRING_CAPTURE_COMMON "C:g:Hh" "jJ:kK:lm:nN:o:P:Qr:R:St:u:vw:X:z:"
513     static const struct option long_options[] = {
514         {(char *)"help", no_argument, NULL, 'h'},
515         {(char *)"read-file", required_argument, NULL, 'r' },
516         {(char *)"version", no_argument, NULL, 'v'},
517         LONGOPT_CAPTURE_COMMON
518         {0, 0, 0, 0 }
519     };
520     static const char optstring[] = OPTSTRING;
521
522     /* Assemble the compile-time version information string */
523     comp_info_str = g_string_new("Compiled ");
524
525     // xxx qtshark
526     get_compiled_version_info(comp_info_str, get_qt_compiled_info, get_gui_compiled_info);
527
528     /* Assemble the run-time version information string */
529     runtime_info_str = g_string_new("Running ");
530     // xxx qtshark
531     get_runtime_version_info(runtime_info_str, get_wireshark_runtime_info);
532
533     ws_add_crash_info(PACKAGE " %s\n"
534            "\n"
535            "%s"
536            "\n"
537            "%s",
538         get_ws_vcs_version_info(), comp_info_str->str, runtime_info_str->str);
539
540     /*
541      * Get credential information for later use, and drop privileges
542      * before doing anything else.
543      * Let the user know if anything happened.
544      */
545     init_process_policies();
546     relinquish_special_privs_perm();
547
548     /*
549      * Attempt to get the pathname of the executable file.
550      */
551     /* init_progfile_dir_error = */ init_progfile_dir(QCoreApplication::applicationFilePath().toUtf8().constData(), NULL);
552     g_log(NULL, G_LOG_LEVEL_DEBUG, "progfile_dir: %s", get_progfile_dir());
553
554     /* initialize the funnel mini-api */
555     // xxx qtshark
556     //initialize_funnel_ops();
557
558     AirPDcapInitContext(&airpdcap_ctx);
559
560 // xxx qtshark
561 #ifdef _WIN32
562     /* Load wpcap if possible. Do this before collecting the run-time version information */
563     load_wpcap();
564
565     /* ... and also load the packet.dll from wpcap */
566     wpcap_packet_load();
567
568 #ifdef HAVE_AIRPCAP
569     /* Load the airpcap.dll.  This must also be done before collecting
570      * run-time version information. */
571     airpcap_dll_ret_val = load_airpcap();
572
573     switch (airpcap_dll_ret_val) {
574     case AIRPCAP_DLL_OK:
575         /* load the airpcap interfaces */
576         airpcap_if_list = get_airpcap_interface_list(&err, &err_str);
577
578         if (airpcap_if_list == NULL || g_list_length(airpcap_if_list) == 0){
579             if (err == CANT_GET_AIRPCAP_INTERFACE_LIST && err_str != NULL) {
580                 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s", "Failed to open Airpcap Adapters!");
581                 g_free(err_str);
582             }
583             airpcap_if_active = NULL;
584
585         } else {
586
587             /* select the first ad default (THIS SHOULD BE CHANGED) */
588             airpcap_if_active = airpcap_get_default_if(airpcap_if_list);
589         }
590         break;
591 #if 0
592     /*
593      * XXX - Maybe we need to warn the user if one of the following happens???
594      */
595     case AIRPCAP_DLL_OLD:
596         simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s","AIRPCAP_DLL_OLD\n");
597         break;
598
599     case AIRPCAP_DLL_ERROR:
600         simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s","AIRPCAP_DLL_ERROR\n");
601         break;
602
603     case AIRPCAP_DLL_NOT_FOUND:
604         simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s","AIRPCAP_DDL_NOT_FOUND\n");
605         break;
606 #endif
607     }
608 #endif /* HAVE_AIRPCAP */
609
610     /* Start windows sockets */
611     WSAStartup( MAKEWORD( 1, 1 ), &wsaData );
612 #endif  /* _WIN32 */
613
614     profile_store_persconffiles (TRUE);
615
616     /* Read the profile independent recent file.  We have to do this here so we can */
617     /* set the profile before it can be set from the command line parameter */
618     recent_read_static(&rf_path, &rf_open_errno);
619     if (rf_path != NULL && rf_open_errno != 0) {
620         simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
621                       "Could not open common recent file\n\"%s\": %s.",
622                       rf_path, strerror(rf_open_errno));
623     }
624     wsApp->emitAppSignal(WiresharkApplication::StaticRecentFilesRead);
625
626
627     /* "pre-scan" the command line parameters, if we have "console only"
628        parameters.  We do this so we don't start Qt if we're only showing
629        command-line help or version information.
630
631         XXX - this pre-scan is done before we start Qt. That means that Qt
632        arguments have not been removed from the argument list; those arguments
633        begin with "--", and will be treated as an error by getopt().
634
635        We thus ignore errors - *and* set "opterr" to 0 to suppress the
636        error messages.*/
637
638     opterr = 0;
639     optind_initial = optind;
640     while ((opt = getopt(argc, argv, optstring)) != -1) {
641         switch (opt) {
642             case 'C':        /* Configuration Profile */
643                 if (profile_exists (optarg, FALSE)) {
644                     set_profile_name (optarg);
645                 } else {
646                     cmdarg_err("Configuration Profile \"%s\" does not exist", optarg);
647                     exit(1);
648                 }
649                 break;
650             case 'D':        /* Print a list of capture devices and exit */
651 #ifdef HAVE_LIBPCAP
652                 if_list = capture_interface_list(&err, &err_str,main_window_update);
653                 if (if_list == NULL) {
654                     switch (err) {
655                         case CANT_GET_INTERFACE_LIST:
656                         case DONT_HAVE_PCAP:
657                             cmdarg_err("%s", err_str);
658                             g_free(err_str);
659                             break;
660
661                         case NO_INTERFACES_FOUND:
662                             cmdarg_err("There are no interfaces on which a capture can be done");
663                             break;
664                     }
665                     exit(2);
666                 }
667 #ifdef _WIN32
668                 create_console();
669 #endif /* _WIN32 */
670                 capture_opts_print_interfaces(if_list);
671                 free_interface_list(if_list);
672 #ifdef _WIN32
673                 destroy_console();
674 #endif /* _WIN32 */
675                 exit(0);
676 #else /* HAVE_LIBPCAP */
677                 capture_option_specified = TRUE;
678                 arg_error = TRUE;
679 #endif /* HAVE_LIBPCAP */
680                 break;
681             case 'h':        /* Print help and exit */
682                 print_usage(TRUE);
683                 exit(0);
684                 break;
685 #ifdef _WIN32
686             case 'i':
687                 if (strcmp(optarg, "-") == 0)
688                     set_stdin_capture(TRUE);
689                 break;
690 #endif
691             case 'P':        /* Personal file directory path settings - change these before the Preferences and alike are processed */
692                 if (!persfilepath_opt(opt, optarg)) {
693                     cmdarg_err("-P flag \"%s\" failed (hint: is it quoted and existing?)", optarg);
694                     exit(2);
695                 }
696                 break;
697             case 'v':        /* Show version and exit */
698 #ifdef _WIN32
699                 create_console();
700 #endif
701                 show_version();
702 #ifdef _WIN32
703                 destroy_console();
704 #endif
705                 exit(0);
706                 break;
707             case 'X':
708                 /*
709                  *  Extension command line options have to be processed before
710                  *  we call epan_init() as they are supposed to be used by dissectors
711                  *  or taps very early in the registration process.
712                  */
713                 ex_opt_add(optarg);
714                 break;
715             case '?':        /* Ignore errors - the "real" scan will catch them. */
716                 break;
717         }
718     }
719
720     /* Init the "Open file" dialog directory */
721     /* (do this after the path settings are processed) */
722
723     /* Read the profile dependent (static part) of the recent file. */
724     /* Only the static part of it will be read, as we don't have the gui now to fill the */
725     /* recent lists which is done in the dynamic part. */
726     /* We have to do this already here, so command line parameters can overwrite these values. */
727     recent_read_profile_static(&rf_path, &rf_open_errno);
728     if (rf_path != NULL && rf_open_errno != 0) {
729         simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
730                       "Could not open recent file\n\"%s\": %s.",
731                       rf_path, g_strerror(rf_open_errno));
732     }
733
734
735     /* Set getopt index back to initial value, so it will start with the
736        first command line parameter again.  Also reset opterr to 1, so that
737        error messages are printed by getopt().
738
739        XXX - this seems to work on most platforms, but time will tell.
740        The Single UNIX Specification says "The getopt() function need
741        not be reentrant", so this isn't guaranteed to work.  The Mac
742        OS X 10.4[.x] getopt() man page says
743
744          In order to use getopt() to evaluate multiple sets of arguments, or to
745          evaluate a single set of arguments multiple times, the variable optreset
746          must be set to 1 before the second and each additional set of calls to
747          getopt(), and the variable optind must be reinitialized.
748
749            ...
750
751          The optreset variable was added to make it possible to call the getopt()
752          function multiple times.  This is an extension to the IEEE Std 1003.2
753          (``POSIX.2'') specification.
754
755        which I think comes from one of the other BSDs.
756
757        XXX - if we want to control all the command-line option errors, so
758        that we can display them where we choose (e.g., in a window), we'd
759        want to leave opterr as 0, and produce our own messages using optopt.
760        We'd have to check the value of optopt to see if it's a valid option
761        letter, in which case *presumably* the error is "this option requires
762        an argument but none was specified", or not a valid option letter,
763        in which case *presumably* the error is "this option isn't valid".
764        Some versions of getopt() let you supply a option string beginning
765        with ':', which means that getopt() will return ':' rather than '?'
766        for "this option requires an argument but none was specified", but
767        not all do. */
768     optind = optind_initial;
769     opterr = 1;
770
771     // Init the main window (and splash)
772     main_w = new(MainWindow);
773     main_w->show();
774     // We may not need a queued connection here but it would seem to make sense
775     // to force the issue.
776     main_w->connect(&ws_app, SIGNAL(openCaptureFile(QString&,QString&,unsigned int)),
777             main_w, SLOT(openCaptureFile(QString&,QString&,unsigned int)));
778
779     while ((opt = getopt_long(argc, argv, optstring, long_options, NULL)) != -1) {
780         switch (opt) {
781         case 'r':
782             cf_name = new QString(optarg);
783             break;
784         case '?':
785             print_usage(TRUE);
786             exit(0);
787             break;
788         }
789     }
790
791     if (!arg_error) {
792         argc -= optind;
793         argv += optind;
794         if (argc >= 1) {
795             if (cf_name != NULL) {
796                 /*
797                  * Input file name specified with "-r" *and* specified as a regular
798                  * command-line argument.
799                  */
800                 cmdarg_err("File name specified both with -r and regular argument");
801                 arg_error = TRUE;
802             } else {
803                 /*
804                  * Input file name not specified with "-r", and a command-line argument
805                  * was specified; treat it as the input file name.
806                  *
807                  * Yes, this is different from tshark, where non-flag command-line
808                  * arguments are a filter, but this works better on GUI desktops
809                  * where a command can be specified to be run to open a particular
810                  * file - yes, you could have "-r" as the last part of the command,
811                  * but that's a bit ugly.
812                  */
813                 cf_name = new QString(g_strdup(argv[0]));
814
815             }
816             argc--;
817             argv++;
818         }
819
820         if (argc != 0) {
821             /*
822              * Extra command line arguments were specified; complain.
823              */
824             cmdarg_err("Invalid argument: %s", argv[0]);
825             arg_error = TRUE;
826         }
827     }
828     if (arg_error) {
829 #ifndef HAVE_LIBPCAP
830         if (capture_option_specified) {
831             cmdarg_err("This version of Wireshark was not built with support for capturing packets.");
832         }
833 #endif
834         print_usage(FALSE);
835         exit(1);
836     }
837
838     /* Init the "Open file" dialog directory */
839     /* (do this after the path settings are processed) */
840
841     /* Read the profile dependent (static part) of the recent file. */
842     /* Only the static part of it will be read, as we don't have the gui now to fill the */
843     /* recent lists which is done in the dynamic part. */
844     /* We have to do this already here, so command line parameters can overwrite these values. */
845     recent_read_profile_static(&rf_path, &rf_open_errno);
846     if (rf_path != NULL && rf_open_errno != 0) {
847       simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
848             "Could not open recent file\n\"%s\": %s.",
849             rf_path, g_strerror(rf_open_errno));
850     }
851
852     if (recent.gui_fileopen_remembered_dir &&
853         test_for_directory(recent.gui_fileopen_remembered_dir) == EISDIR) {
854       wsApp->setLastOpenDir(recent.gui_fileopen_remembered_dir);
855     } else {
856       wsApp->setLastOpenDir(get_persdatafile_dir());
857     }
858
859 #ifdef Q_OS_UNIX
860     // Replicates behavior in gtk_init();
861     signal(SIGPIPE, SIG_IGN);
862 #endif
863
864 #ifdef HAVE_LIBPCAP
865     capture_callback_add(main_capture_callback, NULL);
866 #endif
867     cf_callback_add(main_cf_callback, NULL);
868
869     /* Arrange that if we have no console window, and a GLib message logging
870        routine is called to log a message, we pop up a console window.
871
872        We do that by inserting our own handler for all messages logged
873        to the default domain; that handler pops up a console if necessary,
874        and then calls the default handler. */
875
876     /* We might want to have component specific log levels later ... */
877
878     log_flags = (GLogLevelFlags) (
879             G_LOG_LEVEL_ERROR|
880             G_LOG_LEVEL_CRITICAL|
881             G_LOG_LEVEL_WARNING|
882             G_LOG_LEVEL_MESSAGE|
883             G_LOG_LEVEL_INFO|
884             G_LOG_LEVEL_DEBUG|
885             G_LOG_FLAG_FATAL|G_LOG_FLAG_RECURSION );
886
887     g_log_set_handler(NULL,
888                       log_flags,
889                       console_log_handler, NULL /* user_data */);
890     g_log_set_handler(LOG_DOMAIN_MAIN,
891                       log_flags,
892                       console_log_handler, NULL /* user_data */);
893
894 #ifdef HAVE_LIBPCAP
895     g_log_set_handler(LOG_DOMAIN_CAPTURE,
896                       log_flags,
897                       console_log_handler, NULL /* user_data */);
898     g_log_set_handler(LOG_DOMAIN_CAPTURE_CHILD,
899                       log_flags,
900                       console_log_handler, NULL /* user_data */);
901
902     /* Set the initial values in the capture options. This might be overwritten
903        by preference settings and then again by the command line parameters. */
904     capture_opts_init(&global_capture_opts);
905
906     capture_session_init(&global_capture_session, (void *)&cfile);
907 #endif
908
909     init_report_err(failure_alert_box, open_failure_alert_box,
910                     read_failure_alert_box, write_failure_alert_box);
911
912     init_open_routines();
913
914 #ifdef HAVE_PLUGINS
915     /* Register all the plugin types we have. */
916     epan_register_plugin_types(); /* Types known to libwireshark */
917     wtap_register_plugin_types(); /* Types known to libwiretap */
918     codec_register_plugin_types(); /* Types known to libcodec */
919
920     /* Scan for plugins.  This does *not* call their registration routines;
921        that's done later. */
922     scan_plugins();
923
924     /* Register all libwiretap plugin modules. */
925     register_all_wiretap_modules();
926
927     /* Register all audio codec plugins. */
928     register_all_codecs();
929 #endif
930
931     /* Register all dissectors; we must do this before checking for the
932        "-G" flag, as the "-G" flag dumps information registered by the
933        dissectors, and we must do it before we read the preferences, in
934        case any dissectors register preferences. */
935     epan_init(register_all_protocols,register_all_protocol_handoffs,
936               splash_update, NULL);
937
938     splash_update(RA_LISTENERS, NULL, NULL);
939
940     /* Register all tap listeners; we do this before we parse the arguments,
941        as the "-z" argument can specify a registered tap. */
942
943     /* we register the plugin taps before the other taps because
944             stats_tree taps plugins will be registered as tap listeners
945             by stats_tree_stat.c and need to registered before that */
946
947     g_log(NULL, G_LOG_LEVEL_DEBUG, "plugin_dir: %s", get_plugin_dir());
948 #ifdef HAVE_PLUGINS
949     register_all_plugin_tap_listeners();
950 #endif
951
952     register_all_tap_listeners();
953
954     if (ex_opt_count("read_format") > 0) {
955         in_file_type = open_info_name_to_type(ex_opt_get_next("read_format"));
956     }
957
958     splash_update(RA_PREFERENCES, NULL, NULL);
959     prefs_p = ws_app.readConfigurationFiles (&gdp_path, &dp_path);
960
961     // Initialize our language
962
963     /*TODO: Enhance... may be get the locale from the enum gui_qt_language */
964     switch(prefs_p->gui_qt_language){
965         case 1: /* English */
966         locale = "en";
967         break;
968         case 2: /* French */
969         locale = "fr";
970         break;
971         case 3: /* German */
972         locale = "de";
973         break;
974         case 4: /* Chinese */
975         locale = "zh_CN";
976         break;
977         case 5: /* Polish */
978         locale = "pl";
979         break;
980         default: /* Auto-Detect */
981         locale = QLocale::system().name();
982         break;
983     }
984     g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Translator %s", locale.toStdString().c_str());
985     QTranslator translator;
986     translator.load(QString(":/i18n/qtshark_") + locale);
987     wsApp->installTranslator(&translator);
988
989     QTranslator qtTranslator;
990     qtTranslator.load("qt_" + locale, QLibraryInfo::location(QLibraryInfo::TranslationsPath));
991     wsApp->installTranslator(&qtTranslator);
992
993     /* Removed thread code:
994      * https://code.wireshark.org/review/gitweb?p=wireshark.git;a=commit;h=9e277ae6154fd04bf6a0a34ec5655a73e5a736a3
995      */
996
997     g_log(NULL, G_LOG_LEVEL_DEBUG, "FIX: timestamp types should be set elsewhere");
998     timestamp_set_type(TS_RELATIVE);
999     timestamp_set_precision(TS_PREC_AUTO_USEC);
1000     timestamp_set_seconds_type(TS_SECONDS_DEFAULT);
1001
1002 #ifdef HAVE_LIBPCAP
1003     fill_in_local_interfaces(main_window_update);
1004
1005     capture_opts_trim_snaplen(&global_capture_opts, MIN_PACKET_SIZE);
1006     capture_opts_trim_ring_num_files(&global_capture_opts);
1007 #endif /* HAVE_LIBPCAP */
1008
1009     /* Notify all registered modules that have had any of their preferences
1010        changed either from one of the preferences file or from the command
1011        line that their preferences have changed. */
1012     prefs_apply_all();
1013     wsApp->emitAppSignal(WiresharkApplication::PreferencesChanged);
1014
1015 #ifdef HAVE_LIBPCAP
1016     if ((global_capture_opts.num_selected == 0) &&
1017             (prefs.capture_device != NULL)) {
1018         guint i;
1019         interface_t device;
1020         for (i = 0; i < global_capture_opts.all_ifaces->len; i++) {
1021             device = g_array_index(global_capture_opts.all_ifaces, interface_t, i);
1022             if (!device.hidden && strcmp(device.display_name, prefs.capture_device) == 0) {
1023                 device.selected = TRUE;
1024                 global_capture_opts.num_selected++;
1025                 global_capture_opts.all_ifaces = g_array_remove_index(global_capture_opts.all_ifaces, i);
1026                 g_array_insert_val(global_capture_opts.all_ifaces, i, device);
1027                 break;
1028             }
1029         }
1030     }
1031 #endif
1032
1033     /* disabled protocols as per configuration file */
1034     if (gdp_path == NULL && dp_path == NULL) {
1035         set_disabled_protos_list();
1036     }
1037
1038     build_column_format_array(&cfile.cinfo, prefs_p->num_cols, TRUE);
1039
1040     wsApp->setMonospaceFont(prefs.gui_qt_font_name);
1041
1042 ////////
1043
1044     /* Read the dynamic part of the recent file, as we have the gui now ready for
1045        it. */
1046     recent_read_dynamic(&rf_path, &rf_open_errno);
1047     if (rf_path != NULL && rf_open_errno != 0) {
1048         simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1049                       "Could not open recent file\n\"%s\": %s.",
1050                       rf_path, g_strerror(rf_open_errno));
1051     }
1052
1053     color_filters_enable(recent.packet_list_colorize);
1054
1055     g_log(NULL, G_LOG_LEVEL_DEBUG, "FIX: fetch recent color settings");
1056     color_filters_enable(TRUE);
1057
1058 ////////
1059
1060
1061 ////////
1062     color_filters_init();
1063
1064 ////////
1065
1066 #ifdef HAVE_LIBPCAP
1067     /* if the user didn't supply a capture filter, use the one to filter out remote connections like SSH */
1068     if (!start_capture && !global_capture_opts.default_options.cfilter) {
1069         global_capture_opts.default_options.cfilter = g_strdup(get_conn_cfilter());
1070     }
1071 #else /* HAVE_LIBPCAP */
1072     ////////
1073 #endif /* HAVE_LIBPCAP */
1074
1075 //    w->setEnabled(true);
1076     wsApp->allSystemsGo();
1077     g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_INFO, "Wireshark is up and ready to go");
1078
1079     /* user could specify filename, or display filter, or both */
1080     if (cf_name != NULL || display_filter != NULL) {
1081         if (display_filter == NULL)
1082             display_filter = new QString();
1083         if (cf_name == NULL)
1084             cf_name = new QString();
1085         main_w->openCaptureFile(*cf_name, *display_filter, in_file_type);
1086     }
1087
1088     g_main_loop_new(NULL, FALSE);
1089     return wsApp->exec();
1090 }
1091
1092 /*
1093  * Editor modelines
1094  *
1095  * Local Variables:
1096  * c-basic-offset: 4
1097  * tab-width: 8
1098  * indent-tabs-mode: nil
1099  * End:
1100  *
1101  * ex: set shiftwidth=4 tabstop=8 expandtab:
1102  * :indentSize=4:tabSize=8:noTabs=true:
1103  */