]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - include/numericbuilder.h
Remove the Kiwi links from the readme.
[user/henk/code/inspircd.git] / include / numericbuilder.h
1 /*
2  * InspIRCd -- Internet Relay Chat Daemon
3  *
4  *   Copyright (C) 2018-2020 Sadie Powell <sadie@witchery.services>
5  *   Copyright (C) 2015-2016 Attila Molnar <attilamolnar@hush.com>
6  *
7  * This file is part of InspIRCd.  InspIRCd is free software: you can
8  * redistribute it and/or modify it under the terms of the GNU General Public
9  * License as published by the Free Software Foundation, version 2.
10  *
11  * This program is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
14  * details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20
21 #pragma once
22
23 namespace Numeric
24 {
25         class WriteNumericSink;
26         class WriteRemoteNumericSink;
27
28         template <char Sep, bool SendEmpty, typename Sink>
29         class GenericBuilder;
30
31         template <char Sep = ',', bool SendEmpty = false>
32         class Builder;
33
34         template <unsigned int NumStaticParams, bool SendEmpty, typename Sink>
35         class GenericParamBuilder;
36
37         template <unsigned int NumStaticParams, bool SendEmpty = false>
38         class ParamBuilder;
39 }
40
41 class Numeric::WriteNumericSink
42 {
43         LocalUser* const user;
44
45  public:
46         WriteNumericSink(LocalUser* u)
47                 : user(u)
48         {
49         }
50
51         void operator()(Numeric& numeric) const
52         {
53                 user->WriteNumeric(numeric);
54         }
55 };
56
57 class Numeric::WriteRemoteNumericSink
58 {
59         User* const user;
60
61  public:
62         WriteRemoteNumericSink(User* u)
63                 : user(u)
64         {
65         }
66
67         void operator()(Numeric& numeric) const
68         {
69                 user->WriteRemoteNumeric(numeric);
70         }
71 };
72
73 template <char Sep, bool SendEmpty, typename Sink>
74 class Numeric::GenericBuilder
75 {
76         Sink sink;
77         Numeric numeric;
78         const std::string::size_type max;
79
80         bool HasRoom(const std::string::size_type additional) const
81         {
82                 return (numeric.GetParams().back().size() + additional <= max);
83         }
84
85  public:
86         GenericBuilder(Sink s, unsigned int num, bool addparam = true, size_t additionalsize = 0)
87                 : sink(s)
88                 , numeric(num)
89                 , max(ServerInstance->Config->Limits.MaxLine - ServerInstance->Config->GetServerName().size() - additionalsize - 10)
90         {
91                 if (addparam)
92                         numeric.push(std::string());
93         }
94
95         Numeric& GetNumeric() { return numeric; }
96
97         void Add(const std::string& entry)
98         {
99                 if (!HasRoom(entry.size()))
100                         Flush();
101                 numeric.GetParams().back().append(entry).push_back(Sep);
102         }
103
104         void Add(const std::string& entry1, const std::string& entry2)
105         {
106                 if (!HasRoom(entry1.size() + entry2.size()))
107                         Flush();
108                 numeric.GetParams().back().append(entry1).append(entry2).push_back(Sep);
109         }
110
111         void Flush()
112         {
113                 std::string& data = numeric.GetParams().back();
114                 if (IsEmpty())
115                 {
116                         if (!SendEmpty)
117                                 return;
118                 }
119                 else
120                 {
121                         data.erase(data.size()-1);
122                 }
123
124                 sink(numeric);
125                 data.clear();
126         }
127
128         bool IsEmpty() const { return (numeric.GetParams().back().empty()); }
129 };
130
131 template <char Sep, bool SendEmpty>
132 class Numeric::Builder : public GenericBuilder<Sep, SendEmpty, WriteNumericSink>
133 {
134  public:
135         Builder(LocalUser* user, unsigned int num, bool addparam = true, size_t additionalsize = 0)
136                 : ::Numeric::GenericBuilder<Sep, SendEmpty, WriteNumericSink>(WriteNumericSink(user), num, addparam, additionalsize + user->nick.size())
137         {
138         }
139 };
140
141 template <unsigned int NumStaticParams, bool SendEmpty, typename Sink>
142 class Numeric::GenericParamBuilder
143 {
144         Sink sink;
145         Numeric numeric;
146         std::string::size_type currlen;
147         std::string::size_type max;
148
149         bool HasRoom(const std::string::size_type additional) const
150         {
151                 return (currlen + additional <= max);
152         }
153
154  public:
155         GenericParamBuilder(Sink s, unsigned int num, size_t additionalsize)
156                 : sink(s)
157                 , numeric(num)
158                 , currlen(0)
159                 , max(ServerInstance->Config->Limits.MaxLine - ServerInstance->Config->GetServerName().size() - additionalsize - 10)
160         {
161         }
162
163         void AddStatic(const std::string& entry)
164         {
165                 max -= (entry.length() + 1);
166                 numeric.GetParams().push_back(entry);
167         }
168
169         void Add(const std::string& entry)
170         {
171                 if (!HasRoom(entry.size()))
172                         Flush();
173
174                 currlen += entry.size() + 1;
175                 numeric.GetParams().push_back(entry);
176         }
177
178         void Flush()
179         {
180                 if ((!SendEmpty) && (IsEmpty()))
181                         return;
182
183                 sink(numeric);
184                 currlen = 0;
185                 numeric.GetParams().erase(numeric.GetParams().begin() + NumStaticParams, numeric.GetParams().end());
186         }
187
188         bool IsEmpty() const { return (numeric.GetParams().size() <= NumStaticParams); }
189 };
190
191 template <unsigned int NumStaticParams, bool SendEmpty>
192 class Numeric::ParamBuilder : public GenericParamBuilder<NumStaticParams, SendEmpty, WriteNumericSink>
193 {
194  public:
195         ParamBuilder(LocalUser* user, unsigned int num)
196                 : ::Numeric::GenericParamBuilder<NumStaticParams, SendEmpty, WriteNumericSink>(WriteNumericSink(user), num, user->nick.size())
197         {
198         }
199 };
200
201 namespace Numerics
202 {
203         class CannotSendTo;
204         class InvalidModeParameter;
205         class NoSuchChannel;
206         class NoSuchNick;
207 }
208
209 /** Builder for the ERR_CANNOTSENDTOCHAN and ERR_CANTSENDTOUSER numerics. */
210 class Numerics::CannotSendTo : public Numeric::Numeric
211 {
212  public:
213         CannotSendTo(Channel* chan, const std::string& message)
214                 : Numeric(ERR_CANNOTSENDTOCHAN)
215         {
216                 push(chan->name);
217                 push(message);
218         }
219
220         CannotSendTo(Channel* chan, const std::string& what, ModeHandler* mh)
221                 : Numeric(ERR_CANNOTSENDTOCHAN)
222         {
223                 push(chan->name);
224                 push(InspIRCd::Format("You cannot send %s to this channel whilst the +%c (%s) mode is set.",
225                         what.c_str(), mh->GetModeChar(), mh->name.c_str()));
226         }
227
228         CannotSendTo(Channel* chan, const std::string& what, char extban, const std::string& extbandesc)
229                 : Numeric(ERR_CANNOTSENDTOCHAN)
230         {
231                 push(chan->name);
232                 push(InspIRCd::Format("You cannot send %s to this channel whilst %s %c: (%s) extban is set matching you.",
233                         what.c_str(), strchr("AEIOUaeiou", extban) ? "an" : "a", extban, extbandesc.c_str()));
234         }
235
236         CannotSendTo(User* user, const std::string& message)
237                 : Numeric(ERR_CANTSENDTOUSER)
238         {
239                 push(user->registered & REG_NICK ? user->nick : "*");
240                 push(message);
241         }
242
243         CannotSendTo(User* user, const std::string& what, ModeHandler* mh, bool self = false)
244                 : Numeric(ERR_CANTSENDTOUSER)
245         {
246                 push(user->registered & REG_NICK ? user->nick : "*");
247                 push(InspIRCd::Format("You cannot send %s to this user whilst %s have the +%c (%s) mode set.",
248                         what.c_str(), self ? "you" : "they", mh->GetModeChar(), mh->name.c_str()));
249         }
250 };
251
252 /* Builder for the ERR_INVALIDMODEPARAM numeric. */
253 class Numerics::InvalidModeParameter : public Numeric::Numeric
254 {
255  private:
256         void push_message(ModeHandler* mode, const std::string& message)
257         {
258                 if (!message.empty())
259                 {
260                         // The caller has specified their own message.
261                         push(message);
262                         return;
263                 }
264
265                 const std::string& syntax = mode->GetSyntax();
266                 if (!syntax.empty())
267                 {
268                         // If the mode has a syntax hint we include it in the message.
269                         push(InspIRCd::Format("Invalid %s mode parameter. Syntax: %s.", mode->name.c_str(), syntax.c_str()));
270                 }
271                 else
272                 {
273                         // Otherwise, send it without.
274                         push(InspIRCd::Format("Invalid %s mode parameter.", mode->name.c_str()));
275                 }
276         }
277
278  public:
279         InvalidModeParameter(Channel* chan, ModeHandler* mode, const std::string& parameter, const std::string& message = "")
280                 : Numeric(ERR_INVALIDMODEPARAM)
281         {
282                 push(chan->name);
283                 push(mode->GetModeChar());
284                 push(parameter);
285                 push_message(mode, message);
286         }
287
288         InvalidModeParameter(User* user, ModeHandler* mode, const std::string& parameter, const std::string& message = "")
289                 : Numeric(ERR_INVALIDMODEPARAM)
290         {
291                 push(user->registered & REG_NICK ? user->nick : "*");
292                 push(mode->GetModeChar());
293                 push(parameter);
294                 push_message(mode, message);
295         }
296 };
297
298 /** Builder for the ERR_NOSUCHCHANNEL numeric. */
299 class Numerics::NoSuchChannel : public Numeric::Numeric
300 {
301  public:
302         NoSuchChannel(const std::string& chan)
303                 : Numeric(ERR_NOSUCHCHANNEL)
304         {
305                 push(chan.empty() ? "*" : chan);
306                 push("No such channel");
307         }
308 };
309
310 /** Builder for the ERR_NOSUCHNICK numeric. */
311 class Numerics::NoSuchNick : public Numeric::Numeric
312 {
313  public:
314         NoSuchNick(const std::string& nick)
315                 : Numeric(ERR_NOSUCHNICK)
316         {
317                 push(nick.empty() ? "*" : nick);
318                 push("No such nick");
319         }
320 };