1/***************************************************************************
2 * Copyright (C) 2005-2014 by the Quassel Project *
3 * devel@quassel-irc.org *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) version 3. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
19 ***************************************************************************/
20
21#include "eventstringifier.h"
22
23#include "coresession.h"
24#include "ctcpevent.h"
25#include "messageevent.h"
26
27EventStringifier::EventStringifier(CoreSession *parent) : BasicHandler("handleCtcp", parent),
28 _coreSession(parent),
29 _whois(false)
30{
31 connect(this, SIGNAL(newMessageEvent(Event *)), coreSession()->eventManager(), SLOT(postEvent(Event *)));
32}
33
34
35void EventStringifier::displayMsg(NetworkEvent *event, Message::Type msgType, const QString &msg, const QString &sender,
36 const QString &target, Message::Flags msgFlags)
37{
38 if (event->flags().testFlag(EventManager::Silent))
39 return;
40
41 MessageEvent *msgEvent = createMessageEvent(event, msgType, msg, sender, target, msgFlags);
42 //sendMessageEvent(msgEvent);
43 emit newMessageEvent(msgEvent);
44}
45
46
47MessageEvent *EventStringifier::createMessageEvent(NetworkEvent *event, Message::Type msgType, const QString &msg, const QString &sender,
48 const QString &target, Message::Flags msgFlags)
49{
50 MessageEvent *msgEvent = new MessageEvent(msgType, event->network(), msg, sender, target, msgFlags);
51 msgEvent->setTimestamp(event->timestamp());
52 return msgEvent;
53}
54
55
56bool EventStringifier::checkParamCount(IrcEvent *e, int minParams)
57{
58 if (e->params().count() < minParams) {
59 if (e->type() == EventManager::IrcEventNumeric) {
60 qWarning() << "Command " << static_cast<IrcEventNumeric *>(e)->number() << " requires " << minParams << "params, got: " << e->params();
61 }
62 else {
63 QString name = coreSession()->eventManager()->enumName(e->type());
64 qWarning() << qPrintable(name) << "requires" << minParams << "params, got:" << e->params();
65 }
66 e->stop();
67 return false;
68 }
69 return true;
70}
71
72
73/* These are only for legacy reasons; remove as soon as we handle NetworkSplitEvents properly */
74void EventStringifier::processNetworkSplitJoin(NetworkSplitEvent *e)
75{
76 QString msg = e->users().join("#:#") + "#:#" + e->quitMessage();
77 displayMsg(e, Message::NetsplitJoin, msg, QString(), e->channel());
78}
79
80
81void EventStringifier::processNetworkSplitQuit(NetworkSplitEvent *e)
82{
83 QString msg = e->users().join("#:#") + "#:#" + e->quitMessage();
84 displayMsg(e, Message::NetsplitQuit, msg, QString(), e->channel());
85}
86
87
88/* End legacy */
89
90void EventStringifier::processIrcEventNumeric(IrcEventNumeric *e)
91{
92 //qDebug() << e->number();
93 switch (e->number()) {
94 // Welcome, status, info messages. Just display these.
95 case 1:
96 case 2:
97 case 3:
98 case 4:
99 case 5:
100 case 221:
101 case 250:
102 case 251:
103 case 252:
104 case 253:
105 case 254:
106 case 255:
107 case 256:
108 case 257:
109 case 258:
110 case 259:
111 case 265:
112 case 266:
113 case 372:
114 case 375:
115 displayMsg(e, Message::Server, e->params().join(" "), e->prefix());
116 break;
117
118 // Server error messages without param, just display them
119 case 263:
120 case 409:
121 case 411:
122 case 412:
123 case 422:
124 case 424:
125 case 445:
126 case 446:
127 case 451:
128 case 462:
129 case 463:
130 case 464:
131 case 465:
132 case 466:
133 case 472:
134 case 481:
135 case 483:
136 case 485:
137 case 491:
138 case 501:
139 case 502:
140 case 431: // ERR_NONICKNAMEGIVEN
141 displayMsg(e, Message::Error, e->params().join(" "), e->prefix());
142 break;
143
144 // Server error messages, display them in red. Colon between first param and rest.
145 case 401:
146 {
147 if (!checkParamCount(e, 1))
148 return;
149
150 QStringList params = e->params();
151 QString target = params.takeFirst();
152 displayMsg(e, Message::Error, target + ": " + params.join(" "), e->prefix(), target, Message::Redirected);
153 break;
154 }
155
156 case 402:
157 case 403:
158 case 404:
159 case 406:
160 case 408:
161 case 415:
162 case 421:
163 case 442:
164 {
165 if (!checkParamCount(e, 1))
166 return;
167
168 QStringList params = e->params();
169 QString channelName = params.takeFirst();
170 displayMsg(e, Message::Error, channelName + ": " + params.join(" "), e->prefix());
171 break;
172 }
173
174 // Server error messages which will be displayed with a colon between the first param and the rest
175 case 413:
176 case 414:
177 case 423:
178 case 441:
179 case 444:
180 case 461: // FIXME see below for the 47x codes
181 case 467:
182 case 471:
183 case 473:
184 case 474:
185 case 475:
186 case 476:
187 case 477:
188 case 478:
189 case 482:
190 case 436: // ERR_NICKCOLLISION
191 {
192 if (!checkParamCount(e, 1))
193 return;
194
195 QStringList params = e->params();
196 QString p = params.takeFirst();
197 displayMsg(e, Message::Error, p + ": " + params.join(" "));
198 break;
199 }
200
201 // Ignore these commands.
202 case 321:
203 case 353:
204 case 366:
205 case 376:
206 break;
207
208 // CAP stuff
209 case 900:
210 case 903:
211 case 904:
212 case 905:
213 case 906:
214 case 907:
215 {
216 displayMsg(e, Message::Info, "CAP: " + e->params().join(""));
217 break;
218 }
219
220 // Everything else will be marked in red, so we can add them somewhere.
221 default:
222 if (_whois) {
223 // many nets define their own WHOIS fields. we fetch those not in need of special attention here:
224 displayMsg(e, Message::Server, tr("[Whois] ") + e->params().join(" "), e->prefix());
225 }
226 else {
227 // FIXME figure out how/where to do this in the future
228 //if(coreSession()->ircListHelper()->requestInProgress(network()->networkId()))
229 // coreSession()->ircListHelper()->reportError(params.join(" "));
230 //else
231 displayMsg(e, Message::Error, QString("%1 %2").arg(e->number(), 3, 10, QLatin1Char('0')).arg(e->params().join(" ")), e->prefix());
232 }
233 }
234}
235
236
237void EventStringifier::processIrcEventInvite(IrcEvent *e)
238{
239 displayMsg(e, Message::Invite, tr("%1 invited you to channel %2").arg(e->nick(), e->params().at(1)));
240}
241
242
243void EventStringifier::processIrcEventJoin(IrcEvent *e)
244{
245 if (e->testFlag(EventManager::Netsplit))
246 return;
247
248 displayMsg(e, Message::Join, e->params()[0], e->prefix(), e->params()[0]);
249}
250
251
252void EventStringifier::processIrcEventKick(IrcEvent *e)
253{
254 if (!checkParamCount(e, 2))
255 return;
256
257 IrcUser *victim = e->network()->ircUser(e->params().at(1));
258 if (victim) {
259 QString channel = e->params().at(0);
260 QString msg = victim->nick();
261 if (e->params().count() > 2)
262 msg += " " + e->params().at(2);
263
264 displayMsg(e, Message::Kick, msg, e->prefix(), channel);
265 }
266}
267
268
269void EventStringifier::processIrcEventMode(IrcEvent *e)
270{
271 if (e->network()->isChannelName(e->params().first())) {
272 // Channel Modes
273 displayMsg(e, Message::Mode, e->params().join(" "), e->prefix(), e->params().first());
274 }
275 else {
276 // User Modes
277 // FIXME: redirect
278 displayMsg(e, Message::Mode, e->params().join(" "), e->prefix());
279 }
280}
281
282
283// this needs to be called before the ircuser is renamed!
284void EventStringifier::processIrcEventNick(IrcEvent *e)
285{
286 if (!checkParamCount(e, 1))
287 return;
288
289 IrcUser *ircuser = e->network()->updateNickFromMask(e->prefix());
290 if (!ircuser) {
291 qWarning() << Q_FUNC_INFO << "Unknown IrcUser!";
292 return;
293 }
294
295 QString newnick = e->params().at(0);
296 QString oldnick = ircuser->nick();
297
298 QString sender = e->network()->isMyNick(oldnick) ? newnick : e->prefix();
299 foreach(const QString &channel, ircuser->channels())
300 displayMsg(e, Message::Nick, newnick, sender, channel);
301}
302
303
304void EventStringifier::processIrcEventPart(IrcEvent *e)
305{
306 if (!checkParamCount(e, 1))
307 return;
308
309 QString channel = e->params().at(0);
310 QString msg = e->params().count() > 1 ? e->params().at(1) : QString();
311
312 displayMsg(e, Message::Part, msg, e->prefix(), channel);
313}
314
315
316void EventStringifier::processIrcEventPong(IrcEvent *e)
317{
318 QString timestamp = e->params().at(1);
319 QTime sendTime = QTime::fromString(timestamp, "hh:mm:ss.zzz");
320 if (!sendTime.isValid())
321 displayMsg(e, Message::Server, "PONG " + e->params().join(" "), e->prefix());
322}
323
324
325void EventStringifier::processIrcEventQuit(IrcEvent *e)
326{
327 if (e->testFlag(EventManager::Netsplit))
328 return;
329
330 IrcUser *ircuser = e->network()->updateNickFromMask(e->prefix());
331 if (!ircuser)
332 return;
333
334 foreach(const QString &channel, ircuser->channels())
335 displayMsg(e, Message::Quit, e->params().count() ? e->params().first() : QString(), e->prefix(), channel);
336}
337
338
339void EventStringifier::processIrcEventTopic(IrcEvent *e)
340{
341 displayMsg(e, Message::Topic, tr("%1 has changed topic for %2 to: \"%3\"")
342 .arg(e->nick(), e->params().at(0), e->params().at(1)), QString(), e->params().at(0));
343}
344
345void EventStringifier::processIrcEventWallops(IrcEvent *e)
346{
347 displayMsg(e, Message::Server, tr("[Operwall] %1: %2").arg(e->nick(), e->params().join(" ")));
348}
349
350
351/* RPL_ISUPPORT */
352void EventStringifier::processIrcEvent005(IrcEvent *e)
353{
354 if (!e->params().last().contains(QRegExp("are supported (by|on) this server")))
355 displayMsg(e, Message::Error, tr("Received non-RFC-compliant RPL_ISUPPORT: this can lead to unexpected behavior!"), e->prefix());
356 displayMsg(e, Message::Server, e->params().join(" "), e->prefix());
357}
358
359
360/* RPL_AWAY - "<nick> :<away message>" */
361void EventStringifier::processIrcEvent301(IrcEvent *e)
362{
363 QString nick = e->params().at(0);
364 QString awayMsg = e->params().at(1);
365 QString msg, target;
366 bool send = true;
367
368 // FIXME: proper redirection needed
369 if (_whois) {
370 msg = tr("[Whois] ");
371 }
372 else {
373 target = nick;
374 IrcUser *ircuser = e->network()->ircUser(nick);
375 if (ircuser) {
376 int now = QDateTime::currentDateTime().toTime_t();
377 const int silenceTime = 60;
378 if (ircuser->lastAwayMessage() + silenceTime >= now)
379 send = false;
380 ircuser->setLastAwayMessage(now);
381 }
382 }
383 if (send)
384 displayMsg(e, Message::Server, msg + tr("%1 is away: \"%2\"").arg(nick, awayMsg), QString(), target);
385}
386
387
388/* RPL_UNAWAY - ":You are no longer marked as being away" */
389void EventStringifier::processIrcEvent305(IrcEvent *e)
390{
391 displayMsg(e, Message::Server, tr("You are no longer marked as being away"));
392}
393
394
395/* RPL_NOWAWAY - ":You have been marked as being away" */
396void EventStringifier::processIrcEvent306(IrcEvent *e)
397{
398 if (!e->network()->autoAwayActive())
399 displayMsg(e, Message::Server, tr("You have been marked as being away"));
400}
401
402
403/*
404WHOIS-Message:
405 Replies 311 - 313, 317 - 319 are all replies generated in response to a WHOIS message.
406 and 301 (RPL_AWAY)
407 "<nick> :<away message>"
408WHO-Message:
409 Replies 352 and 315 paired are used to answer a WHO message.
410
411WHOWAS-Message:
412 Replies 314 and 369 are responses to a WHOWAS message.
413
414*/
415
416/* RPL_WHOISUSER - "<nick> <user> <host> * :<real name>" */
417void EventStringifier::processIrcEvent311(IrcEvent *e)
418{
419 _whois = true;
420
421 const QString whoisUserString = tr("[Whois] %1 is %2 (%3)");
422
423 IrcUser *ircuser = e->network()->ircUser(e->params().at(0));
424 if (ircuser)
425 displayMsg(e, Message::Server, whoisUserString.arg(ircuser->nick(), ircuser->hostmask(), ircuser->realName()));
426 else {
427 QString host = QString("%1!%2@%3").arg(e->params().at(0), e->params().at(1), e->params().at(2));
428 displayMsg(e, Message::Server, whoisUserString.arg(e->params().at(0), host, e->params().last()));
429 }
430}
431
432
433/* RPL_WHOISSERVER - "<nick> <server> :<server info>" */
434void EventStringifier::processIrcEvent312(IrcEvent *e)
435{
436 if (_whois)
437 displayMsg(e, Message::Server, tr("[Whois] %1 is online via %2 (%3)").arg(e->params().at(0), e->params().at(1), e->params().last()));
438 else
439 displayMsg(e, Message::Server, tr("[Whowas] %1 was online via %2 (%3)").arg(e->params().at(0), e->params().at(1), e->params().last()));
440}
441
442
443/* RPL_WHOWASUSER - "<nick> <user> <host> * :<real name>" */
444void EventStringifier::processIrcEvent314(IrcEvent *e)
445{
446 if (!checkParamCount(e, 3))
447 return;
448
449 displayMsg(e, Message::Server, tr("[Whowas] %1 was %2@%3 (%4)").arg(e->params()[0], e->params()[1], e->params()[2], e->params().last()));
450}
451
452
453/* RPL_ENDOFWHO: "<name> :End of WHO list" */
454void EventStringifier::processIrcEvent315(IrcEvent *e)
455{
456 QStringList p = e->params();
457 p.takeLast(); // should be "End of WHO list"
458 displayMsg(e, Message::Server, tr("[Who] End of /WHO list for %1").arg(p.join(" ")));
459}
460
461
462/* RPL_WHOISIDLE - "<nick> <integer> :seconds idle"
463 (real life: "<nick> <integer> <integer> :seconds idle, signon time) */
464void EventStringifier::processIrcEvent317(IrcEvent *e)
465{
466 int idleSecs = e->params()[1].toInt();
467
468 if (e->params().count() > 3) { // if we have more then 3 params we have the above mentioned "real life" situation
469 QDateTime loginTime = QDateTime::fromTime_t(e->params()[2].toInt()).toUTC();
470 displayMsg(e, Message::Server, tr("[Whois] %1 is logged in since %2")
471 .arg(e->params()[0], loginTime.toString("yyyy-MM-dd hh:mm:ss UTC")));
472 }
473 QDateTime idlingSince = e->timestamp().toLocalTime().addSecs(-idleSecs).toUTC();
474 displayMsg(e, Message::Server, tr("[Whois] %1 is idling for %2 (since %3)")
475 .arg(e->params()[0], secondsToString(idleSecs),
476 idlingSince.toString("yyyy-MM-dd hh:mm:ss UTC")));
477}
478
479
480/* RPL_ENDOFWHOIS - "<nick> :End of WHOIS list" */
481void EventStringifier::processIrcEvent318(IrcEvent *e)
482{
483 _whois = false;
484 displayMsg(e, Message::Server, tr("[Whois] End of /WHOIS list"));
485}
486
487
488/* RPL_WHOISCHANNELS - "<nick> :*( ( "@" / "+" ) <channel> " " )" */
489void EventStringifier::processIrcEvent319(IrcEvent *e)
490{
491 if (!checkParamCount(e, 2))
492 return;
493
494 QString nick = e->params().first();
495 QStringList op;
496 QStringList voice;
497 QStringList user;
498 foreach(QString channel, e->params().last().split(" ")) {
499 if (channel.startsWith("@"))
500 op.append(channel.remove(0, 1));
501 else if (channel.startsWith("+"))
502 voice.append(channel.remove(0, 1));
503 else
504 user.append(channel);
505 }
506 if (!user.isEmpty())
507 displayMsg(e, Message::Server, tr("[Whois] %1 is a user on channels: %2").arg(nick, user.join(" ")));
508 if (!voice.isEmpty())
509 displayMsg(e, Message::Server, tr("[Whois] %1 has voice on channels: %2").arg(nick, voice.join(" ")));
510 if (!op.isEmpty())
511 displayMsg(e, Message::Server, tr("[Whois] %1 is an operator on channels: %2").arg(nick, op.join(" ")));
512}
513
514
515/* RPL_LIST - "<channel> <# visible> :<topic>" */
516void EventStringifier::processIrcEvent322(IrcEvent *e)
517{
518 QString channelName;
519 quint32 userCount = 0;
520 QString topic;
521
522 switch (e->params().count()) {
523 case 3:
524 topic = e->params()[2];
525 case 2:
526 userCount = e->params()[1].toUInt();
527 case 1:
528 channelName = e->params()[0];
529 default:
530 break;
531 }
532 displayMsg(e, Message::Server, tr("Channel %1 has %2 users. Topic is: \"%3\"")
533 .arg(channelName).arg(userCount).arg(topic));
534}
535
536
537/* RPL_LISTEND ":End of LIST" */
538void EventStringifier::processIrcEvent323(IrcEvent *e)
539{
540 displayMsg(e, Message::Server, tr("End of channel list"));
541}
542
543
544/* RPL_CHANNELMODEIS - "<channel> <mode> <mode params>" */
545void EventStringifier::processIrcEvent324(IrcEvent *e)
546{
547 processIrcEventMode(e);
548}
549
550
551/* RPL_??? - "<channel> <homepage> */
552void EventStringifier::processIrcEvent328(IrcEvent *e)
553{
554 if (!checkParamCount(e, 2))
555 return;
556
557 QString channel = e->params()[0];
558 displayMsg(e, Message::Topic, tr("Homepage for %1 is %2").arg(channel, e->params()[1]), QString(), channel);
559}
560
561
562/* RPL_??? - "<channel> <creation time (unix)>" */
563void EventStringifier::processIrcEvent329(IrcEvent *e)
564{
565 if (!checkParamCount(e, 2))
566 return;
567
568 QString channel = e->params()[0];
569 uint unixtime = e->params()[1].toUInt();
570 if (!unixtime) {
571 qWarning() << Q_FUNC_INFO << "received invalid timestamp:" << e->params()[1];
572 return;
573 }
574 QDateTime time = QDateTime::fromTime_t(unixtime).toUTC();
575 displayMsg(e, Message::Topic, tr("Channel %1 created on %2")
576 .arg(channel, time.toString("yyyy-MM-dd hh:mm:ss UTC")),
577 QString(), channel);
578}
579
580
581/* RPL_WHOISACCOUNT: "<nick> <account> :is authed as */
582void EventStringifier::processIrcEvent330(IrcEvent *e)
583{
584 if (e->params().count() < 3)
585 return;
586
587 // check for whois or whowas
588 if (_whois) {
589 displayMsg(e, Message::Server, tr("[Whois] %1 is authed as %2").arg(e->params()[0], e->params()[1]));
590 }
591 else {
592 displayMsg(e, Message::Server, tr("[Whowas] %1 was authed as %2").arg(e->params()[0], e->params()[1]));
593 }
594}
595
596
597/* RPL_NOTOPIC */
598void EventStringifier::processIrcEvent331(IrcEvent *e)
599{
600 QString channel = e->params().first();
601 displayMsg(e, Message::Topic, tr("No topic is set for %1.").arg(channel), QString(), channel);
602}
603
604
605/* RPL_TOPIC */
606void EventStringifier::processIrcEvent332(IrcEvent *e)
607{
608 QString channel = e->params().first();
609 displayMsg(e, Message::Topic, tr("Topic for %1 is \"%2\"").arg(channel, e->params()[1]), QString(), channel);
610}
611
612
613/* Topic set by... */
614void EventStringifier::processIrcEvent333(IrcEvent *e)
615{
616 if (!checkParamCount(e, 3))
617 return;
618
619 QString channel = e->params().first();
620 QDateTime topicSetTime = QDateTime::fromTime_t(e->params()[2].toInt()).toUTC();
621 displayMsg(e, Message::Topic, tr("Topic set by %1 on %2")
622 .arg(e->params()[1],
623 topicSetTime.toString("yyyy-MM-dd hh:mm:ss UTC")), QString(), channel);
624}
625
626
627/* RPL_INVITING - "<nick> <channel>*/
628void EventStringifier::processIrcEvent341(IrcEvent *e)
629{
630 if (!checkParamCount(e, 2))
631 return;
632
633 QString channel = e->params()[1];
634 displayMsg(e, Message::Server, tr("%1 has been invited to %2").arg(e->params().first(), channel), QString(), channel);
635}
636
637
638/* RPL_WHOREPLY: "<channel> <user> <host> <server> <nick>
639 ( "H" / "G" > ["*"] [ ( "@" / "+" ) ] :<hopcount> <real name>" */
640void EventStringifier::processIrcEvent352(IrcEvent *e)
641{
642 displayMsg(e, Message::Server, tr("[Who] %1").arg(e->params().join(" ")));
643}
644
645
646/* RPL_ENDOFWHOWAS - "<nick> :End of WHOWAS" */
647void EventStringifier::processIrcEvent369(IrcEvent *e)
648{
649 displayMsg(e, Message::Server, tr("End of /WHOWAS"));
650}
651
652
653/* ERR_ERRONEUSNICKNAME */
654void EventStringifier::processIrcEvent432(IrcEvent *e)
655{
656 if (!checkParamCount(e, 1))
657 return;
658
659 displayMsg(e, Message::Error, tr("Nick %1 contains illegal characters").arg(e->params()[0]));
660}
661
662
663/* ERR_NICKNAMEINUSE */
664void EventStringifier::processIrcEvent433(IrcEvent *e)
665{
666 if (!checkParamCount(e, 1))
667 return;
668
669 displayMsg(e, Message::Error, tr("Nick already in use: %1").arg(e->params()[0]));
670}
671
672
673/* ERR_UNAVAILRESOURCE */
674void EventStringifier::processIrcEvent437(IrcEvent *e)
675{
676 if (!checkParamCount(e, 1))
677 return;
678
679 displayMsg(e, Message::Error, tr("Nick/channel is temporarily unavailable: %1").arg(e->params()[0]));
680}
681
682
683// template
684/*
685
686void EventStringifier::processIrcEvent(IrcEvent *e) {
687
688}
689
690*/
691
692/*******************************/
693/******** CTCP HANDLING ********/
694/*******************************/
695
696void EventStringifier::processCtcpEvent(CtcpEvent *e)
697{
698 if (e->type() != EventManager::CtcpEvent)
699 return;
700
701 if (e->testFlag(EventManager::Self)) {
702 displayMsg(e, Message::Action, tr("sending CTCP-%1 request to %2").arg(e->ctcpCmd(), e->target()), e->network()->myNick());
703 return;
704 }
705
706 handle(e->ctcpCmd(), Q_ARG(CtcpEvent *, e));
707}
708
709
710void EventStringifier::defaultHandler(const QString &ctcpCmd, CtcpEvent *e)
711{
712 Q_UNUSED(ctcpCmd);
713 if (e->ctcpType() == CtcpEvent::Query) {
714 QString unknown;
715 if (e->reply().isNull()) // all known core-side handlers (except for ACTION) set a reply!
716 //: Optional "unknown" in "Received unknown CTCP-FOO request by bar"
717 unknown = tr("unknown") + ' ';
718 displayMsg(e, Message::Server, tr("Received %1CTCP-%2 request by %3").arg(unknown, e->ctcpCmd(), e->prefix()));
719 return;
720 }
721 displayMsg(e, Message::Server, tr("Received CTCP-%1 answer from %2: %3").arg(e->ctcpCmd(), nickFromMask(e->prefix()), e->param()));
722}
723
724
725void EventStringifier::handleCtcpAction(CtcpEvent *e)
726{
727 displayMsg(e, Message::Action, e->param(), e->prefix(), e->target());
728}
729
730
731void EventStringifier::handleCtcpPing(CtcpEvent *e)
732{
733 if (e->ctcpType() == CtcpEvent::Query)
734 defaultHandler(e->ctcpCmd(), e);
735 else {
736#if QT_VERSION >= 0x040700
737 displayMsg(e, Message::Server, tr("Received CTCP-PING answer from %1 with %2 milliseconds round trip time")
738 .arg(nickFromMask(e->prefix())).arg(QDateTime::fromMSecsSinceEpoch(e->param().toULongLong()).msecsTo(e->timestamp())));
739#else
740 displayMsg(e, Message::Server, tr("Received CTCP-PING answer from %1 with %2 seconds round trip time")
741 .arg(nickFromMask(e->prefix())).arg(QDateTime::fromTime_t(e->param().toInt()).secsTo(e->timestamp())));
742#endif
743 }
744}
745