/** * ircd_alis.C: ALIS, based on the ratbox-services implementation. * * Copyright © 2007 Pippijn van Steenhoven / The Ermyth Team * Rights to this code are as documented in COPYING. * * * Portions of this file were derived from sources bearing the following license: * Copyright © 2005-2007 William Pitcock, et al. * The rights to this code are as documented under doc/pod/license.pod. * * Copyright © 2003-2007 Lee Hardy * Copyright © 2003-2007 ircd-ratbox development team * * $Id: ircd_alis.C,v 1.6 2007/09/16 18:54:43 pippijn Exp $ */ #include #include "atheme.h" #include static char const rcsid[] = "$Id: ircd_alis.C,v 1.6 2007/09/16 18:54:43 pippijn Exp $"; REGISTER_MODULE ("alis", false, "William Pitcock "); #define ALIS_MAX_PARC 10 #define ALIS_MAX_MATCH 60 #define DIR_UNSET 0 #define DIR_SET 1 #define DIR_EQUAL 2 service_t *alis; cmdvec alis_cmdtree; static void alis_cmd_list (sourceinfo_t *si, int parc, char *parv[]); static void alis_cmd_help (sourceinfo_t *si, int parc, char *parv[]); static void alis_handler (sourceinfo_t *si, int parc, char *parv[]); command_t const alis_list = { "LIST", "Lists channels matching given parameters.", AC_NONE, ALIS_MAX_PARC, alis_cmd_list }; command_t const alis_help = { "HELP", "Displays contextual help information.", AC_NONE, 1, alis_cmd_help }; struct alis_query { char const *mask; char *topic; int min; int max; int show_mode; int show_topicwho; unsigned int mode; int mode_dir; int mode_key; int mode_limit; int skip; }; bool _modinit (module *m) { alis = add_service ("ALIS", "alis", me.name, "Channel Directory", alis_handler, alis_cmdtree); alis_cmdtree << alis_list; alis_cmdtree << alis_help; return true; } void _moddeinit () { alis_cmdtree >> alis_list; alis_cmdtree >> alis_help; del_service (alis); } static int alis_parse_mode (char const * const txt, int *key, int *limit) { int mode = 0; char const *text = txt; if (!text) return 0; while (*text) { switch (*text) { case 'l': *limit = 1; break; case 'k': *key = 1; break; default: mode |= mode_to_flag (*text); break; } text++; } return mode; } static int parse_alis (sourceinfo_t *si, int parc, char *parv[], struct alis_query *query) { int i = 0; char *opt = NULL, *arg = NULL; while ((opt = parv[i++])) { if (!strcasecmp (opt, "-min")) { if ((arg = parv[i++]) == NULL || (query->min = atoi (arg)) < 1) { command_fail (si, fault::badparams, "Invalid -min option"); return 0; } } else if (!strcasecmp (opt, "-max")) { if ((arg = parv[i++]) == NULL || (query->max = atoi (arg)) < 1) { command_fail (si, fault::badparams, "Invalid -max option"); return 0; } } else if (!strcasecmp (opt, "-skip")) { if ((arg = parv[i++]) == NULL || (query->skip = atoi (arg)) < 1) { command_fail (si, fault::badparams, "Invalid -skip option"); return 0; } } else if (!strcasecmp (opt, "-topic")) { query->topic = strtok (NULL, " "); } else if (!strcasecmp (opt, "-show")) { arg = parv[i++]; if (arg == NULL) { command_fail (si, fault::badparams, "Invalid -show option"); return 0; } if (arg[0] == 'm') { query->show_mode = 1; if (arg[1] == 't') query->show_topicwho = 1; } else if (arg[0] == 't') { query->show_topicwho = 1; if (arg[1] == 'm') query->show_mode = 1; } } else if (!strcasecmp (opt, "-mode")) { arg = parv[i++]; if (arg == NULL) { command_fail (si, fault::badparams, "Invalid -mode option"); return 0; } switch (*arg) { case '+': query->mode_dir = DIR_SET; break; case '-': query->mode_dir = DIR_UNSET; break; case '=': query->mode_dir = DIR_EQUAL; break; default: command_fail (si, fault::badparams, "Invalid -mode option"); return 0; } query->mode = alis_parse_mode (arg + 1, &query->mode_key, &query->mode_limit); if (query->mode == 0) { command_fail (si, fault::badparams, "Invalid -mode option"); return 0; } } else { command_fail (si, fault::badparams, "Invalid option %s", opt); return 0; } } return 1; } static void print_channel (sourceinfo_t *si, channel_t *c, struct alis_query *query) { int show_topicwho = query->show_topicwho; int show_topic = 1; char modestr[MAXEXTMODES + 60]; int i, j; /* cant show a topicwho, when a channel has no topic. */ if (!c->topic) { show_topicwho = 0; show_topic = 0; } if (query->show_mode) { j = 0; modestr[j++] = '+'; for (i = 0; i < MAXEXTMODES; i++) if (c->extmodes[i] != NULL) modestr[j++] = ignore_mode_list[i].mode; if (c->limit != 0) modestr[j++] = 'l'; if (c->key != NULL) modestr[j++] = 'k'; modestr[j] = '\0'; strlcat (modestr, flags_to_string (c->modes), sizeof modestr); } if (query->show_mode && show_topicwho && show_topic) command_success_nodata (si, "%-50s %-8s %3ld :%s (%s)", c->name, modestr, LIST_LENGTH (&c->members), c->topic, c->topic_setter); else if (query->show_mode) command_success_nodata (si, "%-50s %-8s %3ld :%s", c->name, modestr, LIST_LENGTH (&c->members), c->topic); else if (show_topicwho && show_topic) command_success_nodata (si, "%-50s %3ld :%s (%s)", c->name, LIST_LENGTH (&c->members), c->topic, c->topic_setter); else if (show_topic) command_success_nodata (si, "%-50s %3ld :%s", c->name, LIST_LENGTH (&c->members), c->topic); else command_success_nodata (si, "%-50s %3ld", c->name, LIST_LENGTH (&c->members)); } static int show_channel (channel_t *c, struct alis_query *query) { /* skip +s channels */ if (c->modes & CMODE_SEC) return 0; if ((int) LIST_LENGTH (&c->members) < query->min || (query->max && (int) LIST_LENGTH (&c->members) > query->max)) return 0; if (query->mode) { if (query->mode_dir == DIR_SET) { if (((c->modes & query->mode) == 0) || (query->mode_key && c->key[0] == '\0') || (query->mode_limit && !c->limit)) return 0; } else if (query->mode_dir == DIR_UNSET) { if ((c->modes & query->mode) || (query->mode_key && c->key[0] != '\0') || (query->mode_limit && c->limit)) return 0; } else if (query->mode_dir == DIR_EQUAL) { if ((c->modes != query->mode) || (query->mode_key && c->key[0] == '\0') || (query->mode_limit && !c->limit)) return 0; } } if (match (query->mask, c->name)) return 0; if (query->topic != NULL && match (query->topic, c->topic)) return 0; if (query->skip) { query->skip--; return 0; } return 1; } static void alis_cmd_list (sourceinfo_t *si, int parc, char *parv[]) { channel_t *c; struct alis_query query; int maxmatch = ALIS_MAX_MATCH; memset (&query, 0, sizeof (struct alis_query)); query.mask = parc >= 1 ? parv[0] : "*"; if (!parse_alis (si, parc - 1, parv + 1, &query)) return; logcommand (si, CMDLOG_GET, "LIST %s", query.mask); command_success_nodata (si, "Returning maximum of %d channel names matching '\2%s\2'", ALIS_MAX_MATCH, query.mask); /* hunting for one channel.. */ if (strchr (query.mask, '*') == NULL && strchr (query.mask, '?') == NULL) { if ((c = channel_find (query.mask)) != NULL) { if (!(c->modes & CMODE_SEC)) print_channel (si, c, &query); } command_success_nodata (si, "End of output"); return; } foreach (channel_pair &cp, chanlist) { c = cp.second; /* matches, so show it */ if (show_channel (c, &query)) { print_channel (si, c, &query); if (--maxmatch == 0) { command_success_nodata (si, "Maximum channel output reached"); break; } } } command_success_nodata (si, "End of output"); return; } static void alis_cmd_help (sourceinfo_t *si, int parc, char *parv[]) { command_help (si, alis_cmdtree); } static void alis_handler (sourceinfo_t *si, int parc, char *parv[]) { char orig[BUFSIZE]; char *cmd; char *text; /* this should never happen */ if (parv[0][0] == '&') { slog (LG_ERROR, "services(): got parv with local channel: %s", parv[0]); return; } /* make a copy of the original for debugging */ strlcpy (orig, parv[parc - 1], BUFSIZE); /* lets go through this to get the command */ cmd = strtok (parv[parc - 1], " "); text = strtok (NULL, ""); if (!cmd) return; if (*cmd == '\001') { handle_ctcp_common (si, cmd, text); return; } /* take the command through the hash table */ command_exec_split (alis, si, cmd, text, alis_cmdtree); }