#!/usr/bin/env python # -*- coding: utf-8 -*- import sys import time import signal import re import sleekxmpp from irc.bot import SingleServerIRCBot from threading import Thread if sys.version_info.major >= 3: from configparser import SafeConfigParser else: from ConfigParser import SafeConfigParser class IRCBot: def __init__(self, opts, inter): self.client = SingleServerIRCBot([(opts['server'], opts['port'])], opts['nick'], opts['nick']) self.conn = self.client.connection self.opts = opts self.nick = opts['nick'] self.pure_nick = self.nick self.chan = opts['chan'] self.inter = inter def register_handlers(self): self.conn.add_global_handler('welcome', self.on_session_start) self.conn.add_global_handler('pubmsg', self.on_message) self.conn.add_global_handler('action', self.on_message) self.conn.add_global_handler('join', self.on_presence) self.conn.add_global_handler('part', self.on_presence) self.conn.add_global_handler('namreply', self.on_namreply) self.conn.add_global_handler('kick', self.on_kick) self.conn.add_global_handler('nicknameinuse', self.on_nicknameinuse) def join_chan(self): self.conn.part(self.chan, message='Replaced by new connection') self.conn.join(self.chan) def on_session_start(self, conn, event): print('Connected to IRC') self.join_chan() def on_message(self, conn, event): nick = event.source.split('!')[0] body = ''.join(event.arguments) typ = event.type if typ == 'action': body = '/me ' + body self.inter.relay_message('irc', nick, body) def on_presence(self, conn, event): try: typ = event.type nick = event.source.nick if typ == 'part': if nick != self.nick: if nick in self.inter.get_irc_users(): self.inter.remove_irc_user(nick) else: if nick != self.nick: if nick not in self.inter.get_irc_users(): self.inter.append_irc_user(nick) except Exception as e: sys.stderr.write(str(e) + '\n') def on_namreply(self, conn, event): for nick in event.arguments[2].split(): if nick != conn.get_nickname(): self.inter.append_irc_user(nick) def on_kick(self, conn, event): self.nick = self.pure_nick conn.nick(self.nick) time.sleep(0.5) self.join_chan() def on_nicknameinuse(self, conn, event): self.nick = self.nick + '_' conn.nick(self.nick) def send_message(self, msg): buffer = 460 try: for i in range(0, len(msg), buffer): self.conn.privmsg(self.chan, msg[i:i + buffer]) except Exception as e: sys.stderr.write(str(e) + '\n') def start(self): self.register_handlers() self.client.start() class XMPPBot: def __init__(self, opts, inter): if sys.version_info.major < 3: sleekxmpp.util.misc_ops.setdefaultencoding('utf-8') self.client = sleekxmpp.ClientXMPP(opts['jid'], opts['passwd']) self.opts = opts self.nick = opts['nick'] self.pure_nick = self.nick self.muc = opts['muc'] self.inter = inter def register_handlers(self): self.client.add_event_handler('session_start', self.on_session_start) self.client.add_event_handler('groupchat_message', self.on_message) self.client.add_event_handler('muc::%s::presence' % self.muc, self.on_presence) def join_muc(self): muc_plugin = self.client.plugin['xep_0045'] if self.muc in muc_plugin.getJoinedRooms(): muc_plugin.leaveMUC(self.muc, self.nick, msg='Replaced by new connection') muc_plugin.joinMUC(self.muc, self.nick, wait=True) def on_session_start(self, event): print('Connected to XMPP') self.client.get_roster() self.client.send_presence() self.join_muc() def on_message(self, event): body = event['body'] nick = event['mucnick'] self.inter.relay_message('xmpp', nick, body) def on_presence(self, event): try: muc_plugin = self.client.plugin['xep_0045'] typ = event['muc']['type'] nick = event['muc']['nick'] if not typ: typ = event['type'] if not nick: nick = muc_plugin.getNick(self.muc, event['from']) if typ == 'error': if event['error']['code'] == '409': self.nick = self.nick + '_' self.join_muc() elif typ == 'unavailable': if nick != self.nick: if nick in self.inter.get_xmpp_users(): self.inter.remove_xmpp_user(nick) else: self.nick = self.pure_nick time.sleep(0.5) self.join_muc() else: if nick != self.nick: if nick not in self.inter.get_xmpp_users(): self.inter.append_xmpp_user(nick) except Exception as e: sys.stderr.write(str(e) + '\n') def send_message(self, msg): try: self.client.send_message(mto=self.muc, mbody=msg, mtype='groupchat') except Exception as e: sys.stderr.write(str(e) + '\n') def start(self): self.client.register_plugin('xep_0045') # XMPP MUC. self.client.register_plugin('xep_0199') # XMPP Ping. if self.client.connect(): # sys.stderr.write('connected with %s\n'%con) self.register_handlers() self.client.process(block=True) else: # sys.stderr.write('could not connect!\n') sys.stderr.write('Could not connect to server, or password ' + 'mismatch!\n') sys.exit(1) class Intermedia: def __init__(self, shared_opts, irc_chan, xmpp_muc): self.irc_chan = irc_chan self.xmpp_muc = xmpp_muc self.ircbot = None self.xmppbot = None self.irc_users = [] self.xmpp_users = [] self.prefix = shared_opts['prefix'] self.owner = shared_opts['owner'] def set_bots(self, ircbot, xmppbot): self.ircbot = ircbot self.xmppbot = xmppbot def to_irc(self, msg): if self.ircbot: self.ircbot.send_message(msg) def to_xmpp(self, msg): if self.xmppbot: self.xmppbot.send_message(msg) def relay_message(self, from_net, nick, body): if not self.ircbot or not self.xmppbot: return if from_net != 'irc' and from_net != 'xmpp': return if from_net == 'irc' and nick == self.ircbot.nick or \ from_net == 'xmpp' and nick == self.xmppbot.nick: return if not body or len(body) <= 0: return try: msg = body.replace('\r\n', '\n').replace('\r', '\n').split('\n') if msg and len(msg) > 0: if len(msg) == 1 and msg[0] == self.prefix + 'users': irc_users = ', '.join(self.get_irc_users()) xmpp_users = ', '.join(self.get_xmpp_users()) if irc_users: irc_users = '[ IRC Users ] ' + irc_users if xmpp_users: xmpp_users = '[ XMPP Users ] ' + xmpp_users if from_net == 'irc': for answer in [xmpp_users]: self.to_irc(answer) elif from_net == 'xmpp': for answer in [irc_users]: self.to_xmpp(answer) elif len(msg) == 1 and msg[0] == self.prefix + 'help': answer = 'The only command I have is \'' + self.prefix + \ 'users\'. Also, my owner is ' + self.owner + '.' if from_net == 'irc': self.to_irc(answer) elif from_net == 'xmpp': self.to_xmpp(answer) else: nick_prefix = '[' + nick + '] ' nick_prefix_me = '***' + nick + ' ' if (not re.match('^/me .+$', msg[0])): msg[0] = nick_prefix + msg[0] else: msg[0] = nick_prefix_me + re.split('^/me ', msg[0])[1] if from_net == 'irc': self.to_xmpp('\n'.join(msg)) elif from_net == 'xmpp': self.to_irc(msg[0]) # Separately as with a standard prefix, always. for m in msg[1:]: time.sleep(0.5) self.to_irc(nick_prefix + m) except Exception as e: sys.stderr.write(str(e) + '\n') def get_irc_users(self): return self.irc_users def append_irc_user(self, user): self.irc_users.append(user) def remove_irc_user(self, user): self.irc_users.remove(user) def get_xmpp_users(self): return self.xmpp_users def append_xmpp_user(self, user): self.xmpp_users.append(user) def remove_xmpp_user(self, user): self.xmpp_users.remove(user) if __name__ == '__main__': config = SafeConfigParser() shared_opts = {} xmpp_opts = {} irc_opts = {} if len(sys.argv) > 1: config.read(sys.argv[1]) else: config.read('config.ini') if not config.sections(): sys.stderr.write('Error: Configuration file does not exist or is empty.\n') sys.exit(1) shared_opts['prefix'] = config.get('Shared', 'prefix') shared_opts['owner'] = config.get('Shared', 'owner') irc_opts['chan'] = config.get('IRC', 'channel') irc_opts['nick'] = config.get('IRC', 'nick') irc_opts['server'] = config.get('IRC', 'server') irc_opts['port'] = int(config.get('IRC', 'port')) xmpp_opts['jid'] = config.get('XMPP', 'jid') xmpp_opts['passwd'] = config.get('XMPP', 'password') xmpp_opts['muc'] = config.get('XMPP', 'muc') xmpp_opts['nick'] = config.get('XMPP', 'nick') signal.signal(signal.SIGINT, signal.SIG_DFL) while True: inter = Intermedia(shared_opts, irc_opts['chan'], xmpp_opts['muc']) ircbot = IRCBot(irc_opts, inter) xmppbot = XMPPBot(xmpp_opts, inter) inter.set_bots(ircbot, xmppbot) irc_thread = Thread(target=ircbot.start, args=()) xmpp_thread = Thread(target=xmppbot.start, args=()) irc_thread.daemon = True xmpp_thread.daemon = True irc_thread.start() time.sleep(1) xmpp_thread.start() irc_thread.join() xmpp_thread.join()