Search in sources :

Example 1 with ReplyInfo

use of com.zimbra.cs.mailbox.CalendarItem.ReplyInfo in project zm-mailbox by Zimbra.

the class SetCalendarItem method getPrintableData.

@Override
protected String getPrintableData() {
    StringBuffer toRet = new StringBuffer();
    toRet.append("calItemId=").append(mCalendarItemId);
    toRet.append(", calItemPartStat=").append(mCalendarItemPartStat);
    toRet.append(", folder=").append(mFolderId);
    if (getVersion().atLeast(1, 11)) {
        toRet.append(", flags=").append(mFlags);
        toRet.append(", tags=").append(TagUtil.encodeTags(mTags));
    }
    toRet.append("\n");
    if (mDefaultInvite != null) {
        toRet.append("Default=").append(mDefaultInvite.toString()).append("\n");
    }
    if (mExceptions != null) {
        for (int i = 0; i < mExceptions.length; i++) {
            toRet.append("Exception").append(i).append("=").append(mExceptions[i].toString()).append("\n");
        }
    }
    if (mReplies != null) {
        int i = 0;
        for (ReplyInfo ri : mReplies) {
            toRet.append("Reply").append(i).append("=").append(ri.toString()).append("\n");
            i++;
        }
    }
    toRet.append("nextAlarm=").append(mNextAlarm).append("\n");
    return toRet.toString();
}
Also used : ReplyInfo(com.zimbra.cs.mailbox.CalendarItem.ReplyInfo)

Example 2 with ReplyInfo

use of com.zimbra.cs.mailbox.CalendarItem.ReplyInfo in project zm-mailbox by Zimbra.

the class SetCalendarItem method deserializeData.

@Override
protected void deserializeData(RedoLogInput in) throws IOException {
    mFolderId = in.readInt();
    if (getVersion().atLeast(1, 0)) {
        in.readShort();
    }
    mCalendarItemId = in.readInt();
    if (getVersion().atLeast(1, 1)) {
        mCalendarItemPartStat = in.readUTF();
    }
    if (getVersion().atLeast(1, 2)) {
        mAttachmentIndexingEnabled = in.readBoolean();
    } else {
        mAttachmentIndexingEnabled = false;
    }
    if (getVersion().atLeast(1, 11)) {
        mFlags = in.readInt();
        if (getVersion().atLeast(1, 33)) {
            mTags = in.readUTFArray();
        } else {
            mTagBitmask = in.readLong();
        }
    }
    Invite tzmapInv = null;
    boolean hasDefaultInvite = true;
    if (getVersion().atLeast(1, 17)) {
        hasDefaultInvite = in.readBoolean();
    }
    try {
        if (hasDefaultInvite) {
            mDefaultInvite = deserializeSetCalendarItemData(in, mAttachmentIndexingEnabled);
            tzmapInv = mDefaultInvite.invite;
        }
        int numExceptions = in.readInt();
        if (numExceptions > 0) {
            mExceptions = new Mailbox.SetCalendarItemData[numExceptions];
            for (int i = 0; i < numExceptions; i++) {
                mExceptions[i] = deserializeSetCalendarItemData(in, mAttachmentIndexingEnabled);
                if (tzmapInv == null) {
                    tzmapInv = mExceptions[i].invite;
                }
            }
        }
    } catch (MessagingException ex) {
        ex.printStackTrace();
        throw new IOException("Cannot read serialized entry for SetCalendarItem" + ex.toString());
    }
    if (getVersion().atLeast(1, 15)) {
        int num = in.readInt();
        if (num > 10000 && !getVersion().atLeast(1, 24)) {
            // exception.
            throw new IOException("Replies count > 10000.  Looks like a corrupted pre-v1.24 redo entry.  Skipping");
        }
        if (num < 0) {
            // no replies list
            mReplies = null;
        } else {
            mReplies = new ArrayList<ReplyInfo>(num);
            TimeZoneMap tzMap = tzmapInv.getTimeZoneMap();
            for (int i = 0; i < num; i++) {
                String data = in.readUTF();
                try {
                    Metadata md = new Metadata(data);
                    ReplyInfo reply = ReplyInfo.decodeFromMetadata(md, tzMap);
                    mReplies.add(reply);
                } catch (ServiceException e) {
                    IOException ioe = new IOException("Cannot read serialized entry for ReplyInfo");
                    ioe.initCause(e);
                    throw ioe;
                }
            }
        }
    }
    if (getVersion().atLeast(1, 21)) {
        mNextAlarm = in.readLong();
    }
}
Also used : Mailbox(com.zimbra.cs.mailbox.Mailbox) ServiceException(com.zimbra.common.service.ServiceException) MessagingException(javax.mail.MessagingException) TimeZoneMap(com.zimbra.common.calendar.TimeZoneMap) Metadata(com.zimbra.cs.mailbox.Metadata) IOException(java.io.IOException) ReplyInfo(com.zimbra.cs.mailbox.CalendarItem.ReplyInfo) Invite(com.zimbra.cs.mailbox.calendar.Invite)

