def _add_command(self, cmd, func): assert callable(func) if cmd in self.commands: log.error("Redefining command: %s" % cmd) else: log.debug("Registering command: %s" % cmd) self.commands[cmd] = func
def __init__(self, config, net=None): self._conf = None if net is not None and net.find("acl"): conffile = net.find("acl").get("file", None) elif config.find("acl") is not None: conffile = config.find("acl").get("file", None) else: log.debug("No ACL file to load") return if conffile is None: raise ConfigError("<acl> tag is missing the file attribute!") if not os.path.isabs(conffile): confdir = config.get('config', None) if not confdir: log.error("Unable to resolve relative path to ACL") return confdir = os.path.dirname(confdir) conffile = os.path.join(confdir, conffile) if not os.access(conffile, os.R_OK): raise ConfigError("Cannot read ACL file %s" % conffile) log.debug("Loading ACL file %s" % conffile) self._conf = ElementTree.parse(conffile)
def __init__(self, config, net=None): self._conf = None if net is not None and net.find("acl"): conffile = net.find("acl").get("file", None) elif config.find("acl") is not None: conffile = config.find("acl").get("file", None) else: log.debug("No ACL file to load") return if conffile is None: raise ConfigError("<acl> tag is missing the file attribute!"); if not os.path.isabs(conffile): confdir = config.get('config', None) if not confdir: log.error("Unable to resolve relative path to ACL") return confdir = os.path.dirname(confdir) conffile = os.path.join(confdir, conffile) if not os.access(conffile, os.R_OK): raise ConfigError("Cannot read ACL file %s" % conffile); log.debug("Loading ACL file %s" % conffile) self._conf = ElementTree.parse(conffile)
def msg(self, conn, event): if ('internal' in event and event['internal'] or event['sent_to'] == conn.nickname): return dbpool = conn.manager.dbpool for match in re.finditer(self._regex, event['text']): if match.group(2) == "++": inc = 1 else: inc = -1 log.debug("score: %s += %s" % (match.group(1), inc)) defer = dbpool.runOperation("INSERT INTO `score` " "(`name`, `value`, `nick`, `chan`, `date`) " "VALUES (%s, %s, %s, %s, FROM_UNIXTIME(%s)) " "ON DUPLICATE KEY UPDATE " "`value` = `value` + VALUES(`value`), " "`nick` = VALUES(`nick`), " "`chan` = VALUES(`chan`), " "`date` = VALUES(`date`)", (match.group(1), inc, event['sent_by'], event['sent_to'], event['time'])) defer.addErrback(log.error)
def check(_): if self._pending: log.debug("Waiting on %d plugin commands" % len(self._pending)) d = defer.DeferredList(self._pending, consumeErrors=True) d.addBoth(check) return d else: log.trace("All plugin commands complete")
def processEnded(self, reason): if isinstance(reason.value, error.ProcessDone): log.debug("Process ended", prefix=self._pid) reason = None else: log.warn(reason, prefix=self._pid) deferred = self._deferred self._deferred = None deferred.callback(reason)
def reload(self): """Reload all available plugins""" log.debug("Reloading all plugins...") # Is this the best way to do this? for module in modules.getModule(plugins.__name__).iterModules(): reload(module.load()) self._load()
def _handle_event(self, conn, event): if 'internal' in event and event['internal']: return conf = conn.manager.config if event['type'] == "command": commands = glob("%s/commands/%s" % (conf.get('root'), event['command'])) else: commands = glob("%s/hooks/%s/*" % (conf.get('root'), event['type'])) if not commands: return vars = os.environ.copy() for key, val in conf.items(): vars["HB_%s" % key.upper()] = str(val) if conn.network.id: vars['HB_NETWORK'] = conn.network.id vars['HB_NICK'] = conn.nickname vars['HB_XML'] = ElementTree.tostring(conn.manager.config) text = "" for key, val in event.iteritems(): if key == 'text': text = val else: vars['HBEV_%s' % key.upper()] = str(val) if 'PERL5LIB' in vars: vars['PERL5LIB'] = "%s:%s" % (conf.get('perl'), vars['PERL5LIB']) else: vars['PERL5LIB'] = conf.get('perl') if 'PYTHONPATH' in vars: vars['PYTHONPATH'] = ("%s:%s" % (conf.get('python'), vars['PYTHONPATH'])) else: vars['PYTHONPATH'] = conf.get('python') deferreds = [] for cmd in commands: if os.access(cmd, os.X_OK): log.debug("Running %s" % cmd) deferred = defer.Deferred() deferreds.append(deferred) proto = HBProcessProtocol(conn, event, deferred) reactor.spawnProcess(proto, cmd, [cmd], vars) if len(deferreds) == 1: return deferreds[0] elif len(deferreds) > 1: return defer.DeferredList(deferreds, consumeErrors=True)
def _load_sql(self, dump): """Execute a chunk of SQL from a file""" log.debug("Loading SQL from %s" % dump) try: dumpfd = open(dump) sql = dumpfd.read() dumpfd.close() except IOError, (errno, errstr): raise DBError("Failed to read %s: %s" % (dump, errstr))
def userQuit(self, user, msg): log.debug("%s quit: %s" % (user, msg)) for chan in self.channels.itervalues(): chan['users'].discard(user) event = { 'type': 'quit', 'user': user, 'text': msg, 'time': time.time() } self.manager.plugins.hook(self, event)
def userJoined(self, user, channel): log.debug("%s joined channel %s" % (user, channel)) self.channels[channel]['users'].add(user) event = { 'type': 'join', 'user': user, 'reply_to': channel, 'channel': channel, 'time': time.time() } self.manager.plugins.hook(self, event)
def msg(self, conn, event): if event["sent_by"] == conn.nickname: return message = event["text"].lower() for topping in self.toppings: if topping in message: if "no " + topping in message or "not " + topping in message: log.debug("Decrementing %s" % topping) self.toppings[topping] -= 1 else: log.debug("Incrementing %s" % topping) self.toppings[topping] += 1
def msg(self, conn, event): if "internal" in event and event["internal"] or event["sent_to"] == conn.nickname: return for match in re.finditer(self._regex, event["text"]): url = match.group(0) log.debug("bitly: Got URL %s" % url) d = defer.Deferred() d.addCallback(self.api.shorten) d.addCallback(self._reply_with_shortened_url, conn, event) reactor.callLater(0, d.callback, url)
def topicUpdated(self, user, channel, topic): log.debug("%s topic: %s" % (channel, topic)) self.channels[channel]['topic'] = topic event = { 'type': 'topic', 'user': user, 'reply_to': channel, 'channel': channel, 'text': topic, 'time': time.time() } self.manager.plugins.hook(self, event)
def userRenamed(self, oldname, newname): log.debug("%s changed to %s" % (oldname, newname)) for chan in self.channels.itervalues(): if oldname in chan['users']: chan['users'].discard(oldname) chan['users'].add(newname) event = { 'type': 'rename', 'old': oldname, 'new': newname, 'time': time.time() } self.manager.plugins.hook(self, event)
def userLeft(self, user, channel): log.debug("%s left channel %s" % (user, channel)) self.channels[channel]['users'].discard(user) # TODO: re-implement this so we can get the text event = { 'type': 'part', 'user': user, 'reply_to': channel, 'channel': channel, 'text': "", 'time': time.time() } self.manager.plugins.hook(self, event)
def userKicked(self, user, channel, kicker, msg): log.debug("%s kicked from %s by %s: %s" % (user, channel, kicker, msg)) self.channels[channel]['users'].discard(user) event = { 'type': 'kick', 'kicker': kicker, 'kickee': user, 'reply_to': channel, 'channel': channel, 'text': msg, 'time': time.time() } self.manager.plugins.hook(self, event)
def _set_version(self, version): """Update the schema version metadata""" if version <= 0: return cursor = self._db.cursor() log.debug("Setting schema version to %s" % version) try: cursor.execute( "INSERT `metadata` (`name` , `value`) " "VALUES ('schema', '%s') " "ON DUPLICATE KEY UPDATE `value` = %s", (version, version)) except MySQLdb.Error, (errno, errstr): raise DBError("DB error: [%s] %s" % (errno, errstr))
def _set_version(self, version): """Update the schema version metadata""" if version <= 0: return cursor = self._db.cursor() log.debug("Setting schema version to %s" % version) try: cursor.execute("INSERT `metadata` (`name` , `value`) " "VALUES ('schema', '%s') " "ON DUPLICATE KEY UPDATE `value` = %s", (version, version)) except MySQLdb.Error, (errno, errstr): raise DBError("DB error: [%s] %s"%(errno, errstr))
def irc_RPL_NAMREPLY(self, prefix, params): # Odd that twisted doesn't handle this one channel = params[2] users = params[3] log.debug("%s users: %s" % (channel, users)) users = [u.lstrip("+@") for u in users.split()] users.sort() # Is it safe to assume that a single NAMREPLY covers all users? self.channels[channel]['users'] = set(users) event = { 'type': 'names', 'channel': channel, 'users': users, 'time': time.time() } self.manager.plugins.hook(self, event)
def msg(self, conn, event): if ('internal' in event and event['internal'] or event['sent_to'] == conn.nickname): return dbpool = conn.manager.dbpool for match in re.finditer(self._regex, event['text']): if match.group(2) == "++": if match.group(1) == event['sent_by']: conn.msg( event['reply_to'], "%s: no self promotion! You lose 5 points." % event['sent_by']) inc = -5 else: inc = 1 else: if match.group(1) == event['sent_by']: conn.msg( event['reply_to'], "%s: Aww, cheer up! You can keep your point." % event['sent_by']) return else: inc = -1 log.debug("score: %s += %s" % (match.group(1), inc)) defer = dbpool.runOperation( "INSERT INTO `score` " "(`name`, `value`, `nick`, `chan`, `date`) " "VALUES (%s, %s, %s, %s, FROM_UNIXTIME(%s)) " "ON DUPLICATE KEY UPDATE " "`value` = `value` + VALUES(`value`), " "`nick` = VALUES(`nick`), " "`chan` = VALUES(`chan`), " "`date` = VALUES(`date`)", (match.group(1), inc, event['sent_by'], event['sent_to'], event['time'])) defer.addErrback(log.error)
def noticed(self, sent_by, sent_to, msg): sent_by = nick(sent_by) sent_to = nick(sent_to) log.debug("<%s> %s" % (sent_by, msg)) event = { 'type': 'notice', 'sent_by': sent_by, 'sent_to': sent_to, 'text': msg, 'time': time.time() } if sent_to == self.nickname: event['reply_to'] = sent_by event['private'] = True else: event['reply_to'] = sent_to event['private'] = False self.manager.plugins.hook(self, event)
def privmsg(self, sent_by, sent_to, msg): sent_by = nick(sent_by) sent_to = nick(sent_to) log.debug("<%s> %s" % (sent_by, msg)) event = { 'type': 'msg', 'sent_by': sent_by, 'sent_to': sent_to, 'text': msg, 'time': time.time() } if sent_to == self.nickname: event['reply_to'] = sent_by event['private'] = True else: event['reply_to'] = sent_to event['private'] = False self.manager.plugins.hook(self, event) match = self.COMMAND.match(msg) if match: command = match.group(1) text = match.group(2) text = text.strip() cmdevent = event.copy() cmdevent['type'] = "command" cmdevent['command'] = command cmdevent['text'] = text ok, reply = self.factory.acl.check(cmdevent) if reply: self.msg(event['reply_to'], reply) if ok: self.manager.plugins.command(self, cmdevent)
def check(self, event): """Check if a command can be run by a user. Returns a tuple: (True/False, message) """ if self._conf is None: acl = None elif event['private']: acl = self.check_private(event['command'], event['sent_by']) else: acl = self.check_public(event['command'], event['sent_by'], event['sent_to']) if acl is None: log.debug("No acl") return (True, "") else: log.debug("Using acl: %s" % ElementTree.tostring(acl).strip()) action = acl.get("action", "") if action == "" or action not in ("allow", "deny"): log.error('Invalid acl action="%s", allowing.' % action) return (action != "deny", acl.get("msg", ""))
def readConnectionLost(self): log.debug("Lost read connection.") reactor.callLater(0,self.transport.loseConnection)
def connectionLost(self, reason): log.debug("Lost connection.")
def connectionMade(self): log.debug("New connection.")
def connectionMade(self): self._pid = str(self.transport.pid) log.debug("Process started", prefix=self._pid)
def _connected(connection): log.debug("Created database connection...")
def readConnectionLost(self): log.debug("Lost read connection.") reactor.callLater(0, self.transport.loseConnection)