Search in sources :

Example 1 with ContentType

use of com.zimbra.common.mime.ContentType in project zm-mailbox by Zimbra.

the class ParseMimeMessageTest method attachZimbraDocument.

@Test
public void attachZimbraDocument() throws Exception {
    Account acct = Provisioning.getInstance().getAccount(MockProvisioning.DEFAULT_ACCOUNT_ID);
    Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(acct);
    OperationContext octxt = new OperationContext(acct);
    Document doc = mbox.createDocument(octxt, Mailbox.ID_FOLDER_BRIEFCASE, "testdoc", MimeConstants.CT_APPLICATION_ZIMBRA_DOC, "author", "description", new ByteArrayInputStream("test123".getBytes()));
    Element el = new Element.JSONElement(MailConstants.E_MSG);
    el.addAttribute(MailConstants.E_SUBJECT, "attach message");
    el.addElement(MailConstants.E_EMAIL).addAttribute(MailConstants.A_ADDRESS_TYPE, EmailType.TO.toString()).addAttribute(MailConstants.A_ADDRESS, "rcpt@zimbra.com");
    el.addElement(MailConstants.E_MIMEPART).addAttribute(MailConstants.A_CONTENT_TYPE, "text/plain").addAttribute(MailConstants.E_CONTENT, "This is the content.");
    el.addElement(MailConstants.E_ATTACH).addElement(MailConstants.E_DOC).addAttribute(MailConstants.A_ID, doc.getId());
    ZimbraSoapContext zsc = getMockSoapContext();
    MimeMessage mm = ParseMimeMessage.parseMimeMsgSoap(zsc, octxt, null, el, null, new ParseMimeMessage.MimeMessageData());
    MimeMultipart mmp = (MimeMultipart) mm.getContent();
    MimeBodyPart part = (MimeBodyPart) mmp.getBodyPart(1);
    Assert.assertEquals(MimeConstants.CT_TEXT_HTML, new ContentType(part.getContentType()).getContentType());
}
Also used : OperationContext(com.zimbra.cs.mailbox.OperationContext) Account(com.zimbra.cs.account.Account) ContentType(com.zimbra.common.mime.ContentType) Element(com.zimbra.common.soap.Element) Document(com.zimbra.cs.mailbox.Document) Mailbox(com.zimbra.cs.mailbox.Mailbox) ByteArrayInputStream(java.io.ByteArrayInputStream) MimeMessage(javax.mail.internet.MimeMessage) MimeMultipart(javax.mail.internet.MimeMultipart) ZimbraSoapContext(com.zimbra.soap.ZimbraSoapContext) MimeBodyPart(javax.mail.internet.MimeBodyPart) Test(org.junit.Test)

Example 2 with ContentType

use of com.zimbra.common.mime.ContentType in project zm-mailbox by Zimbra.

the class ParsedMessage method analyzePart.

/**
 * @return Extracted toplevel text (any text that should go into the toplevel indexed document)
 */
