1 /*
2   Copyright (C) 2008-2020 The Communi Project
3 
4   You may use this file under the terms of BSD license as follows:
5 
6   Redistribution and use in source and binary forms, with or without
7   modification, are permitted provided that the following conditions are met:
8     * Redistributions of source code must retain the above copyright
9       notice, this list of conditions and the following disclaimer.
10     * Redistributions in binary form must reproduce the above copyright
11       notice, this list of conditions and the following disclaimer in the
12       documentation and/or other materials provided with the distribution.
13     * Neither the name of the copyright holder nor the names of its
14       contributors may be used to endorse or promote products derived
15       from this software without specific prior written permission.
16 
17   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18   ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19   WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20   DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR
21   ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22   (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23   LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24   ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28 
29 #include "ircmessage.h"
30 #include "ircmessage_p.h"
31 #include "ircconnection.h"
32 #include "ircconnection_p.h"
33 #include "ircmessagecomposer_p.h"
34 #include "ircnetwork_p.h"
35 #include "irccommand.h"
36 #include "irccore_p.h"
37 #include "irc.h"
38 #include <QMetaEnum>
39 #include <QVariant>
40 #include <QDebug>
41 
42 IRC_BEGIN_NAMESPACE
43 
44 /*!
45     \file ircmessage.h
46     \brief \#include &lt;IrcMessage&gt;
47  */
48 
49 /*!
50     \class IrcMessage ircmessage.h <IrcMessage>
51     \ingroup core
52     \ingroup message
53     \brief The base class of all messages.
54 
55     IRC messages are received from an IRC server. IrcConnection translates received
56     messages into IrcMessage instances and emits the IrcConnection::messageReceived()
57     signal upon message received.
58 
59     Subclasses of IrcMessage contain specialized accessors for parameters that
60     are specific to the particular type of message. See IrcMessage::Type for
61     the list of supported message types.
62 
63     \sa IrcConnection::messageReceived(), IrcMessage::Type
64  */
65 
66 /*!
67     \enum IrcMessage::Type
68     This enum describes the supported message types.
69  */
70 
71 /*!
72     \since 3.3
73     \var IrcMessage::Account
74     \brief An account notify message (IrcAccountMessage).
75     \sa \ref ircv3
76  */
77 
78 /*!
79     \since 3.3
80     \var IrcMessage::Away
81     \brief An away message (IrcAwayMessage).
82  */
83 
84 /*!
85     \since 3.5
86     \var IrcMessage::Batch
87     \brief A batch message (IrcBatchMessage).
88     \sa \ref ircv3
89  */
90 
91 /*!
92     \var IrcMessage::Capability
93     \brief A capability message (IrcCapabilityMessage).
94     \sa \ref ircv3
95  */
96 
97 /*!
98     \var IrcMessage::Error
99     \brief An error message (IrcErrorMessage).
100  */
101 
102 /*!
103     \since 3.4
104     \var IrcMessage::HostChange
105     \brief A host change message (IrcHostChangeMessage).
106  */
107 
108 /*!
109     \var IrcMessage::Invite
110     \brief An invite message (IrcInviteMessage).
111  */
112 
113 /*!
114     \var IrcMessage::Join
115     \brief A join message (IrcJoinMessage).
116  */
117 
118 /*!
119     \var IrcMessage::Kick
120     \brief A kick message (IrcKickMessage).
121  */
122 
123 /*!
124     \var IrcMessage::Mode
125     \brief A mode message (IrcModeMessage).
126  */
127 
128 /*!
129     \var IrcMessage::Motd
130     \brief A message of the day (IrcMotdMessage).
131  */
132 
133 /*!
134     \var IrcMessage::Names
135     \brief A names message (IrcNamesMessage).
136  */
137 
138 /*!
139     \var IrcMessage::Nick
140     \brief A nick message (IrcNickMessage).
141  */
142 
143 /*!
144     \var IrcMessage::Notice
145     \brief A notice message (IrcNoticeMessage).
146  */
147 
148 /*!
149     \var IrcMessage::Numeric
150     \brief A numeric message (IrcNumericMessage).
151  */
152 
153 /*!
154     \var IrcMessage::Part
155     \brief A part message (IrcPartMessage).
156  */
157 
158 /*!
159     \var IrcMessage::Ping
160     \brief A ping message (IrcPingMessage).
161  */
162 
163 /*!
164     \var IrcMessage::Pong
165     \brief A pong message (IrcPongMessage).
166  */
167 
168 /*!
169     \var IrcMessage::Private
170     \brief A private message (IrcPrivateMessage).
171  */
172 
173 /*!
174     \var IrcMessage::Quit
175     \brief A quit message (IrcQuitMessage).
176  */
177 
178 /*!
179     \var IrcMessage::Topic
180     \brief A topic message (IrcTopicMessage).
181  */
182 
183 /*!
184     \var IrcMessage::Unknown
185     \brief An unknown message (IrcMessage).
186  */
187 
188 /*!
189     \since 3.3
190     \var IrcMessage::Whois
191     \brief A whois reply message (IrcWhoisMessage).
192  */
193 
194 /*!
195     \since 3.3
196     \var IrcMessage::Whowas
197     \brief A whowas reply message (IrcWhowasMessage).
198  */
199 
200 /*!
201     \since 3.1
202     \var IrcMessage::WhoReply
203     \brief A who reply message (IrcWhoReplyMessage).
204  */
205 
206 /*!
207     \enum IrcMessage::Flag
208     This enum describes the supported message flags.
209  */
210 
211 /*!
212     \var IrcMessage::None
213     \brief The message has no flags.
214  */
215 
216 /*!
217     \var IrcMessage::Own
218     \brief The message is user's own message.
219  */
220 
221 /*!
222     \var IrcMessage::Identified
223     \brief The message is identified.
224     \deprecated Use IrcMessage::account instead.
225  */
226 
227 /*!
228     \var IrcMessage::Unidentified
229     \brief The message is unidentified.
230     \deprecated Use IrcMessage::account instead.
231  */
232 
233 /*!
234     \since 3.2
235     \var IrcMessage::Playback
236     \brief The message is playback.
237  */
238 
239 /*!
240     \since 3.3
241     \var IrcMessage::Implicit
242     \brief The message is an implicit "reply" after joining a channel.
243  */
244 
245 extern bool irc_is_supported_encoding(const QByteArray& encoding); // ircmessagedecoder.cpp
246 
irc_create_message(const QString & command,IrcConnection * connection)247 static IrcMessage* irc_create_message(const QString& command, IrcConnection* connection)
248 {
249     typedef std::function<IrcMessage *(IrcConnection *)> IrcMessageFactory;
250 
251     static const QHash<QString, IrcMessageFactory> factories = {
252         {"ACCOUNT", [](IrcConnection* c) { return new IrcAccountMessage(c); }},
253         {"AWAY", [](IrcConnection* c) { return new IrcAwayMessage(c); }},
254         {"BATCH", [](IrcConnection* c) { return new IrcBatchMessage(c); }},
255         {"CAP", [](IrcConnection* c) { return new IrcCapabilityMessage(c); }},
256         {"ERROR", [](IrcConnection* c) { return new IrcErrorMessage(c); }},
257         {"CHGHOST", [](IrcConnection* c) { return new IrcHostChangeMessage(c); }},
258         {"INVITE", [](IrcConnection* c) { return new IrcInviteMessage(c); }},
259         {"JOIN", [](IrcConnection* c) { return new IrcJoinMessage(c); }},
260         {"KICK", [](IrcConnection* c) { return new IrcKickMessage(c); }},
261         {"MODE", [](IrcConnection* c) { return new IrcModeMessage(c); }},
262         {"NICK", [](IrcConnection* c) { return new IrcNickMessage(c); }},
263         {"NOTICE", [](IrcConnection* c) { return new IrcNoticeMessage(c); }},
264         {"PART", [](IrcConnection* c) { return new IrcPartMessage(c); }},
265         {"PING", [](IrcConnection* c) { return new IrcPingMessage(c); }},
266         {"PONG", [](IrcConnection* c) { return new IrcPongMessage(c); }},
267         {"PRIVMSG", [](IrcConnection* c) { return new IrcPrivateMessage(c); }},
268         {"QUIT", [](IrcConnection* c) { return new IrcQuitMessage(c); }},
269         {"TOPIC", [](IrcConnection* c) { return new IrcTopicMessage(c); }},
270     };
271 
272     IrcMessageFactory factory = factories.value(command);
273     if (factory)
274         return factory(connection);
275 
276     bool isNumeric = false;
277     int number = command.toInt(&isNumeric);
278     if (isNumeric && number > 0)
279         return new IrcNumericMessage(connection);
280 
281     return new IrcMessage(connection);
282 }
283 
284 /*!
285     Constructs a new IrcMessage with \a connection.
286  */
IrcMessage(IrcConnection * connection)287 IrcMessage::IrcMessage(IrcConnection* connection) : QObject(connection), d_ptr(new IrcMessagePrivate)
288 {
289     Q_D(IrcMessage);
290     d->connection = connection;
291 }
292 
293 /*!
294     Destructs the message.
295  */
~IrcMessage()296 IrcMessage::~IrcMessage()
297 {
298 }
299 
300 /*!
301     This property holds the message connection.
302 
303     \par Access function:
304     \li \ref IrcConnection* <b>connection</b>() const
305  */
connection() const306 IrcConnection* IrcMessage::connection() const
307 {
308     Q_D(const IrcMessage);
309     return d->connection;
310 }
311 
312 /*!
313     This property holds the message network.
314 
315     \par Access function:
316     \li \ref IrcNetwork* <b>network</b>() const
317  */
network() const318 IrcNetwork* IrcMessage::network() const
319 {
320     Q_D(const IrcMessage);
321     return d->connection ? d->connection->network() : nullptr;
322 }
323 
324 /*!
325     This property holds the message type.
326 
327     \par Access function:
328     \li \ref IrcMessage::Type <b>type</b>() const
329  */
type() const330 IrcMessage::Type IrcMessage::type() const
331 {
332     Q_D(const IrcMessage);
333     return d->type;
334 }
335 
336 /*!
337     \since 3.2
338     \property bool IrcMessage::own
339 
340     This property holds whether the message is user's own.
341 
342     This property is provided for convenience. It is equivalent
343     of testing for the IrcMessage::Own flag.
344 
345     \par Access function:
346     \li bool <b>isOwn</b>() const
347  */
isOwn() const348 bool IrcMessage::isOwn() const
349 {
350     return flags() & Own;
351 }
352 
353 /*!
354     \since 3.5
355     \property bool IrcMessage::implicit
356 
357     This property holds whether the message is an implicit "reply"
358     after joining a channel.
359 
360     This property is provided for convenience. It is equivalent
361     of testing for the IrcMessage::Implicit flag.
362 
363     \par Access function:
364     \li bool <b>isImplicit</b>() const
365  */
isImplicit() const366 bool IrcMessage::isImplicit() const
367 {
368     return flags() & Implicit;
369 }
370 
371 /*!
372     This property holds the message flags.
373 
374     \par Access function:
375     \li \ref IrcMessage::Flag "IrcMessage::Flags" <b>flags</b>() const
376     \li void <b>setFlags</b>(\ref IrcMessage::Flag "IrcMessage::Flags" flags) (\b Since 3.2)
377 
378     \sa testFlag(), setFlag()
379  */
flags() const380 IrcMessage::Flags IrcMessage::flags() const
381 {
382     Q_D(const IrcMessage);
383     if (d->flags == -1) {
384         d->flags = IrcMessage::None;
385         if (d->connection && !d->prefix().isEmpty() && d->nick() == d->connection->nickName())
386             d->flags |= IrcMessage::Own;
387     }
388     return IrcMessage::Flags(d->flags);
389 }
390 
setFlags(IrcMessage::Flags flags)391 void IrcMessage::setFlags(IrcMessage::Flags flags)
392 {
393     Q_D(IrcMessage);
394     d->flags = flags;
395 }
396 
397 /*!
398     \since 3.5
399 
400     Returns \c true if the \a flag is on; otherwise \c false.
401 
402     \sa IrcMessage::flags
403  */
testFlag(Flag flag) const404 bool IrcMessage::testFlag(Flag flag) const
405 {
406     return flags().testFlag(flag);
407 }
408 
409 /*!
410     \since 3.5
411 
412     Sets whether the \a flag is \a on.
413 
414     \sa IrcMessage::flags
415  */
setFlag(Flag flag,bool on)416 void IrcMessage::setFlag(Flag flag, bool on)
417 {
418     if (on)
419         setFlags(flags() | flag);
420     else
421         setFlags(flags() & ~flag);
422 }
423 
424 /*!
425     This property holds the message command.
426 
427     \par Access functions:
428     \li QString <b>command</b>() const
429     \li void <b>setCommand</b>(const QString& command)
430  */
command() const431 QString IrcMessage::command() const
432 {
433     Q_D(const IrcMessage);
434     return d->command();
435 }
436 
setCommand(const QString & command)437 void IrcMessage::setCommand(const QString& command)
438 {
439     Q_D(IrcMessage);
440     d->setCommand(command);
441 }
442 
443 /*!
444     This property holds the message sender prefix.
445 
446     The prefix consists of \ref nick, \ref ident and \ref host as specified in RFC 1459:
447     <pre>
448     &lt;prefix&gt; ::= &lt;\ref nick&gt; [ '!' &lt;\ref ident&gt; ] [ '@' &lt;\ref host&gt; ]
449     </pre>
450 
451     \par Access functions:
452     \li QString <b>prefix</b>() const
453     \li void <b>setPrefix</b>(const QString& prefix)
454  */
prefix() const455 QString IrcMessage::prefix() const
456 {
457     Q_D(const IrcMessage);
458     return d->prefix();
459 }
460 
setPrefix(const QString & prefix)461 void IrcMessage::setPrefix(const QString& prefix)
462 {
463     Q_D(IrcMessage);
464     d->setPrefix(prefix);
465 }
466 
467 /*!
468     This property holds the message sender nick.
469 
470     Nick is part of the sender \ref prefix as specified in RFC 1459:
471     <pre>
472     <b>&lt;nick&gt;</b> [ '!' &lt;\ref ident&gt; ] [ '@' &lt;\ref host&gt; ]
473     </pre>
474 
475     \par Access function:
476     \li QString <b>nick</b>() const
477  */
nick() const478 QString IrcMessage::nick() const
479 {
480     Q_D(const IrcMessage);
481     return d->nick();
482 }
483 
484 /*!
485     This property holds the message sender ident.
486 
487     Ident is part of the sender \ref prefix as specified in RFC 1459:
488     <pre>
489     &lt;\ref nick&gt; [ '!' <b>&lt;ident&gt;</b> ] [ '@' &lt;\ref host&gt; ]
490     </pre>
491 
492     \par Access function:
493     \li QString <b>ident</b>() const
494  */
ident() const495 QString IrcMessage::ident() const
496 {
497     Q_D(const IrcMessage);
498     return d->ident();
499 }
500 
501 /*!
502     This property holds the message sender host.
503 
504     Host is part of the sender \ref prefix as specified in RFC 1459:
505     <pre>
506     &lt;\ref nick&gt; [ '!' &lt;\ref ident&gt; ] [ '@' <b>&lt;host&gt;</b> ]
507     </pre>
508 
509     \par Access function:
510     \li QString <b>host</b>() const
511  */
host() const512 QString IrcMessage::host() const
513 {
514     Q_D(const IrcMessage);
515     return d->host();
516 }
517 
518 /*!
519     \since 3.4
520 
521     This property holds the services account of the message sender.
522 
523     \note Only set if the \c account-tag capability is
524     enabled and the user has identified with services.
525 
526     \par Access function:
527     \li QString <b>account</b>() const
528 
529     \sa \ref ircv3
530  */
account() const531 QString IrcMessage::account() const
532 {
533     Q_D(const IrcMessage);
534     return d->tags().value(QLatin1String("account")).toString();
535 }
536 
537 /*!
538     This property holds the message parameters.
539 
540     \par Access functions:
541     \li QStringList <b>parameters</b>() const
542     \li void <b>setParameters</b>(const QStringList& parameters)
543  */
parameters() const544 QStringList IrcMessage::parameters() const
545 {
546     Q_D(const IrcMessage);
547     return d->params();
548 }
549 
setParameters(const QStringList & parameters)550 void IrcMessage::setParameters(const QStringList& parameters)
551 {
552     Q_D(IrcMessage);
553     d->setParams(parameters);
554 }
555 
556 /*!
557     \since 3.5
558 
559     Returns the parameter at the specified \a index.
560  */
parameter(int index) const561 QString IrcMessage::parameter(int index) const
562 {
563     Q_D(const IrcMessage);
564     return d->param(index);
565 }
566 
567 /*!
568     \since 3.5
569 
570     Sets the \a parameter at the specified \a index.
571  */
setParameter(int index,const QString & parameter)572 void IrcMessage::setParameter(int index, const QString& parameter)
573 {
574     Q_D(IrcMessage);
575     QStringList params = d->params();
576     while (index >= params.count())
577         params.append(QString());
578     params[index] = parameter;
579     d->setParams(params);
580 }
581 
582 /*!
583     This property holds the message time stamp.
584 
585     \note When the \c server-time capability is enabled, the time
586           stamp is automatically set from the \c time message tag.
587 
588     \par Access functions:
589     \li QDateTime <b>timeStamp</b>() const
590     \li void <b>setTimeStamp</b>(const QDateTime& timeStamp)
591 
592     \sa \ref ircv3
593  */
timeStamp() const594 QDateTime IrcMessage::timeStamp() const
595 {
596     Q_D(const IrcMessage);
597     return d->timeStamp;
598 }
599 
setTimeStamp(const QDateTime & timeStamp)600 void IrcMessage::setTimeStamp(const QDateTime& timeStamp)
601 {
602     Q_D(IrcMessage);
603     d->timeStamp = timeStamp;
604 }
605 
606 /*!
607     This property holds the FALLBACK encoding for the message.
608 
609     The fallback encoding is used when the message is detected not
610     to be valid UTF-8 and the consequent auto-detection of message
611     encoding fails. See QTextCodec::availableCodes() for the list of
612     supported encodings.
613 
614     The default value is ISO-8859-15.
615 
616     \par Access functions:
617     \li QByteArray <b>encoding</b>() const
618     \li void <b>setEncoding</b>(const QByteArray& encoding)
619 
620     \sa QTextCodec::availableCodecs(), QTextCodec::codecForLocale()
621  */
encoding() const622 QByteArray IrcMessage::encoding() const
623 {
624     Q_D(const IrcMessage);
625     return d->encoding;
626 }
627 
setEncoding(const QByteArray & encoding)628 void IrcMessage::setEncoding(const QByteArray& encoding)
629 {
630     Q_D(IrcMessage);
631     if (!irc_is_supported_encoding(encoding)) {
632         qWarning() << "IrcMessage::setEncoding(): unsupported encoding" << encoding;
633         return;
634     }
635     d->encoding = encoding;
636     d->invalidate();
637 }
638 
639 /*!
640     \since 3.1
641 
642     This property holds the message tags.
643 
644     \par Access functions:
645     \li QVariantMap <b>tags</b>() const
646     \li void <b>setTags</b>(const QVariantMap& tags)
647 
648     \sa \ref ircv3
649  */
tags() const650 QVariantMap IrcMessage::tags() const
651 {
652     Q_D(const IrcMessage);
653     return d->tags();
654 }
655 
setTags(const QVariantMap & tags)656 void IrcMessage::setTags(const QVariantMap& tags)
657 {
658     Q_D(IrcMessage);
659     d->setTags(tags);
660 }
661 
662 /*!
663     \since 3.5
664 
665     Returns the value of the specified tag.
666 
667     \sa \ref ircv3
668  */
tag(const QString & name) const669 QVariant IrcMessage::tag(const QString& name) const
670 {
671     Q_D(const IrcMessage);
672     return d->tags().value(name);
673 }
674 
675 /*!
676     \since 3.5
677 
678     Sets the value of the specified tag.
679 
680     \sa \ref ircv3
681  */
setTag(const QString & name,const QVariant & value)682 void IrcMessage::setTag(const QString& name, const QVariant& value)
683 {
684     Q_D(IrcMessage);
685     QVariantMap tags = d->tags();
686     tags.insert(name, value);
687     d->setTags(tags);
688 }
689 
690 /*!
691     Creates a new message from \a data and \a connection.
692  */
fromData(const QByteArray & data,IrcConnection * connection)693 IrcMessage* IrcMessage::fromData(const QByteArray& data, IrcConnection* connection)
694 {
695     IrcMessageData md = IrcMessageData::fromData(data);
696     IrcMessage* message = irc_create_message(md.command, connection);
697     Q_ASSERT(message);
698     message->d_ptr->data = md;
699     QByteArray tag = md.tags.value("time");
700     if (!tag.isEmpty()) {
701         QDateTime ts = QDateTime::fromString(QString::fromUtf8(tag), Qt::ISODate);
702         if (ts.isValid())
703             message->d_ptr->timeStamp = ts.toTimeSpec(Qt::LocalTime);
704     }
705     return message;
706 }
707 
708 /*!
709     Creates a new message from \a prefix, \a command and \a parameters with \a connection.
710  */
fromParameters(const QString & prefix,const QString & command,const QStringList & parameters,IrcConnection * connection)711 IrcMessage* IrcMessage::fromParameters(const QString& prefix, const QString& command, const QStringList& parameters, IrcConnection* connection)
712 {
713     IrcMessage* message = irc_create_message(command, connection);
714     Q_ASSERT(message);
715     message->setPrefix(prefix);
716     message->setCommand(command);
717     message->setParameters(parameters);
718     return message;
719 }
720 
721 /*!
722     \since 3.5
723 
724     Clones the message.
725  */
clone(QObject * parent) const726 IrcMessage* IrcMessage::clone(QObject* parent) const
727 {
728     Q_D(const IrcMessage);
729     IrcMessage* msg = irc_create_message(d->command(), d->connection);
730     if (msg) {
731         msg->setParent(parent);
732         IrcMessagePrivate* p = IrcMessagePrivate::get(msg);
733         p->timeStamp = d->timeStamp;
734         p->encoding = d->encoding;
735         p->flags = d->flags;
736         p->data = d->data;
737         foreach (IrcMessage* bm, d->batch)
738             p->batch += bm->clone(msg);
739         p->m_nick = d->m_nick;
740         p->m_ident = d->m_ident;
741         p->m_host = d->m_host;
742         p->m_prefix = d->m_prefix;
743         p->m_command = d->m_command;
744         p->m_params = d->m_params;
745         p->m_tags = d->m_tags;
746     }
747     return msg;
748 }
749 
750 /*!
751     \property bool IrcMessage::valid
752     This property is \c true if the message is valid; otherwise \c false.
753 
754     A message is considered valid if the prefix is not empty
755     and the parameters match the message.
756 
757     \par Access function:
758     \li bool <b>isValid</b>() const
759  */
isValid() const760 bool IrcMessage::isValid() const
761 {
762     Q_D(const IrcMessage);
763     return d->connection && !prefix().isNull();
764 }
765 
766 /*!
767     Returns the message as received from an IRC server.
768  */
toData() const769 QByteArray IrcMessage::toData() const
770 {
771     Q_D(const IrcMessage);
772     return d->content();
773 }
774 
775 /*!
776     \since 3.3
777     \class IrcAwayMessage ircmessage.h <IrcMessage>
778     \ingroup message
779     \brief Represents an away message.
780  */
781 
782 /*!
783     Constructs a new IrcAwayMessage with \a connection.
784  */
IrcAwayMessage(IrcConnection * connection)785 IrcAwayMessage::IrcAwayMessage(IrcConnection* connection) : IrcMessage(connection)
786 {
787     Q_D(IrcMessage);
788     d->type = Away;
789 }
790 
791 /*!
792     This property holds the message content.
793 
794     \par Access function:
795     \li QString <b>content</b>() const
796  */
content() const797 QString IrcAwayMessage::content() const
798 {
799     Q_D(const IrcMessage);
800     return d->param(0);
801 }
802 
803 /*!
804     \property bool IrcAwayMessage::reply
805     This property holds whether the message is a reply.
806 
807     Away messages are sent in three situations:
808     \li as a reply when sending a message (\c true),
809     \li as a reply when setting away status (\c true),
810     \li as an away notification when the \c away-notify capability is enabled (\c false).
811 
812     \par Access function:
813     \li bool <b>isReply</b>() const
814 
815     \sa Irc::RPL_AWAY, Irc::RPL_NOWAWAY, Irc::RPL_UNAWAY, \ref ircv3
816  */
isReply() const817 bool IrcAwayMessage::isReply() const
818 {
819     Q_D(const IrcMessage);
820     return d->command().toInt() != 0;
821 }
822 
823 /*!
824     \property bool IrcAwayMessage::away
825     This property holds whether the user is away or back.
826 
827     \par Access function:
828     \li bool <b>isAway</b>() const
829  */
isAway() const830 bool IrcAwayMessage::isAway() const
831 {
832     Q_D(const IrcMessage);
833     int rpl = d->command().toInt();
834     return rpl == Irc::RPL_AWAY || rpl == Irc::RPL_NOWAWAY
835             || (d->command() == "AWAY" && !d->param(0).isEmpty());
836 }
837 
isValid() const838 bool IrcAwayMessage::isValid() const
839 {
840     return IrcMessage::isValid();
841 }
842 
843 /*!
844     \since 3.3
845     \class IrcAccountMessage ircmessage.h <IrcMessage>
846     \ingroup message
847     \brief Represents an account notify message.
848     \sa \ref ircv3
849  */
850 
851 /*!
852     Constructs a new IrcAccountMessage with \a connection.
853  */
IrcAccountMessage(IrcConnection * connection)854 IrcAccountMessage::IrcAccountMessage(IrcConnection* connection) : IrcMessage(connection)
855 {
856     Q_D(IrcMessage);
857     d->type = Account;
858 }
859 
860 /*!
861     This property holds the account name.
862 
863     \note The account name is empty if the user has logged out.
864 
865     \par Access function:
866     \li QString <b>account</b>() const
867  */
account() const868 QString IrcAccountMessage::account() const
869 {
870     Q_D(const IrcMessage);
871     const QString p = d->param(0);
872     if (p != QLatin1String("*"))
873         return p;
874     return QString();
875 }
876 
isValid() const877 bool IrcAccountMessage::isValid() const
878 {
879     Q_D(const IrcMessage);
880     return IrcMessage::isValid() && !d->param(0).isEmpty();
881 }
882 
883 /*!
884     \since 3.5
885     \class IrcBatchMessage ircmessage.h <IrcMessage>
886     \ingroup message
887     \brief Represents a batch message.
888     \sa \ref ircv3
889  */
890 
891 /*!
892     Constructs a new IrcBatchMessage with \a connection.
893  */
IrcBatchMessage(IrcConnection * connection)894 IrcBatchMessage::IrcBatchMessage(IrcConnection* connection) : IrcMessage(connection)
895 {
896     Q_D(IrcMessage);
897     d->type = Batch;
898 }
899 
900 /*!
901     This property holds the batch tag.
902 
903     \par Access function:
904     \li QString <b>tag</b>() const
905  */
tag() const906 QString IrcBatchMessage::tag() const
907 {
908     Q_D(const IrcMessage);
909     return d->param(0).mid(1);
910 }
911 
912 /*!
913     This property holds the batch type.
914 
915     \par Access function:
916     \li QString <b>type</b>() const
917  */
batch() const918 QString IrcBatchMessage::batch() const
919 {
920     Q_D(const IrcMessage);
921     return d->param(1);
922 }
923 
924 /*!
925     This property holds the list of batched messages.
926 
927     \par Access function:
928     \li QList<IrcMessage*> <b>messages</b>() const
929  */
messages() const930 QList<IrcMessage*> IrcBatchMessage::messages() const
931 {
932     Q_D(const IrcMessage);
933     return d->batch;
934 }
935 
isValid() const936 bool IrcBatchMessage::isValid() const
937 {
938     return IrcMessage::isValid() && !batch().isEmpty();
939 }
940 
941 /*!
942     \class IrcCapabilityMessage ircmessage.h <IrcMessage>
943     \ingroup message
944     \brief Represents a capability message.
945     \sa \ref ircv3
946  */
947 
948 /*!
949     Constructs a new IrcCapabilityMessage with \a connection.
950  */
IrcCapabilityMessage(IrcConnection * connection)951 IrcCapabilityMessage::IrcCapabilityMessage(IrcConnection* connection) : IrcMessage(connection)
952 {
953     Q_D(IrcMessage);
954     d->type = Capability;
955 }
956 
957 /*!
958     This property holds the subcommand.
959 
960     The following capability subcommands are defined:
961     LS, LIST, REQ, ACK, NAK, CLEAR, END, NEW, DEL.
962 
963     \par Access function:
964     \li QString <b>subCommand</b>() const
965  */
subCommand() const966 QString IrcCapabilityMessage::subCommand() const
967 {
968     Q_D(const IrcMessage);
969     return d->param(1);
970 }
971 
972 /*!
973     This property holds the capabilities.
974 
975     A list of capabilities may exist for the following
976     subcommands: LS, LIST, REQ, ACK, NAK, NEW, DEL.
977 
978     \par Access function:
979     \li QStringList <b>capabilities</b>() const
980  */
capabilities() const981 QStringList IrcCapabilityMessage::capabilities() const
982 {
983     Q_D(const IrcMessage);
984     QStringList caps;
985     QStringList params = d->params();
986     if (params.count() > 2)
987         caps = params.last().split(QLatin1Char(' '), Qt::SkipEmptyParts);
988     return caps;
989 }
990 
isValid() const991 bool IrcCapabilityMessage::isValid() const
992 {
993     return IrcMessage::isValid();
994 }
995 
996 /*!
997     \class IrcErrorMessage ircmessage.h <IrcMessage>
998     \ingroup message
999     \brief Represents an error message.
1000  */
1001 
1002 /*!
1003     Constructs a new IrcErrorMessage with \a connection.
1004  */
IrcErrorMessage(IrcConnection * connection)1005 IrcErrorMessage::IrcErrorMessage(IrcConnection* connection) : IrcMessage(connection)
1006 {
1007     Q_D(IrcMessage);
1008     d->type = Error;
1009 }
1010 
1011 /*!
1012     This property holds the error.
1013 
1014     \par Access function:
1015     \li QString <b>error</b>() const
1016  */
error() const1017 QString IrcErrorMessage::error() const
1018 {
1019     Q_D(const IrcMessage);
1020     return d->param(0);
1021 }
1022 
isValid() const1023 bool IrcErrorMessage::isValid() const
1024 {
1025     return IrcMessage::isValid() && !error().isEmpty();
1026 }
1027 
1028 /*!
1029     \since 3.4
1030     \class IrcHostChangeMessage ircmessage.h <IrcMessage>
1031     \ingroup message
1032     \brief Represents a host change message.
1033 
1034     \sa \ref ircv3
1035  */
1036 
1037 /*!
1038     Constructs a new IrcHostChangeMessage with \a connection.
1039  */
IrcHostChangeMessage(IrcConnection * connection)1040 IrcHostChangeMessage::IrcHostChangeMessage(IrcConnection* connection) : IrcMessage(connection)
1041 {
1042     Q_D(IrcMessage);
1043     d->type = HostChange;
1044 }
1045 
1046 /*!
1047     This property holds the user name.
1048 
1049     \par Access function:
1050     \li QString <b>user</b>() const
1051  */
user() const1052 QString IrcHostChangeMessage::user() const
1053 {
1054     Q_D(const IrcMessage);
1055     return d->param(0);
1056 }
1057 
1058 /*!
1059     This property holds the new host.
1060 
1061     \par Access function:
1062     \li QString <b>host</b>() const
1063  */
host() const1064 QString IrcHostChangeMessage::host() const
1065 {
1066     Q_D(const IrcMessage);
1067     return d->param(1);
1068 }
1069 
isValid() const1070 bool IrcHostChangeMessage::isValid() const
1071 {
1072     return IrcMessage::isValid() && !user().isEmpty() && !host().isEmpty();
1073 }
1074 
1075 /*!
1076     \class IrcInviteMessage ircmessage.h <IrcMessage>
1077     \ingroup message
1078     \brief Represents an invite message.
1079  */
1080 
1081 /*!
1082     Constructs a new IrcInviteMessage with \a connection.
1083  */
IrcInviteMessage(IrcConnection * connection)1084 IrcInviteMessage::IrcInviteMessage(IrcConnection* connection) : IrcMessage(connection)
1085 {
1086     Q_D(IrcMessage);
1087     d->type = Invite;
1088 }
1089 
1090 /*!
1091     This property holds the user in question.
1092 
1093     \par Access function:
1094     \li QString <b>user</b>() const
1095 
1096     \sa \ref ircv3
1097  */
user() const1098 QString IrcInviteMessage::user() const
1099 {
1100     Q_D(const IrcMessage);
1101     return d->param(0);
1102 }
1103 
1104 /*!
1105     This property holds the channel in question.
1106 
1107     \par Access function:
1108     \li QString <b>channel</b>() const
1109  */
channel() const1110 QString IrcInviteMessage::channel() const
1111 {
1112     Q_D(const IrcMessage);
1113     return d->param(1);
1114 }
1115 
1116 /*!
1117     \property bool IrcInviteMessage::reply
1118     This property holds whether the message is a reply.
1119 
1120     Invite messages are sent in three situations:
1121     \li as a notification of a received invitation (\c false),
1122     \li as a reply when sending an invitation (\c true), or
1123     \li as an invite notification when the \c invite-notify capability is enabled (\c false).
1124 
1125     \par Access function:
1126     \li bool <b>isReply</b>() const
1127 
1128     \sa Irc::RPL_INVITING, Irc::RPL_INVITED, IrcInviteCommand, \ref ircv3
1129  */
isReply() const1130 bool IrcInviteMessage::isReply() const
1131 {
1132     Q_D(const IrcMessage);
1133     int rpl = d->command().toInt();
1134     return rpl == Irc::RPL_INVITING || rpl == Irc::RPL_INVITED;
1135 }
1136 
isValid() const1137 bool IrcInviteMessage::isValid() const
1138 {
1139     return IrcMessage::isValid() && !user().isEmpty() && !channel().isEmpty();
1140 }
1141 
1142 /*!
1143     \class IrcJoinMessage ircmessage.h <IrcMessage>
1144     \ingroup message
1145     \brief Represents a join message.
1146  */
1147 
1148 /*!
1149     Constructs a new IrcJoinMessage with \a connection.
1150  */
IrcJoinMessage(IrcConnection * connection)1151 IrcJoinMessage::IrcJoinMessage(IrcConnection* connection) : IrcMessage(connection)
1152 {
1153     Q_D(IrcMessage);
1154     d->type = Join;
1155 }
1156 
1157 /*!
1158     This property holds the channel in question.
1159 
1160     \par Access function:
1161     \li QString <b>channel</b>() const
1162  */
channel() const1163 QString IrcJoinMessage::channel() const
1164 {
1165     Q_D(const IrcMessage);
1166     return d->param(0);
1167 }
1168 
1169 /*!
1170     \since 3.3
1171 
1172     This property holds the account name of the user.
1173 
1174     \note Only set if the \c extended-join capability is
1175     enabled and the user has identified with services.
1176 
1177     \par Access function:
1178     \li QString <b>account</b>() const
1179 
1180     \sa \ref ircv3
1181  */
account() const1182 QString IrcJoinMessage::account() const
1183 {
1184     Q_D(const IrcMessage);
1185     const QString p = d->param(1);
1186     if (p != QLatin1String("*"))
1187         return p;
1188     return QString();
1189 }
1190 
1191 /*!
1192     \since 3.3
1193 
1194     This property holds the real name of the user.
1195 
1196     \note Only set if the \c extended-join capability is enabled.
1197 
1198     \par Access function:
1199     \li QString <b>realName</b>() const
1200 
1201     \sa \ref ircv3
1202  */
realName() const1203 QString IrcJoinMessage::realName() const
1204 {
1205     Q_D(const IrcMessage);
1206     return d->param(2);
1207 }
1208 
isValid() const1209 bool IrcJoinMessage::isValid() const
1210 {
1211     return IrcMessage::isValid() && !channel().isEmpty();
1212 }
1213 
1214 /*!
1215     \class IrcKickMessage ircmessage.h <IrcMessage>
1216     \ingroup message
1217     \brief Represents a kick message.
1218  */
1219 
1220 /*!
1221     Constructs a new IrcKickMessage with \a connection.
1222  */
IrcKickMessage(IrcConnection * connection)1223 IrcKickMessage::IrcKickMessage(IrcConnection* connection) : IrcMessage(connection)
1224 {
1225     Q_D(IrcMessage);
1226     d->type = Kick;
1227 }
1228 
1229 /*!
1230     This property holds the channel in question.
1231 
1232     \par Access function:
1233     \li QString <b>channel</b>() const
1234  */
channel() const1235 QString IrcKickMessage::channel() const
1236 {
1237     Q_D(const IrcMessage);
1238     return d->param(0);
1239 }
1240 
1241 /*!
1242     This property holds the user in question.
1243 
1244     \par Access function:
1245     \li QString <b>user</b>() const
1246  */
user() const1247 QString IrcKickMessage::user() const
1248 {
1249     Q_D(const IrcMessage);
1250     return d->param(1);
1251 }
1252 
1253 /*!
1254     This property holds the optional kick reason.
1255 
1256     \par Access function:
1257     \li QString <b>reason</b>() const
1258  */
reason() const1259 QString IrcKickMessage::reason() const
1260 {
1261     Q_D(const IrcMessage);
1262     return d->param(2);
1263 }
1264 
isValid() const1265 bool IrcKickMessage::isValid() const
1266 {
1267     return IrcMessage::isValid() && !channel().isEmpty() && !user().isEmpty();
1268 }
1269 
1270 /*!
1271     \class IrcModeMessage ircmessage.h <IrcMessage>
1272     \ingroup message
1273     \brief Represents a mode message.
1274  */
1275 
1276 /*!
1277     \enum IrcModeMessage::Kind
1278     This enum describes the kind of modes.
1279  */
1280 
1281 /*!
1282     \var IrcModeMessage::Channel
1283     \brief Channel mode
1284  */
1285 
1286 /*!
1287     \var IrcModeMessage::User
1288     \brief User mode
1289  */
1290 
1291 /*!
1292     Constructs a new IrcModeMessage with \a connection.
1293  */
IrcModeMessage(IrcConnection * connection)1294 IrcModeMessage::IrcModeMessage(IrcConnection* connection) : IrcMessage(connection)
1295 {
1296     Q_D(IrcMessage);
1297     d->type = Mode;
1298 }
1299 
1300 /*!
1301     This property holds the target channel or user in question.
1302 
1303     \par Access function:
1304     \li QString <b>target</b>() const
1305  */
target() const1306 QString IrcModeMessage::target() const
1307 {
1308     Q_D(const IrcMessage);
1309     return d->param(0);
1310 }
1311 
1312 /*!
1313     This property holds the channel or user mode.
1314 
1315     \par Access function:
1316     \li QString <b>mode</b>() const
1317  */
mode() const1318 QString IrcModeMessage::mode() const
1319 {
1320     Q_D(const IrcMessage);
1321     return d->param(1);
1322 }
1323 
1324 /*!
1325     This property holds the first mode argument.
1326 
1327     \par Access function:
1328     \li QString <b>argument</b>() const
1329  */
argument() const1330 QString IrcModeMessage::argument() const
1331 {
1332     Q_D(const IrcMessage);
1333     return d->param(2);
1334 }
1335 
1336 /*!
1337     \since 3.1
1338 
1339     This property holds the all mode arguments.
1340 
1341     \par Access function:
1342     \li QStringList <b>arguments</b>() const
1343  */
arguments() const1344 QStringList IrcModeMessage::arguments() const
1345 {
1346     Q_D(const IrcMessage);
1347     return d->params().mid(2);
1348 }
1349 
1350 /*!
1351     \property bool IrcModeMessage::reply
1352     This property holds whether the message is a reply.
1353 
1354     Mode messages are sent when a mode changes (\c false)
1355     and when joining a channel (\c true).
1356 
1357     \par Access function:
1358     \li bool <b>isReply</b>() const
1359 
1360     \sa Irc::RPL_CHANNELMODEIS
1361  */
isReply() const1362 bool IrcModeMessage::isReply() const
1363 {
1364     Q_D(const IrcMessage);
1365     int rpl = d->command().toInt();
1366     return rpl == Irc::RPL_CHANNELMODEIS;
1367 }
1368 
1369 /*!
1370     This property holds the kind of the mode.
1371 
1372     \par Access function:
1373     \li Kind <b>kind</b>() const
1374  */
kind() const1375 IrcModeMessage::Kind IrcModeMessage::kind() const
1376 {
1377     const QString m = mode().remove(QLatin1Char('+')).remove(QLatin1Char('-'));
1378     if (!m.isEmpty()) {
1379         QStringList channelModes;
1380         if (const IrcNetwork* net = network())
1381             channelModes = net->channelModes(IrcNetwork::AllTypes);
1382         if (!channelModes.isEmpty()) {
1383             for (int i = 0; i < m.length(); ++i) {
1384                 if (!channelModes.contains(m.at(i)))
1385                     return User;
1386             }
1387         }
1388     }
1389     return Channel;
1390 }
1391 
isValid() const1392 bool IrcModeMessage::isValid() const
1393 {
1394     return IrcMessage::isValid() && !target().isEmpty() && !mode().isEmpty();
1395 }
1396 
1397 /*!
1398     \class IrcMotdMessage ircmessage.h <IrcMessage>
1399     \ingroup message
1400     \brief Represents a message of the day.
1401  */
1402 
1403 /*!
1404     Constructs a new IrcMotdMessage with \a connection.
1405  */
IrcMotdMessage(IrcConnection * connection)1406 IrcMotdMessage::IrcMotdMessage(IrcConnection* connection) : IrcMessage(connection)
1407 {
1408     Q_D(IrcMessage);
1409     d->type = Motd;
1410     setCommand(QLatin1String("MOTD"));
1411 }
1412 
1413 /*!
1414     This property holds the message of the day lines.
1415 
1416     \par Access function:
1417     \li QStringList <b>lines</b>() const
1418  */
lines() const1419 QStringList IrcMotdMessage::lines() const
1420 {
1421     Q_D(const IrcMessage);
1422     return d->params().mid(1);
1423 }
1424 
isValid() const1425 bool IrcMotdMessage::isValid() const
1426 {
1427     Q_D(const IrcMessage);
1428     return IrcMessage::isValid() && !d->params().isEmpty();
1429 }
1430 
1431 /*!
1432     \class IrcNamesMessage ircmessage.h <IrcMessage>
1433     \ingroup message
1434     \brief Represents a names list message.
1435  */
1436 
1437 /*!
1438     Constructs a new IrcNamesMessage with \a connection.
1439  */
IrcNamesMessage(IrcConnection * connection)1440 IrcNamesMessage::IrcNamesMessage(IrcConnection* connection) : IrcMessage(connection)
1441 {
1442     Q_D(IrcMessage);
1443     d->type = Names;
1444     setCommand(QLatin1String("NAMES"));
1445 }
1446 
1447 /*!
1448     This property holds the channel.
1449 
1450     \par Access function:
1451     \li QString <b>channel</b>() const
1452  */
channel() const1453 QString IrcNamesMessage::channel() const
1454 {
1455     Q_D(const IrcMessage);
1456     return d->param(0);
1457 }
1458 
1459 /*!
1460     This property holds the list of names.
1461 
1462     \par Access function:
1463     \li QStringList <b>names</b>() const
1464  */
names() const1465 QStringList IrcNamesMessage::names() const
1466 {
1467     Q_D(const IrcMessage);
1468     return d->params().mid(1);
1469 }
1470 
isValid() const1471 bool IrcNamesMessage::isValid() const
1472 {
1473     Q_D(const IrcMessage);
1474     return IrcMessage::isValid() && !d->params().isEmpty();
1475 }
1476 
1477 /*!
1478     \class IrcNickMessage ircmessage.h <IrcMessage>
1479     \ingroup message
1480     \brief Represents a nick message.
1481  */
1482 
1483 /*!
1484     Constructs a new IrcNickMessage with \a connection.
1485  */
IrcNickMessage(IrcConnection * connection)1486 IrcNickMessage::IrcNickMessage(IrcConnection* connection) : IrcMessage(connection)
1487 {
1488     Q_D(IrcMessage);
1489     d->type = Nick;
1490 }
1491 
1492 /*!
1493     This property holds the old nick.
1494 
1495     This property is provided for symmetry with \ref newNick
1496     and is equal to \ref nick.
1497 
1498     \par Access function:
1499     \li QString <b>oldNick</b>() const
1500  */
oldNick() const1501 QString IrcNickMessage::oldNick() const
1502 {
1503     Q_D(const IrcMessage);
1504     return d->nick();
1505 }
1506 
1507 /*!
1508     This property holds the new nick.
1509 
1510     \par Access function:
1511     \li QString <b>newNick</b>() const
1512  */
newNick() const1513 QString IrcNickMessage::newNick() const
1514 {
1515     Q_D(const IrcMessage);
1516     return d->param(0);
1517 }
1518 
isValid() const1519 bool IrcNickMessage::isValid() const
1520 {
1521     return IrcMessage::isValid() && !newNick().isEmpty();
1522 }
1523 
1524 /*!
1525     \class IrcNoticeMessage ircmessage.h <IrcMessage>
1526     \ingroup message
1527     \brief Represents a notice message.
1528  */
1529 
1530 /*!
1531     Constructs a new IrcNoticeMessage with \a connection.
1532  */
IrcNoticeMessage(IrcConnection * connection)1533 IrcNoticeMessage::IrcNoticeMessage(IrcConnection* connection) : IrcMessage(connection)
1534 {
1535     Q_D(IrcMessage);
1536     d->type = Notice;
1537 }
1538 
1539 /*!
1540     This property holds the target channel or user in question.
1541 
1542     \par Access function:
1543     \li QString <b>target</b>() const
1544  */
target() const1545 QString IrcNoticeMessage::target() const
1546 {
1547     Q_D(const IrcMessage);
1548     if (d->connection) {
1549         const IrcNetwork* network = d->connection->network();
1550         return IrcNetworkPrivate::removePrefix(d->param(0), network->statusPrefixes());
1551     }
1552     return d->param(0);
1553 }
1554 
1555 /*!
1556     This property holds the message content.
1557 
1558     \par Access function:
1559     \li QString <b>content</b>() const
1560  */
content() const1561 QString IrcNoticeMessage::content() const
1562 {
1563     Q_D(const IrcMessage);
1564     QString msg = d->param(1);
1565     if (isReply()) {
1566         msg.remove(0, 1);
1567         msg.chop(1);
1568     }
1569     return msg;
1570 }
1571 
1572 /*!
1573     \since 3.4
1574 
1575     This property holds the status prefix of the message.
1576 
1577     \par Access function:
1578     \li QString <b>statusPrefix</b>() const
1579  */
statusPrefix() const1580 QString IrcNoticeMessage::statusPrefix() const
1581 {
1582     Q_D(const IrcMessage);
1583     if (d->connection) {
1584         const IrcNetwork* network = d->connection->network();
1585         return IrcNetworkPrivate::getPrefix(d->param(0), network->statusPrefixes());
1586     }
1587     return QString();
1588 }
1589 
1590 /*!
1591     \property bool IrcNoticeMessage::private
1592     This property is \c true if the notice is private,
1593     or \c false if it is a channel notice.
1594 
1595     \par Access function:
1596     \li bool <b>isPrivate</b>() const
1597  */
isPrivate() const1598 bool IrcNoticeMessage::isPrivate() const
1599 {
1600     Q_D(const IrcMessage);
1601     if (d->connection)
1602         return !target().compare(d->connection->nickName(), Qt::CaseInsensitive);
1603     return false;
1604 }
1605 
1606 /*!
1607     \property bool IrcNoticeMessage::reply
1608     This property is \c true if the message is a reply; otherwise \c false.
1609 
1610     \par Access function:
1611     \li bool <b>isReply</b>() const
1612  */
isReply() const1613 bool IrcNoticeMessage::isReply() const
1614 {
1615     Q_D(const IrcMessage);
1616     QString msg = d->param(1);
1617     return msg.startsWith('\1') && msg.endsWith('\1');
1618 }
1619 
isValid() const1620 bool IrcNoticeMessage::isValid() const
1621 {
1622     return IrcMessage::isValid() && !target().isEmpty() && !content().isEmpty();
1623 }
1624 
1625 /*!
1626     \class IrcNumericMessage ircmessage.h <IrcMessage>
1627     \ingroup message
1628     \brief Represents a numeric message.
1629  */
1630 
1631 /*!
1632     Constructs a new IrcNumericMessage with \a connection.
1633  */
IrcNumericMessage(IrcConnection * connection)1634 IrcNumericMessage::IrcNumericMessage(IrcConnection* connection) : IrcMessage(connection)
1635 {
1636     Q_D(IrcMessage);
1637     d->type = Numeric;
1638 }
1639 
1640 /*!
1641     This property holds the numeric code.
1642 
1643     \par Access function:
1644     \li int <b>code</b>() const
1645  */
code() const1646 int IrcNumericMessage::code() const
1647 {
1648     Q_D(const IrcMessage);
1649     bool ok = false;
1650     int number = d->command().toInt(&ok);
1651     return ok ? number : -1;
1652 }
1653 
1654 /*!
1655     \since 3.3
1656     \property bool IrcNumericMessage::composed
1657 
1658     This property holds whether the message is composed.
1659 
1660     \li \c RPL_MOTDSTART, \c RPL_MOTD, and \c RPL_ENDOFMOTD are composed as IrcMotdMessage
1661     \li \c RPL_NAMREPLY and \c RPL_ENDOFNAMES are composed as IrcNamesMessage
1662     \li \c RPL_TOPIC and \c RPL_NOTOPIC are composed as IrcTopicMessage
1663     \li \c RPL_INVITING and \c RPL_INVITED are composed as IrcInviteMessage
1664     \li \c RPL_WHOREPLY is composed as IrcWhoReplyMessage
1665     \li \c RPL_CHANNELMODEIS is composed as IrcModeMessage
1666     \li \c RPL_AWAY, \c RPL_UNAWAY, \c RPL_NOWAWAY are composed as as IrcAwayMessage
1667 
1668     \par Access function:
1669     \li bool <b>isComposed</b>() const
1670  */
isComposed() const1671 bool IrcNumericMessage::isComposed() const
1672 {
1673     return IrcMessageComposer::isComposed(code());
1674 }
1675 
isValid() const1676 bool IrcNumericMessage::isValid() const
1677 {
1678     return IrcMessage::isValid() && code() != -1;
1679 }
1680 
1681 /*!
1682     \class IrcPartMessage ircmessage.h <IrcMessage>
1683     \ingroup message
1684     \brief Represents a part message.
1685  */
1686 
1687 /*!
1688     Constructs a new IrcPartMessage with \a connection.
1689  */
IrcPartMessage(IrcConnection * connection)1690 IrcPartMessage::IrcPartMessage(IrcConnection* connection) : IrcMessage(connection)
1691 {
1692     Q_D(IrcMessage);
1693     d->type = Part;
1694 }
1695 
1696 /*!
1697     This property holds the channel in question.
1698 
1699     \par Access function:
1700     \li QString <b>channel</b>() const
1701  */
channel() const1702 QString IrcPartMessage::channel() const
1703 {
1704     Q_D(const IrcMessage);
1705     return d->param(0);
1706 }
1707 
1708 /*!
1709     This property holds the optional part reason.
1710 
1711     \par Access function:
1712     \li QString <b>reason</b>() const
1713  */
reason() const1714 QString IrcPartMessage::reason() const
1715 {
1716     Q_D(const IrcMessage);
1717     return d->param(1);
1718 }
1719 
isValid() const1720 bool IrcPartMessage::isValid() const
1721 {
1722     return IrcMessage::isValid() && !channel().isEmpty();
1723 }
1724 
1725 /*!
1726     \class IrcPingMessage ircmessage.h <IrcMessage>
1727     \ingroup message
1728     \brief Represents a ping message.
1729  */
1730 
1731 /*!
1732     Constructs a new IrcPingMessage with \a connection.
1733  */
IrcPingMessage(IrcConnection * connection)1734 IrcPingMessage::IrcPingMessage(IrcConnection* connection) : IrcMessage(connection)
1735 {
1736     Q_D(IrcMessage);
1737     d->type = Ping;
1738 }
1739 
1740 /*!
1741     This property holds the optional message argument.
1742 
1743     \par Access function:
1744     \li QString <b>argument</b>() const
1745  */
argument() const1746 QString IrcPingMessage::argument() const
1747 {
1748     Q_D(const IrcMessage);
1749     return d->param(0);
1750 }
1751 
isValid() const1752 bool IrcPingMessage::isValid() const
1753 {
1754     return IrcMessage::isValid();
1755 }
1756 
1757 /*!
1758     \class IrcPongMessage ircmessage.h <IrcMessage>
1759     \ingroup message
1760     \brief Represents a pong message.
1761  */
1762 
1763 /*!
1764     Constructs a new IrcPongMessage with \a connection.
1765  */
IrcPongMessage(IrcConnection * connection)1766 IrcPongMessage::IrcPongMessage(IrcConnection* connection) : IrcMessage(connection)
1767 {
1768     Q_D(IrcMessage);
1769     d->type = Pong;
1770 }
1771 
1772 /*!
1773     This property holds the optional message argument.
1774 
1775     \par Access function:
1776     \li QString <b>argument</b>() const
1777  */
argument() const1778 QString IrcPongMessage::argument() const
1779 {
1780     Q_D(const IrcMessage);
1781     QStringList params = d->params();
1782     return params.value(params.count() - 1);
1783 }
1784 
isValid() const1785 bool IrcPongMessage::isValid() const
1786 {
1787     return IrcMessage::isValid();
1788 }
1789 
1790 /*!
1791     \class IrcPrivateMessage ircmessage.h <IrcMessage>
1792     \ingroup message
1793     \brief Represents a private message.
1794  */
1795 
1796 /*!
1797     Constructs a new IrcPrivateMessage with \a connection.
1798  */
IrcPrivateMessage(IrcConnection * connection)1799 IrcPrivateMessage::IrcPrivateMessage(IrcConnection* connection) : IrcMessage(connection)
1800 {
1801     Q_D(IrcMessage);
1802     d->type = Private;
1803 }
1804 
1805 /*!
1806     This property holds the target channel or user in question.
1807 
1808     \par Access function:
1809     \li QString <b>target</b>() const
1810  */
target() const1811 QString IrcPrivateMessage::target() const
1812 {
1813     Q_D(const IrcMessage);
1814     if (d->connection) {
1815         const IrcNetwork* network = d->connection->network();
1816         return IrcNetworkPrivate::removePrefix(d->param(0), network->statusPrefixes());
1817     }
1818     return d->param(0);
1819 }
1820 
1821 /*!
1822     This property holds the message content.
1823 
1824     \par Access function:
1825     \li QString <b>content</b>() const
1826  */
content() const1827 QString IrcPrivateMessage::content() const
1828 {
1829     Q_D(const IrcMessage);
1830     QString msg = d->param(1);
1831     const bool act = isAction();
1832     const bool req = isRequest();
1833     if (act) msg.remove(0, 8);
1834     if (req) msg.remove(0, 1);
1835     if (act || req) msg.chop(1);
1836     return msg;
1837 }
1838 
1839 /*!
1840     \since 3.4
1841 
1842     This property holds the status prefix of the message.
1843 
1844     \par Access function:
1845     \li QString <b>statusPrefix</b>() const
1846  */
statusPrefix() const1847 QString IrcPrivateMessage::statusPrefix() const
1848 {
1849     Q_D(const IrcMessage);
1850     if (d->connection) {
1851         const IrcNetwork* network = d->connection->network();
1852         return IrcNetworkPrivate::getPrefix(d->param(0), network->statusPrefixes());
1853     }
1854     return QString();
1855 }
1856 
1857 /*!
1858     \property bool IrcPrivateMessage::private
1859     This property is \c true if the message is private,
1860     or \c false if it is a channel message.
1861 
1862     \par Access function:
1863     \li bool <b>isPrivate</b>() const
1864  */
isPrivate() const1865 bool IrcPrivateMessage::isPrivate() const
1866 {
1867     Q_D(const IrcMessage);
1868     if (d->connection)
1869         return !target().compare(d->connection->nickName(), Qt::CaseInsensitive);
1870     return false;
1871 }
1872 
1873 /*!
1874     \property bool IrcPrivateMessage::action
1875     This property is \c true if the message is an action; otherwise \c false.
1876 
1877     \par Access function:
1878     \li bool <b>isAction</b>() const
1879  */
isAction() const1880 bool IrcPrivateMessage::isAction() const
1881 {
1882     Q_D(const IrcMessage);
1883     QString msg = d->param(1);
1884     return msg.startsWith("\1ACTION ") && msg.endsWith('\1');
1885 }
1886 
1887 /*!
1888     \property bool IrcPrivateMessage::request
1889     This property is \c true if the message is a request; otherwise \c false.
1890 
1891     \par Access function:
1892     \li bool <b>isRequest</b>() const
1893  */
isRequest() const1894 bool IrcPrivateMessage::isRequest() const
1895 {
1896     Q_D(const IrcMessage);
1897     QString msg = d->param(1);
1898     return msg.startsWith('\1') && msg.endsWith('\1') && !isAction();
1899 }
1900 
isValid() const1901 bool IrcPrivateMessage::isValid() const
1902 {
1903     return IrcMessage::isValid() && !target().isEmpty() && !content().isEmpty();
1904 }
1905 
1906 /*!
1907     \class IrcQuitMessage ircmessage.h <IrcMessage>
1908     \ingroup message
1909     \brief Represents a quit message.
1910  */
1911 
1912 /*!
1913     Constructs a new IrcQuitMessage with \a connection.
1914  */
IrcQuitMessage(IrcConnection * connection)1915 IrcQuitMessage::IrcQuitMessage(IrcConnection* connection) : IrcMessage(connection)
1916 {
1917     Q_D(IrcMessage);
1918     d->type = Quit;
1919 }
1920 
1921 /*!
1922     This property holds the optional quit reason.
1923 
1924     \par Access function:
1925     \li QString <b>reason</b>() const
1926  */
reason() const1927 QString IrcQuitMessage::reason() const
1928 {
1929     Q_D(const IrcMessage);
1930     return d->param(0);
1931 }
1932 
isValid() const1933 bool IrcQuitMessage::isValid() const
1934 {
1935     return IrcMessage::isValid();
1936 }
1937 
1938 /*!
1939     \class IrcTopicMessage ircmessage.h <IrcMessage>
1940     \ingroup message
1941     \brief Represents a topic message.
1942  */
1943 
1944 /*!
1945     Constructs a new IrcTopicMessage with \a connection.
1946  */
IrcTopicMessage(IrcConnection * connection)1947 IrcTopicMessage::IrcTopicMessage(IrcConnection* connection) : IrcMessage(connection)
1948 {
1949     Q_D(IrcMessage);
1950     d->type = Topic;
1951 }
1952 
1953 /*!
1954     This property holds the channel in question.
1955 
1956     \par Access function:
1957     \li QString <b>channel</b>() const
1958  */
channel() const1959 QString IrcTopicMessage::channel() const
1960 {
1961     Q_D(const IrcMessage);
1962     return d->param(0);
1963 }
1964 
1965 /*!
1966     This property holds the new channel topic.
1967 
1968     \par Access function:
1969     \li QString <b>topic</b>() const
1970  */
topic() const1971 QString IrcTopicMessage::topic() const
1972 {
1973     Q_D(const IrcMessage);
1974     if (d->command().toInt() == Irc::RPL_NOTOPIC)
1975         return QString();
1976     return d->param(1);
1977 }
1978 
1979 /*!
1980     \property bool IrcTopicMessage::reply
1981     This property holds whether the message is a reply.
1982 
1983     Topic messages are sent in three situations:
1984     \li as a notification of a topic change (\c false),
1985     \li as a reply when joining a channel (\c true), or
1986     \li as a reply when explicitly querying the channel topic (\c true).
1987 
1988     \par Access function:
1989     \li bool <b>isReply</b>() const
1990 
1991     \sa Irc::RPL_TOPIC, Irc::RPL_NOTOPIC, IrcTopicCommand
1992  */
isReply() const1993 bool IrcTopicMessage::isReply() const
1994 {
1995     Q_D(const IrcMessage);
1996     int rpl = d->command().toInt();
1997     return rpl == Irc::RPL_TOPIC || rpl == Irc::RPL_NOTOPIC;
1998 }
1999 
isValid() const2000 bool IrcTopicMessage::isValid() const
2001 {
2002     return IrcMessage::isValid() && !channel().isEmpty();
2003 }
2004 
2005 /*!
2006     \since 3.3
2007     \class IrcWhoisMessage ircmessage.h <IrcMessage>
2008     \ingroup message
2009     \brief Represents a reply message to a WHOIS command.
2010  */
2011 
2012 /*!
2013     Constructs a new IrcWhoisMessage with \a connection.
2014  */
IrcWhoisMessage(IrcConnection * connection)2015 IrcWhoisMessage::IrcWhoisMessage(IrcConnection* connection) : IrcMessage(connection)
2016 {
2017     Q_D(IrcMessage);
2018     d->type = Whois;
2019     setCommand(QLatin1String("WHOIS"));
2020 }
2021 
2022 /*!
2023     This property holds the real name of the user.
2024 
2025     \par Access function:
2026     \li QString <b>realName</b>() const
2027  */
realName() const2028 QString IrcWhoisMessage::realName() const
2029 {
2030     Q_D(const IrcMessage);
2031     return d->param(0);
2032 }
2033 
2034 /*!
2035     This property holds the server address user is on.
2036 
2037     \par Access function:
2038     \li QString <b>server</b>() const
2039  */
server() const2040 QString IrcWhoisMessage::server() const
2041 {
2042     Q_D(const IrcMessage);
2043     return d->param(1);
2044 }
2045 
2046 /*!
2047     This property holds info of the server the user is on.
2048 
2049     \par Access function:
2050     \li QString <b>info</b>() const
2051  */
info() const2052 QString IrcWhoisMessage::info() const
2053 {
2054     Q_D(const IrcMessage);
2055     return d->param(2);
2056 }
2057 
2058 /*!
2059     This property holds the account name of the user.
2060 
2061     \par Access function:
2062     \li QString <b>account</b>() const
2063  */
account() const2064 QString IrcWhoisMessage::account() const
2065 {
2066     Q_D(const IrcMessage);
2067     return d->param(3);
2068 }
2069 
2070 /*!
2071     This property holds the address the user is connecting from.
2072 
2073     \par Access function:
2074     \li QString <b>address</b>() const
2075  */
address() const2076 QString IrcWhoisMessage::address() const
2077 {
2078     Q_D(const IrcMessage);
2079     return d->param(4);
2080 }
2081 
2082 /*!
2083     This property holds the time since user has been online.
2084 
2085     \par Access function:
2086     \li QDateTime <b>since</b>() const
2087  */
since() const2088 QDateTime IrcWhoisMessage::since() const
2089 {
2090     Q_D(const IrcMessage);
2091     return QDateTime::fromSecsSinceEpoch(d->param(5).toInt());
2092 }
2093 
2094 /*!
2095     This property holds the number of seconds the user has been idle.
2096 
2097     \par Access function:
2098     \li int <b>idle</b>() const
2099  */
idle() const2100 int IrcWhoisMessage::idle() const
2101 {
2102     Q_D(const IrcMessage);
2103     return d->param(6).toInt();
2104 }
2105 
2106 /*!
2107     \property bool IrcWhoisMessage::secure
2108     This property holds whether the user is using a secure connection.
2109 
2110     \par Access function:
2111     \li bool <b>isSecure</b>() const
2112  */
isSecure() const2113 bool IrcWhoisMessage::isSecure() const
2114 {
2115     Q_D(const IrcMessage);
2116     return !d->param(7).isEmpty();
2117 }
2118 
2119 /*!
2120     This property holds the visible list of channels of the user.
2121 
2122     \par Access function:
2123     \li QStringList <b>channels</b>() const
2124  */
channels() const2125 QStringList IrcWhoisMessage::channels() const
2126 {
2127     Q_D(const IrcMessage);
2128     return d->params().value(8).split(QLatin1Char(' '), Qt::SkipEmptyParts);
2129 }
2130 
2131 /*!
2132     \since 3.5
2133 
2134     This property holds the away reason of the user.
2135 
2136     \par Access function:
2137     \li QString <b>awayReason</b>() const
2138  */
awayReason() const2139 QString IrcWhoisMessage::awayReason() const
2140 {
2141     Q_D(const IrcMessage);
2142     return d->param(9);
2143 }
2144 
isValid() const2145 bool IrcWhoisMessage::isValid() const
2146 {
2147     Q_D(const IrcMessage);
2148     return IrcMessage::isValid() && d->params().count() == 10;
2149 }
2150 
2151 /*!
2152     \since 3.3
2153     \class IrcWhowasMessage ircmessage.h <IrcMessage>
2154     \ingroup message
2155     \brief Represents a reply message to a WHOWAS command.
2156  */
2157 
2158 /*!
2159     Constructs a new IrcWhowasMessage with \a connection.
2160  */
IrcWhowasMessage(IrcConnection * connection)2161 IrcWhowasMessage::IrcWhowasMessage(IrcConnection* connection) : IrcMessage(connection)
2162 {
2163     Q_D(IrcMessage);
2164     d->type = Whowas;
2165     setCommand(QLatin1String("WHOWAS"));
2166 }
2167 
2168 /*!
2169     This property holds the real name of the user.
2170 
2171     \par Access function:
2172     \li QString <b>realName</b>() const
2173  */
realName() const2174 QString IrcWhowasMessage::realName() const
2175 {
2176     Q_D(const IrcMessage);
2177     return d->param(0);
2178 }
2179 
2180 /*!
2181     This property holds the server address user was on.
2182 
2183     \par Access function:
2184     \li QString <b>server</b>() const
2185  */
server() const2186 QString IrcWhowasMessage::server() const
2187 {
2188     Q_D(const IrcMessage);
2189     return d->param(1);
2190 }
2191 
2192 /*!
2193     This property holds info of the server the user was on.
2194 
2195     \par Access function:
2196     \li QString <b>info</b>() const
2197  */
info() const2198 QString IrcWhowasMessage::info() const
2199 {
2200     Q_D(const IrcMessage);
2201     return d->param(2);
2202 }
2203 
2204 /*!
2205     This property holds the account of the user.
2206 
2207     \par Access function:
2208     \li QString <b>account</b>() const
2209  */
account() const2210 QString IrcWhowasMessage::account() const
2211 {
2212     Q_D(const IrcMessage);
2213     return d->param(3);
2214 }
2215 
isValid() const2216 bool IrcWhowasMessage::isValid() const
2217 {
2218     Q_D(const IrcMessage);
2219     return IrcMessage::isValid() && d->params().count() == 9;
2220 }
2221 
2222 /*!
2223     \since 3.1
2224     \class IrcWhoReplyMessage ircmessage.h <IrcMessage>
2225     \ingroup message
2226     \brief Represents a reply message to a WHO command.
2227  */
2228 
2229 /*!
2230     Constructs a new IrcWhoReplyMessage with \a connection.
2231  */
IrcWhoReplyMessage(IrcConnection * connection)2232 IrcWhoReplyMessage::IrcWhoReplyMessage(IrcConnection* connection) : IrcMessage(connection)
2233 {
2234     Q_D(IrcMessage);
2235     d->type = WhoReply;
2236 }
2237 
2238 /*!
2239     This property holds the mask.
2240 
2241     \par Access function:
2242     \li QString <b>mask</b>() const
2243  */
mask() const2244 QString IrcWhoReplyMessage::mask() const
2245 {
2246     Q_D(const IrcMessage);
2247     return d->param(0);
2248 }
2249 
2250 /*!
2251     This property holds the server of the user.
2252 
2253     \par Access function:
2254     \li QString <b>server</b>() const
2255  */
server() const2256 QString IrcWhoReplyMessage::server() const
2257 {
2258     Q_D(const IrcMessage);
2259     return d->param(1);
2260 }
2261 
2262 /*!
2263     \property bool IrcWhoReplyMessage::away
2264     This property holds whether the user is away.
2265 
2266     \par Access function:
2267     \li QString <b>isAway</b>() const
2268  */
isAway() const2269 bool IrcWhoReplyMessage::isAway() const
2270 {
2271     Q_D(const IrcMessage);
2272     return d->param(2).contains("G");
2273 }
2274 
2275 /*!
2276     \property bool IrcWhoReplyMessage::servOp
2277     This property holds whether the user is a server operator.
2278 
2279     \par Access function:
2280     \li QString <b>isServOp</b>() const
2281  */
isServOp() const2282 bool IrcWhoReplyMessage::isServOp() const
2283 {
2284     Q_D(const IrcMessage);
2285     return d->param(2).contains("*");
2286 }
2287 
2288 /*!
2289     This property holds the real name of the user.
2290 
2291     \par Access function:
2292     \li QString <b>realName</b>() const
2293  */
realName() const2294 QString IrcWhoReplyMessage::realName() const
2295 {
2296     Q_D(const IrcMessage);
2297     return d->param(3);
2298 }
2299 
isValid() const2300 bool IrcWhoReplyMessage::isValid() const
2301 {
2302     return IrcMessage::isValid() && !mask().isEmpty() && !nick().isEmpty();
2303 }
2304 
2305 #ifndef QT_NO_DEBUG_STREAM
operator <<(QDebug debug,IrcMessage::Type type)2306 QDebug operator<<(QDebug debug, IrcMessage::Type type)
2307 {
2308     const int index = IrcMessage::staticMetaObject.indexOfEnumerator("Type");
2309     QMetaEnum enumerator = IrcMessage::staticMetaObject.enumerator(index);
2310     const char* key = enumerator.valueToKey(type);
2311     debug << (key ? key : "Unknown");
2312     return debug;
2313 }
2314 
operator <<(QDebug debug,IrcMessage::Flag flag)2315 QDebug operator<<(QDebug debug, IrcMessage::Flag flag)
2316 {
2317     const int index = IrcMessage::staticMetaObject.indexOfEnumerator("Flag");
2318     QMetaEnum enumerator = IrcMessage::staticMetaObject.enumerator(index);
2319     const char* key = enumerator.valueToKey(flag);
2320     debug << (key ? key : "None");
2321     return debug;
2322 }
2323 
operator <<(QDebug debug,IrcMessage::Flags flags)2324 QDebug operator<<(QDebug debug, IrcMessage::Flags flags)
2325 {
2326     QStringList lst;
2327     if (flags == IrcMessage::None)
2328         lst << "None";
2329     if (flags & IrcMessage::Own)
2330         lst << "Own";
2331     if (flags & IrcMessage::Playback)
2332         lst << "Playback";
2333     if (flags & IrcMessage::Implicit)
2334         lst << "Implicit";
2335     debug.nospace() << '(' << qPrintable(lst.join("|")) << ')';
2336     return debug;
2337 }
2338 
operator <<(QDebug debug,IrcModeMessage::Kind kind)2339 QDebug operator<<(QDebug debug, IrcModeMessage::Kind kind)
2340 {
2341     const int index = IrcModeMessage::staticMetaObject.indexOfEnumerator("Kind");
2342     QMetaEnum enumerator = IrcModeMessage::staticMetaObject.enumerator(index);
2343     const char* key = enumerator.valueToKey(kind);
2344     debug << (key ? key : "Unknown");
2345     return debug;
2346 }
2347 
operator <<(QDebug debug,const IrcMessage * message)2348 QDebug operator<<(QDebug debug, const IrcMessage* message)
2349 {
2350     if (!message)
2351         return debug << "IrcMessage(0x0) ";
2352     debug.nospace() << message->metaObject()->className() << '(' << (void*) message;
2353     if (!message->objectName().isEmpty())
2354         debug.nospace() << ", name=" << qPrintable(message->objectName());
2355     debug.nospace() << ", flags=" << message->flags();
2356     if (!message->prefix().isEmpty())
2357         debug.nospace() << ", prefix=" << qPrintable(message->prefix());
2358     if (!message->command().isEmpty())
2359         debug.nospace() << ", command=" << qPrintable(message->command());
2360     debug.nospace() << ')';
2361     return debug.space();
2362 }
2363 #endif // QT_NO_DEBUG_STREAM
2364 
2365 #include "moc_ircmessage.cpp"
2366 
2367 IRC_END_NAMESPACE
2368