Exemplo n.º 1
0
    def get_weather(self, location, days=0):
        api_key = self.config.get('api_key', None)
        assert api_key, 'api_key configuration is missing'

        if days > 0:
            api_url = self.api_url_forecast.format(api_key=api_key,
                                                   location=location,
                                                   days=days + 1)
        else:
            api_url = self.api_url_current.format(api_key=api_key,
                                                  location=location)

        print(api_url)
        response = requests.get(api_url, headers=self.headers)

        if response.status_code != requests.codes.ok:
            raise CommandError(response)

        res = response.json()
        code = int(res['cod'])

        if code != requests.codes.ok:
            raise CommandError(res.get('message', res))

        return res
Exemplo n.º 2
0
    def _at_add(self, msg, schedule, cmd_name, *cmd_args, **job_kwargs):
        """Schedule command execution at specific time and date"""
        # Validate schedule
        schedule = str(schedule)

        if schedule.startswith('+'):
            try:
                dt = datetime.now() + timedelta(minutes=int(schedule))
            except ValueError:
                raise CommandError('Invalid date-time (required format: +<integer>)')
        else:
            try:
                dt = datetime.strptime(schedule, '%Y-%m-%d-%H-%M')
            except ValueError:
                raise CommandError('Invalid date-time (required format: YYYY-mm-dd-HH-MM)')

        # Validate command
        cmd = self.xmpp.commands.get_command(cmd_name)

        if not cmd:
            raise CommandError('Invalid command')

        # Check user permission
        user = self.xmpp.get_jid(msg)

        if not cmd.is_jid_permitted_to_run(self.xmpp, user):
            raise CommandError('Permission denied')

        # Create message (the only argument needed for command) with body representing the whole command
        body = ' '.join([cmd.name] + ["%s" % i for i in cmd_args])
        msg = self.xmpp.msg_copy(msg, body=body)
        job = self.xmpp.cron.crontab.add_at(cmd.get_fun(self.xmpp), dt, msg, user, **job_kwargs)
        logger.info('Registered one-time cron job: %s', job.display())

        return 'Scheduled job ID **%s** scheduled at %s' % (job.name, job.schedule)
Exemplo n.º 3
0
    def _set_status(self, show, status=None):
        """Send presence status"""
        if show not in self._status_show_types:
            raise CommandError('Invalid status type')

        if show == 'online':
            show = None

        try:
            self.xmpp.client.send_presence(pstatus=status, pshow=show)
        except IqError as e:
            raise CommandError('Status update failed: __%s__' % getattr(e, 'condition', str(e)))
Exemplo n.º 4
0
    def remind(self, msg, *args):
        """
        List, add, or delete reminders.

        List all scheduled reminders.
        Usage: remind

        Schedule reminder at specific time and date.
        Usage: remind add +minutes <message>
        Usage: remind add Y-m-d-H-M <message>

        Remove reminder from queue of scheduled reminders.
        Usage: remind del <reminder ID>
        """
        args_count = len(args)

        if args_count > 0:
            action = args[0]

            if action == 'add':
                if args_count < 2:
                    raise MissingParameter
                else:
                    at_add_params = (args[1], self._reminder_command, self.xmpp.get_jid(msg), self._reminder) + args[2:]
                    return self._at_add(msg, *at_add_params, at_reply_output=False)
            elif action == 'del':
                if args_count < 2:
                    raise MissingParameter
                else:
                    return self._at_del(msg, args[1])
            else:
                raise CommandError('Invalid action')

        return self._at_list(msg, reminder=True)
Exemplo n.º 5
0
    def _get_output_stream(self, name):
        """Stream Ludolph command output"""
        for line in self.output:
            yield line

        if self.returncode != 0:
            raise CommandError('Command "%s" exited with non-zero status %s' % (name, self.returncode))
Exemplo n.º 6
0
    def _get_output(self, name):
        """Classic Ludolph command output"""
        out = '\n'.join(self.output)

        if self.returncode == 0:
            return out
        else:
            raise CommandError(out)