private String analyzePart(boolean isMainBody, MPartInfo mpi) throws MessagingException, ServiceException {
    boolean ignoreCalendar;
    if (calendarPartInfo == null) {
        ignoreCalendar = isBouncedCalendar(mpi);
    } else {
        ignoreCalendar = true;
    }
    String methodParam = (new ContentType(mpi.getMimePart().getContentType())).getParameter("method");
    if (methodParam == null && !LC.calendar_allow_invite_without_method.booleanValue()) {
        ignoreCalendar = true;
    }
    String toRet = "";
    try {
        // ignore multipart "container" parts
        if (mpi.isMultipart()) {
            return toRet;
        }
        String ctype = mpi.getContentType();
        MimeHandler handler = MimeHandlerManager.getMimeHandler(ctype, mpi.getFilename());
        assert (handler != null);
        handler.setDefaultCharset(defaultCharset);
        Mime.repairTransferEncoding(mpi.getMimePart());
        if (handler.isIndexingEnabled()) {
            handler.init(mpi.getMimePart().getDataHandler().getDataSource());
            handler.setPartName(mpi.getPartName());
            handler.setFilename(mpi.getFilename());
            handler.setSize(mpi.getSize());
            // remember the first iCalendar attachment
            if (!ignoreCalendar && calendarPartInfo == null) {
                ZVCalendar cal = handler.getICalendar();
                if (cal != null) {
                    setCalendarPartInfo(mpi, cal);
                }
            }
            // - IndexAttachments was set and !disableIndexingAttachmentsTogether
            if ((isMainBody && (!handler.runsExternally() || indexAttachments)) || (indexAttachments && !DebugConfig.disableIndexingAttachmentsTogether)) {
                toRet = handler.getContent();
            }
            if (indexAttachments && !DebugConfig.disableIndexingAttachmentsSeparately) {
                // Each non-text MIME part is also indexed as a separate
                // Lucene document.  This is necessary so that we can tell the
                // client what parts match if a search matched a particular
                // part.
                IndexDocument doc = new IndexDocument(handler.getDocument());
                String filename = handler.getFilename();
                if (!Strings.isNullOrEmpty(filename)) {
                    filenames.add(filename);
                }
                doc.addSortSize(mpi.getMimePart().getSize());
                luceneDocuments.add(setLuceneHeadersFromContainer(doc));
            }
        }
        // make sure we've got the text/calendar handler installed
        if (!ignoreCalendar && calendarPartInfo == null && ctype.equals(MimeConstants.CT_TEXT_CALENDAR)) {
            if (handler.isIndexingEnabled()) {
                ZimbraLog.index.warn("TextCalendarHandler not correctly installed");
            }
            InputStream is = null;
            try {
                String charset = mpi.getContentTypeParameter(MimeConstants.P_CHARSET);
                if (charset == null || charset.trim().isEmpty()) {
                    charset = MimeConstants.P_CHARSET_DEFAULT;
                }
                is = mpi.getMimePart().getInputStream();
                ZVCalendar cal = ZCalendarBuilder.build(is, charset);
                if (cal != null) {
                    setCalendarPartInfo(mpi, cal);
                }
            } catch (IOException ioe) {
                ZimbraLog.index.warn("error reading text/calendar mime part", ioe);
            } finally {
                ByteUtil.closeStream(is);
            }
        }
    } catch (MimeHandlerException e) {
        handleParseError(mpi, e);
    } catch (ObjectHandlerException e) {
        handleParseError(mpi, e);
    }
    return toRet;
}
Also used : IndexDocument(com.zimbra.cs.index.IndexDocument) ZVCalendar(com.zimbra.common.calendar.ZCalendar.ZVCalendar) ContentType(com.zimbra.common.mime.ContentType) GZIPInputStream(java.util.zip.GZIPInputStream) SharedInputStream(javax.mail.internet.SharedInputStream) SharedByteArrayInputStream(javax.mail.util.SharedByteArrayInputStream) BlobInputStream(com.zimbra.cs.store.BlobInputStream) FileInputStream(java.io.FileInputStream) InputStream(java.io.InputStream) IOException(java.io.IOException) ObjectHandlerException(com.zimbra.cs.object.ObjectHandlerException)

Example 3 with ContentType

use of com.zimbra.common.mime.ContentType in project zm-mailbox by Zimbra.

the class ImapMessage method serializeStructure.

