Response class is now part of 'more' module.

This commit prepare the new message flow based on protocol independent messages.

	This commit changes the module API: you need to import the Response class manually at the begining of our module.
This commit is contained in:
nemunaire 2014-09-26 18:00:22 +02:00
parent 8f620b9756
commit 41da1c0780
37 changed files with 257 additions and 233 deletions

9
bot.py
View File

@ -36,7 +36,6 @@ from hooks.manager import HooksManager
from networkbot import NetworkBot from networkbot import NetworkBot
from server.IRC import IRCServer from server.IRC import IRCServer
from server.DCC import DCC from server.DCC import DCC
import response
logger = logging.getLogger("nemubot.bot") logger = logging.getLogger("nemubot.bot")
@ -77,13 +76,14 @@ class Bot(threading.Thread):
self.hooks = HooksManager() self.hooks = HooksManager()
def in_ping(msg): def in_ping(msg):
if re.match("^ *(m[' ]?entends?[ -]+tu|h?ear me|do you copy|ping)", msg.text, re.I) is not None: if re.match("^ *(m[' ]?entends?[ -]+tu|h?ear me|do you copy|ping)", msg.text, re.I) is not None:
return response.Response(message="pong", channel=msg.receivers, nick=msg.nick) return "PRIVMSG %s :%s: pong" % (",".join(msg.receivers), msg.nick)
self.hooks.add_hook(MessageHook(in_ping), "in", "PRIVMSG", "ask") self.hooks.add_hook(MessageHook(in_ping), "in", "PRIVMSG", "ask")
def _help_msg(msg): def _help_msg(msg):
"""Parse and response to help messages""" """Parse and response to help messages"""
cmd = msg.cmds cmd = msg.cmds
res = response.Response() from more import Response
res = Response()
if len(cmd) > 1: if len(cmd) > 1:
if cmd[1] in self.modules: if cmd[1] in self.modules:
if len(cmd) > 2: if len(cmd) > 2:
@ -470,9 +470,6 @@ def reload():
import prompt.builtins import prompt.builtins
imp.reload(prompt.builtins) imp.reload(prompt.builtins)
import response
imp.reload(response)
import server import server
rl,wl,xl = server._rlist,server._wlist,server._xlist rl,wl,xl = server._rlist,server._wlist,server._xlist
imp.reload(server) imp.reload(server)

View File

@ -26,7 +26,6 @@ import sys
import bot import bot
from server.DCC import DCC from server.DCC import DCC
from message import Message from message import Message
from response import Response
import server import server
logger = logging.getLogger("nemubot.consumer") logger = logging.getLogger("nemubot.consumer")
@ -89,7 +88,7 @@ class MessageConsumer:
if h.match(message=msg, server=self.srv): if h.match(message=msg, server=self.srv):
res = h.run(msg) res = h.run(msg)
if isinstance(res, list): if isinstance(res, list):
for i in xrange(len(res)): for i in range(len(res)):
if res[i] == msg: if res[i] == msg:
res.pop(i) res.pop(i)
break break
@ -119,11 +118,11 @@ class MessageConsumer:
res = h.run(msg) res = h.run(msg)
if isinstance(res, list): if isinstance(res, list):
for r in res: for r in res:
if isinstance(r, Response): if hasattr(r, "set_sender"):
r.set_sender(msg.sender) r.set_sender(msg.sender)
self.responses += res self.responses += res
elif res is not None: elif res is not None:
if isinstance(res, Response): if hasattr(res, "set_sender"):
res.set_sender(msg.sender) res.set_sender(msg.sender)
self.responses.append(res) self.responses.append(res)
@ -140,15 +139,20 @@ class MessageConsumer:
self.responses = list() self.responses = list()
while len(new_msg) > 0: while len(new_msg) > 0:
msg = self.first_treat(new_msg.pop(0)) ff = new_msg.pop(0)
if isinstance(ff, str):
self.responses.append(ff)
continue
msg = self.first_treat(ff)
for h in hm.get_hooks("post"): for h in hm.get_hooks("post"):
if h.match(message=msg, server=self.srv): if h.match(message=msg, server=self.srv):
res = h.run(msg) res = h.run(msg)
if isinstance(res, list): if isinstance(res, list):
for i in xrange(len(res)): for i in range(len(res)):
if res[i] == msg: if isinstance(res[i], str):
res.pop(i) self.responses.append(res.pop(i))
break break
msg = None
new_msg += res new_msg += res
elif res is not None and res != msg: elif res is not None and res != msg:
new_msg.append(res) new_msg.append(res)
@ -182,7 +186,9 @@ class MessageConsumer:
for res in self.responses: for res in self.responses:
to_server = None to_server = None
if res.server is None: if isinstance(res, str):
to_server = self.srv
elif res.server is None:
to_server = self.srv to_server = self.srv
res.server = self.srv.id res.server = self.srv.id
elif isinstance(res.server, str) and res.server in context.servers: elif isinstance(res.server, str) and res.server in context.servers:
@ -194,7 +200,7 @@ class MessageConsumer:
continue continue
# Sent the message only if treat_post authorize it # Sent the message only if treat_post authorize it
to_server.send_response(res) to_server.write(res)
class EventConsumer: class EventConsumer:
"""Store a event before treating""" """Store a event before treating"""

