2016-04-07 09:03:22 -04:00
|
|
|
#!/usr/bin/env python
|
2013-10-09 14:03:47 -04:00
|
|
|
#
|
|
|
|
# EXPERIMENTAL
|
|
|
|
# IRC <=> Zulip mirroring bot
|
|
|
|
#
|
|
|
|
# Setup: First, you need to install python-irc version 8.5.3
|
2016-10-10 17:15:23 -04:00
|
|
|
# (https://github.com/jaraco/irc)
|
2013-10-09 14:03:47 -04:00
|
|
|
|
2015-11-01 11:11:06 -05:00
|
|
|
from __future__ import print_function
|
2013-10-09 14:03:47 -04:00
|
|
|
import irc.bot
|
|
|
|
import irc.strings
|
2016-09-10 15:19:08 -04:00
|
|
|
from irc.client import ip_numstr_to_quad, ip_quad_to_numstr, Event, ServerConnection
|
2013-10-09 14:03:47 -04:00
|
|
|
import zulip
|
2017-08-01 17:38:33 -04:00
|
|
|
import argparse
|
2013-10-09 14:03:47 -04:00
|
|
|
|
2016-11-30 15:45:02 -05:00
|
|
|
if False:
|
2017-03-03 13:01:52 -05:00
|
|
|
from typing import Any, Dict
|
2016-09-10 15:19:08 -04:00
|
|
|
|
2015-09-19 21:12:02 -04:00
|
|
|
IRC_DOMAIN = "irc.example.com"
|
|
|
|
|
2013-10-09 14:03:47 -04:00
|
|
|
def zulip_sender(sender_string):
|
2016-09-10 15:19:08 -04:00
|
|
|
# type: (str) -> str
|
2013-10-09 14:03:47 -04:00
|
|
|
nick = sender_string.split("!")[0]
|
2015-09-19 21:12:02 -04:00
|
|
|
return nick + "@" + IRC_DOMAIN
|
2013-10-09 14:03:47 -04:00
|
|
|
|
|
|
|
class IRCBot(irc.bot.SingleServerIRCBot):
|
2017-09-04 07:51:55 -04:00
|
|
|
def __init__(self, zulip_client, channel, nickname, server, port=6667):
|
|
|
|
# type: (Any, irc.bot.Channel, str, str, int) -> None
|
2013-10-09 14:03:47 -04:00
|
|
|
irc.bot.SingleServerIRCBot.__init__(self, [(server, port)], nickname, nickname)
|
2017-05-07 10:43:37 -04:00
|
|
|
self.channel = channel # type: irc.bot.Channel
|
2017-09-04 07:51:55 -04:00
|
|
|
self.zulip_client = zulip_client
|
2013-10-09 14:03:47 -04:00
|
|
|
|
|
|
|
def on_nicknameinuse(self, c, e):
|
2016-09-10 15:19:08 -04:00
|
|
|
# type: (ServerConnection, Event) -> None
|
2013-10-09 14:03:47 -04:00
|
|
|
c.nick(c.get_nickname().replace("_zulip", "__zulip"))
|
|
|
|
|
|
|
|
def on_welcome(self, c, e):
|
2016-09-10 15:19:08 -04:00
|
|
|
# type: (ServerConnection, Event) -> None
|
2013-10-09 14:03:47 -04:00
|
|
|
c.join(self.channel)
|
2016-11-29 01:22:02 -05:00
|
|
|
|
2013-10-09 14:03:47 -04:00
|
|
|
def forward_to_irc(msg):
|
2016-09-10 15:19:08 -04:00
|
|
|
# type: (Dict[str, Any]) -> None
|
2013-10-09 14:03:47 -04:00
|
|
|
if msg["type"] == "stream":
|
|
|
|
send = lambda x: c.privmsg(msg["display_recipient"], x)
|
|
|
|
else:
|
|
|
|
recipients = [u["short_name"] for u in msg["display_recipient"] if
|
|
|
|
u["email"] != msg["sender_email"]]
|
|
|
|
if len(recipients) == 1:
|
|
|
|
send = lambda x: c.privmsg(recipients[0], x)
|
|
|
|
else:
|
|
|
|
send = lambda x: c.privmsg_many(recipients, x)
|
|
|
|
for line in msg["content"].split("\n"):
|
|
|
|
send(line)
|
|
|
|
|
|
|
|
## Forwarding from Zulip => IRC is disabled; uncomment the next
|
|
|
|
## line to make this bot forward in that direction instead.
|
|
|
|
#
|
2017-09-04 07:51:55 -04:00
|
|
|
# self.zulip_client.call_on_each_message(forward_to_irc)
|
2013-10-09 14:03:47 -04:00
|
|
|
|
|
|
|
def on_privmsg(self, c, e):
|
2016-09-10 15:19:08 -04:00
|
|
|
# type: (ServerConnection, Event) -> None
|
2013-10-09 14:03:47 -04:00
|
|
|
content = e.arguments[0]
|
|
|
|
sender = zulip_sender(e.source)
|
2015-09-19 21:12:02 -04:00
|
|
|
if sender.endswith("_zulip@" + IRC_DOMAIN):
|
2013-10-09 14:03:47 -04:00
|
|
|
return
|
|
|
|
|
|
|
|
# Forward the PM to Zulip
|
2017-09-04 07:51:55 -04:00
|
|
|
print(self.zulip_client.send_message({
|
2017-01-24 01:06:13 -05:00
|
|
|
"sender": sender,
|
|
|
|
"type": "private",
|
|
|
|
"to": "username@example.com",
|
|
|
|
"content": content,
|
2017-01-24 00:34:26 -05:00
|
|
|
}))
|
2013-10-09 14:03:47 -04:00
|
|
|
|
|
|
|
def on_pubmsg(self, c, e):
|
2016-09-10 15:19:08 -04:00
|
|
|
# type: (ServerConnection, Event) -> None
|
2013-10-09 14:03:47 -04:00
|
|
|
content = e.arguments[0]
|
|
|
|
stream = e.target
|
|
|
|
sender = zulip_sender(e.source)
|
2015-09-19 21:12:02 -04:00
|
|
|
if sender.endswith("_zulip@" + IRC_DOMAIN):
|
2013-10-09 14:03:47 -04:00
|
|
|
return
|
|
|
|
|
|
|
|
# Forward the stream message to Zulip
|
2017-09-04 07:51:55 -04:00
|
|
|
print(self.zulip_client.send_message({
|
2017-01-24 01:06:13 -05:00
|
|
|
"forged": "yes",
|
|
|
|
"sender": sender,
|
|
|
|
"type": "stream",
|
|
|
|
"to": stream,
|
|
|
|
"subject": "IRC",
|
|
|
|
"content": content,
|
2017-01-24 00:34:26 -05:00
|
|
|
}))
|
2013-10-09 14:03:47 -04:00
|
|
|
|
|
|
|
def on_dccmsg(self, c, e):
|
2016-09-10 15:19:08 -04:00
|
|
|
# type: (ServerConnection, Event) -> None
|
2013-10-09 14:03:47 -04:00
|
|
|
c.privmsg("You said: " + e.arguments[0])
|
|
|
|
|
|
|
|
def on_dccchat(self, c, e):
|
2016-09-10 15:19:08 -04:00
|
|
|
# type: (ServerConnection, Event) -> None
|
2013-10-09 14:03:47 -04:00
|
|
|
if len(e.arguments) != 2:
|
|
|
|
return
|
|
|
|
args = e.arguments[1].split()
|
|
|
|
if len(args) == 4:
|
|
|
|
try:
|
|
|
|
address = ip_numstr_to_quad(args[2])
|
|
|
|
port = int(args[3])
|
|
|
|
except ValueError:
|
|
|
|
return
|
|
|
|
self.dcc_connect(address, port)
|
|
|
|
|
2017-08-25 05:03:06 -04:00
|
|
|
usage = """./irc-mirror.py --irc-server=IRC_SERVER --channel=<CHANNEL> --nick-prefix=<NICK> [optional args]
|
2013-10-09 14:03:47 -04:00
|
|
|
|
|
|
|
Example:
|
|
|
|
|
2016-11-21 19:44:16 -05:00
|
|
|
./irc-mirror.py --irc-server=127.0.0.1 --channel='#test' --nick-prefix=username
|
2017-08-25 05:03:06 -04:00
|
|
|
|
|
|
|
Specify your Zulip API credentials and server in a ~/.zuliprc file or using the options.
|
2013-10-09 14:03:47 -04:00
|
|
|
|
|
|
|
Note that "_zulip" will be automatically appended to the IRC nick provided
|
|
|
|
|
|
|
|
Also note that at present you need to edit this code to do the Zulip => IRC side
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
2017-08-01 17:38:33 -04:00
|
|
|
parser = zulip.add_default_arguments(argparse.ArgumentParser(usage=usage))
|
|
|
|
parser.add_argument('--irc-server', default=None)
|
|
|
|
parser.add_argument('--port', default=6667)
|
|
|
|
parser.add_argument('--nick-prefix', default=None)
|
|
|
|
parser.add_argument('--channel', default=None)
|
|
|
|
|
|
|
|
options = parser.parse_args()
|
2013-10-09 14:03:47 -04:00
|
|
|
|
|
|
|
if options.irc_server is None or options.nick_prefix is None or options.channel is None:
|
|
|
|
parser.error("Missing required argument")
|
|
|
|
|
|
|
|
# Setting the client to irc_mirror is critical for this to work
|
|
|
|
options.client = "irc_mirror"
|
|
|
|
zulip_client = zulip.init_from_options(options)
|
|
|
|
|
|
|
|
nickname = options.nick_prefix + "_zulip"
|
2017-09-04 07:51:55 -04:00
|
|
|
bot = IRCBot(zulip_client, options.channel, nickname, options.irc_server, options.port)
|
2013-10-09 14:03:47 -04:00
|
|
|
bot.start()
|