diff --git a/README.md b/README.md index efc62e9..b1a83f8 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ # hybridbot -Hybridbot is a bot that relays messages from a IRC channel to an XMPP MUC and vice versa. First of all, you need to install sleekxmpp and irc. +Hybridbot is a bot that relays messages from a IRC channel to an XMPP MUC and vice versa. First of all, you need to install slixmpp and irc. - su -c "pip install sleekxmpp irc" + su -c "pip3 install slixmpp irc" # or - su -c "pip install -r requirements.txt" + su -c "pip3 install -r requirements.txt" It's configuration is simple, you have to create a config file per relay, as this example (remember to change the values): @@ -32,10 +32,10 @@ The option "owner" is a string that will be printed when issuing the ".help" com To execute it, just do: - python hybridbot.py myconfig.ini + python3 hybridbot.py myconfig.ini Or if the config file is named "config.ini", just do: - python hybridbot.py + python3 hybridbot.py And on the MUC or the IRC channel, you can issue two commands, ".help" and ".users". diff --git a/hybridbot.py b/hybridbot.py index 3f016f6..d4f9ff2 100755 --- a/hybridbot.py +++ b/hybridbot.py @@ -1,23 +1,19 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- +#!/usr/bin/env python3 +import asyncio import re import signal import sys import time -import sleekxmpp -if sys.version_info.major >= 3: - from configparser import SafeConfigParser -else: - from ConfigParser import SafeConfigParser -from threading import Thread +import slixmpp +from configparser import SafeConfigParser from irc.bot import SingleServerIRCBot class IRCBot: def __init__(self, opts, inter): self.client = SingleServerIRCBot([(opts['server'], opts['port'])], - opts['nick'], opts['nick']) + opts['nick'], opts['nick']) self.conn = self.client.connection self.opts = opts self.nick = opts['nick'] @@ -68,7 +64,7 @@ class IRCBot: 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') + print(str(e), file=sys.stderr) def on_namreply(self, conn, event): for nick in event.arguments[2].split(): @@ -101,19 +97,16 @@ class IRCBot: self.conn.privmsg(self.chan, prefix + r) except Exception as e: - sys.stderr.write(str(e) + '\n') + print(str(e), file=sys.stderr) - def start(self): + def run(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.client = slixmpp.ClientXMPP(opts['jid'], opts['passwd']) self.opts = opts self.nick = opts['nick'] self.pure_nick = self.nick @@ -121,6 +114,8 @@ class XMPPBot: self.inter = inter def register_handlers(self): + self.client.add_event_handler('failed_all_auth', + self.on_failed_all_auth) self.client.add_event_handler('session_start', self.on_session_start) self.client.add_event_handler('session_end', self.on_session_end) self.client.add_event_handler('groupchat_message', self.on_message) @@ -128,22 +123,24 @@ class XMPPBot: self.on_presence) def connect(self): - if not self.client.connect(): - # sys.stderr.write('could not connect!\n') - sys.stderr.write('Could not connect to server, or password ' + - 'mismatch!\n') - sys.exit(1) - # sys.stderr.write('connected with %s\n'%con) + self.client.connect() def join_muc(self): muc_plugin = self.client.plugin['xep_0045'] - muc_plugin.joinMUC(self.muc, self.nick) + muc_plugin.join_muc(self.muc, self.nick) + + def on_failed_all_auth(event): + # print('could not connect!', file=sys.stderr) + print('Could not connect to the server, or password mismatch!', + file=sys.stderr) + sys.exit(1) def on_session_start(self, event): + # print('connected with %s' %con, file=sys.stderr) print('Connected to XMPP') - self.client.get_roster() self.client.send_presence() + self.client.get_roster() self.join_muc() def on_session_end(self, event): @@ -165,7 +162,7 @@ class XMPPBot: if not typ: typ = event['type'] if not nick: - nick = muc_plugin.getNick(self.muc, event['from']) + nick = muc_plugin.get_nick(self.muc, event['from']) if typ == 'error': if event['error']['code'] == '409': @@ -187,7 +184,7 @@ class XMPPBot: self.inter.append_xmpp_user(nick) except Exception as e: - sys.stderr.write(str(e) + '\n') + print(str(e), file=sys.stderr) def send_message(self, msg, prefix=''): try: @@ -197,18 +194,19 @@ class XMPPBot: mtype='groupchat') except Exception as e: - sys.stderr.write(str(e) + '\n') + print(str(e), file=sys.stderr) - def start(self): + @asyncio.coroutine + def run(self): self.client.register_plugin('xep_0045') # XMPP MUC. self.client.register_plugin('xep_0199') # XMPP Ping. self.register_handlers() self.connect() - self.client.process(block=True) class Intermedia: - def __init__(self, shared_opts, irc_chan, xmpp_muc): + def __init__(self, loop, shared_opts, irc_chan, xmpp_muc): + self.loop = loop self.irc_chan = irc_chan self.xmpp_muc = xmpp_muc self.ircbot = None @@ -229,7 +227,7 @@ class Intermedia: def to_xmpp(self, msg, prefix=''): if self.xmppbot: - self.xmppbot.send_message(msg, prefix) + loop.call_soon_threadsafe(self.xmppbot.send_message, msg, prefix) def relay_message(self, from_net, nick, body): if not self.ircbot or not self.xmppbot: @@ -292,7 +290,7 @@ class Intermedia: prefix=nick_prefix) except Exception as e: - sys.stderr.write(str(e) + '\n') + print(str(e), file=sys.stderr) def get_irc_users(self): return self.irc_users @@ -324,7 +322,8 @@ if __name__ == '__main__': config.read('config.ini') if not config.sections(): - sys.stderr.write('Error: Configuration file does not exist or is empty.\n') + print('Error: Configuration file does not exist or is empty.', + file=sys.stderr) sys.exit(1) shared_opts['prefix'] = config.get('Shared', 'prefix') @@ -341,22 +340,14 @@ if __name__ == '__main__': xmpp_opts['nick'] = config.get('XMPP', 'nick') signal.signal(signal.SIGINT, signal.SIG_DFL) + loop = asyncio.get_event_loop() - 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) + inter = Intermedia(loop, 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() + asyncio.async(xmppbot.run()) + asyncio.async(loop.run_in_executor(None, ircbot.run)) + loop.run_forever() + loop.close() diff --git a/requirements.txt b/requirements.txt index ed24bda..a9542ae 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,2 @@ -sleekxmpp>=1.2.0 +slixmpp irc>=5.0.1