/* * Copyright © 2007 Pippijn van Steenhoven / The Ermyth Team * Rights to this code are as documented in doc/pod/gplicense.pod. * * Commandtree manipulation routines. * * $Id: commandtree.C,v 1.3 2007/08/28 17:08:12 pippijn Exp $ */ #include #include "atheme.h" #include "users.h" #include "privs.h" static char const rcsid[] = "$Id: commandtree.C,v 1.3 2007/08/28 17:08:12 pippijn Exp $"; // This function is Copyright © 2005-2006 Atheme Development Group // Rights to this function are as documented in doc/pod/license.pod. static int text_to_parv (char const * const text, int maxparc, char **parv); cmdvec null_cmdvec; struct cmd_eq { cmd_eq () : cmd (0) { } cmd_eq (char const * const command) : cmd (command) { } cmd_eq (command_t const &command) : cmd (command.name) { } bool operator () (command_t const *c) { return !strcasecmp (c->name, cmd); } /******/ bool operator () (char const *c1, command_t const *c2) { return !strcasecmp (c1, c2->name); } bool operator () (command_t const *c1, char const *c2) { return !strcasecmp (c1->name, c2); } bool operator () (command_t const *c1, command_t const *c2) { return !strcasecmp (c1->name, c2->name); } private: char const * const cmd; } cmd_compare; /* * command_add_many() * * Inputs: * array of commands to add, list to add them to. * * Output: * none * * Side Effects: * adds an array of commands to a command list, * via command_add(). */ void operator << (cmdvec &commandlist, command_t const &cmd) { if (std::find_if (commandlist.begin (), commandlist.end (), cmd_eq (cmd)) != commandlist.end ()) { slog (LG_INFO, "command_add(): command %s already in the list", cmd.name); return; } commandlist.push_back (&cmd); } void operator << (cmdvec &commandlist, command_t const *cmd[]) { unsigned int i; for (i = 0; cmd[i] != NULL; i++) commandlist << *cmd[i]; } /* * command_delete_many() * * Inputs: * array of commands to delete, list to delete them from. * * Output: * none * * Side Effects: * deletes an array of commands from a command list, * via command_delete(). */ void operator >> (cmdvec &commandlist, command_t const &cmd) { commandlist.erase (std::find_if (commandlist.begin (), commandlist.end (), cmd_eq (cmd))); } void operator >> (cmdvec &commandlist, command_t const *cmd[]) { unsigned int i; for (i = 0; cmd[i] != NULL; i++) commandlist >> *cmd[i]; } command_t const * cmdvec::find (char const *command) { cmdvec::iterator et = end (); cmdvec::iterator it = std::find_if (begin (), et, cmd_eq (command)); if (it != et) return *it; return NULL; } void command_t::exec (service_t *svs, sourceinfo_t *si, int parc, char *parv[]) const { if (has_priv (si, access)) { cmd (si, parc, parv); return; } if (has_any_privs (si)) command_fail (si, fault_noprivs, _("You do not have %s privilege."), access); else command_fail (si, fault_noprivs, _("You are not authorized to perform this operation.")); /*snoop(_("DENIED CMD: \2%s\2 used %s %s"), origin, svs->name, cmd); */ } void command_exec_split (service_t *svs, sourceinfo_t *si, char const * const cmd, char const * const text, cmdvec &commandlist) { size_t i; char *parv[20]; command_t const *c; if ((c = commandlist.find (cmd))) { unsigned const parc = text_to_parv (text, c->maxparc, parv); for (i = parc; i < (sizeof (parv) / sizeof (parv[0])); i++) parv[i] = NULL; c->exec (svs, si, parc, parv); for (i = 0; i < parc; i++) sfree (parv[i]); } else 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); } /* * command_help * Iterates the command tree and lists available commands. * * inputs - * si: The origin of the request. * commandtree: The command tree being listed. * * outputs - * A list of available commands. */ struct render_help { render_help (sourceinfo_t *info) : si (info) { } void operator () (command_t const *c) { /* show only the commands we have access to * (taken from command_exec()) */ if (has_priv (si, c->access)) command_success_nodata (si, "\2%-15s\2 %s", c->name, c->desc); } sourceinfo_t *si; }; void command_help (sourceinfo_t *si, cmdvec &commandlist) { if (si->service == NULL || si->service->cmdtree == &commandlist) command_success_nodata (si, _("The following commands are available:")); else command_success_nodata (si, _("The following subcommands are available:")); std::for_each (commandlist.begin (), commandlist.end (), render_help (si)); } /* name1 name2 name3... */ static bool string_in_list (char const *str, char const *name) { char *p; int l; if (str == NULL) return false; l = strlen (name); while (*str != '\0') { p = strchr (str, ' '); if (p != NULL ? p - str == l && !strncasecmp (str, name, p - str) : !strcasecmp (str, name)) return true; if (p == NULL) return false; str = p; while (*str == ' ') str++; } return false; } /* * command_help_short * Iterates over the command tree and lists available commands. * * inputs - * mynick: The nick of the services bot sending out the notices. * origin: The origin of the request. * commandtree: The command tree being listed. * maincmds: The commands to list verbosely. * * outputs - * A list of available commands. */ struct render_help_short { render_help_short (sourceinfo_t *info, char const * const cmdlist) : si (info), maincmds (cmdlist) { } void operator () (command_t const *c) { /* show only the commands we have access to * (taken from command_exec()) */ if (string_in_list (maincmds, c->name) && has_priv (si, c->access)) command_success_nodata (si, "\2%-15s\2 %s", c->name, c->desc); } private: sourceinfo_t *si; char const * const maincmds; }; struct render_list { render_list (sourceinfo_t *info, dynstr &str, char const * const cmdlist, size_t length) : si (info), buf (str), maincmds (cmdlist), indent (length) { } void operator () (command_t const *c) { /* show only the commands we have access to * (taken from command_exec()) */ size_t l = indent; if (!string_in_list (maincmds, c->name) && has_priv (si, c->access)) { if (buf.length () > l) buf.append (", ", 2); if (buf.length () > 55) { command_success_nodata (si, "%s", buf.c_str ()); buf.reset (); while (--l > 0) buf.append (' '); buf.append (' '); l = indent; } buf.append (c->name, strlen (c->name)); } } private: sourceinfo_t *si; dynstr &buf; char const * const maincmds; size_t indent; }; void command_help_short (sourceinfo_t *si, cmdvec &commandlist, char const * const maincmds) { size_t l; char *lbuf; dynstr buf (256); if (si->service == NULL || si->service->cmdtree == &commandlist) command_success_nodata (si, _("The following commands are available:")); else command_success_nodata (si, _("The following subcommands are available:")); std::for_each (commandlist.begin (), commandlist.end (), render_help_short (si, maincmds)); command_success_nodata (si, " "); lbuf = _("Other commands: "); buf.append (lbuf, l = strlen (lbuf)); std::for_each (commandlist.begin (), commandlist.end (), render_list (si, buf, maincmds, l)); if (buf.length () > l) command_success_nodata (si, "%s", buf.c_str ()); } static int text_to_parv (char const * const text, int maxparc, char **parv) { int count = 0; char *p; if (maxparc == 0) return 0; if (!text) return 0; p = sstrdup (text); while (count < maxparc - 1 && (parv[count] = strtok (p, " ")) != NULL) count++, p = NULL; if ((parv[count] = strtok (p, "")) != NULL) { p = parv[count]; if (*p != '\0') { p += strlen (p) - 1; while (*p == ' ' && p > parv[count]) p--; p[1] = '\0'; } count++; } return count; }