InspIRCd  3.0
numericbuilder.h
1 /*
2  * InspIRCd -- Internet Relay Chat Daemon
3  *
4  * Copyright (C) 2018-2020 Sadie Powell <[email protected]>
5  * Copyright (C) 2015-2016 Attila Molnar <[email protected]>
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>
30 
31  template <char Sep = ',', bool SendEmpty = false>
32  class Builder;
33 
34  template <unsigned int NumStaticParams, bool SendEmpty, typename Sink>
36 
37  template <unsigned int NumStaticParams, bool SendEmpty = false>
38  class ParamBuilder;
39 }
40 
42 {
43  LocalUser* const user;
44 
45  public:
47  : user(u)
48  {
49  }
50 
51  void operator()(Numeric& numeric) const
52  {
53  user->WriteNumeric(numeric);
54  }
55 };
56 
58 {
59  User* const user;
60 
61  public:
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>
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>
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 CannotSendTo;
204  class InvalidModeParameter;
205  class NoSuchChannel;
206  class NoSuchNick;
207 }
208 
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. */
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 
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 
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 };
Numeric::Numeric::push
Numeric & push(const T &x)
Definition: numeric.h:58
Channel::name
std::string name
Definition: channels.h:88
InspIRCd::Format
static std::string Format(const char *formatString,...)
Definition: helperfuncs.cpp:479
Numerics::InvalidModeParameter
Definition: numericbuilder.h:253
Numeric::WriteRemoteNumericSink
Definition: numericbuilder.h:57
Numeric::Builder
Definition: numericbuilder.h:32
Numerics::CannotSendTo
Definition: numericbuilder.h:210
Numerics::NoSuchChannel
Definition: numericbuilder.h:299
Numeric::GenericBuilder
Definition: numericbuilder.h:29
ModeHandler::GetModeChar
char GetModeChar() const
Definition: mode.h:243
Numeric::ParamBuilder
Definition: numericbuilder.h:38
Channel
Definition: channels.h:40
Numeric::WriteNumericSink
Definition: numericbuilder.h:41
Numeric::Numeric::Numeric
Numeric(unsigned int num)
Definition: numeric.h:48
User::nick
std::string nick
Definition: users.h:317
Numerics::NoSuchNick
Definition: numericbuilder.h:311
User
Definition: users.h:239
Numeric::GenericParamBuilder
Definition: numericbuilder.h:35
ServiceProvider::name
const std::string name
Definition: base.h:256
Numeric::Numeric
Definition: numeric.h:30
ModeHandler
Definition: mode.h:99
LocalUser
Definition: users.h:739
User::registered
unsigned int registered
Definition: users.h:360