Пример #1
0
        conn_reject = []  # FIXME: reject ConnBroker.OUTGOING_TRACKABLE ?
        if url[:6].lower() == 'https:':
            conn_need = [ConnBroker.OUTGOING_HTTP]
        elif url[:5].lower() == 'http:':
            conn_need = [ConnBroker.OUTGOING_HTTPS]
        else:
            raise AccessError('Invalid URL scheme')

        try:
            with ConnBroker.context(need=conn_need, reject=conn_reject) as ctx:
                session.ui.mark('Getting: %s' % url)
                response = urlopen(url, data=None, timeout=timeout)
        except HTTPError, e:
            response = e

        data = response.read()
        headers = response.headers
        contenttype = headers.get('content-type', 'application/octet-stream')

        request = html_variables['http_request']
        request.send_http_response(response.code, response.msg)
        request.send_standard_headers(mimetype=contenttype,
                                      header_list=[('Content-Length',
                                                    len(data))])
        request.wfile.write(data)

        raise SuppressHtmlOutput()


_plugins.register_commands(JsApi, ProgressiveWebApp, HttpProxyGetRequest)
Пример #2
0
        # Make everything in the background quit ASAP...
        mailpile.util.LAST_USER_ACTIVITY = 0
        mailpile.util.QUITTING = mailpile.util.QUITTING or True

        if config.plugins:
            config.plugins.process_shutdown_hooks()

        config.stop_workers()
        if config.index:
            config.index.save_changes()
        if config.event_log:
            config.event_log.close()

        session.ui.display_result(Action(session, 'cleanup', ''))

        if session.interactive and config.sys.debug:
            session.ui.display_result(Action(session, 'ps', ''))

        # Remove anything that we couldn't remove before
        safe_remove()

        # Restart the app if that's what was requested
        if mailpile.util.QUITTING == 'restart':
            os.execv(sys.argv[0], sys.argv)


_plugins.register_commands(InteractCommand, WaitCommand)

if __name__ == "__main__":
    Main(sys.argv[1:])
Пример #3
0
            if skip:
                continue

            results.append({
                'fid': fid,
                'terms': trms,
                'tags': tags,
                'human_tags': ' '.join(human_tags),
                'comment': cmnt,
                'type': ftype
            })
        return results


class MoveFilter(ListFilters):
    """Move an auto-tagging rule"""
    SYNOPSIS = (None, 'filter/move', None, '<filter-id> <position>')
    ORDER = ('Tagging', 1)
    HTTP_CALLABLE = ('POST', 'UPDATE')
    COMMAND_SECURITY = security.CC_CHANGE_FILTERS

    def command(self):
        self.session.config.filter_move(self.args[0], self.args[1])
        self._background_save(config=True)
        return ListFilters.command(self, want_fid=self.args[1])


_plugins.register_commands(Tag, TagLater, TagTemporarily, AddTag, DeleteTag,
                           ListTags, Filter, DeleteFilter, MoveFilter,
                           ListFilters)
Пример #4
0
        if motd:
            self.event.data['motd'] = motd

            lang = config.prefs.language or 'en'
            motd['_motd'] = motd.get(lang, motd.get('en'))

            latest = motd.get('latest_version')
            if not latest:
                motd['_version_info'] = _('Mailpile update info unavailable')
            elif latest == APPVER:
                motd['_version_info'] = _('Your Mailpile is up to date')
            else:
                motd['_version_info'] = _('An upgrade for Mailpile is '
                                          'available, version %s'
                                          ) % latest

            if '--silent' in self.args:
                motd = {}
            elif '--ifnew' in self.args and not motd.get('_is_new'):
                motd = {}

            return self._success(message, result=motd)
        else:
            message = '%s: %s' % (_('Message Of The Day'), _('Unknown'))
            return self._error(message, result={})


_plugins.register_commands(MessageOfTheDay)
_plugins.register_slow_periodic_job('motd', 3600, MessageOfTheDay.update)
Пример #5
0
            session, handle = self.session, vcard.nickname
            return (Filter(session, arg=['delete',
                                         'group:{0!s}'.format(handle)]).run() and
                    DeleteTag(session, arg=[handle]).run())

    return GroupVCardCommand


class Group(GroupVCard(VCard)):
    """View groups"""


class AddGroup(GroupVCard(AddVCard)):
    """Add groups"""


class GroupAddLines(GroupVCard(VCardAddLines)):
    """Add lines to a group VCard"""


class RemoveGroup(GroupVCard(RemoveVCard)):
    """Remove groups"""


class ListGroups(GroupVCard(ListVCards)):
    """Find groups"""


_plugins.register_commands(Group, AddGroup, GroupAddLines,
                           RemoveGroup, ListGroups)
Пример #6
0
    """De-authenticate a user (log out)"""
    SYNOPSIS = (None, 'logout', 'auth/logout', '[<session ID>]')
    ORDER = ('Internals', 5)
    SPLIT_ARG = False
    IS_INTERACTIVE = True
    CONFIG_REQUIRED = False
    HTTP_AUTH_REQUIRED = False
    HTTP_CALLABLE = ('GET', 'POST')

    def command(self):
        # FIXME: Should this only be a POST request?
        # FIXME: This needs CSRF protection.

        session_id = self.session.ui.html_variables.get('http_session')
        if self.args and not session_id:
            session_id = self.args[0]

        if session_id:
            try:
                self.session.ui.debug('Logging out %s' % session_id)
                del SESSION_CACHE[session_id]
                return self._success(_('Goodbye!'))
            except KeyError:
                pass

        return self._error(_('No session found!'))


plugin_manager = PluginManager(builtin=True)
plugin_manager.register_commands(Authenticate, DeAuthenticate)
Пример #7
0
                          and (term not in cmnt.lower())):
                        skip = True
            if skip:
                continue

            results.append({
                'fid': fid,
                'terms': trms,
                'tags': tags,
                'human_tags': ' '.join(human_tags),
                'comment': cmnt,
                'type': ftype
            })
        return results


class MoveFilter(ListFilters):
    """Move an auto-tagging rule"""
    SYNOPSIS = (None, 'filter/move', None, '<filter-id> <position>')
    ORDER = ('Tagging', 1)
    HTTP_CALLABLE = ('POST', 'UPDATE')

    def command(self):
        self.session.config.filter_move(self.args[0], self.args[1])
        self.session.config.save()
        return ListFilters.command(self, want_fid=self.args[1])


_plugins.register_commands(Tag, AddTag, DeleteTag, ListTags, Filter,
                           DeleteFilter, MoveFilter, ListFilters)
