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());
}
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;
}
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;
}
}
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;
}
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);
}
Aggregations