]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - include/numericbuilder.h
73bcc2c97f67ec28a7d0c187c3e8ae55f19adc99
[user/henk/code/inspircd.git] / include / numericbuilder.h
1 /*
2  * InspIRCd -- Internet Relay Chat Daemon
3  *
4  *   Copyright (C) 2018-2019 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->ServerName.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->ServerName.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 InvalidModeParameter;
204         class NoSuchChannel;
205         class NoSuchNick;
206 }
207
208 /* Builder for the ERR_INVALIDMODEPARAM numeric. */
209 class Numerics::InvalidModeParameter : public Numeric::Numeric
210 {
211  private:
212         void push_message(ModeHandler* mode, const std::string& message)
213         {
214                 if (!message.empty())
215                 {
216                         // The caller has specified their own message.
217                         push(message);
218                         return;
219                 }
220
221                 const std::string& syntax = mode->GetSyntax();
222                 if (!syntax.empty())
223                 {
224                         // If the mode has a syntax hint we include it in the message.
225                         push(InspIRCd::Format("Invalid %s mode parameter. Syntax: %s.", mode->name.c_str(), syntax.c_str()));
226                 }
227                 else
228                 {
229                         // Otherwise, send it without.
230                         push(InspIRCd::Format("Invalid %s mode parameter.", mode->name.c_str()));
231                 }
232         }
233
234  public:
235         InvalidModeParameter(Channel* chan, ModeHandler* mode, const std::string& parameter, const std::string& message = "")
236                 : Numeric(ERR_INVALIDMODEPARAM)
237         {
238                 push(chan->name);
239                 push(mode->GetModeChar());
240                 push(parameter);
241                 push_message(mode, message);
242         }
243
244         InvalidModeParameter(User* user, ModeHandler* mode, const std::string& parameter, const std::string& message = "")
245                 : Numeric(ERR_INVALIDMODEPARAM)
246         {
247                 push(user->registered & REG_NICK ? user->nick : "*");
248                 push(mode->GetModeChar());
249                 push(parameter);
250                 push_message(mode, message);
251         }
252 };
253
254 /** Builder for the ERR_NOSUCHCHANNEL numeric. */
255 class Numerics::NoSuchChannel : public Numeric::Numeric
256 {
257  public:
258         NoSuchChannel(const std::string& chan)
259                 : Numeric(ERR_NOSUCHCHANNEL)
260         {
261                 push(chan.empty() ? "*" : chan);
262                 push("No such channel");
263         }
264 };
265
266 /** Builder for the ERR_NOSUCHNICK numeric. */
267 class Numerics::NoSuchNick : public Numeric::Numeric
268 {
269  public:
270         NoSuchNick(const std::string& nick)
271                 : Numeric(ERR_NOSUCHNICK)
272         {
273                 push(nick.empty() ? "*" : nick);
274                 push("No such nick");
275         }
276 };