Search in sources :

Example 11 with ZComponent

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);
    }
}
Also used : ZComponent(com.zimbra.common.calendar.ZCalendar.ZComponent) ParserException(net.fortuna.ical4j.data.ParserException) ServiceException(com.zimbra.common.service.ServiceException) ICalTimeZone(com.zimbra.common.calendar.ICalTimeZone) ICalTok(com.zimbra.common.calendar.ZCalendar.ICalTok)

Example 12 with ZComponent

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);
}
Also used : ZComponent(com.zimbra.common.calendar.ZCalendar.ZComponent) TimeZoneMap(com.zimbra.common.calendar.TimeZoneMap) ArrayList(java.util.ArrayList) ICalTimeZone(com.zimbra.common.calendar.ICalTimeZone)

Example 13 with ZComponent

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;
}
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 14 with ZComponent

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;
}
Also used : BodyPart(javax.mail.BodyPart) ContentType(javax.mail.internet.ContentType) MessagingException(javax.mail.MessagingException) ByteArrayInputStream(java.io.ByteArrayInputStream) InputStream(java.io.InputStream) IOException(java.io.IOException) ICalTok(com.zimbra.common.calendar.ZCalendar.ICalTok) ZComponent(com.zimbra.common.calendar.ZCalendar.ZComponent) ZVCalendar(com.zimbra.common.calendar.ZCalendar.ZVCalendar) ByteArrayInputStream(java.io.ByteArrayInputStream) MimeMultipart(javax.mail.internet.MimeMultipart)

Example 15 with ZComponent

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);
        }
    }
}
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

ZComponent (com.zimbra.common.calendar.ZCalendar.ZComponent)35 ZProperty (com.zimbra.common.calendar.ZCalendar.ZProperty)18 ZVCalendar (com.zimbra.common.calendar.ZCalendar.ZVCalendar)16 ICalTimeZone (com.zimbra.common.calendar.ICalTimeZone)14 ArrayList (java.util.ArrayList)10 ICalTok (com.zimbra.common.calendar.ZCalendar.ICalTok)9 ParsedDateTime (com.zimbra.common.calendar.ParsedDateTime)7 ZParameter (com.zimbra.common.calendar.ZCalendar.ZParameter)7 Account (com.zimbra.cs.account.Account)7 Invite (com.zimbra.cs.mailbox.calendar.Invite)7 IOException (java.io.IOException)7 TimeZoneMap (com.zimbra.common.calendar.TimeZoneMap)5 ByteArrayInputStream (java.io.ByteArrayInputStream)5 Test (org.junit.Test)5 ServiceException (com.zimbra.common.service.ServiceException)4 InputStream (java.io.InputStream)4 MessagingException (javax.mail.MessagingException)4 MimeMessage (javax.mail.internet.MimeMessage)4 StringWriter (java.io.StringWriter)3 Address (javax.mail.Address)3