1 /*
2     SPDX-License-Identifier: GPL-2.0-or-later
3 
4     SPDX-FileCopyrightText: 2002 Dario Abatianni <eisfuchs@tigress.com>
5     SPDX-FileCopyrightText: 2005 Ismail Donmez <ismail@kde.org>
6     SPDX-FileCopyrightText: 2005-2016 Peter Simonsson <peter.simonsson@gmail.com>
7     SPDX-FileCopyrightText: 2006-2008 Eli J. MacKenzie <argonel at gmail.com>
8     SPDX-FileCopyrightText: 2005-2008 Eike Hein <hein@kde.org>
9 */
10 
11 #ifndef SERVER_H
12 #define SERVER_H
13 
14 #include "common.h"
15 #include "channelnick.h"
16 #include "inputfilter.h"
17 #include "outputfilter.h"
18 #include "nickinfo.h"
19 #include "serversettings.h"
20 #include "servergroupsettings.h"
21 #include "connectionsettings.h"
22 #include "statuspanel.h"
23 #include "invitedialog.h"
24 #include <config-konversation.h>
25 
26 #ifdef HAVE_QCA2
27 #include "cipher.h"
28 #endif
29 
30 #include <QElapsedTimer>
31 #include <QTimer>
32 #include <QPointer>
33 
34 #include <QHostInfo>
35 #include <QSslSocket>
36 
37 #include <QExplicitlySharedDataPointer>
38 #include <KProcess>
39 #include <preferences.h>
40 
41 class QAbstractItemModel;
42 class QStringListModel;
43 class Channel;
44 class Query;
45 class Identity;
46 class RawLog;
47 class ChannelListPanel;
48 class ServerISON;
49 class ChatWindow;
50 class ViewContainer;
51 
52 class IRCQueue;
53 
54 namespace Konversation
55 {
56     namespace DCC
57     {
58         class Transfer;
59         class Chat;
60     }
61 }
62 
63 class Server : public QObject
64 {
65     Q_OBJECT
66     friend class IRCQueue;
67     friend class QueueTuner;
68     friend class ViewContainer;
69 
70     public:
71         enum QueuePriority
72         {
73             LowPriority,      ///<slow queue, for automatic info gathering
74             StandardPriority, ///<regular queue, for chat and user initiated commands
75             HighPriority,     ///<for pongs and quits
76 
77             _QueueListSize,
78 
79             HiPriority=HighPriority,
80             LoPriority=LowPriority,
81             NormalPriorty=StandardPriority,
82             RegularPriority=StandardPriority
83         };
84 
85         enum CapModifier {
86             NoModifiers = 0x0,
87             DisMod = 0x1,
88             StickyMod = 0x2,
89             AckMod = 0x4
90         };
91         Q_DECLARE_FLAGS(CapModifiers, CapModifier)
92 
93         enum CapabilityFlag {
94             NoCapabilies = 0x00,
95             AwayNotify = 0x01,
96             ExtendedJoin = 0x02,
97             WHOX = 0x04,
98             ServerTime = 0x08,
99             UserHostInNames = 0x10,
100             SASL = 0x20,
101             MultiPrefix = 0x40,
102             AccountNotify = 0x80,
103             SelfMessage = 0x100,
104             ChgHost = 0x200,
105             CapNofify = 0x400,
106         };
107         Q_DECLARE_FLAGS(CapabilityFlags, CapabilityFlag)
108 
109         Server(QObject* parent, ConnectionSettings& settings);
110         ~Server() override;
111 
112         void cycle();
abortScheduledRecreation()113         void abortScheduledRecreation() { m_recreationScheduled = false; }
114 
connectionId()115         int connectionId() const { return m_connectionId; }
116 
getConnectionSettings()117         ConnectionSettings& getConnectionSettings() { return m_connectionSettings; }
getConnectionSettings()118         const ConnectionSettings& getConnectionSettings() const { return m_connectionSettings; }
setConnectionSettings(ConnectionSettings & settings)119         void setConnectionSettings(ConnectionSettings& settings) { m_connectionSettings = settings; }
120 
getDisplayName()121         QString getDisplayName() const { return m_connectionSettings.name(); }
getServerName()122         QString getServerName() const { return m_connectionSettings.server().host(); }
123 
getServerGroup()124         Konversation::ServerGroupSettingsPtr getServerGroup() const { return m_connectionSettings.serverGroup(); }
getIdentity()125         IdentityPtr getIdentity() const { return m_connectionSettings.identity(); }
126 
getConnectionState()127         Konversation::ConnectionState getConnectionState() const { return m_connectionState; }
128 
isConnected()129         bool isConnected() const { return (m_connectionState == Konversation::SSConnected); }
isConnecting()130         bool isConnecting() const { return (m_connectionState == Konversation::SSConnecting); }
isScheduledToConnect()131         bool isScheduledToConnect() const { return (m_connectionState == Konversation::SSScheduledToConnect); }
132 
133         bool getUseSSL() const;
134         QString getSSLInfo() const;
135         int getPort() const;
136         int getLag() const;
137 
138         void updateAutoJoin(Konversation::ChannelList channels = Konversation::ChannelList());
139 
140         /**
141          * Generates the JOIN commands for the given channel list.
142          * This takes care of splitting too long commands into mutliple ones and
143          * filtering out invalid channels (because they are not prefixed with any of the
144          * CHANTYPES).
145          *
146          * @param tmpList The list of channels for which the JOIN command(s) will be generated.
147          * @return A list of QStrings with the JOIN commands.
148          */
149         QStringList generateJoinCommand(const Konversation::ChannelList &tmpList);
150 
151         QAbstractItemModel* nickListModel() const;
152         void resetNickSelection();
153         void queueNicks(const QString& channelName, const QStringList& nicknameList);
154         void addHostmaskToNick(const QString &sourceNick, const QString &sourceHostmask);
155         Channel* nickJoinsChannel(const QString &channelName, const QString &nickname, const QString &hostmask, const QString &account,
156                                   const QString &realName, const QHash<QString, QString> &messageTags);
157         void renameNick(const QString &nickname, const QString &newNick, const QHash<QString, QString> &messageTags);
158         Channel* removeNickFromChannel(const QString &channelName, const QString &nickname, const QString &reason, const QHash<QString, QString> &messageTags, bool quit=false);
159         void nickWasKickedFromChannel(const QString &channelName, const QString &nickname, const QString &kicker, const QString &reason, const QHash<QString, QString> &messageTags);
160         void removeNickFromServer(const QString &nickname, const QString &reason, const QHash<QString, QString> &messageTags);
161 
162         void setChannelTypes(const QString &types);
163         QString getChannelTypes() const;
164 
165         void setModesCount(int count);
166         int getModesCount() const;
167 
168         // extended user modes support
169         void setChanModes(const QString&);                 //grab modes types from RPL_ISUPPORT CHANMODES
banAddressListModes()170         QString banAddressListModes() const { return m_banAddressListModes; }     // aka "TYPE A" modes https://tools.ietf.org/html/draft-brocklesby-irc-isupport-03#section-3.3
171 
172         void setPrefixes(const QString &modes, const QString& prefixes);
173         QString getServerNickPrefixes() const;
174 
175         void mangleNicknameWithModes(QString &nickname,bool& isAdmin,bool& isOwner,bool &isOp,
176             bool& isHalfop,bool &hasVoice);
177 
178         bool isAChannel(const QString &channel) const;
179         bool isNickname(const QString& compare) const;
180 
181         QString getNickname() const;
182         QString loweredNickname() const;
183 
184         QString getNextNickname();
185 
getInputFilter()186         InputFilter* getInputFilter() { return &m_inputFilter; }
getOutputFilter()187         Konversation::OutputFilter* getOutputFilter() const { return m_outputFilter; }
188 
189         Channel* joinChannel(const QString& name, const QString& hostmask, const QHash<QString, QString> &messageTags);
190         void removeChannel(Channel* channel);
191         void appendServerMessageToChannel(const QString& channel, const QString& type, const QString& message, const QHash<QString, QString> &messageTags);
192         void appendCommandMessageToChannel(const QString& channel, const QString& command, const QString& message, const QHash<QString, QString> &messageTags,
193                                            bool highlight = true, bool parseURL = true);
194         void appendStatusMessage(const QString& type,const QString& message, const QHash<QString, QString> &messageTags);
195         void appendMessageToFrontmost(const QString& type,const QString& message, const QHash<QString, QString> &messageTags = QHash<QString, QString>(), bool parseURL = true);
196 
197         int getPreLength(const QString& command, const QString& dest) const;
198 
199         void dbusRaw(const QString& command);
200         void dbusSay(const QString& target,const QString& command);
201         void dbusInfo(const QString& string);
202         void ctcpReply(const QString& receiver, const QString& text);
203 
204         void setChannelTopic(const QString& channel, const QString& topic, const QHash<QString, QString> &messageTags);
205                                                   // Overloaded
206         void setChannelTopic(const QString& nickname, const QString& channel, const QString& topic, const QHash<QString, QString> &messageTags);
207         void updateChannelMode(const QString& nick, const QString& channel, char mode, bool plus, const QString& parameter, const QHash<QString, QString> &messageTags);
208         void updateChannelModeWidgets(const QString& channel, char mode, const QString& parameter);
209 
210         Channel* getChannelByName(const QString& name) const;
211         Query* getQueryByName(const QString& name) const;
212         ChatWindow* getChannelOrQueryByName(const QString& name) const;
213         QString parseWildcards(const QString& toParse, ChatWindow* context = nullptr, const QStringList &nicks = QStringList());
214         QString parseWildcards(const QString& toParse, const QString& nickname, const QString& channelName, const QString &channelKey, const QStringList &nickList, const QString& inputLineText);
215         QString parseWildcards(const QString& toParse, const QString& nickname, const QString& channelName, const QString &channelKey, const QString& nick, const QString& inputLineText);
216 
217         void autoCommandsAndChannels();
218 
219         void sendURIs(const QList<QUrl>& uris, const QString& nick);
220 
221         void notifyAction(const QString& nick);
222         ChannelListPanel* getChannelListPanel() const;
223 
getStatusView()224         StatusPanel* getStatusView() const { return m_statusView; }
225         virtual bool closeYourself(bool askForConfirmation=true);
226 
227         QString getOwnIpByNetworkInterface() const;
228         QString getOwnIpByServerMessage() const;
229 
isAway()230         bool isAway() const { return m_away; }
231         void setAway(bool away, const QHash<QString, QString> &messageTags);
232         QString awayTime() const;
233 
setAwayReason(const QString & reason)234         void setAwayReason(const QString& reason) { m_awayReason = reason; }
235 
236         /**
237          * Returns true if the given nickname is known to be online.
238          * @param nickname      The nickname.  Case insensitive.
239          * @return              True if the nickname is known to be online by the server.
240          * Note that a nick that is not in any of the joined channels and is not on the
241          * notify list, and has not initiated a query with you, may well be online,
242          * but server doesn't know if it is or not, in which case False is returned.
243          */
244         bool isNickOnline(const QString &nickname) const;
245         /** Given a nickname, returns NickInfo object.
246          *  @param nickname    The desired nickname.  Case insensitive.
247          *  @return            Pointer to the nickinfo for this nickname if one exists.
248          *                     0 if not known to be online.
249          *
250          *  A NickInfo pointer will only be returned if the nickname is known to the Konvi
251          *  Server object.  A nick will be known if:
252          *  - It is in one of the server's channels user has joined.
253          *  - It is on the notify list and is known to be online.
254          *  - The nick initiated a query with the user.
255          *  A NickInfo is destroyed when it is offline.
256          */
257         NickInfoPtr getNickInfo(const QString& nickname) const;
258         /** Given a nickname, returns an existing NickInfo object, or creates a new NickInfo object.
259          *  Guaranteed to return a nickinfo.
260          *  @param nickname    The desired nickname.  Case sensitive.
261          *  @return            Pointer to the found or created NickInfo object.
262          */
263         NickInfoPtr obtainNickInfo(const QString& nickname);
264         /** Returns a list of all the NickInfos that are online and known to the server.
265          * Caller should not modify the list.
266          * A nick will be known if:
267          *  - It is in one of the server's channels user has joined.
268          *  - It is on the notify list and is known to be online.
269          *  - The nick initiated a query with the user.
270          *
271          * @return A QMap of NickInfoPtrs indexed by lowercase nickname.
272          */
273         const NickInfoMap* getAllNicks() const;
274         /** Returns the list of members for a channel in the joinedChannels list.
275          *  A joinedChannel is one that you are in, as opposed to a channel that you aren't in,
276          *  but one of your watched nicks is in.
277          *  Code that calls this must not modify the list.
278          *  @param channelName Name of desired channel.  Case insensitive.
279          *  @return            A map of all the nicks in the channel.
280          *                     0 if channel is not in the joinedChannels list.
281          */
282         const ChannelNickMap *getJoinedChannelMembers(const QString& channelName) const;
283         /** Returns the list of members for a channel in the unjoinedChannels list.
284          *  An unjoinedChannel is a channel you aren't in.  As such, this is only going to return
285          *  nicks that you know are in that channel because a /whois has been done against them.
286          *  This could be done automatically if they are on the watch list.
287          *  Code that calls this must not modify the list.
288          *  @param channelName Name of desired channel.  Case insensitive.
289          *  @return            A map of only the nicks that we know that are in the channel.
290          *                     0 if channel is not in the unjoinedChannels list.
291          */
292         const ChannelNickMap *getUnjoinedChannelMembers(const QString& channelName) const;
293         /** Searches the Joined and Unjoined lists for the given channel and returns the member list.
294          *  Code that calls this must not modify the list.
295          *  @param channelName Name of desired channel.  Case insensitive.
296          *  @return            A map of nicks in that channel.  0 if channel is not in either list.
297          *
298          *  @see getJoinedChannelMembers(const QString& channelName)
299          *  @see getUnjoinedChannelMembers(const QString& channelName)
300          */
301         const ChannelNickMap *getChannelMembers(const QString& channelName) const;
302         /** Returns a list of all the joined channels that a nick is in.
303          *  @param nickname    The desired nickname.  Case insensitive.
304          *  @return            A list of joined channels the nick is in.  Empty if none.
305          */
306         QStringList getNickJoinedChannels(const QString& nickname) const;
307         /** Returns a list of all the channels (joined or unjoined) that a nick is in.
308          *  @param nickname    The desired nickname.  Case insensitive.
309          *  @return            A list of channels the nick is in.  Empty if none.
310          *
311          *  A nick will not appear in the Unjoined channels list unless a WHOIS
312          *  has been performed on it.
313          */
314         QStringList getNickChannels(const QString& nickname) const;
315         /** Returns a list of all the channels we're in that nickname is also in.
316          *  @param nickname    The desired nickname.  Case insensitive.
317          *  @return            A list of channels the nick is in that we're also in.  Empty if none.
318          */
319         QStringList getSharedChannels(const QString& nickname) const;
320         /** Returns pointer to the ChannelNick (mode and pointer to NickInfo) for a
321          *  given channel and nickname.
322          *  @param channelName The desired channel name.  Case insensitive.
323          *  @param nickname    The desired nickname.  Case insensitive.
324          *  @return            Pointer to ChannelNick structure containing a pointer
325          *                     to the NickInfo and the mode of the nick in the channel.
326          *                     0 if not found.
327          */
328         ChannelNickPtr getChannelNick(const QString& channelName, const QString& nickname) const;
329         /** Updates a nickname in a channel.  If not on the joined or unjoined lists, and nick
330          *  is in the watch list, adds the channel and nick to the unjoinedChannels list.
331          *  If mode != 99, sets the mode for the nick in the channel.
332          *  Returns the NickInfo object if nick is on any lists, otherwise 0.
333          *  @param channelName The channel name.  Case sensitive.
334          *  @param nickname    The nickname.  Case sensitive.
335          *  @param mode        Bit mask containing the modes the nick has in the channel,
336          *                     or 99 if not known.  See channelnick.cpp for bit definitions.
337          */
338         ChannelNickPtr setChannelNick(const QString& channelName, const QString& nickname, unsigned int mode = 99);
339 
340         /**
341          * Returns a QList of all channels
342          */
getChannelList()343         const QList<Channel *>& getChannelList() const { return m_channelList; }
344 
345         /**
346          * Returns a lower case list of all the nicks on the user watch list.
347          */
348         QStringList getWatchList() const;
349         /**
350          * Return true if the given nickname is on the watch list.
351          */
352         bool isWatchedNick(const QString& nickname) const;
353         /**
354          * Returns a list of all the nicks on the watch list that are not in joined
355          * channels.  ISON command is sent for these nicks.
356          */
357         QStringList getISONList() const;
358         QString getISONListString() const;
359 
360         ViewContainer* getViewContainer() const;
361 
362         /** Adds a nickname to the joinedChannels list.
363          *  Creates new NickInfo if necessary.
364          *  If needed, moves the channel from the unjoined list to the joined list.
365          *  If needed, moves the nickname from the Offline to Online lists.
366          *  If mode != 99 sets the mode for this nick in this channel.
367          *  @param channelName The channel name.  Case sensitive.
368          *  @param nickname    The nickname.  Case sensitive.
369          *  @return            The NickInfo for the nickname.
370          */
371         ChannelNickPtr addNickToJoinedChannelsList(const QString& channelName, const QString& nickname);
372 
setAllowedChannelModes(const QString & modes)373         void setAllowedChannelModes(const QString& modes) { m_allowedChannelModes = modes; }
allowedChannelModes()374         QString allowedChannelModes() const { return m_allowedChannelModes; }
375 
setTopicLength(int topicLength)376         void setTopicLength(int topicLength) { m_topicLength = topicLength; }
topicLength()377         int topicLength() const { return m_topicLength; }
378 
379         void registerWithServices();
380 
381         // Blowfish stuff
382         QByteArray getKeyForRecipient(const QString& recipient) const;
383         void setKeyForRecipient(const QString& recipient, const QByteArray& key);
384 
identifyMsg()385         bool identifyMsg() const { return m_identifyMsg; }
getLastAuthenticateCommand()386         QString getLastAuthenticateCommand() const { return m_lastAuthenticateCommand; }
387 
388         ChannelListPanel* addChannelListPanel();
389 
390         // invoked by DCC::TransferSend
391         void dccSendRequest(const QString& recipient,const QString& fileName,const QString& address,quint16 port,quint64 size);
392         void dccPassiveSendRequest(const QString& recipient,const QString& fileName,const QString& address,quint64 size,const QString& token);
393         // invoked by DCC::TransferRecv
394         void dccPassiveResumeGetRequest(const QString& sender,const QString& fileName,quint16 port,KIO::filesize_t startAt,const QString &token);
395         void dccResumeGetRequest(const QString& sender,const QString& fileName,quint16 port,KIO::filesize_t startAt);
396         void dccReverseSendAck(const QString& partnerNick,const QString& fileName,const QString& ownAddress,quint16 ownPort,quint64 size,const QString& reverseToken);
397         void dccRejectSend(const QString& partnerNick, const QString& fileName);
398         // invoked by DCC::Chat
399         void dccRejectChat(const QString& partnerNick, const QString& extension);
400         void dccPassiveChatRequest(const QString& recipient, const QString& extension, const QString& address, const QString& token);
401         void dccReverseChatAck(const QString& partnerNick, const QString& extension, const QString& ownAddress, quint16 ownPort, const QString& reverseToken);
402 
capEndDelayed()403         bool capEndDelayed() const { return m_capEndDelayed; }
404 
setHasWHOX(bool state)405         void setHasWHOX(bool state) { m_capabilities.setFlag(WHOX, state); }
capabilities()406         CapabilityFlags capabilities() const { return m_capabilities; }
whoRequestsDisabled()407         bool whoRequestsDisabled() const { return m_whoRequestsDisabled; }
408 
409     // IRCQueueManager
410         bool validQueue(QueuePriority priority); ///< is this queue index valid?
411         void resetQueues(); ///< Tell all of the queues to reset
412 
413         /** Forces the queued data to be sent in sequence of age, without pause.
414 
415             This could flood you off but since you're quitting, we probably don't care. This is done
416             here instead of in the queues themselves so we can interleave the queues without having to
417             zip the queues together. If you want to quit the server normally without sending, reset the queues
418             first.
419          */
420         void flushQueues();
421 
422         //These are really only here to limit where ircqueue.h is included
423 
424     Q_SIGNALS:
425         void destroyed(int connectionId);
426         void nicknameChanged(const QString&);
427         void serverLag(Server* server,int msec);  /// will be connected to KonversationMainWindow::updateLag()
428         void tooLongLag(Server* server, int msec);/// will be connected to KonversationMainWindow::updateLag()
429         void resetLag(Server* server); ///< will be emitted when new 303 came in
430         void nicksNowOnline(Server* server,const QStringList& list,bool changed);
431         void awayState(bool away);                /// will be connected to any user input panel;
432         void multiServerCommand(const QString& command, const QString& parameter);
433 
434         /**
435          * Emitted when the server gains/loses connection.
436          * Will be connected to all server dependant tabs.
437          */
438         void serverOnline(bool state);
439 
440         /**
441          * Emitted every time something gets sent.
442          *
443          *  @param  bytes           The count of bytes sent to the server, before re-encoding.
444          *  @param  encodedBytes    The count of bytes sent to the server after re-encoding.
445          */
446         void sentStat(int bytes, int encodedBytes, IRCQueue *whichQueue);
447 
448         //Note that these signals haven't been implemented yet.
449         /// Fires when the information in a NickInfo object changes.
450         void nickInfoChanged(Server* server, const NickInfoPtr nickInfo);
451         /// Emitted once if one or more NickInfo has been changed.
452         void nickInfoChanged();
453         /// Emitted once if one or more ChannelNick has been changed in @p channel.
454         void channelNickChanged(const QString& channel);
455 
456         /// Fires when a nick leaves or joins a channel.  Based on joined flag, receiver could
457         /// call getJoinedChannelMembers or getUnjoinedChannelMembers, or just
458         /// getChannelMembers to get a list of all the nicks now in the channel.
459         /// parted indicates whether the nick joined or left the channel.
460         void channelMembersChanged(Server* server, const QString& channelName, bool joined, bool parted, const QString& nickname);
461 
462         /// Fires when a channel is moved to/from the Joinied/Unjoined lists.
463         /// joined indicates which list it is now on.  Note that if joined is False, it is
464         /// possible the channel does not exist in any list anymore.
465         void channelJoinedOrUnjoined(Server* server, const QString& channelName, bool joined);
466 
467         /// Fires when a nick on the watch list goes online or offline.
468         void watchedNickChanged(Server* server, const QString& nickname, bool online);
469         ///Fires when the user switches his state to away and has enabled "Insert Remember Line on away" in his identity.
470         void awayInsertRememberLine(Server* server);
471         void sslInitFailure();
472         void sslConnected(Server* server);
473 
474         void connectionStateChanged(Server* server, Konversation::ConnectionState state);
475 
476         void showView(ChatWindow* view);
477         void addDccPanel();
478         void addDccChat(Konversation::DCC::Chat *chat);
479 
480     public Q_SLOTS:
481         void connectToIRCServer();
482         void connectToIRCServerIn(uint delay);
483 
484         /** Adds line to queue if non-empty. */
485         bool queue(const QString& line, QueuePriority priority=StandardPriority);
486         //TODO this should be an overload, not a separate name. ambiguous cases need QString() around the cstring
487         bool queueList(const QStringList& buffer, QueuePriority priority=StandardPriority);
488 
489         void setNickname(const QString &newNickname);
490         /** This is called when we want to open a new query, or focus an existing one.
491          *  @param nickInfo The nickinfo we want to open the query to.  Must exist.
492          *  @param weinitiated This is whether we initiated this - did we do /query, or somebody else sending us a message.
493          *  @return A pointer to a new or already-existing query.  Guaranteed to be non-null
494          */
495         Query *addQuery(const NickInfoPtr & nickInfo, bool weinitiated);
496         void closeQuery(const QString &name);
497         void closeChannel(const QString &name);
498         void reconnectServer(const QString& quitMessage = QString());
499         void disconnectServer(const QString& quitMessage = QString());
500         void quitServer(const QString& quitMessage = QString());
501         void openDccChat(const QString& nickname);
502         void openDccWBoard(const QString& nickname);
503         void requestDccChat(const QString& partnerNick, const QString& extension, const QString& numericalOwnIp, quint16 ownPort);
504         void acceptDccGet(const QString& nick, const QString& file);
505         void requestBan(const QStringList& users,const QString& channel,const QString& option);
506         void requestUnban(const QString& mask,const QString& channel);
507 
508         void addDccSend(const QString &recipient, const QUrl &fileURL, bool passive = Preferences::self()->dccPassiveSend(), const QString &altFileName = QString(), quint64 fileSize = 0);
509         void removeQuery(Query *query);
510         void notifyListStarted(int serverGroupId);
511         void startNotifyTimer(int msec=0);
512         void notifyTimeout();
513         void sendJoinCommand(const QString& channelName, const QString& password = QString());
514         void requestAway(const QString& reason = QString());
515         void requestUnaway();
516         void requestChannelList();
517         void requestWhois(const QString& nickname);
518         void requestWho(const QString& channel);
519         void requestUserhost(const QString& nicks);
520         void requestTopic(const QString& channel);
521         void resolveUserhost(const QString& nickname);
522         void addRawLog(bool show);
523         void closeRawLog();
524         void addToChannelList(const QString& channel, int users, const QString& topic);
525         void closeChannelListPanel();
526         void sendMultiServerCommand(const QString& command, const QString& parameter);
527         void executeMultiServerCommand(const QString& command, const QString& parameter);
528         void showSSLDialog();
529         void sendToAllChannels(const QString& text);
530         void sendToAllChannelsAndQueries(const QString& text);
531 
532         void enableIdentifyMsg(bool enabled);
533         bool identifyMsgEnabled();
534         void addBan(const QString &channel, const QString &ban);
535         void removeBan(const QString &channel, const QString &ban);
536 
537         /// Called when we received a PONG from the server
538         void pongReceived();
539 
540         #ifdef HAVE_QCA2
541         void initKeyExchange(const QString &receiver);
542         void parseInitKeyX(const QString &sender, const QString &pubKey);
543         void parseFinishKeyX(const QString &sender, const QString &pubKey);
544         #endif
545 
546         /// Start the NickInfo changed timer if it isn't started already
547         void startNickInfoChangedTimer();
548         /// Start the ChannelNick changed timer if it isn't started already
549         void startChannelNickChangedTimer(const QString& channel);
550 
551         /// Called when the system wants to close the connection due to network going down etc.
552         void involuntaryQuit();
553         /// Will only reconnect if the connection state is involuntary disconnected.
554         void reconnectInvoluntary();
555 
556         void requestAvailableCapabilies ();
557         void capInitiateNegotiation(const QString &availableCaps);
558         void capReply();
559         void capEndNegotiation();
560         void capCheckIgnored();
561         void capAcknowledged(const QString& name, CapModifiers modifiers);
562         void capDenied(const QString& name);
563         void sendAuthenticate(const QString& message);
564         void capDel(const QString &unavailableCaps);
565 
566     private Q_SLOTS:
567         void hostFound();
568         void preShellCommandExited(int exitCode, QProcess::ExitStatus exitStatus);
569         void preShellCommandError(QProcess::ProcessError eror);
570         void socketConnected();
571         void startAwayTimer();
572         void incoming();
573         void processIncomingData();
574         /// Sends the QString to the socket. No longer has any internal concept of queueing
575         void toServer(const QString&, IRCQueue *);
576         /// Because KBufferedSocket has no closed(int) signal we use this slot to call broken(0)
577         void closed();
578         void broken(QAbstractSocket::SocketError error);
579         /** This is connected to the SSLSocket failed.
580          * @param reason The reason why this failed.  This is already translated, ready to show the user.
581          */
582         void sslError(const QList<QSslError>&);
583         void connectionEstablished(const QString& ownHost);
584         void notifyResponse(const QString& nicksOnline);
585 
586         void slotNewDccTransferItemQueued(Konversation::DCC::Transfer* transfer);
587         void startReverseDccSendTransfer(const QString& sourceNick,const QStringList& dccArguments);
588         void startReverseDccChat(const QString &sourceNick, const QStringList &dccArgument);
589         void addDccGet(const QString& sourceNick,const QStringList& dccArguments);
590         void requestDccSend();                    // -> to outputFilter, dccPanel
591                                                   // -> to outputFilter
592         void requestDccSend(const QString& recipient);
593                                                   // -> to inputFilter
594         void resumeDccGetTransfer(const QString& sourceNick,const QStringList& dccArguments);
595                                                   // -> to inputFilter
596         void resumeDccSendTransfer(const QString& sourceNick,const QStringList& dccArguments);
597         void rejectDccSendTransfer(const QString& sourceNick,const QStringList& dccArguments);
598         void dccGetDone(Konversation::DCC::Transfer* item);
599         void dccSendDone(Konversation::DCC::Transfer* item);
600         void dccStatusChanged(Konversation::DCC::Transfer* item, int newStatus, int oldStatus);
601         void addDccChat(const QString& sourceNick,const QStringList& arguments);
602         void rejectDccChat(const QString& sourceNick);
603 
604         void scriptNotFound(const QString& name);
605         void scriptExecutionError(const QString& name);
606         void userhost(const QString& nick,const QString& hostmask,bool away,bool ircOp);
607         void setTopicAuthor(const QString& channel,const QString& author, const QDateTime &t);
608         void endOfWho(const QString& target);
609         void endOfNames(const QString& target);
610         void invitation(const QString& nick,const QString& channel);
611         void gotOwnResolvedHostByWelcome(const QHostInfo& res);
612         void gotOwnResolvedHostByUserhost(const QHostInfo& res);
613 
614         /// Send a PING to the server so we can meassure the lag
615         void sendPing();
616         /// Updates GUI when the lag gets high
617         void updateLongPongLag();
618 
619         /// Update the encoding shown in the mainwindow's actions
620         void updateEncoding();
621 
622         /** Called when the NickInfo changed timer times out.
623           * Emits the nickInfoChanged() signal for all changed NickInfos
624           */
625         void sendNickInfoChangedSignals();
626         /** Called when the ChannelNick changed timer times out.
627           * Emits the channelNickChanged() signal for each channel with changed nicks.
628           */
629         void sendChannelNickChangedSignals();
630 
631         void requestOpenChannelListPanel(const QString& filter);
632 
633         /** Called in the server constructor if the preferences are set to run a command on a new server instance.
634          *  This sets up the kprocess, runs it, and connects the signals to call preShellCommandExited when done. */
635         void doPreShellCommand();
636 
637     private:
638         /// Initialize the timers
639         void initTimers();
640 
641         /// Connect to the signals used in this class.
642         void connectSignals();
643 
644         int _send_internal(QString outputline); ///< Guts of old send, isn't a slot.
645 
646         /** Adds a nickname to the unjoinedChannels list.
647          *  Creates new NickInfo if necessary.
648          *  If needed, moves the channel from the joined list to the unjoined list.
649          *  If needed, moves the nickname from the Offline to the Online list.
650          *  If mode != 99 sets the mode for this nick in this channel.
651          *  @param channelName The channel name.  Case sensitive.
652          *  @param nickname    The nickname.  Case sensitive.
653          *  @return            The NickInfo for the nickname.
654          */
655         ChannelNickPtr addNickToUnjoinedChannelsList(const QString& channelName, const QString& nickname);
656 
657         /**
658          * If not already online, changes a nick to the online state by creating
659          * a NickInfo for it and emits various signals and messages for it.
660          * This method should only be called for nicks on the watch list.
661          * @param nickname           The nickname that is online.
662          * @return                   Pointer to NickInfo for nick.
663          */
664         NickInfoPtr setWatchedNickOnline(const QString& nickname);
665 
666         /**
667         * Display offline notification for a certain nickname. The function doesn't change NickInfo objects.
668         * @param nickname           The nickname that is offline
669         * @param nickInfo           Pointer to NickInfo for nick
670         */
671         void setWatchedNickOffline(const QString& nickname, const NickInfoPtr &nickInfo);
672 
673         /**
674          * If nickname is no longer on any channel list, or the query list, delete it altogether.
675          * Call this routine only if the nick is not on the notify list or is on the notify
676          * list but is known to be offline.
677          * @param nickname           The nickname to be deleted.  Case insensitive.
678          * @return                   True if the nickname is deleted.
679          */
680         bool deleteNickIfUnlisted(const QString &nickname);
681 
682         /**
683          * If not already offline, changes a nick to the offline state.
684          * Removes it from all channels on the joined and unjoined lists.
685          * If the nick is in the watch list, and went offline, emits a signal,
686          * posts a Notify message, and posts a KNotify.
687          * If the nick goes offline, the NickInfo is deleted.
688          *
689          * @param nickname     The nickname.  Case sensitive.
690          * @return             True if the nick was online.
691          */
692         bool setNickOffline(const QString& nickname);
693 
694         /** Remove nickname from a channel (on joined or unjoined lists).
695          *  @param channelName The channel name.  Case insensitive.
696          *  @param nickname    The nickname.  Case insensitive.
697          */
698         void removeChannelNick(const QString& channelName, const QString& nickname);
699 
700         /** Remove channel from the joined list.
701          *  Nicknames in the channel are added to the unjoined list if they are in the watch list.
702          *  @param channelName The channel name.  Case insensitive.
703          */
704         void removeJoinedChannel(const QString& channelName);
705 
706         /** Renames a nickname in all NickInfo lists.
707          *  @param nickInfo    Pointer to existing NickInfo object.
708          *  @param newname     New nickname for the nick.  Case sensitive.
709          */
710         void renameNickInfo(NickInfoPtr nickInfo, const QString& newname);
711 
712         bool getAutoJoin() const;
713         void setAutoJoin(bool on);
714 
getAutoJoinCommands()715         QStringList getAutoJoinCommands() const { return m_autoJoinCommands; }
setAutoJoinCommands(const QStringList & commands)716         void setAutoJoinCommands(const QStringList& commands) { m_autoJoinCommands = commands; }
717 
718         void rebuildTargetPrefixMatcher();          ///< updates the regexp when prefixes change
719 
720         void updateConnectionState(Konversation::ConnectionState state);
721         bool isSocketConnected() const;
722 
723         void purgeData();
724 
725         /// Recovers the filename from the dccArguments list from pos 0 to size-offset-1
726         /// joining with a space and cleans the filename using cleanDccFileName.
727         /// The filename only needs to be recovered if it contains a space, in case
728         /// it does not, the cleaned string at pos 0 is returned.
729         /// "offset" states how many fixed arguments the dcc command has, where the
730         /// filename is variable. For example "filename ip port filesize", offset is 3.
731         inline QString recoverDccFileName(const QStringList& dccArguments, int offset) const;
732 
733         /// Cleans the filename from extra '"'. We just remove '"' if it is the first
734         /// and last char, if the filename really contains a '"' it comes as two chars,
735         /// escaped "\"", and is not affected.
736         /// Some clients return the filename with multiple '"' around the filename
737         /// but all we want is the plain filename.
738         inline QString cleanDccFileName(const QString& filename) const;
739 
740         /// Checks if the port is in a valid range
741         inline quint16 stringToPort(const QString &port, bool *ok = nullptr);
742 
743         /// Creates a list of known users and returns the one chosen by the user
744         inline QString recipientNick() const;
745 
746         void collectStats(int bytes, int encodedBytes);
747 
748         void initCapablityNames();
749 
750     private:
751         // constants
752         static const int BUFFER_LEN=513;
753 
754         unsigned int m_completeQueryPosition;
755         QList<int> m_nickIndices;
756         QStringList m_referenceNicklist;
757         QStringListModel* m_nickListModel;
758 
759         // TODO roll these into a QMap.
760         QString m_serverNickPrefixes;               ///< Nickname prefixes used by the server to indicate a mode
761         QString m_serverNickPrefixModes;            ///< if supplied: mode flags related to nickname prefixes
762 
763         QRegularExpression m_targetMatcher;         ///< a character set composed of m_serverNickPrefixes and m_channelPrefixes
764 
765         QString m_banAddressListModes;              // "TYPE A" modes from RPL_ISUPPORT CHANMODES=A,B,C,D
766 
767         QString m_channelPrefixes;                  // prefixes that indicate channel names. defaults to RFC1459 "#&"
768         int m_modesCount;                           // Maximum number of channel modes with parameter allowed per MODE command.
769 
770         bool m_autoJoin;
771 
772         QStringList m_autoJoinCommands;
773 
774         QSslSocket *m_socket;
775 
776         QTimer m_incomingTimer;
777         QTimer m_notifyTimer;
778         QStringList m_notifyCache;                  // List of users found with ISON
779         int m_currentLag;
780 
781         QStringList m_inputBuffer;
782         QByteArray m_lineBuffer;
783 
784         QList<IRCQueue *> m_queues;
785         // Stats used in QueueTuner
786         int m_bytesSent, m_encodedBytesSent, m_linesSent, m_bytesReceived;
787 
788         QString m_nickname;
789         QString m_loweredNickname;
790         QString m_ownIpByUserhost;                  // RPL_USERHOST
791         QString m_ownIpByWelcome;                   // RPL_WELCOME
792 
793         QList<Channel*> m_channelList;
794         QHash<QString, Channel*> m_loweredChannelNameHash;
795 
796         QList<Query*> m_queryList;
797 
798         InputFilter m_inputFilter;
799         Konversation::OutputFilter* m_outputFilter;
800 
801         QPointer<StatusPanel> m_statusView;
802         QPointer<RawLog> m_rawLog;
803         QPointer<ChannelListPanel> m_channelListPanel;
804 
805         bool m_away;
806         QString m_awayReason;
807         QString m_nonAwayNick;
808         int m_awayTime;
809 
810         Konversation::ConnectionState m_connectionState;
811 
812         KProcess m_preShellCommand;
813 
814         /// Helper object to construct ISON (notify) list.
815         ServerISON* m_serverISON;
816         /// All nicks known to this server.  Note this is NOT a list of all nicks on the server.
817         /// Any nick appearing in this list is online, but may not necessarily appear in
818         /// any of the joined or unjoined channel lists because a WHOIS has not yet been
819         /// performed on the nick.
820         NickInfoMap m_allNicks;
821         /// List of membership lists for joined channels.  A "joined" channel is a channel
822         /// that user has joined, i.e., a tab appears for the channel in the main window.
823         ChannelMembershipMap m_joinedChannels;
824         /// List of membership lists for unjoined channels.  These come from WHOIS responses.
825         /// Note that this is NOT a list of all channels on the server, just those we are
826         /// interested in because of nicks in the Nick Watch List.
827         ChannelMembershipMap m_unjoinedChannels;
828         /// List of nicks in Queries.
829         NickInfoMap m_queryNicks;
830 
831         QString m_allowedChannelModes;
832 
833         int m_topicLength;
834 
835         // Blowfish key map
836         QHash<QString, QByteArray> m_keyHash;
837 
838         bool m_identifyMsg;
839 
840         bool m_sslErrorLock;
841 
842         /// Used to lock incomingTimer while processing message.
843         bool m_processingIncoming;
844 
845         /// Measures the lag between PING and PONG
846         QElapsedTimer m_lagTime;
847         /// Updates the gui when the lag gets too high
848         QTimer m_pingResponseTimer;
849         /// Wait before sending the next PING
850         QTimer m_pingSendTimer;
851 
852         /// Previous ISON reply of the server, needed for comparison with the next reply
853         QStringList m_prevISONList;
854 
855         int m_capRequested;
856         int m_capAnswered;
857         bool m_capEndDelayed;
858         QString m_lastAuthenticateCommand;
859 
860         ConnectionSettings m_connectionSettings;
861 
862         /// Used by ConnectionManager to schedule a reconnect; stopped by /disconnect
863         /// and /quit.
864         QTimer* m_delayedConnectTimer;
865 
866         bool m_reconnectImmediately;
867 
868         static int m_availableConnectionId;
869         int m_connectionId;
870 
871         QPointer<InviteDialog> m_inviteDialog;
872 
873         QTimer* m_nickInfoChangedTimer;
874         QTimer* m_channelNickChangedTimer;
875         QStringList m_changedChannels;
876 
877         bool m_recreationScheduled;
878 
879         CapabilityFlags m_capabilities;
880         QHash<QString, CapabilityFlag> m_capabilityNames;
881 
882         bool m_whoRequestsDisabled;
883 
884         Q_DISABLE_COPY(Server)
885 };
886 
887 Q_DECLARE_OPERATORS_FOR_FLAGS(Server::CapModifiers)
888 Q_DECLARE_OPERATORS_FOR_FLAGS(Server::CapabilityFlags)
889 
890 #endif
891