View File

@ -16,8 +16,6 @@
# You should have received a copy of the GNU Affero General Public License # 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/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
from response import Response
class IRCException(Exception): class IRCException(Exception):
def __init__(self, message, personnal=True): def __init__(self, message, personnal=True):
@ -26,4 +24,6 @@ class IRCException(Exception):
self.personnal = personnal self.personnal = personnal
def fill_response(self, msg): def fill_response(self, msg):
# TODO: no more Response usable here
from more import Response
return Response(self.message, channel=msg.receivers, nick=(msg.nick if self.personnal else None)) return Response(self.message, channel=msg.receivers, nick=(msg.nick if self.personnal else None))

View File

@ -20,7 +20,8 @@ import re
from exception import IRCException from exception import IRCException
import hooks import hooks
from response import Response
from message import Message
class MessageHook(hooks.AbstractHook): class MessageHook(hooks.AbstractHook):
@ -39,8 +40,8 @@ class MessageHook(hooks.AbstractHook):
def match(self, message, server=None): def match(self, message, server=None):
if isinstance(message, Response): if not isinstance(message, Message):
return self.is_matching(None, message.channel, server) return True
elif message.qual == "cmd": elif message.qual == "cmd":
return self.is_matching(message.cmds[0], message.channel, server) return self.is_matching(message.cmds[0], message.channel, server)

View File

@ -28,7 +28,6 @@ from bot import __version__
import event import event
import exception import exception
import hooks import hooks
import response
import xmlparser import xmlparser
logger = logging.getLogger("nemubot.importer") logger = logging.getLogger("nemubot.importer")
@ -159,7 +158,7 @@ class ModuleLoader(SourceLoader):
def send_response(server, res): def send_response(server, res):
if server in self.context.servers: if server in self.context.servers:
return self.context.servers[server].send_response(res) return self.context.servers[server].write("PRIVMSG %s :%s" % (",".join(res.receivers), res.get_message()))
else: else:
module.logger.error("Try to send a message to the unknown server: %s", server) module.logger.error("Try to send a message to the unknown server: %s", server)
return False return False
@ -205,7 +204,6 @@ class ModuleLoader(SourceLoader):
module.ModuleEvent = event.ModuleEvent module.ModuleEvent = event.ModuleEvent
module.ModuleState = xmlparser.module_state.ModuleState module.ModuleState = xmlparser.module_state.ModuleState
module.Response = response.Response
module.IRCException = exception.IRCException module.IRCException = exception.IRCException
# Load dependancies # Load dependancies

View File

@ -19,8 +19,6 @@
from datetime import datetime from datetime import datetime
import shlex import shlex
from response import Response
class Message: class Message:
def __init__ (self, orig, private=False): def __init__ (self, orig, private=False):
self.cmd = orig.cmd self.cmd = orig.cmd

View File

@ -10,6 +10,8 @@ from hooks import hook
nemubotversion = 3.4 nemubotversion = 3.4
from more import Response
def load(context): def load(context):
"""Load this module""" """Load this module"""
global DATAS global DATAS

