Working through QUERY MSG [id] and MSG commands to make it easier to work with the inbox

This commit is contained in:
Jordan Sherer 2019-02-01 01:46:01 -05:00
parent e0838a2164
commit da41991171
3 changed files with 188 additions and 120 deletions

View File

@ -5728,7 +5728,7 @@ void MainWindow::addMessageText(QString text, bool clear, bool selectFirstPlaceh
c.insertText(text);
if(selectFirstPlaceholder){
auto match = QRegularExpression("(\\[.+\\])").match(ui->extFreeTextMsgEdit->toPlainText());
auto match = QRegularExpression("(\\[[^\\]]+\\])").match(ui->extFreeTextMsgEdit->toPlainText());
if(match.hasMatch()){
c.setPosition(match.capturedStart());
c.setPosition(match.capturedEnd(), QTextCursor::KeepAnchor);
@ -6949,8 +6949,8 @@ void MainWindow::sendHeartbeat(){
processTxQueue();
}
void MainWindow::sendHeartbeatAck(QString to, int snr){
auto message = QString("%1 ACK %2").arg(to).arg(Varicode::formatSNR(snr));
void MainWindow::sendHeartbeatAck(QString to, int snr, QString extra){
auto message = QString("%1 ACK %2 %3").arg(to).arg(Varicode::formatSNR(snr)).arg(extra).trimmed();
auto f = m_config.heartbeat_anywhere() ? -1 : findFreeFreqOffset(500, 1000, 50);
@ -7357,7 +7357,7 @@ void MainWindow::buildQueryMenu(QMenu * menu, QString call){
});
#endif
auto alertAction = menu->addAction(QString("%1>[MESSAGE] - Please save this message or relay it to its destination").arg(call).trimmed());
auto alertAction = menu->addAction(QString("%1>[MESSAGE] - Please relay this message to its destination").arg(call).trimmed());
alertAction->setDisabled(isAllCall);
connect(alertAction, &QAction::triggered, this, [this](){
@ -7509,19 +7509,6 @@ void MainWindow::buildQueryMenu(QMenu * menu, QString call){
if(m_config.transmit_directed()) toggleTx(true);
});
auto tuAction = menu->addAction(QString("%1 TU - Thank You").arg(call).trimmed());
connect(tuAction, &QAction::triggered, this, [this](){
QString selectedCall = callsignSelected();
if(selectedCall.isEmpty()){
return;
}
addMessageText(QString("%1 TU").arg(selectedCall), true);
if(m_config.transmit_directed()) toggleTx(true);
});
auto sevenThreeAction = menu->addAction(QString("%1 73 - I send my best regards").arg(call).trimmed());
connect(sevenThreeAction, &QAction::triggered, this, [this](){
@ -9696,10 +9683,13 @@ void MainWindow::processCommandActivity() {
c.movePosition(QTextCursor::StartOfBlock);
c.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor);
qDebug() << "should display directed message, erasing last rx activity line..." << c.selectedText();
c.removeSelectedText();
c.deletePreviousChar();
c.deletePreviousChar();
/*
c.deleteChar();
c.deleteChar();
*/
}
// log it to the display!
@ -9841,14 +9831,9 @@ void MainWindow::processCommandActivity() {
// otherwise, as long as we're not an ACK...alert the user and either send an ACK or Message
} else if(!d.text.startsWith("ACK")) {
QStringList calls;
QString callDePattern = {R"(\sDE\s(?<callsign>\b(?<prefix>[A-Z0-9]{1,4}\/)?(?<base>([0-9A-Z])?([0-9A-Z])([0-9])([A-Z])?([A-Z])?([A-Z])?)(?<suffix>\/[A-Z0-9]{1,4})?)\b)"};
QRegularExpression re(callDePattern);
auto iter = re.globalMatch(text);
while(iter.hasNext()){
auto match = iter.next();
calls.prepend(match.captured("callsign"));
}
// parse out the callsign path
auto calls = parseRelayPathCallsigns(d.from, d.text);
// put these third party calls in the heard list
foreach(auto call, calls){
@ -9862,7 +9847,6 @@ void MainWindow::processCommandActivity() {
logCallActivity(cd, false);
}
calls.prepend(d.from);
d.relayPath = calls.join('>');
reply = QString("%1 ACK").arg(d.relayPath);
@ -9883,7 +9867,7 @@ void MainWindow::processCommandActivity() {
rd.bits = d.bits;
rd.cmd = first;
rd.freq = d.freq;
rd.from = d.relayPath;
rd.from = d.relayPath; // is this correct?
rd.text = d.text;
rd.to = d.to;
rd.utcTimestamp = d.utcTimestamp;
@ -9893,12 +9877,16 @@ void MainWindow::processCommandActivity() {
}
}
#if STORE_RELAY_MSGS_TO_INBOX
// if we make it here, this is a message
addCommandToMyInbox(d);
#endif
#if ALERT_ON_NEW_MSG
QTimer::singleShot(500, this, [this, d](){
MessageBox::information_message(this, QString("A new message was received at %1 UTC from %2").arg(d.utcTimestamp.time().toString()).arg(d.from));
});
#endif
}
}
@ -9943,19 +9931,69 @@ void MainWindow::processCommandActivity() {
// PROCESS ACTIVE HEARTBEAT
// if we have auto reply enabled and we are heartbeating and selcall is not enabled
else if (d.cmd == " HB" && ui->autoReplyButton->isChecked() && ui->hbMacroButton->isChecked() && m_hbInterval > 0){
sendHeartbeatAck(d.from, d.snr);
// check to see if we have a message for a station who is heartbeating
QString extra;
auto mid = getNextMessageIdForCallsign(d.from);
if(mid != -1){
extra = QString("MSG ID %1").arg(mid);
}
sendHeartbeatAck(d.from, d.snr, extra);
if(isAllCall){
// since all pings are technically @ALLCALL, let's bump the allcall cache here...
m_txAllcallCommandCache.insert(d.from, new QDateTime(now), 5);
}
continue;
}
// PROCESS MSG
else if (d.cmd == " MSG"){
auto segs = d.text.split(" ");
if(segs.isEmpty()){
continue;
}
bool ok = false;
auto mid = segs.first().toInt(&ok);
if(!ok){
continue;
}
segs.removeFirst();
if(segs.isEmpty()){
continue;
}
auto text = segs.join(" ");
qDebug() << "adding message" << mid << "to inbox" << text;
auto calls = parseRelayPathCallsigns(d.from, text);
d.cmd = " MSG ";
d.relayPath = calls.join(">");
d.text = text;
addCommandToMyInbox(d);
// make sure this is explicit
continue;
}
// PROCESS ACKS
else if (d.cmd == " ACK"){
qDebug() << "skipping incoming ack" << d.text;
// make sure this is explicit
continue;
}
// PROCESS BUFFERED CMD
else if (d.cmd == " CMD" && ui->autoReplyButton->isChecked()){
else if (d.cmd == " CMD"){
qDebug() << "skipping incoming command" << d.text;
// make sure this is explicit
@ -9963,7 +10001,7 @@ void MainWindow::processCommandActivity() {
}
// PROCESS BUFFERED QUERY
else if (d.cmd == " QUERY" && ui->autoReplyButton->isChecked()){
else if (d.cmd == " QUERY"){
auto who = d.from;
QStringList segs = d.text.split(" ");
@ -10002,7 +10040,12 @@ void MainWindow::processCommandActivity() {
continue;
}
reply = QString("%1>MSG %2 %3 DE %4");
// mark as delivered (so subsequent HBs and QUERY MSGS don't receive this message)
msg.setType("DELIVERED");
inbox.set(mid, msg);
// and reply
reply = QString("%1 MSG %2 %3 DE %4");
reply = reply.arg(who);
reply = reply.arg(mid);
reply = reply.arg(text);
@ -10014,21 +10057,11 @@ void MainWindow::processCommandActivity() {
else if (d.cmd == " QUERY MSGS" && ui->autoReplyButton->isChecked()){
auto who = d.from;
auto inbox = Inbox(inboxPath());
if(!inbox.open()){
continue;
}
// if this is an allcall or a directed call, check to see if we have a stored message for user.
// we reply yes if the user would be able to retreive a stored message
auto v = inbox.values("STORE", "$.params.TO", who, 0, 10);
foreach(auto pair, v){
auto params = pair.second.params();
auto text = params.value("TEXT").toString().trimmed();
if(!text.isEmpty()){
reply = QString("%1 YES MSG %2").arg(who).arg(pair.first);
break;
}
auto mid = getNextMessageIdForCallsign(who);
if(mid != -1){
reply = QString("%1 YES MSG ID %2").arg(who).arg(mid);
}
// if this is not an allcall and we have no messages, reply no.
@ -10193,18 +10226,21 @@ void MainWindow::refreshInboxCounts(){
}
}
void MainWindow::addCommandToMyInbox(CommandDetail d){
int MainWindow::addCommandToMyInbox(CommandDetail d){
// local cache for inbox count
m_rxInboxCountCache[d.from] = m_rxInboxCountCache.value(d.from, 0) + 1;
// add it to my unread inbox
addCommandToInboxStorage("UNREAD", d);
return addCommandToInboxStorage("UNREAD", d);
}
void MainWindow::addCommandToInboxStorage(QString type, CommandDetail d){
int MainWindow::addCommandToInboxStorage(QString type, CommandDetail d){
// inbox:
auto inbox = Inbox(inboxPath());
if(inbox.open()){
if(!inbox.open()){
return -1;
}
auto df = dialFrequency();
QMap<QString, QVariant> v = {
@ -10232,8 +10268,39 @@ void MainWindow::addCommandToInboxStorage(QString type, CommandDetail d){
}
auto m = Message(type, "", v);
inbox.append(m);
return inbox.append(m);
}
int MainWindow::getNextMessageIdForCallsign(QString callsign){
auto inbox = Inbox(inboxPath());
if(!inbox.open()){
return -1;
}
auto v = inbox.values("STORE", "$.params.TO", callsign, 0, 10);
foreach(auto pair, v){
auto params = pair.second.params();
auto text = params.value("TEXT").toString().trimmed();
if(!text.isEmpty()){
return pair.first;
}
}
return -1;
}
QStringList MainWindow::parseRelayPathCallsigns(QString from, QString text){
QStringList calls;
QString callDePattern = {R"(\sDE\s(?<callsign>\b(?<prefix>[A-Z0-9]{1,4}\/)?(?<base>([0-9A-Z])?([0-9A-Z])([0-9])([A-Z])?([A-Z])?([A-Z])?)(?<suffix>\/[A-Z0-9]{1,4})?)\b)"};
QRegularExpression re(callDePattern);
auto iter = re.globalMatch(text);
while(iter.hasNext()){
auto match = iter.next();
calls.prepend(match.captured("callsign"));
}
calls.prepend(from);
return calls;
}
void MainWindow::processAlertReplyForCommand(CommandDetail d, QString from, QString cmd){

View File

@ -284,7 +284,7 @@ private slots:
void buildCQMenu(QMenu *menu);
void buildRepeatMenu(QMenu *menu, QPushButton * button, int * interval);
void sendHeartbeat();
void sendHeartbeatAck(QString to, int snr);
void sendHeartbeatAck(QString to, int snr, QString extra);
void on_hbMacroButton_toggled(bool checked);
void on_hbMacroButton_clicked();
void sendCQ(bool repeat=false);
@ -952,8 +952,10 @@ private:
void processCommandActivity();
QString inboxPath();
void refreshInboxCounts();
void addCommandToMyInbox(CommandDetail d);
void addCommandToInboxStorage(QString type, CommandDetail d);
int addCommandToMyInbox(CommandDetail d);
int addCommandToInboxStorage(QString type, CommandDetail d);
int getNextMessageIdForCallsign(QString callsign);
QStringList parseRelayPathCallsigns(QString from, QString text);
void processAlertReplyForCommand(CommandDetail d, QString from, QString cmd);
void processSpots();
void processTxQueue();

View File

@ -45,12 +45,12 @@ QString alphanumeric = {"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ /@"}; // callsign
QMap<QString, int> directed_cmds = {
// any changes here need to be made also in the directed regular xpression for parsing
// ?*^&@
{" HB", -1 }, // this is my heartbeat (unused except for faux processing of HBs as directed commands)
{" SNR?", 0 }, // query snr
{"?", 0 }, // compat
{" QTH?", 1 }, // query qth
//{" ", 1 }, // unused
//{" ", 2 }, // unused
{" HEARING?", 3 }, // query station calls heard
@ -65,9 +65,7 @@ QMap<QString, int> directed_cmds = {
{" HEARING", 8 }, // these are the stations i'm hearing
{" TU", 9 }, // thank you
{" HB", -1 }, // this is my heartbeat (unused except for faux processing of HBs as directed commands)
{" MSG", 9 }, // this is a complete message
{" MSG TO:", 10 }, // store message at a station
@ -81,18 +79,18 @@ QMap<QString, int> directed_cmds = {
{" GRID", 15 }, // this is my current grid locator
//{" ", 16 }, // unused
{" QTH?", 16 }, // what is your qth message?
{" QTH", 17 }, // this is my qth message
{" FB", 18 }, // fine business
{" HW CPY?", 19 }, // how do you copy?
{" SK", 20 }, // end of contact
{" RR", 21 }, // roger roger
{" QSL?", 22 }, // do you copy?
{" QSL", 23 }, // i copy
{" CMD", 24 }, // open ended command
{" CMD", 24 }, // command
{" SNR", 25 }, // seen a station at the provided snr
{" NO", 26 }, // negative confirm
@ -105,13 +103,13 @@ QMap<QString, int> directed_cmds = {
};
// commands allowed to be processed
QSet<int> allowed_cmds = {-1, 0, 1, /*2,*/ 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /*16,*/ 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
QSet<int> allowed_cmds = {-1, 0, /*1,*/ /*2,*/ 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
// commands that result in an autoreply (which can be relayed)
QSet<int> autoreply_cmds = {0, 1, 3, 4, 6, 10, 11, 12, 13, 30};
QSet<int> autoreply_cmds = {0, 3, 4, 6, 9, 11, 12, 13, 16, 30};
// commands that should be buffered
QSet<int> buffered_cmds = {3, 5, /*6,*/ /*7,*/ 10, 11, 12, 13, 14, 15, 24};
QSet<int> buffered_cmds = {5, /*6,*/ /*7,*/ 9, 10, 11, 12, 13, 14, 15, 24};
// commands that may include an SNR value
QSet<int> snr_cmds = {25, 29};
@ -119,6 +117,7 @@ QSet<int> snr_cmds = {25, 29};
// commands that are checksummed and their crc size
QMap<int, int> checksum_cmds = {
{ 5, 16 },
{ 9, 16 },
{ 10, 16 },
{ 11, 16 },
{ 12, 16 },
@ -129,7 +128,7 @@ QMap<int, int> checksum_cmds = {
};
QString callsign_pattern = QString("(?<callsign>[@]?[A-Z0-9/]+)");
QString optional_cmd_pattern = QString("(?<cmd>\\s?(?:AGN[?]|QSL[?]|HW CPY[?]|APRS[:]|MSG TO[:]|SNR[?]|QTH[?]|GRID[?]|STATUS[?]|HEARING[?]|(?:(?:STATUS|HEARING|QUERY CALL|QUERY MSGS|QUERY|CMD|ACK|73|YES|NO|SNR|QSL|RR|SK|FB|QTH|GRID|TU)(?=[ ]|$))|[?> ]))?");
QString optional_cmd_pattern = QString("(?<cmd>\\s?(?:AGN[?]|QSL[?]|HW CPY[?]|APRS[:]|MSG TO[:]|SNR[?]|QTH[?]|GRID[?]|STATUS[?]|HEARING[?]|(?:(?:STATUS|HEARING|QUERY CALL|QUERY MSGS|QUERY|CMD|MSG|ACK|73|YES|NO|SNR|QSL|RR|SK|FB|QTH|GRID)(?=[ ]|$))|[?> ]))?");
QString optional_grid_pattern = QString("(?<grid>\\s?[A-R]{2}[0-9]{2})?");
QString optional_extended_grid_pattern = QString("^(?<grid>\\s?(?:[A-R]{2}[0-9]{2}(?:[A-X]{2}(?:[0-9]{2})?)*))?");
QString optional_num_pattern = QString("(?<num>(?<=SNR|ACK)\\s?[-+]?(?:3[01]|[0-2]?[0-9]))?");