Пример #1
0
  def evaluate_pgp(self, tree, check_sigs=True, decrypt=False):
    pgpdata = []
    for part in tree['text_parts']:

      # Handle signed messages
      if check_sigs and GnuPG:
        if part['type'] == 'pgpbeginsigned':
          pgpdata = [part]
        elif part['type'] == 'pgpsignedtext':
          pgpdata.append(part)
        elif part['type'] == 'pgpsignature':
          pgpdata.append(part)
          try:
            message = ''.join([p['data'].encode(p['charset']) for p in pgpdata])
            gpg = GnuPG().run(['--utf8-strings', '--verify'],
                              create_fhs=['stdin', 'stderr'])
            gpg.handles['stdin'].write(message)
            gpg.handles['stdin'].close()
            result = ''
            for fh in ('stderr', ):
              result += gpg.handles[fh].read()
              gpg.handles[fh].close()
            gpg.wait()
            pgpdata[0]['data'] = result.decode('utf-8')
            for p in pgpdata:
              p['type'] = self.PGP_OK.get(p['type'], p['type'])
          except IOError:
            part['data'] += result.decode('utf-8')
          except:
            part['data'] += traceback.format_exc()

      # FIXME: Handle encrypted messages
      if decrypt:
        pass
Пример #2
0
  def evaluate_pgp(self, tree, check_sigs=True, decrypt=False):
    pgpdata = []
    for part in tree['text_parts']:

      # Handle signed messages
      if check_sigs and GnuPG:
        if part['type'] == 'pgpbeginsigned':
          pgpdata = [part]
        elif part['type'] == 'pgpsignedtext':
          pgpdata.append(part)
        elif part['type'] == 'pgpsignature':
          pgpdata.append(part)
          try:
            message = ''.join([p['data'].encode(p['charset']) for p in pgpdata])
            gpg = GnuPG().run(['--utf8-strings', '--verify'],
                              create_fhs=['stdin', 'stderr'])
            gpg.handles['stdin'].write(message)
            gpg.handles['stdin'].close()
            result = ''
            for fh in ('stderr', ):
              result += gpg.handles[fh].read()
              gpg.handles[fh].close()
            gpg.wait()
            pgpdata[0]['data'] = result.decode('utf-8')+'\n'
            for p in pgpdata:
              p['type'] = self.PGP_OK.get(p['type'], p['type'])
          except IOError:
            part['data'] += result.decode('utf-8')
          except:
            part['data'] += traceback.format_exc()
          pgpdata = []

      if decrypt and GnuPG:
        if part['type'] in ('pgpbegin', 'pgptext'):
          pgpdata.append(part)
        elif part['type'] == 'pgpend':
          pgpdata.append(part)
          try:
            message = ''.join([p['data'] for p in pgpdata])
            gpg = GnuPG().run(['--utf8-strings'],
                              create_fhs=['stdin', 'stdout', 'stderr'])
            gpg.handles['stdin'].write(message)
            gpg.handles['stdin'].close()
            results = {}
            for fh in ('stderr', 'stdout'):
              results[fh] = gpg.handles[fh].read()
              gpg.handles[fh].close()
            gpg.wait()
            pgpdata[0]['data'] = results['stderr'].decode('utf-8')+'\n'
            pgpdata[1]['data'] = self._decode_gpg(message, results['stdout'])
            for p in pgpdata:
              p['type'] = self.PGP_OK.get(p['type'], p['type'])
          except IOError:
            part['data'] += results['stderr'].decode('utf-8')
          except:
            part['data'] += traceback.format_exc()
          pgpdata = []

    return tree
