23 #include "ircresponseparser.h"    27 #include <QStringList>    29 #include "irc/constants/ircresponsetype.h"    30 #include "irc/ircctcpparser.h"    31 #include "irc/ircglobal.h"    32 #include "irc/ircmessageclass.h"    33 #include "irc/ircnetworkadapter.h"    34 #include "irc/ircuserinfo.h"    36 #include "patternlist.h"    37 #include "strings.hpp"    39 DClass<IRCResponseParser>
    56 IRCResponseParser::~IRCResponseParser()
    60 IRCResponseParser::FlagModes IRCResponseParser::getFlagMode(
char c)
    68                         return FlagModeRemove;
    75 bool IRCResponseParser::isPrefixIgnored()
 const    77         return d->network->ignoredUsersPatterns().isExactMatchAny(d->prefix);
    80 QString IRCResponseParser::joinAndTrimColonIfNecessary(
const QStringList& strList)
 const    82         QString joined = strList.join(
" ");
    83         return this->trimColonIfNecessary(joined);
    88         QString formattedMessage = message.trimmed();
    90         QRegExp prefixRegExp(
"(^:\\S+\\s)(.*)");
    91         prefixRegExp.indexIn(formattedMessage);
    93         QString prefix = prefixRegExp.cap(1);
    94         QString remainder = formattedMessage.mid(prefix.length());
    96         d->prefix = Strings::triml(prefix, 
":").trimmed();
    99         int indexExclamation = prefix.indexOf(
'!');
   100         if (indexExclamation > 0)
   102                 d->sender = d->prefix.left(indexExclamation);
   106                 d->sender = d->prefix;
   109         QStringList msgParameters = remainder.split(
" ");
   110         if (!msgParameters.isEmpty())
   112                 d->type = msgParameters.takeFirst();
   113                 d->params = msgParameters;
   115                 return parseMessage();
   131                         QString nickname = d->params.takeFirst();
   139                         d->params.takeFirst(); 
   140                         QString nickname = d->params.takeFirst();
   141                         QString reason = joinAndTrimColonIfNecessary(d->params);
   142                         emit printToNetworksCurrentChatBox(tr(
"User %1 is away: %2").arg(nickname, reason),
   143                                 IRCMessageClass::NetworkAction);
   150                         d->params.takeFirst();
   153                         QString nickname = d->params.takeFirst();
   154                         QString user = d->params.takeFirst();
   155                         QString hostName = d->params.takeFirst();
   156                         QString realName = joinAndTrimColonIfNecessary(d->params);
   158                         emit 
whoIsUser(nickname, user, hostName, realName);
   173                         d->params.takeFirst(); 
   174                         emit printToNetworksCurrentChatBox(d->params.join(
" "), IRCMessageClass::NetworkAction);
   180                         d->params.takeFirst(); 
   181                         QString nick = d->params.takeFirst();
   182                         int secondsIdle = d->params.takeFirst().toInt();
   183                         emit userIdleTime(nick, secondsIdle);
   184                         if (d->params.first().toInt() != 0)
   186                                 int joinedOn = d->params.takeFirst().toInt();
   187                                 emit userNetworkJoinDateTime(nick, QDateTime::fromTime_t(joinedOn));
   194                         d->params.takeFirst(); 
   195                         QString nick = d->params.takeFirst();
   196                         QString channels = joinAndTrimColonIfNecessary(d->params);
   197                         emit printToNetworksCurrentChatBox(tr(
"%1 is on channels: %2").arg(nick, channels),
   198                                 IRCMessageClass::NetworkAction);
   204                         d->params.takeFirst(); 
   205                         QString nick = d->params.takeFirst();
   206                         QString account = d->params.takeFirst();
   207                         QString message = joinAndTrimColonIfNecessary(d->params);
   208                         emit printToNetworksCurrentChatBox(QString(
"%1 %2 %3").arg(nick, message, account),
   209                                 IRCMessageClass::NetworkAction);
   215                         d->params.takeFirst(); 
   216                         emit iSupportReceived(d->params.join(
" "));
   222                         d->params.takeFirst(); 
   223                         QString channel = d->params.takeFirst();
   224                         QString topic = joinAndTrimColonIfNecessary(d->params);
   225                         QString msg = tr(
"Topic: %1").arg(topic);
   232                         d->params.takeFirst(); 
   233                         QString channel = d->params.takeFirst();
   234                         QString who = d->params.takeFirst();
   235                         qint64 timestampSeconds = d->params.takeFirst().toLongLong();
   236                         QDateTime date = QDateTime::fromMSecsSinceEpoch(timestampSeconds * 1000);
   237                         QString msg = tr(
"Topic set by %1 on %2.").arg(who, date.toString(
"yyyy-MM-dd hh:mm:ss"));
   244                         d->params.takeFirst(); 
   245                         QString channel = d->params.takeFirst();
   246                         QString url = joinAndTrimColonIfNecessary(d->params);
   247                         emit 
