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);
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] ==
':')
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 successfully 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.