use of javax.mail.MessagingException in project zm-mailbox by Zimbra.
the class RemoveAttachments method handle.
@Override
public Element handle(Element request, Map<String, Object> context) throws ServiceException {
ZimbraSoapContext zsc = getZimbraSoapContext(context);
Mailbox mbox = getRequestedMailbox(zsc);
OperationContext octxt = getOperationContext(zsc, context);
ItemIdFormatter ifmt = new ItemIdFormatter(zsc);
Element msgElem = request.getElement(MailConstants.E_MSG);
ItemId iid = new ItemId(msgElem.getAttribute(MailConstants.A_ID), zsc);
Collection<String> parts = sortPartIds(msgElem.getAttribute(MailConstants.A_PART));
Message msg = mbox.getMessageById(octxt, iid.getId());
InputStream is = null;
try {
MimeMessage mm = new Mime.FixedMimeMessage(JMSession.getSession(), is = StoreManager.getInstance().getContent(msg.getBlob().getLocalBlob()));
// do not allow removing attachments of encrypted/pkcs7-signed messages
if (Mime.isEncrypted(mm.getContentType()) || Mime.isPKCS7Signed(mm.getContentType())) {
throw ServiceException.OPERATION_DENIED("not allowed to remove attachments of encrypted/pkcs7-signed message");
}
for (String part : parts) stripPart(mm, part);
mm.saveChanges();
ParsedMessage pm = new ParsedMessage(mm, msg.getDate(), mbox.attachmentsIndexingEnabled());
msg = removeAttachmentOperation(mbox, octxt, pm, msg);
} catch (IOException ioe) {
throw ServiceException.FAILURE("error reading existing message blob", ioe);
} catch (MessagingException me) {
throw ServiceException.FAILURE("error reading existing message blob", me);
} finally {
ByteUtil.closeStream(is);
}
Element response = zsc.createElement(MailConstants.REMOVE_ATTACHMENTS_RESPONSE);
// FIXME: inefficient -- this recalculates the MimeMessage (but RemoveAttachments is called rarely)
ToXML.encodeMessageAsMP(response, ifmt, octxt, msg, null, -1, true, true, null, true, false, LC.mime_encode_missing_blob.booleanValue());
return response;
}
use of javax.mail.MessagingException in project zm-mailbox by Zimbra.
the class SaveDraft method handle.
@Override
public Element handle(Element request, Map<String, Object> context) throws ServiceException {
ZimbraSoapContext zsc = getZimbraSoapContext(context);
Mailbox mbox = getRequestedMailbox(zsc);
OperationContext octxt = getOperationContext(zsc, context);
ItemIdFormatter ifmt = new ItemIdFormatter(zsc);
Element msgElem = request.getElement(MailConstants.E_MSG);
int id = (int) msgElem.getAttributeLong(MailConstants.A_ID, Mailbox.ID_AUTO_INCREMENT);
String originalId = msgElem.getAttribute(MailConstants.A_ORIG_ID, null);
ItemId iidOrigid = originalId == null ? null : new ItemId(originalId, zsc);
String replyType = msgElem.getAttribute(MailConstants.A_REPLY_TYPE, null);
String identity = msgElem.getAttribute(MailConstants.A_IDENTITY_ID, null);
String account = msgElem.getAttribute(MailConstants.A_FOR_ACCOUNT, null);
// allow the caller to update the draft's metadata at the same time as they save the draft
String folderId = msgElem.getAttribute(MailConstants.A_FOLDER, null);
ItemId iidFolder = new ItemId(folderId == null ? "-1" : folderId, zsc);
if (!iidFolder.belongsTo(mbox)) {
throw ServiceException.INVALID_REQUEST("cannot move item between mailboxes", null);
} else if (folderId != null && iidFolder.getId() <= 0) {
throw MailServiceException.NO_SUCH_FOLDER(iidFolder.getId());
}
String flags = msgElem.getAttribute(MailConstants.A_FLAGS, null);
String[] tags = TagUtil.parseTags(msgElem, mbox, octxt);
Color color = ItemAction.getColor(msgElem);
// check to see whether the entire message has been uploaded under separate cover
String attachment = msgElem.getAttribute(MailConstants.A_ATTACHMENT_ID, null);
long autoSendTime = new Long(msgElem.getAttribute(MailConstants.A_AUTO_SEND_TIME, "0"));
ParseMimeMessage.MimeMessageData mimeData = new ParseMimeMessage.MimeMessageData();
Message msg;
try {
MimeMessage mm;
if (attachment != null) {
mm = SendMsg.parseUploadedMessage(zsc, attachment, mimeData);
} else {
mm = ParseMimeMessage.parseMimeMsgSoap(zsc, octxt, mbox, msgElem, null, mimeData, true);
}
long date = System.currentTimeMillis();
try {
Date d = new Date();
mm.setSentDate(d);
date = d.getTime();
} catch (Exception ignored) {
}
try {
mm.saveChanges();
} catch (MessagingException me) {
throw ServiceException.FAILURE("completing MIME message object", me);
}
ParsedMessage pm = new ParsedMessage(mm, date, mbox.attachmentsIndexingEnabled());
if (autoSendTime != 0) {
AccountUtil.checkQuotaWhenSendMail(mbox);
}
String origid = iidOrigid == null ? null : iidOrigid.toString(account == null ? mbox.getAccountId() : account);
msg = mbox.saveDraft(octxt, pm, id, origid, replyType, identity, account, autoSendTime);
} catch (IOException e) {
throw ServiceException.FAILURE("IOException while saving draft", e);
} finally {
// purge the messages fetched from other servers.
if (mimeData.fetches != null) {
FileUploadServlet.deleteUploads(mimeData.fetches);
}
}
// we can now purge the uploaded attachments
if (mimeData.uploads != null) {
FileUploadServlet.deleteUploads(mimeData.uploads);
}
// try to set the metadata on the new/revised draft
if (folderId != null || flags != null || !ArrayUtil.isEmpty(tags) || color != null) {
try {
// best not to fail if there's an error here...
ItemActionHelper.UPDATE(octxt, mbox, zsc.getResponseProtocol(), Arrays.asList(msg.getId()), MailItem.Type.MESSAGE, null, null, iidFolder, flags, tags, color);
// and make sure the Message object reflects post-update reality
msg = mbox.getMessageById(octxt, msg.getId());
} catch (ServiceException e) {
ZimbraLog.soap.warn("error setting metadata for draft " + msg.getId() + "; skipping that operation", e);
}
}
if (schedulesAutoSendTask()) {
if (id != Mailbox.ID_AUTO_INCREMENT) {
// Cancel any existing auto-send task for this draft
AutoSendDraftTask.cancelTask(id, mbox.getId());
}
if (autoSendTime != 0) {
// schedule a new auto-send-draft task
AutoSendDraftTask.scheduleTask(msg.getId(), mbox.getId(), autoSendTime);
}
}
return generateResponse(zsc, ifmt, octxt, mbox, msg);
}
use of javax.mail.MessagingException in project zm-mailbox by Zimbra.
the class SendDeliveryReport method sendReport.
public static void sendReport(Account authAccount, Message msg, boolean automatic, String requestHost, String userAgent) throws ServiceException {
MimeMessage mm = msg.getMimeMessage();
Account owner = msg.getMailbox().getAccount();
String charset = authAccount.getPrefMailDefaultCharset();
if (charset == null) {
charset = MimeConstants.P_CHARSET_UTF8;
}
try {
InternetAddress[] recipients = Mime.parseAddressHeader(mm, "Disposition-Notification-To");
if (recipients == null || recipients.length == 0)
return;
SMTPMessage report = new SMTPMessage(JMSession.getSmtpSession());
String subject = "Read-Receipt: " + msg.getSubject();
report.setSubject(subject, CharsetUtil.checkCharset(subject, charset));
report.setSentDate(new Date());
report.setFrom(AccountUtil.getFriendlyEmailAddress(authAccount));
report.addRecipients(javax.mail.Message.RecipientType.TO, recipients);
report.setHeader("Auto-Submitted", "auto-replied (zimbra; read-receipt)");
report.setHeader("Precedence", "bulk");
if (Provisioning.getInstance().getConfig().isAutoSubmittedNullReturnPath()) {
report.setEnvelopeFrom("<>");
} else {
report.setEnvelopeFrom(authAccount.getName());
}
MimeMultipart multi = new ZMimeMultipart("report");
// part 1: human-readable notification
String text = generateTextPart(owner, mm, authAccount.getLocale());
MimeBodyPart mpText = new ZMimeBodyPart();
mpText.setText(text, CharsetUtil.checkCharset(text, charset));
multi.addBodyPart(mpText);
// part 2: disposition notification
String mdn = generateReport(owner, mm, automatic, requestHost, userAgent);
MimeBodyPart mpMDN = new ZMimeBodyPart();
mpMDN.setText(mdn, MimeConstants.P_CHARSET_UTF8);
mpMDN.setHeader("Content-Type", "message/disposition-notification; charset=utf-8");
multi.addBodyPart(mpMDN);
// // part 3: original message
// MimeBodyPart mpOriginal = new ZMimeBodyPart();
// mpOriginal.setDataHandler(new DataHandler(new BlobDataSource(msg.getBlob())));
// mpOriginal.setHeader("Content-Type", MimeConstants.CT_MESSAGE_RFC822);
// mpOriginal.setHeader("Content-Disposition", Part.ATTACHMENT);
// multi.addBodyPart(mpOriginal);
report.setContent(multi);
report.setHeader("Content-Type", multi.getContentType() + "; report-type=disposition-notification");
report.saveChanges();
Transport.send(report);
} catch (MessagingException me) {
throw ServiceException.FAILURE("error while sending read receipt", me);
}
}
use of javax.mail.MessagingException in project zm-mailbox by Zimbra.
the class SendMsg method doSendMessage.
public static ItemId doSendMessage(OperationContext oc, Mailbox mbox, MimeMessage mm, List<Upload> uploads, ItemId origMsgId, String replyType, String identityId, String dataSourceId, boolean noSaveToSent, boolean needCalendarSentByFixup, boolean isCalendarForward) throws ServiceException {
boolean isCalendarMessage = false;
ItemId id;
OutlookICalendarFixupMimeVisitor mv = null;
if (needCalendarSentByFixup || isCalendarForward) {
mv = new OutlookICalendarFixupMimeVisitor(mbox.getAccount(), mbox).needFixup(needCalendarSentByFixup).setIsCalendarForward(isCalendarForward);
try {
mv.accept(mm);
} catch (MessagingException e) {
throw ServiceException.PARSE_ERROR("Error while fixing up SendMsg for SENT-BY", e);
}
isCalendarMessage = mv.isCalendarMessage();
}
MailSender sender;
if (dataSourceId == null) {
sender = isCalendarMessage ? CalendarMailSender.getCalendarMailSender(mbox) : mbox.getMailSender();
if (noSaveToSent) {
id = sender.sendMimeMessage(oc, mbox, false, mm, uploads, origMsgId, replyType, null, false, processor);
} else {
id = sender.sendMimeMessage(oc, mbox, mm, uploads, origMsgId, replyType, identityId, false, processor);
}
} else {
com.zimbra.cs.account.DataSource dataSource = mbox.getAccount().getDataSourceById(dataSourceId);
if (dataSource == null) {
throw ServiceException.INVALID_REQUEST("No data source with id " + dataSourceId, null);
}
if (!dataSource.isSmtpEnabled()) {
throw ServiceException.INVALID_REQUEST("Data source SMTP is not enabled", null);
}
sender = mbox.getDataSourceMailSender(dataSource, isCalendarMessage);
id = sender.sendDataSourceMimeMessage(oc, mbox, mm, uploads, origMsgId, replyType);
}
// Send Calendar Forward Invitation notification if applicable
try {
if (isCalendarMessage && isCalendarForward && mv.getOriginalInvite() != null) {
ZOrganizer org = mv.getOriginalInvite().getOrganizer();
if (org != null) {
String orgAddress = org.getAddress();
Account orgAccount = Provisioning.getInstance().getAccountByName(orgAddress);
if (orgAccount != null && !orgAccount.getId().equals(mbox.getAccount().getId())) {
MimeMessage notifyMimeMsg = CalendarMailSender.createForwardNotifyMessage(mbox.getAccount(), orgAccount, orgAddress, mm.getAllRecipients(), mv.getOriginalInvite());
CalendarMailSender.sendPartial(oc, mbox, notifyMimeMsg, null, null, null, null, false, true);
}
}
}
} catch (Exception e) {
ZimbraLog.soap.warn("Ignoring error while sending Calendar Invitation Forward Notification", e);
}
return id;
}
use of javax.mail.MessagingException in project zm-mailbox by Zimbra.
the class ModifyCalendarItem method modifyCalendarItem.
private Element modifyCalendarItem(ZimbraSoapContext zsc, OperationContext octxt, Element request, Account acct, Mailbox mbox, int folderId, CalendarItem calItem, Invite inv, Invite seriesInv, Element response, boolean isInterMboxMove, MailSendQueue sendQueue) throws ServiceException {
// <M>
Element msgElem = request.getElement(MailConstants.E_MSG);
ModifyCalendarItemParser parser = new ModifyCalendarItemParser(inv, seriesInv);
CalSendData dat = handleMsgElement(zsc, octxt, msgElem, acct, mbox, parser);
dat.mDontNotifyAttendees = isInterMboxMove;
if (!dat.mInvite.hasRecurId())
ZimbraLog.calendar.info("<ModifyCalendarItem> id=%d, folderId=%d, subject=\"%s\", UID=%s", calItem.getId(), folderId, dat.mInvite.isPublic() ? dat.mInvite.getName() : "(private)", dat.mInvite.getUid());
else
ZimbraLog.calendar.info("<ModifyCalendarItem> id=%d, folderId=%d, subject=\"%s\", UID=%s, recurId=%s", calItem.getId(), folderId, dat.mInvite.isPublic() ? dat.mInvite.getName() : "(private)", dat.mInvite.getUid(), dat.mInvite.getRecurId().getDtZ());
boolean hasRecipients;
try {
Address[] rcpts = dat.mMm.getAllRecipients();
hasRecipients = rcpts != null && rcpts.length > 0;
} catch (MessagingException e) {
throw ServiceException.FAILURE("Checking recipients of outgoing msg ", e);
}
// If we are sending this to other people, then we MUST be the organizer!
if (!dat.mInvite.isOrganizer() && hasRecipients)
throw MailServiceException.MUST_BE_ORGANIZER("ModifyCalendarItem");
if (!dat.mInvite.isOrganizer()) {
// neverSent is always false for attendee users.
dat.mInvite.setNeverSent(false);
} else if (!dat.mInvite.hasOtherAttendees()) {
// neverSent is always false for appointments without attendees.
dat.mInvite.setNeverSent(false);
} else if (hasRecipients) {
// neverSent is set to false when attendees are notified.
dat.mInvite.setNeverSent(false);
} else {
// This is the case of organizer saving an invite with attendees, but without sending the notification.
assert (dat.mInvite.hasOtherAttendees() && !hasRecipients);
if (!inv.hasOtherAttendees()) {
// Special case of going from a personal appointment (no attendees) to a draft appointment with
// attendees. neverSent was false for being a personal appointment, so we need to explicitly set it to true.
// This case is essentially identical to creating a new appointment with attendees without notification.
dat.mInvite.setNeverSent(true);
} else {
// Set neverSent to false, but only if it wasn't already set to true before.
// !inv.isNeverSent() ? false : true ==> inv.isNeverSent()
dat.mInvite.setNeverSent(inv.isNeverSent());
}
}
boolean echo = request.getAttributeBool(MailConstants.A_CAL_ECHO, false);
ItemIdFormatter ifmt = new ItemIdFormatter(zsc);
int maxSize = (int) request.getAttributeLong(MailConstants.A_MAX_INLINED_LENGTH, 0);
boolean wantHTML = request.getAttributeBool(MailConstants.A_WANT_HTML, false);
boolean neuter = request.getAttributeBool(MailConstants.A_NEUTER, true);
boolean forceSend = request.getAttributeBool(MailConstants.A_CAL_FORCESEND, true);
if (inv.isOrganizer()) {
// Notify removed attendees before making any changes to the appointment.
List<ZAttendee> atsCanceled = parser.getAttendeesCanceled();
if (!inv.isNeverSent()) {
// No need to notify for a draft appointment.
if (!atsCanceled.isEmpty()) {
notifyRemovedAttendees(zsc, octxt, acct, mbox, inv.getCalendarItem(), inv, atsCanceled, sendQueue);
}
}
List<ZAttendee> atsAdded = parser.getAttendeesAdded();
// Figure out if we're notifying all attendees. Must do this before clearing recipients from dat.mMm.
boolean notifyAllAttendees = isNotifyingAll(dat.mMm, atsAdded);
// If notifying all the attendees update the last sequence number otherwise retain the existing value.
if (notifyAllAttendees) {
dat.mInvite.setLastFullSeqNo(dat.mInvite.getSeqNo());
} else {
dat.mInvite.setLastFullSeqNo(inv.getLastFullSeqNo());
}
if (inv.isRecurrence()) {
// Clear to/cc/bcc from the MimeMessage, so that the sendCalendarMessage call only updates the organizer's
// own appointment without notifying any attendees. Notifications will be sent later,
removeAllRecipients(dat.mMm);
// (unless they are added as new series attendees)
if (!acct.isCalendarKeepExceptionsOnSeriesTimeChange()) {
InviteChanges ic = new InviteChanges(seriesInv, dat.mInvite);
if (ic.isExceptionRemovingChange()) {
long now = octxt != null ? octxt.getTimestamp() : System.currentTimeMillis();
Invite[] invites = calItem.getInvites();
for (Invite except : invites) {
if (!except.isNeverSent() && except.hasRecurId() && !except.isCancel() && inviteIsAfterTime(except, now)) {
List<ZAttendee> toNotify = CalendarUtils.getRemovedAttendees(except.getAttendees(), seriesInv.getAttendees(), false, acct);
if (!toNotify.isEmpty()) {
notifyRemovedAttendees(zsc, octxt, acct, mbox, calItem, except, toNotify, sendQueue);
}
}
}
}
}
// Save the change to the series as specified by the client.
sendCalendarMessage(zsc, octxt, folderId, acct, mbox, dat, response, true, forceSend, sendQueue);
// Echo the updated inv in the response.
if (echo && dat.mAddInvData != null) {
echoAddedInvite(response, ifmt, octxt, mbox, dat.mAddInvData, maxSize, wantHTML, neuter);
}
boolean ignorePastExceptions = true;
// Reflect added/removed attendees in the exception instances.
if (!atsAdded.isEmpty() || !atsCanceled.isEmpty()) {
addRemoveAttendeesInExceptions(octxt, mbox, inv.getCalendarItem(), atsAdded, atsCanceled, ignorePastExceptions);
}
// Send notifications.
if (hasRecipients) {
notifyCalendarItem(zsc, octxt, acct, mbox, inv.getCalendarItem(), notifyAllAttendees, atsAdded, ignorePastExceptions, sendQueue);
}
} else {
// Modifying a one-off appointment or an exception instance. There are no
// complications like in the series update case. Just update the invite with the
// data supplied by the client, and let the built-in notification take place.
sendCalendarMessage(zsc, octxt, folderId, acct, mbox, dat, response, true, forceSend, sendQueue);
// Echo the updated inv in the response.
if (echo && dat.mAddInvData != null) {
echoAddedInvite(response, ifmt, octxt, mbox, dat.mAddInvData, maxSize, wantHTML, neuter);
}
}
} else {
// not organizer
// Apply the change.
sendCalendarMessage(zsc, octxt, folderId, acct, mbox, dat, response, true, forceSend, sendQueue);
// Echo the updated inv in the response.
if (echo && dat.mAddInvData != null) {
echoAddedInvite(response, ifmt, octxt, mbox, dat.mAddInvData, maxSize, wantHTML, neuter);
}
}
return response;
}
Aggregations