Search in sources :

Example 1 with ParsedDuration

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");
    }
}
Also used : FreeBusy(com.zimbra.cs.fb.FreeBusy) DavException(com.zimbra.cs.dav.DavException) ParsedDuration(com.zimbra.common.calendar.ParsedDuration) FreeBusyQuery(com.zimbra.cs.fb.FreeBusyQuery) ZProperty(com.zimbra.common.calendar.ZCalendar.ZProperty) ParsedDateTime(com.zimbra.common.calendar.ParsedDateTime) ParseException(java.text.ParseException) Date(java.util.Date)

Example 2 with ParsedDuration

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;
}
Also used : Locale(java.util.Locale) ParsedDuration(com.zimbra.common.calendar.ParsedDuration) ZAttendee(com.zimbra.cs.mailbox.calendar.ZAttendee) ZOrganizer(com.zimbra.cs.mailbox.calendar.ZOrganizer) ParsedDateTime(com.zimbra.common.calendar.ParsedDateTime) Invite(com.zimbra.cs.mailbox.calendar.Invite) Date(java.util.Date)

Example 3 with ParsedDuration

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;
}
Also used : ParsedDuration(com.zimbra.common.calendar.ParsedDuration) ZAttendee(com.zimbra.cs.mailbox.calendar.ZAttendee) ParsedDateTime(com.zimbra.common.calendar.ParsedDateTime) Invite(com.zimbra.cs.mailbox.calendar.Invite)

Example 4 with ParsedDuration

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;
}
Also used : IRecurrence(com.zimbra.cs.mailbox.calendar.Recurrence.IRecurrence) ParsedDuration(com.zimbra.common.calendar.ParsedDuration) ZParameter(com.zimbra.common.calendar.ZCalendar.ZParameter) ICalTok(com.zimbra.common.calendar.ZCalendar.ICalTok) ZComponent(com.zimbra.common.calendar.ZCalendar.ZComponent) IRecurrence(com.zimbra.cs.mailbox.calendar.Recurrence.IRecurrence) ZProperty(com.zimbra.common.calendar.ZCalendar.ZProperty) Iterator(java.util.Iterator) ParsedDateTime(com.zimbra.common.calendar.ParsedDateTime)

Example 5 with ParsedDuration

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);
        }
    }
}
Also used : IRecurrence(com.zimbra.cs.mailbox.calendar.Recurrence.IRecurrence) ParsedDuration(com.zimbra.common.calendar.ParsedDuration) ArrayList(java.util.ArrayList) ICalTok(com.zimbra.common.calendar.ZCalendar.ICalTok) ZComponent(com.zimbra.common.calendar.ZCalendar.ZComponent) IRecurrence(com.zimbra.cs.mailbox.calendar.Recurrence.IRecurrence) List(java.util.List) ArrayList(java.util.ArrayList) ImmutableList(com.google.common.collect.ImmutableList) ParsedDateTime(com.zimbra.common.calendar.ParsedDateTime) Attach(com.zimbra.common.calendar.Attach) ZParameter(com.zimbra.common.calendar.ZCalendar.ZParameter) Geo(com.zimbra.common.calendar.Geo) MailItem(com.zimbra.cs.mailbox.MailItem) ServiceException(com.zimbra.common.service.ServiceException) ZProperty(com.zimbra.common.calendar.ZCalendar.ZProperty) ParseException(java.text.ParseException)

Aggregations

ParsedDateTime (com.zimbra.common.calendar.ParsedDateTime)23 ParsedDuration (com.zimbra.common.calendar.ParsedDuration)23 IRecurrence (com.zimbra.cs.mailbox.calendar.Recurrence.IRecurrence)10 ParseException (java.text.ParseException)9 ArrayList (java.util.ArrayList)9 Element (com.zimbra.common.soap.Element)8 ZProperty (com.zimbra.common.calendar.ZCalendar.ZProperty)7 Invite (com.zimbra.cs.mailbox.calendar.Invite)6 Geo (com.zimbra.common.calendar.Geo)5 TimeZoneMap (com.zimbra.common.calendar.TimeZoneMap)5 ServiceException (com.zimbra.common.service.ServiceException)5 RecurId (com.zimbra.cs.mailbox.calendar.RecurId)5 ZAttendee (com.zimbra.cs.mailbox.calendar.ZAttendee)5 ZOrganizer (com.zimbra.cs.mailbox.calendar.ZOrganizer)5 Attach (com.zimbra.common.calendar.Attach)4 ICalTimeZone (com.zimbra.common.calendar.ICalTimeZone)4 ICalTok (com.zimbra.common.calendar.ZCalendar.ICalTok)4 ZParameter (com.zimbra.common.calendar.ZCalendar.ZParameter)4 Account (com.zimbra.cs.account.Account)3 CalendarItem (com.zimbra.cs.mailbox.CalendarItem)3