Пример #8
0
        if self.data.get('_method', None) == 'POST':
            password = self.data.get('password', [None])[0]
        else:
            password = self.session.ui.get_password(
                _('Enter your password:'******' ')

        if policy == 'store':
            if fingerprint in config.passphrases:
                del config.passphrases[fingerprint]
            config.secrets[fingerprint] = {
                'password': password,
                'policy': policy
            }
            return happy(_('Password stored permanently'))

        elif policy == 'cache-only' and password:
            sps = SecurePassphraseStorage(password)
            if ttl > 0:
                sps.expiration = time.time() + ttl
            config.passphrases[fingerprint] = sps
            if fingerprint.lower() in config.secrets:
                del config.secrets[fingerprint.lower()]
            return happy(_('Password stored temporarily'))

        else:
            return self._error(_('Invalid password policy!'), result)


plugin_manager = PluginManager(builtin=True)
plugin_manager.register_commands(Authenticate, DeAuthenticate, SetPassphrase)
Пример #9
0
            results.update({
                'username': username,
                'oauth_url': self.GetOAuthURL(session, ocfg, username) })

        elif code:
            username, oname, csrf = state.split('/', 2)
            if not session.ui.valid_csrf_token(csrf):
                print 'Invalid CSRF token: %s' % csrf
                raise AccessError('Invalid CSRF token')

            oname, ocfg = self.GetOAuthConfig(config, oname=oname)
            tok_id, tok_info = self.GetToken(session, ocfg, code,
                                             tok_id=username)

            # This helps the mail sources/routes detect that it may
            # be worth trying the connection again...
            for msid, source in config.sources.iteritems():
                if source.username == username:
                    source.password = tok_info.access_token
            for msid, route in config.routes.iteritems():
                if route.username == username:
                    route.password = tok_info.access_token

            results['success'] = True

        return self._success(_('OAuth2 Authorization'), results)


_ = gettext
_plugins.register_commands(OAuth2)
Пример #10
0
                        # FIXME: Add route discovery mechanism.
                        profile = {
                            "email": uid["email"],
                            "name": uid["name"],
                        }
                        session.config.profiles.append(profile)
                    if not session.config.prefs.gpg_recipient:
                        session.config.prefs.gpg_recipient = key
                        session.ui.notify(_('Encrypting config to %s') % key)
                    if session.config.prefs.crypto_policy == 'none':
                        session.config.prefs.crypto_policy = 'openpgp-sign'
        else:
            session.ui.warning(_('Oh no, PGP/GPG support is unavailable!'))

        if (session.config.prefs.gpg_recipient
                and not (self._idx() and self._idx().INDEX)
                and not session.config.prefs.obfuscate_index):
            randcrap = sha512b64(open('/dev/urandom').read(1024),
                                 session.config.prefs.gpg_recipient,
                                 '%s' % time.time())
            session.config.prefs.obfuscate_index = randcrap
            session.config.prefs.index_encrypted = True
            session.ui.notify(_('Obfuscating search index and enabling '
                                'indexing of encrypted e-mail. '))

        session.config.save()
        return self._success(_('Performed initial Mailpile setup'))


_plugins.register_commands(Setup)
Пример #11
0
    register(9500, AutoSmtpStartTLSConnBroker)
    register(9500, AutoImapStartTLSConnBroker)
    register(9500, AutoPop3StartTLSConnBroker)

    if socks is not None:
        register(1500, SocksConnBroker)
        register(3500, TorConnBroker)
        register(3500, TorRiskyBroker)
        register(3500, TorOnionBroker)

    # Note: At this point we have already imported security, which
    #       also monkey-patches these same functions. This is a good
    #       thing and is deliberate. :-)
    ssl.wrap_socket = monkey_patch(ssl.wrap_socket, SslWrapOnlyOnce)
    if hasattr(ssl, 'SSLContext'):
        ssl.SSLContext.wrap_socket = monkey_patch(
           ssl.SSLContext.wrap_socket, SslContextWrapOnlyOnce)

    from mailpile.plugins import PluginManager
    _plugins = PluginManager(builtin=__file__)
    _plugins.register_commands(NetworkHistory, GetTlsCertificate)

else:
    import doctest
    import sys
    results = doctest.testmod(optionflags=doctest.ELLIPSIS,
                              extraglobs={})
    print '%s' % (results, )
    if results.failed:
        sys.exit(1)
Пример #12
0
        if len(self.args) > 2:
            server = self.args[2]

        n = Nicknym(self.session.config)
        return n.get_key(address, keytype, server)


class NicknymRefreshKeys(Command):
    """Get a key from a nickserver"""
    ORDER = ('', 0)
    SYNOPSIS = (None, 'crypto/nicknym/refreshkeys', 
                'crypto/nicknym/refreshkeys', '')

    HTTP_CALLABLE = ('POST',)

    def command(self):
        n = Nicknym(self.session.config)
        n.refresh_keys()
        return True


_plugins = PluginManager(builtin=__file__)
_plugins.register_commands(NicknymGetKey)
_plugins.register_commands(NicknymRefreshKeys)


if __name__ == "__main__":
    n = Nicknym()
    print n.get_key("*****@*****.**")
Пример #13
0
            motd = old_motd

        if motd:
            self.event.data['motd'] = motd

            lang = config.prefs.language or 'en'
            motd['_motd'] = motd.get(lang, motd.get('en'))

            latest = motd.get('latest_version')
            if not latest:
                motd['_version_info'] = _('Mailpile update info unavailable')
            elif latest == APPVER:
                motd['_version_info'] = _('Your Mailpile is up to date')
            else:
                motd['_version_info'] = _('An upgrade for Mailpile is '
                                          'available, version %s') % latest

            if '--silent' in self.args:
                motd = {}
            elif '--ifnew' in self.args and not motd.get('_is_new'):
                motd = {}

            return self._success(message, result=motd)
        else:
            message = '%s: %s' % (_('Message Of The Day'), _('Unknown'))
            return self._error(message, result={})


_plugins.register_commands(MessageOfTheDay)
_plugins.register_slow_periodic_job('motd', 3600, MessageOfTheDay.update)
Пример #14
0
    def command(self):
        session, config = self.session, self.session.config
        if 'q' in self.data:
            terms = [t.lower() for t in self.data['q']]
        else:
            terms = [t.lower() for t in self.args]
        count = int(self.data.get('count', 10))
        offset = int(self.data.get('offset', 0))

        vcard_addrs = self._vcard_addresses(config, terms)
        index_addrs = self._index_addresses(config, terms, vcard_addrs)
        addresses = vcard_addrs + index_addrs
        addresses.sort(key=lambda k: -k['rank'])
        total = len(addresses)
        return {
            'addresses': addresses[offset:min(offset + count, total)],
            'displayed': min(count, total),
            'total': total,
            'offset': offset,
            'count': count,
            'start': offset,
            'end': offset + count,
        }


_plugins.register_commands(VCard, AddVCard, VCardAddLines, RemoveVCard,
                           ListVCards)
_plugins.register_commands(Contact, AddContact, ContactAddLines, RemoveContact,
                           ListContacts, AddressSearch)
_plugins.register_commands(ContactImport, ContactImporters)
Пример #15
0
class ConnectToGuiOMatic(Command):
    """Connect to a waiting gui-o-matic GUI"""
    SYNOPSIS = (None, 'gui', 'gui', '[<secret>] [main|watch] <port>')
    ORDER = ('Internals', 9)
    CONFIG_REQUIRED = False
    IS_USER_ACTIVITY = False
    HTTP_CALLABLE = ('GET', 'POST')
    HTTP_AUTH_REQUIRED = False

    def command(self):
        if self.data.get('_method'):
            secret, style, port = self.args
            if secret != GetUserSecret(self.session.config):
                raise AccessError('Invalid User Secret')
        elif len(self.args) == 2:
            style, port = self.args
        elif len(self.args) == 1:
            style, port = 'main', self.args[0]

        with ConnBroker.context(need=[ConnBroker.OUTGOING_RAW]):
            guic = GuiOMaticConnection(self.session.config,
                                       socket.create_connection(
                                           ('localhost', int(port))),
                                       main=(style == 'main'))
        guic.start()

        return self._success("OK")


_plugins.register_commands(ConnectToGuiOMatic)
Пример #16
0
        if url[:6].lower() == 'https:':
            conn_need = [ConnBroker.OUTGOING_HTTP]
        elif url[:5].lower() == 'http:':
            conn_need = [ConnBroker.OUTGOING_HTTPS]
        else:
            raise AccessError('Invalid URL scheme')

        try:
            with ConnBroker.context(need=conn_need, reject=conn_reject) as ctx:
                session.ui.mark('Getting: %s' % url)
                response = urlopen(url, data=None, timeout=timeout)
        except HTTPError, e:
            response = e

        data = response.read()
        headers = response.headers
        contenttype = headers.get('content-type', 'application/octet-stream')

        request = html_variables['http_request']
        request.send_http_response(response.code, response.msg)
        request.send_standard_headers(mimetype=contenttype,
                                      header_list=[('Content-Length',
                                                    len(data))])
        request.wfile.write(data)
        request.send_full_response(response.code, response.msg)

        raise SuppressHtmlOutput()


_plugins.register_commands(JsApi, HttpProxyGetRequest)
Пример #17
0
    def quit(self, join=True):
        self.quitting = True
        if join and self.isAlive():
            self.join()


class HashCash(Command):
    """Try to collide a hash using the SMTorP algorithm"""
    SYNOPSIS = (None, 'hashcash', None, '<bits> <challenge>')
    ORDER = ('Internals', 9)
    HTTP_CALLABLE = ()
    COMMAND_SECURITY = security.CC_CPU_INTENSIVE

    def command(self):
        bits, challenge = int(self.args[0]), self.args[1]
        expected = 2 ** bits
        def marker(counter):
            progress = ((1024.0 * counter) / expected) * 100
            self.session.ui.mark('Finding a %d-bit collision for %s (%d%%)'
                                 % (bits, challenge, progress))
        collision = sha512_512kCollide(challenge, bits, callback1k=marker)
        return self._success({
            'challenge': challenge,
            'collision': collision
        })


_plugins.register_worker(SMTPWorker)
_plugins.register_commands(HashCash)
Пример #18
0
        session, config = self.session, self.session.config
        if 'q' in self.data:
            terms = [t.lower() for t in self.data['q']]
        else:
            terms = [t.lower() for t in self.args]
        count = int(self.data.get('count', 10))
        offset = int(self.data.get('offset', 0))

        vcard_addrs = self._vcard_addresses(config, terms)
        index_addrs = self._index_addresses(config, terms, vcard_addrs)
        addresses = vcard_addrs + index_addrs
        addresses.sort(key=lambda k: -k['rank'])
        total = len(addresses)
        return {
            'addresses': addresses[offset:min(offset+count, total)],
            'displayed': min(count, total),
            'total': total,
            'offset': offset,
            'count': count,
            'start': offset,
            'end': offset+count,
        }


_plugins.register_commands(VCard, AddVCard, VCardAddLines,
                           RemoveVCard, ListVCards)
_plugins.register_commands(Contact, AddContact, ContactAddLines,
                           RemoveContact, ListContacts,
                           AddressSearch)
_plugins.register_commands(ContactImport, ContactImporters)
Пример #19
0
        for name, guard, step in cls._CHECKPOINTS(config):
            auth_required = (step.HTTP_AUTH_REQUIRED is True
                             or (config.prefs.gpg_recipient and
                                 step.HTTP_AUTH_REQUIRED == 'Maybe'))
            if not guard():
                if (not needed_auth) or (not auth_required):
                    return step

        return default

    def setup_command(self, session):
        if '_method' in self.data:
            return self._success(_('Entering setup flow'), result=dict(
                ((c[0], c[1]() and True or False)
                 for c in self._CHECKPOINTS(session.config)
            )))
        else:
            return SetupMagic.setup_command(self, session)


_ = gettext
_plugins.register_commands(SetupMagic,
                           SetupGetEmailSettings,
                           SetupWelcome,
                           SetupCrypto,
                           SetupProfiles,
                           SetupConfigureKey,
                           SetupTestRoute,
                           Setup)
Пример #20
0

class Watch(Command):
    """Watch the events fly by"""
    SYNOPSIS = (None, 'eventlog/watch', None, None)
    ORDER = ('Internals', 9)
    IS_USER_ACTIVITY = False
    CONFIG_REQUIRED = False

    def command(self):
        config = self.session.config
        unregister = False
        self.session.ui.notify(
            _('Watching logs: Press CTRL-C to return to the CLI'))
        try:
            while not mailpile.util.QUITTING and not config.event_log:
                time.sleep(1)
            unregister = config.event_log.ui_watch(self.session.ui)
            self.session.ui.unblock(force=True)
            while not mailpile.util.QUITTING:
                time.sleep(1)
        except KeyboardInterrupt:
            pass
        finally:
            if unregister:
                config.event_log.ui_unwatch(self.session.ui)
        return self._success(_('That was fun!'))


_plugins.register_commands(Events, Cancel, Undo, Watch)
Пример #21
0
            try:
                msg_info = idx.get_msg_at_idx_pos(msg_idx_pos)
                msg_emails = (idx.expand_to_list(msg_info, field=idx.MSG_TO) +
                              idx.expand_to_list(msg_info, field=idx.MSG_CC))
                emails.extend(msg_emails)
                if 'no_from' not in self.data:
                    emails.append(msg_info[idx.MSG_FROM])
            except ValueError:
                pass

        addrs = [
            ai for ee in emails for ai in AddressHeaderParser(unicode_data=ee)
        ]
        return self._success(_('Choosing from address'),
                             result={
                                 'emails':
                                 addrs,
                                 'from':
                                 vcards.choose_from_address(
                                     self.session.config, addrs)
                             })


_plugins.register_commands(VCard, AddVCard, RemoveVCard, ListVCards,
                           VCardAddLines, VCardRemoveLines)
_plugins.register_commands(Contact, AddContact, RemoveContact, ListContacts,
                           AddressSearch)
_plugins.register_commands(Profile, AddProfile, RemoveProfile, ListProfiles,
                           ChooseFromAddress)
_plugins.register_commands(ContactImport, ContactImporters)
Пример #22
0
class ConnectToGuiOMatic(Command):
    """Connect to a waiting gui-o-matic GUI"""
    SYNOPSIS = (None, 'gui', 'gui', '[<secret>] [main|watch] <port>')
    ORDER = ('Internals', 9)
    CONFIG_REQUIRED = False
    IS_USER_ACTIVITY = False
    HTTP_CALLABLE = ('GET', 'POST')
    HTTP_AUTH_REQUIRED = False

    def command(self):
        if self.data.get('_method'):
            secret, style, port = self.args
            if secret != GetUserSecret(self.session.config):
                raise AccessError('Invalid User Secret')
        elif len(self.args) == 2:
            style, port = self.args
        elif len(self.args) == 1:
            style, port = 'main', self.args[0]

        with ConnBroker.context(need=[ConnBroker.OUTGOING_RAW]):
            guic = GuiOMaticConnection(
                self.session.config,
                socket.create_connection(('localhost', int(port))),
                main=(style == 'main'))
        guic.start()

        return self._success("OK")


_plugins.register_commands(ConnectToGuiOMatic)
Пример #23
0
class Cached(Command):
    """Fetch results from the command cache."""
    SYNOPSIS = (None, 'cached', 'cached', '[<cache-id>]')
    ORDER = ('Internals', 7)
    HTTP_QUERY_VARS = {'id': 'Cache ID of command to redisplay'}
    IS_USER_ACTIVITY = False
    LOG_NOTHING = True

    def max_age(self):
        # Allow result to be cached by the browser for 2 seconds; we do
        # this to facilitate cross-tab sharing of cache results.
        return 2

    # Warning: This depends on internals of Command, how things are run there.
    def run(self):
        try:
            cid = self.args[0] if self.args else self.data.get('id', [None])[0]
            rv = self.session.config.command_cache.get_result(cid)
            self.session.copy(rv.session)
            rv.session.ui.render_mode = self.session.ui.render_mode
            return rv
        except:
            self._starting()
            self._error(self.FAILURE % {'name': self.name,
                                        'args': ' '.join(self.args)})
            return self._finishing(False)


_plugins.register_commands(Cached)
Пример #24
0
        for tag in cfg.get_tags(type='outbox'):
            search = ['in:%s' % tag._key]
            for msg_idx_pos in idx.search(self.session,
                                          search,
                                          order='flat-index').as_set():
                messages.append('=%s' % b36(msg_idx_pos))
        if messages:
            self.args = tuple(messages)
            return Sendit.command(self)
        else:
            return self._success(_('The outbox is empty'))


_plugins.register_config_variables('prefs', {
    'empty_outbox_interval':
    [_('Delay between attempts to send mail'), int, 90]
})
_plugins.register_slow_periodic_job('sendmail', 'prefs.empty_outbox_interval',
                                    EmptyOutbox.sendmail)
_plugins.register_commands(
    Compose,
    Reply,
    Forward,  # Create
    Draft,
    Update,
    Attach,  # Manipulate
    UnThread,  # ...
    Sendit,
    UpdateAndSendit,  # Send
    EmptyOutbox)  # ...
Пример #25
0
            for i in reversed(range(0, len(msg_idxs))):
                mi = msg_idxs[i]
                msg_idxs[i:i + 1] = [
                    int(m[idx.MSG_MID], 36)
                    for m in idx.get_conversation(msg_idx=mi)
                ]

        # Let's always export in the same order. Stability is nice.
        msg_idxs.sort()

        mbox = self.create_mailbox(mbox_type, path)
        exported = {}
        while msg_idxs:
            msg_idx = msg_idxs.pop(0)
            if msg_idx not in exported:
                e = Email(idx, msg_idx)
                session.ui.mark('Exporting =%s ...' % e.msg_mid())
                mbox.add(e.get_msg())
                exported[msg_idx] = 1

        mbox.flush()

        return self._success(
            _('Exported %d messages to %s') % (len(exported), path), {
                'exported': len(exported),
                'created': path
            })


_plugins.register_commands(ExportMail)
Пример #26
0
                cids = [cid]

            for c in cids:
                fn, info = e.extract_attachment(session,
                                                c,
                                                name_fmt=name_fmt,
                                                mode=mode)
                if info:
                    info['idx'] = e.msg_idx_pos
                    if fn:
                        info['created_file'] = fn
                    results.append(info)
        return results


_plugins.register_commands(Extract, Next, Order, Previous, Search, View)

##[ Search terms ]############################################################


def mailbox_search(config, idx, term, hits):
    word = term.split(':', 1)[1].lower()
    try:
        mbox_id = FormatMbxId(b36(int(word, 36)))
    except ValueError:
        mbox_id = None

    mailboxes = []
    for m in config.sys.mailbox.keys():
        fn = FilePath(config.sys.mailbox[m]).display().lower()
        if (mbox_id == m) or word in fn:
Пример #27
0
                    event.flags = event.COMPLETE
                    self.session.config.event_log.log_event(event)
                canceled.append(event.event_id)
        return self._success(_('Canceled %d events') % len(canceled),
                             canceled)


class Undo(Command):
    """Undo an event"""
    SYNOPSIS = (None, 'eventlog/undo', 'eventlog/undo', '<eventID>')
    ORDER = ('Internals', 9)
    HTTP_CALLABLE = ('POST', )
    HTTP_POST_VARS = {
        'event_id': 'Event ID'
    }
    IS_USER_ACTIVITY = False

    def command(self):
        event_id = self.data.get('event_id', [None])[0] or self.args[0]
        event = self.session.config.event_log.get(event_id)
        if event:
            try:
                return event.source_class.Undo(self, event)
            except (NameError, AttributeError):
                return self._error(_('Event is not undoable'))
        else:
            return self._error(_('Event not found'))


_plugins.register_commands(Events, Cancel, Undo)
Пример #28
0
        'address': 'The nick/address to find a key for',
        'allowremote': 'Whether to permit remote key lookups (defaults to true)'
    }

    def command(self):
        if len(self.args) > 1:
            allowremote = self.args.pop()
        else:
            allowremote = self.data.get('allowremote', True)
            
        address = " ".join(self.data.get('address', self.args))
        return lookup_crypto_keys(self.session, address, event=self.event,
                                  allowremote=allowremote)

