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
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
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()
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()
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
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
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
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
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
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
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
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()
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
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)