You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
404 lines
7.5 KiB
404 lines
7.5 KiB
#include <string>
|
|
#include <vector>
|
|
#include <regex>
|
|
#include <mutex>
|
|
|
|
#include "IRCutils.h"
|
|
#include "IRCProtocol.h"
|
|
#include "IRCMessageQueue.h"
|
|
#include "IRCDDBApp.h"
|
|
|
|
#define CIRCDDB_VERSION "2.0.0"
|
|
|
|
void IRCProtocol::Init(IRCDDBApp *app, const std::string &callsign, const std::string &password, const std::string &channel, const std::string &versionInfo)
|
|
{
|
|
srand(time(NULL));
|
|
this->password = password;
|
|
this->channel = channel;
|
|
this->app = app;
|
|
|
|
this->versionInfo = "CIRCDDB:";
|
|
this->versionInfo.append(CIRCDDB_VERSION);
|
|
|
|
if (versionInfo.length() > 0)
|
|
{
|
|
this->versionInfo.append(" ");
|
|
this->versionInfo.append(versionInfo);
|
|
}
|
|
|
|
|
|
int hyphenPos = callsign.find('-');
|
|
|
|
if (hyphenPos < 0)
|
|
{
|
|
std::string n;
|
|
|
|
n = callsign + "-1";
|
|
nicks.push_back(n);
|
|
n = callsign + "-2";
|
|
nicks.push_back(n);
|
|
n = callsign + "-3";
|
|
nicks.push_back(n);
|
|
n = callsign + "-4";
|
|
nicks.push_back(n);
|
|
}
|
|
else
|
|
{
|
|
nicks.push_back(callsign);
|
|
}
|
|
|
|
name = callsign;
|
|
|
|
pingTimer = 60; // 30 seconds
|
|
state = 0;
|
|
timer = 0;
|
|
|
|
|
|
chooseNewNick();
|
|
}
|
|
|
|
IRCProtocol::~IRCProtocol()
|
|
{
|
|
}
|
|
|
|
void IRCProtocol::chooseNewNick()
|
|
{
|
|
int r = rand() % nicks.size();
|
|
|
|
currentNick = nicks[r];
|
|
}
|
|
|
|
void IRCProtocol::setNetworkReady(bool b)
|
|
{
|
|
if (b == true)
|
|
{
|
|
if (state != 0)
|
|
printf("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)
|
|
std::string d = std::string("R [") + m->prefix + std::string("] [") + m->command + std::string("]");
|
|
for (int i=0; i < m->numParams; i++)
|
|
{
|
|
d.append(std::string(" [") + m->params[i] + std::string("]") );
|
|
}
|
|
// d.Replace(std::string("%"), std::string("%%"), true);
|
|
// d.Replace(std::string("\\"), std::string("\\\\"), true);
|
|
printf("%s\n", d.c_str());
|
|
#endif
|
|
|
|
if (0 == m->command.compare("004"))
|
|
{
|
|
if (state == 4)
|
|
{
|
|
if (m->params.size() > 1)
|
|
{
|
|
std::regex serverNamePattern("^grp[1-9]s[1-9].ircDDB$");
|
|
|
|
if (std::regex_match(m->params[1], serverNamePattern))
|
|
{
|
|
app->setBestServer(std::string("s-") + m->params[1].substr(0,6));
|
|
}
|
|
}
|
|
state = 5; // next: JOIN
|
|
app->setCurrentNick(currentNick);
|
|
}
|
|
}
|
|
else if (0 == m->command.compare("PING"))
|
|
{
|
|
IRCMessage *m2 = new IRCMessage();
|
|
m2->command = "PONG";
|
|
if (m->params.size() > 0)
|
|
{
|
|
m2->numParams = 1;
|
|
m2->params.push_back( m->params[0] );
|
|
}
|
|
sendQ -> putMessage(m2);
|
|
}
|
|
else if (0 == m->command.compare("JOIN"))
|
|
{
|
|
if ((m->numParams >= 1) && 0==m->params[0].compare(channel))
|
|
{
|
|
if (0==m->getPrefixNick().compare(currentNick) && (state == 6))
|
|
{
|
|
if (debugChannel.length() > 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) && 0==m->params[0].compare(debugChannel))
|
|
{
|
|
if (0==m->getPrefixNick().compare(currentNick) && (state == 8))
|
|
{
|
|
state = 10; // next: WHO *
|
|
}
|
|
}
|
|
}
|
|
else if (0 == m->command.compare("PONG"))
|
|
{
|
|
if (state == 12)
|
|
{
|
|
timer = pingTimer;
|
|
state = 11;
|
|
}
|
|
}
|
|
else if (0 == m->command.compare("PART"))
|
|
{
|
|
if ((m->numParams >= 1) && 0==m->params[0].compare(channel))
|
|
{
|
|
if (app != NULL)
|
|
{
|
|
app->userLeave( m->getPrefixNick() );
|
|
}
|
|
}
|
|
}
|
|
else if (0 == m->command.compare("KICK"))
|
|
{
|
|
if ((m->numParams >= 2) && 0==m->params[0].compare(channel))
|
|
{
|
|
if (0 == m->params[1].compare(currentNick))
|
|
{
|
|
// i was kicked!!
|
|
delete m;
|
|
return false;
|
|
}
|
|
else if (app != NULL)
|
|
{
|
|
app->userLeave( m->params[1] );
|
|
}
|
|
}
|
|
}
|
|
else if (0 == m->command.compare("QUIT"))
|
|
{
|
|
if (app != NULL)
|
|
{
|
|
app->userLeave( m->getPrefixNick() );
|
|
}
|
|
}
|
|
else if (0 == m->command.compare("PRIVMSG"))
|
|
{
|
|
if (app)
|
|
{
|
|
// std::string out;
|
|
// m->composeMessage(out);
|
|
// out.pop_back(); out.pop_back();
|
|
if (2 == m->numParams)
|
|
{
|
|
if (0 == m->params[0].compare(channel))
|
|
{
|
|
app->msgChannel(m);
|
|
}
|
|
else if (0 == m->params[0].compare(currentNick))
|
|
{
|
|
if (0 == m->params[1].find("IDRT_PING"))
|
|
{
|
|
std::string from = m->params[1].substr(10);
|
|
IRCMessage *rm = new IRCMessage("IDRT_PING");
|
|
rm->addParam(from);
|
|
app->putReplyMessage(rm);
|
|
}
|
|
else
|
|
app->msgQuery(m);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (0 == m->command.compare("352")) // WHO list
|
|
{
|
|
if ((m->numParams >= 7) && 0==m->params[0].compare(currentNick) && 0==m->params[1].compare(channel))
|
|
{
|
|
if (app != NULL)
|
|
{
|
|
app->userJoin(m->params[5], m->params[2], m->params[3]);
|
|
}
|
|
}
|
|
}
|
|
else if (0 == m->command.compare("433")) // nick collision
|
|
{
|
|
if (state == 2)
|
|
{
|
|
state = 3; // nick collision, choose new nick
|
|
timer = 10; // wait 5 seconds..
|
|
}
|
|
}
|
|
|
|
delete m;
|
|
}
|
|
|
|
IRCMessage * m;
|
|
|
|
switch (state)
|
|
{
|
|
case 1:
|
|
m = new IRCMessage();
|
|
m->command = "PASS";
|
|
m->numParams = 1;
|
|
m->params.push_back(password);
|
|
sendQ->putMessage(m);
|
|
|
|
m = new IRCMessage();
|
|
m->command = "NICK";
|
|
m->numParams = 1;
|
|
m->params.push_back(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 = "USER";
|
|
m->numParams = 4;
|
|
m->params.push_back(name);
|
|
m->params.push_back("0");
|
|
m->params.push_back("*");
|
|
m->params.push_back(versionInfo);
|
|
sendQ->putMessage(m);
|
|
|
|
timer = 30;
|
|
state = 4; // wait for login message
|
|
}
|
|
break;
|
|
|
|
case 3:
|
|
if (timer == 0)
|
|
{
|
|
chooseNewNick();
|
|
m = new IRCMessage();
|
|
m->command = "NICK";
|
|
m->numParams = 1;
|
|
m->params.push_back(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 = "JOIN";
|
|
m->numParams = 1;
|
|
m->params.push_back(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.length() == 0)
|
|
{
|
|
return false; // this state cannot be processed if there is no debug_channel
|
|
}
|
|
|
|
m = new IRCMessage();
|
|
m->command = "JOIN";
|
|
m->numParams = 1;
|
|
m->params.push_back(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 = "WHO";
|
|
m->numParams = 2;
|
|
m->params.push_back(channel);
|
|
m->params.push_back("*");
|
|
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 = "PING";
|
|
m->numParams = 1;
|
|
m->params.push_back(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;
|
|
}
|