mirror of
				https://github.com/zulip/zulip.git
				synced 2025-11-03 21:43:21 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			141 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			141 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
#!/usr/bin/env python
 | 
						|
#
 | 
						|
# EXPERIMENTAL
 | 
						|
# IRC <=> Zulip mirroring bot
 | 
						|
#
 | 
						|
# Setup: First, you need to install python-irc version 8.5.3
 | 
						|
# (https://bitbucket.org/jaraco/irc)
 | 
						|
 | 
						|
from __future__ import print_function
 | 
						|
import irc.bot
 | 
						|
import irc.strings
 | 
						|
from irc.client import ip_numstr_to_quad, ip_quad_to_numstr, Event, ServerConnection
 | 
						|
import zulip
 | 
						|
import optparse
 | 
						|
 | 
						|
if False: from typing import Any
 | 
						|
 | 
						|
IRC_DOMAIN = "irc.example.com"
 | 
						|
 | 
						|
def zulip_sender(sender_string):
 | 
						|
    # type: (str) -> str
 | 
						|
    nick = sender_string.split("!")[0]
 | 
						|
    return nick + "@" + IRC_DOMAIN
 | 
						|
 | 
						|
class IRCBot(irc.bot.SingleServerIRCBot):
 | 
						|
    def __init__(self, channel, nickname, server, port=6667):
 | 
						|
        # type: (irc.bot.Channel, str, str, int) -> None
 | 
						|
        irc.bot.SingleServerIRCBot.__init__(self, [(server, port)], nickname, nickname)
 | 
						|
        self.channel = channel # type: irc.bot.Channel
 | 
						|
 | 
						|
    def on_nicknameinuse(self, c, e):
 | 
						|
        # type: (ServerConnection, Event) -> None
 | 
						|
        c.nick(c.get_nickname().replace("_zulip", "__zulip"))
 | 
						|
 | 
						|
    def on_welcome(self, c, e):
 | 
						|
        # type: (ServerConnection, Event) -> None
 | 
						|
        c.join(self.channel)
 | 
						|
        def forward_to_irc(msg):
 | 
						|
            # type: (Dict[str, Any]) -> None
 | 
						|
            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.
 | 
						|
        #
 | 
						|
        # zulip_client.call_on_each_message(forward_to_irc)
 | 
						|
 | 
						|
    def on_privmsg(self, c, e):
 | 
						|
        # type: (ServerConnection, Event) -> None
 | 
						|
        content = e.arguments[0]
 | 
						|
        sender = zulip_sender(e.source)
 | 
						|
        if sender.endswith("_zulip@" + IRC_DOMAIN):
 | 
						|
            return
 | 
						|
 | 
						|
        # Forward the PM to Zulip
 | 
						|
        print(zulip_client.send_message({
 | 
						|
                "sender": sender,
 | 
						|
                "type": "private",
 | 
						|
                "to": "username@example.com",
 | 
						|
                "content": content,
 | 
						|
                }))
 | 
						|
 | 
						|
    def on_pubmsg(self, c, e):
 | 
						|
        # type: (ServerConnection, Event) -> None
 | 
						|
        content = e.arguments[0]
 | 
						|
        stream = e.target
 | 
						|
        sender = zulip_sender(e.source)
 | 
						|
        if sender.endswith("_zulip@" + IRC_DOMAIN):
 | 
						|
            return
 | 
						|
 | 
						|
        # Forward the stream message to Zulip
 | 
						|
        print(zulip_client.send_message({
 | 
						|
                "forged": "yes",
 | 
						|
                "sender": sender,
 | 
						|
                "type": "stream",
 | 
						|
                "to": stream,
 | 
						|
                "subject": "IRC",
 | 
						|
                "content": content,
 | 
						|
                }))
 | 
						|
 | 
						|
    def on_dccmsg(self, c, e):
 | 
						|
        # type: (ServerConnection, Event) -> None
 | 
						|
        c.privmsg("You said: " + e.arguments[0])
 | 
						|
 | 
						|
    def on_dccchat(self, c, e):
 | 
						|
        # type: (ServerConnection, Event) -> None
 | 
						|
        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)
 | 
						|
 | 
						|
usage = """python irc-mirror.py --server=IRC_SERVER --channel=<CHANNEL> --nick-prefix=<NICK> [optional args]
 | 
						|
 | 
						|
Example:
 | 
						|
 | 
						|
python irc-mirror.py --irc-server=127.0.0.1 --channel='#test' --nick-prefix=username
 | 
						|
  --site=https://zulip.example.com --user=irc-bot@example.com
 | 
						|
  --api-key=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
 | 
						|
 | 
						|
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__":
 | 
						|
    parser = optparse.OptionParser(usage=usage)
 | 
						|
    parser.add_option('--irc-server', default=None)
 | 
						|
    parser.add_option('--port', default=6667)
 | 
						|
    parser.add_option('--nick-prefix', default=None)
 | 
						|
    parser.add_option('--channel', default=None)
 | 
						|
    parser.add_option_group(zulip.generate_option_group(parser))
 | 
						|
    (options, args) = parser.parse_args()
 | 
						|
 | 
						|
    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"
 | 
						|
    bot = IRCBot(options.channel, nickname, options.irc_server, options.port)
 | 
						|
    bot.start()
 |