static void serializeStructure(PrintStream ps, MimeMessage root, boolean extensions) throws IOException, MessagingException {
    LinkedList<LinkedList<MPartInfo>> queue = new LinkedList<LinkedList<MPartInfo>>();
    LinkedList<MPartInfo> level = new LinkedList<MPartInfo>();
    level.add(Mime.getParts(root).get(0));
    queue.add(level);
    boolean pop = false;
    while (!queue.isEmpty()) {
        level = queue.getLast();
        if (level.isEmpty()) {
            queue.removeLast();
            pop = true;
            continue;
        }
        MPartInfo mpi = level.getFirst();
        MimePart mp = mpi.getMimePart();
        boolean hasChildren = mpi.getChildren() != null && !mpi.getChildren().isEmpty();
        // we used to force unset charsets on text/plain parts to US-ASCII, but that always seemed unwise...
        ContentType ctype = new ContentType(mp.getHeader("Content-Type", null)).setContentType(mpi.getContentType());
        String primary = nATOM(ctype.getPrimaryType()), subtype = nATOM(ctype.getSubType());
        if (!pop)
            ps.write('(');
        if (primary.equals("\"MULTIPART\"")) {
            if (!pop) {
                // list is the multipart subtype (mixed, digest, parallel, alternative, etc.)."
                if (!hasChildren) {
                    ps.print("NIL");
                } else {
                    queue.addLast(new LinkedList<MPartInfo>(mpi.getChildren()));
                    continue;
                }
            }
            ps.write(' ');
            ps.print(subtype);
            if (extensions) {
                // 7.4.2: "Extension data follows the multipart subtype.  Extension data is never
                // returned with the BODY fetch, but can be returned with a BODYSTRUCTURE
                // fetch.  Extension data, if present, MUST be in the defined order.  The
                // extension data of a multipart body part are in the following order:
                // body parameter parenthesized list, body disposition, body language,
                // body location"
                ps.write(' ');
                nparams(ps, ctype);
                ps.write(' ');
                ndisposition(ps, mp.getHeader("Content-Disposition", null));
                ps.write(' ');
                nlist(ps, mp.getContentLanguage());
                ps.write(' ');
                nstring(ps, mp.getHeader("Content-Location", null));
            }
        } else {
            if (!pop) {
                // 7.4.2: "The basic fields of a non-multipart body part are in the following order:
                // body type, body subtype, body parameter parenthesized list, body id, body
                // description, body encoding, body size."
                String cte = mp.getEncoding();
                cte = (cte == null || cte.trim().equals("") ? "7bit" : cte);
                aSTRING(ps, ctype.getPrimaryType());
                ps.write(' ');
                aSTRING(ps, ctype.getSubType());
                ps.write(' ');
                nparams(ps, ctype);
                ps.write(' ');
                nstring(ps, mp.getContentID());
                ps.write(' ');
                nstring2047(ps, mp.getDescription());
                ps.write(' ');
                aSTRING(ps, cte);
                ps.write(' ');
                ps.print(Math.max(mp.getSize(), 0));
            }
            boolean rfc822 = primary.equals("\"MESSAGE\"") && subtype.equals("\"RFC822\"");
            if (rfc822) {
                // size in text lines of the encapsulated message."
                if (!pop) {
                    if (!hasChildren) {
                        ps.print(" NIL NIL");
                    } else {
                        MimeMessage mm = (MimeMessage) mpi.getChildren().get(0).getMimePart();
                        ps.write(' ');
                        serializeEnvelope(ps, mm);
                        ps.write(' ');
                        queue.addLast(new LinkedList<MPartInfo>(mpi.getChildren()));
                        continue;
                    }
                }
                ps.write(' ');
                ps.print(getLineCount(mp));
            } else if (primary.equals("\"TEXT\"")) {
                // 7.4.2: "A body type of type TEXT contains, immediately after the basic fields, the
                // size of the body in text lines.  Note that this size is the size in its
                // content transfer encoding and not the resulting size after any decoding."
                ps.write(' ');
                ps.print(getLineCount(mp));
            }
            if (extensions) {
                // 7.4.2: "Extension data follows the basic fields and the type-specific fields
                // listed above.  Extension data is never returned with the BODY fetch,
                // but can be returned with a BODYSTRUCTURE fetch.  Extension data, if
                // present, MUST be in the defined order.  The extension data of a
                // non-multipart body part are in the following order: body MD5, body
                // disposition, body language, body location"
                ps.write(' ');
                nstring(ps, mp.getContentMD5());
                ps.write(' ');
                ndisposition(ps, mp.getHeader("Content-Disposition", null));
                ps.write(' ');
                nlist(ps, mp.getContentLanguage());
                ps.write(' ');
                nstring(ps, mp.getHeader("Content-Location", null));
            }
        }
        ps.write(')');
        level.removeFirst();
        pop = false;
    }
}
Also used : MPartInfo(com.zimbra.cs.mime.MPartInfo) ContentType(com.zimbra.common.mime.ContentType) MimeMessage(javax.mail.internet.MimeMessage) MimePart(javax.mail.internet.MimePart) LinkedList(java.util.LinkedList)