Example 3 with ReplyInfo

use of com.zimbra.cs.mailbox.CalendarItem.ReplyInfo in project zm-mailbox by Zimbra.

the class CalendarUtils method parseReplyList.

public static List<ReplyInfo> parseReplyList(Element element, TimeZoneMap tzMap) throws ServiceException {
    List<ReplyInfo> list = new ArrayList<ReplyInfo>();
    for (Iterator<Element> iter = element.elementIterator(MailConstants.E_CAL_REPLY); iter.hasNext(); ) {
        Element riElem = iter.next();
        String addr = riElem.getAttribute(MailConstants.A_CAL_ATTENDEE);
        ZAttendee at = new ZAttendee(addr);
        String sentBy = riElem.getAttribute(MailConstants.A_CAL_SENTBY, null);
        if (sentBy != null)
            at.setSentBy(sentBy);
        String partStat = riElem.getAttribute(MailConstants.A_CAL_PARTSTAT, null);
        if (partStat != null)
            at.setPartStat(partStat);
        int seq = (int) riElem.getAttributeLong(MailConstants.A_SEQ);
        long dtStamp = riElem.getAttributeLong(MailConstants.A_DATE);
        RecurId recurId = RecurId.fromXml(riElem, tzMap);
        ReplyInfo ri = new ReplyInfo(at, seq, dtStamp, recurId);
        list.add(ri);
    }
    return list;
}
Also used : Element(com.zimbra.common.soap.Element) ZAttendee(com.zimbra.cs.mailbox.calendar.ZAttendee) ArrayList(java.util.ArrayList) RecurId(com.zimbra.cs.mailbox.calendar.RecurId) ReplyInfo(com.zimbra.cs.mailbox.CalendarItem.ReplyInfo)

Example 4 with ReplyInfo

use of com.zimbra.cs.mailbox.CalendarItem.ReplyInfo in project zm-mailbox by Zimbra.

the class CalendarCollection method createItemFromInvites.

/**
 * @param name Preferred DAV basename for the new item - including ".ics" if appropriate.
 * @param allowUpdate - PUTs are allowed to update a pre-existing item.  POSTs to the containing collection are not.
 */