_plugins = PluginManager(builtin=__file__)
_plugins.register_commands(KeyLookup)


class LookupHandler:
    NAME = "NONE"
    LOCAL = False

    def __init__(self, session):
        self.session = session

    def _score(self, key):
        raise NotImplemented("Subclass and override _score")

    def _lookup(self, address):
        raise NotImplemented("Subclass and override _lookup")
Пример #29
0
    HTTP_QUERY_VARS = {
        'q': 'selectors',
        'no_public': 'omit public keys',
        'no_secret': 'omit secret keys'
    }
    COMMAND_SECURITY = security.CC_CHANGE_CONTACTS

    def command(self):
        session, config = self.session, self.session.config

        selectors = [a for a in self.args if not a.startswith('-')]
        selectors.extend(self.data.get('q', []))

        public = not (int(self.data.get('no_public', [0])[0]) or
                      '-no_public' in self.args)
        secret = not (int(self.data.get('no_secret', [0])[0]) or
                      '-no_secret' in self.args)

        imported = 0
        for cfg in config.prefs.vcard.importers.gpg:
            gimp = GnuPGImporter(session, cfg)
            imported += gimp.import_vcards(session, config.vcards,
                                           selectors=selectors)

        return self._success(_('Imported %d vCards from GPG keychain'
                               ) % imported, {'vcards': imported})


