New message processing

This commit is contained in:
nemunaire 2014-10-05 18:19:20 +02:00
commit dfde4c5f49
20 changed files with 519 additions and 325 deletions

View file

@ -23,14 +23,15 @@ import time
import shlex
from channel import Channel
from message import Message
import server
import message
from message.printer.IRC import IRC as IRCPrinter
from server.socket import SocketServer
class IRCServer(SocketServer):
class IRC(SocketServer):
def __init__(self, node, nick, owner, realname):
self.id = nick + "@" + node["host"] + ":" + node["port"]
self.printer = IRCPrinter
SocketServer.__init__(self,
node["host"],
node["port"],
@ -60,18 +61,18 @@ class IRCServer(SocketServer):
# Register CTCP capabilities
self.ctcp_capabilities = dict()
def _ctcp_clientinfo(msg):
def _ctcp_clientinfo(msg, cmds):
"""Response to CLIENTINFO CTCP message"""
return _ctcp_response(" ".join(self.ctcp_capabilities.keys()))
return " ".join(self.ctcp_capabilities.keys())
def _ctcp_dcc(msg):
def _ctcp_dcc(msg, cmds):
"""Response to DCC CTCP message"""
try:
ip = srv.toIP(int(msg.cmds[3]))
port = int(msg.cmds[4])
ip = srv.toIP(int(cmds[3]))
port = int(cmds[4])
conn = DCC(srv, msg.sender)
except:
return _ctcp_response("ERRMSG invalid parameters provided as DCC CTCP request")
return "ERRMSG invalid parameters provided as DCC CTCP request"
self.logger.info("Receive DCC connection request from %s to %s:%d", conn.sender, ip, port)
@ -80,27 +81,20 @@ class IRCServer(SocketServer):
conn.send_dcc("Hello %s!" % conn.nick)
else:
self.logger.error("DCC: unable to connect to %s:%d", ip, port)
return _ctcp_response("ERRMSG unable to connect to %s:%d" % (ip, port))
return "ERRMSG unable to connect to %s:%d" % (ip, port)
import bot
self.ctcp_capabilities["ACTION"] = lambda msg: print ("ACTION receive: %s" % msg.text)
self.ctcp_capabilities["ACTION"] = lambda msg, cmds: print ("ACTION receive: %s" % cmds)
self.ctcp_capabilities["CLIENTINFO"] = _ctcp_clientinfo
#self.ctcp_capabilities["DCC"] = _ctcp_dcc
self.ctcp_capabilities["FINGER"] = lambda msg: _ctcp_response(
"VERSION nemubot v%s" % bot.__version__)
self.ctcp_capabilities["NEMUBOT"] = lambda msg: _ctcp_response(
"NEMUBOT %s" % bot.__version__)
self.ctcp_capabilities["PING"] = lambda msg: _ctcp_response(
"PING %s" % " ".join(msg.cmds[1:]))
self.ctcp_capabilities["SOURCE"] = lambda msg: _ctcp_response(
"SOURCE https://github.com/nemunaire/nemubot")
self.ctcp_capabilities["TIME"] = lambda msg: _ctcp_response(
"TIME %s" % (datetime.now()))
self.ctcp_capabilities["USERINFO"] = lambda msg: _ctcp_response(
"USERINFO %s" % self.realname)
self.ctcp_capabilities["VERSION"] = lambda msg: _ctcp_response(
"VERSION nemubot v%s" % bot.__version__)
self.ctcp_capabilities["FINGER"] = lambda msg, cmds: "VERSION nemubot v%s" % bot.__version__
self.ctcp_capabilities["NEMUBOT"] = lambda msg, cmds: "NEMUBOT %s" % bot.__version__
self.ctcp_capabilities["PING"] = lambda msg, cmds: "PING %s" % " ".join(cmds[1:])
self.ctcp_capabilities["SOURCE"] = lambda msg, cmds: "SOURCE https://github.com/nemunaire/nemubot"
self.ctcp_capabilities["TIME"] = lambda msg, cmds: "TIME %s" % (datetime.now())
self.ctcp_capabilities["USERINFO"] = lambda msg, cmds: "USERINFO %s" % self.realname
self.ctcp_capabilities["VERSION"] = lambda msg, cmds: "VERSION nemubot v%s" % bot.__version__
self.logger.debug("CTCP capabilities setup: %s", ", ".join(self.ctcp_capabilities))
@ -190,6 +184,18 @@ class IRCServer(SocketServer):
self.write("JOIN " + msg.decode(msg.params[1]))
self.hookscmd["INVITE"] = _on_invite
# Handle CTCP requests
def _on_ctcp(msg):
if len(msg.params) != 2 or not msg.is_ctcp: return
cmds = msg.decode(msg.params[1][1:len(msg.params[1])-1]).split(' ')
if cmds[0] in self.ctcp_capabilities:
res = self.ctcp_capabilities[cmds[0]](msg, cmds)
else:
res = "ERRMSG Unknown or unimplemented CTCP request"
if res is not None:
self.write("NOTICE %s :\x01%s\x01" % (msg.nick, res))
self.hookscmd["PRIVMSG"] = _on_ctcp
def _open(self):
if SocketServer._open(self):
@ -215,31 +221,9 @@ class IRCServer(SocketServer):
if msg.cmd in self.hookscmd:
self.hookscmd[msg.cmd](msg)
else:
mes = msg.to_message()
mes.raw = msg.raw
if hasattr(mes, "receivers"):
# Private message: prepare response
for i in range(len(mes.receivers)):
if mes.receivers[i] == self.nick:
mes.receivers[i] = mes.nick
if (mes.cmd == "PRIVMSG" or mes.cmd == "NOTICE") and mes.is_ctcp:
if mes.cmds[0] in self.ctcp_capabilities:
res = self.ctcp_capabilities[mes.cmds[0]](mes)
else:
res = _ctcp_response("ERRMSG Unknown or unimplemented CTCP request")
if res is not None:
res = res % mes.nick
self.write(res)
else:
yield mes
def _ctcp_response(msg):
return "NOTICE %%s :\x01%s\x01" % msg
mes = msg.to_message(self)
if mes is not None:
yield mes
mgx = re.compile(b'''^(?:@(?P<tags>[^ ]+)\ )?
@ -303,6 +287,11 @@ class IRCMessage:
self.tags[key] = value
@property
def is_ctcp(self):
return self.cmd == "PRIVMSG" and len(self.params) == 2 and len(self.params[1]) > 1 and (self.params[1][0] == 0x01 or self.params[1][1] == 0x01)
def decode(self, s):
"""Decode the content string usign a specific encoding"""
if isinstance(s, bytes):
@ -313,8 +302,6 @@ class IRCMessage:
return s
def to_message(self):
return Message(self)
def to_irc_string(self, client=True):
"""Pretty print the message to close to original input string
@ -336,3 +323,43 @@ class IRCMessage:
res += " :" + self.decode(self.params[-1])
return res
def to_message(self, srv):
if self.cmd == "PRIVMSG" or self.cmd == "NOTICE":
receivers = self.decode(self.params[0]).split(',')
common_args = {
"server": srv.id,
"date": self.tags["time"],
"to": receivers,
"to_response": [r if r != srv.nick else self.nick for r in receivers],
"frm": self.nick
}
# If CTCP, remove 0x01
if self.is_ctcp:
text = self.decode(self.params[1][1:len(self.params[1])-1])
else:
text = self.decode(self.params[1])
if len(text) > 1 and text[0] == '!':
text = text[1:].strip()
# Split content by words
try:
args = shlex.split(text)
except ValueError:
args = text.split(' ')
return message.Command(cmd=args[0], args=args[1:], **common_args)
elif text.find(srv.nick) == 0 and len(text) > len(srv.nick) + 2 and text[len(srv.nick)] == ":":
text = text[len(srv.nick) + 1:].strip()
return message.DirectAsk(designated=srv.nick, message=text, **common_args)
else:
return message.TextMessage(message=text, **common_args)
return None