Search in sources :

Example 6 with Geo

use of com.zimbra.common.calendar.Geo in project zm-mailbox by Zimbra.

the class CalendarUtils method parseInviteElementCommon.

/**
     * UID, DTSTAMP, and SEQUENCE **MUST** be set by caller
     *
     * @param account
     *            user receiving invite
     * @param element
     *            invite XML element
     * @param newInv
     *            Invite we are currently building up
     * @param oldTzMap
     *            time zone map from A DIFFERENT invite; if this method is
     *            called during modify operation, this map contains time zones
     *            before the modification; null if called during create
     *            operation
     * @return
     * @throws ServiceException
     */
private static void parseInviteElementCommon(Account account, MailItem.Type type, Element element, Invite newInv, boolean recurrenceIdAllowed, boolean recurAllowed) throws ServiceException {
    //zdsync
    String invId = element.getAttribute(MailConstants.A_ID, null);
    Element compElem = element.getOptionalElement(MailConstants.E_INVITE_COMPONENT);
    if (compElem != null) {
        element = compElem;
    }
    //zdsync
    String dts = element.getAttribute(MailConstants.A_CAL_DATETIME, null);
    TimeZoneMap tzMap = newInv.getTimeZoneMap();
    parseTimeZones(element.getParent(), tzMap);
    newInv.setItemType(type);
    // UID
    String uid = element.getAttribute(MailConstants.A_UID, null);
    if (uid != null && uid.length() > 0)
        newInv.setUid(uid);
    // RECURRENCE-ID
    if (recurrenceIdAllowed) {
        Element e = element.getOptionalElement(MailConstants.E_CAL_EXCEPTION_ID);
        if (e != null) {
            ParsedDateTime dt = parseDateTime(e, tzMap);
            RecurId recurId = new RecurId(dt, RecurId.RANGE_NONE);
            newInv.setRecurId(recurId);
        }
    } else {
        if (element.getOptionalElement(MailConstants.E_CAL_EXCEPTION_ID) != null) {
            throw ServiceException.INVALID_REQUEST("May not specify an <exceptId> in this request", null);
        }
    }
    String name = element.getAttribute(MailConstants.A_NAME, "");
    String location = element.getAttribute(MailConstants.A_CAL_LOCATION, "");
    // CATEGORIES
    for (Iterator<Element> catIter = element.elementIterator(MailConstants.E_CAL_CATEGORY); catIter.hasNext(); ) {
        String cat = catIter.next().getText();
        newInv.addCategory(cat);
    }
    // COMMENTs
    for (Iterator<Element> cmtIter = element.elementIterator(MailConstants.E_CAL_COMMENT); cmtIter.hasNext(); ) {
        String cmt = cmtIter.next().getText();
        newInv.addComment(cmt);
    }
    // CONTACTs
    for (Iterator<Element> cnIter = element.elementIterator(MailConstants.E_CAL_CONTACT); cnIter.hasNext(); ) {
        String contact = cnIter.next().getTextTrim();
        newInv.addContact(contact);
    }
    // GEO
    Element geoElem = element.getOptionalElement(MailConstants.E_CAL_GEO);
    if (geoElem != null) {
        Geo geo = Geo.parse(geoElem);
        newInv.setGeo(geo);
    }
    // URL
    String url = element.getAttribute(MailConstants.A_CAL_URL, null);
    newInv.setUrl(url);
    // SEQUENCE
    int seq = (int) element.getAttributeLong(MailConstants.A_CAL_SEQUENCE, 0);
    newInv.setSeqNo(seq);
    // SUMMARY (aka Name or Subject)
    newInv.setName(name);
    // DESCRIPTION
    Element descElem = element.getOptionalElement(MailConstants.E_CAL_DESCRIPTION);
    String desc = descElem != null ? descElem.getText() : null;
    Element descHtmlElem = element.getOptionalElement(MailConstants.E_CAL_DESC_HTML);
    String descHtml = descHtmlElem != null ? descHtmlElem.getText() : null;
    newInv.setDescription(desc, descHtml);
    boolean allDay = element.getAttributeBool(MailConstants.A_CAL_ALLDAY, false);
    newInv.setIsAllDayEvent(allDay);
    // DTSTART
    Element startElem;
    if (newInv.isTodo())
        startElem = element.getOptionalElement(MailConstants.E_CAL_START_TIME);
    else
        startElem = element.getElement(MailConstants.E_CAL_START_TIME);
    if (startElem != null) {
        ParsedDateTime dt = parseDtElement(startElem, tzMap, newInv);
        // fixup for bug 30121
        if (allDay && dt.hasTime()) {
            // If this is supposed to be an all-day event but DTSTART has time part, clear the time part.
            dt.setHasTime(false);
        } else if (!allDay && !dt.hasTime()) {
            // If the event isn't marked as all-day but DTSTART is date-only, the client simply forgot
            // to mark it all-day.  Do all-day implicitly.
            allDay = true;
            newInv.setIsAllDayEvent(allDay);
        }
        newInv.setDtStart(dt);
    }
    // DTEND (for VEVENT) or DUE (for VTODO)
    Element endElem = element.getOptionalElement(MailConstants.E_CAL_END_TIME);
    if (endElem != null) {
        ParsedDateTime dt = parseDtElement(endElem, tzMap, newInv);
        // fixup for bug 30121
        if (allDay && dt.hasTime()) {
            // If this is supposed to be an all-day event but DTEND has time part, clear the time part.
            dt.setHasTime(false);
        } else if (!allDay && !dt.hasTime()) {
            // If the event isn't marked as all-day but DTEND is date-only, the client simply forgot
            // to mark it all-day.  Do all-day implicitly.
            allDay = true;
            newInv.setIsAllDayEvent(allDay);
        }
        if (allDay && !newInv.isTodo()) {
            // HACK ALERT: okay, campers, here's the deal.
            // By definition, our end dates are EXCLUSIVE: DTEND is not
            // included.. eg a meeting 7-8pm actually stops at 7:59
            //
            // This makes sense for normal appointments, but apparently
            // this rule is confusing to people when making
            // all-day-events
            //
            // For all-day-events, people want to say that a 1-day-long
            // appointment starts on 11/1 and ends on 11/1, for example
            // this is inconsistent (and incompatible with RFC2445) but
            // it is what people want. Sooo, we to a bit of a hacky
            // translation when sending/receiving all-day-events.
            //
            dt = dt.add(ParsedDuration.ONE_DAY);
        }
        newInv.setDtEnd(dt);
    } else {
        // DURATION
        Element d = element.getOptionalElement(MailConstants.E_CAL_DURATION);
        if (d != null) {
            ParsedDuration pd = ParsedDuration.parse(d);
            newInv.setDuration(pd);
        }
    }
    // LOCATION
    newInv.setLocation(location);
    // STATUS
    String status = element.getAttribute(MailConstants.A_CAL_STATUS, newInv.isEvent() ? IcalXmlStrMap.STATUS_CONFIRMED : IcalXmlStrMap.STATUS_NEEDS_ACTION);
    validateAttr(IcalXmlStrMap.sStatusMap, MailConstants.A_CAL_STATUS, status);
    newInv.setStatus(status);
    // CLASS
    String classProp = element.getAttribute(MailConstants.A_CAL_CLASS, IcalXmlStrMap.CLASS_PUBLIC);
    validateAttr(IcalXmlStrMap.sClassMap, MailConstants.A_CAL_CLASS, classProp);
    newInv.setClassProp(classProp);
    // PRIORITY
    String priority = element.getAttribute(MailConstants.A_CAL_PRIORITY, null);
    newInv.setPriority(priority);
    if (newInv.isEvent()) {
        // FreeBusy
        String fb = element.getAttribute(MailConstants.A_APPT_FREEBUSY, null);
        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);
        } else {
            // TRANSP is examined only when intended F/B is not supplied.
            String transp = element.getAttribute(MailConstants.A_APPT_TRANSPARENCY, IcalXmlStrMap.TRANSP_OPAQUE);
            validateAttr(IcalXmlStrMap.sTranspMap, MailConstants.A_APPT_TRANSPARENCY, transp);
            newInv.setTransparency(transp);
            // If opaque, don't set intended f/b because there are multiple possibilities.
            if (newInv.isTransparent())
                newInv.setFreeBusy(IcalXmlStrMap.FBTYPE_FREE);
        }
    }
    if (newInv.isTodo()) {
        // PERCENT-COMPLETE
        String pctComplete = element.getAttribute(MailConstants.A_TASK_PERCENT_COMPLETE, null);
        newInv.setPercentComplete(pctComplete);
        // COMPLETED
        String completed = element.getAttribute(MailConstants.A_TASK_COMPLETED, null);
        if (completed != null) {
            try {
                ParsedDateTime c = ParsedDateTime.parseUtcOnly(completed);
                newInv.setCompleted(c.getUtcTime());
            } catch (ParseException e) {
                throw ServiceException.INVALID_REQUEST("Invalid COMPLETED value: " + completed, e);
            }
        } else if (status.equals(IcalXmlStrMap.STATUS_COMPLETED)) {
            newInv.setCompleted(System.currentTimeMillis());
        } else {
            newInv.setCompleted(0);
        }
    }
    // ATTENDEEs
    boolean hasAttendees = false;
    for (Iterator<Element> iter = element.elementIterator(MailConstants.E_CAL_ATTENDEE); iter.hasNext(); ) {
        ZAttendee at = ZAttendee.parse(iter.next());
        newInv.addAttendee(at);
        hasAttendees = true;
    }
    if (hasAttendees && newInv.getMethod().equals(ICalTok.PUBLISH.toString())) {
        newInv.setMethod(ICalTok.REQUEST.toString());
    }
    // ORGANIZER
    Element orgElt = element.getOptionalElement(MailConstants.E_CAL_ORGANIZER);
    if (orgElt != null) {
        ZOrganizer org = ZOrganizer.parse(orgElt);
        newInv.setOrganizer(org);
    }
    // Once we have organizer and attendee information, we can tell if this account is the
    // organizer in this invite or not.
    newInv.setIsOrganizer(account);
    if (!newInv.isCancel()) {
        // draft flag
        // True means invite has changes that haven't been sent to attendees.
        boolean draft = element.getAttributeBool(MailConstants.A_CAL_DRAFT, false);
        newInv.setDraft(draft);
        // neverSent flag
        // True means attendees have never been notified for this invite.
        boolean neverSent = element.getAttributeBool(MailConstants.A_CAL_NEVER_SENT, false);
        newInv.setNeverSent(neverSent);
    }
    // RECUR
    Element recur = element.getOptionalElement(MailConstants.A_CAL_RECUR);
    if (recur != null) {
        if (!recurAllowed) {
            throw ServiceException.INVALID_REQUEST("No <recur> allowed in an exception", null);
        }
        // Ensure DTSTART is set if doing recurrence.
        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);
            }
        }
        Recurrence.IRecurrence recurrence = parseRecur(recur, tzMap, newInv.getStartTime(), newInv.getEndTime(), newInv.getDuration(), newInv.getRecurId());
        newInv.setRecurrence(recurrence);
    }
    // VALARMs
    Iterator<Element> alarmsIter = element.elementIterator(MailConstants.E_CAL_ALARM);
    while (alarmsIter.hasNext()) {
        Alarm alarm = Alarm.parse(alarmsIter.next());
        if (alarm != null)
            newInv.addAlarm(alarm);
    }
    List<ZProperty> xprops = parseXProps(element);
    for (ZProperty prop : xprops) newInv.addXProp(prop);
    newInv.validateDuration();
    //zdsync: must set this only after recur is processed
    if (invId != null) {
        try {
            int invIdInt = Integer.parseInt(invId);
            newInv.setInviteId(invIdInt);
        } catch (NumberFormatException e) {
        // ignore if invId is not a number, e.g. refers to a remote account
        }
    }
    if (dts != null) {
        newInv.setDtStamp(Long.parseLong(dts));
    }
    Element fragment = element.getOptionalElement(MailConstants.E_FRAG);
    if (fragment != null) {
        newInv.setFragment(fragment.getText());
    }
}
Also used : IRecurrence(com.zimbra.cs.mailbox.calendar.Recurrence.IRecurrence) Recurrence(com.zimbra.cs.mailbox.calendar.Recurrence) ParsedDuration(com.zimbra.common.calendar.ParsedDuration) IRecurrence(com.zimbra.cs.mailbox.calendar.Recurrence.IRecurrence) Element(com.zimbra.common.soap.Element) ZOrganizer(com.zimbra.cs.mailbox.calendar.ZOrganizer) RecurId(com.zimbra.cs.mailbox.calendar.RecurId) Geo(com.zimbra.common.calendar.Geo) ZAttendee(com.zimbra.cs.mailbox.calendar.ZAttendee) Alarm(com.zimbra.cs.mailbox.calendar.Alarm) TimeZoneMap(com.zimbra.common.calendar.TimeZoneMap) ZProperty(com.zimbra.common.calendar.ZCalendar.ZProperty) ParsedDateTime(com.zimbra.common.calendar.ParsedDateTime) ParseException(java.text.ParseException)

Example 7 with Geo

use of com.zimbra.common.calendar.Geo in project zm-mailbox by Zimbra.

the class ToXML method encodeInviteComponent.

public static Element encodeInviteComponent(Element parent, ItemIdFormatter ifmt, OperationContext octxt, CalendarItem calItem, /* may be null */
ItemId calId, /* may be null */
Invite invite, int fields, boolean neuter) throws ServiceException {
    boolean allFields = true;
    if (fields != NOTIFY_FIELDS) {
        allFields = false;
        if (!needToOutput(fields, Change.INVITE)) {
            return parent;
        }
    }
    Element e = parent.addElement(MailConstants.E_INVITE_COMPONENT);
    e.addAttribute(MailConstants.A_CAL_METHOD, invite.getMethod());
    e.addAttribute(MailConstants.A_CAL_COMPONENT_NUM, invite.getComponentNum());
    e.addAttribute(MailConstants.A_CAL_RSVP, invite.getRsvp());
    boolean allowPrivateAccess = calItem != null ? allowPrivateAccess(octxt, calItem) : true;
    if (allFields) {
        if (invite.isPublic() || allowPrivateAccess) {
            String priority = invite.getPriority();
            if (priority != null) {
                e.addAttribute(MailConstants.A_CAL_PRIORITY, priority);
            }
            e.addAttribute(MailConstants.A_NAME, invite.getName());
            e.addAttribute(MailConstants.A_CAL_LOCATION, invite.getLocation());
            List<String> categories = invite.getCategories();
            if (categories != null) {
                for (String cat : categories) {
                    e.addElement(MailConstants.E_CAL_CATEGORY).setText(cat);
                }
            }
            List<String> comments = invite.getComments();
            if (comments != null) {
                for (String cmt : comments) {
                    e.addElement(MailConstants.E_CAL_COMMENT).setText(cmt);
                }
            }
            List<String> contacts = invite.getContacts();
            if (contacts != null) {
                for (String contact : contacts) {
                    e.addElement(MailConstants.E_CAL_CONTACT).setText(contact);
                }
            }
            Geo geo = invite.getGeo();
            if (geo != null) {
                geo.toXml(e);
            }
            // Percent Complete (VTODO)
            if (invite.isTodo()) {
                String pct = invite.getPercentComplete();
                if (pct != null)
                    e.addAttribute(MailConstants.A_TASK_PERCENT_COMPLETE, pct);
                long completed = invite.getCompleted();
                if (completed != 0) {
                    ParsedDateTime c = ParsedDateTime.fromUTCTime(completed);
                    e.addAttribute(MailConstants.A_TASK_COMPLETED, c.getDateTimePartString());
                }
            }
            // Attendee(s)
            List<ZAttendee> attendees = invite.getAttendees();
            for (ZAttendee at : attendees) {
                at.toXml(e);
            }
            // Alarms
            Iterator<Alarm> alarmsIter = invite.alarmsIterator();
            while (alarmsIter.hasNext()) {
                Alarm alarm = alarmsIter.next();
                alarm.toXml(e);
            }
            // x-prop
            encodeXProps(e, invite.xpropsIterator());
            // fragment
            String fragment = invite.getFragment();
            if (!Strings.isNullOrEmpty(fragment)) {
                e.addAttribute(MailConstants.E_FRAG, fragment, Element.Disposition.CONTENT);
            }
            if (!invite.hasBlobPart()) {
                e.addAttribute(MailConstants.A_CAL_NO_BLOB, true);
            }
            // Description (plain and html)
            String desc = invite.getDescription();
            if (desc != null) {
                Element descElem = e.addElement(MailConstants.E_CAL_DESCRIPTION);
                descElem.setText(desc);
            }
            String descHtml = invite.getDescriptionHtml();
            BrowserDefang defanger = DefangFactory.getDefanger(MimeConstants.CT_TEXT_HTML);
            if (descHtml != null) {
                try {
                    descHtml = StringUtil.stripControlCharacters(descHtml);
                    descHtml = defanger.defang(descHtml, neuter);
                    Element descHtmlElem = e.addElement(MailConstants.E_CAL_DESC_HTML);
                    descHtmlElem.setText(descHtml);
                } catch (IOException ex) {
                    ZimbraLog.calendar.warn("Unable to defang HTML for SetAppointmentRequest", ex);
                }
            }
            if (invite.isEvent()) {
                if (calItem != null && calItem instanceof Appointment) {
                    Instance inst = Instance.fromInvite(calItem.getId(), invite);
                    Appointment appt = (Appointment) calItem;
                    e.addAttribute(MailConstants.A_APPT_FREEBUSY_ACTUAL, appt.getEffectiveFreeBusyActual(invite, inst));
                }
                e.addAttribute(MailConstants.A_APPT_FREEBUSY, invite.getFreeBusy());
                e.addAttribute(MailConstants.A_APPT_TRANSPARENCY, invite.getTransparency());
            }
            // Organizer
            if (invite.hasOrganizer()) {
                ZOrganizer org = invite.getOrganizer();
                org.toXml(e);
            }
            e.addAttribute(MailConstants.A_CAL_URL, invite.getUrl());
        }
        if (invite.isOrganizer()) {
            e.addAttribute(MailConstants.A_CAL_ISORG, true);
        }
        boolean isRecurring = false;
        e.addAttribute("x_uid", invite.getUid());
        e.addAttribute(MailConstants.A_UID, invite.getUid());
        e.addAttribute(MailConstants.A_CAL_SEQUENCE, invite.getSeqNo());
        //zdsync
        e.addAttribute(MailConstants.A_CAL_DATETIME, invite.getDTStamp());
        String itemId = null;
        if (calId != null) {
            itemId = calId.toString(ifmt);
        } else if (calItem != null) {
            itemId = ifmt.formatItemId(calItem);
        }
        if ((itemId != null) && !("0".equals(itemId))) {
            e.addAttribute(MailConstants.A_CAL_ID, /* calItemId */
            itemId);
            if (invite.isEvent()) {
                // for backward compat
                e.addAttribute(MailConstants.A_APPT_ID_DEPRECATE_ME, /* apptId */
                itemId);
            }
            if (calItem != null) {
                ItemId ciFolderId = new ItemId(calItem.getMailbox(), calItem.getFolderId());
                e.addAttribute(MailConstants.A_CAL_ITEM_FOLDER, /* ciFolder */
                ifmt.formatItemId(ciFolderId));
            }
        }
        Recurrence.IRecurrence recur = invite.getRecurrence();
        if (recur != null) {
            isRecurring = true;
            Element recurElt = e.addElement(MailConstants.E_CAL_RECUR);
            recur.toXml(recurElt);
        }
        e.addAttribute(MailConstants.A_CAL_STATUS, invite.getStatus());
        e.addAttribute(MailConstants.A_CAL_CLASS, invite.getClassProp());
        boolean allDay = invite.isAllDayEvent();
        boolean isException = invite.hasRecurId();
        if (isException) {
            e.addAttribute(MailConstants.A_CAL_IS_EXCEPTION, true);
            RecurId rid = invite.getRecurId();
            e.addAttribute(MailConstants.A_CAL_RECURRENCE_ID_Z, rid.getDtZ());
            encodeRecurId(e, rid, allDay);
        }
        boolean forceUTC = DebugConfig.calendarForceUTC && !isRecurring && !isException && !allDay;
        ParsedDateTime dtStart = invite.getStartTime();
        if (dtStart != null) {
            encodeDtStart(e, dtStart, allDay, forceUTC);
        }
        ParsedDateTime dtEnd = invite.getEndTime();
        if (dtEnd != null) {
            encodeDtEnd(e, dtEnd, allDay, invite.isTodo(), forceUTC);
        }
        ParsedDuration dur = invite.getDuration();
        if (dur != null) {
            dur.toXml(e);
        }
        if (allDay) {
            e.addAttribute(MailConstants.A_CAL_ALLDAY, true);
        }
        if (invite.isDraft()) {
            e.addAttribute(MailConstants.A_CAL_DRAFT, true);
        }
        if (invite.isNeverSent()) {
            e.addAttribute(MailConstants.A_CAL_NEVER_SENT, true);
        }
    }
    return e;
}
Also used : Appointment(com.zimbra.cs.mailbox.Appointment) Recurrence(com.zimbra.cs.mailbox.calendar.Recurrence) IRecurrence(com.zimbra.cs.mailbox.calendar.Recurrence.IRecurrence) Instance(com.zimbra.cs.mailbox.CalendarItem.Instance) IRecurrence(com.zimbra.cs.mailbox.calendar.Recurrence.IRecurrence) ParsedDuration(com.zimbra.common.calendar.ParsedDuration) Element(com.zimbra.common.soap.Element) ZOrganizer(com.zimbra.cs.mailbox.calendar.ZOrganizer) BrowserDefang(com.zimbra.cs.html.BrowserDefang) RecurId(com.zimbra.cs.mailbox.calendar.RecurId) IOException(java.io.IOException) ItemId(com.zimbra.cs.service.util.ItemId) Geo(com.zimbra.common.calendar.Geo) ZAttendee(com.zimbra.cs.mailbox.calendar.ZAttendee) Alarm(com.zimbra.cs.mailbox.calendar.Alarm) ParsedDateTime(com.zimbra.common.calendar.ParsedDateTime)

