use of com.zimbra.common.zmime.ZMimeBodyPart in project zm-mailbox by Zimbra.
the class Mime method listParts.
private static List<MPartInfo> listParts(MimePart root, String defaultCharset) throws MessagingException, IOException {
List<MPartInfo> parts = new ArrayList<MPartInfo>();
LinkedList<MPartInfo> queue = new LinkedList<MPartInfo>();
queue.add(generateMPartInfo(root, null, "", 0));
MimeMultipart emptyMultipart = null;
while (!queue.isEmpty()) {
MPartInfo mpart = queue.removeFirst();
MimePart mp = mpart.getMimePart();
parts.add(mpart);
String cts = mpart.mContentType;
boolean isMultipart = cts.startsWith(MimeConstants.CT_MULTIPART_PREFIX);
boolean isMessage = !isMultipart && cts.equals(MimeConstants.CT_MESSAGE_RFC822);
if (isMultipart) {
// IMAP part numbering is screwy: top-level multipart doesn't get a number
String prefix = mpart.mPartName.length() > 0 ? (mpart.mPartName + '.') : "";
if (mp instanceof MimeMessage) {
mpart.mPartName = prefix + "TEXT";
}
MimeMultipart multi = getMultipartContent(mp, cts);
if (multi != null) {
if (multi.getCount() == 0 && LC.mime_promote_empty_multipart.booleanValue()) {
if (emptyMultipart == null) {
emptyMultipart = multi;
}
if (MimeConstants.CT_MULTIPART_APPLEDOUBLE.equalsIgnoreCase(getContentType(mp))) {
ZimbraLog.misc.debug("appledouble with no children; assuming it is malformed and really applefile");
mpart.mContentType = mpart.mContentType.replace(MimeConstants.CT_MULTIPART_APPLEDOUBLE, MimeConstants.CT_APPLEFILE);
}
}
mpart.mChildren = new ArrayList<MPartInfo>(multi.getCount());
for (int i = 1; i <= multi.getCount(); i++) {
mpart.mChildren.add(generateMPartInfo((MimePart) multi.getBodyPart(i - 1), mpart, prefix + i, i));
}
queue.addAll(0, mpart.mChildren);
}
} else if (isMessage) {
MimeMessage mm = getMessageContent(mp);
if (mm != null) {
MPartInfo child = generateMPartInfo(mm, mpart, mpart.mPartName, 0);
queue.addFirst(child);
mpart.mChildren = Arrays.asList(child);
}
} else {
// nothing to do at this stage
}
}
if (emptyMultipart != null && parts.size() == 1) {
String text = emptyMultipart.getPreamble();
if (!StringUtil.isNullOrEmpty(text)) {
ZimbraLog.misc.debug("single multipart with no children. promoting the preamble into a single text part");
parts.remove(0);
MPartInfo mpart = new MPartInfo();
ZMimeBodyPart mp = new ZMimeBodyPart();
mp.setText(text, defaultCharset);
mpart.mPart = mp;
mpart.mContentType = mp.getContentType();
mpart.mDisposition = "";
mpart.mPartName = "1";
parts.add(mpart);
}
}
return parts;
}
use of com.zimbra.common.zmime.ZMimeBodyPart in project zm-mailbox by Zimbra.
the class SpamHandler method sendReport.
private void sendReport(SpamReport sr) throws ServiceException, MessagingException {
Config config = Provisioning.getInstance().getConfig();
String isSpamString = sr.isSpam ? config.getSpamReportTypeSpam() : config.getSpamReportTypeHam();
SMTPMessage out = new SMTPMessage(JMSession.getSmtpSession());
Mailbox mbox = MailboxManager.getInstance().getMailboxById(sr.mailboxId);
Message msg = mbox.getMessageById(null, sr.messageId);
MimeMultipart mmp = new ZMimeMultipart("mixed");
MimeBodyPart infoPart = new ZMimeBodyPart();
infoPart.setHeader("Content-Description", "Zimbra spam classification report");
String body = String.format("Classified-By: %s\r\n" + "Classified-As: %s\r\n" + "Action: %s\r\n" + "Source-Folder: %s\r\n" + "Destination-Folder: %s\r\n" + "Destination-Mailbox: %s\r\n", Strings.nullToEmpty(sr.accountName), isSpamString, Strings.nullToEmpty(sr.action), Strings.nullToEmpty(sr.sourceFolder), Strings.nullToEmpty(sr.destFolder), Strings.nullToEmpty(sr.destAccountName));
infoPart.setText(body);
mmp.addBodyPart(infoPart);
MailboxBlob blob = msg.getBlob();
MimeBodyPart mbp = new ZMimeBodyPart();
mbp.setDataHandler(new DataHandler(new MailboxBlobDataSource(blob)));
mbp.setHeader("Content-Type", MimeConstants.CT_MESSAGE_RFC822);
mbp.setHeader("Content-Disposition", Part.ATTACHMENT);
mmp.addBodyPart(mbp);
out.setContent(mmp);
out.addHeader(config.getSpamReportSenderHeader(), sr.accountName);
out.addHeader(config.getSpamReportTypeHeader(), isSpamString);
if (config.isSmtpSendAddOriginatingIP() && sr.origIp != null)
out.addHeader(MailSender.X_ORIGINATING_IP, MailSender.formatXOrigIpHeader(sr.origIp));
out.setRecipient(javax.mail.Message.RecipientType.TO, sr.reportRecipient);
out.setEnvelopeFrom(config.getSpamReportEnvelopeFrom());
out.setSubject(config.getSpamTrainingSubjectPrefix() + " " + sr.accountName + ": " + isSpamString);
Transport.send(out);
ZimbraLog.misc.info("Sent " + sr);
}
use of com.zimbra.common.zmime.ZMimeBodyPart in project zm-mailbox by Zimbra.
the class UUEncodeConverter method visitMessage.
@Override
protected boolean visitMessage(MimeMessage mm, VisitPhase visitKind) throws MessagingException {
// do the decode in the exit phase
if (visitKind != VisitPhase.VISIT_END)
return false;
MimeMultipart mmp = null;
try {
// only check "text/plain" parts for uudecodeable attachments
if (!mm.isMimeType(MimeConstants.CT_TEXT_PLAIN))
return false;
// don't check transfer-encoded parts for uudecodeable attachments
String cte = mm.getHeader("Content-Transfer-Encoding", null);
if (cte != null) {
cte = cte.trim().toLowerCase();
if (!cte.equals(MimeConstants.ET_7BIT) && !cte.equals(MimeConstants.ET_8BIT) && !cte.equals(MimeConstants.ET_BINARY))
return false;
}
List<UUDecodedFile> uufiles = null;
// go through top-level text/plain part and extract uuencoded files
PositionInputStream is = null;
long size;
try {
is = new PositionInputStream(new BufferedInputStream(mm.getInputStream()));
for (int c = is.read(); c != -1; ) {
long start = is.getPosition() - 1;
// check for uuencode header: "begin NNN filename"
if (c == 'b' && (c = is.read()) == 'e' && (c = is.read()) == 'g' && (c = is.read()) == 'i' && (c = is.read()) == 'n' && ((c = is.read()) == ' ' || c == '\t') && Character.isDigit((c = is.read())) && Character.isDigit(c = is.read()) && Character.isDigit(c = is.read()) && ((c = is.read()) == ' ' || c == '\t')) {
StringBuilder sb = new StringBuilder();
while ((c = is.read()) != '\r' && c != '\n' && c != -1) sb.append((char) c);
String filename = FileUtil.trimFilename(sb.toString().trim());
if (c != -1 && filename.length() > 0) {
if (uufiles == null)
uufiles = new ArrayList<UUDecodedFile>(3);
try {
uufiles.add(new UUDecodedFile(is, filename, start));
// check to make sure that the caller's OK with altering the message
if (uufiles.size() == 1 && mCallback != null && !mCallback.onModification())
return false;
} catch (IOException ioe) {
}
}
}
// skip to the beginning of the next line
while (c != '\r' && c != '\n' && c != -1) c = is.read();
while (c == '\r' || c == '\n') c = is.read();
}
size = is.getPosition();
} finally {
ByteUtil.closeStream(is);
}
if (uufiles == null || uufiles.isEmpty())
return false;
// create MimeParts for the extracted files
mmp = new ZMimeMultipart("mixed");
for (UUDecodedFile uu : uufiles) {
MimeBodyPart mbp = new ZMimeBodyPart();
mbp.setHeader("Content-Type", uu.getContentType());
mbp.setHeader("Content-Disposition", new ContentDisposition(Part.ATTACHMENT).setParameter("filename", uu.getFilename()).toString());
mbp.setDataHandler(new DataHandler(uu.getDataSource()));
mmp.addBodyPart(mbp);
size -= uu.getEndOffset() - uu.getStartOffset();
}
// take the remaining text and put it in as the first "related" part
InputStream isOrig = null;
try {
isOrig = mm.getInputStream();
long offset = 0;
ByteArrayOutputStream baos = new ByteArrayOutputStream((int) size);
byte[] buffer = new byte[8192];
for (UUDecodedFile uu : uufiles) {
long count = uu.getStartOffset() - offset, numRead;
while (count > 0 && (numRead = isOrig.read(buffer, 0, (int) Math.min(count, 8192))) >= 0) {
baos.write(buffer, 0, (int) numRead);
count -= numRead;
}
isOrig.skip(uu.getEndOffset() - uu.getStartOffset());
offset = uu.getEndOffset();
}
ByteUtil.copy(isOrig, true, baos, true);
MimeBodyPart mbp = new ZMimeBodyPart();
mbp.setDataHandler(new DataHandler(new ByteArrayDataSource(baos.toByteArray(), MimeConstants.CT_TEXT_PLAIN)));
mmp.addBodyPart(mbp, 0);
} finally {
ByteUtil.closeStream(isOrig);
}
} catch (MessagingException e) {
ZimbraLog.extensions.warn("exception while uudecoding message part; skipping part", e);
return false;
} catch (IOException e) {
ZimbraLog.extensions.warn("exception while uudecoding message part; skipping part", e);
return false;
}
// replace the top-level part with a new multipart/related
mm.setContent(mmp);
mm.setHeader("Content-Type", mmp.getContentType() + "; generated=true");
return true;
}
use of com.zimbra.common.zmime.ZMimeBodyPart in project zm-mailbox by Zimbra.
the class ParseMimeMessage method setContent.
/**
* The <mp>'s from the client and the MimeBodyParts in alternatives[] all want to be "content"
* of this MimeMessage. The alternatives[] all need to be "alternative" to whatever the client sends
* us....but we want to be careful so that we do NOT create a nested multipart/alternative structure
* within another one (that would be very tacky)....so this is a bit complicated.
*/
private static void setContent(MimeMessage mm, MimeMultipart mmp, Element elem, MimeBodyPart[] alternatives, ParseMessageContext ctxt) throws MessagingException, ServiceException, IOException {
String type = elem.getAttribute(MailConstants.A_CONTENT_TYPE, MimeConstants.CT_DEFAULT).trim();
ContentType ctype = new ContentType(type, ctxt.use2231).cleanup();
// is the client passing us a multipart?
if (ctype.getPrimaryType().equals("multipart")) {
// handle multipart content separately...
setMultipartContent(ctype, mm, mmp, elem, alternatives, ctxt);
return;
}
Element inline = elem.getOptionalElement(MailConstants.E_ATTACH);
if (inline != null) {
handleAttachments(inline, mmp, ctxt, elem.getAttribute(MailConstants.A_CONTENT_ID, null), Part.INLINE);
return;
}
if (alternatives != null) {
// create a multipart/alternative to hold all the alternatives
MimeMultipart mmpNew = new ZMimeMultipart("alternative");
if (mmp == null) {
mm.setContent(mmpNew);
} else {
MimeBodyPart mbpWrapper = new ZMimeBodyPart();
mbpWrapper.setContent(mmpNew);
mmp.addBodyPart(mbpWrapper);
}
mmp = mmpNew;
}
// once we get here, mmp is either NULL, a multipart/mixed from the toplevel,
// or a multipart/alternative created just above....either way we are safe to stick
// the client's nice and simple body right here
String text = elem.getAttribute(MailConstants.E_CONTENT, "");
byte[] raw = text.getBytes(Charsets.UTF_8);
if (raw.length > 0 || !LC.mime_exclude_empty_content.booleanValue() || ctype.getPrimaryType().equals("text")) {
ctxt.incrementSize("message body", raw.length);
// if the user has specified an alternative charset, make sure it exists and can encode the content
String charset = CharsetUtil.checkCharset(text, ctxt.defaultCharset);
ctype.setCharset(charset).setParameter(MimeConstants.P_CHARSET, charset);
Object content = ctype.getContentType().equals(ContentType.MESSAGE_RFC822) ? new ZMimeMessage(JMSession.getSession(), new SharedByteArrayInputStream(raw)) : text;
if (mmp != null) {
MimeBodyPart mbp = new ZMimeBodyPart();
mbp.setContent(content, ctype.toString());
mmp.addBodyPart(mbp);
} else {
mm.setContent(content, ctype.toString());
}
}
if (alternatives != null) {
for (int i = 0; i < alternatives.length; i++) {
ctxt.incrementSize("alternative body", alternatives[i].getSize());
mmp.addBodyPart(alternatives[i]);
}
}
}
use of com.zimbra.common.zmime.ZMimeBodyPart in project zm-mailbox by Zimbra.
the class ParseMimeMessage method attachDocument.
private static void attachDocument(MimeMultipart mmp, Document doc, String contentID, ParseMessageContext ctxt) throws MessagingException, ServiceException {
ctxt.incrementSize("attached document", (long) (doc.getSize() * 1.33));
ContentType ct = new ContentType(doc.getContentType());
if (MimeConstants.isZimbraDocument(ct.getContentType())) {
ct = new ContentType(MimeConstants.CT_TEXT_HTML);
}
MimeBodyPart mbp = new ZMimeBodyPart();
mbp.setDataHandler(new DataHandler(new MailboxBlobDataSource(doc.getBlob(), ct.getContentType())));
mbp.setHeader("Content-Type", ct.cleanup().setParameter("name", doc.getName()).setCharset(ctxt.defaultCharset).toString());
mbp.setHeader("Content-Disposition", new ContentDisposition(Part.ATTACHMENT).setParameter("filename", doc.getName()).toString());
mbp.setContentID(contentID);
mmp.addBodyPart(mbp);
}
Aggregations