public DavResource createItemFromInvites(DavContext ctxt, Account account, String name, List<Invite> invites, boolean allowUpdate) throws DavException, IOException {
    boolean useEtag = allowUpdate;
    try {
        String user = account.getName();
        /*
             * Some of the CalDAV clients do not behave very well when it comes to etags.
             *     chandler doesn't set User-Agent header, doesn't understand If-None-Match or If-Match headers.
             *     evolution 2.8 always sets If-None-Match although we return etag in REPORT.
             *     ical correctly understands etag and sets If-Match for existing etags, but does not use If-None-Match
             *     for new resource creation.
             */
        HttpServletRequest req = ctxt.getRequest();
        String etag = null;
        if (useEtag) {
            etag = req.getHeader(DavProtocol.HEADER_IF_MATCH);
            useEtag = (etag != null);
        }
        String baseName = HttpUtil.urlUnescape(name);
        boolean acceptableClientChosenBasename = DebugConfig.enableDAVclientCanChooseResourceBaseName && baseName.equals(name);
        if (name.endsWith(CalendarObject.CAL_EXTENSION)) {
            name = name.substring(0, name.length() - CalendarObject.CAL_EXTENSION.length());
            // Unescape the name (It was encoded in DavContext intentionally)
            name = HttpUtil.urlUnescape(name);
        }
        String uid = findEventUid(invites);
        Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account);
        CalendarItem origCalItem = null;
        // Is the basename of the path client assigned rather than following the standard pattern?
        Integer itemId = null;
        if (acceptableClientChosenBasename) {
            itemId = DavNames.get(this.mMailboxId, this.mId, baseName);
        }
        if (itemId != null) {
            try {
                MailItem mailItem = mbox.getItemById(ctxt.getOperationContext(), itemId, MailItem.Type.UNKNOWN);
                if (mailItem != null && mailItem instanceof CalendarItem) {
                    origCalItem = (CalendarItem) mailItem;
                }
            } catch (ServiceException se) {
            }
        }
        if (origCalItem == null) {
            if (uid.equals(name)) {
                origCalItem = mbox.getCalendarItemByUid(ctxt.getOperationContext(), name);
            } else {
                /* the basename of the path doesn't fit our preferred naming convention. */
                origCalItem = mbox.getCalendarItemByUid(ctxt.getOperationContext(), uid);
                String redirectUrl = null;
                if (origCalItem != null) {
                    if (this.mId != origCalItem.getFolderId()) {
                        // In another folder, ignore
                        origCalItem = null;
                    } else {
                        // The item exists, but doesn't have this name - UID conflict.
                        if (acceptableClientChosenBasename) {
                            redirectUrl = hrefForCalendarItem(origCalItem, user, uid);
                        } else {
                            redirectUrl = defaultUrlForCalendarItem(user, uid);
                        }
                        throw new DavException.UidConflict("An item with the same UID already exists in the calendar", redirectUrl);
                    }
                }
                if ((origCalItem == null) && (!DebugConfig.enableDAVclientCanChooseResourceBaseName)) {
                    redirectUrl = defaultUrlForCalendarItem(user, uid);
                }
                if (allowUpdate && (redirectUrl != null)) {
                    /* SC_FOUND - Status code (302) indicating that the resource reside temporarily under a
                         * different URI. Since the redirection might be altered on occasion, the client should
                         * continue to use the Request-URI for future requests.(HTTP/1.1) To represent the status code
                         * (302), it is recommended to use this variable.  Used to be called SC_MOVED_TEMPORARILY
                         */
                    // sets status to SC_FOUND
                    ctxt.getResponse().sendRedirect(redirectUrl);
                    StringBuilder wrongUrlMsg = new StringBuilder();
                    wrongUrlMsg.append("wrong url - redirecting to:\n").append(redirectUrl);
                    throw new DavException(wrongUrlMsg.toString(), HttpServletResponse.SC_FOUND, null);
                }
            }
        }
        if (origCalItem == null && useEtag) {
            throw new DavException("event not found", HttpServletResponse.SC_NOT_FOUND, null);
        }
        if (origCalItem != null && !allowUpdate) {
            throw new DavException.UidConflict("An item with the same UID already exists in the calendar", hrefForCalendarItem(origCalItem, user, uid));
        }
        boolean isNewItem = true;
        if (useEtag) {
            String itemEtag = MailItemResource.getEtag(origCalItem);
            if (!itemEtag.equals(etag)) {
                throw new DavException(String.format("CalDAV client has stale event: event has different etag (%s) vs %s", itemEtag, etag), HttpServletResponse.SC_PRECONDITION_FAILED);
            }
            isNewItem = false;
        }
        // prepare to call Mailbox.setCalendarItem()
        int flags = 0;
        String[] tags = null;
        List<ReplyInfo> replies = null;
        Invite[] origInvites = null;
        if (origCalItem != null) {
            flags = origCalItem.getFlagBitmask();
            tags = origCalItem.getTags();
            replies = origCalItem.getAllReplies();
            origInvites = origCalItem.getInvites();
        }
        SetCalendarItemData scidDefault = new SetCalendarItemData();
        SetCalendarItemData[] scidExceptions = null;
        int idxExceptions = 0;
        boolean first = true;
        for (Invite i : invites) {
            // check for valid uid.
            if (i.getUid() == null)
                i.setUid(uid);
            adjustOrganizer(ctxt, i);
            // Carry over the MimeMessage/ParsedMessage to preserve any attachments.
            // CalDAV clients don't support attachments, and on edit we have to either
            // retain existing attachments or drop them.  Retaining is better.
            ParsedMessage oldPm = null;
            if (origCalItem != null) {
                Invite oldInv = origCalItem.getInvite(i.getRecurId());
                if (oldInv == null && i.hasRecurId()) {
                    // It's a new exception instance.  Inherit from series.
                    oldInv = origCalItem.getInvite((RecurId) null);
                }
                if (oldInv != null) {
                    MimeMessage mmInv = origCalItem.getSubpartMessage(oldInv.getMailItemId());
                    oldPm = mmInv != null ? new ParsedMessage(mmInv, false) : null;
                }
            }
            if (first) {
                scidDefault.invite = i;
                scidDefault.message = oldPm;
                first = false;
            } else {
                SetCalendarItemData scid = new SetCalendarItemData();
                scid.invite = i;
                scid.message = oldPm;
                if (scidExceptions == null) {
                    scidExceptions = new SetCalendarItemData[invites.size() - 1];
                }
                scidExceptions[idxExceptions++] = scid;
            }
            // For attendee case, update replies list with matching ATTENDEE from the invite.
            if (!i.isOrganizer() && replies != null) {
                ZAttendee at = i.getMatchingAttendee(account);
                if (at != null) {
                    AccountAddressMatcher acctMatcher = new AccountAddressMatcher(account);
                    ReplyInfo newReply = null;
                    for (Iterator<ReplyInfo> replyIter = replies.iterator(); replyIter.hasNext(); ) {
                        ReplyInfo reply = replyIter.next();
                        if (acctMatcher.matches(reply.getAttendee().getAddress())) {
                            RecurId ridR = reply.getRecurId(), ridI = i.getRecurId();
                            if ((ridR == null && ridI == null) || (ridR != null && ridR.equals(ridI))) {
                                // matching RECURRENCE-ID
                                // No need to compare SEQUENCE and DTSTAMP of existing reply and new invite.
                                // We're just going to take what the caldav client sent, even if it's older
                                // than the existing reply.
                                replyIter.remove();
                                if (!IcalXmlStrMap.PARTSTAT_NEEDS_ACTION.equalsIgnoreCase(at.getPartStat())) {
                                    newReply = new ReplyInfo(at, i.getSeqNo(), i.getDTStamp(), ridI);
                                }
                                break;
                            }
                        }
                    }
                    if (newReply != null) {
                        replies.add(newReply);
                    }
                }
            }
        }
        CalendarItem newCalItem = null;
        AutoScheduler autoScheduler = AutoScheduler.getAutoScheduler(mbox, this.getCalendarMailbox(ctxt), origInvites, mId, flags, tags, scidDefault, scidExceptions, replies, ctxt);
        if (autoScheduler == null) {
            newCalItem = mbox.setCalendarItem(ctxt.getOperationContext(), mId, flags, tags, scidDefault, scidExceptions, replies, CalendarItem.NEXT_ALARM_KEEP_CURRENT);
        } else {
            // Note: This also sets the calendar item
            newCalItem = autoScheduler.doSchedulingActions();
        }
        if (newCalItem == null) {
            throw new DavException("cannot create icalendar item - corrupt ICAL?", HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
        }
        if (!uid.equals(name)) {
            if (acceptableClientChosenBasename) {
                DavNames.put(DavNames.DavName.create(this.mMailboxId, newCalItem.getFolderId(), baseName), newCalItem.getId());
            }
        }
        return new CalendarObject.LocalCalendarObject(ctxt, newCalItem, isNewItem);
    } catch (BadOrganizerException.DiffOrganizerInComponentsException e) {
        throw new DavException.NeedSameOrganizerInAllComponents(e.getMessage());
    } catch (BadOrganizerException e) {
        // FORBIDDEN if we aren't going to be able to cope with the data
        throw new DavException(e.getMessage(), HttpServletResponse.SC_FORBIDDEN, e);
    } catch (ServiceException e) {
        if (e.getCode().equals(ServiceException.FORBIDDEN)) {
            throw new DavException(e.getMessage(), HttpServletResponse.SC_FORBIDDEN, e);
        } else {
            throw new DavException("cannot create icalendar item", HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e);
        }
    }
}
Also used : RecurId(com.zimbra.cs.mailbox.calendar.RecurId) ReplyInfo(com.zimbra.cs.mailbox.CalendarItem.ReplyInfo) SetCalendarItemData(com.zimbra.cs.mailbox.Mailbox.SetCalendarItemData) HttpServletRequest(javax.servlet.http.HttpServletRequest) CalendarItem(com.zimbra.cs.mailbox.CalendarItem) Mailbox(com.zimbra.cs.mailbox.Mailbox) MimeMessage(javax.mail.internet.MimeMessage) BadOrganizerException(com.zimbra.cs.mailbox.BadOrganizerException) AutoScheduler(com.zimbra.cs.dav.caldav.AutoScheduler) DavException(com.zimbra.cs.dav.DavException) ParsedMessage(com.zimbra.cs.mime.ParsedMessage) MailItem(com.zimbra.cs.mailbox.MailItem) ServiceException(com.zimbra.common.service.ServiceException) AccountAddressMatcher(com.zimbra.cs.util.AccountUtil.AccountAddressMatcher) ZAttendee(com.zimbra.cs.mailbox.calendar.ZAttendee) Invite(com.zimbra.cs.mailbox.calendar.Invite)