printWithClass(tr(
"URL: %1").arg(url), channel, IRCMessageClass::ChannelAction);
   253                         d->params.takeFirst(); 
   254                         QString channel = d->params.takeFirst();
   255                         QString time = joinAndTrimColonIfNecessary(d->params);
   257                                 IRCMessageClass::ChannelAction);
   270                         QString channelName = 
"";
   271                         while (!IRCGlobal::isChannelName(channelName) && !d->params.isEmpty())
   273                                 channelName = d->params.takeFirst();
   276                         if (channelName.isEmpty())
   278                                 emit parseError(tr(
"RPLNamReply: Received names list but no channel name."));
   284                         if (!d->params.isEmpty())
   286                                 d->params[0] = d->params[0].remove(0, 1);
   289                         emit namesListReceived(channelName, d->params);
   295                         QString channel = d->params[1];
   296                         emit namesListEndReceived(channel);
   305                         d->params.takeFirst();
   311                                 emit 
print(
"\n----------------------", QString());
   314                         emit 
print(joinAndTrimColonIfNecessary(d->params), QString());
   320                                 emit 
print(
"----------------------\n", QString());
   331                         d->params.takeFirst();
   334                         emit 
print(joinAndTrimColonIfNecessary(d->params), QString());
   344                         d->params.takeFirst();
   348                         QString number = d->params.takeFirst();
   349                         emit 
print(number + 
" " + joinAndTrimColonIfNecessary(d->params), QString());
   356                         d->params.takeFirst();
   359                         QString nickname = d->params.takeFirst();
   361                         emit noSuchNickname(nickname);
   368                         d->params.takeFirst();
   369                         QString badNick = d->params.takeFirst();
   370                         QString msg = tr(
"Erroneous nickname: %1").arg(badNick);
   371                         if (d->params.join(
" ").compare(
":Erroneous nickname", Qt::CaseInsensitive) != 0)
   373                                 msg += tr(
" (%1)").arg(joinAndTrimColonIfNecessary(d->params));
   375                         emit printToNetworksCurrentChatBox(msg, IRCMessageClass::Error);
   382                         d->params.takeFirst();
   384                         QString nickname = d->params.takeFirst();
   386                         emit nicknameInUse(nickname);
   390                 case IRCResponseType::ERRChannelIsFull:
   391                 case IRCResponseType::ERRInviteOnlyChan:
   392                 case IRCResponseType::ERRBannedFromChan:
   393                 case IRCResponseType::ERRBadChannelKey:
   394                 case IRCResponseType::ERRBadChannelMask:
   395                 case IRCResponseType::ERRNoChanModes:
   399                         d->params.takeFirst(); 
   400                         QString channel = d->params.takeFirst();
   401                         QString reason = joinAndTrimColonIfNecessary(d->params);
   404                         case IRCResponseType::ERRChannelIsFull:
   405                         case IRCResponseType::ERRInviteOnlyChan:
   406                         case IRCResponseType::ERRBannedFromChan:
   407                         case IRCResponseType::ERRBadChannelKey:
   408                                 emit printToNetworksCurrentChatBox(tr(
"%1: %2").arg(channel, reason),
   409                                         IRCMessageClass::Error);
   412                                 emit 