Example 8 with Geo

use of com.zimbra.common.calendar.Geo in project zm-mailbox by Zimbra.

the class Invite method decodeMetadata.

/**
     * This API is public for RedoLogging to call into it -- you probably don't want to call it from
     * anywhere else!
     *
     * @param mailboxId
     * @param meta
     * @param calItem
     * @param accountTZ
     * @return
     * @throws ServiceException
     */
public static Invite decodeMetadata(int mailboxId, Metadata meta, CalendarItem calItem, ICalTimeZone accountTZ) throws ServiceException {
    byte btype = (byte) meta.getLong(FN_ITEMTYPE, -1);
    MailItem.Type type = btype >= 0 ? MailItem.Type.of(btype) : MailItem.Type.APPOINTMENT;
    String uid = meta.get(FN_UID, null);
    int mailItemId = (int) meta.getLong(FN_INVMSGID);
    int componentNum = (int) meta.getLong(FN_COMPNUM);
    String classProp = meta.get(FN_CLASS, IcalXmlStrMap.CLASS_PUBLIC);
    boolean classPropSetByMe = meta.getBool(FN_CLASS_SETBYME, false);
    String status = meta.get(FN_STATUS, IcalXmlStrMap.STATUS_CONFIRMED);
    String freebusy = meta.get(FN_APPT_FREEBUSY, null);
    String transp = meta.get(FN_TRANSP, IcalXmlStrMap.TRANSP_OPAQUE);
    boolean sentByMe = meta.getBool(FN_SENTBYME);
    String fragment = meta.get(FN_FRAGMENT, "");
    // default to false for backward compat
    boolean descInMeta = meta.getBool(FN_DESC_IN_META, false);
    String desc = descInMeta ? meta.get(FN_DESC, null) : null;
    String descHtml = descInMeta ? meta.get(FN_DESC_HTML, null) : null;
    long completed = meta.getLong(FN_COMPLETED, 0);
    ParsedDateTime dtStart = null;
    ParsedDateTime dtEnd = null;
    ParsedDuration duration = null;
    RecurId recurrenceId = null;
    TimeZoneMap tzMap = Util.decodeFromMetadata(meta.getMap(FN_TZMAP), accountTZ);
    Metadata metaRecur = meta.getMap(FN_RECURRENCE, true);
    Recurrence.IRecurrence recurrence = null;
    if (metaRecur != null) {
        recurrence = Recurrence.decodeMetadata(metaRecur, tzMap);
    }
    String methodStr = meta.get(FN_METHOD, ICalTok.PUBLISH.toString());
    if (ICalTok.CANCEL.toString().equals(methodStr))
        status = IcalXmlStrMap.STATUS_CANCELLED;
    int flags = (int) meta.getLong(FN_APPT_FLAGS, 0);
    try {
        // DtStart
        dtStart = ParsedDateTime.parse(meta.get(FN_START, null), tzMap);
        // DtEnd
        dtEnd = ParsedDateTime.parse(meta.get(FN_END, null), tzMap);
        if ((flags & APPT_FLAG_ALLDAY) != 0) {
            // Fixup historic data with incorrect all-day start/end format.
            if (dtStart != null)
                dtStart.forceDateOnly();
            if (dtEnd != null)
                dtEnd.forceDateOnly();
        }
        // Duration
        duration = ParsedDuration.parse(meta.get(FN_DURATION, null));
        if (meta.containsKey(FN_RECUR_ID)) {
            Metadata rdata = meta.getMap(FN_RECUR_ID);
            recurrenceId = RecurId.decodeMetadata(rdata, tzMap);
        }
    } catch (ParseException e) {
        throw ServiceException.FAILURE(String.format("Error parsing metadata for invite %s-%s in calItem %s", mailItemId, componentNum, (calItem != null) ? Integer.toString(calItem.getId()) : "(null)"), e);
    }
    String name = meta.get(FN_NAME, "");
    String loc = meta.get(FN_LOCATION, null);
    // For existing invites with no partstat, default to ACCEPTED status.
    String partStat = meta.get(FN_PARTSTAT, IcalXmlStrMap.PARTSTAT_ACCEPTED);
    // For existing invites with no RSVP, default to true.
    boolean rsvp = meta.getBool(FN_RSVP, true);
    long dtstamp = meta.getLong(FN_DTSTAMP, 0);
    long lastModified = meta.getLong(FN_LAST_MODIFIED, 0);
    int seqno = (int) meta.getLong(FN_SEQ_NO, 0);
    int lastFullSeqno = (int) meta.getLong(FN_LAST_FULL_SEQ_NO, seqno);
    ZOrganizer org = null;
    try {
        Metadata metaOrg = meta.getMap(FN_ORGANIZER, true);
        org = metaOrg != null ? new ZOrganizer(metaOrg) : null;
    } catch (ServiceException e) {
        sLog.warn("Problem decoding organizer for calItem %s invite %s-%s", (calItem != null) ? Integer.toString(calItem.getId()) : "(null)", mailItemId, componentNum);
    }
    long numAts = meta.getLong(FN_NUM_ATTENDEES, 0);
    ArrayList<ZAttendee> attendees = new ArrayList<ZAttendee>((int) numAts);
    for (int i = 0; i < numAts; i++) {
        try {
            Metadata metaAttendee = meta.getMap(FN_ATTENDEE + i, true);
            if (metaAttendee != null)
                attendees.add(new ZAttendee(metaAttendee));
        } catch (ServiceException e) {
            ZimbraLog.calendar.warn("Problem decoding attendee %s for calendar item %s invite %s-%s", i, (calItem != null) ? Integer.toString(calItem.getId()) : "(null)", mailItemId, componentNum);
        }
    }
    boolean isOrganizer = false;
    if (meta.containsKey(FN_IS_ORGANIZER)) {
        isOrganizer = meta.getBool(FN_IS_ORGANIZER);
    } else {
        // backward compat for invites created before FN_IS_ORGANIZER was introduced
        if (org != null) {
            String orgAddr = org.getAddress();
            Account account = MailboxManager.getInstance().getMailboxById(mailboxId).getAccount();
            AccountAddressMatcher acctMatcher = new AccountAddressMatcher(account);
            isOrganizer = acctMatcher.matches(orgAddr);
        } else {
            // If there are other attendees, it's an Outlook POP/IMAP bug.  If not,
            // it's a properly formatted single-user event.  See isOrganizer()
            // method for more info.
            isOrganizer = numAts < 1;
        }
    }
    String priority = meta.get(FN_PRIORITY, null);
    String pctComplete = meta.get(FN_PCT_COMPLETE, null);
    List<String> comments = null;
    int numComm = (int) meta.getLong(FN_NUM_COMMENTS, 0);
    if (numComm > 0) {
        comments = new ArrayList<String>(numComm);
        for (int i = 0; i < numComm; i++) {
            String comm = meta.get(FN_COMMENT + i, null);
            if (comm != null)
                comments.add(comm);
        }
    }
    List<String> contacts = null;
    int numContacts = (int) meta.getLong(FN_NUM_CONTACTS, 0);
    if (numContacts > 0) {
        contacts = new ArrayList<String>(numContacts);
        for (int i = 0; i < numContacts; i++) {
            String contact = meta.get(FN_CONTACT + i, null);
            if (contact != null)
                contacts.add(contact);
        }
    }
    List<String> categories = null;
    int numCat = (int) meta.getLong(FN_NUM_CATEGORIES, 0);
    if (numCat > 0) {
        categories = new ArrayList<String>(numCat);
        for (int i = 0; i < numCat; i++) {
            String cat = meta.get(FN_CATEGORY + i, null);
            if (cat != null)
                categories.add(cat);
        }
    }
    Geo geo = null;
    Metadata metaGeo = meta.getMap(FN_GEO, true);
    if (metaGeo != null)
        geo = Util.decodeGeoFromMetadata(metaGeo);
    String url = meta.get(FN_URL, null);
    Invite invite = new Invite(type, methodStr, tzMap, calItem, uid, status, priority, pctComplete, completed, freebusy, transp, classProp, dtStart, dtEnd, duration, recurrence, isOrganizer, org, attendees, name, loc, flags, partStat, rsvp, recurrenceId, dtstamp, lastModified, seqno, lastFullSeqno, mailboxId, mailItemId, componentNum, sentByMe, desc, descHtml, fragment, comments, categories, contacts, geo, url);
    // a little hacky, but necessary
    invite.mDescInMeta = descInMeta;
    invite.setClassPropSetByMe(classPropSetByMe);
    long numAlarms = meta.getLong(FN_NUM_ALARMS, 0);
    for (int i = 0; i < numAlarms; i++) {
        try {
            Metadata metaAlarm = meta.getMap(FN_ALARM + i, true);
            if (metaAlarm != null) {
                Alarm alarm = Alarm.decodeMetadata(metaAlarm);
                if (alarm != null)
                    invite.addAlarm(alarm);
            }
        } catch (ServiceException e) {
            ZimbraLog.calendar.warn("Problem decoding alarm %s for calendar item %s invite %s-%s", i, (calItem != null) ? Integer.toString(calItem.getId()) : "(null)", mailItemId, componentNum, e);
        }
    }
    List<ZProperty> xprops = Util.decodeXPropsFromMetadata(meta);
    if (xprops != null) {
        for (ZProperty xprop : xprops) {
            boolean isHtmlDesc = false;
            if (ICalTok.X_ALT_DESC.equals(xprop.getToken())) {
                // Backward compat.  We used to save X-ALT-DESC property as an x-prop.  Now we use it
                // for HTML description, when FMTTYPE=text/html.
                ZParameter fmttype = xprop.getParameter(ICalTok.FMTTYPE);
                if (fmttype != null && MimeConstants.CT_TEXT_HTML.equalsIgnoreCase(fmttype.getValue())) {
                    isHtmlDesc = true;
                    invite.mDescHtml = xprop.getValue();
                }
            }
            if (!isHtmlDesc)
                invite.addXProp(xprop);
        }
    }
    invite.setDontIndexMimeMessage(meta.getBool(FN_DONT_INDEX_MM, false));
    boolean localOnly = meta.getBool(FN_LOCAL_ONLY, false);
    invite.setLocalOnly(localOnly);
    invite.sanitize(false);
    return invite;
}
Also used : IRecurrence(com.zimbra.cs.mailbox.calendar.Recurrence.IRecurrence) Account(com.zimbra.cs.account.Account) ParsedDuration(com.zimbra.common.calendar.ParsedDuration) IRecurrence(com.zimbra.cs.mailbox.calendar.Recurrence.IRecurrence) Metadata(com.zimbra.cs.mailbox.Metadata) ArrayList(java.util.ArrayList) TimeZoneMap(com.zimbra.common.calendar.TimeZoneMap) ParsedDateTime(com.zimbra.common.calendar.ParsedDateTime) 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) AccountAddressMatcher(com.zimbra.cs.util.AccountUtil.AccountAddressMatcher) ZProperty(com.zimbra.common.calendar.ZCalendar.ZProperty) ParseException(java.text.ParseException)

