#include "util.h"
#include "coresession.h"
+#include "coreirclisthelper.h"
#include "networkconnection.h"
#include "network.h"
#include "identity.h"
#include "ctcphandler.h"
#include "ircuser.h"
-#include "ircchannel.h"
+#include "coreircchannel.h"
+#include "logger.h"
#include <QDebug>
}
IrcServerHandler::~IrcServerHandler() {
-
}
/*! Handle a raw message string sent by the server. We try to find a suitable handler, otherwise we call a default handler. */
void IrcServerHandler::defaultHandler(QString cmd, const QString &prefix, const QList<QByteArray> &rawparams) {
// we assume that all this happens in server encoding
- QStringList params;
- foreach(QByteArray r, rawparams) params << serverDecode(r);
+ QStringList params = serverDecode(rawparams);
uint num = cmd.toUInt();
if(num) {
// A lot of server messages don't really need their own handler because they don't do much.
break;
}
// Ignore these commands.
- case 366: case 376:
+ case 321: case 366: case 376:
break;
// Everything else will be marked in red, so we can add them somewhere.
default:
- emit displayMsg(Message::Error, BufferInfo::StatusBuffer, "", cmd + " " + params.join(" "), prefix);
+ if(_whois) {
+ // many nets define their own WHOIS fields. we fetch those not in need of special attention here:
+ emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "", "[Whois] " + params.join(" "), prefix);
+ } else {
+ if(networkConnection()->coreSession()->ircListHelper()->requestInProgress(network()->networkId()))
+ networkConnection()->coreSession()->ircListHelper()->reportError(params.join(" "));
+ else
+ emit displayMsg(Message::Error, BufferInfo::StatusBuffer, "", cmd + " " + params.join(" "), prefix);
+ }
}
//qDebug() << prefix <<":"<<cmd<<params;
} else {
emit displayMsg(Message::Mode, BufferInfo::ChannelBuffer, serverDecode(params[0]), serverDecode(params).join(" "), prefix);
IrcChannel *channel = network()->ircChannel(params[0]);
+ if(!channel) {
+ // we received mode information for a channel we're not in. that means probably we've just been kicked out or something like that
+ // anyways: we don't have a place to store the data --> discard the info.
+ return;
+ }
+
QString modes = params[1];
bool add = true;
int paramOffset = 2;
return;
QString target = serverDecode(params[0]);
- if(prefix.isEmpty() || target == "AUTH")
+
+ // special treatment for welcome messages like:
+ // :ChanServ!ChanServ@services. NOTICE egst :[#apache] Welcome, this is #apache. Please read the in-channel topic message. This channel is being logged by IRSeekBot. If you have any question please see http://blog.freenode.net/?p=68
+ if(!network()->isChannelName(target)) {
+ QString msg = serverDecode(params[1]);
+ QRegExp welcomeRegExp("^\\[([^\\]]+)\\] ");
+ if(welcomeRegExp.indexIn(msg) != -1) {
+ QString channelname = welcomeRegExp.cap(1);
+ msg = msg.mid(welcomeRegExp.matchedLength());
+ CoreIrcChannel *chan = static_cast<CoreIrcChannel *>(network()->ircChannel(channelname)); // we only have CoreIrcChannels in the core, so this cast is safe
+ if(chan && !chan->receivedWelcomeMsg()) {
+ chan->setReceivedWelcomeMsg();
+ emit displayMsg(Message::Notice, BufferInfo::ChannelBuffer, channelname, msg, prefix);
+ return;
+ }
+ }
+ }
+
+ if(prefix.isEmpty() || target == "AUTH") {
target = "";
- else if(!network()->isChannelName(target))
- target = nickFromMask(prefix);
+ } else {
+ if(!target.isEmpty() && network()->prefixes().contains(target[0]))
+ target = target.mid(1);
+ if(!network()->isChannelName(target))
+ target = nickFromMask(prefix);
+ }
networkConnection()->ctcpHandler()->parse(Message::Notice, prefix, target, params[1]);
}
putCmd("PONG", params);
}
+void IrcServerHandler::handlePong(const QString &prefix, const QList<QByteArray> ¶ms) {
+ Q_UNUSED(prefix);
+ // the server is supposed to send back what we passed as param. and we send a timestamp
+ // but using quote and whatnought one can send arbitrary pings, so we have to do some sanity checks
+ if(params.count() < 2)
+ return;
+
+ QString timestamp = serverDecode(params[1]);
+ QTime sendTime = QTime::fromString(timestamp, "hh:mm:ss.zzz");
+ if(!sendTime.isValid()) {
+ emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "", "PONG " + serverDecode(params).join(" "), prefix);
+ return;
+ }
+
+ network()->setLatency(sendTime.msecsTo(QTime::currentTime()) / 2);
+}
+
void IrcServerHandler::handlePrivmsg(const QString &prefix, const QList<QByteArray> ¶ms) {
if(!checkParamCount("IrcServerHandler::handlePrivmsg()", params, 1))
return;
? QByteArray("")
: params[1];
- // are we the target?
- if(network()->isMyNick(target))
- target = nickFromMask(ircuser->nick());
+ if(!network()->isChannelName(target))
+ target = nickFromMask(prefix);
// it's possible to pack multiple privmsgs into one param using ctcp
// - > we let the ctcpHandler do the work
void IrcServerHandler::handle005(const QString &prefix, const QList<QByteArray> ¶ms) {
Q_UNUSED(prefix);
const int numParams = params.size();
- if(numParams < 1) {
- qWarning() << "IrcServerHandler::handle005(): received RPL_ISUPPORT (005) with too few parameters:" << serverDecode(params);
+ if(numParams == 0) {
+ emit displayMsg(Message::Error, BufferInfo::StatusBuffer, "", tr("Received RPL_ISUPPORT (005) without parameters!"), prefix);
return;
}
+ emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "", serverDecode(params).join(" "), prefix);
+
QString rpl_isupport_suffix = serverDecode(params.last());
- if(!rpl_isupport_suffix.toLower().contains("supported")) {
- qWarning() << "Received invalid RPL_ISUPPORT! Suffix is:" << rpl_isupport_suffix << "Excpected: are supported by this server";
- return;
+ if(!rpl_isupport_suffix.toLower().contains("are supported by this server")) {
+ emit displayMsg(Message::Error, BufferInfo::StatusBuffer, "", tr("Received non RFC compliant RPL_ISUPPORT: this can lead to unexpected behavior!"), prefix);
}
QString rawSupport;
if(me)
me->setAway(false);
- if(!params.isEmpty())
- emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "", serverDecode(params[0]));
+ if(!network()->autoAwayActive()) {
+ if(!params.isEmpty())
+ emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "", serverDecode(params[0]));
+ } else {
+ network()->setAutoAwayActive(false);
+ }
}
// 306 RPL_NOWAWAY
if(me)
me->setAway(true);
- if(!params.isEmpty())
+ if(!params.isEmpty() && !network()->autoAwayActive())
emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "", serverDecode(params[0]));
}
emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("[Whois] %1").arg(serverDecode(params).join(" ")));
}
+/* RPL_LIST - "<channel> <# visible> :<topic>" */
+void IrcServerHandler::handle322(const QString &prefix, const QList<QByteArray> ¶ms) {
+ Q_UNUSED(prefix)
+ QString channelName;
+ quint32 userCount = 0;
+ QString topic;
+
+ int paramCount = params.count();
+ switch(paramCount) {
+ case 3:
+ topic = serverDecode(params[2]);
+ case 2:
+ userCount = serverDecode(params[1]).toUInt();
+ case 1:
+ channelName = serverDecode(params[0]);
+ default:
+ break;
+ }
+ if(!networkConnection()->coreSession()->ircListHelper()->addChannel(network()->networkId(), channelName, userCount, topic))
+ emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("Channel %1 has %2 users. Topic is: %3").arg(channelName).arg(userCount).arg(topic));
+}
+
+/* RPL_LISTEND ":End of LIST" */
+void IrcServerHandler::handle323(const QString &prefix, const QList<QByteArray> ¶ms) {
+ Q_UNUSED(prefix)
+ Q_UNUSED(params)
+
+ if(!networkConnection()->coreSession()->ircListHelper()->endOfChannelList(network()->networkId()))
+ emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("End of channel list"));
+}
+
/* RPL_CHANNELMODEIS - "<channel> <mode> <mode params>" */
void IrcServerHandler::handle324(const QString &prefix, const QList<QByteArray> ¶ms) {
Q_UNUSED(prefix);
/* RPL_??? - "<channel> <creation time (unix)>" */
void IrcServerHandler::handle329(const QString &prefix, const QList<QByteArray> ¶ms) {
Q_UNUSED(prefix);
+ Q_UNUSED(params)
+#ifdef __GNUC__
+# warning "Implement handle329 (Channel creation time)"
+#endif
// FIXME implement this...
}
return;
QString channel = serverDecode(params[0]);
- network()->ircChannel(channel)->setTopic(QString());
+ IrcChannel *chan = network()->ircChannel(channel);
+ if(chan)
+ chan->setTopic(QString());
+
emit displayMsg(Message::Server, BufferInfo::ChannelBuffer, channel, tr("No topic is set for %1.").arg(channel));
}
QString channel = serverDecode(params[0]);
QString topic = channelDecode(channel, params[1]);
- network()->ircChannel(channel)->setTopic(topic);
+ IrcChannel *chan = network()->ircChannel(channel);
+ if(chan)
+ chan->setTopic(topic);
+
emit displayMsg(Message::Server, BufferInfo::ChannelBuffer, channel, tr("Topic for %1 is \"%2\"").arg(channel, topic));
}
/* RPL_NAMREPLY */
void IrcServerHandler::handle353(const QString &prefix, const QList<QByteArray> ¶ms) {
Q_UNUSED(prefix);
- if(!checkParamCount("IrcServerHandler::handle353()", params, 2))
+ if(!checkParamCount("IrcServerHandler::handle353()", params, 3))
return;
// param[0] is either "=", "*" or "@" indicating a public, private or secret channel
bool IrcServerHandler::checkParamCount(const QString &methodName, const QList<QByteArray> ¶ms, int minParams) {
if(params.count() < minParams) {
- qWarning() << qPrintable(methodName) << "requieres" << minParams << "parameters but received only" << params.count() << serverDecode(params);
+ qWarning() << qPrintable(methodName) << "requires" << minParams << "parameters but received only" << params.count() << serverDecode(params);
return false;
} else {
return true;