1
0
Fork 0

Introducing new hooks manager

Currently, the manager use a naive implementation, this is
	mainly for architectural testing purpose.
This commit is contained in:
nemunaire 2014-09-01 19:21:54 +02:00
parent 29819c7874
commit 3bc53bb4ef
14 changed files with 343 additions and 438 deletions

219
bot.py
View File

@ -32,6 +32,7 @@ __author__ = 'nemunaire'
from consumer import Consumer, EventConsumer, MessageConsumer
from event import ModuleEvent
import hooks
from hooksmanager import HooksManager
from networkbot import NetworkBot
from server.IRC import IRCServer
from server.DCC import DCC
@ -77,7 +78,11 @@ class Bot(threading.Thread):
self.event_timer = None
# Own hooks
self.hooks = hooks.MessagesHook(self, self)
self.hooks = HooksManager()
def in_ping(msg):
if re.match("^ *(m[' ]?entends?[ -]+tu|h?ear me|do you copy|ping)", msg.text, re.I) is not None:
return response.Response(msg.sender, message="pong", channel=msg.receivers, nick=msg.nick)
self.hooks.add_hook(hooks.Hook(in_ping), "in", "PRIVMSG")
# Other known bots, making a bots network
self.network = dict()
@ -88,10 +93,6 @@ class Bot(threading.Thread):
self.cnsr_thrd = list()
self.cnsr_thrd_size = -1
self.hooks.add_hook("irc_hook",
hooks.Hook(self.treat_prvmsg, "PRIVMSG"),
self)
def run(self):
from server import _rlist, _wlist, _xlist
@ -299,9 +300,6 @@ class Bot(threading.Thread):
def add_server(self, node, nick, owner, realname):
"""Add a new server to the context"""
srv = IRCServer(node, nick, owner, realname)
srv.add_hook = lambda h: self.hooks.add_hook("irc_hook", h, self)
srv.add_networkbot = self.add_networkbot
srv.send_bot = lambda d: self.send_networkbot(srv, d)
#srv.register_hooks()
if srv.id not in self.servers:
self.servers[srv.id] = srv
@ -348,7 +346,7 @@ class Bot(threading.Thread):
self.modules[name].unload(self)
# Remove registered hooks
for (s, h) in self.modules[name].REGISTERED_HOOKS:
self.hooks.del_hook(s, h)
self.hooks.del_hook(h, s)
# Remove registered events
for e in self.modules[name].REGISTERED_EVENTS:
self.del_event(e)
@ -361,7 +359,7 @@ class Bot(threading.Thread):
def receive_message(self, srv, raw_msg, private=False, data=None):
"""Queued the message for treatment"""
#print (raw_msg)
#print("READ", raw_msg)
self.cnsr_queue.put_nowait(MessageConsumer(srv, raw_msg, datetime.now(), private, data))
# Launch a new thread if necessary
@ -399,57 +397,6 @@ class Bot(threading.Thread):
self.stop = True
# Hooks cache
def create_cache(self, name):
if name not in self.hooks_cache:
if isinstance(self.hooks.__dict__[name], list):
self.hooks_cache[name] = list()
# Start by adding locals hooks
for h in self.hooks.__dict__[name]:
tpl = (h, 0, self.hooks.__dict__[name], self.hooks.bot)
self.hooks_cache[name].append(tpl)
# Now, add extermal hooks
level = 0
while level == 0 or lvl_exist:
lvl_exist = False
for ext in self.network:
if len(self.network[ext].hooks) > level:
lvl_exist = True
for h in self.network[ext].hooks[level].__dict__[name]:
if h not in self.hooks_cache[name]:
self.hooks_cache[name].append((h, level + 1,
self.network[ext].hooks[level].__dict__[name], self.network[ext].hooks[level].bot))
level += 1
elif isinstance(self.hooks.__dict__[name], dict):
self.hooks_cache[name] = dict()
# Start by adding locals hooks
for h in self.hooks.__dict__[name]:
self.hooks_cache[name][h] = (self.hooks.__dict__[name][h], 0,
self.hooks.__dict__[name],
self.hooks.bot)
# Now, add extermal hooks
level = 0
while level == 0 or lvl_exist:
lvl_exist = False
for ext in self.network:
if len(self.network[ext].hooks) > level:
lvl_exist = True
for h in self.network[ext].hooks[level].__dict__[name]:
if h not in self.hooks_cache[name]:
self.hooks_cache[name][h] = (self.network[ext].hooks[level].__dict__[name][h], level + 1, self.network[ext].hooks[level].__dict__[name], self.network[ext].hooks[level].bot)
level += 1
else:
raise Exception(name + " hook type unrecognized")
return self.hooks_cache[name]
# Treatment
def check_rest_times(self, store, hook):
@ -462,48 +409,6 @@ class Bot(threading.Thread):
elif isinstance(store, list):
store.remove(hook)
def treat_pre(self, msg, srv):
"""Treat a message before all other treatment"""
# Treat all messages starting with 'nemubot:' as distinct commands
if msg.cmd == "PRIVMSG" and msg.text.find("%s:"%srv.nick) == 0:
# Remove the bot name
msg.text = msg.text[len(srv.nick)+1:].strip()
msg.parse_content()
msg.private = True
for h, lvl, store, bot in self.create_cache("all_pre"):
if h.is_matching(None, server=srv):
h.run(msg, self.create_cache)
self.check_rest_times(store, h)
def treat_post(self, res):
"""Treat a message before send"""
for h, lvl, store, bot in self.create_cache("all_post"):
if h.is_matching(None, channel=res.channel, server=res.server):
c = h.run(res)
self.check_rest_times(store, h)
if not c:
return False
return True
def treat_irc(self, msg, srv):
"""Treat all incoming IRC commands"""
treated = list()
irc_hooks = self.create_cache("irc_hook")
if msg.cmd in irc_hooks:
(hks, lvl, store, bot) = irc_hooks[msg.cmd]
for h in hks:
if h.is_matching(msg.cmd, server=srv):
res = h.run(msg, srv, msg.cmd)
if res is not None and res != False:
treated.append(res)
self.check_rest_times(store, h)
return treated
def treat_prvmsg_ask(self, msg, srv):
# Treat ping
@ -559,114 +464,6 @@ class Bot(threading.Thread):
return res
def treat_cmd(self, msg, srv):
"""Treat a command message"""
treated = list()
# First, treat simple hook
cmd_hook = self.create_cache("cmd_hook")
if msg.cmds[0] in cmd_hook:
(hks, lvl, store, bot) = cmd_hook[msg.cmds[0]]
for h in hks:
if h.is_matching(msg.cmds[0], channel=msg.receivers, server=srv) and (msg.private or lvl == 0 or bot.nick not in srv.channels[msg.receivers].people):
res = h.run(msg, strcmp=msg.cmds[0])
if res is not None and res != False:
treated.append(res)
self.check_rest_times(store, h)
# Then, treat regexp based hook
cmd_rgxp = self.create_cache("cmd_rgxp")
for hook, lvl, store, bot in cmd_rgxp:
if hook.is_matching(msg.cmds[0], msg.receivers, server=srv) and (msg.private or lvl == 0 or bot.nick not in srv.channels[msg.receivers].people):
res = hook.run(msg)
if res is not None and res != False:
treated.append(res)
self.check_rest_times(store, hook)
# Finally, treat default hooks if not catched before
cmd_default = self.create_cache("cmd_default")
for hook, lvl, store, bot in cmd_default:
if treated:
break
res = hook.run(msg)
if res is not None and res != False:
treated.append(res)
self.check_rest_times(store, hook)
return treated
def treat_ask(self, msg, srv):
"""Treat an ask message"""
treated = list()
# First, treat simple hook
ask_hook = self.create_cache("ask_hook")
if msg.text in ask_hook:
hks, lvl, store, bot = ask_hook[msg.text]
for h in hks:
if h.is_matching(msg.text, channel=msg.receivers, server=srv) and (msg.private or lvl == 0 or bot.nick not in srv.channels[msg.receivers].people):
res = h.run(msg, strcmp=msg.text)
if res is not None and res != False:
treated.append(res)
self.check_rest_times(store, h)
# Then, treat regexp based hook
ask_rgxp = self.create_cache("ask_rgxp")
for hook, lvl, store, bot in ask_rgxp:
if hook.is_matching(msg.text, channel=msg.receivers, server=srv) and (msg.private or lvl == 0 or bot.nick not in srv.channels[msg.receivers].people):
res = hook.run(msg, strcmp=msg.text)
if res is not None and res != False:
treated.append(res)
self.check_rest_times(store, hook)
# Finally, treat default hooks if not catched before
ask_default = self.create_cache("ask_default")
for hook, lvl, store, bot in ask_default:
if treated:
break
res = hook.run(msg)
if res is not None and res != False:
treated.append(res)
self.check_rest_times(store, hook)
return treated
def treat_answer(self, msg, srv):
"""Treat a normal message"""
treated = list()
# First, treat simple hook
msg_hook = self.create_cache("msg_hook")
if msg.text in msg_hook:
hks, lvl, store, bot = msg_hook[msg.text]
for h in hks:
if h.is_matching(msg.text, channel=msg.receivers, server=srv) and (msg.private or lvl == 0 or bot.nick not in srv.channels[msg.receivers].people):
res = h.run(msg, strcmp=msg.text)
if res is not None and res != False:
treated.append(res)
self.check_rest_times(store, h)
# Then, treat regexp based hook
msg_rgxp = self.create_cache("msg_rgxp")
for hook, lvl, store, bot in msg_rgxp:
if hook.is_matching(msg.text, channel=msg.receivers, server=srv) and (msg.private or lvl == 0 or bot.nick not in srv.channels[msg.receivers].people):
res = hook.run(msg, strcmp=msg.text)
if res is not None and res != False:
treated.append(res)
self.check_rest_times(store, hook)
# Finally, treat default hooks if not catched before
msg_default = self.create_cache("msg_default")
for hook, lvl, store, bot in msg_default:
if len(treated) > 0:
break
res = hook.run(msg)
if res is not None and res != False:
treated.append(res)
self.check_rest_times(store, hook)
return treated
def _ctcp_response(sndr, msg):
return response.Response(sndr, msg, ctcp=True)

View File

@ -42,26 +42,151 @@ class MessageConsumer:
self.prvt = prvt
self.data = data
self.msgs = list()
self.responses = None
def treat_in(self, context, msg):
"""Treat the input message"""
if msg.cmd == "PING":
self.srv.write("%s :%s" % ("PONG", msg.params[0]))
elif hasattr(msg, "receivers"):
if msg.receivers:
# All messages
context.treat_pre(msg, self.srv)
return context.treat_irc(msg, self.srv)
def first_treat(self, msg):
"""Qualify a new message/response
def treat_out(self, context, res):
"""Treat the output message"""
if isinstance(res, list):
for r in res:
if r is not None: self.treat_out(context, r)
Argument:
msg -- The Message or Response to qualify
"""
elif isinstance(res, response.Response):
# Define the destination server
if not hasattr(msg, "qual") or msg.qual is None:
# Assume this is a message with no particulariry
msg.qual = "def"
# Define the source server if not already done
if not hasattr(msg, "server") or msg.server is None:
msg.server = self.srv.id
if isinstance(msg, Message):
if msg.cmd == "PRIVMSG" or msg.cmd == "NOTICE":
msg.is_owner = (msg.nick == self.srv.owner)
msg.private = msg.private or (len(msg.receivers) == 1 and msg.receivers[0] == self.srv.nick)
if msg.private:
msg.qual = "ask"
# Remove nemubot:
if msg.qual != "cmd" and msg.text.find(self.srv.nick) == 0 and len(msg.text) > len(self.srv.nick) + 2 and msg.text[len(self.srv.nick)] == ":":
msg.text = msg.text[len(self.srv.nick) + 1:].strip()
msg.qual = "ask"
return msg
def pre_treat(self, hm):
"""Modify input Messages
Arguments:
hm -- Hooks manager
"""
new_msg = list()
new_msg += self.msgs
self.msgs = list()
while len(new_msg) > 0:
msg = new_msg.pop(0)
for h in hm.get_hooks("pre", msg.cmd, msg.qual):
if h.match(message=msg, server=self.srv):
res = h.run(msg)
if isinstance(res, list):
for i in xrange(len(res)):
if res[i] == msg:
res.pop(i)
break
new_msg += res
elif res is not None and res != msg:
new_msg.append(res)
msg = None
break
elif res is None or res == False:
msg = None
break
if msg is not None:
self.msgs.append(msg)
def in_treat(self, hm):
"""Treat Messages and store responses
Arguments:
hm -- Hooks manager
"""
self.responses = list()
for msg in self.msgs:
for h in hm.get_hooks("in", msg.cmd, msg.qual):
if msg.cmd == "PING":
self.srv.write("%s :%s" % ("PONG", msg.params[0]))
elif h.match(message=msg, server=self.srv):
res = h.run(msg)
if isinstance(res, list):
self.responses += res
elif res is not None:
self.responses.append(res)
def post_treat(self, hm):
"""Modify output Messages
Arguments:
hm -- Hooks manager
"""
new_msg = list()
new_msg += self.responses
self.responses = list()
while len(new_msg) > 0:
msg = self.first_treat(new_msg.pop(0))
for h in hm.get_hooks("post"):
if h.match(message=msg, server=self.srv):
res = h.run(msg)
if isinstance(res, list):
for i in xrange(len(res)):
if res[i] == msg:
res.pop(i)
break
new_msg += res
elif res is not None and res != msg:
new_msg.append(res)
msg = None
break
elif res is None or res == False:
msg = None
break
if msg is not None:
self.responses.append(msg)
def run(self, context):
"""Create, parse and treat the message"""
try:
# Parse and create the original message
msg = Message(self.raw, self.time, self.prvt)
self.first_treat(msg)
self.msgs.append(msg)
# Run pre-treatment: from Message to [ Message ]
self.pre_treat(context.hooks)
# Run in-treatment: from Message to [ Response ]
if len(self.msgs) > 0:
self.in_treat(context.hooks)
# Run post-treatment: from Response to [ Response ]
if self.responses is not None and len(self.responses) > 0:
self.post_treat(context.hooks)
except:
logger.exception("Error occurred during the processing of the message: %s", self.raw)
return
#return self.responses
for res in self.responses:
to_server = None
if res.server is None:
to_server = self.srv
@ -75,39 +200,7 @@ class MessageConsumer:
return False
# Sent the message only if treat_post authorize it
if context.treat_post(res):
if type(res.channel) != list:
res.channel = [ res.channel ]
for channel in res.channel:
if channel is not None and channel != to_server.nick:
to_server.write("%s %s :%s" % ("PRIVMSG", channel, res.get_message()))
else:
channel = res.sender.split("!")[0]
to_server.write("%s %s :%s" % ("NOTICE" if res.is_ctcp else "PRIVMSG", channel, res.get_message()))
elif res is not None:
logger.error("Unrecognized response type: %s", res)
def run(self, context):
"""Create, parse and treat the message"""
try:
msg = Message(self.raw, self.time, self.prvt)
msg.server = self.srv.id
if msg.cmd == "PRIVMSG":
msg.is_owner = (msg.nick == self.srv.owner)
msg.private = msg.private or (len(msg.receivers) == 1 and msg.receivers[0] == self.srv.nick)
res = self.treat_in(context, msg)
except:
logger.exception("Error occurred during the processing of the message: %s", self.raw)
return
# Send message
self.treat_out(context, res)
# Inform that the message has been treated
#self.srv.msg_treated(self.data)
to_server.send_response(res)
class EventConsumer:
"""Store a event before treating"""

157
hooks.py
View File

@ -24,151 +24,6 @@ from exception import IRCException
logger = logging.getLogger("nemubot.hooks")
class MessagesHook:
def __init__(self, context, bot):
self.context = context
self.bot = bot
# Store specials hooks
self.all_pre = list() # Treated before any parse
self.all_post = list() # Treated before send message to user
# Store IRC commands hooks
self.irc_hook = dict()
# Store direct hooks
self.cmd_hook = dict()
self.ask_hook = dict()
self.msg_hook = dict()
# Store regexp hooks
self.cmd_rgxp = list()
self.ask_rgxp = list()
self.msg_rgxp = list()
# Store default hooks (after other hooks if no match)
self.cmd_default = list()
self.ask_default = list()
self.msg_default = list()
def add_hook(self, store, hook, module_src=None):
"""Insert in the right place a hook into the given store"""
logger.info("Adding hook '%s' to store '%s' from module '%s'", hook, store, module_src)
if module_src is None:
logger.warn("No source module was passed to add_hook function, "
"please fix it in order to be compatible with unload "
"feature")
if store in self.context.hooks_cache:
logger.debug("Cleaning hooks cache for %s", store)
del self.context.hooks_cache[store]
if not hasattr(self, store):
# TODO: raise custom exception, this is a user problem, not internal one!
logger.error("Unrecognized hook store: %s", store)
return
attr = getattr(self, store)
if isinstance(attr, dict) and hook.name is not None:
if hook.name not in attr:
attr[hook.name] = list()
attr[hook.name].append(hook)
if hook.end is not None:
if hook.end not in attr:
attr[hook.end] = list()
attr[hook.end].append(hook)
elif isinstance(attr, list):
attr.append(hook)
else:
logger.critical("Unrecognized hook store type: %s", type(attr))
return
if module_src is not None and hasattr(module_src, "REGISTERED_HOOKS"):
module_src.REGISTERED_HOOKS.append((store, hook))
def register_hook_attributes(self, store, module, node):
if node.hasAttribute("data"):
data = node["data"]
else:
data = None
if node.hasAttribute("name"):
self.add_hook(store + "_hook", Hook(getattr(module, node["call"]),
node["name"], data=data),
module)
elif node.hasAttribute("regexp"):
self.add_hook(store + "_rgxp", Hook(getattr(module, node["call"]),
regexp=node["regexp"], data=data),
module)
def register_hook(self, module, node):
"""Create a hook from configuration node"""
if node.name == "message" and node.hasAttribute("type"):
if node["type"] == "cmd" or node["type"] == "all":
self.register_hook_attributes("cmd", module, node)
if node["type"] == "ask" or node["type"] == "all":
self.register_hook_attributes("ask", module, node)
if (node["type"] == "msg" or node["type"] == "answer" or
node["type"] == "all"):
self.register_hook_attributes("answer", module, node)
def clear(self):
for h in self.all_pre:
self.del_hook("all_pre", h)
for h in self.all_post:
self.del_hook("all_post", h)
for l in self.irc_hook:
for h in self.irc_hook[l]:
self.del_hook("irc_hook", h)
for l in self.cmd_hook:
for h in self.cmd_hook[l]:
self.del_hook("cmd_hook", h)
for l in self.ask_hook:
for h in self.ask_hook[l]:
self.del_hook("ask_hook", h)
for l in self.msg_hook:
for h in self.msg_hook[l]:
self.del_hook("msg_hook", h)
for h in self.cmd_rgxp:
self.del_hook("cmd_rgxp", h)
for h in self.ask_rgxp:
self.del_hook("ask_rgxp", h)
for h in self.msg_rgxp:
self.del_hook("msg_rgxp", h)
for h in self.cmd_default:
self.del_hook("cmd_default", h)
for h in self.ask_default:
self.del_hook("ask_default", h)
for h in self.msg_default:
self.del_hook("msg_default", h)
def del_hook(self, store, hook, module_src=None):
"""Remove a registered hook from a given store"""
if store in self.context.hooks_cache:
del self.context.hooks_cache[store]
if not hasattr(self, store):
logger.warn("unrecognized hook store type")
return
attr = getattr(self, store)
if isinstance(attr, dict) and hook.name is not None:
if hook.name in attr:
attr[hook.name].remove(hook)
if hook.end is not None and hook.end in attr:
attr[hook.end].remove(hook)
else:
attr.remove(hook)
if module_src is not None:
module_src.REGISTERED_HOOKS.remove((store, hook))
class Hook:
"""Class storing hook informations"""
def __init__(self, call, name=None, data=None, regexp=None, channels=list(), server=None, end=None, call_end=None, help=None):
@ -186,6 +41,18 @@ class Hook:
self.channels = channels
self.help = help
def match(self, message, channel=None, server=None):
if isinstance(message, Response):
return self.is_matching(None, channel, server)
elif message.qual == "cmd":
return self.is_matching(message.cmds[0], channel, server)
elif hasattr(message, "text"):
return self.is_matching(message.text, channel, server)
elif len(message.params) > 0:
return self.is_matching(message.params[0], channel, server)
else:
return self.is_matching(message.cmd, channel, server)
def is_matching(self, strcmp, channel=None, server=None):
"""Test if the current hook correspond to the message"""
return (channel is None or len(self.channels) <= 0 or

107
hooksmanager.py Normal file
View File

@ -0,0 +1,107 @@
# -*- coding: utf-8 -*-
# Nemubot is a smart and modulable IM bot.
# Copyright (C) 2012-2014 nemunaire
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
class HooksManager:
"""Class to manage hooks"""
def __init__(self):
"""Initialize the manager"""
self.hooks = dict()
def add_hook(self, hook, *triggers):
"""Add a hook to the manager
Argument:
hook -- a Hook instance
triggers -- string that trigger the hook
"""
trigger = "_".join(triggers)
if trigger not in self.hooks:
self.hooks[trigger] = list()
#print("ADD hook: %s => %s" % (trigger, hook))
self.hooks[trigger].append(hook)
def del_hook(self, hook=None, *triggers):
"""Remove the given hook from the manager
Return:
Boolean value reporting the deletion success
Argument:
triggers -- trigger string to remove
Keyword argument:
hook -- a Hook instance to remove from the trigger string
"""
trigger = "_".join(triggers)
if trigger in self.hooks:
if hook is None:
del self.hooks[trigger]
return True
else:
return self.hooks[trigger].remove(hook)
return False
def get_hooks(self, *triggers):
"""Returns list of trigger hooks that match the given trigger string
Argument:
triggers -- the trigger string
Keyword argument:
data -- Data to pass to the hook as argument
"""
trigger = "_".join(triggers)
res = list()
for key in self.hooks:
if trigger.find(key) == 0:
res += self.hooks[key]
#print("GET hooks: %s => %d" % (trigger, len(res)))
return res
def exec_hook(self, *triggers, **data):
"""Trigger hooks that match the given trigger string
Argument:
trigger -- the trigger string
Keyword argument:
data -- Data to pass to the hook as argument
"""
trigger = "_".join(triggers)
for key in self.hooks:
if trigger.find(key) == 0:
for hook in self.hooks[key]:
hook.run(**data)

View File

@ -159,15 +159,19 @@ class ModuleLoader(SourceLoader):
def send_response(server, res):
if server in self.context.servers:
return self.context.servers[server].send_response(res, None)
return self.context.servers[server].send_response(res)
else:
module.logger.error("Try to send a message to the unknown server: %s", server)
return False
def add_hook(store, hook):
return self.context.hooks.add_hook(store, hook, module)
store = convert_legacy_store(store)
module.REGISTERED_HOOKS.append((store, hook))
return self.context.hooks.add_hook(hook, store)
def del_hook(store, hook):
return self.context.hooks.del_hook(store, hook)
store = convert_legacy_store(store)
module.REGISTERED_HOOKS.remove((store, hook))
return self.context.hooks.del_hook(hook, store)
def add_event(evt, eid=None):
return self.context.add_event(evt, eid, module_src=module)
def add_event_eid(evt, eid):
@ -236,6 +240,21 @@ class ModuleLoader(SourceLoader):
return module
def convert_legacy_store(old):
if old == "cmd_hook" or old == "cmd_rgxp" or old == "cmd_default":
return "in_PRIVMSG_cmd"
elif old == "ask_hook" or old == "ask_rgxp" or old == "ask_default":
return "in_PRIVMSG_ask"
elif old == "msg_hook" or old == "msg_rgxp" or old == "msg_default":
return "in_PRIVMSG_def"
elif old == "all_post":
return "post"
elif old == "all_pre":
return "pre"
else:
print("UNKNOWN store:", old)
return old
def add_cap_hook(prompt, module, cmd):
if hasattr(module, cmd["call"]):
prompt.add_cap_hook(cmd["name"], getattr(module, cmd["call"]))
@ -250,5 +269,7 @@ def register_hooks(module, context, prompt):
if s == "prompt_cmd":
prompt.add_cap_hook(h.name, h.call)
else:
context.hooks.add_hook(s, h, module)
s = convert_legacy_store(s)
module.REGISTERED_HOOKS.append((s, h))
context.hooks.add_hook(h, s)
hooks.last_registered = []

View File

@ -68,7 +68,7 @@ class Message:
self.params.append(p.group("trailing"))
# Special commands
if self.cmd == 'PRIVMSG':
if self.cmd == 'PRIVMSG' or self.cmd == 'NOTICE':
self.receivers = self.decode(self.params[0]).split(',')
# If CTCP, remove 0x01
@ -106,6 +106,11 @@ class Message:
def parse_content(self):
"""Parse or reparse the message content"""
# Remove !
if self.text[0] == '!':
self.qual = "cmd"
self.text = self.text[1:].strip()
# Split content by words
try:
self.cmds = shlex.split(self.text)

View File

@ -148,28 +148,22 @@ def treat_variables(res):
res.messages[i] = replace_variables(", ".join(res.messages[i]), res)
else:
res.messages[i] = replace_variables(res.messages[i], res)
return True
return res
@hook("all_pre")
def treat_alias(msg, hooks_cache):
if msg.cmd == "PRIVMSG":
if len(msg.cmds) > 0 and (len(msg.cmds[0]) > 0
and msg.cmds[0][0] == "!"
and msg.cmds[0][1:] in DATAS.getNode("aliases").index
and msg.cmds[0][1:] not in hooks_cache("cmd_hook")):
msg.text = msg.text.replace(msg.cmds[0],
DATAS.getNode("aliases").index[msg.cmds[0][1:]]["origin"], 1)
@hook("pre_PRIVMSG_cmd")
def treat_alias(msg):
if msg.cmds[0] in DATAS.getNode("aliases").index:
msg.text = msg.text.replace(msg.cmds[0],
DATAS.getNode("aliases").index[msg.cmds[0]]["origin"], 1)
msg.qual = "def"
msg.parse_content()
msg.parse_content()
return treat_alias(msg)
treat_alias(msg, hooks_cache)
return True
else:
msg.text = replace_variables(msg.text, msg)
msg.parse_content()
return False
return False
else:
msg.text = replace_variables(msg.text, msg)
msg.parse_content()
return msg
@hook("ask_default")
def parseask(msg):
@ -187,4 +181,4 @@ def parseask(msg):
res = Response(msg.sender, "Nouvel alias %s défini avec succès." % result.group(1))
save()
return res
return False
return None

View File

@ -33,7 +33,7 @@ def parseresponse(res):
SERVERS[res.server] = dict()
for receiver in res.receivers:
SERVERS[res.server][receiver] = res
return True
return res
@hook("cmd_hook", "more")

View File

@ -67,9 +67,8 @@ def parselisten(msg):
except:
pass
return False
return msg
@hook("all_post")
def parseresponse(res):
parselisten(res)
return True
return parselisten(res)

View File

@ -66,9 +66,8 @@ def parselisten(msg):
LAST_URLS[msg.channel].append(url)
except:
pass
return False
return msg
@hook("all_post")
def parseresponse(res):
parselisten(res)
return True
return parselisten(res)

View File

@ -69,6 +69,14 @@ class Response:
self.sender = sender
def append_message(self, message, title=None, shown_first_count=-1):
if type(message) is str:
message = message.split('\n')
if len(message) > 1:
for m in message:
self.append_message(m)
return
else:
message = message[0]
if message is not None and len(message) > 0:
if shown_first_count >= 0:
self.messages.append(message[:shown_first_count])

View File

@ -31,7 +31,7 @@ import server
#Store all used ports
PORTS = list()
class DCC(server.Server):
class DCC(server.AbstractServer):
def __init__(self, srv, dest, socket=None):
server.Server.__init__(self)

View File

@ -42,6 +42,17 @@ class IRCServer(SocketServer):
return True
return False
def send_response(self, res):
if type(res.channel) != list:
res.channel = [ res.channel ]
for channel in res.channel:
if channel is not None and channel != self.nick:
self.write("%s %s :%s" % ("PRIVMSG", channel, res.get_message()))
else:
channel = res.sender.split("!")[0]
self.write("%s %s :%s" % ("NOTICE" if res.is_ctcp else "PRIVMSG", channel, res.get_message()))
def _close(self):
self.write("QUIT")
SocketServer._close(self)

View File

@ -63,6 +63,10 @@ class AbstractServer(io.IOBase):
_xlist.remove(self)
def send_response(self, res):
return NotImplemented
def write(self, message):
"""Send a message to the server using send_callback"""
self._send_callback(message)