Example 4 with ContentType

use of com.zimbra.common.mime.ContentType in project zm-mailbox by Zimbra.

the class ToXML method addPart.

private static Element addPart(VisitPhase phase, Element parent, Element root, MPartInfo mpi, Set<MPartInfo> bodies, String prefix, int maxSize, boolean neuter, boolean excludeCalendarParts, String defaultCharset, boolean swallowContentExceptions, MsgContent wantContent) throws ServiceException {
    if (phase == VisitPhase.POSTVISIT) {
        return null;
    }
    String ctype = StringUtil.stripControlCharacters(mpi.getContentType());
    if (excludeCalendarParts && MimeConstants.CT_TEXT_CALENDAR.equalsIgnoreCase(ctype)) {
        // that happens to be a .ics file.
        try {
            ContentType ct = new ContentType(mpi.getMimePart().getContentType());
            if (ct.getParameter("method") != null) {
                return null;
            }
        } catch (MessagingException e) {
        }
    }
    Element el = parent.addNonUniqueElement(MailConstants.E_MIMEPART);
    MimePart mp = mpi.getMimePart();
    String part = mpi.getPartName();
    part = prefix + (prefix.isEmpty() || part.isEmpty() ? "" : ".") + part;
    el.addAttribute(MailConstants.A_PART, part);
    String fname = Mime.getFilename(mp);
    if (MimeConstants.CT_XML_ZIMBRA_SHARE.equals(ctype)) {
        // the <shr> share info goes underneath the top-level <m>
        Element shr = root.addNonUniqueElement(MailConstants.E_SHARE_NOTIFICATION);
        try {
            addContent(shr, mpi, maxSize, defaultCharset);
        } catch (IOException e) {
            if (!swallowContentExceptions) {
                throw ServiceException.FAILURE("error serializing share XML", e);
            } else {
                LOG.warn("error writing body part", e);
            }
        } catch (MessagingException e) {
            if (!swallowContentExceptions) {
                throw ServiceException.FAILURE("error serializing share XML", e);
            }
        }
    } else if (MimeConstants.CT_XML_ZIMBRA_DL_SUBSCRIPTION.equals(ctype)) {
        // the <dlSubs> dl subscription info goes underneath the top-level <m>
        Element dlSubs = root.addNonUniqueElement(MailConstants.E_DL_SUBSCRIPTION_NOTIFICATION);
        try {
            addContent(dlSubs, mpi, maxSize, defaultCharset);
        } catch (IOException e) {
            if (!swallowContentExceptions) {
                throw ServiceException.FAILURE("error serializing DL subscription", e);
            } else {
                LOG.warn("error writing body part", e);
            }
        } catch (MessagingException e) {
            if (!swallowContentExceptions) {
                throw ServiceException.FAILURE("error serializing DL subscription", e);
            }
        }
    } else if (MimeConstants.CT_TEXT_ENRICHED.equals(ctype)) {
        // we'll be replacing text/enriched with text/html
        ctype = MimeConstants.CT_TEXT_HTML;
    } else if (fname != null && (MimeConstants.CT_APPLICATION_OCTET_STREAM.equals(ctype) || MimeConstants.CT_APPLICATION_TNEF.equals(ctype))) {
        String guess = MimeDetect.getMimeDetect().detect(fname);
        if (guess != null) {
            ctype = guess;
        }
    }
    el.addAttribute(MailConstants.A_CONTENT_TYPE, ctype);
    if (mpi.isMultipart()) {
        // none of the below stuff is relevant for a multipart, so just return now...
        return el;
    }
    // figure out attachment size
    try {
        el.addAttribute(MailConstants.A_SIZE, Mime.getSize(mp));
    } catch (Exception e) {
        // don't put out size if we get exception
        ZimbraLog.mailbox.warn("Unable to determine MIME part size: %s", e.getMessage());
    }
    // figure out attachment disposition
    try {
        String disp = mp.getHeader("Content-Disposition", null);
        if (disp != null) {
            ContentDisposition cdisp = new ContentDisposition(MimeUtility.decodeText(disp));
            el.addAttribute(MailConstants.A_CONTENT_DISPOSITION, StringUtil.stripControlCharacters(cdisp.getDisposition()));
        }
    } catch (MessagingException e) {
    } catch (UnsupportedEncodingException e) {
    }
    // figure out attachment name
    try {
        if (fname == null && MimeConstants.CT_MESSAGE_RFC822.equals(ctype)) {
            // "filename" for attached messages is the Subject
            Object content = Mime.getMessageContent(mp);
            if (content instanceof MimeMessage) {
                fname = Mime.getSubject((MimeMessage) content);
            }
        }
        if (!Strings.isNullOrEmpty(fname)) {
            el.addAttribute(MailConstants.A_CONTENT_FILENAME, StringUtil.stripControlCharacters(fname));
        }
    } catch (MessagingException me) {
    } catch (IOException ioe) {
    }
    // figure out content-id (used in displaying attached images)
    String cid = mpi.getContentID();
    if (cid != null) {
        el.addAttribute(MailConstants.A_CONTENT_ID, StringUtil.stripControlCharacters(cid));
    }
    // figure out content-location (used in displaying attached images)
    try {
        String cl = mp.getHeader("Content-Location", null);
        if (cl != null) {
            el.addAttribute(MailConstants.A_CONTENT_LOCATION, StringUtil.stripControlCharacters(cl));
        }
    } catch (MessagingException e) {
    }
    // or if it was requested to include all parts
    if (bodies == null || bodies.contains(mpi)) {
        if (bodies != null) {
            el.addAttribute(MailConstants.A_BODY, true);
        }
        try {
            addContent(el, mpi, maxSize, neuter, defaultCharset, wantContent);
        } catch (IOException e) {
            if (!swallowContentExceptions) {
                throw ServiceException.FAILURE("error serializing part content", e);
            } else {
                LOG.warn("error writing body part", e);
            }
        } catch (MessagingException me) {
            if (!swallowContentExceptions) {
                throw ServiceException.FAILURE("error serializing part content", me);
            }
        }
    }
    return el;
}
Also used : ContentType(com.zimbra.common.mime.ContentType) ContentDisposition(com.zimbra.common.mime.ContentDisposition) MessagingException(javax.mail.MessagingException) MimeMessage(javax.mail.internet.MimeMessage) Element(com.zimbra.common.soap.Element) MimePart(javax.mail.internet.MimePart) UnsupportedEncodingException(java.io.UnsupportedEncodingException) IOException(java.io.IOException) JSONException(org.json.JSONException) NoSuchItemException(com.zimbra.cs.mailbox.MailServiceException.NoSuchItemException) ServiceException(com.zimbra.common.service.ServiceException) IOException(java.io.IOException) MailServiceException(com.zimbra.cs.mailbox.MailServiceException) MessagingException(javax.mail.MessagingException) UnsupportedEncodingException(java.io.UnsupportedEncodingException)