Пример #3
0
    def list_keys(self):
        """Get a list of available PGP public keys."""

        session, config = self.session, self.session.config
        keys = []
        try:
            session.ui.mark("Listing available GPG keys")
            gpg = GnuPG().run(["--list-keys", "--fingerprint"], create_fhs=["stderr", "stdout"])
            keylines = gpg.handles["stdout"].readlines()
            curkey = {}
            for line in keylines:
                if line[0:3] == "pub":
                    if curkey != {}:
                        keys.append(curkey)
                        curkey = {}
                    args = line.split("pub")[1].strip().split(" ")
                    if len(args) == 3:
                        expiry = args[2]
                    else:
                        expiry = None
                    keytype, keyid = args[0].split("/")
                    created = args[1]
                    curkey["subkeys"] = []
                    curkey["uids"] = []
                    curkey["pub"] = {"keyid": keyid, "type": keytype, "created": created, "expires": expiry}
                elif line[0:3] == "sec":
                    if curkey != {}:
                        keys.append(curkey)
                        curkey = {}
                    args = line.split("pub")[1].strip().split(" ")
                    if len(args) == 3:
                        expiry = args[2]
                    else:
                        expiry = None
                    keytype, keyid = args[0].split("/")
                    created = args[1]
                    curkey["subkeys"] = []
                    curkey["uids"] = []
                    curkey["sec"] = {"keyid": keyid, "type": keytype, "created": created, "expires": expiry}
                elif line[0:3] == "uid":
                    curkey["uids"].append(line.split("uid")[1].strip())
                elif line[0:3] == "sub":
                    args = line.split("sub")[1].strip().split(" ")
                    if len(args) == 3:
                        expiry = args[2]
                    else:
                        expiry = None
                    keytype, keyid = args[0].split("/")
                    created = args[1]
                    curkey["subkeys"].append({"keyid": keyid, "type": keytype, "created": created, "expires": expiry})
                elif line[0:24] == "      Key fingerprint = ":
                    line = line.strip("      Key fingerprint = ").strip().replace(" ", "")
                    curkey["fingerprint"] = line
            gpg.handles["stderr"].close()
            gpg.handles["stdout"].close()
            gpg.wait()
            return keys
        except IndexError, e:
            self._ignore_exception()
Пример #4
0
  def list_keys(self):
    """Get a list of available PGP public keys."""

    session, config = self.session, self.session.config
    keys = []
    try:
      session.ui.mark('Listing available GPG keys')
      gpg = GnuPG().run(['--list-keys'], create_fhs=['stderr', 'stdout'])
      keylines = gpg.handles['stdout'].readlines()
      curkey = {}
      for line in keylines:
        if line[0:3] == "pub":
          if curkey != {}:
            keys.append(curkey)
            curkey = {}
          args = line.split("pub")[1].strip().split(" ")
          if len(args) == 3:
            expiry = args[2]
          else:
            expiry = None
          keytype, keyid = args[0].split("/")
          created = args[1]
          curkey["subkeys"] = []
          curkey["uids"] = []
          curkey["pub"] = {"keyid": keyid, "type": keytype, "created": created, "expires": expiry}
        elif line[0:3] == "sec":
          if curkey != {}:
            keys.append(curkey)
            curkey = {}
          args = line.split("pub")[1].strip().split(" ")
          if len(args) == 3:
            expiry = args[2]
          else:
            expiry = None
          keytype, keyid = args[0].split("/")
          created = args[1]
          curkey["subkeys"] = []
          curkey["uids"] = []
          curkey["sec"] = {"keyid": keyid, "type": keytype, "created": created, "expires": expiry}
        elif line[0:3] == "uid":
          curkey["uids"].append(line.split("uid")[1].strip())
        elif line[0:3] == "sub":
          args = line.split("sub")[1].strip().split(" ")
          if len(args) == 3:
            expiry = args[2]
          else:
            expiry = None
          keytype, keyid = args[0].split("/")
          created = args[1]
          curkey["subkeys"].append({"keyid": keyid, "type": keytype, "created": created, "expires": expiry})
      gpg.handles['stderr'].close()
      gpg.handles['stdout'].close()
      gpg.wait()
      session.ui.display_gpg_keys(keys)
    except IndexError, e:
      self._ignore_exception()
Пример #5
0
  def parse_pgpmime(self, message):
    sig_count, sig_parts, sig_alg = 0, [], 'SHA1'
    enc_count, enc_parts, enc_ver = 0, [], None

    for part in message.walk():
      mimetype = part.get_content_type()

      if (sig_count > 1) and (mimetype == 'application/pgp-signature'):
        sig = tempfile.NamedTemporaryFile()
        sig.write(part.get_payload())
        sig.flush()
        msg = '\r\n'.join(sig_parts[0].as_string().splitlines(False))+'\r\n'

        result = None
        try:
          gpg = GnuPG().run(['--utf8-strings', '--verify', sig.name, '-'],
                            create_fhs=['stdin', 'stderr'])
          gpg.handles['stdin'].write(msg)
          gpg.handles['stdin'].close()
          result = gpg.handles['stderr'].read().decode('utf-8')
          gpg.wait()
          summary = ('verified', result)
        except IOError:
          if not result:
            summary = ('signed', 'Error running GnuPG')
          else:          
            reslines = [g.split("gpg: ")[1] for g in result.strip().split("\n")]
            matchgr = re.match(".*made (.*) using (.*) key ID ([a-zA-Z0-9]{8}).*", reslines[0])
            keyid = matchgr.groups()[2]
            keytype = matchgr.groups()[1]
            datetime = matchgr.groups()[0]

            # FIXME: This should understand what kind of UI we have.
            summary = ('signed', "Signed %s with %s key 0x%s (<a onclick=\"mailpile.gpgrecvkey('%s');\">fetch key</a>)" 
              % (datetime, keytype, keyid, keyid))

        for sig_part in sig_parts:
          sig_part.openpgp = summary

        # Reset!
        sig_count, sig_parts = 0, []

      elif sig_count > 0:
          sig_parts.append(part)
          sig_count += 1

      elif enc_count > 0:
        # FIXME: Decrypt and parse!
        pass

      elif mimetype == 'multipart/signed':
        sig_alg = part.get_param('micalg', 'pgp-sha1').split('-')[1].upper()
        sig_count = 1

      elif mimetype == 'multipart/encrypted':
        enc_count = 1
Пример #6
0
 def recv_key(self):
   session, config, arg = self.session, self.session.config, self.args[0]
   try:
     session.ui.mark('Invoking GPG to fetch key %s' % arg)
     keyserver = config.get('gpg_keyserver', 'pool.sks-keyservers.net')
     gpg = GnuPG().run(['--utf8-strings',
                        '--keyserver', keyserver,
                        '--recv-key', arg], create_fhs=['stderr'])
     session.ui.debug(gpg.handles['stderr'].read().decode('utf-8'))
     gpg.handles['stderr'].close()
     gpg.wait()
     session.ui.mark('Fetched key %s' % arg)
   except IOError:
     return self._error('Failed to fetch key %s' % arg)
   return True
Пример #7
0
    def recv_key(self):
        """Fetch a PGP public key from a keyserver."""

        session, config, arg = self.session, self.session.config, self.args[0]
        try:
            session.ui.mark("Invoking GPG to fetch key %s" % arg)
            keyserver = config.get("gpg_keyserver", "pool.sks-keyservers.net")
            gpg = GnuPG().run(["--utf8-strings", "--keyserver", keyserver, "--recv-key", arg], create_fhs=["stderr"])
            session.ui.debug(gpg.handles["stderr"].read().decode("utf-8"))
            gpg.handles["stderr"].close()
            gpg.wait()
            session.ui.mark("Fetched key %s" % arg)
        except IOError:
            return self._error("Failed to fetch key %s" % arg)
        return True
Пример #8
0
    def parse_pgpmime(self, message):
        sig_count, sig_parts, sig_alg = 0, [], 'SHA1'
        enc_count, enc_parts, enc_ver = 0, [], None

        for part in message.walk():
            mimetype = part.get_content_type()

            if (sig_count > 1) and (mimetype == 'application/pgp-signature'):
                sig = tempfile.NamedTemporaryFile()
                sig.write(part.get_payload())
                sig.flush()
                msg = '\r\n'.join(
                    sig_parts[0].as_string().splitlines(False)) + '\r\n'

                result = None
                try:
                    gpg = GnuPG().run(
                        ['--utf8-strings', '--verify', sig.name, '-'],
                        create_fhs=['stdin', 'stderr'])
                    gpg.handles['stdin'].write(msg)
                    gpg.handles['stdin'].close()
                    result = gpg.handles['stderr'].read().decode('utf-8')
                    gpg.wait()
                    summary = ('verified', result)
                except IOError:
                    summary = ('signed', result or 'Error running GnuPG')

                for sig_part in sig_parts:
                    sig_part.openpgp = summary

                # Reset!
                sig_count, sig_parts = 0, []

            elif sig_count > 0:
                sig_parts.append(part)
                sig_count += 1

            elif enc_count > 0:
                # FIXME: Decrypt and parse!
                pass

            elif mimetype == 'multipart/signed':
                sig_alg = part.get_param('micalg',
                                         'pgp-sha1').split('-')[1].upper()
                sig_count = 1

            elif mimetype == 'multipart/encrypted':
                enc_count = 1
Пример #9
0
  def parse_pgpmime(self, message):
    sig_count, sig_parts, sig_alg = 0, [], 'SHA1'
    enc_count, enc_parts, enc_ver = 0, [], None

    for part in message.walk():
      mimetype = part.get_content_type()

      if (sig_count > 1) and (mimetype == 'application/pgp-signature'):
        sig = tempfile.NamedTemporaryFile()
        sig.write(part.get_payload())
        sig.flush()
        msg = '\r\n'.join(sig_parts[0].as_string().splitlines(False))+'\r\n'

        result = None
        try:
          gpg = GnuPG().run(['--utf8-strings', '--verify', sig.name, '-'],
                            create_fhs=['stdin', 'stderr'])
          gpg.handles['stdin'].write(msg)
          gpg.handles['stdin'].close()
          result = gpg.handles['stderr'].read().decode('utf-8')
          gpg.wait()
          summary = ('verified', result)
        except IOError:
          summary = ('signed', result or 'Error running GnuPG')

        for sig_part in sig_parts:
          sig_part.openpgp = summary

        # Reset!
        sig_count, sig_parts = 0, []

      elif sig_count > 0:
          sig_parts.append(part)
          sig_count += 1

      elif enc_count > 0:
        # FIXME: Decrypt and parse!
        pass

      elif mimetype == 'multipart/signed':
        sig_alg = part.get_param('micalg', 'pgp-sha1').split('-')[1].upper()
        sig_count = 1

      elif mimetype == 'multipart/encrypted':
        enc_count = 1
Пример #10
0
    def recv_key(self):
        """Fetch a PGP public key from a keyserver."""

        session, config, arg = self.session, self.session.config, self.args[0]
        try:
            session.ui.mark('Invoking GPG to fetch key %s' % arg)
            keyserver = config.get('gpg_keyserver', 'pool.sks-keyservers.net')
            gpg = GnuPG().run([
                '--utf8-strings', '--keyserver', keyserver, '--recv-key', arg
            ],
                              create_fhs=['stderr'])
            session.ui.debug(gpg.handles['stderr'].read().decode('utf-8'))
            gpg.handles['stderr'].close()
            gpg.wait()
            session.ui.mark('Fetched key %s' % arg)
        except IOError:
            return self._error('Failed to fetch key %s' % arg)
        return True
Пример #11
0
    def parse_pgpmime(self, message):
        sig_count, sig_parts, sig_alg = 0, [], "SHA1"
        enc_count, enc_parts, enc_ver = 0, [], None

        for part in message.walk():
            mimetype = part.get_content_type()
            if (sig_count > 1) and (mimetype == "application/pgp-signature"):
                sig = tempfile.NamedTemporaryFile()
                sig.write(part.get_payload())
                sig.flush()
                msg = "\r\n".join(sig_parts[0].as_string().splitlines(False)) + "\r\n"

                result = None
                try:
                    gpg = GnuPG().run(["--utf8-strings", "--verify", sig.name, "-"], create_fhs=["stdin", "stderr"])
                    gpg.handles["stdin"].write(msg)
                    gpg.handles["stdin"].close()
                    result = gpg.handles["stderr"].read().decode("utf-8")
                    gpg.wait()
                    summary = ("verified", result)
                except IOError:
                    if not result:
                        summary = ("signed", "Error running GnuPG")
                    else:
                        reslines = [g.split("gpg: ")[1] for g in result.strip().split("\n")]
                        matchgr = re.match(".*made (.*) using (.*) key ID ([a-zA-Z0-9]{8}).*", reslines[0])
                        keyid = matchgr.groups()[2]
                        keytype = matchgr.groups()[1]
                        datetime = matchgr.groups()[0]

                        # FIXME: This should understand what kind of UI we have.
                        summary = (
                            "signed",
                            "Signed %s with %s key 0x%s (<a onclick=\"mailpile.gpgrecvkey('%s');\">fetch key</a>)"
                            % (datetime, keytype, keyid, keyid),
                        )

                for sig_part in sig_parts:
                    sig_part.openpgp = summary

                # Reset!
                sig_count, sig_parts = 0, []

            elif sig_count > 0:
                sig_parts.append(part)
                sig_count += 1

            elif enc_count > 0 and (mimetype == "application/octet-stream"):
                # FIXME: Decrypt and parse!
                crypt = tempfile.NamedTemporaryFile()
                crypt.write(part.get_payload())
                crypt.flush()
                msg = "\r\n".join(part.as_string().splitlines(False)) + "\r\n"
                print msg

                result = None
                try:
                    gpg = GnuPG().run(["--utf8-strings", "--decrypt"], create_fhs=["stdin", "stdout", "stderr"])
                    gpg.handles["stdin"].write(msg)
                    gpg.handles["stdin"].close()
                    result = gpg.handles["stdout"].read().decode("utf-8")
                    gpg.wait()
                    print "Decrypted:"
                    print result
                    summary = ("decrypted", result)
                    # part.attach(result)
                    s = StringIO.StringIO()
                    s.write(result)
                    m = Parser().parse(s)
                    print m
                    m = Message()
                    m.set_payload(result)
                    part.set_payload([m])
                    # print part.__module__
                    # enc_parts.append(part)
                except IOError:
                    if not result:
                        summary = ("encrypted", "Error running GnuPG")
                    else:
                        # reslines = [g.split("gpg: ")[1] for g in result.strip().split("\n")]
                        # matchgr = re.match(".*made (.*) using (.*) key ID ([a-zA-Z0-9]{8}).*", reslines[0])
                        # keyid = matchgr.groups()[2]
                        # keytype = matchgr.groups()[1]
                        # datetime = matchgr.groups()[0]

                        # FIXME: This should understand what kind of UI we have.
                        print "FAIL"
                        summary = ("encrypted", result)

                for enc_part in enc_parts:
                    enc_part.openpgp = summary

                # Reset!
                enc_count, enc_parts = 0, []
            elif mimetype == "multipart/signed":
                sig_alg = part.get_param("micalg", "pgp-sha1").split("-")[1].upper()
                sig_count = 1

            elif mimetype == "multipart/encrypted":
                enc_count = 1
Пример #12
0
    def list_keys(self):
        """Get a list of available PGP public keys."""

        session, config = self.session, self.session.config
        keys = []
        try:
            session.ui.mark('Listing available GPG keys')
            gpg = GnuPG().run(['--list-keys'], create_fhs=['stderr', 'stdout'])
            keylines = gpg.handles['stdout'].readlines()
            curkey = {}
            for line in keylines:
                if line[0:3] == "pub":
                    if curkey != {}:
                        keys.append(curkey)
                        curkey = {}
                    args = line.split("pub")[1].strip().split(" ")
                    if len(args) == 3:
                        expiry = args[2]
                    else:
                        expiry = None
                    keytype, keyid = args[0].split("/")
                    created = args[1]
                    curkey["subkeys"] = []
                    curkey["uids"] = []
                    curkey["pub"] = {
                        "keyid": keyid,
                        "type": keytype,
                        "created": created,
                        "expires": expiry
                    }
                elif line[0:3] == "sec":
                    if curkey != {}:
                        keys.append(curkey)
                        curkey = {}
                    args = line.split("pub")[1].strip().split(" ")
                    if len(args) == 3:
                        expiry = args[2]
                    else:
                        expiry = None
                    keytype, keyid = args[0].split("/")
                    created = args[1]
                    curkey["subkeys"] = []
                    curkey["uids"] = []
                    curkey["sec"] = {
                        "keyid": keyid,
                        "type": keytype,
                        "created": created,
                        "expires": expiry
                    }
                elif line[0:3] == "uid":
                    curkey["uids"].append(line.split("uid")[1].strip())
                elif line[0:3] == "sub":
                    args = line.split("sub")[1].strip().split(" ")
                    if len(args) == 3:
                        expiry = args[2]
                    else:
                        expiry = None
                    keytype, keyid = args[0].split("/")
                    created = args[1]
                    curkey["subkeys"].append({
                        "keyid": keyid,
                        "type": keytype,
                        "created": created,
                        "expires": expiry
                    })
            gpg.handles['stderr'].close()
            gpg.handles['stdout'].close()
            gpg.wait()
            session.ui.display_gpg_keys(keys)
        except IndexError, e:
            self._ignore_exception()
Пример #13
0
    def parse_pgpmime(self, message):
        sig_count, sig_parts, sig_alg = 0, [], 'SHA1'
        enc_count, enc_parts, enc_ver = 0, [], None

        for part in message.walk():
            mimetype = part.get_content_type()
            if (sig_count > 1) and (mimetype == 'application/pgp-signature'):
                sig = tempfile.NamedTemporaryFile()
                sig.write(part.get_payload())
                sig.flush()
                msg = '\r\n'.join(
                    sig_parts[0].as_string().splitlines(False)) + '\r\n'

                result = None
                try:
                    gpg = GnuPG().run(
                        ['--utf8-strings', '--verify', sig.name, '-'],
                        create_fhs=['stdin', 'stderr'])
                    gpg.handles['stdin'].write(msg)
                    gpg.handles['stdin'].close()
                    result = gpg.handles['stderr'].read().decode('utf-8')
                    gpg.wait()
                    summary = ('verified', result)
                except IOError:
                    if not result:
                        summary = ('signed', 'Error running GnuPG')
                    else:
                        reslines = [
                            g.split("gpg: ")[1]
                            for g in result.strip().split("\n")
                        ]
                        matchgr = re.match(
                            ".*made (.*) using (.*) key ID ([a-zA-Z0-9]{8}).*",
                            reslines[0])
                        keyid = matchgr.groups()[2]
                        keytype = matchgr.groups()[1]
                        datetime = matchgr.groups()[0]

                        # FIXME: This should understand what kind of UI we have.
                        summary = (
                            'signed',
                            "Signed %s with %s key 0x%s (<a onclick=\"mailpile.gpgrecvkey('%s');\">fetch key</a>)"
                            % (datetime, keytype, keyid, keyid))

                for sig_part in sig_parts:
                    sig_part.openpgp = summary

                # Reset!
                sig_count, sig_parts = 0, []

            elif sig_count > 0:
                sig_parts.append(part)
                sig_count += 1

            elif enc_count > 0 and (mimetype == 'application/octet-stream'):
                # FIXME: Decrypt and parse!
                crypt = tempfile.NamedTemporaryFile()
                crypt.write(part.get_payload())
                crypt.flush()
                msg = '\r\n'.join(part.as_string().splitlines(False)) + '\r\n'
                print msg

                result = None
                try:
                    gpg = GnuPG().run(['--utf8-strings', '--decrypt'],
                                      create_fhs=['stdin', 'stdout', 'stderr'])
                    gpg.handles['stdin'].write(msg)
                    gpg.handles['stdin'].close()
                    result = gpg.handles['stdout'].read().decode('utf-8')
                    gpg.wait()
                    print "Decrypted:"
                    print result
                    summary = ('decrypted', result)
                    # part.attach(result)
                    s = StringIO.StringIO()
                    s.write(result)
                    m = Parser().parse(s)
                    print m
                    m = Message()
                    m.set_payload(result)
                    part.set_payload([m])
                    # print part.__module__
                    # enc_parts.append(part)
                except IOError:
                    if not result:
                        summary = ('encrypted', 'Error running GnuPG')
                    else:
                        #reslines = [g.split("gpg: ")[1] for g in result.strip().split("\n")]
                        #matchgr = re.match(".*made (.*) using (.*) key ID ([a-zA-Z0-9]{8}).*", reslines[0])
                        #keyid = matchgr.groups()[2]
                        #keytype = matchgr.groups()[1]
                        #datetime = matchgr.groups()[0]

                        # FIXME: This should understand what kind of UI we have.
                        print "FAIL"
                        summary = ('encrypted', result)

                for enc_part in enc_parts:
                    enc_part.openpgp = summary

                # Reset!
                enc_count, enc_parts = 0, []
            elif mimetype == 'multipart/signed':
                sig_alg = part.get_param('micalg',
                                         'pgp-sha1').split('-')[1].upper()
                sig_count = 1

            elif mimetype == 'multipart/encrypted':
                enc_count = 1
Пример #14
0
def Action(session, opt, arg):
  config = session.config
  session.ui.reset_marks(quiet=True)
  num_results = config.get('num_results', None)

  if not opt or opt in ('h', 'help'):
    session.ui.print_help(COMMANDS, tags=config.get('tag', {}),
                                    index=config.get_index(session))

  elif opt in ('W', 'webserver'):
    config.prepare_workers(session, daemons=True)
    while not mailpile.util.QUITTING: time.sleep(1)

  elif opt in ('A', 'add'):
    if os.path.exists(arg):
      arg = os.path.abspath(arg)
      if config.parse_set(session,
                          'mailbox:%s=%s' % (config.nid('mailbox'), arg)):
        config.slow_worker.add_task(None, 'Save config', lambda: config.save())
    else:
      session.error('No such file/directory: %s' % arg)

  elif opt in ('T', 'addtag'):
    if (arg
    and ' ' not in arg
    and arg.lower() not in [v.lower() for v in config.get('tag', {}).values()]):
      if config.parse_set(session,
                          'tag:%s=%s' % (config.nid('tag'), arg)):
        config.slow_worker.add_task(None, 'Save config', lambda: config.save())
    else:
      session.error('Invalid tag: %s' % arg)

  elif opt in ('F', 'filter'):
    Action_Filter(session, opt, arg)

  elif opt in ('O', 'optimize'):
    config.slow_worker.do(session, 'Optimize',
                          lambda: Action_Optimize(session, config, arg))

  elif opt in ('P', 'print'):
    session.ui.print_key(arg.strip().lower(), config)

  elif opt in ('U', 'unset'):
    if config.parse_unset(session, arg):
      config.slow_worker.add_task(None, 'Save config', lambda: config.save())

  elif opt in ('S', 'set'):
    if config.parse_set(session, arg):
      config.slow_worker.add_task(None, 'Save config', lambda: config.save())

  elif opt in ('R', 'rescan'):
    Action_Load(session, config)
    config.slow_worker.do(session, 'Rescan',
                          lambda: Action_Rescan(session, config))

  elif opt in ('g', 'gpgrecv'):
    try:
      session.ui.mark('Invoking GPG to fetch key %s' % arg)
      keyserver = config.get('gpg_keyserver', 'pool.sks-keyservers.net')
      gpg = GnuPG().run(['--keyserver', keyserver,
                         '--recv-key', arg], create_fhs=['stderr'])
      session.ui.say(gpg.handles['stderr'].read())
      gpg.handles['stderr'].close()
      gpg.wait()
    except IOError:
      pass
    session.ui.reset_marks()

  elif opt in ('L', 'load'):
    Action_Load(session, config, reset=True)

  elif opt in ('n', 'next'):
    idx = Action_Load(session, config)
    session.ui.reset_marks()
    pos, count = session.displayed
    session.displayed = session.ui.display_results(idx, session.results,
                                                   session.searched,
                                                   start=pos+count,
                                                   num=num_results)
    session.ui.reset_marks()

  elif opt in ('p', 'previous'):
    idx = Action_Load(session, config)
    pos, count = session.displayed
    session.displayed = session.ui.display_results(idx, session.results,
                                                   session.searched,
                                                   end=pos,
                                                   num=num_results)
    session.ui.reset_marks()

  elif opt in ('t', 'tag'):
    Action_Tag(session, opt, arg)

  elif opt in ('o', 'order'):
    idx = Action_Load(session, config)
    session.order = arg or None
    idx.sort_results(session, session.results,
                     how=session.order)
    session.displayed = session.ui.display_results(idx, session.results,
                                                   session.searched,
                                                   num=num_results)
    session.ui.reset_marks()

  elif (opt in ('s', 'search')
        or opt.lower() in [t.lower() for t in config.get('tag', {}).values()]):
    idx = Action_Load(session, config)

    # FIXME: This is all rather dumb.  Make it smarter!

    session.searched = []
    if opt not in ('s', 'search'):
      tid = config.get_tag_id(opt)
      session.searched = ['tag:%s' % tid[0]]

    if arg.startswith('@'):
      try:
        if ' ' in arg:
          args = arg[1:].split(' ')
          start = args.pop(0)
        else:
          start, args = arg[1:], []
        start = int(start)-1
        arg = ' '.join(args)
      except ValueError:
        raise UsageError('Weird starting point')
    else:
      start = 0

    if ':' in arg or '-' in arg or '+' in arg:
      session.searched.extend(arg.lower().split())
    else:
      session.searched.extend(re.findall(WORD_REGEXP, arg.lower()))

    session.results = list(idx.search(session, session.searched))
    idx.sort_results(session, session.results, how=session.order)
    session.displayed = session.ui.display_results(idx, session.results,
                                                   session.searched,
                                                   start=start,
                                                   num=num_results)
    session.ui.reset_marks()

  elif opt in ('v', 'view'):
    args = arg.split()
    if args and args[0].lower() == 'raw':
      raw = args.pop(0)
    else:
      raw = False
    idx = Action_Load(session, config)
    emails = [Email(idx, i) for i in Choose_Messages(session, args)]
    if emails:
      idx.apply_filters(session, '@read', msg_idxs=[e.msg_idx for e in emails])
      session.ui.clear()
      session.ui.display_messages(emails, raw=raw)
    session.ui.reset_marks()

  elif opt in ('e', 'extract'):
    args = arg.split()
    idx = Action_Load(session, config)
    cid = args.pop(0)
    if len(args) > 0 and args[-1].startswith('>'):
      name_fmt = args.pop(-1)[1:]
    else:
      name_fmt = None
    emails = [Email(idx, i) for i in Choose_Messages(session, args)]
    for email in emails:
      email.extract_attachment(session, cid, name_fmt=name_fmt)
    session.ui.reset_marks()

  else:
    raise UsageError('Unknown command: %s' % opt)