Example 5 with ReplyInfo

use of com.zimbra.cs.mailbox.CalendarItem.ReplyInfo in project zm-mailbox by Zimbra.

the class SetCalendarItem method serializeData.

@Override
protected void serializeData(RedoLogOutput out) throws IOException {
    assert (getMailboxId() != 0);
    out.writeInt(mFolderId);
    if (getVersion().atLeast(1, 0)) {
        out.writeShort((short) -1);
    }
    out.writeInt(mCalendarItemId);
    if (getVersion().atLeast(1, 1)) {
        out.writeUTF(mCalendarItemPartStat);
    }
    if (getVersion().atLeast(1, 2)) {
        out.writeBoolean(mAttachmentIndexingEnabled);
    }
    if (getVersion().atLeast(1, 11)) {
        out.writeInt(mFlags);
        if (getVersion().atLeast(1, 33)) {
            out.writeUTFArray(mTags);
        } else {
            out.writeLong(mTagBitmask);
        }
    }
    boolean hasDefaultInvite = mDefaultInvite != null;
    if (getVersion().atLeast(1, 17))
        out.writeBoolean(hasDefaultInvite);
    if (hasDefaultInvite) {
        serializeSetCalendarItemData(out, mDefaultInvite);
    }
    if (mExceptions == null) {
        out.writeInt(0);
    } else {
        out.writeInt(mExceptions.length);
        for (int i = 0; i < mExceptions.length; i++) {
            serializeSetCalendarItemData(out, mExceptions[i]);
        }
    }
    if (getVersion().atLeast(1, 15)) {
        if (mReplies == null) {
            // special case: -1 means there was no replies list.  This is distinct from there
            // being a non-null list with 0 replies.  No list means to leave current replies
            // alone; 0-length list means to clear current list.
            out.writeInt(-1);
        } else {
            int num = mReplies.size();
            out.writeInt(num);
            for (ReplyInfo ri : mReplies) {
                out.writeUTF(ri.encodeAsMetadata().toString());
            }
        }
    }
    if (getVersion().atLeast(1, 21)) {
        out.writeLong(mNextAlarm);
    }
}
Also used : ReplyInfo(com.zimbra.cs.mailbox.CalendarItem.ReplyInfo)

