qnlink uses CQnetConfigure

pull/12/head
Tom Early 7 years ago
parent b4dc0cfb2c
commit f1eb7897d6

@ -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,11 +139,9 @@ 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 (l<min || l>max) {
printf("%s='%s' is wrong size\n", path.c_str(), value.c_str());

@ -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<std::string, std::string> defaults;

@ -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

@ -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

@ -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<std::string> &set, const std::string &delimiters)
{
if (cfg.lookupValue(path, value)) {
if (value < min || value > max)
value = default_value;
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
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;
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<std::string> &set)
{
if (cfg.lookupValue(path, value)) {
int l = value.length();
if (l<min || l>max) {
printf("%s='%s' is has to be between %d and %d characters\n", path, value.c_str(), min, max);
return false;
printf("%s = [ ", key.c_str());
for (auto it=set.begin(); it!=set.end(); it++) {
if (it != set.begin())
printf(", ");
printf("%s", (*it).c_str());
}
} else
value = default_value;
printf("%s = [%s]\n", path, value.c_str());
return true;
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);
return true;
}
catch(const ParseException &pex) {
printf("Parse error at %s:%d - %s\n", pex.getFile(), pex.getLine(), pex.getError());
if (cfg.Initialize(cfgFile))
return true;
}
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());
std::string key("ircddb_login");
if (cfg.GetValue(key, estr, owner, 3, 6))
return true;
} else {
for (i=0; i<l; i++) {
if (islower(login_call[i]))
login_call[i] = toupper(login_call[i]);
}
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, ' ');
printf("%s = [\"%s\"]\n", key.c_str(), login_call.c_str());
}
} else {
printf("%s is not defined.\n", key.c_str());
return true;
}
key = "link.admin";
if (cfg.exists(key)) {
Setting &userlist = cfg.lookup(key);
if (userlist.isArray()) {
for (i=0; i<userlist.getLength(); i++) {
value = (const char *)userlist[i];
int l = value.length();
if (l>2 && l<=CALL_SIZE-2) {
for (unsigned int j=0; j<value.length(); j++) {
if (islower(value[j]))
value[j] = toupper(value[j]);
}
value.resize(CALL_SIZE, ' ');
if (admin.end() == admin.find(value)) {
admin.insert(value).second;
} else
printf("aready added '%s' as user.\n", value.c_str());
} else
printf("'%s' is the wrong length!\n", value.c_str());
}
} else {
printf("%s is not an array!\n", key.c_str());
return true;
}
printf("%s = [ ", key.c_str());
for (auto pos=admin.begin(); pos!=admin.end(); pos++) {
if (pos != admin.begin())
printf(", ");
printf("\"%s\"", (*pos).c_str());
}
printf(" ]\n");
}
key = "link.no_link_unlink";
if (cfg.exists(key)) {
Setting &linkblacklist = cfg.lookup(key);
if (linkblacklist.isArray()) {
for (i=0; i<linkblacklist.getLength(); i++) {
value = (const char *)linkblacklist[i];
int l = value.length();
if (l>2 && l<CALL_SIZE-2) {
for (unsigned int j=0; j<value.length(); j++) {
if (islower(value[j]))
value[j] = toupper(value[j]);
}
value.resize(CALL_SIZE, ' ');
if (link_blacklist.end() == link_blacklist.find(value)) {
link_blacklist.insert(value).second;
} else
printf("already added '%s' to link-blacklist.\n", value.c_str());
} else
printf("'%s' is the wrong length!\n", value.c_str());
}
} else {
printf("%s is not an array!\n", key.c_str());
return true;
}
printf("%s = [ ", key.c_str());
for (auto pos=link_blacklist.begin(); pos!=link_blacklist.end(); pos++) {
if (pos != link_blacklist.begin())
printf(", ");
printf("\"%s\"", (*pos).c_str());
}
printf(" ]\n");
} else {
key = "link.link_unlink";
if (cfg.exists(key)) {
Setting &unlinklist = cfg.lookup(key);
if (unlinklist.isArray()) {
for (i=0; i<unlinklist.getLength(); i++) {
value = (const char *)unlinklist[i];
int l = value.length();
if (l>2 && l<CALL_SIZE-2) {
for (unsigned int j=0; j<value.length(); j++) {
if (islower(value[j]))
value[j] = toupper(value[j]);
}
value.resize(CALL_SIZE, ' ');
if (link_unlink_user.end() == link_unlink_user.find(value)) {
link_unlink_user.insert(value).second;
} else
printf("already added '%s' to link-unlink.\n", value.c_str());
} else
printf("'%s' is the wrong length!\n", value.c_str());
}
} else {
printf("%s is not an array!\n", key.c_str());
int modules = 0;
key.assign("module_");
for (int i=0; i<3; i++) {
key.append(1, 'a'+i);
if (cfg.KeyExists(key)) {
std::string modem_type;
cfg.GetValue(key, estr, modem_type, 1, 16);
modules++;
cfg.GetValue(key+"_inactivity", modem_type, rf_inactivity_timer[i], 0, 300);
rf_inactivity_timer[i] *= 60;
cfg.GetValue(key+"_link_at_start", modem_type, link_at_startup[i], 8, 8);
}
}
if (0 == modules) {
fprintf(stderr, "no rf modules defined!\n");
return true;
}
printf("%s = [ ", key.c_str());
for (auto pos=link_unlink_user.begin(); pos!=link_unlink_user.end(); pos++) {
if (pos != link_unlink_user.begin())
printf(", ");
printf("\"%s\"", (*pos).c_str());
}
printf(" ]\n");
}
}
key = "ircddb.login";
if (cfg.lookupValue(key, owner)) {
int l = owner.length();
if (l>2 && l<=CALL_SIZE-2) {
for (i=0; i<l; i++) {
if (islower(owner[i]))
owner[i] = toupper(owner[i]);
std::string csv;
key.assign("link_admin");
if (cfg.KeyExists(key)) {
cfg.GetValue(key, estr, csv, 0, 10240);
UnpackCallsigns(csv, admin);
PrintCallsigns(key, admin);
}
owner.resize(CALL_SIZE, ' ');
printf("%s = [%s]\n", key.c_str(), owner.c_str());
csv.clear();
key.assign("link_no_link_unlink");
if (cfg.KeyExists(key)) {
cfg.GetValue(key, estr, csv, 0, 10250);
UnpackCallsigns(csv, link_blacklist);
PrintCallsigns(key, link_blacklist);
} else {
printf("%s '%s' is wrong size.\n", key.c_str(), owner.c_str());
return true;
csv.clear();
key.assign("link_link_unlink");
if (cfg.KeyExists(key)) {
cfg.GetValue(key, estr, csv, 0, 10240);
UnpackCallsigns(csv, link_unlink_user);
PrintCallsigns(key, link_unlink_user);
}
}
get_value(cfg, "link.ref_port", rmt_ref_port, 10000, 65535, 20001);
get_value(cfg, "link.xrf_port", rmt_xrf_port, 10000, 65535, 30001);
get_value(cfg, "link.dcs_port", rmt_dcs_port, 10000, 65535, 30051);
get_value(cfg, "gateway.tolink", gate2link, 1, FILENAME_MAX, "gate2link");
get_value(cfg, "gateway.fromlink", link2gate, 1, FILENAME_MAX, "link2gate");
get_value(cfg, "log.qso", qso_details, true);
if (! get_value(cfg, "file.gwys", gwys, 2, FILENAME_MAX, "/usr/local/etc/gwys.txt"))
return true;
if (! get_value(cfg, "file.status", status_file, 2, FILENAME_MAX, "/usr/local/etc/RPTR_STATUS.txt"))
return true;
get_value(cfg, "file.qnvoicefile", qnvoice_file, 2, FILENAME_MAX, "/tmp/qnvoice.txt");
key.assign("link_");
cfg.GetValue(key+"ref_port", estr, rmt_ref_port, 10000, 65535);
cfg.GetValue(key+"xrf_port", estr, rmt_xrf_port, 10000, 65535);
cfg.GetValue(key+"dcs_port", estr, rmt_dcs_port, 10000, 65535);
cfg.GetValue(key+"acknowledge", estr, bool_rptr_ack);
cfg.GetValue(key+"announce", estr, announce);
int maxdongle;
cfg.GetValue(key+"max_dongles", estr, maxdongle, 0, 10);
saved_max_dongles = max_dongles = (unsigned int)maxdongle;
get_value(cfg, "timing.play.delay", delay_between, 9, 25, 19);
key.assign("gateway_");
cfg.GetValue(key+"tolink", estr, gate2link, 1, FILENAME_MAX);
cfg.GetValue(key+"fromlink", estr, link2gate, 1, FILENAME_MAX);
get_value(cfg, "link.acknowledge", bool_rptr_ack, true);
cfg.GetValue("log.qso", estr, qso_details);
get_value(cfg, "link.announce", announce, true);
key.assign("file_");
cfg.GetValue(key+"gwys", estr, gwys, 2, FILENAME_MAX);
cfg.GetValue(key+"status", estr, status_file, 2, FILENAME_MAX);
cfg.GetValue(key+"qnvoicefile", estr, qnvoice_file, 2, FILENAME_MAX);
cfg.GetValue(key+"announce_dir", estr, announce_dir, 2, FILENAME_MAX);
if (! get_value(cfg, "file.announce_dir", announce_dir, 2, FILENAME_MAX, "/usr/local/etc"))
return true;
key.assign("timing_play_");
cfg.GetValue(key+"wait", estr, delay_before, 1, 10);
cfg.GetValue(key+"delay", estr, delay_between, 9, 25);
get_value(cfg, "timing.play.wait", delay_before, 1, 10, 1);
memset(link_at_startup, 0, CALL_SIZE+1);
if (get_value(cfg, "link.link_at_start", value, 5, CALL_SIZE, "NONE")) {
if (strcasecmp(value.c_str(), "none"))
strcpy(link_at_startup, value.c_str());
} else
return true;
int maxdongle;
get_value(cfg, "link.max_dongles", maxdongle, 0, 10, 5);
saved_max_dongles = max_dongles = (unsigned int)maxdongle;
for (i=0; i<3; i++) {
int timer;
key = "timing.inactivity.";
key += ('a' + i);
get_value(cfg, key.c_str(), timer, 0, 300, 0);
timer *= 60;
rf_inactivity_timer[i] = timer;
}
get_value(cfg, "dplus.authorize", dplus_authorize, false);
get_value(cfg, "dplus.use_reflectors", dplus_reflectors, true);
get_value(cfg, "dplus.use_repeaters", dplus_repeaters, true);
key.assign("dplus_");
cfg.GetValue(key+"authorize", estr, dplus_authorize);
cfg.GetValue(key+"use_reflectors", estr, dplus_reflectors);
cfg.GetValue(key+"use_repeaters", estr, dplus_repeaters);
return false;
}
@ -836,7 +718,7 @@ void CQnetLink::srv_close()
}
/* find the repeater IP by callsign and link to it */
void CQnetLink::g2link(char from_mod, char *call, char to_mod)
void CQnetLink::g2link(const char from_mod, const char *call, const char to_mod)
{
short i,j, counter;
@ -1069,17 +951,17 @@ void CQnetLink::Process()
printf("xrf=%d, dcs=%d, ref=%d, gateway=%d, MAX+1=%d\n", xrf_g2_sock, dcs_g2_sock, ref_g2_sock, Gate2Link.GetFD(), max_nfds + 1);
if (strlen(link_at_startup) >= 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");
// 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);
g2link(link_at_startup[0], temp_repeater, link_at_startup[7]);
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,14 +2826,21 @@ 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] != ' ') {
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
if (dstr.vpkt.hdr.ur[7] == '1') {
max_dongles = saved_max_dongles;

@ -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 <set>
#include <atomic>
#include <netinet/in.h>
#include <libconfig.h++>
#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<std::string> &set, const std::string &delimiters = ",");
void PrintCallsigns(const std::string &key, const std::set<std::string> &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

@ -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

Loading…
Cancel
Save

Powered by TurnKey Linux.