diff --git a/alot/commands/thread.py b/alot/commands/thread.py index 433ba6a62..03d5276cd 100644 --- a/alot/commands/thread.py +++ b/alot/commands/thread.py @@ -601,6 +601,11 @@ def apply(self, ui): mimepart = get_body_part(message.get_email(), mimetype) elif self.mimepart is True: mimepart = ui.get_deep_focus().mimepart + if isinstance(mimepart, Attachment): + # We're here because we're processing this attachment using a + # mailcap view entry to actually display within alot. + # Therefore, extract the mimepart from the Attachment here. + mimepart = mimepart.part mt.set_mimepart(mimepart) ui.update() if self.mimetree == 'toggle': @@ -919,7 +924,7 @@ async def apply(self, ui): focus = ui.get_deep_focus() if isinstance(focus, AttachmentWidget): attachment = focus.get_attachment() - filename = attachment.get_filename() + filename = attachment.get_filename() or '' if not self.path: msg = 'save attachment (%s) to ' % filename initialtext = os.path.join(savedir, filename) @@ -1067,6 +1072,18 @@ async def apply(self, ui): await ui.apply_command(OpenAttachmentCommand(focus.get_attachment())) elif getattr(focus, 'mimepart', False): if isinstance(focus.mimepart, Attachment): + # Check if both an attachment opener and view are defined + mimetype = focus.mimepart.get_content_type() + _, entry = settings.mailcap_find_match(mimetype) + logging.debug('full mailcap entry: %s', entry) + if entry.get('x-alot-attachmenttotext', ''): + # Separate view and "dump to text" actions defined, so + # attempt to view. We do this before open, so that + # whatever it's viewed as is visible in alot in case the + # open is some interactive external thing + await ui.apply_command(ChangeDisplaymodeCommand( + mimepart=True, mimetree='toggle')) + # Always attempt to open the attachment await ui.apply_command(OpenAttachmentCommand(focus.mimepart)) else: await ui.apply_command(ChangeDisplaymodeCommand( diff --git a/alot/db/message.py b/alot/db/message.py index 6b1a3d9b8..9fdbbcb41 100644 --- a/alot/db/message.py +++ b/alot/db/message.py @@ -251,8 +251,18 @@ def get_attachments(self): 'application/pgp-encrypted'): self._attachments.pop() + # handle calendar invites from outlook by adding a + # content-disposition header if not present + if ct.lower() == 'text/calendar': + cd = part.get('Content-Disposition', '') + if not cd: + part.add_header('Content-Disposition', 'inline', + filename='inline-{}.ics'.format( + len(self._attachments))) + if self._is_attachment(part, ct): self._attachments.append(Attachment(part)) + return self._attachments @staticmethod diff --git a/alot/db/utils.py b/alot/db/utils.py index 892bc2872..4bd9a2973 100644 --- a/alot/db/utils.py +++ b/alot/db/utils.py @@ -347,9 +347,11 @@ def render_part(part, field_key='copiousoutput'): # get mime handler _, entry = settings.mailcap_find_match(ctype, key=field_key) if entry is not None: + logging.debug('full matching mailcap entry: %s', entry) tempfile_name = None stdin = None - handler_raw_commandstring = entry['view'] + handler_raw_commandstring = entry.get('x-alot-attachmenttotext', '') or entry['view'] + logging.debug('mailcap entry to render part: %s', handler_raw_commandstring) # 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: @@ -368,7 +370,7 @@ def render_part(part, field_key='copiousoutput'): parms = tuple('='.join(p) for p in part.get_params(failobj=[])) # create and call external command - cmd = mailcap.subst(entry['view'], ctype, + cmd = mailcap.subst(handler_raw_commandstring, ctype, filename=tempfile_name, plist=parms) logging.debug('command: %s', cmd) logging.debug('parms: %s', str(parms))