1/*
2 * LegacyClonk
3 *
4 * Copyright (c) RedWolf Design
5 * Copyright (c) 2017-2020, The LegacyClonk Team and contributors
6 *
7 * Distributed under the terms of the ISC license; see accompanying file
8 * "COPYING" for details.
9 *
10 * "Clonk" is a registered trademark of Matthes Bender, used with permission.
11 * See accompanying file "TRADEMARK" for details.
12 *
13 * To redistribute this file separately, substitute the full license texts
14 * for the above references.
15 */
16
17#pragma once
18
19#include "C4NetIO.h"
20
21enum C4Network2IRCMessageType
22{
23 MSG_Server,
24 MSG_Status,
25 MSG_Message,
26 MSG_Notice,
27 MSG_Action,
28};
29
30const int C4NetIRCMaxLogLength = 300000; // Maximum total length of log - if log gets longer, it will be cleared even if messages have never been read
31const int C4NetIRCMaxReadLogLength = 1000; // Maximum log messages kept even after they've been read
32
33class C4Network2IRCMessage
34{
35 friend class C4Network2IRCClient;
36
37public:
38 C4Network2IRCMessage(C4Network2IRCMessageType enType, const char *szSource, const char *szTarget, const char *szData)
39 : eType(enType), Source(szSource), Target(szTarget), Data(szData),
40 iTimestamp(time(timer: nullptr)), Next(nullptr) {}
41
42private:
43 time_t iTimestamp;
44 C4Network2IRCMessageType eType;
45 StdStrBuf Source, Target, Data;
46
47 // used by C4Network2IRCClient
48 C4Network2IRCMessage *Next;
49
50public:
51 time_t getTimestamp() const { return iTimestamp; }
52 C4Network2IRCMessageType getType() const { return eType; }
53 const char *getSource() const { return Source.getData(); }
54 const char *getTarget() const { return Target.getData(); }
55 const char *getData() const { return Data.getData(); }
56 bool isChannel() const { return Target.getLength() && (*Target.getData() == '#' || *Target.getData() == '+'); }
57
58 C4Network2IRCMessage *getNext() const { return Next; }
59};
60
61class C4Network2IRCUser
62{
63 friend class C4Network2IRCChannel;
64
65public:
66 C4Network2IRCUser(const char *szName);
67
68private:
69 StdStrBuf Prefix;
70 StdStrBuf Name;
71
72 // used by C4Network2IRCChannel
73 C4Network2IRCUser *Next;
74
75public:
76 const char *getPrefix() const { return Prefix.getData(); }
77 const char *getName() const { return Name.getData(); }
78 C4Network2IRCUser *getNext() const { return Next; }
79
80private:
81 // called by C4Network2IRCChannel
82 void SetPrefix(const char *szPrefix) { Prefix = szPrefix; }
83};
84
85class C4Network2IRCChannel
86{
87 friend class C4Network2IRCClient;
88
89public:
90 C4Network2IRCChannel(const char *szName);
91 ~C4Network2IRCChannel();
92
93private:
94 StdStrBuf Name;
95 StdStrBuf Topic;
96 C4Network2IRCUser *pUsers;
97
98 bool fReceivingUsers;
99
100 // used by C4Network2IRCClient
101 C4Network2IRCChannel *Next;
102
103public:
104 const char *getName() const { return Name.getData(); }
105 const char *getTopic() const { return Topic.getData(); }
106 C4Network2IRCUser *getUsers() const { return pUsers; }
107 C4Network2IRCUser *getUser(const char *szName) const;
108 bool isUsersLocked() const { return fReceivingUsers; }
109
110private:
111 // called by C4Network2IRCClient
112 void OnUsers(const char *szUsers, const char *szPrefixes);
113 void OnUsersEnd();
114 void OnJoin(const char *szUser);
115 void OnPart(const char *szUser, const char *szComment);
116 void OnKick(const char *szUser, const char *szComment);
117 void OnTopic(const char *szTopic);
118
119 C4Network2IRCUser *AddUser(const char *szName);
120 void DeleteUser(C4Network2IRCUser *pUser);
121 void ClearUsers();
122};
123
124class C4Network2IRCClient : public C4NetIOTCP, private C4NetIO::CBClass
125{
126public:
127 C4Network2IRCClient();
128 ~C4Network2IRCClient();
129
130private:
131 // Connection information
132 C4NetIO::addr_t ServerAddr, PeerAddr;
133 bool fConnecting, fConnected;
134
135 // Status information
136 StdStrBuf Nick, RealName, Password;
137 StdStrBuf AutoJoin;
138 C4Network2IRCChannel *pChannels;
139
140 // User mode/prefix map
141 StdStrBuf Prefixes;
142
143 // Message log
144 C4Network2IRCMessage *pLog, *pLogLastRead, *pLogEnd;
145 int32_t iLogLength, iUnreadLogLength;
146
147 // Event queue for notify
148 class C4InteractiveThread *pNotify;
149
150 // Critical section for data
151 CStdCSec CSec;
152
153private:
154 // Overridden
155 virtual void PackPacket(const C4NetIOPacket &rPacket, StdBuf &rOutBuf) override;
156 virtual size_t UnpackPacket(const StdBuf &rInBuf, const C4NetIO::addr_t &addr) override;
157
158 // Callbacks
159 bool OnConn(const C4NetIO::addr_t &AddrPeer, const C4NetIO::addr_t &AddrConnect, const addr_t *pOwnAddr, C4NetIO *pNetIO) override;
160 void OnDisconn(const C4NetIO::addr_t &AddrPeer, C4NetIO *pNetIO, const char *szReason) override;
161 void OnPacket(const class C4NetIOPacket &rPacket, C4NetIO *pNetIO) override;
162
163public:
164 CStdCSec *getCSec() { return &CSec; }
165
166 // only call these while holding a lock on the above critical section!
167 C4Network2IRCChannel *getFirstChannel() const;
168 C4Network2IRCChannel *getNextChannel(C4Network2IRCChannel *pPrevChan) const;
169 C4Network2IRCChannel *getChannel(const char *szName) const;
170 C4Network2IRCMessage *getMessageLog() const { return pLog; }
171 C4Network2IRCMessage *getUnreadMessageLog() const { return pLogLastRead ? pLogLastRead->getNext() : pLog; }
172 void ClearMessageLog();
173 void MarkMessageLogRead();
174 const char *getUserName() const { return Nick.getData(); }
175
176 // Simple network communication
177 bool Connect(const char *szServer, const char *szNick, const char *szRealName, const char *szPassword = nullptr, const char *szChannel = nullptr);
178 bool Close() override;
179 bool Send(const char *szCommand, const char *szParameters = nullptr);
180
181 // Notfiy interface
182 void SetNotify(class C4InteractiveThread *pnNotify) { pNotify = pnNotify; }
183
184 // Special IRC commands
185 bool Quit(const char *szReason);
186 bool Join(const char *szChannel);
187 bool Part(const char *szChannel);
188 bool Message(const char *szTarget, const char *szText);
189 bool Notice(const char *szTarget, const char *szText);
190 bool Action(const char *szTarget, const char *szText);
191 bool ChangeNick(const char *szNewNick);
192
193 // Status
194 bool IsActive() const { return fConnecting || fConnected; }
195 bool IsConnected() const { return fConnected; }
196
197private:
198 void OnCommand(const char *szSender, const char *szCommand, const char *szParameters);
199 void OnNumericCommand(const char *szSender, int iCommand, const char *szParameters);
200 void OnConnected();
201 void OnMessage(bool fNotice, const char *szSource, const char *szTarget, const char *szText);
202
203 void PopMessage();
204 void PushMessage(C4Network2IRCMessageType eType, const char *szSource, const char *szTarget, const char *szText);
205
206 C4Network2IRCChannel *AddChannel(const char *szName);
207 void DeleteChannel(C4Network2IRCChannel *pChannel);
208};
209