diff --git a/Configuration.cpp b/Configuration.cpp index d11584ce6..27538f734 100644 --- a/Configuration.cpp +++ b/Configuration.cpp @@ -193,6 +193,7 @@ #include "models/FrequencyList.hpp" #include "models/StationList.hpp" #include "Network/NetworkServerLookup.hpp" +#include "Network/FoxVerifier.hpp" #include "widgets/MessageBox.hpp" #include "validators/MaidenheadLocatorValidator.hpp" #include "validators/CallsignValidator.hpp" @@ -596,6 +597,8 @@ private: Q_SLOT void on_rbARRL_Digi_clicked (bool); Q_SLOT void on_cbSuperFox_clicked (bool); Q_SLOT void on_cbContestName_clicked (bool); + Q_SLOT void on_cbOTP_clicked (bool); + void error_during_hamlib_download (QString const& reason); void after_hamlib_downloaded(); void display_file_information(); @@ -608,6 +611,8 @@ private: Q_SLOT void on_Field_Day_Exchange_textEdited (QString const&); Q_SLOT void on_RTTY_Exchange_textEdited (QString const&); Q_SLOT void on_FoxKey_textEdited (QString const&); + Q_SLOT void on_OTPUrl_textEdited (QString const&); + Q_SLOT void on_OTPSeed_textEdited (QString const&); Q_SLOT void on_Contest_Name_textEdited (QString const&); // typenames used as arguments must match registered type names :( @@ -708,6 +713,11 @@ private: QString hamlib_backed_up_; QString FoxKey_; + QString OTPUrl_; + QString OTPSeed_; + bool OTPEnabled_; + qint32 OTPinterval_; + qint32 id_interval_; qint32 ntrials_; qint32 aggressive_; @@ -978,6 +988,26 @@ void Configuration::invalidate_audio_output_device (QString /* error */) m_->audio_output_device_ = QAudioDeviceInfo {}; } +// OTP seed can be empty, in which case it is not used, or a valid 16 character base32 string. +bool Configuration::validate_otp_seed(QString seed) +{ + if (seed.isEmpty()) + { + return true; + } + if (seed.size() != 16) + { + return false; + } + for (QChar c: seed) + { + if (!QString(BASE32_CHARSET).contains(c)) + { + return false; + } + } + return true; +} bool Configuration::valid_n1mm_info () const { // do very rudimentary checking on the n1mm server name and port number. @@ -1084,6 +1114,26 @@ void Configuration::toggle_SF() m_->write_settings(); } +QString Configuration::OTPSeed() const +{ + return m_->OTPSeed_; +} + +QString Configuration::OTPUrl() const +{ + return m_->OTPUrl_; +} + +u_int Configuration::OTPinterval() const +{ + return m_->OTPinterval_; +} + +bool Configuration::OTPEnabled() const +{ + return m_->OTPSeed_.size() == 16 && m_->OTPEnabled_; +} + namespace { #if defined (Q_OS_MAC) @@ -1254,6 +1304,8 @@ Configuration::impl::impl (Configuration * self, QNetworkAccessManager * network ui_->add_macro_line_edit->setValidator (new QRegularExpressionValidator {message_alphabet, this}); ui_->Field_Day_Exchange->setValidator (new QRegularExpressionValidator {field_day_exchange_re, this}); ui_->RTTY_Exchange->setValidator (new QRegularExpressionValidator {RTTY_roundup_exchange_re, this}); + QRegularExpression b32(QString("(^[") + QString(BASE32_CHARSET)+QString(BASE32_CHARSET).toLower() + QString("]{16}$)|(^$)")); + ui_->OTPSeed->setValidator(new QRegularExpressionValidator(b32, this)); // // assign ids to radio buttons @@ -1619,6 +1671,16 @@ void Configuration::impl::read_settings () ui_->Contest_Name->setText(Contest_Name_); hamlib_backed_up_ = settings_->value ("HamlibBackedUp",QString {}).toString (); + OTPinterval_ = settings_->value ("OTPinterval", 3).toUInt (); + OTPUrl_ = settings_->value ("OTPUrl", FoxVerifier::default_url()).toString (); + OTPSeed_ = settings_->value ("OTPSeed", QString {}).toString (); + OTPEnabled_ = settings_->value ("OTPEnabled", false).toBool (); + + ui_->sbOTPinterval->setValue(OTPinterval_); + ui_->OTPUrl->setText(OTPUrl_); + ui_->OTPSeed->setText(OTPSeed_); + ui_->cbOTP->setChecked(OTPEnabled_); + if (next_font_.fromString (settings_->value ("Font", QGuiApplication::font ().toString ()).toString ()) && next_font_ != font_) { @@ -1945,6 +2007,10 @@ void Configuration::impl::write_settings () settings_->setValue ("AutoGrid", use_dynamic_grid_); settings_->setValue ("highlight_DXcall", highlight_DXcall_); settings_->setValue ("highlight_DXgrid", highlight_DXgrid_); + settings_->setValue ("OTPinterval", OTPinterval_); + settings_->setValue ("OTPUrl", OTPUrl_); + settings_->setValue ("OTPSeed", OTPSeed_); + settings_->setValue ("OTPEnabled", OTPEnabled_); settings_->sync (); } @@ -2362,6 +2428,10 @@ void Configuration::impl::accept () pwrBandTxMemory_ = ui_->checkBoxPwrBandTxMemory->isChecked (); pwrBandTuneMemory_ = ui_->checkBoxPwrBandTuneMemory->isChecked (); opCall_=ui_->opCallEntry->text(); + OTPinterval_=ui_->sbOTPinterval->value(); + OTPSeed_=ui_->OTPSeed->text(); + OTPUrl_=ui_->OTPUrl->text(); + OTPEnabled_=ui_->cbOTP->isChecked(); auto new_server = ui_->udp_server_line_edit->text ().trimmed (); auto new_interfaces = get_selected_network_interfaces (ui_->udp_interfaces_combo_box); @@ -3211,6 +3281,11 @@ void Configuration::impl::on_cbContestName_clicked (bool) check_visibility (); } +void Configuration::impl::on_cbOTP_clicked(bool) +{ + check_visibility(); +} + void Configuration::impl::check_visibility () { if (ui_->rbFox->isChecked() and ui_->cbSuperFox->isChecked() and ui_->gbSpecialOpActivity->isChecked()) { @@ -3253,6 +3328,53 @@ void Configuration::impl::check_visibility () } else { ui_->cbContestName->setEnabled (false); } + if (!ui_->cbOTP->isChecked() or !ui_->gbSpecialOpActivity->isChecked()) + { + ui_->OTPSeed->setEnabled(false); + ui_->OTPUrl->setEnabled(false); + ui_->sbOTPinterval->setEnabled(false); + ui_->lblOTPSeed->setEnabled(false); + ui_->lblOTPUrl->setEnabled(false); + ui_->lblOTPEvery->setEnabled(false); + } else + { + if (ui_->rbHound->isChecked()) + { + if (ui_->OTPUrl->text().isEmpty()) + { + ui_->OTPUrl->setText(FoxVerifier::default_url()); + } + ui_->OTPUrl->setEnabled(true); + ui_->lblOTPUrl->setEnabled(true); + } else + { + ui_->OTPUrl->setEnabled(false); + ui_->lblOTPUrl->setEnabled(false); + } + if (ui_->rbFox->isChecked()) + { + ui_->sbOTPinterval->setEnabled(true); + ui_->OTPSeed->setEnabled(true); + ui_->lblOTPSeed->setEnabled(true); + ui_->lblOTPEvery->setEnabled(true); + } else + { + ui_->OTPSeed->setEnabled(false); + ui_->lblOTPSeed->setEnabled(false); + ui_->lblOTPEvery->setEnabled(false); + ui_->sbOTPinterval->setEnabled(false); + } + } +} +void Configuration::impl::on_OTPUrl_textEdited (QString const& url){ + auto text = url; + if (text.size() == 0) + { + ui_->OTPUrl->setText(FoxVerifier::default_url()); + } +} +void Configuration::impl::on_OTPSeed_textEdited (QString const& url){ + ui_->OTPSeed->setText(url.toUpper()); } void Configuration::impl::on_Field_Day_Exchange_textEdited (QString const& exchange) diff --git a/Configuration.hpp b/Configuration.hpp index c965d5e12..87281b310 100644 --- a/Configuration.hpp +++ b/Configuration.hpp @@ -9,6 +9,7 @@ #include "models/IARURegions.hpp" #include "Audio/AudioDevice.hpp" #include "Transceiver/Transceiver.hpp" +#include "foxotpcode.h" #include "pimpl_h.hpp" @@ -193,7 +194,11 @@ public: bool highlight_DXcall () const; bool highlight_DXgrid () const; bool Individual_Contest_Name() const; - + bool validate_otp_seed(QString); + QString OTPSeed() const; + QString OTPUrl() const; + bool OTPEnabled() const; + u_int OTPinterval() const; // 0 1 2 3 4 5 6 7 8 9 enum class SpecialOperatingActivity {NONE, NA_VHF, EU_VHF, FIELD_DAY, RTTY, WW_DIGI, FOX, HOUND, ARRL_DIGI, Q65_PILEUP}; SpecialOperatingActivity special_op_id () const; diff --git a/Configuration.ui b/Configuration.ui index 307d843ea..dfb598288 100644 --- a/Configuration.ui +++ b/Configuration.ui @@ -2907,30 +2907,8 @@ Right click for insert and delete options. false - - - - - - 0 - 18 - - - - <html><head/><body><p>World-Wide Digi-mode contest</p><p><br/></p></body></html> - - - WW Digital Contest - - - WW Digi Contest - - - special_op_activity_button_group - - - - + + @@ -2999,7 +2977,293 @@ Right click for insert and delete options. - + + + + <html><head/><body><p>URL used to verify OTP codes.</p></body></html> + + + + + + + + + + <html><head/><body><p>Click to enable OTP method of Fox verification. Requires internet.</p></body></html> + + + + + + OTP + + + + + + + <html><head/><body><p>FT8 DXpedition mode: Fox (DXpedition) operator.</p></body></html> + + + Fox + + + Fox + + + false + + + special_op_activity_button_group + + + + + + + + + OTP every + + + + + + + <html><head/><body><p>How many cycles between sends of the OTP.</p></body></html> + + + + + + 1 + + + 20 + + + 3 + + + + + + + OTP Key + + + + + + + <html><head/><body><p>Fox's key to generate OTP Codes.</p></body></html> + + + + + + + + + + + + + 0 + 18 + + + + <html><head/><body><p>Exchange 4-character locator instead of signal report. Provides q3-level sensitivities for the DX operator. Especially useful for 6m EME DXpeditions.</p></body></html> + + + Q65 Pileup + + + special_op_activity_button_group + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 18 + + + + <html><head/><body><p>World-Wide Digi-mode contest</p><p><br/></p></body></html> + + + WW Digital Contest + + + WW Digi Contest + + + special_op_activity_button_group + + + + + + + + 0 + 0 + + + + <html><head/><body><p>North American VHF/UHF/Microwave contests and others in which a 4-character grid locator is the required exchange.</p></body></html> + + + NA VHF Contest + + + NA VHF + + + special_op_activity_button_group + + + + + + + + + <html><head/><body><p>Call CQ with an individual contest name instead of TEST, RU, or WW. </p></body></html> + + + CQ with individual contest name + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Contest name: + + + + + + + + 70 + 16777215 + + + + + + + 4 + + + 0 + + + Qt::AlignCenter + + + + + + + + + + + + 0 + 0 + + + + <html><head/><body><p>European VHF+ contests requiring a signal report, serial number, and 6-character locator.</p></body></html> + + + EU VHF Contest + + + EU VHF Contest + + + special_op_activity_button_group + + + + + + + OTP URL + + + + + + + <html><head/><body><p>FT8 DXpedition mode: Hound operator calling the DX.</p></body></html> + + + Hound + + + Hound + + + true + + + special_op_activity_button_group + + + + + + + <html><head/><body><p>ARRL International Digital Contest</p></body></html> + + + ARRL Digi Contest + + + special_op_activity_button_group + + + + @@ -3064,124 +3328,7 @@ Right click for insert and delete options. - - - - - - <html><head/><body><p>Call CQ with an individual contest name instead of TEST, RU, or WW. </p></body></html> - - - CQ with individual contest name - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - Contest name: - - - - - - - - 70 - 16777215 - - - - - - - 4 - - - 0 - - - Qt::AlignCenter - - - - - - - - - - - - 0 - 0 - - - - <html><head/><body><p>North American VHF/UHF/Microwave contests and others in which a 4-character grid locator is the required exchange.</p></body></html> - - - NA VHF Contest - - - NA VHF - - - special_op_activity_button_group - - - - - - - - 0 - 0 - - - - <html><head/><body><p>European VHF+ contests requiring a signal report, serial number, and 6-character locator.</p></body></html> - - - EU VHF Contest - - - EU VHF Contest - - - special_op_activity_button_group - - - - - - - <html><head/><body><p>ARRL International Digital Contest</p></body></html> - - - ARRL Digi Contest - - - special_op_activity_button_group - - - - + @@ -3250,76 +3397,6 @@ Right click for insert and delete options. - - - - - 0 - 18 - - - - <html><head/><body><p>Exchange 4-character locator instead of signal report. Provides q3-level sensitivities for the DX operator. Especially useful for 6m EME DXpeditions.</p></body></html> - - - Q65 Pileup - - - special_op_activity_button_group - - - - - - - <html><head/><body><p>FT8 DXpedition mode: Hound operator calling the DX.</p></body></html> - - - Hound - - - Hound - - - true - - - special_op_activity_button_group - - - - - - - <html><head/><body><p>FT8 DXpedition mode: Fox (DXpedition) operator.</p></body></html> - - - Fox - - - Fox - - - false - - - special_op_activity_button_group - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - @@ -3558,13 +3635,13 @@ Right click for insert and delete options. - - - - - + + + + + diff --git a/Network/FoxVerifier.cpp b/Network/FoxVerifier.cpp index 1c7683469..87d0715e8 100644 --- a/Network/FoxVerifier.cpp +++ b/Network/FoxVerifier.cpp @@ -51,6 +51,7 @@ bool FoxVerifier::finished() { return finished_; } + void FoxVerifier::errorOccurred(QNetworkReply::NetworkError code) { int status = reply_->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); @@ -109,3 +110,7 @@ QString FoxVerifier::formatDecodeMessage(QDateTime ts, QString callsign, QString else return QString{}; } + +QString FoxVerifier::default_url() { + return QString(FOXVERIFIER_DEFAULT_BASE_URL); +} \ No newline at end of file diff --git a/Network/FoxVerifier.hpp b/Network/FoxVerifier.hpp index 5a6a93702..920fbf0bf 100644 --- a/Network/FoxVerifier.hpp +++ b/Network/FoxVerifier.hpp @@ -9,7 +9,7 @@ #include #define FOXVERIFIER_DEFAULT_TIMEOUT_MSEC 5000 -#define FOXVERIFIER_DEFAULT_BASE_URL "https://www.9dx.ccm" +#define FOXVERIFIER_DEFAULT_BASE_URL "https://www.9dx.cc" class FoxVerifier : public QObject { Q_OBJECT @@ -22,6 +22,7 @@ public: QString return_value; bool finished(); static QString formatDecodeMessage(QDateTime ts, QString callsign, QString const& verify_message); + static QString default_url(); private: QNetworkAccessManager* manager_; @@ -57,4 +58,6 @@ signals: void verifyError(int status, QDateTime ts, QString callsign, QString code, QString const& response); }; + + #endif //WSJTX2_FOXVERIFIER_HPP diff --git a/widgets/mainwindow.cpp b/widgets/mainwindow.cpp index 36254fdd4..cd1503011 100644 --- a/widgets/mainwindow.cpp +++ b/widgets/mainwindow.cpp @@ -4306,12 +4306,29 @@ void MainWindow::readFromStdout() //readFromStdout ARRL_Digi_Update(decodedtext1); } - if (ui->labDXped->text() == "Super Hound" && (decodedtext0.mid(24, 8) == "$VERIFY$")) { + if ((SpecOp::HOUND == m_specOp) && + ((m_config.superFox() && (decodedtext0.mid(24, 8) == "$VERIFY$")) || // $VERIFY$ K8R 920749 + (decodedtext0.mid(24, 8).contains(QRegularExpression{"^[A-Z0-9]{2,5}\\.V[0-9]{6}$"})))) // K8R.V920749 + { + // two cases: + // QString test_return = QString{"203630 -12 0.1 775 ~ K8R.V920749"}; // $VERIFY$ foxcall otp // QString test_return = QString{"203630 -12 0.1 775 ~ $VERIFY$ K8R 920749"}; QStringList lineparts; + QStringList otp_parts; + QString callsign, otp; lineparts = decodedtext0.string().split(' ', SkipEmptyParts); - + if (lineparts.length() <= 6) { + // split K8R.V920749 into K8R and 920749 + otp_parts = lineparts[5].split('.', SkipEmptyParts); + callsign = otp_parts[0]; + otp = otp_parts[1].mid(1); // remove the V + } else + { + // split $VERIFY$ K8R 920749 into K8R and 920749 + callsign = lineparts[6]; + otp = lineparts[7]; + } QDateTime verifyDateTime; if (m_diskData) { verifyDateTime = m_UTCdiskDateTime; // get the date set from reading the wav file @@ -4322,9 +4339,9 @@ void MainWindow::readFromStdout() //readFromStdout FoxVerifier *fv = new FoxVerifier(MainWindow::userAgent(), &m_network_manager, FOXVERIFIER_DEFAULT_BASE_URL, - lineparts[6], // foxcall + callsign, // foxcall verifyDateTime, - lineparts[7]); // otp + otp); // otp connect(fv, &FoxVerifier::verifyComplete, this, &MainWindow::handleVerifyMsg); m_verifications << fv; } else { @@ -10185,6 +10202,33 @@ void MainWindow::on_comboBoxHoundSort_activated(int index) if(index!=-99) houndCallers(); //Silence compiler warning } +QString MainWindow::foxOTPcode() +{ + QString code; + if (!m_config.OTPSeed().isEmpty()) + { + char output[7]; + QDateTime dateTime = dateTime.currentDateTime(); + QByteArray ba = m_config.OTPSeed().toLocal8Bit(); + char *c_str = ba.data(); + int return_length; + if (6 == (return_length = create_totp(c_str, output, dateTime.toTime_t(), 30, 0))) + { + code = QString(output); + } else + { + code = "000000"; + LOG_INFO(QString("foxOTPcode: Incorrect return length %1").arg(return_length)); + } + } else + { + code = "000000"; + showStatusMessage(tr("TOTP: No seed entered in fox configuration to generate verification code.")); + LOG_INFO(QString("foxOTPcode: No seed entered in fox configuration to generate verification code.")); + } + return code; +} + //------------------------------------------------------------------------------ QString MainWindow::sortHoundCalls(QString t, int isort, int max_dB) { @@ -10505,6 +10549,7 @@ void MainWindow::foxRxSequencer(QString msg, QString houndCall, QString rptRcvd) } } } + void MainWindow::updateFoxQSOsInProgressDisplay() { @@ -10535,8 +10580,12 @@ void MainWindow::foxTxSequencer() QString hc,hc1,hc2; //Hound calls QString t,rpt; qint32 islot=0; + qint32 ncalls_sent=0; qint32 n1,n2,n3; int nMaxRemainingSlots=0; + static u_int m_tFoxTxSinceOTP=99; + + m_tFoxTxSinceOTP++; m_tFoxTx++; //Increment Fox Tx cycle counter //Is it time for a stand-alone CQ? @@ -10552,15 +10601,27 @@ void MainWindow::foxTxSequencer() foxGenWaveform(islot-1,fm); goto Transmit; } + + // Send OTP message maybe for regular fox mode + if (!m_config.superFox() && m_config.OTPEnabled() && (islot < m_Nslots) && (m_tFoxTxSinceOTP >= m_config.OTPinterval())) + { + // truncated callsign + OTP code (to be under 13 character limit of free text) + QString trunc_call=m_config.my_callsign().left(5).split("/").at(0); + fm = trunc_call + ".V" + foxOTPcode(); // N5J-> N5J.V123456, W1AW/7 -> W1AW.V123456, 4U1IARU -> 4U1IA.V123456 + m_tFoxTxSinceOTP = 0; //Remember when we sent a Tx5 + islot++; + foxGenWaveform(islot - 1, fm); + } + //Compile list1: up to NSLots Hound calls to be sent RR73 for(QString hc: m_foxQSO.keys()) { //Check all Hound calls: First priority if(m_foxQSO[hc].tFoxRrpt<0) continue; if(m_foxQSO[hc].tFoxRrpt - m_foxQSO[hc].tFoxTxRR73 > 3) { //Has been a long time since we sent RR73 + if(list1.size()>=(m_Nslots - islot)) goto list1Done; list1 << hc; //Add to list1 m_foxQSO[hc].tFoxTxRR73 = m_tFoxTx; //Time RR73 is sent m_foxQSO[hc].nRR73++; //Increment RR73 counter - if(list1.size()==m_Nslots) goto list1Done; } } @@ -10568,10 +10629,10 @@ void MainWindow::foxTxSequencer() if(m_foxQSO[hc].tFoxRrpt<0) continue; if(m_foxQSO[hc].tFoxTxRR73 < 0) { //Have not yet sent RR73 + if(list1.size()>=(m_Nslots - islot)) goto list1Done; list1 << hc; //Add to list1 m_foxQSO[hc].tFoxTxRR73 = m_tFoxTx; //Time RR73 is sent m_foxQSO[hc].nRR73++; //Increment RR73 counter - if(list1.size()==m_Nslots) goto list1Done; } } @@ -10579,10 +10640,10 @@ void MainWindow::foxTxSequencer() if(m_foxQSO[hc].tFoxRrpt<0) continue; if(m_foxQSO[hc].tFoxTxRR73 <= m_foxQSO[hc].tFoxRrpt) { //We received R+rpt more recently than we sent RR73 + if(list1.size()>=(m_Nslots - islot)) goto list1Done; list1 << hc; //Add to list1 m_foxQSO[hc].tFoxTxRR73 = m_tFoxTx; //Time RR73 is sent m_foxQSO[hc].nRR73++; //Increment RR73 counter - if(list1.size()==m_Nslots) goto list1Done; } } @@ -10595,13 +10656,18 @@ list1Done: hc=m_foxQSOinProgress.at(i); if((m_foxQSO[hc].tFoxRrpt < 0) and (m_foxQSO[hc].ncall < m_maxStrikes)) { //Sent him a report and have not received R+rpt: call him again + if(list2.size()>=(nMaxRemainingSlots - islot)) goto list2Done; list2 << hc; //Add to list2 - if(list2.size()==nMaxRemainingSlots) goto list2Done; + if(list2.size() == nMaxRemainingSlots) goto list2Done; } } while(!m_houndQueue.isEmpty()) { //Start QSO with a new Hound + if (list2.size() == (nMaxRemainingSlots - islot)) + { + break; + } t=m_houndQueue.dequeue(); //Fetch new hound from queue int i0=t.indexOf(" "); hc=t.mid(0,i0); //hound call @@ -10616,11 +10682,6 @@ list1Done: m_foxQSO[hc].tFoxRrpt = -1; //Have not received R+rpt m_foxQSO[hc].tFoxTxRR73 = -1; //Have not sent RR73 refreshHoundQueueDisplay(); - - if(list2.size()==nMaxRemainingSlots) { - break; - } - } list2Done: @@ -10680,12 +10741,13 @@ list2Done: fm = Radio::base_callsign(hc2) + " " + m_baseCall + " " + m_foxQSO[hc2].sent; //Standard FT8 message } islot++; + ncalls_sent++; foxGenWaveform(islot-1,fm); //Generate tx waveform } if(islot < m_Nslots) { //At least one slot is still open - if(islot==0 or ((m_tFoxTx-m_tFoxTx0>=4) and ui->cbMoreCQs->isChecked())) { + if(ncalls_sent==0 or ((m_tFoxTx-m_tFoxTx0>=4) and ui->cbMoreCQs->isChecked())) { //Roughly every 4th Tx sequence, put a CQ message in an otherwise empty slot fm=ui->comboBoxCQ->currentText() + " " + m_config.my_callsign(); if(!fm.contains("/")) { @@ -11321,28 +11383,24 @@ void MainWindow::sfox_tx() { qint32 otp_key = 0; args.append(m_config.my_callsign()); #ifdef FOX_OTP - if (m_config.FoxKey().startsWith("OTP:", Qt::CaseInsensitive)) + if (m_config.OTPEnabled()) { - LOG_INFO("OTP: Generating OTP key"); - if (m_config.FoxKey().length() > 19) { - QString foxCodeSeed = m_config.FoxKey().mid(4); - char output[7]; - QDateTime dateTime = dateTime.currentDateTime(); - QByteArray ba = foxCodeSeed.toLocal8Bit(); - char *c_str = ba.data(); - int return_length; - if (6 == (return_length = create_totp(c_str, output, dateTime.toTime_t(), 30, 0))) + LOG_INFO("TOTP: Generating OTP key"); + if (m_config.OTPSeed().length() == 16) { + QString output=foxOTPcode(); + if (6 == output.length()) { otp_key = QString(output).toInt(); - LOG_INFO(QString("TOTP: %1 [%2]").arg(output).arg(otp_key).toStdString()); + LOG_INFO(QString("TOTP SF: %1 [%2]").arg(output).arg(otp_key).toStdString()); } else { - LOG_INFO(QString("TOTP: Incorrect return length %1").arg(return_length)); + otp_key = 0; + LOG_INFO(QString("TOTP SF: Incorrect length")); } } else { - showStatusMessage (tr ("TOTP: seed not long enough.")); - LOG_INFO(QString("TOTP: seed not long enough")); + showStatusMessage (tr ("TOTP SF: seed not long enough.")); + LOG_INFO(QString("TOTP SF: seed not long enough")); } } args.append(QString("OTP:%1").arg(otp_key)); diff --git a/widgets/mainwindow.h b/widgets/mainwindow.h index 8c1c35b38..1e078721f 100644 --- a/widgets/mainwindow.h +++ b/widgets/mainwindow.h @@ -898,6 +898,7 @@ private: QString userAgent(); void handleVerifyMsg(int status, QDateTime ts, QString callsign, QString code, QString const &response); void writeFoxTxMsgs(); + QString foxOTPcode(); }; extern int killbyname(const char* progName);