# -*- 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 . import queue import re import threading import traceback import sys import bot from DCC import DCC from message import Message from response import Response import server class MessageConsumer: """Store a message before treating""" def __init__(self, srv, raw, time, prvt, data): self.srv = srv self.raw = raw self.time = time self.prvt = prvt self.data = data def treat_in(self, context, msg): """Treat the input message""" 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 def treat_out(self, context, res): """Treat the output message""" # 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 # Sent the message only if treat_post authorize it if context.treat_post(res): res.server.send_response(res, self.data) def run(self, context): """Create, parse and treat the message""" try: msg = Message(self.srv, self.raw, self.time, self.prvt) res = self.treat_in(context, msg) except: print ("\033[1;31mERROR:\033[0m occurred during the " "processing of the message: %s" % self.raw) exc_type, exc_value, exc_traceback = sys.exc_info() traceback.print_exception(exc_type, exc_value, exc_traceback) 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) # Inform that the message has been treated self.srv.msg_treated(self.data) class EventConsumer: """Store a event before treating""" def __init__(self, evt, timeout=20): self.evt = evt self.timeout = timeout def run(self, context): try: self.evt.launch_check() except: print ("\033[1;31mError:\033[0m during event end") exc_type, exc_value, exc_traceback = sys.exc_info() traceback.print_exception(exc_type, exc_value, exc_traceback) if self.evt.next is not None: context.add_event(self.evt, self.evt.id) class Consumer(threading.Thread): """Dequeue and exec requested action""" def __init__(self, context): self.context = context self.stop = False threading.Thread.__init__(self) def run(self): try: while not self.stop: stm = self.context.cnsr_queue.get(True, 20) stm.run(self.context) except queue.Empty: pass finally: self.context.cnsr_thrd_size -= 2 def _help_msg(modules, sndr, cmd): """Parse and response to help messages""" res = Response(sndr) if len(cmd) > 1: if cmd[1] in modules: if len(cmd) > 2: if hasattr(modules[cmd[1]], "HELP_cmd"): res.append_message(modules[cmd[1]].HELP_cmd(cmd[2])) else: res.append_message("No help for command %s in module %s" % (cmd[2], cmd[1])) elif hasattr(modules[cmd[1]], "help_full"): res.append_message(modules[cmd[1]].help_full()) else: res.append_message("No help for module %s" % cmd[1]) else: res.append_message("No module named %s" % cmd[1]) else: res.append_message("Pour me demander quelque chose, commencez " "votre message par mon nom ; je réagis " "également à certaine commandes commençant par" " !. Pour plus d'informations, envoyez le " "message \"!more\".") res.append_message("Mon code source est libre, publié sous " "licence AGPL (http://www.gnu.org/licenses/). " "Vous pouvez le consulter, le dupliquer, " "envoyer des rapports de bogues ou bien " "contribuer au projet sur GitHub : " "http://github.com/nemunaire/nemubot/") res.append_message(title="Pour plus de détails sur un module, " "envoyez \"!help nomdumodule\". Voici la liste" " de tous les modules disponibles localement", message=["\x03\x02%s\x03\x02 (%s)" % (im, modules[im].help_tiny ()) for im in modules if hasattr(modules[im], "help_tiny")]) return res