1 /*
2  * InspIRCd -- Internet Relay Chat Daemon
3  *
4  *   Copyright (C) 2012-2015, 2018 Attila Molnar <attilamolnar@hush.com>
5  *   Copyright (C) 2012-2013, 2017-2018, 2020 Sadie Powell <sadie@witchery.services>
6  *   Copyright (C) 2012 Robby <robby@chatbelgie.be>
7  *   Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org>
8  *   Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org>
9  *   Copyright (C) 2007-2008 Robin Burchell <robin+git@viroteck.net>
10  *   Copyright (C) 2007 Dennis Friis <peavey@inspircd.org>
11  *   Copyright (C) 2003, 2006-2010 Craig Edwards <brain@inspircd.org>
12  *
13  * This file is part of InspIRCd.  InspIRCd is free software: you can
14  * redistribute it and/or modify it under the terms of the GNU General Public
15  * License as published by the Free Software Foundation, version 2.
16  *
17  * This program is distributed in the hope that it will be useful, but WITHOUT
18  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
19  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
20  * details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
24  */
25 
26 
27 #pragma once
28 
29 /** Used to indicate the result of trying to execute a command. */
30 enum CmdResult
31 {
32 	/** The command exists but its execution failed. */
33 	CMD_FAILURE = 0,
34 
35 	/** The command exists and its execution succeeded. */
36 	CMD_SUCCESS = 1,
37 
38 	/* The command does not exist. */
39 	CMD_INVALID = 2
40 };
41 
42 /** Flag for commands that are only allowed from servers */
43 const char FLAG_SERVERONLY = 7; // technically anything nonzero below 'A' works
44 
45 /** Translation types for translation of parameters to UIDs.
46  * This allows the core commands to not have to be aware of how UIDs
47  * work (making it still possible to write other linking modules which
48  * do not use UID (but why would you want to?)
49  */
50 enum TranslateType
51 {
52 	TR_TEXT,		/* Raw text, leave as-is */
53 	TR_NICK,		/* Nickname, translate to UUID for server->server */
54 	TR_CUSTOM		/* Custom translation handled by EncodeParameter/DecodeParameter */
55 };
56 
57 /** Routing types for a command. Any command which is created defaults
58  * to having its command broadcasted on success. This behaviour may be
59  * overridden to one of the route types shown below (see the #defines
60  * below for more information on each one's behaviour)
61  */
62 enum RouteType
63 {
64 	ROUTE_TYPE_LOCALONLY,
65 	ROUTE_TYPE_BROADCAST,
66 	ROUTE_TYPE_UNICAST,
67 	ROUTE_TYPE_MESSAGE,
68 	ROUTE_TYPE_OPT_BCAST,
69 	ROUTE_TYPE_OPT_UCAST
70 };
71 
72 /** Defines routing information for a command, containing a destination
73  * server id (if applicable) and a routing type from the enum above.
74  */
75 struct RouteDescriptor
76 {
77 	/** Routing type from the enum above
78 	 */
79 	RouteType type;
80 	/** For unicast, the destination server's name
81 	 */
82 	std::string serverdest;
83 
84 	/** For unicast, the destination Server
85 	 */
86 	Server* server;
87 
88 	/** Create a RouteDescriptor
89 	 */
RouteDescriptorRouteDescriptor90 	RouteDescriptor(RouteType t, const std::string &d)
91 		: type(t), serverdest(d), server(NULL) { }
92 
RouteDescriptorRouteDescriptor93 	RouteDescriptor(RouteType t, Server* srv)
94 		: type(t), server(srv) { }
95 };
96 
97 /** Do not route this command */
98 #define ROUTE_LOCALONLY (RouteDescriptor(ROUTE_TYPE_LOCALONLY, ""))
99 /** Route this command to all servers, fail if not understood */
100 #define ROUTE_BROADCAST (RouteDescriptor(ROUTE_TYPE_BROADCAST, ""))
101 /** Route this command to a single server (do nothing if own server name specified) */
102 #define ROUTE_UNICAST(x) (RouteDescriptor(ROUTE_TYPE_UNICAST, x))
103 /** Route this command as a message with the given target (any of user, #channel, @#channel, $servermask) */
104 #define ROUTE_MESSAGE(x) (RouteDescriptor(ROUTE_TYPE_MESSAGE, x))
105 /** Route this command to all servers wrapped via ENCAP, so ignored if not understood */
106 #define ROUTE_OPT_BCAST (RouteDescriptor(ROUTE_TYPE_OPT_BCAST, ""))
107 /** Route this command to a single server wrapped via ENCAP, so ignored if not understood */
108 #define ROUTE_OPT_UCAST(x) (RouteDescriptor(ROUTE_TYPE_OPT_UCAST, x))
109 
110 /** A structure that defines a command. Every command available
111  * in InspIRCd must be defined as derived from Command.
112  */
113 class CoreExport CommandBase : public ServiceProvider
114 {
115  public:
116 	/** Encapsulates parameters to a command. */
117 	class Params : public std::vector<std::string>
118 	{
119 	 private:
120 		/* IRCv3 message tags. */
121 		ClientProtocol::TagMap tags;
122 
123 	 public:
124 		/** Initializes a new instance from parameter and tag references.
125 		 * @param paramsref Message parameters.
126 		 * @param tagsref IRCv3 message tags.
127 		 */
Params(const std::vector<std::string> & paramsref,const ClientProtocol::TagMap & tagsref)128 		Params(const std::vector<std::string>& paramsref, const ClientProtocol::TagMap& tagsref)
129 			: std::vector<std::string>(paramsref)
130 			, tags(tagsref)
131 		{
132 		}
133 
134 		/** Initializes a new instance from parameter iterators.
135 		 * @param first The first element in the parameter array.
136 		 * @param last The last element in the parameter array.
137 		 */
138 		template<typename Iterator>
Params(Iterator first,Iterator last)139 		Params(Iterator first, Iterator last)
140 			: std::vector<std::string>(first, last)
141 		{
142 		}
143 
144 		/** Initializes a new empty instance. */
Params()145 		Params() { }
146 
147 		/** Retrieves the IRCv3 message tags. */
GetTags()148 		const ClientProtocol::TagMap& GetTags() const { return tags; }
GetTags()149 		ClientProtocol::TagMap& GetTags() { return tags; }
150 	};
151 
152 	/** Minimum number of parameters command takes
153 	*/
154 	const unsigned int min_params;
155 
156 	/** Maximum number of parameters command takes.
157 	 * This is used by the command parser to join extra parameters into one last param.
158 	 * If not set, no munging is done to this command.
159 	 */
160 	const unsigned int max_params;
161 
162 	/** True if the command allows an empty last parameter.
163 	 * When false and the last parameter is empty, it's popped BEFORE
164 	 * checking there are enough params, etc. (i.e. the handler won't
165 	 * be called if there aren't enough params after popping the empty
166 	 * param).
167 	 * True by default
168 	 */
169 	bool allow_empty_last_param;
170 
171 	/** Translation type list for possible parameters, used to tokenize
172 	 * parameters into UIDs and SIDs etc.
173 	 */
174 	std::vector<TranslateType> translation;
175 
176 	/** Create a new command.
177 	 * @param me The module which created this command.
178 	 * @param cmd Command name. This must be UPPER CASE.
179 	 * @param minpara Minimum parameters required for the command.
180 	 * @param maxpara Maximum number of parameters this command may have - extra parameters
181 	 * will be tossed into one last space-separated param.
182 	 */
183 	CommandBase(Module* me, const std::string& cmd, unsigned int minpara = 0, unsigned int maxpara = 0);
184 
185 	virtual RouteDescriptor GetRouting(User* user, const CommandBase::Params& parameters);
186 
187 	/** Encode a parameter for server->server transmission.
188 	 * Used for parameters for which the translation type is TR_CUSTOM.
189 	 * @param parameter The parameter to encode. Can be modified in place.
190 	 * @param index The parameter index (0 == first parameter).
191 	 */
192 	virtual void EncodeParameter(std::string& parameter, unsigned int index);
193 
194 	virtual ~CommandBase();
195 };
196 
197 class CoreExport Command : public CommandBase
198 {
199  protected:
200 	/** Initializes a new instance of the Command class.
201 	 * @param me The module which created this instance.
202 	 * @param cmd The name of the command.
203 	 * @param minpara The minimum number of parameters that the command accepts.
204 	 * @param maxpara The maximum number of parameters that the command accepts.
205 	 */
206 	Command(Module* me, const std::string& cmd, unsigned int minpara = 0, unsigned int maxpara = 0);
207 
208  public:
209 	/** Unregisters this command from the command parser. */
210 	~Command() CXX11_OVERRIDE;
211 
212 	/** The user modes required to be able to execute this command. */
213 	unsigned char flags_needed;
214 
215 	/** Whether the command will not be forwarded by the linking module even if it comes via ENCAP. */
216 	bool force_manual_route;
217 
218 	/** The number of seconds worth of penalty that executing this command gives. */
219 	unsigned int Penalty;
220 
221 	/** The number of times this command has been executed. */
222 	unsigned long use_count;
223 
224 	/** If non-empty then the syntax of the parameter for this command. */
225 	std::string syntax;
226 
227 	/** Whether the command can be issued before registering. */
228 	bool works_before_reg;
229 
230 	/** Handle the command from a user.
231 	 * @param user The user who issued the command.
232 	 * @param parameters The parameters for the command.
233 	 * @return Returns CMD_FAILURE on failure, CMD_SUCCESS on success, or CMD_INVALID
234 	 *         if the command was malformed.
235 	 */
236 	virtual CmdResult Handle(User* user, const Params& parameters) = 0;
237 
238 	/** Registers this command with the command parser. */
239 	void RegisterService() CXX11_OVERRIDE;
240 
241 	/** Tells the user they did not specify enough parameters.
242 	 * @param user The user who issued the command.
243 	 * @param parameters The parameters for the command.
244 	 */
245 	virtual void TellNotEnoughParameters(LocalUser* user, const Params& parameters);
246 
247 	/** Tells the user they need to be registered to execute this command.
248 	 * @param user The user who issued the command.
249 	 * @param parameters The parameters for the command.
250 	 */
251 	virtual void TellNotRegistered(LocalUser* user, const Params& parameters);
252 };
253 
254 class CoreExport SplitCommand : public Command
255 {
256 protected:
257 	/** Initializes a new instance of the SplitCommand class.
258 	 * @param me The module which created this instance.
259 	 * @param cmd The name of the command.
260 	 * @param minpara The minimum number of parameters that the command accepts.
261 	 * @param maxpara The maximum number of parameters that the command accepts.
262 	 */
263 	SplitCommand(Module* me, const std::string& cmd, unsigned int minpara = 0, unsigned int maxpara = 0);
264 
265  public:
266 	/** @copydoc Command::Handle */
267 	CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE;
268 
269 	/** Handle the command from a local user.
270 	 * @param user The user who issued the command.
271 	 * @param parameters The parameters for the command.
272 	 * @return Returns CMD_FAILURE on failure, CMD_SUCCESS on success, or CMD_INVALID
273 	 *         if the command was malformed.
274 	 */
275 	virtual CmdResult HandleLocal(LocalUser* user, const Params& parameters);
276 
277 	/** Handle the command from a remote user.
278 	 * @param user The user who issued the command.
279 	 * @param parameters The parameters for the command.
280 	 * @return Returns CMD_FAILURE on failure, CMD_SUCCESS on success, or CMD_INVALID
281 	 *         if the command was malformed.
282 	 */
283 	virtual CmdResult HandleRemote(RemoteUser* user, const Params& parameters);
284 
285 	/** Handle the command from a server user.
286 	 * @param user The user who issued the command.
287 	 * @param parameters The parameters for the command.
288 	 * @return Returns CMD_FAILURE on failure, CMD_SUCCESS on success, or CMD_INVALID
289 	 *         if the command was malformed.
290 	 */
291 	virtual CmdResult HandleServer(FakeUser* user, const Params& parameters);
292 };
293 
294 /** Shortcut macros for defining translation lists
295  */
296 #define TRANSLATE1(x1)	translation.push_back(x1);
297 #define TRANSLATE2(x1,x2)  translation.push_back(x1);translation.push_back(x2);
298 #define TRANSLATE3(x1,x2,x3)  translation.push_back(x1);translation.push_back(x2);translation.push_back(x3);
299 #define TRANSLATE4(x1,x2,x3,x4)  translation.push_back(x1);translation.push_back(x2);translation.push_back(x3);translation.push_back(x4);
300 #define TRANSLATE5(x1,x2,x3,x4,x5)  translation.push_back(x1);translation.push_back(x2);translation.push_back(x3);translation.push_back(x4);\
301 	translation.push_back(x5);
302 #define TRANSLATE6(x1,x2,x3,x4,x5,x6)  translation.push_back(x1);translation.push_back(x2);translation.push_back(x3);translation.push_back(x4);\
303 	translation.push_back(x5);translation.push_back(x6);
304 #define TRANSLATE7(x1,x2,x3,x4,x5,x6,x7)  translation.push_back(x1);translation.push_back(x2);translation.push_back(x3);translation.push_back(x4);\
305 	translation.push_back(x5);translation.push_back(x6);translation.push_back(x7);
306 #define TRANSLATE8(x1,x2,x3,x4,x5,x6,x7,x8)  translation.push_back(x1);translation.push_back(x2);translation.push_back(x3);translation.push_back(x4);\
307 	translation.push_back(x5);translation.push_back(x6);translation.push_back(x7);translation.push_back(x8);
308