1 /* wireshark_application.cpp
3 * Wireshark - Network traffic analyzer
4 * By Gerald Combs <gerald@wireshark.org>
5 * Copyright 1998 Gerald Combs
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 // warning C4267: 'argument' : conversion from 'size_t' to 'int', possible loss of data
25 #pragma warning(disable : 4267)
28 #include "wireshark_application.h"
33 #include "wsutil/filesystem.h"
35 #include "epan/addr_resolv.h"
36 #include "epan/disabled_protos.h"
37 #include "epan/ftypes/ftypes.h"
38 #include "epan/prefs.h"
39 #include "epan/proto.h"
41 #include "epan/timestamp.h"
43 #include "ui/decode_as_utils.h"
44 #include "ui/preference_utils.h"
45 #include "ui/iface_lists.h"
46 #include "ui/recent.h"
47 #include "ui/simple_dialog.h"
50 #include "qt_ui_utils.h"
52 #include "color_filters.h"
54 #include "recent_file_status.h"
57 #include <caputils/iface_monitor.h>
60 #include "ui/capture.h"
61 #include "ui/filters.h"
62 #include "ui/capture_globals.h"
63 #include "ui/software_update.h"
64 #include "ui/last_open_dir.h"
65 #include "ui/recent_utils.h"
66 #include <wsutil/utf8_entities.h>
69 # include "ui/win32/console_win32.h"
73 #include <QDesktopServices>
76 #include <QFileOpenEvent>
77 #include <QFontMetrics>
78 #include <QLibraryInfo>
80 #include <QMutableListIterator>
81 #include <QSocketNotifier>
94 WiresharkApplication *wsApp = NULL;
96 // XXX - Copied from ui/gtk/file_dlg.c
99 static char *last_open_dir = NULL;
100 static bool updated_last_open_dir = FALSE;
101 static QList<recent_item_status *> recent_items_;
102 static QHash<int, QList<QAction *> > dynamic_menu_groups_;
103 static QHash<int, QList<QAction *> > added_menu_groups_;
104 static QHash<int, QList<QAction *> > removed_menu_groups_;
106 QString WiresharkApplication::window_title_separator_ = QString::fromUtf8(" " UTF8_MIDDLE_DOT " ");
109 topic_action(topic_action_e action)
111 if (wsApp) wsApp->helpTopicAction(action);
115 get_last_open_dir(void)
117 return last_open_dir;
121 set_last_open_dir(const char *dirname)
123 if (wsApp) wsApp->setLastOpenDir(dirname);
127 * Add the capture filename to the application-wide "Recent Files" list.
128 * Contrary to the name this isn't limited to the "recent" menu.
131 * XXX - We might want to call SHAddToRecentDocs under Windows 7:
132 * http://stackoverflow.com/questions/437212/how-do-you-register-a-most-recently-used-list-with-windows-in-preparation-for-win
135 add_menu_recent_capture_file(const gchar *cf_name) {
136 QString normalized_cf_name = QString::fromUtf8(cf_name);
139 // cf_path.setPath(normalized_cf_name);
140 // normalized_cf_name = cf_path.absolutePath();
141 normalized_cf_name = QDir::cleanPath(normalized_cf_name);
142 normalized_cf_name = QDir::toNativeSeparators(normalized_cf_name);
144 /* Iterate through the recent items list, removing duplicate entries and every
145 * item above count_max
147 unsigned int cnt = 1;
148 QMutableListIterator<recent_item_status *> rii(recent_items_);
149 while (rii.hasNext()) {
150 recent_item_status *ri = rii.next();
151 /* if this element string is one of our special items (separator, ...) or
152 * already in the list or
153 * this element is above maximum count (too old), remove it
155 if (ri->filename.length() < 1 ||
157 /* do a case insensitive compare on win32 */
158 ri->filename.compare(normalized_cf_name, Qt::CaseInsensitive) == 0 ||
160 /* do a case sensitive compare on unix */
161 ri->filename.compare(normalized_cf_name) == 0 ||
163 cnt >= prefs.gui_recent_files_count_max) {
170 wsApp->addRecentItem(normalized_cf_name, 0, false);
173 /* write all capture filenames of the menu to the user's recent file */
174 extern "C" void menu_recent_file_write_all(FILE *rf) {
176 /* we have to iterate backwards through the children's list,
177 * so we get the latest item last in the file.
179 QListIterator<recent_item_status *> rii(recent_items_);
181 while (rii.hasPrevious()) {
183 /* get capture filename from the menu item label */
184 cf_name = rii.previous()->filename;
185 if (cf_name != NULL) {
187 // fprintf (rf, RECENT_KEY_CAPTURE_FILE ": %s\n", u3_contract_device_path(cf_name));
189 fprintf (rf, RECENT_KEY_CAPTURE_FILE ": %s\n", cf_name.toUtf8().constData());
194 // Check each recent item in a separate thread so that we don't hang while
195 // calling stat(). This is called periodically because files and entire
196 // volumes can disappear and reappear at any time.
197 void WiresharkApplication::refreshRecentFiles(void) {
198 recent_item_status *ri;
199 RecentFileStatus *rf_status;
201 // We're in the middle of a capture. Don't create traffic.
202 if (active_captures_ > 0) return;
204 foreach (ri, recent_items_) {
209 rf_status = new RecentFileStatus(ri->filename, this);
211 connect(rf_status, SIGNAL(statusFound(QString, qint64, bool)),
212 this, SLOT(itemStatusFinished(QString, qint64, bool)), Qt::QueuedConnection);
213 connect(rf_status, SIGNAL(finished()), rf_status, SLOT(deleteLater()));
218 void WiresharkApplication::refreshAddressResolution()
220 // Anything new show up?
221 if (host_name_lookup_process()) {
222 emit addressResolutionChanged();
226 void WiresharkApplication::updateTaps()
228 draw_tap_listeners(FALSE);
231 QDir WiresharkApplication::lastOpenDir() {
232 return QDir(last_open_dir);
235 void WiresharkApplication::setLastOpenDir(QString *dir_str) {
236 setLastOpenDir(dir_str->toUtf8().constData());
239 void WiresharkApplication::helpTopicAction(topic_action_e action)
241 QString url = gchar_free_to_qstring(topic_action_url(action));
244 QDesktopServices::openUrl(QUrl(url));
248 void WiresharkApplication::setMonospaceFont(const char *font_string) {
250 if (font_string && strlen(font_string) > 0) {
251 mono_font_.fromString(font_string);
252 // mono_bold_font_ = QFont(mono_regular_font_);
253 // mono_bold_font_.setBold(true);
257 // http://en.wikipedia.org/wiki/Category:Monospaced_typefaces
258 const char *win_default_font = "Consolas";
259 const char *win_alt_font = "Lucida Console";
260 const char *osx_default_font = "Menlo";
261 const char *osx_alt_font = "Monaco";
262 const char *x11_default_font = "Liberation Mono";
263 const QStringList x11_alt_fonts = QStringList() << "DejaVu Sans Mono" << "Bitstream Vera Sans Mono";
264 const QStringList fallback_fonts = QStringList() << "Lucida Sans Typewriter" << "Inconsolata" << "Droid Sans Mono" << "Andale Mono" << "Courier New" << "monospace";
265 QStringList substitutes;
266 int font_size_adjust = 0;
268 // Try to pick the latest, shiniest fixed-width font for our OS.
269 #if defined(Q_OS_WIN)
270 const char *default_font = win_default_font;
271 substitutes << win_alt_font << osx_default_font << osx_alt_font << x11_default_font << x11_alt_fonts << fallback_fonts;
272 font_size_adjust = 2;
273 #elif defined(Q_OS_MAC)
274 const char *default_font = osx_default_font;
275 substitutes << osx_alt_font << win_default_font << win_alt_font << x11_default_font << x11_alt_fonts << fallback_fonts;
277 const char *default_font = x11_default_font;
278 substitutes << x11_alt_fonts << win_default_font << win_alt_font << osx_default_font << osx_alt_font << fallback_fonts;
281 mono_font_.setFamily(default_font);
282 mono_font_.insertSubstitutions(default_font, substitutes);
283 mono_font_.setPointSize(wsApp->font().pointSize() + font_size_adjust);
284 mono_font_.setBold(false);
286 // mono_bold_font_ = QFont(mono_font_);
287 // mono_bold_font_.setBold(true);
289 g_free(prefs.gui_qt_font_name);
290 prefs.gui_qt_font_name = qstring_strdup(mono_font_.toString());
293 int WiresharkApplication::monospaceTextSize(const char *str)
295 QFontMetrics fm(mono_font_);
297 return fm.width(str);
300 void WiresharkApplication::setConfigurationProfile(const gchar *profile_name)
302 char *gdp_path, *dp_path;
306 /* First check if profile exists */
307 if (!profile_exists(profile_name, FALSE)) {
308 if (profile_exists(profile_name, TRUE)) {
309 char *pf_dir_path, *pf_dir_path2, *pf_filename;
310 /* Copy from global profile */
311 if (create_persconffile_profile(profile_name, &pf_dir_path) == -1) {
312 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
313 "Can't create directory\n\"%s\":\n%s.",
314 pf_dir_path, g_strerror(errno));
319 if (copy_persconffile_profile(profile_name, profile_name, TRUE, &pf_filename,
320 &pf_dir_path, &pf_dir_path2) == -1) {
321 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
322 "Can't copy file \"%s\" in directory\n\"%s\" to\n\"%s\":\n%s.",
323 pf_filename, pf_dir_path2, pf_dir_path, g_strerror(errno));
327 g_free(pf_dir_path2);
330 /* No personal and no global profile exists */
335 /* Then check if changing to another profile */
336 if (profile_name && strcmp (profile_name, get_profile_name()) == 0) {
340 /* Get the current geometry, before writing it to disk */
341 emit profileChanging();
343 if (profile_exists(get_profile_name(), FALSE)) {
344 /* Write recent file for profile we are leaving, if it still exists */
345 write_profile_recent();
348 /* Set profile name and update the status bar */
349 set_profile_name (profile_name);
350 emit profileNameChanged(profile_name);
352 /* Reset current preferences and apply the new */
354 // menu_prefs_reset();
356 (void) readConfigurationFiles (&gdp_path, &dp_path);
358 if (!recent_read_profile_static(&rf_path, &rf_open_errno)) {
359 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
360 "Could not open common recent file\n\"%s\": %s.",
361 rf_path, g_strerror(rf_open_errno));
364 if (recent.gui_fileopen_remembered_dir &&
365 test_for_directory(recent.gui_fileopen_remembered_dir) == EISDIR) {
366 set_last_open_dir(recent.gui_fileopen_remembered_dir);
368 timestamp_set_type (recent.gui_time_format);
369 timestamp_set_seconds_type (recent.gui_seconds_format);
370 color_filters_enable(recent.packet_list_colorize);
371 tap_update_timer_.setInterval(prefs.tap_update_interval);
373 prefs_to_capture_opts();
376 emit preferencesChanged();
377 emit columnsChanged();
378 emit recentFilesRead();
379 emit filterExpressionsChanged();
380 // macros_post_update();
382 /* Enable all protocols and disable from the disabled list */
384 if (gdp_path == NULL && dp_path == NULL) {
385 set_disabled_protos_list();
386 set_disabled_heur_dissector_list();
389 /* Reload color filters */
390 color_filters_reload();
392 // user_font_apply();
394 /* Update menus with new recent values */
395 // menu_recent_read_finished();
398 const QString WiresharkApplication::windowTitleString(QStringList title_parts)
400 QMutableStringListIterator tii(title_parts);
401 while (tii.hasNext()) {
402 QString ti = tii.next();
403 if (ti.isEmpty()) tii.remove();
405 title_parts.prepend(applicationName());
406 return title_parts.join(window_title_separator_);
409 void WiresharkApplication::setLastOpenDir(const char *dir_name)
412 gchar *new_last_open_dir;
414 if (dir_name && dir_name[0]) {
415 len = strlen(dir_name);
416 if (dir_name[len-1] == G_DIR_SEPARATOR) {
417 new_last_open_dir = g_strconcat(dir_name, (char *)NULL);
420 new_last_open_dir = g_strconcat(dir_name,
421 G_DIR_SEPARATOR_S, (char *)NULL);
424 if (last_open_dir == NULL ||
425 strcmp(last_open_dir, new_last_open_dir) != 0)
426 updated_last_open_dir = TRUE;
429 new_last_open_dir = NULL;
430 if (last_open_dir != NULL)
431 updated_last_open_dir = TRUE;
434 g_free(last_open_dir);
435 last_open_dir = new_last_open_dir;
438 bool WiresharkApplication::event(QEvent *event)
440 QString display_filter = NULL;
441 if (event->type() == QEvent::FileOpen) {
442 QFileOpenEvent *foe = static_cast<QFileOpenEvent *>(event);
443 if (foe && foe->file().length() > 0) {
444 QString cf_path(foe->file());
446 emit openCaptureFile(cf_path, display_filter, WTAP_TYPE_AUTO);
448 pending_open_files_.append(cf_path);
453 return QApplication::event(event);
456 void WiresharkApplication::clearRecentItems() {
457 qDeleteAll(recent_items_.begin(), recent_items_.end());
458 recent_items_.clear();
459 emit updateRecentItemStatus(NULL, 0, false);
462 void WiresharkApplication::captureFileReadStarted()
464 // Doesn't appear to do anything. Logic probably needs to be in file.c.
465 QTimer::singleShot(TAP_UPDATE_DEFAULT_INTERVAL / 5, this, SLOT(updateTaps()));
466 QTimer::singleShot(TAP_UPDATE_DEFAULT_INTERVAL / 2, this, SLOT(updateTaps()));
469 void WiresharkApplication::cleanup()
471 software_update_cleanup();
472 // Write the user's recent file(s) to disk.
473 write_profile_recent();
477 void WiresharkApplication::itemStatusFinished(const QString filename, qint64 size, bool accessible) {
478 recent_item_status *ri;
480 foreach (ri, recent_items_) {
481 if (filename == ri->filename && (size != ri->size || accessible != ri->accessible)) {
483 ri->accessible = accessible;
484 ri->in_thread = false;
486 emit updateRecentItemStatus(filename, size, accessible);
491 WiresharkApplication::WiresharkApplication(int &argc, char **argv) :
492 QApplication(argc, argv),
494 is_reloading_lua_(false),
499 setApplicationName("Wireshark");
501 Q_INIT_RESOURCE(about);
502 Q_INIT_RESOURCE(i18n);
503 Q_INIT_RESOURCE(layout);
504 Q_INIT_RESOURCE(toolbar);
505 Q_INIT_RESOURCE(wsicon);
506 Q_INIT_RESOURCE(languages);
509 /* RichEd20.DLL is needed for native file dialog filter entries. */
510 if (QLibrary::isLibrary("riched20.dll")) {
511 QLibrary riched20("riched20.dll");
513 if (!riched20.isLoaded()) {
514 qDebug() << riched20.errorString();
519 #if (QT_VERSION >= QT_VERSION_CHECK(5, 1, 0))
520 setAttribute(Qt::AA_UseHighDpiPixmaps);
523 QList<int> icon_sizes = QList<int>() << 16 << 24 << 32 << 48 << 64 << 128 << 256 << 512 << 1024;
524 foreach (int icon_size, icon_sizes) {
525 QString icon_path = QString(":/wsicon/wsicon%1.png").arg(icon_size);
526 normal_icon_.addFile(icon_path);
527 icon_path = QString(":/wsicon/wsiconcap%1.png").arg(icon_size);
528 capture_icon_.addFile(icon_path);
532 // XXX - this means we try to check for the existence of all files
533 // in the recent list every 2 seconds; that causes noticeable network
534 // traffic if any of them are stored on file servers.
536 // QFileSystemWatcher should allow us to watch for files being
537 // removed or renamed. It uses kqueues and EVFILT_VNODE on FreeBSD,
538 // NetBSD, FSEvents on OS X, inotify on Linux if available, and
539 // FindFirstChagneNotification() on Windows. On all other platforms,
540 // it just periodically polls, as we're doing now.
544 // OS X and FreeBSD deliver NOTE_REVOKE notes for EVFILT_VNODE, and
545 // QFileSystemWatcher delivers signals for them, just as it does for
546 // NOTE_DELETE and NOTE_RENAME.
548 // On Linux, inotify:
550 // http://man7.org/linux/man-pages/man7/inotify.7.html
552 // appears to deliver "filesystem containing watched object was
553 // unmounted" events. It looks as if Qt turns them into "changed"
556 // On Windows, it's not clearly documented what happens on a handle
557 // opened with FindFirstChangeNotification() if the volume on which
558 // the path handed to FindFirstChangeNotification() is removed, or
559 // ejected, or whatever the Windowsese is for "unmounted". The
560 // handle obviously isn't valid any more, but whether it just hangs
561 // around and never delivers any notifications or delivers an
562 // event that turns into an error indication doesn't seem to be
563 // documented. If it just hangs around, I think our main loop will
564 // receive a WM_DEVICECHANGE Windows message with DBT_DEVICEREMOVECOMPLETE
565 // if an unmount occurs - even for network devices. If we need to watch
566 // for those, we can use the winEvent method of the QWidget for the
567 // top-level window to get Windows messages.
569 // Note also that remote file systems might not report file
570 // removal or renames if they're done on the server or done by
571 // another client. At least on OS X, they *will* get reported
572 // if they're done on the machine running the program doing the
573 // kqueue stuff, and, at least in newer versions, should get
574 // reported on SMB-mounted (and AFP-mounted?) file systems
575 // even if done on the server or another client.
577 // But, when push comes to shove, the file manager(s) on the
578 // OSes in question probably use the same mechanisms to
579 // monitor folders in folder windows or open/save dialogs or...,
580 // so my inclination is just to use QFileSystemWatcher.
582 // However, that wouldn't catch files that become *re*-accessible
583 // by virtue of a file system being re-mounted. The only way to
584 // catch *that* would be to watch for mounts and re-check all
585 // marked-as-inaccessible files.
587 // OS X and FreeBSD also support EVFILT_FS events, which notify you
588 // of file system mounts and unmounts. We'd need to add our own
589 // kqueue for that, if we can check those with QSocketNotifier.
591 // On Linux, at least as of 2006, you're supposed to poll /proc/mounts:
593 // https://lkml.org/lkml/2006/2/22/169
595 // to discover mounts.
597 // On Windows, you'd probably have to watch for WM_DEVICECHANGE events.
599 // Then again, with an automounter, a file system containing a
600 // recent capture might get unmounted automatically if you haven't
601 // referred to anything on that file system for a while, and get
602 // treated as inaccessible. However, if you try to access it,
603 // the automounter will attempt to re-mount it, so the access *will*
604 // succeed if the automounter can remount the file.
606 // (Speaking of automounters, repeatedly polling recent files will
607 // keep the file system from being unmounted, for what that's worth.)
609 // At least on OS X, you can determine whether a file is on an
610 // automounted file system by calling statfs() on its path and
611 // checking whether MNT_AUTOMOUNTED is set in f_flags. FreeBSD
612 // appears to support that flag as well, but no other *BSD appears
615 // I'm not sure what can be done on Linux.
617 recent_timer_.setParent(this);
618 connect(&recent_timer_, SIGNAL(timeout()), this, SLOT(refreshRecentFiles()));
619 recent_timer_.start(2000);
621 addr_resolv_timer_.setParent(this);
622 connect(&addr_resolv_timer_, SIGNAL(timeout()), this, SLOT(refreshAddressResolution()));
623 addr_resolv_timer_.start(1000);
625 tap_update_timer_.setParent(this);
626 tap_update_timer_.setInterval(TAP_UPDATE_DEFAULT_INTERVAL);
627 connect(this, SIGNAL(appInitialized()), &tap_update_timer_, SLOT(start()));
628 connect(&tap_update_timer_, SIGNAL(timeout()), this, SLOT(updateTaps()));
630 // Application-wide style sheet
631 QString app_style_sheet = qApp->styleSheet();
632 #if defined(Q_OS_MAC) && QT_VERSION < QT_VERSION_CHECK(5, 6, 0)
633 // Qt uses the HITheme API to draw splitters. In recent versions of OS X
634 // this looks particularly bad: https://bugreports.qt.io/browse/QTBUG-43425
635 // This doesn't look native but it looks better than Yosemite's bit-rotten
636 // rendering of HIThemeSplitterDrawInfo.
638 "QSplitter::handle:vertical { height: 0px; }\n"
639 "QSplitter::handle:horizontal { width: 0px; }\n";
641 qApp->setStyleSheet(app_style_sheet);
643 connect(qApp, SIGNAL(aboutToQuit()), this, SLOT(cleanup()));
646 void WiresharkApplication::registerUpdate(register_action_e action, const char *message)
648 emit splashUpdate(action, message);
651 void WiresharkApplication::emitAppSignal(AppSignal signal)
655 emit columnsChanged();
657 case FilterExpressionsChanged:
658 emit filterExpressionsChanged();
660 case PreferencesChanged:
661 emit preferencesChanged();
663 case PacketDissectionChanged:
664 emit packetDissectionChanged();
666 case RecentFilesRead:
667 emit recentFilesRead();
670 emit fieldsChanged();
677 // Flush any collected app signals.
679 // On OS X emitting PacketDissectionChanged from a dialog can
680 // render the application unusable:
681 // https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=11361
682 // https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=11448
683 // Work around the problem by queueing up app signals and emitting them
684 // after the dialog is closed.
686 // The following bugs might be related although they don't describe the
687 // exact behavior we're working around here:
688 // https://bugreports.qt.io/browse/QTBUG-38512
689 // https://bugreports.qt.io/browse/QTBUG-38600
690 void WiresharkApplication::flushAppSignals()
692 while (!app_signals_.isEmpty()) {
693 wsApp->emitAppSignal(app_signals_.takeFirst());
697 void WiresharkApplication::emitStatCommandSignal(const QString &menu_path, const char *arg, void *userdata)
699 emit openStatCommandDialog(menu_path, arg, userdata);
702 void WiresharkApplication::emitTapParameterSignal(const QString cfg_abbr, const QString arg, void *userdata)
704 emit openTapParameterDialog(cfg_abbr, arg, userdata);
707 // XXX Combine statistics and funnel routines into addGroupItem + groupItems?
708 void WiresharkApplication::addDynamicMenuGroupItem(int group, QAction *sg_action)
710 if (!dynamic_menu_groups_.contains(group)) {
711 dynamic_menu_groups_[group] = QList<QAction *>();
713 dynamic_menu_groups_[group] << sg_action;
716 void WiresharkApplication::appendDynamicMenuGroupItem(int group, QAction *sg_action)
718 if (!added_menu_groups_.contains(group)) {
719 added_menu_groups_[group] = QList<QAction *>();
721 added_menu_groups_[group] << sg_action;
722 addDynamicMenuGroupItem(group, sg_action);
725 void WiresharkApplication::removeDynamicMenuGroupItem(int group, QAction *sg_action)
727 if (!removed_menu_groups_.contains(group)) {
728 removed_menu_groups_[group] = QList<QAction *>();
730 removed_menu_groups_[group] << sg_action;
731 dynamic_menu_groups_[group].removeAll(sg_action);
734 QList<QAction *> WiresharkApplication::dynamicMenuGroupItems(int group)
736 if (!dynamic_menu_groups_.contains(group)) {
737 return QList<QAction *>();
740 QList<QAction *> sgi_list = dynamic_menu_groups_[group];
741 std::sort(sgi_list.begin(), sgi_list.end(), qActionLessThan);
745 QList<QAction *> WiresharkApplication::addedMenuGroupItems(int group)
747 if (!added_menu_groups_.contains(group)) {
748 return QList<QAction *>();
751 QList<QAction *> sgi_list = added_menu_groups_[group];
752 std::sort(sgi_list.begin(), sgi_list.end(), qActionLessThan);
756 QList<QAction *> WiresharkApplication::removedMenuGroupItems(int group)
758 if (!removed_menu_groups_.contains(group)) {
759 return QList<QAction *>();
762 QList<QAction *> sgi_list = removed_menu_groups_[group];
763 std::sort(sgi_list.begin(), sgi_list.end(), qActionLessThan);
767 void WiresharkApplication::clearAddedMenuGroupItems()
769 foreach (int group, added_menu_groups_.uniqueKeys()) {
770 added_menu_groups_[group].clear();
774 void WiresharkApplication::clearRemovedMenuGroupItems()
776 foreach (int group, removed_menu_groups_.uniqueKeys()) {
777 foreach (QAction *action, removed_menu_groups_[group]) {
780 removed_menu_groups_[group].clear();
787 iface_mon_event_cb(const char *iface, int up)
792 interface_options interface_opts;
794 for (ifs = 0; ifs < global_capture_opts.all_ifaces->len; ifs++) {
795 device = g_array_index(global_capture_opts.all_ifaces, interface_t, ifs);
796 if (strcmp(device.name, iface) == 0) {
800 * Interface went down or disappeared; remove all instances
801 * of it from the current list of interfaces selected
804 for (j = 0; j < global_capture_opts.ifaces->len; j++) {
805 interface_opts = g_array_index(global_capture_opts.ifaces, interface_options, j);
806 if (strcmp(interface_opts.name, device.name) == 0) {
807 g_array_remove_index(global_capture_opts.ifaces, j);
816 * We've been told that there's a new interface or that an old
817 * interface is gone; reload the local interface list.
819 scan_local_interfaces(main_window_update);
825 void WiresharkApplication::ifChangeEventsAvailable()
829 * Something's readable from the descriptor for interface
832 * Have the interface-monitoring code Read whatever interface-change
833 * events are available, and call the callback for them.
838 * Now emit a signal to indicate that the list changed, so that all
839 * places displaying the list will get updated.
841 * XXX - only if it *did* change.
843 emit localInterfaceListChanged();
847 void WiresharkApplication::refreshLocalInterfaces()
851 * Reload the local interface list.
853 scan_local_interfaces(main_window_update);
856 * Now emit a signal to indicate that the list changed, so that all
857 * places displaying the list will get updated.
859 * XXX - only if it *did* change.
861 emit localInterfaceListChanged();
865 void WiresharkApplication::allSystemsGo()
867 QString display_filter = NULL;
869 emit appInitialized();
870 while (pending_open_files_.length() > 0) {
871 emit openCaptureFile(pending_open_files_.front(), display_filter, WTAP_TYPE_AUTO);
872 pending_open_files_.pop_front();
874 software_update_init();
878 err = iface_mon_start(&iface_mon_event_cb);
880 if_notifier_ = new QSocketNotifier(iface_mon_get_sock(),
881 QSocketNotifier::Read);
882 connect(if_notifier_, SIGNAL(activated(int)), SLOT(ifChangeEventsAvailable()));
887 _e_prefs *WiresharkApplication::readConfigurationFiles(char **gdp_path, char **dp_path)
889 int gpf_open_errno, gpf_read_errno;
890 int cf_open_errno, df_open_errno;
891 int gdp_open_errno, gdp_read_errno;
892 int dp_open_errno, dp_read_errno;
893 char *gpf_path, *pf_path;
894 char *cf_path, *df_path;
895 int pf_open_errno, pf_read_errno;
898 /* load the decode as entries of this profile */
899 load_decode_as_entries();
901 /* Read the preference files. */
902 prefs_p = read_prefs(&gpf_open_errno, &gpf_read_errno, &gpf_path,
903 &pf_open_errno, &pf_read_errno, &pf_path);
905 if (gpf_path != NULL) {
906 if (gpf_open_errno != 0) {
907 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
908 "Could not open global preferences file\n\"%s\": %s.", gpf_path,
909 g_strerror(gpf_open_errno));
911 if (gpf_read_errno != 0) {
912 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
913 "I/O error reading global preferences file\n\"%s\": %s.", gpf_path,
914 g_strerror(gpf_read_errno));
917 if (pf_path != NULL) {
918 if (pf_open_errno != 0) {
919 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
920 "Could not open your preferences file\n\"%s\": %s.", pf_path,
921 g_strerror(pf_open_errno));
923 if (pf_read_errno != 0) {
924 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
925 "I/O error reading your preferences file\n\"%s\": %s.", pf_path,
926 g_strerror(pf_read_errno));
933 /* if the user wants a console to be always there, well, we should open one for him */
934 if (prefs_p->gui_console_open == console_open_always) {
939 /* Read the capture filter file. */
940 read_filter_list(CFILTER_LIST, &cf_path, &cf_open_errno);
941 if (cf_path != NULL) {
942 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
943 "Could not open your capture filter file\n\"%s\": %s.", cf_path,
944 g_strerror(cf_open_errno));
948 /* Read the display filter file. */
949 read_filter_list(DFILTER_LIST, &df_path, &df_open_errno);
950 if (df_path != NULL) {
951 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
952 "Could not open your display filter file\n\"%s\": %s.", df_path,
953 g_strerror(df_open_errno));
957 /* Read the disabled protocols file. */
958 read_disabled_protos_list(gdp_path, &gdp_open_errno, &gdp_read_errno,
959 dp_path, &dp_open_errno, &dp_read_errno);
960 read_disabled_heur_dissector_list(gdp_path, &gdp_open_errno, &gdp_read_errno,
961 dp_path, &dp_open_errno, &dp_read_errno);
962 if (*gdp_path != NULL) {
963 if (gdp_open_errno != 0) {
964 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
965 "Could not open global disabled protocols file\n\"%s\": %s.",
966 *gdp_path, g_strerror(gdp_open_errno));
968 if (gdp_read_errno != 0) {
969 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
970 "I/O error reading global disabled protocols file\n\"%s\": %s.",
971 *gdp_path, g_strerror(gdp_read_errno));
976 if (*dp_path != NULL) {
977 if (dp_open_errno != 0) {
978 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
979 "Could not open your disabled protocols file\n\"%s\": %s.", *dp_path,
980 g_strerror(dp_open_errno));
982 if (dp_read_errno != 0) {
983 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
984 "I/O error reading your disabled protocols file\n\"%s\": %s.", *dp_path,
985 g_strerror(dp_read_errno));
994 QList<recent_item_status *> WiresharkApplication::recentItems() const {
995 return recent_items_;
998 void WiresharkApplication::addRecentItem(const QString filename, qint64 size, bool accessible) {
999 recent_item_status *ri = new(recent_item_status);
1001 ri->filename = filename;
1003 ri->accessible = accessible;
1004 ri->in_thread = false;
1005 recent_items_.prepend(ri);
1007 itemStatusFinished(filename, size, accessible);
1010 static void switchTranslator(QTranslator& myTranslator, const QString& filename,
1011 const QString& searchPath)
1013 wsApp->removeTranslator(&myTranslator);
1015 if (myTranslator.load(filename, searchPath))
1016 wsApp->installTranslator(&myTranslator);
1019 void WiresharkApplication::loadLanguage(const QString& newLanguage)
1022 QString localeLanguage;
1024 if (newLanguage.isEmpty() || newLanguage == "system") {
1025 localeLanguage = QLocale::system().name();
1027 localeLanguage = newLanguage;
1030 locale = QLocale(localeLanguage);
1031 QLocale::setDefault(locale);
1032 switchTranslator(wsApp->translator,
1033 QString("wireshark_%1.qm").arg(localeLanguage), QString(":/i18n/"));
1034 if (QFile::exists(QString("%1/%2/wireshark_%3.qm")
1035 .arg(get_datafile_dir()).arg("languages").arg(localeLanguage)))
1036 switchTranslator(wsApp->translator,
1037 QString("wireshark_%1.qm").arg(localeLanguage), QString(get_datafile_dir()) + QString("/languages"));
1038 if (QFile::exists(QString("%1/wireshark_%3.qm")
1039 .arg(gchar_free_to_qstring(get_persconffile_path("languages", FALSE))).arg(localeLanguage)))
1040 switchTranslator(wsApp->translator,
1041 QString("wireshark_%1.qm").arg(localeLanguage), gchar_free_to_qstring(get_persconffile_path("languages", FALSE)));
1042 switchTranslator(wsApp->translatorQt,
1043 QString("qt_%1.qm").arg(localeLanguage),
1044 QLibraryInfo::location(QLibraryInfo::TranslationsPath));
1053 * indent-tabs-mode: nil
1056 * ex: set shiftwidth=4 tabstop=8 expandtab:
1057 * :indentSize=4:tabSize=8:noTabs=true: