Add new hook that treat all messages, not only PRIVMSG ; can respond with a response.Hook to create a hook

This commit is contained in:
Némunaire 2012-11-04 04:28:24 +01:00
parent 21f2af1cad
commit dc52593953
10 changed files with 365 additions and 243 deletions

11
DCC.py
View File

@ -35,7 +35,6 @@ class DCC(server.Server):
def __init__(self, srv, dest, socket=None):
server.Server.__init__(self)
self.DCC = False
self.error = False # An error has occur, closing the connection?
self.messages = list() # Message queued before connexion
@ -132,9 +131,10 @@ class DCC(server.Server):
if self.error:
self.srv.send_msg_final(self.nick, msg)
elif not self.connected or self.s is None:
if not self.DCC:
self.DCC = True
try:
self.start()
except RuntimeError:
pass
self.messages.append(msg)
else:
for line in msg.split("\n"):
@ -146,9 +146,10 @@ class DCC(server.Server):
"""Send a file over DCC"""
if os.path.isfile(filename):
self.messages = filename
if not self.DCC:
try:
self.start()
self.DCC = True
except RuntimeError:
pass
else:
print("File not found `%s'" % filename)

View File

@ -22,8 +22,9 @@ import socket
import threading
import traceback
import channel
from channel import Channel
from DCC import DCC
from hooks import Hook
import message
import server
import xmlparser
@ -56,7 +57,7 @@ class IRCServer(server.Server):
self.channels = dict()
for chn in self.node.getNodes("channel"):
chan = channel.Channel(chn, self)
chan = Channel(chn["name"], chn["password"])
self.channels[chan.name] = chan
@ -104,6 +105,23 @@ class IRCServer(server.Server):
"""Gives the server identifiant"""
return self.host + ":" + str(self.port)
def register_hooks(self):
self.add_hook(Hook(self.evt_channel, "JOIN"))
self.add_hook(Hook(self.evt_channel, "PART"))
self.add_hook(Hook(self.evt_server, "NICK"))
self.add_hook(Hook(self.evt_server, "QUIT"))
self.add_hook(Hook(self.evt_channel, "332"))
self.add_hook(Hook(self.evt_channel, "353"))
def evt_server(self, msg, srv):
for chan in self.channels:
self.channels[chan].treat(msg.cmd, msg)
def evt_channel(self, msg, srv):
if msg.channel is not None:
if msg.channel in self.channels:
self.channels[msg.channel].treat(msg.cmd, msg)
def accepted_channel(self, chan, sender = None):
"""Return True if the channel (or the user) is authorized"""
if self.allow_all:
@ -120,11 +138,7 @@ class IRCServer(server.Server):
"""Join a channel"""
if force or (chan is not None and
self.connected and chan not in self.channels):
chn = xmlparser.module_state.ModuleState("channel")
chn["name"] = chan
chn["password"] = password
self.node.addChild(chn)
self.channels[chan] = channel.Channel(chn, self)
self.channels[chan] = Channel(chan, password)
if password is not None:
self.s.send(("JOIN %s %s\r\n" % (chan, password)).encode())
else:
@ -136,7 +150,7 @@ class IRCServer(server.Server):
def leave(self, chan):
"""Leave a channel"""
if chan is not None and self.connected and chan in self.channels:
if chan.instanceof(list):
if isinstance(chan, list):
for c in chan:
self.leave(c)
else:

165
bot.py
View File

@ -21,6 +21,7 @@ from datetime import timedelta
from queue import Queue
import threading
import time
import re
import consumer
import event
@ -67,6 +68,10 @@ class Bot:
self.cnsr_thrd = list()
self.cnsr_thrd_size = -1
self.hooks.add_hook("irc_hook",
hooks.Hook(self.treat_prvmsg, "PRIVMSG"),
self)
def init_ctcp_capabilities(self):
"""Reset existing CTCP capabilities to default one"""
@ -98,7 +103,7 @@ class Bot:
print ("DCC: unable to connect to %s:%s" % (ip, msg.cmds[4]))
def add_event(self, evt, eid=None):
def add_event(self, evt, eid=None, module_src=None):
"""Register an event and return its identifiant for futur update"""
if eid is None:
# Find an ID
@ -123,18 +128,26 @@ class Bot:
if len(self.events) <= 0 or self.events[i+1] != evt:
return None
if module_src is not None:
module_src.REGISTERED_EVENTS.append(evt.id)
return evt.id
def del_event(self, id):
def del_event(self, id, module_src=None):
"""Find and remove an event from list"""
if len(self.events) > 0 and id == self.events[0].id:
self.events.remove(self.events[0])
self.update_timer()
if module_src is not None:
module_src.REGISTERED_EVENTS.remove(evt.id)
return True
for evt in self.events:
if evt.id == id:
self.events.remove(evt)
if module_src is not None:
module_src.REGISTERED_EVENTS.remove(evt.id)
return True
return False
@ -172,6 +185,8 @@ class Bot:
def addServer(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.register_hooks()
if srv.id not in self.servers:
self.servers[srv.id] = srv
if srv.autoconnect:
@ -326,24 +341,111 @@ class Bot:
elif isinstance(store, list):
store.remove(hook)
def treat_pre(self, msg):
def treat_pre(self, msg, srv):
"""Treat a message before all other treatment"""
for h, lvl, store in self.create_cache("all_pre"):
h.run(self.create_cache, msg)
self.check_rest_times(store, h)
if h.is_matching(None, server=srv):
h.run(msg, self.create_cache)
self.check_rest_times(store, h)
def treat_post(self, msg):
def treat_post(self, res):
"""Treat a message before send"""
for h, lvl, store in self.create_cache("all_post"):
c = h.run(msg)
self.check_rest_times(store, h)
if not c:
return False
if h.is_matching(None, channel=res.channel, server=res.server):
c = h.run(msg)
self.check_rest_times(store, h)
if not c:
return False
return True
def treat_cmd(self, msg):
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) = 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
if re.match("^ *(m[' ]?entends?[ -]+tu|h?ear me|do you copy|ping)",
msg.content, re.I) is not None:
return response.Response(msg.sender, message="pong",
channel=msg.channel, nick=msg.nick)
# Ask hooks
else:
return self.treat_ask(msg, srv)
def treat_prvmsg(self, msg, srv):
# First, treat CTCP
if msg.ctcp:
if msg.cmds[0] in self.ctcp_capabilities:
return self.ctcp_capabilities[msg.cmds[0]](srv, msg)
else:
return _ctcp_response(msg.sender, "ERRMSG Unknown or unimplemented CTCP request")
# Treat all messages starting with 'nemubot:' as distinct commands
elif msg.content.find("%s:"%srv.nick) == 0:
# Remove the bot name
msg.content = msg.content[len(srv.nick)+1:].strip()
return self.treat_prvmsg_ask(msg, srv)
# Owner commands
elif msg.content[0] == '`' and msg.nick == srv.owner:
#TODO: owner commands
pass
elif msg.content[0] == '!' and len(msg.content) > 1:
# Remove the !
msg.cmds[0] = msg.cmds[0][1:]
if msg.cmds[0] == "help":
return _help_msg(msg.sender)
elif msg.cmds[0] == "more":
if msg.channel == srv.nick:
if msg.sender in srv.moremessages:
return srv.moremessages[msg.sender]
else:
if msg.channel in srv.moremessages:
return srv.moremessages[msg.channel]
elif msg.cmds[0] == "dcc":
print("dcctest for", msg.sender)
srv.send_dcc("Hello %s!" % msg.nick, msg.sender)
elif msg.cmds[0] == "pvdcctest":
print("dcctest")
return Response(msg.sender, message="Test DCC")
elif msg.cmds[0] == "dccsendtest":
print("dccsendtest")
conn = DCC(srv, msg.sender)
conn.send_file("bot_sample.xml")
else:
return self.treat_cmd(msg, srv)
else:
res = self.treat_answer(msg, srv)
# Assume the message starts with nemubot:
if (res is None or len(res) <= 0) and msg.private:
return self.treat_prvmsg_ask(msg, srv)
return res
def treat_cmd(self, msg, srv):
"""Treat a command message"""
treated = list()
@ -352,15 +454,16 @@ class Bot:
if msg.cmds[0] in cmd_hook:
(hks, lvl, store) = cmd_hook[msg.cmds[0]]
for h in hks:
res = h.run(msg)
if res is not None and res != False:
treated.append(res)
self.check_rest_times(store, h)
if h.is_matching(msg.cmds[0], channel=msg.channel, server=srv):
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 in cmd_rgxp:
if hook.is_matching(msg.cmds[0], msg.channel):
if hook.is_matching(msg.cmds[0], msg.channel, server=srv):
res = hook.run(msg)
if res is not None and res != False:
treated.append(res)
@ -378,7 +481,7 @@ class Bot:
return treated
def treat_ask(self, msg):
def treat_ask(self, msg, srv):
"""Treat an ask message"""
treated = list()
@ -387,16 +490,17 @@ class Bot:
if msg.content in ask_hook:
hks, lvl, store = ask_hook[msg.content]
for h in hks:
res = h.run(msg)
if res is not None and res != False:
treated.append(res)
self.check_rest_times(store, h)
if h.is_matching(msg.content, channel=msg.channel, server=srv):
res = h.run(msg, strcmp=msg.content)
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 in ask_rgxp:
if hook.is_matching(msg.content, msg.channel):
res = hook.run(msg)
if hook.is_matching(msg.content, channel=msg.channel, server=srv):
res = hook.run(msg, strcmp=msg.content)
if res is not None and res != False:
treated.append(res)
self.check_rest_times(store, hook)
@ -413,7 +517,7 @@ class Bot:
return treated
def treat_answer(self, msg):
def treat_answer(self, msg, srv):
"""Treat a normal message"""
treated = list()
@ -422,16 +526,17 @@ class Bot:
if msg.content in msg_hook:
hks, lvl, store = msg_hook[msg.content]
for h in hks:
res = h.run(msg)
if res is not None and res != False:
treated.append(res)
self.check_rest_times(store, h)
if h.is_matching(msg.content, channel=msg.channel, server=srv):
res = h.run(msg, strcmp=msg.content)
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 in msg_rgxp:
if hook.is_matching(msg.content, msg.channel):
res = hook.run(msg)
if hook.is_matching(msg.content, channel=msg.channel, server=srv):
res = hook.run(msg, strcmp=msg.content)
if res is not None and res != False:
treated.append(res)
self.check_rest_times(store, hook)

View File

@ -1,71 +1,102 @@
# coding=utf-8
# Nemubot is a modulable IRC bot, built around XML configuration files.
# Copyright (C) 2012 Mercier Pierre-Olivier
#
# 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 Channel:
def __init__(self, node, srv):
self.node = node
self.name = node["name"]
self.password = node["password"]
self.people = dict()
self.srv = srv
self.topic = ""
def __init__(self, name, password=None):
self.name = name
self.password = password
self.people = dict()
self.topic = ""
def join(self, nick, level = 0):
#print ("%s arrive sur %s" % (nick, self.name))
self.people[nick] = level
def treat(self, cmd, msg):
if cmd == "353":
self.parse353(msg)
elif cmd == "332":
self.parse332(msg)
elif cmd == "MODE":
self.mode(msg)
elif cmd == "JOIN":
self.join(msg.nick)
elif cmd == "NICK":
self.nick(msg.nick, msg.content)
elif cmd == "PART" or cmd == "QUIT":
self.part(msg.nick)
elif cmd == "TOPIC":
self.topic = self.content
def chtopic(self, newtopic):
"""Send command to change the topic"""
self.srv.send_msg(self.name, newtopic, "TOPIC")
self.topic = newtopic
def join(self, nick, level = 0):
"""Someone join the channel"""
#print ("%s arrive sur %s" % (nick, self.name))
self.people[nick] = level
def nick(self, oldnick, newnick):
#print ("%s change de nom pour %s" % (oldnick, newnick))
if oldnick in self.people:
lvl = self.people[oldnick]
del self.people[oldnick]
else:
lvl = 0
self.people[newnick] = lvl
def chtopic(self, newtopic):
"""Send command to change the topic"""
self.srv.send_msg(self.name, newtopic, "TOPIC")
self.topic = newtopic
def part(self, nick):
#print ("%s vient de quitter %s" % (self.sender, self.channel))
if nick in self.people:
del self.people[nick]
def nick(self, oldnick, newnick):
"""Someone change his nick"""
if oldnick in self.people:
#print ("%s change de nom pour %s sur %s" % (oldnick, newnick, self.name))
lvl = self.people[oldnick]
del self.people[oldnick]
self.people[newnick] = lvl
def mode(self, msg):
if msg.content[0] == "-k":
self.password = ""
elif msg.content[0] == "+k":
if len(msg.content) > 1:
self.password = ' '.join(msg.content[1:])[1:]
else:
self.password = msg.content[1]
elif msg.content[0] == "+o":
self.people[msg.nick] |= 4
elif msg.content[0] == "-o":
self.people[msg.nick] &= ~4
elif msg.content[0] == "+h":
self.people[msg.nick] |= 2
elif msg.content[0] == "-h":
self.people[msg.nick] &= ~2
elif msg.content[0] == "+v":
self.people[msg.nick] |= 1
elif msg.content[0] == "-v":
self.people[msg.nick] &= ~1
def part(self, nick):
"""Someone leave the channel"""
if nick in self.people:
#print ("%s vient de quitter %s" % (nick, self.name))
del self.people[nick]
def parse332(self, msg):
self.topic = msg.content
def mode(self, msg):
if msg.content[0] == "-k":
self.password = ""
elif msg.content[0] == "+k":
if len(msg.content) > 1:
self.password = ' '.join(msg.content[1:])[1:]
else:
self.password = msg.content[1]
elif msg.content[0] == "+o":
self.people[msg.nick] |= 4
elif msg.content[0] == "-o":
self.people[msg.nick] &= ~4
elif msg.content[0] == "+h":
self.people[msg.nick] |= 2
elif msg.content[0] == "-h":
self.people[msg.nick] &= ~2
elif msg.content[0] == "+v":
self.people[msg.nick] |= 1
elif msg.content[0] == "-v":
self.people[msg.nick] &= ~1
def parse353(self, msg):
for p in msg.content:
p = p.decode()
if p[0] == "@":
level = 4
elif p[0] == "%":
level = 2
elif p[0] == "+":
level = 1
else:
self.people[p] = 0
continue
self.people[p[1:]] = level
def parse332(self, msg):
self.topic = msg.content
def parse353(self, msg):
for p in msg.content:
p = p.decode()
if p[0] == "@":
level = 4
elif p[0] == "%":
level = 2
elif p[0] == "+":
level = 1
else:
self.join(p, 0)
continue
self.join(p[1:], level)

View File

@ -25,7 +25,7 @@ import sys
import bot
from DCC import DCC
from message import Message
from response import Response
import response
import server
class MessageConsumer:
@ -43,104 +43,48 @@ class MessageConsumer:
if msg.cmd == "PING":
self.srv.send_pong(msg.content)
else:
# TODO: Manage credits here
context.treat_pre(msg)
if msg.cmd == "PRIVMSG" and msg.ctcp:
if msg.cmds[0] in context.ctcp_capabilities:
return context.ctcp_capabilities[msg.cmds[0]](self.srv, msg)
else:
return bot._ctcp_response(msg.sender, "ERRMSG Unknown or unimplemented CTCP request")
elif msg.cmd == "PRIVMSG" and self.srv.accepted_channel(msg.channel):
return self.treat_prvmsg(context, msg)
# TODO: continue here
pass
def treat_prvmsg_ask(self, context, msg):
# Treat ping
if re.match("^ *(m[' ]?entends?[ -]+tu|h?ear me|do you copy|ping)",
msg.content, re.I) is not None:
return Response(msg.sender, message="pong",
channel=msg.channel, nick=msg.nick)
# Ask hooks
else:
return context.treat_ask(msg)
def treat_prvmsg(self, context, msg):
# Treat all messages starting with 'nemubot:' as distinct commands
if msg.content.find("%s:"%self.srv.nick) == 0:
# Remove the bot name
msg.content = msg.content[len(self.srv.nick)+1:].strip()
return self.treat_prvmsg_ask(context, msg)
# Owner commands
elif msg.content[0] == '`' and msg.nick == self.srv.owner:
#TODO: owner commands
pass
elif msg.content[0] == '!' and len(msg.content) > 1:
# Remove the !
msg.cmds[0] = msg.cmds[0][1:]
if msg.cmds[0] == "help":
return _help_msg(msg.sender)
elif msg.cmds[0] == "more":
if msg.channel == self.srv.nick:
if msg.sender in self.srv.moremessages:
return self.srv.moremessages[msg.sender]
else:
if msg.channel in self.srv.moremessages:
return self.srv.moremessages[msg.channel]
elif msg.cmds[0] == "dcc":
print("dcctest for", msg.sender)
self.srv.send_dcc("Hello %s!" % msg.nick, msg.sender)
elif msg.cmds[0] == "pvdcctest":
print("dcctest")
return Response(msg.sender, message="Test DCC")
elif msg.cmds[0] == "dccsendtest":
print("dccsendtest")
conn = DCC(self.srv, msg.sender)
conn.send_file("bot_sample.xml")
else:
return context.treat_cmd(msg)
else:
res = context.treat_answer(msg)
# Assume the message starts with nemubot:
if (res is None or len(res) <= 0) and self.prvt:
return self.treat_prvmsg_ask(context, msg)
return res
# All messages
context.treat_pre(msg, self.srv)
# TODO: Manage credits
return context.treat_irc(msg, self.srv)
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)
elif isinstance(res, response.Response):
# Define the destination server
if (res.server is not None and
res.server.instanceof(string) and res.server in context.servers):
res.server = context.servers[res.server]
if (res.server is not None and
not res.server.instanceof(server.Server)):
print ("\033[1;35mWarning:\033[0m the server defined in this "
"response doesn't exist: %s" % (res.server))
res.server = None
if res.server is None:
res.server = self.srv
if (res.server is not None and
isinstance(res.server, str) and res.server in context.servers):
res.server = context.servers[res.server]
if (res.server is not None and
not isinstance(res.server, server.Server)):
print ("\033[1;35mWarning:\033[0m the server defined in this "
"response doesn't exist: %s" % (res.server))
res.server = None
if res.server is None:
res.server = self.srv
# Sent the message only if treat_post authorize it
if context.treat_post(res):
res.server.send_response(res, self.data)
# Sent the message only if treat_post authorize it
if context.treat_post(res):
res.server.send_response(res, self.data)
elif isinstance(res, response.Hook):
context.hooks.add_hook(res.type, res.hook, res.src)
elif res is not None:
print ("\033[1;35mWarning:\033[0m 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.is_owner = (msg.nick == self.srv.owner)
if msg.cmd == "PRIVMSG":
msg.is_owner = (msg.nick == self.srv.owner)
res = self.treat_in(context, msg)
except:
print ("\033[1;31mERROR:\033[0m occurred during the "
@ -151,17 +95,7 @@ class MessageConsumer:
return
# Send message
if res is not None:
if isinstance(res, list):
for r in res:
if isinstance(r, Response):
self.treat_out(context, r)
elif isinstance(r, list):
for s in r:
if isinstance(s, Response):
self.treat_out(context, s)
elif isinstance(res, Response):
self.treat_out(context, res)
self.treat_out(context, res)
# Inform that the message has been treated
self.srv.msg_treated(self.data)
@ -210,7 +144,7 @@ class Consumer(threading.Thread):
def _help_msg(modules, sndr, cmd):
"""Parse and response to help messages"""
res = Response(sndr)
res = response.Response(sndr)
if len(cmd) > 1:
if cmd[1] in modules:
if len(cmd) > 2:

View File

@ -22,16 +22,19 @@ class MessagesHook:
def __init__(self, context):
self.context = context
# Store specials hook
# Store specials hooks
self.all_pre = list() # Treated before any parse
self.all_post = list() # Treated before send message to user
# Store direct hook
# 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 hook
# Store regexp hooks
self.cmd_rgxp = list()
self.ask_rgxp = list()
self.msg_rgxp = list()
@ -61,12 +64,16 @@ class MessagesHook:
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:
print ("\033[1;32mWarning:\033[0m unrecognized hook store type")
return
if module_src is not None:
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):
@ -92,7 +99,7 @@ class MessagesHook:
node["type"] == "all"):
self.register_hook_attributes("answer", module, node)
def del_hook(self, store, hook):
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]
@ -105,33 +112,68 @@ class MessagesHook:
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()):
def __init__(self, call, name=None, data=None, regexp=None, channels=list(), server=None, end=None, call_end=None):
self.name = name
self.end = end
self.call = call
if call_end is None:
self.call_end = self.call
else:
self.call_end = call_end
self.regexp = regexp
self.data = data
self.times = -1
self.server = server
self.channels = channels
def is_matching(self, strcmp, channel):
def is_matching(self, strcmp, channel=None, server=None):
"""Test if the current hook correspond to the message"""
return (len(self.channel) <= 0 or channel in self.channels) and (
return (channel is None or len(self.channels) <= 0 or
channel in self.channels) and (server is None or
self.server is None or self.server == server) and (
(self.name is not None and strcmp == self.name) or (
self.end is not None and strcmp == self.end) or (
self.regexp is not None and re.match(self.regexp, strcmp)))
def run(self, msg):
def run(self, msg, data2=None, strcmp=None):
"""Run the hook"""
if self.times != 0:
self.times -= 1
if self.data is None:
return self.call(msg)
elif isinstance(self.data, dict):
return self.call(msg, **self.data)
if (self.end is not None and strcmp is not None and
self.call_end is not None and strcmp == self.end):
call = self.call_end
self.times = 0
else:
return self.call(msg, self.data)
call = self.call
if self.data is None:
if data2 is None:
return call(msg)
elif isinstance(data2, dict):
return call(msg, **data2)
else:
return call(msg, data2)
elif isinstance(self.data, dict):
if data2 is None:
return call(msg, **self.data)
else:
return call(msg, data2, **self.data)
else:
if data2 is None:
return call(msg, self.data)
elif isinstance(data2, dict):
return call(msg, self.data, **data2)
else:
return call(msg, self.data, data2)

View File

@ -145,6 +145,7 @@ class ModuleLoader(SourceLoader):
# Set module common functions and datas
module.REGISTERED_HOOKS = list()
module.REGISTERED_EVENTS = list()
module.DEBUG = False
module.DIR = self.mpath
module.name = fullname
@ -152,6 +153,10 @@ class ModuleLoader(SourceLoader):
module.print_debug = lambda msg: mod_print_dbg(module, msg)
module.send_response = lambda srv, res: mod_send_response(self.context, srv, res)
module.add_hook = lambda store, hook: self.context.hooks.add_hook(store, hook, module)
module.del_hook = lambda store, hook: self.context.hooks.del_hook(store, hook)
module.add_event = lambda evt: self.context.add_event(evt, module_src=module)
module.add_event_eid = lambda evt, eid: self.context.add_event(evt, eid, module_src=module)
module.del_event = lambda evt: self.context.add_event(evt, module_src=module)
if not hasattr(module, "NODATA"):
module.DATAS = xmlparser.parse_file(self.context.datas_path

View File

@ -105,8 +105,8 @@ class Message:
def parse_content(self):
"""Parse or reparse the message content"""
# If CTCP, remove 0x01
#if self.ctcp:
# self.content = self.content[1:len(self.content)-1]
if self.ctcp:
self.content = self.content[1:len(self.content)-1]
# Split content by words
try:
@ -146,29 +146,6 @@ class Message:
return False
return self.srv.accepted_channel(self.channel)
def treat(self):
"""Parse and treat the message"""
if self.channel in self.srv.channels:
if self.cmd == "353":
self.srv.channels[self.channel].parse353(self)
elif self.cmd == "332":
self.srv.channels[self.channel].parse332(self)
elif self.cmd == "MODE":
self.srv.channels[self.channel].mode(self)
elif self.cmd == "JOIN":
self.srv.channels[self.channel].join(self.nick)
elif self.cmd == "PART":
self.srv.channels[self.channel].part(self.nick)
elif self.cmd == "TOPIC":
self.srv.channels[self.channel].topic = self.content
elif self.cmd == "NICK":
for chn in self.srv.channels.keys():
self.srv.channels[chn].nick(self.nick, self.content)
elif self.cmd == "QUIT":
for chn in self.srv.channels.keys():
self.srv.channels[chn].part(self.nick)
return None
##############################
# #
# Extraction/Format text #

View File

@ -154,3 +154,13 @@ class Response:
self.pop()
self.elt = 0
return msg
import hooks
class Hook:
def __init__(self, TYPE, call, name=None, data=None, regexp=None,
channels=list(), server=None, end=None, call_end=None,
SRC=None):
self.hook = hooks.Hook(call, name, data, regexp, channels,
server, end, call_end)
self.type = TYPE
self.src = SRC

View File

@ -144,7 +144,10 @@ class Server(threading.Thread):
self._receive_action = receive_action
if not self.connected:
self.stop = False
self.start()
try:
self.start()
except RuntimeError:
pass
elif verb:
print (" Already connected.")