use of com.zimbra.common.calendar.ParsedDuration in project zm-mailbox by Zimbra.
the class ScheduleOutbox method handleFreebusyRequest.
private void handleFreebusyRequest(DavContext ctxt, ZComponent vfreebusy, String originator, String rcpt, Element resp) throws DavException, ServiceException {
ZProperty dtstartProp = vfreebusy.getProperty(ICalTok.DTSTART);
ZProperty dtendProp = vfreebusy.getProperty(ICalTok.DTEND);
ZProperty durationProp = vfreebusy.getProperty(ICalTok.DURATION);
if (dtstartProp == null || dtendProp == null && durationProp == null)
throw new DavException("missing dtstart or dtend/duration in the schedule request", HttpServletResponse.SC_BAD_REQUEST, null);
long start, end;
try {
ParsedDateTime startTime = ParsedDateTime.parseUtcOnly(dtstartProp.getValue());
start = startTime.getUtcTime();
if (dtendProp != null) {
end = ParsedDateTime.parseUtcOnly(dtendProp.getValue()).getUtcTime();
} else {
ParsedDuration dur = ParsedDuration.parse(durationProp.getValue());
ParsedDateTime endTime = startTime.add(dur);
end = endTime.getUtcTime();
}
} catch (ParseException pe) {
throw new DavException("can't parse date", HttpServletResponse.SC_BAD_REQUEST, pe);
}
ZimbraLog.dav.debug("rcpt: " + rcpt + ", start: " + new Date(start) + ", end: " + new Date(end));
FreeBusy fb = null;
if (ctxt.isFreebusyEnabled()) {
FreeBusyQuery fbQuery = new FreeBusyQuery(ctxt.getRequest(), ctxt.getAuthAccount(), start, end, null);
fbQuery.addEmailAddress(getAddressFromPrincipalURL(rcpt), FreeBusyQuery.CALENDAR_FOLDER_ALL);
java.util.Collection<FreeBusy> fbResult = fbQuery.getResults();
if (fbResult.size() > 0)
fb = fbResult.iterator().next();
}
if (fb != null) {
String fbMsg = fb.toVCalendar(FreeBusy.Method.REPLY, originator, rcpt, null);
resp.addElement(DavElements.E_RECIPIENT).addElement(DavElements.E_HREF).setText(rcpt);
resp.addElement(DavElements.E_REQUEST_STATUS).setText("2.0;Success");
resp.addElement(DavElements.E_CALENDAR_DATA).setText(fbMsg);
} else {
resp.addElement(DavElements.E_RECIPIENT).addElement(DavElements.E_HREF).setText(rcpt);
resp.addElement(DavElements.E_REQUEST_STATUS).setText("5.3;No f/b for the user");
}
}
use of com.zimbra.common.calendar.ParsedDuration in project zm-mailbox by Zimbra.
the class CalendarUtils method cancelInvite.
private static Invite cancelInvite(Account acct, Account senderAcct, boolean allowPrivateAccess, boolean onBehalfOf, Invite inv, String comment, List<ZAttendee> forAttendees, RecurId recurId, boolean incrementSeq) throws ServiceException {
Invite cancel = new Invite(inv.getItemType(), ICalTok.CANCEL.toString(), inv.getTimeZoneMap(), inv.isOrganizer());
// ORGANIZER
if (inv.hasOrganizer()) {
ZOrganizer org = new ZOrganizer(inv.getOrganizer());
if (onBehalfOf && senderAcct != null)
org.setSentBy(senderAcct.getName());
cancel.setOrganizer(org);
}
// ATTENDEEs
List<ZAttendee> attendees = forAttendees != null ? forAttendees : inv.getAttendees();
for (ZAttendee a : attendees) cancel.addAttendee(a);
cancel.setClassProp(inv.getClassProp());
boolean showAll = inv.isPublic() || allowPrivateAccess;
Locale locale = acct.getLocale();
if (!showAll) {
// SUMMARY
String sbj = L10nUtil.getMessage(MsgKey.calendarSubjectWithheld, locale);
cancel.setName(CalendarMailSender.getCancelSubject(sbj, locale));
} else {
// SUMMARY
cancel.setName(CalendarMailSender.getCancelSubject(inv.getName(), locale));
// COMMENT
if (comment != null && !comment.equals(""))
cancel.addComment(comment);
}
// UID
cancel.setUid(inv.getUid());
// RECURRENCE-ID
if (inv.hasRecurId()) {
// FIXME: if RECURRENCE-ID can be a range (THISANDFUTURE) then we'll
// need to be smarter here
cancel.setRecurId(inv.getRecurId());
} else {
if (recurId != null) {
cancel.setRecurId(recurId);
}
}
// all-day
// bug 30121
cancel.setIsAllDayEvent(inv.isAllDayEvent());
// DTSTART, DTEND, and LOCATION (Outlook seems to require these, even
// though they are optional according to RFC2446.)
ParsedDateTime dtStart = recurId == null ? inv.getStartTime() : recurId.getDt();
if (dtStart != null) {
cancel.setDtStart(dtStart);
ParsedDuration dur = inv.getEffectiveDuration();
if (dur != null)
cancel.setDtEnd(dtStart.add(dur));
}
// LOCATION
cancel.setLocation(inv.getLocation());
// SEQUENCE
int seq = inv.getSeqNo();
if (incrementSeq) {
// present value. (bug 8465)
if (acct != null && inv.isOrganizer())
seq++;
}
cancel.setSeqNo(seq);
// STATUS
cancel.setStatus(IcalXmlStrMap.STATUS_CANCELLED);
// DTSTAMP
cancel.setDtStamp(new Date().getTime());
return cancel;
}
use of com.zimbra.common.calendar.ParsedDuration in project zm-mailbox by Zimbra.
the class CompleteTaskInstance method createCompletedInstanceInvite.
private Invite createCompletedInstanceInvite(Invite recur, ParsedDateTime dtStart) throws ServiceException {
Invite inst = new Invite(MailItem.Type.TASK, recur.getMethod(), (recur.getTimeZoneMap() != null) ? recur.getTimeZoneMap().clone() : null, recur.isOrganizer());
long now = System.currentTimeMillis();
// Assign a new UID.
String uid = LdapUtil.generateUUID();
inst.setUid(uid);
inst.setSeqNo(0);
// Set completed status/pct/time.
inst.setStatus(IcalXmlStrMap.STATUS_COMPLETED);
inst.setPercentComplete("100");
inst.setCompleted(now);
// Set time fields.
inst.setDtStart(dtStart);
ParsedDuration dur = recur.getEffectiveDuration();
if (dur != null) {
ParsedDateTime due = dtStart.add(dur);
inst.setDtEnd(due);
}
inst.setDtStamp(now);
// Recurrence-related fields should be unset.
inst.setRecurrence(null);
inst.setRecurId(null);
// Copy the rest of the fields.
inst.setPriority(recur.getPriority());
inst.setOrganizer(recur.getOrganizer());
List<ZAttendee> attendees = recur.getAttendees();
for (ZAttendee at : attendees) inst.addAttendee(at);
inst.setName(recur.getName());
inst.setLocation(recur.getLocation());
inst.setFlags(recur.getFlags());
inst.setDescription(recur.getDescription(), recur.getDescriptionHtml());
inst.setFragment(recur.getFragment());
return inst;
}
use of com.zimbra.common.calendar.ParsedDuration 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.ParsedDuration 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