From 663d03ed2cc6c21d564345940804f9e386366212 Mon Sep 17 00:00:00 2001 From: James Lu Date: Wed, 31 Aug 2016 14:07:32 -0700 Subject: [PATCH] relay/clientbot: begin work on outgoing PMs to clientbot users (#318) This still needs to implement PMs going the other way around, and should eventually distinguish between PMs and private notices. --- example-conf.yml | 5 +++++ plugins/relay.py | 6 +++--- plugins/relay_clientbot.py | 27 ++++++++++++++++++++++----- protocols/clientbot.py | 4 ++-- 4 files changed, 32 insertions(+), 10 deletions(-) diff --git a/example-conf.yml b/example-conf.yml index a8cfc71..6f2b4f6 100644 --- a/example-conf.yml +++ b/example-conf.yml @@ -464,6 +464,11 @@ relay: forcetag_nicks: - "*Serv" + # This determines whether private messages / notices will be forwarded over Clientbot relay, + # and whether the 'rpm' command will be allowed from Clientbot networks. This defaults to + # False. + allow_clientbot_pms: false + games: # Sets the nick of the Games service, if you're using it. nick: Games diff --git a/plugins/relay.py b/plugins/relay.py index 7b093f1..2480277 100644 --- a/plugins/relay.py +++ b/plugins/relay.py @@ -1100,9 +1100,9 @@ def handle_messages(irc, numeric, command, args): return remoteirc = world.networkobjects[homenet] - if remoteirc.protoname == 'clientbot': - irc.msg(numeric, 'Error: Private messages to networks ' - 'linked via Clientbot are not yet supported.', notice=True) + if remoteirc.protoname == 'clientbot' and not conf.conf.get('relay', {}).get('allow_clientbot_pms'): + irc.msg(numeric, 'Error: Private messages to users connected via Clientbot have ' + 'been administratively disabled.', notice=True) return user = getRemoteUser(irc, remoteirc, numeric, spawnIfMissing=False) diff --git a/plugins/relay_clientbot.py b/plugins/relay_clientbot.py index 049c5f7..be64345 100644 --- a/plugins/relay_clientbot.py +++ b/plugins/relay_clientbot.py @@ -18,6 +18,7 @@ default_styles = {'MESSAGE': '\x02[$colored_netname]\x02 <$colored_sender> $text 'NOTICE': '\x02[$colored_netname]\x02 - Notice from $colored_sender: $text', 'SQUIT': '\x02[$colored_netname]\x02 - Netsplit lost users: $colored_nicks', 'SJOIN': '\x02[$colored_netname]\x02 - Netjoin gained users: $colored_nicks', + 'PM': 'PM from $sender on $netname: $text', } def color_text(s): @@ -33,11 +34,14 @@ def color_text(s): def cb_relay_core(irc, source, command, args): """ - This function takes Clientbot actions and outputs them to a channel as regular text. + This function takes Clientbot events and formats them as text to the target channel / user. """ real_command = command.split('_')[-1] relay = world.plugins.get('relay') + + force_notice = False + if irc.pseudoclient and relay: try: sourcename = irc.getFriendlyName(source) @@ -57,9 +61,17 @@ def cb_relay_core(irc, source, command, args): real_command = 'ACTION' + elif not utils.isChannel(args['target']): + # Target is PM, handle accordingly. + if relay_conf.get('allow_clientbot_pms'): + real_command = 'PM' + # Always deliver this as a notice to prevent PM loops with bots, etc. + force_notice = True + # Other CTCPs are ignored elif args['text'].startswith('\x01'): return + elif args.get('is_notice'): # Different syntax for notices real_command = 'NOTICE' elif (time.time() - irc.start_ts) < startup_delay: @@ -95,9 +107,10 @@ def cb_relay_core(irc, source, command, args): # Figure out where the message is destined to. target = args.get('channel') or args.get('target') - if target is None or not utils.isChannel(target): - # Quit and nick messages are not channel specific. Figure out all channels that the - # sender shares over the relay, and relay them that way. + if target is None or not (utils.isChannel(target) or real_command == 'PM'): + # Non-channel specific message (e.g. QUIT or NICK). If this isn't a PM, figure out + # all channels that the sender shares over the relay, and relay them to those + # channels. userdata = args.get('userdata') or irc.users.get(source) if not userdata: # No user data given. This was probably some other global event such as SQUIT. @@ -152,7 +165,11 @@ def cb_relay_core(irc, source, command, args): cargs['colored_nicks'] = ', '.join(colored_nicks) text = text_template.safe_substitute(cargs) - irc.proto.message(irc.pseudoclient.uid, channel, text) + if force_notice: + f = irc.proto.notice + else: + f = irc.proto.message + f(irc.pseudoclient.uid, channel, text) utils.add_hook(cb_relay_core, 'CLIENTBOT_MESSAGE') utils.add_hook(cb_relay_core, 'CLIENTBOT_KICK') diff --git a/protocols/clientbot.py b/protocols/clientbot.py index 0f00ea4..8b8bdb1 100644 --- a/protocols/clientbot.py +++ b/protocols/clientbot.py @@ -174,7 +174,7 @@ class ClientbotWrapperProtocol(Protocol): if self.irc.pseudoclient and self.irc.pseudoclient.uid == source: self.irc.send('%s %s :%s' % (command, self._expandPUID(target), text)) - elif utils.isChannel(target): + else: self.irc.callHooks([source, 'CLIENTBOT_MESSAGE', {'target': target, 'is_notice': notice, 'text': text}]) def nick(self, source, newnick): @@ -248,7 +248,7 @@ class ClientbotWrapperProtocol(Protocol): def _stub(self, *args): """Stub outgoing command function (does nothing).""" return - kill = mode = topic = topicBurst = knock = updateClient = numeric = _stub + kill = mode = topic = topicBurst = knock = numeric = _stub def updateClient(self, target, field, text): """Updates the known ident, host, or realname of a client."""