--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/fixbot/irc.py Mon Sep 15 00:27:05 2008 +0300
@@ -0,0 +1,156 @@
+from twisted.words.protocols import irc
+from twisted.internet import protocol
+from twisted.python import log
+import traceback
+
+import buffer
+
+class ReplyException (Exception) :
+ def __init__ (self, reply) :
+ self.reply = reply
+
+class Client (irc.IRCClient, object) :
+ """
+ Fixme IRC bot
+ """
+
+ def __init__ (self) :
+ # can't config yet
+ pass
+
+ # housekeeping
+ def connectionMade (self) :
+ self.nexus = self.factory.nexus
+
+ self.nickname = self.factory.nickname
+ self.username = self.factory.username
+ self.channel = self.factory.channel
+
+ log.msg("IRC Client connected, using username=%s, nickname=%s" % (self.username, self.nickname))
+
+ super(Client, self).connectionMade()
+
+ def connectionLost (self, reason) :
+ log.msg("Connection lost: %s" % reason)
+ super(Client, self).connectionLost(reason)
+
+ def signedOn (self) :
+ log.msg("Signed on, joining channel %s" % self.channel)
+ self.join(self.channel)
+
+ def joined (self, channel) :
+ log.msg("Joined channel %s" % channel)
+
+ self.factory.connected(self)
+
+ # our actual functionality
+ def send (self, msg) :
+ msg = str(msg)
+
+ if len(msg) > 480 :
+ log.msg("truncating: %s" % msg)
+ msg = msg[:480] + "..."
+
+ msg = msg.replace("\n", "\\n").replace("\r", "\\r").replace("\0", "\\0")
+
+ self.notice(CHANNEL, msg)
+
+ def sendEvent (self, event) :
+ self.send("[%s.%s] %s" % (event.module.name, event.type, event.msg))
+
+ def moduleConnected (self, module, addr) :
+ self.send("{modules.%s} connected from %s:%d, version %s" % (module.name, addr.host, addr.port, module.version))
+
+ def moduleDisconnected (self, module, reason) :
+ self.send("{modules.%s} disconnected: %s" % (module.name, reason))
+
+ class _noDefault : pass
+
+ def _lookupCommand (self, command, default=_noDefault) :
+ if '.' in command :
+ raise ReplyException("No support for module commands yet :P")
+ else :
+ method = getattr(self, "cmd_%s" % command, None)
+
+ if method :
+ return method
+ elif default is self._noDefault :
+ raise ReplyException("No such command '%s'. See `help commands'" % command)
+ else :
+ return default
+
+ def privmsg (self, user, channel, message) :
+ if message.lower().startswith(self.nickname.lower() + ':'):
+ me, command = message.split(":", 1)
+
+ args = command.strip().split()
+ command = args.pop(0)
+
+ try :
+ method = self._lookupCommand(command)
+
+ reply = method(*args)
+
+ if reply :
+ self.send(reply)
+
+ except ReplyException, e :
+ self.send(e.reply)
+
+ except Exception, e :
+ self.send("Error: %s: %s" % (e.__class__.__name__, e))
+ traceback.print_exc()
+
+ def cmd_help (self, cmd="help") :
+ """help <command|module> - Display help about the given command or module"""
+
+ method = self._lookupCommand(cmd, None)
+
+ if method :
+ return method.__doc__
+ else :
+ try :
+ module, addr = self.nexus.getModuleInfo(cmd)
+
+ return "%s is version %d from %s:%d. Events: %s. See `commands %s' for a list of commands" % (module.name, module.version, addr.host, addr.port, ', '.join(module.event_types), module.name)
+
+ except KeyError :
+ raise ReplyException("No command/module called `%s'. See `help commands'" % cmd)
+
+ def cmd_commands (self, module=None) :
+ """commands [<module>] - Show primary commands, or commands in the given module (see `help modules')"""
+
+ if module :
+ raise ReplyException("No support for module commands yet :P")
+ else :
+ return "Commands: %s" % ', '.join(
+ attr_name.split('_', 1)[1]
+ for attr_name in Client.__dict__.iterkeys()
+ if attr_name.startswith("cmd_")
+ )
+
+ def cmd_modules (self) :
+ """modules - Show a list of connected modules"""
+
+ return "Modules: %s" % ', '.join(
+ module.name
+ for module in self.nexus.getModules()
+ )
+
+class Factory (protocol.ClientFactory) :
+ protocol = Client
+
+ def __init__ (self, nexus, nickname, username, channel) :
+ self.nexus = nexus
+
+ # config
+ self.nickname = nickname
+ self.username = username
+ self.channel = channel
+
+ # don't have a connection yet
+ self.connection = None
+
+ def connected (self, connection) :
+ self.connection = connection
+