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" 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.