Exemplo n.º 7
0
    def _execute(self, msg, name, cmd, *args):
        """Execute a command and return stdout or raise CommandError"""
        try:
            if cmd is None:  # pass-through mode
                cmd = shlex.split(msg['body'])
            else:
                cmd = shlex.split(cmd)
                cmd.extend(list(map(str, args)))
        except Exception:
            raise CommandError('Could not parse command parameters')

        logger.info('Running dynamic command: %s', cmd)

        try:
            return Process(cmd).cmd_output(name, stream=msg.stream_output)
        except CommandError:
            raise
        except Exception as e:
            raise CommandError('Could not run command (%s)' % e)
Exemplo n.º 8
0
    def kick(self, msg, user):
        """
        Kick user from multi-user chat room (room admin only).

        Usage: kick <JID>
        """
        nick = self._get_nick(user)

        if not nick:
            raise CommandError('User **%s** is not in MUC room' % user)

        try:
            self.xmpp.muc.setRole(self.xmpp.room, nick, 'none')
        except (IqError, ValueError) as e:
            err = getattr(e, 'condition', str(e))
            raise CommandError(
                'User **%s** could not be kicked from MUC room: __%s__' %
                (user, err))

        return 'User **%s** kicked from MUC room' % user
Exemplo n.º 9
0
    def _at_del(self, msg, name):
        """Remove scheduled job"""
        try:
            job_id = int(name)
        except (ValueError, TypeError):
            raise CommandError('Invalid job ID')

        crontab = self.xmpp.cron.crontab
        job = crontab.get(job_id, None)

        if job and job.onetime:
            user = self.xmpp.get_jid(msg)

            if job.owner == user or self.xmpp.is_jid_admin(user):
                crontab.delete(job_id)
                logger.info('Deleted one-time cron jobs: %s', job.display())

                return 'Scheduled job ID **%s** deleted' % job_id
            else:
                raise CommandError('Permission denied')

        raise CommandError('Non-existent job ID')
Exemplo n.º 10
0
    def _set_room_subject(self, text, mfrom=None):
        """Set room subject"""
        msg = self.xmpp.client.Message()
        msg['to'] = self.xmpp.room
        msg['from'] = mfrom
        msg['type'] = 'groupchat'
        # noinspection PyProtectedMember
        msg._set_sub_text('subject', text or '', keep=True)

        try:
            msg.send()
        except IqError as e:
            raise CommandError('Room topic update failed: __%s__' %
                               getattr(e, 'condition', str(e)))
Exemplo n.º 11
0
    def _message_send(self, jid, msg):
        """Send new xmpp message. Used by message command and /message webhook"""
        if jid == self.xmpp.room:
            mtype = 'groupchat'
        elif jid in self.xmpp.client_roster:
            mtype = 'normal'
        else:
            raise CommandError('User "%s" not in roster' % jid)

        logger.info('Sending message to "%s"', jid)
        logger.debug('\twith body: "%s"', msg)
        self.xmpp.msg_send(jid, msg, mtype=mtype)

        return 'Message sent to **%s**' % jid
Exemplo n.º 12
0
    def motd(self, msg, action=None, text=None):
        """
        Show, set or remove message of the day.

        Show message of the day (room user only).
        Usage: motd

        Set message of the day (room admin only).
        Usage: motd set <text>

        Delete message of the day and disable automatic announcements (room admin only).
        Usage: motd del
        """
        if action:
            if not self.xmpp.is_jid_room_admin(self.xmpp.get_jid(msg)):
                raise PermissionDenied

            if action == 'del':
                self.room_motd = None
                return 'MOTD successfully deleted'
            elif action == 'set':
                if not text:
                    raise CommandError('Missing text')
                # Get original version from message body (strip command and sub-command)
                self.room_motd = msg['body'].lstrip().split(None, 2)[-1]
                # Announce new motd into room
                self.xmpp.msg_send(self.xmpp.room,
                                   self.room_motd,
                                   mtype='groupchat')
                return 'MOTD successfully updated'
            else:
                raise CommandError('Invalid action')

        if self.room_motd is None:
            return '(MOTD disabled)'
        else:
            return self.room_motd
