Skip to content

Commit 384e9a8

Browse files
committed
feat: add TCP stream import/export plugin
The plugin was tested with GNU radio, so #27 might be handled by this
1 parent fe0760c commit 384e9a8

14 files changed

+748
-6
lines changed

src/hobbits-gui/mainwindow.cpp

+77-3
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ MainWindow::MainWindow(QString extraPluginPath, QString configFilePath, QWidget
148148

149149
// Import menu initialization
150150
populateRecentImportsMenu();
151+
populateRecentExportsMenu();
151152

152153
// create an initial state
153154
checkOperatorInput();
@@ -720,7 +721,7 @@ void MainWindow::requestImportRun(QString pluginName, QJsonObject pluginState)
720721
if (result.isNull()) {
721722
return;
722723
}
723-
if (!result->getPluginState().isEmpty()) {
724+
if (!result->getPluginState().isEmpty() && !result->getPluginState().contains("error")) {
724725
this->populateRecentImportsMenu({plugin->getName(), result->getPluginState()});
725726
}
726727
if (!result->getContainer().isNull()) {
@@ -737,7 +738,10 @@ void MainWindow::requestExportRun(QString pluginName, QJsonObject pluginState)
737738
warningMessage("Cannot export without a selected bit container");
738739
}
739740
QSharedPointer<ImportExportInterface> plugin = m_pluginManager->getImporterExporter(pluginName);
740-
plugin->exportBits(currContainer(), pluginState, this);
741+
auto result = plugin->exportBits(currContainer(), pluginState, this);
742+
if (!result->getPluginState().isEmpty() && !result->getPluginState().contains("error")) {
743+
this->populateRecentExportsMenu({plugin->getName(), result->getPluginState()});
744+
}
741745
}
742746

743747
void MainWindow::on_pb_analyze_clicked()
@@ -1116,6 +1120,7 @@ void MainWindow::populateRecentImportsMenu(QPair<QString, QJsonObject> addition,
11161120

11171121
SettingsManager::getInstance().setPrivateSetting(key, recentlyImported);
11181122

1123+
int invalidStateCount = 0;
11191124
ui->menuImport_Recent->clear();
11201125
for (QString importString : recentlyImported) {
11211126
QStringList importParts = importString.split(separator);
@@ -1133,6 +1138,7 @@ void MainWindow::populateRecentImportsMenu(QPair<QString, QJsonObject> addition,
11331138

11341139
QString menuLabel = plugin->getImportLabelForState(pluginState);
11351140
if (menuLabel.isEmpty()) {
1141+
invalidStateCount++;
11361142
continue;
11371143
}
11381144
ui->menuImport_Recent->addAction(
@@ -1142,7 +1148,75 @@ void MainWindow::populateRecentImportsMenu(QPair<QString, QJsonObject> addition,
11421148
});
11431149
}
11441150

1145-
ui->menuImport_Recent->setEnabled(recentlyImported.length() > 0);
1151+
ui->menuImport_Recent->setEnabled(recentlyImported.length() - invalidStateCount > 0);
1152+
}
1153+
1154+
void MainWindow::populateRecentExportsMenu(QPair<QString, QJsonObject> addition, QPair<QString, QJsonObject> removal)
1155+
{
1156+
QString key = "recently_exported";
1157+
QString separator = "/[]\"[]/";
1158+
1159+
QString additionString;
1160+
if (!addition.first.isEmpty() && !addition.second.isEmpty()) {
1161+
QJsonDocument doc(addition.second);
1162+
QString additionJson(doc.toJson(QJsonDocument::Compact));
1163+
additionString = QString("%1%2%3").arg(addition.first).arg(separator).arg(additionJson);
1164+
}
1165+
QString removalString;
1166+
if (!removal.first.isEmpty() && !removal.second.isEmpty()) {
1167+
QJsonDocument doc(removal.second);
1168+
QString removalJson(doc.toJson(QJsonDocument::Compact));
1169+
removalString = QString("%1%2%3").arg(removal.first).arg(separator).arg(removalJson);
1170+
}
1171+
1172+
QStringList recentlyExported;
1173+
QVariant currentSetting = SettingsManager::getInstance().getPrivateSetting(key);
1174+
if (!currentSetting.isNull() && currentSetting.canConvert<QStringList>()) {
1175+
recentlyExported = currentSetting.toStringList();
1176+
}
1177+
1178+
if (!removalString.isEmpty()) {
1179+
recentlyExported.removeAll(removalString);
1180+
}
1181+
1182+
if (!additionString.isEmpty()) {
1183+
recentlyExported.removeAll(additionString);
1184+
recentlyExported.insert(0, additionString);
1185+
}
1186+
1187+
recentlyExported = recentlyExported.mid(0, 10);
1188+
1189+
SettingsManager::getInstance().setPrivateSetting(key, recentlyExported);
1190+
1191+
int invalidStateCount = 0;
1192+
ui->menuExport_Recent->clear();
1193+
for (QString importString : recentlyExported) {
1194+
QStringList importParts = importString.split(separator);
1195+
if (importParts.size() != 2) {
1196+
continue;
1197+
}
1198+
QString pluginName = importParts.at(0);
1199+
QSharedPointer<ImportExportInterface> plugin = m_pluginManager->getImporterExporter(pluginName);
1200+
if (plugin.isNull()) {
1201+
continue;
1202+
}
1203+
1204+
QByteArray pluginStateString = importParts.at(1).toUtf8();
1205+
QJsonObject pluginState = QJsonDocument::fromJson(pluginStateString).object();
1206+
1207+
QString menuLabel = plugin->getExportLabelForState(pluginState);
1208+
if (menuLabel.isEmpty()) {
1209+
invalidStateCount++;
1210+
continue;
1211+
}
1212+
ui->menuExport_Recent->addAction(
1213+
menuLabel,
1214+
[this, pluginName, pluginState]() {
1215+
this->requestExportRun(pluginName, pluginState);
1216+
});
1217+
}
1218+
1219+
ui->menuExport_Recent->setEnabled(recentlyExported.length() - invalidStateCount > 0);
11461220
}
11471221

11481222
void MainWindow::on_tb_scrollReset_clicked()

src/hobbits-gui/mainwindow.h

+1
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ private slots:
8383
void removeDisplayGroup(int idx);
8484
void initializeImporterExporters();
8585

86+
void populateRecentExportsMenu(QPair<QString, QJsonObject> addition = QPair<QString, QJsonObject>(), QPair<QString, QJsonObject> removal = QPair<QString, QJsonObject>());
8687
void populateRecentImportsMenu(QPair<QString, QJsonObject> addition = QPair<QString, QJsonObject>(), QPair<QString, QJsonObject> removal = QPair<QString, QJsonObject>());
8788
void populateRecentTemplatesMenu(QString addition = QString(), QString removal = QString());
8889

src/hobbits-gui/mainwindow.ui

+15-1
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,7 @@
288288
<x>0</x>
289289
<y>0</y>
290290
<width>1286</width>
291-
<height>27</height>
291+
<height>29</height>
292292
</rect>
293293
</property>
294294
<widget class="QMenu" name="menuFile">
@@ -323,11 +323,20 @@
323323
<string>Import Recent</string>
324324
</property>
325325
</widget>
326+
<widget class="QMenu" name="menuExport_Recent">
327+
<property name="enabled">
328+
<bool>false</bool>
329+
</property>
330+
<property name="title">
331+
<string>Export Recent</string>
332+
</property>
333+
</widget>
326334
<addaction name="action_Save_Current_Container"/>
327335
<addaction name="actionOpen_Container"/>
328336
<addaction name="separator"/>
329337
<addaction name="menuImport_Recent"/>
330338
<addaction name="menu_Import_Bits_From"/>
339+
<addaction name="menuExport_Recent"/>
331340
<addaction name="menu_Export_Bits_To"/>
332341
<addaction name="separator"/>
333342
<addaction name="menuApply_Recent_Template"/>
@@ -441,6 +450,11 @@
441450
<string>a</string>
442451
</property>
443452
</action>
453+
<action name="actiona_2">
454+
<property name="text">
455+
<string>a</string>
456+
</property>
457+
</action>
444458
</widget>
445459
<layoutdefault spacing="6" margin="11"/>
446460
<tabstops>

src/hobbits-plugins/importerexporters/HttpData/httptransceiver.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ HttpTransceiver::HttpTransceiver(QWidget *parent) :
88
QDialog(parent),
99
ui(new Ui::HttpTransceiver),
1010
m_netManager(new QNetworkAccessManager(this)),
11-
m_downloadFile(new QTemporaryFile),
11+
m_downloadFile(new QTemporaryFile(this)),
1212
m_reply(nullptr)
1313
{
1414
ui->setupUi(this);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
#-------------------------------------------------
2+
#
3+
# Project created by QtCreator 2020-04-10T16:34:57.900Z
4+
#
5+
#-------------------------------------------------
6+
7+
QT += widgets network
8+
9+
QT -= gui
10+
11+
TARGET = TcpData
12+
TEMPLATE = lib
13+
14+
DEFINES += TCPDATA_LIBRARY
15+
16+
CONFIG += c++11 plugin
17+
CONFIG -= debug_and_release_target
18+
19+
# The following define makes your compiler emit warnings if you use
20+
# any feature of Qt which has been marked as deprecated (the exact warnings
21+
# depend on your compiler). Please consult the documentation of the
22+
# deprecated API in order to know how to port your code away from it.
23+
DEFINES += QT_DEPRECATED_WARNINGS
24+
25+
# You can also make your code fail to compile if you use deprecated APIs.
26+
# In order to do so, uncomment the following line.
27+
# You can also select to disable deprecated APIs only up to a certain version of Qt.
28+
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
29+
30+
SOURCES += tcpdata.cpp \
31+
tcpreceiver.cpp \
32+
tcpsender.cpp
33+
34+
HEADERS += tcpdata.h \
35+
tcpreceiver.h \
36+
tcpsender.h
37+
38+
39+
LIBS += -L$$OUT_PWD/../../../hobbits-core/ -lhobbits-core
40+
41+
INCLUDEPATH += $$PWD/../../../hobbits-core
42+
DEPENDPATH += $$PWD/../../../hobbits-core
43+
44+
unix:{
45+
QMAKE_LFLAGS_RPATH=
46+
QMAKE_LFLAGS += "-Wl,-rpath,'$$ORIGIN/../../lib:$$ORIGIN'"
47+
}
48+
49+
unix {
50+
target.path = target.path = $$(HOME)/.local/share/hobbits/plugins/analyzers
51+
INSTALLS += target
52+
}
53+
54+
FORMS += \
55+
tcpreceiver.ui \
56+
tcpsender.ui
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
#include "tcpdata.h"
2+
#include "tcpreceiver.h"
3+
#include "tcpsender.h"
4+
5+
TcpData::TcpData()
6+
{
7+
8+
}
9+
10+
TcpData::~TcpData()
11+
{
12+
}
13+
14+
ImportExportInterface* TcpData::createDefaultImporterExporter()
15+
{
16+
return new TcpData();
17+
}
18+
19+
QString TcpData::getName()
20+
{
21+
return "TCP Data";
22+
}
23+
24+
bool TcpData::canExport()
25+
{
26+
return true;
27+
}
28+
29+
bool TcpData::canImport()
30+
{
31+
return true;
32+
}
33+
34+
QString TcpData::getImportLabelForState(QJsonObject pluginState)
35+
{
36+
if (pluginState.contains("port") && pluginState.value("port").isDouble()) {
37+
return QString("TCP Listen on port %1").arg(pluginState.value("port").toInt());
38+
}
39+
return "";
40+
}
41+
42+
QString TcpData::getExportLabelForState(QJsonObject pluginState)
43+
{
44+
if (pluginState.contains("port") && pluginState.value("port").isDouble()
45+
&& pluginState.contains("host") && pluginState.value("host").isString()) {
46+
return QString("TCP Export to %1 on port %2").arg(pluginState.value("host").toString()).arg(pluginState.value("port").toInt());
47+
}
48+
return "";
49+
}
50+
51+
QSharedPointer<ImportExportResult> TcpData::importBits(QJsonObject pluginState, QWidget *parent)
52+
{
53+
QSharedPointer<TcpReceiver> receiver = QSharedPointer<TcpReceiver>(new TcpReceiver(parent));
54+
if (pluginState.contains("port") && pluginState.value("port").isDouble()) {
55+
receiver->setPort(pluginState.value("port").toInt());
56+
receiver->startListening();
57+
}
58+
59+
if (receiver->exec()) {
60+
QSharedPointer<BitContainer> container = QSharedPointer<BitContainer>(new BitContainer());
61+
container->setBits(receiver->getDownloadedData());
62+
container->setName("TCP Import");
63+
QJsonObject state;
64+
state.insert("port", receiver->getPort());
65+
return ImportExportResult::create(container, state);
66+
}
67+
else {
68+
return ImportExportResult::error(receiver->getError());
69+
}
70+
}
71+
72+
QSharedPointer<ImportExportResult> TcpData::exportBits(
73+
QSharedPointer<const BitContainer> container,
74+
QJsonObject pluginState,
75+
QWidget *parent)
76+
{
77+
QSharedPointer<TcpSender> sender = QSharedPointer<TcpSender>(new TcpSender(container->bits(), parent));
78+
if (pluginState.contains("port") && pluginState.value("port").isDouble()
79+
&& pluginState.contains("host") && pluginState.value("host").isString()) {
80+
sender->setPort(pluginState.value("port").toInt());
81+
sender->setHost(pluginState.value("host").toString());
82+
sender->sendData();
83+
}
84+
85+
if (sender->exec()) {
86+
QJsonObject state;
87+
state.insert("port", sender->getPort());
88+
state.insert("host", sender->getHost());
89+
return ImportExportResult::create(state);
90+
}
91+
else {
92+
return ImportExportResult::error("Failed to export bits over TCP");
93+
}
94+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#ifndef TCPDATA_H
2+
#define TCPDATA_H
3+
4+
#include "importexportinterface.h"
5+
6+
class TcpData : public QObject, ImportExportInterface
7+
{
8+
Q_OBJECT
9+
Q_PLUGIN_METADATA(IID "hobbits.ImportExportInterface.TcpData")
10+
Q_INTERFACES(ImportExportInterface)
11+
12+
public:
13+
TcpData();
14+
~TcpData();
15+
16+
ImportExportInterface* createDefaultImporterExporter() override;
17+
18+
QString getName() override;
19+
20+
bool canExport() override;
21+
bool canImport() override;
22+
23+
QString getImportLabelForState(QJsonObject pluginState) override;
24+
QString getExportLabelForState(QJsonObject pluginState) override;
25+
26+
QSharedPointer<ImportExportResult> importBits(QJsonObject pluginState, QWidget *parent) override;
27+
QSharedPointer<ImportExportResult> exportBits(
28+
QSharedPointer<const BitContainer> container,
29+
QJsonObject pluginState,
30+
QWidget *parent) override;
31+
32+
private:
33+
};
34+
35+
#endif // TCPDATA_H

0 commit comments

Comments
 (0)