_plugins.register_commands(PGPKeysAsVCards, PGPKeysImportAsVCards)
_plugins.register_vcard_importers(GnuPGImporter)
Пример #30
0
                        if a['filename'].lower().endswith(cid[1:].lower())]
            else:
                cids = [cid]

            for c in cids:
                fn, info = e.extract_attachment(session, c,
                                                name_fmt=name_fmt, mode=mode)
                if info:
                    info['idx'] = e.msg_idx_pos
                    if fn:
                        info['created_file'] = fn
                    results.append(info)
        return results


_plugins.register_commands(Extract, Next, Order, Previous, Search, View)


##[ Search terms ]############################################################

def mailbox_search(config, idx, term, hits):
    word = term.split(':', 1)[1].lower()
    try:
        mbox_id = (('0' * MBX_ID_LEN) + b36(int(word, 36)))[-MBX_ID_LEN:]
    except ValueError:
        mbox_id = None

    mailboxes = [m for m in config.sys.mailbox.keys()
                 if (mbox_id == m) or word in config.sys.mailbox[m].lower()]
    rt = []
    for mbox_id in mailboxes:
Пример #31
0
                html = markdown(str(self.result['urlmap']))
            except:
                import traceback
                print traceback.format_exc()
                html = '<pre>%s</pre>' % escape_html(self.result['urlmap'])
            self.result['markdown'] = html
            return Command.CommandResult.as_html(self, *args, **kwargs)

    def command(self):
        prefix = self.args[0] if self.args else None
        return {'urlmap': UrlMap(self.session).map_as_markdown(prefix=prefix)}


