diff --git a/plugins/channelrx/demodm17/m17demodprocessor.cpp b/plugins/channelrx/demodm17/m17demodprocessor.cpp
index c0bc4c2f4..ba264ced3 100644
--- a/plugins/channelrx/demodm17/m17demodprocessor.cpp
+++ b/plugins/channelrx/demodm17/m17demodprocessor.cpp
@@ -390,7 +390,7 @@ bool M17DemodProcessor::decode_packet(modemm17::M17FrameDecoder::packet_buffer_t
<< " Via: " << ax25.m_via
<< " Type: " << ax25.m_type
<< " PID: " << ax25.m_pid
- << " Data: " << ax25.m_dataASCII;
+ << " Data: " << QString::fromUtf8(ax25.m_data);
if (m_demodInputMessageQueue)
{
@@ -402,7 +402,7 @@ bool M17DemodProcessor::decode_packet(modemm17::M17FrameDecoder::packet_buffer_t
ax25.m_via,
ax25.m_type,
ax25.m_pid,
- ax25.m_dataASCII
+ ax25.m_data
);
msg->getPacket() = packet;
m_demodInputMessageQueue->push(msg);
diff --git a/plugins/channelrx/demodpacket/packetdemod.cpp b/plugins/channelrx/demodpacket/packetdemod.cpp
index 926700635..1e58a7c47 100644
--- a/plugins/channelrx/demodpacket/packetdemod.cpp
+++ b/plugins/channelrx/demodpacket/packetdemod.cpp
@@ -216,7 +216,7 @@ bool PacketDemod::handleMessage(const Message& cmd)
<< "\"" << ax25.m_via << "\","
<< ax25.m_type << ","
<< ax25.m_pid << ","
- << "\"" << ax25.m_dataASCII << "\","
+ << "\"" << QString::fromUtf8(ax25.m_data) << "\","
<< "\"" << ax25.m_dataHex << "\"\n";
}
else
@@ -348,7 +348,7 @@ void PacketDemod::applySettings(const PacketDemodSettings& settings, bool force)
if (newFile)
{
// Write header
- m_logStream << "Date,Time,Data,From,To,Via,Type,PID,Data ASCII,Data Hex\n";
+ m_logStream << "Date,Time,Data,From,To,Via,Type,PID,Data UTF-8,Data Hex\n";
}
}
else
diff --git a/plugins/channelrx/demodpacket/packetdemodgui.cpp b/plugins/channelrx/demodpacket/packetdemodgui.cpp
index b013e9410..26256648a 100644
--- a/plugins/channelrx/demodpacket/packetdemodgui.cpp
+++ b/plugins/channelrx/demodpacket/packetdemodgui.cpp
@@ -59,7 +59,7 @@ void PacketDemodGUI::resizeTable()
ui->packets->setItem(row, PACKET_COL_VIA, new QTableWidgetItem("123456-15-"));
ui->packets->setItem(row, PACKET_COL_TYPE, new QTableWidgetItem("Type-"));
ui->packets->setItem(row, PACKET_COL_PID, new QTableWidgetItem("PID-"));
- ui->packets->setItem(row, PACKET_COL_DATA_ASCII, new QTableWidgetItem("ABCEDGHIJKLMNOPQRSTUVWXYZ"));
+ ui->packets->setItem(row, PACKET_COL_DATA_STRING, new QTableWidgetItem("ABCEDGHIJKLMNOPQRSTUVWXYZ"));
ui->packets->setItem(row, PACKET_COL_DATA_HEX, new QTableWidgetItem("ABCEDGHIJKLMNOPQRSTUVWXYZ"));
ui->packets->resizeColumnsToContents();
ui->packets->removeRow(row);
@@ -168,7 +168,7 @@ void PacketDemodGUI::packetReceived(const QByteArray& packet, QDateTime dateTime
QTableWidgetItem *viaItem = new QTableWidgetItem();
QTableWidgetItem *typeItem = new QTableWidgetItem();
QTableWidgetItem *pidItem = new QTableWidgetItem();
- QTableWidgetItem *dataASCIIItem = new QTableWidgetItem();
+ QTableWidgetItem *dataStringItem = new QTableWidgetItem();
QTableWidgetItem *dataHexItem = new QTableWidgetItem();
ui->packets->setItem(row, PACKET_COL_DATE, dateItem);
ui->packets->setItem(row, PACKET_COL_TIME, timeItem);
@@ -177,7 +177,7 @@ void PacketDemodGUI::packetReceived(const QByteArray& packet, QDateTime dateTime
ui->packets->setItem(row, PACKET_COL_VIA, viaItem);
ui->packets->setItem(row, PACKET_COL_TYPE, typeItem);
ui->packets->setItem(row, PACKET_COL_PID, pidItem);
- ui->packets->setItem(row, PACKET_COL_DATA_ASCII, dataASCIIItem);
+ ui->packets->setItem(row, PACKET_COL_DATA_STRING, dataStringItem);
ui->packets->setItem(row, PACKET_COL_DATA_HEX, dataHexItem);
dateItem->setText(dateTime.date().toString());
timeItem->setText(dateTime.time().toString());
@@ -186,7 +186,7 @@ void PacketDemodGUI::packetReceived(const QByteArray& packet, QDateTime dateTime
viaItem->setText(ax25.m_via);
typeItem->setText(ax25.m_type);
pidItem->setText(ax25.m_pid);
- dataASCIIItem->setText(ax25.m_dataASCII);
+ dataStringItem->setText(QString::fromUtf8(ax25.m_data)); // Should possibly support different encodings here. PacketMod uses UTF8.
dataHexItem->setText(ax25.m_dataHex);
filterRow(row);
ui->packets->setSortingEnabled(true);
diff --git a/plugins/channelrx/demodpacket/packetdemodgui.h b/plugins/channelrx/demodpacket/packetdemodgui.h
index b89fd5229..b4a0c0d3c 100644
--- a/plugins/channelrx/demodpacket/packetdemodgui.h
+++ b/plugins/channelrx/demodpacket/packetdemodgui.h
@@ -116,7 +116,7 @@ private:
PACKET_COL_VIA,
PACKET_COL_TYPE,
PACKET_COL_PID,
- PACKET_COL_DATA_ASCII,
+ PACKET_COL_DATA_STRING,
PACKET_COL_DATA_HEX
};
diff --git a/plugins/channelrx/demodpacket/packetdemodgui.ui b/plugins/channelrx/demodpacket/packetdemodgui.ui
index f81552e44..126996967 100644
--- a/plugins/channelrx/demodpacket/packetdemodgui.ui
+++ b/plugins/channelrx/demodpacket/packetdemodgui.ui
@@ -736,10 +736,10 @@
- Data (ASCII)
+ Data
- Packet data as ASCII
+ Packet data as UTF-8 character string
@@ -757,9 +757,10 @@
- ButtonSwitch
- QToolButton
-
+ RollupContents
+ QWidget
+
+ 1
ValueDialZ
@@ -768,10 +769,9 @@
1
- RollupContents
- QWidget
-
- 1
+ ButtonSwitch
+ QToolButton
+
LevelMeterSignalDB
diff --git a/plugins/channelrx/demodpacket/readme.md b/plugins/channelrx/demodpacket/readme.md
index 0747558cb..57e4176a7 100644
--- a/plugins/channelrx/demodpacket/readme.md
+++ b/plugins/channelrx/demodpacket/readme.md
@@ -92,5 +92,5 @@ The received packets table displays the contents of the packets that have been r
* Via - List of addresses of repeaters the packet has passed through or directed via.
* Type - The AX.25 frame type.
* PID - Protocol Identifier.
-* Data (ASCII) - The AX.25 information field displayed as ASCII.
+* Data - The AX.25 information field displayed as UTF-8 character string.
* Data (Hex) - The AX.25 information field displayed as hexadecimal.
diff --git a/plugins/feature/aprs/aprsgui.cpp b/plugins/feature/aprs/aprsgui.cpp
index 4abcdd5b2..eea47c40b 100644
--- a/plugins/feature/aprs/aprsgui.cpp
+++ b/plugins/feature/aprs/aprsgui.cpp
@@ -408,7 +408,7 @@ bool APRSGUI::handleMessage(const Message& message)
else
{
qDebug() << "APRSGUI::handleMessage: Failed to decode as APRS";
- qDebug() << ax25.m_from << " " << ax25.m_to << " " << ax25.m_via << " " << ax25.m_type << " " << ax25.m_pid << " "<< ax25.m_dataASCII;
+ qDebug() << "From:" << ax25.m_from << "To:" << ax25.m_to << "Via:" << ax25.m_via << "Type:" << ax25.m_type << "PID:" << ax25.m_pid << "Data:" << QString::fromLatin1(ax25.m_data);
}
}
else
diff --git a/plugins/feature/aprs/aprsworker.cpp b/plugins/feature/aprs/aprsworker.cpp
index 997296b3d..2a830dd7b 100644
--- a/plugins/feature/aprs/aprsworker.cpp
+++ b/plugins/feature/aprs/aprsworker.cpp
@@ -102,23 +102,25 @@ bool APRSWorker::handleMessage(const Message& cmd)
{
MainCore::MsgPacket& report = (MainCore::MsgPacket&) cmd;
AX25Packet ax25;
- APRSPacket *aprs = new APRSPacket();
+
if (ax25.decode(report.getPacket()))
{
- // #2029 - Forward data even if we can't decode it fully
- aprs->decode(ax25);
+ APRSPacket aprs;
- if (!aprs->m_data.isEmpty())
+ // #2029 - Forward data even if we can't decode it fully
+ aprs.decode(ax25);
+
+ if (!aprs.m_data.isEmpty())
{
// See: http://www.aprs-is.net/IGateDetails.aspx for gating rules
- if (!aprs->m_via.contains("TCPIP")
- && !aprs->m_via.contains("TCPXX")
- && !aprs->m_via.contains("NOGATE")
- && !aprs->m_via.contains("RFONLY"))
+ if (!aprs.m_via.contains("TCPIP")
+ && !aprs.m_via.contains("TCPXX")
+ && !aprs.m_via.contains("NOGATE")
+ && !aprs.m_via.contains("RFONLY"))
{
- aprs->m_dateTime = report.getDateTime();
- QString igateMsg = aprs->toTNC2(m_settings.m_igateCallsign);
- send(igateMsg.toUtf8(), igateMsg.length());
+ aprs.m_dateTime = report.getDateTime();
+ QByteArray igateMsg = aprs.toTNC2(m_settings.m_igateCallsign);
+ send(igateMsg.data(), igateMsg.length());
}
}
}
@@ -210,7 +212,7 @@ void APRSWorker::recv()
if (!m_loggedIn)
{
// Log in with callsign and passcode
- QString login = QString("user %1 pass %2 vers SDRangel 6.4.0%3\r\n").arg(m_settings.m_igateCallsign).arg(m_settings.m_igatePasscode).arg(m_settings.m_igateFilter.isEmpty() ? "" : QString(" filter %1").arg(m_settings.m_igateFilter));
+ QString login = QString("user %1 pass %2 vers SDRangel 7.19.2%3\r\n").arg(m_settings.m_igateCallsign).arg(m_settings.m_igatePasscode).arg(m_settings.m_igateFilter.isEmpty() ? "" : QString(" filter %1").arg(m_settings.m_igateFilter));
send(login.toLatin1(), login.length());
m_loggedIn = true;
if (m_msgQueueToFeature)
diff --git a/sdrbase/util/aprs.cpp b/sdrbase/util/aprs.cpp
index 44d726181..51ba9bf6d 100644
--- a/sdrbase/util/aprs.cpp
+++ b/sdrbase/util/aprs.cpp
@@ -44,7 +44,7 @@ inline int charToIntAscii(QString&s, int idx)
bool APRSPacket::decode(AX25Packet packet)
{
// Check type, PID and length of packet
- if ((packet.m_type == "UI") && (packet.m_pid == "f0") && (packet.m_dataASCII.length() >= 1))
+ if ((packet.m_type == "UI") && (packet.m_pid == "f0") && (packet.m_data.length() >= 1))
{
// Check destination address
QRegularExpression re("^(AIR.*|ALL.*|AP.*|BEACON|CQ.*|GPS.*|DF.*|DGPS.*|DRILL.*|DX.*|ID.*|JAVA.*|MAIL.*|MICE.*|QST.*|QTH.*|RTCM.*|SKY.*|SPACE.*|SPC.*|SYM.*|TEL.*|TEST.*|TLM.*|WX.*|ZIP.*)");
@@ -54,7 +54,10 @@ bool APRSPacket::decode(AX25Packet packet)
m_from = packet.m_from;
m_to = packet.m_to;
m_via = packet.m_via;
- m_data = packet.m_dataASCII;
+ m_data = packet.m_data;
+
+ // UTF-8 is supported: http://aprs.org/aprs12/utf-8.txt
+ QString data = QString::fromUtf8(packet.m_data);
if (packet.m_to.startsWith("GPS") || packet.m_to.startsWith("SPC") || packet.m_to.startsWith("SYM"))
{
@@ -64,20 +67,20 @@ bool APRSPacket::decode(AX25Packet packet)
// Source address SSID can be used to specify a symbol
// First byte of information field is data type ID
- char dataType = packet.m_dataASCII[0].toLatin1();
+ char dataType = data[0].toLatin1();
int idx = 1;
switch (dataType)
{
case '!': // Position without timestamp or Ultimeter 2000 WX Station
- parsePosition(packet.m_dataASCII, idx);
+ parsePosition(data, idx);
if (m_symbolCode == '_')
- parseWeather(packet.m_dataASCII, idx, false);
+ parseWeather(data, idx, false);
else if (m_symbolCode == '@')
- parseStorm(packet.m_dataASCII, idx);
+ parseStorm(data, idx);
else
{
- parseDataExension(packet.m_dataASCII, idx);
- parseComment(packet.m_dataASCII, idx);
+ parseDataExension(data, idx);
+ parseComment(data, idx);
}
break;
case '#': // Peet Bros U-II Weather Station
@@ -85,85 +88,85 @@ bool APRSPacket::decode(AX25Packet packet)
case '%': // Agrelo DFJr / MicroFinder
break;
case ')': // Item
- parseItem(packet.m_dataASCII, idx);
- parsePosition(packet.m_dataASCII, idx);
- parseDataExension(packet.m_dataASCII, idx);
- parseComment(packet.m_dataASCII, idx);
+ parseItem(data, idx);
+ parsePosition(data, idx);
+ parseDataExension(data, idx);
+ parseComment(data, idx);
break;
case '*': // Peet Bros U-II Weather Station
break;
case '/': // Position with timestamp (no APRS messaging)
- parseTime(packet.m_dataASCII, idx);
- parsePosition(packet.m_dataASCII, idx);
+ parseTime(data, idx);
+ parsePosition(data, idx);
if (m_symbolCode == '_')
- parseWeather(packet.m_dataASCII, idx, false);
+ parseWeather(data, idx, false);
else if (m_symbolCode == '@')
- parseStorm(packet.m_dataASCII, idx);
+ parseStorm(data, idx);
else
{
- parseDataExension(packet.m_dataASCII, idx);
- parseComment(packet.m_dataASCII, idx);
+ parseDataExension(data, idx);
+ parseComment(data, idx);
}
break;
case ':': // Message
- parseMessage(packet.m_dataASCII, idx);
+ parseMessage(data, idx);
break;
case ';': // Object
- parseObject(packet.m_dataASCII, idx);
- parseTime(packet.m_dataASCII, idx);
- parsePosition(packet.m_dataASCII, idx);
+ parseObject(data, idx);
+ parseTime(data, idx);
+ parsePosition(data, idx);
if (m_symbolCode == '_')
- parseWeather(packet.m_dataASCII, idx, false);
+ parseWeather(data, idx, false);
else if (m_symbolCode == '@')
- parseStorm(packet.m_dataASCII, idx);
+ parseStorm(data, idx);
else
{
- parseDataExension(packet.m_dataASCII, idx);
- parseComment(packet.m_dataASCII, idx);
+ parseDataExension(data, idx);
+ parseComment(data, idx);
}
break;
case '<': // Station Capabilities
break;
case '=': // Position without timestamp (with APRS messaging)
- parsePosition(packet.m_dataASCII, idx);
+ parsePosition(data, idx);
if (m_symbolCode == '_')
- parseWeather(packet.m_dataASCII, idx, false);
+ parseWeather(data, idx, false);
else if (m_symbolCode == '@')
- parseStorm(packet.m_dataASCII, idx);
+ parseStorm(data, idx);
else
{
- parseDataExension(packet.m_dataASCII, idx);
- parseComment(packet.m_dataASCII, idx);
+ parseDataExension(data, idx);
+ parseComment(data, idx);
}
break;
case '>': // Status
- parseStatus(packet.m_dataASCII, idx);
+ parseStatus(data, idx);
break;
case '?': // Query
break;
case '@': // Position with timestamp (with APRS messaging)
- parseTime(packet.m_dataASCII, idx);
- parsePosition(packet.m_dataASCII, idx);
+ parseTime(data, idx);
+ parsePosition(data, idx);
if (m_symbolCode == '_')
- parseWeather(packet.m_dataASCII, idx, false);
+ parseWeather(data, idx, false);
else if (m_symbolCode == '@')
- parseStorm(packet.m_dataASCII, idx);
+ parseStorm(data, idx);
else
{
- parseDataExension(packet.m_dataASCII, idx);
- parseComment(packet.m_dataASCII, idx);
+ parseDataExension(data, idx);
+ parseComment(data, idx);
}
break;
case 'T': // Telemetry data
- parseTelemetry(packet.m_dataASCII, idx);
+ parseTelemetry(data, idx);
break;
case '_': // Weather report (without position)
- parseTimeMDHM(packet.m_dataASCII, idx);
- parseWeather(packet.m_dataASCII, idx, true);
+ parseTimeMDHM(data, idx);
+ parseWeather(data, idx, true);
break;
case '`': // Mic-E Information Field Data (current)
case '\'': // Mic-E Information Field Data (old)
- parseMicE(packet.m_dataASCII, idx, m_to);
+ parseMicE(data, idx, m_to);
break;
case '{': // User-defined APRS packet format
break;
@@ -182,10 +185,9 @@ bool APRSPacket::decode(AX25Packet packet)
qDebug() << "APRSPacket::decode: AX.25 Destination did not match known regexp " << m_to;
}
} else {
- qDebug() << "APRSPacket::decode: Invalid value in type=" << packet.m_type << " pid=" << packet.m_pid << " length of " << packet.m_dataASCII;
+ qDebug() << "APRSPacket::decode: Not ARPS: type=" << packet.m_type << " pid=" << packet.m_pid << " length=" << packet.m_data.length();
}
-
return false;
}
diff --git a/sdrbase/util/aprs.h b/sdrbase/util/aprs.h
index 22fff583a..8aaedaad6 100644
--- a/sdrbase/util/aprs.h
+++ b/sdrbase/util/aprs.h
@@ -32,7 +32,7 @@ struct SDRBASE_API APRSPacket {
QString m_from;
QString m_to;
QString m_via;
- QString m_data; // Original ASCII data
+ QByteArray m_data; // Original binary data
QDateTime m_dateTime; // Date/time of reception / decoding
@@ -244,9 +244,36 @@ struct SDRBASE_API APRSPacket {
return QString("%1,%2").arg(m_latitude).arg(m_longitude);
}
- QString toTNC2(QString igateCallsign)
+ QByteArray toTNC2(QString igateCallsign)
{
- return m_from + ">" + m_to + (m_via.isEmpty() ? "" : ("," + m_via)) + ",qAR," + igateCallsign + ":" + m_data + "\r\n";
+ QByteArray data;
+
+ data.append(m_from.toLatin1());
+ data.append('>');
+ data.append(m_to.toLatin1());
+ if (!m_via.isEmpty())
+ {
+ data.append(',');
+ data.append(m_via.toLatin1());
+ }
+ data.append(",qAR,");
+ data.append(igateCallsign.toLatin1());
+ data.append(':');
+
+ // #2028 - Protect against APRS-IS server command injection, by only sending up to first CR/LF
+ int idx = m_data.indexOf("\r\n");
+ if (idx >= 0)
+ {
+ data.append(m_data.left(idx + 2));
+ }
+ else
+ {
+ data.append(m_data);
+ data.append('\r');
+ data.append('\n');
+ }
+
+ return data;
}
// Convert a TNC2 formatted packet (as sent by APRS-IS Igates) to an AX25 byte array
diff --git a/sdrbase/util/ax25.cpp b/sdrbase/util/ax25.cpp
index 5e569bb3e..68c862378 100644
--- a/sdrbase/util/ax25.cpp
+++ b/sdrbase/util/ax25.cpp
@@ -132,7 +132,7 @@ bool AX25Packet::decode(QByteArray packet)
infoStart = i;
infoEnd = packet.size()-2-i;
QByteArray info(packet.mid(infoStart, infoEnd));
- m_dataASCII = QString::fromLatin1(info);
+ m_data = info;
m_dataHex = QString(info.toHex());
return true;
diff --git a/sdrbase/util/ax25.h b/sdrbase/util/ax25.h
index 012aebafd..d2c70c0a8 100644
--- a/sdrbase/util/ax25.h
+++ b/sdrbase/util/ax25.h
@@ -32,7 +32,7 @@ struct SDRBASE_API AX25Packet {
QString m_via;
QString m_type;
QString m_pid;
- QString m_dataASCII;
+ QByteArray m_data;
QString m_dataHex;
bool decode(QByteArray packet);