23 #include "ircresponseparser.h"
25 #include "irc/constants/ircresponsetype.h"
26 #include "irc/ircctcpparser.h"
27 #include "irc/ircglobal.h"
28 #include "irc/ircmessageclass.h"
29 #include "irc/ircnetworkadapter.h"
30 #include "irc/ircuserinfo.h"
32 #include "patternlist.h"
33 #include "strings.hpp"
37 #include <QStringList>
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)
101 d->sender = d->prefix.left(indexExclamation);
103 d->sender = d->prefix;
105 QStringList msgParameters = remainder.split(
" ");
106 if (!msgParameters.isEmpty())
108 d->type = msgParameters.takeFirst();
109 d->params = msgParameters;
111 return parseMessage();
127 QString nickname = d->params.takeFirst();
135 d->params.takeFirst();
136 QString nickname = d->params.takeFirst();
137 QString reason = joinAndTrimColonIfNecessary(d->params);
138 emit printToNetworksCurrentChatBox(tr(
"User %1 is away: %2").arg(nickname, reason),
139 IRCMessageClass::NetworkAction);
146 d->params.takeFirst();
149 QString nickname = d->params.takeFirst();
150 QString user = d->params.takeFirst();
151 QString hostName = d->params.takeFirst();
152 QString realName = joinAndTrimColonIfNecessary(d->params);
154 emit
whoIsUser(nickname, user, hostName, realName);
169 d->params.takeFirst();
170 emit printToNetworksCurrentChatBox(d->params.join(
" "), IRCMessageClass::NetworkAction);
176 d->params.takeFirst();
177 QString nick = d->params.takeFirst();
178 int secondsIdle = d->params.takeFirst().toInt();
179 emit userIdleTime(nick, secondsIdle);
180 if (d->params.first().toInt() != 0)
182 int joinedOn = d->params.takeFirst().toInt();
183 emit userNetworkJoinDateTime(nick, QDateTime::fromTime_t(joinedOn));
190 d->params.takeFirst();
191 QString nick = d->params.takeFirst();
192 QString channels = joinAndTrimColonIfNecessary(d->params);
193 emit printToNetworksCurrentChatBox(tr(
"%1 is on channels: %2").arg(nick, channels),
194 IRCMessageClass::NetworkAction);
200 d->params.takeFirst();
201 QString nick = d->params.takeFirst();
202 QString account = d->params.takeFirst();
203 QString message = joinAndTrimColonIfNecessary(d->params);
204 emit printToNetworksCurrentChatBox(QString(
"%1 %2 %3").arg(nick, message, account),
205 IRCMessageClass::NetworkAction);
211 d->params.takeFirst();
212 emit iSupportReceived(d->params.join(
" "));
218 d->params.takeFirst();
219 QString channel = d->params.takeFirst();
220 QString topic = joinAndTrimColonIfNecessary(d->params);
221 QString msg = tr(
"Topic: %1").arg(topic);
228 d->params.takeFirst();
229 QString channel = d->params.takeFirst();
230 QString who = d->params.takeFirst();
231 qint64 timestampSeconds = d->params.takeFirst().toLongLong();
232 QDateTime date = QDateTime::fromMSecsSinceEpoch(timestampSeconds * 1000);
233 QString msg = tr(
"Topic set by %1 on %2.").arg(who, date.toString(
"yyyy-MM-dd hh:mm:ss"));
240 d->params.takeFirst();
241 QString channel = d->params.takeFirst();
242 QString url = joinAndTrimColonIfNecessary(d->params);
243 emit
printWithClass(tr(
"URL: %1").arg(url), channel, IRCMessageClass::ChannelAction);
249 d->params.takeFirst();
250 QString channel = d->params.takeFirst();
251 QString time = joinAndTrimColonIfNecessary(d->params);
253 IRCMessageClass::ChannelAction);
266 QString channelName =
"";
267 while (!IRCGlobal::isChannelName(channelName) && !d->params.isEmpty())
269 channelName = d->params.takeFirst();
272 if (channelName.isEmpty())
274 emit parseError(tr(
"RPLNamReply: Received names list but no channel name."));
280 if (!d->params.isEmpty())
281 d->params[0] = d->params[0].remove(0, 1);
283 emit namesListReceived(channelName, d->params);
289 QString channel = d->params[1];
290 emit namesListEndReceived(channel);
299 d->params.takeFirst();
305 emit
print(
"\n----------------------", QString());
308 emit
print(joinAndTrimColonIfNecessary(d->params), QString());
314 emit
print(
"----------------------\n", QString());
325 d->params.takeFirst();
328 emit
print(joinAndTrimColonIfNecessary(d->params), QString());
338 d->params.takeFirst();
342 QString number = d->params.takeFirst();
343 emit
print(number +
" " + joinAndTrimColonIfNecessary(d->params), QString());
350 d->params.takeFirst();
353 QString nickname = d->params.takeFirst();
355 emit noSuchNickname(nickname);
362 d->params.takeFirst();
363 QString badNick = d->params.takeFirst();
364 QString msg = tr(
"Erroneous nickname: %1").arg(badNick);
365 if (d->params.join(
" ").compare(
":Erroneous nickname", Qt::CaseInsensitive) != 0)
366 msg += tr(
" (%1)").arg(joinAndTrimColonIfNecessary(d->params));
367 emit printToNetworksCurrentChatBox(msg, IRCMessageClass::Error);
374 d->params.takeFirst();
376 QString nickname = d->params.takeFirst();
378 emit nicknameInUse(nickname);
382 case IRCResponseType::ERRChannelIsFull:
383 case IRCResponseType::ERRInviteOnlyChan:
384 case IRCResponseType::ERRBannedFromChan:
385 case IRCResponseType::ERRBadChannelKey:
386 case IRCResponseType::ERRBadChannelMask:
387 case IRCResponseType::ERRNoChanModes:
391 d->params.takeFirst();
392 QString channel = d->params.takeFirst();
393 QString reason = joinAndTrimColonIfNecessary(d->params);
396 case IRCResponseType::ERRChannelIsFull:
397 case IRCResponseType::ERRInviteOnlyChan:
398 case IRCResponseType::ERRBannedFromChan:
399 case IRCResponseType::ERRBadChannelKey:
400 emit printToNetworksCurrentChatBox(tr(
"%1: %2").arg(channel, reason),
401 IRCMessageClass::Error);
404 emit
printWithClass(reason, channel, IRCMessageClass::ChannelAction);
411 case IRCResponseType::Join:
413 QString channel = d->params[0];
414 trimColonIfNecessary(channel);
416 emit userJoinsChannel(channel, d->sender, d->prefix);
420 case IRCResponseType::Kick:
422 QString channel = d->params.takeFirst();
423 QString whoIsKicked = d->params.takeFirst();
425 QString reason = joinAndTrimColonIfNecessary(d->params);
427 emit kick(channel, d->sender, whoIsKicked, reason);
431 case IRCResponseType::Kill:
433 QString victim = d->params.takeFirst();
434 QString comment = joinAndTrimColonIfNecessary(d->params);
435 emit kill(victim, comment);
439 case IRCResponseType::Mode:
441 QString channel = d->params.takeFirst();
442 QString flagsString = d->params.takeFirst();
446 if (!d->params.isEmpty())
448 emit
modeInfo(channel, d->sender, flagsString +
" " + d->params.join(
" "));
449 parseUserModeMessage(channel, flagsString, d->params);
455 case IRCResponseType::Nick:
457 QString oldNickname = d->sender;
458 QString newNickname = d->params[0];
459 trimColonIfNecessary(newNickname);
461 emit userChangesNickname(oldNickname, newNickname);
465 case IRCResponseType::Part:
467 QString farewellMessage = QString();
468 QString channel = d->params[0];
470 if (d->params.size() > 1)
472 d->params.pop_front();
474 farewellMessage = joinAndTrimColonIfNecessary(d->params);
477 emit userPartsChannel(channel, d->sender, farewellMessage);
481 case IRCResponseType::Ping:
483 QString pongToWhom = d->params[0];
485 emit sendPongMessage(pongToWhom);
489 case IRCResponseType::PrivMsg:
490 case IRCResponseType::Notice:
491 parsePrivMsgOrNotice();
494 case IRCResponseType::Quit:
496 QString farewellMessage = QString();
497 farewellMessage = joinAndTrimColonIfNecessary(d->params);
499 emit userQuitsNetwork(d->sender, farewellMessage);
503 case IRCResponseType::Topic:
505 QString channel = d->params.takeFirst();
506 QString topic = joinAndTrimColonIfNecessary(d->params);
507 QString msg = tr(
"New topic set by user %1:\n%2").arg(d->sender, topic);
516 if (responseType.numericType() > 1)
518 emit
print(joinAndTrimColonIfNecessary(d->params),
"");
527 "IRCResponseParser: Type '%1' was recognized but there has been no parse code implemented for it.\
528 (yep, it's a bug in the application!)"
536 void IRCResponseParser::parsePrivMsgOrNotice()
538 if (isPrefixIgnored())
540 QString recipient = d->params.takeFirst();
541 if (!IRCGlobal::isChannelName(recipient))
547 recipient = d->sender;
551 QString content = joinAndTrimColonIfNecessary(d->params);
556 IRCCtcpParser ctcp(d->network, d->sender, recipient, content, ctcpMsgType);
561 case IRCCtcpParser::PrintAsNormalMessage:
564 case IRCCtcpParser::DisplayInServerTab:
565 emit
printWithClass(ctcp.printable(), QString(), IRCMessageClass::Ctcp);
567 case IRCCtcpParser::DisplayThroughGlobalMessage:
568 emit printToNetworksCurrentChatBox(ctcp.printable(), IRCMessageClass::Ctcp);
570 case IRCCtcpParser::DontShow:
573 gLog << QString(
"Unhandled CTCP echo type: %1").arg(ctcp.echo());
574 assert(
false &&
"Unhandled CTCP echo type");
577 if (!ctcp.reply().isEmpty() && responseType.type() != IRCResponseType::Notice)
578 d->network->sendMessage(QString(
"/NOTICE %1 %2%3%2").arg(d->sender, QChar(0x1), ctcp.reply()));
582 if (responseType == IRCResponseType::PrivMsg)
583 emit privMsgReceived(recipient, d->sender, content);
584 else if (responseType == IRCResponseType::Notice)
585 emit
print(tr(
"[%1]: %2").arg(d->sender, content), recipient);
587 emit parseError(tr(
"Type '%1' was incorrectly parsed in PrivMsg block.").arg(d->type));
591 void IRCResponseParser::parseUserModeMessage(
const QString &channel, QString flagsString, QStringList &nicknames)
598 FlagModes flagMode = getFlagMode(flagsString[0].toLatin1());
600 if (flagMode == FlagModeError)
602 emit parseError(tr(
"MODE flags string from IRC server are incorrect: \"%1\". "
603 "Information for channel \"%2\" might not be correct anymore.")
604 .arg(flagsString, channel));
608 for (
int i = 1; i < flagsString.size(); ++i)
610 char flagChar = flagsString[i].toLatin1();
612 FlagModes tmpFlagMode = getFlagMode(flagChar);
613 if (tmpFlagMode == FlagModeError)
615 if (nicknames.empty())
618 QList<char> addedFlags;
619 QList<char> removedFlags;
621 QString name = nicknames[0];
626 addedFlags << flagChar;
630 removedFlags << flagChar;
634 emit parseError(tr(
"IRCResponseParser::parseUserModeMessage(): "
635 "wrong FlagMode. Information for channel \"%2\" might not be correct anymore."));
639 emit userModeChanged(channel, name, addedFlags, removedFlags);
641 nicknames.pop_front();
645 flagMode = tmpFlagMode;
651 QString &IRCResponseParser::trimColonIfNecessary(QString &str)
const
653 if (!str.isEmpty() && str[0] ==
':')