plugin_manager = PluginManager(builtin=True)
if __name__ != "__main__":
    plugin_manager.register_commands(HelpUrlMap, UrlRedirect,
                                     UrlRedirectEdit, UrlRedirectThread)

else:
    # If run as a python script, print map and run doctests.
    import doctest
    import sys
    import mailpile.app
    import mailpile.config.defaults as defaults
    import mailpile.config.manager as cfg_manager
    import mailpile.plugins
    import mailpile.ui

    # Import all the default plugins
    from mailpile.plugins import *

    rules = defaults.CONFIG_RULES
Пример #32
0
                        skip = True
            if skip:
                continue

            results.append({
                'fid': fid,
                'terms': trms,
                'tags': tags,
                'human_tags': ' '.join(human_tags),
                'comment': cmnt,
                'type': ftype
            })
        return results


class MoveFilter(ListFilters):
    """Move an auto-tagging rule"""
    SYNOPSIS = (None, 'filter/move', None, '<filter-id> <position>')
    ORDER = ('Tagging', 1)
    HTTP_CALLABLE = ('POST', 'UPDATE')

    def command(self):
        self.session.config.filter_move(self.args[0], self.args[1])
        self.session.config.save()
        return ListFilters.command(self, want_fid=self.args[1])


_plugins.register_commands(Tag, AddTag, DeleteTag, ListTags,
                           Filter, DeleteFilter,
                           MoveFilter, ListFilters)
Пример #33
0
                    else:
                        tag[at_config.match_tag].append(mid)

                elif at_config.unsure_tag and want is None:
                    if at_config.unsure_tag not in tag:
                        tag[at_config.unsure_tag] = [mid]
                    else:
                        tag[at_config.unsure_tag].append(mid)

        for tid in tag:
            idx.add_tag(session, tid, msg_idxs=[int(i, 36) for i in tag[tid]])

        return self._success(_('Auto-tagged %d messages') % len(emails), tag)


_plugins.register_commands(Retrain, Classify, AutoTag)

##[ Keywords ]################################################################


def filter_hook(session, msg_mid, msg, keywords, **kwargs):
    """Classify this message."""
    if not kwargs.get('incoming', False):
        return keywords

    config = session.config
    for at_config in autotag_configs(config):
        try:
            at_tag = config.get_tag(at_config.match_tag)
            atagger = config.load_auto_tagger(at_config)
            if not atagger.trained:
Пример #34
0
            session, handle = self.session, vcard.nickname
            return (Filter(session, arg=['delete',
                                         'group:%s' % handle]).run()
                    and DeleteTag(session, arg=[handle]).run())

    return GroupVCardCommand


class Group(GroupVCard(VCard)):
    """View groups"""


class AddGroup(GroupVCard(AddVCard)):
    """Add groups"""


class GroupAddLines(GroupVCard(VCardAddLines)):
    """Add lines to a group VCard"""


class RemoveGroup(GroupVCard(RemoveVCard)):
    """Remove groups"""


class ListGroups(GroupVCard(ListVCards)):
    """Find groups"""


_plugins.register_commands(Group, AddGroup, GroupAddLines, RemoveGroup,
                           ListGroups)
Пример #35
0
                            if (rcpt != sender) and rcpt_keyid:
                                kb = gnupg.get_minimal_key(key_id=rcpt_keyid,
                                                           user_id=rcpt)
                                if kb:
                                    gossip_list.append(
                                        make_autocrypt_header(
                                            rcpt,
                                            kb,
                                            prefix='Autocrypt-Gossip'))
                        except (ValueError, IndexError):
                            pass
                    if len(gossip_list) > 1:
                        # No point gossiping peoples keys back to them alone.
                        for hdr in gossip_list:
                            msg.add_header('Autocrypt-Gossip', hdr)

                matched = True

        return sender, rcpts, msg, matched, True


_plugins.register_meta_kw_extractor('autocrypt', autocrypt_meta_kwe)
_plugins.register_commands(AutoCryptSearch, AutoCryptForget, AutoCryptParse,
                           AutoCryptPeers)

# Note: we perform our transformations BEFORE the GnuPG transformations
# (prio 500), so the memory hole transformation can take care of hiding
# the Autocrypt-Gossip headers.
_plugins.register_outgoing_email_content_transform('400_autocrypt',
                                                   AutoCryptTxf)
Пример #36
0
        # sense.
        if not flat:
            for i in reversed(range(0, len(msg_idxs))):
                mi = msg_idxs[i]
                msg_idxs[i:i+1] = [int(m[idx.MSG_MID], 36)
                                   for m in idx.get_conversation(msg_idx=mi)]

        # Let's always export in the same order. Stability is nice.
        msg_idxs.sort()

        mbox = self.create_mailbox(mbox_type, path)
        exported = {}
        while msg_idxs:
            msg_idx = msg_idxs.pop(0)
            if msg_idx not in exported:
                e = Email(idx, msg_idx)
                session.ui.mark('Exporting =%s ...' % e.msg_mid())
                mbox.add(e.get_msg())
                exported[msg_idx] = 1

        mbox.flush()

        return self._success(
            _('Exported %d messages to %s') % (len(exported), path),
            {
                'exported': len(exported),
                'created': path
            })

_plugins.register_commands(ExportMail)
Пример #37
0
        migrations = []
        for a in self.args:
            if a in MIGRATIONS:
                migrations.append(MIGRATIONS[a])
            else:
                raise UsageError(_('Unknown migration: %s (available: %s)'
                                   ) % (a, ', '.join(MIGRATIONS.keys())))

        if not migrations:
            migrations = ((before_setup and MIGRATIONS_BEFORE_SETUP or []) +
                          (after_setup and MIGRATIONS_AFTER_SETUP or []))

        for mig in migrations:
            try:
                if mig(session):
                    cnt += 1
                else:
                    err += 1
            except:
                self._ignore_exception()
                err += 1

        self.session.config.version = APPVER  # We've migrated to this!

        self._background_save(config=True)
        return self._success(_('Performed %d migrations, failed %d.'
                               ) % (cnt, err))


_plugins.register_commands(Migrate)
Пример #38
0
        else:
            password = self.session.ui.get_password(_('Enter your password:'******' ')

        if policy == 'store':
            if fingerprint in config.passphrases:
                del config.passphrases[fingerprint]
            config.secrets[fingerprint] = {
                'password': password,
                'policy': policy
            }
            return happy(_('Password stored permanently'))

        elif policy == 'cache-only' and password:
            from mailpile.config import SecurePassphraseStorage
            sps = SecurePassphraseStorage(password)
            sps.expiration = time.time() + float(ttl)
            config.passphrases[fingerprint] = sps
            if fingerprint.lower() in config.secrets:
                del config.secrets[fingerprint.lower()]
            return happy(_('Password stored temporarily'))

        else:
            return self._error(_('Invalid password policy!'), result)


plugin_manager = PluginManager(builtin=True)
plugin_manager.register_commands(Authenticate,
                                 DeAuthenticate,
                                 SetPassphrase)
Пример #39
0
        if 'send_keys' in cformat:
            send_keys = cls.ShouldAttachKey(
                config,
                vcards=[p[0] for p in policies],
                emails=[p[2] for p in policies if not p[0]])
        else:
            send_keys = False

        return {
          'reason': reason,
          'can-sign': can_sign,
          'can-encrypt': can_encrypt,
          'crypto-policy': policy,
          'crypto-format': cformat,
          'send-keys': send_keys,
          'addresses': dict([(e, AddressInfo(e, vc.fn if vc else e, vcard=vc))
                             for vc, k, e, p, f in policies if vc])
        }

    def command(self):
        emails = list(self.args) + self.data.get('email', [])
        if len(emails) < 1:
            return self._error('Please provide at least one email address!')

        result = self.crypto_policy(self.session, self._idx(), emails)
        return self._success(result['reason'], result=result)


_plugins.register_commands(CryptoPolicy, UpdateCryptoPolicyForUser)
Пример #40
0
    except KeyboardInterrupt:
        pass

    finally:
        if readline:
            readline.write_history_file(session.config.history_file())

        # Make everything in the background quit ASAP...
        mailpile.util.LAST_USER_ACTIVITY = 0
        mailpile.util.QUITTING = True

        if config.plugins:
            config.plugins.process_shutdown_hooks()
        if config.loaded_config:
            config.flush_mbox_cache(session, wait=True)

        config.stop_workers()
        if config.index:
            config.index.save_changes()
        if config.event_log:
            config.event_log.close()

        if session.interactive and config.sys.debug:
            session.ui.display_result(Action(session, 'ps', ''))


_plugins.register_commands(InteractCommand, WaitCommand)

if __name__ == "__main__":
    Main(sys.argv[1:])
Пример #41
0
    """De-authenticate a user (log out)"""
    SYNOPSIS = (None, 'logout', 'auth/logout', '[<session ID>]')
    ORDER = ('Internals', 5)
    SPLIT_ARG = False
    IS_INTERACTIVE = True
    CONFIG_REQUIRED = False
    HTTP_AUTH_REQUIRED = False
    HTTP_CALLABLE = ('GET', 'POST')

    def command(self):
        # FIXME: Should this only be a POST request?
        # FIXME: This needs CSRF protection.

        session_id = self.session.ui.html_variables.get('http_session')
        if self.args and not session_id:
            session_id = self.args[0]

        if session_id:
            try:
                self.session.ui.debug('Logging out %s' % session_id)
                del SESSION_CACHE[session_id]
                return self._success(_('Goodbye!'))
            except KeyError:
                pass

        return self._error(_('No session found!'))


plugin_manager = PluginManager(builtin=True)
plugin_manager.register_commands(Authenticate, DeAuthenticate)
Пример #42
0
            sock  = org_sslwrap(sock, *args, **kwargs)
            Master.get_fd_context(
                sock.fileno()).encryption = _explain_encryption(sock)
        return sock

    ssl.wrap_socket = SslWrapOnlyOnce

    if have_ssl_context:
        # Same again with SSLContext, if we have it.

        def SslContextWrapOnlyOnce(self, sock, *args, **kwargs):
            if not isinstance(sock, ssl.SSLSocket):
                sock = org_context_wrap_socket(self, sock, *args, **kwargs)
                Master.get_fd_context(
                    sock.fileno()).encryption = _explain_encryption(sock)
            return sock

        ssl.SSLContext.wrap_socket = SslContextWrapOnlyOnce

    from mailpile.plugins import PluginManager
    _plugins = PluginManager(builtin=__file__)
    _plugins.register_commands(NetworkHistory)
else:
    import doctest
    import sys
    results = doctest.testmod(optionflags=doctest.ELLIPSIS,
                              extraglobs={})
    print '%s' % (results, )
    if results.failed:
        sys.exit(1)
Пример #43
0
    def command(self):
        if len(self.args) > 1:
            allowremote = self.args.pop()
        else:
            allowremote = self.data.get('allowremote', True)

        address = " ".join(self.data.get('address', self.args))
        return lookup_crypto_keys(self.session,
                                  address,
                                  event=self.event,
                                  allowremote=allowremote)


_plugins = PluginManager(builtin=__file__)
_plugins.register_commands(KeyLookup)


class LookupHandler:
    NAME = "NONE"
    LOCAL = False

    def __init__(self, session):
        self.session = session

    def _score(self, key):
        raise NotImplemented("Subclass and override _score")

    def _lookup(self, address):
        raise NotImplemented("Subclass and override _lookup")
Пример #44
0
        return self._success(_('Loaded plugins: %s') % ', '.join(self.args),
                             {'loaded': self.args})


class DisablePlugin(mailpile.commands.Command):
    """Disable a plugin."""
    SYNOPSIS = (None, 'plugins/disable', 'plugins/disable', '<plugin>')
    ORDER = ('Config', 9)

    def command(self):
        config = self.session.config
        plugins = config.plugins
        for plugin in self.args:
            if plugin in plugins.REQUIRED:
                return self._error(_('Required plugins can not be disabled: %s'
                                     ) % plugin)
            if plugin not in config.sys.plugins:
                return self._error(_('Plugin not loaded: %s') % plugin)

        for plugin in self.args:
            while plugin in config.sys.plugins:
                config.sys.plugins.remove(plugin)

        self._serialize('Save config', lambda: config.save())
        return self._success(_('Disabled plugins: %s (restart required)'
                               ) % ', '.join(self.args),
                             {'disabled': self.args})


_plugins.register_commands(Plugins, LoadPlugin, DisablePlugin)
Пример #45
0
            if skip:
                continue

            results.append({
                'fid': fid,
                'terms': trms,
                'tags': tags,
                'human_tags': ' '.join(human_tags),
                'comment': cmnt,
                'type': ftype
            })
        return results


class MoveFilter(ListFilters):
    """Move an auto-tagging rule"""
    SYNOPSIS = (None, 'filter/move', None, '<filter-id> <position>')
    ORDER = ('Tagging', 1)
    HTTP_CALLABLE = ('POST', 'UPDATE')

    def command(self):
        self.session.config.filter_move(self.args[0], self.args[1])
        self._background_save(config=True)
        return ListFilters.command(self, want_fid=self.args[1])


_plugins.register_commands(Tag, TagLater, TagTemporarily,
                           AddTag, DeleteTag, ListTags,
                           Filter, DeleteFilter,
                           MoveFilter, ListFilters)
Пример #46
0
                    session.config.prefs.crypto_policy = 'openpgp-sign'

            if len(accepted_keys) == 0:
                # FIXME: Start background process generating a key once a user
                #        has supplied a name and e-mail address.
                pass

        else:
            session.ui.warning(_('Oh no, PGP/GPG support is unavailable!'))

        if (session.config.prefs.gpg_recipient
                and not (self._idx() and self._idx().INDEX)
                and not session.config.prefs.obfuscate_index):
            randcrap = sha512b64(
                open('/dev/urandom').read(1024),
                session.config.prefs.gpg_recipient, '%s' % time.time())
            session.config.prefs.obfuscate_index = randcrap
            session.config.prefs.index_encrypted = True
            session.ui.notify(
                _('Obfuscating search index and enabling '
                  'indexing of encrypted e-mail. '))

        # Perform any required migrations
        Migrate(session).run(before_setup=False, after_setup=True)

        session.config.save()
        return self._success(_('Performed initial Mailpile setup'))


_plugins.register_commands(Setup)
Пример #47
0
        session, idx, _, _ = self._do_search(search=["from:%s" % addr, 
            "has:pgp"])
        pgp = 0
        for messageid in session.results:
            pgp += 1

        if total > 0:
            ratio = float(pgp)/total
        else:
            ratio = 0

        res = {"messages": total, 
               "pgpsigned": pgp, 
               "ratio": ratio,
               "address": addr}

        return self._success("Got statistics for address", res)




_plugins.register_commands(GPGKeySearch)
_plugins.register_commands(GPGKeyReceive)
_plugins.register_commands(GPGKeyImport)
_plugins.register_commands(GPGKeyImportFromMail)
_plugins.register_commands(GPGKeySign)
_plugins.register_commands(GPGKeyList)
_plugins.register_commands(GPGUsageStatistics)
_plugins.register_commands(GPGKeyListSecret)
Пример #48
0
        migrations = []
        for a in self.args:
            if a in MIGRATIONS:
                migrations.append(MIGRATIONS[a])
            else:
                raise UsageError(
                    _('Unknown migration: %s (available: %s)') %
                    (a, ', '.join(MIGRATIONS.keys())))

        if not migrations:
            migrations = ((before_setup and MIGRATIONS_BEFORE_SETUP or []) +
                          (after_setup and MIGRATIONS_AFTER_SETUP or []))

        for mig in migrations:
            try:
                if mig(session):
                    cnt += 1
                else:
                    err += 1
            except:
                self._ignore_exception()
                err += 1

        if cnt:
            session.config.save()
        return self._success(
            _('Performed %d migrations, failed %d.') % (cnt, err))


_plugins.register_commands(Migrate)
Пример #49
0
        if url[:6].lower() == 'https:':
            conn_need = [ConnBroker.OUTGOING_HTTP]
        elif url[:5].lower() == 'http:':
            conn_need = [ConnBroker.OUTGOING_HTTPS]
        else:
            raise AccessError('Invalid URL scheme')

        try:
            with ConnBroker.context(need=conn_need, reject=conn_reject) as ctx:
                session.ui.mark('Getting: %s' % url)
                response = urlopen(url, data=None, timeout=timeout)
        except HTTPError, e:
            response = e

        data = response.read()
        headers = response.headers
        contenttype = headers.get('content-type', 'application/octet-stream')

        request = html_variables['http_request']
        request.send_http_response(response.code, response.msg)
        request.send_standard_headers(mimetype=contenttype,
                                      header_list=[('Content-Length',
                                                    len(data))])
        request.wfile.write(data)
        request.send_full_response(response.code, response.msg)

        raise SuppressHtmlOutput()


_plugins.register_commands(JsApi, HttpProxyGetRequest)
Пример #50
0
        # Messages no longer in the outbox get their events canceled...
        if cfg.event_log:
            events = cfg.event_log.incomplete(source='.plugins.compose.Sendit')
            for ev in events:
                if ('mid' in ev.data and
                        ('=%s' % ev.data['mid']) not in messages):
                    ev.flags = ev.COMPLETE
                    ev.message = _('Sending cancelled.')
                    cfg.event_log.log_event(ev)

        # Send all the mail!
        if messages:
            self.args = tuple(set(messages))
            return Sendit.command(self)
        else:
            return self._success(_('The outbox is empty'))


_plugins.register_config_variables('prefs', {
    'empty_outbox_interval': [_('Delay between attempts to send mail'),
                              int, 10]
})
_plugins.register_fast_periodic_job('sendmail',
                                    'prefs.empty_outbox_interval',
                                    EmptyOutbox.sendmail)
_plugins.register_commands(Compose, Reply, Forward,           # Create
                           Draft, Update, Attach, UnAttach,   # Manipulate
                           UnThread,                          # ...
                           Sendit, UpdateAndSendit,           # Send
                           EmptyOutbox)                       # ...
Пример #51
0
                serious += 1

        if len(good_keys) == 0:
            fixes[:0] = [
                self._fix_gen_key(min_bits=self.MIN_KEYSIZE),
                self._fix_mp_config()
            ]

        if quiet and not serious:
            return self._success('OK')

        ret = self._error if serious else self._success
        return ret(_('Sanity checked: %d keys in GPG keyring, %d profiles') %
                   (len(secret_keys), len(profiles)),
                   result={
                       'passed': not serious,
                       'details': details,
                       'fixes': fixes
                   })


_plugins.register_commands(GPGKeySearch)
_plugins.register_commands(GPGKeyReceive)
_plugins.register_commands(GPGKeyImport)
_plugins.register_commands(GPGKeyImportFromMail)
_plugins.register_commands(GPGKeySign)
_plugins.register_commands(GPGKeyList)
_plugins.register_commands(GPGUsageStatistics)
_plugins.register_commands(GPGKeyListSecret)
_plugins.register_commands(GPGCheckKeys)
Пример #52
0
            [m for m in self.args if '@' not in m] +
            ['=%s' % mid for mid in self.data.get('mid', [])]
        )
        for msg_idx_pos in messages:
            try:
                msg_info = idx.get_msg_at_idx_pos(msg_idx_pos)
                msg_emails = (idx.expand_to_list(msg_info, field=idx.MSG_TO) +
                              idx.expand_to_list(msg_info, field=idx.MSG_CC))
                emails.extend(msg_emails)
                if 'no_from' not in self.data:
                    emails.append(msg_info[idx.MSG_FROM])
            except ValueError:
                pass

        addrs = [ai for ee in emails
                 for ai in AddressHeaderParser(unicode_data=ee)]
        return self._success(_('Choosing from address'), result={
            'emails': addrs,
            'from': vcards.choose_from_address(self.session.config, addrs)
        })



_plugins.register_commands(VCard, AddVCard, RemoveVCard, ListVCards,
                           VCardAddLines, VCardRemoveLines)
_plugins.register_commands(Contact, AddContact, RemoveContact, ListContacts,
                           AddressSearch)
_plugins.register_commands(Profile, AddProfile, RemoveProfile, ListProfiles,
                           ChooseFromAddress)
_plugins.register_commands(ContactImport, ContactImporters)
Пример #53
0
                        config.sys.gpg_home = os_gpg_home
                        config.sys.gpg_binary = os_gpg_binary
                        config.sys.http_port = os_http_port
                        config.sys.minfree_mb = os_minfree_mb

                    self._restore_PGP_keys(
                        config, backup_zip,
                        self.data.get('keychain', ['shared'])[0])

                    self._adjust_paths(config)

                    config.prepare_workers(session, daemons=True)
                    message = _('Backup restored')
                    results['restored'] = True
                    AVAILABLE_BACKUPS = {}
                else:
                    message = _('Backup validated, restoration is possible')
                    AVAILABLE_BACKUPS[backup_date] = backup_data

            except (ValueError, KeyError, zipfile.BadZipfile, IOError):
                traceback.print_exc()
                return self._error('Incomplete, invalid or corrupt backup')
        else:
            message = _('Restore from backup')

        results['available'] = AVAILABLE_BACKUPS.keys()
        return self._success(message, result=results)


_plugins.register_commands(MakeBackup, RestoreBackup)
Пример #54
0
        'imap_port': 993,
        'imap_tls': True,
        'pop3_host': 'pop3.wigglebonk.com',
        'pop3_port': 110,
        'pop3_tls': False,
        'smtp_host': 'smtp.wigglebonk.com',
        'smtp_port': 465,
        'smtp_tls': False
    }

    def _get_domain_settings(self, domain):
        raise Exception('FIXME')

    def setup_command(self, session):
        results = {}
        for email in list(self.args) + self.data.get('email'):
            settings = self._testing_data(self._get_domain_settings,
                                          self.TEST_DATA, email)
            if settings:
                results[email] = settings
        if results:
            self._success(_('Found settings for %d addresses'), results)
        else:
            self._error(_('No settings found'))


_plugins.register_commands(Setup,
                           SetupCheckKeychain, SetupCreateNewKey,
                           SetupGuessEmails, SetupTestEmailSettings,
                           Setup)
Пример #55
0
        self.quitting = True
        if join:
            try:
                self.join()
            except RuntimeError:
                pass


class HashCash(Command):
    """Try to collide a hash using the SMTorP algorithm"""
    SYNOPSIS = (None, 'hashcash', None, '<bits> <challenge>')
    ORDER = ('Internals', 9)
    HTTP_CALLABLE = ()
    COMMAND_SECURITY = security.CC_CPU_INTENSIVE

    def command(self):
        bits, challenge = int(self.args[0]), self.args[1]
        expected = 2 ** bits
        def marker(counter):
            progress = ((1024.0 * counter) / expected) * 100
            self.session.ui.mark('Finding a {0:d}-bit collision for {1!s} ({2:d}%)'.format(bits, challenge, progress))
        collision = sha512_512kCollide(challenge, bits, callback1k=marker)
        return self._success({
            'challenge': challenge,
            'collision': collision
        })


_plugins.register_worker(SMTPWorker)
_plugins.register_commands(HashCash)
Пример #56
0
    HTTP_QUERY_VARS = {
        'q': 'selectors',
        'no_public': 'omit public keys',
        'no_secret': 'omit secret keys'
    }
    COMMAND_SECURITY = security.CC_CHANGE_CONTACTS

    def command(self):
        session, config = self.session, self.session.config

        selectors = [a for a in self.args if not a.startswith('-')]
        selectors.extend(self.data.get('q', []))

        public = not (int(self.data.get('no_public', [0])[0]) or
                      '-no_public' in self.args)
        secret = not (int(self.data.get('no_secret', [0])[0]) or
                      '-no_secret' in self.args)

        imported = 0
        for cfg in config.prefs.vcard.importers.gpg:
            gimp = GnuPGImporter(session, cfg)
            imported += gimp.import_vcards(session, config.vcards,
                                           selectors=selectors)

        return self._success(_('Imported %d vCards from GPG keychain'
                               ) % imported, {'vcards': imported})


_plugins.register_commands(PGPKeysAsVCards, PGPKeysImportAsVCards)
_plugins.register_vcard_importers(GnuPGImporter)
Пример #57
0
                from markdown import markdown
                html = markdown(str(self.result['urlmap']))
            except:
                import traceback
                print traceback.format_exc()
                html = '<pre>%s</pre>' % escape_html(self.result['urlmap'])
            self.result['markdown'] = html
            return Command.CommandResult.as_html(self, *args, **kwargs)

    def command(self):
        return {'urlmap': UrlMap(self.session).map_as_markdown()}


plugin_manager = PluginManager(builtin=True)
if __name__ != "__main__":
    plugin_manager.register_commands(HelpUrlMap, UrlRedirect, UrlRedirectEdit,
                                     UrlRedirectThread)

else:
    # If run as a python script, print map and run doctests.
    import doctest
    import sys
    import mailpile.app
    import mailpile.config
    import mailpile.plugins.tags
    import mailpile.plugins.search
    import mailpile.plugins.compose
    import mailpile.plugins.contacts
    import mailpile.defaults
    import mailpile.plugins
    import mailpile.ui