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.
QnetGateway/IRCProtocol.cpp

344 lines
7.7 KiB

#include <string>
#include <vector>
#include <regex>
#include <mutex>
#include "IRCutils.h"
#include "IRCProtocol.h"
#define CIRCDDB_VERSION "2.0.0"
IRCProtocol::IRCProtocol(IRCApplication *app, const std::string &callsign, const std::string &password, const std::string &channel, const std::string &versionInfo)
{
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("MODE")) {
if ((m->numParams >= 3) && 0==m->params[0].compare(channel)) {
if (app != NULL) {
size_t i;
std::string mode = m->params[1];
for (i=1; i<mode.length() && (size_t)m->numParams>=(i+2); i++) {
if (mode[i] == 'o') {
if (mode[0] == '+') {
app->userChanOp(m->params[i+1], true);
} else if (mode[0] == '-') {
app->userChanOp(m->params[i+1], false);
}
}
} // for
}
}
} else if (0 == m->command.compare("PRIVMSG")) {
if ((m->numParams == 2) && (app != NULL)) {
if (0 == m->params[0].compare(channel)) {
app->msgChannel(m);
} else if (0 == m->params[0].compare(currentNick)) {
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]);
app->userChanOp (m->params[5], 0==m->params[6].compare("H@"));
}
}
} else if (0 == m->command.compare("433")) { // nick collision
if (state == 2) {
state = 3; // nick collision, choose new nick
timer = 10; // wait 5 seconds..
}
} else if (0==m->command.compare("332") || 0==m->command.compare("TOPIC")) { // topic
if ((m->numParams == 2) && (app != NULL) && 0==m->params[0].compare(channel)) {
app->setTopic(m->params[1]);
}
}
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;
}

Powered by TurnKey Linux.