use of com.zimbra.common.calendar.Attach in project zm-mailbox by Zimbra.
the class Invite method addInlineATTACHes.
protected ZComponent addInlineATTACHes(ZComponent comp) {
MimeMessage mimeMsg = null;
try {
mimeMsg = getMimeMessage();
} catch (ServiceException e1) {
return comp;
}
if (mimeMsg == null) {
return comp;
}
try {
List<MPartInfo> parts = Mime.getParts(mimeMsg, MimeConstants.P_CHARSET_UTF8);
if (parts != null && !parts.isEmpty()) {
for (MPartInfo body : parts.get(0).getChildren()) {
if (body.isMultipart()) {
continue;
}
MimePart mp = body.getMimePart();
String ctype = StringUtil.stripControlCharacters(body.getContentType());
if (MimeConstants.CT_TEXT_CALENDAR.equalsIgnoreCase(ctype)) {
// Otherwise it's just an attachment that happens to be a .ics file.
try {
ContentType ct = new ContentType(body.getMimePart().getContentType());
if (ct.getParameter("method") != null) {
continue;
}
} catch (MessagingException e) {
}
}
String contentType = StringUtil.stripControlCharacters(body.getContentType());
String fileName = Mime.getFilename(mp);
try (InputStream in = mp.getInputStream()) {
byte[] rawBytes = IOUtils.toByteArray(in);
Attach attachment = Attach.fromUnencodedAndContentType(rawBytes, contentType);
if (!Strings.isNullOrEmpty(fileName)) {
attachment.setFileName(fileName);
}
comp.addProperty(attachment.toZProperty());
}
}
}
} catch (MessagingException | IOException e) {
ZimbraLog.calendar.warn("Problem adding inline ATTACHes", e);
}
return comp;
}
use of com.zimbra.common.calendar.Attach in project zm-mailbox by Zimbra.
the class Invite method createFromCalendar.
private static void createFromCalendar(List<Invite> toAdd, Account account, String fragment, String method, TimeZoneMap tzmap, Iterator<ZComponent> compIter, boolean sentByMe, Mailbox mbx, int mailItemId, boolean continueOnError, InviteVisitor visitor) throws ServiceException {
int compNum = 0;
while (compIter.hasNext()) {
ZComponent comp = compIter.next();
Invite newInv = null;
try {
MailItem.Type type;
ICalTok compTypeTok = comp.getTok();
if (compTypeTok == null)
continue;
if (ICalTok.VTODO.equals(compTypeTok)) {
type = MailItem.Type.TASK;
} else {
type = MailItem.Type.APPOINTMENT;
}
switch(compTypeTok) {
case VEVENT:
case VTODO:
boolean isEvent = ICalTok.VEVENT.equals(compTypeTok);
boolean isTodo = ICalTok.VTODO.equals(compTypeTok);
try {
newInv = new Invite(type, method, tzmap, false);
// set to true later if X-ZIMBRA-LOCAL-ONLY is present
newInv.setLocalOnly(false);
if (toAdd != null)
toAdd.add(newInv);
List<Object> addRecurs = new ArrayList<Object>();
List<Object> subRecurs = new ArrayList<Object>();
newInv.setComponentNum(compNum);
if (mbx != null)
newInv.setMailboxId(mbx.getId());
newInv.setMailItemId(mailItemId);
newInv.setSentByMe(sentByMe);
compNum++;
List<ZComponent> subcomponents = Lists.newArrayList(comp.getComponentIterator());
for (ZComponent subcomp : subcomponents) {
ICalTok subCompTypeTok = subcomp.getTok();
switch(subCompTypeTok) {
case VALARM:
Alarm alarm = Alarm.parse(subcomp);
if (alarm != null)
newInv.addAlarm(alarm);
break;
default:
}
}
boolean isTodoCompleted = false;
boolean sawIntendedFreeBusy = false;
List<ZProperty> properties = Lists.newArrayList(comp.getPropertyIterator());
for (ZProperty prop : properties) {
String propVal = prop.getValue();
ICalTok propToken = prop.getToken();
if (propToken == null) {
// parse errors later, so ignore them.
if (propVal == null || propVal.length() < 1)
continue;
String name = prop.getName();
if (name.startsWith("X-") || name.startsWith("x-"))
newInv.addXProp(prop);
} else if (propToken.equals(ICalTok.CATEGORIES)) {
List<String> categories = prop.getValueList();
if (categories != null && !categories.isEmpty()) {
for (String cat : categories) {
newInv.addCategory(cat);
}
}
} else {
// parse errors later, so ignore them.
if (propVal == null || propVal.length() < 1)
continue;
switch(propToken) {
case ORGANIZER:
newInv.setOrganizer(new ZOrganizer(prop));
break;
case ATTENDEE:
newInv.addAttendee(new ZAttendee(prop));
break;
case DTSTAMP:
ParsedDateTime dtstamp = ParsedDateTime.parse(prop, tzmap);
newInv.setDtStamp(dtstamp.getUtcTime());
break;
case LAST_MODIFIED:
ParsedDateTime lastModified = ParsedDateTime.parse(prop, tzmap);
newInv.setLastModified(lastModified.getUtcTime());
break;
case RECURRENCE_ID:
ParsedDateTime rid = ParsedDateTime.parse(prop, tzmap);
if (DebugConfig.enableThisAndFuture) {
newInv.setRecurId(new RecurId(rid, prop.paramVal(ICalTok.RANGE, null)));
} else {
newInv.setRecurId(new RecurId(rid, RecurId.RANGE_NONE));
}
break;
case SEQUENCE:
newInv.setSeqNo(prop.getIntValue());
break;
case DTSTART:
ParsedDateTime dtstart = ParsedDateTime.parse(prop, tzmap);
newInv.setDtStart(dtstart);
if (!dtstart.hasTime())
newInv.setIsAllDayEvent(true);
break;
case DTEND:
if (isEvent) {
ParsedDateTime dtend = ParsedDateTime.parse(prop, tzmap);
newInv.setDtEnd(dtend);
if (!dtend.hasTime())
newInv.setIsAllDayEvent(true);
}
break;
case DUE:
if (isTodo) {
ParsedDateTime due = ParsedDateTime.parse(prop, tzmap);
// DUE is for VTODO what DTEND is for VEVENT.
newInv.setDtEnd(due);
if (!due.hasTime())
newInv.setIsAllDayEvent(true);
}
break;
case DURATION:
ParsedDuration dur = ParsedDuration.parse(propVal);
newInv.setDuration(dur);
break;
case LOCATION:
newInv.setLocation(propVal);
break;
case SUMMARY:
String summary = propVal;
if (summary != null) {
// Make sure SUMMARY is a single line.
summary = summary.replaceAll("[\\\r\\\n]+", " ");
}
prop.setValue(summary);
newInv.setName(summary);
break;
case DESCRIPTION:
newInv.setDescription(propVal, newInv.mDescHtml);
newInv.setFragment(Fragment.getFragment(propVal, true));
break;
case X_ALT_DESC:
ZParameter fmttype = prop.getParameter(ICalTok.FMTTYPE);
if (fmttype != null && MimeConstants.CT_TEXT_HTML.equalsIgnoreCase(fmttype.getValue())) {
String html = propVal;
newInv.setDescription(newInv.mDescription, html);
} else {
// Unknown format. Just add as an x-prop.
newInv.addXProp(prop);
}
break;
case COMMENT:
newInv.addComment(propVal);
break;
case UID:
newInv.setUid(propVal);
break;
case RRULE:
ZRecur recur = new ZRecur(propVal, tzmap);
addRecurs.add(recur);
newInv.setIsRecurrence(true);
break;
case RDATE:
if (DebugConfig.enableRdate) {
RdateExdate rdate = RdateExdate.parse(prop, tzmap);
addRecurs.add(rdate);
newInv.setIsRecurrence(true);
}
break;
case EXRULE:
ZRecur exrecur = new ZRecur(propVal, tzmap);
subRecurs.add(exrecur);
newInv.setIsRecurrence(true);
break;
case EXDATE:
RdateExdate exdate = RdateExdate.parse(prop, tzmap);
subRecurs.add(exdate);
newInv.setIsRecurrence(true);
break;
case STATUS:
String status = IcalXmlStrMap.sStatusMap.toXml(propVal);
if (status != null) {
if (IcalXmlStrMap.STATUS_IN_PROCESS.equals(status)) {
String zstatus = prop.getParameterVal(ICalTok.X_ZIMBRA_STATUS, null);
if (ICalTok.X_ZIMBRA_STATUS_WAITING.toString().equals(zstatus) || ICalTok.X_ZIMBRA_STATUS_DEFERRED.toString().equals(zstatus)) {
newInv.setStatus(IcalXmlStrMap.sStatusMap.toXml(zstatus));
} else {
newInv.setStatus(status);
}
} else {
newInv.setStatus(status);
if (isTodo && IcalXmlStrMap.STATUS_COMPLETED.equals(status))
isTodoCompleted = true;
}
}
break;
case TRANSP:
// TRANSP is examined only when intended F/B is not supplied.
if (isEvent && !sawIntendedFreeBusy) {
String transp = IcalXmlStrMap.sTranspMap.toXml(propVal);
if (transp != null) {
newInv.setTransparency(transp);
// If opaque, don't set intended f/b because there are multiple possibilities.
if (newInv.isTransparent())
newInv.setFreeBusy(IcalXmlStrMap.FBTYPE_FREE);
}
}
break;
case CLASS:
String classProp = IcalXmlStrMap.sClassMap.toXml(propVal);
if (classProp != null)
newInv.setClassProp(classProp);
break;
case X_MICROSOFT_CDO_ALLDAYEVENT:
if (isEvent) {
if (prop.getBoolValue())
newInv.setIsAllDayEvent(true);
}
break;
case X_MICROSOFT_CDO_INTENDEDSTATUS:
sawIntendedFreeBusy = true;
if (isEvent) {
String fb = IcalXmlStrMap.sOutlookFreeBusyMap.toXml(propVal);
if (fb != null) {
newInv.setFreeBusy(fb);
// Intended F/B takes precedence over TRANSP.
if (IcalXmlStrMap.FBTYPE_FREE.equals(fb))
newInv.setTransparency(IcalXmlStrMap.TRANSP_TRANSPARENT);
else
newInv.setTransparency(IcalXmlStrMap.TRANSP_OPAQUE);
}
}
break;
case PRIORITY:
String prio = propVal;
if (prio != null)
newInv.setPriority(prio);
break;
case PERCENT_COMPLETE:
if (isTodo) {
String pctComplete = propVal;
if (pctComplete != null) {
newInv.setPercentComplete(pctComplete);
if (prop.getIntValue() == 100)
isTodoCompleted = true;
}
}
break;
case COMPLETED:
if (isTodo) {
ParsedDateTime completed = ParsedDateTime.parseUtcOnly(propVal);
newInv.setCompleted(completed.getUtcTime());
isTodoCompleted = true;
}
break;
case CONTACT:
newInv.addContact(propVal);
break;
case GEO:
Geo geo = Geo.parse(prop);
newInv.setGeo(geo);
break;
case URL:
newInv.setUrl(propVal);
break;
case X_ZIMBRA_LOCAL_ONLY:
if (prop.getBoolValue())
newInv.setLocalOnly(true);
break;
case X_ZIMBRA_DISCARD_EXCEPTIONS:
newInv.addXProp(prop);
break;
case X_ZIMBRA_CHANGES:
newInv.addXProp(prop);
break;
case ATTACH:
Attach attach = Attach.parse(prop);
if (attach.getBinaryB64Data() != null) {
newInv.addIcalendarAttach(attach);
}
break;
}
}
}
if (isTodoCompleted) {
// set the status to Completed.
newInv.setStatus(IcalXmlStrMap.STATUS_COMPLETED);
// set percent-complete to 100
newInv.setPercentComplete(Integer.toString(100));
if (// set COMPLETED property to now if not already set.
newInv.getCompleted() == 0)
newInv.setCompleted(System.currentTimeMillis());
}
newInv.setIsOrganizer(account);
newInv.validateDuration();
ParsedDuration duration = newInv.getDuration();
boolean durationCalculated = false;
if (duration == null) {
ParsedDateTime end = newInv.getEndTime();
if (end != null && newInv.getStartTime() != null) {
duration = end.difference(newInv.getStartTime());
durationCalculated = true;
}
}
if (!addRecurs.isEmpty() || !subRecurs.isEmpty()) {
// We have a recurrence. Make sure DTSTART is not null.
ParsedDateTime st = newInv.getStartTime();
if (st == null) {
ParsedDateTime et = newInv.getEndTime();
if (et != null) {
if (et.hasTime())
st = et.add(ParsedDuration.NEGATIVE_ONE_SECOND);
else
st = et.add(ParsedDuration.NEGATIVE_ONE_DAY);
newInv.setDtStart(st);
} else {
// Both DTSTART and DTEND are unspecified. Recurrence makes no sense!
throw ServiceException.INVALID_REQUEST("recurrence used without DTSTART", null);
}
}
if (durationCalculated && newInv.getItemType() == MailItem.Type.TASK) {
if (newInv.getStartTime() != null && !newInv.getStartTime().hasTime()) {
duration = ParsedDuration.ONE_DAY;
} else {
duration = ParsedDuration.ONE_SECOND;
}
}
}
InviteInfo inviteInfo = new InviteInfo(newInv);
List<IRecurrence> addRules = new ArrayList<IRecurrence>();
if (addRecurs.size() > 0) {
for (Iterator<Object> iter = addRecurs.iterator(); iter.hasNext(); ) {
Object next = iter.next();
if (next instanceof ZRecur) {
ZRecur cur = (ZRecur) next;
addRules.add(new Recurrence.SimpleRepeatingRule(newInv.getStartTime(), duration, cur, inviteInfo));
} else if (next instanceof RdateExdate) {
RdateExdate rdate = (RdateExdate) next;
addRules.add(new Recurrence.SingleDates(rdate, duration, inviteInfo));
}
}
}
List<IRecurrence> subRules = new ArrayList<IRecurrence>();
if (subRecurs.size() > 0) {
for (Iterator<Object> iter = subRecurs.iterator(); iter.hasNext(); ) {
Object next = iter.next();
if (next instanceof ZRecur) {
ZRecur cur = (ZRecur) iter.next();
subRules.add(new Recurrence.SimpleRepeatingRule(newInv.getStartTime(), duration, cur, inviteInfo));
} else if (next instanceof RdateExdate) {
RdateExdate exdate = (RdateExdate) next;
subRules.add(new Recurrence.SingleDates(exdate, duration, inviteInfo));
}
}
}
if (newInv.hasRecurId()) {
if (addRules.size() > 0) {
newInv.setRecurrence(new Recurrence.ExceptionRule(newInv.getRecurId(), newInv.getStartTime(), duration, new InviteInfo(newInv), addRules, subRules));
}
} else {
if (addRules.size() > 0) {
// since exclusions can't affect DtStart, just ignore them if there are no add rules
newInv.setRecurrence(new Recurrence.RecurrenceRule(newInv.getStartTime(), duration, new InviteInfo(newInv), addRules, subRules));
}
}
String location = newInv.getLocation();
if (location == null)
newInv.setLocation("");
// Process callback.
if (visitor != null)
visitor.visit(newInv);
} catch (ParseException e) {
throw ServiceException.PARSE_ERROR("Unable to parse iCalendar data: " + e.getMessage(), e);
}
break;
}
} catch (ServiceException e) {
if (!continueOnError)
throw e;
if (newInv != null)
logIcsParseImportError(newInv, e);
else
ZimbraLog.calendar.warn("Skipping error during ics parse/import", e);
} catch (RuntimeException e) {
if (!continueOnError)
throw e;
if (newInv != null)
logIcsParseImportError(newInv, e);
else
ZimbraLog.calendar.warn("Skipping error during ics parse/import", e);
}
}
}
use of com.zimbra.common.calendar.Attach in project zm-mailbox by Zimbra.
the class Alarm method parse.
/**
* Create an Alarm from SOAP. Return value may be null.
* @param alarmElem
* @return
* @throws ServiceException
*/
public static Alarm parse(Element alarmElem) throws ServiceException {
Action action = Action.DISPLAY;
TriggerType triggerType = TriggerType.RELATIVE;
TriggerRelated triggerRelated = null;
ParsedDuration triggerRelative = null;
ParsedDateTime triggerAbsolute = null;
ParsedDuration repeatDuration = null;
int repeatCount = 0;
String description = null;
String summary = null;
Attach attach = null;
List<ZAttendee> attendees = null;
String val;
val = alarmElem.getAttribute(MailConstants.A_CAL_ALARM_ACTION);
action = Action.lookup(val);
if (action == null)
throw ServiceException.INVALID_REQUEST("Invalid " + MailConstants.A_CAL_ALARM_ACTION + " value " + val, null);
if (!actionAllowed(action))
return null;
Element triggerElem = alarmElem.getElement(MailConstants.E_CAL_ALARM_TRIGGER);
Element triggerRelativeElem = triggerElem.getOptionalElement(MailConstants.E_CAL_ALARM_RELATIVE);
if (triggerRelativeElem != null) {
triggerType = TriggerType.RELATIVE;
String related = triggerRelativeElem.getAttribute(MailConstants.A_CAL_ALARM_RELATED, null);
if (related != null) {
triggerRelated = TriggerRelated.lookup(related);
if (triggerRelated == null)
throw ServiceException.INVALID_REQUEST("Invalid " + MailConstants.A_CAL_ALARM_RELATED + " value " + val, null);
}
triggerRelative = ParsedDuration.parse(triggerRelativeElem);
} else {
triggerType = TriggerType.ABSOLUTE;
Element triggerAbsoluteElem = triggerElem.getOptionalElement(MailConstants.E_CAL_ALARM_ABSOLUTE);
if (triggerAbsoluteElem == null)
throw ServiceException.INVALID_REQUEST("<" + MailConstants.E_CAL_ALARM_TRIGGER + "> must have either <" + MailConstants.E_CAL_ALARM_RELATIVE + "> or <" + MailConstants.E_CAL_ALARM_ABSOLUTE + "> child element", null);
String datetime = triggerAbsoluteElem.getAttribute(MailConstants.A_DATE);
try {
triggerAbsolute = ParsedDateTime.parseUtcOnly(datetime);
} catch (ParseException e) {
throw ServiceException.INVALID_REQUEST("Invalid absolute trigger value " + val, e);
}
}
Element repeatElem = alarmElem.getOptionalElement(MailConstants.E_CAL_ALARM_REPEAT);
if (repeatElem != null) {
repeatDuration = ParsedDuration.parse(repeatElem);
repeatCount = (int) repeatElem.getAttributeLong(MailConstants.A_CAL_ALARM_COUNT, 0);
}
Element descElem = alarmElem.getOptionalElement(MailConstants.E_CAL_ALARM_DESCRIPTION);
if (descElem != null) {
description = descElem.getText();
}
Element summaryElem = alarmElem.getOptionalElement(MailConstants.E_CAL_ALARM_SUMMARY);
if (summaryElem != null) {
summary = summaryElem.getText();
}
Element attachElem = alarmElem.getOptionalElement(MailConstants.E_CAL_ATTACH);
if (attachElem != null)
attach = Attach.parse(attachElem);
Iterator<Element> attendeesIter = alarmElem.elementIterator(MailConstants.E_CAL_ATTENDEE);
while (attendeesIter.hasNext()) {
ZAttendee at = ZAttendee.parse(attendeesIter.next());
if (attendees == null)
attendees = new ArrayList<ZAttendee>();
attendees.add(at);
}
Alarm alarm = new Alarm(action, triggerType, triggerRelated, triggerRelative, triggerAbsolute, repeatDuration, repeatCount, description, summary, attach, attendees, CalendarUtils.parseXProps(alarmElem));
return alarm;
}
use of com.zimbra.common.calendar.Attach in project zm-mailbox by Zimbra.
the class Alarm method parse.
/**
* Create an Alarm from ZComponent. Return value may be null.
* @param comp
* @return
* @throws ServiceException
*/
public static Alarm parse(ZComponent comp) throws ServiceException {
Action action = Action.DISPLAY;
TriggerType triggerType = TriggerType.RELATIVE;
TriggerRelated triggerRelated = null;
ParsedDuration triggerRelative = null;
ParsedDateTime triggerAbsolute = null;
ParsedDuration repeatDuration = null;
int repeatCount = 0;
String description = null;
String summary = null;
Attach attach = null;
List<ZAttendee> attendees = null;
List<ZProperty> xprops = new ArrayList<ZProperty>();
Iterator<ZProperty> propIter = comp.getPropertyIterator();
while (propIter.hasNext()) {
ZProperty prop = propIter.next();
ICalTok tok = prop.getToken();
String val = prop.getValue();
if (tok == null) {
String name = prop.getName();
if (name.startsWith("X-") || name.startsWith("x-")) {
xprops.add(prop);
}
continue;
}
switch(tok) {
case ACTION:
if (val != null) {
action = Action.lookup(val);
if (action == null)
throw ServiceException.INVALID_REQUEST("Invalid ACTION value " + val, null);
if (!actionAllowed(action))
return null;
}
break;
case TRIGGER:
ZParameter valueType = prop.getParameter(ICalTok.VALUE);
if (valueType != null) {
String vt = valueType.getValue();
if (ICalTok.DATE_TIME.toString().equals(vt))
triggerType = TriggerType.ABSOLUTE;
}
if (TriggerType.RELATIVE.equals(triggerType)) {
ZParameter related = prop.getParameter(ICalTok.RELATED);
if (related != null) {
String rel = related.getValue();
if (rel != null) {
triggerRelated = TriggerRelated.lookup(rel);
if (triggerRelated == null)
throw ServiceException.INVALID_REQUEST("Invalid RELATED value " + rel, null);
}
}
triggerRelative = ParsedDuration.parse(val);
} else {
try {
if (val != null)
triggerAbsolute = ParsedDateTime.parseUtcOnly(val);
} catch (ParseException e) {
throw ServiceException.INVALID_REQUEST("Invalid TRIGGER value " + val, e);
}
}
break;
case DURATION:
if (val != null)
repeatDuration = ParsedDuration.parse(val);
break;
case REPEAT:
if (val != null) {
try {
repeatCount = Integer.parseInt(val);
} catch (NumberFormatException e) {
throw ServiceException.INVALID_REQUEST("Invalid REPEAT value " + val, e);
}
}
break;
case DESCRIPTION:
description = val;
break;
case SUMMARY:
summary = val;
break;
case ATTACH:
attach = Attach.parse(prop);
break;
case ATTENDEE:
ZAttendee attendee = new ZAttendee(prop);
if (attendees == null)
attendees = new ArrayList<ZAttendee>();
attendees.add(attendee);
break;
}
}
Alarm alarm = new Alarm(action, triggerType, triggerRelated, triggerRelative, triggerAbsolute, repeatDuration, repeatCount, description, summary, attach, attendees, xprops);
return alarm;
}
use of com.zimbra.common.calendar.Attach in project zm-mailbox by Zimbra.
the class CalendarMailSender method createCalendarMessage.
public static MimeMessage createCalendarMessage(Account account, Address fromAddr, Address senderAddr, List<Address> toAddrs, String subject, String desc, String descHtml, String uid, ZCalendar.ZVCalendar cal, List<Attach> attaches, boolean replyToSender) throws ServiceException {
if (desc == null)
desc = "";
try {
MimeMessage mm = new Mime.FixedMimeMessage(JMSession.getSmtpSession(account));
MimeMultipart mpAlternatives = new ZMimeMultipart("alternative");
if (attaches != null && !attaches.isEmpty()) {
MimeMultipart mpMixed = new ZMimeMultipart("mixed");
mm.setContent(mpMixed);
MimeBodyPart mbpWrapper = new ZMimeBodyPart();
mbpWrapper.setContent(mpAlternatives);
mpMixed.addBodyPart(mbpWrapper);
for (Attach attach : attaches) {
byte[] rawData = attach.getDecodedData();
if (rawData == null) {
continue;
}
ContentDisposition cdisp = new ContentDisposition(Part.ATTACHMENT, true);
String ctypeAsString = attach.getContentType();
if (ctypeAsString == null) {
ctypeAsString = MimeConstants.CT_APPLICATION_OCTET_STREAM;
}
ContentType ctype = new ContentType(ctypeAsString);
if (attach.getFileName() != null) {
ctype.setParameter("name", attach.getFileName());
cdisp.setParameter("filename", attach.getFileName());
}
MimeBodyPart mbp2 = new ZMimeBodyPart();
ByteArrayDataSource bads = new ByteArrayDataSource(rawData, ctypeAsString);
mbp2.setDataHandler(new DataHandler(bads));
mbp2.setHeader("Content-Type", ctype.toString());
mbp2.setHeader("Content-Disposition", cdisp.toString());
mbp2.setHeader("Content-Transfer-Encoding", "base64");
mpMixed.addBodyPart(mbp2);
}
} else {
mm.setContent(mpAlternatives);
}
// Add the text as DESCRIPTION property in the iCalendar part.
// MS Entourage for Mac wants this. It ignores text/plain and
// text/html MIME parts.
cal.addDescription(desc, null);
// ///////
// TEXT part (add me first!)
MimeBodyPart textPart = new ZMimeBodyPart();
textPart.setText(desc, MimeConstants.P_CHARSET_UTF8);
mpAlternatives.addBodyPart(textPart);
// HTML part is needed to keep Outlook happy as it doesn't know
// how to deal with a message with only text/plain but no HTML.
MimeBodyPart htmlPart = new ZMimeBodyPart();
if (descHtml != null) {
ContentType ct = new ContentType(MimeConstants.CT_TEXT_HTML);
ct.setParameter(MimeConstants.P_CHARSET, MimeConstants.P_CHARSET_UTF8);
htmlPart.setText(descHtml, MimeConstants.P_CHARSET_UTF8);
htmlPart.setHeader("Content-Type", ct.toString());
} else {
htmlPart.setDataHandler(new DataHandler(new HtmlPartDataSource(desc)));
}
mpAlternatives.addBodyPart(htmlPart);
// ///////
// CALENDAR part
MimeBodyPart icalPart = makeICalIntoMimePart(cal);
mpAlternatives.addBodyPart(icalPart);
// MESSAGE HEADERS
if (subject != null) {
mm.setSubject(subject, MimeConstants.P_CHARSET_UTF8);
}
if (toAddrs != null) {
Address[] addrs = new Address[toAddrs.size()];
toAddrs.toArray(addrs);
mm.addRecipients(javax.mail.Message.RecipientType.TO, addrs);
}
if (fromAddr != null)
mm.setFrom(fromAddr);
if (senderAddr != null) {
mm.setSender(senderAddr);
if (replyToSender) {
mm.setReplyTo(new Address[] { senderAddr });
}
}
mm.setSentDate(new Date());
mm.saveChanges();
return mm;
} catch (MessagingException e) {
throw ServiceException.FAILURE("Messaging Exception while building MimeMessage from invite", e);
}
}
Aggregations