From f1eb7897d6b933708fb8ebc01414f66786299836 Mon Sep 17 00:00:00 2001 From: Tom Early Date: Sun, 23 Dec 2018 11:08:28 -0700 Subject: [PATCH] qnlink uses CQnetConfigure --- QnetConfigure.cpp | 14 +- QnetConfigure.h | 1 + QnetGateway.cpp | 2 +- QnetGateway.h | 2 +- QnetLink.cpp | 359 ++++++++++++++++------------------------------ QnetLink.h | 18 +-- defaults | 13 +- 7 files changed, 151 insertions(+), 258 deletions(-) diff --git a/QnetConfigure.cpp b/QnetConfigure.cpp index 3d4f813..04c56c6 100644 --- a/QnetConfigure.cpp +++ b/QnetConfigure.cpp @@ -74,6 +74,11 @@ bool CQnetConfigure::Initialize(const char *file) return ReadConfigFile(file, cfg); } +bool CQnetConfigure::KeyExists(const std::string &key) +{ + return (cfg.end() != cfg.find(key)); +} + bool CQnetConfigure::GetDefaultBool(const std::string &path, const std::string &mod, bool &dvalue) { std::string value; @@ -134,10 +139,8 @@ bool CQnetConfigure::GetDefaultString(const std::string &path, const std::string auto it = defaults.find(search); if (defaults.end() == it) { it = defaults.find(search_again); - if (defaults.end() == it) { - fprintf(stderr, "%s has no default value!\n", path.c_str()); + if (defaults.end() == it) return true; - } } dvalue = it->second; return false; @@ -221,7 +224,7 @@ bool CQnetConfigure::GetValue(const std::string &path, const std::string &mod, i bool CQnetConfigure::GetValue(const std::string &path, const std::string &mod, std::string &value, int min, int max) { auto it = cfg.find(path); - if (cfg.end() != it) { + if (cfg.end() == it) { std::string dvalue; if (GetDefaultString(path, mod, dvalue)) { fprintf(stderr, "%s not found in either the cfg file for the defaults file\n", path.c_str()); @@ -232,8 +235,9 @@ bool CQnetConfigure::GetValue(const std::string &path, const std::string &mod, s printf("Default value %s='%s' is wrong size\n", path.c_str(), value.c_str()); return true; } + value.assign(dvalue); } else { - value = it->second; + value.assign(it->second); int l = value.length(); if (lmax) { printf("%s='%s' is wrong size\n", path.c_str(), value.c_str()); diff --git a/QnetConfigure.h b/QnetConfigure.h index 3215988..97ff257 100644 --- a/QnetConfigure.h +++ b/QnetConfigure.h @@ -31,6 +31,7 @@ public: bool GetValue(const std::string &path, const std::string &mod, double &value, const double min, const double max); bool GetValue(const std::string &path, const std::string &mod, int &value, const int min, const int max); bool GetValue(const std::string &path, const std::string &mod, std::string &value, const int min, const int max); + bool KeyExists(const std::string &key); private: std::map defaults; diff --git a/QnetGateway.cpp b/QnetGateway.cpp index 0acce7f..047b358 100644 --- a/QnetGateway.cpp +++ b/QnetGateway.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 2010 by Scott Lawson KI4LKF - * Copyright (C) 2017-2018 by Thomas Early N7TAE + * Copyright (C) 2017-2019 by Thomas Early N7TAE * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/QnetGateway.h b/QnetGateway.h index d08cb37..fc05ec8 100644 --- a/QnetGateway.h +++ b/QnetGateway.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 by Thomas Early N7TAE + * Copyright (C) 2018,2019 by Thomas Early N7TAE * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/QnetLink.cpp b/QnetLink.cpp index 8f9cd2c..5d3cbfa 100644 --- a/QnetLink.cpp +++ b/QnetLink.cpp @@ -1,7 +1,7 @@ /* * Copyright (C) 2010 by Scott Lawson KI4LKF - * Copyright (C) 2015,2018 by Thomas A. Early N7TAE + * Copyright (C) 2015,2018,2019 by Thomas A. Early N7TAE * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -51,6 +51,7 @@ #include "versions.h" #include "DPlusAuthenticator.h" +#include "QnetConfigure.h" #include "QnetLink.h" using namespace libconfig; @@ -468,256 +469,137 @@ void CQnetLink::calcPFCS(unsigned char *packet, int len) return; } -bool CQnetLink::get_value(const Config &cfg, const char *path, int &value, int min, int max, int default_value) +void CQnetLink::ToUpper(std::string &s) { - if (cfg.lookupValue(path, value)) { - if (value < min || value > max) - value = default_value; - } else - value = default_value; - printf("%s = [%u]\n", path, value); - return true; + for (auto it=s.begin(); it!=s.end(); it++) + if (islower(*it)) + *it = toupper(*it); } -bool CQnetLink::get_value(const Config &cfg, const char *path, double &value, double min, double max, double default_value) +void CQnetLink::UnpackCallsigns(const std::string &str, std::set &set, const std::string &delimiters) { - if (cfg.lookupValue(path, value)) { - if (value < min || value > max) - value = default_value; - } else - value = default_value; - printf("%s = [%lg]\n", path, value); - return true; -} - -bool CQnetLink::get_value(const Config &cfg, const char *path, bool &value, bool default_value) -{ - if (! cfg.lookupValue(path, value)) - value = default_value; - printf("%s = [%s]\n", path, value ? "true" : "false"); - return true; + std::string::size_type lastPos = str.find_first_not_of(delimiters, 0); // Skip delimiters at beginning. + std::string::size_type pos = str.find_first_of(delimiters, lastPos); // Find first non-delimiter. + + while (std::string::npos != pos || std::string::npos != lastPos) { + std::string element = str.substr(lastPos, pos-lastPos); + if (element.length()>=3 && element.length()<=6) { + ToUpper(element); + element.resize(CALL_SIZE, ' '); + set.insert(element); // Found a token, add it to the list. + } else + fprintf(stderr, "found bad callsign in list: %s\n", str.c_str()); + lastPos = str.find_first_not_of(delimiters, pos); // Skip delimiters. + pos = str.find_first_of(delimiters, lastPos); // Find next non-delimiter. + } } -bool CQnetLink::get_value(const Config &cfg, const char *path, std::string &value, int min, int max, const char *default_value) +void CQnetLink::PrintCallsigns(const std::string &key, const std::set &set) { - if (cfg.lookupValue(path, value)) { - int l = value.length(); - if (lmax) { - printf("%s='%s' is has to be between %d and %d characters\n", path, value.c_str(), min, max); - return false; - } - } else - value = default_value; - printf("%s = [%s]\n", path, value.c_str()); - return true; + printf("%s = [ ", key.c_str()); + for (auto it=set.begin(); it!=set.end(); it++) { + if (it != set.begin()) + printf(", "); + printf("%s", (*it).c_str()); + } + printf(" ]"); } /* process configuration file */ bool CQnetLink::read_config(const char *cfgFile) { - unsigned short i; - Config cfg; + CQnetConfigure cfg; + const std::string estr; // an empty string printf("Reading file %s\n", cfgFile); - // Read the file. If there is an error, report it and exit. - try { - cfg.readFile(cfgFile); - } - catch(const FileIOException &fioex) { - printf("Can't read %s\n", cfgFile); + if (cfg.Initialize(cfgFile)) return true; - } - catch(const ParseException &pex) { - printf("Parse error at %s:%d - %s\n", pex.getFile(), pex.getLine(), pex.getError()); + + std::string key("ircddb_login"); + if (cfg.GetValue(key, estr, owner, 3, 6)) return true; + ToUpper(owner); + owner.resize(CALL_SIZE, ' '); + + if (cfg.GetValue("dplus_ref_login", estr, login_call, 3, 6)) + login_call.assign(owner); + else { + ToUpper(login_call); + login_call.resize(CALL_SIZE, ' '); } - std::string value; - std::string key = "link.ref_login"; - if (cfg.lookupValue(key, login_call) || cfg.lookupValue("ircddb.login", login_call)) { - int l = login_call.length(); - if (l<3 || l>CALL_SIZE-2) { - printf("Call '%s' is invalid length!\n", login_call.c_str()); - return true; - } else { - for (i=0; i2 && l<=CALL_SIZE-2) { - for (unsigned int j=0; j2 && l2 && l2 && l<=CALL_SIZE-2) { - for (i=0; i= 8) { - if ((link_at_startup[0] == 'A') || (link_at_startup[0] == 'B') || (link_at_startup[0] == 'C')) { - char temp_repeater[CALL_SIZE + 1]; - memset(temp_repeater, ' ', CALL_SIZE); - memcpy(temp_repeater, link_at_startup + 1, 6); - temp_repeater[CALL_SIZE] = '\0'; - printf("sleep for 15 before link at startup\n"); - sleep(15); - g2link(link_at_startup[0], temp_repeater, link_at_startup[7]); + // initialize all request links + bool first = true; + for (int i=0; i<3; i++) { + if (8 == link_at_startup[i].length()) { + if (first) { + printf("sleep for 15 sec before link at startup\n"); + sleep(15); + first = false; + } + g2link('A'+i, link_at_startup[i].substr(0, 6).c_str(), link_at_startup[i].at(7)); } - memset(link_at_startup, '\0', sizeof(link_at_startup)); } while (keep_running) { @@ -2944,12 +2826,19 @@ void CQnetLink::Process() sprintf(notify_msg[i], "%c_id.dat_%s_NOT_LINKED", dstr.vpkt.hdr.r1[7], owner.c_str()); } } - else if (0==memcmp(dstr.vpkt.hdr.ur, " ", 6) && dstr.vpkt.hdr.ur[7]=='X' && admin.find(call)!=admin.end()) { // only ADMIN can execute scripts - if (dstr.vpkt.hdr.ur[6] != ' ') { - memset(system_cmd, '\0', sizeof(system_cmd)); - snprintf(system_cmd, FILENAME_MAX, "%s/exec_%c.sh %s %c &", announce_dir.c_str(), dstr.vpkt.hdr.ur[6], call, dstr.vpkt.hdr.r1[7]); - printf("Executing %s\n", system_cmd); - system(system_cmd); + else if (0==memcmp(dstr.vpkt.hdr.ur, " ", 6) && dstr.vpkt.hdr.ur[7]=='X') { // execute a script + if (dstr.vpkt.hdr.ur[6] != ' ') { // there has to be a char here + bool user_ok = true; + if (admin.size()>0 && admin.end()==admin.find(call)) { // only admins (if defined) can execute scripts + printf("%s not found in the link_admin list!\n", call); + user_ok = false; + } + if (user_ok) { + memset(system_cmd, '\0', sizeof(system_cmd)); + snprintf(system_cmd, FILENAME_MAX, "%s/exec_%c.sh %s %c &", announce_dir.c_str(), dstr.vpkt.hdr.ur[6], call, dstr.vpkt.hdr.r1[7]); + printf("Executing %s\n", system_cmd); + system(system_cmd); + } } } else if (0==memcmp(dstr.vpkt.hdr.ur, " ", 6) && dstr.vpkt.hdr.ur[6]=='D' && admin.find(call)!=admin.end()) { // only ADMIN can block dongle users diff --git a/QnetLink.h b/QnetLink.h index 1bb4604..8b62045 100644 --- a/QnetLink.h +++ b/QnetLink.h @@ -1,7 +1,7 @@ #pragma once /* - * Copyright (C) 2018 by Thomas A. Early N7TAE + * Copyright (C) 2018-2019 by Thomas A. Early N7TAE * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,15 +25,12 @@ #include #include #include -#include #include "versions.h" #include "QnetTypeDefs.h" #include "SEcho.h" #include "Random.h" #include "UnixDgramSocket.h" -using namespace libconfig; - /*** version number must be x.xx ***/ #define VERSION LINK_VERSION #define CALL_SIZE 8 @@ -68,13 +65,16 @@ public: void Shutdown(); private: // functions + void ToUpper(std::string &s); + void UnpackCallsigns(const std::string &str, std::set &set, const std::string &delimiters = ","); + void PrintCallsigns(const std::string &key, const std::set &set); bool load_gwys(const std::string &filename); void calcPFCS(unsigned char *packet, int len); bool read_config(const char *); bool srv_open(); void srv_close(); static void sigCatch(int signum); - void g2link(char from_mod, char *call, char to_mod); + void g2link(const char from_mod, const char *call, const char to_mod); void print_status_file(); void send_heartbeat(); bool resolve_rmt(char *name, int type, struct sockaddr_in *addr); @@ -82,19 +82,15 @@ private: void PlayAudioNotifyThread(char *msg); void AudioNotifyThread(SECHO &edata); void RptrAckThread(char *arg); - bool get_value(const Config &cfg, const char *path, int &value, int min, int max, int default_value); - bool get_value(const Config &cfg, const char *path, double &value, double min, double max, double default_value); - bool get_value(const Config &cfg, const char *path, bool &value, bool default_value); - bool get_value(const Config &cfg, const char *path, std::string &value, int min, int max, const char *default_value); /* configuration data */ std::string login_call, owner, to_g2_external_ip, my_g2_link_ip, gwys, status_file, qnvoice_file, announce_dir; bool only_admin_login, only_link_unlink, qso_details, bool_rptr_ack, announce; bool dplus_authorize, dplus_reflectors, dplus_repeaters; int rmt_xrf_port, rmt_ref_port, rmt_dcs_port, my_g2_link_port, to_g2_external_port, delay_between, delay_before; - char link_at_startup[CALL_SIZE+1]; + std::string link_at_startup[3]; unsigned int max_dongles, saved_max_dongles; - long rf_inactivity_timer[3]; + int rf_inactivity_timer[3]; const unsigned char REF_ACK[3] = { 3, 96, 0 }; // the Key in this inbound_list map is the unique IP address of the remote diff --git a/defaults b/defaults index 9b536e5..7a15238 100644 --- a/defaults +++ b/defaults @@ -25,12 +25,15 @@ # If a string value is a simple word, it doesn't need to be quoted # Use the single quote (') for quoting strings, not the double quote(") # Comments can come after a key=value definition, introduced by a pound-sign (#) +# +# if a definition is commented out, it means that key has no default value. And it is +# include here just as a reference. ########################################################################################################################## # # IRCDDB - You MUST use a legal callsign for logging into any IRC network # -ircddb_login_d='' # login callsign for the ircDDB network +#ircddb_login_d='' # login callsign for the ircDDB network ircddb_host_d='rr.openquad.net' # other irc networks include group1-irc.ircddb.net ircddb_port_d=9007 # not a good idea to change! ircddb_password_d='1111111111111' # not needed for rr.openquad.net @@ -61,8 +64,8 @@ aprs_filter_d='' # advanced feature # # LINK - controls the behaviour of QnetLink (qnlink) # -link_admin_d='' # these comma-separated list of users can execute scripts, block dongles, reload the gwys.txt -link_link_unlink_d='' # if defined, comma-separated list of users that can link and unlink a repeater +#link_admin_d='' # these comma-separated list of users can execute scripts, block dongles, reload the gwys.txt +#link_link_unlink_d='' # if defined, comma-separated list of users that can link and unlink a repeater #link_no_link_unlink_d='' # if defined, comma-separated list of users that cannot link or unlink, it's a blacklist # if the blacklist is defined (even if it's empty), the link_unlink will not be read link_incoming_ip_d='0.0.0.0' # incoming ip address of qnlink, '0.0.0.0' means accepts any connection. @@ -77,7 +80,7 @@ link_max_dongles_d=5 # maximum number of linked hot-spots # # GENERIC MODULE - These will be defined for any and all defined modules # -module_x_link_at_start='' # For example, set to 'REF001CL' to link module to 1-charlie when the module starts. +#module_x_link_at_start='' # For example, set to 'REF001 C' to link module to 1-charlie when the module starts. module_x_inactivity=0 # if no activity for this many minutes unlink reflector. Zero means no timer. module_x_callsign='' # if you operate in a 'restriction mode', use your personal callsign. Usually leave this empty. module_x_packet_wait=25 # how many milliseconds to wait on packets in a voicestream @@ -145,7 +148,7 @@ log_dtmf_d=false # DTMF debug info # The following settings do not affect your ability to use dplus linking to XRF or XLX reflectors! # You must be registered on the DPlus system, see www.dstargateway.org, otherwise authorization will fail, # even if QnetLink reports a successful authorization. -dplus_ref_login_d='' # for logging into REF reflectors, if undefined or empty, ircddb_login will be used +dplus_ref_login_d='' # for logging into REF reflectors, if empty, ircddb_login will be used dplus_authorize_d=false # set to true if you want to use the closed-source DPlus reflectors and/or repeaters dplus_use_reflectors_d=true # set to false if you are not going to link to DPlus reflectors dplus_use_repeaters_d=true # set to false if you are not going to link to DPlus repeaters