5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
9 * Richard Sharpe, 13-Feb-1999, added support for initializing structures
10 * needed by dissect routines
11 * Jeff Foster, 2001/03/12, added support tabbed hex display windowss
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
34 #include <gdk/gdkkeysyms.h>
44 #ifdef NEED_STRERROR_H
45 #include "wsutil/strerror.h"
51 #include "wsutil/wsgetopt.h"
54 #ifdef _WIN32 /* Needed for console I/O */
59 #ifdef HAVE_LIBPORTAUDIO
60 #include <portaudio.h>
61 #endif /* HAVE_LIBPORTAUDIO */
63 #include <epan/epan.h>
64 #include <epan/filesystem.h>
65 #include <wsutil/privileges.h>
66 #include <epan/epan_dissect.h>
67 #include <epan/timestamp.h>
68 #include <epan/packet.h>
69 #include <epan/plugins.h>
70 #include <epan/dfilter/dfilter.h>
71 #include <epan/strutil.h>
72 #include <epan/addr_resolv.h>
73 #include <epan/emem.h>
74 #include <epan/ex-opt.h>
75 #include <epan/funnel.h>
76 #include <epan/expert.h>
77 #include <epan/frequency-utils.h>
78 #include <epan/prefs.h>
79 #include <epan/prefs-int.h>
81 #include <epan/stat_cmd_args.h>
83 #include <epan/column.h>
85 /* general (not GTK specific) */
87 #include "../summary.h"
88 #include "../filters.h"
89 #include "../disabled_protos.h"
91 #include "../color_filters.h"
93 #include "../simple_dialog.h"
94 #include "../main_statusbar.h"
95 #include "../register.h"
96 #include "../ringbuffer.h"
97 #include "../ui_util.h"
99 #include "../clopts_common.h"
100 #include "../console_io.h"
101 #include "../cmdarg_err.h"
102 #include "../version_info.h"
103 #include "../merge.h"
104 #include "../alert_box.h"
107 #include <wsutil/file_util.h>
110 #include "../capture_ui_utils.h"
111 #include "../capture-pcap-util.h"
112 #include "../capture_ifinfo.h"
113 #include "../capture.h"
114 #include "../capture_sync.h"
118 #include "../capture-wpcap.h"
119 #include "../capture_wpcap_packet.h"
120 #include <tchar.h> /* Needed for Unicode */
121 #include <wsutil/unicode-utils.h>
122 #include <commctrl.h>
123 #include <shellapi.h>
127 #include "gtk/file_dlg.h"
128 #include "gtk/gtkglobals.h"
129 #include "gtk/color_utils.h"
130 #include "gtk/gui_utils.h"
131 #include "gtk/color_dlg.h"
132 #include "gtk/filter_dlg.h"
133 #include "gtk/uat_gui.h"
134 #include "gtk/main.h"
135 #include "gtk/main_airpcap_toolbar.h"
136 #include "gtk/main_filter_toolbar.h"
137 #include "gtk/menus.h"
138 #include "gtk/macros_dlg.h"
139 #include "gtk/main_statusbar_private.h"
140 #include "gtk/main_toolbar.h"
141 #include "gtk/main_welcome.h"
142 #include "gtk/drag_and_drop.h"
143 #include "gtk/capture_file_dlg.h"
144 #include "gtk/main_proto_draw.h"
145 #include "gtk/keys.h"
146 #include "gtk/packet_win.h"
147 #include "gtk/stock_icons.h"
148 #include "gtk/find_dlg.h"
149 #include "gtk/recent.h"
150 #include "gtk/follow_tcp.h"
151 #include "gtk/font_utils.h"
152 #include "gtk/about_dlg.h"
153 #include "gtk/help_dlg.h"
154 #include "gtk/decode_as_dlg.h"
155 #include "gtk/webbrowser.h"
156 #include "gtk/capture_dlg.h"
157 #include "gtk/capture_if_dlg.h"
158 #include "gtk/tap_dfilter_dlg.h"
159 #include "gtk/prefs_column.h"
160 #include "gtk/prefs_dlg.h"
161 #include "gtk/proto_help.h"
162 #include "gtk/new_packet_list.h"
165 #include "../image/wsicon16.xpm"
166 #include "../image/wsicon32.xpm"
167 #include "../image/wsicon48.xpm"
168 #include "../image/wsicon64.xpm"
169 #include "../image/wsiconcap16.xpm"
170 #include "../image/wsiconcap32.xpm"
171 #include "../image/wsiconcap48.xpm"
176 #include "airpcap_loader.h"
177 #include "airpcap_dlg.h"
178 #include "airpcap_gui_utils.h"
181 #include <epan/crypt/airpdcap_ws.h>
184 #ifdef HAVE_GTKOSXAPPLICATION
185 #include <igemacintegration/gtkosxapplication.h>
189 * Files under personal and global preferences directories in which
190 * GTK settings for Wireshark are stored.
192 #define RC_FILE "gtkrc"
196 /* "exported" main widgets */
197 GtkWidget *top_level = NULL, *pkt_scrollw, *tree_view_gbl, *byte_nb_ptr_gbl;
199 /* placement widgets (can be a bit confusing, because of the many layout possibilities */
200 static GtkWidget *main_vbox, *main_pane_v1, *main_pane_v2, *main_pane_h1, *main_pane_h2;
201 static GtkWidget *main_first_pane, *main_second_pane;
203 /* internally used widgets */
204 static GtkWidget *menubar, *main_tb, *filter_tb, *tv_scrollw, *statusbar, *welcome_pane;
207 GtkWidget *airpcap_tb;
208 int airpcap_dll_ret_val = -1;
211 GString *comp_info_str, *runtime_info_str;
213 static gboolean have_capture_file = FALSE; /* XXX - is there an equivalent in cfile? */
215 static guint tap_update_timer_id;
218 static gboolean has_console; /* TRUE if app has console */
219 static gboolean console_wait; /* "Press any key..." */
220 static void destroy_console(void);
221 static gboolean stdin_capture = FALSE; /* Don't grab stdin & stdout if TRUE */
223 static void console_log_handler(const char *log_domain,
224 GLogLevelFlags log_level, const char *message, gpointer user_data);
227 capture_options global_capture_opts;
231 static void create_main_window(gint, gint, gint, e_prefs*);
232 static void show_main_window(gboolean);
233 static void file_quit_answered_cb(gpointer dialog, gint btn, gpointer data);
234 static void main_save_window_geometry(GtkWidget *widget);
237 /* Match selected byte pattern */
239 match_selected_cb_do(gpointer data, int action, gchar *text)
241 GtkWidget *filter_te;
242 char *cur_filter, *new_filter;
244 if ((!text) || (0 == strlen(text))) {
245 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Could not acquire information to build a filter!\nTry expanding or choosing another item.");
250 filter_te = g_object_get_data(G_OBJECT(data), E_DFILTER_TE_KEY);
253 cur_filter = gtk_editable_get_chars(GTK_EDITABLE(filter_te), 0, -1);
255 switch (action&MATCH_SELECTED_MASK) {
257 case MATCH_SELECTED_REPLACE:
258 new_filter = g_strdup(text);
261 case MATCH_SELECTED_AND:
262 if ((!cur_filter) || (0 == strlen(cur_filter)))
263 new_filter = g_strdup(text);
265 new_filter = g_strconcat("(", cur_filter, ") && (", text, ")", NULL);
268 case MATCH_SELECTED_OR:
269 if ((!cur_filter) || (0 == strlen(cur_filter)))
270 new_filter = g_strdup(text);
272 new_filter = g_strconcat("(", cur_filter, ") || (", text, ")", NULL);
275 case MATCH_SELECTED_NOT:
276 new_filter = g_strconcat("!(", text, ")", NULL);
279 case MATCH_SELECTED_AND_NOT:
280 if ((!cur_filter) || (0 == strlen(cur_filter)))
281 new_filter = g_strconcat("!(", text, ")", NULL);
283 new_filter = g_strconcat("(", cur_filter, ") && !(", text, ")", NULL);
286 case MATCH_SELECTED_OR_NOT:
287 if ((!cur_filter) || (0 == strlen(cur_filter)))
288 new_filter = g_strconcat("!(", text, ")", NULL);
290 new_filter = g_strconcat("(", cur_filter, ") || !(", text, ")", NULL);
294 g_assert_not_reached();
299 /* Free up the copy we got of the old filter text. */
302 /* Don't change the current display filter if we only want to copy the filter */
303 if (action&MATCH_SELECTED_COPY_ONLY) {
304 GString *gtk_text_str = g_string_new("");
305 g_string_append(gtk_text_str, new_filter);
306 copy_to_clipboard(gtk_text_str);
307 g_string_free(gtk_text_str, TRUE);
309 /* create a new one and set the display filter entry accordingly */
310 gtk_entry_set_text(GTK_ENTRY(filter_te), new_filter);
312 /* Run the display filter so it goes in effect. */
313 if (action&MATCH_SELECTED_APPLY_NOW)
314 main_filter_packets(&cfile, new_filter, FALSE);
317 /* Free up the new filter text. */
322 match_selected_ptree_cb(GtkWidget *w, gpointer data, MATCH_SELECTED_E action)
326 if (cfile.finfo_selected) {
327 filter = proto_construct_match_selected_string(cfile.finfo_selected,
329 match_selected_cb_do((data ? data : w), action, filter);
334 colorize_selected_ptree_cb(GtkWidget *w _U_, gpointer data _U_, guint8 filt_nr)
338 if (cfile.finfo_selected) {
339 filter = proto_construct_match_selected_string(cfile.finfo_selected,
341 if ((!filter) || (0 == strlen(filter))) {
342 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
343 "Could not acquire information to build a filter!\n"
344 "Try expanding or choosing another item.");
349 color_display_with_filter(filter);
352 color_filters_reset_tmp();
354 color_filters_set_tmp(filt_nr,filter, FALSE);
356 new_packet_list_colorize_packets();
362 static void selected_ptree_info_answered_cb(gpointer dialog _U_, gint btn, gpointer data)
364 gchar *selected_proto_url;
365 gchar *proto_abbrev = data;
370 if (cfile.finfo_selected) {
371 /* open wiki page using the protocol abbreviation */
372 selected_proto_url = g_strdup_printf("http://wiki.wireshark.org/Protocols/%s", proto_abbrev);
373 browser_open_url(selected_proto_url);
374 g_free(selected_proto_url);
377 case(ESD_BTN_CANCEL):
380 g_assert_not_reached();
386 selected_ptree_info_cb(GtkWidget *widget _U_, gpointer data _U_)
389 const gchar *proto_abbrev;
393 if (cfile.finfo_selected) {
394 /* convert selected field to protocol abbreviation */
395 /* XXX - could this conversion be simplified? */
396 field_id = cfile.finfo_selected->hfinfo->id;
397 /* if the selected field isn't a protocol, get it's parent */
398 if(!proto_registrar_is_protocol(field_id)) {
399 field_id = proto_registrar_get_parent(cfile.finfo_selected->hfinfo->id);
402 proto_abbrev = proto_registrar_get_abbrev(field_id);
404 if (!proto_is_private(field_id)) {
405 /* ask the user if the wiki page really should be opened */
406 dialog = simple_dialog(ESD_TYPE_CONFIRMATION, ESD_BTNS_OK_CANCEL,
407 "%sOpen Wireshark Wiki page of protocol \"%s\"?%s\n"
409 "This will open the \"%s\" related Wireshark Wiki page in your Web browser.\n"
411 "The Wireshark Wiki is a collaborative approach to provide information "
412 "about Wireshark in several ways (not limited to protocol specifics).\n"
414 "This Wiki is new, so the page of the selected protocol "
415 "may not exist and/or may not contain valuable information.\n"
417 "As everyone can edit the Wiki and add new content (or extend existing), "
418 "you are encouraged to add information if you can.\n"
420 "Hint 1: If you are new to wiki editing, try out editing the Sandbox first!\n"
422 "Hint 2: If you want to add a new protocol page, you should use the ProtocolTemplate, "
423 "which will save you a lot of editing and will give a consistent look over the pages.",
424 simple_dialog_primary_start(), proto_abbrev, simple_dialog_primary_end(), proto_abbrev);
425 simple_dialog_set_cb(dialog, selected_ptree_info_answered_cb, (gpointer)proto_abbrev);
427 /* appologize to the user that the wiki page cannot be opened */
428 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
429 "%sCan't open Wireshark Wiki page of protocol \"%s\"%s\n"
431 "This would open the \"%s\" related Wireshark Wiki page in your Web browser.\n"
433 "Since this is a private protocol, such information is not available in "
434 "a public wiki. Therefore this wiki entry is blocked.\n"
436 "Sorry for the inconvenience.\n",
437 simple_dialog_primary_start(), proto_abbrev, simple_dialog_primary_end(), proto_abbrev);
442 static void selected_ptree_ref_answered_cb(gpointer dialog _U_, gint btn, gpointer data)
444 gchar *selected_proto_url;
445 gchar *proto_abbrev = data;
449 if (cfile.finfo_selected) {
450 /* open reference page using the protocol abbreviation */
451 selected_proto_url = g_strdup_printf("http://www.wireshark.org/docs/dfref/%c/%s", proto_abbrev[0], proto_abbrev);
452 browser_open_url(selected_proto_url);
453 g_free(selected_proto_url);
456 case(ESD_BTN_CANCEL):
459 g_assert_not_reached();
464 selected_ptree_ref_cb(GtkWidget *widget _U_, gpointer data _U_)
467 const gchar *proto_abbrev;
471 if (cfile.finfo_selected) {
472 /* convert selected field to protocol abbreviation */
473 /* XXX - could this conversion be simplified? */
474 field_id = cfile.finfo_selected->hfinfo->id;
475 /* if the selected field isn't a protocol, get it's parent */
476 if(!proto_registrar_is_protocol(field_id)) {
477 field_id = proto_registrar_get_parent(cfile.finfo_selected->hfinfo->id);
480 proto_abbrev = proto_registrar_get_abbrev(field_id);
482 if (!proto_is_private(field_id)) {
483 /* ask the user if the wiki page really should be opened */
484 dialog = simple_dialog(ESD_TYPE_CONFIRMATION, ESD_BTNS_OK_CANCEL,
485 "%sOpen Wireshark filter reference page of protocol \"%s\"?%s\n"
487 "This will open the \"%s\" related Wireshark filter reference page in your Web browser.\n"
489 simple_dialog_primary_start(), proto_abbrev, simple_dialog_primary_end(), proto_abbrev);
490 simple_dialog_set_cb(dialog, selected_ptree_ref_answered_cb, (gpointer)proto_abbrev);
492 /* appologize to the user that the wiki page cannot be opened */
493 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
494 "%sCan't open Wireshark filter reference page of protocol \"%s\"%s\n"
496 "This would open the \"%s\" related Wireshark filter reference page in your Web browser.\n"
498 "Since this is a private protocol, such information is not available on "
499 "a public website. Therefore this filter entry is blocked.\n"
501 "Sorry for the inconvenience.\n",
502 simple_dialog_primary_start(), proto_abbrev, simple_dialog_primary_end(), proto_abbrev);
508 is_address_column (gint column)
510 if (((cfile.cinfo.col_fmt[column] == COL_DEF_SRC) ||
511 (cfile.cinfo.col_fmt[column] == COL_RES_SRC) ||
512 (cfile.cinfo.col_fmt[column] == COL_DEF_DST) ||
513 (cfile.cinfo.col_fmt[column] == COL_RES_DST)) &&
514 strlen(cfile.cinfo.col_expr.col_expr_val[column]))
523 get_ip_address_list_from_packet_list_row(gpointer data)
525 gint row = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(data), E_MPACKET_LIST_ROW_KEY));
526 gint column = new_packet_list_get_column_id (GPOINTER_TO_INT(g_object_get_data(G_OBJECT(data), E_MPACKET_LIST_COL_KEY)));
529 GList *addr_list = NULL;
531 fdata = (frame_data *) new_packet_list_get_row_data(row);
536 if (!cf_read_frame (&cfile, fdata))
537 return NULL; /* error reading the frame */
539 epan_dissect_init(&edt, FALSE, FALSE);
540 col_custom_prime_edt(&edt, &cfile.cinfo);
542 epan_dissect_run(&edt, &cfile.pseudo_header, cfile.pd, fdata, &cfile.cinfo);
543 epan_dissect_fill_in_columns(&edt, TRUE, TRUE);
545 /* First check selected column */
546 if (is_address_column (column)) {
547 addr_list = g_list_append (addr_list, se_strdup_printf("%s", cfile.cinfo.col_expr.col_expr_val[column]));
550 for (col = 0; col < cfile.cinfo.num_cols; col++) {
551 /* Then check all columns except the selected */
552 if ((col != column) && (is_address_column (col))) {
553 addr_list = g_list_append (addr_list, se_strdup_printf("%s", cfile.cinfo.col_expr.col_expr_val[col]));
557 epan_dissect_cleanup(&edt);
564 get_filter_from_packet_list_row_and_column(gpointer data)
566 gint row = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(data), E_MPACKET_LIST_ROW_KEY));
567 gint column = new_packet_list_get_column_id (GPOINTER_TO_INT(g_object_get_data(G_OBJECT(data), E_MPACKET_LIST_COL_KEY)));
571 fdata = (frame_data *) new_packet_list_get_row_data(row);
576 if (!cf_read_frame(&cfile, fdata))
577 return NULL; /* error reading the frame */
578 /* proto tree, visible. We need a proto tree if there's custom columns */
579 epan_dissect_init(&edt, have_custom_cols(&cfile.cinfo), FALSE);
580 col_custom_prime_edt(&edt, &cfile.cinfo);
582 epan_dissect_run(&edt, &cfile.pseudo_header, cfile.pd, fdata,
584 epan_dissect_fill_in_columns(&edt, TRUE, TRUE);
586 if ((cfile.cinfo.col_custom_occurrence[column]) ||
587 (strchr (cfile.cinfo.col_expr.col_expr_val[column], ',') == NULL))
589 /* Only construct the filter when a single occurrence is displayed
590 * otherwise we might end up with a filter like "ip.proto==1,6".
592 * Or do we want to be able to filter on multiple occurrences so that
593 * the filter might be calculated as "ip.proto==1 && ip.proto==6"
596 if (strlen(cfile.cinfo.col_expr.col_expr[column]) != 0 &&
597 strlen(cfile.cinfo.col_expr.col_expr_val[column]) != 0) {
598 /* leak a little but safer than ep_ here */
599 if (cfile.cinfo.col_fmt[column] == COL_CUSTOM) {
600 header_field_info *hfi = proto_registrar_get_byname(cfile.cinfo.col_custom_field[column]);
601 if (hfi->parent == -1) {
603 buf = se_strdup(cfile.cinfo.col_expr.col_expr[column]);
604 } else if (hfi->type == FT_STRING) {
605 /* Custom string, add quotes */
606 buf = se_strdup_printf("%s == \"%s\"", cfile.cinfo.col_expr.col_expr[column],
607 cfile.cinfo.col_expr.col_expr_val[column]);
611 buf = se_strdup_printf("%s == %s", cfile.cinfo.col_expr.col_expr[column],
612 cfile.cinfo.col_expr.col_expr_val[column]);
617 epan_dissect_cleanup(&edt);
624 match_selected_plist_cb(GtkWidget *w _U_, gpointer data, MATCH_SELECTED_E action)
626 match_selected_cb_do(data,
628 get_filter_from_packet_list_row_and_column(data));
631 /* This function allows users to right click in the details window and copy the text
632 * information to the operating systems clipboard.
634 * We first check to see if a string representation is setup in the tree and then
635 * read the string. If not available then we try to grab the value. If all else
636 * fails we display a message to the user to indicate the copy could not be completed.
639 copy_selected_plist_cb(GtkWidget *w _U_, gpointer data _U_, COPY_SELECTED_E action)
641 GString *gtk_text_str = g_string_new("");
642 char labelstring[256];
643 char *stringpointer = labelstring;
647 case COPY_SELECTED_DESCRIPTION:
648 if (cfile.finfo_selected->rep &&
649 strlen (cfile.finfo_selected->rep->representation) > 0) {
650 g_string_append(gtk_text_str, cfile.finfo_selected->rep->representation);
653 case COPY_SELECTED_FIELDNAME:
654 if (cfile.finfo_selected->hfinfo->abbrev != 0) {
655 g_string_append(gtk_text_str, cfile.finfo_selected->hfinfo->abbrev);
658 case COPY_SELECTED_VALUE:
659 if (cfile.edt !=0 ) {
660 g_string_append(gtk_text_str,
661 get_node_field_value(cfile.finfo_selected, cfile.edt));
668 if (gtk_text_str->len == 0) {
669 /* If no representation then... Try to read the value */
670 proto_item_fill_label(cfile.finfo_selected, stringpointer);
671 g_string_append(gtk_text_str, stringpointer);
674 if (gtk_text_str->len == 0) {
675 /* Could not get item so display error msg */
676 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Could not acquire information to copy, try expanding or choosing another item");
678 /* Copy string to clipboard */
679 copy_to_clipboard(gtk_text_str);
681 g_string_free(gtk_text_str, TRUE); /* Free the memory */
685 /* mark as reference time frame */
687 set_frame_reftime(gboolean set, frame_data *frame, gint row) {
691 frame->flags.ref_time=1;
692 cfile.ref_time_count++;
694 frame->flags.ref_time=0;
695 cfile.ref_time_count--;
697 cf_reftime_packets(&cfile);
698 if (!frame->flags.ref_time && !frame->flags.passed_dfilter) {
699 new_packet_list_freeze();
700 cfile.displayed_count--;
701 new_packet_list_recreate_visible_rows();
702 new_packet_list_thaw();
704 new_packet_list_queue_draw();
708 static void reftime_answered_cb(gpointer dialog _U_, gint btn, gpointer data _U_)
712 timestamp_set_type(TS_RELATIVE);
713 recent.gui_time_format = TS_RELATIVE;
714 cf_timestamp_auto_precision(&cfile);
715 new_packet_list_queue_draw();
720 g_assert_not_reached();
723 if (cfile.current_frame) {
724 set_frame_reftime(!cfile.current_frame->flags.ref_time,
725 cfile.current_frame, cfile.current_row);
731 reftime_frame_cb(GtkWidget *w _U_, gpointer data _U_, REFTIME_ACTION_E action)
733 static GtkWidget *reftime_dialog = NULL;
737 if (cfile.current_frame) {
738 if(recent.gui_time_format != TS_RELATIVE && cfile.current_frame->flags.ref_time==0) {
739 reftime_dialog = simple_dialog(ESD_TYPE_CONFIRMATION, ESD_BTNS_YES_NO,
740 "%sSwitch to the appropriate Time Display Format?%s\n\n"
741 "Time References don't work well with the currently selected Time Display Format.\n\n"
742 "Do you want to switch to \"Seconds Since Beginning of Capture\" now?",
743 simple_dialog_primary_start(), simple_dialog_primary_end());
744 simple_dialog_set_cb(reftime_dialog, reftime_answered_cb, NULL);
746 set_frame_reftime(!cfile.current_frame->flags.ref_time,
747 cfile.current_frame, cfile.current_row);
751 case REFTIME_FIND_NEXT:
752 cf_find_packet_time_reference(&cfile, SD_FORWARD);
754 case REFTIME_FIND_PREV:
755 cf_find_packet_time_reference(&cfile, SD_BACKWARD);
761 find_next_mark_cb(GtkWidget *w _U_, gpointer data _U_, int action _U_)
763 cf_find_packet_marked(&cfile, SD_FORWARD);
767 find_prev_mark_cb(GtkWidget *w _U_, gpointer data _U_, int action _U_)
769 cf_find_packet_marked(&cfile, SD_BACKWARD);
773 tree_view_selection_changed_cb(GtkTreeSelection *sel, gpointer user_data _U_)
776 gchar len_str[2+10+1+5+1]; /* ", {N} bytes\0",
778 gboolean has_blurb = FALSE;
779 guint length = 0, byte_len;
780 GtkWidget *byte_view;
781 const guint8 *byte_data;
786 /* if nothing is selected */
787 if (!gtk_tree_selection_get_selected(sel, &model, &iter))
790 * Which byte view is displaying the current protocol tree
793 byte_view = get_notebook_bv_ptr(byte_nb_ptr_gbl);
794 if (byte_view == NULL)
797 byte_data = get_byte_view_data_and_length(byte_view, &byte_len);
798 if (byte_data == NULL)
801 cf_unselect_field(&cfile);
802 packet_hex_print(byte_view, byte_data,
803 cfile.current_frame, NULL, byte_len);
804 proto_help_menu_modify(sel, &cfile);
807 gtk_tree_model_get(model, &iter, 1, &finfo, -1);
810 set_notebook_page(byte_nb_ptr_gbl, finfo->ds_tvb);
812 byte_view = get_notebook_bv_ptr(byte_nb_ptr_gbl);
813 byte_data = get_byte_view_data_and_length(byte_view, &byte_len);
814 g_assert(byte_data != NULL);
816 cfile.finfo_selected = finfo;
817 set_menus_for_selected_tree_row(&cfile);
820 if (finfo->hfinfo->blurb != NULL &&
821 finfo->hfinfo->blurb[0] != '\0') {
823 length = (guint) strlen(finfo->hfinfo->blurb);
825 length = (guint) strlen(finfo->hfinfo->name);
827 finfo_length = finfo->length + finfo->appendix_length;
829 if (finfo_length == 0) {
831 } else if (finfo_length == 1) {
832 g_strlcpy (len_str, ", 1 byte", sizeof len_str);
834 g_snprintf (len_str, sizeof len_str, ", %d bytes", finfo_length);
836 statusbar_pop_field_msg(); /* get rid of current help msg */
838 statusbar_push_field_msg(" %s (%s)%s",
839 (has_blurb) ? finfo->hfinfo->blurb : finfo->hfinfo->name,
840 finfo->hfinfo->abbrev, len_str);
843 * Don't show anything if the field name is zero-length;
844 * the pseudo-field for "proto_tree_add_text()" is such
845 * a field, and we don't want "Text (text)" showing up
846 * on the status line if you've selected such a field.
848 * XXX - there are zero-length fields for which we *do*
849 * want to show the field name.
851 * XXX - perhaps the name and abbrev field should be null
852 * pointers rather than null strings for that pseudo-field,
853 * but we'd have to add checks for null pointers in some
854 * places if we did that.
856 * Or perhaps protocol tree items added with
857 * "proto_tree_add_text()" should have -1 as the field index,
858 * with no pseudo-field being used, but that might also
859 * require special checks for -1 to be added.
861 statusbar_push_field_msg("%s", "");
864 packet_hex_print(byte_view, byte_data, cfile.current_frame, finfo,
866 proto_help_menu_modify(sel, &cfile);
869 void collapse_all_cb(GtkWidget *widget _U_, gpointer data _U_) {
871 collapse_all_tree(cfile.edt->tree, tree_view_gbl);
874 void expand_all_cb(GtkWidget *widget _U_, gpointer data _U_) {
876 expand_all_tree(cfile.edt->tree, tree_view_gbl);
879 void apply_as_custom_column_cb (GtkWidget *widget _U_, gpointer data _U_)
881 if (cfile.finfo_selected) {
882 column_prefs_add_custom(COL_CUSTOM, cfile.finfo_selected->hfinfo->name,
883 cfile.finfo_selected->hfinfo->abbrev,0);
884 /* Recreate the packet list according to new preferences */
885 new_packet_list_recreate ();
886 if (!prefs.gui_use_pref_save) {
889 cfile.cinfo.columns_changed = FALSE; /* Reset value */
893 void expand_tree_cb(GtkWidget *widget _U_, gpointer data _U_) {
896 path = tree_find_by_field_info(GTK_TREE_VIEW(tree_view_gbl), cfile.finfo_selected);
898 /* the mouse position is at an entry, expand that one */
899 gtk_tree_view_expand_row(GTK_TREE_VIEW(tree_view_gbl), path, TRUE);
900 gtk_tree_path_free(path);
904 void resolve_name_cb(GtkWidget *widget _U_, gpointer data _U_) {
905 if (cfile.edt->tree) {
906 guint32 tmp = gbl_resolv_flags;
907 gbl_resolv_flags = RESOLV_ALL;
908 proto_tree_draw(cfile.edt->tree, tree_view_gbl);
909 gbl_resolv_flags = tmp;
914 main_set_for_capture_file(gboolean have_capture_file_in)
916 have_capture_file = have_capture_file_in;
918 main_widgets_show_or_hide();
924 /* get the current geometry, before writing it to disk */
925 main_save_window_geometry(top_level);
927 /* write user's recent file to disk
928 * It is no problem to write this file, even if we do not quit */
929 write_profile_recent();
932 /* XXX - should we check whether the capture file is an
933 unsaved temporary file for a live capture and, if so,
934 pop up a "do you want to exit without saving the capture
935 file?" dialog, and then just return, leaving said dialog
936 box to forcibly quit if the user clicks "OK"?
938 If so, note that this should be done in a subroutine that
939 returns TRUE if we do so, and FALSE otherwise, and if it
940 returns TRUE we should return TRUE without nuking anything.
942 Note that, if we do that, we might also want to check if
943 an "Update list of packets in real time" capture is in
944 progress and, if so, ask whether they want to terminate
945 the capture and discard it, and return TRUE, before nuking
946 any child capture, if they say they don't want to do so. */
949 /* Nuke any child capture in progress. */
950 capture_kill_child(&global_capture_opts);
953 /* Are we in the middle of reading a capture? */
954 if (cfile.state == FILE_READ_IN_PROGRESS) {
955 /* Yes, so we can't just close the file and quit, as
956 that may yank the rug out from under the read in
957 progress; instead, just set the state to
958 "FILE_READ_ABORTED" and return - the code doing the read
959 will check for that and, if it sees that, will clean
961 cfile.state = FILE_READ_ABORTED;
963 /* Say that the window should *not* be deleted;
964 that'll be done by the code that cleans up. */
967 /* Close any capture file we have open; on some OSes, you
968 can't unlink a temporary capture file if you have it
970 "cf_close()" will unlink it after closing it if
971 it's a temporary file.
973 We do this here, rather than after the main loop returns,
974 as, after the main loop returns, the main window may have
975 been destroyed (if this is called due to a "destroy"
976 even on the main window rather than due to the user
977 selecting a menu item), and there may be a crash
978 or other problem when "cf_close()" tries to
979 clean up stuff in the main window.
981 XXX - is there a better place to put this?
982 Or should we have a routine that *just* closes the
983 capture file, and doesn't do anything with the UI,
984 which we'd call here, and another routine that
985 calls that routine and also cleans up the UI, which
986 we'd call elsewhere? */
989 /* Exit by leaving the main loop, so that any quit functions
990 we registered get called. */
993 /* Say that the window should be deleted. */
999 main_window_delete_event_cb(GtkWidget *widget _U_, GdkEvent *event _U_, gpointer data _U_)
1003 if((cfile.state != FILE_CLOSED) && !cfile.user_saved && prefs.gui_ask_unsaved) {
1004 gtk_window_present(GTK_WINDOW(top_level));
1005 /* user didn't saved his current file, ask him */
1006 dialog = simple_dialog(ESD_TYPE_CONFIRMATION, ESD_BTNS_SAVE_QUIT_DONTSAVE_CANCEL,
1007 "%sSave capture file before program quit?%s\n\n"
1008 "If you quit the program without saving, your capture data will be discarded.",
1009 simple_dialog_primary_start(), simple_dialog_primary_end());
1010 simple_dialog_set_cb(dialog, file_quit_answered_cb, NULL);
1013 /* unchanged file, just exit */
1014 /* "main_do_quit()" indicates whether the main window should be deleted. */
1015 return main_do_quit();
1021 main_pane_load_window_geometry(void)
1023 if (recent.has_gui_geometry_main_upper_pane && recent.gui_geometry_main_upper_pane)
1024 gtk_paned_set_position(GTK_PANED(main_first_pane), recent.gui_geometry_main_upper_pane);
1025 if (recent.has_gui_geometry_main_lower_pane && recent.gui_geometry_main_lower_pane) {
1026 gtk_paned_set_position(GTK_PANED(main_second_pane), recent.gui_geometry_main_lower_pane);
1032 main_load_window_geometry(GtkWidget *widget)
1034 window_geometry_t geom;
1036 geom.set_pos = prefs.gui_geometry_save_position;
1037 geom.x = recent.gui_geometry_main_x;
1038 geom.y = recent.gui_geometry_main_y;
1039 geom.set_size = prefs.gui_geometry_save_size;
1040 if (recent.gui_geometry_main_width > 0 &&
1041 recent.gui_geometry_main_height > 0) {
1042 geom.width = recent.gui_geometry_main_width;
1043 geom.height = recent.gui_geometry_main_height;
1044 geom.set_maximized = prefs.gui_geometry_save_maximized;
1046 /* We assume this means the width and height weren't set in
1047 the "recent" file (or that there is no "recent" file),
1048 and weren't set to a default value, so we don't set the
1049 size. (The "recent" file code rejects non-positive width
1050 and height values.) */
1051 geom.set_size = FALSE;
1053 geom.maximized = recent.gui_geometry_main_maximized;
1055 window_set_geometry(widget, &geom);
1057 main_pane_load_window_geometry();
1058 statusbar_load_window_geometry();
1063 main_save_window_geometry(GtkWidget *widget)
1065 window_geometry_t geom;
1067 window_get_geometry(widget, &geom);
1069 if (prefs.gui_geometry_save_position) {
1070 recent.gui_geometry_main_x = geom.x;
1071 recent.gui_geometry_main_y = geom.y;
1074 if (prefs.gui_geometry_save_size) {
1075 recent.gui_geometry_main_width = geom.width;
1076 recent.gui_geometry_main_height = geom.height;
1079 if(prefs.gui_geometry_save_maximized) {
1080 recent.gui_geometry_main_maximized = geom.maximized;
1083 recent.gui_geometry_main_upper_pane = gtk_paned_get_position(GTK_PANED(main_first_pane));
1084 recent.gui_geometry_main_lower_pane = gtk_paned_get_position(GTK_PANED(main_second_pane));
1085 statusbar_save_window_geometry();
1088 static void file_quit_answered_cb(gpointer dialog _U_, gint btn, gpointer data _U_)
1092 /* save file first */
1093 file_save_as_cmd(after_save_exit, NULL);
1095 case(ESD_BTN_QUIT_DONT_SAVE):
1098 case(ESD_BTN_CANCEL):
1101 g_assert_not_reached();
1106 file_quit_cmd_cb(GtkWidget *widget _U_, gpointer data _U_)
1110 if((cfile.state != FILE_CLOSED) && !cfile.user_saved && prefs.gui_ask_unsaved) {
1111 /* user didn't saved his current file, ask him */
1112 dialog = simple_dialog(ESD_TYPE_CONFIRMATION, ESD_BTNS_SAVE_QUIT_DONTSAVE_CANCEL,
1113 "%sSave capture file before program quit?%s\n\n"
1114 "If you quit the program without saving, your capture data will be discarded.",
1115 simple_dialog_primary_start(), simple_dialog_primary_end());
1116 simple_dialog_set_cb(dialog, file_quit_answered_cb, NULL);
1118 /* unchanged file, just exit */
1124 print_usage(gboolean print_ver) {
1134 fprintf(output, "Wireshark " VERSION "%s\n"
1135 "Interactively dump and analyze network traffic.\n"
1136 "See http://www.wireshark.org for more information.\n"
1139 wireshark_svnversion, get_copyright_info());
1143 fprintf(output, "\n");
1144 fprintf(output, "Usage: wireshark [options] ... [ <infile> ]\n");
1145 fprintf(output, "\n");
1148 fprintf(output, "Capture interface:\n");
1149 fprintf(output, " -i <interface> name or idx of interface (def: first non-loopback)\n");
1150 fprintf(output, " -f <capture filter> packet filter in libpcap filter syntax\n");
1151 fprintf(output, " -s <snaplen> packet snapshot length (def: 65535)\n");
1152 fprintf(output, " -p don't capture in promiscuous mode\n");
1153 fprintf(output, " -k start capturing immediately (def: do nothing)\n");
1154 fprintf(output, " -Q quit Wireshark after capturing\n");
1155 fprintf(output, " -S update packet display when new packets are captured\n");
1156 fprintf(output, " -l turn on automatic scrolling while -S is in use\n");
1157 #if defined(_WIN32) || defined(HAVE_PCAP_CREATE)
1158 fprintf(output, " -B <buffer size> size of kernel buffer (def: 1MB)\n");
1160 fprintf(output, " -y <link type> link layer type (def: first appropriate)\n");
1161 fprintf(output, " -D print list of interfaces and exit\n");
1162 fprintf(output, " -L print list of link-layer types of iface and exit\n");
1163 fprintf(output, "\n");
1164 fprintf(output, "Capture stop conditions:\n");
1165 fprintf(output, " -c <packet count> stop after n packets (def: infinite)\n");
1166 fprintf(output, " -a <autostop cond.> ... duration:NUM - stop after NUM seconds\n");
1167 fprintf(output, " filesize:NUM - stop this file after NUM KB\n");
1168 fprintf(output, " files:NUM - stop after NUM files\n");
1169 /*fprintf(output, "\n");*/
1170 fprintf(output, "Capture output:\n");
1171 fprintf(output, " -b <ringbuffer opt.> ... duration:NUM - switch to next file after NUM secs\n");
1172 fprintf(output, " filesize:NUM - switch to next file after NUM KB\n");
1173 fprintf(output, " files:NUM - ringbuffer: replace after NUM files\n");
1174 #endif /* HAVE_LIBPCAP */
1176 /*fprintf(output, "\n");*/
1177 fprintf(output, "Input file:\n");
1178 fprintf(output, " -r <infile> set the filename to read from (no pipes or stdin!)\n");
1180 fprintf(output, "\n");
1181 fprintf(output, "Processing:\n");
1182 fprintf(output, " -R <read filter> packet filter in Wireshark display filter syntax\n");
1183 fprintf(output, " -n disable all name resolutions (def: all enabled)\n");
1184 fprintf(output, " -N <name resolve flags> enable specific name resolution(s): \"mntC\"\n");
1186 fprintf(output, "\n");
1187 fprintf(output, "User interface:\n");
1188 fprintf(output, " -C <config profile> start with specified configuration profile\n");
1189 fprintf(output, " -g <packet number> go to specified packet number after \"-r\"\n");
1190 fprintf(output, " -J <jump filter> jump to the first packet matching the (display)\n");
1191 fprintf(output, " filter\n");
1192 fprintf(output, " -j search backwards for a matching packet after \"-J\"\n");
1193 fprintf(output, " -m <font> set the font name used for most text\n");
1194 fprintf(output, " -t ad|a|r|d|dd|e output format of time stamps (def: r: rel. to first)\n");
1195 fprintf(output, " -u s|hms output format of seconds (def: s: seconds)\n");
1196 fprintf(output, " -X <key>:<value> eXtension options, see man page for details\n");
1197 fprintf(output, " -z <statistics> show various statistics, see man page for details\n");
1199 fprintf(output, "\n");
1200 fprintf(output, "Output:\n");
1201 fprintf(output, " -w <outfile|-> set the output filename (or '-' for stdout)\n");
1203 fprintf(output, "\n");
1204 fprintf(output, "Miscellaneous:\n");
1205 fprintf(output, " -h display this help and exit\n");
1206 fprintf(output, " -v display version info and exit\n");
1207 fprintf(output, " -P <key>:<path> persconf:path - personal configuration files\n");
1208 fprintf(output, " persdata:path - personal data files\n");
1209 fprintf(output, " -o <name>:<value> ... override preference or recent setting\n");
1210 fprintf(output, " -K <keytab> keytab file to use for kerberos decryption\n");
1212 fprintf(output, " --display=DISPLAY X display to use\n");
1227 printf(PACKAGE " " VERSION "%s\n"
1234 wireshark_svnversion, get_copyright_info(), comp_info_str->str,
1235 runtime_info_str->str);
1243 * Print to the standard error. On Windows, create a console for the
1244 * standard error to show up on, if necessary.
1245 * XXX - pop this up in a window of some sort on UNIX+X11 if the controlling
1246 * terminal isn't the standard error?
1249 vfprintf_stderr(const char *fmt, va_list ap)
1254 vfprintf(stderr, fmt, ap);
1258 fprintf_stderr(const char *fmt, ...)
1263 vfprintf_stderr(fmt, ap);
1268 * Report an error in command-line arguments.
1269 * Creates a console on Windows.
1272 cmdarg_err(const char *fmt, ...)
1276 fprintf_stderr("wireshark: ");
1278 vfprintf_stderr(fmt, ap);
1280 fprintf_stderr("\n");
1284 * Report additional information for an error in command-line arguments.
1285 * Creates a console on Windows.
1286 * XXX - pop this up in a window of some sort on UNIX+X11 if the controlling
1287 * terminal isn't the standard error?
1290 cmdarg_err_cont(const char *fmt, ...)
1295 vfprintf_stderr(fmt, ap);
1296 fprintf_stderr("\n");
1301 Once every 3 seconds we get a callback here which we use to update
1305 tap_update_cb(gpointer data _U_)
1307 draw_tap_listeners(FALSE);
1311 /* Restart the tap update display timer with new configured interval */
1312 void reset_tap_update_timer(void)
1314 g_source_remove(tap_update_timer_id);
1315 tap_update_timer_id = g_timeout_add(prefs.tap_update_interval, tap_update_cb, NULL);
1319 protect_thread_critical_region(void)
1321 /* Threading support for TAP:s removed
1322 * http://www.wireshark.org/lists/wireshark-dev/200611/msg00199.html
1323 * See the commit for removed code:
1324 * http://anonsvn.wireshark.org/viewvc/viewvc.cgi?view=rev&revision=35027
1328 unprotect_thread_critical_region(void)
1330 /* Threading support for TAP:s removed
1331 * http://www.wireshark.org/lists/wireshark-dev/200611/msg00199.html
1337 * Periodically process outstanding hostname lookups. If we have new items,
1338 * redraw the packet list and tree view.
1342 resolv_update_cb(gpointer data _U_)
1344 /* Anything new show up? */
1345 if (host_name_lookup_process(NULL)) {
1346 #if GTK_CHECK_VERSION(2,14,0)
1347 if (gtk_widget_get_window(pkt_scrollw))
1348 gdk_window_invalidate_rect(gtk_widget_get_window(pkt_scrollw), NULL, TRUE);
1349 if (gtk_widget_get_window(tv_scrollw))
1350 gdk_window_invalidate_rect(gtk_widget_get_window(tv_scrollw), NULL, TRUE);
1352 if (pkt_scrollw->window)
1353 gdk_window_invalidate_rect(pkt_scrollw->window, NULL, TRUE);
1354 if (tv_scrollw->window)
1355 gdk_window_invalidate_rect(tv_scrollw->window, NULL, TRUE);
1359 /* Always check. Even if we don't do async lookups we could still get
1360 passive updates, e.g. from DNS packets. */
1365 /* Set main_window_name and it's icon title to the capture filename */
1367 set_display_filename(capture_file *cf)
1372 window_name = g_strdup_printf("%s", cf_get_display_name(cf));
1373 set_main_window_name(window_name);
1374 g_free(window_name);
1376 set_main_window_name("The Wireshark Network Analyzer");
1380 static GtkWidget *close_dlg = NULL;
1383 priv_warning_dialog_cb(gpointer dialog, gint btn _U_, gpointer data _U_)
1385 recent.privs_warn_if_elevated = !simple_dialog_check_get(dialog);
1390 npf_warning_dialog_cb(gpointer dialog, gint btn _U_, gpointer data _U_)
1392 recent.privs_warn_if_no_npf = !simple_dialog_check_get(dialog);
1397 main_cf_cb_file_closing(capture_file *cf)
1400 /* if we have more than 10000 packets, show a splash screen while closing */
1401 /* XXX - don't know a better way to decide whether to show or not,
1402 * as most of the time is spend in a single eth_clist_clear function,
1403 * so we can't use a progress bar here! */
1404 if(cf->count > 10000) {
1405 close_dlg = simple_dialog(ESD_TYPE_STOP, ESD_BTN_NONE,
1406 "%sClosing file!%s\n\nPlease wait ...",
1407 simple_dialog_primary_start(),
1408 simple_dialog_primary_end());
1409 gtk_window_set_position(GTK_WINDOW(close_dlg), GTK_WIN_POS_CENTER_ON_PARENT);
1412 /* Destroy all windows, which refer to the
1413 capture file we're closing. */
1414 destroy_packet_wins();
1415 file_save_as_destroy();
1417 /* Restore the standard title bar message. */
1418 set_main_window_name("The Wireshark Network Analyzer");
1420 /* Disable all menu items that make sense only if you have a capture. */
1421 set_menus_for_capture_file(NULL);
1422 set_menus_for_captured_packets(FALSE);
1423 set_menus_for_selected_packet(cf);
1424 set_menus_for_capture_in_progress(FALSE);
1425 set_capture_if_dialog_for_capture_in_progress(FALSE);
1426 set_menus_for_selected_tree_row(cf);
1428 /* Set up main window for no capture file. */
1429 main_set_for_capture_file(FALSE);
1431 main_window_update();
1435 main_cf_cb_file_closed(capture_file *cf _U_)
1437 if(close_dlg != NULL) {
1438 splash_destroy(close_dlg);
1445 main_cf_cb_file_read_started(capture_file *cf _U_)
1447 tap_dfilter_dlg_update();
1449 /* Set up main window for a capture file. */
1450 main_set_for_capture_file(TRUE);
1454 main_cf_cb_file_read_finished(capture_file *cf)
1458 if (!cf->is_tempfile && cf->filename) {
1459 /* Add this filename to the list of recent files in the "Recent Files" submenu */
1460 add_menu_recent_capture_file(cf->filename);
1462 /* Remember folder for next Open dialog and save it in recent */
1463 dir_path = get_dirname(g_strdup(cf->filename));
1464 set_last_open_dir(dir_path);
1467 set_display_filename(cf);
1469 /* Enable menu items that make sense if you have a capture file you've
1470 finished reading. */
1471 set_menus_for_capture_file(cf);
1473 /* Enable menu items that make sense if you have some captured packets. */
1474 set_menus_for_captured_packets(TRUE);
1478 static GList *icon_list_create(
1479 const char **icon16_xpm,
1480 const char **icon32_xpm,
1481 const char **icon48_xpm,
1482 const char **icon64_xpm)
1484 GList *icon_list = NULL;
1485 GdkPixbuf * pixbuf16;
1486 GdkPixbuf * pixbuf32;
1487 GdkPixbuf * pixbuf48;
1488 GdkPixbuf * pixbuf64;
1491 if(icon16_xpm != NULL) {
1492 pixbuf16 = gdk_pixbuf_new_from_xpm_data(icon16_xpm);
1494 icon_list = g_list_append(icon_list, pixbuf16);
1497 if(icon32_xpm != NULL) {
1498 pixbuf32 = gdk_pixbuf_new_from_xpm_data(icon32_xpm);
1500 icon_list = g_list_append(icon_list, pixbuf32);
1503 if(icon48_xpm != NULL) {
1504 pixbuf48 = gdk_pixbuf_new_from_xpm_data(icon48_xpm);
1506 icon_list = g_list_append(icon_list, pixbuf48);
1509 if(icon64_xpm != NULL) {
1510 pixbuf64 = gdk_pixbuf_new_from_xpm_data(icon64_xpm);
1512 icon_list = g_list_append(icon_list, pixbuf64);
1519 main_capture_set_main_window_title(capture_options *capture_opts)
1521 GString *title = g_string_new("");
1523 g_string_append(title, "Capturing ");
1524 g_string_append_printf(title, "from %s ", cf_get_tempfile_source(capture_opts->cf));
1525 set_main_window_name(title->str);
1526 g_string_free(title, TRUE);
1530 main_capture_cb_capture_prepared(capture_options *capture_opts)
1532 static GList *icon_list = NULL;
1534 main_capture_set_main_window_title(capture_opts);
1536 if(icon_list == NULL) {
1537 icon_list = icon_list_create(wsiconcap16_xpm, wsiconcap32_xpm, wsiconcap48_xpm, NULL);
1539 gtk_window_set_icon_list(GTK_WINDOW(top_level), icon_list);
1541 /* Disable menu items that make no sense if you're currently running
1543 set_menus_for_capture_in_progress(TRUE);
1544 set_capture_if_dialog_for_capture_in_progress(TRUE);
1546 /* Don't set up main window for a capture file. */
1547 main_set_for_capture_file(FALSE);
1551 main_capture_cb_capture_update_started(capture_options *capture_opts)
1553 /* We've done this in "prepared" above, but it will be cleared while
1554 switching to the next multiple file. */
1555 main_capture_set_main_window_title(capture_opts);
1557 set_menus_for_capture_in_progress(TRUE);
1558 set_capture_if_dialog_for_capture_in_progress(TRUE);
1560 /* Enable menu items that make sense if you have some captured
1561 packets (yes, I know, we don't have any *yet*). */
1562 set_menus_for_captured_packets(TRUE);
1564 /* Set up main window for a capture file. */
1565 main_set_for_capture_file(TRUE);
1569 main_capture_cb_capture_update_finished(capture_options *capture_opts)
1571 capture_file *cf = capture_opts->cf;
1572 static GList *icon_list = NULL;
1574 if (!cf->is_tempfile && cf->filename) {
1575 /* Add this filename to the list of recent files in the "Recent Files" submenu */
1576 add_menu_recent_capture_file(cf->filename);
1578 set_display_filename(cf);
1580 /* Enable menu items that make sense if you're not currently running
1582 set_menus_for_capture_in_progress(FALSE);
1583 set_capture_if_dialog_for_capture_in_progress(FALSE);
1585 /* Enable menu items that make sense if you have a capture file
1586 you've finished reading. */
1587 set_menus_for_capture_file(cf);
1589 /* Set up main window for a capture file. */
1590 main_set_for_capture_file(TRUE);
1592 if(icon_list == NULL) {
1593 icon_list = icon_list_create(wsicon16_xpm, wsicon32_xpm, wsicon48_xpm, wsicon64_xpm);
1595 gtk_window_set_icon_list(GTK_WINDOW(top_level), icon_list);
1597 if(global_capture_opts.quit_after_cap) {
1598 /* command line asked us to quit after the capture */
1599 /* don't pop up a dialog to ask for unsaved files etc. */
1605 main_capture_cb_capture_fixed_started(capture_options *capture_opts _U_)
1607 /* Don't set up main window for a capture file. */
1608 main_set_for_capture_file(FALSE);
1612 main_capture_cb_capture_fixed_finished(capture_options *capture_opts _U_)
1615 capture_file *cf = capture_opts->cf;
1617 static GList *icon_list = NULL;
1619 /*set_display_filename(cf);*/
1621 /* Enable menu items that make sense if you're not currently running
1623 set_menus_for_capture_in_progress(FALSE);
1624 set_capture_if_dialog_for_capture_in_progress(FALSE);
1626 /* Restore the standard title bar message */
1627 /* (just in case we have trouble opening the capture file). */
1628 set_main_window_name("The Wireshark Network Analyzer");
1630 if(icon_list == NULL) {
1631 icon_list = icon_list_create(wsicon16_xpm, wsicon32_xpm, wsicon48_xpm, wsicon64_xpm);
1633 gtk_window_set_icon_list(GTK_WINDOW(top_level), icon_list);
1635 /* We don't have loaded the capture file, this will be done later.
1636 * For now we still have simply a blank screen. */
1638 if(global_capture_opts.quit_after_cap) {
1639 /* command line asked us to quit after the capture */
1640 /* don't pop up a dialog to ask for unsaved files etc. */
1645 #endif /* HAVE_LIBPCAP */
1648 main_cf_cb_packet_selected(gpointer data)
1650 capture_file *cf = data;
1652 /* Display the GUI protocol tree and packet bytes.
1653 XXX - why do we dump core if we call "proto_tree_draw()"
1654 before calling "add_byte_views()"? */
1655 add_main_byte_views(cf->edt);
1656 main_proto_tree_draw(cf->edt->tree);
1658 /* Note: Both string and hex value searches in the packet data produce a non-zero
1659 search_pos if successful */
1660 if(cf->search_in_progress &&
1661 (cf->search_pos != 0 || (cf->string && cf->decode_data))) {
1662 highlight_field(cf->edt->tvb, cf->search_pos,
1663 (GtkTreeView *)tree_view_gbl, cf->edt->tree);
1666 /* A packet is selected. */
1667 set_menus_for_selected_packet(cf);
1671 main_cf_cb_packet_unselected(capture_file *cf)
1673 /* Clear out the display of that packet. */
1674 clear_tree_and_hex_views();
1676 /* No packet is selected. */
1677 set_menus_for_selected_packet(cf);
1681 main_cf_cb_field_unselected(capture_file *cf)
1683 set_menus_for_selected_tree_row(cf);
1687 main_cf_cb_file_save_reload_finished(gpointer data _U_)
1689 set_display_filename(&cfile);
1690 set_menus_for_capture_file(&cfile);
1694 main_cf_callback(gint event, gpointer data, gpointer user_data _U_)
1697 case(cf_cb_file_closing):
1698 g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: Closing");
1699 main_cf_cb_file_closing(data);
1701 case(cf_cb_file_closed):
1702 g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: Closed");
1703 main_cf_cb_file_closed(data);
1705 case(cf_cb_file_read_started):
1706 g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: Read started");
1707 main_cf_cb_file_read_started(data);
1709 case(cf_cb_file_read_finished):
1710 g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: Read finished");
1711 main_cf_cb_file_read_finished(data);
1713 case(cf_cb_packet_selected):
1714 main_cf_cb_packet_selected(data);
1716 case(cf_cb_packet_unselected):
1717 main_cf_cb_packet_unselected(data);
1719 case(cf_cb_field_unselected):
1720 main_cf_cb_field_unselected(data);
1722 case(cf_cb_file_save_started):
1723 g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: Save started");
1725 case(cf_cb_file_save_finished):
1726 g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: Save finished");
1728 case(cf_cb_file_save_reload_finished):
1729 g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: Reload finished");
1730 main_cf_cb_file_save_reload_finished(data);
1732 case(cf_cb_file_save_failed):
1733 g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: Save failed");
1736 g_warning("main_cf_callback: event %u unknown", event);
1737 g_assert_not_reached();
1743 main_capture_callback(gint event, capture_options *capture_opts, gpointer user_data _U_)
1745 #ifdef HAVE_GTKOSXAPPLICATION
1746 GtkOSXApplication *theApp;
1749 case(capture_cb_capture_prepared):
1750 g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: capture prepared");
1751 main_capture_cb_capture_prepared(capture_opts);
1753 case(capture_cb_capture_update_started):
1754 g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: capture update started");
1755 main_capture_cb_capture_update_started(capture_opts);
1756 #ifdef HAVE_GTKOSXAPPLICATION
1757 theApp = g_object_new(GTK_TYPE_OSX_APPLICATION, NULL);
1758 gtk_osxapplication_set_dock_icon_pixbuf(theApp,gdk_pixbuf_new_from_xpm_data(wsiconcap48_xpm));
1761 case(capture_cb_capture_update_continue):
1762 /*g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: capture update continue");*/
1764 case(capture_cb_capture_update_finished):
1765 g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: capture update finished");
1766 main_capture_cb_capture_update_finished(capture_opts);
1768 case(capture_cb_capture_fixed_started):
1769 g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: capture fixed started");
1770 main_capture_cb_capture_fixed_started(capture_opts);
1772 case(capture_cb_capture_fixed_continue):
1773 g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: capture fixed continue");
1775 case(capture_cb_capture_fixed_finished):
1776 g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: capture fixed finished");
1777 main_capture_cb_capture_fixed_finished(capture_opts);
1779 case(capture_cb_capture_stopping):
1780 g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: capture stopping");
1781 /* Beware: this state won't be called, if the capture child
1782 * closes the capturing on it's own! */
1783 #ifdef HAVE_GTKOSXAPPLICATION
1784 theApp = g_object_new(GTK_TYPE_OSX_APPLICATION, NULL);
1785 gtk_osxapplication_set_dock_icon_pixbuf(theApp,gdk_pixbuf_new_from_xpm_data(wsicon64_xpm));
1789 g_warning("main_capture_callback: event %u unknown", event);
1790 g_assert_not_reached();
1796 get_gtk_compiled_info(GString *str)
1798 g_string_append(str, "with ");
1799 g_string_append_printf(str,
1800 #ifdef GTK_MAJOR_VERSION
1801 "GTK+ %d.%d.%d", GTK_MAJOR_VERSION, GTK_MINOR_VERSION,
1804 "GTK+ (version unknown)");
1806 g_string_append(str, ", ");
1810 get_gui_compiled_info(GString *str)
1812 epan_get_compiled_version_info(str);
1814 g_string_append(str, ", ");
1815 #ifdef HAVE_LIBPORTAUDIO
1816 #ifdef PORTAUDIO_API_1
1817 g_string_append(str, "with PortAudio <= V18");
1818 #else /* PORTAUDIO_API_1 */
1819 g_string_append(str, "with ");
1820 g_string_append(str, Pa_GetVersionText());
1821 #endif /* PORTAUDIO_API_1 */
1822 #else /* HAVE_LIBPORTAUDIO */
1823 g_string_append(str, "without PortAudio");
1824 #endif /* HAVE_LIBPORTAUDIO */
1826 g_string_append(str, ", ");
1828 get_compiled_airpcap_version(str);
1830 g_string_append(str, "without AirPcap");
1835 get_gui_runtime_info(GString *str)
1837 epan_get_runtime_version_info(str);
1840 g_string_append(str, ", ");
1841 get_runtime_airpcap_version(str);
1845 g_string_append(str, ", ");
1846 u3_runtime_info(str);
1851 read_configuration_files(char **gdp_path, char **dp_path)
1853 int gpf_open_errno, gpf_read_errno;
1854 int cf_open_errno, df_open_errno;
1855 int gdp_open_errno, gdp_read_errno;
1856 int dp_open_errno, dp_read_errno;
1857 char *gpf_path, *pf_path;
1858 char *cf_path, *df_path;
1859 int pf_open_errno, pf_read_errno;
1862 /* Read the preference files. */
1863 prefs_p = read_prefs(&gpf_open_errno, &gpf_read_errno, &gpf_path,
1864 &pf_open_errno, &pf_read_errno, &pf_path);
1866 if (gpf_path != NULL) {
1867 if (gpf_open_errno != 0) {
1868 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1869 "Could not open global preferences file\n\"%s\": %s.", gpf_path,
1870 strerror(gpf_open_errno));
1872 if (gpf_read_errno != 0) {
1873 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1874 "I/O error reading global preferences file\n\"%s\": %s.", gpf_path,
1875 strerror(gpf_read_errno));
1878 if (pf_path != NULL) {
1879 if (pf_open_errno != 0) {
1880 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1881 "Could not open your preferences file\n\"%s\": %s.", pf_path,
1882 strerror(pf_open_errno));
1884 if (pf_read_errno != 0) {
1885 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1886 "I/O error reading your preferences file\n\"%s\": %s.", pf_path,
1887 strerror(pf_read_errno));
1894 /* if the user wants a console to be always there, well, we should open one for him */
1895 if (prefs_p->gui_console_open == console_open_always) {
1900 /* Read the capture filter file. */
1901 read_filter_list(CFILTER_LIST, &cf_path, &cf_open_errno);
1902 if (cf_path != NULL) {
1903 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1904 "Could not open your capture filter file\n\"%s\": %s.", cf_path,
1905 strerror(cf_open_errno));
1909 /* Read the display filter file. */
1910 read_filter_list(DFILTER_LIST, &df_path, &df_open_errno);
1911 if (df_path != NULL) {
1912 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1913 "Could not open your display filter file\n\"%s\": %s.", df_path,
1914 strerror(df_open_errno));
1918 /* Read the disabled protocols file. */
1919 read_disabled_protos_list(gdp_path, &gdp_open_errno, &gdp_read_errno,
1920 dp_path, &dp_open_errno, &dp_read_errno);
1921 if (*gdp_path != NULL) {
1922 if (gdp_open_errno != 0) {
1923 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1924 "Could not open global disabled protocols file\n\"%s\": %s.",
1925 *gdp_path, strerror(gdp_open_errno));
1927 if (gdp_read_errno != 0) {
1928 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1929 "I/O error reading global disabled protocols file\n\"%s\": %s.",
1930 *gdp_path, strerror(gdp_read_errno));
1935 if (*dp_path != NULL) {
1936 if (dp_open_errno != 0) {
1937 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1938 "Could not open your disabled protocols file\n\"%s\": %s.", *dp_path,
1939 strerror(dp_open_errno));
1941 if (dp_read_errno != 0) {
1942 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1943 "I/O error reading your disabled protocols file\n\"%s\": %s.", *dp_path,
1944 strerror(dp_read_errno));
1953 /* Check if there's something important to tell the user during startup.
1954 * We want to do this *after* showing the main window so that any windows
1955 * we pop up will be above the main window.
1959 check_and_warn_user_startup(gchar *cf_name)
1961 check_and_warn_user_startup(gchar *cf_name _U_)
1964 gchar *cur_user, *cur_group;
1965 gpointer priv_warning_dialog;
1967 /* Tell the user not to run as root. */
1968 if (running_with_special_privs() && recent.privs_warn_if_elevated) {
1969 cur_user = get_cur_username();
1970 cur_group = get_cur_groupname();
1971 priv_warning_dialog = simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1972 "Running as user \"%s\" and group \"%s\".\n"
1973 "This could be dangerous.", cur_user, cur_group);
1976 simple_dialog_check_set(priv_warning_dialog, "Don't show this message again.");
1977 simple_dialog_set_cb(priv_warning_dialog, priv_warning_dialog_cb, NULL);
1981 /* Warn the user if npf.sys isn't loaded. */
1982 if (!stdin_capture && !cf_name && !npf_sys_is_running() && recent.privs_warn_if_no_npf && get_os_major_version() >= 6) {
1983 priv_warning_dialog = simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1984 "The NPF driver isn't running. You may have trouble\n"
1985 "capturing or listing interfaces.");
1986 simple_dialog_check_set(priv_warning_dialog, "Don't show this message again.");
1987 simple_dialog_set_cb(priv_warning_dialog, npf_warning_dialog_cb, NULL);
1994 /* And now our feature presentation... [ fade to music ] */
1996 main(int argc, char *argv[])
1998 char *init_progfile_dir_error;
2001 gboolean arg_error = FALSE;
2003 extern int info_update_freq; /* Found in about_dlg.c. */
2004 const gchar *filter;
2012 char *gdp_path, *dp_path;
2015 gboolean start_capture = FALSE;
2016 gboolean list_link_layer_types = FALSE;
2020 gboolean capture_option_specified = FALSE;
2027 gint pl_size = 280, tv_size = 95, bv_size = 75;
2028 gchar *rc_file, *cf_name = NULL, *rfilter = NULL, *jfilter = NULL;
2029 dfilter_t *rfcode = NULL;
2030 gboolean rfilter_parse_failed = FALSE;
2033 GtkWidget *splash_win = NULL;
2034 GLogLevelFlags log_flags;
2035 guint go_to_packet = 0;
2036 gboolean jump_backwards = FALSE;
2037 dfilter_t *jump_to_filter = NULL;
2040 #ifdef HAVE_GTKOSXAPPLICATION
2041 GtkOSXApplication *theApp;
2045 #if defined(_WIN32) || defined(HAVE_PCAP_CREATE)
2046 #define OPTSTRING_B "B:"
2048 #define OPTSTRING_B ""
2049 #endif /* _WIN32 or HAVE_PCAP_CREATE */
2050 #else /* HAVE_LIBPCAP */
2051 #define OPTSTRING_B ""
2052 #endif /* HAVE_LIBPCAP */
2054 #ifdef HAVE_PCAP_CREATE
2055 #define OPTSTRING_I "I"
2057 #define OPTSTRING_I ""
2060 #define OPTSTRING "a:b:" OPTSTRING_B "c:C:Df:g:Hhi:" OPTSTRING_I "jJ:kK:lLm:nN:o:P:pQr:R:Ss:t:u:vw:X:y:z:"
2062 static const char optstring[] = OPTSTRING;
2065 arg_list_utf_16to8(argc, argv);
2069 * Get credential information for later use, and drop privileges
2070 * before doing anything else.
2071 * Let the user know if anything happened.
2073 init_process_policies();
2074 relinquish_special_privs_perm();
2077 * Attempt to get the pathname of the executable file.
2079 init_progfile_dir_error = init_progfile_dir(argv[0], main);
2081 /* initialize the funnel mini-api */
2082 initialize_funnel_ops();
2084 AirPDcapInitContext(&airpdcap_ctx);
2087 /* Load wpcap if possible. Do this before collecting the run-time version information */
2090 /* ... and also load the packet.dll from wpcap */
2091 wpcap_packet_load();
2094 /* Load the airpcap.dll. This must also be done before collecting
2095 * run-time version information. */
2096 airpcap_dll_ret_val = load_airpcap();
2098 switch (airpcap_dll_ret_val) {
2099 case AIRPCAP_DLL_OK:
2100 /* load the airpcap interfaces */
2101 airpcap_if_list = get_airpcap_interface_list(&err, &err_str);
2103 if (airpcap_if_list == NULL || g_list_length(airpcap_if_list) == 0){
2104 if (err == CANT_GET_AIRPCAP_INTERFACE_LIST && err_str != NULL) {
2105 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s", "Failed to open Airpcap Adapters!");
2108 airpcap_if_active = NULL;
2112 /* select the first ad default (THIS SHOULD BE CHANGED) */
2113 airpcap_if_active = airpcap_get_default_if(airpcap_if_list);
2118 * XXX - Maybe we need to warn the user if one of the following happens???
2120 case AIRPCAP_DLL_OLD:
2121 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s","AIRPCAP_DLL_OLD\n");
2124 case AIRPCAP_DLL_ERROR:
2125 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s","AIRPCAP_DLL_ERROR\n");
2128 case AIRPCAP_DLL_NOT_FOUND:
2129 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s","AIRPCAP_DDL_NOT_FOUND\n");
2133 #endif /* HAVE_AIRPCAP */
2135 /* Start windows sockets */
2136 WSAStartup( MAKEWORD( 1, 1 ), &wsaData );
2139 profile_store_persconffiles (TRUE);
2141 /* Assemble the compile-time version information string */
2142 comp_info_str = g_string_new("Compiled ");
2144 get_compiled_version_info(comp_info_str, get_gtk_compiled_info, get_gui_compiled_info);
2146 /* Assemble the run-time version information string */
2147 runtime_info_str = g_string_new("Running ");
2148 get_runtime_version_info(runtime_info_str, get_gui_runtime_info);
2150 /* Read the profile independent recent file. We have to do this here so we can */
2151 /* set the profile before it can be set from the command line parameterts */
2152 recent_read_static(&rf_path, &rf_open_errno);
2153 if (rf_path != NULL && rf_open_errno != 0) {
2154 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
2155 "Could not open common recent file\n\"%s\": %s.",
2156 rf_path, strerror(rf_open_errno));
2159 /* "pre-scan" the command line parameters, if we have "console only"
2160 parameters. We do this so we don't start GTK+ if we're only showing
2161 command-line help or version information.
2163 XXX - this pre-scan is done before we start GTK+, so we haven't
2164 run gtk_init() on the arguments. That means that GTK+ arguments
2165 have not been removed from the argument list; those arguments
2166 begin with "--", and will be treated as an error by getopt().
2168 We thus ignore errors - *and* set "opterr" to 0 to suppress the
2171 optind_initial = optind;
2172 while ((opt = getopt(argc, argv, optstring)) != -1) {
2174 case 'C': /* Configuration Profile */
2175 if (profile_exists (optarg, FALSE)) {
2176 set_profile_name (optarg);
2178 cmdarg_err("Configuration Profile \"%s\" does not exist", optarg);
2182 case 'D': /* Print a list of capture devices and exit */
2184 if_list = capture_interface_list(&err, &err_str);
2185 if (if_list == NULL) {
2187 case CANT_GET_INTERFACE_LIST:
2188 cmdarg_err("%s", err_str);
2192 case NO_INTERFACES_FOUND:
2193 cmdarg_err("There are no interfaces on which a capture can be done");
2198 capture_opts_print_interfaces(if_list);
2199 free_interface_list(if_list);
2202 capture_option_specified = TRUE;
2206 case 'h': /* Print help and exit */
2212 if (strcmp(optarg, "-") == 0)
2213 stdin_capture = TRUE;
2216 case 'P': /* Path settings - change these before the Preferences and alike are processed */
2217 status = filesystem_opt(opt, optarg);
2219 cmdarg_err("-P flag \"%s\" failed (hint: is it quoted and existing?)", optarg);
2223 case 'v': /* Show version and exit */
2229 * Extension command line options have to be processed before
2230 * we call epan_init() as they are supposed to be used by dissectors
2231 * or taps very early in the registration process.
2235 case '?': /* Ignore errors - the "real" scan will catch them. */
2240 /* Init the "Open file" dialog directory */
2241 /* (do this after the path settings are processed) */
2243 /* Read the profile dependent (static part) of the recent file. */
2244 /* Only the static part of it will be read, as we don't have the gui now to fill the */
2245 /* recent lists which is done in the dynamic part. */
2246 /* We have to do this already here, so command line parameters can overwrite these values. */
2247 recent_read_profile_static(&rf_path, &rf_open_errno);
2248 if (rf_path != NULL && rf_open_errno != 0) {
2249 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
2250 "Could not open recent file\n\"%s\": %s.",
2251 rf_path, strerror(rf_open_errno));
2254 if (recent.gui_fileopen_remembered_dir &&
2255 test_for_directory(recent.gui_fileopen_remembered_dir) == EISDIR) {
2256 set_last_open_dir(recent.gui_fileopen_remembered_dir);
2258 set_last_open_dir(get_persdatafile_dir());
2261 /* Set getopt index back to initial value, so it will start with the
2262 first command line parameter again. Also reset opterr to 1, so that
2263 error messages are printed by getopt().
2265 XXX - this seems to work on most platforms, but time will tell.
2266 The Single UNIX Specification says "The getopt() function need
2267 not be reentrant", so this isn't guaranteed to work. The Mac
2268 OS X 10.4[.x] getopt() man page says
2270 In order to use getopt() to evaluate multiple sets of arguments, or to
2271 evaluate a single set of arguments multiple times, the variable optreset
2272 must be set to 1 before the second and each additional set of calls to
2273 getopt(), and the variable optind must be reinitialized.
2277 The optreset variable was added to make it possible to call the getopt()
2278 function multiple times. This is an extension to the IEEE Std 1003.2
2279 (``POSIX.2'') specification.
2281 which I think comes from one of the other BSDs.
2283 XXX - if we want to control all the command-line option errors, so
2284 that we can display them where we choose (e.g., in a window), we'd
2285 want to leave opterr as 0, and produce our own messages using optopt.
2286 We'd have to check the value of optopt to see if it's a valid option
2287 letter, in which case *presumably* the error is "this option requires
2288 an argument but none was specified", or not a valid option letter,
2289 in which case *presumably* the error is "this option isn't valid".
2290 Some versions of getopt() let you supply a option string beginning
2291 with ':', which means that getopt() will return ':' rather than '?'
2292 for "this option requires an argument but none was specified", but
2294 optind = optind_initial;
2297 /* Set the current locale according to the program environment.
2298 * We haven't localized anything, but some GTK widgets are localized
2299 * (the file selection dialogue, for example).
2300 * This also sets the C-language locale to the native environment. */
2303 /* Let GTK get its args (will need an X server, so do this after command line only commands handled) */
2304 gtk_init (&argc, &argv);
2306 cf_callback_add(main_cf_callback, NULL);
2308 capture_callback_add(main_capture_callback, NULL);
2310 cf_callback_add(statusbar_cf_callback, NULL);
2312 capture_callback_add(statusbar_capture_callback, NULL);
2315 /* Arrange that if we have no console window, and a GLib message logging
2316 routine is called to log a message, we pop up a console window.
2318 We do that by inserting our own handler for all messages logged
2319 to the default domain; that handler pops up a console if necessary,
2320 and then calls the default handler. */
2322 /* We might want to have component specific log levels later ... */
2326 G_LOG_LEVEL_CRITICAL|
2327 G_LOG_LEVEL_WARNING|
2328 G_LOG_LEVEL_MESSAGE|
2331 G_LOG_FLAG_FATAL|G_LOG_FLAG_RECURSION;
2333 g_log_set_handler(NULL,
2335 console_log_handler, NULL /* user_data */);
2336 g_log_set_handler(LOG_DOMAIN_MAIN,
2338 console_log_handler, NULL /* user_data */);
2341 g_log_set_handler(LOG_DOMAIN_CAPTURE,
2343 console_log_handler, NULL /* user_data */);
2344 g_log_set_handler(LOG_DOMAIN_CAPTURE_CHILD,
2346 console_log_handler, NULL /* user_data */);
2348 /* Set the initial values in the capture options. This might be overwritten
2349 by preference settings and then again by the command line parameters. */
2350 capture_opts_init(&global_capture_opts, &cfile);
2353 /* Initialize whatever we need to allocate colors for GTK+ */
2356 /* Non-blank filter means we're remote. Throttle splash screen and resolution updates. */
2357 filter = get_conn_cfilter();
2358 if ( *filter != '\0' ) {
2359 info_update_freq = 1000; /* Milliseconds */
2362 /* We won't come till here, if we had a "console only" command line parameter. */
2363 splash_win = splash_new("Loading Wireshark ...");
2364 if (init_progfile_dir_error != NULL) {
2365 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
2366 "Can't get pathname of Wireshark: %s.\n"
2367 "It won't be possible to capture traffic.\n"
2368 "Report this to the Wireshark developers.",
2369 init_progfile_dir_error);
2370 g_free(init_progfile_dir_error);
2373 splash_update(RA_DISSECTORS, NULL, (gpointer)splash_win);
2375 /* Register all dissectors; we must do this before checking for the
2376 "-G" flag, as the "-G" flag dumps information registered by the
2377 dissectors, and we must do it before we read the preferences, in
2378 case any dissectors register preferences. */
2379 epan_init(register_all_protocols,register_all_protocol_handoffs,
2380 splash_update, (gpointer) splash_win,
2381 failure_alert_box,open_failure_alert_box,read_failure_alert_box,
2382 write_failure_alert_box);
2384 splash_update(RA_LISTENERS, NULL, (gpointer)splash_win);
2386 /* Register all tap listeners; we do this before we parse the arguments,
2387 as the "-z" argument can specify a registered tap. */
2389 /* we register the plugin taps before the other taps because
2390 stats_tree taps plugins will be registered as tap listeners
2391 by stats_tree_stat.c and need to registered before that */
2394 register_all_plugin_tap_listeners();
2397 register_all_tap_listeners();
2399 splash_update(RA_PREFERENCES, NULL, (gpointer)splash_win);
2401 /* Now register the preferences for any non-dissector modules.
2402 We must do that before we read the preferences as well. */
2403 prefs_register_modules();
2405 prefs_p = read_configuration_files (&gdp_path, &dp_path);
2406 /* Removed thread code:
2407 * http://anonsvn.wireshark.org/viewvc/viewvc.cgi?view=rev&revision=35027
2410 /* this is to keep tap extensions updating once every 3 seconds */
2411 tap_update_timer_id = g_timeout_add(prefs_p->tap_update_interval, tap_update_cb, NULL);
2413 splash_update(RA_CONFIGURATION, NULL, (gpointer)splash_win);
2415 cap_file_init(&cfile);
2417 /* Fill in capture options with values from the preferences */
2418 prefs_to_capture_opts();
2420 /* Now get our args */
2421 while ((opt = getopt(argc, argv, optstring)) != -1) {
2423 /*** capture option specific ***/
2424 case 'a': /* autostop criteria */
2425 case 'b': /* Ringbuffer option */
2426 case 'c': /* Capture xxx packets */
2427 case 'f': /* capture filter */
2428 case 'k': /* Start capture immediately */
2429 case 'H': /* Hide capture info dialog box */
2430 case 'i': /* Use interface xxx */
2431 case 'p': /* Don't capture in promiscuous mode */
2432 #ifdef HAVE_PCAP_CREATE
2433 case 'I': /* Capture in monitor mode, if available */
2435 case 'Q': /* Quit after capture (just capture to file) */
2436 case 's': /* Set the snapshot (capture) length */
2437 case 'S': /* "Sync" mode: used for following file ala tail -f */
2438 case 'w': /* Write to capture file xxx */
2439 case 'y': /* Set the pcap data link type */
2440 #if defined(_WIN32) || defined(HAVE_PCAP_CREATE)
2441 case 'B': /* Buffer size */
2442 #endif /* _WIN32 or HAVE_PCAP_CREATE */
2444 status = capture_opts_add_opt(&global_capture_opts, opt, optarg,
2450 capture_option_specified = TRUE;
2455 #if defined(HAVE_HEIMDAL_KERBEROS) || defined(HAVE_MIT_KERBEROS)
2456 case 'K': /* Kerberos keytab file */
2457 read_keytab_file(optarg);
2461 /*** all non capture option specific ***/
2463 /* Configuration profile settings were already processed just ignore them this time*/
2465 case 'j': /* Search backwards for a matching packet from filter in option J */
2466 jump_backwards = TRUE;
2468 case 'g': /* Go to packet with the given packet number */
2469 go_to_packet = get_positive_int(optarg, "go to packet");
2471 case 'J': /* Jump to the first packet which matches the filter criteria */
2474 case 'l': /* Automatic scrolling in live capture mode */
2476 auto_scroll_live = TRUE;
2478 capture_option_specified = TRUE;
2482 case 'L': /* Print list of link-layer types and exit */
2484 list_link_layer_types = TRUE;
2486 capture_option_specified = TRUE;
2490 case 'm': /* Fixed-width font for the display */
2491 g_free(prefs_p->gui_font_name);
2492 prefs_p->gui_font_name = g_strdup(optarg);
2494 case 'n': /* No name resolution */
2495 gbl_resolv_flags = RESOLV_NONE;
2497 case 'N': /* Select what types of addresses/port #s to resolve */
2498 if (gbl_resolv_flags == RESOLV_ALL)
2499 gbl_resolv_flags = RESOLV_NONE;
2500 badopt = string_to_name_resolve(optarg, &gbl_resolv_flags);
2501 if (badopt != '\0') {
2502 cmdarg_err("-N specifies unknown resolving option '%c'; valid options are 'm', 'n', and 't'",
2507 case 'o': /* Override preference from command line */
2508 switch (prefs_set_pref(optarg)) {
2511 case PREFS_SET_SYNTAX_ERR:
2512 cmdarg_err("Invalid -o flag \"%s\"", optarg);
2515 case PREFS_SET_NO_SUCH_PREF:
2516 /* not a preference, might be a recent setting */
2517 switch (recent_set_arg(optarg)) {
2520 case PREFS_SET_SYNTAX_ERR:
2521 /* shouldn't happen, checked already above */
2522 cmdarg_err("Invalid -o flag \"%s\"", optarg);
2525 case PREFS_SET_NO_SUCH_PREF:
2526 case PREFS_SET_OBSOLETE:
2527 cmdarg_err("-o flag \"%s\" specifies unknown preference/recent value",
2532 g_assert_not_reached();
2535 case PREFS_SET_OBSOLETE:
2536 cmdarg_err("-o flag \"%s\" specifies obsolete preference",
2541 g_assert_not_reached();
2545 /* Path settings were already processed just ignore them this time*/
2547 case 'r': /* Read capture file xxx */
2548 /* We may set "last_open_dir" to "cf_name", and if we change
2549 "last_open_dir" later, we free the old value, so we have to
2550 set "cf_name" to something that's been allocated. */
2551 cf_name = g_strdup(optarg);
2553 case 'R': /* Read file filter */
2556 case 't': /* Time stamp type */
2557 if (strcmp(optarg, "r") == 0)
2558 timestamp_set_type(TS_RELATIVE);
2559 else if (strcmp(optarg, "a") == 0)
2560 timestamp_set_type(TS_ABSOLUTE);
2561 else if (strcmp(optarg, "ad") == 0)
2562 timestamp_set_type(TS_ABSOLUTE_WITH_DATE);
2563 else if (strcmp(optarg, "d") == 0)
2564 timestamp_set_type(TS_DELTA);
2565 else if (strcmp(optarg, "dd") == 0)
2566 timestamp_set_type(TS_DELTA_DIS);
2567 else if (strcmp(optarg, "e") == 0)
2568 timestamp_set_type(TS_EPOCH);
2570 cmdarg_err("Invalid time stamp type \"%s\"", optarg);
2571 cmdarg_err_cont("It must be \"r\" for relative, \"a\" for absolute,");
2572 cmdarg_err_cont("\"ad\" for absolute with date, or \"d\" for delta.");
2576 case 'u': /* Seconds type */
2577 if (strcmp(optarg, "s") == 0)
2578 timestamp_set_seconds_type(TS_SECONDS_DEFAULT);
2579 else if (strcmp(optarg, "hms") == 0)
2580 timestamp_set_seconds_type(TS_SECONDS_HOUR_MIN_SEC);
2582 cmdarg_err("Invalid seconds type \"%s\"", optarg);
2583 cmdarg_err_cont("It must be \"s\" for seconds or \"hms\" for hours, minutes and seconds.");
2588 /* ext ops were already processed just ignore them this time*/
2591 /* We won't call the init function for the stat this soon
2592 as it would disallow MATE's fields (which are registered
2593 by the preferences set callback) from being used as
2594 part of a tap filter. Instead, we just add the argument
2595 to a list of stat arguments. */
2596 if (!process_stat_cmd_arg(optarg)) {
2597 cmdarg_err("Invalid -z argument.");
2598 cmdarg_err_cont(" -z argument must be one of :");
2599 list_stat_cmd_args();
2604 case '?': /* Bad flag - print usage message */
2612 if (cf_name != NULL) {
2614 * Input file name specified with "-r" *and* specified as a regular
2615 * command-line argument.
2617 cmdarg_err("File name specified both with -r and regular argument");
2621 * Input file name not specified with "-r", and a command-line argument
2622 * was specified; treat it as the input file name.
2624 * Yes, this is different from tshark, where non-flag command-line
2625 * arguments are a filter, but this works better on GUI desktops
2626 * where a command can be specified to be run to open a particular
2627 * file - yes, you could have "-r" as the last part of the command,
2628 * but that's a bit ugly.
2630 cf_name = g_strdup(argv[0]);
2638 * Extra command line arguments were specified; complain.
2640 cmdarg_err("Invalid argument: %s", argv[0]);
2645 #ifndef HAVE_LIBPCAP
2646 if (capture_option_specified) {
2647 cmdarg_err("This version of Wireshark was not built with support for capturing packets.");
2655 if (start_capture && list_link_layer_types) {
2656 /* Specifying *both* is bogus. */
2657 cmdarg_err("You can't specify both -L and a live capture.");
2661 if (list_link_layer_types) {
2662 /* We're supposed to list the link-layer types for an interface;
2663 did the user also specify a capture file to be read? */
2665 /* Yes - that's bogus. */
2666 cmdarg_err("You can't specify -L and a capture file to be read.");
2669 /* No - did they specify a ring buffer option? */
2670 if (global_capture_opts.multi_files_on) {
2671 cmdarg_err("Ring buffer requested, but a capture isn't being done.");
2675 /* We're supposed to do a live capture; did the user also specify
2676 a capture file to be read? */
2677 if (start_capture && cf_name) {
2678 /* Yes - that's bogus. */
2679 cmdarg_err("You can't specify both a live capture and a capture file to be read.");
2683 /* No - was the ring buffer option specified and, if so, does it make
2685 if (global_capture_opts.multi_files_on) {
2686 /* Ring buffer works only under certain conditions:
2687 a) ring buffer does not work with temporary files;
2688 b) real_time_mode and multi_files_on are mutually exclusive -
2689 real_time_mode takes precedence;
2690 c) it makes no sense to enable the ring buffer if the maximum
2691 file size is set to "infinite". */
2692 if (global_capture_opts.save_file == NULL) {
2693 cmdarg_err("Ring buffer requested, but capture isn't being saved to a permanent file.");
2694 global_capture_opts.multi_files_on = FALSE;
2696 /* if (global_capture_opts.real_time_mode) {
2697 cmdarg_err("Ring buffer requested, but an \"Update list of packets in real time\" capture is being done.");
2698 global_capture_opts.multi_files_on = FALSE;
2700 if (!global_capture_opts.has_autostop_filesize && !global_capture_opts.has_file_duration) {
2701 cmdarg_err("Ring buffer requested, but no maximum capture file size or duration were specified.");
2702 /* XXX - this must be redesigned as the conditions changed */
2703 /* global_capture_opts.multi_files_on = FALSE;*/
2708 if (start_capture || list_link_layer_types) {
2709 /* Did the user specify an interface to use? */
2710 if (!capture_opts_trim_iface(&global_capture_opts,
2711 (prefs_p->capture_device) ? get_if_name(prefs_p->capture_device) : NULL)) {
2716 if (list_link_layer_types) {
2717 /* Get the list of link-layer types for the capture devices. */
2718 if_capabilities_t *caps;
2720 interface_options interface_opts;
2722 for (i = 0; i < global_capture_opts.ifaces->len; i++) {
2724 interface_opts = g_array_index(global_capture_opts.ifaces, interface_options, i);
2725 caps = capture_get_if_capabilities(interface_opts.name, interface_opts.monitor_mode, &err_str);
2727 cmdarg_err("%s", err_str);
2731 if (caps->data_link_types == NULL) {
2732 cmdarg_err("The capture device \"%s\" has no data link types.", interface_opts.name);
2735 capture_opts_print_if_capabilities(caps, interface_opts.name, interface_opts.monitor_mode);
2736 free_if_capabilities(caps);
2741 capture_opts_trim_snaplen(&global_capture_opts, MIN_PACKET_SIZE);
2742 capture_opts_trim_ring_num_files(&global_capture_opts);
2743 #endif /* HAVE_LIBPCAP */
2745 /* Notify all registered modules that have had any of their preferences
2746 changed either from one of the preferences file or from the command
2747 line that their preferences have changed. */
2750 /* disabled protocols as per configuration file */
2751 if (gdp_path == NULL && dp_path == NULL) {
2752 set_disabled_protos_list();
2755 build_column_format_array(&cfile.cinfo, prefs_p->num_cols, TRUE);
2757 /* read in rc file from global and personal configuration paths. */
2758 rc_file = get_datafile_path(RC_FILE);
2759 gtk_rc_parse(rc_file);
2761 rc_file = get_persconffile_path(RC_FILE, FALSE, FALSE);
2762 gtk_rc_parse(rc_file);
2771 /* close the splash screen, as we are going to open the main window now */
2772 splash_destroy(splash_win);
2774 /************************************************************************/
2775 /* Everything is prepared now, preferences and command line was read in */
2777 /* Pop up the main window. */
2778 create_main_window(pl_size, tv_size, bv_size, prefs_p);
2780 /* Read the dynamic part of the recent file, as we have the gui now ready for it. */
2781 recent_read_dynamic(&rf_path, &rf_open_errno);
2782 if (rf_path != NULL && rf_open_errno != 0) {
2783 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
2784 "Could not open recent file\n\"%s\": %s.",
2785 rf_path, strerror(rf_open_errno));
2788 color_filters_enable(recent.packet_list_colorize);
2790 /* rearrange all the widgets as we now have all recent settings ready for this */
2791 main_widgets_rearrange();
2793 /* Fill in column titles. This must be done after the top level window
2796 XXX - is that still true, with fixed-width columns? */
2798 menu_recent_read_finished();
2800 menu_auto_scroll_live_changed(auto_scroll_live);
2803 switch (user_font_apply()) {
2806 case FA_FONT_NOT_RESIZEABLE:
2807 /* "user_font_apply()" popped up an alert box. */
2808 /* turn off zooming - font can't be resized */
2809 case FA_FONT_NOT_AVAILABLE:
2810 /* XXX - did we successfully load the un-zoomed version earlier?
2811 If so, this *probably* means the font is available, but not at
2812 this particular zoom level, but perhaps some other failure
2813 occurred; I'm not sure you can determine which is the case,
2815 /* turn off zooming - zoom level is unavailable */
2817 /* in any other case than FA_SUCCESS, turn off zooming */
2818 recent.gui_zoom_level = 0;
2819 /* XXX: would it be a good idea to disable zooming (insensitive GUI)? */
2822 dnd_init(top_level);
2824 color_filters_init();
2827 /* the window can be sized only, if it's not already shown, so do it now! */
2828 main_load_window_geometry(top_level);
2830 g_timeout_add(info_update_freq, resolv_update_cb, NULL);
2833 /* If we were given the name of a capture file, read it in now;
2834 we defer it until now, so that, if we can't open it, and pop
2835 up an alert box, the alert box is more likely to come up on
2836 top of the main window - but before the preference-file-error
2837 alert box, so, if we get one of those, it's more likely to come
2840 show_main_window(TRUE);
2841 check_and_warn_user_startup(cf_name);
2842 if (rfilter != NULL) {
2843 if (!dfilter_compile(rfilter, &rfcode)) {
2844 bad_dfilter_alert_box(rfilter);
2845 rfilter_parse_failed = TRUE;
2848 if (!rfilter_parse_failed) {
2849 if (cf_open(&cfile, cf_name, FALSE, &err) == CF_OK) {
2850 /* "cf_open()" succeeded, so it closed the previous
2851 capture file, and thus destroyed any previous read filter
2852 attached to "cf". */
2854 cfile.rfcode = rfcode;
2855 /* Open stat windows; we do so after creating the main window,
2856 to avoid GTK warnings, and after successfully opening the
2857 capture file, so we know we have something to compute stats
2858 on, and after registering all dissectors, so that MATE will
2859 have registered its field array and we can have a tap filter
2860 with one of MATE's late-registered fields as part of the
2862 start_requested_stats();
2864 /* Read the capture file. */
2865 switch (cf_read(&cfile, FALSE)) {
2869 /* Just because we got an error, that doesn't mean we were unable
2870 to read any of the file; we handle what we could get from the
2872 /* if the user told us to jump to a specific packet, do it now */
2873 if(go_to_packet != 0) {
2874 /* Jump to the specified frame number, kept for backward
2876 cf_goto_frame(&cfile, go_to_packet);
2877 } else if (jfilter != NULL) {
2878 /* try to compile given filter */
2879 if (!dfilter_compile(jfilter, &jump_to_filter)) {
2880 bad_dfilter_alert_box(jfilter);
2882 /* Filter ok, jump to the first packet matching the filter
2883 conditions. Default search direction is forward, but if
2884 option d was given, search backwards */
2885 cf_find_packet_dfilter(&cfile, jump_to_filter, jump_backwards);
2890 case CF_READ_ABORTED:
2896 /* If the filename is not the absolute path, prepend the current dir. This happens
2897 when wireshark is invoked from a cmd shell (e.g.,'wireshark -r file.pcap'). */
2898 if (!g_path_is_absolute(cf_name)) {
2899 char *old_cf_name = cf_name;
2900 char *pwd = g_get_current_dir();
2901 cf_name = g_strdup_printf("%s%s%s", pwd, G_DIR_SEPARATOR_S, cf_name);
2902 g_free(old_cf_name);
2906 /* Save the name of the containing directory specified in the
2907 path name, if any; we can write over cf_name, which is a
2908 good thing, given that "get_dirname()" does write over its
2910 s = get_dirname(cf_name);
2911 set_last_open_dir(s);
2916 dfilter_free(rfcode);
2917 cfile.rfcode = NULL;
2918 show_main_window(FALSE);
2919 /* Don't call check_and_warn_user_startup(): we did it above */
2920 set_menus_for_capture_in_progress(FALSE);
2921 set_capture_if_dialog_for_capture_in_progress(FALSE);
2926 if (start_capture) {
2927 if (global_capture_opts.save_file != NULL) {
2928 /* Save the directory name for future file dialogs. */
2929 /* (get_dirname overwrites filename) */
2930 s = get_dirname(g_strdup(global_capture_opts.save_file));
2931 set_last_open_dir(s);
2934 /* "-k" was specified; start a capture. */
2935 show_main_window(TRUE);
2936 check_and_warn_user_startup(cf_name);
2937 if (capture_start(&global_capture_opts)) {
2938 /* The capture started. Open stat windows; we do so after creating
2939 the main window, to avoid GTK warnings, and after successfully
2940 opening the capture file, so we know we have something to compute
2941 stats on, and after registering all dissectors, so that MATE will
2942 have registered its field array and we can have a tap filter with
2943 one of MATE's late-registered fields as part of the filter. */
2944 start_requested_stats();
2948 show_main_window(FALSE);
2949 check_and_warn_user_startup(cf_name);
2950 set_menus_for_capture_in_progress(FALSE);
2951 set_capture_if_dialog_for_capture_in_progress(FALSE);
2954 /* if the user didn't supplied a capture filter, use the one to filter out remote connections like SSH */
2955 if (!start_capture && !global_capture_opts.cfilter) {
2956 global_capture_opts.cfilter = g_strdup(get_conn_cfilter());
2958 #else /* HAVE_LIBPCAP */
2959 show_main_window(FALSE);
2960 check_and_warn_user_startup(cf_name);
2961 set_menus_for_capture_in_progress(FALSE);
2962 set_capture_if_dialog_for_capture_in_progress(FALSE);
2963 #endif /* HAVE_LIBPCAP */
2966 /* register our pid if we are being run from a U3 device */
2969 profile_store_persconffiles (FALSE);
2971 #ifdef HAVE_GTKOSXAPPLICATION
2972 theApp = g_object_new(GTK_TYPE_OSX_APPLICATION, NULL);
2973 gtk_osxapplication_set_dock_icon_pixbuf(theApp,gdk_pixbuf_new_from_xpm_data(wsicon64_xpm));
2974 gtk_osxapplication_ready(theApp);
2977 g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_INFO, "Wireshark is up and ready to go");
2979 /* we'll enter the GTK loop now and hand the control over to GTK ... */
2981 /* ... back from GTK, we're going down now! */
2983 /* deregister our pid */
2984 u3_deregister_pid();
2988 AirPDcapDestroyContext(&airpdcap_ctx);
2991 /* hide the (unresponsive) main window, while asking the user to close the console window */
2992 gtk_widget_hide(top_level);
2994 #ifdef HAVE_GTKOSXAPPLICATION
2995 g_object_unref(theApp);
2998 /* Shutdown windows sockets */
3001 /* For some unknown reason, the "atexit()" call in "create_console()"
3002 doesn't arrange that "destroy_console()" be called when we exit,
3003 so we call it here if a console was created. */
3012 /* We build this as a GUI subsystem application on Win32, so
3013 "WinMain()", not "main()", gets called.
3015 Hack shamelessly stolen from the Win32 port of the GIMP. */
3017 #define _stdcall __attribute__((stdcall))
3021 WinMain (struct HINSTANCE__ *hInstance,
3022 struct HINSTANCE__ *hPrevInstance,
3026 INITCOMMONCONTROLSEX comm_ctrl;
3029 * Initialize our DLL search path. MUST be called before LoadLibrary
3032 ws_init_dll_search_path();
3034 /* Initialize our controls. Required for native Windows file dialogs. */
3035 memset (&comm_ctrl, 0, sizeof(comm_ctrl));
3036 comm_ctrl.dwSize = sizeof(comm_ctrl);
3037 /* Includes the animate, header, hot key, list view, progress bar,
3038 * status bar, tab, tooltip, toolbar, trackbar, tree view, and
3041 comm_ctrl.dwICC = ICC_WIN95_CLASSES;
3042 InitCommonControlsEx(&comm_ctrl);
3044 /* RichEd20.DLL is needed for filter entries. */
3045 ws_load_library("riched20.dll");
3047 has_console = FALSE;
3048 console_wait = FALSE;
3049 return main (__argc, __argv);
3052 /* The code to create and desstroy console windows should not be necessary,
3053 at least as I read the GLib source code, as it looks as if GLib is, on
3054 Win32, *supposed* to create a console window into which to display its
3057 That doesn't happen, however. I suspect there's something completely
3058 broken about that code in GLib-for-Win32, and that it may be related
3059 to the breakage that forces us to just call "printf()" on the message
3060 rather than passing the message on to "g_log_default_handler()"
3061 (which is the routine that does the aforementioned non-functional
3062 console window creation). */
3065 * If this application has no console window to which its standard output
3066 * would go, create one.
3069 create_console(void)
3071 if (stdin_capture) {
3072 /* We've been handed "-i -". Don't mess with stdio. */
3077 /* We have no console to which to print the version string, so
3078 create one and make it the standard input, output, and error. */
3081 * See if we have an existing console (i.e. we were run from a
3084 if (!AttachConsole(ATTACH_PARENT_PROCESS)) {
3085 if (AllocConsole()) {
3086 console_wait = TRUE;
3087 SetConsoleTitle(_T("Wireshark Debug Console"));
3089 return; /* couldn't create console */
3093 ws_freopen("CONIN$", "r", stdin);
3094 ws_freopen("CONOUT$", "w", stdout);
3095 ws_freopen("CONOUT$", "w", stderr);
3096 fprintf(stdout, "\n");
3097 fprintf(stderr, "\n");
3099 /* Now register "destroy_console()" as a routine to be called just
3100 before the application exits, so that we can destroy the console
3101 after the user has typed a key (so that the console doesn't just
3102 disappear out from under them, giving the user no chance to see
3103 the message(s) we put in there). */
3104 atexit(destroy_console);
3106 /* Well, we have a console now. */
3112 destroy_console(void)
3115 printf("\n\nPress any key to exit\n");
3124 console_log_handler(const char *log_domain, GLogLevelFlags log_level,
3125 const char *message, gpointer user_data _U_)
3132 /* ignore log message, if log_level isn't interesting based
3133 upon the console log preferences.
3134 If the preferences haven't been loaded loaded yet, display the
3137 The default console_log_level preference value is such that only
3138 ERROR, CRITICAL and WARNING level messages are processed;
3139 MESSAGE, INFO and DEBUG level messages are ignored. */
3140 if((log_level & G_LOG_LEVEL_MASK & prefs.console_log_level) == 0 &&
3141 prefs.console_log_level != 0) {
3146 if (prefs.gui_console_open != console_open_never || log_level & G_LOG_LEVEL_ERROR) {
3147 /* the user wants a console or the application will terminate immediately */
3151 /* For some unknown reason, the above doesn't appear to actually cause
3152 anything to be sent to the standard output, so we'll just splat the
3153 message out directly, just to make sure it gets out. */
3155 switch(log_level & G_LOG_LEVEL_MASK) {
3156 case G_LOG_LEVEL_ERROR:
3159 case G_LOG_LEVEL_CRITICAL:
3162 case G_LOG_LEVEL_WARNING:
3165 case G_LOG_LEVEL_MESSAGE:
3168 case G_LOG_LEVEL_INFO:
3171 case G_LOG_LEVEL_DEBUG:
3175 fprintf(stderr, "unknown log_level %u\n", log_level);
3177 g_assert_not_reached();
3180 /* create a "timestamp" */
3182 today = localtime(&curr);
3184 fprintf(stderr, "%02u:%02u:%02u %8s %s %s\n",
3185 today->tm_hour, today->tm_min, today->tm_sec,
3186 log_domain != NULL ? log_domain : "",
3189 if(log_level & G_LOG_LEVEL_ERROR) {
3190 /* wait for a key press before the following error handler will terminate the program
3191 this way the user at least can read the error message */
3192 printf("\n\nPress any key to exit\n");
3196 /* XXX - on UN*X, should we just use g_log_default_handler()?
3197 We want the error messages to go to the standard output;
3198 on Mac OS X, that will cause them to show up in various
3199 per-user logs accessible through Console (details depend
3200 on whether you're running 10.0 through 10.4 or running
3201 10.5 and later), and, on other UN*X desktop environments,
3202 if they don't show up in some form of console log, that's
3203 a deficiency in that desktop environment. (Too bad
3204 Windows doesn't set the standard output and error for
3205 GUI apps to something that shows up in such a log.) */
3206 g_log_default_handler(log_domain, log_level, message, user_data);
3213 * Helper for main_widgets_rearrange()
3215 static void foreach_remove_a_child(GtkWidget *widget, gpointer data) {
3216 gtk_container_remove(GTK_CONTAINER(data), widget);
3219 static GtkWidget *main_widget_layout(gint layout_content)
3221 switch(layout_content) {
3222 case(layout_pane_content_none):
3224 case(layout_pane_content_plist):
3226 case(layout_pane_content_pdetails):
3228 case(layout_pane_content_pbytes):
3229 return byte_nb_ptr_gbl;
3231 g_assert_not_reached();
3238 * Rearrange the main window widgets
3240 void main_widgets_rearrange(void) {
3241 GtkWidget *first_pane_widget1, *first_pane_widget2;
3242 GtkWidget *second_pane_widget1, *second_pane_widget2;
3243 gboolean split_top_left;
3245 /* be a bit faster */
3246 gtk_widget_hide(main_vbox);
3248 /* be sure we don't lose a widget while rearranging */
3249 g_object_ref(G_OBJECT(menubar));
3250 g_object_ref(G_OBJECT(main_tb));
3251 g_object_ref(G_OBJECT(filter_tb));
3253 g_object_ref(G_OBJECT(airpcap_tb));
3255 g_object_ref(G_OBJECT(pkt_scrollw));
3256 g_object_ref(G_OBJECT(tv_scrollw));
3257 g_object_ref(G_OBJECT(byte_nb_ptr_gbl));
3258 g_object_ref(G_OBJECT(statusbar));
3259 g_object_ref(G_OBJECT(main_pane_v1));
3260 g_object_ref(G_OBJECT(main_pane_v2));
3261 g_object_ref(G_OBJECT(main_pane_h1));
3262 g_object_ref(G_OBJECT(main_pane_h2));
3263 g_object_ref(G_OBJECT(welcome_pane));
3265 /* empty all containers participating */
3266 gtk_container_foreach(GTK_CONTAINER(main_vbox), foreach_remove_a_child, main_vbox);
3267 gtk_container_foreach(GTK_CONTAINER(main_pane_v1), foreach_remove_a_child, main_pane_v1);
3268 gtk_container_foreach(GTK_CONTAINER(main_pane_v2), foreach_remove_a_child, main_pane_v2);
3269 gtk_container_foreach(GTK_CONTAINER(main_pane_h1), foreach_remove_a_child, main_pane_h1);
3270 gtk_container_foreach(GTK_CONTAINER(main_pane_h2), foreach_remove_a_child, main_pane_h2);
3272 statusbar_widgets_emptying(statusbar);
3274 /* add the menubar always at the top */
3275 gtk_box_pack_start(GTK_BOX(main_vbox), menubar, FALSE, TRUE, 0);
3278 gtk_box_pack_start(GTK_BOX(main_vbox), main_tb, FALSE, TRUE, 0);
3280 /* filter toolbar in toolbar area */
3281 if (!prefs.filter_toolbar_show_in_statusbar) {
3282 gtk_box_pack_start(GTK_BOX(main_vbox), filter_tb, FALSE, TRUE, 1);
3286 /* airpcap toolbar */
3287 gtk_box_pack_start(GTK_BOX(main_vbox), airpcap_tb, FALSE, TRUE, 1);
3290 /* fill the main layout panes */
3291 switch(prefs.gui_layout_type) {
3292 case(layout_type_5):
3293 main_first_pane = main_pane_v1;
3294 main_second_pane = main_pane_v2;
3295 split_top_left = FALSE;
3297 case(layout_type_2):
3298 main_first_pane = main_pane_v1;
3299 main_second_pane = main_pane_h1;
3300 split_top_left = FALSE;
3302 case(layout_type_1):
3303 main_first_pane = main_pane_v1;
3304 main_second_pane = main_pane_h1;
3305 split_top_left = TRUE;
3307 case(layout_type_4):
3308 main_first_pane = main_pane_h1;
3309 main_second_pane = main_pane_v1;
3310 split_top_left = FALSE;
3312 case(layout_type_3):
3313 main_first_pane = main_pane_h1;
3314 main_second_pane = main_pane_v1;
3315 split_top_left = TRUE;
3317 case(layout_type_6):
3318 main_first_pane = main_pane_h1;
3319 main_second_pane = main_pane_h2;
3320 split_top_left = FALSE;
3323 main_first_pane = NULL;
3324 main_second_pane = NULL;
3325 split_top_left = FALSE;
3326 g_assert_not_reached();
3328 if (split_top_left) {
3329 first_pane_widget1 = main_second_pane;
3330 second_pane_widget1 = main_widget_layout(prefs.gui_layout_content_1);
3331 second_pane_widget2 = main_widget_layout(prefs.gui_layout_content_2);
3332 first_pane_widget2 = main_widget_layout(prefs.gui_layout_content_3);
3334 first_pane_widget1 = main_widget_layout(prefs.gui_layout_content_1);
3335 first_pane_widget2 = main_second_pane;
3336 second_pane_widget1 = main_widget_layout(prefs.gui_layout_content_2);
3337 second_pane_widget2 = main_widget_layout(prefs.gui_layout_content_3);
3339 if (first_pane_widget1 != NULL)
3340 gtk_paned_add1(GTK_PANED(main_first_pane), first_pane_widget1);
3341 if (first_pane_widget2 != NULL)
3342 gtk_paned_add2(GTK_PANED(main_first_pane), first_pane_widget2);
3343 if (second_pane_widget1 != NULL)
3344 gtk_paned_pack1(GTK_PANED(main_second_pane), second_pane_widget1, TRUE, TRUE);
3345 if (second_pane_widget2 != NULL)
3346 gtk_paned_pack2(GTK_PANED(main_second_pane), second_pane_widget2, FALSE, FALSE);
3348 gtk_container_add(GTK_CONTAINER(main_vbox), main_first_pane);
3351 gtk_box_pack_start(GTK_BOX(main_vbox), welcome_pane, TRUE, TRUE, 0);
3354 gtk_box_pack_start(GTK_BOX(main_vbox), statusbar, FALSE, TRUE, 0);
3356 /* filter toolbar in statusbar hbox */
3357 if (prefs.filter_toolbar_show_in_statusbar) {
3358 gtk_box_pack_start(GTK_BOX(statusbar), filter_tb, FALSE, TRUE, 1);
3361 /* statusbar widgets */
3362 statusbar_widgets_pack(statusbar);
3364 /* hide widgets on users recent settings */
3365 main_widgets_show_or_hide();
3367 gtk_widget_show(main_vbox);
3371 is_widget_visible(GtkWidget *widget, gpointer data)
3373 gboolean *is_visible = data;
3376 #if GTK_CHECK_VERSION(2,18,0)
3377 if (gtk_widget_get_visible(widget))
3379 if (GTK_WIDGET_VISIBLE(widget))
3387 main_widgets_show_or_hide(void)
3389 gboolean main_second_pane_show;
3391 if (recent.main_toolbar_show) {
3392 gtk_widget_show(main_tb);
3394 gtk_widget_hide(main_tb);
3397 statusbar_widgets_show_or_hide(statusbar);
3399 if (recent.filter_toolbar_show) {
3400 gtk_widget_show(filter_tb);
3402 gtk_widget_hide(filter_tb);
3406 if (recent.airpcap_toolbar_show) {
3407 gtk_widget_show(airpcap_tb);
3409 gtk_widget_hide(airpcap_tb);
3413 if (recent.packet_list_show && have_capture_file) {
3414 gtk_widget_show(pkt_scrollw);
3416 gtk_widget_hide(pkt_scrollw);
3419 if (recent.tree_view_show && have_capture_file) {
3420 gtk_widget_show(tv_scrollw);
3422 gtk_widget_hide(tv_scrollw);
3425 if (recent.byte_view_show && have_capture_file) {
3426 gtk_widget_show(byte_nb_ptr_gbl);
3428 gtk_widget_hide(byte_nb_ptr_gbl);
3431 if (have_capture_file) {
3432 gtk_widget_show(main_first_pane);
3434 gtk_widget_hide(main_first_pane);
3438 * Is anything in "main_second_pane" visible?
3439 * If so, show it, otherwise hide it.
3441 main_second_pane_show = FALSE;
3442 gtk_container_foreach(GTK_CONTAINER(main_second_pane), is_widget_visible,
3443 &main_second_pane_show);
3444 if (main_second_pane_show) {
3445 gtk_widget_show(main_second_pane);
3447 gtk_widget_hide(main_second_pane);
3450 if (!have_capture_file) {
3452 gtk_widget_show(welcome_pane);
3455 gtk_widget_hide(welcome_pane);
3460 /* called, when the window state changes (minimized, maximized, ...) */
3462 window_state_event_cb (GtkWidget *widget _U_,
3466 GdkWindowState new_window_state = ((GdkEventWindowState*)event)->new_window_state;
3468 if( (event->type) == (GDK_WINDOW_STATE)) {
3469 if(!(new_window_state & GDK_WINDOW_STATE_ICONIFIED)) {
3470 /* we might have dialogs popped up while we where iconified,
3472 display_queued_messages();
3480 #define NO_SHIFT_MOD_MASK (GDK_MODIFIER_MASK & ~(GDK_SHIFT_MASK|GDK_MOD2_MASK|GDK_LOCK_MASK))
3482 top_level_key_pressed_cb(GtkWidget *w _U_, GdkEventKey *event, gpointer user_data _U_)
3484 if (event->keyval == GDK_F8) {
3485 new_packet_list_next();
3487 } else if (event->keyval == GDK_F7) {
3488 new_packet_list_prev();
3490 } else if (event->state & NO_SHIFT_MOD_MASK) {
3491 return FALSE; /* Skip control, alt, and other modifiers */
3493 * A comment in gdkkeysyms.h says that it's autogenerated from
3494 * freedesktop.org/x.org's keysymdef.h. Although the GDK docs
3495 * don't explicitly say so, isprint() should work as expected
3498 } else if (isascii(event->keyval) && isprint(event->keyval)) {
3499 /* Forward the keypress on to the display filter entry */
3500 if (main_display_filter_widget && !gtk_widget_is_focus(main_display_filter_widget)) {
3501 gtk_window_set_focus(GTK_WINDOW(top_level), main_display_filter_widget);
3502 gtk_editable_set_position(GTK_EDITABLE(main_display_filter_widget), -1);
3510 create_main_window (gint pl_size, gint tv_size, gint bv_size, e_prefs *prefs_p)
3512 GtkAccelGroup *accel;
3515 top_level = window_new(GTK_WINDOW_TOPLEVEL, "");
3516 set_main_window_name("The Wireshark Network Analyzer");
3518 gtk_widget_set_name(top_level, "main window");
3519 g_signal_connect(top_level, "delete_event", G_CALLBACK(main_window_delete_event_cb),
3521 g_signal_connect(GTK_OBJECT(top_level), "window_state_event",
3522 G_CALLBACK(window_state_event_cb), NULL);
3523 g_signal_connect(GTK_OBJECT(top_level), "key-press-event",
3524 G_CALLBACK(top_level_key_pressed_cb), NULL );
3526 /* Vertical container for menu bar, toolbar(s), paned windows and progress/info box */
3527 main_vbox = gtk_vbox_new(FALSE, 1);
3528 gtk_container_set_border_width(GTK_CONTAINER(main_vbox), 0);
3529 gtk_container_add(GTK_CONTAINER(top_level), main_vbox);
3530 gtk_widget_show(main_vbox);
3533 menubar = main_menu_new(&accel);
3535 #if defined(HAVE_IGE_MAC_INTEGRATION) || defined (HAVE_GTKOSXAPPLICATION)
3536 /* Mac OS X native menus are created and displayed by main_menu_new() */
3537 if(!prefs_p->gui_macosx_style) {
3539 gtk_window_add_accel_group(GTK_WINDOW(top_level), accel);
3540 gtk_widget_show(menubar);
3541 #if defined(HAVE_IGE_MAC_INTEGRATION) || defined(HAVE_GTKOSXAPPLICATION)
3546 main_tb = toolbar_new();
3547 gtk_widget_show (main_tb);
3549 /* Filter toolbar */
3550 filter_tb = filter_toolbar_new();
3553 pkt_scrollw = new_packet_list_create();
3554 gtk_widget_set_size_request(pkt_scrollw, -1, pl_size);
3555 gtk_widget_show_all(pkt_scrollw);
3558 tv_scrollw = main_tree_view_new(prefs_p, &tree_view_gbl);
3559 gtk_widget_set_size_request(tv_scrollw, -1, tv_size);
3560 gtk_widget_show(tv_scrollw);
3562 g_signal_connect(gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view_gbl)),
3563 "changed", G_CALLBACK(tree_view_selection_changed_cb), NULL);
3564 g_signal_connect(tree_view_gbl, "button_press_event", G_CALLBACK(popup_menu_handler),
3565 g_object_get_data(G_OBJECT(popup_menu_object), PM_TREE_VIEW_KEY));
3566 gtk_widget_show(tree_view_gbl);
3569 byte_nb_ptr_gbl = byte_view_new();
3570 gtk_widget_set_size_request(byte_nb_ptr_gbl, -1, bv_size);
3571 gtk_widget_show(byte_nb_ptr_gbl);
3573 g_signal_connect(byte_nb_ptr_gbl, "button_press_event", G_CALLBACK(popup_menu_handler),
3574 g_object_get_data(G_OBJECT(popup_menu_object), PM_BYTES_VIEW_KEY));
3576 /* Panes for the packet list, tree, and byte view */
3577 main_pane_v1 = gtk_vpaned_new();
3578 gtk_widget_show(main_pane_v1);
3579 main_pane_v2 = gtk_vpaned_new();
3580 gtk_widget_show(main_pane_v2);
3581 main_pane_h1 = gtk_hpaned_new();
3582 gtk_widget_show(main_pane_h1);
3583 main_pane_h2 = gtk_hpaned_new();
3584 gtk_widget_show(main_pane_h2);
3586 airpcap_tb = airpcap_toolbar_new();
3587 gtk_widget_show(airpcap_tb);
3590 statusbar = statusbar_new();
3591 gtk_widget_show(statusbar);
3593 /* Pane for the welcome screen */
3594 welcome_pane = welcome_new();
3595 gtk_widget_show(welcome_pane);
3599 show_main_window(gboolean doing_work)
3601 main_set_for_capture_file(doing_work);
3603 /*** we have finished all init things, show the main window ***/
3604 gtk_widget_show(top_level);
3606 /* the window can be maximized only, if it's visible, so do it after show! */
3607 main_load_window_geometry(top_level);
3609 /* process all pending GUI events before continue */
3610 while (gtk_events_pending()) gtk_main_iteration();
3612 /* Pop up any queued-up alert boxes. */
3613 display_queued_messages();
3615 /* Move the main window to the front, in case it isn't already there */
3616 #if GTK_CHECK_VERSION(2,14,0)
3617 gdk_window_raise(gtk_widget_get_window(top_level));
3619 gdk_window_raise(top_level->window);
3623 airpcap_toolbar_show(airpcap_tb);
3624 #endif /* HAVE_AIRPCAP */
3627 /* Fill in capture options with values from the preferences */
3629 prefs_to_capture_opts(void)
3632 /* Set promiscuous mode from the preferences setting. */
3633 /* the same applies to other preferences settings as well. */
3634 global_capture_opts.promisc_mode = prefs.capture_prom_mode;
3635 global_capture_opts.use_pcapng = prefs.capture_pcap_ng;
3636 global_capture_opts.show_info = prefs.capture_show_info;
3637 global_capture_opts.real_time_mode = prefs.capture_real_time;
3638 auto_scroll_live = prefs.capture_auto_scroll;
3639 #endif /* HAVE_LIBPCAP */
3641 /* Set the name resolution code's flags from the preferences. */
3642 gbl_resolv_flags = prefs.name_resolve;
3645 static void copy_global_profile (const gchar *profile_name)
3647 char *pf_dir_path, *pf_dir_path2, *pf_filename;
3649 if (create_persconffile_profile(profile_name, &pf_dir_path) == -1) {
3650 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3651 "Can't create directory\n\"%s\":\n%s.",
3652 pf_dir_path, strerror(errno));
3654 g_free(pf_dir_path);
3657 if (copy_persconffile_profile(profile_name, profile_name, TRUE, &pf_filename,
3658 &pf_dir_path, &pf_dir_path2) == -1) {
3659 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3660 "Can't copy file \"%s\" in directory\n\"%s\" to\n\"%s\":\n%s.",
3661 pf_filename, pf_dir_path2, pf_dir_path, strerror(errno));
3663 g_free(pf_filename);
3664 g_free(pf_dir_path);
3665 g_free(pf_dir_path2);
3669 /* Change configuration profile */
3670 void change_configuration_profile (const gchar *profile_name)
3672 char *gdp_path, *dp_path;
3676 /* First check if profile exists */
3677 if (!profile_exists(profile_name, FALSE)) {
3678 if (profile_exists(profile_name, TRUE)) {
3679 /* Copy from global profile */
3680 copy_global_profile (profile_name);
3682 /* No personal and no global profile exists */
3687 /* Then check if changing to another profile */
3688 if (profile_name && strcmp (profile_name, get_profile_name()) == 0) {
3692 /* Get the current geometry, before writing it to disk */
3693 main_save_window_geometry(top_level);
3695 if (profile_exists(get_profile_name(), FALSE)) {
3696 /* Write recent file for profile we are leaving, if it still exists */
3697 write_profile_recent();
3700 /* Set profile name and update the status bar */
3701 set_profile_name (profile_name);
3702 profile_bar_update ();
3704 /* Reset current preferences and apply the new */
3708 (void) read_configuration_files (&gdp_path, &dp_path);
3710 recent_read_profile_static(&rf_path, &rf_open_errno);
3711 if (rf_path != NULL && rf_open_errno != 0) {
3712 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
3713 "Could not open common recent file\n\"%s\": %s.",
3714 rf_path, strerror(rf_open_errno));
3716 if (recent.gui_fileopen_remembered_dir &&
3717 test_for_directory(recent.gui_fileopen_remembered_dir) == EISDIR) {
3718 set_last_open_dir(recent.gui_fileopen_remembered_dir);
3720 timestamp_set_type (recent.gui_time_format);
3721 timestamp_set_seconds_type (recent.gui_seconds_format);
3722 color_filters_enable(recent.packet_list_colorize);
3724 prefs_to_capture_opts();
3726 macros_post_update();
3728 /* Update window view and redraw the toolbar */
3729 update_main_window_title();
3730 toolbar_redraw_all();
3732 /* Enable all protocols and disable from the disabled list */
3734 if (gdp_path == NULL && dp_path == NULL) {
3735 set_disabled_protos_list();
3738 /* Reload color filters */
3739 color_filters_reload();
3741 /* Reload list of interfaces on welcome page */
3742 welcome_if_panel_reload();
3744 /* Recreate the packet list according to new preferences */
3745 new_packet_list_recreate ();
3746 cfile.cinfo.columns_changed = FALSE; /* Reset value */
3749 /* Update menus with new recent values */
3750 menu_recent_read_finished();
3752 /* Reload pane geometry, must be done after recreating the list */
3753 main_pane_load_window_geometry();
3756 /** redissect packets and update UI */
3757 void redissect_packets(void)
3759 cf_redissect_packets(&cfile);
3760 status_expert_update();