use of com.zimbra.common.calendar.ZCalendar.ZComponent in project zm-mailbox by Zimbra.
the class IcsImportParseHandler method endComponent.
@Override
public void endComponent(String name) throws ParserException {
if (mComponents.isEmpty())
throw new ParserException("Found END:" + name + " without BEGIN");
ZComponent comp = mComponents.remove(mComponents.size() - 1);
if (mComponents.size() == 0) {
ICalTok tok = comp.getTok();
if (tok != null) {
try {
switch(tok) {
case VEVENT:
case VTODO:
doComp(comp);
break;
case VTIMEZONE:
String origTZID = comp.getPropVal(ICalTok.TZID, null);
ICalTimeZone tz = ICalTimeZone.fromVTimeZone(comp, false, /* skipLookup */
TZID_NAME_ASSIGNMENT_BEHAVIOR.KEEP_IF_DOESNT_CLASH);
if ((null != origTZID) && (origTZID != tz.getID())) {
tzidRenames.put(origTZID, tz.getID());
}
mTimeZoneMap.add(tz);
break;
default:
break;
}
} catch (ServiceException e) {
throw new ParserException("Error while parsing " + tok.toString(), e);
}
}
} else {
mComponents.get(mComponents.size() - 1).addComponent(comp);
}
}
use of com.zimbra.common.calendar.ZCalendar.ZComponent in project zm-mailbox by Zimbra.
the class IcsImportParseHandler method doComp.
private void doComp(ZComponent comp) throws ServiceException {
// Create a mew TimeZoneMap containing only the timezones used by the current component.
TimeZoneMap tzmap = null;
for (String tzid : mTZIDsSeen) {
ICalTimeZone tz = mTimeZoneMap.getTimeZone(tzid);
if (tz == null) {
// Undefined TZID means bad incoming data, but if it happens to be a well-known timezone,
// let's be lenient and use the predefined definition.
String sanitizedTzid = TimeZoneMap.sanitizeTZID(tzid);
tz = WellKnownTimeZones.getTimeZoneById(sanitizedTzid);
}
if (tz != null) {
if (tzmap == null)
tzmap = new TimeZoneMap(tz);
tzmap.add(tz);
} else {
throw ServiceException.PARSE_ERROR("TZID reference encountered before/without its VTIMEZONE: " + tzid, null);
}
}
if (tzmap == null)
tzmap = new TimeZoneMap(mTimeZoneMap.getLocalTimeZone());
List<ZComponent> comps = new ArrayList<ZComponent>(1);
comps.add(comp);
Invite.createFromCalendar(mAccount, null, mMethod, tzmap, comps.iterator(), true, mContinueOnError, mInviteVisitor);
}
use of com.zimbra.common.calendar.ZCalendar.ZComponent in project zm-mailbox by Zimbra.
the class Invite method newToVComponent.
public ZComponent newToVComponent(boolean useOutlookCompatAllDayEvents, boolean includePrivateData, boolean includeAttaches) throws ServiceException {
boolean isRequestPublishCancel = ICalTok.REQUEST.equals(mMethod) || ICalTok.PUBLISH.equals(mMethod) || ICalTok.CANCEL.equals(mMethod);
ICalTok compTok;
if (type == MailItem.Type.TASK) {
compTok = ICalTok.VTODO;
useOutlookCompatAllDayEvents = false;
} else {
compTok = ICalTok.VEVENT;
}
ZComponent component = new ZComponent(compTok);
component.addProperty(new ZProperty(ICalTok.UID, getUid()));
IRecurrence recur = getRecurrence();
if (recur != null) {
for (Iterator iter = recur.addRulesIterator(); iter != null && iter.hasNext(); ) {
IRecurrence cur = (IRecurrence) iter.next();
switch(cur.getType()) {
case Recurrence.TYPE_SINGLE_DATES:
if (DebugConfig.enableRdate) {
Recurrence.SingleDates sd = (Recurrence.SingleDates) cur;
RdateExdate rdate = sd.getRdateExdate();
rdate.addAsSeparateProperties(component);
}
break;
case Recurrence.TYPE_REPEATING:
Recurrence.SimpleRepeatingRule srr = (Recurrence.SimpleRepeatingRule) cur;
component.addProperty(new ZProperty(ICalTok.RRULE, srr.getRule().toString()));
break;
}
}
for (Iterator iter = recur.subRulesIterator(); iter != null && iter.hasNext(); ) {
IRecurrence cur = (IRecurrence) iter.next();
switch(cur.getType()) {
case Recurrence.TYPE_SINGLE_DATES:
Recurrence.SingleDates sd = (Recurrence.SingleDates) cur;
RdateExdate exdate = sd.getRdateExdate();
exdate.addAsSeparateProperties(component);
break;
case Recurrence.TYPE_REPEATING:
Recurrence.SimpleRepeatingRule srr = (Recurrence.SimpleRepeatingRule) cur;
component.addProperty(new ZProperty(ICalTok.EXRULE, srr.getRule().toString()));
break;
}
}
}
if (includePrivateData || isPublic()) {
// SUMMARY (aka Name or Subject)
String name = getName();
if (name != null && name.length() > 0)
component.addProperty(new ZProperty(ICalTok.SUMMARY, name));
// DESCRIPTION and X-ALT-DESC;FMTTYPE=text/html
String desc = getDescription();
if (desc != null) {
// Remove Outlook-style *~*~*~ header block. Remove separator plus two newlines.
int delim = desc.indexOf(HEADER_SEPARATOR);
if (delim >= 0) {
desc = desc.substring(delim + HEADER_SEPARATOR.length());
desc = desc.replaceFirst("^\\r?\\n\\r?\\n", "");
}
if (desc.length() > 0)
component.addProperty(new ZProperty(ICalTok.DESCRIPTION, desc));
}
String descHtml = getDescriptionHtml();
if (descHtml != null && descHtml.length() > 0) {
ZProperty altDesc = new ZProperty(ICalTok.X_ALT_DESC, descHtml);
altDesc.addParameter(new ZParameter(ICalTok.FMTTYPE, MimeConstants.CT_TEXT_HTML));
component.addProperty(altDesc);
}
// COMMENT
List<String> comments = getComments();
if (comments != null && !comments.isEmpty()) {
for (String comment : comments) {
component.addProperty(new ZProperty(ICalTok.COMMENT, comment));
}
}
// LOCATION
String location = getLocation();
if (location != null && location.length() > 0)
component.addProperty(new ZProperty(ICalTok.LOCATION, location.toString()));
// ATTENDEES
for (ZAttendee at : getAttendees()) {
component.addProperty(at.toProperty());
}
// PRIORITY
if (mPriority != null)
component.addProperty(new ZProperty(ICalTok.PRIORITY, mPriority));
// PERCENT-COMPLETE
if (isTodo() && mPercentComplete != null)
component.addProperty(new ZProperty(ICalTok.PERCENT_COMPLETE, mPercentComplete));
// COMPLETED
if (isTodo() && mCompleted != 0) {
ParsedDateTime completed = ParsedDateTime.fromUTCTime(mCompleted);
component.addProperty(completed.toProperty(ICalTok.COMPLETED, false));
}
// CATEGORIES
List<String> categories = getCategories();
if (categories != null && !categories.isEmpty()) {
ZProperty catsProp = new ZProperty(ICalTok.CATEGORIES);
catsProp.setValueList(categories);
component.addProperty(catsProp);
}
// CONTACT
List<String> contacts = getContacts();
if (contacts != null && !contacts.isEmpty()) {
for (String contact : contacts) {
component.addProperty(new ZProperty(ICalTok.CONTACT, contact));
}
}
// GEO
if (mGeo != null)
component.addProperty(mGeo.toZProperty());
// VALARMs
for (Alarm alarm : mAlarms) {
ZComponent alarmComp = alarm.toZComponent();
component.addComponent(alarmComp);
}
// x-prop
for (ZProperty xprop : mXProps) {
component.addProperty(xprop);
}
// ORGANIZER
if (hasOrganizer()) {
ZOrganizer organizer = getOrganizer();
ZProperty orgProp = organizer.toProperty();
component.addProperty(orgProp);
// Hack for Outlook 2007 (bug 25777)
if (organizer.hasSentBy() && !ICalTok.REPLY.equals(mMethod) && !ICalTok.COUNTER.equals(mMethod)) {
String sentByParam = orgProp.paramVal(ICalTok.SENT_BY, null);
if (sentByParam != null) {
ZProperty xMsOlkSender = new ZProperty("X-MS-OLK-SENDER");
xMsOlkSender.setValue(sentByParam);
component.addProperty(xMsOlkSender);
}
}
}
}
// DTSTART
ParsedDateTime dtstart = getStartTime();
if (dtstart != null)
component.addProperty(dtstart.toProperty(ICalTok.DTSTART, useOutlookCompatAllDayEvents));
// DTEND or DUE
ParsedDateTime dtend = getEndTime();
if (dtend != null) {
ICalTok prop = ICalTok.DTEND;
if (isTodo())
prop = ICalTok.DUE;
component.addProperty(dtend.toProperty(prop, useOutlookCompatAllDayEvents));
}
// DURATION
ParsedDuration dur = getDuration();
if (dur != null)
component.addProperty(new ZProperty(ICalTok.DURATION, dur.toString()));
// STATUS
String status = getStatus();
String statusIcal = IcalXmlStrMap.sStatusMap.toIcal(status);
if (IcalXmlStrMap.STATUS_ZCO_WAITING.equals(status) || IcalXmlStrMap.STATUS_ZCO_DEFERRED.equals(status)) {
ZParameter param = new ZParameter(ICalTok.X_ZIMBRA_STATUS, statusIcal);
ZProperty prop = new ZProperty(ICalTok.STATUS, ICalTok.IN_PROCESS.toString());
prop.addParameter(param);
component.addProperty(prop);
} else {
component.addProperty(new ZProperty(ICalTok.STATUS, statusIcal));
}
// CLASS
component.addProperty(new ZProperty(ICalTok.CLASS, IcalXmlStrMap.sClassMap.toIcal(getClassProp())));
if (isEvent()) {
// allDay
if (isAllDayEvent())
component.addProperty(new ZProperty(ICalTok.X_MICROSOFT_CDO_ALLDAYEVENT, true));
// Microsoft Outlook compatibility for free-busy status
if (isRequestPublishCancel) {
String outlookFreeBusy = IcalXmlStrMap.sOutlookFreeBusyMap.toIcal(getFreeBusy());
component.addProperty(new ZProperty(ICalTok.X_MICROSOFT_CDO_INTENDEDSTATUS, outlookFreeBusy));
}
// TRANSPARENCY
component.addProperty(new ZProperty(ICalTok.TRANSP, IcalXmlStrMap.sTranspMap.toIcal(getTransparency())));
}
// RECURRENCE-ID
RecurId recurId = getRecurId();
if (recurId != null)
component.addProperty(recurId.toProperty(useOutlookCompatAllDayEvents));
// LAST-MODIFIED
long lastModified = getLastModified();
if (lastModified != 0) {
ParsedDateTime dtLastModified = ParsedDateTime.fromUTCTime(lastModified);
component.addProperty(dtLastModified.toProperty(ICalTok.LAST_MODIFIED, false));
}
// DTSTAMP
ParsedDateTime dtStamp = ParsedDateTime.fromUTCTime(getDTStamp());
component.addProperty(dtStamp.toProperty(ICalTok.DTSTAMP, false));
// SEQUENCE
component.addProperty(new ZProperty(ICalTok.SEQUENCE, getSeqNo()));
// URL
String url = getUrl();
if (url != null && url.length() > 0)
component.addProperty(new ZProperty(ICalTok.URL, url));
if (isLocalOnly())
component.addProperty(new ZProperty(ICalTok.X_ZIMBRA_LOCAL_ONLY, true));
if (includeAttaches) {
addInlineATTACHes(component);
}
return component;
}
use of com.zimbra.common.calendar.ZCalendar.ZComponent in project zm-mailbox by Zimbra.
the class Invite method getDescription.
/**
* Returns the meeting notes. Meeting notes is the text/plain part in an
* invite. It typically includes CUA-generated meeting summary as well as
* text entered by the user.
*
* @return null if notes is not found
* @throws ServiceException
*/
public static String getDescription(Part mmInv, String mimeType) throws ServiceException {
if (mmInv == null)
return null;
try {
// If top-level is text/calendar, parse the iCalendar object and return
// the DESCRIPTION of the first VEVENT/VTODO encountered.
String mmCtStr = mmInv.getContentType();
if (mmCtStr != null) {
ContentType mmCt = new ContentType(mmCtStr);
if (mmCt.match(MimeConstants.CT_TEXT_CALENDAR)) {
boolean wantHtml = MimeConstants.CT_TEXT_HTML.equalsIgnoreCase(mimeType);
Object mmInvContent = mmInv.getContent();
InputStream is = null;
try {
String charset = MimeConstants.P_CHARSET_UTF8;
if (mmInvContent instanceof InputStream) {
charset = mmCt.getParameter(MimeConstants.P_CHARSET);
if (charset == null)
charset = MimeConstants.P_CHARSET_UTF8;
is = (InputStream) mmInvContent;
} else if (mmInvContent instanceof String) {
String str = (String) mmInvContent;
charset = MimeConstants.P_CHARSET_UTF8;
is = new ByteArrayInputStream(str.getBytes(charset));
}
if (is != null) {
ZVCalendar iCal = ZCalendarBuilder.build(is, charset);
for (Iterator<ZComponent> compIter = iCal.getComponentIterator(); compIter.hasNext(); ) {
ZComponent component = compIter.next();
ICalTok compTypeTok = component.getTok();
if (compTypeTok == ICalTok.VEVENT || compTypeTok == ICalTok.VTODO) {
if (!wantHtml)
return component.getPropVal(ICalTok.DESCRIPTION, null);
else
return component.getDescriptionHtml();
}
}
}
} finally {
ByteUtil.closeStream(is);
}
}
}
Object mmInvContent = mmInv.getContent();
if (!(mmInvContent instanceof MimeMultipart)) {
if (mmInvContent instanceof InputStream) {
ByteUtil.closeStream((InputStream) mmInvContent);
}
return null;
}
MimeMultipart mm = (MimeMultipart) mmInvContent;
// If top-level is multipart, get description from text/* part.
int numParts = mm.getCount();
String charset = null;
for (int i = 0; i < numParts; i++) {
BodyPart part = mm.getBodyPart(i);
String ctStr = part.getContentType();
try {
ContentType ct = new ContentType(ctStr);
if (ct.match(mimeType)) {
charset = ct.getParameter(MimeConstants.P_CHARSET);
if (charset == null)
charset = MimeConstants.P_CHARSET_DEFAULT;
byte[] descBytes = ByteUtil.getContent(part.getInputStream(), part.getSize());
return new String(descBytes, charset);
}
// If part is a multipart, recurse.
if (ct.getBaseType().matches(MimeConstants.CT_MULTIPART_WILD)) {
String str = getDescription(part, mimeType);
if (str != null) {
return str;
}
}
} catch (javax.mail.internet.ParseException e) {
ZimbraLog.calendar.warn("Invalid Content-Type found: \"" + ctStr + "\"; skipping part", e);
}
}
} catch (IOException e) {
throw ServiceException.FAILURE("Unable to get calendar item notes MIME part", e);
} catch (MessagingException e) {
throw ServiceException.FAILURE("Unable to get calendar item notes MIME part", e);
}
return null;
}
use of com.zimbra.common.calendar.ZCalendar.ZComponent 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);
}
}
}
Aggregations