printWithClass(reason, channel, IRCMessageClass::ChannelAction);
   419                 case IRCResponseType::Join:
   421                         QString channel = d->params[0];
   422                         trimColonIfNecessary(channel);
   424                         emit userJoinsChannel(channel, d->sender, d->prefix);
   428                 case IRCResponseType::Kick:
   430                         QString channel = d->params.takeFirst();
   431                         QString whoIsKicked = d->params.takeFirst();
   433                         QString reason = joinAndTrimColonIfNecessary(d->params);
   435                         emit kick(channel, d->sender, whoIsKicked, reason);
   439                 case IRCResponseType::Kill:
   441                         QString victim = d->params.takeFirst();
   442                         QString comment = joinAndTrimColonIfNecessary(d->params);
   443                         emit kill(victim, comment);
   447                 case IRCResponseType::Mode:
   449                         QString channel = d->params.takeFirst();
   450                         QString flagsString = d->params.takeFirst();
   454                         if (!d->params.isEmpty())
   456                                 emit 
modeInfo(channel, d->sender, flagsString + 
" " + d->params.join(
" "));
   457                                 parseUserModeMessage(channel, flagsString, d->params);
   463                 case IRCResponseType::Nick:
   465                         QString oldNickname = d->sender;
   466                         QString newNickname = d->params[0];
   467                         trimColonIfNecessary(newNickname);
   469                         emit userChangesNickname(oldNickname, newNickname);
   473                 case IRCResponseType::Part:
   475                         QString farewellMessage = QString();
   476                         QString channel = d->params[0];
   478                         if (d->params.size() > 1)
   480                                 d->params.pop_front();
   482                                 farewellMessage = joinAndTrimColonIfNecessary(d->params);
   485                         emit userPartsChannel(channel, d->sender, farewellMessage);
   489                 case IRCResponseType::Ping:
   491                         QString pongToWhom = d->params[0];
   493                         emit sendPongMessage(pongToWhom);
   497                 case IRCResponseType::PrivMsg:
   498                 case IRCResponseType::Notice:
   499                         parsePrivMsgOrNotice();
   502                 case IRCResponseType::Quit:
   504                         QString farewellMessage = QString();
   505                         farewellMessage = joinAndTrimColonIfNecessary(d->params);
   507                         emit userQuitsNetwork(d->sender, farewellMessage);
   511                 case IRCResponseType::Topic:
   513                         QString channel = d->params.takeFirst();
   514                         QString topic = joinAndTrimColonIfNecessary(d->params);
   515                         QString msg = tr(
"New topic set by user %1:\n%2").arg(d->sender, topic);
   526                                 emit 
print(joinAndTrimColonIfNecessary(d->params), 
"");
   535                                 "IRCResponseParser: Type '%1' was recognized but there has been no parse code implemented for it.\   536 (yep, it's a bug in the application!)"   546 void IRCResponseParser::parsePrivMsgOrNotice()
   548         if (isPrefixIgnored())
   552         QString recipient = d->params.takeFirst();
   553         if (!IRCGlobal::isChannelName(recipient))
   559                 recipient = d->sender;
   563         QString content = joinAndTrimColonIfNecessary(d->params);
   568         IRCCtcpParser ctcp(d->network, d->sender, recipient, content, ctcpMsgType);
   573                         case IRCCtcpParser::PrintAsNormalMessage:
   576                         case IRCCtcpParser::DisplayInServerTab:
   577                                 emit 