Exemplo n.º 13
0
    def at(self, msg, *args):
        """
        List, add, or delete jobs for later execution.

        List all scheduled jobs.
        Usage: at

        Schedule command execution at specific time and date.
        Usage: at add +minutes <command> [command parameters...]
        Usage: at add Y-m-d-H-M <command> [command parameters...]

        Remove command from queue of scheduled jobs.
        Usage: at del <job ID>
        """
        if not self.xmpp.cron:
            raise CommandError(
                'Cron support is disabled in Ludolph configuration file')

        args_count = len(args)

        if args_count > 0:
            action = args[0]

            if action == 'add':
                if args_count < 3:
                    raise MissingParameter
                else:
                    return self._at_add(msg, *args[1:])
            elif action == 'del':
                if args_count < 2:
                    raise MissingParameter
                else:
                    return self._at_del(msg, args[1])
            else:
                raise CommandError('Invalid action')

        return self._at_list(msg)
Exemplo n.º 14
0
    def version(self, msg, plugin=None):
        """
        Display version of Ludolph or registered plugin.

        Usage: version [plugin]
        """
        if plugin:
            mod, obj = self.xmpp.plugins.get_plugin(plugin)

            if mod:
                return '**%s** version: %s' % (mod, obj.get_version())
            else:
                raise CommandError('**%s** isn\'t a Ludolph plugin. Check help for available plugins.' % plugin)

        return '**Ludolph** version: %s' % self.get_version()
Exemplo n.º 15
0
    def invite(self, msg, user=None):
        """
        Invite user or yourself to multi-user chat room.

        Usage: invite [JID]
        """
        if not user:
            user = self.xmpp.get_jid(msg)

        if not self.xmpp.is_jid_room_user(user):
            raise CommandError(
                'User **%s** is not allowed to access the MUC room' % user)

        self.xmpp.muc.invite(self.xmpp.room, user)

        return 'Inviting **%s** to MUC room %s' % (user, self.xmpp.room)
Exemplo n.º 16
0
    def _avatar_set(self, msg, avatar_name):
        """Set avatar for Ludolph (admin only)"""
        if os.path.splitext(avatar_name)[-1] not in self._avatar_allowed_extensions:
            raise CommandError('You have requested a file that is not supported')

        avatar = None
        available_avatar_directories = self._get_avatar_dirs()

        for avatar_dir in available_avatar_directories:
            # Create full path to file requested by user
            avatar_file = os.path.join(avatar_dir, avatar_name)
            # Split absolute path for check if user is not trying to jump outside allowed dirs
            path, name = os.path.split(os.path.abspath(avatar_file))

            if path not in available_avatar_directories:
                raise CommandError('You are not allowed to set avatar outside defined directories')

            try:
                with open(avatar_file, 'rb') as f:
                    avatar = f.read()
            except (OSError, IOError):
                avatar = None
            else:
                break

        if not avatar:
            raise CommandError('Avatar "%s" has not been found.\n'
                               'You can list available avatars with the command: **avatar-list**' % avatar_name)

        self.xmpp.msg_reply(msg, 'I have found the selected avatar, changing it might take few seconds...',
                            preserve_msg=True)
        xep_0084 = self.xmpp.client.plugin['xep_0084']
        avatar_type = 'image/%s' % imghdr.what('', avatar)
        avatar_id = xep_0084.generate_id(avatar)
        avatar_bytes = len(avatar)

        try:
            logger.debug('Publishing XEP-0084 avatar data')
            xep_0084.publish_avatar(avatar)
        except XMPPError as e:
            logger.error('Could not publish XEP-0084 avatar: %s' % e.text)
            raise CommandError('Could not publish selected avatar')

        try:
            logger.debug('Publishing XEP-0153 avatar vCard data')
            self.xmpp.client.plugin['xep_0153'].set_avatar(avatar=avatar, mtype=avatar_type)
        except XMPPError as e:
            logger.error('Could not publish XEP-0153 vCard avatar: %s' % e.text)
            raise CommandError('Could not set vCard avatar')

        self.xmpp.msg_reply(msg, 'Almost done, please be patient', preserve_msg=True)

        try:
            logger.debug('Advertise XEP-0084 avatar metadata')
            xep_0084.publish_avatar_metadata([{
                'id': avatar_id,
                'type': avatar_type,
                'bytes': avatar_bytes
            }])
        except XMPPError as e:
            logger.error('Could not publish XEP-0084 metadata: %s' % e.text)
            raise CommandError('Could not publish avatar metadata')

        return 'Avatar has been changed :)'