Example 5 with ContentType

use of com.zimbra.common.mime.ContentType in project zm-mailbox by Zimbra.

the class ParseMimeMessage method attachPart.

private static void attachPart(MimeMultipart mmp, ItemId iid, String part, String contentID, ParseMessageContext ctxt, String contentDisposition) throws IOException, MessagingException, ServiceException {
    if (!iid.isLocal()) {
        Map<String, String> params = new HashMap<String, String>(3);
        params.put(UserServlet.QP_PART, part);
        attachRemoteItem(mmp, iid, contentID, ctxt, params, null);
        return;
    }
    Mailbox mbox = MailboxManager.getInstance().getMailboxByAccountId(iid.getAccountId());
    MimeMessage mm;
    if (iid.hasSubpart()) {
        mm = mbox.getCalendarItemById(ctxt.octxt, iid.getId()).getSubpartMessage(iid.getSubpartId());
    } else {
        mm = mbox.getMessageById(ctxt.octxt, iid.getId()).getMimeMessage();
    }
    MimePart mp = Mime.getMimePart(mm, part);
    if (mp == null) {
        throw MailServiceException.NO_SUCH_PART(part);
    }
    String filename = Mime.getFilename(mp);
    String ctypeHdr = mp.getContentType(), contentType = null;
    if (ctypeHdr != null) {
        contentType = new ContentType(ctypeHdr, ctxt.use2231).cleanup().setCharset(ctxt.defaultCharset).setParameter("name", filename).toString();
    }
    // bug 70015: two concurrent SaveDrafts each reference the same attachment in the original draft
    // -- avoid race condition by copying attached part to FileUploadServlet, so
    // deleting original blob doesn't lead to stale BlobInputStream references
    Upload up = FileUploadServlet.saveUpload(mp.getInputStream(), filename, contentType, DocumentHandler.getRequestedAccount(ctxt.zsc).getId());
    ctxt.out.addFetch(up);
    String[] contentDesc = mp.getHeader("Content-Description");
    attachUpload(mmp, up, contentID, ctxt, null, (contentDesc == null || contentDesc.length == 0) ? null : contentDesc[0], contentDisposition);
}
Also used : Mailbox(com.zimbra.cs.mailbox.Mailbox) ContentType(com.zimbra.common.mime.ContentType) HashMap(java.util.HashMap) ZMimeMessage(com.zimbra.common.zmime.ZMimeMessage) MimeMessage(javax.mail.internet.MimeMessage) MimePart(javax.mail.internet.MimePart) Upload(com.zimbra.cs.service.FileUploadServlet.Upload)

