From 510372cb3968f70057630c8e1e3ec9e0d253e740 Mon Sep 17 00:00:00 2001 From: mathieui Date: Thu, 18 Dec 2014 23:39:13 +0100 Subject: Fix #2543 (irc plugin doesn't authenticate properly) Join the fake room first, then send the message to nickserv, then join initial rooms. Also add two commands and one option. --- plugins/irc.py | 244 +++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 220 insertions(+), 24 deletions(-) (limited to 'plugins') diff --git a/plugins/irc.py b/plugins/irc.py index 6341851e..ae51c297 100644 --- a/plugins/irc.py +++ b/plugins/irc.py @@ -4,8 +4,9 @@ Plugin destined to be used together with the Biboumi IRC gateway. For more information about Biboumi, please see the `official website`_. This plugin is here as a non-default extension of the poezio configuration -made to work with IRC rooms and logins. Therefore, it does not define any -commands or do anything useful except on load. +made to work with IRC rooms and logins. It also defines commands aimed at +reducing the amount of effort needed to navigate smoothly between IRC and +XMPP rooms. Configuration ------------- @@ -21,6 +22,14 @@ Global configuration The JID of the IRC gateway to use. If empty, irc.poez.io will be used. Please try to run your own, though, it’s painless to setup. + initial_connect + **Default:** ``true`` + + If you want to join all the rooms and try to authenticate with + nickserv when the plugin gets loaded. If ``false``, you will have + to use the :term:`/irc_login` command to authenticate, and the + :term:`/irc_join` command to join preconfigured rooms. + .. note:: There is no nickname option because the default from poezio will be used. Server-specific configuration @@ -49,14 +58,37 @@ section name, and the following options: Your nickname on this server. If empty, the default configuration will be used. - rooms + rooms [IRC plugin] **Default:** ``[empty]`` The list of rooms to join on this server (e.g. ``#room1:#room2``). .. note:: If no login_command or login_nick is set, the authentication phase - won’t take place and you will join the rooms after a small delay. + won’t take place and you will join the rooms without authentication + with nickserv or whatever. + +Commands +~~~~~~~~ + +.. glossary:: + :sorted: + /irc_login + **Usage:** ``/irc_login [server1] [server2]…`` + + Authenticate with the specified servers if they are correctly + configured. If no servers are provided, the plugin will try + them all. (You need to set :term:`login_nick` and + :term:`login_command` as well) + + /irc_join + **Usage:** ``/irc_join `` + + Join the specified room on the same server as the current tab (can + be a private conversation or a chatroom). If a server that appears + in the conversation is specified instead of a room, the plugin + will try to join all the rooms configured with autojoin on that + server. Example configuration ~~~~~~~~~~~~~~~~~~~~~ @@ -69,7 +101,7 @@ Example configuration [irc.freenode.net] nickname = mynick login_nick = nickserv - login_command = identify mynick mypassword + login_command = identify mypassword rooms = #testroom1:#testroom2 [irc.geeknode.org] @@ -84,38 +116,202 @@ Example configuration """ from plugin import BasePlugin +from decorators import command_args_parser +import common +import tabs class Plugin(BasePlugin): - def init(self): - - def join(server): - "Join rooms after a small delay" - nick = self.config.get('nickname', '', server) or self.core.own_nick - rooms = self.config.get('rooms', '', server).split(':') - for room in rooms: - room = '{}%{}@{}/{}'.format(room, server, gateway, nick) - self.core.command_join(room) + def init(self): + if self.config.get('initial_connect', True): + self.initial_connect() + + self.api.add_command('irc_login', self.command_irc_login, + usage='[server] [server]…', + help=('Connect to the specified servers if they ' + 'exist in the configuration and the login ' + 'options are set. If not is given, the ' + 'plugin will try all the sections in the ' + 'configuration.'), + short='Login to irc servers with nickserv', + completion=self.completion_irc_login) + + self.api.add_command('irc_join', self.command_irc_join, + usage='', + help=('Join in the same server as the ' + 'current tab (if it is an IRC tab). Or ' + 'join all the preconfigured rooms in ' + ' '), + short='Join irc rooms more easily', + completion=self.completion_irc_join) + + def join(self, gateway, server): + "Join irc rooms on a server" + nick = self.config.get_by_tabname('nickname', server, default='') or self.core.own_nick + rooms = self.config.get_by_tabname('rooms', server, default='').split(':') + for room in rooms: + room = '{}%{}@{}/{}'.format(room, server, gateway, nick) + self.core.command_join(room) + + def initial_connect(self): gateway = self.config.get('gateway', 'irc.poez.io') sections = self.config.sections() for section in (s for s in sections if s != 'irc'): - server_suffix = '%{}@{}'.format(section, gateway) + + room_suffix = '%{}@{}'.format(section, gateway) already_opened = False for tab in self.core.tabs: - if tab.name.endswith(server_suffix): + if tab.name.endswith(room_suffix) and tab.joined: already_opened = True + break - login_command = self.config.get('login_command', '', section) - login_nick = self.config.get('login_nick', '', section) - nick = self.config.get('nickname', '', section) or self.core.own_nick - + login_command = self.config.get_by_tabname('login_command', section, default='') + login_nick = self.config.get_by_tabname('login_nick', section, default='') + nick = self.config.get_by_tabname('nickname', section, default='') or self.core.own_nick if login_command and login_nick: - dest = '{}{}/{}'.format(login_nick, server_suffix, nick) + def login(): + dest = '{}!{}'.format(login_nick, room_suffix[1:]) + self.core.xmpp.send_message(mto=dest, mbody=login_command, mtype='chat') + delayed = self.api.create_delayed_event(5, self.join, gateway, section) + self.api.add_timed_event(delayed) + if not already_opened: + self.core.command_join(room_suffix + '/' + nick) + delayed = self.api.create_delayed_event(3, login) + self.api.add_timed_event(delayed) + else: + login() + elif not already_opened: + self.join(gateway, section) + + @command_args_parser.quoted(0, -1) + def command_irc_login(self, args): + """ + /irc_login [server] [server]… + """ + gateway = self.config.get('gateway', 'irc.poez.io') + if args: + not_present = [] + sections = self.config.sections() + for section in args: + if section not in sections: + not_present.append(section) + continue + login_command = self.config.get_by_tabname('login_command', section, default='') + login_nick = self.config.get_by_tabname('login_nick', section, default='') + if not login_command and not login_nick: + not_present.append(section) + continue + + room_suffix = '%{}@{}'.format(section, gateway) + dest = '{}!{}'.format(login_nick, room_suffix[1:]) self.core.xmpp.send_message(mto=dest, mbody=login_command, mtype='chat') + if len(not_present) == 1: + self.api.information('Section %s does not exist or is not configured' % not_present[0], 'Warning') + elif len(not_present) > 1: + self.api.information('Sections %s do not exist or are not configured' % ', '.join(not_present), 'Warning') + else: + sections = self.config.sections() + + for section in (s for s in sections if s != 'irc'): + login_command = self.config.get_by_tabname('login_command', section, default='') + login_nick = self.config.get_by_tabname('login_nick', section, default='') + if not login_nick and not login_command: + continue + + room_suffix = '%{}@{}'.format(section, gateway) + dest = '{}!{}'.format(login_nick, room_suffix[1:]) + self.core.xmpp.send_message(mto=dest, mbody=login_command, mtype='chat') + + + def completion_irc_login(self, the_input): + """ + completion for /irc_login + """ + args = the_input.text.split() + if '' in args: + args.remove('') + pos = the_input.get_argument_position() + sections = self.config.sections() + if 'irc' in sections: + sections.remove('irc') + for section in args: + try: + sections.remove(section) + except: + pass + return the_input.new_completion(sections, pos) + + @command_args_parser.quoted(1, 1) + def command_irc_join(self, args): + """ + /irc_join + """ + if not args: + return self.core.command_help('irc_join') + sections = self.config.sections() + if 'irc' in sections: + sections.remove('irc') + if args[0] in sections and self.config.get_by_tabname('rooms', args[0]): + self.join_server_rooms(args[0]) + else: + self.join_room(args[0]) + + def join_server_rooms(self, section): + """ + Join all the rooms configured for a section + (section = irc server) + """ + gateway = self.config.get('gateway', 'irc.poez.io') + rooms = self.config.get_by_tabname('rooms', section).split(':') + nick = self.config.get_by_tabname('nickname', section) + if nick: + nick = '/' + nick + else: + nick = '' + suffix = '%{}@{}{}'.format(section, gateway, nick) + + for room in rooms: + self.core.command_join(room + suffix) + + def join_room(self, name): + """ + Join a room with only its name and the current tab + """ + gateway = self.config.get('gateway', 'irc.poez.io') + current = self.core.current_tab() + current_jid = common.safeJID(current.name) + if not current_jid.server == gateway: + self.api.information('The current tab does not appear to be an IRC one', 'Warning') + return + if isinstance(current, tabs.OneToOneTab): + if not '!' in current_jid.node: + server = current_jid.node + else: + ignored, server = current_jid.node.rsplit('!', 1) + elif isinstance(current, tabs.MucTab): + if not '%' in current_jid.node: + server = current_jid.node + else: + ignored, server = current_jid.node.rsplit('%', 1) + else: + self.api.information('The current tab does not appear to be an IRC one', 'Warning') + return + + room = '{}%{}@{}'.format(name, server, gateway) + if self.config.get_by_tabname('nickname', server): + room += '/' + self.config.get_by_tabname('nickname', server) + + self.core.command_join(room) + + def completion_irc_join(self, the_input): + """ + completion for /irc_join + """ + sections = self.config.sections() + if 'irc' in sections: + sections.remove('irc') + return the_input.new_completion(sections, 1) - if not already_opened: - delayed = self.api.create_delayed_event(5, join, section) - self.api.add_timed_event(delayed) -- cgit v1.2.3