from twisted.words.protocols import irc
from twisted.internet import protocol
from twisted.python import log
import traceback
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(self.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" % (module.name, addr))
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 from %s. See `commands %s' for a list of commands" % (module.name, addr, 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