commit 12d55cef370348ac867d03518f1631b414be15c5 Author: Jonathan Naylor Date: Wed May 9 19:23:17 2018 +0100 Initial commit. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0f42248 --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +*.o +*.obj +x86 +Debug +Release +*.user +*~ +*.bak +.vs + diff --git a/APRSTransmit/APRSParser.cpp b/APRSTransmit/APRSParser.cpp new file mode 100644 index 0000000..711297a --- /dev/null +++ b/APRSTransmit/APRSParser.cpp @@ -0,0 +1,601 @@ +/* + * Copyright (C) 2014 by Jonathan Naylor G4KLX + * APRSTransmit Copyright (C) 2015 Geoffrey Merck F4FXL / KC3FRA + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +// Most of the code has been borrowed from APRX Software. I just kept the parts I need for my purpose and C++ed it. Hence the copyright text below. +//https://github.com/PhirePhly/aprx/blob/master/parse_aprs.c + +/******************************************************************** + * APRX -- 2nd generation APRS-i-gate with * + * minimal requirement of esoteric facilities or * + * libraries of any kind beyond UNIX system libc. * + * * + * (c) Matti Aarnio - OH2MQK, 2007-2014 * + * * + ********************************************************************/ +/* + * Some parts of this code are copied from: + * + * aprsc + * + * (c) Heikki Hannikainen, OH7LZB + * + * This program is licensed under the BSD license, which can be found + * in the file LICENSE. + * + */ + +#include "APRSParser.h" +#include +#include +#include + +CAPRSPacket::CAPRSPacket() : +m_type(APT_Unknown), +m_latitude(0.0F), +m_longitude(0.0F), +m_symbol('\0'), +m_symbolTable('\0'), +m_typeChar('\0'), +m_body(), +m_raw() +{ +} +CAPRSPacket::CAPRSPacket(APRSPacketType type, float latitude, float longitude, const wxString& infoText, const wxString raw) : +m_type(type), +m_latitude(latitude), +m_longitude(longitude), +m_symbol('\0'), +m_symbolTable('\0'), +m_typeChar('\0'), +m_body(infoText), +m_raw(raw), +m_destCall(), +m_srcCall() +{ +} + +float& CAPRSPacket::Longitude(){ + return m_longitude; +} +float& CAPRSPacket::Latitude(){ + return m_latitude; +} +wxString& CAPRSPacket::Body(){ + return m_body; +} +wxString& CAPRSPacket::Raw(){ + return m_raw; +} + +wxChar& CAPRSPacket::Symbol(){ + return m_symbol; +} + +wxChar& CAPRSPacket::SymbolTable(){ + return m_symbolTable; +} + +wxChar& CAPRSPacket::TypeChar(){ + return m_typeChar; +} + +APRSPacketType& CAPRSPacket::Type(){ + return m_type; +} + + +wxString& CAPRSPacket::SourceCall(){ + return m_srcCall; +} +wxString& CAPRSPacket::DestinationCall(){ + return m_destCall; +} + +/***************************************************************************** +* Parsed an APRS string into an APRS frame +* currently it does nothing but determine if the packet is Icom supported +* I already added provision for conversion of unsupported packet formats to supported formats +******************************************************************************/ +bool CAPRSParser::Parse(const wxString& aprsFrame, CAPRSPacket& packet) +{ + wxString aprsFrameLocal(aprsFrame); + stripFrame(aprsFrameLocal); + if(!preprocessFrame(packet, aprsFrameLocal)) + return false; + + switch(packet.TypeChar()) + { + case '\'': + case '`' : + { + //Packet is of MicE type + //Icom radios do not support MicE so convert + if(parse_aprs_mice(packet)){ + wxLogMessage(wxT("Got MicE format, converting to Icom supported")); + convertToIcomCompatible(packet); + return Parse(packet.Raw(), packet); + } + packet.Type() = APT_Position; + return false; + } + case '!' : + if(packet.Body().GetChar(0) == '!'){ + //Ultimeter 2000 weather station + //same procedure as above, ignore for now + return false; + } + case '=' : + case '/' : + case '@' : + { + if(packet.Body().Length() < 10) return false;//enough chars to have a chance to parse it ? + /* Normal or compressed location packet, with or without + * timestamp, with or without messaging capability + * + * ! and / have messaging, / and @ have a prepended timestamp + */ + packet.Type() = APT_Position; + if(packet.TypeChar() == '/' || packet.TypeChar() == '@')//With a prepended timestamp, jump over it. + packet.Body() = packet.Body().Mid(7); + + wxChar posChar = packet.Body().GetChar(0); + if(valid_sym_table_compressed(posChar)//Compressed format + && packet.Body().Length() >= 13){//we need at least 13 char + //icom unsupported, ignore for now + return false;//parse_aprs_compressed(pb, body, body_end); + } + else if(posChar >= '0' && posChar <= '9' //Normal uncompressed format + && packet.Body().Length() >=19){//we need at least 19 chars for it to be valid + + if(ensureIsIcomCompatible(packet)) + return Parse(packet.Raw(), packet); + return true; + } + break; + } + case '$' : //NMEA packet + if(packet.Body().Length() > 10){ + packet.Type() = APT_NMEA; + return true; + } + break; + case ':' : + //We have an APRS message + packet.Type() = APT_Message; + //Nice future feature would be to add conversion to icom Android App messaging + return false; + case ';' : + //we have an object + if(packet.Body().Length() > 29){ + //TODO : Parsing ... + packet.Type() = APT_Object; + return true; + } + break; + case ')' : + //this is an item + if(packet.Body().Length() > 19){ + //TODO : Parsing ... + packet.Type() = APT_Item; + return true; + } + break; + case '>' ://APRS status... + case '<' ://stat capa + case '?' ://Query + case 'T' ://Telemetry + return false;//not supported + case '#': /* Peet Bros U-II Weather Station */ + case '*': /* Peet Bros U-I Weather Station */ + case '_': /* Weather report without position */ + packet.Type() = APT_WX; + return true; // AFAIK _ is supported, not sure for the others + case '{' ://custom + return false; + } + + return false; +} + +void CAPRSParser::convertToIcomCompatible(CAPRSPacket& packet) +{ + //first build the coordinate string + float degrees = ::floor(::fabs(packet.Latitude())); + float minutes = (::fabs(packet.Latitude()) - degrees) * 60.0f; + char hemisphere = packet.Latitude() > 0.0f ? 'N' : 'S'; + wxString latString = wxString::Format(wxT("%02.0f%05.2f%c"), degrees, minutes, hemisphere); + + degrees = ::floor(::fabs(packet.Longitude())); + minutes = (::fabs(packet.Longitude()) - degrees) * 60.0f; + hemisphere = packet.Longitude() > 0.0f ? 'E' : 'W'; + wxString longString = wxString::Format(wxT("%03.0f%05.2f%c"), degrees, minutes, hemisphere); + + /*packet.Raw() = wxString::Format(wxT("%s>%s:=%s%c%s%c/%s"), + packet.SourceCall().mb_str().data(), + packet.DestinationCall().mb_str().data(), + latString.mb_str().data(), + (char)packet.SymbolTable(), + longString.mb_str().data(), + (char)packet.Symbol(), + packet.Body().mb_str().data());*/ + + //above code behaved in different manner under wx2.8 let's do it the brutal way ! + packet.Raw() = packet.SourceCall() + + wxT(">") + + packet.DestinationCall() + + wxT(":=") + + latString + + packet.SymbolTable() + + longString + + packet.Symbol() + + wxT("/") + + packet.Body(); +} + +//configures the packet's raw, source call and dest call +bool CAPRSParser::preprocessFrame(CAPRSPacket& packet, const wxString& aprsFrame) +{ + wxString addressField = aprsFrame.BeforeFirst(':'); + wxString body = aprsFrame.AfterFirst(':'); + if(addressField == aprsFrame || body.IsEmpty()){ + wxLogWarning(wxT("Failed to find body of aprs frame")); + return false; + } + + wxString srcCall = addressField.BeforeFirst('>'); + wxString destCall = addressField.AfterFirst('>'); + if(srcCall == addressField){ + wxLogWarning(wxT("Failed to extract source and destination call")); + return false; + } + + packet.TypeChar() = body.GetChar(0); + packet.Body() = body.Mid(1);//strip the type char + packet.SourceCall() = srcCall; + packet.DestinationCall() = destCall; + packet.Raw() = wxString(aprsFrame); + packet.Type() = APT_Unknown; + + return true; +} + +/* Stupidly icom always expects a / after the symbol char, even if no data extension is present -_- +* This function makes sure the frame is icom compatible. In case the frame is invalid, A COMPLETE aprsFrame is built. +* If no modifications were made true is returned, otherwise false */ +bool CAPRSParser::ensureIsIcomCompatible(CAPRSPacket& packet) +{ + bool changeMade = false; + wxChar symbol = packet.Body().GetChar(18); + wxChar charAfterSymbol = packet.Body().GetChar(19); + wxString newBody(packet.Body()); + wxString aprsFrame(packet.Raw()); + + if(charAfterSymbol != '/' + && symbol != '_'){//do not do this for weather packets ! + newBody = packet.Body().Mid(0, 19) + wxT("/") + packet.Body().Mid(19); + aprsFrame.Replace(packet.Body(), newBody); + changeMade = true; + } + + if(stripFrame(aprsFrame)) changeMade = true; + + packet.Body() = newBody; + packet.Raw() = aprsFrame; + + return changeMade; +} + +bool CAPRSParser::stripFrame(wxString& aprsFrame) +{ + const unsigned int maxAprsFrameLen = 64U; + + bool changeMade = false; + + //Trim the path, only keep from and to. Icom device do not support too long frames. + if(aprsFrame.Length() > maxAprsFrameLen){ + wxString dataField = aprsFrame.AfterFirst(':'); + wxString addressField = aprsFrame.BeforeFirst(':'); + addressField = addressField.BeforeFirst(','); + aprsFrame = addressField + wxT(":") + dataField; + changeMade = true; + } + + + + //Still too long ? + if(aprsFrame.Length() > maxAprsFrameLen){ + aprsFrame = aprsFrame.Left(maxAprsFrameLen); + changeMade = true; + } + + return changeMade; +} + + +bool CAPRSParser::parse_aprs_mice(CAPRSPacket& packet) +{ + float lat = 0.0, lng = 0.0; + unsigned int lat_deg = 0, lat_min = 0, lat_min_frag = 0, lng_deg = 0, lng_min = 0, lng_min_frag = 0; + //const char *d_start; + char dstcall[7]; + char *p; + char sym_table, sym_code; + int posambiguity = 0; + int i; + + //code below is just to map wxWidgets stuff to original APRX pointer based logic. + char* body = new char[packet.Body().length()]; + for (unsigned int i = 0U; i < packet.Body().length(); i++) + body[i] = packet.Body().GetChar(i); + char* body_end = body + packet.Body().length(); + + char* d_start = new char[packet.Body().length()]; + for (unsigned int i = 0U; i < packet.Body().length(); i++) + d_start[i] = packet.DestinationCall().GetChar(i); + char* dstcall_end_or_ssid = d_start + packet.DestinationCall().length(); + + + //Original APRX code follows.. Just a few minor changes + + /* check packet length */ + if (body_end - body < 8) { + delete[] body; + delete[] d_start; + return false; + } + + /* check that the destination call exists and is of the right size for mic-e */ + //d_start = pb->srccall_end+1; + if (dstcall_end_or_ssid - d_start != 6) { + //DEBUG_LOG(".. bad destcall length! "); + delete[] body; + delete[] d_start; + return false; /* eh...? */ + } + + /* validate destination call: + * A-K characters are not used in the last 3 characters + * and MNO are never used + */ + //if (debug)printf(" destcall='%6.6s'",d_start); + for (i = 0; i < 3; i++) + if (!((d_start[i] >= '0' && d_start[i] <= '9') + || (d_start[i] >= 'A' && d_start[i] <= 'L') + || (d_start[i] >= 'P' && d_start[i] <= 'Z'))) { + //DEBUG_LOG(".. bad destcall characters in posits 1..3"); + delete[] body; + delete[] d_start; + return false; + } + + for (i = 3; i < 6; i++) + if (!((d_start[i] >= '0' && d_start[i] <= '9') + || (d_start[i] == 'L') + || (d_start[i] >= 'P' && d_start[i] <= 'Z'))) { + //DEBUG_LOG(".. bad destcall characters in posits 4..6"); + delete[] body; + delete[] d_start; + return false; + } + + //DEBUG_LOG("\tpassed dstcall format check"); + + /* validate information field (longitude, course, speed and + * symbol table and code are checked). Not bullet proof.. + * + * 0 1 23 4 5 6 7 + * /^[\x26-\x7f][\x26-\x61][\x1c-\x7f]{2}[\x1c-\x7d][\x1c-\x7f][\x21-\x7b\x7d][\/\\A-Z0-9]/ + */ + if (body[0] < 0x26 || body[0] > 0x7f) { + //DEBUG_LOG("..bad infofield column 1"); + delete[] body; + delete[] d_start; + return false; + } + if (body[1] < 0x26 || body[1] > 0x61) { + //DEBUG_LOG("..bad infofield column 2"); + delete[] body; + delete[] d_start; + return false; + } + if (body[2] < 0x1c || body[2] > 0x7f) { + //DEBUG_LOG("..bad infofield column 3"); + delete[] body; + delete[] d_start; + return false; + } + if (body[3] < 0x1c || body[3] > 0x7f) { + //DEBUG_LOG("..bad infofield column 4"); + delete[] body; + delete[] d_start; + return false; + } + if (body[4] < 0x1c || body[4] > 0x7d) { + //DEBUG_LOG("..bad infofield column 5"); + //delete[] body; + //delete[] d_start; + //return false; + } + if (body[5] < 0x1c || body[5] > 0x7f) { + //DEBUG_LOG("..bad infofield column 6"); + delete[] body; + delete[] d_start; + return false; + } + if ((body[6] < 0x21 || body[6] > 0x7b) + && body[6] != 0x7d) { + //DEBUG_LOG("..bad infofield column 7"); + delete[] body; + delete[] d_start; + return false; + } + if (!valid_sym_table_uncompressed(body[7])) { + //DEBUG_LOG("..bad symbol table entry on column 8"); + delete[] body; + delete[] d_start; + return false; + } + + //DEBUG_LOG("\tpassed info format check"); + + /* make a local copy, we're going to modify it */ + strncpy(dstcall, d_start, 6); + dstcall[6] = 0; + + /* First do the destination callsign + * (latitude, message bits, N/S and W/E indicators and long. offset) + * + * Translate the characters to get the latitude + */ + + //fprintf(stderr, "\tuntranslated dstcall: %s\n", dstcall); + for (p = dstcall; *p; p++) { + if (*p >= 'A' && *p <= 'J') + *p -= 'A' - '0'; + else if (*p >= 'P' && *p <= 'Y') + *p -= 'P' - '0'; + else if (*p == 'K' || *p == 'L' || *p == 'Z') + *p = '_'; + } + //fprintf(stderr, "\ttranslated dstcall: %s\n", dstcall); + + // position ambiquity is going to get ignored now, + // it's not needed in this application. + + if (dstcall[5] == '_') { dstcall[5] = '5'; posambiguity = 1; } + if (dstcall[4] == '_') { dstcall[4] = '5'; posambiguity = 2; } + if (dstcall[3] == '_') { dstcall[3] = '5'; posambiguity = 3; } + if (dstcall[2] == '_') { dstcall[2] = '3'; posambiguity = 4; } + if (dstcall[1] == '_' || dstcall[0] == '_') { + //DEBUG_LOG("..bad pos-ambiguity on destcall"); + delete[] body; + delete[] d_start; + return false; + } // cannot use posamb here + + // convert to degrees, minutes and decimal degrees, + // and then to a float lat + + if (sscanf(dstcall, "%2u%2u%2u", + &lat_deg, &lat_min, &lat_min_frag) != 3) { + //DEBUG_LOG("\tsscanf failed"); + delete[] body; + delete[] d_start; + return false; + } + lat = (float)lat_deg + (float)lat_min / 60.0 + (float)lat_min_frag / 6000.0; + + // check the north/south direction and correct the latitude if necessary + if (d_start[3] <= 0x4c) + lat = 0 - lat; + + /* Decode the longitude, the first three bytes of the body + * after the data type indicator. First longitude degrees, + * remember the longitude offset. + */ + lng_deg = body[0] - 28; + if (d_start[4] >= 0x50) + lng_deg += 100; + if (lng_deg >= 180 && lng_deg <= 189) + lng_deg -= 80; + else if (lng_deg >= 190 && lng_deg <= 199) + lng_deg -= 190; + + /* Decode the longitude minutes */ + lng_min = body[1] - 28; + if (lng_min >= 60) + lng_min -= 60; + + /* ... and minute decimals */ + lng_min_frag = body[2] - 28; + + /* apply position ambiguity to longitude */ + switch (posambiguity) { + case 0: + /* use everything */ + lng = (float)lng_deg + (float)lng_min / 60.0 + + (float)lng_min_frag / 6000.0; + break; + case 1: + /* ignore last number of lng_min_frag */ + lng = (float)lng_deg + (float)lng_min / 60.0 + + (float)(lng_min_frag - lng_min_frag % 10 + 5) / 6000.0; + break; + case 2: + /* ignore lng_min_frag */ + lng = (float)lng_deg + ((float)lng_min + 0.5) / 60.0; + break; + case 3: + /* ignore lng_min_frag and last number of lng_min */ + lng = (float)lng_deg + (float)(lng_min - lng_min % 10 + 5) / 60.0; + break; + case 4: + /* minute is unused -> add 0.5 degrees to longitude */ + lng = (float)lng_deg + 0.5; + break; + default: + //DEBUG_LOG(".. posambiguity code BUG!"); + delete[] body; + delete[] d_start; + return false; + } + + /* check the longitude E/W sign */ + if (d_start[5] >= 0x50) + lng = 0 - lng; + + /* save the symbol table and code */ + sym_code = body[6]; + sym_table = body[7]; + + /* ok, we're done */ + /* + fprintf(stderr, "\tlat %u %u.%u (%.4f) lng %u %u.%u (%.4f)\n", + lat_deg, lat_min, lat_min_frag, lat, + lng_deg, lng_min, lng_min_frag, lng); + fprintf(stderr, "\tsym '%c' '%c'\n", sym_table, sym_code); + */ + + + //return pbuf_fill_pos(pb, lat, lng, sym_table, sym_code); + + ///End of APRX original code + packet.Latitude() = lat; + packet.Longitude() = lng; + packet.Symbol() = sym_code; + packet.SymbolTable() = sym_table; + packet.Body() = packet.Body().Mid(9);//if MicE has additional info like heading it'll be longer than 9, ignore for now + + delete[] body; + delete[] d_start; + + return true; +} + +bool CAPRSParser::valid_sym_table_compressed(wxChar c) +{ + return (c == '/' || c == '\\' || (c >= 0x41 && c <= 0x5A) + || (c >= 0x61 && c <= 0x6A)); /* [\/\\A-Za-j] */ +} + +bool CAPRSParser::valid_sym_table_uncompressed(wxChar c) +{ + return (c == '/' || c == '\\' || (c >= 0x41 && c <= 0x5A) + || (c >= 0x30 && c <= 0x39)); /* [\/\\A-Z0-9] */ +} diff --git a/APRSTransmit/APRSParser.h b/APRSTransmit/APRSParser.h new file mode 100644 index 0000000..73683d8 --- /dev/null +++ b/APRSTransmit/APRSParser.h @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2014 by Jonathan Naylor G4KLX + * APRSTransmit Copyright (C) 2015 Geoffrey Merck F4FXL / KC3FRA + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef APRSParserAppD_H +#define APRSParserAppD_H + +#include + +enum APRSPacketType { + APT_Unknown, + APT_Position, + APT_WX, + APT_Object, + APT_Item, + APT_Message, + APT_NMEA +}; + +class CAPRSPacket{ +public : + CAPRSPacket(); + CAPRSPacket(APRSPacketType type, float latitude, float longitude, const wxString& infoText, const wxString raw); + + float& Longitude(); + float& Latitude(); + wxString& SourceCall(); + wxChar& Symbol(); + wxChar& SymbolTable(); + wxChar& TypeChar(); + wxString& DestinationCall(); + wxString& Body(); + wxString& Raw(); + APRSPacketType& Type(); + +private: + APRSPacketType m_type; + float m_latitude; + float m_longitude; + wxChar m_symbol; + wxChar m_symbolTable; + wxChar m_typeChar; + wxString m_body; + wxString m_raw;//raw string in TNC2 format, including '\r' + wxString m_destCall; + wxString m_srcCall; +}; + +class CAPRSParser{ +public: + static bool Parse(const wxString& aprsString, CAPRSPacket& packet); + +private : + static bool valid_sym_table_compressed(wxChar c); + static bool valid_sym_table_uncompressed(wxChar c); + static bool parse_aprs_mice(CAPRSPacket& packet); + + static bool ensureIsIcomCompatible(CAPRSPacket& packet); + static bool stripFrame(wxString& aprsFrame); + static bool preprocessFrame(CAPRSPacket& packet, const wxString& aprsFrame); + static void convertToIcomCompatible(CAPRSPacket& packet); +}; + +#endif diff --git a/APRSTransmit/APRSTransmit.cpp b/APRSTransmit/APRSTransmit.cpp new file mode 100644 index 0000000..e50393d --- /dev/null +++ b/APRSTransmit/APRSTransmit.cpp @@ -0,0 +1,174 @@ +/* + * Copyright (C) 2014 by Jonathan Naylor G4KLX + * APRSTransmit Copyright (C) 2015 Geoffrey Merck F4FXL / KC3FRA + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "SlowDataEncoder.h" +#include "DStarDefines.h" +#include "APRSTransmit.h" +#include "APRSParser.h" + + +CAPRSTransmit::CAPRSTransmit(const wxString& callsign, const wxString& text) : +m_socket(wxEmptyString, 0U), +m_repeaterCallsign(callsign), +m_APRSCallsign(callsign), +m_text(text) +{ + int index = m_text.Find(wxT(">")); + if(index != wxNOT_FOUND) + m_APRSCallsign = m_text.Left(index); +} + +CAPRSTransmit::~CAPRSTransmit() +{ +} + +bool CAPRSTransmit::run() +{ + //First see if the packet is Icom supported... + CAPRSPacket aprsPacket; + if(!CAPRSParser::Parse(m_text, aprsPacket)){ + wxLogWarning(wxT("Unsupported APRS Format, ignoring => ") + m_text.Trim(true)); + return false; + } + + wxString textWithCRC(aprsPacket.Raw()); + wxLogMessage(wxT("Supported APRS Format => ") + textWithCRC.Trim(true)); + //add nececessary stuff to text, but keep it the original + textWithCRC.Replace(wxT("\n"), wxEmptyString); + if(!textWithCRC.EndsWith(wxT("\r"))) textWithCRC.Append(wxT("\r")); + wxString crc = wxString::Format(wxT("$$CRC%04X,"), calcCRC(textWithCRC)); + textWithCRC.Prepend(crc); + + bool opened = m_socket.open(); + if (!opened) + return false; + + in_addr address = CUDPReaderWriter::lookup(wxT("127.0.0.1")); + + unsigned int id = CHeaderData::createId(); + + wxString callsignG = m_repeaterCallsign.Left(LONG_CALLSIGN_LENGTH - 1U); + callsignG.Append(wxT("G")); + + CHeaderData header; + header.setId(id); + header.setMyCall1(m_APRSCallsign); + header.setMyCall2(wxT("APRS")); + header.setRptCall1(callsignG); + header.setRptCall2(m_repeaterCallsign); + header.setYourCall(wxT("CQCQCQ ")); + header.setDestination(address, G2_DV_PORT); + + sendHeader(header); + + CSlowDataEncoder encoder; + encoder.setHeaderData(header); + encoder.setGPSData(textWithCRC); + encoder.setTextData(wxT("APRS to DPRS")); + + CAMBEData data; + data.setDestination(address, G2_DV_PORT); + data.setId(id); + + wxStopWatch timer; + timer.Start(); + + unsigned int out = 0U; + unsigned int dataOut = 0U; + unsigned int needed = (encoder.getInterleavedDataLength() / (DATA_FRAME_LENGTH_BYTES)) * 2U; + + while (dataOut < needed) { + data.setSeq(out); + + unsigned char buffer[DV_FRAME_LENGTH_BYTES]; + ::memcpy(buffer + 0U, NULL_AMBE_DATA_BYTES, VOICE_FRAME_LENGTH_BYTES); + + // Insert sync bytes when the sequence number is zero, slow data otherwise + if (out == 0U) { + ::memcpy(buffer + VOICE_FRAME_LENGTH_BYTES, DATA_SYNC_BYTES, DATA_FRAME_LENGTH_BYTES); + } else { + encoder.getInterleavedData(buffer + VOICE_FRAME_LENGTH_BYTES); + dataOut++; + } + + data.setData(buffer, DV_FRAME_LENGTH_BYTES); + + sendData(data); + out++; + + if (out == 21U) out = 0U; + } + + data.setData(END_PATTERN_BYTES, DV_FRAME_LENGTH_BYTES); + data.setSeq(out >= 21U ? 0U : out); + data.setEnd(true); + + sendData(data); + + m_socket.close(); + + return true; +} + +bool CAPRSTransmit::sendHeader(const CHeaderData& header) +{ + unsigned char buffer[60U]; + unsigned int length = header.getG2Data(buffer, 60U, true); + + for (unsigned int i = 0U; i < 2U; i++) { + bool res = m_socket.write(buffer, length, header.getYourAddress(), header.getYourPort()); + if (!res) + return false; + } + + return true; +} + +bool CAPRSTransmit::sendData(const CAMBEData& data) +{ + unsigned char buffer[60U]; + unsigned int length = data.getG2Data(buffer, 60U); + + return m_socket.write(buffer, length, data.getYourAddress(), data.getYourPort()); +} + +unsigned int CAPRSTransmit::calcCRC(const wxString& gpsData) +{ + size_t length = gpsData.length(); + wxASSERT(length > 0U); + + unsigned int icomcrc = 0xFFFFU; + + for (unsigned int j = 0U; j < length; j++) { + unsigned char ch = gpsData.GetChar(j); + + for (unsigned int i = 0U; i < 8U; i++) { + bool xorflag = (((icomcrc ^ ch) & 0x01U) == 0x01U); + + icomcrc >>= 1; + + if (xorflag) + icomcrc ^= 0x8408U; + + ch >>= 1; + } + } + + return ~icomcrc & 0xFFFFU; +} diff --git a/APRSTransmit/APRSTransmit.h b/APRSTransmit/APRSTransmit.h new file mode 100644 index 0000000..f24987c --- /dev/null +++ b/APRSTransmit/APRSTransmit.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2014 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef TextTransmit_H +#define TextTransmit_H + +#include "UDPReaderWriter.h" +#include "HeaderData.h" +#include "AMBEData.h" + +class CAPRSTransmit { +public: + CAPRSTransmit(const wxString& callsign, const wxString& text); + ~CAPRSTransmit(); + + bool run(); + +private: + CUDPReaderWriter m_socket; + wxString m_repeaterCallsign; + wxString m_APRSCallsign; + wxString m_text; + + bool sendHeader(const CHeaderData& header); + bool sendData(const CAMBEData& data); + unsigned int calcCRC(const wxString& gpsData); +}; + +#endif diff --git a/APRSTransmit/APRSTransmit.vcxproj b/APRSTransmit/APRSTransmit.vcxproj new file mode 100644 index 0000000..96a54ae --- /dev/null +++ b/APRSTransmit/APRSTransmit.vcxproj @@ -0,0 +1,188 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {F26EA1DB-74CF-4C52-A425-00235C8ABED2} + APRSTransmit + Win32Proj + 10.0.16299.0 + + + + Application + v141 + Unicode + true + + + Application + v141 + Unicode + true + + + Application + v141 + Unicode + + + Application + v141 + Unicode + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>14.0.24720.0 + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\$(ProjectName) + true + $(WXWIN)\include;$(WXWIN)\lib\vc_dll\mswud;$(IncludePath) + + + true + $(WXWIN)\include;$(WXWIN)\lib\vc_x64_dll\mswud;$(IncludePath) + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\$(ProjectName) + false + + + false + + + + Disabled + $(WXWIN)\include\msvc;$(WXWIN)\include;../Common;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;WINVER=0x0400;__WXMSW__;WXUSINGDLL;wxUSE_GUI=1;__WXDEBUG__;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATEWIN32;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + Level3 + EditAndContinue + + + ws2_32.lib;%(AdditionalDependencies) + $(WXWIN)\lib\vc_dll;%(AdditionalLibraryDirectories) + true + Console + MachineX86 + + + + + Disabled + $(WXWIN)\include\msvc;$(WXWIN)\include;../Common;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;WINVER=0x0400;__WXMSW__;WXUSINGDLL;wxUSE_GUI=1;__WXDEBUG__;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATEWIN32;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + + + Level3 + ProgramDatabase + + + ws2_32.lib;%(AdditionalDependencies) + $(WXWIN)\lib\vc_x64_dll;%(AdditionalLibraryDirectories) + true + Console + + + + + MaxSpeed + true + $(WXWIN)\include\msvc;$(WXWIN)\include;../ircDDB;../Common;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;WINVER=0x0400;__WXMSW__;WXUSINGDLL;wxUSE_GUI=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) + MultiThreadedDLL + true + + Level3 + ProgramDatabase + + + ws2_32.lib;%(AdditionalDependencies) + $(WXWIN)\lib\vc_dll;%(AdditionalLibraryDirectories) + true + Console + true + true + MachineX86 + + + + + MaxSpeed + true + $(WXWIN)\include\msvc;$(WXWIN)\include;../ircDDB;../Common;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;WINVER=0x0400;__WXMSW__;WXUSINGDLL;wxUSE_GUI=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) + MultiThreadedDLL + true + + + Level3 + ProgramDatabase + + + ws2_32.lib;%(AdditionalDependencies) + $(WXWIN)\lib\vc_x64_dll;%(AdditionalLibraryDirectories) + true + Console + true + true + + + + + + + + + + + + + + {e793cb8e-2ac9-431a-bbfc-3f52537bb3cf} + false + + + + + + \ No newline at end of file diff --git a/APRSTransmit/APRSTransmit.vcxproj.filters b/APRSTransmit/APRSTransmit.vcxproj.filters new file mode 100644 index 0000000..afc4767 --- /dev/null +++ b/APRSTransmit/APRSTransmit.vcxproj.filters @@ -0,0 +1,32 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/APRSTransmit/APRSTransmitApp.cpp b/APRSTransmit/APRSTransmitApp.cpp new file mode 100644 index 0000000..86c580b --- /dev/null +++ b/APRSTransmit/APRSTransmitApp.cpp @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2014 by Jonathan Naylor G4KLX + * APRSTransmit Copyright (C) 2015 Geoffrey Merck F4FXL / KC3FRA + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "DStarDefines.h" +#include "APRSTransmit.h" + +#include +#include + +const wxChar* REPEATER_PARAM = wxT("Repeater"); +const wxChar* FILE_OPTION = wxT("file"); +const wxChar* APRS_OPTION = wxT("aprs"); + +int main(int argc, char** argv) +{ + bool res = ::wxInitialize(); + if (!res) { + ::fprintf(stderr, "aprstransmit: failed to initialise the wxWidgets library, exiting\n"); + return 1; + } + + wxCmdLineParser parser(argc, argv); + parser.AddParam(REPEATER_PARAM, wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL); + parser.AddOption(APRS_OPTION, wxEmptyString, wxEmptyString, wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL); + parser.AddOption(FILE_OPTION, wxEmptyString, wxEmptyString, wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL); + + int cmd = parser.Parse(); + if (cmd != 0) { + ::wxUninitialize(); + return 1; + } + + if (parser.GetParamCount() < 1U) { + ::fprintf(stderr, "aprstransmit: invalid command line usage: aprstransmit -aprs |-file , exiting\n"); + ::wxUninitialize(); + return 1; + } + + wxString text; + bool aprsFound = parser.Found(APRS_OPTION, &text); + + wxString filename; + bool fileFound = parser.Found(FILE_OPTION, &filename); + + if (!aprsFound && !fileFound) { + ::fprintf(stderr, "aprstransmit: invalid command line usage: aprstransmit -aprs |-file , exiting\n"); + ::wxUninitialize(); + return 1; + } + + if (aprsFound && fileFound) { + ::fprintf(stderr, "aprstransmit: invalid command line usage: aprstransmit -aprs |-file , exiting\n"); + ::wxUninitialize(); + return 1; + } + + wxString repeater = parser.GetParam(0U); + repeater.Replace(wxT("_"), wxT(" ")); + repeater.resize(LONG_CALLSIGN_LENGTH, wxT(' ')); + repeater.MakeUpper(); + + if (fileFound) { + wxTextFile file; + bool found = file.Open(filename); + if (!found) { + ::fprintf(stderr, "aprstransmit: unable to open the file, exiting\n"); + ::wxUninitialize(); + return 1; + } + + text = file.GetFirstLine(); + + file.Close(); + } + + + CAPRSTransmit tt(repeater, text); + bool ret = tt.run(); + + ::wxUninitialize(); + + return ret ? 0 : 1; +} + diff --git a/APRSTransmit/APRSTransmitAppD.cpp b/APRSTransmit/APRSTransmitAppD.cpp new file mode 100644 index 0000000..60f18aa --- /dev/null +++ b/APRSTransmit/APRSTransmitAppD.cpp @@ -0,0 +1,272 @@ +/* + * Copyright (C) 2014 by Jonathan Naylor G4KLX + * APRSTransmit Copyright (C) 2015 Geoffrey Merck F4FXL / KC3FRA + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "DStarDefines.h" +#include "APRSTransmit.h" +#include "APRSTransmitAppD.h" +#include "APRSWriterThread.h" + +#include +#include +#include +#include + +#if defined(__WINDOWS__) +#include +#include +#endif + +const wxChar* REPEATER_PARAM = wxT("Repeater"); +const wxChar* APRS_HOST = wxT("host"); +const wxChar* APRS_PORT = wxT("port"); +const wxChar* APRS_FILTER = wxT("filter"); +const wxChar* DAEMON_SWITCH = wxT("daemon"); + +static CAPRSTransmitAppD* m_aprsTransmit = NULL; + +static void handler(int signum) +{ + m_aprsTransmit->kill(); +} + +static void aprsFrameCallback(const wxString& aprsFrame) +{ + //wxLogMessage(wxT("Received APRS Frame : ") + aprsFrame); + m_aprsTransmit->m_aprsFramesQueue->addData(new wxString(aprsFrame.Clone())); +} + +int main(int argc, char** argv) +{ + bool res = ::wxInitialize(); + if (!res) { + ::fprintf(stderr, "aprstransmit: failed to initialise the wxWidgets library, exiting\n"); + return 1; + } + + wxCmdLineParser parser(argc, argv); + parser.AddParam(REPEATER_PARAM, wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL); + parser.AddOption(APRS_HOST, wxEmptyString, wxEmptyString, wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL); + parser.AddOption(APRS_PORT, wxEmptyString, wxEmptyString, wxCMD_LINE_VAL_NUMBER, wxCMD_LINE_PARAM_OPTIONAL); + parser.AddOption(APRS_FILTER, wxEmptyString, wxEmptyString, wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL); + parser.AddSwitch(DAEMON_SWITCH, wxEmptyString, wxEmptyString, wxCMD_LINE_PARAM_OPTIONAL); + + int cmd = parser.Parse(); + if (cmd != 0) { + ::wxUninitialize(); + return 1; + } + + if (parser.GetParamCount() < 1U) { + ::fprintf(stderr, "aprstransmitd: invalid command line usage: aprstransmitd [-host ] [-port ] [-filter [;init()) { + ::wxUninitialize(); + return 1; + } +#else + if (daemon) { + pid_t pid = ::fork(); + + if (pid < 0) { + ::fprintf(stderr, "aprstransmitd: error in fork(), exiting\n"); + ::wxUninitialize(); + return 1; + } + + // If this is the parent, exit + if (pid > 0) + return 0; + + // We are the child from here onwards + ::setsid(); + ::chdir("/"); + ::umask(0); + } + + //create a pid file + wxString pidFileName = wxT("/var/run/aprstransmit.pid"); + FILE* fp = ::fopen(pidFileName.mb_str(), "wt"); + if (fp != NULL) { + ::fprintf(fp, "%u\n", ::getpid()); + ::fclose(fp); + } + + m_aprsTransmit = new CAPRSTransmitAppD(repeater, aprsHost, aprsPort, aprsFilter, daemon); + if (!m_aprsTransmit->init()) { + ::wxUninitialize(); + return 1; + } + + ::signal(SIGUSR1, handler); + + + ::unlink(pidFileName.mb_str()); +#endif + m_aprsTransmit->run(); + delete m_aprsTransmit; + ::wxUninitialize(); + return 0; +} + + + +CAPRSTransmitAppD::CAPRSTransmitAppD(const wxString& repeater, const wxString& aprsHost, unsigned int aprsPort, const wxString& aprsFilter, bool daemon) : +m_aprsFramesQueue(NULL), +m_repeater(repeater), +m_aprsHost(aprsHost), +m_aprsFilter(aprsFilter), +m_aprsPort(aprsPort), +m_aprsThread(NULL), +m_run(false), +m_checker(NULL), +m_daemon(daemon) +{ +} + +CAPRSTransmitAppD::~CAPRSTransmitAppD() +{ + cleanup(); +} + + +bool CAPRSTransmitAppD::init() +{ +#if defined(__WINDOWS__) + wxString tempPath = wxFileName::GetTempDir(); + m_checker = new wxSingleInstanceChecker(wxT("aprstransmit"), tempPath); +#else + m_checker = new wxSingleInstanceChecker(wxT("aprstransmit"), wxT("/tmp")); +#endif + bool ret = m_checker->IsAnotherRunning(); + if (ret) { + wxLogError(wxT("Another copy of APRSTransmit is running, exiting")); + return false; + } + +#if defined(__WINDOWS__) + wxLog* logger = new wxLogStream(&std::cout); + wxLog::SetActiveTarget(logger); + wxLog::SetLogLevel(wxLOG_Message); + if(m_daemon) + wxLogMessage(wxT("Daemon not supported under Windows, ignoring")); + m_daemon = false; +#else + if(!m_daemon){ + wxLog* logger = new wxLogStream(&std::cout); + wxLog::SetActiveTarget(logger); + wxLog::SetLogLevel(wxLOG_Message); + } else { + new wxLogNull; + } +#endif + + return true; +} + +void CAPRSTransmitAppD::run() +{ + if(m_run) return; + + m_aprsFramesQueue = new CRingBuffer(30U); + m_aprsThread = new CAPRSWriterThread(m_repeater, wxT("0.0.0.0"), m_aprsHost, m_aprsPort, m_aprsFilter, wxT("APRSTransmit 1.1")); + m_aprsThread->setReadAPRSCallback(aprsFrameCallback); + m_aprsThread->start(); + + wxString * aprsFrame; + + m_run = true; + while(m_run){ + wxMilliSleep(10U); + aprsFrame = m_aprsFramesQueue->getData(); + if(aprsFrame){ + CAPRSTransmit aprsTransmit(m_repeater, wxString(*aprsFrame)); + aprsTransmit.run(); + delete aprsFrame; + } + } + + m_aprsThread->stop(); + + cleanup(); +} + + +void CAPRSTransmitAppD::cleanup() +{ + m_aprsThread->setReadAPRSCallback(NULL); + + if(m_aprsFramesQueue) + { + while(m_aprsFramesQueue->peek()) delete m_aprsFramesQueue->getData(); + delete m_aprsFramesQueue; + m_aprsFramesQueue = NULL; + } + if(m_checker) { + delete m_checker; + m_checker = NULL; + } + + if(m_aprsThread) + { + delete m_aprsThread; + m_aprsThread = NULL; + } +} + +void CAPRSTransmitAppD::kill() +{ + m_run = false; +} + diff --git a/APRSTransmit/APRSTransmitAppD.h b/APRSTransmit/APRSTransmitAppD.h new file mode 100644 index 0000000..815a16b --- /dev/null +++ b/APRSTransmit/APRSTransmitAppD.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2014 by Jonathan Naylor G4KLX + * APRSTransmit Copyright (C) 2015 Geoffrey Merck F4FXL / KC3FRA + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef APRSTransmitAppD_H +#define APRSTransmitAppD_H + +#include "RingBuffer.h" +#include "APRSWriterThread.h" + +#include +#include +#include + + +class CAPRSTransmitAppD { + +public: + CAPRSTransmitAppD(const wxString& repeater, const wxString& aprsHost, unsigned int aprsPort, const wxString& aprsFilter, bool daemon); + ~CAPRSTransmitAppD(); + + CRingBuffer * m_aprsFramesQueue; + + bool init(); + void run(); + void kill(); + +private: + wxString m_repeater, m_aprsHost, m_aprsFilter; + unsigned int m_aprsPort; + CAPRSWriterThread * m_aprsThread; + bool m_run; + wxSingleInstanceChecker * m_checker; + bool m_daemon; + + void cleanup(); +}; + +#endif diff --git a/APRSTransmit/APRSTransmitD.vcxproj b/APRSTransmit/APRSTransmitD.vcxproj new file mode 100644 index 0000000..7c3486c --- /dev/null +++ b/APRSTransmit/APRSTransmitD.vcxproj @@ -0,0 +1,189 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {C706EF5D-3917-4796-8BEB-823498A1B13C} + APRSTransmit + Win32Proj + 10.0.16299.0 + + + + Application + v141 + Unicode + true + + + Application + v141 + Unicode + true + + + Application + v141 + Unicode + + + Application + v141 + Unicode + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>14.0.24720.0 + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\$(ProjectName)\ + true + $(WXWIN)\include;$(WXWIN)\lib\vc_dll\mswud;$(IncludePath) + + + true + $(WXWIN)\include;$(WXWIN)\lib\vc_dll\mswud;$(IncludePath) + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\$(ProjectName)\ + false + + + false + + + + Disabled + $(WXWIN)\include\msvc;$(WXWIN)\include;../Common;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;WINVER=0x0400;__WXMSW__;WXUSINGDLL;wxUSE_GUI=1;__WXDEBUG__;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATEWIN32;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + Level3 + EditAndContinue + + + ws2_32.lib;%(AdditionalDependencies) + $(WXWIN)\lib\vc_dll;%(AdditionalLibraryDirectories) + true + Console + MachineX86 + + + + + Disabled + $(WXWIN)\include\msvc;$(WXWIN)\include;../Common;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;WINVER=0x0400;__WXMSW__;WXUSINGDLL;wxUSE_GUI=1;__WXDEBUG__;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATEWIN32;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + + + Level3 + ProgramDatabase + + + ws2_32.lib;%(AdditionalDependencies) + $(WXWIN)\lib\vc_x64_dll;%(AdditionalLibraryDirectories) + true + Console + + + + + MaxSpeed + true + $(WXWIN)\include\msvc;$(WXWIN)\include;../ircDDB;../Common;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;WINVER=0x0400;__WXMSW__;WXUSINGDLL;wxUSE_GUI=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) + MultiThreadedDLL + true + + Level3 + ProgramDatabase + + + ws2_32.lib;%(AdditionalDependencies) + $(WXWIN)\lib\vc_dll;%(AdditionalLibraryDirectories) + true + Console + true + true + MachineX86 + + + + + MaxSpeed + true + $(WXWIN)\include\msvc;$(WXWIN)\include;../ircDDB;../Common;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;WINVER=0x0400;__WXMSW__;WXUSINGDLL;wxUSE_GUI=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) + MultiThreadedDLL + true + + + Level3 + ProgramDatabase + + + ws2_32.lib;%(AdditionalDependencies) + $(WXWIN)\lib\vc_x64_dll;%(AdditionalLibraryDirectories) + true + Console + true + true + + + + + + + + + + + + + + + {e793cb8e-2ac9-431a-bbfc-3f52537bb3cf} + false + + + + + + \ No newline at end of file diff --git a/APRSTransmit/APRSTransmitD.vcxproj.filters b/APRSTransmit/APRSTransmitD.vcxproj.filters new file mode 100644 index 0000000..7910ae4 --- /dev/null +++ b/APRSTransmit/APRSTransmitD.vcxproj.filters @@ -0,0 +1,35 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/CHANGES.txt b/CHANGES.txt new file mode 100644 index 0000000..4f15778 --- /dev/null +++ b/CHANGES.txt @@ -0,0 +1,1478 @@ +ircDDB Gateway - 20180509 +========================= + +20101010 +-------- + +First preview release, lots of bugs left. +CIRCDDB v0.3. + +20101017 +-------- + +Lots of bugs fixed. +Linking to a reflector at startup is now implemented. +Implemented reflector linking at startup. +CIRCDDB v0.4. + +20101018 +-------- + +Initial Linux support. +Drop links on gateway exit. +CIRCDDB v0.4. + +20101023 +-------- + +Incoming DExtra links should now work. +The GUI shows the last ten lines of the log. +Began support for Icom RP2C controller. +Added local cross-band RPT2 routing. +CIRCDDB v0.4.2. + +20101024 +-------- + +First version of Icom RP2C controller support. +Not generally released. + +20101024a +--------- + +Completed Icom RP2C support. + +20101026 +-------- + +Implemented the reconnect timer. +Added language option for the slow data in the ack. +Added German and Danish. + +20101028 +-------- + +Fixed bugs in the 20101026 beta release. +Implemented a proper stop-and-wait protocol handler for communicating with Icom RP2C controllers. +Log ircDDB connection status. +CIRCDDB v1.0. + +20101031 +-------- + +Small changes and bug fixes here and there. + +20101101 +-------- + +Small changes and bug fixes here and there. + +20101101a +--------- + +Small changes and bug fixes here and there. +Added French and Italian translations for the ack text. + +20101102 +-------- + +Added status file for active links for web GUIs. + +20101105 +-------- + +Added -gui command line flag to switch the GUI on. +Recognise another DPlus packet type. +Create a header status file. + +20101107 +-------- + +Added the slow data export UDP socket, details in Usage.txt. +On Linux the PID of the main process is written to /var/run/ircDDBG.pid. +Various bugs fixed. + +20101109 +-------- + +More changes in the Icom RP2C support. + +20101112 +-------- + +All logging under Linux is now in /var/log. +Can force unlinking when the reconnect timer has expired and the reflector is . +More changes to the Icom controller support. + +20101113 +-------- + +Fixed a Linux compile bug. +Invalid cross-band routing is handled nicely. +More work on the Icom controller support. + +20101114 +-------- + +Slight change to the German text for length reasons. +Upgraded the GUI display. +More changes to the Icom support. + +20101117 +-------- + +Clean-up the GUI more. +Add another repeater port and allow for port letter D. +Allow all eight characters for the D-Plus login callsign. +Allow the cache to be written at program exit and re-read when it starts up. +On Icom systems, the ack is generated by the gateway and includes the link state. + +20101118 +-------- + +Removed the cache reading and writing at program start and stop repsectively. +Removed the intelligent ack for Icom systems, they don't seem to like it! + +20101119 +-------- + +Stop gateways from connecting as Dongle users. +More Icom controller changes. +GUI changes for Linux. + +20101127 +-------- + +Added acks for multi-port Icom repeater systems. +Added a UDP port to export all incoming repeater data to. +Removed the slow data UDP port. +Added D-PRS support. +Not generally released. + +20101128 +-------- + +Changed APRS connection to TCP from UDP. +Updated the IP address for XRF008 in DExtra_Hosts.txt. +The repeaters announce themselves via APRS. + +20101201 +-------- + +Put the APRS writing into a thread to improve performance. +Allow Dongle users to hear and be heard over the network. +More Icom controller changes. + +20101203 +-------- + +Handle some odd APRS cases for the repeater locations. +Relax incoming repeater validation to allow CLI tools. +Don't send data to Dongles that are sending the data. + +20101203a +--------- + +Changed to wxWidgets 2.8.11. +Fixed startup with blank entries. + +20101204 +-------- + +Added the Polish language to the ack text. +Changed the Dongle handling to pass all radio audio. +Fixed nasty bug in the DExtra code. + +20101205 +-------- + +Added new ircDDB feature to record the destination and text data. +Added new ircDDB feature to record statistics, but they're not complete yet. +Changed repeater APRS description to be the frequency and offset. +CIRCDDB 1.1. + +20101208 +-------- + +Increased the precision of the latitude and longitude values. +Changed to a new extension protocol to pass data to/from a repeater. +Collect extra statistics. + +20101215 +-------- + +Stop duplicate link requests to the same reflector module. +Display Dongle connections in the GUI. +Upgraded the DPlus handling. +Added the XRF055 reflector. + +20101217 +-------- + +More DPlus changes. + +20110103 +-------- + +Create the /usr/local/etc and /usr/local/bin directories at install time if they don't already exist. +Changed APRS login to be the gateway callsign including the "-G". +Added XRF019, XRF026, XRF027 and XRF044 to DExtra_Hosts.txt. +Added the latest DPlus_Hosts.txt file. + +20110104 +-------- + +Fixed the APRS login. + +20110105 +-------- + +Fixed a bug in the G2 callsign routing when the last letter wasn't blank. + +20110119 +-------- + +Registers with the Dutch*Star DPNS system. +Allow incoming DPlus Dongle links. +Added XRF000 to DExtra_Hosts.txt. + +20110119a +--------- + +More work on DPNS registration. + +20110120 +-------- + +Upgraded the DExtra Dongle support. +More changes to the DPlus protocol. + +20110121 +-------- + +Fixed incoming DPlus callsign mapping. + +20110124 +-------- + +Program no longer overwrites the DPlus_Hosts.txt file on startup. +More DPlus changes to DPNS and port handling. +Commands "E" and "I" are now reserved. + +20110127 +-------- + +The echo command has now been implemented. +Make use of the new DExtra type byte. +Fixed DPlus incoming links, but repeater ports may need changing. + +20110128 +-------- + +Fixed the echo command. + +20110130 +-------- + +Changed the echo replay timing to remove jitter. + +20110201 +-------- + +More echo jitter removal. +The "T" command is now reserved. +Change the UR callsign for the echo reply. + +20110206 +-------- + +Remove the "T" command. +Stop XRF reflectors coming from DPlus going into the cache. +Only write entries from opendstar.org into the cache. +Added the info command with English and German voice files. +Changed the default ports for the gateway and repeaters. + +20110208 +-------- + +Fixed bugs in the audio unit. +Added US English as an option. +Added pauses between phrases and letter/numbers. + +20110213 +-------- + +Improved audio and index files for German, and UK and US English. +Added audio and index files for Italian, French, and Danish. +When connecting to a reflector an audio announcement is made automatically. + +20110215 +-------- + +Allow the Echo and Info command to be disabled. +Swap the RPT1 and RPT2 callsigns for incoming DPlus links. +Added XRF020 to the DExtra_Hosts.txt file. +Added slow data link information to the Info reply. +Info is returned every time a link command is issued, if enabled. + +20110215a +--------- + +Fixed a bug in the info command slow data. +Fixed a bug with headers disrupting DPlus and DExtra links. + +20110215b +--------- + +Fixed Linux compilation bug. + +20110216 +-------- + +Re-swap the DPlus RPT1 and RPT2 callsigns for incoming DPlus links. + +20110219 +-------- + +Fixed the en_US.indx file for the letter X. +Clear the APRS queue if new data arrives. +Allow for linking protocol locking by using the DPlus_Hosts.txt and DExtra_Hosts.txt files. +Added Spanish and Swedish translations. + +20110222 +-------- + +The reconnect timer is now only reset by local RF users. + +20110226 +-------- + +The reconnect timer now includes 60, 90, and 120 minute values. +Reconnect timer works properly with a reflector entry of None. + +20110306 +-------- + +Added daily logs. +Added D-RATS support. +Remove Links.log at startup. +Added XRF007 to the DExtra_Hosts.txt file. + +20110308 +-------- + +Added the -logdir command line option to change the logging directory. +Added XRF021 to the DExtra_Hosts.txt file. + +20110312 +-------- + +Truncate Links.log instead of deleting it at startup. +Fix DPlus being disabled. +Added extra validation to link requests. + +20110313 +-------- + +Added Polish to the Info command. +Updated IP address of XRF008. + +20110315 +-------- + +Networking changes. + +20110320 +-------- + +First version of StarNet. +Not generally released. + +20110320a +--------- + +Bug fixes to StarNet. +Not generally released. + +20110324 +-------- + +Changes to StarNet. +Not generally released. + +20110329 +-------- + +Changes to StarNet. +Not generally released. + +20110330 +-------- + +Allow hostnames in DExtra_Hosts.txt and DPlus_Hosts.txt. +More changes to StarNet. +Not generally released. + +20110404 +-------- + +Beginnings of Icom DD support. +Added two extra StarNet Groups to the configuration. + +20110407 +-------- + +Restructured the source code. +Added the StarNetServer. +Heard message for the StarNet groups now includes the information text. +StarNet headers now appear in the Headers.log if enabled. + +20110409 +-------- + +Fixed reflector relinking when the link fails. +More work on DD support. +Added optional DExtra Link to StarNet. + +20110410 +-------- + +Fixed compilation under Linux when DEXTRA_LINK is defined. + +20110415 +-------- + +Changed from wxWidgets 2.8.11 to 2.8.12. +Added an extra callsign field for StarNet groups to allow a callsign to be used to log off. +Allow StarNet logins, logoffs and info requests when relaying other data. + +20110417 +-------- + +Added the optional StarNet.log to contain StarNet group activity. +Sanitise incoming reflector headers to fix problems created elsewhere. + +20110417a +--------- + +Allow StarNet Server to bind to one IP address. +Not generally released. + +20110419 +-------- + +Added XRF033. +Updated the IP address of XRF013. +The -logdir option works for the output GUI logs too. +Improve the STARnet branding wherever possible. + +20110506 +-------- + +Added XRF031. +Updated the IP address of XRF021 +Randomised the ids of locally generated data. +Increased the delay for sending STARnet control messages. +Removed incoming port restriction for incoming DExtra links. +Increased the number of groups in the StarNet Server from 10 to 15. +First version of the XReflector DExtra/Dplus reflector. + +20110507 +-------- + +Fixed Links.log and added Headers.log to XReflector. +Updated XReflector DPNS registering with additional data. + +20110507a +--------- + +Changed the format of Links.log slightly. +Added -daemon option to create proper daemons on Linux. + +20110511 +-------- + +Special debug version for testing DD mode support. +Not generally released. + +20110512 +-------- + +Added the -confdir option to the daemon versions of the programs. +First version of DD support. + +20110513 +-------- + +Updates to the DD support. +Fixed the reconnect bug in DExtra. +Updated the IP address of XRF020. + +20110523 +-------- + +Upgraded CIRCDDB to v1.2. +Added extra logging when log files cannot be opened. +Extra configuration entries for a description, URL and height above ground level added for QRG & Maps. +Add switches to disable APRS and DExtra. + +20110525 +-------- + +Store and transmit more decimals for the frequency setting(s). +Explicit setting of the DD mode port is now used. +Use the ircDDB watchdog with the software version (repeater 20110525 and newer needed). + +20110529 +-------- + +Improved the software version reporting for Icom controllers and the gateway. + +20110603 +-------- + +Changed "Description" to "QTH" in the gateway configuration tab. +Removed "ircDDB Gateway" as the default first line of the QTH. +Switch off DD mode when not set on one of the repeaters. +Changes to DD mode to fix a crash and short ethernet packets. +Not generally released. + +20110606 +-------- + +Found the bug that suppressed the login and logoff STARnet confirmations. + +20110619 +-------- + +The new Remote Control application has been created to control the ircDDB Gateway and the STARnet Server. + +20110621 +-------- + +Clean-ups and minor fixes for the Remote Control application. + +20110622 +-------- + +Added an optional name to the Remote Control application. +Removed some logging statements. +Added extra user logging to XReflector. +Increased frequency of D-Plus authentication and IP address refreshing. + +20110627 +-------- + +Extra logging to XReflector for user logging. +Removed and simplified internal functions. + +20110629 +-------- + +CIRCDDB v1.2.2. + +20110702 +-------- + +CIRCDDB v1.2.3. + +20110704 +-------- + +Upgraded the APRS reporting of the repeater ports. +Changed DD mode repeater configuration. +Added XRF028. + +20110706 +-------- + +Cleaned up the GUI a bit. +Reverted a change to the XReflector GUI logs. +Fixed Remote Control with DD repeaters. + +20110713 +-------- + +You can now mix homebrew and Icom repeaters on one gateway. +ircDDB queries now have a five second timeout. +Update XRF033. + +20110719 +-------- + +Added Nederlands (NL) and Nederlands (BE) as slow text language options. +Fixed many memory leaks identified by valgrind. +Fixed ircDDB query timer bug. + +20110808 +-------- + +Added debug flags to Linux builds for bug tracking. +Make internal timers more accurate. +Updated to CIRCDDB 1.2.4. + +20110815 +-------- + +Made the Remote Control protocol to be processor independent. +Added wxWidgets and OS version logging to all programs. +Identify as KLX-ware to the DPNS. +Fixed long timeouts with the timer class. +Handle error returns from ircDDB better. + +20110817 +-------- + +Fixed bug in DExtra Link introduced in the last release. + +20110907 +-------- + +Added XRF073. +Removed the Repeater Tap. +Added the MYCALL and TX Msg switches for each STARnet Group. + +20110918 +-------- + +Changed the TX Msg Switch default to true. +Changed XRF002 IP address. +Changed XRF073 IP address. +Added extra DD mode log file. + +20110922 +-------- + +Added timer to DD mode ircDDB reporting, to reduce the amount of traffic. +Not generally relased. + +20110923 +-------- + +More DD mode changes for ircDDB visualisation. + +20111006 +-------- + +Restored the English (US) voice for the info command. +Added XRF069. + +20111022 +-------- + +Updated XRF069 IP address. +Changes to the repeater to gateway protocol. + +20111102 +-------- + +Added XRF123. +The default log directory is now the home directory under Linux. + +20111107 +-------- + +Loosen the internal timing of the gateway. +Added support for reporting private statuses. + +20111112 +-------- + +Found and fixed R2D2 bug. + +20111120 +-------- + +Allow different callsigns to be used for the repeaters. +Updated the D-Plus hosts file. +Updated XRF069 IP address. +Added XRF038. + +20111122 +-------- + +Updated XRF002 IP address. +Removed alternative callsign entry in the GUI. +Added remote script access changes to the remote control system, tnx DL5DI. + +20111125 +-------- + +Internal clean-ups. + +20111126 +-------- + +Fixed bug in APRS reporting of short repeater callsigns. +Changed timing of the audio and echo units. + +20111204 +-------- + +Allow linking commands when a repeater is busy with network traffic. +Enable D-Plus debug mode. +Change for the Echo and Info commands. + +20111205 +-------- + +Large changes to the Echo and Info commands. + +20111207 +-------- + +Allow for the setting of latitude and longitude per repeater. +Allow for the setting of the maximum number of incoming D-Plus and DExtra dongle links. +Allow up to five status messages. +A change in the link status will generate an INFO message if enabled. + +20111209 +-------- + +Pass more information to the repeaters about the link status. +More INFO messages generated on link status changes. +Reverted the English audio changes. +Updated XRF019s IP address. + +20111212 +-------- + +Remove the USAGE.txt file. +Clean up callsign configuration. + +20111218 +-------- + +Added Timer Control application and daemon. + +20111220 +-------- + +Fixed DExtra bug. + +20111223 +-------- + +Updated XRF031s IP address. + +20111231 +-------- + +Allow linking to reflectors with channel E on D-Plus and DExtra. +Added channel E to the XReflector. +Send an end of transmission to the repeater when unlinking from a live reflector. + +20120109 +-------- + +Remove all channel letter restrictions for linking in the gateway. +Removed DPNS support from XReflector, it isn't being used by the DPNS for some reason. +Improved user logging in XReflector. +Added slow data text logging in XReflector. +Added XRF119. + +20120117 +-------- + +Reduce the rate that DD-mode headers are written out to Headers.log. +Updated the Makefiles to handle library dependencies properly. +Updated XRF033s IP address. +Replace the bundled DPlus_Hosts.txt with a new and reduced length one. + +20120125 +-------- + +Added 180 minutes as maximum time for gateway control. +Upgrades to the APRS gating to fully match the specification. +Added GPS mode gating to APRS. +Updated XRF019s IP address. +Added XRF110. + +20120129 +-------- + +Changes to GPS and GPS-A mode to handle malformed data. +Change the relinking behaviour when the link fails. + +20120131 +-------- + +Increase minimum time for consecutive APRS packets to be sent out. +More work on relinking DExtra and D-Plus outgoing links. +More aggressive initialisation of misbehaving Icom RP2C controllers. +Added XRF040. + +20120207 +-------- + +Change in the configuration system for non-Windows platforms. +Convert ircDDB hostname to a drop-down list. + +20120210 +-------- + +Send QRG and range to ircDDB even if the range is zero (DVAP?). +Updated XRF021s IP address. +Small cleanups. + +20120222 +-------- + +Removed the port number from the ircDDB preferences panel. +Added DTMF commands for reflector linking and unlinking. +Updated XRF069s IP address. +Updated the D-Plus host file. + +20120223 +-------- + +Allow for the disabling of DTMF decoding and blanking in the ircDDB Gateway. +Supress DTMF decoding and blanking on crossband traffic. +Hopefully fix D-Plus doubling issue in the ircDDB Gateway and XReflector. + +20120225 +-------- + +Fix any potential problems with doubling with DExtra links. +Fixed XReflector D-Plus user.log format, it was in the wrong order. +Reduce false triggering of the DTMF system by noisy signals. +Validate links to DExtra and D-Plus reflectors at the time of the command. + +20120228 +-------- + +Restore GUI window position on startup. +Allow background DTMF control. +New repeater to gateway protocol implemented. + +20120229 +-------- + +Fixes for background DTMF handling. +Added extra logging and error handling to the XReflector. + +20120302 +-------- + +More changes to the D-Plus support in the XReflector. +Similar changes to the D-Plus support in the gateway. + +20120309 +-------- + +Added repeater watchdog timer to handle poor repeater links. +Updated XRF021s and XRF044s IP address. +Added XRF222, XRF353, and XRF777. +Added support for the new DCS reflector system. +Use dns.xreflector.net to get XRF and DCS reflector IP addresses. + +20120311 +-------- + +Process heard messages from Icom controllers. +Fixed Links.log file updating for DCS. + +20120313 +-------- + +Fall back to the altenate xreflector DNS if the main one fails. +Revert Icom repeater protocol handler change from 20120131. +Extra error handling in XReflector added. +Repeat the repeater header every 21 frames for reliability. +Disable XReflector DNS for DCS reflectors for now. + +20120314 +-------- + +Fix the header repeating for Icom systems. +DExtra Dongle relaying has been fixed, it got broken in 20120213. +Added DCS reflectors to the repeater configuration tab. +Remove Icom heard reporting for now. +Added DCS003. + +20120317 +-------- + +Allow a blank ircDDB password to use the test system. +Handle the callsign server a little better. +Updated XRF021s IP address. +Reinstate the Icom heard reporting. +Disabled DPNS authentication. +Pass reflector link information to ircDDB for ircDDB live. + +20120320 +-------- + +Added XRF000s IP address. +Suppress Icom heard data if a valid header comes in within 100ms. +Last letter of DCS callsigns is never in phonetics. +Allow incoming DCS links. + +20120327 +-------- + +Re-enabled the DPNS authentication. +Updated the DCS and DExtra hosts file to the latest. +Fixed bug in the Linux configuration system. +Added extra reflector logging at startup. + +20120330 +-------- + +Convert the main logs to use UTC instead of local time. +Allow for an IP address lock flag in hosts files. +Updated REF018s IP address. +Removed REF049. +Added DCS006. + +20120403 +-------- + +Minor cleanups. + +20120405 +-------- + +Added the Time Server program. + +20120410 +-------- + +Added the Norwegian language for the gateway announcements. +Added US English and German to the time announcements. +Fix Icom RP2C bug with DCS reflectors. + +20120412 +-------- + +Added DCS007. +Stop duplicate pages appearing in the Timer and Remote Control programs. +Ensure callsigns in the Timer Server are upper case. +Allow software using D-Plus to link into the gateway using the gateway callsign. +Changed default Icom setting in the gateway. + +20120413 +-------- + +Validate with DPNS using the gateway callsign, but the login callsign for opendstar.org. + +20120414 +-------- + +Fixed mistake in the German time announcements. +Fixed Timer Control and handler in the gateway. +Allow all incoming links to hear all other links. + +20120416 +-------- + +Allow for an Every Day entry in the Timer Control program. +Fix audio routing for links in the gateway. +Stop duplicate headers going out over non-RF links. + +20120416a +--------- + +Fix transmitting loop on D-Plus. + +20120417 +-------- + +Fixed the German time in mode 2. +Reorganise the handling of incoming and outgoing links in the gateway. +Add WinSock initialisation to the CIRCDDB library. + +20120420 +-------- + +Introduce a minutes delay to the Timer Control program. +Allow for week day only or weekend only schedule entries into the Timer Control. + +20120422 +-------- + +Rework the Timer Control delay, and make it optional. +Add text only option to the Time Server. +Allow for preloading of the "bands" for an Icom controller. + +20120423 +-------- + +Allow for explicit entry of the Icom band data in the repeater configuration panel. +Allow binding to a specific external IP address. +Allow the passing of a configuration name to the gateway. +Remove the architecture setting in the top level Makefile. +Fixed DD mode logging. + +20120424 +-------- + +Added DCS004. +Allow the Time Server to have a config name to allow more than one instance. +Remove some DD mode logging to reduce the log file size. +Reduced delay in the Timer Control to 20s from 60s. + +20120425 +-------- + +Rework the linking to allow channel change on all types. + +20120428 +-------- + +Add an Unlink button to the Remote Control program. +Rename the output files of the gateway when using it with a config name. + +20120502 +-------- + +Fixed the DTMF blanking in the gateway. +Handle the new callsign server protocol. +Numerous internal cleanups. + +20120511 +-------- + +Improve the timing accuracy throughout the gateway and starnet server. +Upgraded the D-RATS network interface to be more reliable. + +20120512 +-------- + +Upgraded D-RATS RF interface. +Added D-RATS logging to the log file. + +20120524 +-------- + +Added DCS010. +Improved network error logging. +Added Swedish to the Time Server. + +20120605 +-------- + +Removed D-RATS debugging log entries. +Removed XRF009, XRF010, XRF011, XRF030, XRF038, and XRF110. +Updated XRF031s and XRF069s IP addresses. +Added DCS012 and DCS013. +Updated REF001s, REF018s and REF035s IP addresses. +Added REF015, REF049, and REF053. + +20120628 +-------- + +Improve the french times and link status messages. +Allow cross compilation to ARM processors. +Added DCS_LINK to the STARnet Digital servers. + +20120804 +-------- + +Added DCS011, DCS014, and DCS015. +Added REF052 and REF054. +Updated REF008s and REF014s IP address. +Removed REF049. +Removed XRF100. +Fixed ARM cross compilation location of data files. +Fixed AM and PM in English 12-hour clock. +Add an optional permanent user to STARnet Digital groups. +Allow multiple links to the same reflector/gateway from one gateway. +Added the version, " V" command. +Added the two US based ircDDB test servers. +Use new official APRS Ids for APRS reports :-) + +20120805 +-------- + +Fixed the STARnet Digital change, it was slightly wrong. +Make the reported DCS version automatically correct. + +20120826 +-------- + +Upgraded to Visual C++ 2010 on Windows. +Platform dependent settings moved to Makefile includes. +Upgraded the DCS protocol to the latest version. + +20120826a +--------- + +Reverted to Visual C++ 2008. + +20120908 +-------- + +Allow repeater module E to be set. +Allow for multiple links to the same reflector module with internal loopback. +Removed the extra thread created in the Linux command line programs. +Added the ircddb.dstar.su test server. +More changes to the DCS protocol. +Added XRF018 and XRF250. +Added SVN revsion number to the log file. + +20121004 +-------- + +Sort the reflector list in the Remote Control by protocol. +Changed the way that the SVN revision is included. +Change D-RATS handling of incoming network data. +Make the linked/linking/not linked announcement more timely. + +20121023 +-------- + +Make information per repeater. +TimeServer extended for module E. +Added DCS016, DCS017, and DCS018. +Fixed bug in the Time Server that only affected Icom systems. +Changed default APRS host to rotate.aprs2.net. +Changed the announcement audio for B and D for UK English. + +20121029 +-------- + +Fix to the Time Server to make it talk again. +Removed XRF018 and XRF250. +Updated DCS007s IP address. + +20121211 +-------- + +Allow the repeater callsign with a G affixed as the gateway callsign. +DD-Mode multicasts to "all in subnet"/224.0.0.1 and "DX-Cluster"/224.0.0.35 implemented (DX-broadcasts etc.) +Fix APRS reporting when more than one repeater has the same module letter. +Added DCS020. +Updated the DCS protocol. +Fixed DExtra dongle bug. + +20121215 +-------- + +Use link pools for D-Plus, DExtra, and DCS. +Exponential backoff for reflector links. + +20121222 +-------- + +Added REF055, REF056, REF057, and REF058. +Updated REF017s and XRF008s IP address. +Limited UDP port range for D-Plus. +ID rewriting for Icom repeaters. + +20121227 +-------- + +Fixed silly link pool bug(s). +Fixed StarNET Digital compile problem. + +20130111 +-------- + +Updated the host name of the Italian test ircDDB server. +Handle DCS NAK replies to a link request properly. +Handle multiple reflector links better. +Changed gateway loopback behaviour. +Added DCS019. + +20130115 +-------- + +Allow link refusals to be logged and sent as temporary text on the announcement. +Revert DExtra handling to the old behaviour. + +20130122 +-------- + +Add a dummy repeater type for testing. +Fixed slow data text that went missing in 20130115. +Fixed audio problems with multiple reflector links on one gateway. + +20130126 +-------- + +Convert the DCS hosts files to use hostnames. +Update the DCS protocol. +Make ircDDB optional in the gateway. +Removed some log messages (stream ID rewriting and link pools). + +20130131 +-------- + +Fix loopback mode. +Handle APRS failures a little better. + +20130219 +-------- + +Self translated Portugses system messages added. +Only allow DTMF commands when the your call is CQCQCQ. +Modify DExtra DTMF to start with an 'B'. +Updated XRF008s and XRF123s IP addresses. +Allow D-RATS to go over outgoing links. +Removed XReflector. +Added DCS021. +Added XRF333. +Added CCS. + +20130223 +-------- + +Fixed Swedish messages for "Linking to..." and "Linked to...". +Added Spanish, Portuguese, and Norwegian text time messages. +Repeaters announce themselves to CCS for repeater routing. +Correct Portugese translations now used. +Added a DTMF to callsign cache to CCS. +Allow selection of CCS server names. +Internal CCS changes. + +20130302 +-------- + +CCS now updates links.log and the GUI for incoming links. +Suspend outgoing links when a CCS link starts. +Added CCS to the Remote Control application. +Allow voice messages for CCS. +Revision of the Portuguese messages. +Added CCS005 and CCS010 +Added XRF150 + +20130307 +-------- + +Links are not dropped on gateways with incoming CCS links. +CCS is passed to outgoing links on the incoming gateway. +More aggressive link restoration after a CCS link has ended. +Fixed incoming DCS and loopback links. +Fixed the CPU hogging bug. + +20130309 +-------- + +Restored previous CCS behaviour, for now. + +20130315 +-------- + +Fixed port E configuration problem in the GUI. +Don't sort on protocol in the Remote Control GUI. +Remote Control can now unlink incoming links and incoming CCS. +Incoming CCS no longer unlinks existing reflector links. +Info commands are no longer sent over reflector links. +Voice and text messages on incoming CCS links. +Added XRF038. +Updated REF047s IP address. + +20130323 +-------- + +Restrict the characters that can be entered into the description and URL fields. +Allow DTMF "**" to re-link to the default reflector. +Fixed the retry backoff calculation. +Updated XRF003s IP address. + +20130404 +-------- + +Write a .pid file for the gateway (Linux daemon version only). +SIGUSR1 causes the gateway to exit cleanly (Linux daemon version only). +Include code to stop multiple copies of the gateway from running. +Split the configuration of the ircDDB Gateway into a seperate program. +Allow your call command to link to the default reflector. +Allow CCS commands in the your call. +The config directory and file name for the Timer Control are now correct in daemon mode. +The -confdir option now works for the Linux GUI version of the Timer Control. +Check that all repeater modules have seperate callsigns and modules. + +20130405 +-------- + +Added CCS011 and CCS017. +Tweaked GPS-A handling a little with extra debugging. +Makefiles fixed :-) + +20130411 +-------- + +Cleaned up the ircDDB Gateway Config program. +Local echos are not now sent to linked reflectors. +The ircDDB Gateway no longer overwrites the config in GUI mode. +Stop multiple incoming CCS links. +Added French as a language for the Time Server. +Added XRF851. + +20130420 +-------- + +Put the French AMBE and index files into the right place under Linux. +Fixed CCS incoming for "repeater routing". + +20130503 +-------- + +Allow a type to be specified for the gateway. +The local *_Hosts.txt file is now appended to the distributed file. +Read DPlus_Hosts.txt before DExtra_Hosts.txt. +Fix incoming CCS links display in the GUI. + +20130523 +-------- + +Allow for a gateways IP address override file. +Stop the echoed audio from going out over reflector links. +Updated XRF008s, REF035s, REF042s, and REF053s IP addresses. +Added XRF727 and REF060. + +20130611 +-------- + +Added XRF250. +Merge the local *_Hosts.txt file in the RemoteControl and TimerControl programs to match the gateway. +Add another digit to the decimal part of the frequency to handle 6.25 kHz spacing repeaters. +Added the USA QuadNET IRC network to the ircDDB configuration panels. +Allow DTMF numbers to be used for linking to D-Plus and DExtra. +Add remotecontrold to allow command line gateway control. +Handle zero Timer Control actions properly. + +20130622 +-------- + +Allow multiple links to co-operating DExtra reflectors. +Merge the *_Hosts.txt files in the ircDDB Gateway Config program. +Allow for the extra digit in the frequency to be handled by the GUI. +Updated REF047s IP address. +Added XRF310. + +20130725 +-------- + +Added daemon info to the logs. +Fixed STARmet Digital configuration bug in ircDDB Gateway Config. +Restore ircDDB Gateway window at startup. +Added DCS023 and DCS044. +Added XRF121, XRF444, XRF858, and XRFWDX. +Updated XRF901s IP address. + +20131001 +-------- + +Updated XRF012, XRF119, XRF333, and XRFWDXs IP addresses. +Added CCS001(GER), CCS007(NLD), CCS013(NOR), CCS020(USA), CCS022(JPN) and CCS024(USA) +Added DCS024(USA) and DCS025(GER). +Added new Quadnet ircDDB server. +Add homebrew DD data support. +Catch exceptions and other C++ changes in the ircDDB Gateway and STARnet Digital Server. + +20131231 +-------- + +Use latest DExtra and D-Plus host files based on Adrian VK4TUX's. +Added new QuadNet ircDDB server. +Ignore new CCS message type. + +20140101 +-------- + +Fix DEXTRA_LINK compile issues in the StarNET Server. + +20140203 +-------- + +Reduce the network timeout from two to one seconds. +Added the text transmit program. + +20140305 +-------- + +Add IP address logging to the header logging. +Added TextTransmit to Windows. +Write the ircDDB Gateway and STARnet Server configuration files out under Windows. +Rework the CIRCDDB library. +CIRCDDB changes to have better compatibility with QuadNet. +Add STARnet Digital group control to the command-line remote control program. + +20140324 +-------- + +Switch debugging on to enable bug finding on Linux. +Added the voice transmit program. +Allow for multiple STARnet Digital permanent users. + +20140326 +-------- + +Fixed the voice transmit program and added diagnostics. +Fixed the command line remote control program, hopefully. + +20140602 +-------- + +Add StarNet logging for remote control events. +Ensure that duplicate link requests don't initiate a status message. +Stop taking DExtra addresses from xreflector.net +Added the " W" and " M" commands to send weather and messages respectively. + +20150210 +-------- + +Updated the DCS and D-Plus hosts files. +First attempt to fix the multiple linking bug. + +20150213 +-------- + +Slight modification to completely fix the multiple linking bug. + +20150303 +-------- + +A slightly less agressive fix for multiple linking. +Updated the DExtra hosts file. + +20150308 +-------- + +Include .mk file for the Pi2. +Increased the network timeout from one second to two seconds. + +20150507 +-------- + +Update the DExtra_Hosts.txt file. +Handle malformed D-Plus authentication packets better. +Update the copyright date in the GUI Help dialogue boxes. + +20150615 +-------- + +Enable data dumping in the D-RATS server. +Rearrange the source code slightly. +Use hostnames in the DPlus_Hosts.txt file. +Update the DExtra_Hosts.txt file. +Revert to the CIRCDDB library to its previous incarnation. + +20150820 +-------- +Move to the new CCS addressing. + +20151116 +-------- + +CCS7 cleanups and fixes. +Updated DExtra hosts file. +Updated DPlus hosts file to use IP addresses again. +Fix crashing bug in the gateway (from Michael DL1BFF). + +2015xxxx +-------- + +Fix header repeater crashing bug (from Michael DL1BFF). +New slow data encoder from F4FXL. +Added APRSTransmit program from F4FXL. + +20180509 +-------- + +Move to wxWidgets-3.0.x. +UPdate to VS2017 on Windows for 32 and 64 bit compilation. +Simplify the Linux build. diff --git a/COPYING.txt b/COPYING.txt new file mode 100644 index 0000000..3912109 --- /dev/null +++ b/COPYING.txt @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/Common/AMBEData.cpp b/Common/AMBEData.cpp new file mode 100644 index 0000000..c30aacd --- /dev/null +++ b/Common/AMBEData.cpp @@ -0,0 +1,629 @@ +/* + * Copyright (C) 2010-2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "AMBEData.h" + +#include "DStarDefines.h" +#include "Utils.h" + +CAMBEData::CAMBEData() : +m_rptSeq(0U), +m_outSeq(0U), +m_id(0U), +m_band1(0x00U), +m_band2(0x02U), +m_band3(0x01U), +m_data(NULL), +m_yourAddress(), +m_yourPort(0U), +m_myPort(0U), +m_errors(0U), +m_text(), +m_header() +{ + m_data = new unsigned char[DV_FRAME_LENGTH_BYTES]; +} + +CAMBEData::CAMBEData(const CAMBEData& data) : +m_rptSeq(data.m_rptSeq), +m_outSeq(data.m_outSeq), +m_id(data.m_id), +m_band1(data.m_band1), +m_band2(data.m_band2), +m_band3(data.m_band3), +m_data(NULL), +m_yourAddress(data.m_yourAddress), +m_yourPort(data.m_yourPort), +m_myPort(data.m_myPort), +m_errors(data.m_errors), +m_text(data.m_text), +m_header(data.m_header) +{ + m_data = new unsigned char[DV_FRAME_LENGTH_BYTES]; + ::memcpy(m_data, data.m_data, DV_FRAME_LENGTH_BYTES); +} + +CAMBEData::~CAMBEData() +{ + delete[] m_data; +} + +bool CAMBEData::setIcomRepeaterData(const unsigned char *data, unsigned int length, const in_addr& yourAddress, unsigned int yourPort) +{ + wxASSERT(data != NULL); + wxASSERT(length >= 29U); + + m_rptSeq = data[4] * 256U + data[5]; + m_band1 = data[11]; + m_band2 = data[12]; + m_band3 = data[13]; + m_id = data[14] * 256U + data[15]; + m_outSeq = data[16]; + + // A repeater end packet is longer than usual, so we substitute a normal length set of data + if (isEnd()) { + ::memset(m_data, 0x00U, DV_FRAME_LENGTH_BYTES); + ::memcpy(m_data, END_PATTERN_BYTES, END_PATTERN_LENGTH_BYTES); + } else { + ::memcpy(m_data, data + 17U, DV_FRAME_LENGTH_BYTES); + } + + m_yourAddress = yourAddress; + m_yourPort = yourPort; + + return true; +} + +bool CAMBEData::setHBRepeaterData(const unsigned char *data, unsigned int length, const in_addr& yourAddress, unsigned int yourPort) +{ + wxASSERT(data != NULL); + wxASSERT(length >= 21U); + + m_id = data[5U] * 256U + data[6U]; + m_outSeq = data[7U]; + m_errors = data[8U]; + + // A repeater end packet is longer than usual, so we substitute a normal length set of data + if (isEnd()) { + ::memset(m_data, 0x00U, DV_FRAME_LENGTH_BYTES); + ::memcpy(m_data, END_PATTERN_BYTES, END_PATTERN_LENGTH_BYTES); + } else { + ::memcpy(m_data, data + 9U, DV_FRAME_LENGTH_BYTES); + } + + m_yourAddress = yourAddress; + m_yourPort = yourPort; + + return true; +} + +bool CAMBEData::setG2Data(const unsigned char *data, unsigned int length, const in_addr& yourAddress, unsigned int yourPort) +{ + wxASSERT(data != NULL); + wxASSERT(length >= 27U); + + m_band1 = data[9]; + m_band2 = data[10]; + m_band3 = data[11]; + m_id = data[12] * 256U + data[13]; + m_outSeq = data[14]; + + ::memcpy(m_data, data + 15U, DV_FRAME_LENGTH_BYTES); + + m_yourAddress = yourAddress; + m_yourPort = yourPort; + + return true; +} + +bool CAMBEData::setDExtraData(const unsigned char *data, unsigned int length, const in_addr& yourAddress, unsigned int yourPort, unsigned int myPort) +{ + wxASSERT(data != NULL); + wxASSERT(length >= 27U); + + m_band1 = data[9]; + m_band2 = data[10]; + m_band3 = data[11]; + m_id = data[12] * 256U + data[13]; + m_outSeq = data[14]; + + ::memcpy(m_data, data + 15U, DV_FRAME_LENGTH_BYTES); + + m_yourAddress = yourAddress; + m_yourPort = yourPort; + m_myPort = myPort; + + return true; +} + +bool CAMBEData::setDPlusData(const unsigned char *data, unsigned int length, const in_addr& yourAddress, unsigned int yourPort, unsigned int myPort) +{ + wxASSERT(data != NULL); + wxASSERT(length >= 29U); + + if ((data[0] != 0x1D && data[0] != 0x20) || data[1] != 0x80) { + CUtils::dump(wxT("Invalid AMBE length from D-Plus"), data, length); + return false; + } + + m_band1 = data[11]; + m_band2 = data[12]; + m_band3 = data[13]; + m_id = data[14] * 256U + data[15]; + m_outSeq = data[16]; + + if (isEnd()) { + ::memset(m_data, 0x00U, DV_FRAME_LENGTH_BYTES); + ::memcpy(m_data, END_PATTERN_BYTES, END_PATTERN_LENGTH_BYTES); + } else { + ::memcpy(m_data, data + 17U, DV_FRAME_LENGTH_BYTES); + } + + m_yourAddress = yourAddress; + m_yourPort = yourPort; + m_myPort = myPort; + + return true; +} + +bool CAMBEData::setDCSData(const unsigned char *data, unsigned int length, const in_addr& yourAddress, unsigned int yourPort, unsigned int myPort) +{ + wxASSERT(data != NULL); + wxASSERT(length >= 100U); + + m_header.setDCSData(data, length, yourAddress, yourPort, myPort); + + m_id = data[44] * 256U + data[43]; + + m_outSeq = data[45]; + + ::memcpy(m_data, data + 46U, DV_FRAME_LENGTH_BYTES); + + m_rptSeq = data[60] * 65536U + data[59] * 256U + data[58]; + + m_yourAddress = yourAddress; + m_yourPort = yourPort; + m_myPort = myPort; + + return true; +} + +bool CAMBEData::setCCSData(const unsigned char *data, unsigned int length, const in_addr& yourAddress, unsigned int yourPort, unsigned int myPort) +{ + wxASSERT(data != NULL); + wxASSERT(length >= 100U); + + m_header.setCCSData(data, length, yourAddress, yourPort, myPort); + + m_id = data[44] * 256U + data[43]; + + m_outSeq = data[45]; + + ::memcpy(m_data, data + 46U, DV_FRAME_LENGTH_BYTES); + + m_rptSeq = data[60] * 65536U + data[59] * 256U + data[58]; + + m_yourAddress = yourAddress; + m_yourPort = yourPort; + m_myPort = myPort; + + return true; +} + +unsigned int CAMBEData::getIcomRepeaterData(unsigned char *data, unsigned int length) const +{ + wxASSERT(data != NULL); + wxASSERT(length >= 32U); + + data[0] = 'D'; + data[1] = 'S'; + data[2] = 'T'; + data[3] = 'R'; + + data[4] = m_rptSeq / 256U; // Packet sequence number + data[5] = m_rptSeq % 256U; + + data[6] = 0x73; // Not a response + data[7] = 0x12; // Data type + + data[8] = 0x00; // Length MSB + data[9] = 0x13U; // Length LSB + + data[10] = 0x20; // AMBE plus Slow Data following + + data[11] = m_band1; + data[12] = m_band2; + data[13] = m_band3; + + data[14] = m_id / 256U; // Unique session id + data[15] = m_id % 256U; + + data[16] = m_outSeq; + + ::memcpy(data + 17U, m_data, DV_FRAME_LENGTH_BYTES); + + return 17U + DV_FRAME_LENGTH_BYTES; +} + +unsigned int CAMBEData::getHBRepeaterData(unsigned char *data, unsigned int length) const +{ + wxASSERT(data != NULL); + wxASSERT(length >= 21U); + + data[0] = 'D'; + data[1] = 'S'; + data[2] = 'R'; + data[3] = 'P'; + + data[4] = 0x21U; + + data[5] = m_id / 256U; // Unique session id + data[6] = m_id % 256U; + + data[7] = m_outSeq; + + data[8] = 0U; + + ::memcpy(data + 9U, m_data, DV_FRAME_LENGTH_BYTES); + + return 9U + DV_FRAME_LENGTH_BYTES; +} + +unsigned int CAMBEData::getG2Data(unsigned char *data, unsigned int length) const +{ + wxASSERT(data != NULL); + wxASSERT(length >= 30U); + + data[0] = 'D'; + data[1] = 'S'; + data[2] = 'V'; + data[3] = 'T'; + + data[4] = 0x20; + data[5] = 0x00; + data[6] = 0x15; + data[7] = 0x09; + data[8] = 0x20; + + data[9] = m_band1; + data[10] = m_band2; + data[11] = m_band3; + + data[12] = m_id / 256U; // Unique session id + data[13] = m_id % 256U; + + data[14] = m_outSeq; + + ::memcpy(data + 15U, m_data, DV_FRAME_LENGTH_BYTES); + + return 15U + DV_FRAME_LENGTH_BYTES; +} + +unsigned int CAMBEData::getDExtraData(unsigned char* data, unsigned int length) const +{ + wxASSERT(data != NULL); + wxASSERT(length >= 30U); + + data[0] = 'D'; + data[1] = 'S'; + data[2] = 'V'; + data[3] = 'T'; + + data[4] = 0x20; + data[5] = 0x00; + data[6] = 0x00; + data[7] = 0x00; + data[8] = 0x20; + + data[9] = m_band1; + data[10] = m_band2; + data[11] = m_band3; + + data[12] = m_id % 256U; // Unique session id + data[13] = m_id / 256U; + + data[14] = m_outSeq; + + ::memcpy(data + 15U, m_data, DV_FRAME_LENGTH_BYTES); + + return 15U + DV_FRAME_LENGTH_BYTES; +} + +unsigned int CAMBEData::getDPlusData(unsigned char* data, unsigned int length) const +{ + wxASSERT(data != NULL); + wxASSERT(length >= 32U); + + if (isEnd()) { + data[0] = 0x20; + data[1] = 0x80; + } else { + data[0] = 0x1D; + data[1] = 0x80; + } + + data[2] = 'D'; + data[3] = 'S'; + data[4] = 'V'; + data[5] = 'T'; + + data[6] = 0x20; + data[7] = 0x00; + data[8] = 0x00; + data[9] = 0x00; + data[10] = 0x20; + + data[11] = m_band1; + data[12] = m_band2; + data[13] = m_band3; + + data[14] = m_id % 256U; // Unique session id + data[15] = m_id / 256U; + + data[16] = m_outSeq; + + if (isEnd()) { + ::memcpy(data + 17U, NULL_AMBE_DATA_BYTES, VOICE_FRAME_LENGTH_BYTES); + ::memcpy(data + 26U, END_PATTERN_BYTES, END_PATTERN_LENGTH_BYTES); // Add the end flag + return 17U + DV_FRAME_MAX_LENGTH_BYTES; + } else { + // All other cases, just copy the payload + ::memcpy(data + 17U, m_data, DV_FRAME_LENGTH_BYTES); + return 17U + DV_FRAME_LENGTH_BYTES; + } +} + +unsigned int CAMBEData::getDCSData(unsigned char* data, unsigned int length) const +{ + wxASSERT(data != NULL); + wxASSERT(length >= 100U); + + ::memset(data, 0x00U, 100U); + + data[0] = '0'; + data[1] = '0'; + data[2] = '0'; + data[3] = '1'; + + data[43] = m_id % 256U; // Unique session id + data[44] = m_id / 256U; + + data[45] = m_outSeq; + + ::memcpy(data + 46U, m_data, DV_FRAME_LENGTH_BYTES); + + if (isEnd()) { + data[55] = 0x55U; + data[56] = 0x55U; + data[57] = 0x55U; + } + + data[58] = (m_rptSeq >> 0) & 0xFFU; + data[59] = (m_rptSeq >> 8) & 0xFFU; + data[60] = (m_rptSeq >> 16) & 0xFFU; + + data[61] = 0x01U; + data[62] = 0x00U; + + data[63] = 0x21U; + + for (unsigned int i = 0U; i < m_text.Len(); i++) + data[64 + i] = m_text.GetChar(i); + + m_header.getDCSData(data, 100U); + + return 100U; +} + +unsigned int CAMBEData::getCCSData(unsigned char* data, unsigned int length) const +{ + wxASSERT(data != NULL); + wxASSERT(length >= 100U); + + ::memset(data, 0x00U, 100U); + + data[0] = '0'; + data[1] = '0'; + data[2] = '0'; + data[3] = '1'; + + data[43] = m_id % 256U; // Unique session id + data[44] = m_id / 256U; + + data[45] = m_outSeq; + + ::memcpy(data + 46U, m_data, DV_FRAME_LENGTH_BYTES); + + if (isEnd()) { + data[55] = 0x55U; + data[56] = 0x55U; + data[57] = 0x55U; + } + + data[58] = (m_rptSeq >> 0) & 0xFFU; + data[59] = (m_rptSeq >> 8) & 0xFFU; + data[60] = (m_rptSeq >> 16) & 0xFFU; + + data[61] = 0x01U; + data[62] = 0x00U; + + data[63] = 0x21U; + + for (unsigned int i = 0U; i < m_text.Len(); i++) + data[64 + i] = m_text.GetChar(i); + + data[93U] = 0x36U; + + m_header.getCCSData(data, 100U); + + return 100U; +} + +unsigned int CAMBEData::getId() const +{ + return m_id; +} + +void CAMBEData::setId(unsigned int id) +{ + m_id = id; +} + +unsigned char CAMBEData::getBand1() const +{ + return m_band1; +} + +unsigned char CAMBEData::getBand2() const +{ + return m_band2; +} + +unsigned char CAMBEData::getBand3() const +{ + return m_band3; +} + +void CAMBEData::setBand1(unsigned char band) +{ + m_band1 = band; +} + +void CAMBEData::setBand2(unsigned char band) +{ + m_band2 = band; +} + +void CAMBEData::setBand3(unsigned char band) +{ + m_band3 = band; +} + +unsigned int CAMBEData::getRptSeq() const +{ + return m_rptSeq; +} + +void CAMBEData::setRptSeq(unsigned int seqNo) +{ + m_rptSeq = seqNo; +} + +unsigned int CAMBEData::getSeq() const +{ + return m_outSeq & 0x1FU; +} + +void CAMBEData::setSeq(unsigned int seqNo) +{ + m_outSeq = seqNo; +} + +bool CAMBEData::isEnd() const +{ + return (m_outSeq & 0x40U) == 0x40U; +} + +void CAMBEData::setEnd(bool end) +{ + if (end) + m_outSeq |= 0x40U; + else + m_outSeq &= ~0x40U; +} + +bool CAMBEData::isSync() const +{ + return (m_outSeq & 0x1FU) == 0x00U; +} + +void CAMBEData::setDestination(const in_addr& address, unsigned int port) +{ + m_yourAddress = address; + m_yourPort = port; +} + +void CAMBEData::setText(const wxString& text) +{ + m_text = text; +} + +in_addr CAMBEData::getYourAddress() const +{ + return m_yourAddress; +} + +unsigned int CAMBEData::getYourPort() const +{ + return m_yourPort; +} + +unsigned int CAMBEData::getMyPort() const +{ + return m_myPort; +} + +CHeaderData& CAMBEData::getHeader() +{ + return m_header; +} + +unsigned int CAMBEData::getErrors() const +{ + return m_errors; +} + +void CAMBEData::setData(const unsigned char *data, unsigned int length) +{ + wxASSERT(data != NULL); + wxASSERT(length >= DV_FRAME_LENGTH_BYTES); + + ::memcpy(m_data, data, DV_FRAME_LENGTH_BYTES); +} + +unsigned int CAMBEData::getData(unsigned char *data, unsigned int length) const +{ + wxASSERT(data != NULL); + wxASSERT(length >= DV_FRAME_LENGTH_BYTES); + + ::memcpy(data, m_data, DV_FRAME_LENGTH_BYTES); + + return DV_FRAME_LENGTH_BYTES; +} + +CAMBEData& CAMBEData::operator=(const CAMBEData& data) +{ + if (&data != this) { + m_rptSeq = data.m_rptSeq; + m_outSeq = data.m_outSeq; + m_id = data.m_id; + m_band1 = data.m_band1; + m_band2 = data.m_band2; + m_band3 = data.m_band3; + m_yourAddress = data.m_yourAddress; + m_yourPort = data.m_yourPort; + m_myPort = data.m_myPort; + m_errors = data.m_errors; + m_text = data.m_text; + m_header = data.m_header; + + ::memcpy(m_data, data.m_data, DV_FRAME_LENGTH_BYTES); + } + + return *this; +} diff --git a/Common/AMBEData.h b/Common/AMBEData.h new file mode 100644 index 0000000..773df7c --- /dev/null +++ b/Common/AMBEData.h @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2010-2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef AMBEData_H +#define AMBEData_H + +#include "HeaderData.h" + +#include + +#if defined(__WINDOWS__) +#include "Inaddr.h" +#else +#include +#endif + +class CAMBEData { +public: + CAMBEData(); + CAMBEData(const CAMBEData& data); + ~CAMBEData(); + + bool setIcomRepeaterData(const unsigned char* data, unsigned int length, const in_addr& yourAddress, unsigned int yourPort); + bool setHBRepeaterData(const unsigned char* data, unsigned int length, const in_addr& yourAddress, unsigned int yourPort); + bool setG2Data(const unsigned char* data, unsigned int length, const in_addr& yourAddress, unsigned int yourPort); + bool setDExtraData(const unsigned char* data, unsigned int length, const in_addr& yourAddress, unsigned int yourPort, unsigned int myPort); + bool setDPlusData(const unsigned char* data, unsigned int length, const in_addr& yourAddress, unsigned int yourPort, unsigned int myPort); + bool setDCSData(const unsigned char* data, unsigned int length, const in_addr& yourAddress, unsigned int yourPort, unsigned int myPort); + bool setCCSData(const unsigned char* data, unsigned int length, const in_addr& yourAddress, unsigned int yourPort, unsigned int myPort); + + unsigned int getIcomRepeaterData(unsigned char* data, unsigned int length) const; + unsigned int getHBRepeaterData(unsigned char* data, unsigned int length) const; + unsigned int getDExtraData(unsigned char* data, unsigned int length) const; + unsigned int getDPlusData(unsigned char* data, unsigned int length) const; + unsigned int getDCSData(unsigned char* data, unsigned int length) const; + unsigned int getCCSData(unsigned char* data, unsigned int length) const; + unsigned int getG2Data(unsigned char* data, unsigned int length) const; + + unsigned int getId() const; + void setId(unsigned int id); + + unsigned char getBand1() const; + unsigned char getBand2() const; + unsigned char getBand3() const; + void setBand1(unsigned char band); + void setBand2(unsigned char band); + void setBand3(unsigned char band); + + unsigned int getRptSeq() const; + void setRptSeq(unsigned int seqNo); + + unsigned int getSeq() const; + void setSeq(unsigned int seqNo); + + bool isEnd() const; + void setEnd(bool end); + + bool isSync() const; + + void setData(const unsigned char* data, unsigned int length); + unsigned int getData(unsigned char* data, unsigned int length) const; + + void setDestination(const in_addr& address, unsigned int port); + + void setText(const wxString& text); + + in_addr getYourAddress() const; + unsigned int getYourPort() const; + unsigned int getMyPort() const; + + unsigned int getErrors() const; + + CHeaderData& getHeader(); + + CAMBEData& operator=(const CAMBEData& data); + +private: + unsigned int m_rptSeq; + unsigned char m_outSeq; + unsigned int m_id; + unsigned char m_band1; + unsigned char m_band2; + unsigned char m_band3; + unsigned char* m_data; + in_addr m_yourAddress; + unsigned int m_yourPort; + unsigned int m_myPort; + unsigned int m_errors; + wxString m_text; + CHeaderData m_header; +}; + +#endif diff --git a/Common/APRSCollector.cpp b/Common/APRSCollector.cpp new file mode 100644 index 0000000..1973427 --- /dev/null +++ b/Common/APRSCollector.cpp @@ -0,0 +1,661 @@ +/* + * Copyright (C) 2010,2012,2013,2014 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "APRSCollector.h" +#include "DStarDefines.h" +#include "Utils.h" + +const unsigned int APRS_CSUM_LENGTH = 4U; +const unsigned int APRS_DATA_LENGTH = 300U; +const unsigned int SLOW_DATA_BLOCK_LENGTH = 6U; + +CAPRSCollector::CAPRSCollector() : +m_state(AS_NONE), +m_ggaData(NULL), +m_ggaLength(0U), +m_ggaValid(false), +m_rmcData(NULL), +m_rmcLength(0U), +m_rmcValid(false), +m_crcData(NULL), +m_crcLength(0U), +m_crcValid(false), +m_txtData(NULL), +m_txtLength(0U), +m_txtValid(false), +m_buffer(NULL), +m_slowData(SS_FIRST) +{ + m_ggaData = new unsigned char[APRS_DATA_LENGTH]; + m_rmcData = new unsigned char[APRS_DATA_LENGTH]; + m_crcData = new unsigned char[APRS_DATA_LENGTH]; + m_txtData = new unsigned char[APRS_DATA_LENGTH]; + m_buffer = new unsigned char[SLOW_DATA_BLOCK_LENGTH]; +} + +CAPRSCollector::~CAPRSCollector() +{ + delete[] m_ggaData; + delete[] m_rmcData; + delete[] m_crcData; + delete[] m_txtData; + delete[] m_buffer; +} + +bool CAPRSCollector::writeData(const unsigned char* data) +{ + wxASSERT(data != NULL); + + switch (m_slowData) { + case SS_FIRST: + m_buffer[0U] = data[0U] ^ SCRAMBLER_BYTE1; + m_buffer[1U] = data[1U] ^ SCRAMBLER_BYTE2; + m_buffer[2U] = data[2U] ^ SCRAMBLER_BYTE3; + m_slowData = SS_SECOND; + return false; + + case SS_SECOND: + m_buffer[3U] = data[0U] ^ SCRAMBLER_BYTE1; + m_buffer[4U] = data[1U] ^ SCRAMBLER_BYTE2; + m_buffer[5U] = data[2U] ^ SCRAMBLER_BYTE3; + m_slowData = SS_FIRST; + break; + } + + // Is it GPS data, or are we collecting data already? + if ((m_buffer[0U] & SLOW_DATA_TYPE_MASK) != SLOW_DATA_TYPE_GPS) + return false; + + return addData(m_buffer + 1U); +} + +void CAPRSCollector::reset() +{ + m_state = AS_NONE; + m_ggaLength = 0U; + m_ggaValid = false; + m_rmcLength = 0U; + m_rmcValid = false; + m_crcLength = 0U; + m_crcValid = false; + m_txtLength = 0U; + m_txtValid = false; + m_slowData = SS_FIRST; +} + +void CAPRSCollector::sync() +{ + m_slowData = SS_FIRST; +} + +bool CAPRSCollector::addData(const unsigned char* data) +{ + wxASSERT(data != NULL); + + if (::memcmp(data, "$GPGG", 5U) == 0) { + m_state = AS_GGA; + m_ggaLength = 0U; + m_ggaValid = false; + m_rmcLength = 0U; + m_rmcValid = false; + m_txtLength = 0U; + m_txtValid = false; + addGGAData(data); + return false; + } else if (::memcmp(data, "$GPRM", 5U) == 0) { + m_state = AS_RMC; + m_rmcLength = 0U; + m_rmcValid = false; + m_txtLength = 0U; + m_txtValid = false; + addRMCData(data); + return false; + } else if (::memcmp(data, "$$CRC", 5U) == 0) { + m_state = AS_CRC; + m_crcLength = 0U; + m_crcValid = false; + return addCRCData(data); + } else if (m_state == AS_RMC && m_rmcLength == 0U) { + m_state = AS_TXT; + m_txtLength = 0U; + m_txtValid = false; + addTXTData(data); + return false; + } else if (m_state == AS_GGA) { + addGGAData(data); + return false; + } else if (m_state == AS_RMC) { + addRMCData(data); + return false; + } else if (m_state == AS_CRC) { + return addCRCData(data); + } else if (m_state == AS_TXT) { + return addTXTData(data); + } + + return false; +} + +void CAPRSCollector::addGGAData(const unsigned char* data) +{ + for (unsigned int i = 0U; i < 5U; i++) { + unsigned char c = data[i]; + + m_ggaData[m_ggaLength] = c & 0x7FU; + m_ggaLength++; + + if (m_ggaLength >= APRS_DATA_LENGTH) { + // CUtils::dump(wxT("Missed end of $GPGGA data"), m_ggaData, m_ggaLength); + m_ggaLength = 0U; + m_ggaValid = false; + m_state = AS_NONE; + return; + } + + if (c == 0x0AU) { + bool ret = checkXOR(m_ggaData + 1U, m_ggaLength - 1U); + if (ret) { + // CUtils::dump(wxT("$GPGGA Valid"), m_ggaData, m_ggaLength); + m_ggaValid = true; + m_state = AS_RMC; + return; + } else { + // CUtils::dump(wxT("$GPGGA Bad checksum"), m_ggaData, m_ggaLength); + m_ggaLength = 0U; + m_ggaValid = false; + m_state = AS_RMC; + return; + } + } + } +} + +void CAPRSCollector::addRMCData(const unsigned char* data) +{ + for (unsigned int i = 0U; i < 5U; i++) { + unsigned char c = data[i]; + + m_rmcData[m_rmcLength] = c & 0x7FU; + m_rmcLength++; + + if (m_rmcLength >= APRS_DATA_LENGTH) { + // CUtils::dump(wxT("Missed end of $GPRMC data"), m_rmcData, m_rmcLength); + m_rmcLength = 0U; + m_rmcValid = false; + m_state = AS_NONE; + return; + } + + if (c == 0x0AU) { + bool ret = checkXOR(m_rmcData + 1U, m_rmcLength - 1U); + if (ret) { + // CUtils::dump(wxT("$GPRMC Valid"), m_rmcData, m_rmcLength); + m_rmcValid = true; + m_state = AS_TXT; + return; + } else { + // CUtils::dump(wxT("$GPRMC Bad checksum"), m_rmcData, m_rmcLength); + m_rmcLength = 0U; + m_rmcValid = false; + m_state = AS_TXT; + return; + } + } + } +} + +bool CAPRSCollector::addCRCData(const unsigned char* data) +{ + for (unsigned int i = 0U; i < 5U; i++) { + unsigned char c = data[i]; + + // m_crcData[m_crcLength] = c & 0x7FU; // XXX + m_crcData[m_crcLength] = c; + m_crcLength++; + + if (m_crcLength >= APRS_DATA_LENGTH) { + // CUtils::dump(wxT("Missed end of $$CRC data"), m_crcData, m_crcLength); + m_state = AS_NONE; + m_crcLength = 0U; + m_crcValid = false; + return false; + } + + if (c == 0x0DU) { + bool ret = checkCRC(m_crcData, m_crcLength); + if (ret) { + // CUtils::dump(wxT("$$CRC Valid"), m_crcData, m_crcLength); + m_state = AS_NONE; + m_crcValid = true; + return true; + } else { + // CUtils::dump(wxT("$$CRC Bad checksum"), m_crcData, m_crcLength); + m_state = AS_NONE; + m_crcLength = 0U; + m_crcValid = false; + return false; + } + } + } + + return false; +} + +bool CAPRSCollector::addTXTData(const unsigned char* data) +{ + for (unsigned int i = 0U; i < 5U; i++) { + unsigned char c = data[i]; + + m_txtData[m_txtLength] = c & 0x7FU; + m_txtLength++; + + if (m_txtLength >= APRS_DATA_LENGTH) { + // CUtils::dump(wxT("Missed end of TEXT data"), m_txtData, m_txtLength); + m_state = AS_NONE; + m_txtLength = 0U; + m_txtValid = false; + return false; + } + + if (c == 0x0AU) { + bool ret = checkXOR(m_txtData, m_txtLength); + if (ret) { + // CUtils::dump(wxT("TEXT Valid"), m_txtData, m_txtLength); + m_state = AS_NONE; + m_txtValid = true; + return true; + } else { + // CUtils::dump(wxT("TEXT Bad checksum"), m_txtData, m_txtLength); + m_state = AS_NONE; + m_txtLength = 0U; + m_txtValid = false; + return false; + } + } + } + + return false; +} + +unsigned int CAPRSCollector::getData(unsigned char* data, unsigned int length) +{ + wxASSERT(data != NULL); + + // Have we got GPS-A data? + if (m_crcValid) { + unsigned int len = m_crcLength - 10U; + if (len > length) + len = length; + + ::memcpy(data, m_crcData + 10U, len); + + m_crcLength = 0U; + m_crcValid = false; + + return len; + } + + // Have we got GGA and text data? + if (m_ggaValid && m_txtValid) { + unsigned int len = convertNMEA1(data, length); + + m_ggaLength = 0U; + m_rmcLength = 0U; + m_txtLength = 0U; + m_ggaValid = false; + m_rmcValid = false; + m_txtValid = false; + + return len; + } + + // Have we got RMC and text data? + if (m_rmcValid && m_txtValid) { + unsigned int len = convertNMEA2(data, length); + + m_ggaLength = 0U; + m_rmcLength = 0U; + m_txtLength = 0U; + m_ggaValid = false; + m_rmcValid = false; + m_txtValid = false; + + return len; + } + + return 0U; +} + +bool CAPRSCollector::checkXOR(const unsigned char* data, unsigned int length) const +{ + unsigned int posStar = 0U; + for (unsigned int i = length - 1U; i > 0U; i--) { + if (data[i] == '*') { + posStar = i; + break; + } + } + + if (posStar == 0U) + return false; + + unsigned char csum = calcXOR(data, posStar); + + char buffer[10U]; + ::sprintf(buffer, "%02X", csum); + + return ::memcmp(buffer, data + posStar + 1U, 2U) == 0; +} + +unsigned char CAPRSCollector::calcXOR(const unsigned char* buffer, unsigned int length) const +{ + wxASSERT(buffer != NULL); + wxASSERT(length > 0U); + + unsigned char res = 0U; + + for (unsigned int i = 0U; i < length; i++) + res ^= buffer[i]; + + return res; +} + +bool CAPRSCollector::checkCRC(const unsigned char* data, unsigned int length) const +{ + unsigned int csum = calcCRC(data + 10U, length - 10U); + + char buffer[10U]; + ::sprintf(buffer, "%04X", csum); + + return ::memcmp(buffer, data + 5U, APRS_CSUM_LENGTH) == 0; +} + +unsigned int CAPRSCollector::calcCRC(const unsigned char* buffer, unsigned int length) const +{ + wxASSERT(buffer != NULL); + wxASSERT(length > 0U); + + unsigned int icomcrc = 0xFFFFU; + + for (unsigned int j = 0U; j < length; j++) { + unsigned char ch = buffer[j]; + + for (unsigned int i = 0U; i < 8U; i++) { + bool xorflag = (((icomcrc ^ ch) & 0x01U) == 0x01U); + + icomcrc >>= 1; + + if (xorflag) + icomcrc ^= 0x8408U; + + ch >>= 1; + } + } + + return ~icomcrc & 0xFFFFU; +} + +unsigned int CAPRSCollector::convertNMEA1(unsigned char* data, unsigned int) +{ + // Parse the $GPGGA string into tokens + char* pGGA[20U]; + ::memset(pGGA, 0x00U, 20U * sizeof(char*)); + unsigned int nGGA = 0U; + + char* str = (char*)m_ggaData; + for (;;) { + char* p = mystrsep(&str, ",\r\n"); + + pGGA[nGGA++] = p; + if (p == NULL) + break; + } + + // Is there any position data? + if (pGGA[2U] == NULL || pGGA[3U] == NULL || pGGA[4U] == NULL || pGGA[5U] == NULL || ::strlen(pGGA[2U]) == 0U || ::strlen(pGGA[3U]) == 0U || ::strlen(pGGA[4U]) == 0 || ::strlen(pGGA[5U]) == 0) + return 0U; + + // Is it a valid GPS fix? + if (::strcmp(pGGA[6U], "0") == 0) + return 0U; + + char callsign[10U]; + ::memset(callsign, ' ', 10U); + ::strncpy(callsign, (char*)m_txtData, 7U); + + // This can't fail! + char* p = ::strchr(callsign, ' '); + + if (m_txtData[6U] == ' ' && m_txtData[7U] != ' ') { + *p++ = '-'; + *p++ = m_txtData[7U]; + } else if (m_txtData[6U] != ' ' && m_txtData[7U] != ' ') { + *p++ = m_txtData[7U]; + } + + *p = '\0'; + + char symbol, overlay; + getSymbol(m_txtData + 9U, symbol, overlay); + + ::sprintf((char*)data, "%s>APDPRS,DSTAR*:!%.7s%s%c%.8s%s%c", callsign, pGGA[2U], pGGA[3U], overlay, pGGA[4U], pGGA[5U], symbol); + + // Get the bearing and speed from the RMC data + if (m_rmcValid) { + // Parse the $GPRMC string into tokens + char* pRMC[20U]; + ::memset(pRMC, 0x00U, 20U * sizeof(char*)); + unsigned int nRMC = 0U; + + str = (char*)m_rmcData; + for (;;) { + p = mystrsep(&str, ",\r\n"); + + pRMC[nRMC++] = p; + if (p == NULL) + break; + } + + // Check that we have a bearing and speed + if (pRMC[7U] != NULL && pRMC[8U] != NULL && ::strlen(pRMC[7U]) > 0U && ::strlen(pRMC[8U]) > 0U) { + int bearing = ::atoi(pRMC[8U]); + int speed = ::atoi(pRMC[7U]); + + ::sprintf((char*)data + ::strlen((char*)data), "%03d/%03d", bearing, speed); + } + } + + ::strcat((char*)data, " "); + + // Insert the message text + unsigned int j = ::strlen((char*)data); + for (unsigned int i = 13U; i < 29U; i++) { + unsigned char c = m_txtData[i]; + + if (c == '*') { + data[j] = '\0'; + break; + } + + data[j++] = c; + } + + if (pGGA[9U] != NULL && ::strlen(pGGA[9U]) > 0U) { + // Convert altitude from metres to feet + int altitude = ::atoi(pGGA[9U]); + ::sprintf((char*)data + ::strlen((char*)data), "/A=%06.0f", float(altitude) * 3.28F); + } + + return ::strlen((char*)data); +} + +unsigned int CAPRSCollector::convertNMEA2(unsigned char* data, unsigned int) +{ + // Parse the $GPRMC string into tokens + char* pRMC[20U]; + ::memset(pRMC, 0x00U, 20U * sizeof(char*)); + unsigned int nRMC = 0U; + + char* str = (char*)m_rmcData; + for (;;) { + char* p = mystrsep(&str, ",\r\n"); + + pRMC[nRMC++] = p; + if (p == NULL) + break; + } + + // Is there any position data? + if (pRMC[3U] == NULL || pRMC[4U] == NULL || pRMC[5U] == NULL || pRMC[6U] == NULL || ::strlen(pRMC[3U]) == 0U || ::strlen(pRMC[4U]) == 0U || ::strlen(pRMC[5U]) == 0 || ::strlen(pRMC[6U]) == 0) + return 0U; + + // Is it a valid GPS fix? + if (::strcmp(pRMC[2U], "A") != 0) + return 0U; + + char callsign[10U]; + ::memset(callsign, ' ', 10U); + ::strncpy(callsign, (char*)m_txtData, 7U); + + // This can't fail! + char* p = ::strchr(callsign, ' '); + + if (m_txtData[6U] == ' ' && m_txtData[7U] != ' ') { + *p++ = '-'; + *p++ = m_txtData[7U]; + } else if (m_txtData[6U] != ' ' && m_txtData[7U] != ' ') { + *p++ = m_txtData[7U]; + } + + *p = '\0'; + + char symbol, overlay; + getSymbol(m_txtData + 9U, symbol, overlay); + + ::sprintf((char*)data, "%s>APDPRS,DSTAR*:!%.7s%s%c%.8s%s%c", callsign, pRMC[3U], pRMC[4U], overlay, pRMC[5U], pRMC[6U], symbol); + + if (pRMC[7U] != NULL && pRMC[8U] != NULL && ::strlen(pRMC[7U]) > 0U && ::strlen(pRMC[8U]) > 0U) { + int bearing = ::atoi(pRMC[8U]); + int speed = ::atoi(pRMC[7U]); + + ::sprintf((char*)data + ::strlen((char*)data), "%03d/%03d", bearing, speed); + } + + if (m_txtData[13U] != '*') + ::strcat((char*)data, " "); + + // Insert the message text + unsigned int j = ::strlen((char*)data); + for (unsigned int i = 13U; i < 29U; i++) { + unsigned char c = m_txtData[i]; + + if (c == '*') { + data[j] = '\0'; + break; + } + + data[j++] = c; + } + + return ::strlen((char*)data); +} + +// Function taken from DPRSIntf.java from Pete Loveall AE5PL +void CAPRSCollector::getSymbol(const unsigned char* data, char& symbol, char& overlay) +{ + symbol = '.'; + + if (data[3U] == ' ') { + int offset = -1; + + switch (data[0U]) { + case 'B': + case 'O': + offset = -33; + break; + case 'P': + case 'A': + offset = 0; + break; + case 'M': + case 'N': + offset = -24; + break; + case 'H': + case 'D': + offset = 8; + break; + case 'L': + case 'S': + offset = 32; + break; + case 'J': + case 'Q': + offset = 74; + break; + default: + break; + } + + if (offset != -1 && ::isalnum(data[1U])) { + bool altIcons = false; + + // x is valid, lets get y + switch (data[0U]) { + case 'O': + case 'A': + case 'N': + case 'D': + case 'S': + case 'Q': + altIcons = true; + break; + } + + symbol = char(data[1U] + offset); + + overlay = '/'; + + if (altIcons) { + if (data[2] == ' ') + overlay = '\\'; + else if (::isalnum(data[2])) + overlay = data[2U]; + else + overlay = 0; + } + } + } +} + +// Source found at +char* CAPRSCollector::mystrsep(char** sp, const char* sep) const +{ + if (sp == NULL || *sp == NULL || **sp == '\0') + return NULL; + + char* s = *sp; + char* p = s + ::strcspn(s, sep); + + if (*p != '\0') + *p++ = '\0'; + + *sp = p; + + return s; +} diff --git a/Common/APRSCollector.h b/Common/APRSCollector.h new file mode 100644 index 0000000..8c79c1a --- /dev/null +++ b/Common/APRSCollector.h @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2010,2012 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef APRSCollector_H +#define APRSCollector_H + +#include "Defs.h" + +#include + +enum APRS_STATE { + AS_NONE, + AS_GGA, + AS_RMC, + AS_CRC, + AS_TXT +}; + +class CAPRSCollector { +public: + CAPRSCollector(); + ~CAPRSCollector(); + + bool writeData(const unsigned char* data); + + void sync(); + + void reset(); + + unsigned int getData(unsigned char* data, unsigned int length); + +private: + APRS_STATE m_state; + unsigned char* m_ggaData; + unsigned int m_ggaLength; + bool m_ggaValid; + unsigned char* m_rmcData; + unsigned int m_rmcLength; + bool m_rmcValid; + unsigned char* m_crcData; + unsigned int m_crcLength; + bool m_crcValid; + unsigned char* m_txtData; + unsigned int m_txtLength; + bool m_txtValid; + unsigned char* m_buffer; + SLOWDATA_STATE m_slowData; + + bool addData(const unsigned char* data); + void addGGAData(const unsigned char* data); + void addRMCData(const unsigned char* data); + bool addCRCData(const unsigned char* data); + bool addTXTData(const unsigned char* data); + + bool checkXOR(const unsigned char* data, unsigned int length) const; + unsigned char calcXOR(const unsigned char* buffer, unsigned int length) const; + + bool checkCRC(const unsigned char* data, unsigned int length) const; + unsigned int calcCRC(const unsigned char* buffer, unsigned int length) const; + + unsigned int convertNMEA1(unsigned char* data, unsigned int length); + unsigned int convertNMEA2(unsigned char* data, unsigned int length); + + void getSymbol(const unsigned char* data, char& symbol, char& overlay); + + char* mystrsep(char** sp, const char* sep) const; +}; + +#endif diff --git a/Common/APRSWriter.cpp b/Common/APRSWriter.cpp new file mode 100644 index 0000000..ae5d6a0 --- /dev/null +++ b/Common/APRSWriter.cpp @@ -0,0 +1,394 @@ +/* + * Copyright (C) 2010-2014 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "APRSWriter.h" + +#include "DStarDefines.h" +#include "Defs.h" + +CAPRSEntry::CAPRSEntry(const wxString& callsign, const wxString& band, double frequency, double offset, double range, double latitude, double longitude, double agl) : +m_callsign(callsign), +m_band(band), +m_frequency(frequency), +m_offset(offset), +m_range(range), +m_latitude(latitude), +m_longitude(longitude), +m_agl(agl), +m_timer(1000U, 10U), +m_first(true), +m_collector(NULL) +{ + m_callsign.Trim(); + + m_collector = new CAPRSCollector; +} + +CAPRSEntry::~CAPRSEntry() +{ + delete m_collector; +} + +wxString CAPRSEntry::getCallsign() const +{ + return m_callsign; +} + +wxString CAPRSEntry::getBand() const +{ + return m_band; +} + +double CAPRSEntry::getFrequency() const +{ + return m_frequency; +} + +double CAPRSEntry::getOffset() const +{ + return m_offset; +} + +double CAPRSEntry::getRange() const +{ + return m_range; +} + +double CAPRSEntry::getLatitude() const +{ + return m_latitude; +} + +double CAPRSEntry::getLongitude() const +{ + return m_longitude; +} + +double CAPRSEntry::getAGL() const +{ + return m_agl; +} + +CAPRSCollector* CAPRSEntry::getCollector() const +{ + return m_collector; +} + +void CAPRSEntry::reset() +{ + m_first = true; + m_timer.stop(); + m_collector->reset(); +} + +void CAPRSEntry::clock(unsigned int ms) +{ + m_timer.clock(ms); +} + +bool CAPRSEntry::isOK() +{ + if (m_first) { + m_first = false; + m_timer.start(); + return true; + } + + if (m_timer.hasExpired()) { + m_timer.start(); + return true; + } else { + m_timer.start(); + return false; + } +} + +CAPRSWriter::CAPRSWriter(const wxString& hostname, unsigned int port, const wxString& gateway, const wxString& address) : +m_thread(NULL), +m_enabled(false), +m_idTimer(1000U, 20U * 60U), // 20 minutes +m_gateway(), +m_array() +{ + wxASSERT(!hostname.IsEmpty()); + wxASSERT(port > 0U); + wxASSERT(!gateway.IsEmpty()); + + m_thread = new CAPRSWriterThread(gateway, address, hostname, port); + + m_gateway = gateway; + m_gateway.Truncate(LONG_CALLSIGN_LENGTH - 1U); + m_gateway.Trim(); +} + +CAPRSWriter::~CAPRSWriter() +{ + for (CEntry_t::iterator it = m_array.begin(); it != m_array.end(); ++it) + delete it->second; + + m_array.clear(); +} + +void CAPRSWriter::setPort(const wxString& callsign, const wxString& band, double frequency, double offset, double range, double latitude, double longitude, double agl) +{ + wxString temp = callsign; + temp.resize(LONG_CALLSIGN_LENGTH - 1U, wxT(' ')); + temp.Append(band); + + m_array[temp] = new CAPRSEntry(callsign, band, frequency, offset, range, latitude, longitude, agl); +} + +bool CAPRSWriter::open() +{ + return m_thread->start(); +} + +void CAPRSWriter::writeData(const wxString& callsign, const CAMBEData& data) +{ + if (data.isEnd()) + return; + + CAPRSEntry* entry = m_array[callsign]; + if (entry == NULL) { + wxLogError(wxT("Cannot find the callsign \"%s\" in the APRS array"), callsign.c_str()); + return; + } + + CAPRSCollector* collector = entry->getCollector(); + + if (data.isSync()) { + collector->sync(); + return; + } + + unsigned char buffer[400U]; + data.getData(buffer, DV_FRAME_MAX_LENGTH_BYTES); + + bool complete = collector->writeData(buffer + VOICE_FRAME_LENGTH_BYTES); + if (!complete) + return; + + if (!m_enabled) { + collector->reset(); + return; + } + + if (!m_thread->isConnected()) { + collector->reset(); + return; + } + + // Check the transmission timer + bool ok = entry->isOK(); + if (!ok) { + collector->reset(); + return; + } + + unsigned int length = collector->getData(buffer, 400U); + wxString text((char*)buffer, wxConvLocal, length); + + int n = text.Find(wxT(':')); + if (n == wxNOT_FOUND) { + collector->reset(); + return; + } + + wxString header = text.Left(n); + wxString body = text.Mid(n + 1U); + + // If we already have a q-construct, don't send it on + n = header.Find(wxT('q')); + if (n != wxNOT_FOUND) + return; + + // Remove the trailing \r + n = body.Find(wxT('\r')); + if (n != wxNOT_FOUND) + body = body.Left(n); + + wxString output; + output.Printf(wxT("%s,qAR,%s-%s:%s"), header.c_str(), entry->getCallsign().c_str(), entry->getBand().c_str(), body.c_str()); + + char ascii[500U]; + ::memset(ascii, 0x00, 500U); + for (unsigned int i = 0U; i < output.Len(); i++) + ascii[i] = output.GetChar(i); + + m_thread->write(ascii); + + collector->reset(); +} + +void CAPRSWriter::reset(const wxString& callsign) +{ + CAPRSEntry* entry = m_array[callsign]; + if (entry == NULL) { + wxLogError(wxT("Cannot find the callsign \"%s\" in the APRS array"), callsign.c_str()); + return; + } + + entry->reset(); +} + +void CAPRSWriter::setEnabled(bool enabled) +{ + m_enabled = enabled; + + if (m_enabled) { + sendIdFrames(); + m_idTimer.start(); + } +} + +void CAPRSWriter::clock(unsigned int ms) +{ + m_idTimer.clock(ms); + + if (m_idTimer.hasExpired()) { + sendIdFrames(); + m_idTimer.start(); + } + + for (CEntry_t::iterator it = m_array.begin(); it != m_array.end(); ++it) + it->second->clock(ms); +} + +bool CAPRSWriter::isConnected() const +{ + return m_thread->isConnected(); +} + +void CAPRSWriter::close() +{ + m_thread->stop(); +} + +void CAPRSWriter::sendIdFrames() +{ + if (!m_thread->isConnected()) + return; + + time_t now; + ::time(&now); + struct tm* tm = ::gmtime(&now); + + for (CEntry_t::iterator it = m_array.begin(); it != m_array.end(); ++it) { + CAPRSEntry* entry = it->second; + if (entry == NULL) + continue; + + // Default values aren't passed on + if (entry->getLatitude() == 0.0 && entry->getLongitude() == 0.0) + continue; + + wxString desc; + if (entry->getBand().Len() > 1U) { + if (entry->getFrequency() != 0.0) + desc.Printf(wxT("Data %.5lfMHz"), entry->getFrequency()); + else + desc = wxT("Data"); + } else { + if (entry->getFrequency() != 0.0) + desc.Printf(wxT("Voice %.5lfMHz %c%.4lfMHz"), + entry->getFrequency(), + entry->getOffset() < 0.0 ? wxT('-') : wxT('+'), + ::fabs(entry->getOffset())); + else + desc = wxT("Voice"); + } + + wxString band; + if (entry->getFrequency() >= 1200.0) + band = wxT("1.2"); + else if (entry->getFrequency() >= 420.0) + band = wxT("440"); + else if (entry->getFrequency() >= 144.0) + band = wxT("2m"); + else if (entry->getFrequency() >= 50.0) + band = wxT("6m"); + else if (entry->getFrequency() >= 28.0) + band = wxT("10m"); + + double tempLat = ::fabs(entry->getLatitude()); + double tempLong = ::fabs(entry->getLongitude()); + + double latitude = ::floor(tempLat); + double longitude = ::floor(tempLong); + + latitude = (tempLat - latitude) * 60.0 + latitude * 100.0; + longitude = (tempLong - longitude) * 60.0 + longitude * 100.0; + + wxString lat; + if (latitude >= 1000.0F) + lat.Printf(wxT("%.2lf"), latitude); + else if (latitude >= 100.0F) + lat.Printf(wxT("0%.2lf"), latitude); + else if (latitude >= 10.0F) + lat.Printf(wxT("00%.2lf"), latitude); + else + lat.Printf(wxT("000%.2lf"), latitude); + + wxString lon; + if (longitude >= 10000.0F) + lon.Printf(wxT("%.2lf"), longitude); + else if (longitude >= 1000.0F) + lon.Printf(wxT("0%.2lf"), longitude); + else if (longitude >= 100.0F) + lon.Printf(wxT("00%.2lf"), longitude); + else if (longitude >= 10.0F) + lon.Printf(wxT("000%.2lf"), longitude); + else + lon.Printf(wxT("0000%.2lf"), longitude); + + // Convert commas to periods in the latitude and longitude + lat.Replace(wxT(","), wxT(".")); + lon.Replace(wxT(","), wxT(".")); + + wxString output; + output.Printf(wxT("%s-S>APDG01,TCPIP*,qAC,%s-GS:;%-7s%-2s*%02d%02d%02dz%s%cD%s%caRNG%04.0lf %s %s"), + m_gateway.c_str(), m_gateway.c_str(), entry->getCallsign().c_str(), entry->getBand().c_str(), + tm->tm_mday, tm->tm_hour, tm->tm_min, + lat.c_str(), (entry->getLatitude() < 0.0F) ? wxT('S') : wxT('N'), + lon.c_str(), (entry->getLongitude() < 0.0F) ? wxT('W') : wxT('E'), + entry->getRange() * 0.6214, band.c_str(), desc.c_str()); + + char ascii[300U]; + ::memset(ascii, 0x00, 300U); + for (unsigned int i = 0U; i < output.Len(); i++) + ascii[i] = output.GetChar(i); + + m_thread->write(ascii); + + if (entry->getBand().Len() == 1U) { + output.Printf(wxT("%s-%s>APDG02,TCPIP*,qAC,%s-%sS:!%s%cD%s%c&RNG%04.0lf %s %s"), + entry->getCallsign().c_str(), entry->getBand().c_str(), entry->getCallsign().c_str(), entry->getBand().c_str(), + lat.c_str(), (entry->getLatitude() < 0.0F) ? wxT('S') : wxT('N'), + lon.c_str(), (entry->getLongitude() < 0.0F) ? wxT('W') : wxT('E'), + entry->getRange() * 0.6214, band.c_str(), desc.c_str()); + + ::memset(ascii, 0x00, 300U); + for (unsigned int i = 0U; i < output.Len(); i++) + ascii[i] = output.GetChar(i); + + m_thread->write(ascii); + } + } + + m_idTimer.start(); +} diff --git a/Common/APRSWriter.h b/Common/APRSWriter.h new file mode 100644 index 0000000..8eb1bf6 --- /dev/null +++ b/Common/APRSWriter.h @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2010,2011,2012 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef APRSWriter_H +#define APRSWriter_H + +#include "APRSWriterThread.h" +#include "APRSCollector.h" +#include "DStarDefines.h" +#include "AMBEData.h" +#include "Timer.h" +#include "Defs.h" + +#include + +class CAPRSEntry { +public: + CAPRSEntry(const wxString& callsign, const wxString& band, double frequency, double offset, double range, double latitude, double longitude, double agl); + ~CAPRSEntry(); + + wxString getCallsign() const; + wxString getBand() const; + double getFrequency() const; + double getOffset() const; + double getRange() const; + double getLatitude() const; + double getLongitude() const; + double getAGL() const; + CAPRSCollector* getCollector() const; + + // Transmission timer + void reset(); + void clock(unsigned int ms); + bool isOK(); + +private: + wxString m_callsign; + wxString m_band; + double m_frequency; + double m_offset; + double m_range; + double m_latitude; + double m_longitude; + double m_agl; + CTimer m_timer; + bool m_first; + CAPRSCollector* m_collector; +}; + +WX_DECLARE_STRING_HASH_MAP(CAPRSEntry*, CEntry_t); + +class CAPRSWriter { +public: + CAPRSWriter(const wxString& hostname, unsigned int port, const wxString& gateway, const wxString& address); + ~CAPRSWriter(); + + bool open(); + + void setPort(const wxString& callsign, const wxString& band, double frequency, double offset, double range, double latitude, double longitude, double agl); + + void writeData(const wxString& callsign, const CAMBEData& data); + + void reset(const wxString& callsign); + + void setEnabled(bool enable); + + bool isConnected() const; + + void clock(unsigned int ms); + + void close(); + +private: + CAPRSWriterThread* m_thread; + bool m_enabled; + CTimer m_idTimer; + wxString m_gateway; + CEntry_t m_array; + + void sendIdFrames(); +}; + +#endif diff --git a/Common/APRSWriterThread.cpp b/Common/APRSWriterThread.cpp new file mode 100644 index 0000000..dfaf250 --- /dev/null +++ b/Common/APRSWriterThread.cpp @@ -0,0 +1,263 @@ +/* + * Copyright (C) 2010-2014 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "APRSWriterThread.h" +#include "DStarDefines.h" +#include "Utils.h" +#include "Defs.h" + +// #define DUMP_TX + +const unsigned int APRS_TIMEOUT = 10U; + +CAPRSWriterThread::CAPRSWriterThread(const wxString& callsign, const wxString& address, const wxString& hostname, unsigned int port) : +wxThread(wxTHREAD_JOINABLE), +m_username(callsign), +m_ssid(callsign), +m_socket(hostname, port, address), +m_queue(20U), +m_exit(false), +m_connected(false), +m_APRSReadCallback(NULL), +m_filter(wxT("")), +m_clientName(wxT("ircDDBGateway")) +{ + wxASSERT(!callsign.IsEmpty()); + wxASSERT(!hostname.IsEmpty()); + wxASSERT(port > 0U); + + m_username.SetChar(LONG_CALLSIGN_LENGTH - 1U, wxT(' ')); + m_username.Trim(); + m_username.MakeUpper(); + + m_ssid = m_ssid.SubString(LONG_CALLSIGN_LENGTH - 1U, 1); +} + +CAPRSWriterThread::CAPRSWriterThread(const wxString& callsign, const wxString& address, const wxString& hostname, unsigned int port, const wxString& filter, const wxString& clientName) : +wxThread(wxTHREAD_JOINABLE), +m_username(callsign), +m_ssid(callsign), +m_socket(hostname, port, address), +m_queue(20U), +m_exit(false), +m_connected(false), +m_APRSReadCallback(NULL), +m_filter(filter), +m_clientName(clientName) +{ + wxASSERT(!callsign.IsEmpty()); + wxASSERT(!hostname.IsEmpty()); + wxASSERT(port > 0U); + + m_username.SetChar(LONG_CALLSIGN_LENGTH - 1U, wxT(' ')); + m_username.Trim(); + m_username.MakeUpper(); + + m_ssid = m_ssid.SubString(LONG_CALLSIGN_LENGTH - 1U, 1); +} + +CAPRSWriterThread::~CAPRSWriterThread() +{ + m_username.Clear(); +} + +bool CAPRSWriterThread::start() +{ + Create(); + Run(); + + return true; +} + +void* CAPRSWriterThread::Entry() +{ + wxLogMessage(wxT("Starting the APRS Writer thread")); + + m_connected = connect(); + + try { + while (!m_exit) { + if (!m_connected) { + m_connected = connect(); + + if (!m_connected){ + wxLogError(wxT("Reconnect attempt to the APRS server has failed")); + Sleep(10000UL); // 10 secs + } + } + + if (m_connected) { + if(!m_queue.isEmpty()){ + char* p = m_queue.getData(); + + wxString text(p, wxConvLocal); + wxLogMessage(wxT("APRS ==> %s"), text.c_str()); + + ::strcat(p, "\r\n"); + + bool ret = m_socket.write((unsigned char*)p, ::strlen(p)); + if (!ret) { + m_connected = false; + m_socket.close(); + wxLogError(wxT("Connection to the APRS thread has failed")); + } + + delete[] p; + } + { + wxString line; + int length = m_socket.readLine(line, APRS_TIMEOUT); + + /*if (length == 0) + wxLogWarning(wxT("No response from the APRS server after %u seconds"), APRS_TIMEOUT);*/ + + if (length < 0) { + m_connected = false; + m_socket.close(); + wxLogError(wxT("Error when reading from the APRS server")); + } + + if(length > 0 && line.GetChar(0) != '#'//check if we have something and if that something is an APRS frame + && m_APRSReadCallback != NULL)//do we have someone wanting an APRS Frame? + { + //wxLogMessage(wxT("Received APRS Frame : ") + line); + m_APRSReadCallback(wxString(line)); + } + } + + } + } + + if (m_connected) + m_socket.close(); + + while (!m_queue.isEmpty()) { + char* p = m_queue.getData(); + delete[] p; + } + } + catch (std::exception& e) { + wxString message(e.what(), wxConvLocal); + wxLogError(wxT("Exception raised in the APRS Writer thread - \"%s\""), message.c_str()); + } + catch (...) { + wxLogError(wxT("Unknown exception raised in the APRS Writer thread")); + } + + wxLogMessage(wxT("Stopping the APRS Writer thread")); + + return NULL; +} + +void CAPRSWriterThread::setReadAPRSCallback(ReadAPRSFrameCallback cb) +{ + m_APRSReadCallback = cb; +} + +void CAPRSWriterThread::write(const char* data) +{ + wxASSERT(data != NULL); + + if (!m_connected) + return; + + unsigned int len = ::strlen(data); + + char* p = new char[len + 5U]; + ::strcpy(p, data); + + m_queue.addData(p); +} + +bool CAPRSWriterThread::isConnected() const +{ + return m_connected; +} + +void CAPRSWriterThread::stop() +{ + m_exit = true; + + Wait(); +} + +bool CAPRSWriterThread::connect() +{ + unsigned int password = getAPRSPassword(m_username); + + bool ret = m_socket.open(); + if (!ret) + return false; + + //wait for lgin banner + int length; + wxString serverResponse(wxT("")); + length = m_socket.readLine(serverResponse, APRS_TIMEOUT); + if (length == 0) { + wxLogError(wxT("No reply from the APRS server after %u seconds"), APRS_TIMEOUT); + m_socket.close(); + return false; + } + wxLogMessage(wxT("Received login banner : ") + serverResponse); + + wxString filter(m_filter); + if (filter.Length() > 0) filter.Prepend(wxT(" filter ")); + wxString connectString = wxString::Format(wxT("user %s-%s pass %u vers %s%s\n"), m_username.c_str(), m_ssid.c_str(), password, + (m_clientName.Length() ? m_clientName : wxT("ircDDBGateway")).c_str(), + filter.c_str()); + //wxLogMessage(wxT("Connect String : ") + connectString); + ret = m_socket.writeLine(connectString); + if (!ret) { + m_socket.close(); + return false; + } + + + length = m_socket.readLine(serverResponse, APRS_TIMEOUT); + if (length == 0) { + wxLogError(wxT("No reply from the APRS server after %u seconds"), APRS_TIMEOUT); + m_socket.close(); + return false; + } + if (length < 0) { + wxLogError(wxT("Error when reading from the APRS server")); + m_socket.close(); + return false; + } + + wxLogMessage(wxT("Response from APRS server: ") + serverResponse); + + wxLogMessage(wxT("Connected to the APRS server")); + + return true; +} + +unsigned int CAPRSWriterThread::getAPRSPassword(wxString callsign) const +{ + unsigned int len = callsign.Length(); + + wxUint16 hash = 0x73E2U; + + for (unsigned int i = 0U; i < len; i += 2U) { + hash ^= (char)callsign.GetChar(i) << 8; + if(i + 1 < len) + hash ^= (char)callsign.GetChar(i + 1); + } + + return hash & 0x7FFFU; +} diff --git a/Common/APRSWriterThread.h b/Common/APRSWriterThread.h new file mode 100644 index 0000000..1e31254 --- /dev/null +++ b/Common/APRSWriterThread.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2010,2011,2012 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef APRSWriterThread_H +#define APRSWriterThread_H + +#include "TCPReaderWriterClient.h" +#include "RingBuffer.h" + +#include +typedef void (*ReadAPRSFrameCallback)(const wxString&); + +class CAPRSWriterThread : public wxThread { +public: + CAPRSWriterThread(const wxString& callsign, const wxString& address, const wxString& hostname, unsigned int port); + CAPRSWriterThread(const wxString& callsign, const wxString& address, const wxString& hostname, unsigned int port, const wxString& filter, const wxString& clientName); + virtual ~CAPRSWriterThread(); + + virtual bool start(); + + virtual bool isConnected() const; + + virtual void write(const char* data); + + virtual void* Entry(); + + virtual void stop(); + + void setReadAPRSCallback(ReadAPRSFrameCallback cb); + +private: + wxString m_username; + wxString m_ssid; + CTCPReaderWriterClient m_socket; + CRingBuffer m_queue; + bool m_exit; + bool m_connected; + ReadAPRSFrameCallback m_APRSReadCallback; + wxString m_filter; + wxString m_clientName; + + bool connect(); + unsigned int getAPRSPassword(wxString username) const; +}; + +#endif diff --git a/Common/AnnouncementUnit.cpp b/Common/AnnouncementUnit.cpp new file mode 100644 index 0000000..c070543 --- /dev/null +++ b/Common/AnnouncementUnit.cpp @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2014 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "DStarDefines.h" +#include "HeaderData.h" +#include "AnnouncementUnit.h" + +#include + +CAnnouncementUnit::CAnnouncementUnit(IRepeaterCallback* handler, const wxString& callsign, const wxString& fileName, const wxString& name) : +m_handler(handler), +m_callsign(callsign), +m_fileName(fileName), +m_name(name), +m_reader(NULL), +m_status(NS_IDLE), +m_timer(1000U, REPLY_TIME), +m_out(0U), +m_id(0U), +m_time() +{ + wxASSERT(handler != NULL); + + m_name.resize(SHORT_CALLSIGN_LENGTH, wxT(' ')); + + wxLogMessage(wxT("Connected '%s' to %s using file - %s"), name.c_str(), callsign.c_str(), fileName.c_str()); +} + +CAnnouncementUnit::~CAnnouncementUnit() +{ +} + +void CAnnouncementUnit::sendAnnouncement() +{ + if (m_status != NS_IDLE) + return; + + bool ret = wxFile::Exists(m_fileName.c_str()); + if (!ret) + return; + + m_reader = new CDVTOOLFileReader; + + ret = m_reader->open(m_fileName); + if (!ret) { + delete m_reader; + m_reader = NULL; + return; + } + + m_status = NS_WAIT; + m_timer.start(); +} + +void CAnnouncementUnit::clock(unsigned int ms) +{ + m_timer.clock(ms); + + if (m_status == NS_WAIT && m_timer.hasExpired()) { + m_reader->read(); // Pop the first record off the file + + m_id = CHeaderData::createId(); + + CHeaderData header; + header.setMyCall1(m_callsign); + header.setMyCall2(m_name); + header.setYourCall(wxT("CQCQCQ ")); + header.setId(m_id); + + m_handler->process(header, DIR_INCOMING, AS_INFO); + + m_timer.stop(); + + m_out = 0U; + m_status = NS_TRANSMIT; + + m_time.Start(); + + return; + } + + if (m_status == NS_TRANSMIT) { + unsigned int needed = m_time.Time() / DSTAR_FRAME_TIME_MS; + + while (m_out < needed) { + DVTFR_TYPE type = m_reader->read(); + if (type != DVTFR_DATA) { + m_out = 0U; + m_status = NS_IDLE; + m_timer.stop(); + m_reader->close(); + delete m_reader; + m_reader = NULL; + return; + } + + CAMBEData* data = m_reader->readData(); + data->setId(m_id); + + m_out++; + + m_handler->process(*data, DIR_INCOMING, AS_INFO); + + bool end = data->isEnd(); + + delete data; + + if (end) { + m_out = 0U; + m_status = NS_IDLE; + m_reader->close(); + delete m_reader; + m_reader = NULL; + m_timer.stop(); + return; + } + } + + return; + } +} + +void CAnnouncementUnit::cancel() +{ + m_status = NS_IDLE; + m_out = 0U; + m_id = 0U; + + if (m_reader != NULL) { + m_reader->close(); + delete m_reader; + m_reader = NULL; + } + + m_timer.stop(); +} diff --git a/Common/AnnouncementUnit.h b/Common/AnnouncementUnit.h new file mode 100644 index 0000000..57f794b --- /dev/null +++ b/Common/AnnouncementUnit.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2014 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef AnnouncementUnit_H +#define AnnouncementUnit_H + +#include "DVTOOLFileReader.h" +#include "RepeaterCallback.h" +#include "AMBEData.h" +#include "Timer.h" +#include "Defs.h" + +#include + +enum ANNOUNCEMENT_STATUS { + NS_IDLE, + NS_WAIT, + NS_TRANSMIT +}; + +class CAnnouncementUnit { +public: + CAnnouncementUnit(IRepeaterCallback* handler, const wxString& callsign, const wxString& fileName, const wxString& name); + ~CAnnouncementUnit(); + + void sendAnnouncement(); + + void cancel(); + + void clock(unsigned int ms); + +private: + IRepeaterCallback* m_handler; + wxString m_callsign; + wxString m_fileName; + wxString m_name; + CDVTOOLFileReader* m_reader; + ANNOUNCEMENT_STATUS m_status; + CTimer m_timer; + unsigned int m_out; + unsigned int m_id; + wxStopWatch m_time; +}; + +#endif diff --git a/Common/AudioUnit.cpp b/Common/AudioUnit.cpp new file mode 100644 index 0000000..da9774b --- /dev/null +++ b/Common/AudioUnit.cpp @@ -0,0 +1,505 @@ +/* + * Copyright (C) 2011-2014 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "DStarDefines.h" +#include "HeaderData.h" +#include "AudioUnit.h" + +#include +#include +#include +#include + +unsigned char* CAudioUnit::m_ambe = NULL; +unsigned int CAudioUnit::m_ambeLength = 0U; +CIndexList_t CAudioUnit::m_index; + +TEXT_LANG CAudioUnit::m_language = TL_ENGLISH_UK; + +const unsigned int MAX_FRAMES = 60U * DSTAR_FRAMES_PER_SEC; + +const unsigned int SILENCE_LENGTH = 10U; + +void CAudioUnit::initialise() +{ +} + +void CAudioUnit::setLanguage(TEXT_LANG language) +{ + m_language = language; + + wxString ambeFileName; + wxString indxFileName; + + switch (language) { + case TL_DEUTSCH: + ambeFileName = wxT("de_DE.ambe"); + indxFileName = wxT("de_DE.indx"); + break; + case TL_DANSK: + ambeFileName = wxT("dk_DK.ambe"); + indxFileName = wxT("dk_DK.indx"); + break; + case TL_ITALIANO: + ambeFileName = wxT("it_IT.ambe"); + indxFileName = wxT("it_IT.indx"); + break; + case TL_FRANCAIS: + ambeFileName = wxT("fr_FR.ambe"); + indxFileName = wxT("fr_FR.indx"); + break; + case TL_ESPANOL: + ambeFileName = wxT("es_ES.ambe"); + indxFileName = wxT("es_ES.indx"); + break; + case TL_SVENSKA: + ambeFileName = wxT("se_SE.ambe"); + indxFileName = wxT("se_SE.indx"); + break; + case TL_POLSKI: + ambeFileName = wxT("pl_PL.ambe"); + indxFileName = wxT("pl_PL.indx"); + break; + case TL_ENGLISH_US: + ambeFileName = wxT("en_US.ambe"); + indxFileName = wxT("en_US.indx"); + break; + case TL_NORSK: + ambeFileName = wxT("no_NO.ambe"); + indxFileName = wxT("no_NO.indx"); + break; + default: + ambeFileName = wxT("en_GB.ambe"); + indxFileName = wxT("en_GB.indx"); + break; + } + + bool ret = readAMBE(ambeFileName); + if (!ret) { + delete[] m_ambe; + m_ambe = NULL; + return; + } + + ret = readIndex(indxFileName); + if (!ret) { + delete[] m_ambe; + m_ambe = NULL; + } +} + +void CAudioUnit::finalise() +{ + for (CIndexList_t::iterator it = m_index.begin(); it != m_index.end(); ++it) + delete it->second; + + delete[] m_ambe; +} + +CAudioUnit::CAudioUnit(IRepeaterCallback* handler, const wxString& callsign) : +m_handler(handler), +m_callsign(callsign), +m_encoder(), +m_status(AS_IDLE), +m_linkStatus(LS_NONE), +m_tempLinkStatus(LS_NONE), +m_text(), +m_tempText(), +m_reflector(), +m_tempReflector(), +m_hasTemporary(false), +m_timer(1000U, REPLY_TIME), +m_data(NULL), +m_in(0U), +m_out(0U), +m_seqNo(0U), +m_time() +{ + wxASSERT(handler != NULL); + + m_data = new CAMBEData*[MAX_FRAMES]; + + for (unsigned int i = 0U; i < MAX_FRAMES; i++) + m_data[i] = NULL; +} + +CAudioUnit::~CAudioUnit() +{ + delete[] m_data; +} + +void CAudioUnit::sendStatus() +{ + if (m_ambe == NULL) + return; + + if (m_status != AS_IDLE) + return; + + m_status = AS_WAIT; + m_timer.start(); +} + +void CAudioUnit::setStatus(LINK_STATUS status, const wxString& reflector, const wxString& text) +{ + m_linkStatus = status; + m_reflector = reflector; + m_text = text; +} + +void CAudioUnit::setTempStatus(LINK_STATUS status, const wxString& reflector, const wxString& text) +{ + m_tempLinkStatus = status; + m_tempReflector = reflector; + m_tempText = text; + m_hasTemporary = true; +} + +void CAudioUnit::clock(unsigned int ms) +{ + m_timer.clock(ms); + + if (m_status == AS_WAIT && m_timer.hasExpired()) { + if (m_hasTemporary) { + sendStatus(m_tempLinkStatus, m_tempReflector, m_tempText); + m_hasTemporary = false; + } else { + sendStatus(m_linkStatus, m_reflector, m_text); + } + + m_timer.stop(); + + m_out = 0U; + m_seqNo = 0U; + m_status = AS_TRANSMIT; + + m_time.Start(); + + return; + } + + if (m_status == AS_TRANSMIT) { + unsigned int needed = m_time.Time() / DSTAR_FRAME_TIME_MS; + + while (m_out < needed) { + CAMBEData* data = m_data[m_out]; + m_data[m_out] = NULL; + m_out++; + + if (m_in == m_out) + data->setEnd(true); + + m_handler->process(*data, DIR_INCOMING, AS_INFO); + + delete data; + + if (m_in == m_out) { + m_in = 0U; + m_out = 0U; + m_status = AS_IDLE; + m_timer.stop(); + return; + } + } + + return; + } +} + +void CAudioUnit::cancel() +{ + for (unsigned int i = 0U; i < MAX_FRAMES; i++) { + if (m_data[i] != NULL) { + delete m_data[i]; + m_data[i] = NULL; + } + } + + m_status = AS_IDLE; + m_out = 0U; + m_in = 0U; + + m_timer.stop(); +} + +bool CAudioUnit::lookup(unsigned int id, const wxString &name) +{ + CIndexRecord* info = m_index[name]; + if (info == NULL) { + // wxLogError(wxT("Cannot find the AMBE index for *%s*"), name.c_str()); + return false; + } + + unsigned int start = info->getStart(); + unsigned int length = info->getLength(); + + for (unsigned int i = 0U; i < length; i++) { + unsigned char* dataIn = m_ambe + (start + i) * VOICE_FRAME_LENGTH_BYTES; + + CAMBEData* dataOut = new CAMBEData; + dataOut->setSeq(m_seqNo); + dataOut->setId(id); + + unsigned char buffer[DV_FRAME_LENGTH_BYTES]; + ::memcpy(buffer + 0U, dataIn, VOICE_FRAME_LENGTH_BYTES); + + // Insert sync bytes when the sequence number is zero, slow data otherwise + if (m_seqNo == 0U) { + ::memcpy(buffer + VOICE_FRAME_LENGTH_BYTES, DATA_SYNC_BYTES, DATA_FRAME_LENGTH_BYTES); + m_encoder.sync(); + } else { + m_encoder.getTextData(buffer + VOICE_FRAME_LENGTH_BYTES); + } + + dataOut->setData(buffer, DV_FRAME_LENGTH_BYTES); + + m_seqNo++; + if (m_seqNo == 21U) + m_seqNo = 0U; + + m_data[m_in] = dataOut; + m_in++; + } + + return true; +} + +void CAudioUnit::spellReflector(unsigned int id, const wxString &reflector) +{ + unsigned int length = reflector.Len(); + + for (unsigned int i = 0U; i < (length - 1U); i++) { + wxString c = reflector.Mid(i, 1U); + + if (!c.IsSameAs(wxT(" "))) + lookup(id, c); + } + + wxChar c = reflector.GetChar(length - 1U); + + if (c == wxT(' ')) + return; + + if (m_linkStatus == LS_LINKING_DCS || m_linkStatus == LS_LINKED_DCS || + m_linkStatus == LS_LINKING_CCS || m_linkStatus == LS_LINKED_CCS) { + lookup(id, wxString(c)); + return; + } + + switch (c) { + case wxT('A'): + lookup(id, wxT("alpha")); + break; + case wxT('B'): + lookup(id, wxT("bravo")); + break; + case wxT('C'): + lookup(id, wxT("charlie")); + break; + case wxT('D'): + lookup(id, wxT("delta")); + break; + default: + lookup(id, wxString(c)); + break; + } +} + +bool CAudioUnit::readAMBE(const wxString& name) +{ + wxFileName fileName(wxFileName::GetHomeDir(), name); + + if (!fileName.IsFileReadable()) { + wxLogMessage(wxT("File %s not readable"), fileName.GetFullPath().c_str()); +#if defined(__WINDOWS__) + fileName.Assign(::wxGetCwd(), name); +#else + fileName.Assign(wxT(DATA_DIR), name); +#endif + if (!fileName.IsFileReadable()) { + wxLogMessage(wxT("File %s not readable"), fileName.GetFullPath().c_str()); + return false; + } + } + + wxFFile file; + + bool ret = file.Open(fileName.GetFullPath().c_str(), wxT("rb")); + if (!ret) { + wxLogMessage(wxT("Cannot open %s for reading"), fileName.GetFullPath().c_str()); + return false; + } + + wxLogMessage(wxT("Reading %s"), fileName.GetFullPath().c_str()); + + unsigned char buffer[VOICE_FRAME_LENGTH_BYTES]; + + size_t n = file.Read(buffer, 4U); + if (n != 4U) { + wxLogMessage(wxT("Unable to read the header from %s"), fileName.GetFullPath().c_str()); + file.Close(); + return false; + } + + if (::memcmp(buffer, "AMBE", 4U) != 0) { + wxLogMessage(wxT("Invalid header from %s"), fileName.GetFullPath().c_str()); + file.Close(); + return false; + } + + // Length of the file minus the header + unsigned int length = file.Length() - 4U; + + // Hold the file data plus silence at the end + m_ambe = new unsigned char[length + SILENCE_LENGTH * VOICE_FRAME_LENGTH_BYTES]; + m_ambeLength = length / VOICE_FRAME_LENGTH_BYTES; + + // Add silence to the beginning of the buffer + unsigned char* p = m_ambe; + for (unsigned int i = 0U; i < SILENCE_LENGTH; i++, p += VOICE_FRAME_LENGTH_BYTES) + ::memcpy(p, NULL_AMBE_DATA_BYTES, VOICE_FRAME_LENGTH_BYTES); + + n = file.Read(p, length); + if (n != length) { + wxLogMessage(wxT("Unable to read the AMBE data from %s"), fileName.GetFullPath().c_str()); + file.Close(); + delete[] m_ambe; + m_ambe = NULL; + return false; + } + + file.Close(); + + return true; +} + +bool CAudioUnit::readIndex(const wxString& name) +{ + wxFileName fileName(wxFileName::GetHomeDir(), name); + + if (!fileName.IsFileReadable()) { + wxLogMessage(wxT("File %s not readable"), fileName.GetFullPath().c_str()); +#if defined(__WINDOWS__) + fileName.Assign(::wxGetCwd(), name); +#else + fileName.Assign(wxT(DATA_DIR), name); +#endif + if (!fileName.IsFileReadable()) { + wxLogMessage(wxT("File %s not readable"), fileName.GetFullPath().c_str()); + return false; + } + } + + wxTextFile file; + + bool ret = file.Open(fileName.GetFullPath()); + if (!ret) { + wxLogMessage(wxT("Cannot open %s for reading"), fileName.GetFullPath().c_str()); + return false; + } + + // Add a silence entry at the beginning + m_index[wxT(" ")] = new CIndexRecord(wxT(" "), 0U, SILENCE_LENGTH); + + wxLogMessage(wxT("Reading %s"), fileName.GetFullPath().c_str()); + + unsigned int nLines = file.GetLineCount(); + + for (unsigned int i = 0; i < nLines; i++) { + wxString line = file.GetLine(i); + + if (line.length() > 0 && line.GetChar(0) != wxT('#')) { + wxStringTokenizer t(line, wxT(" \t\r\n"), wxTOKEN_STRTOK); + wxString name = t.GetNextToken(); + wxString startTxt = t.GetNextToken(); + wxString lengthTxt = t.GetNextToken(); + + if (!name.IsEmpty() && !startTxt.IsEmpty() && !lengthTxt.IsEmpty()) { + unsigned long start; + startTxt.ToULong(&start); + + unsigned long length; + lengthTxt.ToULong(&length); + + if (start >= m_ambeLength || (start + length) >= m_ambeLength) + wxLogError(wxT("The start or end for *%s* is out of range, start: %lu, end: %lu"), name.c_str(), start, start + length); + else + m_index[name] = new CIndexRecord(name, start + SILENCE_LENGTH, length); + } + } + } + + file.Close(); + + return true; +} + +void CAudioUnit::sendStatus(LINK_STATUS status, const wxString& reflector, const wxString &text) +{ + m_encoder.setTextData(text); + + // Create the message + unsigned int id = CHeaderData::createId(); + + lookup(id, wxT(" ")); + lookup(id, wxT(" ")); + lookup(id, wxT(" ")); + lookup(id, wxT(" ")); + + bool found; + + switch (status) { + case LS_NONE: + lookup(id, wxT("notlinked")); + break; + case LS_LINKED_CCS: + case LS_LINKED_DCS: + case LS_LINKED_DPLUS: + case LS_LINKED_DEXTRA: + case LS_LINKED_LOOPBACK: + found = lookup(id, wxT("linkedto")); + if (!found) { + lookup(id, wxT("linked")); + lookup(id, wxT("2")); + } + spellReflector(id, reflector); + break; + default: + found = lookup(id, wxT("linkingto")); + if (!found) { + lookup(id, wxT("linking")); + lookup(id, wxT("2")); + } + spellReflector(id, reflector); + break; + } + + lookup(id, wxT(" ")); + lookup(id, wxT(" ")); + lookup(id, wxT(" ")); + lookup(id, wxT(" ")); + + // RPT1 and RPT2 will be filled in later + CHeaderData header; + header.setMyCall1(m_callsign); + header.setMyCall2(wxT("INFO")); + header.setYourCall(wxT("CQCQCQ ")); + header.setId(id); + + m_handler->process(header, DIR_INCOMING, AS_INFO); +} diff --git a/Common/AudioUnit.h b/Common/AudioUnit.h new file mode 100644 index 0000000..a910655 --- /dev/null +++ b/Common/AudioUnit.h @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2011,2012,2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef AudioUnit_H +#define AudioUnit_H + +#include "RepeaterCallback.h" +#include "SlowDataEncoder.h" +#include "AMBEData.h" +#include "Timer.h" +#include "Defs.h" + +#include + +class CIndexRecord { +public: + CIndexRecord(const wxString& name, unsigned int start, unsigned int length) : + m_name(name), + m_start(start), + m_length(length) + { + } + + wxString getName() const + { + return m_name; + } + + unsigned int getStart() const + { + return m_start; + } + + unsigned int getLength() const + { + return m_length; + } + +private: + wxString m_name; + unsigned int m_start; + unsigned int m_length; +}; + +WX_DECLARE_STRING_HASH_MAP(CIndexRecord*, CIndexList_t); + +enum AUDIO_STATUS { + AS_IDLE, + AS_WAIT, + AS_TRANSMIT +}; + +class CAudioUnit { +public: + CAudioUnit(IRepeaterCallback* handler, const wxString& callsign); + ~CAudioUnit(); + + void sendStatus(); + + void setStatus(LINK_STATUS status, const wxString& reflector, const wxString& text); + void setTempStatus(LINK_STATUS status, const wxString& reflector, const wxString& text); + + void cancel(); + + void clock(unsigned int ms); + + static void initialise(); + + static void setLanguage(TEXT_LANG language); + + static void finalise(); + +private: + static unsigned char* m_ambe; + static unsigned int m_ambeLength; + static CIndexList_t m_index; + static TEXT_LANG m_language; + + IRepeaterCallback* m_handler; + wxString m_callsign; + CSlowDataEncoder m_encoder; + AUDIO_STATUS m_status; + LINK_STATUS m_linkStatus; + LINK_STATUS m_tempLinkStatus; + wxString m_text; + wxString m_tempText; + wxString m_reflector; + wxString m_tempReflector; + bool m_hasTemporary; + CTimer m_timer; + CAMBEData** m_data; + unsigned int m_in; + unsigned int m_out; + unsigned int m_seqNo; + wxStopWatch m_time; + + bool lookup(unsigned int id, const wxString& name); + void spellReflector(unsigned int id, const wxString& reflector); + void sendStatus(LINK_STATUS status, const wxString& reflector, const wxString& text); + + static bool readAMBE(const wxString& name); + static bool readIndex(const wxString& name); +}; + +#endif diff --git a/Common/CCITTChecksum.cpp b/Common/CCITTChecksum.cpp new file mode 100644 index 0000000..e76b733 --- /dev/null +++ b/Common/CCITTChecksum.cpp @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2009 by Jonathan Naylor, G4KLX + * + * 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 + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "CCITTChecksum.h" + +#include "Utils.h" + +static const unsigned short ccittTab[] = { + 0x0000,0x1189,0x2312,0x329b,0x4624,0x57ad,0x6536,0x74bf, + 0x8c48,0x9dc1,0xaf5a,0xbed3,0xca6c,0xdbe5,0xe97e,0xf8f7, + 0x1081,0x0108,0x3393,0x221a,0x56a5,0x472c,0x75b7,0x643e, + 0x9cc9,0x8d40,0xbfdb,0xae52,0xdaed,0xcb64,0xf9ff,0xe876, + 0x2102,0x308b,0x0210,0x1399,0x6726,0x76af,0x4434,0x55bd, + 0xad4a,0xbcc3,0x8e58,0x9fd1,0xeb6e,0xfae7,0xc87c,0xd9f5, + 0x3183,0x200a,0x1291,0x0318,0x77a7,0x662e,0x54b5,0x453c, + 0xbdcb,0xac42,0x9ed9,0x8f50,0xfbef,0xea66,0xd8fd,0xc974, + 0x4204,0x538d,0x6116,0x709f,0x0420,0x15a9,0x2732,0x36bb, + 0xce4c,0xdfc5,0xed5e,0xfcd7,0x8868,0x99e1,0xab7a,0xbaf3, + 0x5285,0x430c,0x7197,0x601e,0x14a1,0x0528,0x37b3,0x263a, + 0xdecd,0xcf44,0xfddf,0xec56,0x98e9,0x8960,0xbbfb,0xaa72, + 0x6306,0x728f,0x4014,0x519d,0x2522,0x34ab,0x0630,0x17b9, + 0xef4e,0xfec7,0xcc5c,0xddd5,0xa96a,0xb8e3,0x8a78,0x9bf1, + 0x7387,0x620e,0x5095,0x411c,0x35a3,0x242a,0x16b1,0x0738, + 0xffcf,0xee46,0xdcdd,0xcd54,0xb9eb,0xa862,0x9af9,0x8b70, + 0x8408,0x9581,0xa71a,0xb693,0xc22c,0xd3a5,0xe13e,0xf0b7, + 0x0840,0x19c9,0x2b52,0x3adb,0x4e64,0x5fed,0x6d76,0x7cff, + 0x9489,0x8500,0xb79b,0xa612,0xd2ad,0xc324,0xf1bf,0xe036, + 0x18c1,0x0948,0x3bd3,0x2a5a,0x5ee5,0x4f6c,0x7df7,0x6c7e, + 0xa50a,0xb483,0x8618,0x9791,0xe32e,0xf2a7,0xc03c,0xd1b5, + 0x2942,0x38cb,0x0a50,0x1bd9,0x6f66,0x7eef,0x4c74,0x5dfd, + 0xb58b,0xa402,0x9699,0x8710,0xf3af,0xe226,0xd0bd,0xc134, + 0x39c3,0x284a,0x1ad1,0x0b58,0x7fe7,0x6e6e,0x5cf5,0x4d7c, + 0xc60c,0xd785,0xe51e,0xf497,0x8028,0x91a1,0xa33a,0xb2b3, + 0x4a44,0x5bcd,0x6956,0x78df,0x0c60,0x1de9,0x2f72,0x3efb, + 0xd68d,0xc704,0xf59f,0xe416,0x90a9,0x8120,0xb3bb,0xa232, + 0x5ac5,0x4b4c,0x79d7,0x685e,0x1ce1,0x0d68,0x3ff3,0x2e7a, + 0xe70e,0xf687,0xc41c,0xd595,0xa12a,0xb0a3,0x8238,0x93b1, + 0x6b46,0x7acf,0x4854,0x59dd,0x2d62,0x3ceb,0x0e70,0x1ff9, + 0xf78f,0xe606,0xd49d,0xc514,0xb1ab,0xa022,0x92b9,0x8330, + 0x7bc7,0x6a4e,0x58d5,0x495c,0x3de3,0x2c6a,0x1ef1,0x0f78}; + + +CCCITTChecksum::CCCITTChecksum() : +m_crc(0xFFFF) +{ +} + +CCCITTChecksum::~CCCITTChecksum() +{ +} + +void CCCITTChecksum::update(const unsigned char* data, unsigned int length) +{ + wxASSERT(data != NULL); + + for (unsigned int i = 0U; i < length; i++) { + unsigned short byte = data[i]; + + unsigned short tmp = (m_crc & 0x00FF) ^ byte; + + m_crc = (m_crc >> 8) ^ ccittTab[tmp]; + } +} + +void CCCITTChecksum::update(const bool* data) +{ + wxASSERT(data != NULL); + + unsigned short byte = CUtils::bitsToByte(data); + + unsigned short tmp = (m_crc & 0x00FF) ^ byte; + + m_crc = (m_crc >> 8) ^ ccittTab[tmp]; +} + +void CCCITTChecksum::result(unsigned char* data) // XX FIXME +{ + wxASSERT(data != NULL); + + m_crc = ~m_crc; + + unsigned short tmp = m_crc; + + m_crc = (m_crc << 8) | (tmp >> 8 & 0xFF); + + data[0] = (m_crc >> 8) & 0xFF; + data[1] = (m_crc >> 0) & 0xFF; +} + +void CCCITTChecksum::result(bool* data) +{ + wxASSERT(data != NULL); + + m_crc = ~m_crc; + + unsigned short tmp = m_crc; + + m_crc = (m_crc << 8) | (tmp >> 8 & 0xFF); + + unsigned short mask = 0x8000; + for (unsigned int i = 0U; i < 16U; i++, mask >>= 1) + data[i] = (m_crc & mask) ? true : false; +} + +bool CCCITTChecksum::check(const unsigned char* data) +{ + wxASSERT(data != NULL); + + unsigned char sum[2]; + result(sum); + + return sum[0] == data[0] && sum[1] == data[1]; +} + +bool CCCITTChecksum::check(const bool* data) +{ + wxASSERT(data != NULL); + + bool sum[16]; + result(sum); + + for (unsigned int i = 0U; i < 16U; i++) + if (sum[i] != data[i]) + return false; + + return true; +} + +void CCCITTChecksum::reset() +{ + m_crc = 0xFFFF; +} diff --git a/Common/CCITTChecksum.h b/Common/CCITTChecksum.h new file mode 100644 index 0000000..e3b9101 --- /dev/null +++ b/Common/CCITTChecksum.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2009,2013 by Jonathan Naylor, G4KLX + * + * 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 + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef CCITTChecksum_H +#define CCITTChecksum_H + +#include + +class CCCITTChecksum { +public: + CCCITTChecksum(); + ~CCCITTChecksum(); + + void update(const unsigned char* data, unsigned int length); + void update(const bool* data); + + void result(unsigned char* data); + void result(bool* data); + + bool check(const unsigned char* data); + bool check(const bool* data); + + void reset(); + +private: + wxUint16 m_crc; +}; + +#endif diff --git a/Common/CCSCallback.h b/Common/CCSCallback.h new file mode 100644 index 0000000..4fc8864 --- /dev/null +++ b/Common/CCSCallback.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef CCSCallback_H +#define CCSCallback_H + +#include "DStarDefines.h" +#include "HeaderData.h" +#include "AMBEData.h" +#include "Defs.h" + +#include + +class ICCSCallback { +public: + virtual bool process(CHeaderData& header, DIRECTION direction, AUDIO_SOURCE source) = 0; + + virtual bool process(CAMBEData& data, DIRECTION direction, AUDIO_SOURCE source) = 0; + + virtual void ccsLinkMade(const wxString& callsign, DIRECTION direction) = 0; + + virtual void ccsLinkFailed(const wxString& dtmf, DIRECTION direction) = 0; + + virtual void ccsLinkEnded(const wxString& callsign, DIRECTION direction) = 0; + +private: +}; + +#endif diff --git a/Common/CCSData.cpp b/Common/CCSData.cpp new file mode 100644 index 0000000..a589f62 --- /dev/null +++ b/Common/CCSData.cpp @@ -0,0 +1,192 @@ +/* + * Copyright (C) 2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "DStarDefines.h" +#include "CCSData.h" +#include "Utils.h" + +CCCSData::CCCSData(const wxString& local, double latitude, double longitude, double frequency, double offset, const wxString& description1, const wxString& description2, const wxString& url, CC_TYPE type) : +m_local(local), +m_remote(), +m_latitude(latitude), +m_longitude(longitude), +m_frequency(frequency), +m_offset(offset), +m_description1(description1), +m_description2(description2), +m_url(url), +m_type(type), +m_yourAddress(), +m_yourPort(0U), +m_myPort(0U) +{ +} + +CCCSData::CCCSData(const wxString& local, const wxString& remote, CC_TYPE type) : +m_local(local), +m_remote(remote), +m_latitude(0.0), +m_longitude(0.0), +m_frequency(0.0), +m_offset(0.0), +m_description1(), +m_description2(), +m_url(), +m_type(type), +m_yourAddress(), +m_yourPort(0U), +m_myPort(0U) +{ +} + +CCCSData::CCCSData() : +m_local(), +m_remote(), +m_latitude(0.0), +m_longitude(0.0), +m_frequency(0.0), +m_offset(0.0), +m_description1(), +m_description2(), +m_url(), +m_type(), +m_yourAddress(), +m_yourPort(0U), +m_myPort(0U) +{ +} + +CCCSData::~CCCSData() +{ +} + +bool CCCSData::setCCSData(const unsigned char *data, unsigned int length, const in_addr& yourAddress, unsigned int yourPort, unsigned int myPort) +{ + wxASSERT(data != NULL); + + switch (length) { + case 100U: + m_remote = wxString((char*)(data + 0U), wxConvLocal, LONG_CALLSIGN_LENGTH); + + if (::memcmp(data + 8U, "0001", 4U) == 0) { + m_type = CT_TERMINATE; + } else { + // CUtils::dump(wxT("Invalid CCS packet"), data, length); + return false; + } + + m_local = wxString((char*)(data + 12U), wxConvLocal, LONG_CALLSIGN_LENGTH); + break; + + case 20U: + if (::memcmp(data + 0U, "DTMF_CALL:", 10U) == 0) { + m_type = CT_DTMFFOUND; + } else { + CUtils::dump(wxT("Invalid CCS packet"), data, length); + return false; + } + + m_remote = wxString((char*)(data + 10U), wxConvLocal, LONG_CALLSIGN_LENGTH); + break; + + case 17U: + if (::memcmp(data + 0U, "NODTMFCALL", 10U) == 0) { + m_type = CT_DTMFNOTFOUND; + } else { + CUtils::dump(wxT("Invalid CCS packet"), data, length); + return false; + } + break; + + default: + CUtils::dump(wxT("Invalid CCS packet"), data, length); + return false; + } + + m_yourAddress = yourAddress; + m_yourPort = yourPort; + m_myPort = myPort; + + return true; +} + +unsigned int CCCSData::getCCSData(unsigned char* data, unsigned int length) const +{ + wxASSERT(data != NULL); + wxASSERT(length >= 133U); + + if (m_type == CT_TERMINATE) { + ::memset(data, ' ', 38U); + + for (unsigned int i = 0U; i < m_remote.Len() && i < LONG_CALLSIGN_LENGTH; i++) + data[i + 0U] = m_remote.GetChar(i); + + ::memcpy(data + 8U, "0001", 4U); + + for (unsigned int i = 0U; i < m_local.Len() && i < LONG_CALLSIGN_LENGTH; i++) + data[i + 12U] = m_local.GetChar(i); + + return 38U; + } else if (m_type == CT_INFO) { + wxString buffer; + buffer.Printf(wxT("IRPT%.7s %s%-10.4lf%-10.4lf%-10.4lf%-10.4lf%-20s%-20s%-40s"), m_local.Mid(0U, LONG_CALLSIGN_LENGTH - 1U).c_str(), m_local.Mid(LONG_CALLSIGN_LENGTH - 1U, 1U).c_str(), m_latitude, m_longitude, m_frequency, m_offset, m_description1.c_str(), m_description2.c_str(), m_url.c_str()); + + for (unsigned int i = 0U; i < buffer.Len() && i < 133U; i++) + data[i] = buffer.GetChar(i); + + return 133U; + } + + return 0U; +} + +wxString CCCSData::getLocal() const +{ + return m_local; +} + +wxString CCCSData::getRemote() const +{ + return m_remote; +} + +CC_TYPE CCCSData::getType() const +{ + return m_type; +} + +void CCCSData::setDestination(const in_addr& address, unsigned int port) +{ + m_yourAddress = address; + m_yourPort = port; +} + +in_addr CCCSData::getYourAddress() const +{ + return m_yourAddress; +} + +unsigned int CCCSData::getYourPort() const +{ + return m_yourPort; +} + +unsigned int CCCSData::getMyPort() const +{ + return m_myPort; +} diff --git a/Common/CCSData.h b/Common/CCSData.h new file mode 100644 index 0000000..1488dcd --- /dev/null +++ b/Common/CCSData.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef CCSData_H +#define CCSData_H + +#include + +#if defined(__WINDOWS__) +#include "Inaddr.h" +#else +#include +#endif + +enum CC_TYPE { + CT_TERMINATE, + CT_DTMFNOTFOUND, + CT_DTMFFOUND, + CT_INFO +}; + +class CCCSData { +public: + CCCSData(const wxString& local, double latitude, double longitude, double frequency, double offset, const wxString& description1, const wxString& description2, const wxString& url, CC_TYPE type); + CCCSData(const wxString& local, const wxString& remote, CC_TYPE type); + CCCSData(); + ~CCCSData(); + + bool setCCSData(const unsigned char* data, unsigned int length, const in_addr& yourAddress, unsigned int yourPort, unsigned int myPort); + + unsigned int getCCSData(unsigned char* data, unsigned int length) const; + + void setDestination(const in_addr& address, unsigned int port); + + wxString getLocal() const; + wxString getRemote() const; + CC_TYPE getType() const; + + in_addr getYourAddress() const; + unsigned int getYourPort() const; + unsigned int getMyPort() const; + +private: + wxString m_local; + wxString m_remote; + double m_latitude; + double m_longitude; + double m_frequency; + double m_offset; + wxString m_description1; + wxString m_description2; + wxString m_url; + CC_TYPE m_type; + in_addr m_yourAddress; + unsigned int m_yourPort; + unsigned int m_myPort; +}; + +#endif diff --git a/Common/CCSHandler.cpp b/Common/CCSHandler.cpp new file mode 100644 index 0000000..470d648 --- /dev/null +++ b/Common/CCSHandler.cpp @@ -0,0 +1,700 @@ +/* + * Copyright (C) 2013,2014 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "RepeaterHandler.h" +#include "DStarDefines.h" +#include "CCSHandler.h" +#include "Utils.h" + + +CCCSHandler** CCCSHandler::m_handlers = NULL; + +unsigned int CCCSHandler::m_count = 0U; + +wxString CCCSHandler::m_localAddress; +CHeaderLogger* CCCSHandler::m_headerLogger = NULL; + +wxString CCCSHandler::m_ccsHost; + +CCCSCache_t CCCSHandler::m_cache; +wxMutex CCCSHandler::m_mutex; + +bool CCCSHandler::m_stateChange = false; + + +void CCCSHandler::initialise(unsigned int count) +{ + wxASSERT(count > 0U); + + m_count = count; + m_handlers = new CCCSHandler*[m_count]; + + for (unsigned int i = 0U; i < m_count; i++) + m_handlers[i] = NULL; +} + +void CCCSHandler::setLocalAddress(const wxString& address) +{ + m_localAddress = address; +} + +void CCCSHandler::setHeaderLogger(CHeaderLogger* logger) +{ + m_headerLogger = logger; +} + +void CCCSHandler::setHost(const wxString& host) +{ + m_ccsHost = host; +} + +void CCCSHandler::process() +{ + for (unsigned int i = 0U; i < m_count; i++) { + if (m_handlers[i] != NULL) + m_handlers[i]->processInt(); + } +} + +void CCCSHandler::disconnect() +{ + for (unsigned int i = 0U; i < m_count; i++) { + if (m_handlers[i] != NULL) + m_handlers[i]->disconnectInt(); + } +} + +void CCCSHandler::clock(unsigned int ms) +{ + for (unsigned int i = 0U; i < m_count; i++) { + if (m_handlers[i] != NULL) + m_handlers[i]->clockInt(ms); + } +} + +void CCCSHandler::getInfo(ICCSCallback* handler, CRemoteRepeaterData& data) +{ + wxASSERT(handler != NULL); + + for (unsigned int i = 0U; i < m_count; i++) { + CCCSHandler* ccs = m_handlers[i]; + if (ccs != NULL && ccs->m_handler == handler && ccs->m_state == CS_ACTIVE) + data.addLink(ccs->m_yourCall, PROTO_CCS, true, ccs->m_direction, false); + } +} + +wxString CCCSHandler::getIncoming(const wxString& callsign) +{ + wxString incoming; + + for (unsigned int i = 0U; i < m_count; i++) { + CCCSHandler* handler = m_handlers[i]; + if (handler != NULL && handler->m_direction == DIR_INCOMING && handler->m_state == CS_ACTIVE && handler->m_callsign.IsSameAs(callsign)) { + incoming.Append(handler->m_yourCall); + incoming.Append(wxT(" ")); + } + } + + return incoming; +} + +void CCCSHandler::finalise() +{ + for (unsigned int i = 0U; i < m_count; i++) + delete m_handlers[i]; + + delete[] m_handlers; +} + +CCCSHandler::CCCSHandler(ICCSCallback* handler, const wxString& callsign, unsigned int delay, double latitude, double longitude, double frequency, double offset, const wxString& description1, const wxString& description2, const wxString& url, unsigned int localPort) : +m_handler(handler), +m_callsign(callsign), +m_reflector(), +m_latitude(latitude), +m_longitude(longitude), +m_frequency(frequency), +m_offset(offset), +m_description1(description1), +m_description2(description2), +m_url(url), +m_ccsAddress(), +m_protocol(localPort, m_localAddress), +m_state(CS_DISABLED), +m_local(), +m_announceTimer(1000U, 20U), // 20 seconds +m_inactivityTimer(1000U, 300U), // 5 minutes +m_pollInactivityTimer(1000U, 60U), // 60 seconds +m_pollTimer(1000U, 10U), // 10 seconds +m_waitTimer(1000U, delay), +m_tryTimer(1000U, 1U), // 1 second +m_tryCount(0U), +m_id(0x00U), +m_seqNo(0U), +m_time(), +m_direction(DIR_OUTGOING), +m_yourCall(), +m_myCall1(), +m_myCall2(), +m_rptCall1() +{ + wxASSERT(handler != NULL); + + // Add to the global list + for (unsigned int i = 0U; i < m_count; i++) { + if (m_handlers[i] == NULL) { + m_handlers[i] = this; + break; + } + } +} + +CCCSHandler::~CCCSHandler() +{ +} + +void CCCSHandler::setReflector(const wxString& callsign) +{ + m_reflector = callsign; + + if (m_reflector.IsEmpty()) + m_reflector = wxT(" "); +} + +void CCCSHandler::processInt() +{ + if (m_state == CS_DISABLED) + return; + + for (;;) { + CCS_TYPE type = m_protocol.read(); + + switch (type) { + case CT_DATA: { + CAMBEData* data = m_protocol.readData(); + if (data != NULL) { + process(*data); + delete data; + } + } + break; + + case CT_POLL: { + CPollData* poll = m_protocol.readPoll(); + if (poll != NULL) { + process(*poll); + delete poll; + } + } + break; + + case CT_CONNECT: { + CConnectData* connect = m_protocol.readConnect(); + if (connect != NULL) { + process(*connect); + delete connect; + } + } + break; + + case CT_MISC: { + CCCSData* data = m_protocol.readMisc(); + if (data != NULL) { + process(*data); + delete data; + } + } + break; + + default: + return; + } + } +} + +void CCCSHandler::process(CAMBEData& data) +{ + CHeaderData& header = data.getHeader(); + wxString myCall1 = header.getMyCall1(); + wxString rptCall1 = header.getRptCall1(); + wxString yourCall = header.getYourCall(); + unsigned int seqNo = data.getSeq(); + unsigned int id = data.getId(); + + if (m_state != CS_CONNECTED && m_state != CS_ACTIVE) + return; + + // This is a new incoming CCS call + if (m_state == CS_CONNECTED) { + m_yourCall = myCall1; + m_local = yourCall; + m_rptCall1 = rptCall1; + m_direction = DIR_INCOMING; + m_time = ::time(NULL); + m_state = CS_ACTIVE; + m_stateChange = true; + m_inactivityTimer.start(); + + m_handler->ccsLinkMade(m_yourCall, m_direction); + + wxLogMessage(wxT("CCS: New incoming link to %s from %s @ %s"), m_local.c_str(), m_yourCall.c_str(), m_rptCall1.c_str()); + } else { + if (!m_yourCall.IsSameAs(myCall1) && !m_rptCall1.IsSameAs(rptCall1)) { + wxLogMessage(wxT("CCS: Rejecting new incoming CCS link from %s @ %s to %s"), myCall1.c_str(), rptCall1.c_str(), yourCall.c_str()); + + CCCSData data(yourCall, myCall1, CT_TERMINATE); + data.setDestination(m_ccsAddress, CCS_PORT); + + m_protocol.writeMisc(data); + m_protocol.writeMisc(data); + m_protocol.writeMisc(data); + m_protocol.writeMisc(data); + m_protocol.writeMisc(data); + + return; + } + + // Allow for the fact that the distant repeater may change during the QSO + if (m_yourCall.IsSameAs(myCall1) && !m_rptCall1.IsSameAs(rptCall1)) { + wxLogMessage(wxT("CCS: %s has moved from repeater %s to %s"), m_yourCall.c_str(), m_rptCall1.c_str(), rptCall1.c_str()); + m_rptCall1 = rptCall1; + } + } + + m_pollInactivityTimer.start(); + m_inactivityTimer.start(); + + if (m_id != id) { + // Write to Header.log if it's enabled + if (m_headerLogger != NULL) + m_headerLogger->write(wxT("CCS"), header); + + header.setCQCQCQ(); + m_handler->process(header, DIR_INCOMING, AS_CCS); + + m_id = id; + } else if (seqNo == 0U) { + header.setCQCQCQ(); + m_handler->process(header, DIR_INCOMING, AS_DUP); + } + + m_handler->process(data, DIR_INCOMING, AS_CCS); +} + +void CCCSHandler::process(CCCSData& data) +{ + CC_TYPE type = data.getType(); + + switch (type) { + case CT_TERMINATE: + if (m_state == CS_ACTIVE) { + wxLogMessage(wxT("CCS: Link between %s and %s has been terminated"), data.getLocal().c_str(), data.getRemote().c_str()); + m_stateChange = true; + m_state = CS_CONNECTED; + m_inactivityTimer.stop(); + m_handler->ccsLinkEnded(data.getRemote(), m_direction); + } + break; + + case CT_DTMFNOTFOUND: + wxLogMessage(wxT("CCS: Cannot map %s to a callsign"), m_yourCall.c_str()); + m_stateChange = true; + m_state = CS_CONNECTED; + m_inactivityTimer.stop(); + m_handler->ccsLinkFailed(m_yourCall, m_direction); + break; + + case CT_DTMFFOUND: + wxLogMessage(wxT("CCS: Mapped %s to %s, added to the cache"), m_yourCall.c_str(), data.getRemote().c_str()); + addToCache(m_yourCall, data.getRemote()); + m_stateChange = true; + m_yourCall = data.getRemote(); + m_rptCall1 = data.getRemote(); + m_handler->ccsLinkMade(m_yourCall, m_direction); + break; + + default: + break; + } +} + +void CCCSHandler::process(CPollData&) +{ + m_pollInactivityTimer.start(); +} + +void CCCSHandler::process(CConnectData& connect) +{ + CD_TYPE type = connect.getType(); + + if (type == CT_ACK && m_state == CS_CONNECTING) { + wxLogMessage(wxT("CCS: %s connected to server %s"), m_callsign.c_str(), m_ccsHost.c_str()); + + m_announceTimer.start(); + m_pollInactivityTimer.start(); + m_pollTimer.start(); + m_tryTimer.stop(); + + // Give our location, frequency, etc + CCCSData data(m_callsign, m_latitude, m_longitude, m_frequency, m_offset, m_description1, m_description2, m_url, CT_INFO); + data.setDestination(m_ccsAddress, CCS_PORT); + m_protocol.writeMisc(data); + + m_state = CS_CONNECTED; + + return; + } + + if (type == CT_NAK && m_state == CS_CONNECTING) { + wxLogMessage(wxT("CCS: Connection refused for %s"), m_callsign.c_str()); + m_tryTimer.stop(); + m_state = CS_DISABLED; + return; + } +} + +bool CCCSHandler::connect() +{ + // Is CCS disabled? + if (m_localAddress.IsSameAs(wxT("127.0.0.1"))) + return false; + + // Can we resolve the CCS server address? + m_ccsAddress = CUDPReaderWriter::lookup(m_ccsHost); + if (m_ccsAddress.s_addr == INADDR_NONE) { + wxLogError(wxT("CCS: Unable to find the IP address for %s"), m_ccsHost.c_str()); + return false; + } + + bool res = m_protocol.open(); + if (!res) + return false; + + wxLogMessage(wxT("CCS: Opening UDP port %u for %s"), m_protocol.getPort(), m_callsign.c_str()); + + m_waitTimer.start(); + + m_state = CS_CONNECTING; + + return true; +} + +void CCCSHandler::disconnectInt() +{ + if (m_state == CS_CONNECTED || m_state == CS_ACTIVE) { + CConnectData connect(m_callsign, CT_UNLINK, m_ccsAddress, CCS_PORT); + m_protocol.writeConnect(connect); + } + + m_announceTimer.stop(); + m_pollInactivityTimer.stop(); + m_inactivityTimer.stop(); + m_pollTimer.stop(); + m_tryTimer.stop(); + + if (m_state != CS_DISABLED) + m_protocol.close(); + + m_state = CS_DISABLED; +} + +void CCCSHandler::startLink(const wxString& dtmf, const wxString& user, const wxString& type) +{ + if (m_state != CS_CONNECTED) + return; + + wxString callsign = findInCache(dtmf); + if (!callsign.IsEmpty()) { + wxLogMessage(wxT("CCS: New outgoing link to %s/%s via %s by %s"), dtmf.c_str(), callsign.c_str(), type.c_str(), user.c_str()); + m_handler->ccsLinkMade(callsign, m_direction); + m_yourCall = callsign; + m_rptCall1 = callsign; + } else { + wxLogMessage(wxT("CCS: New outgoing link to %s via %s by %s"), dtmf.c_str(), type.c_str(), user.c_str()); + m_yourCall = dtmf; + m_yourCall.resize(LONG_CALLSIGN_LENGTH, wxT(' ')); + m_rptCall1.Clear(); + } + + m_local = user; + m_seqNo = 0U; + + m_time = ::time(NULL); + m_stateChange = true; + m_state = CS_ACTIVE; + m_direction = DIR_OUTGOING; + m_inactivityTimer.start(); +} + +void CCCSHandler::stopLink(const wxString& user, const wxString& type) +{ + if (m_state != CS_ACTIVE) + return; + + if (!user.IsEmpty() && !type.IsEmpty()) + wxLogMessage(wxT("CCS: Link to %s from %s has been terminated via %s by %s"), m_yourCall.c_str(), m_local.c_str(), type.c_str(), user.c_str()); + + CCCSData data(m_local, m_yourCall, CT_TERMINATE); + data.setDestination(m_ccsAddress, CCS_PORT); + + m_protocol.writeMisc(data); + m_protocol.writeMisc(data); + m_protocol.writeMisc(data); + m_protocol.writeMisc(data); + m_protocol.writeMisc(data); + + m_stateChange = true; + m_state = CS_CONNECTED; + m_inactivityTimer.stop(); + + m_handler->ccsLinkEnded(m_yourCall, m_direction); +} + +void CCCSHandler::unlink(const wxString& callsign) +{ + if (m_state != CS_ACTIVE) + return; + + if (!m_yourCall.IsSameAs(callsign)) + return; + + wxLogMessage(wxT("CCS: Link to %s from %s has been terminated by command"), m_yourCall.c_str(), m_local.c_str()); + + CCCSData data(m_local, m_yourCall, CT_TERMINATE); + data.setDestination(m_ccsAddress, CCS_PORT); + + m_protocol.writeMisc(data); + m_protocol.writeMisc(data); + m_protocol.writeMisc(data); + m_protocol.writeMisc(data); + m_protocol.writeMisc(data); + + m_stateChange = true; + m_state = CS_CONNECTED; + m_inactivityTimer.stop(); + + m_handler->ccsLinkEnded(m_yourCall, m_direction); +} + +void CCCSHandler::writeHeard(CHeaderData& header) +{ + if (m_state != CS_CONNECTED && m_state != CS_ACTIVE) + return; + + CHeardData heard(header, m_callsign, m_reflector); + heard.setDestination(m_ccsAddress, CCS_PORT); + m_protocol.writeHeard(heard); +} + +void CCCSHandler::writeHeader(CHeaderData& header) +{ + m_myCall1 = header.getMyCall1(); + m_myCall2 = header.getMyCall2(); + + m_seqNo = 0U; +} + +void CCCSHandler::writeAMBE(CAMBEData& data) +{ + if (m_state != CS_ACTIVE) + return; + + CAMBEData temp(data); + + CHeaderData& header = temp.getHeader(); + header.setMyCall1(m_myCall1); + header.setMyCall2(m_myCall2); + header.setYourCall(m_yourCall); + header.setRptCall1(m_callsign); + header.setRptCall2(m_reflector); + + temp.setRptSeq(m_seqNo++); + temp.setDestination(m_ccsAddress, CCS_PORT); + m_protocol.writeData(temp); +} + +CCS_STATUS CCCSHandler::getStatus() const +{ + return m_state; +} + +void CCCSHandler::clockInt(unsigned int ms) +{ + m_announceTimer.clock(ms); + m_pollInactivityTimer.clock(ms); + m_inactivityTimer.clock(ms); + m_pollTimer.clock(ms); + m_waitTimer.clock(ms); + m_tryTimer.clock(ms); + + if (m_pollInactivityTimer.isRunning() && m_pollInactivityTimer.hasExpired()) { + wxLogMessage(wxT("CCS: Connection has failed (poll inactivity) for %s, reconnecting"), m_callsign.c_str()); + + m_announceTimer.stop(); + m_pollInactivityTimer.stop(); + m_inactivityTimer.stop(); + m_pollTimer.stop(); + + if (m_state == CS_ACTIVE) { + m_stateChange = true; + m_handler->ccsLinkEnded(m_yourCall, m_direction); + } + + m_waitTimer.start(); + + m_state = CS_CONNECTING; + + return; + } + + if (m_tryTimer.isRunning() && m_tryTimer.hasExpired()) { + CConnectData connect(m_callsign, CT_LINK1, m_ccsAddress, CCS_PORT); + if (m_latitude != 0.0 && m_longitude != 0.0) { + wxString locator = CUtils::latLonToLoc(m_latitude, m_longitude); + connect.setLocator(locator); + } + m_protocol.writeConnect(connect); + + unsigned int t = calcBackoff(); + m_tryTimer.start(t); + } + + if (m_pollTimer.isRunning() && m_pollTimer.hasExpired()) { + CPollData poll(m_callsign, m_ccsAddress, CCS_PORT); + m_protocol.writePoll(poll); + + m_pollTimer.start(); + } + + if (m_inactivityTimer.isRunning() && m_inactivityTimer.hasExpired()) { + wxLogMessage(wxT("CCS: Activity timeout on link for %s"), m_callsign.c_str(), m_callsign.c_str()); + + CCCSData data(m_local, m_yourCall, CT_TERMINATE); + data.setDestination(m_ccsAddress, CCS_PORT); + + m_protocol.writeMisc(data); + m_protocol.writeMisc(data); + m_protocol.writeMisc(data); + m_protocol.writeMisc(data); + m_protocol.writeMisc(data); + + m_stateChange = true; + m_state = CS_CONNECTED; + m_inactivityTimer.stop(); + + m_handler->ccsLinkEnded(m_yourCall, m_direction); + } + + if (m_waitTimer.isRunning() && m_waitTimer.hasExpired()) { + CConnectData connect(m_callsign, CT_LINK1, m_ccsAddress, CCS_PORT); + if (m_latitude != 0.0 && m_longitude != 0.0) { + wxString locator = CUtils::latLonToLoc(m_latitude, m_longitude); + connect.setLocator(locator); + } + m_protocol.writeConnect(connect); + + m_tryTimer.start(1U); + m_tryCount = 1U; + + m_waitTimer.stop(); + } + + if (m_announceTimer.isRunning() && m_announceTimer.hasExpired()) { + CHeaderData header; + header.setMyCall1(m_callsign.Left(LONG_CALLSIGN_LENGTH - 1U)); + CHeardData heard(header, m_callsign, wxEmptyString); + heard.setDestination(m_ccsAddress, CCS_PORT); + m_protocol.writeHeard(heard); + + m_announceTimer.start(3600U); + } +} + +unsigned int CCCSHandler::calcBackoff() +{ + if (m_tryCount >= 7U) { + m_tryCount++; + return 60U; + } + + unsigned int timeout = 1U; + + for (unsigned int i = 0U; i < m_tryCount; i++) + timeout *= 2U; + + m_tryCount++; + + if (timeout > 60U) + return 60U; + else + return timeout; +} + +bool CCCSHandler::stateChange() +{ + bool stateChange = m_stateChange; + + m_stateChange = false; + + return stateChange; +} + +void CCCSHandler::writeStatus(wxFFile& file) +{ + for (unsigned int i = 0U; i < m_count; i++) { + CCCSHandler* handler = m_handlers[i]; + if (handler != NULL) { + struct tm* tm = ::gmtime(&handler->m_time); + + switch (handler->m_direction) { + case DIR_OUTGOING: + if (handler->m_state == CS_ACTIVE) { + wxString text; + text.Printf(wxT("%04d-%02d-%02d %02d:%02d:%02d: CCS link - Rptr: %s Remote: %s Dir: Outgoing\n"), + tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, + handler->m_callsign.c_str(), handler->m_yourCall.c_str()); + file.Write(text); + } + break; + + case DIR_INCOMING: + if (handler->m_state == CS_ACTIVE) { + wxString text; + text.Printf(wxT("%04d-%02d-%02d %02d:%02d:%02d: CCS link - Rptr: %s Remote: %s Dir: Incoming\n"), + tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, + handler->m_callsign.c_str(), handler->m_yourCall.c_str()); + file.Write(text); + } + break; + } + } + } +} + +void CCCSHandler::addToCache(const wxString& dtmf, const wxString& callsign) +{ + wxMutexLocker locker(m_mutex); + + m_cache[dtmf] = callsign; +} + +wxString CCCSHandler::findInCache(const wxString& dtmf) +{ + wxMutexLocker locker(m_mutex); + + return m_cache[dtmf]; +} diff --git a/Common/CCSHandler.h b/Common/CCSHandler.h new file mode 100644 index 0000000..81f5a1a --- /dev/null +++ b/Common/CCSHandler.h @@ -0,0 +1,155 @@ +/* + * Copyright (C) 2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef CCSHandler_H +#define CCSHandler_H + +#include "CCSProtocolHandler.h" +#include "DStarDefines.h" +#include "HeaderLogger.h" +#include "ConnectData.h" +#include "CCSCallback.h" +#include "AMBEData.h" +#include "PollData.h" +#include "Timer.h" +#include "Defs.h" + +#if defined(__WINDOWS__) +#include "Inaddr.h" +#else +#include +#endif + +#include +#include + +enum CCS_STATUS { + CS_DISABLED, + CS_CONNECTING, + CS_CONNECTED, + CS_ACTIVE +}; + +WX_DECLARE_STRING_HASH_MAP(wxString, CCCSCache_t); + +class CCCSHandler { +public: + CCCSHandler(ICCSCallback* handler, const wxString& callsign, unsigned int delay, double latitude, double longitude, double frequency, double offset, const wxString& description1, const wxString& description2, const wxString& url, unsigned int localPort); + ~CCCSHandler(); + + bool connect(); + + void writeHeard(CHeaderData& header); + void writeHeader(CHeaderData& header); + void writeAMBE(CAMBEData& data); + + void startLink(const wxString& dtmf, const wxString& user, const wxString& type); + void stopLink(const wxString& user = wxEmptyString, const wxString& type = wxEmptyString); + + void unlink(const wxString& callsign); + + void setReflector(const wxString& callsign = wxEmptyString); + + CCS_STATUS getStatus() const; + + static void disconnect(); + + static void initialise(unsigned int count); + + static void process(); + + static void clock(unsigned int ms); + + static void setHeaderLogger(CHeaderLogger* logger); + + static void setLocalAddress(const wxString& address); + + static void setHost(const wxString& host); + + static bool stateChange(); + static void writeStatus(wxFFile& file); + + static void getInfo(ICCSCallback* handler, CRemoteRepeaterData& data); + + static wxString getIncoming(const wxString& callsign); + + static void finalise(); + +protected: + void clockInt(unsigned int ms); + + void processInt(); + + void disconnectInt(); + +private: + static CCCSHandler** m_handlers; + static unsigned int m_count; + + static wxString m_localAddress; + static CHeaderLogger* m_headerLogger; + + static wxString m_ccsHost; + + static CCCSCache_t m_cache; + static wxMutex m_mutex; + + static bool m_stateChange; + + ICCSCallback* m_handler; + wxString m_callsign; + wxString m_reflector; + double m_latitude; + double m_longitude; + double m_frequency; + double m_offset; + wxString m_description1; + wxString m_description2; + wxString m_url; + in_addr m_ccsAddress; + CCCSProtocolHandler m_protocol; + CCS_STATUS m_state; + wxString m_local; + CTimer m_announceTimer; + CTimer m_inactivityTimer; + CTimer m_pollInactivityTimer; + CTimer m_pollTimer; + CTimer m_waitTimer; + CTimer m_tryTimer; + unsigned int m_tryCount; + unsigned int m_id; + unsigned int m_seqNo; + time_t m_time; + DIRECTION m_direction; + wxString m_yourCall; + wxString m_myCall1; + wxString m_myCall2; + wxString m_rptCall1; + + void process(CAMBEData& header); + void process(CPollData& data); + void process(CConnectData& connect); + void process(CCCSData& data); + + unsigned int calcBackoff(); + + static void addToCache(const wxString& dtmf, const wxString& callsign); + static wxString findInCache(const wxString& dtmf); +}; + +#endif diff --git a/Common/CCSProtocolHandler.cpp b/Common/CCSProtocolHandler.cpp new file mode 100644 index 0000000..9c22456 --- /dev/null +++ b/Common/CCSProtocolHandler.cpp @@ -0,0 +1,235 @@ +/* + * Copyright (C) 2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "CCSProtocolHandler.h" + +#include "DStarDefines.h" +#include "Utils.h" + +// #define DUMP_TX + +const unsigned int BUFFER_LENGTH = 2000U; + +CCCSProtocolHandler::CCCSProtocolHandler(unsigned int port, const wxString& addr) : +m_socket(addr, port), +m_type(CT_NONE), +m_buffer(NULL), +m_length(0U), +m_yourAddress(), +m_yourPort(0U), +m_myPort(port) +{ + m_buffer = new unsigned char[BUFFER_LENGTH]; +} + +CCCSProtocolHandler::~CCCSProtocolHandler() +{ + delete[] m_buffer; +} + +bool CCCSProtocolHandler::open() +{ + return m_socket.open(); +} + +unsigned int CCCSProtocolHandler::getPort() const +{ + return m_myPort; +} + +bool CCCSProtocolHandler::writeData(const CAMBEData& data) +{ + unsigned char buffer[100U]; + unsigned int length = data.getCCSData(buffer, 100U); + +#if defined(DUMP_TX) + CUtils::dump(wxT("Sending Data"), buffer, length); +#endif + + return m_socket.write(buffer, length, data.getYourAddress(), data.getYourPort()); +} + +bool CCCSProtocolHandler::writePoll(const CPollData& poll) +{ + unsigned char buffer[30U]; + unsigned int length = poll.getCCSData(buffer, 30U); + +#if defined(DUMP_TX) + CUtils::dump(wxT("Sending Poll"), buffer, length); +#endif + + return m_socket.write(buffer, length, poll.getYourAddress(), poll.getYourPort()); +} + +bool CCCSProtocolHandler::writeHeard(const CHeardData& heard) +{ + unsigned char buffer[100U]; + unsigned int length = heard.getCCSData(buffer, 100U); + +#if defined(DUMP_TX) + CUtils::dump(wxT("Sending Heard"), buffer, length); +#endif + + return m_socket.write(buffer, length, heard.getAddress(), heard.getPort()); +} + +bool CCCSProtocolHandler::writeConnect(const CConnectData& connect) +{ + unsigned char buffer[40U]; + unsigned int length = connect.getCCSData(buffer, 40U); + +#if defined(DUMP_TX) + CUtils::dump(wxT("Sending Connect"), buffer, length); +#endif + + return m_socket.write(buffer, length, connect.getYourAddress(), connect.getYourPort()); +} + +bool CCCSProtocolHandler::writeMisc(const CCCSData& data) +{ + unsigned char buffer[140U]; + unsigned int length = data.getCCSData(buffer, 140U); + +#if defined(DUMP_TX) + CUtils::dump(wxT("Sending Misc"), buffer, length); +#endif + + return m_socket.write(buffer, length, data.getYourAddress(), data.getYourPort()); +} + +CCS_TYPE CCCSProtocolHandler::read() +{ + bool res = true; + + // Loop until we have no more data from the socket or we have data for the higher layers + while (res) + res = readPackets(); + + return m_type; +} + +bool CCCSProtocolHandler::readPackets() +{ + m_type = CT_NONE; + + // No more data? + int length = m_socket.read(m_buffer, BUFFER_LENGTH, m_yourAddress, m_yourPort); + if (length <= 0) + return false; + + m_length = length; + + if (m_buffer[0] == '0' && m_buffer[1] == '0' && m_buffer[2] == '0' && m_buffer[3] == '1') { + m_type = CT_DATA; + return false; + } else if (m_buffer[0] == 'L' && m_buffer[1] == 'L' && m_buffer[2] == 'L') { + return true; + } else { + switch (m_length) { + case 14U: + m_type = CT_CONNECT; + return false; + case 25U: + m_type = CT_POLL; + return false; + case 100U: + case 20U: + case 17U: + m_type = CT_MISC; + return false; + case 39U: + return true; + default: + break; + } + } + + // An unknown type + CUtils::dump(wxT("Unknown packet type from CCS"), m_buffer, m_length); + + return true; +} + +CAMBEData* CCCSProtocolHandler::readData() +{ + if (m_type != CT_DATA) + return NULL; + + CAMBEData* data = new CAMBEData; + + bool res = data->setCCSData(m_buffer, m_length, m_yourAddress, m_yourPort, m_myPort); + if (!res) { + delete data; + return NULL; + } + + return data; +} + +CConnectData* CCCSProtocolHandler::readConnect() +{ + if (m_type != CT_CONNECT) + return NULL; + + CConnectData* connect = new CConnectData; + + bool res = connect->setCCSData(m_buffer, m_length, m_yourAddress, m_yourPort, m_myPort); + if (!res) { + delete connect; + return NULL; + } + + return connect; +} + +CPollData* CCCSProtocolHandler::readPoll() +{ + if (m_type != CT_POLL) + return NULL; + + CPollData* poll = new CPollData; + + bool res = poll->setCCSData(m_buffer, m_length, m_yourAddress, m_yourPort, m_myPort); + if (!res) { + delete poll; + return NULL; + } + + return poll; +} + +CCCSData* CCCSProtocolHandler::readMisc() +{ + if (m_type != CT_MISC) + return NULL; + + CCCSData* data = new CCCSData; + + bool res = data->setCCSData(m_buffer, m_length, m_yourAddress, m_yourPort, m_myPort); + if (!res) { + delete data; + return NULL; + } + + return data; +} + +void CCCSProtocolHandler::close() +{ + m_socket.close(); +} diff --git a/Common/CCSProtocolHandler.h b/Common/CCSProtocolHandler.h new file mode 100644 index 0000000..87bc9f1 --- /dev/null +++ b/Common/CCSProtocolHandler.h @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef CCSProtocolHandler_H +#define CCSProtocolHandler_H + +#include "UDPReaderWriter.h" +#include "DStarDefines.h" +#include "ConnectData.h" +#include "HeardData.h" +#include "AMBEData.h" +#include "PollData.h" +#include "CCSData.h" + +#if defined(__WINDOWS__) +#include "Inaddr.h" +#else +#include +#endif + +#include + +enum CCS_TYPE { + CT_NONE, + CT_DATA, + CT_POLL, + CT_CONNECT, + CT_MISC +}; + +class CCCSProtocolHandler { +public: + CCCSProtocolHandler(unsigned int port, const wxString& addr = wxEmptyString); + ~CCCSProtocolHandler(); + + bool open(); + + unsigned int getPort() const; + + bool writeData(const CAMBEData& data); + bool writeConnect(const CConnectData& connect); + bool writePoll(const CPollData& poll); + bool writeHeard(const CHeardData& heard); + bool writeMisc(const CCCSData& data); + + CCS_TYPE read(); + CAMBEData* readData(); + CPollData* readPoll(); + CConnectData* readConnect(); + CCCSData* readMisc(); + + void close(); + +private: + CUDPReaderWriter m_socket; + CCS_TYPE m_type; + unsigned char* m_buffer; + unsigned int m_length; + in_addr m_yourAddress; + unsigned int m_yourPort; + unsigned int m_myPort; + + bool readPackets(); +}; + +#endif diff --git a/Common/CacheManager.cpp b/Common/CacheManager.cpp new file mode 100644 index 0000000..7915d1b --- /dev/null +++ b/Common/CacheManager.cpp @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2010,2011,2012 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "CacheManager.h" +#include "DStarDefines.h" + +CCacheManager::CCacheManager() : +m_mutex(), +m_userCache(), +m_gatewayCache(), +m_repeaterCache() +{ +} + +CCacheManager::~CCacheManager() +{ +} + +CUserData* CCacheManager::findUser(const wxString& user) +{ + wxMutexLocker locker(m_mutex); + + CUserRecord* ur = m_userCache.find(user); + if (ur == NULL) + return NULL; + + CRepeaterRecord* rr = m_repeaterCache.find(ur->getRepeater()); + wxString gateway; + if (rr == NULL) { + gateway = ur->getRepeater(); + gateway.Append(wxT(" ")); + gateway.Truncate(LONG_CALLSIGN_LENGTH - 1U); + gateway.Append(wxT("G")); + } else { + gateway = rr->getGateway(); + } + + CGatewayRecord* gr = m_gatewayCache.find(gateway); + if (gr == NULL) + return NULL; + + return new CUserData(user, ur->getRepeater(), gr->getGateway(), gr->getAddress()); +} + +CGatewayData* CCacheManager::findGateway(const wxString& gateway) +{ + wxMutexLocker locker(m_mutex); + + CGatewayRecord* gr = m_gatewayCache.find(gateway); + if (gr == NULL) + return NULL; + + return new CGatewayData(gateway, gr->getAddress(), gr->getProtocol()); +} + +CRepeaterData* CCacheManager::findRepeater(const wxString& repeater) +{ + wxMutexLocker locker(m_mutex); + + CRepeaterRecord* rr = m_repeaterCache.find(repeater); + wxString gateway; + if (rr == NULL) { + gateway = repeater; + gateway.Append(wxT(" ")); + gateway.Truncate(LONG_CALLSIGN_LENGTH - 1U); + gateway.Append(wxT("G")); + } else { + gateway = rr->getGateway(); + } + + CGatewayRecord* gr = m_gatewayCache.find(gateway); + if (gr == NULL) + return NULL; + + return new CRepeaterData(repeater, gr->getGateway(), gr->getAddress(), gr->getProtocol()); +} + +void CCacheManager::updateUser(const wxString& user, const wxString& repeater, const wxString& gateway, const wxString& address, const wxString& timestamp, DSTAR_PROTOCOL protocol, bool addrLock, bool protoLock) +{ + wxMutexLocker locker(m_mutex); + + wxString repeater7 = repeater.Left(LONG_CALLSIGN_LENGTH - 1U); + wxString gateway7 = gateway.Left(LONG_CALLSIGN_LENGTH - 1U); + + m_userCache.update(user, repeater, timestamp); + + // Only store non-standard repeater-gateway pairs + if (!repeater7.IsSameAs(gateway7)) + m_repeaterCache.update(repeater, gateway); + + m_gatewayCache.update(gateway, address, protocol, addrLock, protoLock); +} + +void CCacheManager::updateRepeater(const wxString& repeater, const wxString& gateway, const wxString& address, DSTAR_PROTOCOL protocol, bool addrLock, bool protoLock) +{ + wxMutexLocker locker(m_mutex); + + wxString repeater7 = repeater.Left(LONG_CALLSIGN_LENGTH - 1U); + wxString gateway7 = gateway.Left(LONG_CALLSIGN_LENGTH - 1U); + + // Only store non-standard repeater-gateway pairs + if (!repeater7.IsSameAs(gateway7)) + m_repeaterCache.update(repeater, gateway); + + m_gatewayCache.update(gateway, address, protocol, addrLock, protoLock); +} + +void CCacheManager::updateGateway(const wxString& gateway, const wxString& address, DSTAR_PROTOCOL protocol, bool addrLock, bool protoLock) +{ + wxMutexLocker locker(m_mutex); + + m_gatewayCache.update(gateway, address, protocol, addrLock, protoLock); +} diff --git a/Common/CacheManager.h b/Common/CacheManager.h new file mode 100644 index 0000000..e8d669b --- /dev/null +++ b/Common/CacheManager.h @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2010,2011,2012 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef CacheManager_H +#define CacheManager_H + +#include + +#if defined(__WINDOWS__) +#include "Inaddr.h" +#else +#include +#endif + +#include "RepeaterCache.h" +#include "GatewayCache.h" +#include "UserCache.h" + +class CUserData { +public: + CUserData(const wxString& user, const wxString& repeater, const wxString& gateway, in_addr address) : + m_user(user), + m_repeater(repeater), + m_gateway(gateway), + m_address(address) + { + } + + wxString getUser() const + { + return m_user; + } + + wxString getRepeater() const + { + return m_repeater; + } + + wxString getGateway() const + { + return m_gateway; + } + + in_addr getAddress() const + { + return m_address; + } + +private: + wxString m_user; + wxString m_repeater; + wxString m_gateway; + in_addr m_address; +}; + +class CRepeaterData { +public: + CRepeaterData(const wxString& repeater, const wxString& gateway, in_addr address, DSTAR_PROTOCOL protocol) : + m_repeater(repeater), + m_gateway(gateway), + m_address(address), + m_protocol(protocol) + { + } + + wxString getRepeater() const + { + return m_repeater; + } + + wxString getGateway() const + { + return m_gateway; + } + + in_addr getAddress() const + { + return m_address; + } + + DSTAR_PROTOCOL getProtocol() const + { + return m_protocol; + } + +private: + wxString m_repeater; + wxString m_gateway; + in_addr m_address; + DSTAR_PROTOCOL m_protocol; +}; + +class CGatewayData { +public: + CGatewayData(const wxString& gateway, in_addr address, DSTAR_PROTOCOL protocol) : + m_gateway(gateway), + m_address(address), + m_protocol(protocol) + { + } + + wxString getGateway() const + { + return m_gateway; + } + + in_addr getAddress() const + { + return m_address; + } + + DSTAR_PROTOCOL getProtocol() const + { + return m_protocol; + } + +private: + wxString m_gateway; + in_addr m_address; + DSTAR_PROTOCOL m_protocol; +}; + +class CCacheManager { +public: + CCacheManager(); + ~CCacheManager(); + + CUserData* findUser(const wxString& user); + CGatewayData* findGateway(const wxString& gateway); + CRepeaterData* findRepeater(const wxString& repeater); + + void updateUser(const wxString& user, const wxString& repeater, const wxString& gateway, const wxString& address, const wxString& timeStamp, DSTAR_PROTOCOL protocol, bool addrLock, bool protoLock); + void updateRepeater(const wxString& repeater, const wxString& gateway, const wxString& address, DSTAR_PROTOCOL protocol, bool addrLock, bool protoLock); + void updateGateway(const wxString& gateway, const wxString& address, DSTAR_PROTOCOL protocol, bool addrLock, bool protoLock); + +private: + wxMutex m_mutex; + CUserCache m_userCache; + CGatewayCache m_gatewayCache; + CRepeaterCache m_repeaterCache; +}; + +#endif diff --git a/Common/CallsignList.cpp b/Common/CallsignList.cpp new file mode 100644 index 0000000..f55a1f5 --- /dev/null +++ b/Common/CallsignList.cpp @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2011 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "CallsignList.h" +#include "DStarDefines.h" + +#include + +CCallsignList::CCallsignList(const wxString& filename) : +m_filename(filename), +m_callsigns() +{ +} + + +CCallsignList::~CCallsignList() +{ +} + +bool CCallsignList::load() +{ + wxTextFile file; + + bool res = file.Open(m_filename); + if (!res) + return false; + + unsigned int lines = file.GetLineCount(); + if (lines == 0U) { + file.Close(); + return true; + } + + m_callsigns.Alloc(lines); + + wxString callsign = file.GetFirstLine(); + + while (!file.Eof()) { + callsign.MakeUpper(); + callsign.Append(wxT(" ")); + callsign.Truncate(LONG_CALLSIGN_LENGTH); + + m_callsigns.Add(callsign); + + callsign = file.GetNextLine(); + } + + file.Close(); + + return true; +} + +unsigned int CCallsignList::getCount() const +{ + return m_callsigns.GetCount(); +} + +bool CCallsignList::isInList(const wxString& callsign) const +{ + return m_callsigns.Index(callsign) != wxNOT_FOUND; +} diff --git a/Common/CallsignList.h b/Common/CallsignList.h new file mode 100644 index 0000000..2a8d06c --- /dev/null +++ b/Common/CallsignList.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2011,2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef CallsignList_H +#define CallsignList_H + +#include + +class CCallsignList { +public: + CCallsignList(const wxString& filename); + ~CCallsignList(); + + bool load(); + + unsigned int getCount() const; + + bool isInList(const wxString& callsign) const; + +private: + wxString m_filename; + wxArrayString m_callsigns; +}; + +#endif diff --git a/Common/CallsignServer.cpp b/Common/CallsignServer.cpp new file mode 100644 index 0000000..94e59d7 --- /dev/null +++ b/Common/CallsignServer.cpp @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2012,2013,2014 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "TCPReaderWriterClient.h" +#include "CallsignServer.h" +#include "DStarDefines.h" +#include "Utils.h" +#include "Defs.h" + +const wxString CALLSERVER_HOSTNAME = wxT("dns.xreflector.net"); +const unsigned int CALLSERVER_PORT = 20001U; + +const unsigned int TCP_TIMEOUT = 10U; + +CCallsignServer::CCallsignServer(const wxString& callsign, const wxString& address, CCacheManager* cache) : +wxThread(wxTHREAD_JOINABLE), +m_callsign(callsign), +m_address(address), +m_cache(cache), +m_timer(1U, 1U * 3600U), // 1 hour +m_killed(false) +{ + wxASSERT(!callsign.IsEmpty()); + wxASSERT(cache != NULL); +} + +CCallsignServer::~CCallsignServer() +{ +} + +void CCallsignServer::start() +{ + process(CALLSERVER_HOSTNAME, CALLSERVER_PORT); + + Create(); + Run(); +} + +void* CCallsignServer::Entry() +{ + wxLogMessage(wxT("Starting the Callsign Server thread")); + + m_timer.start(); + + try { + while (!m_killed) { + if (m_timer.hasExpired()) { + process(CALLSERVER_HOSTNAME, CALLSERVER_PORT); + m_timer.start(); + } + + Sleep(1000UL); + + m_timer.clock(); + } + } + catch (std::exception& e) { + wxString message(e.what(), wxConvLocal); + wxLogError(wxT("Exception raised in the Callsign Server thread - \"%s\""), message.c_str()); + } + catch (...) { + wxLogError(wxT("Unknown exception raised in the Callsign Server thread")); + } + + wxLogMessage(wxT("Stopping the Callsign Server thread")); + + return NULL; +} + +void CCallsignServer::stop() +{ + m_killed = true; + + Wait(); +} + +void CCallsignServer::process(const wxString& hostname, unsigned int port) +{ + CTCPReaderWriterClient socket(hostname, port, m_address); + + bool ret = socket.open(); + if (!ret) { + wxLogMessage(wxT("Cannot connect to %s"), hostname.c_str()); + return; + } + + // Space for 5000 entries + unsigned int length = 5000U * (6U + 1U + 15U + 1U); + + unsigned char* buffer = new unsigned char[length + 1U]; + ::memset(buffer, ' ', 29U); + + for (unsigned int i = 0U; i < m_callsign.Len() && i < LONG_CALLSIGN_LENGTH - 1U; i++) + buffer[i + 0U] = m_callsign.GetChar(i); + + ::memcpy(buffer + 9U, "ircDDB Gateway", 14U); + + socket.write(buffer, 29U); + + unsigned int offset = 0U; + + int n = socket.read(buffer, length, TCP_TIMEOUT); + if (n >= 0) + offset += n; + + while (n >= 0 && offset < length) { + n = socket.read(buffer + offset, length - offset, TCP_TIMEOUT); + if (n == 0) + Sleep(TCP_TIMEOUT * 1000UL); + else if (n > 0) + offset += n; + } + + buffer[offset] = 0x00U; + + unsigned int count = 0U; + + char* p = (char*)buffer; + + for (;;) { + // Split into lines + char* p1 = ::strchr(p, 0x0A); + if (p1 != NULL) + *p1 = 0x00; + + if (::strncmp(p, "DCS", 3U) == 0) { + char* p2 = ::strtok(p, " \t\r\n"); + char* p3 = ::strtok(NULL, " \t\r\n"); + + if (p2 != NULL && p3 != NULL) { + wxString name = wxString(p2, wxConvLocal); + wxString address = wxString(p3, wxConvLocal); + + if (!address.IsSameAs(wxT("0.0.0.0"))) { + wxLogMessage(wxT("DCS: %s\t%s"), name.c_str(), address.c_str()); + + name.resize(LONG_CALLSIGN_LENGTH - 1U, wxT(' ')); + name.Append(wxT("G")); + m_cache->updateGateway(name, address, DP_DCS, false, true); + + count++; + } + } + } + + if (p1 == NULL) + break; + + p = p1 + 1U; + } + + wxLogMessage(wxT("Registered with %s using callsign %s"), hostname.c_str(), m_callsign.Left(LONG_CALLSIGN_LENGTH - 1U).c_str()); + + wxLogMessage(wxT("Loaded %u DCS reflectors from %s"), count, hostname.c_str()); + + delete[] buffer; + socket.close(); +} diff --git a/Common/CallsignServer.h b/Common/CallsignServer.h new file mode 100644 index 0000000..1238a44 --- /dev/null +++ b/Common/CallsignServer.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2012,2014 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef CallsignServer_H +#define CallsignServer_H + +#include "CacheManager.h" +#include "Timer.h" + +#include + +#if defined(__WINDOWS__) +#include "Inaddr.h" +#else +#include +#endif + +class CCallsignServer : public wxThread { +public: + CCallsignServer(const wxString& callsign, const wxString& address, CCacheManager* cache); + virtual ~CCallsignServer(); + + virtual void start(); + + virtual void* Entry(); + + virtual void stop(); + +private: + wxString m_callsign; + wxString m_address; + CCacheManager* m_cache; + CTimer m_timer; + bool m_killed; + + void process(const wxString& hostname, unsigned int port); +}; + +#endif diff --git a/Common/Common.vcxproj b/Common/Common.vcxproj new file mode 100644 index 0000000..bdbcfc3 --- /dev/null +++ b/Common/Common.vcxproj @@ -0,0 +1,295 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {E793CB8E-2AC9-431A-BBFC-3F52537BB3CF} + Common + Win32Proj + 10.0.16299.0 + + + + StaticLibrary + v141 + Unicode + true + + + StaticLibrary + v141 + Unicode + true + + + StaticLibrary + v141 + Unicode + + + StaticLibrary + v141 + Unicode + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>14.0.24720.0 + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + $(WXWIN)\include;$(IncludePath);$(WXWIN)\lib\vc_dll\mswud + + + $(WXWIN)\include;$(IncludePath);$(WXWIN)\lib\vc_dll\mswud + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + + + + + + + Disabled + $(WXWIN)\include\msvc;$(WXWIN)\include;../ircDDB;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;WINVER=0x0400;__WXMSW__;WXUSINGDLL;wxUSE_GUI=1;__WXDEBUG__;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_LIB;DCS_LINK;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + Level4 + EditAndContinue + + + + + + + + + Disabled + $(WXWIN)\include\msvc;$(WXWIN)\include;../ircDDB;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;WINVER=0x0400;__WXMSW__;WXUSINGDLL;wxUSE_GUI=1;__WXDEBUG__;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_LIB;DCS_LINK;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + + + Level4 + ProgramDatabase + + + + + + + + MaxSpeed + true + $(WXWIN)\include\msvc;$(WXWIN)\include;../ircDDB;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;WINVER=0x0400;__WXMSW__;WXUSINGDLL;wxUSE_GUI=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_LIB;%(PreprocessorDefinitions) + MultiThreadedDLL + true + + Level3 + ProgramDatabase + + + + + + + + + MaxSpeed + true + $(WXWIN)\include\msvc;$(WXWIN)\include;../ircDDB;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;WINVER=0x0400;__WXMSW__;WXUSINGDLL;wxUSE_GUI=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_LIB;%(PreprocessorDefinitions) + MultiThreadedDLL + true + + + Level3 + ProgramDatabase + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Common/Common.vcxproj.filters b/Common/Common.vcxproj.filters new file mode 100644 index 0000000..8365240 --- /dev/null +++ b/Common/Common.vcxproj.filters @@ -0,0 +1,437 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/Common/ConnectData.cpp b/Common/ConnectData.cpp new file mode 100644 index 0000000..2489b73 --- /dev/null +++ b/Common/ConnectData.cpp @@ -0,0 +1,543 @@ +/* + * Copyright (C) 2010,2012,2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "ConnectData.h" + +#include "DStarDefines.h" +#include "Version.h" +#include "Utils.h" + +const wxChar* HTML = wxT("
%s ircDDB Gateway %s
"); + +CConnectData::CConnectData(GATEWAY_TYPE gatewayType, const wxString& repeater, const wxString& reflector, CD_TYPE type, const in_addr& yourAddress, unsigned int yourPort, unsigned int myPort) : +m_gatewayType(gatewayType), +m_repeater(repeater), +m_reflector(reflector), +m_type(type), +m_locator(), +m_yourAddress(yourAddress), +m_yourPort(yourPort), +m_myPort(myPort) +{ + wxASSERT(yourPort > 0U); + wxASSERT(!repeater.IsEmpty()); + wxASSERT(!reflector.IsEmpty()); +} + +CConnectData::CConnectData(const wxString& repeater, const wxString& reflector, CD_TYPE type, const in_addr& yourAddress, unsigned int yourPort, unsigned int myPort) : +m_gatewayType(GT_REPEATER), +m_repeater(repeater), +m_reflector(reflector), +m_type(type), +m_locator(), +m_yourAddress(yourAddress), +m_yourPort(yourPort), +m_myPort(myPort) +{ + wxASSERT(yourPort > 0U); + wxASSERT(!repeater.IsEmpty()); + wxASSERT(!reflector.IsEmpty()); +} + +CConnectData::CConnectData(const wxString& repeater, CD_TYPE type, const in_addr& yourAddress, unsigned int yourPort, unsigned int myPort) : +m_gatewayType(GT_REPEATER), +m_repeater(repeater), +m_reflector(), +m_type(type), +m_locator(), +m_yourAddress(yourAddress), +m_yourPort(yourPort), +m_myPort(myPort) +{ + wxASSERT(yourPort > 0U); + wxASSERT(!repeater.IsEmpty()); +} + +CConnectData::CConnectData(const wxString& repeater, const in_addr& yourAddress, unsigned int yourPort, unsigned int myPort) : +m_gatewayType(GT_REPEATER), +m_repeater(repeater), +m_reflector(), +m_type(CT_UNLINK), +m_locator(), +m_yourAddress(yourAddress), +m_yourPort(yourPort), +m_myPort(myPort) +{ + wxASSERT(yourPort > 0U); + wxASSERT(!repeater.IsEmpty()); +} + +CConnectData::CConnectData(CD_TYPE type, const in_addr& yourAddress, unsigned int yourPort, unsigned int myPort) : +m_gatewayType(GT_REPEATER), +m_repeater(), +m_reflector(), +m_type(type), +m_locator(), +m_yourAddress(yourAddress), +m_yourPort(yourPort), +m_myPort(myPort) +{ + wxASSERT(yourPort > 0U); +} + +CConnectData::CConnectData() : +m_gatewayType(GT_REPEATER), +m_repeater(wxT(" ")), +m_reflector(), +m_type(CT_LINK1), +m_locator(), +m_yourAddress(), +m_yourPort(0U), +m_myPort(0U) +{ +} + +CConnectData::~CConnectData() +{ +} + +bool CConnectData::setDExtraData(const unsigned char* data, unsigned int length, const in_addr& yourAddress, unsigned int yourPort, unsigned int myPort) +{ + wxASSERT(data != NULL); + wxASSERT(length >= 11U); + wxASSERT(yourPort > 0U); + + m_repeater = wxString((const char*)data, wxConvLocal, LONG_CALLSIGN_LENGTH); + m_repeater.SetChar(LONG_CALLSIGN_LENGTH - 1U, data[LONG_CALLSIGN_LENGTH + 0U]); + + m_reflector = wxT(" "); + m_reflector.SetChar(LONG_CALLSIGN_LENGTH - 1U, data[LONG_CALLSIGN_LENGTH + 1U]); + + switch (length) { + case 11U: + if (m_reflector.IsSameAs(wxT(" "))) + m_type = CT_UNLINK; + else + m_type = CT_LINK1; + break; + + case 14U: + if (data[LONG_CALLSIGN_LENGTH + 2U] == 'A' && + data[LONG_CALLSIGN_LENGTH + 3U] == 'C' && + data[LONG_CALLSIGN_LENGTH + 4U] == 'K') + m_type = CT_ACK; + else if (data[LONG_CALLSIGN_LENGTH + 2U] == 'N' && + data[LONG_CALLSIGN_LENGTH + 3U] == 'A' && + data[LONG_CALLSIGN_LENGTH + 4U] == 'K') + m_type = CT_NAK; + else + return false; + + break; + + default: + return false; + } + + m_yourAddress = yourAddress; + m_yourPort = yourPort; + m_myPort = myPort; + + return true; +} + +bool CConnectData::setDCSData(const unsigned char* data, unsigned int length, const in_addr& yourAddress, unsigned int yourPort, unsigned int myPort) +{ + wxASSERT(data != NULL); + wxASSERT(length >= 11U); + wxASSERT(yourPort > 0U); + + m_repeater = wxString((const char*)data, wxConvLocal, LONG_CALLSIGN_LENGTH); + m_repeater.SetChar(LONG_CALLSIGN_LENGTH - 1U, data[LONG_CALLSIGN_LENGTH + 0U]); + + switch (length) { + case 519U: + m_reflector = wxString((const char*)(data + LONG_CALLSIGN_LENGTH + 3U), wxConvLocal, LONG_CALLSIGN_LENGTH); + m_reflector.SetChar(LONG_CALLSIGN_LENGTH - 1U, data[LONG_CALLSIGN_LENGTH + 1U]); + m_type = CT_LINK1; + break; + + case 19U: + m_reflector = wxString((const char*)(data + LONG_CALLSIGN_LENGTH + 3U), wxConvLocal, LONG_CALLSIGN_LENGTH); + m_reflector.SetChar(LONG_CALLSIGN_LENGTH - 1U, data[LONG_CALLSIGN_LENGTH + 1U]); + m_type = CT_UNLINK; + break; + + case 14U: + if (data[LONG_CALLSIGN_LENGTH + 2U] == 'A' && + data[LONG_CALLSIGN_LENGTH + 3U] == 'C' && + data[LONG_CALLSIGN_LENGTH + 4U] == 'K') + m_type = CT_ACK; + else if (data[LONG_CALLSIGN_LENGTH + 2U] == 'N' && + data[LONG_CALLSIGN_LENGTH + 3U] == 'A' && + data[LONG_CALLSIGN_LENGTH + 4U] == 'K') + m_type = CT_NAK; + else + return false; + + break; + + default: + return false; + } + + m_yourAddress = yourAddress; + m_yourPort = yourPort; + m_myPort = myPort; + + return true; +} + +bool CConnectData::setCCSData(const unsigned char* data, unsigned int length, const in_addr& yourAddress, unsigned int yourPort, unsigned int myPort) +{ + wxASSERT(data != NULL); + wxASSERT(length >= 14U); + wxASSERT(yourPort > 0U); + + m_repeater = wxString((const char*)data, wxConvLocal, LONG_CALLSIGN_LENGTH); + m_repeater.SetChar(LONG_CALLSIGN_LENGTH - 1U, data[LONG_CALLSIGN_LENGTH + 0U]); + + if (data[LONG_CALLSIGN_LENGTH + 2U] == 'A' && + data[LONG_CALLSIGN_LENGTH + 3U] == 'C' && + data[LONG_CALLSIGN_LENGTH + 4U] == 'K') + m_type = CT_ACK; + else if (data[LONG_CALLSIGN_LENGTH + 2U] == 'N' && + data[LONG_CALLSIGN_LENGTH + 3U] == 'A' && + data[LONG_CALLSIGN_LENGTH + 4U] == 'K') + m_type = CT_NAK; + else + return false; + + m_yourAddress = yourAddress; + m_yourPort = yourPort; + m_myPort = myPort; + + return true; +} + +bool CConnectData::setDPlusData(const unsigned char* data, unsigned int length, const in_addr& yourAddress, unsigned int yourPort, unsigned int myPort) +{ + wxASSERT(data != NULL); + wxASSERT(length >= 5U); + wxASSERT(yourPort > 0U); + + switch (length) { + case 5U: + switch (data[4U]) { + case 0x01: + m_type = CT_LINK1; + break; + case 0x00: + m_type = CT_UNLINK; + break; + } + break; + + case 8U: { + wxString reply((const char*)(data + 4U), wxConvLocal, 4U); + wxLogMessage(wxT("D-Plus reply is %.4s"), reply.c_str()); + + if (::memcmp(data + 4U, "OKRW", 4U) == 0) + m_type = CT_ACK; + else + m_type = CT_NAK; + } + break; + + case 28U: + m_repeater = wxString((const char*)(data + 4U), wxConvLocal); + m_type = CT_LINK2; + break; + + default: + return false; + } + + m_yourAddress = yourAddress; + m_yourPort = yourPort; + m_myPort = myPort; + + return true; +} + +unsigned int CConnectData::getDExtraData(unsigned char *data, unsigned int length) const +{ + wxASSERT(data != NULL); + wxASSERT(length >= 11U); + + ::memset(data, ' ', LONG_CALLSIGN_LENGTH); + + for (unsigned int i = 0U; i < m_repeater.Len() && i < (LONG_CALLSIGN_LENGTH - 1U); i++) + data[i] = m_repeater.GetChar(i); + + data[LONG_CALLSIGN_LENGTH + 0U] = m_repeater.GetChar(LONG_CALLSIGN_LENGTH - 1U); + + switch (m_type) { + case CT_LINK1: + case CT_LINK2: + data[LONG_CALLSIGN_LENGTH + 1U] = m_reflector.GetChar(LONG_CALLSIGN_LENGTH - 1U); + data[LONG_CALLSIGN_LENGTH + 2U] = 0x00; + return 11U; + + case CT_UNLINK: + data[LONG_CALLSIGN_LENGTH + 1U] = ' '; + data[LONG_CALLSIGN_LENGTH + 2U] = 0x00; + return 11U; + + case CT_ACK: + data[LONG_CALLSIGN_LENGTH + 1U] = m_reflector.GetChar(LONG_CALLSIGN_LENGTH - 1U); + data[LONG_CALLSIGN_LENGTH + 2U] = 'A'; + data[LONG_CALLSIGN_LENGTH + 3U] = 'C'; + data[LONG_CALLSIGN_LENGTH + 4U] = 'K'; + data[LONG_CALLSIGN_LENGTH + 5U] = 0x00; + return 14U; + + case CT_NAK: + data[LONG_CALLSIGN_LENGTH + 1U] = m_reflector.GetChar(LONG_CALLSIGN_LENGTH - 1U); + data[LONG_CALLSIGN_LENGTH + 2U] = 'N'; + data[LONG_CALLSIGN_LENGTH + 3U] = 'A'; + data[LONG_CALLSIGN_LENGTH + 4U] = 'K'; + data[LONG_CALLSIGN_LENGTH + 5U] = 0x00; + return 14U; + + default: + return 0U; + } +} + +unsigned int CConnectData::getDCSData(unsigned char *data, unsigned int length) const +{ + wxASSERT(data != NULL); + wxASSERT(length >= 519U); + + ::memset(data, ' ', LONG_CALLSIGN_LENGTH); + + for (unsigned int i = 0U; i < m_repeater.Len() && i < (LONG_CALLSIGN_LENGTH - 1U); i++) + data[i] = m_repeater.GetChar(i); + + data[LONG_CALLSIGN_LENGTH + 0U] = m_repeater.GetChar(LONG_CALLSIGN_LENGTH - 1U); + + switch (m_type) { + case CT_LINK1: + case CT_LINK2: { + data[LONG_CALLSIGN_LENGTH + 1U] = m_reflector.GetChar(LONG_CALLSIGN_LENGTH - 1U); + data[LONG_CALLSIGN_LENGTH + 2U] = 0x00U; + ::memset(data + 11U, ' ', LONG_CALLSIGN_LENGTH); + for (unsigned int i = 0U; i < m_reflector.Len() && i < (LONG_CALLSIGN_LENGTH - 1U); i++) + data[i + 11U] = m_reflector.GetChar(i); + + wxString html; + switch (m_gatewayType) { + case GT_HOTSPOT: + html.Printf(HTML, wxT("hotspot.jpg"), wxT("HOTSPOT"), VERSION.c_str()); + break; + case GT_DONGLE: + html.Printf(HTML, wxT("dongle.jpg"), wxT("DONGLE"), VERSION.c_str()); + break; + case GT_STARNET: + html.Printf(HTML, wxT("hf.jpg"), wxT("STARNET"), VERSION.c_str()); + break; + default: + html.Printf(HTML, wxT("hf.jpg"), wxT("REPEATER"), VERSION.c_str()); + break; + } + + ::memset(data + 19U, 0x00U, 500U); + for (unsigned int i = 0U; i < html.Len(); i++) + data[i + 19U] = html.GetChar(i); + } + return 519U; + + case CT_UNLINK: + data[LONG_CALLSIGN_LENGTH + 1U] = 0x20U; + data[LONG_CALLSIGN_LENGTH + 2U] = 0x00U; + ::memset(data + 11U, ' ', LONG_CALLSIGN_LENGTH); + for (unsigned int i = 0U; i < m_reflector.Len() && i < (LONG_CALLSIGN_LENGTH - 1U); i++) + data[i + 11U] = m_reflector.GetChar(i); + return 19U; + + case CT_ACK: + data[LONG_CALLSIGN_LENGTH + 1U] = m_reflector.GetChar(LONG_CALLSIGN_LENGTH - 1U); + data[LONG_CALLSIGN_LENGTH + 2U] = 'A'; + data[LONG_CALLSIGN_LENGTH + 3U] = 'C'; + data[LONG_CALLSIGN_LENGTH + 4U] = 'K'; + data[LONG_CALLSIGN_LENGTH + 5U] = 0x00; + return 14U; + + case CT_NAK: + data[LONG_CALLSIGN_LENGTH + 1U] = 0x20U; + data[LONG_CALLSIGN_LENGTH + 2U] = 'N'; + data[LONG_CALLSIGN_LENGTH + 3U] = 'A'; + data[LONG_CALLSIGN_LENGTH + 4U] = 'K'; + data[LONG_CALLSIGN_LENGTH + 5U] = 0x00; + return 14U; + + default: + return 0U; + } +} + +unsigned int CConnectData::getCCSData(unsigned char *data, unsigned int length) const +{ + wxASSERT(data != NULL); + wxASSERT(length >= 39U); + + ::memset(data, ' ', 39U); + + for (unsigned int i = 0U; i < m_repeater.Len() && i < (LONG_CALLSIGN_LENGTH - 1U); i++) + data[i] = m_repeater.GetChar(i); + + data[LONG_CALLSIGN_LENGTH + 0U] = m_repeater.GetChar(LONG_CALLSIGN_LENGTH - 1U); + + switch (m_type) { + case CT_LINK1: + case CT_LINK2: { + data[9U] = 0x41U; + data[10U] = '@'; + + for (unsigned int i = 0U; i < m_locator.Len(); i++) + data[11U + i] = m_locator.GetChar(i); + + data[17U] = 0x20U; + data[18U] = '@'; + + wxString text; + text.Printf(wxT("ircDDB_GW-%s"), VERSION.Left(8U).c_str()); + + for (unsigned int i = 0U; i < text.Len(); i++) + data[19U + i] = text.GetChar(i); + } + return 39U; + + case CT_UNLINK: + return 19U; + + default: + return 0U; + } +} + +unsigned int CConnectData::getDPlusData(unsigned char *data, unsigned int length) const +{ + wxASSERT(data != NULL); + wxASSERT(length >= 28U); + + switch (m_type) { + case CT_LINK1: + data[0U] = 0x05; + data[1U] = 0x00; + data[2U] = 0x18; + data[3U] = 0x00; + data[4U] = 0x01; + return 5U; + + case CT_LINK2: { + data[0U] = 0x1C; + data[1U] = 0xC0; + data[2U] = 0x04; + data[3U] = 0x00; + + for (unsigned int i = 4U; i < 20U; i++) + data[i] = 0x00; + + wxString callsign = m_repeater; + callsign.Trim(); + + for (unsigned int i = 0U; i < callsign.Len(); i++) + data[i + 4U] = callsign.GetChar(i); + + data[20U] = 'D'; + data[21U] = 'V'; + data[22U] = '0'; + data[23U] = '1'; + data[24U] = '9'; + data[25U] = '9'; + data[26U] = '9'; + data[27U] = '9'; + } + return 28U; + + case CT_UNLINK: + data[0U] = 0x05; + data[1U] = 0x00; + data[2U] = 0x18; + data[3U] = 0x00; + data[4U] = 0x00; + return 5U; + + case CT_ACK: + data[0U] = 0x08; + data[1U] = 0xC0; + data[2U] = 0x04; + data[3U] = 0x00; + data[4U] = 'O'; + data[5U] = 'K'; + data[6U] = 'R'; + data[7U] = 'W'; + return 8U; + + case CT_NAK: + data[0U] = 0x08; + data[1U] = 0xC0; + data[2U] = 0x04; + data[3U] = 0x00; + data[4U] = 'B'; + data[5U] = 'U'; + data[6U] = 'S'; + data[7U] = 'Y'; + return 8U; + + default: + return 0U; + } +} + +in_addr CConnectData::getYourAddress() const +{ + return m_yourAddress; +} + +unsigned int CConnectData::getYourPort() const +{ + return m_yourPort; +} + +unsigned int CConnectData::getMyPort() const +{ + return m_myPort; +} + +wxString CConnectData::getRepeater() const +{ + return m_repeater; +} + +wxString CConnectData::getReflector() const +{ + return m_reflector; +} + +CD_TYPE CConnectData::getType() const +{ + return m_type; +} + +void CConnectData::setLocator(const wxString& locator) +{ + m_locator = locator; +} diff --git a/Common/ConnectData.h b/Common/ConnectData.h new file mode 100644 index 0000000..da6ea78 --- /dev/null +++ b/Common/ConnectData.h @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2010,2012,2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef ConnectData_H +#define ConnectData_H + +#include "Defs.h" + +#include + +#if defined(__WINDOWS__) +#include "Inaddr.h" +#else +#include +#endif + +enum CD_TYPE { + CT_LINK1, + CT_LINK2, + CT_UNLINK, + CT_ACK, + CT_NAK +}; + +class CConnectData { +public: + CConnectData(GATEWAY_TYPE gatewayType, const wxString& repeater, const wxString& reflector, CD_TYPE type, const in_addr& yourAddress, unsigned int yourPort, unsigned int myPort = 0U); + CConnectData(const wxString& repeater, const wxString& reflector, CD_TYPE type, const in_addr& yourAddress, unsigned int yourPort, unsigned int myPort = 0U); + CConnectData(const wxString& repeater, const in_addr& yourAddress, unsigned int yourPort, unsigned int myPort = 0U); + CConnectData(const wxString& repeater, CD_TYPE type, const in_addr& yourAddress, unsigned int yourPort, unsigned int myPort = 0U); + CConnectData(CD_TYPE type, const in_addr& yourAddress, unsigned int yourPort, unsigned int myPort = 0U); + CConnectData(); + ~CConnectData(); + + bool setDExtraData(const unsigned char* data, unsigned int length, const in_addr& yourAddress, unsigned int yourPort, unsigned int myPort); + bool setDPlusData(const unsigned char* data, unsigned int length, const in_addr& yourAddress, unsigned int yourPort, unsigned int myPort); + bool setDCSData(const unsigned char* data, unsigned int length, const in_addr& yourAddress, unsigned int yourPort, unsigned int myPort); + bool setCCSData(const unsigned char* data, unsigned int length, const in_addr& yourAddress, unsigned int yourPort, unsigned int myPort); + + unsigned int getDExtraData(unsigned char* data, unsigned int length) const; + unsigned int getDPlusData(unsigned char* data, unsigned int length) const; + unsigned int getDCSData(unsigned char* data, unsigned int length) const; + unsigned int getCCSData(unsigned char* data, unsigned int length) const; + + wxString getRepeater() const; + wxString getReflector() const; + CD_TYPE getType() const; + + in_addr getYourAddress() const; + unsigned int getYourPort() const; + unsigned int getMyPort() const; + + void setLocator(const wxString& locator); + +private: + GATEWAY_TYPE m_gatewayType; + wxString m_repeater; + wxString m_reflector; + CD_TYPE m_type; + wxString m_locator; + in_addr m_yourAddress; + unsigned int m_yourPort; + unsigned int m_myPort; +}; + +#endif diff --git a/Common/DCSHandler.cpp b/Common/DCSHandler.cpp new file mode 100644 index 0000000..85888d2 --- /dev/null +++ b/Common/DCSHandler.cpp @@ -0,0 +1,884 @@ +/* + * Copyright (C) 2012-2015 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "RepeaterHandler.h" +#include "DStarDefines.h" +#include "DCSHandler.h" +#include "Utils.h" + +unsigned int CDCSHandler::m_maxReflectors = 0U; +CDCSHandler** CDCSHandler::m_reflectors = NULL; + +CDCSProtocolHandlerPool* CDCSHandler::m_pool = NULL; +CDCSProtocolHandler* CDCSHandler::m_incoming = NULL; + +bool CDCSHandler::m_stateChange = false; + +GATEWAY_TYPE CDCSHandler::m_gatewayType = GT_REPEATER; + +CHeaderLogger* CDCSHandler::m_headerLogger = NULL; + +CCallsignList* CDCSHandler::m_whiteList = NULL; +CCallsignList* CDCSHandler::m_blackList = NULL; + + +CDCSHandler::CDCSHandler(IReflectorCallback* handler, const wxString& reflector, const wxString& repeater, CDCSProtocolHandler* protoHandler, const in_addr& address, unsigned int port, DIRECTION direction) : +m_reflector(reflector.Clone()), +m_repeater(repeater.Clone()), +m_handler(protoHandler), +m_yourAddress(address), +m_yourPort(port), +m_myPort(0U), +m_direction(direction), +m_linkState(DCS_LINKING), +m_destination(handler), +m_time(), +m_pollTimer(1000U, 5U), +m_pollInactivityTimer(1000U, 60U), +m_tryTimer(1000U, 1U), +m_tryCount(0U), +m_dcsId(0x00U), +m_dcsSeq(0x00U), +m_seqNo(0x00U), +m_inactivityTimer(1000U, NETWORK_TIMEOUT), +m_yourCall(), +m_myCall1(), +m_myCall2(), +m_rptCall1(), +m_rptCall2() +{ + wxASSERT(protoHandler != NULL); + wxASSERT(handler != NULL); + wxASSERT(port > 0U); + + m_myPort = protoHandler->getPort(); + + m_pollInactivityTimer.start(); + + m_time = ::time(NULL); + + if (direction == DIR_INCOMING) { + m_pollTimer.start(); + m_stateChange = true; + m_linkState = DCS_LINKED; + } else { + m_linkState = DCS_LINKING; + m_tryTimer.start(); + } +} + +CDCSHandler::~CDCSHandler() +{ + if (m_direction == DIR_OUTGOING) + m_pool->release(m_handler); +} + +void CDCSHandler::initialise(unsigned int maxReflectors) +{ + wxASSERT(maxReflectors > 0U); + + m_maxReflectors = maxReflectors; + + m_reflectors = new CDCSHandler*[m_maxReflectors]; + for (unsigned int i = 0U; i < m_maxReflectors; i++) + m_reflectors[i] = NULL; +} + +void CDCSHandler::setDCSProtocolHandlerPool(CDCSProtocolHandlerPool* pool) +{ + wxASSERT(pool != NULL); + + m_pool = pool; +} + +void CDCSHandler::setDCSProtocolIncoming(CDCSProtocolHandler* handler) +{ + wxASSERT(handler != NULL); + + m_incoming = handler; +} + +void CDCSHandler::setHeaderLogger(CHeaderLogger* logger) +{ + m_headerLogger = logger; +} + +void CDCSHandler::setGatewayType(GATEWAY_TYPE type) +{ + m_gatewayType = type; +} + +void CDCSHandler::setWhiteList(CCallsignList* list) +{ + wxASSERT(list != NULL); + + m_whiteList = list; +} + +void CDCSHandler::setBlackList(CCallsignList* list) +{ + wxASSERT(list != NULL); + + m_blackList = list; +} + +wxString CDCSHandler::getIncoming(const wxString& callsign) +{ + wxString incoming; + + for (unsigned int i = 0U; i < m_maxReflectors; i++) { + CDCSHandler* reflector = m_reflectors[i]; + if (reflector != NULL && reflector->m_direction == DIR_INCOMING && reflector->m_repeater.IsSameAs(callsign)) { + incoming.Append(reflector->m_reflector); + incoming.Append(wxT(" ")); + } + } + + return incoming; +} + +void CDCSHandler::getInfo(IReflectorCallback* handler, CRemoteRepeaterData& data) +{ + wxASSERT(handler != NULL); + + for (unsigned int i = 0U; i < m_maxReflectors; i++) { + CDCSHandler* reflector = m_reflectors[i]; + if (reflector != NULL) { + if (reflector->m_destination == handler) { + if (reflector->m_direction == DIR_INCOMING && reflector->m_repeater.IsEmpty()) { + if (reflector->m_linkState != DCS_UNLINKING) + data.addLink(reflector->m_reflector, PROTO_DCS, reflector->m_linkState == DCS_LINKED, DIR_INCOMING, true); + } else { + if (reflector->m_linkState != DCS_UNLINKING) + data.addLink(reflector->m_reflector, PROTO_DCS, reflector->m_linkState == DCS_LINKED, reflector->m_direction, false); + } + } + } + } +} + +void CDCSHandler::process(CAMBEData& data) +{ + in_addr yourAddress = data.getYourAddress(); + unsigned int yourPort = data.getYourPort(); + unsigned int myPort = data.getMyPort(); + + for (unsigned int i = 0U; i < m_maxReflectors; i++) { + CDCSHandler* reflector = m_reflectors[i]; + if (reflector != NULL) { + if (reflector->m_yourAddress.s_addr == yourAddress.s_addr && + reflector->m_yourPort == yourPort && + reflector->m_myPort == myPort) { + reflector->processInt(data); + return; + } + } + } +} + +void CDCSHandler::process(CPollData& poll) +{ + wxString reflector = poll.getData1(); + wxString repeater = poll.getData2(); + in_addr yourAddress = poll.getYourAddress(); + unsigned int yourPort = poll.getYourPort(); + unsigned int myPort = poll.getMyPort(); + unsigned int length = poll.getLength(); + + // Check to see if we already have a link + for (unsigned int i = 0U; i < m_maxReflectors; i++) { + CDCSHandler* handler = m_reflectors[i]; + + if (handler != NULL) { + if (handler->m_reflector.IsSameAs(reflector) && + handler->m_repeater.IsSameAs(repeater) && + handler->m_yourAddress.s_addr == yourAddress.s_addr && + handler->m_yourPort == yourPort && + handler->m_myPort == myPort && + handler->m_direction == DIR_OUTGOING && + handler->m_linkState == DCS_LINKED && + length == 22U) { + handler->m_pollInactivityTimer.start(); + CPollData reply(handler->m_repeater, handler->m_reflector, handler->m_direction, handler->m_yourAddress, handler->m_yourPort); + handler->m_handler->writePoll(reply); + return; + } else if (handler->m_reflector.Left(LONG_CALLSIGN_LENGTH - 1U).IsSameAs(reflector.Left(LONG_CALLSIGN_LENGTH - 1U)) && + handler->m_yourAddress.s_addr == yourAddress.s_addr && + handler->m_yourPort == yourPort && + handler->m_myPort == myPort && + handler->m_direction == DIR_INCOMING && + handler->m_linkState == DCS_LINKED && + length == 17U) { + handler->m_pollInactivityTimer.start(); + return; + } + } + } + + wxLogMessage(wxT("Unknown incoming DCS poll from %s"), reflector.c_str()); +} + +void CDCSHandler::process(CConnectData& connect) +{ + CD_TYPE type = connect.getType(); + + if (type == CT_ACK || type == CT_NAK || type == CT_UNLINK) { + for (unsigned int i = 0U; i < m_maxReflectors; i++) { + if (m_reflectors[i] != NULL) { + bool res = m_reflectors[i]->processInt(connect, type); + if (res) { + delete m_reflectors[i]; + m_reflectors[i] = NULL; + } + } + } + + return; + } + + // else if type == CT_LINK1 or type == CT_LINK2 + in_addr yourAddress = connect.getYourAddress(); + unsigned int yourPort = connect.getYourPort(); + unsigned int myPort = connect.getMyPort(); + + wxString repeaterCallsign = connect.getRepeater(); + wxString reflectorCallsign = connect.getReflector(); + + // Check that it isn't a duplicate + for (unsigned int i = 0U; i < m_maxReflectors; i++) { + if (m_reflectors[i] != NULL) { + if (m_reflectors[i]->m_direction == DIR_INCOMING && + m_reflectors[i]->m_yourAddress.s_addr == yourAddress.s_addr && + m_reflectors[i]->m_yourPort == yourPort && + m_reflectors[i]->m_myPort == myPort && + m_reflectors[i]->m_repeater.IsSameAs(reflectorCallsign) && + m_reflectors[i]->m_reflector.IsSameAs(repeaterCallsign)) + return; + } + } + + // Check the validity of our repeater callsign + IReflectorCallback* handler = CRepeaterHandler::findDVRepeater(reflectorCallsign); + if (handler == NULL) { + wxLogMessage(wxT("DCS connect to unknown reflector %s from %s"), reflectorCallsign.c_str(), repeaterCallsign.c_str()); + CConnectData reply(repeaterCallsign, reflectorCallsign, CT_NAK, connect.getYourAddress(), connect.getYourPort()); + m_incoming->writeConnect(reply); + return; + } + + // A new connect packet indicates the need for a new entry + wxLogMessage(wxT("New incoming DCS link to %s from %s"), reflectorCallsign.c_str(), repeaterCallsign.c_str()); + + CDCSHandler* dcs = new CDCSHandler(handler, repeaterCallsign, reflectorCallsign, m_incoming, yourAddress, yourPort, DIR_INCOMING); + + bool found = false; + for (unsigned int i = 0U; i < m_maxReflectors; i++) { + if (m_reflectors[i] == NULL) { + m_reflectors[i] = dcs; + found = true; + break; + } + } + + if (found) { + CConnectData reply(repeaterCallsign, reflectorCallsign, CT_ACK, yourAddress, yourPort); + m_incoming->writeConnect(reply); + } else { + CConnectData reply(repeaterCallsign, reflectorCallsign, CT_NAK, yourAddress, yourPort); + m_incoming->writeConnect(reply); + + wxLogError(wxT("No space to add new DCS link, ignoring")); + delete dcs; + } +} + +void CDCSHandler::link(IReflectorCallback* handler, const wxString& repeater, const wxString &gateway, const in_addr& address) +{ + for (unsigned int i = 0U; i < m_maxReflectors; i++) { + if (m_reflectors[i] != NULL) { + if (m_reflectors[i]->m_direction == DIR_OUTGOING && m_reflectors[i]->m_destination == handler && m_reflectors[i]->m_linkState != DCS_UNLINKING) + return; + } + } + + CDCSProtocolHandler* protoHandler = m_pool->getHandler(); + if (protoHandler == NULL) + return; + + CDCSHandler* dcs = new CDCSHandler(handler, gateway, repeater, protoHandler, address, DCS_PORT, DIR_OUTGOING); + + bool found = false; + + for (unsigned int i = 0U; i < m_maxReflectors; i++) { + if (m_reflectors[i] == NULL) { + m_reflectors[i] = dcs; + found = true; + break; + } + } + + if (found) { + CConnectData reply(m_gatewayType, repeater, gateway, CT_LINK1, address, DCS_PORT); + protoHandler->writeConnect(reply); + } else { + wxLogError(wxT("No space to add new DCS link, ignoring")); + delete dcs; + } +} + +void CDCSHandler::unlink(IReflectorCallback* handler, const wxString& callsign, bool exclude) +{ + for (unsigned int i = 0U; i < m_maxReflectors; i++) { + CDCSHandler* reflector = m_reflectors[i]; + + if (reflector != NULL) { + bool found = false; + + if (exclude) { + if (reflector->m_direction == DIR_OUTGOING && reflector->m_destination == handler && !reflector->m_reflector.IsSameAs(callsign)) { + wxLogMessage(wxT("Removing outgoing DCS link %s, %s"), reflector->m_repeater.c_str(), reflector->m_reflector.c_str()); + + if (reflector->m_linkState == DCS_LINKING || reflector->m_linkState == DCS_LINKED) { + CConnectData connect(reflector->m_repeater, reflector->m_reflector, CT_UNLINK, reflector->m_yourAddress, reflector->m_yourPort); + reflector->m_handler->writeConnect(connect); + + reflector->m_linkState = DCS_UNLINKING; + reflector->m_tryTimer.start(1U); + reflector->m_tryCount = 0U; + } + + found = true; + } + } else { + if (reflector->m_destination == handler && reflector->m_reflector.IsSameAs(callsign)) { + wxLogMessage(wxT("Removing DCS link %s, %s"), reflector->m_repeater.c_str(), reflector->m_reflector.c_str()); + + if (reflector->m_linkState == DCS_LINKING || reflector->m_linkState == DCS_LINKED) { + CConnectData connect(reflector->m_repeater, reflector->m_reflector, CT_UNLINK, reflector->m_yourAddress, reflector->m_yourPort); + reflector->m_handler->writeConnect(connect); + + reflector->m_linkState = DCS_UNLINKING; + reflector->m_tryTimer.start(1U); + reflector->m_tryCount = 0U; + } + + found = true; + } + } + + // If an active link with incoming traffic, send an EOT to the repeater + if (found) { + if (reflector->m_dcsId != 0x00U) { + unsigned int seq = reflector->m_dcsSeq + 1U; + if (seq == 21U) + seq = 0U; + + CAMBEData data; + data.setData(END_PATTERN_BYTES, DV_FRAME_LENGTH_BYTES); + data.setSeq(seq); + data.setEnd(true); + data.setId(reflector->m_dcsId); + + reflector->m_destination->process(data, reflector->m_direction, AS_DCS); + } + + m_stateChange = true; + } + } + } +} + +void CDCSHandler::unlink() +{ + for (unsigned int i = 0U; i < m_maxReflectors; i++) { + CDCSHandler* reflector = m_reflectors[i]; + + if (reflector != NULL) { + if (!reflector->m_repeater.IsEmpty()) { + wxLogMessage(wxT("Unlinking from DCS reflector %s"), reflector->m_reflector.c_str()); + + CConnectData connect(reflector->m_repeater, reflector->m_reflector, CT_UNLINK, reflector->m_yourAddress, reflector->m_yourPort); + reflector->m_handler->writeConnect(connect); + + reflector->m_linkState = DCS_UNLINKING; + reflector->m_tryTimer.start(1U); + reflector->m_tryCount = 0U; + } + } + } +} + +void CDCSHandler::writeHeader(IReflectorCallback* handler, CHeaderData& header, DIRECTION direction) +{ + for (unsigned int i = 0U; i < m_maxReflectors; i++) { + if (m_reflectors[i] != NULL) + m_reflectors[i]->writeHeaderInt(handler, header, direction); + } +} + +void CDCSHandler::writeAMBE(IReflectorCallback* handler, CAMBEData& data, DIRECTION direction) +{ + for (unsigned int i = 0U; i < m_maxReflectors; i++) { + if (m_reflectors[i] != NULL) + m_reflectors[i]->writeAMBEInt(handler, data, direction); + } +} + +void CDCSHandler::gatewayUpdate(const wxString& reflector, const wxString& address) +{ + wxString gateway = reflector; + gateway.Truncate(LONG_CALLSIGN_LENGTH - 1U); + + for (unsigned int i = 0U; i < m_maxReflectors; i++) { + CDCSHandler* reflector = m_reflectors[i]; + if (reflector != NULL) { + if (reflector->m_reflector.Left(LONG_CALLSIGN_LENGTH - 1U).IsSameAs(gateway)) { + if (!address.IsEmpty()) { + // A new address, change the value + wxLogMessage(wxT("Changing IP address of DCS gateway or reflector %s to %s"), reflector->m_reflector.c_str(), address.c_str()); + reflector->m_yourAddress.s_addr = ::inet_addr(address.mb_str()); + } else { + wxLogMessage(wxT("IP address for DCS gateway or reflector %s has been removed"), reflector->m_reflector.c_str()); + + // No address, this probably shouldn't happen.... + if (reflector->m_direction == DIR_OUTGOING && reflector->m_destination != NULL) + reflector->m_destination->linkFailed(DP_DCS, reflector->m_reflector, false); + + m_stateChange = true; + + delete m_reflectors[i]; + m_reflectors[i] = NULL; + } + } + } + } +} + +void CDCSHandler::clock(unsigned int ms) +{ + for (unsigned int i = 0U; i < m_maxReflectors; i++) { + if (m_reflectors[i] != NULL) { + bool ret = m_reflectors[i]->clockInt(ms); + if (ret) { + delete m_reflectors[i]; + m_reflectors[i] = NULL; + } + } + } +} + +void CDCSHandler::finalise() +{ + for (unsigned int i = 0U; i < m_maxReflectors; i++) + delete m_reflectors[i]; + + delete[] m_reflectors; +} + +void CDCSHandler::processInt(CAMBEData& data) +{ + // Make a copy of the AMBE data so that any changes made here don't modify the original + CAMBEData temp(data); + + unsigned int id = temp.getId(); + CHeaderData& header = temp.getHeader(); + unsigned int seqNo = temp.getSeq(); + + wxString my = header.getMyCall1(); + wxString rpt2 = header.getRptCall2(); + + if (m_whiteList != NULL) { + bool res = m_whiteList->isInList(my); + if (!res) { + wxLogMessage(wxT("%s rejected from DCS as not found in the white list"), my.c_str()); + m_dcsId = 0x00U; + return; + } + } + + if (m_blackList != NULL) { + bool res = m_blackList->isInList(my); + if (res) { + wxLogMessage(wxT("%s rejected from DCS as found in the black list"), my.c_str()); + m_dcsId = 0x00U; + return; + } + } + + if (m_linkState != DCS_LINKED) + return; + + switch (m_direction) { + case DIR_OUTGOING: + if (!m_reflector.IsSameAs(rpt2)) + return; + + if (m_dcsId == 0x00U && seqNo != 0U) + return; + + if (m_dcsId == 0x00U) { // && seqNo == 0U) { + // Write to Header.log if it's enabled + if (m_headerLogger != NULL) + m_headerLogger->write(wxT("DCS"), header); + + m_dcsId = id; + m_dcsSeq = 0x00U; + m_inactivityTimer.start(); + + header.setCQCQCQ(); + header.setFlags(0x00U, 0x00U, 0x00U); + + m_destination->process(header, m_direction, AS_DCS); + } + + if (id == m_dcsId) { + m_pollInactivityTimer.start(); + m_inactivityTimer.start(); + + m_dcsSeq = seqNo; + + if (m_dcsSeq == 0U) { + // Send the header every 21 frames + header.setCQCQCQ(); + header.setFlags(0x00U, 0x00U, 0x00U); + + m_destination->process(header, m_direction, AS_DUP); + } + + m_destination->process(temp, m_direction, AS_DCS); + + if (temp.isEnd()) { + m_dcsId = 0x00U; + m_dcsSeq = 0x00U; + m_inactivityTimer.stop(); + } + } + break; + + case DIR_INCOMING: + if (!m_repeater.IsSameAs(rpt2)) + return; + + if (m_dcsId == 0x00U && seqNo != 0U) + return; + + if (m_dcsId == 0x00U) { // && seqNo == 0U) { + // Write to Header.log if it's enabled + if (m_headerLogger != NULL) + m_headerLogger->write(wxT("DCS"), header); + + m_dcsId = id; + m_dcsSeq = 0x00U; + m_inactivityTimer.start(); + + header.setCQCQCQ(); + header.setFlags(0x00U, 0x00U, 0x00U); + + m_destination->process(header, m_direction, AS_DCS); + } + + if (id == m_dcsId) { + m_pollInactivityTimer.start(); + m_inactivityTimer.start(); + + m_dcsSeq = seqNo; + + if (m_dcsSeq == 0U) { + // Send the header every 21 frames + header.setCQCQCQ(); + header.setFlags(0x00U, 0x00U, 0x00U); + + m_destination->process(header, m_direction, AS_DUP); + } + + m_destination->process(temp, m_direction, AS_DCS); + + if (temp.isEnd()) { + m_dcsId = 0x00U; + m_dcsSeq = 0x00U; + m_inactivityTimer.stop(); + } + } + break; + } +} + +bool CDCSHandler::processInt(CConnectData& connect, CD_TYPE type) +{ + in_addr yourAddress = connect.getYourAddress(); + unsigned int yourPort = connect.getYourPort(); + unsigned int myPort = connect.getMyPort(); + wxString repeater = connect.getRepeater(); + + if (m_yourAddress.s_addr != yourAddress.s_addr || m_yourPort != yourPort || m_myPort != myPort) + return false; + + switch (type) { + case CT_ACK: + if (!m_repeater.IsSameAs(repeater)) + return false; + + if (m_linkState == DCS_LINKING) { + wxLogMessage(wxT("DCS ACK message received from %s"), m_reflector.c_str()); + + if (m_direction == DIR_OUTGOING && m_destination != NULL) + m_destination->linkUp(DP_DCS, m_reflector); + + m_tryTimer.stop(); + m_stateChange = true; + m_linkState = DCS_LINKED; + } + + return false; + + case CT_NAK: + if (!m_repeater.IsSameAs(repeater)) + return false; + + if (m_linkState == DCS_LINKING) { + wxLogMessage(wxT("DCS NAK message received from %s"), m_reflector.c_str()); + + if (m_direction == DIR_OUTGOING && m_destination != NULL) + m_destination->linkRefused(DP_DCS, m_reflector); + + return true; + } + + if (m_linkState == DCS_UNLINKING) { + wxLogMessage(wxT("DCS NAK message received from %s"), m_reflector.c_str()); + + if (m_direction == DIR_OUTGOING && m_destination != NULL) + m_destination->linkFailed(DP_DCS, m_reflector, false); + + return true; + } + + return false; + + case CT_UNLINK: + if (!m_reflector.IsSameAs(repeater)) + return false; + + if (m_linkState == DCS_LINKED) { + wxLogMessage(wxT("DCS disconnect message received from %s"), m_reflector.c_str()); + + if (m_direction == DIR_OUTGOING && m_destination != NULL) + m_destination->linkFailed(DP_DCS, m_reflector, false); + + m_stateChange = true; + } + + return true; + + default: + return false; + } +} + +bool CDCSHandler::clockInt(unsigned int ms) +{ + m_pollInactivityTimer.clock(ms); + m_inactivityTimer.clock(ms); + m_pollTimer.clock(ms); + m_tryTimer.clock(ms); + + if (m_pollInactivityTimer.isRunning() && m_pollInactivityTimer.hasExpired()) { + m_pollInactivityTimer.start(); + + m_stateChange = true; + m_dcsId = 0x00U; + m_dcsSeq = 0x00U; + + switch (m_linkState) { + case DCS_LINKING: + wxLogMessage(wxT("DCS link to %s has failed to connect"), m_reflector.c_str()); + break; + case DCS_LINKED: + wxLogMessage(wxT("DCS link to %s has failed (poll inactivity)"), m_reflector.c_str()); + break; + case DCS_UNLINKING: + wxLogMessage(wxT("DCS link to %s has failed to disconnect cleanly"), m_reflector.c_str()); + break; + default: + break; + } + + if (m_direction == DIR_OUTGOING) { + bool reconnect = m_destination->linkFailed(DP_DCS, m_reflector, true); + if (reconnect) { + CConnectData reply(m_gatewayType, m_repeater, m_reflector, CT_LINK1, m_yourAddress, m_yourPort); + m_handler->writeConnect(reply); + m_linkState = DCS_LINKING; + m_tryTimer.start(1U); + m_tryCount = 0U; + return false; + } + } + + return true; + } + + if (m_inactivityTimer.isRunning() && m_inactivityTimer.hasExpired()) { + m_dcsId = 0x00U; + m_dcsSeq = 0x00U; + m_inactivityTimer.stop(); + } + + if (m_pollTimer.isRunning() && m_pollTimer.hasExpired()) { + m_pollTimer.start(); + + CPollData poll(m_repeater, m_reflector, m_direction, m_yourAddress, m_yourPort); + m_handler->writePoll(poll); + } + + if (m_linkState == DCS_LINKING) { + if (m_tryTimer.isRunning() && m_tryTimer.hasExpired()) { + CConnectData reply(m_gatewayType, m_repeater, m_reflector, CT_LINK1, m_yourAddress, m_yourPort); + m_handler->writeConnect(reply); + + unsigned int timeout = calcBackoff(); + m_tryTimer.start(timeout); + } + } + + if (m_linkState == DCS_UNLINKING) { + if (m_tryTimer.isRunning() && m_tryTimer.hasExpired()) { + CConnectData connect(m_repeater, m_reflector, CT_UNLINK, m_yourAddress, m_yourPort); + m_handler->writeConnect(connect); + + unsigned int timeout = calcBackoff(); + m_tryTimer.start(timeout); + } + } + + return false; +} + +void CDCSHandler::writeHeaderInt(IReflectorCallback* handler, CHeaderData& header, DIRECTION direction) +{ + if (m_linkState != DCS_LINKED) + return; + + // Is it link in the right direction + if (m_direction != direction) + return; + + if (m_destination != handler) + return; + + // Already in use? + if (m_dcsId != 0x00) + return; + + m_seqNo = 0U; + + m_myCall1 = header.getMyCall1(); + m_myCall2 = header.getMyCall2(); + m_yourCall = header.getYourCall(); + m_rptCall1 = header.getRptCall1(); + m_rptCall2 = header.getRptCall2(); +} + +void CDCSHandler::writeAMBEInt(IReflectorCallback* handler, CAMBEData& data, DIRECTION direction) +{ + if (m_linkState != DCS_LINKED) + return; + + // Is it link in the right direction + if (m_direction != direction) + return; + + if (m_destination != handler) + return; + + // Already in use? + if (m_dcsId != 0x00) + return; + + CHeaderData& header = data.getHeader(); + header.setMyCall1(m_myCall1); + header.setMyCall2(m_myCall2); + header.setRptCall1(m_rptCall1); + header.setRptCall2(m_rptCall2); + header.setCQCQCQ(); + + data.setRptSeq(m_seqNo++); + data.setDestination(m_yourAddress, m_yourPort); + m_handler->writeData(data); +} + +bool CDCSHandler::stateChange() +{ + bool stateChange = m_stateChange; + + m_stateChange = false; + + return stateChange; +} + +void CDCSHandler::writeStatus(wxFFile& file) +{ + for (unsigned int i = 0U; i < m_maxReflectors; i++) { + CDCSHandler* reflector = m_reflectors[i]; + if (reflector != NULL) { + struct tm* tm = ::gmtime(&reflector->m_time); + + switch (reflector->m_direction) { + case DIR_OUTGOING: + if (reflector->m_linkState == DCS_LINKED) { + wxString text; + text.Printf(wxT("%04d-%02d-%02d %02d:%02d:%02d: DCS link - Type: Repeater Rptr: %s Refl: %s Dir: Outgoing\n"), + tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, + reflector->m_repeater.c_str(), reflector->m_reflector.c_str()); + file.Write(text); + } + break; + + case DIR_INCOMING: + if (reflector->m_linkState == DCS_LINKED) { + wxString text; + text.Printf(wxT("%04d-%02d-%02d %02d:%02d:%02d: DCS link - Type: Repeater Rptr: %s Refl: %s Dir: Incoming\n"), + tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, + reflector->m_repeater.c_str(), reflector->m_reflector.c_str()); + file.Write(text); + } + break; + } + } + } +} + +unsigned int CDCSHandler::calcBackoff() +{ + if (m_tryCount >= 7U) { + m_tryCount++; + return 60U; + } + + unsigned int timeout = 1U; + + for (unsigned int i = 0U; i < m_tryCount; i++) + timeout *= 2U; + + m_tryCount++; + + if (timeout > 60U) + return 60U; + else + return timeout; +} diff --git a/Common/DCSHandler.h b/Common/DCSHandler.h new file mode 100644 index 0000000..d54334a --- /dev/null +++ b/Common/DCSHandler.h @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2012,2013,2015 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef DCSHandler_H +#define DCSHandler_H + +#include "DCSProtocolHandlerPool.h" +#include "ReflectorCallback.h" +#include "DStarDefines.h" +#include "HeaderLogger.h" +#include "CallsignList.h" +#include "ConnectData.h" +#include "AMBEData.h" +#include "PollData.h" +#include "Timer.h" +#include "Defs.h" + +#if defined(__WINDOWS__) +#include "Inaddr.h" +#else +#include +#endif + +#include +#include + +enum DCS_STATE { + DCS_LINKING, + DCS_LINKED, + DCS_UNLINKING +}; + +class CDCSHandler { +public: + static void initialise(unsigned int maxReflectors); + + static void setDCSProtocolHandlerPool(CDCSProtocolHandlerPool* pool); + static void setDCSProtocolIncoming(CDCSProtocolHandler* handler); + static void setHeaderLogger(CHeaderLogger* logger); + static void setGatewayType(GATEWAY_TYPE type); + + static void link(IReflectorCallback* handler, const wxString& repeater, const wxString& reflector, const in_addr& address); + static void unlink(IReflectorCallback* handler, const wxString& reflector = wxEmptyString, bool exclude = true); + static void unlink(); + + static void writeHeader(IReflectorCallback* handler, CHeaderData& header, DIRECTION direction); + static void writeAMBE(IReflectorCallback* handler, CAMBEData& data, DIRECTION direction); + + static void process(CAMBEData& header); + static void process(CPollData& data); + static void process(CConnectData& connect); + + static void gatewayUpdate(const wxString& reflector, const wxString& address); + static void clock(unsigned int ms); + + static bool stateChange(); + static void writeStatus(wxFFile& file); + + static void setWhiteList(CCallsignList* list); + static void setBlackList(CCallsignList* list); + + static void finalise(); + + static void getInfo(IReflectorCallback* handler, CRemoteRepeaterData& data); + + static wxString getIncoming(const wxString& callsign); + +protected: + CDCSHandler(IReflectorCallback* handler, const wxString& reflector, const wxString& repeater, CDCSProtocolHandler* protoHandler, const in_addr& address, unsigned int port, DIRECTION direction); + ~CDCSHandler(); + + void processInt(CAMBEData& data); + bool processInt(CConnectData& connect, CD_TYPE type); + + void writeHeaderInt(IReflectorCallback* handler, CHeaderData& header, DIRECTION direction); + void writeAMBEInt(IReflectorCallback* handler, CAMBEData& data, DIRECTION direction); + + bool clockInt(unsigned int ms); + +private: + static unsigned int m_maxReflectors; + static CDCSHandler** m_reflectors; + + static CDCSProtocolHandlerPool* m_pool; + static CDCSProtocolHandler* m_incoming; + + static bool m_stateChange; + + static GATEWAY_TYPE m_gatewayType; + + static CHeaderLogger* m_headerLogger; + + static CCallsignList* m_whiteList; + static CCallsignList* m_blackList; + + wxString m_reflector; + wxString m_repeater; + CDCSProtocolHandler* m_handler; + in_addr m_yourAddress; + unsigned int m_yourPort; + unsigned int m_myPort; + DIRECTION m_direction; + DCS_STATE m_linkState; + IReflectorCallback* m_destination; + time_t m_time; + CTimer m_pollTimer; + CTimer m_pollInactivityTimer; + CTimer m_tryTimer; + unsigned int m_tryCount; + unsigned int m_dcsId; + unsigned int m_dcsSeq; + unsigned int m_seqNo; + CTimer m_inactivityTimer; + + // Header data + wxString m_yourCall; + wxString m_myCall1; + wxString m_myCall2; + wxString m_rptCall1; + wxString m_rptCall2; + + unsigned int calcBackoff(); +}; + +#endif diff --git a/Common/DCSProtocolHandler.cpp b/Common/DCSProtocolHandler.cpp new file mode 100644 index 0000000..74eaf45 --- /dev/null +++ b/Common/DCSProtocolHandler.cpp @@ -0,0 +1,196 @@ +/* + * Copyright (C) 2012,2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "DCSProtocolHandler.h" + +#include "DStarDefines.h" +#include "Utils.h" + +// #define DUMP_TX + +const unsigned int BUFFER_LENGTH = 2000U; + +CDCSProtocolHandler::CDCSProtocolHandler(unsigned int port, const wxString& addr) : +m_socket(addr, port), +m_type(DC_NONE), +m_buffer(NULL), +m_length(0U), +m_yourAddress(), +m_yourPort(0U), +m_myPort(port) +{ + m_buffer = new unsigned char[BUFFER_LENGTH]; +} + +CDCSProtocolHandler::~CDCSProtocolHandler() +{ + delete[] m_buffer; +} + +bool CDCSProtocolHandler::open() +{ + return m_socket.open(); +} + +unsigned int CDCSProtocolHandler::getPort() const +{ + return m_myPort; +} + +bool CDCSProtocolHandler::writeData(const CAMBEData& data) +{ + unsigned char buffer[100U]; + unsigned int length = data.getDCSData(buffer, 100U); + +#if defined(DUMP_TX) + CUtils::dump(wxT("Sending Data"), buffer, length); +#endif + + return m_socket.write(buffer, length, data.getYourAddress(), data.getYourPort()); +} + +bool CDCSProtocolHandler::writePoll(const CPollData& poll) +{ + unsigned char buffer[25U]; + unsigned int length = poll.getDCSData(buffer, 25U); + +#if defined(DUMP_TX) + CUtils::dump(wxT("Sending Poll"), buffer, length); +#endif + + return m_socket.write(buffer, length, poll.getYourAddress(), poll.getYourPort()); +} + +bool CDCSProtocolHandler::writeConnect(const CConnectData& connect) +{ + unsigned char buffer[520U]; + unsigned int length = connect.getDCSData(buffer, 520U); + +#if defined(DUMP_TX) + CUtils::dump(wxT("Sending Connect"), buffer, length); +#endif + + return m_socket.write(buffer, length, connect.getYourAddress(), connect.getYourPort()); +} + +DCS_TYPE CDCSProtocolHandler::read() +{ + bool res = true; + + // Loop until we have no more data from the socket or we have data for the higher layers + while (res) + res = readPackets(); + + return m_type; +} + +bool CDCSProtocolHandler::readPackets() +{ + m_type = DC_NONE; + + // No more data? + int length = m_socket.read(m_buffer, BUFFER_LENGTH, m_yourAddress, m_yourPort); + if (length <= 0) + return false; + + m_length = length; + + if (m_buffer[0] == '0' && m_buffer[1] == '0' && m_buffer[2] == '0' && m_buffer[3] == '1') { + if (m_length == 100U) { + m_type = DC_DATA; + return false; + } + } else if (m_buffer[0] == 'E' && m_buffer[1] == 'E' && m_buffer[2] == 'E' && m_buffer[3] == 'E') { + // CUtils::dump(wxT("Status data"), m_buffer, m_length); + return true; + } else { + switch (m_length) { + case 17U: + case 22U: + m_type = DC_POLL; + return false; + case 14U: + case 19U: + case 519U: + m_type = DC_CONNECT; + return false; + case 35U: + // CUtils::dump(wxT("Status data"), m_buffer, m_length); + return true; + default: + break; + } + } + + // An unknown type + // CUtils::dump(wxT("Unknown packet type from DCS"), m_buffer, m_length); + return true; +} + +CAMBEData* CDCSProtocolHandler::readData() +{ + if (m_type != DC_DATA) + return NULL; + + CAMBEData* data = new CAMBEData; + + bool res = data->setDCSData(m_buffer, m_length, m_yourAddress, m_yourPort, m_myPort); + if (!res) { + delete data; + return NULL; + } + + return data; +} + +CPollData* CDCSProtocolHandler::readPoll() +{ + if (m_type != DC_POLL) + return NULL; + + CPollData* poll = new CPollData; + + bool res = poll->setDCSData(m_buffer, m_length, m_yourAddress, m_yourPort, m_myPort); + if (!res) { + delete poll; + return NULL; + } + + return poll; +} + +CConnectData* CDCSProtocolHandler::readConnect() +{ + if (m_type != DC_CONNECT) + return NULL; + + CConnectData* connect = new CConnectData; + + bool res = connect->setDCSData(m_buffer, m_length, m_yourAddress, m_yourPort, m_myPort); + if (!res) { + delete connect; + return NULL; + } + + return connect; +} + +void CDCSProtocolHandler::close() +{ + m_socket.close(); +} diff --git a/Common/DCSProtocolHandler.h b/Common/DCSProtocolHandler.h new file mode 100644 index 0000000..c39c92f --- /dev/null +++ b/Common/DCSProtocolHandler.h @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2012,2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef DCSProtocolHandler_H +#define DCSProtocolHandler_H + +#include "UDPReaderWriter.h" +#include "DStarDefines.h" +#include "ConnectData.h" +#include "AMBEData.h" +#include "PollData.h" + +#if defined(__WINDOWS__) +#include "Inaddr.h" +#else +#include +#endif + +#include + +enum DCS_TYPE { + DC_NONE, + DC_DATA, + DC_POLL, + DC_CONNECT +}; + +class CDCSProtocolHandler { +public: + CDCSProtocolHandler(unsigned int port, const wxString& addr = wxEmptyString); + ~CDCSProtocolHandler(); + + bool open(); + + unsigned int getPort() const; + + bool writeData(const CAMBEData& data); + bool writeConnect(const CConnectData& connect); + bool writePoll(const CPollData& poll); + + DCS_TYPE read(); + CAMBEData* readData(); + CPollData* readPoll(); + CConnectData* readConnect(); + + void close(); + +private: + CUDPReaderWriter m_socket; + DCS_TYPE m_type; + unsigned char* m_buffer; + unsigned int m_length; + in_addr m_yourAddress; + unsigned int m_yourPort; + unsigned int m_myPort; + + bool readPackets(); +}; + +#endif diff --git a/Common/DCSProtocolHandlerPool.cpp b/Common/DCSProtocolHandlerPool.cpp new file mode 100644 index 0000000..25960d2 --- /dev/null +++ b/Common/DCSProtocolHandlerPool.cpp @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2012,2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "DCSProtocolHandlerPool.h" + +CDCSProtocolHandlerPool::CDCSProtocolHandlerPool(unsigned int n, unsigned int port, const wxString& addr) : +m_pool(NULL), +m_n(n), +m_index(0U) +{ + wxASSERT(port > 0U); + wxASSERT(n > 0U); + + m_pool = new CDCSProtocolHandlerEntry[n]; + + for (unsigned int i = 0U; i < n; i++) { + m_pool[i].m_handler = new CDCSProtocolHandler(port + i, addr); + m_pool[i].m_port = port + i; + m_pool[i].m_inUse = false; + } + + wxLogMessage(wxT("Allocated UDP ports %u-%u to DCS"), port, port + n - 1U); +} + +CDCSProtocolHandlerPool::~CDCSProtocolHandlerPool() +{ + for (unsigned int i = 0U; i < m_n; i++) + delete m_pool[i].m_handler; + + delete[] m_pool; +} + +bool CDCSProtocolHandlerPool::open() +{ + for (unsigned int i = 0U; i < m_n; i++) { + bool ret = m_pool[i].m_handler->open(); + if (!ret) + return false; + } + + return true; +} + +CDCSProtocolHandler* CDCSProtocolHandlerPool::getHandler(unsigned int port) +{ + if (port == 0U) { + for (unsigned int i = 0U; i < m_n; i++) { + if (!m_pool[i].m_inUse) { + m_pool[i].m_inUse = true; + return m_pool[i].m_handler; + } + } + } else { + for (unsigned int i = 0U; i < m_n; i++) { + if (m_pool[i].m_port == port) { + m_pool[i].m_inUse = true; + return m_pool[i].m_handler; + } + } + } + + wxLogError(wxT("Cannot find a free DCS port in the pool")); + + return NULL; +} + +void CDCSProtocolHandlerPool::release(CDCSProtocolHandler* handler) +{ + wxASSERT(handler != NULL); + + for (unsigned int i = 0U; i < m_n; i++) { + if (m_pool[i].m_handler == handler && m_pool[i].m_inUse) { + m_pool[i].m_inUse = false; + return; + } + } + + wxLogError(wxT("Trying to release an unused DCS port")); +} + +DCS_TYPE CDCSProtocolHandlerPool::read() +{ + while (m_index < m_n) { + if (m_pool[m_index].m_inUse) { + DCS_TYPE type = m_pool[m_index].m_handler->read(); + if (type != DC_NONE) + return type; + } + + m_index++; + } + + m_index = 0U; + + return DC_NONE; +} + +CAMBEData* CDCSProtocolHandlerPool::readData() +{ + return m_pool[m_index].m_handler->readData(); +} + +CPollData* CDCSProtocolHandlerPool::readPoll() +{ + return m_pool[m_index].m_handler->readPoll(); +} + +CConnectData* CDCSProtocolHandlerPool::readConnect() +{ + return m_pool[m_index].m_handler->readConnect(); +} + +void CDCSProtocolHandlerPool::close() +{ + for (unsigned int i = 0U; i < m_n; i++) + m_pool[i].m_handler->close(); +} diff --git a/Common/DCSProtocolHandlerPool.h b/Common/DCSProtocolHandlerPool.h new file mode 100644 index 0000000..6502605 --- /dev/null +++ b/Common/DCSProtocolHandlerPool.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2012,2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef DCSProtocolHandlerPool_H +#define DCSProtocolHandlerPool_H + +#include + +#include "DCSProtocolHandler.h" + +class CDCSProtocolHandlerEntry { +public: + CDCSProtocolHandler* m_handler; + unsigned int m_port; + bool m_inUse; +}; + +class CDCSProtocolHandlerPool { +public: + CDCSProtocolHandlerPool(unsigned int n, unsigned int port, const wxString& addr = wxEmptyString); + ~CDCSProtocolHandlerPool(); + + bool open(); + + CDCSProtocolHandler* getHandler(unsigned int port = 0U); + void release(CDCSProtocolHandler* handler); + + DCS_TYPE read(); + CAMBEData* readData(); + CPollData* readPoll(); + CConnectData* readConnect(); + + void close(); + +private: + CDCSProtocolHandlerEntry* m_pool; + unsigned int m_n; + unsigned int m_index; +}; + +#endif diff --git a/Common/DDData.cpp b/Common/DDData.cpp new file mode 100644 index 0000000..884702a --- /dev/null +++ b/Common/DDData.cpp @@ -0,0 +1,313 @@ +/* + * Copyright (C) 2011,2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "DStarDefines.h" +#include "DDData.h" +#include "Utils.h" + +unsigned int ETHERNET_ADDRESS_LENGTH = 6U; + +unsigned int BUFFER_LENGTH = 2500U; + +CDDData::CDDData() : +m_header(), +m_length(0U), +m_frame(NULL) +{ + m_frame = new unsigned char[BUFFER_LENGTH]; +} + +CDDData::CDDData(const CDDData& data) : +m_header(data.m_header), +m_length(data.m_length), +m_frame(NULL) +{ + m_frame = new unsigned char[BUFFER_LENGTH]; + ::memcpy(m_frame, data.m_frame, data.m_length); +} + +CDDData::~CDDData() +{ + delete[] m_frame; +} + +bool CDDData::setIcomRepeaterData(const unsigned char *data, unsigned int length, const in_addr& yourAddress, unsigned int yourPort) +{ + wxASSERT(data != NULL); + wxASSERT(length >= 29U); + + bool ret = m_header.setIcomRepeaterData(data, length, true, yourAddress, yourPort); + if (!ret) + return false; + + m_length = data[59] * 256U + data[58]; + + if (m_length > BUFFER_LENGTH) + m_length = BUFFER_LENGTH; + + ::memcpy(m_frame, data + 60U, m_length); + + return true; +} + +bool CDDData::setHBRepeaterData(const unsigned char *data, unsigned int length, const in_addr&, unsigned int) +{ + wxASSERT(data != NULL); + wxASSERT(length >= 60U); + + m_header.setData(data, length, false); + + m_length = length - 44U; + + if (m_length > BUFFER_LENGTH) + m_length = BUFFER_LENGTH; + + ::memcpy(m_frame, data + 44U, m_length); + + return true; +} + +unsigned int CDDData::getIcomRepeaterData(unsigned char *data, unsigned int length) +{ + wxASSERT(data != NULL); + wxASSERT(length >= 32U); + + // This section is used when it's normal data (i.e. not an ack) for an Icom controller + data[0] = 'D'; + data[1] = 'S'; + data[2] = 'T'; + data[3] = 'R'; + + data[4] = m_header.getRptSeq() / 256U; // Packet sequence number + data[5] = m_header.getRptSeq() % 256U; + + data[6] = 0x73; // Not a response + data[7] = 0x11; // DD Data type + + unsigned int dataLength = m_length + 50U; + + data[8] = dataLength / 256U; // Length + data[9] = dataLength % 256U; + + data[10] = 0x40; // DD Data + + data[11] = 0xFF; + data[12] = 0xFF; + data[13] = 0xFF; + + data[14] = 0x00; // Dummy ID + data[15] = 0x00; + + data[16] = 0xC0; // DD Data + + m_header.getData(data + 17U, RADIO_HEADER_LENGTH_BYTES, true); + + // Another length field + data[58] = m_length % 256U; + data[59] = m_length / 256U; + + // Now copy the payload + ::memcpy(data + 60U, m_frame, m_length); + + return 60U + m_length; +} + +unsigned int CDDData::getHBRepeaterData(unsigned char *data, unsigned int length) +{ + wxASSERT(data != NULL); + wxASSERT(length >= 1600U); + + data[0] = 'D'; + data[1] = 'S'; + data[2] = 'R'; + data[3] = 'P'; + + data[4] = 0x24U; + + m_header.getData(data + 5U, RADIO_HEADER_LENGTH_BYTES, false); + + // Now copy the payload + ::memcpy(data + 44U, m_frame, m_length); + + return 44U + m_length; +} + +unsigned int CDDData::getRptSeq() const +{ + return m_header.getRptSeq(); +} + +void CDDData::setRptSeq(unsigned int seqNo) +{ + m_header.setRptSeq(seqNo); +} + +unsigned char CDDData::getBand1() const +{ + return m_header.getBand1(); +} + +unsigned char CDDData::getBand2() const +{ + return m_header.getBand2(); +} + +unsigned char CDDData::getBand3() const +{ + return m_header.getBand3(); +} + +void CDDData::setBand1(unsigned char band) +{ + m_header.setBand1(band); +} + +void CDDData::setBand2(unsigned char band) +{ + m_header.setBand2(band); +} + +void CDDData::setBand3(unsigned char band) +{ + m_header.setBand3(band); +} + +unsigned char CDDData::getFlag1() const +{ + return m_header.getFlag1(); +} + +unsigned char CDDData::getFlag2() const +{ + return m_header.getFlag2(); +} + +unsigned char CDDData::getFlag3() const +{ + return m_header.getFlag3(); +} + +void CDDData::setFlags(unsigned char flag1, unsigned char flag2, unsigned char flag3) +{ + m_header.setFlags(flag1, flag2, flag3); +} + +wxString CDDData::getMyCall1() const +{ + return m_header.getMyCall1(); +} + +wxString CDDData::getMyCall2() const +{ + return m_header.getMyCall2(); +} + +wxString CDDData::getYourCall() const +{ + return m_header.getYourCall(); +} + +wxString CDDData::getRptCall1() const +{ + return m_header.getRptCall1(); +} + +wxString CDDData::getRptCall2() const +{ + return m_header.getRptCall2(); +} + +void CDDData::setMyCall1(const wxString& callsign) +{ + m_header.setMyCall1(callsign); +} + +void CDDData::setMyCall2(const wxString& callsign) +{ + m_header.setMyCall2(callsign); +} + +void CDDData::setYourCall(const wxString& callsign) +{ + m_header.setYourCall(callsign); +} + +void CDDData::setRptCall1(const wxString& callsign) +{ + m_header.setRptCall1(callsign); +} + +void CDDData::setRptCall2(const wxString& callsign) +{ + m_header.setRptCall2(callsign); +} + +void CDDData::setRepeaters(const wxString& rpt1, const wxString& rpt2) +{ + m_header.setRepeaters(rpt1, rpt2); +} + +void CDDData::setDestination(const in_addr& address, unsigned int port) +{ + m_header.setDestination(address, port); +} + +in_addr CDDData::getYourAddress() const +{ + return m_header.getYourAddress(); +} + +unsigned int CDDData::getYourPort() const +{ + return m_header.getYourPort(); +} + +void CDDData::setEthernetFrame(const unsigned char *frame, unsigned int length) +{ + wxASSERT(frame != NULL); + wxASSERT(length > 0U); + + m_length = length; + if (m_length > BUFFER_LENGTH) + m_length = BUFFER_LENGTH; + + ::memcpy(m_frame, frame, m_length); +} + +unsigned int CDDData::getEthernetFrame(unsigned char *frame, unsigned int length) const +{ + wxASSERT(frame != NULL); + wxASSERT(length > 0U); + + if (length > m_length) + length = m_length; + + ::memcpy(frame, m_frame, length); + + return length; +} + +unsigned char* CDDData::getSourceAddress() const +{ + return m_frame + ETHERNET_ADDRESS_LENGTH; +} + +unsigned char* CDDData::getDestinationAddress() const +{ + return m_frame + 0U; +} diff --git a/Common/DDData.h b/Common/DDData.h new file mode 100644 index 0000000..ad89902 --- /dev/null +++ b/Common/DDData.h @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2011,2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef DDData_H +#define DDData_H + +#include "HeaderData.h" + +#include + +#if defined(__WINDOWS__) +#include "Inaddr.h" +#else +#include +#endif + +class CDDData { +public: + CDDData(); + CDDData(const CDDData& data); + ~CDDData(); + + bool setIcomRepeaterData(const unsigned char* data, unsigned int length, const in_addr& yourAddress, unsigned int yourPort); + bool setHBRepeaterData(const unsigned char* data, unsigned int length, const in_addr& yourAddress, unsigned int yourPort); + + unsigned int getIcomRepeaterData(unsigned char* data, unsigned int length); + unsigned int getHBRepeaterData(unsigned char* data, unsigned int length); + + unsigned char getBand1() const; + unsigned char getBand2() const; + unsigned char getBand3() const; + void setBand1(unsigned char band); + void setBand2(unsigned char band); + void setBand3(unsigned char band); + + unsigned char getFlag1() const; + unsigned char getFlag2() const; + unsigned char getFlag3() const; + void setFlags(unsigned char flag1, unsigned char flag2, unsigned char flag3); + + wxString getMyCall1() const; + wxString getMyCall2() const; + wxString getYourCall() const; + wxString getRptCall1() const; + wxString getRptCall2() const; + + void setMyCall1(const wxString& callsign); + void setMyCall2(const wxString& callsign); + void setYourCall(const wxString& callsign); + void setRptCall1(const wxString& callsign); + void setRptCall2(const wxString& callsign); + + unsigned int getRptSeq() const; + void setRptSeq(unsigned int seqNo); + + void setEthernetFrame(const unsigned char* frame, unsigned int length); + unsigned int getEthernetFrame(unsigned char* frame, unsigned int length) const; + + unsigned char* getSourceAddress() const; + unsigned char* getDestinationAddress() const; + + void setRepeaters(const wxString& rpt1, const wxString& rpt2); + void setDestination(const in_addr& address, unsigned int port); + + in_addr getYourAddress() const; + unsigned int getYourPort() const; + +private: + CHeaderData m_header; + unsigned int m_length; + unsigned char* m_frame; +}; + +#endif diff --git a/Common/DDHandler.cpp b/Common/DDHandler.cpp new file mode 100644 index 0000000..cab79e6 --- /dev/null +++ b/Common/DDHandler.cpp @@ -0,0 +1,394 @@ +/* + * Copyright (C) 2011,2012,2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "RepeaterHandler.h" +#include "DDHandler.h" +#include "Defs.h" + +#include + +#if !defined(WIN32) +// XXX Check these +#include +#include +#include +#include +#include +#include +#endif + +const unsigned int ETHERNET_ADDRESS_LENGTH = 6U; +const unsigned int ETHERNET_MTU = 1500U; +const unsigned int BUFFER_LENGTH = 2000U; + +const unsigned int MIN_HEARD_TIME_SECS = 120U; + +const int MINIMUM_DD_FRAME_LENGTH = 60; + +const unsigned char ETHERNET_BROADCAST_ADDRESS[] = {0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU}; +// Multicast address '01:00:5E:00:00:01' - IP: '224.0.0.1' (send to all) +const unsigned char TOALL_MULTICAST_ADDRESS[] = {0x01U, 0x00U, 0x5EU, 0x00U, 0x00U, 0x01U}; +// Multicast address '01:00:5E:00:00:23' - IP: '224.0.0.35' (DX-Cluster) +const unsigned char DX_MULTICAST_ADDRESS[] = {0x01U, 0x00U, 0x5EU, 0x00U, 0x00U, 0x23U}; + +CIRCDDB* CDDHandler::m_irc = NULL; +CHeaderLogger* CDDHandler::m_headerLogger = NULL; +int CDDHandler::m_fd = -1; +unsigned int CDDHandler::m_maxRoutes = 0U; +CEthernet** CDDHandler::m_list = NULL; +unsigned char* CDDHandler::m_buffer = NULL; +bool CDDHandler::m_logEnabled = false; +wxString CDDHandler::m_logDir = wxEmptyString; +wxString CDDHandler::m_name = wxEmptyString; +CTimer CDDHandler::m_timer = CTimer(1000U, MIN_HEARD_TIME_SECS); + +CEthernet::CEthernet(const unsigned char* address, const wxString& callsign) : +m_address(NULL), +m_callsign(callsign) +{ + wxASSERT(address != NULL); + wxASSERT(!callsign.IsEmpty()); + + m_address = new unsigned char[ETHERNET_ADDRESS_LENGTH]; + ::memcpy(m_address, address, ETHERNET_ADDRESS_LENGTH); +} + +CEthernet::~CEthernet() +{ + delete[] m_address; +} + +unsigned char* CEthernet::getAddress() const +{ + return m_address; +} + +wxString CEthernet::getCallsign() const +{ + return m_callsign; +} + +void CDDHandler::initialise(unsigned int maxRoutes, const wxString& name) +{ + wxASSERT(maxRoutes > 0U); + + m_maxRoutes = maxRoutes; + m_name = name; + + m_buffer = new unsigned char[BUFFER_LENGTH]; + + m_list = new CEthernet*[maxRoutes]; + for (unsigned int i = 0U; i < maxRoutes; i++) + m_list[i] = NULL; + + // Add a dummy entry for broadcasts + m_list[0] = new CEthernet(ETHERNET_BROADCAST_ADDRESS, wxT(" ")); + // Add a dummy entry for "to all" multicast + m_list[1] = new CEthernet(TOALL_MULTICAST_ADDRESS, wxT("CQCQCQ ")); + // Add a dummy entry for "DX-Cluster" multicast + m_list[2] = new CEthernet(DX_MULTICAST_ADDRESS, wxT("CQCQCQ ")); + +#if !defined(WIN32) + m_fd = ::open("/dev/net/tun", O_RDWR); + if (m_fd < 0) { + wxLogError(wxT("Cannot open /dev/net/tun")); + return; + } + + struct ifreq ifr1; + ::memset(&ifr1, 0x00, sizeof(struct ifreq)); + + ifr1.ifr_flags = IFF_TAP | IFF_NO_PI; + ::strcpy(ifr1.ifr_name, "tap%d"); + + if (::ioctl(m_fd, TUNSETIFF, (void *)&ifr1) < 0) { + wxLogError(wxT("TUNSETIFF ioctl failed, closing the tap device")); + ::close(m_fd); + m_fd = -1; + return; + } + + wxString device = wxString(ifr1.ifr_name, wxConvLocal); + wxLogMessage(wxT("DD mode Tap interface created on %s"), device.c_str()); + + int fd = ::socket(AF_INET, SOCK_DGRAM, 0); + if (fd < 0) { + wxLogError(wxT("Unable to open the config socket, closing the tap device")); + ::close(m_fd); + m_fd = -1; + return; + } + + struct ifreq ifr2; + ::memset(&ifr2, 0x00, sizeof(struct ifreq)); + ::strcpy(ifr2.ifr_name, ifr1.ifr_name); + + ifr2.ifr_flags = IFF_UP | IFF_BROADCAST | IFF_MULTICAST; + if (::ioctl(fd, SIOCSIFFLAGS, (void *)&ifr2) < 0) { + wxLogError(wxT("SIOCSIFFLAGS ioctl failed, closing the tap device")); + ::close(m_fd); + m_fd = -1; + return; + } + + ::close(fd); +#endif +} + +void CDDHandler::setLogging(bool enabled, const wxString& dir) +{ + m_logDir = dir; + m_logEnabled = enabled; +} + +void CDDHandler::setHeaderLogger(CHeaderLogger* logger) +{ + m_headerLogger = logger; +} + +void CDDHandler::setIRC(CIRCDDB* irc) +{ + wxASSERT(irc != NULL); + + m_irc = irc; +} + +void CDDHandler::process(CDDData& data) +{ + // If we're not initialised, return immediately + if (m_maxRoutes == 0U) + return; + + unsigned char flag1 = data.getFlag1(); + unsigned char flag2 = data.getFlag2(); + unsigned char flag3 = data.getFlag3(); + wxString myCall1 = data.getMyCall1(); + wxString myCall2 = data.getMyCall2(); + wxString yourCall = data.getYourCall(); + wxString rptCall1 = data.getRptCall1(); + wxString rptCall2 = data.getRptCall2(); + + if (!m_timer.isRunning() || m_timer.hasExpired()) { + // Write to Header.log if it's enabled + if (m_headerLogger != NULL) + m_headerLogger->write(wxT("Repeater"), data); + + if (m_irc != NULL) { + m_irc->sendHeardWithTXMsg(myCall1, myCall2, yourCall, rptCall1, rptCall2, flag1, flag2, flag3, wxEmptyString, wxT("Digital Data ")); + m_irc->sendHeardWithTXStats(myCall1, myCall2, yourCall, rptCall1, rptCall2, flag1, flag2, flag3, 1, 0, -1); + } + + m_timer.start(); + } + + // Can we continue? + if (m_fd < 0) + return; + + unsigned char* address = data.getSourceAddress(); + + bool found = false; + for (unsigned int i = 0U; i < m_maxRoutes; i++) { + if (m_list[i] != NULL) { + unsigned char* addr = m_list[i]->getAddress(); + + if (::memcmp(addr, address, ETHERNET_ADDRESS_LENGTH) == 0) { + found = true; + break; + } + } + } + + if (!found) { + wxLogMessage(wxT("Adding DD user %s with ethernet address %02X:%02X:%02X:%02X:%02X:%02X"), myCall1.c_str(), + address[0], address[1], address[2], address[3], address[4], address[5]); + + CEthernet* ethernet = new CEthernet(address, myCall1); + + found = false; + for (unsigned int i = 0U; i < m_maxRoutes; i++) { + if (m_list[i] == NULL) { + m_list[i] = ethernet; + found = true; + if (m_logEnabled) + writeStatus(*ethernet); + break; + } + } + + if (!found) { + wxLogError(wxT("No space to add new DD ethernet address")); + delete ethernet; + return; + } + } + +#if !defined(WIN32) + unsigned int length = data.getEthernetFrame(m_buffer, BUFFER_LENGTH); + + ssize_t len = ::write(m_fd, (char*)m_buffer, length); + if (len != ssize_t(length)) + wxLogError(wxT("Error returned from write()")); +#endif +} + +CDDData* CDDHandler::read() +{ + // If we're not initialised, return immediately + if (m_maxRoutes == 0U) + return NULL; + +#if defined(WIN32) + return NULL; +#else + // Check that the read() won't block + fd_set readFds; + FD_ZERO(&readFds); +#if defined(__WINDOWS__) + FD_SET((unsigned int)m_fd, &readFds); +#else + FD_SET(m_fd, &readFds); +#endif + + // Return immediately + timeval tv; + tv.tv_sec = 0L; + tv.tv_usec = 0L; + + int ret = ::select(m_fd + 1, &readFds, NULL, NULL, &tv); + if (ret < 0) { + wxLogError(wxT("Error returned from select()")); + return NULL; + } + +#if defined(__WINDOWS__) + if (!FD_ISSET((unsigned int)m_fd, &readFds)) + return NULL; +#else + if (!FD_ISSET(m_fd, &readFds)) + return NULL; +#endif + + // Ensure that the minimum length is padded with 0x00s + ::memset(m_buffer, 0x00U, MINIMUM_DD_FRAME_LENGTH); + + ssize_t len = ::read(m_fd, (char*)m_buffer, BUFFER_LENGTH); + if (len <= 0) { + wxLogError(wxT("Error returned from read()")); + return NULL; + } + + // There seems to be a minimum size with DD mode, so pad with zeroes if it's not reached + if (len < MINIMUM_DD_FRAME_LENGTH) + len = MINIMUM_DD_FRAME_LENGTH; + + // Point to the destination ethernet address + unsigned char* address = m_buffer + 0U; + + // Do destination address to callsign lookup + CEthernet* ethernet = NULL; + for (unsigned int i = 0U; i < m_maxRoutes; i++) { + if (m_list[i] != NULL) { + unsigned char* addr = m_list[i]->getAddress(); + + if (::memcmp(addr, address, ETHERNET_ADDRESS_LENGTH) == 0) { + ethernet = m_list[i]; + break; + } + } + } + + if (ethernet == NULL) { + wxLogWarning(wxT("Cannot find the ethernet address of %02X:%02X:%02X:%02X:%02X:%02X in the ethernet list"), address[0], address[1], address[2], address[3], address[4], address[5]); + return NULL; + } + + CRepeaterHandler* handler = CRepeaterHandler::findDDRepeater(); + if (handler == NULL) { + wxLogWarning(wxT("Incoming DD data to unknown repeater")); + return NULL; + } + + // wxLogMessage(wxT("Mapping ethernet address %02X:%02X:%02X:%02X:%02X:%02X to user %s"), + // address[0], address[1], address[2], address[3], address[4], address[5], + // ethernet->getCallsign().c_str()); + + CDDData* data = new CDDData; + data->setEthernetFrame(m_buffer, len); + data->setYourCall(ethernet->getCallsign()); + + handler->process(*data); + + return data; +#endif +} + +void CDDHandler::clock(unsigned int ms) +{ + m_timer.clock(ms); +} + +void CDDHandler::finalise() +{ +#if !defined(WIN32) + if (m_fd >= 0) { + ::close(m_fd); + m_fd = -1; + } +#endif + + delete[] m_buffer; + + for (unsigned int i = 0U; i < m_maxRoutes; i++) + delete m_list[i]; + delete[] m_list; +} + +void CDDHandler::writeStatus(const CEthernet& ethernet) +{ + wxString fullName = DDMODE_BASE_NAME; + + if (!m_name.IsEmpty()) { + fullName.Append(wxT("_")); + fullName.Append(m_name); + } + + wxFileName fileName(m_logDir, fullName, wxT("log")); + + wxFFile file; + bool ret = file.Open(fileName.GetFullPath(), wxT("at")); + if (!ret) { + wxLogError(wxT("Unable to open %s for writing"), fileName.GetFullPath().c_str()); + return; + } + + wxString callsign = ethernet.getCallsign(); + unsigned char* address = ethernet.getAddress(); + + time_t timeNow = ::time(NULL); + struct tm* tm = ::gmtime(&timeNow); + + wxString text; + text.Printf(wxT("%04d-%02d-%02d %02d:%02d:%02d: %02X:%02X:%02X:%02X:%02X:%02X %s\n"), + tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, + address[0], address[1], address[2], address[3], address[4], address[5], callsign.c_str()); + + file.Write(text); + + file.Close(); +} diff --git a/Common/DDHandler.h b/Common/DDHandler.h new file mode 100644 index 0000000..91d097d --- /dev/null +++ b/Common/DDHandler.h @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2011,2012 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef DDHandler_H +#define DDHandler_H + +#include "HeaderLogger.h" +#include "DDData.h" +#include "IRCDDB.h" +#include "Timer.h" + +#include + +class CEthernet { +public: + CEthernet(const unsigned char* address, const wxString& callsign); + ~CEthernet(); + + unsigned char* getAddress() const; + wxString getCallsign() const; + +private: + unsigned char* m_address; + wxString m_callsign; +}; + +class CDDHandler { +public: + static void initialise(unsigned int maxRoutes, const wxString& name); + + static void setLogging(bool enabled, const wxString& dir); + static void setHeaderLogger(CHeaderLogger* logger); + static void setIRC(CIRCDDB* irc); + + static void process(CDDData& data); + + static CDDData* read(); + + static void clock(unsigned int ms); + + static void finalise(); + +private: + static CIRCDDB* m_irc; + static CHeaderLogger* m_headerLogger; + static int m_fd; + static unsigned int m_maxRoutes; + static CEthernet** m_list; + static unsigned char* m_buffer; + static bool m_logEnabled; + static wxString m_logDir; + static wxString m_name; + static CTimer m_timer; + + static void writeStatus(const CEthernet& ethernet); +}; + +#endif diff --git a/Common/DExtraHandler.cpp b/Common/DExtraHandler.cpp new file mode 100644 index 0000000..2ec830e --- /dev/null +++ b/Common/DExtraHandler.cpp @@ -0,0 +1,1004 @@ +/* + * Copyright (C) 2010-2015 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "RepeaterHandler.h" +#include "DExtraHandler.h" +#include "DStarDefines.h" +#include "Utils.h" + +unsigned int CDExtraHandler::m_maxReflectors = 0U; +unsigned int CDExtraHandler::m_maxDongles = 0U; +CDExtraHandler** CDExtraHandler::m_reflectors = NULL; + +wxString CDExtraHandler::m_callsign; +CDExtraProtocolHandlerPool* CDExtraHandler::m_pool = NULL; +CDExtraProtocolHandler* CDExtraHandler::m_incoming = NULL; + +bool CDExtraHandler::m_stateChange = false; + +CHeaderLogger* CDExtraHandler::m_headerLogger = NULL; + +CCallsignList* CDExtraHandler::m_whiteList = NULL; +CCallsignList* CDExtraHandler::m_blackList = NULL; + + +CDExtraHandler::CDExtraHandler(IReflectorCallback* handler, const wxString& reflector, const wxString& repeater, CDExtraProtocolHandler* protoHandler, const in_addr& address, unsigned int port, DIRECTION direction) : +m_reflector(reflector.Clone()), +m_repeater(repeater.Clone()), +m_handler(protoHandler), +m_yourAddress(address), +m_yourPort(port), +m_direction(direction), +m_linkState(DEXTRA_LINKING), +m_destination(handler), +m_time(), +m_pollTimer(1000U, 10U), +m_pollInactivityTimer(1000U, 60U), +m_tryTimer(1000U, 1U), +m_tryCount(0U), +m_dExtraId(0x00U), +m_dExtraSeq(0x00U), +m_inactivityTimer(1000U, NETWORK_TIMEOUT), +m_header(NULL) +{ + wxASSERT(protoHandler != NULL); + wxASSERT(handler != NULL); + wxASSERT(port > 0U); + + m_pollInactivityTimer.start(); + + m_time = ::time(NULL); + + if (direction == DIR_INCOMING) { + m_pollTimer.start(); + m_stateChange = true; + m_linkState = DEXTRA_LINKED; + } else { + m_linkState = DEXTRA_LINKING; + m_tryTimer.start(); + } +} + +CDExtraHandler::CDExtraHandler(CDExtraProtocolHandler* protoHandler, const wxString& reflector, const in_addr& address, unsigned int port, DIRECTION direction) : +m_reflector(reflector.Clone()), +m_repeater(), +m_handler(protoHandler), +m_yourAddress(address), +m_yourPort(port), +m_direction(direction), +m_linkState(DEXTRA_LINKING), +m_destination(NULL), +m_time(), +m_pollTimer(1000U, 10U), +m_pollInactivityTimer(1000U, 60U), +m_tryTimer(1000U, 1U), +m_tryCount(0U), +m_dExtraId(0x00U), +m_dExtraSeq(0x00U), +m_inactivityTimer(1000U, NETWORK_TIMEOUT), +m_header(NULL) +{ + wxASSERT(protoHandler != NULL); + wxASSERT(port > 0U); + + m_pollInactivityTimer.start(); + + m_time = ::time(NULL); + + if (direction == DIR_INCOMING) { + m_pollTimer.start(); + m_stateChange = true; + m_linkState = DEXTRA_LINKED; + } else { + m_linkState = DEXTRA_LINKING; + m_tryTimer.start(); + } +} + +CDExtraHandler::~CDExtraHandler() +{ + if (m_direction == DIR_OUTGOING) + m_pool->release(m_handler); + + delete m_header; +} + +void CDExtraHandler::initialise(unsigned int maxReflectors) +{ + wxASSERT(maxReflectors > 0U); + + m_maxReflectors = maxReflectors; + + m_reflectors = new CDExtraHandler*[m_maxReflectors]; + for (unsigned int i = 0U; i < m_maxReflectors; i++) + m_reflectors[i] = NULL; +} + +void CDExtraHandler::setCallsign(const wxString& callsign) +{ + m_callsign = callsign.Clone();//clone makes deep copy of string, this adds thread safety to our code ! + m_callsign.resize(LONG_CALLSIGN_LENGTH, ' '); + m_callsign.SetChar(LONG_CALLSIGN_LENGTH - 1U, wxT(' ')); +} + +void CDExtraHandler::setDExtraProtocolIncoming(CDExtraProtocolHandler* incoming) +{ + wxASSERT(incoming != NULL); + + m_incoming = incoming; +} + +void CDExtraHandler::setDExtraProtocolHandlerPool(CDExtraProtocolHandlerPool* pool) +{ + wxASSERT(pool != NULL); + + m_pool = pool; +} + +void CDExtraHandler::setHeaderLogger(CHeaderLogger* logger) +{ + m_headerLogger = logger; +} + +void CDExtraHandler::setMaxDongles(unsigned int maxDongles) +{ + m_maxDongles = maxDongles; +} + +void CDExtraHandler::setWhiteList(CCallsignList* list) +{ + wxASSERT(list != NULL); + + m_whiteList = list; +} + +void CDExtraHandler::setBlackList(CCallsignList* list) +{ + wxASSERT(list != NULL); + + m_blackList = list; +} + +wxString CDExtraHandler::getIncoming(const wxString& callsign) +{ + wxString incoming; + + for (unsigned int i = 0U; i < m_maxReflectors; i++) { + CDExtraHandler* reflector = m_reflectors[i]; + if (reflector != NULL && reflector->m_direction == DIR_INCOMING && reflector->m_repeater.IsSameAs(callsign)) { + incoming.Append(reflector->m_reflector); + incoming.Append(wxT(" ")); + } + } + + return incoming; +} + +void CDExtraHandler::getInfo(IReflectorCallback* handler, CRemoteRepeaterData& data) +{ + wxASSERT(handler != NULL); + + for (unsigned int i = 0U; i < m_maxReflectors; i++) { + CDExtraHandler* reflector = m_reflectors[i]; + if (reflector != NULL) { + if (reflector->m_destination == handler) { + if (reflector->m_direction == DIR_INCOMING && reflector->m_repeater.IsEmpty()) { + if (reflector->m_linkState != DEXTRA_UNLINKING) + data.addLink(reflector->m_reflector, PROTO_DEXTRA, reflector->m_linkState == DEXTRA_LINKED, DIR_INCOMING, true); + } else { + if (reflector->m_linkState != DEXTRA_UNLINKING) + data.addLink(reflector->m_reflector, PROTO_DEXTRA, reflector->m_linkState == DEXTRA_LINKED, reflector->m_direction, false); + } + } + } + } +} + +wxString CDExtraHandler::getDongles() +{ + wxString dongles; + + for (unsigned int i = 0U; i < m_maxReflectors; i++) { + CDExtraHandler* reflector = m_reflectors[i]; + if (reflector != NULL && reflector->m_direction == DIR_INCOMING && reflector->m_repeater.IsEmpty()) { + dongles.Append(wxT("X:")); + dongles.Append(reflector->m_reflector); + dongles.Append(wxT(" ")); + } + } + + return dongles; +} + +void CDExtraHandler::process(CHeaderData& header) +{ + in_addr yourAddress = header.getYourAddress(); + unsigned int yourPort = header.getYourPort(); + + for (unsigned int i = 0U; i < m_maxReflectors; i++) { + CDExtraHandler* reflector = m_reflectors[i]; + if (reflector != NULL) { + if (reflector->m_yourAddress.s_addr == yourAddress.s_addr && + reflector->m_yourPort == yourPort) + reflector->processInt(header); + } + } +} + +void CDExtraHandler::process(CAMBEData& data) +{ + in_addr yourAddress = data.getYourAddress(); + unsigned int yourPort = data.getYourPort(); + + for (unsigned int i = 0U; i < m_maxReflectors; i++) { + CDExtraHandler* reflector = m_reflectors[i]; + if (reflector != NULL) { + if (reflector->m_yourAddress.s_addr == yourAddress.s_addr && + reflector->m_yourPort == yourPort) + reflector->processInt(data); + } + } +} + +void CDExtraHandler::process(const CPollData& poll) +{ + bool found = false; + + wxString reflector = poll.getData1(); + in_addr yourAddress = poll.getYourAddress(); + unsigned int yourPort = poll.getYourPort(); + + // Check to see if we already have a link + for (unsigned int i = 0U; i < m_maxReflectors; i++) { + if (m_reflectors[i] != NULL) { + if (m_reflectors[i]->m_reflector.Left(LONG_CALLSIGN_LENGTH - 1U).IsSameAs(reflector.Left(LONG_CALLSIGN_LENGTH - 1U)) && + m_reflectors[i]->m_yourAddress.s_addr == yourAddress.s_addr && + m_reflectors[i]->m_yourPort == yourPort && + m_reflectors[i]->m_linkState == DEXTRA_LINKED) { + m_reflectors[i]->m_pollInactivityTimer.start(); + found = true; + } + } + } + + if (found) + return; + + // A repeater poll arriving here is an error + if (!poll.isDongle()) + return; + + // Check to see if we are allowed to accept it + unsigned int count = 0U; + for (unsigned int i = 0U; i < m_maxReflectors; i++) { + if (m_reflectors[i] != NULL && + m_reflectors[i]->m_direction == DIR_INCOMING && + m_reflectors[i]->m_repeater.IsEmpty()) + count++; + } + + if (count >= m_maxDongles) + return; + + // An unmatched poll indicates the need for a new entry + wxLogMessage(wxT("New incoming DExtra Dongle from %s"), reflector.c_str()); + + CDExtraHandler* handler = new CDExtraHandler(m_incoming, reflector, yourAddress, yourPort, DIR_INCOMING); + + found = false; + + for (unsigned int i = 0U; i < m_maxReflectors; i++) { + if (m_reflectors[i] == NULL) { + m_reflectors[i] = handler; + found = true; + break; + } + } + + if (found) { + // Return the poll + CPollData poll(m_callsign, yourAddress, yourPort); + m_incoming->writePoll(poll); + } else { + wxLogError(wxT("No space to add new DExtra Dongle, ignoring")); + delete handler; + } +} + +void CDExtraHandler::process(CConnectData& connect) +{ + CD_TYPE type = connect.getType(); + + if (type == CT_ACK || type == CT_NAK || type == CT_UNLINK) { + for (unsigned int i = 0U; i < m_maxReflectors; i++) { + if (m_reflectors[i] != NULL) { + bool res = m_reflectors[i]->processInt(connect, type); + if (res) { + delete m_reflectors[i]; + m_reflectors[i] = NULL; + } + } + } + + return; + } + + // else if type == CT_LINK1 or type == CT_LINK2 + in_addr yourAddress = connect.getYourAddress(); + unsigned int yourPort = connect.getYourPort(); + + wxString repeaterCallsign = connect.getRepeater(); + + wxChar band = connect.getReflector().GetChar(LONG_CALLSIGN_LENGTH - 1U); + + wxString reflectorCallsign = m_callsign; + reflectorCallsign.SetChar(LONG_CALLSIGN_LENGTH - 1U, band); + + // Check that it isn't a duplicate + for (unsigned int i = 0U; i < m_maxReflectors; i++) { + if (m_reflectors[i] != NULL) { + if (m_reflectors[i]->m_direction == DIR_INCOMING && + m_reflectors[i]->m_yourAddress.s_addr == yourAddress.s_addr && + m_reflectors[i]->m_yourPort == yourPort && + m_reflectors[i]->m_repeater.IsSameAs(reflectorCallsign) && + m_reflectors[i]->m_reflector.IsSameAs(repeaterCallsign)) + return; + } + } + + // Check the validity of our repeater callsign + IReflectorCallback* handler = CRepeaterHandler::findDVRepeater(reflectorCallsign); + if (handler == NULL) { + wxLogMessage(wxT("DExtra connect to unknown reflector %s from %s"), reflectorCallsign.c_str(), repeaterCallsign.c_str()); + CConnectData reply(repeaterCallsign, reflectorCallsign, CT_NAK, yourAddress, yourPort); + m_incoming->writeConnect(reply); + return; + } + + // A new connect packet indicates the need for a new entry + wxLogMessage(wxT("New incoming DExtra link to %s from %s"), reflectorCallsign.c_str(), repeaterCallsign.c_str()); + + CDExtraHandler* dextra = new CDExtraHandler(handler, repeaterCallsign, reflectorCallsign, m_incoming, yourAddress, yourPort, DIR_INCOMING); + + bool found = false; + for (unsigned int i = 0U; i < m_maxReflectors; i++) { + if (m_reflectors[i] == NULL) { + m_reflectors[i] = dextra; + found = true; + break; + } + } + + if (found) { + CConnectData reply(repeaterCallsign, reflectorCallsign, CT_ACK, yourAddress, yourPort); + m_incoming->writeConnect(reply); + + wxString callsign = repeaterCallsign; + callsign.SetChar(LONG_CALLSIGN_LENGTH - 1U, wxT(' ')); + CPollData poll(callsign, yourAddress, yourPort); + m_incoming->writePoll(poll); + } else { + CConnectData reply(repeaterCallsign, reflectorCallsign, CT_NAK, yourAddress, yourPort); + m_incoming->writeConnect(reply); + + wxLogError(wxT("No space to add new DExtra repeater, ignoring")); + delete dextra; + } +} + +void CDExtraHandler::link(IReflectorCallback* handler, const wxString& repeater, const wxString &gateway, const in_addr& address) +{ + CDExtraProtocolHandler* protoHandler = m_pool->getHandler(); + if (protoHandler == NULL) + return; + + CDExtraHandler* dextra = new CDExtraHandler(handler, gateway, repeater, protoHandler, address, DEXTRA_PORT, DIR_OUTGOING); + + bool found = false; + + for (unsigned int i = 0U; i < m_maxReflectors; i++) { + if (m_reflectors[i] == NULL) { + m_reflectors[i] = dextra; + found = true; + break; + } + } + + if (found) { + CConnectData reply(repeater, gateway, CT_LINK1, address, DEXTRA_PORT); + protoHandler->writeConnect(reply); + } else { + wxLogError(wxT("No space to add new DExtra link, ignoring")); + delete dextra; + } +} + +void CDExtraHandler::unlink(IReflectorCallback* handler, const wxString& callsign, bool exclude) +{ + for (unsigned int i = 0U; i < m_maxReflectors; i++) { + CDExtraHandler* reflector = m_reflectors[i]; + + if (reflector != NULL) { + bool found = false; + + if (exclude) { + if (reflector->m_direction == DIR_OUTGOING && reflector->m_destination == handler && !reflector->m_reflector.IsSameAs(callsign)) { + wxLogMessage(wxT("Removing outgoing DExtra link %s, %s"), reflector->m_repeater.c_str(), reflector->m_reflector.c_str()); + + if (reflector->m_linkState == DEXTRA_LINKING || reflector->m_linkState == DEXTRA_LINKED) { + CConnectData connect(reflector->m_repeater, reflector->m_yourAddress, reflector->m_yourPort); + reflector->m_handler->writeConnect(connect); + + reflector->m_linkState = DEXTRA_UNLINKING; + + reflector->m_destination->linkFailed(DP_DEXTRA, reflector->m_reflector, false); + } + + found = true; + } + } else { + if (reflector->m_destination == handler && reflector->m_reflector.IsSameAs(callsign)) { + wxLogMessage(wxT("Removing DExtra link %s, %s"), reflector->m_repeater.c_str(), reflector->m_reflector.c_str()); + + if (reflector->m_linkState == DEXTRA_LINKING || reflector->m_linkState == DEXTRA_LINKED) { + CConnectData connect(reflector->m_repeater, reflector->m_yourAddress, reflector->m_yourPort); + reflector->m_handler->writeConnect(connect); + + reflector->m_linkState = DEXTRA_UNLINKING; + + reflector->m_destination->linkFailed(DP_DEXTRA, reflector->m_reflector, false); + } + + found = true; + } + } + + // If an active link with incoming traffic, send an EOT to the repeater + if (found) { + if (reflector->m_dExtraId != 0x00U) { + unsigned int seq = reflector->m_dExtraSeq + 1U; + if (seq == 21U) + seq = 0U; + + CAMBEData data; + data.setData(END_PATTERN_BYTES, DV_FRAME_LENGTH_BYTES); + data.setSeq(seq); + data.setEnd(true); + data.setId(reflector->m_dExtraId); + + reflector->m_destination->process(data, reflector->m_direction, AS_DEXTRA); + } + + m_stateChange = true; + + delete m_reflectors[i]; + m_reflectors[i] = NULL; + } + } + } +} + +void CDExtraHandler::unlink() +{ + for (unsigned int i = 0U; i < m_maxReflectors; i++) { + CDExtraHandler* reflector = m_reflectors[i]; + + if (reflector != NULL) { + if (!reflector->m_repeater.IsEmpty()) { + wxLogMessage(wxT("Unlinking from DExtra reflector %s"), reflector->m_reflector.c_str()); + + CConnectData connect(reflector->m_repeater, reflector->m_yourAddress, reflector->m_yourPort); + reflector->m_handler->writeConnect(connect); + + reflector->m_linkState = DEXTRA_UNLINKING; + } + } + } +} + +void CDExtraHandler::writeHeader(IReflectorCallback* handler, CHeaderData& header, DIRECTION direction) +{ + for (unsigned int i = 0U; i < m_maxReflectors; i++) { + if (m_reflectors[i] != NULL) + m_reflectors[i]->writeHeaderInt(handler, header, direction); + } +} + +void CDExtraHandler::writeAMBE(IReflectorCallback* handler, CAMBEData& data, DIRECTION direction) +{ + for (unsigned int i = 0U; i < m_maxReflectors; i++) { + if (m_reflectors[i] != NULL) + m_reflectors[i]->writeAMBEInt(handler, data, direction); + } +} + +void CDExtraHandler::gatewayUpdate(const wxString& reflector, const wxString& address) +{ + wxString gateway = reflector; + gateway.Truncate(LONG_CALLSIGN_LENGTH - 1U); + + for (unsigned int i = 0U; i < m_maxReflectors; i++) { + CDExtraHandler* reflector = m_reflectors[i]; + if (reflector != NULL) { + if (reflector->m_reflector.Left(LONG_CALLSIGN_LENGTH - 1U).IsSameAs(gateway)) { + if (!address.IsEmpty()) { + // A new address, change the value + wxLogMessage(wxT("Changing IP address of DExtra gateway or reflector %s to %s"), reflector->m_reflector.c_str(), address.c_str()); + reflector->m_yourAddress.s_addr = ::inet_addr(address.mb_str()); + } else { + wxLogMessage(wxT("IP address for DExtra gateway or reflector %s has been removed"), reflector->m_reflector.c_str()); + + // No address, this probably shouldn't happen.... + if (reflector->m_direction == DIR_OUTGOING && reflector->m_destination != NULL) + reflector->m_destination->linkFailed(DP_DEXTRA, reflector->m_reflector, false); + + m_stateChange = true; + + delete m_reflectors[i]; + m_reflectors[i] = NULL; + } + } + } + } +} + +void CDExtraHandler::clock(unsigned int ms) +{ + for (unsigned int i = 0U; i < m_maxReflectors; i++) { + if (m_reflectors[i] != NULL) { + bool ret = m_reflectors[i]->clockInt(ms); + if (ret) { + delete m_reflectors[i]; + m_reflectors[i] = NULL; + } + } + } +} + +void CDExtraHandler::finalise() +{ + for (unsigned int i = 0U; i < m_maxReflectors; i++) + delete m_reflectors[i]; + + delete[] m_reflectors; +} + +void CDExtraHandler::processInt(CHeaderData& header) +{ + wxString my = header.getMyCall1(); + wxString rpt1 = header.getRptCall1(); + wxString rpt2 = header.getRptCall2(); + unsigned int id = header.getId(); + + if (m_whiteList != NULL) { + bool res = m_whiteList->isInList(my); + if (!res) { + wxLogMessage(wxT("%s rejected from DExtra as not found in the white list"), my.c_str()); + m_dExtraId = 0x00U; + return; + } + } + + if (m_blackList != NULL) { + bool res = m_blackList->isInList(my); + if (res) { + wxLogMessage(wxT("%s rejected from DExtra as found in the black list"), my.c_str()); + m_dExtraId = 0x00U; + return; + } + } + + if (m_linkState != DEXTRA_LINKED) + return; + + switch (m_direction) { + case DIR_OUTGOING: { + // Always a repeater connection + if (!m_reflector.IsSameAs(rpt2) && !m_reflector.IsSameAs(rpt1)) + return; + + // If we're already processing, ignore the new header + if (m_dExtraId != 0x00U) + return; + + // Write to Header.log if it's enabled + if (m_headerLogger != NULL) + m_headerLogger->write(wxT("DExtra"), header); + + m_dExtraId = id; + m_dExtraSeq = 0x00U; + m_inactivityTimer.start(); + + delete m_header; + + m_header = new CHeaderData(header); + m_header->setCQCQCQ(); + m_header->setFlags(0x00U, 0x00U, 0x00U); + + m_destination->process(*m_header, m_direction, AS_DEXTRA); + } + break; + + case DIR_INCOMING: + if (!m_repeater.IsEmpty()) { + // A repeater connection + if (!m_repeater.IsSameAs(rpt2) && !m_repeater.IsSameAs(rpt1)) + return; + + // If we're already processing, ignore the new header + if (m_dExtraId != 0x00U) + return; + + // Write to Header.log if it's enabled + if (m_headerLogger != NULL) + m_headerLogger->write(wxT("DExtra"), header); + + m_dExtraId = id; + m_dExtraSeq = 0x00U; + m_inactivityTimer.start(); + + delete m_header; + + m_header = new CHeaderData(header); + m_header->setCQCQCQ(); + m_header->setFlags(0x00U, 0x00U, 0x00U); + + m_destination->process(*m_header, m_direction, AS_DEXTRA); + } else { + // A Dongle connection + // Check the destination callsign + m_destination = CRepeaterHandler::findDVRepeater(rpt2); + if (m_destination == NULL) { + m_destination = CRepeaterHandler::findDVRepeater(rpt1); + if (m_destination == NULL) + return; + } + + // If we're already processing, ignore the new header + if (m_dExtraId != 0x00U) + return; + + // Write to Header.log if it's enabled + if (m_headerLogger != NULL) + m_headerLogger->write(wxT("DExtra"), header); + + m_dExtraId = id; + m_dExtraSeq = 0x00U; + m_inactivityTimer.start(); + + delete m_header; + + m_header = new CHeaderData(header); + m_header->setCQCQCQ(); + m_header->setFlags(0x00U, 0x00U, 0x00U); + + m_destination->process(*m_header, m_direction, AS_DEXTRA); + } + break; + } +} + +void CDExtraHandler::processInt(CAMBEData& data) +{ + if (m_linkState != DEXTRA_LINKED) + return; + + if (m_dExtraId != data.getId()) + return; + + m_pollInactivityTimer.start(); + m_inactivityTimer.start(); + + m_dExtraSeq = data.getSeq(); + + // Send the header every 21 frames, if we have it + if (m_dExtraSeq == 0U && m_header != NULL) + m_destination->process(*m_header, m_direction, AS_DUP); + + // Copy the data to ensure it remains unchanged + CAMBEData temp(data); + + m_destination->process(temp, m_direction, AS_DEXTRA); + + if (temp.isEnd()) { + delete m_header; + m_header = NULL; + + m_dExtraId = 0x00U; + m_dExtraSeq = 0x00U; + + m_inactivityTimer.stop(); + } +} + +bool CDExtraHandler::processInt(CConnectData& connect, CD_TYPE type) +{ + in_addr yourAddress = connect.getYourAddress(); + unsigned int yourPort = connect.getYourPort(); + wxString repeater = connect.getRepeater(); + + if (m_yourAddress.s_addr != yourAddress.s_addr || m_yourPort != yourPort) + return false; + + switch (type) { + case CT_ACK: + if (!m_repeater.IsSameAs(repeater)) + return false; + + if (m_linkState == DEXTRA_LINKING) { + wxLogMessage(wxT("DExtra ACK message received from %s"), m_reflector.c_str()); + + if (m_direction == DIR_OUTGOING && m_destination != NULL) + m_destination->linkUp(DP_DEXTRA, m_reflector); + + m_tryTimer.stop(); + m_pollTimer.start(); + m_stateChange = true; + m_linkState = DEXTRA_LINKED; + } + + return false; + + case CT_NAK: + if (!m_repeater.IsSameAs(repeater)) + return false; + + if (m_linkState == DEXTRA_LINKING) { + wxLogMessage(wxT("DExtra NAK message received from %s"), m_reflector.c_str()); + + if (m_direction == DIR_OUTGOING && m_destination != NULL) + m_destination->linkRefused(DP_DEXTRA, m_reflector); + + return true; + } + + return false; + + case CT_UNLINK: + if (!m_reflector.IsSameAs(repeater)) + return false; + + if (m_linkState == DEXTRA_LINKED) { + wxLogMessage(wxT("DExtra disconnect message received from %s"), m_reflector.c_str()); + + if (m_direction == DIR_OUTGOING && m_destination != NULL) + m_destination->linkFailed(DP_DEXTRA, m_reflector, false); + + m_stateChange = true; + } + + return true; + + default: + return false; + } +} + +bool CDExtraHandler::clockInt(unsigned int ms) +{ + m_tryTimer.clock(ms); + m_pollTimer.clock(ms); + m_inactivityTimer.clock(ms); + m_pollInactivityTimer.clock(ms); + + if (m_pollInactivityTimer.isRunning() && m_pollInactivityTimer.hasExpired()) { + m_pollInactivityTimer.start(); + + delete m_header; + m_header = NULL; + + m_stateChange = true; + m_dExtraId = 0x00U; + m_dExtraSeq = 0x00U; + + switch (m_linkState) { + case DEXTRA_LINKING: + wxLogMessage(wxT("DExtra link to %s has failed to connect"), m_reflector.c_str()); + break; + case DEXTRA_LINKED: + wxLogMessage(wxT("DExtra link to %s has failed (poll inactivity)"), m_reflector.c_str()); + break; + case DEXTRA_UNLINKING: + wxLogMessage(wxT("DExtra link to %s has failed to disconnect cleanly"), m_reflector.c_str()); + break; + default: + break; + } + + if (m_direction == DIR_OUTGOING) { + bool reconnect = m_destination->linkFailed(DP_DEXTRA, m_reflector, true); + if (reconnect) { + CConnectData reply(m_repeater, m_reflector, CT_LINK1, m_yourAddress, m_yourPort); + m_handler->writeConnect(reply); + m_linkState = DEXTRA_LINKING; + m_tryTimer.start(1U); + m_tryCount = 0U; + return false; + } + } + + return true; + } + + if (m_pollTimer.isRunning() && m_pollTimer.hasExpired()) { + if (m_linkState == DEXTRA_LINKED) { + if (!m_repeater.IsEmpty()) { + wxString callsign = m_repeater; + callsign.SetChar(LONG_CALLSIGN_LENGTH - 1U, wxT(' ')); + CPollData poll(callsign, m_yourAddress, m_yourPort); + m_handler->writePoll(poll); + } else { + CPollData poll(m_callsign, m_yourAddress, m_yourPort); + m_handler->writePoll(poll); + } + } + + m_pollTimer.start(); + } + + if (m_inactivityTimer.isRunning() && m_inactivityTimer.hasExpired()) { + delete m_header; + m_header = NULL; + + m_dExtraId = 0x00U; + m_dExtraSeq = 0x00U; + + m_inactivityTimer.stop(); + } + + if (m_linkState == DEXTRA_LINKING) { + if (m_tryTimer.isRunning() && m_tryTimer.hasExpired()) { + CConnectData reply(m_repeater, m_reflector, CT_LINK1, m_yourAddress, m_yourPort); + m_handler->writeConnect(reply); + + unsigned int timeout = calcBackoff(); + m_tryTimer.start(timeout); + } + } + + return false; +} + +void CDExtraHandler::writeHeaderInt(IReflectorCallback* handler, CHeaderData& header, DIRECTION direction) +{ + if (m_linkState != DEXTRA_LINKED) + return; + + // Is it link in the right direction + if (m_direction != direction) + return; + + // Already in use? + if (m_dExtraId != 0x00) + return; + + switch (m_direction) { + case DIR_OUTGOING: + if (m_destination == handler) { + header.setDestination(m_yourAddress, m_yourPort); + m_handler->writeHeader(header); + } + break; + + case DIR_INCOMING: + if (m_repeater.IsEmpty() || m_destination == handler) { + header.setDestination(m_yourAddress, m_yourPort); + m_handler->writeHeader(header); + } + break; + } +} + +void CDExtraHandler::writeAMBEInt(IReflectorCallback* handler, CAMBEData& data, DIRECTION direction) +{ + if (m_linkState != DEXTRA_LINKED) + return; + + // Is it link in the right direction + if (m_direction != direction) + return; + + // Already in use? + if (m_dExtraId != 0x00) + return; + + switch (m_direction) { + case DIR_OUTGOING: + if (m_destination == handler) { + data.setDestination(m_yourAddress, m_yourPort); + m_handler->writeAMBE(data); + } + break; + + case DIR_INCOMING: + if (m_repeater.IsEmpty() || m_destination == handler) { + data.setDestination(m_yourAddress, m_yourPort); + m_handler->writeAMBE(data); + } + break; + } +} + +bool CDExtraHandler::stateChange() +{ + bool stateChange = m_stateChange; + + m_stateChange = false; + + return stateChange; +} + +void CDExtraHandler::writeStatus(wxFFile& file) +{ + for (unsigned int i = 0U; i < m_maxReflectors; i++) { + CDExtraHandler* reflector = m_reflectors[i]; + if (reflector != NULL) { + wxString text; + + struct tm* tm = ::gmtime(&reflector->m_time); + + switch (reflector->m_direction) { + case DIR_OUTGOING: + if (reflector->m_linkState == DEXTRA_LINKED) { + text.Printf(wxT("%04d-%02d-%02d %02d:%02d:%02d: DExtra link - Type: Repeater Rptr: %s Refl: %s Dir: Outgoing\n"), + tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, + reflector->m_repeater.c_str(), reflector->m_reflector.c_str()); + + file.Write(text); + } + break; + + case DIR_INCOMING: + if (reflector->m_linkState == DEXTRA_LINKED) { + if (reflector->m_repeater.IsEmpty()) + text.Printf(wxT("%04d-%02d-%02d %02d:%02d:%02d: DExtra link - Type: Dongle User: %s Dir: Incoming\n"), + tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, + reflector->m_reflector.c_str()); + else + text.Printf(wxT("%04d-%02d-%02d %02d:%02d:%02d: DExtra link - Type: Repeater Rptr: %s Refl: %s Dir: Incoming\n"), + tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, + reflector->m_repeater.c_str(), reflector->m_reflector.c_str()); + + file.Write(text); + } + break; + } + + } + } +} + +unsigned int CDExtraHandler::calcBackoff() +{ + if (m_tryCount >= 7U) { + m_tryCount++; + return 60U; + } + + unsigned int timeout = 1U; + + for (unsigned int i = 0U; i < m_tryCount; i++) + timeout *= 2U; + + m_tryCount++; + + if (timeout > 60U) + return 60U; + else + return timeout; +} diff --git a/Common/DExtraHandler.h b/Common/DExtraHandler.h new file mode 100644 index 0000000..8d11676 --- /dev/null +++ b/Common/DExtraHandler.h @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2010-2013,2015 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef DExtraHander_H +#define DExtraHander_H + +#include "DExtraProtocolHandlerPool.h" +#include "ReflectorCallback.h" +#include "DStarDefines.h" +#include "HeaderLogger.h" +#include "CallsignList.h" +#include "ConnectData.h" +#include "HeaderData.h" +#include "AMBEData.h" +#include "PollData.h" +#include "Timer.h" +#include "Defs.h" + +#if defined(__WINDOWS__) +#include "Inaddr.h" +#else +#include +#endif + +#include +#include + +enum DEXTRA_STATE { + DEXTRA_LINKING, + DEXTRA_LINKED, + DEXTRA_UNLINKING +}; + +class CDExtraHandler { +public: + static void initialise(unsigned int maxReflectors); + + static void setCallsign(const wxString& callsign); + static void setDExtraProtocolHandlerPool(CDExtraProtocolHandlerPool* pool); + static void setDExtraProtocolIncoming(CDExtraProtocolHandler* handler); + static void setHeaderLogger(CHeaderLogger* logger); + static void setMaxDongles(unsigned int maxDongles); + + static void link(IReflectorCallback* handler, const wxString& repeater, const wxString& reflector, const in_addr& address); + static void unlink(IReflectorCallback* handler, const wxString& reflector = wxEmptyString, bool exclude = true); + static void unlink(); + + static void writeHeader(IReflectorCallback* handler, CHeaderData& header, DIRECTION direction); + static void writeAMBE(IReflectorCallback* handler, CAMBEData& data, DIRECTION direction); + + static void process(CHeaderData& header); + static void process(CAMBEData& data); + static void process(const CPollData& poll); + static void process(CConnectData& connect); + + static void gatewayUpdate(const wxString& reflector, const wxString& address); + static void clock(unsigned int ms); + + static bool stateChange(); + static void writeStatus(wxFFile& file); + + static void setWhiteList(CCallsignList* list); + static void setBlackList(CCallsignList* list); + + static void finalise(); + + static void getInfo(IReflectorCallback* handler, CRemoteRepeaterData& data); + + static wxString getIncoming(const wxString& callsign); + static wxString getDongles(); + +protected: + CDExtraHandler(IReflectorCallback* handler, const wxString& reflector, const wxString& repeater, CDExtraProtocolHandler* protoHandler, const in_addr& address, unsigned int port, DIRECTION direction); + CDExtraHandler(CDExtraProtocolHandler* protoHandler, const wxString& reflector, const in_addr& address, unsigned int port, DIRECTION direction); + ~CDExtraHandler(); + + void processInt(CHeaderData& header); + void processInt(CAMBEData& data); + bool processInt(CConnectData& connect, CD_TYPE type); + + void writeHeaderInt(IReflectorCallback* handler, CHeaderData& header, DIRECTION direction); + void writeAMBEInt(IReflectorCallback* handler, CAMBEData& data, DIRECTION direction); + + bool clockInt(unsigned int ms); + +private: + static unsigned int m_maxReflectors; + static unsigned int m_maxDongles; + static CDExtraHandler** m_reflectors; + + static wxString m_callsign; + static CDExtraProtocolHandlerPool* m_pool; + static CDExtraProtocolHandler* m_incoming; + + static bool m_stateChange; + + static CHeaderLogger* m_headerLogger; + + static CCallsignList* m_whiteList; + static CCallsignList* m_blackList; + + wxString m_reflector; + wxString m_repeater; + CDExtraProtocolHandler* m_handler; + in_addr m_yourAddress; + unsigned int m_yourPort; + DIRECTION m_direction; + DEXTRA_STATE m_linkState; + IReflectorCallback* m_destination; + time_t m_time; + CTimer m_pollTimer; + CTimer m_pollInactivityTimer; + CTimer m_tryTimer; + unsigned int m_tryCount; + unsigned int m_dExtraId; + unsigned int m_dExtraSeq; + CTimer m_inactivityTimer; + CHeaderData* m_header; + + unsigned int calcBackoff(); +}; + +#endif diff --git a/Common/DExtraProtocolHandler.cpp b/Common/DExtraProtocolHandler.cpp new file mode 100644 index 0000000..7d59bf0 --- /dev/null +++ b/Common/DExtraProtocolHandler.cpp @@ -0,0 +1,228 @@ +/* + * Copyright (C) 2010-2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "DExtraProtocolHandler.h" + +#include "DStarDefines.h" +#include "Utils.h" + +// #define DUMP_TX + +const unsigned int BUFFER_LENGTH = 1000U; + +CDExtraProtocolHandler::CDExtraProtocolHandler(unsigned int port, const wxString& addr) : +m_socket(addr, port), +m_type(DE_NONE), +m_buffer(NULL), +m_length(0U), +m_yourAddress(), +m_yourPort(0U), +m_myPort(port) +{ + m_buffer = new unsigned char[BUFFER_LENGTH]; +} + +CDExtraProtocolHandler::~CDExtraProtocolHandler() +{ + delete[] m_buffer; +} + +bool CDExtraProtocolHandler::open() +{ + return m_socket.open(); +} + +unsigned int CDExtraProtocolHandler::getPort() const +{ + return m_myPort; +} + +bool CDExtraProtocolHandler::writeHeader(const CHeaderData& header) +{ + unsigned char buffer[60U]; + unsigned int length = header.getDExtraData(buffer, 60U, true); + +#if defined(DUMP_TX) + CUtils::dump(wxT("Sending Header"), buffer, length); +#endif + + for (unsigned int i = 0U; i < 5U; i++) { + bool res = m_socket.write(buffer, length, header.getYourAddress(), header.getYourPort()); + if (!res) + return false; + } + + return true; +} + +bool CDExtraProtocolHandler::writeAMBE(const CAMBEData& data) +{ + unsigned char buffer[40U]; + unsigned int length = data.getDExtraData(buffer, 40U); + +#if defined(DUMP_TX) + CUtils::dump(wxT("Sending Data"), buffer, length); +#endif + + return m_socket.write(buffer, length, data.getYourAddress(), data.getYourPort()); +} + +bool CDExtraProtocolHandler::writePoll(const CPollData& poll) +{ + unsigned char buffer[20U]; + unsigned int length = poll.getDExtraData(buffer, 20U); + +#if defined(DUMP_TX) + CUtils::dump(wxT("Sending Poll"), buffer, length); +#endif + + return m_socket.write(buffer, length, poll.getYourAddress(), poll.getYourPort()); +} + +bool CDExtraProtocolHandler::writeConnect(const CConnectData& connect) +{ + unsigned char buffer[20U]; + unsigned int length = connect.getDExtraData(buffer, 20U); + +#if defined(DUMP_TX) + CUtils::dump(wxT("Sending Connect"), buffer, length); +#endif + + for (unsigned int i = 0U; i < 2U; i++) { + bool res = m_socket.write(buffer, length, connect.getYourAddress(), connect.getYourPort()); + if (!res) + return false; + } + + return true; +} + +DEXTRA_TYPE CDExtraProtocolHandler::read() +{ + bool res = true; + + // Loop until we have no more data from the socket or we have data for the higher layers + while (res) + res = readPackets(); + + return m_type; +} + +bool CDExtraProtocolHandler::readPackets() +{ + m_type = DE_NONE; + + // No more data? + int length = m_socket.read(m_buffer, BUFFER_LENGTH, m_yourAddress, m_yourPort); + if (length <= 0) + return false; + + m_length = length; + + if (m_buffer[0] != 'D' || m_buffer[1] != 'S' || m_buffer[2] != 'V' || m_buffer[3] != 'T') { + switch (m_length) { + case 9U: + m_type = DE_POLL; + return false; + case 11U: + case 14U: + m_type = DE_CONNECT; + return false; + default: + return true; + } + } else { + // Header or data packet type? + if (m_buffer[14] == 0x80) + m_type = DE_HEADER; + else + m_type = DE_AMBE; + + return false; + } +} + +CHeaderData* CDExtraProtocolHandler::readHeader() +{ + if (m_type != DE_HEADER) + return NULL; + + CHeaderData* header = new CHeaderData; + + // DExtra checksums are unreliable + bool res = header->setDExtraData(m_buffer, m_length, false, m_yourAddress, m_yourPort, m_myPort); + if (!res) { + delete header; + return NULL; + } + + return header; +} + +CAMBEData* CDExtraProtocolHandler::readAMBE() +{ + if (m_type != DE_AMBE) + return NULL; + + CAMBEData* data = new CAMBEData; + + bool res = data->setDExtraData(m_buffer, m_length, m_yourAddress, m_yourPort, m_myPort); + if (!res) { + delete data; + return NULL; + } + + return data; +} + +CPollData* CDExtraProtocolHandler::readPoll() +{ + if (m_type != DE_POLL) + return NULL; + + CPollData* poll = new CPollData; + + bool res = poll->setDExtraData(m_buffer, m_length, m_yourAddress, m_yourPort, m_myPort); + if (!res) { + delete poll; + return NULL; + } + + return poll; +} + +CConnectData* CDExtraProtocolHandler::readConnect() +{ + if (m_type != DE_CONNECT) + return NULL; + + CConnectData* connect = new CConnectData; + + bool res = connect->setDExtraData(m_buffer, m_length, m_yourAddress, m_yourPort, m_myPort); + if (!res) { + delete connect; + return NULL; + } + + return connect; +} + +void CDExtraProtocolHandler::close() +{ + m_socket.close(); +} diff --git a/Common/DExtraProtocolHandler.h b/Common/DExtraProtocolHandler.h new file mode 100644 index 0000000..5bd9cb8 --- /dev/null +++ b/Common/DExtraProtocolHandler.h @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2010-2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef DExtraProtocolHandler_H +#define DExtraProtocolHandler_H + +#include "UDPReaderWriter.h" +#include "DStarDefines.h" +#include "ConnectData.h" +#include "HeaderData.h" +#include "AMBEData.h" +#include "PollData.h" + +#if defined(__WINDOWS__) +#include "Inaddr.h" +#else +#include +#endif + +#include + +enum DEXTRA_TYPE { + DE_NONE, + DE_HEADER, + DE_AMBE, + DE_POLL, + DE_CONNECT +}; + +class CDExtraProtocolHandler { +public: + CDExtraProtocolHandler(unsigned int port, const wxString& addr = wxEmptyString); + ~CDExtraProtocolHandler(); + + bool open(); + + unsigned int getPort() const; + + bool writeHeader(const CHeaderData& header); + bool writeAMBE(const CAMBEData& data); + bool writeConnect(const CConnectData& connect); + bool writePoll(const CPollData& poll); + + DEXTRA_TYPE read(); + CHeaderData* readHeader(); + CAMBEData* readAMBE(); + CPollData* readPoll(); + CConnectData* readConnect(); + + void close(); + +private: + CUDPReaderWriter m_socket; + DEXTRA_TYPE m_type; + unsigned char* m_buffer; + unsigned int m_length; + in_addr m_yourAddress; + unsigned int m_yourPort; + unsigned int m_myPort; + + bool readPackets(); +}; + +#endif diff --git a/Common/DExtraProtocolHandlerPool.cpp b/Common/DExtraProtocolHandlerPool.cpp new file mode 100644 index 0000000..795d3e3 --- /dev/null +++ b/Common/DExtraProtocolHandlerPool.cpp @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2012,2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "DExtraProtocolHandlerPool.h" + +CDExtraProtocolHandlerPool::CDExtraProtocolHandlerPool(unsigned int n, unsigned int port, const wxString& addr) : +m_pool(NULL), +m_n(n), +m_index(0U) +{ + wxASSERT(port > 0U); + wxASSERT(n > 0U); + + m_pool = new CDExtraProtocolHandlerEntry[n]; + + for (unsigned int i = 0U; i < n; i++) { + m_pool[i].m_handler = new CDExtraProtocolHandler(port + i, addr); + m_pool[i].m_port = port + i; + m_pool[i].m_inUse = false; + } + + wxLogMessage(wxT("Allocated UDP ports %u-%u to DExtra"), port, port + n - 1U); +} + +CDExtraProtocolHandlerPool::~CDExtraProtocolHandlerPool() +{ + for (unsigned int i = 0U; i < m_n; i++) + delete m_pool[i].m_handler; + + delete[] m_pool; +} + +bool CDExtraProtocolHandlerPool::open() +{ + for (unsigned int i = 0U; i < m_n; i++) { + bool ret = m_pool[i].m_handler->open(); + if (!ret) + return false; + } + + return true; +} + +CDExtraProtocolHandler* CDExtraProtocolHandlerPool::getHandler(unsigned int port) +{ + if (port == 0U) { + for (unsigned int i = 0U; i < m_n; i++) { + if (!m_pool[i].m_inUse) { + m_pool[i].m_inUse = true; + return m_pool[i].m_handler; + } + } + } else { + for (unsigned int i = 0U; i < m_n; i++) { + if (m_pool[i].m_port == port) { + m_pool[i].m_inUse = true; + return m_pool[i].m_handler; + } + } + } + + wxLogError(wxT("Cannot find a free DExtra port in the pool")); + + return NULL; +} + +void CDExtraProtocolHandlerPool::release(CDExtraProtocolHandler* handler) +{ + wxASSERT(handler != NULL); + + for (unsigned int i = 0U; i < m_n; i++) { + if (m_pool[i].m_handler == handler && m_pool[i].m_inUse) { + m_pool[i].m_inUse = false; + return; + } + } + + wxLogError(wxT("Trying to release an unused DExtra port")); +} + +DEXTRA_TYPE CDExtraProtocolHandlerPool::read() +{ + while (m_index < m_n) { + if (m_pool[m_index].m_inUse) { + DEXTRA_TYPE type = m_pool[m_index].m_handler->read(); + if (type != DE_NONE) + return type; + } + + m_index++; + } + + m_index = 0U; + + return DE_NONE; +} + +CHeaderData* CDExtraProtocolHandlerPool::readHeader() +{ + return m_pool[m_index].m_handler->readHeader(); +} + +CAMBEData* CDExtraProtocolHandlerPool::readAMBE() +{ + return m_pool[m_index].m_handler->readAMBE(); +} + +CPollData* CDExtraProtocolHandlerPool::readPoll() +{ + return m_pool[m_index].m_handler->readPoll(); +} + +CConnectData* CDExtraProtocolHandlerPool::readConnect() +{ + return m_pool[m_index].m_handler->readConnect(); +} + +void CDExtraProtocolHandlerPool::close() +{ + for (unsigned int i = 0U; i < m_n; i++) + m_pool[i].m_handler->close(); +} diff --git a/Common/DExtraProtocolHandlerPool.h b/Common/DExtraProtocolHandlerPool.h new file mode 100644 index 0000000..23733b4 --- /dev/null +++ b/Common/DExtraProtocolHandlerPool.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2012,2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef DExtraProtocolHandlerPool_H +#define DExtraProtocolHandlerPool_H + +#include + +#include "DExtraProtocolHandler.h" + +class CDExtraProtocolHandlerEntry { +public: + CDExtraProtocolHandler* m_handler; + unsigned int m_port; + bool m_inUse; +}; + +class CDExtraProtocolHandlerPool { +public: + CDExtraProtocolHandlerPool(unsigned int n, unsigned int port, const wxString& addr = wxEmptyString); + ~CDExtraProtocolHandlerPool(); + + bool open(); + + CDExtraProtocolHandler* getHandler(unsigned int port = 0U); + void release(CDExtraProtocolHandler* handler); + + DEXTRA_TYPE read(); + CHeaderData* readHeader(); + CAMBEData* readAMBE(); + CPollData* readPoll(); + CConnectData* readConnect(); + + void close(); + +private: + CDExtraProtocolHandlerEntry* m_pool; + unsigned int m_n; + unsigned int m_index; +}; + +#endif diff --git a/Common/DPlusAuthenticator.cpp b/Common/DPlusAuthenticator.cpp new file mode 100644 index 0000000..7c124a4 --- /dev/null +++ b/Common/DPlusAuthenticator.cpp @@ -0,0 +1,286 @@ +/* + * Copyright (C) 2010-2015 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "DPlusAuthenticator.h" +#include "UDPReaderWriter.h" +#include "DStarDefines.h" +#include "Utils.h" +#include "Defs.h" + +const wxString OPENDSTAR_HOSTNAME = wxT("opendstar.org"); +const unsigned int OPENDSTAR_PORT = 20001U; + +const wxString DUTCHSTAR_HOSTNAME = wxT("dpns.dutch-star.eu"); +const unsigned int DUTCHSTAR_PORT = 20001U; + +const unsigned int TCP_TIMEOUT = 10U; + +CDPlusAuthenticator::CDPlusAuthenticator(const wxString& loginCallsign, const wxString& gatewayCallsign, const wxString& address, CCacheManager* cache) : +wxThread(wxTHREAD_JOINABLE), +m_loginCallsign(loginCallsign), +m_gatewayCallsign(gatewayCallsign), +m_address(address), +m_cache(cache), +m_timer(1U, 6U * 3600U), // 6 hours +m_pollTimer(1U, 60U), // 1 minute +m_killed(false) +{ + wxASSERT(!loginCallsign.IsEmpty()); + wxASSERT(!gatewayCallsign.IsEmpty()); + wxASSERT(cache != NULL); + + m_gatewayCallsign.Truncate(LONG_CALLSIGN_LENGTH - 1U); + + m_loginCallsign.Trim(); + m_gatewayCallsign.Trim(); + + if (m_loginCallsign.IsEmpty()) + m_loginCallsign = m_gatewayCallsign; +} + +CDPlusAuthenticator::~CDPlusAuthenticator() +{ +} + +void CDPlusAuthenticator::start() +{ + Create(); + Run(); +} + +void* CDPlusAuthenticator::Entry() +{ + wxLogMessage(wxT("Starting the D-Plus Authenticator thread")); + + authenticate(m_loginCallsign, OPENDSTAR_HOSTNAME, OPENDSTAR_PORT, '2', true); + authenticate(m_gatewayCallsign, DUTCHSTAR_HOSTNAME, DUTCHSTAR_PORT, 'K', false); + + m_timer.start(); + m_pollTimer.start(); + + try { + while (!m_killed) { + if (m_pollTimer.hasExpired()) { + poll(m_gatewayCallsign, DUTCHSTAR_HOSTNAME, DUTCHSTAR_PORT, 'K'); + m_pollTimer.start(); + } + + if (m_timer.hasExpired()) { + authenticate(m_loginCallsign, OPENDSTAR_HOSTNAME, OPENDSTAR_PORT, '2', true); + authenticate(m_gatewayCallsign, DUTCHSTAR_HOSTNAME, DUTCHSTAR_PORT, 'K', false); + m_timer.start(); + } + + Sleep(1000UL); + + m_timer.clock(); + m_pollTimer.clock(); + } + } + catch (std::exception& e) { + wxString message(e.what(), wxConvLocal); + wxLogError(wxT("Exception raised in the D-Plus Authenticator thread - \"%s\""), message.c_str()); + } + catch (...) { + wxLogError(wxT("Unknown exception raised in the D-Plus Authenticator thread")); + } + + wxLogMessage(wxT("Stopping the D-Plus Authenticator thread")); + + return NULL; +} + +void CDPlusAuthenticator::stop() +{ + m_killed = true; + + Wait(); +} + +bool CDPlusAuthenticator::authenticate(const wxString& callsign, const wxString& hostname, unsigned int port, unsigned char id, bool writeToCache) +{ + CTCPReaderWriterClient socket(hostname, port, m_address); + + bool ret = socket.open(); + if (!ret) + return false; + + unsigned char* buffer = new unsigned char[4096U]; + ::memset(buffer, ' ', 56U); + + buffer[0U] = 0x38U; + buffer[1U] = 0xC0U; + buffer[2U] = 0x01U; + buffer[3U] = 0x00U; + + for (unsigned int i = 0U; i < callsign.Len(); i++) + buffer[i + 4U] = callsign.GetChar(i); + + buffer[12U] = 'D'; + buffer[13U] = 'V'; + buffer[14U] = '0'; + buffer[15U] = '1'; + buffer[16U] = '9'; + buffer[17U] = '9'; + buffer[18U] = '9'; + buffer[19U] = '9'; + + buffer[28U] = 'W'; + buffer[29U] = '7'; + buffer[30U] = 'I'; + buffer[31U] = 'B'; + buffer[32U] = id; + + buffer[40U] = 'D'; + buffer[41U] = 'H'; + buffer[42U] = 'S'; + buffer[43U] = '0'; + buffer[44U] = '2'; + buffer[45U] = '5'; + buffer[46U] = '7'; + + ret = socket.write(buffer, 56U); + if (!ret) { + socket.close(); + delete[] buffer; + return false; + } + + ret = read(socket, buffer + 0U, 2U); + + while (ret) { + unsigned int len = (buffer[1U] & 0x0FU) * 256U + buffer[0U]; + + // Ensure that we get exactly len - 2U bytes from the TCP stream + ret = read(socket, buffer + 2U, len - 2U); + if (!ret) { + wxLogError(wxT("Short read from %s:%u"), hostname.c_str(), port); + break; + } + + if ((buffer[1U] & 0xC0U) != 0xC0U || buffer[2U] != 0x01U) { + wxLogError(wxT("Invalid packet received from %s:%u"), hostname.c_str(), port); + CUtils::dump(wxT("Details:"), buffer, len); + break; + } + + for (unsigned int i = 8U; (i + 25U) < len; i += 26U) { + wxString address = wxString((char*)(buffer + i + 0U), wxConvLocal, 16U); + wxString name = wxString((char*)(buffer + i + 16U), wxConvLocal, LONG_CALLSIGN_LENGTH); + + address.Trim(); + name.Trim(); + + // Get the active flag + bool active = (buffer[i + 25U] & 0x80U) == 0x80U; + + // An empty name or IP address or an inactive gateway/reflector is not written out + if (address.Len() > 0U && name.Len() > 0U && !name.Left(3U).IsSameAs(wxT("XRF")) && active && writeToCache){ + if (name.Left(3U).IsSameAs(wxT("REF"))) + wxLogMessage(wxT("D-Plus: %s\t%s"), name.c_str(), address.c_str()); + + name.Append(wxT(" ")); + name.Truncate(LONG_CALLSIGN_LENGTH - 1U); + name.Append(wxT("G")); + m_cache->updateGateway(name, address, DP_DPLUS, false, true); + } + } + + ret = read(socket, buffer + 0U, 2U); + } + + wxLogMessage(wxT("Registered with %s using callsign %s"), hostname.c_str(), callsign.c_str()); + + socket.close(); + + delete[] buffer; + + return true; +} + +bool CDPlusAuthenticator::poll(const wxString& callsign, const wxString& hostname, unsigned int port, unsigned char id) +{ + CUDPReaderWriter socket(m_address, 0U); + bool ret = socket.open(); + if (!ret) + return false; + + unsigned char buffer[56U]; + ::memset(buffer, ' ', 56U); + + buffer[0U] = 0x38U; + buffer[1U] = 0x20U; + buffer[2U] = 0x01U; + buffer[3U] = 0x01U; + + for (unsigned int i = 0U; i < callsign.Len(); i++) + buffer[i + 4U] = callsign.GetChar(i); + + buffer[12U] = 'D'; + buffer[13U] = 'V'; + buffer[14U] = '0'; + buffer[15U] = '1'; + buffer[16U] = '9'; + buffer[17U] = '9'; + buffer[18U] = '9'; + buffer[19U] = '9'; + + for (unsigned int i = 0U; i < callsign.Len(); i++) + buffer[i + 20U] = callsign.GetChar(i); + + buffer[28U] = 'W'; + buffer[29U] = '7'; + buffer[30U] = 'I'; + buffer[31U] = 'B'; + buffer[32U] = id; + + buffer[40U] = 'D'; + buffer[41U] = 'H'; + buffer[42U] = 'S'; + buffer[43U] = '0'; + buffer[44U] = '2'; + buffer[45U] = '5'; + buffer[46U] = '7'; + + in_addr address = socket.lookup(hostname); + if (address.s_addr == INADDR_NONE) { + socket.close(); + return false; + } + + ret = socket.write(buffer, 56U, address, port); + + socket.close(); + + return ret; +} + +bool CDPlusAuthenticator::read(CTCPReaderWriterClient &socket, unsigned char *buffer, unsigned int len) const +{ + unsigned int offset = 0U; + + do { + int n = socket.read(buffer + offset, len - offset, TCP_TIMEOUT); + if (n < 0) + return false; + + offset += n; + } while ((len - offset) > 0U); + + return true; +} diff --git a/Common/DPlusAuthenticator.h b/Common/DPlusAuthenticator.h new file mode 100644 index 0000000..606ce12 --- /dev/null +++ b/Common/DPlusAuthenticator.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2010-2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef DPlusAuthenticator_H +#define DPlusAuthenticator_H + +#include "TCPReaderWriterClient.h" +#include "CacheManager.h" +#include "Timer.h" + +#include + +#if defined(__WINDOWS__) +#include "Inaddr.h" +#else +#include +#endif + +class CDPlusAuthenticator : public wxThread { +public: + CDPlusAuthenticator(const wxString& loginCallsign, const wxString& gatewayCallsign, const wxString& address, CCacheManager* cache); + virtual ~CDPlusAuthenticator(); + + virtual void start(); + + virtual void* Entry(); + + virtual void stop(); + +private: + wxString m_loginCallsign; + wxString m_gatewayCallsign; + wxString m_address; + CCacheManager* m_cache; + CTimer m_timer; + CTimer m_pollTimer; + bool m_killed; + + bool poll(const wxString& callsign, const wxString& hostname, unsigned int port, unsigned char id); + bool authenticate(const wxString& callsign, const wxString& hostname, unsigned int port, unsigned char id, bool writeToCache); + bool read(CTCPReaderWriterClient& socket, unsigned char* buffer, unsigned int len) const; +}; + +#endif diff --git a/Common/DPlusHandler.cpp b/Common/DPlusHandler.cpp new file mode 100644 index 0000000..f0fb631 --- /dev/null +++ b/Common/DPlusHandler.cpp @@ -0,0 +1,953 @@ +/* + * Copyright (C) 2010-2015 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "RepeaterHandler.h" +#include "DPlusHandler.h" +#include "DStarDefines.h" +#include "Utils.h" + +#include + +unsigned int CDPlusHandler::m_maxReflectors = 0U; +unsigned int CDPlusHandler::m_maxDongles = 0U; +CDPlusHandler** CDPlusHandler::m_reflectors = NULL; + +wxString CDPlusHandler::m_gatewayCallsign; +wxString CDPlusHandler::m_dplusLogin; +CDPlusProtocolHandlerPool* CDPlusHandler::m_pool = NULL; +CDPlusProtocolHandler* CDPlusHandler::m_incoming = NULL; + +bool CDPlusHandler::m_stateChange = false; + +CDPlusAuthenticator* CDPlusHandler::m_authenticator = NULL; +CHeaderLogger* CDPlusHandler::m_headerLogger = NULL; + +CCallsignList* CDPlusHandler::m_whiteList = NULL; +CCallsignList* CDPlusHandler::m_blackList = NULL; + + +CDPlusHandler::CDPlusHandler(IReflectorCallback* handler, const wxString& repeater, const wxString& reflector, CDPlusProtocolHandler* protoHandler, const in_addr& address, unsigned int port) : +m_repeater(repeater.Clone()), +m_callsign(m_dplusLogin.Clone()), +m_reflector(reflector.Clone()), +m_handler(protoHandler), +m_yourAddress(address), +m_yourPort(port), +m_myPort(0U), +m_direction(DIR_OUTGOING), +m_linkState(DPLUS_LINKING), +m_destination(handler), +m_time(), +m_pollTimer(1000U, 1U), // 1s +m_pollInactivityTimer(1000U, 30U), +m_tryTimer(1000U, 1U), +m_tryCount(0U), +m_dPlusId(0x00U), +m_dPlusSeq(0x00U), +m_inactivityTimer(1000U, NETWORK_TIMEOUT), +m_header(NULL) +{ + wxASSERT(protoHandler != NULL); + wxASSERT(handler != NULL); + wxASSERT(port > 0U); + + m_myPort = protoHandler->getPort(); + + m_pollInactivityTimer.start(); + m_tryTimer.start(); + + m_time = ::time(NULL); + + m_callsign.resize(LONG_CALLSIGN_LENGTH, ' '); + wxChar band = m_repeater.GetChar(LONG_CALLSIGN_LENGTH - 1U); + m_callsign.SetChar(LONG_CALLSIGN_LENGTH - 1U, band); +} + +CDPlusHandler::CDPlusHandler(CDPlusProtocolHandler* protoHandler, const in_addr& address, unsigned int port) : +m_repeater(), +m_callsign(), +m_reflector(), +m_handler(protoHandler), +m_yourAddress(address), +m_yourPort(port), +m_myPort(0U), +m_direction(DIR_INCOMING), +m_linkState(DPLUS_LINKING), +m_destination(NULL), +m_time(), +m_pollTimer(1000U, 1U), // 1s +m_pollInactivityTimer(1000U, 10U), // 10s +m_tryTimer(1000U), +m_tryCount(0U), +m_dPlusId(0x00U), +m_dPlusSeq(0x00U), +m_inactivityTimer(1000U, NETWORK_TIMEOUT), +m_header(NULL) +{ + wxASSERT(protoHandler != NULL); + wxASSERT(port > 0U); + + m_myPort = protoHandler->getPort(); + + m_pollTimer.start(); + m_pollInactivityTimer.start(); + + m_time = ::time(NULL); +} + +CDPlusHandler::~CDPlusHandler() +{ + if (m_direction == DIR_OUTGOING) + m_pool->release(m_handler); + + delete m_header; +} + +void CDPlusHandler::initialise(unsigned int maxReflectors) +{ + wxASSERT(maxReflectors > 0U); + + m_maxReflectors = maxReflectors; + + m_reflectors = new CDPlusHandler*[m_maxReflectors]; + for (unsigned int i = 0U; i < m_maxReflectors; i++) + m_reflectors[i] = NULL; +} + +void CDPlusHandler::startAuthenticator(const wxString& address, CCacheManager* cache) +{ + wxASSERT(cache != NULL); + + m_authenticator = new CDPlusAuthenticator(m_dplusLogin, m_gatewayCallsign, address, cache); + m_authenticator->start(); +} + +void CDPlusHandler::setCallsign(const wxString& callsign) +{ + m_gatewayCallsign = callsign; +} + +void CDPlusHandler::setDPlusProtocolHandlerPool(CDPlusProtocolHandlerPool* pool) +{ + wxASSERT(pool != NULL); + + m_pool = pool; +} + +void CDPlusHandler::setDPlusProtocolIncoming(CDPlusProtocolHandler* handler) +{ + wxASSERT(handler != NULL); + + m_incoming = handler; +} + +void CDPlusHandler::setDPlusLogin(const wxString& dplusLogin) +{ + m_dplusLogin = dplusLogin; +} + +void CDPlusHandler::setHeaderLogger(CHeaderLogger* logger) +{ + m_headerLogger = logger; +} + +void CDPlusHandler::setMaxDongles(unsigned int maxDongles) +{ + m_maxDongles = maxDongles; +} + +void CDPlusHandler::setWhiteList(CCallsignList* list) +{ + wxASSERT(list != NULL); + + m_whiteList = list; +} + +void CDPlusHandler::setBlackList(CCallsignList* list) +{ + wxASSERT(list != NULL); + + m_blackList = list; +} + +void CDPlusHandler::getInfo(IReflectorCallback* handler, CRemoteRepeaterData& data) +{ + wxASSERT(handler != NULL); + + for (unsigned int i = 0U; i < m_maxReflectors; i++) { + CDPlusHandler* reflector = m_reflectors[i]; + if (reflector != NULL) { + if (reflector->m_destination == handler && reflector->m_linkState != DPLUS_UNLINKING) + data.addLink(reflector->m_reflector, PROTO_DPLUS, reflector->m_linkState == DPLUS_LINKED, reflector->m_direction, true); + } + } +} + +wxString CDPlusHandler::getDongles() +{ + wxString dongles; + + for (unsigned int i = 0U; i < m_maxReflectors; i++) { + CDPlusHandler* reflector = m_reflectors[i]; + + if (reflector != NULL && reflector->m_direction == DIR_INCOMING) { + dongles.Append(wxT("P:")); + dongles.Append(reflector->m_reflector); + dongles.Append(wxT(" ")); + } + } + + return dongles; +} + +void CDPlusHandler::process(CHeaderData& header) +{ + in_addr yourAddress = header.getYourAddress(); + unsigned int yourPort = header.getYourPort(); + unsigned int myPort = header.getMyPort(); + + for (unsigned int i = 0U; i < m_maxReflectors; i++) { + CDPlusHandler* reflector = m_reflectors[i]; + + if (reflector != NULL) { + if (reflector->m_yourAddress.s_addr == yourAddress.s_addr && + reflector->m_yourPort == yourPort && + reflector->m_myPort == myPort) { + reflector->processInt(header); + return; + } + } + } +} + +void CDPlusHandler::process(CAMBEData& data) +{ + in_addr yourAddress = data.getYourAddress(); + unsigned int yourPort = data.getYourPort(); + unsigned int myPort = data.getMyPort(); + + for (unsigned int i = 0U; i < m_maxReflectors; i++) { + CDPlusHandler* reflector = m_reflectors[i]; + + if (reflector != NULL) { + if (reflector->m_yourAddress.s_addr == yourAddress.s_addr && + reflector->m_yourPort == yourPort && + reflector->m_myPort == myPort) { + reflector->processInt(data); + return; + } + } + } +} + +void CDPlusHandler::process(const CPollData& poll) +{ + in_addr yourAddress = poll.getYourAddress(); + unsigned int yourPort = poll.getYourPort(); + unsigned int myPort = poll.getMyPort(); + + for (unsigned int i = 0U; i < m_maxReflectors; i++) { + CDPlusHandler* reflector = m_reflectors[i]; + + if (reflector != NULL) { + if (reflector->m_yourAddress.s_addr == yourAddress.s_addr && + reflector->m_yourPort == yourPort && + reflector->m_myPort == myPort) { + reflector->m_pollInactivityTimer.start(); + return; + } + } + } + + // If we cannot find an existing link, we ignore the poll + wxLogMessage(wxT("Incoming poll from unknown D-Plus dongle")); +} + +void CDPlusHandler::process(CConnectData& connect) +{ + CD_TYPE type = connect.getType(); + in_addr yourAddress = connect.getYourAddress(); + unsigned int yourPort = connect.getYourPort(); + unsigned int myPort = connect.getMyPort(); + + for (unsigned int i = 0U; i < m_maxReflectors; i++) { + CDPlusHandler* reflector = m_reflectors[i]; + + if (reflector != NULL) { + if (reflector->m_yourAddress.s_addr == yourAddress.s_addr && + reflector->m_yourPort == yourPort && + reflector->m_myPort == myPort) { + bool res = m_reflectors[i]->processInt(connect, type); + if (res) { + delete m_reflectors[i]; + m_reflectors[i] = NULL; + } + } + } + } + + // Check that it isn't a duplicate + for (unsigned int i = 0U; i < m_maxReflectors; i++) { + CDPlusHandler* reflector = m_reflectors[i]; + + if (reflector != NULL) { + if (reflector->m_yourAddress.s_addr == yourAddress.s_addr && + reflector->m_yourPort == yourPort && + reflector->m_myPort == myPort) + return; + } + } + + if (type == CT_UNLINK) + return; + + if (type != CT_LINK1) { + wxLogMessage(wxT("Incoming D-Plus message from unknown source")); + return; + } + + // Check to see if we are allowed to accept it + unsigned int count = 0U; + for (unsigned int i = 0U; i < m_maxReflectors; i++) { + if (m_reflectors[i] != NULL && + m_reflectors[i]->m_direction == DIR_INCOMING) + count++; + } + + if (count >= m_maxDongles) + return; + + CDPlusHandler* dplus = new CDPlusHandler(m_incoming, yourAddress, yourPort); + + bool found = false; + + for (unsigned int i = 0U; i < m_maxReflectors; i++) { + if (m_reflectors[i] == NULL) { + m_reflectors[i] = dplus; + found = true; + break; + } + } + + if (found) { + CConnectData connect(CT_LINK1, yourAddress, yourPort); + m_incoming->writeConnect(connect); + } else { + wxLogError(wxT("No space to add new D-Plus dongle, ignoring")); + delete dplus; + } +} + +void CDPlusHandler::link(IReflectorCallback* handler, const wxString& repeater, const wxString &gateway, const in_addr& address) +{ + CDPlusProtocolHandler* protoHandler = m_pool->getHandler(); + if (protoHandler == NULL) + return; + + CDPlusHandler* dplus = new CDPlusHandler(handler, repeater, gateway, protoHandler, address, DPLUS_PORT); + + bool found = false; + + for (unsigned int i = 0U; i < m_maxReflectors; i++) { + if (m_reflectors[i] == NULL) { + m_reflectors[i] = dplus; + found = true; + break; + } + } + + if (found) { + CConnectData connect(CT_LINK1, address, DPLUS_PORT); + protoHandler->writeConnect(connect); + m_stateChange = true; + } else { + wxLogError(wxT("No space to add new D-Plus reflector, ignoring")); + delete dplus; + } +} + +void CDPlusHandler::relink(IReflectorCallback* handler, const wxString &gateway) +{ + for (unsigned int i = 0U; i < m_maxReflectors; i++) { + if (m_reflectors[i] != NULL && m_reflectors[i]->m_direction == DIR_OUTGOING) { + if (m_reflectors[i]->m_destination == handler) { + m_reflectors[i]->m_reflector = gateway; + m_reflectors[i]->m_dPlusId = 0x00U; + m_reflectors[i]->m_dPlusSeq = 0x00U; + m_stateChange = true; + return; + } + } + } +} + +void CDPlusHandler::unlink(IReflectorCallback* handler, const wxString& callsign, bool exclude) +{ + for (unsigned int i = 0U; i < m_maxReflectors; i++) { + CDPlusHandler* reflector = m_reflectors[i]; + + if (reflector != NULL) { + bool found = false; + + if (exclude) { + if (reflector->m_direction == DIR_OUTGOING && reflector->m_destination == handler && !reflector->m_reflector.IsSameAs(callsign)) { + wxLogMessage(wxT("Removing outgoing D-Plus link %s, %s"), reflector->m_repeater.c_str(), reflector->m_reflector.c_str()); + + if (reflector->m_linkState == DPLUS_LINKING || reflector->m_linkState == DPLUS_LINKED) { + CConnectData connect(CT_UNLINK, reflector->m_yourAddress, DPLUS_PORT); + reflector->m_handler->writeConnect(connect); + reflector->m_handler->writeConnect(connect); + + reflector->m_linkState = DPLUS_UNLINKING; + reflector->m_tryTimer.start(1U); + reflector->m_pollTimer.stop(); + reflector->m_pollInactivityTimer.stop(); + reflector->m_tryCount = 0U; + } + + found = true; + } + } else { + if (reflector->m_destination == handler && reflector->m_reflector.IsSameAs(callsign)) { + wxLogMessage(wxT("Removing D-Plus link %s, %s"), reflector->m_repeater.c_str(), reflector->m_reflector.c_str()); + + if (reflector->m_linkState == DPLUS_LINKING || reflector->m_linkState == DPLUS_LINKED) { + CConnectData connect(CT_UNLINK, reflector->m_yourAddress, DPLUS_PORT); + reflector->m_handler->writeConnect(connect); + reflector->m_handler->writeConnect(connect); + + reflector->m_linkState = DPLUS_UNLINKING; + reflector->m_tryTimer.start(1U); + reflector->m_pollTimer.stop(); + reflector->m_pollInactivityTimer.stop(); + reflector->m_tryCount = 0U; + } + + found = true; + } + } + + // If an active link with incoming traffic, send an EOT to the repeater + if (found) { + if (reflector->m_dPlusId != 0x00U) { + unsigned int seq = reflector->m_dPlusSeq + 1U; + if (seq == 21U) + seq = 0U; + + CAMBEData data; + data.setData(END_PATTERN_BYTES, DV_FRAME_LENGTH_BYTES); + data.setSeq(seq); + data.setEnd(true); + data.setId(reflector->m_dPlusId); + + reflector->m_destination->process(data, reflector->m_direction, AS_DPLUS); + } + + m_stateChange = true; + } + } + } +} + +void CDPlusHandler::unlink() +{ + for (unsigned int i = 0U; i < m_maxReflectors; i++) { + CDPlusHandler* reflector = m_reflectors[i]; + if (reflector != NULL) { + if (!reflector->m_reflector.IsEmpty()) + wxLogMessage(wxT("Unlinking from D-Plus reflector or dongle %s"), reflector->m_reflector.c_str()); + + CConnectData connect(CT_UNLINK, reflector->m_yourAddress, reflector->m_yourPort); + reflector->m_handler->writeConnect(connect); + reflector->m_handler->writeConnect(connect); + reflector->m_tryTimer.start(1U); + reflector->m_pollTimer.stop(); + reflector->m_pollInactivityTimer.stop(); + reflector->m_tryCount = 0U; + } + } +} + +void CDPlusHandler::writeHeader(IReflectorCallback* handler, CHeaderData& header, DIRECTION direction) +{ + for (unsigned int i = 0U; i < m_maxReflectors; i++) { + if (m_reflectors[i] != NULL) + m_reflectors[i]->writeHeaderInt(handler, header, direction); + } +} + +void CDPlusHandler::writeAMBE(IReflectorCallback* handler, CAMBEData& data, DIRECTION direction) +{ + for (unsigned int i = 0U; i < m_maxReflectors; i++) { + if (m_reflectors[i] != NULL) + m_reflectors[i]->writeAMBEInt(handler, data, direction); + } +} + +void CDPlusHandler::gatewayUpdate(const wxString& gateway, const wxString& address) +{ + wxString gatewayBase = gateway; + gatewayBase.Truncate(LONG_CALLSIGN_LENGTH - 1U); + + for (unsigned int i = 0U; i < m_maxReflectors; i++) { + CDPlusHandler* reflector = m_reflectors[i]; + if (reflector != NULL) { + if (!reflector->m_reflector.IsEmpty() && reflector->m_reflector.Left(LONG_CALLSIGN_LENGTH - 1U).IsSameAs(gatewayBase)) { + if (!address.IsEmpty()) { + // A new address, change the value + wxLogMessage(wxT("Changing IP address of D-Plus gateway or reflector %s to %s"), gatewayBase.c_str(), address.c_str()); + reflector->m_yourAddress.s_addr = ::inet_addr(address.mb_str()); + } else { + wxLogMessage(wxT("IP address for D-Plus gateway or reflector %s has been removed"), gatewayBase.c_str()); + + // No address, this probably shouldn't happen.... + if (reflector->m_direction == DIR_OUTGOING && reflector->m_destination != NULL) + reflector->m_destination->linkFailed(DP_DPLUS, reflector->m_reflector, false); + + m_stateChange = true; + + delete m_reflectors[i]; + m_reflectors[i] = NULL; + } + } + } + } +} + +void CDPlusHandler::clock(unsigned int ms) +{ + for (unsigned int i = 0U; i < m_maxReflectors; i++) { + if (m_reflectors[i] != NULL) { + bool ret = m_reflectors[i]->clockInt(ms); + if (ret) { + delete m_reflectors[i]; + m_reflectors[i] = NULL; + } + } + } +} + +void CDPlusHandler::finalise() +{ + if (m_authenticator != NULL) + m_authenticator->stop(); + + for (unsigned int i = 0U; i < m_maxReflectors; i++) + delete m_reflectors[i]; + + delete[] m_reflectors; +} + +void CDPlusHandler::processInt(CHeaderData& header) +{ + wxString my = header.getMyCall1(); + wxString rpt1 = header.getRptCall1(); + wxString rpt2 = header.getRptCall2(); + unsigned int id = header.getId(); + + if (m_whiteList != NULL) { + bool res = m_whiteList->isInList(my); + if (!res) { + wxLogMessage(wxT("%s rejected from D-Plus as not found in the white list"), my.c_str()); + m_dPlusId = 0x00U; + return; + } + } + + if (m_blackList != NULL) { + bool res = m_blackList->isInList(my); + if (res) { + wxLogMessage(wxT("%s rejected from D-Plus as found in the black list"), my.c_str()); + m_dPlusId = 0x00U; + return; + } + } + + if (m_linkState != DPLUS_LINKED) + return; + + switch (m_direction) { + case DIR_OUTGOING: + if (m_reflector.IsSameAs(rpt1) || m_reflector.IsSameAs(rpt2)) { + // If we're already processing, ignore the new header + if (m_dPlusId != 0x00U) + return; + + // Write to Header.log if it's enabled + if (m_headerLogger != NULL) + m_headerLogger->write(wxT("DPlus"), header); + + m_dPlusId = id; + m_dPlusSeq = 0x00U; + m_inactivityTimer.start(); + m_pollInactivityTimer.start(); + + delete m_header; + + m_header = new CHeaderData(header); + m_header->setCQCQCQ(); + m_header->setFlags(0x00U, 0x00U, 0x00U); + + m_destination->process(*m_header, m_direction, AS_DPLUS); + } + break; + + case DIR_INCOMING: { + m_destination = CRepeaterHandler::findDVRepeater(rpt1); + if (m_destination == NULL) { + m_destination = CRepeaterHandler::findDVRepeater(rpt2); + if (m_destination == NULL) + return; + } + + if (m_dPlusId != 0x00U) + return; + + // Write to Header.log if it's enabled + if (m_headerLogger != NULL) + m_headerLogger->write(wxT("DPlus"), header); + + m_dPlusId = id; + m_dPlusSeq = 0x00U; + m_inactivityTimer.start(); + m_pollInactivityTimer.start(); + + delete m_header; + + m_header = new CHeaderData(header); + m_header->setCQCQCQ(); + m_header->setFlags(0x00U, 0x00U, 0x00U); + + m_destination->process(*m_header, m_direction, AS_DPLUS); + } + break; + } +} + +void CDPlusHandler::processInt(CAMBEData& data) +{ + unsigned int id = data.getId(); + + if (m_dPlusId != id) + return; + + m_dPlusSeq = data.getSeq(); + + // Send the header every 21 frames, if we have it + if (m_dPlusSeq == 0U && m_header != NULL) + m_destination->process(*m_header, m_direction, AS_DUP); + + m_inactivityTimer.start(); + m_pollInactivityTimer.start(); + + m_destination->process(data, m_direction, AS_DPLUS); + + if (data.isEnd()) { + m_dPlusId = 0x00U; + m_dPlusSeq = 0x00U; + + delete m_header; + m_header = NULL; + + m_inactivityTimer.stop(); + } +} + +bool CDPlusHandler::processInt(CConnectData& connect, CD_TYPE type) +{ + switch (m_direction) { + case DIR_OUTGOING: + switch (type) { + case CT_ACK: + if (m_linkState == DPLUS_LINKING) { + wxLogMessage(wxT("D-Plus ACK message received from %s"), m_reflector.c_str()); + m_destination->linkUp(DP_DPLUS, m_reflector); + m_stateChange = true; + m_linkState = DPLUS_LINKED; + m_tryTimer.stop(); + m_pollTimer.start(); + m_pollInactivityTimer.start(); + } + return false; + + case CT_NAK: + if (m_linkState == DPLUS_LINKING) { + wxLogMessage(wxT("D-Plus NAK message received from %s"), m_reflector.c_str()); + m_destination->linkRefused(DP_DPLUS, m_reflector); + CConnectData reply(CT_UNLINK, connect.getYourAddress(), connect.getYourPort()); + m_handler->writeConnect(reply); + m_tryTimer.stop(); + } + return true; + + case CT_UNLINK: + if (m_linkState == DPLUS_UNLINKING) { + wxLogMessage(wxT("D-Plus disconnect acknowledgement received from %s"), m_reflector.c_str()); + m_destination->linkFailed(DP_DPLUS, m_reflector, false); + m_stateChange = true; + m_tryTimer.stop(); + } + return true; + + case CT_LINK1: { + CConnectData reply(m_dplusLogin, CT_LINK2, connect.getYourAddress(), connect.getYourPort()); + m_handler->writeConnect(reply); + m_tryTimer.stop(); + } + return false; + + default: + return false; + } + break; + + case DIR_INCOMING: + switch (type) { + case CT_LINK2: { + m_reflector = connect.getRepeater(); + wxLogMessage(wxT("D-Plus dongle link to %s has started"), m_reflector.c_str()); + CConnectData reply(CT_ACK, m_yourAddress, m_yourPort); + m_handler->writeConnect(reply); + m_linkState = DPLUS_LINKED; + m_stateChange = true; + } + return false; + + case CT_UNLINK: + if (m_linkState == DPLUS_LINKED) { + wxLogMessage(wxT("D-Plus dongle link to %s has ended (unlinked)"), m_reflector.c_str()); + m_stateChange = true; + m_handler->writeConnect(connect); + } + return true; + + default: + return false; + } + break; + } + + return false; +} + +bool CDPlusHandler::clockInt(unsigned int ms) +{ + m_tryTimer.clock(ms); + m_pollTimer.clock(ms); + m_inactivityTimer.clock(ms); + m_pollInactivityTimer.clock(ms); + + if (m_pollInactivityTimer.isRunning() && m_pollInactivityTimer.hasExpired()) { + m_pollInactivityTimer.start(); + + delete m_header; + m_header = NULL; + + m_stateChange = true; + m_dPlusId = 0x00U; + m_dPlusSeq = 0x00U; + + if (!m_reflector.IsEmpty()) { + switch (m_linkState) { + case DPLUS_LINKING: + wxLogMessage(wxT("D-Plus link to %s has failed to connect"), m_reflector.c_str()); + break; + case DPLUS_LINKED: + wxLogMessage(wxT("D-Plus link to %s has failed (poll inactivity)"), m_reflector.c_str()); + break; + case DPLUS_UNLINKING: + wxLogMessage(wxT("D-Plus link to %s has failed to disconnect cleanly"), m_reflector.c_str()); + break; + default: + break; + } + } + + if (m_direction == DIR_OUTGOING) { + bool reconnect = m_destination->linkFailed(DP_DPLUS, m_reflector, true); + if (reconnect) { + CConnectData connect(CT_LINK1, m_yourAddress, DPLUS_PORT); + m_handler->writeConnect(connect); + m_linkState = DPLUS_LINKING; + m_tryTimer.start(1U); + m_tryCount = 0U; + return false; + } + } + + return true; + } + + if (m_pollTimer.isRunning() && m_pollTimer.hasExpired()) { + CPollData poll(m_yourAddress, m_yourPort); + m_handler->writePoll(poll); + + m_pollTimer.start(); + } + + if (m_tryTimer.isRunning() && m_tryTimer.hasExpired()) { + switch (m_linkState) { + case DPLUS_LINKING: { + CConnectData connect(CT_LINK1, m_yourAddress, DPLUS_PORT); + m_handler->writeConnect(connect); + } + break; + + case DPLUS_UNLINKING: { + CConnectData connect(CT_UNLINK, m_yourAddress, m_yourPort); + m_handler->writeConnect(connect); + m_handler->writeConnect(connect); + } + break; + + default: + break; + } + + unsigned int timeout = calcBackoff(); + m_tryTimer.start(timeout); + } + + if (m_inactivityTimer.isRunning() && m_inactivityTimer.hasExpired()) { + delete m_header; + m_header = NULL; + + m_dPlusId = 0x00U; + m_dPlusSeq = 0x00U; + + m_inactivityTimer.stop(); + } + + return false; +} + +void CDPlusHandler::writeHeaderInt(IReflectorCallback* handler, CHeaderData& header, DIRECTION direction) +{ + wxASSERT(handler != NULL); + + if (m_linkState != DPLUS_LINKED) + return; + + if (direction != m_direction) + return; + + // Already is use? + if (m_dPlusId != 0x00U) + return; + + switch (m_direction) { + case DIR_OUTGOING: + if (m_destination == handler) { + header.setRepeaters(m_callsign, m_reflector); + header.setDestination(m_yourAddress, m_yourPort); + m_handler->writeHeader(header); + } + break; + + case DIR_INCOMING: + header.setDestination(m_yourAddress, m_yourPort); + m_handler->writeHeader(header); + break; + } +} + +void CDPlusHandler::writeAMBEInt(IReflectorCallback* handler, CAMBEData& data, DIRECTION direction) +{ + if (m_linkState != DPLUS_LINKED) + return; + + if (direction != m_direction) + return; + + // Already in use? + if (m_dPlusId != 0x00U) + return; + + switch (m_direction) { + case DIR_OUTGOING: + if (m_destination == handler) { + data.setDestination(m_yourAddress, m_yourPort); + m_handler->writeAMBE(data); + } + break; + + case DIR_INCOMING: + data.setDestination(m_yourAddress, m_yourPort); + m_handler->writeAMBE(data); + break; + } +} + +bool CDPlusHandler::stateChange() +{ + bool stateChange = m_stateChange; + + m_stateChange = false; + + return stateChange; +} + +void CDPlusHandler::writeStatus(wxFFile& file) +{ + for (unsigned int i = 0U; i < m_maxReflectors; i++) { + CDPlusHandler* reflector = m_reflectors[i]; + if (reflector != NULL) { + wxString text; + + struct tm* tm = ::gmtime(&reflector->m_time); + + if (reflector->m_linkState == DPLUS_LINKED) { + switch (reflector->m_direction) { + case DIR_OUTGOING: + text.Printf(wxT("%04d-%02d-%02d %02d:%02d:%02d: DPlus link - Type: Dongle Rptr: %s Refl: %s Dir: Outgoing\n"), + tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, + reflector->m_repeater.c_str(), reflector->m_reflector.c_str()); + break; + + case DIR_INCOMING: + text.Printf(wxT("%04d-%02d-%02d %02d:%02d:%02d: DPlus link - Type: Dongle User: %s Dir: Incoming\n"), + tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, + reflector->m_reflector.c_str()); + break; + } + + file.Write(text); + } + } + } +} + +unsigned int CDPlusHandler::calcBackoff() +{ + if (m_tryCount >= 7U) { + m_tryCount++; + return 60U; + } + + unsigned int timeout = 1U; + + for (unsigned int i = 0U; i < m_tryCount; i++) + timeout *= 2U; + + m_tryCount++; + + if (timeout > 60U) + return 60U; + else + return timeout; +} diff --git a/Common/DPlusHandler.h b/Common/DPlusHandler.h new file mode 100644 index 0000000..37dcf0b --- /dev/null +++ b/Common/DPlusHandler.h @@ -0,0 +1,147 @@ +/* + * Copyright (C) 2010-2013,2015 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef DPlusHandler_H +#define DPlusHandler_H + +#include "DPlusProtocolHandlerPool.h" +#include "DPlusAuthenticator.h" +#include "ReflectorCallback.h" +#include "CacheManager.h" +#include "DStarDefines.h" +#include "HeaderLogger.h" +#include "CallsignList.h" +#include "ConnectData.h" +#include "HeaderData.h" +#include "AMBEData.h" +#include "PollData.h" +#include "Timer.h" +#include "Defs.h" + +#if defined(__WINDOWS__) +#include "Inaddr.h" +#else +#include +#endif + +#include +#include + +enum DPLUS_STATE { + DPLUS_LINKING, + DPLUS_LINKED, + DPLUS_UNLINKING +}; + +class CDPlusHandler { +public: + static void initialise(unsigned int maxReflectors); + + static void setCallsign(const wxString& callsign); + static void setDPlusProtocolHandlerPool(CDPlusProtocolHandlerPool* pool); + static void setDPlusProtocolIncoming(CDPlusProtocolHandler* handler); + static void setDPlusLogin(const wxString& dplusLogin); + static void setHeaderLogger(CHeaderLogger* logger); + static void setMaxDongles(unsigned int maxDongles); + + static void startAuthenticator(const wxString& address, CCacheManager* cache); + + static void link(IReflectorCallback* handler, const wxString& repeater, const wxString& reflector, const in_addr& address); + static void relink(IReflectorCallback* handler, const wxString& reflector); + static void unlink(IReflectorCallback* handler, const wxString& reflector = wxEmptyString, bool exclude = true); + static void unlink(); + + static void writeHeader(IReflectorCallback* handler, CHeaderData& header, DIRECTION direction); + static void writeAMBE(IReflectorCallback* handler, CAMBEData& data, DIRECTION direction); + + static void process(CHeaderData& header); + static void process(CAMBEData& header); + static void process(const CPollData& header); + static void process(CConnectData& process); + + static void gatewayUpdate(const wxString& gateway, const wxString& address); + static void clock(unsigned int ms); + + static bool stateChange(); + static void writeStatus(wxFFile& file); + + static void setWhiteList(CCallsignList* list); + static void setBlackList(CCallsignList* list); + + static void finalise(); + + static void getInfo(IReflectorCallback* handler, CRemoteRepeaterData& data); + + static wxString getDongles(); + +protected: + CDPlusHandler(IReflectorCallback* handler, const wxString& repeater, const wxString& reflector, CDPlusProtocolHandler* protoHandler, const in_addr& address, unsigned int port); + CDPlusHandler(CDPlusProtocolHandler* protoHandler, const in_addr& address, unsigned int port); + ~CDPlusHandler(); + + void processInt(CHeaderData& header); + void processInt(CAMBEData& data); + bool processInt(CConnectData& connect, CD_TYPE type); + + void writeHeaderInt(IReflectorCallback* handler, CHeaderData& header, DIRECTION direction); + void writeAMBEInt(IReflectorCallback* handler, CAMBEData& data, DIRECTION direction); + + bool clockInt(unsigned int ms); + +private: + static unsigned int m_maxReflectors; + static unsigned int m_maxDongles; + static CDPlusHandler** m_reflectors; + + static wxString m_gatewayCallsign; + static wxString m_dplusLogin; + static CDPlusProtocolHandlerPool* m_pool; + static CDPlusProtocolHandler* m_incoming; + + static bool m_stateChange; + + static CHeaderLogger* m_headerLogger; + static CDPlusAuthenticator* m_authenticator; + + static CCallsignList* m_whiteList; + static CCallsignList* m_blackList; + + wxString m_repeater; + wxString m_callsign; + wxString m_reflector; + CDPlusProtocolHandler* m_handler; + in_addr m_yourAddress; + unsigned int m_yourPort; + unsigned int m_myPort; + DIRECTION m_direction; + DPLUS_STATE m_linkState; + IReflectorCallback* m_destination; + time_t m_time; + CTimer m_pollTimer; + CTimer m_pollInactivityTimer; + CTimer m_tryTimer; + unsigned int m_tryCount; + unsigned int m_dPlusId; + unsigned int m_dPlusSeq; + CTimer m_inactivityTimer; + CHeaderData* m_header; + + unsigned int calcBackoff(); +}; + +#endif diff --git a/Common/DPlusProtocolHandler.cpp b/Common/DPlusProtocolHandler.cpp new file mode 100644 index 0000000..8781ac7 --- /dev/null +++ b/Common/DPlusProtocolHandler.cpp @@ -0,0 +1,233 @@ +/* + * Copyright (C) 2010-2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "DPlusProtocolHandler.h" + +#include "DStarDefines.h" +#include "Utils.h" + +// #define DUMP_TX + +const unsigned int BUFFER_LENGTH = 1000U; + +CDPlusProtocolHandler::CDPlusProtocolHandler(unsigned int port, const wxString& addr) : +m_socket(addr, port), +m_type(DP_NONE), +m_buffer(NULL), +m_length(0U), +m_yourAddress(), +m_yourPort(0U), +m_myPort(port) +{ + m_buffer = new unsigned char[BUFFER_LENGTH]; +} + +CDPlusProtocolHandler::~CDPlusProtocolHandler() +{ + delete[] m_buffer; +} + +bool CDPlusProtocolHandler::open() +{ + return m_socket.open(); +} + +unsigned int CDPlusProtocolHandler::getPort() const +{ + return m_myPort; +} + +bool CDPlusProtocolHandler::writeHeader(const CHeaderData& header) +{ + unsigned char buffer[60U]; + unsigned int length = header.getDPlusData(buffer, 60U, true); + +#if defined(DUMP_TX) + CUtils::dump(wxT("Sending Header"), buffer, length); +#endif + + for (unsigned int i = 0U; i < 5U; i++) { + bool res = m_socket.write(buffer, length, header.getYourAddress(), header.getYourPort()); + if (!res) + return false; + } + + return true; +} + +bool CDPlusProtocolHandler::writeAMBE(const CAMBEData& data) +{ + unsigned char buffer[40U]; + unsigned int length = data.getDPlusData(buffer, 40U); + +#if defined(DUMP_TX) + CUtils::dump(wxT("Sending Data"), buffer, length); +#endif + + return m_socket.write(buffer, length, data.getYourAddress(), data.getYourPort()); +} + +bool CDPlusProtocolHandler::writePoll(const CPollData& poll) +{ + unsigned char buffer[10U]; + unsigned int length = poll.getDPlusData(buffer, 10U); + +#if defined(DUMP_TX) + CUtils::dump(wxT("Sending Poll"), buffer, length); +#endif + + return m_socket.write(buffer, length, poll.getYourAddress(), poll.getYourPort()); +} + +bool CDPlusProtocolHandler::writeConnect(const CConnectData& connect) +{ + unsigned char buffer[40U]; + unsigned int length = connect.getDPlusData(buffer, 40U); + +#if defined(DUMP_TX) + CUtils::dump(wxT("Sending Connect"), buffer, length); +#endif + + return m_socket.write(buffer, length, connect.getYourAddress(), connect.getYourPort()); +} + +DPLUS_TYPE CDPlusProtocolHandler::read() +{ + bool res = true; + + // Loop until we have no more data from the socket or we have data for the higher layers + while (res) + res = readPackets(); + + return m_type; +} + +bool CDPlusProtocolHandler::readPackets() +{ + m_type = DP_NONE; + + // No more data? + int length = m_socket.read(m_buffer, BUFFER_LENGTH, m_yourAddress, m_yourPort); + if (length <= 0) + return false; + + m_length = length; + + if (m_buffer[2] != 'D' || m_buffer[3] != 'S' || m_buffer[4] != 'V' || m_buffer[5] != 'T') { + switch (m_length) { + case 3U: + m_type = DP_POLL; + return false; + case 5U: + case 8U: + case 28U: + m_type = DP_CONNECT; + return false; + default: + // An unknown type + // CUtils::dump(wxT("Unknown packet type from D-Plus"), m_buffer, m_length); + return true; + } + } else { + // Header or data packet type? + if (m_buffer[0] == 0x3A && m_buffer[1] == 0x80) { + m_type = DP_HEADER; + return false; + } else if (m_buffer[0] == 0x1D && m_buffer[1] == 0x80) { + m_type = DP_AMBE; + return false; + } else if (m_buffer[0] == 0x20 && m_buffer[1] == 0x80) { + m_type = DP_AMBE; + return false; + } else { + // An unknown type + CUtils::dump(wxT("Unknown packet type from D-Plus"), m_buffer, m_length); + return true; + } + } +} + +CHeaderData* CDPlusProtocolHandler::readHeader() +{ + if (m_type != DP_HEADER) + return NULL; + + CHeaderData* header = new CHeaderData; + + // DPlus checksums are unreliable + bool res = header->setDPlusData(m_buffer, m_length, false, m_yourAddress, m_yourPort, m_myPort); + if (!res) { + delete header; + return NULL; + } + + return header; +} + +CAMBEData* CDPlusProtocolHandler::readAMBE() +{ + if (m_type != DP_AMBE) + return NULL; + + CAMBEData* data = new CAMBEData; + + bool res = data->setDPlusData(m_buffer, m_length, m_yourAddress, m_yourPort, m_myPort); + if (!res) { + delete data; + return NULL; + } + + return data; +} + +CPollData* CDPlusProtocolHandler::readPoll() +{ + if (m_type != DP_POLL) + return NULL; + + CPollData* poll = new CPollData; + + bool res = poll->setDPlusData(m_buffer, m_length, m_yourAddress, m_yourPort, m_myPort); + if (!res) { + delete poll; + return NULL; + } + + return poll; +} + +CConnectData* CDPlusProtocolHandler::readConnect() +{ + if (m_type != DP_CONNECT) + return NULL; + + CConnectData* connect = new CConnectData; + + bool res = connect->setDPlusData(m_buffer, m_length, m_yourAddress, m_yourPort, m_myPort); + if (!res) { + delete connect; + return NULL; + } + + return connect; +} + +void CDPlusProtocolHandler::close() +{ + m_socket.close(); +} diff --git a/Common/DPlusProtocolHandler.h b/Common/DPlusProtocolHandler.h new file mode 100644 index 0000000..3978f78 --- /dev/null +++ b/Common/DPlusProtocolHandler.h @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2010,2011,2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef DPlusProtocolHandler_H +#define DPlusProtocolHandler_H + +#include "UDPReaderWriter.h" +#include "DStarDefines.h" +#include "ConnectData.h" +#include "HeaderData.h" +#include "AMBEData.h" +#include "PollData.h" + +#if defined(__WINDOWS__) +#include "Inaddr.h" +#else +#include +#endif + +#include + +enum DPLUS_TYPE { + DP_NONE, + DP_HEADER, + DP_AMBE, + DP_POLL, + DP_CONNECT +}; + +class CDPlusProtocolHandler { +public: + CDPlusProtocolHandler(unsigned int port, const wxString& addr = wxEmptyString); + ~CDPlusProtocolHandler(); + + bool open(); + + unsigned int getPort() const; + + bool writeHeader(const CHeaderData& header); + bool writeAMBE(const CAMBEData& data); + bool writeConnect(const CConnectData& connect); + bool writePoll(const CPollData& poll); + + DPLUS_TYPE read(); + CHeaderData* readHeader(); + CAMBEData* readAMBE(); + CPollData* readPoll(); + CConnectData* readConnect(); + + void close(); + +private: + CUDPReaderWriter m_socket; + DPLUS_TYPE m_type; + unsigned char* m_buffer; + unsigned int m_length; + in_addr m_yourAddress; + unsigned int m_yourPort; + unsigned int m_myPort; + + bool readPackets(); +}; + +#endif diff --git a/Common/DPlusProtocolHandlerPool.cpp b/Common/DPlusProtocolHandlerPool.cpp new file mode 100644 index 0000000..d1d50a2 --- /dev/null +++ b/Common/DPlusProtocolHandlerPool.cpp @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2012,2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "DPlusProtocolHandlerPool.h" + +CDPlusProtocolHandlerPool::CDPlusProtocolHandlerPool(unsigned int n, unsigned int port, const wxString& addr) : +m_pool(NULL), +m_n(n), +m_index(0U) +{ + wxASSERT(port > 0U); + wxASSERT(n > 0U); + + m_pool = new CDPlusProtocolHandlerEntry[n]; + + for (unsigned int i = 0U; i < n; i++) { + m_pool[i].m_handler = new CDPlusProtocolHandler(port + i, addr); + m_pool[i].m_port = port + i; + m_pool[i].m_inUse = false; + } + + wxLogMessage(wxT("Allocated UDP ports %u-%u to D-Plus"), port, port + n - 1U); +} + +CDPlusProtocolHandlerPool::~CDPlusProtocolHandlerPool() +{ + for (unsigned int i = 0U; i < m_n; i++) + delete m_pool[i].m_handler; + + delete[] m_pool; +} + +bool CDPlusProtocolHandlerPool::open() +{ + for (unsigned int i = 0U; i < m_n; i++) { + bool ret = m_pool[i].m_handler->open(); + if (!ret) + return false; + } + + return true; +} + +CDPlusProtocolHandler* CDPlusProtocolHandlerPool::getHandler(unsigned int port) +{ + if (port == 0U) { + for (unsigned int i = 0U; i < m_n; i++) { + if (!m_pool[i].m_inUse) { + m_pool[i].m_inUse = true; + return m_pool[i].m_handler; + } + } + } else { + for (unsigned int i = 0U; i < m_n; i++) { + if (m_pool[i].m_port == port) { + m_pool[i].m_inUse = true; + return m_pool[i].m_handler; + } + } + } + + wxLogError(wxT("Cannot find a free D-Plus port in the pool")); + + return NULL; +} + +void CDPlusProtocolHandlerPool::release(CDPlusProtocolHandler* handler) +{ + wxASSERT(handler != NULL); + + for (unsigned int i = 0U; i < m_n; i++) { + if (m_pool[i].m_handler == handler && m_pool[i].m_inUse) { + m_pool[i].m_inUse = false; + return; + } + } + + wxLogError(wxT("Trying to release an unused D-Plus port")); +} + +DPLUS_TYPE CDPlusProtocolHandlerPool::read() +{ + while (m_index < m_n) { + if (m_pool[m_index].m_inUse) { + DPLUS_TYPE type = m_pool[m_index].m_handler->read(); + if (type != DP_NONE) + return type; + } + + m_index++; + } + + m_index = 0U; + + return DP_NONE; +} + +CHeaderData* CDPlusProtocolHandlerPool::readHeader() +{ + return m_pool[m_index].m_handler->readHeader(); +} + +CAMBEData* CDPlusProtocolHandlerPool::readAMBE() +{ + return m_pool[m_index].m_handler->readAMBE(); +} + +CPollData* CDPlusProtocolHandlerPool::readPoll() +{ + return m_pool[m_index].m_handler->readPoll(); +} + +CConnectData* CDPlusProtocolHandlerPool::readConnect() +{ + return m_pool[m_index].m_handler->readConnect(); +} + +void CDPlusProtocolHandlerPool::close() +{ + for (unsigned int i = 0U; i < m_n; i++) + m_pool[i].m_handler->close(); +} diff --git a/Common/DPlusProtocolHandlerPool.h b/Common/DPlusProtocolHandlerPool.h new file mode 100644 index 0000000..b6c14fb --- /dev/null +++ b/Common/DPlusProtocolHandlerPool.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2012,2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef DPlusProtocolHandlerPool_H +#define DPlusProtocolHandlerPool_H + +#include + +#include "DPlusProtocolHandler.h" + +class CDPlusProtocolHandlerEntry { +public: + CDPlusProtocolHandler* m_handler; + unsigned int m_port; + bool m_inUse; +}; + +class CDPlusProtocolHandlerPool { +public: + CDPlusProtocolHandlerPool(unsigned int n, unsigned int port, const wxString& addr = wxEmptyString); + ~CDPlusProtocolHandlerPool(); + + bool open(); + + CDPlusProtocolHandler* getHandler(unsigned int port = 0U); + void release(CDPlusProtocolHandler* handler); + + DPLUS_TYPE read(); + CHeaderData* readHeader(); + CAMBEData* readAMBE(); + CPollData* readPoll(); + CConnectData* readConnect(); + + void close(); + +private: + CDPlusProtocolHandlerEntry* m_pool; + unsigned int m_n; + unsigned int m_index; +}; + +#endif diff --git a/Common/DRATSServer.cpp b/Common/DRATSServer.cpp new file mode 100644 index 0000000..bfb4b1a --- /dev/null +++ b/Common/DRATSServer.cpp @@ -0,0 +1,375 @@ +/* + * Copyright (C) 2011-2015 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "DStarDefines.h" +#include "DRATSServer.h" +#include "Utils.h" + +// #define LOOPBACK + +const unsigned int BUFFER_LENGTH = 30000U; + +CDRATSServer::CDRATSServer(const wxString& address, unsigned int port, const wxString& callsign, IRepeaterCallback* handler) : +wxThread(wxTHREAD_JOINABLE), +m_address(address), +m_port(port), +m_callsign(callsign), +m_handler(handler), +m_socket(NULL), +m_stopped(false), +m_readState(SS_FIRST), +m_readBuffer(NULL), +m_readLength(0U), +m_readPos(0U), +m_readEnd(false), +m_writeText(NULL), +m_writeState(SS_FIRST), +m_writeBuffer(NULL), +m_writeLength(0U) +{ + wxASSERT(handler != NULL); + wxASSERT(port > 0U); + + m_readBuffer = new unsigned char[BUFFER_LENGTH]; + m_writeBuffer = new unsigned char[BUFFER_LENGTH]; + m_writeText = new unsigned char[6U]; +} + +CDRATSServer::~CDRATSServer() +{ + delete[] m_readBuffer; + delete[] m_writeBuffer; + delete[] m_writeText; +} + +bool CDRATSServer::open() +{ + m_socket = new CTCPReaderWriterServer(m_address, m_port); + bool ret = m_socket->start(); + if (!ret) { + delete m_socket; + m_socket = NULL; + return false; + } + + Create(); + Run(); + + return true; +} + +void CDRATSServer::writeHeader(const CHeaderData&) +{ + m_writeState = SS_FIRST; + + if (m_writeLength > 0U && m_socket != NULL) { + CUtils::dump(wxT("From RF"), m_writeBuffer, m_writeLength); + m_socket->write(m_writeBuffer, m_writeLength); + } + + m_writeLength = 0U; +} + +void CDRATSServer::writeData(const CAMBEData& data) +{ + // Sync data isn't sent on + if (data.isSync()) { + m_writeState = SS_FIRST; + return; + } + + if (data.isEnd()) { + if (m_writeLength > 0U && m_socket != NULL) { + CUtils::dump(wxT("From RF"), m_writeBuffer, m_writeLength); + m_socket->write(m_writeBuffer, m_writeLength); + } + + m_writeLength = 0U; + return; + } + + unsigned char buffer[DV_FRAME_MAX_LENGTH_BYTES]; + unsigned int length = data.getData(buffer, DV_FRAME_MAX_LENGTH_BYTES); + + if (length != DV_FRAME_LENGTH_BYTES) + return; + + unsigned char byte1 = buffer[VOICE_FRAME_LENGTH_BYTES + 0U] ^ SCRAMBLER_BYTE1; + unsigned char byte2 = buffer[VOICE_FRAME_LENGTH_BYTES + 1U] ^ SCRAMBLER_BYTE2; + unsigned char byte3 = buffer[VOICE_FRAME_LENGTH_BYTES + 2U] ^ SCRAMBLER_BYTE3; + + switch (m_writeState) { + case SS_FIRST: + m_writeText[0U] = byte1; + m_writeText[1U] = byte2; + m_writeText[2U] = byte3; + m_writeState = SS_SECOND; + return; + + case SS_SECOND: + m_writeText[3U] = byte1; + m_writeText[4U] = byte2; + m_writeText[5U] = byte3; + m_writeState = SS_FIRST; + break; + } + + if ((m_writeText[0U] & SLOW_DATA_TYPE_MASK) != SLOW_DATA_TYPE_GPS) + return; + + length = m_writeText[0U] & 0x07; // Maximum value of 5 + if (length > 5U) + length = 5U; + + for (unsigned int i = 0U; i < length; i++) { + m_writeBuffer[m_writeLength++] = m_writeText[i + 1U]; + + // Check for [EOB] in the buffer to signal the end of the D-RATS data. + // To allow strstr() to run correctly + m_writeBuffer[m_writeLength] = 0x00U; + + if (::strstr((char*)m_writeBuffer, "[EOB]") != NULL) { + if (m_socket != NULL) { + CUtils::dump(wxT("From RF"), m_writeBuffer, m_writeLength); + m_socket->write(m_writeBuffer, m_writeLength); + } + + m_writeLength = 0U; + } + } +} + +void CDRATSServer::writeEnd() +{ + if (m_writeLength > 0U && m_socket != NULL) { + CUtils::dump(wxT("From RF"), m_writeBuffer, m_writeLength); + m_socket->write(m_writeBuffer, m_writeLength); + } + + m_writeLength = 0U; +} + +void* CDRATSServer::Entry() +{ + wxLogMessage(wxT("Starting the D-RATS Server thread for %s"), m_callsign.c_str()); + + bool sending = false; + unsigned int id = 0U; + + unsigned char seqNo = 0U; + unsigned int sent = 0U; + + wxStopWatch time; + + try { + while (!m_stopped) { + serviceSocket(); + + if (m_readEnd && !sending) { + id = CHeaderData::createId(); + + // Write header + CHeaderData header; + header.setMyCall1(m_callsign); + header.setMyCall2(wxT("DATA")); + header.setYourCall(wxT("CQCQCQ ")); + header.setId(id); + +#if defined(LOOPBACK) + writeHeader(header); +#else + m_handler->process(header, DIR_INCOMING, AS_DRATS); +#endif + + m_readState = SS_FIRST; + m_readPos = 0U; + sending = true; + seqNo = 0U; + sent = 0U; + + time.Start(); + } + + if (m_readEnd && sending) { + unsigned int needed = time.Time() / DSTAR_FRAME_TIME_MS; + + while (sent < needed && sending) { + // Write AMBE data + CAMBEData data; + data.setId(id); + + unsigned char buffer[DV_FRAME_LENGTH_BYTES]; + ::memcpy(buffer + 0U, NULL_AMBE_DATA_BYTES, VOICE_FRAME_LENGTH_BYTES); + + // Insert sync bytes when the sequence number is zero, slow data otherwise + if (seqNo == 0U) { + ::memcpy(buffer + VOICE_FRAME_LENGTH_BYTES, DATA_SYNC_BYTES, DATA_FRAME_LENGTH_BYTES); + m_readState = SS_FIRST; + } else { + if (m_readState == SS_FIRST) { + unsigned char readText[3U]; + ::memset(readText, 'f', 3U); + + unsigned int length = m_readLength - m_readPos; + unsigned char bytes = 5U; + if (length < 5U) + bytes = length; + + readText[0U] = SLOW_DATA_TYPE_GPS | bytes; + + for (unsigned int i = 0U; i < 2U && m_readPos < m_readLength; i++) + readText[i + 1U] = m_readBuffer[m_readPos++]; + + readText[0U] ^= SCRAMBLER_BYTE1; + readText[1U] ^= SCRAMBLER_BYTE2; + readText[2U] ^= SCRAMBLER_BYTE3; + + ::memcpy(buffer + VOICE_FRAME_LENGTH_BYTES, readText, DATA_FRAME_LENGTH_BYTES); + + m_readState = SS_SECOND; + } else { + unsigned char readText[3U]; + ::memset(readText, 'f', 3U); + + for (unsigned int i = 0U; i < 3U && m_readPos < m_readLength; i++) + readText[i] = m_readBuffer[m_readPos++]; + + readText[0U] ^= SCRAMBLER_BYTE1; + readText[1U] ^= SCRAMBLER_BYTE2; + readText[2U] ^= SCRAMBLER_BYTE3; + + ::memcpy(buffer + VOICE_FRAME_LENGTH_BYTES, readText, DATA_FRAME_LENGTH_BYTES); + + m_readState = SS_FIRST; + } + } + + data.setSeq(seqNo); + data.setData(buffer, DV_FRAME_LENGTH_BYTES); + sent++; + +#if defined(LOOPBACK) + writeData(data); +#else + m_handler->process(data, DIR_INCOMING, AS_DRATS); +#endif + if (m_readPos == m_readLength) { + if (m_readState == SS_SECOND) { + seqNo++; + if (seqNo == 21U) + seqNo = 0U; + + unsigned char readText[3U]; + readText[0U] = 'f' ^ SCRAMBLER_BYTE1; + readText[1U] = 'f' ^ SCRAMBLER_BYTE2; + readText[2U] = 'f' ^ SCRAMBLER_BYTE3; + + ::memcpy(buffer + VOICE_FRAME_LENGTH_BYTES, readText, DATA_FRAME_LENGTH_BYTES); + + data.setSeq(seqNo); + data.setData(buffer, DV_FRAME_LENGTH_BYTES); + sent++; +#if defined(LOOPBACK) + writeData(data); +#else + m_handler->process(data, DIR_INCOMING, AS_DRATS); +#endif + } + + seqNo++; + if (seqNo == 21U) + seqNo = 0U; + + if (seqNo == 0U) + ::memcpy(buffer + VOICE_FRAME_LENGTH_BYTES, DATA_SYNC_BYTES, DATA_FRAME_LENGTH_BYTES); + else + ::memcpy(buffer + VOICE_FRAME_LENGTH_BYTES, NULL_SLOW_DATA_BYTES, DATA_FRAME_LENGTH_BYTES); + + data.setData(buffer, DV_FRAME_LENGTH_BYTES); + data.setSeq(seqNo); + data.setEnd(true); + sent++; +#if defined(LOOPBACK) + writeData(data); +#else + m_handler->process(data, DIR_INCOMING, AS_DRATS); +#endif + m_readLength = 0U; + m_readPos = 0U; + m_readEnd = false; + sending = false; + sent = 0U; + } + + seqNo++; + if (seqNo == 21U) + seqNo = 0U; + } + } + + // 50ms + Sleep(50UL); + } + + if (m_socket != NULL) + m_socket->stop(); + } + catch (std::exception& e) { + wxString message(e.what(), wxConvLocal); + wxLogError(wxT("Exception raised in the D-RATS Server thread - \"%s\""), message.c_str()); + } + catch (...) { + wxLogError(wxT("Unknown exception raised in the D-RATS Server thread")); + } + + wxLogMessage(wxT("Stopping the D-RATS Server thread for %s"), m_callsign.c_str()); + + return NULL; +} + +void CDRATSServer::close() +{ + m_stopped = true; + + Wait(); +} + +void CDRATSServer::serviceSocket() +{ + if (m_socket == NULL) { + m_readLength = 0U; + m_readPos = 0U; + m_readEnd = false; + return; + } + + int len = m_socket->read(m_readBuffer + m_readLength, BUFFER_LENGTH - m_readLength, 0U); + if (len > 0) { + m_readLength += len; + + if (!m_readEnd) { + // To allow strstr() to run correctly + m_readBuffer[m_readLength] = 0x00U; + + if (::strstr((char*)m_readBuffer, "[EOB]") != NULL) { + CUtils::dump(wxT("To RF"), m_readBuffer, m_readLength); + m_readEnd = true; + } + } + } +} diff --git a/Common/DRATSServer.h b/Common/DRATSServer.h new file mode 100644 index 0000000..d54166a --- /dev/null +++ b/Common/DRATSServer.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2011,2012 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef DRATSServer_H +#define DRATSServer_H + +#include "TCPReaderWriterServer.h" +#include "RepeaterCallback.h" +#include "HeaderData.h" +#include "AMBEData.h" +#include "Defs.h" + +#include + +class CDRATSServer : public wxThread { +public: + CDRATSServer(const wxString& address, unsigned int port, const wxString& callsign, IRepeaterCallback* handler); + virtual ~CDRATSServer(); + + virtual bool open(); + + virtual void writeHeader(const CHeaderData& header); + virtual void writeData(const CAMBEData& data); + virtual void writeEnd(); + + virtual void close(); + + virtual void* Entry(); + +private: + wxString m_address; + unsigned int m_port; + wxString m_callsign; + IRepeaterCallback* m_handler; + CTCPReaderWriterServer* m_socket; + bool m_stopped; + SLOWDATA_STATE m_readState; + unsigned char* m_readBuffer; + unsigned int m_readLength; + unsigned int m_readPos; + bool m_readEnd; + unsigned char* m_writeText; + SLOWDATA_STATE m_writeState; + unsigned char* m_writeBuffer; + unsigned int m_writeLength; + + void serviceSocket(); +}; + +#endif diff --git a/Common/DStarDefines.h b/Common/DStarDefines.h new file mode 100644 index 0000000..8ea9ae6 --- /dev/null +++ b/Common/DStarDefines.h @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2009-2015 by Jonathan Naylor, G4KLX + * + * 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 + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef DStarDefines_H +#define DStarDefines_H + +#include + +const unsigned int DSTAR_GMSK_SYMBOL_RATE = 4800U; +const float DSTAR_GMSK_BT = 0.5F; + +const bool BIT_SYNC_BITS[] = {true, false, true, false}; +const unsigned int BIT_SYNC_LENGTH_BITS = 4U; + +const bool FRAME_SYNC_BITS[] = {true, true, true, false, true, true, false, false, + true, false, true, false, false, false, false}; +const unsigned int FRAME_SYNC_LENGTH_BITS = 15U; + +const unsigned char DATA_SYNC_BYTES[] = {0x55, 0x2D, 0x16}; +const bool DATA_SYNC_BITS[] = {true, false, true, false, true, false, true, false, + true, false, true, true, false, true, false, false, + false, true, true, false, true, false, false, false}; + +const unsigned char END_PATTERN_BYTES[] = {0x55, 0x55, 0x55, 0x55, 0xC8, 0x7A, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; +const bool END_PATTERN_BITS[] = {true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, + false, false, false, true, false, false, true, true, + false, true, false, true, true, true, true, false}; +const unsigned int END_PATTERN_LENGTH_BITS = 48U; +const unsigned int END_PATTERN_LENGTH_BYTES = END_PATTERN_LENGTH_BITS / 8U; + +const unsigned char NULL_AMBE_DATA_BYTES[] = {0x9E, 0x8D, 0x32, 0x88, 0x26, 0x1A, 0x3F, 0x61, 0xE8}; +const bool NULL_AMBE_DATA_BITS[] = {false, true, true, true, true, false, false, true, + true, false, true, true, false, false, false, true, + false, true, false, false, true, true, false, false, + false, false, false, true, false, false, false, true, + false, true, true, false, false, true, false, false, + false, true, false, true, true, false, false, false, + true, true, true, true, true, true, false, false, + true, false, false, false, false, true, true, false, + false, false, false, true, false, true, true, true}; + +// Note that these are already scrambled, 0x66 0x66 0x66 otherwise +const unsigned char NULL_SLOW_DATA_BYTES[] = {0x16, 0x29, 0xF5}; +const bool NULL_SLOW_DATA_BITS[] = {false, true, true, false, true, false, false, false, + true, false, false, true, false, true, false, false, + true, false, true, false, true, true, true, true}; + +const unsigned int VOICE_FRAME_LENGTH_BITS = 72U; +const unsigned int VOICE_FRAME_LENGTH_BYTES = VOICE_FRAME_LENGTH_BITS / 8U; + +const unsigned int DATA_FRAME_LENGTH_BITS = 24U; +const unsigned int DATA_FRAME_LENGTH_BYTES = DATA_FRAME_LENGTH_BITS / 8U; + +const unsigned int DV_FRAME_LENGTH_BITS = VOICE_FRAME_LENGTH_BITS + DATA_FRAME_LENGTH_BITS; +const unsigned int DV_FRAME_LENGTH_BYTES = VOICE_FRAME_LENGTH_BYTES + DATA_FRAME_LENGTH_BYTES; + +// The length of the end frame, three bytes extra +const unsigned int DV_FRAME_MAX_LENGTH_BITS = DV_FRAME_LENGTH_BITS + 24U; +const unsigned int DV_FRAME_MAX_LENGTH_BYTES = DV_FRAME_MAX_LENGTH_BITS / 8U; + +const unsigned int FEC_SECTION_LENGTH_BITS = 660U; + +const unsigned int RADIO_HEADER_LENGTH_BITS = 330U; +const unsigned int RADIO_HEADER_LENGTH_BYTES = 41U; + +const unsigned int DATA_BLOCK_SIZE_BITS = 21U * DV_FRAME_LENGTH_BITS; +const unsigned int DATA_BLOCK_SIZE_BYTES = 21U * DV_FRAME_LENGTH_BYTES; + +const unsigned int LONG_CALLSIGN_LENGTH = 8U; +const unsigned int SHORT_CALLSIGN_LENGTH = 4U; + +const unsigned char SLOW_DATA_TYPE_MASK = 0xF0U; +const unsigned char SLOW_DATA_TYPE_GPS = 0x30U; +const unsigned char SLOW_DATA_TYPE_TEXT = 0x40U; +const unsigned char SLOW_DATA_TYPE_HEADER = 0x50U; + +const unsigned char DATA_MASK = 0x80U; +const unsigned char REPEATER_MASK = 0x40U; +const unsigned char INTERRUPTED_MASK = 0x20U; +const unsigned char CONTROL_SIGNAL_MASK = 0x10U; +const unsigned char URGENT_MASK = 0x08U; + +const unsigned char REPEATER_CONTROL_MASK = 0x07U; +const unsigned char REPEATER_CONTROL = 0x07U; +const unsigned char AUTO_REPLY = 0x06U; +const unsigned char RESEND_REQUESTED = 0x04U; +const unsigned char ACK_FLAG = 0x03U; +const unsigned char NO_RESPONSE = 0x02U; +const unsigned char RELAY_UNAVAILABLE = 0x01U; + +const unsigned int DSTAR_FRAME_TIME_MS = 20U; +const unsigned int DSTAR_FRAMES_PER_SEC = 50U; + +const unsigned char SCRAMBLER_BYTE1 = 0x70U; +const unsigned char SCRAMBLER_BYTE2 = 0x4FU; +const unsigned char SCRAMBLER_BYTE3 = 0x93U; + +const unsigned int DPLUS_PORT = 20001U; +const unsigned int DEXTRA_PORT = 30001U; +const unsigned int DCS_PORT = 30051U; +const unsigned int CCS_PORT = 30062U; // Port for CCS7 +const unsigned int G2_DV_PORT = 40000U; +const unsigned int G2_DD_PORT = 40001U; + +const unsigned int NETWORK_TIMEOUT = 2U; // Network timeout for G2, CCS, DCS, DExtra, and D-Plus +const unsigned int REPEATER_TIMEOUT = 2U; // Repeater timeout +const unsigned int REPLY_TIME = 2U; // The turnaround time for version, echo, audio prompts + +enum DSTAR_PROTOCOL { + DP_UNKNOWN, + DP_LOOPBACK, + DP_DEXTRA, + DP_DPLUS, + DP_DCS +}; + +enum AUDIO_SOURCE { + AS_G2, + AS_ECHO, + AS_INFO, + AS_XBAND, + AS_DRATS, + AS_DPLUS, + AS_DEXTRA, + AS_DCS, + AS_DUP, + AS_VERSION, + AS_CCS +}; + +enum DSTAR_RX_STATE { + DSRXS_LISTENING, + DSRXS_PROCESS_HEADER, + DSRXS_PROCESS_DATA, + DSRXS_PROCESS_SLOW_DATA +}; + +enum DSTAR_RPT_STATE { + DSRS_SHUTDOWN, + DSRS_LISTENING, + DSRS_VALID, + DSRS_VALID_WAIT, + DSRS_INVALID, + DSRS_INVALID_WAIT, + DSRS_TIMEOUT, + DSRS_TIMEOUT_WAIT, + DSRS_NETWORK +}; + +enum NETWORK_TYPE { + NETWORK_NONE, + NETWORK_HEADER, + NETWORK_DATA, + NETWORK_TEXT +}; + +enum DSTAR_MODE { + MODE_DUPLEX, + MODE_SIMPLEX, + MODE_GATEWAY +}; + +#endif diff --git a/Common/DTMF.cpp b/Common/DTMF.cpp new file mode 100644 index 0000000..a05cbed --- /dev/null +++ b/Common/DTMF.cpp @@ -0,0 +1,317 @@ +/* + * Copyright (C) 2012,2013,2015 by Jonathan Naylor G4KLX + * Copyright (C) 2011 by DV Developer Group. DJ0ABR + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "DTMF.h" + +const unsigned char DTMF_MASK[] = {0x82U, 0x08U, 0x20U, 0x82U, 0x00U, 0x00U, 0x82U, 0x00U, 0x00U}; +const unsigned char DTMF_SIG[] = {0x82U, 0x08U, 0x20U, 0x82U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U}; + +const unsigned char DTMF_SYM_MASK[] = {0x10U, 0x40U, 0x08U, 0x20U}; +const unsigned char DTMF_SYM0[] = {0x00U, 0x40U, 0x08U, 0x20U}; +const unsigned char DTMF_SYM1[] = {0x00U, 0x00U, 0x00U, 0x00U}; +const unsigned char DTMF_SYM2[] = {0x00U, 0x40U, 0x00U, 0x00U}; +const unsigned char DTMF_SYM3[] = {0x10U, 0x00U, 0x00U, 0x00U}; +const unsigned char DTMF_SYM4[] = {0x00U, 0x00U, 0x00U, 0x20U}; +const unsigned char DTMF_SYM5[] = {0x00U, 0x40U, 0x00U, 0x20U}; +const unsigned char DTMF_SYM6[] = {0x10U, 0x00U, 0x00U, 0x20U}; +const unsigned char DTMF_SYM7[] = {0x00U, 0x00U, 0x08U, 0x00U}; +const unsigned char DTMF_SYM8[] = {0x00U, 0x40U, 0x08U, 0x00U}; +const unsigned char DTMF_SYM9[] = {0x10U, 0x00U, 0x08U, 0x00U}; +const unsigned char DTMF_SYMA[] = {0x10U, 0x40U, 0x00U, 0x00U}; +const unsigned char DTMF_SYMB[] = {0x10U, 0x40U, 0x00U, 0x20U}; +const unsigned char DTMF_SYMC[] = {0x10U, 0x40U, 0x08U, 0x00U}; +const unsigned char DTMF_SYMD[] = {0x10U, 0x40U, 0x08U, 0x20U}; +const unsigned char DTMF_SYMS[] = {0x00U, 0x00U, 0x08U, 0x20U}; +const unsigned char DTMF_SYMH[] = {0x10U, 0x00U, 0x08U, 0x20U}; + +CDTMF::CDTMF() : +m_data(), +m_command(), +m_pressed(false), +m_releaseCount(0U), +m_pressCount(0U), +m_lastChar(wxT(' ')) +{ +} + +CDTMF::~CDTMF() +{ +} + +bool CDTMF::decode(const unsigned char* ambe, bool end) +{ + // DTMF begins with these byte values + if (!end && (ambe[0] & DTMF_MASK[0]) == DTMF_SIG[0] && (ambe[1] & DTMF_MASK[1]) == DTMF_SIG[1] && + (ambe[2] & DTMF_MASK[2]) == DTMF_SIG[2] && (ambe[3] & DTMF_MASK[3]) == DTMF_SIG[3] && + (ambe[4] & DTMF_MASK[4]) == DTMF_SIG[4] && (ambe[5] & DTMF_MASK[5]) == DTMF_SIG[5] && + (ambe[6] & DTMF_MASK[6]) == DTMF_SIG[6] && (ambe[7] & DTMF_MASK[7]) == DTMF_SIG[7] && + (ambe[8] & DTMF_MASK[8]) == DTMF_SIG[8]) { + unsigned char sym0 = ambe[4] & DTMF_SYM_MASK[0]; + unsigned char sym1 = ambe[5] & DTMF_SYM_MASK[1]; + unsigned char sym2 = ambe[7] & DTMF_SYM_MASK[2]; + unsigned char sym3 = ambe[8] & DTMF_SYM_MASK[3]; + + wxChar c = wxT(' '); + if (sym0 == DTMF_SYM0[0] && sym1 == DTMF_SYM0[1] && sym2 == DTMF_SYM0[2] && sym3 == DTMF_SYM0[3]) + c = wxT('0'); + else if (sym0 == DTMF_SYM1[0] && sym1 == DTMF_SYM1[1] && sym2 == DTMF_SYM1[2] && sym3 == DTMF_SYM1[3]) + c = wxT('1'); + else if (sym0 == DTMF_SYM2[0] && sym1 == DTMF_SYM2[1] && sym2 == DTMF_SYM2[2] && sym3 == DTMF_SYM2[3]) + c = wxT('2'); + else if (sym0 == DTMF_SYM3[0] && sym1 == DTMF_SYM3[1] && sym2 == DTMF_SYM3[2] && sym3 == DTMF_SYM3[3]) + c = wxT('3'); + else if (sym0 == DTMF_SYM4[0] && sym1 == DTMF_SYM4[1] && sym2 == DTMF_SYM4[2] && sym3 == DTMF_SYM4[3]) + c = wxT('4'); + else if (sym0 == DTMF_SYM5[0] && sym1 == DTMF_SYM5[1] && sym2 == DTMF_SYM5[2] && sym3 == DTMF_SYM5[3]) + c = wxT('5'); + else if (sym0 == DTMF_SYM6[0] && sym1 == DTMF_SYM6[1] && sym2 == DTMF_SYM6[2] && sym3 == DTMF_SYM6[3]) + c = wxT('6'); + else if (sym0 == DTMF_SYM7[0] && sym1 == DTMF_SYM7[1] && sym2 == DTMF_SYM7[2] && sym3 == DTMF_SYM7[3]) + c = wxT('7'); + else if (sym0 == DTMF_SYM8[0] && sym1 == DTMF_SYM8[1] && sym2 == DTMF_SYM8[2] && sym3 == DTMF_SYM8[3]) + c = wxT('8'); + else if (sym0 == DTMF_SYM9[0] && sym1 == DTMF_SYM9[1] && sym2 == DTMF_SYM9[2] && sym3 == DTMF_SYM9[3]) + c = wxT('9'); + else if (sym0 == DTMF_SYMA[0] && sym1 == DTMF_SYMA[1] && sym2 == DTMF_SYMA[2] && sym3 == DTMF_SYMA[3]) + c = wxT('A'); + else if (sym0 == DTMF_SYMB[0] && sym1 == DTMF_SYMB[1] && sym2 == DTMF_SYMB[2] && sym3 == DTMF_SYMB[3]) + c = wxT('B'); + else if (sym0 == DTMF_SYMC[0] && sym1 == DTMF_SYMC[1] && sym2 == DTMF_SYMC[2] && sym3 == DTMF_SYMC[3]) + c = wxT('C'); + else if (sym0 == DTMF_SYMD[0] && sym1 == DTMF_SYMD[1] && sym2 == DTMF_SYMD[2] && sym3 == DTMF_SYMD[3]) + c = wxT('D'); + else if (sym0 == DTMF_SYMS[0] && sym1 == DTMF_SYMS[1] && sym2 == DTMF_SYMS[2] && sym3 == DTMF_SYMS[3]) + c = wxT('*'); + else if (sym0 == DTMF_SYMH[0] && sym1 == DTMF_SYMH[1] && sym2 == DTMF_SYMH[2] && sym3 == DTMF_SYMH[3]) + c = wxT('#'); + + if (c == m_lastChar) { + m_pressCount++; + } else { + m_lastChar = c; + m_pressCount = 0U; + } + + if (c != wxT(' ') && !m_pressed && m_pressCount >= 3U) { + m_data.Append(c); + m_releaseCount = 0U; + m_pressed = true; + } + + return c != wxT(' '); + } else { + // If it is not a DTMF Code + if ((end || m_releaseCount >= 100U) && m_data.Len() > 0U) { + m_command = m_data; + m_data.Clear(); + m_releaseCount = 0U; + } + + m_pressed = false; + m_releaseCount++; + m_pressCount = 0U; + m_lastChar = wxT(' '); + + return false; + } +} + +bool CDTMF::hasCommand() const +{ + return !m_command.IsEmpty(); +} + +// DTMF to YOUR call command +wxString CDTMF::translate() +{ + wxString command = m_command; + m_command.Clear(); + + if (command.IsEmpty()) + return wxEmptyString; + + if (command.IsSameAs(wxT("#"))) + return wxT(" U"); + + if (command.IsSameAs(wxT("0"))) + return wxT(" I"); + + if (command.IsSameAs(wxT("A"))) + return wxT("CA "); + + if (command.IsSameAs(wxT("00"))) + return wxT(" I"); + + if (command.IsSameAs(wxT("**"))) + return wxT(" L"); + + if (command.GetChar(0U) == wxT('*')) + return processReflector(wxT("REF"), command.Mid(1U)); + else if (command.GetChar(0U) == wxT('B')) + return processReflector(wxT("XRF"), command.Mid(1U)); + else if (command.GetChar(0U) == wxT('D')) + return processReflector(wxT("DCS"), command.Mid(1U)); + else + return processCCS(command); +} + +void CDTMF::reset() +{ + m_data.Clear(); + m_command.Clear(); + m_pressed = false; + m_pressCount = 0U; + m_releaseCount = 0U; + m_lastChar = wxT(' '); +} + +wxString CDTMF::processReflector(const wxString& prefix, const wxString& command) const +{ + unsigned int len = command.Len(); + + wxChar c = command.GetChar(len - 1U); + if (c == wxT('A') || c == wxT('B') || c == wxT('C') || c == wxT('D')) { + if (len < 2U || len > 4U) + return wxEmptyString; + + unsigned long n; + command.Left(len - 1U).ToULong(&n); + if (n == 0UL) + return wxEmptyString; + + wxString out; + out.Printf(wxT("%s%03lu%cL"), prefix.c_str(), n, c); + + return out; + } else { + if (len < 3U || len > 5U) + return wxEmptyString; + + unsigned long n1; + command.Left(len - 2U).ToULong(&n1); + if (n1 == 0UL) + return wxEmptyString; + + unsigned long n2; + command.Right(2U).ToULong(&n2); + if (n2 == 0UL || n2 > 26UL) + return wxEmptyString; + + c = wxT('A') + n2 - 1UL; + + wxString out; + out.Printf(wxT("%s%03lu%cL"), prefix.c_str(), n1, c); + + return out; + } +} + +wxString CDTMF::processCCS(const wxString& command) const +{ + unsigned int len = command.Len(); + + wxString out = wxEmptyString; + + switch (len) { + case 3U: { + // CCS7 for local repeater without band + unsigned long n; + command.ToULong(&n); + if (n == 0UL) + return wxEmptyString; + out.Printf(wxT("C%03lu "), n); + } + break; + case 4U: { + wxChar c = command.GetChar(3U); + if (c == wxT('A') || c == wxT('B') || c == wxT('C') || c == wxT('D')) { + // CCS7 for local repeater with band + unsigned long n; + command.Mid(0U, 3U).ToULong(&n); + if (n == 0UL) + return wxEmptyString; + out.Printf(wxT("C%03lu%c "), n, c); + } else { + // CCS7 for local user + unsigned long n; + command.ToULong(&n); + if (n == 0UL) + return wxEmptyString; + out.Printf(wxT("C%04lu "), n); + } + } + break; + case 5U: { + wxChar c = command.GetChar(4U); + if (c == wxT('A') || c == wxT('B') || c == wxT('C') || c == wxT('D')) { + // CCS7 for local hostspot with band + unsigned long n; + command.Mid(0U, 4U).ToULong(&n); + if (n == 0UL) + return wxEmptyString; + out.Printf(wxT("C%04lu%c "), n, c); + } + } + break; + case 6U: { + // CCS7 for full repeater without band + unsigned long n; + command.ToULong(&n); + if (n == 0UL) + return wxEmptyString; + out.Printf(wxT("C%06lu "), n); + } + break; + case 7U: { + wxChar c = command.GetChar(6U); + if (c == wxT('A') || c == wxT('B') || c == wxT('C') || c == wxT('D')) { + // CCS7 for full repeater with band + unsigned long n; + command.Mid(0U, 6U).ToULong(&n); + if (n == 0UL) + return wxEmptyString; + out.Printf(wxT("C%06lu%c"), n, c); + } else { + // CCS7 for full user or CCS7 for full hostpot without band + unsigned long n; + command.ToULong(&n); + if (n == 0UL) + return wxEmptyString; + out.Printf(wxT("C%07lu"), n); + } + } + break; + case 8U: { + wxChar c = command.GetChar(7U); + if (c == wxT('A') || c == wxT('B') || c == wxT('C') || c == wxT('D')) { + // CCS7 for full hotspot with band + unsigned long n; + command.Mid(0U, 7U).ToULong(&n); + if (n == 0UL) + return wxEmptyString; + out.Printf(wxT("C%07lu%c"), n, c); + } + } + break; + default: + break; + } + + return out; +} diff --git a/Common/DTMF.h b/Common/DTMF.h new file mode 100644 index 0000000..71ab364 --- /dev/null +++ b/Common/DTMF.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2012,2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef DTMF_H +#define DTMF_H + +#include + +class CDTMF { +public: + CDTMF(); + ~CDTMF(); + + bool decode(const unsigned char* ambe, bool end); + + bool hasCommand() const; + + wxString translate(); + + void reset(); + +private: + wxString m_data; + wxString m_command; + bool m_pressed; + unsigned int m_releaseCount; + unsigned int m_pressCount; + wxChar m_lastChar; + + wxString processReflector(const wxString& prefix, const wxString& command) const; + wxString processCCS(const wxString& command) const; +}; + +#endif diff --git a/Common/DVTOOLFileReader.cpp b/Common/DVTOOLFileReader.cpp new file mode 100644 index 0000000..4090721 --- /dev/null +++ b/Common/DVTOOLFileReader.cpp @@ -0,0 +1,181 @@ +/* + * Copyright (C) 2009,2013,2014 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "DVTOOLFileReader.h" +#include "DStarDefines.h" + +#include + +static const char DVTOOL_SIGNATURE[] = "DVTOOL"; +static const unsigned int DVTOOL_SIGNATURE_LENGTH = 6U; + +static const char DSVT_SIGNATURE[] = "DSVT"; +static const unsigned int DSVT_SIGNATURE_LENGTH = 4U; + +static const unsigned int FIXED_DATA_LENGTH = 9U; + +static const unsigned char HEADER_FLAG = 0x10; +static const unsigned char DATA_FLAG = 0x20; + +static const unsigned char HEADER_MASK = 0x80; +static const unsigned char TRAILER_MASK = 0x40; + +const unsigned int BUFFER_LENGTH = 255U; + + +CDVTOOLFileReader::CDVTOOLFileReader() : +m_fileName(), +m_file(), +m_records(0U), +m_type(DVTFR_NONE), +m_buffer(NULL), +m_length(0U), +m_seqNo(0U) +{ + m_buffer = new unsigned char[BUFFER_LENGTH]; +} + +CDVTOOLFileReader::~CDVTOOLFileReader() +{ + delete[] m_buffer; +} + +wxString CDVTOOLFileReader::getFileName() const +{ + return m_fileName; +} + +unsigned int CDVTOOLFileReader::getRecords() const +{ + return m_records; +} + +bool CDVTOOLFileReader::open(const wxString& fileName) +{ + m_fileName = fileName; + + bool res = m_file.Open(fileName, wxT("rb")); + if (!res) + return false; + + unsigned char buffer[DVTOOL_SIGNATURE_LENGTH]; + size_t n = m_file.Read(buffer, DVTOOL_SIGNATURE_LENGTH); + if (n != DVTOOL_SIGNATURE_LENGTH) { + m_file.Close(); + return false; + } + + if (::memcmp(buffer, DVTOOL_SIGNATURE, DVTOOL_SIGNATURE_LENGTH) != 0) { + m_file.Close(); + return false; + } + + wxUint32 uint32; + n = m_file.Read(&uint32, sizeof(wxUint32)); + if (n != sizeof(wxUint32)) { + m_file.Close(); + return false; + } + + m_records = wxUINT32_SWAP_ON_LE(uint32); + m_seqNo = 0U; + + return true; +} + +DVTFR_TYPE CDVTOOLFileReader::read() +{ + wxUint16 uint16; + size_t n = m_file.Read(&uint16, sizeof(wxUint16)); + if (n != sizeof(wxUint16)) + return DVTFR_NONE; + + m_length = wxUINT16_SWAP_ON_BE(uint16) - 15U; + + unsigned char bytes[FIXED_DATA_LENGTH]; + n = m_file.Read(bytes, DSVT_SIGNATURE_LENGTH); + if (n != DSVT_SIGNATURE_LENGTH) + return DVTFR_NONE; + + if (::memcmp(bytes, DSVT_SIGNATURE, DSVT_SIGNATURE_LENGTH) != 0) + return DVTFR_NONE; + + char flag; + n = m_file.Read(&flag, 1U); + if (n != 1U) + return DVTFR_NONE; + + m_type = (flag == HEADER_FLAG) ? DVTFR_HEADER : DVTFR_DATA; + + n = m_file.Read(bytes, FIXED_DATA_LENGTH); + if (n != FIXED_DATA_LENGTH) + return DVTFR_NONE; + + n = m_file.Read(&flag, 1U); + if (n != 1U) + return DVTFR_NONE; + + if (m_type == DVTFR_DATA) + m_seqNo = flag; + + n = m_file.Read(m_buffer, m_length); + if (n != m_length) + return DVTFR_NONE; + + return m_type; +} + +CHeaderData* CDVTOOLFileReader::readHeader() +{ + if (m_type != DVTFR_HEADER) + return NULL; + + CHeaderData* header = new CHeaderData; + + if (m_buffer[39U] == 0xFFU && m_buffer[40U] == 0xFFU) { + header->setDVTOOLData(m_buffer, RADIO_HEADER_LENGTH_BYTES, false); + return header; + } + + // Header checksum testing is enabled + bool valid = header->setDVTOOLData(m_buffer, RADIO_HEADER_LENGTH_BYTES, true); + if (!valid) { + delete header; + return NULL; + } + + return header; +} + +CAMBEData* CDVTOOLFileReader::readData() +{ + if (m_type != DVTFR_DATA) + return NULL; + + CAMBEData* data = new CAMBEData; + + data->setData(m_buffer, m_length); + data->setSeq(m_seqNo); + + return data; +} + +void CDVTOOLFileReader::close() +{ + m_file.Close(); +} diff --git a/Common/DVTOOLFileReader.h b/Common/DVTOOLFileReader.h new file mode 100644 index 0000000..e8b9adc --- /dev/null +++ b/Common/DVTOOLFileReader.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2009,2014 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef DVTOOLFileReader_H +#define DVTOOLFileReader_H + +#include "HeaderData.h" +#include "AMBEData.h" + +enum DVTFR_TYPE { + DVTFR_NONE, + DVTFR_HEADER, + DVTFR_DATA +}; + +#include +#include + +class CDVTOOLFileReader { +public: + CDVTOOLFileReader(); + ~CDVTOOLFileReader(); + + wxString getFileName() const; + unsigned int getRecords() const; + + bool open(const wxString& fileName); + + DVTFR_TYPE read(); + + CHeaderData* readHeader(); + CAMBEData* readData(); + + void close(); + +private: + wxString m_fileName; + wxFFile m_file; + wxUint32 m_records; + DVTFR_TYPE m_type; + unsigned char* m_buffer; + unsigned int m_length; + unsigned char m_seqNo; +}; + +#endif diff --git a/Common/Defs.h b/Common/Defs.h new file mode 100644 index 0000000..f2c5c31 --- /dev/null +++ b/Common/Defs.h @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2010-2015 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef Defs_H +#define Defs_H + +#include + +const wxString DEXTRA_HOSTS_FILE_NAME = wxT("DExtra_Hosts.txt"); +const wxString DPLUS_HOSTS_FILE_NAME = wxT("DPlus_Hosts.txt"); +const wxString DCS_HOSTS_FILE_NAME = wxT("DCS_Hosts.txt"); +const wxString CCS_HOSTS_FILE_NAME = wxT("CCS_Hosts.txt"); +const wxString GATEWAY_HOSTS_FILE_NAME = wxT("Gateway_Hosts.txt"); + +const wxString LINKS_BASE_NAME = wxT("Links"); +const wxString TEXT_BASE_NAME = wxT("Text"); +const wxString USERS_BASE_NAME = wxT("Users"); +const wxString STARNET_BASE_NAME = wxT("STARnet"); +const wxString HEADERS_BASE_NAME = wxT("Headers"); +const wxString DDMODE_BASE_NAME = wxT("DDMode"); + +enum RECONNECT { + RECONNECT_NEVER, + RECONNECT_FIXED, + RECONNECT_5MINS, + RECONNECT_10MINS, + RECONNECT_15MINS, + RECONNECT_20MINS, + RECONNECT_25MINS, + RECONNECT_30MINS, + RECONNECT_60MINS, + RECONNECT_90MINS, + RECONNECT_120MINS, + RECONNECT_180MINS +}; + +enum DIRECTION { + DIR_INCOMING, + DIR_OUTGOING +}; + +enum PROTOCOL { + PROTO_DEXTRA, + PROTO_DPLUS, + PROTO_DCS, + PROTO_CCS +}; + +enum HW_TYPE { + HW_HOMEBREW, + HW_ICOM, + HW_DUMMY +}; + +enum TEXT_LANG { + TL_ENGLISH_UK, + TL_DEUTSCH, + TL_DANSK, + TL_FRANCAIS, + TL_ITALIANO, + TL_POLSKI, + TL_ENGLISH_US, + TL_ESPANOL, + TL_SVENSKA, + TL_NEDERLANDS_NL, + TL_NEDERLANDS_BE, + TL_NORSK, + TL_PORTUGUES +}; + +enum IRCDDB_STATUS { + IS_DISABLED, + IS_DISCONNECTED, + IS_CONNECTING, + IS_CONNECTED +}; + +enum G2_STATUS { + G2_NONE, + G2_LOCAL, + G2_USER, + G2_REPEATER, + G2_OK, + G2_XBAND, + G2_ECHO, + G2_VERSION, + G2_STARNET +}; + +enum LINK_STATUS { + LS_NONE, + LS_PENDING_IRCDDB, + LS_LINKING_LOOPBACK, + LS_LINKING_DEXTRA, + LS_LINKING_DPLUS, + LS_LINKING_DCS, + LS_LINKING_CCS, + LS_LINKED_LOOPBACK, + LS_LINKED_DEXTRA, + LS_LINKED_DPLUS, + LS_LINKED_DCS, + LS_LINKED_CCS +}; + +enum SLOWDATA_STATE { + SS_FIRST, + SS_SECOND +}; + +enum STARNET_CALLSIGN_SWITCH { + SCS_GROUP_CALLSIGN, + SCS_USER_CALLSIGN +}; + +enum GATEWAY_TYPE { + GT_REPEATER, + GT_HOTSPOT, + GT_DONGLE, + GT_STARNET +}; + +const unsigned int TIME_PER_TIC_MS = 5U; + +#if defined(__WINDOWS__) +typedef unsigned long in_addr_t; +#endif + +#endif diff --git a/Common/DummyRepeaterProtocolHandler.cpp b/Common/DummyRepeaterProtocolHandler.cpp new file mode 100644 index 0000000..44ae8cb --- /dev/null +++ b/Common/DummyRepeaterProtocolHandler.cpp @@ -0,0 +1,133 @@ +/* + * Copyright (C) 2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "DummyRepeaterProtocolHandler.h" + +#include "DStarDefines.h" +#include "Utils.h" + +CDummyRepeaterProtocolHandler::CDummyRepeaterProtocolHandler() +{ +} + +CDummyRepeaterProtocolHandler::~CDummyRepeaterProtocolHandler() +{ +} + +bool CDummyRepeaterProtocolHandler::open() +{ + return true; +} + +bool CDummyRepeaterProtocolHandler::writeHeader(CHeaderData& header) +{ + unsigned char buffer[50U]; + unsigned int length = header.getHBRepeaterData(buffer, 50U, true); + + wxLogMessage(wxT("Sending Header to port: %u, id: %04X"), header.getYourPort(), header.getId()); + + CUtils::dump(wxT("Data"), buffer + 8U, length - 8U); + + return true; +} + +bool CDummyRepeaterProtocolHandler::writeAMBE(CAMBEData& data) +{ + unsigned char buffer[30U]; + unsigned int length = data.getHBRepeaterData(buffer, 30U); + + wxLogMessage(wxT("Sending AMBE to port: %u, seq: %02X, id: %04X"), data.getYourPort(), data.getSeq(), data.getId()); + + CUtils::dump(wxT("Data"), buffer + 9U, length - 9U); + + return true; +} + +bool CDummyRepeaterProtocolHandler::writeDD(CDDData& data) +{ + unsigned char buffer[2000U]; + unsigned int length = data.getHBRepeaterData(buffer, 2000U); + + CUtils::dump(wxT("DD Data"), buffer, length); + + return true; +} + +bool CDummyRepeaterProtocolHandler::writeText(CTextData& text) +{ + unsigned char buffer[40U]; + unsigned int length = text.getHBRepeaterData(buffer, 40U); + + CUtils::dump(wxT("Sending Text"), buffer, length); + + return true; +} + +bool CDummyRepeaterProtocolHandler::writeStatus(CStatusData& status) +{ + unsigned char buffer[30U]; + unsigned int length = status.getHBRepeaterData(buffer, 30U); + + CUtils::dump(wxT("Sending Status"), buffer, length); + + return true; +} + +REPEATER_TYPE CDummyRepeaterProtocolHandler::read() +{ + return RT_NONE; +} + +CPollData* CDummyRepeaterProtocolHandler::readPoll() +{ + return NULL; +} + +CHeaderData* CDummyRepeaterProtocolHandler::readHeader() +{ + return NULL; +} + +CAMBEData* CDummyRepeaterProtocolHandler::readAMBE() +{ + return NULL; +} + +CHeaderData* CDummyRepeaterProtocolHandler::readBusyHeader() +{ + return NULL; +} + +CAMBEData* CDummyRepeaterProtocolHandler::readBusyAMBE() +{ + return NULL; +} + +CHeardData* CDummyRepeaterProtocolHandler::readHeard() +{ + return NULL; +} + +CDDData* CDummyRepeaterProtocolHandler::readDD() +{ + return NULL; +} + +void CDummyRepeaterProtocolHandler::close() +{ +} diff --git a/Common/DummyRepeaterProtocolHandler.h b/Common/DummyRepeaterProtocolHandler.h new file mode 100644 index 0000000..5fc2a37 --- /dev/null +++ b/Common/DummyRepeaterProtocolHandler.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef DummyRepeaterProtocolHandler_H +#define DummyRepeaterProtocolHandler_H + +#include "RepeaterProtocolHandler.h" +#include "DStarDefines.h" +#include "HeaderData.h" +#include "StatusData.h" +#include "HeardData.h" +#include "AMBEData.h" +#include "TextData.h" +#include "PollData.h" +#include "DDData.h" + +#if defined(__WINDOWS__) +#include "Inaddr.h" +#else +#include +#endif + +#include + +class CDummyRepeaterProtocolHandler : public IRepeaterProtocolHandler { +public: + CDummyRepeaterProtocolHandler(); + virtual ~CDummyRepeaterProtocolHandler(); + + virtual bool open(); + + virtual bool writeHeader(CHeaderData& header); + virtual bool writeAMBE(CAMBEData& data); + virtual bool writeDD(CDDData& data); + virtual bool writeText(CTextData& text); + virtual bool writeStatus(CStatusData& status); + + virtual REPEATER_TYPE read(); + virtual CPollData* readPoll(); + virtual CHeardData* readHeard(); + virtual CHeaderData* readHeader(); + virtual CAMBEData* readAMBE(); + virtual CDDData* readDD(); + virtual CHeaderData* readBusyHeader(); + virtual CAMBEData* readBusyAMBE(); + + virtual void close(); + +private: +}; + +#endif diff --git a/Common/EchoUnit.cpp b/Common/EchoUnit.cpp new file mode 100644 index 0000000..0e82e46 --- /dev/null +++ b/Common/EchoUnit.cpp @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2011-2014 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "DStarDefines.h" +#include "EchoUnit.h" +#include "Defs.h" + +const unsigned int MAX_FRAMES = 60U * DSTAR_FRAMES_PER_SEC; + +CEchoUnit::CEchoUnit(IRepeaterCallback* handler, const wxString& callsign) : +m_handler(handler), +m_callsign(callsign), +m_status(ES_IDLE), +m_timer(1000U, REPLY_TIME), +m_header(NULL), +m_data(NULL), +m_in(0U), +m_out(0U), +m_time() +{ + wxASSERT(handler != NULL); + + m_data = new CAMBEData*[MAX_FRAMES]; + + for (unsigned int i = 0U; i < MAX_FRAMES; i++) + m_data[i] = NULL; +} + +CEchoUnit::~CEchoUnit() +{ + delete[] m_data; +} + +void CEchoUnit::writeHeader(const CHeaderData& header) +{ + if (m_status != ES_IDLE) + return; + + m_header = new CHeaderData(header); + + m_in = 0U; + m_status = ES_RECEIVE; +} + +void CEchoUnit::writeData(const CAMBEData& data) +{ + if (m_status != ES_RECEIVE) + return; + + if (m_in < MAX_FRAMES) { + m_data[m_in] = new CAMBEData(data); + m_in++; + } + + if (data.isEnd()) { + wxLogMessage(wxT("Received %.1f secs of audio from %s for echoing"), float(m_in) / float(DSTAR_FRAMES_PER_SEC), m_header->getMyCall1().c_str()); + + m_timer.start(); + m_status = ES_WAIT; + } +} + +void CEchoUnit::end() +{ + if (m_status != ES_RECEIVE) + return; + + wxLogMessage(wxT("Received %.1f secs of audio from %s for echoing"), float(m_in) / float(DSTAR_FRAMES_PER_SEC), m_header->getMyCall1().c_str()); + + m_timer.start(); + m_status = ES_WAIT; +} + +void CEchoUnit::clock(unsigned int ms) +{ + m_timer.clock(ms); + + if (m_status == ES_WAIT && m_timer.hasExpired()) { + m_timer.stop(); + + // RPT1 and RPT2 will be filled in later + m_header->setMyCall1(m_callsign); + m_header->setMyCall2(wxT("ECHO")); + m_header->setYourCall(wxT("CQCQCQ ")); + + m_handler->process(*m_header, DIR_INCOMING, AS_ECHO); + + delete m_header; + + m_out = 0U; + m_status = ES_TRANSMIT; + + m_time.Start(); + + return; + } + + if (m_status == ES_TRANSMIT) { + unsigned int needed = m_time.Time() / DSTAR_FRAME_TIME_MS; + + while (m_out < needed) { + CAMBEData* data = m_data[m_out]; + m_data[m_out] = NULL; + m_out++; + + if (m_in == m_out) + data->setEnd(true); + + m_handler->process(*data, DIR_INCOMING, AS_ECHO); + + delete data; + + if (m_in == m_out) { + m_in = 0U; + m_out = 0U; + m_status = ES_IDLE; + return; + } + } + + return; + } +} + +void CEchoUnit::cancel() +{ + for (unsigned int i = 0U; i < MAX_FRAMES; i++) { + if (m_data[i] != NULL) { + delete m_data[i]; + m_data[i] = NULL; + } + } + + m_status = ES_IDLE; + m_out = 0U; + m_in = 0U; + + m_timer.stop(); +} diff --git a/Common/EchoUnit.h b/Common/EchoUnit.h new file mode 100644 index 0000000..1786c2f --- /dev/null +++ b/Common/EchoUnit.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2011,2012 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef EchoUnit_H +#define EchoUnit_H + +#include "RepeaterCallback.h" +#include "HeaderData.h" +#include "AMBEData.h" +#include "Timer.h" + +#include + +enum ECHO_STATUS { + ES_IDLE, + ES_RECEIVE, + ES_WAIT, + ES_TRANSMIT +}; + +class CEchoUnit { +public: + CEchoUnit(IRepeaterCallback* handler, const wxString& callsign); + ~CEchoUnit(); + + void writeHeader(const CHeaderData& header); + + void writeData(const CAMBEData& data); + + void end(); + + void cancel(); + + void clock(unsigned int ms); + +private: + IRepeaterCallback* m_handler; + wxString m_callsign; + ECHO_STATUS m_status; + CTimer m_timer; + CHeaderData* m_header; + CAMBEData** m_data; + unsigned int m_in; + unsigned int m_out; + wxStopWatch m_time; +}; + +#endif diff --git a/Common/G2Handler.cpp b/Common/G2Handler.cpp new file mode 100644 index 0000000..3604a61 --- /dev/null +++ b/Common/G2Handler.cpp @@ -0,0 +1,198 @@ +/* + * Copyright (C) 2010-2014 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "StarNetHandler.h" +#include "DStarDefines.h" +#include "G2Handler.h" +#include "Utils.h" +#include "Defs.h" + +unsigned int CG2Handler::m_maxRoutes = 0U; +CG2Handler** CG2Handler::m_routes = NULL; + +CG2ProtocolHandler* CG2Handler::m_handler = NULL; + +CHeaderLogger* CG2Handler::m_headerLogger = NULL; + +CG2Handler::CG2Handler(CRepeaterHandler* repeater, const in_addr& address, unsigned int id) : +m_repeater(repeater), +m_address(address), +m_id(id), +m_inactivityTimer(1000U, NETWORK_TIMEOUT) +{ + m_inactivityTimer.start(); +} + +CG2Handler::~CG2Handler() +{ +} + +void CG2Handler::initialise(unsigned int maxRoutes) +{ + m_maxRoutes = maxRoutes; + + if (maxRoutes == 0U) + return; + + m_routes = new CG2Handler*[m_maxRoutes]; + for (unsigned int i = 0U; i < m_maxRoutes; i++) + m_routes[i] = NULL; +} + +void CG2Handler::setG2ProtocolHandler(CG2ProtocolHandler* handler) +{ + wxASSERT(handler != NULL); + + m_handler = handler; +} + +void CG2Handler::setHeaderLogger(CHeaderLogger* logger) +{ + m_headerLogger = logger; +} + +void CG2Handler::process(CHeaderData& header) +{ + // Is this a busy reply? + unsigned char flag1 = header.getFlag1(); + if (flag1 == 0x01) { + // Don't check the incoming stream + // wxLogMessage(wxT("G2 busy message received")); + return; + } + + // Check to see if this is for StarNet + CStarNetHandler* handler = CStarNetHandler::findStarNet(header); + if (handler != NULL) { + // Write to Header.log if it's enabled + if (m_headerLogger != NULL) + m_headerLogger->write(wxT("StarNet"), header); + + handler->process(header); + return; + } + + // No need to go any further + if (m_maxRoutes == 0U) + return; + + in_addr address = header.getYourAddress(); + unsigned int id = header.getId(); + + for (unsigned int i = 0U; i < m_maxRoutes; i++) { + CG2Handler* route = m_routes[i]; + if (route != NULL) { + // Is this a duplicate header, ignore it + if (route->m_id == id) + return; + } + } + + // Find the destination repeater + CRepeaterHandler* repeater = CRepeaterHandler::findDVRepeater(header.getRptCall2()); + if (repeater == NULL) { + wxLogMessage(wxT("Incoming G2 header from %s to unknown repeater - %s"), header.getMyCall1().c_str(), header.getRptCall2().c_str()); + return; // Not found, ignore + } + + CG2Handler* route = new CG2Handler(repeater, address, id); + + for (unsigned int i = 0U; i < m_maxRoutes; i++) { + if (m_routes[i] == NULL) { + m_routes[i] = route; + + // Write to Header.log if it's enabled + if (m_headerLogger != NULL) + m_headerLogger->write(wxT("G2"), header); + + repeater->process(header, DIR_INCOMING, AS_G2); + return; + } + } + + wxLogMessage(wxT("No space to add new G2 route, ignoring")); + + delete route; +} + +void CG2Handler::process(CAMBEData& data) +{ + // Check to see if this is for StarNet + CStarNetHandler* handler = CStarNetHandler::findStarNet(data); + if (handler != NULL) { + handler->process(data); + return; + } + + // No need to go any further + if (m_maxRoutes == 0U) + return; + + unsigned int id = data.getId(); + + for (unsigned int i = 0U; i < m_maxRoutes; i++) { + CG2Handler* route = m_routes[i]; + if (route != NULL) { + if (route->m_id == id) { + route->m_inactivityTimer.start(); + route->m_repeater->process(data, DIR_INCOMING, AS_G2); + + if (data.isEnd()) { + delete route; + m_routes[i] = NULL; + } + + return; + } + } + } +} + +void CG2Handler::clock(unsigned int ms) +{ + for (unsigned int i = 0U; i < m_maxRoutes; i++) { + CG2Handler* route = m_routes[i]; + if (route != NULL) { + bool ret = route->clockInt(ms); + if (ret) { + delete route; + m_routes[i] = NULL; + } + } + } +} + +void CG2Handler::finalise() +{ + for (unsigned int i = 0U; i < m_maxRoutes; i++) + delete m_routes[i]; + + delete[] m_routes; +} + +bool CG2Handler::clockInt(unsigned int ms) +{ + m_inactivityTimer.clock(ms); + + if (m_inactivityTimer.isRunning() && m_inactivityTimer.hasExpired()) { + wxLogMessage(wxT("Inactivity timeout for a G2 route has expired")); + return true; + } + + return false; +} diff --git a/Common/G2Handler.h b/Common/G2Handler.h new file mode 100644 index 0000000..d9e1402 --- /dev/null +++ b/Common/G2Handler.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2010,2012 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef G2Handler_H +#define G2Handler_H + +#include "G2ProtocolHandler.h" +#include "RepeaterHandler.h" +#include "DStarDefines.h" +#include "HeaderLogger.h" +#include "HeaderData.h" +#include "AMBEData.h" +#include "Timer.h" + +#if defined(__WINDOWS__) +#include "Inaddr.h" +#else +#include +#endif + +#include + +class CG2Handler { +public: + static void initialise(unsigned int maxRoutes); + + static void setG2ProtocolHandler(CG2ProtocolHandler* handler); + static void setHeaderLogger(CHeaderLogger* logger); + + static void process(CHeaderData& header); + static void process(CAMBEData& header); + + static void clock(unsigned int ms); + + static void finalise(); + +protected: + CG2Handler(CRepeaterHandler* repeater, const in_addr& address, unsigned int id); + ~CG2Handler(); + + bool clockInt(unsigned int ms); + +private: + static unsigned int m_maxRoutes; + static CG2Handler** m_routes; + + static CG2ProtocolHandler* m_handler; + + static CHeaderLogger* m_headerLogger; + + CRepeaterHandler* m_repeater; + in_addr m_address; + unsigned int m_id; + CTimer m_inactivityTimer; +}; + +#endif diff --git a/Common/G2ProtocolHandler.cpp b/Common/G2ProtocolHandler.cpp new file mode 100644 index 0000000..8f68b98 --- /dev/null +++ b/Common/G2ProtocolHandler.cpp @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2010,2011,2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "G2ProtocolHandler.h" + +#include "DStarDefines.h" +#include "Utils.h" + +// #define DUMP_TX + +const unsigned int BUFFER_LENGTH = 255U; + +CG2ProtocolHandler::CG2ProtocolHandler(unsigned int port, const wxString& addr) : +m_socket(addr, port), +m_type(GT_NONE), +m_buffer(NULL), +m_length(0U), +m_address(), +m_port(0U) +{ + m_buffer = new unsigned char[BUFFER_LENGTH]; +} + +CG2ProtocolHandler::~CG2ProtocolHandler() +{ + delete[] m_buffer; +} + +bool CG2ProtocolHandler::open() +{ + return m_socket.open(); +} + +bool CG2ProtocolHandler::writeHeader(const CHeaderData& header) +{ + unsigned char buffer[60U]; + unsigned int length = header.getG2Data(buffer, 60U, true); + +#if defined(DUMP_TX) + CUtils::dump(wxT("Sending Header"), buffer, length); +#endif + + for (unsigned int i = 0U; i < 5U; i++) { + bool res = m_socket.write(buffer, length, header.getYourAddress(), header.getYourPort()); + if (!res) + return false; + } + + return true; +} + +bool CG2ProtocolHandler::writeAMBE(const CAMBEData& data) +{ + unsigned char buffer[40U]; + unsigned int length = data.getG2Data(buffer, 40U); + +#if defined(DUMP_TX) + CUtils::dump(wxT("Sending Data"), buffer, length); +#endif + + return m_socket.write(buffer, length, data.getYourAddress(), data.getYourPort()); +} + +G2_TYPE CG2ProtocolHandler::read() +{ + bool res = true; + + // Loop until we have no more data from the socket or we have data for the higher layers + while (res) + res = readPackets(); + + return m_type; +} + +bool CG2ProtocolHandler::readPackets() +{ + m_type = GT_NONE; + + // No more data? + int length = m_socket.read(m_buffer, BUFFER_LENGTH, m_address, m_port); + if (length <= 0) + return false; + + m_length = length; + + if (m_buffer[0] != 'D' || m_buffer[1] != 'S' || m_buffer[2] != 'V' || m_buffer[3] != 'T') { + return true; + } else { + // Header or data packet type? + if ((m_buffer[14] & 0x80) == 0x80) + m_type = GT_HEADER; + else + m_type = GT_AMBE; + + return false; + } +} + +CHeaderData* CG2ProtocolHandler::readHeader() +{ + if (m_type != GT_HEADER) + return NULL; + + CHeaderData* header = new CHeaderData; + + // G2 checksums are unreliable + bool res = header->setG2Data(m_buffer, m_length, false, m_address, m_port); + if (!res) { + delete header; + return NULL; + } + + return header; +} + +CAMBEData* CG2ProtocolHandler::readAMBE() +{ + if (m_type != GT_AMBE) + return NULL; + + CAMBEData* data = new CAMBEData; + + bool res = data->setG2Data(m_buffer, m_length, m_address, m_port); + if (!res) { + delete data; + return NULL; + } + + return data; +} + +void CG2ProtocolHandler::close() +{ + m_socket.close(); +} diff --git a/Common/G2ProtocolHandler.h b/Common/G2ProtocolHandler.h new file mode 100644 index 0000000..3a87834 --- /dev/null +++ b/Common/G2ProtocolHandler.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2010,2011 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef G2ProtocolHandler_H +#define G2ProtocolHandler_H + +#include "UDPReaderWriter.h" +#include "DStarDefines.h" +#include "HeaderData.h" +#include "AMBEData.h" + +#if defined(__WINDOWS__) +#include "Inaddr.h" +#else +#include +#endif + +#include + +enum G2_TYPE { + GT_NONE, + GT_HEADER, + GT_AMBE +}; + +class CG2ProtocolHandler { +public: + CG2ProtocolHandler(unsigned int port, const wxString& addr = wxEmptyString); + ~CG2ProtocolHandler(); + + bool open(); + + bool writeHeader(const CHeaderData& header); + bool writeAMBE(const CAMBEData& data); + + G2_TYPE read(); + CHeaderData* readHeader(); + CAMBEData* readAMBE(); + + void close(); + +private: + CUDPReaderWriter m_socket; + G2_TYPE m_type; + unsigned char* m_buffer; + unsigned int m_length; + in_addr m_address; + unsigned int m_port; + + bool readPackets(); +}; + +#endif diff --git a/Common/GatewayCache.cpp b/Common/GatewayCache.cpp new file mode 100644 index 0000000..b029d7c --- /dev/null +++ b/Common/GatewayCache.cpp @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2010,2011,2012 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "GatewayCache.h" + +const unsigned int CACHE_SIZE = 500U; + +CGatewayCache::CGatewayCache() : +m_cache(CACHE_SIZE) +{ +} + +CGatewayCache::~CGatewayCache() +{ + for (CGatewayCache_t::iterator it = m_cache.begin(); it != m_cache.end(); ++it) + delete it->second; +} + +CGatewayRecord* CGatewayCache::find(const wxString& gateway) +{ + return m_cache[gateway]; +} + +void CGatewayCache::update(const wxString& gateway, const wxString& address, DSTAR_PROTOCOL protocol, bool addrLock, bool protoLock) +{ + CGatewayRecord* rec = m_cache[gateway]; + + in_addr addr_in; + addr_in.s_addr = ::inet_addr(address.mb_str()); + + if (rec == NULL) + // A brand new record is needed + m_cache[gateway] = new CGatewayRecord(gateway, addr_in, protocol, addrLock, protoLock); + else + // Update an existing record + rec->setData(addr_in, protocol, addrLock, protoLock); +} + +unsigned int CGatewayCache::getCount() const +{ + return m_cache.size(); +} diff --git a/Common/GatewayCache.h b/Common/GatewayCache.h new file mode 100644 index 0000000..561743c --- /dev/null +++ b/Common/GatewayCache.h @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2010,2011,2012 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef GatewayCache_H +#define GatewayCache_H + +#include "DStarDefines.h" +#include "Defs.h" + +#if defined(__WINDOWS__) +#include "Inaddr.h" +#else +#include +#include +#include +#endif + +#include +#include + +class CGatewayRecord { +public: + CGatewayRecord(const wxString& gateway, in_addr address, DSTAR_PROTOCOL protocol, bool addrLock, bool protoLock) : + m_gateway(gateway), + m_address(address), + m_protocol(DP_UNKNOWN), + m_addrLock(addrLock), + m_protoLock(false) + { + if (protocol != DP_UNKNOWN) { + m_protocol = protocol; + m_protoLock = protoLock; + } + } + + wxString getGateway() const + { + return m_gateway; + } + + in_addr getAddress() const + { + return m_address; + } + + DSTAR_PROTOCOL getProtocol() const + { + return m_protocol; + } + + void setData(in_addr address, DSTAR_PROTOCOL protocol, bool addrLock, bool protoLock) + { + if (!m_addrLock) { + m_address = address; + m_addrLock = addrLock; + } + + if (!m_protoLock) { + if (protocol != DP_UNKNOWN) { + m_protocol = protocol; + m_protoLock = protoLock; + } + } + } + +private: + wxString m_gateway; + in_addr m_address; + DSTAR_PROTOCOL m_protocol; + bool m_addrLock; + bool m_protoLock; +}; + +WX_DECLARE_STRING_HASH_MAP(CGatewayRecord*, CGatewayCache_t); + +class CGatewayCache { +public: + CGatewayCache(); + ~CGatewayCache(); + + CGatewayRecord* find(const wxString& gateway); + + void update(const wxString& gateway, const wxString& address, DSTAR_PROTOCOL protocol, bool addrLock, bool protoLock); + + unsigned int getCount() const; + +private: + CGatewayCache_t m_cache; +}; + +#endif diff --git a/Common/HBRepeaterProtocolHandler.cpp b/Common/HBRepeaterProtocolHandler.cpp new file mode 100644 index 0000000..0ee7c45 --- /dev/null +++ b/Common/HBRepeaterProtocolHandler.cpp @@ -0,0 +1,285 @@ +/* + * Copyright (C) 2010-2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "HBRepeaterProtocolHandler.h" + +#include "CCITTChecksum.h" +#include "DStarDefines.h" +#include "Utils.h" + +const unsigned int BUFFER_LENGTH = 255U; + +CHBRepeaterProtocolHandler::CHBRepeaterProtocolHandler(const wxString& address, unsigned int port) : +m_socket(address, port), +m_type(RT_NONE), +m_buffer(NULL), +m_length(0U), +m_address(), +m_port(0U) +{ + wxASSERT(!address.IsEmpty()); + wxASSERT(port > 0U); + + m_buffer = new unsigned char[BUFFER_LENGTH]; +} + +CHBRepeaterProtocolHandler::~CHBRepeaterProtocolHandler() +{ + delete[] m_buffer; +} + +bool CHBRepeaterProtocolHandler::open() +{ + return m_socket.open(); +} + +bool CHBRepeaterProtocolHandler::writeHeader(CHeaderData& header) +{ + unsigned char buffer[50U]; + unsigned int length = header.getHBRepeaterData(buffer, 50U, true); + +#if defined(DUMP_TX) + CUtils::dump(wxT("Sending Header"), buffer, length); + return true; +#else + return m_socket.write(buffer, length, header.getYourAddress(), header.getYourPort()); +#endif +} + +bool CHBRepeaterProtocolHandler::writeAMBE(CAMBEData& data) +{ + unsigned char buffer[30U]; + unsigned int length = data.getHBRepeaterData(buffer, 30U); + +#if defined(DUMP_TX) + CUtils::dump(wxT("Sending Data"), buffer, length); + return true; +#else + return m_socket.write(buffer, length, data.getYourAddress(), data.getYourPort()); +#endif +} + +bool CHBRepeaterProtocolHandler::writeDD(CDDData& data) +{ + unsigned char buffer[2000U]; + unsigned int length = data.getHBRepeaterData(buffer, 2000U); + +#if defined(DUMP_TX) + CUtils::dump(wxT("Sending DD Data"), buffer, length); + return true; +#else + return m_socket.write(buffer, length, data.getYourAddress(), data.getYourPort()); +#endif +} + +bool CHBRepeaterProtocolHandler::writeText(CTextData& text) +{ + unsigned char buffer[40U]; + unsigned int length = text.getHBRepeaterData(buffer, 40U); + +#if defined(DUMP_TX) + CUtils::dump(wxT("Sending Text"), buffer, length); + return true; +#else + return m_socket.write(buffer, length, text.getAddress(), text.getPort()); +#endif +} + +bool CHBRepeaterProtocolHandler::writeStatus(CStatusData& status) +{ + unsigned char buffer[30U]; + unsigned int length = status.getHBRepeaterData(buffer, 30U); + +#if defined(DUMP_TX) + CUtils::dump(wxT("Sending Status"), buffer, length); + return true; +#else + return m_socket.write(buffer, length, status.getAddress(), status.getPort()); +#endif +} + +REPEATER_TYPE CHBRepeaterProtocolHandler::read() +{ + bool res = true; + + // Loop until we have no more data from the socket or we have data for the higher layers + while (res) + res = readPackets(); + + return m_type; +} + +bool CHBRepeaterProtocolHandler::readPackets() +{ + m_type = RT_NONE; + + // No more data? + int length = m_socket.read(m_buffer, BUFFER_LENGTH, m_address, m_port); + if (length <= 0) + return false; + + m_length = length; + + // Invalid packet type? + if (m_buffer[0] == 'D' && m_buffer[1] == 'S' && m_buffer[2] == 'R' && m_buffer[3] == 'P') { + // Poll data + if (m_buffer[4] == 0x0AU) { + m_type = RT_POLL; + return false; + } + + // Header data + else if (m_buffer[4] == 0x20U) { + m_type = RT_HEADER; + return false; + } + + // User data + else if (m_buffer[4] == 0x21U) { + m_type = RT_AMBE; + return false; + } + + // DD data + else if (m_buffer[4] == 0x24U) { + m_type = RT_DD; + return false; + } + + // Busy header data + else if (m_buffer[4] == 0x22U) { + m_type = RT_BUSY_HEADER; + return false; + } + + // Busy user data + else if (m_buffer[4] == 0x23U) { + m_type = RT_BUSY_AMBE; + return false; + } + } + + CUtils::dump(wxT("Unknown packet from the Repeater"), m_buffer, m_length); + + return true; +} + +CPollData* CHBRepeaterProtocolHandler::readPoll() +{ + if (m_type != RT_POLL) + return NULL; + + wxString text = wxString((char*)(m_buffer + 5U), wxConvLocal); + + return new CPollData(text, m_address, m_port, m_socket.getPort()); +} + +CHeaderData* CHBRepeaterProtocolHandler::readHeader() +{ + if (m_type != RT_HEADER) + return NULL; + + CHeaderData* header = new CHeaderData; + + bool res = header->setHBRepeaterData(m_buffer, m_length, true, m_address, m_port); + if (!res) { + wxLogError(wxT("Invalid checksum from the repeater")); + delete header; + return NULL; + } + + return header; +} + +CAMBEData* CHBRepeaterProtocolHandler::readAMBE() +{ + if (m_type != RT_AMBE) + return NULL; + + CAMBEData* data = new CAMBEData; + + bool res = data->setHBRepeaterData(m_buffer, m_length, m_address, m_port); + if (!res) { + wxLogError(wxT("Invalid AMBE data from the repeater")); + delete data; + return NULL; + } + + return data; +} + +CHeaderData* CHBRepeaterProtocolHandler::readBusyHeader() +{ + if (m_type != RT_BUSY_HEADER) + return NULL; + + CHeaderData* header = new CHeaderData; + + bool res = header->setHBRepeaterData(m_buffer, m_length, true, m_address, m_port); + if (!res) { + wxLogError(wxT("Invalid checksum from the repeater")); + delete header; + return NULL; + } + + return header; +} + +CAMBEData* CHBRepeaterProtocolHandler::readBusyAMBE() +{ + if (m_type != RT_BUSY_AMBE) + return NULL; + + CAMBEData* data = new CAMBEData; + + bool res = data->setHBRepeaterData(m_buffer, m_length, m_address, m_port); + if (!res) { + wxLogError(wxT("Invalid AMBE data from the repeater")); + delete data; + return NULL; + } + + return data; +} + +CHeardData* CHBRepeaterProtocolHandler::readHeard() +{ + return NULL; +} + +CDDData* CHBRepeaterProtocolHandler::readDD() +{ + if (m_type != RT_DD) + return NULL; + + CDDData* data = new CDDData; + + bool res = data->setHBRepeaterData(m_buffer, m_length, m_address, m_port); + if (!res) { + wxLogError(wxT("Invalid DD data from the repeater")); + delete data; + return NULL; + } + + return data; +} + +void CHBRepeaterProtocolHandler::close() +{ + m_socket.close(); +} diff --git a/Common/HBRepeaterProtocolHandler.h b/Common/HBRepeaterProtocolHandler.h new file mode 100644 index 0000000..f2de49e --- /dev/null +++ b/Common/HBRepeaterProtocolHandler.h @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2010-2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef HBRepeaterProtocolHandler_H +#define HBRepeaterProtocolHandler_H + +#include "RepeaterProtocolHandler.h" +#include "UDPReaderWriter.h" +#include "DStarDefines.h" +#include "HeaderData.h" +#include "StatusData.h" +#include "HeardData.h" +#include "AMBEData.h" +#include "TextData.h" +#include "PollData.h" +#include "DDData.h" + +#if defined(__WINDOWS__) +#include "Inaddr.h" +#else +#include +#endif + +#include + +class CHBRepeaterProtocolHandler : public IRepeaterProtocolHandler { +public: + CHBRepeaterProtocolHandler(const wxString& address, unsigned int port); + virtual ~CHBRepeaterProtocolHandler(); + + virtual bool open(); + + virtual bool writeHeader(CHeaderData& header); + virtual bool writeAMBE(CAMBEData& data); + virtual bool writeDD(CDDData& data); + virtual bool writeText(CTextData& text); + virtual bool writeStatus(CStatusData& status); + + virtual REPEATER_TYPE read(); + virtual CPollData* readPoll(); + virtual CHeardData* readHeard(); + virtual CHeaderData* readHeader(); + virtual CAMBEData* readAMBE(); + virtual CDDData* readDD(); + virtual CHeaderData* readBusyHeader(); + virtual CAMBEData* readBusyAMBE(); + + virtual void close(); + +private: + CUDPReaderWriter m_socket; + REPEATER_TYPE m_type; + unsigned char* m_buffer; + unsigned int m_length; + in_addr m_address; + unsigned int m_port; + + bool readPackets(); +}; + +#endif diff --git a/Common/HeaderData.cpp b/Common/HeaderData.cpp new file mode 100644 index 0000000..fd518bd --- /dev/null +++ b/Common/HeaderData.cpp @@ -0,0 +1,951 @@ +/* + * Copyright (C) 2010-2014 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "HeaderData.h" + +#include + +#include "CCITTChecksum.h" +#include "DStarDefines.h" +#include "Utils.h" + +void CHeaderData::initialise() +{ + wxDateTime now = wxDateTime::UNow(); + ::srand(now.GetMillisecond()); +} + +void CHeaderData::finalise() +{ +} + +unsigned int CHeaderData::createId() +{ + return (::rand() % 65535U) + 1U; +} + +CHeaderData::CHeaderData() : +m_rptSeq(0U), +m_id(0U), +m_band1(0x00U), +m_band2(0x02U), +m_band3(0x01U), +m_flag1(0U), +m_flag2(0U), +m_flag3(0U), +m_myCall1(NULL), +m_myCall2(NULL), +m_yourCall(NULL), +m_rptCall1(NULL), +m_rptCall2(NULL), +m_yourAddress(), +m_yourPort(0U), +m_myPort(0U), +m_errors(0U) +{ + m_myCall1 = new unsigned char[LONG_CALLSIGN_LENGTH]; + m_myCall2 = new unsigned char[SHORT_CALLSIGN_LENGTH]; + m_yourCall = new unsigned char[LONG_CALLSIGN_LENGTH]; + m_rptCall1 = new unsigned char[LONG_CALLSIGN_LENGTH]; + m_rptCall2 = new unsigned char[LONG_CALLSIGN_LENGTH]; + + ::memset(m_rptCall1, ' ', LONG_CALLSIGN_LENGTH); + ::memset(m_rptCall2, ' ', LONG_CALLSIGN_LENGTH); + ::memset(m_yourCall, ' ', LONG_CALLSIGN_LENGTH); + ::memset(m_myCall1, ' ', LONG_CALLSIGN_LENGTH); + ::memset(m_myCall2, ' ', SHORT_CALLSIGN_LENGTH); +} + +CHeaderData::CHeaderData(const CHeaderData& header) : +m_rptSeq(header.m_rptSeq), +m_id(header.m_id), +m_band1(header.m_band1), +m_band2(header.m_band2), +m_band3(header.m_band3), +m_flag1(header.m_flag1), +m_flag2(header.m_flag2), +m_flag3(header.m_flag3), +m_myCall1(NULL), +m_myCall2(NULL), +m_yourCall(NULL), +m_rptCall1(NULL), +m_rptCall2(NULL), +m_yourAddress(header.m_yourAddress), +m_yourPort(header.m_yourPort), +m_myPort(header.m_myPort), +m_errors(header.m_errors) +{ + m_myCall1 = new unsigned char[LONG_CALLSIGN_LENGTH]; + m_myCall2 = new unsigned char[SHORT_CALLSIGN_LENGTH]; + m_yourCall = new unsigned char[LONG_CALLSIGN_LENGTH]; + m_rptCall1 = new unsigned char[LONG_CALLSIGN_LENGTH]; + m_rptCall2 = new unsigned char[LONG_CALLSIGN_LENGTH]; + + ::memcpy(m_myCall1, header.m_myCall1, LONG_CALLSIGN_LENGTH); + ::memcpy(m_myCall2, header.m_myCall2, SHORT_CALLSIGN_LENGTH); + ::memcpy(m_yourCall, header.m_yourCall, LONG_CALLSIGN_LENGTH); + ::memcpy(m_rptCall1, header.m_rptCall1, LONG_CALLSIGN_LENGTH); + ::memcpy(m_rptCall2, header.m_rptCall2, LONG_CALLSIGN_LENGTH); +} + +CHeaderData::CHeaderData(const wxString& myCall1, const wxString& myCall2, const wxString& yourCall, + const wxString& rptCall1, const wxString& rptCall2, unsigned char flag1, + unsigned char flag2, unsigned char flag3) : +m_rptSeq(0U), +m_id(0U), +m_band1(0U), +m_band2(0U), +m_band3(0U), +m_flag1(flag1), +m_flag2(flag2), +m_flag3(flag3), +m_myCall1(NULL), +m_myCall2(NULL), +m_yourCall(NULL), +m_rptCall1(NULL), +m_rptCall2(NULL), +m_yourAddress(), +m_yourPort(0U), +m_myPort(0U), +m_errors(0U) +{ + m_myCall1 = new unsigned char[LONG_CALLSIGN_LENGTH]; + m_myCall2 = new unsigned char[SHORT_CALLSIGN_LENGTH]; + m_yourCall = new unsigned char[LONG_CALLSIGN_LENGTH]; + m_rptCall1 = new unsigned char[LONG_CALLSIGN_LENGTH]; + m_rptCall2 = new unsigned char[LONG_CALLSIGN_LENGTH]; + + ::memset(m_myCall1, ' ', LONG_CALLSIGN_LENGTH); + ::memset(m_myCall2, ' ', SHORT_CALLSIGN_LENGTH); + ::memset(m_yourCall, ' ', LONG_CALLSIGN_LENGTH); + ::memset(m_rptCall1, ' ', LONG_CALLSIGN_LENGTH); + ::memset(m_rptCall2, ' ', LONG_CALLSIGN_LENGTH); + + for (unsigned int i = 0U; i < myCall1.Len() && i < LONG_CALLSIGN_LENGTH; i++) + m_myCall1[i] = myCall1.GetChar(i); + + for (unsigned int i = 0U; i < myCall2.Len() && i < SHORT_CALLSIGN_LENGTH; i++) + m_myCall2[i] = myCall2.GetChar(i); + + for (unsigned int i = 0U; i < yourCall.Len() && i < LONG_CALLSIGN_LENGTH; i++) + m_yourCall[i] = yourCall.GetChar(i); + + for (unsigned int i = 0U; i < rptCall1.Len() && i < LONG_CALLSIGN_LENGTH; i++) + m_rptCall1[i] = rptCall1.GetChar(i); + + for (unsigned int i = 0U; i < rptCall2.Len() && i < LONG_CALLSIGN_LENGTH; i++) + m_rptCall2[i] = rptCall2.GetChar(i); +} + +CHeaderData::~CHeaderData() +{ + delete[] m_myCall1; + delete[] m_myCall2; + delete[] m_yourCall; + delete[] m_rptCall1; + delete[] m_rptCall2; +} + +bool CHeaderData::setIcomRepeaterData(const unsigned char *data, unsigned int length, bool check, const in_addr& yourAddress, unsigned int yourPort) +{ + wxASSERT(data != NULL); + wxASSERT(length >= 58U); + + m_rptSeq = data[4] * 256U + data[5]; + m_band1 = data[11]; + m_band2 = data[12]; + m_band3 = data[13]; + m_id = data[14] * 256U + data[15]; + + m_flag1 = data[17U]; + m_flag2 = data[18U]; + m_flag3 = data[19U]; + + ::memcpy(m_rptCall2, data + 20U, LONG_CALLSIGN_LENGTH); + ::memcpy(m_rptCall1, data + 28U, LONG_CALLSIGN_LENGTH); + ::memcpy(m_yourCall, data + 36U, LONG_CALLSIGN_LENGTH); + ::memcpy(m_myCall1, data + 44U, LONG_CALLSIGN_LENGTH); + ::memcpy(m_myCall2, data + 52U, SHORT_CALLSIGN_LENGTH); + + m_yourAddress = yourAddress; + m_yourPort = yourPort; + + if (check) { + CCCITTChecksum cksum; + cksum.update(data + 17U, RADIO_HEADER_LENGTH_BYTES - 2U); + bool valid = cksum.check(data + 17U + RADIO_HEADER_LENGTH_BYTES - 2U); + + if (!valid) + CUtils::dump(wxT("Header checksum failure from the repeater"), data + 17U, RADIO_HEADER_LENGTH_BYTES); + + return valid; + } else { + return true; + } +} + +bool CHeaderData::setHBRepeaterData(const unsigned char *data, unsigned int length, bool check, const in_addr& yourAddress, unsigned int yourPort) +{ + wxASSERT(data != NULL); + wxASSERT(length >= 49U); + + m_id = data[5U] * 256U + data[6U]; + m_errors = data[7U]; + + m_flag1 = data[8U]; + m_flag2 = data[9U]; + m_flag3 = data[10U]; + + ::memcpy(m_rptCall2, data + 11U, LONG_CALLSIGN_LENGTH); + ::memcpy(m_rptCall1, data + 19U, LONG_CALLSIGN_LENGTH); + ::memcpy(m_yourCall, data + 27U, LONG_CALLSIGN_LENGTH); + ::memcpy(m_myCall1, data + 35U, LONG_CALLSIGN_LENGTH); + ::memcpy(m_myCall2, data + 43U, SHORT_CALLSIGN_LENGTH); + + m_yourAddress = yourAddress; + m_yourPort = yourPort; + + if (check) { + CCCITTChecksum cksum; + cksum.update(data + 8U, RADIO_HEADER_LENGTH_BYTES - 2U); + bool valid = cksum.check(data + 8U + RADIO_HEADER_LENGTH_BYTES - 2U); + + if (!valid) + CUtils::dump(wxT("Header checksum failure from the repeater"), data + 8U, RADIO_HEADER_LENGTH_BYTES); + + return valid; + } else { + return true; + } +} + +void CHeaderData::setDCSData(const unsigned char *data, unsigned int length, const in_addr& yourAddress, unsigned int yourPort, unsigned int myPort) +{ + wxASSERT(data != NULL); + wxASSERT(length >= 100U); + + m_id = data[44U] * 256U + data[43U]; + + m_flag1 = data[4U]; + m_flag2 = data[5U]; + m_flag3 = data[6U]; + + ::memcpy(m_rptCall2, data + 7U, LONG_CALLSIGN_LENGTH); + ::memcpy(m_rptCall1, data + 15U, LONG_CALLSIGN_LENGTH); + ::memcpy(m_yourCall, data + 23U, LONG_CALLSIGN_LENGTH); + ::memcpy(m_myCall1, data + 31U, LONG_CALLSIGN_LENGTH); + ::memcpy(m_myCall2, data + 39U, SHORT_CALLSIGN_LENGTH); + + m_yourAddress = yourAddress; + m_yourPort = yourPort; + m_myPort = myPort; +} + +void CHeaderData::setCCSData(const unsigned char *data, unsigned int length, const in_addr& yourAddress, unsigned int yourPort, unsigned int myPort) +{ + wxASSERT(data != NULL); + wxASSERT(length >= 100U); + + m_id = data[44U] * 256U + data[43U]; + + ::memcpy(m_rptCall2, data + 7U, LONG_CALLSIGN_LENGTH); + ::memcpy(m_rptCall1, data + 15U, LONG_CALLSIGN_LENGTH); + ::memcpy(m_yourCall, data + 23U, LONG_CALLSIGN_LENGTH); + ::memcpy(m_myCall1, data + 31U, LONG_CALLSIGN_LENGTH); + ::memcpy(m_myCall2, data + 39U, SHORT_CALLSIGN_LENGTH); + + m_yourAddress = yourAddress; + m_yourPort = yourPort; + m_myPort = myPort; +} + +bool CHeaderData::setG2Data(const unsigned char *data, unsigned int length, bool check, const in_addr& yourAddress, unsigned int yourPort) +{ + wxASSERT(data != NULL); + wxASSERT(length >= 56U); + + m_band1 = data[9]; + m_band2 = data[10]; + m_band3 = data[11]; + m_id = data[12] * 256U + data[13]; + + m_flag1 = data[15U]; + m_flag2 = data[16U]; + m_flag3 = data[17U]; + + ::memcpy(m_rptCall2, data + 18U, LONG_CALLSIGN_LENGTH); + ::memcpy(m_rptCall1, data + 26U, LONG_CALLSIGN_LENGTH); + ::memcpy(m_yourCall, data + 34U, LONG_CALLSIGN_LENGTH); + ::memcpy(m_myCall1, data + 42U, LONG_CALLSIGN_LENGTH); + ::memcpy(m_myCall2, data + 50U, SHORT_CALLSIGN_LENGTH); + + m_yourAddress = yourAddress; + m_yourPort = yourPort; + + if (check) { + CCCITTChecksum cksum; + cksum.update(data + 15U, RADIO_HEADER_LENGTH_BYTES - 2U); + bool valid = cksum.check(data + 15U + RADIO_HEADER_LENGTH_BYTES - 2U); + + if (!valid) + CUtils::dump(wxT("Header checksum failure from G2"), data + 15U, RADIO_HEADER_LENGTH_BYTES); + + return valid; + } else { + return true; + } +} + +bool CHeaderData::setDExtraData(const unsigned char *data, unsigned int length, bool check, const in_addr& yourAddress, unsigned int yourPort, unsigned int myPort) +{ + wxASSERT(data != NULL); + wxASSERT(length >= 56U); + + m_band1 = data[9]; + m_band2 = data[10]; + m_band3 = data[11]; + m_id = data[12] * 256U + data[13]; + + m_flag1 = data[15U]; + m_flag2 = data[16U]; + m_flag3 = data[17U]; + + ::memcpy(m_rptCall2, data + 18U, LONG_CALLSIGN_LENGTH); + ::memcpy(m_rptCall1, data + 26U, LONG_CALLSIGN_LENGTH); + ::memcpy(m_yourCall, data + 34U, LONG_CALLSIGN_LENGTH); + ::memcpy(m_myCall1, data + 42U, LONG_CALLSIGN_LENGTH); + ::memcpy(m_myCall2, data + 50U, SHORT_CALLSIGN_LENGTH); + + m_yourAddress = yourAddress; + m_yourPort = yourPort; + m_myPort = myPort; + + if (check) { + CCCITTChecksum cksum; + cksum.update(data + 15U, RADIO_HEADER_LENGTH_BYTES - 2U); + bool valid = cksum.check(data + 15U + RADIO_HEADER_LENGTH_BYTES - 2U); + + if (!valid) + CUtils::dump(wxT("Header checksum failure from DExtra"), data + 15U, RADIO_HEADER_LENGTH_BYTES); + + return valid; + } else { + return true; + } +} + +bool CHeaderData::setDPlusData(const unsigned char *data, unsigned int length, bool check, const in_addr& yourAddress, unsigned int yourPort, unsigned int myPort) +{ + wxASSERT(data != NULL); + wxASSERT(length >= 58U); + + if (data[0] != 0x3A || data[1] != 0x80) { + CUtils::dump(wxT("Invalid header length from D-Plus"), data, length); + return false; + } + + m_band1 = data[11]; + m_band2 = data[12]; + m_band3 = data[13]; + m_id = data[14] * 256U + data[15]; + + m_flag1 = data[17U]; + m_flag2 = data[18U]; + m_flag3 = data[19U]; + + ::memcpy(m_rptCall2, data + 20U, LONG_CALLSIGN_LENGTH); + ::memcpy(m_rptCall1, data + 28U, LONG_CALLSIGN_LENGTH); + ::memcpy(m_yourCall, data + 36U, LONG_CALLSIGN_LENGTH); + ::memcpy(m_myCall1, data + 44U, LONG_CALLSIGN_LENGTH); + ::memcpy(m_myCall2, data + 52U, SHORT_CALLSIGN_LENGTH); + + m_yourAddress = yourAddress; + m_yourPort = yourPort; + m_myPort = myPort; + + if (check) { + CCCITTChecksum cksum; + cksum.update(data + 17U, RADIO_HEADER_LENGTH_BYTES - 2U); + bool valid = cksum.check(data + 17U + RADIO_HEADER_LENGTH_BYTES - 2U); + + if (!valid) + CUtils::dump(wxT("Header checksum failure from D-Plus"), data + 17U, RADIO_HEADER_LENGTH_BYTES); + + return valid; + } else { + return true; + } +} + +bool CHeaderData::setDVTOOLData(const unsigned char* data, unsigned int length, bool check) +{ + wxASSERT(data != NULL); + wxASSERT(length >= RADIO_HEADER_LENGTH_BYTES); + + m_flag1 = data[0U]; + m_flag2 = data[1U]; + m_flag3 = data[2U]; + + ::memcpy(m_rptCall2, data + 3U, LONG_CALLSIGN_LENGTH); + ::memcpy(m_rptCall1, data + 11U, LONG_CALLSIGN_LENGTH); + ::memcpy(m_yourCall, data + 19U, LONG_CALLSIGN_LENGTH); + ::memcpy(m_myCall1, data + 27U, LONG_CALLSIGN_LENGTH); + ::memcpy(m_myCall2, data + 35U, SHORT_CALLSIGN_LENGTH); + + if (check) { + CCCITTChecksum cksum; + cksum.update(data, RADIO_HEADER_LENGTH_BYTES - 2U); + bool valid = cksum.check(data + RADIO_HEADER_LENGTH_BYTES - 2U); + + if (!valid) + CUtils::dump(wxT("Header checksum failure from DVTOOL"), data, RADIO_HEADER_LENGTH_BYTES); + + return valid; + } else { + return true; + } +} + +unsigned int CHeaderData::getIcomRepeaterData(unsigned char *data, unsigned int length, bool check) const +{ + wxASSERT(data != NULL); + wxASSERT(length >= 58U); + + data[0] = 'D'; + data[1] = 'S'; + data[2] = 'T'; + data[3] = 'R'; + + data[4] = m_rptSeq / 256U; // Packet sequence number + data[5] = m_rptSeq % 256U; + + data[6] = 0x73; // Not a response + data[7] = 0x12; // Data type + + data[8] = 0x00; // Length of 48 bytes following + data[9] = 0x30; + + data[10] = 0x20; // AMBE plus Slow Data following + + data[11] = m_band1; + data[12] = m_band2; + data[13] = m_band3; + + data[14] = m_id / 256U; // Unique session id + data[15] = m_id % 256U; + + data[16] = 0x80; + + data[17] = m_flag1; // Flags 1, 2, and 3 + data[18] = m_flag2; + data[19] = m_flag3; + + ::memcpy(data + 20U, m_rptCall2, LONG_CALLSIGN_LENGTH); + ::memcpy(data + 28U, m_rptCall1, LONG_CALLSIGN_LENGTH); + ::memcpy(data + 36U, m_yourCall, LONG_CALLSIGN_LENGTH); + ::memcpy(data + 44U, m_myCall1, LONG_CALLSIGN_LENGTH); + ::memcpy(data + 52U, m_myCall2, SHORT_CALLSIGN_LENGTH); + + if (check) { + CCCITTChecksum csum; + csum.update(data + 17, 4U * LONG_CALLSIGN_LENGTH + SHORT_CALLSIGN_LENGTH + 3U); + csum.result(data + 56); + } else { + data[56] = 0xFF; + data[57] = 0xFF; + } + + return 58U; +} + +unsigned int CHeaderData::getHBRepeaterData(unsigned char *data, unsigned int length, bool check) const +{ + wxASSERT(data != NULL); + wxASSERT(length >= 49U); + + data[0] = 'D'; + data[1] = 'S'; + data[2] = 'R'; + data[3] = 'P'; + + data[4] = 0x20U; + + data[5] = m_id / 256U; // Unique session id + data[6] = m_id % 256U; + + data[7] = 0U; + + data[8] = m_flag1; // Flags 1, 2, and 3 + data[9] = m_flag2; + data[10] = m_flag3; + + ::memcpy(data + 11U, m_rptCall2, LONG_CALLSIGN_LENGTH); + ::memcpy(data + 19U, m_rptCall1, LONG_CALLSIGN_LENGTH); + ::memcpy(data + 27U, m_yourCall, LONG_CALLSIGN_LENGTH); + ::memcpy(data + 35U, m_myCall1, LONG_CALLSIGN_LENGTH); + ::memcpy(data + 43U, m_myCall2, SHORT_CALLSIGN_LENGTH); + + if (check) { + CCCITTChecksum csum; + csum.update(data + 8U, 4U * LONG_CALLSIGN_LENGTH + SHORT_CALLSIGN_LENGTH + 3U); + csum.result(data + 47U); + } else { + data[47] = 0xFF; + data[48] = 0xFF; + } + + return 49U; +} + +void CHeaderData::getDCSData(unsigned char *data, unsigned int length) const +{ + wxASSERT(data != NULL); + wxASSERT(length >= 100U); + + data[4] = m_flag1; // Flags 1, 2, and 3 + data[5] = m_flag2; + data[6] = m_flag3; + + ::memcpy(data + 7U, m_rptCall2, LONG_CALLSIGN_LENGTH); + ::memcpy(data + 15U, m_rptCall1, LONG_CALLSIGN_LENGTH); + ::memcpy(data + 23U, m_yourCall, LONG_CALLSIGN_LENGTH); + ::memcpy(data + 31U, m_myCall1, LONG_CALLSIGN_LENGTH); + ::memcpy(data + 39U, m_myCall2, SHORT_CALLSIGN_LENGTH); +} + +void CHeaderData::getCCSData(unsigned char *data, unsigned int length) const +{ + wxASSERT(data != NULL); + wxASSERT(length >= 100U); + + ::memcpy(data + 7U, m_rptCall2, LONG_CALLSIGN_LENGTH); + ::memcpy(data + 15U, m_rptCall1, LONG_CALLSIGN_LENGTH); + ::memcpy(data + 23U, m_yourCall, LONG_CALLSIGN_LENGTH); + ::memcpy(data + 31U, m_myCall1, LONG_CALLSIGN_LENGTH); + ::memcpy(data + 39U, m_myCall2, SHORT_CALLSIGN_LENGTH); +} + +unsigned int CHeaderData::getG2Data(unsigned char *data, unsigned int length, bool check) const +{ + wxASSERT(data != NULL); + wxASSERT(length >= 56U); + + data[0] = 'D'; + data[1] = 'S'; + data[2] = 'V'; + data[3] = 'T'; + + data[4] = 0x10; + data[5] = 0x00; + data[6] = 0x15; + data[7] = 0x09; + data[8] = 0x20; + + data[9] = m_band1; + data[10] = m_band2; + data[11] = m_band3; + + data[12] = m_id / 256U; // Unique session id + data[13] = m_id % 256U; + + data[14] = 0x80; + + data[15] = m_flag1; // Flags 1, 2, and 3 + data[16] = m_flag2; + data[17] = m_flag3; + + ::memcpy(data + 18U, m_rptCall2, LONG_CALLSIGN_LENGTH); + ::memcpy(data + 26U, m_rptCall1, LONG_CALLSIGN_LENGTH); + ::memcpy(data + 34U, m_yourCall, LONG_CALLSIGN_LENGTH); + ::memcpy(data + 42U, m_myCall1, LONG_CALLSIGN_LENGTH); + ::memcpy(data + 50U, m_myCall2, SHORT_CALLSIGN_LENGTH); + + if (check) { + CCCITTChecksum csum; + csum.update(data + 15, 4U * LONG_CALLSIGN_LENGTH + SHORT_CALLSIGN_LENGTH + 3U); + csum.result(data + 54); + } else { + data[54] = 0xFF; + data[55] = 0xFF; + } + + return 56U; +} + +unsigned int CHeaderData::getDExtraData(unsigned char* data, unsigned int length, bool check) const +{ + wxASSERT(data != NULL); + wxASSERT(length >= 56U); + + data[0] = 'D'; + data[1] = 'S'; + data[2] = 'V'; + data[3] = 'T'; + + data[4] = 0x10; + data[5] = 0x00; + data[6] = 0x00; + data[7] = 0x00; + data[8] = 0x20; + + data[9] = m_band1; + data[10] = m_band2; + data[11] = m_band3; + + data[12] = m_id % 256U; // Unique session id + data[13] = m_id / 256U; + + data[14] = 0x80; + + data[15] = 0x00; // Flags 1, 2, and 3 + data[16] = 0x00; + data[17] = 0x00; + + ::memcpy(data + 18U, m_rptCall2, LONG_CALLSIGN_LENGTH); + ::memcpy(data + 26U, m_rptCall1, LONG_CALLSIGN_LENGTH); + ::memcpy(data + 34U, m_yourCall, LONG_CALLSIGN_LENGTH); + ::memcpy(data + 42U, m_myCall1, LONG_CALLSIGN_LENGTH); + ::memcpy(data + 50U, m_myCall2, SHORT_CALLSIGN_LENGTH); + + if (check) { + CCCITTChecksum csum; + csum.update(data + 15, 4U * LONG_CALLSIGN_LENGTH + SHORT_CALLSIGN_LENGTH + 3U); + csum.result(data + 54); + } else { + data[54] = 0xFF; + data[55] = 0xFF; + } + + return 56U; +} + +unsigned int CHeaderData::getDPlusData(unsigned char* data, unsigned int length, bool check) const +{ + wxASSERT(data != NULL); + wxASSERT(length >= 58U); + + data[0] = 0x3A; + data[1] = 0x80; + + data[2] = 'D'; + data[3] = 'S'; + data[4] = 'V'; + data[5] = 'T'; + + data[6] = 0x10; + data[7] = 0x00; + data[8] = 0x00; + data[9] = 0x00; + data[10] = 0x20; + + data[11] = m_band1; + data[12] = m_band2; + data[13] = m_band3; + + data[14] = m_id % 256U; // Unique session id + data[15] = m_id / 256U; + + data[16] = 0x80; + + data[17] = 0x00; // Flags 1, 2, and 3 + data[18] = 0x00; + data[19] = 0x00; + + ::memcpy(data + 20U, m_rptCall2, LONG_CALLSIGN_LENGTH); + ::memcpy(data + 28U, m_rptCall1, LONG_CALLSIGN_LENGTH); + ::memcpy(data + 36U, m_yourCall, LONG_CALLSIGN_LENGTH); + ::memcpy(data + 44U, m_myCall1, LONG_CALLSIGN_LENGTH); + ::memcpy(data + 52U, m_myCall2, SHORT_CALLSIGN_LENGTH); + + if (check) { + CCCITTChecksum csum; + csum.update(data + 17, 4U * LONG_CALLSIGN_LENGTH + SHORT_CALLSIGN_LENGTH + 3U); + csum.result(data + 56); + } else { + data[56] = 0xFF; + data[57] = 0xFF; + } + + return 58U; +} + +unsigned int CHeaderData::getId() const +{ + return m_id; +} + +void CHeaderData::setId(unsigned int id) +{ + m_id = id; +} + +unsigned char CHeaderData::getBand1() const +{ + return m_band1; +} + +unsigned char CHeaderData::getBand2() const +{ + return m_band2; +} + +unsigned char CHeaderData::getBand3() const +{ + return m_band3; +} + +void CHeaderData::setBand1(unsigned char band) +{ + m_band1 = band; +} + +void CHeaderData::setBand2(unsigned char band) +{ + m_band2 = band; +} + +void CHeaderData::setBand3(unsigned char band) +{ + m_band3 = band; +} + +unsigned int CHeaderData::getRptSeq() const +{ + return m_rptSeq; +} + +void CHeaderData::setRptSeq(unsigned int seqNo) +{ + m_rptSeq = seqNo; +} + +unsigned char CHeaderData::getFlag1() const +{ + return m_flag1; +} + +unsigned char CHeaderData::getFlag2() const +{ + return m_flag2; +} + +unsigned char CHeaderData::getFlag3() const +{ + return m_flag3; +} + +void CHeaderData::setFlags(unsigned char flag1, unsigned char flag2, unsigned char flag3) +{ + m_flag1 = flag1; + m_flag2 = flag2; + m_flag3 = flag3; +} + +wxString CHeaderData::getMyCall1() const +{ + return wxString((const char*)m_myCall1, wxConvLocal, LONG_CALLSIGN_LENGTH); +} + +wxString CHeaderData::getMyCall2() const +{ + return wxString((const char*)m_myCall2, wxConvLocal, SHORT_CALLSIGN_LENGTH); +} + +wxString CHeaderData::getYourCall() const +{ + return wxString((const char*)m_yourCall, wxConvLocal, LONG_CALLSIGN_LENGTH); +} + +wxString CHeaderData::getRptCall1() const +{ + return wxString((const char*)m_rptCall1, wxConvLocal, LONG_CALLSIGN_LENGTH); +} + +wxString CHeaderData::getRptCall2() const +{ + return wxString((const char*)m_rptCall2, wxConvLocal, LONG_CALLSIGN_LENGTH); +} + +void CHeaderData::setFlag1(unsigned char flag) +{ + m_flag1 = flag; +} + +void CHeaderData::setFlag2(unsigned char flag) +{ + m_flag2 = flag; +} + +void CHeaderData::setFlag3(unsigned char flag) +{ + m_flag3 = flag; +} + +void CHeaderData::setMyCall1(const wxString& my1) +{ + ::memset(m_myCall1, ' ', LONG_CALLSIGN_LENGTH); + + for (unsigned int i = 0U; i < my1.Len(); i++) + m_myCall1[i] = my1.GetChar(i); +} + +void CHeaderData::setMyCall2(const wxString& my2) +{ + ::memset(m_myCall2, ' ', SHORT_CALLSIGN_LENGTH); + + for (unsigned int i = 0U; i < my2.Len(); i++) + m_myCall2[i] = my2.GetChar(i); +} + +void CHeaderData::setYourCall(const wxString& your) +{ + ::memset(m_yourCall, ' ', LONG_CALLSIGN_LENGTH); + + for (unsigned int i = 0U; i < your.Len(); i++) + m_yourCall[i] = your.GetChar(i); +} + +void CHeaderData::setRptCall1(const wxString& rpt1) +{ + ::memset(m_rptCall1, ' ', LONG_CALLSIGN_LENGTH); + + for (unsigned int i = 0U; i < rpt1.Len(); i++) + m_rptCall1[i] = rpt1.GetChar(i); +} + +void CHeaderData::setRptCall2(const wxString& rpt2) +{ + ::memset(m_rptCall2, ' ', LONG_CALLSIGN_LENGTH); + + for (unsigned int i = 0U; i < rpt2.Len(); i++) + m_rptCall2[i] = rpt2.GetChar(i); +} + +void CHeaderData::setRepeaters(const wxString& rpt1, const wxString& rpt2) +{ + ::memset(m_rptCall1, ' ', LONG_CALLSIGN_LENGTH); + ::memset(m_rptCall2, ' ', LONG_CALLSIGN_LENGTH); + + for (unsigned int i = 0U; i < rpt1.Len(); i++) + m_rptCall1[i] = rpt1.GetChar(i); + + for (unsigned int i = 0U; i < rpt2.Len(); i++) + m_rptCall2[i] = rpt2.GetChar(i); +} + +void CHeaderData::setCQCQCQ() +{ + ::memcpy(m_yourCall, "CQCQCQ ", LONG_CALLSIGN_LENGTH); +} + +bool CHeaderData::setData(const unsigned char *data, unsigned int length, bool check) +{ + wxASSERT(data != NULL); + wxASSERT(length >= RADIO_HEADER_LENGTH_BYTES); + + m_flag1 = data[0U]; + m_flag2 = data[1U]; + m_flag3 = data[2U]; + + ::memcpy(m_rptCall2, data + 3U, LONG_CALLSIGN_LENGTH); + ::memcpy(m_rptCall1, data + 11U, LONG_CALLSIGN_LENGTH); + ::memcpy(m_yourCall, data + 19U, LONG_CALLSIGN_LENGTH); + ::memcpy(m_myCall1, data + 27U, LONG_CALLSIGN_LENGTH); + ::memcpy(m_myCall2, data + 35U, SHORT_CALLSIGN_LENGTH); + + if (check) { + CCCITTChecksum cksum; + cksum.update(data, RADIO_HEADER_LENGTH_BYTES - 2U); + return cksum.check(data + RADIO_HEADER_LENGTH_BYTES - 2U); + } else { + return true; + } +} + +unsigned int CHeaderData::getData(unsigned char *data, unsigned int length, bool check) const +{ + wxASSERT(data != NULL); + wxASSERT(length >= RADIO_HEADER_LENGTH_BYTES); + + data[0] = m_flag1; // Flags 1, 2, and 3 + data[1] = m_flag2; + data[2] = m_flag3; + + ::memcpy(data + 3U, m_rptCall2, LONG_CALLSIGN_LENGTH); + ::memcpy(data + 11U, m_rptCall1, LONG_CALLSIGN_LENGTH); + ::memcpy(data + 19U, m_yourCall, LONG_CALLSIGN_LENGTH); + ::memcpy(data + 27U, m_myCall1, LONG_CALLSIGN_LENGTH); + ::memcpy(data + 35U, m_myCall2, SHORT_CALLSIGN_LENGTH); + + if (check) { + CCCITTChecksum csum; + csum.update(data, RADIO_HEADER_LENGTH_BYTES - 2U); + csum.result(data + RADIO_HEADER_LENGTH_BYTES - 2U); + + return RADIO_HEADER_LENGTH_BYTES; + } else { + return RADIO_HEADER_LENGTH_BYTES - 2U; + } +} + +void CHeaderData::setDestination(const in_addr& address, unsigned int port) +{ + m_yourAddress = address; + m_yourPort = port; +} + +in_addr CHeaderData::getYourAddress() const +{ + return m_yourAddress; +} + +unsigned int CHeaderData::getYourPort() const +{ + return m_yourPort; +} + +unsigned int CHeaderData::getMyPort() const +{ + return m_myPort; +} + +CHeaderData& CHeaderData::operator =(const CHeaderData& header) +{ + if (&header != this) { + m_rptSeq = header.m_rptSeq; + m_id = header.m_id; + m_band1 = header.m_band1; + m_band2 = header.m_band2; + m_band3 = header.m_band3; + m_flag1 = header.m_flag1; + m_flag2 = header.m_flag2; + m_flag3 = header.m_flag3; + m_yourAddress = header.m_yourAddress; + m_yourPort = header.m_yourPort; + m_myPort = header.m_myPort; + m_errors = header.m_errors; + + ::memcpy(m_myCall1, header.m_myCall1, LONG_CALLSIGN_LENGTH); + ::memcpy(m_myCall2, header.m_myCall2, SHORT_CALLSIGN_LENGTH); + ::memcpy(m_yourCall, header.m_yourCall, LONG_CALLSIGN_LENGTH); + ::memcpy(m_rptCall1, header.m_rptCall1, LONG_CALLSIGN_LENGTH); + ::memcpy(m_rptCall2, header.m_rptCall2, LONG_CALLSIGN_LENGTH); + } + + return *this; +} diff --git a/Common/HeaderData.h b/Common/HeaderData.h new file mode 100644 index 0000000..791ec36 --- /dev/null +++ b/Common/HeaderData.h @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2010-2014 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef HeaderData_H +#define HeaderData_H + +#include + +#if defined(__WINDOWS__) +#include "Inaddr.h" +#else +#include +#endif + +class CHeaderData { +public: + CHeaderData(); + CHeaderData(const CHeaderData& header); + CHeaderData(const wxString& myCall1, const wxString& myCall2, const wxString& yourCall, + const wxString& rptCall1, const wxString& rptCall2, unsigned char flag1 = 0x00, + unsigned char flag2 = 0x00, unsigned char flag3 = 0x00); + ~CHeaderData(); + + bool setIcomRepeaterData(const unsigned char* data, unsigned int length, bool check, const in_addr& yourAddress, unsigned int yourPort); + bool setHBRepeaterData(const unsigned char* data, unsigned int length, bool check, const in_addr& yourAddress, unsigned int yourPort); + bool setG2Data(const unsigned char* data, unsigned int length, bool check, const in_addr& yourAddress, unsigned int yourPort); + bool setDExtraData(const unsigned char* data, unsigned int length, bool check, const in_addr& yourAddress, unsigned int yourPort, unsigned int myPort); + bool setDPlusData(const unsigned char* data, unsigned int length, bool check, const in_addr& yourAddress, unsigned int yourPort, unsigned int myPort); + void setDCSData(const unsigned char* data, unsigned int length, const in_addr& yourAddress, unsigned int yourPort, unsigned int myPort); + void setCCSData(const unsigned char* data, unsigned int length, const in_addr& yourAddress, unsigned int yourPort, unsigned int myPort); + + unsigned int getIcomRepeaterData(unsigned char* data, unsigned int length, bool check) const; + unsigned int getHBRepeaterData(unsigned char* data, unsigned int length, bool check) const; + unsigned int getDExtraData(unsigned char* data, unsigned int length, bool check) const; + unsigned int getDPlusData(unsigned char* data, unsigned int length, bool check) const; + unsigned int getG2Data(unsigned char* data, unsigned int length, bool check) const; + void getDCSData(unsigned char* data, unsigned int length) const; + void getCCSData(unsigned char* data, unsigned int length) const; + + bool setDVTOOLData(const unsigned char* data, unsigned int length, bool check); + + unsigned int getId() const; + void setId(unsigned int id); + + unsigned char getBand1() const; + unsigned char getBand2() const; + unsigned char getBand3() const; + void setBand1(unsigned char band); + void setBand2(unsigned char band); + void setBand3(unsigned char band); + + unsigned int getRptSeq() const; + void setRptSeq(unsigned int seqNo); + + unsigned char getFlag1() const; + unsigned char getFlag2() const; + unsigned char getFlag3() const; + + wxString getMyCall1() const; + wxString getMyCall2() const; + wxString getYourCall() const; + wxString getRptCall1() const; + wxString getRptCall2() const; + + void setFlag1(unsigned char flag); + void setFlag2(unsigned char flag); + void setFlag3(unsigned char flag); + void setFlags(unsigned char flag1, unsigned char flag2, unsigned char flag3); + + void setMyCall1(const wxString& callsign); + void setMyCall2(const wxString& callsign); + void setYourCall(const wxString& callsign); + void setRptCall1(const wxString& callsign); + void setRptCall2(const wxString& callsign); + void setCQCQCQ(); + + void setRepeaters(const wxString& rpt1, const wxString& rpt2); + void setDestination(const in_addr& address, unsigned int port); + + bool setData(const unsigned char* data, unsigned int length, bool check); + unsigned int getData(unsigned char* data, unsigned int length, bool check) const; + + in_addr getYourAddress() const; + unsigned int getYourPort() const; + unsigned int getMyPort() const; + + unsigned int getErrors() const; + + static void initialise(); + static void finalise(); + static unsigned int createId(); + + CHeaderData& operator=(const CHeaderData& header); + +private: + unsigned int m_rptSeq; + unsigned int m_id; + unsigned char m_band1; + unsigned char m_band2; + unsigned char m_band3; + unsigned char m_flag1; + unsigned char m_flag2; + unsigned char m_flag3; + unsigned char* m_myCall1; + unsigned char* m_myCall2; + unsigned char* m_yourCall; + unsigned char* m_rptCall1; + unsigned char* m_rptCall2; + in_addr m_yourAddress; + unsigned int m_yourPort; + unsigned int m_myPort; + unsigned int m_errors; +}; + +#endif diff --git a/Common/HeaderLogger.cpp b/Common/HeaderLogger.cpp new file mode 100644 index 0000000..26eea68 --- /dev/null +++ b/Common/HeaderLogger.cpp @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2010,2011,2012,2014 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "HeaderLogger.h" +#include "Defs.h" + +#if !defined(__WXMSW__) +#include +#include +#include +#endif + +#include + +CHeaderLogger::CHeaderLogger(const wxString& dir, const wxString& name) : +m_dir(dir), +m_name(name), +m_file() +{ +} + +CHeaderLogger::~CHeaderLogger() +{ +} + +bool CHeaderLogger::open() +{ + wxString fullName = HEADERS_BASE_NAME; + + if (!m_name.IsEmpty()) { + fullName.Append(wxT("_")); + fullName.Append(m_name); + } + + wxFileName fileName(m_dir, fullName, wxT("log")); + + bool ret = m_file.Open(fileName.GetFullPath(), wxT("a+t")); + if (!ret) { + wxLogError(wxT("Cannot open %s file for appending"), fileName.GetFullPath().c_str()); + return false; + } + + return true; +} + +void CHeaderLogger::write(const wxChar* type, const CHeaderData& header) +{ + wxASSERT(type != NULL); + + time_t timeNow = ::time(NULL); + struct tm* tm = ::gmtime(&timeNow); + + char* t = ::inet_ntoa(header.getYourAddress()); + wxString address(t, wxConvLocal); + + wxString text; + text.Printf(wxT("%04d-%02d-%02d %02d:%02d:%02d: %s header - My: %s/%s Your: %s Rpt1: %s Rpt2: %s Flags: %02X %02X %02X (%s:%u)\n"), + tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, type, + header.getMyCall1().c_str(), header.getMyCall2().c_str(), header.getYourCall().c_str(), + header.getRptCall1().c_str(), header.getRptCall2().c_str(), header.getFlag1(), header.getFlag2(), + header.getFlag3(), address.c_str(), header.getYourPort()); + + m_file.Write(text); + m_file.Flush(); +} + +void CHeaderLogger::write(const wxChar* type, const CDDData& data) +{ + wxASSERT(type != NULL); + + time_t timeNow = ::time(NULL); + struct tm* tm = ::gmtime(&timeNow); + + wxString text; + text.Printf(wxT("%04d-%02d-%02d %02d:%02d:%02d: %s header - My: %s/%s Your: %s Rpt1: %s Rpt2: %s Flags: %02X %02X %02X\n"), + tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, type, + data.getMyCall1().c_str(), data.getMyCall2().c_str(), data.getYourCall().c_str(), + data.getRptCall1().c_str(), data.getRptCall2().c_str(), data.getFlag1(), data.getFlag2(), + data.getFlag3()); + + m_file.Write(text); + m_file.Flush(); +} + +void CHeaderLogger::close() +{ + m_file.Close(); +} diff --git a/Common/HeaderLogger.h b/Common/HeaderLogger.h new file mode 100644 index 0000000..8d1693c --- /dev/null +++ b/Common/HeaderLogger.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2010-2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef HeaderLogger_H +#define HeaderLogger_H + +#include "HeaderData.h" +#include "DDData.h" + +#include +#include + +class CHeaderLogger { +public: + CHeaderLogger(const wxString& dir, const wxString& name = wxEmptyString); + ~CHeaderLogger(); + + bool open(); + + void write(const wxChar* type, const CHeaderData& header); + void write(const wxChar* type, const CDDData& header); + + void close(); + +private: + wxString m_dir; + wxString m_name; + wxFFile m_file; +}; + +#endif diff --git a/Common/HeardData.cpp b/Common/HeardData.cpp new file mode 100644 index 0000000..e2d8f2e --- /dev/null +++ b/Common/HeardData.cpp @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2012,2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "HeardData.h" + +CHeardData::CHeardData() : +m_reflector(), +m_repeater(), +m_user(), +m_ext(), +m_address(), +m_port(0U) +{ +} + +CHeardData::CHeardData(const CHeardData& data) : +m_reflector(data.m_reflector), +m_repeater(data.m_repeater), +m_user(data.m_user), +m_ext(data.m_ext), +m_address(data.m_address), +m_port(data.m_port) +{ +} + +CHeardData::CHeardData(const CHeaderData& data, const wxString& repeater, const wxString& reflector) : +m_reflector(reflector), +m_repeater(repeater), +m_user(), +m_ext(), +m_address(), +m_port() +{ + m_user = data.getMyCall1(); + m_ext = data.getMyCall2(); +} + +CHeardData::~CHeardData() +{ +} + +bool CHeardData::setIcomRepeaterData(const unsigned char *data, unsigned int length, const in_addr& address, unsigned int port) +{ + wxASSERT(data != NULL); + wxASSERT(length >= 26U); + + m_user = wxString((char*)(data + 10U), wxConvLocal, LONG_CALLSIGN_LENGTH); + m_repeater = wxString((char*)(data + 18U), wxConvLocal, LONG_CALLSIGN_LENGTH); + + m_address = address; + m_port = port; + + return true; +} + +unsigned int CHeardData::getCCSData(unsigned char *data, unsigned int length) const +{ + wxASSERT(data != NULL); + wxASSERT(length >= 100U); + + ::memset(data, 0x00U, 100U); + + data[0U] = '0'; + data[1U] = '0'; + data[2U] = '0'; + data[3U] = '1'; + + ::memset(data + 7U, ' ', 36U); + + for (unsigned int i = 0U; i < m_reflector.Len(); i++) + data[i + 7U] = m_reflector.GetChar(i); + + for (unsigned int i = 0U; i < m_repeater.Len(); i++) + data[i + 15U] = m_repeater.GetChar(i); + + ::memcpy(data + 23U, "CQCQCQ ", LONG_CALLSIGN_LENGTH); + + for (unsigned int i = 0U; i < m_user.Len(); i++) + data[i + 31U] = m_user.GetChar(i); + + for (unsigned int i = 0U; i < m_ext.Len(); i++) + data[i + 39U] = m_ext.GetChar(i); + + data[61U] = 0x01U; + + data[63U] = 0x21U; + + ::memset(data + 64U, ' ', 20U); + + data[93U] = 0x36U; + + return 100U; +} + +wxString CHeardData::getRepeater() const +{ + return m_repeater; +} + +wxString CHeardData::getUser() const +{ + return m_user; +} + +void CHeardData::setDestination(const in_addr& address, unsigned int port) +{ + m_address = address; + m_port = port; +} + +in_addr CHeardData::getAddress() const +{ + return m_address; +} + +unsigned int CHeardData::getPort() const +{ + return m_port; +} diff --git a/Common/HeardData.h b/Common/HeardData.h new file mode 100644 index 0000000..61010fa --- /dev/null +++ b/Common/HeardData.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2012,2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef HeardData_H +#define HeardData_H + +#include + +#include "DStarDefines.h" +#include "HeaderData.h" + +#if defined(__WINDOWS__) +#include "Inaddr.h" +#else +#include +#endif + +class CHeardData { +public: + CHeardData(); + CHeardData(const CHeardData& data); + CHeardData(const CHeaderData& data, const wxString& repeater, const wxString& reflector); + ~CHeardData(); + + bool setIcomRepeaterData(const unsigned char* data, unsigned int length, const in_addr& address, unsigned int port); + + unsigned int getCCSData(unsigned char* data, unsigned int length) const; + + wxString getRepeater() const; + wxString getUser() const; + + void setDestination(const in_addr& address, unsigned int port); + + in_addr getAddress() const; + unsigned int getPort() const; + +private: + wxString m_reflector; + wxString m_repeater; + wxString m_user; + wxString m_ext; + in_addr m_address; + unsigned int m_port; +}; + +#endif diff --git a/Common/HostFile.cpp b/Common/HostFile.cpp new file mode 100644 index 0000000..13e174c --- /dev/null +++ b/Common/HostFile.cpp @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2010-2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "DStarDefines.h" +#include "HostFile.h" + +#include +#include +#include + +CHostFile::CHostFile(const wxString& fileName, bool logging) : +m_names(), +m_addresses(), +m_locks() +{ + if (!wxFile::Exists(fileName)) + return; + + wxTextFile file; + + bool ret = file.Open(fileName); + if (!ret) + return; + + if (logging) + wxLogMessage(wxT("Reading %s"), fileName.c_str()); + + unsigned int nLines = file.GetLineCount(); + + for (unsigned int i = 0; i < nLines; i++) { + wxString line = file.GetLine(i); + + if (line.length() > 0 && line.GetChar(0) != wxT('#')) { + wxStringTokenizer t(line, wxT(" \t\r\n"), wxTOKEN_STRTOK); + wxString name = t.GetNextToken(); + wxString address = t.GetNextToken(); + wxString lock = t.GetNextToken(); + + name.Append(wxT(" ")); + name.Truncate(LONG_CALLSIGN_LENGTH); + + if (!name.IsEmpty() && !address.IsEmpty()) { + m_names.Add(name); + m_addresses.Add(address); + m_locks.Add(lock.IsEmpty() ? 0 : 1); + } + } + } + + file.Close(); +} + +CHostFile::~CHostFile() +{ +} + +unsigned int CHostFile::getCount() const +{ + return m_names.GetCount(); +} + +wxString CHostFile::getName(unsigned int n) const +{ + return m_names.Item(n); +} + +wxString CHostFile::getAddress(unsigned int n) const +{ + return m_addresses.Item(n); +} + +wxString CHostFile::getAddress(const wxString& host) const +{ + wxString name = host; + name.resize(LONG_CALLSIGN_LENGTH, wxT(' ')); + + int n = m_names.Index(name); + if (n == wxNOT_FOUND) + return wxEmptyString; + + return m_addresses.Item(n); +} + +bool CHostFile::getLock(unsigned int n) const +{ + return m_locks.Item(n) == 1; +} + +wxArrayString CHostFile::getNames() const +{ + return m_names; +} diff --git a/Common/HostFile.h b/Common/HostFile.h new file mode 100644 index 0000000..c8b7a49 --- /dev/null +++ b/Common/HostFile.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2010-2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef HostFile_H +#define HostFile_H + +#include + +WX_DEFINE_ARRAY_INT(int, CArrayInt); + +class CHostFile { +public: + CHostFile(const wxString& fileName, bool logging); + ~CHostFile(); + + unsigned int getCount() const; + wxString getName(unsigned int n) const; + wxString getAddress(unsigned int n) const; + wxString getAddress(const wxString& host) const; + bool getLock(unsigned int n) const; + + wxArrayString getNames() const; + +private: + wxArrayString m_names; + wxArrayString m_addresses; + CArrayInt m_locks; +}; + +#endif diff --git a/Common/IRCDDBGatewayConfig.cpp b/Common/IRCDDBGatewayConfig.cpp new file mode 100644 index 0000000..9e97d14 --- /dev/null +++ b/Common/IRCDDBGatewayConfig.cpp @@ -0,0 +1,2651 @@ +/* + * Copyright (C) 2010-2015 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "IRCDDBGatewayConfig.h" + +#include + +const wxString KEY_GATEWAY_TYPE = wxT("gatewayType"); +const wxString KEY_GATEWAY_CALLSIGN = wxT("gatewayCallsign"); +const wxString KEY_GATEWAY_ADDRESS = wxT("gatewayAddress"); +const wxString KEY_ICOM_ADDRESS = wxT("icomAddress"); +const wxString KEY_ICOM_PORT = wxT("icomPort"); +const wxString KEY_HB_ADDRESS = wxT("hbAddress"); +const wxString KEY_HB_PORT = wxT("hbPort"); +const wxString KEY_LATITUDE = wxT("latitude"); +const wxString KEY_LONGITUDE = wxT("longitude"); +const wxString KEY_DESCRIPTION1 = wxT("description1"); +const wxString KEY_DESCRIPTION2 = wxT("description2"); +const wxString KEY_URL = wxT("url"); +const wxString KEY_REPEATER_CALL1 = wxT("repeaterCall1"); +const wxString KEY_REPEATER_BAND1 = wxT("repeaterBand1"); +const wxString KEY_REPEATER_TYPE1 = wxT("repeaterType1"); +const wxString KEY_REPEATER_ADDRESS1 = wxT("repeaterAddress1"); +const wxString KEY_REPEATER_PORT1 = wxT("repeaterPort1"); +const wxString KEY_REFLECTOR1 = wxT("reflector1"); +const wxString KEY_ATSTARTUP1 = wxT("atStartup1"); +const wxString KEY_RECONNECT1 = wxT("reconnect1"); +const wxString KEY_FREQUENCY1 = wxT("frequency1"); +const wxString KEY_OFFSET1 = wxT("offset1"); +const wxString KEY_RANGE1 = wxT("rangeKms1"); +const wxString KEY_LATITUDE1 = wxT("latitude1"); +const wxString KEY_LONGITUDE1 = wxT("longitude1"); +const wxString KEY_AGL1 = wxT("agl1"); +const wxString KEY_DESCRIPTION11 = wxT("description1_1"); +const wxString KEY_DESCRIPTION12 = wxT("description1_2"); +const wxString KEY_URL1 = wxT("url1"); +const wxString KEY_BAND11 = wxT("band1_1"); +const wxString KEY_BAND12 = wxT("band1_2"); +const wxString KEY_BAND13 = wxT("band1_3"); +const wxString KEY_REPEATER_CALL2 = wxT("repeaterCall2"); +const wxString KEY_REPEATER_BAND2 = wxT("repeaterBand2"); +const wxString KEY_REPEATER_TYPE2 = wxT("repeaterType2"); +const wxString KEY_REPEATER_ADDRESS2 = wxT("repeaterAddress2"); +const wxString KEY_REPEATER_PORT2 = wxT("repeaterPort2"); +const wxString KEY_REFLECTOR2 = wxT("reflector2"); +const wxString KEY_ATSTARTUP2 = wxT("atStartup2"); +const wxString KEY_RECONNECT2 = wxT("reconnect2"); +const wxString KEY_FREQUENCY2 = wxT("frequency2"); +const wxString KEY_OFFSET2 = wxT("offset2"); +const wxString KEY_RANGE2 = wxT("rangeKms2"); +const wxString KEY_LATITUDE2 = wxT("latitude2"); +const wxString KEY_LONGITUDE2 = wxT("longitude2"); +const wxString KEY_AGL2 = wxT("agl2"); +const wxString KEY_DESCRIPTION21 = wxT("description2_1"); +const wxString KEY_DESCRIPTION22 = wxT("description2_2"); +const wxString KEY_URL2 = wxT("url2"); +const wxString KEY_BAND21 = wxT("band2_1"); +const wxString KEY_BAND22 = wxT("band2_2"); +const wxString KEY_BAND23 = wxT("band2_3"); +const wxString KEY_REPEATER_CALL3 = wxT("repeaterCall3"); +const wxString KEY_REPEATER_BAND3 = wxT("repeaterBand3"); +const wxString KEY_REPEATER_TYPE3 = wxT("repeaterType3"); +const wxString KEY_REPEATER_ADDRESS3 = wxT("repeaterAddress3"); +const wxString KEY_REPEATER_PORT3 = wxT("repeaterPort3"); +const wxString KEY_REFLECTOR3 = wxT("reflector3"); +const wxString KEY_ATSTARTUP3 = wxT("atStartup3"); +const wxString KEY_RECONNECT3 = wxT("reconnect3"); +const wxString KEY_FREQUENCY3 = wxT("frequency3"); +const wxString KEY_OFFSET3 = wxT("offset3"); +const wxString KEY_RANGE3 = wxT("rangeKms3"); +const wxString KEY_LATITUDE3 = wxT("latitude3"); +const wxString KEY_LONGITUDE3 = wxT("longitude3"); +const wxString KEY_AGL3 = wxT("agl3"); +const wxString KEY_DESCRIPTION31 = wxT("description3_1"); +const wxString KEY_DESCRIPTION32 = wxT("description3_2"); +const wxString KEY_URL3 = wxT("url3"); +const wxString KEY_BAND31 = wxT("band3_1"); +const wxString KEY_BAND32 = wxT("band3_2"); +const wxString KEY_BAND33 = wxT("band3_3"); +const wxString KEY_REPEATER_CALL4 = wxT("repeaterCall4"); +const wxString KEY_REPEATER_BAND4 = wxT("repeaterBand4"); +const wxString KEY_REPEATER_TYPE4 = wxT("repeaterType4"); +const wxString KEY_REPEATER_ADDRESS4 = wxT("repeaterAddress4"); +const wxString KEY_REPEATER_PORT4 = wxT("repeaterPort4"); +const wxString KEY_REFLECTOR4 = wxT("reflector4"); +const wxString KEY_ATSTARTUP4 = wxT("atStartup4"); +const wxString KEY_RECONNECT4 = wxT("reconnect4"); +const wxString KEY_FREQUENCY4 = wxT("frequency4"); +const wxString KEY_OFFSET4 = wxT("offset4"); +const wxString KEY_RANGE4 = wxT("rangeKms4"); +const wxString KEY_LATITUDE4 = wxT("latitude4"); +const wxString KEY_LONGITUDE4 = wxT("longitude4"); +const wxString KEY_AGL4 = wxT("agl4"); +const wxString KEY_DESCRIPTION41 = wxT("description4_1"); +const wxString KEY_DESCRIPTION42 = wxT("description4_2"); +const wxString KEY_URL4 = wxT("url4"); +const wxString KEY_BAND41 = wxT("band4_1"); +const wxString KEY_BAND42 = wxT("band4_2"); +const wxString KEY_BAND43 = wxT("band4_3"); +const wxString KEY_IRCDDB_ENABLED = wxT("ircddbEnabled"); +const wxString KEY_IRCDDB_HOSTNAME = wxT("ircddbHostname"); +const wxString KEY_IRCDDB_USERNAME = wxT("ircddbUsername"); +const wxString KEY_IRCDDB_PASSWORD = wxT("ircddbPassword"); +const wxString KEY_IRCDDB_ENABLED2 = wxT("ircddbEnabled2"); +const wxString KEY_IRCDDB_HOSTNAME2 = wxT("ircddbHostname2"); +const wxString KEY_IRCDDB_USERNAME2 = wxT("ircddbUsername2"); +const wxString KEY_IRCDDB_PASSWORD2 = wxT("ircddbPassword2"); +const wxString KEY_IRCDDB_ENABLED3 = wxT("ircddbEnabled3"); +const wxString KEY_IRCDDB_HOSTNAME3 = wxT("ircddbHostname3"); +const wxString KEY_IRCDDB_USERNAME3 = wxT("ircddbUsername3"); +const wxString KEY_IRCDDB_PASSWORD3 = wxT("ircddbPassword3"); +const wxString KEY_IRCDDB_ENABLED4 = wxT("ircddbEnabled4"); +const wxString KEY_IRCDDB_HOSTNAME4 = wxT("ircddbHostname4"); +const wxString KEY_IRCDDB_USERNAME4 = wxT("ircddbUsername4"); +const wxString KEY_IRCDDB_PASSWORD4 = wxT("ircddbPassword4"); +const wxString KEY_APRS_ENABLED = wxT("aprsEnabled"); +const wxString KEY_APRS_HOSTNAME = wxT("aprsHostname"); +const wxString KEY_APRS_PORT = wxT("aprsPort"); +const wxString KEY_DEXTRA_ENABLED = wxT("dextraEnabled"); +const wxString KEY_DEXTRA_MAXDONGLES = wxT("dextraMaxDongles"); +const wxString KEY_DPLUS_ENABLED = wxT("dplusEnabled"); +const wxString KEY_DPLUS_MAXDONGLES = wxT("dplusMaxDongles"); +const wxString KEY_DPLUS_LOGIN = wxT("dplusLogin"); +const wxString KEY_DCS_ENABLED = wxT("dcsEnabled"); +const wxString KEY_CCS_ENABLED = wxT("ccsEnabled"); +const wxString KEY_CCS_HOST = wxT("ccsHost"); +const wxString KEY_XLX_ENABLED = wxT("xlxEnabled"); +const wxString KEY_XLX_OVERRIDE_LOCAL = wxT("xlxOverrideLocal"); +const wxString KEY_XLX_HOSTS_FILE_URL = wxT("xlxHostsFileUrl"); +const wxString KEY_STARNET_BAND1 = wxT("starNetBand1"); +const wxString KEY_STARNET_CALLSIGN1 = wxT("starNetCallsign1"); +const wxString KEY_STARNET_LOGOFF1 = wxT("starNetLogoff1"); +const wxString KEY_STARNET_INFO1 = wxT("starNetInfo1"); +const wxString KEY_STARNET_PERMANENT1 = wxT("starNetPermanent1"); +const wxString KEY_STARNET_USER_TIMEOUT1 = wxT("starNetUserTimeout1"); +const wxString KEY_STARNET_GROUP_TIMEOUT1 = wxT("starNetGroupTimeout1"); +const wxString KEY_STARNET_CALLSIGN_SWITCH1 = wxT("starNetCallsignSwitch1"); +const wxString KEY_STARNET_TXMSG_SWITCH1 = wxT("starNetTXMsgSwitch1"); +const wxString KEY_STARNET_REFLECTOR1 = wxT("starNetReflector1"); // DEXTRA_LINK +const wxString KEY_STARNET_BAND2 = wxT("starNetBand2"); +const wxString KEY_STARNET_CALLSIGN2 = wxT("starNetCallsign2"); +const wxString KEY_STARNET_LOGOFF2 = wxT("starNetLogoff2"); +const wxString KEY_STARNET_INFO2 = wxT("starNetInfo2"); +const wxString KEY_STARNET_PERMANENT2 = wxT("starNetPermanent2"); +const wxString KEY_STARNET_USER_TIMEOUT2 = wxT("starNetUserTimeout2"); +const wxString KEY_STARNET_GROUP_TIMEOUT2 = wxT("starNetGroupTimeout2"); +const wxString KEY_STARNET_CALLSIGN_SWITCH2 = wxT("starNetCallsignSwitch2"); +const wxString KEY_STARNET_TXMSG_SWITCH2 = wxT("starNetTXMsgSwitch2"); +const wxString KEY_STARNET_REFLECTOR2 = wxT("starNetReflector2"); // DEXTRA_LINK +const wxString KEY_STARNET_BAND3 = wxT("starNetBand3"); +const wxString KEY_STARNET_CALLSIGN3 = wxT("starNetCallsign3"); +const wxString KEY_STARNET_LOGOFF3 = wxT("starNetLogoff3"); +const wxString KEY_STARNET_INFO3 = wxT("starNetInfo3"); +const wxString KEY_STARNET_PERMANENT3 = wxT("starNetPermanent3"); +const wxString KEY_STARNET_USER_TIMEOUT3 = wxT("starNetUserTimeout3"); +const wxString KEY_STARNET_GROUP_TIMEOUT3 = wxT("starNetGroupTimeout3"); +const wxString KEY_STARNET_CALLSIGN_SWITCH3 = wxT("starNetCallsignSwitch3"); +const wxString KEY_STARNET_TXMSG_SWITCH3 = wxT("starNetTXMsgSwitch3"); +const wxString KEY_STARNET_REFLECTOR3 = wxT("starNetReflector3"); // DEXTRA_LINK +const wxString KEY_STARNET_BAND4 = wxT("starNetBand4"); +const wxString KEY_STARNET_CALLSIGN4 = wxT("starNetCallsign4"); +const wxString KEY_STARNET_LOGOFF4 = wxT("starNetLogoff4"); +const wxString KEY_STARNET_INFO4 = wxT("starNetInfo4"); +const wxString KEY_STARNET_PERMANENT4 = wxT("starNetPermanent4"); +const wxString KEY_STARNET_USER_TIMEOUT4 = wxT("starNetUserTimeout4"); +const wxString KEY_STARNET_GROUP_TIMEOUT4 = wxT("starNetGroupTimeout4"); +const wxString KEY_STARNET_CALLSIGN_SWITCH4 = wxT("starNetCallsignSwitch4"); +const wxString KEY_STARNET_TXMSG_SWITCH4 = wxT("starNetTXMsgSwitch4"); +const wxString KEY_STARNET_REFLECTOR4 = wxT("starNetReflector4"); // DEXTRA_LINK +const wxString KEY_STARNET_BAND5 = wxT("starNetBand5"); +const wxString KEY_STARNET_CALLSIGN5 = wxT("starNetCallsign5"); +const wxString KEY_STARNET_LOGOFF5 = wxT("starNetLogoff5"); +const wxString KEY_STARNET_INFO5 = wxT("starNetInfo5"); +const wxString KEY_STARNET_PERMANENT5 = wxT("starNetPermanent5"); +const wxString KEY_STARNET_USER_TIMEOUT5 = wxT("starNetUserTimeout5"); +const wxString KEY_STARNET_GROUP_TIMEOUT5 = wxT("starNetGroupTimeout5"); +const wxString KEY_STARNET_CALLSIGN_SWITCH5 = wxT("starNetCallsignSwitch5"); +const wxString KEY_STARNET_TXMSG_SWITCH5 = wxT("starNetTXMsgSwitch5"); +const wxString KEY_STARNET_REFLECTOR5 = wxT("starNetReflector5"); // DEXTRA_LINK +const wxString KEY_REMOTE_ENABLED = wxT("remoteEnabled"); +const wxString KEY_REMOTE_PASSWORD = wxT("remotePassword"); +const wxString KEY_REMOTE_PORT = wxT("remotePort"); +const wxString KEY_LANGUAGE = wxT("language"); +const wxString KEY_INFO_ENABLED = wxT("infoEnabled"); +const wxString KEY_ECHO_ENABLED = wxT("echoEnabled"); +const wxString KEY_LOG_ENABLED = wxT("logEnabled"); +const wxString KEY_DRATS_ENABLED = wxT("dratsEnabled"); +const wxString KEY_DTMF_ENABLED = wxT("dtmfEnabled"); +const wxString KEY_WINDOW_X = wxT("windowX"); +const wxString KEY_WINDOW_Y = wxT("windowY"); + +const GATEWAY_TYPE DEFAULT_GATEWAY_TYPE = GT_REPEATER; +const wxString DEFAULT_GATEWAY_CALLSIGN = wxEmptyString; +const wxString DEFAULT_GATEWAY_ADDRESS = wxEmptyString; +const wxString DEFAULT_ICOM_ADDRESS = wxT("172.16.0.20"); +const unsigned int DEFAULT_ICOM_PORT = 20000U; +const wxString DEFAULT_HB_ADDRESS = wxT("127.0.0.1"); +const unsigned int DEFAULT_HB_PORT = 20010U; +const double DEFAULT_LATITUDE = 0.0; +const double DEFAULT_LONGITUDE = 0.0; +const wxString DEFAULT_DESCRIPTION1 = wxEmptyString; +const wxString DEFAULT_DESCRIPTION2 = wxEmptyString; +const wxString DEFAULT_URL = wxEmptyString; +const wxString DEFAULT_REPEATER_CALL = wxEmptyString; +const wxString DEFAULT_REPEATER_BAND = wxT(" "); +const HW_TYPE DEFAULT_REPEATER_TYPE = HW_HOMEBREW; +const wxString DEFAULT_REPEATER_ADDRESS = wxT("127.0.0.1"); +const wxString DEFAULT_REFLECTOR = wxEmptyString; +const bool DEFAULT_ATSTARTUP = false; +const RECONNECT DEFAULT_RECONNECT = RECONNECT_NEVER; +const double DEFAULT_FREQUENCY = 0.0; +const double DEFAULT_OFFSET = 0.0; +const double DEFAULT_RANGE = 0.0; +const double DEFAULT_AGL = 0.0; +const unsigned char DEFAULT_BAND1 = 0x00U; +const unsigned char DEFAULT_BAND2 = 0x00U; +const unsigned char DEFAULT_BAND3 = 0x00U; +const unsigned int DEFAULT_REPEATER_PORT1 = 20011U; +const unsigned int DEFAULT_REPEATER_PORT2 = 20012U; +const unsigned int DEFAULT_REPEATER_PORT3 = 20013U; +const unsigned int DEFAULT_REPEATER_PORT4 = 20014U; +const bool DEFAULT_IRCDDB_ENABLED = true; +const wxString DEFAULT_IRCDDB_HOSTNAME = wxT("group1-irc.ircddb.net"); +const wxString DEFAULT_IRCDDB_USERNAME = wxEmptyString; +const wxString DEFAULT_IRCDDB_PASSWORD = wxEmptyString; +const bool DEFAULT_IRCDDB_ENABLED2 = true; +const wxString DEFAULT_IRCDDB_HOSTNAME2 = wxT("rr.openquad.net"); +const wxString DEFAULT_IRCDDB_USERNAME2 = wxEmptyString; +const wxString DEFAULT_IRCDDB_PASSWORD2 = wxEmptyString; +const bool DEFAULT_IRCDDB_ENABLED3 = false; +const wxString DEFAULT_IRCDDB_HOSTNAME3 = wxEmptyString; +const wxString DEFAULT_IRCDDB_USERNAME3 = wxEmptyString; +const wxString DEFAULT_IRCDDB_PASSWORD3 = wxEmptyString; +const bool DEFAULT_IRCDDB_ENABLED4 = false; +const wxString DEFAULT_IRCDDB_HOSTNAME4 = wxEmptyString; +const wxString DEFAULT_IRCDDB_USERNAME4 = wxEmptyString; +const wxString DEFAULT_IRCDDB_PASSWORD4 = wxEmptyString; +const bool DEFAULT_APRS_ENABLED = true; +const wxString DEFAULT_APRS_HOSTNAME = wxT("rotate.aprs2.net"); +const unsigned int DEFAULT_APRS_PORT = 14580U; +const bool DEFAULT_DEXTRA_ENABLED = true; +const unsigned int DEFAULT_DEXTRA_MAXDONGLES = 5U; +const bool DEFAULT_DPLUS_ENABLED = false; +const unsigned int DEFAULT_DPLUS_MAXDONGLES = 5U; +const wxString DEFAULT_DPLUS_LOGIN = wxEmptyString; +const bool DEFAULT_DCS_ENABLED = true; +const bool DEFAULT_CCS_ENABLED = true; +const wxString DEFAULT_CCS_HOST = wxT("CCS704 "); +const bool DEFAULT_XLX_ENABLED = true; +const bool DEFAULT_XLX_OVERRIDE_LOCAL = true; +const wxString DEFAULT_XLX_HOSTS_FILE_URL = _T("http://xlxapi.rlx.lu/api.php?do=GetReflectorHostname"); +const wxString DEFAULT_STARNET_BAND = wxEmptyString; +const wxString DEFAULT_STARNET_CALLSIGN = wxEmptyString; +const wxString DEFAULT_STARNET_LOGOFF = wxEmptyString; +const wxString DEFAULT_STARNET_INFO = wxEmptyString; +const wxString DEFAULT_STARNET_PERMANENT = wxEmptyString; +const unsigned int DEFAULT_STARNET_USER_TIMEOUT = 300U; +const unsigned int DEFAULT_STARNET_GROUP_TIMEOUT = 300U; +const STARNET_CALLSIGN_SWITCH DEFAULT_STARNET_CALLSIGN_SWITCH = SCS_GROUP_CALLSIGN; +const bool DEFAULT_STARNET_TXMSG_SWITCH = true; +const wxString DEFAULT_STARNET_REFLECTOR = wxEmptyString; +const bool DEFAULT_REMOTE_ENABLED = false; +const wxString DEFAULT_REMOTE_PASSWORD = wxEmptyString; +const unsigned int DEFAULT_REMOTE_PORT = 0U; +const TEXT_LANG DEFAULT_LANGUAGE = TL_ENGLISH_UK; +const bool DEFAULT_LOG_ENABLED = false; +const bool DEFAULT_INFO_ENABLED = true; +const bool DEFAULT_ECHO_ENABLED = true; +const bool DEFAULT_DRATS_ENABLED = false; +const bool DEFAULT_DTMF_ENABLED = true; +const int DEFAULT_WINDOW_X = -1; +const int DEFAULT_WINDOW_Y = -1; + + +#if defined(__WINDOWS__) + +CIRCDDBGatewayConfig::CIRCDDBGatewayConfig(wxConfigBase* config, const wxString& dir, const wxString& configName, const wxString& name) : +m_config(config), +m_name(wxT("/")), +m_fileName(), +m_type(DEFAULT_GATEWAY_TYPE), +m_callsign(DEFAULT_GATEWAY_CALLSIGN), +m_address(DEFAULT_GATEWAY_ADDRESS), +m_icomAddress(DEFAULT_ICOM_ADDRESS), +m_icomPort(DEFAULT_ICOM_PORT), +m_hbAddress(DEFAULT_HB_ADDRESS), +m_hbPort(DEFAULT_HB_PORT), +m_latitude(DEFAULT_LATITUDE), +m_longitude(DEFAULT_LONGITUDE), +m_description1(DEFAULT_DESCRIPTION1), +m_description2(DEFAULT_DESCRIPTION2), +m_url(DEFAULT_URL), +m_repeater1Callsign(DEFAULT_REPEATER_CALL), +m_repeater1Band(DEFAULT_REPEATER_BAND), +m_repeater1Type(DEFAULT_REPEATER_TYPE), +m_repeater1Address(DEFAULT_REPEATER_ADDRESS), +m_repeater1Port(DEFAULT_REPEATER_PORT1), +m_repeater1Reflector(DEFAULT_REFLECTOR), +m_repeater1AtStartup(DEFAULT_ATSTARTUP), +m_repeater1Reconnect(DEFAULT_RECONNECT), +m_repeater1Frequency(DEFAULT_FREQUENCY), +m_repeater1Offset(DEFAULT_OFFSET), +m_repeater1Range(DEFAULT_RANGE), +m_repeater1Latitude(DEFAULT_LATITUDE), +m_repeater1Longitude(DEFAULT_LONGITUDE), +m_repeater1Agl(DEFAULT_AGL), +m_repeater1Description1(DEFAULT_DESCRIPTION1), +m_repeater1Description2(DEFAULT_DESCRIPTION2), +m_repeater1URL(DEFAULT_URL), +m_repeater1Band1(DEFAULT_BAND1), +m_repeater1Band2(DEFAULT_BAND2), +m_repeater1Band3(DEFAULT_BAND2), +m_repeater2Callsign(DEFAULT_REPEATER_CALL), +m_repeater2Band(DEFAULT_REPEATER_BAND), +m_repeater2Type(DEFAULT_REPEATER_TYPE), +m_repeater2Address(DEFAULT_REPEATER_ADDRESS), +m_repeater2Port(DEFAULT_REPEATER_PORT2), +m_repeater2Reflector(DEFAULT_REFLECTOR), +m_repeater2AtStartup(DEFAULT_ATSTARTUP), +m_repeater2Reconnect(DEFAULT_RECONNECT), +m_repeater2Frequency(DEFAULT_FREQUENCY), +m_repeater2Offset(DEFAULT_OFFSET), +m_repeater2Range(DEFAULT_RANGE), +m_repeater2Latitude(DEFAULT_LATITUDE), +m_repeater2Longitude(DEFAULT_LONGITUDE), +m_repeater2Agl(DEFAULT_AGL), +m_repeater2Description1(DEFAULT_DESCRIPTION1), +m_repeater2Description2(DEFAULT_DESCRIPTION2), +m_repeater2URL(DEFAULT_URL), +m_repeater2Band1(DEFAULT_BAND1), +m_repeater2Band2(DEFAULT_BAND2), +m_repeater2Band3(DEFAULT_BAND3), +m_repeater3Callsign(DEFAULT_REPEATER_CALL), +m_repeater3Band(DEFAULT_REPEATER_BAND), +m_repeater3Type(DEFAULT_REPEATER_TYPE), +m_repeater3Address(DEFAULT_REPEATER_ADDRESS), +m_repeater3Port(DEFAULT_REPEATER_PORT3), +m_repeater3Reflector(DEFAULT_REFLECTOR), +m_repeater3AtStartup(DEFAULT_ATSTARTUP), +m_repeater3Reconnect(DEFAULT_RECONNECT), +m_repeater3Frequency(DEFAULT_FREQUENCY), +m_repeater3Offset(DEFAULT_OFFSET), +m_repeater3Range(DEFAULT_RANGE), +m_repeater3Latitude(DEFAULT_LATITUDE), +m_repeater3Longitude(DEFAULT_LONGITUDE), +m_repeater3Agl(DEFAULT_AGL), +m_repeater3Description1(DEFAULT_DESCRIPTION1), +m_repeater3Description2(DEFAULT_DESCRIPTION2), +m_repeater3URL(DEFAULT_URL), +m_repeater3Band1(DEFAULT_BAND1), +m_repeater3Band2(DEFAULT_BAND2), +m_repeater3Band3(DEFAULT_BAND3), +m_repeater4Callsign(DEFAULT_REPEATER_CALL), +m_repeater4Band(DEFAULT_REPEATER_BAND), +m_repeater4Type(DEFAULT_REPEATER_TYPE), +m_repeater4Address(DEFAULT_REPEATER_ADDRESS), +m_repeater4Port(DEFAULT_REPEATER_PORT4), +m_repeater4Reflector(DEFAULT_REFLECTOR), +m_repeater4AtStartup(DEFAULT_ATSTARTUP), +m_repeater4Reconnect(DEFAULT_RECONNECT), +m_repeater4Frequency(DEFAULT_FREQUENCY), +m_repeater4Offset(DEFAULT_OFFSET), +m_repeater4Range(DEFAULT_RANGE), +m_repeater4Latitude(DEFAULT_LATITUDE), +m_repeater4Longitude(DEFAULT_LONGITUDE), +m_repeater4Agl(DEFAULT_AGL), +m_repeater4Description1(DEFAULT_DESCRIPTION1), +m_repeater4Description2(DEFAULT_DESCRIPTION2), +m_repeater4URL(DEFAULT_URL), +m_repeater4Band1(DEFAULT_BAND1), +m_repeater4Band2(DEFAULT_BAND2), +m_repeater4Band3(DEFAULT_BAND3), +m_ircddbEnabled(DEFAULT_IRCDDB_ENABLED), +m_ircddbHostname(DEFAULT_IRCDDB_HOSTNAME), +m_ircddbUsername(DEFAULT_IRCDDB_USERNAME), +m_ircddbPassword(DEFAULT_IRCDDB_PASSWORD), +m_ircddbEnabled2(DEFAULT_IRCDDB_ENABLED2), +m_ircddbHostname2(DEFAULT_IRCDDB_HOSTNAME2), +m_ircddbUsername2(DEFAULT_IRCDDB_USERNAME2), +m_ircddbPassword2(DEFAULT_IRCDDB_PASSWORD2), +m_ircddbEnabled3(DEFAULT_IRCDDB_ENABLED3), +m_ircddbHostname3(DEFAULT_IRCDDB_HOSTNAME3), +m_ircddbUsername3(DEFAULT_IRCDDB_USERNAME3), +m_ircddbPassword3(DEFAULT_IRCDDB_PASSWORD3), +m_ircddbEnabled4(DEFAULT_IRCDDB_ENABLED4), +m_ircddbHostname4(DEFAULT_IRCDDB_HOSTNAME4), +m_ircddbUsername4(DEFAULT_IRCDDB_USERNAME4), +m_ircddbPassword4(DEFAULT_IRCDDB_PASSWORD4), +m_aprsEnabled(DEFAULT_APRS_ENABLED), +m_aprsHostname(DEFAULT_APRS_HOSTNAME), +m_aprsPort(DEFAULT_APRS_PORT), +m_dextraEnabled(DEFAULT_DEXTRA_ENABLED), +m_dextraMaxDongles(DEFAULT_DEXTRA_MAXDONGLES), +m_dplusEnabled(DEFAULT_DPLUS_ENABLED), +m_dplusMaxDongles(DEFAULT_DPLUS_MAXDONGLES), +m_dplusLogin(DEFAULT_DPLUS_LOGIN), +m_dcsEnabled(DEFAULT_DCS_ENABLED), +m_ccsEnabled(DEFAULT_CCS_ENABLED), +m_ccsHost(DEFAULT_CCS_HOST), +m_xlxEnabled(DEFAULT_XLX_ENABLED), +m_xlxOverrideLocal(DEFAULT_XLX_OVERRIDE_LOCAL), +m_xlxHostsFileUrl(DEFAULT_XLX_HOSTS_FILE_URL), +m_starNet1Band(DEFAULT_STARNET_BAND), +m_starNet1Callsign(DEFAULT_STARNET_CALLSIGN), +m_starNet1Logoff(DEFAULT_STARNET_LOGOFF), +m_starNet1Info(DEFAULT_STARNET_INFO), +m_starNet1Permanent(DEFAULT_STARNET_PERMANENT), +m_starNet1UserTimeout(DEFAULT_STARNET_USER_TIMEOUT), +m_starNet1GroupTimeout(DEFAULT_STARNET_GROUP_TIMEOUT), +m_starNet1CallsignSwitch(DEFAULT_STARNET_CALLSIGN_SWITCH), +m_starNet1TxMsgSwitch(DEFAULT_STARNET_TXMSG_SWITCH), +m_starNet1Reflector(DEFAULT_STARNET_REFLECTOR), +m_starNet2Band(DEFAULT_STARNET_BAND), +m_starNet2Callsign(DEFAULT_STARNET_CALLSIGN), +m_starNet2Logoff(DEFAULT_STARNET_LOGOFF), +m_starNet2Info(DEFAULT_STARNET_INFO), +m_starNet2Permanent(DEFAULT_STARNET_PERMANENT), +m_starNet2UserTimeout(DEFAULT_STARNET_USER_TIMEOUT), +m_starNet2GroupTimeout(DEFAULT_STARNET_GROUP_TIMEOUT), +m_starNet2CallsignSwitch(DEFAULT_STARNET_CALLSIGN_SWITCH), +m_starNet2TxMsgSwitch(DEFAULT_STARNET_TXMSG_SWITCH), +m_starNet2Reflector(DEFAULT_STARNET_REFLECTOR), +m_starNet3Band(DEFAULT_STARNET_BAND), +m_starNet3Callsign(DEFAULT_STARNET_CALLSIGN), +m_starNet3Logoff(DEFAULT_STARNET_LOGOFF), +m_starNet3Info(DEFAULT_STARNET_INFO), +m_starNet3Permanent(DEFAULT_STARNET_PERMANENT), +m_starNet3UserTimeout(DEFAULT_STARNET_USER_TIMEOUT), +m_starNet3GroupTimeout(DEFAULT_STARNET_GROUP_TIMEOUT), +m_starNet3CallsignSwitch(DEFAULT_STARNET_CALLSIGN_SWITCH), +m_starNet3TxMsgSwitch(DEFAULT_STARNET_TXMSG_SWITCH), +m_starNet3Reflector(DEFAULT_STARNET_REFLECTOR), +m_starNet4Band(DEFAULT_STARNET_BAND), +m_starNet4Callsign(DEFAULT_STARNET_CALLSIGN), +m_starNet4Logoff(DEFAULT_STARNET_LOGOFF), +m_starNet4Info(DEFAULT_STARNET_INFO), +m_starNet4Permanent(DEFAULT_STARNET_PERMANENT), +m_starNet4UserTimeout(DEFAULT_STARNET_USER_TIMEOUT), +m_starNet4GroupTimeout(DEFAULT_STARNET_GROUP_TIMEOUT), +m_starNet4CallsignSwitch(DEFAULT_STARNET_CALLSIGN_SWITCH), +m_starNet4TxMsgSwitch(DEFAULT_STARNET_TXMSG_SWITCH), +m_starNet4Reflector(DEFAULT_STARNET_REFLECTOR), +m_starNet5Band(DEFAULT_STARNET_BAND), +m_starNet5Callsign(DEFAULT_STARNET_CALLSIGN), +m_starNet5Logoff(DEFAULT_STARNET_LOGOFF), +m_starNet5Info(DEFAULT_STARNET_INFO), +m_starNet5Permanent(DEFAULT_STARNET_PERMANENT), +m_starNet5UserTimeout(DEFAULT_STARNET_USER_TIMEOUT), +m_starNet5GroupTimeout(DEFAULT_STARNET_GROUP_TIMEOUT), +m_starNet5CallsignSwitch(DEFAULT_STARNET_CALLSIGN_SWITCH), +m_starNet5TxMsgSwitch(DEFAULT_STARNET_TXMSG_SWITCH), +m_starNet5Reflector(DEFAULT_STARNET_REFLECTOR), +m_remoteEnabled(DEFAULT_REMOTE_ENABLED), +m_remotePassword(DEFAULT_REMOTE_PASSWORD), +m_remotePort(DEFAULT_REMOTE_PORT), +m_language(DEFAULT_LANGUAGE), +m_infoEnabled(DEFAULT_INFO_ENABLED), +m_echoEnabled(DEFAULT_ECHO_ENABLED), +m_logEnabled(DEFAULT_LOG_ENABLED), +m_dratsEnabled(DEFAULT_DRATS_ENABLED), +m_dtmfEnabled(DEFAULT_DTMF_ENABLED), +m_x(DEFAULT_WINDOW_X), +m_y(DEFAULT_WINDOW_Y) +{ + wxASSERT(config != NULL); + wxASSERT(!dir.IsEmpty()); + + wxString fileName = configName; + if (!name.IsEmpty()) { + fileName = configName + wxT("_") + name; + m_name = wxT("/") + name + wxT("/"); + } + + m_fileName.Assign(dir, fileName); + + long temp; + + m_config->Read(m_name + KEY_GATEWAY_TYPE, &temp, long(DEFAULT_GATEWAY_TYPE)); + m_type = GATEWAY_TYPE(temp); + + m_config->Read(m_name + KEY_GATEWAY_CALLSIGN, &m_callsign, DEFAULT_GATEWAY_CALLSIGN); + + m_config->Read(m_name + KEY_GATEWAY_ADDRESS, &m_address, DEFAULT_GATEWAY_ADDRESS); + + m_config->Read(m_name + KEY_ICOM_ADDRESS, &m_icomAddress, DEFAULT_ICOM_ADDRESS); + + m_config->Read(m_name + KEY_ICOM_PORT, &temp, long(DEFAULT_ICOM_PORT)); + m_icomPort = (unsigned int)temp; + + m_config->Read(m_name + KEY_HB_ADDRESS, &m_hbAddress, DEFAULT_HB_ADDRESS); + + m_config->Read(m_name + KEY_HB_PORT, &temp, long(DEFAULT_HB_PORT)); + m_hbPort = (unsigned int)temp; + + m_config->Read(m_name + KEY_LATITUDE, &m_latitude, DEFAULT_LATITUDE); + + m_config->Read(m_name + KEY_LONGITUDE, &m_longitude, DEFAULT_LONGITUDE); + + m_config->Read(m_name + KEY_DESCRIPTION1, &m_description1, DEFAULT_DESCRIPTION1); + + m_config->Read(m_name + KEY_DESCRIPTION2, &m_description2, DEFAULT_DESCRIPTION2); + + m_config->Read(m_name + KEY_URL, &m_url, DEFAULT_URL); + + m_config->Read(m_name + KEY_REPEATER_CALL1, &m_repeater1Callsign, DEFAULT_REPEATER_CALL); + + m_config->Read(m_name + KEY_REPEATER_BAND1, &m_repeater1Band, DEFAULT_REPEATER_BAND); + + m_config->Read(m_name + KEY_REPEATER_TYPE1, &temp, long(DEFAULT_REPEATER_TYPE)); + m_repeater1Type = HW_TYPE(temp); + + m_config->Read(m_name + KEY_REPEATER_ADDRESS1, &m_repeater1Address, DEFAULT_REPEATER_ADDRESS); + + m_config->Read(m_name + KEY_REPEATER_PORT1, &temp, long(DEFAULT_REPEATER_PORT1)); + m_repeater1Port = (unsigned int)temp; + + m_config->Read(m_name + KEY_REFLECTOR1, &m_repeater1Reflector, DEFAULT_REFLECTOR); + + m_config->Read(m_name + KEY_ATSTARTUP1, &m_repeater1AtStartup, DEFAULT_ATSTARTUP); + + m_config->Read(m_name + KEY_RECONNECT1, &temp, long(DEFAULT_RECONNECT)); + m_repeater1Reconnect = RECONNECT(temp); + + m_config->Read(m_name + KEY_FREQUENCY1, &m_repeater1Frequency, DEFAULT_FREQUENCY); + + m_config->Read(m_name + KEY_OFFSET1, &m_repeater1Offset, DEFAULT_OFFSET); + + m_config->Read(m_name + KEY_RANGE1, &m_repeater1Range, DEFAULT_RANGE); + + m_config->Read(m_name + KEY_LATITUDE1, &m_repeater1Latitude, DEFAULT_LATITUDE); + + m_config->Read(m_name + KEY_LONGITUDE1, &m_repeater1Longitude, DEFAULT_LONGITUDE); + + m_config->Read(m_name + KEY_AGL1, &m_repeater1Agl, DEFAULT_AGL); + + m_config->Read(m_name + KEY_DESCRIPTION11, &m_repeater1Description1, DEFAULT_DESCRIPTION1); + + m_config->Read(m_name + KEY_DESCRIPTION12, &m_repeater1Description2, DEFAULT_DESCRIPTION2); + + m_config->Read(m_name + KEY_URL1, &m_repeater1URL, DEFAULT_URL); + + m_config->Read(m_name + KEY_BAND11, &temp, long(DEFAULT_BAND1)); + m_repeater1Band1 = (unsigned char)temp; + + m_config->Read(m_name + KEY_BAND12, &temp, long(DEFAULT_BAND2)); + m_repeater1Band2 = (unsigned char)temp; + + m_config->Read(m_name + KEY_BAND13, &temp, long(DEFAULT_BAND3)); + m_repeater1Band3 = (unsigned char)temp; + + m_config->Read(m_name + KEY_REPEATER_CALL2, &m_repeater2Callsign, DEFAULT_REPEATER_CALL); + + m_config->Read(m_name + KEY_REPEATER_BAND2, &m_repeater2Band, DEFAULT_REPEATER_BAND); + + m_config->Read(m_name + KEY_REPEATER_TYPE2, &temp, long(DEFAULT_REPEATER_TYPE)); + m_repeater2Type = HW_TYPE(temp); + + m_config->Read(m_name + KEY_REPEATER_ADDRESS2, &m_repeater2Address, DEFAULT_REPEATER_ADDRESS); + + m_config->Read(m_name + KEY_REPEATER_PORT2, &temp, long(DEFAULT_REPEATER_PORT2)); + m_repeater2Port = (unsigned int)temp; + + m_config->Read(m_name + KEY_REFLECTOR2, &m_repeater2Reflector, DEFAULT_REFLECTOR); + + m_config->Read(m_name + KEY_ATSTARTUP2, &m_repeater2AtStartup, DEFAULT_ATSTARTUP); + + m_config->Read(m_name + KEY_RECONNECT2, &temp, long(DEFAULT_RECONNECT)); + m_repeater2Reconnect = RECONNECT(temp); + + m_config->Read(m_name + KEY_FREQUENCY2, &m_repeater2Frequency, DEFAULT_FREQUENCY); + + m_config->Read(m_name + KEY_OFFSET2, &m_repeater2Offset, DEFAULT_OFFSET); + + m_config->Read(m_name + KEY_RANGE2, &m_repeater2Range, DEFAULT_RANGE); + + m_config->Read(m_name + KEY_LATITUDE2, &m_repeater2Latitude, DEFAULT_LATITUDE); + + m_config->Read(m_name + KEY_LONGITUDE2, &m_repeater2Longitude, DEFAULT_LONGITUDE); + + m_config->Read(m_name + KEY_AGL2, &m_repeater2Agl, DEFAULT_AGL); + + m_config->Read(m_name + KEY_DESCRIPTION21, &m_repeater2Description1, DEFAULT_DESCRIPTION1); + + m_config->Read(m_name + KEY_DESCRIPTION22, &m_repeater2Description2, DEFAULT_DESCRIPTION2); + + m_config->Read(m_name + KEY_URL2, &m_repeater2URL, DEFAULT_URL); + + m_config->Read(m_name + KEY_BAND21, &temp, long(DEFAULT_BAND1)); + m_repeater2Band1 = (unsigned char)temp; + + m_config->Read(m_name + KEY_BAND22, &temp, long(DEFAULT_BAND2)); + m_repeater2Band2 = (unsigned char)temp; + + m_config->Read(m_name + KEY_BAND23, &temp, long(DEFAULT_BAND3)); + m_repeater2Band3 = (unsigned char)temp; + + m_config->Read(m_name + KEY_REPEATER_CALL3, &m_repeater3Callsign, DEFAULT_REPEATER_CALL); + + m_config->Read(m_name + KEY_REPEATER_BAND3, &m_repeater3Band, DEFAULT_REPEATER_BAND); + + m_config->Read(m_name + KEY_REPEATER_TYPE3, &temp, long(DEFAULT_REPEATER_TYPE)); + m_repeater3Type = HW_TYPE(temp); + + m_config->Read(m_name + KEY_REPEATER_ADDRESS3, &m_repeater3Address, DEFAULT_REPEATER_ADDRESS); + + m_config->Read(m_name + KEY_REPEATER_PORT3, &temp, long(DEFAULT_REPEATER_PORT3)); + m_repeater3Port = (unsigned int)temp; + + m_config->Read(m_name + KEY_REFLECTOR3, &m_repeater3Reflector, DEFAULT_REFLECTOR); + + m_config->Read(m_name + KEY_ATSTARTUP3, &m_repeater3AtStartup, DEFAULT_ATSTARTUP); + + m_config->Read(m_name + KEY_RECONNECT3, &temp, long(DEFAULT_RECONNECT)); + m_repeater3Reconnect = RECONNECT(temp); + + m_config->Read(m_name + KEY_FREQUENCY3, &m_repeater3Frequency, DEFAULT_FREQUENCY); + + m_config->Read(m_name + KEY_OFFSET3, &m_repeater3Offset, DEFAULT_OFFSET); + + m_config->Read(m_name + KEY_RANGE3, &m_repeater3Range, DEFAULT_RANGE); + + m_config->Read(m_name + KEY_LATITUDE3, &m_repeater3Latitude, DEFAULT_LATITUDE); + + m_config->Read(m_name + KEY_LONGITUDE3, &m_repeater3Longitude, DEFAULT_LONGITUDE); + + m_config->Read(m_name + KEY_AGL3, &m_repeater3Agl, DEFAULT_AGL); + + m_config->Read(m_name + KEY_DESCRIPTION31, &m_repeater3Description1, DEFAULT_DESCRIPTION1); + + m_config->Read(m_name + KEY_DESCRIPTION32, &m_repeater3Description2, DEFAULT_DESCRIPTION2); + + m_config->Read(m_name + KEY_URL3, &m_repeater3URL, DEFAULT_URL); + + m_config->Read(m_name + KEY_BAND31, &temp, long(DEFAULT_BAND1)); + m_repeater3Band1 = (unsigned char)temp; + + m_config->Read(m_name + KEY_BAND32, &temp, long(DEFAULT_BAND2)); + m_repeater3Band2 = (unsigned char)temp; + + m_config->Read(m_name + KEY_BAND33, &temp, long(DEFAULT_BAND3)); + m_repeater3Band3 = (unsigned char)temp; + + m_config->Read(m_name + KEY_REPEATER_CALL4, &m_repeater4Callsign, DEFAULT_REPEATER_CALL); + + m_config->Read(m_name + KEY_REPEATER_BAND4, &m_repeater4Band, DEFAULT_REPEATER_BAND); + + m_config->Read(m_name + KEY_REPEATER_TYPE4, &temp, long(DEFAULT_REPEATER_TYPE)); + m_repeater4Type = HW_TYPE(temp); + + m_config->Read(m_name + KEY_REPEATER_ADDRESS4, &m_repeater4Address, DEFAULT_REPEATER_ADDRESS); + + m_config->Read(m_name + KEY_REPEATER_PORT4, &temp, long(DEFAULT_REPEATER_PORT4)); + m_repeater4Port = (unsigned int)temp; + + m_config->Read(m_name + KEY_REFLECTOR4, &m_repeater4Reflector, DEFAULT_REFLECTOR); + + m_config->Read(m_name + KEY_ATSTARTUP4, &m_repeater4AtStartup, DEFAULT_ATSTARTUP); + + m_config->Read(m_name + KEY_RECONNECT4, &temp, long(DEFAULT_RECONNECT)); + m_repeater4Reconnect = RECONNECT(temp); + + m_config->Read(m_name + KEY_FREQUENCY4, &m_repeater4Frequency, DEFAULT_FREQUENCY); + + m_config->Read(m_name + KEY_OFFSET4, &m_repeater4Offset, DEFAULT_OFFSET); + + m_config->Read(m_name + KEY_RANGE4, &m_repeater4Range, DEFAULT_RANGE); + + m_config->Read(m_name + KEY_LATITUDE4, &m_repeater4Latitude, DEFAULT_LATITUDE); + + m_config->Read(m_name + KEY_LONGITUDE4, &m_repeater4Longitude, DEFAULT_LONGITUDE); + + m_config->Read(m_name + KEY_AGL4, &m_repeater4Agl, DEFAULT_AGL); + + m_config->Read(m_name + KEY_DESCRIPTION41, &m_repeater4Description1, DEFAULT_DESCRIPTION1); + + m_config->Read(m_name + KEY_DESCRIPTION42, &m_repeater4Description2, DEFAULT_DESCRIPTION2); + + m_config->Read(m_name + KEY_URL4, &m_repeater4URL, DEFAULT_URL); + + m_config->Read(m_name + KEY_BAND41, &temp, long(DEFAULT_BAND1)); + m_repeater4Band1 = (unsigned char)temp; + + m_config->Read(m_name + KEY_BAND42, &temp, long(DEFAULT_BAND2)); + m_repeater4Band2 = (unsigned char)temp; + + m_config->Read(m_name + KEY_BAND43, &temp, long(DEFAULT_BAND3)); + m_repeater4Band3 = (unsigned char)temp; + + m_config->Read(m_name + KEY_IRCDDB_ENABLED, &m_ircddbEnabled, DEFAULT_IRCDDB_ENABLED); + m_config->Read(m_name + KEY_IRCDDB_HOSTNAME, &m_ircddbHostname, DEFAULT_IRCDDB_HOSTNAME); + m_config->Read(m_name + KEY_IRCDDB_USERNAME, &m_ircddbUsername, DEFAULT_IRCDDB_USERNAME); + m_config->Read(m_name + KEY_IRCDDB_PASSWORD, &m_ircddbPassword, DEFAULT_IRCDDB_PASSWORD); + + m_config->Read(m_name + KEY_IRCDDB_ENABLED2, &m_ircddbEnabled, DEFAULT_IRCDDB_ENABLED2); + m_config->Read(m_name + KEY_IRCDDB_HOSTNAME2, &m_ircddbHostname, DEFAULT_IRCDDB_HOSTNAME2); + m_config->Read(m_name + KEY_IRCDDB_USERNAME2, &m_ircddbUsername, DEFAULT_IRCDDB_USERNAME2); + m_config->Read(m_name + KEY_IRCDDB_PASSWORD2, &m_ircddbPassword, DEFAULT_IRCDDB_PASSWORD2); + + m_config->Read(m_name + KEY_IRCDDB_ENABLED3, &m_ircddbEnabled, DEFAULT_IRCDDB_ENABLED3); + m_config->Read(m_name + KEY_IRCDDB_HOSTNAME3, &m_ircddbHostname, DEFAULT_IRCDDB_HOSTNAME3); + m_config->Read(m_name + KEY_IRCDDB_USERNAME3, &m_ircddbUsername, DEFAULT_IRCDDB_USERNAME3); + m_config->Read(m_name + KEY_IRCDDB_PASSWORD3, &m_ircddbPassword, DEFAULT_IRCDDB_PASSWORD3); + + m_config->Read(m_name + KEY_IRCDDB_ENABLED4, &m_ircddbEnabled, DEFAULT_IRCDDB_ENABLED4); + m_config->Read(m_name + KEY_IRCDDB_HOSTNAME4, &m_ircddbHostname, DEFAULT_IRCDDB_HOSTNAME4); + m_config->Read(m_name + KEY_IRCDDB_USERNAME4, &m_ircddbUsername, DEFAULT_IRCDDB_USERNAME4); + m_config->Read(m_name + KEY_IRCDDB_PASSWORD4, &m_ircddbPassword, DEFAULT_IRCDDB_PASSWORD4); + + m_config->Read(m_name + KEY_APRS_ENABLED, &m_aprsEnabled, DEFAULT_APRS_ENABLED); + + m_config->Read(m_name + KEY_APRS_HOSTNAME, &m_aprsHostname, DEFAULT_APRS_HOSTNAME); + + m_config->Read(m_name + KEY_APRS_PORT, &temp, long(DEFAULT_APRS_PORT)); + m_aprsPort = (unsigned int)temp; + + m_config->Read(m_name + KEY_DEXTRA_ENABLED, &m_dextraEnabled, DEFAULT_DEXTRA_ENABLED); + + m_config->Read(m_name + KEY_DEXTRA_MAXDONGLES, &temp, long(DEFAULT_DEXTRA_MAXDONGLES)); + m_dextraMaxDongles = (unsigned int)temp; + + m_config->Read(m_name + KEY_DPLUS_ENABLED, &m_dplusEnabled, DEFAULT_DPLUS_ENABLED); + + m_config->Read(m_name + KEY_DPLUS_MAXDONGLES, &temp, long(DEFAULT_DPLUS_MAXDONGLES)); + m_dplusMaxDongles = (unsigned int)temp; + + m_config->Read(m_name + KEY_DPLUS_LOGIN, &m_dplusLogin, DEFAULT_DPLUS_LOGIN); + + m_config->Read(m_name + KEY_DCS_ENABLED, &m_dcsEnabled, DEFAULT_DCS_ENABLED); + + m_config->Read(m_name + KEY_CCS_ENABLED, &m_ccsEnabled, DEFAULT_CCS_ENABLED); + + m_config->Read(m_name + KEY_CCS_HOST, &m_ccsHost, DEFAULT_CCS_HOST); + + m_config->Read(m_name + KEY_XLX_ENABLED, &m_xlxEnabled, DEFAULT_XLX_ENABLED); + + m_config->Read(m_name + KEY_XLX_OVERRIDE_LOCAL, &m_xlxOverrideLocal, DEFAULT_XLX_OVERRIDE_LOCAL); + + m_config->Read(m_name + KEY_XLX_HOSTS_FILE_URL, &m_xlxHostsFileUrl, DEFAULT_XLX_HOSTS_FILE_URL); + + m_config->Read(m_name + KEY_STARNET_BAND1, &m_starNet1Band, DEFAULT_STARNET_BAND); + + m_config->Read(m_name + KEY_STARNET_CALLSIGN1, &m_starNet1Callsign, DEFAULT_STARNET_CALLSIGN); + + m_config->Read(m_name + KEY_STARNET_LOGOFF1, &m_starNet1Logoff, DEFAULT_STARNET_LOGOFF); + + m_config->Read(m_name + KEY_STARNET_INFO1, &m_starNet1Info, DEFAULT_STARNET_INFO); + + m_config->Read(m_name + KEY_STARNET_PERMANENT1, &m_starNet1Permanent, DEFAULT_STARNET_PERMANENT); + + m_config->Read(m_name + KEY_STARNET_USER_TIMEOUT1, &temp, long(DEFAULT_STARNET_USER_TIMEOUT)); + m_starNet1UserTimeout = (unsigned int)temp; + + m_config->Read(m_name + KEY_STARNET_GROUP_TIMEOUT1, &temp, long(DEFAULT_STARNET_GROUP_TIMEOUT)); + m_starNet1GroupTimeout = (unsigned int)temp; + + m_config->Read(m_name + KEY_STARNET_CALLSIGN_SWITCH1, &temp, long(DEFAULT_STARNET_CALLSIGN_SWITCH)); + m_starNet1CallsignSwitch = STARNET_CALLSIGN_SWITCH(temp); + + m_config->Read(m_name + KEY_STARNET_TXMSG_SWITCH1, &m_starNet1TxMsgSwitch, DEFAULT_STARNET_TXMSG_SWITCH); + + m_config->Read(m_name + KEY_STARNET_REFLECTOR1, &m_starNet1Reflector, DEFAULT_STARNET_REFLECTOR); + + m_config->Read(m_name + KEY_STARNET_BAND2, &m_starNet2Band, DEFAULT_STARNET_BAND); + + m_config->Read(m_name + KEY_STARNET_CALLSIGN2, &m_starNet2Callsign, DEFAULT_STARNET_CALLSIGN); + + m_config->Read(m_name + KEY_STARNET_LOGOFF2, &m_starNet2Logoff, DEFAULT_STARNET_LOGOFF); + + m_config->Read(m_name + KEY_STARNET_INFO2, &m_starNet2Info, DEFAULT_STARNET_INFO); + + m_config->Read(m_name + KEY_STARNET_PERMANENT2, &m_starNet2Permanent, DEFAULT_STARNET_PERMANENT); + + m_config->Read(m_name + KEY_STARNET_USER_TIMEOUT2, &temp, long(DEFAULT_STARNET_USER_TIMEOUT)); + m_starNet2UserTimeout = (unsigned int)temp; + + m_config->Read(m_name + KEY_STARNET_GROUP_TIMEOUT2, &temp, long(DEFAULT_STARNET_GROUP_TIMEOUT)); + m_starNet2GroupTimeout = (unsigned int)temp; + + m_config->Read(m_name + KEY_STARNET_CALLSIGN_SWITCH2, &temp, long(DEFAULT_STARNET_CALLSIGN_SWITCH)); + m_starNet2CallsignSwitch = STARNET_CALLSIGN_SWITCH(temp); + + m_config->Read(m_name + KEY_STARNET_TXMSG_SWITCH2, &m_starNet2TxMsgSwitch, DEFAULT_STARNET_TXMSG_SWITCH); + + m_config->Read(m_name + KEY_STARNET_REFLECTOR2, &m_starNet2Reflector, DEFAULT_STARNET_REFLECTOR); + + m_config->Read(m_name + KEY_STARNET_BAND3, &m_starNet3Band, DEFAULT_STARNET_BAND); + + m_config->Read(m_name + KEY_STARNET_CALLSIGN3, &m_starNet3Callsign, DEFAULT_STARNET_CALLSIGN); + + m_config->Read(m_name + KEY_STARNET_LOGOFF3, &m_starNet3Logoff, DEFAULT_STARNET_LOGOFF); + + m_config->Read(m_name + KEY_STARNET_INFO3, &m_starNet3Info, DEFAULT_STARNET_INFO); + + m_config->Read(m_name + KEY_STARNET_PERMANENT3, &m_starNet3Permanent, DEFAULT_STARNET_PERMANENT); + + m_config->Read(m_name + KEY_STARNET_USER_TIMEOUT3, &temp, long(DEFAULT_STARNET_USER_TIMEOUT)); + m_starNet3UserTimeout = (unsigned int)temp; + + m_config->Read(m_name + KEY_STARNET_GROUP_TIMEOUT3, &temp, long(DEFAULT_STARNET_GROUP_TIMEOUT)); + m_starNet3GroupTimeout = (unsigned int)temp; + + m_config->Read(m_name + KEY_STARNET_CALLSIGN_SWITCH3, &temp, long(DEFAULT_STARNET_CALLSIGN_SWITCH)); + m_starNet3CallsignSwitch = STARNET_CALLSIGN_SWITCH(temp); + + m_config->Read(m_name + KEY_STARNET_TXMSG_SWITCH3, &m_starNet3TxMsgSwitch, DEFAULT_STARNET_TXMSG_SWITCH); + + m_config->Read(m_name + KEY_STARNET_REFLECTOR3, &m_starNet3Reflector, DEFAULT_STARNET_REFLECTOR); + + m_config->Read(m_name + KEY_STARNET_BAND4, &m_starNet4Band, DEFAULT_STARNET_BAND); + + m_config->Read(m_name + KEY_STARNET_CALLSIGN4, &m_starNet4Callsign, DEFAULT_STARNET_CALLSIGN); + + m_config->Read(m_name + KEY_STARNET_LOGOFF4, &m_starNet4Logoff, DEFAULT_STARNET_LOGOFF); + + m_config->Read(m_name + KEY_STARNET_INFO4, &m_starNet4Info, DEFAULT_STARNET_INFO); + + m_config->Read(m_name + KEY_STARNET_PERMANENT4, &m_starNet4Permanent, DEFAULT_STARNET_PERMANENT); + + m_config->Read(m_name + KEY_STARNET_USER_TIMEOUT4, &temp, long(DEFAULT_STARNET_USER_TIMEOUT)); + m_starNet4UserTimeout = (unsigned int)temp; + + m_config->Read(m_name + KEY_STARNET_GROUP_TIMEOUT4, &temp, long(DEFAULT_STARNET_GROUP_TIMEOUT)); + m_starNet4GroupTimeout = (unsigned int)temp; + + m_config->Read(m_name + KEY_STARNET_CALLSIGN_SWITCH4, &temp, long(DEFAULT_STARNET_CALLSIGN_SWITCH)); + m_starNet4CallsignSwitch = STARNET_CALLSIGN_SWITCH(temp); + + m_config->Read(m_name + KEY_STARNET_TXMSG_SWITCH4, &m_starNet4TxMsgSwitch, DEFAULT_STARNET_TXMSG_SWITCH); + + m_config->Read(m_name + KEY_STARNET_REFLECTOR4, &m_starNet4Reflector, DEFAULT_STARNET_REFLECTOR); + + m_config->Read(m_name + KEY_STARNET_BAND5, &m_starNet5Band, DEFAULT_STARNET_BAND); + + m_config->Read(m_name + KEY_STARNET_CALLSIGN5, &m_starNet5Callsign, DEFAULT_STARNET_CALLSIGN); + + m_config->Read(m_name + KEY_STARNET_LOGOFF5, &m_starNet5Logoff, DEFAULT_STARNET_LOGOFF); + + m_config->Read(m_name + KEY_STARNET_INFO5, &m_starNet5Info, DEFAULT_STARNET_INFO); + + m_config->Read(m_name + KEY_STARNET_PERMANENT5, &m_starNet5Permanent, DEFAULT_STARNET_PERMANENT); + + m_config->Read(m_name + KEY_STARNET_USER_TIMEOUT5, &temp, long(DEFAULT_STARNET_USER_TIMEOUT)); + m_starNet5UserTimeout = (unsigned int)temp; + + m_config->Read(m_name + KEY_STARNET_GROUP_TIMEOUT5, &temp, long(DEFAULT_STARNET_GROUP_TIMEOUT)); + m_starNet5GroupTimeout = (unsigned int)temp; + + m_config->Read(m_name + KEY_STARNET_CALLSIGN_SWITCH5, &temp, long(DEFAULT_STARNET_CALLSIGN_SWITCH)); + m_starNet5CallsignSwitch = STARNET_CALLSIGN_SWITCH(temp); + + m_config->Read(m_name + KEY_STARNET_TXMSG_SWITCH5, &m_starNet5TxMsgSwitch, DEFAULT_STARNET_TXMSG_SWITCH); + + m_config->Read(m_name + KEY_STARNET_REFLECTOR5, &m_starNet5Reflector, DEFAULT_STARNET_REFLECTOR); + + m_config->Read(m_name + KEY_REMOTE_ENABLED, &m_remoteEnabled, DEFAULT_REMOTE_ENABLED); + + m_config->Read(m_name + KEY_REMOTE_PASSWORD, &m_remotePassword, DEFAULT_REMOTE_PASSWORD); + + m_config->Read(m_name + KEY_REMOTE_PORT, &temp, long(DEFAULT_REMOTE_PORT)); + m_remotePort = (unsigned int)temp; + + m_config->Read(m_name + KEY_LANGUAGE, &temp, long(DEFAULT_LANGUAGE)); + m_language = TEXT_LANG(temp); + + m_config->Read(m_name + KEY_INFO_ENABLED, &m_infoEnabled, DEFAULT_INFO_ENABLED); + + m_config->Read(m_name + KEY_ECHO_ENABLED, &m_echoEnabled, DEFAULT_ECHO_ENABLED); + + m_config->Read(m_name + KEY_LOG_ENABLED, &m_logEnabled, DEFAULT_LOG_ENABLED); + + m_config->Read(m_name + KEY_DRATS_ENABLED, &m_dratsEnabled, DEFAULT_DRATS_ENABLED); + + m_config->Read(m_name + KEY_DTMF_ENABLED, &m_dtmfEnabled, DEFAULT_DTMF_ENABLED); + + m_config->Read(m_name + KEY_WINDOW_X, &temp, long(DEFAULT_WINDOW_X)); + m_x = int(temp); + + m_config->Read(m_name + KEY_WINDOW_Y, &temp, long(DEFAULT_WINDOW_Y)); + m_y = int(temp); +} + +CIRCDDBGatewayConfig::~CIRCDDBGatewayConfig() +{ + delete m_config; +} + +#else + +CIRCDDBGatewayConfig::CIRCDDBGatewayConfig(const wxString& dir, const wxString& configName, const wxString& name) : +m_fileName(), +m_type(DEFAULT_GATEWAY_TYPE), +m_callsign(DEFAULT_GATEWAY_CALLSIGN), +m_address(DEFAULT_GATEWAY_ADDRESS), +m_icomAddress(DEFAULT_ICOM_ADDRESS), +m_icomPort(DEFAULT_ICOM_PORT), +m_hbAddress(DEFAULT_HB_ADDRESS), +m_hbPort(DEFAULT_HB_PORT), +m_latitude(DEFAULT_LATITUDE), +m_longitude(DEFAULT_LONGITUDE), +m_description1(DEFAULT_DESCRIPTION1), +m_description2(DEFAULT_DESCRIPTION2), +m_url(DEFAULT_URL), +m_repeater1Callsign(DEFAULT_REPEATER_CALL), +m_repeater1Band(DEFAULT_REPEATER_BAND), +m_repeater1Type(DEFAULT_REPEATER_TYPE), +m_repeater1Address(DEFAULT_REPEATER_ADDRESS), +m_repeater1Port(DEFAULT_REPEATER_PORT1), +m_repeater1Reflector(DEFAULT_REFLECTOR), +m_repeater1AtStartup(DEFAULT_ATSTARTUP), +m_repeater1Reconnect(DEFAULT_RECONNECT), +m_repeater1Frequency(DEFAULT_FREQUENCY), +m_repeater1Offset(DEFAULT_OFFSET), +m_repeater1Range(DEFAULT_RANGE), +m_repeater1Latitude(DEFAULT_LATITUDE), +m_repeater1Longitude(DEFAULT_LONGITUDE), +m_repeater1Agl(DEFAULT_AGL), +m_repeater1Description1(DEFAULT_DESCRIPTION1), +m_repeater1Description2(DEFAULT_DESCRIPTION2), +m_repeater1URL(DEFAULT_URL), +m_repeater1Band1(DEFAULT_BAND1), +m_repeater1Band2(DEFAULT_BAND2), +m_repeater1Band3(DEFAULT_BAND3), +m_repeater2Callsign(DEFAULT_REPEATER_CALL), +m_repeater2Band(DEFAULT_REPEATER_BAND), +m_repeater2Type(DEFAULT_REPEATER_TYPE), +m_repeater2Address(DEFAULT_REPEATER_ADDRESS), +m_repeater2Port(DEFAULT_REPEATER_PORT2), +m_repeater2Reflector(DEFAULT_REFLECTOR), +m_repeater2AtStartup(DEFAULT_ATSTARTUP), +m_repeater2Reconnect(DEFAULT_RECONNECT), +m_repeater2Frequency(DEFAULT_FREQUENCY), +m_repeater2Offset(DEFAULT_OFFSET), +m_repeater2Range(DEFAULT_RANGE), +m_repeater2Latitude(DEFAULT_LATITUDE), +m_repeater2Longitude(DEFAULT_LONGITUDE), +m_repeater2Agl(DEFAULT_AGL), +m_repeater2Description1(DEFAULT_DESCRIPTION1), +m_repeater2Description2(DEFAULT_DESCRIPTION2), +m_repeater2URL(DEFAULT_URL), +m_repeater2Band1(DEFAULT_BAND1), +m_repeater2Band2(DEFAULT_BAND2), +m_repeater2Band3(DEFAULT_BAND3), +m_repeater3Callsign(DEFAULT_REPEATER_CALL), +m_repeater3Band(DEFAULT_REPEATER_BAND), +m_repeater3Type(DEFAULT_REPEATER_TYPE), +m_repeater3Address(DEFAULT_REPEATER_ADDRESS), +m_repeater3Port(DEFAULT_REPEATER_PORT3), +m_repeater3Reflector(DEFAULT_REFLECTOR), +m_repeater3AtStartup(DEFAULT_ATSTARTUP), +m_repeater3Reconnect(DEFAULT_RECONNECT), +m_repeater3Frequency(DEFAULT_FREQUENCY), +m_repeater3Offset(DEFAULT_OFFSET), +m_repeater3Range(DEFAULT_RANGE), +m_repeater3Latitude(DEFAULT_LATITUDE), +m_repeater3Longitude(DEFAULT_LONGITUDE), +m_repeater3Agl(DEFAULT_AGL), +m_repeater3Description1(DEFAULT_DESCRIPTION1), +m_repeater3Description2(DEFAULT_DESCRIPTION2), +m_repeater3URL(DEFAULT_URL), +m_repeater3Band1(DEFAULT_BAND1), +m_repeater3Band2(DEFAULT_BAND2), +m_repeater3Band3(DEFAULT_BAND3), +m_repeater4Callsign(DEFAULT_REPEATER_CALL), +m_repeater4Band(DEFAULT_REPEATER_BAND), +m_repeater4Type(DEFAULT_REPEATER_TYPE), +m_repeater4Address(DEFAULT_REPEATER_ADDRESS), +m_repeater4Port(DEFAULT_REPEATER_PORT4), +m_repeater4Reflector(DEFAULT_REFLECTOR), +m_repeater4AtStartup(DEFAULT_ATSTARTUP), +m_repeater4Reconnect(DEFAULT_RECONNECT), +m_repeater4Frequency(DEFAULT_FREQUENCY), +m_repeater4Offset(DEFAULT_OFFSET), +m_repeater4Range(DEFAULT_RANGE), +m_repeater4Latitude(DEFAULT_LATITUDE), +m_repeater4Longitude(DEFAULT_LONGITUDE), +m_repeater4Agl(DEFAULT_AGL), +m_repeater4Description1(DEFAULT_DESCRIPTION1), +m_repeater4Description2(DEFAULT_DESCRIPTION2), +m_repeater4URL(DEFAULT_URL), +m_repeater4Band1(DEFAULT_BAND1), +m_repeater4Band2(DEFAULT_BAND2), +m_repeater4Band3(DEFAULT_BAND3), +m_ircddbEnabled(DEFAULT_IRCDDB_ENABLED), +m_ircddbHostname(DEFAULT_IRCDDB_HOSTNAME), +m_ircddbUsername(DEFAULT_IRCDDB_USERNAME), +m_ircddbPassword(DEFAULT_IRCDDB_PASSWORD), +m_ircddbEnabled2(DEFAULT_IRCDDB_ENABLED2), +m_ircddbHostname2(DEFAULT_IRCDDB_HOSTNAME2), +m_ircddbUsername2(DEFAULT_IRCDDB_USERNAME2), +m_ircddbPassword2(DEFAULT_IRCDDB_PASSWORD2), +m_ircddbEnabled3(DEFAULT_IRCDDB_ENABLED3), +m_ircddbHostname3(DEFAULT_IRCDDB_HOSTNAME3), +m_ircddbUsername3(DEFAULT_IRCDDB_USERNAME3), +m_ircddbPassword3(DEFAULT_IRCDDB_PASSWORD3), +m_ircddbEnabled4(DEFAULT_IRCDDB_ENABLED4), +m_ircddbHostname4(DEFAULT_IRCDDB_HOSTNAME4), +m_ircddbUsername4(DEFAULT_IRCDDB_USERNAME4), +m_ircddbPassword4(DEFAULT_IRCDDB_PASSWORD4), +m_aprsEnabled(DEFAULT_APRS_ENABLED), +m_aprsHostname(DEFAULT_APRS_HOSTNAME), +m_aprsPort(DEFAULT_APRS_PORT), +m_dextraEnabled(DEFAULT_DEXTRA_ENABLED), +m_dextraMaxDongles(DEFAULT_DEXTRA_MAXDONGLES), +m_dplusEnabled(DEFAULT_DPLUS_ENABLED), +m_dplusMaxDongles(DEFAULT_DPLUS_MAXDONGLES), +m_dplusLogin(DEFAULT_DPLUS_LOGIN), +m_dcsEnabled(DEFAULT_DCS_ENABLED), +m_ccsEnabled(DEFAULT_CCS_ENABLED), +m_ccsHost(DEFAULT_CCS_HOST), +m_xlxEnabled(DEFAULT_XLX_ENABLED), +m_xlxOverrideLocal(DEFAULT_XLX_OVERRIDE_LOCAL), +m_xlxHostsFileUrl(DEFAULT_XLX_HOSTS_FILE_URL), +m_starNet1Band(DEFAULT_STARNET_BAND), +m_starNet1Callsign(DEFAULT_STARNET_CALLSIGN), +m_starNet1Logoff(DEFAULT_STARNET_LOGOFF), +m_starNet1Info(DEFAULT_STARNET_INFO), +m_starNet1Permanent(DEFAULT_STARNET_PERMANENT), +m_starNet1UserTimeout(DEFAULT_STARNET_USER_TIMEOUT), +m_starNet1GroupTimeout(DEFAULT_STARNET_GROUP_TIMEOUT), +m_starNet1CallsignSwitch(DEFAULT_STARNET_CALLSIGN_SWITCH), +m_starNet1TxMsgSwitch(DEFAULT_STARNET_TXMSG_SWITCH), +m_starNet1Reflector(DEFAULT_STARNET_REFLECTOR), +m_starNet2Band(DEFAULT_STARNET_BAND), +m_starNet2Callsign(DEFAULT_STARNET_CALLSIGN), +m_starNet2Logoff(DEFAULT_STARNET_LOGOFF), +m_starNet2Info(DEFAULT_STARNET_INFO), +m_starNet2Permanent(DEFAULT_STARNET_PERMANENT), +m_starNet2UserTimeout(DEFAULT_STARNET_USER_TIMEOUT), +m_starNet2GroupTimeout(DEFAULT_STARNET_GROUP_TIMEOUT), +m_starNet2CallsignSwitch(DEFAULT_STARNET_CALLSIGN_SWITCH), +m_starNet2TxMsgSwitch(DEFAULT_STARNET_TXMSG_SWITCH), +m_starNet2Reflector(DEFAULT_STARNET_REFLECTOR), +m_starNet3Band(DEFAULT_STARNET_BAND), +m_starNet3Callsign(DEFAULT_STARNET_CALLSIGN), +m_starNet3Logoff(DEFAULT_STARNET_LOGOFF), +m_starNet3Info(DEFAULT_STARNET_INFO), +m_starNet3Permanent(DEFAULT_STARNET_PERMANENT), +m_starNet3UserTimeout(DEFAULT_STARNET_USER_TIMEOUT), +m_starNet3GroupTimeout(DEFAULT_STARNET_GROUP_TIMEOUT), +m_starNet3CallsignSwitch(DEFAULT_STARNET_CALLSIGN_SWITCH), +m_starNet3TxMsgSwitch(DEFAULT_STARNET_TXMSG_SWITCH), +m_starNet3Reflector(DEFAULT_STARNET_REFLECTOR), +m_starNet4Band(DEFAULT_STARNET_BAND), +m_starNet4Callsign(DEFAULT_STARNET_CALLSIGN), +m_starNet4Logoff(DEFAULT_STARNET_LOGOFF), +m_starNet4Info(DEFAULT_STARNET_INFO), +m_starNet4Permanent(DEFAULT_STARNET_PERMANENT), +m_starNet4UserTimeout(DEFAULT_STARNET_USER_TIMEOUT), +m_starNet4GroupTimeout(DEFAULT_STARNET_GROUP_TIMEOUT), +m_starNet4CallsignSwitch(DEFAULT_STARNET_CALLSIGN_SWITCH), +m_starNet4TxMsgSwitch(DEFAULT_STARNET_TXMSG_SWITCH), +m_starNet4Reflector(DEFAULT_STARNET_REFLECTOR), +m_starNet5Band(DEFAULT_STARNET_BAND), +m_starNet5Callsign(DEFAULT_STARNET_CALLSIGN), +m_starNet5Logoff(DEFAULT_STARNET_LOGOFF), +m_starNet5Info(DEFAULT_STARNET_INFO), +m_starNet5Permanent(DEFAULT_STARNET_PERMANENT), +m_starNet5UserTimeout(DEFAULT_STARNET_USER_TIMEOUT), +m_starNet5GroupTimeout(DEFAULT_STARNET_GROUP_TIMEOUT), +m_starNet5CallsignSwitch(DEFAULT_STARNET_CALLSIGN_SWITCH), +m_starNet5TxMsgSwitch(DEFAULT_STARNET_TXMSG_SWITCH), +m_starNet5Reflector(DEFAULT_STARNET_REFLECTOR), +m_remoteEnabled(DEFAULT_REMOTE_ENABLED), +m_remotePassword(DEFAULT_REMOTE_PASSWORD), +m_remotePort(DEFAULT_REMOTE_PORT), +m_language(DEFAULT_LANGUAGE), +m_infoEnabled(DEFAULT_INFO_ENABLED), +m_echoEnabled(DEFAULT_ECHO_ENABLED), +m_logEnabled(DEFAULT_LOG_ENABLED), +m_dratsEnabled(DEFAULT_DRATS_ENABLED), +m_dtmfEnabled(DEFAULT_DTMF_ENABLED), +m_x(DEFAULT_WINDOW_X), +m_y(DEFAULT_WINDOW_Y) +{ + wxASSERT(!dir.IsEmpty()); + + wxString fileName = configName; + if (!name.IsEmpty()) + fileName = configName + wxT("_") + name; + + m_fileName.Assign(dir, fileName); + + wxTextFile file(m_fileName.GetFullPath()); + + bool exists = file.Exists(); + if (!exists) + return; + + bool ret = file.Open(); + if (!ret) { + wxLogError(wxT("Cannot open the config file - %s"), m_fileName.GetFullPath().c_str()); + return; + } + + long temp1; + unsigned long temp2; + + wxString str = file.GetFirstLine(); + + while (!file.Eof()) { + if (str.GetChar(0U) == wxT('#')) { + str = file.GetNextLine(); + continue; + } + + int n = str.Find(wxT('=')); + if (n == wxNOT_FOUND) { + str = file.GetNextLine(); + continue; + } + + wxString key = str.Left(n); + wxString val = str.Mid(n + 1U); + + if (key.IsSameAs(KEY_GATEWAY_TYPE)) { + val.ToLong(&temp1); + m_type = GATEWAY_TYPE(temp1); + } else if (key.IsSameAs(KEY_GATEWAY_CALLSIGN)) { + m_callsign = val; + } else if (key.IsSameAs(KEY_GATEWAY_ADDRESS)) { + m_address = val; + } else if (key.IsSameAs(KEY_ICOM_ADDRESS)) { + m_icomAddress = val; + } else if (key.IsSameAs(KEY_ICOM_PORT)) { + val.ToULong(&temp2); + m_icomPort = (unsigned int)temp2; + } else if (key.IsSameAs(KEY_HB_ADDRESS)) { + m_hbAddress = val; + } else if (key.IsSameAs(KEY_HB_PORT)) { + val.ToULong(&temp2); + m_hbPort = (unsigned int)temp2; + } else if (key.IsSameAs(KEY_LATITUDE)) { + val.ToDouble(&m_latitude); + } else if (key.IsSameAs(KEY_LONGITUDE)) { + val.ToDouble(&m_longitude); + } else if (key.IsSameAs(KEY_DESCRIPTION1)) { + m_description1 = val; + } else if (key.IsSameAs(KEY_DESCRIPTION2)) { + m_description2 = val; + } else if (key.IsSameAs(KEY_URL)) { + m_url = val; + } else if (key.IsSameAs(KEY_REPEATER_CALL1)) { + m_repeater1Callsign = val; + } else if (key.IsSameAs(KEY_REPEATER_BAND1)) { + m_repeater1Band = val; + } else if (key.IsSameAs(KEY_REPEATER_TYPE1)) { + val.ToLong(&temp1); + m_repeater1Type = HW_TYPE(temp1); + } else if (key.IsSameAs(KEY_REPEATER_ADDRESS1)) { + m_repeater1Address = val; + } else if (key.IsSameAs(KEY_REPEATER_PORT1)) { + val.ToULong(&temp2); + m_repeater1Port = (unsigned int)temp2; + } else if (key.IsSameAs(KEY_REFLECTOR1)) { + m_repeater1Reflector = val; + } else if (key.IsSameAs(KEY_ATSTARTUP1)) { + val.ToLong(&temp1); + m_repeater1AtStartup = temp1 == 1L; + } else if (key.IsSameAs(KEY_RECONNECT1)) { + val.ToLong(&temp1); + m_repeater1Reconnect = RECONNECT(temp1); + } else if (key.IsSameAs(KEY_FREQUENCY1)) { + val.ToDouble(&m_repeater1Frequency); + } else if (key.IsSameAs(KEY_OFFSET1)) { + val.ToDouble(&m_repeater1Offset); + } else if (key.IsSameAs(KEY_RANGE1)) { + val.ToDouble(&m_repeater1Range); + } else if (key.IsSameAs(KEY_LATITUDE1)) { + val.ToDouble(&m_repeater1Latitude); + } else if (key.IsSameAs(KEY_LONGITUDE1)) { + val.ToDouble(&m_repeater1Longitude); + } else if (key.IsSameAs(KEY_AGL1)) { + val.ToDouble(&m_repeater1Agl); + } else if (key.IsSameAs(KEY_DESCRIPTION11)) { + m_repeater1Description1 = val; + } else if (key.IsSameAs(KEY_DESCRIPTION12)) { + m_repeater1Description2 = val; + } else if (key.IsSameAs(KEY_URL1)) { + m_repeater1URL = val; + } else if (key.IsSameAs(KEY_BAND11)) { + val.ToULong(&temp2); + m_repeater1Band1 = (unsigned char)temp2; + } else if (key.IsSameAs(KEY_BAND12)) { + val.ToULong(&temp2); + m_repeater1Band2 = (unsigned char)temp2; + } else if (key.IsSameAs(KEY_BAND13)) { + val.ToULong(&temp2); + m_repeater1Band3 = (unsigned char)temp2; + } else if (key.IsSameAs(KEY_REPEATER_CALL2)) { + m_repeater2Callsign = val; + } else if (key.IsSameAs(KEY_REPEATER_BAND2)) { + m_repeater2Band = val; + } else if (key.IsSameAs(KEY_REPEATER_TYPE2)) { + val.ToLong(&temp1); + m_repeater2Type = HW_TYPE(temp1); + } else if (key.IsSameAs(KEY_REPEATER_ADDRESS2)) { + m_repeater2Address = val; + } else if (key.IsSameAs(KEY_REPEATER_PORT2)) { + val.ToULong(&temp2); + m_repeater2Port = (unsigned int)temp2; + } else if (key.IsSameAs(KEY_REFLECTOR2)) { + m_repeater2Reflector = val; + } else if (key.IsSameAs(KEY_ATSTARTUP2)) { + val.ToLong(&temp1); + m_repeater2AtStartup = temp1 == 1L; + } else if (key.IsSameAs(KEY_RECONNECT2)) { + val.ToLong(&temp1); + m_repeater2Reconnect = RECONNECT(temp1); + } else if (key.IsSameAs(KEY_FREQUENCY2)) { + val.ToDouble(&m_repeater2Frequency); + } else if (key.IsSameAs(KEY_OFFSET2)) { + val.ToDouble(&m_repeater2Offset); + } else if (key.IsSameAs(KEY_RANGE2)) { + val.ToDouble(&m_repeater2Range); + } else if (key.IsSameAs(KEY_LATITUDE2)) { + val.ToDouble(&m_repeater2Latitude); + } else if (key.IsSameAs(KEY_LONGITUDE2)) { + val.ToDouble(&m_repeater2Longitude); + } else if (key.IsSameAs(KEY_AGL2)) { + val.ToDouble(&m_repeater2Agl); + } else if (key.IsSameAs(KEY_DESCRIPTION21)) { + m_repeater2Description1 = val; + } else if (key.IsSameAs(KEY_DESCRIPTION22)) { + m_repeater2Description2 = val; + } else if (key.IsSameAs(KEY_URL2)) { + m_repeater2URL = val; + } else if (key.IsSameAs(KEY_BAND21)) { + val.ToULong(&temp2); + m_repeater2Band1 = (unsigned char)temp2; + } else if (key.IsSameAs(KEY_BAND22)) { + val.ToULong(&temp2); + m_repeater2Band2 = (unsigned char)temp2; + } else if (key.IsSameAs(KEY_BAND23)) { + val.ToULong(&temp2); + m_repeater2Band3 = (unsigned char)temp2; + } else if (key.IsSameAs(KEY_REPEATER_CALL3)) { + m_repeater3Callsign = val; + } else if (key.IsSameAs(KEY_REPEATER_BAND3)) { + m_repeater3Band = val; + } else if (key.IsSameAs(KEY_REPEATER_TYPE3)) { + val.ToLong(&temp1); + m_repeater3Type = HW_TYPE(temp1); + } else if (key.IsSameAs(KEY_REPEATER_ADDRESS3)) { + m_repeater3Address = val; + } else if (key.IsSameAs(KEY_REPEATER_PORT3)) { + val.ToULong(&temp2); + m_repeater3Port = (unsigned int)temp2; + } else if (key.IsSameAs(KEY_REFLECTOR3)) { + m_repeater3Reflector = val; + } else if (key.IsSameAs(KEY_ATSTARTUP3)) { + val.ToLong(&temp1); + m_repeater3AtStartup = temp1 == 1L; + } else if (key.IsSameAs(KEY_RECONNECT3)) { + val.ToLong(&temp1); + m_repeater3Reconnect = RECONNECT(temp1); + } else if (key.IsSameAs(KEY_FREQUENCY3)) { + val.ToDouble(&m_repeater3Frequency); + } else if (key.IsSameAs(KEY_OFFSET3)) { + val.ToDouble(&m_repeater3Offset); + } else if (key.IsSameAs(KEY_RANGE3)) { + val.ToDouble(&m_repeater3Range); + } else if (key.IsSameAs(KEY_LATITUDE3)) { + val.ToDouble(&m_repeater3Latitude); + } else if (key.IsSameAs(KEY_LONGITUDE3)) { + val.ToDouble(&m_repeater3Longitude); + } else if (key.IsSameAs(KEY_AGL3)) { + val.ToDouble(&m_repeater3Agl); + } else if (key.IsSameAs(KEY_DESCRIPTION31)) { + m_repeater3Description1 = val; + } else if (key.IsSameAs(KEY_DESCRIPTION32)) { + m_repeater3Description2 = val; + } else if (key.IsSameAs(KEY_URL3)) { + m_repeater3URL = val; + } else if (key.IsSameAs(KEY_BAND31)) { + val.ToULong(&temp2); + m_repeater3Band1 = (unsigned char)temp2; + } else if (key.IsSameAs(KEY_BAND32)) { + val.ToULong(&temp2); + m_repeater3Band2 = (unsigned char)temp2; + } else if (key.IsSameAs(KEY_BAND33)) { + val.ToULong(&temp2); + m_repeater3Band3 = (unsigned char)temp2; + } else if (key.IsSameAs(KEY_REPEATER_CALL4)) { + m_repeater4Callsign = val; + } else if (key.IsSameAs(KEY_REPEATER_BAND4)) { + m_repeater4Band = val; + } else if (key.IsSameAs(KEY_REPEATER_TYPE4)) { + val.ToLong(&temp1); + m_repeater4Type = HW_TYPE(temp1); + } else if (key.IsSameAs(KEY_REPEATER_ADDRESS4)) { + m_repeater4Address = val; + } else if (key.IsSameAs(KEY_REPEATER_PORT4)) { + val.ToULong(&temp2); + m_repeater4Port = (unsigned int)temp2; + } else if (key.IsSameAs(KEY_REFLECTOR4)) { + m_repeater4Reflector = val; + } else if (key.IsSameAs(KEY_ATSTARTUP4)) { + val.ToLong(&temp1); + m_repeater4AtStartup = temp1 == 1L; + } else if (key.IsSameAs(KEY_RECONNECT4)) { + val.ToLong(&temp1); + m_repeater4Reconnect = RECONNECT(temp1); + } else if (key.IsSameAs(KEY_FREQUENCY4)) { + val.ToDouble(&m_repeater4Frequency); + } else if (key.IsSameAs(KEY_OFFSET4)) { + val.ToDouble(&m_repeater4Offset); + } else if (key.IsSameAs(KEY_RANGE4)) { + val.ToDouble(&m_repeater4Range); + } else if (key.IsSameAs(KEY_LATITUDE4)) { + val.ToDouble(&m_repeater4Latitude); + } else if (key.IsSameAs(KEY_LONGITUDE4)) { + val.ToDouble(&m_repeater4Longitude); + } else if (key.IsSameAs(KEY_AGL4)) { + val.ToDouble(&m_repeater4Agl); + } else if (key.IsSameAs(KEY_DESCRIPTION41)) { + m_repeater4Description1 = val; + } else if (key.IsSameAs(KEY_DESCRIPTION42)) { + m_repeater4Description2 = val; + } else if (key.IsSameAs(KEY_URL4)) { + m_repeater4URL = val; + } else if (key.IsSameAs(KEY_BAND41)) { + val.ToULong(&temp2); + m_repeater4Band1 = (unsigned char)temp2; + } else if (key.IsSameAs(KEY_BAND42)) { + val.ToULong(&temp2); + m_repeater4Band2 = (unsigned char)temp2; + } else if (key.IsSameAs(KEY_BAND43)) { + val.ToULong(&temp2); + m_repeater4Band3 = (unsigned char)temp2; + } else if (key.IsSameAs(KEY_IRCDDB_ENABLED)) { + val.ToLong(&temp1); + m_ircddbEnabled = temp1 == 1L; + } else if (key.IsSameAs(KEY_IRCDDB_HOSTNAME)) { + m_ircddbHostname = val; + } else if (key.IsSameAs(KEY_IRCDDB_USERNAME)) { + m_ircddbUsername = val; + } else if (key.IsSameAs(KEY_IRCDDB_PASSWORD)) { + m_ircddbPassword = val; + } else if (key.IsSameAs(KEY_IRCDDB_ENABLED2)) { + val.ToLong(&temp1); + m_ircddbEnabled2 = temp1 == 1L; + } else if (key.IsSameAs(KEY_IRCDDB_HOSTNAME2)) { + m_ircddbHostname2 = val; + } else if (key.IsSameAs(KEY_IRCDDB_USERNAME2)) { + m_ircddbUsername2 = val; + } else if (key.IsSameAs(KEY_IRCDDB_PASSWORD2)) { + m_ircddbPassword2 = val; + } else if (key.IsSameAs(KEY_IRCDDB_ENABLED3)) { + val.ToLong(&temp1); + m_ircddbEnabled3 = temp1 == 1L; + } else if (key.IsSameAs(KEY_IRCDDB_HOSTNAME3)) { + m_ircddbHostname3 = val; + } else if (key.IsSameAs(KEY_IRCDDB_USERNAME3)) { + m_ircddbUsername3 = val; + } else if (key.IsSameAs(KEY_IRCDDB_PASSWORD3)) { + m_ircddbPassword3 = val; + } else if (key.IsSameAs(KEY_IRCDDB_ENABLED4)) { + val.ToLong(&temp1); + m_ircddbEnabled4 = temp1 == 1L; + } else if (key.IsSameAs(KEY_IRCDDB_HOSTNAME4)) { + m_ircddbHostname4 = val; + } else if (key.IsSameAs(KEY_IRCDDB_USERNAME4)) { + m_ircddbUsername4 = val; + } else if (key.IsSameAs(KEY_IRCDDB_PASSWORD4)) { + m_ircddbPassword4 = val; + } else if (key.IsSameAs(KEY_APRS_ENABLED)) { + val.ToLong(&temp1); + m_aprsEnabled = temp1 == 1L; + } else if (key.IsSameAs(KEY_APRS_HOSTNAME)) { + m_aprsHostname = val; + } else if (key.IsSameAs(KEY_APRS_PORT)) { + val.ToULong(&temp2); + m_aprsPort = (unsigned int)temp2; + } else if (key.IsSameAs(KEY_DEXTRA_ENABLED)) { + val.ToLong(&temp1); + m_dextraEnabled = temp1 == 1L; + } else if (key.IsSameAs(KEY_DEXTRA_MAXDONGLES)) { + val.ToULong(&temp2); + m_dextraMaxDongles = (unsigned int)temp2; + } else if (key.IsSameAs(KEY_DPLUS_ENABLED)) { + val.ToLong(&temp1); + m_dplusEnabled = temp1 == 1L; + } else if (key.IsSameAs(KEY_DPLUS_MAXDONGLES)) { + val.ToULong(&temp2); + m_dplusMaxDongles = (unsigned int)temp2; + } else if (key.IsSameAs(KEY_DPLUS_LOGIN)) { + m_dplusLogin = val; + } else if (key.IsSameAs(KEY_DCS_ENABLED)) { + val.ToLong(&temp1); + m_dcsEnabled = temp1 == 1L; + } else if (key.IsSameAs(KEY_CCS_ENABLED)) { + val.ToLong(&temp1); + m_ccsEnabled = temp1 == 1L; + } else if (key.IsSameAs(KEY_CCS_HOST)) { + m_ccsHost = val; + } else if (key.IsSameAs(KEY_XLX_ENABLED)) { + val.ToLong(&temp1); + m_xlxEnabled = temp1 == 1L; + } else if (key.IsSameAs(KEY_XLX_OVERRIDE_LOCAL)) { + val.ToLong(&temp1); + m_xlxOverrideLocal = temp1 == 1L; + } else if (key.IsSameAs(KEY_XLX_HOSTS_FILE_URL)) { + m_xlxHostsFileUrl = val; + } else if (key.IsSameAs(KEY_STARNET_BAND1)) { + m_starNet1Band = val; + } else if (key.IsSameAs(KEY_STARNET_CALLSIGN1)) { + m_starNet1Callsign = val; + } else if (key.IsSameAs(KEY_STARNET_LOGOFF1)) { + m_starNet1Logoff = val; + } else if (key.IsSameAs(KEY_STARNET_INFO1)) { + m_starNet1Info = val; + } else if (key.IsSameAs(KEY_STARNET_PERMANENT1)) { + m_starNet1Permanent = val; + } else if (key.IsSameAs(KEY_STARNET_USER_TIMEOUT1)) { + val.ToULong(&temp2); + m_starNet1UserTimeout = (unsigned int)temp2; + } else if (key.IsSameAs(KEY_STARNET_GROUP_TIMEOUT1)) { + val.ToULong(&temp2); + m_starNet1GroupTimeout = (unsigned int)temp2; + } else if (key.IsSameAs(KEY_STARNET_CALLSIGN_SWITCH1)) { + val.ToLong(&temp1); + m_starNet1CallsignSwitch = STARNET_CALLSIGN_SWITCH(temp1); + } else if (key.IsSameAs(KEY_STARNET_TXMSG_SWITCH1)) { + val.ToLong(&temp1); + m_starNet1TxMsgSwitch = temp1 == 1L; + } else if (key.IsSameAs(KEY_STARNET_REFLECTOR1)) { + m_starNet1Reflector = val; + } else if (key.IsSameAs(KEY_STARNET_BAND2)) { + m_starNet2Band = val; + } else if (key.IsSameAs(KEY_STARNET_CALLSIGN2)) { + m_starNet2Callsign = val; + } else if (key.IsSameAs(KEY_STARNET_LOGOFF2)) { + m_starNet2Logoff = val; + } else if (key.IsSameAs(KEY_STARNET_INFO2)) { + m_starNet2Info = val; + } else if (key.IsSameAs(KEY_STARNET_PERMANENT2)) { + m_starNet2Permanent = val; + } else if (key.IsSameAs(KEY_STARNET_USER_TIMEOUT2)) { + val.ToULong(&temp2); + m_starNet2UserTimeout = (unsigned int)temp2; + } else if (key.IsSameAs(KEY_STARNET_GROUP_TIMEOUT2)) { + val.ToULong(&temp2); + m_starNet2GroupTimeout = (unsigned int)temp2; + } else if (key.IsSameAs(KEY_STARNET_CALLSIGN_SWITCH2)) { + val.ToLong(&temp1); + m_starNet2CallsignSwitch = STARNET_CALLSIGN_SWITCH(temp1); + } else if (key.IsSameAs(KEY_STARNET_TXMSG_SWITCH2)) { + val.ToLong(&temp1); + m_starNet2TxMsgSwitch = temp1 == 1L; + } else if (key.IsSameAs(KEY_STARNET_REFLECTOR2)) { + m_starNet2Reflector = val; + } else if (key.IsSameAs(KEY_STARNET_BAND3)) { + m_starNet3Band = val; + } else if (key.IsSameAs(KEY_STARNET_CALLSIGN3)) { + m_starNet3Callsign = val; + } else if (key.IsSameAs(KEY_STARNET_LOGOFF3)) { + m_starNet3Logoff = val; + } else if (key.IsSameAs(KEY_STARNET_INFO3)) { + m_starNet3Info = val; + } else if (key.IsSameAs(KEY_STARNET_PERMANENT3)) { + m_starNet3Permanent = val; + } else if (key.IsSameAs(KEY_STARNET_USER_TIMEOUT3)) { + val.ToULong(&temp2); + m_starNet3UserTimeout = (unsigned int)temp2; + } else if (key.IsSameAs(KEY_STARNET_GROUP_TIMEOUT3)) { + val.ToULong(&temp2); + m_starNet3GroupTimeout = (unsigned int)temp2; + } else if (key.IsSameAs(KEY_STARNET_CALLSIGN_SWITCH3)) { + val.ToLong(&temp1); + m_starNet3CallsignSwitch = STARNET_CALLSIGN_SWITCH(temp1); + } else if (key.IsSameAs(KEY_STARNET_TXMSG_SWITCH3)) { + val.ToLong(&temp1); + m_starNet3TxMsgSwitch = temp1 == 1L; + } else if (key.IsSameAs(KEY_STARNET_REFLECTOR3)) { + m_starNet3Reflector = val; + } else if (key.IsSameAs(KEY_STARNET_BAND4)) { + m_starNet4Band = val; + } else if (key.IsSameAs(KEY_STARNET_CALLSIGN4)) { + m_starNet4Callsign = val; + } else if (key.IsSameAs(KEY_STARNET_LOGOFF4)) { + m_starNet4Logoff = val; + } else if (key.IsSameAs(KEY_STARNET_INFO4)) { + m_starNet4Info = val; + } else if (key.IsSameAs(KEY_STARNET_PERMANENT4)) { + m_starNet4Permanent = val; + } else if (key.IsSameAs(KEY_STARNET_USER_TIMEOUT4)) { + val.ToULong(&temp2); + m_starNet4UserTimeout = (unsigned int)temp2; + } else if (key.IsSameAs(KEY_STARNET_GROUP_TIMEOUT4)) { + val.ToULong(&temp2); + m_starNet4GroupTimeout = (unsigned int)temp2; + } else if (key.IsSameAs(KEY_STARNET_CALLSIGN_SWITCH4)) { + val.ToLong(&temp1); + m_starNet4CallsignSwitch = STARNET_CALLSIGN_SWITCH(temp1); + } else if (key.IsSameAs(KEY_STARNET_TXMSG_SWITCH4)) { + val.ToLong(&temp1); + m_starNet4TxMsgSwitch = temp1 == 1L; + } else if (key.IsSameAs(KEY_STARNET_REFLECTOR4)) { + m_starNet4Reflector = val; + } else if (key.IsSameAs(KEY_STARNET_BAND5)) { + m_starNet5Band = val; + } else if (key.IsSameAs(KEY_STARNET_CALLSIGN5)) { + m_starNet5Callsign = val; + } else if (key.IsSameAs(KEY_STARNET_LOGOFF5)) { + m_starNet5Logoff = val; + } else if (key.IsSameAs(KEY_STARNET_INFO5)) { + m_starNet5Info = val; + } else if (key.IsSameAs(KEY_STARNET_PERMANENT5)) { + m_starNet5Permanent = val; + } else if (key.IsSameAs(KEY_STARNET_USER_TIMEOUT5)) { + val.ToULong(&temp2); + m_starNet5UserTimeout = (unsigned int)temp2; + } else if (key.IsSameAs(KEY_STARNET_GROUP_TIMEOUT5)) { + val.ToULong(&temp2); + m_starNet5GroupTimeout = (unsigned int)temp2; + } else if (key.IsSameAs(KEY_STARNET_CALLSIGN_SWITCH5)) { + val.ToLong(&temp1); + m_starNet5CallsignSwitch = STARNET_CALLSIGN_SWITCH(temp1); + } else if (key.IsSameAs(KEY_STARNET_TXMSG_SWITCH5)) { + val.ToLong(&temp1); + m_starNet5TxMsgSwitch = temp1 == 1L; + } else if (key.IsSameAs(KEY_STARNET_REFLECTOR5)) { + m_starNet5Reflector = val; + } else if (key.IsSameAs(KEY_REMOTE_ENABLED)) { + val.ToLong(&temp1); + m_remoteEnabled = temp1 == 1L; + } else if (key.IsSameAs(KEY_REMOTE_PASSWORD)) { + m_remotePassword = val; + } else if (key.IsSameAs(KEY_REMOTE_PORT)) { + val.ToULong(&temp2); + m_remotePort = (unsigned int)temp2; + } else if (key.IsSameAs(KEY_LANGUAGE)) { + val.ToLong(&temp1); + m_language = TEXT_LANG(temp1); + } else if (key.IsSameAs(KEY_INFO_ENABLED)) { + val.ToLong(&temp1); + m_infoEnabled = temp1 == 1L; + } else if (key.IsSameAs(KEY_ECHO_ENABLED)) { + val.ToLong(&temp1); + m_echoEnabled = temp1 == 1L; + } else if (key.IsSameAs(KEY_LOG_ENABLED)) { + val.ToLong(&temp1); + m_logEnabled = temp1 == 1L; + } else if (key.IsSameAs(KEY_DRATS_ENABLED)) { + val.ToLong(&temp1); + m_dratsEnabled = temp1 == 1L; + } else if (key.IsSameAs(KEY_DTMF_ENABLED)) { + val.ToLong(&temp1); + m_dtmfEnabled = temp1 == 1L; + } else if (key.IsSameAs(KEY_WINDOW_X)) { + val.ToLong(&temp1); + m_x = int(temp1); + } else if (key.IsSameAs(KEY_WINDOW_Y)) { + val.ToLong(&temp1); + m_y = int(temp1); + } + + str = file.GetNextLine(); + } + + file.Close(); +} + +CIRCDDBGatewayConfig::~CIRCDDBGatewayConfig() +{ +} + +#endif + +void CIRCDDBGatewayConfig::getGateway(GATEWAY_TYPE& type, wxString& callsign, wxString& address, wxString& icomAddress, unsigned int& icomPort, wxString& hbAddress, unsigned int& hbPort, double& latitude, double& longitude, wxString& description1, wxString& description2, wxString& url) const +{ + type = m_type; + callsign = m_callsign; + address = m_address; + icomAddress = m_icomAddress; + icomPort = m_icomPort; + hbAddress = m_hbAddress; + hbPort = m_hbPort; + latitude = m_latitude; + longitude = m_longitude; + description1 = m_description1; + description2 = m_description2; + url = m_url; + + if (address.IsSameAs(wxT("127.0.0.1"))) + address.Clear(); +} + +void CIRCDDBGatewayConfig::setGateway(GATEWAY_TYPE type, const wxString& callsign, const wxString& address, const wxString& icomAddress, unsigned int icomPort, const wxString& hbAddress, unsigned int hbPort, double latitude, double longitude, const wxString& description1, const wxString& description2, const wxString& url) +{ + m_type = type; + m_callsign = callsign; + m_address = address; + m_icomAddress = icomAddress; + m_icomPort = icomPort; + m_hbAddress = hbAddress; + m_hbPort = hbPort; + m_latitude = latitude; + m_longitude = longitude; + m_description1 = description1; + m_description2 = description2; + m_url = url; +} + +void CIRCDDBGatewayConfig::getRepeater1(wxString& callsign, wxString& band, HW_TYPE& type, wxString& address, unsigned int& port, unsigned char& band1, unsigned char& band2, unsigned char& band3, wxString& reflector, bool& atStartup, RECONNECT& reconnect, double& frequency, double& offset, double& range, double& latitude, double& longitude, double& agl, wxString& description1, wxString& description2, wxString& url) const +{ + callsign = m_repeater1Callsign; + band = m_repeater1Band; + type = m_repeater1Type; + address = m_repeater1Address; + port = m_repeater1Port; + band1 = m_repeater1Band1; + band2 = m_repeater1Band2; + band3 = m_repeater1Band3; + reflector = m_repeater1Reflector; + atStartup = m_repeater1AtStartup; + reconnect = m_repeater1Reconnect; + frequency = m_repeater1Frequency; + offset = m_repeater1Offset; + range = m_repeater1Range; + latitude = m_repeater1Latitude; + longitude = m_repeater1Longitude; + agl = m_repeater1Agl; + description1 = m_repeater1Description1; + description2 = m_repeater1Description2; + url = m_repeater1URL; +} + +void CIRCDDBGatewayConfig::setRepeater1(const wxString& band, HW_TYPE type, const wxString& address, unsigned int port, unsigned char band1, unsigned char band2, unsigned char band3, const wxString& reflector, bool atStartup, RECONNECT reconnect, double frequency, double offset, double range, double latitude, double longitude, double agl, const wxString& description1, const wxString& description2, const wxString& url) +{ + m_repeater1Band = band; + m_repeater1Type = type; + m_repeater1Address = address; + m_repeater1Port = port; + m_repeater1Band1 = band1; + m_repeater1Band2 = band2; + m_repeater1Band3 = band3; + m_repeater1Reflector = reflector; + m_repeater1AtStartup = atStartup; + m_repeater1Reconnect = reconnect; + m_repeater1Frequency = frequency; + m_repeater1Offset = offset; + m_repeater1Range = range; + m_repeater1Latitude = latitude; + m_repeater1Longitude = longitude; + m_repeater1Agl = agl; + m_repeater1Description1 = description1; + m_repeater1Description2 = description2; + m_repeater1URL = url; +} + +void CIRCDDBGatewayConfig::getRepeater2(wxString& callsign, wxString& band, HW_TYPE& type, wxString& address, unsigned int& port, unsigned char& band1, unsigned char& band2, unsigned char& band3, wxString& reflector, bool& atStartup, RECONNECT& reconnect, double& frequency, double& offset, double& range, double& latitude, double& longitude, double& agl, wxString& description1, wxString& description2, wxString& url) const +{ + callsign = m_repeater2Callsign; + band = m_repeater2Band; + type = m_repeater2Type; + address = m_repeater2Address; + port = m_repeater2Port; + band1 = m_repeater2Band1; + band2 = m_repeater2Band2; + band3 = m_repeater2Band3; + reflector = m_repeater2Reflector; + atStartup = m_repeater2AtStartup; + reconnect = m_repeater2Reconnect; + frequency = m_repeater2Frequency; + offset = m_repeater2Offset; + range = m_repeater2Range; + latitude = m_repeater2Latitude; + longitude = m_repeater2Longitude; + agl = m_repeater2Agl; + description1 = m_repeater2Description1; + description2 = m_repeater2Description2; + url = m_repeater2URL; +} + +void CIRCDDBGatewayConfig::setRepeater2(const wxString& band, HW_TYPE type, const wxString& address, unsigned int port, unsigned char band1, unsigned char band2, unsigned char band3, const wxString& reflector, bool atStartup, RECONNECT reconnect, double frequency, double offset, double range, double latitude, double longitude, double agl, const wxString& description1, const wxString& description2, const wxString& url) +{ + m_repeater2Band = band; + m_repeater2Type = type; + m_repeater2Address = address; + m_repeater2Port = port; + m_repeater2Band1 = band1; + m_repeater2Band2 = band2; + m_repeater2Band3 = band3; + m_repeater2Reflector = reflector; + m_repeater2AtStartup = atStartup; + m_repeater2Reconnect = reconnect; + m_repeater2Frequency = frequency; + m_repeater2Offset = offset; + m_repeater2Range = range; + m_repeater2Latitude = latitude; + m_repeater2Longitude = longitude; + m_repeater2Agl = agl; + m_repeater2Description1 = description1; + m_repeater2Description2 = description2; + m_repeater2URL = url; +} + +void CIRCDDBGatewayConfig::getRepeater3(wxString& callsign, wxString& band, HW_TYPE& type, wxString& address, unsigned int& port, unsigned char& band1, unsigned char& band2, unsigned char& band3, wxString& reflector, bool& atStartup, RECONNECT& reconnect, double& frequency, double& offset, double& range, double& latitude, double& longitude, double& agl, wxString& description1, wxString& description2, wxString& url) const +{ + callsign = m_repeater3Callsign; + band = m_repeater3Band; + type = m_repeater3Type; + address = m_repeater3Address; + port = m_repeater3Port; + band1 = m_repeater3Band1; + band2 = m_repeater3Band2; + band3 = m_repeater3Band3; + reflector = m_repeater3Reflector; + atStartup = m_repeater3AtStartup; + reconnect = m_repeater3Reconnect; + frequency = m_repeater3Frequency; + offset = m_repeater3Offset; + range = m_repeater3Range; + latitude = m_repeater3Latitude; + longitude = m_repeater3Longitude; + agl = m_repeater3Agl; + description1 = m_repeater3Description1; + description2 = m_repeater3Description2; + url = m_repeater3URL; +} + +void CIRCDDBGatewayConfig::setRepeater3(const wxString& band, HW_TYPE type, const wxString& address, unsigned int port, unsigned char band1, unsigned char band2, unsigned char band3, const wxString& reflector, bool atStartup, RECONNECT reconnect, double frequency, double offset, double range, double latitude, double longitude, double agl, const wxString& description1, const wxString& description2, const wxString& url) +{ + m_repeater3Band = band; + m_repeater3Type = type; + m_repeater3Address = address; + m_repeater3Port = port; + m_repeater3Band1 = band1; + m_repeater3Band2 = band2; + m_repeater3Band3 = band3; + m_repeater3Reflector = reflector; + m_repeater3AtStartup = atStartup; + m_repeater3Reconnect = reconnect; + m_repeater3Frequency = frequency; + m_repeater3Offset = offset; + m_repeater3Range = range; + m_repeater3Latitude = latitude; + m_repeater3Longitude = longitude; + m_repeater3Agl = agl; + m_repeater3Description1 = description1; + m_repeater3Description2 = description2; + m_repeater3URL = url; +} + +void CIRCDDBGatewayConfig::getRepeater4(wxString& callsign, wxString& band, HW_TYPE& type, wxString& address, unsigned int& port, unsigned char& band1, unsigned char& band2, unsigned char& band3, wxString& reflector, bool& atStartup, RECONNECT& reconnect, double& frequency, double& offset, double& range, double& latitude, double& longitude, double& agl, wxString& description1, wxString& description2, wxString& url) const +{ + callsign = m_repeater4Callsign; + band = m_repeater4Band; + type = m_repeater4Type; + address = m_repeater4Address; + port = m_repeater4Port; + band1 = m_repeater4Band1; + band2 = m_repeater4Band2; + band3 = m_repeater4Band3; + reflector = m_repeater4Reflector; + atStartup = m_repeater4AtStartup; + reconnect = m_repeater4Reconnect; + frequency = m_repeater4Frequency; + offset = m_repeater4Offset; + range = m_repeater4Range; + latitude = m_repeater4Latitude; + longitude = m_repeater4Longitude; + agl = m_repeater4Agl; + description1 = m_repeater4Description1; + description2 = m_repeater4Description2; + url = m_repeater4URL; +} + +void CIRCDDBGatewayConfig::setRepeater4(const wxString& band, HW_TYPE type, const wxString& address, unsigned int port, unsigned char band1, unsigned char band2, unsigned char band3, const wxString& reflector, bool atStartup, RECONNECT reconnect, double frequency, double offset, double range, double latitude, double longitude, double agl, const wxString& description1, const wxString& description2, const wxString& url) +{ + m_repeater4Band = band; + m_repeater4Type = type; + m_repeater4Address = address; + m_repeater4Port = port; + m_repeater4Band1 = band1; + m_repeater4Band2 = band2; + m_repeater4Band3 = band3; + m_repeater4Reflector = reflector; + m_repeater4AtStartup = atStartup; + m_repeater4Reconnect = reconnect; + m_repeater4Frequency = frequency; + m_repeater4Offset = offset; + m_repeater4Range = range; + m_repeater4Latitude = latitude; + m_repeater4Longitude = longitude; + m_repeater4Agl = agl; + m_repeater4Description1 = description1; + m_repeater4Description2 = description2; + m_repeater4URL = url; +} + +void CIRCDDBGatewayConfig::getIrcDDB(bool& enabled, wxString& hostname, wxString& username, wxString& password) const +{ + enabled = m_ircddbEnabled; + hostname = m_ircddbHostname; + username = m_ircddbUsername; + password = m_ircddbPassword; +} + +void CIRCDDBGatewayConfig::setIrcDDB(bool enabled, const wxString& hostname, const wxString& username, const wxString& password) +{ + m_ircddbEnabled = enabled; + m_ircddbHostname = hostname; + m_ircddbUsername = username; + m_ircddbPassword = password; +} + +void CIRCDDBGatewayConfig::getIrcDDB2(bool& enabled, wxString& hostname, wxString& username, wxString& password) const +{ + enabled = m_ircddbEnabled2; + hostname = m_ircddbHostname2; + username = m_ircddbUsername2; + + /*if(username.IsEmpty()){ + //no user specified for openquad? use the one from the default network ! + username = m_ircddbUsername; + if(username[0] >= '0' && username[0] <= '9') + username = wxT("r") + username; + }*/ + + password = m_ircddbPassword2; +} + +void CIRCDDBGatewayConfig::setIrcDDB2(bool enabled, const wxString& hostname, const wxString& username, const wxString& password) +{ + m_ircddbEnabled2 = enabled; + m_ircddbHostname2 = hostname; + m_ircddbUsername2 = username; + m_ircddbPassword2 = password; +} + +void CIRCDDBGatewayConfig::getIrcDDB3(bool& enabled, wxString& hostname, wxString& username, wxString& password) const +{ + enabled = m_ircddbEnabled3; + hostname = m_ircddbHostname3; + username = m_ircddbUsername3; + password = m_ircddbPassword3; +} + +void CIRCDDBGatewayConfig::setIrcDDB3(bool enabled, const wxString& hostname, const wxString& username, const wxString& password) +{ + m_ircddbEnabled3 = enabled; + m_ircddbHostname3 = hostname; + m_ircddbUsername3 = username; + m_ircddbPassword3 = password; +} + +void CIRCDDBGatewayConfig::getIrcDDB4(bool& enabled, wxString& hostname, wxString& username, wxString& password) const +{ + enabled = m_ircddbEnabled4; + hostname = m_ircddbHostname4; + username = m_ircddbUsername4; + password = m_ircddbPassword4; +} + +void CIRCDDBGatewayConfig::setIrcDDB4(bool enabled, const wxString& hostname, const wxString& username, const wxString& password) +{ + m_ircddbEnabled4 = enabled; + m_ircddbHostname4 = hostname; + m_ircddbUsername4 = username; + m_ircddbPassword4 = password; +} + +void CIRCDDBGatewayConfig::getDPRS(bool& enabled, wxString& hostname, unsigned int& port) const +{ + enabled = m_aprsEnabled; + hostname = m_aprsHostname; + port = m_aprsPort; +} + +void CIRCDDBGatewayConfig::setDPRS(bool enabled, const wxString& hostname, unsigned int port) +{ + m_aprsEnabled = enabled; + m_aprsHostname = hostname; + m_aprsPort = port; +} + +void CIRCDDBGatewayConfig::getDExtra(bool& enabled, unsigned int& maxDongles) const +{ + enabled = m_dextraEnabled; + maxDongles = m_dextraMaxDongles; +} + +void CIRCDDBGatewayConfig::setDExtra(bool enabled, unsigned int maxDongles) +{ + m_dextraEnabled = enabled; + m_dextraMaxDongles = maxDongles; +} + +void CIRCDDBGatewayConfig::getDPlus(bool& enabled, unsigned int& maxDongles, wxString& login) const +{ + enabled = m_dplusEnabled; + maxDongles = m_dplusMaxDongles; + login = m_dplusLogin; +} + +void CIRCDDBGatewayConfig::setDPlus(bool enabled, unsigned int maxDongles, const wxString& login) +{ + m_dplusEnabled = enabled; + m_dplusMaxDongles = maxDongles; + m_dplusLogin = login; +} + +void CIRCDDBGatewayConfig::getDCS(bool& dcsEnabled, bool& ccsEnabled, wxString& ccsHost) const +{ + dcsEnabled = m_dcsEnabled; + ccsEnabled = m_ccsEnabled; + ccsHost = m_ccsHost; +} + +void CIRCDDBGatewayConfig::setDCS(bool dcsEnabled, bool ccsEnabled, const wxString& ccsHost) +{ + m_dcsEnabled = dcsEnabled; + m_ccsEnabled = ccsEnabled; + m_ccsHost = ccsHost; +} + +void CIRCDDBGatewayConfig::getXLX(bool& xlxEnabled, bool& xlxOverrideLocal, wxString& xlxHostsFileUrl) +{ + xlxEnabled = m_xlxEnabled; + xlxOverrideLocal = m_xlxOverrideLocal; + xlxHostsFileUrl = m_xlxHostsFileUrl; +} + +void CIRCDDBGatewayConfig::setXLX(bool xlxEnabled, bool xlxOverrideLocal, wxString xlxHostsFileUrl) +{ + m_xlxEnabled = xlxEnabled; + m_xlxOverrideLocal = xlxOverrideLocal; + m_xlxHostsFileUrl = xlxHostsFileUrl; +} + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) +void CIRCDDBGatewayConfig::getStarNet1(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch, wxString& reflector) const +#else +void CIRCDDBGatewayConfig::getStarNet1(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch) const +#endif +{ + band = m_starNet1Band; + callsign = m_starNet1Callsign; + logoff = m_starNet1Logoff; + info = m_starNet1Info; + permanent = m_starNet1Permanent; + userTimeout = m_starNet1UserTimeout; + groupTimeout = m_starNet1GroupTimeout; + callsignSwitch = m_starNet1CallsignSwitch; + txMsgSwitch = m_starNet1TxMsgSwitch; + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + reflector = m_starNet1Reflector; +#endif +} + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) +void CIRCDDBGatewayConfig::setStarNet1(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch, const wxString& reflector) +#else +void CIRCDDBGatewayConfig::setStarNet1(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch) +#endif +{ + m_starNet1Band = band; + m_starNet1Callsign = callsign; + m_starNet1Logoff = logoff; + m_starNet1Info = info; + m_starNet1Permanent = permanent; + m_starNet1UserTimeout = userTimeout; + m_starNet1GroupTimeout = groupTimeout; + m_starNet1CallsignSwitch = callsignSwitch; + m_starNet1TxMsgSwitch = txMsgSwitch; + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + m_starNet1Reflector = reflector; +#endif +} + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) +void CIRCDDBGatewayConfig::getStarNet2(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch, wxString& reflector) const +#else +void CIRCDDBGatewayConfig::getStarNet2(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch) const +#endif +{ + band = m_starNet2Band; + callsign = m_starNet2Callsign; + logoff = m_starNet2Logoff; + info = m_starNet2Info; + permanent = m_starNet2Permanent; + userTimeout = m_starNet2UserTimeout; + groupTimeout = m_starNet2GroupTimeout; + callsignSwitch = m_starNet2CallsignSwitch; + txMsgSwitch = m_starNet2TxMsgSwitch; + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + reflector = m_starNet2Reflector; +#endif +} + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) +void CIRCDDBGatewayConfig::setStarNet2(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch, const wxString& reflector) +#else +void CIRCDDBGatewayConfig::setStarNet2(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch) +#endif +{ + m_starNet2Band = band; + m_starNet2Callsign = callsign; + m_starNet2Logoff = logoff; + m_starNet2Info = info; + m_starNet2Permanent = permanent; + m_starNet2UserTimeout = userTimeout; + m_starNet2GroupTimeout = groupTimeout; + m_starNet2CallsignSwitch = callsignSwitch; + m_starNet2TxMsgSwitch = txMsgSwitch; + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + m_starNet2Reflector = reflector; +#endif +} + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) +void CIRCDDBGatewayConfig::getStarNet3(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch, wxString& reflector) const +#else +void CIRCDDBGatewayConfig::getStarNet3(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch) const +#endif +{ + band = m_starNet3Band; + callsign = m_starNet3Callsign; + logoff = m_starNet3Logoff; + info = m_starNet3Info; + permanent = m_starNet3Permanent; + userTimeout = m_starNet3UserTimeout; + groupTimeout = m_starNet3GroupTimeout; + callsignSwitch = m_starNet3CallsignSwitch; + txMsgSwitch = m_starNet3TxMsgSwitch; + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + reflector = m_starNet3Reflector; +#endif +} + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) +void CIRCDDBGatewayConfig::setStarNet3(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch, const wxString& reflector) +#else +void CIRCDDBGatewayConfig::setStarNet3(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch) +#endif +{ + m_starNet3Band = band; + m_starNet3Callsign = callsign; + m_starNet3Logoff = logoff; + m_starNet3Info = info; + m_starNet3Permanent = permanent; + m_starNet3UserTimeout = userTimeout; + m_starNet3GroupTimeout = groupTimeout; + m_starNet3CallsignSwitch = callsignSwitch; + m_starNet3TxMsgSwitch = txMsgSwitch; + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + m_starNet3Reflector = reflector; +#endif +} + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) +void CIRCDDBGatewayConfig::getStarNet4(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch, wxString& reflector) const +#else +void CIRCDDBGatewayConfig::getStarNet4(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch) const +#endif +{ + band = m_starNet4Band; + callsign = m_starNet4Callsign; + logoff = m_starNet4Logoff; + info = m_starNet4Info; + permanent = m_starNet4Permanent; + userTimeout = m_starNet4UserTimeout; + groupTimeout = m_starNet4GroupTimeout; + callsignSwitch = m_starNet4CallsignSwitch; + txMsgSwitch = m_starNet4TxMsgSwitch; + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + reflector = m_starNet4Reflector; +#endif +} + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) +void CIRCDDBGatewayConfig::setStarNet4(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch, const wxString& reflector) +#else +void CIRCDDBGatewayConfig::setStarNet4(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch) +#endif +{ + m_starNet4Band = band; + m_starNet4Callsign = callsign; + m_starNet4Logoff = logoff; + m_starNet4Info = info; + m_starNet4Permanent = permanent; + m_starNet4UserTimeout = userTimeout; + m_starNet4GroupTimeout = groupTimeout; + m_starNet4CallsignSwitch = callsignSwitch; + m_starNet4TxMsgSwitch = txMsgSwitch; + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + m_starNet4Reflector = reflector; +#endif +} + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) +void CIRCDDBGatewayConfig::getStarNet5(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch, wxString& reflector) const +#else +void CIRCDDBGatewayConfig::getStarNet5(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch) const +#endif +{ + band = m_starNet5Band; + callsign = m_starNet5Callsign; + logoff = m_starNet5Logoff; + info = m_starNet5Info; + permanent = m_starNet5Permanent; + userTimeout = m_starNet5UserTimeout; + groupTimeout = m_starNet5GroupTimeout; + callsignSwitch = m_starNet5CallsignSwitch; + txMsgSwitch = m_starNet5TxMsgSwitch; + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + reflector = m_starNet5Reflector; +#endif +} + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) +void CIRCDDBGatewayConfig::setStarNet5(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch, const wxString& reflector) +#else +void CIRCDDBGatewayConfig::setStarNet5(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch) +#endif +{ + m_starNet5Band = band; + m_starNet5Callsign = callsign; + m_starNet5Logoff = logoff; + m_starNet5Info = info; + m_starNet5Permanent = permanent; + m_starNet5UserTimeout = userTimeout; + m_starNet5GroupTimeout = groupTimeout; + m_starNet5CallsignSwitch = callsignSwitch; + m_starNet5TxMsgSwitch = txMsgSwitch; + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + m_starNet5Reflector = reflector; +#endif +} + +void CIRCDDBGatewayConfig::getRemote(bool& enabled, wxString& password, unsigned int& port) const +{ + enabled = m_remoteEnabled; + password = m_remotePassword; + port = m_remotePort; +} + +void CIRCDDBGatewayConfig::setRemote(bool enabled, const wxString& password, unsigned int port) +{ + m_remoteEnabled = enabled; + m_remotePassword = password; + m_remotePort = port; +} + +void CIRCDDBGatewayConfig::getMiscellaneous(TEXT_LANG& language, bool& infoEnabled, bool& echoEnabled, bool& logEnabled, bool& dratsEnabled, bool& dtmfEnabled) const +{ + language = m_language; + infoEnabled = m_infoEnabled; + echoEnabled = m_echoEnabled; + logEnabled = m_logEnabled; + dratsEnabled = m_dratsEnabled; + dtmfEnabled = m_dtmfEnabled; +} + +void CIRCDDBGatewayConfig::setMiscellaneous(TEXT_LANG language, bool infoEnabled, bool echoEnabled, bool logEnabled, bool dratsEnabled, bool dtmfEnabled) +{ + m_language = language; + m_infoEnabled = infoEnabled; + m_echoEnabled = echoEnabled; + m_logEnabled = logEnabled; + m_dratsEnabled = dratsEnabled; + m_dtmfEnabled = dtmfEnabled; +} + +void CIRCDDBGatewayConfig::getPosition(int& x, int& y) const +{ + x = m_x; + y = m_y; +} + +void CIRCDDBGatewayConfig::setPosition(int x, int y) +{ + m_x = x; + m_y = y; +} + +bool CIRCDDBGatewayConfig::write() +{ +#if defined(__WINDOWS__) + wxString text; + + m_config->Write(m_name + KEY_GATEWAY_TYPE, long(m_type)); + m_config->Write(m_name + KEY_GATEWAY_CALLSIGN, m_callsign); + m_config->Write(m_name + KEY_GATEWAY_ADDRESS, m_address); + m_config->Write(m_name + KEY_ICOM_ADDRESS, m_icomAddress); + m_config->Write(m_name + KEY_ICOM_PORT, long(m_icomPort)); + m_config->Write(m_name + KEY_HB_ADDRESS, m_hbAddress); + m_config->Write(m_name + KEY_HB_PORT, long(m_hbPort)); + + text.Printf(wxT("%.6lf"), m_latitude); + m_config->Write(m_name + KEY_LATITUDE, text); + + text.Printf(wxT("%.6lf"), m_longitude); + m_config->Write(m_name + KEY_LONGITUDE, text); + + m_config->Write(m_name + KEY_DESCRIPTION1, m_description1); + m_config->Write(m_name + KEY_DESCRIPTION2, m_description2); + m_config->Write(m_name + KEY_URL, m_url); + m_config->Write(m_name + KEY_REPEATER_BAND1, m_repeater1Band); + m_config->Write(m_name + KEY_REPEATER_TYPE1, long(m_repeater1Type)); + m_config->Write(m_name + KEY_REPEATER_ADDRESS1, m_repeater1Address); + m_config->Write(m_name + KEY_REPEATER_PORT1, long(m_repeater1Port)); + m_config->Write(m_name + KEY_REFLECTOR1, m_repeater1Reflector); + m_config->Write(m_name + KEY_ATSTARTUP1, m_repeater1AtStartup); + m_config->Write(m_name + KEY_RECONNECT1, long(m_repeater1Reconnect)); + + text.Printf(wxT("%.5lf"), m_repeater1Frequency); + m_config->Write(m_name + KEY_FREQUENCY1, text); + + text.Printf(wxT("%.4lf"), m_repeater1Offset); + m_config->Write(m_name + KEY_OFFSET1, text); + + m_config->Write(m_name + KEY_RANGE1, m_repeater1Range); + + text.Printf(wxT("%.6lf"), m_repeater1Latitude); + m_config->Write(m_name + KEY_LATITUDE1, text); + + text.Printf(wxT("%.6lf"), m_repeater1Longitude); + m_config->Write(m_name + KEY_LONGITUDE1, text); + + m_config->Write(m_name + KEY_AGL1, m_repeater1Agl); + m_config->Write(m_name + KEY_DESCRIPTION11, m_repeater1Description1); + m_config->Write(m_name + KEY_DESCRIPTION12, m_repeater1Description2); + m_config->Write(m_name + KEY_URL1, m_repeater1URL); + m_config->Write(m_name + KEY_BAND11, long(m_repeater1Band1)); + m_config->Write(m_name + KEY_BAND12, long(m_repeater1Band2)); + m_config->Write(m_name + KEY_BAND13, long(m_repeater1Band3)); + m_config->Write(m_name + KEY_REPEATER_BAND2, m_repeater2Band); + m_config->Write(m_name + KEY_REPEATER_TYPE2, long(m_repeater2Type)); + m_config->Write(m_name + KEY_REPEATER_ADDRESS2, m_repeater2Address); + m_config->Write(m_name + KEY_REPEATER_PORT2, long(m_repeater2Port)); + m_config->Write(m_name + KEY_REFLECTOR2, m_repeater2Reflector); + m_config->Write(m_name + KEY_ATSTARTUP2, m_repeater2AtStartup); + m_config->Write(m_name + KEY_RECONNECT2, long(m_repeater2Reconnect)); + + text.Printf(wxT("%.5lf"), m_repeater2Frequency); + m_config->Write(m_name + KEY_FREQUENCY2, text); + + text.Printf(wxT("%.4lf"), m_repeater2Offset); + m_config->Write(m_name + KEY_OFFSET2, text); + + m_config->Write(m_name + KEY_RANGE2, m_repeater2Range); + + text.Printf(wxT("%.6lf"), m_repeater2Latitude); + m_config->Write(m_name + KEY_LATITUDE2, text); + + text.Printf(wxT("%.6lf"), m_repeater2Longitude); + m_config->Write(m_name + KEY_LONGITUDE2, text); + + m_config->Write(m_name + KEY_AGL2, m_repeater2Agl); + m_config->Write(m_name + KEY_DESCRIPTION21, m_repeater2Description1); + m_config->Write(m_name + KEY_DESCRIPTION22, m_repeater2Description2); + m_config->Write(m_name + KEY_URL2, m_repeater2URL); + m_config->Write(m_name + KEY_BAND21, long(m_repeater2Band1)); + m_config->Write(m_name + KEY_BAND22, long(m_repeater2Band2)); + m_config->Write(m_name + KEY_BAND23, long(m_repeater2Band3)); + m_config->Write(m_name + KEY_REPEATER_BAND3, m_repeater3Band); + m_config->Write(m_name + KEY_REPEATER_TYPE3, long(m_repeater3Type)); + m_config->Write(m_name + KEY_REPEATER_ADDRESS3, m_repeater3Address); + m_config->Write(m_name + KEY_REPEATER_PORT3, long(m_repeater3Port)); + m_config->Write(m_name + KEY_REFLECTOR3, m_repeater3Reflector); + m_config->Write(m_name + KEY_ATSTARTUP3, m_repeater3AtStartup); + m_config->Write(m_name + KEY_RECONNECT3, long(m_repeater3Reconnect)); + + text.Printf(wxT("%.5lf"), m_repeater3Frequency); + m_config->Write(m_name + KEY_FREQUENCY3, text); + + text.Printf(wxT("%.4lf"), m_repeater3Offset); + m_config->Write(m_name + KEY_OFFSET3, text); + + m_config->Write(m_name + KEY_RANGE3, m_repeater3Range); + + text.Printf(wxT("%.6lf"), m_repeater3Latitude); + m_config->Write(m_name + KEY_LATITUDE3, text); + + text.Printf(wxT("%.6lf"), m_repeater3Longitude); + m_config->Write(m_name + KEY_LONGITUDE3, text); + + m_config->Write(m_name + KEY_AGL3, m_repeater3Agl); + m_config->Write(m_name + KEY_DESCRIPTION31, m_repeater3Description1); + m_config->Write(m_name + KEY_DESCRIPTION32, m_repeater3Description2); + m_config->Write(m_name + KEY_URL3, m_repeater3URL); + m_config->Write(m_name + KEY_BAND31, long(m_repeater3Band1)); + m_config->Write(m_name + KEY_BAND32, long(m_repeater3Band2)); + m_config->Write(m_name + KEY_BAND33, long(m_repeater3Band3)); + m_config->Write(m_name + KEY_REPEATER_BAND4, m_repeater4Band); + m_config->Write(m_name + KEY_REPEATER_TYPE4, long(m_repeater4Type)); + m_config->Write(m_name + KEY_REPEATER_ADDRESS4, m_repeater4Address); + m_config->Write(m_name + KEY_REPEATER_PORT4, long(m_repeater4Port)); + m_config->Write(m_name + KEY_REFLECTOR4, m_repeater4Reflector); + m_config->Write(m_name + KEY_ATSTARTUP4, m_repeater4AtStartup); + m_config->Write(m_name + KEY_RECONNECT4, long(m_repeater4Reconnect)); + + text.Printf(wxT("%.5lf"), m_repeater4Frequency); + m_config->Write(m_name + KEY_FREQUENCY4, text); + + text.Printf(wxT("%.4lf"), m_repeater4Offset); + m_config->Write(m_name + KEY_OFFSET4, text); + + m_config->Write(m_name + KEY_RANGE4, m_repeater4Range); + + text.Printf(wxT("%.6lf"), m_repeater4Latitude); + m_config->Write(m_name + KEY_LATITUDE4, text); + + text.Printf(wxT("%.6lf"), m_repeater4Longitude); + m_config->Write(m_name + KEY_LONGITUDE4, text); + + m_config->Write(m_name + KEY_AGL4, m_repeater4Agl); + m_config->Write(m_name + KEY_DESCRIPTION41, m_repeater4Description1); + m_config->Write(m_name + KEY_DESCRIPTION42, m_repeater4Description2); + m_config->Write(m_name + KEY_URL4, m_repeater4URL); + m_config->Write(m_name + KEY_BAND41, long(m_repeater4Band1)); + m_config->Write(m_name + KEY_BAND42, long(m_repeater4Band2)); + m_config->Write(m_name + KEY_BAND43, long(m_repeater4Band3)); + m_config->Write(m_name + KEY_IRCDDB_ENABLED, m_ircddbEnabled); + m_config->Write(m_name + KEY_IRCDDB_HOSTNAME, m_ircddbHostname); + m_config->Write(m_name + KEY_IRCDDB_USERNAME, m_ircddbUsername); + m_config->Write(m_name + KEY_IRCDDB_PASSWORD, m_ircddbPassword); + m_config->Write(m_name + KEY_IRCDDB_ENABLED2, m_ircddbEnabled2); + m_config->Write(m_name + KEY_IRCDDB_HOSTNAME2, m_ircddbHostname2); + m_config->Write(m_name + KEY_IRCDDB_USERNAME2, m_ircddbUsername2); + m_config->Write(m_name + KEY_IRCDDB_PASSWORD2, m_ircddbPassword2); + m_config->Write(m_name + KEY_IRCDDB_ENABLED3, m_ircddbEnabled3); + m_config->Write(m_name + KEY_IRCDDB_HOSTNAME3, m_ircddbHostname3); + m_config->Write(m_name + KEY_IRCDDB_USERNAME3, m_ircddbUsername3); + m_config->Write(m_name + KEY_IRCDDB_PASSWORD3, m_ircddbPassword3); + m_config->Write(m_name + KEY_IRCDDB_ENABLED4, m_ircddbEnabled4); + m_config->Write(m_name + KEY_IRCDDB_HOSTNAME4, m_ircddbHostname4); + m_config->Write(m_name + KEY_IRCDDB_USERNAME4, m_ircddbUsername4); + m_config->Write(m_name + KEY_IRCDDB_PASSWORD4, m_ircddbPassword4); + m_config->Write(m_name + KEY_APRS_ENABLED, m_aprsEnabled); + m_config->Write(m_name + KEY_APRS_HOSTNAME, m_aprsHostname); + m_config->Write(m_name + KEY_APRS_PORT, long(m_aprsPort)); + m_config->Write(m_name + KEY_DEXTRA_ENABLED, m_dextraEnabled); + m_config->Write(m_name + KEY_DEXTRA_MAXDONGLES, long(m_dextraMaxDongles)); + m_config->Write(m_name + KEY_DPLUS_ENABLED, m_dplusEnabled); + m_config->Write(m_name + KEY_DPLUS_MAXDONGLES, long(m_dplusMaxDongles)); + m_config->Write(m_name + KEY_DPLUS_LOGIN, m_dplusLogin); + m_config->Write(m_name + KEY_DCS_ENABLED, m_dcsEnabled); + m_config->Write(m_name + KEY_CCS_ENABLED, m_ccsEnabled); + m_config->Write(m_name + KEY_CCS_HOST, m_ccsHost); + m_config->Write(m_name + KEY_XLX_ENABLED, m_xlxEnabled); + m_config->Write(m_name + KEY_XLX_OVERRIDE_LOCAL, m_xlxOverrideLocal); + m_config->Write(m_name + KEY_XLX_HOSTS_FILE_URL, m_xlxHostsFileUrl); + m_config->Write(m_name + KEY_STARNET_BAND1, m_starNet1Band); + m_config->Write(m_name + KEY_STARNET_CALLSIGN1, m_starNet1Callsign); + m_config->Write(m_name + KEY_STARNET_LOGOFF1, m_starNet1Logoff); + m_config->Write(m_name + KEY_STARNET_INFO1, m_starNet1Info); + m_config->Write(m_name + KEY_STARNET_PERMANENT1, m_starNet1Permanent); + m_config->Write(m_name + KEY_STARNET_USER_TIMEOUT1, long(m_starNet1UserTimeout)); + m_config->Write(m_name + KEY_STARNET_GROUP_TIMEOUT1, long(m_starNet1GroupTimeout)); + m_config->Write(m_name + KEY_STARNET_CALLSIGN_SWITCH1, long(m_starNet1CallsignSwitch)); + m_config->Write(m_name + KEY_STARNET_TXMSG_SWITCH1, long(m_starNet1TxMsgSwitch)); + m_config->Write(m_name + KEY_STARNET_REFLECTOR1, m_starNet1Reflector); + m_config->Write(m_name + KEY_STARNET_BAND2, m_starNet2Band); + m_config->Write(m_name + KEY_STARNET_CALLSIGN2, m_starNet2Callsign); + m_config->Write(m_name + KEY_STARNET_LOGOFF2, m_starNet2Logoff); + m_config->Write(m_name + KEY_STARNET_INFO2, m_starNet2Info); + m_config->Write(m_name + KEY_STARNET_PERMANENT2, m_starNet2Permanent); + m_config->Write(m_name + KEY_STARNET_USER_TIMEOUT2, long(m_starNet2UserTimeout)); + m_config->Write(m_name + KEY_STARNET_GROUP_TIMEOUT2, long(m_starNet2GroupTimeout)); + m_config->Write(m_name + KEY_STARNET_CALLSIGN_SWITCH2, long(m_starNet2CallsignSwitch)); + m_config->Write(m_name + KEY_STARNET_TXMSG_SWITCH2, long(m_starNet2TxMsgSwitch)); + m_config->Write(m_name + KEY_STARNET_REFLECTOR2, m_starNet2Reflector); + m_config->Write(m_name + KEY_STARNET_BAND3, m_starNet3Band); + m_config->Write(m_name + KEY_STARNET_CALLSIGN3, m_starNet3Callsign); + m_config->Write(m_name + KEY_STARNET_LOGOFF3, m_starNet3Logoff); + m_config->Write(m_name + KEY_STARNET_INFO3, m_starNet3Info); + m_config->Write(m_name + KEY_STARNET_PERMANENT3, m_starNet3Permanent); + m_config->Write(m_name + KEY_STARNET_USER_TIMEOUT3, long(m_starNet3UserTimeout)); + m_config->Write(m_name + KEY_STARNET_GROUP_TIMEOUT3, long(m_starNet3GroupTimeout)); + m_config->Write(m_name + KEY_STARNET_CALLSIGN_SWITCH3, long(m_starNet3CallsignSwitch)); + m_config->Write(m_name + KEY_STARNET_TXMSG_SWITCH3, long(m_starNet3TxMsgSwitch)); + m_config->Write(m_name + KEY_STARNET_REFLECTOR3, m_starNet3Reflector); + m_config->Write(m_name + KEY_STARNET_BAND4, m_starNet4Band); + m_config->Write(m_name + KEY_STARNET_CALLSIGN4, m_starNet4Callsign); + m_config->Write(m_name + KEY_STARNET_LOGOFF4, m_starNet4Logoff); + m_config->Write(m_name + KEY_STARNET_INFO4, m_starNet4Info); + m_config->Write(m_name + KEY_STARNET_PERMANENT4, m_starNet4Permanent); + m_config->Write(m_name + KEY_STARNET_USER_TIMEOUT4, long(m_starNet4UserTimeout)); + m_config->Write(m_name + KEY_STARNET_GROUP_TIMEOUT4, long(m_starNet4GroupTimeout)); + m_config->Write(m_name + KEY_STARNET_CALLSIGN_SWITCH4, long(m_starNet4CallsignSwitch)); + m_config->Write(m_name + KEY_STARNET_TXMSG_SWITCH4, long(m_starNet4TxMsgSwitch)); + m_config->Write(m_name + KEY_STARNET_REFLECTOR4, m_starNet4Reflector); + m_config->Write(m_name + KEY_STARNET_BAND5, m_starNet5Band); + m_config->Write(m_name + KEY_STARNET_CALLSIGN5, m_starNet5Callsign); + m_config->Write(m_name + KEY_STARNET_LOGOFF5, m_starNet5Logoff); + m_config->Write(m_name + KEY_STARNET_INFO5, m_starNet5Info); + m_config->Write(m_name + KEY_STARNET_PERMANENT5, m_starNet5Permanent); + m_config->Write(m_name + KEY_STARNET_USER_TIMEOUT5, long(m_starNet5UserTimeout)); + m_config->Write(m_name + KEY_STARNET_GROUP_TIMEOUT5, long(m_starNet5GroupTimeout)); + m_config->Write(m_name + KEY_STARNET_CALLSIGN_SWITCH5, long(m_starNet5CallsignSwitch)); + m_config->Write(m_name + KEY_STARNET_TXMSG_SWITCH5, long(m_starNet5TxMsgSwitch)); + m_config->Write(m_name + KEY_STARNET_REFLECTOR5, m_starNet5Reflector); + m_config->Write(m_name + KEY_REMOTE_ENABLED, m_remoteEnabled); + m_config->Write(m_name + KEY_REMOTE_PASSWORD, m_remotePassword); + m_config->Write(m_name + KEY_REMOTE_PORT, long(m_remotePort)); + m_config->Write(m_name + KEY_LANGUAGE, long(m_language)); + m_config->Write(m_name + KEY_INFO_ENABLED, m_infoEnabled); + m_config->Write(m_name + KEY_ECHO_ENABLED, m_echoEnabled); + m_config->Write(m_name + KEY_LOG_ENABLED, m_logEnabled); + m_config->Write(m_name + KEY_DRATS_ENABLED, m_dratsEnabled); + m_config->Write(m_name + KEY_DTMF_ENABLED, m_dtmfEnabled); + m_config->Write(m_name + KEY_WINDOW_X, long(m_x)); + m_config->Write(m_name + KEY_WINDOW_Y, long(m_y)); + m_config->Flush(); +#endif + + wxTextFile file(m_fileName.GetFullPath()); + + bool exists = file.Exists(); + if (exists) { + bool ret = file.Open(); + if (!ret) { + wxLogError(wxT("Cannot open the config file - %s"), m_fileName.GetFullPath().c_str()); + return false; + } + + // Remove the existing file entries + file.Clear(); + } else { + bool ret = file.Create(); + if (!ret) { + wxLogError(wxT("Cannot create the config file - %s"), m_fileName.GetFullPath().c_str()); + return false; + } + } + + wxString buffer; + buffer.Printf(wxT("%s=%d"), KEY_GATEWAY_TYPE.c_str(), int(m_type)); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_GATEWAY_CALLSIGN.c_str(), m_callsign.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_GATEWAY_ADDRESS.c_str(), m_address.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_ICOM_ADDRESS.c_str(), m_icomAddress.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%u"), KEY_ICOM_PORT.c_str(), m_icomPort); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_HB_ADDRESS.c_str(), m_hbAddress.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%u"), KEY_HB_PORT.c_str(), m_hbPort); file.AddLine(buffer); + buffer.Printf(wxT("%s=%.6lf"), KEY_LATITUDE.c_str(), m_latitude); file.AddLine(buffer); + buffer.Printf(wxT("%s=%.6lf"), KEY_LONGITUDE.c_str(), m_longitude); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_DESCRIPTION1.c_str(), m_description1.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_DESCRIPTION2.c_str(), m_description2.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_URL.c_str(), m_url.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_REPEATER_CALL1.c_str(), m_repeater1Callsign.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_REPEATER_BAND1.c_str(), m_repeater1Band.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%d"), KEY_REPEATER_TYPE1.c_str(), int(m_repeater1Type)); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_REPEATER_ADDRESS1.c_str(), m_repeater1Address.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%u"), KEY_REPEATER_PORT1.c_str(), m_repeater1Port); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_REFLECTOR1.c_str(), m_repeater1Reflector.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%d"), KEY_ATSTARTUP1.c_str(), m_repeater1AtStartup ? 1 : 0); file.AddLine(buffer); + buffer.Printf(wxT("%s=%d"), KEY_RECONNECT1.c_str(), int(m_repeater1Reconnect)); file.AddLine(buffer); + buffer.Printf(wxT("%s=%.5lf"), KEY_FREQUENCY1.c_str(), m_repeater1Frequency); file.AddLine(buffer); + buffer.Printf(wxT("%s=%.4lf"), KEY_OFFSET1.c_str(), m_repeater1Offset); file.AddLine(buffer); + buffer.Printf(wxT("%s=%.3lf"), KEY_RANGE1.c_str(), m_repeater1Range); file.AddLine(buffer); + buffer.Printf(wxT("%s=%.6lf"), KEY_LATITUDE1.c_str(), m_repeater1Latitude); file.AddLine(buffer); + buffer.Printf(wxT("%s=%.6lf"), KEY_LONGITUDE1.c_str(), m_repeater1Longitude); file.AddLine(buffer); + buffer.Printf(wxT("%s=%.3lf"), KEY_AGL1.c_str(), m_repeater1Agl); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_DESCRIPTION11.c_str(), m_repeater1Description1.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_DESCRIPTION12.c_str(), m_repeater1Description2.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_URL1.c_str(), m_repeater1URL.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%u"), KEY_BAND11.c_str(), m_repeater1Band1); file.AddLine(buffer); + buffer.Printf(wxT("%s=%u"), KEY_BAND12.c_str(), m_repeater1Band2); file.AddLine(buffer); + buffer.Printf(wxT("%s=%u"), KEY_BAND13.c_str(), m_repeater1Band3); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_REPEATER_CALL2.c_str(), m_repeater2Callsign.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_REPEATER_BAND2.c_str(), m_repeater2Band.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%d"), KEY_REPEATER_TYPE2.c_str(), int(m_repeater2Type)); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_REPEATER_ADDRESS2.c_str(), m_repeater2Address.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%u"), KEY_REPEATER_PORT2.c_str(), m_repeater2Port); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_REFLECTOR2.c_str(), m_repeater2Reflector.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%d"), KEY_ATSTARTUP2.c_str(), m_repeater2AtStartup ? 1 : 0); file.AddLine(buffer); + buffer.Printf(wxT("%s=%d"), KEY_RECONNECT2.c_str(), int(m_repeater2Reconnect)); file.AddLine(buffer); + buffer.Printf(wxT("%s=%.5lf"), KEY_FREQUENCY2.c_str(), m_repeater2Frequency); file.AddLine(buffer); + buffer.Printf(wxT("%s=%.4lf"), KEY_OFFSET2.c_str(), m_repeater2Offset); file.AddLine(buffer); + buffer.Printf(wxT("%s=%.3lf"), KEY_RANGE2.c_str(), m_repeater2Range); file.AddLine(buffer); + buffer.Printf(wxT("%s=%.6lf"), KEY_LATITUDE2.c_str(), m_repeater2Latitude); file.AddLine(buffer); + buffer.Printf(wxT("%s=%.6lf"), KEY_LONGITUDE2.c_str(), m_repeater2Longitude); file.AddLine(buffer); + buffer.Printf(wxT("%s=%.3lf"), KEY_AGL2.c_str(), m_repeater2Agl); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_DESCRIPTION21.c_str(), m_repeater2Description1.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_DESCRIPTION22.c_str(), m_repeater2Description2.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_URL2.c_str(), m_repeater2URL.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%u"), KEY_BAND21.c_str(), m_repeater2Band1); file.AddLine(buffer); + buffer.Printf(wxT("%s=%u"), KEY_BAND22.c_str(), m_repeater2Band2); file.AddLine(buffer); + buffer.Printf(wxT("%s=%u"), KEY_BAND23.c_str(), m_repeater2Band3); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_REPEATER_CALL3.c_str(), m_repeater3Callsign.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_REPEATER_BAND3.c_str(), m_repeater3Band.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%d"), KEY_REPEATER_TYPE3.c_str(), int(m_repeater3Type)); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_REPEATER_ADDRESS3.c_str(), m_repeater3Address.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%u"), KEY_REPEATER_PORT3.c_str(), m_repeater3Port); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_REFLECTOR3.c_str(), m_repeater3Reflector.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%d"), KEY_ATSTARTUP3.c_str(), m_repeater3AtStartup ? 1 : 0); file.AddLine(buffer); + buffer.Printf(wxT("%s=%d"), KEY_RECONNECT3.c_str(), int(m_repeater3Reconnect)); file.AddLine(buffer); + buffer.Printf(wxT("%s=%.5lf"), KEY_FREQUENCY3.c_str(), m_repeater3Frequency); file.AddLine(buffer); + buffer.Printf(wxT("%s=%.4lf"), KEY_OFFSET3.c_str(), m_repeater3Offset); file.AddLine(buffer); + buffer.Printf(wxT("%s=%.3lf"), KEY_RANGE3.c_str(), m_repeater3Range); file.AddLine(buffer); + buffer.Printf(wxT("%s=%.6lf"), KEY_LATITUDE3.c_str(), m_repeater3Latitude); file.AddLine(buffer); + buffer.Printf(wxT("%s=%.6lf"), KEY_LONGITUDE3.c_str(), m_repeater3Longitude); file.AddLine(buffer); + buffer.Printf(wxT("%s=%.3lf"), KEY_AGL3.c_str(), m_repeater3Agl); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_DESCRIPTION31.c_str(), m_repeater3Description1.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_DESCRIPTION32.c_str(), m_repeater3Description2.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_URL3.c_str(), m_repeater3URL.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%u"), KEY_BAND31.c_str(), m_repeater3Band1); file.AddLine(buffer); + buffer.Printf(wxT("%s=%u"), KEY_BAND32.c_str(), m_repeater3Band2); file.AddLine(buffer); + buffer.Printf(wxT("%s=%u"), KEY_BAND33.c_str(), m_repeater3Band3); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_REPEATER_CALL4.c_str(), m_repeater4Callsign.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_REPEATER_BAND4.c_str(), m_repeater4Band.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%d"), KEY_REPEATER_TYPE4.c_str(), int(m_repeater4Type)); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_REPEATER_ADDRESS4.c_str(), m_repeater4Address.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%u"), KEY_REPEATER_PORT4.c_str(), m_repeater4Port); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_REFLECTOR4.c_str(), m_repeater4Reflector.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%d"), KEY_ATSTARTUP4.c_str(), m_repeater4AtStartup ? 1 : 0); file.AddLine(buffer); + buffer.Printf(wxT("%s=%d"), KEY_RECONNECT4.c_str(), int(m_repeater4Reconnect)); file.AddLine(buffer); + buffer.Printf(wxT("%s=%.5lf"), KEY_FREQUENCY4.c_str(), m_repeater4Frequency); file.AddLine(buffer); + buffer.Printf(wxT("%s=%.4lf"), KEY_OFFSET4.c_str(), m_repeater4Offset); file.AddLine(buffer); + buffer.Printf(wxT("%s=%.3lf"), KEY_RANGE4.c_str(), m_repeater4Range); file.AddLine(buffer); + buffer.Printf(wxT("%s=%.6lf"), KEY_LATITUDE4.c_str(), m_repeater4Latitude); file.AddLine(buffer); + buffer.Printf(wxT("%s=%.6lf"), KEY_LONGITUDE4.c_str(), m_repeater4Longitude); file.AddLine(buffer); + buffer.Printf(wxT("%s=%.3lf"), KEY_AGL4.c_str(), m_repeater4Agl); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_DESCRIPTION41.c_str(), m_repeater4Description1.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_DESCRIPTION42.c_str(), m_repeater4Description2.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_URL4.c_str(), m_repeater4URL.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%u"), KEY_BAND41.c_str(), m_repeater4Band1); file.AddLine(buffer); + buffer.Printf(wxT("%s=%u"), KEY_BAND42.c_str(), m_repeater4Band2); file.AddLine(buffer); + buffer.Printf(wxT("%s=%u"), KEY_BAND43.c_str(), m_repeater4Band3); file.AddLine(buffer); + buffer.Printf(wxT("%s=%d"), KEY_IRCDDB_ENABLED.c_str(), m_ircddbEnabled ? 1 : 0); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_IRCDDB_HOSTNAME.c_str(), m_ircddbHostname.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_IRCDDB_USERNAME.c_str(), m_ircddbUsername.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_IRCDDB_PASSWORD.c_str(), m_ircddbPassword.c_str()); file.AddLine(buffer); + buffer.Printf("%s=%d", KEY_IRCDDB_ENABLED2.c_str(), m_ircddbEnabled2 ? 1 : 0); file.AddLine(buffer); + buffer.Printf("%s=%s", KEY_IRCDDB_HOSTNAME2.c_str(), m_ircddbHostname2.c_str()); file.AddLine(buffer); + buffer.Printf("%s=%s", KEY_IRCDDB_USERNAME2.c_str(), m_ircddbUsername2.c_str()); file.AddLine(buffer); + buffer.Printf("%s=%s", KEY_IRCDDB_PASSWORD2.c_str(), m_ircddbPassword2.c_str()); file.AddLine(buffer); + buffer.Printf("%s=%d", KEY_IRCDDB_ENABLED3.c_str(), m_ircddbEnabled3 ? 1 : 0); file.AddLine(buffer); + buffer.Printf("%s=%s", KEY_IRCDDB_HOSTNAME3.c_str(), m_ircddbHostname3.c_str()); file.AddLine(buffer); + buffer.Printf("%s=%s", KEY_IRCDDB_USERNAME3.c_str(), m_ircddbUsername3.c_str()); file.AddLine(buffer); + buffer.Printf("%s=%s", KEY_IRCDDB_PASSWORD3.c_str(), m_ircddbPassword3.c_str()); file.AddLine(buffer); + buffer.Printf("%s=%d", KEY_IRCDDB_ENABLED4.c_str(), m_ircddbEnabled4 ? 1 : 0); file.AddLine(buffer); + buffer.Printf("%s=%s", KEY_IRCDDB_HOSTNAME4.c_str(), m_ircddbHostname4.c_str()); file.AddLine(buffer); + buffer.Printf("%s=%s", KEY_IRCDDB_USERNAME4.c_str(), m_ircddbUsername4.c_str()); file.AddLine(buffer); + buffer.Printf("%s=%s", KEY_IRCDDB_PASSWORD4.c_str(), m_ircddbPassword4.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%d"), KEY_APRS_ENABLED.c_str(), m_aprsEnabled ? 1 : 0); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_APRS_HOSTNAME.c_str(), m_aprsHostname.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%u"), KEY_APRS_PORT.c_str(), m_aprsPort); file.AddLine(buffer); + buffer.Printf(wxT("%s=%d"), KEY_DEXTRA_ENABLED.c_str(), m_dextraEnabled ? 1 : 0); file.AddLine(buffer); + buffer.Printf(wxT("%s=%u"), KEY_DEXTRA_MAXDONGLES.c_str(), m_dextraMaxDongles); file.AddLine(buffer); + buffer.Printf(wxT("%s=%d"), KEY_DPLUS_ENABLED.c_str(), m_dplusEnabled ? 1 : 0); file.AddLine(buffer); + buffer.Printf(wxT("%s=%u"), KEY_DPLUS_MAXDONGLES.c_str(), m_dplusMaxDongles); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_DPLUS_LOGIN.c_str(), m_dplusLogin.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%d"), KEY_DCS_ENABLED.c_str(), m_dcsEnabled ? 1 : 0); file.AddLine(buffer); + buffer.Printf(wxT("%s=%d"), KEY_CCS_ENABLED.c_str(), m_ccsEnabled ? 1 : 0); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_CCS_HOST.c_str(), m_ccsHost.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%d"), KEY_XLX_ENABLED.c_str(), m_xlxEnabled ? 1 : 0); file.AddLine(buffer); + buffer.Printf(wxT("%s=%d"), KEY_XLX_OVERRIDE_LOCAL.c_str(), m_xlxOverrideLocal ? 1 : 0); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_XLX_HOSTS_FILE_URL.c_str(), m_xlxHostsFileUrl.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_BAND1.c_str(), m_starNet1Band.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_CALLSIGN1.c_str(), m_starNet1Callsign.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_LOGOFF1.c_str(), m_starNet1Logoff.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_INFO1.c_str(), m_starNet1Info.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_PERMANENT1.c_str(), m_starNet1Permanent.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%u"), KEY_STARNET_USER_TIMEOUT1.c_str(), m_starNet1UserTimeout); file.AddLine(buffer); + buffer.Printf(wxT("%s=%u"), KEY_STARNET_GROUP_TIMEOUT1.c_str(), m_starNet1GroupTimeout); file.AddLine(buffer); + buffer.Printf(wxT("%s=%d"), KEY_STARNET_CALLSIGN_SWITCH1.c_str(), int(m_starNet1CallsignSwitch)); file.AddLine(buffer); + buffer.Printf(wxT("%s=%d"), KEY_STARNET_TXMSG_SWITCH1.c_str(), m_starNet1TxMsgSwitch ? 1 : 0); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_REFLECTOR1.c_str(), m_starNet1Reflector.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_BAND2.c_str(), m_starNet2Band.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_CALLSIGN2.c_str(), m_starNet2Callsign.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_LOGOFF2.c_str(), m_starNet2Logoff.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_INFO2.c_str(), m_starNet2Info.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_PERMANENT2.c_str(), m_starNet2Permanent.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%u"), KEY_STARNET_USER_TIMEOUT2.c_str(), m_starNet2UserTimeout); file.AddLine(buffer); + buffer.Printf(wxT("%s=%u"), KEY_STARNET_GROUP_TIMEOUT2.c_str(), m_starNet2GroupTimeout); file.AddLine(buffer); + buffer.Printf(wxT("%s=%d"), KEY_STARNET_CALLSIGN_SWITCH2.c_str(), int(m_starNet2CallsignSwitch)); file.AddLine(buffer); + buffer.Printf(wxT("%s=%d"), KEY_STARNET_TXMSG_SWITCH2.c_str(), m_starNet2TxMsgSwitch ? 1 : 0); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_REFLECTOR2.c_str(), m_starNet2Reflector.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_BAND3.c_str(), m_starNet3Band.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_CALLSIGN3.c_str(), m_starNet3Callsign.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_LOGOFF3.c_str(), m_starNet3Logoff.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_INFO3.c_str(), m_starNet3Info.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_PERMANENT3.c_str(), m_starNet3Permanent.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%u"), KEY_STARNET_USER_TIMEOUT3.c_str(), m_starNet3UserTimeout); file.AddLine(buffer); + buffer.Printf(wxT("%s=%u"), KEY_STARNET_GROUP_TIMEOUT3.c_str(), m_starNet3GroupTimeout); file.AddLine(buffer); + buffer.Printf(wxT("%s=%d"), KEY_STARNET_CALLSIGN_SWITCH3.c_str(), int(m_starNet3CallsignSwitch)); file.AddLine(buffer); + buffer.Printf(wxT("%s=%d"), KEY_STARNET_TXMSG_SWITCH3.c_str(), m_starNet3TxMsgSwitch ? 1 : 0); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_REFLECTOR3.c_str(), m_starNet3Reflector.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_BAND4.c_str(), m_starNet4Band.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_CALLSIGN4.c_str(), m_starNet4Callsign.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_LOGOFF4.c_str(), m_starNet4Logoff.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_INFO4.c_str(), m_starNet4Info.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_PERMANENT4.c_str(), m_starNet4Permanent.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%u"), KEY_STARNET_USER_TIMEOUT4.c_str(), m_starNet4UserTimeout); file.AddLine(buffer); + buffer.Printf(wxT("%s=%u"), KEY_STARNET_GROUP_TIMEOUT4.c_str(), m_starNet4GroupTimeout); file.AddLine(buffer); + buffer.Printf(wxT("%s=%d"), KEY_STARNET_CALLSIGN_SWITCH4.c_str(), int(m_starNet4CallsignSwitch)); file.AddLine(buffer); + buffer.Printf(wxT("%s=%d"), KEY_STARNET_TXMSG_SWITCH4.c_str(), m_starNet4TxMsgSwitch ? 1 : 0); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_REFLECTOR4.c_str(), m_starNet4Reflector.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_BAND5.c_str(), m_starNet5Band.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_CALLSIGN5.c_str(), m_starNet5Callsign.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_LOGOFF5.c_str(), m_starNet5Logoff.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_INFO5.c_str(), m_starNet5Info.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_PERMANENT5.c_str(), m_starNet5Permanent.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%u"), KEY_STARNET_USER_TIMEOUT5.c_str(), m_starNet5UserTimeout); file.AddLine(buffer); + buffer.Printf(wxT("%s=%u"), KEY_STARNET_GROUP_TIMEOUT5.c_str(), m_starNet5GroupTimeout); file.AddLine(buffer); + buffer.Printf(wxT("%s=%d"), KEY_STARNET_CALLSIGN_SWITCH5.c_str(), int(m_starNet5CallsignSwitch)); file.AddLine(buffer); + buffer.Printf(wxT("%s=%d"), KEY_STARNET_TXMSG_SWITCH5.c_str(), m_starNet5TxMsgSwitch ? 1 : 0); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_REFLECTOR5.c_str(), m_starNet5Reflector.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%d"), KEY_REMOTE_ENABLED.c_str(), m_remoteEnabled ? 1 : 0); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_REMOTE_PASSWORD.c_str(), m_remotePassword.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%u"), KEY_REMOTE_PORT.c_str(), m_remotePort); file.AddLine(buffer); + buffer.Printf(wxT("%s=%d"), KEY_LANGUAGE.c_str(), int(m_language)); file.AddLine(buffer); + buffer.Printf(wxT("%s=%d"), KEY_INFO_ENABLED.c_str(), m_infoEnabled ? 1 : 0); file.AddLine(buffer); + buffer.Printf(wxT("%s=%d"), KEY_ECHO_ENABLED.c_str(), m_echoEnabled ? 1 : 0); file.AddLine(buffer); + buffer.Printf(wxT("%s=%d"), KEY_LOG_ENABLED.c_str(), m_logEnabled ? 1 : 0); file.AddLine(buffer); + buffer.Printf(wxT("%s=%d"), KEY_DRATS_ENABLED.c_str(), m_dratsEnabled ? 1 : 0); file.AddLine(buffer); + buffer.Printf(wxT("%s=%d"), KEY_DTMF_ENABLED.c_str(), m_dtmfEnabled ? 1 : 0); file.AddLine(buffer); + buffer.Printf(wxT("%s=%d"), KEY_WINDOW_X.c_str(), m_x); file.AddLine(buffer); + buffer.Printf(wxT("%s=%d"), KEY_WINDOW_Y.c_str(), m_y); file.AddLine(buffer); + + bool ret = file.Write(); + if (!ret) { + file.Close(); + wxLogError(wxT("Cannot write the config file - %s"), m_fileName.GetFullPath().c_str()); + return false; + } + + file.Close(); + + return true; +} diff --git a/Common/IRCDDBGatewayConfig.h b/Common/IRCDDBGatewayConfig.h new file mode 100644 index 0000000..f1c8ca2 --- /dev/null +++ b/Common/IRCDDBGatewayConfig.h @@ -0,0 +1,311 @@ +/* + * Copyright (C) 2010-2014 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef IRCDDBGatewayConfig_H +#define IRCDDBGatewayConfig_H + +#include "Defs.h" + +#include +#include +#include + +class CIRCDDBGatewayConfig { +public: +#if defined(__WINDOWS__) + CIRCDDBGatewayConfig(wxConfigBase* config, const wxString& dir, const wxString& configName, const wxString& name); +#else + CIRCDDBGatewayConfig(const wxString& dir, const wxString& configName, const wxString& name); +#endif + ~CIRCDDBGatewayConfig(); + + void getGateway(GATEWAY_TYPE& type, wxString& callsign, wxString& address, wxString& icomAddress, unsigned int& icomPort, wxString& hbAddress, unsigned int& hbPort, double& latitude, double& longitude, wxString& description1, wxString& description2, wxString& url) const; + void setGateway(GATEWAY_TYPE type, const wxString& callsign, const wxString& address, const wxString& icomAddress, unsigned int icomPort, const wxString& hbAddress, unsigned int hbPort, double latitude, double longitude, const wxString& description1, const wxString& description2, const wxString& url); + + void getRepeater1(wxString& callsign, wxString& band, HW_TYPE& type, wxString& address, unsigned int& port, unsigned char& band1, unsigned char& band2, unsigned char& band3, wxString& reflector, bool& atStartup, RECONNECT& reconnect, double& frequency, double& offset, double& range, double& latitude, double& longitude, double& agl, wxString& description1, wxString& description2, wxString& url) const; + void setRepeater1(const wxString& band, HW_TYPE type, const wxString& address, unsigned int port, unsigned char band1, unsigned char band2, unsigned char band3, const wxString& reflector, bool atStartup, RECONNECT reconnect, double frequency, double offset, double range, double latitude, double longitude, double agl, const wxString& description1, const wxString& description2, const wxString& url); + + void getRepeater2(wxString& callsign, wxString& band, HW_TYPE& type, wxString& address, unsigned int& port, unsigned char& band1, unsigned char& band2, unsigned char& band3, wxString& reflector, bool& atStartup, RECONNECT& reconnect, double& frequency, double& offset, double& range, double& latitude, double& longitude, double& agl, wxString& description1, wxString& description2, wxString& url) const; + void setRepeater2(const wxString& band, HW_TYPE type, const wxString& address, unsigned int port, unsigned char band1, unsigned char band2, unsigned char band3, const wxString& reflector, bool atStartup, RECONNECT reconnect, double frequency, double offset, double range, double latitude, double longitude, double agl, const wxString& description1, const wxString& description2, const wxString& url); + + void getRepeater3(wxString& callsign, wxString& band, HW_TYPE& type, wxString& address, unsigned int& port, unsigned char& band1, unsigned char& band2, unsigned char& band3, wxString& reflector, bool& atStartup, RECONNECT& reconnect, double& frequency, double& offset, double& range, double& latitude, double& longitude, double& agl, wxString& description1, wxString& description2, wxString& url) const; + void setRepeater3(const wxString& band, HW_TYPE type, const wxString& address, unsigned int port, unsigned char band1, unsigned char band2, unsigned char band3, const wxString& reflector, bool atStartup, RECONNECT reconnect, double frequency, double offset, double range, double latitude, double longitude, double agl, const wxString& description1, const wxString& description2, const wxString& url); + + void getRepeater4(wxString& callsign, wxString& band, HW_TYPE& type, wxString& address, unsigned int& port, unsigned char& band1, unsigned char& band2, unsigned char& band3, wxString& reflector, bool& atStartup, RECONNECT& reconnect, double& frequency, double& offset, double& range, double& latitude, double& longitude, double& agl, wxString& description1, wxString& description2, wxString& url) const; + void setRepeater4(const wxString& band, HW_TYPE type, const wxString& address, unsigned int port, unsigned char band1, unsigned char band2, unsigned char band3, const wxString& reflector, bool atStartup, RECONNECT reconnect, double frequency, double offset, double range, double latitude, double longitude, double agl, const wxString& description1, const wxString& description2, const wxString& url); + + void getIrcDDB(bool& enabled, wxString& hostname, wxString& username, wxString& password) const; + void getIrcDDB2(bool& enabled, wxString& hostname, wxString& username, wxString& password) const; + void getIrcDDB3(bool& enabled, wxString& hostname, wxString& username, wxString& password) const; + void getIrcDDB4(bool& enabled, wxString& hostname, wxString& username, wxString& password) const; + + void setIrcDDB(bool enabled, const wxString& hostname, const wxString& username, const wxString& password); + void setIrcDDB2(bool enabled, const wxString& hostname, const wxString& username, const wxString& password); + void setIrcDDB3(bool enabled, const wxString& hostname, const wxString& username, const wxString& password); + void setIrcDDB4(bool enabled, const wxString& hostname, const wxString& username, const wxString& password); + + void getDPRS(bool& enabled, wxString& hostname, unsigned int& port) const; + void setDPRS(bool enabled, const wxString& hostname, unsigned int port); + + void getDExtra(bool& enabled, unsigned int& maxDongles) const; + void setDExtra(bool enabled, unsigned int maxDongles); + + void getDPlus(bool& enabled, unsigned int& maxDongles, wxString& login) const; + void setDPlus(bool enabled, unsigned int maxDongles, const wxString& login); + + void getDCS(bool& dcsEnabled, bool& ccsEnabled, wxString& ccsHost) const; + void setDCS(bool dcsEnabled, bool ccsEnabled, const wxString& ccsHost); + + void getXLX(bool& xlxEnabled, bool& xlxOverrideLocal, wxString& xlxHostsFileUrl); + void setXLX(bool xlxEnabled, bool xlxOverrideLocal, wxString xlxHostsFileUrl); + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + void getStarNet1(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch, wxString& reflector) const; + void setStarNet1(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch, const wxString& reflector); + + void getStarNet2(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch, wxString& reflector) const; + void setStarNet2(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch, const wxString& reflector); + + void getStarNet3(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch, wxString& reflector) const; + void setStarNet3(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch, const wxString& reflector); + + void getStarNet4(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch, wxString& reflector) const; + void setStarNet4(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch, const wxString& reflector); + + void getStarNet5(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch, wxString& reflector) const; + void setStarNet5(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch, const wxString& reflector); +#else + void getStarNet1(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch) const; + void setStarNet1(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch); + + void getStarNet2(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch) const; + void setStarNet2(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch); + + void getStarNet3(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch) const; + void setStarNet3(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch); + + void getStarNet4(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch) const; + void setStarNet4(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch); + + void getStarNet5(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch) const; + void setStarNet5(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch); +#endif + + void getRemote(bool& enabled, wxString& password, unsigned int& port) const; + void setRemote(bool enabled, const wxString& password, unsigned int port); + + void getMiscellaneous(TEXT_LANG& language, bool& infoEnabled, bool& echoEnabled, bool& logEnabled, bool& dratsEnabled, bool& dtmfEnabled) const; + void setMiscellaneous(TEXT_LANG language, bool infoEnabled, bool echoEnabled, bool logEnabled, bool dratsEnabled, bool dtmfEnabled); + + void getPosition(int& x, int& y) const; + void setPosition(int x, int y); + + bool write(); + +private: +#if defined(__WINDOWS__) + wxConfigBase* m_config; + wxString m_name; +#endif + wxFileName m_fileName; + GATEWAY_TYPE m_type; + wxString m_callsign; + wxString m_address; + wxString m_icomAddress; + unsigned int m_icomPort; + wxString m_hbAddress; + unsigned int m_hbPort; + double m_latitude; + double m_longitude; + wxString m_description1; + wxString m_description2; + wxString m_url; + wxString m_repeater1Callsign; + wxString m_repeater1Band; + HW_TYPE m_repeater1Type; + wxString m_repeater1Address; + unsigned int m_repeater1Port; + wxString m_repeater1Reflector; + bool m_repeater1AtStartup; + RECONNECT m_repeater1Reconnect; + double m_repeater1Frequency; + double m_repeater1Offset; + double m_repeater1Range; + double m_repeater1Latitude; + double m_repeater1Longitude; + double m_repeater1Agl; + wxString m_repeater1Description1; + wxString m_repeater1Description2; + wxString m_repeater1URL; + unsigned char m_repeater1Band1; + unsigned char m_repeater1Band2; + unsigned char m_repeater1Band3; + wxString m_repeater2Callsign; + wxString m_repeater2Band; + HW_TYPE m_repeater2Type; + wxString m_repeater2Address; + unsigned int m_repeater2Port; + wxString m_repeater2Reflector; + bool m_repeater2AtStartup; + RECONNECT m_repeater2Reconnect; + double m_repeater2Frequency; + double m_repeater2Offset; + double m_repeater2Range; + double m_repeater2Latitude; + double m_repeater2Longitude; + double m_repeater2Agl; + wxString m_repeater2Description1; + wxString m_repeater2Description2; + wxString m_repeater2URL; + unsigned char m_repeater2Band1; + unsigned char m_repeater2Band2; + unsigned char m_repeater2Band3; + wxString m_repeater3Callsign; + wxString m_repeater3Band; + HW_TYPE m_repeater3Type; + wxString m_repeater3Address; + unsigned int m_repeater3Port; + wxString m_repeater3Reflector; + bool m_repeater3AtStartup; + RECONNECT m_repeater3Reconnect; + double m_repeater3Frequency; + double m_repeater3Offset; + double m_repeater3Range; + double m_repeater3Latitude; + double m_repeater3Longitude; + double m_repeater3Agl; + wxString m_repeater3Description1; + wxString m_repeater3Description2; + wxString m_repeater3URL; + unsigned char m_repeater3Band1; + unsigned char m_repeater3Band2; + unsigned char m_repeater3Band3; + wxString m_repeater4Callsign; + wxString m_repeater4Band; + HW_TYPE m_repeater4Type; + wxString m_repeater4Address; + unsigned int m_repeater4Port; + wxString m_repeater4Reflector; + bool m_repeater4AtStartup; + RECONNECT m_repeater4Reconnect; + double m_repeater4Frequency; + double m_repeater4Offset; + double m_repeater4Range; + double m_repeater4Latitude; + double m_repeater4Longitude; + double m_repeater4Agl; + wxString m_repeater4Description1; + wxString m_repeater4Description2; + wxString m_repeater4URL; + unsigned char m_repeater4Band1; + unsigned char m_repeater4Band2; + unsigned char m_repeater4Band3; + bool m_ircddbEnabled; + wxString m_ircddbHostname; + wxString m_ircddbUsername; + wxString m_ircddbPassword; + bool m_ircddbEnabled2; + wxString m_ircddbHostname2; + wxString m_ircddbUsername2; + wxString m_ircddbPassword2; + bool m_ircddbEnabled3; + wxString m_ircddbHostname3; + wxString m_ircddbUsername3; + wxString m_ircddbPassword3; + bool m_ircddbEnabled4; + wxString m_ircddbHostname4; + wxString m_ircddbUsername4; + wxString m_ircddbPassword4; + bool m_aprsEnabled; + wxString m_aprsHostname; + unsigned int m_aprsPort; + bool m_dextraEnabled; + unsigned int m_dextraMaxDongles; + bool m_dplusEnabled; + unsigned int m_dplusMaxDongles; + wxString m_dplusLogin; + bool m_dcsEnabled; + bool m_ccsEnabled; + wxString m_ccsHost; + bool m_xlxEnabled; + bool m_xlxOverrideLocal; + wxString m_xlxHostsFileUrl; + wxString m_starNet1Band; + wxString m_starNet1Callsign; + wxString m_starNet1Logoff; + wxString m_starNet1Info; + wxString m_starNet1Permanent; + unsigned int m_starNet1UserTimeout; + unsigned int m_starNet1GroupTimeout; + STARNET_CALLSIGN_SWITCH m_starNet1CallsignSwitch; + bool m_starNet1TxMsgSwitch; + wxString m_starNet1Reflector; + wxString m_starNet2Band; + wxString m_starNet2Callsign; + wxString m_starNet2Logoff; + wxString m_starNet2Info; + wxString m_starNet2Permanent; + unsigned int m_starNet2UserTimeout; + unsigned int m_starNet2GroupTimeout; + STARNET_CALLSIGN_SWITCH m_starNet2CallsignSwitch; + bool m_starNet2TxMsgSwitch; + wxString m_starNet2Reflector; + wxString m_starNet3Band; + wxString m_starNet3Callsign; + wxString m_starNet3Logoff; + wxString m_starNet3Info; + wxString m_starNet3Permanent; + unsigned int m_starNet3UserTimeout; + unsigned int m_starNet3GroupTimeout; + STARNET_CALLSIGN_SWITCH m_starNet3CallsignSwitch; + bool m_starNet3TxMsgSwitch; + wxString m_starNet3Reflector; + wxString m_starNet4Band; + wxString m_starNet4Callsign; + wxString m_starNet4Logoff; + wxString m_starNet4Info; + wxString m_starNet4Permanent; + unsigned int m_starNet4UserTimeout; + unsigned int m_starNet4GroupTimeout; + STARNET_CALLSIGN_SWITCH m_starNet4CallsignSwitch; + bool m_starNet4TxMsgSwitch; + wxString m_starNet4Reflector; + wxString m_starNet5Band; + wxString m_starNet5Callsign; + wxString m_starNet5Logoff; + wxString m_starNet5Info; + wxString m_starNet5Permanent; + unsigned int m_starNet5UserTimeout; + unsigned int m_starNet5GroupTimeout; + STARNET_CALLSIGN_SWITCH m_starNet5CallsignSwitch; + bool m_starNet5TxMsgSwitch; + wxString m_starNet5Reflector; + bool m_remoteEnabled; + wxString m_remotePassword; + unsigned int m_remotePort; + TEXT_LANG m_language; + bool m_infoEnabled; + bool m_echoEnabled; + bool m_logEnabled; + bool m_dratsEnabled; + bool m_dtmfEnabled; + int m_x; + int m_y; +}; + +#endif diff --git a/Common/IcomRepeaterProtocolHandler.cpp b/Common/IcomRepeaterProtocolHandler.cpp new file mode 100644 index 0000000..61e6417 --- /dev/null +++ b/Common/IcomRepeaterProtocolHandler.cpp @@ -0,0 +1,650 @@ +/* + * Copyright (C) 2010-2014 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "IcomRepeaterProtocolHandler.h" + +#include + +#include "CCITTChecksum.h" +#include "DStarDefines.h" +#include "Utils.h" + +// Allow space for a big DD packet +const unsigned int BUFFER_LENGTH = 2500U; + +const unsigned int QUEUE_LENGTH = 50U; + +const unsigned int LOOP_DELAY = 5UL; +const unsigned int LOOP_TICKS = 200U; + +CIcomRepeaterProtocolHandler::CIcomRepeaterProtocolHandler(const wxString& address, unsigned int port, const wxString& icomAddress, unsigned int icomPort) : +wxThread(wxTHREAD_JOINABLE), +m_socket(address, port), +m_icomAddress(), +m_icomPort(icomPort), +m_over1(false), +m_seqNo(0U), +m_tries(0U), +m_ackQueue(NULL), +m_killed(false), +m_type(RT_NONE), +m_buffer(NULL), +m_rptrQueue(QUEUE_LENGTH), +m_gwyQueue(QUEUE_LENGTH), +m_retryTimer(LOOP_TICKS, 0U, 200U) // 200ms +{ + wxASSERT(!icomAddress.IsEmpty()); + wxASSERT(!address.IsEmpty()); + wxASSERT(icomPort > 0U); + wxASSERT(port > 0U); + + m_icomAddress.s_addr = ::inet_addr(icomAddress.mb_str()); + + m_buffer = new unsigned char[BUFFER_LENGTH]; + + wxDateTime now = wxDateTime::UNow(); + ::srand(now.GetMillisecond()); +} + +CIcomRepeaterProtocolHandler::~CIcomRepeaterProtocolHandler() +{ + while (!m_gwyQueue.isEmpty()) { + CDataQueue* dq = m_gwyQueue.getData(); + free(dq); + } + + while (!m_rptrQueue.isEmpty()) { + CDataQueue* dq = m_rptrQueue.getData(); + free(dq); + } + + delete[] m_buffer; +} + +void CIcomRepeaterProtocolHandler::setCount(unsigned int count) +{ + m_over1 = count > 1U; +} + +bool CIcomRepeaterProtocolHandler::open() +{ + bool ret = m_socket.open(); + if (!ret) + return false; + + unsigned char buffer[10U]; + + buffer[0U] = 'I'; + buffer[1U] = 'N'; + buffer[2U] = 'I'; + buffer[3U] = 'T'; + buffer[4U] = 0x00; + buffer[5U] = 0x00; + buffer[6U] = 0x73; + buffer[7U] = 0x00; + buffer[8U] = 0x00; + buffer[9U] = 0x00; + + ret = m_socket.write(buffer, 10U, m_icomAddress, m_icomPort); + if (!ret) { + m_socket.close(); + return false; + } + + // Wait for a reply from the RP2C + for (unsigned int i = 0U; i < 10U; i++) { + in_addr address; + unsigned int port; + int length = m_socket.read(m_buffer, BUFFER_LENGTH, address, port); + + if (length == 10 && m_buffer[0U] == 'I' && m_buffer[1U] == 'N' && m_buffer[2U] == 'I' && m_buffer[3U] == 'T' && m_buffer[6U] == 0x72 && m_buffer[7U] == 0x00) { + m_seqNo = m_buffer[4U] * 256U + m_buffer[5U] + 1U; + wxLogMessage(wxT("Initial sequence number from the RP2C is %u"), m_seqNo); + + // Start the thread + Create(); + Run(); + + return true; + } + + ::wxSleep(1); + } + + m_socket.close(); + + wxLogError(wxT("No reply from the RP2C for 10 seconds, aborting")); + + return false; +} + +void* CIcomRepeaterProtocolHandler::Entry() +{ + wxLogMessage(wxT("Starting the Icom Controller thread")); + + try { + while (!m_killed) { + sendGwyPackets(); + + Sleep(LOOP_DELAY); + + readIcomPackets(); + + m_retryTimer.clock(); + } + } + catch (std::exception& e) { + wxString message(e.what(), wxConvLocal); + wxLogError(wxT("Exception raised in the Icom Controller thread - \"%s\""), message.c_str()); + } + catch (...) { + wxLogError(wxT("Unknown exception raised in the Icom Controller thread")); + } + + wxLogMessage(wxT("Stopping the Icom Controller thread")); + + m_socket.close(); + + return NULL; +} + +bool CIcomRepeaterProtocolHandler::writeHeader(CHeaderData& header) +{ + CDataQueue* dq = new CDataQueue(new CHeaderData(header)); + + m_gwyQueue.addData(dq); + + return true; +} + +bool CIcomRepeaterProtocolHandler::writeAMBE(CAMBEData& data) +{ + CDataQueue* dq = new CDataQueue(new CAMBEData(data)); + + m_gwyQueue.addData(dq); + + return true; +} + +bool CIcomRepeaterProtocolHandler::writeDD(CDDData& data) +{ + CDataQueue* dq = new CDataQueue(new CDDData(data)); + + m_gwyQueue.addData(dq); + + return true; +} + +bool CIcomRepeaterProtocolHandler::writeText(CTextData&) +{ + return true; +} + +bool CIcomRepeaterProtocolHandler::writeStatus(CStatusData&) +{ + return true; +} + +void CIcomRepeaterProtocolHandler::readIcomPackets() +{ + for (;;) { + // No more data? + in_addr address; + unsigned int port; + int length = m_socket.read(m_buffer, BUFFER_LENGTH, address, port); + if (length <= 0) + return; + + if (address.s_addr != m_icomAddress.s_addr || port != m_icomPort) { + wxLogError(wxT("Incoming Icom data from an unknown source")); + continue; + } + + // Invalid packet type? + if (m_buffer[0] != 'D' || m_buffer[1] != 'S' || m_buffer[2] != 'T' || m_buffer[3] != 'R') { + CUtils::dump(wxT("Missing DSTR from the RP2C"), m_buffer, length); + continue; + } + + // An ack + if (length == 10 && m_buffer[6] == 0x72) { + wxUint16 seqNo = m_buffer[4] * 256U + m_buffer[5]; + + if (seqNo == m_seqNo) + m_seqNo++; + else + m_seqNo = seqNo; + + // Free the ack queue + free(m_ackQueue); + m_ackQueue = NULL; + + m_retryTimer.stop(); + m_tries = 0U; + + continue; + } + + // Send an ack for all packet types except an ack + wxUint16 seqNo = m_buffer[4] * 256U + m_buffer[5]; + sendAck(seqNo); + + // Heard data + if (m_buffer[6] == 0x73 && m_buffer[7] == 0x21) { + CHeardData* heard = new CHeardData; + bool ret = heard->setIcomRepeaterData(m_buffer, length, m_icomAddress, m_icomPort); + if (!ret) { + wxLogError(wxT("Invalid heard data from the RP2C")); + delete heard; + continue; + } + + m_rptrQueue.addData(new CDataQueue(heard)); + continue; + } + + // Poll data + if (m_buffer[6] == 0x73 && m_buffer[7] == 0x00) { + m_rptrQueue.addData(new CDataQueue); + continue; + } + + // DD Data + if (m_buffer[6] == 0x73 && m_buffer[7] == 0x11) { + CDDData* data = new CDDData; + bool ret = data->setIcomRepeaterData(m_buffer, length, m_icomAddress, m_icomPort); + if (!ret) { + wxLogError(wxT("Invalid DD data from the RP2C")); + delete data; + continue; + } + + m_rptrQueue.addData(new CDataQueue(data)); + continue; + } + + // DV data + if (m_buffer[6] == 0x73 && m_buffer[7] == 0x12 && m_buffer[10] == 0x20) { + if ((m_buffer[16] & 0x80) == 0x80) { + CHeaderData* header = new CHeaderData; + bool ret = header->setIcomRepeaterData(m_buffer, length, true, m_icomAddress, m_icomPort); + if (!ret) { + wxLogError(wxT("Invalid header data or checksum from the RP2C")); + delete header; + continue; + } + + if (m_over1) + sendMultiReply(*header); + else + sendSingleReply(*header); + + m_rptrQueue.addData(new CDataQueue(header)); + continue; + } else { + CAMBEData* data = new CAMBEData; + bool ret = data->setIcomRepeaterData(m_buffer, length, m_icomAddress, m_icomPort); + if (!ret) { + wxLogError(wxT("Invalid AMBE data from the RP2C")); + delete data; + continue; + } + + m_rptrQueue.addData(new CDataQueue(data)); + continue; + } + } + + // An unknown type + CUtils::dump(wxT("Unknown packet type from the RP2C"), m_buffer, length); + } +} + +void CIcomRepeaterProtocolHandler::sendGwyPackets() +{ + // Anything to send + if (m_gwyQueue.isEmpty() && m_ackQueue == NULL) + return; + + if (m_tries > 0U && !m_retryTimer.hasExpired()) + return; + + if (m_ackQueue == NULL) { + m_ackQueue = m_gwyQueue.getData(); + if (m_ackQueue == NULL) { + wxLogError(wxT("getData of a non-empty gateway queue is NULL")); + return; + } + } + + unsigned int length = 0U; + + switch (m_ackQueue->getType()) { + case RT_HEADER: { + CHeaderData* header = m_ackQueue->getHeader(); + header->setRptSeq(m_seqNo); + length = header->getIcomRepeaterData(m_buffer, 60U, true); + } + break; + + case RT_AMBE: { + CAMBEData* data = m_ackQueue->getAMBE(); + data->setRptSeq(m_seqNo); + length = data->getIcomRepeaterData(m_buffer, 60U); + } + break; + + case RT_DD: { + CDDData* data = m_ackQueue->getDD(); + data->setRptSeq(m_seqNo); + length = data->getIcomRepeaterData(m_buffer, BUFFER_LENGTH); + } + break; + + default: + wxLogError(wxT("Invalid type in the gateway queue")); + break; + } + + if (length > 0U) { + m_socket.write(m_buffer, length, m_icomAddress, m_icomPort); + + m_tries++; + m_retryTimer.start(); + + if (m_tries > 0U && (m_tries % 100U) == 0U) + wxLogMessage(wxT("No reply from the RP2C after %u retries"), m_tries); + } +} + +REPEATER_TYPE CIcomRepeaterProtocolHandler::read() +{ + if (m_rptrQueue.isEmpty()) { + m_type = RT_NONE; + } else { + CDataQueue* dq = m_rptrQueue.peek(); + if (dq == NULL) { + wxLogError(wxT("Peek of a non-empty repeater queue is NULL")); + m_type = RT_NONE; + } else { + m_type = dq->getType(); + } + } + + return m_type; +} + +CPollData* CIcomRepeaterProtocolHandler::readPoll() +{ + if (m_type != RT_POLL) + return NULL; + + CDataQueue* dq = m_rptrQueue.getData(); + if (dq == NULL) { + wxLogError(wxT("Missing DataQueue in readPoll")); + return NULL; + } + + if (dq->getType() != RT_POLL) { + wxLogError(wxT("Wrong DataQueue type in readPoll")); + delete dq; + return NULL; + } + + delete dq; + + CPollData* data = new CPollData; + data->setData1(wxT("icom_rp2c")); + + return data; +} + +CHeaderData* CIcomRepeaterProtocolHandler::readHeader() +{ + if (m_type != RT_HEADER) + return NULL; + + CDataQueue* dq = m_rptrQueue.getData(); + if (dq == NULL) { + wxLogError(wxT("Missing DataQueue in readHeader")); + return NULL; + } + + if (dq->getType() != RT_HEADER) { + wxLogError(wxT("Wrong DataQueue type in readHeader")); + delete dq; + return NULL; + } + + CHeaderData* header = dq->getHeader(); + + delete dq; + + return header; +} + +CAMBEData* CIcomRepeaterProtocolHandler::readAMBE() +{ + if (m_type != RT_AMBE) + return NULL; + + CDataQueue* dq = m_rptrQueue.getData(); + if (dq == NULL) { + wxLogError(wxT("Missing DataQueue in readData")); + return NULL; + } + + if (dq->getType() != RT_AMBE) { + wxLogError(wxT("Wrong DataQueue type in readData")); + delete dq; + return NULL; + } + + CAMBEData* data = dq->getAMBE(); + + delete dq; + + return data; +} + +CHeardData* CIcomRepeaterProtocolHandler::readHeard() +{ + if (m_type != RT_HEARD) + return NULL; + + CDataQueue* dq = m_rptrQueue.getData(); + if (dq == NULL) { + wxLogError(wxT("Missing DataQueue in readHeard")); + return NULL; + } + + if (dq->getType() != RT_HEARD) { + wxLogError(wxT("Wrong DataQueue type in readHeard")); + delete dq; + return NULL; + } + + CHeardData* heard = dq->getHeard(); + + delete dq; + + return heard; +} + +CDDData* CIcomRepeaterProtocolHandler::readDD() +{ + if (m_type != RT_DD) + return NULL; + + CDataQueue* dq = m_rptrQueue.getData(); + if (dq == NULL) { + wxLogError(wxT("Missing DataQueue in readData")); + return NULL; + } + + if (dq->getType() != RT_DD) { + wxLogError(wxT("Wrong DataQueue type in readData")); + delete dq; + return NULL; + } + + CDDData* data = dq->getDD(); + + delete dq; + + return data; +} + +CHeaderData* CIcomRepeaterProtocolHandler::readBusyHeader() +{ + return NULL; +} + +CAMBEData* CIcomRepeaterProtocolHandler::readBusyAMBE() +{ + return NULL; +} + +void CIcomRepeaterProtocolHandler::close() +{ + m_killed = true; + + Wait(); +} + +bool CIcomRepeaterProtocolHandler::sendAck(wxUint16 seqNo) +{ + unsigned char buffer[10U]; + + buffer[0U] = 'D'; + buffer[1U] = 'S'; + buffer[2U] = 'T'; + buffer[3U] = 'R'; + + buffer[4U] = seqNo / 256U; + buffer[5U] = seqNo % 256U; + + buffer[6U] = 0x72U; + buffer[7U] = 0x00U; + + buffer[8U] = 0x00U; + buffer[9U] = 0x00U; + + return m_socket.write(buffer, 10U, m_icomAddress, m_icomPort); +} + +void CIcomRepeaterProtocolHandler::sendSingleReply(const CHeaderData& header) +{ + unsigned int id = ::rand() % 0xFFFF; + + CHeaderData replyHdr; + replyHdr.setId(id); + replyHdr.setBand1(0xFFU); + replyHdr.setBand2(0xFFU); + replyHdr.setBand3(0xFFU); + replyHdr.setFlag1(0x01U); + replyHdr.setMyCall1(header.getRptCall2()); + replyHdr.setMyCall2(wxT(" ")); + replyHdr.setYourCall(header.getMyCall1()); + replyHdr.setRptCall1(header.getRptCall2()); + replyHdr.setRptCall2(header.getRptCall1()); + + writeHeader(replyHdr); + + unsigned char buffer[DV_FRAME_MAX_LENGTH_BYTES]; + ::memcpy(buffer + 0U, NULL_AMBE_DATA_BYTES, VOICE_FRAME_LENGTH_BYTES); + ::memcpy(buffer + VOICE_FRAME_LENGTH_BYTES, END_PATTERN_BYTES, END_PATTERN_LENGTH_BYTES); + + CAMBEData replyData; + replyData.setId(id); + replyData.setBand1(0xFFU); + replyData.setBand2(0xFFU); + replyData.setBand3(0xFFU); + replyData.setSeq(0x40U); // Seq = 0 and end-of-data + replyData.setData(buffer, DV_FRAME_MAX_LENGTH_BYTES); + + writeAMBE(replyData); +} + +void CIcomRepeaterProtocolHandler::sendMultiReply(const CHeaderData& header) +{ + unsigned int id = ::rand() % 0xFFFF; + + CHeaderData replyHdr; + replyHdr.setId(id); + replyHdr.setBand1(0xFFU); + replyHdr.setBand2(0xFFU); + replyHdr.setBand3(0xFFU); + replyHdr.setFlag1(0x41U); + replyHdr.setMyCall1(header.getRptCall2()); + replyHdr.setMyCall2(wxT(" ")); + replyHdr.setYourCall(header.getMyCall1()); + replyHdr.setRptCall1(header.getRptCall2()); + replyHdr.setRptCall2(header.getRptCall1()); + + writeHeader(replyHdr); + + CAMBEData replyData; + unsigned char buffer[DV_FRAME_LENGTH_BYTES]; + + replyData.setId(id); + replyData.setBand1(0xFFU); + replyData.setBand2(0xFFU); + replyData.setBand3(0xFFU); + + ::memcpy(buffer + 0U, NULL_AMBE_DATA_BYTES, VOICE_FRAME_LENGTH_BYTES); + ::memcpy(buffer + VOICE_FRAME_LENGTH_BYTES, END_PATTERN_BYTES + 0U, 3U); + + replyData.setSeq(0x00U); // Seq = 0 + replyData.setData(buffer, DV_FRAME_LENGTH_BYTES); + + writeAMBE(replyData); + + ::memset(buffer + 0U, 0x00, DV_FRAME_LENGTH_BYTES); + ::memcpy(buffer + 0U, END_PATTERN_BYTES + 3U, 3U); + + replyData.setSeq(0x41U); // Seq = 1 and end-of-data + replyData.setData(buffer, DV_FRAME_LENGTH_BYTES); + + writeAMBE(replyData); +} + +void CIcomRepeaterProtocolHandler::free(CDataQueue* dataQueue) +{ + if (dataQueue == NULL) + return; + + switch (dataQueue->getType()) { + case RT_HEADER: + delete dataQueue->getHeader(); + break; + case RT_HEARD: + delete dataQueue->getHeard(); + break; + case RT_AMBE: + delete dataQueue->getAMBE(); + break; + case RT_DD: + delete dataQueue->getDD(); + break; + default: + break; + } + + delete dataQueue; +} diff --git a/Common/IcomRepeaterProtocolHandler.h b/Common/IcomRepeaterProtocolHandler.h new file mode 100644 index 0000000..95ee151 --- /dev/null +++ b/Common/IcomRepeaterProtocolHandler.h @@ -0,0 +1,176 @@ +/* + * Copyright (C) 2010-2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef IcomRepeaterProtocolHandler_H +#define IcomRepeaterProtocolHandler_H + +#include "RepeaterProtocolHandler.h" +#include "UDPReaderWriter.h" +#include "DStarDefines.h" +#include "RingBuffer.h" +#include "HeaderData.h" +#include "StatusData.h" +#include "HeardData.h" +#include "AMBEData.h" +#include "TextData.h" +#include "PollData.h" +#include "DDData.h" +#include "Timer.h" + +#if defined(__WINDOWS__) +#include "Inaddr.h" +#else +#include +#endif + +#include + +class CDataQueue { +public: + CDataQueue(CHeaderData* header) : + m_type(RT_HEADER), + m_header(header), + m_heard(NULL), + m_ambe(NULL), + m_dd(NULL) + { + } + + CDataQueue(CHeardData* heard) : + m_type(RT_HEARD), + m_header(NULL), + m_heard(heard), + m_ambe(NULL), + m_dd(NULL) + { + } + + CDataQueue(CAMBEData* data) : + m_type(RT_AMBE), + m_header(NULL), + m_heard(NULL), + m_ambe(data), + m_dd(NULL) + { + } + + CDataQueue(CDDData* data) : + m_type(RT_DD), + m_header(NULL), + m_heard(NULL), + m_ambe(NULL), + m_dd(data) + { + } + + CDataQueue() : + m_type(RT_POLL), + m_header(NULL), + m_heard(NULL), + m_ambe(NULL), + m_dd(NULL) + { + } + + REPEATER_TYPE getType() const + { + return m_type; + } + + CHeaderData* getHeader() const + { + return m_header; + } + + CHeardData* getHeard() const + { + return m_heard; + } + + CAMBEData* getAMBE() const + { + return m_ambe; + } + + CDDData* getDD() const + { + return m_dd; + } + +private: + REPEATER_TYPE m_type; + CHeaderData* m_header; + CHeardData* m_heard; + CAMBEData* m_ambe; + CDDData* m_dd; +}; + +class CIcomRepeaterProtocolHandler : public IRepeaterProtocolHandler, public wxThread { +public: + CIcomRepeaterProtocolHandler(const wxString& address, unsigned int port, const wxString& icomAddress, unsigned int icomPort); + virtual ~CIcomRepeaterProtocolHandler(); + + virtual void setCount(unsigned int count); + + virtual bool open(); + + virtual void* Entry(); + + virtual bool writeHeader(CHeaderData& header); + virtual bool writeAMBE(CAMBEData& data); + virtual bool writeDD(CDDData& data); + virtual bool writeText(CTextData& text); + virtual bool writeStatus(CStatusData& status); + + virtual REPEATER_TYPE read(); + virtual CPollData* readPoll(); + virtual CHeardData* readHeard(); + virtual CHeaderData* readHeader(); + virtual CAMBEData* readAMBE(); + virtual CDDData* readDD(); + virtual CHeaderData* readBusyHeader(); + virtual CAMBEData* readBusyAMBE(); + + virtual void close(); + +private: + CUDPReaderWriter m_socket; + in_addr m_icomAddress; + unsigned int m_icomPort; + bool m_over1; + wxUint16 m_seqNo; + unsigned int m_tries; + CDataQueue* m_ackQueue; + bool m_killed; + REPEATER_TYPE m_type; + unsigned char* m_buffer; + CRingBuffer m_rptrQueue; + CRingBuffer m_gwyQueue; + CTimer m_retryTimer; + + void readIcomPackets(); + void sendGwyPackets(); + bool sendAck(wxUint16 seqNo); + + void sendSingleReply(const CHeaderData& header); + void sendMultiReply(const CHeaderData& header); + + void free(CDataQueue* dataQueue); +}; + +#endif diff --git a/Common/LogEvent.cpp b/Common/LogEvent.cpp new file mode 100644 index 0000000..2cd850c --- /dev/null +++ b/Common/LogEvent.cpp @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2010 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "LogEvent.h" + +CLogEvent::CLogEvent(const wxString& text, wxEventType type, int id) : +wxEvent(id, type), +m_text(text) +{ +} + +CLogEvent::CLogEvent(const CLogEvent& event) : +wxEvent(event), +m_text(event.m_text) +{ +} + +CLogEvent::~CLogEvent() +{ +} + +wxString CLogEvent::getText() const +{ + return m_text; +} + +wxEvent* CLogEvent::Clone() const +{ + return new CLogEvent(*this); +} diff --git a/Common/LogEvent.h b/Common/LogEvent.h new file mode 100644 index 0000000..4721989 --- /dev/null +++ b/Common/LogEvent.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2010 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef LogEvent_H +#define LogEvent_H + +#include + +class CLogEvent : public wxEvent { +public: + CLogEvent(const wxString& text, wxEventType type, int id = 0); + virtual ~CLogEvent(); + + virtual wxString getText() const; + + virtual wxEvent* Clone() const; + +protected: + CLogEvent(const CLogEvent& event); + +private: + wxString m_text; +}; + +#endif diff --git a/Common/Logger.cpp b/Common/Logger.cpp new file mode 100644 index 0000000..8edd3b1 --- /dev/null +++ b/Common/Logger.cpp @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2002,2003,2009,2011,2012,2018 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "Logger.h" + +CLogger::CLogger(const wxString& directory, const wxString& name) : +#if(defined(__WINDOWS__)) +m_day(0), +#endif +wxLog(), +m_name(name), +m_file(NULL), +m_fileName() +{ + m_file = new wxFFile; + + m_fileName.SetPath(directory); + m_fileName.SetExt(wxT("log")); + +#if(defined(__WINDOWS__)) + time_t timestamp; + ::time(×tamp); + struct tm* tm = ::gmtime(×tamp); + + wxString text; + text.Printf(wxT("%s-%04d-%02d-%02d"), m_name.c_str(), tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday); + + m_day = tm->tm_yday; + m_fileName.SetName(text); +#else + m_fileName.SetName(m_name); +#endif + + bool ret = m_file->Open(m_fileName.GetFullPath(), wxT("a+t")); + if (!ret) { + wxLogError(wxT("Cannot open %s file for appending"), m_fileName.GetFullPath().c_str()); + return; + } +} + +CLogger::~CLogger() +{ + wxASSERT(m_file != NULL); + + m_file->Close(); + delete m_file; +} + +void CLogger::DoLogRecord(wxLogLevel level, const wxString& msg, const wxLogRecordInfo& info) +{ + wxASSERT(m_file != NULL); + wxASSERT(m_file->IsOpened()); + + wxString letter; + + switch (level) { + case wxLOG_FatalError: letter = wxT("F"); break; + case wxLOG_Error: letter = wxT("E"); break; + case wxLOG_Warning: letter = wxT("W"); break; + case wxLOG_Info: letter = wxT("I"); break; + case wxLOG_Message: letter = wxT("M"); break; + case wxLOG_Status: letter = wxT("M"); break; + case wxLOG_Trace: letter = wxT("T"); break; + case wxLOG_Debug: letter = wxT("D"); break; + default: letter = wxT("U"); break; + } + + struct tm* tm = ::gmtime(&info.timestamp); + + wxString message; + message.Printf(wxT("%s: %04d-%02d-%02d %02d:%02d:%02d: %s\n"), letter.c_str(), tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, msg.c_str()); + + logString(message, info.timestamp); + + if (level == wxLOG_FatalError) + ::abort(); +} + +void CLogger::logString(const wxString& msg, time_t timestamp) +{ + wxASSERT(m_file != NULL); + wxASSERT(m_file->IsOpened()); + +#if(defined(__WINDOWS__)) + struct tm* tm = ::gmtime(×tamp); + + int day = tm->tm_yday; + if (day != m_day) { + wxString text; + text.Printf(wxT("%s-%04d-%02d-%02d"), m_name.c_str(), tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday); + + m_day = day; + m_fileName.SetName(text); + + m_file->Close(); + + bool ret = m_file->Open(m_fileName.GetFullPath(), wxT("a+t")); + if (!ret) { + wxLogError(wxT("Cannot open %s file for appending"), m_fileName.GetFullPath().c_str()); + return; + } + } +#endif + + m_file->Write(msg); + m_file->Flush(); +} diff --git a/Common/Logger.h b/Common/Logger.h new file mode 100644 index 0000000..0d082f0 --- /dev/null +++ b/Common/Logger.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2002,2003,2009,2011,2012,2018 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef Logger_H +#define Logger_H + +#include +#include +#include +#include + +class CLogger : public wxLog { +public: + CLogger(const wxString& directory, const wxString& name); + virtual ~CLogger(); + + virtual void DoLogRecord(wxLogLevel level, const wxString& msg, const wxLogRecordInfo& info); + +private: + wxString m_name; + wxFFile* m_file; + wxFileName m_fileName; +#if(defined(__WINDOWS__)) + int m_day; +#endif + + void logString(const wxString& msg, time_t timestamp); +}; + +#endif diff --git a/Common/PollData.cpp b/Common/PollData.cpp new file mode 100644 index 0000000..04b2569 --- /dev/null +++ b/Common/PollData.cpp @@ -0,0 +1,284 @@ +/* + * Copyright (C) 2010,2012,2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "PollData.h" + +#include "DStarDefines.h" +#include "Utils.h" + +CPollData::CPollData(const wxString& data1, const wxString& data2, DIRECTION direction, const in_addr& yourAddress, unsigned int yourPort, unsigned int myPort) : +m_data1(data1), +m_data2(data2), +m_direction(direction), +m_dongle(false), +m_length(0U), +m_yourAddress(yourAddress), +m_yourPort(yourPort), +m_myPort(myPort) +{ + wxASSERT(yourPort > 0U); +} + +CPollData::CPollData(const wxString& data, const in_addr& yourAddress, unsigned int yourPort, unsigned int myPort) : +m_data1(data), +m_data2(), +m_direction(DIR_OUTGOING), +m_dongle(false), +m_length(0U), +m_yourAddress(yourAddress), +m_yourPort(yourPort), +m_myPort(myPort) +{ + wxASSERT(yourPort > 0U); +} + +CPollData::CPollData(const in_addr& yourAddress, unsigned int yourPort, unsigned int myPort) : +m_data1(), +m_data2(), +m_direction(DIR_OUTGOING), +m_dongle(false), +m_length(0U), +m_yourAddress(yourAddress), +m_yourPort(yourPort), +m_myPort(myPort) +{ + wxASSERT(yourPort > 0U); +} + +CPollData::CPollData() : +m_data1(), +m_data2(), +m_direction(DIR_OUTGOING), +m_dongle(false), +m_length(0U), +m_yourAddress(), +m_yourPort(0U), +m_myPort(0U) +{ +} + +CPollData::~CPollData() +{ +} + +bool CPollData::setDExtraData(const unsigned char* data, unsigned int length, const in_addr& yourAddress, unsigned int yourPort, unsigned int myPort) +{ + wxASSERT(data != NULL); + wxASSERT(length >= 9U); + wxASSERT(yourPort > 0U); + + m_data1 = wxString((const char*)data, wxConvLocal, LONG_CALLSIGN_LENGTH); + m_dongle = data[LONG_CALLSIGN_LENGTH] != 0x00; + + m_length = length; + m_yourAddress = yourAddress; + m_yourPort = yourPort; + m_myPort = myPort; + + + return true; +} + +bool CPollData::setDCSData(const unsigned char* data, unsigned int length, const in_addr& yourAddress, unsigned int yourPort, unsigned int myPort) +{ + wxASSERT(data != NULL); + wxASSERT(yourPort > 0U); + + switch (length) { + case 17U: + m_data1 = wxString((const char*)(data + 0U), wxConvLocal, LONG_CALLSIGN_LENGTH); + m_data2 = wxString((const char*)(data + 9U), wxConvLocal, LONG_CALLSIGN_LENGTH); + m_length = length; + m_direction = DIR_INCOMING; + m_yourAddress = yourAddress; + m_yourPort = yourPort; + m_myPort = myPort; + break; + + case 22U: + m_data1 = wxString((const char*)(data + 0U), wxConvLocal, LONG_CALLSIGN_LENGTH); + m_data2 = wxString((const char*)(data + 9U), wxConvLocal, LONG_CALLSIGN_LENGTH - 1U); + m_data2.Append(wxString((const char*)(data + 17U), wxConvLocal, 1U)); + m_length = length; + m_direction = DIR_OUTGOING; + m_yourAddress = yourAddress; + m_yourPort = yourPort; + m_myPort = myPort; + break; + } + + return true; +} + +bool CPollData::setCCSData(const unsigned char* data, unsigned int length, const in_addr& yourAddress, unsigned int yourPort, unsigned int myPort) +{ + wxASSERT(data != NULL); + wxASSERT(length >= 25U); + wxASSERT(yourPort > 0U); + + m_data1 = wxString((const char*)(data + 0U), wxConvLocal, 25U); + m_length = length; + m_yourAddress = yourAddress; + m_yourPort = yourPort; + m_myPort = myPort; + + return true; +} + +bool CPollData::setDPlusData(const unsigned char*, unsigned int length, const in_addr& yourAddress, unsigned int yourPort, unsigned int myPort) +{ + wxASSERT(yourPort > 0U); + + m_length = length; + m_yourAddress = yourAddress; + m_yourPort = yourPort; + m_myPort = myPort; + + return true; +} + +unsigned int CPollData::getDExtraData(unsigned char *data, unsigned int length) const +{ + wxASSERT(data != NULL); + wxASSERT(length >= 9U); + + ::memset(data, ' ', LONG_CALLSIGN_LENGTH); + + for (unsigned int i = 0U; i < m_data1.Len() && i < LONG_CALLSIGN_LENGTH; i++) + data[i] = m_data1.GetChar(i); + + data[LONG_CALLSIGN_LENGTH] = 0x00; + + return 9U; +} + +unsigned int CPollData::getDCSData(unsigned char *data, unsigned int length) const +{ + wxASSERT(data != NULL); + wxASSERT(length >= 22U); + + if (m_direction == DIR_OUTGOING) { + ::memset(data, ' ', 17U); + + for (unsigned int i = 0U; i < m_data1.Len() && i < LONG_CALLSIGN_LENGTH; i++) + data[i + 0U] = m_data1.GetChar(i); + + data[8U] = 0x00U; + + for (unsigned int i = 0U; i < m_data2.Len() && i < LONG_CALLSIGN_LENGTH; i++) + data[i + 9U] = m_data2.GetChar(i); + + return 17U; + } else { + ::memset(data, ' ', 22U); + + for (unsigned int i = 0U; i < m_data1.Len() && i < LONG_CALLSIGN_LENGTH; i++) + data[i + 0U] = m_data1.GetChar(i); + + for (unsigned int i = 0U; i < m_data2.Len() && i < (LONG_CALLSIGN_LENGTH - 1U); i++) + data[i + 9U] = m_data2.GetChar(i); + + if (m_data2.Len() >= LONG_CALLSIGN_LENGTH) + data[17U] = m_data2.GetChar(LONG_CALLSIGN_LENGTH - 1U); + + data[18U] = 0x0AU; + data[19U] = 0x00U; + + return 22U; + } +} + +unsigned int CPollData::getCCSData(unsigned char *data, unsigned int length) const +{ + wxASSERT(data != NULL); + wxASSERT(length >= 25U); + + ::memset(data, ' ', 25U); + + for (unsigned int i = 0U; i < m_data1.Len() && i < LONG_CALLSIGN_LENGTH; i++) + data[i + 0U] = m_data1.GetChar(i); + + if (!m_data2.IsEmpty()) { + for (unsigned int i = 0U; i < m_data2.Len() && i < LONG_CALLSIGN_LENGTH; i++) + data[i + 8U] = m_data2.GetChar(i); + } + + return 25U; +} + +unsigned int CPollData::getDPlusData(unsigned char *data, unsigned int length) const +{ + wxASSERT(data != NULL); + wxASSERT(length >= 3U); + + data[0U] = 0x03; + data[1U] = 0x60; + data[2U] = 0x00; + + return 3U; +} + +wxString CPollData::getData1() const +{ + return m_data1; +} + +void CPollData::setData1(const wxString& data) +{ + m_data1 = data; +} + +wxString CPollData::getData2() const +{ + return m_data2; +} + +void CPollData::setData2(const wxString& data) +{ + m_data2 = data; +} + +bool CPollData::isDongle() const +{ + return m_dongle; +} + +in_addr CPollData::getYourAddress() const +{ + return m_yourAddress; +} + +unsigned int CPollData::getYourPort() const +{ + return m_yourPort; +} + +unsigned int CPollData::getMyPort() const +{ + return m_myPort; +} + +DIRECTION CPollData::getDirection() const +{ + return m_direction; +} + +unsigned int CPollData::getLength() const +{ + return m_length; +} diff --git a/Common/PollData.h b/Common/PollData.h new file mode 100644 index 0000000..d85ec78 --- /dev/null +++ b/Common/PollData.h @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2010,2012,2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef PollData_H +#define PollData_H + +#include "Defs.h" + +#include + +#if defined(__WINDOWS__) +#include "Inaddr.h" +#else +#include +#endif + +class CPollData { +public: + CPollData(const wxString& data1, const wxString& data2, DIRECTION direction, const in_addr& yourAddress, unsigned int yourPort, unsigned int myPort = 0U); + CPollData(const wxString& data, const in_addr& yourAddress, unsigned int yourPort, unsigned int myPort = 0U); + CPollData(const in_addr& yourAddress, unsigned int yourPort, unsigned int myPort = 0U); + CPollData(); + ~CPollData(); + + bool setDExtraData(const unsigned char* data, unsigned int length, const in_addr& yourAddress, unsigned int yourPort, unsigned int myPort); + bool setDPlusData(const unsigned char* data, unsigned int length, const in_addr& yourAddress, unsigned int yourPort, unsigned int myPort); + bool setDCSData(const unsigned char* data, unsigned int length, const in_addr& yourAddress, unsigned int yourPort, unsigned int myPort); + bool setCCSData(const unsigned char* data, unsigned int length, const in_addr& yourAddress, unsigned int yourPort, unsigned int myPort); + + unsigned int getDExtraData(unsigned char* data, unsigned int length) const; + unsigned int getDPlusData(unsigned char* data, unsigned int length) const; + unsigned int getDCSData(unsigned char* data, unsigned int length) const; + unsigned int getCCSData(unsigned char* data, unsigned int length) const; + + wxString getData1() const; + void setData1(const wxString& data); + + wxString getData2() const; + void setData2(const wxString& data); + + bool isDongle() const; + + in_addr getYourAddress() const; + unsigned int getYourPort() const; + unsigned int getMyPort() const; + + DIRECTION getDirection() const; + unsigned int getLength() const; + +private: + wxString m_data1; + wxString m_data2; + DIRECTION m_direction; + bool m_dongle; + unsigned int m_length; + in_addr m_yourAddress; + unsigned int m_yourPort; + unsigned int m_myPort; +}; + +#endif diff --git a/Common/ReflectorCallback.h b/Common/ReflectorCallback.h new file mode 100644 index 0000000..68f97f1 --- /dev/null +++ b/Common/ReflectorCallback.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2011,2012,2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef ReflectorCallback_H +#define ReflectorCallback_H + +#include "DStarDefines.h" +#include "HeaderData.h" +#include "AMBEData.h" +#include "Defs.h" + +#include + +class IReflectorCallback { +public: + virtual bool process(CHeaderData& header, DIRECTION direction, AUDIO_SOURCE source) = 0; + + virtual bool process(CAMBEData& data, DIRECTION direction, AUDIO_SOURCE source) = 0; + + virtual bool linkFailed(DSTAR_PROTOCOL protocol, const wxString& callsign, bool isRecoverable) = 0; + + virtual void linkRefused(DSTAR_PROTOCOL protocol, const wxString& callsign) = 0; + + virtual void linkUp(DSTAR_PROTOCOL protocol, const wxString& callsign) = 0; + +private: +}; + +#endif diff --git a/Common/RemoteHandler.cpp b/Common/RemoteHandler.cpp new file mode 100644 index 0000000..dbbe1fd --- /dev/null +++ b/Common/RemoteHandler.cpp @@ -0,0 +1,214 @@ +/* + * Copyright (C) 2011,2012,2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "RepeaterHandler.h" +#include "StarNetHandler.h" +#include "RemoteHandler.h" +#include "DExtraHandler.h" +#include "DPlusHandler.h" +#include "DStarDefines.h" +#include "DCSHandler.h" + +CRemoteHandler::CRemoteHandler(const wxString& password, unsigned int port, const wxString& address) : +m_password(password), +m_handler(port, address), +m_random(0U) +{ + wxASSERT(port > 0U); + wxASSERT(!password.IsEmpty()); +} + +CRemoteHandler::~CRemoteHandler() +{ +} + +bool CRemoteHandler::open() +{ + return m_handler.open(); +} + +void CRemoteHandler::process() +{ + RPH_TYPE type = m_handler.readType(); + switch (type) { + case RPHT_LOGOUT: + m_handler.setLoggedIn(false); + wxLogMessage(wxT("Remote control user has logged out")); + break; + case RPHT_LOGIN: + m_random = ::rand(); + m_handler.sendRandom(m_random); + break; + case RPHT_HASH: { + bool valid = m_handler.readHash(m_password, m_random); + if (valid) { + wxLogMessage(wxT("Remote control user has logged in")); + m_handler.setLoggedIn(true); + m_handler.sendACK(); + } else { + wxLogMessage(wxT("Remote control user has failed login authentication")); + m_handler.setLoggedIn(false); + m_handler.sendNAK(wxT("Invalid password")); + } + } + break; + case RPHT_CALLSIGNS: + sendCallsigns(); + break; + case RPHT_REPEATER: { + wxString callsign = m_handler.readRepeater(); + sendRepeater(callsign); + } + break; + case RPHT_STARNET: { + wxString callsign = m_handler.readStarNetGroup(); + sendStarNetGroup(callsign); + } + break; + case RPHT_LINK: { + wxString callsign, reflector; + RECONNECT reconnect; + m_handler.readLink(callsign, reconnect, reflector); + if (reflector.IsEmpty()) + wxLogMessage(wxT("Remote control user has linked \"%s\" to \"None\" with reconnect %d"), callsign.c_str(), int(reconnect)); + else + wxLogMessage(wxT("Remote control user has linked \"%s\" to \"%s\" with reconnect %d"), callsign.c_str(), reflector.c_str(), int(reconnect)); + link(callsign, reconnect, reflector, true); + } + break; + case RPHT_UNLINK: { + wxString callsign, reflector; + PROTOCOL protocol; + m_handler.readUnlink(callsign, protocol, reflector); + wxLogMessage(wxT("Remote control user has unlinked \"%s\" from \"%s\" for protocol %d"), callsign.c_str(), reflector.c_str(), int(protocol)); + unlink(callsign, protocol, reflector); + } + break; + case RPHT_LINKSCR: { + wxString callsign, reflector; + RECONNECT reconnect; + m_handler.readLinkScr(callsign, reconnect, reflector); + if (reflector.IsEmpty()) + wxLogMessage(wxT("Remote control user has linked \"%s\" to \"None\" with reconnect %d from localhost"), callsign.c_str(), reconnect); + else + wxLogMessage(wxT("Remote control user has linked \"%s\" to \"%s\" with reconnect %d from localhost"), callsign.c_str(), reflector.c_str(), reconnect); + link(callsign, reconnect, reflector, false); + } + break; + case RPHT_LOGOFF: { + wxString callsign, user; + m_handler.readLogoff(callsign, user); + wxLogMessage(wxT("Remote control user has logged off \"%s\" from \"%s\""), user.c_str(), callsign.c_str()); + logoff(callsign, user); + } + break; + default: + break; + } +} + +void CRemoteHandler::close() +{ + m_handler.close(); +} + +void CRemoteHandler::sendCallsigns() +{ + wxArrayString repeaters = CRepeaterHandler::listDVRepeaters(); + wxArrayString starNets = CStarNetHandler::listStarNets(); + + m_handler.sendCallsigns(repeaters, starNets); +} + +void CRemoteHandler::sendRepeater(const wxString& callsign) +{ + CRepeaterHandler* repeater = CRepeaterHandler::findDVRepeater(callsign); + if (repeater == NULL) { + m_handler.sendNAK(wxT("Invalid repeater callsign")); + return; + } + + CRemoteRepeaterData* data = repeater->getInfo(); + if (data != NULL) { + CDExtraHandler::getInfo(repeater, *data); + CDPlusHandler::getInfo(repeater, *data); + CDCSHandler::getInfo(repeater, *data); + CCCSHandler::getInfo(repeater, *data); + + m_handler.sendRepeater(*data); + } + + delete data; +} + +void CRemoteHandler::sendStarNetGroup(const wxString& callsign) +{ + CStarNetHandler* starNet = CStarNetHandler::findStarNet(callsign); + if (starNet == NULL) { + m_handler.sendNAK(wxT("Invalid STARnet Group callsign")); + return; + } + + CRemoteStarNetGroup* data = starNet->getInfo(); + if (data != NULL) + m_handler.sendStarNetGroup(*data); + + delete data; +} + +void CRemoteHandler::link(const wxString& callsign, RECONNECT reconnect, const wxString& reflector, bool respond) +{ + CRepeaterHandler* repeater = CRepeaterHandler::findDVRepeater(callsign); + if (repeater == NULL) { + m_handler.sendNAK(wxT("Invalid repeater callsign")); + return; + } + + repeater->link(reconnect, reflector); + + if (respond) + m_handler.sendACK(); +} + +void CRemoteHandler::unlink(const wxString& callsign, PROTOCOL protocol, const wxString& reflector) +{ + CRepeaterHandler* repeater = CRepeaterHandler::findDVRepeater(callsign); + if (repeater == NULL) { + m_handler.sendNAK(wxT("Invalid repeater callsign")); + return; + } + + repeater->unlink(protocol, reflector); + + m_handler.sendACK(); +} + +void CRemoteHandler::logoff(const wxString& callsign, const wxString& user) +{ + CStarNetHandler* starNet = CStarNetHandler::findStarNet(callsign); + if (starNet == NULL) { + m_handler.sendNAK(wxT("Invalid STARnet group callsign")); + return; + } + + bool res = starNet->logoff(user); + if (!res) + m_handler.sendNAK(wxT("Invalid STARnet user callsign")); + else + m_handler.sendACK(); +} diff --git a/Common/RemoteHandler.h b/Common/RemoteHandler.h new file mode 100644 index 0000000..6ad2f94 --- /dev/null +++ b/Common/RemoteHandler.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2011,2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef RemoteHandler_H +#define RemoteHandler_H + +#include "RemoteProtocolHandler.h" +#include "Timer.h" + +#include + +class CRemoteHandler { +public: + CRemoteHandler(const wxString& password, unsigned int port, const wxString& address = wxEmptyString); + ~CRemoteHandler(); + + bool open(); + + void process(); + + void close(); + +private: + wxString m_password; + CRemoteProtocolHandler m_handler; + unsigned int m_random; + + void sendCallsigns(); + void sendRepeater(const wxString& callsign); + void sendStarNetGroup(const wxString& callsign); + void link(const wxString& callsign, RECONNECT reconnect, const wxString& reflector, bool respond); + void unlink(const wxString& callsign, PROTOCOL protocol, const wxString& reflector); + void logoff(const wxString& callsign, const wxString& user); +}; + +#endif diff --git a/Common/RemoteLinkData.cpp b/Common/RemoteLinkData.cpp new file mode 100644 index 0000000..1483c40 --- /dev/null +++ b/Common/RemoteLinkData.cpp @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2011 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "RemoteLinkData.h" + +CRemoteLinkData::CRemoteLinkData(const wxString& callsign, PROTOCOL protocol, bool linked, DIRECTION direction, bool dongle) : +m_callsign(callsign), +m_protocol(protocol), +m_linked(linked), +m_direction(direction), +m_dongle(dongle) +{ +} + +CRemoteLinkData::~CRemoteLinkData() +{ +} + +wxString CRemoteLinkData::getCallsign() const +{ + return m_callsign; +} + +wxInt32 CRemoteLinkData::getProtocol() const +{ + return wxInt32(m_protocol); +} + +wxInt32 CRemoteLinkData::isLinked() const +{ + return m_linked ? 1 : 0; +} + +wxInt32 CRemoteLinkData::getDirection() const +{ + return wxInt32(m_direction); +} + +wxInt32 CRemoteLinkData::isDongle() const +{ + return m_dongle ? 1 : 0; +} diff --git a/Common/RemoteLinkData.h b/Common/RemoteLinkData.h new file mode 100644 index 0000000..23df8f8 --- /dev/null +++ b/Common/RemoteLinkData.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2011 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef RemoteLinkData_H +#define RemoteLinkData_H + +#include "Defs.h" + +#include + +class CRemoteLinkData { +public: + CRemoteLinkData(const wxString& callsign, PROTOCOL protocol, bool linked, DIRECTION direction, bool dongle); + ~CRemoteLinkData(); + + wxString getCallsign() const; + wxInt32 getProtocol() const; + wxInt32 isLinked() const; + wxInt32 getDirection() const; + wxInt32 isDongle() const; + +private: + wxString m_callsign; + PROTOCOL m_protocol; + bool m_linked; + DIRECTION m_direction; + bool m_dongle; +}; + +#endif diff --git a/Common/RemoteProtocolHandler.cpp b/Common/RemoteProtocolHandler.cpp new file mode 100644 index 0000000..1c77426 --- /dev/null +++ b/Common/RemoteProtocolHandler.cpp @@ -0,0 +1,441 @@ +/* + * Copyright (C) 2011,2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "RemoteProtocolHandler.h" +#include "DStarDefines.h" +#include "SHA256.h" +#include "Utils.h" + +const unsigned int BUFFER_LENGTH = 2000U; + +CRemoteProtocolHandler::CRemoteProtocolHandler(unsigned int port, const wxString& address) : +m_socket(address, port), +m_address(), +m_port(0U), +m_loggedIn(false), +m_type(RPHT_NONE), +m_inBuffer(NULL), +m_inLength(0U), +m_outBuffer(NULL) +{ + wxASSERT(port > 0U); + + m_inBuffer = new unsigned char[BUFFER_LENGTH]; + m_outBuffer = new unsigned char[BUFFER_LENGTH]; +} + +CRemoteProtocolHandler::~CRemoteProtocolHandler() +{ + delete[] m_outBuffer; + delete[] m_inBuffer; +} + +bool CRemoteProtocolHandler::open() +{ + return m_socket.open(); +} + +RPH_TYPE CRemoteProtocolHandler::readType() +{ + m_type = RPHT_NONE; + + in_addr address; + unsigned int port; + + int length = m_socket.read(m_inBuffer, BUFFER_LENGTH, address, port); + if (length <= 0) + return m_type; + + // CUtils::dump(wxT("Incoming"), m_inBuffer, length); + + if (::memcmp(m_inBuffer, "LIN", 3U) == 0) { + m_loggedIn = false; + m_address = address; + m_port = port; + m_type = RPHT_LOGIN; + return m_type; + } + + if (address.s_addr == inet_addr("127.0.0.1")) { + if (::memcmp(m_inBuffer, "LKS", 3U) == 0) { + m_inLength = length; + m_type = RPHT_LINKSCR; + return m_type; + } + } + + if (m_loggedIn) { + if (address.s_addr != m_address.s_addr || port != m_port) { + sendNAK(wxT("You are not logged in")); + return m_type; + } + } + + m_inLength = length; + + if (::memcmp(m_inBuffer, "SHA", 3U) == 0) { + if (m_loggedIn) { + sendNAK(wxT("Someone is already logged in")); + return m_type; + } + m_type = RPHT_HASH; + return m_type; + } else if (::memcmp(m_inBuffer, "GCS", 3U) == 0) { + if (!m_loggedIn) { + sendNAK(wxT("You are not logged in")); + return m_type; + } + m_type = RPHT_CALLSIGNS; + return m_type; + } else if (::memcmp(m_inBuffer, "GRP", 3U) == 0) { + if (!m_loggedIn) { + sendNAK(wxT("You are not logged in")); + return m_type; + } + m_type = RPHT_REPEATER; + return m_type; + } else if (::memcmp(m_inBuffer, "GSN", 3U) == 0) { + if (!m_loggedIn) { + sendNAK(wxT("You are not logged in")); + return m_type; + } + m_type = RPHT_STARNET; + return m_type; + } else if (::memcmp(m_inBuffer, "LNK", 3U) == 0) { + if (!m_loggedIn) { + sendNAK(wxT("You are not logged in")); + return m_type; + } + m_type = RPHT_LINK; + return m_type; + } else if (::memcmp(m_inBuffer, "UNL", 3U) == 0) { + if (!m_loggedIn) { + sendNAK(wxT("You are not logged in")); + return m_type; + } + m_type = RPHT_UNLINK; + return m_type; + } else if (::memcmp(m_inBuffer, "LGO", 3U) == 0) { + if (!m_loggedIn) { + sendNAK(wxT("You are not logged in")); + return m_type; + } + m_type = RPHT_LOGOFF; + return m_type; + } else if (::memcmp(m_inBuffer, "LOG", 3U) == 0) { + if (!m_loggedIn) + return m_type; + m_type = RPHT_LOGOUT; + return m_type; + } else { + if (!m_loggedIn) { + sendNAK(wxT("You are not logged in")); + return m_type; + } + m_type = RPHT_UNKNOWN; + return m_type; + } +} + +bool CRemoteProtocolHandler::readHash(const wxString& password, wxUint32 random) +{ + if (m_type != RPHT_HASH) + return false; + + unsigned char* hash = m_inBuffer + 3U; + + unsigned int len = password.Len() + sizeof(wxUint32); + unsigned char* in = new unsigned char[len]; + unsigned char* out = new unsigned char[32U]; + + ::memcpy(in, &random, sizeof(wxUint32)); + for (unsigned int i = 0U; i < password.Len(); i++) + in[i + sizeof(unsigned int)] = password.GetChar(i); + + CSHA256 sha256; + sha256.buffer(in, len, out); + + bool res = ::memcmp(out, hash, 32U) == 0; + + delete[] in; + delete[] out; + + return res; +} + +wxString CRemoteProtocolHandler::readRepeater() +{ + if (m_type != RPHT_REPEATER) + return wxEmptyString; + + wxString callsign((char*)(m_inBuffer + 3U), wxConvLocal, LONG_CALLSIGN_LENGTH); + + return callsign; +} + +wxString CRemoteProtocolHandler::readStarNetGroup() +{ + if (m_type != RPHT_STARNET) + return wxEmptyString; + + wxString callsign((char*)(m_inBuffer + 3U), wxConvLocal, LONG_CALLSIGN_LENGTH); + + return callsign; +} + +bool CRemoteProtocolHandler::readLogoff(wxString& callsign, wxString& user) +{ + if (m_type != RPHT_LOGOFF) + return false; + + callsign = wxString((char*)(m_inBuffer + 3U), wxConvLocal, LONG_CALLSIGN_LENGTH); + user = wxString((char*)(m_inBuffer + 3U + LONG_CALLSIGN_LENGTH), wxConvLocal, LONG_CALLSIGN_LENGTH); + + return true; +} + + +bool CRemoteProtocolHandler::readLink(wxString& callsign, RECONNECT& reconnect, wxString& reflector) +{ + if (m_type != RPHT_LINK) + return false; + + callsign = wxString((char*)(m_inBuffer + 3U), wxConvLocal, LONG_CALLSIGN_LENGTH); + + wxInt32 temp; + ::memcpy(&temp, m_inBuffer + 3U + LONG_CALLSIGN_LENGTH, sizeof(wxInt32)); + reconnect = RECONNECT(wxINT32_SWAP_ON_BE(temp)); + + reflector = wxString((char*)(m_inBuffer + 3U + LONG_CALLSIGN_LENGTH + sizeof(wxInt32)), wxConvLocal, LONG_CALLSIGN_LENGTH); + + if (reflector.IsSameAs(wxT(" "))) + reflector.Clear(); + + return true; +} + +bool CRemoteProtocolHandler::readUnlink(wxString& callsign, PROTOCOL& protocol, wxString& reflector) +{ + if (m_type != RPHT_UNLINK) + return false; + + callsign = wxString((char*)(m_inBuffer + 3U), wxConvLocal, LONG_CALLSIGN_LENGTH); + + wxInt32 temp; + ::memcpy(&temp, m_inBuffer + 3U + LONG_CALLSIGN_LENGTH, sizeof(wxInt32)); + protocol = PROTOCOL(wxINT32_SWAP_ON_BE(temp)); + + reflector = wxString((char*)(m_inBuffer + 3U + LONG_CALLSIGN_LENGTH + sizeof(wxInt32)), wxConvLocal, LONG_CALLSIGN_LENGTH); + + return true; +} + +bool CRemoteProtocolHandler::readLinkScr(wxString& callsign, RECONNECT& reconnect, wxString& reflector) +{ + if (m_type != RPHT_LINKSCR) + return false; + + callsign = wxString((char*)(m_inBuffer + 3U), wxConvLocal, LONG_CALLSIGN_LENGTH); + + reflector = wxString((char*)(m_inBuffer + 3U + LONG_CALLSIGN_LENGTH), wxConvLocal, LONG_CALLSIGN_LENGTH); + + wxString rec = wxString((char*)(m_inBuffer + 3U + 2U * LONG_CALLSIGN_LENGTH), wxConvLocal, 1U); + + unsigned long val; + rec.ToULong(&val); + + reconnect = RECONNECT(val); + + if (reflector.IsSameAs(wxT(" "))) + reflector.Clear(); + + return true; +} + +bool CRemoteProtocolHandler::sendCallsigns(const wxArrayString& repeaters, const wxArrayString& starNets) +{ + unsigned char* p = m_outBuffer; + + ::memcpy(p, "CAL", 3U); + p += 3U; + + for (unsigned int n = 0U; n < repeaters.GetCount(); n++) { + *p++ = 'R'; + + ::memset(p, ' ' , LONG_CALLSIGN_LENGTH); + for (unsigned int i = 0U; i < repeaters.Item(n).Len(); i++) + p[i] = repeaters.Item(n).GetChar(i); + p += LONG_CALLSIGN_LENGTH; + } + + for (unsigned int n = 0U; n < starNets.GetCount(); n++) { + *p++ = 'S'; + + ::memset(p, ' ' , LONG_CALLSIGN_LENGTH); + for (unsigned int i = 0U; i < starNets.Item(n).Len(); i++) + p[i] = starNets.Item(n).GetChar(i); + p += LONG_CALLSIGN_LENGTH; + } + + // CUtils::dump(wxT("Outgoing"), m_outBuffer, p - m_outBuffer); + + return m_socket.write(m_outBuffer, p - m_outBuffer, m_address, m_port); +} + +bool CRemoteProtocolHandler::sendRepeater(const CRemoteRepeaterData& data) +{ + unsigned char* p = m_outBuffer; + + ::memcpy(p, "RPT", 3U); + p += 3U; + + ::memset(p, ' ', LONG_CALLSIGN_LENGTH); + for (unsigned int i = 0U; i < data.getCallsign().Len(); i++) + p[i] = data.getCallsign().GetChar(i); + p += LONG_CALLSIGN_LENGTH; + + wxInt32 reconnect = wxINT32_SWAP_ON_BE(data.getReconnect()); + ::memcpy(p, &reconnect, sizeof(wxInt32)); + p += sizeof(wxInt32); + + ::memset(p, ' ', LONG_CALLSIGN_LENGTH); + for (unsigned int i = 0U; i < data.getReflector().Len(); i++) + p[i] = data.getReflector().GetChar(i); + p += LONG_CALLSIGN_LENGTH; + + for (unsigned int n = 0U; n < data.getLinkCount(); n++) { + CRemoteLinkData& link = data.getLink(n); + + ::memset(p, ' ', LONG_CALLSIGN_LENGTH); + for (unsigned int i = 0U; i < link.getCallsign().Len(); i++) + p[i] = link.getCallsign().GetChar(i); + p += LONG_CALLSIGN_LENGTH; + + wxInt32 protocol = wxINT32_SWAP_ON_BE(link.getProtocol()); + ::memcpy(p, &protocol, sizeof(wxInt32)); + p += sizeof(wxInt32); + + wxInt32 linked = wxINT32_SWAP_ON_BE(link.isLinked()); + ::memcpy(p, &linked, sizeof(wxInt32)); + p += sizeof(wxInt32); + + wxInt32 direction = wxINT32_SWAP_ON_BE(link.getDirection()); + ::memcpy(p, &direction, sizeof(wxInt32)); + p += sizeof(wxInt32); + + wxInt32 dongle = wxINT32_SWAP_ON_BE(link.isDongle()); + ::memcpy(p, &dongle, sizeof(wxInt32)); + p += sizeof(wxInt32); + } + + // CUtils::dump(wxT("Outgoing"), m_outBuffer, p - m_outBuffer); + + return m_socket.write(m_outBuffer, p - m_outBuffer, m_address, m_port); +} + +bool CRemoteProtocolHandler::sendStarNetGroup(const CRemoteStarNetGroup& data) +{ + unsigned char* p = m_outBuffer; + + ::memcpy(p, "SNT", 3U); + p += 3U; + + ::memset(p, ' ', LONG_CALLSIGN_LENGTH); + for (unsigned int i = 0U; i < data.getCallsign().Len(); i++) + p[i] = data.getCallsign().GetChar(i); + p += LONG_CALLSIGN_LENGTH; + + ::memset(p, ' ', LONG_CALLSIGN_LENGTH); + for (unsigned int i = 0U; i < data.getLogoff().Len(); i++) + p[i] = data.getLogoff().GetChar(i); + p += LONG_CALLSIGN_LENGTH; + + wxUint32 timer = wxUINT32_SWAP_ON_BE(data.getTimer()); + ::memcpy(p, &timer, sizeof(wxUint32)); + p += sizeof(wxUint32); + + wxUint32 timeout = wxUINT32_SWAP_ON_BE(data.getTimeout()); + ::memcpy(p, &timeout, sizeof(wxUint32)); + p += sizeof(wxUint32); + + for (unsigned int n = 0U; n < data.getUserCount(); n++) { + CRemoteStarNetUser& user = data.getUser(n); + + ::memset(p, ' ', LONG_CALLSIGN_LENGTH); + for (unsigned int i = 0U; i < user.getCallsign().Len(); i++) + p[i] = user.getCallsign().GetChar(i); + p += LONG_CALLSIGN_LENGTH; + + timer = wxUINT32_SWAP_ON_BE(user.getTimer()); + ::memcpy(p, &timer, sizeof(wxUint32)); + p += sizeof(wxUint32); + + timeout = wxUINT32_SWAP_ON_BE(user.getTimeout()); + ::memcpy(p, &timeout, sizeof(wxUint32)); + p += sizeof(wxUint32); + } + + // CUtils::dump(wxT("Outgoing"), m_outBuffer, p - m_outBuffer); + + return m_socket.write(m_outBuffer, p - m_outBuffer, m_address, m_port); +} + +void CRemoteProtocolHandler::setLoggedIn(bool set) +{ + m_loggedIn = set; +} + +void CRemoteProtocolHandler::close() +{ + m_socket.close(); +} + +bool CRemoteProtocolHandler::sendACK() +{ + ::memcpy(m_outBuffer + 0U, "ACK", 3U); + + // CUtils::dump(wxT("Outgoing"), m_outBuffer, 3U); + + return m_socket.write(m_outBuffer, 3U, m_address, m_port); +} + +bool CRemoteProtocolHandler::sendNAK(const wxString& text) +{ + ::memcpy(m_outBuffer + 0U, "NAK", 3U); + + ::memset(m_outBuffer + 3U, 0x00U, text.Len() + 1U); + + for (unsigned int i = 0U; i < text.Len(); i++) + m_outBuffer[i + 3U] = text.GetChar(i); + + // CUtils::dump(wxT("Outgoing"), m_outBuffer, 3U + text.Len() + 1U); + + return m_socket.write(m_outBuffer, 3U + text.Len() + 1U, m_address, m_port); +} + +bool CRemoteProtocolHandler::sendRandom(wxUint32 random) +{ + ::memcpy(m_outBuffer + 0U, "RND", 3U); + + wxUint32 temp = wxUINT32_SWAP_ON_BE(random); + ::memcpy(m_outBuffer + 3U, &temp, sizeof(wxUint32)); + + // CUtils::dump(wxT("Outgoing"), m_outBuffer, 3U + sizeof(wxUint32)); + + return m_socket.write(m_outBuffer, 3U + sizeof(wxUint32), m_address, m_port); +} diff --git a/Common/RemoteProtocolHandler.h b/Common/RemoteProtocolHandler.h new file mode 100644 index 0000000..5355f25 --- /dev/null +++ b/Common/RemoteProtocolHandler.h @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2011,2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef RemoteProtocolHandler_H +#define RemoteProtocolHandler_H + +#include "RemoteStarNetGroup.h" +#include "RemoteRepeaterData.h" +#include "UDPReaderWriter.h" +#include "Defs.h" + +#include + +enum RPH_TYPE { + RPHT_NONE, + RPHT_LOGIN, + RPHT_HASH, + RPHT_CALLSIGNS, + RPHT_REPEATER, + RPHT_STARNET, + RPHT_LINK, + RPHT_UNLINK, + RPHT_LINKSCR, + RPHT_LOGOFF, + RPHT_LOGOUT, + RPHT_UNKNOWN +}; + +class CRemoteProtocolHandler { +public: + CRemoteProtocolHandler(unsigned int port, const wxString& address = wxEmptyString); + ~CRemoteProtocolHandler(); + + bool open(); + + RPH_TYPE readType(); + + bool readHash(const wxString& password, wxUint32 random); + wxString readRepeater(); + wxString readStarNetGroup(); + bool readLink(wxString& callsign, RECONNECT& reconnect, wxString& reflector); + bool readUnlink(wxString& callsign, PROTOCOL& protocol, wxString& reflector); + bool readLinkScr(wxString& callsign, RECONNECT& reconnect, wxString& reflector); + bool readLogoff(wxString& callsign, wxString& user); + + bool sendACK(); + bool sendNAK(const wxString& text); + bool sendRandom(wxUint32 random); + bool sendCallsigns(const wxArrayString& repeaters, const wxArrayString& starNets); + bool sendRepeater(const CRemoteRepeaterData& data); + bool sendStarNetGroup(const CRemoteStarNetGroup& data); + + void setLoggedIn(bool set); + + void close(); + +private: + CUDPReaderWriter m_socket; + in_addr m_address; + unsigned int m_port; + bool m_loggedIn; + RPH_TYPE m_type; + unsigned char* m_inBuffer; + unsigned int m_inLength; + unsigned char* m_outBuffer; +}; + +#endif diff --git a/Common/RemoteRepeaterData.cpp b/Common/RemoteRepeaterData.cpp new file mode 100644 index 0000000..39bc714 --- /dev/null +++ b/Common/RemoteRepeaterData.cpp @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2011 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "RemoteRepeaterData.h" + +#include +WX_DEFINE_OBJARRAY(CLinkData_t); + +CRemoteRepeaterData::CRemoteRepeaterData(const wxString& callsign, RECONNECT reconnect, const wxString& reflector) : +m_callsign(callsign), +m_reconnect(reconnect), +m_reflector(reflector), +m_links() +{ +} + +CRemoteRepeaterData::~CRemoteRepeaterData() +{ + m_links.Clear(); +} + +void CRemoteRepeaterData::addLink(const wxString& callsign, PROTOCOL protocol, bool linked, DIRECTION direction, bool dongle) +{ + CRemoteLinkData data(callsign, protocol, linked, direction, dongle); + + m_links.Add(data); +} + +wxString CRemoteRepeaterData::getCallsign() const +{ + return m_callsign; +} + +wxInt32 CRemoteRepeaterData::getReconnect() const +{ + return wxInt32(m_reconnect); +} + +wxString CRemoteRepeaterData::getReflector() const +{ + return m_reflector; +} + +unsigned int CRemoteRepeaterData::getLinkCount() const +{ + return m_links.GetCount(); +} + +CRemoteLinkData& CRemoteRepeaterData::getLink(unsigned int n) const +{ + return m_links.Item(n); +} diff --git a/Common/RemoteRepeaterData.h b/Common/RemoteRepeaterData.h new file mode 100644 index 0000000..1a6ff6c --- /dev/null +++ b/Common/RemoteRepeaterData.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2011 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef RemoteRepeaterData_H +#define RemoteRepeaterData_H + +#include "RemoteLinkData.h" + +#include +#include + +WX_DECLARE_OBJARRAY(CRemoteLinkData, CLinkData_t); + +class CRemoteRepeaterData { +public: + CRemoteRepeaterData(const wxString& callsign, RECONNECT reconnect, const wxString& reflector); + ~CRemoteRepeaterData(); + + void addLink(const wxString& callsign, PROTOCOL protocol, bool linked, DIRECTION direction, bool dongle); + + wxString getCallsign() const; + wxInt32 getReconnect() const; + wxString getReflector() const; + + unsigned int getLinkCount() const; + CRemoteLinkData& getLink(unsigned int n) const; + +private: + wxString m_callsign; + RECONNECT m_reconnect; + wxString m_reflector; + CLinkData_t m_links; +}; + +#endif diff --git a/Common/RemoteStarNetGroup.cpp b/Common/RemoteStarNetGroup.cpp new file mode 100644 index 0000000..9afdd2d --- /dev/null +++ b/Common/RemoteStarNetGroup.cpp @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2011 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "RemoteStarNetGroup.h" + +#include +WX_DEFINE_OBJARRAY(CUserData_t); + +CRemoteStarNetGroup::CRemoteStarNetGroup(const wxString& callsign, const wxString& logoff, unsigned int timer, unsigned int timeout) : +m_callsign(callsign), +m_logoff(logoff), +m_timer(timer), +m_timeout(timeout), +m_users() +{ + if (m_logoff.IsSameAs(wxT(" "))) + m_logoff.Clear(); +} + +CRemoteStarNetGroup::~CRemoteStarNetGroup() +{ + m_users.Clear(); +} + +void CRemoteStarNetGroup::addUser(const wxString& callsign, unsigned int timer, unsigned int timeout) +{ + CRemoteStarNetUser user(callsign, timer, timeout); + + m_users.Add(user); +} + +wxString CRemoteStarNetGroup::getCallsign() const +{ + return m_callsign; +} + +wxString CRemoteStarNetGroup::getLogoff() const +{ + return m_logoff; +} + +wxUint32 CRemoteStarNetGroup::getTimer() const +{ + return wxUint32(m_timer); +} + +wxUint32 CRemoteStarNetGroup::getTimeout() const +{ + return wxUint32(m_timeout); +} + +unsigned int CRemoteStarNetGroup::getUserCount() const +{ + return m_users.GetCount(); +} + +CRemoteStarNetUser& CRemoteStarNetGroup::getUser(unsigned int n) const +{ + return m_users.Item(n); +} diff --git a/Common/RemoteStarNetGroup.h b/Common/RemoteStarNetGroup.h new file mode 100644 index 0000000..095d4e7 --- /dev/null +++ b/Common/RemoteStarNetGroup.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2011 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef RemoteStarNetGroup_H +#define RemoteStarNetGroup_H + +#include "RemoteStarNetUser.h" + +#include + +#include +WX_DECLARE_OBJARRAY(CRemoteStarNetUser, CUserData_t); + +class CRemoteStarNetGroup { +public: + CRemoteStarNetGroup(const wxString& callsign, const wxString& logoff, unsigned int timer, unsigned int timeout); + ~CRemoteStarNetGroup(); + + void addUser(const wxString& callsign, unsigned int timer, unsigned int timeout); + + wxString getCallsign() const; + wxString getLogoff() const; + wxUint32 getTimer() const; + wxUint32 getTimeout() const; + + unsigned int getUserCount() const; + CRemoteStarNetUser& getUser(unsigned int n) const; + +private: + wxString m_callsign; + wxString m_logoff; + unsigned int m_timer; + unsigned int m_timeout; + CUserData_t m_users; +}; + +#endif diff --git a/Common/RemoteStarNetUser.cpp b/Common/RemoteStarNetUser.cpp new file mode 100644 index 0000000..fc1f2c1 --- /dev/null +++ b/Common/RemoteStarNetUser.cpp @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2011 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "RemoteStarNetUser.h" + +CRemoteStarNetUser::CRemoteStarNetUser(const wxString& callsign, unsigned int timer, unsigned int timeout) : +m_callsign(callsign), +m_timer(timer), +m_timeout(timeout) +{ +} + +CRemoteStarNetUser::~CRemoteStarNetUser() +{ +} + +wxString CRemoteStarNetUser::getCallsign() const +{ + return m_callsign; +} + +wxUint32 CRemoteStarNetUser::getTimer() const +{ + return wxUint32(m_timer); +} + +wxUint32 CRemoteStarNetUser::getTimeout() const +{ + return wxUint32(m_timeout); +} diff --git a/Common/RemoteStarNetUser.h b/Common/RemoteStarNetUser.h new file mode 100644 index 0000000..a23256e --- /dev/null +++ b/Common/RemoteStarNetUser.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2011 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef RemoteStarNetUser_H +#define RemoteStarNetUser_H + +#include + +class CRemoteStarNetUser { +public: + CRemoteStarNetUser(const wxString& callsign, unsigned int timer, unsigned int timeout); + ~CRemoteStarNetUser(); + + wxString getCallsign() const; + wxUint32 getTimer() const; + wxUint32 getTimeout() const; + +private: + wxString m_callsign; + unsigned int m_timer; + unsigned int m_timeout; +}; + +#endif diff --git a/Common/RepeaterCache.cpp b/Common/RepeaterCache.cpp new file mode 100644 index 0000000..e24041e --- /dev/null +++ b/Common/RepeaterCache.cpp @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2010 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "RepeaterCache.h" + +const unsigned int CACHE_SIZE = 500U; + +CRepeaterCache::CRepeaterCache() : +m_cache(CACHE_SIZE) +{ +} + +CRepeaterCache::~CRepeaterCache() +{ + for (CRepeaterCache_t::iterator it = m_cache.begin(); it != m_cache.end(); ++it) + delete it->second; +} + +CRepeaterRecord* CRepeaterCache::find(const wxString& repeater) +{ + return m_cache[repeater]; +} + +void CRepeaterCache::update(const wxString& repeater, const wxString& gateway) +{ + CRepeaterRecord* rec = m_cache[repeater]; + + if (rec == NULL) + // A brand new record is needed + m_cache[repeater] = new CRepeaterRecord(repeater, gateway); + else + // Update an existing record + rec->setGateway(gateway); +} + +unsigned int CRepeaterCache::getCount() const +{ + return m_cache.size(); +} diff --git a/Common/RepeaterCache.h b/Common/RepeaterCache.h new file mode 100644 index 0000000..2fe2b54 --- /dev/null +++ b/Common/RepeaterCache.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2010 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef RepeaterCache_H +#define RepeaterCache_H + +#include +#include + +class CRepeaterRecord { +public: + CRepeaterRecord(const wxString& repeater, const wxString& gateway) : + m_repeater(repeater), + m_gateway(gateway) + { + } + + wxString getRepeater() const + { + return m_repeater; + } + + wxString getGateway() const + { + return m_gateway; + } + + void setGateway(const wxString& gateway) + { + m_gateway = gateway; + } + +private: + wxString m_repeater; + wxString m_gateway; +}; + +WX_DECLARE_STRING_HASH_MAP(CRepeaterRecord*, CRepeaterCache_t); + +class CRepeaterCache { +public: + CRepeaterCache(); + ~CRepeaterCache(); + + CRepeaterRecord* find(const wxString& repeater); + + void update(const wxString& repeater, const wxString& gateway); + + unsigned int getCount() const; + +private: + CRepeaterCache_t m_cache; +}; + +#endif diff --git a/Common/RepeaterCallback.h b/Common/RepeaterCallback.h new file mode 100644 index 0000000..fb6004c --- /dev/null +++ b/Common/RepeaterCallback.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2011,2012,2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef RepeaterCallback_H +#define RepeaterCallback_H + +#include "DStarDefines.h" +#include "HeaderData.h" +#include "AMBEData.h" +#include "Defs.h" + +#include + +class IRepeaterCallback { +public: + virtual bool process(CHeaderData& header, DIRECTION direction, AUDIO_SOURCE source) = 0; + + virtual bool process(CAMBEData& data, DIRECTION direction, AUDIO_SOURCE source) = 0; + +private: +}; + +#endif diff --git a/Common/RepeaterHandler.cpp b/Common/RepeaterHandler.cpp new file mode 100644 index 0000000..497c4c7 --- /dev/null +++ b/Common/RepeaterHandler.cpp @@ -0,0 +1,2970 @@ +/* + * Copyright (C) 2010-2015 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "RepeaterHandler.h" +#include "DExtraHandler.h" +#include "DPlusHandler.h" +#include "DStarDefines.h" +#include "DCSHandler.h" +#include "CCSHandler.h" +#include "HeaderData.h" +#include "DDHandler.h" +#include "AMBEData.h" +#include "Utils.h" + +#include + +const unsigned int ETHERNET_ADDRESS_LENGTH = 6U; + +const unsigned char ETHERNET_BROADCAST_ADDRESS[] = {0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU}; +// Multicast address '01:00:5E:00:00:01' - IP: '224.0.0.1' (to all) +const unsigned char TOALL_MULTICAST_ADDRESS[] = {0x01U, 0x00U, 0x5EU, 0x00U, 0x00U, 0x01U}; +// Multicast address '01:00:5E:00:00:23' - IP: '224.0.0.35' (DX-Cluster) +const unsigned char DX_MULTICAST_ADDRESS[] = {0x01U, 0x00U, 0x5EU, 0x00U, 0x00U, 0x23U}; + +unsigned int CRepeaterHandler::m_maxRepeaters = 0U; +CRepeaterHandler** CRepeaterHandler::m_repeaters = NULL; + +wxString CRepeaterHandler::m_localAddress; +CG2ProtocolHandler* CRepeaterHandler::m_g2Handler = NULL; +CIRCDDB* CRepeaterHandler::m_irc = NULL; +CCacheManager* CRepeaterHandler::m_cache = NULL; +wxString CRepeaterHandler::m_gateway; +TEXT_LANG CRepeaterHandler::m_language = TL_ENGLISH_UK; +bool CRepeaterHandler::m_dextraEnabled = true; +bool CRepeaterHandler::m_dplusEnabled = false; +bool CRepeaterHandler::m_dcsEnabled = true; +bool CRepeaterHandler::m_infoEnabled = true; +bool CRepeaterHandler::m_echoEnabled = true; +bool CRepeaterHandler::m_dtmfEnabled = true; + +CHeaderLogger* CRepeaterHandler::m_headerLogger = NULL; + +CAPRSWriter* CRepeaterHandler::m_aprsWriter = NULL; + +CCallsignList* CRepeaterHandler::m_restrictList = NULL; + +CRepeaterHandler::CRepeaterHandler(const wxString& callsign, const wxString& band, const wxString& address, unsigned int port, HW_TYPE hwType, const wxString& reflector, bool atStartup, RECONNECT reconnect, bool dratsEnabled, double frequency, double offset, double range, double latitude, double longitude, double agl, const wxString& description1, const wxString& description2, const wxString& url, IRepeaterProtocolHandler* handler, unsigned char band1, unsigned char band2, unsigned char band3) : +m_index(0x00U), +m_rptCallsign(), +m_gwyCallsign(), +m_band(' '), +m_address(), +m_port(port), +m_hwType(hwType), +m_repeaterHandler(handler), +m_frequency(frequency), +m_offset(offset), +m_range(range), +m_latitude(latitude), +m_longitude(longitude), +m_agl(agl), +m_description1(description1), +m_description2(description2), +m_url(url), +m_band1(band1), +m_band2(band2), +m_band3(band3), +m_repeaterId(0x00U), +m_busyId(0x00U), +m_watchdogTimer(1000U, REPEATER_TIMEOUT), +m_ddMode(false), +m_ddCallsign(), +m_queryTimer(1000U, 5U), // 5 seconds +m_myCall1(), +m_myCall2(), +m_yourCall(), +m_rptCall1(), +m_rptCall2(), +m_flag1(0x00U), +m_flag2(0x00U), +m_flag3(0x00U), +m_restricted(false), +m_frames(0U), +m_silence(0U), +m_errors(0U), +m_textCollector(), +m_text(), +m_xBandRptr(NULL), +m_starNet(NULL), +m_g2Status(G2_NONE), +m_g2User(), +m_g2Repeater(), +m_g2Gateway(), +m_g2Header(NULL), +m_g2Address(), +m_linkStatus(LS_NONE), +m_linkRepeater(), +m_linkGateway(), +m_linkReconnect(reconnect), +m_linkAtStartup(atStartup), +m_linkStartup(reflector), +m_linkReconnectTimer(1000U), +m_linkRelink(false), +m_echo(NULL), +m_infoAudio(NULL), +m_infoNeeded(false), +m_msgAudio(NULL), +m_msgNeeded(false), +m_wxAudio(NULL), +m_wxNeeded(false), +m_version(NULL), +m_drats(NULL), +m_dtmf(), +m_pollTimer(1000U, 900U), // 15 minutes +m_ccsHandler(NULL), +m_lastReflector(), +m_heardUser(), +m_heardRepeater(), +m_heardTimer(1000U, 0U, 100U) // 100ms +{ + wxASSERT(!callsign.IsEmpty()); + wxASSERT(port > 0U); + wxASSERT(handler != NULL); + + m_ddMode = band.Len() > 1U; + + m_band = band.GetChar(0U); + + m_rptCallsign = callsign; + m_rptCallsign.Append(wxT(" ")); + m_rptCallsign.Truncate(LONG_CALLSIGN_LENGTH - 1U); + m_rptCallsign.Append(band); + m_rptCallsign.Truncate(LONG_CALLSIGN_LENGTH); + + m_gwyCallsign = callsign; + m_gwyCallsign.Append(wxT(" ")); + m_gwyCallsign.Truncate(LONG_CALLSIGN_LENGTH - 1U); + m_gwyCallsign.Append(wxT("G")); + + m_address.s_addr = ::inet_addr(address.mb_str()); + + m_pollTimer.start(); + + switch (m_linkReconnect) { + case RECONNECT_5MINS: + m_linkReconnectTimer.start(5U * 60U); + break; + case RECONNECT_10MINS: + m_linkReconnectTimer.start(10U * 60U); + break; + case RECONNECT_15MINS: + m_linkReconnectTimer.start(15U * 60U); + break; + case RECONNECT_20MINS: + m_linkReconnectTimer.start(20U * 60U); + break; + case RECONNECT_25MINS: + m_linkReconnectTimer.start(25U * 60U); + break; + case RECONNECT_30MINS: + m_linkReconnectTimer.start(30U * 60U); + break; + case RECONNECT_60MINS: + m_linkReconnectTimer.start(60U * 60U); + break; + case RECONNECT_90MINS: + m_linkReconnectTimer.start(90U * 60U); + break; + case RECONNECT_120MINS: + m_linkReconnectTimer.start(120U * 60U); + break; + case RECONNECT_180MINS: + m_linkReconnectTimer.start(180U * 60U); + break; + default: + break; + } + + wxFileName messageFile; + messageFile.SetPath(::wxGetHomeDir()); + messageFile.SetName(wxT("message")); + messageFile.SetExt(wxT("dvtool")); + + wxFileName weatherFile; + weatherFile.SetPath(::wxGetHomeDir()); + weatherFile.SetName(wxT("weather")); + weatherFile.SetExt(wxT("dvtool")); + + m_echo = new CEchoUnit(this, callsign); + m_infoAudio = new CAudioUnit(this, callsign); + m_msgAudio = new CAnnouncementUnit(this, callsign, messageFile.GetFullPath(), wxT("MSG")); + m_wxAudio = new CAnnouncementUnit(this, callsign, weatherFile.GetFullPath(), wxT("WX")); + m_version = new CVersionUnit(this, callsign); + + if (dratsEnabled) { + m_drats = new CDRATSServer(m_localAddress, port, callsign, this); + bool ret = m_drats->open(); + if (!ret) { + delete m_drats; + m_drats = NULL; + } + } +} + +CRepeaterHandler::~CRepeaterHandler() +{ + delete m_echo; + delete m_infoAudio; + delete m_msgAudio; + delete m_wxAudio; + delete m_version; + + if (m_drats != NULL) + m_drats->close(); +} + +void CRepeaterHandler::initialise(unsigned int maxRepeaters) +{ + wxASSERT(maxRepeaters > 0U); + + m_maxRepeaters = maxRepeaters; + + m_repeaters = new CRepeaterHandler*[m_maxRepeaters]; + for (unsigned int i = 0U; i < m_maxRepeaters; i++) + m_repeaters[i] = NULL; +} + +void CRepeaterHandler::setIndex(unsigned int index) +{ + m_index = index; +} + +void CRepeaterHandler::add(const wxString& callsign, const wxString& band, const wxString& address, unsigned int port, HW_TYPE hwType, const wxString& reflector, bool atStartup, RECONNECT reconnect, bool dratsEnabled, double frequency, double offset, double range, double latitude, double longitude, double agl, const wxString& description1, const wxString& description2, const wxString& url, IRepeaterProtocolHandler* handler, unsigned char band1, unsigned char band2, unsigned char band3) +{ + wxASSERT(!callsign.IsEmpty()); + wxASSERT(port > 0U); + wxASSERT(handler != NULL); + + CRepeaterHandler* repeater = new CRepeaterHandler(callsign, band, address, port, hwType, reflector, atStartup, reconnect, dratsEnabled, frequency, offset, range, latitude, longitude, agl, description1, description2, url, handler, band1, band2, band3); + + for (unsigned int i = 0U; i < m_maxRepeaters; i++) { + if (m_repeaters[i] == NULL) { + repeater->setIndex(i); + m_repeaters[i] = repeater; + return; + } + } + + wxLogError(wxT("Cannot add repeater with callsign %s, no space"), callsign.c_str()); + + delete repeater; +} + +void CRepeaterHandler::setG2Handler(CG2ProtocolHandler* handler) +{ + wxASSERT(handler != NULL); + + m_g2Handler = handler; +} + +void CRepeaterHandler::setCache(CCacheManager* cache) +{ + wxASSERT(cache != NULL); + + m_cache = cache; +} + +void CRepeaterHandler::setIRC(CIRCDDB* irc) +{ + wxASSERT(irc != NULL); + + m_irc = irc; +} + +void CRepeaterHandler::setGateway(const wxString& gateway) +{ + m_gateway = gateway; +} + +void CRepeaterHandler::setLanguage(TEXT_LANG language) +{ + m_language = language; +} + +void CRepeaterHandler::setDExtraEnabled(bool enabled) +{ + m_dextraEnabled = enabled; +} + +void CRepeaterHandler::setDPlusEnabled(bool enabled) +{ + m_dplusEnabled = enabled; +} + +void CRepeaterHandler::setDCSEnabled(bool enabled) +{ + m_dcsEnabled = enabled; +} + +void CRepeaterHandler::setInfoEnabled(bool enabled) +{ + m_infoEnabled = enabled; +} + +void CRepeaterHandler::setEchoEnabled(bool enabled) +{ + m_echoEnabled = enabled; +} + +void CRepeaterHandler::setDTMFEnabled(bool enabled) +{ + m_dtmfEnabled = enabled; +} + +void CRepeaterHandler::setHeaderLogger(CHeaderLogger* logger) +{ + m_headerLogger = logger; +} + +void CRepeaterHandler::setAPRSWriter(CAPRSWriter* writer) +{ + m_aprsWriter = writer; +} + +void CRepeaterHandler::setLocalAddress(const wxString& address) +{ + m_localAddress = address; +} + +void CRepeaterHandler::setRestrictList(CCallsignList* list) +{ + wxASSERT(list != NULL); + + m_restrictList = list; +} + +bool CRepeaterHandler::getRepeater(unsigned int n, wxString& callsign, LINK_STATUS& linkStatus, wxString& linkCallsign) +{ + if (n >= m_maxRepeaters) + return false; + + if (m_repeaters[n] == NULL) + return false; + + callsign = m_repeaters[n]->m_rptCallsign; + linkStatus = m_repeaters[n]->m_linkStatus; + linkCallsign = m_repeaters[n]->m_linkRepeater; + + return true; +} + +void CRepeaterHandler::resolveUser(const wxString &user, const wxString& repeater, const wxString& gateway, const wxString &address) +{ + for (unsigned int i = 0U; i < m_maxRepeaters; i++) { + if (m_repeaters[i] != NULL) + m_repeaters[i]->resolveUserInt(user, repeater, gateway, address); + } +} + +void CRepeaterHandler::resolveRepeater(const wxString& repeater, const wxString& gateway, const wxString &address, DSTAR_PROTOCOL protocol) +{ + for (unsigned int i = 0U; i < m_maxRepeaters; i++) { + if (m_repeaters[i] != NULL) + m_repeaters[i]->resolveRepeaterInt(repeater, gateway, address, protocol); + } +} + +void CRepeaterHandler::startup() +{ + for (unsigned int i = 0U; i < m_maxRepeaters; i++) { + if (m_repeaters[i] != NULL) + m_repeaters[i]->startupInt(); + } +} + +void CRepeaterHandler::clock(unsigned int ms) +{ + for (unsigned int i = 0U; i < m_maxRepeaters; i++) { + if (m_repeaters[i] != NULL) + m_repeaters[i]->clockInt(ms); + } +} + +void CRepeaterHandler::finalise() +{ + for (unsigned int i = 0U; i < m_maxRepeaters; i++) { + delete m_repeaters[i]; + m_repeaters[i] = NULL; + } + + if (m_aprsWriter != NULL) { + m_aprsWriter->close(); + delete m_aprsWriter; + } + + delete[] m_repeaters; +} + +CRepeaterHandler* CRepeaterHandler::findDVRepeater(const CHeaderData& header) +{ + wxString rpt1 = header.getRptCall1(); + in_addr address = header.getYourAddress(); + + for (unsigned int i = 0U; i < m_maxRepeaters; i++) { + CRepeaterHandler* repeater = m_repeaters[i]; + if (repeater != NULL) { + if (!repeater->m_ddMode && repeater->m_address.s_addr == address.s_addr && repeater->m_rptCallsign.IsSameAs(rpt1)) + return repeater; + } + } + + return NULL; +} + +CRepeaterHandler* CRepeaterHandler::findDVRepeater(const CAMBEData& data, bool busy) +{ + unsigned int id = data.getId(); + + for (unsigned int i = 0U; i < m_maxRepeaters; i++) { + CRepeaterHandler* repeater = m_repeaters[i]; + if (repeater != NULL) { + if (!busy && !repeater->m_ddMode && repeater->m_repeaterId == id) + return repeater; + if (busy && !repeater->m_ddMode && repeater->m_busyId == id) + return repeater; + } + } + + return NULL; +} + +CRepeaterHandler* CRepeaterHandler::findDVRepeater(const wxString& callsign) +{ + for (unsigned int i = 0U; i < m_maxRepeaters; i++) { + CRepeaterHandler* repeater = m_repeaters[i]; + if (repeater != NULL) { + if (!repeater->m_ddMode && repeater->m_rptCallsign.IsSameAs(callsign)) + return repeater; + } + } + + return NULL; +} + +CRepeaterHandler* CRepeaterHandler::findRepeater(const CPollData& data) +{ + in_addr address = data.getYourAddress(); + unsigned int port = data.getYourPort(); + + for (unsigned int i = 0U; i < m_maxRepeaters; i++) { + CRepeaterHandler* repeater = m_repeaters[i]; + if (repeater != NULL) { + if (repeater->m_address.s_addr == address.s_addr && repeater->m_port == port) + return repeater; + } + } + + return NULL; +} + +CRepeaterHandler* CRepeaterHandler::findDDRepeater(const CDDData& data) +{ + wxString rpt1 = data.getRptCall1(); + + for (unsigned int i = 0U; i < m_maxRepeaters; i++) { + CRepeaterHandler* repeater = m_repeaters[i]; + if (repeater != NULL) { + if (repeater->m_ddMode && repeater->m_rptCallsign.IsSameAs(rpt1)) + return repeater; + } + } + + return NULL; +} + +CRepeaterHandler* CRepeaterHandler::findDDRepeater() +{ + for (unsigned int i = 0U; i < m_maxRepeaters; i++) { + CRepeaterHandler* repeater = m_repeaters[i]; + if (repeater != NULL) { + if (repeater->m_ddMode) + return repeater; + } + } + + return NULL; +} + +wxArrayString CRepeaterHandler::listDVRepeaters() +{ + wxArrayString repeaters; + + for (unsigned int i = 0U; i < m_maxRepeaters; i++) { + CRepeaterHandler* repeater = m_repeaters[i]; + if (repeater != NULL && !repeater->m_ddMode) + repeaters.Add(repeater->m_rptCallsign); + } + + return repeaters; +} + +void CRepeaterHandler::pollAllIcom(CPollData& data) +{ + for (unsigned int i = 0U; i < m_maxRepeaters; i++) { + CRepeaterHandler* repeater = m_repeaters[i]; + if (repeater != NULL && repeater->m_hwType == HW_ICOM) + repeater->processRepeater(data); + } +} + +CRemoteRepeaterData* CRepeaterHandler::getInfo() const +{ + return new CRemoteRepeaterData(m_rptCallsign, m_linkReconnect, m_linkStartup); +} + +void CRepeaterHandler::processRepeater(CHeaderData& header) +{ + unsigned int id = header.getId(); + + // Stop duplicate headers + if (id == m_repeaterId) + return; + + // Save the header fields + m_myCall1 = header.getMyCall1(); + m_myCall2 = header.getMyCall2(); + m_yourCall = header.getYourCall(); + m_rptCall1 = header.getRptCall1(); + m_rptCall2 = header.getRptCall2(); + m_flag1 = header.getFlag1(); + m_flag2 = header.getFlag2(); + m_flag3 = header.getFlag3(); + + if (m_hwType == HW_ICOM) { + unsigned char band1 = header.getBand1(); + unsigned char band2 = header.getBand2(); + unsigned char band3 = header.getBand3(); + + if (m_band1 != band1 || m_band2 != band2 || m_band3 != band3) { + m_band1 = band1; + m_band2 = band2; + m_band3 = band3; + wxLogMessage(wxT("Repeater %s registered with bands %u %u %u"), m_rptCall1.c_str(), m_band1, m_band2, m_band3); + } + } + + if (m_flag1 == 0x01) { + wxLogMessage(wxT("Received a busy message from repeater %s"), m_rptCall1.c_str()); + return; + } + + if (!m_heardUser.IsEmpty() && !m_myCall1.IsSameAs(m_heardUser) && m_irc != NULL) + m_irc->sendHeard(m_heardUser, wxT(" "), wxT(" "), m_heardRepeater, wxT(" "), 0x00U, 0x00U, 0x00U); + + // Inform CCS + m_ccsHandler->writeHeard(header); + m_ccsHandler->writeHeader(header); + + // The Icom heard timer + m_heardTimer.stop(); + + if (m_drats != NULL) + m_drats->writeHeader(header); + + // Reset the statistics + m_frames = 0U; + m_silence = 0U; + m_errors = 0U; + + // An RF header resets the reconnect timer + m_linkReconnectTimer.start(); + + // Incoming links get everything + sendToIncoming(header); + + // Reset the slow data text collector + m_textCollector.reset(); + m_text.Clear(); + + // Reset the APRS Writer if it's enabled + if (m_aprsWriter != NULL) + m_aprsWriter->reset(m_rptCallsign); + + // Write to Header.log if it's enabled + if (m_headerLogger != NULL) + m_headerLogger->write(wxT("Repeater"), header); + + // Reset the DTMF decoder + m_dtmf.reset(); + + // Reset the info, echo and version commands if they're running + m_infoAudio->cancel(); + m_msgAudio->cancel(); + m_wxAudio->cancel(); + m_echo->cancel(); + m_version->cancel(); + + // A new header resets fields and G2 routing status + m_repeaterId = id; + m_busyId = 0x00U; + m_watchdogTimer.start(); + + m_xBandRptr = NULL; + m_starNet = NULL; + + // If we're querying for a user or repeater, kill the query timer + if (m_g2Status == G2_USER || m_g2Status == G2_REPEATER) + m_queryTimer.stop(); + + delete m_g2Header; + m_g2Header = NULL; + m_g2Status = G2_NONE; + m_g2User.Clear(); + m_g2Repeater.Clear(); + m_g2Gateway.Clear(); + + // Check if this user is restricted + m_restricted = false; + if (m_restrictList != NULL) { + bool res = m_restrictList->isInList(m_myCall1); + if (res) + m_restricted = true; + } + + // Reject silly RPT2 values + if (m_rptCall2.IsSameAs(m_rptCallsign) || m_rptCall2.IsSameAs(wxT(" "))) + return; + + // Do cross-band routing if RPT2 is not one of the gateway callsigns + if (!m_rptCall2.IsSameAs(m_gwyCallsign) && !m_rptCall2.IsSameAs(m_gateway)) { + CRepeaterHandler* repeater = findDVRepeater(m_rptCall2); + if (repeater != NULL) { + wxLogMessage(wxT("Cross-band routing by %s from %s to %s"), m_myCall1.c_str(), m_rptCallsign.c_str(), m_rptCall2.c_str()); + m_xBandRptr = repeater; + m_xBandRptr->process(header, DIR_INCOMING, AS_XBAND); + m_g2Status = G2_XBAND; + } else { + // Keep the transmission local + wxLogMessage(wxT("Invalid cross-band route by %s from %s to %s"), m_myCall1.c_str(), m_rptCallsign.c_str(), m_rptCall2.c_str()); + m_g2Status = G2_LOCAL; + } + return; + } + + m_starNet = CStarNetHandler::findStarNet(header); + if (m_starNet != NULL && !m_restricted) { + wxLogMessage(wxT("StarNet routing by %s to %s"), m_myCall1.c_str(), m_yourCall.c_str()); + m_starNet->process(header); + m_g2Status = G2_STARNET; + return; + } + + // Reject simple cases + if (m_yourCall.Left(4).IsSameAs(wxT("CQCQ"))) { + sendToOutgoing(header); + return; + } + + // Handle the Echo command + if (m_echoEnabled && m_yourCall.IsSameAs(wxT(" E"))) { + m_g2Status = G2_ECHO; + m_echo->writeHeader(header); + return; + } + + // Handle the Info command + if (m_infoEnabled && m_yourCall.IsSameAs(wxT(" I"))) { + m_g2Status = G2_LOCAL; + m_infoNeeded = true; + return; + } + + // Handle the MSG command + if (m_infoEnabled && m_yourCall.IsSameAs(wxT(" M"))) { + m_g2Status = G2_LOCAL; + m_msgNeeded = true; + return; + } + + // Handle the WX command + if (m_infoEnabled && m_yourCall.IsSameAs(wxT(" W"))) { + m_g2Status = G2_LOCAL; + m_wxNeeded = true; + return; + } + + // Handle the Version command + if (m_infoEnabled && m_yourCall.IsSameAs(wxT(" V"))) { + m_g2Status = G2_VERSION; + sendToOutgoing(header); + return; + } + + if (m_restricted) { + sendToOutgoing(header); + return; + } + + if (isCCSCommand(m_yourCall)) { + ccsCommandHandler(m_yourCall, m_myCall1, wxT("UR Call")); + sendToOutgoing(header); + } else { + g2CommandHandler(m_yourCall, m_myCall1, header); + + if (m_g2Status == G2_NONE) { + reflectorCommandHandler(m_yourCall, m_myCall1, wxT("UR Call")); + sendToOutgoing(header); + } + } +} + +void CRepeaterHandler::processRepeater(CAMBEData& data) +{ + // AMBE data via RF resets the reconnect timer + m_linkReconnectTimer.start(); + m_watchdogTimer.start(); + + m_frames++; + m_errors += data.getErrors(); + + unsigned char buffer[DV_FRAME_MAX_LENGTH_BYTES]; + data.getData(buffer, DV_FRAME_MAX_LENGTH_BYTES); + + if (::memcmp(buffer, NULL_AMBE_DATA_BYTES, VOICE_FRAME_LENGTH_BYTES) == 0) + m_silence++; + + // Don't do DTMF decoding or blanking if off and not on crossband either + if (m_dtmfEnabled && m_g2Status != G2_XBAND) { + bool pressed = m_dtmf.decode(buffer, data.isEnd()); + if (pressed) { + // Replace the DTMF with silence + ::memcpy(buffer, NULL_AMBE_DATA_BYTES, VOICE_FRAME_LENGTH_BYTES); + data.setData(buffer, DV_FRAME_LENGTH_BYTES); + } + + bool dtmfDone = m_dtmf.hasCommand(); + if (dtmfDone) { + wxString command = m_dtmf.translate(); + + // Only process the DTMF command if the your call is CQCQCQ and not a restricted user + if (!m_restricted && m_yourCall.Left(4U).IsSameAs(wxT("CQCQ"))) { + if (command.IsEmpty()) { + // Do nothing + } else if (isCCSCommand(command)) { + ccsCommandHandler(command, m_myCall1, wxT("DTMF")); + } else if (command.IsSameAs(wxT(" I"))) { + m_infoNeeded = true; + } else { + reflectorCommandHandler(command, m_myCall1, wxT("DTMF")); + } + } + } + } + + // Incoming links get everything + sendToIncoming(data); + + // CCS gets everything + m_ccsHandler->writeAMBE(data); + + if (m_drats != NULL) + m_drats->writeData(data); + + if (m_aprsWriter != NULL) + m_aprsWriter->writeData(m_rptCallsign, data); + + if (m_text.IsEmpty() && !data.isEnd()) { + m_textCollector.writeData(data); + + bool hasText = m_textCollector.hasData(); + if (hasText) { + m_text = m_textCollector.getData(); + sendHeard(m_text); + } + } + + data.setText(m_text); + + // If no slow data text has been received, send a heard with no text when the end of the + // transmission arrives + if (data.isEnd() && m_text.IsEmpty()) + sendHeard(); + + // Send the statistics after the end of the data, any stats from the repeater should have + // been received by now + if (data.isEnd()) { + m_watchdogTimer.stop(); + sendStats(); + } + + switch (m_g2Status) { + case G2_LOCAL: + if (data.isEnd()) { + m_repeaterId = 0x00U; + m_g2Status = G2_NONE; + } + break; + + case G2_OK: + data.setDestination(m_g2Address, G2_DV_PORT); + m_g2Handler->writeAMBE(data); + + if (data.isEnd()) { + m_repeaterId = 0x00U; + m_g2Status = G2_NONE; + } + break; + + case G2_USER: + case G2_REPEATER: + // Data ended before the callsign could be resolved + if (data.isEnd()) { + m_queryTimer.stop(); + delete m_g2Header; + m_repeaterId = 0x0U; + m_g2Status = G2_NONE; + m_g2Header = NULL; + } + break; + + case G2_NONE: + if (data.isEnd()) + m_repeaterId = 0x00U; + + sendToOutgoing(data); + break; + + case G2_XBAND: + m_xBandRptr->process(data, DIR_INCOMING, AS_XBAND); + + if (data.isEnd()) { + m_repeaterId = 0x00U; + m_g2Status = G2_NONE; + m_xBandRptr = NULL; + } + break; + + case G2_STARNET: + m_starNet->process(data); + + if (data.isEnd()) { + m_repeaterId = 0x00U; + m_g2Status = G2_NONE; + m_starNet = NULL; + } + break; + + case G2_ECHO: + m_echo->writeData(data); + + if (data.isEnd()) { + m_repeaterId = 0x00U; + m_g2Status = G2_NONE; + } + break; + + case G2_VERSION: + sendToOutgoing(data); + + if (data.isEnd()) { + m_version->sendVersion(); + + m_repeaterId = 0x00U; + m_g2Status = G2_NONE; + } + break; + } + + if (data.isEnd() && m_infoNeeded) { + m_infoAudio->sendStatus(); + m_infoNeeded = false; + } + + if (data.isEnd() && m_msgNeeded) { + m_msgAudio->sendAnnouncement(); + m_msgNeeded = false; + } + + if (data.isEnd() && m_wxNeeded) { + m_wxAudio->sendAnnouncement(); + m_wxNeeded = false; + } +} + +// Incoming headers when relaying network traffic, as detected by the repeater, will be used as a command +// to the reflector command handler, probably to do an unlink. +void CRepeaterHandler::processBusy(CHeaderData& header) +{ + unsigned int id = header.getId(); + + // Ignore duplicate headers + if (id == m_busyId) + return; + + wxString rptCall1 = header.getRptCall1(); + wxString rptCall2 = header.getRptCall2(); + + if (m_hwType == HW_ICOM) { + unsigned char band1 = header.getBand1(); + unsigned char band2 = header.getBand2(); + unsigned char band3 = header.getBand3(); + + if (m_band1 != band1 || m_band2 != band2 || m_band3 != band3) { + m_band1 = band1; + m_band2 = band2; + m_band3 = band3; + wxLogMessage(wxT("Repeater %s registered with bands %u %u %u"), rptCall1.c_str(), m_band1, m_band2, m_band3); + } + } + + if (header.getFlag1() == 0x01) { + wxLogMessage(wxT("Received a busy message from repeater %s"), rptCall1.c_str()); + return; + } + + // Reject the header if the RPT2 value is not one of the gateway callsigns + if (!rptCall2.IsSameAs(m_gwyCallsign) && !rptCall2.IsSameAs(m_gateway)) + return; + + m_myCall1 = header.getMyCall1(); + m_yourCall = header.getYourCall(); + m_rptCall1 = rptCall1; + m_rptCall2 = rptCall2; + + m_dtmf.reset(); + + m_busyId = id; + m_repeaterId = 0x00U; + m_watchdogTimer.start(); + + // If restricted then don't send to the command handler + m_restricted = false; + if (m_restrictList != NULL) { + bool res = m_restrictList->isInList(m_myCall1); + if (res) { + m_restricted = true; + return; + } + } + + // Reject simple cases + if (m_yourCall.Left(4).IsSameAs(wxT("CQCQ")) || m_yourCall.IsSameAs(wxT(" E")) || m_yourCall.IsSameAs(wxT(" I"))) + return; + + if (isCCSCommand(m_yourCall)) + ccsCommandHandler(m_yourCall, m_myCall1, wxT("background UR Call")); + else + reflectorCommandHandler(m_yourCall, m_myCall1, wxT("background UR Call")); +} + +void CRepeaterHandler::processBusy(CAMBEData& data) +{ + m_watchdogTimer.start(); + + unsigned char buffer[DV_FRAME_MAX_LENGTH_BYTES]; + data.getData(buffer, DV_FRAME_MAX_LENGTH_BYTES); + + // Don't do DTMF decoding if off + if (m_dtmfEnabled) { + m_dtmf.decode(buffer, data.isEnd()); + + bool dtmfDone = m_dtmf.hasCommand(); + if (dtmfDone) { + wxString command = m_dtmf.translate(); + + // Only process the DTMF command if the your call is CQCQCQ and the user isn't restricted + if (!m_restricted && m_yourCall.Left(4U).IsSameAs(wxT("CQCQ"))) { + if (command.IsEmpty()) { + // Do nothing + } else if (isCCSCommand(command)) { + ccsCommandHandler(command, m_myCall1, wxT("background DTMF")); + } else if (command.IsSameAs(wxT(" I"))) { + // Do nothing + } else { + reflectorCommandHandler(command, m_myCall1, wxT("background DTMF")); + } + } + } + } + + if (data.isEnd()) { + if (m_infoNeeded) { + m_infoAudio->sendStatus(); + m_infoNeeded = false; + } + + if (m_msgNeeded) { + m_msgAudio->sendAnnouncement(); + m_msgNeeded = false; + } + + if (m_wxNeeded) { + m_wxAudio->sendAnnouncement(); + m_wxNeeded = false; + } + + if (m_g2Status == G2_VERSION) + m_version->sendVersion(); + + m_g2Status = G2_NONE; + m_busyId = 0x00U; + m_watchdogTimer.stop(); + } +} + +void CRepeaterHandler::processRepeater(CHeardData& heard) +{ + if (m_irc == NULL) + return; + + // A second heard has come in before the original has been sent or cancelled + if (m_heardTimer.isRunning() && !m_heardTimer.hasExpired()) + m_irc->sendHeard(m_heardUser, wxT(" "), wxT(" "), m_heardRepeater, wxT(" "), 0x00U, 0x00U, 0x00U); + + m_heardUser = heard.getUser(); + m_heardRepeater = heard.getRepeater(); + + m_heardTimer.start(); +} + +void CRepeaterHandler::processRepeater(CPollData& data) +{ + if (!m_pollTimer.hasExpired()) + return; + + if (m_irc == NULL) + return; + + wxString callsign = m_rptCallsign; + if (m_ddMode) + callsign.Append(wxT("D")); + + wxString text = data.getData1(); + + m_irc->kickWatchdog(callsign, text); + + m_pollTimer.start(); +} + +void CRepeaterHandler::processRepeater(CDDData& data) +{ + if (!m_ddMode) + return; + + if (m_ddCallsign.IsEmpty()) { + m_ddCallsign = data.getYourCall(); + wxLogMessage(wxT("Added DD callsign %s"), m_ddCallsign.c_str()); + } + + CDDHandler::process(data); +} + +bool CRepeaterHandler::process(CDDData& data) +{ + unsigned char* address = data.getDestinationAddress(); + if (::memcmp(address, ETHERNET_BROADCAST_ADDRESS, ETHERNET_ADDRESS_LENGTH) == 0) + data.setRepeaters(m_gwyCallsign, wxT(" ")); + else if (::memcmp(address, TOALL_MULTICAST_ADDRESS, ETHERNET_ADDRESS_LENGTH) == 0) + data.setRepeaters(m_gwyCallsign, m_rptCallsign); + else if (::memcmp(address, DX_MULTICAST_ADDRESS, ETHERNET_ADDRESS_LENGTH) == 0) + data.setRepeaters(m_gwyCallsign, m_rptCallsign); + else + data.setRepeaters(m_gwyCallsign, m_rptCallsign); + + data.setDestination(m_address, m_port); + data.setFlags(0xC0U, 0x00U, 0x00U); + data.setMyCall1(m_ddCallsign); + data.setMyCall2(wxT(" ")); + + m_repeaterHandler->writeDD(data); + + return true; +} + +bool CRepeaterHandler::process(CHeaderData& header, DIRECTION, AUDIO_SOURCE source) +{ + // If data is coming from the repeater then don't send + if (m_repeaterId != 0x00U) + return false; + + // Rewrite the ID if we're using Icom hardware + if (m_hwType == HW_ICOM) { + unsigned int id1 = header.getId(); + unsigned int id2 = id1 + m_index; + header.setId(id2); + } + + // Send all original headers to all repeater types, and only send duplicate headers to homebrew repeaters + if (source != AS_DUP || (source == AS_DUP && m_hwType == HW_HOMEBREW)) { + header.setBand1(m_band1); + header.setBand2(m_band2); + header.setBand3(m_band3); + header.setDestination(m_address, m_port); + header.setRepeaters(m_gwyCallsign, m_rptCallsign); + + m_repeaterHandler->writeHeader(header); + } + + // Don't send duplicate headers to anyone else + if (source == AS_DUP) + return true; + + sendToIncoming(header); + + if (source == AS_DPLUS || source == AS_DEXTRA || source == AS_DCS) + m_ccsHandler->writeHeader(header); + + if (source == AS_G2 || source == AS_INFO || source == AS_VERSION || source == AS_XBAND || source == AS_ECHO) + return true; + + // Reset the slow data text collector, used for DCS text passing + m_textCollector.reset(); + m_text.Clear(); + + sendToOutgoing(header); + + return true; +} + +bool CRepeaterHandler::process(CAMBEData& data, DIRECTION, AUDIO_SOURCE source) +{ + // If data is coming from the repeater then don't send + if (m_repeaterId != 0x00U) + return false; + + // Rewrite the ID if we're using Icom hardware + if (m_hwType == HW_ICOM) { + unsigned int id = data.getId(); + id += m_index; + data.setId(id); + } + + data.setBand1(m_band1); + data.setBand2(m_band2); + data.setBand3(m_band3); + data.setDestination(m_address, m_port); + + m_repeaterHandler->writeAMBE(data); + + sendToIncoming(data); + + if (source == AS_DPLUS || source == AS_DEXTRA || source == AS_DCS) + m_ccsHandler->writeAMBE(data); + + if (source == AS_G2 || source == AS_INFO || source == AS_VERSION || source == AS_XBAND || source == AS_ECHO) + return true; + + // Collect the text from the slow data for DCS + if (m_text.IsEmpty() && !data.isEnd()) { + m_textCollector.writeData(data); + + bool hasText = m_textCollector.hasData(); + if (hasText) + m_text = m_textCollector.getData(); + } + + data.setText(m_text); + + sendToOutgoing(data); + + return true; +} + +void CRepeaterHandler::resolveUserInt(const wxString& user, const wxString& repeater, const wxString& gateway, const wxString &address) +{ + if (m_g2Status == G2_USER && m_g2User.IsSameAs(user)) { + m_queryTimer.stop(); + + if (!address.IsEmpty()) { + // No point routing to self + if (repeater.IsSameAs(m_rptCallsign)) { + m_g2Status = G2_LOCAL; + delete m_g2Header; + m_g2Header = NULL; + return; + } + + // User found, update the settings and send the header to the correct place + m_g2Address.s_addr = ::inet_addr(address.mb_str()); + + m_g2Repeater = repeater; + m_g2Gateway = gateway; + + m_g2Header->setDestination(m_g2Address, G2_DV_PORT); + m_g2Header->setRepeaters(m_g2Gateway, m_g2Repeater); + m_g2Handler->writeHeader(*m_g2Header); + + delete m_g2Header; + m_g2Status = G2_OK; + m_g2Header = NULL; + } else { + // User not found, remove G2 settings + m_g2Status = G2_LOCAL; + m_g2User.Clear(); + m_g2Repeater.Clear(); + m_g2Gateway.Clear(); + + delete m_g2Header; + m_g2Header = NULL; + } + } +} + +void CRepeaterHandler::resolveRepeaterInt(const wxString& repeater, const wxString& gateway, const wxString &address, DSTAR_PROTOCOL protocol) +{ + if (m_g2Status == G2_REPEATER && m_g2Repeater.IsSameAs(repeater)) { + m_queryTimer.stop(); + + if (!address.IsEmpty()) { + // Repeater found, update the settings and send the header to the correct place + m_g2Address.s_addr = ::inet_addr(address.mb_str()); + + m_g2Repeater = repeater; + m_g2Gateway = gateway; + + m_g2Header->setDestination(m_g2Address, G2_DV_PORT); + m_g2Header->setRepeaters(m_g2Gateway, m_g2Repeater); + m_g2Handler->writeHeader(*m_g2Header); + + delete m_g2Header; + m_g2Status = G2_OK; + m_g2Header = NULL; + } else { + // Repeater not found, remove G2 settings + m_g2Status = G2_LOCAL; + m_g2User.Clear(); + m_g2Repeater.Clear(); + m_g2Gateway.Clear(); + + delete m_g2Header; + m_g2Header = NULL; + } + } + + if (m_linkStatus == LS_PENDING_IRCDDB && m_linkRepeater.IsSameAs(repeater)) { + m_queryTimer.stop(); + + if (!address.IsEmpty()) { + // Repeater found + in_addr addr; + switch (protocol) { + case DP_DPLUS: + if (m_dplusEnabled) { + m_linkGateway = gateway; + addr.s_addr = ::inet_addr(address.mb_str()); + CDPlusHandler::link(this, m_rptCallsign, m_linkRepeater, addr); + m_linkStatus = LS_LINKING_DPLUS; + } else { + wxLogMessage(wxT("Require D-Plus for linking to %s, but D-Plus is disabled"), repeater.c_str()); + m_linkStatus = LS_NONE; + m_linkRepeater.Clear(); + m_linkGateway.Clear(); + writeNotLinked(); + triggerInfo(); + } + break; + + case DP_DCS: + if (m_dcsEnabled) { + m_linkGateway = gateway; + addr.s_addr = ::inet_addr(address.mb_str()); + CDCSHandler::link(this, m_rptCallsign, m_linkRepeater, addr); + m_linkStatus = LS_LINKING_DCS; + } else { + wxLogMessage(wxT("Require DCS for linking to %s, but DCS is disabled"), repeater.c_str()); + m_linkStatus = LS_NONE; + m_linkRepeater.Clear(); + m_linkGateway.Clear(); + writeNotLinked(); + triggerInfo(); + } + break; + + case DP_LOOPBACK: + m_linkGateway = gateway; + addr.s_addr = ::inet_addr(address.mb_str()); + CDCSHandler::link(this, m_rptCallsign, m_linkRepeater, addr); + m_linkStatus = LS_LINKING_LOOPBACK; + break; + + default: + if (m_dextraEnabled) { + m_linkGateway = gateway; + addr.s_addr = ::inet_addr(address.mb_str()); + CDExtraHandler::link(this, m_rptCallsign, m_linkRepeater, addr); + m_linkStatus = LS_LINKING_DEXTRA; + } else { + wxLogMessage(wxT("Require DExtra for linking to %s, but DExtra is disabled"), repeater.c_str()); + m_linkStatus = LS_NONE; + m_linkRepeater.Clear(); + m_linkGateway.Clear(); + writeNotLinked(); + triggerInfo(); + } + break; + + } + } else { + // Repeater not found + m_linkStatus = LS_NONE; + m_linkRepeater.Clear(); + m_linkGateway.Clear(); + + writeNotLinked(); + triggerInfo(); + } + } +} + +void CRepeaterHandler::clockInt(unsigned int ms) +{ + m_infoAudio->clock(ms); + m_msgAudio->clock(ms); + m_wxAudio->clock(ms); + m_echo->clock(ms); + m_version->clock(ms); + + m_linkReconnectTimer.clock(ms); + m_watchdogTimer.clock(ms); + m_queryTimer.clock(ms); + m_heardTimer.clock(ms); + m_pollTimer.clock(ms); + + // If the reconnect timer has expired + if (m_linkReconnectTimer.isRunning() && m_linkReconnectTimer.hasExpired()) { + if (m_linkStatus != LS_NONE && (m_linkStartup.IsEmpty() || m_linkStartup.IsSameAs(wxT(" ")))) { + // Unlink if linked to something + wxLogMessage(wxT("Reconnect timer has expired, unlinking %s from %s"), m_rptCallsign.c_str(), m_linkRepeater.c_str()); + + CDExtraHandler::unlink(this); + CDPlusHandler::unlink(this); + CDCSHandler::unlink(this); + + m_linkStatus = LS_NONE; + m_linkRepeater.Clear(); + + // Tell the users + writeNotLinked(); + triggerInfo(); + } else if ((m_linkStatus == LS_NONE && !m_linkStartup.IsEmpty() && !m_linkStartup.IsSameAs(wxT(" "))) || + (m_linkStatus != LS_NONE && !m_linkRepeater.IsSameAs(m_linkStartup))) { + // Relink if not linked or linked to the wrong reflector + wxLogMessage(wxT("Reconnect timer has expired, relinking %s to %s"), m_rptCallsign.c_str(), m_linkStartup.c_str()); + + // Check for just a change of letter + if (m_linkStatus != LS_NONE) { + wxString oldCall = m_linkRepeater.Left(LONG_CALLSIGN_LENGTH - 1U); + wxString newCall = m_linkStartup.Left(LONG_CALLSIGN_LENGTH - 1U); + + // Just a change of port? + if (oldCall.IsSameAs(newCall)) { + switch (m_linkStatus) { + case LS_LINKING_DEXTRA: + case LS_LINKED_DEXTRA: + m_linkRelink = true; + m_linkRepeater = m_linkStartup; + CDExtraHandler::unlink(this, m_linkRepeater); + + m_linkStatus = LS_LINKING_DEXTRA; + writeLinkingTo(m_linkRepeater); + triggerInfo(); + break; + + case LS_LINKING_DCS: + case LS_LINKED_DCS: + m_linkRelink = true; + m_linkRepeater = m_linkStartup; + CDCSHandler::unlink(this, m_linkRepeater); + + m_linkStatus = LS_LINKING_DCS; + writeLinkingTo(m_linkRepeater); + triggerInfo(); + break; + + case LS_LINKING_LOOPBACK: + case LS_LINKED_LOOPBACK: + m_linkRelink = true; + m_linkRepeater = m_linkStartup; + CDCSHandler::unlink(this, m_linkRepeater); + + m_linkStatus = LS_LINKING_LOOPBACK; + writeLinkingTo(m_linkRepeater); + triggerInfo(); + break; + + case LS_LINKING_DPLUS: + m_linkRepeater = m_linkStartup; + CDPlusHandler::relink(this, m_linkRepeater); + writeLinkingTo(m_linkRepeater); + triggerInfo(); + break; + + case LS_LINKED_DPLUS: + m_linkRepeater = m_linkStartup; + CDPlusHandler::relink(this, m_linkRepeater); + writeLinkedTo(m_linkRepeater); + triggerInfo(); + break; + + default: + break; + } + + return; + } + } + + CDExtraHandler::unlink(this); + CDPlusHandler::unlink(this); + CDCSHandler::unlink(this); + + linkInt(m_linkStartup); + } + + m_linkReconnectTimer.start(); + } + + // If the ircDDB query timer has expired + if (m_queryTimer.isRunning() && m_queryTimer.hasExpired()) { + m_queryTimer.stop(); + + if (m_g2Status == G2_USER || m_g2Status == G2_REPEATER) { + // User or repeater not found in time, remove G2 settings + wxLogMessage(wxT("ircDDB did not reply within five seconds")); + + m_g2Status = G2_LOCAL; + m_g2User.Clear(); + m_g2Repeater.Clear(); + m_g2Gateway.Clear(); + + delete m_g2Header; + m_g2Header = NULL; + } else if (m_linkStatus == LS_PENDING_IRCDDB) { + // Repeater not found in time + wxLogMessage(wxT("ircDDB did not reply within five seconds")); + + m_linkStatus = LS_NONE; + m_linkRepeater.Clear(); + m_linkGateway.Clear(); + + writeNotLinked(); + triggerInfo(); + } else if (m_linkStatus == LS_LINKING_CCS) { + // CCS didn't reply in time + wxLogMessage(wxT("CCS did not reply within five seconds")); + + m_ccsHandler->stopLink(); + + m_linkStatus = LS_NONE; + m_linkRepeater.Clear(); + + restoreLinks(); + } + } + + // Icom heard timer has expired + if (m_heardTimer.isRunning() && m_heardTimer.hasExpired() && m_irc != NULL) { + m_irc->sendHeard(m_heardUser, wxT(" "), wxT(" "), m_heardRepeater, wxT(" "), 0x00U, 0x00U, 0x00U); + m_heardTimer.stop(); + } + + // If the watchdog timer has expired, clean up + if (m_watchdogTimer.isRunning() && m_watchdogTimer.hasExpired()) { + wxLogMessage(wxT("Radio watchdog timer for %s has expired"), m_rptCallsign.c_str()); + m_watchdogTimer.stop(); + + if (m_repeaterId != 0x00U) { + if (m_text.IsEmpty()) + sendHeard(); + + if (m_drats != NULL) + m_drats->writeEnd(); + + sendStats(); + + switch (m_g2Status) { + case G2_USER: + case G2_REPEATER: + m_queryTimer.stop(); + delete m_g2Header; + m_g2Header = NULL; + break; + + case G2_XBAND: + m_xBandRptr = NULL; + break; + + case G2_STARNET: + m_starNet = NULL; + break; + + case G2_ECHO: + m_echo->end(); + break; + + case G2_VERSION: + m_version->sendVersion(); + break; + + default: + break; + } + + if (m_infoNeeded) { + m_infoAudio->sendStatus(); + m_infoNeeded = false; + } + + if (m_msgNeeded) { + m_msgAudio->sendAnnouncement(); + m_msgNeeded = false; + } + + if (m_wxNeeded) { + m_wxAudio->sendAnnouncement(); + m_wxNeeded = false; + } + + m_repeaterId = 0x00U; + m_g2Status = G2_NONE; + } + + if (m_busyId != 0x00U) { + if (m_infoNeeded) { + m_infoAudio->sendStatus(); + m_infoNeeded = false; + } + + if (m_msgNeeded) { + m_msgAudio->sendAnnouncement(); + m_msgNeeded = false; + } + + if (m_wxNeeded) { + m_wxAudio->sendAnnouncement(); + m_wxNeeded = false; + } + + if (m_g2Status == G2_VERSION) + m_version->sendVersion(); + + m_g2Status = G2_NONE; + m_busyId = 0x00U; + } + } +} + +void CRepeaterHandler::linkUp(DSTAR_PROTOCOL protocol, const wxString& callsign) +{ + if (protocol == DP_DEXTRA && m_linkStatus == LS_LINKING_DEXTRA) { + wxLogMessage(wxT("DExtra link to %s established"), callsign.c_str()); + m_linkStatus = LS_LINKED_DEXTRA; + writeLinkedTo(callsign); + triggerInfo(); + } + + if (protocol == DP_DPLUS && m_linkStatus == LS_LINKING_DPLUS) { + wxLogMessage(wxT("D-Plus link to %s established"), callsign.c_str()); + m_linkStatus = LS_LINKED_DPLUS; + writeLinkedTo(callsign); + triggerInfo(); + } + + if (protocol == DP_DCS && m_linkStatus == LS_LINKING_DCS) { + wxLogMessage(wxT("DCS link to %s established"), callsign.c_str()); + m_linkStatus = LS_LINKED_DCS; + writeLinkedTo(callsign); + triggerInfo(); + } + + if (protocol == DP_DCS && m_linkStatus == LS_LINKING_LOOPBACK) { + wxLogMessage(wxT("Loopback link to %s established"), callsign.c_str()); + m_linkStatus = LS_LINKED_LOOPBACK; + writeLinkedTo(callsign); + triggerInfo(); + } +} + +bool CRepeaterHandler::linkFailed(DSTAR_PROTOCOL protocol, const wxString& callsign, bool isRecoverable) +{ + // Is relink to another module required? + if (!isRecoverable && m_linkRelink) { + m_linkRelink = false; + wxLogMessage(wxT("Relinking %s from %s to %s"), m_rptCallsign.c_str(), callsign.c_str(), m_linkRepeater.c_str()); + linkInt(m_linkRepeater); + return false; + } + + // Have we linked to something else in the meantime? + if (m_linkStatus == LS_NONE || !m_linkRepeater.IsSameAs(callsign)) { + switch (protocol) { + case DP_DCS: + wxLogMessage(wxT("DCS link to %s has failed"), callsign.c_str()); + break; + case DP_DEXTRA: + wxLogMessage(wxT("DExtra link to %s has failed"), callsign.c_str()); + break; + case DP_DPLUS: + wxLogMessage(wxT("D-Plus link to %s has failed"), callsign.c_str()); + break; + default: + break; + } + + return false; + } + + if (!isRecoverable) { + if (protocol == DP_DEXTRA && callsign.IsSameAs(m_linkRepeater)) { + wxLogMessage(wxT("DExtra link to %s has failed"), m_linkRepeater.c_str()); + m_linkRepeater.Clear(); + m_linkStatus = LS_NONE; + writeNotLinked(); + triggerInfo(); + } + + if (protocol == DP_DPLUS && callsign.IsSameAs(m_linkRepeater)) { + wxLogMessage(wxT("D-Plus link to %s has failed"), m_linkRepeater.c_str()); + m_linkRepeater.Clear(); + m_linkStatus = LS_NONE; + writeNotLinked(); + triggerInfo(); + } + + if (protocol == DP_DCS && callsign.IsSameAs(m_linkRepeater)) { + if (m_linkStatus == LS_LINKED_DCS || m_linkStatus == LS_LINKING_DCS) + wxLogMessage(wxT("DCS link to %s has failed"), m_linkRepeater.c_str()); + else + wxLogMessage(wxT("Loopback link to %s has failed"), m_linkRepeater.c_str()); + m_linkRepeater.Clear(); + m_linkStatus = LS_NONE; + writeNotLinked(); + triggerInfo(); + } + + return false; + } + + if (protocol == DP_DEXTRA) { + switch (m_linkStatus) { + case LS_LINKED_DEXTRA: + wxLogMessage(wxT("DExtra link to %s has failed, relinking"), m_linkRepeater.c_str()); + m_linkStatus = LS_LINKING_DEXTRA; + writeLinkingTo(m_linkRepeater); + triggerInfo(); + return true; + + case LS_LINKING_DEXTRA: + return true; + + default: + return false; + } + } + + if (protocol == DP_DPLUS) { + switch (m_linkStatus) { + case LS_LINKED_DPLUS: + wxLogMessage(wxT("D-Plus link to %s has failed, relinking"), m_linkRepeater.c_str()); + m_linkStatus = LS_LINKING_DPLUS; + writeLinkingTo(m_linkRepeater); + triggerInfo(); + return true; + + case LS_LINKING_DPLUS: + return true; + + default: + return false; + } + } + + if (protocol == DP_DCS) { + switch (m_linkStatus) { + case LS_LINKED_DCS: + wxLogMessage(wxT("DCS link to %s has failed, relinking"), m_linkRepeater.c_str()); + m_linkStatus = LS_LINKING_DCS; + writeLinkingTo(m_linkRepeater); + triggerInfo(); + return true; + + case LS_LINKED_LOOPBACK: + wxLogMessage(wxT("Loopback link to %s has failed, relinking"), m_linkRepeater.c_str()); + m_linkStatus = LS_LINKING_LOOPBACK; + writeLinkingTo(m_linkRepeater); + triggerInfo(); + return true; + + case LS_LINKING_DCS: + case LS_LINKING_LOOPBACK: + return true; + + default: + return false; + } + } + + return false; +} + +void CRepeaterHandler::linkRefused(DSTAR_PROTOCOL protocol, const wxString& callsign) +{ + if (protocol == DP_DEXTRA && callsign.IsSameAs(m_linkRepeater)) { + wxLogMessage(wxT("DExtra link to %s was refused"), m_linkRepeater.c_str()); + m_linkRepeater.Clear(); + m_linkStatus = LS_NONE; + writeIsBusy(callsign); + triggerInfo(); + } + + if (protocol == DP_DPLUS && callsign.IsSameAs(m_linkRepeater)) { + wxLogMessage(wxT("D-Plus link to %s was refused"), m_linkRepeater.c_str()); + m_linkRepeater.Clear(); + m_linkStatus = LS_NONE; + writeIsBusy(callsign); + triggerInfo(); + } + + if (protocol == DP_DCS && callsign.IsSameAs(m_linkRepeater)) { + if (m_linkStatus == LS_LINKED_DCS || m_linkStatus == LS_LINKING_DCS) + wxLogMessage(wxT("DCS link to %s was refused"), m_linkRepeater.c_str()); + else + wxLogMessage(wxT("Loopback link to %s was refused"), m_linkRepeater.c_str()); + m_linkRepeater.Clear(); + m_linkStatus = LS_NONE; + writeIsBusy(callsign); + triggerInfo(); + } +} + +void CRepeaterHandler::link(RECONNECT reconnect, const wxString& reflector) +{ + // CCS removal + if (m_linkStatus == LS_LINKING_CCS || m_linkStatus == LS_LINKED_CCS) { + wxLogMessage(wxT("Dropping CCS link to %s"), m_linkRepeater.c_str()); + + m_ccsHandler->stopLink(); + + m_linkStatus = LS_NONE; + m_linkRepeater.Clear(); + m_queryTimer.stop(); + } + + m_linkStartup = reflector; + m_linkReconnect = reconnect; + + m_linkReconnectTimer.stop(); + + switch (m_linkReconnect) { + case RECONNECT_5MINS: + m_linkReconnectTimer.start(5U * 60U); + break; + case RECONNECT_10MINS: + m_linkReconnectTimer.start(10U * 60U); + break; + case RECONNECT_15MINS: + m_linkReconnectTimer.start(15U * 60U); + break; + case RECONNECT_20MINS: + m_linkReconnectTimer.start(20U * 60U); + break; + case RECONNECT_25MINS: + m_linkReconnectTimer.start(25U * 60U); + break; + case RECONNECT_30MINS: + m_linkReconnectTimer.start(30U * 60U); + break; + case RECONNECT_60MINS: + m_linkReconnectTimer.start(60U * 60U); + break; + case RECONNECT_90MINS: + m_linkReconnectTimer.start(90U * 60U); + break; + case RECONNECT_120MINS: + m_linkReconnectTimer.start(120U * 60U); + break; + case RECONNECT_180MINS: + m_linkReconnectTimer.start(180U * 60U); + break; + default: + break; + } + + // Nothing to do + if ((m_linkStatus != LS_NONE && m_linkRepeater.IsSameAs(reflector)) || + (m_linkStatus == LS_NONE && (reflector.IsEmpty() || reflector.IsSameAs(wxT(" "))))) + return; + + // Handle unlinking + if (m_linkStatus != LS_NONE && (reflector.IsEmpty() || reflector.IsSameAs(wxT(" ")))) { + wxLogMessage(wxT("Unlinking %s from %s"), m_rptCallsign.c_str(), m_linkRepeater.c_str()); + + CDExtraHandler::unlink(this); + CDPlusHandler::unlink(this); + CDCSHandler::unlink(this); + + m_linkStatus = LS_NONE; + m_linkRepeater.Clear(); + + writeNotLinked(); + triggerInfo(); + + return; + } + + wxLogMessage(wxT("Linking %s to %s"), m_rptCallsign.c_str(), reflector.c_str()); + + // Check for just a change of letter + if (m_linkStatus != LS_NONE) { + wxString oldCall = m_linkRepeater.Left(LONG_CALLSIGN_LENGTH - 1U); + wxString newCall = reflector.Left(LONG_CALLSIGN_LENGTH - 1U); + + // Just a change of port? + if (oldCall.IsSameAs(newCall)) { + switch (m_linkStatus) { + case LS_LINKING_DEXTRA: + case LS_LINKED_DEXTRA: + m_linkRelink = true; + m_linkRepeater = reflector; + CDExtraHandler::unlink(this, m_linkRepeater); + + m_linkStatus = LS_LINKING_DEXTRA; + writeLinkingTo(m_linkRepeater); + triggerInfo(); + break; + + case LS_LINKING_DCS: + case LS_LINKED_DCS: + m_linkRelink = true; + m_linkRepeater = reflector; + CDCSHandler::unlink(this, m_linkRepeater); + + m_linkStatus = LS_LINKING_DCS; + writeLinkingTo(m_linkRepeater); + triggerInfo(); + break; + + case LS_LINKING_LOOPBACK: + case LS_LINKED_LOOPBACK: + m_linkRelink = true; + m_linkRepeater = reflector; + CDCSHandler::unlink(this, m_linkRepeater); + + m_linkStatus = LS_LINKING_LOOPBACK; + writeLinkingTo(m_linkRepeater); + triggerInfo(); + break; + + case LS_LINKING_DPLUS: + m_linkRepeater = reflector; + CDPlusHandler::relink(this, m_linkRepeater); + writeLinkingTo(m_linkRepeater); + triggerInfo(); + break; + + case LS_LINKED_DPLUS: + m_linkRepeater = reflector; + CDPlusHandler::relink(this, m_linkRepeater); + writeLinkedTo(m_linkRepeater); + triggerInfo(); + break; + + default: + break; + } + + return; + } + } + + CDExtraHandler::unlink(this); + CDPlusHandler::unlink(this); + CDCSHandler::unlink(this); + + linkInt(m_linkStartup); +} + +void CRepeaterHandler::unlink(PROTOCOL protocol, const wxString& reflector) +{ + if (protocol == PROTO_CCS) { + m_ccsHandler->unlink(reflector); + return; + } + + if (m_linkReconnect == RECONNECT_FIXED && m_linkRepeater.IsSameAs(reflector)) { + wxLogMessage(wxT("Cannot unlink %s because it is fixed"), reflector.c_str()); + return; + } + + switch (protocol) { + case PROTO_DPLUS: + CDPlusHandler::unlink(this, reflector, false); + break; + + case PROTO_DEXTRA: + CDExtraHandler::unlink(this, reflector, false); + break; + + case PROTO_DCS: + CDCSHandler::unlink(this, reflector, false); + break; + + default: + break; + } +} + +void CRepeaterHandler::g2CommandHandler(const wxString& callsign, const wxString& user, CHeaderData& header) +{ + if (m_linkStatus == LS_LINKING_CCS || m_linkStatus == LS_LINKED_CCS) + return; + + if (callsign.Left(1).IsSameAs(wxT("/"))) { + if (m_irc == NULL) { + wxLogMessage(wxT("%s is trying to G2 route with ircDDB disabled"), user.c_str()); + m_g2Status = G2_LOCAL; + return; + } + + // This a repeater route + // Convert "/1234567" to "123456 7" + wxString repeater = callsign.Mid(1, LONG_CALLSIGN_LENGTH - 2U); + repeater.Append(wxT(" ")); + repeater.Append(callsign.Right(1)); + + if (repeater.IsSameAs(m_rptCallsign)) { + wxLogMessage(wxT("%s is trying to G2 route to self, ignoring"), user.c_str()); + m_g2Status = G2_LOCAL; + return; + } + + if (repeater.Left(3U).IsSameAs(wxT("REF")) || repeater.Left(3U).IsSameAs(wxT("XRF")) || repeater.Left(3U).IsSameAs(wxT("DCS"))) { + wxLogMessage(wxT("%s is trying to G2 route to reflector %s, ignoring"), user.c_str(), repeater.c_str()); + m_g2Status = G2_LOCAL; + return; + } + + wxLogMessage(wxT("%s is trying to G2 route to repeater %s"), user.c_str(), repeater.c_str()); + + m_g2Repeater = repeater; + m_g2User = wxT("CQCQCQ "); + + CRepeaterData* data = m_cache->findRepeater(m_g2Repeater); + + if (data == NULL) { + m_g2Status = G2_REPEATER; + m_irc->findRepeater(m_g2Repeater); + m_g2Header = new CHeaderData(header); + m_queryTimer.start(); + } else { + m_g2Status = G2_OK; + m_g2Address = data->getAddress(); + m_g2Gateway = data->getGateway(); + header.setDestination(m_g2Address, G2_DV_PORT); + header.setRepeaters(m_g2Gateway, m_g2Repeater); + m_g2Handler->writeHeader(header); + delete data; + } + } else if (!callsign.Right(1).IsSameAs(wxT("L")) && !callsign.Right(1).IsSameAs(wxT("U"))) { + if (m_irc == NULL) { + wxLogMessage(wxT("%s is trying to G2 route with ircDDB disabled"), user.c_str()); + m_g2Status = G2_LOCAL; + return; + } + + // This a callsign route + if (callsign.Left(3U).IsSameAs(wxT("REF")) || callsign.Left(3U).IsSameAs(wxT("XRF")) || callsign.Left(3U).IsSameAs(wxT("DCS"))) { + wxLogMessage(wxT("%s is trying to G2 route to reflector %s, ignoring"), user.c_str(), callsign.c_str()); + m_g2Status = G2_LOCAL; + return; + } + + wxLogMessage(wxT("%s is trying to G2 route to callsign %s"), user.c_str(), callsign.c_str()); + + CUserData* data = m_cache->findUser(callsign); + + if (data == NULL) { + m_g2User = callsign; + m_g2Status = G2_USER; + m_irc->findUser(m_g2User); + m_g2Header = new CHeaderData(header); + m_queryTimer.start(); + } else { + // No point G2 routing to yourself + if (data->getRepeater().IsSameAs(m_rptCallsign)) { + m_g2Status = G2_LOCAL; + delete data; + return; + } + + m_g2Status = G2_OK; + m_g2User = callsign; + m_g2Address = data->getAddress(); + m_g2Repeater = data->getRepeater(); + m_g2Gateway = data->getGateway(); + header.setDestination(m_g2Address, G2_DV_PORT); + header.setRepeaters(m_g2Gateway, m_g2Repeater); + m_g2Handler->writeHeader(header); + + delete data; + } + } +} + +void CRepeaterHandler::ccsCommandHandler(const wxString& callsign, const wxString& user, const wxString& type) +{ + if (callsign.IsSameAs(wxT("CA "))) { + m_ccsHandler->stopLink(user, type); + } else { + CCS_STATUS status = m_ccsHandler->getStatus(); + if (status == CS_CONNECTED) { + suspendLinks(); + m_queryTimer.start(); + m_linkStatus = LS_LINKING_CCS; + m_linkRepeater = callsign.Mid(1U); + m_ccsHandler->startLink(m_linkRepeater, user, type); + } + } +} + +void CRepeaterHandler::reflectorCommandHandler(const wxString& callsign, const wxString& user, const wxString& type) +{ + if (m_linkStatus == LS_LINKING_CCS || m_linkStatus == LS_LINKED_CCS) + return; + + if (m_linkReconnect == RECONNECT_FIXED) + return; + + m_queryTimer.stop(); + + wxString letter = callsign.Right(1); + + if (letter.IsSameAs(wxT("U"))) { + // Ignore duplicate unlink requests + if (m_linkStatus == LS_NONE) + return; + + wxLogMessage(wxT("Unlink command issued via %s by %s"), type.c_str(), user.c_str()); + + CDExtraHandler::unlink(this); + CDPlusHandler::unlink(this); + CDCSHandler::unlink(this); + + m_linkStatus = LS_NONE; + m_linkRepeater.Clear(); + + writeNotLinked(); + triggerInfo(); + } else if (letter.IsSameAs(wxT("L"))) { + wxString reflector; + + // Handle the special case of " L" + if (callsign.IsSameAs(wxT(" L"))) { + if (m_linkStartup.IsEmpty()) + return; + + reflector = m_linkStartup; + } else { + // Extract the callsign "1234567L" -> "123456 7" + reflector = callsign.Left(LONG_CALLSIGN_LENGTH - 2U); + reflector.Append(wxT(" ")); + reflector.Append(callsign.Mid(LONG_CALLSIGN_LENGTH - 2U, 1)); + } + + // Ensure duplicate link requests aren't acted on + if (m_linkStatus != LS_NONE && reflector.IsSameAs(m_linkRepeater)) + return; + + // We can't link to ourself + if (reflector.IsSameAs(m_rptCallsign)) { + wxLogMessage(wxT("%s is trying to link with self via %s, ignoring"), user.c_str(), type.c_str()); + triggerInfo(); + return; + } + + wxLogMessage(wxT("Link command from %s to %s issued via %s by %s"), m_rptCallsign.c_str(), reflector.c_str(), type.c_str(), user.c_str()); + + // Check for just a change of letter + if (m_linkStatus != LS_NONE) { + wxString oldCall = m_linkRepeater.Left(LONG_CALLSIGN_LENGTH - 1U); + wxString newCall = reflector.Left(LONG_CALLSIGN_LENGTH - 1U); + + // Just a change of port? + if (oldCall.IsSameAs(newCall)) { + switch (m_linkStatus) { + case LS_LINKING_DEXTRA: + case LS_LINKED_DEXTRA: + m_linkRelink = true; + m_linkRepeater = reflector; + CDExtraHandler::unlink(this, m_linkRepeater); + + m_linkStatus = LS_LINKING_DEXTRA; + writeLinkingTo(m_linkRepeater); + triggerInfo(); + break; + + case LS_LINKING_DCS: + case LS_LINKED_DCS: + m_linkRelink = true; + m_linkRepeater = reflector; + CDCSHandler::unlink(this, m_linkRepeater); + + m_linkStatus = LS_LINKING_DCS; + writeLinkingTo(m_linkRepeater); + triggerInfo(); + break; + + case LS_LINKING_LOOPBACK: + case LS_LINKED_LOOPBACK: + m_linkRelink = true; + m_linkRepeater = reflector; + CDCSHandler::unlink(this, m_linkRepeater); + + m_linkStatus = LS_LINKING_LOOPBACK; + writeLinkingTo(m_linkRepeater); + triggerInfo(); + break; + + case LS_LINKING_DPLUS: + m_linkRepeater = reflector; + CDPlusHandler::relink(this, m_linkRepeater); + writeLinkingTo(m_linkRepeater); + triggerInfo(); + break; + + case LS_LINKED_DPLUS: + m_linkRepeater = reflector; + CDPlusHandler::relink(this, m_linkRepeater); + writeLinkedTo(m_linkRepeater); + triggerInfo(); + break; + + default: + break; + } + + return; + } + } + + CDExtraHandler::unlink(this); + CDPlusHandler::unlink(this); + CDCSHandler::unlink(this); + + linkInt(reflector); + } +} + +void CRepeaterHandler::linkInt(const wxString& callsign) +{ + // Find the repeater to link to + CRepeaterData* data = m_cache->findRepeater(callsign); + + // Are we trying to link to an unknown DExtra, D-Plus, or DCS reflector? + if (data == NULL && (callsign.Left(3U).IsSameAs(wxT("REF")) || callsign.Left(3U).IsSameAs(wxT("XRF")) || callsign.Left(3U).IsSameAs(wxT("DCS")))) { + wxLogMessage(wxT("%s is unknown, ignoring link request"), callsign.c_str()); + triggerInfo(); + return; + } + + m_linkRepeater = callsign; + + if (data != NULL) { + m_linkGateway = data->getGateway(); + + switch (data->getProtocol()) { + case DP_DPLUS: + if (m_dplusEnabled) { + m_linkStatus = LS_LINKING_DPLUS; + CDPlusHandler::link(this, m_rptCallsign, m_linkRepeater, data->getAddress()); + writeLinkingTo(m_linkRepeater); + triggerInfo(); + } else { + wxLogMessage(wxT("Require D-Plus for linking to %s, but D-Plus is disabled"), callsign.c_str()); + m_linkStatus = LS_NONE; + writeNotLinked(); + triggerInfo(); + } + break; + + case DP_DCS: + if (m_dcsEnabled) { + m_linkStatus = LS_LINKING_DCS; + CDCSHandler::link(this, m_rptCallsign, m_linkRepeater, data->getAddress()); + writeLinkingTo(m_linkRepeater); + triggerInfo(); + } else { + wxLogMessage(wxT("Require DCS for linking to %s, but DCS is disabled"), callsign.c_str()); + m_linkStatus = LS_NONE; + writeNotLinked(); + triggerInfo(); + } + break; + + case DP_LOOPBACK: + m_linkStatus = LS_LINKING_LOOPBACK; + CDCSHandler::link(this, m_rptCallsign, m_linkRepeater, data->getAddress()); + writeLinkingTo(m_linkRepeater); + triggerInfo(); + break; + + default: + if (m_dextraEnabled) { + m_linkStatus = LS_LINKING_DEXTRA; + CDExtraHandler::link(this, m_rptCallsign, m_linkRepeater, data->getAddress()); + writeLinkingTo(m_linkRepeater); + triggerInfo(); + } else { + wxLogMessage(wxT("Require DExtra for linking to %s, but DExtra is disabled"), callsign.c_str()); + m_linkStatus = LS_NONE; + writeNotLinked(); + triggerInfo(); + } + break; + } + + delete data; + } else { + if (m_irc != NULL) { + m_linkStatus = LS_PENDING_IRCDDB; + m_irc->findRepeater(callsign); + m_queryTimer.start(); + writeLinkingTo(callsign); + triggerInfo(); + } else { + m_linkStatus = LS_NONE; + writeNotLinked(); + triggerInfo(); + } + } +} + +void CRepeaterHandler::sendToOutgoing(const CHeaderData& header) +{ + CHeaderData temp(header); + + temp.setCQCQCQ(); + temp.setFlags(0x00U, 0x00U, 0x00U); + + // Outgoing DPlus links change the RPT1 and RPT2 values in the DPlus handler + CDPlusHandler::writeHeader(this, temp, DIR_OUTGOING); + + // Outgoing DExtra links have the currently linked repeater/gateway + // as the RPT1 and RPT2 values + temp.setRepeaters(m_linkGateway, m_linkRepeater); + CDExtraHandler::writeHeader(this, temp, DIR_OUTGOING); + + // Outgoing DCS links have the currently linked repeater and repeater callsign + // as the RPT1 and RPT2 values + temp.setRepeaters(m_rptCallsign, m_linkRepeater); + CDCSHandler::writeHeader(this, temp, DIR_OUTGOING); +} + +void CRepeaterHandler::sendToOutgoing(const CAMBEData& data) +{ + CAMBEData temp(data); + + CDExtraHandler::writeAMBE(this, temp, DIR_OUTGOING); + + CDPlusHandler::writeAMBE(this, temp, DIR_OUTGOING); + + CDCSHandler::writeAMBE(this, temp, DIR_OUTGOING); +} + +void CRepeaterHandler::sendToIncoming(const CHeaderData& header) +{ + CHeaderData temp(header); + + temp.setCQCQCQ(); + temp.setFlags(0x00U, 0x00U, 0x00U); + + // Incoming DPlus links + temp.setRepeaters(m_rptCallsign, m_gateway); + CDPlusHandler::writeHeader(this, temp, DIR_INCOMING); + + // Incoming DExtra links have RPT1 and RPT2 swapped + temp.setRepeaters(m_gwyCallsign, m_rptCallsign); + CDExtraHandler::writeHeader(this, temp, DIR_INCOMING); + + // Incoming DCS links have RPT1 and RPT2 swapped + temp.setRepeaters(m_gwyCallsign, m_rptCallsign); + CDCSHandler::writeHeader(this, temp, DIR_INCOMING); +} + +void CRepeaterHandler::sendToIncoming(const CAMBEData& data) +{ + CAMBEData temp(data); + + CDExtraHandler::writeAMBE(this, temp, DIR_INCOMING); + + CDPlusHandler::writeAMBE(this, temp, DIR_INCOMING); + + CDCSHandler::writeAMBE(this, temp, DIR_INCOMING); +} + +void CRepeaterHandler::startupInt() +{ + // Report our existence to ircDDB + if (m_irc != NULL) { + wxString callsign = m_rptCallsign; + if (m_ddMode) + callsign.Append(wxT("D")); + + if (m_frequency > 0.0) + m_irc->rptrQRG(callsign, m_frequency, m_offset, m_range * 1000.0, m_agl); + + if (m_latitude != 0.0 && m_longitude != 0.0) + m_irc->rptrQTH(callsign, m_latitude, m_longitude, m_description1, m_description2, m_url); + } + + + m_ccsHandler = new CCCSHandler(this, m_rptCallsign, m_index + 1U, m_latitude, m_longitude, m_frequency, m_offset, m_description1, m_description2, m_url, CCS_PORT + m_index); + + // Start up our CCS link if we are DV mode + if (!m_ddMode) + m_ccsHandler->connect(); + + // Link to a startup reflector/repeater + if (m_linkAtStartup && !m_linkStartup.IsEmpty()) { + wxLogMessage(wxT("Linking %s at startup to %s"), m_rptCallsign.c_str(), m_linkStartup.c_str()); + + // Find the repeater to link to + CRepeaterData* data = m_cache->findRepeater(m_linkStartup); + + m_linkRepeater = m_linkStartup; + + if (data != NULL) { + m_linkGateway = data->getGateway(); + + DSTAR_PROTOCOL protocol = data->getProtocol(); + switch (protocol) { + case DP_DPLUS: + if (m_dplusEnabled) { + m_linkStatus = LS_LINKING_DPLUS; + CDPlusHandler::link(this, m_rptCallsign, m_linkRepeater, data->getAddress()); + writeLinkingTo(m_linkRepeater); + triggerInfo(); + } else { + wxLogMessage(wxT("Require D-Plus for linking to %s, but D-Plus is disabled"), m_linkRepeater.c_str()); + m_linkStatus = LS_NONE; + writeNotLinked(); + triggerInfo(); + } + break; + + case DP_DCS: + if (m_dcsEnabled) { + m_linkStatus = LS_LINKING_DCS; + CDCSHandler::link(this, m_rptCallsign, m_linkRepeater, data->getAddress()); + writeLinkingTo(m_linkRepeater); + triggerInfo(); + } else { + wxLogMessage(wxT("Require DCS for linking to %s, but DCS is disabled"), m_linkRepeater.c_str()); + m_linkStatus = LS_NONE; + writeNotLinked(); + triggerInfo(); + } + break; + + case DP_LOOPBACK: + m_linkStatus = LS_LINKING_LOOPBACK; + CDCSHandler::link(this, m_rptCallsign, m_linkRepeater, data->getAddress()); + writeLinkingTo(m_linkRepeater); + triggerInfo(); + break; + + default: + if (m_dextraEnabled) { + m_linkStatus = LS_LINKING_DEXTRA; + CDExtraHandler::link(this, m_rptCallsign, m_linkRepeater, data->getAddress()); + writeLinkingTo(m_linkRepeater); + triggerInfo(); + } else { + wxLogMessage(wxT("Require DExtra for linking to %s, but DExtra is disabled"), m_linkRepeater.c_str()); + m_linkStatus = LS_NONE; + writeNotLinked(); + triggerInfo(); + } + break; + } + + delete data; + } else { + if (m_irc != NULL) { + m_linkStatus = LS_PENDING_IRCDDB; + m_irc->findRepeater(m_linkStartup); + m_queryTimer.start(); + writeLinkingTo(m_linkStartup); + triggerInfo(); + } else { + m_linkStatus = LS_NONE; + writeNotLinked(); + triggerInfo(); + } + } + } else { + writeNotLinked(); + triggerInfo(); + } +} + +void CRepeaterHandler::writeLinkingTo(const wxString &callsign) +{ + wxString text; + + switch (m_language) { + case TL_DEUTSCH: + text.Printf(wxT("Verbinde mit %s"), callsign.c_str()); + break; + case TL_DANSK: + text.Printf(wxT("Linker til %s"), callsign.c_str()); + break; + case TL_FRANCAIS: + text.Printf(wxT("Connexion a %s"), callsign.c_str()); + break; + case TL_ITALIANO: + text.Printf(wxT("In conn con %s"), callsign.c_str()); + break; + case TL_POLSKI: + text.Printf(wxT("Linkuje do %s"), callsign.c_str()); + break; + case TL_ESPANOL: + text.Printf(wxT("Enlazando %s"), callsign.c_str()); + break; + case TL_SVENSKA: + text.Printf(wxT("Lankar till %s"), callsign.c_str()); + break; + case TL_NEDERLANDS_NL: + case TL_NEDERLANDS_BE: + text.Printf(wxT("Linken naar %s"), callsign.c_str()); + break; + case TL_NORSK: + text.Printf(wxT("Kobler til %s"), callsign.c_str()); + break; + case TL_PORTUGUES: + text.Printf(wxT("Conectando, %s"), callsign.c_str()); + break; + default: + text.Printf(wxT("Linking to %s"), callsign.c_str()); + break; + } + + CTextData textData(m_linkStatus, callsign, text, m_address, m_port); + m_repeaterHandler->writeText(textData); + + m_infoAudio->setStatus(m_linkStatus, m_linkRepeater, text); + triggerInfo(); + + m_ccsHandler->setReflector(); +} + +void CRepeaterHandler::writeLinkedTo(const wxString &callsign) +{ + wxString text; + + switch (m_language) { + case TL_DEUTSCH: + text.Printf(wxT("Verlinkt zu %s"), callsign.c_str()); + break; + case TL_DANSK: + text.Printf(wxT("Linket til %s"), callsign.c_str()); + break; + case TL_FRANCAIS: + text.Printf(wxT("Connecte a %s"), callsign.c_str()); + break; + case TL_ITALIANO: + text.Printf(wxT("Connesso a %s"), callsign.c_str()); + break; + case TL_POLSKI: + text.Printf(wxT("Polaczony z %s"), callsign.c_str()); + break; + case TL_ESPANOL: + text.Printf(wxT("Enlazado %s"), callsign.c_str()); + break; + case TL_SVENSKA: + text.Printf(wxT("Lankad till %s"), callsign.c_str()); + break; + case TL_NEDERLANDS_NL: + case TL_NEDERLANDS_BE: + text.Printf(wxT("Gelinkt met %s"), callsign.c_str()); + break; + case TL_NORSK: + text.Printf(wxT("Tilkoblet %s"), callsign.c_str()); + break; + case TL_PORTUGUES: + text.Printf(wxT("Conectado a %s"), callsign.c_str()); + break; + default: + text.Printf(wxT("Linked to %s"), callsign.c_str()); + break; + } + + CTextData textData(m_linkStatus, callsign, text, m_address, m_port); + m_repeaterHandler->writeText(textData); + + m_infoAudio->setStatus(m_linkStatus, m_linkRepeater, text); + triggerInfo(); + + m_ccsHandler->setReflector(callsign); +} + +void CRepeaterHandler::writeNotLinked() +{ + wxString text; + + switch (m_language) { + case TL_DEUTSCH: + text = wxT("Nicht verbunden"); + break; + case TL_DANSK: + text = wxT("Ikke forbundet"); + break; + case TL_FRANCAIS: + text = wxT("Non connecte"); + break; + case TL_ITALIANO: + text = wxT("Non connesso"); + break; + case TL_POLSKI: + text = wxT("Nie polaczony"); + break; + case TL_ESPANOL: + text = wxT("No enlazado"); + break; + case TL_SVENSKA: + text = wxT("Ej lankad"); + break; + case TL_NEDERLANDS_NL: + case TL_NEDERLANDS_BE: + text = wxT("Niet gelinkt"); + break; + case TL_NORSK: + text = wxT("Ikke linket"); + break; + case TL_PORTUGUES: + text = wxT("Desconectado"); + break; + default: + text = wxT("Not linked"); + break; + } + + CTextData textData(LS_NONE, wxEmptyString, text, m_address, m_port); + m_repeaterHandler->writeText(textData); + + m_infoAudio->setStatus(m_linkStatus, m_linkRepeater, text); + triggerInfo(); + + m_ccsHandler->setReflector(); +} + +void CRepeaterHandler::writeIsBusy(const wxString& callsign) +{ + wxString tempText; + wxString text; + + switch (m_language) { + case TL_DEUTSCH: + text = wxT("Nicht verbunden"); + tempText.Printf(wxT("%s ist belegt"), callsign.c_str()); + break; + case TL_DANSK: + text = wxT("Ikke forbundet"); + tempText.Printf(wxT("Optaget fra %s"), callsign.c_str()); + break; + case TL_FRANCAIS: + text = wxT("Non connecte"); + tempText.Printf(wxT("Occupe par %s"), callsign.c_str()); + break; + case TL_ITALIANO: + text = wxT("Non connesso"); + tempText.Printf(wxT("Occupado da%s"), callsign.c_str()); + break; + case TL_POLSKI: + text = wxT("Nie polaczony"); + tempText.Printf(wxT("%s jest zajety"), callsign.c_str()); + break; + case TL_ESPANOL: + text = wxT("No enlazado"); + tempText.Printf(wxT("%s ocupado"), callsign.c_str()); + break; + case TL_SVENSKA: + text = wxT("Ej lankad"); + tempText.Printf(wxT("%s ar upptagen"), callsign.c_str()); + break; + case TL_NEDERLANDS_NL: + case TL_NEDERLANDS_BE: + text = wxT("Niet gelinkt"); + tempText.Printf(wxT("%s is bezet"), callsign.c_str()); + break; + case TL_NORSK: + text = wxT("Ikke linket"); + tempText.Printf(wxT("%s er opptatt"), callsign.c_str()); + break; + case TL_PORTUGUES: + text = wxT("Desconectado"); + tempText.Printf(wxT("%s, ocupado"), callsign.c_str()); + break; + default: + text = wxT("Not linked"); + tempText.Printf(wxT("%s is busy"), callsign.c_str()); + break; + } + + CTextData textData1(m_linkStatus, m_linkRepeater, tempText, m_address, m_port, true); + m_repeaterHandler->writeText(textData1); + + CTextData textData2(m_linkStatus, m_linkRepeater, text, m_address, m_port); + m_repeaterHandler->writeText(textData2); + + m_infoAudio->setStatus(m_linkStatus, m_linkRepeater, text); + m_infoAudio->setTempStatus(m_linkStatus, m_linkRepeater, tempText); + triggerInfo(); + + m_ccsHandler->setReflector(); +} + +void CRepeaterHandler::ccsLinkMade(const wxString& callsign, DIRECTION direction) +{ + wxString text; + + switch (m_language) { + case TL_DEUTSCH: + text.Printf(wxT("Verlinkt zu %s"), callsign.c_str()); + break; + case TL_DANSK: + text.Printf(wxT("Linket til %s"), callsign.c_str()); + break; + case TL_FRANCAIS: + text.Printf(wxT("Connecte a %s"), callsign.c_str()); + break; + case TL_ITALIANO: + text.Printf(wxT("Connesso a %s"), callsign.c_str()); + break; + case TL_POLSKI: + text.Printf(wxT("Polaczony z %s"), callsign.c_str()); + break; + case TL_ESPANOL: + text.Printf(wxT("Enlazado %s"), callsign.c_str()); + break; + case TL_SVENSKA: + text.Printf(wxT("Lankad till %s"), callsign.c_str()); + break; + case TL_NEDERLANDS_NL: + case TL_NEDERLANDS_BE: + text.Printf(wxT("Gelinkt met %s"), callsign.c_str()); + break; + case TL_NORSK: + text.Printf(wxT("Tilkoblet %s"), callsign.c_str()); + break; + case TL_PORTUGUES: + text.Printf(wxT("Conectado a %s"), callsign.c_str()); + break; + default: + text.Printf(wxT("Linked to %s"), callsign.c_str()); + break; + } + + if (direction == DIR_OUTGOING) { + suspendLinks(); + + m_linkStatus = LS_LINKED_CCS; + m_linkRepeater = callsign; + m_queryTimer.stop(); + + CTextData textData(m_linkStatus, callsign, text, m_address, m_port); + m_repeaterHandler->writeText(textData); + + m_infoAudio->setStatus(m_linkStatus, m_linkRepeater, text); + triggerInfo(); + } else { + CTextData textData(m_linkStatus, m_linkRepeater, text, m_address, m_port, true); + m_repeaterHandler->writeText(textData); + + m_infoAudio->setTempStatus(LS_LINKED_CCS, callsign, text); + triggerInfo(); + } +} + +void CRepeaterHandler::ccsLinkEnded(const wxString&, DIRECTION direction) +{ + wxString tempText; + wxString text; + + switch (m_language) { + case TL_DEUTSCH: + text = wxT("Nicht verbunden"); + tempText = wxT("CCS ist beendet"); + break; + case TL_DANSK: + text = wxT("Ikke forbundet"); + tempText = wxT("CCS er afsluttet"); + break; + case TL_FRANCAIS: + text = wxT("Non connecte"); + tempText = wxT("CCS a pris fin"); + break; + case TL_ITALIANO: + text = wxT("Non connesso"); + tempText = wxT("CCS e finita"); + break; + case TL_POLSKI: + text = wxT("Nie polaczony"); + tempText = wxT("CCS zakonczyl"); + break; + case TL_ESPANOL: + text = wxT("No enlazado"); + tempText = wxT("CCS ha terminado"); + break; + case TL_SVENSKA: + text = wxT("Ej lankad"); + tempText = wxT("CCS har upphort"); + break; + case TL_NEDERLANDS_NL: + case TL_NEDERLANDS_BE: + text = wxT("Niet gelinkt"); + tempText = wxT("CCS is afgelopen"); + break; + case TL_NORSK: + text = wxT("Ikke linket"); + tempText = wxT("CCS er avsluttet"); + break; + case TL_PORTUGUES: + text = wxT("Desconectado"); + tempText = wxT("CCS terminou"); + break; + default: + text = wxT("Not linked"); + tempText = wxT("CCS has ended"); + break; + } + + if (direction == DIR_OUTGOING) { + m_linkStatus = LS_NONE; + m_linkRepeater.Clear(); + m_queryTimer.stop(); + + bool res = restoreLinks(); + if (!res) { + CTextData textData1(m_linkStatus, m_linkRepeater, tempText, m_address, m_port, true); + m_repeaterHandler->writeText(textData1); + + CTextData textData2(m_linkStatus, m_linkRepeater, text, m_address, m_port); + m_repeaterHandler->writeText(textData2); + + m_infoAudio->setStatus(m_linkStatus, m_linkRepeater, text); + m_infoAudio->setTempStatus(m_linkStatus, m_linkRepeater, tempText); + triggerInfo(); + } + } else { + CTextData textData(m_linkStatus, m_linkRepeater, tempText, m_address, m_port, true); + m_repeaterHandler->writeText(textData); + + m_infoAudio->setTempStatus(m_linkStatus, m_linkRepeater, tempText); + triggerInfo(); + } +} + +void CRepeaterHandler::ccsLinkFailed(const wxString& dtmf, DIRECTION direction) +{ + wxString tempText; + wxString text; + + switch (m_language) { + case TL_DEUTSCH: + text = wxT("Nicht verbunden"); + tempText.Printf(wxT("%s unbekannt"), dtmf.c_str()); + break; + case TL_DANSK: + text = wxT("Ikke forbundet"); + tempText.Printf(wxT("%s unknown"), dtmf.c_str()); + break; + case TL_FRANCAIS: + text = wxT("Non connecte"); + tempText.Printf(wxT("%s inconnu"), dtmf.c_str()); + break; + case TL_ITALIANO: + text = wxT("Non connesso"); + tempText.Printf(wxT("Sconosciuto %s"), dtmf.c_str()); + break; + case TL_POLSKI: + text = wxT("Nie polaczony"); + tempText.Printf(wxT("%s nieznany"), dtmf.c_str()); + break; + case TL_ESPANOL: + text = wxT("No enlazado"); + tempText.Printf(wxT("Desconocido %s"), dtmf.c_str()); + break; + case TL_SVENSKA: + text = wxT("Ej lankad"); + tempText.Printf(wxT("%s okand"), dtmf.c_str()); + break; + case TL_NEDERLANDS_NL: + case TL_NEDERLANDS_BE: + text = wxT("Niet gelinkt"); + tempText.Printf(wxT("%s bekend"), dtmf.c_str()); + break; + case TL_NORSK: + text = wxT("Ikke linket"); + tempText.Printf(wxT("%s ukjent"), dtmf.c_str()); + break; + case TL_PORTUGUES: + text = wxT("Desconectado"); + tempText.Printf(wxT("%s desconhecido"), dtmf.c_str()); + break; + default: + text = wxT("Not linked"); + tempText.Printf(wxT("%s unknown"), dtmf.c_str()); + break; + } + + if (direction == DIR_OUTGOING) { + m_linkStatus = LS_NONE; + m_linkRepeater.Clear(); + m_queryTimer.stop(); + + bool res = restoreLinks(); + if (!res) { + CTextData textData1(m_linkStatus, m_linkRepeater, tempText, m_address, m_port, true); + m_repeaterHandler->writeText(textData1); + + CTextData textData2(m_linkStatus, m_linkRepeater, text, m_address, m_port); + m_repeaterHandler->writeText(textData2); + + m_infoAudio->setStatus(m_linkStatus, m_linkRepeater, text); + m_infoAudio->setTempStatus(m_linkStatus, m_linkRepeater, tempText); + triggerInfo(); + } + } else { + CTextData textData(m_linkStatus, m_linkRepeater, tempText, m_address, m_port, true); + m_repeaterHandler->writeText(textData); + + m_infoAudio->setTempStatus(m_linkStatus, m_linkRepeater, tempText); + triggerInfo(); + } +} + +void CRepeaterHandler::writeStatus(CStatusData& statusData) +{ + for (unsigned int i = 0U; i < m_maxRepeaters; i++) { + if (m_repeaters[i] != NULL) { + statusData.setDestination(m_repeaters[i]->m_address, m_repeaters[i]->m_port); + m_repeaters[i]->m_repeaterHandler->writeStatus(statusData); + } + } +} + +void CRepeaterHandler::sendHeard(const wxString& text) +{ + if (m_irc == NULL) + return; + + wxString destination; + + if (m_g2Status == G2_OK) { + destination = m_g2Repeater; + } else if (m_g2Status == G2_NONE && (m_linkStatus == LS_LINKED_DPLUS || m_linkStatus == LS_LINKED_DEXTRA || m_linkStatus == LS_LINKED_DCS)) { + if (m_linkRepeater.Left(3U).IsSameAs(wxT("REF")) || m_linkRepeater.Left(3U).IsSameAs(wxT("XRF")) || m_linkRepeater.Left(3U).IsSameAs(wxT("DCS"))) + destination = m_linkRepeater; + } + + m_irc->sendHeardWithTXMsg(m_myCall1, m_myCall2, m_yourCall, m_rptCall1, m_rptCall2, m_flag1, m_flag2, m_flag3, destination, text); +} + +void CRepeaterHandler::sendStats() +{ + if (m_irc != NULL) + m_irc->sendHeardWithTXStats(m_myCall1, m_myCall2, m_yourCall, m_rptCall1, m_rptCall2, m_flag1, m_flag2, m_flag3, m_frames, m_silence, m_errors / 2U); +} + +void CRepeaterHandler::suspendLinks() +{ + if (m_linkStatus == LS_LINKING_DCS || m_linkStatus == LS_LINKED_DCS || + m_linkStatus == LS_LINKING_DEXTRA || m_linkStatus == LS_LINKED_DEXTRA || + m_linkStatus == LS_LINKING_DPLUS || m_linkStatus == LS_LINKED_DPLUS || + m_linkStatus == LS_LINKING_LOOPBACK || m_linkStatus == LS_LINKED_LOOPBACK) { + m_lastReflector = m_linkRepeater; + m_lastReflector.Trim(); + } + + CDPlusHandler::unlink(this); + CDExtraHandler::unlink(this); + CDCSHandler::unlink(this); + + m_linkStatus = LS_NONE; + m_linkRepeater.Clear(); + m_linkReconnectTimer.stop(); + + m_ccsHandler->setReflector(); +} + +bool CRepeaterHandler::restoreLinks() +{ + if (m_linkReconnect == RECONNECT_FIXED) { + if (!m_lastReflector.IsEmpty()) { + linkInt(m_linkStartup); + m_lastReflector.Clear(); + return true; + } + } else if (m_linkReconnect == RECONNECT_NEVER) { + if (!m_lastReflector.IsEmpty()) { + linkInt(m_lastReflector); + m_lastReflector.Clear(); + return true; + } + } else { + m_linkReconnectTimer.start(); + if (!m_lastReflector.IsEmpty()) { + linkInt(m_lastReflector); + m_lastReflector.Clear(); + return true; + } + } + + m_lastReflector.Clear(); + return false; +} + +void CRepeaterHandler::triggerInfo() +{ + if (!m_infoEnabled) + return; + + // Either send the audio now, or queue it until the end of the transmission + if (m_repeaterId != 0x00U || m_busyId != 0x00U) { + m_infoNeeded = true; + } else { + m_infoAudio->sendStatus(); + m_infoNeeded = false; + } +} + +bool CRepeaterHandler::isCCSCommand(const wxString& command) const +{ + if (command.IsSameAs(wxT("CA "))) + return true; + + wxChar c = command.GetChar(0U); + if (c != wxT('C')) + return false; + + c = command.GetChar(1U); + if (c < wxT('0') || c > wxT('9')) + return false; + + c = command.GetChar(2U); + if (c < wxT('0') || c > wxT('9')) + return false; + + c = command.GetChar(3U); + if (c < wxT('0') || c > wxT('9')) + return false; + + return true; +} diff --git a/Common/RepeaterHandler.h b/Common/RepeaterHandler.h new file mode 100644 index 0000000..5871775 --- /dev/null +++ b/Common/RepeaterHandler.h @@ -0,0 +1,305 @@ +/* + * Copyright (C) 2010-2015 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef RepeaterHandler_H +#define RepeaterHandler_H + +#include "RepeaterProtocolHandler.h" +#include "DExtraProtocolHandler.h" +#include "DPlusProtocolHandler.h" +#include "RemoteRepeaterData.h" +#include "G2ProtocolHandler.h" +#include "ReflectorCallback.h" +#include "RepeaterCallback.h" +#include "AnnouncementUnit.h" +#include "StarNetHandler.h" +#include "TextCollector.h" +#include "CacheManager.h" +#include "HeaderLogger.h" +#include "CallsignList.h" +#include "DRATSServer.h" +#include "CCSCallback.h" +#include "VersionUnit.h" +#include "CCSHandler.h" +#include "StatusData.h" +#include "APRSWriter.h" +#include "HeardData.h" +#include "AudioUnit.h" +#include "EchoUnit.h" +#include "PollData.h" +#include "DDData.h" +#include "IRCDDB.h" +#include "Timer.h" +#include "DTMF.h" +#include "Defs.h" + +#if defined(__WINDOWS__) +#include "Inaddr.h" +#else +#include +#endif + +#include + +class CRepeaterHandler : public IRepeaterCallback, public IReflectorCallback, public ICCSCallback { +public: + static void initialise(unsigned int maxRepeaters); + + static void add(const wxString& callsign, const wxString& band, const wxString& address, unsigned int port, HW_TYPE hwType, const wxString& reflector, bool atStartup, RECONNECT reconnect, bool dratsEnabled, double frequency, double offset, double range, double latitude, double longitude, double agl, const wxString& description1, const wxString& description2, const wxString& url, IRepeaterProtocolHandler* handler, unsigned char band1, unsigned char band2, unsigned char band3); + + static void setLocalAddress(const wxString& address); + static void setG2Handler(CG2ProtocolHandler* handler); + static void setIRC(CIRCDDB* irc); + static void setCache(CCacheManager* cache); + static void setGateway(const wxString& gateway); + static void setLanguage(TEXT_LANG language); + static void setDExtraEnabled(bool enabled); + static void setDPlusEnabled(bool enabled); + static void setDCSEnabled(bool enabled); + static void setHeaderLogger(CHeaderLogger* logger); + static void setAPRSWriter(CAPRSWriter* writer); + static void setInfoEnabled(bool enabled); + static void setEchoEnabled(bool enabled); + static void setDTMFEnabled(bool enabled); + static void setWhiteList(CCallsignList* list); + static void setBlackList(CCallsignList* list); + static void setRestrictList(CCallsignList* list); + + static void startup(); + + static bool getRepeater(unsigned int n, wxString& callsign, LINK_STATUS& linkStatus, wxString& linkCallsign); + + static wxArrayString listDVRepeaters(); + + static CRepeaterHandler* findDVRepeater(const CHeaderData& header); + static CRepeaterHandler* findDVRepeater(const CAMBEData& data, bool busy); + static CRepeaterHandler* findDVRepeater(const wxString& callsign); + + static CRepeaterHandler* findRepeater(const CPollData& data); + + static CRepeaterHandler* findDDRepeater(const CDDData& data); + static CRepeaterHandler* findDDRepeater(); + + static void pollAllIcom(CPollData& data); + + static void writeStatus(CStatusData& statusData); + + static void resolveUser(const wxString& user, const wxString& repeater, const wxString& gateway, const wxString& address); + static void resolveRepeater(const wxString& repeater, const wxString& gateway, const wxString& address, DSTAR_PROTOCOL protocol); + + static void finalise(); + + static void clock(unsigned int ms); + + void processRepeater(CHeaderData& header); + void processRepeater(CHeardData& heard); + void processRepeater(CAMBEData& data); + void processRepeater(CPollData& data); + void processRepeater(CDDData& data); + + void processBusy(CHeaderData& header); + void processBusy(CAMBEData& data); + + void link(RECONNECT reconnect, const wxString& reflector); + void unlink(PROTOCOL protocol, const wxString& reflector); + + CRemoteRepeaterData* getInfo() const; + + virtual bool process(CHeaderData& header, DIRECTION direction, AUDIO_SOURCE source); + virtual bool process(CAMBEData& data, DIRECTION direction, AUDIO_SOURCE source); + virtual bool process(CDDData& data); + + virtual void linkUp(DSTAR_PROTOCOL protocol, const wxString& callsign); + virtual void linkRefused(DSTAR_PROTOCOL protocol, const wxString& callsign); + virtual bool linkFailed(DSTAR_PROTOCOL protocol, const wxString& callsign, bool isRecoverable); + + virtual void ccsLinkMade(const wxString& callsign, DIRECTION direction); + virtual void ccsLinkFailed(const wxString& dtmf, DIRECTION direction); + virtual void ccsLinkEnded(const wxString& callsign, DIRECTION direction); + +protected: + CRepeaterHandler(const wxString& callsign, const wxString& band, const wxString& address, unsigned int port, HW_TYPE hwType, const wxString& reflector, bool atStartup, RECONNECT reconnect, bool dratsEnabled, double frequency, double offset, double range, double latitude, double longitude, double agl, const wxString& description1, const wxString& description2, const wxString& url, IRepeaterProtocolHandler* handler, unsigned char band1, unsigned char band2, unsigned char band3); + virtual ~CRepeaterHandler(); + + void resolveUserInt(const wxString& user, const wxString& repeater, const wxString& gateway, const wxString& address); + void resolveRepeaterInt(const wxString& repeater, const wxString& gateway, const wxString& address, DSTAR_PROTOCOL protocol); + + void startupInt(); + + void setIndex(unsigned int index); + + void clockInt(unsigned int ms); + +private: + static unsigned int m_maxRepeaters; + static CRepeaterHandler** m_repeaters; + + static wxString m_localAddress; + static CG2ProtocolHandler* m_g2Handler; + static CCacheManager* m_cache; + static wxString m_gateway; + static CIRCDDB* m_irc; + static TEXT_LANG m_language; + static bool m_dextraEnabled; + static bool m_dplusEnabled; + static bool m_dcsEnabled; + static bool m_infoEnabled; + static bool m_echoEnabled; + static bool m_dtmfEnabled; + + static CHeaderLogger* m_headerLogger; + + static CAPRSWriter* m_aprsWriter; + + static CCallsignList* m_whiteList; + static CCallsignList* m_blackList; + static CCallsignList* m_restrictList; + + // Repeater info + unsigned int m_index; + wxString m_rptCallsign; + wxString m_gwyCallsign; + unsigned char m_band; + in_addr m_address; + unsigned int m_port; + HW_TYPE m_hwType; + IRepeaterProtocolHandler* m_repeaterHandler; + double m_frequency; + double m_offset; + double m_range; + double m_latitude; + double m_longitude; + double m_agl; + wxString m_description1; + wxString m_description2; + wxString m_url; + unsigned char m_band1; + unsigned char m_band2; + unsigned char m_band3; + unsigned int m_repeaterId; + unsigned int m_busyId; + CTimer m_watchdogTimer; + bool m_ddMode; + wxString m_ddCallsign; + CTimer m_queryTimer; + + // User details + wxString m_myCall1; + wxString m_myCall2; + wxString m_yourCall; + wxString m_rptCall1; + wxString m_rptCall2; + unsigned char m_flag1; + unsigned char m_flag2; + unsigned char m_flag3; + bool m_restricted; + + // Statistics + unsigned int m_frames; + unsigned int m_silence; + unsigned int m_errors; + + // Slow data handling + CTextCollector m_textCollector; + wxString m_text; + + // Cross-band repeating + CRepeaterHandler* m_xBandRptr; + + // StarNet + CStarNetHandler* m_starNet; + + // G2 info + G2_STATUS m_g2Status; + wxString m_g2User; + wxString m_g2Repeater; + wxString m_g2Gateway; + CHeaderData* m_g2Header; + in_addr m_g2Address; + + // Link info + LINK_STATUS m_linkStatus; + wxString m_linkRepeater; + wxString m_linkGateway; + RECONNECT m_linkReconnect; + bool m_linkAtStartup; + wxString m_linkStartup; + CTimer m_linkReconnectTimer; + bool m_linkRelink; + + // Echoing + CEchoUnit* m_echo; + + // Voice messages + CAudioUnit* m_infoAudio; + bool m_infoNeeded; + CAnnouncementUnit* m_msgAudio; + bool m_msgNeeded; + CAnnouncementUnit* m_wxAudio; + bool m_wxNeeded; + + // Version information + CVersionUnit* m_version; + + // D-RATS handler + CDRATSServer* m_drats; + + // DTMF commands + CDTMF m_dtmf; + + // Poll timer + CTimer m_pollTimer; + + // CCS + CCCSHandler* m_ccsHandler; + + // Reflector restoration + wxString m_lastReflector; + + // Icom heard data + wxString m_heardUser; + wxString m_heardRepeater; + CTimer m_heardTimer; + + void g2CommandHandler(const wxString& callsign, const wxString& user, CHeaderData& header); + void ccsCommandHandler(const wxString& callsign, const wxString& user, const wxString& type); + void reflectorCommandHandler(const wxString& callsign, const wxString& user, const wxString& type); + void sendToOutgoing(const CHeaderData& header); + void sendToOutgoing(const CAMBEData& data); + void sendToIncoming(const CHeaderData& header); + void sendToIncoming(const CAMBEData& data); + + void writeIsBusy(const wxString& callsign); + void writeLinkedTo(const wxString& callsign); + void writeLinkingTo(const wxString& callsign); + void writeNotLinked(); + + void sendHeard(const wxString& text = wxEmptyString); + void sendStats(); + + void linkInt(const wxString& callsign); + + void suspendLinks(); + bool restoreLinks(); + + void triggerInfo(); + + bool isCCSCommand(const wxString& command) const; +}; + +#endif diff --git a/Common/RepeaterProtocolHandler.h b/Common/RepeaterProtocolHandler.h new file mode 100644 index 0000000..3486a98 --- /dev/null +++ b/Common/RepeaterProtocolHandler.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2010-2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef RepeaterProtocolHandler_H +#define RepeaterProtocolHandler_H + +#include "HeaderData.h" +#include "StatusData.h" +#include "HeardData.h" +#include "AMBEData.h" +#include "TextData.h" +#include "PollData.h" +#include "DDData.h" + +#include + +enum REPEATER_TYPE { + RT_NONE, + RT_POLL, + RT_HEARD, + RT_HEADER, + RT_AMBE, + RT_BUSY_HEADER, + RT_BUSY_AMBE, + RT_DD +}; + +class IRepeaterProtocolHandler { +public: + virtual bool open() = 0; + + virtual bool writeHeader(CHeaderData& header) = 0; + virtual bool writeAMBE(CAMBEData& data) = 0; + virtual bool writeDD(CDDData& data) = 0; + virtual bool writeText(CTextData& text) = 0; + virtual bool writeStatus(CStatusData& status) = 0; + + virtual REPEATER_TYPE read() = 0; + virtual CPollData* readPoll() = 0; + virtual CHeardData* readHeard() = 0; + virtual CHeaderData* readHeader() = 0; + virtual CAMBEData* readAMBE() = 0; + virtual CDDData* readDD() = 0; + virtual CHeaderData* readBusyHeader() = 0; + virtual CAMBEData* readBusyAMBE() = 0; + + virtual void close() = 0; + +private: +}; + +#endif diff --git a/Common/RingBuffer.h b/Common/RingBuffer.h new file mode 100644 index 0000000..4a180dd --- /dev/null +++ b/Common/RingBuffer.h @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2006-2009,2013,2015 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef RingBuffer_H +#define RingBuffer_H + +#include + +template class CRingBuffer { +public: + CRingBuffer(unsigned int length) : + m_length(length), + m_buffer(NULL), + m_iPtr(0U), + m_oPtr(0U), + m_mutex() + { + wxASSERT(length > 0U); + + m_buffer = new T[length]; + + ::memset(m_buffer, 0x00, length * sizeof(T)); + } + + ~CRingBuffer() + { + delete[] m_buffer; + } + + void addData(const T data) + { + wxMutexLocker locker(m_mutex); + + m_buffer[m_iPtr++] = data; + + if (m_iPtr == m_length) + m_iPtr = 0U; + } + + T getData() + { + wxMutexLocker locker(m_mutex); + + if (m_iPtr == m_oPtr) + return NULL; + + T data = m_buffer[m_oPtr++]; + + if (m_oPtr == m_length) + m_oPtr = 0U; + + return data; + } + + void clear() + { + wxMutexLocker locker(m_mutex); + + m_iPtr = 0U; + m_oPtr = 0U; + + ::memset(m_buffer, 0x00, m_length * sizeof(T)); + } + + bool isEmpty() + { + wxMutexLocker locker(m_mutex); + + return m_iPtr == m_oPtr; + } + + T peek() + { + wxMutexLocker locker(m_mutex); + + if (m_iPtr == m_oPtr) + return NULL; + + return m_buffer[m_oPtr]; + } + +private: + unsigned int m_length; + T* m_buffer; + volatile unsigned int m_iPtr; + volatile unsigned int m_oPtr; + wxMutex m_mutex; +}; + +#endif diff --git a/Common/SHA256.cpp b/Common/SHA256.cpp new file mode 100644 index 0000000..3aceee2 --- /dev/null +++ b/Common/SHA256.cpp @@ -0,0 +1,369 @@ +/* + * Copyright (C) 2005, 2006, 2008 Free Software Foundation, Inc. + * Copyright (C) 2011 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "SHA256.h" + +#ifdef WORDS_BIGENDIAN +# define SWAP(n) (n) +#else +# define SWAP(n) \ + (((n) << 24) | (((n) & 0xff00) << 8) | (((n) >> 8) & 0xff00) | ((n) >> 24)) +#endif + +#define BLOCKSIZE 4096 +#if BLOCKSIZE % 64 != 0 +# error "invalid BLOCKSIZE" +#endif + +/* This array contains the bytes used to pad the buffer to the next + 64-byte boundary. */ +static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ }; + + +/* + Takes a pointer to a 256 bit block of data (eight 32 bit ints) and + intializes it to the start constants of the SHA256 algorithm. This + must be called before using hash in the call to sha256_hash +*/ +CSHA256::CSHA256() : +m_state(NULL), +m_total(NULL), +m_buflen(0U), +m_buffer(NULL) +{ + m_state = new wxUint32[8U]; + m_total = new wxUint32[2U]; + m_buffer = new wxUint32[32U]; + + init(); +} + +CSHA256::~CSHA256() +{ + delete[] m_state; + delete[] m_total; + delete[] m_buffer; +} + +void CSHA256::init() +{ + m_state[0] = 0x6a09e667UL; + m_state[1] = 0xbb67ae85UL; + m_state[2] = 0x3c6ef372UL; + m_state[3] = 0xa54ff53aUL; + m_state[4] = 0x510e527fUL; + m_state[5] = 0x9b05688cUL; + m_state[6] = 0x1f83d9abUL; + m_state[7] = 0x5be0cd19UL; + + m_total[0] = m_total[1] = 0; + m_buflen = 0; +} + +/* Copy the value from v into the memory location pointed to by *cp, + If your architecture allows unaligned access this is equivalent to + * (uint32_t *) cp = v */ +static inline void set_uint32(unsigned char* cp, wxUint32 v) +{ + wxASSERT(cp != NULL); + + ::memcpy(cp, &v, sizeof v); +} + +/* Put result from CTX in first 32 bytes following RESBUF. The result + must be in little endian byte order. */ +unsigned char* CSHA256::read(unsigned char* resbuf) +{ + wxASSERT(resbuf != NULL); + + for (unsigned int i = 0U; i < 8U; i++) + set_uint32(resbuf + i * sizeof(m_state[0]), SWAP(m_state[i])); + + return resbuf; +} + +/* Process the remaining bytes in the internal buffer and the usual + prolog according to the standard and write the result to RESBUF. */ +void CSHA256::conclude() +{ + /* Take yet unprocessed bytes into account. */ + unsigned int bytes = m_buflen; + unsigned int size = (bytes < 56) ? 64 / 4 : 64 * 2 / 4; + + /* Now count remaining bytes. */ + m_total[0] += bytes; + if (m_total[0] < bytes) + ++m_total[1]; + + /* Put the 64-bit file length in *bits* at the end of the buffer. + Use set_uint32 rather than a simple assignment, to avoid risk of + unaligned access. */ + set_uint32((unsigned char*)&m_buffer[size - 2], SWAP((m_total[1] << 3) | (m_total[0] >> 29))); + set_uint32((unsigned char*)&m_buffer[size - 1], SWAP(m_total[0] << 3)); + + ::memcpy(&((char*)m_buffer)[bytes], fillbuf, (size - 2) * 4 - bytes); + + /* Process last bytes. */ + processBlock((unsigned char*)m_buffer, size * 4); +} + +unsigned char* CSHA256::finish(unsigned char* resbuf) +{ + wxASSERT(resbuf != NULL); + + conclude(); + + return read(resbuf); +} + +/* Compute SHA256 message digest for LEN bytes beginning at BUFFER. The + result is always in little endian byte order, so that a byte-wise + output yields to the wanted ASCII representation of the message + digest. */ +unsigned char* CSHA256::buffer(const unsigned char* buffer, unsigned int len, unsigned char* resblock) +{ + wxASSERT(buffer != NULL); + wxASSERT(resblock != NULL); + + /* Initialize the computation context. */ + init(); + + /* Process whole buffer but last len % 64 bytes. */ + processBytes(buffer, len); + + /* Put result in desired memory area. */ + return finish(resblock); +} + +void CSHA256::processBytes(const unsigned char* buffer, unsigned int len) +{ + wxASSERT(buffer != NULL); + + /* When we already have some bits in our internal buffer concatenate + both inputs first. */ + if (m_buflen != 0U) { + unsigned int left_over = m_buflen; + unsigned int add = 128U - left_over > len ? len : 128U - left_over; + + ::memcpy(&((char*)m_buffer)[left_over], buffer, add); + m_buflen += add; + + if (m_buflen > 64U) { + processBlock((unsigned char*)m_buffer, m_buflen & ~63U); + + m_buflen &= 63U; + + /* The regions in the following copy operation cannot overlap. */ + ::memcpy(m_buffer, &((char*)m_buffer)[(left_over + add) & ~63U], m_buflen); + } + + buffer += add; + len -= add; + } + + /* Process available complete blocks. */ + if (len >= 64U) { +//#if !_STRING_ARCH_unaligned +//# define alignof(type) offsetof (struct { char c; type x; }, x) +//# define UNALIGNED_P(p) (((unsigned int) p) % alignof (wxUint32) != 0) +// if (UNALIGNED_P (buffer)) { +// while (len > 64U) { +// ::memcpy(m_buffer, buffer, 64U); +// processBlock((unsigned char*)m_buffer, 64U); +// buffer += 64U; +// len -= 64U; +// } +// } else +//#endif + { + processBlock(buffer, len & ~63U); + buffer += (len & ~63U); + len &= 63U; + } + } + + /* Move remaining bytes in internal buffer. */ + if (len > 0U) { + unsigned int left_over = m_buflen; + + ::memcpy(&((char*)m_buffer)[left_over], buffer, len); + left_over += len; + + if (left_over >= 64U) { + processBlock((unsigned char*)m_buffer, 64U); + left_over -= 64U; + ::memcpy(m_buffer, &m_buffer[16], left_over); + } + + m_buflen = left_over; + } +} + +/* --- Code below is the primary difference between sha1.c and sha256.c --- */ + +/* SHA256 round constants */ +#define K(I) roundConstants[I] +static const wxUint32 roundConstants[64] = { + 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, + 0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, + 0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL, + 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL, + 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL, + 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, + 0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, + 0xc6e00bf3UL, 0xd5a79147UL, 0x06ca6351UL, 0x14292967UL, + 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL, + 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL, + 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, + 0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, + 0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL, + 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL, + 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL, + 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL, +}; + +/* Round functions. */ +#define F2(A,B,C) ( ( A & B ) | ( C & ( A | B ) ) ) +#define F1(E,F,G) ( G ^ ( E & ( F ^ G ) ) ) + +/* Process LEN bytes of BUFFER, accumulating context into CTX. + It is assumed that LEN % 64 == 0. + Most of this code comes from GnuPG's cipher/sha1.c. */ + +void CSHA256::processBlock(const unsigned char* buffer, unsigned int len) +{ + wxASSERT(buffer != NULL); + + const wxUint32* words = (wxUint32*)buffer; + unsigned int nwords = len / sizeof(wxUint32); + const wxUint32* endp = words + nwords; + wxUint32 x[16]; + wxUint32 a = m_state[0]; + wxUint32 b = m_state[1]; + wxUint32 c = m_state[2]; + wxUint32 d = m_state[3]; + wxUint32 e = m_state[4]; + wxUint32 f = m_state[5]; + wxUint32 g = m_state[6]; + wxUint32 h = m_state[7]; + + /* First increment the byte count. FIPS PUB 180-2 specifies the possible + length of the file up to 2^64 bits. Here we only compute the + number of bytes. Do a double word increment. */ + m_total[0] += len; + if (m_total[0] < len) + ++m_total[1]; + + #define rol(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) + #define S0(x) (rol(x,25)^rol(x,14)^(x>>3)) + #define S1(x) (rol(x,15)^rol(x,13)^(x>>10)) + #define SS0(x) (rol(x,30)^rol(x,19)^rol(x,10)) + #define SS1(x) (rol(x,26)^rol(x,21)^rol(x,7)) + + #define M(I) (tm = S1(x[(I-2)&0x0f]) + x[(I-7)&0x0f] + S0(x[(I-15)&0x0f]) + x[I&0x0f], x[I&0x0f] = tm) + + #define R(A,B,C,D,E,F,G,H,K,M) do { t0 = SS0(A) + F2(A,B,C); \ + t1 = H + SS1(E) + F1(E,F,G) + K + M; \ + D += t1; H = t0 + t1; \ + } while(0) + + while (words < endp) { + wxUint32 tm; + wxUint32 t0, t1; + /* FIXME: see sha1.c for a better implementation. */ + for (unsigned int t = 0U; t < 16U; t++) { + x[t] = SWAP(*words); + words++; + } + + R( a, b, c, d, e, f, g, h, K( 0), x[ 0] ); + R( h, a, b, c, d, e, f, g, K( 1), x[ 1] ); + R( g, h, a, b, c, d, e, f, K( 2), x[ 2] ); + R( f, g, h, a, b, c, d, e, K( 3), x[ 3] ); + R( e, f, g, h, a, b, c, d, K( 4), x[ 4] ); + R( d, e, f, g, h, a, b, c, K( 5), x[ 5] ); + R( c, d, e, f, g, h, a, b, K( 6), x[ 6] ); + R( b, c, d, e, f, g, h, a, K( 7), x[ 7] ); + R( a, b, c, d, e, f, g, h, K( 8), x[ 8] ); + R( h, a, b, c, d, e, f, g, K( 9), x[ 9] ); + R( g, h, a, b, c, d, e, f, K(10), x[10] ); + R( f, g, h, a, b, c, d, e, K(11), x[11] ); + R( e, f, g, h, a, b, c, d, K(12), x[12] ); + R( d, e, f, g, h, a, b, c, K(13), x[13] ); + R( c, d, e, f, g, h, a, b, K(14), x[14] ); + R( b, c, d, e, f, g, h, a, K(15), x[15] ); + R( a, b, c, d, e, f, g, h, K(16), M(16) ); + R( h, a, b, c, d, e, f, g, K(17), M(17) ); + R( g, h, a, b, c, d, e, f, K(18), M(18) ); + R( f, g, h, a, b, c, d, e, K(19), M(19) ); + R( e, f, g, h, a, b, c, d, K(20), M(20) ); + R( d, e, f, g, h, a, b, c, K(21), M(21) ); + R( c, d, e, f, g, h, a, b, K(22), M(22) ); + R( b, c, d, e, f, g, h, a, K(23), M(23) ); + R( a, b, c, d, e, f, g, h, K(24), M(24) ); + R( h, a, b, c, d, e, f, g, K(25), M(25) ); + R( g, h, a, b, c, d, e, f, K(26), M(26) ); + R( f, g, h, a, b, c, d, e, K(27), M(27) ); + R( e, f, g, h, a, b, c, d, K(28), M(28) ); + R( d, e, f, g, h, a, b, c, K(29), M(29) ); + R( c, d, e, f, g, h, a, b, K(30), M(30) ); + R( b, c, d, e, f, g, h, a, K(31), M(31) ); + R( a, b, c, d, e, f, g, h, K(32), M(32) ); + R( h, a, b, c, d, e, f, g, K(33), M(33) ); + R( g, h, a, b, c, d, e, f, K(34), M(34) ); + R( f, g, h, a, b, c, d, e, K(35), M(35) ); + R( e, f, g, h, a, b, c, d, K(36), M(36) ); + R( d, e, f, g, h, a, b, c, K(37), M(37) ); + R( c, d, e, f, g, h, a, b, K(38), M(38) ); + R( b, c, d, e, f, g, h, a, K(39), M(39) ); + R( a, b, c, d, e, f, g, h, K(40), M(40) ); + R( h, a, b, c, d, e, f, g, K(41), M(41) ); + R( g, h, a, b, c, d, e, f, K(42), M(42) ); + R( f, g, h, a, b, c, d, e, K(43), M(43) ); + R( e, f, g, h, a, b, c, d, K(44), M(44) ); + R( d, e, f, g, h, a, b, c, K(45), M(45) ); + R( c, d, e, f, g, h, a, b, K(46), M(46) ); + R( b, c, d, e, f, g, h, a, K(47), M(47) ); + R( a, b, c, d, e, f, g, h, K(48), M(48) ); + R( h, a, b, c, d, e, f, g, K(49), M(49) ); + R( g, h, a, b, c, d, e, f, K(50), M(50) ); + R( f, g, h, a, b, c, d, e, K(51), M(51) ); + R( e, f, g, h, a, b, c, d, K(52), M(52) ); + R( d, e, f, g, h, a, b, c, K(53), M(53) ); + R( c, d, e, f, g, h, a, b, K(54), M(54) ); + R( b, c, d, e, f, g, h, a, K(55), M(55) ); + R( a, b, c, d, e, f, g, h, K(56), M(56) ); + R( h, a, b, c, d, e, f, g, K(57), M(57) ); + R( g, h, a, b, c, d, e, f, K(58), M(58) ); + R( f, g, h, a, b, c, d, e, K(59), M(59) ); + R( e, f, g, h, a, b, c, d, K(60), M(60) ); + R( d, e, f, g, h, a, b, c, K(61), M(61) ); + R( c, d, e, f, g, h, a, b, K(62), M(62) ); + R( b, c, d, e, f, g, h, a, K(63), M(63) ); + + a = m_state[0] += a; + b = m_state[1] += b; + c = m_state[2] += c; + d = m_state[3] += d; + e = m_state[4] += e; + f = m_state[5] += f; + g = m_state[6] += g; + h = m_state[7] += h; + } +} diff --git a/Common/SHA256.h b/Common/SHA256.h new file mode 100644 index 0000000..1a3577a --- /dev/null +++ b/Common/SHA256.h @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2005, 2006, 2008, 2009 Free Software Foundation, Inc. + * Copyright (C) 2011 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef SHA256_H +#define SHA256_H + +#include + +enum { + SHA256_DIGEST_SIZE = 256 / 8 +}; + +class CSHA256 { +public: + CSHA256(); + ~CSHA256(); + + /* Starting with the result of former calls of this function (or the + initialization function update the context for the next LEN bytes + starting at BUFFER. + It is necessary that LEN is a multiple of 64!!! */ + void processBlock(const unsigned char* buffer, unsigned int len); + + /* Starting with the result of former calls of this function (or the + initialization function update the context for the next LEN bytes + starting at BUFFER. + It is NOT required that LEN is a multiple of 64. */ + void processBytes(const unsigned char* buffer, unsigned int len); + + /* Process the remaining bytes in the buffer and put result from CTX + in first 32 bytes following RESBUF. The result is always in little + endian byte order, so that a byte-wise output yields to the wanted + ASCII representation of the message digest. */ + unsigned char* finish(unsigned char* resbuf); + + /* Put result from CTX in first 32 bytes following RESBUF. The result is + always in little endian byte order, so that a byte-wise output yields + to the wanted ASCII representation of the message digest. */ + unsigned char* read(unsigned char* resbuf); + + /* Compute SHA256 message digest for LEN bytes beginning at BUFFER. The + result is always in little endian byte order, so that a byte-wise + output yields to the wanted ASCII representation of the message + digest. */ + unsigned char* buffer(const unsigned char* buffer, unsigned int len, unsigned char* resblock); + +private: + wxUint32* m_state; + wxUint32* m_total; + unsigned int m_buflen; + wxUint32* m_buffer; + + void init(); + void conclude(); +}; + +#endif diff --git a/Common/SlowDataEncoder.cpp b/Common/SlowDataEncoder.cpp new file mode 100644 index 0000000..c22c500 --- /dev/null +++ b/Common/SlowDataEncoder.cpp @@ -0,0 +1,358 @@ +/* + * Copyright (C) 2010 by Jonathan Naylor, G4KLX + * + * 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 + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "SlowDataEncoder.h" +#include "CCITTChecksum.h" +#include "DStarDefines.h" + +const unsigned int SLOW_DATA_BLOCK_SIZE = 6U; + +const unsigned int SLOW_DATA_FULL_BLOCK_SIZE = SLOW_DATA_BLOCK_SIZE * 10U; + +const unsigned char SLOW_DATA_FILLER_BYTES[] = {'f', 'f', 'f' }; + +const unsigned int HEADER_SIZE = 54U; +const unsigned int TEXT_SIZE = 24U; + +CSlowDataEncoder::CSlowDataEncoder() : +m_headerData(NULL), +m_textData(NULL), +m_gpsData(NULL), +m_interleavedData(NULL), +m_headerPtr(0U), +m_textPtr(0U), +m_gpsPtr(0U), +m_interleavedPtr(0U), +m_gpsDataSize(0U), +m_gpsDataFullSize(0U), +m_interleavedDataFullSize(0U) +{ +} + +CSlowDataEncoder::~CSlowDataEncoder() +{ + reset(); +} + +void CSlowDataEncoder::clearHeaderData() +{ + if(m_headerData) + { + delete[] m_headerData; + m_headerData = NULL; + m_headerPtr = 0U; + } +} + +void CSlowDataEncoder::clearTextData() +{ + if(m_textData) + { + delete[] m_textData; + m_textData = NULL; + m_textPtr = 0U; + } +} + +void CSlowDataEncoder::clearGPSData() +{ + if(m_gpsData) + { + delete[] m_gpsData; + m_gpsData = NULL; + m_gpsPtr = 0U; + } +} + +void CSlowDataEncoder::clearInterleavedData() +{ + if(m_interleavedData) + { + delete[] m_interleavedData; + m_interleavedData = NULL; + m_interleavedPtr = 0U; + } +} + +void CSlowDataEncoder::getData(unsigned char* source, unsigned char* data, unsigned int &sourcePtr, unsigned int sourceLength) +{ + wxASSERT(data != NULL); + if(source != NULL){ + data[0U] = source[sourcePtr++] ^ SCRAMBLER_BYTE1; + data[1U] = source[sourcePtr++] ^ SCRAMBLER_BYTE2; + data[2U] = source[sourcePtr++] ^ SCRAMBLER_BYTE3; + } + else{ + data[0U] = SLOW_DATA_FILLER_BYTES[sourcePtr++] ^ SCRAMBLER_BYTE1; + data[1U] = SLOW_DATA_FILLER_BYTES[sourcePtr++] ^ SCRAMBLER_BYTE2; + data[2U] = SLOW_DATA_FILLER_BYTES[sourcePtr++] ^ SCRAMBLER_BYTE3; + } + + if (sourcePtr >= sourceLength) + sourcePtr = 0U; +} + +void CSlowDataEncoder::getHeaderData(unsigned char* data) +{ + getData(m_headerData, data, m_headerPtr, SLOW_DATA_FULL_BLOCK_SIZE); +} + +void CSlowDataEncoder::getTextData(unsigned char* data) +{ + getData(m_textData, data, m_textPtr, SLOW_DATA_FULL_BLOCK_SIZE); +} + +void CSlowDataEncoder::getGPSData(unsigned char* data) +{ + getData(m_gpsData, data, m_gpsPtr, m_gpsDataFullSize); +} + +void CSlowDataEncoder::getInterleavedData(unsigned char* data) +{ + if(m_textData && !m_gpsData && !m_headerData) + getTextData(data); + else if(!m_textData && m_gpsData && !m_headerData) + getGPSData(data); + else if(!m_textData && !m_gpsData && m_headerData) + getHeaderData(data); + else { + buildInterleavedData(); + getData(m_interleavedData, data, m_interleavedPtr, m_gpsDataFullSize); + } +} + +void CSlowDataEncoder::buildInterleavedData() +{ + //first build interleaved data if we do not have it + if(!m_interleavedData) + { + getInterleavedDataLength(); + m_interleavedData = new unsigned char[m_interleavedDataFullSize]; + ::memset(m_interleavedData, 'f', m_interleavedDataFullSize); + + unsigned int textPtr = 0U; + unsigned int gpsPtr = 0U; + unsigned int headerPtr = 0U; + + //now proceed with data copying, according to this document http://www.qsl.net/kb9mwr/projects/dv/dstar/Slow%20Data.pdf + if(m_textData && m_gpsData){ + for(unsigned int interleavedPtr = 0; interleavedPtr < m_interleavedDataFullSize; interleavedPtr += SLOW_DATA_BLOCK_SIZE){ + if(textPtr < TEXT_SIZE + && ((interleavedPtr / SLOW_DATA_BLOCK_SIZE) & 0x01U) == 0) + { + ::memcpy(m_interleavedData + interleavedPtr, m_textData + textPtr, SLOW_DATA_BLOCK_SIZE); + textPtr += SLOW_DATA_BLOCK_SIZE; + } + else if(gpsPtr < m_gpsDataSize){ + ::memcpy(m_interleavedData + interleavedPtr, m_gpsData + gpsPtr, SLOW_DATA_BLOCK_SIZE); + gpsPtr += SLOW_DATA_BLOCK_SIZE; + } + else if(m_headerData && headerPtr < HEADER_SIZE){ + ::memcpy(m_interleavedData + interleavedPtr, m_headerData + headerPtr, SLOW_DATA_BLOCK_SIZE); + headerPtr += SLOW_DATA_BLOCK_SIZE; + } + } + } + else if(m_textData && !m_gpsData && m_headerData){ + //according to above doc, header and text are not interleaved, just on after the other. filler bytes between resync bytes. + ::memcpy(m_interleavedData, m_textData, SLOW_DATA_FULL_BLOCK_SIZE); + ::memcpy(m_interleavedData + SLOW_DATA_FULL_BLOCK_SIZE, m_headerData, SLOW_DATA_FULL_BLOCK_SIZE); + } + else if(!m_textData && m_gpsData && m_headerData){ + //could not find any spec about this particular case, let's put the data one after the other + ::memcpy(m_interleavedData, m_gpsData, SLOW_DATA_FULL_BLOCK_SIZE); + ::memcpy(m_interleavedData + SLOW_DATA_FULL_BLOCK_SIZE, m_headerData, SLOW_DATA_FULL_BLOCK_SIZE); + } + } +} + +unsigned int CSlowDataEncoder::getInterleavedDataLength() +{ + //calculate size (including filler bytes); + m_interleavedDataFullSize = 0U; + if(m_textData) m_interleavedDataFullSize += TEXT_SIZE; + if(m_headerData) m_interleavedDataFullSize += HEADER_SIZE; + if(m_gpsData) m_interleavedDataFullSize += m_gpsDataSize; + m_interleavedDataFullSize = SLOW_DATA_FULL_BLOCK_SIZE * (1U + ((m_interleavedDataFullSize - 1U) / SLOW_DATA_FULL_BLOCK_SIZE)); + return m_interleavedDataFullSize; +} + +void CSlowDataEncoder::sync() +{ + m_headerPtr = 0U; + m_textPtr = 0U; + m_gpsPtr = 0U; + m_interleavedPtr = 0U; +} + +void CSlowDataEncoder::reset() +{ + clearHeaderData(); + clearTextData(); + clearGPSData(); + clearInterleavedData(); +} + +void CSlowDataEncoder::setHeaderData(const CHeaderData& header) +{ + clearInterleavedData(); + if(!m_headerData) m_headerData = new unsigned char[SLOW_DATA_FULL_BLOCK_SIZE]; + ::memset(m_headerData, 'f', SLOW_DATA_FULL_BLOCK_SIZE); + + m_headerData[0U] = SLOW_DATA_TYPE_HEADER | 5U; + m_headerData[1U] = header.getFlag1(); + m_headerData[2U] = header.getFlag2(); + m_headerData[3U] = header.getFlag3(); + m_headerData[4U] = header.getRptCall2().GetChar(0); + m_headerData[5U] = header.getRptCall2().GetChar(1); + + m_headerData[6U] = SLOW_DATA_TYPE_HEADER | 5U; + m_headerData[7U] = header.getRptCall2().GetChar(2); + m_headerData[8U] = header.getRptCall2().GetChar(3); + m_headerData[9U] = header.getRptCall2().GetChar(4); + m_headerData[10U] = header.getRptCall2().GetChar(5); + m_headerData[11U] = header.getRptCall2().GetChar(6); + + m_headerData[12U] = SLOW_DATA_TYPE_HEADER | 5U; + m_headerData[13U] = header.getRptCall2().GetChar(7); + m_headerData[14U] = header.getRptCall1().GetChar(0); + m_headerData[15U] = header.getRptCall1().GetChar(1); + m_headerData[16U] = header.getRptCall1().GetChar(2); + m_headerData[17U] = header.getRptCall1().GetChar(3); + + m_headerData[18U] = SLOW_DATA_TYPE_HEADER | 5U; + m_headerData[19U] = header.getRptCall1().GetChar(4); + m_headerData[20U] = header.getRptCall1().GetChar(5); + m_headerData[21U] = header.getRptCall1().GetChar(6); + m_headerData[22U] = header.getRptCall1().GetChar(7); + m_headerData[23U] = header.getYourCall().GetChar(0); + + m_headerData[24U] = SLOW_DATA_TYPE_HEADER | 5U; + m_headerData[25U] = header.getYourCall().GetChar(1); + m_headerData[26U] = header.getYourCall().GetChar(2); + m_headerData[27U] = header.getYourCall().GetChar(3); + m_headerData[28U] = header.getYourCall().GetChar(4); + m_headerData[29U] = header.getYourCall().GetChar(5); + + m_headerData[30U] = SLOW_DATA_TYPE_HEADER | 5U; + m_headerData[31U] = header.getYourCall().GetChar(6); + m_headerData[32U] = header.getYourCall().GetChar(7); + m_headerData[33U] = header.getMyCall1().GetChar(0); + m_headerData[34U] = header.getMyCall1().GetChar(1); + m_headerData[35U] = header.getMyCall1().GetChar(2); + + m_headerData[36U] = SLOW_DATA_TYPE_HEADER | 5U; + m_headerData[37U] = header.getMyCall1().GetChar(3); + m_headerData[38U] = header.getMyCall1().GetChar(4); + m_headerData[39U] = header.getMyCall1().GetChar(5); + m_headerData[40U] = header.getMyCall1().GetChar(6); + m_headerData[41U] = header.getMyCall1().GetChar(7); + + m_headerData[42U] = SLOW_DATA_TYPE_HEADER | 5U; + m_headerData[43U] = header.getMyCall2().GetChar(0); + m_headerData[44U] = header.getMyCall2().GetChar(1); + m_headerData[45U] = header.getMyCall2().GetChar(2); + m_headerData[46U] = header.getMyCall2().GetChar(3); + + CCCITTChecksum cksum; + cksum.update(m_headerData + 1U, 5U); + cksum.update(m_headerData + 7U, 5U); + cksum.update(m_headerData + 13U, 5U); + cksum.update(m_headerData + 19U, 5U); + cksum.update(m_headerData + 25U, 5U); + cksum.update(m_headerData + 31U, 5U); + cksum.update(m_headerData + 37U, 5U); + cksum.update(m_headerData + 43U, 4U); + + unsigned char checkSum[2U]; + cksum.result(checkSum); + + m_headerData[47U] = checkSum[0]; + + m_headerData[48U] = SLOW_DATA_TYPE_HEADER | 1U; + m_headerData[49U] = checkSum[1]; + + m_headerPtr = 0U; +} + +void CSlowDataEncoder::setTextData(const wxString& text) +{ + clearInterleavedData(); + if(!m_textData) m_textData = new unsigned char[SLOW_DATA_FULL_BLOCK_SIZE]; + ::memset(m_textData, 'f', SLOW_DATA_FULL_BLOCK_SIZE); + + wxString paddedText = text; + paddedText.Append(wxT(" ")); + paddedText.Truncate(20U); + + m_textData[0U] = SLOW_DATA_TYPE_TEXT | 0U; + m_textData[1U] = paddedText.GetChar(0); + m_textData[2U] = paddedText.GetChar(1); + m_textData[3U] = paddedText.GetChar(2); + m_textData[4U] = paddedText.GetChar(3); + m_textData[5U] = paddedText.GetChar(4); + + m_textData[6U] = SLOW_DATA_TYPE_TEXT | 1U; + m_textData[7U] = paddedText.GetChar(5); + m_textData[8U] = paddedText.GetChar(6); + m_textData[9U] = paddedText.GetChar(7); + m_textData[10U] = paddedText.GetChar(8); + m_textData[11U] = paddedText.GetChar(9); + + m_textData[12U] = SLOW_DATA_TYPE_TEXT | 2U; + m_textData[13U] = paddedText.GetChar(10); + m_textData[14U] = paddedText.GetChar(11); + m_textData[15U] = paddedText.GetChar(12); + m_textData[16U] = paddedText.GetChar(13); + m_textData[17U] = paddedText.GetChar(14); + + m_textData[18U] = SLOW_DATA_TYPE_TEXT | 3U; + m_textData[19U] = paddedText.GetChar(15); + m_textData[20U] = paddedText.GetChar(16); + m_textData[21U] = paddedText.GetChar(17); + m_textData[22U] = paddedText.GetChar(18); + m_textData[23U] = paddedText.GetChar(19); + + m_textPtr = 0U; +} + +void CSlowDataEncoder::setGPSData(const wxString& gpsData) +{ + size_t gpsDataStrLen; + clearInterleavedData(); + + if(m_gpsData) delete[] m_gpsData; + m_gpsDataSize = 0U; + m_gpsPtr = 0U; + + if((gpsDataStrLen = gpsData.length()) > 0){ + unsigned int gpsDataPos; + unsigned int strPos = 0; + m_gpsDataSize = 1U + ((gpsDataStrLen - 1U) / 6U);//to make room for the type bytes + m_gpsDataSize += gpsDataStrLen; + m_gpsDataFullSize = SLOW_DATA_FULL_BLOCK_SIZE * (1U + ((m_gpsDataSize - 1U) / SLOW_DATA_FULL_BLOCK_SIZE)); + + m_gpsData = new unsigned char[m_gpsDataFullSize]; + ::memset(m_gpsData, 'f', m_gpsDataFullSize); + + for(gpsDataPos = 0; gpsDataPos < m_gpsDataFullSize;){ + unsigned int dataLen = gpsDataStrLen - strPos < 5U ? gpsDataStrLen - strPos : 5U; + m_gpsData[gpsDataPos++] = SLOW_DATA_TYPE_GPS | dataLen; + + for(unsigned int i = 0U; i < dataLen; i++){ + m_gpsData[gpsDataPos++] = gpsData.GetChar(strPos++); + } + } + } +} + diff --git a/Common/SlowDataEncoder.h b/Common/SlowDataEncoder.h new file mode 100644 index 0000000..5172466 --- /dev/null +++ b/Common/SlowDataEncoder.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2010 by Jonathan Naylor, G4KLX + * + * 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 + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef SlowDataEncoder_H +#define SlowDataEncoder_H + +#include "HeaderData.h" + +#include + +class CSlowDataEncoder { +public: + CSlowDataEncoder(); + ~CSlowDataEncoder(); + + + void setHeaderData(const CHeaderData& header); + void setTextData(const wxString& text); + void setGPSData(const wxString& gpsData); + + void clearHeaderData(); + void clearTextData(); + void clearGPSData(); + void clearInterleavedData(); + + void getHeaderData(unsigned char* data); + void getTextData(unsigned char* data); + void getGPSData(unsigned char* data); + + void getInterleavedData(unsigned char* data); + + unsigned int getInterleavedDataLength(); + + void reset(); + void sync(); + +private: + void getData(unsigned char* source, unsigned char* data, unsigned int &sourcePtr, unsigned int sourceLength); + void buildInterleavedData(); + + unsigned char* m_headerData; + unsigned char* m_textData; + unsigned char* m_gpsData; + unsigned char* m_interleavedData; + + unsigned int m_headerPtr; + unsigned int m_textPtr; + unsigned int m_gpsPtr; + unsigned int m_interleavedPtr; + + unsigned int m_gpsDataSize; //actual useful data size + unsigned int m_gpsDataFullSize; //size including filler bytes + + unsigned int m_interleavedDataFullSize; //size of interleaved data including filler bytes +}; + +#endif diff --git a/Common/StarNetHandler.cpp b/Common/StarNetHandler.cpp new file mode 100644 index 0000000..3b33a0a --- /dev/null +++ b/Common/StarNetHandler.cpp @@ -0,0 +1,1338 @@ +/* + * Copyright (C) 2011-2014 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "SlowDataEncoder.h" +#include "RepeaterHandler.h" +#include "StarNetHandler.h" +#include "DExtraHandler.h" // DEXTRA_LINK +#include "DStarDefines.h" +#include "DCSHandler.h" // DCS_LINK + +#include +#include +#include + +const unsigned int MESSAGE_DELAY = 4U; + +unsigned int CStarNetHandler::m_maxStarNets = 0U; +CStarNetHandler** CStarNetHandler::m_starNets = NULL; + +CG2ProtocolHandler* CStarNetHandler::m_g2Handler = NULL; +CIRCDDB* CStarNetHandler::m_irc = NULL; +CCacheManager* CStarNetHandler::m_cache = NULL; +wxString CStarNetHandler::m_gateway; + +wxString CStarNetHandler::m_name; +wxFFile* CStarNetHandler::m_logFile = NULL; + + +CStarNetUser::CStarNetUser(const wxString &callsign, unsigned int timeout) : +m_callsign(callsign), +m_timer(1000U, timeout) +{ + m_timer.start(); +} + +CStarNetUser::~CStarNetUser() +{ +} + +bool CStarNetUser::clock(unsigned int ms) +{ + m_timer.clock(ms); + + return m_timer.isRunning() && m_timer.hasExpired(); +} + +bool CStarNetUser::hasExpired() +{ + return m_timer.isRunning() && m_timer.hasExpired(); +} + +void CStarNetUser::reset() +{ + m_timer.start(); +} + +wxString CStarNetUser::getCallsign() const +{ + return m_callsign; +} + +CTimer CStarNetUser::getTimer() const +{ + return m_timer; +} + +CStarNetId::CStarNetId(unsigned int id, unsigned int timeout, CStarNetUser* user) : +m_id(id), +m_timer(1000U, timeout), +m_login(false), +m_info(false), +m_logoff(false), +m_end(false), +m_user(user), +m_textCollector() +{ + wxASSERT(user != NULL); + + m_timer.start(); +} + +CStarNetId::~CStarNetId() +{ +} + +unsigned int CStarNetId::getId() const +{ + return m_id; +} + +void CStarNetId::reset() +{ + m_timer.start(); +} + +void CStarNetId::setLogin() +{ + m_login = true; +} + +void CStarNetId::setInfo() +{ + if (!m_login && !m_logoff) + m_info = true; +} + +void CStarNetId::setLogoff() +{ + if (!m_login && !m_info) + m_logoff = true; +} + +void CStarNetId::setEnd() +{ + m_end = true; +} + +bool CStarNetId::clock(unsigned int ms) +{ + m_timer.clock(ms); + + return m_timer.isRunning() && m_timer.hasExpired(); +} + +bool CStarNetId::hasExpired() +{ + return m_timer.isRunning() && m_timer.hasExpired(); +} + +bool CStarNetId::isLogin() const +{ + return m_login; +} + +bool CStarNetId::isInfo() const +{ + return m_info; +} + +bool CStarNetId::isLogoff() const +{ + return m_logoff; +} + +bool CStarNetId::isEnd() const +{ + return m_end; +} + +CStarNetUser* CStarNetId::getUser() const +{ + return m_user; +} + +CTextCollector& CStarNetId::getTextCollector() +{ + return m_textCollector; +} + +void CStarNetHandler::initialise(unsigned int maxStarNets, const wxString& name) +{ + wxASSERT(maxStarNets > 0U); + + m_maxStarNets = maxStarNets; + m_name = name; + + m_starNets = new CStarNetHandler*[maxStarNets]; + + for (unsigned int i = 0U; i < maxStarNets; i++) + m_starNets[i] = NULL; +} + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) +void CStarNetHandler::add(const wxString& callsign, const wxString& logoff, const wxString& repeater, const wxString& infoText, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch, const wxString& reflector) +{ + CStarNetHandler* starNet = new CStarNetHandler(callsign, logoff, repeater, infoText, permanent, userTimeout, groupTimeout, callsignSwitch, txMsgSwitch, reflector); + + for (unsigned int i = 0U; i < m_maxStarNets; i++) { + if (m_starNets[i] == NULL) { + m_starNets[i] = starNet; + return; + } + } + + wxLogError(wxT("Cannot add StarNet group with callsign %s, no space"), callsign.c_str()); + + delete starNet; +} +#else +void CStarNetHandler::add(const wxString& callsign, const wxString& logoff, const wxString& repeater, const wxString& infoText, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch) +{ + CStarNetHandler* starNet = new CStarNetHandler(callsign, logoff, repeater, infoText, permanent, userTimeout, groupTimeout, callsignSwitch, txMsgSwitch); + + for (unsigned int i = 0U; i < m_maxStarNets; i++) { + if (m_starNets[i] == NULL) { + m_starNets[i] = starNet; + return; + } + } + + wxLogError(wxT("Cannot add StarNet group with callsign %s, no space"), callsign.c_str()); + + delete starNet; +} +#endif + +void CStarNetHandler::setG2Handler(CG2ProtocolHandler* handler) +{ + wxASSERT(handler != NULL); + + m_g2Handler = handler; +} + +void CStarNetHandler::setIRC(CIRCDDB* irc) +{ + wxASSERT(irc != NULL); + + m_irc = irc; +} + +void CStarNetHandler::setCache(CCacheManager* cache) +{ + wxASSERT(cache != NULL); + + m_cache = cache; +} + +void CStarNetHandler::setGateway(const wxString& gateway) +{ + m_gateway = gateway; +} + +void CStarNetHandler::setLogging(bool enable, const wxString& dir) +{ + if (!enable) + return; + + wxString fullName = STARNET_BASE_NAME; + + if (!m_name.IsEmpty()) { + fullName.Append(wxT("_")); + fullName.Append(m_name); + } + + wxFileName fileName(dir, fullName, wxT("log")); + + m_logFile = new wxFFile; + bool ret = m_logFile->Open(fileName.GetFullPath(), wxT("wt")); + if (!ret) { + wxLogError(wxT("Unable to open %s for writing"), fileName.GetFullPath().c_str()); + delete m_logFile; + m_logFile = NULL; + } +} + +CStarNetHandler* CStarNetHandler::findStarNet(const wxString& callsign) +{ + for (unsigned int i = 0U; i < m_maxStarNets; i++) { + CStarNetHandler* starNet = m_starNets[i]; + if (starNet != NULL) { + if (starNet->m_groupCallsign.IsSameAs(callsign)) + return starNet; + } + } + + return NULL; +} + +CStarNetHandler* CStarNetHandler::findStarNet(const CHeaderData& header) +{ + wxString your = header.getYourCall(); + + for (unsigned int i = 0U; i < m_maxStarNets; i++) { + CStarNetHandler* starNet = m_starNets[i]; + if (starNet != NULL) { + if (starNet->m_groupCallsign.IsSameAs(your)) + return starNet; + if (starNet->m_offCallsign.IsSameAs(your)) + return starNet; + } + } + + return NULL; +} + +CStarNetHandler* CStarNetHandler::findStarNet(const CAMBEData& data) +{ + unsigned int id = data.getId(); + + for (unsigned int i = 0U; i < m_maxStarNets; i++) { + CStarNetHandler* starNet = m_starNets[i]; + if (starNet != NULL) { + if (starNet->m_id == id) + return starNet; + } + } + + return NULL; +} + +wxArrayString CStarNetHandler::listStarNets() +{ + wxArrayString starNets; + + for (unsigned int i = 0U; i < m_maxStarNets; i++) { + CStarNetHandler* starNet = m_starNets[i]; + if (starNet != NULL) + starNets.Add(starNet->m_groupCallsign); + } + + return starNets; +} + +CRemoteStarNetGroup* CStarNetHandler::getInfo() const +{ + CRemoteStarNetGroup* data = new CRemoteStarNetGroup(m_groupCallsign, m_offCallsign, m_groupTimer.getTimer(), m_groupTimer.getTimeout()); + + for (CStarNetUsersHashMap::const_iterator it = m_users.begin(); it != m_users.end(); ++it) { + CStarNetUser* user = it->second; + data->addUser(user->getCallsign(), user->getTimer().getTimer(), user->getTimer().getTimeout()); + } + + return data; +} + +void CStarNetHandler::finalise() +{ + for (unsigned int i = 0U; i < m_maxStarNets; i++) + delete m_starNets[i]; + + delete[] m_starNets; + + if (m_logFile != NULL) { + m_logFile->Close(); + delete m_logFile; + } +} + +void CStarNetHandler::clock(unsigned int ms) +{ + for (unsigned int i = 0U; i < m_maxStarNets; i++) { + if (m_starNets[i] != NULL) + m_starNets[i]->clockInt(ms); + } +} + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) +void CStarNetHandler::link() +{ + for (unsigned int i = 0U; i < m_maxStarNets; i++) { + if (m_starNets[i] != NULL) + m_starNets[i]->linkInt(); + } +} +#endif + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) +CStarNetHandler::CStarNetHandler(const wxString& callsign, const wxString& logoff, const wxString& repeater, const wxString& infoText, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch, const wxString& reflector) : +m_groupCallsign(callsign), +m_offCallsign(logoff), +m_shortCallsign(wxT("SNET")), +m_repeater(repeater), +m_infoText(infoText), +m_permanent(), +m_linkReflector(reflector), +m_linkGateway(), +m_linkStatus(LS_NONE), +m_linkTimer(1000U, NETWORK_TIMEOUT), +m_id(0x00U), +m_groupTimer(1000U, groupTimeout * 60U), +m_announceTimer(1000U, 2U * 60U), // 2 minutes +m_userTimeout(userTimeout), +m_callsignSwitch(callsignSwitch), +m_txMsgSwitch(txMsgSwitch), +m_ids(), +m_users(), +m_repeaters() +{ + m_announceTimer.start(); + + // Create the short version of the STARnet Group callsign + wxString rest; + if (m_groupCallsign.StartsWith(wxT("STN"), &rest)) { + wxChar c = m_groupCallsign.GetChar(7U); + if (c == wxT(' ')) + m_shortCallsign.Printf(wxT("S%s"), rest.Left(3U).c_str()); + else + m_shortCallsign.Printf(wxT("%s%c"), rest.Left(3U).c_str(), c); + } + + wxStringTokenizer tkn(permanent, wxT(",")); + while (tkn.HasMoreTokens()) { + wxString callsign = tkn.GetNextToken(); + callsign.resize(LONG_CALLSIGN_LENGTH, wxT(' ')); + m_permanent.Add(callsign); + } +} +#else +CStarNetHandler::CStarNetHandler(const wxString& callsign, const wxString& logoff, const wxString& repeater, const wxString& infoText, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch) : +m_groupCallsign(callsign), +m_offCallsign(logoff), +m_shortCallsign(wxT("SNET")), +m_repeater(repeater), +m_infoText(infoText), +m_permanent(), +m_id(0x00U), +m_groupTimer(1000U, groupTimeout * 60U), +m_announceTimer(1000U, 2U * 60U), // 2 minutes +m_userTimeout(userTimeout), +m_callsignSwitch(callsignSwitch), +m_txMsgSwitch(txMsgSwitch), +m_ids(), +m_users(), +m_repeaters() +{ + m_announceTimer.start(); + + // Create the short version of the STARnet Group callsign + wxString rest; + if (m_groupCallsign.StartsWith(wxT("STN"), &rest)) { + wxChar c = m_groupCallsign.GetChar(7U); + if (c == wxT(' ')) + m_shortCallsign.Printf(wxT("S%s"), rest.Left(3U).c_str()); + else + m_shortCallsign.Printf(wxT("%s%c"), rest.Left(3U).c_str(), c); + } + + wxStringTokenizer tkn(permanent, wxT(",")); + while (tkn.HasMoreTokens()) { + wxString callsign = tkn.GetNextToken(); + callsign.resize(LONG_CALLSIGN_LENGTH, wxT(' ')); + m_permanent.Add(callsign); + } +} +#endif + +CStarNetHandler::~CStarNetHandler() +{ + for (CStarNetUsersHashMap::iterator it = m_users.begin(); it != m_users.end(); ++it) + delete it->second; + + for (CStarNetRepeatersHashMap::iterator it = m_repeaters.begin(); it != m_repeaters.end(); ++it) + delete it->second; + + m_users.clear(); + m_repeaters.clear(); +} + +void CStarNetHandler::process(CHeaderData &header) +{ + wxString my = header.getMyCall1(); + wxString your = header.getYourCall(); + + unsigned int id = header.getId(); + + CStarNetUser* user = m_users[my]; + + // Ensure that this user is in the cache + CUserData* userData = m_cache->findUser(my); + if (userData == NULL) + m_irc->findUser(my); + + if (your.IsSameAs(m_groupCallsign)) { + // This is a normal message for logging in/relaying + if (user == NULL) { + // This is a new user, add them to the list + if (m_logFile != NULL) { + time_t timeNow = ::time(NULL); + struct tm* tm = ::gmtime(&timeNow); + + wxString text; + text.Printf(wxT("%04d-%02d-%02d %02d:%02d:%02d: Adding %s to StarNet group %s\n"), + tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, + my.c_str(), m_groupCallsign.c_str()); + + m_logFile->Write(text); + m_logFile->Flush(); + } + + // Start the StarNet group timer if not already running + if (!m_groupTimer.isRunning()) + m_groupTimer.start(); + + user = new CStarNetUser(my, m_userTimeout * 60U); + m_users[my] = user; + + CStarNetId* tx = new CStarNetId(id, MESSAGE_DELAY, user); + tx->setLogin(); + m_ids[id] = tx; + } else { + user->reset(); + + // Check that it isn't a duplicate header + CStarNetId* tx = m_ids[id]; + if (tx != NULL) { + delete userData; + return; + } + + m_ids[id] = new CStarNetId(id, MESSAGE_DELAY, user); + } + } else { + delete userData; + userData = NULL; + + // This is a logoff message + if (user == NULL) // Not a known user, ignore + return; + + if (m_logFile != NULL) { + time_t timeNow = ::time(NULL); + struct tm* tm = ::gmtime(&timeNow); + + wxString text; + text.Printf(wxT("%04d-%02d-%02d %02d:%02d:%02d: Removing %s from StarNet group %s, logged off\n"), + tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, + user->getCallsign().c_str(), m_groupCallsign.c_str()); + + m_logFile->Write(text); + m_logFile->Flush(); + } + + // Remove the user from the user list + m_users.erase(my); + + CStarNetId* tx = new CStarNetId(id, MESSAGE_DELAY, user); + tx->setLogoff(); + m_ids[id] = tx; + + return; + } + + m_groupTimer.start(); + + if (m_id != 0x00U) { + delete userData; + return; + } + + m_id = id; + + // Change the Your callsign to CQCQCQ + header.setCQCQCQ(); + + header.setFlag1(0x00); + header.setFlag2(0x00); + header.setFlag3(0x00); + +#if defined(DEXTRA_LINK) + header.setRepeaters(m_linkGateway, m_linkReflector); + CDExtraHandler::writeHeader(this, header, DIR_OUTGOING); +#endif +#if defined(DCS_LINK) + header.setRepeaters(m_linkGateway, m_linkReflector); + CDCSHandler::writeHeader(this, header, DIR_OUTGOING); +#endif + + // Get the home repeater of the user + wxString exclude; + if (userData != NULL) { + exclude = userData->getRepeater(); + delete userData; + userData = NULL; + } + + // Build new repeater list + for (CStarNetUsersHashMap::const_iterator it = m_users.begin(); it != m_users.end(); ++it) { + CStarNetUser* user = it->second; + if (user != NULL) { + // Find the user in the cache + CUserData* userData = m_cache->findUser(user->getCallsign()); + + if (userData != NULL) { + // Check for the excluded repeater + if (!userData->getRepeater().IsSameAs(exclude)) { + // Find the users repeater in the repeater list, add it otherwise + CStarNetRepeater* repeater = m_repeaters[userData->getRepeater()]; + if (repeater == NULL) { + // Add a new repeater entry + repeater = new CStarNetRepeater; + repeater->m_destination = wxT("/") + userData->getRepeater().Left(6U) + userData->getRepeater().Right(1U); + repeater->m_repeater = userData->getRepeater(); + repeater->m_gateway = userData->getGateway(); + repeater->m_address = userData->getAddress(); + repeater->m_local = CRepeaterHandler::findDVRepeater(userData->getRepeater()); + m_repeaters[userData->getRepeater()] = repeater; + } + } + + delete userData; + userData = NULL; + } + } + } + + switch (m_callsignSwitch) { + case SCS_GROUP_CALLSIGN: + // Change the My Callsign 1 to be that of the StarNet group + header.setMyCall1(m_groupCallsign); + header.setMyCall2(wxT("SNET")); + break; + case SCS_USER_CALLSIGN: + // Change the My Callsign 2 to be that of the StarNet group + header.setMyCall1(my); + header.setMyCall2(m_shortCallsign); + break; + default: + break; + } + + sendToRepeaters(header); + + if (m_txMsgSwitch) + sendFromText(my); +} + +void CStarNetHandler::process(CAMBEData &data) +{ + unsigned int id = data.getId(); + + CStarNetId* tx = m_ids[id]; + if (tx == NULL) + return; + + tx->reset(); + + CStarNetUser* user = tx->getUser(); + user->reset(); + + m_groupTimer.start(); + + // If we've just logged in, the LOGOFF and INFO commands are disabled + if (!tx->isLogin()) { + // If we've already found some slow data, then don't look again + if (!tx->isLogoff() && !tx->isInfo()) { + tx->getTextCollector().writeData(data); + bool hasText = tx->getTextCollector().hasData(); + if (hasText) { + wxString text = tx->getTextCollector().getData(); + + if (text.Left(6U).IsSameAs(wxT("LOGOFF"), false)) { + if (m_logFile != NULL) { + time_t timeNow = ::time(NULL); + struct tm* tm = ::gmtime(&timeNow); + + wxString text; + text.Printf(wxT("%04d-%02d-%02d %02d:%02d:%02d: Removing %s from StarNet group %s, logged off\n"), + tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, + user->getCallsign().c_str(), m_groupCallsign.c_str()); + + m_logFile->Write(text); + m_logFile->Flush(); + } + + tx->setLogoff(); + + // Ensure that this user is in the cache in time for the logoff ack + CUserData* cacheUser = m_cache->findUser(user->getCallsign()); + if (cacheUser == NULL) + m_irc->findUser(user->getCallsign()); + + delete cacheUser; + cacheUser = NULL; + } + + if (text.Left(4U).IsSameAs(wxT("INFO"), false)) { + tx->setInfo(); + + // Ensure that this user is in the cache in time for the info text + CUserData* cacheUser = m_cache->findUser(user->getCallsign()); + if (cacheUser == NULL) + m_irc->findUser(user->getCallsign()); + + delete cacheUser; + cacheUser = NULL; + } + } + } + } + + if (id == m_id) { +#if defined(DEXTRA_LINK) + CDExtraHandler::writeAMBE(this, data, DIR_OUTGOING); +#endif +#if defined(DCS_LINK) + CDCSHandler::writeAMBE(this, data, DIR_OUTGOING); +#endif + sendToRepeaters(data); + } + + if (data.isEnd()) { + if (id == m_id) { + // Clear the repeater list if we're the relayed id + for (CStarNetRepeatersHashMap::iterator it = m_repeaters.begin(); it != m_repeaters.end(); ++it) + delete it->second; + m_repeaters.clear(); + m_id = 0x00U; + } + + if (tx->isLogin()) { + tx->reset(); + tx->setEnd(); + } else if (tx->isLogoff()) { + m_users.erase(user->getCallsign()); + tx->reset(); + tx->setEnd(); + } else if (tx->isInfo()) { + tx->reset(); + tx->setEnd(); + } else { + m_ids.erase(tx->getId()); + delete tx; + } + } +} + +bool CStarNetHandler::logoff(const wxString &callsign) +{ + if (callsign.IsSameAs(wxT("ALL "))) { + for (CStarNetUsersHashMap::iterator it = m_users.begin(); it != m_users.end(); ++it) { + CStarNetUser* user = it->second; + + if (user != NULL && m_logFile != NULL) { + time_t timeNow = ::time(NULL); + struct tm* tm = ::gmtime(&timeNow); + + wxString text; + text.Printf(wxT("%04d-%02d-%02d %02d:%02d:%02d: Removing %s from StarNet group %s, logged off by remote control\n"), + tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, + user->getCallsign().c_str(), m_groupCallsign.c_str()); + + m_logFile->Write(text); + } + + delete user; + } + + if (m_logFile != NULL) + m_logFile->Flush(); + + for (CStarNetIdsHashMap::iterator it = m_ids.begin(); it != m_ids.end(); ++it) + delete it->second; + + for (CStarNetRepeatersHashMap::iterator it = m_repeaters.begin(); it != m_repeaters.end(); ++it) + delete it->second; + + m_users.clear(); + m_ids.clear(); + m_repeaters.end(); + + m_groupTimer.stop(); + m_id = 0x00U; + + return true; + } else { + CStarNetUser* user = m_users[callsign]; + if (user == NULL) { + wxLogMessage(wxT("Invalid callsign asked to logoff")); + return false; + } + + if (m_logFile != NULL) { + time_t timeNow = ::time(NULL); + struct tm* tm = ::gmtime(&timeNow); + + wxString text; + text.Printf(wxT("%04d-%02d-%02d %02d:%02d:%02d: Removing %s from StarNet group %s, logged off by remote control\n"), + tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, + user->getCallsign().c_str(), m_groupCallsign.c_str()); + + m_logFile->Write(text); + m_logFile->Flush(); + } + + // Find any associated id structure associated with this use, and the logged off user is the + // currently relayed one, remove his id. + for (CStarNetIdsHashMap::iterator it = m_ids.begin(); it != m_ids.end(); ++it) { + CStarNetId* id = it->second; + if (id != NULL && id->getUser() == user) { + if (id->getId() == m_id) + m_id = 0x00U; + + m_ids.erase(it); + delete id; + break; + } + } + + m_users.erase(callsign); + delete user; + + // Check to see if we have any users left + unsigned int count = 0U; + for (CStarNetUsersHashMap::iterator it = m_users.begin(); it != m_users.end(); ++it) { + if (it->second != NULL) + count++; + } + + // If none then clear all the data structures + if (count == 0U) { + for (CStarNetUsersHashMap::iterator it = m_users.begin(); it != m_users.end(); ++it) + delete it->second; + for (CStarNetIdsHashMap::iterator it = m_ids.begin(); it != m_ids.end(); ++it) + delete it->second; + for (CStarNetRepeatersHashMap::iterator it = m_repeaters.begin(); it != m_repeaters.end(); ++it) + delete it->second; + + m_users.clear(); + m_ids.clear(); + m_repeaters.end(); + + m_groupTimer.stop(); + m_id = 0x00U; + } + + return true; + } +} + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) +bool CStarNetHandler::process(CHeaderData &header, DIRECTION, AUDIO_SOURCE) +{ + if (m_id != 0x00U) + return false; + + wxString my = header.getMyCall1(); + m_id = header.getId(); + + m_linkTimer.start(); + + // Change the Your callsign to CQCQCQ + header.setCQCQCQ(); + + header.setFlag1(0x00); + header.setFlag2(0x00); + header.setFlag3(0x00); + + // Build new repeater list + for (CStarNetUsersHashMap::const_iterator it = m_users.begin(); it != m_users.end(); ++it) { + CStarNetUser* user = it->second; + if (user != NULL) { + // Find the user in the cache + CUserData* userData = m_cache->findUser(user->getCallsign()); + + if (userData != NULL) { + // Find the users repeater in the repeater list, add it otherwise + CStarNetRepeater* repeater = m_repeaters[userData->getRepeater()]; + if (repeater == NULL) { + // Add a new repeater entry + repeater = new CStarNetRepeater; + repeater->m_destination = wxT("/") + userData->getRepeater().Left(6U) + userData->getRepeater().Right(1U); + repeater->m_repeater = userData->getRepeater(); + repeater->m_gateway = userData->getGateway(); + repeater->m_address = userData->getAddress(); + repeater->m_local = CRepeaterHandler::findDVRepeater(userData->getRepeater()); + m_repeaters[userData->getRepeater()] = repeater; + } + + delete userData; + userData = NULL; + } + } + } + + switch (m_callsignSwitch) { + case SCS_GROUP_CALLSIGN: + // Change the My Callsign 1 to be that of the StarNet group + header.setMyCall1(m_groupCallsign); + header.setMyCall2(wxT("SNET")); + break; + case SCS_USER_CALLSIGN: + // Change the My Callsign 2 to be that of the StarNet group + header.setMyCall1(my); + header.setMyCall2(m_shortCallsign); + break; + default: + break; + } + + sendToRepeaters(header); + + if (m_txMsgSwitch) + sendFromText(my); + + return true; +} + +bool CStarNetHandler::process(CAMBEData &data, DIRECTION, AUDIO_SOURCE) +{ + unsigned int id = data.getId(); + if (id != m_id) + return false; + + m_linkTimer.start(); + + sendToRepeaters(data); + + if (data.isEnd()) { + m_linkTimer.stop(); + m_id = 0x00U; + + // Clear the repeater list + for (CStarNetRepeatersHashMap::iterator it = m_repeaters.begin(); it != m_repeaters.end(); ++it) + delete it->second; + m_repeaters.clear(); + } + + return true; +} +#endif + +#if defined(DEXTRA_LINK) +void CStarNetHandler::linkInt() +{ + if (m_linkReflector.IsEmpty()) + return; + + wxLogMessage(wxT("Linking %s at startup to DExtra reflector %s"), m_repeater.c_str(), m_linkReflector.c_str()); + + // Find the repeater to link to + CRepeaterData* data = m_cache->findRepeater(m_linkReflector); + if (data == NULL) { + wxLogError(wxT("Cannot find the reflector in the cache, not linking")); + return; + } + + m_linkGateway = data->getGateway(); + m_linkStatus = LS_LINKING_DEXTRA; + + CDExtraHandler::link(this, m_repeater, m_linkReflector, data->getAddress()); + + delete data; +} +#endif + +#if defined(DCS_LINK) +void CStarNetHandler::linkInt() +{ + if (m_linkReflector.IsEmpty()) + return; + + wxLogMessage(wxT("Linking %s at startup to DCS reflector %s"), m_repeater.c_str(), m_linkReflector.c_str()); + + // Find the repeater to link to + CRepeaterData* data = m_cache->findRepeater(m_linkReflector); + if (data == NULL) { + wxLogError(wxT("Cannot find the reflector in the cache, not linking")); + return; + } + + m_linkGateway = data->getGateway(); + m_linkStatus = LS_LINKING_DCS; + + CDCSHandler::link(this, m_repeater, m_linkReflector, data->getAddress()); + + delete data; +} +#endif + +void CStarNetHandler::clockInt(unsigned int ms) +{ +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + m_linkTimer.clock(ms); + if (m_linkTimer.isRunning() && m_linkTimer.hasExpired()) { + m_linkTimer.stop(); + m_id = 0x00U; + + // Clear the repeater list + for (CStarNetRepeatersHashMap::iterator it = m_repeaters.begin(); it != m_repeaters.end(); ++it) + delete it->second; + m_repeaters.clear(); + } +#endif + + m_announceTimer.clock(ms); + if (m_announceTimer.hasExpired()) { + m_irc->sendHeardWithTXMsg(m_groupCallsign, wxT(" "), wxT("CQCQCQ "), m_repeater, m_gateway, 0x00U, 0x00U, 0x00U, wxEmptyString, m_infoText); + + if (!m_offCallsign.IsEmpty() && !m_offCallsign.IsSameAs(wxT(" "))) + m_irc->sendHeardWithTXMsg(m_offCallsign, wxT(" "), wxT("CQCQCQ "), m_repeater, m_gateway, 0x00U, 0x00U, 0x00U, wxEmptyString, m_infoText); + + m_announceTimer.start(60U * 60U); // 1 hour + } + + // For each incoming id + for (CStarNetIdsHashMap::iterator it = m_ids.begin(); it != m_ids.end(); ++it) { + CStarNetId* tx = it->second; + + if (tx != NULL && tx->clock(ms)) { + wxString callsign = tx->getUser()->getCallsign(); + + if (tx->isEnd()) { + CUserData* user = m_cache->findUser(callsign); + if (user != NULL) { + if (tx->isLogin()) + sendAck(*user, wxT("Logged in")); + else if (tx->isInfo()) + sendAck(*user, m_infoText); + else if (tx->isLogoff()) + sendAck(*user, wxT("Logged off")); + + delete user; + user = NULL; + } else { + wxLogError(wxT("Cannot find %s in the cache"), callsign.c_str()); + } + + delete tx; + m_ids.erase(it); + + // The iterator is now invalid, so we'll find the next expiry on the next clock tick with a + // new iterator + break; + } else { + if (tx->getId() == m_id) { + // Clear the repeater list if we're the relayed id + for (CStarNetRepeatersHashMap::iterator it1 = m_repeaters.begin(); it1 != m_repeaters.end(); ++it1) + delete it1->second; + m_repeaters.clear(); + m_id = 0x00U; + } + + if (tx->isLogin()) { + tx->reset(); + tx->setEnd(); + } else if (tx->isLogoff()) { + m_users.erase(callsign); + tx->reset(); + tx->setEnd(); + } else if (tx->isInfo()) { + tx->reset(); + tx->setEnd(); + } else { + delete tx; + m_ids.erase(it); + // The iterator is now invalid, so we'll find the next expiry on the next clock tick with a + // new iterator + break; + } + } + } + } + + // Individual user expiry, but not for the permanent entries + for (CStarNetUsersHashMap::iterator it = m_users.begin(); it != m_users.end(); ++it) { + CStarNetUser* user = it->second; + if (user != NULL && m_permanent.Index(user->getCallsign()) == wxNOT_FOUND) + user->clock(ms); + } + + // Handle the group expiry timer + m_groupTimer.clock(ms); + + // Don't do timeouts when relaying audio + if (m_id != 0x00U) + return; + + if (m_groupTimer.isRunning() && m_groupTimer.hasExpired()) { + std::vector permanent; + + // Clear all the users, except the permenent one + for (CStarNetUsersHashMap::iterator it = m_users.begin(); it != m_users.end(); ++it) { + CStarNetUser* user = it->second; + + if (user != NULL) { + if (m_permanent.Index(user->getCallsign()) != wxNOT_FOUND) { + permanent.push_back(user); + } else { + if (m_logFile != NULL) { + time_t timeNow = ::time(NULL); + struct tm* tm = ::gmtime(&timeNow); + + wxString text; + text.Printf(wxT("%04d-%02d-%02d %02d:%02d:%02d: Removing %s from StarNet group %s, group timeout\n"), + tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, + user->getCallsign().c_str(), m_groupCallsign.c_str()); + + m_logFile->Write(text); + m_logFile->Flush(); + } + + delete user; + } + } + } + + m_users.clear(); + + // Re-insert the permenent users + for (std::vector::const_iterator it = permanent.begin(); it != permanent.end(); ++it) { + CStarNetUser* user = *it; + wxString callsign = user->getCallsign(); + m_users[callsign] = user; + } + + m_groupTimer.stop(); + } + + // Individual user expiry + for (CStarNetUsersHashMap::iterator it = m_users.begin(); it != m_users.end(); ++it) { + CStarNetUser* user = it->second; + if (user != NULL && user->hasExpired()) { + if (m_logFile != NULL) { + time_t timeNow = ::time(NULL); + struct tm* tm = ::gmtime(&timeNow); + + wxString text; + text.Printf(wxT("%04d-%02d-%02d %02d:%02d:%02d: Removing %s from StarNet group %s, user timeout\n"), + tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, + user->getCallsign().c_str(), m_groupCallsign.c_str()); + + m_logFile->Write(text); + m_logFile->Flush(); + } + + delete user; + m_users.erase(it); + // The iterator is now invalid, so we'll find the next expiry on the next clock tick with a + // new iterator + break; + } + } +} + +void CStarNetHandler::sendToRepeaters(CHeaderData& header) const +{ + for (CStarNetRepeatersHashMap::const_iterator it = m_repeaters.begin(); it != m_repeaters.end(); ++it) { + CStarNetRepeater* repeater = it->second; + if (repeater != NULL) { + header.setYourCall(repeater->m_destination); + header.setDestination(repeater->m_address, G2_DV_PORT); + header.setRepeaters(repeater->m_gateway, repeater->m_repeater); + if (repeater->m_local != NULL) + repeater->m_local->process(header, DIR_INCOMING, AS_G2); + else + m_g2Handler->writeHeader(header); + } + } +} + +void CStarNetHandler::sendToRepeaters(CAMBEData& data) const +{ + for (CStarNetRepeatersHashMap::const_iterator it = m_repeaters.begin(); it != m_repeaters.end(); ++it) { + CStarNetRepeater* repeater = it->second; + if (repeater != NULL) { + data.setDestination(repeater->m_address, G2_DV_PORT); + if (repeater->m_local != NULL) + repeater->m_local->process(data, DIR_INCOMING, AS_G2); + else + m_g2Handler->writeAMBE(data); + } + } +} + +void CStarNetHandler::sendFromText(const wxString& my) const +{ + wxString text; + switch (m_callsignSwitch) { + case SCS_GROUP_CALLSIGN: + text.Printf(wxT("FROM %s"), my.c_str()); + break; + case SCS_USER_CALLSIGN: + text.Printf(wxT("VIA STARnet %s"), m_groupCallsign.c_str()); + break; + default: + break; + } + + CSlowDataEncoder slowData; + slowData.setTextData(text); + + CAMBEData data; + data.setId(m_id); + + unsigned char buffer[DV_FRAME_LENGTH_BYTES]; + ::memcpy(buffer + 0U, NULL_AMBE_DATA_BYTES, VOICE_FRAME_LENGTH_BYTES); + + for (unsigned int i = 0U; i < 21U; i++) { + if (i == 0U) { + // The first AMBE packet is a sync + ::memcpy(buffer + VOICE_FRAME_LENGTH_BYTES, DATA_SYNC_BYTES, DATA_FRAME_LENGTH_BYTES); + data.setData(buffer, DV_FRAME_LENGTH_BYTES); + data.setSeq(i); + } else { + // The packets containing the text data + unsigned char slowDataBuffer[DATA_FRAME_LENGTH_BYTES]; + slowData.getTextData(slowDataBuffer); + ::memcpy(buffer + VOICE_FRAME_LENGTH_BYTES, slowDataBuffer, DATA_FRAME_LENGTH_BYTES); + data.setData(buffer, DV_FRAME_LENGTH_BYTES); + data.setSeq(i); + } + + sendToRepeaters(data); + } +} + +void CStarNetHandler::sendAck(const CUserData& user, const wxString& text) const +{ + unsigned int id = CHeaderData::createId(); + + CHeaderData header(m_groupCallsign, wxT(" "), user.getUser(), user.getGateway(), user.getRepeater()); + header.setDestination(user.getAddress(), G2_DV_PORT); + header.setId(id); + m_g2Handler->writeHeader(header); + + CSlowDataEncoder slowData; + slowData.setTextData(text); + + CAMBEData data; + data.setId(id); + data.setDestination(user.getAddress(), G2_DV_PORT); + + unsigned char buffer[DV_FRAME_MAX_LENGTH_BYTES]; + ::memcpy(buffer + 0U, NULL_AMBE_DATA_BYTES, VOICE_FRAME_LENGTH_BYTES); + + for (unsigned int i = 0U; i < 20U; i++) { + if (i == 0U) { + // The first AMBE packet is a sync + ::memcpy(buffer + VOICE_FRAME_LENGTH_BYTES, DATA_SYNC_BYTES, DATA_FRAME_LENGTH_BYTES); + data.setData(buffer, DV_FRAME_LENGTH_BYTES); + data.setSeq(i); + } else if (i == 19U) { + // The last packet of the ack + ::memcpy(buffer + VOICE_FRAME_LENGTH_BYTES, END_PATTERN_BYTES, END_PATTERN_LENGTH_BYTES); + data.setData(buffer, DV_FRAME_MAX_LENGTH_BYTES); + data.setSeq(i); + data.setEnd(true); + } else { + // The packets containing the text data + unsigned char slowDataBuffer[DATA_FRAME_LENGTH_BYTES]; + slowData.getTextData(slowDataBuffer); + ::memcpy(buffer + VOICE_FRAME_LENGTH_BYTES, slowDataBuffer, DATA_FRAME_LENGTH_BYTES); + data.setData(buffer, DV_FRAME_LENGTH_BYTES); + data.setSeq(i); + } + + m_g2Handler->writeAMBE(data); + } +} + +#if defined(DEXTRA_LINK) +void CStarNetHandler::linkUp(DSTAR_PROTOCOL, const wxString& callsign) +{ + wxLogMessage(wxT("DExtra link to %s established"), callsign.c_str()); + + m_linkStatus = LS_LINKED_DEXTRA; +} + +bool CStarNetHandler::linkFailed(DSTAR_PROTOCOL, const wxString& callsign, bool isRecoverable) +{ + if (!isRecoverable) { + if (m_linkStatus != LS_NONE) { + wxLogMessage(wxT("DExtra link to %s has failed"), callsign.c_str()); + m_linkStatus = LS_NONE; + } + + return false; + } + + if (m_linkStatus == LS_LINKING_DEXTRA || m_linkStatus == LS_LINKED_DEXTRA) { + wxLogMessage(wxT("DExtra link to %s has failed, relinking"), callsign.c_str()); + m_linkStatus = LS_LINKING_DEXTRA; + return true; + } + + return false; +} + +void CStarNetHandler::linkRefused(DSTAR_PROTOCOL, const wxString& callsign) +{ + if (m_linkStatus != LS_NONE) { + wxLogMessage(wxT("DExtra link to %s was refused"), callsign.c_str()); + m_linkStatus = LS_NONE; + } +} + +bool CStarNetHandler::singleHeader() +{ + return true; +} +#endif + +#if defined(DCS_LINK) +void CStarNetHandler::linkUp(DSTAR_PROTOCOL, const wxString& callsign) +{ + wxLogMessage(wxT("DCS link to %s established"), callsign.c_str()); + + m_linkStatus = LS_LINKED_DCS; +} + +void CStarNetHandler::linkRefused(DSTAR_PROTOCOL, const wxString& callsign) +{ + if (m_linkStatus != LS_NONE) { + wxLogMessage(wxT("DCS link to %s was refused"), callsign.c_str()); + m_linkStatus = LS_NONE; + } +} + +bool CStarNetHandler::linkFailed(DSTAR_PROTOCOL, const wxString& callsign, bool isRecoverable) +{ + if (!isRecoverable) { + if (m_linkStatus != LS_NONE) { + wxLogMessage(wxT("DCS link to %s has failed"), callsign.c_str()); + m_linkStatus = LS_NONE; + } + + return false; + } + + if (m_linkStatus == LS_LINKING_DCS || m_linkStatus == LS_LINKED_DCS) { + wxLogMessage(wxT("DCS link to %s has failed, relinking"), callsign.c_str()); + m_linkStatus = LS_LINKING_DCS; + return true; + } + + return false; +} + +bool CStarNetHandler::singleHeader() +{ + return true; +} +#endif diff --git a/Common/StarNetHandler.h b/Common/StarNetHandler.h new file mode 100644 index 0000000..067d6cd --- /dev/null +++ b/Common/StarNetHandler.h @@ -0,0 +1,221 @@ +/* + * Copyright (C) 2011-2014 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef StarNetHandler_H +#define StarNetHandler_H + +#include "RemoteStarNetGroup.h" +#include "G2ProtocolHandler.h" +#include "ReflectorCallback.h" // DEXTRA_LINK || DCS_LINK +#include "RepeaterCallback.h" +#include "TextCollector.h" +#include "CacheManager.h" +#include "HeaderData.h" +#include "AMBEData.h" +#include "IRCDDB.h" +#include "Timer.h" + +#if defined(__WINDOWS__) +#include "Inaddr.h" +#else +#include +#endif + +#include + +class CStarNetUser { +public: + CStarNetUser(const wxString& callsign, unsigned int timeout); + ~CStarNetUser(); + + void reset(); + + bool clock(unsigned int ms); + bool hasExpired(); + + wxString getCallsign() const; + CTimer getTimer() const; + +private: + wxString m_callsign; + CTimer m_timer; +}; + +class CStarNetId { +public: + CStarNetId(unsigned int id, unsigned int timeout, CStarNetUser* user); + ~CStarNetId(); + + unsigned int getId() const; + + void reset(); + + void setLogin(); + void setInfo(); + void setLogoff(); + void setEnd(); + + bool clock(unsigned int ms); + bool hasExpired(); + + bool isLogin() const; + bool isInfo() const; + bool isLogoff() const; + bool isEnd() const; + + CStarNetUser* getUser() const; + + CTextCollector& getTextCollector(); + +private: + unsigned int m_id; + CTimer m_timer; + bool m_login; + bool m_info; + bool m_logoff; + bool m_end; + CStarNetUser* m_user; + CTextCollector m_textCollector; +}; + +class CStarNetRepeater { +public: + wxString m_destination; + wxString m_repeater; + wxString m_gateway; + in_addr m_address; + IRepeaterCallback* m_local; +}; + +WX_DECLARE_HASH_MAP(unsigned int, CStarNetId*, wxIntegerHash, wxIntegerEqual, CStarNetIdsHashMap); +WX_DECLARE_STRING_HASH_MAP(CStarNetUser*, CStarNetUsersHashMap); +WX_DECLARE_STRING_HASH_MAP(CStarNetRepeater*, CStarNetRepeatersHashMap); + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) +class CStarNetHandler : public IReflectorCallback { +#else +class CStarNetHandler { +#endif +public: + static void initialise(unsigned int maxStarNets, const wxString& name = wxEmptyString); + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + static void add(const wxString& callsign, const wxString& logoff, const wxString& repeater, const wxString& infoText, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch, const wxString& reflector); +#else + static void add(const wxString& callsign, const wxString& logoff, const wxString& repeater, const wxString& infoText, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch); +#endif + + static void setG2Handler(CG2ProtocolHandler* handler); + static void setIRC(CIRCDDB* irc); + static void setCache(CCacheManager* cache); + static void setGateway(const wxString& gateway); + static void setLogging(bool enable, const wxString& dir); + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + static void link(); +#endif + + static wxArrayString listStarNets(); + + static CStarNetHandler* findStarNet(const wxString& callsign); + static CStarNetHandler* findStarNet(const CHeaderData& header); + static CStarNetHandler* findStarNet(const CAMBEData& data); + + static void finalise(); + + static void clock(unsigned int ms); + + void process(CHeaderData& header); + void process(CAMBEData& data); + + CRemoteStarNetGroup* getInfo() const; + + bool logoff(const wxString& callsign); + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + virtual bool process(CHeaderData& header, DIRECTION direction, AUDIO_SOURCE source); + virtual bool process(CAMBEData& data, DIRECTION direction, AUDIO_SOURCE source); + + virtual void linkUp(DSTAR_PROTOCOL protocol, const wxString& callsign); + virtual void linkRefused(DSTAR_PROTOCOL protocol, const wxString& callsign); + virtual bool linkFailed(DSTAR_PROTOCOL protocol, const wxString& callsign, bool isRecoverable); + + virtual bool singleHeader(); +#endif + +protected: +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + CStarNetHandler(const wxString& callsign, const wxString& logoff, const wxString& repeater, const wxString& infoText, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch, const wxString& reflector); +#else + CStarNetHandler(const wxString& callsign, const wxString& logoff, const wxString& repeater, const wxString& infoText, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch); +#endif + ~CStarNetHandler(); + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + void linkInt(); +#endif + + void clockInt(unsigned int ms); + +private: + static unsigned int m_maxStarNets; + static CStarNetHandler** m_starNets; + + static CG2ProtocolHandler* m_g2Handler; + static CIRCDDB* m_irc; + static CCacheManager* m_cache; + static wxString m_gateway; + + static wxString m_name; + static wxFFile* m_logFile; + + // Group info + wxString m_groupCallsign; + wxString m_offCallsign; + wxString m_shortCallsign; + wxString m_repeater; + wxString m_infoText; + wxArrayString m_permanent; +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + wxString m_linkReflector; + wxString m_linkGateway; + LINK_STATUS m_linkStatus; + CTimer m_linkTimer; +#endif + + unsigned int m_id; + + CTimer m_groupTimer; + CTimer m_announceTimer; + + unsigned int m_userTimeout; + + STARNET_CALLSIGN_SWITCH m_callsignSwitch; + bool m_txMsgSwitch; + + CStarNetIdsHashMap m_ids; + CStarNetUsersHashMap m_users; + CStarNetRepeatersHashMap m_repeaters; + + void sendFromText(const wxString& text) const; + void sendToRepeaters(CHeaderData& header) const; + void sendToRepeaters(CAMBEData& data) const; + void sendAck(const CUserData& user, const wxString& text) const; +}; + +#endif diff --git a/Common/StatusData.cpp b/Common/StatusData.cpp new file mode 100644 index 0000000..e83ce8f --- /dev/null +++ b/Common/StatusData.cpp @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2011,2012 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "StatusData.h" + +#include "DStarDefines.h" +#include "Utils.h" + +CStatusData::CStatusData(const wxString& text, unsigned int n) : +m_data(NULL), +m_n(n), +m_address(), +m_port(0U) +{ + m_data = new unsigned char[20U]; + ::memset(m_data, ' ', 20U); + + for (unsigned int i = 0U; i < text.Length() && i < 20U; i++) + m_data[i] = text.GetChar(i); +} + +CStatusData::~CStatusData() +{ + delete[] m_data; +} + +unsigned int CStatusData::getHBRepeaterData(unsigned char *data, unsigned int length) const +{ + wxASSERT(data != NULL); + wxASSERT(length >= 26U); + + data[0] = 'D'; + data[1] = 'S'; + data[2] = 'R'; + data[3] = 'P'; + + data[4] = 0x04; // Status text data + + data[5] = m_n; + + ::memcpy(data + 6U, m_data, 20U); + + return 26U; +} + +void CStatusData::setDestination(const in_addr& address, unsigned int port) +{ + m_address = address; + m_port = port; +} + +in_addr CStatusData::getAddress() const +{ + return m_address; +} + +unsigned int CStatusData::getPort() const +{ + return m_port; +} diff --git a/Common/StatusData.h b/Common/StatusData.h new file mode 100644 index 0000000..c351921 --- /dev/null +++ b/Common/StatusData.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2011,2012 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef StatusData_H +#define StatusData_H + +#include + +#if defined(__WINDOWS__) +#include "Inaddr.h" +#else +#include +#endif + +class CStatusData { +public: + CStatusData(const wxString& text, unsigned int n); + virtual ~CStatusData(); + + unsigned int getHBRepeaterData(unsigned char* data, unsigned int length) const; + + void setDestination(const in_addr& address, unsigned int port); + + in_addr getAddress() const; + unsigned int getPort() const; + +private: + unsigned char* m_data; + unsigned int m_n; + in_addr m_address; + unsigned int m_port; +}; + +#endif diff --git a/Common/TCPReaderWriterClient.cpp b/Common/TCPReaderWriterClient.cpp new file mode 100644 index 0000000..09e2489 --- /dev/null +++ b/Common/TCPReaderWriterClient.cpp @@ -0,0 +1,292 @@ +/* + * Copyright (C) 2010-2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "TCPReaderWriterClient.h" +#include "UDPReaderWriter.h" + +#include + +#if !defined(__WINDOWS__) +#include +#endif + + +CTCPReaderWriterClient::CTCPReaderWriterClient(const wxString& address, unsigned int port, const wxString& localAddress) : +m_address(address), +m_port(port), +m_localAddress(localAddress), +m_fd(-1) +{ + wxASSERT(!address.IsEmpty()); + wxASSERT(port > 0U); + +#if defined(__WINDOWS__) + WSAData data; + int wsaRet = ::WSAStartup(MAKEWORD(2, 2), &data); + if (wsaRet != 0) + wxLogError(wxT("Error from WSAStartup")); +#endif +} + +CTCPReaderWriterClient::CTCPReaderWriterClient(int fd) : +m_address(), +m_port(0U), +m_localAddress(), +m_fd(fd) +{ + wxASSERT(fd >= 0); + +#if defined(__WINDOWS__) + WSAData data; + int wsaRet = ::WSAStartup(MAKEWORD(2, 2), &data); + if (wsaRet != 0) + wxLogError(wxT("Error from WSAStartup")); +#endif +} + +CTCPReaderWriterClient::CTCPReaderWriterClient() : +m_address(), +m_port(0U), +m_localAddress(), +m_fd(-1) +{ +#if defined(__WINDOWS__) + WSAData data; + int wsaRet = ::WSAStartup(MAKEWORD(2, 2), &data); + if (wsaRet != 0) + wxLogError(wxT("Error from WSAStartup")); +#endif +} + +CTCPReaderWriterClient::~CTCPReaderWriterClient() +{ +#if defined(__WINDOWS__) + ::WSACleanup(); +#endif +} + +bool CTCPReaderWriterClient::open(const wxString& address, unsigned int port, const wxString& localAddress) +{ + m_address = address; + m_port = port; + m_localAddress = localAddress; + + return open(); +} + +bool CTCPReaderWriterClient::open() +{ + if (m_fd != -1) + return true; + + if (m_address.IsEmpty() || m_port == 0U) + return false; + + m_fd = ::socket(PF_INET, SOCK_STREAM, 0); + if (m_fd < 0) { +#if defined(__WINDOWS__) + wxLogError(wxT("Cannot create the TCP client socket, err=%d"), ::GetLastError()); +#else + wxLogError(wxT("Cannot create the TCP client socket, err=%d"), errno); +#endif + return false; + } + + if (!m_localAddress.IsEmpty()) { + sockaddr_in addr; + ::memset(&addr, 0x00, sizeof(struct sockaddr_in)); + addr.sin_family = AF_INET; + addr.sin_port = 0U; +#if defined(__WINDOWS__) + addr.sin_addr.s_addr = ::inet_addr(m_localAddress.mb_str()); +#else + addr.sin_addr.s_addr = ::inet_addr(m_localAddress.mb_str()); +#endif + if (addr.sin_addr.s_addr == INADDR_NONE) { + wxLogError(wxT("The address is invalid - %s"), m_localAddress.c_str()); + close(); + return false; + } + + if (::bind(m_fd, (sockaddr*)&addr, sizeof(sockaddr_in)) == -1) { +#if defined(__WINDOWS__) + wxLogError(wxT("Cannot bind the TCP client address, err=%d"), ::GetLastError()); +#else + wxLogError(wxT("Cannot bind the TCP client address, err=%d"), errno); +#endif + close(); + return false; + } + } + + struct sockaddr_in addr; + ::memset(&addr, 0x00, sizeof(struct sockaddr_in)); + addr.sin_family = AF_INET; + addr.sin_port = htons(m_port); + addr.sin_addr = CUDPReaderWriter::lookup(m_address); + + if (addr.sin_addr.s_addr == INADDR_NONE) { + close(); + return false; + } + + if (::connect(m_fd, (sockaddr*)&addr, sizeof(struct sockaddr_in)) == -1) { +#if defined(__WINDOWS__) + wxLogError(wxT("Cannot connect the TCP client socket, err=%d"), ::GetLastError()); +#else + wxLogError(wxT("Cannot connect the TCP client socket, err=%d"), errno); +#endif + close(); + return false; + } + + int noDelay = 1; + if (::setsockopt(m_fd, IPPROTO_TCP, TCP_NODELAY, (char *)&noDelay, sizeof(noDelay)) == -1) { +#if defined(__WINDOWS__) + wxLogError(wxT("Cannot set the TCP client socket option, err=%d"), ::GetLastError()); +#else + wxLogError(wxT("Cannot set the TCP client socket option, err=%d"), errno); +#endif + close(); + return false; + } + + return true; +} + +int CTCPReaderWriterClient::read(unsigned char* buffer, unsigned int length, unsigned int secs, unsigned int msecs) +{ + wxASSERT(buffer != NULL); + wxASSERT(length > 0U); + wxASSERT(m_fd != -1); + + // Check that the recv() won't block + fd_set readFds; + FD_ZERO(&readFds); +#if defined(__WINDOWS__) + FD_SET((unsigned int)m_fd, &readFds); +#else + FD_SET(m_fd, &readFds); +#endif + + // Return after timeout + timeval tv; + tv.tv_sec = secs; + tv.tv_usec = msecs * 1000; + + int ret = ::select(m_fd + 1, &readFds, NULL, NULL, &tv); + if (ret < 0) { +#if defined(__WINDOWS__) + wxLogError(wxT("Error returned from TCP client select, err=%d"), ::GetLastError()); +#else + wxLogError(wxT("Error returned from TCP client select, err=%d"), errno); +#endif + return -1; + } + +#if defined(__WINDOWS__) + if (!FD_ISSET((unsigned int)m_fd, &readFds)) + return 0; +#else + if (!FD_ISSET(m_fd, &readFds)) + return 0; +#endif + + ssize_t len = ::recv(m_fd, (char*)buffer, length, 0); + if (len == 0) { + return -2; + } else if (len < 0) { +#if defined(__WINDOWS__) + wxLogError(wxT("Error returned from recv, err=%d"), ::GetLastError()); +#else + wxLogError(wxT("Error returned from recv, err=%d"), errno); +#endif + return -1; + } + + return len; +} + +int CTCPReaderWriterClient::readLine(wxString& line, unsigned int secs) +{ + //maybe there is a better way to do this like reading blocks, pushing them for later calls + //Nevermind, we'll read one char at a time for the time being. + unsigned char c; + int resultCode; + int len = 0; + line = wxT(""); + + do + { + resultCode = read(&c, 1, secs); + if(resultCode == 1){ + line.Append(c); + len++; + } + }while(c != '\n' && resultCode == 1); + + return resultCode <= 0 ? resultCode : len; +} + +bool CTCPReaderWriterClient::write(const unsigned char* buffer, unsigned int length) +{ + wxASSERT(buffer != NULL); + wxASSERT(length > 0U); + wxASSERT(m_fd != -1); + + ssize_t ret = ::send(m_fd, (char *)buffer, length, 0); + if (ret != ssize_t(length)) { +#if defined(__WINDOWS__) + wxLogError(wxT("Error returned from send, err=%d"), ::GetLastError()); +#else + wxLogError(wxT("Error returned from send, err=%d"), errno); +#endif + return false; + } + + return true; +} + +bool CTCPReaderWriterClient::writeLine(const wxString& line) +{ + wxString lineCopy(line); + if(lineCopy.Length() > 0 && lineCopy.GetChar(lineCopy.Length() - 1) != '\n') + lineCopy.Append(wxT("\n")); + + //stupidly write one char after the other + size_t len = lineCopy.Length(); + bool result = true; + for(size_t i = 0; i < len && result; i++){ + unsigned char c = lineCopy.GetChar(i); + result = write(&c , 1); + } + + return result; +} + +void CTCPReaderWriterClient::close() +{ + if (m_fd != -1) { +#if defined(__WINDOWS__) + ::closesocket(m_fd); +#else + ::close(m_fd); +#endif + m_fd = -1; + } +} diff --git a/Common/TCPReaderWriterClient.h b/Common/TCPReaderWriterClient.h new file mode 100644 index 0000000..1f5f31f --- /dev/null +++ b/Common/TCPReaderWriterClient.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2010,2011,2012,2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef TCPReaderWriterClient_H +#define TCPReaderWriterClient_H + +#include + +#if !defined(__WINDOWS__) +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif + +class CTCPReaderWriterClient { +public: + CTCPReaderWriterClient(const wxString& address, unsigned int port, const wxString& localAddress = wxEmptyString); + CTCPReaderWriterClient(int fd); + CTCPReaderWriterClient(); + ~CTCPReaderWriterClient(); + + bool open(const wxString& address, unsigned int port, const wxString& localAddress = wxEmptyString); + bool open(); + + int read(unsigned char* buffer, unsigned int length, unsigned int secs, unsigned int msecs = 0U); + int readLine(wxString& line, unsigned int secs); + bool write(const unsigned char* buffer, unsigned int length); + bool writeLine(const wxString& line); + + void close(); + +private: + wxString m_address; + unsigned short m_port; + wxString m_localAddress; + int m_fd; +}; + +#endif diff --git a/Common/TCPReaderWriterServer.cpp b/Common/TCPReaderWriterServer.cpp new file mode 100644 index 0000000..ef945ad --- /dev/null +++ b/Common/TCPReaderWriterServer.cpp @@ -0,0 +1,319 @@ +/* + * Copyright (C) 2011,2014 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "TCPReaderWriterServer.h" + +#if !defined(__WINDOWS__) +#include +#endif + + +CTCPReaderWriterServer::CTCPReaderWriterServer(const wxString& address, unsigned int port) : +wxThread(wxTHREAD_JOINABLE), +m_address(address), +m_port(port), +m_fd(-1), +m_client(NULL), +m_stopped(false) +{ + wxASSERT(port > 0U); + +#if defined(__WINDOWS__) + WSAData data; + int wsaRet = ::WSAStartup(MAKEWORD(2, 2), &data); + if (wsaRet != 0) + wxLogError(wxT("Error from WSAStartup")); +#endif +} + +CTCPReaderWriterServer::~CTCPReaderWriterServer() +{ +#if defined(__WINDOWS__) + ::WSACleanup(); +#endif +} + +bool CTCPReaderWriterServer::start() +{ + bool ret = open(); + if (!ret) { + close(); + return false; + } + + Create(); + Run(); + + return true; +} + +int CTCPReaderWriterServer::read(unsigned char* buffer, unsigned int length, unsigned int secs) +{ + wxASSERT(buffer != NULL); + wxASSERT(length > 0U); + + if (m_client != NULL) { + int ret = m_client->read(buffer, length, secs); + if (ret < 0) { + wxLogMessage(wxT("Lost TCP connection to port %u"), m_port); + + m_client->close(); + delete m_client; + m_client = NULL; + + open(); + + return 0; + } + + return ret; + } + + return 0; +} + +bool CTCPReaderWriterServer::write(const unsigned char* buffer, unsigned int length) +{ + wxASSERT(buffer != NULL); + wxASSERT(length > 0U); + + if (m_client != NULL) { + bool ret = m_client->write(buffer, length); + if (!ret) { + wxLogMessage(wxT("Lost TCP connection to port %u"), m_port); + + m_client->close(); + delete m_client; + m_client = NULL; + + open(); + + return false; + } + + return true; + } + + return true; +} + +void* CTCPReaderWriterServer::Entry() +{ + try { + while (!m_stopped) { + int ret = accept(); + switch (ret) { + case -2: + break; + case -1: + break; + default: + wxLogMessage(wxT("Incoming TCP connection to port %u"), m_port); + m_client = new CTCPReaderWriterClient(ret); + close(); + break; + } + + Sleep(1000UL); + } + + if (m_client != NULL) { + m_client->close(); + delete m_client; + } + + close(); + } + catch (std::exception& e) { + wxString message(e.what(), wxConvLocal); + wxLogError(wxT("Exception raised in the TCP Reader-Writer Server thread - \"%s\""), message.c_str()); + } + catch (...) { + wxLogError(wxT("Unknown exception raised in the TCP Reader-Writer Server thread")); + } + + return NULL; +} + +void CTCPReaderWriterServer::stop() +{ + m_stopped = true; + + Wait(); +} + +bool CTCPReaderWriterServer::open() +{ + m_fd = ::socket(PF_INET, SOCK_STREAM, 0); + if (m_fd < 0) { +#if defined(__WINDOWS__) + wxLogError(wxT("Cannot create the TCP server socket, err=%d"), ::GetLastError()); +#else + wxLogError(wxT("Cannot create the TCP server socket, err=%d"), errno); +#endif + return false; + } + + struct sockaddr_in addr; + ::memset(&addr, 0x00, sizeof(struct sockaddr_in)); + addr.sin_family = AF_INET; + addr.sin_port = htons(m_port); + if (m_address.IsEmpty()) + addr.sin_addr.s_addr = htonl(INADDR_ANY); + else + addr.sin_addr = lookup(m_address); + + if (addr.sin_addr.s_addr == INADDR_NONE) { + wxLogError(wxT("The address is invalid - %s"), m_address.c_str()); + close(); + return false; + } + + int reuse = 1; + if (::setsockopt(m_fd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) == -1) { +#if defined(__WINDOWS__) + wxLogError(wxT("Cannot set the TCP server socket option, err=%d"), ::GetLastError()); +#else + wxLogError(wxT("Cannot set the TCP server socket option, err=%d"), errno); +#endif + close(); + return false; + } + + if (::bind(m_fd, (sockaddr*)&addr, sizeof(struct sockaddr_in)) == -1) { +#if defined(__WINDOWS__) + wxLogError(wxT("Cannot bind the TCP server address, err=%d"), ::GetLastError()); +#else + wxLogError(wxT("Cannot bind the TCP server address, err=%d"), errno); +#endif + close(); + return false; + } + + ::listen(m_fd, 5); + + return true; +} + +int CTCPReaderWriterServer::accept() +{ + if (m_fd == -1) + return -1; + + // Check that the accept() won't block + fd_set readFds; + FD_ZERO(&readFds); +#if defined(__WINDOWS__) + FD_SET((unsigned int)m_fd, &readFds); +#else + FD_SET(m_fd, &readFds); +#endif + + // Return after timeout + timeval tv; + tv.tv_sec = 0L; + tv.tv_usec = 0L; + + int ret = ::select(m_fd + 1, &readFds, NULL, NULL, &tv); + if (ret < 0) { +#if defined(__WINDOWS__) + wxLogError(wxT("Error returned from TCP server select, err=%d"), ::GetLastError()); +#else + wxLogError(wxT("Error returned from TCP server select, err=%d"), errno); +#endif + return -2; + } + +#if defined(__WINDOWS__) + if (!FD_ISSET((unsigned int)m_fd, &readFds)) + return -1; +#else + if (!FD_ISSET(m_fd, &readFds)) + return -1; +#endif + + struct sockaddr_in addr; +#if defined(__WINDOWS__) + int len = sizeof(struct sockaddr_in); +#else + socklen_t len = sizeof(struct sockaddr_in); +#endif + + ret = ::accept(m_fd, (sockaddr*)&addr, &len); + if (ret < 0) { +#if defined(__WINDOWS__) + wxLogError(wxT("Error returned from TCP server accept, err=%d"), ::GetLastError()); +#else + wxLogError(wxT("Error returned from TCP server accept, err=%d"), errno); +#endif + } + + return ret; +} + +void CTCPReaderWriterServer::close() +{ + if (m_fd != -1) { +#if defined(__WINDOWS__) + ::closesocket(m_fd); +#else + ::close(m_fd); +#endif + m_fd = -1; + } +} + +in_addr CTCPReaderWriterServer::lookup(const wxString& hostname) const +{ + in_addr addr; +#if defined(WIN32) + unsigned long address = ::inet_addr(hostname.mb_str()); + if (address != INADDR_NONE && address != INADDR_ANY) { + addr.s_addr = address; + return addr; + } + + struct hostent* hp = ::gethostbyname(hostname.mb_str()); + if (hp != NULL) { + ::memcpy(&addr, hp->h_addr_list[0], hp->h_length); + return addr; + } + + wxLogError(wxT("Cannot find %s"), hostname.c_str()); + + addr.s_addr = INADDR_NONE; + return addr; +#else + in_addr_t address = ::inet_addr(hostname.mb_str()); + if (address != in_addr_t(-1)) { + addr.s_addr = address; + return addr; + } + + struct hostent* hp = ::gethostbyname(hostname.mb_str()); + if (hp != NULL) { + ::memcpy(&addr, hp->h_addr_list[0], hp->h_length); + return addr; + } + + wxLogError(wxT("Cannot find %s"), hostname.c_str()); + + addr.s_addr = INADDR_NONE; + return addr; +#endif +} diff --git a/Common/TCPReaderWriterServer.h b/Common/TCPReaderWriterServer.h new file mode 100644 index 0000000..f3d7c1d --- /dev/null +++ b/Common/TCPReaderWriterServer.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2011 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef TCPReaderWriterServer_H +#define TCPReaderWriterServer_H + +#include "TCPReaderWriterClient.h" + +#include + +#if !defined(__WINDOWS__) +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif + +class CTCPReaderWriterServer : public wxThread { +public: + CTCPReaderWriterServer(const wxString& address, unsigned int port); + virtual ~CTCPReaderWriterServer(); + + virtual bool start(); + + virtual bool write(const unsigned char* buffer, unsigned int length); + virtual int read(unsigned char* buffer, unsigned int length, unsigned int secs); + + virtual void stop(); + + virtual void* Entry(); + +private: + wxString m_address; + unsigned short m_port; + int m_fd; + CTCPReaderWriterClient* m_client; + bool m_stopped; + + bool open(); + int accept(); + void close(); + in_addr lookup(const wxString& hostname) const; +}; + +#endif diff --git a/Common/TextCollector.cpp b/Common/TextCollector.cpp new file mode 100644 index 0000000..0f985f2 --- /dev/null +++ b/Common/TextCollector.cpp @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2010,2011 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "TextCollector.h" +#include "DStarDefines.h" +#include "Utils.h" + +const unsigned int TEXT_DATA_LENGTH = 20U; +const unsigned int SLOW_DATA_BLOCK_LENGTH = 6U; + +CTextCollector::CTextCollector() : +m_data(NULL), +m_buffer(NULL), +m_slowData(SS_FIRST), +m_has0(false), +m_has1(false), +m_has2(false), +m_has3(false) +{ + m_data = new char[TEXT_DATA_LENGTH]; + m_buffer = new unsigned char[SLOW_DATA_BLOCK_LENGTH]; +} + +CTextCollector::~CTextCollector() +{ + delete[] m_data; + delete[] m_buffer; +} + +void CTextCollector::writeData(const CAMBEData& data) +{ + if (data.isSync()) { + sync(); + return; + } + + unsigned char buffer[DV_FRAME_MAX_LENGTH_BYTES]; + data.getData(buffer, DV_FRAME_MAX_LENGTH_BYTES); + + switch (m_slowData) { + case SS_FIRST: + m_buffer[0U] = buffer[VOICE_FRAME_LENGTH_BYTES + 0U] ^ SCRAMBLER_BYTE1; + m_buffer[1U] = buffer[VOICE_FRAME_LENGTH_BYTES + 1U] ^ SCRAMBLER_BYTE2; + m_buffer[2U] = buffer[VOICE_FRAME_LENGTH_BYTES + 2U] ^ SCRAMBLER_BYTE3; + m_slowData = SS_SECOND; + return; + + case SS_SECOND: + m_buffer[3U] = buffer[VOICE_FRAME_LENGTH_BYTES + 0U] ^ SCRAMBLER_BYTE1; + m_buffer[4U] = buffer[VOICE_FRAME_LENGTH_BYTES + 1U] ^ SCRAMBLER_BYTE2; + m_buffer[5U] = buffer[VOICE_FRAME_LENGTH_BYTES + 2U] ^ SCRAMBLER_BYTE3; + m_slowData = SS_FIRST; + break; + } + + switch (m_buffer[0U]) { + case SLOW_DATA_TYPE_TEXT | 0U: + m_data[0U] = m_buffer[1U] & 0x7FU; + m_data[1U] = m_buffer[2U] & 0x7FU; + m_data[2U] = m_buffer[3U] & 0x7FU; + m_data[3U] = m_buffer[4U] & 0x7FU; + m_data[4U] = m_buffer[5U] & 0x7FU; + m_has0 = true; + break; + case SLOW_DATA_TYPE_TEXT | 1U: + m_data[5U] = m_buffer[1U] & 0x7FU; + m_data[6U] = m_buffer[2U] & 0x7FU; + m_data[7U] = m_buffer[3U] & 0x7FU; + m_data[8U] = m_buffer[4U] & 0x7FU; + m_data[9U] = m_buffer[5U] & 0x7FU; + m_has1 = true; + break; + case SLOW_DATA_TYPE_TEXT | 2U: + m_data[10U] = m_buffer[1U] & 0x7FU; + m_data[11U] = m_buffer[2U] & 0x7FU; + m_data[12U] = m_buffer[3U] & 0x7FU; + m_data[13U] = m_buffer[4U] & 0x7FU; + m_data[14U] = m_buffer[5U] & 0x7FU; + m_has2 = true; + break; + case SLOW_DATA_TYPE_TEXT | 3U: + m_data[15U] = m_buffer[1U] & 0x7FU; + m_data[16U] = m_buffer[2U] & 0x7FU; + m_data[17U] = m_buffer[3U] & 0x7FU; + m_data[18U] = m_buffer[4U] & 0x7FU; + m_data[19U] = m_buffer[5U] & 0x7FU; + m_has3 = true; + break; + default: + break; + } +} + +void CTextCollector::reset() +{ + m_slowData = SS_FIRST; + m_has0 = false; + m_has1 = false; + m_has2 = false; + m_has3 = false; +} + +void CTextCollector::sync() +{ + m_slowData = SS_FIRST; +} + +bool CTextCollector::hasData() const +{ + return m_has0 && m_has1 && m_has2 && m_has3; +} + +wxString CTextCollector::getData() +{ + wxString text; + + if (!m_has0 || !m_has1 || !m_has2 || !m_has3) + return text; + + m_has0 = false; + m_has1 = false; + m_has2 = false; + m_has3 = false; + + return wxString(m_data, wxConvLocal, TEXT_DATA_LENGTH); +} diff --git a/Common/TextCollector.h b/Common/TextCollector.h new file mode 100644 index 0000000..955a822 --- /dev/null +++ b/Common/TextCollector.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2010 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef TextCollector_H +#define TextCollector_H + +#include "AMBEData.h" +#include "Defs.h" + +#include + +class CTextCollector { +public: + CTextCollector(); + ~CTextCollector(); + + void writeData(const CAMBEData& data); + + void sync(); + + void reset(); + + bool hasData() const; + + wxString getData(); + +private: + char* m_data; + unsigned char* m_buffer; + SLOWDATA_STATE m_slowData; + bool m_has0; + bool m_has1; + bool m_has2; + bool m_has3; +}; + +#endif diff --git a/Common/TextData.cpp b/Common/TextData.cpp new file mode 100644 index 0000000..2eb57d4 --- /dev/null +++ b/Common/TextData.cpp @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2010,2012,2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "TextData.h" + +#include "DStarDefines.h" +#include "Utils.h" + +CTextData::CTextData(LINK_STATUS status, const wxString& reflector, const wxString& text, const in_addr& address, unsigned int port, bool temporary) : +m_status(status), +m_reflector(NULL), +m_text(NULL), +m_address(address), +m_port(port), +m_temporary(temporary) +{ + wxASSERT(port > 0U); + + m_reflector = new unsigned char[8U]; + m_text = new unsigned char[20U]; + + ::memset(m_reflector, ' ', 8U); + ::memset(m_text, ' ', 20U); + + if (status != LS_NONE) { + for (unsigned int i = 0U; i < reflector.Length() && i < 8U; i++) + m_reflector[i] = reflector.GetChar(i); + } + + for (unsigned int i = 0U; i < text.Length() && i < 20U; i++) + m_text[i] = text.GetChar(i); +} + +CTextData::CTextData(const wxString& text, const in_addr& address, unsigned int port, bool temporary) : +m_status(LS_NONE), +m_reflector(NULL), +m_text(NULL), +m_address(address), +m_port(port), +m_temporary(temporary) +{ + wxASSERT(port > 0U); + + m_reflector = new unsigned char[8U]; + m_text = new unsigned char[20U]; + + ::memset(m_reflector, ' ', 8U); + ::memset(m_text, ' ', 20U); + + for (unsigned int i = 0U; i < text.Length() && i < 20U; i++) + m_text[i] = text.GetChar(i); +} + +CTextData::~CTextData() +{ + delete[] m_reflector; + delete[] m_text; +} + +unsigned int CTextData::getHBRepeaterData(unsigned char *data, unsigned int length) const +{ + wxASSERT(data != NULL); + wxASSERT(length >= 34U); + + data[0] = 'D'; + data[1] = 'S'; + data[2] = 'R'; + data[3] = 'P'; + + if (m_temporary) { + data[4] = 0x01U; // Temporary text data + ::memcpy(data + 5U, m_text, 20U); + return 25U; + } else { + data[4] = 0x00U; // Permanent text data + ::memcpy(data + 5U, m_text, 20U); + data[25U] = (unsigned char)m_status; + ::memcpy(data + 26U, m_reflector, 8U); + return 34U; + } +} + +in_addr CTextData::getAddress() const +{ + return m_address; +} + +unsigned int CTextData::getPort() const +{ + return m_port; +} diff --git a/Common/TextData.h b/Common/TextData.h new file mode 100644 index 0000000..4184445 --- /dev/null +++ b/Common/TextData.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2010,2011,2012,2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef TextData_H +#define TextData_H + +#include +#include "Defs.h" + +#if defined(__WINDOWS__) +#include "Inaddr.h" +#else +#include +#endif + +class CTextData { +public: + CTextData(LINK_STATUS status, const wxString& reflector, const wxString& text, const in_addr& address, unsigned int port, bool temporary = false); + CTextData(const wxString& text, const in_addr& address, unsigned int port, bool temporary = true); + virtual ~CTextData(); + + unsigned int getHBRepeaterData(unsigned char* data, unsigned int length) const; + + in_addr getAddress() const; + unsigned int getPort() const; + +private: + LINK_STATUS m_status; + unsigned char* m_reflector; + unsigned char* m_text; + in_addr m_address; + unsigned int m_port; + bool m_temporary; +}; + +#endif diff --git a/Common/Timer.cpp b/Common/Timer.cpp new file mode 100644 index 0000000..39e2ff1 --- /dev/null +++ b/Common/Timer.cpp @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2009,2010 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "Timer.h" + +#include + +CTimer::CTimer(unsigned int ticksPerSec, unsigned int secs, unsigned int msecs) : +m_ticksPerSec(ticksPerSec), +m_timeout(0U), +m_timer(0U) +{ + wxASSERT(ticksPerSec > 0U); + + if (secs > 0U || msecs > 0U) { + // m_timeout = ((secs * 1000U + msecs) * m_ticksPerSec) / 1000U + 1U; + unsigned wxLongLong_t temp = (secs * wxULL(1000) + msecs) * m_ticksPerSec; + m_timeout = (unsigned int)(temp / wxULL(1000) + wxULL(1)); + } +} + +CTimer::~CTimer() +{ +} + +void CTimer::setTimeout(unsigned int secs, unsigned int msecs) +{ + if (secs > 0U || msecs > 0U) { + // m_timeout = ((secs * 1000U + msecs) * m_ticksPerSec) / 1000U + 1U; + unsigned wxLongLong_t temp = (secs * wxULL(1000) + msecs) * m_ticksPerSec; + m_timeout = (unsigned int)(temp / wxULL(1000) + wxULL(1)); + } else { + m_timeout = 0U; + m_timer = 0U; + } +} + +unsigned int CTimer::getTimeout() const +{ + if (m_timeout == 0U) + return 0U; + + return (m_timeout - 1U) / m_ticksPerSec; +} + +unsigned int CTimer::getTimer() const +{ + if (m_timer == 0U) + return 0U; + + return (m_timer - 1U) / m_ticksPerSec; +} diff --git a/Common/Timer.h b/Common/Timer.h new file mode 100644 index 0000000..dd09f96 --- /dev/null +++ b/Common/Timer.h @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2009-2014 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef Timer_H +#define Timer_H + +class CTimer { +public: + CTimer(unsigned int ticksPerSec, unsigned int secs = 0U, unsigned int msecs = 0U); + ~CTimer(); + + void setTimeout(unsigned int secs, unsigned int msecs = 0U); + + unsigned int getTimeout() const; + unsigned int getTimer() const; + + unsigned int getRemaining() + { + if (m_timeout == 0U || m_timer == 0U) + return 0U; + + if (m_timer >= m_timeout) + return 0U; + + return (m_timeout - m_timer) / m_ticksPerSec; + } + + bool isRunning() + { + return m_timer > 0U; + } + + void start(unsigned int secs, unsigned int msecs = 0U) + { + setTimeout(secs, msecs); + + start(); + } + + void start() + { + if (m_timeout > 0U) + m_timer = 1U; + } + + void stop() + { + m_timer = 0U; + } + + bool hasExpired() + { + if (m_timeout == 0U || m_timer == 0U) + return false; + + if (m_timer >= m_timeout) + return true; + + return false; + } + + void clock(unsigned int t = 1U) + { + if (m_timer > 0U && m_timeout > 0U) + m_timer += t; + } + +private: + unsigned int m_ticksPerSec; + unsigned int m_timeout; + unsigned int m_timer; +}; + +#endif diff --git a/Common/UDPReaderWriter.cpp b/Common/UDPReaderWriter.cpp new file mode 100644 index 0000000..5a18a8e --- /dev/null +++ b/Common/UDPReaderWriter.cpp @@ -0,0 +1,230 @@ +/* + * Copyright (C) 2006-2014 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "UDPReaderWriter.h" + +#if !defined(__WINDOWS__) +#include +#endif + + +CUDPReaderWriter::CUDPReaderWriter(const wxString& address, unsigned int port) : +m_address(address), +m_port(port), +m_addr(), +m_fd(-1) +{ +#if defined(__WINDOWS__) + WSAData data; + int wsaRet = ::WSAStartup(MAKEWORD(2, 2), &data); + if (wsaRet != 0) + wxLogError(wxT("Error from WSAStartup")); +#endif +} + +CUDPReaderWriter::~CUDPReaderWriter() +{ +#if defined(__WINDOWS__) + ::WSACleanup(); +#endif +} + +in_addr CUDPReaderWriter::lookup(const wxString& hostname) +{ + in_addr addr; +#if defined(WIN32) + unsigned long address = ::inet_addr(hostname.mb_str()); + if (address != INADDR_NONE && address != INADDR_ANY) { + addr.s_addr = address; + return addr; + } + + struct hostent* hp = ::gethostbyname(hostname.mb_str()); + if (hp != NULL) { + ::memcpy(&addr, hp->h_addr_list[0], sizeof(struct in_addr)); + return addr; + } + + wxLogError(wxT("Cannot find address for host %s"), hostname.c_str()); + + addr.s_addr = INADDR_NONE; + return addr; +#else + in_addr_t address = ::inet_addr(hostname.mb_str()); + if (address != in_addr_t(-1)) { + addr.s_addr = address; + return addr; + } + + struct hostent* hp = ::gethostbyname(hostname.mb_str()); + if (hp != NULL) { + ::memcpy(&addr, hp->h_addr_list[0], sizeof(struct in_addr)); + return addr; + } + + wxLogError(wxT("Cannot find address for host %s"), hostname.c_str()); + + addr.s_addr = INADDR_NONE; + return addr; +#endif +} + +bool CUDPReaderWriter::open() +{ + m_fd = ::socket(PF_INET, SOCK_DGRAM, 0); + if (m_fd < 0) { +#if defined(__WINDOWS__) + wxLogError(wxT("Cannot create the UDP socket, err: %lu"), ::GetLastError()); +#else + wxLogError(wxT("Cannot create the UDP socket, err: %d"), errno); +#endif + return false; + } + + if (m_port > 0U) { + sockaddr_in addr; + ::memset(&addr, 0x00, sizeof(sockaddr_in)); + addr.sin_family = AF_INET; + addr.sin_port = htons(m_port); + addr.sin_addr.s_addr = htonl(INADDR_ANY); + + if (!m_address.IsEmpty()) { +#if defined(__WINDOWS__) + addr.sin_addr.s_addr = ::inet_addr(m_address.mb_str()); +#else + addr.sin_addr.s_addr = ::inet_addr(m_address.mb_str()); +#endif + if (addr.sin_addr.s_addr == INADDR_NONE) { + wxLogError(wxT("The address is invalid - %s"), m_address.c_str()); + return false; + } + } + + int reuse = 1; + if (::setsockopt(m_fd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) == -1) { +#if defined(__WINDOWS__) + wxLogError(wxT("Cannot set the UDP socket option (port: %u), err: %lu"), m_port, ::GetLastError()); +#else + wxLogError(wxT("Cannot set the UDP socket option (port: %u), err: %d"), m_port, errno); +#endif + return false; + } + + if (::bind(m_fd, (sockaddr*)&addr, sizeof(sockaddr_in)) == -1) { +#if defined(__WINDOWS__) + wxLogError(wxT("Cannot bind the UDP address (port: %u), err: %lu"), m_port, ::GetLastError()); +#else + wxLogError(wxT("Cannot bind the UDP address (port: %u), err: %d"), m_port, errno); +#endif + return false; + } + } + + return true; +} + +int CUDPReaderWriter::read(unsigned char* buffer, unsigned int length, in_addr& address, unsigned int& port) +{ + // Check that the readfrom() won't block + fd_set readFds; + FD_ZERO(&readFds); +#if defined(__WINDOWS__) + FD_SET((unsigned int)m_fd, &readFds); +#else + FD_SET(m_fd, &readFds); +#endif + + // Return immediately + timeval tv; + tv.tv_sec = 0L; + tv.tv_usec = 0L; + + int ret = ::select(m_fd + 1, &readFds, NULL, NULL, &tv); + if (ret < 0) { +#if defined(__WINDOWS__) + wxLogError(wxT("Error returned from UDP select (port: %u), err: %lu"), m_port, ::GetLastError()); +#else + wxLogError(wxT("Error returned from UDP select (port: %u), err: %d"), m_port, errno); +#endif + return -1; + } + + if (ret == 0) + return 0; + + sockaddr_in addr; +#if defined(__WINDOWS__) + int size = sizeof(sockaddr_in); +#else + socklen_t size = sizeof(sockaddr_in); +#endif + + ssize_t len = ::recvfrom(m_fd, (char*)buffer, length, 0, (sockaddr *)&addr, &size); + if (len <= 0) { +#if defined(__WINDOWS__) + wxLogError(wxT("Error returned from recvfrom (port: %u), err: %lu"), m_port, ::GetLastError()); +#else + wxLogError(wxT("Error returned from recvfrom (port: %u), err: %d"), m_port, errno); +#endif + return -1; + } + + address = addr.sin_addr; + port = ntohs(addr.sin_port); + + return len; +} + +bool CUDPReaderWriter::write(const unsigned char* buffer, unsigned int length, const in_addr& address, unsigned int port) +{ + sockaddr_in addr; + ::memset(&addr, 0x00, sizeof(sockaddr_in)); + + addr.sin_family = AF_INET; + addr.sin_addr = address; + addr.sin_port = htons(port); + + ssize_t ret = ::sendto(m_fd, (char *)buffer, length, 0, (sockaddr *)&addr, sizeof(sockaddr_in)); + if (ret < 0) { +#if defined(__WINDOWS__) + wxLogError(wxT("Error returned from sendto (port: %u), err: %lu"), m_port, ::GetLastError()); +#else + wxLogError(wxT("Error returned from sendto (port: %u), err: %d"), m_port, errno); +#endif + return false; + } + + if (ret != ssize_t(length)) + return false; + + return true; +} + +void CUDPReaderWriter::close() +{ +#if defined(__WINDOWS__) + ::closesocket(m_fd); +#else + ::close(m_fd); +#endif +} + +unsigned int CUDPReaderWriter::getPort() const +{ + return m_port; +} diff --git a/Common/UDPReaderWriter.h b/Common/UDPReaderWriter.h new file mode 100644 index 0000000..4167662 --- /dev/null +++ b/Common/UDPReaderWriter.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2009-2011,2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef UDPReaderWriter_H +#define UDPReaderWriter_H + +#include + +#if !defined(__WINDOWS__) +#include +#include +#include +#include +#include +#include +#include +#include +#endif + +class CUDPReaderWriter { +public: + CUDPReaderWriter(const wxString& address, unsigned int port); + ~CUDPReaderWriter(); + + static in_addr lookup(const wxString& hostName); + + bool open(); + + int read(unsigned char* buffer, unsigned int length, in_addr& address, unsigned int& port); + bool write(const unsigned char* buffer, unsigned int length, const in_addr& address, unsigned int port); + + void close(); + + unsigned int getPort() const; + +private: + wxString m_address; + unsigned short m_port; + in_addr m_addr; + int m_fd; +}; + +#endif diff --git a/Common/UserCache.cpp b/Common/UserCache.cpp new file mode 100644 index 0000000..2536abf --- /dev/null +++ b/Common/UserCache.cpp @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2010 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "UserCache.h" + +const unsigned int CACHE_SIZE = 1000U; + +CUserCache::CUserCache() : +m_cache(CACHE_SIZE) +{ +} + +CUserCache::~CUserCache() +{ + for (CUserCache_t::iterator it = m_cache.begin(); it != m_cache.end(); ++it) + delete it->second; +} + +CUserRecord* CUserCache::find(const wxString& user) +{ + return m_cache[user]; +} + +void CUserCache::update(const wxString& user, const wxString& repeater, const wxString& timestamp) +{ + CUserRecord* rec = m_cache[user]; + + if (rec == NULL) + // A brand new record is needed + m_cache[user] = new CUserRecord(user, repeater, timestamp); + else if(timestamp.Cmp(rec->getTimeStamp()) > 0) { + // Update an existing record, but only if the received timestamp is newer + rec->setRepeater(repeater); + rec->setTimestamp(timestamp); + } +} + +unsigned int CUserCache::getCount() const +{ + return m_cache.size(); +} diff --git a/Common/UserCache.h b/Common/UserCache.h new file mode 100644 index 0000000..c040ad2 --- /dev/null +++ b/Common/UserCache.h @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2010 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef UserCache_H +#define UserCache_H + +#include +#include + +class CUserRecord { +public: + CUserRecord(const wxString& user, const wxString& repeater, const wxString& timestamp) : + m_user(user), + m_repeater(repeater), + m_timestamp(timestamp) + { + } + + wxString getUser() const + { + return m_user; + } + + wxString getRepeater() const + { + return m_repeater; + } + + wxString getTimeStamp() const + { + return m_timestamp; + } + + void setRepeater(const wxString& repeater) + { + m_repeater = repeater; + } + + void setTimestamp(const wxString& timestamp) + { + m_timestamp = timestamp; + } + +private: + wxString m_user; + wxString m_repeater; + wxString m_timestamp; +}; + +WX_DECLARE_STRING_HASH_MAP(CUserRecord*, CUserCache_t); + +class CUserCache { +public: + CUserCache(); + ~CUserCache(); + + CUserRecord* find(const wxString& user); + + void update(const wxString& user, const wxString& repeater, const wxString& timestamp); + + unsigned int getCount() const; + +private: + CUserCache_t m_cache; +}; + +#endif diff --git a/Common/Utils.cpp b/Common/Utils.cpp new file mode 100644 index 0000000..3cb449b --- /dev/null +++ b/Common/Utils.cpp @@ -0,0 +1,257 @@ +/* + * Copyright (C) 2009,2013 Jonathan Naylor, G4KLX + * + * 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 + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "Utils.h" + +void CUtils::dump(const wxChar* title, const bool* data, unsigned int length) +{ + wxASSERT(title != NULL); + wxASSERT(data != NULL); + + wxLogMessage(wxT("%s"), title); + + unsigned int offset = 0U; + + while (offset < length) { + wxString output; + + unsigned char buffer[16]; + unsigned int bytes = 0U; + for (unsigned int bits = 0U; bits < 128U && (offset + bits) < length; bits += 8U) + buffer[bytes++] = bitsToByte(data + offset + bits); + + for (unsigned i = 0U; i < bytes; i++) { + wxString temp; + temp.Printf(wxT("%02X "), buffer[i]); + output += temp; + } + + for (unsigned int i = bytes; i < 16U; i++) + output += wxT(" "); + + output += wxT(" *"); + + for (unsigned i = 0U; i < bytes; i++) { + unsigned char c = buffer[i]; + + if (::isprint(c)) + output += wxChar(c); + else + output += wxT('.'); + } + + output += wxT('*'); + + wxLogMessage(wxT("%04X: %s"), offset / 8U, output.c_str()); + + offset += 128U; + } +} + +void CUtils::dumpRev(const wxChar* title, const bool* data, unsigned int length) +{ + wxASSERT(title != NULL); + wxASSERT(data != NULL); + + wxLogMessage(wxT("%s"), title); + + unsigned int offset = 0U; + + while (offset < length) { + wxString output; + + unsigned char buffer[16]; + unsigned int bytes = 0U; + for (unsigned int bits = 0U; bits < 128U && (offset + bits) < length; bits += 8U) + buffer[bytes++] = bitsToByteRev(data + offset + bits); + + for (unsigned i = 0U; i < bytes; i++) { + wxString temp; + temp.Printf(wxT("%02X "), buffer[i]); + output += temp; + } + + for (unsigned int i = bytes; i < 16U; i++) + output += wxT(" "); + + output += wxT(" *"); + + for (unsigned i = 0U; i < bytes; i++) { + unsigned char c = buffer[i]; + + if (::isprint(c)) + output += wxChar(c); + else + output += wxT('.'); + } + + output += wxT('*'); + + wxLogMessage(wxT("%04X: %s"), offset / 8U, output.c_str()); + + offset += 128U; + } +} + +void CUtils::dump(const wxChar* title, const unsigned char* data, unsigned int length) +{ + wxASSERT(title != NULL); + wxASSERT(data != NULL); + + wxLogMessage(wxT("%s"), title); + + unsigned int offset = 0U; + + while (length > 0U) { + wxString output; + + unsigned int bytes = (length > 16U) ? 16U : length; + + for (unsigned i = 0U; i < bytes; i++) { + wxString temp; + temp.Printf(wxT("%02X "), data[offset + i]); + output += temp; + } + + for (unsigned int i = bytes; i < 16U; i++) + output += wxT(" "); + + output += wxT(" *"); + + for (unsigned i = 0U; i < bytes; i++) { + unsigned char c = data[offset + i]; + + if (::isprint(c)) + output += wxChar(c); + else + output += wxT('.'); + } + + output += wxT('*'); + + wxLogMessage(wxT("%04X: %s"), offset, output.c_str()); + + offset += 16U; + + if (length >= 16U) + length -= 16U; + else + length = 0U; + } +} + +unsigned char CUtils::bitsToByte(const bool* bits) +{ + wxASSERT(bits != NULL); + + unsigned char val = 0x00; + + for (unsigned int i = 0U; i < 8U; i++) { + val <<= 1; + + if (bits[i]) + val |= 0x01; + } + + return val; +} + +unsigned char CUtils::bitsToByteRev(const bool* bits) +{ + wxASSERT(bits != NULL); + + unsigned char val = 0x00; + + for (unsigned int i = 0U; i < 8U; i++) { + val >>= 1; + + if (bits[i]) + val |= 0x80; + } + + return val; +} + +void CUtils::byteToBits(unsigned char byte, bool* data) +{ + wxASSERT(data != NULL); + + unsigned char mask = 0x80U; + for (unsigned int i = 0U; i < 8U; i++, mask >>= 1) + data[i] = byte & mask ? true : false; +} + +void CUtils::byteToBitsRev(unsigned char byte, bool* data) +{ + wxASSERT(data != NULL); + + unsigned char mask = 0x01U; + for (unsigned int i = 0U; i < 8U; i++, mask <<= 1) + data[i] = byte & mask ? true : false; +} + +wxString CUtils::latLonToLoc(double latitude, double longitude) +{ + if (latitude < -90.0 || latitude > 90.0) + return wxEmptyString; + + if (longitude < -360.0 || longitude > 360.0) + return wxEmptyString; + + latitude += 90.0; + + if (longitude > 180.0) + longitude -= 360.0; + + if (longitude < -180.0) + longitude += 360.0; + + longitude += 180.0; + + char locator[6U]; + + double lon = ::floor(longitude / 20.0); + double lat = ::floor(latitude / 10.0); + + locator[0U] = 'A' + (unsigned int)lon; + locator[1U] = 'A' + (unsigned int)lat; + + longitude -= lon * 20.0; + latitude -= lat * 10.0; + + lon = ::floor(longitude / 2.0); + lat = ::floor(latitude / 1.0); + + locator[2U] = '0' + (unsigned int)lon; + locator[3U] = '0' + (unsigned int)lat; + + longitude -= lon * 2.0; + latitude -= lat * 1.0; + + lon = ::floor(longitude / (2.0 / 24.0)); + lat = ::floor(latitude / (1.0 / 24.0)); + + locator[4U] = 'A' + (unsigned int)lon; + locator[5U] = 'A' + (unsigned int)lat; + + return wxString(locator, wxConvLocal, 6U); +} + +void CUtils::clean(wxString &str, const wxString& allowed) +{ + for (unsigned int i = 0U; i < str.Len(); i++) { + int n = allowed.Find(str.GetChar(i)); + if (n == wxNOT_FOUND) + str.SetChar(i, wxT(' ')); + } +} diff --git a/Common/Utils.h b/Common/Utils.h new file mode 100644 index 0000000..2f51ab5 --- /dev/null +++ b/Common/Utils.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2009,2013 by Jonathan Naylor, G4KLX + * + * 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 + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef Utils_H +#define Utils_H + +#include + +enum TRISTATE { + STATE_FALSE, + STATE_TRUE, + STATE_UNKNOWN +}; + +class CUtils { +public: + static void dump(const wxChar* title, const bool* data, unsigned int length); + static void dumpRev(const wxChar* title, const bool* data, unsigned int length); + static void dump(const wxChar* title, const unsigned char* data, unsigned int length); + static unsigned char bitsToByte(const bool* bits); + static unsigned char bitsToByteRev(const bool* bits); + static void byteToBits(unsigned char byte, bool* bits); + static void byteToBitsRev(unsigned char byte, bool* bits); + static wxString latLonToLoc(double latitude, double longitude); + static void clean(wxString& str, const wxString& allowed); + +private: +}; + +#endif diff --git a/Common/Version.h b/Common/Version.h new file mode 100644 index 0000000..9138fe5 --- /dev/null +++ b/Common/Version.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2010-2015,2018 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef Version_H +#define Version_H + +#include + +const wxString VENDOR_NAME = wxT("G4KLX"); + +#if defined(__WXDEBUG__) +const wxString VERSION = wxT("20180509 - DEBUG"); +#else +const wxString VERSION = wxT("20180509"); +#endif + +#endif diff --git a/Common/VersionUnit.cpp b/Common/VersionUnit.cpp new file mode 100644 index 0000000..e9ca109 --- /dev/null +++ b/Common/VersionUnit.cpp @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2011-2014 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "SlowDataEncoder.h" +#include "DStarDefines.h" +#include "VersionUnit.h" +#include "HeaderData.h" +#include "Version.h" + +const unsigned int NUM_FRAMES = 20U; + +CVersionUnit::CVersionUnit(IRepeaterCallback* handler, const wxString& callsign) : +m_handler(handler), +m_callsign(callsign), +m_status(VS_IDLE), +m_timer(1000U, REPLY_TIME), +m_data(NULL), +m_id(0U), +m_out(0U), +m_time() +{ + wxASSERT(handler != NULL); + + m_data = new CAMBEData*[NUM_FRAMES]; + + wxString versionText; + versionText.Printf(wxT("ircDDB GW - %s"), VERSION.Left(8U).c_str()); + + wxLogMessage(wxT("Version text set to \"%s\""), versionText.c_str()); + + CSlowDataEncoder encoder; + encoder.setTextData(versionText); + + // Seq No and end + for (unsigned int i = 0U; i < NUM_FRAMES; i++) { + unsigned char buffer[DV_FRAME_LENGTH_BYTES]; + ::memcpy(buffer + 0U, NULL_AMBE_DATA_BYTES, VOICE_FRAME_LENGTH_BYTES); + + // Insert sync bytes when the sequence number is zero, slow data otherwise + if (i == 0U) { + ::memcpy(buffer + VOICE_FRAME_LENGTH_BYTES, DATA_SYNC_BYTES, DATA_FRAME_LENGTH_BYTES); + encoder.sync(); + } else { + encoder.getTextData(buffer + VOICE_FRAME_LENGTH_BYTES); + } + + m_data[i] = new CAMBEData; + m_data[i]->setData(buffer, DV_FRAME_LENGTH_BYTES); + m_data[i]->setSeq(i); + + if (i == (NUM_FRAMES - 1U)) + m_data[i]->setEnd(true); + } +} + +CVersionUnit::~CVersionUnit() +{ + for (unsigned int i = 0U; i < NUM_FRAMES; i++) + delete m_data[i]; + + delete[] m_data; +} + +void CVersionUnit::sendVersion() +{ + if (m_status != VS_IDLE) + return; + + m_id = CHeaderData::createId(); + + m_status = VS_WAIT; + m_timer.start(); +} + +void CVersionUnit::clock(unsigned int ms) +{ + m_timer.clock(ms); + + if (m_status == VS_WAIT && m_timer.hasExpired()) { + m_timer.stop(); + + // RPT1 and RPT2 will be filled in later + CHeaderData header; + header.setMyCall1(m_callsign); + header.setMyCall2(wxT("VERS")); + header.setYourCall(wxT("CQCQCQ ")); + header.setId(m_id); + + m_handler->process(header, DIR_INCOMING, AS_VERSION); + + m_out = 0U; + m_status = VS_TRANSMIT; + + m_time.Start(); + + return; + } + + if (m_status == VS_TRANSMIT) { + unsigned int needed = m_time.Time() / DSTAR_FRAME_TIME_MS; + + while (m_out < needed) { + CAMBEData* data = m_data[m_out]; + data->setId(m_id); + + m_out++; + + m_handler->process(*data, DIR_INCOMING, AS_VERSION); + + if (m_out == NUM_FRAMES) { + m_out = 0U; + m_status = VS_IDLE; + return; + } + } + + return; + } +} + +void CVersionUnit::cancel() +{ + m_status = VS_IDLE; + m_out = 0U; + + m_timer.stop(); +} diff --git a/Common/VersionUnit.h b/Common/VersionUnit.h new file mode 100644 index 0000000..b70326e --- /dev/null +++ b/Common/VersionUnit.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2012 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef VersionUnit_H +#define VersionUnit_H + +#include "RepeaterCallback.h" +#include "AMBEData.h" +#include "Timer.h" +#include "Defs.h" + +#include + +enum VERSION_STATUS { + VS_IDLE, + VS_WAIT, + VS_TRANSMIT +}; + +class CVersionUnit { +public: + CVersionUnit(IRepeaterCallback* handler, const wxString& callsign); + ~CVersionUnit(); + + void sendVersion(); + + void cancel(); + + void clock(unsigned int ms); + +private: + IRepeaterCallback* m_handler; + wxString m_callsign; + VERSION_STATUS m_status; + CTimer m_timer; + CAMBEData** m_data; + unsigned int m_id; + unsigned int m_out; + wxStopWatch m_time; +}; + +#endif diff --git a/Common/XLXHostsFileDownloader.cpp b/Common/XLXHostsFileDownloader.cpp new file mode 100644 index 0000000..bcf86de --- /dev/null +++ b/Common/XLXHostsFileDownloader.cpp @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2010-2013,2015 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "XLXHostsFileDownloader.h" +#ifdef XLX_USE_WGET +#include +#else +#include +#endif +#include + +/* wxHTTP randomly crashes when called on a worker thread, this must be called from main thread ! */ +wxString CXLXHostsFileDownloader::Download(const wxString & xlxHostsFileURL) +{ +#ifdef XLX_USE_WGET + wxString xlxHostsFileName = wxFileName::CreateTempFileName(_T("XLX_Hosts_")); + wxString commandLine = _T("wget -q -O ") + xlxHostsFileName + _T(" ") + xlxHostsFileURL; + bool execResult = wxShell(commandLine); + + if(!execResult) { + wxLogError(_T("Unable do download XLX host file, make sure wget is installed")); + return wxEmptyString; + } + + return xlxHostsFileName; +#else + wxHTTP http; + http.SetNotify(false); + http.SetFlags(wxSOCKET_WAITALL); + http.SetHeader( _T("Accept") , _T("text/*") ); + http.SetHeader( _T("User-Agent"), _T("ircddbGateway") ); + http.SetTimeout(5); // seconds + + wxLogMessage(_T("Downloading XLX reflector list from %s"), xlxHostsFileURL.c_str()); + + // remove "http://" from the url, i.e. minus 7 chars + size_t len = xlxHostsFileURL.length(); + wxString path = xlxHostsFileURL.Right(len-7); + + // find the first forward slash + int slash = path.Find(wxChar('/')); + len = path.length(); + wxString server = path.Left(slash); + path = path.Right(len-slash); + + // Note that Connect() wants a host address, not an URL. 80 is the server's port. + if(!http.Connect(server, 80 )) { + wxLogError(_T("Failed to connect to %s"), server); + return wxEmptyString; + } + + wxInputStream* in = NULL; + if((in = http.GetInputStream(path)) && in->IsOk()) { + wxFile file; + wxString xlxHostsFileName = wxFileName::CreateTempFileName(_T("XLX_Hosts_"), &file); + wxLogMessage(_T("Created temporary file %s"), xlxHostsFileName); + if(!file.IsOpened()) { + wxLogError(_T("Failed to open temporary file %s"), xlxHostsFileName); + wxDELETE(in); + return wxEmptyString; + } + + //in->Read(fileStream); + //fileStream.Write(*in); + //in->Read(tempFileStream); + //Both call above seem to not work when run in a separate thread, hence the old fashion loop below + unsigned char buffer[2048]; + while(!in->Eof()) { + in->Read(buffer, 2048); + int readCount = in->LastRead(); + if(readCount <= 0) + break; + + file.Write(buffer, readCount); + } + wxLogMessage(_T("XLX Successfuly downloaded to %s"), xlxHostsFileName); + file.Close(); + http.Close(); + wxDELETE(in); + return xlxHostsFileName; + } + + wxLogError(_T("Failed to get HTTP stream")); + if(in) wxDELETE(in); + + return wxEmptyString; +#endif +} diff --git a/Common/XLXHostsFileDownloader.h b/Common/XLXHostsFileDownloader.h new file mode 100644 index 0000000..7fba376 --- /dev/null +++ b/Common/XLXHostsFileDownloader.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2010-2013,2015 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + +#ifndef XLXHostsFileDownloader_H +#define XLXHostsFileDownloader_H +#define XLX_USE_WGET +#include + +class CXLXHostsFileDownloader { +public: + static wxString Download(const wxString & xlxHostsFileURL); +}; + +#endif diff --git a/Data/CCS_Hosts.txt b/Data/CCS_Hosts.txt new file mode 100644 index 0000000..e572182 --- /dev/null +++ b/Data/CCS_Hosts.txt @@ -0,0 +1,15 @@ +CCS701 ccs701.xreflector.net +CCS702 ccs702.xreflector.net +CCS703 ccs703.xreflector.net +CCS704 ccs704.xreflector.net +CCS705 ccs705.xreflector.net +CCS706 ccs706.xreflector.net +CCS707 ccs707.xreflector.net +CCS710 ccs710.xreflector.net +CCS711 ccs711.xreflector.net +CCS713 ccs713.xreflector.net +CCS721 ccs721.xreflector.net +CCS722 ccs722.xreflector.net +CCS724 ccs724.xreflector.net +CCS728 ccs728.xreflector.net +CCS732 ccs732.xreflector.net diff --git a/Data/DCS_Hosts.txt b/Data/DCS_Hosts.txt new file mode 100644 index 0000000..1d3667d --- /dev/null +++ b/Data/DCS_Hosts.txt @@ -0,0 +1,244 @@ +DCS000 206.208.56.92 +DCS001 dcs001.xreflector.net +DCS002 dcs002.xreflector.net +DCS003 dcs003.xreflector.net +DCS004 dcs004.xreflector.net +DCS005 www.bm-dmr.uk +DCS006 dcs006.xreflector.net +DCS007 dcs007.xreflector.net +DCS008 dcs008.xreflector.net +DCS009 dcs009.xreflector.net +DCS010 dcs010.xreflector.net +DCS011 dcs011.xreflector.net +DCS012 dcs012.xreflector.net +DCS013 dcs013.xreflector.net +DCS014 dcs014.xreflector.net +DCS015 dcs015.xreflector.net +DCS016 dcs016.xreflector.net +DCS017 dcs017.xreflector.net +DCS018 dcs018.xreflector.net +DCS019 dcs019.xreflector.net +DCS021 dcs021.xreflector.net +DCS022 dcs022.xreflector.net +DCS023 dcs023.xreflector.net +DCS024 dcs024.xreflector.net +DCS025 dcs025.xreflector.net +DCS026 dcs026.xreflector.net +DCS027 dcs027.xreflector.net +DCS028 xlx028.org L +DCS029 dcs029.xreflector.net +DCS032 dcs032.xreflector.net +DCS033 dcs033.xreflector.net +DCS035 45.79.94.184 +DCS039 185.203.118.66 +DCS040 109.71.45.29 +DCS041 45.62.226.137 +DCS044 dcs044.xreflector.net +DCS045 64.137.172.60 +DCS046 176.10.140.161 +DCS047 121.94.218.243 +DCS050 212.237.17.133 +DCS051 93.186.254.219 +DCS052 60.47.177.125 +DCS054 52.86.180.251 +DCS055 52.80.4.154 +DCS057 74.193.209.20 +DCS058 118.236.151.192 +DCS060 212.237.36.181 +DCS061 68.115.205.110 +DCS062 70.88.145.163 +DCS064 202.241.175.133 +DCS066 79.16.44.125 +DCS068 92.222.145.202 +DCS069 89.36.214.120 +DCS071 211.60.41.185 +DCS072 211.60.41.186 +DCS075 5.135.162.136 +DCS076 203.137.116.117 +DCS077 5.249.151.111 +DCS078 109.10.128.221 +DCS079 121.162.91.94 +DCS080 121.85.180.61 +DCS081 121.84.13.151 +DCS082 108.21.232.21 +DCS083 108.21.232.22 +DCS085 27.92.11.123 +DCS086 220.133.89.28 +DCS087 44.137.36.209 +DCS088 194.109.192.235 +DCS089 194.109.192.236 +DCS090 91.92.136.252 +DCS092 94.177.190.50 +DCS093 98.29.99.252 +DCS095 58.1.93.223 +DCS098 111.168.216.126 +DCS099 212.237.59.103 +DCS100 96.94.7.196 +DCS101 104.233.105.86 +DCS102 206.208.56.13 +DCS103 64.137.248.42 +DCS104 206.208.56.93 +DCS111 81.95.126.168 +DCS112 216.45.55.151 +DCS114 91.121.136.94 +DCS115 217.182.128.3 +DCS116 31.185.101.211 +DCS118 5.249.148.252 +DCS119 125.129.207.86 +DCS120 24.43.83.140 +DCS121 174.37.249.156 +DCS124 211.14.169.234 +DCS125 213.181.208.52 +DCS127 190.112.228.107 +DCS128 153.249.96.5 +DCS145 178.59.23.138 +DCS146 87.228.241.43 +DCS147 46.41.1.127 +DCS150 212.237.3.87 +DCS170 210.178.113.173 +DCS171 121.162.91.45 +DCS185 118.152.21.76 +DCS204 185.85.18.162 +DCS206 193.190.240.227 +DCS208 151.80.155.39 +DCS210 45.62.210.243 +DCS212 52.38.90.188 +DCS214 185.47.129.230 +DCS216 74.214.25.135 +DCS222 93.189.136.50 +DCS227 86.122.173.9 +DCS228 212.237.33.114 +DCS230 80.250.3.114 +DCS232 213.47.219.169 +DCS241 151.80.158.227 +DCS242 73.14.84.43 +DCS246 172.93.48.159 +DCS248 158.69.206.45 +DCS252 118.21.66.186 +DCS255 245.115.35.52 +DCS261 44.144.0.23 +DCS262 44.144.0.24 +DCS264 52.2.131.118 +DCS265 51.255.43.60 +DCS270 158.64.26.132 +DCS291 60.112.168.104 +DCS295 45.62.238.78 +DCS298 133.208.206.141 +DCS299 125.236.227.43 +DCS300 64.137.172.56 +DCS302 144.217.241.23 +DCS307 104.36.40.243 +DCS310 64.137.165.141 +DCS311 78.47.206.12 +DCS313 xlx313.openstd.net +DCS317 44.48.8.15 +DCS321 31.207.110.231 +DCS333 194.116.29.73 +DCS334 199.119.98.174 +DCS336 23.226.233.133 +DCS339 198.98.53.247 +DCS357 52.39.82.54 +DCS359 79.232.250.96 +DCS365 59.139.141.204 +DCS370 188.213.168.24 +DCS373 101.143.24.88 +DCS382 61.116.7.187 +DCS389 106.71.106.79 +DCS390 31.14.140.230 +DCS398 45.62.243.153 +DCS404 91.229.143.187 +DCS412 42.151.104.175 +DCS433 217.160.22.17 +DCS440 114.176.44.90 +DCS441 203.137.99.110 +DCS444 188.68.37.51 +DCS450 64.137.161.11 +DCS486 51.255.172.249 +DCS499 59.157.4.151 +DCS500 172.104.32.192 +DCS502 74.208.88.137 +DCS515 163.44.167.125 +DCS518 176.9.1.168 +DCS519 24.55.202.247 +DCS520 202.6.18.14 +DCS538 133.137.49.171 +DCS550 151.80.141.175 +DCS555 64.137.186.11 +DCS569 219.122.146.110 +DCS570 104.128.230.153 +DCS573 216.189.148.204 +DCS595 219.104.19.203 +DCS600 13.69.14.204 +DCS601 51.141.52.193 +DCS602 212.56.100.200 +DCS603 24.233.107.8 +DCS610 103.1.213.21 +DCS616 44.103.39.7 +DCS626 202.137.244.157 +DCS666 54.144.216.63 +DCS689 97.107.128.47 +DCS699 82.102.5.239 +DCS700 78.47.222.93 +DCS706 93.186.255.126 +DCS707 90.145.156.196 +DCS708 202.218.37.62 +DCS709 212.237.34.32 +DCS711 212.237.18.27 +DCS712 153.227.250.188 +DCS714 85.214.119.76 +DCS724 191.232.36.180 +DCS737 195.130.75.246 +DCS746 178.254.34.44 +DCS747 93.209.43.173 +DCS748 64.137.197.36 +DCS750 203.86.206.49 +DCS751 210.55.201.126 +DCS755 193.248.45.246 +DCS766 201.62.48.61 +DCS773 94.177.175.230 +DCS777 45.62.251.163 +DCS781 175.179.238.153 +DCS787 87.154.55.113 +DCS789 75.144.65.122 +DCS800 52.26.26.195 +DCS801 77.117.160.175 +DCS807 118.8.17.123 +DCS812 126.25.168.252 +DCS813 97.76.81.165 +DCS850 88.198.94.77 +DCS870 103.3.234.95 +DCS880 176.10.105.211 +DCS886 118.163.103.178 +DCS887 118.163.103.177 +DCS888 31.14.135.7 +DCS897 92.222.23.124 +DCS900 85.214.114.27 +DCS901 77.117.160.175 +DCS906 212.237.11.53 +DCS908 212.237.2.183 +DCS909 216.86.147.198 +DCS910 94.177.207.26 +DCS911 5.196.73.89 +DCS921 44.143.184.83 +DCS929 158.69.166.132 +DCS930 94.177.160.5 +DCS931 173.50.88.34 +DCS933 37.59.119.115 +DCS940 202.218.37.121 +DCS950 158.64.26.134 +DCS960 80.211.226.89 +DCS964 52.173.142.244 +DCS967 95.158.165.32 +DCS972 46.121.158.50 +DCS974 94.177.217.52 +DCS975 176.31.161.9 +DCS976 212.237.36.71 +DCS978 193.70.0.229 +DCS986 81.89.102.160 +DCS987 185.32.183.148 +DCS989 xrf989.bbhill.net +DCS990 35.164.237.63 +DCS995 142.116.255.245 +DCS997 94.177.187.40 +DCS998 44.140.236.20 +DCS999 94.177.173.53 diff --git a/Data/DExtra_Hosts.txt b/Data/DExtra_Hosts.txt new file mode 100644 index 0000000..d97b33d --- /dev/null +++ b/Data/DExtra_Hosts.txt @@ -0,0 +1,199 @@ +#>>Downloaded from W6KD host file server +#>>Last updated 17 NOV 2016 by W6KD + +XRF000 000.xreflector.org +XRF001 xlx001.homepc.it +XRF002 xrf002.dstar.club +XRF003 xrf003.iw0red.it +XRF004 xrf004.kb8zgl.net +XRF005 216.16.240.236 +XRF006 xrf006.xrefl.net +XRF007 xrf007.ea5gf.es +XRF008 95.110.231.219 +XRF010 xlx010.n8qq.com +XRF011 xlx011.n8qq.com +XRF012 xrf012.papasys.com +XRF014 xrf014.iz0rin.it +XRF015 xrf015.theapplecore.me +XRF016 xrf016.ampr.at +XRF018 99.167.129.166 +XRF019 66.30.81.236 +XRF020 67.210.212.144 +XRF021 44.103.32.250 +XRF022 xrf022.tms-it.net +XRF024 xrf024.dstar.at +XRF025 025.ham-digital.es +XRF027 194.116.29.78 +XRF028 stn028.dstar.be +XRF029 xrf029.tms-it.net +XRF030 xrf030.oe3xht.at +XRF032 xlx032.epf.lu +XRF033 46.226.178.81 +XRF035 xrf035.wa7dre.org +XRF036 xrf036.ddns.net +XRF037 185.58.193.163 +XRF038 66.6.171.228 +XRF040 xrf040.dyndns.org +XRF041 167.88.37.80 +XRF042 xrf042.luthienstar.fr +XRF043 xrf043.aotnet.it +XRF044 82.1.185.173 +XRF045 45.62.233.223 +XRF046 xlx.c4fm.se +XRF047 xlx047.ddns.net +XRF052 xrf052.dip.jp +XRF055 95.110.229.195 +XRF061 68.115.205.110 +XRF062 xlx.maryland-dstar.net +XRF063 162.248.141.148 +XRF064 xrf064.owari.biz +XRF067 xrf067.f5kav.org +XRF068 xrf068.ircddb.it +XRF069 069.xreflector.es +XRF070 xrf070.iptime.org +XRF071 xrf.elechomebrew.com +XRF073 147.102.7.34 +XRF074 xrf074.dyndns.org +XRF075 xrf075.ir9bs.it +XRF076 xrf076.xreflector-jp.org +XRF077 xrf077.duckdns.org +XRF078 xrf078.duckdns.org +XRF080 jr3vh.jpn.ph.jp +XRF081 ja3gqj.dip.jp +XRF084 xrf084.fabbroni.eu +XRF085 jr1ofp.dip.jp +XRF088 xrf088.pa4tw.nl +XRF091 091.xreflector.es +XRF098 xrf098.dip.jp +XRF100 xlx100.xlxreflector.org +XRF101 xlx101.xlxreflector.org +XRF102 xlx102.xlxreflector.org +XRF103 xlx103.xlxreflector.org +XRF104 xlx104.xlxreflector.org +XRF112 112.xreflector.es +XRF113 xlx113.homepc.it +XRF113 xrf113.dstarspain.es +XRF118 xlx118.ns0.it +XRF120 24.43.83.140 +XRF123 213.126.90.100 +XRF125 xlx125.dyndns.hu +XRF132 xrf132.dstar.radom.pl +XRF133 xrf133.gb7de.co.uk +XRF145 178.59.21.32 +XRF147 46.41.1.127 +XRF150 xrf150.dstarspain.es +XRF170 dvham.mooo.com +XRF177 xlx177.webandcloud.net +XRF200 xrf200.theapplecore.co.uk +XRF204 xlx204.ph0dv.nl +XRF210 210.xreflector.org +XRF212 xlx212.dstar.club +XRF214 xlx214.sustrai.org +XRF216 74.214.25.135 +XRF223 k0pra.ddns.net +XRF232 xrf232.tms-it.net +XRF248 xrf248.dyndns.org +XRF250 xrf250.dstar.su +XRF255 xrf255.reflector.up4dar.de +XRF262 xrf262.reflector.up4dar.de +XRF264 52.2.131.118 +XRF270 xrf270.reflector.up4dar.de +XRF275 xrf275.dyndns.org +XRF295 xrf295.dyndns.org +XRF300 300.xreflector.org +XRF307 xlx307.ddns.net +XRF308 xlx308.w6kd.com +XRF310 xrf310.xrefl.net +XRF311 xrf311.ernix.de +XRF312 xrf312.xrefl.net +XRF313 xlx313.xrefl.net +XRF314 xlx314.xrefl.net +XRF317 xrf317.crossroadsdmr.org +XRF321 vps.makeitrad.com +XRF333 xrf333.f1smf.com +XRF336 xrf336.mawcg.org +XRF350 350.dstarspain.es +XRF353 94.173.206.53 +XRF357 xlx357.w6kd.com +XRF370 xrf370.selfip.com +XRF387 195.130.59.77 +XRF390 xrf390.aotnet.it +XRF398 104.167.117.71 +XRF400 xrf400.no-ip.org +XRF404 xlx.bendiksverden.net +XRF413 xlx413.xrefl.net +XRF420 kc9qen.com +XRF423 4ix.hacktic.de +XRF433 xrf433.de +XRF440 dg8rp.dynaccess.de +XRF443 xrf443.arisondrio.it +XRF444 xlx444.pa3dfn.nl +XRF450 450.xreflector.org +XRF456 xrf456.de +XRF490 xrf490.dyndns.org +XRF500 125.63.57.138 +XRF502 74.208.88.137 +XRF518 xrf518.n18.de +XRF519 24.55.196.105 +XRF550 550.xreflector.es +XRF555 xrf555.w6kd.com +XRF556 xrf556.w6kd.com +XRF569 xlxreflector.jpn.ph +XRF570 xrf.no-ip.org +XRF573 216.189.148.204 +XRF580 67.20.31.79 +XRF600 xrf600.gb7de.co.uk +XRF603 xlx603.cnharc.org +XRF610 xrf610.vkradio.com +XRF666 vpngrf.webandcloud.net +XRF669 xrf669.no-ip.org +XRF678 xrf678.ddns.net +XRF699 xlx.tekniksnack.se +XRF700 xrf700.d-star.se +XRF706 xlx706.iz0rin.it +XRF707 xrf707.openquad.net +XRF710 oe7mfi.ddns.net +XRF714 85.214.119.76 +XRF719 199.227.117.121 +XRF720 xrf720.freestar.us +XRF724 191.232.36.180 +XRF727 w4icy.inerrantenergy.com +XRF737 195.130.75.246 +XRF740 imagewell.duckdns.org +XRF747 xrf747.de +XRF748 xrf748.dyndns.org +XRF750 104.128.230.153 +XRF757 xrf757.openquad.net +XRF766 xlx.amrase.org.br +XRF767 xrf767.de +XRF773 xrf773.iz0rin.it +XRF777 112.218.40.91 +XRF787 xrf787.de +XRF789 xrf789.dstarxlx.com.br +XRF807 hajikko.iobb.net +XRF810 810.xreflector.org +XRF813 kj4qal.inerrantenergy.com +XRF828 xlx828.ddnss.de +XRF850 xrf850.xrfmaster.net +XRF851 xrf851.rsdt.de +XRF860 xrf.njpaasterisk.org +XRF870 103.18.207.114 +XRF886 xrf886.metropit.net +XRF888 xlx888.ns0.it +XRF897 92.222.23.124 +XRF901 xrf901.dyndns.org +XRF902 xrf902.dyndns.org +XRF905 199.212.121.20 +XRF906 xrf906.radioclubveleta.es +XRF909 xrf909.ealink.org +XRF911 5.196.73.89 +XRF920 xrf920.oe7xxr.ampr.at +XRF929 xrf929.ddns.net +XRF930 xreflector.ddns.net +XRF950 xlx950.epf.lu +XRF986 81.89.102.160 +XRF987 xrf987.metro-uhf.org +XRF988 988.xreflector.es +XRF989 xrf989.bbhill.net +XRF998 xlx.sm7.hamnet.nu +XRF999 xrf999.no-ip.org diff --git a/Data/DPlus_Hosts.txt b/Data/DPlus_Hosts.txt new file mode 100644 index 0000000..5e6bf6c --- /dev/null +++ b/Data/DPlus_Hosts.txt @@ -0,0 +1,110 @@ +#>>Downloaded from W6KD host file server +#>>Last updated 17 NOV 2016 by W6KD +#>>Request changes on this server's lists by posting at +#>>http://xrefl.boards.net/board/2/directory-changes-forum +REF001 ref001.dstargateway.org +REF002 ref002.dstargateway.org +REF003 ref003.dstargateway.org +REF004 ref004.dstargateway.org +REF005 ref005.dstargateway.org +REF006 ref006.dstargateway.org +REF007 ref007.dstargateway.org +REF008 ref008.dstargateway.org +REF009 ref009.dstargateway.org +REF010 ref010.dstargateway.org +REF011 ref011.dstargateway.org +REF012 ref012.dstargateway.org +REF013 ref013.dstargateway.org +REF014 ref014.dstargateway.org +REF015 ref015.dstargateway.org +REF016 ref016.dstargateway.org +REF017 ref017.dstargateway.org +REF018 ref018.dstargateway.org +REF019 ref019.dstargateway.org +REF020 ref020.dstargateway.org +REF021 ref021.dstargateway.org +REF022 ref022.dstargateway.org +REF023 ref023.dstargateway.org +REF024 ref024.dstargateway.org +REF025 ref025.dstargateway.org +REF026 ref026.dstargateway.org +REF027 ref027.dstargateway.org +REF028 ref028.dstargateway.org +REF029 ref029.dstargateway.org +REF030 ref030.dstargateway.org +REF031 ref031.dstargateway.org +REF032 ref032.dstargateway.org +REF033 ref033.dstargateway.org +REF034 ref034.dstargateway.org +REF035 ref035.dstargateway.org +REF036 ref036.dstargateway.org +REF037 ref037.dstargateway.org +REF038 ref038.dstargateway.org +REF039 ref039.dstargateway.org +REF040 ref040.dstargateway.org +REF041 ref041.dstargateway.org +REF042 ref042.dstargateway.org +REF043 ref043.dstargateway.org +REF044 ref044.dstargateway.org +REF045 ref045.dstargateway.org +REF046 ref046.dstargateway.org +REF047 ref047.dstargateway.org +REF048 ref048.dstargateway.org +REF049 ref049.dstargateway.org +REF050 ref050.dstargateway.org +REF051 ref051.dstargateway.org +REF052 ref052.dstargateway.org +REF053 ref053.dstargateway.org +REF054 ref054.dstargateway.org +REF055 ref055.dstargateway.org +REF056 ref056.dstargateway.org +REF057 ref057.dstargateway.org +REF058 ref058.dstargateway.org +REF059 ref059.dstargateway.org +REF060 ref060.dstargateway.org +REF061 ref061.dstargateway.org +REF062 ref062.dstargateway.org +REF063 ref063.dstargateway.org +REF064 ref064.dstargateway.org +REF065 ref065.dstargateway.org +REF066 ref066.dstargateway.org +REF067 ref067.dstargateway.org +REF068 ref068.dstargateway.org +REF069 ref069.dstargateway.org +REF070 ref070.dstargateway.org +REF071 ref071.dstargateway.org +REF072 ref072.dstargateway.org +#REF073 ref073.dstargateway.org +#REF074 ref074.dstargateway.org +REF075 ref075.dstargateway.org +REF076 ref076.dstargateway.org +REF077 ref077.dstargateway.org +REF078 ref078.dstargateway.org +#REF079 ref079.dstargateway.org +#REF080 ref080.dstargateway.org +#REF081 ref081.dstargateway.org +#REF082 ref082.dstargateway.org +#REF083 ref083.dstargateway.org +#REF084 ref084.dstargateway.org +#REF085 ref085.dstargateway.org +#REF086 ref086.dstargateway.org +#REF087 ref087.dstargateway.org +#REF088 ref088.dstargateway.org +#REF089 ref089.dstargateway.org +#REF090 ref090.dstargateway.org +#REF091 ref091.dstargateway.org +#REF092 ref092.dstargateway.org +#REF093 ref093.dstargateway.org +#REF094 ref094.dstargateway.org +#REF095 ref095.dstargateway.org +#REF096 ref096.dstargateway.org +#REF097 ref097.dstargateway.org +#REF098 ref098.dstargateway.org +#REF099 ref099.dstargateway.org +REF117 ref001.dstargateway.org +REF212 xlx212.dstar.club +REF308 xlx308.w6kd.com +REF313 xlx313.xrefl.net +REF357 xlx357.w6kd.com +REF404 xlx.bendiksverden.net +REF850 xrf850.xrfmaster.net diff --git a/Data/TIME_de_DE.ambe b/Data/TIME_de_DE.ambe new file mode 100644 index 0000000..132926a Binary files /dev/null and b/Data/TIME_de_DE.ambe differ diff --git a/Data/TIME_de_DE.indx b/Data/TIME_de_DE.indx new file mode 100644 index 0000000..99fa58e --- /dev/null +++ b/Data/TIME_de_DE.indx @@ -0,0 +1,31 @@ +Es_ist 44 43 +null 91 41 +ein 136 24 +zwei 210 41 +drei 290 39 +vier 332 35 +fuenf 370 46 +sechs 421 50 +sieben 473 41 +acht 520 41 +neun 566 37 +zehn 607 38 +elf 651 46 +zwoelf 695 46 +dreizehn 749 49 +vierzehn 801 49 +fuenfzehn 854 54 +sechzehn 910 54 +siebzehn 968 51 +achtzehn 1025 49 +neunzehn 1077 56 +zwanzig 1138 51 +einundzwanzig 1186 63 +zweiundzwanzig 1254 71 +dreiundzwanzig 1333 68 +dreissig 1477 49 +fuenfundvierzig 1531 62 +Uhr 1594 34 +viertel_nach 1631 43 +halb 1678 32 +viertel_vor 1714 55 diff --git a/Data/TIME_en_GB.ambe b/Data/TIME_en_GB.ambe new file mode 100644 index 0000000..a8ae306 Binary files /dev/null and b/Data/TIME_en_GB.ambe differ diff --git a/Data/TIME_en_GB.indx b/Data/TIME_en_GB.indx new file mode 100644 index 0000000..19c5cea --- /dev/null +++ b/Data/TIME_en_GB.indx @@ -0,0 +1,26 @@ +It_is 41 37 +zero 81 49 +one 134 38 +two 175 37 +three 215 42 +four 260 40 +five 301 48 +six 353 40 +seven 395 47 +eight 445 35 +nine 482 46 +ten 531 42 +eleven 577 46 +twelve 627 52 +fifteen 795 54 +thirty 1355 44 +forty-five 1402 63 +AM 1466 42 +PM 1512 40 +O_Clock 1581 40 +a_quarter_past 1620 68 +half_past 1691 55 +a_quarter_to 1750 57 +midnight 1810 47 +midday 1860 44 +noon 1907 38 diff --git a/Data/TIME_en_US.ambe b/Data/TIME_en_US.ambe new file mode 100644 index 0000000..cd4856c Binary files /dev/null and b/Data/TIME_en_US.ambe differ diff --git a/Data/TIME_en_US.indx b/Data/TIME_en_US.indx new file mode 100644 index 0000000..8546649 --- /dev/null +++ b/Data/TIME_en_US.indx @@ -0,0 +1,26 @@ +It_is 44 31 +zero 79 36 +one 120 35 +two 162 31 +three 200 30 +four 234 35 +five 275 35 +six 315 37 +seven 357 37 +eight 398 31 +nine 433 35 +ten 475 31 +eleven 510 38 +twelve 554 37 +fifteen 696 43 +thirty 1198 30 +forty-five 1231 53 +AM 1287 39 +PM 1333 37 +O_Clock 1401 39 +a_quarter_past 1448 68 +half_past 1516 52 +a_quarter_to 1573 59 +midnight 1635 44 +midday 1683 36 +noon 1723 30 diff --git a/Data/TIME_fr_FR.ambe b/Data/TIME_fr_FR.ambe new file mode 100644 index 0000000..9cda77e Binary files /dev/null and b/Data/TIME_fr_FR.ambe differ diff --git a/Data/TIME_fr_FR.indx b/Data/TIME_fr_FR.indx new file mode 100644 index 0000000..085f7c8 --- /dev/null +++ b/Data/TIME_fr_FR.indx @@ -0,0 +1,20 @@ +bonjour 0 79 +cinq 80 48 +deux 129 42 +dix 172 55 +et_demie 228 69 +et_quart 298 71 +heure 370 64 +heures 435 64 +huit 500 47 +il_est 548 58 +midi 607 73 +minuit 681 68 +moins_le_quart 750 89 +neuf 840 46 +onze 887 65 +quatre 953 45 +sept 999 49 +six 1049 53 +trois 1103 43 +une 1147 72 diff --git a/Data/TIME_se_SE.ambe b/Data/TIME_se_SE.ambe new file mode 100644 index 0000000..d9969bf Binary files /dev/null and b/Data/TIME_se_SE.ambe differ diff --git a/Data/TIME_se_SE.indx b/Data/TIME_se_SE.indx new file mode 100644 index 0000000..eaa58da --- /dev/null +++ b/Data/TIME_se_SE.indx @@ -0,0 +1,17 @@ +Klockan_ar 66 52 +noll 121 33 +ett 159 32 +tva 197 35 +tre 238 31 +fyra 272 39 +fem 316 43 +sex 362 42 +sju 407 37 +atta 448 36 +nio 487 38 +tio 532 40 +elva 576 36 +tolv 620 36 +kvart_over 1407 57 +halv 1468 37 +kvart_i 1512 39 diff --git a/Data/de_DE.ambe b/Data/de_DE.ambe new file mode 100644 index 0000000..3189f05 Binary files /dev/null and b/Data/de_DE.ambe differ diff --git a/Data/de_DE.indx b/Data/de_DE.indx new file mode 100644 index 0000000..0f9fcdd --- /dev/null +++ b/Data/de_DE.indx @@ -0,0 +1,44 @@ +0 78 24 +1 121 24 +2 163 25 +3 202 28 +4 248 30 +5 295 27 +6 340 32 +7 391 32 +8 440 25 +9 484 32 +alpha 533 25 +bravo 576 31 +charlie 629 26 +delta 676 30 +A 725 19 +B 769 21 +C 818 27 +D 870 23 +E 917 23 +F 965 23 +G 1014 22 +H 1060 24 +I 1109 18 +J 1151 26 +K 1207 26 +L 1258 23 +M 1305 21 +N 1351 25 +O 1401 19 +P 1446 19 +Q 1493 24 +R 1543 23 +S 1591 21 +T 1644 23 +U 1693 22 +V 1740 19 +W 1784 22 +X 1831 24 +Y 1883 34 +Z 1943 25 +linkedto 1995 40 +notlinked 2088 50 +linkingto 2158 44 +isbusy 2268 40 diff --git a/Data/dk_DK.ambe b/Data/dk_DK.ambe new file mode 100644 index 0000000..d9cc78a Binary files /dev/null and b/Data/dk_DK.ambe differ diff --git a/Data/dk_DK.indx b/Data/dk_DK.indx new file mode 100644 index 0000000..ba64aa4 --- /dev/null +++ b/Data/dk_DK.indx @@ -0,0 +1,44 @@ +0 82 21 +1 120 15 +2 160 19 +3 198 22 +4 236 35 +5 288 24 +6 329 31 +7 378 27 +8 422 27 +9 466 24 +alpha 506 32 +bravo 558 27 +charlie 604 38 +delta 663 27 +A 710 18 +B 754 16 +C 796 20 +D 843 16 +E 885 14 +F 923 18 +G 967 13 +H 1005 19 +I 1049 13 +J 1087 23 +K 1137 20 +L 1180 20 +M 1224 19 +N 1268 17 +O 1310 16 +P 1352 15 +Q 1395 17 +R 1437 18 +S 1480 19 +T 1525 19 +U 1569 18 +V 1611 17 +W 1655 34 +X 1714 20 +Y 1759 19 +Z 1802 23 +linkedto 1852 37 +notlinked 1928 50 +linkingto 1998 34 +isbusy 2071 40 diff --git a/Data/en_GB.ambe b/Data/en_GB.ambe new file mode 100644 index 0000000..4a7c83c Binary files /dev/null and b/Data/en_GB.ambe differ diff --git a/Data/en_GB.indx b/Data/en_GB.indx new file mode 100644 index 0000000..ea3889d --- /dev/null +++ b/Data/en_GB.indx @@ -0,0 +1,44 @@ +0 85 41 +1 144 24 +2 186 25 +3 229 30 +4 278 35 +5 331 35 +6 384 39 +7 441 34 +8 494 29 +9 541 35 +alpha 595 31 +bravo 646 33 +charlie 700 31 +delta 753 30 +A 804 24 +B 850 33 +C 898 23 +D 933 33 +E 990 34 +F 1041 34 +G 1093 34 +H 1145 40 +I 1204 30 +J 1253 35 +K 1307 33 +L 1358 30 +M 1406 28 +N 1452 30 +O 1500 23 +P 1541 32 +Q 1592 39 +R 1648 23 +S 1689 33 +T 1742 32 +U 1791 35 +V 1845 33 +W 1896 38 +X 1953 35 +Y 2007 28 +Z 2060 37 +linked 2124 19 +notlinked 2194 44 +linking 2258 31 +isbusy 2350 33 diff --git a/Data/en_US.ambe b/Data/en_US.ambe new file mode 100644 index 0000000..6b91c91 Binary files /dev/null and b/Data/en_US.ambe differ diff --git a/Data/en_US.indx b/Data/en_US.indx new file mode 100644 index 0000000..040e476 --- /dev/null +++ b/Data/en_US.indx @@ -0,0 +1,44 @@ +0 89 39 +1 146 34 +2 202 22 +3 246 31 +4 294 34 +5 345 46 +6 409 39 +7 466 37 +8 521 29 +9 568 35 +alpha 621 26 +bravo 669 34 +charlie 726 34 +delta 781 31 +A 833 19 +B 870 24 +C 938 27 +D 1009 24 +E 1076 28 +F 1148 29 +G 1221 24 +H 1290 31 +I 1363 29 +J 1432 33 +K 1510 25 +L 1578 22 +M 1644 28 +N 1715 28 +O 1785 27 +P 1858 24 +Q 1927 25 +R 1993 26 +S 2063 29 +T 2139 25 +U 2208 25 +V 2273 27 +W 2344 33 +X 2421 24 +Y 2489 26 +Z 2561 32 +linked 2637 20 +notlinked 2710 49 +linking 2779 25 +isbusy 2872 34 diff --git a/Data/es_ES.ambe b/Data/es_ES.ambe new file mode 100644 index 0000000..f416848 Binary files /dev/null and b/Data/es_ES.ambe differ diff --git a/Data/es_ES.indx b/Data/es_ES.indx new file mode 100644 index 0000000..e8d62c8 --- /dev/null +++ b/Data/es_ES.indx @@ -0,0 +1,44 @@ +0 83 31 +1 128 32 +2 174 33 +3 226 30 +4 273 36 +5 323 42 +6 379 37 +7 430 37 +8 480 35 +9 529 34 +alpha 578 34 +bravo 628 36 +charlie 682 43 +delta 742 38 +A 798 26 +B 836 22 +C 881 22 +D 923 24 +E 967 17 +F 1004 31 +G 1053 26 +H 1097 35 +I 1150 20 +J 1189 34 +K 1246 22 +L 1287 30 +M 1337 30 +N 1388 33 +O 1439 22 +P 1480 21 +Q 1524 26 +R 1571 32 +S 1622 31 +T 1675 22 +U 1718 23 +V 1756 28 +W 1804 52 +X 1876 28 +Y 1925 17 +Z 1961 35 +linkedto 2017 64 +notlinked 2133 68 +linkingto 2217 66 +isbusy 2364 58 diff --git a/Data/fr_FR.ambe b/Data/fr_FR.ambe new file mode 100644 index 0000000..c81d063 Binary files /dev/null and b/Data/fr_FR.ambe differ diff --git a/Data/fr_FR.indx b/Data/fr_FR.indx new file mode 100644 index 0000000..f67b54a --- /dev/null +++ b/Data/fr_FR.indx @@ -0,0 +1,44 @@ +0 94 29 +1 140 16 +2 173 20 +3 215 19 +4 255 24 +5 298 29 +6 344 34 +7 398 25 +8 440 24 +9 481 23 +alpha 521 29 +bravo 568 27 +charlie 615 30 +delta 666 30 +A 714 21 +B 753 27 +C 796 34 +D 848 30 +E 895 23 +F 936 27 +G 982 27 +H 1026 30 +I 1075 20 +J 1113 29 +K 1162 22 +L 1201 28 +M 1248 28 +N 1295 28 +O 1341 23 +P 1386 21 +Q 1426 23 +R 1466 28 +S 1511 31 +T 1567 21 +U 1606 22 +V 1646 30 +W 1693 46 +X 1756 31 +Y 1806 21 +Z 1844 14 +linkedto 1858 35 +notlinked 1941 46 +linkingto 2008 38 +isbusy 2091 47 diff --git a/Data/it_IT.ambe b/Data/it_IT.ambe new file mode 100644 index 0000000..b76a97a Binary files /dev/null and b/Data/it_IT.ambe differ diff --git a/Data/it_IT.indx b/Data/it_IT.indx new file mode 100644 index 0000000..a94e2ea --- /dev/null +++ b/Data/it_IT.indx @@ -0,0 +1,44 @@ +0 86 33 +1 136 27 +2 180 30 +3 231 17 +4 270 38 +5 328 38 +6 383 31 +7 431 36 +8 485 33 +9 535 39 +alpha 591 34 +bravo 644 35 +charlie 701 35 +delta 757 34 +A 810 12 +B 840 19 +C 883 17 +D 923 17 +E 965 14 +F 1001 34 +G 1058 20 +H 1100 32 +I 1155 14 +J 1192 43 +K 1263 30 +L 1316 34 +M 1373 30 +N 1426 29 +O 1477 13 +P 1519 15 +Q 1559 16 +R 1598 28 +S 1649 30 +T 1699 20 +U 1741 12 +V 1775 21 +W 1819 47 +X 1888 25 +Y 1936 43 +Z 2002 35 +linkedto 2064 48 +notlinked 2154 65 +linkingto 2239 41 +isbusy 2321 51 diff --git a/Data/no_NO.ambe b/Data/no_NO.ambe new file mode 100644 index 0000000..bff2bd6 Binary files /dev/null and b/Data/no_NO.ambe differ diff --git a/Data/no_NO.indx b/Data/no_NO.indx new file mode 100644 index 0000000..a3548c0 --- /dev/null +++ b/Data/no_NO.indx @@ -0,0 +1,44 @@ +0 67 28 +1 102 29 +2 137 27 +3 170 25 +4 199 36 +5 238 30 +6 272 38 +7 314 31 +8 349 34 +9 386 28 +alpha 418 36 +bravo 472 30 +charlie 519 34 +delta 569 34 +A 622 23 +B 665 24 +C 710 24 +D 758 21 +E 803 28 +F 856 24 +G 903 32 +H 955 31 +I 1007 18 +J 1045 30 +K 1100 28 +L 1152 19 +M 1196 20 +N 1241 17 +O 1282 27 +P 1332 24 +Q 1378 24 +R 1426 19 +S 1470 31 +T 1524 24 +U 1572 23 +V 1616 20 +W 1658 40 +X 1722 32 +Y 1779 24 +Z 1823 29 +linkedto 1882 40 +notlinked 1966 49 +linkingto 2034 40 +isbusy 2148 38 diff --git a/Data/pl_PL.ambe b/Data/pl_PL.ambe new file mode 100644 index 0000000..565d99f Binary files /dev/null and b/Data/pl_PL.ambe differ diff --git a/Data/pl_PL.indx b/Data/pl_PL.indx new file mode 100644 index 0000000..9f41cf0 --- /dev/null +++ b/Data/pl_PL.indx @@ -0,0 +1,44 @@ +0 99 36 +1 163 38 +2 229 29 +3 290 31 +4 351 37 +5 420 42 +6 490 41 +7 559 43 +8 630 34 +9 692 50 +alpha 771 30 +bravo 820 32 +charlie 873 35 +delta 931 34 +A 987 17 +B 1012 30 +C 1070 25 +D 1118 27 +E 1169 29 +F 1221 36 +G 1281 30 +H 1333 26 +I 1383 18 +J 1425 32 +K 1485 23 +L 1532 26 +M 1581 26 +N 1629 24 +O 1676 18 +P 1724 23 +Q 1773 20 +R 1817 23 +S 1863 35 +T 1926 25 +U 1975 22 +V 2021 28 +W 2070 15 +X 2107 31 +Y 2161 39 +Z 2226 12 +linkedto 2263 45 +notlinked 2360 51 +linkingto 2433 45 +isbusy 2559 59 diff --git a/Data/se_SE.ambe b/Data/se_SE.ambe new file mode 100644 index 0000000..7e5567c Binary files /dev/null and b/Data/se_SE.ambe differ diff --git a/Data/se_SE.indx b/Data/se_SE.indx new file mode 100644 index 0000000..1f78bef --- /dev/null +++ b/Data/se_SE.indx @@ -0,0 +1,44 @@ +0 83 35 +1 138 33 +2 188 32 +3 240 28 +4 286 41 +5 345 30 +6 393 43 +7 451 34 +8 505 35 +9 555 28 +alpha 603 35 +bravo 660 35 +charlie 716 32 +delta 768 48 +A 836 30 +B 894 28 +C 946 33 +D 1005 22 +E 1053 34 +F 1115 20 +G 1160 36 +H 1223 30 +I 1280 27 +J 1333 35 +K 1393 29 +L 1453 25 +M 1507 26 +N 1560 20 +O 1607 26 +P 1657 28 +Q 1714 34 +R 1781 23 +S 1833 30 +T 1890 25 +U 1943 23 +V 1989 35 +W 2050 47 +X 2126 27 +Y 2178 19 +Z 2223 45 +linkedto 2298 39 +notlinked 2390 51 +linkingto 2461 36 +isbusy 2577 54 diff --git a/GUICommon/AddressTextCtrl.cpp b/GUICommon/AddressTextCtrl.cpp new file mode 100644 index 0000000..c40cfce --- /dev/null +++ b/GUICommon/AddressTextCtrl.cpp @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2002,2003,2009 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "AddressTextCtrl.h" + +CAddressTextCtrl::CAddressTextCtrl(wxWindow* parent, int id, const wxString& value, const wxPoint& pos, const wxSize& size, long style) : +CRestrictedTextCtrl(parent, id, value, pos, size, style, ADDRESS_CHARS) +{ +} + +CAddressTextCtrl::~CAddressTextCtrl() +{ +} + diff --git a/GUICommon/AddressTextCtrl.h b/GUICommon/AddressTextCtrl.h new file mode 100644 index 0000000..a0c99c5 --- /dev/null +++ b/GUICommon/AddressTextCtrl.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2002,2003,2009 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef AddressTextCtrl_H +#define AddressTextCtrl_H + +#include + +#include "RestrictedTextCtrl.h" + +const wxString ADDRESS_CHARS = wxT("0123456789."); + +class CAddressTextCtrl : public CRestrictedTextCtrl { + +public: + CAddressTextCtrl(wxWindow* parent, int id, const wxString& value, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = 0L); + virtual ~CAddressTextCtrl(); + + private: +}; + +#endif diff --git a/GUICommon/CallsignTextCtrl.cpp b/GUICommon/CallsignTextCtrl.cpp new file mode 100644 index 0000000..f37b11a --- /dev/null +++ b/GUICommon/CallsignTextCtrl.cpp @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2002,2003 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "CallsignTextCtrl.h" + +CCallsignTextCtrl::CCallsignTextCtrl(wxWindow* parent, int id, const wxString& value, const wxPoint& pos, const wxSize& size, long style) : +CRestrictedTextCtrl(parent, id, value, pos, size, style, CALLSIGN_CHARS) +{ +} + +CCallsignTextCtrl::~CCallsignTextCtrl() +{ +} + diff --git a/GUICommon/CallsignTextCtrl.h b/GUICommon/CallsignTextCtrl.h new file mode 100644 index 0000000..70a422e --- /dev/null +++ b/GUICommon/CallsignTextCtrl.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2002,2003 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef CallsignTextCtrl_H +#define CallsignTextCtrl_H + +#include + +#include "RestrictedTextCtrl.h" + +const wxString CALLSIGN_CHARS = wxT("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789/ "); + +class CCallsignTextCtrl : public CRestrictedTextCtrl { + +public: + CCallsignTextCtrl(wxWindow* parent, int id, const wxString& value, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = 0L); + virtual ~CCallsignTextCtrl(); + + private: +}; + +#endif diff --git a/GUICommon/DCSSet.cpp b/GUICommon/DCSSet.cpp new file mode 100644 index 0000000..6339de8 --- /dev/null +++ b/GUICommon/DCSSet.cpp @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2012,2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "HostFile.h" +#include "DCSSet.h" +#include "Defs.h" + +#include + +const unsigned int CONTROL_WIDTH = 130U; + +const unsigned int BORDER_SIZE = 5U; + +const int CHOICE_ENABLED = 8787; + +BEGIN_EVENT_TABLE(CDCSSet, wxPanel) + EVT_CHOICE(CHOICE_ENABLED, CDCSSet::onEnabled) +END_EVENT_TABLE() + + +CDCSSet::CDCSSet(wxWindow* parent, int id, const wxString& title, bool dcsEnabled, bool ccsEnabled, const wxString& ccsHost) : +wxPanel(parent, id), +m_title(title), +m_dcsEnabled(NULL), +m_ccsEnabled(NULL), +m_ccsHosts(NULL) +{ + wxFlexGridSizer* sizer = new wxFlexGridSizer(2); + + wxStaticText* dcsEnabledLabel = new wxStaticText(this, -1, wxT("DCS")); + sizer->Add(dcsEnabledLabel, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + m_dcsEnabled = new wxChoice(this, -1, wxDefaultPosition, wxSize(CONTROL_WIDTH, -1)); + m_dcsEnabled->Append(_("Disabled")); + m_dcsEnabled->Append(_("Enabled")); + sizer->Add(m_dcsEnabled, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + m_dcsEnabled->SetSelection(dcsEnabled ? 1 : 0); + + wxStaticText* ccsEnabledLabel = new wxStaticText(this, -1, wxT("CCS")); + sizer->Add(ccsEnabledLabel, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + m_ccsEnabled = new wxChoice(this, CHOICE_ENABLED, wxDefaultPosition, wxSize(CONTROL_WIDTH, -1)); + m_ccsEnabled->Append(_("Disabled")); + m_ccsEnabled->Append(_("Enabled")); + sizer->Add(m_ccsEnabled, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + m_ccsEnabled->SetSelection(ccsEnabled ? 1 : 0); + + wxStaticText* ccsHostsLabel = new wxStaticText(this, -1, _("Server")); + sizer->Add(ccsHostsLabel, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + m_ccsHosts = new wxChoice(this, -1, wxDefaultPosition, wxSize(CONTROL_WIDTH, -1)); + sizer->Add(m_ccsHosts, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + + wxFileName fileName(wxFileName::GetHomeDir(), CCS_HOSTS_FILE_NAME); + if (!fileName.IsFileReadable()) { +#if defined(__WINDOWS__) + fileName.Assign(::wxGetCwd(), CCS_HOSTS_FILE_NAME); +#else + fileName.Assign(wxT(DATA_DIR), CCS_HOSTS_FILE_NAME); +#endif + } + + CHostFile file(fileName.GetFullPath(), false); + + for (unsigned int i = 0U; i < file.getCount(); i++) + m_ccsHosts->Append(file.getName(i)); + + if (ccsHost.IsEmpty()) { + m_ccsHosts->SetSelection(0); + } else { + bool res = m_ccsHosts->SetStringSelection(ccsHost); + if (!res) + m_ccsHosts->SetSelection(0); + } + + if (ccsEnabled) + m_ccsHosts->Enable(); + else + m_ccsHosts->Disable(); + + SetAutoLayout(true); + + SetSizer(sizer); +} + + +CDCSSet::~CDCSSet() +{ +} + +bool CDCSSet::Validate() +{ + int n = m_dcsEnabled->GetCurrentSelection(); + if (n == wxNOT_FOUND) + return false; + + n = m_ccsEnabled->GetCurrentSelection(); + if (n == wxNOT_FOUND) + return false; + + if (m_ccsHosts->GetCurrentSelection() == wxNOT_FOUND) + return false; + + return true; +} + +bool CDCSSet::getDCSEnabled() const +{ + int c = m_dcsEnabled->GetCurrentSelection(); + if (c == wxNOT_FOUND) + return false; + + return c == 1; +} + +bool CDCSSet::getCCSEnabled() const +{ + int c = m_ccsEnabled->GetCurrentSelection(); + if (c == wxNOT_FOUND) + return false; + + return c == 1; +} + +wxString CDCSSet::getCCSHost() const +{ + int n = m_ccsHosts->GetSelection(); + if (n == wxNOT_FOUND) + return wxEmptyString; + + return m_ccsHosts->GetStringSelection(); +} + +void CDCSSet::onEnabled(wxCommandEvent &event) +{ + int n = m_ccsEnabled->GetCurrentSelection(); + if (n != 1) + m_ccsHosts->Disable(); + else + m_ccsHosts->Enable(); +} diff --git a/GUICommon/DCSSet.h b/GUICommon/DCSSet.h new file mode 100644 index 0000000..1771636 --- /dev/null +++ b/GUICommon/DCSSet.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2012,2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef DCSSet_H +#define DCSSet_H + +#include + +class CDCSSet : public wxPanel { +public: + CDCSSet(wxWindow* parent, int id, const wxString& title, bool dcsEnabled, bool ccsEnabled, const wxString& ccsHost); + virtual ~CDCSSet(); + + virtual bool Validate(); + + virtual bool getDCSEnabled() const; + virtual bool getCCSEnabled() const; + virtual wxString getCCSHost() const; + + virtual void onEnabled(wxCommandEvent& event); + +private: + wxString m_title; + wxChoice* m_dcsEnabled; + wxChoice* m_ccsEnabled; + wxChoice* m_ccsHosts; + + DECLARE_EVENT_TABLE() +}; + +#endif diff --git a/GUICommon/DExtraSet.cpp b/GUICommon/DExtraSet.cpp new file mode 100644 index 0000000..f96f948 --- /dev/null +++ b/GUICommon/DExtraSet.cpp @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2011,2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "DExtraSet.h" + +const unsigned int CONTROL_WIDTH = 130U; + +const unsigned int BORDER_SIZE = 5U; + +CDExtraSet::CDExtraSet(wxWindow* parent, int id, const wxString& title, bool enabled, unsigned int maxDongles, unsigned int maxLinks) : +wxPanel(parent, id), +m_title(title), +m_enabled(NULL), +m_maxDongles(NULL) +{ + wxFlexGridSizer* sizer = new wxFlexGridSizer(2); + + wxStaticText* enabledLabel = new wxStaticText(this, -1, _("DExtra")); + sizer->Add(enabledLabel, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + m_enabled = new wxChoice(this, -1, wxDefaultPosition, wxSize(CONTROL_WIDTH, -1)); + m_enabled->Append(_("Disabled")); + m_enabled->Append(_("Enabled")); + sizer->Add(m_enabled, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + m_enabled->SetSelection(enabled ? 1 : 0); + + wxStaticText* maxDonglesLabel = new wxStaticText(this, -1, _("Max. Dongles")); + sizer->Add(maxDonglesLabel, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + m_maxDongles = new wxChoice(this, -1, wxDefaultPosition, wxSize(CONTROL_WIDTH, -1)); + for (unsigned int i = 0U; i <= maxLinks; i++) { + wxString text; + text.Printf(wxT("%u"), i); + m_maxDongles->Append(text); + } + sizer->Add(m_maxDongles, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + m_maxDongles->SetSelection(maxDongles); + + SetAutoLayout(true); + + SetSizer(sizer); +} + + +CDExtraSet::~CDExtraSet() +{ +} + +bool CDExtraSet::Validate() +{ + int n = m_enabled->GetCurrentSelection(); + if (n == wxNOT_FOUND) + return false; + + n = m_maxDongles->GetCurrentSelection(); + if (n == wxNOT_FOUND) + return false; + + return true; +} + +bool CDExtraSet::getEnabled() const +{ + int c = m_enabled->GetCurrentSelection(); + if (c == wxNOT_FOUND) + return false; + + return c == 1; +} + +unsigned int CDExtraSet::getMaxDongles() const +{ + int c = m_maxDongles->GetCurrentSelection(); + if (c == wxNOT_FOUND) + return 0U; + + return (unsigned int)c; +} diff --git a/GUICommon/DExtraSet.h b/GUICommon/DExtraSet.h new file mode 100644 index 0000000..1e50733 --- /dev/null +++ b/GUICommon/DExtraSet.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2011,2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef DExtraSet_H +#define DExtraSet_H + +#include + +class CDExtraSet : public wxPanel { +public: + CDExtraSet(wxWindow* parent, int id, const wxString& title, bool enabled, unsigned int maxDongles, unsigned int maxLinks); + virtual ~CDExtraSet(); + + virtual bool Validate(); + + virtual bool getEnabled() const; + virtual unsigned int getMaxDongles() const; + +private: + wxString m_title; + wxChoice* m_enabled; + wxChoice* m_maxDongles; +}; + +#endif diff --git a/GUICommon/DPRSSet.cpp b/GUICommon/DPRSSet.cpp new file mode 100644 index 0000000..5a99dde --- /dev/null +++ b/GUICommon/DPRSSet.cpp @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2010 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "DPRSSet.h" + +const unsigned int BORDER_SIZE = 5U; +const unsigned int CONTROL_WIDTH1 = 200U; +const unsigned int CONTROL_WIDTH2 = 80U; + +const unsigned int PORT_LENGTH = 5U; +const unsigned int PASSWORD_LENGTH = 5U; + +CDPRSSet::CDPRSSet(wxWindow* parent, int id, const wxString& title, bool enabled, const wxString& hostname, unsigned int port) : +wxPanel(parent, id), +m_title(title), +m_enabled(NULL), +m_hostname(NULL), +m_port(NULL) +{ + wxFlexGridSizer* sizer = new wxFlexGridSizer(2); + + wxStaticText* enabledLabel = new wxStaticText(this, -1, _("D-PRS")); + sizer->Add(enabledLabel, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + m_enabled = new wxChoice(this, -1, wxDefaultPosition, wxSize(CONTROL_WIDTH1, -1)); + m_enabled->Append(_("Disabled")); + m_enabled->Append(_("Enabled")); + sizer->Add(m_enabled, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + m_enabled->SetSelection(enabled ? 1 : 0); + + wxStaticText* hostnameLabel = new wxStaticText(this, -1, _("Hostname")); + sizer->Add(hostnameLabel, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + + m_hostname = new wxTextCtrl(this, -1, hostname, wxDefaultPosition, wxSize(CONTROL_WIDTH1, -1)); + sizer->Add(m_hostname, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + + wxStaticText* portLabel = new wxStaticText(this, -1, _("Port")); + sizer->Add(portLabel, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + + wxString buffer; + buffer.Printf(wxT("%u"), port); + + m_port = new CPortTextCtrl(this, -1, buffer, wxDefaultPosition, wxSize(CONTROL_WIDTH2, -1)); + m_port->SetMaxLength(PORT_LENGTH); + sizer->Add(m_port, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + + SetAutoLayout(true); + + SetSizer(sizer); +} + + +CDPRSSet::~CDPRSSet() +{ +} + +bool CDPRSSet::Validate() +{ + int n = m_enabled->GetCurrentSelection(); + if (n == wxNOT_FOUND) + return false; + + wxString hostname = m_hostname->GetValue(); + if (hostname.IsEmpty()) + return true; + + unsigned int port = getPort(); + + if (port == 0U || port > 65535U) { + wxMessageDialog dialog(this, _("The Port is not valid"), m_title + _(" Error"), wxICON_ERROR); + dialog.ShowModal(); + return false; + } + + return true; +} + +bool CDPRSSet::getEnabled() const +{ + int c = m_enabled->GetCurrentSelection(); + if (c == wxNOT_FOUND) + return false; + + return c == 1; +} + +wxString CDPRSSet::getHostname() const +{ + return m_hostname->GetValue(); +} + +unsigned int CDPRSSet::getPort() const +{ + unsigned long n; + + m_port->GetValue().ToULong(&n); + + return n; +} diff --git a/GUICommon/DPRSSet.h b/GUICommon/DPRSSet.h new file mode 100644 index 0000000..2d18220 --- /dev/null +++ b/GUICommon/DPRSSet.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2010 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef DPRSSet_H +#define DPRSSet_H + +#include "PortTextCtrl.h" + +#include + +class CDPRSSet : public wxPanel { +public: + CDPRSSet(wxWindow* parent, int id, const wxString& title, bool enabled, const wxString& hostname, unsigned int port); + virtual ~CDPRSSet(); + + virtual bool Validate(); + + virtual bool getEnabled() const; + virtual wxString getHostname() const; + virtual unsigned int getPort() const; + +private: + wxString m_title; + wxChoice* m_enabled; + wxTextCtrl* m_hostname; + CPortTextCtrl* m_port; +}; + +#endif diff --git a/GUICommon/DPlusSet.cpp b/GUICommon/DPlusSet.cpp new file mode 100644 index 0000000..5c70b33 --- /dev/null +++ b/GUICommon/DPlusSet.cpp @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2010-2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "DStarDefines.h" +#include "DPlusSet.h" + +const unsigned int CONTROL_WIDTH = 130U; + +const unsigned int BORDER_SIZE = 5U; + +CDPlusSet::CDPlusSet(wxWindow* parent, int id, const wxString& title, bool enabled, unsigned int maxDongles, unsigned int maxLinks, const wxString& login) : +wxPanel(parent, id), +m_title(title), +m_enabled(NULL), +m_maxDongles(NULL), +m_login(NULL) +{ + wxFlexGridSizer* sizer = new wxFlexGridSizer(2); + + wxStaticText* enabledLabel = new wxStaticText(this, -1, _("D-Plus")); + sizer->Add(enabledLabel, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + m_enabled = new wxChoice(this, -1, wxDefaultPosition, wxSize(CONTROL_WIDTH, -1)); + m_enabled->Append(_("Disabled")); + m_enabled->Append(_("Enabled")); + sizer->Add(m_enabled, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + m_enabled->SetSelection(enabled ? 1 : 0); + + wxStaticText* maxDonglesLabel = new wxStaticText(this, -1, _("Max. Dongles")); + sizer->Add(maxDonglesLabel, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + m_maxDongles = new wxChoice(this, -1, wxDefaultPosition, wxSize(CONTROL_WIDTH, -1)); + for (unsigned int i = 0U; i <= maxLinks; i++) { + wxString text; + text.Printf(wxT("%u"), i); + m_maxDongles->Append(text); + } + sizer->Add(m_maxDongles, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + m_maxDongles->SetSelection(maxDongles); + + wxStaticText* loginLabel = new wxStaticText(this, -1, _("Login")); + sizer->Add(loginLabel, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + m_login = new CCallsignTextCtrl(this, -1, login, wxDefaultPosition, wxSize(CONTROL_WIDTH, -1)); + m_login->SetMaxLength(LONG_CALLSIGN_LENGTH); + sizer->Add(m_login, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + + SetAutoLayout(true); + + SetSizer(sizer); +} + + +CDPlusSet::~CDPlusSet() +{ +} + +bool CDPlusSet::Validate() +{ + int n = m_enabled->GetCurrentSelection(); + if (n == wxNOT_FOUND) + return false; + + if (n == 1) { + wxString login = m_login->GetValue(); + if (login.IsEmpty() || login.IsSameAs(wxT(" "))) { + wxMessageDialog dialog(this, _("The D-Plus Login is blank"), m_title + _(" Error"), wxICON_ERROR); + dialog.ShowModal(); + return false; + } + } + + n = m_maxDongles->GetCurrentSelection(); + if (n == wxNOT_FOUND) + return false; + + return true; +} + +bool CDPlusSet::getEnabled() const +{ + int c = m_enabled->GetCurrentSelection(); + if (c == wxNOT_FOUND) + return false; + + return c == 1; +} + +unsigned int CDPlusSet::getMaxDongles() const +{ + int c = m_maxDongles->GetCurrentSelection(); + if (c == wxNOT_FOUND) + return 0U; + + return (unsigned int)c; +} + +wxString CDPlusSet::getLogin() const +{ + wxString callsign = m_login->GetValue(); + + callsign.MakeUpper(); + callsign.Append(wxT(" ")); + callsign.Truncate(LONG_CALLSIGN_LENGTH); + + return callsign; +} diff --git a/GUICommon/DPlusSet.h b/GUICommon/DPlusSet.h new file mode 100644 index 0000000..2e9225b --- /dev/null +++ b/GUICommon/DPlusSet.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2010,2011,2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef DPlusSet_H +#define DPlusSet_H + +#include "CallsignTextCtrl.h" +#include "Defs.h" + +#include + +class CDPlusSet : public wxPanel { +public: + CDPlusSet(wxWindow* parent, int id, const wxString& title, bool enabled, unsigned int maxDongles, unsigned int maxLinks, const wxString& login); + virtual ~CDPlusSet(); + + virtual bool Validate(); + + virtual bool getEnabled() const; + virtual unsigned int getMaxDongles() const; + virtual wxString getLogin() const; + +private: + wxString m_title; + wxChoice* m_enabled; + wxChoice* m_maxDongles; + CCallsignTextCtrl* m_login; +}; + +#endif diff --git a/GUICommon/DescriptionTextCtrl.cpp b/GUICommon/DescriptionTextCtrl.cpp new file mode 100644 index 0000000..e69bba8 --- /dev/null +++ b/GUICommon/DescriptionTextCtrl.cpp @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2002,2003,2009,2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "DescriptionTextCtrl.h" + +CDescriptionTextCtrl::CDescriptionTextCtrl(wxWindow* parent, int id, const wxString& value, const wxPoint& pos, const wxSize& size, long style) : +CRestrictedTextCtrl(parent, id, value, pos, size, style, DESCRIPTION_CHARS) +{ +} + +CDescriptionTextCtrl::~CDescriptionTextCtrl() +{ +} + diff --git a/GUICommon/DescriptionTextCtrl.h b/GUICommon/DescriptionTextCtrl.h new file mode 100644 index 0000000..e0f626b --- /dev/null +++ b/GUICommon/DescriptionTextCtrl.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2002,2003,2009,2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef DescriptionTextCtrl_H +#define DescriptionTextCtrl_H + +#include + +#include "RestrictedTextCtrl.h" + +const wxString DESCRIPTION_CHARS = wxT("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 .,&*()-+=@/?:;"); + +class CDescriptionTextCtrl : public CRestrictedTextCtrl { + +public: + CDescriptionTextCtrl(wxWindow* parent, int id, const wxString& value, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = 0L); + virtual ~CDescriptionTextCtrl(); + + private: +}; + +#endif diff --git a/GUICommon/GUICommon.vcxproj b/GUICommon/GUICommon.vcxproj new file mode 100644 index 0000000..b04a02c --- /dev/null +++ b/GUICommon/GUICommon.vcxproj @@ -0,0 +1,169 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {02D03515-0BBE-4553-8C40-566A597478F8} + GUICommon + Win32Proj + 10.0.16299.0 + + + + StaticLibrary + v141 + Unicode + true + + + StaticLibrary + v141 + Unicode + true + + + StaticLibrary + v141 + Unicode + + + StaticLibrary + v141 + Unicode + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>14.0.24720.0 + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + $(WXWIN)\include;$(WXWIN)\lib\vc_dll\mswud;$(IncludePath) + + + $(WXWIN)\include;$(WXWIN)\lib\vc_dll\mswud;$(IncludePath) + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + + + + Disabled + $(WXWIN)\include\msvc;$(WXWIN)\include;../Common;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;WINVER=0x0400;__WXMSW__;WXUSINGDLL;wxUSE_GUI=1;__WXDEBUG__;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_LIB;DCS_LINK;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + Level3 + EditAndContinue + + + + + Disabled + $(WXWIN)\include\msvc;$(WXWIN)\include;../Common;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;WINVER=0x0400;__WXMSW__;WXUSINGDLL;wxUSE_GUI=1;__WXDEBUG__;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_LIB;DCS_LINK;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + + + Level3 + ProgramDatabase + + + + + MaxSpeed + true + $(WXWIN)\include\msvc;$(WXWIN)\include;../Common;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;WINVER=0x0400;__WXMSW__;WXUSINGDLL;wxUSE_GUI=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_LIB;%(PreprocessorDefinitions) + MultiThreadedDLL + true + + Level3 + ProgramDatabase + + + + + MaxSpeed + true + $(WXWIN)\include\msvc;$(WXWIN)\include;../Common;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;WINVER=0x0400;__WXMSW__;WXUSINGDLL;wxUSE_GUI=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_LIB;%(PreprocessorDefinitions) + MultiThreadedDLL + true + + + Level3 + ProgramDatabase + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/GUICommon/GUICommon.vcxproj.filters b/GUICommon/GUICommon.vcxproj.filters new file mode 100644 index 0000000..479d80d --- /dev/null +++ b/GUICommon/GUICommon.vcxproj.filters @@ -0,0 +1,101 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/GUICommon/PortTextCtrl.cpp b/GUICommon/PortTextCtrl.cpp new file mode 100644 index 0000000..51435d9 --- /dev/null +++ b/GUICommon/PortTextCtrl.cpp @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2002,2003,2009 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "PortTextCtrl.h" + +CPortTextCtrl::CPortTextCtrl(wxWindow* parent, int id, const wxString& value, const wxPoint& pos, const wxSize& size, long style) : +CRestrictedTextCtrl(parent, id, value, pos, size, style, PORT_CHARS) +{ +} + +CPortTextCtrl::~CPortTextCtrl() +{ +} + diff --git a/GUICommon/PortTextCtrl.h b/GUICommon/PortTextCtrl.h new file mode 100644 index 0000000..8d096c8 --- /dev/null +++ b/GUICommon/PortTextCtrl.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2002,2003,2009 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef PortTextCtrl_H +#define PortTextCtrl_H + +#include + +#include "RestrictedTextCtrl.h" + +const wxString PORT_CHARS = wxT("0123456789"); + +class CPortTextCtrl : public CRestrictedTextCtrl { + +public: + CPortTextCtrl(wxWindow* parent, int id, const wxString& value, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = 0L); + virtual ~CPortTextCtrl(); + + private: +}; + +#endif diff --git a/GUICommon/RemoteSet.cpp b/GUICommon/RemoteSet.cpp new file mode 100644 index 0000000..f37ff59 --- /dev/null +++ b/GUICommon/RemoteSet.cpp @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2011 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "DStarDefines.h" +#include "RemoteSet.h" + +const unsigned int PASSWORD_WIDTH = 120U; +const unsigned int PORT_WIDTH = 80U; + +const unsigned int PORT_LENGTH = 5U; + +const unsigned int BORDER_SIZE = 5U; + +CRemoteSet::CRemoteSet(wxWindow* parent, int id, const wxString& title, bool enabled, const wxString& password, unsigned int port) : +wxPanel(parent, id), +m_title(title), +m_enabled(NULL), +m_password(NULL), +m_port(NULL) +{ + wxFlexGridSizer* sizer = new wxFlexGridSizer(2); + + wxStaticText* enabledLabel = new wxStaticText(this, -1, _("Remote")); + sizer->Add(enabledLabel, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + m_enabled = new wxChoice(this, -1, wxDefaultPosition, wxSize(PASSWORD_WIDTH, -1)); + m_enabled->Append(_("Disabled")); + m_enabled->Append(_("Enabled")); + sizer->Add(m_enabled, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + m_enabled->SetSelection(enabled ? 1 : 0); + + wxStaticText* passwordLabel = new wxStaticText(this, -1, _("Password")); + sizer->Add(passwordLabel, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + m_password = new wxTextCtrl(this, -1, password, wxDefaultPosition, wxSize(PASSWORD_WIDTH, -1), wxTE_PASSWORD); + sizer->Add(m_password, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + + wxStaticText* repeaterPortLabel = new wxStaticText(this, -1, _("Port")); + sizer->Add(repeaterPortLabel, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + wxString buffer; + buffer.Printf(wxT("%u"), port); + + m_port = new CPortTextCtrl(this, -1, buffer, wxDefaultPosition, wxSize(PORT_WIDTH, -1)); + m_port->SetMaxLength(PORT_LENGTH); + sizer->Add(m_port, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + + SetAutoLayout(true); + + SetSizer(sizer); +} + + +CRemoteSet::~CRemoteSet() +{ +} + +bool CRemoteSet::Validate() +{ + int n = m_enabled->GetCurrentSelection(); + if (n == wxNOT_FOUND) { + wxMessageDialog dialog(this, _("Remote Enabled is not set"), m_title + _(" Error"), wxICON_ERROR); + dialog.ShowModal(); + return false; + } + + if (n == 0) + return true; + + wxString password = getPassword(); + if (password.IsEmpty()) { + wxMessageDialog dialog(this, _("The Remote Password is empty"), m_title + _(" Error"), wxICON_ERROR); + dialog.ShowModal(); + return false; + } + + unsigned int port = getPort(); + if (port == 0U || port > 65535U) { + wxMessageDialog dialog(this, _("The Remote Port is not valid"), m_title + _(" Error"), wxICON_ERROR); + dialog.ShowModal(); + return false; + } + + return true; +} + +bool CRemoteSet::getEnabled() const +{ + int n = m_enabled->GetCurrentSelection(); + + return n == 1; +} + +wxString CRemoteSet::getPassword() const +{ + return m_password->GetValue(); +} + +unsigned int CRemoteSet::getPort() const +{ + unsigned long n; + m_port->GetValue().ToULong(&n); + + return n; +} diff --git a/GUICommon/RemoteSet.h b/GUICommon/RemoteSet.h new file mode 100644 index 0000000..2f4a58a --- /dev/null +++ b/GUICommon/RemoteSet.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2011 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef RemoteSet_H +#define RemoteSet_H + +#include "PortTextCtrl.h" + +#include + +class CRemoteSet : public wxPanel { +public: + CRemoteSet(wxWindow* parent, int id, const wxString& title, bool enabled, const wxString& password, unsigned int port); + virtual ~CRemoteSet(); + + virtual bool Validate(); + + virtual bool getEnabled() const; + virtual wxString getPassword() const; + virtual unsigned int getPort() const; + +private: + wxString m_title; + wxChoice* m_enabled; + wxTextCtrl* m_password; + CPortTextCtrl* m_port; +}; + +#endif diff --git a/GUICommon/RepeaterDataSet.cpp b/GUICommon/RepeaterDataSet.cpp new file mode 100644 index 0000000..ce3fc01 --- /dev/null +++ b/GUICommon/RepeaterDataSet.cpp @@ -0,0 +1,554 @@ +/* + * Copyright (C) 2010-2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "RepeaterDataSet.h" +#include "DStarDefines.h" +#include "HostFile.h" + +#include + +const unsigned int CONTROL_WIDTH1 = 130U; +const unsigned int CONTROL_WIDTH2 = 80U; +const unsigned int CONTROL_WIDTH3 = 40U; + +const unsigned int ADDRESS_LENGTH = 15U; +const unsigned int PORT_LENGTH = 5U; + +const unsigned int BORDER_SIZE = 5U; + + +const int CHOICE_BAND = 8745; +const int CHOICE_TYPE = 8746; + +BEGIN_EVENT_TABLE(CRepeaterDataSet, wxPanel) + EVT_CHOICE(CHOICE_BAND, CRepeaterDataSet::onBand) + EVT_CHOICE(CHOICE_TYPE, CRepeaterDataSet::onType) +END_EVENT_TABLE() + + +CRepeaterDataSet::CRepeaterDataSet(wxWindow* parent, int id, const wxString& title, const wxString& band, HW_TYPE type, const wxString& address, unsigned int port, unsigned char band1, unsigned char band2, unsigned char band3, bool dplusEnabled, bool dExtraEnabled, bool dcsEnabled, const wxString& reflector, bool atStartup, RECONNECT reconnect) : +wxPanel(parent, id), +m_title(title), +m_band(NULL), +m_type(NULL), +m_address(NULL), +m_port(NULL), +m_band1(NULL), +m_band2(NULL), +m_band3(NULL), +m_reflector(NULL), +m_channel(NULL), +m_startup(NULL), +m_reconnect(NULL) +{ + wxFlexGridSizer* sizer = new wxFlexGridSizer(3); + + wxStaticText* bandLabel = new wxStaticText(this, -1, _("Band")); + sizer->Add(bandLabel, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + m_band = new wxChoice(this, CHOICE_BAND, wxDefaultPosition, wxSize(CONTROL_WIDTH2, -1)); + m_band->Append(_("None")); + m_band->Append(wxT("A")); + m_band->Append(wxT("B")); + m_band->Append(wxT("C")); + m_band->Append(wxT("D")); + m_band->Append(wxT("E")); + m_band->Append(wxT("AD")); + m_band->Append(wxT("BD")); + m_band->Append(wxT("CD")); + m_band->Append(wxT("DD")); + m_band->Append(wxT("ED")); + sizer->Add(m_band, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + bool res = m_band->SetStringSelection(band); + if (!res) + m_band->SetSelection(0); + + wxStaticText* dummy1Label = new wxStaticText(this, -1, wxEmptyString); + sizer->Add(dummy1Label, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + wxStaticText* hardwareTypeLabel = new wxStaticText(this, -1, _("Type")); + sizer->Add(hardwareTypeLabel, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + m_type = new wxChoice(this, CHOICE_TYPE, wxDefaultPosition, wxSize(CONTROL_WIDTH1, -1)); + m_type->Append(_("Homebrew")); + m_type->Append(wxT("Icom")); + m_type->Append(_("Dummy")); + sizer->Add(m_type, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + m_type->SetSelection(int(type)); + + wxStaticText* dummy2Label = new wxStaticText(this, -1, wxEmptyString); + sizer->Add(dummy2Label, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + wxStaticText* addressLabel = new wxStaticText(this, -1, _("Address")); + sizer->Add(addressLabel, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + m_address = new CAddressTextCtrl(this, -1, address, wxDefaultPosition, wxSize(CONTROL_WIDTH1, -1)); + m_address->SetMaxLength(ADDRESS_LENGTH); + sizer->Add(m_address, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + + wxStaticText* dummy3Label = new wxStaticText(this, -1, wxEmptyString); + sizer->Add(dummy3Label, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + wxStaticText* portLabel = new wxStaticText(this, -1, _("Port")); + sizer->Add(portLabel, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + wxString buffer; + buffer.Printf(wxT("%u"), port); + + m_port = new CPortTextCtrl(this, -1, buffer, wxDefaultPosition, wxSize(CONTROL_WIDTH2, -1)); + m_port->SetMaxLength(PORT_LENGTH); + sizer->Add(m_port, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + + wxStaticText* dummy4Label = new wxStaticText(this, -1, wxEmptyString); + sizer->Add(dummy4Label, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + wxStaticText* icomBandsLabel = new wxStaticText(this, -1, _("Bands")); + sizer->Add(icomBandsLabel, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + wxBoxSizer* bandSizer = new wxBoxSizer(wxHORIZONTAL); + + buffer.Printf(wxT("%u"), band1); + m_band1 = new CPortTextCtrl(this, -1, buffer, wxDefaultPosition, wxSize(CONTROL_WIDTH3, -1)); + m_band1->SetMaxLength(2U); + bandSizer->Add(m_band1, 0, wxALIGN_LEFT, BORDER_SIZE); + + buffer.Printf(wxT("%u"), band2); + m_band2 = new CPortTextCtrl(this, -1, buffer, wxDefaultPosition, wxSize(CONTROL_WIDTH3, -1)); + m_band2->SetMaxLength(2U); + bandSizer->Add(m_band2, 0, wxLEFT | wxALIGN_LEFT, BORDER_SIZE); + + buffer.Printf(wxT("%u"), band3); + m_band3 = new CPortTextCtrl(this, -1, buffer, wxDefaultPosition, wxSize(CONTROL_WIDTH3, -1)); + m_band3->SetMaxLength(2U); + bandSizer->Add(m_band3, 0, wxLEFT | wxALIGN_LEFT, BORDER_SIZE); + + sizer->Add(bandSizer, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + wxStaticText* dummy0Label = new wxStaticText(this, -1, wxEmptyString); + sizer->Add(dummy0Label, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + wxStaticText* reflectorLabel = new wxStaticText(this, -1, _("Reflector")); + sizer->Add(reflectorLabel, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + m_reflector = new wxChoice(this, -1, wxDefaultPosition, wxSize(CONTROL_WIDTH1, -1)); + m_reflector->Append(_("None")); + + if (dplusEnabled) { + wxFileName fileName1(wxFileName::GetHomeDir(), DPLUS_HOSTS_FILE_NAME); + if (fileName1.IsFileReadable()) { + CHostFile file(fileName1.GetFullPath(), false); + + for (unsigned int i = 0U; i < file.getCount(); i++) + m_reflector->Append(file.getName(i).Trim()); + } + +#if defined(__WINDOWS__) + wxFileName fileName4(::wxGetCwd(), DPLUS_HOSTS_FILE_NAME); +#else + wxFileName fileName4(wxT(DATA_DIR), DPLUS_HOSTS_FILE_NAME); +#endif + if (fileName4.IsFileReadable()) { + CHostFile file(fileName4.GetFullPath(), false); + + for (unsigned int i = 0U; i < file.getCount(); i++) { + wxString name = file.getName(i).Trim(); + if (m_reflector->FindString(name) == wxNOT_FOUND) + m_reflector->Append(name); + } + } + } + + if (dExtraEnabled) { + wxFileName fileName2(wxFileName::GetHomeDir(), DEXTRA_HOSTS_FILE_NAME); + if (fileName2.IsFileReadable()) { + CHostFile file(fileName2.GetFullPath(), false); + + for (unsigned int i = 0U; i < file.getCount(); i++) + m_reflector->Append(file.getName(i).Trim()); + } + +#if defined(__WINDOWS__) + wxFileName fileName5(::wxGetCwd(), DEXTRA_HOSTS_FILE_NAME); +#else + wxFileName fileName5(wxT(DATA_DIR), DEXTRA_HOSTS_FILE_NAME); +#endif + if (fileName5.IsFileReadable()) { + CHostFile file(fileName5.GetFullPath(), false); + + for (unsigned int i = 0U; i < file.getCount(); i++) { + wxString name = file.getName(i).Trim(); + if (m_reflector->FindString(name) == wxNOT_FOUND) + m_reflector->Append(name); + } + } + } + + if (dcsEnabled) { + wxFileName fileName3(wxFileName::GetHomeDir(), DCS_HOSTS_FILE_NAME); + if (fileName3.IsFileReadable()) { + CHostFile file(fileName3.GetFullPath(), false); + + for (unsigned int i = 0U; i < file.getCount(); i++) + m_reflector->Append(file.getName(i).Trim()); + } + +#if defined(__WINDOWS__) + wxFileName fileName6(::wxGetCwd(), DCS_HOSTS_FILE_NAME); +#else + wxFileName fileName6(wxT(DATA_DIR), DCS_HOSTS_FILE_NAME); +#endif + if (fileName6.IsFileReadable()) { + CHostFile file(fileName6.GetFullPath(), false); + + for (unsigned int i = 0U; i < file.getCount(); i++) { + wxString name = file.getName(i).Trim(); + if (m_reflector->FindString(name) == wxNOT_FOUND) + m_reflector->Append(name); + } + } + } + + sizer->Add(m_reflector, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + + if (reflector.IsEmpty()) { + m_reflector->SetSelection(0); + } else { + wxString name = reflector; + name.Truncate(7U); + name.Trim(); + bool res = m_reflector->SetStringSelection(name); + if (!res) + m_reflector->SetSelection(0); + } + + m_channel = new wxChoice(this, -1, wxDefaultPosition, wxSize(CONTROL_WIDTH2, -1)); + m_channel->Append(wxT("A")); + m_channel->Append(wxT("B")); + m_channel->Append(wxT("C")); + m_channel->Append(wxT("D")); + m_channel->Append(wxT("E")); + m_channel->Append(wxT("F")); + m_channel->Append(wxT("G")); + m_channel->Append(wxT("H")); + m_channel->Append(wxT("I")); + m_channel->Append(wxT("J")); + m_channel->Append(wxT("K")); + m_channel->Append(wxT("L")); + m_channel->Append(wxT("M")); + m_channel->Append(wxT("N")); + m_channel->Append(wxT("O")); + m_channel->Append(wxT("P")); + m_channel->Append(wxT("Q")); + m_channel->Append(wxT("R")); + m_channel->Append(wxT("S")); + m_channel->Append(wxT("T")); + m_channel->Append(wxT("U")); + m_channel->Append(wxT("V")); + m_channel->Append(wxT("W")); + m_channel->Append(wxT("X")); + m_channel->Append(wxT("Y")); + m_channel->Append(wxT("Z")); + sizer->Add(m_channel, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + res = m_channel->SetStringSelection(reflector.Right(1U)); + if (!res) + m_channel->SetSelection(0); + + wxStaticText* startupLabel = new wxStaticText(this, -1, _("Startup")); + sizer->Add(startupLabel, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + m_startup = new wxChoice(this, -1, wxDefaultPosition, wxSize(CONTROL_WIDTH1, -1)); + m_startup->Append(_("No")); + m_startup->Append(_("Yes")); + sizer->Add(m_startup, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + m_startup->SetSelection(atStartup ? 1 : 0); + + wxStaticText* dummy5Label = new wxStaticText(this, -1, wxEmptyString); + sizer->Add(dummy5Label, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + wxStaticText* reconnectLabel = new wxStaticText(this, -1, _("Reconnect")); + sizer->Add(reconnectLabel, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + m_reconnect = new wxChoice(this, -1, wxDefaultPosition, wxSize(CONTROL_WIDTH1, -1)); + m_reconnect->Append(_("Never")); + m_reconnect->Append(_("Fixed")); + m_reconnect->Append(_("5 minutes")); + m_reconnect->Append(_("10 minutes")); + m_reconnect->Append(_("15 minutes")); + m_reconnect->Append(_("20 minutes")); + m_reconnect->Append(_("25 minutes")); + m_reconnect->Append(_("30 minutes")); + m_reconnect->Append(_("60 minutes")); + m_reconnect->Append(_("90 minutes")); + m_reconnect->Append(_("120 minutes")); + m_reconnect->Append(_("180 minutes")); + sizer->Add(m_reconnect, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + m_reconnect->SetSelection(int(reconnect)); + + if (isDDMode()) { + m_type->SetSelection(1); + m_reflector->SetSelection(0); + m_channel->SetSelection(0); + m_startup->SetSelection(0); + m_reconnect->SetSelection(0); + + m_type->Disable(); + m_reflector->Disable(); + m_channel->Disable(); + m_startup->Disable(); + m_reconnect->Disable(); + } else { + m_type->Enable(); + m_reflector->Enable(); + m_channel->Enable(); + m_startup->Enable(); + m_reconnect->Enable(); + } + + if (type == HW_ICOM) { + m_band1->Enable(); + m_band2->Enable(); + m_band3->Enable(); + } else { + m_band1->Disable(); + m_band2->Disable(); + m_band3->Disable(); + } + + SetAutoLayout(true); + + SetSizer(sizer); +} + + +CRepeaterDataSet::~CRepeaterDataSet() +{ +} + +bool CRepeaterDataSet::Validate() +{ + int band = m_band->GetCurrentSelection(); + if (band == wxNOT_FOUND) + return false; + + if (band == 0) + return true; + + if (m_type->GetCurrentSelection() == wxNOT_FOUND) { + wxMessageDialog dialog(this, _("The Hardware Type is not set"), m_title + _(" Error"), wxICON_ERROR); + dialog.ShowModal(); + return false; + } + + wxString address = getAddress(); + + if (address.IsEmpty()) { + wxMessageDialog dialog(this, _("The Repeater Address is not valid"), m_title + _(" Error"), wxICON_ERROR); + dialog.ShowModal(); + return false; + } + + unsigned int port = getPort(); + + if (port == 0U || port > 65535U) { + wxMessageDialog dialog(this, _("The Repeater Port is not valid"), m_title + _(" Error"), wxICON_ERROR); + dialog.ShowModal(); + return false; + } + + if (m_reflector->GetCurrentSelection() == wxNOT_FOUND) + return false; + + if (m_channel->GetCurrentSelection() == wxNOT_FOUND) + return false; + + if (m_startup->GetCurrentSelection() == wxNOT_FOUND) + return false; + + if (m_reconnect->GetCurrentSelection() == wxNOT_FOUND) + return false; + + return true; +} + +wxString CRepeaterDataSet::getBand() const +{ + int c = m_band->GetCurrentSelection(); + + switch (c) { + case 0: + return wxT(" "); + case 1: + return wxT("A"); + case 2: + return wxT("B"); + case 3: + return wxT("C"); + case 4: + return wxT("D"); + case 5: + return wxT("E"); + case 6: + return wxT("AD"); + case 7: + return wxT("BD"); + case 8: + return wxT("CD"); + case 9: + return wxT("DD"); + case 10: + return wxT("ED"); + default: + return wxT(" "); + } +} + +wxString CRepeaterDataSet::getAddress() const +{ + return m_address->GetValue(); +} + +HW_TYPE CRepeaterDataSet::getType() const +{ + if (isDDMode()) + return HW_ICOM; + + int n = m_type->GetCurrentSelection(); + if (n == wxNOT_FOUND) + n = 0; + + return HW_TYPE(n); +} + +unsigned int CRepeaterDataSet::getPort() const +{ + unsigned long n; + m_port->GetValue().ToULong(&n); + + return n; +} + +unsigned char CRepeaterDataSet::getBand1() const +{ + unsigned long n; + m_band1->GetValue().ToULong(&n); + + return n; +} + +unsigned char CRepeaterDataSet::getBand2() const +{ + unsigned long n; + m_band2->GetValue().ToULong(&n); + + return n; +} + +unsigned char CRepeaterDataSet::getBand3() const +{ + unsigned long n; + m_band3->GetValue().ToULong(&n); + + return n; +} + +wxString CRepeaterDataSet::getReflector() const +{ + if (isDDMode()) + return wxEmptyString; + + if (m_reflector->GetCurrentSelection() == 0) + return wxEmptyString; + + wxString reflector = m_reflector->GetStringSelection(); + + reflector.Append(wxT(" ")); + reflector.Truncate(LONG_CALLSIGN_LENGTH - 1U); + reflector.Append(m_channel->GetStringSelection()); + + return reflector; +} + +bool CRepeaterDataSet::atStartup() const +{ + if (isDDMode()) + return false; + + int n = m_startup->GetCurrentSelection(); + + return n == 1; +} + +RECONNECT CRepeaterDataSet::getReconnect() const +{ + if (isDDMode()) + return RECONNECT_NEVER; + + int n = m_reconnect->GetCurrentSelection(); + + return RECONNECT(n); +} + +void CRepeaterDataSet::onBand(wxCommandEvent &event) +{ + if (isDDMode()) { + m_reflector->SetSelection(0); + m_channel->SetSelection(0); + m_startup->SetSelection(0); + m_reconnect->SetSelection(0); + + m_reflector->Disable(); + m_channel->Disable(); + m_startup->Disable(); + m_reconnect->Disable(); + } else { + m_reflector->Enable(); + m_channel->Enable(); + m_startup->Enable(); + m_reconnect->Enable(); + } +} + +void CRepeaterDataSet::onType(wxCommandEvent &event) +{ + int n = m_type->GetCurrentSelection(); + if (n != 1) { + m_band1->Disable(); + m_band2->Disable(); + m_band3->Disable(); + } else { + m_band1->Enable(); + m_band2->Enable(); + m_band3->Enable(); + } +} + +bool CRepeaterDataSet::isDDMode() const +{ + int c = m_band->GetCurrentSelection(); + + switch (c) { + case 6: + case 7: + case 8: + case 9: + case 10: + return true; + default: + return false; + } +} diff --git a/GUICommon/RepeaterDataSet.h b/GUICommon/RepeaterDataSet.h new file mode 100644 index 0000000..5048eb9 --- /dev/null +++ b/GUICommon/RepeaterDataSet.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2010,2011,2012 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef RepeaterDataSet_H +#define RepeaterDataSet_H + +#include "AddressTextCtrl.h" +#include "PortTextCtrl.h" +#include "Defs.h" + +#include + +class CRepeaterDataSet : public wxPanel { +public: + CRepeaterDataSet(wxWindow* parent, int id, const wxString& title, const wxString& band, HW_TYPE type, const wxString& address, unsigned int port, unsigned char band1, unsigned char band2, unsigned char band3, bool dplusEnabled, bool dExtraEnabled, bool dcsEnabled, const wxString& reflector, bool atStartup, RECONNECT reconnect); + virtual ~CRepeaterDataSet(); + + virtual bool Validate(); + + virtual wxString getBand() const; + + virtual HW_TYPE getType() const; + virtual wxString getAddress() const; + virtual unsigned int getPort() const; + + virtual unsigned char getBand1() const; + virtual unsigned char getBand2() const; + virtual unsigned char getBand3() const; + + virtual wxString getReflector() const; + virtual bool atStartup() const; + virtual RECONNECT getReconnect() const; + + virtual void onBand(wxCommandEvent& event); + virtual void onType(wxCommandEvent& event); + +private: + wxString m_title; + wxChoice* m_band; + wxChoice* m_type; + CAddressTextCtrl* m_address; + CPortTextCtrl* m_port; + CPortTextCtrl* m_band1; + CPortTextCtrl* m_band2; + CPortTextCtrl* m_band3; + wxChoice* m_reflector; + wxChoice* m_channel; + wxChoice* m_startup; + wxChoice* m_reconnect; + + bool isDDMode() const; + + DECLARE_EVENT_TABLE() +}; + +#endif diff --git a/GUICommon/RepeaterInfoSet.cpp b/GUICommon/RepeaterInfoSet.cpp new file mode 100644 index 0000000..0feebbf --- /dev/null +++ b/GUICommon/RepeaterInfoSet.cpp @@ -0,0 +1,218 @@ +/* + * Copyright (C) 2010-2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "RepeaterInfoSet.h" +#include "DStarDefines.h" + +const unsigned int CONTROL_WIDTH1 = 130U; +const unsigned int CONTROL_WIDTH2 = 80U; +const unsigned int CONTROL_WIDTH3 = 40U; + +const unsigned int DESCRIPTION_LENGTH = 20U; +const unsigned int FREQUENCY_LENGTH = 9U; +const unsigned int OFFSET_LENGTH = 6U; +const unsigned int PORT_LENGTH = 5U; +const unsigned int URL_LENGTH = 40U; + +const unsigned int BORDER_SIZE = 5U; + + +CRepeaterInfoSet::CRepeaterInfoSet(wxWindow* parent, int id, const wxString& title, double frequency, double offset, double range, double latitude, double longitude, double agl, const wxString& description1, const wxString& description2, const wxString& url) : +wxPanel(parent, id), +m_title(title), +m_frequency(NULL), +m_offset(NULL), +m_range(NULL), +m_latitude(NULL), +m_longitude(NULL), +m_agl(NULL), +m_description1(NULL), +m_description2(NULL), +m_url(NULL) +{ + wxFlexGridSizer* sizer = new wxFlexGridSizer(2); + + wxStaticText* frequencyLabel = new wxStaticText(this, -1, _("Frequency (MHz)")); + sizer->Add(frequencyLabel, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + wxString buffer; + buffer.Printf(wxT("%.5lf"), frequency); + + m_frequency = new wxTextCtrl(this, -1, buffer, wxDefaultPosition, wxSize(CONTROL_WIDTH1, -1)); + m_frequency->SetMaxLength(FREQUENCY_LENGTH); + sizer->Add(m_frequency, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + + wxStaticText* offsetLabel = new wxStaticText(this, -1, _("Offset (MHz)")); + sizer->Add(offsetLabel, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + buffer.Printf(wxT("%.4lf"), offset); + + m_offset = new wxTextCtrl(this, -1, buffer, wxDefaultPosition, wxSize(CONTROL_WIDTH1, -1)); + m_offset->SetMaxLength(OFFSET_LENGTH); + sizer->Add(m_offset, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + + wxStaticText* rangeLabel = new wxStaticText(this, -1, _("Range (kms)")); + sizer->Add(rangeLabel, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + buffer.Printf(wxT("%.0lf"), range); + + m_range = new wxTextCtrl(this, -1, buffer, wxDefaultPosition, wxSize(CONTROL_WIDTH2, -1)); + m_range->SetMaxLength(PORT_LENGTH); + sizer->Add(m_range, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + + wxStaticText* latitudeLabel = new wxStaticText(this, -1, _("Latitude")); + sizer->Add(latitudeLabel, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + buffer.Printf(wxT("%lf"), latitude); + + m_latitude = new wxTextCtrl(this, -1, buffer, wxDefaultPosition, wxSize(CONTROL_WIDTH1, -1)); + sizer->Add(m_latitude, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + + wxStaticText* longitudeLabel = new wxStaticText(this, -1, _("Longitude")); + sizer->Add(longitudeLabel, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + buffer.Printf(wxT("%lf"), longitude); + + m_longitude = new wxTextCtrl(this, -1, buffer, wxDefaultPosition, wxSize(CONTROL_WIDTH1, -1)); + sizer->Add(m_longitude, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + + wxStaticText* aglLabel = new wxStaticText(this, -1, _("AGL (m)")); + sizer->Add(aglLabel, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + buffer.Printf(wxT("%.0lf"), agl); + + m_agl = new wxTextCtrl(this, -1, buffer, wxDefaultPosition, wxSize(CONTROL_WIDTH2, -1)); + m_agl->SetMaxLength(PORT_LENGTH); + sizer->Add(m_agl, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + + wxStaticText* descriptionLabel = new wxStaticText(this, -1, _("QTH")); + sizer->Add(descriptionLabel, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + m_description1 = new CDescriptionTextCtrl(this, -1, description1, wxDefaultPosition, wxSize(CONTROL_WIDTH1, -1)); + m_description1->SetMaxLength(DESCRIPTION_LENGTH); + sizer->Add(m_description1, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + + wxStaticText* dummyLabel = new wxStaticText(this, -1, wxEmptyString); + sizer->Add(dummyLabel, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + m_description2 = new CDescriptionTextCtrl(this, -1, description2, wxDefaultPosition, wxSize(CONTROL_WIDTH1, -1)); + m_description2->SetMaxLength(DESCRIPTION_LENGTH); + sizer->Add(m_description2, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + + wxStaticText* urlLabel = new wxStaticText(this, -1, _("URL")); + sizer->Add(urlLabel, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + m_url = new CDescriptionTextCtrl(this, -1, url, wxDefaultPosition, wxSize(CONTROL_WIDTH1, -1)); + m_url->SetMaxLength(URL_LENGTH); + sizer->Add(m_url, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + + SetAutoLayout(true); + + SetSizer(sizer); +} + + +CRepeaterInfoSet::~CRepeaterInfoSet() +{ +} + +bool CRepeaterInfoSet::Validate() +{ + double latitude = getLatitude(); + + if (latitude < -90.0 || latitude > 90.0) { + wxMessageDialog dialog(this, _("The Latitude is invalid"), m_title + _(" Error"), wxICON_ERROR); + dialog.ShowModal(); + return false; + } + + double longitude = getLongitude(); + + if (longitude < -180.0 || longitude > 180.0) { + wxMessageDialog dialog(this, _("The Longitude is invalid"), m_title + _(" Error"), wxICON_ERROR); + dialog.ShowModal(); + return false; + } + + return true; +} + +double CRepeaterInfoSet::getFrequency() const +{ + double n; + m_frequency->GetValue().ToDouble(&n); + + return n; +} + +double CRepeaterInfoSet::getOffset() const +{ + double n; + m_offset->GetValue().ToDouble(&n); + + return n; +} + +double CRepeaterInfoSet::getRange() const +{ + double n; + m_range->GetValue().ToDouble(&n); + + return n; +} + +double CRepeaterInfoSet::getLatitude() const +{ + double val; + + m_latitude->GetValue().ToDouble(&val); + + return val; +} + +double CRepeaterInfoSet::getLongitude() const +{ + double val; + + m_longitude->GetValue().ToDouble(&val); + + return val; +} + +wxString CRepeaterInfoSet::getDescription1() const +{ + return m_description1->GetValue(); +} + +wxString CRepeaterInfoSet::getDescription2() const +{ + return m_description2->GetValue(); +} + +wxString CRepeaterInfoSet::getURL() const +{ + return m_url->GetValue(); +} + +double CRepeaterInfoSet::getAGL() const +{ + double n; + m_agl->GetValue().ToDouble(&n); + + return n; +} diff --git a/GUICommon/RepeaterInfoSet.h b/GUICommon/RepeaterInfoSet.h new file mode 100644 index 0000000..c9a9568 --- /dev/null +++ b/GUICommon/RepeaterInfoSet.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2010-2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef RepeaterInfoSet_H +#define RepeaterInfoSet_H + +#include "DescriptionTextCtrl.h" + +#include + +class CRepeaterInfoSet : public wxPanel { +public: + CRepeaterInfoSet(wxWindow* parent, int id, const wxString& title, double frequency, double offset, double range, double latitude, double longitude, double agl, const wxString& description1, const wxString& description2, const wxString& url); + virtual ~CRepeaterInfoSet(); + + virtual bool Validate(); + + virtual double getFrequency() const; + virtual double getOffset() const; + virtual double getRange() const; + + virtual double getLatitude() const; + virtual double getLongitude() const; + virtual double getAGL() const; + + virtual wxString getDescription1() const; + virtual wxString getDescription2() const; + virtual wxString getURL() const; + +private: + wxString m_title; + wxTextCtrl* m_frequency; + wxTextCtrl* m_offset; + wxTextCtrl* m_range; + wxTextCtrl* m_latitude; + wxTextCtrl* m_longitude; + wxTextCtrl* m_agl; + CDescriptionTextCtrl* m_description1; + CDescriptionTextCtrl* m_description2; + CDescriptionTextCtrl* m_url; +}; + +#endif diff --git a/GUICommon/RestrictedTextCtrl.cpp b/GUICommon/RestrictedTextCtrl.cpp new file mode 100644 index 0000000..a291044 --- /dev/null +++ b/GUICommon/RestrictedTextCtrl.cpp @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2002,2003,2009 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "RestrictedTextCtrl.h" + +CRestrictedTextCtrl::CRestrictedTextCtrl(wxWindow* parent, int id, const wxString& value, const wxPoint& pos, const wxSize& size, long style, const wxString& wantedChars) : +wxTextCtrl() +{ + wxASSERT(parent != NULL); + + wxArrayString charList; + + for (unsigned int i = 0; i < wantedChars.Length(); i++) + charList.Add(wantedChars.Mid(i, 1)); + + wxTextValidator validator(wxFILTER_INCLUDE_CHAR_LIST); + validator.SetIncludes(charList); + + Create(parent, id, value, pos, size, style, validator); +} + +CRestrictedTextCtrl::~CRestrictedTextCtrl() +{ +} + diff --git a/GUICommon/RestrictedTextCtrl.h b/GUICommon/RestrictedTextCtrl.h new file mode 100644 index 0000000..f3d57b6 --- /dev/null +++ b/GUICommon/RestrictedTextCtrl.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2002,2003 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef RestrictedTextCtrl_H +#define RestrictedTextCtrl_H + +#include + +class CRestrictedTextCtrl : public wxTextCtrl { +public: + CRestrictedTextCtrl(wxWindow* parent, int id, const wxString& value, const wxPoint& pos, const wxSize& size, long style, const wxString& wantedChars); + virtual ~CRestrictedTextCtrl(); + +private: +}; + +#endif diff --git a/GUICommon/StarNetSet.cpp b/GUICommon/StarNetSet.cpp new file mode 100644 index 0000000..b45fb12 --- /dev/null +++ b/GUICommon/StarNetSet.cpp @@ -0,0 +1,509 @@ +/* + * Copyright (C) 2011,2012,2014 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "DStarDefines.h" +#include "StarNetSet.h" +#include "HostFile.h" // DEXTRA_LINK || DCS_LINK +#include "Defs.h" // DEXTRA_LINK || DCS_LINK + +#include // DEXTRA_LINK || DCS_LINK + +const unsigned int BAND_WIDTH = 60U; +const unsigned int CALLSIGN_WIDTH = 120U; +const unsigned int INFO_WIDTH = 150U; +const unsigned int TIMEOUT_WIDTH = 150U; + +const unsigned int CONTROL_WIDTH1 = 150U; // DEXTRA_LINK +const unsigned int CONTROL_WIDTH2 = 60U; // DEXTRA_LINK + +const unsigned int INFO_LENGTH = 20U; + +const unsigned int BORDER_SIZE = 5U; + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) +CStarNetSet::CStarNetSet(wxWindow* parent, int id, const wxString& title, const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch, const wxString& reflector) : +#else +CStarNetSet::CStarNetSet(wxWindow* parent, int id, const wxString& title, const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch) : +#endif +wxPanel(parent, id), +m_title(title), +m_band(NULL), +m_callsign(NULL), +m_logoff(NULL), +m_info(NULL), +m_permanent(NULL), +m_userTimeout(NULL), +m_groupTimeout(NULL), +m_callsignSwitch(NULL), +m_txMsgSwitch(NULL) +#if defined(DEXTRA_LINK) || defined(DCS_LINK) +,m_reflector(NULL) +#endif +{ + wxFlexGridSizer* sizer = new wxFlexGridSizer(3); + + wxStaticText* bandLabel = new wxStaticText(this, -1, _("Band")); + sizer->Add(bandLabel, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + m_band = new wxChoice(this, -1, wxDefaultPosition, wxSize(BAND_WIDTH, -1)); + m_band->Append(wxT("A")); + m_band->Append(wxT("B")); + m_band->Append(wxT("C")); + m_band->Append(wxT("D")); + sizer->Add(m_band, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + bool res = m_band->SetStringSelection(band); + if (!res) + m_band->SetSelection(0); + + wxStaticText* dummy1Label = new wxStaticText(this, -1, wxEmptyString); + sizer->Add(dummy1Label, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + wxStaticText* callsignLabel = new wxStaticText(this, -1, _("Group Call")); + sizer->Add(callsignLabel, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + wxString call = callsign; + call.Truncate(LONG_CALLSIGN_LENGTH); + + m_callsign = new CCallsignTextCtrl(this, -1, call, wxDefaultPosition, wxSize(CALLSIGN_WIDTH, -1)); + m_callsign->SetMaxLength(LONG_CALLSIGN_LENGTH); + sizer->Add(m_callsign, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + + wxStaticText* dummy2Label = new wxStaticText(this, -1, wxEmptyString); + sizer->Add(dummy2Label, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + wxStaticText* logoffLabel = new wxStaticText(this, -1, _("Logoff Call")); + sizer->Add(logoffLabel, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + call = logoff; + call.Truncate(LONG_CALLSIGN_LENGTH); + + m_logoff = new CCallsignTextCtrl(this, -1, call, wxDefaultPosition, wxSize(CALLSIGN_WIDTH, -1)); + m_logoff->SetMaxLength(LONG_CALLSIGN_LENGTH); + sizer->Add(m_logoff, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + + wxStaticText* dummy3Label = new wxStaticText(this, -1, wxEmptyString); + sizer->Add(dummy3Label, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + wxStaticText* infoLabel = new wxStaticText(this, -1, _("Information")); + sizer->Add(infoLabel, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + m_info = new wxTextCtrl(this, -1, info, wxDefaultPosition, wxSize(INFO_WIDTH, -1)); + m_info->SetMaxLength(INFO_LENGTH); + sizer->Add(m_info, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + + wxStaticText* dummy4Label = new wxStaticText(this, -1, wxEmptyString); + sizer->Add(dummy4Label, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + wxStaticText* permanentLabel = new wxStaticText(this, -1, _("Permanent Calls")); + sizer->Add(permanentLabel, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + call = permanent; + call.Truncate(LONG_CALLSIGN_LENGTH); + + m_permanent = new CCallsignTextCtrl(this, -1, call, wxDefaultPosition, wxSize(INFO_WIDTH, -1)); + sizer->Add(m_permanent, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + + wxStaticText* dummy4ALabel = new wxStaticText(this, -1, wxEmptyString); + sizer->Add(dummy4ALabel, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + wxStaticText* userTimeoutLabel = new wxStaticText(this, -1, _("User Timeout")); + sizer->Add(userTimeoutLabel, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + m_userTimeout = new wxChoice(this, -1, wxDefaultPosition, wxSize(TIMEOUT_WIDTH, -1)); + m_userTimeout->Append(_("Never")); + m_userTimeout->Append(_("30 mins")); + m_userTimeout->Append(_("60 mins")); + m_userTimeout->Append(_("120 mins")); + m_userTimeout->Append(_("180 mins")); + m_userTimeout->Append(_("240 mins")); + m_userTimeout->Append(_("300 mins")); + sizer->Add(m_userTimeout, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + + switch (userTimeout) { + case 0U: m_userTimeout->SetSelection(0); break; + case 30U: m_userTimeout->SetSelection(1); break; + case 60U: m_userTimeout->SetSelection(2); break; + case 120U: m_userTimeout->SetSelection(3); break; + case 180U: m_userTimeout->SetSelection(4); break; + case 240U: m_userTimeout->SetSelection(5); break; + default: m_userTimeout->SetSelection(6); break; + } + + wxStaticText* dummy5Label = new wxStaticText(this, -1, wxEmptyString); + sizer->Add(dummy5Label, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + wxStaticText* groupTimeoutLabel = new wxStaticText(this, -1, _("Group Timeout")); + sizer->Add(groupTimeoutLabel, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + m_groupTimeout = new wxChoice(this, -1, wxDefaultPosition, wxSize(TIMEOUT_WIDTH, -1)); + m_groupTimeout->Append(_("Never")); + m_groupTimeout->Append(_("30 mins")); + m_groupTimeout->Append(_("60 mins")); + m_groupTimeout->Append(_("120 mins")); + m_groupTimeout->Append(_("180 mins")); + m_groupTimeout->Append(_("240 mins")); + m_groupTimeout->Append(_("300 mins")); + sizer->Add(m_groupTimeout, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + + switch (groupTimeout) { + case 0U: m_groupTimeout->SetSelection(0); break; + case 30U: m_groupTimeout->SetSelection(1); break; + case 60U: m_groupTimeout->SetSelection(2); break; + case 120U: m_groupTimeout->SetSelection(3); break; + case 180U: m_groupTimeout->SetSelection(4); break; + case 240U: m_groupTimeout->SetSelection(5); break; + default: m_groupTimeout->SetSelection(6); break; + } + + wxStaticText* dummy6Label = new wxStaticText(this, -1, wxEmptyString); + sizer->Add(dummy6Label, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + wxStaticText* callsignSwitchLabel = new wxStaticText(this, -1, _("MYCALL Setting")); + sizer->Add(callsignSwitchLabel, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + m_callsignSwitch = new wxChoice(this, -1, wxDefaultPosition, wxSize(CALLSIGN_WIDTH, -1)); + m_callsignSwitch->Append(_("Group")); + m_callsignSwitch->Append(_("User")); + sizer->Add(m_callsignSwitch, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + + switch (callsignSwitch) { + case SCS_GROUP_CALLSIGN: m_callsignSwitch->SetSelection(0); break; + case SCS_USER_CALLSIGN: m_callsignSwitch->SetSelection(1); break; + default: m_callsignSwitch->SetSelection(0); break; + } + + wxStaticText* dummy7Label = new wxStaticText(this, -1, wxEmptyString); + sizer->Add(dummy7Label, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + wxStaticText* txMsgSwitchLabel = new wxStaticText(this, -1, _("TX Message")); + sizer->Add(txMsgSwitchLabel, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + m_txMsgSwitch = new wxChoice(this, -1, wxDefaultPosition, wxSize(CALLSIGN_WIDTH, -1)); + m_txMsgSwitch->Append(_("Off")); + m_txMsgSwitch->Append(_("On")); + sizer->Add(m_txMsgSwitch, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + m_txMsgSwitch->SetSelection(txMsgSwitch ? 1 : 0); + + wxStaticText* dummy8Label = new wxStaticText(this, -1, wxEmptyString); + sizer->Add(dummy8Label, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + +#if defined(DEXTRA_LINK) + wxStaticText* reflectorLabel = new wxStaticText(this, -1, _("Reflector")); + sizer->Add(reflectorLabel, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + + m_reflector = new wxChoice(this, -1, wxDefaultPosition, wxSize(CONTROL_WIDTH1, -1)); + m_reflector->Append(_("None")); + + wxFileName fileName(wxFileName::GetHomeDir(), DEXTRA_HOSTS_FILE_NAME); + if (!fileName.IsFileReadable()) { + wxLogMessage(wxT("File %s not readable"), fileName.GetFullPath().c_str()); +#if defined(__WINDOWS__) + fileName.Assign(::wxGetCwd(), DEXTRA_HOSTS_FILE_NAME); +#else + fileName.Assign(wxT(DATA_DIR), DEXTRA_HOSTS_FILE_NAME); +#endif + if (!fileName.IsFileReadable()) + wxLogMessage(wxT("File %s not readable"), fileName.GetFullPath().c_str()); + } + + CHostFile file(fileName.GetFullPath(), false); + + for (unsigned int i = 0U; i < file.getCount(); i++) + m_reflector->Append(file.getName(i)); + + sizer->Add(m_reflector, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + + if (reflector.IsEmpty()) { + m_reflector->SetSelection(0); + } else { + wxString name = reflector; + name.SetChar(LONG_CALLSIGN_LENGTH - 1U, wxT(' ')); + bool res = m_reflector->SetStringSelection(name); + if (!res) + m_reflector->SetSelection(0); + } + + m_channel = new wxChoice(this, -1, wxDefaultPosition, wxSize(CONTROL_WIDTH2, -1)); + m_channel->Append(wxT("A")); + m_channel->Append(wxT("B")); + m_channel->Append(wxT("C")); + m_channel->Append(wxT("D")); + m_channel->Append(wxT("E")); + sizer->Add(m_channel, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + res = m_channel->SetStringSelection(reflector.Right(1U)); + if (!res) + m_channel->SetSelection(0); +#endif + +#if defined(DCS_LINK) + wxStaticText* reflectorLabel = new wxStaticText(this, -1, _("Reflector")); + sizer->Add(reflectorLabel, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + + m_reflector = new wxChoice(this, -1, wxDefaultPosition, wxSize(CONTROL_WIDTH1, -1)); + m_reflector->Append(_("None")); + + wxFileName fileName(wxFileName::GetHomeDir(), DCS_HOSTS_FILE_NAME); + if (!fileName.IsFileReadable()) { + wxLogMessage(wxT("File %s not readable"), fileName.GetFullPath().c_str()); +#if defined(__WINDOWS__) + fileName.Assign(::wxGetCwd(), DCS_HOSTS_FILE_NAME); +#else + fileName.Assign(wxT(DATA_DIR), DCS_HOSTS_FILE_NAME); +#endif + if (!fileName.IsFileReadable()) + wxLogMessage(wxT("File %s not readable"), fileName.GetFullPath().c_str()); + } + + CHostFile file(fileName.GetFullPath(), false); + + for (unsigned int i = 0U; i < file.getCount(); i++) + m_reflector->Append(file.getName(i)); + + sizer->Add(m_reflector, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + + if (reflector.IsEmpty()) { + m_reflector->SetSelection(0); + } else { + wxString name = reflector; + name.SetChar(LONG_CALLSIGN_LENGTH - 1U, wxT(' ')); + bool res = m_reflector->SetStringSelection(name); + if (!res) + m_reflector->SetSelection(0); + } + + m_channel = new wxChoice(this, -1, wxDefaultPosition, wxSize(CONTROL_WIDTH2, -1)); + m_channel->Append(wxT("A")); + m_channel->Append(wxT("B")); + m_channel->Append(wxT("C")); + m_channel->Append(wxT("D")); + m_channel->Append(wxT("E")); + m_channel->Append(wxT("F")); + m_channel->Append(wxT("G")); + m_channel->Append(wxT("H")); + m_channel->Append(wxT("I")); + m_channel->Append(wxT("J")); + m_channel->Append(wxT("K")); + m_channel->Append(wxT("L")); + m_channel->Append(wxT("M")); + m_channel->Append(wxT("N")); + m_channel->Append(wxT("O")); + m_channel->Append(wxT("P")); + m_channel->Append(wxT("Q")); + m_channel->Append(wxT("R")); + m_channel->Append(wxT("S")); + m_channel->Append(wxT("T")); + m_channel->Append(wxT("U")); + m_channel->Append(wxT("V")); + m_channel->Append(wxT("W")); + m_channel->Append(wxT("X")); + m_channel->Append(wxT("Y")); + m_channel->Append(wxT("Z")); + sizer->Add(m_channel, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + res = m_channel->SetStringSelection(reflector.Right(1U)); + if (!res) + m_channel->SetSelection(0); +#endif + + SetAutoLayout(true); + + SetSizer(sizer); +} + + +CStarNetSet::~CStarNetSet() +{ +} + +bool CStarNetSet::Validate() +{ + int n = m_band->GetCurrentSelection(); + if (n == wxNOT_FOUND) { + wxMessageDialog dialog(this, _("The StarNet Band is not set"), m_title + _(" Error"), wxICON_ERROR); + dialog.ShowModal(); + return false; + } + + n = m_userTimeout->GetCurrentSelection(); + if (n == wxNOT_FOUND) { + wxMessageDialog dialog(this, _("The StarNet user timeout is not set"), m_title + _(" Error"), wxICON_ERROR); + dialog.ShowModal(); + return false; + } + + n = m_groupTimeout->GetCurrentSelection(); + if (n == wxNOT_FOUND) { + wxMessageDialog dialog(this, _("The StarNet group timeout is not set"), m_title + _(" Error"), wxICON_ERROR); + dialog.ShowModal(); + return false; + } + + n = m_callsignSwitch->GetCurrentSelection(); + if (n == wxNOT_FOUND) { + wxMessageDialog dialog(this, _("The MYCALL Setting is not set"), m_title + _(" Error"), wxICON_ERROR); + dialog.ShowModal(); + return false; + } + + n = m_txMsgSwitch->GetCurrentSelection(); + if (n == wxNOT_FOUND) { + wxMessageDialog dialog(this, _("The TX Message switch is not set"), m_title + _(" Error"), wxICON_ERROR); + dialog.ShowModal(); + return false; + } + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + n = m_reflector->GetCurrentSelection(); + if (n == wxNOT_FOUND) { + wxMessageDialog dialog(this, _("The StarNet reflector link is not set"), m_title + _(" Error"), wxICON_ERROR); + dialog.ShowModal(); + return false; + } +#endif + + return true; +} + +wxString CStarNetSet::getBand() const +{ + return m_band->GetStringSelection(); +} + +wxString CStarNetSet::getCallsign() const +{ + wxString callsign = m_callsign->GetValue(); + + callsign.MakeUpper(); + callsign.Append(wxT(" ")); + callsign.Truncate(LONG_CALLSIGN_LENGTH); + + return callsign; +} + +wxString CStarNetSet::getLogoff() const +{ + wxString callsign = m_logoff->GetValue(); + + callsign.MakeUpper(); + callsign.Append(wxT(" ")); + callsign.Truncate(LONG_CALLSIGN_LENGTH); + + return callsign; +} + +wxString CStarNetSet::getInfo() const +{ + return m_info->GetValue(); +} + +wxString CStarNetSet::getPermanent() const +{ + wxString callsign = m_permanent->GetValue(); + + callsign.MakeUpper(); + callsign.Append(wxT(" ")); + callsign.Truncate(LONG_CALLSIGN_LENGTH); + + return callsign; +} + +unsigned int CStarNetSet::getUserTimeout() const +{ + int n = m_userTimeout->GetCurrentSelection(); + switch (n) { + case 0: + return 0U; + case 1: + return 30U; + case 2: + return 60U; + case 3: + return 120U; + case 4: + return 180U; + case 5: + return 240U; + default: + return 300U; + } +} + +unsigned int CStarNetSet::getGroupTimeout() const +{ + int n = m_groupTimeout->GetCurrentSelection(); + switch (n) { + case 0: + return 0U; + case 1: + return 30U; + case 2: + return 60U; + case 3: + return 120U; + case 4: + return 180U; + case 5: + return 240U; + default: + return 300U; + } +} + +STARNET_CALLSIGN_SWITCH CStarNetSet::getCallsignSwitch() const +{ + int n = m_callsignSwitch->GetCurrentSelection(); + switch (n) { + case 0: + return SCS_GROUP_CALLSIGN; + case 1: + return SCS_USER_CALLSIGN; + default: + return SCS_GROUP_CALLSIGN; + } +} + +bool CStarNetSet::getTXMsgSwitch() const +{ + int n = m_txMsgSwitch->GetCurrentSelection(); + switch (n) { + case 0: + return false; + case 1: + return true; + default: + return false; + } +} + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) +wxString CStarNetSet::getReflector() const +{ + int n = m_reflector->GetCurrentSelection(); + int c = m_channel->GetCurrentSelection(); + + if (n == 0) + return wxEmptyString; + + wxString reflector = m_reflector->GetStringSelection(); + + reflector.Append(wxT(" ")); + reflector.Truncate(LONG_CALLSIGN_LENGTH - 1U); + reflector.Append((char)('A' + c)); + + return reflector; +} +#endif diff --git a/GUICommon/StarNetSet.h b/GUICommon/StarNetSet.h new file mode 100644 index 0000000..7ccf9f0 --- /dev/null +++ b/GUICommon/StarNetSet.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2011,2012 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef StarNetSet_H +#define StarNetSet_H + +#include "CallsignTextCtrl.h" +#include "Defs.h" + +#include + +class CStarNetSet : public wxPanel { +public: +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + CStarNetSet(wxWindow* parent, int id, const wxString& title, const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch, const wxString& reflector); +#else + CStarNetSet(wxWindow* parent, int id, const wxString& title, const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch); +#endif + virtual ~CStarNetSet(); + + virtual bool Validate(); + + virtual wxString getBand() const; + virtual wxString getCallsign() const; + virtual wxString getLogoff() const; + virtual wxString getInfo() const; + virtual wxString getPermanent() const; + virtual unsigned int getGroupTimeout() const; + virtual unsigned int getUserTimeout() const; + virtual STARNET_CALLSIGN_SWITCH getCallsignSwitch() const; + virtual bool getTXMsgSwitch() const; +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + virtual wxString getReflector() const; +#endif + +private: + wxString m_title; + wxChoice* m_band; + CCallsignTextCtrl* m_callsign; + CCallsignTextCtrl* m_logoff; + wxTextCtrl* m_info; + CCallsignTextCtrl* m_permanent; + wxChoice* m_userTimeout; + wxChoice* m_groupTimeout; + wxChoice* m_callsignSwitch; + wxChoice* m_txMsgSwitch; +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + wxChoice* m_reflector; + wxChoice* m_channel; +#endif +}; + +#endif diff --git a/GUICommon/XLXSet.cpp b/GUICommon/XLXSet.cpp new file mode 100644 index 0000000..616e6c0 --- /dev/null +++ b/GUICommon/XLXSet.cpp @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2012,2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "HostFile.h" +#include "XLXSet.h" +#include "Defs.h" + +// TODO F4FXL try to figure out why below symbols are not found under ubuntu +//#include + +const unsigned int CONTROL_WIDTH = 130U; + +const unsigned int BORDER_SIZE = 5U; + +const int CHOICE_ENABLED = 8788; + +BEGIN_EVENT_TABLE(CXLXSet, wxPanel) + EVT_CHOICE(CHOICE_ENABLED, CXLXSet::onEnabled) +END_EVENT_TABLE() + + +CXLXSet::CXLXSet(wxWindow* parent, int id, const wxString& title, bool xlxEnabled, bool xlxOverrideLocal, const wxString& xlxHostsFileUrl) : +wxPanel(parent, id), +m_title(title), +m_xlxEnabled(NULL), +m_xlxOverrideLocal(NULL), +m_xlxHostsFileUrl(NULL) +{ + wxFlexGridSizer* sizer = new wxFlexGridSizer(2); + + wxStaticText* xlxEnabledLabel = new wxStaticText(this, -1, wxT("XLX")); + sizer->Add(xlxEnabledLabel, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + m_xlxEnabled = new wxChoice(this, CHOICE_ENABLED, wxDefaultPosition, wxSize(CONTROL_WIDTH, -1)); + m_xlxEnabled->Append(_("Disabled")); + m_xlxEnabled->Append(_("Enabled")); + sizer->Add(m_xlxEnabled, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + m_xlxEnabled->SetSelection(xlxEnabled ? 1 : 0); + + wxStaticText* xlxOverrideLocalLabel = new wxStaticText(this, -1, _("Override local hosts files")); + sizer->Add(xlxOverrideLocalLabel, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + m_xlxOverrideLocal = new wxChoice(this, CHOICE_ENABLED, wxDefaultPosition, wxSize(CONTROL_WIDTH, -1)); + m_xlxOverrideLocal->Append(_("No")); + m_xlxOverrideLocal->Append(_("Yes")); + sizer->Add(m_xlxOverrideLocal, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + m_xlxOverrideLocal->SetSelection(xlxOverrideLocal ? 1 : 0); + + wxStaticText* xlxHostsFileUrlLabel = new wxStaticText(this, -1, _("Hosts file URL")); + sizer->Add(xlxHostsFileUrlLabel, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + m_xlxHostsFileUrl = new wxTextCtrl(this, -1, xlxHostsFileUrl, wxDefaultPosition, wxSize(CONTROL_WIDTH, -1)); + sizer->Add(m_xlxHostsFileUrl, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + + + if (xlxEnabled) + m_xlxHostsFileUrl->Enable(); + else + m_xlxHostsFileUrl->Disable(); + + SetAutoLayout(true); + + SetSizer(sizer); +} + + +CXLXSet::~CXLXSet() +{ +} + +bool CXLXSet::Validate() +{ + int n = m_xlxEnabled->GetCurrentSelection(); + if (n == wxNOT_FOUND) + return false; + + n = m_xlxOverrideLocal->GetCurrentSelection(); + if (n == wxNOT_FOUND) + return false; + + // TODO F4FXL try to figure out why below symbols are not found under ubuntu + /*wxString value = m_xlxHostsFileUrl->GetValue(); + wxURL url(value); + if (url.GetError() != wxURL_NOERR) + return false;*/ + + return true; +} + +bool CXLXSet::getXLXOverrideLocal() const +{ + int c = m_xlxEnabled->GetCurrentSelection(); + if (c == wxNOT_FOUND) + return false; + + return c == 1; +} + +bool CXLXSet::getXLXEnabled() const +{ + int c = m_xlxEnabled->GetCurrentSelection(); + if (c == wxNOT_FOUND) + return false; + + return c == 1; +} + +wxString CXLXSet::getXLXHostsFileUrl() const +{ + wxString value = m_xlxHostsFileUrl->GetValue(); + + + // TODO F4FXL try to figure out why below symbols are not found under ubuntu + //wxURL url(value); + //if (url.GetError() == wxURL_NOERR) + // return value; + + return wxEmptyString; +} + +void CXLXSet::onEnabled(wxCommandEvent &event) +{ + int n = m_xlxEnabled->GetCurrentSelection(); + if (n != 1) + m_xlxHostsFileUrl->Disable(); + else + m_xlxHostsFileUrl->Enable(); +} diff --git a/GUICommon/XLXSet.h b/GUICommon/XLXSet.h new file mode 100644 index 0000000..f765b55 --- /dev/null +++ b/GUICommon/XLXSet.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2012,2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef XLXSet_H +#define XLXSet_H + +#include + +class CXLXSet : public wxPanel { +public: + CXLXSet(wxWindow* parent, int id, const wxString& title, bool xlxEnabled, bool xlxOverrideLocal, const wxString& xlxHostsFileUrl); + virtual ~CXLXSet(); + + virtual bool Validate(); + + virtual bool getXLXEnabled() const; + virtual bool getXLXOverrideLocal() const; + virtual wxString getXLXHostsFileUrl() const; + + virtual void onEnabled(wxCommandEvent& event); + +private: + wxString m_title; + wxChoice* m_xlxEnabled; + wxChoice* m_xlxOverrideLocal; + wxTextCtrl* m_xlxHostsFileUrl; + + DECLARE_EVENT_TABLE() +}; + +#endif diff --git a/README.md b/README.md new file mode 100644 index 0000000..d099084 --- /dev/null +++ b/README.md @@ -0,0 +1,24 @@ +This is the ircDDB Gateway. It allows a D-Star Repeater to interface into callsign routing via ircDDB and all of the different reflector types. It includes many facilities, including: + +* Supports Icom stacks. +* Supports homebrew repeaters. +* Icom DD mode under Linux with Internet access. +* Callsign routing via ircDDB. +* D-Plus REF reflectors. +* DExtra XRF reflectors. +* DCS reflectors. +* XLX reflectors. +* CCS7 routing. +* D-RATS data transfers. +* Gateway DPRS data to aprs.fi. +* Full multi lingual text and voice announcements. +* DTMF or UR call control. +* Remote control interface. +* StarNet server. +* Ability to set policies for reflector usage. + +There are many external programs that allow for inserting voice or text messages, as well as remote control operation. + +They all build on 32-bit and 64-bit Linux as well as on Windows using Visual Studio 2017 on x86 and x64. + +This software is licenced under the GPL v2. diff --git a/RemoteControl/RemoteControl.vcxproj b/RemoteControl/RemoteControl.vcxproj new file mode 100644 index 0000000..ba4020a --- /dev/null +++ b/RemoteControl/RemoteControl.vcxproj @@ -0,0 +1,214 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {F7756875-1F58-4006-AD55-5C963AB682C0} + RemoteControl + Win32Proj + 10.0.16299.0 + + + + Application + v141 + Unicode + true + + + Application + v141 + Unicode + true + + + Application + v141 + Unicode + + + Application + v141 + Unicode + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>14.0.24720.0 + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + true + $(WXWIN)\include;$(WXWIN)\lib\vc_dll\mswud;$(IncludePath) + + + true + $(WXWIN)\include;$(WXWIN)\lib\vc_x64_dll\mswud;$(IncludePath) + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + false + + + false + + + + Disabled + $(WXWIN)\include\msvc;$(WXWIN)\include;../Common;../GUICommon;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;WINVER=0x0400;__WXMSW__;WXUSINGDLL;wxUSE_GUI=1;__WXDEBUG__;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + Level4 + EditAndContinue + + + ws2_32.lib;%(AdditionalDependencies) + $(WXWIN)\lib\vc_dll;%(AdditionalLibraryDirectories) + true + Windows + MachineX86 + + + + + Disabled + $(WXWIN)\include\msvc;$(WXWIN)\include;../Common;../GUICommon;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;WINVER=0x0400;__WXMSW__;WXUSINGDLL;wxUSE_GUI=1;__WXDEBUG__;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + + + Level4 + ProgramDatabase + + + ws2_32.lib;%(AdditionalDependencies) + $(WXWIN)\lib\vc_x64_dll;%(AdditionalLibraryDirectories) + true + Windows + + + + + MaxSpeed + true + $(WXWIN)\include\msvc;$(WXWIN)\include;../Common;../GUICommon;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;WINVER=0x0400;__WXMSW__;WXUSINGDLL;wxUSE_GUI=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) + MultiThreadedDLL + true + + Level3 + ProgramDatabase + + + ws2_32.lib;%(AdditionalDependencies) + $(WXWIN)\lib\vc_dll;%(AdditionalLibraryDirectories) + true + Windows + true + true + MachineX86 + + + + + MaxSpeed + true + $(WXWIN)\include\msvc;$(WXWIN)\include;../Common;../GUICommon;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;WINVER=0x0400;__WXMSW__;WXUSINGDLL;wxUSE_GUI=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) + MultiThreadedDLL + true + + + Level3 + ProgramDatabase + + + ws2_32.lib;%(AdditionalDependencies) + $(WXWIN)\lib\vc_x64_dll;%(AdditionalLibraryDirectories) + true + Windows + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {e793cb8e-2ac9-431a-bbfc-3f52537bb3cf} + false + + + {02d03515-0bbe-4553-8c40-566a597478f8} + false + + + + + + \ No newline at end of file diff --git a/RemoteControl/RemoteControl.vcxproj.filters b/RemoteControl/RemoteControl.vcxproj.filters new file mode 100644 index 0000000..af844a0 --- /dev/null +++ b/RemoteControl/RemoteControl.vcxproj.filters @@ -0,0 +1,98 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/RemoteControl/RemoteControlApp.cpp b/RemoteControl/RemoteControlApp.cpp new file mode 100644 index 0000000..ec215a3 --- /dev/null +++ b/RemoteControl/RemoteControlApp.cpp @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2011,2012,2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "RemoteControlDefs.h" +#include "RemoteControlApp.h" +#include "Version.h" + +#include +#include + +IMPLEMENT_APP(CRemoteControlApp) + +const wxChar* NAME_PARAM = wxT("Name"); + +CRemoteControlApp::CRemoteControlApp() : +wxApp(), +m_name(), +m_frame(NULL), +m_config(NULL) +{ +} + +CRemoteControlApp::~CRemoteControlApp() +{ +} + +bool CRemoteControlApp::OnInit() +{ + SetVendorName(VENDOR_NAME); + + if (!wxApp::OnInit()) + return false; + + m_config = new CRemoteControlConfig(new wxConfig(APPLICATION_NAME), m_name); + + wxString frameName = APPLICATION_NAME + wxT(" - "); + if (!m_name.IsEmpty()) { + frameName.Append(m_name); + frameName.Append(wxT(" - ")); + } + frameName.Append(VERSION); + + wxPoint position = wxDefaultPosition; + + int x, y; + getPosition(x, y); + if (x >= 0 && y >= 0) + position = wxPoint(x, y); + + m_frame = new CRemoteControlFrame(frameName, position); + m_frame->Show(); + + SetTopWindow(m_frame); + + return wxApp::OnInit(); +} + +int CRemoteControlApp::OnExit() +{ + delete m_config; + + return 0; +} + +void CRemoteControlApp::OnInitCmdLine(wxCmdLineParser& parser) +{ + parser.AddParam(NAME_PARAM, wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL); + + wxApp::OnInitCmdLine(parser); +} + +bool CRemoteControlApp::OnCmdLineParsed(wxCmdLineParser& parser) +{ + if (!wxApp::OnCmdLineParsed(parser)) + return false; + + if (parser.GetParamCount() > 0U) + m_name = parser.GetParam(0U); + + return true; +} + +void CRemoteControlApp::getConfig(wxString& address, unsigned int& port, wxString& password) const +{ + m_config->getConfig(address, port, password); +} + +void CRemoteControlApp::setConfig(const wxString& address, unsigned int port, const wxString& password) const +{ + m_config->setConfig(address, port, password); +} + +void CRemoteControlApp::getPosition(int& x, int& y) const +{ + m_config->getPosition(x, y); +} + +void CRemoteControlApp::setPosition(int x, int y) +{ + m_config->setPosition(x, y); +} + +void CRemoteControlApp::repeaterRefresh(const wxString& callsign) +{ + m_frame->repeaterRefresh(callsign); +} + +void CRemoteControlApp::starNetRefresh(const wxString& callsign) +{ + m_frame->starNetRefresh(callsign); +} + +void CRemoteControlApp::link(const wxString& callsign, RECONNECT reconnect, const wxString& reflector) +{ + m_frame->link(callsign, reconnect, reflector); +} + +void CRemoteControlApp::unlink(const wxString& callsign, PROTOCOL protocol, const wxString& reflector) +{ + m_frame->unlink(callsign, protocol, reflector); +} + +void CRemoteControlApp::starNetLogoff(const wxString& callsign, const wxString& user) +{ + m_frame->starNetLogoff(callsign, user); +} diff --git a/RemoteControl/RemoteControlApp.h b/RemoteControl/RemoteControlApp.h new file mode 100644 index 0000000..6fde68e --- /dev/null +++ b/RemoteControl/RemoteControlApp.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2011,2012,2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef RemoteControlApp_H +#define RemoteControlApp_H + +#include "RemoteControlConfig.h" +#include "RemoteControlFrame.h" + +#include + +class CRemoteControlApp : public wxApp { + +public: + CRemoteControlApp(); + virtual ~CRemoteControlApp(); + + virtual bool OnInit(); + virtual int OnExit(); + + virtual void OnInitCmdLine(wxCmdLineParser& parser); + virtual bool OnCmdLineParsed(wxCmdLineParser& parser); + + virtual void getConfig(wxString& address, unsigned int& port, wxString& password) const; + virtual void setConfig(const wxString& address, unsigned int port, const wxString& password) const; + + virtual void getPosition(int& x, int& y) const; + virtual void setPosition(int x, int y); + + virtual void repeaterRefresh(const wxString& callsign); + virtual void starNetRefresh(const wxString& callsign); + virtual void link(const wxString& callsign, RECONNECT reconnect, const wxString& reflector); + virtual void unlink(const wxString& callsign, PROTOCOL protocol, const wxString& reflector); + virtual void starNetLogoff(const wxString& callsign, const wxString& user); + +private: + wxString m_name; + CRemoteControlFrame* m_frame; + CRemoteControlConfig* m_config; +}; + +DECLARE_APP(CRemoteControlApp) + +#endif diff --git a/RemoteControl/RemoteControlAppD.cpp b/RemoteControl/RemoteControlAppD.cpp new file mode 100644 index 0000000..2deea20 --- /dev/null +++ b/RemoteControl/RemoteControlAppD.cpp @@ -0,0 +1,287 @@ +/* + * Copyright (C) 2013,2014 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "RemoteControlRemoteControlHandler.h" +#include "RemoteControlConfig.h" +#include "RemoteControlDefs.h" +#include "DStarDefines.h" +#include "SHA256.h" +#include "Defs.h" + +#include + +const wxChar* NAME_OPTION = wxT("name"); +const wxChar* REPEATER_PARAM = wxT("Callsign"); +const wxChar* ACTION_PARAM = wxT("Action"); +const wxChar* RECONNECT_PARAM = wxT("Param1"); +const wxChar* REFLECTOR_PARAM = wxT("Param2"); + +void sendHash(CRemoteControlRemoteControlHandler* handler, const wxString& password, unsigned int rnd) +{ + wxASSERT(handler != NULL); + + unsigned int len = password.Len() + sizeof(unsigned int); + unsigned char* in = new unsigned char[len]; + unsigned char* out = new unsigned char[32U]; + + ::memcpy(in, &rnd, sizeof(unsigned int)); + for (unsigned int i = 0U; i < password.Len(); i++) + in[i + sizeof(unsigned int)] = password.GetChar(i); + + CSHA256 sha256; + sha256.buffer(in, len, out); + + handler->sendHash(out, 32U); + + delete[] in; + delete[] out; +} + +int main(int argc, char** argv) +{ + bool res = ::wxInitialize(); + if (!res) { + ::fprintf(stderr, "remotecontrold: failed to initialise the wxWidgets library, exiting\n"); + return -1; + } + + wxCmdLineParser parser(argc, argv); + parser.AddOption(NAME_OPTION, wxEmptyString, wxEmptyString, wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL); + parser.AddParam(REPEATER_PARAM, wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL); + parser.AddParam(ACTION_PARAM, wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL); + parser.AddParam(RECONNECT_PARAM, wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL); + parser.AddParam(REFLECTOR_PARAM, wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL); + + int cmd = parser.Parse(); + if (cmd != 0) { + ::wxUninitialize(); + return 0; + } + + wxString name; + parser.Found(NAME_OPTION, &name); + + if (parser.GetParamCount() < 2U) { + ::fprintf(stderr, "remotecontrold: invalid command line usage: remotecontrold [-name ] link \n"); + ::fprintf(stderr, " remotecontrold [-name ] unlink\n"); + ::fprintf(stderr, " remotecontrold [-name ] drop \n"); + ::fprintf(stderr, " remotecontrold [-name ] drop all\n"); + ::wxUninitialize(); + return 1; + } + + wxString repeater = parser.GetParam(0U); + repeater.Replace(wxT("_"), wxT(" ")); + repeater.resize(LONG_CALLSIGN_LENGTH, wxT(' ')); + repeater.MakeUpper(); + + wxString actionText = parser.GetParam(1U); + + wxString user; // For STARnet Digital + wxString reflector; // For linking + RECONNECT reconnect = RECONNECT_NEVER; // For linking + + if (actionText.IsSameAs(wxT("link"), false)) { + if (parser.GetParamCount() < 4U) { + ::fprintf(stderr, "remotecontrold: invalid command line usage: remotecontrold [-name ] link \n"); + ::wxUninitialize(); + return 1; + } + + wxString reconnectText = parser.GetParam(2U); + + reflector = parser.GetParam(3U); + reflector.Replace(wxT("_"), wxT(" ")); + reflector.resize(LONG_CALLSIGN_LENGTH, wxT(' ')); + reflector.MakeUpper(); + + if (reconnectText.IsSameAs(wxT("never"), false)) { + reconnect = RECONNECT_NEVER; + } else if (reconnectText.IsSameAs(wxT("fixed"), false)) { + reconnect = RECONNECT_FIXED; + } else if (reconnectText.IsSameAs(wxT("5"), false)) { + reconnect = RECONNECT_5MINS; + } else if (reconnectText.IsSameAs(wxT("10"), false)) { + reconnect = RECONNECT_10MINS; + } else if (reconnectText.IsSameAs(wxT("15"), false)) { + reconnect = RECONNECT_15MINS; + } else if (reconnectText.IsSameAs(wxT("20"), false)) { + reconnect = RECONNECT_20MINS; + } else if (reconnectText.IsSameAs(wxT("25"), false)) { + reconnect = RECONNECT_25MINS; + } else if (reconnectText.IsSameAs(wxT("30"), false)) { + reconnect = RECONNECT_30MINS; + } else if (reconnectText.IsSameAs(wxT("60"), false)) { + reconnect = RECONNECT_60MINS; + } else if (reconnectText.IsSameAs(wxT("90"), false)) { + reconnect = RECONNECT_90MINS; + } else if (reconnectText.IsSameAs(wxT("120"), false)) { + reconnect = RECONNECT_120MINS; + } else if (reconnectText.IsSameAs(wxT("180"), false)) { + reconnect = RECONNECT_180MINS; + } else { + ::fprintf(stderr, "remotecontrold: invalid reconnect value passed\n"); + ::wxUninitialize(); + return 1; + } + } else if (actionText.IsSameAs(wxT("unlink"), false)) { + reconnect = RECONNECT_NEVER; + reflector.Clear(); + } else if (actionText.IsSameAs(wxT("drop"), false)) { + if (parser.GetParamCount() < 3U) { + ::fprintf(stderr, "remotecontrold: invalid command line usage: remotecontrold [-name ] drop \n"); + ::fprintf(stderr, " remotecontrold [-name ] drop all\n"); + ::wxUninitialize(); + return 1; + } + + user = parser.GetParam(2U); + user.Replace(wxT("_"), wxT(" ")); + user.resize(LONG_CALLSIGN_LENGTH, wxT(' ')); + user.MakeUpper(); + } else { + ::fprintf(stderr, "remotecontrold: invalid action value passed, only drop, link or unlink are allowed\n"); + ::wxUninitialize(); + return 1; + } + + CRemoteControlConfig config(new wxConfig(APPLICATION_NAME), name); + + wxString address, password; + unsigned int port; + config.getConfig(address, port, password); + + if (address.IsEmpty() || port == 0U || password.IsEmpty()) { + ::fprintf(stderr, "remotecontrold: no address, port, or password is set\n"); + ::wxUninitialize(); + return 1; + } + + CRemoteControlRemoteControlHandler handler(address, port); + + bool ret = handler.open(); + if (!ret) { + ::fprintf(stderr, "remotecontrold: uanble to open the UDP port\n"); + ::wxUninitialize(); + return 1; + } + + ret = handler.login(); + if (!ret) { + handler.close(); + ::fprintf(stderr, "remotecontrold: uanble to login to the gateway/starnetserver\n"); + ::wxUninitialize(); + return 1; + } + + unsigned int count = 0U; + while (count < 10U) { + ::wxMilliSleep(100UL); + + RC_TYPE type = handler.readType(); + if (type == RCT_RANDOM) + break; + + if (type == RCT_NONE) + handler.retry(); + + count++; + } + + if (count >= 10U) { + handler.close(); + ::fprintf(stderr, "remotecontrold: unable to get a response from the gateway/starnetserver\n"); + ::wxUninitialize(); + return 1; + } + + unsigned int rnd = handler.readRandom(); + sendHash(&handler, password, rnd); + + count = 0U; + while (count < 10U) { + ::wxMilliSleep(100UL); + + RC_TYPE type = handler.readType(); + if (type == RCT_ACK) + break; + + if (type == RCT_NAK) { + handler.close(); + ::fprintf(stderr, "remotecontrold: invalid password sent to the gateway/starnetserver\n"); + ::wxUninitialize(); + return 1; + } + + if (type == RCT_NONE) + handler.retry(); + + count++; + } + + if (count >= 10U) { + handler.close(); + ::fprintf(stderr, "remotecontrold: unable to get a response from the gateway/starnetserver\n"); + ::wxUninitialize(); + return 1; + } + + handler.setLoggedIn(true); + + if (actionText.IsSameAs(wxT("drop"), false)) + handler.logoff(repeater, user); + else + handler.link(repeater, reconnect, reflector); + + count = 0U; + while (count < 10U) { + ::wxMilliSleep(100UL); + + RC_TYPE type = handler.readType(); + if (type == RCT_ACK) + break; + + if (type == RCT_NAK) { + handler.close(); + ::fprintf(stderr, "remotecontrold: drop/link/unlink command rejected by the gateway/starnetserver\n"); + ::wxUninitialize(); + return 1; + } + + if (type == RCT_NONE) + handler.retry(); + + count++; + } + + if (count >= 10U) { + handler.close(); + ::fprintf(stderr, "remotecontrold: unable to get a response from the gateway/starnetserver\n"); + ::wxUninitialize(); + return 1; + } + + ::fprintf(stdout, "remotecontrold: command accepted by the gateway/starnetserver\n"); + + handler.logout(); + handler.close(); + + ::wxUninitialize(); + + return 0; +} diff --git a/RemoteControl/RemoteControlCallsignData.cpp b/RemoteControl/RemoteControlCallsignData.cpp new file mode 100644 index 0000000..43ab9a7 --- /dev/null +++ b/RemoteControl/RemoteControlCallsignData.cpp @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2011 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "RemoteControlCallsignData.h" + +CRemoteControlCallsignData::CRemoteControlCallsignData() : +m_repeaters(), +m_starNets() +{ +} + +CRemoteControlCallsignData::~CRemoteControlCallsignData() +{ +} + +void CRemoteControlCallsignData::addRepeater(const wxString& callsign) +{ + m_repeaters.Add(callsign); +} + +void CRemoteControlCallsignData::addStarNet(const wxString& callsign) +{ + m_starNets.Add(callsign); +} + +unsigned int CRemoteControlCallsignData::getRepeaterCount() const +{ + return m_repeaters.GetCount(); +} + +wxString CRemoteControlCallsignData::getRepeater(unsigned int n) const +{ + return m_repeaters.Item(n); +} + +unsigned int CRemoteControlCallsignData::getStarNetCount() const +{ + return m_starNets.GetCount(); +} + +wxString CRemoteControlCallsignData::getStarNet(unsigned int n) const +{ + return m_starNets.Item(n); +} diff --git a/RemoteControl/RemoteControlCallsignData.h b/RemoteControl/RemoteControlCallsignData.h new file mode 100644 index 0000000..737f603 --- /dev/null +++ b/RemoteControl/RemoteControlCallsignData.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2011 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef RemoteControlCallsignData_H +#define RemoteControlCallsignData_H + +#include + +class CRemoteControlCallsignData { +public: + CRemoteControlCallsignData(); + ~CRemoteControlCallsignData(); + + void addRepeater(const wxString& callsign); + void addStarNet(const wxString& callsign); + + unsigned int getRepeaterCount() const; + unsigned int getStarNetCount() const; + + wxString getRepeater(unsigned int n) const; + wxString getStarNet(unsigned int n) const; + +private: + wxArrayString m_repeaters; + wxArrayString m_starNets; +}; + +#endif diff --git a/RemoteControl/RemoteControlConfig.cpp b/RemoteControl/RemoteControlConfig.cpp new file mode 100644 index 0000000..b07ae89 --- /dev/null +++ b/RemoteControl/RemoteControlConfig.cpp @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2011,2012 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "RemoteControlConfig.h" + +const wxString KEY_ADDRESS = wxT("/address"); +const wxString KEY_PORT = wxT("/port"); +const wxString KEY_PASSWORD = wxT("/password"); +const wxString KEY_WINDOW_X = wxT("/windowX"); +const wxString KEY_WINDOW_Y = wxT("/windowY"); + +const wxString DEFAULT_ADDRESS = wxEmptyString; +const long DEFAULT_PORT = 0L; +const wxString DEFAULT_PASSWORD = wxEmptyString; +const long DEFAULT_WINDOW_X = -1L; +const long DEFAULT_WINDOW_Y = -1L; + + +CRemoteControlConfig::CRemoteControlConfig(wxConfigBase* config, const wxString& name) : +m_config(config), +m_name() +{ + wxASSERT(config != NULL); + + if (!name.IsEmpty()) + m_name = wxT("/") + name; +} + +CRemoteControlConfig::~CRemoteControlConfig() +{ + delete m_config; +} + +void CRemoteControlConfig::getConfig(wxString& address, unsigned int& port, wxString& password) const +{ + wxString addressKey = m_name + KEY_ADDRESS; + wxString portKey = m_name + KEY_PORT; + wxString passwordKey = m_name + KEY_PASSWORD; + + m_config->Read(addressKey, &address, DEFAULT_ADDRESS); + + long temp; + m_config->Read(portKey, &temp, DEFAULT_PORT); + port = (unsigned int)temp; + + m_config->Read(passwordKey, &password, DEFAULT_PASSWORD); +} + +void CRemoteControlConfig::setConfig(const wxString& address, unsigned int port, const wxString& password) const +{ + wxString addressKey = m_name + KEY_ADDRESS; + wxString portKey = m_name + KEY_PORT; + wxString passwordKey = m_name + KEY_PASSWORD; + + m_config->Write(addressKey, address); + m_config->Write(portKey, long(port)); + m_config->Write(passwordKey, password); + m_config->Flush(); +} + + +void CRemoteControlConfig::getPosition(int& x, int& y) const +{ + wxString xKey = m_name + KEY_WINDOW_X; + wxString yKey = m_name + KEY_WINDOW_Y; + + long temp; + m_config->Read(xKey, &temp, DEFAULT_WINDOW_X); + x = (unsigned int)temp; + + m_config->Read(yKey, &temp, DEFAULT_WINDOW_Y); + y = (unsigned int)temp; +} + +void CRemoteControlConfig::setPosition(int x, int y) +{ + wxString xKey = m_name + KEY_WINDOW_X; + wxString yKey = m_name + KEY_WINDOW_Y; + + m_config->Write(xKey, long(x)); + m_config->Write(yKey, long(y)); + m_config->Flush(); +} diff --git a/RemoteControl/RemoteControlConfig.h b/RemoteControl/RemoteControlConfig.h new file mode 100644 index 0000000..238dd80 --- /dev/null +++ b/RemoteControl/RemoteControlConfig.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2011,2012 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef RemoteControlConfig_H +#define RemoteControlConfig_H + +#include +#include + +class CRemoteControlConfig { + +public: + CRemoteControlConfig(wxConfigBase* config, const wxString& name); + ~CRemoteControlConfig(); + + void getConfig(wxString& address, unsigned int& port, wxString& password) const; + void setConfig(const wxString& address, unsigned int port, const wxString& password) const; + + void getPosition(int& x, int& y) const; + void setPosition(int x, int y); + +private: + wxConfigBase* m_config; + wxString m_name; +}; + +#endif diff --git a/RemoteControl/RemoteControlDefs.h b/RemoteControl/RemoteControlDefs.h new file mode 100644 index 0000000..dfffaa9 --- /dev/null +++ b/RemoteControl/RemoteControlDefs.h @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2011 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef RemoteControlDefs_H +#define RemoteControlDefs_H + +#include + +const wxString APPLICATION_NAME = wxT("Remote Control"); + +const wxString CONFIG_FILE_NAME = wxT(".Remote Control"); + +#endif diff --git a/RemoteControl/RemoteControlFrame.cpp b/RemoteControl/RemoteControlFrame.cpp new file mode 100644 index 0000000..8403851 --- /dev/null +++ b/RemoteControl/RemoteControlFrame.cpp @@ -0,0 +1,348 @@ +/* + * Copyright (C) 2011-2015 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "RemoteControlPreferences.h" +#include "RemoteControlFrame.h" +#include "RemoteControlDefs.h" +#include "RemoteControlApp.h" +#include "Version.h" +#include "SHA256.h" + +const unsigned int BORDER_SIZE = 5U; + +#if defined(__WINDOWS__) +const unsigned int MAIN_HEIGHT = 350U; +const unsigned int MAIN_WIDTH = 500U; +#else +const unsigned int MAIN_HEIGHT = 350U; +const unsigned int MAIN_WIDTH = 520U; +#endif + +#include + +enum { + Menu_Edit_Preferences = 7000 +}; + +BEGIN_EVENT_TABLE(CRemoteControlFrame, wxFrame) + EVT_MENU(wxID_EXIT, CRemoteControlFrame::onQuit) + EVT_MENU(Menu_Edit_Preferences, CRemoteControlFrame::onPreferences) + EVT_MENU(wxID_ABOUT, CRemoteControlFrame::onAbout) + + EVT_TIMER(-1, CRemoteControlFrame::onTimer) + + EVT_CLOSE(CRemoteControlFrame::onClose) +END_EVENT_TABLE() + +CRemoteControlFrame::CRemoteControlFrame(const wxString& title, const wxPoint& position) : +wxFrame(NULL, -1, title, position), +m_state(RCFS_NORMAL), +m_timer(this), +m_noteBook(NULL), +m_handler(NULL), +m_password(), +m_repeaters(), +m_starNets(), +m_it1(), +m_it2() +{ + SetMenuBar(createMenuBar()); + + wxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL); + + wxPanel* panel = new wxPanel(this, -1); + + wxBoxSizer* panelSizer = new wxBoxSizer(wxVERTICAL); + + m_noteBook = new wxNotebook(panel, -1, wxDefaultPosition, wxSize(MAIN_WIDTH, MAIN_HEIGHT)); + panelSizer->Add(m_noteBook, 0, wxALL | wxGROW, BORDER_SIZE); + + panel->SetSizer(panelSizer); + + panelSizer->SetSizeHints(panel); + + mainSizer->Add(panel); + + SetSizer(mainSizer); + mainSizer->SetSizeHints(this); + + wxString address; + unsigned int port; + ::wxGetApp().getConfig(address, port, m_password); + + if (address.IsEmpty() || port == 0U || m_password.IsEmpty()) + return; + + m_handler = new CRemoteControlRemoteControlHandler(address, port); + + bool ret = m_handler->open(); + if (!ret) { + delete m_handler; + m_handler = NULL; + return; + } + + ret = m_handler->login(); + if (!ret) { + m_handler->close(); + delete m_handler; + m_handler = NULL; + return; + } + + m_state = RCFS_LOGIN; + + m_timer.Start(100); +} + +CRemoteControlFrame::~CRemoteControlFrame() +{ +} + +wxMenuBar* CRemoteControlFrame::createMenuBar() +{ + wxMenu* fileMenu = new wxMenu(); + fileMenu->Append(wxID_EXIT, _("Exit")); + + wxMenu* editMenu = new wxMenu(); + editMenu->Append(Menu_Edit_Preferences, _("Preferences...")); + + wxMenu* helpMenu = new wxMenu(); + helpMenu->Append(wxID_ABOUT, _("About Remote Control")); + + wxMenuBar* menuBar = new wxMenuBar(); + menuBar->Append(fileMenu, _("File")); + menuBar->Append(editMenu, _("Edit")); + menuBar->Append(helpMenu, _("Help")); + + return menuBar; +} + +void CRemoteControlFrame::onQuit(wxCommandEvent&) +{ + Close(false); +} + +void CRemoteControlFrame::onClose(wxCloseEvent&) +{ + int x, y; + GetPosition(&x, &y); + if (x >= 0 && y >= 0) + ::wxGetApp().setPosition(x, y); + + m_timer.Stop(); + + if (m_handler != NULL) { + m_handler->logout(); + m_handler->close(); + } + + Destroy(); +} + +void CRemoteControlFrame::onPreferences(wxCommandEvent&) +{ + wxString address, password; + unsigned int port; + ::wxGetApp().getConfig(address, port, password); + + CRemoteControlPreferences dialog1(this, -1, address, port, password); + if (dialog1.ShowModal() != wxID_OK) + return; + + address = dialog1.getAddress(); + port = dialog1.getPort(); + password = dialog1.getPassword(); + + ::wxGetApp().setConfig(address, port, password); + + wxMessageDialog dialog2(this, _("The changes made will not take effect\nuntil the application is restarted"), _("Remote Control Information"), wxICON_INFORMATION); + dialog2.ShowModal(); +} + +void CRemoteControlFrame::onAbout(wxCommandEvent&) +{ + wxAboutDialogInfo info; + info.AddDeveloper(wxT("Jonathan Naylor, G4KLX")); + info.SetCopyright(wxT("(C) 2011-2015 using GPL v2 or later")); + info.SetName(APPLICATION_NAME); + info.SetVersion(VERSION); + info.SetDescription(_("This program allows for the controlling of\nircDDB Gateway and STARnet Digital Server.")); + + ::wxAboutBox(info); +} + +void CRemoteControlFrame::onTimer(wxTimerEvent&) +{ + RC_TYPE type = m_handler->readType(); + + switch (type) { + case RCT_NONE: + m_handler->retry(); + break; + + case RCT_ACK: + if (m_state == RCFS_HASH) { + m_handler->setLoggedIn(true); + m_handler->getCallsigns(); + m_state = RCFS_NORMAL; + } + break; + + case RCT_NAK: { + if (m_state == RCFS_HASH || m_state == RCFS_LOGIN) + m_handler->setLoggedIn(false); + + wxString text = m_handler->readNAK(); + m_state = RCFS_NORMAL; + ::wxMessageBox(text); + } + break; + + case RCT_RANDOM: { + unsigned int rnd = m_handler->readRandom(); + sendHash(rnd); + m_state = RCFS_HASH; + } + break; + + case RCT_CALLSIGNS: { + m_noteBook->DeleteAllPages(); + + CRemoteControlCallsignData* data = m_handler->readCallsigns(); + for (unsigned int i = 0U; i < data->getRepeaterCount(); i++) + addRepeater(data->getRepeater(i)); + for (unsigned int i = 0U; i < data->getStarNetCount(); i++) + addStarNet(data->getStarNet(i)); + delete data; + + m_state = RCFS_GET_REPEATERS; + m_it1 = m_repeaters.begin(); + m_it2 = m_starNets.begin(); + getNextRepeater(); + } + break; + + case RCT_REPEATER: { + CRemoteControlRepeaterData* data = m_handler->readRepeater(); + wxString callsign = data->getCallsign(); + m_repeaters[callsign]->add(*data); + delete data; + + if (m_state == RCFS_GET_REPEATERS || m_state == RCFS_GET_STARNETS) + getNextRepeater(); + } + break; + + case RCT_STARNET: { + CRemoteControlStarNetGroup* data = m_handler->readStarNetGroup(); + wxString callsign = data->getCallsign(); + m_starNets[callsign]->add(*data); + delete data; + + if (m_state == RCFS_GET_REPEATERS || m_state == RCFS_GET_STARNETS) + getNextStarNet(); + } + break; + } +} + +void CRemoteControlFrame::addRepeater(const wxString& callsign) +{ + CRemoteControlRepeaterPanel* repeater = new CRemoteControlRepeaterPanel(m_noteBook, -1, callsign); + + m_noteBook->AddPage(repeater, callsign, false); + + m_repeaters[callsign] = repeater; +} + +void CRemoteControlFrame::addStarNet(const wxString& callsign) +{ + CRemoteControlStarNetPanel* starNet = new CRemoteControlStarNetPanel(m_noteBook, -1, callsign); + + m_noteBook->AddPage(starNet, callsign, false); + + m_starNets[callsign] = starNet; +} + +void CRemoteControlFrame::repeaterRefresh(const wxString& callsign) +{ + m_handler->getRepeater(callsign); +} + +void CRemoteControlFrame::starNetRefresh(const wxString& callsign) +{ + m_handler->getStarNet(callsign); +} + +void CRemoteControlFrame::link(const wxString& callsign, RECONNECT reconnect, const wxString& reflector) +{ + m_handler->link(callsign, reconnect, reflector); +} + +void CRemoteControlFrame::unlink(const wxString& callsign, PROTOCOL protocol, const wxString& reflector) +{ + m_handler->unlink(callsign, protocol, reflector); +} + +void CRemoteControlFrame::starNetLogoff(const wxString& callsign, const wxString& user) +{ + m_handler->logoff(callsign, user); +} + +void CRemoteControlFrame::sendHash(unsigned int rnd) +{ + unsigned int len = m_password.Len() + sizeof(unsigned int); + unsigned char* in = new unsigned char[len]; + unsigned char* out = new unsigned char[32U]; + + ::memcpy(in, &rnd, sizeof(unsigned int)); + for (unsigned int i = 0U; i < m_password.Len(); i++) + in[i + sizeof(unsigned int)] = m_password.GetChar(i); + + CSHA256 sha256; + sha256.buffer(in, len, out); + + m_handler->sendHash(out, 32U); + + delete[] in; + delete[] out; +} + +void CRemoteControlFrame::getNextRepeater() +{ + if (m_it1 == m_repeaters.end()) { + m_state = RCFS_GET_STARNETS; + getNextStarNet(); + return; + } + + m_handler->getRepeater(m_it1->first); + ++m_it1; +} + +void CRemoteControlFrame::getNextStarNet() +{ + if (m_it2 == m_starNets.end()) { + m_state = RCFS_NORMAL; + return; + } + + m_handler->getStarNet(m_it2->first); + ++m_it2; +} diff --git a/RemoteControl/RemoteControlFrame.h b/RemoteControl/RemoteControlFrame.h new file mode 100644 index 0000000..c145c39 --- /dev/null +++ b/RemoteControl/RemoteControlFrame.h @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2011,2012,2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef RemoteControlFrame_H +#define RemoteControlFrame_H + +#include "RemoteControlRemoteControlHandler.h" +#include "RemoteControlRepeaterPanel.h" +#include "RemoteControlStarNetPanel.h" +#include "Defs.h" + +#include +#include + +WX_DECLARE_STRING_HASH_MAP(CRemoteControlRepeaterPanel*, CRepeater_t); +WX_DECLARE_STRING_HASH_MAP(CRemoteControlStarNetPanel*, CStarNet_t); + +enum RCF_STATE { + RCFS_NORMAL, + RCFS_LOGIN, + RCFS_HASH, + RCFS_GET_REPEATERS, + RCFS_GET_STARNETS +}; + +class CRemoteControlFrame : public wxFrame { +public: + CRemoteControlFrame(const wxString& title, const wxPoint& position); + virtual ~CRemoteControlFrame(); + + virtual void onQuit(wxCommandEvent& event); + virtual void onPreferences(wxCommandEvent& event); + virtual void onAbout(wxCommandEvent& event); + virtual void onClose(wxCloseEvent& event); + virtual void onTimer(wxTimerEvent& event); + + virtual void repeaterRefresh(const wxString& callsign); + virtual void starNetRefresh(const wxString& callsign); + virtual void link(const wxString& callsign, RECONNECT reconnect, const wxString& reflector); + virtual void unlink(const wxString& callsign, PROTOCOL protocol, const wxString& reflector); + virtual void starNetLogoff(const wxString& callsign, const wxString& user); + +private: + RCF_STATE m_state; + wxTimer m_timer; + wxNotebook* m_noteBook; + CRemoteControlRemoteControlHandler* m_handler; + wxString m_password; + CRepeater_t m_repeaters; + CStarNet_t m_starNets; + CRepeater_t::iterator m_it1; + CStarNet_t::iterator m_it2; + + DECLARE_EVENT_TABLE() + + wxMenuBar* createMenuBar(); + void addRepeater(const wxString& callsign); + void addStarNet(const wxString& callsign); + void sendHash(unsigned int rnd); + void getNextRepeater(); + void getNextStarNet(); +}; + +#endif diff --git a/RemoteControl/RemoteControlLinkData.cpp b/RemoteControl/RemoteControlLinkData.cpp new file mode 100644 index 0000000..ed274b9 --- /dev/null +++ b/RemoteControl/RemoteControlLinkData.cpp @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2011 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "RemoteControlLinkData.h" + +CRemoteControlLinkData::CRemoteControlLinkData(const wxString& callsign, wxInt32 protocol, wxInt32 linked, wxInt32 direction, wxInt32 dongle) : +m_callsign(callsign), +m_protocol(PROTOCOL(protocol)), +m_linked(false), +m_direction(DIRECTION(direction)), +m_dongle(false) +{ + m_linked = linked == 1; + m_dongle = dongle == 1; +} + +CRemoteControlLinkData::~CRemoteControlLinkData() +{ +} + +wxString CRemoteControlLinkData::getCallsign() const +{ + return m_callsign; +} + +PROTOCOL CRemoteControlLinkData::getProtocol() const +{ + return m_protocol; +} + +bool CRemoteControlLinkData::isLinked() const +{ + return m_linked; +} + +DIRECTION CRemoteControlLinkData::getDirection() const +{ + return m_direction; +} + +bool CRemoteControlLinkData::isDongle() const +{ + return m_dongle; +} diff --git a/RemoteControl/RemoteControlLinkData.h b/RemoteControl/RemoteControlLinkData.h new file mode 100644 index 0000000..8d69016 --- /dev/null +++ b/RemoteControl/RemoteControlLinkData.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2011 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef RemoteControlLinkData_H +#define RemoteControlLinkData_H + +#include "Defs.h" + +#include + +class CRemoteControlLinkData { +public: + CRemoteControlLinkData(const wxString& callsign, wxInt32 protocol, wxInt32 linked, wxInt32 direction, wxInt32 dongle); + ~CRemoteControlLinkData(); + + wxString getCallsign() const; + PROTOCOL getProtocol() const; + bool isLinked() const; + DIRECTION getDirection() const; + bool isDongle() const; + +private: + wxString m_callsign; + PROTOCOL m_protocol; + bool m_linked; + DIRECTION m_direction; + bool m_dongle; +}; + +#endif diff --git a/RemoteControl/RemoteControlPreferences.cpp b/RemoteControl/RemoteControlPreferences.cpp new file mode 100644 index 0000000..6b35889 --- /dev/null +++ b/RemoteControl/RemoteControlPreferences.cpp @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2011 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "RemoteControlPreferences.h" +#include "RemoteControlDefs.h" + +const unsigned int BORDER_SIZE = 5U; + +CRemoteControlPreferences::CRemoteControlPreferences(wxWindow* parent, int id, const wxString& address, unsigned int port, const wxString& password) : +wxDialog(parent, id, wxString(_("Remote Control Preferences"))), +m_remote(NULL) +{ + wxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL); + + wxNotebook* noteBook = new wxNotebook(this, -1); + + m_remote = new CRemoteControlRemoteSet(noteBook, -1, APPLICATION_NAME, address, port, password); + noteBook->AddPage(m_remote, _("Gateway"), true); + + mainSizer->Add(noteBook, 1, wxALL | wxGROW, BORDER_SIZE); + + mainSizer->Add(CreateButtonSizer(wxOK | wxCANCEL), 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + SetAutoLayout(true); + Layout(); + + mainSizer->Fit(this); + mainSizer->SetSizeHints(this); + + SetSizer(mainSizer); +} + +CRemoteControlPreferences::~CRemoteControlPreferences() +{ +} + +bool CRemoteControlPreferences::Validate() +{ + return m_remote->Validate(); +} + +wxString CRemoteControlPreferences::getAddress() const +{ + return m_remote->getAddress(); +} + +unsigned int CRemoteControlPreferences::getPort() const +{ + return m_remote->getPort(); +} + +wxString CRemoteControlPreferences::getPassword() const +{ + return m_remote->getPassword(); +} diff --git a/RemoteControl/RemoteControlPreferences.h b/RemoteControl/RemoteControlPreferences.h new file mode 100644 index 0000000..a4c6ce6 --- /dev/null +++ b/RemoteControl/RemoteControlPreferences.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2011 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef RemoteControlPreferences_H +#define RemoteControlPreferences_H + +#include +#include + +#include "RemoteControlRemoteSet.h" + +class CRemoteControlPreferences : public wxDialog { +public: + CRemoteControlPreferences(wxWindow* parent, int id, const wxString& address, unsigned int port, const wxString& password); + virtual ~CRemoteControlPreferences(); + + virtual bool Validate(); + + virtual wxString getAddress() const; + virtual unsigned int getPort() const; + virtual wxString getPassword() const; + +private: + CRemoteControlRemoteSet* m_remote; +}; + +#endif diff --git a/RemoteControl/RemoteControlRemoteControlHandler.cpp b/RemoteControl/RemoteControlRemoteControlHandler.cpp new file mode 100644 index 0000000..2719812 --- /dev/null +++ b/RemoteControl/RemoteControlRemoteControlHandler.cpp @@ -0,0 +1,557 @@ +/* + * Copyright (C) 2011,2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "RemoteControlRemoteControlHandler.h" +#include "DStarDefines.h" + +const unsigned int BUFFER_LENGTH = 2000U; + +const unsigned int MAX_RETRIES = 3U; + +CRemoteControlRemoteControlHandler::CRemoteControlRemoteControlHandler(const wxString& address, unsigned int port) : +m_socket(wxEmptyString, 0U), +m_address(), +m_port(port), +m_loggedIn(false), +m_retryCount(0U), +m_type(RCT_NONE), +m_inBuffer(NULL), +m_inLength(0U), +m_outBuffer(NULL), +m_outLength(0U) +{ + wxASSERT(!address.IsEmpty()); + wxASSERT(port > 0U); + + m_address = CUDPReaderWriter::lookup(address); + + m_inBuffer = new unsigned char[BUFFER_LENGTH]; + m_outBuffer = new unsigned char[BUFFER_LENGTH]; +} + +CRemoteControlRemoteControlHandler::~CRemoteControlRemoteControlHandler() +{ + delete[] m_inBuffer; + delete[] m_outBuffer; +} + +bool CRemoteControlRemoteControlHandler::open() +{ + return m_socket.open(); +} + +RC_TYPE CRemoteControlRemoteControlHandler::readType() +{ + m_type = RCT_NONE; + + in_addr address; + unsigned int port; + + int length = m_socket.read(m_inBuffer, BUFFER_LENGTH, address, port); + if (length <= 0) + return m_type; + + m_inLength = length; + + if (::memcmp(m_inBuffer, "ACK", 3U) == 0) { + m_retryCount = 0U; + m_type = RCT_ACK; + return m_type; + } else if (::memcmp(m_inBuffer, "NAK", 3U) == 0) { + m_retryCount = 0U; + m_type = RCT_NAK; + return m_type; + } else if (::memcmp(m_inBuffer, "RND", 3U) == 0) { + m_retryCount = 0U; + m_type = RCT_RANDOM; + return m_type; + } else if (::memcmp(m_inBuffer, "CAL", 3U) == 0) { + m_retryCount = 0U; + m_type = RCT_CALLSIGNS; + return m_type; + } else if (::memcmp(m_inBuffer, "RPT", 3U) == 0) { + m_retryCount = 0U; + m_type = RCT_REPEATER; + return m_type; + } else if (::memcmp(m_inBuffer, "SNT", 3U) == 0) { + m_retryCount = 0U; + m_type = RCT_STARNET; + return m_type; + } + + return m_type; +} + +wxString CRemoteControlRemoteControlHandler::readNAK() +{ + if (m_type != RCT_NAK) + return wxEmptyString; + + wxString text((char*)(m_inBuffer + 3U), wxConvLocal); + + return text; +} + +unsigned int CRemoteControlRemoteControlHandler::readRandom() +{ + if (m_type != RCT_RANDOM) + return 0U; + + wxUint32 random; + ::memcpy(&random, m_inBuffer + 3U, sizeof(wxUint32)); + + return wxUINT32_SWAP_ON_BE(random); +} + +CRemoteControlCallsignData* CRemoteControlRemoteControlHandler::readCallsigns() +{ + if (m_type != RCT_CALLSIGNS) + return NULL; + + CRemoteControlCallsignData* data = new CRemoteControlCallsignData; + + unsigned char* p = m_inBuffer + 3U; + unsigned int pos = 3U; + + while (pos < m_inLength) { + unsigned char type = *p; + pos += 1U; + p += 1U; + + wxString callsign((char*)p, wxConvLocal, LONG_CALLSIGN_LENGTH); + pos += LONG_CALLSIGN_LENGTH; + p += LONG_CALLSIGN_LENGTH; + + switch (type) { + case 'R': + data->addRepeater(callsign); + break; + case 'S': + data->addStarNet(callsign); + break; + default: // ???? + break; + } + } + + return data; +} + +CRemoteControlRepeaterData* CRemoteControlRemoteControlHandler::readRepeater() +{ + if (m_type != RCT_REPEATER) + return NULL; + + unsigned char* p = m_inBuffer + 3U; + unsigned int pos = 3U; + + wxString callsign((char*)p, wxConvLocal, LONG_CALLSIGN_LENGTH); + pos += LONG_CALLSIGN_LENGTH; + p += LONG_CALLSIGN_LENGTH; + + wxInt32 reconnect; + ::memcpy(&reconnect, p, sizeof(wxInt32)); + pos += sizeof(wxInt32); + p += sizeof(wxInt32); + + wxString reflector((char*)p, wxConvLocal, LONG_CALLSIGN_LENGTH); + pos += LONG_CALLSIGN_LENGTH; + p += LONG_CALLSIGN_LENGTH; + + CRemoteControlRepeaterData* data = new CRemoteControlRepeaterData(callsign, wxINT32_SWAP_ON_BE(reconnect), reflector); + + while (pos < m_inLength) { + wxString callsign((char*)p, wxConvLocal, LONG_CALLSIGN_LENGTH); + pos += LONG_CALLSIGN_LENGTH; + p += LONG_CALLSIGN_LENGTH; + + wxInt32 protocol; + ::memcpy(&protocol, p, sizeof(wxInt32)); + pos += sizeof(wxInt32); + p += sizeof(wxInt32); + + wxInt32 linked; + ::memcpy(&linked, p, sizeof(wxInt32)); + pos += sizeof(wxInt32); + p += sizeof(wxInt32); + + wxInt32 direction; + ::memcpy(&direction, p, sizeof(wxInt32)); + pos += sizeof(wxInt32); + p += sizeof(wxInt32); + + wxInt32 dongle; + ::memcpy(&dongle, p, sizeof(wxInt32)); + pos += sizeof(wxInt32); + p += sizeof(wxInt32); + + data->addLink(callsign, wxINT32_SWAP_ON_BE(protocol), wxINT32_SWAP_ON_BE(linked), wxINT32_SWAP_ON_BE(direction), wxINT32_SWAP_ON_BE(dongle)); + } + + return data; +} + +CRemoteControlStarNetGroup* CRemoteControlRemoteControlHandler::readStarNetGroup() +{ + if (m_type != RCT_STARNET) + return NULL; + + unsigned char* p = m_inBuffer + 3U; + unsigned int pos = 3U; + + wxString callsign((char*)p, wxConvLocal, LONG_CALLSIGN_LENGTH); + pos += LONG_CALLSIGN_LENGTH; + p += LONG_CALLSIGN_LENGTH; + + wxString logoff((char*)p, wxConvLocal, LONG_CALLSIGN_LENGTH); + pos += LONG_CALLSIGN_LENGTH; + p += LONG_CALLSIGN_LENGTH; + + wxUint32 timer; + ::memcpy(&timer, p, sizeof(wxUint32)); + pos += sizeof(wxUint32); + p += sizeof(wxUint32); + + wxUint32 timeout; + ::memcpy(&timeout, p, sizeof(wxUint32)); + pos += sizeof(wxUint32); + p += sizeof(wxUint32); + + CRemoteControlStarNetGroup* group = new CRemoteControlStarNetGroup(callsign, logoff, wxUINT32_SWAP_ON_BE(timer), wxUINT32_SWAP_ON_BE(timeout)); + + while (pos < m_inLength) { + wxString callsign((char*)p, wxConvLocal, LONG_CALLSIGN_LENGTH); + pos += LONG_CALLSIGN_LENGTH; + p += LONG_CALLSIGN_LENGTH; + + ::memcpy(&timer, p, sizeof(wxUint32)); + pos += sizeof(wxUint32); + p += sizeof(wxUint32); + + ::memcpy(&timeout, p, sizeof(wxUint32)); + pos += sizeof(wxUint32); + p += sizeof(wxUint32); + + group->addUser(callsign, wxUINT32_SWAP_ON_BE(timer), wxUINT32_SWAP_ON_BE(timeout)); + } + + return group; +} + +bool CRemoteControlRemoteControlHandler::login() +{ + if (m_loggedIn) + return false; + + if (m_address.s_addr == INADDR_NONE) + return false; + + ::memcpy(m_outBuffer, "LIN", 3U); + m_outLength = 3U; + + bool ret = m_socket.write(m_outBuffer, m_outLength, m_address, m_port); + if (!ret) { + m_retryCount = 0U; + return false; + } else { + m_retryCount = 1U; + return true; + } +} + +void CRemoteControlRemoteControlHandler::setLoggedIn(bool set) +{ + m_loggedIn = set; +} + +bool CRemoteControlRemoteControlHandler::getCallsigns() +{ + if (!m_loggedIn || m_retryCount > 0U) + return false; + + ::memcpy(m_outBuffer, "GCS", 3U); + m_outLength = 3U; + + bool ret = m_socket.write(m_outBuffer, m_outLength, m_address, m_port); + if (!ret) { + m_retryCount = 0U; + return false; + } else { + m_retryCount = 1U; + return true; + } +} + +bool CRemoteControlRemoteControlHandler::sendHash(const unsigned char* hash, unsigned int length) +{ + wxASSERT(hash != NULL); + wxASSERT(length > 0U); + + if (m_loggedIn || m_retryCount > 0U) + return false; + + unsigned char* p = m_outBuffer; + m_outLength = 0U; + + ::memcpy(p, "SHA", 3U); + m_outLength += 3U; + p += 3U; + + ::memcpy(p, hash, length); + m_outLength += length; + p += length; + + bool ret = m_socket.write(m_outBuffer, m_outLength, m_address, m_port); + if (!ret) { + m_retryCount = 0U; + return false; + } else { + m_retryCount = 1U; + return true; + } +} + +bool CRemoteControlRemoteControlHandler::getRepeater(const wxString& callsign) +{ + wxASSERT(!callsign.IsEmpty()); + + if (!m_loggedIn || m_retryCount > 0U) + return false; + + unsigned char* p = m_outBuffer; + m_outLength = 0U; + + ::memcpy(p, "GRP", 3U); + m_outLength += 3U; + p += 3U; + + ::memset(p, ' ', LONG_CALLSIGN_LENGTH); + for (unsigned int i = 0U; i < callsign.Len(); i++) + p[i] = callsign.GetChar(i); + + m_outLength += LONG_CALLSIGN_LENGTH; + p += LONG_CALLSIGN_LENGTH; + + bool ret = m_socket.write(m_outBuffer, m_outLength, m_address, m_port); + if (!ret) { + m_retryCount = 0U; + return false; + } else { + m_retryCount = 1U; + return true; + } +} + +bool CRemoteControlRemoteControlHandler::getStarNet(const wxString& callsign) +{ + wxASSERT(!callsign.IsEmpty()); + + if (!m_loggedIn || m_retryCount > 0U) + return false; + + unsigned char* p = m_outBuffer; + m_outLength = 0U; + + ::memcpy(p, "GSN", 3U); + m_outLength += 3U; + p += 3U; + + ::memset(p, ' ', LONG_CALLSIGN_LENGTH); + for (unsigned int i = 0U; i < callsign.Len(); i++) + p[i] = callsign.GetChar(i); + + m_outLength += LONG_CALLSIGN_LENGTH; + p += LONG_CALLSIGN_LENGTH; + + bool ret = m_socket.write(m_outBuffer, m_outLength, m_address, m_port); + if (!ret) { + m_retryCount = 0U; + return false; + } else { + m_retryCount = 1U; + return true; + } +} + +bool CRemoteControlRemoteControlHandler::link(const wxString& callsign, RECONNECT reconnect, const wxString& reflector) +{ + wxASSERT(!callsign.IsEmpty()); + + if (!m_loggedIn || m_retryCount > 0U) + return false; + + unsigned char* p = m_outBuffer; + m_outLength = 0U; + + ::memcpy(p, "LNK", 3U); + m_outLength += 3U; + p += 3U; + + ::memset(p, ' ', LONG_CALLSIGN_LENGTH); + for (unsigned int i = 0U; i < callsign.Len(); i++) + p[i] = callsign.GetChar(i); + + m_outLength += LONG_CALLSIGN_LENGTH; + p += LONG_CALLSIGN_LENGTH; + + wxInt32 temp1 = wxInt32(reconnect); + wxInt32 temp2 = wxINT32_SWAP_ON_BE(temp1); + ::memcpy(p, &temp2, sizeof(wxInt32)); + m_outLength += sizeof(wxInt32); + p += sizeof(wxInt32); + + ::memset(p, ' ', LONG_CALLSIGN_LENGTH); + for (unsigned int i = 0U; i < reflector.Len(); i++) + p[i] = reflector.GetChar(i); + + m_outLength += LONG_CALLSIGN_LENGTH; + p += LONG_CALLSIGN_LENGTH; + + bool ret = m_socket.write(m_outBuffer, m_outLength, m_address, m_port); + if (!ret) { + m_retryCount = 0U; + return false; + } else { + m_retryCount = 1U; + return true; + } +} + +bool CRemoteControlRemoteControlHandler::unlink(const wxString& callsign, PROTOCOL protocol, const wxString& reflector) +{ + wxASSERT(!callsign.IsEmpty()); + + if (!m_loggedIn || m_retryCount > 0U) + return false; + + unsigned char* p = m_outBuffer; + m_outLength = 0U; + + ::memcpy(p, "UNL", 3U); + m_outLength += 3U; + p += 3U; + + ::memset(p, ' ', LONG_CALLSIGN_LENGTH); + for (unsigned int i = 0U; i < callsign.Len(); i++) + p[i] = callsign.GetChar(i); + + m_outLength += LONG_CALLSIGN_LENGTH; + p += LONG_CALLSIGN_LENGTH; + + wxInt32 temp1 = wxInt32(protocol); + wxInt32 temp2 = wxINT32_SWAP_ON_BE(temp1); + ::memcpy(p, &temp2, sizeof(wxInt32)); + m_outLength += sizeof(wxInt32); + p += sizeof(wxInt32); + + ::memset(p, ' ', LONG_CALLSIGN_LENGTH); + for (unsigned int i = 0U; i < reflector.Len(); i++) + p[i] = reflector.GetChar(i); + + m_outLength += LONG_CALLSIGN_LENGTH; + p += LONG_CALLSIGN_LENGTH; + + bool ret = m_socket.write(m_outBuffer, m_outLength, m_address, m_port); + if (!ret) { + m_retryCount = 0U; + return false; + } else { + m_retryCount = 1U; + return true; + } +} + +bool CRemoteControlRemoteControlHandler::logoff(const wxString& callsign, const wxString& user) +{ + wxASSERT(!callsign.IsEmpty()); + wxASSERT(!user.IsEmpty()); + + if (!m_loggedIn || m_retryCount > 0U) + return false; + + unsigned char* p = m_outBuffer; + m_outLength = 0U; + + ::memcpy(p, "LGO", 3U); + m_outLength += 3U; + p += 3U; + + ::memset(p, ' ', LONG_CALLSIGN_LENGTH); + for (unsigned int i = 0U; i < callsign.Len(); i++) + p[i] = callsign.GetChar(i); + + m_outLength += LONG_CALLSIGN_LENGTH; + p += LONG_CALLSIGN_LENGTH; + + ::memset(p, ' ', LONG_CALLSIGN_LENGTH); + for (unsigned int i = 0U; i < user.Len(); i++) + p[i] = user.GetChar(i); + + m_outLength += LONG_CALLSIGN_LENGTH; + p += LONG_CALLSIGN_LENGTH; + + bool ret = m_socket.write(m_outBuffer, m_outLength, m_address, m_port); + if (!ret) { + m_retryCount = 0U; + return false; + } else { + m_retryCount = 1U; + return true; + } +} + +bool CRemoteControlRemoteControlHandler::logout() +{ + if (!m_loggedIn || m_retryCount > 0U) + return false; + + ::memcpy(m_outBuffer, "LOG", 3U); + m_outLength = 3U; + + for (unsigned int i = 0U; i < 5U; i++) { + bool ret = m_socket.write(m_outBuffer, m_outLength, m_address, m_port); + if (!ret) { + m_retryCount = 0U; + return false; + } + } + + m_retryCount = 1U; + + return true; +} + +bool CRemoteControlRemoteControlHandler::retry() +{ + if (m_retryCount > 0U) { + m_retryCount++; + if (m_retryCount >= MAX_RETRIES) { + m_retryCount = 0U; + return false; + } + + m_socket.write(m_outBuffer, m_outLength, m_address, m_port); + } + + return true; +} + +void CRemoteControlRemoteControlHandler::close() +{ + m_socket.close(); +} diff --git a/RemoteControl/RemoteControlRemoteControlHandler.h b/RemoteControl/RemoteControlRemoteControlHandler.h new file mode 100644 index 0000000..e9d315b --- /dev/null +++ b/RemoteControl/RemoteControlRemoteControlHandler.h @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2011,2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef RemoteControlRemoteControlHandler_H +#define RemoteControlRemoteControlHandler_H + +#include "RemoteControlRepeaterData.h" +#include "RemoteControlStarNetGroup.h" +#include "RemoteControlCallsignData.h" +#include "UDPReaderWriter.h" + +#include + +enum RC_TYPE { + RCT_NONE, + RCT_ACK, + RCT_NAK, + RCT_RANDOM, + RCT_CALLSIGNS, + RCT_REPEATER, + RCT_STARNET +}; + +class CRemoteControlRemoteControlHandler { +public: + CRemoteControlRemoteControlHandler(const wxString& address, unsigned int port); + ~CRemoteControlRemoteControlHandler(); + + bool open(); + + RC_TYPE readType(); + + wxString readNAK(); + unsigned int readRandom(); + CRemoteControlCallsignData* readCallsigns(); + CRemoteControlRepeaterData* readRepeater(); + CRemoteControlStarNetGroup* readStarNetGroup(); + + bool login(); + bool sendHash(const unsigned char* hash, unsigned int length); + + void setLoggedIn(bool set); + + bool getCallsigns(); + bool getRepeater(const wxString& callsign); + bool getStarNet(const wxString& callsign); + + bool link(const wxString& callsign, RECONNECT reconnect, const wxString& reflector); + bool unlink(const wxString& callsign, PROTOCOL protocol, const wxString& reflector); + bool logoff(const wxString& callsign, const wxString& user); + + bool logout(); + + bool retry(); + + void close(); + +private: + CUDPReaderWriter m_socket; + in_addr m_address; + unsigned int m_port; + bool m_loggedIn; + unsigned int m_retryCount; + RC_TYPE m_type; + unsigned char* m_inBuffer; + unsigned int m_inLength; + unsigned char* m_outBuffer; + unsigned int m_outLength; +}; + +#endif diff --git a/RemoteControl/RemoteControlRemoteSet.cpp b/RemoteControl/RemoteControlRemoteSet.cpp new file mode 100644 index 0000000..0c8f788 --- /dev/null +++ b/RemoteControl/RemoteControlRemoteSet.cpp @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2011 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "RemoteControlRemoteSet.h" +#include "DStarDefines.h" + +const unsigned int PASSWORD_WIDTH = 120U; +const unsigned int PORT_WIDTH = 80U; + +const unsigned int PORT_LENGTH = 5U; + +const unsigned int BORDER_SIZE = 5U; + +CRemoteControlRemoteSet::CRemoteControlRemoteSet(wxWindow* parent, int id, const wxString& title, const wxString& address, unsigned int port, const wxString& password) : +wxPanel(parent, id), +m_title(title), +m_address(NULL), +m_port(NULL), +m_password(NULL) +{ + wxFlexGridSizer* sizer = new wxFlexGridSizer(2); + + wxStaticText* addressLabel = new wxStaticText(this, -1, _("Address")); + sizer->Add(addressLabel, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + m_address = new wxTextCtrl(this, -1, address, wxDefaultPosition, wxSize(PASSWORD_WIDTH, -1)); + sizer->Add(m_address, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + + wxStaticText* portLabel = new wxStaticText(this, -1, _("Port")); + sizer->Add(portLabel, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + wxString buffer; + buffer.Printf(wxT("%u"), port); + + m_port = new CPortTextCtrl(this, -1, buffer, wxDefaultPosition, wxSize(PORT_WIDTH, -1)); + m_port->SetMaxLength(PORT_LENGTH); + sizer->Add(m_port, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + + wxStaticText* passwordLabel = new wxStaticText(this, -1, _("Password")); + sizer->Add(passwordLabel, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + m_password = new wxTextCtrl(this, -1, password, wxDefaultPosition, wxSize(PASSWORD_WIDTH, -1), wxTE_PASSWORD); + sizer->Add(m_password, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + + SetAutoLayout(true); + + SetSizer(sizer); +} + + +CRemoteControlRemoteSet::~CRemoteControlRemoteSet() +{ +} + +bool CRemoteControlRemoteSet::Validate() +{ + wxString address = getAddress(); + if (address.IsEmpty()) { + wxMessageDialog dialog(this, _("The Address is empty"), m_title + _(" Error"), wxICON_ERROR); + dialog.ShowModal(); + return false; + } + + unsigned int port = getPort(); + if (port == 0U || port > 65535U) { + wxMessageDialog dialog(this, _("The Port is not valid"), m_title + _(" Error"), wxICON_ERROR); + dialog.ShowModal(); + return false; + } + + wxString password = getPassword(); + if (password.IsEmpty()) { + wxMessageDialog dialog(this, _("The Password is empty"), m_title + _(" Error"), wxICON_ERROR); + dialog.ShowModal(); + return false; + } + + return true; +} + +wxString CRemoteControlRemoteSet::getAddress() const +{ + return m_address->GetValue(); +} + +unsigned int CRemoteControlRemoteSet::getPort() const +{ + unsigned long n; + m_port->GetValue().ToULong(&n); + + return n; +} + +wxString CRemoteControlRemoteSet::getPassword() const +{ + return m_password->GetValue(); +} diff --git a/RemoteControl/RemoteControlRemoteSet.h b/RemoteControl/RemoteControlRemoteSet.h new file mode 100644 index 0000000..a74c354 --- /dev/null +++ b/RemoteControl/RemoteControlRemoteSet.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2011 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef RemoteControlRemoteSet_H +#define RemoteControlRemoteSet_H + +#include "PortTextCtrl.h" + +#include + +class CRemoteControlRemoteSet : public wxPanel { +public: + CRemoteControlRemoteSet(wxWindow* parent, int id, const wxString& title, const wxString& address, unsigned int port, const wxString& password); + virtual ~CRemoteControlRemoteSet(); + + virtual bool Validate(); + + virtual wxString getAddress() const; + virtual unsigned int getPort() const; + virtual wxString getPassword() const; + +private: + wxString m_title; + wxTextCtrl* m_address; + CPortTextCtrl* m_port; + wxTextCtrl* m_password; +}; + +#endif diff --git a/RemoteControl/RemoteControlRepeaterData.cpp b/RemoteControl/RemoteControlRepeaterData.cpp new file mode 100644 index 0000000..bd1148c --- /dev/null +++ b/RemoteControl/RemoteControlRepeaterData.cpp @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2011 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "RemoteControlRepeaterData.h" + +#include +WX_DEFINE_OBJARRAY(CRemoteLinkData_t); + +CRemoteControlRepeaterData::CRemoteControlRepeaterData(const wxString& callsign, wxInt32 reconnect, const wxString& reflector) : +m_callsign(callsign), +m_reconnect(RECONNECT(reconnect)), +m_reflector(reflector), +m_links() +{ +} + +CRemoteControlRepeaterData::~CRemoteControlRepeaterData() +{ + m_links.Clear(); +} + +void CRemoteControlRepeaterData::addLink(const wxString& callsign, wxInt32 protocol, wxInt32 linked, wxInt32 direction, wxInt32 dongle) +{ + CRemoteControlLinkData data(callsign, protocol, linked, direction, dongle); + + m_links.Add(data); +} + +wxString CRemoteControlRepeaterData::getCallsign() const +{ + return m_callsign; +} + +RECONNECT CRemoteControlRepeaterData::getReconnect() const +{ + return m_reconnect; +} + +wxString CRemoteControlRepeaterData::getReflector() const +{ + return m_reflector; +} + +unsigned int CRemoteControlRepeaterData::getLinkCount() const +{ + return m_links.GetCount(); +} + +CRemoteControlLinkData& CRemoteControlRepeaterData::getLink(unsigned int n) const +{ + return m_links.Item(n); +} diff --git a/RemoteControl/RemoteControlRepeaterData.h b/RemoteControl/RemoteControlRepeaterData.h new file mode 100644 index 0000000..5a5a4e3 --- /dev/null +++ b/RemoteControl/RemoteControlRepeaterData.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2011 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef RemoteControlRepeaterData_H +#define RemoteControlRepeaterData_H + +#include "RemoteControlLinkData.h" + +#include +#include + +WX_DECLARE_OBJARRAY(CRemoteControlLinkData, CRemoteLinkData_t); + +class CRemoteControlRepeaterData { +public: + CRemoteControlRepeaterData(const wxString& callsign, wxInt32 reconnect, const wxString& reflector); + ~CRemoteControlRepeaterData(); + + void addLink(const wxString& callsign, wxInt32 protocol, wxInt32 linked, wxInt32 direction, wxInt32 dongle); + + wxString getCallsign() const; + RECONNECT getReconnect() const; + wxString getReflector() const; + + unsigned int getLinkCount() const; + CRemoteControlLinkData& getLink(unsigned int n) const; + +private: + wxString m_callsign; + RECONNECT m_reconnect; + wxString m_reflector; + CRemoteLinkData_t m_links; +}; + +#endif diff --git a/RemoteControl/RemoteControlRepeaterPanel.cpp b/RemoteControl/RemoteControlRepeaterPanel.cpp new file mode 100644 index 0000000..78b5356 --- /dev/null +++ b/RemoteControl/RemoteControlRepeaterPanel.cpp @@ -0,0 +1,397 @@ +/* + * Copyright (C) 2011,2012,2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "RemoteControlRepeaterPanel.h" +#include "RemoteControlApp.h" +#include "DStarDefines.h" +#include "HostFile.h" + +#include + +enum { + List_Reflectors = 7100, + Button_Refresh, + Button_Link, + Button_Unlink +}; + +BEGIN_EVENT_TABLE(CRemoteControlRepeaterPanel, wxPanel) + EVT_LIST_ITEM_SELECTED(List_Reflectors, CRemoteControlRepeaterPanel::onSelect) + EVT_BUTTON(Button_Refresh, CRemoteControlRepeaterPanel::onRefresh) + EVT_BUTTON(Button_Link, CRemoteControlRepeaterPanel::onLink) + EVT_BUTTON(Button_Unlink, CRemoteControlRepeaterPanel::onUnlink) +END_EVENT_TABLE() + +#if defined(__WINDOWS__) +const unsigned int LIST_HEIGHT = 350U; +const unsigned int LIST_WIDTH = 350U; +const unsigned int CALLSIGN_WIDTH = 100U; +const unsigned int PROTOCOL_WIDTH = 55U; +const unsigned int DIRECTION_WIDTH = 55U; +const unsigned int TYPE_WIDTH = 65U; +const unsigned int STATE_WIDTH = 55U; +const unsigned int BUTTON_WIDTH = 75U; +const unsigned int REFLECTOR_WIDTH = 75U; +const unsigned int CHANNEL_WIDTH = 40U; +const unsigned int RECONNECT_WIDTH = 75U; +#else +const unsigned int LIST_HEIGHT = 350U; +const unsigned int LIST_WIDTH = 350U; +const unsigned int CALLSIGN_WIDTH = 100U; +const unsigned int PROTOCOL_WIDTH = 55U; +const unsigned int DIRECTION_WIDTH = 55U; +const unsigned int TYPE_WIDTH = 65U; +const unsigned int STATE_WIDTH = 55U; +const unsigned int BUTTON_WIDTH = 75U; +const unsigned int REFLECTOR_WIDTH = 90U; +const unsigned int CHANNEL_WIDTH = 50U; +const unsigned int RECONNECT_WIDTH = 100U; +#endif + +const unsigned int BORDER_SIZE = 5U; + +CRemoteControlRepeaterPanel::CRemoteControlRepeaterPanel(wxWindow* parent, int id, const wxString& callsign) : +wxPanel(parent, id), +m_callsign(callsign), +m_list(NULL), +m_reflector(NULL), +m_channel(NULL), +m_reconnect(NULL), +m_unlink(NULL), +m_selected(-1), +m_reflectors(), +m_protocols() +{ + wxBoxSizer* sizer1 = new wxBoxSizer(wxHORIZONTAL); + + m_list = new wxListCtrl(this, List_Reflectors, wxDefaultPosition, wxSize(LIST_WIDTH, LIST_HEIGHT), wxLC_REPORT | wxLC_SINGLE_SEL); + m_list->InsertColumn(0L, _("Callsign")); + m_list->SetColumnWidth(0L, CALLSIGN_WIDTH); + m_list->InsertColumn(1L, _("Protocol")); + m_list->SetColumnWidth(1L, PROTOCOL_WIDTH); + m_list->InsertColumn(2L, _("Direction")); + m_list->SetColumnWidth(2L, DIRECTION_WIDTH); + m_list->InsertColumn(3L, _("Type")); + m_list->SetColumnWidth(3L, TYPE_WIDTH); + m_list->InsertColumn(4L, _("State")); + m_list->SetColumnWidth(4L, STATE_WIDTH); + sizer1->Add(m_list, 0, wxTOP | wxBOTTOM | wxLEFT | wxEXPAND, BORDER_SIZE); + + wxBoxSizer* sizer2 = new wxBoxSizer(wxVERTICAL); + + wxButton* refreshButton = new wxButton(this, Button_Refresh, _("Refresh"), wxDefaultPosition, wxSize(BUTTON_WIDTH, -1)); + sizer2->Add(refreshButton, 0, wxALL, BORDER_SIZE); + + wxStaticText* dummy1Label = new wxStaticText(this, -1, wxEmptyString); + sizer2->Add(dummy1Label, 0, wxALL, BORDER_SIZE); + + wxStaticText* dummy2Label = new wxStaticText(this, -1, wxEmptyString); + sizer2->Add(dummy2Label, 0, wxALL, BORDER_SIZE); + + wxBoxSizer* sizer3 = new wxBoxSizer(wxHORIZONTAL); + + m_reflector = new wxChoice(this, -1, wxDefaultPosition, wxSize(REFLECTOR_WIDTH, -1)); + m_reflector->Append(_("None")); + + wxFileName fileName1(wxFileName::GetHomeDir(), DPLUS_HOSTS_FILE_NAME); + if (fileName1.IsFileReadable()) { + CHostFile file(fileName1.GetFullPath(), false); + + for (unsigned int i = 0U; i < file.getCount(); i++) + m_reflector->Append(file.getName(i).Trim()); + } + +#if defined(__WINDOWS__) + wxFileName fileName4(::wxGetCwd(), DPLUS_HOSTS_FILE_NAME); +#else + wxFileName fileName4(wxT(DATA_DIR), DPLUS_HOSTS_FILE_NAME); +#endif + if (fileName4.IsFileReadable()) { + CHostFile file(fileName4.GetFullPath(), false); + + for (unsigned int i = 0U; i < file.getCount(); i++) { + wxString name = file.getName(i).Trim(); + if (m_reflector->FindString(name) == wxNOT_FOUND) + m_reflector->Append(name); + } + } + + wxFileName fileName2(wxFileName::GetHomeDir(), DEXTRA_HOSTS_FILE_NAME); + if (fileName2.IsFileReadable()) { + CHostFile file(fileName2.GetFullPath(), false); + + for (unsigned int i = 0U; i < file.getCount(); i++) + m_reflector->Append(file.getName(i).Trim()); + } + +#if defined(__WINDOWS__) + wxFileName fileName5(::wxGetCwd(), DEXTRA_HOSTS_FILE_NAME); +#else + wxFileName fileName5(wxT(DATA_DIR), DEXTRA_HOSTS_FILE_NAME); +#endif + if (fileName5.IsFileReadable()) { + CHostFile file(fileName5.GetFullPath(), false); + + for (unsigned int i = 0U; i < file.getCount(); i++) { + wxString name = file.getName(i).Trim(); + if (m_reflector->FindString(name) == wxNOT_FOUND) + m_reflector->Append(name); + } + } + + wxFileName fileName3(wxFileName::GetHomeDir(), DCS_HOSTS_FILE_NAME); + if (fileName3.IsFileReadable()) { + CHostFile file(fileName3.GetFullPath(), false); + + for (unsigned int i = 0U; i < file.getCount(); i++) + m_reflector->Append(file.getName(i).Trim()); + } + +#if defined(__WINDOWS__) + wxFileName fileName6(::wxGetCwd(), DCS_HOSTS_FILE_NAME); +#else + wxFileName fileName6(wxT(DATA_DIR), DCS_HOSTS_FILE_NAME); +#endif + if (fileName6.IsFileReadable()) { + CHostFile file(fileName6.GetFullPath(), false); + + for (unsigned int i = 0U; i < file.getCount(); i++) { + wxString name = file.getName(i).Trim(); + if (m_reflector->FindString(name) == wxNOT_FOUND) + m_reflector->Append(name); + } + } + + sizer3->Add(m_reflector, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + m_reflector->SetSelection(0); + + m_channel = new wxChoice(this, -1, wxDefaultPosition, wxSize(CHANNEL_WIDTH, -1)); + m_channel->Append(wxT("A")); + m_channel->Append(wxT("B")); + m_channel->Append(wxT("C")); + m_channel->Append(wxT("D")); + m_channel->Append(wxT("E")); + m_channel->Append(wxT("F")); + m_channel->Append(wxT("G")); + m_channel->Append(wxT("H")); + m_channel->Append(wxT("I")); + m_channel->Append(wxT("J")); + m_channel->Append(wxT("K")); + m_channel->Append(wxT("L")); + m_channel->Append(wxT("M")); + m_channel->Append(wxT("N")); + m_channel->Append(wxT("O")); + m_channel->Append(wxT("P")); + m_channel->Append(wxT("Q")); + m_channel->Append(wxT("R")); + m_channel->Append(wxT("S")); + m_channel->Append(wxT("T")); + m_channel->Append(wxT("U")); + m_channel->Append(wxT("V")); + m_channel->Append(wxT("W")); + m_channel->Append(wxT("X")); + m_channel->Append(wxT("Y")); + m_channel->Append(wxT("Z")); + sizer3->Add(m_channel, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + m_channel->SetSelection(0); + + sizer2->Add(sizer3); + + m_reconnect = new wxChoice(this, -1, wxDefaultPosition, wxSize(RECONNECT_WIDTH, -1)); + m_reconnect->Append(_("Never")); + m_reconnect->Append(_("Fixed")); + m_reconnect->Append(_("5 minutes")); + m_reconnect->Append(_("10 minutes")); + m_reconnect->Append(_("15 minutes")); + m_reconnect->Append(_("20 minutes")); + m_reconnect->Append(_("25 minutes")); + m_reconnect->Append(_("30 minutes")); + m_reconnect->Append(_("60 minutes")); + m_reconnect->Append(_("90 minutes")); + m_reconnect->Append(_("120 minutes")); + m_reconnect->Append(_("180 minutes")); + sizer2->Add(m_reconnect, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + m_reconnect->SetSelection(0); + + wxStaticText* dummy3Label = new wxStaticText(this, -1, wxEmptyString); + sizer2->Add(dummy3Label, 0, wxALL, BORDER_SIZE); + + wxButton* linkButton = new wxButton(this, Button_Link, _("Link"), wxDefaultPosition, wxSize(BUTTON_WIDTH, -1)); + sizer2->Add(linkButton, 0, wxALL, BORDER_SIZE); + + m_unlink = new wxButton(this, Button_Unlink, _("Unlink"), wxDefaultPosition, wxSize(BUTTON_WIDTH, -1)); + sizer2->Add(m_unlink, 0, wxALL, BORDER_SIZE); + m_unlink->Disable(); + + sizer1->Add(sizer2); + + SetAutoLayout(true); + + SetSizer(sizer1); +} + + +CRemoteControlRepeaterPanel::~CRemoteControlRepeaterPanel() +{ +} + +void CRemoteControlRepeaterPanel::add(const CRemoteControlRepeaterData& data) +{ + m_list->DeleteAllItems(); + m_unlink->Disable(); + m_reflectors.Clear(); + m_protocols.Clear(); + + RECONNECT reconnect = data.getReconnect(); + m_reconnect->SetSelection(int(reconnect)); + + wxString reflector = data.getReflector(); + reflector.Append(wxT(" ")); + reflector.Truncate(LONG_CALLSIGN_LENGTH); + + bool res = m_channel->SetStringSelection(reflector.Right(1)); + if (!res) + m_channel->SetSelection(0); + + reflector.Truncate(LONG_CALLSIGN_LENGTH - 1U); + reflector.Append(wxT(" ")); + + res = m_reflector->SetStringSelection(reflector); + if (!res) + m_reflector->SetSelection(0); + + unsigned int count = data.getLinkCount(); + for (unsigned int i = 0U; i < count; i++) { + CRemoteControlLinkData& link = data.getLink(i); + + wxString callsign = link.getCallsign(); + PROTOCOL protocol = link.getProtocol(); + bool isLinked = link.isLinked(); + DIRECTION direction = link.getDirection(); + bool isDongle = link.isDongle(); + + m_reflectors.Add(callsign); + m_protocols.Add(protocol); + + m_list->InsertItem(0L, callsign); + + // To allow for sorting + m_list->SetItemData(0L, long(protocol)); + + switch (protocol) { + case PROTO_DEXTRA: + m_list->SetItem(0L, 1, wxT("DExtra")); + break; + case PROTO_DPLUS: + m_list->SetItem(0L, 1, wxT("D-Plus")); + break; + case PROTO_DCS: + m_list->SetItem(0L, 1, wxT("DCS")); + break; + case PROTO_CCS: + m_list->SetItem(0L, 1, wxT("CCS")); + break; + default: + m_list->SetItem(0L, 1, wxT("?????")); + break; + } + + switch (direction){ + case DIR_INCOMING: + m_list->SetItem(0L, 2, _("IN")); + break; + case DIR_OUTGOING: + m_list->SetItem(0L, 2, _("OUT")); + break; + default: + m_list->SetItem(0L, 2, wxT("???")); + break; + } + + if (isDongle) + m_list->SetItem(0L, 3, _("Dongle")); + else + m_list->SetItem(0L, 3, _("Repeater")); + + if (isLinked) + m_list->SetItem(0L, 4, _("Linked")); + else + m_list->SetItem(0L, 4, _("Linking")); + } +} + +void CRemoteControlRepeaterPanel::onRefresh(wxCommandEvent&) +{ + ::wxGetApp().repeaterRefresh(m_callsign); +} + +void CRemoteControlRepeaterPanel::onLink(wxCommandEvent&) +{ + int n = m_reconnect->GetCurrentSelection(); + if (n == wxNOT_FOUND) + return; + + RECONNECT reconnect = RECONNECT(n); + + n = m_reflector->GetCurrentSelection(); + if (n == wxNOT_FOUND) + return; + + wxString reflector = wxEmptyString; + + if (n > 0) { + n = m_channel->GetCurrentSelection(); + if (n == wxNOT_FOUND) + return; + + reflector = m_reflector->GetStringSelection(); + if (reflector.IsEmpty()) + return; + + wxString channel = m_channel->GetStringSelection(); + if (channel.IsEmpty()) + return; + + reflector.Append(wxT(" ")); + reflector.Truncate(LONG_CALLSIGN_LENGTH - 1U); + reflector.Append(channel); + } + + ::wxGetApp().link(m_callsign, reconnect, reflector); +} + +void CRemoteControlRepeaterPanel::onUnlink(wxCommandEvent&) +{ + if (m_selected == -1) + return; + + wxString reflector = m_reflectors.Item(m_selected); + PROTOCOL protocol = m_protocols.Item(m_selected); + + m_selected = -1; + m_unlink->Disable(); + + ::wxGetApp().unlink(m_callsign, protocol, reflector); +} + +void CRemoteControlRepeaterPanel::onSelect(wxListEvent& event) +{ + m_selected = event.GetSelection(); + + m_unlink->Enable(); +} diff --git a/RemoteControl/RemoteControlRepeaterPanel.h b/RemoteControl/RemoteControlRepeaterPanel.h new file mode 100644 index 0000000..dbe48e6 --- /dev/null +++ b/RemoteControl/RemoteControlRepeaterPanel.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2011,2012,2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef RemoteControlRepeaterPanel_H +#define RemoteControlRepeaterPanel_H + +#include "RemoteControlRepeaterData.h" + +#include +#include + +WX_DEFINE_ARRAY_INT(PROTOCOL, CArrayProtocol); + +class CRemoteControlRepeaterPanel : public wxPanel { +public: + CRemoteControlRepeaterPanel(wxWindow* parent, int id, const wxString& callsign); + virtual ~CRemoteControlRepeaterPanel(); + + virtual void add(const CRemoteControlRepeaterData& data); + + virtual void onRefresh(wxCommandEvent& event); + virtual void onLink(wxCommandEvent& event); + virtual void onUnlink(wxCommandEvent& event); + virtual void onSelect(wxListEvent& event); + +private: + wxString m_callsign; + wxListCtrl* m_list; + wxChoice* m_reflector; + wxChoice* m_channel; + wxChoice* m_reconnect; + wxButton* m_unlink; + int m_selected; + wxArrayString m_reflectors; + CArrayProtocol m_protocols; + + DECLARE_EVENT_TABLE() +}; + +#endif diff --git a/RemoteControl/RemoteControlStarNetGroup.cpp b/RemoteControl/RemoteControlStarNetGroup.cpp new file mode 100644 index 0000000..3247654 --- /dev/null +++ b/RemoteControl/RemoteControlStarNetGroup.cpp @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2011 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "RemoteControlStarNetGroup.h" + +#include +WX_DEFINE_OBJARRAY(CRemoteUserData_t); + +CRemoteControlStarNetGroup::CRemoteControlStarNetGroup(const wxString& callsign, const wxString& logoff, wxUint32 timer, wxUint32 timeout) : +m_callsign(callsign), +m_logoff(logoff), +m_timer((unsigned int)timer), +m_timeout((unsigned int)timeout), +m_users() +{ + if (m_logoff.IsSameAs(wxT(" "))) + m_logoff.Clear(); +} + +CRemoteControlStarNetGroup::~CRemoteControlStarNetGroup() +{ + m_users.Clear(); +} + +void CRemoteControlStarNetGroup::addUser(const wxString& callsign, wxUint32 timer, wxUint32 timeout) +{ + CRemoteControlStarNetUser user(callsign, timer, timeout); + + m_users.Add(user); +} + +wxString CRemoteControlStarNetGroup::getCallsign() const +{ + return m_callsign; +} + +wxString CRemoteControlStarNetGroup::getLogoff() const +{ + return m_logoff; +} + +unsigned int CRemoteControlStarNetGroup::getTimer() const +{ + return m_timer; +} + +unsigned int CRemoteControlStarNetGroup::getTimeout() const +{ + return m_timeout; +} + +unsigned int CRemoteControlStarNetGroup::getUserCount() const +{ + return m_users.GetCount(); +} + +CRemoteControlStarNetUser& CRemoteControlStarNetGroup::getUser(unsigned int n) const +{ + return m_users.Item(n); +} diff --git a/RemoteControl/RemoteControlStarNetGroup.h b/RemoteControl/RemoteControlStarNetGroup.h new file mode 100644 index 0000000..ea1e380 --- /dev/null +++ b/RemoteControl/RemoteControlStarNetGroup.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2011 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef RemoteControlStarNetGroup_H +#define RemoteControlStarNetGroup_H + +#include "RemoteControlStarNetUser.h" + +#include + +#include +WX_DECLARE_OBJARRAY(CRemoteControlStarNetUser, CRemoteUserData_t); + +class CRemoteControlStarNetGroup { +public: + CRemoteControlStarNetGroup(const wxString& callsign, const wxString& logoff, wxUint32 timer, wxUint32 timeout); + ~CRemoteControlStarNetGroup(); + + void addUser(const wxString& callsign, wxUint32 timer, wxUint32 timeout); + + wxString getCallsign() const; + wxString getLogoff() const; + unsigned int getTimer() const; + unsigned int getTimeout() const; + + unsigned int getUserCount() const; + CRemoteControlStarNetUser& getUser(unsigned int n) const; + +private: + wxString m_callsign; + wxString m_logoff; + unsigned int m_timer; + unsigned int m_timeout; + CRemoteUserData_t m_users; +}; + +#endif diff --git a/RemoteControl/RemoteControlStarNetPanel.cpp b/RemoteControl/RemoteControlStarNetPanel.cpp new file mode 100644 index 0000000..7efe0e6 --- /dev/null +++ b/RemoteControl/RemoteControlStarNetPanel.cpp @@ -0,0 +1,188 @@ +/* + * Copyright (C) 2011 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "RemoteControlStarNetPanel.h" +#include "RemoteControlApp.h" + +enum { + Button_Refresh = 7100, + Button_LogoffAll, + List_StarNets, + Menu_Logoff +}; + +BEGIN_EVENT_TABLE(CRemoteControlStarNetPanel, wxPanel) + EVT_BUTTON(Button_Refresh, CRemoteControlStarNetPanel::onRefresh) + EVT_BUTTON(Button_LogoffAll, CRemoteControlStarNetPanel::onLogoffAll) + EVT_LIST_ITEM_RIGHT_CLICK(List_StarNets, CRemoteControlStarNetPanel::onClick) + EVT_MENU(Menu_Logoff, CRemoteControlStarNetPanel::onLogoff) +END_EVENT_TABLE() + +#if defined(__WINDOWS__) +const unsigned int LIST_HEIGHT = 350U; +const unsigned int LIST_WIDTH = 350U; +const unsigned int CALLSIGN_WIDTH = 100U; +const unsigned int TIMER_WIDTH = 145U; +const unsigned int BUTTON_WIDTH = 75U; +#else +const unsigned int LIST_HEIGHT = 350U; +const unsigned int LIST_WIDTH = 350U; +const unsigned int CALLSIGN_WIDTH = 100U; +const unsigned int TIMER_WIDTH = 145U; +const unsigned int BUTTON_WIDTH = 75U; +#endif + +const unsigned int BORDER_SIZE = 5U; + +CRemoteControlStarNetPanel::CRemoteControlStarNetPanel(wxWindow* parent, int id, const wxString& callsign) : +wxPanel(parent, id), +m_callsign(callsign), +m_list(NULL), +m_logoff(NULL), +m_timer(NULL), +m_logoffAll(NULL), +m_chosen(), +m_menu(NULL) +{ + wxBoxSizer* sizer1 = new wxBoxSizer(wxHORIZONTAL); + + m_list = new wxListCtrl(this, List_StarNets, wxDefaultPosition, wxSize(LIST_WIDTH, LIST_HEIGHT), wxLC_REPORT | wxLC_SINGLE_SEL); + m_list->InsertColumn(0L, _("Callsign")); + m_list->SetColumnWidth(0L, CALLSIGN_WIDTH); + m_list->InsertColumn(1L, _("User Timer")); + m_list->SetColumnWidth(1L, TIMER_WIDTH); + sizer1->Add(m_list, 0, wxTOP | wxBOTTOM | wxLEFT | wxEXPAND, BORDER_SIZE); + + wxBoxSizer* sizer2 = new wxBoxSizer(wxVERTICAL); + + wxButton* refreshButton = new wxButton(this, Button_Refresh, _("Refresh"), wxDefaultPosition, wxSize(BUTTON_WIDTH, -1)); + sizer2->Add(refreshButton, 0, wxALL, BORDER_SIZE); + + wxStaticText* dummy1Label = new wxStaticText(this, -1, wxEmptyString); + sizer2->Add(dummy1Label, 0, wxALL, BORDER_SIZE); + + wxStaticText* logoffLabel = new wxStaticText(this, -1, _("Logoff Callsign")); + sizer2->Add(logoffLabel, 0, wxALL, BORDER_SIZE); + + m_logoff = new wxStaticText(this, -1, wxEmptyString); + sizer2->Add(m_logoff, 0, wxALL, BORDER_SIZE); + + wxStaticText* dummy3Label = new wxStaticText(this, -1, wxEmptyString); + sizer2->Add(dummy3Label, 0, wxALL, BORDER_SIZE); + + wxStaticText* timerLabel = new wxStaticText(this, -1, _("Group Timer")); + sizer2->Add(timerLabel, 0, wxALL, BORDER_SIZE); + + m_timer = new wxStaticText(this, -1, wxEmptyString); + sizer2->Add(m_timer, 0, wxALL, BORDER_SIZE); + + wxStaticText* dummy5Label = new wxStaticText(this, -1, wxEmptyString); + sizer2->Add(dummy5Label, 0, wxALL, BORDER_SIZE); + + m_logoffAll = new wxButton(this, Button_LogoffAll, _("Logoff All"), wxDefaultPosition, wxSize(BUTTON_WIDTH, -1)); + m_logoffAll->Disable(); + sizer2->Add(m_logoffAll, 0, wxALL, BORDER_SIZE); + + sizer1->Add(sizer2); + + SetAutoLayout(true); + + SetSizer(sizer1); + + m_menu = new wxMenu; + m_menu->Append(Menu_Logoff, _("Logoff")); +} + + +CRemoteControlStarNetPanel::~CRemoteControlStarNetPanel() +{ +} + +void CRemoteControlStarNetPanel::add(const CRemoteControlStarNetGroup& data) +{ + m_list->DeleteAllItems(); + + wxString logoff = data.getLogoff(); + if (logoff.IsEmpty()) + m_logoff->SetLabel(_("None")); + else + m_logoff->SetLabel(logoff); + + unsigned int timer = data.getTimer(); + unsigned int timeout = data.getTimeout(); + + if (timeout == 0U) { + m_timer->SetLabel(_("None")); + } else { + wxString text; + text.Printf(wxT("%u/%u"), timer, timeout); + m_timer->SetLabel(text); + } + + unsigned int count = data.getUserCount(); + for (unsigned int i = 0U; i < count; i++) { + CRemoteControlStarNetUser& user = data.getUser(i); + + wxString callsign = user.getCallsign(); + timer = user.getTimer(); + timeout = user.getTimeout(); + + m_list->InsertItem(0L, callsign); + + if (timeout == 0U) { + m_list->SetItem(0L, 1, _("None")); + } else { + wxString text; + text.Printf(wxT("%u/%u"), timer, timeout); + m_list->SetItem(0L, 1, text); + } + } + + if (count > 0U) + m_logoffAll->Enable(); + else + m_logoffAll->Disable(); +} + +void CRemoteControlStarNetPanel::onClick(wxListEvent& event) +{ + long n = event.GetIndex(); + if (n < 0) { + m_chosen.Clear(); + return; + } + + m_chosen = m_list->GetItemText(n); + + PopupMenu(m_menu); +} + +void CRemoteControlStarNetPanel::onRefresh(wxCommandEvent&) +{ + ::wxGetApp().starNetRefresh(m_callsign); +} + +void CRemoteControlStarNetPanel::onLogoff(wxCommandEvent&) +{ + ::wxGetApp().starNetLogoff(m_callsign, m_chosen); +} + +void CRemoteControlStarNetPanel::onLogoffAll(wxCommandEvent&) +{ + ::wxGetApp().starNetLogoff(m_callsign, wxT("ALL ")); +} diff --git a/RemoteControl/RemoteControlStarNetPanel.h b/RemoteControl/RemoteControlStarNetPanel.h new file mode 100644 index 0000000..e9cc682 --- /dev/null +++ b/RemoteControl/RemoteControlStarNetPanel.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2011 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef RemoteControlStarNetPanel_H +#define RemoteControlStarNetPanel_H + +#include "RemoteControlStarNetGroup.h" + +#include +#include + +class CRemoteControlStarNetPanel : public wxPanel { +public: + CRemoteControlStarNetPanel(wxWindow* parent, int id, const wxString& callsign); + virtual ~CRemoteControlStarNetPanel(); + + virtual void add(const CRemoteControlStarNetGroup& data); + + virtual void onClick(wxListEvent& event); + virtual void onRefresh(wxCommandEvent& event); + virtual void onLogoff(wxCommandEvent& event); + virtual void onLogoffAll(wxCommandEvent& event); + +private: + wxString m_callsign; + wxListCtrl* m_list; + wxStaticText* m_logoff; + wxStaticText* m_timer; + wxButton* m_logoffAll; + wxString m_chosen; + wxMenu* m_menu; + + DECLARE_EVENT_TABLE() +}; + +#endif diff --git a/RemoteControl/RemoteControlStarNetUser.cpp b/RemoteControl/RemoteControlStarNetUser.cpp new file mode 100644 index 0000000..545fd2e --- /dev/null +++ b/RemoteControl/RemoteControlStarNetUser.cpp @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2011 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "RemoteControlStarNetUser.h" + +CRemoteControlStarNetUser::CRemoteControlStarNetUser(const wxString& callsign, wxUint32 timer, wxUint32 timeout) : +m_callsign(callsign), +m_timer((unsigned int)timer), +m_timeout((unsigned int)timeout) +{ +} + +CRemoteControlStarNetUser::~CRemoteControlStarNetUser() +{ +} + +wxString CRemoteControlStarNetUser::getCallsign() const +{ + return m_callsign; +} + +unsigned int CRemoteControlStarNetUser::getTimer() const +{ + return m_timer; +} + +unsigned int CRemoteControlStarNetUser::getTimeout() const +{ + return m_timeout; +} diff --git a/RemoteControl/RemoteControlStarNetUser.h b/RemoteControl/RemoteControlStarNetUser.h new file mode 100644 index 0000000..a066eda --- /dev/null +++ b/RemoteControl/RemoteControlStarNetUser.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2011 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef RemoteControlStarNetUser_H +#define RemoteControlStarNetUser_H + +#include + +class CRemoteControlStarNetUser { +public: + CRemoteControlStarNetUser(const wxString& callsign, wxUint32 timer, wxUint32 timeout); + ~CRemoteControlStarNetUser(); + + wxString getCallsign() const; + unsigned int getTimer() const; + unsigned int getTimeout() const; + +private: + wxString m_callsign; + unsigned int m_timer; + unsigned int m_timeout; +}; + +#endif diff --git a/StarNetServer/StarNetServer.vcxproj b/StarNetServer/StarNetServer.vcxproj new file mode 100644 index 0000000..4c7a44c --- /dev/null +++ b/StarNetServer/StarNetServer.vcxproj @@ -0,0 +1,212 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {4E9989C8-80D4-4F6E-BCA1-754DCED3AF5F} + StarNetServer + Win32Proj + 10.0.16299.0 + + + + Application + v141 + Unicode + true + + + Application + v141 + Unicode + true + + + Application + v141 + Unicode + + + Application + v141 + Unicode + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>14.0.24720.0 + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + true + $(WXWIN)\include;$(WXWIN)\lib\vc_dll\mswud;$(IncludePath) + + + true + $(WXWIN)\include;$(WXWIN)\lib\vc_x64_dll\mswud;$(IncludePath) + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + false + + + false + + + + Disabled + $(WXWIN)\include\msvc;$(WXWIN)\include;../Common;../GUICommon;../ircDDB;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;WINVER=0x0400;__WXMSW__;WXUSINGDLL;wxUSE_GUI=1;__WXDEBUG__;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;DCS_LINK;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + Level4 + EditAndContinue + + + ws2_32.lib;%(AdditionalDependencies) + $(WXWIN)\lib\vc_dll;%(AdditionalLibraryDirectories) + true + Windows + MachineX86 + + + + + Disabled + $(WXWIN)\include\msvc;$(WXWIN)\include;../Common;../GUICommon;../ircDDB;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;WINVER=0x0400;__WXMSW__;WXUSINGDLL;wxUSE_GUI=1;__WXDEBUG__;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;DCS_LINK;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + + + Level4 + ProgramDatabase + + + ws2_32.lib;%(AdditionalDependencies) + $(WXWIN)\lib\vc_x64_dll;%(AdditionalLibraryDirectories) + true + Windows + + + + + MaxSpeed + true + $(WXWIN)\include\msvc;$(WXWIN)\include;../ircDDB;../Common;../GUICommon;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;WINVER=0x0400;__WXMSW__;WXUSINGDLL;wxUSE_GUI=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) + MultiThreadedDLL + true + + Level3 + ProgramDatabase + + + ws2_32.lib;%(AdditionalDependencies) + $(WXWIN)\lib\vc_dll;%(AdditionalLibraryDirectories) + true + Windows + true + true + MachineX86 + + + + + MaxSpeed + true + $(WXWIN)\include\msvc;$(WXWIN)\include;../ircDDB;../Common;../GUICommon;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;WINVER=0x0400;__WXMSW__;WXUSINGDLL;wxUSE_GUI=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) + MultiThreadedDLL + true + + + Level3 + ProgramDatabase + + + ws2_32.lib;%(AdditionalDependencies) + $(WXWIN)\lib\vc_x64_dll;%(AdditionalLibraryDirectories) + true + Windows + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {e793cb8e-2ac9-431a-bbfc-3f52537bb3cf} + false + + + {02d03515-0bbe-4553-8c40-566a597478f8} + false + + + {276bc54d-5581-4a0c-afd5-a5bdc947f0ad} + false + + + + + + \ No newline at end of file diff --git a/StarNetServer/StarNetServer.vcxproj.filters b/StarNetServer/StarNetServer.vcxproj.filters new file mode 100644 index 0000000..1cd5368 --- /dev/null +++ b/StarNetServer/StarNetServer.vcxproj.filters @@ -0,0 +1,80 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/StarNetServer/StarNetServerApp.cpp b/StarNetServer/StarNetServerApp.cpp new file mode 100644 index 0000000..84f48bf --- /dev/null +++ b/StarNetServer/StarNetServerApp.cpp @@ -0,0 +1,947 @@ +/* + * Copyright (C) 2010,2011,2012,2015 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "StarNetServerLogRedirect.h" +#include "StarNetServerThread.h" +#include "StarNetServerDefs.h" +#include "StarNetServerApp.h" +#include "Version.h" +#include "Logger.h" +#include "IRCDDBClient.h" + +#include +#include +#include + +IMPLEMENT_APP(CStarNetServerApp) + +const wxChar* NOLOGGING_SWITCH = wxT("nolog"); +const wxChar* GUI_SWITCH = wxT("gui"); +const wxChar* LOGDIR_OPTION = wxT("logdir"); +const wxChar* CONFDIR_OPTION = wxT("confdir"); + +CStarNetServerApp::CStarNetServerApp() : +wxApp(), +m_nolog(false), +m_gui(false), +m_logDir(), +m_confDir(), +m_frame(NULL), +m_thread(NULL), +m_config(NULL), +m_logChain(NULL) +{ +} + +CStarNetServerApp::~CStarNetServerApp() +{ +} + +bool CStarNetServerApp::OnInit() +{ +#if defined(__WINDOWS__) + WSAData data; + int wsaRet = ::WSAStartup(MAKEWORD(2, 2), &data); + if (wsaRet != 0) { + wxLogError(wxT("Error from WSAStartup")); + return false; + } +#endif + + SetVendorName(VENDOR_NAME); + + if (!wxApp::OnInit()) + return false; + + if (!m_nolog) { +#if defined(__WINDOWS__) + if (m_logDir.IsEmpty()) + m_logDir = ::wxGetHomeDir(); +#else + if (m_logDir.IsEmpty()) + m_logDir = wxT(LOG_DIR); +#endif + + wxLog* log = new CLogger(m_logDir, LOG_BASE_NAME); + wxLog::SetActiveTarget(log); + } else { + new wxLogNull; + } + + m_logChain = new wxLogChain(new CStarNetServerLogRedirect); + +#if defined(__WINDOWS__) + if (m_confDir.IsEmpty()) + m_confDir = wxGetHomeDir(); + + m_config = new CStarNetServerConfig(new wxConfig(APPLICATION_NAME), m_confDir); +#else + if (m_confDir.IsEmpty()) + m_confDir = wxT(CONF_DIR); + + m_config = new CStarNetServerConfig(m_confDir); +#endif + + wxPoint position = wxDefaultPosition; + + int x, y; + getPosition(x, y); + if (x >= 0 && y >= 0) + position = wxPoint(x, y); + + m_frame = new CStarNetServerFrame(APPLICATION_NAME + wxT(" - ") + VERSION, position, m_gui); + m_frame->Show(); + + SetTopWindow(m_frame); + + wxLogInfo(wxT("Starting ") + APPLICATION_NAME + wxT(" - ") + VERSION); + + // Log the version of wxWidgets and the Operating System + wxLogInfo(wxT("Using wxWidgets %d.%d.%d on %s"), wxMAJOR_VERSION, wxMINOR_VERSION, wxRELEASE_NUMBER, ::wxGetOsDescription().c_str()); + + createThread(); + + return true; +} + +int CStarNetServerApp::OnExit() +{ + m_logChain->SetLog(NULL); + + wxLogInfo(APPLICATION_NAME + wxT(" is exiting")); + + m_thread->kill(); + + delete m_config; + +#if defined(__WINDOWS__) + ::WSACleanup(); +#endif + + return 0; +} + +void CStarNetServerApp::OnInitCmdLine(wxCmdLineParser& parser) +{ + parser.AddSwitch(NOLOGGING_SWITCH, wxEmptyString, wxEmptyString, wxCMD_LINE_PARAM_OPTIONAL); + parser.AddSwitch(GUI_SWITCH, wxEmptyString, wxEmptyString, wxCMD_LINE_PARAM_OPTIONAL); + parser.AddOption(LOGDIR_OPTION, wxEmptyString, wxEmptyString, wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL); + parser.AddOption(CONFDIR_OPTION, wxEmptyString, wxEmptyString, wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL); + + wxApp::OnInitCmdLine(parser); +} + +bool CStarNetServerApp::OnCmdLineParsed(wxCmdLineParser& parser) +{ + if (!wxApp::OnCmdLineParsed(parser)) + return false; + + m_nolog = parser.Found(NOLOGGING_SWITCH); + m_gui = parser.Found(GUI_SWITCH); + + wxString logDir; + bool found = parser.Found(LOGDIR_OPTION, &logDir); + if (found) + m_logDir = logDir; + + wxString confDir; + found = parser.Found(CONFDIR_OPTION, &confDir); + if (found) + m_confDir = confDir; + + return true; +} + +#if defined(__WXDEBUG__) +void CStarNetServerApp::OnAssertFailure(const wxChar* file, int line, const wxChar* func, const wxChar* cond, const wxChar* msg) +{ + wxLogFatalError(wxT("Assertion failed on line %d in file %s and function %s: %s %s"), line, file, func, cond, msg); +} +#endif + +void CStarNetServerApp::showLog(const wxString& text) +{ + m_frame->showLog(text); +} + +void CStarNetServerApp::getGateway(wxString& callsign, wxString& address) const +{ + m_config->getGateway(callsign, address); +} + +void CStarNetServerApp::setGateway(const wxString& callsign, const wxString& address) +{ + m_config->setGateway(callsign, address); +} + +void CStarNetServerApp::getIrcDDB(wxString& hostname, wxString& username, wxString& password) const +{ + m_config->getIrcDDB(hostname, username, password); +} + +void CStarNetServerApp::setIrcDDB(const wxString& hostname, const wxString& username, const wxString& password) +{ + m_config->setIrcDDB(hostname, username, password); +} + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) +void CStarNetServerApp::getStarNet1(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch, wxString& reflector) const +{ + m_config->getStarNet1(band, callsign, logoff, info, permanent, userTimeout, groupTimeout, callsignSwitch, txMsgSwitch, reflector); +} + +void CStarNetServerApp::setStarNet1(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch, const wxString& reflector) +{ + m_config->setStarNet1(band, callsign, logoff, info, permanent, userTimeout, groupTimeout, callsignSwitch, txMsgSwitch, reflector); +} + +void CStarNetServerApp::getStarNet2(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch, wxString& reflector) const +{ + m_config->getStarNet2(band, callsign, logoff, info, permanent, userTimeout, groupTimeout, callsignSwitch, txMsgSwitch, reflector); +} + +void CStarNetServerApp::setStarNet2(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch, const wxString& reflector) +{ + m_config->setStarNet2(band, callsign, logoff, info, permanent, userTimeout, groupTimeout, callsignSwitch, txMsgSwitch, reflector); +} + +void CStarNetServerApp::getStarNet3(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch, wxString& reflector) const +{ + m_config->getStarNet3(band, callsign, logoff, info, permanent, userTimeout, groupTimeout, callsignSwitch, txMsgSwitch, reflector); +} + +void CStarNetServerApp::setStarNet3(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch, const wxString& reflector) +{ + m_config->setStarNet3(band, callsign, logoff, info, permanent, userTimeout, groupTimeout, callsignSwitch, txMsgSwitch, reflector); +} + +void CStarNetServerApp::getStarNet4(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch, wxString& reflector) const +{ + m_config->getStarNet4(band, callsign, logoff, info, permanent, userTimeout, groupTimeout, callsignSwitch, txMsgSwitch, reflector); +} + +void CStarNetServerApp::setStarNet4(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch, const wxString& reflector) +{ + m_config->setStarNet4(band, callsign, logoff, info, permanent, userTimeout, groupTimeout, callsignSwitch, txMsgSwitch, reflector); +} + +void CStarNetServerApp::getStarNet5(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch, wxString& reflector) const +{ + m_config->getStarNet5(band, callsign, logoff, info, permanent, userTimeout, groupTimeout, callsignSwitch, txMsgSwitch, reflector); +} + +void CStarNetServerApp::setStarNet5(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch, const wxString& reflector) +{ + m_config->setStarNet5(band, callsign, logoff, info, permanent, userTimeout, groupTimeout, callsignSwitch, txMsgSwitch, reflector); +} + +void CStarNetServerApp::getStarNet6(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch, wxString& reflector) const +{ + m_config->getStarNet6(band, callsign, logoff, info, permanent, userTimeout, groupTimeout, callsignSwitch, txMsgSwitch, reflector); +} + +void CStarNetServerApp::setStarNet6(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch, const wxString& reflector) +{ + m_config->setStarNet6(band, callsign, logoff, info, permanent, userTimeout, groupTimeout, callsignSwitch, txMsgSwitch, reflector); +} + +void CStarNetServerApp::getStarNet7(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch, wxString& reflector) const +{ + m_config->getStarNet7(band, callsign, logoff, info, permanent, userTimeout, groupTimeout, callsignSwitch, txMsgSwitch, reflector); +} + +void CStarNetServerApp::setStarNet7(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch, const wxString& reflector) +{ + m_config->setStarNet7(band, callsign, logoff, info, permanent, userTimeout, groupTimeout, callsignSwitch, txMsgSwitch, reflector); +} + +void CStarNetServerApp::getStarNet8(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch, wxString& reflector) const +{ + m_config->getStarNet8(band, callsign, logoff, info, permanent, userTimeout, groupTimeout, callsignSwitch, txMsgSwitch, reflector); +} + +void CStarNetServerApp::setStarNet8(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch, const wxString& reflector) +{ + m_config->setStarNet8(band, callsign, logoff, info, permanent, userTimeout, groupTimeout, callsignSwitch, txMsgSwitch, reflector); +} + +void CStarNetServerApp::getStarNet9(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch, wxString& reflector) const +{ + m_config->getStarNet9(band, callsign, logoff, info, permanent, userTimeout, groupTimeout, callsignSwitch, txMsgSwitch, reflector); +} + +void CStarNetServerApp::setStarNet9(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch, const wxString& reflector) +{ + m_config->setStarNet9(band, callsign, logoff, info, permanent, userTimeout, groupTimeout, callsignSwitch, txMsgSwitch, reflector); +} + +void CStarNetServerApp::getStarNet10(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch, wxString& reflector) const +{ + m_config->getStarNet10(band, callsign, logoff, info, permanent, userTimeout, groupTimeout, callsignSwitch, txMsgSwitch, reflector); +} + +void CStarNetServerApp::setStarNet10(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch, const wxString& reflector) +{ + m_config->setStarNet10(band, callsign, logoff, info, permanent, userTimeout, groupTimeout, callsignSwitch, txMsgSwitch, reflector); +} + +void CStarNetServerApp::getStarNet11(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch, wxString& reflector) const +{ + m_config->getStarNet11(band, callsign, logoff, info, permanent, userTimeout, groupTimeout, callsignSwitch, txMsgSwitch, reflector); +} + +void CStarNetServerApp::setStarNet11(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch, const wxString& reflector) +{ + m_config->setStarNet11(band, callsign, logoff, info, permanent, userTimeout, groupTimeout, callsignSwitch, txMsgSwitch, reflector); +} + +void CStarNetServerApp::getStarNet12(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch, wxString& reflector) const +{ + m_config->getStarNet12(band, callsign, logoff, info, permanent, userTimeout, groupTimeout, callsignSwitch, txMsgSwitch, reflector); +} + +void CStarNetServerApp::setStarNet12(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch, const wxString& reflector) +{ + m_config->setStarNet12(band, callsign, logoff, info, permanent, userTimeout, groupTimeout, callsignSwitch, txMsgSwitch, reflector); +} + +void CStarNetServerApp::getStarNet13(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch, wxString& reflector) const +{ + m_config->getStarNet13(band, callsign, logoff, info, permanent, userTimeout, groupTimeout, callsignSwitch, txMsgSwitch, reflector); +} + +void CStarNetServerApp::setStarNet13(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch, const wxString& reflector) +{ + m_config->setStarNet13(band, callsign, logoff, info, permanent, userTimeout, groupTimeout, callsignSwitch, txMsgSwitch, reflector); +} + +void CStarNetServerApp::getStarNet14(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch, wxString& reflector) const +{ + m_config->getStarNet14(band, callsign, logoff, info, permanent, userTimeout, groupTimeout, callsignSwitch, txMsgSwitch, reflector); +} + +void CStarNetServerApp::setStarNet14(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch, const wxString& reflector) +{ + m_config->setStarNet14(band, callsign, logoff, info, permanent, userTimeout, groupTimeout, callsignSwitch, txMsgSwitch, reflector); +} + +void CStarNetServerApp::getStarNet15(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch, wxString& reflector) const +{ + m_config->getStarNet15(band, callsign, logoff, info, permanent, userTimeout, groupTimeout, callsignSwitch, txMsgSwitch, reflector); +} + +void CStarNetServerApp::setStarNet15(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch, const wxString& reflector) +{ + m_config->setStarNet15(band, callsign, logoff, info, permanent, userTimeout, groupTimeout, callsignSwitch, txMsgSwitch, reflector); +} +#else +void CStarNetServerApp::getStarNet1(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch) const +{ + m_config->getStarNet1(band, callsign, logoff, info, permanent, userTimeout, groupTimeout, callsignSwitch, txMsgSwitch); +} + +void CStarNetServerApp::setStarNet1(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch) +{ + m_config->setStarNet1(band, callsign, logoff, info, permanent, userTimeout, groupTimeout, callsignSwitch, txMsgSwitch); +} + +void CStarNetServerApp::getStarNet2(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch) const +{ + m_config->getStarNet2(band, callsign, logoff, info, permanent, userTimeout, groupTimeout, callsignSwitch, txMsgSwitch); +} + +void CStarNetServerApp::setStarNet2(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch) +{ + m_config->setStarNet2(band, callsign, logoff, info, permanent, userTimeout, groupTimeout, callsignSwitch, txMsgSwitch); +} + +void CStarNetServerApp::getStarNet3(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch) const +{ + m_config->getStarNet3(band, callsign, logoff, info, permanent, userTimeout, groupTimeout, callsignSwitch, txMsgSwitch); +} + +void CStarNetServerApp::setStarNet3(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch) +{ + m_config->setStarNet3(band, callsign, logoff, info, permanent, userTimeout, groupTimeout, callsignSwitch, txMsgSwitch); +} + +void CStarNetServerApp::getStarNet4(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch) const +{ + m_config->getStarNet4(band, callsign, logoff, info, permanent, userTimeout, groupTimeout, callsignSwitch, txMsgSwitch); +} + +void CStarNetServerApp::setStarNet4(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch) +{ + m_config->setStarNet4(band, callsign, logoff, info, permanent, userTimeout, groupTimeout, callsignSwitch, txMsgSwitch); +} + +void CStarNetServerApp::getStarNet5(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch) const +{ + m_config->getStarNet5(band, callsign, logoff, info, permanent, userTimeout, groupTimeout, callsignSwitch, txMsgSwitch); +} + +void CStarNetServerApp::setStarNet5(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch) +{ + m_config->setStarNet5(band, callsign, logoff, info, permanent, userTimeout, groupTimeout, callsignSwitch, txMsgSwitch); +} + +void CStarNetServerApp::getStarNet6(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch) const +{ + m_config->getStarNet6(band, callsign, logoff, info, permanent, userTimeout, groupTimeout, callsignSwitch, txMsgSwitch); +} + +void CStarNetServerApp::setStarNet6(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch) +{ + m_config->setStarNet6(band, callsign, logoff, info, permanent, userTimeout, groupTimeout, callsignSwitch, txMsgSwitch); +} + +void CStarNetServerApp::getStarNet7(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch) const +{ + m_config->getStarNet7(band, callsign, logoff, info, permanent, userTimeout, groupTimeout, callsignSwitch, txMsgSwitch); +} + +void CStarNetServerApp::setStarNet7(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch) +{ + m_config->setStarNet7(band, callsign, logoff, info, permanent, userTimeout, groupTimeout, callsignSwitch, txMsgSwitch); +} + +void CStarNetServerApp::getStarNet8(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch) const +{ + m_config->getStarNet8(band, callsign, logoff, info, permanent, userTimeout, groupTimeout, callsignSwitch, txMsgSwitch); +} + +void CStarNetServerApp::setStarNet8(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch) +{ + m_config->setStarNet8(band, callsign, logoff, info, permanent, userTimeout, groupTimeout, callsignSwitch, txMsgSwitch); +} + +void CStarNetServerApp::getStarNet9(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch) const +{ + m_config->getStarNet9(band, callsign, logoff, info, permanent, userTimeout, groupTimeout, callsignSwitch, txMsgSwitch); +} + +void CStarNetServerApp::setStarNet9(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch) +{ + m_config->setStarNet9(band, callsign, logoff, info, permanent, userTimeout, groupTimeout, callsignSwitch, txMsgSwitch); +} + +void CStarNetServerApp::getStarNet10(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch) const +{ + m_config->getStarNet10(band, callsign, logoff, info, permanent, userTimeout, groupTimeout, callsignSwitch, txMsgSwitch); +} + +void CStarNetServerApp::setStarNet10(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch) +{ + m_config->setStarNet10(band, callsign, logoff, info, permanent, userTimeout, groupTimeout, callsignSwitch, txMsgSwitch); +} + +void CStarNetServerApp::getStarNet11(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch) const +{ + m_config->getStarNet11(band, callsign, logoff, info, permanent, userTimeout, groupTimeout, callsignSwitch, txMsgSwitch); +} + +void CStarNetServerApp::setStarNet11(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch) +{ + m_config->setStarNet11(band, callsign, logoff, info, permanent, userTimeout, groupTimeout, callsignSwitch, txMsgSwitch); +} + +void CStarNetServerApp::getStarNet12(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch) const +{ + m_config->getStarNet12(band, callsign, logoff, info, permanent, userTimeout, groupTimeout, callsignSwitch, txMsgSwitch); +} + +void CStarNetServerApp::setStarNet12(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch) +{ + m_config->setStarNet12(band, callsign, logoff, info, permanent, userTimeout, groupTimeout, callsignSwitch, txMsgSwitch); +} + +void CStarNetServerApp::getStarNet13(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch) const +{ + m_config->getStarNet13(band, callsign, logoff, info, permanent, userTimeout, groupTimeout, callsignSwitch, txMsgSwitch); +} + +void CStarNetServerApp::setStarNet13(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch) +{ + m_config->setStarNet13(band, callsign, logoff, info, permanent, userTimeout, groupTimeout, callsignSwitch, txMsgSwitch); +} + +void CStarNetServerApp::getStarNet14(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch) const +{ + m_config->getStarNet14(band, callsign, logoff, info, permanent, userTimeout, groupTimeout, callsignSwitch, txMsgSwitch); +} + +void CStarNetServerApp::setStarNet14(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch) +{ + m_config->setStarNet14(band, callsign, logoff, info, permanent, userTimeout, groupTimeout, callsignSwitch, txMsgSwitch); +} + +void CStarNetServerApp::getStarNet15(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch) const +{ + m_config->getStarNet15(band, callsign, logoff, info, permanent, userTimeout, groupTimeout, callsignSwitch, txMsgSwitch); +} + +void CStarNetServerApp::setStarNet15(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch) +{ + m_config->setStarNet15(band, callsign, logoff, info, permanent, userTimeout, groupTimeout, callsignSwitch, txMsgSwitch); +} +#endif + +void CStarNetServerApp::getRemote(bool& enabled, wxString& password, unsigned int& port) const +{ + m_config->getRemote(enabled, password, port); +} + +void CStarNetServerApp::setRemote(bool enabled, const wxString& password, unsigned int port) +{ + m_config->setRemote(enabled, password, port); +} + +void CStarNetServerApp::getMiscellaneous(bool& logEnabled) const +{ + m_config->getMiscellaneous(logEnabled); +} + +void CStarNetServerApp::setMiscellaneous(bool logEnabled) +{ + m_config->setMiscellaneous(logEnabled); +} + +void CStarNetServerApp::getPosition(int& x, int& y) const +{ + m_config->getPosition(x, y); +} + +void CStarNetServerApp::setPosition(int x, int y) +{ + m_config->setPosition(x, y); +} + +bool CStarNetServerApp::writeConfig() +{ + return m_config->write(); +} + +void CStarNetServerApp::createThread() +{ + CStarNetServerThread* thread = new CStarNetServerThread(m_nolog, m_logDir); + + wxString callsign, address; + getGateway(callsign, address); + + callsign.Append(wxT(" ")); + callsign.Truncate(LONG_CALLSIGN_LENGTH - 1U); + callsign.Append(wxT("G")); + + wxLogInfo(wxT("Gateway callsign set to %s, local address set to %s"), callsign.c_str(), address.c_str()); + + bool logEnabled; + getMiscellaneous(logEnabled); + wxLogInfo(wxT("Log enabled set to %d"), int(logEnabled)); + + wxString hostname, username, password; + getIrcDDB(hostname, username, password); + wxLogInfo(wxT("ircDDB host set to %s, username set to %s"), hostname.c_str(), username.c_str()); + + if (!hostname.IsEmpty() && !username.IsEmpty()) { +#if defined(__WINDOWS__) + CIRCDDB* ircDDB = new CIRCDDBClient(hostname, 9007U, username, password, wxT("win_") + LOG_BASE_NAME + wxT("-") + VERSION, address); +#else + CIRCDDB* ircDDB = new CIRCDDBClient(hostname, 9007U, username, password, wxT("linux_") + LOG_BASE_NAME + wxT("-") + VERSION, address); +#endif + bool res = ircDDB->open(); + if (!res) + wxLogError(wxT("Cannot initialise the ircDDB protocol handler")); + else + thread->setIRC(ircDDB); + } + + wxString starNetBand1, starNetCallsign1, starNetLogoff1, starNetInfo1, starNetPermanent1, starNetLink1; // DEXTRA_LINK || DCS_LINK + unsigned int starNetUserTimeout1, starNetGroupTimeout1; + STARNET_CALLSIGN_SWITCH starNetCallsignSwitch1; + bool starNetTXMsgSwitch1; + getStarNet1(starNetBand1, starNetCallsign1, starNetLogoff1, starNetInfo1, starNetPermanent1, starNetUserTimeout1, starNetGroupTimeout1, starNetCallsignSwitch1, starNetTXMsgSwitch1 +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + ,starNetLink1 +#endif +); + + if (!starNetCallsign1.IsEmpty() && !starNetCallsign1.IsSameAs(wxT(" "))) { + wxString repeater = callsign; + repeater.Truncate(LONG_CALLSIGN_LENGTH - 1U); + repeater.Append(starNetBand1); + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + thread->addStarNet(starNetCallsign1, starNetLogoff1, repeater, starNetInfo1, starNetPermanent1, starNetUserTimeout1, starNetGroupTimeout1, starNetCallsignSwitch1, starNetTXMsgSwitch1, starNetLink1); + wxLogInfo(wxT("StarNet 1 set to %s/%s on repeater %s, info: \"%s\", permanent: %s, user: %u mins, group: %u mins, callsign switch: %d, tx msg switch: %d, reflector: %s"), starNetCallsign1.c_str(), starNetLogoff1.c_str(), repeater.c_str(), starNetInfo1.c_str(), starNetPermanent1.c_str(), starNetUserTimeout1, starNetGroupTimeout1, int(starNetCallsignSwitch1), int(starNetTXMsgSwitch1), starNetLink1.c_str()); +#else + thread->addStarNet(starNetCallsign1, starNetLogoff1, repeater, starNetInfo1, starNetPermanent1, starNetUserTimeout1, starNetGroupTimeout1, starNetCallsignSwitch1, starNetTXMsgSwitch1); + wxLogInfo(wxT("StarNet 1 set to %s/%s on repeater %s, info: \"%s\", permanent: %s, user: %u mins, group: %u mins, callsign switch: %d, tx msg switch: %d"), starNetCallsign1.c_str(), starNetLogoff1.c_str(), repeater.c_str(), starNetInfo1.c_str(), starNetPermanent1.c_str(), starNetUserTimeout1, starNetGroupTimeout1, int(starNetCallsignSwitch1), int(starNetTXMsgSwitch1)); +#endif + } + + wxString starNetBand2, starNetCallsign2, starNetLogoff2, starNetInfo2, starNetPermanent2, starNetLink2; // DEXTRA_LINK || DCS_LINK + unsigned int starNetUserTimeout2, starNetGroupTimeout2; + STARNET_CALLSIGN_SWITCH starNetCallsignSwitch2; + bool starNetTXMsgSwitch2; + getStarNet2(starNetBand2, starNetCallsign2, starNetLogoff2, starNetInfo2, starNetPermanent2, starNetUserTimeout2, starNetGroupTimeout2, starNetCallsignSwitch2, starNetTXMsgSwitch2 +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + ,starNetLink2 +#endif +); + + if (!starNetCallsign2.IsEmpty() && !starNetCallsign2.IsSameAs(wxT(" "))) { + wxString repeater = callsign; + repeater.Truncate(LONG_CALLSIGN_LENGTH - 1U); + repeater.Append(starNetBand2); + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + thread->addStarNet(starNetCallsign2, starNetLogoff2, repeater, starNetInfo2, starNetPermanent2, starNetUserTimeout2, starNetGroupTimeout2, starNetCallsignSwitch2, starNetTXMsgSwitch2, starNetLink2); + wxLogInfo(wxT("StarNet 2 set to %s/%s on repeater %s, info: \"%s\", permanent: %s, user: %u mins, group: %u mins, callsign switch: %d, tx msg switch: %d, reflector: %s"), starNetCallsign2.c_str(), starNetLogoff2.c_str(), repeater.c_str(), starNetInfo2.c_str(), starNetPermanent2.c_str(), starNetUserTimeout2, starNetGroupTimeout2, int(starNetCallsignSwitch2), int(starNetTXMsgSwitch2), starNetLink2.c_str()); +#else + thread->addStarNet(starNetCallsign2, starNetLogoff2, repeater, starNetInfo2, starNetPermanent2, starNetUserTimeout2, starNetGroupTimeout2, starNetCallsignSwitch2, starNetTXMsgSwitch2); + wxLogInfo(wxT("StarNet 2 set to %s/%s on repeater %s, info: \"%s\", permanent: %s, user: %u mins, group: %u mins, callsign switch: %d, tx msg switch: %d"), starNetCallsign2.c_str(), starNetLogoff2.c_str(), repeater.c_str(), starNetInfo2.c_str(), starNetPermanent2.c_str(), starNetUserTimeout2, starNetGroupTimeout2, int(starNetCallsignSwitch2), int(starNetTXMsgSwitch2)); +#endif + } + + wxString starNetBand3, starNetCallsign3, starNetLogoff3, starNetInfo3, starNetPermanent3, starNetLink3; // DEXTRA_LINK || DCS_LINK + unsigned int starNetUserTimeout3, starNetGroupTimeout3; + STARNET_CALLSIGN_SWITCH starNetCallsignSwitch3; + bool starNetTXMsgSwitch3; + getStarNet3(starNetBand3, starNetCallsign3, starNetLogoff3, starNetInfo3, starNetPermanent3, starNetUserTimeout3, starNetGroupTimeout3, starNetCallsignSwitch3, starNetTXMsgSwitch3 +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + ,starNetLink3 +#endif +); + + if (!starNetCallsign3.IsEmpty() && !starNetCallsign3.IsSameAs(wxT(" "))) { + wxString repeater = callsign; + repeater.Truncate(LONG_CALLSIGN_LENGTH - 1U); + repeater.Append(starNetBand3); + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + thread->addStarNet(starNetCallsign3, starNetLogoff3, repeater, starNetInfo3, starNetPermanent3, starNetUserTimeout3, starNetGroupTimeout3, starNetCallsignSwitch3, starNetTXMsgSwitch3, starNetLink3); + wxLogInfo(wxT("StarNet 3 set to %s/%s on repeater %s, info: \"%s\", permanent: %s, user: %u mins, group: %u mins, callsign switch: %d, tx msg switch: %d, reflector: %s"), starNetCallsign3.c_str(), starNetLogoff3.c_str(), repeater.c_str(), starNetInfo3.c_str(), starNetPermanent3.c_str(), starNetUserTimeout3, starNetGroupTimeout3, int(starNetCallsignSwitch3), int(starNetTXMsgSwitch3), starNetLink3.c_str()); +#else + thread->addStarNet(starNetCallsign3, starNetLogoff3, repeater, starNetInfo3, starNetPermanent3, starNetUserTimeout3, starNetGroupTimeout3, starNetCallsignSwitch3, starNetTXMsgSwitch3); + wxLogInfo(wxT("StarNet 3 set to %s/%s on repeater %s, info: \"%s\", permanent: %s, user: %u mins, group: %u mins, callsign switch: %d, tx msg switch: %d"), starNetCallsign3.c_str(), starNetLogoff3.c_str(), repeater.c_str(), starNetInfo3.c_str(), starNetPermanent3.c_str(), starNetUserTimeout3, starNetGroupTimeout3, int(starNetCallsignSwitch3), int(starNetTXMsgSwitch3)); +#endif + } + + wxString starNetBand4, starNetCallsign4, starNetLogoff4, starNetInfo4, starNetPermanent4, starNetLink4; // DEXTRA_LINK || DCS_LINK + unsigned int starNetUserTimeout4, starNetGroupTimeout4; + STARNET_CALLSIGN_SWITCH starNetCallsignSwitch4; + bool starNetTXMsgSwitch4; + getStarNet4(starNetBand4, starNetCallsign4, starNetLogoff4, starNetInfo4, starNetPermanent4, starNetUserTimeout4, starNetGroupTimeout4, starNetCallsignSwitch4, starNetTXMsgSwitch4 +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + ,starNetLink4 +#endif +); + + if (!starNetCallsign4.IsEmpty() && !starNetCallsign4.IsSameAs(wxT(" "))) { + wxString repeater = callsign; + repeater.Truncate(LONG_CALLSIGN_LENGTH - 1U); + repeater.Append(starNetBand4); + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + thread->addStarNet(starNetCallsign4, starNetLogoff4, repeater, starNetInfo4, starNetPermanent4, starNetUserTimeout4, starNetGroupTimeout4, starNetCallsignSwitch4, starNetTXMsgSwitch4, starNetLink4); + wxLogInfo(wxT("StarNet 4 set to %s/%s on repeater %s, info: \"%s\", permanent: %s, user: %u mins, group: %u mins, callsign switch: %d, tx msg switch: %d, reflector: %s"), starNetCallsign4.c_str(), starNetLogoff4.c_str(), repeater.c_str(), starNetInfo4.c_str(), starNetPermanent4.c_str(), starNetUserTimeout4, starNetGroupTimeout4, int(starNetCallsignSwitch4), int(starNetTXMsgSwitch4), starNetLink4.c_str()); +#else + thread->addStarNet(starNetCallsign4, starNetLogoff4, repeater, starNetInfo4, starNetPermanent4, starNetUserTimeout4, starNetGroupTimeout4, starNetCallsignSwitch4, starNetTXMsgSwitch4); + wxLogInfo(wxT("StarNet 4 set to %s/%s on repeater %s, info: \"%s\", permanent: %s, user: %u mins, group: %u mins, callsign switch: %d, tx msg switch: %d"), starNetCallsign4.c_str(), starNetLogoff4.c_str(), repeater.c_str(), starNetInfo4.c_str(), starNetPermanent4.c_str(), starNetUserTimeout4, starNetGroupTimeout4, int(starNetCallsignSwitch4), int(starNetTXMsgSwitch4)); +#endif + } + + wxString starNetBand5, starNetCallsign5, starNetLogoff5, starNetInfo5, starNetPermanent5, starNetLink5; // DEXTRA_LINK || DCS_LINK + unsigned int starNetUserTimeout5, starNetGroupTimeout5; + STARNET_CALLSIGN_SWITCH starNetCallsignSwitch5; + bool starNetTXMsgSwitch5; + getStarNet5(starNetBand5, starNetCallsign5, starNetLogoff5, starNetInfo5, starNetPermanent5, starNetUserTimeout5, starNetGroupTimeout5, starNetCallsignSwitch5, starNetTXMsgSwitch5 +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + ,starNetLink5 +#endif +); + + if (!starNetCallsign5.IsEmpty() && !starNetCallsign5.IsSameAs(wxT(" "))) { + wxString repeater = callsign; + repeater.Truncate(LONG_CALLSIGN_LENGTH - 1U); + repeater.Append(starNetBand5); + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + thread->addStarNet(starNetCallsign5, starNetLogoff5, repeater, starNetInfo5, starNetPermanent5, starNetUserTimeout5, starNetGroupTimeout5, starNetCallsignSwitch5, starNetTXMsgSwitch5, starNetLink5); + wxLogInfo(wxT("StarNet 5 set to %s/%s on repeater %s, info: \"%s\", permanent: %s, user: %u mins, group: %u mins, callsign switch: %d, tx msg switch: %d, reflector: %s"), starNetCallsign5.c_str(), starNetLogoff5.c_str(), repeater.c_str(), starNetInfo5.c_str(), starNetPermanent5.c_str(), starNetUserTimeout5, starNetGroupTimeout5, int(starNetCallsignSwitch5), int(starNetTXMsgSwitch5), starNetLink5.c_str()); +#else + thread->addStarNet(starNetCallsign5, starNetLogoff5, repeater, starNetInfo5, starNetPermanent5, starNetUserTimeout5, starNetGroupTimeout5, starNetCallsignSwitch5, starNetTXMsgSwitch5); + wxLogInfo(wxT("StarNet 5 set to %s/%s on repeater %s, info: \"%s\", permanent: %s, user: %u mins, group: %u mins, callsign switch: %d, tx msg switch: %d"), starNetCallsign5.c_str(), starNetLogoff5.c_str(), repeater.c_str(), starNetInfo5.c_str(), starNetPermanent5.c_str(), starNetUserTimeout5, starNetGroupTimeout5, int(starNetCallsignSwitch5), int(starNetTXMsgSwitch5)); +#endif + } + + wxString starNetBand6, starNetCallsign6, starNetLogoff6, starNetInfo6, starNetPermanent6, starNetLink6; // DEXTRA_LINK || DCS_LINK + unsigned int starNetUserTimeout6, starNetGroupTimeout6; + STARNET_CALLSIGN_SWITCH starNetCallsignSwitch6; + bool starNetTXMsgSwitch6; + getStarNet6(starNetBand6, starNetCallsign6, starNetLogoff6, starNetInfo6, starNetPermanent6, starNetUserTimeout6, starNetGroupTimeout6, starNetCallsignSwitch6, starNetTXMsgSwitch6 +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + ,starNetLink6 +#endif +); + + if (!starNetCallsign6.IsEmpty() && !starNetCallsign6.IsSameAs(wxT(" "))) { + wxString repeater = callsign; + repeater.Truncate(LONG_CALLSIGN_LENGTH - 1U); + repeater.Append(starNetBand6); + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + thread->addStarNet(starNetCallsign6, starNetLogoff6, repeater, starNetInfo6, starNetPermanent6, starNetUserTimeout6, starNetGroupTimeout6, starNetCallsignSwitch6, starNetTXMsgSwitch6, starNetLink6); + wxLogInfo(wxT("StarNet 6 set to %s/%s on repeater %s, info: \"%s\", permanent: %s, user: %u mins, group: %u mins, callsign switch: %d, tx msg switch: %d, reflector: %s"), starNetCallsign6.c_str(), starNetLogoff6.c_str(), repeater.c_str(), starNetInfo6.c_str(), starNetPermanent6.c_str(), starNetUserTimeout6, starNetGroupTimeout6, int(starNetCallsignSwitch6), int(starNetTXMsgSwitch6), starNetLink6.c_str()); +#else + thread->addStarNet(starNetCallsign6, starNetLogoff6, repeater, starNetInfo6, starNetPermanent6, starNetUserTimeout6, starNetGroupTimeout6, starNetCallsignSwitch6, starNetTXMsgSwitch6); + wxLogInfo(wxT("StarNet 6 set to %s/%s on repeater %s, info: \"%s\", permanent: %s, user: %u mins, group: %u mins, callsign switch: %d, tx msg switch: %d"), starNetCallsign6.c_str(), starNetLogoff6.c_str(), repeater.c_str(), starNetInfo6.c_str(), starNetPermanent6.c_str(), starNetUserTimeout6, starNetGroupTimeout6, int(starNetCallsignSwitch6), int(starNetTXMsgSwitch6)); +#endif + } + + wxString starNetBand7, starNetCallsign7, starNetLogoff7, starNetInfo7, starNetPermanent7, starNetLink7; // DEXTRA_LINK || DCS_LINK + unsigned int starNetUserTimeout7, starNetGroupTimeout7; + STARNET_CALLSIGN_SWITCH starNetCallsignSwitch7; + bool starNetTXMsgSwitch7; + getStarNet7(starNetBand7, starNetCallsign7, starNetLogoff7, starNetInfo7, starNetPermanent7, starNetUserTimeout7, starNetGroupTimeout7, starNetCallsignSwitch7, starNetTXMsgSwitch7 +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + ,starNetLink7 +#endif +); + + if (!starNetCallsign7.IsEmpty() && !starNetCallsign7.IsSameAs(wxT(" "))) { + wxString repeater = callsign; + repeater.Truncate(LONG_CALLSIGN_LENGTH - 1U); + repeater.Append(starNetBand7); + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + thread->addStarNet(starNetCallsign7, starNetLogoff7, repeater, starNetInfo7, starNetPermanent7, starNetUserTimeout7, starNetGroupTimeout7, starNetCallsignSwitch7, starNetTXMsgSwitch7, starNetLink7); + wxLogInfo(wxT("StarNet 7 set to %s/%s on repeater %s, info: \"%s\", permanent: %s, user: %u mins, group: %u mins, callsign switch: %d, tx msg switch: %d, reflector: %s"), starNetCallsign7.c_str(), starNetLogoff7.c_str(), repeater.c_str(), starNetInfo7.c_str(), starNetPermanent7.c_str(), starNetUserTimeout7, starNetGroupTimeout7, int(starNetCallsignSwitch7), int(starNetTXMsgSwitch7), starNetLink7.c_str()); +#else + thread->addStarNet(starNetCallsign7, starNetLogoff7, repeater, starNetInfo7, starNetPermanent7, starNetUserTimeout7, starNetGroupTimeout7, starNetCallsignSwitch7, starNetTXMsgSwitch7); + wxLogInfo(wxT("StarNet 7 set to %s/%s on repeater %s, info: \"%s\", permanent: %s, user: %u mins, group: %u mins, callsign switch: %d, tx msg switch: %d"), starNetCallsign7.c_str(), starNetLogoff7.c_str(), repeater.c_str(), starNetInfo7.c_str(), starNetPermanent7.c_str(), starNetUserTimeout7, starNetGroupTimeout7, int(starNetCallsignSwitch7), int(starNetTXMsgSwitch7)); +#endif + } + + wxString starNetBand8, starNetCallsign8, starNetLogoff8, starNetInfo8, starNetPermanent8, starNetLink8; // DEXTRA_LINK || DCS_LINK + unsigned int starNetUserTimeout8, starNetGroupTimeout8; + STARNET_CALLSIGN_SWITCH starNetCallsignSwitch8; + bool starNetTXMsgSwitch8; + getStarNet8(starNetBand8, starNetCallsign8, starNetLogoff8, starNetInfo8, starNetPermanent8, starNetUserTimeout8, starNetGroupTimeout8, starNetCallsignSwitch8, starNetTXMsgSwitch8 +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + ,starNetLink8 +#endif +); + + if (!starNetCallsign8.IsEmpty() && !starNetCallsign8.IsSameAs(wxT(" "))) { + wxString repeater = callsign; + repeater.Truncate(LONG_CALLSIGN_LENGTH - 1U); + repeater.Append(starNetBand8); + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + thread->addStarNet(starNetCallsign8, starNetLogoff8, repeater, starNetInfo8, starNetPermanent8, starNetUserTimeout8, starNetGroupTimeout8, starNetCallsignSwitch8, starNetTXMsgSwitch8, starNetLink8); + wxLogInfo(wxT("StarNet 8 set to %s/%s on repeater %s, info: \"%s\", permanent: %s, user: %u mins, group: %u mins, callsign switch: %d, tx msg switch: %d, reflector: %s"), starNetCallsign8.c_str(), starNetLogoff8.c_str(), repeater.c_str(), starNetInfo8.c_str(), starNetPermanent8.c_str(), starNetUserTimeout8, starNetGroupTimeout8, int(starNetCallsignSwitch8), int(starNetTXMsgSwitch8), starNetLink8.c_str()); +#else + thread->addStarNet(starNetCallsign8, starNetLogoff8, repeater, starNetInfo8, starNetPermanent8, starNetUserTimeout8, starNetGroupTimeout8, starNetCallsignSwitch8, starNetTXMsgSwitch8); + wxLogInfo(wxT("StarNet 8 set to %s/%s on repeater %s, info: \"%s\", permanent: %s, user: %u mins, group: %u mins, callsign switch: %d, tx msg switch: %d"), starNetCallsign8.c_str(), starNetLogoff8.c_str(), repeater.c_str(), starNetInfo8.c_str(), starNetPermanent8.c_str(), starNetUserTimeout8, starNetGroupTimeout8, int(starNetCallsignSwitch8), int(starNetTXMsgSwitch8)); +#endif + } + + wxString starNetBand9, starNetCallsign9, starNetLogoff9, starNetInfo9, starNetPermanent9, starNetLink9; // DEXTRA_LINK || DCS_LINK + unsigned int starNetUserTimeout9, starNetGroupTimeout9; + STARNET_CALLSIGN_SWITCH starNetCallsignSwitch9; + bool starNetTXMsgSwitch9; + getStarNet9(starNetBand9, starNetCallsign9, starNetLogoff9, starNetInfo9, starNetPermanent9, starNetUserTimeout9, starNetGroupTimeout9, starNetCallsignSwitch9, starNetTXMsgSwitch9 +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + ,starNetLink9 +#endif +); + + if (!starNetCallsign9.IsEmpty() && !starNetCallsign9.IsSameAs(wxT(" "))) { + wxString repeater = callsign; + repeater.Truncate(LONG_CALLSIGN_LENGTH - 1U); + repeater.Append(starNetBand9); + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + thread->addStarNet(starNetCallsign9, starNetLogoff9, repeater, starNetInfo9, starNetPermanent9, starNetUserTimeout9, starNetGroupTimeout9, starNetCallsignSwitch9, starNetTXMsgSwitch9, starNetLink9); + wxLogInfo(wxT("StarNet 9 set to %s/%s on repeater %s, info: \"%s\", permanent: %s, user: %u mins, group: %u mins, callsign switch: %d, tx msg switch: %d, reflector: %s"), starNetCallsign9.c_str(), starNetLogoff9.c_str(), repeater.c_str(), starNetInfo9.c_str(), starNetPermanent9.c_str(), starNetUserTimeout9, starNetGroupTimeout9, int(starNetCallsignSwitch9), int(starNetTXMsgSwitch9), starNetLink9.c_str()); +#else + thread->addStarNet(starNetCallsign9, starNetLogoff9, repeater, starNetInfo9, starNetPermanent9, starNetUserTimeout9, starNetGroupTimeout9, starNetCallsignSwitch9, starNetTXMsgSwitch9); + wxLogInfo(wxT("StarNet 9 set to %s/%s on repeater %s, info: \"%s\", permanent: %s, user: %u mins, group: %u mins, callsign switch: %d, tx msg switch: %d"), starNetCallsign9.c_str(), starNetLogoff9.c_str(), repeater.c_str(), starNetInfo9.c_str(), starNetPermanent9.c_str(), starNetUserTimeout9, starNetGroupTimeout9, int(starNetCallsignSwitch9), int(starNetTXMsgSwitch9)); +#endif + } + + wxString starNetBand10, starNetCallsign10, starNetLogoff10, starNetInfo10, starNetPermanent10, starNetLink10; // DEXTRA_LINK || DCS_LINK + unsigned int starNetUserTimeout10, starNetGroupTimeout10; + STARNET_CALLSIGN_SWITCH starNetCallsignSwitch10; + bool starNetTXMsgSwitch10; + getStarNet10(starNetBand10, starNetCallsign10, starNetLogoff10, starNetInfo10, starNetPermanent10, starNetUserTimeout10, starNetGroupTimeout10, starNetCallsignSwitch10, starNetTXMsgSwitch10 +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + ,starNetLink10 +#endif +); + + if (!starNetCallsign10.IsEmpty() && !starNetCallsign10.IsSameAs(wxT(" "))) { + wxString repeater = callsign; + repeater.Truncate(LONG_CALLSIGN_LENGTH - 1U); + repeater.Append(starNetBand10); + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + thread->addStarNet(starNetCallsign10, starNetLogoff10, repeater, starNetInfo10, starNetPermanent10, starNetUserTimeout10, starNetGroupTimeout10, starNetCallsignSwitch10, starNetTXMsgSwitch10, starNetLink10); + wxLogInfo(wxT("StarNet 10 set to %s/%s on repeater %s, info: \"%s\", permanent: %s, user: %u mins, group: %u mins, callsign switch: %d, tx msg switch: %d, reflector: %s"), starNetCallsign10.c_str(), starNetLogoff10.c_str(), repeater.c_str(), starNetInfo10.c_str(), starNetPermanent10.c_str(), starNetUserTimeout10, starNetGroupTimeout10, int(starNetCallsignSwitch10), int(starNetTXMsgSwitch10), starNetLink10.c_str()); +#else + thread->addStarNet(starNetCallsign10, starNetLogoff10, repeater, starNetInfo10, starNetPermanent10, starNetUserTimeout10, starNetGroupTimeout10, starNetCallsignSwitch10, starNetTXMsgSwitch10); + wxLogInfo(wxT("StarNet 10 set to %s/%s on repeater %s, info: \"%s\", permanent: %s, user: %u mins, group: %u mins, callsign switch: %d, tx msg switch: %d"), starNetCallsign10.c_str(), starNetLogoff10.c_str(), repeater.c_str(), starNetInfo10.c_str(), starNetPermanent10.c_str(), starNetUserTimeout10, starNetGroupTimeout10, int(starNetCallsignSwitch10), int(starNetTXMsgSwitch10)); +#endif + } + + wxString starNetBand11, starNetCallsign11, starNetLogoff11, starNetInfo11, starNetPermanent11, starNetLink11; // DEXTRA_LINK || DCS_LINK + unsigned int starNetUserTimeout11, starNetGroupTimeout11; + STARNET_CALLSIGN_SWITCH starNetCallsignSwitch11; + bool starNetTXMsgSwitch11; + getStarNet11(starNetBand11, starNetCallsign11, starNetLogoff11, starNetInfo11, starNetPermanent11, starNetUserTimeout11, starNetGroupTimeout11, starNetCallsignSwitch11, starNetTXMsgSwitch11 +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + ,starNetLink11 +#endif +); + + if (!starNetCallsign11.IsEmpty() && !starNetCallsign11.IsSameAs(wxT(" "))) { + wxString repeater = callsign; + repeater.Truncate(LONG_CALLSIGN_LENGTH - 1U); + repeater.Append(starNetBand11); + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + thread->addStarNet(starNetCallsign11, starNetLogoff11, repeater, starNetInfo11, starNetPermanent11, starNetUserTimeout11, starNetGroupTimeout11, starNetCallsignSwitch11, starNetTXMsgSwitch11, starNetLink11); + wxLogInfo(wxT("StarNet 11 set to %s/%s on repeater %s, info: \"%s\", permanent: %s, user: %u mins, group: %u mins, callsign switch: %d, tx msg switch: %d, reflector: %s"), starNetCallsign11.c_str(), starNetLogoff11.c_str(), repeater.c_str(), starNetInfo11.c_str(), starNetPermanent11.c_str(), starNetUserTimeout11, starNetGroupTimeout11, int(starNetCallsignSwitch11), int(starNetTXMsgSwitch11), starNetLink11.c_str()); +#else + thread->addStarNet(starNetCallsign11, starNetLogoff11, repeater, starNetInfo11, starNetPermanent11, starNetUserTimeout11, starNetGroupTimeout11, starNetCallsignSwitch11, starNetTXMsgSwitch11); + wxLogInfo(wxT("StarNet 11 set to %s/%s on repeater %s, info: \"%s\", permanent: %s, user: %u mins, group: %u mins, callsign switch: %d, tx msg switch: %d"), starNetCallsign11.c_str(), starNetLogoff11.c_str(), repeater.c_str(), starNetInfo11.c_str(), starNetPermanent11.c_str(), starNetUserTimeout11, starNetGroupTimeout11, int(starNetCallsignSwitch11), int(starNetTXMsgSwitch11)); +#endif + } + + wxString starNetBand12, starNetCallsign12, starNetLogoff12, starNetInfo12, starNetPermanent12, starNetLink12; // DEXTRA_LINK || DCS_LINK + unsigned int starNetUserTimeout12, starNetGroupTimeout12; + STARNET_CALLSIGN_SWITCH starNetCallsignSwitch12; + bool starNetTXMsgSwitch12; + getStarNet12(starNetBand12, starNetCallsign12, starNetLogoff12, starNetInfo12, starNetPermanent12, starNetUserTimeout12, starNetGroupTimeout12, starNetCallsignSwitch12, starNetTXMsgSwitch12 +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + ,starNetLink12 +#endif +); + + if (!starNetCallsign12.IsEmpty() && !starNetCallsign12.IsSameAs(wxT(" "))) { + wxString repeater = callsign; + repeater.Truncate(LONG_CALLSIGN_LENGTH - 1U); + repeater.Append(starNetBand12); + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + thread->addStarNet(starNetCallsign12, starNetLogoff12, repeater, starNetInfo12, starNetPermanent12, starNetUserTimeout12, starNetGroupTimeout12, starNetCallsignSwitch12, starNetTXMsgSwitch12, starNetLink12); + wxLogInfo(wxT("StarNet 12 set to %s/%s on repeater %s, info: \"%s\", permanent: %s, user: %u mins, group: %u mins, callsign switch: %d, tx msg switch: %d, reflector: %s"), starNetCallsign12.c_str(), starNetLogoff12.c_str(), repeater.c_str(), starNetInfo12.c_str(), starNetPermanent12.c_str(), starNetUserTimeout12, starNetGroupTimeout12, int(starNetCallsignSwitch12), int(starNetTXMsgSwitch12), starNetLink12.c_str()); +#else + thread->addStarNet(starNetCallsign12, starNetLogoff12, repeater, starNetInfo12, starNetPermanent12, starNetUserTimeout12, starNetGroupTimeout12, starNetCallsignSwitch12, starNetTXMsgSwitch12); + wxLogInfo(wxT("StarNet 12 set to %s/%s on repeater %s, info: \"%s\", permanent: %s, user: %u mins, group: %u mins, callsign switch: %d, tx msg switch: %d"), starNetCallsign12.c_str(), starNetLogoff12.c_str(), repeater.c_str(), starNetInfo12.c_str(), starNetPermanent12.c_str(), starNetUserTimeout12, starNetGroupTimeout12, int(starNetCallsignSwitch12), int(starNetTXMsgSwitch12)); +#endif + } + + wxString starNetBand13, starNetCallsign13, starNetLogoff13, starNetInfo13, starNetPermanent13, starNetLink13; // DEXTRA_LINK || DCS_LINK + unsigned int starNetUserTimeout13, starNetGroupTimeout13; + STARNET_CALLSIGN_SWITCH starNetCallsignSwitch13; + bool starNetTXMsgSwitch13; + getStarNet13(starNetBand13, starNetCallsign13, starNetLogoff13, starNetInfo13, starNetPermanent13, starNetUserTimeout13, starNetGroupTimeout13, starNetCallsignSwitch13, starNetTXMsgSwitch13 +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + ,starNetLink13 +#endif +); + + if (!starNetCallsign13.IsEmpty() && !starNetCallsign13.IsSameAs(wxT(" "))) { + wxString repeater = callsign; + repeater.Truncate(LONG_CALLSIGN_LENGTH - 1U); + repeater.Append(starNetBand13); + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + thread->addStarNet(starNetCallsign13, starNetLogoff13, repeater, starNetInfo13, starNetPermanent13, starNetUserTimeout13, starNetGroupTimeout13, starNetCallsignSwitch13, starNetTXMsgSwitch13, starNetLink13); + wxLogInfo(wxT("StarNet 13 set to %s/%s on repeater %s, info: \"%s\", permanent: %s, user: %u mins, group: %u mins, callsign switch: %d, tx msg switch: %d, reflector: %s"), starNetCallsign13.c_str(), starNetLogoff13.c_str(), repeater.c_str(), starNetInfo13.c_str(), starNetPermanent13.c_str(), starNetUserTimeout13, starNetGroupTimeout13, int(starNetCallsignSwitch13), int(starNetTXMsgSwitch13), starNetLink13.c_str()); +#else + thread->addStarNet(starNetCallsign13, starNetLogoff13, repeater, starNetInfo13, starNetPermanent13, starNetUserTimeout13, starNetGroupTimeout13, starNetCallsignSwitch13, starNetTXMsgSwitch13); + wxLogInfo(wxT("StarNet 13 set to %s/%s on repeater %s, info: \"%s\", permanent: %s, user: %u mins, group: %u mins, callsign switch: %d, tx msg switch: %d"), starNetCallsign13.c_str(), starNetLogoff13.c_str(), repeater.c_str(), starNetInfo13.c_str(), starNetPermanent13.c_str(), starNetUserTimeout13, starNetGroupTimeout13, int(starNetCallsignSwitch13), int(starNetTXMsgSwitch13)); +#endif + } + + wxString starNetBand14, starNetCallsign14, starNetLogoff14, starNetInfo14, starNetPermanent14, starNetLink14; // DEXTRA_LINK || DCS_LINK + unsigned int starNetUserTimeout14, starNetGroupTimeout14; + STARNET_CALLSIGN_SWITCH starNetCallsignSwitch14; + bool starNetTXMsgSwitch14; + getStarNet14(starNetBand14, starNetCallsign14, starNetLogoff14, starNetInfo14, starNetPermanent14, starNetUserTimeout14, starNetGroupTimeout14, starNetCallsignSwitch14, starNetTXMsgSwitch14 +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + ,starNetLink14 +#endif +); + + if (!starNetCallsign14.IsEmpty() && !starNetCallsign14.IsSameAs(wxT(" "))) { + wxString repeater = callsign; + repeater.Truncate(LONG_CALLSIGN_LENGTH - 1U); + repeater.Append(starNetBand14); + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + thread->addStarNet(starNetCallsign14, starNetLogoff14, repeater, starNetInfo14, starNetPermanent14, starNetUserTimeout14, starNetGroupTimeout14, starNetCallsignSwitch14, starNetTXMsgSwitch14, starNetLink14); + wxLogInfo(wxT("StarNet 14 set to %s/%s on repeater %s, info: \"%s\", permanent: %s, user: %u mins, group: %u mins, callsign switch: %d, tx msg switch: %d, reflector: %s"), starNetCallsign14.c_str(), starNetLogoff14.c_str(), repeater.c_str(), starNetInfo14.c_str(), starNetPermanent14.c_str(), starNetUserTimeout14, starNetGroupTimeout14, int(starNetCallsignSwitch14), int(starNetTXMsgSwitch14), starNetLink14.c_str()); +#else + thread->addStarNet(starNetCallsign14, starNetLogoff14, repeater, starNetInfo14, starNetPermanent14, starNetUserTimeout14, starNetGroupTimeout14, starNetCallsignSwitch14, starNetTXMsgSwitch14); + wxLogInfo(wxT("StarNet 14 set to %s/%s on repeater %s, info: \"%s\", permanent: %s, user: %u mins, group: %u mins, callsign switch: %d, tx msg switch: %d"), starNetCallsign14.c_str(), starNetLogoff14.c_str(), repeater.c_str(), starNetInfo14.c_str(), starNetPermanent14.c_str(), starNetUserTimeout14, starNetGroupTimeout14, int(starNetCallsignSwitch14), int(starNetTXMsgSwitch14)); +#endif + } + + wxString starNetBand15, starNetCallsign15, starNetLogoff15, starNetInfo15, starNetPermanent15, starNetLink15; // DEXTRA_LINK || DCS_LINK + unsigned int starNetUserTimeout15, starNetGroupTimeout15; + STARNET_CALLSIGN_SWITCH starNetCallsignSwitch15; + bool starNetTXMsgSwitch15; + getStarNet15(starNetBand15, starNetCallsign15, starNetLogoff15, starNetInfo15, starNetPermanent15, starNetUserTimeout15, starNetGroupTimeout15, starNetCallsignSwitch15, starNetTXMsgSwitch15 +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + ,starNetLink15 +#endif +); + + if (!starNetCallsign15.IsEmpty() && !starNetCallsign15.IsSameAs(wxT(" "))) { + wxString repeater = callsign; + repeater.Truncate(LONG_CALLSIGN_LENGTH - 1U); + repeater.Append(starNetBand15); + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + thread->addStarNet(starNetCallsign15, starNetLogoff15, repeater, starNetInfo15, starNetPermanent15, starNetUserTimeout15, starNetGroupTimeout15, starNetCallsignSwitch15, starNetTXMsgSwitch15, starNetLink15); + wxLogInfo(wxT("StarNet 15 set to %s/%s on repeater %s, info: \"%s\", permanent: %s, user: %u mins, group: %u mins, callsign switch: %d, tx msg switch: %d, reflector: %s"), starNetCallsign15.c_str(), starNetLogoff15.c_str(), repeater.c_str(), starNetInfo15.c_str(), starNetPermanent15.c_str(), starNetUserTimeout15, starNetGroupTimeout15, int(starNetCallsignSwitch15), int(starNetTXMsgSwitch15), starNetLink15.c_str()); +#else + thread->addStarNet(starNetCallsign15, starNetLogoff15, repeater, starNetInfo15, starNetPermanent15, starNetUserTimeout15, starNetGroupTimeout15, starNetCallsignSwitch15, starNetTXMsgSwitch15); + wxLogInfo(wxT("StarNet 15 set to %s/%s on repeater %s, info: \"%s\", permanent: %s, user: %u mins, group: %u mins, callsign switch: %d, tx msg switch: %d"), starNetCallsign15.c_str(), starNetLogoff15.c_str(), repeater.c_str(), starNetInfo15.c_str(), starNetPermanent15.c_str(), starNetUserTimeout15, starNetGroupTimeout15, int(starNetCallsignSwitch15), int(starNetTXMsgSwitch15)); +#endif + } + + bool remoteEnabled; + wxString remotePassword; + unsigned int remotePort; + getRemote(remoteEnabled, remotePassword, remotePort); + wxLogInfo(wxT("Remote enabled set to %d, port set to %u"), int(remoteEnabled), remotePort); + thread->setRemote(remoteEnabled, remotePassword, remotePort); + + thread->setLog(logEnabled); + thread->setAddress(address); + thread->setCallsign(callsign); + + // Convert the worker class into a thread + m_thread = new CStarNetServerThreadHelper(thread); + m_thread->start(); +} diff --git a/StarNetServer/StarNetServerApp.h b/StarNetServer/StarNetServerApp.h new file mode 100644 index 0000000..c97689e --- /dev/null +++ b/StarNetServer/StarNetServerApp.h @@ -0,0 +1,172 @@ +/* + * Copyright (C) 2010,2011,2012 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef StarNetServerApp_H +#define StarNetServerApp_H + +#include "StarNetServerThreadHelper.h" +#include "StarNetServerConfig.h" +#include "StarNetServerFrame.h" +#include "Defs.h" + +#include + +class CStarNetServerApp : public wxApp { + +public: + CStarNetServerApp(); + virtual ~CStarNetServerApp(); + + virtual bool OnInit(); + virtual int OnExit(); + + virtual void OnInitCmdLine(wxCmdLineParser& parser); + virtual bool OnCmdLineParsed(wxCmdLineParser& parser); + + // This is overridden because dialog boxes from threads are bad news +#if defined(__WXDEBUG__) + virtual void OnAssertFailure(const wxChar* file, int line, const wxChar* func, const wxChar* cond, const wxChar* msg); +#endif + + virtual void showLog(const wxString& text); + + virtual void getGateway(wxString& callsign, wxString& address) const; + virtual void setGateway(const wxString& callsign, const wxString& address); + + virtual void getIrcDDB(wxString& hostname, wxString& username, wxString& password) const; + virtual void setIrcDDB(const wxString& hostname, const wxString& username, const wxString& password); + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + virtual void getStarNet1(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch, wxString& reflector) const; + virtual void setStarNet1(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch, const wxString& reflector); + + virtual void getStarNet2(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch, wxString& reflector) const; + virtual void setStarNet2(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch, const wxString& reflector); + + virtual void getStarNet3(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch, wxString& reflector) const; + virtual void setStarNet3(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch, const wxString& reflector); + + virtual void getStarNet4(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch, wxString& reflector) const; + virtual void setStarNet4(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch, const wxString& reflector); + + virtual void getStarNet5(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch, wxString& reflector) const; + virtual void setStarNet5(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch, const wxString& reflector); + + virtual void getStarNet6(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch, wxString& reflector) const; + virtual void setStarNet6(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch, const wxString& reflector); + + virtual void getStarNet7(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch, wxString& reflector) const; + virtual void setStarNet7(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch, const wxString& reflector); + + virtual void getStarNet8(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch, wxString& reflector) const; + virtual void setStarNet8(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch, const wxString& reflector); + + virtual void getStarNet9(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch, wxString& reflector) const; + virtual void setStarNet9(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch, const wxString& reflector); + + virtual void getStarNet10(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch, wxString& reflector) const; + virtual void setStarNet10(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch, const wxString& reflector); + + virtual void getStarNet11(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch, wxString& reflector) const; + virtual void setStarNet11(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch, const wxString& reflector); + + virtual void getStarNet12(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch, wxString& reflector) const; + virtual void setStarNet12(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch, const wxString& reflector); + + virtual void getStarNet13(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch, wxString& reflector) const; + virtual void setStarNet13(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch, const wxString& reflector); + + virtual void getStarNet14(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch, wxString& reflector) const; + virtual void setStarNet14(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch, const wxString& reflector); + + virtual void getStarNet15(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch, wxString& reflector) const; + virtual void setStarNet15(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch, const wxString& reflector); +#else + virtual void getStarNet1(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch) const; + virtual void setStarNet1(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch); + + virtual void getStarNet2(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch) const; + virtual void setStarNet2(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch); + + virtual void getStarNet3(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch) const; + virtual void setStarNet3(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch); + + virtual void getStarNet4(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch) const; + virtual void setStarNet4(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch); + + virtual void getStarNet5(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch) const; + virtual void setStarNet5(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch); + + virtual void getStarNet6(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch) const; + virtual void setStarNet6(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch); + + virtual void getStarNet7(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch) const; + virtual void setStarNet7(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch); + + virtual void getStarNet8(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch) const; + virtual void setStarNet8(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch); + + virtual void getStarNet9(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch) const; + virtual void setStarNet9(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch); + + virtual void getStarNet10(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch) const; + virtual void setStarNet10(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch); + + virtual void getStarNet11(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch) const; + virtual void setStarNet11(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch); + + virtual void getStarNet12(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch) const; + virtual void setStarNet12(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch); + + virtual void getStarNet13(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch) const; + virtual void setStarNet13(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch); + + virtual void getStarNet14(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch) const; + virtual void setStarNet14(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch); + + virtual void getStarNet15(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch) const; + virtual void setStarNet15(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch); +#endif + + virtual void getRemote(bool& enabled, wxString& password, unsigned int& port) const; + virtual void setRemote(bool enabled, const wxString& password, unsigned int port); + + virtual void getMiscellaneous(bool& logEnabled) const; + virtual void setMiscellaneous(bool logEnabled); + + virtual void getPosition(int& x, int& y) const; + virtual void setPosition(int x, int y); + + virtual bool writeConfig(); + +private: + bool m_nolog; + bool m_gui; + wxString m_logDir; + wxString m_confDir; + CStarNetServerFrame* m_frame; + CStarNetServerThreadHelper* m_thread; + CStarNetServerConfig* m_config; + wxLogChain* m_logChain; + + void createThread(); +}; + +DECLARE_APP(CStarNetServerApp) + +#endif diff --git a/StarNetServer/StarNetServerAppD.cpp b/StarNetServer/StarNetServerAppD.cpp new file mode 100644 index 0000000..5fd1610 --- /dev/null +++ b/StarNetServer/StarNetServerAppD.cpp @@ -0,0 +1,561 @@ +/* + * Copyright (C) 2010-2015 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "IcomRepeaterProtocolHandler.h" +#include "HBRepeaterProtocolHandler.h" +#include "StarNetServerConfig.h" +#include "StarNetServerAppD.h" +#include "StarNetServerDefs.h" +#include "APRSWriter.h" +#include "Version.h" +#include "Logger.h" +#include "IRCDDBClient.h" + +#include +#include +#include +#include + +#include +#include +#include + +const wxChar* NOLOGGING_SWITCH = wxT("nolog"); +const wxChar* LOGDIR_OPTION = wxT("logdir"); +const wxChar* CONFDIR_OPTION = wxT("confdir"); +const wxChar* DAEMON_SWITCH = wxT("daemon"); + + +int main(int argc, char** argv) +{ + bool res = ::wxInitialize(); + if (!res) { + ::fprintf(stderr, "starnetserverd: failed to initialise the wxWidgets library, exiting\n"); + return -1; + } + + wxCmdLineParser parser(argc, argv); + parser.AddSwitch(NOLOGGING_SWITCH, wxEmptyString, wxEmptyString, wxCMD_LINE_PARAM_OPTIONAL); + parser.AddSwitch(DAEMON_SWITCH, wxEmptyString, wxEmptyString, wxCMD_LINE_PARAM_OPTIONAL); + parser.AddOption(LOGDIR_OPTION, wxEmptyString, wxEmptyString, wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL); + parser.AddOption(CONFDIR_OPTION, wxEmptyString, wxEmptyString, wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL); + + int cmd = parser.Parse(); + if (cmd != 0) { + ::wxUninitialize(); + return 0; + } + + bool nolog = parser.Found(NOLOGGING_SWITCH); + bool daemon = parser.Found(DAEMON_SWITCH); + + wxString logDir; + bool found = parser.Found(LOGDIR_OPTION, &logDir); + if (!found) + logDir.Clear(); + + wxString confDir; + found = parser.Found(CONFDIR_OPTION, &confDir); + if (!found) + confDir = wxT(CONF_DIR); + + if (daemon) { + pid_t pid = ::fork(); + + if (pid < 0) { + ::fprintf(stderr, "starnetserverd: error in fork(), exiting\n"); + ::wxUninitialize(); + return 1; + } + + // If this is the parent, exit + if (pid > 0) + return 0; + + // We are the child from here onwards + ::setsid(); + + ::chdir("/"); + + ::umask(0); + } + + CStarNetServerAppD gateway(nolog, logDir, confDir); + + if (!gateway.init()) { + ::wxUninitialize(); + return 1; + } + + gateway.run(); + + ::wxUninitialize(); + return 0; +} + +CStarNetServerAppD::CStarNetServerAppD(bool nolog, const wxString& logDir, const wxString& confDir) : +m_nolog(nolog), +m_logDir(logDir), +m_confDir(confDir), +m_thread(NULL) +{ +} + +CStarNetServerAppD::~CStarNetServerAppD() +{ +} + +bool CStarNetServerAppD::init() +{ + if (!m_nolog) { + if (m_logDir.IsEmpty()) + m_logDir = wxT(LOG_DIR); + + wxLog* log = new CLogger(m_logDir, LOG_BASE_NAME); + wxLog::SetActiveTarget(log); + } else { + new wxLogNull; + } + + wxLogInfo(wxT("Starting ") + APPLICATION_NAME + wxT(" daemon - ") + VERSION); + + // Log the version of wxWidgets and the Operating System + wxLogInfo(wxT("Using wxWidgets %d.%d.%d on %s"), wxMAJOR_VERSION, wxMINOR_VERSION, wxRELEASE_NUMBER, ::wxGetOsDescription().c_str()); + + return createThread(); +} + +void CStarNetServerAppD::run() +{ + m_thread->run(); + + wxLogInfo(APPLICATION_NAME + wxT(" is exiting")); +} + +bool CStarNetServerAppD::createThread() +{ + CStarNetServerConfig config(m_confDir); + + m_thread = new CStarNetServerThread(m_nolog, m_logDir); + + wxString callsign, address; + config.getGateway(callsign, address); + + callsign.Append(wxT(" ")); + callsign.Truncate(LONG_CALLSIGN_LENGTH - 1U); + callsign.Append(wxT("G")); + + wxLogInfo(wxT("Gateway callsign set to %s, local address set to %s"), callsign.c_str(), address.c_str()); + + bool logEnabled; + config.getMiscellaneous(logEnabled); + wxLogInfo(wxT("Log enabled set to %d"), int(logEnabled)); + + wxString hostname, username, password; + config.getIrcDDB(hostname, username, password); + wxLogInfo(wxT("ircDDB host set to %s, username set to %s"), hostname.c_str(), username.c_str()); + + if (!hostname.IsEmpty() && !username.IsEmpty()) { +#if defined(__WINDOWS__) + CIRCDDB* ircDDB = new CIRCDDBClient(hostname, 9007U, username, password, wxT("win_") + LOG_BASE_NAME + wxT("-") + VERSION, address); +#else + CIRCDDB* ircDDB = new CIRCDDBClient(hostname, 9007U, username, password, wxT("linux_") + LOG_BASE_NAME + wxT("-") + VERSION, address); +#endif + bool res = ircDDB->open(); + if (!res) { + wxLogError(wxT("Cannot initialise the ircDDB protocol handler")); + return false; + } + + m_thread->setIRC(ircDDB); + } + + wxString starNetBand1, starNetCallsign1, starNetLogoff1, starNetInfo1, starNetPermanent1, starNetLink1; // DEXTRA_LINK || DCS_LINK + unsigned int starNetUserTimeout1, starNetGroupTimeout1; + STARNET_CALLSIGN_SWITCH starNetCallsignSwitch1; + bool starNetTXMsgSwitch1; + config.getStarNet1(starNetBand1, starNetCallsign1, starNetLogoff1, starNetInfo1, starNetPermanent1, starNetUserTimeout1, starNetGroupTimeout1, starNetCallsignSwitch1, starNetTXMsgSwitch1 +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + ,starNetLink1 +#endif +); + + if (!starNetCallsign1.IsEmpty() && !starNetCallsign1.IsSameAs(wxT(" "))) { + wxString repeater = callsign; + repeater.Truncate(LONG_CALLSIGN_LENGTH - 1U); + repeater.Append(starNetBand1); + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + m_thread->addStarNet(starNetCallsign1, starNetLogoff1, repeater, starNetInfo1, starNetPermanent1, starNetUserTimeout1, starNetGroupTimeout1, starNetCallsignSwitch1, starNetTXMsgSwitch1, starNetLink1); + wxLogInfo(wxT("StarNet 1 set to %s/%s on repeater %s, info: \"%s\", permanent: %s, user: %u mins, group: %u mins, callsign switch: %d, tx msg switch: %d, reflector: %s"), starNetCallsign1.c_str(), starNetLogoff1.c_str(), repeater.c_str(), starNetInfo1.c_str(), starNetPermanent1.c_str(), starNetUserTimeout1, starNetGroupTimeout1, int(starNetCallsignSwitch1), int(starNetTXMsgSwitch1), starNetLink1.c_str()); +#else + m_thread->addStarNet(starNetCallsign1, starNetLogoff1, repeater, starNetInfo1, starNetPermanent1, starNetUserTimeout1, starNetGroupTimeout1, starNetCallsignSwitch1, starNetTXMsgSwitch1); + wxLogInfo(wxT("StarNet 1 set to %s/%s on repeater %s, info: \"%s\", permanent: %s, user: %u mins, group: %u mins, callsign switch: %d, tx msg switch: %d"), starNetCallsign1.c_str(), starNetLogoff1.c_str(), repeater.c_str(), starNetInfo1.c_str(), starNetPermanent1.c_str(), starNetUserTimeout1, starNetGroupTimeout1, int(starNetCallsignSwitch1), int(starNetTXMsgSwitch1)); +#endif + } + + wxString starNetBand2, starNetCallsign2, starNetLogoff2, starNetInfo2, starNetPermanent2, starNetLink2; // DEXTRA_LINK || DCS_LINK + unsigned int starNetUserTimeout2, starNetGroupTimeout2; + STARNET_CALLSIGN_SWITCH starNetCallsignSwitch2; + bool starNetTXMsgSwitch2; + config.getStarNet2(starNetBand2, starNetCallsign2, starNetLogoff2, starNetInfo2, starNetPermanent2, starNetUserTimeout2, starNetGroupTimeout2, starNetCallsignSwitch2, starNetTXMsgSwitch2 +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + ,starNetLink2 +#endif +); + + if (!starNetCallsign2.IsEmpty() && !starNetCallsign2.IsSameAs(wxT(" "))) { + wxString repeater = callsign; + repeater.Truncate(LONG_CALLSIGN_LENGTH - 1U); + repeater.Append(starNetBand2); + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + m_thread->addStarNet(starNetCallsign2, starNetLogoff2, repeater, starNetInfo2, starNetPermanent2, starNetUserTimeout2, starNetGroupTimeout2, starNetCallsignSwitch2, starNetTXMsgSwitch2, starNetLink2); + wxLogInfo(wxT("StarNet 2 set to %s/%s on repeater %s, info: \"%s\", permanent: %s, user: %u mins, group: %u mins, callsign switch: %d, tx msg switch: %d, reflector: %s"), starNetCallsign2.c_str(), starNetLogoff2.c_str(), repeater.c_str(), starNetInfo2.c_str(), starNetPermanent2.c_str(), starNetUserTimeout2, starNetGroupTimeout2, int(starNetCallsignSwitch2), int(starNetTXMsgSwitch2), starNetLink2.c_str()); +#else + m_thread->addStarNet(starNetCallsign2, starNetLogoff2, repeater, starNetInfo2, starNetPermanent2, starNetUserTimeout2, starNetGroupTimeout2, starNetCallsignSwitch2, starNetTXMsgSwitch2); + wxLogInfo(wxT("StarNet 2 set to %s/%s on repeater %s, info: \"%s\", permanent: %s, user: %u mins, group: %u mins, callsign switch: %d, tx msg switch: %d"), starNetCallsign2.c_str(), starNetLogoff2.c_str(), repeater.c_str(), starNetInfo2.c_str(), starNetPermanent2.c_str(), starNetUserTimeout2, starNetGroupTimeout2, int(starNetCallsignSwitch2), int(starNetTXMsgSwitch2)); +#endif + } + + wxString starNetBand3, starNetCallsign3, starNetLogoff3, starNetInfo3, starNetPermanent3, starNetLink3; // DEXTRA_LINK || DCS_LINK + unsigned int starNetUserTimeout3, starNetGroupTimeout3; + STARNET_CALLSIGN_SWITCH starNetCallsignSwitch3; + bool starNetTXMsgSwitch3; + config.getStarNet3(starNetBand3, starNetCallsign3, starNetLogoff3, starNetInfo3, starNetPermanent3, starNetUserTimeout3, starNetGroupTimeout3, starNetCallsignSwitch3, starNetTXMsgSwitch3 +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + ,starNetLink3 +#endif +); + + if (!starNetCallsign3.IsEmpty() && !starNetCallsign3.IsSameAs(wxT(" "))) { + wxString repeater = callsign; + repeater.Truncate(LONG_CALLSIGN_LENGTH - 1U); + repeater.Append(starNetBand3); + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + m_thread->addStarNet(starNetCallsign3, starNetLogoff3, repeater, starNetInfo3, starNetPermanent3, starNetUserTimeout3, starNetGroupTimeout3, starNetCallsignSwitch3, starNetTXMsgSwitch3, starNetLink3); + wxLogInfo(wxT("StarNet 3 set to %s/%s on repeater %s, info: \"%s\", permanent: %s, user: %u mins, group: %u mins, callsign switch: %d, tx msg switch: %d, reflector: %s"), starNetCallsign3.c_str(), starNetLogoff3.c_str(), repeater.c_str(), starNetInfo3.c_str(), starNetPermanent3.c_str(), starNetUserTimeout3, starNetGroupTimeout3, int(starNetCallsignSwitch3), int(starNetTXMsgSwitch3), starNetLink3.c_str()); +#else + m_thread->addStarNet(starNetCallsign3, starNetLogoff3, repeater, starNetInfo3, starNetPermanent3, starNetUserTimeout3, starNetGroupTimeout3, starNetCallsignSwitch3, starNetTXMsgSwitch3); + wxLogInfo(wxT("StarNet 3 set to %s/%s on repeater %s, info: \"%s\", permanent: %s, user: %u mins, group: %u mins, callsign switch: %d, tx msg switch: %d"), starNetCallsign3.c_str(), starNetLogoff3.c_str(), repeater.c_str(), starNetInfo3.c_str(), starNetPermanent3.c_str(), starNetUserTimeout3, starNetGroupTimeout3, int(starNetCallsignSwitch3), int(starNetTXMsgSwitch3)); +#endif + } + + wxString starNetBand4, starNetCallsign4, starNetLogoff4, starNetInfo4, starNetPermanent4, starNetLink4; // DEXTRA_LINK || DCS_LINK + unsigned int starNetUserTimeout4, starNetGroupTimeout4; + STARNET_CALLSIGN_SWITCH starNetCallsignSwitch4; + bool starNetTXMsgSwitch4; + config.getStarNet4(starNetBand4, starNetCallsign4, starNetLogoff4, starNetInfo4, starNetPermanent4, starNetUserTimeout4, starNetGroupTimeout4, starNetCallsignSwitch4, starNetTXMsgSwitch4 +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + ,starNetLink4 +#endif +); + + if (!starNetCallsign4.IsEmpty() && !starNetCallsign4.IsSameAs(wxT(" "))) { + wxString repeater = callsign; + repeater.Truncate(LONG_CALLSIGN_LENGTH - 1U); + repeater.Append(starNetBand4); + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + m_thread->addStarNet(starNetCallsign4, starNetLogoff4, repeater, starNetInfo4, starNetPermanent4, starNetUserTimeout4, starNetGroupTimeout4, starNetCallsignSwitch4, starNetTXMsgSwitch4, starNetLink4); + wxLogInfo(wxT("StarNet 4 set to %s/%s on repeater %s, info: \"%s\", permanent: %s, user: %u mins, group: %u mins, callsign switch: %d, tx msg switch: %d, reflector: %s"), starNetCallsign4.c_str(), starNetLogoff4.c_str(), repeater.c_str(), starNetInfo4.c_str(), starNetPermanent4.c_str(), starNetUserTimeout4, starNetGroupTimeout4, int(starNetCallsignSwitch4), int(starNetTXMsgSwitch4), starNetLink4.c_str()); +#else + m_thread->addStarNet(starNetCallsign4, starNetLogoff4, repeater, starNetInfo4, starNetPermanent4, starNetUserTimeout4, starNetGroupTimeout4, starNetCallsignSwitch4, starNetTXMsgSwitch4); + wxLogInfo(wxT("StarNet 4 set to %s/%s on repeater %s, info: \"%s\", permanent: %s, user: %u mins, group: %u mins, callsign switch: %d, tx msg switch: %d"), starNetCallsign4.c_str(), starNetLogoff4.c_str(), repeater.c_str(), starNetInfo4.c_str(), starNetPermanent4.c_str(), starNetUserTimeout4, starNetGroupTimeout4, int(starNetCallsignSwitch4), int(starNetTXMsgSwitch4)); +#endif + } + + wxString starNetBand5, starNetCallsign5, starNetLogoff5, starNetInfo5, starNetPermanent5, starNetLink5; // DEXTRA_LINK || DCS_LINK + unsigned int starNetUserTimeout5, starNetGroupTimeout5; + STARNET_CALLSIGN_SWITCH starNetCallsignSwitch5; + bool starNetTXMsgSwitch5; + config.getStarNet5(starNetBand5, starNetCallsign5, starNetLogoff5, starNetInfo5, starNetPermanent5, starNetUserTimeout5, starNetGroupTimeout5, starNetCallsignSwitch5, starNetTXMsgSwitch5 +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + ,starNetLink5 +#endif +); + + if (!starNetCallsign5.IsEmpty() && !starNetCallsign5.IsSameAs(wxT(" "))) { + wxString repeater = callsign; + repeater.Truncate(LONG_CALLSIGN_LENGTH - 1U); + repeater.Append(starNetBand5); + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + m_thread->addStarNet(starNetCallsign5, starNetLogoff5, repeater, starNetInfo5, starNetPermanent5, starNetUserTimeout5, starNetGroupTimeout5, starNetCallsignSwitch5, starNetTXMsgSwitch5, starNetLink5); + wxLogInfo(wxT("StarNet 5 set to %s/%s on repeater %s, info: \"%s\", permanent: %s, user: %u mins, group: %u mins, callsign switch: %d, tx msg switch: %d, reflector: %s"), starNetCallsign5.c_str(), starNetLogoff5.c_str(), repeater.c_str(), starNetInfo5.c_str(), starNetPermanent5.c_str(), starNetUserTimeout5, starNetGroupTimeout5, int(starNetCallsignSwitch5), int(starNetTXMsgSwitch5), starNetLink5.c_str()); +#else + m_thread->addStarNet(starNetCallsign5, starNetLogoff5, repeater, starNetInfo5, starNetPermanent5, starNetUserTimeout5, starNetGroupTimeout5, starNetCallsignSwitch5, starNetTXMsgSwitch5); + wxLogInfo(wxT("StarNet 5 set to %s/%s on repeater %s, info: \"%s\", permanent: %s, user: %u mins, group: %u mins, callsign switch: %d, tx msg switch: %d"), starNetCallsign5.c_str(), starNetLogoff5.c_str(), repeater.c_str(), starNetInfo5.c_str(), starNetPermanent5.c_str(), starNetUserTimeout5, starNetGroupTimeout5, int(starNetCallsignSwitch5), int(starNetTXMsgSwitch5)); +#endif + } + + wxString starNetBand6, starNetCallsign6, starNetLogoff6, starNetInfo6, starNetPermanent6, starNetLink6; // DEXTRA_LINK || DCS_LINK + unsigned int starNetUserTimeout6, starNetGroupTimeout6; + STARNET_CALLSIGN_SWITCH starNetCallsignSwitch6; + bool starNetTXMsgSwitch6; + config.getStarNet6(starNetBand6, starNetCallsign6, starNetLogoff6, starNetInfo6, starNetPermanent6, starNetUserTimeout6, starNetGroupTimeout6, starNetCallsignSwitch6, starNetTXMsgSwitch6 +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + ,starNetLink6 +#endif +); + + if (!starNetCallsign6.IsEmpty() && !starNetCallsign6.IsSameAs(wxT(" "))) { + wxString repeater = callsign; + repeater.Truncate(LONG_CALLSIGN_LENGTH - 1U); + repeater.Append(starNetBand6); + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + m_thread->addStarNet(starNetCallsign6, starNetLogoff6, repeater, starNetInfo6, starNetPermanent6, starNetUserTimeout6, starNetGroupTimeout6, starNetCallsignSwitch6, starNetTXMsgSwitch6, starNetLink6); + wxLogInfo(wxT("StarNet 6 set to %s/%s on repeater %s, info: \"%s\", permanent: %s, user: %u mins, group: %u mins, callsign switch: %d, tx msg switch: %d, reflector: %s"), starNetCallsign6.c_str(), starNetLogoff6.c_str(), repeater.c_str(), starNetInfo6.c_str(), starNetPermanent6.c_str(), starNetUserTimeout6, starNetGroupTimeout6, int(starNetCallsignSwitch6), int(starNetTXMsgSwitch6), starNetLink6.c_str()); +#else + m_thread->addStarNet(starNetCallsign6, starNetLogoff6, repeater, starNetInfo6, starNetPermanent6, starNetUserTimeout6, starNetGroupTimeout6, starNetCallsignSwitch6, starNetTXMsgSwitch6); + wxLogInfo(wxT("StarNet 6 set to %s/%s on repeater %s, info: \"%s\", permanent: %s, user: %u mins, group: %u mins, callsign switch: %d, tx msg switch: %d"), starNetCallsign6.c_str(), starNetLogoff6.c_str(), repeater.c_str(), starNetInfo6.c_str(), starNetPermanent6.c_str(), starNetUserTimeout6, starNetGroupTimeout6, int(starNetCallsignSwitch6), int(starNetTXMsgSwitch6)); +#endif + } + + wxString starNetBand7, starNetCallsign7, starNetLogoff7, starNetInfo7, starNetPermanent7, starNetLink7; // DEXTRA_LINK || DCS_LINK + unsigned int starNetUserTimeout7, starNetGroupTimeout7; + STARNET_CALLSIGN_SWITCH starNetCallsignSwitch7; + bool starNetTXMsgSwitch7; + config.getStarNet7(starNetBand7, starNetCallsign7, starNetLogoff7, starNetInfo7, starNetPermanent7, starNetUserTimeout7, starNetGroupTimeout7, starNetCallsignSwitch7, starNetTXMsgSwitch7 +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + ,starNetLink7 +#endif +); + + if (!starNetCallsign7.IsEmpty() && !starNetCallsign7.IsSameAs(wxT(" "))) { + wxString repeater = callsign; + repeater.Truncate(LONG_CALLSIGN_LENGTH - 1U); + repeater.Append(starNetBand7); + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + m_thread->addStarNet(starNetCallsign7, starNetLogoff7, repeater, starNetInfo7, starNetPermanent7, starNetUserTimeout7, starNetGroupTimeout7, starNetCallsignSwitch7, starNetTXMsgSwitch7, starNetLink7); + wxLogInfo(wxT("StarNet 7 set to %s/%s on repeater %s, info: \"%s\", permanent: %s, user: %u mins, group: %u mins, callsign switch: %d, tx msg switch: %d, reflector: %s"), starNetCallsign7.c_str(), starNetLogoff7.c_str(), repeater.c_str(), starNetInfo7.c_str(), starNetPermanent7.c_str(), starNetUserTimeout7, starNetGroupTimeout7, int(starNetCallsignSwitch7), int(starNetTXMsgSwitch7), starNetLink7.c_str()); +#else + m_thread->addStarNet(starNetCallsign7, starNetLogoff7, repeater, starNetInfo7, starNetPermanent7, starNetUserTimeout7, starNetGroupTimeout7, starNetCallsignSwitch7, starNetTXMsgSwitch7); + wxLogInfo(wxT("StarNet 7 set to %s/%s on repeater %s, info: \"%s\", permanent: %s, user: %u mins, group: %u mins, callsign switch: %d, tx msg switch: %d"), starNetCallsign7.c_str(), starNetLogoff7.c_str(), repeater.c_str(), starNetInfo7.c_str(), starNetPermanent7.c_str(), starNetUserTimeout7, starNetGroupTimeout7, int(starNetCallsignSwitch7), int(starNetTXMsgSwitch7)); +#endif + } + + wxString starNetBand8, starNetCallsign8, starNetLogoff8, starNetInfo8, starNetPermanent8, starNetLink8; // DEXTRA_LINK || DCS_LINK + unsigned int starNetUserTimeout8, starNetGroupTimeout8; + STARNET_CALLSIGN_SWITCH starNetCallsignSwitch8; + bool starNetTXMsgSwitch8; + config.getStarNet8(starNetBand8, starNetCallsign8, starNetLogoff8, starNetInfo8, starNetPermanent8, starNetUserTimeout8, starNetGroupTimeout8, starNetCallsignSwitch8, starNetTXMsgSwitch8 +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + ,starNetLink8 +#endif +); + + if (!starNetCallsign8.IsEmpty() && !starNetCallsign8.IsSameAs(wxT(" "))) { + wxString repeater = callsign; + repeater.Truncate(LONG_CALLSIGN_LENGTH - 1U); + repeater.Append(starNetBand8); + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + m_thread->addStarNet(starNetCallsign8, starNetLogoff8, repeater, starNetInfo8, starNetPermanent8, starNetUserTimeout8, starNetGroupTimeout8, starNetCallsignSwitch8, starNetTXMsgSwitch8, starNetLink8); + wxLogInfo(wxT("StarNet 8 set to %s/%s on repeater %s, info: \"%s\", permanent: %s, user: %u mins, group: %u mins, callsign switch: %d, tx msg switch: %d, reflector: %s"), starNetCallsign8.c_str(), starNetLogoff8.c_str(), repeater.c_str(), starNetInfo8.c_str(), starNetPermanent8.c_str(), starNetUserTimeout8, starNetGroupTimeout8, int(starNetCallsignSwitch8), int(starNetTXMsgSwitch8), starNetLink8.c_str()); +#else + m_thread->addStarNet(starNetCallsign8, starNetLogoff8, repeater, starNetInfo8, starNetPermanent8, starNetUserTimeout8, starNetGroupTimeout8, starNetCallsignSwitch8, starNetTXMsgSwitch8); + wxLogInfo(wxT("StarNet 8 set to %s/%s on repeater %s, info: \"%s\", permanent: %s, user: %u mins, group: %u mins, callsign switch: %d, tx msg switch: %d"), starNetCallsign8.c_str(), starNetLogoff8.c_str(), repeater.c_str(), starNetInfo8.c_str(), starNetPermanent8.c_str(), starNetUserTimeout8, starNetGroupTimeout8, int(starNetCallsignSwitch8), int(starNetTXMsgSwitch8)); +#endif + } + + wxString starNetBand9, starNetCallsign9, starNetLogoff9, starNetInfo9, starNetPermanent9, starNetLink9; // DEXTRA_LINK || DCS_LINK + unsigned int starNetUserTimeout9, starNetGroupTimeout9; + STARNET_CALLSIGN_SWITCH starNetCallsignSwitch9; + bool starNetTXMsgSwitch9; + config.getStarNet9(starNetBand9, starNetCallsign9, starNetLogoff9, starNetInfo9, starNetPermanent9, starNetUserTimeout9, starNetGroupTimeout9, starNetCallsignSwitch9, starNetTXMsgSwitch9 +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + ,starNetLink9 +#endif +); + + if (!starNetCallsign9.IsEmpty() && !starNetCallsign9.IsSameAs(wxT(" "))) { + wxString repeater = callsign; + repeater.Truncate(LONG_CALLSIGN_LENGTH - 1U); + repeater.Append(starNetBand9); + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + m_thread->addStarNet(starNetCallsign9, starNetLogoff9, repeater, starNetInfo9, starNetPermanent9, starNetUserTimeout9, starNetGroupTimeout9, starNetCallsignSwitch9, starNetTXMsgSwitch9, starNetLink9); + wxLogInfo(wxT("StarNet 9 set to %s/%s on repeater %s, info: \"%s\", permanent: %s, user: %u mins, group: %u mins, callsign switch: %d, tx msg switch: %d, reflector: %s"), starNetCallsign9.c_str(), starNetLogoff9.c_str(), repeater.c_str(), starNetInfo9.c_str(), starNetPermanent9.c_str(), starNetUserTimeout9, starNetGroupTimeout9, int(starNetCallsignSwitch9), int(starNetTXMsgSwitch9), starNetLink9.c_str()); +#else + m_thread->addStarNet(starNetCallsign9, starNetLogoff9, repeater, starNetInfo9, starNetPermanent9, starNetUserTimeout9, starNetGroupTimeout9, starNetCallsignSwitch9, starNetTXMsgSwitch9); + wxLogInfo(wxT("StarNet 9 set to %s/%s on repeater %s, info: \"%s\", permanent: %s, user: %u mins, group: %u mins, callsign switch: %d, tx msg switch: %d"), starNetCallsign9.c_str(), starNetLogoff9.c_str(), repeater.c_str(), starNetInfo9.c_str(), starNetPermanent9.c_str(), starNetUserTimeout9, starNetGroupTimeout9, int(starNetCallsignSwitch9), int(starNetTXMsgSwitch9)); +#endif + } + + wxString starNetBand10, starNetCallsign10, starNetLogoff10, starNetInfo10, starNetPermanent10, starNetLink10; // DEXTRA_LINK || DCS_LINK + unsigned int starNetUserTimeout10, starNetGroupTimeout10; + STARNET_CALLSIGN_SWITCH starNetCallsignSwitch10; + bool starNetTXMsgSwitch10; + config.getStarNet10(starNetBand10, starNetCallsign10, starNetLogoff10, starNetInfo10, starNetPermanent10, starNetUserTimeout10, starNetGroupTimeout10, starNetCallsignSwitch10, starNetTXMsgSwitch10 +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + ,starNetLink10 +#endif +); + + if (!starNetCallsign10.IsEmpty() && !starNetCallsign10.IsSameAs(wxT(" "))) { + wxString repeater = callsign; + repeater.Truncate(LONG_CALLSIGN_LENGTH - 1U); + repeater.Append(starNetBand10); + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + m_thread->addStarNet(starNetCallsign10, starNetLogoff10, repeater, starNetInfo10, starNetPermanent10, starNetUserTimeout10, starNetGroupTimeout10, starNetCallsignSwitch10, starNetTXMsgSwitch10, starNetLink10); + wxLogInfo(wxT("StarNet 10 set to %s/%s on repeater %s, info: \"%s\", permanent: %s, user: %u mins, group: %u mins, callsign switch: %d, tx msg switch: %d, reflector: %s"), starNetCallsign10.c_str(), starNetLogoff10.c_str(), repeater.c_str(), starNetInfo10.c_str(), starNetPermanent10.c_str(), starNetUserTimeout10, starNetGroupTimeout10, int(starNetCallsignSwitch10), int(starNetTXMsgSwitch10), starNetLink10.c_str()); +#else + m_thread->addStarNet(starNetCallsign10, starNetLogoff10, repeater, starNetInfo10, starNetPermanent10, starNetUserTimeout10, starNetGroupTimeout10, starNetCallsignSwitch10, starNetTXMsgSwitch10); + wxLogInfo(wxT("StarNet 10 set to %s/%s on repeater %s, info: \"%s\", permanent: %s, user: %u mins, group: %u mins, callsign switch: %d, tx msg switch: %d"), starNetCallsign10.c_str(), starNetLogoff10.c_str(), repeater.c_str(), starNetInfo10.c_str(), starNetPermanent10.c_str(), starNetUserTimeout10, starNetGroupTimeout10, int(starNetCallsignSwitch10), int(starNetTXMsgSwitch10)); +#endif + } + + wxString starNetBand11, starNetCallsign11, starNetLogoff11, starNetInfo11, starNetPermanent11, starNetLink11; // DEXTRA_LINK || DCS_LINK + unsigned int starNetUserTimeout11, starNetGroupTimeout11; + STARNET_CALLSIGN_SWITCH starNetCallsignSwitch11; + bool starNetTXMsgSwitch11; + config.getStarNet11(starNetBand11, starNetCallsign11, starNetLogoff11, starNetInfo11, starNetPermanent11, starNetUserTimeout11, starNetGroupTimeout11, starNetCallsignSwitch11, starNetTXMsgSwitch11 +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + ,starNetLink11 +#endif +); + + if (!starNetCallsign11.IsEmpty() && !starNetCallsign11.IsSameAs(wxT(" "))) { + wxString repeater = callsign; + repeater.Truncate(LONG_CALLSIGN_LENGTH - 1U); + repeater.Append(starNetBand11); + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + m_thread->addStarNet(starNetCallsign11, starNetLogoff11, repeater, starNetInfo11, starNetPermanent11, starNetUserTimeout11, starNetGroupTimeout11, starNetCallsignSwitch11, starNetTXMsgSwitch11, starNetLink11); + wxLogInfo(wxT("StarNet 11 set to %s/%s on repeater %s, info: \"%s\", permanent: %s, user: %u mins, group: %u mins, callsign switch: %d, tx msg switch: %d, reflector: %s"), starNetCallsign11.c_str(), starNetLogoff11.c_str(), repeater.c_str(), starNetInfo11.c_str(), starNetPermanent11.c_str(), starNetUserTimeout11, starNetGroupTimeout11, int(starNetCallsignSwitch11), int(starNetTXMsgSwitch11), starNetLink11.c_str()); +#else + m_thread->addStarNet(starNetCallsign11, starNetLogoff11, repeater, starNetInfo11, starNetPermanent11, starNetUserTimeout11, starNetGroupTimeout11, starNetCallsignSwitch11, starNetTXMsgSwitch11); + wxLogInfo(wxT("StarNet 11 set to %s/%s on repeater %s, info: \"%s\", permanent: %s, user: %u mins, group: %u mins, callsign switch: %d, tx msg switch: %d"), starNetCallsign11.c_str(), starNetLogoff11.c_str(), repeater.c_str(), starNetInfo11.c_str(), starNetPermanent11.c_str(), starNetUserTimeout11, starNetGroupTimeout11, int(starNetCallsignSwitch11), int(starNetTXMsgSwitch11)); +#endif + } + + wxString starNetBand12, starNetCallsign12, starNetLogoff12, starNetInfo12, starNetPermanent12, starNetLink12; // DEXTRA_LINK || DCS_LINK + unsigned int starNetUserTimeout12, starNetGroupTimeout12; + STARNET_CALLSIGN_SWITCH starNetCallsignSwitch12; + bool starNetTXMsgSwitch12; + config.getStarNet12(starNetBand12, starNetCallsign12, starNetLogoff12, starNetInfo12, starNetPermanent12, starNetUserTimeout12, starNetGroupTimeout12, starNetCallsignSwitch12, starNetTXMsgSwitch12 +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + ,starNetLink12 +#endif +); + + if (!starNetCallsign12.IsEmpty() && !starNetCallsign12.IsSameAs(wxT(" "))) { + wxString repeater = callsign; + repeater.Truncate(LONG_CALLSIGN_LENGTH - 1U); + repeater.Append(starNetBand12); + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + m_thread->addStarNet(starNetCallsign12, starNetLogoff12, repeater, starNetInfo12, starNetPermanent12, starNetUserTimeout12, starNetGroupTimeout12, starNetCallsignSwitch12, starNetTXMsgSwitch12, starNetLink12); + wxLogInfo(wxT("StarNet 12 set to %s/%s on repeater %s, info: \"%s\", permanent: %s, user: %u mins, group: %u mins, callsign switch: %d, tx msg switch: %d, reflector: %s"), starNetCallsign12.c_str(), starNetLogoff12.c_str(), repeater.c_str(), starNetInfo12.c_str(), starNetPermanent12.c_str(), starNetUserTimeout12, starNetGroupTimeout12, int(starNetCallsignSwitch12), int(starNetTXMsgSwitch12), starNetLink12.c_str()); +#else + m_thread->addStarNet(starNetCallsign12, starNetLogoff12, repeater, starNetInfo12, starNetPermanent12, starNetUserTimeout12, starNetGroupTimeout12, starNetCallsignSwitch12, starNetTXMsgSwitch12); + wxLogInfo(wxT("StarNet 12 set to %s/%s on repeater %s, info: \"%s\", permanent: %s, user: %u mins, group: %u mins, callsign switch: %d, tx msg switch: %d"), starNetCallsign12.c_str(), starNetLogoff12.c_str(), repeater.c_str(), starNetInfo12.c_str(), starNetPermanent12.c_str(), starNetUserTimeout12, starNetGroupTimeout12, int(starNetCallsignSwitch12), int(starNetTXMsgSwitch12)); +#endif + } + + wxString starNetBand13, starNetCallsign13, starNetLogoff13, starNetInfo13, starNetPermanent13, starNetLink13; // DEXTRA_LINK || DCS_LINK + unsigned int starNetUserTimeout13, starNetGroupTimeout13; + STARNET_CALLSIGN_SWITCH starNetCallsignSwitch13; + bool starNetTXMsgSwitch13; + config.getStarNet13(starNetBand13, starNetCallsign13, starNetLogoff13, starNetInfo13, starNetPermanent13, starNetUserTimeout13, starNetGroupTimeout13, starNetCallsignSwitch13, starNetTXMsgSwitch13 +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + ,starNetLink13 +#endif +); + + if (!starNetCallsign13.IsEmpty() && !starNetCallsign13.IsSameAs(wxT(" "))) { + wxString repeater = callsign; + repeater.Truncate(LONG_CALLSIGN_LENGTH - 1U); + repeater.Append(starNetBand13); + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + m_thread->addStarNet(starNetCallsign13, starNetLogoff13, repeater, starNetInfo13, starNetPermanent13, starNetUserTimeout13, starNetGroupTimeout13, starNetCallsignSwitch13, starNetTXMsgSwitch13, starNetLink13); + wxLogInfo(wxT("StarNet 13 set to %s/%s on repeater %s, info: \"%s\", permanent: %s, user: %u mins, group: %u mins, callsign switch: %d, tx msg switch: %d, reflector: %s"), starNetCallsign13.c_str(), starNetLogoff13.c_str(), repeater.c_str(), starNetInfo13.c_str(), starNetPermanent13.c_str(), starNetUserTimeout13, starNetGroupTimeout13, int(starNetCallsignSwitch13), int(starNetTXMsgSwitch13), starNetLink13.c_str()); +#else + m_thread->addStarNet(starNetCallsign13, starNetLogoff13, repeater, starNetInfo13, starNetPermanent13, starNetUserTimeout13, starNetGroupTimeout13, starNetCallsignSwitch13, starNetTXMsgSwitch13); + wxLogInfo(wxT("StarNet 13 set to %s/%s on repeater %s, info: \"%s\", permanent: %s, user: %u mins, group: %u mins, callsign switch: %d, tx msg switch: %d"), starNetCallsign13.c_str(), starNetLogoff13.c_str(), repeater.c_str(), starNetInfo13.c_str(), starNetPermanent13.c_str(), starNetUserTimeout13, starNetGroupTimeout13, int(starNetCallsignSwitch13), int(starNetTXMsgSwitch13)); +#endif + } + + wxString starNetBand14, starNetCallsign14, starNetLogoff14, starNetInfo14, starNetPermanent14, starNetLink14; // DEXTRA_LINK || DCS_LINK + unsigned int starNetUserTimeout14, starNetGroupTimeout14; + STARNET_CALLSIGN_SWITCH starNetCallsignSwitch14; + bool starNetTXMsgSwitch14; + config.getStarNet14(starNetBand14, starNetCallsign14, starNetLogoff14, starNetInfo14, starNetPermanent14, starNetUserTimeout14, starNetGroupTimeout14, starNetCallsignSwitch14, starNetTXMsgSwitch14 +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + ,starNetLink14 +#endif +); + + if (!starNetCallsign14.IsEmpty() && !starNetCallsign14.IsSameAs(wxT(" "))) { + wxString repeater = callsign; + repeater.Truncate(LONG_CALLSIGN_LENGTH - 1U); + repeater.Append(starNetBand14); + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + m_thread->addStarNet(starNetCallsign14, starNetLogoff14, repeater, starNetInfo14, starNetPermanent14, starNetUserTimeout14, starNetGroupTimeout14, starNetCallsignSwitch14, starNetTXMsgSwitch14, starNetLink14); + wxLogInfo(wxT("StarNet 14 set to %s/%s on repeater %s, info: \"%s\", permanent: %s, user: %u mins, group: %u mins, callsign switch: %d, tx msg switch: %d, reflector: %s"), starNetCallsign14.c_str(), starNetLogoff14.c_str(), repeater.c_str(), starNetInfo14.c_str(), starNetPermanent14.c_str(), starNetUserTimeout14, starNetGroupTimeout14, int(starNetCallsignSwitch14), int(starNetTXMsgSwitch14), starNetLink14.c_str()); +#else + m_thread->addStarNet(starNetCallsign14, starNetLogoff14, repeater, starNetInfo14, starNetPermanent14, starNetUserTimeout14, starNetGroupTimeout14, starNetCallsignSwitch14, starNetTXMsgSwitch14); + wxLogInfo(wxT("StarNet 14 set to %s/%s on repeater %s, info: \"%s\", permanent: %s, user: %u mins, group: %u mins, callsign switch: %d, tx msg switch: %d"), starNetCallsign14.c_str(), starNetLogoff14.c_str(), repeater.c_str(), starNetInfo14.c_str(), starNetPermanent14.c_str(), starNetUserTimeout14, starNetGroupTimeout14, int(starNetCallsignSwitch14), int(starNetTXMsgSwitch14)); +#endif + } + + wxString starNetBand15, starNetCallsign15, starNetLogoff15, starNetInfo15, starNetPermanent15, starNetLink15; // DEXTRA_LINK || DCS_LINK + unsigned int starNetUserTimeout15, starNetGroupTimeout15; + STARNET_CALLSIGN_SWITCH starNetCallsignSwitch15; + bool starNetTXMsgSwitch15; + config.getStarNet15(starNetBand15, starNetCallsign15, starNetLogoff15, starNetInfo15, starNetPermanent15, starNetUserTimeout15, starNetGroupTimeout15, starNetCallsignSwitch15, starNetTXMsgSwitch15 +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + ,starNetLink15 +#endif +); + + if (!starNetCallsign15.IsEmpty() && !starNetCallsign15.IsSameAs(wxT(" "))) { + wxString repeater = callsign; + repeater.Truncate(LONG_CALLSIGN_LENGTH - 1U); + repeater.Append(starNetBand15); + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + m_thread->addStarNet(starNetCallsign15, starNetLogoff15, repeater, starNetInfo15, starNetPermanent15, starNetUserTimeout15, starNetGroupTimeout15, starNetCallsignSwitch15, starNetTXMsgSwitch15, starNetLink15); + wxLogInfo(wxT("StarNet 15 set to %s/%s on repeater %s, info: \"%s\", permanent: %s, user: %u mins, group: %u mins, callsign switch: %d, tx msg switch: %d, reflector: %s"), starNetCallsign15.c_str(), starNetLogoff15.c_str(), repeater.c_str(), starNetInfo15.c_str(), starNetPermanent15.c_str(), starNetUserTimeout15, starNetGroupTimeout15, int(starNetCallsignSwitch15), int(starNetTXMsgSwitch15), starNetLink15.c_str()); +#else + m_thread->addStarNet(starNetCallsign15, starNetLogoff15, repeater, starNetInfo15, starNetPermanent15, starNetUserTimeout15, starNetGroupTimeout15, starNetCallsignSwitch15, starNetTXMsgSwitch15); + wxLogInfo(wxT("StarNet 15 set to %s/%s on repeater %s, info: \"%s\", permanent: %s, user: %u mins, group: %u mins, callsign switch: %d, tx msg switch: %d"), starNetCallsign15.c_str(), starNetLogoff15.c_str(), repeater.c_str(), starNetInfo15.c_str(), starNetPermanent15.c_str(), starNetUserTimeout15, starNetGroupTimeout15, int(starNetCallsignSwitch15), int(starNetTXMsgSwitch15)); +#endif + } + + bool remoteEnabled; + wxString remotePassword; + unsigned int remotePort; + config.getRemote(remoteEnabled, remotePassword, remotePort); + wxLogInfo(wxT("Remote enabled set to %d, port set to %u"), int(remoteEnabled), remotePort); + m_thread->setRemote(remoteEnabled, remotePassword, remotePort); + + m_thread->setLog(logEnabled); + m_thread->setAddress(address); + m_thread->setCallsign(callsign); + + return true; +} + diff --git a/StarNetServer/StarNetServerAppD.h b/StarNetServer/StarNetServerAppD.h new file mode 100644 index 0000000..05380bb --- /dev/null +++ b/StarNetServer/StarNetServerAppD.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2010,2011 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef StarNetServerAppD_H +#define StarNetServerAppD_H + +#include "StarNetServerThread.h" + +#include +#include + +class CStarNetServerAppD { + +public: + CStarNetServerAppD(bool nolog, const wxString& logDir, const wxString& confDir); + ~CStarNetServerAppD(); + + bool init(); + + void run(); + +private: + bool m_nolog; + wxString m_logDir; + wxString m_confDir; + CStarNetServerThread* m_thread; + + bool createThread(); +}; + +#endif diff --git a/StarNetServer/StarNetServerCallsignSet.cpp b/StarNetServer/StarNetServerCallsignSet.cpp new file mode 100644 index 0000000..fdb68f9 --- /dev/null +++ b/StarNetServer/StarNetServerCallsignSet.cpp @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2010,2011 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "StarNetServerCallsignSet.h" +#include "DStarDefines.h" +#include + +const unsigned int CALLSIGN_WIDTH = 120U; +const unsigned int ADDRESS_WIDTH = 120U; + +const unsigned int ADDRESS_LENGTH = 15U; + +const unsigned int BORDER_SIZE = 5U; + +CStarNetServerCallsignSet::CStarNetServerCallsignSet(wxWindow* parent, int id, const wxString& title, const wxString& callsign, const wxString& address) : +wxPanel(parent, id), +m_title(title), +m_callsign(NULL), +m_address(NULL) +{ + wxFlexGridSizer* sizer = new wxFlexGridSizer(3); + + wxStaticText* callsignLabel = new wxStaticText(this, -1, _("Callsign")); + sizer->Add(callsignLabel, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + wxString call = callsign; + call.Truncate(LONG_CALLSIGN_LENGTH - 1U); + call.Trim(); + + m_callsign = new CCallsignTextCtrl(this, -1, call, wxDefaultPosition, wxSize(CALLSIGN_WIDTH, -1)); + m_callsign->SetMaxLength(LONG_CALLSIGN_LENGTH); + sizer->Add(m_callsign, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + + wxStaticText* gLabel = new wxStaticText(this, -1, wxT("G")); + sizer->Add(gLabel, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + wxStaticText* addressLabel = new wxStaticText(this, -1, _("Address")); + sizer->Add(addressLabel, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + m_address = new CAddressTextCtrl(this, -1, address, wxDefaultPosition, wxSize(ADDRESS_WIDTH, -1)); + m_address->SetMaxLength(ADDRESS_LENGTH); + sizer->Add(m_address, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + + SetAutoLayout(true); + + SetSizer(sizer); +} + + +CStarNetServerCallsignSet::~CStarNetServerCallsignSet() +{ +} + +bool CStarNetServerCallsignSet::Validate() +{ + wxString callsign = getCallsign(); + + if (callsign.IsEmpty()) { + wxMessageDialog dialog(this, _("The Callsign Callsign is not valid"), m_title + _(" Error"), wxICON_ERROR); + dialog.ShowModal(); + return false; + } + + return true; +} + +wxString CStarNetServerCallsignSet::getCallsign() const +{ + wxString callsign = m_callsign->GetValue(); + + callsign.MakeUpper(); + + return callsign; +} + +wxString CStarNetServerCallsignSet::getAddress() const +{ + return m_address->GetValue(); +} diff --git a/StarNetServer/StarNetServerCallsignSet.h b/StarNetServer/StarNetServerCallsignSet.h new file mode 100644 index 0000000..8b05c7c --- /dev/null +++ b/StarNetServer/StarNetServerCallsignSet.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2010,2011 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef StarNetServerCallsignSet_H +#define StarNetServerCallsignSet_H + +#include "CallsignTextCtrl.h" +#include "AddressTextCtrl.h" +#include "Defs.h" + +#include + +class CStarNetServerCallsignSet : public wxPanel { +public: + CStarNetServerCallsignSet(wxWindow* parent, int id, const wxString& title, const wxString& callsign, const wxString& address); + virtual ~CStarNetServerCallsignSet(); + + virtual bool Validate(); + + virtual wxString getCallsign() const; + virtual wxString getAddress() const; + +private: + wxString m_title; + CCallsignTextCtrl* m_callsign; + CAddressTextCtrl* m_address; +}; + +#endif diff --git a/StarNetServer/StarNetServerConfig.cpp b/StarNetServer/StarNetServerConfig.cpp new file mode 100644 index 0000000..fd7bbac --- /dev/null +++ b/StarNetServer/StarNetServerConfig.cpp @@ -0,0 +1,2415 @@ +/* + * Copyright (C) 2010,2011,2012 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "StarNetServerConfig.h" +#include "StarNetServerDefs.h" + +#include + +const wxString KEY_CALLSIGN = wxT("callsign"); +const wxString KEY_ADDRESS = wxT("address"); +const wxString KEY_IRCDDB_HOSTNAME = wxT("ircddbHostname"); +const wxString KEY_IRCDDB_USERNAME = wxT("ircddbUsername"); +const wxString KEY_IRCDDB_PASSWORD = wxT("ircddbPassword"); +const wxString KEY_STARNET_BAND1 = wxT("starNetBand1"); +const wxString KEY_STARNET_CALLSIGN1 = wxT("starNetCallsign1"); +const wxString KEY_STARNET_LOGOFF1 = wxT("starNetLogoff1"); +const wxString KEY_STARNET_INFO1 = wxT("starNetInfo1"); +const wxString KEY_STARNET_PERMANENT1 = wxT("starNetPermanent1"); +const wxString KEY_STARNET_USER_TIMEOUT1 = wxT("starNetUserTimeout1"); +const wxString KEY_STARNET_GROUP_TIMEOUT1 = wxT("starNetGroupTimeout1"); +const wxString KEY_STARNET_CALLSIGN_SWITCH1 = wxT("starNetCallsignSwitch1"); +const wxString KEY_STARNET_TXMSG_SWITCH1 = wxT("starNetTXMsgSwitch1"); +const wxString KEY_STARNET_REFLECTOR1 = wxT("starNetReflector1"); // DEXTRA_LINK +const wxString KEY_STARNET_BAND2 = wxT("starNetBand2"); +const wxString KEY_STARNET_CALLSIGN2 = wxT("starNetCallsign2"); +const wxString KEY_STARNET_LOGOFF2 = wxT("starNetLogoff2"); +const wxString KEY_STARNET_INFO2 = wxT("starNetInfo2"); +const wxString KEY_STARNET_PERMANENT2 = wxT("starNetPermanent2"); +const wxString KEY_STARNET_USER_TIMEOUT2 = wxT("starNetUserTimeout2"); +const wxString KEY_STARNET_GROUP_TIMEOUT2 = wxT("starNetGroupTimeout2"); +const wxString KEY_STARNET_CALLSIGN_SWITCH2 = wxT("starNetCallsignSwitch2"); +const wxString KEY_STARNET_TXMSG_SWITCH2 = wxT("starNetTXMsgSwitch2"); +const wxString KEY_STARNET_REFLECTOR2 = wxT("starNetReflector2"); // DEXTRA_LINK +const wxString KEY_STARNET_BAND3 = wxT("starNetBand3"); +const wxString KEY_STARNET_CALLSIGN3 = wxT("starNetCallsign3"); +const wxString KEY_STARNET_LOGOFF3 = wxT("starNetLogoff3"); +const wxString KEY_STARNET_INFO3 = wxT("starNetInfo3"); +const wxString KEY_STARNET_PERMANENT3 = wxT("starNetPermanent3"); +const wxString KEY_STARNET_USER_TIMEOUT3 = wxT("starNetUserTimeout3"); +const wxString KEY_STARNET_GROUP_TIMEOUT3 = wxT("starNetGroupTimeout3"); +const wxString KEY_STARNET_CALLSIGN_SWITCH3 = wxT("starNetCallsignSwitch3"); +const wxString KEY_STARNET_TXMSG_SWITCH3 = wxT("starNetTXMsgSwitch3"); +const wxString KEY_STARNET_REFLECTOR3 = wxT("starNetReflector3"); // DEXTRA_LINK +const wxString KEY_STARNET_BAND4 = wxT("starNetBand4"); +const wxString KEY_STARNET_CALLSIGN4 = wxT("starNetCallsign4"); +const wxString KEY_STARNET_LOGOFF4 = wxT("starNetLogoff4"); +const wxString KEY_STARNET_INFO4 = wxT("starNetInfo4"); +const wxString KEY_STARNET_PERMANENT4 = wxT("starNetPermanent4"); +const wxString KEY_STARNET_USER_TIMEOUT4 = wxT("starNetUserTimeout4"); +const wxString KEY_STARNET_GROUP_TIMEOUT4 = wxT("starNetGroupTimeout4"); +const wxString KEY_STARNET_CALLSIGN_SWITCH4 = wxT("starNetCallsignSwitch4"); +const wxString KEY_STARNET_TXMSG_SWITCH4 = wxT("starNetTXMsgSwitch4"); +const wxString KEY_STARNET_REFLECTOR4 = wxT("starNetReflector4"); // DEXTRA_LINK +const wxString KEY_STARNET_BAND5 = wxT("starNetBand5"); +const wxString KEY_STARNET_CALLSIGN5 = wxT("starNetCallsign5"); +const wxString KEY_STARNET_LOGOFF5 = wxT("starNetLogoff5"); +const wxString KEY_STARNET_INFO5 = wxT("starNetInfo5"); +const wxString KEY_STARNET_PERMANENT5 = wxT("starNetPermanent5"); +const wxString KEY_STARNET_USER_TIMEOUT5 = wxT("starNetUserTimeout5"); +const wxString KEY_STARNET_GROUP_TIMEOUT5 = wxT("starNetGroupTimeout5"); +const wxString KEY_STARNET_CALLSIGN_SWITCH5 = wxT("starNetCallsignSwitch5"); +const wxString KEY_STARNET_TXMSG_SWITCH5 = wxT("starNetTXMsgSwitch5"); +const wxString KEY_STARNET_REFLECTOR5 = wxT("starNetReflector5"); // DEXTRA_LINK +const wxString KEY_STARNET_BAND6 = wxT("starNetBand6"); +const wxString KEY_STARNET_CALLSIGN6 = wxT("starNetCallsign6"); +const wxString KEY_STARNET_LOGOFF6 = wxT("starNetLogoff6"); +const wxString KEY_STARNET_INFO6 = wxT("starNetInfo6"); +const wxString KEY_STARNET_PERMANENT6 = wxT("starNetPermanent6"); +const wxString KEY_STARNET_USER_TIMEOUT6 = wxT("starNetUserTimeout6"); +const wxString KEY_STARNET_GROUP_TIMEOUT6 = wxT("starNetGroupTimeout6"); +const wxString KEY_STARNET_CALLSIGN_SWITCH6 = wxT("starNetCallsignSwitch6"); +const wxString KEY_STARNET_TXMSG_SWITCH6 = wxT("starNetTXMsgSwitch6"); +const wxString KEY_STARNET_REFLECTOR6 = wxT("starNetReflector6"); // DEXTRA_LINK +const wxString KEY_STARNET_BAND7 = wxT("starNetBand7"); +const wxString KEY_STARNET_CALLSIGN7 = wxT("starNetCallsign7"); +const wxString KEY_STARNET_LOGOFF7 = wxT("starNetLogoff7"); +const wxString KEY_STARNET_INFO7 = wxT("starNetInfo7"); +const wxString KEY_STARNET_PERMANENT7 = wxT("starNetPermanent7"); +const wxString KEY_STARNET_USER_TIMEOUT7 = wxT("starNetUserTimeout7"); +const wxString KEY_STARNET_GROUP_TIMEOUT7 = wxT("starNetGroupTimeout7"); +const wxString KEY_STARNET_CALLSIGN_SWITCH7 = wxT("starNetCallsignSwitch7"); +const wxString KEY_STARNET_TXMSG_SWITCH7 = wxT("starNetTXMsgSwitch7"); +const wxString KEY_STARNET_REFLECTOR7 = wxT("starNetReflector7"); // DEXTRA_LINK +const wxString KEY_STARNET_BAND8 = wxT("starNetBand8"); +const wxString KEY_STARNET_CALLSIGN8 = wxT("starNetCallsign8"); +const wxString KEY_STARNET_LOGOFF8 = wxT("starNetLogoff8"); +const wxString KEY_STARNET_INFO8 = wxT("starNetInfo8"); +const wxString KEY_STARNET_PERMANENT8 = wxT("starNetPermanent8"); +const wxString KEY_STARNET_USER_TIMEOUT8 = wxT("starNetUserTimeout8"); +const wxString KEY_STARNET_GROUP_TIMEOUT8 = wxT("starNetGroupTimeout8"); +const wxString KEY_STARNET_CALLSIGN_SWITCH8 = wxT("starNetCallsignSwitch8"); +const wxString KEY_STARNET_TXMSG_SWITCH8 = wxT("starNetTXMsgSwitch8"); +const wxString KEY_STARNET_REFLECTOR8 = wxT("starNetReflector8"); // DEXTRA_LINK +const wxString KEY_STARNET_BAND9 = wxT("starNetBand9"); +const wxString KEY_STARNET_CALLSIGN9 = wxT("starNetCallsign9"); +const wxString KEY_STARNET_LOGOFF9 = wxT("starNetLogoff9"); +const wxString KEY_STARNET_INFO9 = wxT("starNetInfo9"); +const wxString KEY_STARNET_PERMANENT9 = wxT("starNetPermanent9"); +const wxString KEY_STARNET_USER_TIMEOUT9 = wxT("starNetUserTimeout9"); +const wxString KEY_STARNET_GROUP_TIMEOUT9 = wxT("starNetGroupTimeout9"); +const wxString KEY_STARNET_CALLSIGN_SWITCH9 = wxT("starNetCallsignSwitch9"); +const wxString KEY_STARNET_TXMSG_SWITCH9 = wxT("starNetTXMsgSwitch9"); +const wxString KEY_STARNET_REFLECTOR9 = wxT("starNetReflector9"); // DEXTRA_LINK +const wxString KEY_STARNET_BAND10 = wxT("starNetBand10"); +const wxString KEY_STARNET_CALLSIGN10 = wxT("starNetCallsign10"); +const wxString KEY_STARNET_LOGOFF10 = wxT("starNetLogoff10"); +const wxString KEY_STARNET_INFO10 = wxT("starNetInfo10"); +const wxString KEY_STARNET_PERMANENT10 = wxT("starNetPermanent10"); +const wxString KEY_STARNET_USER_TIMEOUT10 = wxT("starNetUserTimeout10"); +const wxString KEY_STARNET_GROUP_TIMEOUT10 = wxT("starNetGroupTimeout10"); +const wxString KEY_STARNET_CALLSIGN_SWITCH10 = wxT("starNetCallsignSwitch10"); +const wxString KEY_STARNET_TXMSG_SWITCH10 = wxT("starNetTXMsgSwitch10"); +const wxString KEY_STARNET_REFLECTOR10 = wxT("starNetReflector10"); // DEXTRA_LINK +const wxString KEY_STARNET_BAND11 = wxT("starNetBand11"); +const wxString KEY_STARNET_CALLSIGN11 = wxT("starNetCallsign11"); +const wxString KEY_STARNET_LOGOFF11 = wxT("starNetLogoff11"); +const wxString KEY_STARNET_INFO11 = wxT("starNetInfo11"); +const wxString KEY_STARNET_PERMANENT11 = wxT("starNetPermanent11"); +const wxString KEY_STARNET_USER_TIMEOUT11 = wxT("starNetUserTimeout11"); +const wxString KEY_STARNET_GROUP_TIMEOUT11 = wxT("starNetGroupTimeout11"); +const wxString KEY_STARNET_CALLSIGN_SWITCH11 = wxT("starNetCallsignSwitch11"); +const wxString KEY_STARNET_TXMSG_SWITCH11 = wxT("starNetTXMsgSwitch11"); +const wxString KEY_STARNET_REFLECTOR11 = wxT("starNetReflector11"); // DEXTRA_LINK +const wxString KEY_STARNET_BAND12 = wxT("starNetBand12"); +const wxString KEY_STARNET_CALLSIGN12 = wxT("starNetCallsign12"); +const wxString KEY_STARNET_LOGOFF12 = wxT("starNetLogoff12"); +const wxString KEY_STARNET_INFO12 = wxT("starNetInfo12"); +const wxString KEY_STARNET_PERMANENT12 = wxT("starNetPermanent12"); +const wxString KEY_STARNET_USER_TIMEOUT12 = wxT("starNetUserTimeout12"); +const wxString KEY_STARNET_GROUP_TIMEOUT12 = wxT("starNetGroupTimeout12"); +const wxString KEY_STARNET_CALLSIGN_SWITCH12 = wxT("starNetCallsignSwitch12"); +const wxString KEY_STARNET_TXMSG_SWITCH12 = wxT("starNetTXMsgSwitch12"); +const wxString KEY_STARNET_REFLECTOR12 = wxT("starNetReflector12"); // DEXTRA_LINK +const wxString KEY_STARNET_BAND13 = wxT("starNetBand13"); +const wxString KEY_STARNET_CALLSIGN13 = wxT("starNetCallsign13"); +const wxString KEY_STARNET_LOGOFF13 = wxT("starNetLogoff13"); +const wxString KEY_STARNET_INFO13 = wxT("starNetInfo13"); +const wxString KEY_STARNET_PERMANENT13 = wxT("starNetPermanent13"); +const wxString KEY_STARNET_USER_TIMEOUT13 = wxT("starNetUserTimeout13"); +const wxString KEY_STARNET_GROUP_TIMEOUT13 = wxT("starNetGroupTimeout13"); +const wxString KEY_STARNET_CALLSIGN_SWITCH13 = wxT("starNetCallsignSwitch13"); +const wxString KEY_STARNET_TXMSG_SWITCH13 = wxT("starNetTXMsgSwitch13"); +const wxString KEY_STARNET_REFLECTOR13 = wxT("starNetReflector13"); // DEXTRA_LINK +const wxString KEY_STARNET_BAND14 = wxT("starNetBand14"); +const wxString KEY_STARNET_CALLSIGN14 = wxT("starNetCallsign14"); +const wxString KEY_STARNET_LOGOFF14 = wxT("starNetLogoff14"); +const wxString KEY_STARNET_INFO14 = wxT("starNetInfo14"); +const wxString KEY_STARNET_PERMANENT14 = wxT("starNetPermanent14"); +const wxString KEY_STARNET_USER_TIMEOUT14 = wxT("starNetUserTimeout14"); +const wxString KEY_STARNET_GROUP_TIMEOUT14 = wxT("starNetGroupTimeout14"); +const wxString KEY_STARNET_CALLSIGN_SWITCH14 = wxT("starNetCallsignSwitch14"); +const wxString KEY_STARNET_TXMSG_SWITCH14 = wxT("starNetTXMsgSwitch14"); +const wxString KEY_STARNET_REFLECTOR14 = wxT("starNetReflector14"); // DEXTRA_LINK +const wxString KEY_STARNET_BAND15 = wxT("starNetBand15"); +const wxString KEY_STARNET_CALLSIGN15 = wxT("starNetCallsign15"); +const wxString KEY_STARNET_LOGOFF15 = wxT("starNetLogoff15"); +const wxString KEY_STARNET_INFO15 = wxT("starNetInfo15"); +const wxString KEY_STARNET_PERMANENT15 = wxT("starNetPermanent15"); +const wxString KEY_STARNET_USER_TIMEOUT15 = wxT("starNetUserTimeout15"); +const wxString KEY_STARNET_GROUP_TIMEOUT15 = wxT("starNetGroupTimeout15"); +const wxString KEY_STARNET_CALLSIGN_SWITCH15 = wxT("starNetCallsignSwitch15"); +const wxString KEY_STARNET_TXMSG_SWITCH15 = wxT("starNetTXMsgSwitch15"); +const wxString KEY_STARNET_REFLECTOR15 = wxT("starNetReflector15"); // DEXTRA_LINK +const wxString KEY_REMOTE_ENABLED = wxT("remoteEnabled"); +const wxString KEY_REMOTE_PASSWORD = wxT("remotePassword"); +const wxString KEY_REMOTE_PORT = wxT("remotePort"); +const wxString KEY_LOG_ENABLED = wxT("logEnabled"); +const wxString KEY_WINDOW_X = wxT("windowX"); +const wxString KEY_WINDOW_Y = wxT("windowY"); + +const wxString DEFAULT_CALLSIGN = wxEmptyString; +const wxString DEFAULT_ADDRESS = wxEmptyString; +const wxString DEFAULT_IRCDDB_HOSTNAME = wxT("group1-irc.ircddb.net"); +const wxString DEFAULT_IRCDDB_USERNAME = wxEmptyString; +const wxString DEFAULT_IRCDDB_PASSWORD = wxEmptyString; +const wxString DEFAULT_STARNET_BAND = wxEmptyString; +const wxString DEFAULT_STARNET_CALLSIGN = wxEmptyString; +const wxString DEFAULT_STARNET_LOGOFF = wxEmptyString; +const wxString DEFAULT_STARNET_INFO = wxEmptyString; +const wxString DEFAULT_STARNET_PERMANENT = wxEmptyString; +const unsigned int DEFAULT_STARNET_USER_TIMEOUT = 300U; +const unsigned int DEFAULT_STARNET_GROUP_TIMEOUT = 300U; +const STARNET_CALLSIGN_SWITCH DEFAULT_STARNET_CALLSIGN_SWITCH = SCS_GROUP_CALLSIGN; +const bool DEFAULT_STARNET_TXMSG_SWITCH = true; +const wxString DEFAULT_STARNET_REFLECTOR = wxEmptyString; +const bool DEFAULT_REMOTE_ENABLED = false; +const wxString DEFAULT_REMOTE_PASSWORD = wxEmptyString; +const unsigned int DEFAULT_REMOTE_PORT = 0U; +const bool DEFAULT_LOG_ENABLED = false; +const int DEFAULT_WINDOW_X = -1; +const int DEFAULT_WINDOW_Y = -1; + +#if defined(__WINDOWS__) + +CStarNetServerConfig::CStarNetServerConfig(wxConfigBase* config, const wxString& dir) : +m_config(config), +m_fileName(), +m_callsign(DEFAULT_CALLSIGN), +m_address(DEFAULT_ADDRESS), +m_ircddbHostname(DEFAULT_IRCDDB_HOSTNAME), +m_ircddbUsername(DEFAULT_IRCDDB_USERNAME), +m_ircddbPassword(DEFAULT_IRCDDB_PASSWORD), +m_starNet1Band(DEFAULT_STARNET_BAND), +m_starNet1Callsign(DEFAULT_STARNET_CALLSIGN), +m_starNet1Logoff(DEFAULT_STARNET_LOGOFF), +m_starNet1Info(DEFAULT_STARNET_INFO), +m_starNet1Permanent(DEFAULT_STARNET_PERMANENT), +m_starNet1UserTimeout(DEFAULT_STARNET_USER_TIMEOUT), +m_starNet1GroupTimeout(DEFAULT_STARNET_GROUP_TIMEOUT), +m_starNet1CallsignSwitch(DEFAULT_STARNET_CALLSIGN_SWITCH), +m_starNet1TxMsgSwitch(DEFAULT_STARNET_TXMSG_SWITCH), +m_starNet1Reflector(DEFAULT_STARNET_REFLECTOR), +m_starNet2Band(DEFAULT_STARNET_BAND), +m_starNet2Callsign(DEFAULT_STARNET_CALLSIGN), +m_starNet2Logoff(DEFAULT_STARNET_LOGOFF), +m_starNet2Info(DEFAULT_STARNET_INFO), +m_starNet2Permanent(DEFAULT_STARNET_PERMANENT), +m_starNet2UserTimeout(DEFAULT_STARNET_USER_TIMEOUT), +m_starNet2GroupTimeout(DEFAULT_STARNET_GROUP_TIMEOUT), +m_starNet2CallsignSwitch(DEFAULT_STARNET_CALLSIGN_SWITCH), +m_starNet2TxMsgSwitch(DEFAULT_STARNET_TXMSG_SWITCH), +m_starNet2Reflector(DEFAULT_STARNET_REFLECTOR), +m_starNet3Band(DEFAULT_STARNET_BAND), +m_starNet3Callsign(DEFAULT_STARNET_CALLSIGN), +m_starNet3Logoff(DEFAULT_STARNET_LOGOFF), +m_starNet3Info(DEFAULT_STARNET_INFO), +m_starNet3Permanent(DEFAULT_STARNET_PERMANENT), +m_starNet3UserTimeout(DEFAULT_STARNET_USER_TIMEOUT), +m_starNet3GroupTimeout(DEFAULT_STARNET_GROUP_TIMEOUT), +m_starNet3CallsignSwitch(DEFAULT_STARNET_CALLSIGN_SWITCH), +m_starNet3TxMsgSwitch(DEFAULT_STARNET_TXMSG_SWITCH), +m_starNet3Reflector(DEFAULT_STARNET_REFLECTOR), +m_starNet4Band(DEFAULT_STARNET_BAND), +m_starNet4Callsign(DEFAULT_STARNET_CALLSIGN), +m_starNet4Logoff(DEFAULT_STARNET_LOGOFF), +m_starNet4Info(DEFAULT_STARNET_INFO), +m_starNet4Permanent(DEFAULT_STARNET_PERMANENT), +m_starNet4UserTimeout(DEFAULT_STARNET_USER_TIMEOUT), +m_starNet4GroupTimeout(DEFAULT_STARNET_GROUP_TIMEOUT), +m_starNet4CallsignSwitch(DEFAULT_STARNET_CALLSIGN_SWITCH), +m_starNet4TxMsgSwitch(DEFAULT_STARNET_TXMSG_SWITCH), +m_starNet4Reflector(DEFAULT_STARNET_REFLECTOR), +m_starNet5Band(DEFAULT_STARNET_BAND), +m_starNet5Callsign(DEFAULT_STARNET_CALLSIGN), +m_starNet5Logoff(DEFAULT_STARNET_LOGOFF), +m_starNet5Info(DEFAULT_STARNET_INFO), +m_starNet5Permanent(DEFAULT_STARNET_PERMANENT), +m_starNet5UserTimeout(DEFAULT_STARNET_USER_TIMEOUT), +m_starNet5GroupTimeout(DEFAULT_STARNET_GROUP_TIMEOUT), +m_starNet5CallsignSwitch(DEFAULT_STARNET_CALLSIGN_SWITCH), +m_starNet5TxMsgSwitch(DEFAULT_STARNET_TXMSG_SWITCH), +m_starNet5Reflector(DEFAULT_STARNET_REFLECTOR), +m_starNet6Band(DEFAULT_STARNET_BAND), +m_starNet6Callsign(DEFAULT_STARNET_CALLSIGN), +m_starNet6Logoff(DEFAULT_STARNET_LOGOFF), +m_starNet6Info(DEFAULT_STARNET_INFO), +m_starNet6Permanent(DEFAULT_STARNET_PERMANENT), +m_starNet6UserTimeout(DEFAULT_STARNET_USER_TIMEOUT), +m_starNet6GroupTimeout(DEFAULT_STARNET_GROUP_TIMEOUT), +m_starNet6CallsignSwitch(DEFAULT_STARNET_CALLSIGN_SWITCH), +m_starNet6TxMsgSwitch(DEFAULT_STARNET_TXMSG_SWITCH), +m_starNet6Reflector(DEFAULT_STARNET_REFLECTOR), +m_starNet7Band(DEFAULT_STARNET_BAND), +m_starNet7Callsign(DEFAULT_STARNET_CALLSIGN), +m_starNet7Logoff(DEFAULT_STARNET_LOGOFF), +m_starNet7Info(DEFAULT_STARNET_INFO), +m_starNet7Permanent(DEFAULT_STARNET_PERMANENT), +m_starNet7UserTimeout(DEFAULT_STARNET_USER_TIMEOUT), +m_starNet7GroupTimeout(DEFAULT_STARNET_GROUP_TIMEOUT), +m_starNet7CallsignSwitch(DEFAULT_STARNET_CALLSIGN_SWITCH), +m_starNet7TxMsgSwitch(DEFAULT_STARNET_TXMSG_SWITCH), +m_starNet7Reflector(DEFAULT_STARNET_REFLECTOR), +m_starNet8Band(DEFAULT_STARNET_BAND), +m_starNet8Callsign(DEFAULT_STARNET_CALLSIGN), +m_starNet8Logoff(DEFAULT_STARNET_LOGOFF), +m_starNet8Info(DEFAULT_STARNET_INFO), +m_starNet8Permanent(DEFAULT_STARNET_PERMANENT), +m_starNet8UserTimeout(DEFAULT_STARNET_USER_TIMEOUT), +m_starNet8GroupTimeout(DEFAULT_STARNET_GROUP_TIMEOUT), +m_starNet8CallsignSwitch(DEFAULT_STARNET_CALLSIGN_SWITCH), +m_starNet8TxMsgSwitch(DEFAULT_STARNET_TXMSG_SWITCH), +m_starNet8Reflector(DEFAULT_STARNET_REFLECTOR), +m_starNet9Band(DEFAULT_STARNET_BAND), +m_starNet9Callsign(DEFAULT_STARNET_CALLSIGN), +m_starNet9Logoff(DEFAULT_STARNET_LOGOFF), +m_starNet9Info(DEFAULT_STARNET_INFO), +m_starNet9Permanent(DEFAULT_STARNET_PERMANENT), +m_starNet9UserTimeout(DEFAULT_STARNET_USER_TIMEOUT), +m_starNet9GroupTimeout(DEFAULT_STARNET_GROUP_TIMEOUT), +m_starNet9CallsignSwitch(DEFAULT_STARNET_CALLSIGN_SWITCH), +m_starNet9TxMsgSwitch(DEFAULT_STARNET_TXMSG_SWITCH), +m_starNet9Reflector(DEFAULT_STARNET_REFLECTOR), +m_starNet10Band(DEFAULT_STARNET_BAND), +m_starNet10Callsign(DEFAULT_STARNET_CALLSIGN), +m_starNet10Logoff(DEFAULT_STARNET_LOGOFF), +m_starNet10Info(DEFAULT_STARNET_INFO), +m_starNet10Permanent(DEFAULT_STARNET_PERMANENT), +m_starNet10UserTimeout(DEFAULT_STARNET_USER_TIMEOUT), +m_starNet10GroupTimeout(DEFAULT_STARNET_GROUP_TIMEOUT), +m_starNet10CallsignSwitch(DEFAULT_STARNET_CALLSIGN_SWITCH), +m_starNet10TxMsgSwitch(DEFAULT_STARNET_TXMSG_SWITCH), +m_starNet10Reflector(DEFAULT_STARNET_REFLECTOR), +m_starNet11Band(DEFAULT_STARNET_BAND), +m_starNet11Callsign(DEFAULT_STARNET_CALLSIGN), +m_starNet11Logoff(DEFAULT_STARNET_LOGOFF), +m_starNet11Info(DEFAULT_STARNET_INFO), +m_starNet11Permanent(DEFAULT_STARNET_PERMANENT), +m_starNet11UserTimeout(DEFAULT_STARNET_USER_TIMEOUT), +m_starNet11GroupTimeout(DEFAULT_STARNET_GROUP_TIMEOUT), +m_starNet11CallsignSwitch(DEFAULT_STARNET_CALLSIGN_SWITCH), +m_starNet11TxMsgSwitch(DEFAULT_STARNET_TXMSG_SWITCH), +m_starNet11Reflector(DEFAULT_STARNET_REFLECTOR), +m_starNet12Band(DEFAULT_STARNET_BAND), +m_starNet12Callsign(DEFAULT_STARNET_CALLSIGN), +m_starNet12Logoff(DEFAULT_STARNET_LOGOFF), +m_starNet12Info(DEFAULT_STARNET_INFO), +m_starNet12Permanent(DEFAULT_STARNET_PERMANENT), +m_starNet12UserTimeout(DEFAULT_STARNET_USER_TIMEOUT), +m_starNet12GroupTimeout(DEFAULT_STARNET_GROUP_TIMEOUT), +m_starNet12CallsignSwitch(DEFAULT_STARNET_CALLSIGN_SWITCH), +m_starNet12TxMsgSwitch(DEFAULT_STARNET_TXMSG_SWITCH), +m_starNet12Reflector(DEFAULT_STARNET_REFLECTOR), +m_starNet13Band(DEFAULT_STARNET_BAND), +m_starNet13Callsign(DEFAULT_STARNET_CALLSIGN), +m_starNet13Logoff(DEFAULT_STARNET_LOGOFF), +m_starNet13Info(DEFAULT_STARNET_INFO), +m_starNet13Permanent(DEFAULT_STARNET_PERMANENT), +m_starNet13UserTimeout(DEFAULT_STARNET_USER_TIMEOUT), +m_starNet13GroupTimeout(DEFAULT_STARNET_GROUP_TIMEOUT), +m_starNet13CallsignSwitch(DEFAULT_STARNET_CALLSIGN_SWITCH), +m_starNet13TxMsgSwitch(DEFAULT_STARNET_TXMSG_SWITCH), +m_starNet13Reflector(DEFAULT_STARNET_REFLECTOR), +m_starNet14Band(DEFAULT_STARNET_BAND), +m_starNet14Callsign(DEFAULT_STARNET_CALLSIGN), +m_starNet14Logoff(DEFAULT_STARNET_LOGOFF), +m_starNet14Info(DEFAULT_STARNET_INFO), +m_starNet14Permanent(DEFAULT_STARNET_PERMANENT), +m_starNet14UserTimeout(DEFAULT_STARNET_USER_TIMEOUT), +m_starNet14GroupTimeout(DEFAULT_STARNET_GROUP_TIMEOUT), +m_starNet14CallsignSwitch(DEFAULT_STARNET_CALLSIGN_SWITCH), +m_starNet14TxMsgSwitch(DEFAULT_STARNET_TXMSG_SWITCH), +m_starNet14Reflector(DEFAULT_STARNET_REFLECTOR), +m_starNet15Band(DEFAULT_STARNET_BAND), +m_starNet15Callsign(DEFAULT_STARNET_CALLSIGN), +m_starNet15Logoff(DEFAULT_STARNET_LOGOFF), +m_starNet15Info(DEFAULT_STARNET_INFO), +m_starNet15Permanent(DEFAULT_STARNET_PERMANENT), +m_starNet15UserTimeout(DEFAULT_STARNET_USER_TIMEOUT), +m_starNet15GroupTimeout(DEFAULT_STARNET_GROUP_TIMEOUT), +m_starNet15CallsignSwitch(DEFAULT_STARNET_CALLSIGN_SWITCH), +m_starNet15TxMsgSwitch(DEFAULT_STARNET_TXMSG_SWITCH), +m_starNet15Reflector(DEFAULT_STARNET_REFLECTOR), +m_remoteEnabled(DEFAULT_REMOTE_ENABLED), +m_remotePassword(DEFAULT_REMOTE_PASSWORD), +m_remotePort(DEFAULT_REMOTE_PORT), +m_logEnabled(DEFAULT_LOG_ENABLED), +m_x(DEFAULT_WINDOW_X), +m_y(DEFAULT_WINDOW_Y) +{ + wxASSERT(config != NULL); + wxASSERT(!dir.IsEmpty()); + + m_fileName.Assign(dir, CONFIG_FILE_NAME); + + wxTextFile file(m_fileName.GetFullPath()); + + long temp; + + m_config->Read(wxT("/") + KEY_CALLSIGN, &m_callsign, DEFAULT_CALLSIGN); + + m_config->Read(wxT("/") + KEY_ADDRESS, &m_address, DEFAULT_ADDRESS); + + m_config->Read(wxT("/") + KEY_IRCDDB_HOSTNAME, &m_ircddbHostname, DEFAULT_IRCDDB_HOSTNAME); + + m_config->Read(wxT("/") + KEY_IRCDDB_USERNAME, &m_ircddbUsername, DEFAULT_IRCDDB_USERNAME); + + m_config->Read(wxT("/") + KEY_IRCDDB_PASSWORD, &m_ircddbPassword, DEFAULT_IRCDDB_PASSWORD); + + m_config->Read(wxT("/") + KEY_STARNET_BAND1, &m_starNet1Band, DEFAULT_STARNET_BAND); + + m_config->Read(wxT("/") + KEY_STARNET_CALLSIGN1, &m_starNet1Callsign, DEFAULT_STARNET_CALLSIGN); + + m_config->Read(wxT("/") + KEY_STARNET_LOGOFF1, &m_starNet1Logoff, DEFAULT_STARNET_LOGOFF); + + m_config->Read(wxT("/") + KEY_STARNET_INFO1, &m_starNet1Info, DEFAULT_STARNET_INFO); + + m_config->Read(wxT("/") + KEY_STARNET_PERMANENT1, &m_starNet1Permanent, DEFAULT_STARNET_PERMANENT); + + m_config->Read(wxT("/") + KEY_STARNET_USER_TIMEOUT1, &temp, long(DEFAULT_STARNET_USER_TIMEOUT)); + m_starNet1UserTimeout = (unsigned int)temp; + + m_config->Read(wxT("/") + KEY_STARNET_GROUP_TIMEOUT1, &temp, long(DEFAULT_STARNET_GROUP_TIMEOUT)); + m_starNet1GroupTimeout = (unsigned int)temp; + + m_config->Read(wxT("/") + KEY_STARNET_CALLSIGN_SWITCH1, &temp, long(DEFAULT_STARNET_CALLSIGN_SWITCH)); + m_starNet1CallsignSwitch = STARNET_CALLSIGN_SWITCH(temp); + + m_config->Read(wxT("/") + KEY_STARNET_TXMSG_SWITCH1, &m_starNet1TxMsgSwitch, DEFAULT_STARNET_TXMSG_SWITCH); + + m_config->Read(wxT("/") + KEY_STARNET_REFLECTOR1, &m_starNet1Reflector, DEFAULT_STARNET_REFLECTOR); + + m_config->Read(wxT("/") + KEY_STARNET_BAND2, &m_starNet2Band, DEFAULT_STARNET_BAND); + + m_config->Read(wxT("/") + KEY_STARNET_CALLSIGN2, &m_starNet2Callsign, DEFAULT_STARNET_CALLSIGN); + + m_config->Read(wxT("/") + KEY_STARNET_LOGOFF2, &m_starNet2Logoff, DEFAULT_STARNET_LOGOFF); + + m_config->Read(wxT("/") + KEY_STARNET_INFO2, &m_starNet2Info, DEFAULT_STARNET_INFO); + + m_config->Read(wxT("/") + KEY_STARNET_PERMANENT2, &m_starNet2Permanent, DEFAULT_STARNET_PERMANENT); + + m_config->Read(wxT("/") + KEY_STARNET_USER_TIMEOUT2, &temp, long(DEFAULT_STARNET_USER_TIMEOUT)); + m_starNet2UserTimeout = (unsigned int)temp; + + m_config->Read(wxT("/") + KEY_STARNET_GROUP_TIMEOUT2, &temp, long(DEFAULT_STARNET_GROUP_TIMEOUT)); + m_starNet2GroupTimeout = (unsigned int)temp; + + m_config->Read(wxT("/") + KEY_STARNET_CALLSIGN_SWITCH2, &temp, long(DEFAULT_STARNET_CALLSIGN_SWITCH)); + m_starNet2CallsignSwitch = STARNET_CALLSIGN_SWITCH(temp); + + m_config->Read(wxT("/") + KEY_STARNET_TXMSG_SWITCH2, &m_starNet2TxMsgSwitch, DEFAULT_STARNET_TXMSG_SWITCH); + + m_config->Read(wxT("/") + KEY_STARNET_REFLECTOR2, &m_starNet2Reflector, DEFAULT_STARNET_REFLECTOR); + + m_config->Read(wxT("/") + KEY_STARNET_BAND3, &m_starNet3Band, DEFAULT_STARNET_BAND); + + m_config->Read(wxT("/") + KEY_STARNET_CALLSIGN3, &m_starNet3Callsign, DEFAULT_STARNET_CALLSIGN); + + m_config->Read(wxT("/") + KEY_STARNET_LOGOFF3, &m_starNet3Logoff, DEFAULT_STARNET_LOGOFF); + + m_config->Read(wxT("/") + KEY_STARNET_INFO3, &m_starNet3Info, DEFAULT_STARNET_INFO); + + m_config->Read(wxT("/") + KEY_STARNET_PERMANENT3, &m_starNet3Permanent, DEFAULT_STARNET_PERMANENT); + + m_config->Read(wxT("/") + KEY_STARNET_USER_TIMEOUT3, &temp, long(DEFAULT_STARNET_USER_TIMEOUT)); + m_starNet3UserTimeout = (unsigned int)temp; + + m_config->Read(wxT("/") + KEY_STARNET_GROUP_TIMEOUT3, &temp, long(DEFAULT_STARNET_GROUP_TIMEOUT)); + m_starNet3GroupTimeout = (unsigned int)temp; + + m_config->Read(wxT("/") + KEY_STARNET_CALLSIGN_SWITCH3, &temp, long(DEFAULT_STARNET_CALLSIGN_SWITCH)); + m_starNet3CallsignSwitch = STARNET_CALLSIGN_SWITCH(temp); + + m_config->Read(wxT("/") + KEY_STARNET_TXMSG_SWITCH3, &m_starNet3TxMsgSwitch, DEFAULT_STARNET_TXMSG_SWITCH); + + m_config->Read(wxT("/") + KEY_STARNET_REFLECTOR3, &m_starNet3Reflector, DEFAULT_STARNET_REFLECTOR); + + m_config->Read(wxT("/") + KEY_STARNET_BAND4, &m_starNet4Band, DEFAULT_STARNET_BAND); + + m_config->Read(wxT("/") + KEY_STARNET_CALLSIGN4, &m_starNet4Callsign, DEFAULT_STARNET_CALLSIGN); + + m_config->Read(wxT("/") + KEY_STARNET_LOGOFF4, &m_starNet4Logoff, DEFAULT_STARNET_LOGOFF); + + m_config->Read(wxT("/") + KEY_STARNET_INFO4, &m_starNet4Info, DEFAULT_STARNET_INFO); + + m_config->Read(wxT("/") + KEY_STARNET_PERMANENT4, &m_starNet4Permanent, DEFAULT_STARNET_PERMANENT); + + m_config->Read(wxT("/") + KEY_STARNET_USER_TIMEOUT4, &temp, long(DEFAULT_STARNET_USER_TIMEOUT)); + m_starNet4UserTimeout = (unsigned int)temp; + + m_config->Read(wxT("/") + KEY_STARNET_GROUP_TIMEOUT4, &temp, long(DEFAULT_STARNET_GROUP_TIMEOUT)); + m_starNet4GroupTimeout = (unsigned int)temp; + + m_config->Read(wxT("/") + KEY_STARNET_CALLSIGN_SWITCH4, &temp, long(DEFAULT_STARNET_CALLSIGN_SWITCH)); + m_starNet4CallsignSwitch = STARNET_CALLSIGN_SWITCH(temp); + + m_config->Read(wxT("/") + KEY_STARNET_TXMSG_SWITCH4, &m_starNet4TxMsgSwitch, DEFAULT_STARNET_TXMSG_SWITCH); + + m_config->Read(wxT("/") + KEY_STARNET_REFLECTOR4, &m_starNet4Reflector, DEFAULT_STARNET_REFLECTOR); + + m_config->Read(wxT("/") + KEY_STARNET_BAND5, &m_starNet5Band, DEFAULT_STARNET_BAND); + + m_config->Read(wxT("/") + KEY_STARNET_CALLSIGN5, &m_starNet5Callsign, DEFAULT_STARNET_CALLSIGN); + + m_config->Read(wxT("/") + KEY_STARNET_LOGOFF5, &m_starNet5Logoff, DEFAULT_STARNET_LOGOFF); + + m_config->Read(wxT("/") + KEY_STARNET_INFO5, &m_starNet5Info, DEFAULT_STARNET_INFO); + + m_config->Read(wxT("/") + KEY_STARNET_PERMANENT5, &m_starNet5Permanent, DEFAULT_STARNET_PERMANENT); + + m_config->Read(wxT("/") + KEY_STARNET_USER_TIMEOUT5, &temp, long(DEFAULT_STARNET_USER_TIMEOUT)); + m_starNet5UserTimeout = (unsigned int)temp; + + m_config->Read(wxT("/") + KEY_STARNET_GROUP_TIMEOUT5, &temp, long(DEFAULT_STARNET_GROUP_TIMEOUT)); + m_starNet5GroupTimeout = (unsigned int)temp; + + m_config->Read(wxT("/") + KEY_STARNET_CALLSIGN_SWITCH5, &temp, long(DEFAULT_STARNET_CALLSIGN_SWITCH)); + m_starNet5CallsignSwitch = STARNET_CALLSIGN_SWITCH(temp); + + m_config->Read(wxT("/") + KEY_STARNET_TXMSG_SWITCH5, &m_starNet5TxMsgSwitch, DEFAULT_STARNET_TXMSG_SWITCH); + + m_config->Read(wxT("/") + KEY_STARNET_REFLECTOR5, &m_starNet5Reflector, DEFAULT_STARNET_REFLECTOR); + + m_config->Read(wxT("/") + KEY_STARNET_BAND6, &m_starNet6Band, DEFAULT_STARNET_BAND); + + m_config->Read(wxT("/") + KEY_STARNET_CALLSIGN6, &m_starNet6Callsign, DEFAULT_STARNET_CALLSIGN); + + m_config->Read(wxT("/") + KEY_STARNET_LOGOFF6, &m_starNet6Logoff, DEFAULT_STARNET_LOGOFF); + + m_config->Read(wxT("/") + KEY_STARNET_INFO6, &m_starNet6Info, DEFAULT_STARNET_INFO); + + m_config->Read(wxT("/") + KEY_STARNET_PERMANENT6, &m_starNet6Permanent, DEFAULT_STARNET_PERMANENT); + + m_config->Read(wxT("/") + KEY_STARNET_USER_TIMEOUT6, &temp, long(DEFAULT_STARNET_USER_TIMEOUT)); + m_starNet6UserTimeout = (unsigned int)temp; + + m_config->Read(wxT("/") + KEY_STARNET_GROUP_TIMEOUT6, &temp, long(DEFAULT_STARNET_GROUP_TIMEOUT)); + m_starNet6GroupTimeout = (unsigned int)temp; + + m_config->Read(wxT("/") + KEY_STARNET_CALLSIGN_SWITCH6, &temp, long(DEFAULT_STARNET_CALLSIGN_SWITCH)); + m_starNet6CallsignSwitch = STARNET_CALLSIGN_SWITCH(temp); + + m_config->Read(wxT("/") + KEY_STARNET_TXMSG_SWITCH6, &m_starNet6TxMsgSwitch, DEFAULT_STARNET_TXMSG_SWITCH); + + m_config->Read(wxT("/") + KEY_STARNET_REFLECTOR6, &m_starNet6Reflector, DEFAULT_STARNET_REFLECTOR); + + m_config->Read(wxT("/") + KEY_STARNET_BAND7, &m_starNet7Band, DEFAULT_STARNET_BAND); + + m_config->Read(wxT("/") + KEY_STARNET_CALLSIGN7, &m_starNet7Callsign, DEFAULT_STARNET_CALLSIGN); + + m_config->Read(wxT("/") + KEY_STARNET_LOGOFF7, &m_starNet7Logoff, DEFAULT_STARNET_LOGOFF); + + m_config->Read(wxT("/") + KEY_STARNET_INFO7, &m_starNet7Info, DEFAULT_STARNET_INFO); + + m_config->Read(wxT("/") + KEY_STARNET_PERMANENT7, &m_starNet7Permanent, DEFAULT_STARNET_PERMANENT); + + m_config->Read(wxT("/") + KEY_STARNET_USER_TIMEOUT7, &temp, long(DEFAULT_STARNET_USER_TIMEOUT)); + m_starNet7UserTimeout = (unsigned int)temp; + + m_config->Read(wxT("/") + KEY_STARNET_GROUP_TIMEOUT7, &temp, long(DEFAULT_STARNET_GROUP_TIMEOUT)); + m_starNet7GroupTimeout = (unsigned int)temp; + + m_config->Read(wxT("/") + KEY_STARNET_CALLSIGN_SWITCH7, &temp, long(DEFAULT_STARNET_CALLSIGN_SWITCH)); + m_starNet7CallsignSwitch = STARNET_CALLSIGN_SWITCH(temp); + + m_config->Read(wxT("/") + KEY_STARNET_TXMSG_SWITCH7, &m_starNet7TxMsgSwitch, DEFAULT_STARNET_TXMSG_SWITCH); + + m_config->Read(wxT("/") + KEY_STARNET_REFLECTOR7, &m_starNet7Reflector, DEFAULT_STARNET_REFLECTOR); + + m_config->Read(wxT("/") + KEY_STARNET_BAND8, &m_starNet8Band, DEFAULT_STARNET_BAND); + + m_config->Read(wxT("/") + KEY_STARNET_CALLSIGN8, &m_starNet8Callsign, DEFAULT_STARNET_CALLSIGN); + + m_config->Read(wxT("/") + KEY_STARNET_LOGOFF8, &m_starNet8Logoff, DEFAULT_STARNET_LOGOFF); + + m_config->Read(wxT("/") + KEY_STARNET_INFO8, &m_starNet8Info, DEFAULT_STARNET_INFO); + + m_config->Read(wxT("/") + KEY_STARNET_PERMANENT8, &m_starNet8Permanent, DEFAULT_STARNET_PERMANENT); + + m_config->Read(wxT("/") + KEY_STARNET_USER_TIMEOUT8, &temp, long(DEFAULT_STARNET_USER_TIMEOUT)); + m_starNet8UserTimeout = (unsigned int)temp; + + m_config->Read(wxT("/") + KEY_STARNET_GROUP_TIMEOUT8, &temp, long(DEFAULT_STARNET_GROUP_TIMEOUT)); + m_starNet8GroupTimeout = (unsigned int)temp; + + m_config->Read(wxT("/") + KEY_STARNET_CALLSIGN_SWITCH8, &temp, long(DEFAULT_STARNET_CALLSIGN_SWITCH)); + m_starNet8CallsignSwitch = STARNET_CALLSIGN_SWITCH(temp); + + m_config->Read(wxT("/") + KEY_STARNET_TXMSG_SWITCH8, &m_starNet8TxMsgSwitch, DEFAULT_STARNET_TXMSG_SWITCH); + + m_config->Read(wxT("/") + KEY_STARNET_REFLECTOR8, &m_starNet8Reflector, DEFAULT_STARNET_REFLECTOR); + + m_config->Read(wxT("/") + KEY_STARNET_BAND9, &m_starNet9Band, DEFAULT_STARNET_BAND); + + m_config->Read(wxT("/") + KEY_STARNET_CALLSIGN9, &m_starNet9Callsign, DEFAULT_STARNET_CALLSIGN); + + m_config->Read(wxT("/") + KEY_STARNET_LOGOFF9, &m_starNet9Logoff, DEFAULT_STARNET_LOGOFF); + + m_config->Read(wxT("/") + KEY_STARNET_INFO9, &m_starNet9Info, DEFAULT_STARNET_INFO); + + m_config->Read(wxT("/") + KEY_STARNET_PERMANENT9, &m_starNet9Permanent, DEFAULT_STARNET_PERMANENT); + + m_config->Read(wxT("/") + KEY_STARNET_USER_TIMEOUT9, &temp, long(DEFAULT_STARNET_USER_TIMEOUT)); + m_starNet9UserTimeout = (unsigned int)temp; + + m_config->Read(wxT("/") + KEY_STARNET_GROUP_TIMEOUT9, &temp, long(DEFAULT_STARNET_GROUP_TIMEOUT)); + m_starNet9GroupTimeout = (unsigned int)temp; + + m_config->Read(wxT("/") + KEY_STARNET_CALLSIGN_SWITCH9, &temp, long(DEFAULT_STARNET_CALLSIGN_SWITCH)); + m_starNet9CallsignSwitch = STARNET_CALLSIGN_SWITCH(temp); + + m_config->Read(wxT("/") + KEY_STARNET_TXMSG_SWITCH9, &m_starNet9TxMsgSwitch, DEFAULT_STARNET_TXMSG_SWITCH); + + m_config->Read(wxT("/") + KEY_STARNET_REFLECTOR9, &m_starNet9Reflector, DEFAULT_STARNET_REFLECTOR); + + m_config->Read(wxT("/") + KEY_STARNET_BAND10, &m_starNet10Band, DEFAULT_STARNET_BAND); + + m_config->Read(wxT("/") + KEY_STARNET_CALLSIGN10, &m_starNet10Callsign, DEFAULT_STARNET_CALLSIGN); + + m_config->Read(wxT("/") + KEY_STARNET_LOGOFF10, &m_starNet10Logoff, DEFAULT_STARNET_LOGOFF); + + m_config->Read(wxT("/") + KEY_STARNET_INFO10, &m_starNet10Info, DEFAULT_STARNET_INFO); + + m_config->Read(wxT("/") + KEY_STARNET_PERMANENT10, &m_starNet10Permanent, DEFAULT_STARNET_PERMANENT); + + m_config->Read(wxT("/") + KEY_STARNET_USER_TIMEOUT10, &temp, long(DEFAULT_STARNET_USER_TIMEOUT)); + m_starNet10UserTimeout = (unsigned int)temp; + + m_config->Read(wxT("/") + KEY_STARNET_GROUP_TIMEOUT10, &temp, long(DEFAULT_STARNET_GROUP_TIMEOUT)); + m_starNet10GroupTimeout = (unsigned int)temp; + + m_config->Read(wxT("/") + KEY_STARNET_CALLSIGN_SWITCH10, &temp, long(DEFAULT_STARNET_CALLSIGN_SWITCH)); + m_starNet10CallsignSwitch = STARNET_CALLSIGN_SWITCH(temp); + + m_config->Read(wxT("/") + KEY_STARNET_TXMSG_SWITCH10, &m_starNet10TxMsgSwitch, DEFAULT_STARNET_TXMSG_SWITCH); + + m_config->Read(wxT("/") + KEY_STARNET_REFLECTOR10, &m_starNet10Reflector, DEFAULT_STARNET_REFLECTOR); + + m_config->Read(wxT("/") + KEY_STARNET_BAND11, &m_starNet11Band, DEFAULT_STARNET_BAND); + + m_config->Read(wxT("/") + KEY_STARNET_CALLSIGN11, &m_starNet11Callsign, DEFAULT_STARNET_CALLSIGN); + + m_config->Read(wxT("/") + KEY_STARNET_LOGOFF11, &m_starNet11Logoff, DEFAULT_STARNET_LOGOFF); + + m_config->Read(wxT("/") + KEY_STARNET_INFO11, &m_starNet11Info, DEFAULT_STARNET_INFO); + + m_config->Read(wxT("/") + KEY_STARNET_PERMANENT11, &m_starNet11Permanent, DEFAULT_STARNET_PERMANENT); + + m_config->Read(wxT("/") + KEY_STARNET_USER_TIMEOUT11, &temp, long(DEFAULT_STARNET_USER_TIMEOUT)); + m_starNet11UserTimeout = (unsigned int)temp; + + m_config->Read(wxT("/") + KEY_STARNET_GROUP_TIMEOUT11, &temp, long(DEFAULT_STARNET_GROUP_TIMEOUT)); + m_starNet11GroupTimeout = (unsigned int)temp; + + m_config->Read(wxT("/") + KEY_STARNET_CALLSIGN_SWITCH11, &temp, long(DEFAULT_STARNET_CALLSIGN_SWITCH)); + m_starNet11CallsignSwitch = STARNET_CALLSIGN_SWITCH(temp); + + m_config->Read(wxT("/") + KEY_STARNET_TXMSG_SWITCH11, &m_starNet11TxMsgSwitch, DEFAULT_STARNET_TXMSG_SWITCH); + + m_config->Read(wxT("/") + KEY_STARNET_REFLECTOR11, &m_starNet11Reflector, DEFAULT_STARNET_REFLECTOR); + + m_config->Read(wxT("/") + KEY_STARNET_BAND12, &m_starNet12Band, DEFAULT_STARNET_BAND); + + m_config->Read(wxT("/") + KEY_STARNET_CALLSIGN12, &m_starNet12Callsign, DEFAULT_STARNET_CALLSIGN); + + m_config->Read(wxT("/") + KEY_STARNET_LOGOFF12, &m_starNet12Logoff, DEFAULT_STARNET_LOGOFF); + + m_config->Read(wxT("/") + KEY_STARNET_INFO12, &m_starNet12Info, DEFAULT_STARNET_INFO); + + m_config->Read(wxT("/") + KEY_STARNET_PERMANENT12, &m_starNet12Permanent, DEFAULT_STARNET_PERMANENT); + + m_config->Read(wxT("/") + KEY_STARNET_USER_TIMEOUT12, &temp, long(DEFAULT_STARNET_USER_TIMEOUT)); + m_starNet12UserTimeout = (unsigned int)temp; + + m_config->Read(wxT("/") + KEY_STARNET_GROUP_TIMEOUT12, &temp, long(DEFAULT_STARNET_GROUP_TIMEOUT)); + m_starNet12GroupTimeout = (unsigned int)temp; + + m_config->Read(wxT("/") + KEY_STARNET_CALLSIGN_SWITCH12, &temp, long(DEFAULT_STARNET_CALLSIGN_SWITCH)); + m_starNet12CallsignSwitch = STARNET_CALLSIGN_SWITCH(temp); + + m_config->Read(wxT("/") + KEY_STARNET_TXMSG_SWITCH12, &m_starNet12TxMsgSwitch, DEFAULT_STARNET_TXMSG_SWITCH); + + m_config->Read(wxT("/") + KEY_STARNET_REFLECTOR12, &m_starNet12Reflector, DEFAULT_STARNET_REFLECTOR); + + m_config->Read(wxT("/") + KEY_STARNET_BAND13, &m_starNet13Band, DEFAULT_STARNET_BAND); + + m_config->Read(wxT("/") + KEY_STARNET_CALLSIGN13, &m_starNet13Callsign, DEFAULT_STARNET_CALLSIGN); + + m_config->Read(wxT("/") + KEY_STARNET_LOGOFF13, &m_starNet13Logoff, DEFAULT_STARNET_LOGOFF); + + m_config->Read(wxT("/") + KEY_STARNET_INFO13, &m_starNet13Info, DEFAULT_STARNET_INFO); + + m_config->Read(wxT("/") + KEY_STARNET_PERMANENT13, &m_starNet13Permanent, DEFAULT_STARNET_PERMANENT); + + m_config->Read(wxT("/") + KEY_STARNET_USER_TIMEOUT13, &temp, long(DEFAULT_STARNET_USER_TIMEOUT)); + m_starNet13UserTimeout = (unsigned int)temp; + + m_config->Read(wxT("/") + KEY_STARNET_GROUP_TIMEOUT13, &temp, long(DEFAULT_STARNET_GROUP_TIMEOUT)); + m_starNet13GroupTimeout = (unsigned int)temp; + + m_config->Read(wxT("/") + KEY_STARNET_CALLSIGN_SWITCH13, &temp, long(DEFAULT_STARNET_CALLSIGN_SWITCH)); + m_starNet13CallsignSwitch = STARNET_CALLSIGN_SWITCH(temp); + + m_config->Read(wxT("/") + KEY_STARNET_TXMSG_SWITCH13, &m_starNet13TxMsgSwitch, DEFAULT_STARNET_TXMSG_SWITCH); + + m_config->Read(wxT("/") + KEY_STARNET_REFLECTOR13, &m_starNet13Reflector, DEFAULT_STARNET_REFLECTOR); + + m_config->Read(wxT("/") + KEY_STARNET_BAND14, &m_starNet14Band, DEFAULT_STARNET_BAND); + + m_config->Read(wxT("/") + KEY_STARNET_CALLSIGN14, &m_starNet14Callsign, DEFAULT_STARNET_CALLSIGN); + + m_config->Read(wxT("/") + KEY_STARNET_LOGOFF14, &m_starNet14Logoff, DEFAULT_STARNET_LOGOFF); + + m_config->Read(wxT("/") + KEY_STARNET_INFO14, &m_starNet14Info, DEFAULT_STARNET_INFO); + + m_config->Read(wxT("/") + KEY_STARNET_PERMANENT14, &m_starNet14Permanent, DEFAULT_STARNET_PERMANENT); + + m_config->Read(wxT("/") + KEY_STARNET_USER_TIMEOUT14, &temp, long(DEFAULT_STARNET_USER_TIMEOUT)); + m_starNet14UserTimeout = (unsigned int)temp; + + m_config->Read(wxT("/") + KEY_STARNET_GROUP_TIMEOUT14, &temp, long(DEFAULT_STARNET_GROUP_TIMEOUT)); + m_starNet14GroupTimeout = (unsigned int)temp; + + m_config->Read(wxT("/") + KEY_STARNET_CALLSIGN_SWITCH14, &temp, long(DEFAULT_STARNET_CALLSIGN_SWITCH)); + m_starNet14CallsignSwitch = STARNET_CALLSIGN_SWITCH(temp); + + m_config->Read(wxT("/") + KEY_STARNET_TXMSG_SWITCH14, &m_starNet14TxMsgSwitch, DEFAULT_STARNET_TXMSG_SWITCH); + + m_config->Read(wxT("/") + KEY_STARNET_REFLECTOR14, &m_starNet14Reflector, DEFAULT_STARNET_REFLECTOR); + + m_config->Read(wxT("/") + KEY_STARNET_BAND15, &m_starNet15Band, DEFAULT_STARNET_BAND); + + m_config->Read(wxT("/") + KEY_STARNET_CALLSIGN15, &m_starNet15Callsign, DEFAULT_STARNET_CALLSIGN); + + m_config->Read(wxT("/") + KEY_STARNET_LOGOFF15, &m_starNet15Logoff, DEFAULT_STARNET_LOGOFF); + + m_config->Read(wxT("/") + KEY_STARNET_INFO15, &m_starNet15Info, DEFAULT_STARNET_INFO); + + m_config->Read(wxT("/") + KEY_STARNET_PERMANENT15, &m_starNet15Permanent, DEFAULT_STARNET_PERMANENT); + + m_config->Read(wxT("/") + KEY_STARNET_USER_TIMEOUT15, &temp, long(DEFAULT_STARNET_USER_TIMEOUT)); + m_starNet15UserTimeout = (unsigned int)temp; + + m_config->Read(wxT("/") + KEY_STARNET_GROUP_TIMEOUT15, &temp, long(DEFAULT_STARNET_GROUP_TIMEOUT)); + m_starNet15GroupTimeout = (unsigned int)temp; + + m_config->Read(wxT("/") + KEY_STARNET_CALLSIGN_SWITCH15, &temp, long(DEFAULT_STARNET_CALLSIGN_SWITCH)); + m_starNet15CallsignSwitch = STARNET_CALLSIGN_SWITCH(temp); + + m_config->Read(wxT("/") + KEY_STARNET_TXMSG_SWITCH15, &m_starNet15TxMsgSwitch, DEFAULT_STARNET_TXMSG_SWITCH); + + m_config->Read(wxT("/") + KEY_STARNET_REFLECTOR15, &m_starNet15Reflector, DEFAULT_STARNET_REFLECTOR); + + m_config->Read(wxT("/") + KEY_REMOTE_ENABLED, &m_remoteEnabled, DEFAULT_REMOTE_ENABLED); + + m_config->Read(wxT("/") + KEY_REMOTE_PASSWORD, &m_remotePassword, DEFAULT_REMOTE_PASSWORD); + + m_config->Read(wxT("/") + KEY_REMOTE_PORT, &temp, long(DEFAULT_REMOTE_PORT)); + m_remotePort = (unsigned int)temp; + + m_config->Read(wxT("/") + KEY_LOG_ENABLED, &m_logEnabled, DEFAULT_LOG_ENABLED); + + m_config->Read(wxT("/") + KEY_WINDOW_X, &temp, long(DEFAULT_WINDOW_X)); + m_x = int(temp); + + m_config->Read(wxT("/") + KEY_WINDOW_Y, &temp, long(DEFAULT_WINDOW_Y)); + m_y = int(temp); +} + +CStarNetServerConfig::~CStarNetServerConfig() +{ + delete m_config; +} + +#else + +CStarNetServerConfig::CStarNetServerConfig(const wxString& dir) : +m_fileName(), +m_callsign(DEFAULT_CALLSIGN), +m_address(DEFAULT_ADDRESS), +m_ircddbHostname(DEFAULT_IRCDDB_HOSTNAME), +m_ircddbUsername(DEFAULT_IRCDDB_USERNAME), +m_ircddbPassword(DEFAULT_IRCDDB_PASSWORD), +m_starNet1Band(DEFAULT_STARNET_BAND), +m_starNet1Callsign(DEFAULT_STARNET_CALLSIGN), +m_starNet1Logoff(DEFAULT_STARNET_LOGOFF), +m_starNet1Info(DEFAULT_STARNET_INFO), +m_starNet1Permanent(DEFAULT_STARNET_PERMANENT), +m_starNet1UserTimeout(DEFAULT_STARNET_USER_TIMEOUT), +m_starNet1GroupTimeout(DEFAULT_STARNET_GROUP_TIMEOUT), +m_starNet1CallsignSwitch(DEFAULT_STARNET_CALLSIGN_SWITCH), +m_starNet1TxMsgSwitch(DEFAULT_STARNET_TXMSG_SWITCH), +m_starNet1Reflector(DEFAULT_STARNET_REFLECTOR), +m_starNet2Band(DEFAULT_STARNET_BAND), +m_starNet2Callsign(DEFAULT_STARNET_CALLSIGN), +m_starNet2Logoff(DEFAULT_STARNET_LOGOFF), +m_starNet2Info(DEFAULT_STARNET_INFO), +m_starNet2Permanent(DEFAULT_STARNET_PERMANENT), +m_starNet2UserTimeout(DEFAULT_STARNET_USER_TIMEOUT), +m_starNet2GroupTimeout(DEFAULT_STARNET_GROUP_TIMEOUT), +m_starNet2CallsignSwitch(DEFAULT_STARNET_CALLSIGN_SWITCH), +m_starNet2TxMsgSwitch(DEFAULT_STARNET_TXMSG_SWITCH), +m_starNet2Reflector(DEFAULT_STARNET_REFLECTOR), +m_starNet3Band(DEFAULT_STARNET_BAND), +m_starNet3Callsign(DEFAULT_STARNET_CALLSIGN), +m_starNet3Logoff(DEFAULT_STARNET_LOGOFF), +m_starNet3Info(DEFAULT_STARNET_INFO), +m_starNet3Permanent(DEFAULT_STARNET_PERMANENT), +m_starNet3UserTimeout(DEFAULT_STARNET_USER_TIMEOUT), +m_starNet3GroupTimeout(DEFAULT_STARNET_GROUP_TIMEOUT), +m_starNet3CallsignSwitch(DEFAULT_STARNET_CALLSIGN_SWITCH), +m_starNet3TxMsgSwitch(DEFAULT_STARNET_TXMSG_SWITCH), +m_starNet3Reflector(DEFAULT_STARNET_REFLECTOR), +m_starNet4Band(DEFAULT_STARNET_BAND), +m_starNet4Callsign(DEFAULT_STARNET_CALLSIGN), +m_starNet4Logoff(DEFAULT_STARNET_LOGOFF), +m_starNet4Info(DEFAULT_STARNET_INFO), +m_starNet4Permanent(DEFAULT_STARNET_PERMANENT), +m_starNet4UserTimeout(DEFAULT_STARNET_USER_TIMEOUT), +m_starNet4GroupTimeout(DEFAULT_STARNET_GROUP_TIMEOUT), +m_starNet4CallsignSwitch(DEFAULT_STARNET_CALLSIGN_SWITCH), +m_starNet4TxMsgSwitch(DEFAULT_STARNET_TXMSG_SWITCH), +m_starNet4Reflector(DEFAULT_STARNET_REFLECTOR), +m_starNet5Band(DEFAULT_STARNET_BAND), +m_starNet5Callsign(DEFAULT_STARNET_CALLSIGN), +m_starNet5Logoff(DEFAULT_STARNET_LOGOFF), +m_starNet5Info(DEFAULT_STARNET_INFO), +m_starNet5Permanent(DEFAULT_STARNET_PERMANENT), +m_starNet5UserTimeout(DEFAULT_STARNET_USER_TIMEOUT), +m_starNet5GroupTimeout(DEFAULT_STARNET_GROUP_TIMEOUT), +m_starNet5CallsignSwitch(DEFAULT_STARNET_CALLSIGN_SWITCH), +m_starNet5TxMsgSwitch(DEFAULT_STARNET_TXMSG_SWITCH), +m_starNet5Reflector(DEFAULT_STARNET_REFLECTOR), +m_starNet6Band(DEFAULT_STARNET_BAND), +m_starNet6Callsign(DEFAULT_STARNET_CALLSIGN), +m_starNet6Logoff(DEFAULT_STARNET_LOGOFF), +m_starNet6Info(DEFAULT_STARNET_INFO), +m_starNet6Permanent(DEFAULT_STARNET_PERMANENT), +m_starNet6UserTimeout(DEFAULT_STARNET_USER_TIMEOUT), +m_starNet6GroupTimeout(DEFAULT_STARNET_GROUP_TIMEOUT), +m_starNet6CallsignSwitch(DEFAULT_STARNET_CALLSIGN_SWITCH), +m_starNet6TxMsgSwitch(DEFAULT_STARNET_TXMSG_SWITCH), +m_starNet6Reflector(DEFAULT_STARNET_REFLECTOR), +m_starNet7Band(DEFAULT_STARNET_BAND), +m_starNet7Callsign(DEFAULT_STARNET_CALLSIGN), +m_starNet7Logoff(DEFAULT_STARNET_LOGOFF), +m_starNet7Info(DEFAULT_STARNET_INFO), +m_starNet7Permanent(DEFAULT_STARNET_PERMANENT), +m_starNet7UserTimeout(DEFAULT_STARNET_USER_TIMEOUT), +m_starNet7GroupTimeout(DEFAULT_STARNET_GROUP_TIMEOUT), +m_starNet7CallsignSwitch(DEFAULT_STARNET_CALLSIGN_SWITCH), +m_starNet7TxMsgSwitch(DEFAULT_STARNET_TXMSG_SWITCH), +m_starNet7Reflector(DEFAULT_STARNET_REFLECTOR), +m_starNet8Band(DEFAULT_STARNET_BAND), +m_starNet8Callsign(DEFAULT_STARNET_CALLSIGN), +m_starNet8Logoff(DEFAULT_STARNET_LOGOFF), +m_starNet8Info(DEFAULT_STARNET_INFO), +m_starNet8Permanent(DEFAULT_STARNET_PERMANENT), +m_starNet8UserTimeout(DEFAULT_STARNET_USER_TIMEOUT), +m_starNet8GroupTimeout(DEFAULT_STARNET_GROUP_TIMEOUT), +m_starNet8CallsignSwitch(DEFAULT_STARNET_CALLSIGN_SWITCH), +m_starNet8TxMsgSwitch(DEFAULT_STARNET_TXMSG_SWITCH), +m_starNet8Reflector(DEFAULT_STARNET_REFLECTOR), +m_starNet9Band(DEFAULT_STARNET_BAND), +m_starNet9Callsign(DEFAULT_STARNET_CALLSIGN), +m_starNet9Logoff(DEFAULT_STARNET_LOGOFF), +m_starNet9Info(DEFAULT_STARNET_INFO), +m_starNet9Permanent(DEFAULT_STARNET_PERMANENT), +m_starNet9UserTimeout(DEFAULT_STARNET_USER_TIMEOUT), +m_starNet9GroupTimeout(DEFAULT_STARNET_GROUP_TIMEOUT), +m_starNet9CallsignSwitch(DEFAULT_STARNET_CALLSIGN_SWITCH), +m_starNet9TxMsgSwitch(DEFAULT_STARNET_TXMSG_SWITCH), +m_starNet9Reflector(DEFAULT_STARNET_REFLECTOR), +m_starNet10Band(DEFAULT_STARNET_BAND), +m_starNet10Callsign(DEFAULT_STARNET_CALLSIGN), +m_starNet10Logoff(DEFAULT_STARNET_LOGOFF), +m_starNet10Info(DEFAULT_STARNET_INFO), +m_starNet10Permanent(DEFAULT_STARNET_PERMANENT), +m_starNet10UserTimeout(DEFAULT_STARNET_USER_TIMEOUT), +m_starNet10GroupTimeout(DEFAULT_STARNET_GROUP_TIMEOUT), +m_starNet10CallsignSwitch(DEFAULT_STARNET_CALLSIGN_SWITCH), +m_starNet10TxMsgSwitch(DEFAULT_STARNET_TXMSG_SWITCH), +m_starNet10Reflector(DEFAULT_STARNET_REFLECTOR), +m_starNet11Band(DEFAULT_STARNET_BAND), +m_starNet11Callsign(DEFAULT_STARNET_CALLSIGN), +m_starNet11Logoff(DEFAULT_STARNET_LOGOFF), +m_starNet11Info(DEFAULT_STARNET_INFO), +m_starNet11Permanent(DEFAULT_STARNET_PERMANENT), +m_starNet11UserTimeout(DEFAULT_STARNET_USER_TIMEOUT), +m_starNet11GroupTimeout(DEFAULT_STARNET_GROUP_TIMEOUT), +m_starNet11CallsignSwitch(DEFAULT_STARNET_CALLSIGN_SWITCH), +m_starNet11TxMsgSwitch(DEFAULT_STARNET_TXMSG_SWITCH), +m_starNet11Reflector(DEFAULT_STARNET_REFLECTOR), +m_starNet12Band(DEFAULT_STARNET_BAND), +m_starNet12Callsign(DEFAULT_STARNET_CALLSIGN), +m_starNet12Logoff(DEFAULT_STARNET_LOGOFF), +m_starNet12Info(DEFAULT_STARNET_INFO), +m_starNet12Permanent(DEFAULT_STARNET_PERMANENT), +m_starNet12UserTimeout(DEFAULT_STARNET_USER_TIMEOUT), +m_starNet12GroupTimeout(DEFAULT_STARNET_GROUP_TIMEOUT), +m_starNet12CallsignSwitch(DEFAULT_STARNET_CALLSIGN_SWITCH), +m_starNet12TxMsgSwitch(DEFAULT_STARNET_TXMSG_SWITCH), +m_starNet12Reflector(DEFAULT_STARNET_REFLECTOR), +m_starNet13Band(DEFAULT_STARNET_BAND), +m_starNet13Callsign(DEFAULT_STARNET_CALLSIGN), +m_starNet13Logoff(DEFAULT_STARNET_LOGOFF), +m_starNet13Info(DEFAULT_STARNET_INFO), +m_starNet13Permanent(DEFAULT_STARNET_PERMANENT), +m_starNet13UserTimeout(DEFAULT_STARNET_USER_TIMEOUT), +m_starNet13GroupTimeout(DEFAULT_STARNET_GROUP_TIMEOUT), +m_starNet13CallsignSwitch(DEFAULT_STARNET_CALLSIGN_SWITCH), +m_starNet13TxMsgSwitch(DEFAULT_STARNET_TXMSG_SWITCH), +m_starNet13Reflector(DEFAULT_STARNET_REFLECTOR), +m_starNet14Band(DEFAULT_STARNET_BAND), +m_starNet14Callsign(DEFAULT_STARNET_CALLSIGN), +m_starNet14Logoff(DEFAULT_STARNET_LOGOFF), +m_starNet14Info(DEFAULT_STARNET_INFO), +m_starNet14Permanent(DEFAULT_STARNET_PERMANENT), +m_starNet14UserTimeout(DEFAULT_STARNET_USER_TIMEOUT), +m_starNet14GroupTimeout(DEFAULT_STARNET_GROUP_TIMEOUT), +m_starNet14CallsignSwitch(DEFAULT_STARNET_CALLSIGN_SWITCH), +m_starNet14TxMsgSwitch(DEFAULT_STARNET_TXMSG_SWITCH), +m_starNet14Reflector(DEFAULT_STARNET_REFLECTOR), +m_starNet15Band(DEFAULT_STARNET_BAND), +m_starNet15Callsign(DEFAULT_STARNET_CALLSIGN), +m_starNet15Logoff(DEFAULT_STARNET_LOGOFF), +m_starNet15Info(DEFAULT_STARNET_INFO), +m_starNet15Permanent(DEFAULT_STARNET_PERMANENT), +m_starNet15UserTimeout(DEFAULT_STARNET_USER_TIMEOUT), +m_starNet15GroupTimeout(DEFAULT_STARNET_GROUP_TIMEOUT), +m_starNet15CallsignSwitch(DEFAULT_STARNET_CALLSIGN_SWITCH), +m_starNet15TxMsgSwitch(DEFAULT_STARNET_TXMSG_SWITCH), +m_starNet15Reflector(DEFAULT_STARNET_REFLECTOR), +m_remoteEnabled(DEFAULT_REMOTE_ENABLED), +m_remotePassword(DEFAULT_REMOTE_PASSWORD), +m_remotePort(DEFAULT_REMOTE_PORT), +m_logEnabled(DEFAULT_LOG_ENABLED), +m_x(DEFAULT_WINDOW_X), +m_y(DEFAULT_WINDOW_Y) +{ + wxASSERT(!dir.IsEmpty()); + + m_fileName.Assign(dir, CONFIG_FILE_NAME); + + wxTextFile file(m_fileName.GetFullPath()); + + bool exists = file.Exists(); + if (!exists) + return; + + bool ret = file.Open(); + if (!ret) { + wxLogError(wxT("Cannot open the config file - %s"), m_fileName.GetFullPath().c_str()); + return; + } + + long temp1; + unsigned long temp2; + + wxString str = file.GetFirstLine(); + + while (!file.Eof()) { + if (str.GetChar(0U) == wxT('#')) { + str = file.GetNextLine(); + continue; + } + + int n = str.Find(wxT('=')); + if (n == wxNOT_FOUND) { + str = file.GetNextLine(); + continue; + } + + wxString key = str.Left(n); + wxString val = str.Mid(n + 1U); + + if (key.IsSameAs(KEY_CALLSIGN)) { + m_callsign = val; + } else if (key.IsSameAs(KEY_ADDRESS)) { + m_address = val; + } else if (key.IsSameAs(KEY_IRCDDB_HOSTNAME)) { + m_ircddbHostname = val; + } else if (key.IsSameAs(KEY_IRCDDB_USERNAME)) { + m_ircddbUsername = val; + } else if (key.IsSameAs(KEY_IRCDDB_PASSWORD)) { + m_ircddbPassword = val; + } else if (key.IsSameAs(KEY_STARNET_BAND1)) { + m_starNet1Band = val; + } else if (key.IsSameAs(KEY_STARNET_CALLSIGN1)) { + m_starNet1Callsign = val; + } else if (key.IsSameAs(KEY_STARNET_LOGOFF1)) { + m_starNet1Logoff = val; + } else if (key.IsSameAs(KEY_STARNET_INFO1)) { + m_starNet1Info = val; + } else if (key.IsSameAs(KEY_STARNET_PERMANENT1)) { + m_starNet1Permanent = val; + } else if (key.IsSameAs(KEY_STARNET_USER_TIMEOUT1)) { + val.ToULong(&temp2); + m_starNet1UserTimeout = (unsigned int)temp2; + } else if (key.IsSameAs(KEY_STARNET_GROUP_TIMEOUT1)) { + val.ToULong(&temp2); + m_starNet1GroupTimeout = (unsigned int)temp2; + } else if (key.IsSameAs(KEY_STARNET_CALLSIGN_SWITCH1)) { + val.ToLong(&temp1); + m_starNet1CallsignSwitch = STARNET_CALLSIGN_SWITCH(temp1); + } else if (key.IsSameAs(KEY_STARNET_TXMSG_SWITCH1)) { + val.ToLong(&temp1); + m_starNet1TxMsgSwitch = temp1 == 1L; + } else if (key.IsSameAs(KEY_STARNET_REFLECTOR1)) { + m_starNet1Reflector = val; + } else if (key.IsSameAs(KEY_STARNET_BAND2)) { + m_starNet2Band = val; + } else if (key.IsSameAs(KEY_STARNET_CALLSIGN2)) { + m_starNet2Callsign = val; + } else if (key.IsSameAs(KEY_STARNET_LOGOFF2)) { + m_starNet2Logoff = val; + } else if (key.IsSameAs(KEY_STARNET_INFO2)) { + m_starNet2Info = val; + } else if (key.IsSameAs(KEY_STARNET_PERMANENT2)) { + m_starNet2Permanent = val; + } else if (key.IsSameAs(KEY_STARNET_USER_TIMEOUT2)) { + val.ToULong(&temp2); + m_starNet2UserTimeout = (unsigned int)temp2; + } else if (key.IsSameAs(KEY_STARNET_GROUP_TIMEOUT2)) { + val.ToULong(&temp2); + m_starNet2GroupTimeout = (unsigned int)temp2; + } else if (key.IsSameAs(KEY_STARNET_CALLSIGN_SWITCH2)) { + val.ToLong(&temp1); + m_starNet2CallsignSwitch = STARNET_CALLSIGN_SWITCH(temp1); + } else if (key.IsSameAs(KEY_STARNET_TXMSG_SWITCH2)) { + val.ToLong(&temp1); + m_starNet2TxMsgSwitch = temp1 == 1L; + } else if (key.IsSameAs(KEY_STARNET_REFLECTOR2)) { + m_starNet2Reflector = val; + } else if (key.IsSameAs(KEY_STARNET_BAND3)) { + m_starNet3Band = val; + } else if (key.IsSameAs(KEY_STARNET_CALLSIGN3)) { + m_starNet3Callsign = val; + } else if (key.IsSameAs(KEY_STARNET_LOGOFF3)) { + m_starNet3Logoff = val; + } else if (key.IsSameAs(KEY_STARNET_INFO3)) { + m_starNet3Info = val; + } else if (key.IsSameAs(KEY_STARNET_PERMANENT3)) { + m_starNet3Permanent = val; + } else if (key.IsSameAs(KEY_STARNET_USER_TIMEOUT3)) { + val.ToULong(&temp2); + m_starNet3UserTimeout = (unsigned int)temp2; + } else if (key.IsSameAs(KEY_STARNET_GROUP_TIMEOUT3)) { + val.ToULong(&temp2); + m_starNet3GroupTimeout = (unsigned int)temp2; + } else if (key.IsSameAs(KEY_STARNET_CALLSIGN_SWITCH3)) { + val.ToLong(&temp1); + m_starNet3CallsignSwitch = STARNET_CALLSIGN_SWITCH(temp1); + } else if (key.IsSameAs(KEY_STARNET_TXMSG_SWITCH3)) { + val.ToLong(&temp1); + m_starNet3TxMsgSwitch = temp1 == 1L; + } else if (key.IsSameAs(KEY_STARNET_REFLECTOR3)) { + m_starNet3Reflector = val; + } else if (key.IsSameAs(KEY_STARNET_BAND4)) { + m_starNet4Band = val; + } else if (key.IsSameAs(KEY_STARNET_CALLSIGN4)) { + m_starNet4Callsign = val; + } else if (key.IsSameAs(KEY_STARNET_LOGOFF4)) { + m_starNet4Logoff = val; + } else if (key.IsSameAs(KEY_STARNET_INFO4)) { + m_starNet4Info = val; + } else if (key.IsSameAs(KEY_STARNET_PERMANENT4)) { + m_starNet4Permanent = val; + } else if (key.IsSameAs(KEY_STARNET_USER_TIMEOUT4)) { + val.ToULong(&temp2); + m_starNet4UserTimeout = (unsigned int)temp2; + } else if (key.IsSameAs(KEY_STARNET_GROUP_TIMEOUT4)) { + val.ToULong(&temp2); + m_starNet4GroupTimeout = (unsigned int)temp2; + } else if (key.IsSameAs(KEY_STARNET_CALLSIGN_SWITCH4)) { + val.ToLong(&temp1); + m_starNet4CallsignSwitch = STARNET_CALLSIGN_SWITCH(temp1); + } else if (key.IsSameAs(KEY_STARNET_TXMSG_SWITCH4)) { + val.ToLong(&temp1); + m_starNet4TxMsgSwitch = temp1 == 1L; + } else if (key.IsSameAs(KEY_STARNET_REFLECTOR4)) { + m_starNet4Reflector = val; + } else if (key.IsSameAs(KEY_STARNET_BAND5)) { + m_starNet5Band = val; + } else if (key.IsSameAs(KEY_STARNET_CALLSIGN5)) { + m_starNet5Callsign = val; + } else if (key.IsSameAs(KEY_STARNET_LOGOFF5)) { + m_starNet5Logoff = val; + } else if (key.IsSameAs(KEY_STARNET_INFO5)) { + m_starNet5Info = val; + } else if (key.IsSameAs(KEY_STARNET_PERMANENT5)) { + m_starNet5Permanent = val; + } else if (key.IsSameAs(KEY_STARNET_USER_TIMEOUT5)) { + val.ToULong(&temp2); + m_starNet5UserTimeout = (unsigned int)temp2; + } else if (key.IsSameAs(KEY_STARNET_GROUP_TIMEOUT5)) { + val.ToULong(&temp2); + m_starNet5GroupTimeout = (unsigned int)temp2; + } else if (key.IsSameAs(KEY_STARNET_CALLSIGN_SWITCH5)) { + val.ToLong(&temp1); + m_starNet5CallsignSwitch = STARNET_CALLSIGN_SWITCH(temp1); + } else if (key.IsSameAs(KEY_STARNET_TXMSG_SWITCH5)) { + val.ToLong(&temp1); + m_starNet5TxMsgSwitch = temp1 == 1L; + } else if (key.IsSameAs(KEY_STARNET_REFLECTOR5)) { + m_starNet5Reflector = val; + } else if (key.IsSameAs(KEY_STARNET_BAND6)) { + m_starNet6Band = val; + } else if (key.IsSameAs(KEY_STARNET_CALLSIGN6)) { + m_starNet6Callsign = val; + } else if (key.IsSameAs(KEY_STARNET_LOGOFF6)) { + m_starNet6Logoff = val; + } else if (key.IsSameAs(KEY_STARNET_INFO6)) { + m_starNet6Info = val; + } else if (key.IsSameAs(KEY_STARNET_PERMANENT6)) { + m_starNet6Permanent = val; + } else if (key.IsSameAs(KEY_STARNET_USER_TIMEOUT6)) { + val.ToULong(&temp2); + m_starNet6UserTimeout = (unsigned int)temp2; + } else if (key.IsSameAs(KEY_STARNET_GROUP_TIMEOUT6)) { + val.ToULong(&temp2); + m_starNet6GroupTimeout = (unsigned int)temp2; + } else if (key.IsSameAs(KEY_STARNET_CALLSIGN_SWITCH6)) { + val.ToLong(&temp1); + m_starNet6CallsignSwitch = STARNET_CALLSIGN_SWITCH(temp1); + } else if (key.IsSameAs(KEY_STARNET_TXMSG_SWITCH6)) { + val.ToLong(&temp1); + m_starNet6TxMsgSwitch = temp1 == 1L; + } else if (key.IsSameAs(KEY_STARNET_REFLECTOR6)) { + m_starNet6Reflector = val; + } else if (key.IsSameAs(KEY_STARNET_BAND7)) { + m_starNet7Band = val; + } else if (key.IsSameAs(KEY_STARNET_CALLSIGN7)) { + m_starNet7Callsign = val; + } else if (key.IsSameAs(KEY_STARNET_LOGOFF7)) { + m_starNet7Logoff = val; + } else if (key.IsSameAs(KEY_STARNET_INFO7)) { + m_starNet7Info = val; + } else if (key.IsSameAs(KEY_STARNET_PERMANENT7)) { + m_starNet7Permanent = val; + } else if (key.IsSameAs(KEY_STARNET_USER_TIMEOUT7)) { + val.ToULong(&temp2); + m_starNet7UserTimeout = (unsigned int)temp2; + } else if (key.IsSameAs(KEY_STARNET_GROUP_TIMEOUT7)) { + val.ToULong(&temp2); + m_starNet7GroupTimeout = (unsigned int)temp2; + } else if (key.IsSameAs(KEY_STARNET_CALLSIGN_SWITCH7)) { + val.ToLong(&temp1); + m_starNet7CallsignSwitch = STARNET_CALLSIGN_SWITCH(temp1); + } else if (key.IsSameAs(KEY_STARNET_TXMSG_SWITCH7)) { + val.ToLong(&temp1); + m_starNet7TxMsgSwitch = temp1 == 1L; + } else if (key.IsSameAs(KEY_STARNET_REFLECTOR7)) { + m_starNet7Reflector = val; + } else if (key.IsSameAs(KEY_STARNET_BAND8)) { + m_starNet8Band = val; + } else if (key.IsSameAs(KEY_STARNET_CALLSIGN8)) { + m_starNet8Callsign = val; + } else if (key.IsSameAs(KEY_STARNET_LOGOFF8)) { + m_starNet8Logoff = val; + } else if (key.IsSameAs(KEY_STARNET_INFO8)) { + m_starNet8Info = val; + } else if (key.IsSameAs(KEY_STARNET_PERMANENT8)) { + m_starNet8Permanent = val; + } else if (key.IsSameAs(KEY_STARNET_USER_TIMEOUT8)) { + val.ToULong(&temp2); + m_starNet8UserTimeout = (unsigned int)temp2; + } else if (key.IsSameAs(KEY_STARNET_GROUP_TIMEOUT8)) { + val.ToULong(&temp2); + m_starNet8GroupTimeout = (unsigned int)temp2; + } else if (key.IsSameAs(KEY_STARNET_CALLSIGN_SWITCH8)) { + val.ToLong(&temp1); + m_starNet8CallsignSwitch = STARNET_CALLSIGN_SWITCH(temp1); + } else if (key.IsSameAs(KEY_STARNET_TXMSG_SWITCH8)) { + val.ToLong(&temp1); + m_starNet8TxMsgSwitch = temp1 == 1L; + } else if (key.IsSameAs(KEY_STARNET_REFLECTOR8)) { + m_starNet8Reflector = val; + } else if (key.IsSameAs(KEY_STARNET_BAND9)) { + m_starNet9Band = val; + } else if (key.IsSameAs(KEY_STARNET_CALLSIGN9)) { + m_starNet9Callsign = val; + } else if (key.IsSameAs(KEY_STARNET_LOGOFF9)) { + m_starNet9Logoff = val; + } else if (key.IsSameAs(KEY_STARNET_INFO9)) { + m_starNet9Info = val; + } else if (key.IsSameAs(KEY_STARNET_PERMANENT9)) { + m_starNet9Permanent = val; + } else if (key.IsSameAs(KEY_STARNET_USER_TIMEOUT9)) { + val.ToULong(&temp2); + m_starNet9UserTimeout = (unsigned int)temp2; + } else if (key.IsSameAs(KEY_STARNET_GROUP_TIMEOUT9)) { + val.ToULong(&temp2); + m_starNet9GroupTimeout = (unsigned int)temp2; + } else if (key.IsSameAs(KEY_STARNET_CALLSIGN_SWITCH9)) { + val.ToLong(&temp1); + m_starNet9CallsignSwitch = STARNET_CALLSIGN_SWITCH(temp1); + } else if (key.IsSameAs(KEY_STARNET_TXMSG_SWITCH9)) { + val.ToLong(&temp1); + m_starNet9TxMsgSwitch = temp1 == 1L; + } else if (key.IsSameAs(KEY_STARNET_REFLECTOR9)) { + m_starNet9Reflector = val; + } else if (key.IsSameAs(KEY_STARNET_BAND10)) { + m_starNet10Band = val; + } else if (key.IsSameAs(KEY_STARNET_CALLSIGN10)) { + m_starNet10Callsign = val; + } else if (key.IsSameAs(KEY_STARNET_LOGOFF10)) { + m_starNet10Logoff = val; + } else if (key.IsSameAs(KEY_STARNET_INFO10)) { + m_starNet10Info = val; + } else if (key.IsSameAs(KEY_STARNET_PERMANENT10)) { + m_starNet10Permanent = val; + } else if (key.IsSameAs(KEY_STARNET_USER_TIMEOUT10)) { + val.ToULong(&temp2); + m_starNet10UserTimeout = (unsigned int)temp2; + } else if (key.IsSameAs(KEY_STARNET_GROUP_TIMEOUT10)) { + val.ToULong(&temp2); + m_starNet10GroupTimeout = (unsigned int)temp2; + } else if (key.IsSameAs(KEY_STARNET_CALLSIGN_SWITCH10)) { + val.ToLong(&temp1); + m_starNet10CallsignSwitch = STARNET_CALLSIGN_SWITCH(temp1); + } else if (key.IsSameAs(KEY_STARNET_TXMSG_SWITCH10)) { + val.ToLong(&temp1); + m_starNet10TxMsgSwitch = temp1 == 1L; + } else if (key.IsSameAs(KEY_STARNET_REFLECTOR10)) { + m_starNet10Reflector = val; + } else if (key.IsSameAs(KEY_STARNET_BAND11)) { + m_starNet11Band = val; + } else if (key.IsSameAs(KEY_STARNET_CALLSIGN11)) { + m_starNet11Callsign = val; + } else if (key.IsSameAs(KEY_STARNET_LOGOFF11)) { + m_starNet11Logoff = val; + } else if (key.IsSameAs(KEY_STARNET_INFO11)) { + m_starNet11Info = val; + } else if (key.IsSameAs(KEY_STARNET_PERMANENT11)) { + m_starNet11Permanent = val; + } else if (key.IsSameAs(KEY_STARNET_USER_TIMEOUT11)) { + val.ToULong(&temp2); + m_starNet11UserTimeout = (unsigned int)temp2; + } else if (key.IsSameAs(KEY_STARNET_GROUP_TIMEOUT11)) { + val.ToULong(&temp2); + m_starNet11GroupTimeout = (unsigned int)temp2; + } else if (key.IsSameAs(KEY_STARNET_CALLSIGN_SWITCH11)) { + val.ToLong(&temp1); + m_starNet11CallsignSwitch = STARNET_CALLSIGN_SWITCH(temp1); + } else if (key.IsSameAs(KEY_STARNET_TXMSG_SWITCH11)) { + val.ToLong(&temp1); + m_starNet11TxMsgSwitch = temp1 == 1L; + } else if (key.IsSameAs(KEY_STARNET_REFLECTOR11)) { + m_starNet11Reflector = val; + } else if (key.IsSameAs(KEY_STARNET_BAND12)) { + m_starNet12Band = val; + } else if (key.IsSameAs(KEY_STARNET_CALLSIGN12)) { + m_starNet12Callsign = val; + } else if (key.IsSameAs(KEY_STARNET_LOGOFF12)) { + m_starNet12Logoff = val; + } else if (key.IsSameAs(KEY_STARNET_INFO12)) { + m_starNet12Info = val; + } else if (key.IsSameAs(KEY_STARNET_PERMANENT12)) { + m_starNet12Permanent = val; + } else if (key.IsSameAs(KEY_STARNET_USER_TIMEOUT12)) { + val.ToULong(&temp2); + m_starNet12UserTimeout = (unsigned int)temp2; + } else if (key.IsSameAs(KEY_STARNET_GROUP_TIMEOUT12)) { + val.ToULong(&temp2); + m_starNet12GroupTimeout = (unsigned int)temp2; + } else if (key.IsSameAs(KEY_STARNET_CALLSIGN_SWITCH12)) { + val.ToLong(&temp1); + m_starNet12CallsignSwitch = STARNET_CALLSIGN_SWITCH(temp1); + } else if (key.IsSameAs(KEY_STARNET_TXMSG_SWITCH12)) { + val.ToLong(&temp1); + m_starNet12TxMsgSwitch = temp1 == 1L; + } else if (key.IsSameAs(KEY_STARNET_REFLECTOR12)) { + m_starNet12Reflector = val; + } else if (key.IsSameAs(KEY_STARNET_BAND13)) { + m_starNet13Band = val; + } else if (key.IsSameAs(KEY_STARNET_CALLSIGN13)) { + m_starNet13Callsign = val; + } else if (key.IsSameAs(KEY_STARNET_LOGOFF13)) { + m_starNet13Logoff = val; + } else if (key.IsSameAs(KEY_STARNET_INFO13)) { + m_starNet13Info = val; + } else if (key.IsSameAs(KEY_STARNET_PERMANENT13)) { + m_starNet13Permanent = val; + } else if (key.IsSameAs(KEY_STARNET_USER_TIMEOUT13)) { + val.ToULong(&temp2); + m_starNet13UserTimeout = (unsigned int)temp2; + } else if (key.IsSameAs(KEY_STARNET_GROUP_TIMEOUT13)) { + val.ToULong(&temp2); + m_starNet13GroupTimeout = (unsigned int)temp2; + } else if (key.IsSameAs(KEY_STARNET_CALLSIGN_SWITCH13)) { + val.ToLong(&temp1); + m_starNet13CallsignSwitch = STARNET_CALLSIGN_SWITCH(temp1); + } else if (key.IsSameAs(KEY_STARNET_TXMSG_SWITCH13)) { + val.ToLong(&temp1); + m_starNet13TxMsgSwitch = temp1 == 1L; + } else if (key.IsSameAs(KEY_STARNET_REFLECTOR13)) { + m_starNet13Reflector = val; + } else if (key.IsSameAs(KEY_STARNET_BAND14)) { + m_starNet14Band = val; + } else if (key.IsSameAs(KEY_STARNET_CALLSIGN14)) { + m_starNet14Callsign = val; + } else if (key.IsSameAs(KEY_STARNET_LOGOFF14)) { + m_starNet14Logoff = val; + } else if (key.IsSameAs(KEY_STARNET_INFO14)) { + m_starNet14Info = val; + } else if (key.IsSameAs(KEY_STARNET_PERMANENT14)) { + m_starNet14Permanent = val; + } else if (key.IsSameAs(KEY_STARNET_USER_TIMEOUT14)) { + val.ToULong(&temp2); + m_starNet14UserTimeout = (unsigned int)temp2; + } else if (key.IsSameAs(KEY_STARNET_GROUP_TIMEOUT14)) { + val.ToULong(&temp2); + m_starNet14GroupTimeout = (unsigned int)temp2; + } else if (key.IsSameAs(KEY_STARNET_CALLSIGN_SWITCH14)) { + val.ToLong(&temp1); + m_starNet14CallsignSwitch = STARNET_CALLSIGN_SWITCH(temp1); + } else if (key.IsSameAs(KEY_STARNET_TXMSG_SWITCH14)) { + val.ToLong(&temp1); + m_starNet14TxMsgSwitch = temp1 == 1L; + } else if (key.IsSameAs(KEY_STARNET_REFLECTOR14)) { + m_starNet14Reflector = val; + } else if (key.IsSameAs(KEY_STARNET_BAND15)) { + m_starNet15Band = val; + } else if (key.IsSameAs(KEY_STARNET_CALLSIGN15)) { + m_starNet15Callsign = val; + } else if (key.IsSameAs(KEY_STARNET_LOGOFF15)) { + m_starNet15Logoff = val; + } else if (key.IsSameAs(KEY_STARNET_INFO15)) { + m_starNet15Info = val; + } else if (key.IsSameAs(KEY_STARNET_PERMANENT15)) { + m_starNet15Permanent = val; + } else if (key.IsSameAs(KEY_STARNET_USER_TIMEOUT15)) { + val.ToULong(&temp2); + m_starNet15UserTimeout = (unsigned int)temp2; + } else if (key.IsSameAs(KEY_STARNET_GROUP_TIMEOUT15)) { + val.ToULong(&temp2); + m_starNet15GroupTimeout = (unsigned int)temp2; + } else if (key.IsSameAs(KEY_STARNET_CALLSIGN_SWITCH15)) { + val.ToLong(&temp1); + m_starNet15CallsignSwitch = STARNET_CALLSIGN_SWITCH(temp1); + } else if (key.IsSameAs(KEY_STARNET_TXMSG_SWITCH15)) { + val.ToLong(&temp1); + m_starNet15TxMsgSwitch = temp1 == 1L; + } else if (key.IsSameAs(KEY_STARNET_REFLECTOR15)) { + m_starNet15Reflector = val; + } else if (key.IsSameAs(KEY_REMOTE_ENABLED)) { + val.ToLong(&temp1); + m_remoteEnabled = temp1 == 1L; + } else if (key.IsSameAs(KEY_REMOTE_PASSWORD)) { + m_remotePassword = val; + } else if (key.IsSameAs(KEY_REMOTE_PORT)) { + val.ToULong(&temp2); + m_remotePort = (unsigned int)temp2; + } else if (key.IsSameAs(KEY_LOG_ENABLED)) { + val.ToLong(&temp1); + m_logEnabled = temp1 == 1L; + } else if (key.IsSameAs(KEY_WINDOW_X)) { + val.ToLong(&temp1); + m_x = int(temp1); + } else if (key.IsSameAs(KEY_WINDOW_Y)) { + val.ToLong(&temp1); + m_y = int(temp1); + } + + str = file.GetNextLine(); + } + + file.Close(); +} + +CStarNetServerConfig::~CStarNetServerConfig() +{ +} + +#endif + +void CStarNetServerConfig::getGateway(wxString& callsign, wxString& address) const +{ + callsign = m_callsign; + address = m_address; +} + +void CStarNetServerConfig::setGateway(const wxString& callsign, const wxString& address) +{ + m_callsign = callsign; + m_address = address; +} + +void CStarNetServerConfig::getIrcDDB(wxString& hostname, wxString& username, wxString& password) const +{ + hostname = m_ircddbHostname; + username = m_ircddbUsername; + password = m_ircddbPassword; +} + +void CStarNetServerConfig::setIrcDDB(const wxString& hostname, const wxString& username, const wxString& password) +{ + m_ircddbHostname = hostname; + m_ircddbUsername = username; + m_ircddbPassword = password; +} + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) +void CStarNetServerConfig::getStarNet1(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch, wxString& reflector) const +#else +void CStarNetServerConfig::getStarNet1(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch) const +#endif +{ + band = m_starNet1Band; + callsign = m_starNet1Callsign; + logoff = m_starNet1Logoff; + info = m_starNet1Info; + permanent = m_starNet1Permanent; + userTimeout = m_starNet1UserTimeout; + groupTimeout = m_starNet1GroupTimeout; + callsignSwitch = m_starNet1CallsignSwitch; + txMsgSwitch = m_starNet1TxMsgSwitch; + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + reflector = m_starNet1Reflector; +#endif +} + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) +void CStarNetServerConfig::setStarNet1(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch, const wxString& reflector) +#else +void CStarNetServerConfig::setStarNet1(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch) +#endif +{ + m_starNet1Band = band; + m_starNet1Callsign = callsign; + m_starNet1Logoff = logoff; + m_starNet1Info = info; + m_starNet1Permanent = permanent; + m_starNet1UserTimeout = userTimeout; + m_starNet1GroupTimeout = groupTimeout; + m_starNet1CallsignSwitch = callsignSwitch; + m_starNet1TxMsgSwitch = txMsgSwitch; + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + m_starNet1Reflector = reflector; +#endif +} + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) +void CStarNetServerConfig::getStarNet2(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch, wxString& reflector) const +#else +void CStarNetServerConfig::getStarNet2(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch) const +#endif +{ + band = m_starNet2Band; + callsign = m_starNet2Callsign; + logoff = m_starNet2Logoff; + info = m_starNet2Info; + permanent = m_starNet2Permanent; + userTimeout = m_starNet2UserTimeout; + groupTimeout = m_starNet2GroupTimeout; + callsignSwitch = m_starNet2CallsignSwitch; + txMsgSwitch = m_starNet2TxMsgSwitch; + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + reflector = m_starNet2Reflector; +#endif +} + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) +void CStarNetServerConfig::setStarNet2(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch, const wxString& reflector) +#else +void CStarNetServerConfig::setStarNet2(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch) +#endif +{ + m_starNet2Band = band; + m_starNet2Callsign = callsign; + m_starNet2Logoff = logoff; + m_starNet2Info = info; + m_starNet2Permanent = permanent; + m_starNet2UserTimeout = userTimeout; + m_starNet2GroupTimeout = groupTimeout; + m_starNet2CallsignSwitch = callsignSwitch; + m_starNet2TxMsgSwitch = txMsgSwitch; + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + m_starNet2Reflector = reflector; +#endif +} + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) +void CStarNetServerConfig::getStarNet3(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch, wxString& reflector) const +#else +void CStarNetServerConfig::getStarNet3(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch) const +#endif +{ + band = m_starNet3Band; + callsign = m_starNet3Callsign; + logoff = m_starNet3Logoff; + info = m_starNet3Info; + permanent = m_starNet3Permanent; + userTimeout = m_starNet3UserTimeout; + groupTimeout = m_starNet3GroupTimeout; + callsignSwitch = m_starNet3CallsignSwitch; + txMsgSwitch = m_starNet3TxMsgSwitch; + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + reflector = m_starNet3Reflector; +#endif +} + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) +void CStarNetServerConfig::setStarNet3(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch, const wxString& reflector) +#else +void CStarNetServerConfig::setStarNet3(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch) +#endif +{ + m_starNet3Band = band; + m_starNet3Callsign = callsign; + m_starNet3Logoff = logoff; + m_starNet3Info = info; + m_starNet3Permanent = permanent; + m_starNet3UserTimeout = userTimeout; + m_starNet3GroupTimeout = groupTimeout; + m_starNet3CallsignSwitch = callsignSwitch; + m_starNet3TxMsgSwitch = txMsgSwitch; + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + m_starNet3Reflector = reflector; +#endif +} + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) +void CStarNetServerConfig::getStarNet4(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch, wxString& reflector) const +#else +void CStarNetServerConfig::getStarNet4(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch) const +#endif +{ + band = m_starNet4Band; + callsign = m_starNet4Callsign; + logoff = m_starNet4Logoff; + info = m_starNet4Info; + permanent = m_starNet4Permanent; + userTimeout = m_starNet4UserTimeout; + groupTimeout = m_starNet4GroupTimeout; + callsignSwitch = m_starNet4CallsignSwitch; + txMsgSwitch = m_starNet4TxMsgSwitch; + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + reflector = m_starNet4Reflector; +#endif +} + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) +void CStarNetServerConfig::setStarNet4(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch, const wxString& reflector) +#else +void CStarNetServerConfig::setStarNet4(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch) +#endif +{ + m_starNet4Band = band; + m_starNet4Callsign = callsign; + m_starNet4Logoff = logoff; + m_starNet4Info = info; + m_starNet4Permanent = permanent; + m_starNet4UserTimeout = userTimeout; + m_starNet4GroupTimeout = groupTimeout; + m_starNet4CallsignSwitch = callsignSwitch; + m_starNet4TxMsgSwitch = txMsgSwitch; + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + m_starNet4Reflector = reflector; +#endif +} + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) +void CStarNetServerConfig::getStarNet5(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch, wxString& reflector) const +#else +void CStarNetServerConfig::getStarNet5(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch) const +#endif +{ + band = m_starNet5Band; + callsign = m_starNet5Callsign; + logoff = m_starNet5Logoff; + info = m_starNet5Info; + permanent = m_starNet5Permanent; + userTimeout = m_starNet5UserTimeout; + groupTimeout = m_starNet5GroupTimeout; + callsignSwitch = m_starNet5CallsignSwitch; + txMsgSwitch = m_starNet5TxMsgSwitch; + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + reflector = m_starNet5Reflector; +#endif +} + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) +void CStarNetServerConfig::setStarNet5(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch, const wxString& reflector) +#else +void CStarNetServerConfig::setStarNet5(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch) +#endif +{ + m_starNet5Band = band; + m_starNet5Callsign = callsign; + m_starNet5Logoff = logoff; + m_starNet5Info = info; + m_starNet5Permanent = permanent; + m_starNet5UserTimeout = userTimeout; + m_starNet5GroupTimeout = groupTimeout; + m_starNet5CallsignSwitch = callsignSwitch; + m_starNet5TxMsgSwitch = txMsgSwitch; + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + m_starNet5Reflector = reflector; +#endif +} + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) +void CStarNetServerConfig::getStarNet6(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch, wxString& reflector) const +#else +void CStarNetServerConfig::getStarNet6(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch) const +#endif +{ + band = m_starNet6Band; + callsign = m_starNet6Callsign; + logoff = m_starNet6Logoff; + info = m_starNet6Info; + permanent = m_starNet6Permanent; + userTimeout = m_starNet6UserTimeout; + groupTimeout = m_starNet6GroupTimeout; + callsignSwitch = m_starNet6CallsignSwitch; + txMsgSwitch = m_starNet6TxMsgSwitch; + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + reflector = m_starNet6Reflector; +#endif +} + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) +void CStarNetServerConfig::setStarNet6(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch, const wxString& reflector) +#else +void CStarNetServerConfig::setStarNet6(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch) +#endif +{ + m_starNet6Band = band; + m_starNet6Callsign = callsign; + m_starNet6Logoff = logoff; + m_starNet6Info = info; + m_starNet6Permanent = permanent; + m_starNet6UserTimeout = userTimeout; + m_starNet6GroupTimeout = groupTimeout; + m_starNet6CallsignSwitch = callsignSwitch; + m_starNet6TxMsgSwitch = txMsgSwitch; + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + m_starNet6Reflector = reflector; +#endif +} + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) +void CStarNetServerConfig::getStarNet7(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch, wxString& reflector) const +#else +void CStarNetServerConfig::getStarNet7(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch) const +#endif +{ + band = m_starNet7Band; + callsign = m_starNet7Callsign; + logoff = m_starNet7Logoff; + info = m_starNet7Info; + permanent = m_starNet7Permanent; + userTimeout = m_starNet7UserTimeout; + groupTimeout = m_starNet7GroupTimeout; + callsignSwitch = m_starNet7CallsignSwitch; + txMsgSwitch = m_starNet7TxMsgSwitch; + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + reflector = m_starNet7Reflector; +#endif +} + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) +void CStarNetServerConfig::setStarNet7(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch, const wxString& reflector) +#else +void CStarNetServerConfig::setStarNet7(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch) +#endif +{ + m_starNet7Band = band; + m_starNet7Callsign = callsign; + m_starNet7Logoff = logoff; + m_starNet7Info = info; + m_starNet7Permanent = permanent; + m_starNet7UserTimeout = userTimeout; + m_starNet7GroupTimeout = groupTimeout; + m_starNet7CallsignSwitch = callsignSwitch; + m_starNet7TxMsgSwitch = txMsgSwitch; + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + m_starNet7Reflector = reflector; +#endif +} + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) +void CStarNetServerConfig::getStarNet8(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch, wxString& reflector) const +#else +void CStarNetServerConfig::getStarNet8(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch) const +#endif +{ + band = m_starNet8Band; + callsign = m_starNet8Callsign; + logoff = m_starNet8Logoff; + info = m_starNet8Info; + permanent = m_starNet8Permanent; + userTimeout = m_starNet8UserTimeout; + groupTimeout = m_starNet8GroupTimeout; + callsignSwitch = m_starNet8CallsignSwitch; + txMsgSwitch = m_starNet8TxMsgSwitch; + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + reflector = m_starNet8Reflector; +#endif +} + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) +void CStarNetServerConfig::setStarNet8(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch, const wxString& reflector) +#else +void CStarNetServerConfig::setStarNet8(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch) +#endif +{ + m_starNet8Band = band; + m_starNet8Callsign = callsign; + m_starNet8Logoff = logoff; + m_starNet8Info = info; + m_starNet8Permanent = permanent; + m_starNet8UserTimeout = userTimeout; + m_starNet8GroupTimeout = groupTimeout; + m_starNet8CallsignSwitch = callsignSwitch; + m_starNet8TxMsgSwitch = txMsgSwitch; + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + m_starNet8Reflector = reflector; +#endif +} + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) +void CStarNetServerConfig::getStarNet9(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch, wxString& reflector) const +#else +void CStarNetServerConfig::getStarNet9(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch) const +#endif +{ + band = m_starNet9Band; + callsign = m_starNet9Callsign; + logoff = m_starNet9Logoff; + info = m_starNet9Info; + permanent = m_starNet9Permanent; + userTimeout = m_starNet9UserTimeout; + groupTimeout = m_starNet9GroupTimeout; + callsignSwitch = m_starNet9CallsignSwitch; + txMsgSwitch = m_starNet9TxMsgSwitch; + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + reflector = m_starNet9Reflector; +#endif +} + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) +void CStarNetServerConfig::setStarNet9(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch, const wxString& reflector) +#else +void CStarNetServerConfig::setStarNet9(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch) +#endif +{ + m_starNet9Band = band; + m_starNet9Callsign = callsign; + m_starNet9Logoff = logoff; + m_starNet9Info = info; + m_starNet9Permanent = permanent; + m_starNet9UserTimeout = userTimeout; + m_starNet9GroupTimeout = groupTimeout; + m_starNet9CallsignSwitch = callsignSwitch; + m_starNet9TxMsgSwitch = txMsgSwitch; + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + m_starNet9Reflector = reflector; +#endif +} + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) +void CStarNetServerConfig::getStarNet10(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch, wxString& reflector) const +#else +void CStarNetServerConfig::getStarNet10(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch) const +#endif +{ + band = m_starNet10Band; + callsign = m_starNet10Callsign; + logoff = m_starNet10Logoff; + info = m_starNet10Info; + permanent = m_starNet10Permanent; + userTimeout = m_starNet10UserTimeout; + groupTimeout = m_starNet10GroupTimeout; + callsignSwitch = m_starNet10CallsignSwitch; + txMsgSwitch = m_starNet10TxMsgSwitch; + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + reflector = m_starNet10Reflector; +#endif +} + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) +void CStarNetServerConfig::setStarNet10(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch, const wxString& reflector) +#else +void CStarNetServerConfig::setStarNet10(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch) +#endif +{ + m_starNet10Band = band; + m_starNet10Callsign = callsign; + m_starNet10Logoff = logoff; + m_starNet10Info = info; + m_starNet10Permanent = permanent; + m_starNet10UserTimeout = userTimeout; + m_starNet10GroupTimeout = groupTimeout; + m_starNet10CallsignSwitch = callsignSwitch; + m_starNet10TxMsgSwitch = txMsgSwitch; + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + m_starNet10Reflector = reflector; +#endif +} + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) +void CStarNetServerConfig::getStarNet11(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch, wxString& reflector) const +#else +void CStarNetServerConfig::getStarNet11(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch) const +#endif +{ + band = m_starNet11Band; + callsign = m_starNet11Callsign; + logoff = m_starNet11Logoff; + info = m_starNet11Info; + permanent = m_starNet11Permanent; + userTimeout = m_starNet11UserTimeout; + groupTimeout = m_starNet11GroupTimeout; + callsignSwitch = m_starNet11CallsignSwitch; + txMsgSwitch = m_starNet11TxMsgSwitch; + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + reflector = m_starNet11Reflector; +#endif +} + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) +void CStarNetServerConfig::setStarNet11(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch, const wxString& reflector) +#else +void CStarNetServerConfig::setStarNet11(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch) +#endif +{ + m_starNet11Band = band; + m_starNet11Callsign = callsign; + m_starNet11Logoff = logoff; + m_starNet11Info = info; + m_starNet11Permanent = permanent; + m_starNet11UserTimeout = userTimeout; + m_starNet11GroupTimeout = groupTimeout; + m_starNet11CallsignSwitch = callsignSwitch; + m_starNet11TxMsgSwitch = txMsgSwitch; + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + m_starNet11Reflector = reflector; +#endif +} + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) +void CStarNetServerConfig::getStarNet12(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch, wxString& reflector) const +#else +void CStarNetServerConfig::getStarNet12(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch) const +#endif +{ + band = m_starNet12Band; + callsign = m_starNet12Callsign; + logoff = m_starNet12Logoff; + info = m_starNet12Info; + permanent = m_starNet12Permanent; + userTimeout = m_starNet12UserTimeout; + groupTimeout = m_starNet12GroupTimeout; + callsignSwitch = m_starNet12CallsignSwitch; + txMsgSwitch = m_starNet12TxMsgSwitch; + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + reflector = m_starNet12Reflector; +#endif +} + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) +void CStarNetServerConfig::setStarNet12(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch, const wxString& reflector) +#else +void CStarNetServerConfig::setStarNet12(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch) +#endif +{ + m_starNet12Band = band; + m_starNet12Callsign = callsign; + m_starNet12Logoff = logoff; + m_starNet12Info = info; + m_starNet12Permanent = permanent; + m_starNet12UserTimeout = userTimeout; + m_starNet12GroupTimeout = groupTimeout; + m_starNet12CallsignSwitch = callsignSwitch; + m_starNet12TxMsgSwitch = txMsgSwitch; + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + m_starNet12Reflector = reflector; +#endif +} + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) +void CStarNetServerConfig::getStarNet13(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch, wxString& reflector) const +#else +void CStarNetServerConfig::getStarNet13(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch) const +#endif +{ + band = m_starNet13Band; + callsign = m_starNet13Callsign; + logoff = m_starNet13Logoff; + info = m_starNet13Info; + permanent = m_starNet13Permanent; + userTimeout = m_starNet13UserTimeout; + groupTimeout = m_starNet13GroupTimeout; + callsignSwitch = m_starNet13CallsignSwitch; + txMsgSwitch = m_starNet13TxMsgSwitch; + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + reflector = m_starNet13Reflector; +#endif +} + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) +void CStarNetServerConfig::setStarNet13(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch, const wxString& reflector) +#else +void CStarNetServerConfig::setStarNet13(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch) +#endif +{ + m_starNet13Band = band; + m_starNet13Callsign = callsign; + m_starNet13Logoff = logoff; + m_starNet13Info = info; + m_starNet13Permanent = permanent; + m_starNet13UserTimeout = userTimeout; + m_starNet13GroupTimeout = groupTimeout; + m_starNet13CallsignSwitch = callsignSwitch; + m_starNet13TxMsgSwitch = txMsgSwitch; + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + m_starNet13Reflector = reflector; +#endif +} + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) +void CStarNetServerConfig::getStarNet14(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch, wxString& reflector) const +#else +void CStarNetServerConfig::getStarNet14(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch) const +#endif +{ + band = m_starNet14Band; + callsign = m_starNet14Callsign; + logoff = m_starNet14Logoff; + info = m_starNet14Info; + permanent = m_starNet14Permanent; + userTimeout = m_starNet14UserTimeout; + groupTimeout = m_starNet14GroupTimeout; + callsignSwitch = m_starNet14CallsignSwitch; + txMsgSwitch = m_starNet14TxMsgSwitch; + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + reflector = m_starNet14Reflector; +#endif +} + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) +void CStarNetServerConfig::setStarNet14(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch, const wxString& reflector) +#else +void CStarNetServerConfig::setStarNet14(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch) +#endif +{ + m_starNet14Band = band; + m_starNet14Callsign = callsign; + m_starNet14Logoff = logoff; + m_starNet14Info = info; + m_starNet14Permanent = permanent; + m_starNet14UserTimeout = userTimeout; + m_starNet14GroupTimeout = groupTimeout; + m_starNet14CallsignSwitch = callsignSwitch; + m_starNet14TxMsgSwitch = txMsgSwitch; + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + m_starNet14Reflector = reflector; +#endif +} + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) +void CStarNetServerConfig::getStarNet15(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch, wxString& reflector) const +#else +void CStarNetServerConfig::getStarNet15(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch) const +#endif +{ + band = m_starNet15Band; + callsign = m_starNet15Callsign; + logoff = m_starNet15Logoff; + info = m_starNet15Info; + permanent = m_starNet15Permanent; + userTimeout = m_starNet15UserTimeout; + groupTimeout = m_starNet15GroupTimeout; + callsignSwitch = m_starNet15CallsignSwitch; + txMsgSwitch = m_starNet15TxMsgSwitch; + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + reflector = m_starNet15Reflector; +#endif +} + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) +void CStarNetServerConfig::setStarNet15(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch, const wxString& reflector) +#else +void CStarNetServerConfig::setStarNet15(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch) +#endif +{ + m_starNet15Band = band; + m_starNet15Callsign = callsign; + m_starNet15Logoff = logoff; + m_starNet15Info = info; + m_starNet15Permanent = permanent; + m_starNet15UserTimeout = userTimeout; + m_starNet15GroupTimeout = groupTimeout; + m_starNet15CallsignSwitch = callsignSwitch; + m_starNet15TxMsgSwitch = txMsgSwitch; + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + m_starNet15Reflector = reflector; +#endif +} + +void CStarNetServerConfig::getRemote(bool& enabled, wxString& password, unsigned int& port) const +{ + enabled = m_remoteEnabled; + password = m_remotePassword; + port = m_remotePort; +} + +void CStarNetServerConfig::setRemote(bool enabled, const wxString& password, unsigned int port) +{ + m_remoteEnabled = enabled; + m_remotePassword = password; + m_remotePort = port; +} + +void CStarNetServerConfig::getMiscellaneous(bool& enabled) const +{ + enabled = m_logEnabled; +} + +void CStarNetServerConfig::setMiscellaneous(bool enabled) +{ + m_logEnabled = enabled; +} + +void CStarNetServerConfig::getPosition(int& x, int& y) const +{ + x = m_x; + y = m_y; +} + +void CStarNetServerConfig::setPosition(int x, int y) +{ + m_x = x; + m_y = y; +} + +bool CStarNetServerConfig::write() +{ +#if defined(__WINDOWS__) + m_config->Write(wxT("/") + KEY_CALLSIGN, m_callsign); + m_config->Write(wxT("/") + KEY_ADDRESS, m_address); + m_config->Write(wxT("/") + KEY_IRCDDB_HOSTNAME, m_ircddbHostname); + m_config->Write(wxT("/") + KEY_IRCDDB_USERNAME, m_ircddbUsername); + m_config->Write(wxT("/") + KEY_IRCDDB_PASSWORD, m_ircddbPassword); + m_config->Write(wxT("/") + KEY_STARNET_BAND1, m_starNet1Band); + m_config->Write(wxT("/") + KEY_STARNET_CALLSIGN1, m_starNet1Callsign); + m_config->Write(wxT("/") + KEY_STARNET_LOGOFF1, m_starNet1Logoff); + m_config->Write(wxT("/") + KEY_STARNET_INFO1, m_starNet1Info); + m_config->Write(wxT("/") + KEY_STARNET_PERMANENT1, m_starNet1Permanent); + m_config->Write(wxT("/") + KEY_STARNET_USER_TIMEOUT1, long(m_starNet1UserTimeout)); + m_config->Write(wxT("/") + KEY_STARNET_GROUP_TIMEOUT1, long(m_starNet1GroupTimeout)); + m_config->Write(wxT("/") + KEY_STARNET_CALLSIGN_SWITCH1, long(m_starNet1CallsignSwitch)); + m_config->Write(wxT("/") + KEY_STARNET_TXMSG_SWITCH1, m_starNet1TxMsgSwitch); + m_config->Write(wxT("/") + KEY_STARNET_REFLECTOR1, m_starNet1Reflector); + m_config->Write(wxT("/") + KEY_STARNET_BAND2, m_starNet2Band); + m_config->Write(wxT("/") + KEY_STARNET_CALLSIGN2, m_starNet2Callsign); + m_config->Write(wxT("/") + KEY_STARNET_LOGOFF2, m_starNet2Logoff); + m_config->Write(wxT("/") + KEY_STARNET_INFO2, m_starNet2Info); + m_config->Write(wxT("/") + KEY_STARNET_PERMANENT2, m_starNet2Permanent); + m_config->Write(wxT("/") + KEY_STARNET_USER_TIMEOUT2, long(m_starNet2UserTimeout)); + m_config->Write(wxT("/") + KEY_STARNET_GROUP_TIMEOUT2, long(m_starNet2GroupTimeout)); + m_config->Write(wxT("/") + KEY_STARNET_CALLSIGN_SWITCH2, long(m_starNet2CallsignSwitch)); + m_config->Write(wxT("/") + KEY_STARNET_TXMSG_SWITCH2, m_starNet2TxMsgSwitch); + m_config->Write(wxT("/") + KEY_STARNET_REFLECTOR2, m_starNet2Reflector); + m_config->Write(wxT("/") + KEY_STARNET_BAND3, m_starNet3Band); + m_config->Write(wxT("/") + KEY_STARNET_CALLSIGN3, m_starNet3Callsign); + m_config->Write(wxT("/") + KEY_STARNET_LOGOFF3, m_starNet3Logoff); + m_config->Write(wxT("/") + KEY_STARNET_INFO3, m_starNet3Info); + m_config->Write(wxT("/") + KEY_STARNET_PERMANENT3, m_starNet3Permanent); + m_config->Write(wxT("/") + KEY_STARNET_USER_TIMEOUT3, long(m_starNet3UserTimeout)); + m_config->Write(wxT("/") + KEY_STARNET_GROUP_TIMEOUT3, long(m_starNet3GroupTimeout)); + m_config->Write(wxT("/") + KEY_STARNET_CALLSIGN_SWITCH3, long(m_starNet3CallsignSwitch)); + m_config->Write(wxT("/") + KEY_STARNET_TXMSG_SWITCH3, m_starNet3TxMsgSwitch); + m_config->Write(wxT("/") + KEY_STARNET_REFLECTOR3, m_starNet3Reflector); + m_config->Write(wxT("/") + KEY_STARNET_BAND4, m_starNet4Band); + m_config->Write(wxT("/") + KEY_STARNET_CALLSIGN4, m_starNet4Callsign); + m_config->Write(wxT("/") + KEY_STARNET_LOGOFF4, m_starNet4Logoff); + m_config->Write(wxT("/") + KEY_STARNET_INFO4, m_starNet4Info); + m_config->Write(wxT("/") + KEY_STARNET_PERMANENT4, m_starNet4Permanent); + m_config->Write(wxT("/") + KEY_STARNET_USER_TIMEOUT4, long(m_starNet4UserTimeout)); + m_config->Write(wxT("/") + KEY_STARNET_GROUP_TIMEOUT4, long(m_starNet4GroupTimeout)); + m_config->Write(wxT("/") + KEY_STARNET_CALLSIGN_SWITCH4, long(m_starNet4CallsignSwitch)); + m_config->Write(wxT("/") + KEY_STARNET_TXMSG_SWITCH4, m_starNet4TxMsgSwitch); + m_config->Write(wxT("/") + KEY_STARNET_REFLECTOR4, m_starNet4Reflector); + m_config->Write(wxT("/") + KEY_STARNET_BAND5, m_starNet5Band); + m_config->Write(wxT("/") + KEY_STARNET_CALLSIGN5, m_starNet5Callsign); + m_config->Write(wxT("/") + KEY_STARNET_LOGOFF5, m_starNet5Logoff); + m_config->Write(wxT("/") + KEY_STARNET_INFO5, m_starNet5Info); + m_config->Write(wxT("/") + KEY_STARNET_PERMANENT5, m_starNet5Permanent); + m_config->Write(wxT("/") + KEY_STARNET_USER_TIMEOUT5, long(m_starNet5UserTimeout)); + m_config->Write(wxT("/") + KEY_STARNET_GROUP_TIMEOUT5, long(m_starNet5GroupTimeout)); + m_config->Write(wxT("/") + KEY_STARNET_CALLSIGN_SWITCH5, long(m_starNet5CallsignSwitch)); + m_config->Write(wxT("/") + KEY_STARNET_TXMSG_SWITCH5, m_starNet5TxMsgSwitch); + m_config->Write(wxT("/") + KEY_STARNET_REFLECTOR5, m_starNet5Reflector); + m_config->Write(wxT("/") + KEY_STARNET_BAND6, m_starNet6Band); + m_config->Write(wxT("/") + KEY_STARNET_CALLSIGN6, m_starNet6Callsign); + m_config->Write(wxT("/") + KEY_STARNET_LOGOFF6, m_starNet6Logoff); + m_config->Write(wxT("/") + KEY_STARNET_INFO6, m_starNet6Info); + m_config->Write(wxT("/") + KEY_STARNET_PERMANENT6, m_starNet6Permanent); + m_config->Write(wxT("/") + KEY_STARNET_USER_TIMEOUT6, long(m_starNet6UserTimeout)); + m_config->Write(wxT("/") + KEY_STARNET_GROUP_TIMEOUT6, long(m_starNet6GroupTimeout)); + m_config->Write(wxT("/") + KEY_STARNET_CALLSIGN_SWITCH6, long(m_starNet6CallsignSwitch)); + m_config->Write(wxT("/") + KEY_STARNET_TXMSG_SWITCH6, m_starNet6TxMsgSwitch); + m_config->Write(wxT("/") + KEY_STARNET_REFLECTOR6, m_starNet6Reflector); + m_config->Write(wxT("/") + KEY_STARNET_BAND7, m_starNet7Band); + m_config->Write(wxT("/") + KEY_STARNET_CALLSIGN7, m_starNet7Callsign); + m_config->Write(wxT("/") + KEY_STARNET_LOGOFF7, m_starNet7Logoff); + m_config->Write(wxT("/") + KEY_STARNET_INFO7, m_starNet7Info); + m_config->Write(wxT("/") + KEY_STARNET_PERMANENT7, m_starNet7Permanent); + m_config->Write(wxT("/") + KEY_STARNET_USER_TIMEOUT7, long(m_starNet7UserTimeout)); + m_config->Write(wxT("/") + KEY_STARNET_GROUP_TIMEOUT7, long(m_starNet7GroupTimeout)); + m_config->Write(wxT("/") + KEY_STARNET_CALLSIGN_SWITCH7, long(m_starNet7CallsignSwitch)); + m_config->Write(wxT("/") + KEY_STARNET_TXMSG_SWITCH7, m_starNet7TxMsgSwitch); + m_config->Write(wxT("/") + KEY_STARNET_REFLECTOR7, m_starNet7Reflector); + m_config->Write(wxT("/") + KEY_STARNET_BAND8, m_starNet8Band); + m_config->Write(wxT("/") + KEY_STARNET_CALLSIGN8, m_starNet8Callsign); + m_config->Write(wxT("/") + KEY_STARNET_LOGOFF8, m_starNet8Logoff); + m_config->Write(wxT("/") + KEY_STARNET_INFO8, m_starNet8Info); + m_config->Write(wxT("/") + KEY_STARNET_PERMANENT8, m_starNet8Permanent); + m_config->Write(wxT("/") + KEY_STARNET_USER_TIMEOUT8, long(m_starNet8UserTimeout)); + m_config->Write(wxT("/") + KEY_STARNET_GROUP_TIMEOUT8, long(m_starNet8GroupTimeout)); + m_config->Write(wxT("/") + KEY_STARNET_CALLSIGN_SWITCH8, long(m_starNet8CallsignSwitch)); + m_config->Write(wxT("/") + KEY_STARNET_TXMSG_SWITCH8, m_starNet8TxMsgSwitch); + m_config->Write(wxT("/") + KEY_STARNET_REFLECTOR8, m_starNet8Reflector); + m_config->Write(wxT("/") + KEY_STARNET_BAND9, m_starNet9Band); + m_config->Write(wxT("/") + KEY_STARNET_CALLSIGN9, m_starNet9Callsign); + m_config->Write(wxT("/") + KEY_STARNET_LOGOFF9, m_starNet9Logoff); + m_config->Write(wxT("/") + KEY_STARNET_INFO9, m_starNet9Info); + m_config->Write(wxT("/") + KEY_STARNET_PERMANENT9, m_starNet9Permanent); + m_config->Write(wxT("/") + KEY_STARNET_USER_TIMEOUT9, long(m_starNet9UserTimeout)); + m_config->Write(wxT("/") + KEY_STARNET_GROUP_TIMEOUT9, long(m_starNet9GroupTimeout)); + m_config->Write(wxT("/") + KEY_STARNET_CALLSIGN_SWITCH9, long(m_starNet9CallsignSwitch)); + m_config->Write(wxT("/") + KEY_STARNET_TXMSG_SWITCH9, m_starNet9TxMsgSwitch); + m_config->Write(wxT("/") + KEY_STARNET_REFLECTOR9, m_starNet9Reflector); + m_config->Write(wxT("/") + KEY_STARNET_BAND10, m_starNet10Band); + m_config->Write(wxT("/") + KEY_STARNET_CALLSIGN10, m_starNet10Callsign); + m_config->Write(wxT("/") + KEY_STARNET_LOGOFF10, m_starNet10Logoff); + m_config->Write(wxT("/") + KEY_STARNET_INFO10, m_starNet10Info); + m_config->Write(wxT("/") + KEY_STARNET_PERMANENT10, m_starNet10Permanent); + m_config->Write(wxT("/") + KEY_STARNET_USER_TIMEOUT10, long(m_starNet10UserTimeout)); + m_config->Write(wxT("/") + KEY_STARNET_GROUP_TIMEOUT10, long(m_starNet10GroupTimeout)); + m_config->Write(wxT("/") + KEY_STARNET_CALLSIGN_SWITCH10, long(m_starNet10CallsignSwitch)); + m_config->Write(wxT("/") + KEY_STARNET_TXMSG_SWITCH10, m_starNet10TxMsgSwitch); + m_config->Write(wxT("/") + KEY_STARNET_REFLECTOR10, m_starNet10Reflector); + m_config->Write(wxT("/") + KEY_STARNET_BAND11, m_starNet11Band); + m_config->Write(wxT("/") + KEY_STARNET_CALLSIGN11, m_starNet11Callsign); + m_config->Write(wxT("/") + KEY_STARNET_LOGOFF11, m_starNet11Logoff); + m_config->Write(wxT("/") + KEY_STARNET_INFO11, m_starNet11Info); + m_config->Write(wxT("/") + KEY_STARNET_PERMANENT11, m_starNet11Permanent); + m_config->Write(wxT("/") + KEY_STARNET_USER_TIMEOUT11, long(m_starNet11UserTimeout)); + m_config->Write(wxT("/") + KEY_STARNET_GROUP_TIMEOUT11, long(m_starNet11GroupTimeout)); + m_config->Write(wxT("/") + KEY_STARNET_CALLSIGN_SWITCH11, long(m_starNet11CallsignSwitch)); + m_config->Write(wxT("/") + KEY_STARNET_TXMSG_SWITCH11, m_starNet11TxMsgSwitch); + m_config->Write(wxT("/") + KEY_STARNET_REFLECTOR11, m_starNet11Reflector); + m_config->Write(wxT("/") + KEY_STARNET_BAND12, m_starNet12Band); + m_config->Write(wxT("/") + KEY_STARNET_CALLSIGN12, m_starNet12Callsign); + m_config->Write(wxT("/") + KEY_STARNET_LOGOFF12, m_starNet12Logoff); + m_config->Write(wxT("/") + KEY_STARNET_INFO12, m_starNet12Info); + m_config->Write(wxT("/") + KEY_STARNET_PERMANENT12, m_starNet12Permanent); + m_config->Write(wxT("/") + KEY_STARNET_USER_TIMEOUT12, long(m_starNet12UserTimeout)); + m_config->Write(wxT("/") + KEY_STARNET_GROUP_TIMEOUT12, long(m_starNet12GroupTimeout)); + m_config->Write(wxT("/") + KEY_STARNET_CALLSIGN_SWITCH12, long(m_starNet12CallsignSwitch)); + m_config->Write(wxT("/") + KEY_STARNET_TXMSG_SWITCH12, m_starNet12TxMsgSwitch); + m_config->Write(wxT("/") + KEY_STARNET_REFLECTOR12, m_starNet12Reflector); + m_config->Write(wxT("/") + KEY_STARNET_BAND13, m_starNet13Band); + m_config->Write(wxT("/") + KEY_STARNET_CALLSIGN13, m_starNet13Callsign); + m_config->Write(wxT("/") + KEY_STARNET_LOGOFF13, m_starNet13Logoff); + m_config->Write(wxT("/") + KEY_STARNET_INFO13, m_starNet13Info); + m_config->Write(wxT("/") + KEY_STARNET_PERMANENT13, m_starNet13Permanent); + m_config->Write(wxT("/") + KEY_STARNET_USER_TIMEOUT13, long(m_starNet13UserTimeout)); + m_config->Write(wxT("/") + KEY_STARNET_GROUP_TIMEOUT13, long(m_starNet13GroupTimeout)); + m_config->Write(wxT("/") + KEY_STARNET_CALLSIGN_SWITCH13, long(m_starNet13CallsignSwitch)); + m_config->Write(wxT("/") + KEY_STARNET_TXMSG_SWITCH13, m_starNet13TxMsgSwitch); + m_config->Write(wxT("/") + KEY_STARNET_REFLECTOR13, m_starNet13Reflector); + m_config->Write(wxT("/") + KEY_STARNET_BAND14, m_starNet14Band); + m_config->Write(wxT("/") + KEY_STARNET_CALLSIGN14, m_starNet14Callsign); + m_config->Write(wxT("/") + KEY_STARNET_LOGOFF14, m_starNet14Logoff); + m_config->Write(wxT("/") + KEY_STARNET_INFO14, m_starNet14Info); + m_config->Write(wxT("/") + KEY_STARNET_PERMANENT14, m_starNet14Permanent); + m_config->Write(wxT("/") + KEY_STARNET_USER_TIMEOUT14, long(m_starNet14UserTimeout)); + m_config->Write(wxT("/") + KEY_STARNET_GROUP_TIMEOUT14, long(m_starNet14GroupTimeout)); + m_config->Write(wxT("/") + KEY_STARNET_CALLSIGN_SWITCH14, long(m_starNet14CallsignSwitch)); + m_config->Write(wxT("/") + KEY_STARNET_TXMSG_SWITCH14, m_starNet14TxMsgSwitch); + m_config->Write(wxT("/") + KEY_STARNET_REFLECTOR14, m_starNet14Reflector); + m_config->Write(wxT("/") + KEY_STARNET_BAND15, m_starNet15Band); + m_config->Write(wxT("/") + KEY_STARNET_CALLSIGN15, m_starNet15Callsign); + m_config->Write(wxT("/") + KEY_STARNET_LOGOFF15, m_starNet15Logoff); + m_config->Write(wxT("/") + KEY_STARNET_INFO15, m_starNet15Info); + m_config->Write(wxT("/") + KEY_STARNET_PERMANENT15, m_starNet15Permanent); + m_config->Write(wxT("/") + KEY_STARNET_USER_TIMEOUT15, long(m_starNet15UserTimeout)); + m_config->Write(wxT("/") + KEY_STARNET_GROUP_TIMEOUT15, long(m_starNet15GroupTimeout)); + m_config->Write(wxT("/") + KEY_STARNET_CALLSIGN_SWITCH15, long(m_starNet15CallsignSwitch)); + m_config->Write(wxT("/") + KEY_STARNET_TXMSG_SWITCH15, m_starNet15TxMsgSwitch); + m_config->Write(wxT("/") + KEY_STARNET_REFLECTOR15, m_starNet15Reflector); + m_config->Write(wxT("/") + KEY_REMOTE_ENABLED, m_remoteEnabled); + m_config->Write(wxT("/") + KEY_REMOTE_PASSWORD, m_remotePassword); + m_config->Write(wxT("/") + KEY_REMOTE_PORT, long(m_remotePort)); + m_config->Write(wxT("/") + KEY_LOG_ENABLED, m_logEnabled); + m_config->Write(wxT("/") + KEY_WINDOW_X, long(m_x)); + m_config->Write(wxT("/") + KEY_WINDOW_Y, long(m_y)); + m_config->Flush(); +#endif + + wxTextFile file(m_fileName.GetFullPath()); + + bool exists = file.Exists(); + if (exists) { + bool ret = file.Open(); + if (!ret) { + wxLogError(wxT("Cannot open the config file - %s"), m_fileName.GetFullPath().c_str()); + return false; + } + + // Remove the existing file entries + file.Clear(); + } else { + bool ret = file.Create(); + if (!ret) { + wxLogError(wxT("Cannot create the config file - %s"), m_fileName.GetFullPath().c_str()); + return false; + } + } + + wxString buffer; + buffer.Printf(wxT("%s=%s"), KEY_CALLSIGN.c_str(), m_callsign.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_ADDRESS.c_str(), m_address.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_IRCDDB_HOSTNAME.c_str(), m_ircddbHostname.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_IRCDDB_USERNAME.c_str(), m_ircddbUsername.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_IRCDDB_PASSWORD.c_str(), m_ircddbPassword.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_BAND1.c_str(), m_starNet1Band.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_CALLSIGN1.c_str(), m_starNet1Callsign.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_LOGOFF1.c_str(), m_starNet1Logoff.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_INFO1.c_str(), m_starNet1Info.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_PERMANENT1.c_str(), m_starNet1Permanent.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%u"), KEY_STARNET_USER_TIMEOUT1.c_str(), m_starNet1UserTimeout); file.AddLine(buffer); + buffer.Printf(wxT("%s=%u"), KEY_STARNET_GROUP_TIMEOUT1.c_str(), m_starNet1GroupTimeout); file.AddLine(buffer); + buffer.Printf(wxT("%s=%d"), KEY_STARNET_CALLSIGN_SWITCH1.c_str(), int(m_starNet1CallsignSwitch)); file.AddLine(buffer); + buffer.Printf(wxT("%s=%d"), KEY_STARNET_TXMSG_SWITCH1.c_str(), m_starNet1TxMsgSwitch ? 1 : 0); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_REFLECTOR1.c_str(), m_starNet1Reflector.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_BAND2.c_str(), m_starNet2Band.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_CALLSIGN2.c_str(), m_starNet2Callsign.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_LOGOFF2.c_str(), m_starNet2Logoff.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_INFO2.c_str(), m_starNet2Info.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_PERMANENT2.c_str(), m_starNet2Permanent.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%u"), KEY_STARNET_USER_TIMEOUT2.c_str(), m_starNet2UserTimeout); file.AddLine(buffer); + buffer.Printf(wxT("%s=%u"), KEY_STARNET_GROUP_TIMEOUT2.c_str(), m_starNet2GroupTimeout); file.AddLine(buffer); + buffer.Printf(wxT("%s=%d"), KEY_STARNET_CALLSIGN_SWITCH2.c_str(), int(m_starNet2CallsignSwitch)); file.AddLine(buffer); + buffer.Printf(wxT("%s=%d"), KEY_STARNET_TXMSG_SWITCH2.c_str(), m_starNet2TxMsgSwitch ? 1 : 0); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_REFLECTOR2.c_str(), m_starNet2Reflector.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_BAND3.c_str(), m_starNet3Band.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_CALLSIGN3.c_str(), m_starNet3Callsign.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_LOGOFF3.c_str(), m_starNet3Logoff.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_INFO3.c_str(), m_starNet3Info.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_PERMANENT3.c_str(), m_starNet3Permanent.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%u"), KEY_STARNET_USER_TIMEOUT3.c_str(), m_starNet3UserTimeout); file.AddLine(buffer); + buffer.Printf(wxT("%s=%u"), KEY_STARNET_GROUP_TIMEOUT3.c_str(), m_starNet3GroupTimeout); file.AddLine(buffer); + buffer.Printf(wxT("%s=%d"), KEY_STARNET_CALLSIGN_SWITCH3.c_str(), int(m_starNet3CallsignSwitch)); file.AddLine(buffer); + buffer.Printf(wxT("%s=%d"), KEY_STARNET_TXMSG_SWITCH3.c_str(), m_starNet3TxMsgSwitch ? 1 : 0); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_REFLECTOR3.c_str(), m_starNet3Reflector.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_BAND4.c_str(), m_starNet4Band.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_CALLSIGN4.c_str(), m_starNet4Callsign.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_LOGOFF4.c_str(), m_starNet4Logoff.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_INFO4.c_str(), m_starNet4Info.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_PERMANENT4.c_str(), m_starNet4Permanent.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%u"), KEY_STARNET_USER_TIMEOUT4.c_str(), m_starNet4UserTimeout); file.AddLine(buffer); + buffer.Printf(wxT("%s=%u"), KEY_STARNET_GROUP_TIMEOUT4.c_str(), m_starNet4GroupTimeout); file.AddLine(buffer); + buffer.Printf(wxT("%s=%d"), KEY_STARNET_CALLSIGN_SWITCH4.c_str(), int(m_starNet4CallsignSwitch)); file.AddLine(buffer); + buffer.Printf(wxT("%s=%d"), KEY_STARNET_TXMSG_SWITCH4.c_str(), m_starNet4TxMsgSwitch ? 1 : 0); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_REFLECTOR4.c_str(), m_starNet4Reflector.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_BAND5.c_str(), m_starNet5Band.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_CALLSIGN5.c_str(), m_starNet5Callsign.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_LOGOFF5.c_str(), m_starNet5Logoff.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_INFO5.c_str(), m_starNet5Info.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_PERMANENT5.c_str(), m_starNet5Permanent.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%u"), KEY_STARNET_USER_TIMEOUT5.c_str(), m_starNet5UserTimeout); file.AddLine(buffer); + buffer.Printf(wxT("%s=%u"), KEY_STARNET_GROUP_TIMEOUT5.c_str(), m_starNet5GroupTimeout); file.AddLine(buffer); + buffer.Printf(wxT("%s=%d"), KEY_STARNET_CALLSIGN_SWITCH5.c_str(), int(m_starNet5CallsignSwitch)); file.AddLine(buffer); + buffer.Printf(wxT("%s=%d"), KEY_STARNET_TXMSG_SWITCH5.c_str(), m_starNet5TxMsgSwitch ? 1 : 0); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_REFLECTOR5.c_str(), m_starNet5Reflector.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_BAND6.c_str(), m_starNet6Band.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_CALLSIGN6.c_str(), m_starNet6Callsign.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_LOGOFF6.c_str(), m_starNet6Logoff.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_INFO6.c_str(), m_starNet6Info.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_PERMANENT6.c_str(), m_starNet6Permanent.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%u"), KEY_STARNET_USER_TIMEOUT6.c_str(), m_starNet6UserTimeout); file.AddLine(buffer); + buffer.Printf(wxT("%s=%u"), KEY_STARNET_GROUP_TIMEOUT6.c_str(), m_starNet6GroupTimeout); file.AddLine(buffer); + buffer.Printf(wxT("%s=%d"), KEY_STARNET_CALLSIGN_SWITCH6.c_str(), int(m_starNet6CallsignSwitch)); file.AddLine(buffer); + buffer.Printf(wxT("%s=%d"), KEY_STARNET_TXMSG_SWITCH6.c_str(), m_starNet6TxMsgSwitch ? 1 : 0); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_REFLECTOR6.c_str(), m_starNet6Reflector.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_BAND7.c_str(), m_starNet7Band.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_CALLSIGN7.c_str(), m_starNet7Callsign.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_LOGOFF7.c_str(), m_starNet7Logoff.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_INFO7.c_str(), m_starNet7Info.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_PERMANENT7.c_str(), m_starNet7Permanent.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%u"), KEY_STARNET_USER_TIMEOUT7.c_str(), m_starNet7UserTimeout); file.AddLine(buffer); + buffer.Printf(wxT("%s=%u"), KEY_STARNET_GROUP_TIMEOUT7.c_str(), m_starNet7GroupTimeout); file.AddLine(buffer); + buffer.Printf(wxT("%s=%d"), KEY_STARNET_CALLSIGN_SWITCH7.c_str(), int(m_starNet7CallsignSwitch)); file.AddLine(buffer); + buffer.Printf(wxT("%s=%d"), KEY_STARNET_TXMSG_SWITCH7.c_str(), m_starNet7TxMsgSwitch ? 1 : 0); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_REFLECTOR7.c_str(), m_starNet7Reflector.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_BAND8.c_str(), m_starNet8Band.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_CALLSIGN8.c_str(), m_starNet8Callsign.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_LOGOFF8.c_str(), m_starNet8Logoff.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_INFO8.c_str(), m_starNet8Info.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_PERMANENT8.c_str(), m_starNet8Permanent.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%u"), KEY_STARNET_USER_TIMEOUT8.c_str(), m_starNet8UserTimeout); file.AddLine(buffer); + buffer.Printf(wxT("%s=%u"), KEY_STARNET_GROUP_TIMEOUT8.c_str(), m_starNet8GroupTimeout); file.AddLine(buffer); + buffer.Printf(wxT("%s=%d"), KEY_STARNET_CALLSIGN_SWITCH8.c_str(), int(m_starNet8CallsignSwitch)); file.AddLine(buffer); + buffer.Printf(wxT("%s=%d"), KEY_STARNET_TXMSG_SWITCH8.c_str(), m_starNet8TxMsgSwitch ? 1 : 0); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_REFLECTOR8.c_str(), m_starNet8Reflector.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_BAND9.c_str(), m_starNet9Band.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_CALLSIGN9.c_str(), m_starNet9Callsign.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_LOGOFF9.c_str(), m_starNet9Logoff.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_INFO9.c_str(), m_starNet9Info.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_PERMANENT9.c_str(), m_starNet9Permanent.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%u"), KEY_STARNET_USER_TIMEOUT9.c_str(), m_starNet9UserTimeout); file.AddLine(buffer); + buffer.Printf(wxT("%s=%u"), KEY_STARNET_GROUP_TIMEOUT9.c_str(), m_starNet9GroupTimeout); file.AddLine(buffer); + buffer.Printf(wxT("%s=%d"), KEY_STARNET_CALLSIGN_SWITCH9.c_str(), int(m_starNet9CallsignSwitch)); file.AddLine(buffer); + buffer.Printf(wxT("%s=%d"), KEY_STARNET_TXMSG_SWITCH9.c_str(), m_starNet9TxMsgSwitch ? 1 : 0); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_REFLECTOR9.c_str(), m_starNet9Reflector.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_BAND10.c_str(), m_starNet10Band.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_CALLSIGN10.c_str(), m_starNet10Callsign.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_LOGOFF10.c_str(), m_starNet10Logoff.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_INFO10.c_str(), m_starNet10Info.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_PERMANENT10.c_str(), m_starNet10Permanent.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%u"), KEY_STARNET_USER_TIMEOUT10.c_str(), m_starNet10UserTimeout); file.AddLine(buffer); + buffer.Printf(wxT("%s=%u"), KEY_STARNET_GROUP_TIMEOUT10.c_str(), m_starNet10GroupTimeout); file.AddLine(buffer); + buffer.Printf(wxT("%s=%d"), KEY_STARNET_CALLSIGN_SWITCH10.c_str(), int(m_starNet10CallsignSwitch)); file.AddLine(buffer); + buffer.Printf(wxT("%s=%d"), KEY_STARNET_TXMSG_SWITCH10.c_str(), m_starNet10TxMsgSwitch ? 1 : 0); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_REFLECTOR10.c_str(), m_starNet10Reflector.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_BAND11.c_str(), m_starNet11Band.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_CALLSIGN11.c_str(), m_starNet11Callsign.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_LOGOFF11.c_str(), m_starNet11Logoff.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_INFO11.c_str(), m_starNet11Info.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_PERMANENT11.c_str(), m_starNet11Permanent.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%u"), KEY_STARNET_USER_TIMEOUT11.c_str(), m_starNet11UserTimeout); file.AddLine(buffer); + buffer.Printf(wxT("%s=%u"), KEY_STARNET_GROUP_TIMEOUT11.c_str(), m_starNet11GroupTimeout); file.AddLine(buffer); + buffer.Printf(wxT("%s=%d"), KEY_STARNET_CALLSIGN_SWITCH11.c_str(), int(m_starNet11CallsignSwitch)); file.AddLine(buffer); + buffer.Printf(wxT("%s=%d"), KEY_STARNET_TXMSG_SWITCH11.c_str(), m_starNet11TxMsgSwitch ? 1 : 0); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_REFLECTOR11.c_str(), m_starNet11Reflector.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_BAND12.c_str(), m_starNet12Band.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_CALLSIGN12.c_str(), m_starNet12Callsign.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_LOGOFF12.c_str(), m_starNet12Logoff.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_INFO12.c_str(), m_starNet12Info.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_PERMANENT12.c_str(), m_starNet12Permanent.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%u"), KEY_STARNET_USER_TIMEOUT12.c_str(), m_starNet12UserTimeout); file.AddLine(buffer); + buffer.Printf(wxT("%s=%u"), KEY_STARNET_GROUP_TIMEOUT12.c_str(), m_starNet12GroupTimeout); file.AddLine(buffer); + buffer.Printf(wxT("%s=%d"), KEY_STARNET_CALLSIGN_SWITCH12.c_str(), int(m_starNet12CallsignSwitch)); file.AddLine(buffer); + buffer.Printf(wxT("%s=%d"), KEY_STARNET_TXMSG_SWITCH12.c_str(), m_starNet12TxMsgSwitch ? 1 : 0); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_REFLECTOR12.c_str(), m_starNet12Reflector.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_BAND13.c_str(), m_starNet13Band.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_CALLSIGN13.c_str(), m_starNet13Callsign.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_LOGOFF13.c_str(), m_starNet13Logoff.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_INFO13.c_str(), m_starNet13Info.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_PERMANENT13.c_str(), m_starNet13Permanent.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%u"), KEY_STARNET_USER_TIMEOUT13.c_str(), m_starNet13UserTimeout); file.AddLine(buffer); + buffer.Printf(wxT("%s=%u"), KEY_STARNET_GROUP_TIMEOUT13.c_str(), m_starNet13GroupTimeout); file.AddLine(buffer); + buffer.Printf(wxT("%s=%d"), KEY_STARNET_CALLSIGN_SWITCH13.c_str(), int(m_starNet13CallsignSwitch)); file.AddLine(buffer); + buffer.Printf(wxT("%s=%d"), KEY_STARNET_TXMSG_SWITCH13.c_str(), m_starNet13TxMsgSwitch ? 1 : 0); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_REFLECTOR13.c_str(), m_starNet13Reflector.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_BAND14.c_str(), m_starNet14Band.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_CALLSIGN14.c_str(), m_starNet14Callsign.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_LOGOFF14.c_str(), m_starNet14Logoff.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_INFO14.c_str(), m_starNet14Info.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_PERMANENT14.c_str(), m_starNet14Permanent.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%u"), KEY_STARNET_USER_TIMEOUT14.c_str(), m_starNet14UserTimeout); file.AddLine(buffer); + buffer.Printf(wxT("%s=%u"), KEY_STARNET_GROUP_TIMEOUT14.c_str(), m_starNet14GroupTimeout); file.AddLine(buffer); + buffer.Printf(wxT("%s=%d"), KEY_STARNET_CALLSIGN_SWITCH14.c_str(), int(m_starNet14CallsignSwitch)); file.AddLine(buffer); + buffer.Printf(wxT("%s=%d"), KEY_STARNET_TXMSG_SWITCH14.c_str(), m_starNet14TxMsgSwitch ? 1 : 0); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_REFLECTOR14.c_str(), m_starNet14Reflector.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_BAND15.c_str(), m_starNet15Band.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_CALLSIGN15.c_str(), m_starNet15Callsign.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_LOGOFF15.c_str(), m_starNet15Logoff.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_INFO15.c_str(), m_starNet15Info.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_PERMANENT15.c_str(), m_starNet15Permanent.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%u"), KEY_STARNET_USER_TIMEOUT15.c_str(), m_starNet15UserTimeout); file.AddLine(buffer); + buffer.Printf(wxT("%s=%u"), KEY_STARNET_GROUP_TIMEOUT15.c_str(), m_starNet15GroupTimeout); file.AddLine(buffer); + buffer.Printf(wxT("%s=%d"), KEY_STARNET_CALLSIGN_SWITCH15.c_str(), int(m_starNet15CallsignSwitch)); file.AddLine(buffer); + buffer.Printf(wxT("%s=%d"), KEY_STARNET_TXMSG_SWITCH15.c_str(), m_starNet15TxMsgSwitch ? 1 : 0); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_STARNET_REFLECTOR15.c_str(), m_starNet15Reflector.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%d"), KEY_REMOTE_ENABLED.c_str(), m_remoteEnabled ? 1 : 0); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_REMOTE_PASSWORD.c_str(), m_remotePassword.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%u"), KEY_REMOTE_PORT.c_str(), m_remotePort); file.AddLine(buffer); + buffer.Printf(wxT("%s=%d"), KEY_LOG_ENABLED.c_str(), m_logEnabled ? 1 : 0); file.AddLine(buffer); + buffer.Printf(wxT("%s=%d"), KEY_WINDOW_X.c_str(), m_x); file.AddLine(buffer); + buffer.Printf(wxT("%s=%d"), KEY_WINDOW_Y.c_str(), m_y); file.AddLine(buffer); + + bool ret = file.Write(); + if (!ret) { + file.Close(); + wxLogError(wxT("Cannot write the config file - %s"), m_fileName.GetFullPath().c_str()); + return false; + } + + file.Close(); + + return true; +} diff --git a/StarNetServer/StarNetServerConfig.h b/StarNetServer/StarNetServerConfig.h new file mode 100644 index 0000000..cf6f2a0 --- /dev/null +++ b/StarNetServer/StarNetServerConfig.h @@ -0,0 +1,314 @@ +/* + * Copyright (C) 2010,2011,2012,2014 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef StarNetServerConfig_H +#define StarNetServerConfig_H + +#include "Defs.h" + +#include +#include +#include + +class CStarNetServerConfig { +public: +#if defined(__WINDOWS__) + CStarNetServerConfig(wxConfigBase* config, const wxString& dir); +#else + CStarNetServerConfig(const wxString& dir); +#endif + ~CStarNetServerConfig(); + + void getGateway(wxString& callsign, wxString& address) const; + void setGateway(const wxString& callsign, const wxString& address); + + void getIrcDDB(wxString& hostname, wxString& username, wxString& password) const; + void setIrcDDB(const wxString& hostname, const wxString& username, const wxString& password); + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + void getStarNet1(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch, wxString& reflector) const; + void setStarNet1(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch, const wxString& reflector); + + void getStarNet2(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch, wxString& reflector) const; + void setStarNet2(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch, const wxString& reflector); + + void getStarNet3(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch, wxString& reflector) const; + void setStarNet3(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch, const wxString& reflector); + + void getStarNet4(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch, wxString& reflector) const; + void setStarNet4(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch, const wxString& reflector); + + void getStarNet5(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch, wxString& reflector) const; + void setStarNet5(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch, const wxString& reflector); + + void getStarNet6(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch, wxString& reflector) const; + void setStarNet6(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch, const wxString& reflector); + + void getStarNet7(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch, wxString& reflector) const; + void setStarNet7(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch, const wxString& reflector); + + void getStarNet8(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch, wxString& reflector) const; + void setStarNet8(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch, const wxString& reflector); + + void getStarNet9(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch, wxString& reflector) const; + void setStarNet9(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch, const wxString& reflector); + + void getStarNet10(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch, wxString& reflector) const; + void setStarNet10(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch, const wxString& reflector); + + void getStarNet11(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch, wxString& reflector) const; + void setStarNet11(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch, const wxString& reflector); + + void getStarNet12(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch, wxString& reflector) const; + void setStarNet12(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch, const wxString& reflector); + + void getStarNet13(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch, wxString& reflector) const; + void setStarNet13(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch, const wxString& reflector); + + void getStarNet14(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch, wxString& reflector) const; + void setStarNet14(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch, const wxString& reflector); + + void getStarNet15(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch, wxString& reflector) const; + void setStarNet15(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch, const wxString& reflector); +#else + void getStarNet1(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch) const; + void setStarNet1(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch); + + void getStarNet2(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch) const; + void setStarNet2(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch); + + void getStarNet3(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch) const; + void setStarNet3(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch); + + void getStarNet4(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch) const; + void setStarNet4(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch); + + void getStarNet5(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch) const; + void setStarNet5(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch); + + void getStarNet6(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch) const; + void setStarNet6(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch); + + void getStarNet7(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch) const; + void setStarNet7(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch); + + void getStarNet8(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch) const; + void setStarNet8(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch); + + void getStarNet9(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch) const; + void setStarNet9(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch); + + void getStarNet10(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch) const; + void setStarNet10(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch); + + void getStarNet11(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch) const; + void setStarNet11(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch); + + void getStarNet12(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch) const; + void setStarNet12(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch); + + void getStarNet13(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch) const; + void setStarNet13(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch); + + void getStarNet14(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch) const; + void setStarNet14(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch); + + void getStarNet15(wxString& band, wxString& callsign, wxString& logoff, wxString& info, wxString& permanent, unsigned int& userTimeout, unsigned int& groupTimeout, STARNET_CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch) const; + void setStarNet15(const wxString& band, const wxString& callsign, const wxString& logoff, const wxString& info, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch); +#endif + + void getRemote(bool& enabled, wxString& password, unsigned int& port) const; + void setRemote(bool enabled, const wxString& password, unsigned int port); + + void getMiscellaneous(bool& enabled) const; + void setMiscellaneous(bool enabled); + + void getPosition(int& x, int& y) const; + void setPosition(int x, int y); + + bool write(); + +private: +#if defined(__WINDOWS__) + wxConfigBase* m_config; +#endif + wxFileName m_fileName; + wxString m_callsign; + wxString m_address; + wxString m_ircddbHostname; + wxString m_ircddbUsername; + wxString m_ircddbPassword; + wxString m_starNet1Band; + wxString m_starNet1Callsign; + wxString m_starNet1Logoff; + wxString m_starNet1Info; + wxString m_starNet1Permanent; + unsigned int m_starNet1UserTimeout; + unsigned int m_starNet1GroupTimeout; + STARNET_CALLSIGN_SWITCH m_starNet1CallsignSwitch; + bool m_starNet1TxMsgSwitch; + wxString m_starNet1Reflector; + wxString m_starNet2Band; + wxString m_starNet2Callsign; + wxString m_starNet2Logoff; + wxString m_starNet2Info; + wxString m_starNet2Permanent; + unsigned int m_starNet2UserTimeout; + unsigned int m_starNet2GroupTimeout; + STARNET_CALLSIGN_SWITCH m_starNet2CallsignSwitch; + bool m_starNet2TxMsgSwitch; + wxString m_starNet2Reflector; + wxString m_starNet3Band; + wxString m_starNet3Callsign; + wxString m_starNet3Logoff; + wxString m_starNet3Info; + wxString m_starNet3Permanent; + unsigned int m_starNet3UserTimeout; + unsigned int m_starNet3GroupTimeout; + STARNET_CALLSIGN_SWITCH m_starNet3CallsignSwitch; + bool m_starNet3TxMsgSwitch; + wxString m_starNet3Reflector; + wxString m_starNet4Band; + wxString m_starNet4Callsign; + wxString m_starNet4Logoff; + wxString m_starNet4Info; + wxString m_starNet4Permanent; + unsigned int m_starNet4UserTimeout; + unsigned int m_starNet4GroupTimeout; + STARNET_CALLSIGN_SWITCH m_starNet4CallsignSwitch; + bool m_starNet4TxMsgSwitch; + wxString m_starNet4Reflector; + wxString m_starNet5Band; + wxString m_starNet5Callsign; + wxString m_starNet5Logoff; + wxString m_starNet5Info; + wxString m_starNet5Permanent; + unsigned int m_starNet5UserTimeout; + unsigned int m_starNet5GroupTimeout; + STARNET_CALLSIGN_SWITCH m_starNet5CallsignSwitch; + bool m_starNet5TxMsgSwitch; + wxString m_starNet5Reflector; + wxString m_starNet6Band; + wxString m_starNet6Callsign; + wxString m_starNet6Logoff; + wxString m_starNet6Info; + wxString m_starNet6Permanent; + unsigned int m_starNet6UserTimeout; + unsigned int m_starNet6GroupTimeout; + STARNET_CALLSIGN_SWITCH m_starNet6CallsignSwitch; + bool m_starNet6TxMsgSwitch; + wxString m_starNet6Reflector; + wxString m_starNet7Band; + wxString m_starNet7Callsign; + wxString m_starNet7Logoff; + wxString m_starNet7Info; + wxString m_starNet7Permanent; + unsigned int m_starNet7UserTimeout; + unsigned int m_starNet7GroupTimeout; + STARNET_CALLSIGN_SWITCH m_starNet7CallsignSwitch; + bool m_starNet7TxMsgSwitch; + wxString m_starNet7Reflector; + wxString m_starNet8Band; + wxString m_starNet8Callsign; + wxString m_starNet8Logoff; + wxString m_starNet8Info; + wxString m_starNet8Permanent; + unsigned int m_starNet8UserTimeout; + unsigned int m_starNet8GroupTimeout; + STARNET_CALLSIGN_SWITCH m_starNet8CallsignSwitch; + bool m_starNet8TxMsgSwitch; + wxString m_starNet8Reflector; + wxString m_starNet9Band; + wxString m_starNet9Callsign; + wxString m_starNet9Logoff; + wxString m_starNet9Info; + wxString m_starNet9Permanent; + unsigned int m_starNet9UserTimeout; + unsigned int m_starNet9GroupTimeout; + STARNET_CALLSIGN_SWITCH m_starNet9CallsignSwitch; + bool m_starNet9TxMsgSwitch; + wxString m_starNet9Reflector; + wxString m_starNet10Band; + wxString m_starNet10Callsign; + wxString m_starNet10Logoff; + wxString m_starNet10Info; + wxString m_starNet10Permanent; + unsigned int m_starNet10UserTimeout; + unsigned int m_starNet10GroupTimeout; + STARNET_CALLSIGN_SWITCH m_starNet10CallsignSwitch; + bool m_starNet10TxMsgSwitch; + wxString m_starNet10Reflector; + wxString m_starNet11Band; + wxString m_starNet11Callsign; + wxString m_starNet11Logoff; + wxString m_starNet11Info; + wxString m_starNet11Permanent; + unsigned int m_starNet11UserTimeout; + unsigned int m_starNet11GroupTimeout; + STARNET_CALLSIGN_SWITCH m_starNet11CallsignSwitch; + bool m_starNet11TxMsgSwitch; + wxString m_starNet11Reflector; + wxString m_starNet12Band; + wxString m_starNet12Callsign; + wxString m_starNet12Logoff; + wxString m_starNet12Info; + wxString m_starNet12Permanent; + unsigned int m_starNet12UserTimeout; + unsigned int m_starNet12GroupTimeout; + STARNET_CALLSIGN_SWITCH m_starNet12CallsignSwitch; + bool m_starNet12TxMsgSwitch; + wxString m_starNet12Reflector; + wxString m_starNet13Band; + wxString m_starNet13Callsign; + wxString m_starNet13Logoff; + wxString m_starNet13Info; + wxString m_starNet13Permanent; + unsigned int m_starNet13UserTimeout; + unsigned int m_starNet13GroupTimeout; + STARNET_CALLSIGN_SWITCH m_starNet13CallsignSwitch; + bool m_starNet13TxMsgSwitch; + wxString m_starNet13Reflector; + wxString m_starNet14Band; + wxString m_starNet14Callsign; + wxString m_starNet14Logoff; + wxString m_starNet14Info; + wxString m_starNet14Permanent; + unsigned int m_starNet14UserTimeout; + unsigned int m_starNet14GroupTimeout; + STARNET_CALLSIGN_SWITCH m_starNet14CallsignSwitch; + bool m_starNet14TxMsgSwitch; + wxString m_starNet14Reflector; + wxString m_starNet15Band; + wxString m_starNet15Callsign; + wxString m_starNet15Logoff; + wxString m_starNet15Info; + wxString m_starNet15Permanent; + unsigned int m_starNet15UserTimeout; + unsigned int m_starNet15GroupTimeout; + STARNET_CALLSIGN_SWITCH m_starNet15CallsignSwitch; + bool m_starNet15TxMsgSwitch; + wxString m_starNet15Reflector; + bool m_remoteEnabled; + wxString m_remotePassword; + unsigned int m_remotePort; + bool m_logEnabled; + int m_x; + int m_y; +}; + +#endif diff --git a/StarNetServer/StarNetServerDefs.h b/StarNetServer/StarNetServerDefs.h new file mode 100644 index 0000000..d1f3538 --- /dev/null +++ b/StarNetServer/StarNetServerDefs.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2010,2011,2012,2014 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef StarNetServerDefs_H +#define StarNetServerDefs_H + +#include + +const wxString APPLICATION_NAME = wxT("StarNet Server"); + +const wxString LOG_BASE_NAME = wxT("STARnetServer"); + +const wxString CONFIG_FILE_NAME = wxT("starnetserver"); + +const unsigned int MAX_STARNETS = 15U; +const unsigned int MAX_DEXTRA_LINKS = 15U; +const unsigned int MAX_DCS_LINKS = 15U; +const unsigned int MAX_ROUTES = 0U; + +#endif diff --git a/StarNetServer/StarNetServerFrame.cpp b/StarNetServer/StarNetServerFrame.cpp new file mode 100644 index 0000000..c931797 --- /dev/null +++ b/StarNetServer/StarNetServerFrame.cpp @@ -0,0 +1,719 @@ +/* + * Copyright (C) 2010-2015 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "StarNetServerPreferences.h" +#include "StarNetServerFrame.h" +#include "StarNetServerDefs.h" +#include "StarNetServerApp.h" +#include "LogEvent.h" +#include "Version.h" + +const unsigned int BORDER_SIZE = 5U; + +#if defined(__WINDOWS__) +const unsigned int LOGTEXT_WIDTH = 560U; +#else +const unsigned int LOGTEXT_WIDTH = 700U; +#endif + +#include +#include + +DEFINE_EVENT_TYPE(LOG_EVENT) + +enum { + Menu_Edit_Preferences = 6000, + Menu_View_Updates +}; + +BEGIN_EVENT_TABLE(CStarNetServerFrame, wxFrame) + EVT_MENU(wxID_EXIT, CStarNetServerFrame::onQuit) + EVT_MENU(Menu_Edit_Preferences, CStarNetServerFrame::onPreferences) + EVT_MENU(Menu_View_Updates, CStarNetServerFrame::onUpdates) + EVT_MENU(wxID_ABOUT, CStarNetServerFrame::onAbout) + + EVT_CLOSE(CStarNetServerFrame::onClose) + + EVT_CUSTOM(LOG_EVENT, wxID_ANY, CStarNetServerFrame::onLog) +END_EVENT_TABLE() + +CStarNetServerFrame::CStarNetServerFrame(const wxString& title, const wxPoint& position, bool gui) : +wxFrame(NULL, -1, title, position), +#if defined(__WXDEBUG__) +m_updates(true) +#else +m_updates(gui) +#endif +{ + SetMenuBar(createMenuBar()); + + wxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL); + + wxPanel* panel = new wxPanel(this); + + wxBoxSizer* panelSizer = new wxBoxSizer(wxVERTICAL); + + wxStaticBoxSizer* log1Sizer = new wxStaticBoxSizer(new wxStaticBox(panel, -1, _("Log")), wxVERTICAL); + wxBoxSizer* log2Sizer = new wxBoxSizer(wxVERTICAL); + + for (unsigned int i = 0U; i < 20U; i++) { + m_logLine[i] = new wxStaticText(panel, -1, wxEmptyString, wxDefaultPosition, wxSize(LOGTEXT_WIDTH, -1)); + m_logLine[i]->Wrap(LOGTEXT_WIDTH); + log2Sizer->Add(m_logLine[i], 0, wxTOP | wxLEFT | wxRIGHT, BORDER_SIZE); + } + + log1Sizer->Add(log2Sizer); + panelSizer->Add(log1Sizer, 0, wxALL, BORDER_SIZE); + + panel->SetSizer(panelSizer); + panelSizer->SetSizeHints(panel); + + mainSizer->Add(panel); + + SetSizer(mainSizer); + mainSizer->SetSizeHints(this); +} + +CStarNetServerFrame::~CStarNetServerFrame() +{ +} + +wxMenuBar* CStarNetServerFrame::createMenuBar() +{ + wxMenu* fileMenu = new wxMenu(); + fileMenu->Append(wxID_EXIT, _("Exit")); + + wxMenu* editMenu = new wxMenu(); + editMenu->Append(Menu_Edit_Preferences, _("Preferences...")); + + wxMenu* viewMenu = new wxMenu(); + viewMenu->AppendCheckItem(Menu_View_Updates, _("GUI Updates")); + viewMenu->Check(Menu_View_Updates, m_updates); + + wxMenu* helpMenu = new wxMenu(); + helpMenu->Append(wxID_ABOUT, _("About StarNet Server")); + + wxMenuBar* menuBar = new wxMenuBar(); + menuBar->Append(fileMenu, _("File")); + menuBar->Append(editMenu, _("Edit")); + menuBar->Append(viewMenu, _("View")); + menuBar->Append(helpMenu, _("Help")); + + return menuBar; +} + +void CStarNetServerFrame::onQuit(wxCommandEvent&) +{ + Close(false); +} + +void CStarNetServerFrame::onClose(wxCloseEvent&) +{ + int x, y; + GetPosition(&x, &y); + if (x >= 0 && y >= 0) { + ::wxGetApp().setPosition(x, y); + ::wxGetApp().writeConfig(); + } + + Destroy(); +} + +void CStarNetServerFrame::onPreferences(wxCommandEvent&) +{ + wxString callsign, address; + ::wxGetApp().getGateway(callsign, address); + + wxString hostname, username, password; + ::wxGetApp().getIrcDDB(hostname, username, password); + + unsigned int remotePort; + wxString remotePassword; + bool remoteEnabled; + ::wxGetApp().getRemote(remoteEnabled, remotePassword, remotePort); + + bool logEnabled; + ::wxGetApp().getMiscellaneous(logEnabled); + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + wxString starNetBand1, starNetCallsign1, starNetLogoff1, starNetInfo1, starNetLink1, starNetPermanent1; + unsigned int starNetUserTimeout1, starNetGroupTimeout1; + STARNET_CALLSIGN_SWITCH starNetCallsignSwitch1; + bool starNetTXMsgSwitch1; + ::wxGetApp().getStarNet1(starNetBand1, starNetCallsign1, starNetLogoff1, starNetInfo1, starNetPermanent1, starNetUserTimeout1, starNetGroupTimeout1, starNetCallsignSwitch1, starNetTXMsgSwitch1, starNetLink1); + + wxString starNetBand2, starNetCallsign2, starNetLogoff2, starNetInfo2, starNetLink2, starNetPermanent2; + unsigned int starNetUserTimeout2, starNetGroupTimeout2; + STARNET_CALLSIGN_SWITCH starNetCallsignSwitch2; + bool starNetTXMsgSwitch2; + ::wxGetApp().getStarNet2(starNetBand2, starNetCallsign2, starNetLogoff2, starNetInfo2, starNetPermanent2, starNetUserTimeout2, starNetGroupTimeout2, starNetCallsignSwitch2, starNetTXMsgSwitch2, starNetLink2); + + wxString starNetBand3, starNetCallsign3, starNetLogoff3, starNetInfo3, starNetLink3, starNetPermanent3; + unsigned int starNetUserTimeout3, starNetGroupTimeout3; + STARNET_CALLSIGN_SWITCH starNetCallsignSwitch3; + bool starNetTXMsgSwitch3; + ::wxGetApp().getStarNet3(starNetBand3, starNetCallsign3, starNetLogoff3, starNetInfo3, starNetPermanent3, starNetUserTimeout3, starNetGroupTimeout3, starNetCallsignSwitch3, starNetTXMsgSwitch3, starNetLink3); + + wxString starNetBand4, starNetCallsign4, starNetLogoff4, starNetInfo4, starNetLink4, starNetPermanent4; + unsigned int starNetUserTimeout4, starNetGroupTimeout4; + STARNET_CALLSIGN_SWITCH starNetCallsignSwitch4; + bool starNetTXMsgSwitch4; + ::wxGetApp().getStarNet4(starNetBand4, starNetCallsign4, starNetLogoff4, starNetInfo4, starNetPermanent4, starNetUserTimeout4, starNetGroupTimeout4, starNetCallsignSwitch4, starNetTXMsgSwitch4, starNetLink4); + + wxString starNetBand5, starNetCallsign5, starNetLogoff5, starNetInfo5, starNetLink5, starNetPermanent5; + unsigned int starNetUserTimeout5, starNetGroupTimeout5; + STARNET_CALLSIGN_SWITCH starNetCallsignSwitch5; + bool starNetTXMsgSwitch5; + ::wxGetApp().getStarNet5(starNetBand5, starNetCallsign5, starNetLogoff5, starNetInfo5, starNetPermanent5, starNetUserTimeout5, starNetGroupTimeout5, starNetCallsignSwitch5, starNetTXMsgSwitch5, starNetLink5); + + wxString starNetBand6, starNetCallsign6, starNetLogoff6, starNetInfo6, starNetLink6, starNetPermanent6; + unsigned int starNetUserTimeout6, starNetGroupTimeout6; + STARNET_CALLSIGN_SWITCH starNetCallsignSwitch6; + bool starNetTXMsgSwitch6; + ::wxGetApp().getStarNet6(starNetBand6, starNetCallsign6, starNetLogoff6, starNetInfo6, starNetPermanent6, starNetUserTimeout6, starNetGroupTimeout6, starNetCallsignSwitch6, starNetTXMsgSwitch6, starNetLink6); + + wxString starNetBand7, starNetCallsign7, starNetLogoff7, starNetInfo7, starNetLink7, starNetPermanent7; + unsigned int starNetUserTimeout7, starNetGroupTimeout7; + STARNET_CALLSIGN_SWITCH starNetCallsignSwitch7; + bool starNetTXMsgSwitch7; + ::wxGetApp().getStarNet7(starNetBand7, starNetCallsign7, starNetLogoff7, starNetInfo7, starNetPermanent7, starNetUserTimeout7, starNetGroupTimeout7, starNetCallsignSwitch7, starNetTXMsgSwitch7, starNetLink7); + + wxString starNetBand8, starNetCallsign8, starNetLogoff8, starNetInfo8, starNetLink8, starNetPermanent8; + unsigned int starNetUserTimeout8, starNetGroupTimeout8; + STARNET_CALLSIGN_SWITCH starNetCallsignSwitch8; + bool starNetTXMsgSwitch8; + ::wxGetApp().getStarNet8(starNetBand8, starNetCallsign8, starNetLogoff8, starNetInfo8, starNetPermanent8, starNetUserTimeout8, starNetGroupTimeout8, starNetCallsignSwitch8, starNetTXMsgSwitch8, starNetLink8); + + wxString starNetBand9, starNetCallsign9, starNetLogoff9, starNetInfo9, starNetLink9, starNetPermanent9; + unsigned int starNetUserTimeout9, starNetGroupTimeout9; + STARNET_CALLSIGN_SWITCH starNetCallsignSwitch9; + bool starNetTXMsgSwitch9; + ::wxGetApp().getStarNet9(starNetBand9, starNetCallsign9, starNetLogoff9, starNetInfo9, starNetPermanent9, starNetUserTimeout9, starNetGroupTimeout9, starNetCallsignSwitch9, starNetTXMsgSwitch9, starNetLink9); + + wxString starNetBand10, starNetCallsign10, starNetInfo10, starNetLogoff10, starNetLink10, starNetPermanent10; + unsigned int starNetUserTimeout10, starNetGroupTimeout10; + STARNET_CALLSIGN_SWITCH starNetCallsignSwitch10; + bool starNetTXMsgSwitch10; + ::wxGetApp().getStarNet10(starNetBand10, starNetCallsign10, starNetLogoff10, starNetInfo10, starNetPermanent10, starNetUserTimeout10, starNetGroupTimeout10, starNetCallsignSwitch10, starNetTXMsgSwitch10, starNetLink10); + + wxString starNetBand11, starNetCallsign11, starNetLogoff11, starNetInfo11, starNetLink11, starNetPermanent11; + unsigned int starNetUserTimeout11, starNetGroupTimeout11; + STARNET_CALLSIGN_SWITCH starNetCallsignSwitch11; + bool starNetTXMsgSwitch11; + ::wxGetApp().getStarNet11(starNetBand11, starNetCallsign11, starNetLogoff11, starNetInfo11, starNetPermanent11, starNetUserTimeout11, starNetGroupTimeout11, starNetCallsignSwitch11, starNetTXMsgSwitch11, starNetLink11); + + wxString starNetBand12, starNetCallsign12, starNetLogoff12, starNetInfo12, starNetLink12, starNetPermanent12; + unsigned int starNetUserTimeout12, starNetGroupTimeout12; + STARNET_CALLSIGN_SWITCH starNetCallsignSwitch12; + bool starNetTXMsgSwitch12; + ::wxGetApp().getStarNet12(starNetBand12, starNetCallsign12, starNetLogoff12, starNetInfo12, starNetPermanent12, starNetUserTimeout12, starNetGroupTimeout12, starNetCallsignSwitch12, starNetTXMsgSwitch12, starNetLink12); + + wxString starNetBand13, starNetCallsign13, starNetLogoff13, starNetInfo13, starNetLink13, starNetPermanent13; + unsigned int starNetUserTimeout13, starNetGroupTimeout13; + STARNET_CALLSIGN_SWITCH starNetCallsignSwitch13; + bool starNetTXMsgSwitch13; + ::wxGetApp().getStarNet13(starNetBand13, starNetCallsign13, starNetLogoff13, starNetInfo13, starNetPermanent13, starNetUserTimeout13, starNetGroupTimeout13, starNetCallsignSwitch13, starNetTXMsgSwitch13, starNetLink13); + + wxString starNetBand14, starNetCallsign14, starNetLogoff14, starNetInfo14, starNetLink14, starNetPermanent14; + unsigned int starNetUserTimeout14, starNetGroupTimeout14; + STARNET_CALLSIGN_SWITCH starNetCallsignSwitch14; + bool starNetTXMsgSwitch14; + ::wxGetApp().getStarNet14(starNetBand14, starNetCallsign14, starNetLogoff14, starNetInfo14, starNetPermanent14, starNetUserTimeout14, starNetGroupTimeout14, starNetCallsignSwitch14, starNetTXMsgSwitch14, starNetLink14); + + wxString starNetBand15, starNetCallsign15, starNetLogoff15, starNetInfo15, starNetLink15, starNetPermanent15; + unsigned int starNetUserTimeout15, starNetGroupTimeout15; + STARNET_CALLSIGN_SWITCH starNetCallsignSwitch15; + bool starNetTXMsgSwitch15; + ::wxGetApp().getStarNet15(starNetBand15, starNetCallsign15, starNetLogoff15, starNetInfo15, starNetPermanent15, starNetUserTimeout15, starNetGroupTimeout15, starNetCallsignSwitch15, starNetTXMsgSwitch15, starNetLink15); + + CStarNetServerPreferences dialog1(this, -1, callsign, address, + hostname, username, password, logEnabled, + starNetBand1, starNetCallsign1, starNetLogoff1, starNetInfo1, starNetPermanent1, starNetUserTimeout1, starNetGroupTimeout1, starNetCallsignSwitch1, starNetTXMsgSwitch1, starNetLink1, + starNetBand2, starNetCallsign2, starNetLogoff2, starNetInfo2, starNetPermanent2, starNetUserTimeout2, starNetGroupTimeout2, starNetCallsignSwitch2, starNetTXMsgSwitch2, starNetLink2, + starNetBand3, starNetCallsign3, starNetLogoff3, starNetInfo3, starNetPermanent3, starNetUserTimeout3, starNetGroupTimeout3, starNetCallsignSwitch3, starNetTXMsgSwitch3, starNetLink3, + starNetBand4, starNetCallsign4, starNetLogoff4, starNetInfo4, starNetPermanent4, starNetUserTimeout4, starNetGroupTimeout4, starNetCallsignSwitch4, starNetTXMsgSwitch4, starNetLink4, + starNetBand5, starNetCallsign5, starNetLogoff5, starNetInfo5, starNetPermanent5, starNetUserTimeout5, starNetGroupTimeout5, starNetCallsignSwitch5, starNetTXMsgSwitch5, starNetLink5, + starNetBand6, starNetCallsign6, starNetLogoff6, starNetInfo6, starNetPermanent6, starNetUserTimeout6, starNetGroupTimeout6, starNetCallsignSwitch6, starNetTXMsgSwitch6, starNetLink6, + starNetBand7, starNetCallsign7, starNetLogoff7, starNetInfo7, starNetPermanent7, starNetUserTimeout7, starNetGroupTimeout7, starNetCallsignSwitch7, starNetTXMsgSwitch7, starNetLink7, + starNetBand8, starNetCallsign8, starNetLogoff8, starNetInfo8, starNetPermanent8, starNetUserTimeout8, starNetGroupTimeout8, starNetCallsignSwitch8, starNetTXMsgSwitch8, starNetLink8, + starNetBand9, starNetCallsign9, starNetLogoff9, starNetInfo9, starNetPermanent9, starNetUserTimeout9, starNetGroupTimeout9, starNetCallsignSwitch9, starNetTXMsgSwitch9, starNetLink9, + starNetBand10, starNetCallsign10, starNetLogoff10, starNetInfo10, starNetPermanent10, starNetUserTimeout10, starNetGroupTimeout10, starNetCallsignSwitch10, starNetTXMsgSwitch10, starNetLink10, + starNetBand11, starNetCallsign11, starNetLogoff11, starNetInfo11, starNetPermanent11, starNetUserTimeout11, starNetGroupTimeout11, starNetCallsignSwitch11, starNetTXMsgSwitch11, starNetLink11, + starNetBand12, starNetCallsign12, starNetLogoff12, starNetInfo12, starNetPermanent12, starNetUserTimeout12, starNetGroupTimeout12, starNetCallsignSwitch12, starNetTXMsgSwitch12, starNetLink12, + starNetBand13, starNetCallsign13, starNetLogoff13, starNetInfo13, starNetPermanent13, starNetUserTimeout13, starNetGroupTimeout13, starNetCallsignSwitch13, starNetTXMsgSwitch13, starNetLink13, + starNetBand14, starNetCallsign14, starNetLogoff14, starNetInfo14, starNetPermanent14, starNetUserTimeout14, starNetGroupTimeout14, starNetCallsignSwitch14, starNetTXMsgSwitch14, starNetLink14, + starNetBand15, starNetCallsign15, starNetLogoff15, starNetInfo15, starNetPermanent15, starNetUserTimeout15, starNetGroupTimeout15, starNetCallsignSwitch15, starNetTXMsgSwitch15, starNetLink15, + remoteEnabled, remotePassword, remotePort); +#else + wxString starNetBand1, starNetCallsign1, starNetLogoff1, starNetInfo1, starNetPermanent1; + unsigned int starNetUserTimeout1, starNetGroupTimeout1; + STARNET_CALLSIGN_SWITCH starNetCallsignSwitch1; + bool starNetTXMsgSwitch1; + ::wxGetApp().getStarNet1(starNetBand1, starNetCallsign1, starNetLogoff1, starNetInfo1, starNetPermanent1, starNetUserTimeout1, starNetGroupTimeout1, starNetCallsignSwitch1, starNetTXMsgSwitch1); + + wxString starNetBand2, starNetCallsign2, starNetLogoff2, starNetInfo2, starNetPermanent2; + unsigned int starNetUserTimeout2, starNetGroupTimeout2; + STARNET_CALLSIGN_SWITCH starNetCallsignSwitch2; + bool starNetTXMsgSwitch2; + ::wxGetApp().getStarNet2(starNetBand2, starNetCallsign2, starNetLogoff2, starNetInfo2, starNetPermanent2, starNetUserTimeout2, starNetGroupTimeout2, starNetCallsignSwitch2, starNetTXMsgSwitch2); + + wxString starNetBand3, starNetCallsign3, starNetLogoff3, starNetInfo3, starNetPermanent3; + unsigned int starNetUserTimeout3, starNetGroupTimeout3; + STARNET_CALLSIGN_SWITCH starNetCallsignSwitch3; + bool starNetTXMsgSwitch3; + ::wxGetApp().getStarNet3(starNetBand3, starNetCallsign3, starNetLogoff3, starNetInfo3, starNetPermanent3, starNetUserTimeout3, starNetGroupTimeout3, starNetCallsignSwitch3, starNetTXMsgSwitch3); + + wxString starNetBand4, starNetCallsign4, starNetLogoff4, starNetInfo4, starNetPermanent4; + unsigned int starNetUserTimeout4, starNetGroupTimeout4; + STARNET_CALLSIGN_SWITCH starNetCallsignSwitch4; + bool starNetTXMsgSwitch4; + ::wxGetApp().getStarNet4(starNetBand4, starNetCallsign4, starNetLogoff4, starNetInfo4, starNetPermanent4, starNetUserTimeout4, starNetGroupTimeout4, starNetCallsignSwitch4, starNetTXMsgSwitch4); + + wxString starNetBand5, starNetCallsign5, starNetLogoff5, starNetInfo5, starNetPermanent5; + unsigned int starNetUserTimeout5, starNetGroupTimeout5; + STARNET_CALLSIGN_SWITCH starNetCallsignSwitch5; + bool starNetTXMsgSwitch5; + ::wxGetApp().getStarNet5(starNetBand5, starNetCallsign5, starNetLogoff5, starNetInfo5, starNetPermanent5, starNetUserTimeout5, starNetGroupTimeout5, starNetCallsignSwitch5, starNetTXMsgSwitch5); + + wxString starNetBand6, starNetCallsign6, starNetLogoff6, starNetInfo6, starNetPermanent6; + unsigned int starNetUserTimeout6, starNetGroupTimeout6; + STARNET_CALLSIGN_SWITCH starNetCallsignSwitch6; + bool starNetTXMsgSwitch6; + ::wxGetApp().getStarNet6(starNetBand6, starNetCallsign6, starNetLogoff6, starNetInfo6, starNetPermanent6, starNetUserTimeout6, starNetGroupTimeout6, starNetCallsignSwitch6, starNetTXMsgSwitch6); + + wxString starNetBand7, starNetCallsign7, starNetLogoff7, starNetInfo7, starNetPermanent7; + unsigned int starNetUserTimeout7, starNetGroupTimeout7; + STARNET_CALLSIGN_SWITCH starNetCallsignSwitch7; + bool starNetTXMsgSwitch7; + ::wxGetApp().getStarNet7(starNetBand7, starNetCallsign7, starNetLogoff7, starNetInfo7, starNetPermanent7, starNetUserTimeout7, starNetGroupTimeout7, starNetCallsignSwitch7, starNetTXMsgSwitch7); + + wxString starNetBand8, starNetCallsign8, starNetLogoff8, starNetInfo8, starNetPermanent8; + unsigned int starNetUserTimeout8, starNetGroupTimeout8; + STARNET_CALLSIGN_SWITCH starNetCallsignSwitch8; + bool starNetTXMsgSwitch8; + ::wxGetApp().getStarNet8(starNetBand8, starNetCallsign8, starNetLogoff8, starNetInfo8, starNetPermanent8, starNetUserTimeout8, starNetGroupTimeout8, starNetCallsignSwitch8, starNetTXMsgSwitch8); + + wxString starNetBand9, starNetCallsign9, starNetLogoff9, starNetInfo9, starNetPermanent9; + unsigned int starNetUserTimeout9, starNetGroupTimeout9; + STARNET_CALLSIGN_SWITCH starNetCallsignSwitch9; + bool starNetTXMsgSwitch9; + ::wxGetApp().getStarNet9(starNetBand9, starNetCallsign9, starNetLogoff9, starNetInfo9, starNetPermanent9, starNetUserTimeout9, starNetGroupTimeout9, starNetCallsignSwitch9, starNetTXMsgSwitch9); + + wxString starNetBand10, starNetCallsign10, starNetLogoff10, starNetInfo10, starNetPermanent10; + unsigned int starNetUserTimeout10, starNetGroupTimeout10; + STARNET_CALLSIGN_SWITCH starNetCallsignSwitch10; + bool starNetTXMsgSwitch10; + ::wxGetApp().getStarNet10(starNetBand10, starNetCallsign10, starNetLogoff10, starNetInfo10, starNetPermanent10, starNetUserTimeout10, starNetGroupTimeout10, starNetCallsignSwitch10, starNetTXMsgSwitch10); + + wxString starNetBand11, starNetCallsign11, starNetLogoff11, starNetInfo11, starNetPermanent11; + unsigned int starNetUserTimeout11, starNetGroupTimeout11; + STARNET_CALLSIGN_SWITCH starNetCallsignSwitch11; + bool starNetTXMsgSwitch11; + ::wxGetApp().getStarNet11(starNetBand11, starNetCallsign11, starNetLogoff11, starNetInfo11, starNetPermanent11, starNetUserTimeout11, starNetGroupTimeout11, starNetCallsignSwitch11, starNetTXMsgSwitch11); + + wxString starNetBand12, starNetCallsign12, starNetLogoff12, starNetInfo12, starNetPermanent12; + unsigned int starNetUserTimeout12, starNetGroupTimeout12; + STARNET_CALLSIGN_SWITCH starNetCallsignSwitch12; + bool starNetTXMsgSwitch12; + ::wxGetApp().getStarNet12(starNetBand12, starNetCallsign12, starNetLogoff12, starNetInfo12, starNetPermanent12, starNetUserTimeout12, starNetGroupTimeout12, starNetCallsignSwitch12, starNetTXMsgSwitch12); + + wxString starNetBand13, starNetCallsign13, starNetLogoff13, starNetInfo13, starNetPermanent13; + unsigned int starNetUserTimeout13, starNetGroupTimeout13; + STARNET_CALLSIGN_SWITCH starNetCallsignSwitch13; + bool starNetTXMsgSwitch13; + ::wxGetApp().getStarNet13(starNetBand13, starNetCallsign13, starNetLogoff13, starNetInfo13, starNetPermanent13, starNetUserTimeout13, starNetGroupTimeout13, starNetCallsignSwitch13, starNetTXMsgSwitch13); + + wxString starNetBand14, starNetCallsign14, starNetLogoff14, starNetInfo14, starNetPermanent14; + unsigned int starNetUserTimeout14, starNetGroupTimeout14; + STARNET_CALLSIGN_SWITCH starNetCallsignSwitch14; + bool starNetTXMsgSwitch14; + ::wxGetApp().getStarNet14(starNetBand14, starNetCallsign14, starNetLogoff14, starNetInfo14, starNetPermanent14, starNetUserTimeout14, starNetGroupTimeout14, starNetCallsignSwitch14, starNetTXMsgSwitch14); + + wxString starNetBand15, starNetCallsign15, starNetLogoff15, starNetInfo15, starNetPermanent15; + unsigned int starNetUserTimeout15, starNetGroupTimeout15; + STARNET_CALLSIGN_SWITCH starNetCallsignSwitch15; + bool starNetTXMsgSwitch15; + ::wxGetApp().getStarNet15(starNetBand15, starNetCallsign15, starNetLogoff15, starNetInfo15, starNetPermanent15, starNetUserTimeout15, starNetGroupTimeout15, starNetCallsignSwitch15, starNetTXMsgSwitch15); + + CStarNetServerPreferences dialog1(this, -1, callsign, address, + hostname, username, password, logEnabled, + starNetBand1, starNetCallsign1, starNetLogoff1, starNetInfo1, starNetPermanent1, starNetUserTimeout1, starNetGroupTimeout1, starNetCallsignSwitch1, starNetTXMsgSwitch1, + starNetBand2, starNetCallsign2, starNetLogoff2, starNetInfo2, starNetPermanent2, starNetUserTimeout2, starNetGroupTimeout2, starNetCallsignSwitch2, starNetTXMsgSwitch2, + starNetBand3, starNetCallsign3, starNetLogoff3, starNetInfo3, starNetPermanent3, starNetUserTimeout3, starNetGroupTimeout3, starNetCallsignSwitch3, starNetTXMsgSwitch3, + starNetBand4, starNetCallsign4, starNetLogoff4, starNetInfo4, starNetPermanent4, starNetUserTimeout4, starNetGroupTimeout4, starNetCallsignSwitch4, starNetTXMsgSwitch4, + starNetBand5, starNetCallsign5, starNetLogoff5, starNetInfo5, starNetPermanent5, starNetUserTimeout5, starNetGroupTimeout5, starNetCallsignSwitch5, starNetTXMsgSwitch5, + starNetBand6, starNetCallsign6, starNetLogoff6, starNetInfo6, starNetPermanent6, starNetUserTimeout6, starNetGroupTimeout6, starNetCallsignSwitch6, starNetTXMsgSwitch6, + starNetBand7, starNetCallsign7, starNetLogoff7, starNetInfo7, starNetPermanent7, starNetUserTimeout7, starNetGroupTimeout7, starNetCallsignSwitch7, starNetTXMsgSwitch7, + starNetBand8, starNetCallsign8, starNetLogoff8, starNetInfo8, starNetPermanent8, starNetUserTimeout8, starNetGroupTimeout8, starNetCallsignSwitch8, starNetTXMsgSwitch8, + starNetBand9, starNetCallsign9, starNetLogoff9, starNetInfo9, starNetPermanent9, starNetUserTimeout9, starNetGroupTimeout9, starNetCallsignSwitch9, starNetTXMsgSwitch9, + starNetBand10, starNetCallsign10, starNetLogoff10, starNetInfo10, starNetPermanent10, starNetUserTimeout10, starNetGroupTimeout10, starNetCallsignSwitch10, starNetTXMsgSwitch10, + starNetBand11, starNetCallsign11, starNetLogoff11, starNetInfo11, starNetPermanent11, starNetUserTimeout11, starNetGroupTimeout11, starNetCallsignSwitch11, starNetTXMsgSwitch11, + starNetBand12, starNetCallsign12, starNetLogoff12, starNetInfo12, starNetPermanent12, starNetUserTimeout12, starNetGroupTimeout12, starNetCallsignSwitch12, starNetTXMsgSwitch12, + starNetBand13, starNetCallsign13, starNetLogoff13, starNetInfo13, starNetPermanent13, starNetUserTimeout13, starNetGroupTimeout13, starNetCallsignSwitch13, starNetTXMsgSwitch13, + starNetBand14, starNetCallsign14, starNetLogoff14, starNetInfo14, starNetPermanent14, starNetUserTimeout14, starNetGroupTimeout14, starNetCallsignSwitch14, starNetTXMsgSwitch14, + starNetBand15, starNetCallsign15, starNetLogoff15, starNetInfo15, starNetPermanent15, starNetUserTimeout15, starNetGroupTimeout15, starNetCallsignSwitch15, starNetTXMsgSwitch15, + remoteEnabled, remotePassword, remotePort); +#endif + if (dialog1.ShowModal() != wxID_OK) + return; + + callsign = dialog1.getCallsign(); + address = dialog1.getAddress(); + + hostname = dialog1.getHostname(); + username = dialog1.getUsername(); + password = dialog1.getPassword(); + + starNetBand1 = dialog1.getStarNetBand1(); + starNetCallsign1 = dialog1.getStarNetCallsign1(); + starNetLogoff1 = dialog1.getStarNetLogoff1(); + starNetInfo1 = dialog1.getStarNetInfo1(); + starNetPermanent1 = dialog1.getStarNetPermanent1(); + starNetUserTimeout1 = dialog1.getStarNetUserTimeout1(); + starNetGroupTimeout1 = dialog1.getStarNetGroupTimeout1(); + starNetCallsignSwitch1 = dialog1.getStarNetCallsignSwitch1(); + starNetTXMsgSwitch1 = dialog1.getStarNetTXMsgSwitch1(); +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + starNetLink1 = dialog1.getStarNetLink1(); +#endif + + starNetBand2 = dialog1.getStarNetBand2(); + starNetCallsign2 = dialog1.getStarNetCallsign2(); + starNetLogoff2 = dialog1.getStarNetLogoff2(); + starNetInfo2 = dialog1.getStarNetInfo2(); + starNetPermanent2 = dialog1.getStarNetPermanent2(); + starNetUserTimeout2 = dialog1.getStarNetUserTimeout2(); + starNetGroupTimeout2 = dialog1.getStarNetGroupTimeout2(); + starNetCallsignSwitch2 = dialog1.getStarNetCallsignSwitch2(); + starNetTXMsgSwitch2 = dialog1.getStarNetTXMsgSwitch2(); +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + starNetLink2 = dialog1.getStarNetLink2(); +#endif + + starNetBand3 = dialog1.getStarNetBand3(); + starNetCallsign3 = dialog1.getStarNetCallsign3(); + starNetLogoff3 = dialog1.getStarNetLogoff3(); + starNetInfo3 = dialog1.getStarNetInfo3(); + starNetPermanent3 = dialog1.getStarNetPermanent3(); + starNetUserTimeout3 = dialog1.getStarNetUserTimeout3(); + starNetGroupTimeout3 = dialog1.getStarNetGroupTimeout3(); + starNetCallsignSwitch3 = dialog1.getStarNetCallsignSwitch3(); + starNetTXMsgSwitch3 = dialog1.getStarNetTXMsgSwitch3(); +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + starNetLink3 = dialog1.getStarNetLink3(); +#endif + + starNetBand4 = dialog1.getStarNetBand4(); + starNetCallsign4 = dialog1.getStarNetCallsign4(); + starNetLogoff4 = dialog1.getStarNetLogoff4(); + starNetInfo4 = dialog1.getStarNetInfo4(); + starNetPermanent4 = dialog1.getStarNetPermanent4(); + starNetUserTimeout4 = dialog1.getStarNetUserTimeout4(); + starNetGroupTimeout4 = dialog1.getStarNetGroupTimeout4(); + starNetCallsignSwitch4 = dialog1.getStarNetCallsignSwitch4(); + starNetTXMsgSwitch4 = dialog1.getStarNetTXMsgSwitch4(); +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + starNetLink4 = dialog1.getStarNetLink4(); +#endif + + starNetBand5 = dialog1.getStarNetBand5(); + starNetCallsign5 = dialog1.getStarNetCallsign5(); + starNetLogoff5 = dialog1.getStarNetLogoff5(); + starNetInfo5 = dialog1.getStarNetInfo5(); + starNetPermanent5 = dialog1.getStarNetPermanent5(); + starNetUserTimeout5 = dialog1.getStarNetUserTimeout5(); + starNetGroupTimeout5 = dialog1.getStarNetGroupTimeout5(); + starNetCallsignSwitch5 = dialog1.getStarNetCallsignSwitch5(); + starNetTXMsgSwitch5 = dialog1.getStarNetTXMsgSwitch5(); +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + starNetLink5 = dialog1.getStarNetLink5(); +#endif + + starNetBand6 = dialog1.getStarNetBand6(); + starNetCallsign6 = dialog1.getStarNetCallsign6(); + starNetLogoff6 = dialog1.getStarNetLogoff6(); + starNetInfo6 = dialog1.getStarNetInfo6(); + starNetPermanent6 = dialog1.getStarNetPermanent6(); + starNetUserTimeout6 = dialog1.getStarNetUserTimeout6(); + starNetGroupTimeout6 = dialog1.getStarNetGroupTimeout6(); + starNetCallsignSwitch6 = dialog1.getStarNetCallsignSwitch6(); + starNetTXMsgSwitch6 = dialog1.getStarNetTXMsgSwitch6(); +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + starNetLink6 = dialog1.getStarNetLink6(); +#endif + + starNetBand7 = dialog1.getStarNetBand7(); + starNetCallsign7 = dialog1.getStarNetCallsign7(); + starNetLogoff7 = dialog1.getStarNetLogoff7(); + starNetInfo7 = dialog1.getStarNetInfo7(); + starNetPermanent7 = dialog1.getStarNetPermanent7(); + starNetUserTimeout7 = dialog1.getStarNetUserTimeout7(); + starNetGroupTimeout7 = dialog1.getStarNetGroupTimeout7(); + starNetCallsignSwitch7 = dialog1.getStarNetCallsignSwitch7(); + starNetTXMsgSwitch7 = dialog1.getStarNetTXMsgSwitch7(); +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + starNetLink7 = dialog1.getStarNetLink7(); +#endif + + starNetBand8 = dialog1.getStarNetBand8(); + starNetCallsign8 = dialog1.getStarNetCallsign8(); + starNetLogoff8 = dialog1.getStarNetLogoff8(); + starNetInfo8 = dialog1.getStarNetInfo8(); + starNetPermanent8 = dialog1.getStarNetPermanent8(); + starNetUserTimeout8 = dialog1.getStarNetUserTimeout8(); + starNetGroupTimeout8 = dialog1.getStarNetGroupTimeout8(); + starNetCallsignSwitch8 = dialog1.getStarNetCallsignSwitch8(); + starNetTXMsgSwitch8 = dialog1.getStarNetTXMsgSwitch8(); +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + starNetLink8 = dialog1.getStarNetLink8(); +#endif + + starNetBand9 = dialog1.getStarNetBand9(); + starNetCallsign9 = dialog1.getStarNetCallsign9(); + starNetLogoff9 = dialog1.getStarNetLogoff9(); + starNetInfo9 = dialog1.getStarNetInfo9(); + starNetPermanent9 = dialog1.getStarNetPermanent9(); + starNetUserTimeout9 = dialog1.getStarNetUserTimeout9(); + starNetGroupTimeout9 = dialog1.getStarNetGroupTimeout9(); + starNetCallsignSwitch9 = dialog1.getStarNetCallsignSwitch9(); + starNetTXMsgSwitch9 = dialog1.getStarNetTXMsgSwitch9(); +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + starNetLink9 = dialog1.getStarNetLink9(); +#endif + + starNetBand10 = dialog1.getStarNetBand10(); + starNetCallsign10 = dialog1.getStarNetCallsign10(); + starNetLogoff10 = dialog1.getStarNetLogoff10(); + starNetInfo10 = dialog1.getStarNetInfo10(); + starNetPermanent10 = dialog1.getStarNetPermanent10(); + starNetUserTimeout10 = dialog1.getStarNetUserTimeout10(); + starNetGroupTimeout10 = dialog1.getStarNetGroupTimeout10(); + starNetCallsignSwitch10 = dialog1.getStarNetCallsignSwitch10(); + starNetTXMsgSwitch10 = dialog1.getStarNetTXMsgSwitch10(); +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + starNetLink10 = dialog1.getStarNetLink10(); +#endif + + starNetBand11 = dialog1.getStarNetBand11(); + starNetCallsign11 = dialog1.getStarNetCallsign11(); + starNetLogoff11 = dialog1.getStarNetLogoff11(); + starNetInfo11 = dialog1.getStarNetInfo11(); + starNetPermanent11 = dialog1.getStarNetPermanent11(); + starNetUserTimeout11 = dialog1.getStarNetUserTimeout11(); + starNetGroupTimeout11 = dialog1.getStarNetGroupTimeout11(); + starNetCallsignSwitch11 = dialog1.getStarNetCallsignSwitch11(); + starNetTXMsgSwitch11 = dialog1.getStarNetTXMsgSwitch11(); +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + starNetLink11 = dialog1.getStarNetLink11(); +#endif + + starNetBand12 = dialog1.getStarNetBand12(); + starNetCallsign12 = dialog1.getStarNetCallsign12(); + starNetLogoff12 = dialog1.getStarNetLogoff12(); + starNetInfo12 = dialog1.getStarNetInfo12(); + starNetPermanent12 = dialog1.getStarNetPermanent12(); + starNetUserTimeout12 = dialog1.getStarNetUserTimeout12(); + starNetGroupTimeout12 = dialog1.getStarNetGroupTimeout12(); + starNetCallsignSwitch12 = dialog1.getStarNetCallsignSwitch12(); + starNetTXMsgSwitch12 = dialog1.getStarNetTXMsgSwitch12(); +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + starNetLink12 = dialog1.getStarNetLink12(); +#endif + + starNetBand13 = dialog1.getStarNetBand13(); + starNetCallsign13 = dialog1.getStarNetCallsign13(); + starNetLogoff13 = dialog1.getStarNetLogoff13(); + starNetInfo13 = dialog1.getStarNetInfo13(); + starNetPermanent13 = dialog1.getStarNetPermanent13(); + starNetUserTimeout13 = dialog1.getStarNetUserTimeout13(); + starNetGroupTimeout13 = dialog1.getStarNetGroupTimeout13(); + starNetCallsignSwitch13 = dialog1.getStarNetCallsignSwitch13(); + starNetTXMsgSwitch13 = dialog1.getStarNetTXMsgSwitch13(); +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + starNetLink13 = dialog1.getStarNetLink13(); +#endif + + starNetBand14 = dialog1.getStarNetBand14(); + starNetCallsign14 = dialog1.getStarNetCallsign14(); + starNetLogoff14 = dialog1.getStarNetLogoff14(); + starNetInfo14 = dialog1.getStarNetInfo14(); + starNetPermanent14 = dialog1.getStarNetPermanent14(); + starNetUserTimeout14 = dialog1.getStarNetUserTimeout14(); + starNetGroupTimeout14 = dialog1.getStarNetGroupTimeout14(); + starNetCallsignSwitch14 = dialog1.getStarNetCallsignSwitch14(); + starNetTXMsgSwitch14 = dialog1.getStarNetTXMsgSwitch14(); +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + starNetLink14 = dialog1.getStarNetLink14(); +#endif + + starNetBand15 = dialog1.getStarNetBand15(); + starNetCallsign15 = dialog1.getStarNetCallsign15(); + starNetLogoff15 = dialog1.getStarNetLogoff15(); + starNetInfo15 = dialog1.getStarNetInfo15(); + starNetPermanent15 = dialog1.getStarNetPermanent15(); + starNetUserTimeout15 = dialog1.getStarNetUserTimeout15(); + starNetGroupTimeout15 = dialog1.getStarNetGroupTimeout15(); + starNetCallsignSwitch15 = dialog1.getStarNetCallsignSwitch15(); + starNetTXMsgSwitch15 = dialog1.getStarNetTXMsgSwitch15(); +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + starNetLink15 = dialog1.getStarNetLink15(); +#endif + + remoteEnabled = dialog1.getRemoteEnabled(); + remotePassword = dialog1.getRemotePassword(); + remotePort = dialog1.getRemotePort(); + + logEnabled = dialog1.getLogEnabled(); + + ::wxGetApp().setGateway(callsign, address); + ::wxGetApp().setIrcDDB(hostname, username, password); +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + ::wxGetApp().setStarNet1(starNetBand1, starNetCallsign1, starNetLogoff1, starNetInfo1, starNetPermanent1, starNetUserTimeout1, starNetGroupTimeout1, starNetCallsignSwitch1, starNetTXMsgSwitch1, starNetLink1); + ::wxGetApp().setStarNet2(starNetBand2, starNetCallsign2, starNetLogoff2, starNetInfo2, starNetPermanent2, starNetUserTimeout2, starNetGroupTimeout2, starNetCallsignSwitch2, starNetTXMsgSwitch2, starNetLink2); + ::wxGetApp().setStarNet3(starNetBand3, starNetCallsign3, starNetLogoff3, starNetInfo3, starNetPermanent3, starNetUserTimeout3, starNetGroupTimeout3, starNetCallsignSwitch3, starNetTXMsgSwitch3, starNetLink3); + ::wxGetApp().setStarNet4(starNetBand4, starNetCallsign4, starNetLogoff4, starNetInfo4, starNetPermanent4, starNetUserTimeout4, starNetGroupTimeout4, starNetCallsignSwitch4, starNetTXMsgSwitch4, starNetLink4); + ::wxGetApp().setStarNet5(starNetBand5, starNetCallsign5, starNetLogoff5, starNetInfo5, starNetPermanent5, starNetUserTimeout5, starNetGroupTimeout5, starNetCallsignSwitch5, starNetTXMsgSwitch5, starNetLink5); + ::wxGetApp().setStarNet6(starNetBand6, starNetCallsign6, starNetLogoff6, starNetInfo6, starNetPermanent6, starNetUserTimeout6, starNetGroupTimeout6, starNetCallsignSwitch6, starNetTXMsgSwitch6, starNetLink6); + ::wxGetApp().setStarNet7(starNetBand7, starNetCallsign7, starNetLogoff7, starNetInfo7, starNetPermanent7, starNetUserTimeout7, starNetGroupTimeout7, starNetCallsignSwitch7, starNetTXMsgSwitch7, starNetLink7); + ::wxGetApp().setStarNet8(starNetBand8, starNetCallsign8, starNetLogoff8, starNetInfo8, starNetPermanent8, starNetUserTimeout8, starNetGroupTimeout8, starNetCallsignSwitch8, starNetTXMsgSwitch8, starNetLink8); + ::wxGetApp().setStarNet9(starNetBand9, starNetCallsign9, starNetLogoff9, starNetInfo9, starNetPermanent9, starNetUserTimeout9, starNetGroupTimeout9, starNetCallsignSwitch9, starNetTXMsgSwitch9, starNetLink9); + ::wxGetApp().setStarNet10(starNetBand10, starNetCallsign10, starNetLogoff10, starNetInfo10, starNetPermanent10, starNetUserTimeout10, starNetGroupTimeout10, starNetCallsignSwitch10, starNetTXMsgSwitch10, starNetLink10); + ::wxGetApp().setStarNet11(starNetBand11, starNetCallsign11, starNetLogoff11, starNetInfo11, starNetPermanent11, starNetUserTimeout11, starNetGroupTimeout11, starNetCallsignSwitch11, starNetTXMsgSwitch11, starNetLink11); + ::wxGetApp().setStarNet12(starNetBand12, starNetCallsign12, starNetLogoff12, starNetInfo12, starNetPermanent12, starNetUserTimeout12, starNetGroupTimeout12, starNetCallsignSwitch12, starNetTXMsgSwitch12, starNetLink12); + ::wxGetApp().setStarNet13(starNetBand13, starNetCallsign13, starNetLogoff13, starNetInfo13, starNetPermanent13, starNetUserTimeout13, starNetGroupTimeout13, starNetCallsignSwitch13, starNetTXMsgSwitch13, starNetLink13); + ::wxGetApp().setStarNet14(starNetBand14, starNetCallsign14, starNetLogoff14, starNetInfo14, starNetPermanent14, starNetUserTimeout14, starNetGroupTimeout14, starNetCallsignSwitch14, starNetTXMsgSwitch14, starNetLink14); + ::wxGetApp().setStarNet15(starNetBand15, starNetCallsign15, starNetLogoff15, starNetInfo15, starNetPermanent15, starNetUserTimeout15, starNetGroupTimeout15, starNetCallsignSwitch15, starNetTXMsgSwitch15, starNetLink15); +#else + ::wxGetApp().setStarNet1(starNetBand1, starNetCallsign1, starNetLogoff1, starNetInfo1, starNetPermanent1, starNetUserTimeout1, starNetGroupTimeout1, starNetCallsignSwitch1, starNetTXMsgSwitch1); + ::wxGetApp().setStarNet2(starNetBand2, starNetCallsign2, starNetLogoff2, starNetInfo2, starNetPermanent2, starNetUserTimeout2, starNetGroupTimeout2, starNetCallsignSwitch2, starNetTXMsgSwitch2); + ::wxGetApp().setStarNet3(starNetBand3, starNetCallsign3, starNetLogoff3, starNetInfo3, starNetPermanent3, starNetUserTimeout3, starNetGroupTimeout3, starNetCallsignSwitch3, starNetTXMsgSwitch3); + ::wxGetApp().setStarNet4(starNetBand4, starNetCallsign4, starNetLogoff4, starNetInfo4, starNetPermanent4, starNetUserTimeout4, starNetGroupTimeout4, starNetCallsignSwitch4, starNetTXMsgSwitch4); + ::wxGetApp().setStarNet5(starNetBand5, starNetCallsign5, starNetLogoff5, starNetInfo5, starNetPermanent5, starNetUserTimeout5, starNetGroupTimeout5, starNetCallsignSwitch5, starNetTXMsgSwitch5); + ::wxGetApp().setStarNet6(starNetBand6, starNetCallsign6, starNetLogoff6, starNetInfo6, starNetPermanent6, starNetUserTimeout6, starNetGroupTimeout6, starNetCallsignSwitch6, starNetTXMsgSwitch6); + ::wxGetApp().setStarNet7(starNetBand7, starNetCallsign7, starNetLogoff7, starNetInfo7, starNetPermanent7, starNetUserTimeout7, starNetGroupTimeout7, starNetCallsignSwitch7, starNetTXMsgSwitch7); + ::wxGetApp().setStarNet8(starNetBand8, starNetCallsign8, starNetLogoff8, starNetInfo8, starNetPermanent8, starNetUserTimeout8, starNetGroupTimeout8, starNetCallsignSwitch8, starNetTXMsgSwitch8); + ::wxGetApp().setStarNet9(starNetBand9, starNetCallsign9, starNetLogoff9, starNetInfo9, starNetPermanent9, starNetUserTimeout9, starNetGroupTimeout9, starNetCallsignSwitch9, starNetTXMsgSwitch9); + ::wxGetApp().setStarNet10(starNetBand10, starNetCallsign10, starNetLogoff10, starNetInfo10, starNetPermanent10, starNetUserTimeout10, starNetGroupTimeout10, starNetCallsignSwitch10, starNetTXMsgSwitch10); + ::wxGetApp().setStarNet11(starNetBand11, starNetCallsign11, starNetLogoff11, starNetInfo11, starNetPermanent11, starNetUserTimeout11, starNetGroupTimeout11, starNetCallsignSwitch11, starNetTXMsgSwitch11); + ::wxGetApp().setStarNet12(starNetBand12, starNetCallsign12, starNetLogoff12, starNetInfo12, starNetPermanent12, starNetUserTimeout12, starNetGroupTimeout12, starNetCallsignSwitch12, starNetTXMsgSwitch12); + ::wxGetApp().setStarNet13(starNetBand13, starNetCallsign13, starNetLogoff13, starNetInfo13, starNetPermanent13, starNetUserTimeout13, starNetGroupTimeout13, starNetCallsignSwitch13, starNetTXMsgSwitch13); + ::wxGetApp().setStarNet14(starNetBand14, starNetCallsign14, starNetLogoff14, starNetInfo14, starNetPermanent14, starNetUserTimeout14, starNetGroupTimeout14, starNetCallsignSwitch14, starNetTXMsgSwitch14); + ::wxGetApp().setStarNet15(starNetBand15, starNetCallsign15, starNetLogoff15, starNetInfo15, starNetPermanent15, starNetUserTimeout15, starNetGroupTimeout15, starNetCallsignSwitch15, starNetTXMsgSwitch15); +#endif + ::wxGetApp().setRemote(remoteEnabled, remotePassword, remotePort); + ::wxGetApp().setMiscellaneous(logEnabled); + ::wxGetApp().writeConfig(); + + wxMessageDialog dialog2(this, _("The changes made will not take effect\nuntil the application is restarted"), _("StarNET Server Information"), wxICON_INFORMATION); + dialog2.ShowModal(); +} + +void CStarNetServerFrame::onUpdates(wxCommandEvent& event) +{ + m_updates = event.IsChecked(); +} + +void CStarNetServerFrame::onAbout(wxCommandEvent&) +{ + wxAboutDialogInfo info; + info.AddDeveloper(wxT("Jonathan Naylor, G4KLX")); + info.AddDeveloper(wxT("Michael Dirska, DL1BFF")); + info.SetCopyright(wxT("(C) 2011-2015 using GPL v2 or later")); + info.SetName(APPLICATION_NAME); + info.SetVersion(VERSION); + info.SetDescription(_("This program allows an Internet connected computer \nto become a StarNet Digital Server.")); + + ::wxAboutBox(info); +} + +void CStarNetServerFrame::onLog(wxEvent& event) +{ + CLogEvent& logEvent = dynamic_cast(event); + + wxString text; + + text = m_logLine[1U]->GetLabel(); + m_logLine[0U]->SetLabel(text); + + text = m_logLine[2U]->GetLabel(); + m_logLine[1U]->SetLabel(text); + + text = m_logLine[3U]->GetLabel(); + m_logLine[2U]->SetLabel(text); + + text = m_logLine[4U]->GetLabel(); + m_logLine[3U]->SetLabel(text); + + text = m_logLine[5U]->GetLabel(); + m_logLine[4U]->SetLabel(text); + + text = m_logLine[6U]->GetLabel(); + m_logLine[5U]->SetLabel(text); + + text = m_logLine[7U]->GetLabel(); + m_logLine[6U]->SetLabel(text); + + text = m_logLine[8U]->GetLabel(); + m_logLine[7U]->SetLabel(text); + + text = m_logLine[9U]->GetLabel(); + m_logLine[8U]->SetLabel(text); + + text = m_logLine[10U]->GetLabel(); + m_logLine[9U]->SetLabel(text); + + text = m_logLine[11U]->GetLabel(); + m_logLine[10U]->SetLabel(text); + + text = m_logLine[12U]->GetLabel(); + m_logLine[11U]->SetLabel(text); + + text = m_logLine[13U]->GetLabel(); + m_logLine[12U]->SetLabel(text); + + text = m_logLine[14U]->GetLabel(); + m_logLine[13U]->SetLabel(text); + + text = m_logLine[15U]->GetLabel(); + m_logLine[14U]->SetLabel(text); + + text = m_logLine[16U]->GetLabel(); + m_logLine[15U]->SetLabel(text); + + text = m_logLine[17U]->GetLabel(); + m_logLine[16U]->SetLabel(text); + + text = m_logLine[18U]->GetLabel(); + m_logLine[17U]->SetLabel(text); + + text = m_logLine[19U]->GetLabel(); + m_logLine[18U]->SetLabel(text); + + text = logEvent.getText(); + m_logLine[19U]->SetLabel(text); +} + +void CStarNetServerFrame::showLog(const wxString& text) +{ + if (!m_updates) + return; + + CLogEvent event(text, LOG_EVENT); + + AddPendingEvent(event); +} diff --git a/StarNetServer/StarNetServerFrame.h b/StarNetServer/StarNetServerFrame.h new file mode 100644 index 0000000..9561190 --- /dev/null +++ b/StarNetServer/StarNetServerFrame.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2010,2011,2012 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef StarNetServerFrame_H +#define StarNetServerFrame_H + +#include "Defs.h" + +#include +#include + +class CStarNetServerFrame : public wxFrame { +public: + CStarNetServerFrame(const wxString& title, const wxPoint& position, bool gui); + virtual ~CStarNetServerFrame(); + + virtual void onQuit(wxCommandEvent& event); + virtual void onPreferences(wxCommandEvent& event); + virtual void onUpdates(wxCommandEvent& event); + virtual void onAbout(wxCommandEvent& event); + virtual void onClose(wxCloseEvent& event); + virtual void onLog(wxEvent& event); + + virtual void showLog(const wxString& text); + +private: + wxStaticText* m_logLine[20]; + bool m_updates; + + DECLARE_EVENT_TABLE() + + wxMenuBar* createMenuBar(); +}; + +#endif diff --git a/StarNetServer/StarNetServerIrcDDBSet.cpp b/StarNetServer/StarNetServerIrcDDBSet.cpp new file mode 100644 index 0000000..f4f9b25 --- /dev/null +++ b/StarNetServer/StarNetServerIrcDDBSet.cpp @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2010,2012,2013,2014 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "StarNetServerIrcDDBSet.h" + +const unsigned int BORDER_SIZE = 5U; +const unsigned int CONTROL_WIDTH1 = 200U; +const unsigned int CONTROL_WIDTH2 = 80U; + +const unsigned int PORT_LENGTH = 5U; + +CStarNetServerIrcDDBSet::CStarNetServerIrcDDBSet(wxWindow* parent, int id, const wxString& title, const wxString& hostname, const wxString& username, const wxString& password) : +wxPanel(parent, id), +m_title(title), +m_hostname(NULL), +m_username(NULL), +m_password(NULL) +{ + wxFlexGridSizer* sizer = new wxFlexGridSizer(2); + + wxStaticText* hostnameLabel = new wxStaticText(this, -1, _("Hostname")); + sizer->Add(hostnameLabel, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + + m_hostname = new wxChoice(this, -1, wxDefaultPosition, wxSize(CONTROL_WIDTH1, -1)); + m_hostname->Append(wxT("group1-irc.ircddb.net")); + m_hostname->Append(wxT("group2-irc.ircddb.net")); + m_hostname->Append(wxT("irc1.openquad.net")); + m_hostname->Append(wxT("irc2.openquad.net")); + m_hostname->Append(wxT("irc3.openquad.net")); + m_hostname->Append(wxT("irc4.openquad.net")); + m_hostname->Append(wxT("irc5.openquad.net")); + m_hostname->Append(wxT("irc6.openquad.net")); + m_hostname->Append(wxT("server1-ik2xyp.free-dstar.org")); + m_hostname->Append(wxT("ircddb.dstar.su")); + sizer->Add(m_hostname, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + m_hostname->SetStringSelection(hostname); + + wxStaticText* usernameLabel = new wxStaticText(this, -1, _("Username")); + sizer->Add(usernameLabel, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + + m_username = new wxTextCtrl(this, -1, username, wxDefaultPosition, wxSize(CONTROL_WIDTH2, -1)); + sizer->Add(m_username, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + + wxStaticText* passwordLabel = new wxStaticText(this, -1, _("Password")); + sizer->Add(passwordLabel, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + + m_password = new wxTextCtrl(this, -1, password, wxDefaultPosition, wxSize(CONTROL_WIDTH1, -1), wxTE_PASSWORD); + sizer->Add(m_password, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + + SetAutoLayout(true); + + SetSizer(sizer); +} + + +CStarNetServerIrcDDBSet::~CStarNetServerIrcDDBSet() +{ +} + +bool CStarNetServerIrcDDBSet::Validate() +{ + bool res = getHostname().IsEmpty(); + if (res) { + wxMessageDialog dialog(this, _("The Hostname may not be empty"), m_title + _(" Error"), wxICON_ERROR); + dialog.ShowModal(); + return false; + } + + res = getUsername().IsEmpty(); + if (res) { + wxMessageDialog dialog(this, _("The Username may not be empty"), m_title + _(" Error"), wxICON_ERROR); + dialog.ShowModal(); + return false; + } + + return true; +} + +wxString CStarNetServerIrcDDBSet::getHostname() const +{ + return m_hostname->GetStringSelection(); +} + +wxString CStarNetServerIrcDDBSet::getUsername() const +{ + return m_username->GetValue(); +} + +wxString CStarNetServerIrcDDBSet::getPassword() const +{ + return m_password->GetValue(); +} diff --git a/StarNetServer/StarNetServerIrcDDBSet.h b/StarNetServer/StarNetServerIrcDDBSet.h new file mode 100644 index 0000000..8eba83e --- /dev/null +++ b/StarNetServer/StarNetServerIrcDDBSet.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2010,2012,2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef StarNetServerIrcDDBSet_H +#define StarNetServerIrcDDBSet_H + +#include + +class CStarNetServerIrcDDBSet : public wxPanel { +public: + CStarNetServerIrcDDBSet(wxWindow* parent, int id, const wxString& title, const wxString& hostname, const wxString& username, const wxString& password); + virtual ~CStarNetServerIrcDDBSet(); + + virtual bool Validate(); + + virtual wxString getHostname() const; + virtual wxString getUsername() const; + virtual wxString getPassword() const; + +private: + wxString m_title; + wxChoice* m_hostname; + wxTextCtrl* m_username; + wxTextCtrl* m_password; +}; + +#endif diff --git a/StarNetServer/StarNetServerLogRedirect.cpp b/StarNetServer/StarNetServerLogRedirect.cpp new file mode 100644 index 0000000..800c485 --- /dev/null +++ b/StarNetServer/StarNetServerLogRedirect.cpp @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2002,2003,2009-2013,2018 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "StarNetServerLogRedirect.h" +#include "StarNetServerApp.h" + +CStarNetServerLogRedirect::CStarNetServerLogRedirect() : +wxLog() +{ +} + +CStarNetServerLogRedirect::~CStarNetServerLogRedirect() +{ +} + +void CStarNetServerLogRedirect::DoLogRecord(wxLogLevel level, const wxString& msg, const wxLogRecordInfo& info) +{ + wxString letter; + + switch (level) { + case wxLOG_FatalError: letter = wxT("F"); break; + case wxLOG_Error: letter = wxT("E"); break; + case wxLOG_Warning: letter = wxT("W"); break; + case wxLOG_Info: letter = wxT("I"); break; + case wxLOG_Message: letter = wxT("M"); break; + case wxLOG_Status: letter = wxT("M"); break; + case wxLOG_Trace: letter = wxT("T"); break; + case wxLOG_Debug: letter = wxT("D"); break; + default: letter = wxT("U"); break; + } + + struct tm* tm = ::gmtime(&info.timestamp); + + wxString message; + message.Printf(wxT("%s: %04d-%02d-%02d %02d:%02d:%02d: %s\n"), letter.c_str(), tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, msg.c_str()); + + ::wxGetApp().showLog(message); + + if (level == wxLOG_FatalError) + ::abort(); +} diff --git a/StarNetServer/StarNetServerLogRedirect.h b/StarNetServer/StarNetServerLogRedirect.h new file mode 100644 index 0000000..753d3b4 --- /dev/null +++ b/StarNetServer/StarNetServerLogRedirect.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2002,2003,2009-2011,2018 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef StarNetServerLogRedirect_H +#define StarNetServerLogRedirect_H + +#include +#include + +class CStarNetServerLogRedirect : public wxLog { +public: + CStarNetServerLogRedirect(); + virtual ~CStarNetServerLogRedirect(); + + virtual void DoLogRecord(wxLogLevel level, const wxString& msg, const wxLogRecordInfo& info); + +private: +}; + +#endif diff --git a/StarNetServer/StarNetServerMiscellaneousSet.cpp b/StarNetServer/StarNetServerMiscellaneousSet.cpp new file mode 100644 index 0000000..8ea7bc5 --- /dev/null +++ b/StarNetServer/StarNetServerMiscellaneousSet.cpp @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2010,2011 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "StarNetServerMiscellaneousSet.h" +#include "DStarDefines.h" + +const unsigned int CONTROL_WIDTH = 130U; + +const unsigned int BORDER_SIZE = 5U; + +CStarNetServerMiscellaneousSet::CStarNetServerMiscellaneousSet(wxWindow* parent, int id, const wxString& title, bool logEnabled) : +wxPanel(parent, id), +m_title(title), +m_logEnabled(NULL) +{ + wxFlexGridSizer* sizer = new wxFlexGridSizer(2); + + wxStaticText* logEnabledLabel = new wxStaticText(this, -1, _("GUI Log")); + sizer->Add(logEnabledLabel, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + m_logEnabled = new wxChoice(this, -1, wxDefaultPosition, wxSize(CONTROL_WIDTH, -1)); + m_logEnabled->Append(_("Disabled")); + m_logEnabled->Append(_("Enabled")); + sizer->Add(m_logEnabled, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + m_logEnabled->SetSelection(logEnabled ? 1 : 0); + + SetAutoLayout(true); + + SetSizer(sizer); +} + + +CStarNetServerMiscellaneousSet::~CStarNetServerMiscellaneousSet() +{ +} + +bool CStarNetServerMiscellaneousSet::Validate() +{ + return m_logEnabled->GetCurrentSelection() != wxNOT_FOUND; +} + +bool CStarNetServerMiscellaneousSet::getLogEnabled() const +{ + int c = m_logEnabled->GetCurrentSelection(); + if (c == wxNOT_FOUND) + return false; + + return c == 1; +} diff --git a/StarNetServer/StarNetServerMiscellaneousSet.h b/StarNetServer/StarNetServerMiscellaneousSet.h new file mode 100644 index 0000000..ea72977 --- /dev/null +++ b/StarNetServer/StarNetServerMiscellaneousSet.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2010,2011 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef StarNetServerMiscellaneousSet_H +#define StarNetServerMiscellaneousSet_H + +#include "Defs.h" + +#include + +class CStarNetServerMiscellaneousSet : public wxPanel { +public: + CStarNetServerMiscellaneousSet(wxWindow* parent, int id, const wxString& title, bool logEnabled); + virtual ~CStarNetServerMiscellaneousSet(); + + virtual bool Validate(); + + virtual bool getLogEnabled() const; + +private: + wxString m_title; + wxChoice* m_logEnabled; +}; + +#endif diff --git a/StarNetServer/StarNetServerPreferences.cpp b/StarNetServer/StarNetServerPreferences.cpp new file mode 100644 index 0000000..bede7ec --- /dev/null +++ b/StarNetServer/StarNetServerPreferences.cpp @@ -0,0 +1,1091 @@ +/* + * Copyright (C) 2010,2011,2012,2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "StarNetServerPreferences.h" +#include "StarNetServerDefs.h" + +const unsigned int BORDER_SIZE = 5U; + +CStarNetServerPreferences::CStarNetServerPreferences(wxWindow* parent, int id, + const wxString& callsign, const wxString& address, + const wxString& hostname, const wxString& username, + const wxString& password, + bool logEnabled, +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + const wxString& starNetBand1, const wxString& callsign1, const wxString& logoff1, const wxString& info1, const wxString& permanent1, unsigned int userTimeout1, unsigned int groupTimeout1, STARNET_CALLSIGN_SWITCH callsignSwitch1, bool txMsgSwitch1, const wxString& link1, + const wxString& starNetBand2, const wxString& callsign2, const wxString& logoff2, const wxString& info2, const wxString& permanent2, unsigned int userTimeout2, unsigned int groupTimeout2, STARNET_CALLSIGN_SWITCH callsignSwitch2, bool txMsgSwitch2, const wxString& link2, + const wxString& starNetBand3, const wxString& callsign3, const wxString& logoff3, const wxString& info3, const wxString& permanent3, unsigned int userTimeout3, unsigned int groupTimeout3, STARNET_CALLSIGN_SWITCH callsignSwitch3, bool txMsgSwitch3, const wxString& link3, + const wxString& starNetBand4, const wxString& callsign4, const wxString& logoff4, const wxString& info4, const wxString& permanent4, unsigned int userTimeout4, unsigned int groupTimeout4, STARNET_CALLSIGN_SWITCH callsignSwitch4, bool txMsgSwitch4, const wxString& link4, + const wxString& starNetBand5, const wxString& callsign5, const wxString& logoff5, const wxString& info5, const wxString& permanent5, unsigned int userTimeout5, unsigned int groupTimeout5, STARNET_CALLSIGN_SWITCH callsignSwitch5, bool txMsgSwitch5, const wxString& link5, + const wxString& starNetBand6, const wxString& callsign6, const wxString& logoff6, const wxString& info6, const wxString& permanent6, unsigned int userTimeout6, unsigned int groupTimeout6, STARNET_CALLSIGN_SWITCH callsignSwitch6, bool txMsgSwitch6, const wxString& link6, + const wxString& starNetBand7, const wxString& callsign7, const wxString& logoff7, const wxString& info7, const wxString& permanent7, unsigned int userTimeout7, unsigned int groupTimeout7, STARNET_CALLSIGN_SWITCH callsignSwitch7, bool txMsgSwitch7, const wxString& link7, + const wxString& starNetBand8, const wxString& callsign8, const wxString& logoff8, const wxString& info8, const wxString& permanent8, unsigned int userTimeout8, unsigned int groupTimeout8, STARNET_CALLSIGN_SWITCH callsignSwitch8, bool txMsgSwitch8, const wxString& link8, + const wxString& starNetBand9, const wxString& callsign9, const wxString& logoff9, const wxString& info9, const wxString& permanent9, unsigned int userTimeout9, unsigned int groupTimeout9, STARNET_CALLSIGN_SWITCH callsignSwitch9, bool txMsgSwitch9, const wxString& link9, + const wxString& starNetBand10, const wxString& callsign10, const wxString& logoff10, const wxString& info10, const wxString& permanent10, unsigned int userTimeout10, unsigned int groupTimeout10, STARNET_CALLSIGN_SWITCH callsignSwitch10, bool txMsgSwitch10, const wxString& link10, + const wxString& starNetBand11, const wxString& callsign11, const wxString& logoff11, const wxString& info11, const wxString& permanent11, unsigned int userTimeout11, unsigned int groupTimeout11, STARNET_CALLSIGN_SWITCH callsignSwitch11, bool txMsgSwitch11, const wxString& link11, + const wxString& starNetBand12, const wxString& callsign12, const wxString& logoff12, const wxString& info12, const wxString& permanent12, unsigned int userTimeout12, unsigned int groupTimeout12, STARNET_CALLSIGN_SWITCH callsignSwitch12, bool txMsgSwitch12, const wxString& link12, + const wxString& starNetBand13, const wxString& callsign13, const wxString& logoff13, const wxString& info13, const wxString& permanent13, unsigned int userTimeout13, unsigned int groupTimeout13, STARNET_CALLSIGN_SWITCH callsignSwitch13, bool txMsgSwitch13, const wxString& link13, + const wxString& starNetBand14, const wxString& callsign14, const wxString& logoff14, const wxString& info14, const wxString& permanent14, unsigned int userTimeout14, unsigned int groupTimeout14, STARNET_CALLSIGN_SWITCH callsignSwitch14, bool txMsgSwitch14, const wxString& link14, + const wxString& starNetBand15, const wxString& callsign15, const wxString& logoff15, const wxString& info15, const wxString& permanent15, unsigned int userTimeout15, unsigned int groupTimeout15, STARNET_CALLSIGN_SWITCH callsignSwitch15, bool txMsgSwitch15, const wxString& link15, +#else + const wxString& starNetBand1, const wxString& callsign1, const wxString& logoff1, const wxString& info1, const wxString& permanent1, unsigned int userTimeout1, unsigned int groupTimeout1, STARNET_CALLSIGN_SWITCH callsignSwitch1, bool txMsgSwitch1, + const wxString& starNetBand2, const wxString& callsign2, const wxString& logoff2, const wxString& info2, const wxString& permanent2, unsigned int userTimeout2, unsigned int groupTimeout2, STARNET_CALLSIGN_SWITCH callsignSwitch2, bool txMsgSwitch2, + const wxString& starNetBand3, const wxString& callsign3, const wxString& logoff3, const wxString& info3, const wxString& permanent3, unsigned int userTimeout3, unsigned int groupTimeout3, STARNET_CALLSIGN_SWITCH callsignSwitch3, bool txMsgSwitch3, + const wxString& starNetBand4, const wxString& callsign4, const wxString& logoff4, const wxString& info4, const wxString& permanent4, unsigned int userTimeout4, unsigned int groupTimeout4, STARNET_CALLSIGN_SWITCH callsignSwitch4, bool txMsgSwitch4, + const wxString& starNetBand5, const wxString& callsign5, const wxString& logoff5, const wxString& info5, const wxString& permanent5, unsigned int userTimeout5, unsigned int groupTimeout5, STARNET_CALLSIGN_SWITCH callsignSwitch5, bool txMsgSwitch5, + const wxString& starNetBand6, const wxString& callsign6, const wxString& logoff6, const wxString& info6, const wxString& permanent6, unsigned int userTimeout6, unsigned int groupTimeout6, STARNET_CALLSIGN_SWITCH callsignSwitch6, bool txMsgSwitch6, + const wxString& starNetBand7, const wxString& callsign7, const wxString& logoff7, const wxString& info7, const wxString& permanent7, unsigned int userTimeout7, unsigned int groupTimeout7, STARNET_CALLSIGN_SWITCH callsignSwitch7, bool txMsgSwitch7, + const wxString& starNetBand8, const wxString& callsign8, const wxString& logoff8, const wxString& info8, const wxString& permanent8, unsigned int userTimeout8, unsigned int groupTimeout8, STARNET_CALLSIGN_SWITCH callsignSwitch8, bool txMsgSwitch8, + const wxString& starNetBand9, const wxString& callsign9, const wxString& logoff9, const wxString& info9, const wxString& permanent9, unsigned int userTimeout9, unsigned int groupTimeout9, STARNET_CALLSIGN_SWITCH callsignSwitch9, bool txMsgSwitch9, + const wxString& starNetBand10, const wxString& callsign10, const wxString& logoff10, const wxString& info10, const wxString& permanent10, unsigned int userTimeout10, unsigned int groupTimeout10, STARNET_CALLSIGN_SWITCH callsignSwitch10, bool txMsgSwitch10, + const wxString& starNetBand11, const wxString& callsign11, const wxString& logoff11, const wxString& info11, const wxString& permanent11, unsigned int userTimeout11, unsigned int groupTimeout11, STARNET_CALLSIGN_SWITCH callsignSwitch11, bool txMsgSwitch11, + const wxString& starNetBand12, const wxString& callsign12, const wxString& logoff12, const wxString& info12, const wxString& permanent12, unsigned int userTimeout12, unsigned int groupTimeout12, STARNET_CALLSIGN_SWITCH callsignSwitch12, bool txMsgSwitch12, + const wxString& starNetBand13, const wxString& callsign13, const wxString& logoff13, const wxString& info13, const wxString& permanent13, unsigned int userTimeout13, unsigned int groupTimeout13, STARNET_CALLSIGN_SWITCH callsignSwitch13, bool txMsgSwitch13, + const wxString& starNetBand14, const wxString& callsign14, const wxString& logoff14, const wxString& info14, const wxString& permanent14, unsigned int userTimeout14, unsigned int groupTimeout14, STARNET_CALLSIGN_SWITCH callsignSwitch14, bool txMsgSwitch14, + const wxString& starNetBand15, const wxString& callsign15, const wxString& logoff15, const wxString& info15, const wxString& permanent15, unsigned int userTimeout15, unsigned int groupTimeout15, STARNET_CALLSIGN_SWITCH callsignSwitch15, bool txMsgSwitch15, +#endif + bool remoteEnabled, const wxString& remotePassword, unsigned int remotePort) : +wxDialog(parent, id, wxString(_("StarNet Server Preferences"))), +m_callsign(NULL), +m_ircDDB(NULL), +m_starNet1(NULL), +m_starNet2(NULL), +m_starNet3(NULL), +m_starNet4(NULL), +m_starNet5(NULL), +m_starNet6(NULL), +m_starNet7(NULL), +m_starNet8(NULL), +m_starNet9(NULL), +m_starNet10(NULL), +m_starNet11(NULL), +m_starNet12(NULL), +m_starNet13(NULL), +m_starNet14(NULL), +m_starNet15(NULL), +m_remote(NULL), +m_miscellaneous(NULL) +{ + wxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL); + + wxNotebook* noteBook = new wxNotebook(this, -1); + + m_callsign = new CStarNetServerCallsignSet(noteBook, -1, APPLICATION_NAME, callsign, address); + noteBook->AddPage(m_callsign, _("Callsign"), true); + + m_ircDDB = new CStarNetServerIrcDDBSet(noteBook, -1, APPLICATION_NAME, hostname, username, password); + noteBook->AddPage(m_ircDDB, wxT("ircDDB"), false); + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + m_starNet1 = new CStarNetSet(noteBook, -1, APPLICATION_NAME, starNetBand1, callsign1, logoff1, info1, permanent1, userTimeout1, groupTimeout1, callsignSwitch1, txMsgSwitch1, link1); + noteBook->AddPage(m_starNet1, wxT("StarNet 1"), false); + + m_starNet2 = new CStarNetSet(noteBook, -1, APPLICATION_NAME, starNetBand2, callsign2, logoff2, info2, permanent2, userTimeout2, groupTimeout2, callsignSwitch2, txMsgSwitch2, link2); + noteBook->AddPage(m_starNet2, wxT("StarNet 2"), false); + + m_starNet3 = new CStarNetSet(noteBook, -1, APPLICATION_NAME, starNetBand3, callsign3, logoff3, info3, permanent3, userTimeout3, groupTimeout3, callsignSwitch3, txMsgSwitch3, link3); + noteBook->AddPage(m_starNet3, wxT("StarNet 3"), false); + + m_starNet4 = new CStarNetSet(noteBook, -1, APPLICATION_NAME, starNetBand4, callsign4, logoff4, info4, permanent4, userTimeout4, groupTimeout4, callsignSwitch4, txMsgSwitch4, link4); + noteBook->AddPage(m_starNet4, wxT("StarNet 4"), false); + + m_starNet5 = new CStarNetSet(noteBook, -1, APPLICATION_NAME, starNetBand5, callsign5, logoff5, info5, permanent5, userTimeout5, groupTimeout5, callsignSwitch5, txMsgSwitch5, link5); + noteBook->AddPage(m_starNet5, wxT("StarNet 5"), false); + + m_starNet6 = new CStarNetSet(noteBook, -1, APPLICATION_NAME, starNetBand6, callsign6, logoff6, info6, permanent6, userTimeout6, groupTimeout6, callsignSwitch6, txMsgSwitch6, link6); + noteBook->AddPage(m_starNet6, wxT("StarNet 6"), false); + + m_starNet7 = new CStarNetSet(noteBook, -1, APPLICATION_NAME, starNetBand7, callsign7, logoff7, info7, permanent7, userTimeout7, groupTimeout7, callsignSwitch7, txMsgSwitch7, link7); + noteBook->AddPage(m_starNet7, wxT("StarNet 7"), false); + + m_starNet8 = new CStarNetSet(noteBook, -1, APPLICATION_NAME, starNetBand8, callsign8, logoff8, info8, permanent8, userTimeout8, groupTimeout8, callsignSwitch8, txMsgSwitch8, link8); + noteBook->AddPage(m_starNet8, wxT("StarNet 8"), false); + + m_starNet9 = new CStarNetSet(noteBook, -1, APPLICATION_NAME, starNetBand9, callsign9, logoff9, info9, permanent9, userTimeout9, groupTimeout9, callsignSwitch9, txMsgSwitch9, link9); + noteBook->AddPage(m_starNet9, wxT("StarNet 9"), false); + + m_starNet10 = new CStarNetSet(noteBook, -1, APPLICATION_NAME, starNetBand10, callsign10, logoff10, info10, permanent10, userTimeout10, groupTimeout10, callsignSwitch10, txMsgSwitch10, link10); + noteBook->AddPage(m_starNet10, wxT("StarNet 10"), false); + + m_starNet11 = new CStarNetSet(noteBook, -1, APPLICATION_NAME, starNetBand11, callsign11, logoff11, info11, permanent11, userTimeout11, groupTimeout11, callsignSwitch11, txMsgSwitch11, link11); + noteBook->AddPage(m_starNet11, wxT("StarNet 11"), false); + + m_starNet12 = new CStarNetSet(noteBook, -1, APPLICATION_NAME, starNetBand12, callsign12, logoff12, info12, permanent12, userTimeout12, groupTimeout12, callsignSwitch12, txMsgSwitch12, link12); + noteBook->AddPage(m_starNet12, wxT("StarNet 12"), false); + + m_starNet13 = new CStarNetSet(noteBook, -1, APPLICATION_NAME, starNetBand13, callsign13, logoff13, info13, permanent13, userTimeout13, groupTimeout13, callsignSwitch13, txMsgSwitch13, link13); + noteBook->AddPage(m_starNet13, wxT("StarNet 13"), false); + + m_starNet14 = new CStarNetSet(noteBook, -1, APPLICATION_NAME, starNetBand14, callsign14, logoff14, info14, permanent14, userTimeout14, groupTimeout14, callsignSwitch14, txMsgSwitch14, link14); + noteBook->AddPage(m_starNet14, wxT("StarNet 14"), false); + + m_starNet15 = new CStarNetSet(noteBook, -1, APPLICATION_NAME, starNetBand15, callsign15, logoff15, info15, permanent15, userTimeout15, groupTimeout15, callsignSwitch15, txMsgSwitch15, link15); + noteBook->AddPage(m_starNet15, wxT("StarNet 15"), false); +#else + m_starNet1 = new CStarNetSet(noteBook, -1, APPLICATION_NAME, starNetBand1, callsign1, logoff1, info1, permanent1, userTimeout1, groupTimeout1, callsignSwitch1, txMsgSwitch1); + noteBook->AddPage(m_starNet1, wxT("StarNet 1"), false); + + m_starNet2 = new CStarNetSet(noteBook, -1, APPLICATION_NAME, starNetBand2, callsign2, logoff2, info2, permanent2, userTimeout2, groupTimeout2, callsignSwitch2, txMsgSwitch2); + noteBook->AddPage(m_starNet2, wxT("StarNet 2"), false); + + m_starNet3 = new CStarNetSet(noteBook, -1, APPLICATION_NAME, starNetBand3, callsign3, logoff3, info3, permanent3, userTimeout3, groupTimeout3, callsignSwitch3, txMsgSwitch3); + noteBook->AddPage(m_starNet3, wxT("StarNet 3"), false); + + m_starNet4 = new CStarNetSet(noteBook, -1, APPLICATION_NAME, starNetBand4, callsign4, logoff4, info4, permanent4, userTimeout4, groupTimeout4, callsignSwitch4, txMsgSwitch4); + noteBook->AddPage(m_starNet4, wxT("StarNet 4"), false); + + m_starNet5 = new CStarNetSet(noteBook, -1, APPLICATION_NAME, starNetBand5, callsign5, logoff5, info5, permanent5, userTimeout5, groupTimeout5, callsignSwitch5, txMsgSwitch5); + noteBook->AddPage(m_starNet5, wxT("StarNet 5"), false); + + m_starNet6 = new CStarNetSet(noteBook, -1, APPLICATION_NAME, starNetBand6, callsign6, logoff6, info6, permanent6, userTimeout6, groupTimeout6, callsignSwitch6, txMsgSwitch6); + noteBook->AddPage(m_starNet6, wxT("StarNet 6"), false); + + m_starNet7 = new CStarNetSet(noteBook, -1, APPLICATION_NAME, starNetBand7, callsign7, logoff7, info7, permanent7, userTimeout7, groupTimeout7, callsignSwitch7, txMsgSwitch7); + noteBook->AddPage(m_starNet7, wxT("StarNet 7"), false); + + m_starNet8 = new CStarNetSet(noteBook, -1, APPLICATION_NAME, starNetBand8, callsign8, logoff8, info8, permanent8, userTimeout8, groupTimeout8, callsignSwitch8, txMsgSwitch8); + noteBook->AddPage(m_starNet8, wxT("StarNet 8"), false); + + m_starNet9 = new CStarNetSet(noteBook, -1, APPLICATION_NAME, starNetBand9, callsign9, logoff9, info9, permanent9, userTimeout9, groupTimeout9, callsignSwitch9, txMsgSwitch9); + noteBook->AddPage(m_starNet9, wxT("StarNet 9"), false); + + m_starNet10 = new CStarNetSet(noteBook, -1, APPLICATION_NAME, starNetBand10, callsign10, logoff10, info10, permanent10, userTimeout10, groupTimeout10, callsignSwitch10, txMsgSwitch10); + noteBook->AddPage(m_starNet10, wxT("StarNet 10"), false); + + m_starNet11 = new CStarNetSet(noteBook, -1, APPLICATION_NAME, starNetBand11, callsign11, logoff11, info11, permanent11, userTimeout11, groupTimeout11, callsignSwitch11, txMsgSwitch11); + noteBook->AddPage(m_starNet11, wxT("StarNet 11"), false); + + m_starNet12 = new CStarNetSet(noteBook, -1, APPLICATION_NAME, starNetBand12, callsign12, logoff12, info12, permanent12, userTimeout12, groupTimeout12, callsignSwitch12, txMsgSwitch12); + noteBook->AddPage(m_starNet12, wxT("StarNet 12"), false); + + m_starNet13 = new CStarNetSet(noteBook, -1, APPLICATION_NAME, starNetBand13, callsign13, logoff13, info13, permanent13, userTimeout13, groupTimeout13, callsignSwitch13, txMsgSwitch13); + noteBook->AddPage(m_starNet13, wxT("StarNet 13"), false); + + m_starNet14 = new CStarNetSet(noteBook, -1, APPLICATION_NAME, starNetBand14, callsign14, logoff14, info14, permanent14, userTimeout14, groupTimeout14, callsignSwitch14, txMsgSwitch14); + noteBook->AddPage(m_starNet14, wxT("StarNet 14"), false); + + m_starNet15 = new CStarNetSet(noteBook, -1, APPLICATION_NAME, starNetBand15, callsign15, logoff15, info15, permanent15, userTimeout15, groupTimeout15, callsignSwitch15, txMsgSwitch15); + noteBook->AddPage(m_starNet15, wxT("StarNet 15"), false); +#endif + + m_remote = new CRemoteSet(noteBook, -1, APPLICATION_NAME, remoteEnabled, remotePassword, remotePort); + noteBook->AddPage(m_remote, wxT("Remote"), false); + + m_miscellaneous = new CStarNetServerMiscellaneousSet(noteBook, -1, APPLICATION_NAME, logEnabled); + noteBook->AddPage(m_miscellaneous, wxT("Misc"), false); + + mainSizer->Add(noteBook, 1, wxALL | wxGROW, BORDER_SIZE); + + mainSizer->Add(CreateButtonSizer(wxOK | wxCANCEL), 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + SetAutoLayout(true); + Layout(); + + mainSizer->Fit(this); + mainSizer->SetSizeHints(this); + + SetSizer(mainSizer); +} + +CStarNetServerPreferences::~CStarNetServerPreferences() +{ +} + +bool CStarNetServerPreferences::Validate() +{ + if (!m_callsign->Validate()) + return false; + + if (!m_ircDDB->Validate()) + return false; + + if (!m_starNet1->Validate()) + return false; + + if (!m_starNet2->Validate()) + return false; + + if (!m_starNet3->Validate()) + return false; + + if (!m_starNet4->Validate()) + return false; + + if (!m_starNet5->Validate()) + return false; + + if (!m_starNet6->Validate()) + return false; + + if (!m_starNet7->Validate()) + return false; + + if (!m_starNet8->Validate()) + return false; + + if (!m_starNet9->Validate()) + return false; + + if (!m_starNet10->Validate()) + return false; + + if (!m_starNet11->Validate()) + return false; + + if (!m_starNet12->Validate()) + return false; + + if (!m_starNet13->Validate()) + return false; + + if (!m_starNet14->Validate()) + return false; + + if (!m_starNet15->Validate()) + return false; + + if (!m_remote->Validate()) + return false; + + return m_miscellaneous->Validate(); +} + +wxString CStarNetServerPreferences::getCallsign() const +{ + return m_callsign->getCallsign(); +} + +wxString CStarNetServerPreferences::getAddress() const +{ + return m_callsign->getAddress(); +} + +wxString CStarNetServerPreferences::getHostname() const +{ + return m_ircDDB->getHostname(); +} + +wxString CStarNetServerPreferences::getUsername() const +{ + return m_ircDDB->getUsername(); +} + +wxString CStarNetServerPreferences::getPassword() const +{ + return m_ircDDB->getPassword(); +} + +bool CStarNetServerPreferences::getLogEnabled() const +{ + return m_miscellaneous->getLogEnabled(); +} + +wxString CStarNetServerPreferences::getStarNetBand1() const +{ + return m_starNet1->getBand(); +} + +wxString CStarNetServerPreferences::getStarNetCallsign1() const +{ + return m_starNet1->getCallsign(); +} + +wxString CStarNetServerPreferences::getStarNetLogoff1() const +{ + return m_starNet1->getLogoff(); +} + +wxString CStarNetServerPreferences::getStarNetInfo1() const +{ + return m_starNet1->getInfo(); +} + +wxString CStarNetServerPreferences::getStarNetPermanent1() const +{ + return m_starNet1->getPermanent(); +} + +unsigned int CStarNetServerPreferences::getStarNetUserTimeout1() const +{ + return m_starNet1->getUserTimeout(); +} + +unsigned int CStarNetServerPreferences::getStarNetGroupTimeout1() const +{ + return m_starNet1->getGroupTimeout(); +} + +STARNET_CALLSIGN_SWITCH CStarNetServerPreferences::getStarNetCallsignSwitch1() const +{ + return m_starNet1->getCallsignSwitch(); +} + +bool CStarNetServerPreferences::getStarNetTXMsgSwitch1() const +{ + return m_starNet1->getTXMsgSwitch(); +} + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) +wxString CStarNetServerPreferences::getStarNetLink1() const +{ + return m_starNet1->getReflector(); +} +#endif + +wxString CStarNetServerPreferences::getStarNetBand2() const +{ + return m_starNet2->getBand(); +} + +wxString CStarNetServerPreferences::getStarNetCallsign2() const +{ + return m_starNet2->getCallsign(); +} + +wxString CStarNetServerPreferences::getStarNetLogoff2() const +{ + return m_starNet2->getLogoff(); +} + +wxString CStarNetServerPreferences::getStarNetInfo2() const +{ + return m_starNet2->getInfo(); +} + +wxString CStarNetServerPreferences::getStarNetPermanent2() const +{ + return m_starNet2->getPermanent(); +} + +unsigned int CStarNetServerPreferences::getStarNetUserTimeout2() const +{ + return m_starNet2->getUserTimeout(); +} + +unsigned int CStarNetServerPreferences::getStarNetGroupTimeout2() const +{ + return m_starNet2->getGroupTimeout(); +} + +STARNET_CALLSIGN_SWITCH CStarNetServerPreferences::getStarNetCallsignSwitch2() const +{ + return m_starNet2->getCallsignSwitch(); +} + +bool CStarNetServerPreferences::getStarNetTXMsgSwitch2() const +{ + return m_starNet2->getTXMsgSwitch(); +} + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) +wxString CStarNetServerPreferences::getStarNetLink2() const +{ + return m_starNet2->getReflector(); +} +#endif + +wxString CStarNetServerPreferences::getStarNetBand3() const +{ + return m_starNet3->getBand(); +} + +wxString CStarNetServerPreferences::getStarNetCallsign3() const +{ + return m_starNet3->getCallsign(); +} + +wxString CStarNetServerPreferences::getStarNetLogoff3() const +{ + return m_starNet3->getLogoff(); +} + +wxString CStarNetServerPreferences::getStarNetInfo3() const +{ + return m_starNet3->getInfo(); +} + +wxString CStarNetServerPreferences::getStarNetPermanent3() const +{ + return m_starNet3->getPermanent(); +} + +unsigned int CStarNetServerPreferences::getStarNetUserTimeout3() const +{ + return m_starNet3->getUserTimeout(); +} + +unsigned int CStarNetServerPreferences::getStarNetGroupTimeout3() const +{ + return m_starNet3->getGroupTimeout(); +} + +STARNET_CALLSIGN_SWITCH CStarNetServerPreferences::getStarNetCallsignSwitch3() const +{ + return m_starNet3->getCallsignSwitch(); +} + +bool CStarNetServerPreferences::getStarNetTXMsgSwitch3() const +{ + return m_starNet3->getTXMsgSwitch(); +} + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) +wxString CStarNetServerPreferences::getStarNetLink3() const +{ + return m_starNet3->getReflector(); +} +#endif + +wxString CStarNetServerPreferences::getStarNetBand4() const +{ + return m_starNet4->getBand(); +} + +wxString CStarNetServerPreferences::getStarNetCallsign4() const +{ + return m_starNet4->getCallsign(); +} + +wxString CStarNetServerPreferences::getStarNetLogoff4() const +{ + return m_starNet4->getLogoff(); +} + +wxString CStarNetServerPreferences::getStarNetInfo4() const +{ + return m_starNet4->getInfo(); +} + +wxString CStarNetServerPreferences::getStarNetPermanent4() const +{ + return m_starNet4->getPermanent(); +} + +unsigned int CStarNetServerPreferences::getStarNetUserTimeout4() const +{ + return m_starNet4->getUserTimeout(); +} + +unsigned int CStarNetServerPreferences::getStarNetGroupTimeout4() const +{ + return m_starNet4->getGroupTimeout(); +} + +STARNET_CALLSIGN_SWITCH CStarNetServerPreferences::getStarNetCallsignSwitch4() const +{ + return m_starNet4->getCallsignSwitch(); +} + +bool CStarNetServerPreferences::getStarNetTXMsgSwitch4() const +{ + return m_starNet4->getTXMsgSwitch(); +} + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) +wxString CStarNetServerPreferences::getStarNetLink4() const +{ + return m_starNet4->getReflector(); +} +#endif + +wxString CStarNetServerPreferences::getStarNetBand5() const +{ + return m_starNet5->getBand(); +} + +wxString CStarNetServerPreferences::getStarNetCallsign5() const +{ + return m_starNet5->getCallsign(); +} + +wxString CStarNetServerPreferences::getStarNetLogoff5() const +{ + return m_starNet5->getLogoff(); +} + +wxString CStarNetServerPreferences::getStarNetInfo5() const +{ + return m_starNet5->getInfo(); +} + +wxString CStarNetServerPreferences::getStarNetPermanent5() const +{ + return m_starNet5->getPermanent(); +} + +unsigned int CStarNetServerPreferences::getStarNetUserTimeout5() const +{ + return m_starNet5->getUserTimeout(); +} + +unsigned int CStarNetServerPreferences::getStarNetGroupTimeout5() const +{ + return m_starNet5->getGroupTimeout(); +} + +STARNET_CALLSIGN_SWITCH CStarNetServerPreferences::getStarNetCallsignSwitch5() const +{ + return m_starNet5->getCallsignSwitch(); +} + +bool CStarNetServerPreferences::getStarNetTXMsgSwitch5() const +{ + return m_starNet5->getTXMsgSwitch(); +} + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) +wxString CStarNetServerPreferences::getStarNetLink5() const +{ + return m_starNet5->getReflector(); +} +#endif + +wxString CStarNetServerPreferences::getStarNetBand6() const +{ + return m_starNet6->getBand(); +} + +wxString CStarNetServerPreferences::getStarNetCallsign6() const +{ + return m_starNet6->getCallsign(); +} + +wxString CStarNetServerPreferences::getStarNetLogoff6() const +{ + return m_starNet6->getLogoff(); +} + +wxString CStarNetServerPreferences::getStarNetInfo6() const +{ + return m_starNet6->getInfo(); +} + +wxString CStarNetServerPreferences::getStarNetPermanent6() const +{ + return m_starNet6->getPermanent(); +} + +unsigned int CStarNetServerPreferences::getStarNetUserTimeout6() const +{ + return m_starNet6->getUserTimeout(); +} + +unsigned int CStarNetServerPreferences::getStarNetGroupTimeout6() const +{ + return m_starNet6->getGroupTimeout(); +} + +STARNET_CALLSIGN_SWITCH CStarNetServerPreferences::getStarNetCallsignSwitch6() const +{ + return m_starNet6->getCallsignSwitch(); +} + +bool CStarNetServerPreferences::getStarNetTXMsgSwitch6() const +{ + return m_starNet6->getTXMsgSwitch(); +} + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) +wxString CStarNetServerPreferences::getStarNetLink6() const +{ + return m_starNet6->getReflector(); +} +#endif + +wxString CStarNetServerPreferences::getStarNetBand7() const +{ + return m_starNet7->getBand(); +} + +wxString CStarNetServerPreferences::getStarNetCallsign7() const +{ + return m_starNet7->getCallsign(); +} + +wxString CStarNetServerPreferences::getStarNetLogoff7() const +{ + return m_starNet7->getLogoff(); +} + +wxString CStarNetServerPreferences::getStarNetInfo7() const +{ + return m_starNet7->getInfo(); +} + +wxString CStarNetServerPreferences::getStarNetPermanent7() const +{ + return m_starNet7->getPermanent(); +} + +unsigned int CStarNetServerPreferences::getStarNetUserTimeout7() const +{ + return m_starNet7->getUserTimeout(); +} + +unsigned int CStarNetServerPreferences::getStarNetGroupTimeout7() const +{ + return m_starNet7->getGroupTimeout(); +} + +STARNET_CALLSIGN_SWITCH CStarNetServerPreferences::getStarNetCallsignSwitch7() const +{ + return m_starNet7->getCallsignSwitch(); +} + +bool CStarNetServerPreferences::getStarNetTXMsgSwitch7() const +{ + return m_starNet7->getTXMsgSwitch(); +} + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) +wxString CStarNetServerPreferences::getStarNetLink7() const +{ + return m_starNet7->getReflector(); +} +#endif + +wxString CStarNetServerPreferences::getStarNetBand8() const +{ + return m_starNet8->getBand(); +} + +wxString CStarNetServerPreferences::getStarNetCallsign8() const +{ + return m_starNet8->getCallsign(); +} + +wxString CStarNetServerPreferences::getStarNetLogoff8() const +{ + return m_starNet8->getLogoff(); +} + +wxString CStarNetServerPreferences::getStarNetInfo8() const +{ + return m_starNet8->getInfo(); +} + +wxString CStarNetServerPreferences::getStarNetPermanent8() const +{ + return m_starNet8->getPermanent(); +} + +unsigned int CStarNetServerPreferences::getStarNetUserTimeout8() const +{ + return m_starNet8->getUserTimeout(); +} + +unsigned int CStarNetServerPreferences::getStarNetGroupTimeout8() const +{ + return m_starNet8->getGroupTimeout(); +} + +STARNET_CALLSIGN_SWITCH CStarNetServerPreferences::getStarNetCallsignSwitch8() const +{ + return m_starNet8->getCallsignSwitch(); +} + +bool CStarNetServerPreferences::getStarNetTXMsgSwitch8() const +{ + return m_starNet8->getTXMsgSwitch(); +} + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) +wxString CStarNetServerPreferences::getStarNetLink8() const +{ + return m_starNet8->getReflector(); +} +#endif + +wxString CStarNetServerPreferences::getStarNetBand9() const +{ + return m_starNet9->getBand(); +} + +wxString CStarNetServerPreferences::getStarNetCallsign9() const +{ + return m_starNet9->getCallsign(); +} + +wxString CStarNetServerPreferences::getStarNetLogoff9() const +{ + return m_starNet9->getLogoff(); +} + +wxString CStarNetServerPreferences::getStarNetInfo9() const +{ + return m_starNet9->getInfo(); +} + +wxString CStarNetServerPreferences::getStarNetPermanent9() const +{ + return m_starNet9->getPermanent(); +} + +unsigned int CStarNetServerPreferences::getStarNetUserTimeout9() const +{ + return m_starNet9->getUserTimeout(); +} + +unsigned int CStarNetServerPreferences::getStarNetGroupTimeout9() const +{ + return m_starNet9->getGroupTimeout(); +} + +STARNET_CALLSIGN_SWITCH CStarNetServerPreferences::getStarNetCallsignSwitch9() const +{ + return m_starNet9->getCallsignSwitch(); +} + +bool CStarNetServerPreferences::getStarNetTXMsgSwitch9() const +{ + return m_starNet9->getTXMsgSwitch(); +} + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) +wxString CStarNetServerPreferences::getStarNetLink9() const +{ + return m_starNet9->getReflector(); +} +#endif + +wxString CStarNetServerPreferences::getStarNetBand10() const +{ + return m_starNet10->getBand(); +} + +wxString CStarNetServerPreferences::getStarNetCallsign10() const +{ + return m_starNet10->getCallsign(); +} + +wxString CStarNetServerPreferences::getStarNetLogoff10() const +{ + return m_starNet10->getLogoff(); +} + +wxString CStarNetServerPreferences::getStarNetInfo10() const +{ + return m_starNet10->getInfo(); +} + +wxString CStarNetServerPreferences::getStarNetPermanent10() const +{ + return m_starNet10->getPermanent(); +} + +unsigned int CStarNetServerPreferences::getStarNetUserTimeout10() const +{ + return m_starNet10->getUserTimeout(); +} + +unsigned int CStarNetServerPreferences::getStarNetGroupTimeout10() const +{ + return m_starNet10->getGroupTimeout(); +} + +STARNET_CALLSIGN_SWITCH CStarNetServerPreferences::getStarNetCallsignSwitch10() const +{ + return m_starNet10->getCallsignSwitch(); +} + +bool CStarNetServerPreferences::getStarNetTXMsgSwitch10() const +{ + return m_starNet10->getTXMsgSwitch(); +} + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) +wxString CStarNetServerPreferences::getStarNetLink10() const +{ + return m_starNet10->getReflector(); +} +#endif + +wxString CStarNetServerPreferences::getStarNetBand11() const +{ + return m_starNet11->getBand(); +} + +wxString CStarNetServerPreferences::getStarNetCallsign11() const +{ + return m_starNet11->getCallsign(); +} + +wxString CStarNetServerPreferences::getStarNetLogoff11() const +{ + return m_starNet11->getLogoff(); +} + +wxString CStarNetServerPreferences::getStarNetInfo11() const +{ + return m_starNet11->getInfo(); +} + +wxString CStarNetServerPreferences::getStarNetPermanent11() const +{ + return m_starNet11->getPermanent(); +} + +unsigned int CStarNetServerPreferences::getStarNetUserTimeout11() const +{ + return m_starNet11->getUserTimeout(); +} + +unsigned int CStarNetServerPreferences::getStarNetGroupTimeout11() const +{ + return m_starNet11->getGroupTimeout(); +} + +STARNET_CALLSIGN_SWITCH CStarNetServerPreferences::getStarNetCallsignSwitch11() const +{ + return m_starNet11->getCallsignSwitch(); +} + +bool CStarNetServerPreferences::getStarNetTXMsgSwitch11() const +{ + return m_starNet11->getTXMsgSwitch(); +} + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) +wxString CStarNetServerPreferences::getStarNetLink11() const +{ + return m_starNet11->getReflector(); +} +#endif + +wxString CStarNetServerPreferences::getStarNetBand12() const +{ + return m_starNet12->getBand(); +} + +wxString CStarNetServerPreferences::getStarNetCallsign12() const +{ + return m_starNet12->getCallsign(); +} + +wxString CStarNetServerPreferences::getStarNetLogoff12() const +{ + return m_starNet12->getLogoff(); +} + +wxString CStarNetServerPreferences::getStarNetInfo12() const +{ + return m_starNet12->getInfo(); +} + +wxString CStarNetServerPreferences::getStarNetPermanent12() const +{ + return m_starNet12->getPermanent(); +} + +unsigned int CStarNetServerPreferences::getStarNetUserTimeout12() const +{ + return m_starNet12->getUserTimeout(); +} + +unsigned int CStarNetServerPreferences::getStarNetGroupTimeout12() const +{ + return m_starNet12->getGroupTimeout(); +} + +STARNET_CALLSIGN_SWITCH CStarNetServerPreferences::getStarNetCallsignSwitch12() const +{ + return m_starNet12->getCallsignSwitch(); +} + +bool CStarNetServerPreferences::getStarNetTXMsgSwitch12() const +{ + return m_starNet12->getTXMsgSwitch(); +} + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) +wxString CStarNetServerPreferences::getStarNetLink12() const +{ + return m_starNet12->getReflector(); +} +#endif + +wxString CStarNetServerPreferences::getStarNetBand13() const +{ + return m_starNet13->getBand(); +} + +wxString CStarNetServerPreferences::getStarNetCallsign13() const +{ + return m_starNet13->getCallsign(); +} + +wxString CStarNetServerPreferences::getStarNetLogoff13() const +{ + return m_starNet13->getLogoff(); +} + +wxString CStarNetServerPreferences::getStarNetInfo13() const +{ + return m_starNet13->getInfo(); +} + +wxString CStarNetServerPreferences::getStarNetPermanent13() const +{ + return m_starNet13->getPermanent(); +} + +unsigned int CStarNetServerPreferences::getStarNetUserTimeout13() const +{ + return m_starNet13->getUserTimeout(); +} + +unsigned int CStarNetServerPreferences::getStarNetGroupTimeout13() const +{ + return m_starNet13->getGroupTimeout(); +} + +STARNET_CALLSIGN_SWITCH CStarNetServerPreferences::getStarNetCallsignSwitch13() const +{ + return m_starNet13->getCallsignSwitch(); +} + +bool CStarNetServerPreferences::getStarNetTXMsgSwitch13() const +{ + return m_starNet13->getTXMsgSwitch(); +} + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) +wxString CStarNetServerPreferences::getStarNetLink13() const +{ + return m_starNet13->getReflector(); +} +#endif + +wxString CStarNetServerPreferences::getStarNetBand14() const +{ + return m_starNet14->getBand(); +} + +wxString CStarNetServerPreferences::getStarNetCallsign14() const +{ + return m_starNet14->getCallsign(); +} + +wxString CStarNetServerPreferences::getStarNetLogoff14() const +{ + return m_starNet14->getLogoff(); +} + +wxString CStarNetServerPreferences::getStarNetInfo14() const +{ + return m_starNet14->getInfo(); +} + +wxString CStarNetServerPreferences::getStarNetPermanent14() const +{ + return m_starNet14->getPermanent(); +} + +unsigned int CStarNetServerPreferences::getStarNetUserTimeout14() const +{ + return m_starNet14->getUserTimeout(); +} + +unsigned int CStarNetServerPreferences::getStarNetGroupTimeout14() const +{ + return m_starNet14->getGroupTimeout(); +} + +STARNET_CALLSIGN_SWITCH CStarNetServerPreferences::getStarNetCallsignSwitch14() const +{ + return m_starNet14->getCallsignSwitch(); +} + +bool CStarNetServerPreferences::getStarNetTXMsgSwitch14() const +{ + return m_starNet14->getTXMsgSwitch(); +} + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) +wxString CStarNetServerPreferences::getStarNetLink14() const +{ + return m_starNet14->getReflector(); +} +#endif + +wxString CStarNetServerPreferences::getStarNetBand15() const +{ + return m_starNet15->getBand(); +} + +wxString CStarNetServerPreferences::getStarNetCallsign15() const +{ + return m_starNet15->getCallsign(); +} + +wxString CStarNetServerPreferences::getStarNetLogoff15() const +{ + return m_starNet15->getLogoff(); +} + +wxString CStarNetServerPreferences::getStarNetInfo15() const +{ + return m_starNet15->getInfo(); +} + +wxString CStarNetServerPreferences::getStarNetPermanent15() const +{ + return m_starNet15->getPermanent(); +} + +unsigned int CStarNetServerPreferences::getStarNetUserTimeout15() const +{ + return m_starNet15->getUserTimeout(); +} + +unsigned int CStarNetServerPreferences::getStarNetGroupTimeout15() const +{ + return m_starNet15->getGroupTimeout(); +} + +STARNET_CALLSIGN_SWITCH CStarNetServerPreferences::getStarNetCallsignSwitch15() const +{ + return m_starNet15->getCallsignSwitch(); +} + +bool CStarNetServerPreferences::getStarNetTXMsgSwitch15() const +{ + return m_starNet15->getTXMsgSwitch(); +} + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) +wxString CStarNetServerPreferences::getStarNetLink15() const +{ + return m_starNet15->getReflector(); +} +#endif + +bool CStarNetServerPreferences::getRemoteEnabled() const +{ + return m_remote->getEnabled(); +} + +wxString CStarNetServerPreferences::getRemotePassword() const +{ + return m_remote->getPassword(); +} + +unsigned int CStarNetServerPreferences::getRemotePort() const +{ + return m_remote->getPort(); +} diff --git a/StarNetServer/StarNetServerPreferences.h b/StarNetServer/StarNetServerPreferences.h new file mode 100644 index 0000000..7726d9b --- /dev/null +++ b/StarNetServer/StarNetServerPreferences.h @@ -0,0 +1,305 @@ +/* + * Copyright (C) 2010,2011,2012,2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef StarNetServerPreferences_H +#define StarNetServerPreferences_H + +#include +#include + +#include "StarNetServerMiscellaneousSet.h" +#include "StarNetServerCallsignSet.h" +#include "StarNetServerIrcDDBSet.h" +#include "StarNetSet.h" +#include "RemoteSet.h" + +class CStarNetServerPreferences : public wxDialog { +public: + CStarNetServerPreferences(wxWindow* parent, int id, + const wxString& callsign, const wxString& address, + const wxString& hostname, const wxString& username, const wxString& password, + bool logEnabled, +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + const wxString& starNetBand1, const wxString& callsign1, const wxString& logoff1, const wxString& info1, const wxString& permanent1, unsigned int userTimeout1, unsigned int groupTimeout1, STARNET_CALLSIGN_SWITCH callsignSwitch1, bool txMsgSwitch1, const wxString& link1, + const wxString& starNetBand2, const wxString& callsign2, const wxString& logoff2, const wxString& info2, const wxString& permanent2, unsigned int userTimeout2, unsigned int groupTimeout2, STARNET_CALLSIGN_SWITCH callsignSwitch2, bool txMsgSwitch2, const wxString& link2, + const wxString& starNetBand3, const wxString& callsign3, const wxString& logoff3, const wxString& info3, const wxString& permanent3, unsigned int userTimeout3, unsigned int groupTimeout3, STARNET_CALLSIGN_SWITCH callsignSwitch3, bool txMsgSwitch3, const wxString& link3, + const wxString& starNetBand4, const wxString& callsign4, const wxString& logoff4, const wxString& info4, const wxString& permanent4, unsigned int userTimeout4, unsigned int groupTimeout4, STARNET_CALLSIGN_SWITCH callsignSwitch4, bool txMsgSwitch4, const wxString& link4, + const wxString& starNetBand5, const wxString& callsign5, const wxString& logoff5, const wxString& info5, const wxString& permanent5, unsigned int userTimeout5, unsigned int groupTimeout5, STARNET_CALLSIGN_SWITCH callsignSwitch5, bool txMsgSwitch5, const wxString& link5, + const wxString& starNetBand6, const wxString& callsign6, const wxString& logoff6, const wxString& info6, const wxString& permanent6, unsigned int userTimeout6, unsigned int groupTimeout6, STARNET_CALLSIGN_SWITCH callsignSwitch6, bool txMsgSwitch6, const wxString& link6, + const wxString& starNetBand7, const wxString& callsign7, const wxString& logoff7, const wxString& info7, const wxString& permanent7, unsigned int userTimeout7, unsigned int groupTimeout7, STARNET_CALLSIGN_SWITCH callsignSwitch7, bool txMsgSwitch7, const wxString& link7, + const wxString& starNetBand8, const wxString& callsign8, const wxString& logoff8, const wxString& info8, const wxString& permanent8, unsigned int userTimeout8, unsigned int groupTimeout8, STARNET_CALLSIGN_SWITCH callsignSwitch8, bool txMsgSwitch8, const wxString& link8, + const wxString& starNetBand9, const wxString& callsign9, const wxString& logoff9, const wxString& info9, const wxString& permanent9, unsigned int userTimeout9, unsigned int groupTimeout9, STARNET_CALLSIGN_SWITCH callsignSwitch9, bool txMsgSwitch9, const wxString& link9, + const wxString& starNetBand10, const wxString& callsign10, const wxString& logoff10, const wxString& info10, const wxString& permanent10, unsigned int userTimeout10, unsigned int groupTimeout10, STARNET_CALLSIGN_SWITCH callsignSwitch10, bool txMsgSwitch10, const wxString& link10, + const wxString& starNetBand11, const wxString& callsign11, const wxString& logoff11, const wxString& info11, const wxString& permanent11, unsigned int userTimeout11, unsigned int groupTimeout11, STARNET_CALLSIGN_SWITCH callsignSwitch11, bool txMsgSwitch11, const wxString& link11, + const wxString& starNetBand12, const wxString& callsign12, const wxString& logoff12, const wxString& info12, const wxString& permanent12, unsigned int userTimeout12, unsigned int groupTimeout12, STARNET_CALLSIGN_SWITCH callsignSwitch12, bool txMsgSwitch12, const wxString& link12, + const wxString& starNetBand13, const wxString& callsign13, const wxString& logoff13, const wxString& info13, const wxString& permanent13, unsigned int userTimeout13, unsigned int groupTimeout13, STARNET_CALLSIGN_SWITCH callsignSwitch13, bool txMsgSwitch13, const wxString& link13, + const wxString& starNetBand14, const wxString& callsign14, const wxString& logoff14, const wxString& info14, const wxString& permanent14, unsigned int userTimeout14, unsigned int groupTimeout14, STARNET_CALLSIGN_SWITCH callsignSwitch14, bool txMsgSwitch14, const wxString& link14, + const wxString& starNetBand15, const wxString& callsign15, const wxString& logoff15, const wxString& info15, const wxString& permanent15, unsigned int userTimeout15, unsigned int groupTimeout15, STARNET_CALLSIGN_SWITCH callsignSwitch15, bool txMsgSwitch15, const wxString& link15, +#else + const wxString& starNetBand1, const wxString& callsign1, const wxString& logoff1, const wxString& info1, const wxString& permanent1, unsigned int userTimeout1, unsigned int groupTimeout1, STARNET_CALLSIGN_SWITCH callsignSwitch1, bool txMsgSwitch1, + const wxString& starNetBand2, const wxString& callsign2, const wxString& logoff2, const wxString& info2, const wxString& permanent2, unsigned int userTimeout2, unsigned int groupTimeout2, STARNET_CALLSIGN_SWITCH callsignSwitch2, bool txMsgSwitch2, + const wxString& starNetBand3, const wxString& callsign3, const wxString& logoff3, const wxString& info3, const wxString& permanent3, unsigned int userTimeout3, unsigned int groupTimeout3, STARNET_CALLSIGN_SWITCH callsignSwitch3, bool txMsgSwitch3, + const wxString& starNetBand4, const wxString& callsign4, const wxString& logoff4, const wxString& info4, const wxString& permanent4, unsigned int userTimeout4, unsigned int groupTimeout4, STARNET_CALLSIGN_SWITCH callsignSwitch4, bool txMsgSwitch4, + const wxString& starNetBand5, const wxString& callsign5, const wxString& logoff5, const wxString& info5, const wxString& permanent5, unsigned int userTimeout5, unsigned int groupTimeout5, STARNET_CALLSIGN_SWITCH callsignSwitch5, bool txMsgSwitch5, + const wxString& starNetBand6, const wxString& callsign6, const wxString& logoff6, const wxString& info6, const wxString& permanent6, unsigned int userTimeout6, unsigned int groupTimeout6, STARNET_CALLSIGN_SWITCH callsignSwitch6, bool txMsgSwitch6, + const wxString& starNetBand7, const wxString& callsign7, const wxString& logoff7, const wxString& info7, const wxString& permanent7, unsigned int userTimeout7, unsigned int groupTimeout7, STARNET_CALLSIGN_SWITCH callsignSwitch7, bool txMsgSwitch7, + const wxString& starNetBand8, const wxString& callsign8, const wxString& logoff8, const wxString& info8, const wxString& permanent8, unsigned int userTimeout8, unsigned int groupTimeout8, STARNET_CALLSIGN_SWITCH callsignSwitch8, bool txMsgSwitch8, + const wxString& starNetBand9, const wxString& callsign9, const wxString& logoff9, const wxString& info9, const wxString& permanent9, unsigned int userTimeout9, unsigned int groupTimeout9, STARNET_CALLSIGN_SWITCH callsignSwitch9, bool txMsgSwitch9, + const wxString& starNetBand10, const wxString& callsign10, const wxString& logoff10, const wxString& info10, const wxString& permanent10, unsigned int userTimeout10, unsigned int groupTimeout10, STARNET_CALLSIGN_SWITCH callsignSwitch10, bool txMsgSwitch10, + const wxString& starNetBand11, const wxString& callsign11, const wxString& logoff11, const wxString& info11, const wxString& permanent11, unsigned int userTimeout11, unsigned int groupTimeout11, STARNET_CALLSIGN_SWITCH callsignSwitch11, bool txMsgSwitch11, + const wxString& starNetBand12, const wxString& callsign12, const wxString& logoff12, const wxString& info12, const wxString& permanent12, unsigned int userTimeout12, unsigned int groupTimeout12, STARNET_CALLSIGN_SWITCH callsignSwitch12, bool txMsgSwitch12, + const wxString& starNetBand13, const wxString& callsign13, const wxString& logoff13, const wxString& info13, const wxString& permanent13, unsigned int userTimeout13, unsigned int groupTimeout13, STARNET_CALLSIGN_SWITCH callsignSwitch13, bool txMsgSwitch13, + const wxString& starNetBand14, const wxString& callsign14, const wxString& logoff14, const wxString& info14, const wxString& permanent14, unsigned int userTimeout14, unsigned int groupTimeout14, STARNET_CALLSIGN_SWITCH callsignSwitch14, bool txMsgSwitch14, + const wxString& starNetBand15, const wxString& callsign15, const wxString& logoff15, const wxString& info15, const wxString& permanent15, unsigned int userTimeout15, unsigned int groupTimeout15, STARNET_CALLSIGN_SWITCH callsignSwitch15, bool txMsgSwitch15, +#endif + bool remoteEnabled, const wxString& remotePassword, unsigned int remotePort); + virtual ~CStarNetServerPreferences(); + + virtual bool Validate(); + + virtual wxString getCallsign() const; + virtual wxString getAddress() const; + + virtual wxString getHostname() const; + virtual wxString getUsername() const; + virtual wxString getPassword() const; + + virtual bool getLogEnabled() const; + + virtual wxString getStarNetBand1() const; + virtual wxString getStarNetCallsign1() const; + virtual wxString getStarNetLogoff1() const; + virtual wxString getStarNetInfo1() const; + virtual wxString getStarNetPermanent1() const; + virtual unsigned int getStarNetUserTimeout1() const; + virtual unsigned int getStarNetGroupTimeout1() const; + virtual STARNET_CALLSIGN_SWITCH getStarNetCallsignSwitch1() const; + virtual bool getStarNetTXMsgSwitch1() const; +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + virtual wxString getStarNetLink1() const; +#endif + + virtual wxString getStarNetBand2() const; + virtual wxString getStarNetCallsign2() const; + virtual wxString getStarNetLogoff2() const; + virtual wxString getStarNetInfo2() const; + virtual wxString getStarNetPermanent2() const; + virtual unsigned int getStarNetUserTimeout2() const; + virtual unsigned int getStarNetGroupTimeout2() const; + virtual STARNET_CALLSIGN_SWITCH getStarNetCallsignSwitch2() const; + virtual bool getStarNetTXMsgSwitch2() const; +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + virtual wxString getStarNetLink2() const; +#endif + + virtual wxString getStarNetBand3() const; + virtual wxString getStarNetCallsign3() const; + virtual wxString getStarNetLogoff3() const; + virtual wxString getStarNetInfo3() const; + virtual wxString getStarNetPermanent3() const; + virtual unsigned int getStarNetUserTimeout3() const; + virtual unsigned int getStarNetGroupTimeout3() const; + virtual STARNET_CALLSIGN_SWITCH getStarNetCallsignSwitch3() const; + virtual bool getStarNetTXMsgSwitch3() const; +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + virtual wxString getStarNetLink3() const; +#endif + + virtual wxString getStarNetBand4() const; + virtual wxString getStarNetCallsign4() const; + virtual wxString getStarNetLogoff4() const; + virtual wxString getStarNetInfo4() const; + virtual wxString getStarNetPermanent4() const; + virtual unsigned int getStarNetUserTimeout4() const; + virtual unsigned int getStarNetGroupTimeout4() const; + virtual STARNET_CALLSIGN_SWITCH getStarNetCallsignSwitch4() const; + virtual bool getStarNetTXMsgSwitch4() const; +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + virtual wxString getStarNetLink4() const; +#endif + + virtual wxString getStarNetBand5() const; + virtual wxString getStarNetCallsign5() const; + virtual wxString getStarNetLogoff5() const; + virtual wxString getStarNetInfo5() const; + virtual wxString getStarNetPermanent5() const; + virtual unsigned int getStarNetUserTimeout5() const; + virtual unsigned int getStarNetGroupTimeout5() const; + virtual STARNET_CALLSIGN_SWITCH getStarNetCallsignSwitch5() const; + virtual bool getStarNetTXMsgSwitch5() const; +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + virtual wxString getStarNetLink5() const; +#endif + + virtual wxString getStarNetBand6() const; + virtual wxString getStarNetCallsign6() const; + virtual wxString getStarNetLogoff6() const; + virtual wxString getStarNetInfo6() const; + virtual wxString getStarNetPermanent6() const; + virtual unsigned int getStarNetUserTimeout6() const; + virtual unsigned int getStarNetGroupTimeout6() const; + virtual STARNET_CALLSIGN_SWITCH getStarNetCallsignSwitch6() const; + virtual bool getStarNetTXMsgSwitch6() const; +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + virtual wxString getStarNetLink6() const; +#endif + + virtual wxString getStarNetBand7() const; + virtual wxString getStarNetCallsign7() const; + virtual wxString getStarNetLogoff7() const; + virtual wxString getStarNetInfo7() const; + virtual wxString getStarNetPermanent7() const; + virtual unsigned int getStarNetUserTimeout7() const; + virtual unsigned int getStarNetGroupTimeout7() const; + virtual STARNET_CALLSIGN_SWITCH getStarNetCallsignSwitch7() const; + virtual bool getStarNetTXMsgSwitch7() const; +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + virtual wxString getStarNetLink7() const; +#endif + + virtual wxString getStarNetBand8() const; + virtual wxString getStarNetCallsign8() const; + virtual wxString getStarNetLogoff8() const; + virtual wxString getStarNetInfo8() const; + virtual wxString getStarNetPermanent8() const; + virtual unsigned int getStarNetUserTimeout8() const; + virtual unsigned int getStarNetGroupTimeout8() const; + virtual STARNET_CALLSIGN_SWITCH getStarNetCallsignSwitch8() const; + virtual bool getStarNetTXMsgSwitch8() const; +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + virtual wxString getStarNetLink8() const; +#endif + + virtual wxString getStarNetBand9() const; + virtual wxString getStarNetCallsign9() const; + virtual wxString getStarNetLogoff9() const; + virtual wxString getStarNetInfo9() const; + virtual wxString getStarNetPermanent9() const; + virtual unsigned int getStarNetUserTimeout9() const; + virtual unsigned int getStarNetGroupTimeout9() const; + virtual STARNET_CALLSIGN_SWITCH getStarNetCallsignSwitch9() const; + virtual bool getStarNetTXMsgSwitch9() const; +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + virtual wxString getStarNetLink9() const; +#endif + + virtual wxString getStarNetBand10() const; + virtual wxString getStarNetCallsign10() const; + virtual wxString getStarNetLogoff10() const; + virtual wxString getStarNetInfo10() const; + virtual wxString getStarNetPermanent10() const; + virtual unsigned int getStarNetUserTimeout10() const; + virtual unsigned int getStarNetGroupTimeout10() const; + virtual STARNET_CALLSIGN_SWITCH getStarNetCallsignSwitch10() const; + virtual bool getStarNetTXMsgSwitch10() const; +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + virtual wxString getStarNetLink10() const; +#endif + + virtual wxString getStarNetBand11() const; + virtual wxString getStarNetCallsign11() const; + virtual wxString getStarNetLogoff11() const; + virtual wxString getStarNetInfo11() const; + virtual wxString getStarNetPermanent11() const; + virtual unsigned int getStarNetUserTimeout11() const; + virtual unsigned int getStarNetGroupTimeout11() const; + virtual STARNET_CALLSIGN_SWITCH getStarNetCallsignSwitch11() const; + virtual bool getStarNetTXMsgSwitch11() const; +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + virtual wxString getStarNetLink11() const; +#endif + + virtual wxString getStarNetBand12() const; + virtual wxString getStarNetCallsign12() const; + virtual wxString getStarNetLogoff12() const; + virtual wxString getStarNetInfo12() const; + virtual wxString getStarNetPermanent12() const; + virtual unsigned int getStarNetUserTimeout12() const; + virtual unsigned int getStarNetGroupTimeout12() const; + virtual STARNET_CALLSIGN_SWITCH getStarNetCallsignSwitch12() const; + virtual bool getStarNetTXMsgSwitch12() const; +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + virtual wxString getStarNetLink12() const; +#endif + + virtual wxString getStarNetBand13() const; + virtual wxString getStarNetCallsign13() const; + virtual wxString getStarNetLogoff13() const; + virtual wxString getStarNetInfo13() const; + virtual wxString getStarNetPermanent13() const; + virtual unsigned int getStarNetUserTimeout13() const; + virtual unsigned int getStarNetGroupTimeout13() const; + virtual STARNET_CALLSIGN_SWITCH getStarNetCallsignSwitch13() const; + virtual bool getStarNetTXMsgSwitch13() const; +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + virtual wxString getStarNetLink13() const; +#endif + + virtual wxString getStarNetBand14() const; + virtual wxString getStarNetCallsign14() const; + virtual wxString getStarNetLogoff14() const; + virtual wxString getStarNetInfo14() const; + virtual wxString getStarNetPermanent14() const; + virtual unsigned int getStarNetUserTimeout14() const; + virtual unsigned int getStarNetGroupTimeout14() const; + virtual STARNET_CALLSIGN_SWITCH getStarNetCallsignSwitch14() const; + virtual bool getStarNetTXMsgSwitch14() const; +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + virtual wxString getStarNetLink14() const; +#endif + + virtual wxString getStarNetBand15() const; + virtual wxString getStarNetCallsign15() const; + virtual wxString getStarNetLogoff15() const; + virtual wxString getStarNetInfo15() const; + virtual wxString getStarNetPermanent15() const; + virtual unsigned int getStarNetUserTimeout15() const; + virtual unsigned int getStarNetGroupTimeout15() const; + virtual STARNET_CALLSIGN_SWITCH getStarNetCallsignSwitch15() const; + virtual bool getStarNetTXMsgSwitch15() const; +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + virtual wxString getStarNetLink15() const; +#endif + + virtual bool getRemoteEnabled() const; + virtual wxString getRemotePassword() const; + virtual unsigned int getRemotePort() const; + +private: + CStarNetServerCallsignSet* m_callsign; + CStarNetServerIrcDDBSet* m_ircDDB; + CStarNetSet* m_starNet1; + CStarNetSet* m_starNet2; + CStarNetSet* m_starNet3; + CStarNetSet* m_starNet4; + CStarNetSet* m_starNet5; + CStarNetSet* m_starNet6; + CStarNetSet* m_starNet7; + CStarNetSet* m_starNet8; + CStarNetSet* m_starNet9; + CStarNetSet* m_starNet10; + CStarNetSet* m_starNet11; + CStarNetSet* m_starNet12; + CStarNetSet* m_starNet13; + CStarNetSet* m_starNet14; + CStarNetSet* m_starNet15; + CRemoteSet* m_remote; + CStarNetServerMiscellaneousSet* m_miscellaneous; +}; + +#endif diff --git a/StarNetServer/StarNetServerThread.cpp b/StarNetServer/StarNetServerThread.cpp new file mode 100644 index 0000000..2b86002 --- /dev/null +++ b/StarNetServer/StarNetServerThread.cpp @@ -0,0 +1,627 @@ +/* + * Copyright (C) 2010-2014 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "StarNetServerThread.h" +#include "StarNetServerDefs.h" +#include "StarNetHandler.h" +#include "DExtraHandler.h" // DEXTRA LINK +#include "DCSHandler.h" // DCS LINK +#include "HeaderData.h" +#include "G2Handler.h" +#include "AMBEData.h" +#include "HostFile.h" // DEXTRA_LINK || DCS_LINK +#include "Utils.h" + +#include +#include + +const unsigned int REMOTE_DUMMY_PORT = 65015U; + +CStarNetServerThread::CStarNetServerThread(bool nolog, const wxString& logDir) : +m_nolog(nolog), +m_logDir(logDir), +m_killed(false), +m_stopped(true), +m_callsign(), +m_address(), +#if defined(DEXTRA_LINK) +m_dextraPool(NULL), +#endif +#if defined(DCS_LINK) +m_dcsPool(NULL), +#endif +m_g2Handler(NULL), +m_irc(NULL), +m_cache(), +m_logEnabled(false), +m_statusTimer(1000U, 1U), // 1 second +m_lastStatus(IS_DISCONNECTED), +m_remoteEnabled(false), +m_remotePassword(), +m_remotePort(0U), +m_remote(NULL) +{ + CHeaderData::initialise(); + CG2Handler::initialise(MAX_ROUTES); + CStarNetHandler::initialise(MAX_STARNETS); +#if defined(DEXTRA_LINK) + CDExtraHandler::initialise(MAX_DEXTRA_LINKS); +#endif +#if defined(DCS_LINK) + CDCSHandler::initialise(MAX_DCS_LINKS); +#endif +} + +CStarNetServerThread::~CStarNetServerThread() +{ + CHeaderData::finalise(); + CG2Handler::finalise(); + CStarNetHandler::finalise(); +#if defined(DEXTRA_LINK) + CDExtraHandler::finalise(); +#endif +#if defined(DCS_LINK) + CDCSHandler::finalise(); +#endif +} + +void CStarNetServerThread::run() +{ + // Truncate the old StarNet.log file + wxFileName fileName(m_logDir, STARNET_BASE_NAME, wxT("log")); + wxLogMessage(wxT("Truncating %s"), fileName.GetFullPath().c_str()); + + wxFFile file; + bool ret = file.Open(fileName.GetFullPath(), wxT("wt")); + if (ret) + file.Close(); + +#if defined(DEXTRA_LINK) + m_dextraPool = new CDExtraProtocolHandlerPool(MAX_DEXTRA_LINKS, DEXTRA_PORT, m_address); + ret = m_dextraPool->open(); + if (!ret) { + wxLogError(wxT("Could not open the DExtra protocol pool")); + delete m_dextraPool; + m_dextraPool = NULL; + } +#endif + +#if defined(DCS_LINK) + m_dcsPool = new CDCSProtocolHandlerPool(MAX_DCS_LINKS, DCS_PORT, m_address); + ret = m_dcsPool->open(); + if (!ret) { + wxLogError(wxT("Could not open the DCS protocol pool")); + delete m_dcsPool; + m_dcsPool = NULL; + } +#endif + + m_g2Handler = new CG2ProtocolHandler(G2_DV_PORT, m_address); + ret = m_g2Handler->open(); + if (!ret) { + wxLogError(wxT("Could not open the G2 protocol handler")); + delete m_g2Handler; + m_g2Handler = NULL; + } + + // Wait here until we have the essentials to run +#if defined(DEXTRA_LINK) + while (!m_killed && (m_g2Handler == NULL || m_dextraPool == NULL || m_irc == NULL || m_callsign.IsEmpty())) + ::wxMilliSleep(500UL); // 1/2 sec +#elif defined(DCS_LINK) + while (!m_killed && (m_g2Handler == NULL || m_dcsPool == NULL || m_irc == NULL || m_callsign.IsEmpty())) + ::wxMilliSleep(500UL); // 1/2 sec +#else + while (!m_killed && (m_g2Handler == NULL || m_irc == NULL || m_callsign.IsEmpty())) + ::wxMilliSleep(500UL); // 1/2 sec +#endif + + if (m_killed) + return; + + m_stopped = false; + + wxLogMessage(wxT("Starting the StarNet Server thread")); + + CHeaderLogger* headerLogger = NULL; + if (m_logEnabled) { + headerLogger = new CHeaderLogger(m_logDir); + ret = headerLogger->open(); + if (!ret) { + delete headerLogger; + headerLogger = NULL; + } + } + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + loadReflectors(); +#endif + + CG2Handler::setG2ProtocolHandler(m_g2Handler); + CG2Handler::setHeaderLogger(headerLogger); + +#if defined(DEXTRA_LINK) + CDExtraHandler::setCallsign(m_callsign); + CDExtraHandler::setDExtraProtocolHandlerPool(m_dextraPool); + CDExtraHandler::setHeaderLogger(headerLogger); +#endif +#if defined(DCS_LINK) + CDCSHandler::setDCSProtocolHandlerPool(m_dcsPool); + CDCSHandler::setHeaderLogger(headerLogger); + CDCSHandler::setGatewayType(GT_STARNET); +#endif + + CStarNetHandler::setCache(&m_cache); + CStarNetHandler::setGateway(m_callsign); + CStarNetHandler::setG2Handler(m_g2Handler); + CStarNetHandler::setIRC(m_irc); + CStarNetHandler::setLogging(m_logEnabled, m_logDir); +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + CStarNetHandler::link(); +#endif + + if (m_remoteEnabled && !m_remotePassword.IsEmpty() && m_remotePort > 0U) { + m_remote = new CRemoteHandler(m_remotePassword, m_remotePort); + bool res = m_remote->open(); + if (!res) { + delete m_remote; + m_remote = NULL; + } + } + + wxStopWatch stopWatch; + stopWatch.Start(); + + m_statusTimer.start(); + + try { + while (!m_killed) { + processIrcDDB(); + processG2(); +#if defined(DEXTRA_LINK) + processDExtra(); +#endif +#if defined(DCS_LINK) + processDCS(); +#endif + if (m_remote != NULL) + m_remote->process(); + + unsigned long ms = stopWatch.Time(); + stopWatch.Start(); + + m_statusTimer.clock(ms); + + CG2Handler::clock(ms); + CStarNetHandler::clock(ms); +#if defined(DEXTRA_LINK) + CDExtraHandler::clock(ms); +#endif +#if defined(DCS_LINK) + CDCSHandler::clock(ms); +#endif + + ::wxMilliSleep(TIME_PER_TIC_MS); + } + } + catch (std::exception& e) { + wxString message(e.what(), wxConvLocal); + wxLogError(wxT("Exception raised - \"%s\""), message.c_str()); + } + catch (...) { + wxLogError(wxT("Unknown exception raised")); + } + + wxLogMessage(wxT("Stopping the StarNet Server thread")); + +#if defined(DEXTRA_LINK) + // Unlink from all reflectors + CDExtraHandler::unlink(); + + m_dextraPool->close(); + delete m_dextraPool; +#endif + +#if defined(DCS_LINK) + // Unlink from all reflectors + CDCSHandler::unlink(); + + m_dcsPool->close(); + delete m_dcsPool; +#endif + + m_g2Handler->close(); + delete m_g2Handler; + + m_irc->close(); + delete m_irc; + + if (m_remote != NULL) { + m_remote->close(); + delete m_remote; + } + + if (headerLogger != NULL) { + headerLogger->close(); + delete headerLogger; + } +} + +void CStarNetServerThread::kill() +{ + m_killed = true; +} + +void CStarNetServerThread::setCallsign(const wxString& callsign) +{ + if (!m_stopped) + return; + + m_callsign = callsign; +} + +void CStarNetServerThread::setAddress(const wxString& address) +{ + m_address = address; +} + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) +void CStarNetServerThread::addStarNet(const wxString& callsign, const wxString& logoff, const wxString& repeater, const wxString& infoText, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch, const wxString& reflector) +{ + CStarNetHandler::add(callsign, logoff, repeater, infoText, permanent, userTimeout, groupTimeout, callsignSwitch, txMsgSwitch, reflector); +} +#else +void CStarNetServerThread::addStarNet(const wxString& callsign, const wxString& logoff, const wxString& repeater, const wxString& infoText, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch) +{ + CStarNetHandler::add(callsign, logoff, repeater, infoText, permanent, userTimeout, groupTimeout, callsignSwitch, txMsgSwitch); +} +#endif + +void CStarNetServerThread::setIRC(CIRCDDB* irc) +{ + wxASSERT(irc != NULL); + + m_irc = irc; +} + +void CStarNetServerThread::setLog(bool enabled) +{ + m_logEnabled = enabled; +} + +void CStarNetServerThread::setRemote(bool enabled, const wxString& password, unsigned int port) +{ + if (enabled) { + m_remoteEnabled = true; + m_remotePassword = password; + m_remotePort = port; + } else { + m_remoteEnabled = false; + m_remotePassword = password; + m_remotePort = REMOTE_DUMMY_PORT; + } +} + +void CStarNetServerThread::processIrcDDB() +{ + // Once per second + if (m_statusTimer.hasExpired()) { + int status = m_irc->getConnectionState(); + switch (status) { + case 0: + case 10: + if (m_lastStatus != IS_DISCONNECTED) { + wxLogInfo(wxT("Disconnected from ircDDB")); + m_lastStatus = IS_DISCONNECTED; + } + break; + case 7: + if (m_lastStatus != IS_CONNECTED) { + wxLogInfo(wxT("Connected to ircDDB")); + m_lastStatus = IS_CONNECTED; + } + break; + default: + if (m_lastStatus != IS_CONNECTING) { + wxLogInfo(wxT("Connecting to ircDDB")); + m_lastStatus = IS_CONNECTING; + } + break; + } + + m_statusTimer.start(); + } + + // Process all incoming ircDDB messages, updating the caches + for (;;) { + IRCDDB_RESPONSE_TYPE type = m_irc->getMessageType(); + + switch (type) { + case IDRT_NONE: + return; + + case IDRT_USER: { + wxString user, repeater, gateway, address, timestamp; + bool res = m_irc->receiveUser(user, repeater, gateway, address, timestamp); + if (!res) + break; + + if (!address.IsEmpty()) { + wxLogMessage(wxT("USER: %s %s %s %s"), user.c_str(), repeater.c_str(), gateway.c_str(), address.c_str()); + m_cache.updateUser(user, repeater, gateway, address, timestamp, DP_DEXTRA, false, false); + } else { + wxLogMessage(wxT("USER: %s NOT FOUND"), user.c_str()); + } + } + break; + + case IDRT_REPEATER: { + wxString repeater, gateway, address; + bool res = m_irc->receiveRepeater(repeater, gateway, address); + if (!res) + break; + + if (!address.IsEmpty()) { + wxLogMessage(wxT("REPEATER: %s %s %s"), repeater.c_str(), gateway.c_str(), address.c_str()); + m_cache.updateRepeater(repeater, gateway, address, DP_DEXTRA, false, false); + } else { + wxLogMessage(wxT("REPEATER: %s NOT FOUND"), repeater.c_str()); + } + } + break; + + case IDRT_GATEWAY: { + wxString gateway, address; + bool res = m_irc->receiveGateway(gateway, address); + if (!res) + break; + +#if defined(DEXTRA_LINK) + CDExtraHandler::gatewayUpdate(gateway, address); +#endif +#if defined(DCS_LINK) + CDCSHandler::gatewayUpdate(gateway, address); +#endif + + if (!address.IsEmpty()) { + wxLogMessage(wxT("GATEWAY: %s %s"), gateway.c_str(), address.c_str()); + m_cache.updateGateway(gateway, address, DP_DEXTRA, false, false); + } else { + wxLogMessage(wxT("GATEWAY: %s NOT FOUND"), gateway.c_str()); + } + } + break; + } + } +} + +#if defined(DEXTRA_LINK) +void CStarNetServerThread::processDExtra() +{ + for (;;) { + DEXTRA_TYPE type = m_dextraPool->read(); + + switch (type) { + case DE_NONE: + return; + + case DE_POLL: { + CPollData* poll = m_dextraPool->readPoll(); + if (poll != NULL) { + CDExtraHandler::process(*poll); + delete poll; + } + } + break; + + case DE_CONNECT: { + CConnectData* connect = m_dextraPool->readConnect(); + if (connect != NULL) { + CDExtraHandler::process(*connect); + delete connect; + } + } + break; + + case DE_HEADER: { + CHeaderData* header = m_dextraPool->readHeader(); + if (header != NULL) { + // wxLogMessage(wxT("DExtra header - My: %s/%s Your: %s Rpt1: %s Rpt2: %s"), header->getMyCall1().c_str(), header->getMyCall2().c_str(), header->getYourCall().c_str(), header->getRptCall1().c_str(), header->getRptCall2().c_str()); + CDExtraHandler::process(*header); + delete header; + } + } + break; + + case DE_AMBE: { + CAMBEData* data = m_dextraPool->readAMBE(); + if (data != NULL) { + CDExtraHandler::process(*data); + delete data; + } + } + break; + } + } +} +#endif + +#if defined(DCS_LINK) +void CStarNetServerThread::processDCS() +{ + for (;;) { + DCS_TYPE type = m_dcsPool->read(); + + switch (type) { + case DC_NONE: + return; + + case DC_POLL: { + CPollData* poll = m_dcsPool->readPoll(); + if (poll != NULL) { + CDCSHandler::process(*poll); + delete poll; + } + } + break; + + case DC_CONNECT: { + CConnectData* connect = m_dcsPool->readConnect(); + if (connect != NULL) { + CDCSHandler::process(*connect); + delete connect; + } + } + break; + + case DC_DATA: { + CAMBEData* data = m_dcsPool->readData(); + if (data != NULL) { + // wxLogMessage(wxT("DCS header - My: %s/%s Your: %s Rpt1: %s Rpt2: %s"), header->getMyCall1().c_str(), header->getMyCall2().c_str(), header->getYourCall().c_str(), header->getRptCall1().c_str(), header->getRptCall2().c_str()); + CDCSHandler::process(*data); + delete data; + } + } + break; + } + } +} +#endif + +void CStarNetServerThread::processG2() +{ + for (;;) { + G2_TYPE type = m_g2Handler->read(); + + switch (type) { + case GT_NONE: + return; + + case GT_HEADER: { + CHeaderData* header = m_g2Handler->readHeader(); + if (header != NULL) { + // wxLogMessage(wxT("G2 header - My: %s/%s Your: %s Rpt1: %s Rpt2: %s Flags: %02X %02X %02X"), header->getMyCall1().c_str(), header->getMyCall2().c_str(), header->getYourCall().c_str(), header->getRptCall1().c_str(), header->getRptCall2().c_str(), header->getFlag1(), header->getFlag2(), header->getFlag3()); + CG2Handler::process(*header); + delete header; + } + } + break; + + case GT_AMBE: { + CAMBEData* data = m_g2Handler->readAMBE(); + if (data != NULL) { + CG2Handler::process(*data); + delete data; + } + } + break; + } + } +} + +#if defined(DEXTRA_LINK) +void CStarNetServerThread::loadReflectors() +{ + wxFileName fileName(wxFileName::GetHomeDir(), DEXTRA_HOSTS_FILE_NAME); + + if (!fileName.IsFileReadable()) { + wxLogMessage(wxT("File %s not readable"), fileName.GetFullPath().c_str()); +#if defined(__WINDOWS__) + fileName.Assign(::wxGetCwd(), DEXTRA_HOSTS_FILE_NAME); +#else + fileName.Assign(wxT(DATA_DIR), DEXTRA_HOSTS_FILE_NAME); +#endif + if (!fileName.IsFileReadable()) + wxLogMessage(wxT("File %s not readable"), fileName.GetFullPath().c_str()); + } + + unsigned int count = 0U; + + CHostFile hostFile(fileName.GetFullPath(), true); + for (unsigned int i = 0U; i < hostFile.getCount(); i++) { + wxString reflector = hostFile.getName(i); + in_addr address = CUDPReaderWriter::lookup(hostFile.getAddress(i)); + bool lock = hostFile.getLock(i); + + if (address.s_addr != INADDR_NONE) { + unsigned char* ucp = (unsigned char*)&address; + + wxString addrText; + addrText.Printf(wxT("%u.%u.%u.%u"), ucp[0U] & 0xFFU, ucp[1U] & 0xFFU, ucp[2U] & 0xFFU, ucp[3U] & 0xFFU); + + if (lock) + wxLogMessage(wxT("Locking %s to %s"), reflector.c_str(), addrText.c_str()); + + reflector.Append(wxT(" ")); + reflector.Truncate(LONG_CALLSIGN_LENGTH - 1U); + reflector.Append(wxT("G")); + m_cache.updateGateway(reflector, addrText, DP_DEXTRA, lock, true); + + count++; + } + } + + wxLogMessage(wxT("Loaded %u of %u DExtra reflectors"), count, hostFile.getCount()); +} +#endif + +#if defined(DCS_LINK) +void CStarNetServerThread::loadReflectors() +{ + wxFileName fileName(wxFileName::GetHomeDir(), DCS_HOSTS_FILE_NAME); + + if (!fileName.IsFileReadable()) { + wxLogMessage(wxT("File %s not readable"), fileName.GetFullPath().c_str()); +#if defined(__WINDOWS__) + fileName.Assign(::wxGetCwd(), DCS_HOSTS_FILE_NAME); +#else + fileName.Assign(wxT(DATA_DIR), DCS_HOSTS_FILE_NAME); +#endif + if (!fileName.IsFileReadable()) + wxLogMessage(wxT("File %s not readable"), fileName.GetFullPath().c_str()); + } + + unsigned int count = 0U; + + CHostFile hostFile(fileName.GetFullPath(), true); + for (unsigned int i = 0U; i < hostFile.getCount(); i++) { + wxString reflector = hostFile.getName(i); + in_addr address = CUDPReaderWriter::lookup(hostFile.getAddress(i)); + bool lock = hostFile.getLock(i); + + if (address.s_addr != INADDR_NONE) { + unsigned char* ucp = (unsigned char*)&address; + + wxString addrText; + addrText.Printf(wxT("%u.%u.%u.%u"), ucp[0U] & 0xFFU, ucp[1U] & 0xFFU, ucp[2U] & 0xFFU, ucp[3U] & 0xFFU); + + if (lock) + wxLogMessage(wxT("Locking %s to %s"), reflector.c_str(), addrText.c_str()); + + reflector.Append(wxT(" ")); + reflector.Truncate(LONG_CALLSIGN_LENGTH - 1U); + reflector.Append(wxT("G")); + m_cache.updateGateway(reflector, addrText, DP_DCS, lock, true); + + count++; + } + } + + wxLogMessage(wxT("Loaded %u of %u DCS reflectors"), count, hostFile.getCount()); +} +#endif diff --git a/StarNetServer/StarNetServerThread.h b/StarNetServer/StarNetServerThread.h new file mode 100644 index 0000000..aac957a --- /dev/null +++ b/StarNetServer/StarNetServerThread.h @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2010,2011,2012,2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef StarNetServerThread_H +#define StarNetServerThread_H + +#include "DExtraProtocolHandlerPool.h" // DEXTRA_LINK +#include "DCSProtocolHandlerPool.h" // DCS_LINK +#include "G2ProtocolHandler.h" +#include "RemoteHandler.h" +#include "CacheManager.h" +#include "IRCDDB.h" +#include "Timer.h" +#include "Defs.h" + +#include + +class CStarNetServerThread { +public: + CStarNetServerThread(bool nolog, const wxString& logDir); + virtual ~CStarNetServerThread(); + + virtual void setCallsign(const wxString& callsign); + virtual void setAddress(const wxString& address); +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + virtual void addStarNet(const wxString& callsign, const wxString& logoff, const wxString& repeater, const wxString& infoText, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch, const wxString& reflector); +#else + virtual void addStarNet(const wxString& callsign, const wxString& logoff, const wxString& repeater, const wxString& infoText, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch); +#endif + virtual void setRemote(bool enabled, const wxString& password, unsigned int port); + virtual void setIRC(CIRCDDB* irc); + virtual void setLog(bool enabled); + + virtual void run(); + virtual void kill(); + +private: + bool m_nolog; + wxString m_logDir; + bool m_killed; + bool m_stopped; + wxString m_callsign; + wxString m_address; +#if defined(DEXTRA_LINK) + CDExtraProtocolHandlerPool* m_dextraPool; +#endif +#if defined(DCS_LINK) + CDCSProtocolHandlerPool* m_dcsPool; +#endif + CG2ProtocolHandler* m_g2Handler; + CIRCDDB* m_irc; + CCacheManager m_cache; + bool m_logEnabled; + CTimer m_statusTimer; + IRCDDB_STATUS m_lastStatus; + bool m_remoteEnabled; + wxString m_remotePassword; + unsigned int m_remotePort; + CRemoteHandler* m_remote; + + void processIrcDDB(); + void processG2(); +#if defined(DEXTRA_LINK) + void processDExtra(); + void loadReflectors(); +#endif +#if defined(DCS_LINK) + void processDCS(); + void loadReflectors(); +#endif +}; + +#endif diff --git a/StarNetServer/StarNetServerThreadHelper.cpp b/StarNetServer/StarNetServerThreadHelper.cpp new file mode 100644 index 0000000..e6bb482 --- /dev/null +++ b/StarNetServer/StarNetServerThreadHelper.cpp @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2012 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "StarNetServerThreadHelper.h" + +CStarNetServerThreadHelper::CStarNetServerThreadHelper(CStarNetServerThread* thread) : +wxThread(wxTHREAD_JOINABLE), +m_thread(thread) +{ + wxASSERT(thread != NULL); +} + +CStarNetServerThreadHelper::~CStarNetServerThreadHelper() +{ + delete m_thread; +} + +void CStarNetServerThreadHelper::start() +{ + Create(); + + SetPriority(100U); + + Run(); +} + +void* CStarNetServerThreadHelper::Entry() +{ + wxASSERT(m_thread != NULL); + + m_thread->run(); + + return NULL; +} + +void CStarNetServerThreadHelper::kill() +{ + wxASSERT(m_thread != NULL); + + m_thread->kill(); + + Wait(); +} diff --git a/StarNetServer/StarNetServerThreadHelper.h b/StarNetServer/StarNetServerThreadHelper.h new file mode 100644 index 0000000..17796e8 --- /dev/null +++ b/StarNetServer/StarNetServerThreadHelper.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2012,2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef StarNetServerThreadHelper_H +#define StarNetServerThreadHelper_H + +#include "StarNetServerThread.h" + +#include + +class CStarNetServerThreadHelper : public wxThread { + +public: + CStarNetServerThreadHelper(CStarNetServerThread* thread); + virtual ~CStarNetServerThreadHelper(); + + virtual void start(); + + virtual void* Entry(); + + virtual void kill(); + +private: + CStarNetServerThread* m_thread; +}; + +#endif diff --git a/TextTransmit/TextTransmit.cpp b/TextTransmit/TextTransmit.cpp new file mode 100644 index 0000000..091a8a0 --- /dev/null +++ b/TextTransmit/TextTransmit.cpp @@ -0,0 +1,209 @@ +/* + * Copyright (C) 2014 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "SlowDataEncoder.h" +#include "DStarDefines.h" +#include "TextTransmit.h" + +#include +#include + +const wxChar* REPEATER_PARAM = wxT("Repeater"); +const wxChar* FILE_OPTION = wxT("file"); +const wxChar* TEXT_OPTION = wxT("text"); + +int main(int argc, char** argv) +{ + bool res = ::wxInitialize(); + if (!res) { + ::fprintf(stderr, "texttransmit: failed to initialise the wxWidgets library, exiting\n"); + return 1; + } + + wxCmdLineParser parser(argc, argv); + parser.AddParam(REPEATER_PARAM, wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL); + parser.AddOption(TEXT_OPTION, wxEmptyString, wxEmptyString, wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL); + parser.AddOption(FILE_OPTION, wxEmptyString, wxEmptyString, wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL); + + int cmd = parser.Parse(); + if (cmd != 0) { + ::wxUninitialize(); + return 1; + } + + if (parser.GetParamCount() < 1U) { + ::fprintf(stderr, "texttransmit: invalid command line usage: texttransmit -text |-file , exiting\n"); + ::wxUninitialize(); + return 1; + } + + wxString text; + bool textFound = parser.Found(TEXT_OPTION, &text); + + wxString filename; + bool fileFound = parser.Found(FILE_OPTION, &filename); + + if (!textFound && !fileFound) { + ::fprintf(stderr, "texttransmit: invalid command line usage: texttransmit -text |-file , exiting\n"); + ::wxUninitialize(); + return 1; + } + + if (textFound && fileFound) { + ::fprintf(stderr, "texttransmit: invalid command line usage: texttransmit -text |-file , exiting\n"); + ::wxUninitialize(); + return 1; + } + + wxString repeater = parser.GetParam(0U); + repeater.Replace(wxT("_"), wxT(" ")); + repeater.resize(LONG_CALLSIGN_LENGTH, wxT(' ')); + repeater.MakeUpper(); + + if (fileFound) { + wxTextFile file; + bool found = file.Open(filename); + if (!found) { + ::fprintf(stderr, "texttransmit: unable to open the file, exiting\n"); + ::wxUninitialize(); + return 1; + } + + text = file.GetFirstLine(); + + file.Close(); + } + + text.resize(20U, wxT(' ')); + + CTextTransmit tt(repeater, text); + bool ret = tt.run(); + + ::wxUninitialize(); + + return ret ? 0 : 1; +} + +CTextTransmit::CTextTransmit(const wxString& callsign, const wxString& text) : +m_socket(wxEmptyString, 0U), +m_callsign(callsign), +m_text(text) +{ +} + +CTextTransmit::~CTextTransmit() +{ +} + +bool CTextTransmit::run() +{ + bool opened = m_socket.open(); + if (!opened) + return false; + + in_addr address = CUDPReaderWriter::lookup(wxT("127.0.0.1")); + + unsigned int id = CHeaderData::createId(); + + wxString callsignG = m_callsign.Left(LONG_CALLSIGN_LENGTH - 1U); + callsignG.Append(wxT("G")); + + CHeaderData header; + header.setId(id); + header.setMyCall1(m_callsign); + header.setMyCall2(wxT("INFO")); + header.setRptCall1(callsignG); + header.setRptCall2(m_callsign); + header.setYourCall(wxT("CQCQCQ ")); + header.setDestination(address, G2_DV_PORT); + + sendHeader(header); + + CSlowDataEncoder encoder; + encoder.setHeaderData(header); + encoder.setTextData(m_text); + + CAMBEData data; + data.setDestination(address, G2_DV_PORT); + data.setId(id); + + wxStopWatch timer; + timer.Start(); + + unsigned int out = 0U; + + for (;;) { + unsigned int needed = timer.Time() / DSTAR_FRAME_TIME_MS; + + while (out < needed) { + data.setSeq(out); + + unsigned char buffer[DV_FRAME_LENGTH_BYTES]; + ::memcpy(buffer + 0U, NULL_AMBE_DATA_BYTES, VOICE_FRAME_LENGTH_BYTES); + + // Insert sync bytes when the sequence number is zero, slow data otherwise + if (out == 0U) { + ::memcpy(buffer + VOICE_FRAME_LENGTH_BYTES, DATA_SYNC_BYTES, DATA_FRAME_LENGTH_BYTES); + encoder.sync(); + } else { + encoder.getTextData(buffer + VOICE_FRAME_LENGTH_BYTES); + } + + data.setData(buffer, DV_FRAME_LENGTH_BYTES); + + sendData(data); + out++; + + if (out == 21U) { + data.setData(END_PATTERN_BYTES, DV_FRAME_LENGTH_BYTES); + data.setSeq(0U); + data.setEnd(true); + + sendData(data); + + m_socket.close(); + + return true; + } + } + + ::wxMilliSleep(10UL); + } +} + +bool CTextTransmit::sendHeader(const CHeaderData& header) +{ + unsigned char buffer[60U]; + unsigned int length = header.getG2Data(buffer, 60U, true); + + for (unsigned int i = 0U; i < 2U; i++) { + bool res = m_socket.write(buffer, length, header.getYourAddress(), header.getYourPort()); + if (!res) + return false; + } + + return true; +} + +bool CTextTransmit::sendData(const CAMBEData& data) +{ + unsigned char buffer[40U]; + unsigned int length = data.getG2Data(buffer, 40U); + + return m_socket.write(buffer, length, data.getYourAddress(), data.getYourPort()); +} diff --git a/TextTransmit/TextTransmit.h b/TextTransmit/TextTransmit.h new file mode 100644 index 0000000..cd6e0a1 --- /dev/null +++ b/TextTransmit/TextTransmit.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2014 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef TextTransmit_H +#define TextTransmit_H + +#include "UDPReaderWriter.h" +#include "HeaderData.h" +#include "AMBEData.h" + +class CTextTransmit { +public: + CTextTransmit(const wxString& callsign, const wxString& text); + ~CTextTransmit(); + + bool run(); + +private: + CUDPReaderWriter m_socket; + wxString m_callsign; + wxString m_text; + + bool sendHeader(const CHeaderData& header); + bool sendData(const CAMBEData& data); +}; + +#endif diff --git a/TextTransmit/TextTransmit.vcxproj b/TextTransmit/TextTransmit.vcxproj new file mode 100644 index 0000000..9f636d8 --- /dev/null +++ b/TextTransmit/TextTransmit.vcxproj @@ -0,0 +1,185 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {AFB9BCE5-0D37-4707-93A1-DA14E39F2773} + TextTransmit + Win32Proj + 10.0.16299.0 + + + + Application + v141 + Unicode + true + + + Application + v141 + Unicode + true + + + Application + v141 + Unicode + + + Application + v141 + Unicode + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>14.0.24720.0 + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + true + $(WXWIN)\include;$(WXWIN)\lib\vc_dll\mswud;$(IncludePath) + + + true + $(WXWIN)\include;$(WXWIN)\lib\vc_x64_dll\mswud;$(IncludePath) + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + false + + + false + + + + Disabled + $(WXWIN)\include\msvc;$(WXWIN)\include;../Common;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;WINVER=0x0400;__WXMSW__;WXUSINGDLL;wxUSE_GUI=1;__WXDEBUG__;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATEWIN32;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + Level4 + EditAndContinue + + + ws2_32.lib;%(AdditionalDependencies) + $(WXWIN)\lib\vc_dll;%(AdditionalLibraryDirectories) + true + Console + MachineX86 + + + + + Disabled + $(WXWIN)\include\msvc;$(WXWIN)\include;../Common;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;WINVER=0x0400;__WXMSW__;WXUSINGDLL;wxUSE_GUI=1;__WXDEBUG__;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATEWIN32;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + + + Level4 + ProgramDatabase + + + ws2_32.lib;%(AdditionalDependencies) + $(WXWIN)\lib\vc_x64_dll;%(AdditionalLibraryDirectories) + true + Console + + + + + MaxSpeed + true + $(WXWIN)\include\msvc;$(WXWIN)\include;../ircDDB;../Common;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;WINVER=0x0400;__WXMSW__;WXUSINGDLL;wxUSE_GUI=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) + MultiThreadedDLL + true + + Level3 + ProgramDatabase + + + ws2_32.lib;%(AdditionalDependencies) + $(WXWIN)\lib\vc_dll;%(AdditionalLibraryDirectories) + true + Console + true + true + MachineX86 + + + + + MaxSpeed + true + $(WXWIN)\include\msvc;$(WXWIN)\include;../ircDDB;../Common;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;WINVER=0x0400;__WXMSW__;WXUSINGDLL;wxUSE_GUI=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) + MultiThreadedDLL + true + + + Level3 + ProgramDatabase + + + ws2_32.lib;%(AdditionalDependencies) + $(WXWIN)\lib\vc_x64_dll;%(AdditionalLibraryDirectories) + true + Console + true + true + + + + + + + + + + + {e793cb8e-2ac9-431a-bbfc-3f52537bb3cf} + false + + + + + + \ No newline at end of file diff --git a/TextTransmit/TextTransmit.vcxproj.filters b/TextTransmit/TextTransmit.vcxproj.filters new file mode 100644 index 0000000..a917404 --- /dev/null +++ b/TextTransmit/TextTransmit.vcxproj.filters @@ -0,0 +1,23 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + + + Source Files + + + + + Header Files + + + \ No newline at end of file diff --git a/TimeServer/TimeServer.vcxproj b/TimeServer/TimeServer.vcxproj new file mode 100644 index 0000000..ff96b71 --- /dev/null +++ b/TimeServer/TimeServer.vcxproj @@ -0,0 +1,206 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {99F336A5-6E33-4919-BF75-D6D8BA26345E} + TimeServer + Win32Proj + 10.0.16299.0 + + + + Application + v141 + Unicode + true + + + Application + v141 + Unicode + true + + + Application + v141 + Unicode + + + Application + v141 + Unicode + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>14.0.24720.0 + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + true + $(WXWIN)\include;$(WXWIN)\lib\vc_dll\mswud;$(IncludePath) + + + true + $(WXWIN)\include;$(WXWIN)\lib\vc_x64_dll\mswud;$(IncludePath) + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + false + + + false + + + + Disabled + $(WXWIN)\include\msvc;$(WXWIN)\include;../Common;../GUICommon;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;WINVER=0x0400;__WXMSW__;WXUSINGDLL;wxUSE_GUI=1;__WXDEBUG__;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + Level4 + EditAndContinue + + + ws2_32.lib;%(AdditionalDependencies) + $(WXWIN)\lib\vc_dll;%(AdditionalLibraryDirectories) + true + Windows + MachineX86 + + + + + Disabled + $(WXWIN)\include\msvc;$(WXWIN)\include;../Common;../GUICommon;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;WINVER=0x0400;__WXMSW__;WXUSINGDLL;wxUSE_GUI=1;__WXDEBUG__;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + + + Level4 + ProgramDatabase + + + ws2_32.lib;%(AdditionalDependencies) + $(WXWIN)\lib\vc_x64_dll;%(AdditionalLibraryDirectories) + true + Windows + + + + + MaxSpeed + true + $(WXWIN)\include\msvc;$(WXWIN)\include;../Common;../GUICommon;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;WINVER=0x0400;__WXMSW__;WXUSINGDLL;wxUSE_GUI=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) + MultiThreadedDLL + true + + Level3 + ProgramDatabase + + + ws2_32.lib;%(AdditionalDependencies) + $(WXWIN)\lib\vc_dll;%(AdditionalLibraryDirectories) + true + Windows + true + true + MachineX86 + + + + + MaxSpeed + true + $(WXWIN)\include\msvc;$(WXWIN)\include;../Common;../GUICommon;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;WINVER=0x0400;__WXMSW__;WXUSINGDLL;wxUSE_GUI=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) + MultiThreadedDLL + true + + + Level3 + ProgramDatabase + + + ws2_32.lib;%(AdditionalDependencies) + $(WXWIN)\lib\vc_x64_dll;%(AdditionalLibraryDirectories) + true + Windows + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + {e793cb8e-2ac9-431a-bbfc-3f52537bb3cf} + false + + + {02d03515-0bbe-4553-8c40-566a597478f8} + false + + + + + + \ No newline at end of file diff --git a/TimeServer/TimeServer.vcxproj.filters b/TimeServer/TimeServer.vcxproj.filters new file mode 100644 index 0000000..d6e951c --- /dev/null +++ b/TimeServer/TimeServer.vcxproj.filters @@ -0,0 +1,74 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/TimeServer/TimeServerAnnouncementsSet.cpp b/TimeServer/TimeServerAnnouncementsSet.cpp new file mode 100644 index 0000000..37bbd22 --- /dev/null +++ b/TimeServer/TimeServerAnnouncementsSet.cpp @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2012,2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "TimeServerAnnouncementsSet.h" +#include "DStarDefines.h" + +const unsigned int BORDER_SIZE = 5U; +const unsigned int CONTROL_WIDTH = 150U; + +CTimeServerAnnouncementsSet::CTimeServerAnnouncementsSet(wxWindow* parent, int id, const wxString& title, LANGUAGE language, FORMAT format, INTERVAL interval) : +wxPanel(parent, id), +m_title(title), +m_language(NULL), +m_format(NULL), +m_interval(NULL) +{ + wxFlexGridSizer* sizer = new wxFlexGridSizer(2); + + wxStaticText* languageLabel = new wxStaticText(this, -1, _("Language")); + sizer->Add(languageLabel, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + m_language = new wxChoice(this, -1, wxDefaultPosition, wxSize(CONTROL_WIDTH, -1)); + m_language->Append(wxT("English 1 (UK)")); + m_language->Append(wxT("English 2 (UK)")); + m_language->Append(wxT("English 1 (US)")); + m_language->Append(wxT("English 2 (US)")); + m_language->Append(wxT("Deutsch 1")); + m_language->Append(wxT("Deutsch 2")); + m_language->Append(wxT("Francais")); + m_language->Append(wxT("Nederlands")); + m_language->Append(wxT("Svenska")); + m_language->Append(wxT("Espanol")); + m_language->Append(wxT("Norsk")); + m_language->Append(wxT("Portugues")); + sizer->Add(m_language, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + m_language->SetSelection(int(language)); + + wxStaticText* formatLabel = new wxStaticText(this, -1, _("Format")); + sizer->Add(formatLabel, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + + m_format = new wxChoice(this, -1, wxDefaultPosition, wxSize(CONTROL_WIDTH, -1)); + m_format->Append(_("Voice, time only")); + m_format->Append(_("Voice, callsign + time")); + m_format->Append(_("Text, time only")); + sizer->Add(m_format, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + m_format->SetSelection(int(format)); + + wxStaticText* intervalLabel = new wxStaticText(this, -1, _("Interval")); + sizer->Add(intervalLabel, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + + m_interval = new wxChoice(this, -1, wxDefaultPosition, wxSize(CONTROL_WIDTH, -1)); + m_interval->Append(_("Every 15 minutes")); + m_interval->Append(_("Every 30 minutes")); + m_interval->Append(_("Every hour")); + sizer->Add(m_interval, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + m_interval->SetSelection(int(interval)); + + SetAutoLayout(true); + + SetSizer(sizer); +} + + +CTimeServerAnnouncementsSet::~CTimeServerAnnouncementsSet() +{ +} + +bool CTimeServerAnnouncementsSet::Validate() +{ + if (m_language->GetCurrentSelection() == wxNOT_FOUND) + return false; + + return m_interval->GetCurrentSelection() != wxNOT_FOUND; +} + +LANGUAGE CTimeServerAnnouncementsSet::getLanguage() const +{ + int n = m_language->GetCurrentSelection(); + if (n == wxNOT_FOUND) + return LANG_ENGLISH_UK_1; + + return LANGUAGE(n); +} + +FORMAT CTimeServerAnnouncementsSet::getFormat() const +{ + int n = m_format->GetCurrentSelection(); + if (n == wxNOT_FOUND) + return FORMAT_VOICE_TIME; + + return FORMAT(n); +} + +INTERVAL CTimeServerAnnouncementsSet::getInterval() const +{ + int n = m_interval->GetCurrentSelection(); + if (n == wxNOT_FOUND) + return INTERVAL_15MINS; + + return INTERVAL(n); +} diff --git a/TimeServer/TimeServerAnnouncementsSet.h b/TimeServer/TimeServerAnnouncementsSet.h new file mode 100644 index 0000000..621ec8e --- /dev/null +++ b/TimeServer/TimeServerAnnouncementsSet.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2012 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef TimeServerAnnouncementsSet_H +#define TimeServerAnnouncementsSet_H + +#include "TimeServerDefs.h" + +#include + +class CTimeServerAnnouncementsSet : public wxPanel { +public: + CTimeServerAnnouncementsSet(wxWindow* parent, int id, const wxString& title, LANGUAGE language, FORMAT format, INTERVAL interval); + virtual ~CTimeServerAnnouncementsSet(); + + virtual bool Validate(); + + virtual LANGUAGE getLanguage() const; + + virtual FORMAT getFormat() const; + + virtual INTERVAL getInterval() const; + +private: + wxString m_title; + wxChoice* m_language; + wxChoice* m_format; + wxChoice* m_interval; +}; + +#endif diff --git a/TimeServer/TimeServerApp.cpp b/TimeServer/TimeServerApp.cpp new file mode 100644 index 0000000..f1ec9f6 --- /dev/null +++ b/TimeServer/TimeServerApp.cpp @@ -0,0 +1,241 @@ +/* + * Copyright (C) 2012,2014,2015 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "TimeServerLogRedirect.h" +#include "TimeServerThread.h" +#include "TimeServerApp.h" +#include "Version.h" +#include "Logger.h" + +#include +#include +#include + +IMPLEMENT_APP(CTimeServerApp) + +const wxChar* NAME_PARAM = wxT("Name"); +const wxChar* NOLOGGING_SWITCH = wxT("nolog"); +const wxChar* GUI_SWITCH = wxT("gui"); +const wxChar* LOGDIR_OPTION = wxT("logdir"); +const wxChar* CONFDIR_OPTION = wxT("confdir"); + +static const wxString LOG_BASE_NAME ="timeserver"; + +CTimeServerApp::CTimeServerApp() : +wxApp(), +m_name(), +m_nolog(false), +m_gui(false), +m_logDir(), +m_confDir(), +m_frame(NULL), +m_thread(NULL), +m_config(NULL), +m_logChain(NULL) +{ +} + +CTimeServerApp::~CTimeServerApp() +{ +} + +bool CTimeServerApp::OnInit() +{ + SetVendorName(VENDOR_NAME); + + if (!wxApp::OnInit()) + return false; + + if (!m_nolog) { + wxString logBaseName = LOG_BASE_NAME; + if (!m_name.IsEmpty()) { + logBaseName.Append(wxT("_")); + logBaseName.Append(m_name); + } + +#if defined(__WINDOWS__) + if (m_logDir.IsEmpty()) + m_logDir = wxFileName::GetHomeDir(); +#else + if (m_logDir.IsEmpty()) + m_logDir = wxT(LOG_DIR); +#endif + + wxLog* log = new CLogger(m_logDir, logBaseName); + wxLog::SetActiveTarget(log); + } else { + new wxLogNull; + } + + m_logChain = new wxLogChain(new CTimeServerLogRedirect); + +#if defined(__WINDOWS__) + m_config = new CTimeServerConfig(new wxConfig(APPLICATION_NAME), m_name); +#else + if (m_confDir.IsEmpty()) + m_confDir = wxT(CONF_DIR); + + m_config = new CTimeServerConfig(m_confDir, m_name); +#endif + + wxString frameName = APPLICATION_NAME + wxT(" - "); + if (!m_name.IsEmpty()) { + frameName.Append(m_name); + frameName.Append(wxT(" - ")); + } + frameName.Append(VERSION); + + wxPoint position = wxDefaultPosition; + + int x, y; + getPosition(x, y); + if (x >= 0 && y >= 0) + position = wxPoint(x, y); + + m_frame = new CTimeServerFrame(frameName, position, m_gui); + m_frame->Show(); + + SetTopWindow(m_frame); + + wxLogInfo(wxT("Starting ") + APPLICATION_NAME + wxT(" - ") + VERSION); + + // Log the version of wxWidgets and the Operating System + wxLogInfo(wxT("Using wxWidgets %d.%d.%d on %s"), wxMAJOR_VERSION, wxMINOR_VERSION, wxRELEASE_NUMBER, ::wxGetOsDescription().c_str()); + + createThread(); + + return true; +} + +int CTimeServerApp::OnExit() +{ + m_logChain->SetLog(NULL); + + wxLogInfo(APPLICATION_NAME + wxT(" is exiting")); + + m_thread->kill(); + + delete m_config; + + return 0; +} + +void CTimeServerApp::OnInitCmdLine(wxCmdLineParser& parser) +{ + parser.AddSwitch(NOLOGGING_SWITCH, wxEmptyString, wxEmptyString, wxCMD_LINE_PARAM_OPTIONAL); + parser.AddSwitch(GUI_SWITCH, wxEmptyString, wxEmptyString, wxCMD_LINE_PARAM_OPTIONAL); + parser.AddOption(LOGDIR_OPTION, wxEmptyString, wxEmptyString, wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL); + parser.AddOption(CONFDIR_OPTION, wxEmptyString, wxEmptyString, wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL); + parser.AddParam(NAME_PARAM, wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL); + + wxApp::OnInitCmdLine(parser); +} + +bool CTimeServerApp::OnCmdLineParsed(wxCmdLineParser& parser) +{ + if (!wxApp::OnCmdLineParsed(parser)) + return false; + + m_nolog = parser.Found(NOLOGGING_SWITCH); + m_gui = parser.Found(GUI_SWITCH); + + wxString logDir; + bool found = parser.Found(LOGDIR_OPTION, &logDir); + if (found) + m_logDir = logDir; + + wxString confDir; + found = parser.Found(CONFDIR_OPTION, &confDir); + if (found) + m_confDir = confDir; + + if (parser.GetParamCount() > 0U) + m_name = parser.GetParam(0U); + + return true; +} + +#if defined(__WXDEBUG__) +void CTimeServerApp::OnAssertFailure(const wxChar* file, int line, const wxChar* func, const wxChar* cond, const wxChar* msg) +{ + wxLogFatalError(wxT("Assertion failed on line %d in file %s and function %s: %s %s"), line, file, func, cond, msg); +} +#endif + +void CTimeServerApp::showLog(const wxString& text) +{ + m_frame->showLog(text); +} + +void CTimeServerApp::getGateway(wxString& callsign, bool& sendA, bool& sendB, bool& sendC, bool& sendD, bool& sendE, wxString& address) const +{ + m_config->getGateway(callsign, sendA, sendB, sendC, sendD, sendE, address); +} + +void CTimeServerApp::setGateway(const wxString& callsign, bool sendA, bool sendB, bool sendC, bool sendD, bool sendE, const wxString& address) +{ + m_config->setGateway(callsign, sendA, sendB, sendC, sendD, sendE, address); +} + +void CTimeServerApp::getAnnouncements(LANGUAGE& language, FORMAT& format, INTERVAL& interval) const +{ + m_config->getAnnouncements(language, format, interval); +} + +void CTimeServerApp::setAnnouncements(LANGUAGE language, FORMAT format, INTERVAL interval) +{ + m_config->setAnnouncements(language, format, interval); +} + +void CTimeServerApp::getPosition(int& x, int& y) const +{ + m_config->getPosition(x, y); +} + +void CTimeServerApp::setPosition(int x, int y) +{ + m_config->setPosition(x, y); +} + +bool CTimeServerApp::writeConfig() +{ + return m_config->write(); +} + +void CTimeServerApp::createThread() +{ + CTimeServerThread* thread = new CTimeServerThread; + + wxString callsign, address; + bool sendA, sendB, sendC, sendD, sendE; + getGateway(callsign, sendA, sendB, sendC, sendD, sendE, address); + callsign.MakeUpper(); + thread->setGateway(callsign, sendA, sendB, sendC, sendD, sendE, address); + wxLogInfo(wxT("Callsign set to %s, module %s%s%s%s, address: %s"), callsign.c_str(), sendA ? wxT("A") : wxT(""), sendB ? wxT("B") : wxT(""), sendC ? wxT("C") : wxT(""), sendD ? wxT("D") : wxT(""), sendE ? wxT("E") : wxT(""), address.c_str()); + + LANGUAGE language; + FORMAT format; + INTERVAL interval; + getAnnouncements(language, format, interval); + thread->setAnnouncements(language, format, interval); + wxLogInfo(wxT("Language: %d, format: %d, interval: %d"), int(language), int(format), int(interval)); + + // Convert the worker class into a thread + m_thread = new CTimeServerThreadHelper(thread); + m_thread->start(); +} diff --git a/TimeServer/TimeServerApp.h b/TimeServer/TimeServerApp.h new file mode 100644 index 0000000..d232786 --- /dev/null +++ b/TimeServer/TimeServerApp.h @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2012 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef TimeServerApp_H +#define TimeServerApp_H + +#include "TimeServerThreadHelper.h" +#include "TimeServerConfig.h" +#include "TimeServerFrame.h" +#include "TimeServerDefs.h" + +#include + +class CTimeServerApp : public wxApp { + +public: + CTimeServerApp(); + virtual ~CTimeServerApp(); + + virtual bool OnInit(); + virtual int OnExit(); + + virtual void OnInitCmdLine(wxCmdLineParser& parser); + virtual bool OnCmdLineParsed(wxCmdLineParser& parser); + + // This is overridden because dialog boxes from threads are bad news +#if defined(__WXDEBUG__) + virtual void OnAssertFailure(const wxChar* file, int line, const wxChar* func, const wxChar* cond, const wxChar* msg); +#endif + + virtual void showLog(const wxString& text); + + virtual void getGateway(wxString& callsign, bool& sendA, bool& sendB, bool& sendC, bool& sendD, bool& sendE, wxString& address) const; + virtual void setGateway(const wxString& callsign, bool sendA, bool sendB, bool sendC, bool sendD, bool sendE, const wxString& address); + + virtual void getAnnouncements(LANGUAGE& language, FORMAT& format, INTERVAL& interval) const; + virtual void setAnnouncements(LANGUAGE language, FORMAT format, INTERVAL interval); + + virtual void getPosition(int& x, int& y) const; + virtual void setPosition(int x, int y); + + virtual bool writeConfig(); + +private: + wxString m_name; + bool m_nolog; + bool m_gui; + wxString m_logDir; + wxString m_confDir; + CTimeServerFrame* m_frame; + CTimeServerThreadHelper* m_thread; + CTimeServerConfig* m_config; + wxLogChain* m_logChain; + + void createThread(); +}; + +DECLARE_APP(CTimeServerApp) + +#endif diff --git a/TimeServer/TimeServerConfig.cpp b/TimeServer/TimeServerConfig.cpp new file mode 100644 index 0000000..17a71a1 --- /dev/null +++ b/TimeServer/TimeServerConfig.cpp @@ -0,0 +1,331 @@ +/* + * Copyright (C) 2012 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "TimeServerConfig.h" + +const wxString KEY_CALLSIGN = wxT("callsign"); +const wxString KEY_SENDA = wxT("sendA"); +const wxString KEY_SENDB = wxT("sendB"); +const wxString KEY_SENDC = wxT("sendC"); +const wxString KEY_SENDD = wxT("sendD"); +const wxString KEY_SENDE = wxT("sendE"); +const wxString KEY_ADDRESS = wxT("address"); +const wxString KEY_LANGUAGE = wxT("language"); +const wxString KEY_FORMAT = wxT("format"); +const wxString KEY_INTERVAL = wxT("interval"); +const wxString KEY_WINDOW_X = wxT("windowX"); +const wxString KEY_WINDOW_Y = wxT("windowY"); + + +const wxString DEFAULT_CALLSIGN = wxEmptyString; +const bool DEFAULT_SENDA = false; +const bool DEFAULT_SENDB = false; +const bool DEFAULT_SENDC = false; +const bool DEFAULT_SENDD = false; +const bool DEFAULT_SENDE = false; +const wxString DEFAULT_ADDRESS = wxT("127.0.0.1"); +const LANGUAGE DEFAULT_LANGUAGE = LANG_ENGLISH_UK_1; +const FORMAT DEFAULT_FORMAT = FORMAT_VOICE_TIME; +const INTERVAL DEFAULT_INTERVAL = INTERVAL_15MINS; +const int DEFAULT_WINDOW_X = -1; +const int DEFAULT_WINDOW_Y = -1; + + +#if defined(__WINDOWS__) + +CTimeServerConfig::CTimeServerConfig(wxConfigBase* config, const wxString& name) : +m_config(config), +m_name(wxT("/")), +m_callsign(DEFAULT_CALLSIGN), +m_sendA(DEFAULT_SENDA), +m_sendB(DEFAULT_SENDB), +m_sendC(DEFAULT_SENDC), +m_sendD(DEFAULT_SENDD), +m_sendE(DEFAULT_SENDE), +m_address(DEFAULT_ADDRESS), +m_language(DEFAULT_LANGUAGE), +m_format(DEFAULT_FORMAT), +m_interval(DEFAULT_INTERVAL), +m_x(DEFAULT_WINDOW_X), +m_y(DEFAULT_WINDOW_Y) +{ + wxASSERT(config != NULL); + + if (!name.IsEmpty()) + m_name = wxT("/") + name + wxT("/"); + + m_config->Read(m_name + KEY_CALLSIGN, &m_callsign, DEFAULT_CALLSIGN); + + m_config->Read(m_name + KEY_SENDA, &m_sendA, DEFAULT_SENDA); + + m_config->Read(m_name + KEY_SENDB, &m_sendB, DEFAULT_SENDB); + + m_config->Read(m_name + KEY_SENDC, &m_sendC, DEFAULT_SENDC); + + m_config->Read(m_name + KEY_SENDD, &m_sendD, DEFAULT_SENDD); + + m_config->Read(m_name + KEY_SENDE, &m_sendE, DEFAULT_SENDE); + + m_config->Read(m_name + KEY_ADDRESS, &m_address, DEFAULT_ADDRESS); + + long temp; + m_config->Read(m_name + KEY_LANGUAGE, &temp, long(DEFAULT_LANGUAGE)); + m_language = LANGUAGE(temp); + + m_config->Read(m_name + KEY_FORMAT, &temp, long(DEFAULT_FORMAT)); + m_format = FORMAT(temp); + + m_config->Read(m_name + KEY_INTERVAL, &temp, long(DEFAULT_INTERVAL)); + m_interval = INTERVAL(temp); + + m_config->Read(m_name + KEY_WINDOW_X, &temp, long(DEFAULT_WINDOW_X)); + m_x = int(temp); + + m_config->Read(m_name + KEY_WINDOW_Y, &temp, long(DEFAULT_WINDOW_Y)); + m_y = int(temp); +} + +CTimeServerConfig::~CTimeServerConfig() +{ + delete m_config; +} + +#else + +CTimeServerConfig::CTimeServerConfig(const wxString& dir, const wxString& name) : +m_fileName(), +m_callsign(DEFAULT_CALLSIGN), +m_sendA(DEFAULT_SENDA), +m_sendB(DEFAULT_SENDB), +m_sendC(DEFAULT_SENDC), +m_sendD(DEFAULT_SENDD), +m_sendE(DEFAULT_SENDE), +m_address(DEFAULT_ADDRESS), +m_language(DEFAULT_LANGUAGE), +m_format(DEFAULT_FORMAT), +m_interval(DEFAULT_INTERVAL), +m_x(DEFAULT_WINDOW_X), +m_y(DEFAULT_WINDOW_Y) +{ + wxASSERT(!dir.IsEmpty()); + + wxString fileName = CONFIG_FILE_NAME; + if (!name.IsEmpty()) + fileName = CONFIG_FILE_NAME + wxT("_") + name; + + m_fileName.Assign(dir, fileName); + + wxTextFile file(m_fileName.GetFullPath()); + + bool exists = file.Exists(); + if (!exists) + return; + + bool ret = file.Open(); + if (!ret) { + wxLogError(wxT("Cannot open the config file - %s"), m_fileName.GetFullPath().c_str()); + return; + } + + long temp; + + wxString str = file.GetFirstLine(); + + while (!file.Eof()) { + if (str.GetChar(0U) == wxT('#')) { + str = file.GetNextLine(); + continue; + } + + int n = str.Find(wxT('=')); + if (n == wxNOT_FOUND) { + str = file.GetNextLine(); + continue; + } + + wxString key = str.Left(n); + wxString val = str.Mid(n + 1U); + + if (key.IsSameAs(KEY_CALLSIGN)) { + m_callsign = val; + } else if (key.IsSameAs(KEY_SENDA)) { + val.ToLong(&temp); + m_sendA = temp == 1L; + } else if (key.IsSameAs(KEY_SENDB)) { + val.ToLong(&temp); + m_sendB = temp == 1L; + } else if (key.IsSameAs(KEY_SENDC)) { + val.ToLong(&temp); + m_sendC = temp == 1L; + } else if (key.IsSameAs(KEY_SENDD)) { + val.ToLong(&temp); + m_sendD = temp == 1L; + } else if (key.IsSameAs(KEY_SENDE)) { + val.ToLong(&temp); + m_sendE = temp == 1L; + } else if (key.IsSameAs(KEY_ADDRESS)) { + m_address = val; + } else if (key.IsSameAs(KEY_LANGUAGE)) { + val.ToLong(&temp); + m_language = LANGUAGE(temp); + } else if (key.IsSameAs(KEY_FORMAT)) { + val.ToLong(&temp); + m_format = FORMAT(temp); + } else if (key.IsSameAs(KEY_INTERVAL)) { + val.ToLong(&temp); + m_interval = INTERVAL(temp); + } else if (key.IsSameAs(KEY_WINDOW_X)) { + val.ToLong(&temp); + m_x = int(temp); + } else if (key.IsSameAs(KEY_WINDOW_Y)) { + val.ToLong(&temp); + m_y = int(temp); + } + + str = file.GetNextLine(); + } + + file.Close(); +} + +CTimeServerConfig::~CTimeServerConfig() +{ +} + +#endif + +void CTimeServerConfig::getGateway(wxString& callsign, bool& sendA, bool& sendB, bool& sendC, bool& sendD, bool& sendE, wxString& address) const +{ + callsign = m_callsign; + sendA = m_sendA; + sendB = m_sendB; + sendC = m_sendC; + sendD = m_sendD; + sendE = m_sendE; + address = m_address; +} + +void CTimeServerConfig::setGateway(const wxString& callsign, bool sendA, bool sendB, bool sendC, bool sendD, bool sendE, const wxString& address) +{ + m_callsign = callsign; + m_sendA = sendA; + m_sendB = sendB; + m_sendC = sendC; + m_sendD = sendD; + m_sendE = sendE; + m_address = address; +} + +void CTimeServerConfig::getAnnouncements(LANGUAGE& language, FORMAT& format, INTERVAL& interval) const +{ + language = m_language; + format = m_format; + interval = m_interval; +} + +void CTimeServerConfig::setAnnouncements(LANGUAGE language, FORMAT format, INTERVAL interval) +{ + m_language = language; + m_format = format; + m_interval = interval; +} + +void CTimeServerConfig::getPosition(int& x, int& y) const +{ + x = m_x; + y = m_y; +} + +void CTimeServerConfig::setPosition(int x, int y) +{ + m_x = x; + m_y = y; +} + +#if defined(__WINDOWS__) + +bool CTimeServerConfig::write() +{ + m_config->Write(m_name + KEY_CALLSIGN, m_callsign); + m_config->Write(m_name + KEY_SENDA, m_sendA); + m_config->Write(m_name + KEY_SENDB, m_sendB); + m_config->Write(m_name + KEY_SENDC, m_sendC); + m_config->Write(m_name + KEY_SENDD, m_sendD); + m_config->Write(m_name + KEY_SENDE, m_sendE); + m_config->Write(m_name + KEY_ADDRESS, m_address); + m_config->Write(m_name + KEY_LANGUAGE, long(m_language)); + m_config->Write(m_name + KEY_FORMAT, long(m_format)); + m_config->Write(m_name + KEY_INTERVAL, long(m_interval)); + m_config->Write(m_name + KEY_WINDOW_X, long(m_x)); + m_config->Write(m_name + KEY_WINDOW_Y, long(m_y)); + m_config->Flush(); + + return true; +} + +#else + +bool CTimeServerConfig::write() +{ + wxTextFile file(m_fileName.GetFullPath()); + + bool exists = file.Exists(); + if (exists) { + bool ret = file.Open(); + if (!ret) { + wxLogError(wxT("Cannot open the config file - %s"), m_fileName.GetFullPath().c_str()); + return false; + } + + // Remove the existing file entries + file.Clear(); + } else { + bool ret = file.Create(); + if (!ret) { + wxLogError(wxT("Cannot create the config file - %s"), m_fileName.GetFullPath().c_str()); + return false; + } + } + + wxString buffer; + buffer.Printf(wxT("%s=%s"), KEY_CALLSIGN.c_str(), m_callsign.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%d"), KEY_SENDA.c_str(), m_sendA ? 1 : 0); file.AddLine(buffer); + buffer.Printf(wxT("%s=%d"), KEY_SENDB.c_str(), m_sendB ? 1 : 0); file.AddLine(buffer); + buffer.Printf(wxT("%s=%d"), KEY_SENDC.c_str(), m_sendC ? 1 : 0); file.AddLine(buffer); + buffer.Printf(wxT("%s=%d"), KEY_SENDD.c_str(), m_sendD ? 1 : 0); file.AddLine(buffer); + buffer.Printf(wxT("%s=%d"), KEY_SENDE.c_str(), m_sendE ? 1 : 0); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_ADDRESS.c_str(), m_address.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%d"), KEY_LANGUAGE.c_str(), int(m_language)); file.AddLine(buffer); + buffer.Printf(wxT("%s=%d"), KEY_FORMAT.c_str(), int(m_format)); file.AddLine(buffer); + buffer.Printf(wxT("%s=%d"), KEY_INTERVAL.c_str(), int(m_interval)); file.AddLine(buffer); + buffer.Printf(wxT("%s=%d"), KEY_WINDOW_X.c_str(), m_x); file.AddLine(buffer); + buffer.Printf(wxT("%s=%d"), KEY_WINDOW_Y.c_str(), m_y); file.AddLine(buffer); + + bool ret = file.Write(); + if (!ret) { + file.Close(); + wxLogError(wxT("Cannot write the config file - %s"), m_fileName.GetFullPath().c_str()); + return false; + } + + file.Close(); + + return true; +} + +#endif diff --git a/TimeServer/TimeServerConfig.h b/TimeServer/TimeServerConfig.h new file mode 100644 index 0000000..869ed11 --- /dev/null +++ b/TimeServer/TimeServerConfig.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2012 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef TimeServerConfig_H +#define TimeServerConfig_H + +#include "TimeServerDefs.h" + +#include +#include +#include + +class CTimeServerConfig { +public: +#if defined(__WINDOWS__) + CTimeServerConfig(wxConfigBase* config, const wxString& name); +#else + CTimeServerConfig(const wxString& dir, const wxString& name); +#endif + ~CTimeServerConfig(); + + void getGateway(wxString& callsign, bool& sendA, bool& sendB, bool& sendC, bool& sendD, bool& sendE, wxString& address) const; + void setGateway(const wxString& callsign, bool sendA, bool sendB, bool sendC, bool sendD, bool sendE, const wxString& address); + + void getAnnouncements(LANGUAGE& language, FORMAT& format, INTERVAL& interval) const; + void setAnnouncements(LANGUAGE language, FORMAT format, INTERVAL interval); + + void getPosition(int& x, int& y) const; + void setPosition(int x, int y); + + bool write(); + +private: +#if defined(__WINDOWS__) + wxConfigBase* m_config; + wxString m_name; +#else + wxFileName m_fileName; +#endif + wxString m_callsign; + bool m_sendA; + bool m_sendB; + bool m_sendC; + bool m_sendD; + bool m_sendE; + wxString m_address; + LANGUAGE m_language; + FORMAT m_format; + INTERVAL m_interval; + int m_x; + int m_y; +}; + +#endif diff --git a/TimeServer/TimeServerD.cpp b/TimeServer/TimeServerD.cpp new file mode 100644 index 0000000..4ede2cc --- /dev/null +++ b/TimeServer/TimeServerD.cpp @@ -0,0 +1,180 @@ +/* + * Copyright (C) 2012-2015 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "TimeServerConfig.h" +#include "TimeServerD.h" +#include "Version.h" +#include "Logger.h" + +#include +#include +#include +#include + +#include +#include +#include + +const wxChar* NAME_PARAM = wxT("Name"); +const wxChar* NOLOGGING_SWITCH = wxT("nolog"); +const wxChar* LOGDIR_OPTION = wxT("logdir"); +const wxChar* CONFDIR_OPTION = wxT("confdir"); +const wxChar* DAEMON_SWITCH = wxT("daemon"); + +static const wxString LOG_BASE_NAME = "timeserverd"; + +int main(int argc, char** argv) +{ + bool res = ::wxInitialize(); + if (!res) { + ::fprintf(stderr, "timeserverd: failed to initialise the wxWidgets library, exiting\n"); + return -1; + } + + wxCmdLineParser parser(argc, argv); + parser.AddSwitch(NOLOGGING_SWITCH, wxEmptyString, wxEmptyString, wxCMD_LINE_PARAM_OPTIONAL); + parser.AddSwitch(DAEMON_SWITCH, wxEmptyString, wxEmptyString, wxCMD_LINE_PARAM_OPTIONAL); + parser.AddOption(LOGDIR_OPTION, wxEmptyString, wxEmptyString, wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL); + parser.AddOption(CONFDIR_OPTION, wxEmptyString, wxEmptyString, wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL); + parser.AddParam(NAME_PARAM, wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL); + + int cmd = parser.Parse(); + if (cmd != 0) { + ::wxUninitialize(); + return 0; + } + + bool nolog = parser.Found(NOLOGGING_SWITCH); + bool daemon = parser.Found(DAEMON_SWITCH); + + wxString logDir; + bool found = parser.Found(LOGDIR_OPTION, &logDir); + if (!found) + logDir.Clear(); + + wxString confDir; + found = parser.Found(CONFDIR_OPTION, &confDir); + if (!found) + confDir = wxT(CONF_DIR); + + wxString name; + if (parser.GetParamCount() > 0U) + name = parser.GetParam(0U); + + if (daemon) { + pid_t pid = ::fork(); + + if (pid < 0) { + ::fprintf(stderr, "timeserverd: error in fork(), exiting\n"); + ::wxUninitialize(); + return 1; + } + + // If this is the parent, exit + if (pid > 0) + return 0; + + // We are the child from here onwards + ::setsid(); + + ::chdir("/"); + + ::umask(0); + } + + CTimeServerD gateway(nolog, logDir, confDir, name); + + if (!gateway.init()) { + ::wxUninitialize(); + return 1; + } + + gateway.run(); + + ::wxUninitialize(); + return 0; +} + +CTimeServerD::CTimeServerD(bool nolog, const wxString& logDir, const wxString& confDir, const wxString& name) : +m_name(name), +m_nolog(nolog), +m_logDir(logDir), +m_confDir(confDir), +m_thread(NULL) +{ +} + +CTimeServerD::~CTimeServerD() +{ +} + +bool CTimeServerD::init() +{ + if (!m_nolog) { + wxString logBaseName = LOG_BASE_NAME; + if (!m_name.IsEmpty()) { + logBaseName.Append(wxT("_")); + logBaseName.Append(m_name); + } + + if (m_logDir.IsEmpty()) + m_logDir = wxT(LOG_DIR); + + wxLog* log = new CLogger(m_logDir, logBaseName); + wxLog::SetActiveTarget(log); + } else { + new wxLogNull; + } + + wxLogInfo(wxT("Starting ") + APPLICATION_NAME + wxT(" daemon - ") + VERSION); + + // Log the version of wxWidgets and the Operating System + wxLogInfo(wxT("Using wxWidgets %d.%d.%d on %s"), wxMAJOR_VERSION, wxMINOR_VERSION, wxRELEASE_NUMBER, ::wxGetOsDescription().c_str()); + + return createThread(); +} + +void CTimeServerD::run() +{ + m_thread->run(); + + wxLogInfo(APPLICATION_NAME + wxT(" is exiting")); +} + +bool CTimeServerD::createThread() +{ + CTimeServerConfig config(m_confDir, m_name); + + m_thread = new CTimeServerThread; + + wxString callsign, address; + bool sendA, sendB, sendC, sendD, sendE; + config.getGateway(callsign, sendA, sendB, sendC, sendD, sendE, address); + callsign.MakeUpper(); + m_thread->setGateway(callsign, sendA, sendB, sendC, sendD, sendE, address); + wxLogInfo(wxT("Callsign set to %s, module %s%s%s%s, address: %s"), callsign.c_str(), sendA ? wxT("A") : wxT(""), sendB ? wxT("B") : wxT(""), sendC ? wxT("C") : wxT(""), sendD ? wxT("D") : wxT(""), sendE ? wxT("E") : wxT(""), address.c_str()); + + LANGUAGE language; + FORMAT format; + INTERVAL interval; + config.getAnnouncements(language, format, interval); + m_thread->setAnnouncements(language, format, interval); + wxLogInfo(wxT("Language: %d, format: %d, interval: %d"), int(language), int(format), int(interval)); + + return true; +} diff --git a/TimeServer/TimeServerD.h b/TimeServer/TimeServerD.h new file mode 100644 index 0000000..2006dec --- /dev/null +++ b/TimeServer/TimeServerD.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2012 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef TimeServerD_H +#define TimeServerD_H + +#include "TimeServerThread.h" +#include "TimeServerDefs.h" + +#include +#include + +class CTimeServerD { + +public: + CTimeServerD(bool nolog, const wxString& logDir, const wxString& confDir, const wxString& name); + ~CTimeServerD(); + + bool init(); + + void run(); + +private: + wxString m_name; + bool m_nolog; + wxString m_logDir; + wxString m_confDir; + CTimeServerThread* m_thread; + + bool createThread(); +}; + +#endif diff --git a/TimeServer/TimeServerDefs.h b/TimeServer/TimeServerDefs.h new file mode 100644 index 0000000..85245b4 --- /dev/null +++ b/TimeServer/TimeServerDefs.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2012,2013,2014 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef TimeServerDefs_H +#define TimeServerDefs_H + +#include + +const wxString APPLICATION_NAME = wxT("Time Server"); + +#if !defined(__WINDOWS__) +const wxString CONFIG_FILE_NAME = wxT("timeserver"); +#endif + +enum LANGUAGE { + LANG_ENGLISH_UK_1, + LANG_ENGLISH_UK_2, + LANG_ENGLISH_US_1, + LANG_ENGLISH_US_2, + LANG_DEUTSCH_1, + LANG_DEUTSCH_2, + LANG_FRANCAIS, + LANG_NEDERLANDS, + LANG_SVENSKA, + LANG_ESPANOL, + LANG_NORSK, + LANG_PORTUGUES +}; + +enum INTERVAL { + INTERVAL_15MINS, + INTERVAL_30MINS, + INTERVAL_60MINS +}; + +enum FORMAT { + FORMAT_VOICE_TIME, + FORMAT_VOICE_ALL, + FORMAT_TEXT_TIME +}; + +#endif diff --git a/TimeServer/TimeServerFrame.cpp b/TimeServer/TimeServerFrame.cpp new file mode 100644 index 0000000..d01b52d --- /dev/null +++ b/TimeServer/TimeServerFrame.cpp @@ -0,0 +1,232 @@ +/* + * Copyright (C) 2012-2015 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "TimeServerPreferences.h" +#include "TimeServerFrame.h" +#include "TimeServerApp.h" +#include "LogEvent.h" +#include "Version.h" + +#if defined(__WINDOWS__) +const unsigned int LOGTEXT_WIDTH = 560U; +#else +const unsigned int LOGTEXT_WIDTH = 700U; +#endif + +const unsigned int BORDER_SIZE = 5U; + +#include +#include + +DEFINE_EVENT_TYPE(LOG_EVENT) + +enum { + Menu_Edit_Preferences = 6000, + Menu_View_Updates +}; + +BEGIN_EVENT_TABLE(CTimeServerFrame, wxFrame) + EVT_MENU(wxID_EXIT, CTimeServerFrame::onQuit) + EVT_MENU(Menu_Edit_Preferences, CTimeServerFrame::onPreferences) + EVT_MENU(Menu_View_Updates, CTimeServerFrame::onUpdates) + EVT_MENU(wxID_ABOUT, CTimeServerFrame::onAbout) + + EVT_CLOSE(CTimeServerFrame::onClose) + + EVT_CUSTOM(LOG_EVENT, wxID_ANY, CTimeServerFrame::onLog) +END_EVENT_TABLE() + +CTimeServerFrame::CTimeServerFrame(const wxString& title, const wxPoint& position, bool gui) : +wxFrame(NULL, -1, title, position), +#if defined(__WXDEBUG__) +m_updates(true) +#else +m_updates(gui) +#endif +{ + SetMenuBar(createMenuBar()); + + wxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL); + + wxPanel* panel = new wxPanel(this); + + wxBoxSizer* panelSizer = new wxBoxSizer(wxVERTICAL); + + wxStaticBoxSizer* log1Sizer = new wxStaticBoxSizer(new wxStaticBox(panel, -1, _("Log")), wxVERTICAL); + wxBoxSizer* log2Sizer = new wxBoxSizer(wxVERTICAL); + + for (unsigned int i = 0U; i < 10U; i++) { + m_logLine[i] = new wxStaticText(panel, -1, wxEmptyString, wxDefaultPosition, wxSize(LOGTEXT_WIDTH, -1)); + m_logLine[i]->Wrap(LOGTEXT_WIDTH); + log2Sizer->Add(m_logLine[i], 0, wxTOP | wxLEFT | wxRIGHT, BORDER_SIZE); + } + + log1Sizer->Add(log2Sizer); + panelSizer->Add(log1Sizer, 0, wxALL, BORDER_SIZE); + + panel->SetSizer(panelSizer); + panelSizer->SetSizeHints(panel); + + mainSizer->Add(panel); + + SetSizer(mainSizer); + mainSizer->SetSizeHints(this); +} + +CTimeServerFrame::~CTimeServerFrame() +{ +} + +wxMenuBar* CTimeServerFrame::createMenuBar() +{ + wxMenu* fileMenu = new wxMenu(); + fileMenu->Append(wxID_EXIT, _("Exit")); + + wxMenu* editMenu = new wxMenu(); + editMenu->Append(Menu_Edit_Preferences, _("Preferences...")); + + wxMenu* viewMenu = new wxMenu(); + viewMenu->AppendCheckItem(Menu_View_Updates, _("GUI Updates")); + viewMenu->Check(Menu_View_Updates, m_updates); + + wxMenu* helpMenu = new wxMenu(); + helpMenu->Append(wxID_ABOUT, _("About Time Server")); + + wxMenuBar* menuBar = new wxMenuBar(); + menuBar->Append(fileMenu, _("File")); + menuBar->Append(editMenu, _("Edit")); + menuBar->Append(viewMenu, _("View")); + menuBar->Append(helpMenu, _("Help")); + + return menuBar; +} + +void CTimeServerFrame::onQuit(wxCommandEvent&) +{ + Close(false); +} + +void CTimeServerFrame::onClose(wxCloseEvent&) +{ + int x, y; + GetPosition(&x, &y); + if (x >= 0 && y >= 0) { + ::wxGetApp().setPosition(x, y); + ::wxGetApp().writeConfig(); + } + + Destroy(); +} + +void CTimeServerFrame::onPreferences(wxCommandEvent&) +{ + wxString callsign, address; + bool sendA, sendB, sendC, sendD, sendE; + ::wxGetApp().getGateway(callsign, sendA, sendB, sendC, sendD, sendE, address); + + LANGUAGE language; + FORMAT format; + INTERVAL interval; + ::wxGetApp().getAnnouncements(language, format, interval); + + CTimeServerPreferences dialog1(this, -1, callsign, sendA, sendB, sendC, sendD, sendE, address, language, format, interval); + if (dialog1.ShowModal() != wxID_OK) + return; + + callsign = dialog1.getCallsign(); + sendA = dialog1.getSendA(); + sendB = dialog1.getSendB(); + sendC = dialog1.getSendC(); + sendD = dialog1.getSendD(); + sendE = dialog1.getSendE(); + address = dialog1.getAddress(); + language = dialog1.getLanguage(); + format = dialog1.getFormat(); + interval = dialog1.getInterval(); + + ::wxGetApp().setGateway(callsign, sendA, sendB, sendC, sendD, sendE, address); + ::wxGetApp().setAnnouncements(language, format, interval); + ::wxGetApp().writeConfig(); + + wxMessageDialog dialog2(this, _("The changes made will not take effect\nuntil the application is restarted"), _("DCS Gateway Information"), wxICON_INFORMATION); + dialog2.ShowModal(); +} + +void CTimeServerFrame::onUpdates(wxCommandEvent& event) +{ + m_updates = event.IsChecked(); +} + +void CTimeServerFrame::onAbout(wxCommandEvent&) +{ + wxAboutDialogInfo info; + info.AddDeveloper(wxT("Jonathan Naylor, G4KLX")); + info.SetCopyright(wxT("(C) 2012-2015 using GPL v2 or later")); + info.SetName(APPLICATION_NAME); + info.SetVersion(VERSION); + info.SetDescription(_("This program allows a computer running a gateway\nto have the time announced.")); + + ::wxAboutBox(info); +} + +void CTimeServerFrame::onLog(wxEvent& event) +{ + CLogEvent& logEvent = dynamic_cast(event); + + wxString text; + + text = m_logLine[1U]->GetLabel(); + m_logLine[0U]->SetLabel(text); + + text = m_logLine[2U]->GetLabel(); + m_logLine[1U]->SetLabel(text); + + text = m_logLine[3U]->GetLabel(); + m_logLine[2U]->SetLabel(text); + + text = m_logLine[4U]->GetLabel(); + m_logLine[3U]->SetLabel(text); + + text = m_logLine[5U]->GetLabel(); + m_logLine[4U]->SetLabel(text); + + text = m_logLine[6U]->GetLabel(); + m_logLine[5U]->SetLabel(text); + + text = m_logLine[7U]->GetLabel(); + m_logLine[6U]->SetLabel(text); + + text = m_logLine[8U]->GetLabel(); + m_logLine[7U]->SetLabel(text); + + text = m_logLine[9U]->GetLabel(); + m_logLine[8U]->SetLabel(text); + + text = logEvent.getText(); + m_logLine[9U]->SetLabel(text); +} + +void CTimeServerFrame::showLog(const wxString& text) +{ + if (!m_updates) + return; + + CLogEvent event(text, LOG_EVENT); + + AddPendingEvent(event); +} diff --git a/TimeServer/TimeServerFrame.h b/TimeServer/TimeServerFrame.h new file mode 100644 index 0000000..540dc69 --- /dev/null +++ b/TimeServer/TimeServerFrame.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2012 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef TimeServerFrame_H +#define TimeServerFrame_H + +#include "TimeServerDefs.h" + +#include +#include + +class CTimeServerFrame : public wxFrame { +public: + CTimeServerFrame(const wxString& title, const wxPoint& position, bool gui); + virtual ~CTimeServerFrame(); + + virtual void onQuit(wxCommandEvent& event); + virtual void onPreferences(wxCommandEvent& event); + virtual void onUpdates(wxCommandEvent& event); + virtual void onAbout(wxCommandEvent& event); + virtual void onClose(wxCloseEvent& event); + virtual void onLog(wxEvent& event); + + virtual void showLog(const wxString& text); + +private: + wxStaticText* m_logLine[10]; + bool m_updates; + + DECLARE_EVENT_TABLE() + + wxMenuBar* createMenuBar(); +}; + +#endif diff --git a/TimeServer/TimeServerGatewaySet.cpp b/TimeServer/TimeServerGatewaySet.cpp new file mode 100644 index 0000000..2223af3 --- /dev/null +++ b/TimeServer/TimeServerGatewaySet.cpp @@ -0,0 +1,184 @@ +/* + * Copyright (C) 2012 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "TimeServerGatewaySet.h" +#include "DStarDefines.h" + +const unsigned int BORDER_SIZE = 5U; +const unsigned int CONTROL_WIDTH = 150U; + +CTimeServerGatewaySet::CTimeServerGatewaySet(wxWindow* parent, int id, const wxString& title, const wxString& callsign, bool sendA, bool sendB, bool sendC, bool sendD, bool sendE, const wxString& address) : +wxPanel(parent, id), +m_title(title), +m_callsign(NULL), +m_address(NULL), +m_sendA(NULL), +m_sendB(NULL), +m_sendC(NULL), +m_sendD(NULL), +m_sendE(NULL) +{ + wxFlexGridSizer* sizer = new wxFlexGridSizer(2); + + wxStaticText* callsignLabel = new wxStaticText(this, -1, _("Callsign")); + sizer->Add(callsignLabel, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + + m_callsign = new CCallsignTextCtrl(this, -1, callsign, wxDefaultPosition, wxSize(CONTROL_WIDTH, -1)); + m_callsign->SetMaxLength(LONG_CALLSIGN_LENGTH - 1U); + sizer->Add(m_callsign, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + + wxStaticText* addressLabel = new wxStaticText(this, -1, _("Address")); + sizer->Add(addressLabel, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + + m_address = new CAddressTextCtrl(this, -1, address, wxDefaultPosition, wxSize(CONTROL_WIDTH, -1)); + sizer->Add(m_address, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + + wxStaticText* sendALabel = new wxStaticText(this, -1, _("Module A")); + sizer->Add(sendALabel, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + + m_sendA = new wxChoice(this, -1, wxDefaultPosition, wxSize(CONTROL_WIDTH, -1)); + m_sendA->Append(_("No")); + m_sendA->Append(_("Yes")); + sizer->Add(m_sendA, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + m_sendA->SetSelection(sendA ? 1 : 0); + + wxStaticText* sendBLabel = new wxStaticText(this, -1, _("Module B")); + sizer->Add(sendBLabel, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + + m_sendB = new wxChoice(this, -1, wxDefaultPosition, wxSize(CONTROL_WIDTH, -1)); + m_sendB->Append(_("No")); + m_sendB->Append(_("Yes")); + sizer->Add(m_sendB, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + m_sendB->SetSelection(sendB ? 1 : 0); + + wxStaticText* sendCLabel = new wxStaticText(this, -1, _("Module C")); + sizer->Add(sendCLabel, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + + m_sendC = new wxChoice(this, -1, wxDefaultPosition, wxSize(CONTROL_WIDTH, -1)); + m_sendC->Append(_("No")); + m_sendC->Append(_("Yes")); + sizer->Add(m_sendC, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + m_sendC->SetSelection(sendC ? 1 : 0); + + wxStaticText* sendDLabel = new wxStaticText(this, -1, _("Module D")); + sizer->Add(sendDLabel, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + + m_sendD = new wxChoice(this, -1, wxDefaultPosition, wxSize(CONTROL_WIDTH, -1)); + m_sendD->Append(_("No")); + m_sendD->Append(_("Yes")); + sizer->Add(m_sendD, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + m_sendD->SetSelection(sendD ? 1 : 0); + + wxStaticText* sendELabel = new wxStaticText(this, -1, _("Module E")); + sizer->Add(sendELabel, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + + m_sendE = new wxChoice(this, -1, wxDefaultPosition, wxSize(CONTROL_WIDTH, -1)); + m_sendE->Append(_("No")); + m_sendE->Append(_("Yes")); + sizer->Add(m_sendE, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + m_sendE->SetSelection(sendE ? 1 : 0); + + SetAutoLayout(true); + + SetSizer(sizer); +} + + +CTimeServerGatewaySet::~CTimeServerGatewaySet() +{ +} + +bool CTimeServerGatewaySet::Validate() +{ + bool res = getCallsign().IsEmpty(); + if (res) { + wxMessageDialog dialog(this, _("The Callsign may not be empty"), _("Time Server Error"), wxICON_ERROR); + dialog.ShowModal(); + return false; + } + + res = getAddress().IsEmpty(); + if (res) { + wxMessageDialog dialog(this, _("The Address may not be empty"), _("Time Server Error"), wxICON_ERROR); + dialog.ShowModal(); + return false; + } + + if (m_sendA->GetCurrentSelection() == wxNOT_FOUND) + return false; + + if (m_sendB->GetCurrentSelection() == wxNOT_FOUND) + return false; + + if (m_sendC->GetCurrentSelection() == wxNOT_FOUND) + return false; + + if (m_sendD->GetCurrentSelection() == wxNOT_FOUND) + return false; + + return m_sendE->GetCurrentSelection() != wxNOT_FOUND; +} + +wxString CTimeServerGatewaySet::getCallsign() const +{ + wxString callsign = m_callsign->GetValue(); + + callsign.MakeUpper(); + + return callsign; +} + +wxString CTimeServerGatewaySet::getAddress() const +{ + return m_address->GetValue(); +} + +bool CTimeServerGatewaySet::getSendA() const +{ + int n = m_sendA->GetCurrentSelection(); + + return n == 1; +} + +bool CTimeServerGatewaySet::getSendB() const +{ + int n = m_sendB->GetCurrentSelection(); + + return n == 1; +} + +bool CTimeServerGatewaySet::getSendC() const +{ + int n = m_sendC->GetCurrentSelection(); + + return n == 1; +} + +bool CTimeServerGatewaySet::getSendD() const +{ + int n = m_sendD->GetCurrentSelection(); + + return n == 1; +} + +bool CTimeServerGatewaySet::getSendE() const +{ + int n = m_sendE->GetCurrentSelection(); + + return n == 1; +} diff --git a/TimeServer/TimeServerGatewaySet.h b/TimeServer/TimeServerGatewaySet.h new file mode 100644 index 0000000..0a55e17 --- /dev/null +++ b/TimeServer/TimeServerGatewaySet.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2012 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef TimeServerGatewaySet_H +#define TimeServerGatewaySet_H + +#include "CallsignTextCtrl.h" +#include "AddressTextCtrl.h" + +#include + +class CTimeServerGatewaySet : public wxPanel { +public: + CTimeServerGatewaySet(wxWindow* parent, int id, const wxString& title, const wxString& callsign, bool sendA, bool sendB, + bool sendC, bool sendD, bool sendE, const wxString& address); + virtual ~CTimeServerGatewaySet(); + + virtual bool Validate(); + + virtual wxString getCallsign() const; + + virtual wxString getAddress() const; + + virtual bool getSendA() const; + virtual bool getSendB() const; + virtual bool getSendC() const; + virtual bool getSendD() const; + virtual bool getSendE() const; + +private: + wxString m_title; + CCallsignTextCtrl* m_callsign; + CAddressTextCtrl* m_address; + wxChoice* m_sendA; + wxChoice* m_sendB; + wxChoice* m_sendC; + wxChoice* m_sendD; + wxChoice* m_sendE; +}; + +#endif diff --git a/TimeServer/TimeServerLogRedirect.cpp b/TimeServer/TimeServerLogRedirect.cpp new file mode 100644 index 0000000..e30afd5 --- /dev/null +++ b/TimeServer/TimeServerLogRedirect.cpp @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2002,2003,2009-2013,2018 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "TimeServerLogRedirect.h" +#include "TimeServerApp.h" + +CTimeServerLogRedirect::CTimeServerLogRedirect() : +wxLog() +{ +} + +CTimeServerLogRedirect::~CTimeServerLogRedirect() +{ +} + +void CTimeServerLogRedirect::DoLogRecord(wxLogLevel level, const wxString& msg, const wxLogRecordInfo& info) +{ + wxString letter; + + switch (level) { + case wxLOG_FatalError: letter = wxT("F"); break; + case wxLOG_Error: letter = wxT("E"); break; + case wxLOG_Warning: letter = wxT("W"); break; + case wxLOG_Info: letter = wxT("I"); break; + case wxLOG_Message: letter = wxT("M"); break; + case wxLOG_Status: letter = wxT("M"); break; + case wxLOG_Trace: letter = wxT("T"); break; + case wxLOG_Debug: letter = wxT("D"); break; + default: letter = wxT("U"); break; + } + + struct tm* tm = ::gmtime(&info.timestamp); + + wxString message; + message.Printf(wxT("%s: %04d-%02d-%02d %02d:%02d:%02d: %s\n"), letter.c_str(), tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, msg.c_str()); + + ::wxGetApp().showLog(message); + + if (level == wxLOG_FatalError) + ::abort(); +} diff --git a/TimeServer/TimeServerLogRedirect.h b/TimeServer/TimeServerLogRedirect.h new file mode 100644 index 0000000..f66cdd7 --- /dev/null +++ b/TimeServer/TimeServerLogRedirect.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2002,2003,2009-2011,2018 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef TimeServerLogRedirect_H +#define TimeServerLogRedirect_H + +#include +#include + +class CTimeServerLogRedirect : public wxLog { +public: + CTimeServerLogRedirect(); + virtual ~CTimeServerLogRedirect(); + + virtual void DoLogRecord(wxLogLevel level, const wxString& msg, const wxLogRecordInfo& info); + +private: +}; + +#endif diff --git a/TimeServer/TimeServerPreferences.cpp b/TimeServer/TimeServerPreferences.cpp new file mode 100644 index 0000000..d044e9d --- /dev/null +++ b/TimeServer/TimeServerPreferences.cpp @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2012 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "TimeServerPreferences.h" +#include "DStarDefines.h" + +const unsigned int BORDER_SIZE = 5U; +const unsigned int CONTROL_WIDTH = 150U; + +CTimeServerPreferences::CTimeServerPreferences(wxWindow* parent, int id, const wxString& callsign, bool sendA, bool sendB, bool sendC, bool sendD, bool sendE, const wxString& address, LANGUAGE language, FORMAT format, INTERVAL interval) : +wxDialog(parent, id, wxString(_("Time Server Preferences"))), +m_gateway(NULL), +m_announcements(NULL) +{ + wxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL); + + wxNotebook* noteBook = new wxNotebook(this, -1); + + m_gateway = new CTimeServerGatewaySet(noteBook, -1, APPLICATION_NAME, callsign, sendA, sendB, sendC, sendD, sendE, address); + noteBook->AddPage(m_gateway, _("Gateway"), true); + + m_announcements = new CTimeServerAnnouncementsSet(noteBook, -1, APPLICATION_NAME, language, format, interval); + noteBook->AddPage(m_announcements, _("Announcements"), false); + + mainSizer->Add(noteBook, 1, wxALL | wxGROW, BORDER_SIZE); + + mainSizer->Add(CreateButtonSizer(wxOK | wxCANCEL), 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + SetAutoLayout(true); + Layout(); + + mainSizer->Fit(this); + mainSizer->SetSizeHints(this); + + SetSizer(mainSizer); +} + + +CTimeServerPreferences::~CTimeServerPreferences() +{ +} + +bool CTimeServerPreferences::Validate() +{ + if (!m_gateway->Validate()) + return false; + + return m_announcements->Validate(); +} + +wxString CTimeServerPreferences::getCallsign() const +{ + return m_gateway->getCallsign(); +} + +wxString CTimeServerPreferences::getAddress() const +{ + return m_gateway->getAddress(); +} + +bool CTimeServerPreferences::getSendA() const +{ + return m_gateway->getSendA(); +} + +bool CTimeServerPreferences::getSendB() const +{ + return m_gateway->getSendB(); +} + +bool CTimeServerPreferences::getSendC() const +{ + return m_gateway->getSendC(); +} + +bool CTimeServerPreferences::getSendD() const +{ + return m_gateway->getSendD(); +} + +bool CTimeServerPreferences::getSendE() const +{ + return m_gateway->getSendE(); +} + +LANGUAGE CTimeServerPreferences::getLanguage() const +{ + return m_announcements->getLanguage(); +} + +FORMAT CTimeServerPreferences::getFormat() const +{ + return m_announcements->getFormat(); +} + +INTERVAL CTimeServerPreferences::getInterval() const +{ + return m_announcements->getInterval(); +} diff --git a/TimeServer/TimeServerPreferences.h b/TimeServer/TimeServerPreferences.h new file mode 100644 index 0000000..2249428 --- /dev/null +++ b/TimeServer/TimeServerPreferences.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2012 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef TimeServerPreferences_H +#define TimeServerPreferences_H + +#include "TimeServerAnnouncementsSet.h" +#include "TimeServerGatewaySet.h" +#include "TimeServerDefs.h" + +#include +#include + +class CTimeServerPreferences : public wxDialog { +public: + CTimeServerPreferences(wxWindow* parent, int id, const wxString& callsign, bool sendA, bool sendB, + bool sendC, bool sendD, bool sendE, const wxString& address, LANGUAGE language, FORMAT format, INTERVAL interval); + virtual ~CTimeServerPreferences(); + + virtual bool Validate(); + + virtual wxString getCallsign() const; + virtual wxString getAddress() const; + virtual bool getSendA() const; + virtual bool getSendB() const; + virtual bool getSendC() const; + virtual bool getSendD() const; + virtual bool getSendE() const; + + virtual LANGUAGE getLanguage() const; + virtual FORMAT getFormat() const; + virtual INTERVAL getInterval() const; + +private: + CTimeServerGatewaySet* m_gateway; + CTimeServerAnnouncementsSet* m_announcements; +}; + +#endif diff --git a/TimeServer/TimeServerThread.cpp b/TimeServer/TimeServerThread.cpp new file mode 100644 index 0000000..dd28cdc --- /dev/null +++ b/TimeServer/TimeServerThread.cpp @@ -0,0 +1,1466 @@ +/* + * Copyright (C) 2012,2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "TimeServerThread.h" +#include "DStarDefines.h" +#include "Utils.h" + +#include +#include +#include +#include + +const unsigned int MAX_FRAMES = 60U * DSTAR_FRAMES_PER_SEC; + +const unsigned int SILENCE_LENGTH = 10U; + +enum SLOW_DATA { + SD_HEADER, + SD_TEXT +}; + +CTimeServerThread::CTimeServerThread() : +m_socket(wxEmptyString, 0U), +m_callsign(), +m_callsignA(), +m_callsignB(), +m_callsignC(), +m_callsignD(), +m_callsignE(), +m_callsignG(), +m_address(), +m_language(LANG_ENGLISH_UK_1), +m_format(FORMAT_VOICE_TIME), +m_interval(INTERVAL_15MINS), +m_ambe(NULL), +m_ambeLength(0U), +m_index(), +m_seqNo(0U), +m_in(0U), +m_encoder(), +m_data(NULL), +m_killed(false) +{ + m_address.s_addr = INADDR_NONE; + + m_data = new CAMBEData*[MAX_FRAMES]; + + for (unsigned int i = 0U; i < MAX_FRAMES; i++) + m_data[i] = NULL; +} + +CTimeServerThread::~CTimeServerThread() +{ + for (CIndexList_t::iterator it = m_index.begin(); it != m_index.end(); ++it) + delete it->second; + + delete[] m_ambe; + delete[] m_data; +} + +void CTimeServerThread::run() +{ + // Wait here until we have the essentials to run + while (!m_killed && m_address.s_addr == INADDR_NONE && m_callsignA.IsEmpty() && m_callsignB.IsEmpty() && m_callsignC.IsEmpty() && m_callsignD.IsEmpty() && m_callsignE.IsEmpty()) + ::wxMilliSleep(500UL); // 1/2 sec + + if (m_killed) + return; + + if (m_format != FORMAT_TEXT_TIME) { + bool ret = loadAMBE(); + if (!ret) { + wxLogWarning(wxT("Cannot load the AMBE data, using text only time")); + m_format = FORMAT_TEXT_TIME; + } + } + + wxLogMessage(wxT("Starting the Time Server thread")); + + unsigned int lastMin = 0U; + + while (!m_killed) { + time_t now; + ::time(&now); + + struct tm* tm = ::localtime(&now); + + unsigned int hour = tm->tm_hour; + unsigned int min = tm->tm_min; + + if (min != lastMin) { + if (m_interval == INTERVAL_15MINS && (min == 0U || min == 15U || min == 30U || min == 45U)) + sendTime(hour, min); + else if (m_interval == INTERVAL_30MINS && (min == 0U || min == 30U)) + sendTime(hour, min); + else if (m_interval == INTERVAL_60MINS && min == 0U) + sendTime(hour, min); + } + + lastMin = min; + + ::wxMilliSleep(450UL); + } + + wxLogMessage(wxT("Stopping the Time Server thread")); + + m_socket.close(); +} + +void CTimeServerThread::kill() +{ + m_killed = true; +} + +bool CTimeServerThread::setGateway(const wxString& callsign, bool sendA, bool sendB, bool sendC, bool sendD, bool sendE, const wxString& address) +{ + m_callsign = callsign; + m_callsign.resize(LONG_CALLSIGN_LENGTH - 1U, wxT(' ')); + + m_callsignG = m_callsign; + m_callsignG.Append(wxT("G")); + + if (sendA) { + m_callsignA = m_callsign; + m_callsignA.Append(wxT("A")); + } + + if (sendB) { + m_callsignB = m_callsign; + m_callsignB.Append(wxT("B")); + } + + if (sendC) { + m_callsignC = m_callsign; + m_callsignC.Append(wxT("C")); + } + + if (sendD) { + m_callsignD = m_callsign; + m_callsignD.Append(wxT("D")); + } + + if (sendE) { + m_callsignE = m_callsign; + m_callsignE.Append(wxT("E")); + } + + m_callsign.Append(wxT(" ")); + + m_address = CUDPReaderWriter::lookup(address); + + bool ret = m_socket.open(); + if (!ret) + return false; + + return true; +} + +void CTimeServerThread::setAnnouncements(LANGUAGE language, FORMAT format, INTERVAL interval) +{ + m_language = language; + m_format = format; + m_interval = interval; +} + +void CTimeServerThread::sendTime(unsigned int hour, unsigned int min) +{ + wxArrayString words; + + switch (m_language) { + case LANG_ENGLISH_UK_1: + words = sendTimeEnGB1(hour, min); + break; + case LANG_ENGLISH_UK_2: + words = sendTimeEnGB2(hour, min); + break; + case LANG_ENGLISH_US_1: + words = sendTimeEnUS1(hour, min); + break; + case LANG_ENGLISH_US_2: + words = sendTimeEnUS2(hour, min); + break; + case LANG_DEUTSCH_1: + words = sendTimeDeDE1(hour, min); + break; + case LANG_DEUTSCH_2: + words = sendTimeDeDE2(hour, min); + break; + case LANG_FRANCAIS: + words = sendTimeFrFR(hour, min); + break; + case LANG_NEDERLANDS: + words = sendTimeNlNL(hour, min); + break; + case LANG_SVENSKA: + words = sendTimeSeSE(hour, min); + break; + case LANG_ESPANOL: + words = sendTimeEsES(hour, min); + break; + case LANG_NORSK: + words = sendTimeNoNO(hour, min); + break; + case LANG_PORTUGUES: + words = sendTimePtPT(hour, min); + break; + default: + break; + } + + send(words, hour, min); +} + +wxArrayString CTimeServerThread::sendTimeEnGB1(unsigned int hour, unsigned int min) +{ + wxArrayString words; + + words.Add(wxT("It_is")); + + switch (hour) { + case 0U: + case 12U: + words.Add(wxT("twelve")); + break; + case 1U: + case 13U: + words.Add(wxT("one")); + break; + case 2U: + case 14U: + words.Add(wxT("two")); + break; + case 3U: + case 15U: + words.Add(wxT("three")); + break; + case 4U: + case 16U: + words.Add(wxT("four")); + break; + case 5U: + case 17U: + words.Add(wxT("five")); + break; + case 6U: + case 18U: + words.Add(wxT("six")); + break; + case 7U: + case 19U: + words.Add(wxT("seven")); + break; + case 8U: + case 20U: + words.Add(wxT("eight")); + break; + case 9U: + case 21U: + words.Add(wxT("nine")); + break; + case 10U: + case 22U: + words.Add(wxT("ten")); + break; + case 11U: + case 23U: + words.Add(wxT("eleven")); + break; + default: + break; + } + + switch (min) { + case 15U: + words.Add(wxT("fifteen")); + break; + case 30U: + words.Add(wxT("thirty")); + break; + case 45U: + words.Add(wxT("forty-five")); + break; + default: + break; + } + + if (hour >= 12U) + words.Add(wxT("PM")); + else + words.Add(wxT("AM")); + + return words; +} + +wxArrayString CTimeServerThread::sendTimeEnGB2(unsigned int hour, unsigned int min) +{ + wxArrayString words; + + words.Add(wxT("It_is")); + + if (min == 15U) { + words.Add(wxT("a_quarter_past")); + } else if (min == 30U) { + words.Add(wxT("half_past")); + } else if (min == 45U) { + words.Add(wxT("a_quarter_to")); + if (hour == 23U) + hour = 0U; + else + hour++; + } + + if (hour == 0U && min == 0U) { + words.Add(wxT("midnight")); + } else if (hour == 12U && min == 0U) { + words.Add(wxT("twelve")); + words.Add(wxT("noon")); + } else if (hour == 0U || hour == 12U) { + words.Add(wxT("twelve")); + } else if (hour == 1U || hour == 13U) { + words.Add(wxT("one")); + } else if (hour == 2U || hour == 14U) { + words.Add(wxT("two")); + } else if (hour == 3U || hour == 15U) { + words.Add(wxT("three")); + } else if (hour == 4U || hour == 16U) { + words.Add(wxT("four")); + } else if (hour == 5U || hour == 17U) { + words.Add(wxT("five")); + } else if (hour == 6U || hour == 18U) { + words.Add(wxT("six")); + } else if (hour == 7U || hour == 19U) { + words.Add(wxT("seven")); + } else if (hour == 8U || hour == 20U) { + words.Add(wxT("eight")); + } else if (hour == 9U || hour == 21U) { + words.Add(wxT("nine")); + } else if (hour == 10U || hour == 22U) { + words.Add(wxT("ten")); + } else if (hour == 11U || hour == 23U) { + words.Add(wxT("eleven")); + } + + if (hour != 0U && hour != 12U && min == 0U) + words.Add(wxT("O_Clock")); + + return words; +} + +wxArrayString CTimeServerThread::sendTimeEnUS1(unsigned int hour, unsigned int min) +{ + wxArrayString words; + + words.Add(wxT("It_is")); + + switch (hour) { + case 0U: + case 12U: + words.Add(wxT("twelve")); + break; + case 1U: + case 13U: + words.Add(wxT("one")); + break; + case 2U: + case 14U: + words.Add(wxT("two")); + break; + case 3U: + case 15U: + words.Add(wxT("three")); + break; + case 4U: + case 16U: + words.Add(wxT("four")); + break; + case 5U: + case 17U: + words.Add(wxT("five")); + break; + case 6U: + case 18U: + words.Add(wxT("six")); + break; + case 7U: + case 19U: + words.Add(wxT("seven")); + break; + case 8U: + case 20U: + words.Add(wxT("eight")); + break; + case 9U: + case 21U: + words.Add(wxT("nine")); + break; + case 10U: + case 22U: + words.Add(wxT("ten")); + break; + case 11U: + case 23U: + words.Add(wxT("eleven")); + break; + default: + break; + } + + switch (min) { + case 15U: + words.Add(wxT("fifteen")); + break; + case 30U: + words.Add(wxT("thirty")); + break; + case 45U: + words.Add(wxT("forty-five")); + break; + default: + break; + } + + if (hour >= 12U) + words.Add(wxT("PM")); + else + words.Add(wxT("AM")); + + return words; +} + +wxArrayString CTimeServerThread::sendTimeEnUS2(unsigned int hour, unsigned int min) +{ + wxArrayString words; + + words.Add(wxT("It_is")); + + if (min == 15U) { + words.Add(wxT("a_quarter_past")); + } else if (min == 30U) { + words.Add(wxT("half_past")); + } else if (min == 45U) { + words.Add(wxT("a_quarter_to")); + if (hour == 23U) + hour = 0U; + else + hour++; + } + + if (hour == 0U && min == 0U) { + words.Add(wxT("midnight")); + } else if (hour == 12U && min == 0U) { + words.Add(wxT("twelve")); + words.Add(wxT("noon")); + } else if (hour == 0U || hour == 12U) { + words.Add(wxT("twelve")); + } else if (hour == 1U || hour == 13U) { + words.Add(wxT("one")); + } else if (hour == 2U || hour == 14U) { + words.Add(wxT("two")); + } else if (hour == 3U || hour == 15U) { + words.Add(wxT("three")); + } else if (hour == 4U || hour == 16U) { + words.Add(wxT("four")); + } else if (hour == 5U || hour == 17U) { + words.Add(wxT("five")); + } else if (hour == 6U || hour == 18U) { + words.Add(wxT("six")); + } else if (hour == 7U || hour == 19U) { + words.Add(wxT("seven")); + } else if (hour == 8U || hour == 20U) { + words.Add(wxT("eight")); + } else if (hour == 9U || hour == 21U) { + words.Add(wxT("nine")); + } else if (hour == 10U || hour == 22U) { + words.Add(wxT("ten")); + } else if (hour == 11U || hour == 23U) { + words.Add(wxT("eleven")); + } + + if (hour != 0U && hour != 12U && min == 0U) + words.Add(wxT("O_Clock")); + + return words; +} + +wxArrayString CTimeServerThread::sendTimeDeDE1(unsigned int hour, unsigned int min) +{ + wxArrayString words; + + words.Add(wxT("Es_ist")); + + switch (hour) { + case 0U: words.Add(wxT("null")); break; + case 1U: words.Add(wxT("ein")); break; + case 2U: words.Add(wxT("zwei")); break; + case 3U: words.Add(wxT("drei")); break; + case 4U: words.Add(wxT("vier")); break; + case 5U: words.Add(wxT("fuenf")); break; + case 6U: words.Add(wxT("sechs")); break; + case 7U: words.Add(wxT("sieben")); break; + case 8U: words.Add(wxT("acht")); break; + case 9U: words.Add(wxT("neun")); break; + case 10U: words.Add(wxT("zehn")); break; + case 11U: words.Add(wxT("elf")); break; + case 12U: words.Add(wxT("zwoelf")); break; + case 13U: words.Add(wxT("dreizehn")); break; + case 14U: words.Add(wxT("vierzehn")); break; + case 15U: words.Add(wxT("fuenfzehn")); break; + case 16U: words.Add(wxT("sechzehn")); break; + case 17U: words.Add(wxT("siebzehn")); break; + case 18U: words.Add(wxT("achtzehn")); break; + case 19U: words.Add(wxT("neunzehn")); break; + case 20U: words.Add(wxT("zwanzig")); break; + case 21U: words.Add(wxT("einundzwanzig")); break; + case 22U: words.Add(wxT("zweiundzwanzig")); break; + case 23U: words.Add(wxT("dreiundzwanzig")); break; + default: break; + } + + words.Add(wxT("Uhr")); + + switch (min) { + case 15U: + words.Add(wxT("fuenfzehn")); + break; + case 30U: + words.Add(wxT("dreissig")); + break; + case 45U: + words.Add(wxT("fuenfundvierzig")); + break; + default: + break; + } + + return words; +} + +wxArrayString CTimeServerThread::sendTimeDeDE2(unsigned int hour, unsigned int min) +{ + wxArrayString words; + + words.Add(wxT("Es_ist")); + + if (min == 15U) { + words.Add(wxT("viertel_nach")); + } else if (min == 30U) { + words.Add(wxT("halb")); + if (hour == 23U) + hour = 0U; + else + hour++; + } else if (min == 45U) { + words.Add(wxT("viertel_vor")); + if (hour == 23U) + hour = 0U; + else + hour++; + } + + if (hour == 0U) { + words.Add(wxT("null")); + } else if (hour == 1U || hour == 13U) { + words.Add(wxT("ein")); + } else if (hour == 2U || hour == 14U) { + words.Add(wxT("zwei")); + } else if (hour == 3U || hour == 15U) { + words.Add(wxT("drei")); + } else if (hour == 4U || hour == 16U) { + words.Add(wxT("vier")); + } else if (hour == 5U || hour == 17U) { + words.Add(wxT("fuenf")); + } else if (hour == 6U || hour == 18U) { + words.Add(wxT("sechs")); + } else if (hour == 7U || hour == 19U) { + words.Add(wxT("sieben")); + } else if (hour == 8U || hour == 20U) { + words.Add(wxT("acht")); + } else if (hour == 9U || hour == 21U) { + words.Add(wxT("neun")); + } else if (hour == 10U || hour == 22U) { + words.Add(wxT("zehn")); + } else if (hour == 11U || hour == 23U) { + words.Add(wxT("elf")); + } else if (hour == 12U) { + words.Add(wxT("zwoelf")); + } + + if (min == 0U) + words.Add(wxT("Uhr")); + + return words; +} + +wxArrayString CTimeServerThread::sendTimeFrFR(unsigned int hour, unsigned int min) +{ + wxArrayString words; + + // if (hour > 17U) + // words.Add(wxT("bonsoir")); + // else + // words.Add(wxT("bonjour")); + + words.Add(wxT("il_est")); + + if (min == 45U) + hour++; + + if (hour == 0U) { + words.Add(wxT("minuit")); + } else if (hour == 1U || hour == 13U) { + words.Add(wxT("une")); + } else if (hour == 2U || hour == 14U) { + words.Add(wxT("deux")); + } else if (hour == 3U || hour == 15U) { + words.Add(wxT("trois")); + } else if (hour == 4U || hour == 16U) { + words.Add(wxT("quatre")); + } else if (hour == 5U || hour == 17U) { + words.Add(wxT("cinq")); + } else if (hour == 6U || hour == 18U) { + words.Add(wxT("six")); + } else if (hour == 7U || hour == 19U) { + words.Add(wxT("sept")); + } else if (hour == 8U || hour == 20U) { + words.Add(wxT("huit")); + } else if (hour == 9U || hour == 21U) { + words.Add(wxT("neuf")); + } else if (hour == 10U || hour == 22U) { + words.Add(wxT("dix")); + } else if (hour == 11U || hour == 23U) { + words.Add(wxT("onze")); + } else if (hour == 12U) { + words.Add(wxT("midi")); + } + + if (hour == 1U || hour == 13U) + words.Add(wxT("heure")); + else if (hour != 12U && hour != 0U) + words.Add(wxT("heures")); + + if (min == 15U) { + words.Add(wxT("et_quart")); + } else if (min == 30U) { + words.Add(wxT("et_demie")); + } else if (min == 45U) { + words.Add(wxT("moins_le_quart")); + if (hour == 23U) + hour = 0U; + else + hour++; + } + + return words; +} + +wxArrayString CTimeServerThread::sendTimeNlNL(unsigned int hour, unsigned int min) +{ + wxArrayString words; + + words.Add(wxT("Het_is")); + + if (min == 15U) { + words.Add(wxT("kwart_over")); + } else if (min == 30U) { + words.Add(wxT("half")); + if (hour == 23U) + hour = 0U; + else + hour++; + } else if (min == 45U) { + words.Add(wxT("kwart_voor")); + if (hour == 23U) + hour = 0U; + else + hour++; + } + + if (hour == 0U || hour == 12U) { + words.Add(wxT("twaalf")); + } else if (hour == 1U || hour == 13U) { + words.Add(wxT("een")); + } else if (hour == 2U || hour == 14U) { + words.Add(wxT("twee")); + } else if (hour == 3U || hour == 15U) { + words.Add(wxT("drie")); + } else if (hour == 4U || hour == 16U) { + words.Add(wxT("vier")); + } else if (hour == 5U || hour == 17U) { + words.Add(wxT("vijf")); + } else if (hour == 6U || hour == 18U) { + words.Add(wxT("zes")); + } else if (hour == 7U || hour == 19U) { + words.Add(wxT("zeven")); + } else if (hour == 8U || hour == 20U) { + words.Add(wxT("acht")); + } else if (hour == 9U || hour == 21U) { + words.Add(wxT("negen")); + } else if (hour == 10U || hour == 22U) { + words.Add(wxT("tien")); + } else if (hour == 11U || hour == 23U) { + words.Add(wxT("elf")); + } + + if (min == 0U) + words.Add(wxT("uur")); + + return words; +} + +wxArrayString CTimeServerThread::sendTimeSeSE(unsigned int hour, unsigned int min) +{ + wxArrayString words; + + words.Add(wxT("Klockan_ar")); + + if (min == 15U) { + words.Add(wxT("kvart_over")); + } else if (min == 30U) { + words.Add(wxT("halv")); + if (hour == 23U) + hour = 0U; + else + hour++; + } else if (min == 45U) { + words.Add(wxT("kvart_i")); + if (hour == 23U) + hour = 0U; + else + hour++; + } + + if (hour == 0U || hour == 12U) { + words.Add(wxT("tolv")); + } else if (hour == 1U || hour == 13U) { + words.Add(wxT("ett")); + } else if (hour == 2U || hour == 14U) { + words.Add(wxT("tva")); + } else if (hour == 3U || hour == 15U) { + words.Add(wxT("tre")); + } else if (hour == 4U || hour == 16U) { + words.Add(wxT("fyra")); + } else if (hour == 5U || hour == 17U) { + words.Add(wxT("fem")); + } else if (hour == 6U || hour == 18U) { + words.Add(wxT("sex")); + } else if (hour == 7U || hour == 19U) { + words.Add(wxT("sju")); + } else if (hour == 8U || hour == 20U) { + words.Add(wxT("atta")); + } else if (hour == 9U || hour == 21U) { + words.Add(wxT("nio")); + } else if (hour == 10U || hour == 22U) { + words.Add(wxT("tio")); + } else if (hour == 11U || hour == 23U) { + words.Add(wxT("elva")); + } + + return words; +} + +wxArrayString CTimeServerThread::sendTimeEsES(unsigned int hour, unsigned int min) +{ + wxArrayString words; + + if (min == 45U) { + hour++; + if (hour == 24U) + hour = 0U; + } + + if (hour == 1U) + words.Add(wxT("Es_la")); + else if (hour == 0U || hour == 12U) + words.Add(wxT("Es")); + else + words.Add(wxT("Son_las")); + + if (hour == 0U) { + words.Add(wxT("medianoche")); + } else if (hour == 1U || hour == 13U) { + words.Add(wxT("una")); + } else if (hour == 2U || hour == 14U) { + words.Add(wxT("dos")); + } else if (hour == 3U || hour == 15U) { + words.Add(wxT("tres")); + } else if (hour == 4U || hour == 16U) { + words.Add(wxT("cuarto")); + } else if (hour == 5U || hour == 17U) { + words.Add(wxT("cinco")); + } else if (hour == 6U || hour == 18U) { + words.Add(wxT("seis")); + } else if (hour == 7U || hour == 19U) { + words.Add(wxT("siete")); + } else if (hour == 8U || hour == 20U) { + words.Add(wxT("ocho")); + } else if (hour == 9U || hour == 21U) { + words.Add(wxT("nueve")); + } else if (hour == 10U || hour == 22U) { + words.Add(wxT("diez")); + } else if (hour == 11U || hour == 23U) { + words.Add(wxT("once")); + } else { + words.Add(wxT("mediodia")); + } + + if (min == 15U) + words.Add(wxT("y_cuarto")); + else if (min == 30U) + words.Add(wxT("y_media")); + else if (min == 45U) + words.Add(wxT("menos_cuarto")); + + if (hour > 0U && hour < 12U) + words.Add(wxT("de_la_manana")); + else if (hour > 12U && hour < 19U) + words.Add(wxT("de_la_tarde")); + else if (hour >= 19U && hour <= 23U) + words.Add(wxT("de_la_noche")); + + return words; +} + +wxArrayString CTimeServerThread::sendTimeNoNO(unsigned int hour, unsigned int min) +{ + wxArrayString words; + + words.Add(wxT("Klokken_er")); + + if (min == 15U) { + words.Add(wxT("kvart_over")); + } else if (min == 30U) { + words.Add(wxT("halv")); + if (hour == 23U) + hour = 0U; + else + hour++; + } else if (min == 45U) { + words.Add(wxT("kvart_pa")); + if (hour == 23U) + hour = 0U; + else + hour++; + } + + if (hour == 0U || hour == 12U) { + words.Add(wxT("tolv")); + } else if (hour == 1U || hour == 13U) { + words.Add(wxT("ett")); + } else if (hour == 2U || hour == 14U) { + words.Add(wxT("to")); + } else if (hour == 3U || hour == 15U) { + words.Add(wxT("tre")); + } else if (hour == 4U || hour == 16U) { + words.Add(wxT("fire")); + } else if (hour == 5U || hour == 17U) { + words.Add(wxT("fem")); + } else if (hour == 6U || hour == 18U) { + words.Add(wxT("seks")); + } else if (hour == 7U || hour == 19U) { + words.Add(wxT("sju")); + } else if (hour == 8U || hour == 20U) { + words.Add(wxT("atte")); + } else if (hour == 9U || hour == 21U) { + words.Add(wxT("ni")); + } else if (hour == 10U || hour == 22U) { + words.Add(wxT("ti")); + } else if (hour == 11U || hour == 23U) { + words.Add(wxT("elleve")); + } + + return words; +} + +wxArrayString CTimeServerThread::sendTimePtPT(unsigned int hour, unsigned int min) +{ + wxArrayString words; + + if (min == 45U) { + hour++; + if (hour == 24U) + hour = 0U; + } + + if (hour == 1U || hour == 13U) + words.Add(wxT("E")); + else if (hour == 0U || hour == 12U) + words.Add(wxT("Es")); + else + words.Add(wxT("Sao")); + + if (min == 45U) { + if (hour == 0U || hour == 12U || hour == 1U || hour == 13U) + words.Add(wxT("quinze_para")); + else + words.Add(wxT("quinze_para_as")); + } + + if (hour == 0U) { + words.Add(wxT("meia-noite")); + } else if (hour == 1U || hour == 13U) { + words.Add(wxT("uma")); + } else if (hour == 2U || hour == 14U) { + words.Add(wxT("duas")); + } else if (hour == 3U || hour == 15U) { + words.Add(wxT("tres")); + } else if (hour == 4U || hour == 16U) { + words.Add(wxT("quatro")); + } else if (hour == 5U || hour == 17U) { + words.Add(wxT("cinco")); + } else if (hour == 6U || hour == 18U) { + words.Add(wxT("seis")); + } else if (hour == 7U || hour == 19U) { + words.Add(wxT("sete")); + } else if (hour == 8U || hour == 20U) { + words.Add(wxT("oito")); + } else if (hour == 9U || hour == 21U) { + words.Add(wxT("nove")); + } else if (hour == 10U || hour == 22U) { + words.Add(wxT("dez")); + } else if (hour == 11U || hour == 23U) { + words.Add(wxT("onze")); + } else { + words.Add(wxT("meio-dia")); + } + + if (min == 0U) + words.Add(wxT("hora")); + else if (min == 15U) + words.Add(wxT("e_quinze")); + else if (min == 30U) + words.Add(wxT("e_meia")); + + return words; +} + +bool CTimeServerThread::loadAMBE() +{ + wxString ambeFileName; + wxString indxFileName; + + switch (m_language) { + case LANG_ENGLISH_US_1: + case LANG_ENGLISH_US_2: + ambeFileName = wxT("TIME_en_US.ambe"); + indxFileName = wxT("TIME_en_US.indx"); + break; + case LANG_DEUTSCH_1: + case LANG_DEUTSCH_2: + ambeFileName = wxT("TIME_de_DE.ambe"); + indxFileName = wxT("TIME_de_DE.indx"); + break; + case LANG_FRANCAIS: + ambeFileName = wxT("TIME_fr_FR.ambe"); + indxFileName = wxT("TIME_fr_FR.indx"); + break; + case LANG_NEDERLANDS: + ambeFileName = wxT("TIME_nl_NL.ambe"); + indxFileName = wxT("TIME_nl_NL.indx"); + break; + case LANG_SVENSKA: + ambeFileName = wxT("TIME_se_SE.ambe"); + indxFileName = wxT("TIME_se_SE.indx"); + break; + case LANG_ESPANOL: + ambeFileName = wxT("TIME_es_ES.ambe"); + indxFileName = wxT("TIME_es_ES.indx"); + break; + case LANG_NORSK: + ambeFileName = wxT("TIME_no_NO.ambe"); + indxFileName = wxT("TIME_no_NO.indx"); + break; + case LANG_PORTUGUES: + ambeFileName = wxT("TIME_pt_PT.ambe"); + indxFileName = wxT("TIME_pt_PT.indx"); + break; + default: + ambeFileName = wxT("TIME_en_GB.ambe"); + indxFileName = wxT("TIME_en_GB.indx"); + break; + } + + bool ret = readAMBE(ambeFileName); + if (!ret) { + delete[] m_ambe; + m_ambe = NULL; + return false; + } + + ret = readIndex(indxFileName); + if (!ret) { + delete[] m_ambe; + m_ambe = NULL; + return false; + } + + return true; +} + +bool CTimeServerThread::readAMBE(const wxString& name) +{ + wxFileName fileName(wxFileName::GetHomeDir(), name); + + if (!fileName.IsFileReadable()) { + wxLogMessage(wxT("File %s not readable"), fileName.GetFullPath().c_str()); +#if defined(__WINDOWS__) + fileName.Assign(::wxGetCwd(), name); +#else + fileName.Assign(wxT(DATA_DIR), name); +#endif + if (!fileName.IsFileReadable()) { + wxLogMessage(wxT("File %s not readable"), fileName.GetFullPath().c_str()); + return false; + } + } + + wxFFile file; + + bool ret = file.Open(fileName.GetFullPath().c_str(), wxT("rb")); + if (!ret) { + wxLogMessage(wxT("Cannot open %s for reading"), fileName.GetFullPath().c_str()); + return false; + } + + wxLogMessage(wxT("Reading %s"), fileName.GetFullPath().c_str()); + + unsigned char buffer[VOICE_FRAME_LENGTH_BYTES]; + + size_t n = file.Read(buffer, 4U); + if (n != 4U) { + wxLogMessage(wxT("Unable to read the header from %s"), fileName.GetFullPath().c_str()); + file.Close(); + return false; + } + + if (::memcmp(buffer, "AMBE", 4U) != 0) { + wxLogMessage(wxT("Invalid header from %s"), fileName.GetFullPath().c_str()); + file.Close(); + return false; + } + + // Length of the file minus the header + unsigned int length = file.Length() - 4U; + + // Hold the file data plus silence at the end + m_ambe = new unsigned char[length + SILENCE_LENGTH * VOICE_FRAME_LENGTH_BYTES]; + m_ambeLength = length / VOICE_FRAME_LENGTH_BYTES; + + // Add silence to the beginning of the buffer + unsigned char* p = m_ambe; + for (unsigned int i = 0U; i < SILENCE_LENGTH; i++, p += VOICE_FRAME_LENGTH_BYTES) + ::memcpy(p, NULL_AMBE_DATA_BYTES, VOICE_FRAME_LENGTH_BYTES); + + n = file.Read(p, length); + if (n != length) { + wxLogMessage(wxT("Unable to read the AMBE data from %s"), fileName.GetFullPath().c_str()); + file.Close(); + delete[] m_ambe; + m_ambe = NULL; + return false; + } + + file.Close(); + + return true; +} + +bool CTimeServerThread::readIndex(const wxString& name) +{ + wxFileName fileName(wxFileName::GetHomeDir(), name); + + if (!fileName.IsFileReadable()) { + wxLogMessage(wxT("File %s not readable"), fileName.GetFullPath().c_str()); +#if defined(__WINDOWS__) + fileName.Assign(::wxGetCwd(), name); +#else + fileName.Assign(wxT(DATA_DIR), name); +#endif + if (!fileName.IsFileReadable()) { + wxLogMessage(wxT("File %s not readable"), fileName.GetFullPath().c_str()); + return false; + } + } + + wxTextFile file; + + bool ret = file.Open(fileName.GetFullPath()); + if (!ret) { + wxLogMessage(wxT("Cannot open %s for reading"), fileName.GetFullPath().c_str()); + return false; + } + + // Add a silence entry at the beginning + m_index[wxT(" ")] = new CIndexRecord(wxT(" "), 0U, SILENCE_LENGTH); + + wxLogMessage(wxT("Reading %s"), fileName.GetFullPath().c_str()); + + unsigned int nLines = file.GetLineCount(); + + for (unsigned int i = 0; i < nLines; i++) { + wxString line = file.GetLine(i); + + if (line.length() > 0 && line.GetChar(0) != wxT('#')) { + wxStringTokenizer t(line, wxT(" \t\r\n"), wxTOKEN_STRTOK); + wxString name = t.GetNextToken(); + wxString startTxt = t.GetNextToken(); + wxString lengthTxt = t.GetNextToken(); + + if (!name.IsEmpty() && !startTxt.IsEmpty() && !lengthTxt.IsEmpty()) { + unsigned long start; + startTxt.ToULong(&start); + + unsigned long length; + lengthTxt.ToULong(&length); + + if (start >= m_ambeLength || (start + length) >= m_ambeLength) + wxLogError(wxT("The start or end for *%s* is out of range, start: %lu, end: %lu"), name.c_str(), start, start + length); + else + m_index[name] = new CIndexRecord(name, start + SILENCE_LENGTH, length); + } + } + } + + file.Close(); + + return true; +} + +bool CTimeServerThread::lookup(const wxString &id) +{ + CIndexRecord* info = m_index[id]; + if (info == NULL) { + // wxLogError(wxT("Cannot find the AMBE index for *%s*"), id.c_str()); + return false; + } + + unsigned int start = info->getStart(); + unsigned int length = info->getLength(); + + SLOW_DATA slowData = SD_TEXT; + + for (unsigned int i = 0U; i < length; i++) { + unsigned char* dataIn = m_ambe + (start + i) * VOICE_FRAME_LENGTH_BYTES; + + CAMBEData* dataOut = new CAMBEData; + dataOut->setDestination(m_address, G2_DV_PORT); + dataOut->setSeq(m_seqNo); + + unsigned char buffer[DV_FRAME_LENGTH_BYTES]; + ::memcpy(buffer + 0U, dataIn, VOICE_FRAME_LENGTH_BYTES); + + // Insert sync bytes when the sequence number is zero, slow data otherwise + if (m_seqNo == 0U) { + ::memcpy(buffer + VOICE_FRAME_LENGTH_BYTES, DATA_SYNC_BYTES, DATA_FRAME_LENGTH_BYTES); + m_encoder.sync(); + + switch (slowData) { + case SD_HEADER: + slowData = SD_TEXT; + break; + case SD_TEXT: + slowData = SD_HEADER; + break; + } + } else { + switch (slowData) { + case SD_HEADER: + m_encoder.getHeaderData(buffer + VOICE_FRAME_LENGTH_BYTES); + break; + case SD_TEXT: + m_encoder.getTextData(buffer + VOICE_FRAME_LENGTH_BYTES); + break; + } + } + + dataOut->setData(buffer, DV_FRAME_LENGTH_BYTES); + + m_seqNo++; + if (m_seqNo == 21U) + m_seqNo = 0U; + + m_data[m_in] = dataOut; + m_in++; + } + + return true; +} + +void CTimeServerThread::end() +{ + CAMBEData* dataOut = new CAMBEData; + dataOut->setData(END_PATTERN_BYTES, DV_FRAME_LENGTH_BYTES); + dataOut->setDestination(m_address, G2_DV_PORT); + dataOut->setSeq(m_seqNo); + dataOut->setEnd(true); + + m_data[m_in] = dataOut; + m_in++; +} + +bool CTimeServerThread::send(const wxArrayString &words, unsigned int hour, unsigned int min) +{ + unsigned int idA = CHeaderData::createId(); + unsigned int idB = CHeaderData::createId(); + unsigned int idC = CHeaderData::createId(); + unsigned int idD = CHeaderData::createId(); + unsigned int idE = CHeaderData::createId(); + + CHeaderData header; + header.setMyCall1(m_callsign); + header.setRptCall1(m_callsignG); + header.setRptCall2(m_callsign); // Just for the slow data header + header.setYourCall(wxT("CQCQCQ ")); + header.setDestination(m_address, G2_DV_PORT); + + wxString slowData; + switch (m_language) { + case LANG_DEUTSCH_1: + case LANG_DEUTSCH_2: + header.setMyCall2(wxT("ZEIT")); + slowData.Printf(wxT("Es ist %02u:%02u Uhr"), hour, min); + break; + case LANG_FRANCAIS: + header.setMyCall2(wxT("TIME")); + slowData.Printf(wxT("Il est %02u:%02u"), hour, min); + break; + case LANG_NEDERLANDS: + header.setMyCall2(wxT("TIJD")); + slowData.Printf(wxT("Het is %02u:%02u"), hour, min); + break; + case LANG_SVENSKA: + header.setMyCall2(wxT("TID ")); + slowData.Printf(wxT("Klockan ar %02u:%02u"), hour, min); + break; + case LANG_ENGLISH_US_1: + case LANG_ENGLISH_UK_1: + header.setMyCall2(wxT("TIME")); + if (hour == 0U) + slowData.Printf(wxT("It is 12:%02u AM"), min); + else if (hour == 12U) + slowData.Printf(wxT("It is 12:%02u PM"), min); + else if (hour > 12U) + slowData.Printf(wxT("It is %02u:%02u PM"), hour - 12U, min); + else + slowData.Printf(wxT("It is %02u:%02u AM"), hour, min); + break; + case LANG_ESPANOL: + header.setMyCall2(wxT("HORA")); + if (hour == 1U) + slowData.Printf(wxT("Es la %02u:%02u"), hour, min); + else + slowData.Printf(wxT("Son las %02u:%02u"), hour, min); + break; + case LANG_NORSK: + header.setMyCall2(wxT("TID ")); + slowData.Printf(wxT("Klokken er %02u:%02u"), hour, min); + break; + case LANG_PORTUGUES: + header.setMyCall2(wxT("HORA")); + if (hour == 1U) + slowData.Printf(wxT("E %02u:%02u"), hour, min); + else + slowData.Printf(wxT("Sao %02u:%02u"), hour, min); + break; + default: + header.setMyCall2(wxT("TIME")); + slowData.Printf(wxT("It is %02u:%02u"), hour, min); + break; + } + + m_encoder.setHeaderData(header); + m_encoder.setTextData(slowData); + + m_in = 0U; + + if (m_format != FORMAT_TEXT_TIME) { + wxString text = words.Item(0U); + for (unsigned int i = 1U; i < words.GetCount(); i++) { + text.Append(wxT(" ")); + text.Append(words.Item(i)); + } + + text.Replace(wxT("_"), wxT(" ")); + wxLogMessage(wxT("Sending voice \"%s\", sending text \"%s\""), text.c_str(), slowData.c_str()); + + m_seqNo = 0U; + + // Build the audio + lookup(wxT(" ")); + lookup(wxT(" ")); + lookup(wxT(" ")); + lookup(wxT(" ")); + + for (unsigned int i = 0U; i < words.GetCount(); i++) + lookup(words.Item(i)); + + lookup(wxT(" ")); + lookup(wxT(" ")); + lookup(wxT(" ")); + lookup(wxT(" ")); + + end(); + } else { + wxLogMessage(wxT("Sending text \"%s\""), slowData.c_str()); + + for (unsigned int i = 0U; i < 21U; i++) { + CAMBEData* dataOut = new CAMBEData; + dataOut->setDestination(m_address, G2_DV_PORT); + dataOut->setSeq(i); + + unsigned char buffer[DV_FRAME_LENGTH_BYTES]; + ::memcpy(buffer + 0U, NULL_AMBE_DATA_BYTES, VOICE_FRAME_LENGTH_BYTES); + + // Insert sync bytes when the sequence number is zero, slow data otherwise + if (i == 0U) { + ::memcpy(buffer + VOICE_FRAME_LENGTH_BYTES, DATA_SYNC_BYTES, DATA_FRAME_LENGTH_BYTES); + m_encoder.sync(); + } else { + m_encoder.getTextData(buffer + VOICE_FRAME_LENGTH_BYTES); + } + + dataOut->setData(buffer, DV_FRAME_LENGTH_BYTES); + + m_data[m_in] = dataOut; + m_in++; + } + + CAMBEData* dataOut = new CAMBEData; + dataOut->setData(END_PATTERN_BYTES, DV_FRAME_LENGTH_BYTES); + dataOut->setDestination(m_address, G2_DV_PORT); + dataOut->setSeq(0U); + dataOut->setEnd(true); + + m_data[m_in] = dataOut; + m_in++; + } + + if (m_in == 0U) { + wxLogWarning(wxT("Not sending, no audio files loaded")); + return false; + } + + if (!m_callsignA.IsEmpty()) { + header.setRptCall2(m_callsignA); + header.setId(idA); + sendHeader(header); + } + + if (!m_callsignB.IsEmpty()) { + header.setRptCall2(m_callsignB); + header.setId(idB); + sendHeader(header); + } + + if (!m_callsignC.IsEmpty()) { + header.setRptCall2(m_callsignC); + header.setId(idC); + sendHeader(header); + } + + if (!m_callsignD.IsEmpty()) { + header.setRptCall2(m_callsignD); + header.setId(idD); + sendHeader(header); + } + + if (!m_callsignE.IsEmpty()) { + header.setRptCall2(m_callsignE); + header.setId(idE); + sendHeader(header); + } + + unsigned int out = 0U; + + wxStopWatch timer; + timer.Start(); + + for (;;) { + unsigned int needed = timer.Time() / DSTAR_FRAME_TIME_MS; + + while (out < needed) { + CAMBEData* data = m_data[out]; + m_data[out] = NULL; + out++; + + if (!m_callsignA.IsEmpty()) { + data->setId(idA); + sendData(*data); + } + + if (!m_callsignB.IsEmpty()) { + data->setId(idB); + sendData(*data); + } + + if (!m_callsignC.IsEmpty()) { + data->setId(idC); + sendData(*data); + } + + if (!m_callsignD.IsEmpty()) { + data->setId(idD); + sendData(*data); + } + + if (!m_callsignE.IsEmpty()) { + data->setId(idE); + sendData(*data); + } + + delete data; + + if (m_in == out) + return true; + } + + ::wxMilliSleep(10UL); + } +} + +bool CTimeServerThread::sendHeader(const CHeaderData &header) +{ + unsigned char buffer[60U]; + unsigned int length = header.getG2Data(buffer, 60U, true); + +#if defined(DUMP_TX) + CUtils::dump(wxT("Sending Header"), buffer, length); + return true; +#else + for (unsigned int i = 0U; i < 5U; i++) { + bool res = m_socket.write(buffer, length, header.getYourAddress(), header.getYourPort()); + if (!res) + return false; + } + + return true; +#endif +} + +bool CTimeServerThread::sendData(const CAMBEData& data) +{ + unsigned char buffer[40U]; + unsigned int length = data.getG2Data(buffer, 40U); + +#if defined(DUMP_TX) + CUtils::dump(wxT("Sending Data"), buffer, length); + return true; +#else + return m_socket.write(buffer, length, data.getYourAddress(), data.getYourPort()); +#endif +} diff --git a/TimeServer/TimeServerThread.h b/TimeServer/TimeServerThread.h new file mode 100644 index 0000000..eb6d26e --- /dev/null +++ b/TimeServer/TimeServerThread.h @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2012,2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef TimeServerThread_H +#define TimeServerThread_H + +#include "SlowDataEncoder.h" +#include "UDPReaderWriter.h" +#include "TimeServerDefs.h" +#include "HeaderData.h" +#include "AMBEData.h" + +#include + +class CIndexRecord { +public: + CIndexRecord(const wxString& name, unsigned int start, unsigned int length) : + m_name(name), + m_start(start), + m_length(length) + { + } + + wxString getName() const + { + return m_name; + } + + unsigned int getStart() const + { + return m_start; + } + + unsigned int getLength() const + { + return m_length; + } + +private: + wxString m_name; + unsigned int m_start; + unsigned int m_length; +}; + +WX_DECLARE_STRING_HASH_MAP(CIndexRecord*, CIndexList_t); + +class CTimeServerThread { +public: + CTimeServerThread(); + virtual ~CTimeServerThread(); + + virtual bool setGateway(const wxString& callsign, bool sendA, bool sendB, bool sendC, bool sendD, bool sendE, const wxString& address); + virtual void setAnnouncements(LANGUAGE language, FORMAT format, INTERVAL interval); + + virtual void run(); + virtual void kill(); + +private: + CUDPReaderWriter m_socket; + wxString m_callsign; + wxString m_callsignA; + wxString m_callsignB; + wxString m_callsignC; + wxString m_callsignD; + wxString m_callsignE; + wxString m_callsignG; + in_addr m_address; + LANGUAGE m_language; + FORMAT m_format; + INTERVAL m_interval; + unsigned char* m_ambe; + unsigned int m_ambeLength; + CIndexList_t m_index; + unsigned int m_seqNo; + unsigned int m_in; + CSlowDataEncoder m_encoder; + CAMBEData** m_data; + bool m_killed; + + void sendTime(unsigned int hour, unsigned int min); + + wxArrayString sendTimeEnGB1(unsigned int hour, unsigned int min); + wxArrayString sendTimeEnGB2(unsigned int hour, unsigned int min); + wxArrayString sendTimeEnUS1(unsigned int hour, unsigned int min); + wxArrayString sendTimeEnUS2(unsigned int hour, unsigned int min); + wxArrayString sendTimeDeDE1(unsigned int hour, unsigned int min); + wxArrayString sendTimeDeDE2(unsigned int hour, unsigned int min); + wxArrayString sendTimeFrFR(unsigned int hour, unsigned int min); + wxArrayString sendTimeNlNL(unsigned int hour, unsigned int min); + wxArrayString sendTimeSeSE(unsigned int hour, unsigned int min); + wxArrayString sendTimeEsES(unsigned int hour, unsigned int min); + wxArrayString sendTimeNoNO(unsigned int hour, unsigned int min); + wxArrayString sendTimePtPT(unsigned int hour, unsigned int min); + + bool send(const wxArrayString& words, unsigned int hour, unsigned int min); + bool sendHeader(const CHeaderData& header); + bool sendData(const CAMBEData& data); + + bool loadAMBE(); + bool readAMBE(const wxString& name); + bool readIndex(const wxString& name); + + bool lookup(const wxString& id); + void end(); +}; + +#endif diff --git a/TimeServer/TimeServerThreadHelper.cpp b/TimeServer/TimeServerThreadHelper.cpp new file mode 100644 index 0000000..f5b7f8e --- /dev/null +++ b/TimeServer/TimeServerThreadHelper.cpp @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2012 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "TimeServerThreadHelper.h" + +CTimeServerThreadHelper::CTimeServerThreadHelper(CTimeServerThread* thread) : +wxThread(wxTHREAD_JOINABLE), +m_thread(thread) +{ + wxASSERT(thread != NULL); +} + +CTimeServerThreadHelper::~CTimeServerThreadHelper() +{ + delete m_thread; +} + +void CTimeServerThreadHelper::start() +{ + Create(); + + SetPriority(100U); + + Run(); +} + +void* CTimeServerThreadHelper::Entry() +{ + wxASSERT(m_thread != NULL); + + m_thread->run(); + + return NULL; +} + +void CTimeServerThreadHelper::kill() +{ + wxASSERT(m_thread != NULL); + + m_thread->kill(); + + Wait(); +} diff --git a/TimeServer/TimeServerThreadHelper.h b/TimeServer/TimeServerThreadHelper.h new file mode 100644 index 0000000..4c276d1 --- /dev/null +++ b/TimeServer/TimeServerThreadHelper.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2012,2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef TimeServerThreadHelper_H +#define TimeServerThreadHelper_H + +#include "TimeServerThread.h" + +#include + +class CTimeServerThreadHelper : public wxThread { + +public: + CTimeServerThreadHelper(CTimeServerThread* thread); + virtual ~CTimeServerThreadHelper(); + + virtual void start(); + + virtual void* Entry(); + + virtual void kill(); + +private: + CTimeServerThread* m_thread; +}; + +#endif diff --git a/TimerControl/TimerControl.vcxproj b/TimerControl/TimerControl.vcxproj new file mode 100644 index 0000000..96779de --- /dev/null +++ b/TimerControl/TimerControl.vcxproj @@ -0,0 +1,209 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {68CFAB6D-AED3-4B8A-BCB3-EE4136CA00A3} + TimerControl + Win32Proj + 10.0.16299.0 + + + + Application + v141 + Unicode + true + + + Application + v141 + Unicode + true + + + Application + v141 + Unicode + + + Application + v141 + Unicode + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>14.0.24720.0 + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + true + $(WXWIN)\include;$(WXWIN)\lib\vc_dll\mswud;$(IncludePath) + + + true + $(WXWIN)\include;$(WXWIN)\lib\vc_x64_dll\mswud;$(IncludePath) + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + false + + + false + + + + Disabled + $(WXWIN)\include\msvc;$(WXWIN)\include;../Common;../GUICommon;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;WINVER=0x0400;__WXMSW__;WXUSINGDLL;wxUSE_GUI=1;__WXDEBUG__;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + Level4 + EditAndContinue + + + ws2_32.lib;%(AdditionalDependencies) + $(WXWIN)\lib\vc_dll;%(AdditionalLibraryDirectories) + true + Windows + MachineX86 + + + + + Disabled + $(WXWIN)\include\msvc;$(WXWIN)\include;../Common;../GUICommon;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;WINVER=0x0400;__WXMSW__;WXUSINGDLL;wxUSE_GUI=1;__WXDEBUG__;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + + + Level4 + ProgramDatabase + + + ws2_32.lib;%(AdditionalDependencies) + $(WXWIN)\lib\vc_x64_dll;%(AdditionalLibraryDirectories) + true + Windows + + + + + MaxSpeed + true + $(WXWIN)\include\msvc;$(WXWIN)\include;../Common;../GUICommon;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;WINVER=0x0400;__WXMSW__;WXUSINGDLL;wxUSE_GUI=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) + MultiThreadedDLL + true + + Level3 + ProgramDatabase + + + ws2_32.lib;%(AdditionalDependencies) + $(WXWIN)\lib\vc_dll;%(AdditionalLibraryDirectories) + true + Windows + true + true + MachineX86 + + + + + MaxSpeed + true + $(WXWIN)\include\msvc;$(WXWIN)\include;../Common;../GUICommon;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;WINVER=0x0400;__WXMSW__;WXUSINGDLL;wxUSE_GUI=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) + MultiThreadedDLL + true + + + Level3 + ProgramDatabase + + + ws2_32.lib;%(AdditionalDependencies) + $(WXWIN)\lib\vc_x64_dll;%(AdditionalLibraryDirectories) + true + Windows + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {e793cb8e-2ac9-431a-bbfc-3f52537bb3cf} + false + + + {02d03515-0bbe-4553-8c40-566a597478f8} + false + + + + + + \ No newline at end of file diff --git a/TimerControl/TimerControl.vcxproj.filters b/TimerControl/TimerControl.vcxproj.filters new file mode 100644 index 0000000..592c7a5 --- /dev/null +++ b/TimerControl/TimerControl.vcxproj.filters @@ -0,0 +1,83 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/TimerControl/TimerControlApp.cpp b/TimerControl/TimerControlApp.cpp new file mode 100644 index 0000000..5ac83c6 --- /dev/null +++ b/TimerControl/TimerControlApp.cpp @@ -0,0 +1,262 @@ +/* + * Copyright (C) 2011-2015 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "TimerControlThread.h" +#include "TimerControlDefs.h" +#include "TimerControlApp.h" +#include "Version.h" +#include "Logger.h" + +#include +#include +#include + +IMPLEMENT_APP(CTimerControlApp) + +const wxChar* NAME_PARAM = wxT("Name"); +const wxChar* NOLOGGING_SWITCH = wxT("nolog"); +const wxChar* LOGDIR_OPTION = wxT("logdir"); +const wxChar* CONFDIR_OPTION = wxT("confdir"); + +static const wxString LOG_BASE_NAME = wxT("timercontrol"); + +CTimerControlApp::CTimerControlApp() : +wxApp(), +m_name(), +m_fileName(), +m_nolog(false), +m_logDir(), +m_confDir(), +m_frame(NULL), +m_config(NULL), +m_thread(NULL) +{ +} + +CTimerControlApp::~CTimerControlApp() +{ +} + +bool CTimerControlApp::OnInit() +{ + SetVendorName(VENDOR_NAME); + + if (!wxApp::OnInit()) + return false; + + if (!m_nolog) { + wxString logBaseName = LOG_BASE_NAME; + if (!m_name.IsEmpty()) { + logBaseName.Append(wxT("_")); + logBaseName.Append(m_name); + } + +#if defined(__WINDOWS__) + if (m_logDir.IsEmpty()) + m_logDir = wxFileName::GetHomeDir(); +#else + if (m_logDir.IsEmpty()) + m_logDir = LOG_DIR; +#endif + + wxLog* log = new CLogger(m_logDir, logBaseName); + wxLog::SetActiveTarget(log); + } else { + new wxLogNull; + } + +#if defined(__WINDOWS__) + m_config = new CTimerControlConfig(new wxConfig(APPLICATION_NAME), m_name); +#else + if (m_confDir.IsEmpty()) + m_confDir = wxT(CONF_DIR); + + m_config = new CTimerControlConfig(m_confDir, m_name); +#endif + + wxString frameName = APPLICATION_NAME + wxT(" - "); + if (!m_name.IsEmpty()) { + frameName.Append(m_name); + frameName.Append(wxT(" - ")); + } + frameName.Append(VERSION); + + if (!m_name.IsEmpty()) { + wxString fileBase = SCHEDULE_BASE_NAME; + fileBase.Append(wxT("_")); + fileBase.Append(m_name); + fileBase.Replace(wxT(" "), wxT("_")); + + wxString dir = m_confDir; + if (dir.IsEmpty()) + dir = wxFileName::GetHomeDir(); + + wxFileName fileName(dir, fileBase, wxT("dat")); + m_fileName = fileName.GetFullPath(); + } else { + wxString dir = m_confDir; + if (dir.IsEmpty()) + dir = wxFileName::GetHomeDir(); + + wxFileName fileName(dir, SCHEDULE_BASE_NAME, wxT("dat")); + m_fileName = fileName.GetFullPath(); + } + + wxPoint position = wxDefaultPosition; + + int x, y; + getPosition(x, y); + if (x >= 0 && y >= 0) + position = wxPoint(x, y); + + bool delay; + getDelay(delay); + + m_frame = new CTimerControlFrame(frameName, position, delay); + m_frame->Show(); + + SetTopWindow(m_frame); + + wxLogInfo(wxT("Starting ") + APPLICATION_NAME + wxT(" - ") + VERSION); + + // Log the version of wxWidgets and the Operating System + wxLogInfo(wxT("Using wxWidgets %d.%d.%d on %s"), wxMAJOR_VERSION, wxMINOR_VERSION, wxRELEASE_NUMBER, ::wxGetOsDescription().c_str()); + + createThread(); + + return wxApp::OnInit(); +} + +int CTimerControlApp::OnExit() +{ + wxLogInfo(APPLICATION_NAME + wxT(" is exiting")); + + m_thread->kill(); + + delete m_config; + + return 0; +} + +void CTimerControlApp::OnInitCmdLine(wxCmdLineParser& parser) +{ + parser.AddSwitch(NOLOGGING_SWITCH, wxEmptyString, wxEmptyString, wxCMD_LINE_PARAM_OPTIONAL); + parser.AddOption(LOGDIR_OPTION, wxEmptyString, wxEmptyString, wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL); + parser.AddOption(CONFDIR_OPTION, wxEmptyString, wxEmptyString, wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL); + parser.AddParam(NAME_PARAM, wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL); + + wxApp::OnInitCmdLine(parser); +} + +bool CTimerControlApp::OnCmdLineParsed(wxCmdLineParser& parser) +{ + if (!wxApp::OnCmdLineParsed(parser)) + return false; + + m_nolog = parser.Found(NOLOGGING_SWITCH); + + wxString logDir; + bool found = parser.Found(LOGDIR_OPTION, &logDir); + if (found) + m_logDir = logDir; + + wxString confDir; + found = parser.Found(CONFDIR_OPTION, &confDir); + if (found) + m_confDir = confDir; + + if (parser.GetParamCount() > 0U) + m_name = parser.GetParam(0U); + + return true; +} + +#if defined(__WXDEBUG__) +void CTimerControlApp::OnAssertFailure(const wxChar* file, int line, const wxChar* func, const wxChar* cond, const wxChar* msg) +{ + wxLogFatalError(wxT("Assertion failed on line %d in file %s and function %s: %s %s"), line, file, func, cond, msg); +} +#endif + +void CTimerControlApp::getGateway(wxString& address, unsigned int& port, wxString& password) const +{ + m_config->getGateway(address, port, password); +} + +void CTimerControlApp::setGateway(const wxString& address, unsigned int port, const wxString& password) +{ + m_config->setGateway(address, port, password); +} + +void CTimerControlApp::getDelay(bool& delay) const +{ + m_config->getDelay(delay); +} + +void CTimerControlApp::setDelay(bool delay) +{ + m_config->setDelay(delay); +} + +void CTimerControlApp::getPosition(int& x, int& y) const +{ + m_config->getPosition(x, y); +} + +void CTimerControlApp::setPosition(int x, int y) +{ + m_config->setPosition(x, y); +} + +void CTimerControlApp::writeConfig() +{ + m_config->write(); +} + +void CTimerControlApp::writeItems() +{ + m_frame->writeItems(); + + m_thread->reload(); +} + +void CTimerControlApp::createThread() +{ + CTimerControlThread* thread = new CTimerControlThread; + + wxString address, password; + unsigned int port; + getGateway(address, port, password); + thread->setGateway(address, port, password); + wxLogInfo(wxT("Gateway set to %s:%u"), address.c_str(), port); + + bool delay; + getDelay(delay); + thread->setDelay(delay); + wxLogInfo(wxT("Delay set to %d"), int(delay)); + + wxLogInfo(wxT("Schedule file is %s"), m_fileName.c_str()); + m_frame->setFileName(m_fileName); + thread->setFileName(m_fileName); + + thread->reload(); + + // Convert the worker class into a thread + m_thread = new CTimerControlThreadHelper(thread); + m_thread->start(); +} diff --git a/TimerControl/TimerControlApp.h b/TimerControl/TimerControlApp.h new file mode 100644 index 0000000..5cc0800 --- /dev/null +++ b/TimerControl/TimerControlApp.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2011,2012,2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef TimerControlApp_H +#define TimerControlApp_H + +#include "TimerControlThreadHelper.h" +#include "TimerControlConfig.h" +#include "TimerControlFrame.h" +#include "TimerControlItem.h" + +#include + +class CTimerControlApp : public wxApp { + +public: + CTimerControlApp(); + virtual ~CTimerControlApp(); + + virtual bool OnInit(); + virtual int OnExit(); + + virtual void OnInitCmdLine(wxCmdLineParser& parser); + virtual bool OnCmdLineParsed(wxCmdLineParser& parser); + + // This is overridden because dialog boxes from threads are bad news +#if defined(__WXDEBUG__) + virtual void OnAssertFailure(const wxChar* file, int line, const wxChar* func, const wxChar* cond, const wxChar* msg); +#endif + + virtual void getGateway(wxString& address, unsigned int& port, wxString& password) const; + virtual void setGateway(const wxString& address, unsigned int port, const wxString& password); + + virtual void getDelay(bool& enabled) const; + virtual void setDelay(bool enabled); + + virtual void getPosition(int& x, int& y) const; + virtual void setPosition(int x, int y); + + virtual void writeConfig(); + + virtual void writeItems(); + +private: + wxString m_name; + wxString m_fileName; + bool m_nolog; + wxString m_logDir; + wxString m_confDir; + CTimerControlFrame* m_frame; + CTimerControlConfig* m_config; + CTimerControlThreadHelper* m_thread; + + void createThread(); +}; + +DECLARE_APP(CTimerControlApp) + +#endif diff --git a/TimerControl/TimerControlAppD.cpp b/TimerControl/TimerControlAppD.cpp new file mode 100644 index 0000000..26ab75a --- /dev/null +++ b/TimerControl/TimerControlAppD.cpp @@ -0,0 +1,206 @@ +/* + * Copyright (C) 2011-2015 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "TimerControlConfig.h" +#include "TimerControlDefs.h" +#include "TimerControlAppD.h" +#include "Version.h" +#include "Logger.h" + +#include +#include +#include +#include + +const wxChar* NAME_PARAM = wxT("Name"); +const wxChar* NOLOGGING_SWITCH = wxT("nolog"); +const wxChar* LOGDIR_OPTION = wxT("logdir"); +const wxChar* CONFDIR_OPTION = wxT("confdir"); +const wxChar* DAEMON_SWITCH = wxT("daemon"); + +static const wxString LOG_BASE_NAME = wxT("timercontrold"); + +int main(int argc, char** argv) +{ + bool res = ::wxInitialize(); + if (!res) { + ::fprintf(stderr, "timercontrold: failed to initialise the wxWidgets library, exiting\n"); + return -1; + } + + wxCmdLineParser parser(argc, argv); + parser.AddSwitch(NOLOGGING_SWITCH, wxEmptyString, wxEmptyString, wxCMD_LINE_PARAM_OPTIONAL); + parser.AddSwitch(DAEMON_SWITCH, wxEmptyString, wxEmptyString, wxCMD_LINE_PARAM_OPTIONAL); + parser.AddOption(LOGDIR_OPTION, wxEmptyString, wxEmptyString, wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL); + parser.AddOption(CONFDIR_OPTION, wxEmptyString, wxEmptyString, wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL); + parser.AddParam(NAME_PARAM, wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL); + + int cmd = parser.Parse(); + if (cmd != 0) { + ::wxUninitialize(); + return 0; + } + + bool nolog = parser.Found(NOLOGGING_SWITCH); + bool daemon = parser.Found(DAEMON_SWITCH); + + wxString logDir; + bool found = parser.Found(LOGDIR_OPTION, &logDir); + if (!found) + logDir.Clear(); + + wxString confDir; + found = parser.Found(CONFDIR_OPTION, &confDir); + if (!found) + confDir = wxT(CONF_DIR); + + wxString name; + if (parser.GetParamCount() > 0U) + name = parser.GetParam(0U); + + if (daemon) { + pid_t pid = ::fork(); + + if (pid < 0) { + ::fprintf(stderr, "timercontrold: error in fork(), exiting\n"); + ::wxUninitialize(); + return 1; + } + + // If this is the parent, exit + if (pid > 0) + return 0; + + // We are the child from here onwards + ::setsid(); + + ::chdir("/"); + + ::umask(0); + } + + CTimerControlAppD controller(nolog, logDir, confDir, name); + + if (!controller.init()) { + ::wxUninitialize(); + return 1; + } + + controller.run(); + + ::wxUninitialize(); + return 0; +} + +CTimerControlAppD::CTimerControlAppD(bool nolog, const wxString& logDir, const wxString& confDir, const wxString& name) : +m_name(name), +m_nolog(nolog), +m_logDir(logDir), +m_confDir(confDir), +m_fileName(), +m_thread(NULL) +{ +} + +CTimerControlAppD::~CTimerControlAppD() +{ +} + +bool CTimerControlAppD::init() +{ + if (!m_name.IsEmpty()) { + wxString fileBase = SCHEDULE_BASE_NAME; + fileBase.Append(wxT("_")); + fileBase.Append(m_name); + fileBase.Replace(wxT(" "), wxT("_")); + + wxString dir = m_confDir; + if (dir.IsEmpty()) + dir = wxFileName::GetHomeDir(); + + wxFileName fileName(dir, fileBase, wxT("dat")); + m_fileName = fileName.GetFullPath(); + } else { + wxString dir = m_confDir; + if (dir.IsEmpty()) + dir = wxFileName::GetHomeDir(); + + wxFileName fileName(dir, SCHEDULE_BASE_NAME, wxT("dat")); + m_fileName = fileName.GetFullPath(); + } + + if (!m_nolog) { + wxString logBaseName = LOG_BASE_NAME; + if (!m_name.IsEmpty()) { + logBaseName.Append(wxT("_")); + logBaseName.Append(m_name); + } + +#if defined(__WINDOWS__) + if (m_logDir.IsEmpty()) + m_logDir = wxFileName::GetHomeDir(); +#else + if (m_logDir.IsEmpty()) + m_logDir = LOG_DIR; +#endif + + wxLog* log = new CLogger(m_logDir, logBaseName); + wxLog::SetActiveTarget(log); + } else { + new wxLogNull; + } + + wxLogInfo(wxT("Starting ") + APPLICATION_NAME + wxT(" daemon - ") + VERSION); + + // Log the version of wxWidgets and the Operating System + wxLogInfo(wxT("Using wxWidgets %d.%d.%d on %s"), wxMAJOR_VERSION, wxMINOR_VERSION, wxRELEASE_NUMBER, ::wxGetOsDescription().c_str()); + + return createThread(); +} + +void CTimerControlAppD::run() +{ + m_thread->run(); + + wxLogInfo(APPLICATION_NAME + wxT(" is exiting")); +} + +bool CTimerControlAppD::createThread() +{ + CTimerControlConfig config(m_confDir, m_name); + + m_thread = new CTimerControlThread; + + wxString address, password; + unsigned int port; + config.getGateway(address, port, password); + m_thread->setGateway(address, port, password); + wxLogInfo(wxT("Gateway set to %s:%u"), address.c_str(), port); + + bool delay; + config.getDelay(delay); + m_thread->setDelay(delay); + wxLogInfo(wxT("Delay set to %d"), int(delay)); + + wxLogInfo(wxT("Schedule file is %s"), m_fileName.c_str()); + m_thread->setFileName(m_fileName); + + m_thread->reload(); + + return true; +} diff --git a/TimerControl/TimerControlAppD.h b/TimerControl/TimerControlAppD.h new file mode 100644 index 0000000..5710a91 --- /dev/null +++ b/TimerControl/TimerControlAppD.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2011 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef TimerControlAppD_H +#define TimerControlAppD_H + +#include "TimerControlThread.h" + +#include + +class CTimerControlAppD { + +public: + CTimerControlAppD(bool nolog, const wxString& logDir, const wxString& confDir, const wxString& name); + ~CTimerControlAppD(); + + bool init(); + + void run(); + +private: + wxString m_name; + bool m_nolog; + wxString m_logDir; + wxString m_confDir; + wxString m_fileName; + CTimerControlThread* m_thread; + + bool createThread(); +}; + +#endif diff --git a/TimerControl/TimerControlConfig.cpp b/TimerControl/TimerControlConfig.cpp new file mode 100644 index 0000000..47ad5de --- /dev/null +++ b/TimerControl/TimerControlConfig.cpp @@ -0,0 +1,251 @@ +/* + * Copyright (C) 2011,2012,2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "TimerControlConfig.h" +#include "TimerControlDefs.h" + +const wxString KEY_ADDRESS = wxT("address"); +const wxString KEY_PORT = wxT("port"); +const wxString KEY_PASSWORD = wxT("password"); +const wxString KEY_DELAY = wxT("delay"); +const wxString KEY_WINDOW_X = wxT("windowX"); +const wxString KEY_WINDOW_Y = wxT("windowY"); + +const wxString DEFAULT_ADDRESS = wxEmptyString; +const long DEFAULT_PORT = 0L; +const wxString DEFAULT_PASSWORD = wxEmptyString; +const bool DEFAULT_DELAY = false; +const long DEFAULT_WINDOW_X = -1L; +const long DEFAULT_WINDOW_Y = -1L; + + +#if defined(__WINDOWS__) + +CTimerControlConfig::CTimerControlConfig(wxConfigBase* config, const wxString& name) : +m_config(config), +m_name(wxT("/")), +m_address(DEFAULT_ADDRESS), +m_port(DEFAULT_PORT), +m_password(DEFAULT_PASSWORD), +m_delay(DEFAULT_DELAY), +m_x(DEFAULT_WINDOW_X), +m_y(DEFAULT_WINDOW_Y) +{ + wxASSERT(config != NULL); + + if (!name.IsEmpty()) + m_name = wxT("/") + name; + + m_config->Read(m_name + KEY_ADDRESS, &m_address, DEFAULT_ADDRESS); + + long temp; + m_config->Read(m_name + KEY_PORT, &temp, DEFAULT_PORT); + m_port = (unsigned int)temp; + + m_config->Read(m_name + KEY_PASSWORD, &m_password, DEFAULT_PASSWORD); + + m_config->Read(m_name + KEY_DELAY, &m_delay, DEFAULT_DELAY); + + m_config->Read(m_name + KEY_WINDOW_X, &temp, DEFAULT_WINDOW_X); + m_x = (unsigned int)temp; + + m_config->Read(m_name + KEY_WINDOW_Y, &temp, DEFAULT_WINDOW_Y); + m_y = (unsigned int)temp; +} + +CTimerControlConfig::~CTimerControlConfig() +{ + delete m_config; +} + +#else + +CTimerControlConfig::CTimerControlConfig(const wxString& dir, const wxString& name) : +m_fileName(), +m_address(DEFAULT_ADDRESS), +m_port(DEFAULT_PORT), +m_password(DEFAULT_PASSWORD), +m_delay(DEFAULT_DELAY), +m_x(DEFAULT_WINDOW_X), +m_y(DEFAULT_WINDOW_Y) +{ + wxASSERT(!dir.IsEmpty()); + + wxString fileName = CONFIG_FILE_NAME; + if (!name.IsEmpty()) + fileName = CONFIG_FILE_NAME + wxT("_") + name; + + m_fileName.Assign(dir, fileName); + + wxTextFile file(m_fileName.GetFullPath()); + + bool exists = file.Exists(); + if (!exists) + return; + + bool ret = file.Open(); + if (!ret) { + wxLogError(wxT("Cannot open the config file - %s"), m_fileName.GetFullPath().c_str()); + return; + } + + long temp; + + wxString str = file.GetFirstLine(); + + while (!file.Eof()) { + if (str.GetChar(0U) == wxT('#')) { + str = file.GetNextLine(); + continue; + } + + int n = str.Find(wxT('=')); + if (n == wxNOT_FOUND) { + str = file.GetNextLine(); + continue; + } + + wxString key = str.Left(n); + wxString val = str.Mid(n + 1U); + + if (key.IsSameAs(KEY_ADDRESS)) { + m_address = val; + } else if (key.IsSameAs(KEY_PORT)) { + val.ToLong(&temp); + m_port = (unsigned int)temp; + } else if (key.IsSameAs(KEY_PASSWORD)) { + m_password = val; + } else if (key.IsSameAs(KEY_DELAY)) { + val.ToLong(&temp); + m_delay = temp == 1L; + } else if (key.IsSameAs(KEY_WINDOW_X)) { + val.ToLong(&temp); + m_x = int(temp); + } else if (key.IsSameAs(KEY_WINDOW_Y)) { + val.ToLong(&temp); + m_y = int(temp); + } + + str = file.GetNextLine(); + } + + file.Close(); +} + +CTimerControlConfig::~CTimerControlConfig() +{ +} + +#endif + +void CTimerControlConfig::getGateway(wxString& address, unsigned int& port, wxString& password) const +{ + address = m_address; + port = m_port; + password = m_password; +} + +void CTimerControlConfig::setGateway(const wxString& address, unsigned int port, const wxString& password) +{ + m_address = address; + m_port = port; + m_password = password; +} + +void CTimerControlConfig::getDelay(bool& delay) const +{ + delay = m_delay; +} + +void CTimerControlConfig::setDelay(bool delay) +{ + m_delay = delay; +} + +void CTimerControlConfig::getPosition(int& x, int& y) const +{ + x = m_x; + y = m_y; +} + +void CTimerControlConfig::setPosition(int x, int y) +{ + m_x = x; + m_y = y; +} + +#if defined(__WINDOWS__) + +bool CTimerControlConfig::write() +{ + m_config->Write(m_name + KEY_ADDRESS, m_address); + m_config->Write(m_name + KEY_PORT, long(m_port)); + m_config->Write(m_name + KEY_PASSWORD, m_password); + m_config->Write(m_name + KEY_DELAY, m_delay); + m_config->Write(m_name + KEY_WINDOW_X, long(m_x)); + m_config->Write(m_name + KEY_WINDOW_Y, long(m_y)); + m_config->Flush(); + + return true; +} + +#else + +bool CTimerControlConfig::write() +{ + wxTextFile file(m_fileName.GetFullPath()); + + bool exists = file.Exists(); + if (exists) { + bool ret = file.Open(); + if (!ret) { + wxLogError(wxT("Cannot open the config file - %s"), m_fileName.GetFullPath().c_str()); + return false; + } + + // Remove the existing file entries + file.Clear(); + } else { + bool ret = file.Create(); + if (!ret) { + wxLogError(wxT("Cannot create the config file - %s"), m_fileName.GetFullPath().c_str()); + return false; + } + } + + wxString buffer; + buffer.Printf(wxT("%s=%s"), KEY_ADDRESS.c_str(), m_address.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%u"), KEY_PORT.c_str(), m_port); file.AddLine(buffer); + buffer.Printf(wxT("%s=%s"), KEY_PASSWORD.c_str(), m_password.c_str()); file.AddLine(buffer); + buffer.Printf(wxT("%s=%d"), KEY_DELAY.c_str(), m_delay ? 1 : 0); file.AddLine(buffer); + buffer.Printf(wxT("%s=%d"), KEY_WINDOW_X.c_str(), m_x); file.AddLine(buffer); + buffer.Printf(wxT("%s=%d"), KEY_WINDOW_Y.c_str(), m_y); file.AddLine(buffer); + + bool ret = file.Write(); + if (!ret) { + file.Close(); + wxLogError(wxT("Cannot write the config file - %s"), m_fileName.GetFullPath().c_str()); + return false; + } + + file.Close(); + + return true; +} + +#endif diff --git a/TimerControl/TimerControlConfig.h b/TimerControl/TimerControlConfig.h new file mode 100644 index 0000000..9fb5578 --- /dev/null +++ b/TimerControl/TimerControlConfig.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2011,2012,2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef TimerControlConfig_H +#define TimerControlConfig_H + +#include +#include +#include + +class CTimerControlConfig { + +public: +#if defined(__WINDOWS__) + CTimerControlConfig(wxConfigBase* config, const wxString& name); +#else + CTimerControlConfig(const wxString& dir, const wxString& name); +#endif + ~CTimerControlConfig(); + + void getGateway(wxString& address, unsigned int& port, wxString& password) const; + void setGateway(const wxString& address, unsigned int port, const wxString& password); + + void getDelay(bool& enabled) const; + void setDelay(bool enabled); + + void getPosition(int& x, int& y) const; + void setPosition(int x, int y); + + bool write(); + +private: +#if defined(__WINDOWS__) + wxConfigBase* m_config; + wxString m_name; +#else + wxFileName m_fileName; +#endif + wxString m_address; + unsigned int m_port; + wxString m_password; + bool m_delay; + int m_x; + int m_y; +}; + +#endif diff --git a/TimerControl/TimerControlDefs.h b/TimerControl/TimerControlDefs.h new file mode 100644 index 0000000..4ce01af --- /dev/null +++ b/TimerControl/TimerControlDefs.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2011 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef TimerControlDefs_H +#define TimerControlDefs_H + +#include + +const wxString APPLICATION_NAME = wxT("Timer Control"); + +#if !defined(__WINDOWS__) +const wxString CONFIG_FILE_NAME = wxT("timercontrol"); +#endif + +const wxString SCHEDULE_BASE_NAME = wxT("Schedule"); + +#endif diff --git a/TimerControl/TimerControlFrame.cpp b/TimerControl/TimerControlFrame.cpp new file mode 100644 index 0000000..65fdd3a --- /dev/null +++ b/TimerControl/TimerControlFrame.cpp @@ -0,0 +1,343 @@ +/* + * Copyright (C) 2011-2015 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "TimerControlPreferences.h" +#include "TimerControlItemFile.h" +#include "TimerControlFrame.h" +#include "TimerControlItem.h" +#include "TimerControlDefs.h" +#include "TimerControlApp.h" +#include "Version.h" +#include "SHA256.h" + +const unsigned int BORDER_SIZE = 5U; + +#if defined(__WINDOWS__) +const unsigned int MAIN_HEIGHT = 350U; +const unsigned int MAIN_WIDTH = 500U; +#else +const unsigned int MAIN_HEIGHT = 400U; +const unsigned int MAIN_WIDTH = 590U; +#endif + +#include + +enum { + Menu_Edit_Preferences = 7000, + + Timer_Timer1, + Timer_Timer2 +}; + +BEGIN_EVENT_TABLE(CTimerControlFrame, wxFrame) + EVT_MENU(wxID_EXIT, CTimerControlFrame::onQuit) + EVT_MENU(Menu_Edit_Preferences, CTimerControlFrame::onPreferences) + EVT_MENU(wxID_ABOUT, CTimerControlFrame::onAbout) + + EVT_TIMER(Timer_Timer1, CTimerControlFrame::onTimer1) + EVT_TIMER(Timer_Timer2, CTimerControlFrame::onTimer2) + + EVT_CLOSE(CTimerControlFrame::onClose) +END_EVENT_TABLE() + +CTimerControlFrame::CTimerControlFrame(const wxString& title, const wxPoint& position, bool delay) : +wxFrame(NULL, -1, title, position), +m_state(TCFS_NORMAL), +m_timer1(this, Timer_Timer1), +m_timer2(this, Timer_Timer2), +m_noteBook(NULL), +m_handler(NULL), +m_password(), +m_fileName(), +m_repeaters() +{ + SetMenuBar(createMenuBar()); + + wxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL); + + wxPanel* panel = new wxPanel(this, -1); + + wxBoxSizer* panelSizer = new wxBoxSizer(wxVERTICAL); + + m_noteBook = new wxNotebook(panel, -1, wxDefaultPosition, wxSize(MAIN_WIDTH, MAIN_HEIGHT)); + panelSizer->Add(m_noteBook, 0, wxALL | wxGROW, BORDER_SIZE); + + panel->SetSizer(panelSizer); + + panelSizer->SetSizeHints(panel); + + mainSizer->Add(panel); + + SetSizer(mainSizer); + mainSizer->SetSizeHints(this); + + m_timer1.Start(delay ? 20000 : 100, wxTIMER_ONE_SHOT); +} + +CTimerControlFrame::~CTimerControlFrame() +{ +} + +wxMenuBar* CTimerControlFrame::createMenuBar() +{ + wxMenu* fileMenu = new wxMenu(); + fileMenu->Append(wxID_EXIT, _("Exit")); + + wxMenu* editMenu = new wxMenu(); + editMenu->Append(Menu_Edit_Preferences, _("Preferences...")); + + wxMenu* helpMenu = new wxMenu(); + helpMenu->Append(wxID_ABOUT, _("About Timer Control")); + + wxMenuBar* menuBar = new wxMenuBar(); + menuBar->Append(fileMenu, _("File")); + menuBar->Append(editMenu, _("Edit")); + menuBar->Append(helpMenu, _("Help")); + + return menuBar; +} + +void CTimerControlFrame::onQuit(wxCommandEvent&) +{ + Close(false); +} + +void CTimerControlFrame::onClose(wxCloseEvent&) +{ + int x, y; + GetPosition(&x, &y); + if (x >= 0 && y >= 0) { + ::wxGetApp().setPosition(x, y); + ::wxGetApp().writeConfig(); + } + + m_timer1.Stop(); + m_timer2.Stop(); + + if (m_handler != NULL) { + m_handler->logout(); + m_handler->close(); + } + + Destroy(); +} + +void CTimerControlFrame::onPreferences(wxCommandEvent&) +{ + wxString address, password; + unsigned int port; + ::wxGetApp().getGateway(address, port, password); + + bool delay; + ::wxGetApp().getDelay(delay); + + CTimerControlPreferences dialog1(this, -1, address, port, password, delay); + if (dialog1.ShowModal() != wxID_OK) + return; + + address = dialog1.getAddress(); + port = dialog1.getPort(); + password = dialog1.getPassword(); + + delay = dialog1.getDelay(); + + ::wxGetApp().setGateway(address, port, password); + ::wxGetApp().setDelay(delay); + ::wxGetApp().writeConfig(); + + wxMessageDialog dialog2(this, _("The changes made will not take effect\nuntil the application is restarted"), _("Timer Control Information"), wxICON_INFORMATION); + dialog2.ShowModal(); +} + +void CTimerControlFrame::onAbout(wxCommandEvent&) +{ + wxAboutDialogInfo info; + info.AddDeveloper(wxT("Jonathan Naylor, G4KLX")); + info.SetCopyright(wxT("(C) 2011-2015 using GPL v2 or later")); + info.SetName(APPLICATION_NAME); + info.SetVersion(VERSION); + info.SetDescription(_("This program allows for the controlling of\nthe ircDDB Gateway.")); + + ::wxAboutBox(info); +} + +void CTimerControlFrame::onTimer1(wxTimerEvent&) +{ + startup(); +} + +void CTimerControlFrame::onTimer2(wxTimerEvent&) +{ + TC_TYPE type = m_handler->readType(); + + switch (type) { + case TCT_NONE: + m_handler->retry(); + break; + + case TCT_ACK: + if (m_state == TCFS_HASH) { + m_handler->setLoggedIn(true); + m_handler->getCallsigns(); + m_state = TCFS_NORMAL; + } + break; + + case TCT_NAK: { + if (m_state == TCFS_HASH || m_state == TCFS_LOGIN) + m_handler->setLoggedIn(false); + m_handler->logout(); + + wxString text = m_handler->readNAK(); + m_state = TCFS_NORMAL; + ::wxMessageBox(text); + } + break; + + case TCT_RANDOM: { + unsigned int rnd = m_handler->readRandom(); + sendHash(rnd); + m_state = TCFS_HASH; + } + break; + + case TCT_CALLSIGNS: { + m_noteBook->DeleteAllPages(); + + wxArrayString data = m_handler->readCallsigns(); + + for (unsigned int i = 0U; i < data.GetCount(); i++) + addRepeater(data.Item(i)); + + m_handler->logout(); + + loadItems(); + } + break; + } +} + +void CTimerControlFrame::startup() +{ + wxString address; + unsigned int port; + ::wxGetApp().getGateway(address, port, m_password); + + if (address.IsEmpty() || port == 0U || m_password.IsEmpty()) + return; + + m_handler = new CTimerControlRemoteControlHandler(address, port); + + bool ret = m_handler->open(); + if (!ret) { + delete m_handler; + m_handler = NULL; + return; + } + + ret = m_handler->login(); + if (!ret) { + m_handler->close(); + delete m_handler; + m_handler = NULL; + return; + } + + m_state = TCFS_LOGIN; + + m_timer2.Start(100, wxTIMER_CONTINUOUS); +} + +void CTimerControlFrame::addRepeater(const wxString& callsign) +{ + CTimerControlRepeaterPanel* repeater = new CTimerControlRepeaterPanel(m_noteBook, -1, callsign); + + m_noteBook->AddPage(repeater, callsign, false); + + m_repeaters[callsign] = repeater; +} + +void CTimerControlFrame::setFileName(const wxString& fileName) +{ + m_fileName = fileName; +} + +void CTimerControlFrame::loadItems() +{ + CTimerControlItemFile file(m_fileName); + + unsigned int count; + CTimerControlItem** items = file.readItems(count); + + if (count == 0U) + return; + + for (CRepeater_t::iterator it = m_repeaters.begin(); it != m_repeaters.end(); ++it) + (*it).second->load(items, count); + + delete[] items; +} + +void CTimerControlFrame::writeItems() +{ + // Count the total number of items from all the panels + unsigned int count = 0U; + for (CRepeater_t::iterator it = m_repeaters.begin(); it != m_repeaters.end(); ++it) + count += (*it).second->getCount(); + + if (count == 0U) + return; + + CTimerControlItem** items = new CTimerControlItem*[count]; + + unsigned int n = 0U; + for (CRepeater_t::iterator it = m_repeaters.begin(); it != m_repeaters.end(); ++it) { + unsigned int count1 = (*it).second->getCount(); + CTimerControlItem** items1 = (*it).second->getItems(); + + for (unsigned int i = 0U; i < count1; i++, n++) + items[n] = items1[i]; + + delete[] items1; + } + + CTimerControlItemFile file(m_fileName); + + file.writeItems(items, count); + + delete[] items; +} + +void CTimerControlFrame::sendHash(unsigned int rnd) +{ + unsigned int len = m_password.Len() + sizeof(unsigned int); + unsigned char* in = new unsigned char[len]; + unsigned char* out = new unsigned char[32U]; + + ::memcpy(in, &rnd, sizeof(unsigned int)); + for (unsigned int i = 0U; i < m_password.Len(); i++) + in[i + sizeof(unsigned int)] = m_password.GetChar(i); + + CSHA256 sha256; + sha256.buffer(in, len, out); + + m_handler->sendHash(out, 32U); + + delete[] in; + delete[] out; +} diff --git a/TimerControl/TimerControlFrame.h b/TimerControl/TimerControlFrame.h new file mode 100644 index 0000000..b608f7a --- /dev/null +++ b/TimerControl/TimerControlFrame.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2011,2012 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef TimerControlFrame_H +#define TimerControlFrame_H + +#include "TimerControlRemoteControlHandler.h" +#include "TimerControlRepeaterPanel.h" +#include "Defs.h" + +#include +#include + +WX_DECLARE_STRING_HASH_MAP(CTimerControlRepeaterPanel*, CRepeater_t); + +enum TCF_STATE { + TCFS_NORMAL, + TCFS_LOGIN, + TCFS_HASH +}; + +class CTimerControlFrame : public wxFrame { +public: + CTimerControlFrame(const wxString& title, const wxPoint& position, bool delay); + virtual ~CTimerControlFrame(); + + virtual void onQuit(wxCommandEvent& event); + virtual void onPreferences(wxCommandEvent& event); + virtual void onAbout(wxCommandEvent& event); + virtual void onClose(wxCloseEvent& event); + virtual void onTimer1(wxTimerEvent& event); + virtual void onTimer2(wxTimerEvent& event); + + virtual void setFileName(const wxString& fileName); + + virtual void writeItems(); + +private: + TCF_STATE m_state; + wxTimer m_timer1; + wxTimer m_timer2; + wxNotebook* m_noteBook; + CTimerControlRemoteControlHandler* m_handler; + wxString m_password; + wxString m_fileName; + CRepeater_t m_repeaters; + + DECLARE_EVENT_TABLE() + + wxMenuBar* createMenuBar(); + void startup(); + void addRepeater(const wxString& callsign); + void sendHash(unsigned int rnd); + void loadItems(); +}; + +#endif diff --git a/TimerControl/TimerControlItem.h b/TimerControl/TimerControlItem.h new file mode 100644 index 0000000..ec5ba64 --- /dev/null +++ b/TimerControl/TimerControlItem.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2011 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef TimerControlItem_H +#define TimerControlItem_H + +#include "Defs.h" + +#include + +struct CTimerControlItem { + wxString m_repeater; + unsigned int m_day; + unsigned int m_hour; + unsigned int m_minute; + wxString m_reflector; + RECONNECT m_reconnect; +}; + +#endif diff --git a/TimerControl/TimerControlItemFile.cpp b/TimerControl/TimerControlItemFile.cpp new file mode 100644 index 0000000..7de3932 --- /dev/null +++ b/TimerControl/TimerControlItemFile.cpp @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2011,2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "TimerControlItemFile.h" + +#include +#include + +const unsigned int RECORD_LENGTH = 32U; + +CTimerControlItemFile::CTimerControlItemFile(const wxString& fileName) : +m_fileName(fileName), +m_mutex() +{ +} + +CTimerControlItemFile::~CTimerControlItemFile() +{ +} + +bool CTimerControlItemFile::writeItems(CTimerControlItem** items, unsigned int count) +{ + wxMutexLocker locker(m_mutex); + + wxFFile file; + bool ret = file.Open(m_fileName, wxT("wb")); + if (!ret) { + wxLogError(wxT("Cannot open %s for writing"), m_fileName.c_str()); + return false; + } + + file.Write("TC1", 3U); + + for (unsigned int i = 0U; i < count; i++) { + unsigned char buffer[RECORD_LENGTH]; + ::memset(buffer, ' ', RECORD_LENGTH); + + wxString repeater = items[i]->m_repeater; + for (unsigned int j = 0U; j < repeater.Len(); j++) + buffer[j + 0U] = repeater.GetChar(j); + + wxUint32 day = wxUint32(items[i]->m_day); + ::memcpy(buffer + 8U, &day, sizeof(wxUint32)); + + wxUint32 hour = wxUint32(items[i]->m_hour); + ::memcpy(buffer + 12U, &hour, sizeof(wxUint32)); + + wxUint32 minute = wxUint32(items[i]->m_minute); + ::memcpy(buffer + 16U, &minute, sizeof(wxUint32)); + + wxString reflector = items[i]->m_reflector; + for (unsigned int j = 0U; j < reflector.Len(); j++) + buffer[j + 20U] = reflector.GetChar(j); + + wxUint32 reconnect = wxUint32(items[i]->m_reconnect); + ::memcpy(buffer + 28U, &reconnect, sizeof(wxUint32)); + + file.Write(buffer, RECORD_LENGTH); + } + + file.Close(); + + return true; +} + +CTimerControlItem** CTimerControlItemFile::readItems(unsigned int& count) +{ + wxMutexLocker locker(m_mutex); + + count = 0U; + + bool exists = wxFile::Exists(m_fileName); + if (!exists) + return NULL; + + wxFFile file; + bool ret = file.Open(m_fileName, wxT("rb")); + if (!ret) + return NULL; + + unsigned int length = file.Length(); + if (length < 3U) { + file.Close(); + return NULL; + } + + count = (length - 3U) / RECORD_LENGTH; + + unsigned char buffer[RECORD_LENGTH]; + file.Read(buffer, 3U); + + if (::memcmp(buffer, "TC1", 3U) != 0) { + file.Close(); + return NULL; + } + + CTimerControlItem** items = new CTimerControlItem*[count]; + + for (unsigned int i = 0U; i < count; i++) { + file.Read(buffer, RECORD_LENGTH); + + wxString repeater = wxString((char*)(buffer + 0U), wxConvLocal, 8U); + wxUint32* day = (wxUint32*)(buffer + 8U); + wxUint32* hour = (wxUint32*)(buffer + 12U); + wxUint32* minute = (wxUint32*)(buffer + 16U); + wxString reflector = wxString((char*)(buffer + 20U), wxConvLocal, 8U); + wxUint32* reconnect = (wxUint32*)(buffer + 28U); + + CTimerControlItem* item = new CTimerControlItem; + item->m_repeater = repeater; + item->m_day = *day; + item->m_hour = *hour; + item->m_minute = *minute; + item->m_reflector = reflector.Trim(); + item->m_reconnect = RECONNECT(*reconnect); + items[i] = item; + } + + file.Close(); + + return items; +} diff --git a/TimerControl/TimerControlItemFile.h b/TimerControl/TimerControlItemFile.h new file mode 100644 index 0000000..96fd02a --- /dev/null +++ b/TimerControl/TimerControlItemFile.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2011,2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef TimerControlItemFile_H +#define TimerControlItemFile_H + +#include "TimerControlItem.h" + +#include + +class CTimerControlItemFile { +public: + CTimerControlItemFile(const wxString& fileName); + ~CTimerControlItemFile(); + + bool writeItems(CTimerControlItem** items, unsigned int count); + + CTimerControlItem** readItems(unsigned int& count); + +private: + wxString m_fileName; + wxMutex m_mutex; +}; + +#endif diff --git a/TimerControl/TimerControlPreferences.cpp b/TimerControl/TimerControlPreferences.cpp new file mode 100644 index 0000000..9e82fad --- /dev/null +++ b/TimerControl/TimerControlPreferences.cpp @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2011,2012 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "TimerControlPreferences.h" +#include "TimerControlDefs.h" + +const unsigned int BORDER_SIZE = 5U; + +CTimerControlPreferences::CTimerControlPreferences(wxWindow* parent, int id, const wxString& address, unsigned int port, const wxString& password, bool delay) : +wxDialog(parent, id, wxString(_("Timer Control Preferences"))), +m_remote(NULL) +{ + wxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL); + + wxNotebook* noteBook = new wxNotebook(this, -1); + + m_remote = new CTimerControlRemoteSet(noteBook, -1, APPLICATION_NAME, address, port, password, delay); + noteBook->AddPage(m_remote, _("Gateway"), true); + + mainSizer->Add(noteBook, 1, wxALL | wxGROW, BORDER_SIZE); + + mainSizer->Add(CreateButtonSizer(wxOK | wxCANCEL), 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + SetAutoLayout(true); + Layout(); + + mainSizer->Fit(this); + mainSizer->SetSizeHints(this); + + SetSizer(mainSizer); +} + +CTimerControlPreferences::~CTimerControlPreferences() +{ +} + +bool CTimerControlPreferences::Validate() +{ + return m_remote->Validate(); +} + +wxString CTimerControlPreferences::getAddress() const +{ + return m_remote->getAddress(); +} + +unsigned int CTimerControlPreferences::getPort() const +{ + return m_remote->getPort(); +} + +wxString CTimerControlPreferences::getPassword() const +{ + return m_remote->getPassword(); +} + +bool CTimerControlPreferences::getDelay() const +{ + return m_remote->getDelay(); +} diff --git a/TimerControl/TimerControlPreferences.h b/TimerControl/TimerControlPreferences.h new file mode 100644 index 0000000..b3d4ab5 --- /dev/null +++ b/TimerControl/TimerControlPreferences.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2011,2012 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef TimerControlPreferences_H +#define TimerControlPreferences_H + +#include +#include + +#include "TimerControlRemoteSet.h" + +class CTimerControlPreferences : public wxDialog { +public: + CTimerControlPreferences(wxWindow* parent, int id, const wxString& address, unsigned int port, const wxString& password, bool delay); + virtual ~CTimerControlPreferences(); + + virtual bool Validate(); + + virtual wxString getAddress() const; + virtual unsigned int getPort() const; + virtual wxString getPassword() const; + virtual bool getDelay() const; + +private: + CTimerControlRemoteSet* m_remote; +}; + +#endif diff --git a/TimerControl/TimerControlRemoteControlHandler.cpp b/TimerControl/TimerControlRemoteControlHandler.cpp new file mode 100644 index 0000000..24ffd52 --- /dev/null +++ b/TimerControl/TimerControlRemoteControlHandler.cpp @@ -0,0 +1,295 @@ +/* + * Copyright (C) 2011,2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "TimerControlRemoteControlHandler.h" +#include "DStarDefines.h" + +const unsigned int BUFFER_LENGTH = 2000U; + +const unsigned int MAX_RETRIES = 3U; + +CTimerControlRemoteControlHandler::CTimerControlRemoteControlHandler(const wxString& address, unsigned int port) : +m_socket(wxEmptyString, 0U), +m_address(), +m_port(port), +m_loggedIn(false), +m_retryCount(0U), +m_type(TCT_NONE), +m_inBuffer(NULL), +m_inLength(0U), +m_outBuffer(NULL), +m_outLength(0U) +{ + wxASSERT(!address.IsEmpty()); + wxASSERT(port > 0U); + + m_address = CUDPReaderWriter::lookup(address); + + m_inBuffer = new unsigned char[BUFFER_LENGTH]; + m_outBuffer = new unsigned char[BUFFER_LENGTH]; +} + +CTimerControlRemoteControlHandler::~CTimerControlRemoteControlHandler() +{ + delete[] m_inBuffer; + delete[] m_outBuffer; +} + +bool CTimerControlRemoteControlHandler::open() +{ + return m_socket.open(); +} + +TC_TYPE CTimerControlRemoteControlHandler::readType() +{ + m_type = TCT_NONE; + + in_addr address; + unsigned int port; + + int length = m_socket.read(m_inBuffer, BUFFER_LENGTH, address, port); + if (length <= 0) + return m_type; + + m_inLength = length; + + if (::memcmp(m_inBuffer, "ACK", 3U) == 0) { + m_retryCount = 0U; + m_type = TCT_ACK; + return m_type; + } else if (::memcmp(m_inBuffer, "NAK", 3U) == 0) { + m_retryCount = 0U; + m_type = TCT_NAK; + return m_type; + } else if (::memcmp(m_inBuffer, "RND", 3U) == 0) { + m_retryCount = 0U; + m_type = TCT_RANDOM; + return m_type; + } else if (::memcmp(m_inBuffer, "CAL", 3U) == 0) { + m_retryCount = 0U; + m_type = TCT_CALLSIGNS; + return m_type; + } + + return m_type; +} + +wxString CTimerControlRemoteControlHandler::readNAK() +{ + if (m_type != TCT_NAK) + return wxEmptyString; + + wxString text((char*)(m_inBuffer + 3U), wxConvLocal); + + return text; +} + +unsigned int CTimerControlRemoteControlHandler::readRandom() +{ + if (m_type != TCT_RANDOM) + return 0U; + + wxUint32 random; + ::memcpy(&random, m_inBuffer + 3U, sizeof(wxUint32)); + + return wxUINT32_SWAP_ON_BE(random); +} + +wxArrayString CTimerControlRemoteControlHandler::readCallsigns() +{ + wxArrayString data; + + if (m_type != TCT_CALLSIGNS) + return data; + + unsigned char* p = m_inBuffer + 3U; + unsigned int pos = 3U; + + while (pos < m_inLength) { + unsigned char type = *p; + pos += 1U; + p += 1U; + + wxString callsign((char*)p, wxConvLocal, LONG_CALLSIGN_LENGTH); + pos += LONG_CALLSIGN_LENGTH; + p += LONG_CALLSIGN_LENGTH; + + if (type == 'R') + data.Add(callsign); + } + + return data; +} + +bool CTimerControlRemoteControlHandler::login() +{ + if (m_loggedIn) + return false; + + if (m_address.s_addr == INADDR_NONE) + return false; + + ::memcpy(m_outBuffer, "LIN", 3U); + m_outLength = 3U; + + bool ret = m_socket.write(m_outBuffer, m_outLength, m_address, m_port); + if (!ret) { + m_retryCount = 0U; + return false; + } else { + m_retryCount = 1U; + return true; + } +} + +void CTimerControlRemoteControlHandler::setLoggedIn(bool set) +{ + m_loggedIn = set; +} + +bool CTimerControlRemoteControlHandler::getCallsigns() +{ + if (!m_loggedIn || m_retryCount > 0U) + return false; + + ::memcpy(m_outBuffer, "GCS", 3U); + m_outLength = 3U; + + bool ret = m_socket.write(m_outBuffer, m_outLength, m_address, m_port); + if (!ret) { + m_retryCount = 0U; + return false; + } else { + m_retryCount = 1U; + return true; + } +} + +bool CTimerControlRemoteControlHandler::sendHash(const unsigned char* hash, unsigned int length) +{ + wxASSERT(hash != NULL); + wxASSERT(length > 0U); + + if (m_loggedIn || m_retryCount > 0U) + return false; + + unsigned char* p = m_outBuffer; + m_outLength = 0U; + + ::memcpy(p, "SHA", 3U); + m_outLength += 3U; + p += 3U; + + ::memcpy(p, hash, length); + m_outLength += length; + p += length; + + bool ret = m_socket.write(m_outBuffer, m_outLength, m_address, m_port); + if (!ret) { + m_retryCount = 0U; + return false; + } else { + m_retryCount = 1U; + return true; + } +} + +bool CTimerControlRemoteControlHandler::link(const wxString& callsign, RECONNECT reconnect, const wxString& reflector) +{ + wxASSERT(!callsign.IsEmpty()); + + if (!m_loggedIn || m_retryCount > 0U) + return false; + + unsigned char* p = m_outBuffer; + m_outLength = 0U; + + ::memcpy(p, "LNK", 3U); + m_outLength += 3U; + p += 3U; + + ::memset(p, ' ', LONG_CALLSIGN_LENGTH); + for (unsigned int i = 0U; i < callsign.Len(); i++) + p[i] = callsign.GetChar(i); + + m_outLength += LONG_CALLSIGN_LENGTH; + p += LONG_CALLSIGN_LENGTH; + + wxInt32 temp1 = wxInt32(reconnect); + wxInt32 temp2 = wxINT32_SWAP_ON_BE(temp1); + ::memcpy(p, &temp2, sizeof(wxInt32)); + m_outLength += sizeof(wxInt32); + p += sizeof(wxInt32); + + ::memset(p, ' ', LONG_CALLSIGN_LENGTH); + for (unsigned int i = 0U; i < reflector.Len(); i++) + p[i] = reflector.GetChar(i); + + m_outLength += LONG_CALLSIGN_LENGTH; + p += LONG_CALLSIGN_LENGTH; + + bool ret = m_socket.write(m_outBuffer, m_outLength, m_address, m_port); + if (!ret) { + m_retryCount = 0U; + return false; + } else { + m_retryCount = 1U; + return true; + } +} + +bool CTimerControlRemoteControlHandler::logout() +{ + if (!m_loggedIn || m_retryCount > 0U) + return false; + + ::memcpy(m_outBuffer, "LOG", 3U); + m_outLength = 3U; + + for (unsigned int i = 0U; i < 5U; i++) { + bool ret = m_socket.write(m_outBuffer, m_outLength, m_address, m_port); + if (!ret) { + m_retryCount = 0U; + return false; + } + } + + m_retryCount = 1U; + + return true; +} + +bool CTimerControlRemoteControlHandler::retry() +{ + if (m_retryCount > 0U) { + m_retryCount++; + if (m_retryCount >= MAX_RETRIES) { + m_retryCount = 0U; + return false; + } + + m_socket.write(m_outBuffer, m_outLength, m_address, m_port); + } + + return true; +} + +void CTimerControlRemoteControlHandler::close() +{ + m_socket.close(); +} diff --git a/TimerControl/TimerControlRemoteControlHandler.h b/TimerControl/TimerControlRemoteControlHandler.h new file mode 100644 index 0000000..18c576e --- /dev/null +++ b/TimerControl/TimerControlRemoteControlHandler.h @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2011 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef TimerControlRemoteControlHandler_H +#define TimerControlRemoteControlHandler_H + +#include "UDPReaderWriter.h" +#include "Defs.h" + +#include + +enum TC_TYPE { + TCT_NONE, + TCT_ACK, + TCT_NAK, + TCT_RANDOM, + TCT_CALLSIGNS +}; + +class CTimerControlRemoteControlHandler { +public: + CTimerControlRemoteControlHandler(const wxString& address, unsigned int port); + ~CTimerControlRemoteControlHandler(); + + bool open(); + + TC_TYPE readType(); + + wxString readNAK(); + unsigned int readRandom(); + wxArrayString readCallsigns(); + + bool login(); + bool sendHash(const unsigned char* hash, unsigned int length); + + void setLoggedIn(bool set); + + bool getCallsigns(); + + bool link(const wxString& callsign, RECONNECT reconnect, const wxString& reflector); + + bool logout(); + + bool retry(); + + void close(); + +private: + CUDPReaderWriter m_socket; + in_addr m_address; + unsigned int m_port; + bool m_loggedIn; + unsigned int m_retryCount; + TC_TYPE m_type; + unsigned char* m_inBuffer; + unsigned int m_inLength; + unsigned char* m_outBuffer; + unsigned int m_outLength; +}; + +#endif diff --git a/TimerControl/TimerControlRemoteSet.cpp b/TimerControl/TimerControlRemoteSet.cpp new file mode 100644 index 0000000..c04261e --- /dev/null +++ b/TimerControl/TimerControlRemoteSet.cpp @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2011,2012 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "TimerControlRemoteSet.h" +#include "DStarDefines.h" + +const unsigned int PASSWORD_WIDTH = 120U; +const unsigned int PORT_WIDTH = 80U; + +const unsigned int PORT_LENGTH = 5U; + +const unsigned int BORDER_SIZE = 5U; + +CTimerControlRemoteSet::CTimerControlRemoteSet(wxWindow* parent, int id, const wxString& title, const wxString& address, unsigned int port, const wxString& password, bool delay) : +wxPanel(parent, id), +m_title(title), +m_address(NULL), +m_port(NULL), +m_password(NULL), +m_delay(NULL) +{ + wxFlexGridSizer* sizer = new wxFlexGridSizer(2); + + wxStaticText* addressLabel = new wxStaticText(this, -1, _("Address")); + sizer->Add(addressLabel, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + m_address = new wxTextCtrl(this, -1, address, wxDefaultPosition, wxSize(PASSWORD_WIDTH, -1)); + sizer->Add(m_address, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + + wxStaticText* portLabel = new wxStaticText(this, -1, _("Port")); + sizer->Add(portLabel, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + wxString buffer; + buffer.Printf(wxT("%u"), port); + + m_port = new CPortTextCtrl(this, -1, buffer, wxDefaultPosition, wxSize(PORT_WIDTH, -1)); + m_port->SetMaxLength(PORT_LENGTH); + sizer->Add(m_port, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + + wxStaticText* passwordLabel = new wxStaticText(this, -1, _("Password")); + sizer->Add(passwordLabel, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + m_password = new wxTextCtrl(this, -1, password, wxDefaultPosition, wxSize(PASSWORD_WIDTH, -1), wxTE_PASSWORD); + sizer->Add(m_password, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + + wxStaticText* delayLabel = new wxStaticText(this, -1, _("Delay")); + sizer->Add(delayLabel, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + m_delay = new wxChoice(this, -1, wxDefaultPosition, wxSize(PASSWORD_WIDTH, -1)); + m_delay->Append(_("Disabled")); + m_delay->Append(_("Enabled")); + sizer->Add(m_delay, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + m_delay->SetSelection(delay ? 1 : 0); + + SetAutoLayout(true); + + SetSizer(sizer); +} + + +CTimerControlRemoteSet::~CTimerControlRemoteSet() +{ +} + +bool CTimerControlRemoteSet::Validate() +{ + wxString address = getAddress(); + if (address.IsEmpty()) { + wxMessageDialog dialog(this, _("The Address is empty"), m_title + _(" Error"), wxICON_ERROR); + dialog.ShowModal(); + return false; + } + + unsigned int port = getPort(); + if (port == 0U || port > 65535U) { + wxMessageDialog dialog(this, _("The Port is not valid"), m_title + _(" Error"), wxICON_ERROR); + dialog.ShowModal(); + return false; + } + + wxString password = getPassword(); + if (password.IsEmpty()) { + wxMessageDialog dialog(this, _("The Password is empty"), m_title + _(" Error"), wxICON_ERROR); + dialog.ShowModal(); + return false; + } + + int n = m_delay->GetCurrentSelection(); + if (n == wxNOT_FOUND) + return false; + + return true; +} + +wxString CTimerControlRemoteSet::getAddress() const +{ + return m_address->GetValue(); +} + +unsigned int CTimerControlRemoteSet::getPort() const +{ + unsigned long n; + m_port->GetValue().ToULong(&n); + + return n; +} + +wxString CTimerControlRemoteSet::getPassword() const +{ + return m_password->GetValue(); +} + +bool CTimerControlRemoteSet::getDelay() const +{ + int n = m_delay->GetCurrentSelection(); + + if (n == wxNOT_FOUND) + return false; + + return n == 1; +} diff --git a/TimerControl/TimerControlRemoteSet.h b/TimerControl/TimerControlRemoteSet.h new file mode 100644 index 0000000..3315cc9 --- /dev/null +++ b/TimerControl/TimerControlRemoteSet.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2011,2012 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef TimerControlRemoteSet_H +#define TimerControlRemoteSet_H + +#include "PortTextCtrl.h" + +#include + +class CTimerControlRemoteSet : public wxPanel { +public: + CTimerControlRemoteSet(wxWindow* parent, int id, const wxString& title, const wxString& address, unsigned int port, const wxString& password, bool delay); + virtual ~CTimerControlRemoteSet(); + + virtual bool Validate(); + + virtual wxString getAddress() const; + virtual unsigned int getPort() const; + virtual wxString getPassword() const; + virtual bool getDelay() const; + +private: + wxString m_title; + wxTextCtrl* m_address; + CPortTextCtrl* m_port; + wxTextCtrl* m_password; + wxChoice* m_delay; +}; + +#endif diff --git a/TimerControl/TimerControlRepeaterPanel.cpp b/TimerControl/TimerControlRepeaterPanel.cpp new file mode 100644 index 0000000..9f5fa08 --- /dev/null +++ b/TimerControl/TimerControlRepeaterPanel.cpp @@ -0,0 +1,592 @@ +/* + * Copyright (C) 2011,2012,2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "TimerControlRepeaterPanel.h" +#include "TimerControlApp.h" +#include "DStarDefines.h" +#include "HostFile.h" + +#include + +#include + +enum { + List_Select = 7100, + Button_Add, + Button_Modify, + Button_Delete +}; + +BEGIN_EVENT_TABLE(CTimerControlRepeaterPanel, wxPanel) + EVT_LIST_ITEM_SELECTED(List_Select, CTimerControlRepeaterPanel::onSelect) + + EVT_BUTTON(Button_Add, CTimerControlRepeaterPanel::onAdd) + EVT_BUTTON(Button_Modify, CTimerControlRepeaterPanel::onModify) + EVT_BUTTON(Button_Delete, CTimerControlRepeaterPanel::onDelete) +END_EVENT_TABLE() + +#if defined(__WINDOWS__) +const unsigned int LIST_HEIGHT = 350U; +const unsigned int LIST_WIDTH = 350U; +const unsigned int DAY_WIDTH = 75U; +const unsigned int TIME_WIDTH = 60U; +const unsigned int CALLSIGN_WIDTH = 100U; +const unsigned int TYPE_WIDTH = 85U; +const unsigned int BUTTON_WIDTH = 75U; +const unsigned int HOUR_WIDTH = 40U; +const unsigned int MINUTE_WIDTH = 40U; +const unsigned int REFLECTOR_WIDTH = 80U; +const unsigned int CHANNEL_WIDTH = 40U; +const unsigned int RECONNECT_WIDTH = 75U; +#else +const unsigned int LIST_HEIGHT = 350U; +const unsigned int LIST_WIDTH = 350U; +const unsigned int DAY_WIDTH = 100U; +const unsigned int TIME_WIDTH = 100U; +const unsigned int CALLSIGN_WIDTH = 100U; +const unsigned int TYPE_WIDTH = 65U; +const unsigned int BUTTON_WIDTH = 75U; +const unsigned int HOUR_WIDTH = 50U; +const unsigned int MINUTE_WIDTH = 50U; +const unsigned int REFLECTOR_WIDTH = 90U; +const unsigned int CHANNEL_WIDTH = 50U; +const unsigned int RECONNECT_WIDTH = 100U; +#endif + +const unsigned int BORDER_SIZE = 5U; + +int itemCompare(const void* a, const void* b) +{ + const CTimerControlItem** first = (const CTimerControlItem**)a; + const CTimerControlItem** second = (const CTimerControlItem**)b; + + if ((*first)->m_day != (*second)->m_day) + return int((*second)->m_day) - int((*first)->m_day); + + if ((*first)->m_hour != (*second)->m_hour) + return int((*second)->m_hour) - int((*first)->m_hour); + + return int((*second)->m_minute) - int((*first)->m_minute); +} + +CTimerControlRepeaterPanel::CTimerControlRepeaterPanel(wxWindow* parent, int id, const wxString& callsign) : +wxPanel(parent, id), +m_callsign(callsign), +m_list(NULL), +m_day(NULL), +m_hour(NULL), +m_minute(NULL), +m_reflector(NULL), +m_channel(NULL), +m_reconnect(NULL), +m_item(NULL), +m_n(0) +{ + wxBoxSizer* sizer1 = new wxBoxSizer(wxHORIZONTAL); + + m_list = new wxListCtrl(this, List_Select, wxDefaultPosition, wxSize(LIST_WIDTH, LIST_HEIGHT), wxLC_REPORT | wxLC_SINGLE_SEL); + m_list->InsertColumn(0L, _("Day")); + m_list->SetColumnWidth(0L, DAY_WIDTH); + m_list->InsertColumn(1L, _("Time")); + m_list->SetColumnWidth(1L, TIME_WIDTH); + m_list->InsertColumn(2L, _("Type")); + m_list->SetColumnWidth(2L, TYPE_WIDTH); + m_list->InsertColumn(3L, _("Reflector")); + m_list->SetColumnWidth(3L, REFLECTOR_WIDTH); + sizer1->Add(m_list, 0, wxTOP | wxBOTTOM | wxLEFT | wxEXPAND, BORDER_SIZE); + + wxBoxSizer* sizer2 = new wxBoxSizer(wxVERTICAL); + + m_day = new wxChoice(this, -1, wxDefaultPosition, wxSize(DAY_WIDTH, -1)); + m_day->Append(_("Sunday")); + m_day->Append(_("Monday")); + m_day->Append(_("Tuesday")); + m_day->Append(_("Wednesday")); + m_day->Append(_("Thursday")); + m_day->Append(_("Friday")); + m_day->Append(_("Saturday")); + m_day->Append(_("Every day")); + m_day->Append(_("Mon-Fri")); + m_day->Append(_("Sat-Sun")); + sizer2->Add(m_day, 0, wxALL, BORDER_SIZE); + m_day->SetSelection(0); + + wxBoxSizer* sizer2a = new wxBoxSizer(wxHORIZONTAL); + + m_hour = new wxChoice(this, -1, wxDefaultPosition, wxSize(HOUR_WIDTH, -1)); + m_hour->Append(wxT("00")); + m_hour->Append(wxT("01")); + m_hour->Append(wxT("02")); + m_hour->Append(wxT("03")); + m_hour->Append(wxT("04")); + m_hour->Append(wxT("05")); + m_hour->Append(wxT("06")); + m_hour->Append(wxT("07")); + m_hour->Append(wxT("08")); + m_hour->Append(wxT("09")); + m_hour->Append(wxT("10")); + m_hour->Append(wxT("11")); + m_hour->Append(wxT("12")); + m_hour->Append(wxT("13")); + m_hour->Append(wxT("14")); + m_hour->Append(wxT("15")); + m_hour->Append(wxT("16")); + m_hour->Append(wxT("17")); + m_hour->Append(wxT("18")); + m_hour->Append(wxT("19")); + m_hour->Append(wxT("20")); + m_hour->Append(wxT("21")); + m_hour->Append(wxT("22")); + m_hour->Append(wxT("23")); + sizer2a->Add(m_hour, 0, wxALL, BORDER_SIZE); + m_hour->SetSelection(0); + + wxStaticText* dummy1Label = new wxStaticText(this, -1, wxT(":")); + sizer2a->Add(dummy1Label, 0, wxALL, BORDER_SIZE); + + m_minute = new wxChoice(this, -1, wxDefaultPosition, wxSize(MINUTE_WIDTH, -1)); + m_minute->Append(wxT("00")); + m_minute->Append(wxT("05")); + m_minute->Append(wxT("10")); + m_minute->Append(wxT("15")); + m_minute->Append(wxT("20")); + m_minute->Append(wxT("25")); + m_minute->Append(wxT("30")); + m_minute->Append(wxT("35")); + m_minute->Append(wxT("40")); + m_minute->Append(wxT("45")); + m_minute->Append(wxT("50")); + m_minute->Append(wxT("55")); + sizer2a->Add(m_minute, 0, wxALL, BORDER_SIZE); + m_minute->SetSelection(0); + + sizer2->Add(sizer2a); + + wxStaticText* dummy2Label = new wxStaticText(this, -1, wxEmptyString); + sizer2->Add(dummy2Label, 0, wxALL, BORDER_SIZE); + + wxBoxSizer* sizer3 = new wxBoxSizer(wxHORIZONTAL); + + m_reflector = new wxChoice(this, -1, wxDefaultPosition, wxSize(REFLECTOR_WIDTH, -1)); + m_reflector->Append(_("None")); + + wxFileName fileName1(wxFileName::GetHomeDir(), DPLUS_HOSTS_FILE_NAME); + if (fileName1.IsFileReadable()) { + CHostFile file(fileName1.GetFullPath(), false); + + for (unsigned int i = 0U; i < file.getCount(); i++) + m_reflector->Append(file.getName(i).Trim()); + } + +#if defined(__WINDOWS__) + wxFileName fileName4(::wxGetCwd(), DPLUS_HOSTS_FILE_NAME); +#else + wxFileName fileName4(wxT(DATA_DIR), DPLUS_HOSTS_FILE_NAME); +#endif + if (fileName4.IsFileReadable()) { + CHostFile file(fileName4.GetFullPath(), false); + + for (unsigned int i = 0U; i < file.getCount(); i++) { + wxString name = file.getName(i).Trim(); + if (m_reflector->FindString(name) == wxNOT_FOUND) + m_reflector->Append(name); + } + } + + wxFileName fileName2(wxFileName::GetHomeDir(), DEXTRA_HOSTS_FILE_NAME); + if (fileName2.IsFileReadable()) { + CHostFile file(fileName2.GetFullPath(), false); + + for (unsigned int i = 0U; i < file.getCount(); i++) + m_reflector->Append(file.getName(i).Trim()); + } + +#if defined(__WINDOWS__) + wxFileName fileName5(::wxGetCwd(), DEXTRA_HOSTS_FILE_NAME); +#else + wxFileName fileName5(wxT(DATA_DIR), DEXTRA_HOSTS_FILE_NAME); +#endif + if (fileName5.IsFileReadable()) { + CHostFile file(fileName5.GetFullPath(), false); + + for (unsigned int i = 0U; i < file.getCount(); i++) { + wxString name = file.getName(i).Trim(); + if (m_reflector->FindString(name) == wxNOT_FOUND) + m_reflector->Append(name); + } + } + + wxFileName fileName3(wxFileName::GetHomeDir(), DCS_HOSTS_FILE_NAME); + if (fileName3.IsFileReadable()) { + CHostFile file(fileName3.GetFullPath(), false); + + for (unsigned int i = 0U; i < file.getCount(); i++) + m_reflector->Append(file.getName(i).Trim()); + } + +#if defined(__WINDOWS__) + wxFileName fileName6(::wxGetCwd(), DCS_HOSTS_FILE_NAME); +#else + wxFileName fileName6(wxT(DATA_DIR), DCS_HOSTS_FILE_NAME); +#endif + if (fileName6.IsFileReadable()) { + CHostFile file(fileName6.GetFullPath(), false); + + for (unsigned int i = 0U; i < file.getCount(); i++) { + wxString name = file.getName(i).Trim(); + if (m_reflector->FindString(name) == wxNOT_FOUND) + m_reflector->Append(name); + } + } + + sizer3->Add(m_reflector, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + m_reflector->SetSelection(0); + + m_channel = new wxChoice(this, -1, wxDefaultPosition, wxSize(CHANNEL_WIDTH, -1)); + m_channel->Append(wxT("A")); + m_channel->Append(wxT("B")); + m_channel->Append(wxT("C")); + m_channel->Append(wxT("D")); + m_channel->Append(wxT("E")); + m_channel->Append(wxT("F")); + m_channel->Append(wxT("G")); + m_channel->Append(wxT("H")); + m_channel->Append(wxT("I")); + m_channel->Append(wxT("J")); + m_channel->Append(wxT("K")); + m_channel->Append(wxT("L")); + m_channel->Append(wxT("M")); + m_channel->Append(wxT("N")); + m_channel->Append(wxT("O")); + m_channel->Append(wxT("P")); + m_channel->Append(wxT("Q")); + m_channel->Append(wxT("R")); + m_channel->Append(wxT("S")); + m_channel->Append(wxT("T")); + m_channel->Append(wxT("U")); + m_channel->Append(wxT("V")); + m_channel->Append(wxT("W")); + m_channel->Append(wxT("X")); + m_channel->Append(wxT("Y")); + m_channel->Append(wxT("Z")); + sizer3->Add(m_channel, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + m_channel->SetSelection(0); + + sizer2->Add(sizer3); + + m_reconnect = new wxChoice(this, -1, wxDefaultPosition, wxSize(RECONNECT_WIDTH, -1)); + m_reconnect->Append(_("Never")); + m_reconnect->Append(_("Fixed")); + m_reconnect->Append(_("5 minutes")); + m_reconnect->Append(_("10 minutes")); + m_reconnect->Append(_("15 minutes")); + m_reconnect->Append(_("20 minutes")); + m_reconnect->Append(_("25 minutes")); + m_reconnect->Append(_("30 minutes")); + m_reconnect->Append(_("60 minutes")); + m_reconnect->Append(_("90 minutes")); + m_reconnect->Append(_("120 minutes")); + m_reconnect->Append(_("180 minutes")); + sizer2->Add(m_reconnect, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + m_reconnect->SetSelection(0); + + wxStaticText* dummy3Label = new wxStaticText(this, -1, wxEmptyString); + sizer2->Add(dummy3Label, 0, wxALL, BORDER_SIZE); + + wxButton* addButton = new wxButton(this, Button_Add, _("Add"), wxDefaultPosition, wxSize(BUTTON_WIDTH, -1)); + sizer2->Add(addButton, 0, wxALL, BORDER_SIZE); + + wxButton* modButton = new wxButton(this, Button_Modify, _("Modify"), wxDefaultPosition, wxSize(BUTTON_WIDTH, -1)); + sizer2->Add(modButton, 0, wxALL, BORDER_SIZE); + + wxButton* delButton = new wxButton(this, Button_Delete, _("Delete"), wxDefaultPosition, wxSize(BUTTON_WIDTH, -1)); + sizer2->Add(delButton, 0, wxALL, BORDER_SIZE); + + sizer1->Add(sizer2); + + SetAutoLayout(true); + + SetSizer(sizer1); +} + + +CTimerControlRepeaterPanel::~CTimerControlRepeaterPanel() +{ +} + +void CTimerControlRepeaterPanel::load(CTimerControlItem** items, unsigned int count) +{ + for (unsigned int i = 0U; i < count; i++) { + if (items[i]->m_repeater.IsSameAs(m_callsign)) + insertItem(items[i]); + } + + reload(); +} + +unsigned int CTimerControlRepeaterPanel::getCount() const +{ + return (unsigned int)m_list->GetItemCount(); +} + +CTimerControlItem** CTimerControlRepeaterPanel::getItems() const +{ + unsigned int count = getCount(); + + CTimerControlItem** items = new CTimerControlItem*[count]; + + for (unsigned int i = 0U; i < count; i++) + items[i] = (CTimerControlItem*)m_list->GetItemData(i); + + return items; +} + +void CTimerControlRepeaterPanel::insertItem(CTimerControlItem* item) +{ + switch (item->m_day) { + case 0U: m_list->InsertItem(0L, _("Sunday")); break; + case 1U: m_list->InsertItem(0L, _("Monday")); break; + case 2U: m_list->InsertItem(0L, _("Tuesday")); break; + case 3U: m_list->InsertItem(0L, _("Wednesday")); break; + case 4U: m_list->InsertItem(0L, _("Thursday")); break; + case 5U: m_list->InsertItem(0L, _("Friday")); break; + case 6U: m_list->InsertItem(0L, _("Saturday")); break; + case 7U: m_list->InsertItem(0L, _("Every day")); break; + case 8U: m_list->InsertItem(0L, _("Mon-Fri")); break; + case 9U: m_list->InsertItem(0L, _("Sat-Sun")); break; + default: m_list->InsertItem(0L, wxT("??????")); break; + } + + wxString text; + text.Printf(wxT("%02u:%02u"), item->m_hour, item->m_minute); + m_list->SetItem(0L, 1, text); + + switch (item->m_reconnect) { + case RECONNECT_NEVER: m_list->SetItem(0L, 2, _("Never")); break; + case RECONNECT_FIXED: m_list->SetItem(0L, 2, _("Fixed")); break; + case RECONNECT_5MINS: m_list->SetItem(0L, 2, _("5 minutes")); break; + case RECONNECT_10MINS: m_list->SetItem(0L, 2, _("10 minutes")); break; + case RECONNECT_15MINS: m_list->SetItem(0L, 2, _("15 minutes")); break; + case RECONNECT_20MINS: m_list->SetItem(0L, 2, _("20 minutes")); break; + case RECONNECT_25MINS: m_list->SetItem(0L, 2, _("25 minutes")); break; + case RECONNECT_30MINS: m_list->SetItem(0L, 2, _("30 minutes")); break; + case RECONNECT_60MINS: m_list->SetItem(0L, 2, _("60 minutes")); break; + case RECONNECT_90MINS: m_list->SetItem(0L, 2, _("90 minutes")); break; + case RECONNECT_120MINS: m_list->SetItem(0L, 2, _("120 minutes")); break; + case RECONNECT_180MINS: m_list->SetItem(0L, 2, _("180 minutes")); break; + default: m_list->SetItem(0L, 2, wxT("????????")); break; + } + + if (item->m_reflector.IsEmpty()) + m_list->SetItem(0L, 3, _("None")); + else + m_list->SetItem(0L, 3, item->m_reflector); + + m_list->SetItemPtrData(0L, wxUIntPtr(item)); +} + +void CTimerControlRepeaterPanel::onSelect(wxListEvent& event) +{ + m_n = event.GetIndex(); + m_item = (CTimerControlItem*)m_list->GetItemData(m_n); + if (m_item == NULL) + return; + + m_day->SetSelection(int(m_item->m_day)); + m_hour->SetSelection(int(m_item->m_hour)); + m_minute->SetSelection(int(m_item->m_minute / 5U)); + + if (m_item->m_reflector.IsEmpty()) { + m_reflector->SetSelection(0); + m_channel->SetSelection(0); + } else { + m_reflector->SetStringSelection(m_item->m_reflector.Left(7U).Trim()); + m_channel->SetStringSelection(m_item->m_reflector.Mid(7U).Trim()); + } + + m_reconnect->SetSelection(int(m_item->m_reconnect)); +} + +void CTimerControlRepeaterPanel::onAdd(wxCommandEvent&) +{ + int day = m_day->GetSelection(); + int hour = m_hour->GetSelection(); + int minute = m_minute->GetSelection(); + int reflector = m_reflector->GetSelection(); + int channel = m_channel->GetSelection(); + int reconnect = m_reconnect->GetSelection(); + + if (day == wxNOT_FOUND || hour == wxNOT_FOUND || minute == wxNOT_FOUND || reflector == wxNOT_FOUND || channel == wxNOT_FOUND || reconnect == wxNOT_FOUND) + return; + + CTimerControlItem* item = new CTimerControlItem; + + item->m_repeater = m_callsign; + item->m_day = (unsigned int)day; + item->m_hour = (unsigned int)hour; + item->m_minute = (unsigned int)minute * 5U; + + if (reflector != 0) { + wxString callsign = m_reflector->GetStringSelection(); + callsign.Append(wxT(" ")); + callsign.Truncate(7U); + callsign.Append(m_channel->GetStringSelection()); + item->m_reflector = callsign; + } + + item->m_reconnect = RECONNECT(reconnect); + + m_day->SetSelection(0); + m_hour->SetSelection(0); + m_minute->SetSelection(0); + m_reflector->SetSelection(0); + m_channel->SetSelection(0); + m_reconnect->SetSelection(0); + + reload(item); + + ::wxGetApp().writeItems(); +} + +void CTimerControlRepeaterPanel::onModify(wxCommandEvent&) +{ + if (m_item == NULL) + return; + + int day = m_day->GetSelection(); + int hour = m_hour->GetSelection(); + int minute = m_minute->GetSelection(); + int reflector = m_reflector->GetSelection(); + int channel = m_channel->GetSelection(); + int reconnect = m_reconnect->GetSelection(); + + if (day == wxNOT_FOUND || hour == wxNOT_FOUND || minute == wxNOT_FOUND || reflector == wxNOT_FOUND || channel == wxNOT_FOUND || reconnect == wxNOT_FOUND) + return; + + CTimerControlItem* item = new CTimerControlItem; + + item->m_repeater = m_callsign; + item->m_day = (unsigned int)day; + item->m_hour = (unsigned int)hour; + item->m_minute = (unsigned int)minute * 5U; + + if (reflector != 0) { + wxString callsign = m_reflector->GetStringSelection(); + callsign.Append(wxT(" ")); + callsign.Truncate(7U); + callsign.Append(m_channel->GetStringSelection()); + item->m_reflector = callsign; + } + + item->m_reconnect = RECONNECT(reconnect); + + m_list->DeleteItem(m_n); + + delete m_item; + m_item = NULL; + + m_day->SetSelection(0); + m_hour->SetSelection(0); + m_minute->SetSelection(0); + m_reflector->SetSelection(0); + m_channel->SetSelection(0); + m_reconnect->SetSelection(0); + + reload(item); + + ::wxGetApp().writeItems(); +} + +void CTimerControlRepeaterPanel::onDelete(wxCommandEvent&) +{ + if (m_item == NULL) + return; + + m_list->DeleteItem(m_n); + + delete m_item; + m_item = NULL; + + m_day->SetSelection(0); + m_hour->SetSelection(0); + m_minute->SetSelection(0); + m_reflector->SetSelection(0); + m_channel->SetSelection(0); + m_reconnect->SetSelection(0); + + ::wxGetApp().writeItems(); +} + +void CTimerControlRepeaterPanel::reload(CTimerControlItem* item) +{ + int n = m_list->GetItemCount(); + + CTimerControlItem** items = new CTimerControlItem*[n + 1]; + + unsigned int count = 0U; + for (int i = 0; i < n; i++) { + CTimerControlItem* listItem = (CTimerControlItem*)m_list->GetItemData(i); + + // Reject any that have the same day, hour and minute settings + if (item != NULL) { + // Match the exact day, hour, and minute + if (listItem->m_day == item->m_day && listItem->m_hour == item->m_hour && listItem->m_minute == item->m_minute) { + delete listItem; + // Match every day, hour, and minute + } else if (7U == item->m_day && listItem->m_hour == item->m_hour && listItem->m_minute == item->m_minute) { + delete listItem; + // Match every day, hour, and minute + } else if (listItem->m_day == 7U && listItem->m_hour == item->m_hour && listItem->m_minute == item->m_minute) { + delete listItem; + // Match week day, hour, and minute + } else if (8U == item->m_day && ((listItem->m_day >= 1U && listItem->m_day <= 5U) || listItem->m_day == 7U) && listItem->m_hour == item->m_hour && listItem->m_minute == item->m_minute) { + delete listItem; + // Match week day, hour, and minute + } else if (listItem->m_day == 8U && ((item->m_day >= 1U && item->m_day <= 5U) || item->m_day == 7U) && listItem->m_hour == item->m_hour && listItem->m_minute == item->m_minute) { + delete listItem; + // Match weekend, hour, and minute + } else if (9U == item->m_day && (listItem->m_day == 0U || listItem->m_day == 6U || listItem->m_day == 7U) && listItem->m_hour == item->m_hour && listItem->m_minute == item->m_minute) { + delete listItem; + // Match weekend, hour, and minute + } else if (listItem->m_day == 9U && (item->m_day == 0U || item->m_day == 6U || item->m_day == 7U) && listItem->m_hour == item->m_hour && listItem->m_minute == item->m_minute) { + delete listItem; + } else { + items[count] = listItem; + count++; + } + } else { + items[count] = listItem; + count++; + } + } + + // Put the new one at the end of the list + if (item != NULL) { + items[count] = item; + count++; + } + + m_list->DeleteAllItems(); + + ::qsort(items, count, sizeof(CTimerControlItem*), itemCompare); + + for (unsigned int i = 0U; i < count; i++) + insertItem(items[i]); + + delete[] items; +} diff --git a/TimerControl/TimerControlRepeaterPanel.h b/TimerControl/TimerControlRepeaterPanel.h new file mode 100644 index 0000000..9e5ac27 --- /dev/null +++ b/TimerControl/TimerControlRepeaterPanel.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2011 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef TimerControlRepeaterPanel_H +#define TimerControlRepeaterPanel_H + +#include "TimerControlItem.h" + +#include +#include + +class CTimerControlRepeaterPanel : public wxPanel { +public: + CTimerControlRepeaterPanel(wxWindow* parent, int id, const wxString& callsign); + virtual ~CTimerControlRepeaterPanel(); + + virtual void onSelect(wxListEvent& event); + + virtual void onAdd(wxCommandEvent& event); + virtual void onModify(wxCommandEvent& event); + virtual void onDelete(wxCommandEvent& event); + + virtual void load(CTimerControlItem** items, unsigned int count); + + virtual unsigned int getCount() const; + virtual CTimerControlItem** getItems() const; + +private: + wxString m_callsign; + wxListCtrl* m_list; + wxChoice* m_day; + wxChoice* m_hour; + wxChoice* m_minute; + wxChoice* m_reflector; + wxChoice* m_channel; + wxChoice* m_reconnect; + CTimerControlItem* m_item; + int m_n; + + DECLARE_EVENT_TABLE() + + void insertItem(CTimerControlItem* item); + void reload(CTimerControlItem* item = NULL); +}; + +#endif diff --git a/TimerControl/TimerControlThread.cpp b/TimerControl/TimerControlThread.cpp new file mode 100644 index 0000000..d5182fd --- /dev/null +++ b/TimerControl/TimerControlThread.cpp @@ -0,0 +1,291 @@ +/* + * Copyright (C) 2011,2012 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "TimerControlItemFile.h" +#include "TimerControlThread.h" +#include "SHA256.h" + + +CTimerControlThread::CTimerControlThread() : +m_password(), +m_fileName(), +m_delay(false), +m_count(0U), +m_items(NULL), +m_mutex(), +m_handler(NULL), +m_killed(false) +{ +} + +CTimerControlThread::~CTimerControlThread() +{ + if (m_items != NULL) { + for (unsigned int i = 0U; i < m_count; i++) + delete m_items[i]; + + delete[] m_items; + } + + delete m_handler; +} + +void CTimerControlThread::run() +{ + if (m_delay) { + for (unsigned int i = 0U; i < 20U; i++) { + if (m_killed) + return; + + ::wxMilliSleep(1000UL); + } + } else { + ::wxMilliSleep(100UL); + } + + int lastDay = 0; + int lastHour = 0; + int lastMin = 0; + + while (!m_killed) { + time_t t; + ::time(&t); + + struct tm* tm = ::localtime(&t); + int day = tm->tm_wday; + int hour = tm->tm_hour; + int min = tm->tm_min; + + if (day != lastDay || hour != lastHour || min != lastMin) { + m_mutex.Lock(); + + bool open = false; + for (unsigned int i = 0U; i < m_count; i++) { + // Check the day matching + if (int(m_items[i]->m_day) == day || // Exact day match + m_items[i]->m_day == 7U || // Every day match + (m_items[i]->m_day == 8U && day >= 1 && day <= 5) || // Weekday match + (m_items[i]->m_day == 9U && (day == 0 || day == 6))) { // Weekend match + + // Check the time matching + if (int(m_items[i]->m_hour) == hour && int(m_items[i]->m_minute) == min) { + if (m_items[i]->m_reflector.IsEmpty()) + wxLogMessage(wxT("Linking \"%s\" to \"None\" with reconnect %d"), m_items[i]->m_repeater.c_str(), m_items[i]->m_reconnect); + else + wxLogMessage(wxT("Linking \"%s\" to \"%s\" with reconnect %d"), m_items[i]->m_repeater.c_str(), m_items[i]->m_reflector.c_str(), m_items[i]->m_reconnect); + + if (!open) + open = login(); + + if (open) + link(m_items[i]->m_repeater, m_items[i]->m_reconnect, m_items[i]->m_reflector); + } + } + } + + m_mutex.Unlock(); + + if (open) + logoff(); + + lastDay = day; + lastHour = hour; + lastMin = min; + } + + ::wxMilliSleep(5000UL); + } +} + +void CTimerControlThread::setGateway(const wxString& address, unsigned int port, const wxString& password) +{ + m_password = password; + + delete m_handler; + + m_handler = new CTimerControlRemoteControlHandler(address, port); +} + +void CTimerControlThread::setDelay(bool enabled) +{ + m_delay = enabled; +} + +void CTimerControlThread::setFileName(const wxString& fileName) +{ + m_fileName = fileName; +} + +void CTimerControlThread::reload() +{ + wxMutexLocker lock(m_mutex); + + wxLogMessage(wxT("Reloading the schedule file")); + + // Remove the old schedule + if (m_items != NULL) { + for (unsigned int i = 0U; i < m_count; i++) + delete m_items[i]; + + delete[] m_items; + m_items = NULL; + } + + CTimerControlItemFile file(m_fileName); + m_items = file.readItems(m_count); +} + +void CTimerControlThread::kill() +{ + m_killed = true; +} + +bool CTimerControlThread::login() +{ + wxASSERT(m_handler != NULL); + + wxLogMessage(wxT("Logging into the gateway")); + + bool ret = m_handler->open(); + if (!ret) { + wxLogError(wxT("Error opening the port")); + return false; + } + + TC_TYPE type; + + do { + ret = m_handler->login(); + if (!ret) { + wxLogError(wxT("Error when sending the login command")); + m_handler->close(); + return false; + } + + ::wxMilliSleep(100UL); + + type = m_handler->readType(); + switch (type) { + case TCT_RANDOM: + wxLogMessage(wxT("Read the random number")); + break; + case TCT_NAK: + wxLogError(wxT("Received a NAK when asking for the random number")); + m_handler->setLoggedIn(false); + m_handler->readNAK(); + m_handler->close(); + return false; + default: + ::wxMilliSleep(100UL); + break; + } + } while (type != TCT_RANDOM); + + unsigned int rnd = m_handler->readRandom(); + + do { + ret = sendHash(rnd); + if (!ret) { + wxLogError(wxT("Error when sending the hash")); + m_handler->close(); + return false; + } + + ::wxMilliSleep(100UL); + + type = m_handler->readType(); + switch (type) { + case TCT_ACK: + wxLogMessage(wxT("Logged in to the gateway")); + m_handler->setLoggedIn(true); + break; + case TCT_NAK: + wxLogError(wxT("Received a NAK after sending the hash")); + m_handler->setLoggedIn(false); + m_handler->readNAK(); + m_handler->close(); + return false; + default: + ::wxMilliSleep(100UL); + break; + } + } while (type != TCT_ACK); + + return true; +} + +bool CTimerControlThread::link(const wxString& repeater, RECONNECT reconnect, const wxString& reflector) +{ + wxASSERT(m_handler != NULL); + + for (;;) { + bool ret = m_handler->link(repeater, reconnect, reflector); + if (!ret) { + wxLogError(wxT("Error when sending the link command")); + return false; + } + + ::wxMilliSleep(100UL); + + TC_TYPE type = m_handler->readType(); + switch (type) { + case TCT_ACK: + wxLogMessage(wxT("Sent the link command OK")); + return true; + case TCT_NAK: + wxLogError(wxT("Received a NAK after sending the link command")); + m_handler->readNAK(); + return false; + default: + ::wxMilliSleep(100UL); + break; + } + } +} + +void CTimerControlThread::logoff() +{ + wxASSERT(m_handler != NULL); + + wxLogMessage(wxT("Logging out of the gateway")); + + m_handler->logout(); + m_handler->setLoggedIn(false); + m_handler->close(); +} + +bool CTimerControlThread::sendHash(unsigned int rnd) +{ + unsigned int len = m_password.Len() + sizeof(unsigned int); + unsigned char* in = new unsigned char[len]; + unsigned char* out = new unsigned char[32U]; + + ::memcpy(in, &rnd, sizeof(unsigned int)); + for (unsigned int i = 0U; i < m_password.Len(); i++) + in[i + sizeof(unsigned int)] = m_password.GetChar(i); + + CSHA256 sha256; + sha256.buffer(in, len, out); + + bool ret = m_handler->sendHash(out, 32U); + + delete[] in; + delete[] out; + + return ret; +} diff --git a/TimerControl/TimerControlThread.h b/TimerControl/TimerControlThread.h new file mode 100644 index 0000000..e090cd7 --- /dev/null +++ b/TimerControl/TimerControlThread.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2011,2012 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef TimerControlThread_H +#define TimerControlThread_H + +#include "TimerControlRemoteControlHandler.h" +#include "TimerControlItem.h" +#include "Defs.h" + +#include + +class CTimerControlThread { +public: + CTimerControlThread(); + virtual ~CTimerControlThread(); + + virtual void setGateway(const wxString& address, unsigned int port, const wxString& password); + virtual void setDelay(bool enabled); + virtual void setFileName(const wxString& fileName); + + virtual void reload(); + + virtual void run(); + virtual void kill(); + +private: + wxString m_password; + wxString m_fileName; + bool m_delay; + unsigned int m_count; + CTimerControlItem** m_items; + wxMutex m_mutex; + CTimerControlRemoteControlHandler* m_handler; + bool m_killed; + + bool login(); + bool link(const wxString& repeater, RECONNECT reconnect, const wxString& reflector); + void logoff(); + + bool sendHash(unsigned int rnd); +}; + +#endif diff --git a/TimerControl/TimerControlThreadHelper.cpp b/TimerControl/TimerControlThreadHelper.cpp new file mode 100644 index 0000000..181ce3a --- /dev/null +++ b/TimerControl/TimerControlThreadHelper.cpp @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2012 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "TimerControlThreadHelper.h" + +CTimerControlThreadHelper::CTimerControlThreadHelper(CTimerControlThread* thread) : +wxThread(wxTHREAD_JOINABLE), +m_thread(thread) +{ + wxASSERT(thread != NULL); +} + +CTimerControlThreadHelper::~CTimerControlThreadHelper() +{ + delete m_thread; +} + +void CTimerControlThreadHelper::start() +{ + Create(); + + SetPriority(100U); + + Run(); +} + +void* CTimerControlThreadHelper::Entry() +{ + wxASSERT(m_thread != NULL); + + m_thread->run(); + + return NULL; +} + +void CTimerControlThreadHelper::kill() +{ + wxASSERT(m_thread != NULL); + + m_thread->kill(); + + Wait(); +} + +void CTimerControlThreadHelper::reload() +{ + wxASSERT(m_thread != NULL); + + m_thread->reload(); +} diff --git a/TimerControl/TimerControlThreadHelper.h b/TimerControl/TimerControlThreadHelper.h new file mode 100644 index 0000000..fdb47c0 --- /dev/null +++ b/TimerControl/TimerControlThreadHelper.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2012,2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef TimerControlThreadHelper_H +#define TimerControlThreadHelper_H + +#include "TimerControlThread.h" + +#include + +class CTimerControlThreadHelper : public wxThread { + +public: + CTimerControlThreadHelper(CTimerControlThread* thread); + virtual ~CTimerControlThreadHelper(); + + virtual void start(); + + virtual void* Entry(); + + virtual void kill(); + + virtual void reload(); + +private: + CTimerControlThread* m_thread; +}; + +#endif diff --git a/VoiceTransmit/VoiceStore.cpp b/VoiceTransmit/VoiceStore.cpp new file mode 100644 index 0000000..01ca126 --- /dev/null +++ b/VoiceTransmit/VoiceStore.cpp @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2014 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "DStarDefines.h" +#include "VoiceStore.h" + +CVoiceStore::CVoiceStore(const wxArrayString& filenames) : +m_filenames(filenames), +m_header(NULL), +m_fileNumber(0U), +m_file() +{ +} + +CVoiceStore::~CVoiceStore() +{ +} + +bool CVoiceStore::open() +{ + wxString fileName = m_filenames.Item(0U); + + bool ret = m_file.open(fileName); + if (!ret) + return false; + + DVTFR_TYPE type = m_file.read(); + if (type != DVTFR_HEADER) { + m_file.close(); + return false; + } + + m_header = m_file.readHeader(); + m_fileNumber = 0U; + + return true; +} + +CHeaderData* CVoiceStore::getHeader() +{ + CHeaderData* header = m_header; + + m_header = NULL; + + return header; +} + +CAMBEData* CVoiceStore::getAMBE() +{ + DVTFR_TYPE type = m_file.read(); + if (type == DVTFR_DATA) { + CAMBEData* ambe = m_file.readData(); + if (ambe != NULL) + return ambe; + } + + for (;;) { + m_file.close(); + m_fileNumber++; + + // The end of the last file? + if (m_fileNumber == m_filenames.GetCount()) + return NULL; + + wxString filename = m_filenames.Item(m_fileNumber); + + bool ret = m_file.open(filename); + if (!ret) + return NULL; + + // This should get the header + type = m_file.read(); + + if (type == DVTFR_HEADER) { + // Throw the header away + CHeaderData* header = m_file.readHeader(); + delete header; + } else if (type == DVTFR_DATA) { + // Shouldn't usually happen + CAMBEData* ambe = m_file.readData(); + if (ambe != NULL) + return ambe; + else + continue; + } else { + // !!!! + continue; + } + + // This should get the first data record + type = m_file.read(); + + if (type == DVTFR_DATA) { + CAMBEData* ambe = m_file.readData(); + if (ambe != NULL) + return ambe; + } + } +} + +void CVoiceStore::close() +{ + m_file.close(); +} diff --git a/VoiceTransmit/VoiceStore.h b/VoiceTransmit/VoiceStore.h new file mode 100644 index 0000000..a87b3d0 --- /dev/null +++ b/VoiceTransmit/VoiceStore.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2014 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef VoiceStore_H +#define VoiceStore_H + +#include "DVTOOLFileReader.h" +#include "HeaderData.h" +#include "AMBEData.h" + +#include + +class CVoiceStore { +public: + CVoiceStore(const wxArrayString& filenames); + ~CVoiceStore(); + + bool open(); + + CHeaderData* getHeader(); + + CAMBEData* getAMBE(); + + void close(); + +private: + wxArrayString m_filenames; + CHeaderData* m_header; + unsigned int m_fileNumber; + CDVTOOLFileReader m_file; +}; + +#endif diff --git a/VoiceTransmit/VoiceTransmit.cpp b/VoiceTransmit/VoiceTransmit.cpp new file mode 100644 index 0000000..2b35cbf --- /dev/null +++ b/VoiceTransmit/VoiceTransmit.cpp @@ -0,0 +1,175 @@ +/* + * Copyright (C) 2014 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "DStarDefines.h" +#include "VoiceTransmit.h" + +int main(int argc, char** argv) +{ + bool res = ::wxInitialize(); + if (!res) { + ::fprintf(stderr, "voicetransmit: failed to initialise the wxWidgets library, exiting\n"); + return 1; + } + + if (argc < 3) { + ::fprintf(stderr, "voicetransmit: invalid command line usage: voicetransmit ..., exiting\n"); + ::wxUninitialize(); + return 1; + } + + wxString repeater = wxString(argv[1], wxConvLocal); + repeater.Replace(wxT("_"), wxT(" ")); + repeater.resize(LONG_CALLSIGN_LENGTH, wxT(' ')); + repeater.MakeUpper(); + + wxArrayString filenames; + for (int i = 2; i < argc; i++) + filenames.Add(wxString(argv[i], wxConvLocal)); + + CVoiceStore store(filenames); + bool opened = store.open(); + if (!opened) { + ::fprintf(stderr, "voicetransmit: unable to open one of the files, exiting\n"); + ::wxUninitialize(); + return 1; + } + + CVoiceTransmit tt(repeater, &store); + bool ret = tt.run(); + + store.close(); + + ::wxUninitialize(); + + return ret ? 0 : 1; +} + +CVoiceTransmit::CVoiceTransmit(const wxString& callsign, CVoiceStore* store) : +m_socket(wxEmptyString, 0U), +m_callsign(callsign), +m_store(store) +{ + wxASSERT(store != NULL); +} + +CVoiceTransmit::~CVoiceTransmit() +{ +} + +bool CVoiceTransmit::run() +{ + bool opened = m_socket.open(); + if (!opened) + return false; + + in_addr address = CUDPReaderWriter::lookup(wxT("127.0.0.1")); + + unsigned int id = CHeaderData::createId(); + + wxString callsignG = m_callsign.Left(LONG_CALLSIGN_LENGTH - 1U); + callsignG.Append(wxT("G")); + + CHeaderData* header = m_store->getHeader(); + if (header == NULL) { + m_socket.close(); + return false; + } + + header->setId(id); + header->setRptCall1(callsignG); + header->setRptCall2(m_callsign); + header->setDestination(address, G2_DV_PORT); + + sendHeader(header); + + delete header; + + wxStopWatch timer; + timer.Start(); + + unsigned int out = 0U; + unsigned int seqNo = 0U; + + for (;;) { + unsigned int needed = timer.Time() / DSTAR_FRAME_TIME_MS; + + while (out < needed) { + CAMBEData* ambe = m_store->getAMBE(); + + if (ambe == NULL) { + seqNo++; + if (seqNo >= 21U) + seqNo = 0U; + + CAMBEData data; + data.setData(END_PATTERN_BYTES, DV_FRAME_LENGTH_BYTES); + data.setDestination(address, G2_DV_PORT); + data.setId(id); + data.setSeq(seqNo); + data.setEnd(true); + + sendData(&data); + + m_socket.close(); + + return true; + } + + seqNo = ambe->getSeq(); + + ambe->setDestination(address, G2_DV_PORT); + ambe->setEnd(false); + ambe->setId(id); + + sendData(ambe); + + delete ambe; + + out++; + } + + ::wxMilliSleep(10UL); + } +} + +bool CVoiceTransmit::sendHeader(CHeaderData* header) +{ + wxASSERT(header != NULL); + + unsigned char buffer[60U]; + unsigned int length = header->getG2Data(buffer, 60U, true); + + for (unsigned int i = 0U; i < 2U; i++) { + bool res = m_socket.write(buffer, length, header->getYourAddress(), header->getYourPort()); + if (!res) + return false; + } + + return true; +} + +bool CVoiceTransmit::sendData(CAMBEData* data) +{ + wxASSERT(data != NULL); + + unsigned char buffer[40U]; + unsigned int length = data->getG2Data(buffer, 40U); + + return m_socket.write(buffer, length, data->getYourAddress(), data->getYourPort()); +} diff --git a/VoiceTransmit/VoiceTransmit.h b/VoiceTransmit/VoiceTransmit.h new file mode 100644 index 0000000..868292d --- /dev/null +++ b/VoiceTransmit/VoiceTransmit.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2014 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef VoiceTransmit_H +#define VoiceTransmit_H + +#include "UDPReaderWriter.h" +#include "VoiceStore.h" +#include "HeaderData.h" +#include "AMBEData.h" + +class CVoiceTransmit { +public: + CVoiceTransmit(const wxString& callsign, CVoiceStore* store); + ~CVoiceTransmit(); + + bool run(); + +private: + CUDPReaderWriter m_socket; + wxString m_callsign; + CVoiceStore* m_store; + + bool sendHeader(CHeaderData* header); + bool sendData(CAMBEData* data); +}; + +#endif diff --git a/VoiceTransmit/VoiceTransmit.vcxproj b/VoiceTransmit/VoiceTransmit.vcxproj new file mode 100644 index 0000000..c0af277 --- /dev/null +++ b/VoiceTransmit/VoiceTransmit.vcxproj @@ -0,0 +1,187 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {27D44C4F-6849-4E15-A5BB-0B54BA296D98} + VoiceTransmit + Win32Proj + 10.0.16299.0 + + + + Application + v141 + Unicode + true + + + Application + v141 + Unicode + true + + + Application + v141 + Unicode + + + Application + v141 + Unicode + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>14.0.24720.0 + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + true + $(WXWIN)\include;$(WXWIN)\lib\vc_dll\mswud;$(IncludePath) + + + true + $(WXWIN)\include;$(WXWIN)\lib\vc_x64_dll\mswud;$(IncludePath) + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + false + + + false + + + + Disabled + $(WXWIN)\include\msvc;$(WXWIN)\include;../Common;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;WINVER=0x0400;__WXMSW__;WXUSINGDLL;wxUSE_GUI=1;__WXDEBUG__;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATEWIN32;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + Level3 + EditAndContinue + + + ws2_32.lib;%(AdditionalDependencies) + $(WXWIN)\lib\vc_dll;%(AdditionalLibraryDirectories) + true + Console + MachineX86 + + + + + Disabled + $(WXWIN)\include\msvc;$(WXWIN)\include;../Common;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;WINVER=0x0400;__WXMSW__;WXUSINGDLL;wxUSE_GUI=1;__WXDEBUG__;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATEWIN32;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + + + Level3 + ProgramDatabase + + + ws2_32.lib;%(AdditionalDependencies) + $(WXWIN)\lib\vc_x64_dll;%(AdditionalLibraryDirectories) + true + Console + + + + + MaxSpeed + true + $(WXWIN)\include\msvc;$(WXWIN)\include;../ircDDB;../Common;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;WINVER=0x0400;__WXMSW__;WXUSINGDLL;wxUSE_GUI=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) + MultiThreadedDLL + true + + Level3 + ProgramDatabase + + + ws2_32.lib;%(AdditionalDependencies) + $(WXWIN)\lib\vc_dll;%(AdditionalLibraryDirectories) + true + Console + true + true + MachineX86 + + + + + MaxSpeed + true + $(WXWIN)\include\msvc;$(WXWIN)\include;../ircDDB;../Common;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;WINVER=0x0400;__WXMSW__;WXUSINGDLL;wxUSE_GUI=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) + MultiThreadedDLL + true + + + Level3 + ProgramDatabase + + + ws2_32.lib;%(AdditionalDependencies) + $(WXWIN)\lib\vc_x64_dll;%(AdditionalLibraryDirectories) + true + Console + true + true + + + + + + + + + + + + + {e793cb8e-2ac9-431a-bbfc-3f52537bb3cf} + false + + + + + + \ No newline at end of file diff --git a/VoiceTransmit/VoiceTransmit.vcxproj.filters b/VoiceTransmit/VoiceTransmit.vcxproj.filters new file mode 100644 index 0000000..91f12c6 --- /dev/null +++ b/VoiceTransmit/VoiceTransmit.vcxproj.filters @@ -0,0 +1,29 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/debian/README b/debian/README new file mode 100644 index 0000000..d774460 --- /dev/null +++ b/debian/README @@ -0,0 +1,6 @@ +The Debian Package ircddbgateway +---------------------------- + +Comments regarding the Package + + -- Jeremy McDermond Thu, 31 Mar 2016 12:47:42 -0700 diff --git a/debian/README.Debian b/debian/README.Debian new file mode 100644 index 0000000..0d1e5a9 --- /dev/null +++ b/debian/README.Debian @@ -0,0 +1,6 @@ +ircddbgateway for Debian +------------------------ + + + + -- Jeremy McDermond Thu, 31 Mar 2016 12:47:42 -0700 diff --git a/debian/README.source b/debian/README.source new file mode 100644 index 0000000..a292090 --- /dev/null +++ b/debian/README.source @@ -0,0 +1,10 @@ +ircddbgateway for Debian +------------------------ + + + + + + -- Jeremy McDermond Thu, 31 Mar 2016 12:47:42 -0700 + diff --git a/debian/aprstransmitd.aprstransmitd@.service b/debian/aprstransmitd.aprstransmitd@.service new file mode 100644 index 0000000..2ecad69 --- /dev/null +++ b/debian/aprstransmitd.aprstransmitd@.service @@ -0,0 +1,14 @@ +[Unit] +Description=D-STAR APRS Transmit Daemon +Wants=ircddbgatewayd.service +After=ircddbgatewayd.service + +[Service] +User=opendv +EnvironmentFile=/etc/opendv/aprstransmitd_%i.conf +ExecStart=/usr/sbin/aprstransmitd %i -host $APRS_SERVER -port $APRS_PORT -filter ${FILTER} +Restart=on-abort + +[Install] +WantedBy=multi-user.target +DefaultInstance=1 diff --git a/debian/aprstransmitd.conf b/debian/aprstransmitd.conf new file mode 100644 index 0000000..20e49e0 --- /dev/null +++ b/debian/aprstransmitd.conf @@ -0,0 +1,3 @@ +FILTER="m/50" +APRS_SERVER=rotate.aprs2.net +APRS_PORT=14580 diff --git a/debian/aprstransmitd.install b/debian/aprstransmitd.install new file mode 100644 index 0000000..5357072 --- /dev/null +++ b/debian/aprstransmitd.install @@ -0,0 +1,2 @@ +usr/sbin/aprstransmitd +../aprstransmitd.conf etc/opendv diff --git a/debian/changelog b/debian/changelog new file mode 100644 index 0000000..96d755e --- /dev/null +++ b/debian/changelog @@ -0,0 +1,5 @@ +ircddbgateway (1.20160331-1) unstable; urgency=low + + * Initial Release. + + -- Jeremy McDermond Thu, 31 Mar 2016 12:47:42 -0700 diff --git a/debian/compat b/debian/compat new file mode 100644 index 0000000..ec63514 --- /dev/null +++ b/debian/compat @@ -0,0 +1 @@ +9 diff --git a/debian/control b/debian/control new file mode 100644 index 0000000..2ed1d4f --- /dev/null +++ b/debian/control @@ -0,0 +1,91 @@ +Source: ircddbgateway +Section: hamradio +Priority: optional +Maintainer: Jeremy McDermond +Build-Depends: debhelper (>= 9), autotools-dev , pkg-config, libwxgtk3.0-dev +Standards-Version: 3.9.6 +Homepage: https://github.com/dl5di/OpenDV + +Package: opendv-base +Architecture: all +Description: D-STAR Digital Voice Base Components + + +Package: ircddbgatewayd +Architecture: armhf armel i386 amd64 +Depends: ${shlibs:Depends}, ${misc:Depends}, opendv-base +Description: D-STAR Digital Voice Internet Gateway Daemon Components + + +Package: ircddbgateway +Architecture: armhf armel i386 amd64 +Depends: ${shlibs:Depends}, ${misc:Depends}, opendv-base +Description: D-STAR Digital Voice Internet Gateway GUI Components + + +Package: starnetserverd +Architecture: armhf armel i386 amd64 +Depends: ${shlibs:Depends}, ${misc:Depends}, opendv-base +Description: D-STAR Digital Voice StarNet Daemon Components + + +Package: starnetserver +Architecture: armhf armel i386 amd64 +Depends: ${shlibs:Depends}, ${misc:Depends}, opendv-base +Description: D-STAR Digital Voice StarNet GUI Components + + +Package: remotecontrol +Architecture: armhf armel i386 amd64 +Depends: ${shlibs:Depends}, ${misc:Depends}, opendv-base +Description: D-STAR Digital Voice Internet Gateway Remote Control + Used to control either an ircDDBGateway or a STARnet Digital Server. + +Package: remotecontrold +Architecture: armhf armel i386 amd64 +Depends: ${shlibs:Depends}, ${misc:Depends}, opendv-base +Description: D-STAR Digital Voice Internet Gateway Remote Control - Command Line + Used to control either an ircDDBGateway or a STARnet Digital Server. + Command line version. + +Package: timercontrol +Architecture: armhf armel i386 amd64 +Depends: ${shlibs:Depends}, ${misc:Depends}, opendv-base +Description: D-STAR Digital Voice Internet Gateway Timer Control GUI Components + The Timer Control application and daemon are used to control the reflector + links of the ircDDB Gateway. It allows a time schedule to be entered, so + that access to the various reflectors can depend on the day and time. + +Package: timercontrold +Architecture: armhf armel i386 amd64 +Depends: ${shlibs:Depends}, ${misc:Depends}, opendv-base +Description: D-STAR Digital Voice Internet Gateway Timer Control Daemon Components + The Timer Control application and daemon are used to control the reflector + links of the ircDDB Gateway. It allows a time schedule to be entered, so + that access to the various reflectors can depend on the day and time. + +Package: timeserver +Architecture: armhf armel i386 amd64 +Depends: ${shlibs:Depends}, ${misc:Depends}, opendv-base +Description: D-STAR Digital Voice Internet Gateway Time Server GUI Components + The Time Server is used with the ircDDB Gateway to add time announcements to + the system. + +Package: timeserverd +Architecture: armhf armel i386 amd64 +Depends: ${shlibs:Depends}, ${misc:Depends}, opendv-base +Description: D-STAR Digital Voice Internet Gateway Time Server Daemon Components + The Time Server is used with the ircDDB Gateway to add time announcements to + the system. + +Package: ircddbgateway-tools +Architecture: armhf armel i386 amd64 +Depends: ${shlibs:Depends}, ${misc:Depends} +Description: D-STAR Digital Voice Internet Gateway Transmit Tools + These tools are used to transmit by hand to APRS, D-STAR text or voice. + +Package: aprstransmitd +Architecture: armhf armel i386 amd64 +Depends: ${shlibs:Depends}, ${misc:Depends}, opendv-base +Description: D-STAR Digital Voice Internet Gateway APRS Tansmit Daemon + This daemon is used to echo APRS data into a D-STAR gateway. diff --git a/debian/copyright b/debian/copyright new file mode 100644 index 0000000..d6ff572 --- /dev/null +++ b/debian/copyright @@ -0,0 +1,34 @@ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: ircddbgateway +Source: + +Files: * +Copyright: + +License: GPL-2.0+ + +Files: debian/* +Copyright: 2016 Jeremy McDermond +License: GPL-2.0+ + +License: GPL-2.0+ + This package is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + . + This package is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + . + You should have received a copy of the GNU General Public License + along with this program. If not, see + . + On Debian systems, the complete text of the GNU General + Public License version 2 can be found in "/usr/share/common-licenses/GPL-2". + +# Please also look if there are files or directories which have a +# different copyright/license attached and list them here. +# Please avoid picking licenses with terms that are more restrictive than the +# packaged work, as it may make Debian's contributions unacceptable upstream. diff --git a/debian/docs b/debian/docs new file mode 100644 index 0000000..b9eb9fd --- /dev/null +++ b/debian/docs @@ -0,0 +1,3 @@ +BUILD.txt +CHANGES.txt +COPYING.txt diff --git a/debian/ircddbgateway-tools.install b/debian/ircddbgateway-tools.install new file mode 100644 index 0000000..516b271 --- /dev/null +++ b/debian/ircddbgateway-tools.install @@ -0,0 +1,3 @@ +usr/bin/voicetransmit +usr/bin/aprstransmit +usr/bin/texttransmit diff --git a/debian/ircddbgateway.install b/debian/ircddbgateway.install new file mode 100644 index 0000000..28cd041 --- /dev/null +++ b/debian/ircddbgateway.install @@ -0,0 +1,2 @@ +usr/bin/ircddbgateway +usr/bin/ircddbgatewayconfig diff --git a/debian/ircddbgateway.logrotate b/debian/ircddbgateway.logrotate new file mode 100644 index 0000000..247f063 --- /dev/null +++ b/debian/ircddbgateway.logrotate @@ -0,0 +1,7 @@ +/var/log/opendv/ircddbgateway.log { + rotate 14 + daily + compress + missingok + copytruncate +} diff --git a/debian/ircddbgatewayd.install b/debian/ircddbgatewayd.install new file mode 100644 index 0000000..8b9572d --- /dev/null +++ b/debian/ircddbgatewayd.install @@ -0,0 +1 @@ +usr/sbin/ircddbgatewayd diff --git a/debian/ircddbgatewayd.ircddbgatewayd.service b/debian/ircddbgatewayd.ircddbgatewayd.service new file mode 100644 index 0000000..48010dd --- /dev/null +++ b/debian/ircddbgatewayd.ircddbgatewayd.service @@ -0,0 +1,11 @@ +[Unit] +Description=D-STAR Gateway Daemon +After=network.target + +[Service] +User=opendv +ExecStart=/usr/sbin/ircddbgatewayd +Restart=on-abort + +[Install] +WantedBy=multi-user.target diff --git a/debian/ircddbgatewayd.logrotate b/debian/ircddbgatewayd.logrotate new file mode 100644 index 0000000..a2754f5 --- /dev/null +++ b/debian/ircddbgatewayd.logrotate @@ -0,0 +1,7 @@ +/var/log/opendv/ircddbgatewayd.log { + rotate 14 + daily + compress + missingok + copytruncate +} diff --git a/debian/opendv-base.dirs b/debian/opendv-base.dirs new file mode 100644 index 0000000..ae9d91a --- /dev/null +++ b/debian/opendv-base.dirs @@ -0,0 +1,2 @@ +etc/opendv +var/log/opendv diff --git a/debian/opendv-base.install b/debian/opendv-base.install new file mode 100644 index 0000000..d14edc5 --- /dev/null +++ b/debian/opendv-base.install @@ -0,0 +1,34 @@ +usr/share/opendv/CCS_Hosts.txt +usr/share/opendv/DCS_Hosts.txt +usr/share/opendv/de_DE.ambe +usr/share/opendv/de_DE.indx +usr/share/opendv/DExtra_Hosts.txt +usr/share/opendv/dk_DK.ambe +usr/share/opendv/dk_DK.indx +usr/share/opendv/DPlus_Hosts.txt +usr/share/opendv/en_GB.ambe +usr/share/opendv/en_GB.indx +usr/share/opendv/en_US.ambe +usr/share/opendv/en_US.indx +usr/share/opendv/es_ES.ambe +usr/share/opendv/es_ES.indx +usr/share/opendv/fr_FR.ambe +usr/share/opendv/fr_FR.indx +usr/share/opendv/it_IT.ambe +usr/share/opendv/it_IT.indx +usr/share/opendv/no_NO.ambe +usr/share/opendv/no_NO.indx +usr/share/opendv/pl_PL.ambe +usr/share/opendv/pl_PL.indx +usr/share/opendv/se_SE.ambe +usr/share/opendv/se_SE.indx +usr/share/opendv/TIME_de_DE.ambe +usr/share/opendv/TIME_de_DE.indx +usr/share/opendv/TIME_en_GB.ambe +usr/share/opendv/TIME_en_GB.indx +usr/share/opendv/TIME_en_US.ambe +usr/share/opendv/TIME_en_US.indx +usr/share/opendv/TIME_fr_FR.ambe +usr/share/opendv/TIME_fr_FR.indx +usr/share/opendv/TIME_se_SE.ambe +usr/share/opendv/TIME_se_SE.indx diff --git a/debian/opendv-base.postinst b/debian/opendv-base.postinst new file mode 100644 index 0000000..7ef22e3 --- /dev/null +++ b/debian/opendv-base.postinst @@ -0,0 +1,48 @@ +#!/bin/sh +# postinst script for dstarrepeater +# +# see: dh_installdeb(1) + +set -e + +# summary of how this script can be called: +# * `configure' +# * `abort-upgrade' +# * `abort-remove' `in-favour' +# +# * `abort-remove' +# * `abort-deconfigure' `in-favour' +# `removing' +# +# for details, see https://www.debian.org/doc/debian-policy/ or +# the debian-policy package + + +case "$1" in + configure) + useradd --user-group -M --system opendv --shell /bin/false || true + + # Add the opendv user to the audio group so that it can open audio + # devices when using the audio based drivers such as the Sound Card + # one. + usermod --groups audio --append opendv || true + usermod --groups dialout --append opendv || true + usermod --groups gpio --append opendv || true + chown opendv:opendv /var/log/opendv + ;; + + abort-upgrade|abort-remove|abort-deconfigure) + ;; + + *) + echo "postinst called with unknown argument \`$1'" >&2 + exit 1 + ;; +esac + +# dh_installdeb will replace this with shell code automatically +# generated by other debhelper scripts. + +#DEBHELPER# + +exit 0 diff --git a/debian/remotecontrol.install b/debian/remotecontrol.install new file mode 100644 index 0000000..d95c5f4 --- /dev/null +++ b/debian/remotecontrol.install @@ -0,0 +1 @@ +usr/bin/remotecontrol diff --git a/debian/remotecontrold.install b/debian/remotecontrold.install new file mode 100644 index 0000000..6155b51 --- /dev/null +++ b/debian/remotecontrold.install @@ -0,0 +1 @@ +usr/bin/remotecontrold diff --git a/debian/rules b/debian/rules new file mode 100644 index 0000000..e87d57a --- /dev/null +++ b/debian/rules @@ -0,0 +1,36 @@ +#!/usr/bin/make -f +# See debhelper(7) (uncomment to enable) +# output every command that modifies files on the build system. +#export DH_VERBOSE = 1 + +# see EXAMPLES in dpkg-buildflags(1) and read /usr/share/dpkg/* +DPKG_EXPORT_BUILDFLAGS = 1 +include /usr/share/dpkg/default.mk + +# see FEATURE AREAS in dpkg-buildflags(1) +#export DEB_BUILD_MAINT_OPTIONS = hardening=+all + +# see ENVIRONMENT in dpkg-buildflags(1) +# package maintainers to append CFLAGS +#export DEB_CFLAGS_MAINT_APPEND = -Wall -pedantic +# package maintainers to append LDFLAGS +#export DEB_LDFLAGS_MAINT_APPEND = -Wl,--as-needed + + +# main packaging script based on dh7 syntax +%: + dh $@ --with autotools-dev --parallel + +# dh_make generated override targets +# This is example for Cmake (See https://bugs.debian.org/641051 ) +#override_dh_auto_configure: +# dh_auto_configure -- \ +# -DCMAKE_LIBRARY_PATH=$(DEB_HOST_MULTIARCH) + +override_dh_installinit: + dh_installinit + dh_installinit --name=ircddbgatewayd + dh_installinit --name=starnetserverd + dh_installinit --name=timercontrold + dh_installinit --name=timeserverd + dh_installinit --name=aprstransmitd@ diff --git a/debian/source/format b/debian/source/format new file mode 100644 index 0000000..89ae9db --- /dev/null +++ b/debian/source/format @@ -0,0 +1 @@ +3.0 (native) diff --git a/debian/starnetserver.install b/debian/starnetserver.install new file mode 100644 index 0000000..8d43e0d --- /dev/null +++ b/debian/starnetserver.install @@ -0,0 +1 @@ +usr/bin/starnetserver diff --git a/debian/starnetserver.logrotate b/debian/starnetserver.logrotate new file mode 100644 index 0000000..d251afc --- /dev/null +++ b/debian/starnetserver.logrotate @@ -0,0 +1,7 @@ +/var/log/opendv/starnetserver.log { + rotate 14 + daily + compress + missingok + copytruncate +} diff --git a/debian/starnetserverd.install b/debian/starnetserverd.install new file mode 100644 index 0000000..d42003a --- /dev/null +++ b/debian/starnetserverd.install @@ -0,0 +1 @@ +usr/sbin/starnetserverd diff --git a/debian/starnetserverd.logrotate b/debian/starnetserverd.logrotate new file mode 100644 index 0000000..b50cf56 --- /dev/null +++ b/debian/starnetserverd.logrotate @@ -0,0 +1,7 @@ +/var/log/opendv/starnetserverd.log { + rotate 14 + daily + compress + missingok + copytruncate +} diff --git a/debian/starnetserverd.starnetserverd.service b/debian/starnetserverd.starnetserverd.service new file mode 100644 index 0000000..ce5db1d --- /dev/null +++ b/debian/starnetserverd.starnetserverd.service @@ -0,0 +1,11 @@ +[Unit] +Description=D-STAR Gateway Daemon +After=network.target + +[Service] +User=opendv +ExecStart=/usr/sbin/starnetserverd +Restart=on-abort + +[Install] +WantedBy=multi-user.target diff --git a/debian/timercontrol.install b/debian/timercontrol.install new file mode 100644 index 0000000..38f4093 --- /dev/null +++ b/debian/timercontrol.install @@ -0,0 +1 @@ +usr/bin/timercontrol diff --git a/debian/timercontrol.logrotate b/debian/timercontrol.logrotate new file mode 100644 index 0000000..84d4a4b --- /dev/null +++ b/debian/timercontrol.logrotate @@ -0,0 +1,7 @@ +/var/log/opendv/timercontrol.log { + rotate 14 + daily + compress + missingok + copytruncate +} diff --git a/debian/timercontrold.install b/debian/timercontrold.install new file mode 100644 index 0000000..efe8d13 --- /dev/null +++ b/debian/timercontrold.install @@ -0,0 +1 @@ +usr/sbin/timercontrold diff --git a/debian/timercontrold.logrotate b/debian/timercontrold.logrotate new file mode 100644 index 0000000..97972f8 --- /dev/null +++ b/debian/timercontrold.logrotate @@ -0,0 +1,7 @@ +/var/log/opendv/timercontrold.log { + rotate 14 + daily + compress + missingok + copytruncate +} diff --git a/debian/timercontrold.timercontrold.service b/debian/timercontrold.timercontrold.service new file mode 100644 index 0000000..58e5b8c --- /dev/null +++ b/debian/timercontrold.timercontrold.service @@ -0,0 +1,12 @@ +[Unit] +Description=D-STAR Timer Control Daemon +Wants=ircddbgatewayd.service +After=ircddbgatewayd.service + +[Service] +User=opendv +ExecStart=/usr/sbin/timercontrold +Restart=on-abort + +[Install] +WantedBy=multi-user.target diff --git a/debian/timeserver.install b/debian/timeserver.install new file mode 100644 index 0000000..311e8a2 --- /dev/null +++ b/debian/timeserver.install @@ -0,0 +1 @@ +usr/bin/timeserver diff --git a/debian/timeserver.logrotate b/debian/timeserver.logrotate new file mode 100644 index 0000000..541a80d --- /dev/null +++ b/debian/timeserver.logrotate @@ -0,0 +1,7 @@ +/var/log/opendv/timeserver.log { + rotate 14 + daily + compress + missingok + copytruncate +} diff --git a/debian/timeserverd.install b/debian/timeserverd.install new file mode 100644 index 0000000..bfc53bf --- /dev/null +++ b/debian/timeserverd.install @@ -0,0 +1 @@ +usr/sbin/timeserverd diff --git a/debian/timeserverd.logrotate b/debian/timeserverd.logrotate new file mode 100644 index 0000000..1cdfe67 --- /dev/null +++ b/debian/timeserverd.logrotate @@ -0,0 +1,7 @@ +/var/log/opendv/timeserverd.log { + rotate 14 + daily + compress + missingok + copytruncate +} diff --git a/debian/timeserverd.timeserverd.service b/debian/timeserverd.timeserverd.service new file mode 100644 index 0000000..4425358 --- /dev/null +++ b/debian/timeserverd.timeserverd.service @@ -0,0 +1,12 @@ +[Unit] +Description=D-STAR Timer Control Daemon +Wants=ircddbgatewayd.service +After=ircddbgatewayd.service + +[Service] +User=opendv +ExecStart=/usr/sbin/timeserverd +Restart=on-abort + +[Install] +WantedBy=multi-user.target diff --git a/ircDDB/IRCApplication.h b/ircDDB/IRCApplication.h new file mode 100644 index 0000000..3e2a19e --- /dev/null +++ b/ircDDB/IRCApplication.h @@ -0,0 +1,50 @@ +/* + +CIRCDDB - ircDDB client library in C++ + +Copyright (C) 2010 Michael Dirska, DL1BFF (dl1bff@mdx.de) + +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 +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +*/ + +#if !defined(_IRCAPPLICATION_H) +#define _IRCAPPLICATION_H + +#include + +#include "IRCMessageQueue.h" + +class IRCApplication +{ +public: + virtual void userJoin (const wxString& nick, const wxString& name, const wxString& host) = 0; + virtual void userLeave (const wxString& nick) = 0; + virtual void userChanOp (const wxString& nick, bool op) = 0; + virtual void userListReset(void) = 0; + + virtual void msgChannel (IRCMessage * m) = 0; + virtual void msgQuery (IRCMessage * m) = 0; + + virtual void setCurrentNick(const wxString& nick) = 0; + virtual void setTopic(const wxString& topic) = 0; + + virtual void setBestServer(const wxString& ircUser) = 0; + + virtual void setSendQ( IRCMessageQueue * s ) = 0; + virtual IRCMessageQueue * getSendQ (void) = 0; +}; + + +#endif diff --git a/ircDDB/IRCClient.cpp b/ircDDB/IRCClient.cpp new file mode 100644 index 0000000..751231f --- /dev/null +++ b/ircDDB/IRCClient.cpp @@ -0,0 +1,515 @@ +/* + +CIRCDDB - ircDDB client library in C++ + +Copyright (C) 2010-2011 Michael Dirska, DL1BFF (dl1bff@mdx.de) +Copyright (C) 2012 Jonathan Naylor, G4KLX + +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 +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +*/ + + +#if defined(WIN32) + +#define WIN32_LEAN_AND_MEAN + +#include +#include + +#else + +#include +#include +#include + +#endif + + +#include "IRCClient.h" +#include "IRCutils.h" + +#include + + + +#include +#include + + + + + + +IRCClient::IRCClient( IRCApplication * app, const wxString& update_channel, + const wxString& hostName, unsigned int port, const wxString& callsign, const wxString& password, + const wxString& versionInfo, const wxString& localAddr ) + : wxThread(wxTHREAD_JOINABLE) +{ +#if defined(__WINDOWS__) + WSAData data; + int wsaRet = ::WSAStartup(MAKEWORD(2, 2), &data); + if (wsaRet != 0) + wxLogError(wxT("IRCClient::IRCClient: Error from WSAStartup")); +#endif + + safeStringCopy(host_name, hostName.mb_str(), sizeof host_name); + + this -> callsign = callsign.Lower(); + this -> port = port; + this -> password = password; + + this -> app = app; + + if (localAddr.IsEmpty()) + { + safeStringCopy(local_addr, "0.0.0.0", sizeof local_addr); + } + else + { + safeStringCopy(local_addr, localAddr.mb_str(), sizeof local_addr); + } + + proto = new IRCProtocol ( app, this->callsign, password, update_channel, versionInfo ); + + recvQ = NULL; + sendQ = NULL; + + recv = NULL; +} + +IRCClient::~IRCClient() +{ + delete proto; + +#if defined(__WINDOWS__) + ::WSACleanup(); +#endif +} + +void IRCClient::startWork() +{ + terminateThread = false; + + Create(); + Run(); +} + +void IRCClient::stopWork() +{ + terminateThread = true; + + Wait(); +} + +wxThread::ExitCode IRCClient::Entry () +{ + unsigned int numAddr; + +#define MAXIPV4ADDR 10 + struct sockaddr_in addr[MAXIPV4ADDR]; + + struct sockaddr_in myaddr; + + int state = 0; + int timer = 0; + int sock = 0; + unsigned int currentAddr = 0; + + int result; + + + numAddr = 0; + + result = getAllIPV4Addresses(local_addr, 0, &numAddr, &myaddr, 1); + + if ((result != 0) || (numAddr != 1)) + { + wxLogVerbose(wxT("IRCClient::Entry: local address not parseable, using 0.0.0.0")); + memset(&myaddr, 0x00, sizeof(struct sockaddr_in)); + } + + while (true) + { + + if (timer > 0) + { + timer --; + } + + switch (state) + { + case 0: + if (terminateThread) + { + wxLogVerbose(wxT("IRCClient::Entry: thread terminated at state=%d"), state); + return 0; + } + + if (timer == 0) + { + timer = 30; + + if (getAllIPV4Addresses(host_name, port, &numAddr, addr, MAXIPV4ADDR) == 0) + { + wxLogVerbose(wxT("IRCClient::Entry: number of DNS entries %d"), numAddr); + if (numAddr > 0) + { + currentAddr = 0; + state = 1; + timer = 0; + } + } + } + break; + + case 1: + if (terminateThread) + { + wxLogVerbose(wxT("IRCClient::Entry: thread terminated at state=%d"), state); + return 0; + } + + if (timer == 0) + { + sock = socket( PF_INET, SOCK_STREAM, IPPROTO_TCP); + + if (sock < 0) + { + wxLogSysError(wxT("IRCClient::Entry: socket")); + timer = 30; + state = 0; + } + else + { +#if defined(__WINDOWS__) + u_long nonBlock = 1UL; + if (ioctlsocket( sock, FIONBIO, &nonBlock ) != 0) + { + wxLogSysError(wxT("IRCClient::Entry: ioctlsocket")); + closesocket(sock); + timer = 30; + state = 0; + } +#else + if (fcntl( sock, F_SETFL, O_NONBLOCK ) < 0) + { + wxLogSysError(wxT("IRCClient::Entry: fcntl")); + close(sock); + timer = 30; + state = 0; + } +#endif + else + { + unsigned char * h = (unsigned char *) &(myaddr.sin_addr); + int res; + + if ((h[0] != 0) || (h[1] != 0) || (h[2] != 0) || (h[3] != 0)) + { + wxLogVerbose(wxT("IRCClient::Entry: bind: local address %d.%d.%d.%d"), + h[0], h[1], h[2], h[3]); + } + + res = bind(sock, (struct sockaddr *) &myaddr, sizeof (struct sockaddr_in)); + + if (res != 0) + { + + wxLogSysError(wxT("IRCClient::Entry: bind")); +#if defined(__WINDOWS__) + closesocket(sock); +#else + close(sock); +#endif + state = 0; + timer = 30; + break; + } + + + h = (unsigned char *) &(addr[currentAddr].sin_addr); + wxLogVerbose(wxT("IRCClient::Entry: trying to connect to %d.%d.%d.%d"), + h[0], h[1], h[2], h[3]); + + res = connect(sock, (struct sockaddr *) (addr + currentAddr), sizeof (struct sockaddr_in)); + + if (res == 0) + { + wxLogVerbose(wxT("IRCClient::Entry: connected")); + state = 4; + } + else + { +#if defined(__WINDOWS__) + if (WSAGetLastError() == WSAEWOULDBLOCK) +#else + if (errno == EINPROGRESS) +#endif + { + wxLogVerbose(wxT("IRCClient::Entry: connect in progress")); + state = 3; + timer = 10; // 5 second timeout + } + else + { + wxLogSysError(wxT("IRCClient::Entry: connect")); +#if defined(__WINDOWS__) + closesocket(sock); +#else + close(sock); +#endif + currentAddr ++; + if (currentAddr >= numAddr) + { + state = 0; + timer = 30; + } + else + { + state = 1; + timer = 4; + } + } + } + } // connect + } + } + break; + + case 3: + { + struct timeval tv; + tv.tv_sec = 0; + tv.tv_usec = 0; + + fd_set myset; + FD_ZERO(&myset); +#if defined(__WINDOWS__) + FD_SET((unsigned int)sock, &myset); +#else + FD_SET(sock, &myset); +#endif + + int res = select(sock+1, NULL, &myset, NULL, &tv); + if (res < 0) + { + wxLogSysError(wxT("IRCClient::Entry: select")); +#if defined(__WINDOWS__) + closesocket(sock); +#else + close(sock); +#endif + state = 0; + timer = 30; + } + else if (res > 0) // connect is finished + { +#if defined(__WINDOWS__) + int val_len; +#else + socklen_t val_len; +#endif + int value; + + val_len = sizeof value; + + if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (char *) &value, &val_len) < 0) + { + wxLogSysError(wxT("IRCClient::Entry: getsockopt")); +#if defined(__WINDOWS__) + closesocket(sock); +#else + close(sock); +#endif + state = 0; + timer = 30; + } + else + { + if (value != 0) + { + wxLogWarning(wxT("IRCClient::Entry: SO_ERROR=%d"), value); +#if defined(__WINDOWS__) + closesocket(sock); +#else + close(sock); +#endif + currentAddr ++; + if (currentAddr >= numAddr) + { + state = 0; + timer = 30; + } + else + { + state = 1; + timer = 2; + } + } + else + { + wxLogVerbose(wxT("IRCClient::Entry: connected2")); + state = 4; + } + } + + } + else if (timer == 0) + { // select timeout and timer timeout + wxLogVerbose(wxT("IRCClient::Entry: connect timeout")); +#if defined(__WINDOWS__) + closesocket(sock); +#else + close(sock); +#endif + currentAddr ++; + if (currentAddr >= numAddr) + { + state = 0; + timer = 30; + } + else + { + state = 1; // open new socket + timer = 2; + } + } + + } + break; + + case 4: + { + recvQ = new IRCMessageQueue(); + sendQ = new IRCMessageQueue(); + + recv = new IRCReceiver(sock, recvQ); + recv->startWork(); + + proto->setNetworkReady(true); + state = 5; + timer = 0; + + } + break; + + + case 5: + if (terminateThread) + { + state = 6; + } + else + { + + if (recvQ -> isEOF()) + { + timer = 0; + state = 6; + } + else if (proto -> processQueues(recvQ, sendQ) == false) + { + timer = 0; + state = 6; + } + + while ((state == 5) && sendQ->messageAvailable()) + { + IRCMessage * m = sendQ -> getMessage(); + + wxString out; + + m -> composeMessage ( out ); + + char buf[200]; + safeStringCopy(buf, out.mb_str(wxConvUTF8), sizeof buf); + int len = strlen(buf); + + if (buf[len - 1] == 10) // is there a NL char at the end? + { + int r = send(sock, buf, len, 0); + + if (r != len) + { + wxLogVerbose(wxT("IRCClient::Entry: short write %d < %d"), r, len); + + timer = 0; + state = 6; + } +/* else + { + wxLogVerbose(wxT("write %d bytes (") + out + wxT(")"), len ); + } */ + } + else + { + wxLogVerbose(wxT("IRCClient::Entry: no NL at end, len=%d"), len); + + timer = 0; + state = 6; + } + + delete m; + } + } + break; + + case 6: + { + if (app != NULL) + { + app->setSendQ(NULL); + app->userListReset(); + } + + proto->setNetworkReady(false); + recv->stopWork(); + + wxThread::Sleep(2000); + + delete recv; + delete recvQ; + delete sendQ; + +#if defined(__WINDOWS__) + closesocket(sock); +#else + close(sock); +#endif + + if (terminateThread) // request to end the thread + { + wxLogVerbose(wxT("IRCClient::Entry: thread terminated at state=%d"), state); + return 0; + } + + timer = 30; + state = 0; // reconnect to IRC server + } + break; + + } + + wxThread::Sleep(500); + + } + + return 0; +} + + + + + diff --git a/ircDDB/IRCClient.h b/ircDDB/IRCClient.h new file mode 100644 index 0000000..521f900 --- /dev/null +++ b/ircDDB/IRCClient.h @@ -0,0 +1,77 @@ +/* + +CIRCDDB - ircDDB client library in C++ + +Copyright (C) 2010-2011 Michael Dirska, DL1BFF (dl1bff@mdx.de) +Copyright (C) 2011,2012 Jonathan Naylor, G4KLX + +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 +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +*/ + + +#if !defined(_IRCCLIENT_H) +#define _IRCCLIENT_H + +#include "IRCReceiver.h" +#include "IRCMessageQueue.h" +#include "IRCProtocol.h" +#include "IRCApplication.h" + +#include + + +class IRCClient : public wxThread +{ + public: + + IRCClient( IRCApplication * app, const wxString& update_channel, + const wxString& hostName, unsigned int port, const wxString& callsign, const wxString& password, + const wxString& versionInfo, const wxString& localAddr ); + + virtual ~IRCClient(); + + + virtual void startWork(); + + virtual void stopWork(); + + + protected: + + virtual wxThread::ExitCode Entry(); + + + + private: + + char host_name[100]; + char local_addr[100]; + unsigned int port; + wxString callsign; + wxString password; + + bool terminateThread; + + IRCReceiver * recv; + IRCMessageQueue * recvQ; + IRCMessageQueue * sendQ; + IRCProtocol * proto; + + IRCApplication * app; + +}; + + +#endif diff --git a/ircDDB/IRCDDB.cpp b/ircDDB/IRCDDB.cpp new file mode 100644 index 0000000..afec4c1 --- /dev/null +++ b/ircDDB/IRCDDB.cpp @@ -0,0 +1,32 @@ +/* + +CIRCDDBClient - ircDDB client library in C++ + +Copyright (C) 2010-2011 Michael Dirska, DL1BFF (dl1bff@mdx.de) +Copyright (C) 2011,2012 Jonathan Naylor, G4KLX + +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 +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +*/ + +#include "IRCDDB.h" + +CIRCDDB::CIRCDDB() +{ +} + + +CIRCDDB::~CIRCDDB() +{ +} diff --git a/ircDDB/IRCDDB.h b/ircDDB/IRCDDB.h new file mode 100644 index 0000000..328f6dc --- /dev/null +++ b/ircDDB/IRCDDB.h @@ -0,0 +1,163 @@ +/* + +CIRCDDB - ircDDB client library in C++ + +Copyright (C) 2010-2011 Michael Dirska, DL1BFF (dl1bff@mdx.de) +Copyright (C) 2011,2012 Jonathan Naylor, G4KLX + +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 +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +*/ + +#include + +#if !defined(_IRCDDB_H) +#define _IRCDDB_H + +enum IRCDDB_RESPONSE_TYPE { + IDRT_NONE, + IDRT_USER, + IDRT_GATEWAY, + IDRT_REPEATER +}; + + +class CIRCDDB +{ +public: + CIRCDDB(); + virtual ~CIRCDDB(); + + // A false return implies a network error, or unable to log in + virtual bool open() = 0; + + + // rptrQTH can be called multiple times if necessary + // callsign The callsign of the repeater + // latitude WGS84 position of antenna in degrees, positive value -> NORTH + // longitude WGS84 position of antenna in degrees, positive value -> EAST + // desc1, desc2 20-character description of QTH + // infoURL URL of a web page with information about the repeater + + virtual void rptrQTH(const wxString& callsign, double latitude, double longitude, const wxString& desc1, + const wxString& desc2, const wxString& infoURL) = 0; + + + + // rptrQRG can be called multiple times if necessary + // callsign callsign of the repeater + // txFrequency repeater TX frequency in MHz + // duplexShift duplex shift in MHz (positive or negative value): RX_freq = txFrequency + duplexShift + // range range of the repeater in meters (meters = miles * 1609.344) + // agl height of the antenna above ground in meters (meters = feet * 0.3048) + + virtual void rptrQRG(const wxString& callsign, double txFrequency, double duplexShift, double range, double agl) = 0; + + + // If you call this method once, watchdog messages will be sent to the + // to the ircDDB network every 15 minutes. Invoke this method every 1-2 minutes to indicate + // that the gateway is working properly. After activating the watchdog, a red LED will be displayed + // on the ircDDB web page if this method is not called within a period of about 30 minutes. + // The string wdInfo should contain information about the source of the alive messages, e.g., + // version of the RF decoding software. For example, the ircDDB java software sets this + // to "rpm_ircddbmhd-x.z-z". The string wdInfo must contain at least one non-space character. + + virtual void kickWatchdog(const wxString& callsign, const wxString& wdInfo) = 0; + + + + // get internal network status + virtual int getConnectionState() = 0; + // one of these values is returned: + // 0 = not (yet) connected to the IRC server + // 1-6 = a new connection was established, download of repeater info etc. is + // in progress + // 7 = the ircDDB connection is fully operational + // 10 = some network error occured, next state is "0" (new connection attempt) + + // Send heard data, a false return implies a network error + virtual bool sendHeard(const wxString& myCall, const wxString& myCallExt, + const wxString& yourCall, const wxString& rpt1, + const wxString& rpt2, unsigned char flag1, + unsigned char flag2, unsigned char flag3) = 0; + + + // same as sendHeard with two new fields: + // network_destination: empty string or 8-char call sign of the repeater + // or reflector, where this transmission is relayed to. + // tx_message: 20-char TX message or empty string, if the user did not + // send a TX message + virtual bool sendHeardWithTXMsg(const wxString& myCall, const wxString& myCallExt, + const wxString& yourCall, const wxString& rpt1, + const wxString& rpt2, unsigned char flag1, + unsigned char flag2, unsigned char flag3, + const wxString& network_destination, + const wxString& tx_message) = 0; + + // this method should be called at the end of a transmission + // num_dv_frames: number of DV frames sent out (96 bit frames, 20ms) + // num_dv_silent_frames: number of DV silence frames sent out in the + // last transmission, or -1 if the information is not available + // num_bit_errors: number of bit errors of the received data. This should + // be the derived from the first Golay block of the voice data. This + // error correction code only looks at 24 bits of the 96 bit frame. + // So, the overall bit error rate is calculated like this: + // BER = num_bit_errors / (num_dv_frames * 24) + // Set num_bit_errors = -1, if the error information is not available. + virtual bool sendHeardWithTXStats(const wxString& myCall, const wxString& myCallExt, + const wxString& yourCall, const wxString& rpt1, + const wxString& rpt2, unsigned char flag1, + unsigned char flag2, unsigned char flag3, + int num_dv_frames, + int num_dv_silent_frames, + int num_bit_errors) = 0; + + // The following three functions don't block waiting for a reply, they just send the data + + // Send query for a gateway/reflector, a false return implies a network error + virtual bool findGateway(const wxString& gatewayCallsign) = 0; + + // Send query for a repeater module, a false return implies a network error + virtual bool findRepeater(const wxString& repeaterCallsign) = 0; + + // Send query for a user, a false return implies a network error + virtual bool findUser(const wxString& userCallsign) = 0; + + // The following functions are for processing received messages + + // Get the waiting message type + virtual IRCDDB_RESPONSE_TYPE getMessageType() = 0; + + // Get a gateway message, as a result of IDRT_REPEATER returned from getMessageType() + // A false return implies a network error + virtual bool receiveRepeater(wxString& repeaterCallsign, wxString& gatewayCallsign, wxString& address) = 0; + + // Get a gateway message, as a result of IDRT_GATEWAY returned from getMessageType() + // A false return implies a network error + virtual bool receiveGateway(wxString& gatewayCallsign, wxString& address) = 0; + + // Get a user message, as a result of IDRT_USER returned from getMessageType() + // A false return implies a network error + virtual bool receiveUser(wxString& userCallsign, wxString& repeaterCallsign, wxString& gatewayCallsign, wxString& address) = 0; + + virtual bool receiveUser(wxString& userCallsign, wxString& repeaterCallsign, wxString& gatewayCallsign, wxString& address, + wxString& timeStamp) = 0; + + virtual void close() = 0; // Implictely kills any threads in the IRC code + +}; + +WX_DEFINE_ARRAY_PTR(CIRCDDB*, CIRCDDB_Array); +#endif + diff --git a/ircDDB/IRCDDBApp.cpp b/ircDDB/IRCDDBApp.cpp new file mode 100644 index 0000000..78b8c9f --- /dev/null +++ b/ircDDB/IRCDDBApp.cpp @@ -0,0 +1,1353 @@ +/* + +CIRCDDB - ircDDB client library in C++ + +Copyright (C) 2010-2011 Michael Dirska, DL1BFF (dl1bff@mdx.de) +Copyright (C) 2012 Jonathan Naylor, G4KLX + +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 +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +*/ + +#if defined(WIN32) + +#define WIN32_LEAN_AND_MEAN + +#include +#include + +#else + +#include +#include +#include + +#endif + + +#include "IRCDDBApp.h" +#include "IRCutils.h" + +#include +#include +#include + +class IRCDDBAppUserObject +{ + public: + + wxString nick; + wxString name; + wxString host; + bool op; + unsigned int usn; + + IRCDDBAppUserObject () + { + IRCDDBAppUserObject (wxT(""), wxT(""), wxT("")); + } + + IRCDDBAppUserObject ( const wxString& n, const wxString& nm, const wxString& h ) + { + nick = n; + name = nm; + host = h; + op = false; + usn = 0; + //usn = counter; + //counter ++; + } + + //static unsigned int counter; +}; + +//unsigned int IRCDDBAppUserObject::counter = 0; + + +WX_DECLARE_STRING_HASH_MAP( IRCDDBAppUserObject, IRCDDBAppUserMap ); + + +class IRCDDBAppRptrObject +{ + public: + + wxString arearp_cs; + wxDateTime lastChanged; + wxString zonerp_cs; + + IRCDDBAppRptrObject () + { + } + + IRCDDBAppRptrObject (wxDateTime& dt, wxString& repeaterCallsign, wxString& gatewayCallsign, wxDateTime& maxTime) + { + arearp_cs = repeaterCallsign; + lastChanged = dt; + zonerp_cs = gatewayCallsign; + + if (dt.IsLaterThan(maxTime)) + { + maxTime = dt; + } + } + + //static wxDateTime maxTime; +}; + +//wxDateTime IRCDDBAppRptrObject::maxTime((time_t) 950000000); // February 2000 + + +WX_DECLARE_STRING_HASH_MAP( IRCDDBAppRptrObject, IRCDDBAppRptrMap ); + +WX_DECLARE_STRING_HASH_MAP( wxString, IRCDDBAppModuleQRG ); +WX_DECLARE_STRING_HASH_MAP( wxString, IRCDDBAppModuleQTH ); +WX_DECLARE_STRING_HASH_MAP( wxString, IRCDDBAppModuleURL ); +WX_DECLARE_STRING_HASH_MAP( wxString, IRCDDBAppModuleWD ); + +class IRCDDBAppPrivate +{ + public: + + IRCDDBAppPrivate() + : tablePattern(wxT("^[0-9]$")), + datePattern(wxT("^20[0-9][0-9]-((1[0-2])|(0[1-9]))-((3[01])|([12][0-9])|(0[1-9]))$")), + timePattern(wxT("^((2[0-3])|([01][0-9])):[0-5][0-9]:[0-5][0-9]$")), + dbPattern(wxT("^[0-9A-Z_]{8}$")) + { + } + + IRCMessageQueue * sendQ; + + IRCDDBAppUserMap user; + wxMutex userMapMutex; + + wxString currentServer; + wxString myNick; + + wxRegEx tablePattern; + wxRegEx datePattern; + wxRegEx timePattern; + wxRegEx dbPattern; + + int state; + int timer; + int infoTimer; + + wxString updateChannel; + wxString channelTopic; + wxString bestServer; + + bool initReady; + + bool terminateThread; + + IRCDDBAppRptrMap rptrMap; + wxMutex rptrMapMutex; + + IRCMessageQueue replyQ; + + IRCDDBAppModuleQRG moduleQRG; + wxMutex moduleQRGMutex; + + IRCDDBAppModuleQTH moduleQTH; + IRCDDBAppModuleURL moduleURL; + wxMutex moduleQTHURLMutex; + + IRCDDBAppModuleWD moduleWD; + wxMutex moduleWDMutex; + + int wdTimer; +}; + + +IRCDDBApp::IRCDDBApp( const wxString& u_chan ) + : wxThread(wxTHREAD_JOINABLE), + d(new IRCDDBAppPrivate), + m_maxTime((time_t)950000000)//februray 2000 +{ + + d->sendQ = NULL; + d->initReady = false; + + userListReset(); + + d->state = 0; + d->timer = 0; + d->myNick = wxT("none"); + + d->updateChannel = u_chan; + + d->terminateThread = false; + +} + +IRCDDBApp::~IRCDDBApp() +{ + delete d->sendQ; + delete d; +} + + +void IRCDDBApp::rptrQTH(const wxString& callsign, double latitude, double longitude, const wxString& desc1, const wxString& desc2, const wxString& infoURL) +{ + wxString pos; + pos.Printf(wxT("%+09.5f %+010.5f"), latitude, longitude); + + wxString cs = callsign; + wxString d1 = desc1; + wxString d2 = desc2; + + d1.Append(wxT(' '), 20); + d2.Append(wxT(' '), 20); + + wxRegEx nonValid(wxT("[^a-zA-Z0-9 +&(),./'-]")); + nonValid.Replace(&d1, wxEmptyString); + nonValid.Replace(&d2, wxEmptyString); + + pos.Replace(wxT(","), wxT(".")); + d1.Replace(wxT(" "), wxT("_")); + d2.Replace(wxT(" "), wxT("_")); + cs.Replace(wxT(" "), wxT("_")); + + wxMutexLocker lock(d->moduleQTHURLMutex); + + d->moduleQTH[cs] = cs + wxT(" ") + pos + wxT(" ") + d1.Mid(0, 20) + wxT(" ") + d2.Mid(0, 20); + + wxLogVerbose(wxT("QTH: ") + d->moduleQTH[cs]); + + wxString url = infoURL; + + wxRegEx urlNonValid(wxT("[^[:graph:]]")); + urlNonValid.Replace(&url, wxEmptyString); + + if (!url.IsEmpty()) { + d->moduleURL[cs] = cs + wxT(" ") + url; + + wxLogVerbose(wxT("URL: ") + d->moduleURL[cs]); + } + + d->infoTimer = 5; // send info in 5 seconds +} + + +void IRCDDBApp::rptrQRG(const wxString& callsign, double txFrequency, double duplexShift, double range, double agl) +{ + wxString cs = callsign; + cs.Replace(wxT(" "), wxT("_")); + + wxString f; + f.Printf(wxT("%011.5f %+010.5f %06.2f %06.1f"), txFrequency, duplexShift, range / 1609.344, agl); + f.Replace(wxT(","), wxT(".")); + + wxMutexLocker lock(d->moduleQRGMutex); + + d->moduleQRG[cs] = cs + wxT(" ") + f; + + wxLogVerbose(wxT("QRG: ") + d->moduleQRG[cs]); + + d->infoTimer = 5; // send info in 5 seconds +} + +void IRCDDBApp::kickWatchdog(const wxString& callsign, const wxString& s) +{ + wxString text = s; + + wxRegEx nonValid(wxT("[^[:graph:]]")); + nonValid.Replace(&text, wxEmptyString); + + if (!text.IsEmpty()) { + wxString cs = callsign; + cs.Replace(wxT(" "), wxT("_")); + + wxMutexLocker lock(d->moduleWDMutex); + + d->moduleWD[cs] = cs + wxT(" ") + text; + + d->wdTimer = 60; + } +} + + +int IRCDDBApp::getConnectionState() +{ + return d->state; +} + +IRCDDB_RESPONSE_TYPE IRCDDBApp::getReplyMessageType() +{ + IRCMessage* m = d->replyQ.peekFirst(); + if (m == NULL) + return IDRT_NONE; + + wxString msgType = m->getCommand(); + + if (msgType.IsSameAs(wxT("IDRT_USER"))) + return IDRT_USER; + + if (msgType.IsSameAs(wxT("IDRT_REPEATER"))) + return IDRT_REPEATER; + + if (msgType.IsSameAs(wxT("IDRT_GATEWAY"))) + return IDRT_GATEWAY; + + wxLogError(wxT("IRCDDBApp::getMessageType: unknown msg type: %s"), msgType.c_str()); + + return IDRT_NONE; +} + + +IRCMessage* IRCDDBApp::getReplyMessage() +{ + return d->replyQ.getMessage(); +} + + + +void IRCDDBApp::startWork() +{ + d->terminateThread = false; + + Create(); + Run(); +} + +void IRCDDBApp::stopWork() +{ + d->terminateThread = true; + + Wait(); +} + +unsigned int IRCDDBApp::calculateUsn(const wxString& nick) +{ + wxString lnick = nick.BeforeLast('-'); + unsigned int maxUsn = 0; + for (int i = 1; i <= 4; i++) { + wxString ircUser = lnick + wxString::Format(wxT("-%d"), i); + + if (d->user.count(ircUser) == 1) { + IRCDDBAppUserObject obj = d->user[ircUser]; + if (obj.usn > maxUsn) + maxUsn = obj.usn; + } + } + + return maxUsn + 1; +} + +void IRCDDBApp::userJoin (const wxString& nick, const wxString& name, const wxString& host) +{ + wxMutexLocker lock(d->userMapMutex); + + wxString lnick = nick; + lnick.MakeLower(); + + IRCDDBAppUserObject u( lnick, name, host ); + u.usn = calculateUsn(lnick); + + d->user[lnick] = u; + + // wxLogVerbose(wxT("add %d: (") + u.nick + wxT(") (") + u.host + wxT(")"), d->user.size()); + + if (d->initReady) + { + int hyphenPos = nick.Find(wxT('-')); + + if ((hyphenPos >= 4) && (hyphenPos <= 6)) + { + wxString gatewayCallsign = nick.Mid(0, hyphenPos).Upper(); + + while (gatewayCallsign.Length() < 7) + { + gatewayCallsign.Append(wxT(' ')); + } + + gatewayCallsign.Append(wxT('G')); + + IRCMessage * m2 = new IRCMessage(wxT( "IDRT_GATEWAY")); + m2->addParam(gatewayCallsign); + m2->addParam(host); + d->replyQ.putMessage(m2); + } + } + + // wxLogVerbose(wxT("user %d"), u.usn ); +} + + + + +void IRCDDBApp::userLeave (const wxString& nick) +{ + wxMutexLocker lock(d->userMapMutex); + + wxString lnick = nick; + lnick.MakeLower(); + + d->user.erase(lnick); + + // wxLogVerbose(wxT("rm %d: ") + nick, d->user.size()); + + if (d->currentServer.Len() > 0) + { + if (d->user.count(d->myNick) != 1) + { + wxLogVerbose(wxT("IRCDDBApp::userLeave: could not find own nick")); + return; + } + + IRCDDBAppUserObject me = d->user[d->myNick]; + + if (me.op == false) + { + // if I am not op, then look for new server + + if (d->currentServer.IsSameAs(lnick)) + { + // currentServer = null; + d->state = 2; // choose new server + d->timer = 200; + d->initReady = false; + } + } + } +} + +void IRCDDBApp::userListReset() +{ + wxMutexLocker lock(d->userMapMutex); + + d->user.clear(); +} + +void IRCDDBApp::setCurrentNick(const wxString& nick) +{ + d->myNick = nick; + wxLogVerbose(wxT("IRCDDBApp::setCurrentNick ") + nick); +} + +void IRCDDBApp::setBestServer(const wxString& ircUser) +{ + d->bestServer = ircUser; + wxLogVerbose(wxT("IRCDDBApp::setBestServer ") + ircUser); +} + +void IRCDDBApp::setTopic(const wxString& topic) +{ + d->channelTopic = topic; +} + +bool IRCDDBApp::findServerUser() +{ + wxMutexLocker lock(d->userMapMutex); + + bool found = false; + + IRCDDBAppUserMap::iterator it; + + for( it = d->user.begin(); it != d->user.end(); ++it ) + { + IRCDDBAppUserObject u = it->second; + + if (u.nick.StartsWith(wxT("s-")) && u.op && !d->myNick.IsSameAs(u.nick) + && u.nick.IsSameAs(d->bestServer)) + { + d->currentServer = u.nick; + found = true; + break; + } + } + + if (found) + return true; + + if (d->bestServer.Len() == 8) + { + for( it = d->user.begin(); it != d->user.end(); ++it ) + { + IRCDDBAppUserObject u = it->second; + + if (u.nick.StartsWith(d->bestServer.Mid(0,7)) && u.op && + !d->myNick.IsSameAs(u.nick) ) + { + d->currentServer = u.nick; + found = true; + break; + } + } + } + + if (found) + return true; + + for( it = d->user.begin(); it != d->user.end(); ++it ) + { + IRCDDBAppUserObject u = it->second; + + if (u.nick.StartsWith(wxT("s-")) && u.op && !d->myNick.IsSameAs(u.nick)) + { + d->currentServer = u.nick; + found = true; + break; + } + } + + return found; +} + +void IRCDDBApp::userChanOp (const wxString& nick, bool op) +{ + wxMutexLocker lock(d->userMapMutex); + + wxString lnick = nick; + lnick.MakeLower(); + + if (d->user.count(lnick) == 1) + { + d->user[lnick].op = op; + } +} + + + +static const int numberOfTables = 2; + + + + + +wxString IRCDDBApp::getIPAddress(wxString& zonerp_cs) +{ + wxMutexLocker lock(d->userMapMutex); + wxString gw = zonerp_cs; + + gw.Replace(wxT("_"), wxT(" ")); + gw.MakeLower(); + + unsigned int max_usn = 0; + wxString ipAddr; + + int j; + + for (j=1; j <= 4; j++) + { + // int i = 0; + wxString ircUser = gw.Strip() + wxString::Format(wxT("-%d"), j); + + if (d->user.count(ircUser) == 1) + { + IRCDDBAppUserObject o = d->user[ ircUser ]; + + if (o.usn >= max_usn) + { + max_usn = o.usn; + ipAddr = o.host.c_str(); // make a deep copy of the string and do not use wxString reference counting! + // This is important, because the reference counting feature + // in wxString is not thread-safe. + } + // i = 1; + } + // wxLogVerbose(wxT("getIP %d (") + ircUser + wxT(") (") + ipAddr + wxT(")"), i); + + } + + return ipAddr; +} + + +bool IRCDDBApp::findGateway(const wxString& gwCall) +{ + wxString s = gwCall.Mid(0,6); + + IRCMessage * m2 = new IRCMessage(wxT( "IDRT_GATEWAY")); + m2->addParam(gwCall); + m2->addParam(getIPAddress(s)); + d->replyQ.putMessage(m2); + + return true; +} + +static void findReflector( const wxString& rptrCall, IRCDDBAppPrivate * d ) +{ + wxString zonerp_cs; + wxString ipAddr; + +#define MAXIPV4ADDR 5 + struct sockaddr_in addr[MAXIPV4ADDR]; + unsigned int numAddr = 0; + + char host_name[80]; + + wxString host = rptrCall.Mid(0,6) + wxT(".reflector.ircddb.net"); + + safeStringCopy(host_name, host.mb_str(wxConvUTF8), sizeof host_name); + + if (getAllIPV4Addresses(host_name, 0, &numAddr, addr, MAXIPV4ADDR) == 0) + { + if (numAddr > 0) + { + unsigned char * a = (unsigned char *) &addr[0].sin_addr; + + ipAddr = wxString::Format(wxT("%d.%d.%d.%d"), a[0], a[1], a[2], a[3]); + zonerp_cs = rptrCall; + zonerp_cs.SetChar(7, wxT('G')); + } + } + + + IRCMessage * m2 = new IRCMessage(wxT("IDRT_REPEATER")); + m2->addParam(rptrCall); + m2->addParam(zonerp_cs); + m2->addParam(ipAddr); + d->replyQ.putMessage(m2); +} + +bool IRCDDBApp::findRepeater(const wxString& rptrCall) +{ + + if (rptrCall.StartsWith(wxT("XRF")) || rptrCall.StartsWith(wxT("REF"))) + { + findReflector(rptrCall, d); + return true; + } + + wxString arearp_cs = rptrCall; + arearp_cs.Replace(wxT(" "), wxT("_")); + + wxString zonerp_cs; + + wxMutexLocker lock(d->rptrMapMutex); + + wxString s = wxT("NONE"); + + if (d->rptrMap.count(arearp_cs) == 1) + { + IRCDDBAppRptrObject o = d->rptrMap[arearp_cs]; + zonerp_cs = o.zonerp_cs; + zonerp_cs.Replace(wxT("_"), wxT(" ")); + zonerp_cs.SetChar(7, wxT('G')); + s = o.zonerp_cs; + } + + IRCMessage * m2 = new IRCMessage(wxT("IDRT_REPEATER")); + m2->addParam(rptrCall); + m2->addParam(zonerp_cs); + m2->addParam(getIPAddress(s)); + d->replyQ.putMessage(m2); + + return true; +} + + +bool IRCDDBApp::sendHeard(const wxString& myCall, const wxString& myCallExt, + const wxString& yourCall, const wxString& rpt1, + const wxString& rpt2, unsigned char flag1, + unsigned char flag2, unsigned char flag3, + const wxString& destination, const wxString& tx_msg, + const wxString& tx_stats ) +{ + + wxString my = myCall; + wxString myext = myCallExt; + wxString ur = yourCall; + wxString r1 = rpt1; + wxString r2 = rpt2; + wxString dest = destination; + + wxRegEx nonValid(wxT("[^A-Z0-9/]")); + wxString underScore = wxT("_"); + + nonValid.Replace(&my, underScore); + nonValid.Replace(&myext, underScore); + nonValid.Replace(&ur, underScore); + nonValid.Replace(&r1, underScore); + nonValid.Replace(&r2, underScore); + nonValid.Replace(&dest, underScore); + + bool statsMsg = (tx_stats.Len() > 0); + + wxString srv = d->currentServer; + IRCMessageQueue * q = getSendQ(); + + if ((srv.Len() > 0) && (d->state >= 6) && (q != NULL)) + { + wxString cmd = wxT("UPDATE "); + + cmd.Append( getCurrentTime() ); + + cmd.Append(wxT(" ")); + + cmd.Append(my); + cmd.Append(wxT(" ")); + cmd.Append(r1); + cmd.Append(wxT(" ")); + if (!statsMsg) + { + cmd.Append(wxT("0 ")); + } + cmd.Append(r2); + cmd.Append(wxT(" ")); + cmd.Append(ur); + cmd.Append(wxT(" ")); + + wxString flags = wxString::Format(wxT("%02X %02X %02X"), flag1, flag2, flag3); + + cmd.Append(flags); + cmd.Append(wxT(" ")); + cmd.Append(myext); + + if (statsMsg) + { + cmd.Append(wxT(" # ")); + cmd.Append(tx_stats); + } + else + { + cmd.Append(wxT(" 00 ")); + cmd.Append(dest); + + if (tx_msg.Len() == 20) + { + cmd.Append(wxT(" ")); + cmd.Append(tx_msg); + } + } + + + IRCMessage * m = new IRCMessage(srv, cmd); + + q->putMessage(m); + return true; + } + else + { + return false; + } +} + +bool IRCDDBApp::findUser(const wxString& usrCall) +{ + wxString srv = d->currentServer; + IRCMessageQueue * q = getSendQ(); + + if ((srv.Len() > 0) && (d->state >= 6) && (q != NULL)) + { + wxString usr = usrCall; + + usr.Replace(wxT(" "), wxT("_")); + + IRCMessage * m = new IRCMessage(srv, + wxT("FIND ") + usr ); + + q->putMessage(m); + } + else + { + IRCMessage * m2 = new IRCMessage(wxT("IDRT_USER")); + m2->addParam(usrCall); + m2->addParam(wxT("")); + m2->addParam(wxT("")); + m2->addParam(wxT("")); + m2->addParam(wxT("")); + d->replyQ.putMessage(m2); + } + + return true; +} + + +void IRCDDBApp::msgChannel (IRCMessage * m) +{ + if (m->getPrefixNick().StartsWith(wxT("s-")) && (m->numParams >= 2)) // server msg + { + doUpdate(m->params[1]); + } +} + + +void IRCDDBApp::doNotFound ( wxString& msg, wxString& retval ) +{ + int tableID = 0; + + wxStringTokenizer tkz(msg); + + if (!tkz.HasMoreTokens()) + { + return; // no text in message + } + + wxString tk = tkz.GetNextToken(); + + + if (d->tablePattern.Matches(tk)) + { + long i; + + if (tk.ToLong(&i)) + { + tableID = i; + if ((tableID < 0) || (tableID >= numberOfTables)) + { + wxLogVerbose(wxT("invalid table ID %d"), tableID); + return; + } + } + else + { + return; // not a valid number + } + + if (!tkz.HasMoreTokens()) + { + return; // received nothing but the tableID + } + + tk = tkz.GetNextToken(); + } + + if (tableID == 0) + { + if (! d->dbPattern.Matches(tk)) + { + return; // no valid key + } + + retval = tk; + } +} + +void IRCDDBApp::doUpdate ( wxString& msg ) +{ + int tableID = 0; + + wxStringTokenizer tkz(msg); + + if (!tkz.HasMoreTokens()) + { + return; // no text in message + } + + wxString tk = tkz.GetNextToken(); + + + if (d->tablePattern.Matches(tk)) + { + long i; + + if (tk.ToLong(&i)) + { + tableID = i; + if ((tableID < 0) || (tableID >= numberOfTables)) + { + wxLogVerbose(wxT("invalid table ID %d"), tableID); + return; + } + } + else + { + return; // not a valid number + } + + if (!tkz.HasMoreTokens()) + { + return; // received nothing but the tableID + } + + tk = tkz.GetNextToken(); + } + + if (d->datePattern.Matches(tk)) + { + if (!tkz.HasMoreTokens()) + { + return; // nothing after date string + } + + wxString timeToken = tkz.GetNextToken(); + + if (! d->timePattern.Matches(timeToken)) + { + return; // no time string after date string + } + + wxDateTime dt; + +#if wxMAJOR_VERSION == 3 + if (dt.ParseFormat(tk + wxT(" ") + timeToken, wxT("%Y-%m-%d %H:%M:%S")) == false) +#else + if (dt.ParseFormat(tk + wxT(" ") + timeToken, wxT("%Y-%m-%d %H:%M:%S")) == NULL) +#endif + { + return; // date+time parsing failed + } + + if ((tableID == 0) || (tableID == 1)) + { + if (!tkz.HasMoreTokens()) + { + return; // nothing after time string + } + + wxString key = tkz.GetNextToken(); + + if (! d->dbPattern.Matches(key)) + { + return; // no valid key + } + + if (!tkz.HasMoreTokens()) + { + return; // nothing after time string + } + + wxString value = tkz.GetNextToken(); + + if (! d->dbPattern.Matches(value)) + { + return; // no valid key + } + + //wxLogVerbose(wxT("TABLE %d ") + key + wxT(" ") + value, tableID ); + + + if (tableID == 1) + { + wxMutexLocker lock(d->rptrMapMutex); + + IRCDDBAppRptrObject newRptr(dt, key, value, m_maxTime); + + d->rptrMap[key] = newRptr; + + if (d->initReady) + { + wxString arearp_cs = key; + wxString zonerp_cs = value; + + arearp_cs.Replace(wxT("_"), wxT(" ")); + zonerp_cs.Replace(wxT("_"), wxT(" ")); + zonerp_cs.SetChar(7, wxT('G')); + + IRCMessage * m2 = new IRCMessage(wxT("IDRT_REPEATER")); + m2->addParam(arearp_cs); + m2->addParam(zonerp_cs); + m2->addParam(getIPAddress(value)); + d->replyQ.putMessage(m2); + } + } + else if ((tableID == 0) && d->initReady) + { + wxMutexLocker lock(d->rptrMapMutex); + + wxString userCallsign = key; + wxString arearp_cs = value; + wxString zonerp_cs; + wxString ip_addr; + + userCallsign.Replace(wxT("_"), wxT(" ")); + arearp_cs.Replace(wxT("_"), wxT(" ")); + + if (d->rptrMap.count(value) == 1) + { + IRCDDBAppRptrObject o = d->rptrMap[value]; + zonerp_cs = o.zonerp_cs; + zonerp_cs.Replace(wxT("_"), wxT(" ")); + zonerp_cs.SetChar(7, wxT('G')); + + ip_addr = getIPAddress(o.zonerp_cs); + } + + IRCMessage * m2 = new IRCMessage(wxT("IDRT_USER")); + m2->addParam(userCallsign); + m2->addParam(arearp_cs); + m2->addParam(zonerp_cs); + m2->addParam(ip_addr); + m2->addParam(tk + wxT(" ") + timeToken); + d->replyQ.putMessage(m2); + + } + + + } + } + +} + + +static wxString getTableIDString( int tableID, bool spaceBeforeNumber ) +{ + if (tableID == 0) + { + return wxT(""); + } + else if ((tableID > 0) && (tableID < numberOfTables)) + { + if (spaceBeforeNumber) + { + return wxString::Format(wxT(" %d"),tableID); + } + else + { + return wxString::Format(wxT("%d "),tableID); + } + } + else + { + return wxT(" TABLE_ID_OUT_OF_RANGE "); + } +} + + +void IRCDDBApp::msgQuery (IRCMessage * m) +{ + + if (m->getPrefixNick().StartsWith(wxT("s-")) && (m->numParams >= 2)) // server msg + { + wxString msg = m->params[1]; + wxStringTokenizer tkz(msg); + + if (!tkz.HasMoreTokens()) + { + return; // no text in message + } + + wxString cmd = tkz.GetNextToken(); + + if (cmd.IsSameAs(wxT("UPDATE"))) + { + wxString restOfLine = tkz.GetString(); + doUpdate(restOfLine); + } + else if (cmd.IsSameAs(wxT("LIST_END"))) + { + if (d->state == 5) // if in sendlist processing state + { + d->state = 3; // get next table + } + } + else if (cmd.IsSameAs(wxT("LIST_MORE"))) + { + if (d->state == 5) // if in sendlist processing state + { + d->state = 4; // send next SENDLIST + } + } + else if (cmd.IsSameAs(wxT("NOT_FOUND"))) + { + wxString callsign; + wxString restOfLine = tkz.GetString(); + doNotFound(restOfLine, callsign); + + if (callsign.Len() > 0) + { + callsign.Replace(wxT("_"), wxT(" ")); + + IRCMessage * m2 = new IRCMessage(wxT("IDRT_USER")); + m2->addParam(callsign); + m2->addParam(wxT("")); + m2->addParam(wxT("")); + m2->addParam(wxT("")); + m2->addParam(wxT("")); + d->replyQ.putMessage(m2); + } + } + } +} + + +void IRCDDBApp::setSendQ( IRCMessageQueue * s ) +{ + d->sendQ = s; +} + +IRCMessageQueue * IRCDDBApp::getSendQ() +{ + return d->sendQ; +} + + +wxString IRCDDBApp::getLastEntryTime(int tableID) +{ + + if (tableID == 1) + { + wxString max = /*IRCDDBAppRptrObject::maxTime*/m_maxTime.Format( wxT("%Y-%m-%d %H:%M:%S") ); + return max; + } + + return wxT("DBERROR"); +} + + +static bool needsDatabaseUpdate( int tableID ) +{ + return (tableID == 1); +} + + +wxThread::ExitCode IRCDDBApp::Entry() +{ + + int sendlistTableID = 0; + + while (!d->terminateThread) + { + + if (d->timer > 0) + { + d->timer --; + } + + switch(d->state) + { + case 0: // wait for network to start + + if (getSendQ() != NULL) + { + d->state = 1; + } + break; + + case 1: + // connect to db + d->state = 2; + d->timer = 200; + break; + + case 2: // choose server + wxLogVerbose(wxT("IRCDDBApp: state=2 choose new 's-'-user")); + if (getSendQ() == NULL) + { + d->state = 10; + } + else + { + if (findServerUser()) + { + sendlistTableID = numberOfTables; + + d->state = 3; // next: send "SENDLIST" + } + else if (d->timer == 0) + { + d->state = 10; + IRCMessage * m = new IRCMessage(wxT("QUIT")); + + m->addParam(wxT("no op user with 's-' found.")); + + IRCMessageQueue * q = getSendQ(); + if (q != NULL) + { + q->putMessage(m); + } + } + } + break; + + case 3: + if (getSendQ() == NULL) + { + d->state = 10; // disconnect DB + } + else + { + sendlistTableID --; + if (sendlistTableID < 0) + { + d->state = 6; // end of sendlist + } + else + { + wxLogVerbose(wxT("IRCDDBApp: state=3 tableID=%d"), sendlistTableID); + d->state = 4; // send "SENDLIST" + d->timer = 900; // 15 minutes max for update + } + } + break; + + case 4: + if (getSendQ() == NULL) + { + d->state = 10; // disconnect DB + } + else + { + if (needsDatabaseUpdate(sendlistTableID)) + { + IRCMessage * m = new IRCMessage(d->currentServer, + wxT("SENDLIST") + getTableIDString(sendlistTableID, true) + + wxT(" ") + getLastEntryTime(sendlistTableID) ); + + IRCMessageQueue * q = getSendQ(); + if (q != NULL) + { + q->putMessage(m); + } + + d->state = 5; // wait for answers + } + else + { + d->state = 3; // don't send SENDLIST for this table, go to next table + } + } + break; + + case 5: // sendlist processing + if (getSendQ() == NULL) + { + d->state = 10; // disconnect DB + } + else if (d->timer == 0) + { + d->state = 10; // disconnect DB + IRCMessage * m = new IRCMessage(wxT("QUIT")); + + m->addParam(wxT("timeout SENDLIST")); + + IRCMessageQueue * q = getSendQ(); + if (q != NULL) + { + q->putMessage(m); + } + + } + break; + + case 6: + if (getSendQ() == NULL) + { + d->state = 10; // disconnect DB + } + else + { + wxLogVerbose(wxT( "IRCDDBApp: state=6 initialization completed")); + + d->infoTimer = 2; + + d->initReady = true; + d->state = 7; + } + break; + + + case 7: // standby state after initialization + if (getSendQ() == NULL) + { + d->state = 10; // disconnect DB + } + + if (d->infoTimer > 0) + { + d->infoTimer --; + + if (d->infoTimer == 0) + { + d->moduleQTHURLMutex.Lock(); + + for (IRCDDBAppModuleQTH::iterator it = d->moduleQTH.begin(); it != d->moduleQTH.end(); ++it) + { + wxString value = it->second; + IRCMessage* m = new IRCMessage(d->currentServer, wxT("IRCDDB RPTRQTH: ") + value); + + IRCMessageQueue* q = getSendQ(); + if (q != NULL) + { + q->putMessage(m); + } + } + + d->moduleQTH.clear(); + + for (IRCDDBAppModuleURL::iterator it = d->moduleURL.begin(); it != d->moduleURL.end(); ++it) + { + wxString value = it->second; + IRCMessage* m = new IRCMessage(d->currentServer, wxT("IRCDDB RPTRURL: ") + value); + + IRCMessageQueue* q = getSendQ(); + if (q != NULL) + { + q->putMessage(m); + } + } + + d->moduleURL.clear(); + + d->moduleQTHURLMutex.Unlock(); + + d->moduleQRGMutex.Lock(); + + for (IRCDDBAppModuleQRG::iterator it = d->moduleQRG.begin(); it != d->moduleQRG.end(); ++it) + { + wxString value = it->second; + IRCMessage* m = new IRCMessage(d->currentServer, wxT("IRCDDB RPTRQRG: ") + value); + + IRCMessageQueue* q = getSendQ(); + if (q != NULL) + { + q->putMessage(m); + } + } + + d->moduleQRG.clear(); + + d->moduleQRGMutex.Unlock(); + + } + } + + if (d->wdTimer > 0) + { + d->wdTimer --; + + if (d->wdTimer == 0) + { + d->moduleWDMutex.Lock(); + + for (IRCDDBAppModuleWD::iterator it = d->moduleWD.begin(); it != d->moduleWD.end(); ++it) + { + wxString value = it->second; + IRCMessage* m = new IRCMessage(d->currentServer, wxT("IRCDDB RPTRSW: ") + value); + + IRCMessageQueue* q = getSendQ(); + if (q != NULL) + { + q->putMessage(m); + } + } + + d->moduleWD.clear(); + + d->moduleWDMutex.Unlock(); + } + } + break; + + case 10: + // disconnect db + d->state = 0; + d->timer = 0; + d->initReady = false; + break; + + } + + wxThread::Sleep(1000); + + + + + } // while + + return 0; +} // Entry() diff --git a/ircDDB/IRCDDBApp.h b/ircDDB/IRCDDBApp.h new file mode 100644 index 0000000..d4f4812 --- /dev/null +++ b/ircDDB/IRCDDBApp.h @@ -0,0 +1,103 @@ +/* + +CIRCDDB - ircDDB client library in C++ + +Copyright (C) 2010-2011 Michael Dirska, DL1BFF (dl1bff@mdx.de) +Copyright (C) 2012 Jonathan Naylor, G4KLX + +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 +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +*/ + +#if !defined(_IRCDDBAPP_H) +#define _IRCDDBAPP_H + + +#include "IRCDDB.h" +#include "IRCApplication.h" + +#include +#include + +class IRCDDBAppPrivate; + +class IRCDDBApp : public IRCApplication, wxThread +{ + public: + IRCDDBApp(const wxString& update_channel); + + virtual ~IRCDDBApp(); + + virtual void userJoin (const wxString& nick, const wxString& name, const wxString& host); + + virtual void userLeave (const wxString& nick); + + virtual void userChanOp (const wxString& nick, bool op); + virtual void userListReset(); + + virtual void msgChannel (IRCMessage * m); + virtual void msgQuery (IRCMessage * m); + + virtual void setCurrentNick(const wxString& nick); + virtual void setTopic(const wxString& topic); + + virtual void setBestServer(const wxString& ircUser); + + virtual void setSendQ( IRCMessageQueue * s ); + virtual IRCMessageQueue * getSendQ (); + + void startWork(); + void stopWork(); + + IRCDDB_RESPONSE_TYPE getReplyMessageType(); + + IRCMessage * getReplyMessage(); + + bool findUser ( const wxString& s ); + bool findRepeater ( const wxString& s ); + bool findGateway ( const wxString& s ); + + bool sendHeard(const wxString& myCall, const wxString& myCallExt, + const wxString& yourCall, const wxString& rpt1, + const wxString& rpt2, unsigned char flag1, + unsigned char flag2, unsigned char flag3, + const wxString& destination, const wxString& tx_msg, + const wxString& tx_stats); + + int getConnectionState(); + + void rptrQRG( const wxString& callsign, double txFrequency, double duplexShift, + double range, double agl ); + + void rptrQTH( const wxString& callsign, double latitude, double longitude, const wxString& desc1, + const wxString& desc2, const wxString& infoURL ); + + void kickWatchdog( const wxString& callsign, const wxString& wdInfo ); + + protected: + virtual wxThread::ExitCode Entry(); + + private: + void doUpdate ( wxString& msg ); + void doNotFound ( wxString& msg, wxString& retval ); + wxString getIPAddress( wxString& zonerp_cs ); + bool findServerUser(); + unsigned int calculateUsn(const wxString& nick); + wxString getLastEntryTime(int tableID); + IRCDDBAppPrivate * d; + wxDateTime m_maxTime; +}; + + +#endif diff --git a/ircDDB/IRCDDBClient.cpp b/ircDDB/IRCDDBClient.cpp new file mode 100644 index 0000000..359a73a --- /dev/null +++ b/ircDDB/IRCDDBClient.cpp @@ -0,0 +1,487 @@ +/* + +CIRCDDBClient - ircDDB client library in C++ + +Copyright (C) 2010-2011 Michael Dirska, DL1BFF (dl1bff@mdx.de) +Copyright (C) 2011,2012 Jonathan Naylor, G4KLX + +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 +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +*/ + + +#include "IRCDDBClient.h" + +#include "IRCClient.h" +#include "IRCDDBApp.h" + +#include + + +struct CIRCDDBClientPrivate +{ + IRCClient * client; + IRCDDBApp * app; +}; + + +CIRCDDBClient::CIRCDDBClient(const wxString& hostName, unsigned int port, + const wxString& callsign, const wxString& password, + const wxString& versionInfo, const wxString& localAddr ) : d( new CIRCDDBClientPrivate ) + +{ + wxString update_channel = wxT("#dstar"); + + d->app = new IRCDDBApp(update_channel); + + d->client = new IRCClient( d->app, update_channel, hostName, port, callsign, + password, versionInfo, localAddr ); +} + +CIRCDDBClient::~CIRCDDBClient() +{ + delete d->client; + delete d->app; + delete d; +} + + + // A false return implies a network error, or unable to log in +bool CIRCDDBClient::open() +{ + wxLogVerbose(wxT("start")); + + d->client->startWork(); + d->app->startWork(); + + return true; +} + + +int CIRCDDBClient::getConnectionState() +{ + return d->app->getConnectionState(); +} + + +void CIRCDDBClient::rptrQTH(const wxString& callsign, double latitude, double longitude, const wxString& desc1, const wxString& desc2, const wxString& infoURL) +{ + d->app->rptrQTH(callsign, latitude, longitude, desc1, desc2, infoURL); +} + + +void CIRCDDBClient::rptrQRG(const wxString& callsign, double txFrequency, double duplexShift, double range, double agl) +{ + d->app->rptrQRG(callsign, txFrequency, duplexShift, range, agl); +} + + +void CIRCDDBClient::kickWatchdog(const wxString& callsign, const wxString& wdInfo) +{ + d->app->kickWatchdog(callsign, wdInfo); +} + + + +// Send heard data, a false return implies a network error +bool CIRCDDBClient::sendHeard( const wxString& myCall, const wxString& myCallExt, + const wxString& yourCall, const wxString& rpt1, + const wxString& rpt2, unsigned char flag1, + unsigned char flag2, unsigned char flag3 ) +{ + if (myCall.Len() != 8) + { + wxLogVerbose(wxT("CIRCDDBClient::sendHeard:myCall: len != 8")); + return false; + } + + if (myCallExt.Len() != 4) + { + wxLogVerbose(wxT("CIRCDDBClient::sendHeard:myCallExt: len != 4")); + return false; + } + + if (yourCall.Len() != 8) + { + wxLogVerbose(wxT("CIRCDDBClient::sendHeard:yourCall: len != 8")); + return false; + } + + if (rpt1.Len() != 8) + { + wxLogVerbose(wxT("CIRCDDBClient::sendHeard:rpt1: len != 8")); + return false; + } + + if (rpt2.Len() != 8) + { + wxLogVerbose(wxT("CIRCDDBClient::sendHeard:rpt2: len != 8")); + return false; + } + + return d->app->sendHeard( myCall, myCallExt, yourCall, rpt1, rpt2, flag1, flag2, flag3, + wxT(" "), wxT(""), wxT("")); +} + + +// Send heard data, a false return implies a network error +bool CIRCDDBClient::sendHeardWithTXMsg( const wxString& myCall, const wxString& myCallExt, + const wxString& yourCall, const wxString& rpt1, + const wxString& rpt2, unsigned char flag1, + unsigned char flag2, unsigned char flag3, + const wxString& network_destination, + const wxString& tx_message ) +{ + if (myCall.Len() != 8) + { + wxLogVerbose(wxT("CIRCDDBClient::sendHeard:myCall: len != 8")); + return false; + } + + if (myCallExt.Len() != 4) + { + wxLogVerbose(wxT("CIRCDDBClient::sendHeard:myCallExt: len != 4")); + return false; + } + + if (yourCall.Len() != 8) + { + wxLogVerbose(wxT("CIRCDDBClient::sendHeard:yourCall: len != 8")); + return false; + } + + if (rpt1.Len() != 8) + { + wxLogVerbose(wxT("CIRCDDBClient::sendHeard:rpt1: len != 8")); + return false; + } + + if (rpt2.Len() != 8) + { + wxLogVerbose(wxT("CIRCDDBClient::sendHeard:rpt2: len != 8")); + return false; + } + + wxString dest = network_destination; + + if (dest.Len() == 0) + { + dest = wxT(" "); + } + + if (dest.Len() != 8) + { + wxLogVerbose(wxT("CIRCDDBClient::sendHeard:network_destination: len != 8")); + return false; + } + + wxString msg; + + if (tx_message.Len() == 20) + { + unsigned int i; + for (i=0; i < tx_message.Len(); i++) + { + wxChar ch = tx_message.GetChar(i); + + if ((ch > 32) && (ch < 127)) + { + msg.Append(ch); + } + else + { + msg.Append(wxT('_')); + } + } + } + + return d->app->sendHeard( myCall, myCallExt, yourCall, rpt1, rpt2, flag1, flag2, flag3, + dest, msg, wxT("")); +} + + + +bool CIRCDDBClient::sendHeardWithTXStats( const wxString& myCall, const wxString& myCallExt, + const wxString& yourCall, const wxString& rpt1, + const wxString& rpt2, unsigned char flag1, + unsigned char flag2, unsigned char flag3, + int num_dv_frames, + int num_dv_silent_frames, + int num_bit_errors ) +{ + if ((num_dv_frames <= 0) || (num_dv_frames > 65535)) + { + wxLogVerbose(wxT("CIRCDDBClient::sendHeard:num_dv_frames not in range 1-65535")); + return false; + } + + if (num_dv_silent_frames > num_dv_frames) + { + wxLogVerbose(wxT("CIRCDDBClient::sendHeard:num_dv_silent_frames > num_dv_frames")); + return false; + } + + if (num_bit_errors > (4*num_dv_frames)) // max 4 bit errors per frame + { + wxLogVerbose(wxT("CIRCDDBClient::sendHeard:num_bit_errors > (4*num_dv_frames)")); + return false; + } + + if (myCall.Len() != 8) + { + wxLogVerbose(wxT("CIRCDDBClient::sendHeard:myCall: len != 8")); + return false; + } + + if (myCallExt.Len() != 4) + { + wxLogVerbose(wxT("CIRCDDBClient::sendHeard:myCallExt: len != 4")); + return false; + } + + if (yourCall.Len() != 8) + { + wxLogVerbose(wxT("CIRCDDBClient::sendHeard:yourCall: len != 8")); + return false; + } + + if (rpt1.Len() != 8) + { + wxLogVerbose(wxT("CIRCDDBClient::sendHeard:rpt1: len != 8")); + return false; + } + + if (rpt2.Len() != 8) + { + wxLogVerbose(wxT("CIRCDDBClient::sendHeard:rpt2: len != 8")); + return false; + } + + wxString stats = wxString::Format(wxT("%04x"), num_dv_frames); + + if (num_dv_silent_frames >= 0) + { + wxString s = wxString::Format(wxT("%02x"), (num_dv_silent_frames * 100) / num_dv_frames); + stats.Append(s); + + if (num_bit_errors >= 0) + { + s = wxString::Format(wxT("%02x"), (num_bit_errors * 125) / (num_dv_frames * 3)); + stats.Append(s); + } + else + { + stats.Append(wxT("__")); + } + } + else + { + stats.Append(wxT("____")); + } + + stats.Append(wxT("____________")); // stats string should have 20 chars + + return d->app->sendHeard( myCall, myCallExt, yourCall, rpt1, rpt2, flag1, flag2, flag3, + wxT(" "), wxT(""), stats); +} + + + +// Send query for a gateway/reflector, a false return implies a network error +bool CIRCDDBClient::findGateway(const wxString& gatewayCallsign) +{ + if (gatewayCallsign.Len() != 8) + { + wxLogVerbose(wxT("CIRCDDBClient::findGateway: len != 8")); + return false; + } + + return d->app->findGateway( gatewayCallsign.Upper()); +} + + +bool CIRCDDBClient::findRepeater(const wxString& repeaterCallsign) +{ + if (repeaterCallsign.Len() != 8) + { + wxLogVerbose(wxT("CIRCDDBClient::findRepeater: len != 8")); + return false; + } + + return d->app->findRepeater( repeaterCallsign.Upper()); +} + +// Send query for a user, a false return implies a network error +bool CIRCDDBClient::findUser(const wxString& userCallsign) +{ + if (userCallsign.Len() != 8) + { + wxLogVerbose(wxT("CIRCDDBClient::findUser: len != 8")); + return false; + } + + return d->app->findUser( userCallsign.Upper()); +} + +// The following functions are for processing received messages + +// Get the waiting message type +IRCDDB_RESPONSE_TYPE CIRCDDBClient::getMessageType() +{ + return d->app->getReplyMessageType(); +} + +// Get a gateway message, as a result of IDRT_REPEATER returned from getMessageType() +// A false return implies a network error +bool CIRCDDBClient::receiveRepeater(wxString& repeaterCallsign, wxString& gatewayCallsign, wxString& address) +{ + IRCDDB_RESPONSE_TYPE rt = d->app->getReplyMessageType(); + + if (rt != IDRT_REPEATER) + { + wxLogError(wxT("CIRCDDBClient::receiveRepeater: unexpected response type")); + return false; + } + + IRCMessage * m = d->app->getReplyMessage(); + + if (m == NULL) + { + wxLogError(wxT("CIRCDDBClient::receiveRepeater: no message")); + return false; + } + + if (!m->getCommand().IsSameAs(wxT("IDRT_REPEATER"))) + { + wxLogError(wxT("CIRCDDBClient::receiveRepeater: wrong message type")); + delete m; + return false; + } + + if (m->getParamCount() != 3) + { + wxLogError(wxT("CIRCDDBClient::receiveRepeater: unexpected number of message parameters")); + delete m; + return false; + } + + repeaterCallsign = m->getParam(0); + gatewayCallsign = m->getParam(1); + address = m->getParam(2); + + delete m; + + return true; +} + +// Get a gateway message, as a result of IDRT_GATEWAY returned from getMessageType() +// A false return implies a network error +bool CIRCDDBClient::receiveGateway(wxString& gatewayCallsign, wxString& address) +{ + IRCDDB_RESPONSE_TYPE rt = d->app->getReplyMessageType(); + + if (rt != IDRT_GATEWAY) + { + wxLogError(wxT("CIRCDDBClient::receiveGateway: unexpected response type")); + return false; + } + + IRCMessage * m = d->app->getReplyMessage(); + + if (m == NULL) + { + wxLogError(wxT("CIRCDDBClient::receiveGateway: no message")); + return false; + } + + if (!m->getCommand().IsSameAs(wxT("IDRT_GATEWAY"))) + { + wxLogError(wxT("CIRCDDBClient::receiveGateway: wrong message type")); + delete m; + return false; + } + + if (m->getParamCount() != 2) + { + wxLogError(wxT("CIRCDDBClient::receiveGateway: unexpected number of message parameters")); + delete m; + return false; + } + + gatewayCallsign = m->getParam(0); + address = m->getParam(1); + + delete m; + + return true; +} + +// Get a user message, as a result of IDRT_USER returned from getMessageType() +// A false return implies a network error +bool CIRCDDBClient::receiveUser(wxString& userCallsign, wxString& repeaterCallsign, wxString& gatewayCallsign, wxString& address) +{ + wxString dummy; + return receiveUser(userCallsign, repeaterCallsign, gatewayCallsign, address, dummy); +} + +bool CIRCDDBClient::receiveUser(wxString& userCallsign, wxString& repeaterCallsign, wxString& gatewayCallsign, wxString& address, + wxString& timeStamp) +{ + IRCDDB_RESPONSE_TYPE rt = d->app->getReplyMessageType(); + + if (rt != IDRT_USER) + { + wxLogError(wxT("CIRCDDBClient::receiveUser: unexpected response type")); + return false; + } + + IRCMessage * m = d->app->getReplyMessage(); + + if (m == NULL) + { + wxLogError(wxT("CIRCDDBClient::receiveUser: no message")); + return false; + } + + if (!m->getCommand().IsSameAs(wxT("IDRT_USER"))) + { + wxLogError(wxT("CIRCDDBClient::receiveUser: wrong message type")); + delete m; + return false; + } + + if (m->getParamCount() != 5) + { + wxLogError(wxT("CIRCDDBClient::receiveUser: unexpected number of message parameters")); + delete m; + return false; + } + + userCallsign = m->getParam(0); + repeaterCallsign = m->getParam(1); + gatewayCallsign = m->getParam(2); + address = m->getParam(3); + timeStamp = m->getParam(4); + + delete m; + + return true; +} + +void CIRCDDBClient::close() // Implictely kills any threads in the IRC code +{ + d->client -> stopWork(); + d->app -> stopWork(); +} + diff --git a/ircDDB/IRCDDBClient.h b/ircDDB/IRCDDBClient.h new file mode 100644 index 0000000..f8c8650 --- /dev/null +++ b/ircDDB/IRCDDBClient.h @@ -0,0 +1,162 @@ +/* + +CIRCDDB - ircDDB client library in C++ + +Copyright (C) 2010-2011 Michael Dirska, DL1BFF (dl1bff@mdx.de) +Copyright (C) 2011,2012 Jonathan Naylor, G4KLX + +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 +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +*/ + + +#if !defined(_IRCDDBCLIENT_H) +#define _IRCDDBCLIENT_H + +#include "IRCDDB.h" +#include + +struct CIRCDDBPrivate; + +class CIRCDDBClient : public CIRCDDB{ +public: + CIRCDDBClient(const wxString& hostName, unsigned int port, const wxString& callsign, const wxString& password, + const wxString& versionInfo, const wxString& localAddr = wxEmptyString ); + ~CIRCDDBClient(); + + // A false return implies a network error, or unable to log in + bool open(); + + + // rptrQTH can be called multiple times if necessary + // callsign The callsign of the repeater + // latitude WGS84 position of antenna in degrees, positive value -> NORTH + // longitude WGS84 position of antenna in degrees, positive value -> EAST + // desc1, desc2 20-character description of QTH + // infoURL URL of a web page with information about the repeater + + void rptrQTH( const wxString& callsign, double latitude, double longitude, const wxString& desc1, + const wxString& desc2, const wxString& infoURL ); + + + + // rptrQRG can be called multiple times if necessary + // callsign callsign of the repeater + // txFrequency repeater TX frequency in MHz + // duplexShift duplex shift in MHz (positive or negative value): RX_freq = txFrequency + duplexShift + // range range of the repeater in meters (meters = miles * 1609.344) + // agl height of the antenna above ground in meters (meters = feet * 0.3048) + + void rptrQRG( const wxString& callsign, double txFrequency, double duplexShift, double range, double agl ); + + + // If you call this method once, watchdog messages will be sent to the + // to the ircDDB network every 15 minutes. Invoke this method every 1-2 minutes to indicate + // that the gateway is working properly. After activating the watchdog, a red LED will be displayed + // on the ircDDB web page if this method is not called within a period of about 30 minutes. + // The string wdInfo should contain information about the source of the alive messages, e.g., + // version of the RF decoding software. For example, the ircDDB java software sets this + // to "rpm_ircddbmhd-x.z-z". The string wdInfo must contain at least one non-space character. + + void kickWatchdog(const wxString& callsign, const wxString& wdInfo); + + + + // get internal network status + int getConnectionState(); + // one of these values is returned: + // 0 = not (yet) connected to the IRC server + // 1-6 = a new connection was established, download of repeater info etc. is + // in progress + // 7 = the ircDDB connection is fully operational + // 10 = some network error occured, next state is "0" (new connection attempt) + + // Send heard data, a false return implies a network error + bool sendHeard(const wxString& myCall, const wxString& myCallExt, + const wxString& yourCall, const wxString& rpt1, + const wxString& rpt2, unsigned char flag1, + unsigned char flag2, unsigned char flag3 ); + + + // same as sendHeard with two new fields: + // network_destination: empty string or 8-char call sign of the repeater + // or reflector, where this transmission is relayed to. + // tx_message: 20-char TX message or empty string, if the user did not + // send a TX message + bool sendHeardWithTXMsg(const wxString& myCall, const wxString& myCallExt, + const wxString& yourCall, const wxString& rpt1, + const wxString& rpt2, unsigned char flag1, + unsigned char flag2, unsigned char flag3, + const wxString& network_destination, + const wxString& tx_message ); + + // this method should be called at the end of a transmission + // num_dv_frames: number of DV frames sent out (96 bit frames, 20ms) + // num_dv_silent_frames: number of DV silence frames sent out in the + // last transmission, or -1 if the information is not available + // num_bit_errors: number of bit errors of the received data. This should + // be the derived from the first Golay block of the voice data. This + // error correction code only looks at 24 bits of the 96 bit frame. + // So, the overall bit error rate is calculated like this: + // BER = num_bit_errors / (num_dv_frames * 24) + // Set num_bit_errors = -1, if the error information is not available. + bool sendHeardWithTXStats(const wxString& myCall, const wxString& myCallExt, + const wxString& yourCall, const wxString& rpt1, + const wxString& rpt2, unsigned char flag1, + unsigned char flag2, unsigned char flag3, + int num_dv_frames, + int num_dv_silent_frames, + int num_bit_errors ); + + // The following three functions don't block waiting for a reply, they just send the data + + // Send query for a gateway/reflector, a false return implies a network error + bool findGateway(const wxString& gatewayCallsign); + + // Send query for a repeater module, a false return implies a network error + bool findRepeater(const wxString& repeaterCallsign); + + // Send query for a user, a false return implies a network error + bool findUser(const wxString& userCallsign); + + // The following functions are for processing received messages + + // Get the waiting message type + IRCDDB_RESPONSE_TYPE getMessageType(); + + // Get a gateway message, as a result of IDRT_REPEATER returned from getMessageType() + // A false return implies a network error + bool receiveRepeater(wxString& repeaterCallsign, wxString& gatewayCallsign, wxString& address); + + // Get a gateway message, as a result of IDRT_GATEWAY returned from getMessageType() + // A false return implies a network error + bool receiveGateway(wxString& gatewayCallsign, wxString& address); + + // Get a user message, as a result of IDRT_USER returned from getMessageType() + // A false return implies a network error + bool receiveUser(wxString& userCallsign, wxString& repeaterCallsign, wxString& gatewayCallsign, wxString& address); + + bool receiveUser(wxString& userCallsign, wxString& repeaterCallsign, wxString& gatewayCallsign, wxString& address, + wxString& timeStamp ); + + void close(); // Implictely kills any threads in the IRC code + + +private: + struct CIRCDDBClientPrivate * const d; + +}; + +#endif // _IRCDDB_H + diff --git a/ircDDB/IRCDDBMultiClient.cpp b/ircDDB/IRCDDBMultiClient.cpp new file mode 100644 index 0000000..f7feb11 --- /dev/null +++ b/ircDDB/IRCDDBMultiClient.cpp @@ -0,0 +1,354 @@ +/* + +CIRCDDBClient - ircDDB client library in C++ + +Copyright (C) 2010-2011 Michael Dirska, DL1BFF (dl1bff@mdx.de) +Copyright (C) 2011,2012 Jonathan Naylor, G4KLX + +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 +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +*/ + +#include "IRCDDBMultiClient.h" +#include + +CIRCDDBMultiClient::CIRCDDBMultiClient(const CIRCDDB_Array& clients) : +m_clients(), +m_queriesLock(), +m_responseQueueLock() +{ + for (unsigned int i = 0; i < clients.Count(); i++) { + if (clients[i] != NULL) + m_clients.Add(clients[i]); + } +} + +CIRCDDBMultiClient::~CIRCDDBMultiClient() +{ + for (unsigned int i = 0; i < m_clients.Count(); i++) { + delete m_clients[i]; + } + + while (m_responseQueue.Count() > 0) { + delete m_responseQueue[0]; + m_responseQueue.RemoveAt(0); + } + + for (CIRCDDBMultiClientQuery_HashMap::iterator it = m_userQueries.begin(); it != m_userQueries.end(); it++) + delete it->second; + m_userQueries.clear(); + + for (CIRCDDBMultiClientQuery_HashMap::iterator it = m_repeaterQueries.begin(); it != m_repeaterQueries.end(); it++) + delete it->second; + m_repeaterQueries.clear(); + + for (CIRCDDBMultiClientQuery_HashMap::iterator it = m_gatewayQueries.begin(); it != m_gatewayQueries.end(); it++) + delete it->second; + m_gatewayQueries.clear(); +} + +bool CIRCDDBMultiClient::open() +{ + bool result = true; + + for (unsigned int i = 0; i < m_clients.Count(); i++) { + result = m_clients[i]->open() && result; + } + + if (!result) close(); + + return result; +} + +void CIRCDDBMultiClient::rptrQTH(const wxString & callsign, double latitude, double longitude, const wxString & desc1, const wxString & desc2, const wxString & infoURL) +{ + for (unsigned int i = 0; i < m_clients.Count(); i++) { + m_clients[i]->rptrQTH(callsign, latitude, longitude, desc1, desc2, infoURL); + } +} + +void CIRCDDBMultiClient::rptrQRG(const wxString & callsign, double txFrequency, double duplexShift, double range, double agl) +{ + for (unsigned int i = 0; i < m_clients.Count(); i++) { + m_clients[i]->rptrQRG(callsign, txFrequency, duplexShift, range, agl); + } +} + +void CIRCDDBMultiClient::kickWatchdog(const wxString & callsign, const wxString & wdInfo) +{ + for (unsigned int i = 0; i < m_clients.Count(); i++) { + m_clients[i]->kickWatchdog(callsign, wdInfo); + } +} + +int CIRCDDBMultiClient::getConnectionState() +{ + for (unsigned int i = 0; i < m_clients.Count(); i++) { + int state = m_clients[i]->getConnectionState(); + if (state != 7) + return state; + } + + return 7; +} + +bool CIRCDDBMultiClient::sendHeard(const wxString & myCall, const wxString & myCallExt, const wxString & yourCall, const wxString & rpt1, const wxString & rpt2, unsigned char flag1, unsigned char flag2, unsigned char flag3) +{ + bool result = true; + + for (unsigned int i = 0; i < m_clients.Count(); i++) { + result = m_clients[i]->sendHeard(myCall, myCallExt, yourCall, rpt1, rpt2, flag1, flag2, flag3) && result; + } + + return result; +} + +bool CIRCDDBMultiClient::sendHeardWithTXMsg(const wxString & myCall, const wxString & myCallExt, const wxString & yourCall, const wxString & rpt1, const wxString & rpt2, unsigned char flag1, unsigned char flag2, unsigned char flag3, const wxString & network_destination, const wxString & tx_message) +{ + bool result = true; + + for (unsigned int i = 0; i < m_clients.Count(); i++) { + result = m_clients[i]->sendHeardWithTXMsg(myCall, myCallExt, yourCall, rpt1, rpt2, flag1, flag2, flag3, network_destination, tx_message) && result; + } + + return result; +} + +bool CIRCDDBMultiClient::sendHeardWithTXStats(const wxString & myCall, const wxString & myCallExt, const wxString & yourCall, const wxString & rpt1, const wxString & rpt2, unsigned char flag1, unsigned char flag2, unsigned char flag3, int num_dv_frames, int num_dv_silent_frames, int num_bit_errors) +{ + bool result = true; + + for (unsigned int i = 0; i < m_clients.Count(); i++) { + result = m_clients[i]->sendHeardWithTXStats(myCall, myCallExt, yourCall, rpt1, rpt2, flag1, flag2, flag3, num_dv_frames, num_dv_silent_frames, num_bit_errors) && result; + } + + return result; +} + +bool CIRCDDBMultiClient::findGateway(const wxString & gatewayCallsign) +{ + pushQuery(IDRT_GATEWAY, gatewayCallsign, new CIRCDDBMultiClientQuery(wxEmptyString, wxEmptyString, gatewayCallsign, wxEmptyString, wxEmptyString, IDRT_GATEWAY)); + bool result = true; + for (unsigned int i = 0; i < m_clients.Count(); i++) { + result = m_clients[i]->findGateway(gatewayCallsign) && result; + } + + return result; +} + +bool CIRCDDBMultiClient::findRepeater(const wxString & repeaterCallsign) +{ + pushQuery(IDRT_REPEATER, repeaterCallsign, new CIRCDDBMultiClientQuery(wxEmptyString, repeaterCallsign, wxEmptyString, wxEmptyString, wxEmptyString, IDRT_REPEATER)); + bool result = true; + for (unsigned int i = 0; i < m_clients.Count(); i++) { + result = m_clients[i]->findRepeater(repeaterCallsign) && result; + } + + return result; +} + +bool CIRCDDBMultiClient::findUser(const wxString & userCallsign) +{ + pushQuery(IDRT_USER, userCallsign, new CIRCDDBMultiClientQuery(userCallsign, wxEmptyString, wxEmptyString, wxEmptyString, wxEmptyString, IDRT_USER)); + bool result = true; + for (unsigned int i = 0; i < m_clients.Count(); i++) { + result = m_clients[i]->findUser(userCallsign) && result; + } + + return result; +} + +IRCDDB_RESPONSE_TYPE CIRCDDBMultiClient::getMessageType() +{ + //procees the inner clients at each call + for (unsigned int i = 0; i < m_clients.Count(); i++) { + wxString user = wxEmptyString, repeater = wxEmptyString, gateway = wxEmptyString, address = wxEmptyString, timestamp = wxEmptyString, key = wxEmptyString; + IRCDDB_RESPONSE_TYPE type = m_clients[i]->getMessageType(); + + switch (type) { + case IDRT_USER: { + if (!m_clients[i]->receiveUser(user, repeater, gateway, address, timestamp)) + type = IDRT_NONE; + key = user; + //wxLogMessage(wxT("After receive user : %s %s %s %s %s client idx %d"), user, repeater, gateway, address, timestamp, i); + break; + } + case IDRT_GATEWAY: { + if (!m_clients[i]->receiveGateway(gateway, address)) + type = IDRT_NONE; + key = gateway; + break; + } + case IDRT_REPEATER: { + if (!m_clients[i]->receiveRepeater(repeater, gateway, address)) + type = IDRT_NONE; + key = repeater; + break; + } + case IDRT_NONE: { + default: + break; + } + } + + if (type != IDRT_NONE) + { + wxMutexLocker locker(m_queriesLock); + bool canAddToQueue = false; + bool wasQuery = false; + CIRCDDBMultiClientQuery * item = popQuery(type, key); + if (item != NULL) {//is this a response to a query we've sent ? + item->Update(user, repeater, gateway, address, timestamp);//update item (if needed) + canAddToQueue = (item->incrementResponseCount() >= m_clients.Count()); //did all the clients respond or did we have an answer ? + wasQuery = true; + } + else { + item = new CIRCDDBMultiClientQuery(user, repeater, gateway, address, timestamp, type); + canAddToQueue = true; + } + + //wxLogMessage(wxT("After process : %s %s %s %s %s canAdd %d wasQuery %d"), user, repeater, gateway, address, timestamp, (int)canAddToQueue, (int)wasQuery); + if (canAddToQueue) { + wxMutexLocker responselocker(m_responseQueueLock); + m_responseQueue.Add(item); + } + else if (wasQuery) + pushQuery(type, key, item); + } + } + + { //this is an artificial scope, I'm not sure if compiler optimization would move instantiation of locker or not hence this + //finally send the first item we queued + wxMutexLocker locker(m_responseQueueLock); + if (m_responseQueue.Count() == 0) + return IDRT_NONE; + + return m_responseQueue[0]->getType(); + } +} + +bool CIRCDDBMultiClient::receiveRepeater(wxString & repeaterCallsign, wxString & gatewayCallsign, wxString & address) +{ + CIRCDDBMultiClientQuery * item = checkAndGetNextResponse(IDRT_REPEATER, wxT("CIRCDDBMultiClient::receiveRepeater: unexpected response type")); + if (item == NULL) + return false; + + repeaterCallsign = item->getRepeater(); + gatewayCallsign = item->getGateway(); + address = item->getAddress(); + delete item; + return true; +} + +bool CIRCDDBMultiClient::receiveGateway(wxString & gatewayCallsign, wxString & address) +{ + CIRCDDBMultiClientQuery * item = checkAndGetNextResponse(IDRT_GATEWAY, wxT("CIRCDDBMultiClient::receiveGateway: unexpected response type")); + if (item == NULL) + return false; + + gatewayCallsign = item->getGateway(); + address = item->getAddress(); + delete item; + return true; +} + +bool CIRCDDBMultiClient::receiveUser(wxString & userCallsign, wxString & repeaterCallsign, wxString & gatewayCallsign, wxString & address) +{ + wxString dummy; + return receiveUser(userCallsign, repeaterCallsign, gatewayCallsign, address, dummy); +} + +bool CIRCDDBMultiClient::receiveUser(wxString & userCallsign, wxString & repeaterCallsign, wxString & gatewayCallsign, wxString & address, wxString & timeStamp) +{ + CIRCDDBMultiClientQuery * item = checkAndGetNextResponse(IDRT_USER, wxT("CIRCDDBMultiClient::receiveUser: unexpected response type")); + if (item == NULL) { + //wxLogMessage(wxT("CIRCDDBMultiClient::receiveUser NO USER IN QUEUE")); + return false; + } + + //wxLogMessage(wxT("CIRCDDBMultiClient::receiveUser : %s"), item->toString()); + + userCallsign = item->getUser().Clone(); + repeaterCallsign = item->getRepeater().Clone(); + gatewayCallsign = item->getGateway().Clone(); + address = item->getAddress().Clone(); + timeStamp = item->getTimestamp().Clone(); + delete item; + return true; +} + +void CIRCDDBMultiClient::close() +{ + for (unsigned int i = 0; i < m_clients.Count(); i++) { + m_clients[i]->close(); + } +} + +CIRCDDBMultiClientQuery * CIRCDDBMultiClient::checkAndGetNextResponse(IRCDDB_RESPONSE_TYPE expectedType, wxString errorMessage) +{ + CIRCDDBMultiClientQuery * item = NULL; + wxMutexLocker locker(m_responseQueueLock); + + if (m_responseQueue.Count() == 0 || m_responseQueue[0]->getType() != expectedType) { + wxLogError(errorMessage); + } + else { + item = m_responseQueue[0]; + m_responseQueue.RemoveAt(0); + } + + return item; +} + +void CIRCDDBMultiClient::pushQuery(IRCDDB_RESPONSE_TYPE type, const wxString& key, CIRCDDBMultiClientQuery * query) +{ + CIRCDDBMultiClientQuery_HashMap * queries = getQueriesHashMap(type); + wxMutexLocker locker(m_queriesLock); + if (queries != NULL && (*queries)[key] == NULL) + (*queries)[key] = query; + else + delete query; +} + + +CIRCDDBMultiClientQuery * CIRCDDBMultiClient::popQuery(IRCDDB_RESPONSE_TYPE type, const wxString & key) +{ + CIRCDDBMultiClientQuery_HashMap * queries = getQueriesHashMap(type); + wxMutexLocker locker(m_queriesLock); + + CIRCDDBMultiClientQuery * item = NULL; + + if (queries != NULL && (item = (*queries)[key]) != NULL) + queries->erase(key); + + return item; +} + +CIRCDDBMultiClientQuery_HashMap * CIRCDDBMultiClient::getQueriesHashMap(IRCDDB_RESPONSE_TYPE type) +{ + switch (type) + { + case IDRT_USER: + return &m_userQueries; + case IDRT_GATEWAY: + return &m_gatewayQueries; + case IDRT_REPEATER: + return &m_repeaterQueries; + case IDRT_NONE: + default: + return NULL; + } +} + + diff --git a/ircDDB/IRCDDBMultiClient.h b/ircDDB/IRCDDBMultiClient.h new file mode 100644 index 0000000..42f81ae --- /dev/null +++ b/ircDDB/IRCDDBMultiClient.h @@ -0,0 +1,172 @@ +/* + +CIRCDDB - ircDDB client library in C++ + +Copyright (C) 2010-2011 Michael Dirska, DL1BFF (dl1bff@mdx.de) +Copyright (C) 2011,2012 Jonathan Naylor, G4KLX + +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 +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +*/ + + +#if !defined(_IRCDDBMULTICLIENT_H) +#define _IRCDDBMULTICLIENT_H + +#include "IRCDDB.h" +#include +#include + +//Small data container to keep track of queries with sent to the inner clients +class CIRCDDBMultiClientQuery +{ +public: + CIRCDDBMultiClientQuery(const wxString& user, + const wxString& repeater, + const wxString& gateway, + const wxString& address, + const wxString& timestamp, + IRCDDB_RESPONSE_TYPE type) : + m_user(user.Clone()), + m_repeater(repeater.Clone()), + m_gateway(gateway.Clone()), + m_address(address.Clone()), + m_timestamp(timestamp.Clone()), + m_type(type), + m_responseCount(0) + { + + } + + wxString getUser() const + { + return m_user; + } + + wxString getRepeater() const + { + return m_repeater; + } + + wxString getGateway() const + { + return m_gateway; + } + + wxString getAddress() const + { + return m_address; + } + + wxString getTimestamp() const + { + return m_timestamp; + } + + unsigned int getResponseCount() + { + return m_responseCount; + } + + unsigned int incrementResponseCount() + { + ++m_responseCount; + //wxLogMessage(wxT("Resp Count : %s %d"), toString(), m_responseCount); + return m_responseCount; + } + + /* + Updates the entry, but only if the timestamp is newer. if an address was already specified it is kept. + */ + void Update(const wxString& user, const wxString& repeater, const wxString& gateway, const wxString& address, const wxString& timestamp) + { + //wxLogMessage(wxT("Before : %s"), toString()); + if (timestamp.IsEmpty() || timestamp.Cmp(m_timestamp) >= 0) { + m_user = user.Clone(); + m_repeater = repeater.Clone(); + m_gateway = gateway.Clone(); + m_timestamp = timestamp.Clone(); + + if(m_address.IsEmpty() && !address.IsEmpty()) + m_address = address.Clone(); + } + //wxLogMessage(wxT("After : %s"), toString()); + } + + IRCDDB_RESPONSE_TYPE getType() + { + return m_type; + } + + wxString toString() + { + return wxString::Format(wxT("%s %s %s %s %s"), m_user, m_repeater, m_gateway, m_address, m_timestamp); + } + +private: + wxString m_user; + wxString m_repeater; + wxString m_gateway; + wxString m_address; + wxString m_timestamp; + IRCDDB_RESPONSE_TYPE m_type; + unsigned int m_responseCount; +}; + +WX_DECLARE_STRING_HASH_MAP(CIRCDDBMultiClientQuery*, CIRCDDBMultiClientQuery_HashMap); +WX_DEFINE_ARRAY_PTR(CIRCDDBMultiClientQuery*, CIRCDDBMultiClientQuery_Array); + +class CIRCDDBMultiClient : public CIRCDDB +{ +public: + CIRCDDBMultiClient(const CIRCDDB_Array& clients); + ~CIRCDDBMultiClient(); + + // Inherited via CIRCDDB + virtual bool open(); + virtual void rptrQTH(const wxString & callsign, double latitude, double longitude, const wxString & desc1, const wxString & desc2, const wxString & infoURL); + virtual void rptrQRG(const wxString & callsign, double txFrequency, double duplexShift, double range, double agl); + virtual void kickWatchdog(const wxString & callsign, const wxString & wdInfo); + virtual int getConnectionState() ; + virtual bool sendHeard(const wxString & myCall, const wxString & myCallExt, const wxString & yourCall, const wxString & rpt1, const wxString & rpt2, unsigned char flag1, unsigned char flag2, unsigned char flag3); + virtual bool sendHeardWithTXMsg(const wxString & myCall, const wxString & myCallExt, const wxString & yourCall, const wxString & rpt1, const wxString & rpt2, unsigned char flag1, unsigned char flag2, unsigned char flag3, const wxString & network_destination, const wxString & tx_message); + virtual bool sendHeardWithTXStats(const wxString & myCall, const wxString & myCallExt, const wxString & yourCall, const wxString & rpt1, const wxString & rpt2, unsigned char flag1, unsigned char flag2, unsigned char flag3, int num_dv_frames, int num_dv_silent_frames, int num_bit_errors); + virtual bool findGateway(const wxString & gatewayCallsign); + virtual bool findRepeater(const wxString & repeaterCallsign); + virtual bool findUser(const wxString & userCallsign); + virtual IRCDDB_RESPONSE_TYPE getMessageType(); + virtual bool receiveRepeater(wxString & repeaterCallsign, wxString & gatewayCallsign, wxString & address); + virtual bool receiveGateway(wxString & gatewayCallsign, wxString & address); + virtual bool receiveUser(wxString & userCallsign, wxString & repeaterCallsign, wxString & gatewayCallsign, wxString & address); + virtual bool receiveUser(wxString & userCallsign, wxString & repeaterCallsign, wxString & gatewayCallsign, wxString & address, wxString & timeStamp); + virtual void close(); + + // + +private : + CIRCDDB_Array m_clients; + wxMutex m_queriesLock, m_responseQueueLock; + + CIRCDDBMultiClientQuery_HashMap m_userQueries; + CIRCDDBMultiClientQuery_HashMap m_repeaterQueries; + CIRCDDBMultiClientQuery_HashMap m_gatewayQueries; + CIRCDDBMultiClientQuery_Array m_responseQueue; + + CIRCDDBMultiClientQuery * checkAndGetNextResponse(IRCDDB_RESPONSE_TYPE expectedType, wxString errorMessage); + void pushQuery(IRCDDB_RESPONSE_TYPE type, const wxString& key, CIRCDDBMultiClientQuery * query); + CIRCDDBMultiClientQuery * popQuery(IRCDDB_RESPONSE_TYPE type, const wxString& key); + CIRCDDBMultiClientQuery_HashMap * getQueriesHashMap(IRCDDB_RESPONSE_TYPE type); +}; +#endif + diff --git a/ircDDB/IRCMessage.cpp b/ircDDB/IRCMessage.cpp new file mode 100644 index 0000000..b8a9ebd --- /dev/null +++ b/ircDDB/IRCMessage.cpp @@ -0,0 +1,177 @@ +/* + +CIRCDDB - ircDDB client library in C++ + +Copyright (C) 2010-2011 Michael Dirska, DL1BFF (dl1bff@mdx.de) + +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 +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +*/ + +#include "IRCMessage.h" + + + +IRCMessage::IRCMessage () +{ + numParams = 0; + prefixParsed = false; +} + +IRCMessage::IRCMessage ( const wxString& toNick, const wxString& msg ) +{ + command = wxT("PRIVMSG"); + numParams = 2; + params.Add( toNick ); + params.Add( msg ); + prefixParsed = false; +} + +IRCMessage::IRCMessage ( const wxString& cmd ) +{ + command = cmd; + numParams = 0; + prefixParsed = false; +} + +IRCMessage::~IRCMessage() +{ +} + + +void IRCMessage::addParam( const wxString& p ) +{ + params.Add( p ); + numParams = params.GetCount(); +} + +int IRCMessage::getParamCount() +{ + return params.GetCount(); +} + +wxString IRCMessage::getParam( int pos ) +{ + return params[pos]; +} + +wxString IRCMessage::getCommand() +{ + return command; +} + + +void IRCMessage::parsePrefix() +{ + unsigned int i; + + for (i=0; i < 3; i++) + { + prefixComponents.Add(wxT("")); + } + + int state = 0; + + for (i=0; i < prefix.Len(); i++) + { + wxChar c = prefix.GetChar(i); + + switch (c) + { + case wxT('!'): + state = 1; // next is name + break; + + case wxT('@'): + state = 2; // next is host + break; + + default: + prefixComponents[state].Append(c); + break; + } + } + + prefixParsed = true; +} + +wxString& IRCMessage::getPrefixNick() +{ + if (!prefixParsed) + { + parsePrefix(); + } + + return prefixComponents[0]; +} + +wxString& IRCMessage::getPrefixName() +{ + if (!prefixParsed) + { + parsePrefix(); + } + + return prefixComponents[1]; +} + +wxString& IRCMessage::getPrefixHost() +{ + if (!prefixParsed) + { + parsePrefix(); + } + + return prefixComponents[2]; +} + +void IRCMessage::composeMessage ( wxString& output ) +{ +#if defined(DEBUG_IRC) + wxString d = wxT("T [") + prefix + wxT("] [") + command + wxT("]"); + for (int i=0; i < numParams; i++) + { + d.Append(wxT(" [") + params[i] + wxT("]") ); + } + d.Replace(wxT("%"), wxT("%%"), true); + d.Replace(wxT("\\"), wxT("\\\\"), true); + wxLogVerbose(d); +#endif + + wxString o; + + if (prefix.Len() > 0) + { + o = wxT(":") + prefix + wxT(" "); + } + + o.Append(command); + + for (int i=0; i < numParams; i++) + { + if (i == (numParams - 1)) + { + o.Append(wxT(" :") + params[i]); + } + else + { + o.Append(wxT(" ") + params[i]); + } + } + + o.Append(wxT("\r\n")); + + output = o; +} + diff --git a/ircDDB/IRCMessage.h b/ircDDB/IRCMessage.h new file mode 100644 index 0000000..25c33af --- /dev/null +++ b/ircDDB/IRCMessage.h @@ -0,0 +1,71 @@ +/* + +CIRCDDB - ircDDB client library in C++ + +Copyright (C) 2010 Michael Dirska, DL1BFF (dl1bff@mdx.de) + +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 +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +*/ + +#if !defined(_IRC_MESSAGE_H) +#define _IRC_MESSAGE_H + +#include + + +class IRCMessage +{ + public: + + IRCMessage(); + + IRCMessage( const wxString& toNick, const wxString& msg ); + + IRCMessage( const wxString& command ); + + ~IRCMessage(); + + + + wxString prefix; + wxString command; + wxArrayString params; + + int numParams; + + wxString& getPrefixNick(); + wxString& getPrefixName(); + wxString& getPrefixHost(); + + void composeMessage ( wxString& output ); + + void addParam( const wxString& p ); + + wxString getCommand(); + + wxString getParam( int pos ); + + int getParamCount(); + + private: + + void parsePrefix(); + + wxArrayString prefixComponents; + bool prefixParsed; + +}; + +#endif diff --git a/ircDDB/IRCMessageQueue.cpp b/ircDDB/IRCMessageQueue.cpp new file mode 100644 index 0000000..b42d798 --- /dev/null +++ b/ircDDB/IRCMessageQueue.cpp @@ -0,0 +1,137 @@ +/* + +CIRCDDB - ircDDB client library in C++ + +Copyright (C) 2010 Michael Dirska, DL1BFF (dl1bff@mdx.de) + +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 +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +*/ + +#include "IRCMessageQueue.h" + + +IRCMessageQueue::IRCMessageQueue() +{ + eof = false; + first = NULL; + last = NULL; + +} + +IRCMessageQueue::~IRCMessageQueue() +{ + while (messageAvailable()) + { + IRCMessage * m = getMessage(); + + delete m; + } +} + + +bool IRCMessageQueue::isEOF() +{ + return eof; +} + + +void IRCMessageQueue::signalEOF() +{ + eof = true; +} + + +bool IRCMessageQueue::messageAvailable() +{ + wxMutexLocker lock(accessMutex); + + return (first != NULL); +} + + +IRCMessage * IRCMessageQueue::peekFirst() +{ + wxMutexLocker lock(accessMutex); + + IRCMessageQueueItem * k = first; + + if ( k == NULL ) + { + return NULL; + } + + return k->msg; +} + + +IRCMessage * IRCMessageQueue::getMessage() +{ + wxMutexLocker lock(accessMutex); + + IRCMessageQueueItem * k; + + if (first == NULL) + { + return NULL; + } + + k = first; + + first = k -> next; + + if (k -> next == NULL) + { + last = NULL; + } + else + { + k -> next -> prev = NULL; + } + + + IRCMessage * msg = k -> msg; + + delete k; + + return msg; +} + + +void IRCMessageQueue::putMessage( IRCMessage * m ) +{ + wxMutexLocker lock(accessMutex); + + // wxLogVerbose(wxT("IRCMessageQueue::putMessage")); + + IRCMessageQueueItem * k = new IRCMessageQueueItem(m); + + k -> prev = last; + k -> next = NULL; + + if (last == NULL) + { + first = k; + } + else + { + last -> next = k; + } + + last = k; +} + + + + diff --git a/ircDDB/IRCMessageQueue.h b/ircDDB/IRCMessageQueue.h new file mode 100644 index 0000000..b405a40 --- /dev/null +++ b/ircDDB/IRCMessageQueue.h @@ -0,0 +1,79 @@ +/* + +CIRCDDB - ircDDB client library in C++ + +Copyright (C) 2010 Michael Dirska, DL1BFF (dl1bff@mdx.de) + +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 +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +*/ + +#if !defined(_IRCMESSAGEQUEUE_H) +#define _IRCMESSAGEQUEUE_H + +#include + +#include "IRCMessage.h" + + +class IRCMessageQueueItem +{ + public: + IRCMessageQueueItem( IRCMessage * m ) + { + msg = m; + } + + ~IRCMessageQueueItem() + { + } + + IRCMessage * msg; + + IRCMessageQueueItem * prev; + IRCMessageQueueItem * next; +}; + + +class IRCMessageQueue +{ + public: + IRCMessageQueue(); + + ~IRCMessageQueue(); + + bool isEOF(); + + void signalEOF(); + + bool messageAvailable(); + + IRCMessage * getMessage(); + + IRCMessage * peekFirst(); + + void putMessage ( IRCMessage * m ); + + private: + + bool eof; + + IRCMessageQueueItem * first; + IRCMessageQueueItem * last; + + wxMutex accessMutex; + +}; + +#endif diff --git a/ircDDB/IRCProtocol.cpp b/ircDDB/IRCProtocol.cpp new file mode 100644 index 0000000..122b687 --- /dev/null +++ b/ircDDB/IRCProtocol.cpp @@ -0,0 +1,447 @@ +/* + +CIRCDDB - ircDDB client library in C++ + +Copyright (C) 2010-2011 Michael Dirska, DL1BFF (dl1bff@mdx.de) + +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 +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +*/ + + +#include "IRCProtocol.h" + +#include + +#define CIRCDDB_VERSION "1.2.4" + +IRCProtocol::IRCProtocol ( IRCApplication * app, + const wxString& callsign, const wxString& password, const wxString& channel, + const wxString& versionInfo ) +{ + this -> password = password; + this -> channel = channel; + this -> app = app; + + this->versionInfo = wxT("CIRCDDB:"); + this->versionInfo.Append(wxT(CIRCDDB_VERSION)); + + if (versionInfo.Len() > 0) + { + this->versionInfo.Append(wxT(" ")); + this->versionInfo.Append(versionInfo); + } + + + int hyphenPos = callsign.find(wxT('-')); + + if (hyphenPos == wxNOT_FOUND) + { + wxString n; + + n = callsign + wxT("-1"); + nicks.Add(n); + n = callsign + wxT("-2"); + nicks.Add(n); + n = callsign + wxT("-3"); + nicks.Add(n); + n = callsign + wxT("-4"); + nicks.Add(n); + } + else + { + nicks.Add(callsign); + } + + name = callsign; + + pingTimer = 60; // 30 seconds + state = 0; + timer = 0; + + + chooseNewNick(); +} + +IRCProtocol::~IRCProtocol() +{ +} + +void IRCProtocol::chooseNewNick() +{ + int r = rand() % nicks.GetCount(); + + currentNick = nicks[r]; +} + +void IRCProtocol::setNetworkReady( bool b ) +{ + if (b == true) + { + if (state != 0) + { + wxLogError(wxT("IRCProtocol::setNetworkReady: unexpected state")); + } + + state = 1; + chooseNewNick(); + } + else + { + state = 0; + } +} + + +bool IRCProtocol::processQueues ( IRCMessageQueue * recvQ, IRCMessageQueue * sendQ ) +{ + if (timer > 0) + { + timer --; + } + + while (recvQ->messageAvailable()) + { + IRCMessage * m = recvQ -> getMessage(); + +#if defined(DEBUG_IRC) + wxString d = wxT("R [") + m->prefix + wxT("] [") + m->command + wxT("]"); + for (int i=0; i < m->numParams; i++) + { + d.Append(wxT(" [") + m->params[i] + wxT("]") ); + } + d.Replace(wxT("%"), wxT("%%"), true); + d.Replace(wxT("\\"), wxT("\\\\"), true); + wxLogVerbose(d); +#endif + + if (m->command.IsSameAs(wxT("004"))) + { + if (state == 4) + { + if (m->params.GetCount() > 1) + { + wxRegEx serverNamePattern(wxT("^grp[1-9]s[1-9].ircDDB$")); + + if (serverNamePattern.Matches( m->params[1] )) + { + app->setBestServer(wxT("s-") + m->params[1].Mid(0,6)); + } + } + state = 5; // next: JOIN + app->setCurrentNick(currentNick); + } + } + else if (m->command.IsSameAs(wxT("PING"))) + { + IRCMessage * m2 = new IRCMessage(); + m2->command = wxT("PONG"); + if (m->params.GetCount() > 0) + { + m2->numParams = 1; + m2->params.Add( m->params[0] ); + } + sendQ -> putMessage(m2); + } + else if (m->command.IsSameAs(wxT("JOIN"))) + { + if ((m->numParams >= 1) && m->params[0].IsSameAs(channel)) + { + if (m->getPrefixNick().IsSameAs(currentNick) && (state == 6)) + { + if (debugChannel.Len() > 0) + { + state = 7; // next: join debug_channel + } + else + { + state = 10; // next: WHO * + } + } + else if (app != NULL) + { + app->userJoin( m->getPrefixNick(), m->getPrefixName(), m->getPrefixHost()); + } + } + + if ((m->numParams >= 1) && m->params[0].IsSameAs(debugChannel)) + { + if (m->getPrefixNick().IsSameAs(currentNick) && (state == 8)) + { + state = 10; // next: WHO * + } + } + } + else if (m->command.IsSameAs(wxT("PONG"))) + { + if (state == 12) + { + timer = pingTimer; + state = 11; + } + } + else if (m->command.IsSameAs(wxT("PART"))) + { + if ((m->numParams >= 1) && m->params[0].IsSameAs(channel)) + { + if (app != NULL) + { + app->userLeave( m->getPrefixNick() ); + } + } + } + else if (m->command.IsSameAs(wxT("KICK"))) + { + if ((m->numParams >= 2) && m->params[0].IsSameAs(channel)) + { + if (m->params[1].IsSameAs(currentNick)) + { + // i was kicked!! + delete m; + return false; + } + else if (app != NULL) + { + app->userLeave( m->params[1] ); + } + } + } + else if (m->command.IsSameAs(wxT("QUIT"))) + { + if (app != NULL) + { + app->userLeave( m->getPrefixNick() ); + } + } + else if (m->command.IsSameAs(wxT("MODE"))) + { + if ((m->numParams >= 3) && m->params[0].IsSameAs(channel)) + { + if (app != NULL) + { + size_t i; + wxString mode = m->params[1]; + + for (i = 1; (i < mode.Len()) && ((size_t) m->numParams >= (i+2)); i++) + { + if ( mode[i] == wxT('o') ) + { + if ( mode[0] == wxT('+') ) + { + app->userChanOp(m->params[i+1], true); + } + else if ( mode[0] == wxT('-') ) + { + app->userChanOp(m->params[i+1], false); + } + } + } // for + } + } + } + else if (m->command.IsSameAs(wxT("PRIVMSG"))) + { + if ((m->numParams == 2) && (app != NULL)) + { + if (m->params[0].IsSameAs(channel)) + { + app->msgChannel(m); + } + else if (m->params[0].IsSameAs(currentNick)) + { + app->msgQuery(m); + } + } + } + else if (m->command.IsSameAs(wxT("352"))) // WHO list + { + if ((m->numParams >= 7) && m->params[0].IsSameAs(currentNick) + && m->params[1].IsSameAs(channel)) + { + if (app != NULL) + { + app->userJoin( m->params[5], m->params[2], m->params[3]); + app->userChanOp ( m->params[5], m->params[6].IsSameAs(wxT("H@"))); + } + } + } + else if (m->command.IsSameAs(wxT("433"))) // nick collision + { + if (state == 2) + { + state = 3; // nick collision, choose new nick + timer = 10; // wait 5 seconds.. + } + } + else if (m->command.IsSameAs(wxT("332")) || + m->command.IsSameAs(wxT("TOPIC"))) // topic + { + if ((m->numParams == 2) && (app != NULL) && + m->params[0].IsSameAs(channel) ) + { + app->setTopic(m->params[1]); + } + } + + delete m; + } + + IRCMessage * m; + + switch (state) + { + case 1: + m = new IRCMessage(); + m->command = wxT("PASS"); + m->numParams = 1; + m->params.Add(password); + sendQ->putMessage(m); + + m = new IRCMessage(); + m->command = wxT("NICK"); + m->numParams = 1; + m->params.Add(currentNick); + sendQ->putMessage(m); + + timer = 10; // wait for possible nick collision message + state = 2; + break; + + case 2: + if (timer == 0) + { + m = new IRCMessage(); + m->command = wxT("USER"); + m->numParams = 4; + m->params.Add(name); + m->params.Add(wxT("0")); + m->params.Add(wxT("*")); + m->params.Add(versionInfo); + sendQ->putMessage(m); + + timer = 30; + state = 4; // wait for login message + } + break; + + case 3: + if (timer == 0) + { + chooseNewNick(); + m = new IRCMessage(); + m->command = wxT("NICK"); + m->numParams = 1; + m->params.Add(currentNick); + sendQ->putMessage(m); + + timer = 10; // wait for possible nick collision message + state = 2; + } + break; + + case 4: + if (timer == 0) + { + // no login message received -> disconnect + return false; + } + break; + + case 5: + m = new IRCMessage(); + m->command = wxT("JOIN"); + m->numParams = 1; + m->params.Add(channel); + sendQ->putMessage(m); + + timer = 30; + state = 6; // wait for join message + break; + + case 6: + if (timer == 0) + { + // no join message received -> disconnect + return false; + } + break; + + case 7: + if (debugChannel.Len() == 0) + { + return false; // this state cannot be processed if there is no debug_channel + } + + m = new IRCMessage(); + m->command = wxT("JOIN"); + m->numParams = 1; + m->params.Add(debugChannel); + sendQ->putMessage(m); + + timer = 30; + state = 8; // wait for join message + break; + + case 8: + if (timer == 0) + { + // no join message received -> disconnect + return false; + } + break; + + case 10: + m = new IRCMessage(); + m->command = wxT("WHO"); + m->numParams = 2; + m->params.Add(channel); + m->params.Add(wxT("*")); + sendQ->putMessage(m); + + timer = pingTimer; + state = 11; // wait for timer and then send ping + + if (app != NULL) + { + app->setSendQ(sendQ); // this switches the application on + } + break; + + case 11: + if (timer == 0) + { + m = new IRCMessage(); + m->command = wxT("PING"); + m->numParams = 1; + m->params.Add(currentNick); + sendQ->putMessage(m); + + timer = pingTimer; + state = 12; // wait for pong + } + break; + + case 12: + if (timer == 0) + { + // no pong message received -> disconnect + return false; + } + break; + } + + return true; +} + + diff --git a/ircDDB/IRCProtocol.h b/ircDDB/IRCProtocol.h new file mode 100644 index 0000000..cf144aa --- /dev/null +++ b/ircDDB/IRCProtocol.h @@ -0,0 +1,65 @@ +/* + +CIRCDDB - ircDDB client library in C++ + +Copyright (C) 2010 Michael Dirska, DL1BFF (dl1bff@mdx.de) + +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 +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +*/ + +#if !defined(_IRCPROTOCOL_H) +#define _IRCPROTOCOL_H + +#include + +#include "IRCMessageQueue.h" +#include "IRCApplication.h" + + +class IRCProtocol +{ + public: + IRCProtocol ( IRCApplication * app, + const wxString& callsign, const wxString& password, const wxString& channel, + const wxString& versionInfo ); + + ~IRCProtocol(); + + void setNetworkReady( bool state ); + + bool processQueues ( IRCMessageQueue * recvQ, IRCMessageQueue * sendQ ); + + private: + void chooseNewNick(); + + wxArrayString nicks; + wxString password; + wxString channel; + wxString name; + wxString currentNick; + wxString versionInfo; + + int state; + int timer; + int pingTimer; + + wxString debugChannel; + + IRCApplication * app; + +}; + + +#endif diff --git a/ircDDB/IRCReceiver.cpp b/ircDDB/IRCReceiver.cpp new file mode 100644 index 0000000..dc0df95 --- /dev/null +++ b/ircDDB/IRCReceiver.cpp @@ -0,0 +1,237 @@ +/* + +CIRCDDB - ircDDB client library in C++ + +Copyright (C) 2010 Michael Dirska, DL1BFF (dl1bff@mdx.de) + +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 +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +*/ + +#if defined(WIN32) + +#define WIN32_LEAN_AND_MEAN + +#include +#include + +#else + +#include +#include + +#endif + + + +#include "IRCReceiver.h" + +#include + +IRCReceiver::IRCReceiver(int sock, IRCMessageQueue * q ) + : wxThread(wxTHREAD_JOINABLE) +{ + this->sock = sock; + + recvQ = q; +} + +IRCReceiver::~IRCReceiver() +{ +} + +void IRCReceiver::startWork() +{ + terminateThread = false; + + Create(); + Run(); +} + +void IRCReceiver::stopWork() +{ + terminateThread = true; + + Wait(); +} + +static int doRead( int sock, char * buf, int buf_size ) +{ + struct timeval tv; + tv.tv_sec = 1; + tv.tv_usec = 0; + fd_set rdset; + fd_set errset; + + FD_ZERO(&rdset); + FD_ZERO(&errset); + FD_SET(sock, &rdset); + FD_SET(sock, &errset); + + int res; + + res = select(sock+1, &rdset, NULL, &errset, &tv); + + if ( res < 0 ) + { + wxLogSysError(wxT("IRCReceiver::doRead: select")); + return -1; + } + else if ( res > 0 ) + { + if (FD_ISSET(sock, &errset)) + { + wxLogVerbose(wxT("IRCReceiver::doRead: select (FD_ISSET(sock, exceptfds))")); + return -1; + } + + if (FD_ISSET(sock, &rdset)) + { + res = recv(sock, buf, buf_size, 0); + + if (res < 0) + { + wxLogSysError(wxT("IRCReceiver::doRead: read")); + return -1; + } + else if (res == 0) + { + wxLogVerbose(wxT("IRCReceiver::doRead: EOF read==0")); + return -1; + } + else + { + return res; + } + } + + } + + return 0; +} + +wxThread::ExitCode IRCReceiver::Entry () +{ + IRCMessage * m = new IRCMessage(); + + int i; + int state = 0; + + while (!terminateThread) + { + + // wxLogVerbose(wxT("IRCReceiver: tick")); + + char buf[200]; + int r = doRead( sock, buf, sizeof buf ); + + if (r < 0) + { + recvQ -> signalEOF(); + delete m; // delete unfinished IRCMessage + break; + } + + for (i=0; i < r; i++) + { + char b = buf[i]; + + if (b > 0) + { + if (b == 10) + { + recvQ -> putMessage(m); + m = new IRCMessage(); + state = 0; + } + else if (b == 13) + { + // do nothing + } + else switch (state) + { + case 0: + if (b == ':') + { + state = 1; // prefix + } + else if (b == 32) + { + // do nothing + } + else + { + m -> command.Append(wxChar(b)); + state = 2; // command + } + break; + + case 1: + if (b == 32) + { + state = 2; // command is next + } + else + { + m -> prefix.Append(wxChar(b)); + } + break; + + case 2: + if (b == 32) + { + state = 3; // params + m -> numParams = 1; + m -> params.Add(wxT("")); + } + else + { + m -> command.Append(wxChar(b)); + } + break; + + case 3: + if (b == 32) + { + m -> numParams ++; + if (m -> numParams >= 15) + { + state = 5; // ignore the rest + } + + m -> params.Add(wxT("")); + } + else if ((b == ':') && (m -> params[ m -> numParams-1 ].Len() == 0)) + { + state = 4; // rest of line is this param + } + else + { + m -> params[ m -> numParams-1 ].Append(wxChar(b)); + } + break; + + case 4: + m -> params[ m -> numParams-1 ].Append(wxChar(b)); + break; + + + } // switch + } // if + } // for + } // while + + return 0; +} + diff --git a/ircDDB/IRCReceiver.h b/ircDDB/IRCReceiver.h new file mode 100644 index 0000000..547a9b3 --- /dev/null +++ b/ircDDB/IRCReceiver.h @@ -0,0 +1,63 @@ +/* + +CIRCDDB - ircDDB client library in C++ + +Copyright (C) 2010 Michael Dirska, DL1BFF (dl1bff@mdx.de) +Copyright (C) 2012 Jonathan Naylor, G4KLX + +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 +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +*/ + + + +#if !defined(_IRCRECEIVER_H) +#define _IRCRECEIVER_H + +#include + +#include "IRCMessageQueue.h" + + +class IRCReceiver : public wxThread +{ + public: + + IRCReceiver(int sock, IRCMessageQueue * q); + + virtual ~IRCReceiver(); + + + virtual void startWork(); + + virtual void stopWork(); + + + protected: + + virtual wxThread::ExitCode Entry(); + + + + private: + + + bool terminateThread; + int sock; + IRCMessageQueue * recvQ; + +}; + + +#endif diff --git a/ircDDB/IRCutils.cpp b/ircDDB/IRCutils.cpp new file mode 100644 index 0000000..fafda59 --- /dev/null +++ b/ircDDB/IRCutils.cpp @@ -0,0 +1,179 @@ +/* + +CIRCDDB - ircDDB client library in C++ + +Copyright (C) 2010-2011 Michael Dirska, DL1BFF (dl1bff@mdx.de) + +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 +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +*/ + + +#if defined(WIN32) + +#define WIN32_LEAN_AND_MEAN + +#include +#include + +#else + +#include +#include +#include + +#endif + + + +#include + +#include "IRCutils.h" + + +int getAllIPV4Addresses ( const char * name, unsigned short port, + unsigned int * num, struct sockaddr_in * addr, unsigned int max_addr ) +{ + + struct addrinfo hints; + struct addrinfo * res; + + memset(&hints, 0x00, sizeof(struct addrinfo)); + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + + int r = getaddrinfo( name, NULL, &hints, &res ); + + if (r == 0) + { + struct addrinfo * rp; + unsigned int numAddr = 0; + + for (rp = res; rp != NULL; rp = rp->ai_next) + { + if (rp->ai_family == AF_INET) + { + numAddr ++; + } + } + + if (numAddr > 0) + { + if (numAddr > max_addr) + { + numAddr = max_addr; + } + + int * shuffle = new int[numAddr]; + + unsigned int i; + + for (i=0; i < numAddr; i++) + { + shuffle[i] = i; + } + + for (i=0; i < (numAddr - 1); i++) + { + if (rand() & 1) + { + int tmp; + tmp = shuffle[i]; + shuffle[i] = shuffle[i+1]; + shuffle[i+1] = tmp; + } + } + + for (i=(numAddr - 1); i > 0; i--) + { + if (rand() & 1) + { + int tmp; + tmp = shuffle[i]; + shuffle[i] = shuffle[i-1]; + shuffle[i-1] = tmp; + } + } + + for (rp = res, i=0 ; (rp != NULL) && (i < numAddr); rp = rp->ai_next) + { + if (rp->ai_family == AF_INET) + { + memcpy( addr+shuffle[i], rp->ai_addr, sizeof (struct sockaddr_in) ); + + addr[shuffle[i]].sin_port = htons(port); + + i++; + } + } + + delete[] shuffle; + } + + *num = numAddr; + + freeaddrinfo(res); + + return 0; + + } + else + { + wxString e( gai_strerror(r), wxConvUTF8); + + wxLogWarning(wxT("getaddrinfo: ") + e ); + + return 1; + } + + +} + + + + + +void safeStringCopy (char * dest, const char * src, unsigned int buf_size) +{ + unsigned int i = 0; + + while (i < (buf_size - 1) && (src[i] != 0)) + { + dest[i] = src[i]; + i++; + } + + dest[i] = 0; +} + + +wxString getCurrentTime(void) +{ + time_t now = time(NULL); + struct tm* tm; + struct tm tm_buf; + char buffer[25]; + +#if defined(__WINDOWS__) + gmtime_s( &tm_buf, &now ); + tm = &tm_buf; +#else + tm = gmtime_r(&now, &tm_buf); +#endif + + strftime(buffer, sizeof buffer, "%Y-%m-%d %H:%M:%S", tm); + + return wxString(buffer, wxConvLocal); +} + diff --git a/ircDDB/IRCutils.h b/ircDDB/IRCutils.h new file mode 100644 index 0000000..f2e44a6 --- /dev/null +++ b/ircDDB/IRCutils.h @@ -0,0 +1,31 @@ +/* + +CIRCDDB - ircDDB client library in C++ + +Copyright (C) 2010 Michael Dirska, DL1BFF (dl1bff@mdx.de) + +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 +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +*/ + + + +int getAllIPV4Addresses ( const char * name, unsigned short port, + unsigned int * num, struct sockaddr_in * addr, unsigned int max_addr ); + + +void safeStringCopy (char * dest, const char * src, unsigned int buf_size); + +wxString getCurrentTime(void); + diff --git a/ircDDB/LICENSE b/ircDDB/LICENSE new file mode 100644 index 0000000..08ddefd --- /dev/null +++ b/ircDDB/LICENSE @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. + diff --git a/ircDDB/README b/ircDDB/README new file mode 100644 index 0000000..e69de29 diff --git a/ircDDB/ircDDB.vcxproj b/ircDDB/ircDDB.vcxproj new file mode 100644 index 0000000..75e4f54 --- /dev/null +++ b/ircDDB/ircDDB.vcxproj @@ -0,0 +1,171 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {276BC54D-5581-4A0C-AFD5-A5BDC947F0AD} + ircDDB + Win32Proj + 10.0.16299.0 + + + + StaticLibrary + v141 + Unicode + true + + + StaticLibrary + v141 + Unicode + true + + + StaticLibrary + v141 + Unicode + + + StaticLibrary + v141 + Unicode + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>14.0.24720.0 + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + $(WXWIN)\include;$(WXWIN)\lib\vc_dll\mswud;$(IncludePath) + + + $(WXWIN)\include;$(WXWIN)\lib\vc_dll\mswud;$(IncludePath) + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + + + + Disabled + $(WXWIN)\include\msvc;$(WXWIN)\include;../Common;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;WINVER=0x0400;__WXMSW__;WXUSINGDLL;wxUSE_GUI=1;__WXDEBUG__;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_LIB;DEXTRA_LINK;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + Level4 + EditAndContinue + + + + + Disabled + $(WXWIN)\include\msvc;$(WXWIN)\include;../Common;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;WINVER=0x0400;__WXMSW__;WXUSINGDLL;wxUSE_GUI=1;__WXDEBUG__;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_LIB;DEXTRA_LINK;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + + + Level4 + ProgramDatabase + + + + + MaxSpeed + true + $(WXWIN)\include\msvc;$(WXWIN)\include;../Common;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_LIB;_WINDOWS;WINVER=0x0400;__WXMSW__;WXUSINGDLL;wxUSE_GUI=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) + MultiThreadedDLL + true + + Level3 + ProgramDatabase + + + + + MaxSpeed + true + $(WXWIN)\include\msvc;$(WXWIN)\include;../Common;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_LIB;_WINDOWS;WINVER=0x0400;__WXMSW__;WXUSINGDLL;wxUSE_GUI=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) + MultiThreadedDLL + true + + + Level3 + ProgramDatabase + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {e793cb8e-2ac9-431a-bbfc-3f52537bb3cf} + false + + + + + + + + + \ No newline at end of file diff --git a/ircDDB/ircDDB.vcxproj.filters b/ircDDB/ircDDB.vcxproj.filters new file mode 100644 index 0000000..49eb42e --- /dev/null +++ b/ircDDB/ircDDB.vcxproj.filters @@ -0,0 +1,83 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + + \ No newline at end of file diff --git a/ircDDBGateway.sln b/ircDDBGateway.sln new file mode 100644 index 0000000..b080f45 --- /dev/null +++ b/ircDDBGateway.sln @@ -0,0 +1,151 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.27703.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ircDDBGateway", "ircDDBGateway\ircDDBGateway.vcxproj", "{6DDA3497-66A3-4856-BAD4-1DDCDBDFF959}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ircDDB", "ircDDB\ircDDB.vcxproj", "{276BC54D-5581-4A0C-AFD5-A5BDC947F0AD}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Common", "Common\Common.vcxproj", "{E793CB8E-2AC9-431A-BBFC-3F52537BB3CF}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "StarNetServer", "StarNetServer\StarNetServer.vcxproj", "{4E9989C8-80D4-4F6E-BCA1-754DCED3AF5F}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RemoteControl", "RemoteControl\RemoteControl.vcxproj", "{F7756875-1F58-4006-AD55-5C963AB682C0}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TimerControl", "TimerControl\TimerControl.vcxproj", "{68CFAB6D-AED3-4B8A-BCB3-EE4136CA00A3}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TimeServer", "TimeServer\TimeServer.vcxproj", "{99F336A5-6E33-4919-BF75-D6D8BA26345E}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ircDDBGatewayConfig", "ircDDBGatewayConfig\ircDDBGatewayConfig.vcxproj", "{D0A32505-822B-4936-A61B-A5151966AEAA}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TextTransmit", "TextTransmit\TextTransmit.vcxproj", "{AFB9BCE5-0D37-4707-93A1-DA14E39F2773}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "VoiceTransmit", "VoiceTransmit\VoiceTransmit.vcxproj", "{27D44C4F-6849-4E15-A5BB-0B54BA296D98}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GUICommon", "GUICommon\GUICommon.vcxproj", "{02D03515-0BBE-4553-8C40-566A597478F8}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "APRSTransmit", "APRSTransmit\APRSTransmit.vcxproj", "{F26EA1DB-74CF-4C52-A425-00235C8ABED2}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "APRSTransmitD", "APRSTransmit\APRSTransmitD.vcxproj", "{C706EF5D-3917-4796-8BEB-823498A1B13C}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {6DDA3497-66A3-4856-BAD4-1DDCDBDFF959}.Debug|Win32.ActiveCfg = Debug|Win32 + {6DDA3497-66A3-4856-BAD4-1DDCDBDFF959}.Debug|Win32.Build.0 = Debug|Win32 + {6DDA3497-66A3-4856-BAD4-1DDCDBDFF959}.Debug|x64.ActiveCfg = Debug|x64 + {6DDA3497-66A3-4856-BAD4-1DDCDBDFF959}.Debug|x64.Build.0 = Debug|x64 + {6DDA3497-66A3-4856-BAD4-1DDCDBDFF959}.Release|Win32.ActiveCfg = Release|Win32 + {6DDA3497-66A3-4856-BAD4-1DDCDBDFF959}.Release|Win32.Build.0 = Release|Win32 + {6DDA3497-66A3-4856-BAD4-1DDCDBDFF959}.Release|x64.ActiveCfg = Release|x64 + {6DDA3497-66A3-4856-BAD4-1DDCDBDFF959}.Release|x64.Build.0 = Release|x64 + {276BC54D-5581-4A0C-AFD5-A5BDC947F0AD}.Debug|Win32.ActiveCfg = Debug|Win32 + {276BC54D-5581-4A0C-AFD5-A5BDC947F0AD}.Debug|Win32.Build.0 = Debug|Win32 + {276BC54D-5581-4A0C-AFD5-A5BDC947F0AD}.Debug|x64.ActiveCfg = Debug|x64 + {276BC54D-5581-4A0C-AFD5-A5BDC947F0AD}.Debug|x64.Build.0 = Debug|x64 + {276BC54D-5581-4A0C-AFD5-A5BDC947F0AD}.Release|Win32.ActiveCfg = Release|Win32 + {276BC54D-5581-4A0C-AFD5-A5BDC947F0AD}.Release|Win32.Build.0 = Release|Win32 + {276BC54D-5581-4A0C-AFD5-A5BDC947F0AD}.Release|x64.ActiveCfg = Release|x64 + {276BC54D-5581-4A0C-AFD5-A5BDC947F0AD}.Release|x64.Build.0 = Release|x64 + {E793CB8E-2AC9-431A-BBFC-3F52537BB3CF}.Debug|Win32.ActiveCfg = Debug|Win32 + {E793CB8E-2AC9-431A-BBFC-3F52537BB3CF}.Debug|Win32.Build.0 = Debug|Win32 + {E793CB8E-2AC9-431A-BBFC-3F52537BB3CF}.Debug|x64.ActiveCfg = Debug|x64 + {E793CB8E-2AC9-431A-BBFC-3F52537BB3CF}.Debug|x64.Build.0 = Debug|x64 + {E793CB8E-2AC9-431A-BBFC-3F52537BB3CF}.Release|Win32.ActiveCfg = Release|Win32 + {E793CB8E-2AC9-431A-BBFC-3F52537BB3CF}.Release|Win32.Build.0 = Release|Win32 + {E793CB8E-2AC9-431A-BBFC-3F52537BB3CF}.Release|x64.ActiveCfg = Release|x64 + {E793CB8E-2AC9-431A-BBFC-3F52537BB3CF}.Release|x64.Build.0 = Release|x64 + {4E9989C8-80D4-4F6E-BCA1-754DCED3AF5F}.Debug|Win32.ActiveCfg = Debug|Win32 + {4E9989C8-80D4-4F6E-BCA1-754DCED3AF5F}.Debug|Win32.Build.0 = Debug|Win32 + {4E9989C8-80D4-4F6E-BCA1-754DCED3AF5F}.Debug|x64.ActiveCfg = Debug|x64 + {4E9989C8-80D4-4F6E-BCA1-754DCED3AF5F}.Debug|x64.Build.0 = Debug|x64 + {4E9989C8-80D4-4F6E-BCA1-754DCED3AF5F}.Release|Win32.ActiveCfg = Release|Win32 + {4E9989C8-80D4-4F6E-BCA1-754DCED3AF5F}.Release|Win32.Build.0 = Release|Win32 + {4E9989C8-80D4-4F6E-BCA1-754DCED3AF5F}.Release|x64.ActiveCfg = Release|x64 + {4E9989C8-80D4-4F6E-BCA1-754DCED3AF5F}.Release|x64.Build.0 = Release|x64 + {F7756875-1F58-4006-AD55-5C963AB682C0}.Debug|Win32.ActiveCfg = Debug|Win32 + {F7756875-1F58-4006-AD55-5C963AB682C0}.Debug|Win32.Build.0 = Debug|Win32 + {F7756875-1F58-4006-AD55-5C963AB682C0}.Debug|x64.ActiveCfg = Debug|x64 + {F7756875-1F58-4006-AD55-5C963AB682C0}.Debug|x64.Build.0 = Debug|x64 + {F7756875-1F58-4006-AD55-5C963AB682C0}.Release|Win32.ActiveCfg = Release|Win32 + {F7756875-1F58-4006-AD55-5C963AB682C0}.Release|Win32.Build.0 = Release|Win32 + {F7756875-1F58-4006-AD55-5C963AB682C0}.Release|x64.ActiveCfg = Release|x64 + {F7756875-1F58-4006-AD55-5C963AB682C0}.Release|x64.Build.0 = Release|x64 + {68CFAB6D-AED3-4B8A-BCB3-EE4136CA00A3}.Debug|Win32.ActiveCfg = Debug|Win32 + {68CFAB6D-AED3-4B8A-BCB3-EE4136CA00A3}.Debug|Win32.Build.0 = Debug|Win32 + {68CFAB6D-AED3-4B8A-BCB3-EE4136CA00A3}.Debug|x64.ActiveCfg = Debug|x64 + {68CFAB6D-AED3-4B8A-BCB3-EE4136CA00A3}.Debug|x64.Build.0 = Debug|x64 + {68CFAB6D-AED3-4B8A-BCB3-EE4136CA00A3}.Release|Win32.ActiveCfg = Release|Win32 + {68CFAB6D-AED3-4B8A-BCB3-EE4136CA00A3}.Release|Win32.Build.0 = Release|Win32 + {68CFAB6D-AED3-4B8A-BCB3-EE4136CA00A3}.Release|x64.ActiveCfg = Release|x64 + {68CFAB6D-AED3-4B8A-BCB3-EE4136CA00A3}.Release|x64.Build.0 = Release|x64 + {99F336A5-6E33-4919-BF75-D6D8BA26345E}.Debug|Win32.ActiveCfg = Debug|Win32 + {99F336A5-6E33-4919-BF75-D6D8BA26345E}.Debug|Win32.Build.0 = Debug|Win32 + {99F336A5-6E33-4919-BF75-D6D8BA26345E}.Debug|x64.ActiveCfg = Debug|x64 + {99F336A5-6E33-4919-BF75-D6D8BA26345E}.Debug|x64.Build.0 = Debug|x64 + {99F336A5-6E33-4919-BF75-D6D8BA26345E}.Release|Win32.ActiveCfg = Release|Win32 + {99F336A5-6E33-4919-BF75-D6D8BA26345E}.Release|Win32.Build.0 = Release|Win32 + {99F336A5-6E33-4919-BF75-D6D8BA26345E}.Release|x64.ActiveCfg = Release|x64 + {99F336A5-6E33-4919-BF75-D6D8BA26345E}.Release|x64.Build.0 = Release|x64 + {D0A32505-822B-4936-A61B-A5151966AEAA}.Debug|Win32.ActiveCfg = Debug|Win32 + {D0A32505-822B-4936-A61B-A5151966AEAA}.Debug|Win32.Build.0 = Debug|Win32 + {D0A32505-822B-4936-A61B-A5151966AEAA}.Debug|x64.ActiveCfg = Debug|x64 + {D0A32505-822B-4936-A61B-A5151966AEAA}.Debug|x64.Build.0 = Debug|x64 + {D0A32505-822B-4936-A61B-A5151966AEAA}.Release|Win32.ActiveCfg = Release|Win32 + {D0A32505-822B-4936-A61B-A5151966AEAA}.Release|Win32.Build.0 = Release|Win32 + {D0A32505-822B-4936-A61B-A5151966AEAA}.Release|x64.ActiveCfg = Release|x64 + {D0A32505-822B-4936-A61B-A5151966AEAA}.Release|x64.Build.0 = Release|x64 + {AFB9BCE5-0D37-4707-93A1-DA14E39F2773}.Debug|Win32.ActiveCfg = Debug|Win32 + {AFB9BCE5-0D37-4707-93A1-DA14E39F2773}.Debug|Win32.Build.0 = Debug|Win32 + {AFB9BCE5-0D37-4707-93A1-DA14E39F2773}.Debug|x64.ActiveCfg = Debug|x64 + {AFB9BCE5-0D37-4707-93A1-DA14E39F2773}.Debug|x64.Build.0 = Debug|x64 + {AFB9BCE5-0D37-4707-93A1-DA14E39F2773}.Release|Win32.ActiveCfg = Release|Win32 + {AFB9BCE5-0D37-4707-93A1-DA14E39F2773}.Release|Win32.Build.0 = Release|Win32 + {AFB9BCE5-0D37-4707-93A1-DA14E39F2773}.Release|x64.ActiveCfg = Release|x64 + {AFB9BCE5-0D37-4707-93A1-DA14E39F2773}.Release|x64.Build.0 = Release|x64 + {27D44C4F-6849-4E15-A5BB-0B54BA296D98}.Debug|Win32.ActiveCfg = Debug|Win32 + {27D44C4F-6849-4E15-A5BB-0B54BA296D98}.Debug|Win32.Build.0 = Debug|Win32 + {27D44C4F-6849-4E15-A5BB-0B54BA296D98}.Debug|x64.ActiveCfg = Debug|x64 + {27D44C4F-6849-4E15-A5BB-0B54BA296D98}.Debug|x64.Build.0 = Debug|x64 + {27D44C4F-6849-4E15-A5BB-0B54BA296D98}.Release|Win32.ActiveCfg = Release|Win32 + {27D44C4F-6849-4E15-A5BB-0B54BA296D98}.Release|Win32.Build.0 = Release|Win32 + {27D44C4F-6849-4E15-A5BB-0B54BA296D98}.Release|x64.ActiveCfg = Release|x64 + {27D44C4F-6849-4E15-A5BB-0B54BA296D98}.Release|x64.Build.0 = Release|x64 + {02D03515-0BBE-4553-8C40-566A597478F8}.Debug|Win32.ActiveCfg = Debug|Win32 + {02D03515-0BBE-4553-8C40-566A597478F8}.Debug|Win32.Build.0 = Debug|Win32 + {02D03515-0BBE-4553-8C40-566A597478F8}.Debug|x64.ActiveCfg = Debug|x64 + {02D03515-0BBE-4553-8C40-566A597478F8}.Debug|x64.Build.0 = Debug|x64 + {02D03515-0BBE-4553-8C40-566A597478F8}.Release|Win32.ActiveCfg = Release|Win32 + {02D03515-0BBE-4553-8C40-566A597478F8}.Release|Win32.Build.0 = Release|Win32 + {02D03515-0BBE-4553-8C40-566A597478F8}.Release|x64.ActiveCfg = Release|x64 + {02D03515-0BBE-4553-8C40-566A597478F8}.Release|x64.Build.0 = Release|x64 + {F26EA1DB-74CF-4C52-A425-00235C8ABED2}.Debug|Win32.ActiveCfg = Debug|Win32 + {F26EA1DB-74CF-4C52-A425-00235C8ABED2}.Debug|Win32.Build.0 = Debug|Win32 + {F26EA1DB-74CF-4C52-A425-00235C8ABED2}.Debug|x64.ActiveCfg = Debug|x64 + {F26EA1DB-74CF-4C52-A425-00235C8ABED2}.Debug|x64.Build.0 = Debug|x64 + {F26EA1DB-74CF-4C52-A425-00235C8ABED2}.Release|Win32.ActiveCfg = Release|Win32 + {F26EA1DB-74CF-4C52-A425-00235C8ABED2}.Release|Win32.Build.0 = Release|Win32 + {F26EA1DB-74CF-4C52-A425-00235C8ABED2}.Release|x64.ActiveCfg = Release|x64 + {F26EA1DB-74CF-4C52-A425-00235C8ABED2}.Release|x64.Build.0 = Release|x64 + {C706EF5D-3917-4796-8BEB-823498A1B13C}.Debug|Win32.ActiveCfg = Debug|Win32 + {C706EF5D-3917-4796-8BEB-823498A1B13C}.Debug|Win32.Build.0 = Debug|Win32 + {C706EF5D-3917-4796-8BEB-823498A1B13C}.Debug|x64.ActiveCfg = Debug|x64 + {C706EF5D-3917-4796-8BEB-823498A1B13C}.Debug|x64.Build.0 = Debug|x64 + {C706EF5D-3917-4796-8BEB-823498A1B13C}.Release|Win32.ActiveCfg = Release|Win32 + {C706EF5D-3917-4796-8BEB-823498A1B13C}.Release|Win32.Build.0 = Release|Win32 + {C706EF5D-3917-4796-8BEB-823498A1B13C}.Release|x64.ActiveCfg = Release|x64 + {C706EF5D-3917-4796-8BEB-823498A1B13C}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {A992CB62-4EA0-4731-B9A4-6CC00564AB56} + EndGlobalSection +EndGlobal diff --git a/ircDDBGateway/IRCDDBGatewayApp.cpp b/ircDDBGateway/IRCDDBGatewayApp.cpp new file mode 100644 index 0000000..e6107aa --- /dev/null +++ b/ircDDBGateway/IRCDDBGatewayApp.cpp @@ -0,0 +1,923 @@ +/* + * Copyright (C) 2010-2015 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "DummyRepeaterProtocolHandler.h" +#include "IcomRepeaterProtocolHandler.h" +#include "HBRepeaterProtocolHandler.h" +#include "IRCDDBGatewayLogRedirect.h" +#include "IRCDDBGatewayThread.h" +#include "IRCDDBGatewayDefs.h" +#include "IRCDDBGatewayApp.h" +#include "CallsignList.h" +#include "APRSWriter.h" +#include "Version.h" +#include "Logger.h" +#include "IRCDDBClient.h" +#include "IRCDDBMultiClient.h" +#include "Utils.h" +#include "XLXHostsFileDownloader.h" + +#include +#include +#include + +IMPLEMENT_APP(CIRCDDBGatewayApp) + +const wxChar* NAME_PARAM = wxT("Gateway Name"); +const wxChar* NOLOGGING_SWITCH = wxT("nolog"); +const wxChar* GUI_SWITCH = wxT("gui"); +const wxChar* LOGDIR_OPTION = wxT("logdir"); +const wxChar* CONFDIR_OPTION = wxT("confdir"); + +const wxString LOG_BASE_NAME = wxT("ircddbgateway"); + +CIRCDDBGatewayApp::CIRCDDBGatewayApp() : +wxApp(), +m_name(), +m_nolog(false), +m_gui(false), +m_logDir(), +m_confDir(), +m_frame(NULL), +m_thread(NULL), +m_config(NULL), +m_checker(NULL), +m_logChain(NULL) +{ +} + +CIRCDDBGatewayApp::~CIRCDDBGatewayApp() +{ +} + +bool CIRCDDBGatewayApp::OnInit() +{ + SetVendorName(VENDOR_NAME); + + if (!wxApp::OnInit()) + return false; + + if (!m_nolog) { + wxString logBaseName = LOG_BASE_NAME; + if (!m_name.IsEmpty()) { + logBaseName.Append(wxT("_")); + logBaseName.Append(m_name); + } + +#if defined(__WINDOWS__) + if (m_logDir.IsEmpty()) + m_logDir = ::wxGetHomeDir(); +#else + if (m_logDir.IsEmpty()) + m_logDir = wxT(LOG_DIR); +#endif + + wxLog* log = new CLogger(m_logDir, logBaseName); + wxLog::SetActiveTarget(log); + } else { + new wxLogNull; + } + + m_logChain = new wxLogChain(new CIRCDDBGatewayLogRedirect); + + wxString appName; + if (!m_name.IsEmpty()) + appName = APPLICATION_NAME + wxT(" ") + m_name; + else + appName = APPLICATION_NAME; + +#if !defined(__WINDOWS__) + appName.Replace(wxT(" "), wxT("_")); + m_checker = new wxSingleInstanceChecker(appName, wxT("/tmp")); +#else + m_checker = new wxSingleInstanceChecker(appName); +#endif + + bool ret = m_checker->IsAnotherRunning(); + if (ret) { + wxLogError(wxT("Another copy of the ircDDB Gateway is running, exiting")); + return false; + } + +#if defined(__WINDOWS__) + if (m_confDir.IsEmpty()) + m_confDir = ::wxGetHomeDir(); + + m_config = new CIRCDDBGatewayConfig(new wxConfig(APPLICATION_NAME), m_confDir, CONFIG_FILE_NAME, m_name); +#else + if (m_confDir.IsEmpty()) + m_confDir = wxT(CONF_DIR); + + m_config = new CIRCDDBGatewayConfig(m_confDir, CONFIG_FILE_NAME, m_name); +#endif + + wxString frameName = APPLICATION_NAME + wxT(" - "); + if (!m_name.IsEmpty()) { + frameName.Append(m_name); + frameName.Append(wxT(" - ")); + } + frameName.Append(VERSION); + + wxPoint position = wxDefaultPosition; + + int x, y; + m_config->getPosition(x, y); + if (x >= 0 && y >= 0) + position = wxPoint(x, y); + + m_frame = new CIRCDDBGatewayFrame(frameName, position, m_gui); + m_frame->Show(); + + SetTopWindow(m_frame); + + wxLogInfo(wxT("Starting ") + APPLICATION_NAME + wxT(" - ") + VERSION); + + // Log the version of wxWidgets and the Operating System + wxLogInfo(wxT("Using wxWidgets %d.%d.%d on %s"), wxMAJOR_VERSION, wxMINOR_VERSION, wxRELEASE_NUMBER, ::wxGetOsDescription().c_str()); + + createThread(); + + return true; +} + +int CIRCDDBGatewayApp::OnExit() +{ + m_logChain->SetLog(NULL); + + wxLogInfo(APPLICATION_NAME + wxT(" is exiting")); + + //m_thread->kill(); + wxGetApp().GetTopWindow()->Close(); + + delete m_config; + + delete m_checker; + + return 0; +} + +void CIRCDDBGatewayApp::OnInitCmdLine(wxCmdLineParser& parser) +{ + parser.AddSwitch(NOLOGGING_SWITCH, wxEmptyString, wxEmptyString, wxCMD_LINE_PARAM_OPTIONAL); + parser.AddSwitch(GUI_SWITCH, wxEmptyString, wxEmptyString, wxCMD_LINE_PARAM_OPTIONAL); + parser.AddOption(LOGDIR_OPTION, wxEmptyString, wxEmptyString, wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL); + parser.AddOption(CONFDIR_OPTION, wxEmptyString, wxEmptyString, wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL); + parser.AddParam(NAME_PARAM, wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL); + + wxApp::OnInitCmdLine(parser); +} + +bool CIRCDDBGatewayApp::OnCmdLineParsed(wxCmdLineParser& parser) +{ + if (!wxApp::OnCmdLineParsed(parser)) + return false; + + m_nolog = parser.Found(NOLOGGING_SWITCH); + m_gui = parser.Found(GUI_SWITCH); + + wxString logDir; + bool found = parser.Found(LOGDIR_OPTION, &logDir); + if (found) + m_logDir = logDir; + + wxString confDir; + found = parser.Found(CONFDIR_OPTION, &confDir); + if (found) + m_confDir = confDir; + + if (parser.GetParamCount() > 0U) + m_name = parser.GetParam(0U); + + return true; +} + +#if defined(__WXDEBUG__) +void CIRCDDBGatewayApp::OnAssertFailure(const wxChar* file, int line, const wxChar* func, const wxChar* cond, const wxChar* msg) +{ + wxLogFatalError(wxT("Assertion failed on line %d in file %s and function %s: %s %s"), line, file, func, cond, msg); +} +#endif + +void CIRCDDBGatewayApp::showLog(const wxString& text) +{ + m_frame->showLog(text); +} + +CIRCDDBGatewayStatusData* CIRCDDBGatewayApp::getStatus() const +{ + return m_thread->getStatus(); +} + +void CIRCDDBGatewayApp::setPosition(int x, int y) +{ + m_config->setPosition(x, y); + m_config->write(); +} + +void CIRCDDBGatewayApp::createThread() +{ + wxASSERT(m_config != NULL); + + CIRCDDBGatewayThread* thread = new CIRCDDBGatewayThread(m_logDir, m_name); + + GATEWAY_TYPE gatewayType; + wxString gatewayCallsign, gatewayAddress, icomAddress, hbAddress, description1, description2, url; + unsigned int icomPort, hbPort; + double latitude, longitude; + m_config->getGateway(gatewayType, gatewayCallsign, gatewayAddress, icomAddress, icomPort, hbAddress, hbPort, latitude, longitude, description1, description2, url); + + gatewayCallsign.MakeUpper(); + gatewayCallsign.Append(wxT(" ")); + gatewayCallsign.Truncate(LONG_CALLSIGN_LENGTH - 1U); + + wxString callsign = gatewayCallsign; + callsign.Append(wxT(" ")); + + gatewayCallsign.Append(wxT("G")); + + wxLogInfo(wxT("Gateway type: %d, callsign: \"%s\", address: %s, Icom address: %s:%u, homebrew address: %s:%u, latitude: %lf, longitude: %lf, description: \"%s %s\", URL: \"%s\""), int(gatewayType), gatewayCallsign.c_str(), gatewayAddress.c_str(), icomAddress.c_str(), icomPort, hbAddress.c_str(), hbPort, latitude, longitude, description1.c_str(), description2.c_str(), url.c_str()); + + thread->setGateway(gatewayType, gatewayCallsign, gatewayAddress); + + wxString aprsHostname; + unsigned int aprsPort; + bool aprsEnabled; + m_config->getDPRS(aprsEnabled, aprsHostname, aprsPort); + wxLogInfo(wxT("APRS enabled: %d, host: %s:%u"), int(aprsEnabled), aprsHostname.c_str(), aprsPort); + + CAPRSWriter* aprs = NULL; + if (aprsEnabled && !gatewayCallsign.IsEmpty() && !aprsHostname.IsEmpty() && aprsPort != 0U) { + aprs = new CAPRSWriter(aprsHostname, aprsPort, gatewayCallsign, gatewayAddress); + + bool res = aprs->open(); + if (!res) + wxLogError(wxT("Cannot initialise the APRS data writer")); + else + thread->setAPRSWriter(aprs); + } + + TEXT_LANG language; + bool infoEnabled, echoEnabled, logEnabled, dratsEnabled, dtmfEnabled; + m_config->getMiscellaneous(language, infoEnabled, echoEnabled, logEnabled, dratsEnabled, dtmfEnabled); + wxLogInfo(wxT("Language: %d, info enabled: %d, echo enabled: %d, log enabled : %d, D-RATS enabled: %d, DTMF control enabled: %d"), int(language), int(infoEnabled), int(echoEnabled), int(logEnabled), int(dratsEnabled), int(dtmfEnabled)); + + CIcomRepeaterProtocolHandler* icomRepeaterHandler = NULL; + CHBRepeaterProtocolHandler* hbRepeaterHandler = NULL; + CDummyRepeaterProtocolHandler* dummyRepeaterHandler = NULL; + + unsigned int icomCount = 0U; + + wxString repeaterCall1, repeaterBand1, repeaterAddress1, reflector1, description11, description12, url1; + double frequency1, offset1, range1, latitude1, longitude1, agl1; + unsigned char band11, band12, band13; + unsigned int repeaterPort1; + HW_TYPE repeaterType1; + bool atStartup1; + RECONNECT reconnect1; + m_config->getRepeater1(repeaterCall1, repeaterBand1, repeaterType1, repeaterAddress1, repeaterPort1, band11, band12, band13, reflector1, atStartup1, reconnect1, frequency1, offset1, range1, latitude1, longitude1, agl1, description11, description12, url1); + + CUtils::clean(description11, wxT("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 .,&*()-+=@/?:;")); + CUtils::clean(description12, wxT("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 .,&*()-+=@/?:;")); + CUtils::clean(url1, wxT("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 .,&*()-+=@/?:;")); + + wxString callsign1 = callsign; + if (!repeaterBand1.IsSameAs(wxT(" "))) { + if (!repeaterCall1.IsEmpty()) { + callsign1 = repeaterCall1; + callsign1.Append(wxT(" ")); + callsign1.Truncate(LONG_CALLSIGN_LENGTH); + } + + wxLogInfo(wxT("Repeater 1 callsign: \"%.7s%s\", hardware type: %d, address: %s:%u"), callsign1.c_str(), repeaterBand1.c_str(), int(repeaterType1), repeaterAddress1.c_str(), repeaterPort1); + wxLogInfo(wxT("Repeater 1 reflector: %s, at startup: %d, reconnect: %d"), reflector1.c_str(), atStartup1, reconnect1); + wxLogInfo(wxT("Repeater 1 latitude: %lf, longitude: %lf, range: %.0lf kms, height: %.0lf m, frequency: %.4lf MHz, offset: %.4lf MHz"), latitude1, longitude1, range1, agl1, frequency1, offset1); + wxLogInfo(wxT("Repeater 1 description: \"%s %s\", URL: \"%s\""), description11.c_str(), description12.c_str(), url1.c_str()); + + if (repeaterType1 == HW_ICOM && !icomAddress.IsEmpty()) { + icomRepeaterHandler = new CIcomRepeaterProtocolHandler(icomAddress, icomPort, repeaterAddress1, repeaterPort1); + bool res = icomRepeaterHandler->open(); + if (!res) { + wxLogError(wxT("Cannot open the Icom repeater protocol handler")); + delete icomRepeaterHandler; + icomRepeaterHandler = NULL; + } + } else if (repeaterType1 == HW_HOMEBREW && !hbAddress.IsEmpty()) { + hbRepeaterHandler = new CHBRepeaterProtocolHandler(hbAddress, hbPort); + bool res = hbRepeaterHandler->open(); + if (!res) { + wxLogError(wxT("Cannot open the Homebrew repeater protocol handler")); + delete hbRepeaterHandler; + hbRepeaterHandler = NULL; + } + } else if (repeaterType1 == HW_DUMMY && !hbAddress.IsEmpty()) { + dummyRepeaterHandler = new CDummyRepeaterProtocolHandler; + bool res = dummyRepeaterHandler->open(); + if (!res) { + wxLogError(wxT("Cannot open the Dummy repeater protocol handler")); + delete dummyRepeaterHandler; + dummyRepeaterHandler = NULL; + } + } + + if (latitude1 == 0.0 && longitude1 == 0.0) { + latitude1 = latitude; + longitude1 = longitude; + } + + if (description11.IsEmpty()) + description11 = description1; + if (description12.IsEmpty()) + description12 = description2; + + if (url1.IsEmpty()) + url1 = url; + + if (repeaterType1 == HW_ICOM && icomRepeaterHandler != NULL) { + wxLogInfo(wxT("Repeater 1 bands: %u %u %u"), band11, band12, band13); + thread->addRepeater(callsign1, repeaterBand1, repeaterAddress1, repeaterPort1, repeaterType1, reflector1, atStartup1, reconnect1, dratsEnabled, frequency1, offset1, range1, latitude1, longitude1, agl1, description11, description12, url1, icomRepeaterHandler, band11, band12, band13); + + if (aprs != NULL) + aprs->setPort(callsign1, repeaterBand1, frequency1, offset1, range1, latitude1, longitude1, agl1); + + icomCount++; + } else if (repeaterType1 == HW_HOMEBREW && hbRepeaterHandler != NULL) { + thread->addRepeater(callsign1, repeaterBand1, repeaterAddress1, repeaterPort1, repeaterType1, reflector1, atStartup1, reconnect1, dratsEnabled, frequency1, offset1, range1, latitude1, longitude1, agl1, description11, description12, url1, hbRepeaterHandler); + + if (aprs != NULL) + aprs->setPort(callsign1, repeaterBand1, frequency1, offset1, range1, latitude1, longitude1, agl1); + } else if (repeaterType1 == HW_DUMMY && dummyRepeaterHandler != NULL) { + thread->addRepeater(callsign1, repeaterBand1, repeaterAddress1, repeaterPort1, repeaterType1, reflector1, atStartup1, reconnect1, dratsEnabled, frequency1, offset1, range1, latitude1, longitude1, agl1, description11, description12, url1, dummyRepeaterHandler); + } + } + + wxString repeaterCall2, repeaterBand2, repeaterAddress2, reflector2, description21, description22, url2; + double frequency2, offset2, range2, latitude2, longitude2, agl2; + unsigned char band21, band22, band23; + unsigned int repeaterPort2; + HW_TYPE repeaterType2; + bool atStartup2; + RECONNECT reconnect2; + m_config->getRepeater2(repeaterCall2, repeaterBand2, repeaterType2, repeaterAddress2, repeaterPort2, band21, band22, band23, reflector2, atStartup2, reconnect2, frequency2, offset2, range2, latitude2, longitude2, agl2, description21, description22, url2); + + CUtils::clean(description21, wxT("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 .,&*()-+=@/?:;")); + CUtils::clean(description22, wxT("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 .,&*()-+=@/?:;")); + CUtils::clean(url2, wxT("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 .,&*()-+=@/?:;")); + + wxString callsign2 = callsign; + if (!repeaterBand2.IsSameAs(wxT(" "))) { + if (!repeaterCall2.IsEmpty()) { + callsign2 = repeaterCall2; + callsign2.Append(wxT(" ")); + callsign2.Truncate(LONG_CALLSIGN_LENGTH); + } + + wxLogInfo(wxT("Repeater 2 callsign: \"%.7s%s\", hardware type: %d, address: %s:%u"), callsign2.c_str(), repeaterBand2.c_str(), int(repeaterType2), repeaterAddress2.c_str(), repeaterPort2); + wxLogInfo(wxT("Repeater 2 reflector: %s, at startup: %d, reconnect: %d"), reflector2.c_str(), atStartup2, reconnect2); + wxLogInfo(wxT("Repeater 2 latitude: %lf, longitude: %lf, range: %.0lf kms, height: %.0lf m, frequency: %.4lf MHz, offset: %.4lf MHz"), latitude2, longitude2, range2, agl2, frequency2, offset2); + wxLogInfo(wxT("Repeater 2 description: \"%s %s\", URL: \"%s\""), description21.c_str(), description22.c_str(), url2.c_str()); + + if (callsign1.IsSameAs(callsign2) && repeaterBand1.IsSameAs(repeaterBand2)) { + wxLogError(wxT("Repeater 2 has the same callsign and module as repeater 1, exiting")); + return; + } + + if (repeaterType2 == HW_ICOM && !icomAddress.IsEmpty() && icomRepeaterHandler == NULL) { + icomRepeaterHandler = new CIcomRepeaterProtocolHandler(icomAddress, icomPort, repeaterAddress2, repeaterPort2); + bool res = icomRepeaterHandler->open(); + if (!res) { + wxLogError(wxT("Cannot open the Icom repeater protocol handler")); + delete icomRepeaterHandler; + icomRepeaterHandler = NULL; + } + } else if (repeaterType2 == HW_HOMEBREW && !hbAddress.IsEmpty() && hbRepeaterHandler == NULL) { + hbRepeaterHandler = new CHBRepeaterProtocolHandler(hbAddress, hbPort); + bool res = hbRepeaterHandler->open(); + if (!res) { + wxLogError(wxT("Cannot open the Homebrew repeater protocol handler")); + delete hbRepeaterHandler; + hbRepeaterHandler = NULL; + } + } else if (repeaterType2 == HW_DUMMY && !hbAddress.IsEmpty() && dummyRepeaterHandler == NULL) { + dummyRepeaterHandler = new CDummyRepeaterProtocolHandler; + bool res = dummyRepeaterHandler->open(); + if (!res) { + wxLogError(wxT("Cannot open the Dummy repeater protocol handler")); + delete dummyRepeaterHandler; + dummyRepeaterHandler = NULL; + } + } + + if (latitude2 == 0.0 && longitude2 == 0.0) { + latitude2 = latitude; + longitude2 = longitude; + } + + if (description21.IsEmpty()) + description21 = description1; + if (description22.IsEmpty()) + description22 = description2; + + if (url2.IsEmpty()) + url2 = url; + + if (repeaterType2 == HW_ICOM && icomRepeaterHandler != NULL) { + wxLogInfo(wxT("Repeater 2 bands: %u %u %u"), band21, band22, band23); + thread->addRepeater(callsign2, repeaterBand2, repeaterAddress2, repeaterPort2, repeaterType2, reflector2, atStartup2, reconnect2, dratsEnabled, frequency2, offset2, range2, latitude2, longitude2, agl2, description21, description22, url2, icomRepeaterHandler, band21, band22, band23); + + if (aprs != NULL) + aprs->setPort(callsign2, repeaterBand2, frequency2, offset2, range2, latitude2, longitude2, agl2); + + icomCount++; + } else if (repeaterType2 == HW_HOMEBREW && hbRepeaterHandler != NULL) { + thread->addRepeater(callsign2, repeaterBand2, repeaterAddress2, repeaterPort2, repeaterType2, reflector2, atStartup2, reconnect2, dratsEnabled, frequency2, offset2, range2, latitude2, longitude2, agl2, description21, description22, url2, hbRepeaterHandler); + + if (aprs != NULL) + aprs->setPort(callsign2, repeaterBand2, frequency2, offset2, range2, latitude2, longitude2, agl2); + } else if (repeaterType2 == HW_DUMMY && dummyRepeaterHandler != NULL) { + thread->addRepeater(callsign2, repeaterBand2, repeaterAddress2, repeaterPort2, repeaterType2, reflector2, atStartup2, reconnect2, dratsEnabled, frequency2, offset2, range2, latitude2, longitude2, agl2, description21, description22, url2, dummyRepeaterHandler); + } + } + + wxString repeaterCall3, repeaterBand3, repeaterAddress3, reflector3, description31, description32, url3; + double frequency3, offset3, range3, latitude3, longitude3, agl3; + unsigned char band31, band32, band33; + unsigned int repeaterPort3; + HW_TYPE repeaterType3; + bool atStartup3; + RECONNECT reconnect3; + m_config->getRepeater3(repeaterCall3, repeaterBand3, repeaterType3, repeaterAddress3, repeaterPort3, band31, band32, band33, reflector3, atStartup3, reconnect3, frequency3, offset3, range3, latitude3, longitude3, agl3, description31, description32, url3); + + CUtils::clean(description31, wxT("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 .,&*()-+=@/?:;")); + CUtils::clean(description32, wxT("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 .,&*()-+=@/?:;")); + CUtils::clean(url3, wxT("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 .,&*()-+=@/?:;")); + + wxString callsign3 = callsign; + if (!repeaterBand3.IsSameAs(wxT(" "))) { + if (!repeaterCall3.IsEmpty()) { + callsign3 = repeaterCall3; + callsign3.Append(wxT(" ")); + callsign3.Truncate(LONG_CALLSIGN_LENGTH); + } + + wxLogInfo(wxT("Repeater 3 callsign: \"%.7s%s\", hardware type: %d, address: %s:%u"), callsign3.c_str(), repeaterBand3.c_str(), int(repeaterType3), repeaterAddress3.c_str(), repeaterPort3); + wxLogInfo(wxT("Repeater 3 reflector: %s, at startup: %d, reconnect: %d"), reflector3.c_str(), atStartup3, reconnect3); + wxLogInfo(wxT("Repeater 3 latitude: %lf, longitude: %lf, range: %.0lf kms, height: %.0lf m, frequency: %.4lf MHz, offset: %.4lf MHz"), latitude3, longitude3, range3, agl3, frequency3, offset3); + wxLogInfo(wxT("Repeater 3 description: \"%s %s\", URL: \"%s\""), description31.c_str(), description32.c_str(), url3.c_str()); + + if (callsign1.IsSameAs(callsign3) && repeaterBand1.IsSameAs(repeaterBand3)) { + wxLogError(wxT("Repeater 3 has the same callsign and module as repeater 1, exiting")); + return; + } + if (callsign2.IsSameAs(callsign3) && repeaterBand2.IsSameAs(repeaterBand3)) { + wxLogError(wxT("Repeater 3 has the same callsign and module as repeater 2, exiting")); + return; + } + + if (repeaterType3 == HW_ICOM && !icomAddress.IsEmpty() && icomRepeaterHandler == NULL) { + icomRepeaterHandler = new CIcomRepeaterProtocolHandler(icomAddress, icomPort, repeaterAddress3, repeaterPort3); + bool res = icomRepeaterHandler->open(); + if (!res) { + wxLogError(wxT("Cannot open the Icom repeater protocol handler")); + delete icomRepeaterHandler; + icomRepeaterHandler = NULL; + } + } else if (repeaterType3 == HW_HOMEBREW && !hbAddress.IsEmpty() && hbRepeaterHandler == NULL) { + hbRepeaterHandler = new CHBRepeaterProtocolHandler(hbAddress, hbPort); + bool res = hbRepeaterHandler->open(); + if (!res) { + wxLogError(wxT("Cannot open the Homebrew repeater protocol handler")); + delete hbRepeaterHandler; + hbRepeaterHandler = NULL; + } + } else if (repeaterType3 == HW_DUMMY && !hbAddress.IsEmpty() && dummyRepeaterHandler == NULL) { + dummyRepeaterHandler = new CDummyRepeaterProtocolHandler; + bool res = dummyRepeaterHandler->open(); + if (!res) { + wxLogError(wxT("Cannot open the Dummy repeater protocol handler")); + delete dummyRepeaterHandler; + dummyRepeaterHandler = NULL; + } + } + + if (latitude3 == 0.0 && longitude3 == 0.0) { + latitude3 = latitude; + longitude3 = longitude; + } + + if (description31.IsEmpty()) + description31 = description1; + if (description32.IsEmpty()) + description32 = description2; + + if (url3.IsEmpty()) + url3 = url; + + if (repeaterType3 == HW_ICOM && icomRepeaterHandler != NULL) { + wxLogInfo(wxT("Repeater 3 bands: %u %u %u"), band31, band32, band33); + thread->addRepeater(callsign3, repeaterBand3, repeaterAddress3, repeaterPort3, repeaterType3, reflector3, atStartup3, reconnect3, dratsEnabled, frequency3, offset3, range3, latitude3, longitude3, agl3, description31, description32, url3, icomRepeaterHandler, band31, band32, band33); + + if (aprs != NULL) + aprs->setPort(callsign3, repeaterBand3, frequency3, offset3, range3, latitude3, longitude3, agl3); + + icomCount++; + } else if (repeaterType3 == HW_HOMEBREW && hbRepeaterHandler != NULL) { + thread->addRepeater(callsign3, repeaterBand3, repeaterAddress3, repeaterPort3, repeaterType3, reflector3, atStartup3, reconnect3, dratsEnabled, frequency3, offset3, range3, latitude3, longitude3, agl3, description31, description32, url3, hbRepeaterHandler); + + if (aprs != NULL) + aprs->setPort(callsign3, repeaterBand3, frequency3, offset3, range3, latitude3, longitude3, agl3); + } else if (repeaterType3 == HW_DUMMY && dummyRepeaterHandler != NULL) { + thread->addRepeater(callsign3, repeaterBand3, repeaterAddress3, repeaterPort3, repeaterType3, reflector3, atStartup3, reconnect3, dratsEnabled, frequency3, offset3, range3, latitude3, longitude3, agl3, description31, description32, url3, dummyRepeaterHandler); + } + } + + wxString repeaterCall4, repeaterBand4, repeaterAddress4, reflector4, description41, description42, url4; + double frequency4, offset4, range4, latitude4, longitude4, agl4; + unsigned char band41, band42, band43; + unsigned int repeaterPort4; + HW_TYPE repeaterType4; + bool atStartup4; + RECONNECT reconnect4; + m_config->getRepeater4(repeaterCall4, repeaterBand4, repeaterType4, repeaterAddress4, repeaterPort4, band41, band42, band43, reflector4, atStartup4, reconnect4, frequency4, offset4, range4, latitude4, longitude4, agl4, description41, description42, url4); + + CUtils::clean(description41, wxT("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 .,&*()-+=@/?:;")); + CUtils::clean(description42, wxT("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 .,&*()-+=@/?:;")); + CUtils::clean(url4, wxT("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 .,&*()-+=@/?:;")); + + wxString callsign4 = callsign; + if (!repeaterBand4.IsSameAs(wxT(" "))) { + if (!repeaterCall4.IsEmpty()) { + callsign4 = repeaterCall4; + callsign4.Append(wxT(" ")); + callsign4.Truncate(LONG_CALLSIGN_LENGTH); + } + + wxLogInfo(wxT("Repeater 4 callsign: \"%.7s%s\", hardware type: %d, address: %s:%u"), callsign4.c_str(), repeaterBand4.c_str(), int(repeaterType4), repeaterAddress4.c_str(), repeaterPort4); + wxLogInfo(wxT("Repeater 4 reflector: %s, at startup: %d, reconnect: %d"), reflector4.c_str(), atStartup4, reconnect4); + wxLogInfo(wxT("Repeater 4 latitude: %lf, longitude: %lf, range: %.0lf kms, height: %.0lf m, frequency: %.4lf MHz, offset: %.4lf MHz"), latitude4, longitude4, range4, agl4, frequency4, offset4); + wxLogInfo(wxT("Repeater 4 description: \"%s %s\", URL: \"%s\""), description41.c_str(), description42.c_str(), url4.c_str()); + + if (callsign1.IsSameAs(callsign4) && repeaterBand1.IsSameAs(repeaterBand4)) { + wxLogError(wxT("Repeater 4 has the same callsign and module as repeater 1, exiting")); + return; + } + if (callsign2.IsSameAs(callsign4) && repeaterBand2.IsSameAs(repeaterBand4)) { + wxLogError(wxT("Repeater 4 has the same callsign and module as repeater 2, exiting")); + return; + } + if (callsign3.IsSameAs(callsign4) && repeaterBand3.IsSameAs(repeaterBand4)) { + wxLogError(wxT("Repeater 4 has the same callsign and module as repeater 3, exiting")); + return; + } + + if (repeaterType4 == HW_ICOM && !icomAddress.IsEmpty() && icomRepeaterHandler == NULL) { + icomRepeaterHandler = new CIcomRepeaterProtocolHandler(icomAddress, icomPort, repeaterAddress4, repeaterPort4); + bool res = icomRepeaterHandler->open(); + if (!res) { + wxLogError(wxT("Cannot open the Icom repeater protocol handler")); + delete icomRepeaterHandler; + icomRepeaterHandler = NULL; + } + } else if (repeaterType4 == HW_HOMEBREW && !hbAddress.IsEmpty() && hbRepeaterHandler == NULL) { + hbRepeaterHandler = new CHBRepeaterProtocolHandler(hbAddress, hbPort); + bool res = hbRepeaterHandler->open(); + if (!res) { + wxLogError(wxT("Cannot open the Homebrew repeater protocol handler")); + delete hbRepeaterHandler; + hbRepeaterHandler = NULL; + } + } else if (repeaterType4 == HW_DUMMY && !hbAddress.IsEmpty() && dummyRepeaterHandler == NULL) { + dummyRepeaterHandler = new CDummyRepeaterProtocolHandler; + bool res = dummyRepeaterHandler->open(); + if (!res) { + wxLogError(wxT("Cannot open the Dummy repeater protocol handler")); + delete dummyRepeaterHandler; + dummyRepeaterHandler = NULL; + } + } + + if (latitude4 == 0.0 && longitude4 == 0.0) { + latitude4 = latitude; + longitude4 = longitude; + } + + if (description41.IsEmpty()) + description41 = description1; + if (description42.IsEmpty()) + description42 = description2; + + if (url4.IsEmpty()) + url4 = url; + + if (repeaterType4 == HW_ICOM && icomRepeaterHandler != NULL) { + wxLogInfo(wxT("Repeater 4 bands: %u %u %u"), band41, band42, band43); + thread->addRepeater(callsign4, repeaterBand4, repeaterAddress4, repeaterPort4, repeaterType4, reflector4, atStartup4, reconnect4, dratsEnabled, frequency4, offset4, range4, latitude4, longitude4, agl4, description41, description42, url4, icomRepeaterHandler, band41, band42, band43); + + if (aprs != NULL) + aprs->setPort(callsign4, repeaterBand4, frequency4, offset4, range4, latitude4, longitude4, agl4); + + icomCount++; + } else if (repeaterType4 == HW_HOMEBREW && hbRepeaterHandler != NULL) { + thread->addRepeater(callsign4, repeaterBand4, repeaterAddress4, repeaterPort4, repeaterType4, reflector4, atStartup4, reconnect4, dratsEnabled, frequency4, offset4, range4, latitude4, longitude4, agl4, description41, description42, url4, hbRepeaterHandler); + + if (aprs != NULL) + aprs->setPort(callsign4, repeaterBand4, frequency4, offset4, range4, latitude4, longitude4, agl4); + } else if (repeaterType4 == HW_DUMMY && dummyRepeaterHandler != NULL) { + thread->addRepeater(callsign4, repeaterBand4, repeaterAddress4, repeaterPort4, repeaterType4, reflector4, atStartup4, reconnect4, dratsEnabled, frequency4, offset4, range4, latitude4, longitude4, agl4, description41, description42, url4, dummyRepeaterHandler); + } + } + + if (icomRepeaterHandler != NULL) + icomRepeaterHandler->setCount(icomCount); + + bool ircDDBAtLeastOneEnabled, ircDDBEnabled1, ircDDBEnabled2, ircDDBEnabled3, ircDDBEnabled4; + wxString ircDDBHostname1, ircDDBUsername1, ircDDBPassword1; + wxString ircDDBHostname2, ircDDBUsername2, ircDDBPassword2; + wxString ircDDBHostname3, ircDDBUsername3, ircDDBPassword3; + wxString ircDDBHostname4, ircDDBUsername4, ircDDBPassword4; + + m_config->getIrcDDB(ircDDBEnabled1, ircDDBHostname1, ircDDBUsername1, ircDDBPassword1); + wxLogInfo(wxT("ircDDB 1 enabled: %d, host: %s, username: %s"), int(ircDDBEnabled1), ircDDBHostname1.c_str(), ircDDBUsername1.c_str()); + + m_config->getIrcDDB2(ircDDBEnabled2, ircDDBHostname2, ircDDBUsername2, ircDDBPassword2); + wxLogInfo(wxT("ircDDB 2 enabled: %d, host: %s, username: %s"), int(ircDDBEnabled2), ircDDBHostname2.c_str(), ircDDBUsername2.c_str()); + + m_config->getIrcDDB3(ircDDBEnabled3, ircDDBHostname3, ircDDBUsername3, ircDDBPassword3); + wxLogInfo(wxT("ircDDB 3 enabled: %d, host: %s, username: %s"), int(ircDDBEnabled3), ircDDBHostname3.c_str(), ircDDBUsername3.c_str()); + + m_config->getIrcDDB4(ircDDBEnabled4, ircDDBHostname4, ircDDBUsername4, ircDDBPassword4); + wxLogInfo(wxT("ircDDB 4 enabled: %d, host: %s, username: %s"), int(ircDDBEnabled4), ircDDBHostname4.c_str(), ircDDBUsername4.c_str()); + + ircDDBAtLeastOneEnabled = ircDDBEnabled1 || ircDDBEnabled2 || ircDDBEnabled3 || ircDDBEnabled4; + + if (ircDDBAtLeastOneEnabled) { +#if defined(__WINDOWS__) + wxString versionInfo = wxT("win_") + LOG_BASE_NAME + wxT("-") + VERSION; +#else + wxString versionInfo = wxT("linux_") + LOG_BASE_NAME + wxT("-") + VERSION; +#endif + CIRCDDB_Array ircDDBClients; + if(ircDDBEnabled1) + ircDDBClients.Add(new CIRCDDBClient(ircDDBHostname1, 9007U, ircDDBUsername1, ircDDBPassword1, versionInfo, gatewayAddress)); + if (ircDDBEnabled2) + ircDDBClients.Add(new CIRCDDBClient(ircDDBHostname2, 9007U, ircDDBUsername2, ircDDBPassword2, versionInfo, gatewayAddress)); + if (ircDDBEnabled3) + ircDDBClients.Add(new CIRCDDBClient(ircDDBHostname3, 9007U, ircDDBUsername3, ircDDBPassword3, versionInfo, gatewayAddress)); + if (ircDDBEnabled4) + ircDDBClients.Add(new CIRCDDBClient(ircDDBHostname4, 9007U, ircDDBUsername4, ircDDBPassword4, versionInfo, gatewayAddress)); + + CIRCDDBMultiClient * ircDDB = new CIRCDDBMultiClient(ircDDBClients); + + bool res = ircDDB->open(); + if (!res) { + wxLogError(wxT("Cannot initialise the ircDDB protocol handler")); + ircDDBAtLeastOneEnabled = false; + } else { + thread->setIRC(ircDDB); + } + } + + if (ircDDBAtLeastOneEnabled) { + wxString starNetBand1, starNetCallsign1, starNetLogoff1, starNetInfo1, starNetPermanent1, link1; // DEXTRA_LINK || DCS_LINK + unsigned int starNetUserTimeout1, starNetGroupTimeout1; + STARNET_CALLSIGN_SWITCH starNetCallsignSwitch1; + bool starNetTXMsgSwitch1; + m_config->getStarNet1(starNetBand1, starNetCallsign1, starNetLogoff1, starNetInfo1, starNetPermanent1, starNetUserTimeout1, starNetGroupTimeout1, starNetCallsignSwitch1, starNetTXMsgSwitch1 +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + ,link1 +#endif + ); + + if (!starNetCallsign1.IsEmpty() && !starNetCallsign1.IsSameAs(wxT(" "))) { + wxString repeater = gatewayCallsign; + repeater.Truncate(LONG_CALLSIGN_LENGTH - 1U); + repeater.Append(starNetBand1); + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + thread->addStarNet(starNetCallsign1, starNetLogoff1, repeater, starNetInfo1, starNetPermanent1, starNetUserTimeout1, starNetGroupTimeout1, starNetCallsignSwitch1, starNetTXMsgSwitch1, link1); + wxLogInfo(wxT("STARnet group 1 set to %s/%s on repeater %s, info: \"%s\", permanent: %s, user: %u mins, group: %u mins, callsign switch: %d, tx msg switch: %d, reflector: %s"), starNetCallsign1.c_str(), starNetLogoff1.c_str(), repeater.c_str(), starNetInfo1.c_str(), starNetPermanent1.c_str(), starNetUserTimeout1, starNetGroupTimeout1, int(starNetCallsignSwitch1), int(starNetTXMsgSwitch1), link1.c_str()); +#else + thread->addStarNet(starNetCallsign1, starNetLogoff1, repeater, starNetInfo1, starNetPermanent1, starNetUserTimeout1, starNetGroupTimeout1, starNetCallsignSwitch1, starNetTXMsgSwitch1); + wxLogInfo(wxT("STARnet group 1 set to %s/%s on repeater %s, info: \"%s\", permanent: %s, user: %u mins, group: %u mins, callsign switch: %d, tx msg switch: %d"), starNetCallsign1.c_str(), starNetLogoff1.c_str(), repeater.c_str(), starNetInfo1.c_str(), starNetPermanent1.c_str(), starNetUserTimeout1, starNetGroupTimeout1, int(starNetCallsignSwitch1), int(starNetTXMsgSwitch1)); +#endif + } + + wxString starNetBand2, starNetCallsign2, starNetLogoff2, starNetInfo2, starNetPermanent2, link2; // DEXTRA_LINK || DCS_LINK + unsigned int starNetUserTimeout2, starNetGroupTimeout2; + STARNET_CALLSIGN_SWITCH starNetCallsignSwitch2; + bool starNetTXMsgSwitch2; + m_config->getStarNet2(starNetBand2, starNetCallsign2, starNetLogoff2, starNetInfo2, starNetPermanent2, starNetUserTimeout2, starNetGroupTimeout2, starNetCallsignSwitch2, starNetTXMsgSwitch2 +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + ,link2 +#endif + ); + + if (!starNetCallsign2.IsEmpty() && !starNetCallsign2.IsSameAs(wxT(" "))) { + wxString repeater = gatewayCallsign; + repeater.Truncate(LONG_CALLSIGN_LENGTH - 1U); + repeater.Append(starNetBand2); + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + thread->addStarNet(starNetCallsign2, starNetLogoff2, repeater, starNetInfo2, starNetPermanent2, starNetUserTimeout2, starNetGroupTimeout2, starNetCallsignSwitch2, starNetTXMsgSwitch2, link2); + wxLogInfo(wxT("STARnet group 2 set to %s/%s on repeater %s, info: \"%s\", permanent: %s, user: %u mins, group: %u mins, callsign switch: %d, tx msg switch: %d, reflector: %s"), starNetCallsign2.c_str(), starNetLogoff2.c_str(), repeater.c_str(), starNetInfo2.c_str(), starNetPermanent2.c_str(), starNetUserTimeout2, starNetGroupTimeout2, int(starNetCallsignSwitch2), int(starNetTXMsgSwitch2), link2.c_str()); +#else + thread->addStarNet(starNetCallsign2, starNetLogoff2, repeater, starNetInfo2, starNetPermanent2, starNetUserTimeout2, starNetGroupTimeout2, starNetCallsignSwitch2, starNetTXMsgSwitch2); + wxLogInfo(wxT("STARnet group 2 set to %s/%s on repeater %s, info: \"%s\", permanent: %s, user: %u mins, group: %u mins, callsign switch: %d, tx msg switch: %d"), starNetCallsign2.c_str(), starNetLogoff2.c_str(), repeater.c_str(), starNetInfo2.c_str(), starNetPermanent2.c_str(), starNetUserTimeout2, starNetGroupTimeout2, int(starNetCallsignSwitch2), int(starNetTXMsgSwitch2)); +#endif + } + + wxString starNetBand3, starNetCallsign3, starNetLogoff3, starNetInfo3, starNetPermanent3, link3; // DEXTRA_LINK || DCS_LINK + unsigned int starNetUserTimeout3, starNetGroupTimeout3; + STARNET_CALLSIGN_SWITCH starNetCallsignSwitch3; + bool starNetTXMsgSwitch3; + m_config->getStarNet3(starNetBand3, starNetCallsign3, starNetLogoff3, starNetInfo3, starNetPermanent3, starNetUserTimeout3, starNetGroupTimeout3, starNetCallsignSwitch3, starNetTXMsgSwitch3 +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + ,link3 +#endif + ); + + if (!starNetCallsign3.IsEmpty() && !starNetCallsign3.IsSameAs(wxT(" "))) { + wxString repeater = gatewayCallsign; + repeater.Truncate(LONG_CALLSIGN_LENGTH - 1U); + repeater.Append(starNetBand3); + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + thread->addStarNet(starNetCallsign3, starNetLogoff3, repeater, starNetInfo3, starNetPermanent3, starNetUserTimeout3, starNetGroupTimeout3, starNetCallsignSwitch3, starNetTXMsgSwitch3, link3); + wxLogInfo(wxT("STARnet group 3 set to %s/%s on repeater %s, info: \"%s\", permanent: %s, user: %u mins, group: %u mins, callsign switch: %d, tx msg switch: %d, reflector: %s"), starNetCallsign3.c_str(), starNetLogoff3.c_str(), repeater.c_str(), starNetInfo3.c_str(), starNetPermanent3.c_str(), starNetUserTimeout3, starNetGroupTimeout3, int(starNetCallsignSwitch3), int(starNetTXMsgSwitch3), link3.c_str()); +#else + thread->addStarNet(starNetCallsign3, starNetLogoff3, repeater, starNetInfo3, starNetPermanent3, starNetUserTimeout3, starNetGroupTimeout3, starNetCallsignSwitch3, starNetTXMsgSwitch3); + wxLogInfo(wxT("STARnet group 3 set to %s/%s on repeater %s, info: \"%s\", permanent: %s, user: %u mins, group: %u mins, callsign switch: %d, tx msg switch: %d"), starNetCallsign3.c_str(), starNetLogoff3.c_str(), repeater.c_str(), starNetInfo3.c_str(), starNetPermanent3.c_str(), starNetUserTimeout3, starNetGroupTimeout3, int(starNetCallsignSwitch3), int(starNetTXMsgSwitch3)); +#endif + } + + wxString starNetBand4, starNetCallsign4, starNetLogoff4, starNetInfo4, starNetPermanent4, link4; // DEXTRA_LINK || DCS_LINK + unsigned int starNetUserTimeout4, starNetGroupTimeout4; + STARNET_CALLSIGN_SWITCH starNetCallsignSwitch4; + bool starNetTXMsgSwitch4; + m_config->getStarNet4(starNetBand4, starNetCallsign4, starNetLogoff4, starNetInfo4, starNetPermanent4, starNetUserTimeout4, starNetGroupTimeout4, starNetCallsignSwitch4, starNetTXMsgSwitch4 +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + ,link4 +#endif + ); + + if (!starNetCallsign4.IsEmpty() && !starNetCallsign4.IsSameAs(wxT(" "))) { + wxString repeater = gatewayCallsign; + repeater.Truncate(LONG_CALLSIGN_LENGTH - 1U); + repeater.Append(starNetBand4); + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + thread->addStarNet(starNetCallsign4, starNetLogoff4, repeater, starNetInfo4, starNetPermanent4, starNetUserTimeout4, starNetGroupTimeout4, starNetCallsignSwitch4, starNetTXMsgSwitch4, link4); + wxLogInfo(wxT("STARnet group 4 set to %s/%s on repeater %s, info: \"%s\", permanent: %s, user: %u mins, group: %u mins, callsign switch: %d, tx msg switch: %d, reflector: %s"), starNetCallsign4.c_str(), starNetLogoff4.c_str(), repeater.c_str(), starNetInfo4.c_str(), starNetPermanent4.c_str(), starNetUserTimeout4, starNetGroupTimeout4, int(starNetCallsignSwitch4), int(starNetTXMsgSwitch4), link4.c_str()); +#else + thread->addStarNet(starNetCallsign4, starNetLogoff4, repeater, starNetInfo4, starNetPermanent4, starNetUserTimeout4, starNetGroupTimeout4, starNetCallsignSwitch4, starNetTXMsgSwitch4); + wxLogInfo(wxT("STARnet group 4 set to %s/%s on repeater %s, info: \"%s\", permanent: %s, user: %u mins, group: %u mins, callsign switch: %d, tx msg switch: %d"), starNetCallsign4.c_str(), starNetLogoff4.c_str(), repeater.c_str(), starNetInfo4.c_str(), starNetPermanent4.c_str(), starNetUserTimeout4, starNetGroupTimeout4, int(starNetCallsignSwitch4), int(starNetTXMsgSwitch4)); +#endif + } + + wxString starNetBand5, starNetCallsign5, starNetLogoff5, starNetInfo5, starNetPermanent5, link5; // DEXTRA_LINK || DCS_LINK + unsigned int starNetUserTimeout5, starNetGroupTimeout5; + STARNET_CALLSIGN_SWITCH starNetCallsignSwitch5; + bool starNetTXMsgSwitch5; + m_config->getStarNet5(starNetBand5, starNetCallsign5, starNetLogoff5, starNetInfo5, starNetPermanent5, starNetUserTimeout5, starNetGroupTimeout5, starNetCallsignSwitch5, starNetTXMsgSwitch5 +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + ,link5 +#endif + ); + + if (!starNetCallsign5.IsEmpty() && !starNetCallsign5.IsSameAs(wxT(" "))) { + wxString repeater = gatewayCallsign; + repeater.Truncate(LONG_CALLSIGN_LENGTH - 1U); + repeater.Append(starNetBand5); + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + thread->addStarNet(starNetCallsign5, starNetLogoff5, repeater, starNetInfo5, starNetPermanent5, starNetUserTimeout5, starNetGroupTimeout5, starNetCallsignSwitch5, starNetTXMsgSwitch5, link5); + wxLogInfo(wxT("STARnet group 5 set to %s/%s on repeater %s, info: \"%s\", permanent: %s, user: %u mins, group: %u mins, callsign switch: %d, tx msg switch: %d, reflector: %s"), starNetCallsign5.c_str(), starNetLogoff5.c_str(), repeater.c_str(), starNetInfo5.c_str(), starNetPermanent5.c_str(), starNetUserTimeout5, starNetGroupTimeout5, int(starNetCallsignSwitch5), int(starNetTXMsgSwitch5), link5.c_str()); +#else + thread->addStarNet(starNetCallsign5, starNetLogoff5, repeater, starNetInfo5, starNetPermanent5, starNetUserTimeout5, starNetGroupTimeout5, starNetCallsignSwitch5, starNetTXMsgSwitch5); + wxLogInfo(wxT("STARnet group 5 set to %s/%s on repeater %s, info: \"%s\", permanent: %s, user: %u mins, group: %u mins, callsign switch: %d, tx msg switch: %d"), starNetCallsign5.c_str(), starNetLogoff5.c_str(), repeater.c_str(), starNetInfo5.c_str(), starNetPermanent5.c_str(), starNetUserTimeout5, starNetGroupTimeout5, int(starNetCallsignSwitch5), int(starNetTXMsgSwitch5)); +#endif + } + } + + bool dextraEnabled; + unsigned int dextraMaxDongles; + m_config->getDExtra(dextraEnabled, dextraMaxDongles); + wxLogInfo(wxT("DExtra enabled: %d, max. dongles: %u"), int(dextraEnabled), dextraMaxDongles); + + bool remoteEnabled; + wxString remotePassword; + unsigned int remotePort; + m_config->getRemote(remoteEnabled, remotePassword, remotePort); + wxLogInfo(wxT("Remote enabled: %d, port: %u"), int(remoteEnabled), remotePort); + thread->setRemote(remoteEnabled, remotePassword, remotePort); + + wxString dplusLogin; + unsigned int dplusMaxDongles; + bool dplusEnabled; + m_config->getDPlus(dplusEnabled, dplusMaxDongles, dplusLogin); + wxLogInfo(wxT("D-Plus enabled: %d, max. dongles; %u, login: %s"), int(dplusEnabled), dplusMaxDongles, dplusLogin.c_str()); + + bool dcsEnabled, ccsEnabled; + wxString ccsHost; + m_config->getDCS(dcsEnabled, ccsEnabled, ccsHost); + wxLogInfo(wxT("DCS enabled: %d, CCS enabled: %d, server: %s"), int(dcsEnabled), int(ccsEnabled), ccsHost.c_str()); + + bool xlxEnabled; + bool xlxOverrideLocal; + wxString xlxHostsFileUrl; + m_config->getXLX(xlxEnabled, xlxOverrideLocal, xlxHostsFileUrl); + wxLogInfo(wxT("XLX enabled: %d, Override Local %d, Hosts file url: %s"), int(xlxEnabled), int(xlxOverrideLocal), xlxHostsFileUrl.c_str()); + + if (repeaterBand1.Len() > 1U || repeaterBand2.Len() > 1U || + repeaterBand3.Len() > 1U || repeaterBand4.Len() > 1U) { + wxLogInfo(wxT("DD mode enabled")); + thread->setDDModeEnabled(true); + } + + wxFileName wlFilename(wxFileName::GetHomeDir(), PRIMARY_WHITELIST_FILE_NAME); + bool exists = wlFilename.FileExists(); + + if (!exists) { + wlFilename.Assign(wxFileName::GetHomeDir(), SECONDARY_WHITELIST_FILE_NAME); + exists = wlFilename.FileExists(); + } + + if (exists) { + CCallsignList* list = new CCallsignList(wlFilename.GetFullPath()); + bool res = list->load(); + if (!res) { + wxLogError(wxT("Unable to open the white list file - %s"), wlFilename.GetFullPath().c_str()); + delete list; + } else { + wxLogInfo(wxT("%u callsigns loaded into the white list"), list->getCount()); + thread->setWhiteList(list); + } + } + + wxFileName blFilename(wxFileName::GetHomeDir(), PRIMARY_BLACKLIST_FILE_NAME); + exists = blFilename.FileExists(); + + if (!exists) { + blFilename.Assign(wxFileName::GetHomeDir(), SECONDARY_BLACKLIST_FILE_NAME); + exists = blFilename.FileExists(); + } + + if (exists) { + CCallsignList* list = new CCallsignList(blFilename.GetFullPath()); + bool res = list->load(); + if (!res) { + wxLogError(wxT("Unable to open the black list file - %s"), blFilename.GetFullPath().c_str()); + delete list; + } else { + wxLogInfo(wxT("%u callsigns loaded into the black list"), list->getCount()); + thread->setBlackList(list); + } + } + + wxFileName rlFilename(wxFileName::GetHomeDir(), RESTRICT_FILE_NAME); + exists = rlFilename.FileExists(); + if (exists) { + CCallsignList* list = new CCallsignList(rlFilename.GetFullPath()); + bool res = list->load(); + if (!res) { + wxLogError(wxT("Unable to open the restrict list file - %s"), rlFilename.GetFullPath().c_str()); + delete list; + } else { + wxLogInfo(wxT("%u callsigns loaded into the restrict list"), list->getCount()); + thread->setRestrictList(list); + } + } + + thread->setIcomRepeaterHandler(icomRepeaterHandler); + thread->setHBRepeaterHandler(hbRepeaterHandler); + thread->setDummyRepeaterHandler(dummyRepeaterHandler); + thread->setLanguage(language); + thread->setDPlus(dplusEnabled, dplusMaxDongles, dplusLogin); + thread->setDExtra(dextraEnabled, dextraMaxDongles); + thread->setDCS(dcsEnabled); + thread->setCCS(ccsEnabled, ccsHost); + thread->setXLX(xlxEnabled, xlxOverrideLocal, xlxEnabled ? CXLXHostsFileDownloader::Download(xlxHostsFileUrl) : wxString(wxEmptyString)); + thread->setInfoEnabled(infoEnabled); + thread->setEchoEnabled(echoEnabled); + thread->setDTMFEnabled(dtmfEnabled); + thread->setLog(logEnabled); + thread->setLocation(latitude, longitude); + + // Convert the worker class into a thread + m_thread = new CIRCDDBGatewayThreadHelper(thread); + m_thread->start(); +} diff --git a/ircDDBGateway/IRCDDBGatewayApp.h b/ircDDBGateway/IRCDDBGatewayApp.h new file mode 100644 index 0000000..6486931 --- /dev/null +++ b/ircDDBGateway/IRCDDBGatewayApp.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2010-2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef IRCDDBGatewayApp_H +#define IRCDDBGatewayApp_H + +#include "IRCDDBGatewayThreadHelper.h" +#include "IRCDDBGatewayStatusData.h" +#include "IRCDDBGatewayConfig.h" +#include "IRCDDBGatewayFrame.h" +#include "Defs.h" + +#include +#include + +class CIRCDDBGatewayApp : public wxApp { + +public: + CIRCDDBGatewayApp(); + virtual ~CIRCDDBGatewayApp(); + + virtual bool OnInit(); + virtual int OnExit(); + + virtual void OnInitCmdLine(wxCmdLineParser& parser); + virtual bool OnCmdLineParsed(wxCmdLineParser& parser); + + // This is overridden because dialog boxes from threads are bad news +#if defined(__WXDEBUG__) + virtual void OnAssertFailure(const wxChar* file, int line, const wxChar* func, const wxChar* cond, const wxChar* msg); +#endif + + virtual void showLog(const wxString& text); + + virtual CIRCDDBGatewayStatusData* getStatus() const; + + virtual void setPosition(int x, int y); + +private: + wxString m_name; + bool m_nolog; + bool m_gui; + wxString m_logDir; + wxString m_confDir; + CIRCDDBGatewayFrame* m_frame; + CIRCDDBGatewayThreadHelper* m_thread; + CIRCDDBGatewayConfig* m_config; + wxSingleInstanceChecker* m_checker; + wxLogChain* m_logChain; + + void createThread(); +}; + +DECLARE_APP(CIRCDDBGatewayApp) + +#endif diff --git a/ircDDBGateway/IRCDDBGatewayAppD.cpp b/ircDDBGateway/IRCDDBGatewayAppD.cpp new file mode 100644 index 0000000..ced3177 --- /dev/null +++ b/ircDDBGateway/IRCDDBGatewayAppD.cpp @@ -0,0 +1,916 @@ +/* + * Copyright (C) 2010-2013,2015 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "DummyRepeaterProtocolHandler.h" +#include "IcomRepeaterProtocolHandler.h" +#include "HBRepeaterProtocolHandler.h" +#include "IRCDDBGatewayConfig.h" +#include "IRCDDBGatewayAppD.h" +#include "IRCDDBGatewayDefs.h" +#include "CallsignList.h" +#include "APRSWriter.h" +#include "Version.h" +#include "Logger.h" +#include "IRCDDB.h" +#include "IRCDDBClient.h" +#include "IRCDDBMultiClient.h" +#include "Utils.h" +#include "XLXHostsFileDownloader.h" + +#include +#include +#include +#include + +#include +#include +#include +#include + +const wxChar* NAME_PARAM = wxT("Gateway Name"); +const wxChar* NOLOGGING_SWITCH = wxT("nolog"); +const wxChar* LOGDIR_OPTION = wxT("logdir"); +const wxChar* CONFDIR_OPTION = wxT("confdir"); +const wxChar* DAEMON_SWITCH = wxT("daemon"); + +const wxString LOG_BASE_NAME = wxT("ircddbgatewayd"); + +static CIRCDDBGatewayAppD* m_gateway = NULL; + +static void handler(int signum) +{ + m_gateway->kill(); +} + +int main(int argc, char** argv) +{ + bool res = ::wxInitialize(); + if (!res) { + ::fprintf(stderr, "ircddbgatewayd: failed to initialise the wxWidgets library, exiting\n"); + return -1; + } + + wxCmdLineParser parser(argc, argv); + parser.AddSwitch(NOLOGGING_SWITCH, wxEmptyString, wxEmptyString, wxCMD_LINE_PARAM_OPTIONAL); + parser.AddSwitch(DAEMON_SWITCH, wxEmptyString, wxEmptyString, wxCMD_LINE_PARAM_OPTIONAL); + parser.AddOption(LOGDIR_OPTION, wxEmptyString, wxEmptyString, wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL); + parser.AddOption(CONFDIR_OPTION, wxEmptyString, wxEmptyString, wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL); + parser.AddParam(NAME_PARAM, wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL); + + int cmd = parser.Parse(); + if (cmd != 0) { + ::wxUninitialize(); + return 0; + } + + bool nolog = parser.Found(NOLOGGING_SWITCH); + bool daemon = parser.Found(DAEMON_SWITCH); + + wxString logDir; + bool found = parser.Found(LOGDIR_OPTION, &logDir); + if (!found) + logDir.Clear(); + + wxString confDir; + found = parser.Found(CONFDIR_OPTION, &confDir); + if (!found) + confDir = wxT(CONF_DIR); + + wxString name; + if (parser.GetParamCount() > 0U) + name = parser.GetParam(0U); + + if (daemon) { + pid_t pid = ::fork(); + + if (pid < 0) { + ::fprintf(stderr, "ircddbgatewayd: error in fork(), exiting\n"); + ::wxUninitialize(); + return 1; + } + + // If this is the parent, exit + if (pid > 0) + return 0; + + // We are the child from here onwards + ::setsid(); + + if(::chdir("/") == -1) + ::fprintf(stderr, "ircddbgatewayd: error changing directory %s\n", strerror(errno)); + + ::umask(0); + } + + wxString pidFileName; + if (!name.IsEmpty()) + pidFileName.Printf(wxT("/var/run/ircddbgateway_%s.pid"), name.c_str()); + else + pidFileName = wxT("/var/run/ircddbgateway.pid"); + pidFileName.Replace(wxT(" "), wxT("_")); + + char fileName[128U]; + ::memset(fileName, 0x00U, 128U); + for (unsigned int i = 0U; i < pidFileName.Len(); i++) + fileName[i] = pidFileName.GetChar(i); + + FILE* fp = ::fopen(fileName, "wt"); + if (fp != NULL) { + ::fprintf(fp, "%u\n", ::getpid()); + ::fclose(fp); + } + + m_gateway = new CIRCDDBGatewayAppD(nolog, logDir, confDir, name); + if (!m_gateway->init()) { + ::wxUninitialize(); + return 1; + } + + ::signal(SIGUSR1, handler); + + m_gateway->run(); + + delete m_gateway; + + ::unlink(fileName); + + ::wxUninitialize(); + + return 0; +} + +CIRCDDBGatewayAppD::CIRCDDBGatewayAppD(bool nolog, const wxString& logDir, const wxString& confDir, const wxString& name) : +m_name(name), +m_nolog(nolog), +m_logDir(logDir), +m_confDir(confDir), +m_thread(NULL), +m_checker(NULL) +{ +} + +CIRCDDBGatewayAppD::~CIRCDDBGatewayAppD() +{ +} + +bool CIRCDDBGatewayAppD::init() +{ + if (!m_nolog) { + wxString logBaseName = LOG_BASE_NAME; + if (!m_name.IsEmpty()) { + logBaseName.Append(wxT("_")); + logBaseName.Append(m_name); + } + + if (m_logDir.IsEmpty()) + m_logDir = wxT(LOG_DIR); + + wxLog* log = new CLogger(m_logDir, logBaseName); + wxLog::SetActiveTarget(log); + } else { + new wxLogNull; + } + + wxString appName; + if (!m_name.IsEmpty()) + appName = APPLICATION_NAME + wxT(" ") + m_name; + else + appName = APPLICATION_NAME; + appName.Replace(wxT(" "), wxT("_")); + + m_checker = new wxSingleInstanceChecker(appName, wxT("/tmp")); + bool ret = m_checker->IsAnotherRunning(); + if (ret) { + wxLogError(wxT("Another copy of the ircDDB Gateway is running, exiting")); + return false; + } + + wxLogInfo(wxT("Starting ") + APPLICATION_NAME + wxT(" daemon - ") + VERSION); + + // Log the version of wxWidgets and the Operating System + wxLogInfo(wxT("Using wxWidgets %d.%d.%d on %s"), wxMAJOR_VERSION, wxMINOR_VERSION, wxRELEASE_NUMBER, ::wxGetOsDescription().c_str()); + + return createThread(); +} + +void CIRCDDBGatewayAppD::run() +{ + m_thread->run(); + + delete m_checker; + + wxLogInfo(APPLICATION_NAME + wxT(" is exiting")); +} + +bool CIRCDDBGatewayAppD::createThread() +{ + CIRCDDBGatewayConfig config(m_confDir, CONFIG_FILE_NAME, m_name); + + m_thread = new CIRCDDBGatewayThread(m_logDir, m_name); + + GATEWAY_TYPE gatewayType; + wxString gatewayCallsign, gatewayAddress, icomAddress, hbAddress, description1, description2, url; + unsigned int icomPort, hbPort; + double latitude, longitude; + config.getGateway(gatewayType, gatewayCallsign, gatewayAddress, icomAddress, icomPort, hbAddress, hbPort, latitude, longitude, description1, description2, url); + + gatewayCallsign.MakeUpper(); + gatewayCallsign.Append(wxT(" ")); + gatewayCallsign.Truncate(LONG_CALLSIGN_LENGTH - 1U); + + wxString callsign = gatewayCallsign; + callsign.Append(wxT(" ")); + + gatewayCallsign.Append(wxT("G")); + + wxLogInfo(wxT("Gateway type: %d, callsign: \"%s\", address: %s, Icom address: %s:%u, homebrew address: %s:%u, latitude: %lf, longitude: %lf, description: \"%s %s\", URL: \"%s\""), int(gatewayType), gatewayCallsign.c_str(), gatewayAddress.c_str(), icomAddress.c_str(), icomPort, hbAddress.c_str(), hbPort, latitude, longitude, description1.c_str(), description2.c_str(), url.c_str()); + + m_thread->setGateway(gatewayType, gatewayCallsign, gatewayAddress); + + wxString aprsHostname; + unsigned int aprsPort; + bool aprsEnabled; + config.getDPRS(aprsEnabled, aprsHostname, aprsPort); + wxLogInfo(wxT("APRS enabled: %d, host: %s:%u"), int(aprsEnabled), aprsHostname.c_str(), aprsPort); + + CAPRSWriter* aprs = NULL; + if (aprsEnabled && !gatewayCallsign.IsEmpty() && !aprsHostname.IsEmpty() && aprsPort != 0U) { + aprs = new CAPRSWriter(aprsHostname, aprsPort, gatewayCallsign, gatewayAddress); + + bool res = aprs->open(); + if (!res) + wxLogError(wxT("Cannot initialise the APRS data writer")); + else + m_thread->setAPRSWriter(aprs); + } + + TEXT_LANG language; + bool infoEnabled, echoEnabled, logEnabled, dratsEnabled, dtmfEnabled; + config.getMiscellaneous(language, infoEnabled, echoEnabled, logEnabled, dratsEnabled, dtmfEnabled); + wxLogInfo(wxT("Language: %d, info enabled: %d, echo enabled: %d, log enabled : %d, D-RATS enabled: %d, DTMF control enabled: %d"), int(language), int(infoEnabled), int(echoEnabled), int(logEnabled), int(dratsEnabled), int(dtmfEnabled)); + + CIcomRepeaterProtocolHandler* icomRepeaterHandler = NULL; + CHBRepeaterProtocolHandler* hbRepeaterHandler = NULL; + CDummyRepeaterProtocolHandler* dummyRepeaterHandler = NULL; + + unsigned int icomCount = 0U; + + wxString repeaterCall1, repeaterBand1, repeaterAddress1, reflector1, description11, description12, url1; + double frequency1, offset1, range1, latitude1, longitude1, agl1; + unsigned char band11, band12, band13; + unsigned int repeaterPort1; + HW_TYPE repeaterType1; + bool atStartup1; + RECONNECT reconnect1; + config.getRepeater1(repeaterCall1, repeaterBand1, repeaterType1, repeaterAddress1, repeaterPort1, band11, band12, band13, reflector1, atStartup1, reconnect1, frequency1, offset1, range1, latitude1, longitude1, agl1, description11, description12, url1); + + CUtils::clean(description11, wxT("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 .,&*()-+=@/?:;")); + CUtils::clean(description12, wxT("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 .,&*()-+=@/?:;")); + CUtils::clean(url1, wxT("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 .,&*()-+=@/?:;")); + + wxString callsign1 = callsign; + if (!repeaterBand1.IsSameAs(wxT(" "))) { + if (!repeaterCall1.IsEmpty()) { + callsign1 = repeaterCall1; + callsign1.Append(wxT(" ")); + callsign1.Truncate(LONG_CALLSIGN_LENGTH); + } + + wxLogInfo(wxT("Repeater 1 callsign: \"%.7s%s\", hardware type: %d, address: %s:%u"), callsign1.c_str(), repeaterBand1.c_str(), int(repeaterType1), repeaterAddress1.c_str(), repeaterPort1); + wxLogInfo(wxT("Repeater 1 reflector: %s, at startup: %d, reconnect: %d"), reflector1.c_str(), atStartup1, reconnect1); + wxLogInfo(wxT("Repeater 1 latitude: %lf, longitude: %lf, range: %.0lf kms, height: %.0lf m, frequency: %.4lf MHz, offset: %.4lf MHz"), latitude1, longitude1, range1, agl1, frequency1, offset1); + wxLogInfo(wxT("Repeater 1 description: \"%s %s\", URL: \"%s\""), description11.c_str(), description12.c_str(), url1.c_str()); + + if (repeaterType1 == HW_ICOM && !icomAddress.IsEmpty()) { + icomRepeaterHandler = new CIcomRepeaterProtocolHandler(icomAddress, icomPort, repeaterAddress1, repeaterPort1); + bool res = icomRepeaterHandler->open(); + if (!res) { + wxLogError(wxT("Cannot open the Icom repeater protocol handler")); + delete icomRepeaterHandler; + icomRepeaterHandler = NULL; + } + } else if (repeaterType1 == HW_HOMEBREW && !hbAddress.IsEmpty()) { + hbRepeaterHandler = new CHBRepeaterProtocolHandler(hbAddress, hbPort); + bool res = hbRepeaterHandler->open(); + if (!res) { + wxLogError(wxT("Cannot open the Homebrew repeater protocol handler")); + delete hbRepeaterHandler; + hbRepeaterHandler = NULL; + } + } else if (repeaterType1 == HW_DUMMY && !hbAddress.IsEmpty()) { + dummyRepeaterHandler = new CDummyRepeaterProtocolHandler; + bool res = dummyRepeaterHandler->open(); + if (!res) { + wxLogError(wxT("Cannot open the Dummy repeater protocol handler")); + delete dummyRepeaterHandler; + dummyRepeaterHandler = NULL; + } + } + + if (latitude1 == 0.0 && longitude1 == 0.0) { + latitude1 = latitude; + longitude1 = longitude; + } + + if (description11.IsEmpty()) + description11 = description1; + if (description12.IsEmpty()) + description12 = description2; + + if (url1.IsEmpty()) + url1 = url; + + if (repeaterType1 == HW_ICOM && icomRepeaterHandler != NULL) { + wxLogInfo(wxT("Repeater 1 bands: %u %u %u"), band11, band12, band13); + m_thread->addRepeater(callsign1, repeaterBand1, repeaterAddress1, repeaterPort1, repeaterType1, reflector1, atStartup1, reconnect1, dratsEnabled, frequency1, offset1, range1, latitude1, longitude1, agl1, description11, description12, url1, icomRepeaterHandler, band11, band12, band13); + + if (aprs != NULL) + aprs->setPort(callsign1, repeaterBand1, frequency1, offset1, range1, latitude1, longitude1, agl1); + + icomCount++; + } else if (repeaterType1 == HW_HOMEBREW && hbRepeaterHandler != NULL) { + m_thread->addRepeater(callsign1, repeaterBand1, repeaterAddress1, repeaterPort1, repeaterType1, reflector1, atStartup1, reconnect1, dratsEnabled, frequency1, offset1, range1, latitude1, longitude1, agl1, description11, description12, url1, hbRepeaterHandler); + + if (aprs != NULL) + aprs->setPort(callsign1, repeaterBand1, frequency1, offset1, range1, latitude1, longitude1, agl1); + } else if (repeaterType1 == HW_DUMMY && dummyRepeaterHandler != NULL) { + m_thread->addRepeater(callsign1, repeaterBand1, repeaterAddress1, repeaterPort1, repeaterType1, reflector1, atStartup1, reconnect1, dratsEnabled, frequency1, offset1, range1, latitude1, longitude1, agl1, description11, description12, url1, dummyRepeaterHandler); + } + } + + wxString repeaterCall2, repeaterBand2, repeaterAddress2, reflector2, description21, description22, url2; + double frequency2, offset2, range2, latitude2, longitude2, agl2; + unsigned char band21, band22, band23; + unsigned int repeaterPort2; + HW_TYPE repeaterType2; + bool atStartup2; + RECONNECT reconnect2; + config.getRepeater2(repeaterCall2, repeaterBand2, repeaterType2, repeaterAddress2, repeaterPort2, band21, band22, band23, reflector2, atStartup2, reconnect2, frequency2, offset2, range2, latitude2, longitude2, agl2, description21, description22, url2); + + CUtils::clean(description21, wxT("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 .,&*()-+=@/?:;")); + CUtils::clean(description22, wxT("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 .,&*()-+=@/?:;")); + CUtils::clean(url2, wxT("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 .,&*()-+=@/?:;")); + + wxString callsign2 = callsign; + if (!repeaterBand2.IsSameAs(wxT(" "))) { + if (!repeaterCall2.IsEmpty()) { + callsign2 = repeaterCall2; + callsign2.Append(wxT(" ")); + callsign2.Truncate(LONG_CALLSIGN_LENGTH); + } + + wxLogInfo(wxT("Repeater 2 callsign: \"%.7s%s\", hardware type: %d, address: %s:%u"), callsign2.c_str(), repeaterBand2.c_str(), int(repeaterType2), repeaterAddress2.c_str(), repeaterPort2); + wxLogInfo(wxT("Repeater 2 reflector: %s, at startup: %d, reconnect: %d"), reflector2.c_str(), atStartup2, reconnect2); + wxLogInfo(wxT("Repeater 2 latitude: %lf, longitude: %lf, range: %.0lf kms, height: %.0lf m, frequency: %.4lf MHz, offset: %.4lf MHz"), latitude2, longitude2, range2, agl2, frequency2, offset2); + wxLogInfo(wxT("Repeater 2 description: \"%s %s\", URL: \"%s\""), description21.c_str(), description22.c_str(), url2.c_str()); + + if (callsign1.IsSameAs(callsign2) && repeaterBand1.IsSameAs(repeaterBand2)) { + wxLogError(wxT("Repeater 2 has the same callsign and module as repeater 1, exiting")); + return false; + } + + if (repeaterType2 == HW_ICOM && !icomAddress.IsEmpty() && icomRepeaterHandler == NULL) { + icomRepeaterHandler = new CIcomRepeaterProtocolHandler(icomAddress, icomPort, repeaterAddress2, repeaterPort2); + bool res = icomRepeaterHandler->open(); + if (!res) { + wxLogError(wxT("Cannot open the Icom repeater protocol handler")); + delete icomRepeaterHandler; + icomRepeaterHandler = NULL; + } + } else if (repeaterType2 == HW_HOMEBREW && !hbAddress.IsEmpty() && hbRepeaterHandler == NULL) { + hbRepeaterHandler = new CHBRepeaterProtocolHandler(hbAddress, hbPort); + bool res = hbRepeaterHandler->open(); + if (!res) { + wxLogError(wxT("Cannot open the Homebrew repeater protocol handler")); + delete hbRepeaterHandler; + hbRepeaterHandler = NULL; + } + } else if (repeaterType2 == HW_DUMMY && !hbAddress.IsEmpty() && dummyRepeaterHandler == NULL) { + dummyRepeaterHandler = new CDummyRepeaterProtocolHandler; + bool res = dummyRepeaterHandler->open(); + if (!res) { + wxLogError(wxT("Cannot open the Dummy repeater protocol handler")); + delete dummyRepeaterHandler; + dummyRepeaterHandler = NULL; + } + } + + if (latitude2 == 0.0 && longitude2 == 0.0) { + latitude2 = latitude; + longitude2 = longitude; + } + + if (description21.IsEmpty()) + description21 = description1; + if (description22.IsEmpty()) + description22 = description2; + + if (url2.IsEmpty()) + url2 = url; + + if (repeaterType2 == HW_ICOM && icomRepeaterHandler != NULL) { + wxLogInfo(wxT("Repeater 2 bands: %u %u %u"), band21, band22, band23); + m_thread->addRepeater(callsign2, repeaterBand2, repeaterAddress2, repeaterPort2, repeaterType2, reflector2, atStartup2, reconnect2, dratsEnabled, frequency2, offset2, range2, latitude2, longitude2, agl2, description21, description22, url2, icomRepeaterHandler, band21, band22, band23); + + if (aprs != NULL) + aprs->setPort(callsign2, repeaterBand2, frequency2, offset2, range2, latitude2, longitude2, agl2); + + icomCount++; + } else if (repeaterType2 == HW_HOMEBREW && hbRepeaterHandler != NULL) { + m_thread->addRepeater(callsign2, repeaterBand2, repeaterAddress2, repeaterPort2, repeaterType2, reflector2, atStartup2, reconnect2, dratsEnabled, frequency2, offset2, range2, latitude2, longitude2, agl2, description21, description22, url2, hbRepeaterHandler); + + if (aprs != NULL) + aprs->setPort(callsign2, repeaterBand2, frequency2, offset2, range2, latitude2, longitude2, agl2); + } else if (repeaterType2 == HW_DUMMY && dummyRepeaterHandler != NULL) { + m_thread->addRepeater(callsign2, repeaterBand2, repeaterAddress2, repeaterPort2, repeaterType2, reflector2, atStartup2, reconnect2, dratsEnabled, frequency2, offset2, range2, latitude2, longitude2, agl2, description21, description22, url2, dummyRepeaterHandler); + } + } + + wxString repeaterCall3, repeaterBand3, repeaterAddress3, reflector3, description31, description32, url3; + double frequency3, offset3, range3, latitude3, longitude3, agl3; + unsigned char band31, band32, band33; + unsigned int repeaterPort3; + HW_TYPE repeaterType3; + bool atStartup3; + RECONNECT reconnect3; + config.getRepeater3(repeaterCall3, repeaterBand3, repeaterType3, repeaterAddress3, repeaterPort3, band31, band32, band33, reflector3, atStartup3, reconnect3, frequency3, offset3, range3, latitude3, longitude3, agl3, description31, description32, url3); + + CUtils::clean(description31, wxT("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 .,&*()-+=@/?:;")); + CUtils::clean(description32, wxT("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 .,&*()-+=@/?:;")); + CUtils::clean(url3, wxT("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 .,&*()-+=@/?:;")); + + wxString callsign3 = callsign; + if (!repeaterBand3.IsSameAs(wxT(" "))) { + if (!repeaterCall3.IsEmpty()) { + callsign3 = repeaterCall3; + callsign3.Append(wxT(" ")); + callsign3.Truncate(LONG_CALLSIGN_LENGTH); + } + + wxLogInfo(wxT("Repeater 3 callsign: \"%.7s%s\", hardware type: %d, address: %s:%u"), callsign3.c_str(), repeaterBand3.c_str(), int(repeaterType3), repeaterAddress3.c_str(), repeaterPort3); + wxLogInfo(wxT("Repeater 3 reflector: %s, at startup: %d, reconnect: %d"), reflector3.c_str(), atStartup3, reconnect3); + wxLogInfo(wxT("Repeater 3 latitude: %lf, longitude: %lf, range: %.0lf kms, height: %.0lf m, frequency: %.4lf MHz, offset: %.4lf MHz"), latitude3, longitude3, range3, agl3, frequency3, offset3); + wxLogInfo(wxT("Repeater 3 description: \"%s %s\", URL: \"%s\""), description31.c_str(), description32.c_str(), url3.c_str()); + + if (callsign1.IsSameAs(callsign3) && repeaterBand1.IsSameAs(repeaterBand3)) { + wxLogError(wxT("Repeater 3 has the same callsign and module as repeater 1, exiting")); + return false; + } + if (callsign2.IsSameAs(callsign3) && repeaterBand2.IsSameAs(repeaterBand3)) { + wxLogError(wxT("Repeater 3 has the same callsign and module as repeater 2, exiting")); + return false; + } + + if (repeaterType3 == HW_ICOM && !icomAddress.IsEmpty() && icomRepeaterHandler == NULL) { + icomRepeaterHandler = new CIcomRepeaterProtocolHandler(icomAddress, icomPort, repeaterAddress3, repeaterPort3); + bool res = icomRepeaterHandler->open(); + if (!res) { + wxLogError(wxT("Cannot open the Icom repeater protocol handler")); + delete icomRepeaterHandler; + icomRepeaterHandler = NULL; + } + } else if (repeaterType3 == HW_HOMEBREW && !hbAddress.IsEmpty() && hbRepeaterHandler == NULL) { + hbRepeaterHandler = new CHBRepeaterProtocolHandler(hbAddress, hbPort); + bool res = hbRepeaterHandler->open(); + if (!res) { + wxLogError(wxT("Cannot open the Homebrew repeater protocol handler")); + delete hbRepeaterHandler; + hbRepeaterHandler = NULL; + } + } else if (repeaterType3 == HW_DUMMY && !hbAddress.IsEmpty() && dummyRepeaterHandler == NULL) { + dummyRepeaterHandler = new CDummyRepeaterProtocolHandler; + bool res = dummyRepeaterHandler->open(); + if (!res) { + wxLogError(wxT("Cannot open the Dummy repeater protocol handler")); + delete dummyRepeaterHandler; + dummyRepeaterHandler = NULL; + } + } + + if (latitude3 == 0.0 && longitude3 == 0.0) { + latitude3 = latitude; + longitude3 = longitude; + } + + if (description31.IsEmpty()) + description31 = description1; + if (description32.IsEmpty()) + description32 = description2; + + if (url3.IsEmpty()) + url3 = url; + + if (repeaterType3 == HW_ICOM && icomRepeaterHandler != NULL) { + wxLogInfo(wxT("Repeater 3 bands: %u %u %u"), band31, band32, band33); + m_thread->addRepeater(callsign3, repeaterBand3, repeaterAddress3, repeaterPort3, repeaterType3, reflector3, atStartup3, reconnect3, dratsEnabled, frequency3, offset3, range3, latitude3, longitude3, agl3, description31, description32, url3, icomRepeaterHandler, band31, band32, band33); + + if (aprs != NULL) + aprs->setPort(callsign3, repeaterBand3, frequency3, offset3, range3, latitude3, longitude3, agl3); + + icomCount++; + } else if (repeaterType3 == HW_HOMEBREW && hbRepeaterHandler != NULL) { + m_thread->addRepeater(callsign3, repeaterBand3, repeaterAddress3, repeaterPort3, repeaterType3, reflector3, atStartup3, reconnect3, dratsEnabled, frequency3, offset3, range3, latitude3, longitude3, agl3, description31, description32, url3, hbRepeaterHandler); + + if (aprs != NULL) + aprs->setPort(callsign3, repeaterBand3, frequency3, offset3, range3, latitude3, longitude3, agl3); + } else if (repeaterType3 == HW_DUMMY && dummyRepeaterHandler != NULL) { + m_thread->addRepeater(callsign3, repeaterBand3, repeaterAddress3, repeaterPort3, repeaterType3, reflector3, atStartup3, reconnect3, dratsEnabled, frequency3, offset3, range3, latitude3, longitude3, agl3, description31, description32, url3, dummyRepeaterHandler); + } + } + + wxString repeaterCall4, repeaterBand4, repeaterAddress4, reflector4, description41, description42, url4; + double frequency4, offset4, range4, latitude4, longitude4, agl4; + unsigned char band41, band42, band43; + unsigned int repeaterPort4; + HW_TYPE repeaterType4; + bool atStartup4; + RECONNECT reconnect4; + config.getRepeater4(repeaterCall4, repeaterBand4, repeaterType4, repeaterAddress4, repeaterPort4, band41, band42, band43, reflector4, atStartup4, reconnect4, frequency4, offset4, range4, latitude4, longitude4, agl4, description41, description42, url4); + + CUtils::clean(description41, wxT("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 .,&*()-+=@/?:;")); + CUtils::clean(description42, wxT("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 .,&*()-+=@/?:;")); + CUtils::clean(url4, wxT("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 .,&*()-+=@/?:;")); + + wxString callsign4 = callsign; + if (!repeaterBand4.IsSameAs(wxT(" "))) { + if (!repeaterCall4.IsEmpty()) { + callsign4 = repeaterCall4; + callsign4.Append(wxT(" ")); + callsign4.Truncate(LONG_CALLSIGN_LENGTH); + } + + wxLogInfo(wxT("Repeater 4 callsign: \"%.7s%s\", hardware type: %d, address: %s:%u"), callsign4.c_str(), repeaterBand4.c_str(), int(repeaterType4), repeaterAddress4.c_str(), repeaterPort4); + wxLogInfo(wxT("Repeater 4 reflector: %s, at startup: %d, reconnect: %d"), reflector4.c_str(), atStartup4, reconnect4); + wxLogInfo(wxT("Repeater 4 latitude: %lf, longitude: %lf, range: %.0lf kms, height: %.0lf m, frequency: %.4lf MHz, offset: %.4lf MHz"), latitude4, longitude4, range4, agl4, frequency4, offset4); + wxLogInfo(wxT("Repeater 4 description: \"%s %s\", URL: \"%s\""), description41.c_str(), description42.c_str(), url4.c_str()); + + if (callsign1.IsSameAs(callsign4) && repeaterBand1.IsSameAs(repeaterBand4)) { + wxLogError(wxT("Repeater 4 has the same callsign and module as repeater 1, exiting")); + return false; + } + if (callsign2.IsSameAs(callsign4) && repeaterBand2.IsSameAs(repeaterBand4)) { + wxLogError(wxT("Repeater 4 has the same callsign and module as repeater 2, exiting")); + return false; + } + if (callsign3.IsSameAs(callsign4) && repeaterBand3.IsSameAs(repeaterBand4)) { + wxLogError(wxT("Repeater 4 has the same callsign and module as repeater 3, exiting")); + return false; + } + + if (repeaterType4 == HW_ICOM && !icomAddress.IsEmpty() && icomRepeaterHandler == NULL) { + icomRepeaterHandler = new CIcomRepeaterProtocolHandler(icomAddress, icomPort, repeaterAddress4, repeaterPort4); + bool res = icomRepeaterHandler->open(); + if (!res) { + wxLogError(wxT("Cannot open the Icom repeater protocol handler")); + delete icomRepeaterHandler; + icomRepeaterHandler = NULL; + } + } else if (repeaterType4 == HW_HOMEBREW && !hbAddress.IsEmpty() && hbRepeaterHandler == NULL) { + hbRepeaterHandler = new CHBRepeaterProtocolHandler(hbAddress, hbPort); + bool res = hbRepeaterHandler->open(); + if (!res) { + wxLogError(wxT("Cannot open the Homebrew repeater protocol handler")); + delete hbRepeaterHandler; + hbRepeaterHandler = NULL; + } + } else if (repeaterType4 == HW_DUMMY && !hbAddress.IsEmpty() && dummyRepeaterHandler == NULL) { + dummyRepeaterHandler = new CDummyRepeaterProtocolHandler; + bool res = dummyRepeaterHandler->open(); + if (!res) { + wxLogError(wxT("Cannot open the Dummy repeater protocol handler")); + delete dummyRepeaterHandler; + dummyRepeaterHandler = NULL; + } + } + + if (latitude4 == 0.0 && longitude4 == 0.0) { + latitude4 = latitude; + longitude4 = longitude; + } + + if (description41.IsEmpty()) + description41 = description1; + if (description42.IsEmpty()) + description42 = description2; + + if (url4.IsEmpty()) + url4 = url; + + if (repeaterType4 == HW_ICOM && icomRepeaterHandler != NULL) { + wxLogInfo(wxT("Repeater 4 bands: %u %u %u"), band41, band42, band43); + m_thread->addRepeater(callsign4, repeaterBand4, repeaterAddress4, repeaterPort4, repeaterType4, reflector4, atStartup4, reconnect4, dratsEnabled, frequency4, offset4, range4, latitude4, longitude4, agl4, description41, description42, url4, icomRepeaterHandler, band41, band42, band43); + + if (aprs != NULL) + aprs->setPort(callsign4, repeaterBand4, frequency4, offset4, range4, latitude4, longitude4, agl4); + + icomCount++; + } else if (repeaterType4 == HW_HOMEBREW && hbRepeaterHandler != NULL) { + m_thread->addRepeater(callsign4, repeaterBand4, repeaterAddress4, repeaterPort4, repeaterType4, reflector4, atStartup4, reconnect4, dratsEnabled, frequency4, offset4, range4, latitude4, longitude4, agl4, description41, description42, url4, hbRepeaterHandler); + + if (aprs != NULL) + aprs->setPort(callsign4, repeaterBand4, frequency4, offset4, range4, latitude4, longitude4, agl4); + } else if (repeaterType4 == HW_DUMMY && dummyRepeaterHandler != NULL) { + m_thread->addRepeater(callsign4, repeaterBand4, repeaterAddress4, repeaterPort4, repeaterType4, reflector4, atStartup4, reconnect4, dratsEnabled, frequency4, offset4, range4, latitude4, longitude4, agl4, description41, description42, url4, dummyRepeaterHandler); + } + } + + if (icomRepeaterHandler != NULL) + icomRepeaterHandler->setCount(icomCount); + + bool ircDDBAtLeastOneEnabled, ircDDBEnabled1, ircDDBEnabled2, ircDDBEnabled3, ircDDBEnabled4; + wxString ircDDBHostname1, ircDDBUsername1, ircDDBPassword1; + wxString ircDDBHostname2, ircDDBUsername2, ircDDBPassword2; + wxString ircDDBHostname3, ircDDBUsername3, ircDDBPassword3; + wxString ircDDBHostname4, ircDDBUsername4, ircDDBPassword4; + + config.getIrcDDB(ircDDBEnabled1, ircDDBHostname1, ircDDBUsername1, ircDDBPassword1); + wxLogInfo(wxT("ircDDB 1 enabled: %d, host: %s, username: %s"), int(ircDDBEnabled1), ircDDBHostname1.c_str(), ircDDBUsername1.c_str()); + + config.getIrcDDB2(ircDDBEnabled2, ircDDBHostname2, ircDDBUsername2, ircDDBPassword2); + wxLogInfo(wxT("ircDDB 2 enabled: %d, host: %s, username: %s"), int(ircDDBEnabled2), ircDDBHostname2.c_str(), ircDDBUsername2.c_str()); + + config.getIrcDDB3(ircDDBEnabled3, ircDDBHostname3, ircDDBUsername3, ircDDBPassword3); + wxLogInfo(wxT("ircDDB 3 enabled: %d, host: %s, username: %s"), int(ircDDBEnabled3), ircDDBHostname3.c_str(), ircDDBUsername3.c_str()); + + config.getIrcDDB4(ircDDBEnabled4, ircDDBHostname4, ircDDBUsername4, ircDDBPassword4); + wxLogInfo(wxT("ircDDB 4 enabled: %d, host: %s, username: %s"), int(ircDDBEnabled4), ircDDBHostname4.c_str(), ircDDBUsername4.c_str()); + + ircDDBAtLeastOneEnabled = ircDDBEnabled1 || ircDDBEnabled2 || ircDDBEnabled3 || ircDDBEnabled4; + + if (ircDDBAtLeastOneEnabled) { +#if defined(__WINDOWS__) + wxString versionInfo = wxT("win_") + LOG_BASE_NAME + wxT("-") + VERSION; +#else + wxString versionInfo = wxT("linux_") + LOG_BASE_NAME + wxT("-") + VERSION; +#endif + CIRCDDB_Array ircDDBClients; + if (ircDDBEnabled1) + ircDDBClients.Add(new CIRCDDBClient(ircDDBHostname1, 9007U, ircDDBUsername1, ircDDBPassword1, versionInfo, gatewayAddress)); + if (ircDDBEnabled2) + ircDDBClients.Add(new CIRCDDBClient(ircDDBHostname2, 9007U, ircDDBUsername2, ircDDBPassword2, versionInfo, gatewayAddress)); + if (ircDDBEnabled3) + ircDDBClients.Add(new CIRCDDBClient(ircDDBHostname3, 9007U, ircDDBUsername3, ircDDBPassword3, versionInfo, gatewayAddress)); + if (ircDDBEnabled4) + ircDDBClients.Add(new CIRCDDBClient(ircDDBHostname4, 9007U, ircDDBUsername4, ircDDBPassword4, versionInfo, gatewayAddress)); + + CIRCDDBMultiClient * ircDDB = new CIRCDDBMultiClient(ircDDBClients); + + bool res = ircDDB->open(); + if (!res) { + wxLogError(wxT("Cannot initialise the ircDDB protocol handler")); + ircDDBAtLeastOneEnabled = false; + } + else { + m_thread->setIRC(ircDDB); + } + } + + if (ircDDBAtLeastOneEnabled) { + wxString starNetBand1, starNetCallsign1, starNetLogoff1, starNetInfo1, starNetPermanent1, link1; // DEXTRA_LINK || DCS_LINK + unsigned int starNetUserTimeout1, starNetGroupTimeout1; + STARNET_CALLSIGN_SWITCH starNetCallsignSwitch1; + bool starNetTXMsgSwitch1; + config.getStarNet1(starNetBand1, starNetCallsign1, starNetLogoff1, starNetInfo1, starNetPermanent1, starNetUserTimeout1, starNetGroupTimeout1, starNetCallsignSwitch1, starNetTXMsgSwitch1 +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + ,link1 +#endif + ); + + if (!starNetCallsign1.IsEmpty() && !starNetCallsign1.IsSameAs(wxT(" "))) { + wxString repeater = gatewayCallsign; + repeater.Truncate(LONG_CALLSIGN_LENGTH - 1U); + repeater.Append(starNetBand1); + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + m_thread->addStarNet(starNetCallsign1, starNetLogoff1, repeater, starNetInfo1, starNetPermanent1, starNetUserTimeout1, starNetGroupTimeout1, starNetCallsignSwitch1, starNetTXMsgSwitch1, link1); + wxLogInfo(wxT("STARnet group 1 set to %s/%s on repeater %s, info: \"%s\", permanent: %s, user: %u mins, group: %u mins, callsign switch: %d, tx msg switch: %d, reflector: %s"), starNetCallsign1.c_str(), starNetLogoff1.c_str(), repeater.c_str(), starNetInfo1.c_str(), starNetPermanent1.c_str(), starNetUserTimeout1, starNetGroupTimeout1, int(starNetCallsignSwitch1), int(starNetTXMsgSwitch1), link1.c_str()); +#else + m_thread->addStarNet(starNetCallsign1, starNetLogoff1, repeater, starNetInfo1, starNetPermanent1, starNetUserTimeout1, starNetGroupTimeout1, starNetCallsignSwitch1, starNetTXMsgSwitch1); + wxLogInfo(wxT("STARnet group 1 set to %s/%s on repeater %s, info: \"%s\", permanent: %s, user: %u mins, group: %u mins, callsign switch: %d, tx msg switch: %d"), starNetCallsign1.c_str(), starNetLogoff1.c_str(), repeater.c_str(), starNetInfo1.c_str(), starNetPermanent1.c_str(), starNetUserTimeout1, starNetGroupTimeout1, int(starNetCallsignSwitch1), int(starNetTXMsgSwitch1)); +#endif + } + + wxString starNetBand2, starNetCallsign2, starNetLogoff2, starNetInfo2, starNetPermanent2, link2; // DEXTRA_LINK || DCS_LINK + unsigned int starNetUserTimeout2, starNetGroupTimeout2; + STARNET_CALLSIGN_SWITCH starNetCallsignSwitch2; + bool starNetTXMsgSwitch2; + config.getStarNet2(starNetBand2, starNetCallsign2, starNetLogoff2, starNetInfo2, starNetPermanent2, starNetUserTimeout2, starNetGroupTimeout2, starNetCallsignSwitch2, starNetTXMsgSwitch2 +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + ,link2 +#endif + ); + + if (!starNetCallsign2.IsEmpty() && !starNetCallsign2.IsSameAs(wxT(" "))) { + wxString repeater = gatewayCallsign; + repeater.Truncate(LONG_CALLSIGN_LENGTH - 1U); + repeater.Append(starNetBand2); + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + m_thread->addStarNet(starNetCallsign2, starNetLogoff2, repeater, starNetInfo2, starNetPermanent2, starNetUserTimeout2, starNetGroupTimeout2, starNetCallsignSwitch2, starNetTXMsgSwitch2, link2); + wxLogInfo(wxT("STARnet group 2 set to %s/%s on repeater %s, info: \"%s\", permanent: %s, user: %u mins, group: %u mins, callsign switch: %d, tx msg switch: %d, reflector: %s"), starNetCallsign2.c_str(), starNetLogoff2.c_str(), repeater.c_str(), starNetInfo2.c_str(), starNetPermanent2.c_str(), starNetUserTimeout2, starNetGroupTimeout2, int(starNetCallsignSwitch2), int(starNetTXMsgSwitch2), link2.c_str()); +#else + m_thread->addStarNet(starNetCallsign2, starNetLogoff2, repeater, starNetInfo2, starNetPermanent2, starNetUserTimeout2, starNetGroupTimeout2, starNetCallsignSwitch2, starNetTXMsgSwitch2); + wxLogInfo(wxT("STARnet group 2 set to %s/%s on repeater %s, info: \"%s\", permanent: %s, user: %u mins, group: %u mins, callsign switch: %d, tx msg switch: %d"), starNetCallsign2.c_str(), starNetLogoff2.c_str(), repeater.c_str(), starNetInfo2.c_str(), starNetPermanent2.c_str(), starNetUserTimeout2, starNetGroupTimeout2, int(starNetCallsignSwitch2), int(starNetTXMsgSwitch2)); +#endif + } + + wxString starNetBand3, starNetCallsign3, starNetLogoff3, starNetInfo3, starNetPermanent3, link3; // DEXTRA_LINK || DCS_LINK + unsigned int starNetUserTimeout3, starNetGroupTimeout3; + STARNET_CALLSIGN_SWITCH starNetCallsignSwitch3; + bool starNetTXMsgSwitch3; + config.getStarNet3(starNetBand3, starNetCallsign3, starNetLogoff3, starNetInfo3, starNetPermanent3, starNetUserTimeout3, starNetGroupTimeout3, starNetCallsignSwitch3, starNetTXMsgSwitch3 +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + ,link3 +#endif + ); + + if (!starNetCallsign3.IsEmpty() && !starNetCallsign3.IsSameAs(wxT(" "))) { + wxString repeater = gatewayCallsign; + repeater.Truncate(LONG_CALLSIGN_LENGTH - 1U); + repeater.Append(starNetBand3); + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + m_thread->addStarNet(starNetCallsign3, starNetLogoff3, repeater, starNetInfo3, starNetPermanent3, starNetUserTimeout3, starNetGroupTimeout3, starNetCallsignSwitch3, starNetTXMsgSwitch3, link3); + wxLogInfo(wxT("STARnet group 3 set to %s/%s on repeater %s, info: \"%s\", permanent: %s, user: %u mins, group: %u mins, callsign switch: %d, tx msg switch: %d, reflector: %s"), starNetCallsign3.c_str(), starNetLogoff3.c_str(), repeater.c_str(), starNetInfo3.c_str(), starNetPermanent3.c_str(), starNetUserTimeout3, starNetGroupTimeout3, int(starNetCallsignSwitch3), int(starNetTXMsgSwitch3), link3.c_str()); +#else + m_thread->addStarNet(starNetCallsign3, starNetLogoff3, repeater, starNetInfo3, starNetPermanent3, starNetUserTimeout3, starNetGroupTimeout3, starNetCallsignSwitch3, starNetTXMsgSwitch3); + wxLogInfo(wxT("STARnet group 3 set to %s/%s on repeater %s, info: \"%s\", permanent: %s, user: %u mins, group: %u mins, callsign switch: %d, tx msg switch: %d"), starNetCallsign3.c_str(), starNetLogoff3.c_str(), repeater.c_str(), starNetInfo3.c_str(), starNetPermanent3.c_str(), starNetUserTimeout3, starNetGroupTimeout3, int(starNetCallsignSwitch3), int(starNetTXMsgSwitch3)); +#endif + } + + wxString starNetBand4, starNetCallsign4, starNetLogoff4, starNetInfo4, starNetPermanent4, link4; // DEXTRA_LINK || DCS_LINK + unsigned int starNetUserTimeout4, starNetGroupTimeout4; + STARNET_CALLSIGN_SWITCH starNetCallsignSwitch4; + bool starNetTXMsgSwitch4; + config.getStarNet4(starNetBand4, starNetCallsign4, starNetLogoff4, starNetInfo4, starNetPermanent4, starNetUserTimeout4, starNetGroupTimeout4, starNetCallsignSwitch4, starNetTXMsgSwitch4 +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + ,link4 +#endif + ); + + if (!starNetCallsign4.IsEmpty() && !starNetCallsign4.IsSameAs(wxT(" "))) { + wxString repeater = gatewayCallsign; + repeater.Truncate(LONG_CALLSIGN_LENGTH - 1U); + repeater.Append(starNetBand4); + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + m_thread->addStarNet(starNetCallsign4, starNetLogoff4, repeater, starNetInfo4, starNetPermanent4, starNetUserTimeout4, starNetGroupTimeout4, starNetCallsignSwitch4, starNetTXMsgSwitch4, link4); + wxLogInfo(wxT("STARnet group 4 set to %s/%s on repeater %s, info: \"%s\", permanent: %s, user: %u mins, group: %u mins, callsign switch: %d, tx msg switch: %d, reflector: %s"), starNetCallsign4.c_str(), starNetLogoff4.c_str(), repeater.c_str(), starNetInfo4.c_str(), starNetPermanent4.c_str(), starNetUserTimeout4, starNetGroupTimeout4, int(starNetCallsignSwitch4), int(starNetTXMsgSwitch4), link4.c_str()); +#else + m_thread->addStarNet(starNetCallsign4, starNetLogoff4, repeater, starNetInfo4, starNetPermanent4, starNetUserTimeout4, starNetGroupTimeout4, starNetCallsignSwitch4, starNetTXMsgSwitch4); + wxLogInfo(wxT("STARnet group 4 set to %s/%s on repeater %s, info: \"%s\", permanent: %s, user: %u mins, group: %u mins, callsign switch: %d, tx msg switch: %d"), starNetCallsign4.c_str(), starNetLogoff4.c_str(), repeater.c_str(), starNetInfo4.c_str(), starNetPermanent4.c_str(), starNetUserTimeout4, starNetGroupTimeout4, int(starNetCallsignSwitch4), int(starNetTXMsgSwitch4)); +#endif + } + + wxString starNetBand5, starNetCallsign5, starNetLogoff5, starNetInfo5, starNetPermanent5, link5; // DEXTRA_LINK || DCS_LINK + unsigned int starNetUserTimeout5, starNetGroupTimeout5; + STARNET_CALLSIGN_SWITCH starNetCallsignSwitch5; + bool starNetTXMsgSwitch5; + config.getStarNet5(starNetBand5, starNetCallsign5, starNetLogoff5, starNetInfo5, starNetPermanent5, starNetUserTimeout5, starNetGroupTimeout5, starNetCallsignSwitch5, starNetTXMsgSwitch5 +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + ,link5 +#endif + ); + + if (!starNetCallsign5.IsEmpty() && !starNetCallsign5.IsSameAs(wxT(" "))) { + wxString repeater = gatewayCallsign; + repeater.Truncate(LONG_CALLSIGN_LENGTH - 1U); + repeater.Append(starNetBand5); + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + m_thread->addStarNet(starNetCallsign5, starNetLogoff5, repeater, starNetInfo5, starNetPermanent5, starNetUserTimeout5, starNetGroupTimeout5, starNetCallsignSwitch5, starNetTXMsgSwitch5, link5); + wxLogInfo(wxT("STARnet group 5 set to %s/%s on repeater %s, info: \"%s\", permanent: %s, user: %u mins, group: %u mins, callsign switch: %d, tx msg switch: %d, reflector: %s"), starNetCallsign5.c_str(), starNetLogoff5.c_str(), repeater.c_str(), starNetInfo5.c_str(), starNetPermanent5.c_str(), starNetUserTimeout5, starNetGroupTimeout5, int(starNetCallsignSwitch5), int(starNetTXMsgSwitch5), link5.c_str()); +#else + m_thread->addStarNet(starNetCallsign5, starNetLogoff5, repeater, starNetInfo5, starNetPermanent5, starNetUserTimeout5, starNetGroupTimeout5, starNetCallsignSwitch5, starNetTXMsgSwitch5); + wxLogInfo(wxT("STARnet group 5 set to %s/%s on repeater %s, info: \"%s\", permanent: %s, user: %u mins, group: %u mins, callsign switch: %d, tx msg switch: %d"), starNetCallsign5.c_str(), starNetLogoff5.c_str(), repeater.c_str(), starNetInfo5.c_str(), starNetPermanent5.c_str(), starNetUserTimeout5, starNetGroupTimeout5, int(starNetCallsignSwitch5), int(starNetTXMsgSwitch5)); +#endif + } + } + + bool dextraEnabled; + unsigned int dextraMaxDongles; + config.getDExtra(dextraEnabled, dextraMaxDongles); + wxLogInfo(wxT("DExtra enabled: %d, max. dongles: %u"), int(dextraEnabled), dextraMaxDongles); + + bool remoteEnabled; + wxString remotePassword; + unsigned int remotePort; + config.getRemote(remoteEnabled, remotePassword, remotePort); + wxLogInfo(wxT("Remote enabled: %d, port: %u"), int(remoteEnabled), remotePort); + m_thread->setRemote(remoteEnabled, remotePassword, remotePort); + + wxString dplusLogin; + unsigned int dplusMaxDongles; + bool dplusEnabled; + config.getDPlus(dplusEnabled, dplusMaxDongles, dplusLogin); + wxLogInfo(wxT("D-Plus enabled: %d, max. dongles; %u, login: %s"), int(dplusEnabled), dplusMaxDongles, dplusLogin.c_str()); + + bool dcsEnabled, ccsEnabled; + wxString ccsHost; + config.getDCS(dcsEnabled, ccsEnabled, ccsHost); + wxLogInfo(wxT("DCS enabled: %d, CCS enabled: %d, server: %s"), int(dcsEnabled), int(ccsEnabled), ccsHost.c_str()); + + bool xlxEnabled; + bool xlxOverrideLocal; + wxString xlxHostsFileUrl; + config.getXLX(xlxEnabled, xlxOverrideLocal, xlxHostsFileUrl); + wxLogInfo(wxT("XLX enabled: %d, Override Local %d, Hosts file url: %s"), int(xlxEnabled), int(xlxOverrideLocal), xlxHostsFileUrl.c_str()); + + if (repeaterBand1.Len() > 1U || repeaterBand2.Len() > 1U || + repeaterBand3.Len() > 1U || repeaterBand4.Len() > 1U) { + wxLogInfo(wxT("DD mode enabled")); + m_thread->setDDModeEnabled(true); + } + + wxFileName wlFilename(wxFileName::GetHomeDir(), PRIMARY_WHITELIST_FILE_NAME); + bool exists = wlFilename.FileExists(); + + if (!exists) { + wlFilename.Assign(wxFileName::GetHomeDir(), SECONDARY_WHITELIST_FILE_NAME); + exists = wlFilename.FileExists(); + } + + if (exists) { + CCallsignList* list = new CCallsignList(wlFilename.GetFullPath()); + bool res = list->load(); + if (!res) { + wxLogError(wxT("Unable to open the white list file - %s"), wlFilename.GetFullPath().c_str()); + delete list; + } else { + wxLogInfo(wxT("%u callsigns loaded into the white list"), list->getCount()); + m_thread->setWhiteList(list); + } + } + + wxFileName blFilename(wxFileName::GetHomeDir(), PRIMARY_BLACKLIST_FILE_NAME); + exists = blFilename.FileExists(); + + if (!exists) { + blFilename.Assign(wxFileName::GetHomeDir(), SECONDARY_BLACKLIST_FILE_NAME); + exists = blFilename.FileExists(); + } + + if (exists) { + CCallsignList* list = new CCallsignList(blFilename.GetFullPath()); + bool res = list->load(); + if (!res) { + wxLogError(wxT("Unable to open the black list file - %s"), blFilename.GetFullPath().c_str()); + delete list; + } else { + wxLogInfo(wxT("%u callsigns loaded into the black list"), list->getCount()); + m_thread->setBlackList(list); + } + } + + wxFileName rlFilename(wxFileName::GetHomeDir(), RESTRICT_FILE_NAME); + exists = rlFilename.FileExists(); + if (exists) { + CCallsignList* list = new CCallsignList(rlFilename.GetFullPath()); + bool res = list->load(); + if (!res) { + wxLogError(wxT("Unable to open the restrict list file - %s"), rlFilename.GetFullPath().c_str()); + delete list; + } else { + wxLogInfo(wxT("%u callsigns loaded into the restrict list"), list->getCount()); + m_thread->setRestrictList(list); + } + } + m_thread->setIcomRepeaterHandler(icomRepeaterHandler); + m_thread->setHBRepeaterHandler(hbRepeaterHandler); + m_thread->setDummyRepeaterHandler(dummyRepeaterHandler); + m_thread->setLanguage(language); + m_thread->setDPlus(dplusEnabled, dplusMaxDongles, dplusLogin); + m_thread->setDExtra(dextraEnabled, dextraMaxDongles); + m_thread->setDCS(dcsEnabled); + m_thread->setCCS(ccsEnabled, ccsHost); + m_thread->setXLX(xlxEnabled, xlxOverrideLocal, xlxEnabled ? CXLXHostsFileDownloader::Download(xlxHostsFileUrl): wxString(wxEmptyString)); + m_thread->setInfoEnabled(infoEnabled); + m_thread->setEchoEnabled(echoEnabled); + m_thread->setDTMFEnabled(dtmfEnabled); + m_thread->setLog(logEnabled); + m_thread->setLocation(latitude, longitude); + + return true; +} + +void CIRCDDBGatewayAppD::kill() +{ + wxASSERT(m_thread != NULL); + + m_thread->kill(); +} diff --git a/ircDDBGateway/IRCDDBGatewayAppD.h b/ircDDBGateway/IRCDDBGatewayAppD.h new file mode 100644 index 0000000..bee1aa4 --- /dev/null +++ b/ircDDBGateway/IRCDDBGatewayAppD.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2010-2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef IRCDDBGatewayAppD_H +#define IRCDDBGatewayAppD_H + +#include "IRCDDBGatewayThread.h" + +#include +#include +#include + +class CIRCDDBGatewayAppD { + +public: + CIRCDDBGatewayAppD(bool nolog, const wxString& logDir, const wxString& confDir, const wxString& name); + ~CIRCDDBGatewayAppD(); + + bool init(); + + void run(); + + void kill(); + +private: + wxString m_name; + bool m_nolog; + wxString m_logDir; + wxString m_confDir; + CIRCDDBGatewayThread* m_thread; + wxSingleInstanceChecker* m_checker; + + bool createThread(); +}; + +#endif diff --git a/ircDDBGateway/IRCDDBGatewayDefs.h b/ircDDBGateway/IRCDDBGatewayDefs.h new file mode 100644 index 0000000..9eac8a0 --- /dev/null +++ b/ircDDBGateway/IRCDDBGatewayDefs.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2010-2015 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef IRCDDBGatewayDefs_H +#define IRCDDBGatewayDefs_H + +#include + +const wxString APPLICATION_NAME = wxT("ircDDB Gateway"); + +const wxString CONFIG_FILE_NAME = wxT("ircddbgateway"); + +const wxString STATUS1_FILE_NAME = wxT("status1.txt"); +const wxString STATUS2_FILE_NAME = wxT("status2.txt"); +const wxString STATUS3_FILE_NAME = wxT("status3.txt"); +const wxString STATUS4_FILE_NAME = wxT("status4.txt"); +const wxString STATUS5_FILE_NAME = wxT("status5.txt"); + +const wxString PRIMARY_WHITELIST_FILE_NAME = wxT("gw_whitelist.dat"); +const wxString SECONDARY_WHITELIST_FILE_NAME = wxT("whitelist.dat"); +const wxString PRIMARY_BLACKLIST_FILE_NAME = wxT("gw_blacklist.dat"); +const wxString SECONDARY_BLACKLIST_FILE_NAME = wxT("blacklist.dat"); +const wxString RESTRICT_FILE_NAME = wxT("restrict.txt"); + +const unsigned int MAX_OUTGOING = 6U; +const unsigned int MAX_REPEATERS = 4U; +const unsigned int MAX_DEXTRA_LINKS = 5U; +const unsigned int MAX_DPLUS_LINKS = 5U; +const unsigned int MAX_DCS_LINKS = 5U; +const unsigned int MAX_STARNETS = 5U; +const unsigned int MAX_ROUTES = MAX_REPEATERS + 5U; +const unsigned int MAX_DD_ROUTES = 20U; + +#endif diff --git a/ircDDBGateway/IRCDDBGatewayFrame.cpp b/ircDDBGateway/IRCDDBGatewayFrame.cpp new file mode 100644 index 0000000..6fe3c7d --- /dev/null +++ b/ircDDBGateway/IRCDDBGatewayFrame.cpp @@ -0,0 +1,322 @@ +/* + * Copyright (C) 2010-2015 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "IRCDDBGatewayStatusData.h" +#include "IRCDDBGatewayFrame.h" +#include "IRCDDBGatewayDefs.h" +#include "IRCDDBGatewayApp.h" +#include "LogEvent.h" +#include "Version.h" + +const unsigned int BORDER_SIZE = 5U; + +#if defined(__WINDOWS__) +const unsigned int IRCDDB_WIDTH = 230U; +const unsigned int LINKED_WIDTH = 160U; +const unsigned int INCOMING_WIDTH = 320U; +const unsigned int DONGLES_WIDTH = 560U; +const unsigned int LOGTEXT_WIDTH = 560U; +#else +const unsigned int IRCDDB_WIDTH = 288U; +const unsigned int LINKED_WIDTH = 220U; +const unsigned int INCOMING_WIDTH = 385U; +const unsigned int DONGLES_WIDTH = 700U; +const unsigned int LOGTEXT_WIDTH = 700U; +#endif + +#include +#include + +DEFINE_EVENT_TYPE(LOG_EVENT) + +enum { + Menu_Edit_Preferences = 6000, + Menu_View_Updates +}; + +BEGIN_EVENT_TABLE(CIRCDDBGatewayFrame, wxFrame) + EVT_MENU(wxID_EXIT, CIRCDDBGatewayFrame::onQuit) + EVT_MENU(Menu_View_Updates, CIRCDDBGatewayFrame::onUpdates) + EVT_MENU(wxID_ABOUT, CIRCDDBGatewayFrame::onAbout) + + EVT_TIMER(-1, CIRCDDBGatewayFrame::onTimer) + + EVT_CLOSE(CIRCDDBGatewayFrame::onClose) + + EVT_CUSTOM(LOG_EVENT, wxID_ANY, CIRCDDBGatewayFrame::onLog) +END_EVENT_TABLE() + +CIRCDDBGatewayFrame::CIRCDDBGatewayFrame(const wxString& title, const wxPoint& position, bool gui) : +wxFrame(NULL, -1, title, position), +m_timer(this), +m_ircDDBStatus(NULL), +m_dprsStatus(NULL), +#if defined(__WXDEBUG__) +m_updates(true) +#else +m_updates(gui) +#endif +{ + SetMenuBar(createMenuBar()); + + wxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL); + + wxPanel* panel = new wxPanel(this); + + wxBoxSizer* panelSizer = new wxBoxSizer(wxVERTICAL); + + wxStaticBoxSizer* status1Sizer = new wxStaticBoxSizer(new wxStaticBox(panel, -1, _("Status")), wxVERTICAL); + wxFlexGridSizer* status2Sizer = new wxFlexGridSizer(6); + + wxStaticText* ircDDBStatusLabel = new wxStaticText(panel, -1, _("ircDDB:")); + status2Sizer->Add(ircDDBStatusLabel, 0, wxALL, BORDER_SIZE); + + m_ircDDBStatus = new wxStaticText(panel, -1, wxEmptyString, wxDefaultPosition, wxSize(IRCDDB_WIDTH, -1)); + status2Sizer->Add(m_ircDDBStatus, 0, wxALL, BORDER_SIZE); + + wxStaticText* dprsStatusLabel = new wxStaticText(panel, -1, _("D-PRS:")); + status2Sizer->Add(dprsStatusLabel, 0, wxALL, BORDER_SIZE); + + m_dprsStatus = new wxStaticText(panel, -1, wxEmptyString, wxDefaultPosition, wxSize(IRCDDB_WIDTH, -1)); + status2Sizer->Add(m_dprsStatus, 0, wxALL, BORDER_SIZE); + + status1Sizer->Add(status2Sizer); + panelSizer->Add(status1Sizer, 0, wxALL, BORDER_SIZE); + + wxStaticBoxSizer* links1Sizer = new wxStaticBoxSizer(new wxStaticBox(panel, -1, _("Links")), wxVERTICAL); + wxFlexGridSizer* links2Sizer = new wxFlexGridSizer(3); + + for (unsigned int i = 0U; i < 4U; i++) { + wxString text; + text.Printf(_("Repeater %u:"), i + 1U); + + wxStaticText* repeaterLabel = new wxStaticText(panel, -1, text); + links2Sizer->Add(repeaterLabel, 0, wxALL, BORDER_SIZE); + + m_linkStatus[i] = new wxStaticText(panel, -1, wxEmptyString, wxDefaultPosition, wxSize(LINKED_WIDTH, -1)); + links2Sizer->Add(m_linkStatus[i], 0, wxALL, BORDER_SIZE); + + m_incoming[i] = new wxStaticText(panel, -1, wxEmptyString, wxDefaultPosition, wxSize(INCOMING_WIDTH, -1)); + links2Sizer->Add(m_incoming[i], 0, wxALL, BORDER_SIZE); + } + + links1Sizer->Add(links2Sizer); + panelSizer->Add(links1Sizer, 0, wxALL, BORDER_SIZE); + + wxStaticBoxSizer* dongles1Sizer = new wxStaticBoxSizer(new wxStaticBox(panel, -1, _("Dongles")), wxVERTICAL); + wxFlexGridSizer* dongles2Sizer = new wxFlexGridSizer(5); + + m_dongles = new wxStaticText(panel, -1, wxEmptyString, wxDefaultPosition, wxSize(DONGLES_WIDTH, -1)); + dongles2Sizer->Add(m_dongles, 0, wxALL, BORDER_SIZE); + + dongles1Sizer->Add(dongles2Sizer); + panelSizer->Add(dongles1Sizer, 0, wxALL, BORDER_SIZE); + + wxStaticBoxSizer* log1Sizer = new wxStaticBoxSizer(new wxStaticBox(panel, -1, _("Log")), wxVERTICAL); + wxBoxSizer* log2Sizer = new wxBoxSizer(wxVERTICAL); + + for (unsigned int i = 0U; i < 7U; i++) { + m_logLine[i] = new wxStaticText(panel, -1, wxEmptyString, wxDefaultPosition, wxSize(LOGTEXT_WIDTH, -1)); + m_logLine[i]->Wrap(LOGTEXT_WIDTH); + log2Sizer->Add(m_logLine[i], 0, wxTOP | wxLEFT | wxRIGHT, BORDER_SIZE); + } + + log1Sizer->Add(log2Sizer); + panelSizer->Add(log1Sizer, 0, wxALL, BORDER_SIZE); + + panel->SetSizer(panelSizer); + panelSizer->SetSizeHints(panel); + + mainSizer->Add(panel); + + SetSizer(mainSizer); + mainSizer->SetSizeHints(this); + + m_timer.Start(5000); +} + +CIRCDDBGatewayFrame::~CIRCDDBGatewayFrame() +{ +} + +wxMenuBar* CIRCDDBGatewayFrame::createMenuBar() +{ + wxMenu* fileMenu = new wxMenu(); + fileMenu->Append(wxID_EXIT, _("Exit")); + + wxMenu* viewMenu = new wxMenu(); + viewMenu->AppendCheckItem(Menu_View_Updates, _("GUI Updates")); + viewMenu->Check(Menu_View_Updates, m_updates); + + wxMenu* helpMenu = new wxMenu(); + helpMenu->Append(wxID_ABOUT, _("About ircDDB Gateway")); + + wxMenuBar* menuBar = new wxMenuBar(); + menuBar->Append(fileMenu, _("File")); + menuBar->Append(viewMenu, _("View")); + menuBar->Append(helpMenu, _("Help")); + + return menuBar; +} + +void CIRCDDBGatewayFrame::onQuit(wxCommandEvent&) +{ + Close(false); +} + +void CIRCDDBGatewayFrame::onClose(wxCloseEvent&) +{ + int x, y; + GetPosition(&x, &y); + if (x >= 0 && y >= 0) + ::wxGetApp().setPosition(x, y); + + Destroy(); +} + +void CIRCDDBGatewayFrame::onUpdates(wxCommandEvent& event) +{ + m_updates = event.IsChecked(); +} + +void CIRCDDBGatewayFrame::onAbout(wxCommandEvent&) +{ + wxAboutDialogInfo info; + info.AddDeveloper(wxT("Jonathan Naylor, G4KLX")); + info.AddDeveloper(wxT("Michael Dirska, DL1BFF")); + info.SetCopyright(wxT("(C) 2010-2015 using GPL v2 or later")); + info.SetName(APPLICATION_NAME); + info.SetVersion(VERSION); + info.SetDescription(_("This program allows a computer running homebrew repeaters\nto access the ircDDB network for G2 callsign and repeater routing,\nas well as D-Plus and DExtra reflectors. It includes a StarNet\nDigital server.")); + + ::wxAboutBox(info); +} + +void CIRCDDBGatewayFrame::onLog(wxEvent& event) +{ + CLogEvent& logEvent = dynamic_cast(event); + + wxString text; + + text = m_logLine[1U]->GetLabel(); + m_logLine[0U]->SetLabel(text); + + text = m_logLine[2U]->GetLabel(); + m_logLine[1U]->SetLabel(text); + + text = m_logLine[3U]->GetLabel(); + m_logLine[2U]->SetLabel(text); + + text = m_logLine[4U]->GetLabel(); + m_logLine[3U]->SetLabel(text); + + text = m_logLine[5U]->GetLabel(); + m_logLine[4U]->SetLabel(text); + + text = m_logLine[6U]->GetLabel(); + m_logLine[5U]->SetLabel(text); + + text = logEvent.getText(); + m_logLine[6U]->SetLabel(text); +} + +void CIRCDDBGatewayFrame::showLog(const wxString& text) +{ + if (!m_updates) + return; + + CLogEvent event(text, LOG_EVENT); + + AddPendingEvent(event); +} + +void CIRCDDBGatewayFrame::onTimer(wxTimerEvent&) +{ + if (!m_updates) + return; + + CIRCDDBGatewayStatusData* status = ::wxGetApp().getStatus(); + if (status == NULL) + return; + + IRCDDB_STATUS ircDDBStatus = status->getIrcDDBStatus(); + switch (ircDDBStatus) { + case IS_DISABLED: + m_ircDDBStatus->SetLabel(_("Disabled")); + break; + case IS_DISCONNECTED: + m_ircDDBStatus->SetLabel(_("Disconnected")); + break; + case IS_CONNECTING: + m_ircDDBStatus->SetLabel(_("Connecting")); + break; + default: + m_ircDDBStatus->SetLabel(_("Connected")); + break; + } + + bool dprsStatus = status->getDPRSStatus(); + if (dprsStatus) { + if (ircDDBStatus == IS_CONNECTED || ircDDBStatus == IS_DISABLED) + m_dprsStatus->SetLabel(_("Active")); + else + m_dprsStatus->SetLabel(_("Waiting")); + } else { + m_dprsStatus->SetLabel(_("Inactive")); + } + + for (unsigned int i = 0U; i < 4U; i++) { + wxString callsign = status->getCallsign(i); + if (!callsign.IsEmpty()) { + wxString text = callsign; + + wxString linkCallsign = status->getLinkCallsign(i); + + switch (status->getLinkStatus(i)) { + case LS_NONE: + text.Append(_(" Not linked")); + break; + case LS_LINKED_LOOPBACK: + case LS_LINKED_DEXTRA: + case LS_LINKED_DPLUS: + case LS_LINKED_DCS: + case LS_LINKED_CCS: + text.Append(_(" Linked to ")); + text.Append(linkCallsign); + break; + default: + text.Append(_(" Linking to ")); + text.Append(linkCallsign); + break; + } + m_linkStatus[i]->SetLabel(text); + + wxString incoming = status->getIncoming(i); + if (!incoming.IsEmpty()) { + incoming.Prepend(wxT("[ ")); + incoming.Append(wxT("]")); + } + m_incoming[i]->SetLabel(incoming); + } + } + + wxString dongles = status->getDongles(); + m_dongles->SetLabel(dongles); + + delete status; +} diff --git a/ircDDBGateway/IRCDDBGatewayFrame.h b/ircDDBGateway/IRCDDBGatewayFrame.h new file mode 100644 index 0000000..2d0b7dc --- /dev/null +++ b/ircDDBGateway/IRCDDBGatewayFrame.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2010-2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef IRCDDBGatewayFrame_H +#define IRCDDBGatewayFrame_H + +#include "Defs.h" + +#include +#include + +class CIRCDDBGatewayFrame : public wxFrame { +public: + CIRCDDBGatewayFrame(const wxString& title, const wxPoint& position, bool gui); + virtual ~CIRCDDBGatewayFrame(); + + virtual void onQuit(wxCommandEvent& event); + virtual void onUpdates(wxCommandEvent& event); + virtual void onAbout(wxCommandEvent& event); + virtual void onClose(wxCloseEvent& event); + virtual void onLog(wxEvent& event); + virtual void onTimer(wxTimerEvent& event); + + virtual void showLog(const wxString& text); + +private: + wxTimer m_timer; + wxStaticText* m_ircDDBStatus; + wxStaticText* m_dprsStatus; + wxStaticText* m_linkStatus[4]; + wxStaticText* m_incoming[4]; + wxStaticText* m_dongles; + wxStaticText* m_logLine[7]; + bool m_updates; + + DECLARE_EVENT_TABLE() + + wxMenuBar* createMenuBar(); +}; + +#endif diff --git a/ircDDBGateway/IRCDDBGatewayLogRedirect.cpp b/ircDDBGateway/IRCDDBGatewayLogRedirect.cpp new file mode 100644 index 0000000..357a59a --- /dev/null +++ b/ircDDBGateway/IRCDDBGatewayLogRedirect.cpp @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2002,2003,2009-2013,2018 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "IRCDDBGatewayLogRedirect.h" +#include "IRCDDBGatewayApp.h" + +CIRCDDBGatewayLogRedirect::CIRCDDBGatewayLogRedirect() : +wxLog() +{ +} + +CIRCDDBGatewayLogRedirect::~CIRCDDBGatewayLogRedirect() +{ +} + +void CIRCDDBGatewayLogRedirect::DoLogRecord(wxLogLevel level, const wxString& msg, const wxLogRecordInfo& info) +{ + wxString letter; + + switch (level) { + case wxLOG_FatalError: letter = wxT("F"); break; + case wxLOG_Error: letter = wxT("E"); break; + case wxLOG_Warning: letter = wxT("W"); break; + case wxLOG_Info: letter = wxT("I"); break; + case wxLOG_Message: letter = wxT("M"); break; + case wxLOG_Status: letter = wxT("M"); break; + case wxLOG_Trace: letter = wxT("T"); break; + case wxLOG_Debug: letter = wxT("D"); break; + default: letter = wxT("U"); break; + } + + struct tm* tm = ::gmtime(&info.timestamp); + + wxString message; + message.Printf(wxT("%s: %04d-%02d-%02d %02d:%02d:%02d: %s\n"), letter.c_str(), tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, msg.c_str()); + + ::wxGetApp().showLog(message); + + if (level == wxLOG_FatalError) + ::abort(); +} diff --git a/ircDDBGateway/IRCDDBGatewayLogRedirect.h b/ircDDBGateway/IRCDDBGatewayLogRedirect.h new file mode 100644 index 0000000..a7d0d16 --- /dev/null +++ b/ircDDBGateway/IRCDDBGatewayLogRedirect.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2002,2003,2009-2011,2018 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef IRCDDBGatewayLogRedirect_H +#define IRCDDBGatewayLogRedirect_H + +#include +#include + +class CIRCDDBGatewayLogRedirect : public wxLog { +public: + CIRCDDBGatewayLogRedirect(); + virtual ~CIRCDDBGatewayLogRedirect(); + + virtual void DoLogRecord(wxLogLevel level, const wxString& msg, const wxLogRecordInfo& info); + +private: +}; + +#endif diff --git a/ircDDBGateway/IRCDDBGatewayStatusData.cpp b/ircDDBGateway/IRCDDBGatewayStatusData.cpp new file mode 100644 index 0000000..17bf722 --- /dev/null +++ b/ircDDBGateway/IRCDDBGatewayStatusData.cpp @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2010,2011,2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "IRCDDBGatewayStatusData.h" + +CIRCDDBGatewayStatusData::CIRCDDBGatewayStatusData(IRCDDB_STATUS ircDDBStatus, bool dprsStatus) : +m_ircDDBStatus(ircDDBStatus), +m_dprsStatus(dprsStatus) +{ +} + +CIRCDDBGatewayStatusData::~CIRCDDBGatewayStatusData() +{ +} + +void CIRCDDBGatewayStatusData::setRepeater(unsigned int n, const wxString& callsign, LINK_STATUS linkStatus, const wxString& linkCallsign, const wxString& incoming) +{ + wxASSERT(n < 4U); + + m_callsign[n] = callsign; + m_linkStatus[n] = linkStatus; + m_linkCallsign[n] = linkCallsign; + m_incoming[n] = incoming; +} + +void CIRCDDBGatewayStatusData::setDongles(const wxString& dongles) +{ + m_dongles = dongles; +} + +IRCDDB_STATUS CIRCDDBGatewayStatusData::getIrcDDBStatus() const +{ + return m_ircDDBStatus; +} + +bool CIRCDDBGatewayStatusData::getDPRSStatus() const +{ + return m_dprsStatus; +} + +wxString CIRCDDBGatewayStatusData::getCallsign(unsigned int n) const +{ + wxASSERT(n < 4U); + + return m_callsign[n]; +} + +LINK_STATUS CIRCDDBGatewayStatusData::getLinkStatus(unsigned int n) const +{ + wxASSERT(n < 4U); + + return m_linkStatus[n]; +} + +wxString CIRCDDBGatewayStatusData::getLinkCallsign(unsigned int n) const +{ + wxASSERT(n < 4U); + + return m_linkCallsign[n]; +} + +wxString CIRCDDBGatewayStatusData::getIncoming(unsigned int n) const +{ + wxASSERT(n < 4U); + + return m_incoming[n]; +} + +wxString CIRCDDBGatewayStatusData::getDongles() const +{ + return m_dongles; +} diff --git a/ircDDBGateway/IRCDDBGatewayStatusData.h b/ircDDBGateway/IRCDDBGatewayStatusData.h new file mode 100644 index 0000000..d308337 --- /dev/null +++ b/ircDDBGateway/IRCDDBGatewayStatusData.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2010,2011,2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef IRCDDBGatewayStatusData_H +#define IRCDDBGatewayStatusData_H + +#include "Defs.h" + +#include + +class CIRCDDBGatewayStatusData { +public: + CIRCDDBGatewayStatusData(IRCDDB_STATUS ircDDBStatus, bool dprsStatus); + ~CIRCDDBGatewayStatusData(); + + void setRepeater(unsigned int n, const wxString& callsign, LINK_STATUS linkStatus, const wxString& linkCallsign, const wxString& incoming); + + void setDongles(const wxString& dongles); + + IRCDDB_STATUS getIrcDDBStatus() const; + bool getDPRSStatus() const; + + wxString getCallsign(unsigned int n) const; + LINK_STATUS getLinkStatus(unsigned int n) const; + wxString getLinkCallsign(unsigned int n) const; + wxString getIncoming(unsigned int n) const; + + wxString getDongles() const; + +private: + IRCDDB_STATUS m_ircDDBStatus; + bool m_dprsStatus; + wxString m_callsign[4]; + LINK_STATUS m_linkStatus[4]; + wxString m_linkCallsign[4]; + wxString m_incoming[4]; + wxString m_dongles; +}; + +#endif diff --git a/ircDDBGateway/IRCDDBGatewayThread.cpp b/ircDDBGateway/IRCDDBGatewayThread.cpp new file mode 100644 index 0000000..9b9f830 --- /dev/null +++ b/ircDDBGateway/IRCDDBGatewayThread.cpp @@ -0,0 +1,1389 @@ +/* + * Copyright (C) 2010-2015 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "IRCDDBGatewayThread.h" +#include "IRCDDBGatewayDefs.h" +#include "RepeaterHandler.h" +#include "StarNetHandler.h" +#include "CallsignServer.h" +#include "DExtraHandler.h" +#include "DPlusHandler.h" +#include "HeaderLogger.h" +#include "ConnectData.h" +#include "CCSHandler.h" +#include "HeaderData.h" +#include "StatusData.h" +#include "DCSHandler.h" +#include "DDHandler.h" +#include "G2Handler.h" +#include "HeardData.h" +#include "PollData.h" +#include "AMBEData.h" +#include "HostFile.h" +#include "CCSData.h" +#include "DDData.h" +#include "Utils.h" +#include "Defs.h" + +#include +#include +#include +#include +#include + + +#if defined(__WINDOWS__) +#include "Inaddr.h" +#else +#include +#endif + +const wxString LOOPBACK_ADDRESS = wxT("127.0.0.1"); + +const unsigned int REMOTE_DUMMY_PORT = 65016U; + +CIRCDDBGatewayThread::CIRCDDBGatewayThread(const wxString& logDir, const wxString& name) : +m_logDir(logDir), +m_name(name), +m_killed(false), +m_stopped(true), +m_gatewayType(GT_REPEATER), +m_gatewayCallsign(), +m_gatewayAddress(), +m_icomRepeaterHandler(NULL), +m_hbRepeaterHandler(NULL), +m_dummyRepeaterHandler(NULL), +m_dextraPool(NULL), +m_dplusPool(NULL), +m_dcsPool(NULL), +m_g2Handler(NULL), +m_aprsWriter(NULL), +m_irc(NULL), +m_cache(), +m_language(TL_ENGLISH_UK), +m_dextraEnabled(true), +m_dextraMaxDongles(0U), +m_dplusEnabled(false), +m_dplusMaxDongles(0U), +m_dplusLogin(), +m_dcsEnabled(true), +m_xlxEnabled(true), +m_xlxHostsFileName(), +m_ccsEnabled(true), +m_ccsHost(), +m_infoEnabled(true), +m_echoEnabled(true), +m_dtmfEnabled(true), +m_logEnabled(false), +m_ddModeEnabled(false), +m_lastStatus(IS_DISABLED), +m_statusTimer1(1000U, 1U), // 1 second +m_statusTimer2(1000U, 1U), // 1 second +m_remoteEnabled(false), +m_remotePassword(), +m_remotePort(0U), +m_remote(NULL), +m_statusFileTimer(1000U, 2U * 60U), // 2 minutes +m_status1(), +m_status2(), +m_status3(), +m_status4(), +m_status5(), +m_latitude(0.0), +m_longitude(0.0), +m_whiteList(NULL), +m_blackList(NULL), +m_restrictList(NULL) +{ + CHeaderData::initialise(); + CG2Handler::initialise(MAX_ROUTES); + CDExtraHandler::initialise(MAX_DEXTRA_LINKS); + CDPlusHandler::initialise(MAX_DPLUS_LINKS); + CDCSHandler::initialise(MAX_DCS_LINKS); + CRepeaterHandler::initialise(MAX_REPEATERS); + CStarNetHandler::initialise(MAX_STARNETS, m_name); + CCCSHandler::initialise(MAX_REPEATERS); + CAudioUnit::initialise(); +} + +CIRCDDBGatewayThread::~CIRCDDBGatewayThread() +{ + CHeaderData::finalise(); + CG2Handler::finalise(); + CDExtraHandler::finalise(); + CDPlusHandler::finalise(); + CDCSHandler::finalise(); + CRepeaterHandler::finalise(); + CStarNetHandler::finalise(); + CCCSHandler::finalise(); + CAudioUnit::finalise(); +} + +void CIRCDDBGatewayThread::run() +{ + // Truncate the old Links.log file + wxString fullName = LINKS_BASE_NAME; + + if (!m_name.IsEmpty()) { + fullName.Append(wxT("_")); + fullName.Append(m_name); + } + + wxFileName fileName1(m_logDir, fullName, wxT("log")); + wxLogMessage(wxT("Truncating %s"), fileName1.GetFullPath().c_str()); + + wxFFile file; + bool ret = file.Open(fileName1.GetFullPath(), wxT("wt")); + if (ret) + file.Close(); + + // Truncate the old StarNet.log file + fullName = STARNET_BASE_NAME; + + if (!m_name.IsEmpty()) { + fullName.Append(wxT("_")); + fullName.Append(m_name); + } + + wxFileName fileName2(m_logDir, fullName, wxT("log")); + wxLogMessage(wxT("Truncating %s"), fileName2.GetFullPath().c_str()); + + ret = file.Open(fileName2.GetFullPath(), wxT("wt")); + if (ret) + file.Close(); + + wxString dextraAddress = m_dextraEnabled ? m_gatewayAddress : LOOPBACK_ADDRESS; + m_dextraPool = new CDExtraProtocolHandlerPool(MAX_OUTGOING + 1U, DEXTRA_PORT, dextraAddress); + ret = m_dextraPool->open(); + if (!ret) { + wxLogError(wxT("Could not open the DExtra protocol pool")); + delete m_dextraPool; + m_dextraPool = NULL; + } else { + // Allocate the incoming port + CDExtraProtocolHandler* handler = m_dextraPool->getHandler(DEXTRA_PORT); + CDExtraHandler::setDExtraProtocolIncoming(handler); + CDExtraHandler::setDExtraProtocolHandlerPool(m_dextraPool); + } + + wxString dplusAddress = m_dplusEnabled ? m_gatewayAddress : LOOPBACK_ADDRESS; + m_dplusPool = new CDPlusProtocolHandlerPool(MAX_OUTGOING + 1U, DPLUS_PORT, dplusAddress); + ret = m_dplusPool->open(); + if (!ret) { + wxLogError(wxT("Could not open the D-Plus protocol pool")); + delete m_dplusPool; + m_dplusPool = NULL; + } else { + // Allocate the incoming port + CDPlusProtocolHandler* handler = m_dplusPool->getHandler(DPLUS_PORT); + CDPlusHandler::setDPlusProtocolIncoming(handler); + CDPlusHandler::setDPlusProtocolHandlerPool(m_dplusPool); + } + + wxString dcsAddress = m_dcsEnabled ? m_gatewayAddress : LOOPBACK_ADDRESS; + m_dcsPool = new CDCSProtocolHandlerPool(MAX_OUTGOING + 1U, DCS_PORT, dcsAddress); + ret = m_dcsPool->open(); + if (!ret) { + wxLogError(wxT("Could not open the DCS protocol pool")); + delete m_dcsPool; + m_dcsPool = NULL; + } else { + // Allocate the incoming port + CDCSProtocolHandler* handler = m_dcsPool->getHandler(DCS_PORT); + CDCSHandler::setDCSProtocolIncoming(handler); + CDCSHandler::setDCSProtocolHandlerPool(m_dcsPool); + } + + m_g2Handler = new CG2ProtocolHandler(G2_DV_PORT, m_gatewayAddress); + ret = m_g2Handler->open(); + if (!ret) { + wxLogError(wxT("Could not open the G2 protocol handler")); + delete m_g2Handler; + m_g2Handler = NULL; + } + + // Wait here until we have the essentials to run + while (!m_killed && (m_dextraPool == NULL || m_dplusPool == NULL || m_dcsPool == NULL || m_g2Handler == NULL || (m_icomRepeaterHandler == NULL && m_hbRepeaterHandler == NULL && m_dummyRepeaterHandler == NULL) || m_gatewayCallsign.IsEmpty())) + ::wxMilliSleep(500UL); // 1/2 sec + + if (m_killed) + return; + + m_stopped = false; + + wxLogMessage(wxT("Starting the ircDDB Gateway thread")); + + CHeaderLogger* headerLogger = NULL; + if (m_logEnabled) { + m_statusTimer1.start(); + + headerLogger = new CHeaderLogger(m_logDir, m_name); + ret = headerLogger->open(); + if (!ret) { + delete headerLogger; + headerLogger = NULL; + } + } + + loadGateways(); + loadReflectors(); + + CG2Handler::setG2ProtocolHandler(m_g2Handler); + CG2Handler::setHeaderLogger(headerLogger); + + CDExtraHandler::setCallsign(m_gatewayCallsign); + CDExtraHandler::setHeaderLogger(headerLogger); + CDExtraHandler::setMaxDongles(m_dextraMaxDongles); + + CDPlusHandler::setCallsign(m_gatewayCallsign); + CDPlusHandler::setDPlusLogin(m_dplusLogin); + CDPlusHandler::setHeaderLogger(headerLogger); + CDPlusHandler::setMaxDongles(m_dplusMaxDongles); + if (m_dplusEnabled) + CDPlusHandler::startAuthenticator(m_gatewayAddress, &m_cache); + + CDCSHandler::setGatewayType(m_gatewayType); + CDCSHandler::setHeaderLogger(headerLogger); + + CRepeaterHandler::setLocalAddress(m_gatewayAddress); + CRepeaterHandler::setG2Handler(m_g2Handler); + + if (m_irc != NULL) + CRepeaterHandler::setIRC(m_irc); + + CRepeaterHandler::setCache(&m_cache); + CRepeaterHandler::setGateway(m_gatewayCallsign); + CRepeaterHandler::setLanguage(m_language); + CRepeaterHandler::setDExtraEnabled(m_dextraEnabled); + CRepeaterHandler::setDPlusEnabled(m_dplusEnabled); + CRepeaterHandler::setDCSEnabled(m_dcsEnabled); + CRepeaterHandler::setHeaderLogger(headerLogger); + CRepeaterHandler::setAPRSWriter(m_aprsWriter); + CRepeaterHandler::setInfoEnabled(m_infoEnabled); + CRepeaterHandler::setEchoEnabled(m_echoEnabled); + CRepeaterHandler::setDTMFEnabled(m_dtmfEnabled); + if (m_whiteList != NULL) { + CDExtraHandler::setWhiteList(m_whiteList); + CDPlusHandler::setWhiteList(m_whiteList); + CDCSHandler::setWhiteList(m_whiteList); + } + if (m_blackList != NULL) { + CDExtraHandler::setBlackList(m_blackList); + CDPlusHandler::setBlackList(m_blackList); + CDCSHandler::setBlackList(m_blackList); + } + if (m_restrictList != NULL) + CRepeaterHandler::setRestrictList(m_restrictList); + + CAudioUnit::setLanguage(m_language); + + CStarNetHandler::setCache(&m_cache); + CStarNetHandler::setGateway(m_gatewayCallsign); + CStarNetHandler::setG2Handler(m_g2Handler); + + if (m_irc != NULL) + CStarNetHandler::setIRC(m_irc); + + CStarNetHandler::setLogging(m_logEnabled, m_logDir); +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + CStarNetHandler::link(); +#endif + + if (m_ddModeEnabled) { + CDDHandler::initialise(MAX_DD_ROUTES, m_name); + CDDHandler::setLogging(m_logEnabled, m_logDir); + CDDHandler::setHeaderLogger(headerLogger); + + if (m_irc != NULL) + CDDHandler::setIRC(m_irc); + } + + wxString ccsAddress = m_ccsEnabled ? m_gatewayAddress : LOOPBACK_ADDRESS; + CCCSHandler::setLocalAddress(ccsAddress); + CCCSHandler::setHeaderLogger(headerLogger); + CCCSHandler::setHost(m_ccsHost); + + // If no ircDDB then APRS is started immediately + if (m_aprsWriter != NULL && m_irc == NULL) + m_aprsWriter->setEnabled(true); + + if (m_remoteEnabled && !m_remotePassword.IsEmpty() && m_remotePort > 0U) { + m_remote = new CRemoteHandler(m_remotePassword, m_remotePort, m_gatewayAddress); + bool res = m_remote->open(); + if (!res) { + delete m_remote; + m_remote = NULL; + } + } + + CRepeaterHandler::startup(); + + m_statusFileTimer.start(); + + CCallsignServer* server = NULL; + if (m_dextraEnabled || m_dcsEnabled) { + server = new CCallsignServer(m_gatewayCallsign, m_gatewayAddress, &m_cache); + server->start(); + } + + wxStopWatch stopWatch; + stopWatch.Start(); + + m_statusTimer2.start(); + + try { + while (!m_killed) { + if (m_icomRepeaterHandler != NULL) + processRepeater(m_icomRepeaterHandler); + + if (m_hbRepeaterHandler != NULL) + processRepeater(m_hbRepeaterHandler); + + if (m_dummyRepeaterHandler != NULL) + processRepeater(m_dummyRepeaterHandler); + + if (m_irc != NULL) + processIrcDDB(); + + processDExtra(); + processDPlus(); + processDCS(); + processG2(); + CCCSHandler::process(); + + if (m_ddModeEnabled) + processDD(); + + if (m_remote != NULL) + m_remote->process(); + + unsigned long ms = stopWatch.Time(); + stopWatch.Start(); + + CRepeaterHandler::clock(ms); + CG2Handler::clock(ms); + CDExtraHandler::clock(ms); + CDPlusHandler::clock(ms); + CDCSHandler::clock(ms); + CStarNetHandler::clock(ms); + CDDHandler::clock(ms); + CCCSHandler::clock(ms); + + m_statusTimer2.clock(ms); + + m_statusFileTimer.clock(ms); + if (m_statusFileTimer.hasExpired()) { + readStatusFiles(); + m_statusFileTimer.start(); + } + + if (m_aprsWriter != NULL) + m_aprsWriter->clock(ms); + + if (m_logEnabled) { + m_statusTimer1.clock(ms); + if (m_statusTimer1.hasExpired()) { + bool ret1 = CDExtraHandler::stateChange(); + bool ret2 = CDPlusHandler::stateChange(); + bool ret3 = CDCSHandler::stateChange(); + bool ret4 = CCCSHandler::stateChange(); + if (ret1 || ret2 || ret3 || ret4) + writeStatus(); + + m_statusTimer1.start(); + } + } + + ::wxMilliSleep(TIME_PER_TIC_MS); + } + } + catch (std::exception& e) { + wxString message(e.what(), wxConvLocal); + wxLogError(wxT("Exception raised in the main thread - \"%s\""), message.c_str()); + } + catch (...) { + wxLogError(wxT("Unknown exception raised in the main thread")); + } + + wxLogMessage(wxT("Stopping the ircDDB Gateway thread")); + + // Unlink from all reflectors + CDExtraHandler::unlink(); + CDPlusHandler::unlink(); + CDCSHandler::unlink(); + CCCSHandler::disconnect(); + + if (m_ddModeEnabled) + CDDHandler::finalise(); + + if (server != NULL) + server->stop(); + + m_dextraPool->close(); + delete m_dextraPool; + + m_dplusPool->close(); + delete m_dplusPool; + + m_dcsPool->close(); + delete m_dcsPool; + + m_g2Handler->close(); + delete m_g2Handler; + + if (m_irc != NULL) { + m_irc->close(); + delete m_irc; + } + + if (m_icomRepeaterHandler != NULL) { + m_icomRepeaterHandler->close(); + delete m_icomRepeaterHandler; + } + + if (m_hbRepeaterHandler != NULL) { + m_hbRepeaterHandler->close(); + delete m_hbRepeaterHandler; + } + + if (m_dummyRepeaterHandler != NULL) { + m_dummyRepeaterHandler->close(); + delete m_dummyRepeaterHandler; + } + + if (m_remote != NULL) { + m_remote->close(); + delete m_remote; + } + + if (headerLogger != NULL) { + headerLogger->close(); + delete headerLogger; + } +} + +void CIRCDDBGatewayThread::kill() +{ + m_killed = true; +} + +void CIRCDDBGatewayThread::setGateway(GATEWAY_TYPE gatewayType, const wxString& gatewayCallsign, const wxString& gatewayAddress) +{ + if (!m_stopped) + return; + + m_gatewayType = gatewayType; + m_gatewayCallsign = gatewayCallsign; + m_gatewayAddress = gatewayAddress; +} + +void CIRCDDBGatewayThread::addRepeater(const wxString& callsign, const wxString& band, const wxString& address, unsigned int port, HW_TYPE hwType, const wxString& reflector, bool atStartup, RECONNECT reconnect, bool dratsEnabled, double frequency, double offset, double range, double latitude, double longitude, double agl, const wxString& description1, const wxString& description2, const wxString& url, IRepeaterProtocolHandler* handler, unsigned char band1, unsigned char band2, unsigned char band3) +{ + CRepeaterHandler::add(callsign, band, address, port, hwType, reflector, atStartup, reconnect, dratsEnabled, frequency, offset, range, latitude, longitude, agl, description1, description2, url, handler, band1, band2, band3); + + wxString repeater = callsign; + repeater.Truncate(LONG_CALLSIGN_LENGTH - 1U); + repeater.Append(band); + + // Add a fixed address and protocol for the local repeaters + m_cache.updateRepeater(repeater, m_gatewayCallsign, wxT("127.0.0.1"), DP_LOOPBACK, true, true); + + wxLogMessage(wxT("Adding %s to the cache as a local repeater"), repeater.c_str()); +} + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) +void CIRCDDBGatewayThread::addStarNet(const wxString& callsign, const wxString& logoff, const wxString& repeater, const wxString& infoText, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch, const wxString& reflector) +{ + CStarNetHandler::add(callsign, logoff, repeater, infoText, permanent, userTimeout, groupTimeout, callsignSwitch, txMsgSwitch, reflector); +} +#else +void CIRCDDBGatewayThread::addStarNet(const wxString& callsign, const wxString& logoff, const wxString& repeater, const wxString& infoText, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch) +{ + CStarNetHandler::add(callsign, logoff, repeater, infoText, permanent, userTimeout, groupTimeout, callsignSwitch, txMsgSwitch); +} +#endif + +void CIRCDDBGatewayThread::setIcomRepeaterHandler(CIcomRepeaterProtocolHandler* handler) +{ + m_icomRepeaterHandler = handler; +} + +void CIRCDDBGatewayThread::setHBRepeaterHandler(CHBRepeaterProtocolHandler* handler) +{ + m_hbRepeaterHandler = handler; +} + +void CIRCDDBGatewayThread::setDummyRepeaterHandler(CDummyRepeaterProtocolHandler* handler) +{ + m_dummyRepeaterHandler = handler; +} + +void CIRCDDBGatewayThread::setIRC(CIRCDDB* irc) +{ + wxASSERT(irc != NULL); + + m_irc = irc; + + m_lastStatus = IS_DISCONNECTED; +} + +void CIRCDDBGatewayThread::setLanguage(TEXT_LANG language) +{ + m_language = language; +} + +void CIRCDDBGatewayThread::setDExtra(bool enabled, unsigned int maxDongles) +{ + if (enabled) { + m_dextraEnabled = true; + m_dextraMaxDongles = maxDongles; + } else { + m_dextraEnabled = false; + m_dextraMaxDongles = 0U; + } +} + +void CIRCDDBGatewayThread::setDPlus(bool enabled, unsigned int maxDongles, const wxString& login) +{ + if (enabled) { + m_dplusEnabled = true; + m_dplusMaxDongles = maxDongles; + } else { + m_dplusEnabled = false; + m_dplusMaxDongles = 0U; + } + + m_dplusLogin = login; +} + +void CIRCDDBGatewayThread::setDCS(bool enabled) +{ + m_dcsEnabled = enabled; +} + +void CIRCDDBGatewayThread::setXLX(bool enabled, bool overrideLocal, const wxString& xlxHostsFileName) +{ + m_xlxEnabled = enabled; + m_xlxHostsFileName = xlxHostsFileName; + m_xlxOverrideLocal = overrideLocal; +} + +void CIRCDDBGatewayThread::setCCS(bool enabled, const wxString& host) +{ + m_ccsEnabled = enabled; + + wxFileName fileName(wxFileName::GetHomeDir(), CCS_HOSTS_FILE_NAME); + + if (!fileName.IsFileReadable()) { + wxLogMessage(wxT("File %s not readable"), fileName.GetFullPath().c_str()); +#if defined(__WINDOWS__) + fileName.Assign(::wxGetCwd(), CCS_HOSTS_FILE_NAME); +#else + fileName.Assign(wxT(DATA_DIR), CCS_HOSTS_FILE_NAME); +#endif + if (!fileName.IsFileReadable()) { + wxLogMessage(wxT("File %s not readable"), fileName.GetFullPath().c_str()); + m_ccsEnabled = false; + return; + } + } + + CHostFile hostFile(fileName.GetFullPath(), true); + + m_ccsHost = hostFile.getAddress(host); +} + +void CIRCDDBGatewayThread::setLog(bool enabled) +{ + m_logEnabled = enabled; +} + +void CIRCDDBGatewayThread::setAPRSWriter(CAPRSWriter* writer) +{ + m_aprsWriter = writer; +} + +void CIRCDDBGatewayThread::setInfoEnabled(bool enabled) +{ + m_infoEnabled = enabled; +} + +void CIRCDDBGatewayThread::setEchoEnabled(bool enabled) +{ + m_echoEnabled = enabled; +} + +void CIRCDDBGatewayThread::setDTMFEnabled(bool enabled) +{ + m_dtmfEnabled = enabled; +} + +void CIRCDDBGatewayThread::setDDModeEnabled(bool enabled) +{ + m_ddModeEnabled = enabled; +} + +void CIRCDDBGatewayThread::setLocation(double latitude, double longitude) +{ + m_latitude = latitude; + m_longitude = longitude; +} + +void CIRCDDBGatewayThread::setRemote(bool enabled, const wxString& password, unsigned int port) +{ + if (enabled) { + m_remoteEnabled = true; + m_remotePassword = password; + m_remotePort = port; + } else { + m_remoteEnabled = false; + m_remotePassword = password; + m_remotePort = REMOTE_DUMMY_PORT; + } +} + +void CIRCDDBGatewayThread::setWhiteList(CCallsignList* list) +{ + wxASSERT(list != NULL); + + m_whiteList = list; +} + +void CIRCDDBGatewayThread::setBlackList(CCallsignList* list) +{ + wxASSERT(list != NULL); + + m_blackList = list; +} + +void CIRCDDBGatewayThread::setRestrictList(CCallsignList* list) +{ + wxASSERT(list != NULL); + + m_restrictList = list; +} + +void CIRCDDBGatewayThread::processIrcDDB() +{ + // Once per second + if (m_statusTimer2.hasExpired()) { + int status = m_irc->getConnectionState(); + switch (status) { + case 0: + case 10: + if (m_lastStatus != IS_DISCONNECTED) { + wxLogInfo(wxT("Disconnected from ircDDB")); + m_lastStatus = IS_DISCONNECTED; + if (m_aprsWriter != NULL) + m_aprsWriter->setEnabled(false); + } + break; + case 7: + if (m_lastStatus != IS_CONNECTED) { + wxLogInfo(wxT("Connected to ircDDB")); + m_lastStatus = IS_CONNECTED; + if (m_aprsWriter != NULL) + m_aprsWriter->setEnabled(true); + } + break; + default: + if (m_lastStatus != IS_CONNECTING) { + wxLogInfo(wxT("Connecting to ircDDB")); + m_lastStatus = IS_CONNECTING; + if (m_aprsWriter != NULL) + m_aprsWriter->setEnabled(false); + } + break; + } + + m_statusTimer2.start(); + } + + // Process incoming ircDDB messages, updating the caches + for (;;) { + IRCDDB_RESPONSE_TYPE type = m_irc->getMessageType(); + + switch (type) { + case IDRT_USER: { + wxString user, repeater, gateway, address, timestamp; + bool res = m_irc->receiveUser(user, repeater, gateway, address, timestamp); + if (!res) + break; + + if (!address.IsEmpty()) { + wxLogMessage(wxT("USER: %s %s %s %s"), user.c_str(), repeater.c_str(), gateway.c_str(), address.c_str()); + m_cache.updateUser(user, repeater, gateway, address, timestamp, DP_DEXTRA, false, false); + } else { + wxLogMessage(wxT("USER: %s NOT FOUND"), user.c_str()); + } + } + break; + + case IDRT_REPEATER: { + wxString repeater, gateway, address; + bool res = m_irc->receiveRepeater(repeater, gateway, address); + if (!res) + break; + + CRepeaterHandler::resolveRepeater(repeater, gateway, address, DP_DEXTRA); + if (!address.IsEmpty()) { + wxLogMessage(wxT("REPEATER: %s %s %s"), repeater.c_str(), gateway.c_str(), address.c_str()); + m_cache.updateRepeater(repeater, gateway, address, DP_DEXTRA, false, false); + } else { + wxLogMessage(wxT("REPEATER: %s NOT FOUND"), repeater.c_str()); + } + } + break; + + case IDRT_GATEWAY: { + wxString gateway, address; + bool res = m_irc->receiveGateway(gateway, address); + if (!res) + break; + + CDExtraHandler::gatewayUpdate(gateway, address); + CDPlusHandler::gatewayUpdate(gateway, address); + if (!address.IsEmpty()) { + wxLogMessage(wxT("GATEWAY: %s %s"), gateway.c_str(), address.c_str()); + m_cache.updateGateway(gateway, address, DP_DEXTRA, false, false); + } else { + wxLogMessage(wxT("GATEWAY: %s NOT FOUND"), gateway.c_str()); + } + } + break; + + default: + return; + } + } +} + +void CIRCDDBGatewayThread::processRepeater(IRepeaterProtocolHandler* handler) +{ + for (;;) { + REPEATER_TYPE type = handler->read(); + + switch (type) { + case RT_POLL: { + CPollData* poll = handler->readPoll(); + if (poll != NULL) { + CRepeaterHandler* handler = CRepeaterHandler::findRepeater(*poll); + if (handler != NULL) + handler->processRepeater(*poll); + else + CRepeaterHandler::pollAllIcom(*poll); + + delete poll; + } + } + break; + + case RT_HEARD: { + CHeardData* heard = handler->readHeard(); + if (heard != NULL) { + wxString user = heard->getUser(); + wxString repeater = heard->getRepeater(); + + // Internal controller heard have identical user and repeater values + if (!repeater.IsSameAs(user)) { + CRepeaterHandler* handler = CRepeaterHandler::findDVRepeater(repeater); + if (handler == NULL) + wxLogMessage(wxT("Heard received from unknown repeater, %s"), repeater.c_str()); + else + handler->processRepeater(*heard); + + delete heard; + } + } + } + break; + + case RT_HEADER: { + CHeaderData* header = handler->readHeader(); + if (header != NULL) { + // wxLogMessage(wxT("Repeater header - My: %s/%s Your: %s Rpt1: %s Rpt2: %s Flags: %02X %02X %02X"), header->getMyCall1().c_str(), header->getMyCall2().c_str(), header->getYourCall().c_str(), header->getRptCall1().c_str(), header->getRptCall2().c_str(), header->getFlag1(), header->getFlag2(), header->getFlag3()); + + CRepeaterHandler* repeater = CRepeaterHandler::findDVRepeater(*header); + if (repeater == NULL) + wxLogMessage(wxT("Header received from unknown repeater, %s"), header->getRptCall1().c_str()); + else + repeater->processRepeater(*header); + + delete header; + } + } + break; + + case RT_AMBE: { + CAMBEData* data = handler->readAMBE(); + if (data != NULL) { + CRepeaterHandler* repeater = CRepeaterHandler::findDVRepeater(*data, false); + if (repeater != NULL) + repeater->processRepeater(*data); + + delete data; + } + } + break; + + case RT_BUSY_HEADER: { + CHeaderData* header = handler->readBusyHeader(); + if (header != NULL) { + // wxLogMessage(wxT("Repeater busy header - My: %s/%s Your: %s Rpt1: %s Rpt2: %s Flags: %02X %02X %02X"), header->getMyCall1().c_str(), header->getMyCall2().c_str(), header->getYourCall().c_str(), header->getRptCall1().c_str(), header->getRptCall2().c_str(), header->getFlag1(), header->getFlag2(), header->getFlag3()); + + CRepeaterHandler* repeater = CRepeaterHandler::findDVRepeater(*header); + if (repeater == NULL) + wxLogMessage(wxT("Busy header received from unknown repeater, %s"), header->getRptCall1().c_str()); + else + repeater->processBusy(*header); + + delete header; + } + } + break; + + case RT_BUSY_AMBE: { + CAMBEData* data = handler->readBusyAMBE(); + if (data != NULL) { + CRepeaterHandler* repeater = CRepeaterHandler::findDVRepeater(*data, true); + if (repeater != NULL) + repeater->processBusy(*data); + + delete data; + } + } + break; + + case RT_DD: { + CDDData* data = handler->readDD(); + if (data != NULL) { + // wxLogMessage(wxT("DD header - My: %s/%s Your: %s Rpt1: %s Rpt2: %s Flags: %02X %02X %02X"), data->getMyCall1().c_str(), data->getMyCall2().c_str(), data->getYourCall().c_str(), data->getRptCall1().c_str(), data->getRptCall2().c_str(), data->getFlag1(), data->getFlag2(), data->getFlag3()); + + CRepeaterHandler* repeater = CRepeaterHandler::findDDRepeater(); + if (repeater == NULL) + wxLogMessage(wxT("DD data received from unknown DD repeater, %s"), data->getRptCall1().c_str()); + else + repeater->processRepeater(*data); + + delete data; + } + } + break; + + default: + return; + } + } +} + +void CIRCDDBGatewayThread::processDExtra() +{ + for (;;) { + DEXTRA_TYPE type = m_dextraPool->read(); + + switch (type) { + case DE_POLL: { + CPollData* poll = m_dextraPool->readPoll(); + if (poll != NULL) { + CDExtraHandler::process(*poll); + delete poll; + } + } + break; + + case DE_CONNECT: { + CConnectData* connect = m_dextraPool->readConnect(); + if (connect != NULL) { + CDExtraHandler::process(*connect); + delete connect; + } + } + break; + + case DE_HEADER: { + CHeaderData* header = m_dextraPool->readHeader(); + if (header != NULL) { + // wxLogMessage(wxT("DExtra header - My: %s/%s Your: %s Rpt1: %s Rpt2: %s"), header->getMyCall1().c_str(), header->getMyCall2().c_str(), header->getYourCall().c_str(), header->getRptCall1().c_str(), header->getRptCall2().c_str()); + CDExtraHandler::process(*header); + delete header; + } + } + break; + + case DE_AMBE: { + CAMBEData* data = m_dextraPool->readAMBE(); + if (data != NULL) { + CDExtraHandler::process(*data); + delete data; + } + } + break; + + default: + return; + } + } +} + +void CIRCDDBGatewayThread::processDPlus() +{ + for (;;) { + DPLUS_TYPE type = m_dplusPool->read(); + + switch (type) { + case DP_POLL: { + CPollData* poll = m_dplusPool->readPoll(); + if (poll != NULL) { + CDPlusHandler::process(*poll); + delete poll; + } + } + break; + + case DP_CONNECT: { + CConnectData* connect = m_dplusPool->readConnect(); + if (connect != NULL) { + CDPlusHandler::process(*connect); + delete connect; + } + } + break; + + case DP_HEADER: { + CHeaderData* header = m_dplusPool->readHeader(); + if (header != NULL) { + // wxLogMessage(wxT("D-Plus header - My: %s/%s Your: %s Rpt1: %s Rpt2: %s"), header->getMyCall1().c_str(), header->getMyCall2().c_str(), header->getYourCall().c_str(), header->getRptCall1().c_str(), header->getRptCall2().c_str()); + CDPlusHandler::process(*header); + delete header; + } + } + break; + + case DP_AMBE: { + CAMBEData* data = m_dplusPool->readAMBE(); + if (data != NULL) { + CDPlusHandler::process(*data); + delete data; + } + } + break; + + default: + return; + } + } +} + +void CIRCDDBGatewayThread::processDCS() +{ + for (;;) { + DCS_TYPE type = m_dcsPool->read(); + + switch (type) { + case DC_POLL: { + CPollData* poll = m_dcsPool->readPoll(); + if (poll != NULL) { + CDCSHandler::process(*poll); + delete poll; + } + } + break; + + case DC_CONNECT: { + CConnectData* connect = m_dcsPool->readConnect(); + if (connect != NULL) { + CDCSHandler::process(*connect); + delete connect; + } + } + break; + + case DC_DATA: { + CAMBEData* data = m_dcsPool->readData(); + if (data != NULL) { + // wxLogMessage(wxT("DCS header - My: %s/%s Your: %s Rpt1: %s Rpt2: %s"), header->getMyCall1().c_str(), header->getMyCall2().c_str(), header->getYourCall().c_str(), header->getRptCall1().c_str(), header->getRptCall2().c_str()); + CDCSHandler::process(*data); + delete data; + } + } + break; + + default: + return; + } + } +} + +void CIRCDDBGatewayThread::processG2() +{ + for (;;) { + G2_TYPE type = m_g2Handler->read(); + + switch (type) { + case GT_HEADER: { + CHeaderData* header = m_g2Handler->readHeader(); + if (header != NULL) { + // wxLogMessage(wxT("G2 header - My: %s/%s Your: %s Rpt1: %s Rpt2: %s Flags: %02X %02X %02X"), header->getMyCall1().c_str(), header->getMyCall2().c_str(), header->getYourCall().c_str(), header->getRptCall1().c_str(), header->getRptCall2().c_str(), header->getFlag1(), header->getFlag2(), header->getFlag3()); + CG2Handler::process(*header); + delete header; + } + } + break; + + case GT_AMBE: { + CAMBEData* data = m_g2Handler->readAMBE(); + if (data != NULL) { + CG2Handler::process(*data); + delete data; + } + } + break; + + default: + return; + } + } +} + +void CIRCDDBGatewayThread::processDD() +{ + for (;;) { + CDDData* data = CDDHandler::read(); + if (data == NULL) + return; + + // wxLogMessage(wxT("DD header - My: %s/%s Your: %s Rpt1: %s Rpt2: %s Flags: %02X %02X %02X"), data->getMyCall1().c_str(), data->getMyCall2().c_str(), data->getYourCall().c_str(), data->getRptCall1().c_str(), data->getRptCall2().c_str(), data->getFlag1(), data->getFlag2(), data->getFlag3()); + + delete data; + } +} + +void CIRCDDBGatewayThread::loadGateways() +{ + wxFileName fileName(wxFileName::GetHomeDir(), GATEWAY_HOSTS_FILE_NAME); + if (!fileName.IsFileReadable()) + return; + + unsigned int count = 0U; + + CHostFile hostFile(fileName.GetFullPath(), false); + for (unsigned int i = 0U; i < hostFile.getCount(); i++) { + wxString gateway = hostFile.getName(i); + in_addr address = CUDPReaderWriter::lookup(hostFile.getAddress(i)); + + if (address.s_addr != INADDR_NONE) { + unsigned char* ucp = (unsigned char*)&address; + + wxString addrText; + addrText.Printf(wxT("%u.%u.%u.%u"), ucp[0U] & 0xFFU, ucp[1U] & 0xFFU, ucp[2U] & 0xFFU, ucp[3U] & 0xFFU); + + wxLogMessage(wxT("Locking %s to %s"), gateway.c_str(), addrText.c_str()); + + gateway.Append(wxT(" ")); + gateway.Truncate(LONG_CALLSIGN_LENGTH - 1U); + gateway.Append(wxT("G")); + m_cache.updateGateway(gateway, addrText, DP_DEXTRA, true, false); + + count++; + } + } + + wxLogMessage(wxT("Loaded %u of %u gateways from %s"), count, hostFile.getCount(), fileName.GetFullPath().c_str()); +} + +void CIRCDDBGatewayThread::loadReflectors() +{ + if(m_xlxEnabled && !m_xlxOverrideLocal) { + loadXLXReflectors(); + } + + if (m_dplusEnabled) { + wxFileName fileName(wxFileName::GetHomeDir(), DPLUS_HOSTS_FILE_NAME); + if (fileName.IsFileReadable()) + loadDPlusReflectors(fileName.GetFullPath()); + +#if defined(__WINDOWS__) + fileName.Assign(::wxGetCwd(), DPLUS_HOSTS_FILE_NAME); +#else + fileName.Assign(wxT(DATA_DIR), DPLUS_HOSTS_FILE_NAME); +#endif + if (fileName.IsFileReadable()) + loadDPlusReflectors(fileName.GetFullPath()); + } + + if (m_dextraEnabled) { + wxFileName fileName(wxFileName::GetHomeDir(), DEXTRA_HOSTS_FILE_NAME); + if (fileName.IsFileReadable()) + loadDExtraReflectors(fileName.GetFullPath()); + +#if defined(__WINDOWS__) + fileName.Assign(::wxGetCwd(), DEXTRA_HOSTS_FILE_NAME); +#else + fileName.Assign(wxT(DATA_DIR), DEXTRA_HOSTS_FILE_NAME); +#endif + if (fileName.IsFileReadable()) + loadDExtraReflectors(fileName.GetFullPath()); + } + + if (m_dcsEnabled) { + wxFileName fileName(wxFileName::GetHomeDir(), DCS_HOSTS_FILE_NAME); + if (fileName.IsFileReadable()) + loadDCSReflectors(fileName.GetFullPath()); + +#if defined(__WINDOWS__) + fileName.Assign(::wxGetCwd(), DCS_HOSTS_FILE_NAME); +#else + fileName.Assign(wxT(DATA_DIR), DCS_HOSTS_FILE_NAME); +#endif + if (fileName.IsFileReadable()) + loadDCSReflectors(fileName.GetFullPath()); + } + + if(m_xlxEnabled && m_xlxOverrideLocal) { + loadXLXReflectors(); + } +} + +void CIRCDDBGatewayThread::loadDExtraReflectors(const wxString& fileName) +{ + unsigned int count = 0U; + + CHostFile hostFile(fileName, false); + for (unsigned int i = 0U; i < hostFile.getCount(); i++) { + wxString reflector = hostFile.getName(i); + in_addr address = CUDPReaderWriter::lookup(hostFile.getAddress(i)); + bool lock = hostFile.getLock(i); + + if (address.s_addr != INADDR_NONE) { + unsigned char* ucp = (unsigned char*)&address; + + wxString addrText; + addrText.Printf(wxT("%u.%u.%u.%u"), ucp[0U] & 0xFFU, ucp[1U] & 0xFFU, ucp[2U] & 0xFFU, ucp[3U] & 0xFFU); + + if (lock) + wxLogMessage(wxT("Locking %s to %s"), reflector.c_str(), addrText.c_str()); + + reflector.Append(wxT(" ")); + reflector.Truncate(LONG_CALLSIGN_LENGTH - 1U); + reflector.Append(wxT("G")); + m_cache.updateGateway(reflector, addrText, DP_DEXTRA, lock, true); + + count++; + } + } + + wxLogMessage(wxT("Loaded %u of %u DExtra reflectors from %s"), count, hostFile.getCount(), fileName.c_str()); +} + +void CIRCDDBGatewayThread::loadDPlusReflectors(const wxString& fileName) +{ + unsigned int count = 0U; + + CHostFile hostFile(fileName, false); + for (unsigned int i = 0U; i < hostFile.getCount(); i++) { + wxString reflector = hostFile.getName(i); + in_addr address = CUDPReaderWriter::lookup(hostFile.getAddress(i)); + bool lock = hostFile.getLock(i); + + if (address.s_addr != INADDR_NONE) { + unsigned char* ucp = (unsigned char*)&address; + + wxString addrText; + addrText.Printf(wxT("%u.%u.%u.%u"), ucp[0U] & 0xFFU, ucp[1U] & 0xFFU, ucp[2U] & 0xFFU, ucp[3U] & 0xFFU); + + if (lock) + wxLogMessage(wxT("Locking %s to %s"), reflector.c_str(), addrText.c_str()); + + reflector.Append(wxT(" ")); + reflector.Truncate(LONG_CALLSIGN_LENGTH - 1U); + reflector.Append(wxT("G")); + m_cache.updateGateway(reflector, addrText, DP_DPLUS, lock, true); + + count++; + } + } + + wxLogMessage(wxT("Loaded %u of %u D-Plus reflectors from %s"), count, hostFile.getCount(), fileName.c_str()); +} + +void CIRCDDBGatewayThread::loadDCSReflectors(const wxString& fileName) +{ + unsigned int count = 0U; + + CHostFile hostFile(fileName, false); + for (unsigned int i = 0U; i < hostFile.getCount(); i++) { + wxString reflector = hostFile.getName(i); + in_addr address = CUDPReaderWriter::lookup(hostFile.getAddress(i)); + bool lock = hostFile.getLock(i); + + if (address.s_addr != INADDR_NONE) { + unsigned char* ucp = (unsigned char*)&address; + + wxString addrText; + addrText.Printf(wxT("%u.%u.%u.%u"), ucp[0U] & 0xFFU, ucp[1U] & 0xFFU, ucp[2U] & 0xFFU, ucp[3U] & 0xFFU); + + if (lock) + wxLogMessage(wxT("Locking %s to %s"), reflector.c_str(), addrText.c_str()); + + reflector.Append(wxT(" ")); + reflector.Truncate(LONG_CALLSIGN_LENGTH - 1U); + reflector.Append(wxT("G")); + m_cache.updateGateway(reflector, addrText, DP_DCS, lock, true); + + count++; + } + } + + wxLogMessage(wxT("Loaded %u of %u DCS reflectors from %s"), count, hostFile.getCount(), fileName.c_str()); +} + +void CIRCDDBGatewayThread::loadXLXReflectors() +{ + unsigned int count = 0U; + CHostFile hostFile = CHostFile(m_xlxHostsFileName, true); + for (unsigned int i = 0U; i < hostFile.getCount(); i++) { + wxString reflector = hostFile.getName(i); + in_addr address = CUDPReaderWriter::lookup(hostFile.getAddress(i)); + bool lock = hostFile.getLock(i); + + if (address.s_addr != INADDR_NONE) { + unsigned char* ucp = (unsigned char*)&address; + + wxString addrText; + addrText.Printf(wxT("%u.%u.%u.%u"), ucp[0U] & 0xFFU, ucp[1U] & 0xFFU, ucp[2U] & 0xFFU, ucp[3U] & 0xFFU); + + if (lock) + wxLogMessage(wxT("Locking %s to %s"), reflector.c_str(), addrText.c_str()); + + reflector.Append(wxT(" ")); + reflector.Truncate(LONG_CALLSIGN_LENGTH - 1U); + reflector.Append(wxT("G")); + + if(m_dcsEnabled && reflector.StartsWith(wxT("DCS"))) + m_cache.updateGateway(reflector, addrText, DP_DCS, lock, true); + else if(m_dextraEnabled && reflector.StartsWith(wxT("XRF"))) + m_cache.updateGateway(reflector, addrText, DP_DEXTRA, lock, true); + + count++; + } + } + + wxLogMessage(wxT("Loaded %u of %u XLX reflectors from %s"), count, hostFile.getCount(), m_xlxHostsFileName.c_str()); +} + +void CIRCDDBGatewayThread::writeStatus() +{ + wxString fullName = LINKS_BASE_NAME; + + if (!m_name.IsEmpty()) { + fullName.Append(wxT("_")); + fullName.Append(m_name); + } + + wxFileName fileName(m_logDir, fullName, wxT("log")); + + wxFFile file; + bool ret = file.Open(fileName.GetFullPath(), wxT("wt")); + if (!ret) { + wxLogError(wxT("Unable to open %s for writing"), fileName.GetFullPath().c_str()); + return; + } + + CDExtraHandler::writeStatus(file); + CDPlusHandler::writeStatus(file); + CDCSHandler::writeStatus(file); + CCCSHandler::writeStatus(file); + + file.Close(); +} + +CIRCDDBGatewayStatusData* CIRCDDBGatewayThread::getStatus() const +{ + bool aprsStatus = false; + if (m_aprsWriter != NULL) + aprsStatus = m_aprsWriter->isConnected(); + + CIRCDDBGatewayStatusData* status = new CIRCDDBGatewayStatusData(m_lastStatus, aprsStatus); + + for (unsigned int i = 0U; i < 4U; i++) { + wxString callsign, linkCallsign; + LINK_STATUS linkStatus; + bool ret = CRepeaterHandler::getRepeater(i, callsign, linkStatus, linkCallsign); + if (ret) { + wxString incoming1 = CDExtraHandler::getIncoming(callsign); + wxString incoming2 = CDCSHandler::getIncoming(callsign); + wxString incoming3 = CCCSHandler::getIncoming(callsign); + + wxString incoming; + if (!incoming1.IsEmpty()) { + incoming.Append(incoming1); + incoming.Append(wxT(" ")); + } + if (!incoming2.IsEmpty()) { + incoming.Append(incoming2); + incoming.Append(wxT(" ")); + } + if (!incoming3.IsEmpty()) { + incoming.Append(incoming3); + incoming.Append(wxT(" ")); + } + + status->setRepeater(i, callsign, linkStatus, linkCallsign, incoming); + } + } + + wxString dongles; + dongles.Append(CDExtraHandler::getDongles()); + dongles.Append(CDPlusHandler::getDongles()); + status->setDongles(dongles); + + return status; +} + +void CIRCDDBGatewayThread::readStatusFiles() +{ + readStatusFile(STATUS1_FILE_NAME, 0U, m_status1); + readStatusFile(STATUS2_FILE_NAME, 1U, m_status2); + readStatusFile(STATUS3_FILE_NAME, 2U, m_status3); + readStatusFile(STATUS4_FILE_NAME, 3U, m_status4); + readStatusFile(STATUS5_FILE_NAME, 4U, m_status5); +} + +void CIRCDDBGatewayThread::readStatusFile(const wxString& filename, unsigned int n, wxString& var) +{ + wxFileName name(wxFileName::GetHomeDir(), filename); + + wxString text; + + bool res = wxFile::Exists(name.GetFullPath()); + if (res) { + wxTextFile textFile(name.GetFullPath()); + res = textFile.Open(); + if (res) { + text = textFile.GetFirstLine(); + textFile.Close(); + } + } + + if (!var.IsSameAs(text)) { + wxLogMessage(wxT("Status %u message set to \"%s\""), n + 1U, text.c_str()); + CStatusData statusData(text, n); + CRepeaterHandler::writeStatus(statusData); + var = text; + } +} diff --git a/ircDDBGateway/IRCDDBGatewayThread.h b/ircDDBGateway/IRCDDBGatewayThread.h new file mode 100644 index 0000000..e3cc863 --- /dev/null +++ b/ircDDBGateway/IRCDDBGatewayThread.h @@ -0,0 +1,155 @@ +/* + * Copyright (C) 2010-2013,2015 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef IRCDDBGatewayThread_H +#define IRCDDBGatewayThread_H + +#include "DummyRepeaterProtocolHandler.h" +#include "IcomRepeaterProtocolHandler.h" +#include "HBRepeaterProtocolHandler.h" +#include "DExtraProtocolHandlerPool.h" +#include "DPlusProtocolHandlerPool.h" +#include "RepeaterProtocolHandler.h" +#include "IRCDDBGatewayStatusData.h" +#include "DCSProtocolHandlerPool.h" +#include "G2ProtocolHandler.h" +#include "RemoteHandler.h" +#include "CacheManager.h" +#include "CallsignList.h" +#include "APRSWriter.h" +#include "IRCDDB.h" +#include "Timer.h" +#include "Defs.h" + +#include + +class CIRCDDBGatewayThread { +public: + CIRCDDBGatewayThread(const wxString& logDir, const wxString& name); + virtual ~CIRCDDBGatewayThread(); + + virtual void setGateway(GATEWAY_TYPE type, const wxString& callsign, const wxString& address); + virtual void addRepeater(const wxString& callsign, const wxString& band, const wxString& address, unsigned int port, HW_TYPE hwType, const wxString& reflector, bool atStartup, RECONNECT reconnect, bool dratsEnabled, double frequency, double offset, double range, double latitude, double longitude, double agl, const wxString& description1, const wxString& description2, const wxString& url, IRepeaterProtocolHandler* handler, unsigned char band1 = 0x00U, unsigned char band2 = 0x00U, unsigned char band3 = 0x00U); +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + virtual void addStarNet(const wxString& callsign, const wxString& logoff, const wxString& repeater, const wxString& infoText, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch, const wxString& reflector); +#else + virtual void addStarNet(const wxString& callsign, const wxString& logoff, const wxString& repeater, const wxString& infoText, const wxString& permanent, unsigned int userTimeout, unsigned int groupTimeout, STARNET_CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch); +#endif + virtual void setIcomRepeaterHandler(CIcomRepeaterProtocolHandler* handler); + virtual void setHBRepeaterHandler(CHBRepeaterProtocolHandler* handler); + virtual void setDummyRepeaterHandler(CDummyRepeaterProtocolHandler* handler); + virtual void setIRC(CIRCDDB* irc); + virtual void setLanguage(TEXT_LANG language); + virtual void setDExtra(bool enabled, unsigned int maxDongles); + virtual void setDPlus(bool enabled, unsigned int maxDongles, const wxString& login); + virtual void setDCS(bool enabled); + virtual void setXLX(bool enabled, bool overrideLocal, const wxString& fileName); + virtual void setCCS(bool enabled, const wxString& host); + virtual void setLog(bool enabled); + virtual void setAPRSWriter(CAPRSWriter* writer); + virtual void setInfoEnabled(bool enabled); + virtual void setEchoEnabled(bool enabled); + virtual void setDTMFEnabled(bool enabled); + virtual void setDDModeEnabled(bool enabled); + virtual void setRemote(bool enabled, const wxString& password, unsigned int port); + virtual void setLocation(double latitude, double longitude); + virtual void setWhiteList(CCallsignList* list); + virtual void setBlackList(CCallsignList* list); + virtual void setRestrictList(CCallsignList* list); + + virtual CIRCDDBGatewayStatusData* getStatus() const; + + virtual void run(); + virtual void kill(); + +private: + wxString m_logDir; + wxString m_name; + bool m_killed; + bool m_stopped; + GATEWAY_TYPE m_gatewayType; + wxString m_gatewayCallsign; + wxString m_gatewayAddress; + CIcomRepeaterProtocolHandler* m_icomRepeaterHandler; + CHBRepeaterProtocolHandler* m_hbRepeaterHandler; + CDummyRepeaterProtocolHandler* m_dummyRepeaterHandler; + CDExtraProtocolHandlerPool* m_dextraPool; + CDPlusProtocolHandlerPool* m_dplusPool; + CDCSProtocolHandlerPool* m_dcsPool; + CG2ProtocolHandler* m_g2Handler; + CAPRSWriter* m_aprsWriter; + CIRCDDB* m_irc; + CCacheManager m_cache; + TEXT_LANG m_language; + bool m_dextraEnabled; + unsigned int m_dextraMaxDongles; + bool m_dplusEnabled; + unsigned int m_dplusMaxDongles; + wxString m_dplusLogin; + bool m_dcsEnabled; + bool m_xlxEnabled; + bool m_xlxOverrideLocal; + wxString m_xlxHostsFileName; + bool m_ccsEnabled; + wxString m_ccsHost; + bool m_infoEnabled; + bool m_echoEnabled; + bool m_dtmfEnabled; + bool m_logEnabled; + bool m_ddModeEnabled; + IRCDDB_STATUS m_lastStatus; + CTimer m_statusTimer1; + CTimer m_statusTimer2; + bool m_remoteEnabled; + wxString m_remotePassword; + unsigned int m_remotePort; + CRemoteHandler* m_remote; + CTimer m_statusFileTimer; + wxString m_status1; + wxString m_status2; + wxString m_status3; + wxString m_status4; + wxString m_status5; + double m_latitude; + double m_longitude; + CCallsignList* m_whiteList; + CCallsignList* m_blackList; + CCallsignList* m_restrictList; + + void processIrcDDB(); + void processRepeater(IRepeaterProtocolHandler* handler); + void processDExtra(); + void processDPlus(); + void processDCS(); + void processG2(); + void processDD(); + + void loadGateways(); + void loadReflectors(); + void loadDExtraReflectors(const wxString& fileName); + void loadDPlusReflectors(const wxString& fileName); + void loadDCSReflectors(const wxString& fileName); + void loadXLXReflectors(); + + void writeStatus(); + + void readStatusFiles(); + void readStatusFile(const wxString& filename, unsigned int n, wxString& var); +}; + +#endif diff --git a/ircDDBGateway/IRCDDBGatewayThreadHelper.cpp b/ircDDBGateway/IRCDDBGatewayThreadHelper.cpp new file mode 100644 index 0000000..d1ff6b4 --- /dev/null +++ b/ircDDBGateway/IRCDDBGatewayThreadHelper.cpp @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2012 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "IRCDDBGatewayThreadHelper.h" + +CIRCDDBGatewayThreadHelper::CIRCDDBGatewayThreadHelper(CIRCDDBGatewayThread* thread) : +wxThread(wxTHREAD_JOINABLE), +m_thread(thread) +{ + wxASSERT(thread != NULL); +} + +CIRCDDBGatewayThreadHelper::~CIRCDDBGatewayThreadHelper() +{ + delete m_thread; +} + +void CIRCDDBGatewayThreadHelper::start() +{ + Create(); + + SetPriority(100U); + + Run(); +} + +void* CIRCDDBGatewayThreadHelper::Entry() +{ + wxASSERT(m_thread != NULL); + + m_thread->run(); + + return NULL; +} + +void CIRCDDBGatewayThreadHelper::kill() +{ + wxASSERT(m_thread != NULL); + + m_thread->kill(); + + Wait(); +} + +CIRCDDBGatewayStatusData* CIRCDDBGatewayThreadHelper::getStatus() +{ + wxASSERT(m_thread != NULL); + + return m_thread->getStatus(); +} diff --git a/ircDDBGateway/IRCDDBGatewayThreadHelper.h b/ircDDBGateway/IRCDDBGatewayThreadHelper.h new file mode 100644 index 0000000..4b0b3f8 --- /dev/null +++ b/ircDDBGateway/IRCDDBGatewayThreadHelper.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2012 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef IRCDDBGatewayThreadHelper_H +#define IRCDDBGatewayThreadHelper_H + +#include "IRCDDBGatewayStatusData.h" +#include "IRCDDBGatewayThread.h" + +#include + +class CIRCDDBGatewayThreadHelper : public wxThread { + +public: + CIRCDDBGatewayThreadHelper(CIRCDDBGatewayThread* thread); + virtual ~CIRCDDBGatewayThreadHelper(); + + virtual void start(); + + virtual void* Entry(); + + virtual void kill(); + + virtual CIRCDDBGatewayStatusData* getStatus(); + +private: + CIRCDDBGatewayThread* m_thread; +}; + +#endif diff --git a/ircDDBGateway/ircDDBGateway.vcxproj b/ircDDBGateway/ircDDBGateway.vcxproj new file mode 100644 index 0000000..991b1d1 --- /dev/null +++ b/ircDDBGateway/ircDDBGateway.vcxproj @@ -0,0 +1,200 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {6DDA3497-66A3-4856-BAD4-1DDCDBDFF959} + ircDDBGateway + Win32Proj + 10.0.16299.0 + + + + Application + v141 + Unicode + true + + + Application + v141 + Unicode + true + + + Application + v141 + Unicode + + + Application + v141 + Unicode + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>14.0.24720.0 + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + true + $(WXWIN)\include;$(WXWIN)\lib\vc_dll\mswud;$(IncludePath) + + + true + $(WXWIN)\include;$(WXWIN)\lib\vc_x64_dll\mswud;$(IncludePath) + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + false + + + false + + + + Disabled + $(WXWIN)\include\msvc;$(WXWIN)\include;../Common;../ircDDB;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;WINVER=0x0400;__WXMSW__;WXUSINGDLL;wxUSE_GUI=1;__WXDEBUG__;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;DCS_LINK;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + Level4 + EditAndContinue + + + ws2_32.lib;%(AdditionalDependencies) + $(WXWIN)\lib\vc_dll;%(AdditionalLibraryDirectories) + true + Windows + MachineX86 + + + + + Disabled + $(WXWIN)\include\msvc;$(WXWIN)\include;../Common;../ircDDB;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;WINVER=0x0400;__WXMSW__;WXUSINGDLL;wxUSE_GUI=1;__WXDEBUG__;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;DCS_LINK;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + + + Level4 + ProgramDatabase + + + ws2_32.lib;%(AdditionalDependencies) + $(WXWIN)\lib\vc_x64_dll;%(AdditionalLibraryDirectories) + true + Windows + + + + + MaxSpeed + true + $(WXWIN)\include\msvc;$(WXWIN)\include;../ircDDB;../Common;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;WINVER=0x0400;__WXMSW__;WXUSINGDLL;wxUSE_GUI=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) + MultiThreadedDLL + true + + Level3 + ProgramDatabase + + + ws2_32.lib;%(AdditionalDependencies) + $(WXWIN)\lib\vc_dll;%(AdditionalLibraryDirectories) + true + Windows + true + true + MachineX86 + + + + + MaxSpeed + true + $(WXWIN)\include\msvc;$(WXWIN)\include;../ircDDB;../Common;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;WINVER=0x0400;__WXMSW__;WXUSINGDLL;wxUSE_GUI=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) + MultiThreadedDLL + true + + + Level3 + ProgramDatabase + + + ws2_32.lib;%(AdditionalDependencies) + $(WXWIN)\lib\vc_x64_dll;%(AdditionalLibraryDirectories) + true + Windows + true + true + + + + + + + + + + + + + + + + + + + + + + {e793cb8e-2ac9-431a-bbfc-3f52537bb3cf} + false + + + {276bc54d-5581-4a0c-afd5-a5bdc947f0ad} + false + + + + + + \ No newline at end of file diff --git a/ircDDBGateway/ircDDBGateway.vcxproj.filters b/ircDDBGateway/ircDDBGateway.vcxproj.filters new file mode 100644 index 0000000..acace74 --- /dev/null +++ b/ircDDBGateway/ircDDBGateway.vcxproj.filters @@ -0,0 +1,56 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/ircDDBGatewayConfig/IRCDDBGatewayConfigApp.cpp b/ircDDBGatewayConfig/IRCDDBGatewayConfigApp.cpp new file mode 100644 index 0000000..6ab9c8f --- /dev/null +++ b/ircDDBGatewayConfig/IRCDDBGatewayConfigApp.cpp @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2010-2014 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "IRCDDBGatewayConfigDefs.h" +#include "IRCDDBGatewayConfigApp.h" +#include "Version.h" +#include "Utils.h" + +#include +#include +#include + +IMPLEMENT_APP(CIRCDDBGatewayConfigApp) + +const wxChar* NAME_PARAM = wxT("Gateway Name"); +const wxChar* CONFDIR_OPTION = wxT("confdir"); + +CIRCDDBGatewayConfigApp::CIRCDDBGatewayConfigApp() : +wxApp(), +m_name(), +m_confDir(), +m_frame(NULL) +{ +} + +CIRCDDBGatewayConfigApp::~CIRCDDBGatewayConfigApp() +{ +} + +bool CIRCDDBGatewayConfigApp::OnInit() +{ + SetVendorName(VENDOR_NAME); + + if (!wxApp::OnInit()) + return false; + + wxString frameName = APPLICATION_NAME + wxT(" - "); + if (!m_name.IsEmpty()) { + frameName.Append(m_name); + frameName.Append(wxT(" - ")); + } + frameName.Append(VERSION); + + m_frame = new CIRCDDBGatewayConfigFrame(frameName, m_confDir, m_name); + m_frame->Show(); + + SetTopWindow(m_frame); + + return true; +} + +int CIRCDDBGatewayConfigApp::OnExit() +{ + return 0; +} + +void CIRCDDBGatewayConfigApp::OnInitCmdLine(wxCmdLineParser& parser) +{ + parser.AddOption(CONFDIR_OPTION, wxEmptyString, wxEmptyString, wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL); + parser.AddParam(NAME_PARAM, wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL); + + wxApp::OnInitCmdLine(parser); +} + +bool CIRCDDBGatewayConfigApp::OnCmdLineParsed(wxCmdLineParser& parser) +{ + if (!wxApp::OnCmdLineParsed(parser)) + return false; + + wxString confDir; + bool found = parser.Found(CONFDIR_OPTION, &confDir); + if (found) + m_confDir = confDir; + + if (parser.GetParamCount() > 0U) + m_name = parser.GetParam(0U); + + return true; +} diff --git a/ircDDBGatewayConfig/IRCDDBGatewayConfigApp.h b/ircDDBGatewayConfig/IRCDDBGatewayConfigApp.h new file mode 100644 index 0000000..20ee352 --- /dev/null +++ b/ircDDBGatewayConfig/IRCDDBGatewayConfigApp.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2010-2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef IRCDDBGatewayConfigApp_H +#define IRCDDBGatewayConfigApp_H + +#include "IRCDDBGatewayConfigFrame.h" +#include "Defs.h" + +#include + +class CIRCDDBGatewayConfigApp : public wxApp { + +public: + CIRCDDBGatewayConfigApp(); + virtual ~CIRCDDBGatewayConfigApp(); + + virtual bool OnInit(); + virtual int OnExit(); + + virtual void OnInitCmdLine(wxCmdLineParser& parser); + virtual bool OnCmdLineParsed(wxCmdLineParser& parser); + +private: + wxString m_name; + wxString m_confDir; + CIRCDDBGatewayConfigFrame* m_frame; +}; + +DECLARE_APP(CIRCDDBGatewayConfigApp) + +#endif diff --git a/ircDDBGatewayConfig/IRCDDBGatewayConfigDefs.h b/ircDDBGatewayConfig/IRCDDBGatewayConfigDefs.h new file mode 100644 index 0000000..5bd7fed --- /dev/null +++ b/ircDDBGatewayConfig/IRCDDBGatewayConfigDefs.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2010-2014 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef IRCDDBGatewayConfigDefs_H +#define IRCDDBGatewayConfigDefs_H + +#include + +const wxString APPLICATION_NAME = wxT("ircDDB Gateway"); + +const wxString LOG_BASE_NAME = wxT("ircDDBGateway"); + +const wxString CONFIG_FILE_NAME = wxT("ircddbgateway"); + +const unsigned int MAX_OUTGOING = 6U; +const unsigned int MAX_REPEATERS = 4U; +const unsigned int MAX_DEXTRA_LINKS = 5U; +const unsigned int MAX_DPLUS_LINKS = 5U; +const unsigned int MAX_DCS_LINKS = 5U; +const unsigned int MAX_STARNETS = 5U; +const unsigned int MAX_ROUTES = MAX_REPEATERS + 5U; +const unsigned int MAX_DD_ROUTES = 20U; + +#endif diff --git a/ircDDBGatewayConfig/IRCDDBGatewayConfigFrame.cpp b/ircDDBGatewayConfig/IRCDDBGatewayConfigFrame.cpp new file mode 100644 index 0000000..40ffb31 --- /dev/null +++ b/ircDDBGatewayConfig/IRCDDBGatewayConfigFrame.cpp @@ -0,0 +1,636 @@ +/* + * Copyright (C) 2010-2015 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "IRCDDBGatewayConfigFrame.h" +#include "IRCDDBGatewayConfigDefs.h" +#include "Version.h" + +const unsigned int BORDER_SIZE = 5U; + +#include +#include +#include + +enum { + Menu_File_Save = 6000 +}; + +BEGIN_EVENT_TABLE(CIRCDDBGatewayConfigFrame, wxFrame) + EVT_MENU(wxID_EXIT, CIRCDDBGatewayConfigFrame::onQuit) + EVT_MENU(Menu_File_Save, CIRCDDBGatewayConfigFrame::onSave) + EVT_MENU(wxID_ABOUT, CIRCDDBGatewayConfigFrame::onAbout) + + EVT_CLOSE(CIRCDDBGatewayConfigFrame::onClose) +END_EVENT_TABLE() + +CIRCDDBGatewayConfigFrame::CIRCDDBGatewayConfigFrame(const wxString& title, const wxString& confDir, const wxString& name) : +wxFrame(NULL, -1, title), +m_config(NULL), +m_gateway(NULL), +m_repeaterData1(NULL), +m_repeaterInfo1(NULL), +m_repeaterData2(NULL), +m_repeaterInfo2(NULL), +m_repeaterData3(NULL), +m_repeaterInfo3(NULL), +m_repeaterData4(NULL), +m_repeaterInfo4(NULL), +m_ircDDB(NULL), +m_ircDDB2(NULL), +m_ircDDB3(NULL), +m_ircDDB4(NULL), +m_dprs(NULL), +m_dextra(NULL), +m_dplus(NULL), +m_dcs(NULL), +m_xlx(NULL), +m_starNet1(NULL), +m_starNet2(NULL), +m_starNet3(NULL), +m_starNet4(NULL), +m_starNet5(NULL), +m_remote(NULL), +m_miscellaneous(NULL) +{ + SetMenuBar(createMenuBar()); + + wxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL); + + wxPanel* panel = new wxPanel(this, -1); + +#if defined(__WINDOWS__) + if (confDir.IsEmpty()) + m_config = new CIRCDDBGatewayConfig(new wxConfig(APPLICATION_NAME), ::wxGetHomeDir(), CONFIG_FILE_NAME, name); + else + m_config = new CIRCDDBGatewayConfig(new wxConfig(APPLICATION_NAME), confDir, CONFIG_FILE_NAME, name); +#else + if (confDir.IsEmpty()) + m_config = new CIRCDDBGatewayConfig(wxT(CONF_DIR), CONFIG_FILE_NAME, name); + else + m_config = new CIRCDDBGatewayConfig(confDir, CONFIG_FILE_NAME, name); +#endif + + wxBoxSizer* sizer = new wxBoxSizer(wxVERTICAL); + + wxNotebook* noteBook = new wxNotebook(panel, -1); + + bool dextraEnabled; + unsigned int maxDExtraDongles; + m_config->getDExtra(dextraEnabled, maxDExtraDongles); + + wxString dplusLogin; + unsigned int maxDPlusDongles; + bool dplusEnabled; + m_config->getDPlus(dplusEnabled, maxDPlusDongles, dplusLogin); + + bool dcsEnabled, ccsEnabled; + wxString ccsHost; + m_config->getDCS(dcsEnabled, ccsEnabled, ccsHost); + + bool xlxEnabled; + bool xlxOverrideLocal; + wxString xlxHostsFileUrl; + m_config->getXLX(xlxEnabled, xlxOverrideLocal, xlxHostsFileUrl); + + GATEWAY_TYPE gatewayType; + wxString gatewayCallsign, gatewayAddress, icomAddress, hbAddress, description1, description2, url; + unsigned int icomPort, hbPort; + double latitude, longitude; + m_config->getGateway(gatewayType, gatewayCallsign, gatewayAddress, icomAddress, icomPort, hbAddress, hbPort, latitude, longitude, description1, description2, url); + + m_gateway = new CIRCDDBGatewayConfigGatewaySet(noteBook, -1, APPLICATION_NAME, gatewayType, gatewayCallsign, gatewayAddress, icomAddress, icomPort, hbAddress, hbPort, latitude, longitude, description1, description2, url); + noteBook->AddPage(m_gateway, _("Gateway"), true); + + wxString repeaterCall1, repeaterBand1, repeaterAddress1, reflector1, description11, description12, url1; + double frequency1, offset1, range1, latitude1, longitude1, agl1; + unsigned char band11, band12, band13; + unsigned int repeaterPort1; + HW_TYPE repeaterType1; + bool atStartup1; + RECONNECT reconnect1; + m_config->getRepeater1(repeaterCall1, repeaterBand1, repeaterType1, repeaterAddress1, repeaterPort1, band11, band12, band13, reflector1, atStartup1, reconnect1, frequency1, offset1, range1, latitude1, longitude1, agl1, description11, description12, url1); + + m_repeaterData1 = new CRepeaterDataSet(noteBook, -1, APPLICATION_NAME, repeaterBand1, repeaterType1, repeaterAddress1, repeaterPort1, band11, band12, band13, dplusEnabled, dextraEnabled, dcsEnabled, reflector1, atStartup1, reconnect1); + noteBook->AddPage(m_repeaterData1, _("Repeater 1"), false); + + m_repeaterInfo1 = new CRepeaterInfoSet(noteBook, -1, APPLICATION_NAME, frequency1, offset1, range1, latitude1, longitude1, agl1, description11, description12, url1); + noteBook->AddPage(m_repeaterInfo1, _("Repeater 1"), false); + + wxString repeaterCall2, repeaterBand2, repeaterAddress2, reflector2, description21, description22, url2; + double frequency2, offset2, range2, latitude2, longitude2, agl2; + unsigned char band21, band22, band23; + unsigned int repeaterPort2; + HW_TYPE repeaterType2; + bool atStartup2; + RECONNECT reconnect2; + m_config->getRepeater2(repeaterCall2, repeaterBand2, repeaterType2, repeaterAddress2, repeaterPort2, band21, band22, band23, reflector2, atStartup2, reconnect2, frequency2, offset2, range2, latitude2, longitude2, agl2, description21, description22, url2); + + m_repeaterData2 = new CRepeaterDataSet(noteBook, -1, APPLICATION_NAME, repeaterBand2, repeaterType2, repeaterAddress2, repeaterPort2, band21, band22, band23, dplusEnabled, dextraEnabled, dcsEnabled, reflector2, atStartup2, reconnect2); + noteBook->AddPage(m_repeaterData2, _("Repeater 2"), false); + + m_repeaterInfo2 = new CRepeaterInfoSet(noteBook, -1, APPLICATION_NAME, frequency2, offset2, range2, latitude2, longitude2, agl2, description21, description22, url2); + noteBook->AddPage(m_repeaterInfo2, _("Repeater 2"), false); + + wxString repeaterCall3, repeaterBand3, repeaterAddress3, reflector3, description31, description32, url3; + double frequency3, offset3, range3, latitude3, longitude3, agl3; + unsigned char band31, band32, band33; + unsigned int repeaterPort3; + HW_TYPE repeaterType3; + bool atStartup3; + RECONNECT reconnect3; + m_config->getRepeater3(repeaterCall3, repeaterBand3, repeaterType3, repeaterAddress3, repeaterPort3, band31, band32, band33, reflector3, atStartup3, reconnect3, frequency3, offset3, range3, latitude3, longitude3, agl3, description31, description32, url3); + + m_repeaterData3 = new CRepeaterDataSet(noteBook, -1, APPLICATION_NAME, repeaterBand3, repeaterType3, repeaterAddress3, repeaterPort3, band31, band32, band33, dplusEnabled, dextraEnabled, dcsEnabled, reflector3, atStartup3, reconnect3); + noteBook->AddPage(m_repeaterData3, _("Repeater 3"), false); + + m_repeaterInfo3 = new CRepeaterInfoSet(noteBook, -1, APPLICATION_NAME, frequency3, offset3, range3, latitude3, longitude3, agl3, description31, description32, url3); + noteBook->AddPage(m_repeaterInfo3, _("Repeater 3"), false); + + wxString repeaterCall4, repeaterBand4, repeaterAddress4, reflector4, description41, description42, url4; + double frequency4, offset4, range4, latitude4, longitude4, agl4; + unsigned char band41, band42, band43; + unsigned int repeaterPort4; + HW_TYPE repeaterType4; + bool atStartup4; + RECONNECT reconnect4; + m_config->getRepeater4(repeaterCall4, repeaterBand4, repeaterType4, repeaterAddress4, repeaterPort4, band41, band42, band43, reflector4, atStartup4, reconnect4, frequency4, offset4, range4, latitude4, longitude4, agl4, description41, description42, url4); + + m_repeaterData4 = new CRepeaterDataSet(noteBook, -1, APPLICATION_NAME, repeaterBand4, repeaterType4, repeaterAddress4, repeaterPort4, band41, band42, band43, dplusEnabled, dextraEnabled, dcsEnabled, reflector4, atStartup4, reconnect4); + noteBook->AddPage(m_repeaterData4, _("Repeater 4"), false); + + m_repeaterInfo4 = new CRepeaterInfoSet(noteBook, -1, APPLICATION_NAME, frequency4, offset4, range4, latitude4, longitude4, agl4, description41, description42, url4); + noteBook->AddPage(m_repeaterInfo4, _("Repeater 4"), false); + + bool ircDDBEnabled; + wxString ircDDBHostname, ircDDBUsername, ircDDBPassword; + m_config->getIrcDDB(ircDDBEnabled, ircDDBHostname, ircDDBUsername, ircDDBPassword); + m_ircDDB = new CIRCDDBGatewayConfigIrcDDBSet(noteBook, -1, APPLICATION_NAME, ircDDBEnabled, ircDDBHostname, ircDDBUsername, ircDDBPassword); + noteBook->AddPage(m_ircDDB, wxT("ircDDB 1st Network"), false); + + m_config->getIrcDDB2(ircDDBEnabled, ircDDBHostname, ircDDBUsername, ircDDBPassword); + m_ircDDB2 = new CIRCDDBGatewayConfigIrcDDBSet(noteBook, -1, APPLICATION_NAME, ircDDBEnabled, ircDDBHostname, ircDDBUsername, ircDDBPassword); + noteBook->AddPage(m_ircDDB2, wxT("ircDDB 2nd Network"), false); + + m_config->getIrcDDB3(ircDDBEnabled, ircDDBHostname, ircDDBUsername, ircDDBPassword); + m_ircDDB3 = new CIRCDDBGatewayConfigIrcDDBSet(noteBook, -1, APPLICATION_NAME, ircDDBEnabled, ircDDBHostname, ircDDBUsername, ircDDBPassword); + noteBook->AddPage(m_ircDDB3, wxT("ircDDB 3rd Network"), false); + + m_config->getIrcDDB4(ircDDBEnabled, ircDDBHostname, ircDDBUsername, ircDDBPassword); + m_ircDDB4 = new CIRCDDBGatewayConfigIrcDDBSet(noteBook, -1, APPLICATION_NAME, ircDDBEnabled, ircDDBHostname, ircDDBUsername, ircDDBPassword); + noteBook->AddPage(m_ircDDB4, wxT("ircDDB 4th Network"), false); + + wxString aprsHostname; + unsigned int aprsPort; + bool aprsEnabled; + m_config->getDPRS(aprsEnabled, aprsHostname, aprsPort); + + m_dprs = new CDPRSSet(noteBook, -1, APPLICATION_NAME, aprsEnabled, aprsHostname, aprsPort); + noteBook->AddPage(m_dprs, wxT("D-PRS"), false); + + m_dextra = new CDExtraSet(noteBook, -1, APPLICATION_NAME, dextraEnabled, maxDExtraDongles, MAX_DEXTRA_LINKS); + noteBook->AddPage(m_dextra, wxT("DExtra"), false); + + m_dplus = new CDPlusSet(noteBook, -1, APPLICATION_NAME, dplusEnabled, maxDPlusDongles, MAX_DPLUS_LINKS, dplusLogin); + noteBook->AddPage(m_dplus, wxT("D-Plus"), false); + + m_dcs = new CDCSSet(noteBook, -1, APPLICATION_NAME, dcsEnabled, ccsEnabled, ccsHost); + noteBook->AddPage(m_dcs, _("DCS and CCS"), false); + + m_xlx = new CXLXSet(noteBook, -1, APPLICATION_NAME, xlxEnabled, xlxOverrideLocal, xlxHostsFileUrl); + noteBook->AddPage(m_xlx, _("XLX Hosts File"), false); + +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + wxString starNetBand1, starNetCallsign1, starNetLogoff1, starNetInfo1, starNetLink1, starNetPermanent1; + unsigned int starNetUserTimeout1, starNetGroupTimeout1; + STARNET_CALLSIGN_SWITCH starNetCallsignSwitch1; + bool starNetTXMsgSwitch1; + m_config->getStarNet1(starNetBand1, starNetCallsign1, starNetLogoff1, starNetInfo1, starNetPermanent1, starNetUserTimeout1, starNetGroupTimeout1, starNetCallsignSwitch1, starNetTXMsgSwitch1, starNetLink1); + + m_starNet1 = new CStarNetSet(noteBook, -1, APPLICATION_NAME, starNetBand1, starNetCallsign1, starNetLogoff1, starNetInfo1, starNetPermanent1, starNetUserTimeout1, starNetGroupTimeout1, starNetCallsignSwitch1, starNetTXMsgSwitch1, starNetLink1); + noteBook->AddPage(m_starNet1, wxT("StarNet 1"), false); + + wxString starNetBand2, starNetCallsign2, starNetLogoff2, starNetInfo2, starNetLink2, starNetPermanent2; + unsigned int starNetUserTimeout2, starNetGroupTimeout2; + STARNET_CALLSIGN_SWITCH starNetCallsignSwitch2; + bool starNetTXMsgSwitch2; + m_config->getStarNet2(starNetBand2, starNetCallsign2, starNetLogoff2, starNetInfo2, starNetPermanent2, starNetUserTimeout2, starNetGroupTimeout2, starNetCallsignSwitch2, starNetTXMsgSwitch2, starNetLink2); + + m_starNet2 = new CStarNetSet(noteBook, -1, APPLICATION_NAME, starNetBand2, starNetCallsign2, starNetLogoff2, starNetInfo2, starNetPermanent2, starNetUserTimeout2, starNetGroupTimeout2, starNetCallsignSwitch2, starNetTXMsgSwitch2, starNetLink2); + noteBook->AddPage(m_starNet2, wxT("StarNet 2"), false); + + wxString starNetBand3, starNetCallsign3, starNetLogoff3, starNetInfo3, starNetLink3, starNetPermanent3; + unsigned int starNetUserTimeout3, starNetGroupTimeout3; + STARNET_CALLSIGN_SWITCH starNetCallsignSwitch3; + bool starNetTXMsgSwitch3; + m_config->getStarNet3(starNetBand3, starNetCallsign3, starNetLogoff3, starNetInfo3, starNetPermanent3, starNetUserTimeout3, starNetGroupTimeout3, starNetCallsignSwitch3, starNetTXMsgSwitch3, starNetLink3); + + m_starNet3 = new CStarNetSet(noteBook, -1, APPLICATION_NAME, starNetBand3, starNetCallsign3, starNetLogoff3, starNetInfo3, starNetPermanent3, starNetUserTimeout3, starNetGroupTimeout3, starNetCallsignSwitch3, starNetTXMsgSwitch3, starNetLink3); + noteBook->AddPage(m_starNet3, wxT("StarNet 3"), false); + + wxString starNetBand4, starNetCallsign4, starNetLogoff4, starNetInfo4, starNetLink4, starNetPermanent4; + unsigned int starNetUserTimeout4, starNetGroupTimeout4; + STARNET_CALLSIGN_SWITCH starNetCallsignSwitch4; + bool starNetTXMsgSwitch4; + m_config->getStarNet4(starNetBand4, starNetCallsign4, starNetLogoff4, starNetInfo4, starNetPermanent4, starNetUserTimeout4, starNetGroupTimeout4, starNetCallsignSwitch4, starNetTXMsgSwitch4, starNetLink4); + + m_starNet4 = new CStarNetSet(noteBook, -1, APPLICATION_NAME, starNetBand4, starNetCallsign4, starNetLogoff4, starNetInfo4, starNetPermanent4, starNetUserTimeout4, starNetGroupTimeout4, starNetCallsignSwitch4, starNetTXMsgSwitch4, starNetLink4); + noteBook->AddPage(m_starNet4, wxT("StarNet 4"), false); + + wxString starNetBand5, starNetCallsign5, starNetLogoff5, starNetInfo5, starNetLink5, starNetPermanent5; + unsigned int starNetUserTimeout5, starNetGroupTimeout5; + STARNET_CALLSIGN_SWITCH starNetCallsignSwitch5; + bool starNetTXMsgSwitch5; + m_config->getStarNet5(starNetBand5, starNetCallsign5, starNetLogoff5, starNetInfo5, starNetPermanent5, starNetUserTimeout5, starNetGroupTimeout5, starNetCallsignSwitch5, starNetTXMsgSwitch5, starNetLink5); + + m_starNet5 = new CStarNetSet(noteBook, -1, APPLICATION_NAME, starNetBand5, starNetCallsign5, starNetLogoff5, starNetInfo5, starNetPermanent5, starNetUserTimeout5, starNetGroupTimeout5, starNetCallsignSwitch5, starNetTXMsgSwitch5, starNetLink5); + noteBook->AddPage(m_starNet5, wxT("StarNet 5"), false); +#else + wxString starNetBand1, starNetCallsign1, starNetLogoff1, starNetInfo1, starNetPermanent1; + unsigned int starNetUserTimeout1, starNetGroupTimeout1; + STARNET_CALLSIGN_SWITCH starNetCallsignSwitch1; + bool starNetTXMsgSwitch1; + m_config->getStarNet1(starNetBand1, starNetCallsign1, starNetLogoff1, starNetInfo1, starNetPermanent1, starNetUserTimeout1, starNetGroupTimeout1, starNetCallsignSwitch1, starNetTXMsgSwitch1); + + m_starNet1 = new CStarNetSet(noteBook, -1, APPLICATION_NAME, starNetBand1, starNetCallsign1, starNetLogoff1, starNetInfo1, starNetPermanent1, starNetUserTimeout1, starNetGroupTimeout1, starNetCallsignSwitch1, starNetTXMsgSwitch1); + noteBook->AddPage(m_starNet1, wxT("StarNet 1"), false); + + wxString starNetBand2, starNetCallsign2, starNetLogoff2, starNetInfo2, starNetPermanent2; + unsigned int starNetUserTimeout2, starNetGroupTimeout2; + STARNET_CALLSIGN_SWITCH starNetCallsignSwitch2; + bool starNetTXMsgSwitch2; + m_config->getStarNet2(starNetBand2, starNetCallsign2, starNetLogoff2, starNetInfo2, starNetPermanent2, starNetUserTimeout2, starNetGroupTimeout2, starNetCallsignSwitch2, starNetTXMsgSwitch2); + + m_starNet2 = new CStarNetSet(noteBook, -1, APPLICATION_NAME, starNetBand2, starNetCallsign2, starNetLogoff2, starNetInfo2, starNetPermanent2, starNetUserTimeout2, starNetGroupTimeout2, starNetCallsignSwitch2, starNetTXMsgSwitch2); + noteBook->AddPage(m_starNet2, wxT("StarNet 2"), false); + + wxString starNetBand3, starNetCallsign3, starNetLogoff3, starNetInfo3, starNetPermanent3; + unsigned int starNetUserTimeout3, starNetGroupTimeout3; + STARNET_CALLSIGN_SWITCH starNetCallsignSwitch3; + bool starNetTXMsgSwitch3; + m_config->getStarNet3(starNetBand3, starNetCallsign3, starNetLogoff3, starNetInfo3, starNetPermanent3, starNetUserTimeout3, starNetGroupTimeout3, starNetCallsignSwitch3, starNetTXMsgSwitch3); + + m_starNet3 = new CStarNetSet(noteBook, -1, APPLICATION_NAME, starNetBand3, starNetCallsign3, starNetLogoff3, starNetInfo3, starNetPermanent3, starNetUserTimeout3, starNetGroupTimeout3, starNetCallsignSwitch3, starNetTXMsgSwitch3); + noteBook->AddPage(m_starNet3, wxT("StarNet 3"), false); + + wxString starNetBand4, starNetCallsign4, starNetLogoff4, starNetInfo4, starNetPermanent4; + unsigned int starNetUserTimeout4, starNetGroupTimeout4; + STARNET_CALLSIGN_SWITCH starNetCallsignSwitch4; + bool starNetTXMsgSwitch4; + m_config->getStarNet4(starNetBand4, starNetCallsign4, starNetLogoff4, starNetInfo4, starNetPermanent4, starNetUserTimeout4, starNetGroupTimeout4, starNetCallsignSwitch4, starNetTXMsgSwitch4); + + m_starNet4 = new CStarNetSet(noteBook, -1, APPLICATION_NAME, starNetBand4, starNetCallsign4, starNetLogoff4, starNetInfo4, starNetPermanent4, starNetUserTimeout4, starNetGroupTimeout4, starNetCallsignSwitch4, starNetTXMsgSwitch4); + noteBook->AddPage(m_starNet4, wxT("StarNet 4"), false); + + wxString starNetBand5, starNetCallsign5, starNetLogoff5, starNetInfo5, starNetPermanent5; + unsigned int starNetUserTimeout5, starNetGroupTimeout5; + STARNET_CALLSIGN_SWITCH starNetCallsignSwitch5; + bool starNetTXMsgSwitch5; + m_config->getStarNet5(starNetBand5, starNetCallsign5, starNetLogoff5, starNetInfo5, starNetPermanent5, starNetUserTimeout5, starNetGroupTimeout5, starNetCallsignSwitch5, starNetTXMsgSwitch5); + + m_starNet5 = new CStarNetSet(noteBook, -1, APPLICATION_NAME, starNetBand5, starNetCallsign5, starNetLogoff5, starNetInfo5, starNetPermanent5, starNetUserTimeout5, starNetGroupTimeout5, starNetCallsignSwitch5, starNetTXMsgSwitch5); + noteBook->AddPage(m_starNet5, wxT("StarNet 5"), false); +#endif + + unsigned int remotePort; + wxString remotePassword; + bool remoteEnabled; + m_config->getRemote(remoteEnabled, remotePassword, remotePort); + + m_remote = new CRemoteSet(noteBook, -1, APPLICATION_NAME, remoteEnabled, remotePassword, remotePort); + noteBook->AddPage(m_remote, wxT("Remote"), false); + + TEXT_LANG language; + bool infoEnabled, echoEnabled, logEnabled, dratsEnabled, dtmfEnabled; + m_config->getMiscellaneous(language, infoEnabled, echoEnabled, logEnabled, dratsEnabled, dtmfEnabled); + + m_miscellaneous = new CIRCDDBGatewayConfigMiscellaneousSet(noteBook, -1, APPLICATION_NAME, language, infoEnabled, echoEnabled, logEnabled, dratsEnabled, dtmfEnabled); + noteBook->AddPage(m_miscellaneous, wxT("Misc"), false); + + sizer->Add(noteBook, 0, wxEXPAND | wxALL, BORDER_SIZE); + + panel->SetSizer(sizer); + + mainSizer->Add(panel, 0, wxEXPAND | wxALL, BORDER_SIZE); + + mainSizer->SetSizeHints(this); + + SetSizer(mainSizer); +} + +CIRCDDBGatewayConfigFrame::~CIRCDDBGatewayConfigFrame() +{ + delete m_config; +} + +wxMenuBar* CIRCDDBGatewayConfigFrame::createMenuBar() +{ + wxMenu* fileMenu = new wxMenu(); + fileMenu->Append(Menu_File_Save, _("Save")); + fileMenu->AppendSeparator(); + fileMenu->Append(wxID_EXIT, _("Exit")); + + wxMenu* helpMenu = new wxMenu(); + helpMenu->Append(wxID_ABOUT, _("About ircDDB Gateway Config")); + + wxMenuBar* menuBar = new wxMenuBar(); + menuBar->Append(fileMenu, _("File")); + menuBar->Append(helpMenu, _("Help")); + + return menuBar; +} + +void CIRCDDBGatewayConfigFrame::onQuit(wxCommandEvent&) +{ + Close(false); +} + +void CIRCDDBGatewayConfigFrame::onClose(wxCloseEvent&) +{ + Destroy(); +} + +void CIRCDDBGatewayConfigFrame::onSave(wxCommandEvent&) +{ + if (!m_gateway->Validate() || !m_repeaterData1->Validate() || !m_repeaterInfo1->Validate() || !m_repeaterData2->Validate() || + !m_repeaterInfo2->Validate() || !m_repeaterData3->Validate() || !m_repeaterInfo3->Validate() || !m_repeaterData4->Validate() || + !m_repeaterInfo4->Validate() || + !m_ircDDB->Validate() || !m_ircDDB2->Validate() || !m_ircDDB3->Validate() || !m_ircDDB4->Validate() || !m_dprs->Validate() || !m_dplus->Validate() || !m_dcs->Validate() || !m_xlx->Validate() || + !m_starNet1->Validate() || !m_starNet2->Validate() || !m_starNet3->Validate() || !m_starNet4->Validate() || + !m_starNet5->Validate() || !m_remote->Validate() || !m_miscellaneous->Validate()) + return; + + GATEWAY_TYPE gatewayType = m_gateway->getType(); + wxString gatewayCallsign = m_gateway->getCallsign(); + wxString gatewayAddress = m_gateway->getAddress(); + wxString icomAddress = m_gateway->getIcomAddress(); + unsigned int icomPort = m_gateway->getIcomPort(); + wxString hbAddress = m_gateway->getHBAddress(); + unsigned int hbPort = m_gateway->getHBPort(); + double latitude = m_gateway->getLatitude(); + double longitude = m_gateway->getLongitude(); + wxString description1 = m_gateway->getDescription1(); + wxString description2 = m_gateway->getDescription2(); + wxString url = m_gateway->getURL(); + m_config->setGateway(gatewayType, gatewayCallsign, gatewayAddress, icomAddress, icomPort, hbAddress, hbPort, latitude, longitude, description1, description2, url); + + wxString repeaterBand1 = m_repeaterData1->getBand(); + HW_TYPE repeaterType1 = m_repeaterData1->getType(); + wxString repeaterAddress1 = m_repeaterData1->getAddress(); + unsigned int repeaterPort1 = m_repeaterData1->getPort(); + unsigned char band11 = m_repeaterData1->getBand1(); + unsigned char band12 = m_repeaterData1->getBand2(); + unsigned char band13 = m_repeaterData1->getBand3(); + wxString reflector1 = m_repeaterData1->getReflector(); + bool atStartup1 = m_repeaterData1->atStartup(); + RECONNECT reconnect1 = m_repeaterData1->getReconnect(); + double frequency1 = m_repeaterInfo1->getFrequency(); + double offset1 = m_repeaterInfo1->getOffset(); + double range1 = m_repeaterInfo1->getRange(); + double latitude1 = m_repeaterInfo1->getLatitude(); + double longitude1 = m_repeaterInfo1->getLongitude(); + double agl1 = m_repeaterInfo1->getAGL(); + wxString description11 = m_repeaterInfo1->getDescription1(); + wxString description12 = m_repeaterInfo1->getDescription2(); + wxString url1 = m_repeaterInfo1->getURL(); + m_config->setRepeater1(repeaterBand1, repeaterType1, repeaterAddress1, repeaterPort1, band11, band12, band13, reflector1, atStartup1, reconnect1, frequency1, offset1, range1, latitude1, longitude1, agl1, description11, description12, url1); + + wxString repeaterBand2 = m_repeaterData2->getBand(); + HW_TYPE repeaterType2 = m_repeaterData2->getType(); + wxString repeaterAddress2 = m_repeaterData2->getAddress(); + unsigned int repeaterPort2 = m_repeaterData2->getPort(); + unsigned char band21 = m_repeaterData2->getBand1(); + unsigned char band22 = m_repeaterData2->getBand2(); + unsigned char band23 = m_repeaterData2->getBand3(); + wxString reflector2 = m_repeaterData2->getReflector(); + bool atStartup2 = m_repeaterData2->atStartup(); + RECONNECT reconnect2 = m_repeaterData2->getReconnect(); + double frequency2 = m_repeaterInfo2->getFrequency(); + double offset2 = m_repeaterInfo2->getOffset(); + double range2 = m_repeaterInfo2->getRange(); + double latitude2 = m_repeaterInfo2->getLatitude(); + double longitude2 = m_repeaterInfo2->getLongitude(); + double agl2 = m_repeaterInfo2->getAGL(); + wxString description21 = m_repeaterInfo2->getDescription1(); + wxString description22 = m_repeaterInfo2->getDescription2(); + wxString url2 = m_repeaterInfo2->getURL(); + m_config->setRepeater2(repeaterBand2, repeaterType2, repeaterAddress2, repeaterPort2, band21, band22, band23, reflector2, atStartup2, reconnect2, frequency2, offset2, range2, latitude2, longitude2, agl2, description21, description22, url2); + + wxString repeaterBand3 = m_repeaterData3->getBand(); + HW_TYPE repeaterType3 = m_repeaterData3->getType(); + wxString repeaterAddress3 = m_repeaterData3->getAddress(); + unsigned int repeaterPort3 = m_repeaterData3->getPort(); + unsigned char band31 = m_repeaterData3->getBand1(); + unsigned char band32 = m_repeaterData3->getBand2(); + unsigned char band33 = m_repeaterData3->getBand3(); + wxString reflector3 = m_repeaterData3->getReflector(); + bool atStartup3 = m_repeaterData3->atStartup(); + RECONNECT reconnect3 = m_repeaterData3->getReconnect(); + double frequency3 = m_repeaterInfo3->getFrequency(); + double offset3 = m_repeaterInfo3->getOffset(); + double range3 = m_repeaterInfo3->getRange(); + double latitude3 = m_repeaterInfo3->getLatitude(); + double longitude3 = m_repeaterInfo3->getLongitude(); + double agl3 = m_repeaterInfo3->getAGL(); + wxString description31 = m_repeaterInfo3->getDescription1(); + wxString description32 = m_repeaterInfo3->getDescription2(); + wxString url3 = m_repeaterInfo3->getURL(); + m_config->setRepeater3(repeaterBand3, repeaterType3, repeaterAddress3, repeaterPort3, band31, band32, band33, reflector3, atStartup3, reconnect3, frequency3, offset3, range3, latitude3, longitude3, agl3, description31, description32, url3); + + wxString repeaterBand4 = m_repeaterData4->getBand(); + HW_TYPE repeaterType4 = m_repeaterData4->getType(); + wxString repeaterAddress4 = m_repeaterData4->getAddress(); + unsigned int repeaterPort4 = m_repeaterData4->getPort(); + unsigned char band41 = m_repeaterData4->getBand1(); + unsigned char band42 = m_repeaterData4->getBand2(); + unsigned char band43 = m_repeaterData4->getBand3(); + wxString reflector4 = m_repeaterData4->getReflector(); + bool atStartup4 = m_repeaterData4->atStartup(); + RECONNECT reconnect4 = m_repeaterData4->getReconnect(); + double frequency4 = m_repeaterInfo4->getFrequency(); + double offset4 = m_repeaterInfo4->getOffset(); + double range4 = m_repeaterInfo4->getRange(); + double latitude4 = m_repeaterInfo4->getLatitude(); + double longitude4 = m_repeaterInfo4->getLongitude(); + double agl4 = m_repeaterInfo4->getAGL(); + wxString description41 = m_repeaterInfo4->getDescription1(); + wxString description42 = m_repeaterInfo4->getDescription2(); + wxString url4 = m_repeaterInfo4->getURL(); + m_config->setRepeater4(repeaterBand4, repeaterType4, repeaterAddress4, repeaterPort4, band41, band42, band43, reflector4, atStartup4, reconnect4, frequency4, offset4, range4, latitude4, longitude4, agl4, description41, description42, url4); + + bool ircDDBEnabled = m_ircDDB->getEnabled(); + wxString ircDDBHostname = m_ircDDB->getHostname(); + wxString ircDDBUsername = m_ircDDB->getUsername(); + wxString ircDDBPassword = m_ircDDB->getPassword(); + m_config->setIrcDDB(ircDDBEnabled, ircDDBHostname, ircDDBUsername, ircDDBPassword); + + ircDDBEnabled = m_ircDDB2->getEnabled(); + ircDDBHostname = m_ircDDB2->getHostname(); + ircDDBUsername = m_ircDDB2->getUsername(); + ircDDBPassword = m_ircDDB2->getPassword(); + m_config->setIrcDDB2(ircDDBEnabled, ircDDBHostname, ircDDBUsername, ircDDBPassword); + + ircDDBEnabled = m_ircDDB3->getEnabled(); + ircDDBHostname = m_ircDDB3->getHostname(); + ircDDBUsername = m_ircDDB3->getUsername(); + ircDDBPassword = m_ircDDB3->getPassword(); + m_config->setIrcDDB3(ircDDBEnabled, ircDDBHostname, ircDDBUsername, ircDDBPassword); + + ircDDBEnabled = m_ircDDB4->getEnabled(); + ircDDBHostname = m_ircDDB4->getHostname(); + ircDDBUsername = m_ircDDB4->getUsername(); + ircDDBPassword = m_ircDDB4->getPassword(); + m_config->setIrcDDB4(ircDDBEnabled, ircDDBHostname, ircDDBUsername, ircDDBPassword); + + bool aprsEnabled = m_dprs->getEnabled(); + wxString aprsHostname = m_dprs->getHostname(); + unsigned int aprsPort = m_dprs->getPort(); + m_config->setDPRS(aprsEnabled, aprsHostname, aprsPort); + + bool dextraEnabled = m_dextra->getEnabled(); + unsigned int maxDExtraDongles = m_dextra->getMaxDongles(); + m_config->setDExtra(dextraEnabled, maxDExtraDongles); + + bool dplusEnabled = m_dplus->getEnabled(); + unsigned int maxDPlusDongles = m_dplus->getMaxDongles(); + wxString dplusLogin = m_dplus->getLogin(); + m_config->setDPlus(dplusEnabled, maxDPlusDongles, dplusLogin); + + bool dcsEnabled = m_dcs->getDCSEnabled(); + bool ccsEnabled = m_dcs->getCCSEnabled(); + wxString ccsHost = m_dcs->getCCSHost(); + m_config->setDCS(dcsEnabled, ccsEnabled, ccsHost); + + bool xlxEnabled = m_xlx->getXLXEnabled(); + bool xlxOverrideLocal = m_xlx->getXLXOverrideLocal(); + wxString xlxHostsFileUrl = m_xlx->getXLXHostsFileUrl(); + m_config->setXLX(xlxEnabled, xlxOverrideLocal, xlxHostsFileUrl); + + wxString starNetBand1 = m_starNet1->getBand(); + wxString starNetCallsign1 = m_starNet1->getCallsign(); + wxString starNetLogoff1 = m_starNet1->getLogoff(); + wxString starNetInfo1 = m_starNet1->getInfo(); + wxString starNetPermanent1 = m_starNet1->getPermanent(); + unsigned int starNetUserTimeout1 = m_starNet1->getUserTimeout(); + unsigned int starNetGroupTimeout1 = m_starNet1->getGroupTimeout(); + STARNET_CALLSIGN_SWITCH starNetCallsignSwitch1 = m_starNet1->getCallsignSwitch(); + bool starNetTXMsgSwitch1 = m_starNet1->getTXMsgSwitch(); +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + wxString starNetLink1 = m_starNet1->getReflector(); + m_config->setStarNet1(starNetBand1, starNetCallsign1, starNetLogoff1, starNetInfo1, starNetPermanent1, starNetUserTimeout1, starNetGroupTimeout1, starNetCallsignSwitch1, starNetTXMsgSwitch1, starNetLink1); +#else + m_config->setStarNet1(starNetBand1, starNetCallsign1, starNetLogoff1, starNetInfo1, starNetPermanent1, starNetUserTimeout1, starNetGroupTimeout1, starNetCallsignSwitch1, starNetTXMsgSwitch1); +#endif + + wxString starNetBand2 = m_starNet2->getBand(); + wxString starNetCallsign2 = m_starNet2->getCallsign(); + wxString starNetLogoff2 = m_starNet2->getLogoff(); + wxString starNetInfo2 = m_starNet2->getInfo(); + wxString starNetPermanent2 = m_starNet2->getPermanent(); + unsigned int starNetUserTimeout2 = m_starNet2->getUserTimeout(); + unsigned int starNetGroupTimeout2 = m_starNet2->getGroupTimeout(); + STARNET_CALLSIGN_SWITCH starNetCallsignSwitch2 = m_starNet2->getCallsignSwitch(); + bool starNetTXMsgSwitch2 = m_starNet2->getTXMsgSwitch(); +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + wxString starNetLink2 = m_starNet2->getReflector(); + m_config->setStarNet2(starNetBand2, starNetCallsign2, starNetLogoff2, starNetInfo2, starNetPermanent2, starNetUserTimeout2, starNetGroupTimeout2, starNetCallsignSwitch2, starNetTXMsgSwitch2, starNetLink2); +#else + m_config->setStarNet2(starNetBand2, starNetCallsign2, starNetLogoff2, starNetInfo2, starNetPermanent2, starNetUserTimeout2, starNetGroupTimeout2, starNetCallsignSwitch2, starNetTXMsgSwitch2); +#endif + + wxString starNetBand3 = m_starNet3->getBand(); + wxString starNetCallsign3 = m_starNet3->getCallsign(); + wxString starNetLogoff3 = m_starNet3->getLogoff(); + wxString starNetInfo3 = m_starNet3->getInfo(); + wxString starNetPermanent3 = m_starNet3->getPermanent(); + unsigned int starNetUserTimeout3 = m_starNet3->getUserTimeout(); + unsigned int starNetGroupTimeout3 = m_starNet3->getGroupTimeout(); + STARNET_CALLSIGN_SWITCH starNetCallsignSwitch3 = m_starNet3->getCallsignSwitch(); + bool starNetTXMsgSwitch3 = m_starNet3->getTXMsgSwitch(); +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + wxString starNetLink3 = m_starNet3->getReflector(); + m_config->setStarNet3(starNetBand3, starNetCallsign3, starNetLogoff3, starNetInfo3, starNetPermanent3, starNetUserTimeout3, starNetGroupTimeout3, starNetCallsignSwitch3, starNetTXMsgSwitch3, starNetLink3); +#else + m_config->setStarNet3(starNetBand3, starNetCallsign3, starNetLogoff3, starNetInfo3, starNetPermanent3, starNetUserTimeout3, starNetGroupTimeout3, starNetCallsignSwitch3, starNetTXMsgSwitch3); +#endif + + wxString starNetBand4 = m_starNet4->getBand(); + wxString starNetCallsign4 = m_starNet4->getCallsign(); + wxString starNetLogoff4 = m_starNet4->getLogoff(); + wxString starNetInfo4 = m_starNet4->getInfo(); + wxString starNetPermanent4 = m_starNet4->getPermanent(); + unsigned int starNetUserTimeout4 = m_starNet4->getUserTimeout(); + unsigned int starNetGroupTimeout4 = m_starNet4->getGroupTimeout(); + STARNET_CALLSIGN_SWITCH starNetCallsignSwitch4 = m_starNet4->getCallsignSwitch(); + bool starNetTXMsgSwitch4 = m_starNet4->getTXMsgSwitch(); +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + wxString starNetLink4 = m_starNet4->getReflector(); + m_config->setStarNet4(starNetBand4, starNetCallsign4, starNetLogoff4, starNetInfo4, starNetPermanent4, starNetUserTimeout4, starNetGroupTimeout4, starNetCallsignSwitch4, starNetTXMsgSwitch4, starNetLink4); +#else + m_config->setStarNet4(starNetBand4, starNetCallsign4, starNetLogoff4, starNetInfo4, starNetPermanent4, starNetUserTimeout4, starNetGroupTimeout4, starNetCallsignSwitch4, starNetTXMsgSwitch4); +#endif + + wxString starNetBand5 = m_starNet5->getBand(); + wxString starNetCallsign5 = m_starNet5->getCallsign(); + wxString starNetLogoff5 = m_starNet5->getLogoff(); + wxString starNetInfo5 = m_starNet5->getInfo(); + wxString starNetPermanent5 = m_starNet5->getPermanent(); + unsigned int starNetUserTimeout5 = m_starNet5->getUserTimeout(); + unsigned int starNetGroupTimeout5 = m_starNet5->getGroupTimeout(); + STARNET_CALLSIGN_SWITCH starNetCallsignSwitch5 = m_starNet5->getCallsignSwitch(); + bool starNetTXMsgSwitch5 = m_starNet5->getTXMsgSwitch(); +#if defined(DEXTRA_LINK) || defined(DCS_LINK) + wxString starNetLink5 = m_starNet5->getReflector(); + m_config->setStarNet5(starNetBand5, starNetCallsign5, starNetLogoff5, starNetInfo5, starNetPermanent5, starNetUserTimeout5, starNetGroupTimeout5, starNetCallsignSwitch5, starNetTXMsgSwitch5, starNetLink5); +#else + m_config->setStarNet5(starNetBand5, starNetCallsign5, starNetLogoff5, starNetInfo5, starNetPermanent5, starNetUserTimeout5, starNetGroupTimeout5, starNetCallsignSwitch5, starNetTXMsgSwitch5); +#endif + + bool remoteEnabled = m_remote->getEnabled(); + wxString remotePassword = m_remote->getPassword(); + unsigned int remotePort = m_remote->getPort(); + m_config->setRemote(remoteEnabled, remotePassword, remotePort); + + TEXT_LANG language = m_miscellaneous->getLanguage(); + bool infoEnabled = m_miscellaneous->getInfoEnabled(); + bool echoEnabled = m_miscellaneous->getEchoEnabled(); + bool logEnabled = m_miscellaneous->getLogEnabled(); + bool dratsEnabled = m_miscellaneous->getDRATSEnabled(); + bool dtmfEnabled = m_miscellaneous->getDTMFEnabled(); + m_config->setMiscellaneous(language, infoEnabled, echoEnabled, logEnabled, dratsEnabled, dtmfEnabled); + + bool ret = m_config->write(); + if (!ret) { + wxMessageDialog dialog(this, _("There was an error when writing the ircDDB Gateway configuration file"), _("Error"), wxICON_ERROR); + dialog.ShowModal(); + } else { + wxMessageDialog dialog(this, _("The changes made will not take effect\nuntil the ircDDB Gateway is (re)started"), _("Information"), wxICON_INFORMATION); + dialog.ShowModal(); + } +} + +void CIRCDDBGatewayConfigFrame::onAbout(wxCommandEvent&) +{ + wxAboutDialogInfo info; + info.AddDeveloper(wxT("Jonathan Naylor, G4KLX")); + info.SetCopyright(wxT("(C) 2010-2015 using GPL v2 or later")); + info.SetName(APPLICATION_NAME); + info.SetVersion(VERSION); + info.SetDescription(_("This program configures the ircDDB Gateway.")); + + ::wxAboutBox(info); +} diff --git a/ircDDBGatewayConfig/IRCDDBGatewayConfigFrame.h b/ircDDBGatewayConfig/IRCDDBGatewayConfigFrame.h new file mode 100644 index 0000000..15032c0 --- /dev/null +++ b/ircDDBGatewayConfig/IRCDDBGatewayConfigFrame.h @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2010-2014 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef IRCDDBGatewayConfigFrame_H +#define IRCDDBGatewayConfigFrame_H + +#include "IRCDDBGatewayConfigMiscellaneousSet.h" +#include "IRCDDBGatewayConfigGatewaySet.h" +#include "IRCDDBGatewayConfigIrcDDBSet.h" +#include "IRCDDBGatewayConfig.h" +#include "RepeaterInfoSet.h" +#include "RepeaterDataSet.h" +#include "StarNetSet.h" +#include "RemoteSet.h" +#include "DExtraSet.h" +#include "DPlusSet.h" +#include "DPRSSet.h" +#include "DCSSet.h" +#include "XLXSet.h" +#include "Defs.h" + +#include + +class CIRCDDBGatewayConfigFrame : public wxFrame { +public: + CIRCDDBGatewayConfigFrame(const wxString& title, const wxString& confDir, const wxString& name); + virtual ~CIRCDDBGatewayConfigFrame(); + + virtual void onQuit(wxCommandEvent& event); + virtual void onSave(wxCommandEvent& event); + virtual void onAbout(wxCommandEvent& event); + virtual void onClose(wxCloseEvent& event); + +private: + CIRCDDBGatewayConfig* m_config; + CIRCDDBGatewayConfigGatewaySet* m_gateway; + CRepeaterDataSet* m_repeaterData1; + CRepeaterInfoSet* m_repeaterInfo1; + CRepeaterDataSet* m_repeaterData2; + CRepeaterInfoSet* m_repeaterInfo2; + CRepeaterDataSet* m_repeaterData3; + CRepeaterInfoSet* m_repeaterInfo3; + CRepeaterDataSet* m_repeaterData4; + CRepeaterInfoSet* m_repeaterInfo4; + CIRCDDBGatewayConfigIrcDDBSet* m_ircDDB; + CIRCDDBGatewayConfigIrcDDBSet* m_ircDDB2; + CIRCDDBGatewayConfigIrcDDBSet* m_ircDDB3; + CIRCDDBGatewayConfigIrcDDBSet* m_ircDDB4; + CDPRSSet* m_dprs; + CDExtraSet* m_dextra; + CDPlusSet* m_dplus; + CDCSSet* m_dcs; + CXLXSet* m_xlx; + CStarNetSet* m_starNet1; + CStarNetSet* m_starNet2; + CStarNetSet* m_starNet3; + CStarNetSet* m_starNet4; + CStarNetSet* m_starNet5; + CRemoteSet* m_remote; + CIRCDDBGatewayConfigMiscellaneousSet* m_miscellaneous; + + DECLARE_EVENT_TABLE() + + wxMenuBar* createMenuBar(); +}; + +#endif diff --git a/ircDDBGatewayConfig/IRCDDBGatewayConfigGatewaySet.cpp b/ircDDBGatewayConfig/IRCDDBGatewayConfigGatewaySet.cpp new file mode 100644 index 0000000..4f469a9 --- /dev/null +++ b/ircDDBGatewayConfig/IRCDDBGatewayConfigGatewaySet.cpp @@ -0,0 +1,320 @@ +/* + * Copyright (C) 2010-2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "DStarDefines.h" +#include "IRCDDBGatewayConfigGatewaySet.h" +#include + +const unsigned int DESCRIPTION_WIDTH = 120U; +const unsigned int ADDRESS_WIDTH = 120U; +const unsigned int PORT_WIDTH = 80U; + +const unsigned int DESCRIPTION_LENGTH = 20U; +const unsigned int ADDRESS_LENGTH = 15U; +const unsigned int PORT_LENGTH = 5U; + +const unsigned int BORDER_SIZE = 5U; + +CIRCDDBGatewayConfigGatewaySet::CIRCDDBGatewayConfigGatewaySet(wxWindow* parent, int id, const wxString& title, GATEWAY_TYPE type, const wxString& callsign, const wxString& address, const wxString& icomAddress, unsigned int icomPort, const wxString& hbAddress, unsigned int hbPort, double latitude, double longitude, const wxString& description1, const wxString& description2, const wxString& url) : +wxPanel(parent, id), +m_title(title), +m_type(NULL), +m_callsign(NULL), +m_address(NULL), +m_icomAddress(NULL), +m_icomPort(NULL), +m_hbAddress(NULL), +m_hbPort(NULL), +m_latitude(NULL), +m_longitude(NULL), +m_description1(NULL), +m_description2(NULL), +m_url(NULL) +{ + wxFlexGridSizer* sizer = new wxFlexGridSizer(3); + + wxStaticText* typeLabel = new wxStaticText(this, -1, _("Type")); + sizer->Add(typeLabel, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + m_type = new wxChoice(this, -1); + m_type->Append(_("Repeater")); + m_type->Append(_("Hotspot")); + m_type->Append(_("Dongle")); + sizer->Add(m_type, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + m_type->SetSelection(int(type)); + + wxStaticText* dummy10Label = new wxStaticText(this, -1, wxEmptyString); + sizer->Add(dummy10Label, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + wxStaticText* callsignLabel = new wxStaticText(this, -1, _("Callsign")); + sizer->Add(callsignLabel, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + wxString call = callsign; + call.Truncate(LONG_CALLSIGN_LENGTH - 1U); + call.Trim(); + + m_callsign = new CCallsignTextCtrl(this, -1, call, wxDefaultPosition, wxSize(ADDRESS_WIDTH, -1)); + m_callsign->SetMaxLength(LONG_CALLSIGN_LENGTH); + sizer->Add(m_callsign, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + + wxStaticText* gLabel = new wxStaticText(this, -1, wxT("G")); + sizer->Add(gLabel, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + wxStaticText* addressLabel = new wxStaticText(this, -1, _("Gateway Address")); + sizer->Add(addressLabel, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + m_address = new CAddressTextCtrl(this, -1, address, wxDefaultPosition, wxSize(ADDRESS_WIDTH, -1)); + m_address->SetMaxLength(ADDRESS_LENGTH); + sizer->Add(m_address, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + + wxStaticText* dummy0Label = new wxStaticText(this, -1, wxEmptyString); + sizer->Add(dummy0Label, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + wxStaticText* icomAddressLabel = new wxStaticText(this, -1, _("Local Icom Address")); + sizer->Add(icomAddressLabel, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + m_icomAddress = new CAddressTextCtrl(this, -1, icomAddress, wxDefaultPosition, wxSize(ADDRESS_WIDTH, -1)); + m_icomAddress->SetMaxLength(ADDRESS_LENGTH); + sizer->Add(m_icomAddress, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + + wxStaticText* dummy1Label = new wxStaticText(this, -1, wxEmptyString); + sizer->Add(dummy1Label, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + wxStaticText* icomPortLabel = new wxStaticText(this, -1, _("Local Icom Port")); + sizer->Add(icomPortLabel, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + wxString buffer; + buffer.Printf(wxT("%u"), icomPort); + + m_icomPort = new CPortTextCtrl(this, -1, buffer, wxDefaultPosition, wxSize(PORT_WIDTH, -1)); + m_icomPort->SetMaxLength(PORT_LENGTH); + sizer->Add(m_icomPort, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + + wxStaticText* dummy2Label = new wxStaticText(this, -1, wxEmptyString); + sizer->Add(dummy2Label, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + wxStaticText* hbAddressLabel = new wxStaticText(this, -1, _("Local HB Address")); + sizer->Add(hbAddressLabel, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + m_hbAddress = new CAddressTextCtrl(this, -1, hbAddress, wxDefaultPosition, wxSize(ADDRESS_WIDTH, -1)); + m_hbAddress->SetMaxLength(ADDRESS_LENGTH); + sizer->Add(m_hbAddress, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + + wxStaticText* dummy3Label = new wxStaticText(this, -1, wxEmptyString); + sizer->Add(dummy3Label, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + wxStaticText* hbPortLabel = new wxStaticText(this, -1, _("Local HB Port")); + sizer->Add(hbPortLabel, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + buffer.Printf(wxT("%u"), hbPort); + + m_hbPort = new CPortTextCtrl(this, -1, buffer, wxDefaultPosition, wxSize(PORT_WIDTH, -1)); + m_hbPort->SetMaxLength(PORT_LENGTH); + sizer->Add(m_hbPort, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + + wxStaticText* dummy4Label = new wxStaticText(this, -1, wxEmptyString); + sizer->Add(dummy4Label, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + wxStaticText* latitudeLabel = new wxStaticText(this, -1, _("Latitude")); + sizer->Add(latitudeLabel, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + buffer.Printf(wxT("%lf"), latitude); + + m_latitude = new wxTextCtrl(this, -1, buffer, wxDefaultPosition, wxSize(PORT_WIDTH, -1)); + sizer->Add(m_latitude, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + + wxStaticText* dummy5Label = new wxStaticText(this, -1, wxEmptyString); + sizer->Add(dummy5Label, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + wxStaticText* longitudeLabel = new wxStaticText(this, -1, _("Longitude")); + sizer->Add(longitudeLabel, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + buffer.Printf(wxT("%lf"), longitude); + + m_longitude = new wxTextCtrl(this, -1, buffer, wxDefaultPosition, wxSize(PORT_WIDTH, -1)); + sizer->Add(m_longitude, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + + wxStaticText* dummy6Label = new wxStaticText(this, -1, wxEmptyString); + sizer->Add(dummy6Label, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + wxStaticText* descriptionLabel = new wxStaticText(this, -1, _("QTH")); + sizer->Add(descriptionLabel, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + m_description1 = new CDescriptionTextCtrl(this, -1, description1, wxDefaultPosition, wxSize(DESCRIPTION_WIDTH, -1)); + m_description1->SetMaxLength(DESCRIPTION_LENGTH); + sizer->Add(m_description1, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + + wxStaticText* dummy7Label = new wxStaticText(this, -1, wxEmptyString); + sizer->Add(dummy7Label, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + wxStaticText* dummy8Label = new wxStaticText(this, -1, wxEmptyString); + sizer->Add(dummy8Label, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + m_description2 = new CDescriptionTextCtrl(this, -1, description2, wxDefaultPosition, wxSize(DESCRIPTION_WIDTH, -1)); + m_description2->SetMaxLength(DESCRIPTION_LENGTH); + sizer->Add(m_description2, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + + wxStaticText* dummy9Label = new wxStaticText(this, -1, wxEmptyString); + sizer->Add(dummy9Label, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + wxStaticText* urlLabel = new wxStaticText(this, -1, _("URL")); + sizer->Add(urlLabel, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + m_url = new CDescriptionTextCtrl(this, -1, url, wxDefaultPosition, wxSize(DESCRIPTION_WIDTH, -1)); + sizer->Add(m_url, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + + SetAutoLayout(true); + + SetSizer(sizer); +} + + +CIRCDDBGatewayConfigGatewaySet::~CIRCDDBGatewayConfigGatewaySet() +{ +} + +bool CIRCDDBGatewayConfigGatewaySet::Validate() +{ + int n = m_type->GetCurrentSelection(); + if (n == wxNOT_FOUND) + return false; + + wxString callsign = getCallsign(); + + if (callsign.IsEmpty()) { + wxMessageDialog dialog(this, _("The Gateway Callsign is not valid"), m_title + _(" Error"), wxICON_ERROR); + dialog.ShowModal(); + return false; + } + + unsigned int port = getIcomPort(); + + if (port == 0U || port > 65535U) { + wxMessageDialog dialog(this, _("The Icom Port is not valid"), m_title + _(" Error"), wxICON_ERROR); + dialog.ShowModal(); + return false; + } + + port = getHBPort(); + + if (port == 0U || port > 65535U) { + wxMessageDialog dialog(this, _("The Homebrew Port is not valid"), m_title + _(" Error"), wxICON_ERROR); + dialog.ShowModal(); + return false; + } + + double latitude = getLatitude(); + + if (latitude < -90.0 || latitude > 90.0) { + wxMessageDialog dialog(this, _("The Latitude is invalid"), m_title + _(" Error"), wxICON_ERROR); + dialog.ShowModal(); + return false; + } + + double longitude = getLongitude(); + + if (longitude < -180.0 || longitude > 180.0) { + wxMessageDialog dialog(this, _("The Longitude is invalid"), m_title + _(" Error"), wxICON_ERROR); + dialog.ShowModal(); + return false; + } + + return true; +} + +GATEWAY_TYPE CIRCDDBGatewayConfigGatewaySet::getType() const +{ + int n = m_type->GetCurrentSelection(); + if (n == wxNOT_FOUND) + return GT_REPEATER; + + return GATEWAY_TYPE(n); +} + +wxString CIRCDDBGatewayConfigGatewaySet::getCallsign() const +{ + wxString callsign = m_callsign->GetValue(); + + callsign.MakeUpper(); + + return callsign; +} + +wxString CIRCDDBGatewayConfigGatewaySet::getAddress() const +{ + return m_address->GetValue(); +} + +wxString CIRCDDBGatewayConfigGatewaySet::getIcomAddress() const +{ + return m_icomAddress->GetValue(); +} + +unsigned int CIRCDDBGatewayConfigGatewaySet::getIcomPort() const +{ + unsigned long n; + m_icomPort->GetValue().ToULong(&n); + + return n; +} + +wxString CIRCDDBGatewayConfigGatewaySet::getHBAddress() const +{ + return m_hbAddress->GetValue(); +} + +unsigned int CIRCDDBGatewayConfigGatewaySet::getHBPort() const +{ + unsigned long n; + m_hbPort->GetValue().ToULong(&n); + + return n; +} + +double CIRCDDBGatewayConfigGatewaySet::getLatitude() const +{ + double val; + + m_latitude->GetValue().ToDouble(&val); + + return val; +} + +double CIRCDDBGatewayConfigGatewaySet::getLongitude() const +{ + double val; + + m_longitude->GetValue().ToDouble(&val); + + return val; +} + +wxString CIRCDDBGatewayConfigGatewaySet::getDescription1() const +{ + return m_description1->GetValue(); +} + +wxString CIRCDDBGatewayConfigGatewaySet::getDescription2() const +{ + return m_description2->GetValue(); +} + +wxString CIRCDDBGatewayConfigGatewaySet::getURL() const +{ + return m_url->GetValue(); +} diff --git a/ircDDBGatewayConfig/IRCDDBGatewayConfigGatewaySet.h b/ircDDBGatewayConfig/IRCDDBGatewayConfigGatewaySet.h new file mode 100644 index 0000000..658bf40 --- /dev/null +++ b/ircDDBGatewayConfig/IRCDDBGatewayConfigGatewaySet.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2010-2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef IRCDDBGatewayConfigGatewaySet_H +#define IRCDDBGatewayConfigGatewaySet_H + +#include "DescriptionTextCtrl.h" +#include "CallsignTextCtrl.h" +#include "AddressTextCtrl.h" +#include "PortTextCtrl.h" +#include "Defs.h" + +#include + +class CIRCDDBGatewayConfigGatewaySet : public wxPanel { +public: + CIRCDDBGatewayConfigGatewaySet(wxWindow* parent, int id, const wxString& title, GATEWAY_TYPE type, const wxString& callsign, const wxString& address, const wxString& icomAddress, unsigned int icomPort, const wxString& hbAddress, unsigned int hbPort, double latitude, double longitude, const wxString& description1, const wxString& description2, const wxString& url); + virtual ~CIRCDDBGatewayConfigGatewaySet(); + + virtual bool Validate(); + + virtual GATEWAY_TYPE getType() const; + virtual wxString getCallsign() const; + virtual wxString getAddress() const; + virtual wxString getIcomAddress() const; + virtual unsigned int getIcomPort() const; + virtual wxString getHBAddress() const; + virtual unsigned int getHBPort() const; + virtual double getLatitude() const; + virtual double getLongitude() const; + virtual wxString getDescription1() const; + virtual wxString getDescription2() const; + virtual wxString getURL() const; + +private: + wxString m_title; + wxChoice* m_type; + CCallsignTextCtrl* m_callsign; + CAddressTextCtrl* m_address; + CAddressTextCtrl* m_icomAddress; + CPortTextCtrl* m_icomPort; + CAddressTextCtrl* m_hbAddress; + CPortTextCtrl* m_hbPort; + wxTextCtrl* m_latitude; + wxTextCtrl* m_longitude; + CDescriptionTextCtrl* m_description1; + CDescriptionTextCtrl* m_description2; + CDescriptionTextCtrl* m_url; +}; + +#endif diff --git a/ircDDBGatewayConfig/IRCDDBGatewayConfigIrcDDBSet.cpp b/ircDDBGatewayConfig/IRCDDBGatewayConfigIrcDDBSet.cpp new file mode 100644 index 0000000..af4fd83 --- /dev/null +++ b/ircDDBGatewayConfig/IRCDDBGatewayConfigIrcDDBSet.cpp @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2010,2012,2013,2014 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "IRCDDBGatewayConfigIrcDDBSet.h" + +const unsigned int BORDER_SIZE = 5U; +const unsigned int CONTROL_WIDTH1 = 200U; +const unsigned int CONTROL_WIDTH2 = 80U; + +const unsigned int PORT_LENGTH = 5U; + +CIRCDDBGatewayConfigIrcDDBSet::CIRCDDBGatewayConfigIrcDDBSet(wxWindow* parent, int id, const wxString& title, bool enabled, const wxString& hostname, const wxString& username, const wxString& password) : +wxPanel(parent, id), +m_title(title), +m_enabled(NULL), +m_hostname(NULL), +m_username(NULL), +m_password(NULL) +{ + wxFlexGridSizer* sizer = new wxFlexGridSizer(2); + + wxStaticText* enabledLabel = new wxStaticText(this, -1, _("ircDDB")); + sizer->Add(enabledLabel, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + m_enabled = new wxChoice(this, -1, wxDefaultPosition, wxSize(CONTROL_WIDTH1, -1)); + m_enabled->Append(_("Disabled")); + m_enabled->Append(_("Enabled")); + sizer->Add(m_enabled, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + m_enabled->SetSelection(enabled ? 1 : 0); + + wxStaticText* hostnameLabel = new wxStaticText(this, -1, _("Hostname")); + sizer->Add(hostnameLabel, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + + m_hostname = new wxChoice(this, -1, wxDefaultPosition, wxSize(CONTROL_WIDTH1, -1)); + m_hostname->Append(wxT("group1-irc.ircddb.net")); + m_hostname->Append(wxT("group2-irc.ircddb.net")); + m_hostname->Append(wxT("rr.openquad.net")); + m_hostname->Append(wxT("freestar-irc-cluster.ve3lsr.ca")); + m_hostname->Append(wxT("server1-ik2xyp.free-dstar.org")); + m_hostname->Append(wxT("ircddb.dstar.su")); + sizer->Add(m_hostname, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + m_hostname->SetStringSelection(hostname); + + wxStaticText* usernameLabel = new wxStaticText(this, -1, _("Username")); + sizer->Add(usernameLabel, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + + m_username = new wxTextCtrl(this, -1, username, wxDefaultPosition, wxSize(CONTROL_WIDTH2, -1)); + sizer->Add(m_username, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + + wxStaticText* passwordLabel = new wxStaticText(this, -1, _("Password")); + sizer->Add(passwordLabel, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + + m_password = new wxTextCtrl(this, -1, password, wxDefaultPosition, wxSize(CONTROL_WIDTH1, -1), wxTE_PASSWORD); + sizer->Add(m_password, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + + SetAutoLayout(true); + + SetSizer(sizer); +} + + +CIRCDDBGatewayConfigIrcDDBSet::~CIRCDDBGatewayConfigIrcDDBSet() +{ +} + +bool CIRCDDBGatewayConfigIrcDDBSet::Validate() +{ + int n = m_enabled->GetCurrentSelection(); + if (n == wxNOT_FOUND) + return false; + + bool enabled = getEnabled(); + if (!enabled) + return true; + + bool res = getHostname().IsEmpty(); + if (res) { + wxMessageDialog dialog(this, _("The ircDDB Hostname may not be empty"), m_title + _(" Error"), wxICON_ERROR); + dialog.ShowModal(); + return false; + } + + res = getUsername().IsEmpty(); + if (res) { + wxMessageDialog dialog(this, _("The ircDDB Username may not be empty"), m_title + _(" Error"), wxICON_ERROR); + dialog.ShowModal(); + return false; + } + + return true; +} + +bool CIRCDDBGatewayConfigIrcDDBSet::getEnabled() const +{ + int c = m_enabled->GetCurrentSelection(); + if (c == wxNOT_FOUND) + return false; + + return c == 1; +} + +wxString CIRCDDBGatewayConfigIrcDDBSet::getHostname() const +{ + return m_hostname->GetStringSelection(); +} + +wxString CIRCDDBGatewayConfigIrcDDBSet::getUsername() const +{ + return m_username->GetValue(); +} + +wxString CIRCDDBGatewayConfigIrcDDBSet::getPassword() const +{ + return m_password->GetValue(); +} diff --git a/ircDDBGatewayConfig/IRCDDBGatewayConfigIrcDDBSet.h b/ircDDBGatewayConfig/IRCDDBGatewayConfigIrcDDBSet.h new file mode 100644 index 0000000..7b1936e --- /dev/null +++ b/ircDDBGatewayConfig/IRCDDBGatewayConfigIrcDDBSet.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2010,2012,2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef IRCDDBGatewayConfigIrcDDBSet_H +#define IRCDDBGatewayConfigIrcDDBSet_H + +#include + +class CIRCDDBGatewayConfigIrcDDBSet : public wxPanel { +public: + CIRCDDBGatewayConfigIrcDDBSet(wxWindow* parent, int id, const wxString& title, bool enabled, const wxString& hostname, const wxString& username, const wxString& password); + virtual ~CIRCDDBGatewayConfigIrcDDBSet(); + + virtual bool Validate(); + + virtual bool getEnabled() const; + virtual wxString getHostname() const; + virtual wxString getUsername() const; + virtual wxString getPassword() const; + +private: + wxString m_title; + wxChoice* m_enabled; + wxChoice* m_hostname; + wxTextCtrl* m_username; + wxTextCtrl* m_password; +}; + +#endif diff --git a/ircDDBGatewayConfig/IRCDDBGatewayConfigMiscellaneousSet.cpp b/ircDDBGatewayConfig/IRCDDBGatewayConfigMiscellaneousSet.cpp new file mode 100644 index 0000000..fa6cf95 --- /dev/null +++ b/ircDDBGatewayConfig/IRCDDBGatewayConfigMiscellaneousSet.cpp @@ -0,0 +1,185 @@ +/* + * Copyright (C) 2010-2013 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "IRCDDBGatewayConfigMiscellaneousSet.h" +#include "DStarDefines.h" + +const unsigned int CONTROL_WIDTH = 130U; + +const unsigned int BORDER_SIZE = 5U; + +CIRCDDBGatewayConfigMiscellaneousSet::CIRCDDBGatewayConfigMiscellaneousSet(wxWindow* parent, int id, const wxString& title, TEXT_LANG language, bool infoEnabled, bool echoEnabled, bool logEnabled, bool dratsEnabled, bool dtmfEnabled) : +wxPanel(parent, id), +m_title(title), +m_language(NULL), +m_infoEnabled(NULL), +m_echoEnabled(NULL), +m_logEnabled(NULL), +m_dratsEnabled(NULL), +m_dtmfEnabled(NULL) +{ + wxFlexGridSizer* sizer = new wxFlexGridSizer(2); + + wxStaticText* languageLabel = new wxStaticText(this, -1, _("Language")); + sizer->Add(languageLabel, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + m_language = new wxChoice(this, -1, wxDefaultPosition, wxSize(CONTROL_WIDTH, -1)); + m_language->Append(wxT("English (UK)")); + m_language->Append(wxT("Deutsch")); + m_language->Append(wxT("Dansk")); + m_language->Append(wxT("Francais")); + m_language->Append(wxT("Italiano")); + m_language->Append(wxT("Polski")); + m_language->Append(wxT("English (US)")); + m_language->Append(wxT("Espanol")); + m_language->Append(wxT("Svenska")); + m_language->Append(wxT("Nederlands (NL)")); + m_language->Append(wxT("Nederlands (BE)")); + m_language->Append(wxT("Norsk")); + m_language->Append(wxT("Portugues")); + sizer->Add(m_language, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + m_language->SetSelection(int(language)); + + wxStaticText* infoEnabledLabel = new wxStaticText(this, -1, _("Info Command")); + sizer->Add(infoEnabledLabel, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + m_infoEnabled = new wxChoice(this, -1, wxDefaultPosition, wxSize(CONTROL_WIDTH, -1)); + m_infoEnabled->Append(_("Disabled")); + m_infoEnabled->Append(_("Enabled")); + sizer->Add(m_infoEnabled, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + m_infoEnabled->SetSelection(infoEnabled ? 1 : 0); + + wxStaticText* echoEnabledLabel = new wxStaticText(this, -1, _("Echo Command")); + sizer->Add(echoEnabledLabel, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + m_echoEnabled = new wxChoice(this, -1, wxDefaultPosition, wxSize(CONTROL_WIDTH, -1)); + m_echoEnabled->Append(_("Disabled")); + m_echoEnabled->Append(_("Enabled")); + sizer->Add(m_echoEnabled, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + m_echoEnabled->SetSelection(echoEnabled ? 1 : 0); + + wxStaticText* logEnabledLabel = new wxStaticText(this, -1, _("GUI Log")); + sizer->Add(logEnabledLabel, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + m_logEnabled = new wxChoice(this, -1, wxDefaultPosition, wxSize(CONTROL_WIDTH, -1)); + m_logEnabled->Append(_("Disabled")); + m_logEnabled->Append(_("Enabled")); + sizer->Add(m_logEnabled, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + m_logEnabled->SetSelection(logEnabled ? 1 : 0); + + wxStaticText* dratsEnabledLabel = new wxStaticText(this, -1, wxT("D-RATS")); + sizer->Add(dratsEnabledLabel, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + m_dratsEnabled = new wxChoice(this, -1, wxDefaultPosition, wxSize(CONTROL_WIDTH, -1)); + m_dratsEnabled->Append(_("Disabled")); + m_dratsEnabled->Append(_("Enabled")); + sizer->Add(m_dratsEnabled, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + m_dratsEnabled->SetSelection(dratsEnabled ? 1 : 0); + + wxStaticText* dtmfEnabledLabel = new wxStaticText(this, -1, wxT("DTMF Control")); + sizer->Add(dtmfEnabledLabel, 0, wxALL | wxALIGN_RIGHT, BORDER_SIZE); + + m_dtmfEnabled = new wxChoice(this, -1, wxDefaultPosition, wxSize(CONTROL_WIDTH, -1)); + m_dtmfEnabled->Append(_("Disabled")); + m_dtmfEnabled->Append(_("Enabled")); + sizer->Add(m_dtmfEnabled, 0, wxALL | wxALIGN_LEFT, BORDER_SIZE); + m_dtmfEnabled->SetSelection(dtmfEnabled ? 1 : 0); + + SetAutoLayout(true); + + SetSizer(sizer); +} + + +CIRCDDBGatewayConfigMiscellaneousSet::~CIRCDDBGatewayConfigMiscellaneousSet() +{ +} + +bool CIRCDDBGatewayConfigMiscellaneousSet::Validate() +{ + if (m_language->GetCurrentSelection() == wxNOT_FOUND) + return false; + + if (m_logEnabled->GetCurrentSelection() == wxNOT_FOUND) + return false; + + if (m_infoEnabled->GetCurrentSelection() == wxNOT_FOUND) + return false; + + if (m_echoEnabled->GetCurrentSelection() == wxNOT_FOUND) + return false; + + if (m_dratsEnabled->GetCurrentSelection() == wxNOT_FOUND) + return false; + + return m_dtmfEnabled->GetCurrentSelection() != wxNOT_FOUND; +} + +TEXT_LANG CIRCDDBGatewayConfigMiscellaneousSet::getLanguage() const +{ + int c = m_language->GetCurrentSelection(); + if (c == wxNOT_FOUND) + return TL_ENGLISH_UK; + + return TEXT_LANG(c); +} + +bool CIRCDDBGatewayConfigMiscellaneousSet::getInfoEnabled() const +{ + int c = m_infoEnabled->GetCurrentSelection(); + if (c == wxNOT_FOUND) + return false; + + return c == 1; +} + +bool CIRCDDBGatewayConfigMiscellaneousSet::getEchoEnabled() const +{ + int c = m_echoEnabled->GetCurrentSelection(); + if (c == wxNOT_FOUND) + return false; + + return c == 1; +} + +bool CIRCDDBGatewayConfigMiscellaneousSet::getLogEnabled() const +{ + int c = m_logEnabled->GetCurrentSelection(); + if (c == wxNOT_FOUND) + return false; + + return c == 1; +} + +bool CIRCDDBGatewayConfigMiscellaneousSet::getDRATSEnabled() const +{ + int c = m_dratsEnabled->GetCurrentSelection(); + if (c == wxNOT_FOUND) + return false; + + return c == 1; +} + +bool CIRCDDBGatewayConfigMiscellaneousSet::getDTMFEnabled() const +{ + int c = m_dtmfEnabled->GetCurrentSelection(); + if (c == wxNOT_FOUND) + return false; + + return c == 1; +} diff --git a/ircDDBGatewayConfig/IRCDDBGatewayConfigMiscellaneousSet.h b/ircDDBGatewayConfig/IRCDDBGatewayConfigMiscellaneousSet.h new file mode 100644 index 0000000..c5c81fd --- /dev/null +++ b/ircDDBGatewayConfig/IRCDDBGatewayConfigMiscellaneousSet.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2010,2011,2012 by Jonathan Naylor G4KLX + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef IRCDDBGatewayConfigMiscellaneousSet_H +#define IRCDDBGatewayConfigMiscellaneousSet_H + +#include "Defs.h" + +#include + +class CIRCDDBGatewayConfigMiscellaneousSet : public wxPanel { +public: + CIRCDDBGatewayConfigMiscellaneousSet(wxWindow* parent, int id, const wxString& title, TEXT_LANG language, bool infoEnabled, bool echoEnabled, bool logEnabled, bool dratsEnabled, bool dtmfEnabled); + virtual ~CIRCDDBGatewayConfigMiscellaneousSet(); + + virtual bool Validate(); + + virtual TEXT_LANG getLanguage() const; + + virtual bool getInfoEnabled() const; + + virtual bool getEchoEnabled() const; + + virtual bool getLogEnabled() const; + + virtual bool getDRATSEnabled() const; + + virtual bool getDTMFEnabled() const; + +private: + wxString m_title; + wxChoice* m_language; + wxChoice* m_infoEnabled; + wxChoice* m_echoEnabled; + wxChoice* m_logEnabled; + wxChoice* m_dratsEnabled; + wxChoice* m_dtmfEnabled; +}; + +#endif diff --git a/ircDDBGatewayConfig/ircDDBGatewayConfig.vcxproj b/ircDDBGatewayConfig/ircDDBGatewayConfig.vcxproj new file mode 100644 index 0000000..1d6186c --- /dev/null +++ b/ircDDBGatewayConfig/ircDDBGatewayConfig.vcxproj @@ -0,0 +1,198 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {D0A32505-822B-4936-A61B-A5151966AEAA} + ircDDBGatewayConfig + Win32Proj + 10.0.16299.0 + + + + Application + v141 + Unicode + true + + + Application + v141 + Unicode + true + + + Application + v141 + Unicode + + + Application + v141 + Unicode + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>14.0.24720.0 + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + true + $(WXWIN)\include;$(WXWIN)\lib\vc_dll\mswud;$(IncludePath) + + + true + $(WXWIN)\include;$(WXWIN)\lib\vc_x64_dll\mswud;$(IncludePath) + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + false + + + false + + + + Disabled + $(WXWIN)\include\msvc;$(WXWIN)\include;../Common;../GUICommon;../ircDDB;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;WINVER=0x0400;__WXMSW__;WXUSINGDLL;wxUSE_GUI=1;__WXDEBUG__;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;DCS_LINK;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + Level4 + EditAndContinue + + + ws2_32.lib;%(AdditionalDependencies) + $(WXWIN)\lib\vc_dll;%(AdditionalLibraryDirectories) + true + Windows + MachineX86 + + + + + Disabled + $(WXWIN)\include\msvc;$(WXWIN)\include;../Common;../GUICommon;../ircDDB;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;WINVER=0x0400;__WXMSW__;WXUSINGDLL;wxUSE_GUI=1;__WXDEBUG__;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;DCS_LINK;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + + + Level4 + ProgramDatabase + + + ws2_32.lib;%(AdditionalDependencies) + $(WXWIN)\lib\vc_x64_dll;%(AdditionalLibraryDirectories) + true + Windows + + + + + MaxSpeed + true + $(WXWIN)\include\msvc;$(WXWIN)\include;../Common;../GUICommon;../ircDDB;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;WINVER=0x0400;__WXMSW__;WXUSINGDLL;wxUSE_GUI=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) + MultiThreadedDLL + true + + Level3 + ProgramDatabase + + + ws2_32.lib;%(AdditionalDependencies) + $(WXWIN)\lib\vc_dll;%(AdditionalLibraryDirectories) + true + Windows + true + true + MachineX86 + + + + + MaxSpeed + true + $(WXWIN)\include\msvc;$(WXWIN)\include;../Common;../GUICommon;../ircDDB;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;WINVER=0x0400;__WXMSW__;WXUSINGDLL;wxUSE_GUI=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) + MultiThreadedDLL + true + + + Level3 + ProgramDatabase + + + ws2_32.lib;%(AdditionalDependencies) + $(WXWIN)\lib\vc_x64_dll;%(AdditionalLibraryDirectories) + true + Windows + true + true + + + + + + + + + + + + + + + + + + + + {e793cb8e-2ac9-431a-bbfc-3f52537bb3cf} + false + + + {02d03515-0bbe-4553-8c40-566a597478f8} + false + + + + + + \ No newline at end of file diff --git a/ircDDBGatewayConfig/ircDDBGatewayConfig.vcxproj.filters b/ircDDBGatewayConfig/ircDDBGatewayConfig.vcxproj.filters new file mode 100644 index 0000000..3d00a5e --- /dev/null +++ b/ircDDBGatewayConfig/ircDDBGatewayConfig.vcxproj.filters @@ -0,0 +1,50 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + \ No newline at end of file