def __init__(self, path, spawn=None, thread=None, **kwargs): """ :param path: path to the file to be edited :type path: str :param spawn: force running edtor in a new terminal :type spawn: bool :param thread: run asynchronously, don't block alot :type thread: bool """ self.spawn = spawn if spawn is None: self.spawn = settings.get('editor_spawn') self.thread = thread if thread is None: self.thread = settings.get('editor_in_thread') editor_cmdstring = None if os.path.isfile('/usr/bin/editor'): editor_cmdstring = '/usr/bin/editor' editor_cmdstring = os.environ.get('EDITOR', editor_cmdstring) editor_cmdstring = settings.get('editor_cmd') or editor_cmdstring logging.debug('using editor_cmd: %s' % editor_cmdstring) self.cmdlist = None if '%s' in editor_cmdstring: cmdstring = editor_cmdstring.replace('%s', helper.shell_quote(path)) self.cmdlist = split_commandstring(cmdstring) else: self.cmdlist = split_commandstring(editor_cmdstring) + [path] logging.debug({'spawn: ': self.spawn, 'in_thread': self.thread}) ExternalCommand.__init__(self, self.cmdlist, spawn=self.spawn, thread=self.thread, **kwargs)
def __init__(self, cmd, stdin=None, shell=False, spawn=False, refocus=True, thread=False, on_success=None, **kwargs): """ :param cmd: the command to call :type cmd: list or str :param stdin: input to pipe to the process :type stdin: file or str :param spawn: run command in a new terminal :type spawn: bool :param shell: let shell interpret command string :type shell: bool :param thread: run asynchronously, don't block alot :type thread: bool :param refocus: refocus calling buffer after cmd termination :type refocus: bool :param on_success: code to execute after command successfully exited :type on_success: callable """ logging.debug({'spawn': spawn}) # make sure cmd is a list of str if isinstance(cmd, unicode): # convert cmdstring to list: in case shell==True, # Popen passes only the first item in the list to $SHELL cmd = [cmd] if shell else split_commandstring(cmd) # determine complete command list to pass touchhook = settings.get_hook('touch_external_cmdlist') # filter cmd, shell and thread through hook if defined if touchhook is not None: logging.debug('calling hook: touch_external_cmdlist') res = touchhook(cmd, shell=shell, spawn=spawn, thread=thread) logging.debug('got: %s' % res) cmd, shell, self.in_thread = res # otherwise if spawn requested and X11 is running elif spawn: if 'DISPLAY' in os.environ: term_cmd = settings.get('terminal_cmd', '') logging.info('spawn in terminal: %s' % term_cmd) termcmdlist = split_commandstring(term_cmd) cmd = termcmdlist + cmd else: thread = False self.cmdlist = cmd self.stdin = stdin self.shell = shell self.refocus = refocus self.in_thread = thread self.on_success = on_success Command.__init__(self, **kwargs)
def __init__( self, cmd, stdin=None, shell=False, spawn=False, refocus=True, thread=False, on_success=None, **kwargs ): """ :param cmd: the command to call :type cmd: list or str :param stdin: input to pipe to the process :type stdin: file or str :param spawn: run command in a new terminal :type spawn: bool :param shell: let shell interpret command string :type shell: bool :param thread: run asynchronously, don't block alot :type thread: bool :param refocus: refocus calling buffer after cmd termination :type refocus: bool :param on_success: code to execute after command successfully exited :type on_success: callable """ logging.debug({"spawn": spawn}) # make sure cmd is a list of str if isinstance(cmd, unicode): # convert cmdstring to list: in case shell==True, # Popen passes only the first item in the list to $SHELL cmd = [cmd] if shell else split_commandstring(cmd) # determine complete command list to pass touchhook = settings.get_hook("touch_external_cmdlist") # filter cmd, shell and thread through hook if defined if touchhook is not None: logging.debug("calling hook: touch_external_cmdlist") res = touchhook(cmd, shell=shell, spawn=spawn, thread=thread) logging.debug("got: %s" % res) cmd, shell, self.in_thread = res # otherwise if spawn requested and X11 is running elif spawn: if "DISPLAY" in os.environ: term_cmd = settings.get("terminal_cmd", "") logging.info("spawn in terminal: %s" % term_cmd) termcmdlist = split_commandstring(term_cmd) cmd = termcmdlist + cmd else: thread = False self.cmdlist = cmd self.stdin = stdin self.shell = shell self.refocus = refocus self.in_thread = thread self.on_success = on_success Command.__init__(self, **kwargs)
def commandfactory(cmdline, mode='global'): """ parses `cmdline` and constructs a :class:`Command`. :param cmdline: command line to interpret :type cmdline: str :param mode: mode identifier :type mode: str >>> cmd = alot.commands.commandfactory('save --all /foo', mode='thread') >>> cmd <alot.commands.thread.SaveAttachmentCommand object at 0x272cf10 >>> cmd.all True >>> cmd.path u'/foo' """ # split commandname and parameters if not cmdline: return None logging.debug('mode:%s got commandline "%s"' % (mode, cmdline)) # allow to shellescape without a space after '!' if cmdline.startswith('!'): cmdline = 'shellescape \'%s\'' % cmdline[1:] cmdline = re.sub(r'"(.*)"', r'"\\"\1\\""', cmdline) try: args = split_commandstring(cmdline) except ValueError, e: raise CommandParseError(e.message)
def commandfactory(cmdline, mode='global'): """ parses `cmdline` and constructs a :class:`Command`. :param cmdline: command line to interpret :type cmdline: str :param mode: mode identifier :type mode: str >>> cmd = alot.commands.commandfactory('save --all /foo', mode='thread') >>> cmd <alot.commands.thread.SaveAttachmentCommand object at 0x272cf10 >>> cmd.all True >>> cmd.path u'/foo' """ # split commandname and parameters if not cmdline: return None logging.debug('mode:%s got commandline "%s"' % (mode, cmdline)) # allow to shellescape without a space after '!' if cmdline.startswith('!'): cmdline = 'shellescape \'%s\'' % cmdline[1:] cmdline = re.sub(r'"(.*)"', r'"\\"\1\\""', cmdline) try: args = split_commandstring(cmdline) except ValueError as e: raise CommandParseError(e.message) args = map(lambda x: alot.helper.string_decode(x, 'utf-8'), args) logging.debug('ARGS: %s' % args) cmdname = args[0] args = args[1:] # unfold aliases # TODO: read from settingsmanager # get class, argparser and forced parameter (cmdclass, parser, forcedparms) = lookup_command(cmdname, mode) if cmdclass is None: msg = 'unknown command: %s' % cmdname logging.debug(msg) raise CommandParseError(msg) parms = vars(parser.parse_args(args)) parms.update(forcedparms) logging.debug('cmd parms %s' % parms) # create Command cmd = cmdclass(**parms) # set pre and post command hooks get_hook = settings.get_hook cmd.prehook = get_hook('pre_%s_%s' % (mode, cmdname)) or \ get_hook('pre_global_%s' % cmdname) cmd.posthook = get_hook('post_%s_%s' % (mode, cmdname)) or \ get_hook('post_global_%s' % cmdname) return cmd
def apply(self, ui): logging.info('open attachment') mimetype = self.attachment.get_content_type() # returns pair of preliminary command string and entry dict containing # more info. We only use the dict and construct the command ourselves _, entry = settings.mailcap_find_match(mimetype) if entry: afterwards = None # callback, will rm tempfile if used handler_stdin = None tempfile_name = None handler_raw_commandstring = entry['view'] # read parameter part = self.attachment.get_mime_representation() parms = tuple(map('='.join, part.get_params())) # in case the mailcap defined command contains no '%s', # we pipe the files content to the handling command via stdin if '%s' in handler_raw_commandstring: nametemplate = entry.get('nametemplate', '%s') prefix, suffix = parse_mailcap_nametemplate(nametemplate) fn_hook = settings.get_hook('sanitize_attachment_filename') if fn_hook: # get filename filename = self.attachment.get_filename() prefix, suffix = fn_hook(filename, prefix, suffix) tmpfile = tempfile.NamedTemporaryFile(delete=False, prefix=prefix, suffix=suffix) tempfile_name = tmpfile.name self.attachment.write(tmpfile) tmpfile.close() def afterwards(): os.unlink(tempfile_name) else: handler_stdin = StringIO() self.attachment.write(handler_stdin) # create handler command list handler_cmd = mailcap.subst(handler_raw_commandstring, mimetype, filename=tempfile_name, plist=parms) handler_cmdlist = split_commandstring(handler_cmd) # 'needsterminal' makes handler overtake the terminal nt = entry.get('needsterminal', None) overtakes = (nt is None) ui.apply_command(ExternalCommand(handler_cmdlist, stdin=handler_stdin, on_success=afterwards, thread=overtakes)) else: ui.notify('unknown mime type')
def __init__(self, cmd, all=False, separately=False, background=False, shell=False, notify_stdout=False, format='raw', add_tags=False, noop_msg='no command specified', confirm_msg='', done_msg='done', **kwargs): """ :param cmd: shellcommand to open :type cmd: str or list of str :param all: pipe all, not only selected message :type all: bool :param separately: call command once per message :type separately: bool :param background: do not suspend the interface :type background: bool :param notify_stdout: display command\'s stdout as notification message :type notify_stdout: bool :param shell: let the shell interpret the command :type shell: bool :param format: what to pipe to the processes stdin. one of: 'raw': message content as is, 'decoded': message content, decoded quoted printable, 'id': message ids, separated by newlines, 'filepath': paths to message files on disk :type format: str :param add_tags: add 'Tags' header to the message :type add_tags: bool :param noop_msg: error notification to show if `cmd` is empty :type noop_msg: str :param confirm_msg: confirmation question to ask (continues directly if unset) :type confirm_msg: str :param done_msg: notification message to show upon success :type done_msg: str """ Command.__init__(self, **kwargs) if isinstance(cmd, unicode): cmd = split_commandstring(cmd) self.cmd = cmd self.whole_thread = all self.separately = separately self.background = background self.shell = shell self.notify_stdout = notify_stdout self.output_format = format self.add_tags = add_tags self.noop_msg = noop_msg self.confirm_msg = confirm_msg self.done_msg = done_msg
def lookup(self, prefix): cmdlist = split_commandstring(self.command) resultstring, errmsg, retval = call_cmd(cmdlist + [prefix]) if not resultstring: return [] lines = resultstring.splitlines() res = [] for l in lines: m = re.match(self.match, l) if m: info = m.groupdict() email = info['email'].strip() name = info['name'] res.append((name, email)) return res
def lookup(self, prefix): cmdlist = split_commandstring(self.command) resultstring, errmsg, retval = call_cmd(cmdlist + [prefix]) if not resultstring: return [] lines = resultstring.splitlines() res = [] for l in lines: m = re.match(self.match, l, self.reflags) if m: info = m.groupdict() email = info['email'].strip() name = info['name'] res.append((name, email)) return res
def __init__(self, cmd, all=False, separately=False, background=False, shell=False, notify_stdout=False, format='raw', add_tags=False, noop_msg='no command specified', confirm_msg='', done_msg=None, **kwargs): """ :param cmd: shellcommand to open :type cmd: str or list of str :param all: pipe all, not only selected message :type all: bool :param separately: call command once per message :type separately: bool :param background: do not suspend the interface :type background: bool :param notify_stdout: display command\'s stdout as notification message :type notify_stdout: bool :param shell: let the shell interpret the command :type shell: bool 'raw': message content as is, 'decoded': message content, decoded quoted printable, 'id': message ids, separated by newlines, 'filepath': paths to message files on disk :type format: str :param add_tags: add 'Tags' header to the message :type add_tags: bool :param noop_msg: error notification to show if `cmd` is empty :type noop_msg: str :param confirm_msg: confirmation question to ask (continues directly if unset) :type confirm_msg: str :param done_msg: notification message to show upon success :type done_msg: str """ Command.__init__(self, **kwargs) if isinstance(cmd, unicode): cmd = split_commandstring(cmd) self.cmd = cmd self.whole_thread = all self.separately = separately self.background = background self.shell = shell self.notify_stdout = notify_stdout self.output_format = format self.add_tags = add_tags self.noop_msg = noop_msg self.confirm_msg = confirm_msg self.done_msg = done_msg
def send_mail(self, mail): cmdlist = split_commandstring(self.cmd) def cb(out): logging.info('sent mail successfully') logging.info(out) def errb(failure): termobj = failure.value errmsg = '%s\nsendmail_cmd set to: %s' % (str(termobj), self.cmd) logging.error(errmsg) logging.error(failure.getTraceback()) logging.error(failure.value.stderr) raise SendingMailFailed(errmsg) d = call_cmd_async(cmdlist, stdin=mail) d.addCallback(cb) d.addErrback(errb) return d
def send_mail(self, mail): cmdlist = split_commandstring(self.cmd) def cb(out): logging.info("sent mail successfully") logging.info(out) def errb(failure): termobj = failure.value errmsg = "%s failed with code %s:\n%s" % (self.cmd, termobj.exitCode, str(failure.value)) logging.error(errmsg) logging.error(failure.getTraceback()) logging.error(failure.value.stderr) raise SendingMailFailed(errmsg) d = call_cmd_async(cmdlist, stdin=mail) d.addCallback(cb) d.addErrback(errb) return d
def send_mail(self, mail): mail['Date'] = email.utils.formatdate(time.time(), True) cmdlist = split_commandstring(self.cmd) def cb(out): logging.info('sent mail successfully') logging.info(out) def errb(failure): termobj = failure.value errmsg = '%s\nsendmail_cmd set to: %s' % (str(termobj), self.cmd) logging.error(errmsg) logging.error(failure.getTraceback()) logging.error(failure.value.stderr) raise SendingMailFailed(errmsg) d = call_cmd_async(cmdlist, stdin=crypto.email_as_string(mail)) d.addCallback(cb) d.addErrback(errb) return d
def send_mail(self, mail): cmdlist = split_commandstring(self.cmd) def cb(out): logging.info('sent mail successfully') logging.info(out) def errb(failure): termobj = failure.value errmsg = '%s failed with code %s:\n%s' % \ (self.cmd, termobj.exitCode, failure.value.stderr.rstrip()) logging.error(errmsg) logging.error(failure.getTraceback()) logging.error(failure.value.stderr) raise SendingMailFailed(errmsg) d = call_cmd_async(cmdlist, stdin=mail) d.addCallback(cb) d.addErrback(errb) return d
def dimapseminar(ui): """interprets DIMAP seminar mails""" msg = ui.current_buffer.get_selected_message() msgtext = msg.accumulate_body() r = r"Title:\s*(?P<title>((.*)(\n\s*.*)*))\n\nSpeaker:\s*(?P<speaker>.*)\nTime:\s*(?P<time>.*)\nLocation:\s*(?P<location>.*)\n\s*Abstract:\s*(?P<abstract>((.*)\n)*)" info = re.search(r, msgtext).groupdict() info['title'] = ' '.join(info['title'].split()) #ui.notify('info: %s' % str(info.items())) cmd = "gcalcli add " \ "--calendar uni " \ "--title \"DIMAP: {speaker}:{title}\" " \ "--where \"{location}\" " \ "--when \"{time}\" "\ "--description \"{abstract}\" "\ "--duration 60 "\ "--reminder 30" cmdlist = split_commandstring(cmd.format(**info)) msg = ui.notify('info: %s' % cmdlist) if (yield ui.choice("commit?", select='yes', cancel='no')) == 'no': return ui.clear_notify([msg]) ui.notify('info: %s' % str(call_cmd(cmdlist)))
def lookup(self, prefix): cmdlist = split_commandstring(self.command) resultstring, errmsg, retval = call_cmd(cmdlist + [prefix]) if retval != 0: msg = 'abook command "%s" returned with ' % self.command msg += 'return code %d' % retval if errmsg: msg += ':\n%s' % errmsg raise AddressbookError(msg) if not resultstring: return [] lines = resultstring.splitlines() res = [] for l in lines: m = re.match(self.match, l, self.reflags) if m: info = m.groupdict() if 'email' and 'name' in info: email = info['email'].strip() name = info['name'] res.append((name, email)) return res
def dimapseminar(ui): """interprets DIMAP seminar mails""" msg = ui.current_buffer.get_selected_message() msgtext = msg.accumulate_body() r = r"Title:\s*(?P<title>((.*)(\n\s*.*)*))\n\nSpeaker:\s*(?P<speaker>.*)\nTime:\s*(?P<time>.*)\nLocation:\s*(?P<location>.*)\n\s*Abstract:\s*(?P<abstract>((.*)\n)*)" info = re.search(r, msgtext).groupdict() info["title"] = " ".join(info["title"].split()) # ui.notify('info: %s' % str(info.items())) cmd = ( "gcalcli add " "--calendar uni " '--title "DIMAP: {speaker}:{title}" ' '--where "{location}" ' '--when "{time}" ' '--description "{abstract}" ' "--duration 60 " "--reminder 30" ) cmdlist = split_commandstring(cmd.format(**info)) msg = ui.notify("info: %s" % cmdlist) if (yield ui.choice("commit?", select="yes", cancel="no")) == "no": return ui.clear_notify([msg]) ui.notify("info: %s" % str(call_cmd(cmdlist)))
def extract_body(mail, types=None): """ returns a body text string for given mail. If types is `None`, `text/*` is used: The exact preferred type is specified by the prefer_plaintext config option which defaults to text/html. :param mail: the mail to use :type mail: :class:`email.Message` :param types: mime content types to use for body string :type types: list of str """ preferred = 'text/plain' if settings.get('prefer_plaintext') else 'text/html' has_preferred = False # see if the mail has our preferred type if types == None: has_preferred = list(typed_subpart_iterator(mail, *preferred.split('/'))) body_parts = [] for part in mail.walk(): ctype = part.get_content_type() if types is not None: if ctype not in types: continue cd = part.get('Content-Disposition', '') if cd.startswith('attachment'): continue # if the mail has our preferred type, we only keep this type # note that if types != None, has_preferred always stays False if has_preferred and ctype != preferred: continue enc = part.get_content_charset() or 'ascii' raw_payload = part.get_payload(decode=True) if ctype == 'text/plain': raw_payload = string_decode(raw_payload, enc) body_parts.append(string_sanitize(raw_payload)) else: #get mime handler key = 'copiousoutput' handler, entry = settings.mailcap_find_match(ctype, key=key) tempfile_name = None stdin = None if entry: handler_raw_commandstring = entry['view'] # in case the mailcap defined command contains no '%s', # we pipe the files content to the handling command via stdin if '%s' in handler_raw_commandstring: # open tempfile, respect mailcaps nametemplate nametemplate = entry.get('nametemplate', '%s') prefix, suffix = parse_mailcap_nametemplate(nametemplate) tmpfile = tempfile.NamedTemporaryFile(delete=False, prefix=prefix, suffix=suffix) # write payload to tmpfile tmpfile.write(raw_payload) tmpfile.close() tempfile_name = tmpfile.name else: stdin = raw_payload # read parameter, create handler command parms = tuple(map('='.join, part.get_params())) # create and call external command cmd = mailcap.subst(entry['view'], ctype, filename=tempfile_name, plist=parms) logging.debug('command: %s' % cmd) logging.debug('parms: %s' % str(parms)) cmdlist = split_commandstring(cmd) # call handler rendered_payload, errmsg, retval = helper.call_cmd(cmdlist, stdin=stdin) # remove tempfile if tempfile_name: os.unlink(tempfile_name) if rendered_payload: # handler had output body_parts.append(string_sanitize(rendered_payload)) return u'\n\n'.join(body_parts)
def _test(self, base, expected): """Shared helper to reduce some boilerplate.""" actual = helper.split_commandstring(base) self.assertListEqual(actual, expected)
def extract_body(mail, types=None): """ returns a body text string for given mail. If types is `None`, `text/*` is used: In case mail has a `text/html` part, it is prefered over `text/plain` parts. :param mail: the mail to use :type mail: :class:`email.Message` :param types: mime content types to use for body string :type types: list of str """ html = list(typed_subpart_iterator(mail, 'text', 'html')) # if no specific types are given, we favor text/html over text/plain drop_plaintext = False if html and not types: drop_plaintext = True body_parts = [] for part in mail.walk(): ctype = part.get_content_type() if types is not None: if ctype not in types: continue cd = part.get('Content-Disposition', '') if cd.startswith('attachment'): continue enc = part.get_content_charset() or 'ascii' raw_payload = part.get_payload(decode=True) if ctype == 'text/plain' and not drop_plaintext: raw_payload = string_decode(raw_payload, enc) body_parts.append(string_sanitize(raw_payload)) else: #get mime handler key = 'copiousoutput' handler, entry = settings.mailcap_find_match(ctype, key=key) if entry: # open tempfile, respect mailcaps nametemplate nametemplate = entry.get('nametemplate', '%s') prefix, suffix = parse_mailcap_nametemplate(nametemplate) tmpfile = tempfile.NamedTemporaryFile(delete=False, prefix=prefix, suffix=suffix) # write payload to tmpfile tmpfile.write(raw_payload) tmpfile.close() # read parameter, create handler command parms = tuple(map('='.join, part.get_params())) # create and call external command cmd = mailcap.subst(entry['view'], ctype, filename=tmpfile.name, plist=parms) logging.debug('command: %s' % cmd) logging.debug('parms: %s' % str(parms)) cmdlist = split_commandstring(cmd) # call handler rendered_payload, errmsg, retval = helper.call_cmd(cmdlist) # remove tempfile os.unlink(tmpfile.name) if rendered_payload: # handler had output body_parts.append(string_sanitize(rendered_payload)) return u'\n\n'.join(body_parts)
def extract_body(mail, types=None): """ returns a body text string for given mail. If types is `None`, `text/*` is used: In case mail has a `text/html` part, it is prefered over `text/plain` parts. :param mail: the mail to use :type mail: :class:`email.Message` :param types: mime content types to use for body string :type types: list of str """ html = list(typed_subpart_iterator(mail, 'text', 'html')) # if no specific types are given, we favor text/html over text/plain drop_plaintext = False if html and not types: drop_plaintext = True body_parts = [] for part in mail.walk(): ctype = part.get_content_type() logging.debug(ctype) if types is not None: if ctype not in types: continue cd = part.get('Content-Disposition', '') if cd.startswith('attachment'): continue enc = part.get_content_charset() or 'ascii' raw_payload = part.get_payload(decode=True) if ctype == 'text/plain' and not drop_plaintext: raw_payload = string_decode(raw_payload, enc) body_parts.append(string_sanitize(raw_payload)) else: #get mime handler key = 'copiousoutput' handler, entry = settings.mailcap_find_match(ctype, key=key) if entry: # open tempfile, respect mailcaps nametemplate nametemplate = entry.get('nametemplate', '%s') prefix, suffix = parse_mailcap_nametemplate(nametemplate) tmpfile = tempfile.NamedTemporaryFile(delete=False, prefix=prefix, suffix=suffix) # write payload to tmpfile tmpfile.write(raw_payload) tmpfile.close() # read parameter, create handler command parms = tuple(map('='.join, part.get_params())) # create and call external command cmd = mailcap.subst(entry['view'], ctype, filename=tmpfile.name, plist=parms) logging.debug('command: %s' % cmd) logging.debug('parms: %s' % str(parms)) cmdlist = split_commandstring(cmd) # call handler rendered_payload, errmsg, retval = helper.call_cmd(cmdlist) # remove tempfile os.unlink(tmpfile.name) if rendered_payload: # handler had output body_parts.append(string_sanitize(rendered_payload)) return u'\n\n'.join(body_parts)
def extract_body(mail, types=None): """ returns a body text string for given mail. If types is `None`, `text/*` is used: The exact preferred type is specified by the prefer_plaintext config option which defaults to text/html. :param mail: the mail to use :type mail: :class:`email.Message` :param types: mime content types to use for body string :type types: list of str """ preferred = 'text/plain' if settings.get( 'prefer_plaintext') else 'text/html' has_preferred = False # see if the mail has our preferred type if types is None: has_preferred = list( typed_subpart_iterator(mail, *preferred.split('/'))) body_parts = [] for part in mail.walk(): ctype = part.get_content_type() if types is not None: if ctype not in types: continue cd = part.get('Content-Disposition', '') if cd.startswith('attachment'): continue # if the mail has our preferred type, we only keep this type # note that if types != None, has_preferred always stays False if has_preferred and ctype != preferred: continue enc = part.get_content_charset() or 'ascii' raw_payload = part.get_payload(decode=True) if ctype == 'text/plain': raw_payload = string_decode(raw_payload, enc) body_parts.append(string_sanitize(raw_payload)) else: # get mime handler key = 'copiousoutput' handler, entry = settings.mailcap_find_match(ctype, key=key) tempfile_name = None stdin = None if entry: handler_raw_commandstring = entry['view'] # in case the mailcap defined command contains no '%s', # we pipe the files content to the handling command via stdin if '%s' in handler_raw_commandstring: # open tempfile, respect mailcaps nametemplate nametemplate = entry.get('nametemplate', '%s') prefix, suffix = parse_mailcap_nametemplate(nametemplate) tmpfile = tempfile.NamedTemporaryFile(delete=False, prefix=prefix, suffix=suffix) # write payload to tmpfile tmpfile.write(raw_payload) tmpfile.close() tempfile_name = tmpfile.name else: stdin = raw_payload # read parameter, create handler command parms = tuple(map('='.join, part.get_params())) # create and call external command cmd = mailcap.subst(entry['view'], ctype, filename=tempfile_name, plist=parms) logging.debug('command: %s' % cmd) logging.debug('parms: %s' % str(parms)) cmdlist = split_commandstring(cmd) # call handler rendered_payload, errmsg, retval = helper.call_cmd(cmdlist, stdin=stdin) # remove tempfile if tempfile_name: os.unlink(tempfile_name) if rendered_payload: # handler had output body_parts.append(string_sanitize(rendered_payload)) return u'\n\n'.join(body_parts)