diff options
author | Roland Knall <rknall@gmail.com> | 2019-07-11 00:25:45 +0200 |
---|---|---|
committer | Roland Knall <rknall@gmail.com> | 2019-07-17 18:25:11 +0000 |
commit | 390071ed0bc8aaf378c3468989ccde1c93817542 (patch) | |
tree | 2e7abfd67e050a42bdd739a105fdf4032782cf9f /ui | |
parent | 0696d9349524ae06d17e774f5590a0b94ebae1c9 (diff) |
Qt: Import Profile information
Allow easy import of profiles. Profiles must be stored inside
a zip file, with no additional hierarchy.
Change-Id: I0ae77460c20ef6b3e447906e671b0cefa6b9b032
Reviewed-on: https://code.wireshark.org/review/33881
Petri-Dish: Roland Knall <rknall@gmail.com>
Tested-by: Petri Dish Buildbot
Reviewed-by: Roland Knall <rknall@gmail.com>
Diffstat (limited to 'ui')
-rw-r--r-- | ui/profile.c | 4 | ||||
-rw-r--r-- | ui/qt/CMakeLists.txt | 4 | ||||
-rw-r--r-- | ui/qt/main_status_bar.cpp | 3 | ||||
-rw-r--r-- | ui/qt/models/profile_model.cpp | 121 | ||||
-rw-r--r-- | ui/qt/models/profile_model.h | 10 | ||||
-rw-r--r-- | ui/qt/profile_dialog.cpp | 38 | ||||
-rw-r--r-- | ui/qt/profile_dialog.h | 7 | ||||
-rw-r--r-- | ui/qt/profile_dialog.ui | 25 | ||||
-rw-r--r-- | ui/qt/utils/wireshark_zip_helper.cpp | 123 | ||||
-rw-r--r-- | ui/qt/utils/wireshark_zip_helper.h | 42 |
10 files changed, 339 insertions, 38 deletions
diff --git a/ui/profile.c b/ui/profile.c index 786b6bedcb..6b16e4af4f 100644 --- a/ui/profile.c +++ b/ui/profile.c @@ -262,6 +262,8 @@ empty_profile_list(gboolean edit_list) } g_assert(g_list_length(*flpp) == 0); + if ( ! edited_profiles ) + edited_profiles = NULL; } flpp = ¤t_profiles; @@ -271,6 +273,8 @@ empty_profile_list(gboolean edit_list) } g_assert(g_list_length(*flpp) == 0); + if ( ! current_profiles ) + current_profiles = NULL; } void diff --git a/ui/qt/CMakeLists.txt b/ui/qt/CMakeLists.txt index 1d1ae00a49..8c7c888898 100644 --- a/ui/qt/CMakeLists.txt +++ b/ui/qt/CMakeLists.txt @@ -63,6 +63,7 @@ set(WIRESHARK_UTILS_HEADERS utils/tango_colors.h utils/variant_pointer.h utils/wireshark_mime_data.h + utils/wireshark_zip_helper.h ) set(WIRESHARK_MODEL_HEADERS @@ -90,7 +91,7 @@ set(WIRESHARK_MODEL_HEADERS models/percent_bar_delegate.h models/pref_delegate.h models/pref_models.h - models/profile_model.h + models/profile_model.h models/proto_tree_model.h models/related_packet_delegate.h models/sparkline_delegate.h @@ -288,6 +289,7 @@ set(WIRESHARK_UTILS_SRCS utils/qt_ui_utils.cpp utils/stock_icon.cpp utils/wireshark_mime_data.cpp + utils/wireshark_zip_helper.cpp ) set(WIRESHARK_MODEL_SRCS diff --git a/ui/qt/main_status_bar.cpp b/ui/qt/main_status_bar.cpp index 2bd86d1451..2aac68b053 100644 --- a/ui/qt/main_status_bar.cpp +++ b/ui/qt/main_status_bar.cpp @@ -591,6 +591,9 @@ void MainStatusBar::showProfileMenu(const QPoint &global_pos, Qt::MouseButton bu QAction * action = ctx_menu_.addAction(tr("Manage Profiles" UTF8_HORIZONTAL_ELLIPSIS)); action->setProperty("dialog_action_", (int)ProfileDialog::ShowProfiles); connect(action, SIGNAL(triggered()), this, SLOT(manageProfile())); + action = ctx_menu_.addAction(tr("Import" UTF8_HORIZONTAL_ELLIPSIS)); + action->setProperty("dialog_action_", (int)ProfileDialog::ImportProfile); + connect(action, SIGNAL(triggered()), this, SLOT(manageProfile())); ctx_menu_.addSeparator(); action = ctx_menu_.addAction(tr("New" UTF8_HORIZONTAL_ELLIPSIS)); action->setProperty("dialog_action_", (int)ProfileDialog::NewProfile); diff --git a/ui/qt/models/profile_model.cpp b/ui/qt/models/profile_model.cpp index 98b1938b44..64360cbcbf 100644 --- a/ui/qt/models/profile_model.cpp +++ b/ui/qt/models/profile_model.cpp @@ -7,6 +7,7 @@ * SPDX-License-Identifier: GPL-2.0-or-later */ +#include "config.h" #include "glib.h" #include "ui/profile.h" @@ -17,9 +18,11 @@ #include <ui/qt/utils/color_utils.h> #include <ui/qt/utils/qt_ui_utils.h> +#include <ui/qt/utils/wireshark_zip_helper.h> #include <QDir> #include <QFont> +#include <QTemporaryDir> #define gxx_list_next(list) ((list) ? ((reinterpret_cast<GList *>(list))->next) : Q_NULLPTR) @@ -114,14 +117,14 @@ ProfileModel::ProfileModel(QObject * parent) : void ProfileModel::loadProfiles() { - bool refresh = profiles_.count() > 0; + emit beginResetModel(); - if ( refresh ) - profiles_.clear(); - else - init_profile_list(); + bool refresh = profiles_.count() > 0; - emit beginResetModel(); + if ( refresh ) + profiles_.clear(); + else + init_profile_list(); GList *fl_entry = edited_profile_list(); while (fl_entry && fl_entry->data) @@ -166,6 +169,20 @@ int ProfileModel::columnCount(const QModelIndex &) const return static_cast<int>(_LAST_ENTRY); } +profile_def * ProfileModel::guard(int row) const +{ + if ( profiles_.count() <= row ) + return Q_NULLPTR; + + if ( ! edited_profile_list() ) + { + static_cast<QList<profile_def *>>(profiles_).clear(); + return Q_NULLPTR; + } + + return profiles_.at(row); +} + QVariant ProfileModel::data(const QModelIndex &index, int role) const { QString msg; @@ -173,7 +190,7 @@ QVariant ProfileModel::data(const QModelIndex &index, int role) const if ( ! index.isValid() || profiles_.count() <= index.row() ) return QVariant(); - profile_def * prof = profiles_.at(index.row()); + profile_def * prof = guard(index.row()); if ( ! prof ) return QVariant(); @@ -225,7 +242,7 @@ QVariant ProfileModel::data(const QModelIndex &index, int role) const if ( set_profile_.compare(prof->name) == 0 ) { - profile_def * act = profiles_.at(activeProfile().row()); + profile_def * act = guard(activeProfile().row()); if ( act->is_global == prof->is_global ) font.setBold(true); } @@ -316,7 +333,7 @@ QVariant ProfileModel::data(const QModelIndex &index, int role) const case ProfileModel::DATA_IS_SELECTED: { QModelIndex selected = activeProfile(); - profile_def * selprof = profiles_.at(selected.row()); + profile_def * selprof = guard(selected.row()); if ( selprof ) { if ( selprof->is_global != prof->is_global ) @@ -388,7 +405,7 @@ Qt::ItemFlags ProfileModel::flags(const QModelIndex &index) const if ( ! index.isValid() || profiles_.count() <= index.row() ) return fl; - profile_def * prof = profiles_.at(index.row()); + profile_def * prof = guard(index.row()); if ( ! prof ) return fl; @@ -419,7 +436,7 @@ QList<int> ProfileModel::findAllByNameAndVisibility(QString name, bool isGlobal) for ( int cnt = 0; cnt < profiles_.count(); cnt++ ) { - profile_def * prof = profiles_.at(cnt); + profile_def * prof = guard(cnt); if ( prof && static_cast<bool>(prof->is_global) == isGlobal && name.compare(prof->name) == 0 ) result << cnt; } @@ -441,7 +458,7 @@ QModelIndex ProfileModel::duplicateEntry(QModelIndex idx) if ( ! idx.isValid() || profiles_.count() <= idx.row() ) return QModelIndex(); - profile_def * prof = profiles_.at(idx.row()); + profile_def * prof = guard(idx.row()); if ( ! prof ) return QModelIndex(); @@ -476,7 +493,7 @@ void ProfileModel::deleteEntry(QModelIndex idx) if ( ! idx.isValid() ) return; - profile_def * prof = profiles_.at(idx.row()); + profile_def * prof = guard(idx.row()); if ( ! prof ) return; @@ -530,7 +547,7 @@ bool ProfileModel::setData(const QModelIndex &idx, const QVariant &value, int ro if ( ! value.isValid() || value.toString().isEmpty() ) return false; - profile_def * prof = profiles_.at(idx.row()); + profile_def * prof = guard(idx.row()); if ( ! prof || prof->status == PROF_STAT_DEFAULT ) return false; @@ -552,6 +569,82 @@ bool ProfileModel::setData(const QModelIndex &idx, const QVariant &value, int ro return true; } +#ifdef HAVE_MINIZIP +/* This check runs BEFORE the file has been unzipped! */ +bool ProfileModel::acceptFile(QString fileName, int fileSize) +{ + if ( fileName.contains(".") || fileName.startsWith("_") ) + return false; + + if ( fileSize > 1024 * 512 ) + return false; + + /* config_file_exists_with_entries cannot be used, due to the fact, that the file has not been extracted yet */ + + return true; +} + +int ProfileModel::unzipProfiles(QString filename) +{ + int count = 0; + QDir profileDir(get_profiles_dir()); + QTemporaryDir dir; +#if 0 + dir.setAutoRemove(false); +#endif + + if ( dir.isValid() ) + { + WireSharkZipHelper::unzip(filename, dir.path(), &ProfileModel::acceptFile); + + QDir temp(dir.path()); + temp.setSorting(QDir::Name); + temp.setFilter(QDir::Dirs | QDir::NoSymLinks | QDir::NoDotAndDotDot); + QFileInfoList entries = temp.entryInfoList(); + + foreach ( QFileInfo fentry, entries ) + { + QString profilePath = profileDir.absolutePath() + QDir::separator() + fentry.fileName(); + QString tempPath = fentry.absoluteFilePath(); + + if ( QFile::exists(profilePath) ) + continue; + + QDir profileDir(profilePath); + if ( ! profileDir.mkpath(profilePath) || ! QFile::exists(tempPath) ) + continue; + + QDir tempProfile(tempPath); + tempProfile.setFilter(QDir::Files | QDir::Hidden | QDir::NoSymLinks); + QFileInfoList files = tempProfile.entryInfoList(); + if ( files.count() <= 0 ) + continue; + + int created = 0; + foreach ( QFileInfo finfo, files) + { + QString tempFile = finfo.absoluteFilePath(); + QString profileFile = profilePath + QDir::separator() + finfo.fileName(); + + if ( ! QFile::exists(tempFile) || QFile::exists(profileFile) ) + continue; + + if ( QFile::copy(tempFile, profileFile) ) + created++; + } + + if ( created > 0 ) + count++; + } + } + + if ( count > 0 ) + loadProfiles(); + + return count; +} +#endif + bool ProfileModel::checkNameValidity(QString name, QString *msg) { QString message; diff --git a/ui/qt/models/profile_model.h b/ui/qt/models/profile_model.h index b49b593377..527101c531 100644 --- a/ui/qt/models/profile_model.h +++ b/ui/qt/models/profile_model.h @@ -10,6 +10,7 @@ #ifndef PROFILE_MODEL_H #define PROFILE_MODEL_H +#include "config.h" #include "glib.h" #include <ui/profile.h> @@ -88,6 +89,10 @@ public: GList * at(int row) const; +#ifdef HAVE_MINIZIP + int unzipProfiles(QString filename); +#endif + static bool checkNameValidity(QString name, QString *msg = Q_NULLPTR); QList<int> findAllByNameAndVisibility(QString name, bool isGlobal = false); @@ -97,9 +102,14 @@ private: bool reset_default_; void loadProfiles(); + profile_def * guard(int row) const; GList * entry(profile_def *) const; int findByNameAndVisibility(QString name, bool isGlobal = false); + +#ifdef HAVE_MINIZIP + static bool acceptFile(QString fileName, int fileSize); +#endif }; #endif diff --git a/ui/qt/profile_dialog.cpp b/ui/qt/profile_dialog.cpp index 158b6322b2..6bf2e689bc 100644 --- a/ui/qt/profile_dialog.cpp +++ b/ui/qt/profile_dialog.cpp @@ -25,6 +25,7 @@ #include <ui_profile_dialog.h> #include "wireshark_application.h" #include <ui/qt/utils/color_utils.h> +#include <ui/qt/simple_dialog.h> #include <QBrush> #include <QDir> @@ -35,6 +36,8 @@ #include <QUrl> #include <QComboBox> #include <QLineEdit> +#include <QFileDialog> +#include <QStandardPaths> ProfileDialog::ProfileDialog(QWidget *parent) : GeometryStateDialog(parent), @@ -59,7 +62,11 @@ ProfileDialog::ProfileDialog(QWidget *parent) : pd_ui_->newToolButton->setAttribute(Qt::WA_MacSmallSize, true); pd_ui_->deleteToolButton->setAttribute(Qt::WA_MacSmallSize, true); pd_ui_->copyToolButton->setAttribute(Qt::WA_MacSmallSize, true); - pd_ui_->infoLabel->setAttribute(Qt::WA_MacSmallSize, true); + pd_ui_->btnImport->setAttribute(Qt::WA_MacSmallSize, true); +#endif + +#ifndef HAVE_MINIZIP + pd_ui_->btnImport->setVisible(false); #endif model_ = new ProfileModel(this); @@ -118,6 +125,11 @@ int ProfileDialog::execAction(ProfileDialog::ProfileAction profile_action) on_newToolButton_clicked(); ret = exec(); break; + case ImportProfile: +#ifdef HAVE_MINIZIP + on_btnImport_clicked(); +#endif + break; case EditCurrentProfile: item = pd_ui_->profileTreeView->currentIndex(); if (item.isValid()) { @@ -315,6 +327,30 @@ void ProfileDialog::filterChanged(const QString &text) pd_ui_->profileTreeView->setCurrentIndex(active); } +#ifdef HAVE_MINIZIP +void ProfileDialog::on_btnImport_clicked() +{ + QString docDir = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation); + QString zipFile = QFileDialog::getOpenFileName(this, tr("Select zip file for import"), + docDir, tr("Zip File (*.zip)")); + + QFileInfo fi(zipFile); + if ( ! fi.exists() ) + return; + + int count = 0; + if ( ( count = model_->unzipProfiles(zipFile) ) == 0 ) + { + QString msg = tr("An error occured, while importing profiles from %1").arg(fi.fileName()); + QMessageBox::warning(this, tr("Error importing profiles"), msg ); + } + else { + QString msg = tr("%1 profiles have been imported").arg(QString::number(count)); + QMessageBox::information(this, tr("Importing profiles"), msg ); + } +} +#endif + /* * Editor modelines * diff --git a/ui/qt/profile_dialog.h b/ui/qt/profile_dialog.h index 407ad910e0..05bc708beb 100644 --- a/ui/qt/profile_dialog.h +++ b/ui/qt/profile_dialog.h @@ -10,6 +10,8 @@ #ifndef PROFILE_DIALOG_H #define PROFILE_DIALOG_H +#include "config.h" + #include <ui/qt/geometry_state_dialog.h> #include <ui/qt/models/profile_model.h> #include <ui/qt/widgets/profile_tree_view.h> @@ -26,7 +28,7 @@ class ProfileDialog : public GeometryStateDialog Q_OBJECT public: - enum ProfileAction { ShowProfiles, NewProfile, EditCurrentProfile, DeleteCurrentProfile }; + enum ProfileAction { ShowProfiles, NewProfile, ImportProfile, EditCurrentProfile, DeleteCurrentProfile }; explicit ProfileDialog(QWidget *parent = Q_NULLPTR); ~ProfileDialog(); @@ -52,6 +54,9 @@ private: private slots: void currentItemChanged(); +#ifdef HAVE_MINIZIP + void on_btnImport_clicked(); +#endif void on_newToolButton_clicked(); void on_deleteToolButton_clicked(); diff --git a/ui/qt/profile_dialog.ui b/ui/qt/profile_dialog.ui index 0a4f14716d..63da77d532 100644 --- a/ui/qt/profile_dialog.ui +++ b/ui/qt/profile_dialog.ui @@ -6,7 +6,7 @@ <rect> <x>0</x> <y>0</y> - <width>470</width> + <width>557</width> <height>386</height> </rect> </property> @@ -51,7 +51,7 @@ </widget> </item> <item> - <layout class="QHBoxLayout" name="horizontalLayout" stretch="0,0,0,0,0"> + <layout class="QHBoxLayout" name="horizontalLayout" stretch="0,0,0,0,0,0"> <item> <widget class="StockIconToolButton" name="newToolButton"> <property name="toolTip"> @@ -93,21 +93,9 @@ </spacer> </item> <item> - <widget class="ElidedLabel" name="infoLabel"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Expanding" vsizetype="Preferred"> - <horstretch>1</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> + <widget class="QPushButton" name="btnImport"> <property name="text"> - <string/> - </property> - <property name="alignment"> - <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> - </property> - <property name="openExternalLinks"> - <bool>true</bool> + <string>Import</string> </property> </widget> </item> @@ -127,11 +115,6 @@ </widget> <customwidgets> <customwidget> - <class>ElidedLabel</class> - <extends>QLabel</extends> - <header>widgets/elided_label.h</header> - </customwidget> - <customwidget> <class>StockIconToolButton</class> <extends>QToolButton</extends> <header>widgets/stock_icon_tool_button.h</header> diff --git a/ui/qt/utils/wireshark_zip_helper.cpp b/ui/qt/utils/wireshark_zip_helper.cpp new file mode 100644 index 0000000000..78dc9949fe --- /dev/null +++ b/ui/qt/utils/wireshark_zip_helper.cpp @@ -0,0 +1,123 @@ +/* wireshark_zip_helper.cpp + * + * Definitions for zip / unzip of files + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1998 Gerald Combs + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include <ui/qt/utils/wireshark_zip_helper.h> + +#ifdef HAVE_MINIZIP +#include "config.h" + +#include "glib.h" + +#include <iosfwd> +#include <iostream> +#include <minizip/unzip.h> + +#include "epan/prefs.h" +#include "wsutil/file_util.h" + +#include <QDataStream> +#include <QDir> +#include <QFileInfo> + +bool WireSharkZipHelper::unzip(QString zipFile, QString directory, bool (*fileCheck)(QString, int)) +{ + unzFile uf = Q_NULLPTR; + QFileInfo fi(zipFile); + QDir di(directory); + int files = 0; + + if ( ! fi.exists() || ! di.exists() ) + return false; + + if ( ( uf = unzOpen64(zipFile.toUtf8().constData()) ) == Q_NULLPTR ) + return false; + + unz_global_info64 gi; + int err = unzGetGlobalInfo64(uf,&gi); + unsigned int nmbr = static_cast<unsigned int>(gi.number_entry); + if (nmbr <= 0) + return false; + + for ( unsigned int cnt = 0; cnt < nmbr; cnt++ ) + { + char filename_inzip[256]; + unz_file_info64 file_info; + err = unzGetCurrentFileInfo64(uf, &file_info, filename_inzip, sizeof(filename_inzip), + Q_NULLPTR, 0, Q_NULLPTR, 0); + if ( err == UNZ_OK ) + { + QString fileInZip(filename_inzip); + int fileSize = static_cast<int>(file_info.uncompressed_size); + /* Sanity check for the filenames as well as the file size (max 512kb) */ + if ( fileCheck && fileCheck(fileInZip, fileSize) && di.exists() ) + { + QFileInfo fi(di.path() + QDir::separator() + fileInZip); + QDir tP(fi.absolutePath()); + if ( ! tP.exists() ) + di.mkpath(fi.absolutePath()); + + if ( fileInZip.contains("/") ) + { + QString filePath = fi.absoluteFilePath(); + + err = unzOpenCurrentFile(uf); + if ( err == UNZ_OK ) + { + char * buf = static_cast<char *>(malloc(IO_BUF_SIZE)); + QFile file(filePath); + if ( file.open(QIODevice::WriteOnly) ) + { + QDataStream out(&file); + while ( ( err = unzReadCurrentFile(uf, buf, IO_BUF_SIZE) ) != UNZ_EOF ) + { + QByteArray buffer(buf, err); + out << buffer; + } + + file.close(); + } + unzCloseCurrentFile(uf); + + files++; + } + } + } + } + + if ((cnt+1) < nmbr) + { + err = unzGoToNextFile(uf); + if (err!=UNZ_OK) + { + break; + } + } + } + + unzClose(uf); + + return files > 0 ? true : false; +} + +#endif + +/* + * Editor modelines - http://www.wireshark.org/tools/modelines.html + * + * Local variables: + * c-basic-offset: 4 + * tab-width: 8 + * indent-tabs-mode: nil + * End: + * + * vi: set shiftwidth=4 tabstop=8 expandtab: + * :indentSize=4:tabSize=8:noTabs=true: + */ diff --git a/ui/qt/utils/wireshark_zip_helper.h b/ui/qt/utils/wireshark_zip_helper.h new file mode 100644 index 0000000000..8b232dc966 --- /dev/null +++ b/ui/qt/utils/wireshark_zip_helper.h @@ -0,0 +1,42 @@ +/* wireshark_zip_helper.h + * + * Definitions for zip / unzip of files + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1998 Gerald Combs + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef WS_ZIP_HELPER_H +#define WS_ZIP_HELPER_H + +#include "config.h" + +#include <QDir> + +#ifdef HAVE_MINIZIP + +class WireSharkZipHelper +{ +public: + static bool unzip(QString zipFile, QString directory, bool (*fileCheck)(QString fileName, int fileSize) ); +}; + +#endif + +#endif // WS_ZIP_HELPER_H + +/* + * Editor modelines - http://www.wireshark.org/tools/modelines.html + * + * Local variables: + * c-basic-offset: 4 + * tab-width: 8 + * indent-tabs-mode: nil + * End: + * + * vi: set shiftwidth=4 tabstop=8 expandtab: + * :indentSize=4:tabSize=8:noTabs=true: + */ |