2012-10-18 21:14:43 +00:00
|
|
|
/* export_object_dialog.cpp
|
|
|
|
*
|
|
|
|
* Wireshark - Network traffic analyzer
|
|
|
|
* By Gerald Combs <gerald@wireshark.org>
|
|
|
|
* Copyright 1998 Gerald Combs
|
|
|
|
*
|
2018-02-07 12:26:45 +01:00
|
|
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
2012-10-18 21:14:43 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include "export_object_dialog.h"
|
2015-06-25 09:17:03 -07:00
|
|
|
#include <ui_export_object_dialog.h>
|
2014-12-29 14:12:43 -08:00
|
|
|
|
|
|
|
#include <ui/alert_box.h>
|
2015-10-04 18:10:29 +01:00
|
|
|
#include <wsutil/utf8_entities.h>
|
2014-12-29 14:12:43 -08:00
|
|
|
|
2022-01-31 19:30:09 -08:00
|
|
|
#include "main_application.h"
|
2018-05-15 17:02:26 -07:00
|
|
|
#include "ui/qt/widgets/wireshark_file_dialog.h"
|
2019-11-21 15:57:32 +01:00
|
|
|
#include <ui/qt/widgets/export_objects_view.h>
|
|
|
|
#include <ui/qt/models/export_objects_model.h>
|
2021-02-12 11:54:54 -08:00
|
|
|
#include <ui/qt/utils/qt_ui_utils.h>
|
2012-10-18 21:14:43 +00:00
|
|
|
|
|
|
|
#include <QDialogButtonBox>
|
2015-08-24 12:30:56 -07:00
|
|
|
#include <QMessageBox>
|
2021-02-12 11:54:54 -08:00
|
|
|
#include <QMimeDatabase>
|
2015-08-24 12:30:56 -07:00
|
|
|
#include <QPushButton>
|
2019-11-21 15:57:32 +01:00
|
|
|
#include <QComboBox>
|
|
|
|
#include <QDir>
|
|
|
|
#include <QFile>
|
|
|
|
#include <QFileInfo>
|
|
|
|
#include <QDesktopServices>
|
2016-11-24 09:37:01 -05:00
|
|
|
|
|
|
|
ExportObjectDialog::ExportObjectDialog(QWidget &parent, CaptureFile &cf, register_eo_t* eo) :
|
2014-12-29 14:12:43 -08:00
|
|
|
WiresharkDialog(parent, cf),
|
2012-10-18 21:14:43 +00:00
|
|
|
eo_ui_(new Ui::ExportObjectDialog),
|
|
|
|
save_bt_(NULL),
|
|
|
|
save_all_bt_(NULL),
|
2017-12-26 11:46:48 -05:00
|
|
|
model_(eo, this),
|
|
|
|
proxyModel_(this)
|
2012-10-18 21:14:43 +00:00
|
|
|
{
|
|
|
|
QPushButton *close_bt;
|
|
|
|
|
|
|
|
eo_ui_->setupUi(this);
|
|
|
|
setAttribute(Qt::WA_DeleteOnClose, true);
|
|
|
|
|
2017-12-26 11:46:48 -05:00
|
|
|
proxyModel_.setSourceModel(&model_);
|
|
|
|
eo_ui_->objectTree->setModel(&proxyModel_);
|
|
|
|
|
2018-07-24 18:09:20 -04:00
|
|
|
proxyModel_.setFilterFixedString("");
|
|
|
|
proxyModel_.setFilterCaseSensitivity(Qt::CaseInsensitive);
|
|
|
|
proxyModel_.setFilterKeyColumn(-1);
|
|
|
|
|
2013-04-24 11:07:25 +00:00
|
|
|
#if defined(Q_OS_MAC)
|
2012-10-18 21:14:43 +00:00
|
|
|
eo_ui_->progressLabel->setAttribute(Qt::WA_MacSmallSize, true);
|
|
|
|
eo_ui_->progressBar->setAttribute(Qt::WA_MacSmallSize, true);
|
|
|
|
#endif
|
|
|
|
|
2021-10-10 16:05:57 -07:00
|
|
|
connect(&model_, &ExportObjectModel::rowsInserted,
|
|
|
|
this, &ExportObjectDialog::modelDataChanged);
|
|
|
|
connect(&model_, &ExportObjectModel::modelReset, this, &ExportObjectDialog::modelRowsReset);
|
2019-11-21 15:57:32 +01:00
|
|
|
connect(eo_ui_->filterLine, &QLineEdit::textChanged, &proxyModel_, &ExportObjectProxyModel::setTextFilterString);
|
|
|
|
connect(eo_ui_->objectTree, &ExportObjectsTreeView::currentIndexChanged, this, &ExportObjectDialog::currentHasChanged);
|
2012-10-18 21:14:43 +00:00
|
|
|
|
|
|
|
save_bt_ = eo_ui_->buttonBox->button(QDialogButtonBox::Save);
|
|
|
|
save_all_bt_ = eo_ui_->buttonBox->button(QDialogButtonBox::SaveAll);
|
|
|
|
close_bt = eo_ui_->buttonBox->button(QDialogButtonBox::Close);
|
2019-11-21 15:57:32 +01:00
|
|
|
if (eo_ui_->buttonBox->button(QDialogButtonBox::Open))
|
|
|
|
{
|
|
|
|
QPushButton * open = eo_ui_->buttonBox->button(QDialogButtonBox::Open);
|
|
|
|
open->setText(tr("Preview"));
|
|
|
|
open->setEnabled(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
contentTypes << tr("All Content-Types");
|
|
|
|
eo_ui_->cmbContentType->addItems(contentTypes);
|
2012-10-18 21:14:43 +00:00
|
|
|
|
2022-01-31 19:30:09 -08:00
|
|
|
setWindowTitle(mainApp->windowTitleString(QStringList() << tr("Export") << tr("%1 object list").arg(proto_get_protocol_short_name(find_protocol_by_id(get_eo_proto_id(eo))))));
|
2014-06-02 16:54:00 +02:00
|
|
|
|
2012-10-18 21:14:43 +00:00
|
|
|
if (save_bt_) save_bt_->setEnabled(false);
|
|
|
|
if (save_all_bt_) save_all_bt_->setEnabled(false);
|
|
|
|
if (close_bt) close_bt->setDefault(true);
|
|
|
|
|
2021-10-10 16:05:57 -07:00
|
|
|
connect(&cap_file_, &CaptureFile::captureEvent,
|
|
|
|
this, &ExportObjectDialog::captureEvent);
|
2012-10-18 21:14:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ExportObjectDialog::~ExportObjectDialog()
|
|
|
|
{
|
|
|
|
delete eo_ui_;
|
2017-12-26 11:46:48 -05:00
|
|
|
model_.removeTap();
|
2015-08-24 12:30:56 -07:00
|
|
|
removeTapListeners();
|
2012-10-18 21:14:43 +00:00
|
|
|
}
|
|
|
|
|
2019-11-21 15:57:32 +01:00
|
|
|
void ExportObjectDialog::currentHasChanged(QModelIndex current)
|
2012-10-18 21:14:43 +00:00
|
|
|
{
|
2019-11-21 15:57:32 +01:00
|
|
|
if (current.isValid())
|
|
|
|
{
|
|
|
|
QModelIndex sibl = current.sibling(current.row(), ExportObjectModel::colPacket);
|
|
|
|
if (eo_ui_->buttonBox->button(QDialogButtonBox::Open))
|
|
|
|
{
|
2021-02-12 11:54:54 -08:00
|
|
|
QString mime_type = sibl.sibling(current.row(), ExportObjectModel::colContent).data().toString();
|
|
|
|
eo_ui_->buttonBox->button(QDialogButtonBox::Open)->setEnabled(mimeTypeIsPreviewable(mime_type));
|
2019-11-21 15:57:32 +01:00
|
|
|
}
|
2022-01-31 19:30:09 -08:00
|
|
|
mainApp->gotoFrame(sibl.data().toInt());
|
2019-11-21 15:57:32 +01:00
|
|
|
}
|
2012-10-18 21:14:43 +00:00
|
|
|
}
|
|
|
|
|
2021-02-12 11:54:54 -08:00
|
|
|
bool ExportObjectDialog::mimeTypeIsPreviewable(QString mime_type)
|
|
|
|
{
|
|
|
|
// XXX This excludes everything except HTTP. Maybe that's a good thing?
|
|
|
|
// Take care when adding to this, e.g. text/html or image/svg might contain JavaScript.
|
|
|
|
QStringList previewable_mime_types = QStringList()
|
|
|
|
<< "text/plain"
|
|
|
|
<< "image/gif" << "image/jpeg" << "image/png";
|
|
|
|
|
|
|
|
if (previewable_mime_types.contains(mime_type)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-11-21 15:57:32 +01:00
|
|
|
void ExportObjectDialog::modelDataChanged(const QModelIndex&, int from, int to)
|
2012-10-18 21:14:43 +00:00
|
|
|
{
|
2020-11-30 20:20:25 -05:00
|
|
|
bool contentTypes_changed = false;
|
2017-12-26 11:46:48 -05:00
|
|
|
bool enabled = (model_.rowCount() > 0);
|
|
|
|
if (save_bt_) save_bt_->setEnabled(enabled);
|
|
|
|
if (save_all_bt_) save_all_bt_->setEnabled(enabled);
|
2019-11-21 15:57:32 +01:00
|
|
|
|
|
|
|
for (int row = from; row <= to; row++)
|
|
|
|
{
|
|
|
|
QModelIndex idx = model_.index(row, ExportObjectModel::colContent);
|
|
|
|
if (idx.isValid())
|
|
|
|
{
|
|
|
|
QString dataType = idx.data().toString();
|
|
|
|
if (dataType.length() > 0 && ! contentTypes.contains(dataType))
|
|
|
|
{
|
|
|
|
contentTypes << dataType;
|
2020-11-30 20:20:25 -05:00
|
|
|
contentTypes_changed = true;
|
2019-11-21 15:57:32 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-11-30 20:20:25 -05:00
|
|
|
if (contentTypes_changed) {
|
|
|
|
contentTypes.sort(Qt::CaseInsensitive);
|
|
|
|
QString selType = eo_ui_->cmbContentType->currentText();
|
|
|
|
eo_ui_->cmbContentType->clear();
|
|
|
|
eo_ui_->cmbContentType->addItem(tr("All Content-Types"));
|
|
|
|
eo_ui_->cmbContentType->addItems(contentTypes);
|
|
|
|
if (contentTypes.contains(selType) )
|
|
|
|
eo_ui_->cmbContentType->setCurrentText(selType);
|
|
|
|
}
|
2012-10-18 21:14:43 +00:00
|
|
|
}
|
|
|
|
|
2017-12-26 11:46:48 -05:00
|
|
|
void ExportObjectDialog::modelRowsReset()
|
2012-10-18 21:14:43 +00:00
|
|
|
{
|
2019-11-21 15:57:32 +01:00
|
|
|
contentTypes.clear();
|
|
|
|
eo_ui_->cmbContentType->clear();
|
2020-11-30 20:20:25 -05:00
|
|
|
eo_ui_->cmbContentType->addItem(tr("All Content-Types"));
|
2019-11-21 15:57:32 +01:00
|
|
|
|
2012-10-18 21:14:43 +00:00
|
|
|
if (save_bt_) save_bt_->setEnabled(false);
|
|
|
|
if (save_all_bt_) save_all_bt_->setEnabled(false);
|
|
|
|
}
|
|
|
|
|
2012-10-18 21:51:38 +00:00
|
|
|
void ExportObjectDialog::show()
|
|
|
|
{
|
|
|
|
/* Data will be gathered via a tap callback */
|
2017-12-26 11:46:48 -05:00
|
|
|
if (!registerTapListener(model_.getTapListenerName(), model_.getTapData(), NULL, 0,
|
|
|
|
ExportObjectModel::resetTap,
|
|
|
|
model_.getTapPacketFunc(),
|
2015-08-24 12:30:56 -07:00
|
|
|
NULL)) {
|
2012-10-18 21:51:38 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
QDialog::show();
|
2014-12-29 14:12:43 -08:00
|
|
|
cap_file_.retapPackets();
|
2012-10-18 21:51:38 +00:00
|
|
|
eo_ui_->progressFrame->hide();
|
2017-12-26 11:46:48 -05:00
|
|
|
for (int i = 0; i < eo_ui_->objectTree->model()->columnCount(); i++)
|
2012-10-18 21:51:38 +00:00
|
|
|
eo_ui_->objectTree->resizeColumnToContents(i);
|
|
|
|
|
2017-12-26 11:46:48 -05:00
|
|
|
eo_ui_->objectTree->sortByColumn(ExportObjectModel::colPacket, Qt::AscendingOrder);
|
2012-10-18 21:51:38 +00:00
|
|
|
}
|
|
|
|
|
2019-11-21 15:57:32 +01:00
|
|
|
void ExportObjectDialog::keyPressEvent(QKeyEvent *evt)
|
|
|
|
{
|
|
|
|
if(evt->key() == Qt::Key_Enter || evt->key() == Qt::Key_Return)
|
|
|
|
return;
|
|
|
|
QDialog::keyPressEvent(evt);
|
|
|
|
}
|
|
|
|
|
2012-10-18 21:14:43 +00:00
|
|
|
void ExportObjectDialog::accept()
|
|
|
|
{
|
|
|
|
// Don't close the dialog.
|
|
|
|
}
|
|
|
|
|
2018-03-28 10:04:50 +02:00
|
|
|
void ExportObjectDialog::captureEvent(CaptureEvent e)
|
2012-10-18 21:14:43 +00:00
|
|
|
{
|
2018-03-28 10:04:50 +02:00
|
|
|
if ((e.captureContext() == CaptureEvent::File) &&
|
|
|
|
(e.eventType() == CaptureEvent::Closing))
|
2017-12-26 11:46:48 -05:00
|
|
|
{
|
|
|
|
close();
|
|
|
|
}
|
2012-10-18 21:14:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ExportObjectDialog::on_buttonBox_helpRequested()
|
|
|
|
{
|
2022-01-31 19:30:09 -08:00
|
|
|
mainApp->helpTopicAction(HELP_EXPORT_OBJECT_LIST);
|
2012-10-18 21:14:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ExportObjectDialog::on_buttonBox_clicked(QAbstractButton *button)
|
|
|
|
{
|
|
|
|
switch (eo_ui_->buttonBox->standardButton(button)) {
|
|
|
|
case QDialogButtonBox::Save:
|
|
|
|
saveCurrentEntry();
|
|
|
|
break;
|
|
|
|
case QDialogButtonBox::SaveAll:
|
|
|
|
saveAllEntries();
|
|
|
|
break;
|
2019-11-21 15:57:32 +01:00
|
|
|
case QDialogButtonBox::Open:
|
|
|
|
{
|
|
|
|
QString temp;
|
|
|
|
saveCurrentEntry(&temp);
|
|
|
|
|
2021-02-12 11:54:54 -08:00
|
|
|
if (temp.length() > 0) {
|
|
|
|
QMimeDatabase mime_db;
|
|
|
|
QMimeType mime_type = mime_db.mimeTypeForFile(temp, QMimeDatabase::MatchContent);
|
|
|
|
if (mimeTypeIsPreviewable(mime_type.name())) {
|
|
|
|
QDesktopServices::openUrl(QUrl(QString("file:///").append(temp), QUrl::TolerantMode));
|
|
|
|
} else {
|
|
|
|
desktop_show_in_folder(temp);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2019-11-21 15:57:32 +01:00
|
|
|
break;
|
|
|
|
}
|
2012-10-18 21:14:43 +00:00
|
|
|
default: // Help, Cancel
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-21 15:57:32 +01:00
|
|
|
void ExportObjectDialog::on_cmbContentType_currentIndexChanged(int index)
|
|
|
|
{
|
|
|
|
QString filterString = index <= 0 ? "" : eo_ui_->cmbContentType->currentText();
|
|
|
|
proxyModel_.setContentFilterString(filterString);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void ExportObjectDialog::saveCurrentEntry(QString *tempFile)
|
2012-10-18 21:14:43 +00:00
|
|
|
{
|
Work around macOS running applications in /.
If an application is launched from the Finder, it appears to get / as
its current directory. This causes Wireshark open/save dialogs to open
up / if the user hasn't already opened a file in another directory, so
that there's no "last open directory" in the recent file.
Have get_persdatafile_dir(), on UN*X, cache the personal data directory
just as it does on Windows and, if nothing's been cached, have it fetch
the current directory and, if that succeeds *and* it's not the root
directory, use that. Otherwise, use the user's home directory.
Fixes #9862.
In addition, separate the notion of "last open directory" and "open
dialog initial directory", where the latter is the last open directory
*if* a file has been opened in this session or the recent file has the
last open directory from a previous session, otherwise it's the user's
personal data directory.
Use the latter notion in file open/save dialogs; use the former notion
when reading from and writing to the recent file.
This means we don't need to set the "last open directory" at startup
time. That way, running Wireshark without opening a file won't cause
the "last open directory" to be set, so that if a user runs it from a
directory, the "open dialog initial directory" won't be the last
directory from which Wireshark was run.
2023-11-10 00:08:48 -08:00
|
|
|
QDir path(mainApp->openDialogInitialDir());
|
2012-10-18 21:14:43 +00:00
|
|
|
|
2018-10-25 20:54:51 -04:00
|
|
|
QModelIndex proxyIndex = eo_ui_->objectTree->currentIndex();
|
|
|
|
if (!proxyIndex.isValid())
|
|
|
|
return;
|
|
|
|
|
|
|
|
QModelIndex current = proxyModel_.mapToSource(proxyIndex);
|
2017-12-26 11:46:48 -05:00
|
|
|
if (!current.isValid())
|
2016-11-24 09:37:01 -05:00
|
|
|
return;
|
2012-10-18 21:14:43 +00:00
|
|
|
|
2019-11-21 15:57:32 +01:00
|
|
|
QString entry_filename = current.sibling(current.row(), ExportObjectModel::colFilename).data().toString();
|
2017-12-26 11:46:48 -05:00
|
|
|
if (entry_filename.isEmpty())
|
2016-11-24 09:37:01 -05:00
|
|
|
return;
|
2012-10-18 21:14:43 +00:00
|
|
|
|
2019-11-21 15:57:32 +01:00
|
|
|
QString file_name;
|
|
|
|
if (!tempFile)
|
|
|
|
{
|
|
|
|
GString *safe_filename = eo_massage_str(entry_filename.toUtf8().constData(), EXPORT_OBJECT_MAXFILELEN, 0);
|
2022-01-31 19:30:09 -08:00
|
|
|
file_name = WiresharkFileDialog::getSaveFileName(this, mainApp->windowTitleString(tr("Save Object As…")),
|
2019-11-21 15:57:32 +01:00
|
|
|
safe_filename->str);
|
2024-04-02 10:17:30 -07:00
|
|
|
g_string_free(safe_filename, true);
|
2019-11-21 15:57:32 +01:00
|
|
|
} else {
|
2020-02-29 10:34:31 +01:00
|
|
|
QString path = QDir::tempPath().append("/").append(entry_filename);
|
2019-11-21 15:57:32 +01:00
|
|
|
/* This means, the system must remove the file! */
|
|
|
|
file_name = path;
|
|
|
|
if (QFileInfo::exists(path))
|
|
|
|
QFile::remove(path);
|
|
|
|
*tempFile = path;
|
|
|
|
}
|
2012-10-18 21:14:43 +00:00
|
|
|
|
2017-12-26 11:46:48 -05:00
|
|
|
model_.saveEntry(current, file_name);
|
2012-10-18 21:14:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ExportObjectDialog::saveAllEntries()
|
|
|
|
{
|
Work around macOS running applications in /.
If an application is launched from the Finder, it appears to get / as
its current directory. This causes Wireshark open/save dialogs to open
up / if the user hasn't already opened a file in another directory, so
that there's no "last open directory" in the recent file.
Have get_persdatafile_dir(), on UN*X, cache the personal data directory
just as it does on Windows and, if nothing's been cached, have it fetch
the current directory and, if that succeeds *and* it's not the root
directory, use that. Otherwise, use the user's home directory.
Fixes #9862.
In addition, separate the notion of "last open directory" and "open
dialog initial directory", where the latter is the last open directory
*if* a file has been opened in this session or the recent file has the
last open directory from a previous session, otherwise it's the user's
personal data directory.
Use the latter notion in file open/save dialogs; use the former notion
when reading from and writing to the recent file.
This means we don't need to set the "last open directory" at startup
time. That way, running Wireshark without opening a file won't cause
the "last open directory" to be set, so that if a user runs it from a
directory, the "open dialog initial directory" won't be the last
directory from which Wireshark was run.
2023-11-10 00:08:48 -08:00
|
|
|
QDir save_in_dir(mainApp->openDialogInitialDir());
|
2015-03-17 11:45:43 -07:00
|
|
|
QString save_in_path;
|
2012-10-18 21:14:43 +00:00
|
|
|
|
2015-03-17 11:45:43 -07:00
|
|
|
//
|
|
|
|
// We want the user to be able to specify a directory in which
|
|
|
|
// to drop files for all the objects, not a file name.
|
|
|
|
//
|
|
|
|
// XXX - what we *really* want is something that asks the user
|
|
|
|
// for an existing directory *but* lets them create a new
|
2017-04-05 12:15:27 -07:00
|
|
|
// directory in the process. That's what we get on macOS,
|
2015-03-17 11:45:43 -07:00
|
|
|
// as the native dialog is used, and it supports that; does
|
|
|
|
// that also work on Windows and with Qt's own dialog?
|
|
|
|
//
|
2022-01-31 19:30:09 -08:00
|
|
|
save_in_path = WiresharkFileDialog::getExistingDirectory(this, mainApp->windowTitleString(tr("Save All Objects In…")),
|
2015-03-17 11:45:43 -07:00
|
|
|
save_in_dir.canonicalPath(),
|
|
|
|
QFileDialog::ShowDirsOnly);
|
|
|
|
|
2019-01-01 13:04:44 -08:00
|
|
|
if (save_in_path.length() < 1)
|
2017-12-26 11:46:48 -05:00
|
|
|
return;
|
|
|
|
|
2019-01-01 14:12:15 -08:00
|
|
|
model_.saveAllEntries(save_in_path);
|
2012-10-18 21:14:43 +00:00
|
|
|
}
|