Aggregations

Geo (com.zimbra.common.calendar.Geo)8 ParsedDateTime (com.zimbra.common.calendar.ParsedDateTime)5 ParsedDuration (com.zimbra.common.calendar.ParsedDuration)5 Element (com.zimbra.common.soap.Element)5 IRecurrence (com.zimbra.cs.mailbox.calendar.Recurrence.IRecurrence)4 ZOrganizer (com.zimbra.cs.mailbox.calendar.ZOrganizer)4 ZProperty (com.zimbra.common.calendar.ZCalendar.ZProperty)3 RecurId (com.zimbra.cs.mailbox.calendar.RecurId)3 ParseException (java.text.ParseException)3 TimeZoneMap (com.zimbra.common.calendar.TimeZoneMap)2 ZParameter (com.zimbra.common.calendar.ZCalendar.ZParameter)2 ServiceException (com.zimbra.common.service.ServiceException)2 Account (com.zimbra.cs.account.Account)2 Appointment (com.zimbra.cs.mailbox.Appointment)2 MailItem (com.zimbra.cs.mailbox.MailItem)2 Metadata (com.zimbra.cs.mailbox.Metadata)2 Alarm (com.zimbra.cs.mailbox.calendar.Alarm)2 Recurrence (com.zimbra.cs.mailbox.calendar.Recurrence)2 ZAttendee (com.zimbra.cs.mailbox.calendar.ZAttendee)2 ItemId (com.zimbra.cs.service.util.ItemId)2