/*
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()