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

# User Rev Content
1 pippijn 1.1 /*
2     * Copyright © 2007 Pippijn van Steenhoven / The Ermyth Team
3 pippijn 1.3 * Rights to this code are as documented in doc/pod/gplicense.pod.
4 pippijn 1.1 *
5     * Commandtree manipulation routines.
6     *
7 pippijn 1.3 * $Id: commandtree.C,v 1.2 2007-07-21 01:29:10 pippijn Exp $
8 pippijn 1.1 */
9    
10     #include <algorithm>
11    
12     #include "atheme.h"
13     #include "users.h"
14     #include "privs.h"
15    
16 pippijn 1.3 static char const rcsid[] = "$Id: commandtree.C,v 1.2 2007-07-21 01:29:10 pippijn Exp $";
17 pippijn 1.1
18 pippijn 1.3 // 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 pippijn 1.1
22     cmdvec null_cmdvec;
23    
24     struct cmd_eq
25     {
26 pippijn 1.3 cmd_eq () : cmd (0) { }
27     cmd_eq (char const * const command) : cmd (command) { }
28     cmd_eq (command_t const &command) : cmd (command.name) { }
29 pippijn 1.1
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 pippijn 1.3 char const * const cmd;
54 pippijn 1.1 } 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 pippijn 1.3 operator << (cmdvec &commandlist, command_t const &cmd)
71 pippijn 1.1 {
72 pippijn 1.3 if (std::find_if (commandlist.begin (), commandlist.end (), cmd_eq (cmd)) != commandlist.end ())
73 pippijn 1.1 {
74     slog (LG_INFO, "command_add(): command %s already in the list", cmd.name);
75     return;
76     }
77    
78 pippijn 1.3 commandlist.push_back (&cmd);
79 pippijn 1.1 }
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 pippijn 1.3 commandlist << *cmd[i];
88 pippijn 1.1 }
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 pippijn 1.3 operator >> (cmdvec &commandlist, command_t const &cmd)
105 pippijn 1.1 {
106 pippijn 1.3 commandlist.erase (std::find_if (commandlist.begin (), commandlist.end (), cmd_eq (cmd)));
107 pippijn 1.1 }
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 pippijn 1.3 commandlist >> *cmd[i];
116 pippijn 1.1 }
117    
118     command_t const *
119     cmdvec::find (char const *command)
120     {
121 pippijn 1.3 cmdvec::iterator et = end ();
122     cmdvec::iterator it = std::find_if (begin (), et, cmd_eq (command));
123 pippijn 1.1
124 pippijn 1.3 if (it != et)
125 pippijn 1.1 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 pippijn 1.3 command_exec_split (service_t *svs, sourceinfo_t *si, char const * const cmd, char const * const text, cmdvec &commandlist)
148 pippijn 1.1 {
149 pippijn 1.3 size_t i;
150 pippijn 1.1 char *parv[20];
151     command_t const *c;
152    
153 pippijn 1.3 if ((c = commandlist.find (cmd)))
154 pippijn 1.1 {
155 pippijn 1.3 unsigned const parc = text_to_parv (text, c->maxparc, parv);
156     for (i = parc; i < (sizeof (parv) / sizeof (parv[0])); i++)
157 pippijn 1.1 parv[i] = NULL;
158     c->exec (svs, si, parc, parv);
159 pippijn 1.3 for (i = 0; i < parc; i++)
160     sfree (parv[i]);
161 pippijn 1.1 }
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 pippijn 1.3 render_help (sourceinfo_t *info)
180     : si (info)
181 pippijn 1.1 {
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 pippijn 1.3 command_help (sourceinfo_t *si, cmdvec &commandlist)
198 pippijn 1.1 {
199 pippijn 1.3 if (si->service == NULL || si->service->cmdtree == &commandlist)
200 pippijn 1.1 command_success_nodata (si, _("The following commands are available:"));
201     else
202     command_success_nodata (si, _("The following subcommands are available:"));
203    
204 pippijn 1.3 std::for_each (commandlist.begin (), commandlist.end (), render_help (si));
205 pippijn 1.1 }
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 pippijn 1.3 render_help_short (sourceinfo_t *info, char const * const cmdlist)
247     : si (info), maincmds (cmdlist)
248 pippijn 1.1 {
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 pippijn 1.3 char const * const maincmds;
263 pippijn 1.1 };
264    
265     struct render_list
266     {
267 pippijn 1.3 render_list (sourceinfo_t *info, dynstr &str, char const * const cmdlist, size_t length)
268     : si (info), buf (str), maincmds (cmdlist), indent (length)
269 pippijn 1.1 {
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 pippijn 1.3 if (buf.length () > l)
281     buf.append (", ", 2);
282     if (buf.length () > 55)
283 pippijn 1.1 {
284 pippijn 1.3 command_success_nodata (si, "%s", buf.c_str ());
285     buf.reset ();
286 pippijn 1.1 while (--l > 0)
287 pippijn 1.3 buf.append (' ');
288     buf.append (' ');
289 pippijn 1.1 l = indent;
290     }
291 pippijn 1.3 buf.append (c->name, strlen (c->name));
292 pippijn 1.1 }
293     }
294    
295     private:
296     sourceinfo_t *si;
297 pippijn 1.3 dynstr &buf;
298     char const * const maincmds;
299 pippijn 1.1 size_t indent;
300     };
301    
302     void
303 pippijn 1.3 command_help_short (sourceinfo_t *si, cmdvec &commandlist, char const * const maincmds)
304 pippijn 1.1 {
305     size_t l;
306     char *lbuf;
307 pippijn 1.3 dynstr buf (256);
308 pippijn 1.1
309 pippijn 1.3 if (si->service == NULL || si->service->cmdtree == &commandlist)
310 pippijn 1.1 command_success_nodata (si, _("The following commands are available:"));
311     else
312     command_success_nodata (si, _("The following subcommands are available:"));
313    
314 pippijn 1.3 std::for_each (commandlist.begin (), commandlist.end (), render_help_short (si, maincmds));
315 pippijn 1.1
316     command_success_nodata (si, " ");
317     lbuf = _("Other commands: ");
318     buf.append (lbuf, l = strlen (lbuf));
319    
320 pippijn 1.3 std::for_each (commandlist.begin (), commandlist.end (), render_list (si, buf, maincmds, l));
321 pippijn 1.1
322     if (buf.length () > l)
323     command_success_nodata (si, "%s", buf.c_str ());
324     }
325    
326     static int
327 pippijn 1.3 text_to_parv (char const * const text, int maxparc, char **parv)
328 pippijn 1.1 {
329     int count = 0;
330     char *p;
331    
332     if (maxparc == 0)
333     return 0;
334    
335     if (!text)
336     return 0;
337    
338 pippijn 1.3 p = sstrdup (text);
339 pippijn 1.1 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     }