ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/ermyth/src/commandtree.C
Revision: 1.3
Committed: Tue Aug 28 17:08:12 2007 UTC (16 years, 9 months ago) by pippijn
Content type: text/plain
Branch: MAIN
Changes since 1.2: +54 -52 lines
Log Message:
- changed name
- updated the example config to the new system
- added more documentation
- enhanced documentation generators
- added a link to the pdf to the website
- added an RSS feed generator
- transitioned hooks to c++ callbacks
- did various merges with upstream along the way
- added const where appropriate
- removed the old block allocator
- fixed most memory leaks
- transitioned some dictionaries to std::map
- transitioned some lists to std::vector
- made some free functions members where appropriate
- renamed string to dynstr and added a static string ststr
- use NOW instead of time (NULL) if possible
- completely reworked database backends, crypto handlers and protocol handlers
  to use an object factory
- removed the old module system. ermyth does not do any dynamic loading anymore
- fixed most of the build system
- reworked how protocol commands work

File Contents

# Content
1 /*
2 * Copyright © 2007 Pippijn van Steenhoven / The Ermyth Team
3 * Rights to this code are as documented in doc/pod/gplicense.pod.
4 *
5 * Commandtree manipulation routines.
6 *
7 * $Id: commandtree.C,v 1.2 2007-07-21 01:29:10 pippijn Exp $
8 */
9
10 #include <algorithm>
11
12 #include "atheme.h"
13 #include "users.h"
14 #include "privs.h"
15
16 static char const rcsid[] = "$Id: commandtree.C,v 1.2 2007-07-21 01:29:10 pippijn Exp $";
17
18 // This function is Copyright © 2005-2006 Atheme Development Group
19 // Rights to this function are as documented in doc/pod/license.pod.
20 static int text_to_parv (char const * const text, int maxparc, char **parv);
21
22 cmdvec null_cmdvec;
23
24 struct cmd_eq
25 {
26 cmd_eq () : cmd (0) { }
27 cmd_eq (char const * const command) : cmd (command) { }
28 cmd_eq (command_t const &command) : cmd (command.name) { }
29
30 bool operator () (command_t const *c)
31 {
32 return !strcasecmp (c->name, cmd);
33 }
34
35 /******/
36
37 bool operator () (char const *c1, command_t const *c2)
38 {
39 return !strcasecmp (c1, c2->name);
40 }
41
42 bool operator () (command_t const *c1, char const *c2)
43 {
44 return !strcasecmp (c1->name, c2);
45 }
46
47 bool operator () (command_t const *c1, command_t const *c2)
48 {
49 return !strcasecmp (c1->name, c2->name);
50 }
51
52 private:
53 char const * const cmd;
54 } cmd_compare;
55
56 /*
57 * command_add_many()
58 *
59 * Inputs:
60 * array of commands to add, list to add them to.
61 *
62 * Output:
63 * none
64 *
65 * Side Effects:
66 * adds an array of commands to a command list,
67 * via command_add().
68 */
69 void
70 operator << (cmdvec &commandlist, command_t const &cmd)
71 {
72 if (std::find_if (commandlist.begin (), commandlist.end (), cmd_eq (cmd)) != commandlist.end ())
73 {
74 slog (LG_INFO, "command_add(): command %s already in the list", cmd.name);
75 return;
76 }
77
78 commandlist.push_back (&cmd);
79 }
80
81 void
82 operator << (cmdvec &commandlist, command_t const *cmd[])
83 {
84 unsigned int i;
85
86 for (i = 0; cmd[i] != NULL; i++)
87 commandlist << *cmd[i];
88 }
89
90 /*
91 * command_delete_many()
92 *
93 * Inputs:
94 * array of commands to delete, list to delete them from.
95 *
96 * Output:
97 * none
98 *
99 * Side Effects:
100 * deletes an array of commands from a command list,
101 * via command_delete().
102 */
103 void
104 operator >> (cmdvec &commandlist, command_t const &cmd)
105 {
106 commandlist.erase (std::find_if (commandlist.begin (), commandlist.end (), cmd_eq (cmd)));
107 }
108
109 void
110 operator >> (cmdvec &commandlist, command_t const *cmd[])
111 {
112 unsigned int i;
113
114 for (i = 0; cmd[i] != NULL; i++)
115 commandlist >> *cmd[i];
116 }
117
118 command_t const *
119 cmdvec::find (char const *command)
120 {
121 cmdvec::iterator et = end ();
122 cmdvec::iterator it = std::find_if (begin (), et, cmd_eq (command));
123
124 if (it != et)
125 return *it;
126
127 return NULL;
128 }
129
130 void
131 command_t::exec (service_t *svs, sourceinfo_t *si, int parc, char *parv[]) const
132 {
133 if (has_priv (si, access))
134 {
135 cmd (si, parc, parv);
136 return;
137 }
138
139 if (has_any_privs (si))
140 command_fail (si, fault_noprivs, _("You do not have %s privilege."), access);
141 else
142 command_fail (si, fault_noprivs, _("You are not authorized to perform this operation."));
143 /*snoop(_("DENIED CMD: \2%s\2 used %s %s"), origin, svs->name, cmd); */
144 }
145
146 void
147 command_exec_split (service_t *svs, sourceinfo_t *si, char const * const cmd, char const * const text, cmdvec &commandlist)
148 {
149 size_t i;
150 char *parv[20];
151 command_t const *c;
152
153 if ((c = commandlist.find (cmd)))
154 {
155 unsigned const parc = text_to_parv (text, c->maxparc, parv);
156 for (i = parc; i < (sizeof (parv) / sizeof (parv[0])); i++)
157 parv[i] = NULL;
158 c->exec (svs, si, parc, parv);
159 for (i = 0; i < parc; i++)
160 sfree (parv[i]);
161 }
162 else
163 notice (svs->name, si->su->nick, _("Invalid command. Use \2/%s%s help\2 for a command listing."), (ircd->uses_rcommand == false) ? "msg " : "", svs->disp);
164 }
165
166 /*
167 * command_help
168 * Iterates the command tree and lists available commands.
169 *
170 * inputs -
171 * si: The origin of the request.
172 * commandtree: The command tree being listed.
173 *
174 * outputs -
175 * A list of available commands.
176 */
177 struct render_help
178 {
179 render_help (sourceinfo_t *info)
180 : si (info)
181 {
182 }
183
184 void operator () (command_t const *c)
185 {
186 /* show only the commands we have access to
187 * (taken from command_exec())
188 */
189 if (has_priv (si, c->access))
190 command_success_nodata (si, "\2%-15s\2 %s", c->name, c->desc);
191 }
192
193 sourceinfo_t *si;
194 };
195
196 void
197 command_help (sourceinfo_t *si, cmdvec &commandlist)
198 {
199 if (si->service == NULL || si->service->cmdtree == &commandlist)
200 command_success_nodata (si, _("The following commands are available:"));
201 else
202 command_success_nodata (si, _("The following subcommands are available:"));
203
204 std::for_each (commandlist.begin (), commandlist.end (), render_help (si));
205 }
206
207 /* name1 name2 name3... */
208 static bool
209 string_in_list (char const *str, char const *name)
210 {
211 char *p;
212 int l;
213
214 if (str == NULL)
215 return false;
216 l = strlen (name);
217 while (*str != '\0')
218 {
219 p = strchr (str, ' ');
220 if (p != NULL ? p - str == l && !strncasecmp (str, name, p - str) : !strcasecmp (str, name))
221 return true;
222 if (p == NULL)
223 return false;
224 str = p;
225 while (*str == ' ')
226 str++;
227 }
228 return false;
229 }
230
231 /*
232 * command_help_short
233 * Iterates over the command tree and lists available commands.
234 *
235 * inputs -
236 * mynick: The nick of the services bot sending out the notices.
237 * origin: The origin of the request.
238 * commandtree: The command tree being listed.
239 * maincmds: The commands to list verbosely.
240 *
241 * outputs -
242 * A list of available commands.
243 */
244 struct render_help_short
245 {
246 render_help_short (sourceinfo_t *info, char const * const cmdlist)
247 : si (info), maincmds (cmdlist)
248 {
249 }
250
251 void operator () (command_t const *c)
252 {
253 /* show only the commands we have access to
254 * (taken from command_exec())
255 */
256 if (string_in_list (maincmds, c->name) && has_priv (si, c->access))
257 command_success_nodata (si, "\2%-15s\2 %s", c->name, c->desc);
258 }
259
260 private:
261 sourceinfo_t *si;
262 char const * const maincmds;
263 };
264
265 struct render_list
266 {
267 render_list (sourceinfo_t *info, dynstr &str, char const * const cmdlist, size_t length)
268 : si (info), buf (str), maincmds (cmdlist), indent (length)
269 {
270 }
271
272 void operator () (command_t const *c)
273 {
274 /* show only the commands we have access to
275 * (taken from command_exec())
276 */
277 size_t l = indent;
278 if (!string_in_list (maincmds, c->name) && has_priv (si, c->access))
279 {
280 if (buf.length () > l)
281 buf.append (", ", 2);
282 if (buf.length () > 55)
283 {
284 command_success_nodata (si, "%s", buf.c_str ());
285 buf.reset ();
286 while (--l > 0)
287 buf.append (' ');
288 buf.append (' ');
289 l = indent;
290 }
291 buf.append (c->name, strlen (c->name));
292 }
293 }
294
295 private:
296 sourceinfo_t *si;
297 dynstr &buf;
298 char const * const maincmds;
299 size_t indent;
300 };
301
302 void
303 command_help_short (sourceinfo_t *si, cmdvec &commandlist, char const * const maincmds)
304 {
305 size_t l;
306 char *lbuf;
307 dynstr buf (256);
308
309 if (si->service == NULL || si->service->cmdtree == &commandlist)
310 command_success_nodata (si, _("The following commands are available:"));
311 else
312 command_success_nodata (si, _("The following subcommands are available:"));
313
314 std::for_each (commandlist.begin (), commandlist.end (), render_help_short (si, maincmds));
315
316 command_success_nodata (si, " ");
317 lbuf = _("Other commands: ");
318 buf.append (lbuf, l = strlen (lbuf));
319
320 std::for_each (commandlist.begin (), commandlist.end (), render_list (si, buf, maincmds, l));
321
322 if (buf.length () > l)
323 command_success_nodata (si, "%s", buf.c_str ());
324 }
325
326 static int
327 text_to_parv (char const * const text, int maxparc, char **parv)
328 {
329 int count = 0;
330 char *p;
331
332 if (maxparc == 0)
333 return 0;
334
335 if (!text)
336 return 0;
337
338 p = sstrdup (text);
339 while (count < maxparc - 1 && (parv[count] = strtok (p, " ")) != NULL)
340 count++, p = NULL;
341
342 if ((parv[count] = strtok (p, "")) != NULL)
343 {
344 p = parv[count];
345 if (*p != '\0')
346 {
347 p += strlen (p) - 1;
348 while (*p == ' ' && p > parv[count])
349 p--;
350 p[1] = '\0';
351 }
352 count++;
353 }
354 return count;
355 }