diff --git a/DrBotIRC.py b/DrBotIRC.py index ae0c95b..47f174b 100644 --- a/DrBotIRC.py +++ b/DrBotIRC.py @@ -17,6 +17,7 @@ along with this program. If not, see . """ +import bisect import copy from ConfigParser import NoOptionError, NoSectionError import logging @@ -213,6 +214,8 @@ class DrBotIRC(irclib.IRC): self.config = config self.xmlrpc = None + self.regex_handlers = dict() + # handle SIGINT signal.signal(signal.SIGINT, self.sigint_handler) @@ -257,8 +260,62 @@ class DrBotIRC(irclib.IRC): return self.server + def add_global_regex_handler(self, event, regex, handler, priority=0): + """Adds a global handler function for a specific event type and regex. + + The handler function is called whenever the specified event is + triggered in any of the connections and the regex matches. + See documentation for the Event class. + + The handler functions are called in priority order (lowest + number is highest priority). If a handler function returns + "NO MORE", no more handlers will be called. + + This is basically an extension of add_global_handler(), either may + work, though it turns out most modules probably want this one. + + The provided method should take as arguments: + * nick the nick creating the event, or None + * userhost the userhost creating the event, or None + * event the raw IRC event, which may be None + * from_admin whether or not the event came from an admin + * groups list of match.groups(), from re.search() + + Args: + event event type (a string), as in numeric_events + regex regex string to match before doing callback invocation + handler callback function to invoke + priority integer, the lower number, the higher priority + + """ + + if not event in self.regex_handlers: + self.regex_handlers[event] = [] + bisect.insort(self.regex_handlers[event], ((priority, regex, handler))) + + def remove_global_regex_handler(self, event, regex, handler): + """Removes a global regex handler function. + + Args: + event event type (a string), as in numeric_events + regex regex string that was used in matching + handler callback function to remove + + Returns: + 1 on success, otherwise 0. + + """ + + if not event in self.regex_handlers: + return 0 + + for h in self.regex_handlers[event]: + if regex == h[1] and handler == h[2]: + self.regex_handlers[event].remove(h) + return 1 + def _handle_event(self, connection, event): - """Override event handler to do recursion. + """Override event handler to do recursion and regex checking. Args: connection source connection @@ -287,6 +344,41 @@ class DrBotIRC(irclib.IRC): self.try_recursion(connection, event) self.try_alias(connection, event) + nick = None + userhost = None + admin = False + + if event.source() is not None: + nick = irclib.nm_to_n(event.source()) + try: + userhost = irclib.nm_to_uh(event.source()) + except IndexError: pass + + try: + if userhost == self.config.get('dr.botzo', 'admin_userhost'): + admin = True + except NoOptionError: pass + + # try regex handlers first, since they're more specific + rh = self.regex_handlers + trh = sorted(rh.get('all_events', []) + rh.get(event.eventtype(), [])) + for handler in trh: + try: + prio, regex, method = handler + for line in event.arguments(): + match = re.search(regex, line) + if match: + log.debug("pattern matched, calling " + "{0:s}".format(method)) + # pattern matched, call method with pattern groups + ret = method(nick, userhost, event, admin, + match.groups()) + if ret == 'NO MORE': + return + except Exception as e: + log.error("exception floated up to DrBotIrc!") + log.exception(e) + h = self.handlers th = sorted(h.get('all_events', []) + h.get(event.eventtype(), [])) for handler in th: @@ -335,6 +427,41 @@ class DrBotIRC(irclib.IRC): replies = [] + nick = None + userhost = None + admin = False + + if event.source() is not None: + nick = irclib.nm_to_n(event.source()) + try: + userhost = irclib.nm_to_uh(event.source()) + except IndexError: pass + + try: + if userhost == self.config.get('dr.botzo', 'admin_userhost'): + admin = True + except NoOptionError: pass + + # try regex handlers first, since they're more specific + rh = self.regex_handlers + trh = sorted(rh.get('all_events', []) + rh.get(event.eventtype(), [])) + for handler in trh: + try: + prio, regex, method = handler + for line in event.arguments(): + match = re.search(regex, line) + if match: + log.debug("pattern matched, calling " + "{0:s}".format(method)) + # pattern matched, call method with pattern groups + ret = method(nick, userhost, event, admin, + match.groups()) + if ret: + replies.append(ret) + except Exception as e: + log.error("exception floated up to DrBotIrc!") + log.exception(e) + h = self.handlers th = sorted(h.get('all_events', []) + h.get(event.eventtype(), [])) for handler in th: