Search in sources :

Example 1 with Mime

use of com.zimbra.cs.mime.Mime in project zm-mailbox by Zimbra.

the class MessageCache method getMimeMessage.

/**
 * Returns a JavaMail {@link javax.mail.internet.MimeMessage}
 *  encapsulating the message content.  If possible, TNEF and uuencoded
 *  attachments are expanded and their components are presented as
 *  standard MIME attachments.  If TNEF or uuencode decoding fails, the
 *  MimeMessage wraps the raw message content.
 *
 * @return A MimeMessage wrapping the RFC822 content of the Message.
 * @throws ServiceException when errors occur opening, reading,
 *                          uncompressing, or parsing the message file,
 *                          or when the file does not exist.
 * @see #getRawContent()
 * @see #getItemContent()
 * @see com.zimbra.cs.mime.TnefConverter
 * @see com.zimbra.cs.mime.UUEncodeConverter
 */
static MimeMessage getMimeMessage(MailItem item, boolean expand) throws ServiceException {
    String digest = item.getDigest();
    CacheNode cnode = null;
    boolean cacheHit = true;
    boolean newNode = false;
    InputStream in = null;
    int mboxId = item.getMailboxId();
    boolean isEncrypted = false;
    synchronized (sCache) {
        cnode = sCache.get(digest);
        if (cnode == null) {
            newNode = true;
            cnode = new CacheNode();
        }
    }
    try {
        if (cnode.message == null) {
            sLog.debug("Loading MimeMessage for item %d.", item.getId());
            cacheHit = false;
            try {
                in = fetchFromStore(item);
                cnode.message = new Mime.FixedMimeMessage(JMSession.getSession(), in);
                if (item.getSize() < MESSAGE_CACHE_DISK_STREAMING_THRESHOLD) {
                    cnode.size = item.getSize();
                    // Not the best place to increment the data size, but cacheItem()
                    // won't get called if we're expanding a message for an existing
                    // node.
                    sDataSize += cnode.size;
                }
            } finally {
                ByteUtil.closeStream(in);
            }
        }
        if (expand) {
            sLog.debug("Expanding MimeMessage for item %d.", item.getId());
            try {
                MimeMessage decryptedMimeMessage = null;
                if (item instanceof Message) {
                    // if the mime is encrypted; decrypt it first
                    if (cnode.message != null) {
                        isEncrypted = Mime.isEncrypted(cnode.message.getContentType());
                    }
                    if (isEncrypted) {
                        if (isSmimeFeatureToggled(item.getMailbox(), cnode)) {
                            sLog.debug("Smime feature is toggled. So remove old entry from smimeAccessInfo for mailboxId=%d and itemDigest=%s", mboxId, item.getDigest());
                            cnode.smimeAccessInfo.remove(mboxId);
                        }
                        if (cnode.expanded == null || !cnode.smimeAccessInfo.containsKey(mboxId)) {
                            cacheHit = false;
                            decryptedMimeMessage = doDecryption(item, cnode, mboxId);
                        }
                    }
                }
                // expand if the message has not yet been expanded or if the message is decrypted successfully
                if (cnode.expanded == null || (decryptedMimeMessage != null && cnode.expanded != decryptedMimeMessage)) {
                    cacheHit = false;
                    expandMessage(item, cnode, decryptedMimeMessage);
                }
            } catch (Exception e) {
                // if the conversion bombs for any reason, revert to the original
                sLog.warn("MIME converter failed for message %d.  Reverting to original.", item.getId(), e);
                cnode.expanded = cnode.message;
            }
        }
        if (newNode) {
            cacheItem(digest, cnode);
        }
    } catch (IOException e) {
        throw ServiceException.FAILURE("IOException while retrieving content for item " + item.getId(), e);
    } catch (MessagingException e) {
        throw ServiceException.FAILURE("MessagingException while creating MimeMessage for item " + item.getId(), e);
    } finally {
        ByteUtil.closeStream(in);
    }
    if (cacheHit) {
        sLog.debug("Cache hit for item %d: digest=%s, expand=%b.", item.getId(), item.getDigest(), expand);
        ZimbraPerf.COUNTER_MBOX_MSG_CACHE.increment(100);
    } else {
        sLog.debug("Cache miss for item %d: digest=%s, expand=%b.", item.getId(), item.getDigest(), expand);
        ZimbraPerf.COUNTER_MBOX_MSG_CACHE.increment(0);
    }
    if (expand) {
        if (isEncrypted && (!cnode.smimeAccessInfo.containsKey(mboxId) || cnode.smimeAccessInfo.get(mboxId) != null)) {
            return cnode.message;
        }
        return cnode.expanded;
    } else {
        return cnode.message;
    }
}
Also used : Mime(com.zimbra.cs.mime.Mime) MimeMessage(javax.mail.internet.MimeMessage) ExpandMimeMessage(com.zimbra.cs.mime.ExpandMimeMessage) MimeMessage(javax.mail.internet.MimeMessage) ExpandMimeMessage(com.zimbra.cs.mime.ExpandMimeMessage) MessagingException(javax.mail.MessagingException) InputStream(java.io.InputStream) IOException(java.io.IOException) MessagingException(javax.mail.MessagingException) IOException(java.io.IOException) ServiceException(com.zimbra.common.service.ServiceException)

Example 2 with Mime

use of com.zimbra.cs.mime.Mime in project zm-mailbox by Zimbra.

the class ToXML method encodeMessageAsMPHelper.

/**
 * Encodes a Message object into <m> element with <mp> elements for
 *  message body.
 * @param parent  The Element to add the new <tt>&lt;m></tt> to.
 * @param ifmt    The formatter to sue when serializing item ids.
 * @param msg     The Message to serialize.
 * @param part    If non-null, serialize this message/rfc822 subpart of
 *                the Message instead of the Message itself.
 * @param maxSize TODO
 * @param wantHTML  <tt>true</tt> to prefer HTML parts as the "body",
 *                  <tt>false</tt> to prefer text/plain parts.
 * @param neuter  Whether to rename "src" attributes on HTML <img> tags.
 * @param headers Extra message headers to include in the returned element.
 * @param serializeType If <tt>false</tt>, always serializes as an
 *                      <tt>&lt;m></tt> element.
 * @param bestEffort  If <tt>true</tt>, errors serializing part content
 *                    are swallowed.
 * @return The newly-created <tt>&lt;m></tt> Element, which has already
 *         been added as a child to the passed-in <tt>parent</tt>.
 * @throws ServiceException
 */
private static Element encodeMessageAsMPHelper(boolean bestEffort, Element parent, ItemIdFormatter ifmt, OperationContext octxt, Message msg, String part, int maxSize, boolean wantHTML, boolean neuter, Set<String> headers, boolean serializeType, boolean wantExpandGroupInfo, boolean encodeMissingBlobs, MsgContent wantContent, int fields) throws ServiceException {
    Element m = null;
    boolean success = false;
    try {
        boolean wholeMessage = part == null || part.trim().isEmpty();
        m = encodeMsgCommonAndIdInfo(parent, ifmt, octxt, msg, part, serializeType, fields);
        MimeMessage mm = null;
        try {
            String requestedAccountId = octxt.getmRequestedAccountId();
            String authtokenAccountId = octxt.getmAuthTokenAccountId();
            boolean isDecryptionNotAllowed = StringUtils.isNotEmpty(authtokenAccountId) && !authtokenAccountId.equalsIgnoreCase(requestedAccountId);
            if (isDecryptionNotAllowed && Mime.isEncrypted(msg.getMimeMessage(false).getContentType())) {
                mm = msg.getMimeMessage(false);
            } else {
                mm = msg.getMimeMessage();
            }
        } catch (MailServiceException e) {
            if (encodeMissingBlobs && MailServiceException.NO_SUCH_BLOB.equals(e.getCode())) {
                ZimbraLog.mailbox.error("Unable to get blob while encoding message", e);
                encodeEmail(m, msg.getSender(), EmailType.FROM);
                encodeEmail(m, msg.getSender(), EmailType.SENDER);
                if (msg.getRecipients() != null) {
                    addEmails(m, Mime.parseAddressHeader(msg.getRecipients()), EmailType.TO);
                }
                m.addAttribute(MailConstants.A_SUBJECT, msg.getSubject());
                Element mimePart = m.addNonUniqueElement(MailConstants.E_MIMEPART);
                mimePart.addAttribute(MailConstants.A_PART, 1);
                mimePart.addAttribute(MailConstants.A_BODY, true);
                mimePart.addAttribute(MailConstants.A_CONTENT_TYPE, MimeConstants.CT_TEXT_PLAIN);
                String errMsg = L10nUtil.getMessage(L10nUtil.MsgKey.errMissingBlob, msg.getAccount().getLocale(), ifmt.formatItemId(msg));
                m.addAttribute(MailConstants.E_FRAG, errMsg, Element.Disposition.CONTENT);
                mimePart.addAttribute(MailConstants.E_CONTENT, errMsg, Element.Disposition.CONTENT);
                // not really success, but mark as such so the element is appended correctly
                success = true;
                return m;
            }
            throw e;
        }
        if (!wholeMessage) {
            MimePart mp = Mime.getMimePart(mm, part);
            if (mp == null) {
                throw MailServiceException.NO_SUCH_PART(part);
            }
            Object content = Mime.getMessageContent(mp);
            if (!(content instanceof MimeMessage)) {
                throw MailServiceException.NO_SUCH_PART(part);
            }
            mm = (MimeMessage) content;
        } else {
            part = "";
        }
        // Add fragment before emails to maintain consistent ordering
        // of elements with encodeConversation - need to do this to
        // overcome JAXB issues.
        String fragment = msg.getFragment();
        if (fragment != null && !fragment.isEmpty()) {
            m.addAttribute(MailConstants.E_FRAG, fragment, Element.Disposition.CONTENT);
        }
        addEmails(m, Mime.parseAddressHeader(mm, "From"), EmailType.FROM);
        addEmails(m, Mime.parseAddressHeader(mm, "Sender"), EmailType.SENDER);
        addEmails(m, Mime.parseAddressHeader(mm, "Reply-To"), EmailType.REPLY_TO);
        addEmails(m, Mime.parseAddressHeader(mm, "To"), EmailType.TO);
        addEmails(m, Mime.parseAddressHeader(mm, "Cc"), EmailType.CC);
        addEmails(m, Mime.parseAddressHeader(mm, "Bcc"), EmailType.BCC);
        addEmails(m, Mime.parseAddressHeader(mm.getHeader("Resent-From", null), false), EmailType.RESENT_FROM);
        // read-receipts only get sent by the mailbox's owner
        if (!(octxt.isDelegatedRequest(msg.getMailbox()) && octxt.isOnBehalfOfRequest(msg.getMailbox()))) {
            addEmails(m, Mime.parseAddressHeader(mm, "Disposition-Notification-To"), EmailType.READ_RECEIPT);
        }
        String calIntendedFor = msg.getCalendarIntendedFor();
        m.addAttribute(MailConstants.A_CAL_INTENDED_FOR, calIntendedFor);
        String subject = Mime.getSubject(mm);
        if (subject != null) {
            m.addAttribute(MailConstants.E_SUBJECT, StringUtil.stripControlCharacters(subject), Element.Disposition.CONTENT);
        }
        String messageID = mm.getMessageID();
        if (messageID != null && !messageID.trim().isEmpty()) {
            m.addAttribute(MailConstants.E_MSG_ID_HDR, StringUtil.stripControlCharacters(messageID), Element.Disposition.CONTENT);
        }
        if (wholeMessage && msg.isDraft()) {
            if (!msg.getDraftOrigId().isEmpty()) {
                ItemId origId = new ItemId(msg.getDraftOrigId(), msg.getMailbox().getAccountId());
                m.addAttribute(MailConstants.A_ORIG_ID, ifmt.formatItemId(origId));
            }
            if (!msg.getDraftReplyType().isEmpty()) {
                m.addAttribute(MailConstants.A_REPLY_TYPE, msg.getDraftReplyType());
            }
            if (!msg.getDraftIdentityId().isEmpty()) {
                m.addAttribute(MailConstants.A_IDENTITY_ID, msg.getDraftIdentityId());
            }
            if (!msg.getDraftAccountId().isEmpty()) {
                m.addAttribute(MailConstants.A_FOR_ACCOUNT, msg.getDraftAccountId());
            }
            String inReplyTo = mm.getHeader("In-Reply-To", null);
            if (inReplyTo != null && !inReplyTo.isEmpty()) {
                m.addAttribute(MailConstants.E_IN_REPLY_TO, StringUtil.stripControlCharacters(inReplyTo), Element.Disposition.CONTENT);
            }
            if (msg.getDraftAutoSendTime() != 0) {
                m.addAttribute(MailConstants.A_AUTO_SEND_TIME, msg.getDraftAutoSendTime());
            }
        }
        if (!wholeMessage) {
            m.addAttribute(MailConstants.A_SIZE, mm.getSize());
        }
        Date sent = mm.getSentDate();
        if (sent != null) {
            m.addAttribute(MailConstants.A_SENT_DATE, sent.getTime());
        }
        Calendar resent = DateUtil.parseRFC2822DateAsCalendar(mm.getHeader("Resent-Date", null));
        if (resent != null) {
            m.addAttribute(MailConstants.A_RESENT_DATE, resent.getTimeInMillis());
        }
        if (msg.isInvite() && msg.hasCalendarItemInfos()) {
            encodeInvitesForMessage(m, ifmt, octxt, msg, NOTIFY_FIELDS, neuter);
        }
        if (headers != null) {
            for (String name : headers) {
                String[] values = mm.getHeader(name);
                if (values != null) {
                    for (int i = 0; i < values.length; i++) {
                        m.addKeyValuePair(name, values[i], MailConstants.A_HEADER, MailConstants.A_ATTRIBUTE_NAME);
                    }
                }
            }
        }
        List<MPartInfo> parts = Mime.getParts(mm, getDefaultCharset(msg));
        if (parts != null && !parts.isEmpty()) {
            Set<MPartInfo> bodies = Mime.getBody(parts, wantHTML);
            addParts(m, parts.get(0), bodies, part, maxSize, neuter, false, getDefaultCharset(msg), bestEffort, wantContent);
        }
        if (wantExpandGroupInfo) {
            ZimbraLog.gal.trace("want expand group info");
            Account authedAcct = octxt.getAuthenticatedUser();
            Account requestedAcct = msg.getMailbox().getAccount();
            encodeAddrsWithGroupInfo(m, requestedAcct, authedAcct);
        } else {
            ZimbraLog.gal.trace("do not want expand group info");
        }
        success = true;
        // update crypto flags - isSigned/isEncrypted
        if (SmimeHandler.getHandler() != null) {
            if (!wholeMessage) {
                // check content type of attachment message for encryption flag
                SmimeHandler.getHandler().updateCryptoFlags(msg, m, mm, mm);
            } else {
                MimeMessage originalMimeMessage = msg.getMimeMessage(false);
                SmimeHandler.getHandler().updateCryptoFlags(msg, m, originalMimeMessage, mm);
            }
        }
        // if the mime it is signed
        if (Mime.isMultipartSigned(mm.getContentType()) || Mime.isPKCS7Signed(mm.getContentType())) {
            ZimbraLog.mailbox.debug("The message is signed. Forwarding it to SmimeHandler for signature verification.");
            if (SmimeHandler.getHandler() != null) {
                SmimeHandler.getHandler().verifyMessageSignature(msg, m, mm, octxt);
            }
        } else {
            // decoded and stored in cache as plain mime
            if ((mm instanceof Mime.FixedMimeMessage) && ((Mime.FixedMimeMessage) mm).isPKCS7Signed()) {
                if (SmimeHandler.getHandler() != null) {
                    SmimeHandler.getHandler().addPKCS7SignedMessageSignatureDetails(msg.getMailbox().getAccount(), m, mm, octxt.getmResponseProtocol());
                }
            }
        }
        return m;
    } catch (IOException ex) {
        throw ServiceException.FAILURE(ex.getMessage(), ex);
    } catch (MessagingException ex) {
        throw ServiceException.FAILURE(ex.getMessage(), ex);
    } finally {
        // don't leave turds around if we're going to retry
        if (!success && !bestEffort && m != null) {
            m.detach();
        }
    }
}
Also used : Account(com.zimbra.cs.account.Account) MessagingException(javax.mail.MessagingException) Element(com.zimbra.common.soap.Element) Calendar(java.util.Calendar) IOException(java.io.IOException) ItemId(com.zimbra.cs.service.util.ItemId) Date(java.util.Date) Mountpoint(com.zimbra.cs.mailbox.Mountpoint) Mime(com.zimbra.cs.mime.Mime) MPartInfo(com.zimbra.cs.mime.MPartInfo) MimeMessage(javax.mail.internet.MimeMessage) MimePart(javax.mail.internet.MimePart) MailServiceException(com.zimbra.cs.mailbox.MailServiceException)

Aggregations

Mime (com.zimbra.cs.mime.Mime)2 IOException (java.io.IOException)2 MessagingException (javax.mail.MessagingException)2 MimeMessage (javax.mail.internet.MimeMessage)2 ServiceException (com.zimbra.common.service.ServiceException)1 Element (com.zimbra.common.soap.Element)1 Account (com.zimbra.cs.account.Account)1 MailServiceException (com.zimbra.cs.mailbox.MailServiceException)1 Mountpoint (com.zimbra.cs.mailbox.Mountpoint)1 ExpandMimeMessage (com.zimbra.cs.mime.ExpandMimeMessage)1 MPartInfo (com.zimbra.cs.mime.MPartInfo)1 ItemId (com.zimbra.cs.service.util.ItemId)1 InputStream (java.io.InputStream)1 Calendar (java.util.Calendar)1 Date (java.util.Date)1 MimePart (javax.mail.internet.MimePart)1