Mercurial > xib
changeset 180:102f895347ff
added a required "importance" argument to Bot.error()
Signed-off-by: Charly COSTE <changaco@changaco.net>
author | Charly COSTE <changaco@changaco.net> |
---|---|
date | Sat, 13 Feb 2010 16:32:28 +0100 |
parents | f6c6708c6c0e |
children | 803e00d72cb7 |
files | admin.py bot.py bridge.py commands.py irclib.py participant.py say_levels.py start_bots_from_xml_config.py weighted_string.py |
diffstat | 9 files changed, 293 insertions(+), 183 deletions(-) [+] |
line wrap: on
line diff
new file mode 100644 --- /dev/null +++ b/admin.py @@ -0,0 +1,23 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + + +class Admin: + def __init__(self, jid=None, say_level=None): + if jid: + self.jid = jid + if say_level: + self.say_level = say_level
--- a/bot.py +++ b/bot.py @@ -30,11 +30,12 @@ del muc from bridge import Bridge from participant import Participant import commands +import say_levels class Bot(threading.Thread): - def __init__(self, jid, password, nickname, admins_jid=[], error_fd=sys.stderr, debug=False): + def __init__(self, jid, password, nickname, admins=[], error_fd=sys.stderr, debug=False): threading.Thread.__init__(self) self.halt = False self.bridges = [] @@ -44,7 +45,7 @@ class Bot(threading.Thread): self.password = password self.error_fd = error_fd self.debug = debug - self.admins_jid = admins_jid + self.admins = admins self.xmpp_connections = {} self.irc = irclib.IRC() self.irc.bot = self @@ -55,18 +56,22 @@ class Bot(threading.Thread): try: self.xmpp_c = self.get_xmpp_connection(self.nickname) except: - self.error('[Error] XMPP Connection failed') + self.error(say_levels.error, 'XMPP Connection failed') raise self.xmpp_thread = threading.Thread(target=self._xmpp_loop) self.xmpp_thread.start() - def error(self, s, debug=False, send_to_admins=False): + def error(self, importance, message, debug=False, send_to_admins=False): """Output an error message.""" if send_to_admins == True: - self._send_message_to_admins(s) - if not debug or debug and self.debug: - self.error_fd.write(s.encode('utf-8')+"\n") + self._send_message_to_admins(importance, message) + if importance == -1: + return + if not debug: + self.error_fd.write(self.format_message(importance, message).encode('utf-8')+'\n') + if debug and self.debug: + self.error_fd.write('='*importance+'> '+message.encode('utf-8')+'\n') def _xmpp_loop(self): @@ -89,7 +94,7 @@ class Bot(threading.Thread): if i == j: ping = xmpp.protocol.Iq(typ='get') ping.addChild(name='ping', namespace='urn:xmpp:ping') - self.error('=> Debug: sending XMPP ping', debug=True) + self.error(1, 'sending XMPP ping', debug=True) c.pings.append(c.send(ping)) if hasattr(c, 'Process'): c.Process(0.01) @@ -99,17 +104,16 @@ class Bot(threading.Thread): except RuntimeError: pass except (xml.parsers.expat.ExpatError, xmpp.protocol.XMLNotWellFormed): - self.error('=> Debug: invalid stanza', debug=True) + self.error(1, 'invalid stanza', debug=True) self.reopen_xmpp_connection(c) unlock = True except xmpp.Conflict: - self.error('=> Debug: conflict', debug=True) + self.error(1, 'conflict', debug=True) self.reopen_xmpp_connection(c) unlock = True except: - error = '[Error] Unknown exception on XMPP thread:\n' - error += traceback.format_exc() - self.error(error, send_to_admins=True) + error = 'Unknown exception on XMPP thread:\n'+traceback.format_exc() + self.error(say_levels.error, error, send_to_admins=True) unlock = True if unlock == True: c.lock.release() @@ -121,11 +125,10 @@ class Bot(threading.Thread): xmpp_c = dispatcher._owner if xmpp_c.nickname != self.nickname: - self.error('=> Debug: Skipping XMPP presence not received on bot connection.', debug=True) + self.error(1, 'Skipping XMPP presence not received on bot connection.', debug=True) return - self.error('==> Debug: Received XMPP presence.', debug=True) - self.error(presence.__str__(fancy=1), debug=True) + self.error(2, 'Received XMPP presence.\n'+presence.__str__(fancy=1), debug=True) from_ = xmpp.protocol.JID(presence.getFrom()) bare_jid = unicode(from_.getNode()+'@'+from_.getDomain()) @@ -153,9 +156,9 @@ class Bot(threading.Thread): if r == 'The conference component is shutting down': # MUC server is going down, try to restart the bridges in 1 minute bridges = self.findBridges([from_.getDomain()]) - error_message = '[Warning] The MUC server '+from_.getDomain()+' seems to be going down, the bot will try to recreate all bridges related to this server in 1 minute' - self.restart_bridges_delayed(bridges, 60, error_message) - self.error(presence.__str__(fancy=1).encode('utf-8'), debug=True) + m = 'The MUC server '+from_.getDomain()+' seems to be going down, the bot will try to recreate all bridges related to this server in 1 minute' + error = (say_levels.warning, m) + self.restart_bridges_delayed(bridges, 60, error) return elif r == '': r = 'None given' @@ -163,7 +166,7 @@ class Bot(threading.Thread): r = 'None given' # room has been destroyed, stop the bridge - self.error('[Error] The MUC room of the bridge '+str(bridge)+' has been destroyed with reason "'+r+'", stopping the bridge', send_to_admins=True) + self.error(say_levels.error, 'The MUC room of the bridge '+str(bridge)+' has been destroyed with reason "'+r+'", stopping the bridge', send_to_admins=True) bridge.stop(message='The MUC room of the bridge has been destroyed with reason "'+r+'", stopping the bridge') else: @@ -188,11 +191,11 @@ class Bot(threading.Thread): return item = x.getTag('item') if not item: - self.error('=> Debug: bad stanza, no item element', debug=True) + self.error(1, 'bad stanza, no item element', debug=True) return new_nick = item.getAttr('nick') if not new_nick: - self.error('=> Debug: bad stanza, new nick is not given', debug=True) + self.error(1, 'bad stanza, new nick is not given', debug=True) return p.changeNickname(new_nick, 'irc') @@ -225,9 +228,7 @@ class Bot(threading.Thread): elif x and x.getTag('status', attrs={'code': '301'}): # participant was banned if p == None: - m = '[Error] bot got banned from XMPP' - self.error(m) - bridge.say(m, on_xmpp=False) + bridge.say(say_levels.error, 'bot got banned from XMPP', on_xmpp=False, send_to_admins=True) self.removeBridge(bridge) return if item: @@ -265,7 +266,6 @@ class Bot(threading.Thread): bridges = self.findBridges([from_.getDomain()]) error_message = '[Error] XMPP Remote server not found: '+from_.getDomain() self.restart_bridges_delayed(bridges, 60, error_message) - self.error(presence.__str__(fancy=1).encode('utf-8'), debug=True) else: raise Exception(presence.__str__(fancy=1).encode('utf-8')) @@ -278,8 +278,8 @@ class Bot(threading.Thread): # if we have the real jid check if the participant is a bot admin if real_jid and isinstance(p, Participant): - for jid in self.admins_jid: - if xmpp.protocol.JID(jid).bareMatch(real_jid): + for admin in self.admins: + if xmpp.protocol.JID(admin.jid).bareMatch(real_jid): p.bot_admin = True break @@ -296,11 +296,10 @@ class Bot(threading.Thread): # Ignore pongs if iq.getType() in ['result', 'error'] and iq.getID() in xmpp_c.pings: xmpp_c.pings.remove(iq.getID()) - self.error('=> Debug: received XMPP pong', debug=True) + self.error(1, 'received XMPP pong', debug=True) return - self.error('==> Debug: Received XMPP iq.', debug=True) - self.error(iq.__str__(fancy=1), debug=True) + self.error(2, 'Received XMPP iq.\n'+iq.__str__(fancy=1), debug=True) def _xmpp_message_handler(self, dispatcher, message): @@ -317,8 +316,7 @@ class Bot(threading.Thread): if from_bare_jid == bridge.xmpp_room_jid: # message comes from a room participant - self.error('==> Debug: Received XMPP chat message.', debug=True) - self.error(message.__str__(fancy=1), debug=True) + self.error(2, 'Received XMPP chat message.\n'+message.__str__(fancy=1), debug=True) try: from_ = bridge.getParticipant(message.getFrom().getResource()) @@ -331,24 +329,22 @@ class Bot(threading.Thread): r = self.respond(str(message.getBody()), participant=from_) if isinstance(r, basestring) and len(r) > 0: s = xmpp.protocol.Message(to=message.getFrom(), body=r, typ='chat') - self.error('==> Debug: Sending', debug=True) - self.error(s.__str__(fancy=1), debug=True) + self.error(2, 'Sending\n'+s.__str__(fancy=1), debug=True) xmpp_c.send(s) else: - self.error('=> Debug: won\'t answer.', debug=True) + self.error(1, 'won\'t answer.', debug=True) return - self.error('=> Debug: XMPP chat message not relayed', debug=True) + self.error(1, 'XMPP chat message not relayed', debug=True) return # message does not come from a room if xmpp_c.nickname == self.nickname: - self.error('==> Debug: Received XMPP chat message.', debug=True) - self.error(message.__str__(fancy=1), debug=True) + self.error(2, 'Received XMPP chat message.\n'+message.__str__(fancy=1), debug=True) # Find out if the message comes from a bot admin bot_admin = False - for jid in self.admins_jid: - if xmpp.protocol.JID(jid).bareMatch(message.getFrom()): + for admin in self.admins: + if xmpp.protocol.JID(admin.jid).bareMatch(message.getFrom()): bot_admin = True break @@ -356,12 +352,11 @@ class Bot(threading.Thread): r = self.respond(str(message.getBody()), bot_admin=bot_admin) if isinstance(r, basestring) and len(r) > 0: s = xmpp.protocol.Message(to=message.getFrom(), body=r, typ='chat') - self.error('==> Debug: Sending', debug=True) - self.error(s.__str__(fancy=1), debug=True) + self.error(2, 'Sending\n'+s.__str__(fancy=1), debug=True) xmpp_c.send(s) else: - self.error('=> Debug: Ignoring XMPP chat message not received on bot connection.', debug=True) + self.error(1, 'Ignoring XMPP chat message not received on bot connection.', debug=True) elif message.getType() == 'groupchat': # message comes from a room @@ -372,14 +367,14 @@ class Bot(threading.Thread): return if xmpp_c.nickname != self.nickname: - self.error('=> Debug: Ignoring XMPP MUC message not received on bot connection.', debug=True) + self.error(1, 'Ignoring XMPP MUC message not received on bot connection.', debug=True) return from_ = xmpp.protocol.JID(message.getFrom()) if unicode(from_.getResource()) == self.nickname: - self.error('=> Debug: Ignoring XMPP MUC message sent by self.', debug=True) + self.error(1, 'Ignoring XMPP MUC message sent by self.', debug=True) return room_jid = unicode(from_.getNode()+'@'+from_.getDomain()) @@ -388,18 +383,17 @@ class Bot(threading.Thread): resource = unicode(from_.getResource()) if resource == '': # message comes from the room itself - self.error('=> Debug: Ignoring XMPP groupchat message sent by the room.', debug=True) + self.error(1, 'Ignoring XMPP groupchat message sent by the room.', debug=True) return else: # message comes from a participant of the room - self.error('==> Debug: Received XMPP groupchat message.', debug=True) - self.error(message.__str__(fancy=1), debug=True) + self.error(2, 'Received XMPP groupchat message.\n'+message.__str__(fancy=1), debug=True) try: participant = bridge.getParticipant(resource) except Bridge.NoSuchParticipantException: if resource != self.nickname: - self.error('=> Debug: NoSuchParticipantException "'+resource+'" on "'+str(bridge)+'", WTF ?', debug=True) + self.error(1, 'NoSuchParticipantException "'+resource+'" on "'+str(bridge)+'", WTF ?', debug=True) return participant.sayOnIRC(message.getBody()) @@ -422,19 +416,16 @@ class Bot(threading.Thread): elif err == 'forbidden': # we don't have the permission to speak # let's remove the bridge and tell admins - self.error('[Error] Not allowed to speak on the XMPP MUC of bridge '+str(b)+', stopping it', send_to_admins=True) + self.error(say_levels.error, 'Not allowed to speak on the XMPP MUC of bridge '+str(b)+', stopping it', send_to_admins=True) b.stop(message='Not allowed to speak on the XMPP MUC, stopping bridge.') else: - self.error('==> Debug: recevied unknown error message', debug=True) - self.error(message.__str__(fancy=1), debug=True) + self.error(2, 'recevied unknown error message\n'+message.__str__(fancy=1), debug=True) return - self.error('==> Debug: recevied unknown error message', debug=True) - self.error(message.__str__(fancy=1), debug=True) + self.error(2, 'recevied unknown error message\n'+message.__str__(fancy=1), debug=True) else: - self.error('==> Debug: Received XMPP message of unknown type "'+str(message.getType())+'".', debug=True) - self.error(message.__str__(fancy=1), debug=True) + self.error(2, 'Received XMPP message of unknown type "'+str(message.getType())+'".\n'+message.__str__(fancy=1), debug=True) def _irc_event_handler(self, connection, event): @@ -450,7 +441,7 @@ class Bot(threading.Thread): if 'all' in event.eventtype() or 'motd' in event.eventtype() or event.eventtype() in ['nicknameinuse', 'nickcollision', 'erroneusnickname']: return if event.eventtype() in ['pong', 'privnotice', 'ctcp', 'nochanmodes', 'notexttosend', 'currenttopic', 'topicinfo', '328']: - self.error('=> Debug: ignoring IRC '+event.eventtype(), debug=True) + self.error(1, 'ignoring IRC '+event.eventtype(), debug=True) return @@ -467,15 +458,15 @@ class Bot(threading.Thread): connection.really_connected = True connection._call_nick_callbacks(None) elif len(connection.nick_callbacks) > 0: - self.error('===> Debug: event target ('+event.target()+') and connection nickname ('+connection.nickname+') don\'t match') + self.error(3, 'event target ('+event.target()+') and connection nickname ('+connection.nickname+') don\'t match') connection._call_nick_callbacks('nicknametoolong', arguments=[len(event.target())]) - self.error('=> Debug: ignoring '+event.eventtype(), debug=True) + self.error(1, 'ignoring '+event.eventtype(), debug=True) return # A string representation of the event event_str = 'connection='+connection.__str__()+'\neventtype='+event.eventtype()+'\nsource='+repr(event.source())+'\ntarget='+repr(event.target())+'\narguments='+repr(event.arguments()) - debug_str = '==> Debug: Received IRC event.\n'+event_str + debug_str = 'Received IRC event.\n'+event_str printed_event = False @@ -490,22 +481,22 @@ class Bot(threading.Thread): if event.eventtype() in ['quit', 'part', 'nick', 'kick']: if connection.get_nickname() != self.nickname: - self.error('=> Debug: ignoring IRC '+event.eventtype()+' not received on bot connection', debug=True) + self.error(1, 'ignoring IRC '+event.eventtype()+' not received on bot connection', debug=True) return else: - self.error(debug_str, debug=True) + self.error(2, debug_str, debug=True) printed_event = True if event.eventtype() == 'kick' and len(event.arguments()) < 1: - self.error('=> Debug: length of arguments should be greater than 0 for a '+event.eventtype()+' event') + self.error(1, 'length of arguments should be greater than 0 for a '+event.eventtype()+' event') return if event.eventtype() in ['pubmsg', 'action']: if connection.get_nickname() != self.nickname: - self.error('=> Debug: ignoring IRC '+event.eventtype()+' not received on bot connection', debug=True) + self.error(1, 'ignoring IRC '+event.eventtype()+' not received on bot connection', debug=True) return if nickname == self.nickname: - self.error('=> Debug: ignoring IRC '+event.eventtype()+' sent by self', debug=True) + self.error(1, 'ignoring IRC '+event.eventtype()+' sent by self', debug=True) return # TODO: lock self.bridges for thread safety @@ -527,14 +518,14 @@ class Bot(threading.Thread): try: to_ = bridge.getParticipant(event.target().split('!')[0]) - self.error(debug_str, debug=True) + self.error(2, debug_str, debug=True) from_.sayOnXMPPTo(to_.nickname, event.arguments()[0]) return except Bridge.NoSuchParticipantException: if event.target().split('!')[0] == self.nickname: # Message is for the bot - self.error(debug_str, debug=True) + self.error(2, debug_str, debug=True) connection.privmsg(from_.nickname, self.respond(event.arguments()[0])) return else: @@ -555,7 +546,7 @@ class Bot(threading.Thread): bridge.removeParticipant('irc', kicked.nickname, 'Kicked by '+nickname+' (no reason was given)') return except Bridge.NoSuchParticipantException: - self.error('=> Debug: a participant that was not here has been kicked ? WTF ?') + self.error(1, 'a participant that was not here has been kicked ? WTF ?') return else: continue @@ -588,7 +579,7 @@ class Bot(threading.Thread): # Chan message if event.eventtype() in ['pubmsg', 'action']: if bridge.irc_room == event.target().lower() and bridge.irc_server == connection.server: - self.error(debug_str, debug=True) + self.error(2, debug_str, debug=True) message = event.arguments()[0] if event.eventtype() == 'action': message = '/me '+message @@ -604,7 +595,7 @@ class Bot(threading.Thread): # Handle bannedfromchan if event.eventtype() == 'bannedfromchan': if len(event.arguments()) < 1: - self.error('=> Debug: length of arguments should be greater than 0 for a '+event.eventtype()+' event') + self.error(1, 'length of arguments should be greater than 0 for a '+event.eventtype()+' event') return for bridge in self.bridges: @@ -612,19 +603,19 @@ class Bot(threading.Thread): continue if event.target() == self.nickname: - self.error('[Error] the nickname "'+event.target()+'" is banned from the IRC chan of bridge "'+str(bridge)+'"') + self.error(say_levels.error, 'the nickname "'+event.target()+'" is banned from the IRC chan of bridge "'+str(bridge)+'"') raise Exception('[Error] the nickname "'+event.target()+'" is banned from the IRC chan of bridge "'+str(bridge)+'"') else: try: banned = bridge.getParticipant(event.target()) if banned.irc_connection != 'bannedfromchan': banned.irc_connection = 'bannedfromchan' - self.error(debug_str, debug=True) - bridge.say('[Warning] the nickname "'+event.target()+'" is banned from the IRC chan', log=True) + self.error(2, debug_str, debug=True) + bridge.say(say_levels.warning, 'the nickname "'+event.target()+'" is banned from the IRC chan', log=True) else: - self.error('=> Debug: ignoring '+event.eventtype(), debug=True) + self.error(1, 'ignoring '+event.eventtype(), debug=True) except Bridge.NoSuchParticipantException: - self.error('=> Debug: no such participant. WTF ?') + self.error(1, 'no such participant. WTF ?') return return @@ -633,7 +624,7 @@ class Bot(threading.Thread): # Joining events if event.eventtype() in ['namreply', 'join']: if connection.get_nickname() != self.nickname: - self.error('=> Debug: ignoring IRC '+event.eventtype()+' not received on bridge connection', debug=True) + self.error(1, 'ignoring IRC '+event.eventtype()+' not received on bridge connection', debug=True) return if event.eventtype() == 'namreply': @@ -646,8 +637,8 @@ class Bot(threading.Thread): elif event.eventtype() == 'join': bridges = self.getBridges(irc_room=event.target().lower(), irc_server=connection.server) if len(bridges) == 0: - self.error(debug_str, debug=True) - self.error('===> Debug: no bridge found for "'+event.target().lower()+' at '+connection.server+'"', debug=True) + self.error(2, debug_str, debug=True) + self.error(3, 'no bridge found for "'+event.target().lower()+' at '+connection.server+'"', debug=True) return for bridge in bridges: bridge.addParticipant('irc', nickname, irc_id=event.source()) @@ -656,14 +647,14 @@ class Bot(threading.Thread): if event.eventtype() in ['disconnect', 'kill', 'error']: if len(event.arguments()) > 0 and event.arguments()[0] == 'Connection reset by peer': - self.error(debug_str, debug=True) + self.error(2, debug_str, debug=True) else: - self.error(debug_str, send_to_admins=True) + self.error(2, debug_str, send_to_admins=True) return if event.eventtype() in ['cannotsendtochan', 'notonchannel']: - self.error(debug_str, debug=True) + self.error(2, debug_str, debug=True) bridges = self.getBridges(irc_room=event.arguments()[0], irc_server=connection.server) if len(bridges) > 1: raise Exception, 'more than one bridge for one irc chan, WTF ?' @@ -679,17 +670,22 @@ class Bot(threading.Thread): # Unhandled events if not printed_event: - self.error('[Debug] The following IRC event was not handled:\n'+event_str+'\n', send_to_admins=True) + self.error(say_levels.debug, 'The following IRC event was not handled:\n'+event_str+'\n', send_to_admins=True) else: - self.error('=> Debug: event not handled', debug=True) + self.error(1, 'event not handled', debug=True) self._send_message_to_admins('[Debug] The following IRC event was not handled:\n'+event_str) - def _send_message_to_admins(self, message): + def _send_message_to_admins(self, importance, message): """[Internal] Send XMPP Message to bot admin(s)""" - for admin_jid in self.admins_jid: + for admin in self.admins: + if importance != -1: + if admin.say_level == say_levels.nothing or importance < admin.say_level: + continue + message = self.format_message(importance, message) + try: - self.xmpp_c.send(xmpp.protocol.Message(to=admin_jid, body=message, typ='chat')) + self.xmpp_c.send(xmpp.protocol.Message(to=admin.jid, body=message, typ='chat')) except: pass @@ -712,6 +708,12 @@ class Bot(threading.Thread): return bridges + def format_message(self, importance, message): + if importance < 0 or importance >= len(say_levels.levels): + raise Exception('[Internal Error] unknown message importance') + return'['+str(say_levels.get(importance))+'] '+message + + def getBridges(self, irc_room=None, irc_server=None, xmpp_room_jid=None): # TODO: lock self.bridges for thread safety bridges = [b for b in self.bridges] @@ -732,9 +734,9 @@ class Bot(threading.Thread): if self.xmpp_connections.has_key(nickname): c = self.xmpp_connections[nickname] c.used_by += 1 - self.error('===> Debug: using existing XMPP connection for "'+nickname+'", now used by '+str(c.used_by)+' bridges', debug=True) + self.error(3, 'using existing XMPP connection for "'+nickname+'", now used by '+str(c.used_by)+' bridges', debug=True) return c - self.error('===> Debug: opening new XMPP connection for "'+nickname+'"', debug=True) + self.error(3, 'opening new XMPP connection for "'+nickname+'"', debug=True) c = xmpp.client.Client(self.bare_jid.getDomain(), debug=[]) c.lock = threading.RLock() c.lock.acquire() @@ -770,7 +772,7 @@ class Bot(threading.Thread): if p.xmpp_c == c: participants.append(p) p.xmpp_c = None - self.error('===> Debug: reopening XMPP connection for "'+nickname+'"', debug=True) + self.error(3, 'reopening XMPP connection for "'+nickname+'"', debug=True) if self.xmpp_connections.has_key(nickname): self.xmpp_connections.pop(nickname) c.send(xmpp.protocol.Presence(typ='unavailable')) @@ -794,14 +796,14 @@ class Bot(threading.Thread): c.lock.acquire() c.used_by -= 1 if c.used_by < 1 or force: - self.error('===> Debug: closing XMPP connection for "'+nickname+'"', debug=True) + self.error(3, 'closing XMPP connection for "'+nickname+'"', debug=True) self.xmpp_connections.pop(nickname) c.send(xmpp.protocol.Presence(typ='unavailable')) c.lock.release() del c else: c.lock.release() - self.error('===> Debug: XMPP connection for "'+nickname+'" is now used by '+str(c.used_by)+' bridges', debug=True) + self.error(3, 'XMPP connection for "'+nickname+'" is now used by '+str(c.used_by)+' bridges', debug=True) def removeBridge(self, bridge, message='Removing bridge'): @@ -832,14 +834,14 @@ class Bot(threading.Thread): for b in self.bridges: b.init2() - self.error('Bot restarted.', send_to_admins=True) + self.error(-1, 'Bot restarted.', send_to_admins=True) - def restart_bridges_delayed(self, bridges, delay, error_message, protocol='xmpp'): + def restart_bridges_delayed(self, bridges, delay, error, protocol='xmpp'): if len(bridges) > 0: - error_message += '\nThese bridges will be stopped:' + error[1] += '\nThese bridges will be stopped:' for b in bridges: - error_message += '\n'+str(b) + error[1] += '\n'+str(b) if protocol == 'xmpp': leave_message = 'Could not connect to the MUC server ('+b.xmpp_room_jid+')' @@ -853,7 +855,7 @@ class Bot(threading.Thread): b.stop(message=leave_message) - self.error(error_message, send_to_admins=True) + self.error(error[0], error[1], send_to_admins=True) def stop(self, message='Stopping bot'):
--- a/bridge.py +++ b/bridge.py @@ -25,19 +25,12 @@ xmpp = muc.xmpp del muc from participant import Participant +import say_levels class Bridge: - _all = 0 - _info = 1 - _notice = 2 - _warning = 3 - _error = 4 - _nothing = 5 - _say_levels = ['all', 'info', 'notice', 'warning', 'error', 'nothing'] - _modes = ['normal', 'bypass', 'limited', 'minimal'] - + modes = ['bypass', 'normal', 'limited', 'minimal'] class NoSuchParticipantException(Exception): pass @@ -51,12 +44,9 @@ class Bridge: self.irc_connection_interval = irc_connection_interval self.irc_charsets = irc_charsets self.xmpp_room_jid = xmpp_room_jid - if hasattr(self.__class__, '_'+say_level): - self.say_level = getattr(self.__class__, '_'+say_level) - else: - raise Exception('[Error] "'+say_level+'" is not a correct value for a bridge\'s "say_level" attribute') + self.say_level = say_level self.participants = [] - if mode not in self.__class__._modes: + if mode not in self.__class__.modes: raise Exception('[Error] "'+mode+'" is not a correct value for a bridge\'s "mode" attribute') self.mode = mode @@ -74,11 +64,11 @@ class Bridge: self.irc_connection = self.bot.irc.open_connection(self.irc_server, self.irc_port, self.bot.nickname, delay=self.irc_connection_interval) self.irc_connection.connect(nick_callback=self._irc_nick_callback, charsets=self.irc_charsets) - self.bot.error('[Notice] bridge "'+str(self)+'" is running in '+self.mode+' mode and a say_level of "'+self.__class__._say_levels[self.say_level]+'"') + self.bot.error(say_levels.notice, 'bridge "'+str(self)+'" is running in '+self.mode+' mode and a say_level of "'+str(self.say_level)+'"') def _join_irc_failed(self): - self.bot.error('[Error] failed to connect to the IRC chan of bridge "'+str(self)+'", stopping bridge', send_to_admins=True) + self.bot.error(say_levels.error, 'failed to connect to the IRC chan of bridge "'+str(self)+'", stopping bridge', send_to_admins=True) self.stop(message='failed to connect to the IRC chan') @@ -87,14 +77,14 @@ class Bridge: if self.mode == None: return self.irc_connection.join(self.irc_room) - self.bot.error('===> Debug: successfully connected on IRC side of bridge "'+str(self)+'"', debug=True) - self.say('[Notice] bridge "'+str(self)+'" is running in '+self.mode+' mode', on_xmpp=False) + self.bot.error(3, 'successfully connected on IRC side of bridge "'+str(self)+'"', debug=True) + self.say(say_levels.notice, 'bridge "'+str(self)+'" is running in '+self.mode+' mode', on_xmpp=False) if self.mode not in ['normal', 'bypass']: self.show_participants_list_on(protocols=['irc']) else: self.mode = None if self.xmpp_room.connected == True: - self.say('[Error] failed to connect to the IRC chan, leaving ...', on_irc=False) + self.say(say_levels.error, 'failed to connect to the IRC chan, leaving ...', on_irc=False) try: if error == 'nicknameinuse': raise Exception('[Error] "'+self.bot.nickname+'" is already used in the IRC chan or reserved on the IRC server of bridge "'+str(self)+'"') @@ -125,12 +115,12 @@ class Bridge: del self.reconnecting if self.mode == None: return - self.bot.error('===> Debug: succesfully connected on XMPP side of bridge "'+str(self)+'"', debug=True) - self.say('[Notice] bridge "'+str(self)+'" is running in '+self.mode+' mode', on_irc=False) + self.bot.error(3, 'succesfully connected on XMPP side of bridge "'+str(self)+'"', debug=True) + self.say(say_levels.notice, 'bridge "'+str(self)+'" is running in '+self.mode+' mode', on_irc=False) else: self.mode = None if self.irc_connection.really_connected == True: - self.say('[Error] failed to connect to the XMPP room, leaving ...', on_xmpp=False) + self.say(say_levels.error, 'failed to connect to the XMPP room, leaving ...', on_xmpp=False) for error in errors: try: raise error @@ -138,14 +128,14 @@ class Bridge: self._RemoteServerNotFound_handler() except: trace = traceback.format_exc() - self.bot.error('[Error] failed to connect to the XMPP room of bridge "'+str(self)+'", stopping bridge\n'+trace, send_to_admins=True) + self.bot.error(say_levels.error, 'failed to connect to the XMPP room of bridge "'+str(self)+'", stopping bridge\n'+trace, send_to_admins=True) self.stop(message='failed to connect to the XMPP room') def addParticipant(self, from_protocol, nickname, real_jid=None, irc_id=None): """Add a participant to the bridge.""" if (from_protocol == 'irc' and nickname == self.bot.nickname) or (from_protocol == 'xmpp' and nickname == self.bot.nickname): - self.bot.error('===> Debug: not adding self ('+self.bot.nickname+') to bridge "'+str(self)+'"', debug=True) + self.bot.error(3, 'not adding self ('+self.bot.nickname+') to bridge "'+str(self)+'"', debug=True) return try: p = self.getParticipant(nickname) @@ -163,14 +153,14 @@ class Bridge: return self.lock.acquire() - self.bot.error('===> Debug: adding participant "'+nickname+'" from "'+from_protocol+'" to bridge "'+str(self)+'"', debug=True) + self.bot.error(3, 'adding participant "'+nickname+'" from "'+from_protocol+'" to bridge "'+str(self)+'"', debug=True) try: p = Participant(self, from_protocol, nickname, real_jid=real_jid) except IOError: - self.bot.error('===> Debug: IOError while adding participant "'+nickname+'" from "'+from_protocol+'" to bridge "'+str(self)+'", reconnectiong ...', debug=True) + self.bot.error(3, 'IOError while adding participant "'+nickname+'" from "'+from_protocol+'" to bridge "'+str(self)+'", reconnectiong ...', debug=True) p.xmpp_c.reconnectAndReauth() except: - self.bot.error('===> Debug: unknown error while adding participant "'+nickname+'" from "'+from_protocol+'" to bridge "'+str(self)+'"', debug=True) + self.bot.error(3, 'unknown error while adding participant "'+nickname+'" from "'+from_protocol+'" to bridge "'+str(self)+'"', debug=True) traceback.print_exc() return self.participants.append(p) @@ -249,7 +239,7 @@ class Bridge: if p.nickname != p.duplicate_nickname: p.leave('Bridge is switching to '+new_mode+' mode') - self.say('[Notice] Bridge is switching from '+old_mode+' to '+new_mode+' mode.', log=True) + self.say(say_levels.notice, 'Bridge is switching from '+old_mode+' to '+new_mode+' mode.', log=True) def getParticipant(self, nickname): @@ -328,11 +318,11 @@ class Bridge: raise Exception('[Internal Error] bad protocol') if was_on_both == True: - self.bot.error('===> Debug: "'+nickname+'" was on both sides of bridge "'+str(self)+'" but left '+left_protocol, debug=True) + self.bot.error(3, '"'+nickname+'" was on both sides of bridge "'+str(self)+'" but left '+left_protocol, debug=True) elif was_on_both == False: self.lock.acquire() - self.bot.error('===> Debug: removing participant "'+nickname+'" from bridge "'+str(self)+'"', debug=True) + self.bot.error(3, 'removing participant "'+nickname+'" from bridge "'+str(self)+'"', debug=True) self.participants.remove(p) p.leave(leave_message) del p @@ -345,14 +335,14 @@ class Bridge: self.show_participants_list_on(protocols=['xmpp']) else: - self.bot.error('=> Debug: Bad decision tree, p.protocol='+p.protocol+' left_protocol='+left_protocol+'\np.xmpp_c='+str(p.xmpp_c)+'\np.irc_connection='+str(p.irc_connection), debug=True) + self.bot.error(1, 'Bad decision tree, p.protocol='+p.protocol+' left_protocol='+left_protocol+'\np.xmpp_c='+str(p.xmpp_c)+'\np.irc_connection='+str(p.irc_connection), debug=True) def restart(self): """Restart the bridge""" # Tell admins - self.bot.error('Restarting bridge '+str(self), send_to_admins=True) + self.bot.error(-1, 'Restarting bridge '+str(self), send_to_admins=True) # Stop the bridge self.stop(message='Restarting bridge') @@ -361,19 +351,12 @@ class Bridge: self.init2() - def say(self, message, on_irc=True, on_xmpp=True, log=False): + def say(self, importance, message, on_irc=True, on_xmpp=True, log=False, send_to_admins=False): """Make the bot say something.""" - if message[0] != '[': - raise Exception('[Internal Error] message does not start with "["') - if log: - self.bot.error(message+' ('+str(self)+')') - if self.say_level == self.__class__._nothing: - return - level = re.findall('^\[(Info|Notice|Warning|Error)\]', message) - if len(level) == 0: - raise Exception('[Internal Error] unknown message importance "'+re.findall('^\[([^[\]]+)', message)[0]+'"') - level = level[0].lower() - if getattr(self.__class__, '_'+level) < self.say_level: + message = self.bot.format_message(importance, message) + if log or send_to_admins: + self.bot.error(importance, message+' ('+str(self)+')', send_to_admins=send_to_admins) + if importance < self.say_level: return if on_xmpp == True: self.xmpp_room.say(message) @@ -384,10 +367,10 @@ class Bridge: def show_participants_list_on(self, protocols=[]): if 'irc' in protocols and self.irc_connection.really_connected: xmpp_participants_nicknames = self.get_participants_nicknames_list(protocols=['xmpp']) - self.say('[Info] Participants on XMPP: '+' '.join(xmpp_participants_nicknames), on_xmpp=False) + self.say(say_levels.info, 'Participants on XMPP: '+' '.join(xmpp_participants_nicknames), on_xmpp=False) if 'xmpp' in protocols: irc_participants_nicknames = self.get_participants_nicknames_list(protocols=['irc']) - self.say('[Info] Participants on IRC: '+' '.join(irc_participants_nicknames), on_irc=False) + self.say(say_levels.info, 'Participants on IRC: '+' '.join(irc_participants_nicknames), on_irc=False) def stop(self, message='Stopping bridge'):
--- a/commands.py +++ b/commands.py @@ -22,7 +22,9 @@ import muc xmpp = muc.xmpp del muc +from admin import Admin from bridge import Bridge +import say_levels commands = ['xmpp-participants', 'irc-participants', 'xmpp-connections', 'irc-connections', 'connections', 'bridges'] @@ -80,8 +82,8 @@ def add_bridge(bot, command, args_array, parser.add_argument('xmpp_room_jid', type=str) parser.add_argument('irc_chan', type=str) parser.add_argument('irc_server', type=str) - parser.add_argument('--mode', choices=Bridge._modes, default='normal') - parser.add_argument('--say-level', choices=Bridge._say_levels, default='all') + parser.add_argument('--mode', choices=Bridge.modes, default=Bridge.modes[0]) + parser.add_argument('--say-level', choices=say_levels.levels, default=say_levels.levels[1]) parser.add_argument('--irc-port', type=int, default=6667) try: args = parser.parse_args(args_array) @@ -96,11 +98,15 @@ def add_bridge(bot, command, args_array, def add_xmpp_admin(bot, command, args_array, bridge): parser = ArgumentParser(prog=command) parser.add_argument('jid', type=str) + parser.add_argument('--say-level', choices=say_levels.levels, default=say_levels.levels[1]) try: args = parser.parse_args(args_array) except Exception as e: return '\n'+e.args[1] - bot.admins_jid.append(args.jid) + admin = Admin() + admin.jid = args.jid + admin.say_level = args.say_level + bot.admins.append(admin) for b in bot.bridges: for p in b.participants: if p.real_jid != None and xmpp.protocol.JID(args.jid).bareMatch(p.real_jid): @@ -124,7 +130,7 @@ def bridges(bot, command, args_array, br if args.show_mode: ret += ' - mode='+b.mode if args.show_say_level: - ret += ' - say_level='+Bridge._say_levels[b.say_level] + ret += ' - say_level='+str(b.say_level) if args.show_participants: xmpp_participants_nicknames = b.get_participants_nicknames_list(protocols=['xmpp']) ret += '\nparticipants on XMPP ('+str(len(xmpp_participants_nicknames))+'): '+' '.join(xmpp_participants_nicknames) @@ -138,7 +144,7 @@ def bridges(bot, command, args_array, br def change_bridges_mode(bot, command, args_array, bridge): parser = ArgumentParser(prog=command) parser.add_argument('bridge_id', nargs='+') - parser.add_argument('new_mode', choices=Bridge._modes) + parser.add_argument('new_mode', choices=Bridge.modes) try: args = parser.parse_args(args_array) except Exception as e:
--- a/irclib.py +++ b/irclib.py @@ -73,6 +73,8 @@ import threading import traceback import math +import say_levels + VERSION = 0, 4, 8 DEBUG = 0 @@ -176,7 +178,7 @@ class IRC: stack[0][0](*stack[0][1]) stack.pop(0) delay = self.connection_interval(server=server_str) - self.bot.error('==> Debug: waiting '+str(delay)+' seconds before next connection on '+server_str, debug=True) + self.bot.error(2, 'waiting '+str(delay)+' seconds before next connection on '+server_str, debug=True) self.execute_delayed(delay, self._connection_loop, (server_str,)) else: self.connection_stacks.pop(server_str) @@ -293,7 +295,7 @@ class IRC: except ServerNotConnectedError: self.bot.restart() except: - self.bot.error('[Error] Unkonwn exception on IRC thread:\n'+traceback.format_exc(), send_to_admins=True) + self.bot.error(say_levels.error, 'Unkonwn exception on IRC thread:\n'+traceback.format_exc(), send_to_admins=True) def disconnect_all(self, message="", volontary=True): """Disconnects all connections.""" @@ -473,7 +475,7 @@ class ServerConnection(Connection): self.irclibobj.execute_delayed(60, self._ping) if self.connected == False: return - self.irclibobj.bot.error('=> Debug: sending IRC ping', debug=True) + self.irclibobj.bot.error(1, 'sending IRC ping', debug=True) self.ping(self.get_server_name()) @@ -513,7 +515,7 @@ class ServerConnection(Connection): if self.used_by > 0: self.used_by += 1 - self.irclibobj.bot.error('===> Debug: using existing IRC connection for '+self.__str__()+', this connection is now used by '+str(self.used_by)+' bridges', debug=True) + self.irclibobj.bot.error(3, 'using existing IRC connection for '+self.__str__()+', this connection is now used by '+str(self.used_by)+' bridges', debug=True) if self.really_connected: self._call_nick_callbacks(None) self.lock.release() @@ -550,9 +552,9 @@ class ServerConnection(Connection): self.lock.acquire() if self.socket != 'closed': - self.irclibobj.bot.error('===> Debug: opening new IRC connection for '+self.__str__(), debug=True) + self.irclibobj.bot.error(3, 'opening new IRC connection for '+self.__str__(), debug=True) else: - self.irclibobj.bot.error('===> Debug: reopening IRC connection for '+self.__str__(), debug=True) + self.irclibobj.bot.error(3, 'reopening IRC connection for '+self.__str__(), debug=True) if self.ipv6: self.socket = socket.socket(socket.AF_INET6, socket.SOCK_STREAM) @@ -588,9 +590,9 @@ class ServerConnection(Connection): f(error, arguments=arguments) self.nick_callbacks = [] if i == 0: - self.irclibobj.bot.error('=> Debug: no nick callback for "'+self.__str__()+'"', debug=True) + self.irclibobj.bot.error(1, 'no nick callback for "'+self.__str__()+'"', debug=True) else: - self.irclibobj.bot.error('=> Debug: called '+str(i)+' callback(s) for "'+self.__str__()+'"', debug=True) + self.irclibobj.bot.error(1, 'called '+str(i)+' callback(s) for "'+self.__str__()+'"', debug=True) def add_nick_callback(self, callback):
--- a/participant.py +++ b/participant.py @@ -23,6 +23,8 @@ import muc xmpp = muc.xmpp del muc +import say_levels + class Participant: def __init__(self, owner_bridge, protocol, nickname, real_jid=None): @@ -64,11 +66,11 @@ class Participant: def _xmpp_join_callback(self, errors): if len(errors) == 0: - m = '===> Debug: "'+self.nickname+'" duplicate succesfully created on XMPP side of bridge "'+str(self.bridge)+'"' + m = '"'+self.nickname+'" duplicate succesfully created on XMPP side of bridge "'+str(self.bridge)+'"' if self.nickname != self.duplicate_nickname: m += ' using nickname "'+self.duplicate_nickname+'"' - self.bridge.say('[Info] "'+self.nickname+'" will appear as "'+self.duplicate_nickname+'" on XMPP because its real nickname is reserved or contains unauthorized characters') - self.bridge.bot.error(m, debug=True) + self.bridge.say(say_levels.info, '"'+self.nickname+'" will appear as "'+self.duplicate_nickname+'" on XMPP because its real nickname is reserved or contains unauthorized characters') + self.bridge.bot.error(3, m, debug=True) elif self.xmpp_c != 'both': for error in errors: try: @@ -80,9 +82,9 @@ class Participant: if self.bridge.mode == 'bypass': new_duplicate_nickname = self._get_new_duplicate_nickname() if new_duplicate_nickname != None: - self.bridge.bot.error('===> Debug: "'+self.duplicate_nickname+'" is already used in the XMPP MUC or reserved on the XMPP server of bridge "'+str(self.bridge)+'", trying "'+new_duplicate_nickname+'"', debug=True) + self.bridge.bot.error(3, '"'+self.duplicate_nickname+'" is already used in the XMPP MUC or reserved on the XMPP server of bridge "'+str(self.bridge)+'", trying "'+new_duplicate_nickname+'"', debug=True) if self.duplicate_nickname == self.nickname: - self.bridge.say('[Info] The nickname "'+self.duplicate_nickname+'" is used on both rooms or reserved on the XMPP server') + self.bridge.say(say_levels.info, 'The nickname "'+self.duplicate_nickname+'" is used on both rooms or reserved on the XMPP server') self.duplicate_nickname = new_duplicate_nickname if isinstance(self.xmpp_c, xmpp.client.Client): self.bridge.bot.close_xmpp_connection(self.nickname) @@ -91,11 +93,11 @@ class Participant: return else: - self.bridge.say('[Warning] The nickname "'+self.nickname+'" is used on both rooms or reserved on the XMPP server', log=True) + self.bridge.say(say_levels.warning, 'The nickname "'+self.nickname+'" is used on both rooms or reserved on the XMPP server', log=True) if self.muc.connected == True: self.muc.leave('Changed nickname to "'+self.nickname+'"') except xmpp.muc.RoomIsFull: - self.bridge.say('[Warning] XMPP room is full', log=True) + self.bridge.say(say_levels.warning, 'XMPP room is full', log=True) except xmpp.muc.RemoteServerNotFound: self.bridge._RemoteServerNotFound_handler() @@ -114,11 +116,11 @@ class Participant: def _irc_nick_callback(self, error, arguments=[]): if error == None: self.irc_connection.join(self.bridge.irc_room) - m = '===> Debug: "'+self.nickname+'" duplicate succesfully created on IRC side of bridge "'+str(self.bridge)+'"' + m = '"'+self.nickname+'" duplicate succesfully created on IRC side of bridge "'+str(self.bridge)+'"' if self.nickname != self.duplicate_nickname: m += ' using nickname "'+self.duplicate_nickname+'"' - self.bridge.say('[Info] "'+self.nickname+'" will appear as "'+self.duplicate_nickname+'" on IRC because its real nickname is reserved or contains unauthorized characters') - self.bridge.bot.error(m, debug=True) + self.bridge.say(say_levels.info, '"'+self.nickname+'" will appear as "'+self.duplicate_nickname+'" on IRC because its real nickname is reserved or contains unauthorized characters') + self.bridge.bot.error(3, m, debug=True) elif self.irc_connection != 'both': @@ -129,9 +131,9 @@ class Participant: if self.bridge.mode == 'bypass': new_duplicate_nickname = self._get_new_duplicate_nickname() if new_duplicate_nickname != None: - self.bridge.bot.error('===> Debug: "'+self.duplicate_nickname+'" is already used or reserved on the IRC server of bridge "'+str(self.bridge)+'", trying "'+new_duplicate_nickname+'"', debug=True) + self.bridge.bot.error(3, '"'+self.duplicate_nickname+'" is already used or reserved on the IRC server of bridge "'+str(self.bridge)+'", trying "'+new_duplicate_nickname+'"', debug=True) if self.duplicate_nickname == self.nickname: - self.bridge.say('[Info] The nickname "'+self.duplicate_nickname+'" is used or reserved on the IRC server') + self.bridge.say(say_levels.info, 'The nickname "'+self.duplicate_nickname+'" is used or reserved on the IRC server') self.duplicate_nickname = new_duplicate_nickname if isinstance(self.irc_connection, ServerConnection): self.irc_connection.close('') @@ -140,7 +142,7 @@ class Participant: return else: - self.bridge.say('[Warning] The nickname "'+self.nickname+'" is used or reserved on the IRC server', log=True) + self.bridge.say(say_levels.warning, 'The nickname "'+self.nickname+'" is used or reserved on the IRC server', log=True) elif error == 'erroneusnickname': if self.bridge.mode == 'bypass': @@ -151,13 +153,13 @@ class Participant: self.createDuplicateOnIRC() return else: - self.bridge.say('[Warning] The nickname "'+self.nickname+'" contains unauthorized characters and cannot be used in the IRC channel', log=True) + self.bridge.say(say_levels.warning, 'The nickname "'+self.nickname+'" contains unauthorized characters and cannot be used in the IRC channel', log=True) elif error == 'nicknametoolong': - self.bridge.say('[Warning] The nickname "'+self.nickname+'" is too long (limit seems to be '+str(arguments[0])+') and cannot be used in the IRC channel', log=True) + self.bridge.say(say_levels.warning, 'The nickname "'+self.nickname+'" is too long (limit seems to be '+str(arguments[0])+') and cannot be used in the IRC channel', log=True) else: - self.bridge.say('[Warning] unknown error while adding "'+self.nickname+'" to IRC side of bridge', log=True) + self.bridge.say(say_levels.warning, 'unknown error while adding "'+self.nickname+'" to IRC side of bridge', log=True) if isinstance(self.irc_connection, ServerConnection): self.irc_connection.close('') @@ -165,7 +167,7 @@ class Participant: def set_both_sides(self): - self.bridge.say('[Warning] The nickname "'+self.nickname+'" is used on both sides of the bridge', log=True) + self.bridge.say(say_levels.warning, 'The nickname "'+self.nickname+'" is used on both sides of the bridge', log=True) if isinstance(self.irc_connection, ServerConnection): self.irc_connection.close('') if self.irc_connection != 'both': @@ -296,7 +298,7 @@ class Participant: else: self.bridge.irc_connection.privmsg(self.bridge.irc_room, '<'+self.nickname+'> '+message) except EncodingException: - self.bridge.say('[Warning] "'+self.nickname+'" is sending messages using an unknown encoding', log=True) + self.bridge.say(say_levels.warning, '"'+self.nickname+'" is sending messages using an unknown encoding', log=True) def sayOnIRCTo(self, to, message): @@ -304,7 +306,7 @@ class Participant: try: self.irc_connection.privmsg(to, message) except EncodingException: - self.bridge.say('[Warning] "'+self.nickname+'" is sending messages using an unknown encoding', log=True) + self.bridge.say(say_levels.warning, '"'+self.nickname+'" is sending messages using an unknown encoding', log=True) elif not isinstance(self.xmpp_c, xmpp.client.Client): if self.bridge.mode != 'normal': self.bridge.getParticipant(to).sayOnXMPPTo(self.nickname, 'Sorry but cross-protocol private messages are disabled in '+self.bridge.mode+' mode.') @@ -322,7 +324,7 @@ class Participant: else: self.bridge.xmpp_room.say('<'+self.nickname+'> '+message) except EncodingException: - self.bridge.say('[Warning] "'+self.nickname+'" is sending messages using an unknown encoding', log=True) + self.bridge.say(say_levels.warning, '"'+self.nickname+'" is sending messages using an unknown encoding', log=True) def sayOnXMPPTo(self, to, message): @@ -335,7 +337,7 @@ class Participant: else: self.bridge.getParticipant(to).sayOnXMPPTo(self.nickname, 'Sorry but you cannot send cross-protocol private messages because I don\'t have an XMPP duplicate with your nickname.') except EncodingException: - self.bridge.say('[Warning] "'+self.nickname+'" is sending messages using an unknown encoding', log=True) + self.bridge.say(say_levels.warning, '"'+self.nickname+'" is sending messages using an unknown encoding', log=True) def leave(self, message):
new file mode 100644 --- /dev/null +++ b/say_levels.py @@ -0,0 +1,37 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + + +from weighted_string import Weighted_string + +debug = Weighted_string(0, 'debug') +info = Weighted_string(1, 'info') +notice = Weighted_string(2, 'notice') +warning = Weighted_string(3, 'warning') +error = Weighted_string(4, 'error') +nothing = Weighted_string(5, 'nothing') +levels = ['debug', 'info', 'notice', 'warning', 'error', 'nothing'] + +def get(level): + if isinstance(level, int): + return globals()[levels[level]] + elif isinstance(level, basestring): + try: + return globals()[str(level)] + except KeyError: + raise ValueError, 'say_level must be one of these values: '+', '.join(levels) + else: + raise TypeError, 'say_level must be either an int or a string'
--- a/start_bots_from_xml_config.py +++ b/start_bots_from_xml_config.py @@ -22,7 +22,9 @@ from time import sleep import sys import traceback +from admin import Admin from bot import Bot +import say_levels try: @@ -49,11 +51,19 @@ for bot_el in config.getElementsByTagNam if bot_el.hasAttribute('debug'): if bot_el.getAttribute('debug') == 'true': debug = True - admins_jid = [] + + admins = [] for admin_el in bot_el.getElementsByTagName('admin'): if admin_el.hasAttribute('jid'): - admins_jid.append(admin_el.getAttribute('jid')) - bot = Bot(bot_el.getAttribute('jid'), bot_el.getAttribute('password'), bot_el.getAttribute('nickname'), admins_jid=admins_jid, debug=debug) + admin = Admin() + admin.jid = admin_el.getAttribute('jid') + if admin_el.hasAttribute('say_level'): + admin.say_level = say_levels.get(admin_el.getAttribute('say_level')) + else: + admin.say_level = say_levels.warning + admins.append(admin) + + bot = Bot(bot_el.getAttribute('jid'), bot_el.getAttribute('password'), bot_el.getAttribute('nickname'), admins=admins, debug=debug) bots.append(bot) for bridge_el in bot_el.getElementsByTagName('bridge'): xmpp_room = bridge_el.getElementsByTagName('xmpp-room')[0] @@ -71,14 +81,14 @@ for bot_el in config.getElementsByTagNam irc_charsets = None if bridge_el.hasAttribute('say_level'): - say_level = bridge_el.getAttribute('say_level') + say_level = say_levels.get(bridge_el.getAttribute('say_level')) else: - say_level = 'all' + say_level = say_levels.nothing if bridge_el.hasAttribute('mode'): mode = bridge_el.getAttribute('mode') else: - mode = 'normal' + mode = 'bypass' bot.new_bridge(xmpp_room.getAttribute('jid'), irc.getAttribute('chan'), irc.getAttribute('server'), mode, say_level, irc_connection_interval=irc_connection_interval, irc_charsets=irc_charsets)
new file mode 100644 --- /dev/null +++ b/weighted_string.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + + +class Weighted_string(unicode): + + def __new__(cls, weight, string): + return super(Weighted_string, cls).__new__(cls, unicode(string)) + + def __init__(self, weight, string): + self.weight = weight + + def __lt__(self, other): + return self.weight < other + + def __le__(self, other): + return self.weight <= other + + def __eq__(self, other): + return self.weight == other + + def __ne__(self, other): + return self.weight != other + + def __gt__(self, other): + return self.weight > other + + def __ge__(self, other): + return self.weight >= other + + def __repr__(self): + return '<'+unicode(self.weight)+', '+unicode.__repr__(self)+'>'