/* * Copyright © 2007 Pippijn van Steenhoven / The Ermyth Team * Copyright © 2005-2006 Atheme Development Group * Rights to this code are as documented in doc/LICENSE. * * Commandtree manipulation routines. * * $Id: commandtree.C,v 1.1 2007/07/19 08:24:56 pippijn Exp $ */ #include #include "atheme.h" #include "users.h" #include "privs.h" static char const rcsid[] = "$Id: commandtree.C,v 1.1 2007/07/19 08:24:56 pippijn Exp $"; static int text_to_parv (char *text, int maxparc, char **parv); command_t null_cmd = { NULL, NULL, NULL, 0, NULL }; cmdvec null_cmdvec; struct cmd_eq { cmd_eq () { } cmd_eq (char const *cmd) : cmd (cmd) { } cmd_eq (command_t const &cmd) : cmd (cmd.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: const char *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 it_end = this->end (); cmdvec::iterator it = std::find_if (this->begin (), it_end, cmd_eq (command)); if (it != it_end) 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 *cmd, char *text, cmdvec *commandlist) { int parc, i; char *parv[20]; command_t const *c; if ((c = commandlist->find (cmd))) { parc = text_to_parv (text, c->maxparc, parv); for (i = parc; i < (int) (sizeof (parv) / sizeof (parv[0])); i++) parv[i] = NULL; c->exec (svs, si, parc, parv); } 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 *si) : si (si) { } 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 *si, char *maincmds) : si (si), maincmds (maincmds) { } 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 *maincmds; }; struct render_list { render_list (sourceinfo_t *si, string *buf, char *maincmds, size_t length) : si (si), buf (buf), maincmds (maincmds), 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; string *buf; char *maincmds; size_t indent; }; void command_help_short (sourceinfo_t *si, cmdvec *commandlist, char *maincmds) { size_t l; char *lbuf; string 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 *text, int maxparc, char **parv) { int count = 0; char *p; if (maxparc == 0) return 0; if (!text) return 0; p = 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; }