Aggregations

ContentType (com.zimbra.common.mime.ContentType)20 MimeBodyPart (javax.mail.internet.MimeBodyPart)8 MimeMessage (javax.mail.internet.MimeMessage)8 ContentDisposition (com.zimbra.common.mime.ContentDisposition)7 ZMimeBodyPart (com.zimbra.common.zmime.ZMimeBodyPart)6 Mailbox (com.zimbra.cs.mailbox.Mailbox)6 IOException (java.io.IOException)6 ServiceException (com.zimbra.common.service.ServiceException)5 InputStream (java.io.InputStream)5 Element (com.zimbra.common.soap.Element)4 ZMimeMessage (com.zimbra.common.zmime.ZMimeMessage)4 MimeMultipart (javax.mail.internet.MimeMultipart)4 MimePart (javax.mail.internet.MimePart)4 Account (com.zimbra.cs.account.Account)3 Document (com.zimbra.cs.mailbox.Document)3 MailServiceException (com.zimbra.cs.mailbox.MailServiceException)3 Message (com.zimbra.cs.mailbox.Message)3 ByteArrayInputStream (java.io.ByteArrayInputStream)3 MessagingException (javax.mail.MessagingException)3 ZVCalendar (com.zimbra.common.calendar.ZCalendar.ZVCalendar)2