Aggregations

ReplyInfo (com.zimbra.cs.mailbox.CalendarItem.ReplyInfo)5 ServiceException (com.zimbra.common.service.ServiceException)2 Mailbox (com.zimbra.cs.mailbox.Mailbox)2 Invite (com.zimbra.cs.mailbox.calendar.Invite)2 RecurId (com.zimbra.cs.mailbox.calendar.RecurId)2 ZAttendee (com.zimbra.cs.mailbox.calendar.ZAttendee)2 TimeZoneMap (com.zimbra.common.calendar.TimeZoneMap)1 Element (com.zimbra.common.soap.Element)1 DavException (com.zimbra.cs.dav.DavException)1 AutoScheduler (com.zimbra.cs.dav.caldav.AutoScheduler)1 BadOrganizerException (com.zimbra.cs.mailbox.BadOrganizerException)1 CalendarItem (com.zimbra.cs.mailbox.CalendarItem)1 MailItem (com.zimbra.cs.mailbox.MailItem)1 SetCalendarItemData (com.zimbra.cs.mailbox.Mailbox.SetCalendarItemData)1 Metadata (com.zimbra.cs.mailbox.Metadata)1 ParsedMessage (com.zimbra.cs.mime.ParsedMessage)1 AccountAddressMatcher (com.zimbra.cs.util.AccountUtil.AccountAddressMatcher)1 IOException (java.io.IOException)1 ArrayList (java.util.ArrayList)1 MessagingException (javax.mail.MessagingException)1