printWithClass(ctcp.printable(), QString(), IRCMessageClass::Ctcp);
   579                         case IRCCtcpParser::DisplayThroughGlobalMessage:
   580                                 emit printToNetworksCurrentChatBox(ctcp.printable(), IRCMessageClass::Ctcp);
   582                         case IRCCtcpParser::DontShow:
   585                                 gLog << QString(
"Unhandled CTCP echo type: %1").arg(ctcp.echo());
   586                                 assert(
false && 
"Unhandled CTCP echo type");
   589                 if (!ctcp.reply().isEmpty() && responseType.type() != IRCResponseType::Notice)
   591                         d->network->sendMessage(QString(
"/NOTICE %1 %2%3%2").arg(d->sender, QChar(0x1), ctcp.reply()));
   596                 if (responseType == IRCResponseType::PrivMsg)
   598                         emit privMsgReceived(recipient, d->sender, content);
   600                 else if (responseType == IRCResponseType::Notice)
   602                         emit 
print(tr(
"[%1]: %2").arg(d->sender, content), recipient);
   606                         emit parseError(tr(
"Type '%1' was incorrectly parsed in PrivMsg block.").arg(d->type));
   611 void IRCResponseParser::parseUserModeMessage(
const QString& channel, QString flagsString, QStringList& nicknames)
   618         FlagModes flagMode = getFlagMode(flagsString[0].toLatin1());
   620         if (flagMode == FlagModeError)
   622                 emit parseError(tr(
"MODE flags string from IRC server are incorrect: \"%1\". "   623                         "Information for channel \"%2\" might not be correct anymore.")
   624                         .arg(flagsString, channel));
   628         for (
int i = 1; i < flagsString.size(); ++i)
   630                 char flagChar = flagsString[i].toLatin1();
   632                 FlagModes tmpFlagMode = getFlagMode(flagChar);
   633                 if (tmpFlagMode == FlagModeError)
   635                         if (nicknames.empty())
   640                         QList<char> addedFlags;
   641                         QList<char> removedFlags;
   643                         QString name = nicknames[0];
   648                                         addedFlags << flagChar;
   652                                         removedFlags << flagChar;
   656                                         emit parseError(tr(
"IRCResponseParser::parseUserModeMessage(): "   657                                                 "wrong FlagMode. Information for channel \"%2\" might not be correct anymore."));
   661                         emit userModeChanged(channel, name, addedFlags, removedFlags);
   663                         nicknames.pop_front();
   667                         flagMode = tmpFlagMode;
   673 QString& IRCResponseParser::trimColonIfNecessary(QString& str)
 const   675         if (!str.isEmpty() && str[0] == 
':')
 Interprets communication between the client and the IRC server. 
 
void print(const QString &printWhat, const QString &printWhere)
Tells the network adapter to print a message. 
 
375 - start of the message of the day 
 
void privMsgLiteralReceived(const QString &recipient, const QString &content, const IRCMessageClass &msgClass)
Create chat window if necessary and display message 'as is' without further string gluing...
 
An answer is being sent through NOTICE. 
 
void modeInfo(const QString &channel, const QString &whoSetThis, const QString &modeParams)
Carries info about MODE for display. 
 
IRCResponseParseResult parse(const QString &message)
Parses the message received from the network. 
 
253 - how many unknown connections 
 
void whoIsUser(const QString &nickname, const QString &user, const QString &hostName, const QString &realName)
Emitted with response 311 RPL_WHOISUSER. 
 
251 - how many users on how many servers 
 
320 - it's inconclusive what this code means. 
 
Defines types of IRC network response message. 
 
void helloClient(const QString &nickname)
Emitted when user successfuly joins the network. 
 
A question is being asked through PRIVMSG. 
 
353 - names list for a channel 
 
376 - end of the message of the day 
 
001 - sent when client connects. 
 
005 - all sorts of server flags. 
 
Result info generated by the IRCResponseParser. 
 
MsgType
Represents types defined by RFC 1459. 
 
307 - no idea what this is, but we'll treat it the same way we treat RPLWhoIsSpecial. 
 
255 - how many clients on how many servers, 
 
int numericType() const 
If message type can be represented as number, this will contain its value. 
 
Type unknown to this IRC client. 
 
void printWithClass(const QString &printWhat, const QString &printWhere, const IRCMessageClass &msgClass)
Same as print(), but allows to specify message class.