View File

@ -14,6 +14,8 @@ from xmlparser.node import ModuleState
nemubotversion = 3.4 nemubotversion = 3.4
from more import Response
def load(context): def load(context):
global DATAS global DATAS
DATAS.setIndex("name", "birthday") DATAS.setIndex("name", "birthday")

View File

@ -9,6 +9,8 @@ from tools.countdown import countdown_format
nemubotversion = 3.4 nemubotversion = 3.4
from more import Response
yr = datetime.today().year yr = datetime.today().year
yrn = datetime.today().year + 1 yrn = datetime.today().year + 1

View File

@ -9,6 +9,8 @@ from tools import web
nemubotversion = 3.4 nemubotversion = 3.4
from more import Response
def load(context): def load(context):
if not CONF or not CONF.hasNode("goodreadsapi") or not CONF.getNode("goodreadsapi").hasAttribute("key"): if not CONF or not CONF.hasNode("goodreadsapi") or not CONF.getNode("goodreadsapi").hasAttribute("key"):
print ("You need a Goodreads API key in order to use this " print ("You need a Goodreads API key in order to use this "

View File

@ -14,6 +14,8 @@ from collections import defaultdict
nemubotversion = 3.4 nemubotversion = 3.4
from more import Response
s = [('present', '0'), ('présent', '0'), ('pr', '0'), s = [('present', '0'), ('présent', '0'), ('pr', '0'),
('passé simple', '12'), ('passe simple', '12'), ('ps', '12'), ('passé simple', '12'), ('passe simple', '12'), ('ps', '12'),
('passé antérieur', '112'), ('passe anterieur', '112'), ('pa', '112'), ('passé antérieur', '112'), ('passe anterieur', '112'), ('pa', '112'),

View File

@ -8,6 +8,8 @@ from hooks import hook
nemubotversion = 3.4 nemubotversion = 3.4
from more import Response
from . import DDGSearch from . import DDGSearch
from . import UrbanDictionnary from . import UrbanDictionnary
from . import WFASearch from . import WFASearch

View File

@ -11,13 +11,15 @@ import time
import threading import threading
import traceback import traceback
nemubotversion = 3.4
from event import ModuleEvent from event import ModuleEvent
from hooks import hook from hooks import hook
from tools.date import extractDate from tools.date import extractDate
from tools.countdown import countdown_format, countdown from tools.countdown import countdown_format, countdown
nemubotversion = 3.4
from more import Response
def help_full (): def help_full ():
return "This module store a lot of events: ny, we, " + (", ".join(DATAS.index.keys())) + "\n!eventslist: gets list of timer\n!start /something/: launch a timer" return "This module store a lot of events: ny, we, " + (", ".join(DATAS.index.keys())) + "\n!eventslist: gets list of timer\n!start /something/: launch a timer"

View File

@ -12,6 +12,8 @@ from hooks import hook
nemubotversion = 3.4 nemubotversion = 3.4
from more import Response
def help_full (): def help_full ():
return "!github /repo/: Display information about /repo/.\n!github_user /user/: Display information about /user/." return "!github /repo/: Display information about /repo/.\n!github_user /user/: Display information about /user/."

View File

@ -10,6 +10,8 @@ from hooks import hook
nemubotversion = 3.4 nemubotversion = 3.4
from more import Response
def help_full(): def help_full():
return "Search a movie title with: !imdbs <approximative title> ; View movie details with !imdb <title>" return "Search a movie title with: !imdbs <approximative title> ; View movie details with !imdb <title>"

View File

@ -8,6 +8,8 @@ from hooks import hook
nemubotversion = 3.4 nemubotversion = 3.4
from more import Response
def help_tiny(): def help_tiny():
"""Line inserted in the response to the command !help""" """Line inserted in the response to the command !help"""
return "Read manual pages on IRC" return "Read manual pages on IRC"

View File

@ -7,6 +7,8 @@ from urllib.request import urlopen
nemubotversion = 3.4 nemubotversion = 3.4
from more import Response
def load(context): def load(context):
if not CONF or not CONF.hasNode("mapquestapi") or not CONF.getNode("mapquestapi").hasAttribute("key"): if not CONF or not CONF.hasNode("mapquestapi") or not CONF.getNode("mapquestapi").hasAttribute("key"):
print ("You need a MapQuest API key in order to use this " print ("You need a MapQuest API key in order to use this "

View File

@ -12,6 +12,8 @@ from tools.web import striphtml
nemubotversion = 3.4 nemubotversion = 3.4
from more import Response
def get_raw_page(site, term, ssl=False): def get_raw_page(site, term, ssl=False):
# Built IRL # Built IRL
url = "http%s://%s/w/api.php?format=json&redirects&action=query&prop=revisions&rvprop=content&titles=%s" % ( url = "http%s://%s/w/api.php?format=json&redirects&action=query&prop=revisions&rvprop=content&titles=%s" % (

View File

@ -18,22 +18,195 @@
"""Progressive display of very long messages""" """Progressive display of very long messages"""
import logging
from hooks import hook from hooks import hook
nemubotversion = 3.4 nemubotversion = 3.4
logger = logging.getLogger("nemubot.response")
class Response:
def __init__(self, message=None, channel=None, nick=None, server=None,
nomore="No more message", title=None, more="(suite) ",
count=None, ctcp=False, shown_first_count=-1,
line_treat=None):
self.nomore = nomore
self.more = more
self.line_treat = line_treat
self.rawtitle = title
self.server = server
self.messages = list()
self.alone = True
self.is_ctcp = ctcp
if message is not None:
self.append_message(message, shown_first_count=shown_first_count)
self.elt = 0 # Next element to display
self.sender = None
self.channel = channel
self.nick = nick
self.count = count
@property
def receivers(self):
if self.channel is None:
if self.nick is not None:
return [ self.nick ]
return [ self.sender.split("!")[0] ]
elif isinstance(self.channel, list):
return self.channel
else:
return [ self.channel ]
def set_sender(self, sender):
if sender is None or sender.find("!") < 0:
if sender is not None:
logger.warn("Bad sender provided in Response, it will be ignored.", stack_info=True)
self.sender = None
else:
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])
message = message[shown_first_count:]
self.messages.append(message)
self.alone = self.alone and len(self.messages) <= 1
if isinstance(self.rawtitle, list):
self.rawtitle.append(title)
elif title is not None:
rawtitle = self.rawtitle
self.rawtitle = list()
for osef in self.messages:
self.rawtitle.append(rawtitle)
self.rawtitle.pop()
self.rawtitle.append(title)
def append_content(self, message):
if message is not None and len(message) > 0:
if self.messages is None or len(self.messages) == 0:
self.messages = list(message)
self.alone = True
else:
self.messages[len(self.messages)-1] += message
self.alone = self.alone and len(self.messages) <= 1
@property
def empty(self):
return len(self.messages) <= 0
@property
def title(self):
if isinstance(self.rawtitle, list):
return self.rawtitle[0]
else:
return self.rawtitle
def pop(self):
self.messages.pop(0)
self.elt = 0
if isinstance(self.rawtitle, list):
self.rawtitle.pop(0)
if len(self.rawtitle) <= 0:
self.rawtitle = None
def treat_ctcp(self, content):
if self.is_ctcp:
return "\x01" + content + "\x01"
else:
return content
def get_message(self):
if self.alone and len(self.messages) > 1:
self.alone = False
if self.empty:
return self.treat_ctcp(self.nomore)
if self.line_treat is not None and self.elt == 0:
self.messages[0] = self.line_treat(self.messages[0]).replace("\n", " ").strip()
msg = ""
if self.channel is not None and self.nick is not None:
msg += self.nick + ": "
if self.title is not None:
if self.elt > 0:
msg += self.title + " " + self.more + ": "
else:
msg += self.title + ": "
if self.elt > 0:
msg += "[…] "
elts = self.messages[0][self.elt:]
if isinstance(elts, list):
for e in elts:
if len(msg) + len(e) > 430:
msg += "[…]"
self.alone = False
return self.treat_ctcp(msg)
else:
msg += e + ", "
self.elt += 1
self.pop()
return self.treat_ctcp(msg[:len(msg)-2])
else:
if len(elts.encode()) <= 432:
self.pop()
if self.count is not None:
return self.treat_ctcp(msg + elts + (self.count % len(self.messages)))
else:
return self.treat_ctcp(msg + elts)
else:
words = elts.split(' ')
if len(words[0].encode()) > 432 - len(msg.encode()):
self.elt += 432 - len(msg.encode())
return self.treat_ctcp(msg + elts[:self.elt] + "[…]")
for w in words:
if len(msg.encode()) + len(w.encode()) > 431:
msg += "[…]"
self.alone = False
return self.treat_ctcp(msg)
else:
msg += w + " "
self.elt += len(w) + 1
self.pop()
return self.treat_ctcp(msg)
SERVERS = dict() SERVERS = dict()
@hook("all_post") @hook("all_post")
def parseresponse(res): def parseresponse(res):
# TODO: handle inter-bot communication NOMORE # TODO: handle inter-bot communication NOMORE
# TODO: check that the response is not the one already saved # TODO: check that the response is not the one already saved
rstr = res.get_message()
if not res.alone: if not res.alone:
if res.server not in SERVERS: if res.server not in SERVERS:
SERVERS[res.server] = dict() SERVERS[res.server] = dict()
for receiver in res.receivers: for receiver in res.receivers:
SERVERS[res.server][receiver] = res SERVERS[res.server][receiver] = res
return res
ret = list()
for channel in res.receivers:
ret.append("%s %s :%s" % ("NOTICE" if res.is_ctcp else "PRIVMSG", channel, rstr))
return ret
@hook("cmd_hook", "more") @hook("cmd_hook", "more")

View File

@ -14,6 +14,8 @@ from tools import web
nemubotversion = 3.4 nemubotversion = 3.4
from more import Response
def load(context): def load(context):
if not CONF or not CONF.hasNode("whoisxmlapi") or not CONF.getNode("whoisxmlapi").hasAttribute("username") or not CONF.getNode("whoisxmlapi").hasAttribute("password"): if not CONF or not CONF.hasNode("whoisxmlapi") or not CONF.getNode("whoisxmlapi").hasAttribute("username") or not CONF.getNode("whoisxmlapi").hasAttribute("password"):
print ("You need a WhoisXML API account in order to use the " print ("You need a WhoisXML API account in order to use the "

View File

@ -9,6 +9,7 @@ import urllib
nemubotversion = 3.4 nemubotversion = 3.4
from hooks import hook from hooks import hook
from more import Response
def help_full(): def help_full():
return "!subreddit /subreddit/: Display information on the subreddit." return "!subreddit /subreddit/: Display information on the subreddit."

View File

@ -8,6 +8,8 @@ from hooks import hook
nemubotversion = 3.4 nemubotversion = 3.4
from more import Response
@hook("cmd_hook", "choice") @hook("cmd_hook", "choice")
def cmd_choice(msg): def cmd_choice(msg):
if len(msg.cmds) > 1: if len(msg.cmds) > 1:

View File

@ -12,6 +12,8 @@ from tools.web import striphtml
nemubotversion = 3.4 nemubotversion = 3.4
from more import Response
def help_full (): def help_full ():
return "!tcode <transaction code|keywords>" return "!tcode <transaction code|keywords>"

View File

@ -11,6 +11,8 @@ from hooks import hook
nemubotversion = 3.4 nemubotversion = 3.4
from more import Response
def help_full(): def help_full():
return "If you would like to sleep soon, use !sleepytime to know the best time to wake up; use !sleepytime hh:mm if you want to wake up at hh:mm" return "If you would like to sleep soon, use !sleepytime to know the best time to wake up; use !sleepytime hh:mm if you want to wake up at hh:mm"

View File

@ -13,6 +13,8 @@ from hooks import hook
nemubotversion = 3.4 nemubotversion = 3.4
from more import Response
def load(context): def load(context):
global DATAS global DATAS
DATAS.setIndex("name", "phone") DATAS.setIndex("name", "phone")

View File

@ -12,6 +12,8 @@ from .pyaspell import AspellError
nemubotversion = 3.4 nemubotversion = 3.4
from more import Response
def help_full(): def help_full():
return "!spell [<lang>] <word>: give the correct spelling of <word> in <lang=fr>." return "!spell [<lang>] <word>: give the correct spelling of <word> in <lang=fr>."

View File

@ -12,6 +12,8 @@ from tools import web
nemubotversion = 3.4 nemubotversion = 3.4
from more import Response
def help_full(): def help_full():
return "!syno <word>: give a list of synonyms for <word>." return "!syno <word>: give a list of synonyms for <word>."

View File

@ -11,6 +11,8 @@ from urllib.request import urlopen
nemubotversion = 3.4 nemubotversion = 3.4
from more import Response
import xmlparser import xmlparser
LANG = ["ar", "zh", "cz", "en", "fr", "gr", "it", LANG = ["ar", "zh", "cz", "en", "fr", "gr", "it",

View File

@ -9,6 +9,8 @@ from tools import web
nemubotversion = 3.4 nemubotversion = 3.4
from more import Response
def load(context): def load(context):
global DATAS global DATAS
DATAS.setIndex("name", "station") DATAS.setIndex("name", "station")

View File

@ -15,10 +15,11 @@ from urllib.parse import urlparse
from hooks import hook from hooks import hook
nemubotversion = 3.4
from networking import w3m from networking import w3m
from .atom import Atom from .atom import Atom
from more import Response
nemubotversion = 3.4
def help_full (): def help_full ():
return "This module is autonomous you can't interract with it." return "This module is autonomous you can't interract with it."

View File

@ -14,6 +14,8 @@ import mapquest
nemubotversion = 3.4 nemubotversion = 3.4
from more import Response
def load(context): def load(context):
global DATAS global DATAS
DATAS.setIndex("name", "city") DATAS.setIndex("name", "city")

View File

@ -10,6 +10,8 @@ from urllib.request import urlopen
nemubotversion = 3.4 nemubotversion = 3.4
from more import Response
from hooks import hook from hooks import hook
API_URL="http://worldcup.sfg.io/%s" API_URL="http://worldcup.sfg.io/%s"

View File

@ -11,6 +11,8 @@ from hooks import hook
nemubotversion = 3.4 nemubotversion = 3.4
from more import Response
def help_full(): def help_full():
return "!ycc [<url>]: with an argument, reduce the given <url> thanks to ycc.fr; without argument, reduce the last URL said on the current channel." return "!ycc [<url>]: with an argument, reduce the given <url> thanks to ycc.fr; without argument, reduce the last URL said on the current channel."

View File

@ -24,7 +24,6 @@ import zlib
from server.DCC import DCC from server.DCC import DCC
import hooks import hooks
from response import Response
class NetworkBot: class NetworkBot:
def __init__(self, context, srv, dest, dcc=None): def __init__(self, context, srv, dest, dcc=None):

View File

@ -1,185 +0,0 @@
# -*- 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/>.
import logging
import traceback
import sys
logger = logging.getLogger("nemubot.response")
class Response:
def __init__(self, message=None, channel=None, nick=None, server=None,
nomore="No more message", title=None, more="(suite) ",
count=None, ctcp=False, shown_first_count=-1,
line_treat=None):
self.nomore = nomore
self.more = more
self.line_treat = line_treat
self.rawtitle = title
self.server = server
self.messages = list()
self.alone = True
self.is_ctcp = ctcp
if message is not None:
self.append_message(message, shown_first_count=shown_first_count)
self.elt = 0 # Next element to display
self.sender = None
self.channel = channel
self.nick = nick
self.count = count
@property
def receivers(self):
if self.channel is None:
if self.nick is not None:
return [ self.nick ]
return [ self.sender.split("!")[0] ]
elif isinstance(self.channel, list):
return self.channel
else:
return [ self.channel ]
def set_sender(self, sender):
if sender is None or sender.find("!") < 0:
if sender is not None:
logger.warn("Bad sender provided in Response, it will be ignored.", stack_info=True)
self.sender = None
else:
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])
message = message[shown_first_count:]
self.messages.append(message)
self.alone = self.alone and len(self.messages) <= 1
if isinstance(self.rawtitle, list):
self.rawtitle.append(title)
elif title is not None:
rawtitle = self.rawtitle
self.rawtitle = list()
for osef in self.messages:
self.rawtitle.append(rawtitle)
self.rawtitle.pop()
self.rawtitle.append(title)
def append_content(self, message):
if message is not None and len(message) > 0:
if self.messages is None or len(self.messages) == 0:
self.messages = list(message)
self.alone = True
else:
self.messages[len(self.messages)-1] += message
self.alone = self.alone and len(self.messages) <= 1
@property
def empty(self):
return len(self.messages) <= 0
@property
def title(self):
if isinstance(self.rawtitle, list):
return self.rawtitle[0]
else:
return self.rawtitle
def pop(self):
self.messages.pop(0)
self.elt = 0
if isinstance(self.rawtitle, list):
self.rawtitle.pop(0)
if len(self.rawtitle) <= 0:
self.rawtitle = None
def treat_ctcp(self, content):
if self.is_ctcp:
return "\x01" + content + "\x01"
else:
return content
def get_message(self):
if self.alone and len(self.messages) > 1:
self.alone = False
if self.empty:
return self.treat_ctcp(self.nomore)
if self.line_treat is not None and self.elt == 0:
self.messages[0] = self.line_treat(self.messages[0]).replace("\n", " ").strip()
msg = ""
if self.channel is not None and self.nick is not None:
msg += self.nick + ": "
if self.title is not None:
if self.elt > 0:
msg += self.title + " " + self.more + ": "
else:
msg += self.title + ": "
if self.elt > 0:
msg += "[…] "
elts = self.messages[0][self.elt:]
if isinstance(elts, list):
for e in elts:
if len(msg) + len(e) > 430:
msg += "[…]"
self.alone = False
return self.treat_ctcp(msg)
else:
msg += e + ", "
self.elt += 1
self.pop()
return self.treat_ctcp(msg[:len(msg)-2])
else:
if len(elts.encode()) <= 432:
self.pop()
if self.count is not None:
return self.treat_ctcp(msg + elts + (self.count % len(self.messages)))
else:
return self.treat_ctcp(msg + elts)
else:
words = elts.split(' ')
if len(words[0].encode()) > 432 - len(msg.encode()):
self.elt += 432 - len(msg.encode())
return self.treat_ctcp(msg + elts[:self.elt] + "[…]")
for w in words:
if len(msg.encode()) + len(w.encode()) > 431:
msg += "[…]"
self.alone = False
return self.treat_ctcp(msg)
else:
msg += w + " "
self.elt += len(w) + 1
self.pop()
return self.treat_ctcp(msg)

View File

@ -185,13 +185,6 @@ class IRCServer(SocketServer):
return True return True
return False return False
def send_response(self, res):
for channel in res.receivers:
if channel is not None and channel != self.nick:
self.write("%s %s :%s" % ("NOTICE" if res.is_ctcp else "PRIVMSG", channel, res.get_message()))
else:
raise Exception("Trying to send a message to an undefined channel: %s" % channel)
def _close(self): def _close(self):
if self.socket is not None: self.write("QUIT") if self.socket is not None: self.write("QUIT")
return SocketServer._close(self) return SocketServer._close(self)
@ -219,17 +212,15 @@ class IRCServer(SocketServer):
else: else:
res = _ctcp_response("ERRMSG Unknown or unimplemented CTCP request") res = _ctcp_response("ERRMSG Unknown or unimplemented CTCP request")
if res is not None: if res is not None:
res.set_sender(mes.sender) res = res % mes.nick
self.send_response(res) self.write(res)
else: else:
yield mes yield mes
from response import Response
def _ctcp_response(msg): def _ctcp_response(msg):
return Response(msg, ctcp=True) return "NOTICE %%s :\x01%s\x01" % msg
mgx = re.compile(b'''^(?:@(?P<tags>[^ ]+)\ )? mgx = re.compile(b'''^(?:@(?P<tags>[^ ]+)\ )?

View File

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