Search in sources :

Example 31 with Invite

use of com.zimbra.cs.mailbox.calendar.Invite in project zm-mailbox by Zimbra.

the class CalendarItem method updateLocalExceptionsWhichMatchSeriesReply.

/**
     * Exceptions can be created which aren't communicated to ATTENDEEs, either because the ORGANIZER wants to
     * have local changes like a different alarm time or because a response is received which only affects one
     * instance of a series.
     * Caller is responsible for ensuring changed MetaData is written through to SQL sending notification of change.
     */
private void updateLocalExceptionsWhichMatchSeriesReply(Invite reply) throws ServiceException {
    if ((reply == null) || reply.getRecurId() != null) {
        // Only interested in series replies
        return;
    }
    IRecurrence replyRecurrence = reply.getRecurrence();
    if (replyRecurrence == null) {
        sLog.debug("Giving up on trying to match series reply to local exceptions - no recurrence in reply");
        return;
    }
    for (int i = 0; i < numInvites(); i++) {
        Invite cur = getInvite(i);
        if (!cur.classPropSetByMe() || (cur.getRecurId() == null)) {
            continue;
        }
        ParsedDateTime recurIdDT = cur.getRecurId().getDt();
        ParsedDateTime startDT = cur.getStartTime();
        // If the start time has moved then the series response can't be applicable.
        if ((recurIdDT == null) || (startDT == null) || !recurIdDT.sameTime(startDT)) {
            continue;
        }
        long utcTime = recurIdDT.getUtcTime();
        // Find instances within 2 seconds either side of start - assuming it will be a direct hit if found
        List<Instance> instances = Recurrence.expandInstances(replyRecurrence, getId(), utcTime - 2000L, utcTime + 2000L);
        if (instances == null || (instances.size() != 1)) {
            continue;
        }
        cur.updateMatchingAttendeesFromReply(reply);
    }
}
Also used : IRecurrence(com.zimbra.cs.mailbox.calendar.Recurrence.IRecurrence) ParsedDateTime(com.zimbra.common.calendar.ParsedDateTime) Invite(com.zimbra.cs.mailbox.calendar.Invite)

Example 32 with Invite

use of com.zimbra.cs.mailbox.calendar.Invite in project zm-mailbox by Zimbra.

the class CalendarItem method processNewInviteReply.

boolean processNewInviteReply(Invite reply, String sender) throws ServiceException {
    List<ZAttendee> attendees = reply.getAttendees();
    String senderAddress = null;
    if (sender != null && !sender.isEmpty()) {
        try {
            JavaMailInternetAddress address = new JavaMailInternetAddress(sender);
            senderAddress = address.getAddress();
        } catch (AddressException e) {
        // ignore invalid sender address.
        }
    }
    if (senderAddress != null && !attendees.isEmpty()) {
        AccountAddressMatcher acctMatcher = null;
        Account acct = Provisioning.getInstance().get(AccountBy.name, senderAddress);
        if (acct != null) {
            acctMatcher = new AccountAddressMatcher(acct);
        }
        Iterator<ZAttendee> iter = attendees.iterator();
        while (iter.hasNext()) {
            ZAttendee att = iter.next();
            // Remove the attendee if not same as the sender.
            if (!(att.addressMatches(senderAddress) || (acctMatcher != null && acctMatcher.matches(att.getAddress())))) {
                iter.remove();
            }
        }
    }
    // trace logging
    ZAttendee att1 = !attendees.isEmpty() ? attendees.get(0) : null;
    if (att1 != null) {
        String ptst = IcalXmlStrMap.sPartStatMap.toIcal(att1.getPartStat());
        if (!reply.hasRecurId())
            ZimbraLog.calendar.info("Processing CalendarItem reply: attendee=%s, partstat=%s, id=%d, folderId=%d, subject=\"%s\", UID=%s", att1.getAddress(), ptst, mId, getFolderId(), reply.isPublic() ? reply.getName() : "(private)", mUid);
        else
            ZimbraLog.calendar.info("Processing CalendarItem reply: attendee=%s, partstat=%s, id=%d, folderId=%d, subject=\"%s\", UID=%s, recurId=%s", att1.getAddress(), ptst, mId, getFolderId(), reply.isPublic() ? reply.getName() : "(private)", mUid, reply.getRecurId().getDtZ());
    }
    // Require private access permission only when we're replying to a private series/instance.
    boolean requirePrivateCheck = requirePrivateCheck(reply);
    OperationContext octxt = getMailbox().getOperationContext();
    Account authAccount = octxt != null ? octxt.getAuthenticatedUser() : null;
    boolean asAdmin = octxt != null ? octxt.isUsingAdminPrivileges() : false;
    if (!canAccess(ACL.RIGHT_ACTION, authAccount, asAdmin, requirePrivateCheck))
        throw ServiceException.PERM_DENIED("you do not have sufficient permissions to change this appointment/task's state");
    boolean dirty = false;
    // unique ID: UID+RECURRENCE_ID
    // See RFC2446: 2.1.5 Message Sequencing
    // UID already matches...next check if RecurId matches
    // if so, then seqNo is next
    // finally use DTStamp
    Invite matchingInvite = matchingInvite(reply.getRecurId());
    if (matchingInvite != null) {
        //             up to date with the organizer's event, provided there were no major changes.
        if ((matchingInvite.isOrganizer() && (matchingInvite.getLastFullSeqNo() > reply.getSeqNo())) || (!matchingInvite.isOrganizer() && (matchingInvite.getSeqNo() > reply.getSeqNo()))) {
            sLog.info("Invite-Reply %s is outdated (Calendar entry has higher SEQUENCE), ignoring!", reply);
            return false;
        }
    // maybeStoreNewReply does some further checks which might invalidate this reply
    // so, postpone updating attendee information until after that.
    }
    // they must be replying to a arbitrary instance)
    for (ZAttendee at : attendees) {
        if (mReplyList.maybeStoreNewReply(reply, at, this))
            dirty = true;
    }
    if (!dirty) {
        sLog.info("Invite-Reply %s is outdated ignoring!", reply);
        return false;
    }
    if (matchingInvite != null) {
        matchingInvite.updateMatchingAttendeesFromReply(reply);
        updateLocalExceptionsWhichMatchSeriesReply(reply);
    } else {
        createPseudoExceptionForSingleInstanceReplyIfNecessary(reply);
    }
    saveMetadata();
    return true;
}
Also used : Account(com.zimbra.cs.account.Account) AccountAddressMatcher(com.zimbra.cs.util.AccountUtil.AccountAddressMatcher) ZAttendee(com.zimbra.cs.mailbox.calendar.ZAttendee) AddressException(javax.mail.internet.AddressException) JavaMailInternetAddress(com.zimbra.common.mime.shim.JavaMailInternetAddress) Invite(com.zimbra.cs.mailbox.calendar.Invite)

Example 33 with Invite

use of com.zimbra.cs.mailbox.calendar.Invite in project zm-mailbox by Zimbra.

the class CalendarItem method move.

@Override
boolean move(Folder target) throws ServiceException {
    Invite defInv = getDefaultInviteOrNull();
    String sbj;
    if (defInv != null)
        sbj = defInv.isPublic() ? defInv.getName() : "(private)";
    else
        sbj = "(none)";
    ZimbraLog.calendar.info("Moving CalendarItem: id=%d, src=%s, dest=%s, subject=\"%s\", UID=%s", mId, getMailopContext(getFolder()), getMailopContext(target), sbj, mUid);
    if (!isPublic()) {
        if (!canAccess(ACL.RIGHT_PRIVATE))
            throw ServiceException.PERM_DENIED("you do not have permission to move private calendar item from the current folder");
        if (target.getId() != Mailbox.ID_FOLDER_TRASH && !target.canAccess(ACL.RIGHT_PRIVATE))
            throw ServiceException.PERM_DENIED("you do not have permission to move private calendar item to the target folder");
    }
    addRevision(true);
    return super.move(target);
}
Also used : Invite(com.zimbra.cs.mailbox.calendar.Invite)

Example 34 with Invite

use of com.zimbra.cs.mailbox.calendar.Invite in project zm-mailbox by Zimbra.

the class CalendarItem method getNextAlarmHelperForTasks.

/**
     * Find the next absolute trigger alarm.  This is primarily for tasks.  Tasks have a slightly different constraint
     * on alarms than appointments do.  In particular, the absolute trigger time of tasks need not be before DTSTART
     * or DUE, whereas alarms for appointments are meaningful only if it triggers before DTSTART.  A reminder for a
     * meeting that has already started is useless, but a reminder for an over-due task can be quite useful.
     *
     * @param atOrAfter
     * @param snoozeUntil
     * @param forEmailAction
     * @return
     */
private AlarmData getNextAlarmHelperForTasks(long atOrAfter, long snoozeUntil, boolean forEmailAction) {
    // Find the two nearest alarms that surround atOrAfter such that t(alarm1) <= atOrAfter < t(alarm2).
    Alarm alarm1 = null, alarm2 = null;
    // trigger times for alarm1 and alarm2
    long trigger1 = Long.MIN_VALUE, trigger2 = Long.MAX_VALUE;
    // instance start time for alarm1 and alarm2
    long instStart1 = 0, instStart2 = 0;
    // invId and compNum for inst1 and inst2
    int invId1 = 0, compNum1 = 0, invId2 = 0, compNum2 = 0;
    for (Invite inv : mInvites) {
        if (inv.isCancel())
            continue;
        // The invite can have multiple alarms.
        for (Iterator<Alarm> alarms = inv.alarmsIterator(); alarms.hasNext(); ) {
            Alarm alarm = alarms.next();
            if (Action.EMAIL.equals(alarm.getAction()) == forEmailAction && alarm.getTriggerAbsolute() != null) {
                long trg = alarm.getTriggerAbsolute().getUtcTime();
                if (trg <= atOrAfter) {
                    if (trg > trigger1) {
                        trigger1 = trg;
                        alarm1 = alarm;
                        instStart1 = inv.getStartTime() != null ? inv.getStartTime().getUtcTime() : 0;
                        invId1 = inv.getMailItemId();
                        compNum1 = inv.getComponentNum();
                    }
                } else {
                    // trg > atOrAfter
                    if (trg < trigger2) {
                        trigger2 = trg;
                        alarm2 = alarm;
                        instStart2 = inv.getStartTime() != null ? inv.getStartTime().getUtcTime() : 0;
                        invId2 = inv.getMailItemId();
                        compNum2 = inv.getComponentNum();
                    }
                }
            }
        }
    }
    AlarmData ad1 = alarm1 != null ? new AlarmData(trigger1, snoozeUntil, instStart1, invId1, compNum1, alarm1) : null;
    AlarmData ad2 = alarm2 != null ? new AlarmData(trigger2, AlarmData.NO_SNOOZE, instStart2, invId2, compNum2, alarm2) : null;
    return chooseNextAlarm(atOrAfter, snoozeUntil, ad1, ad2);
}
Also used : Alarm(com.zimbra.cs.mailbox.calendar.Alarm) Invite(com.zimbra.cs.mailbox.calendar.Invite)

Example 35 with Invite

use of com.zimbra.cs.mailbox.calendar.Invite in project zm-mailbox by Zimbra.

the class CalendarItem method getSender.

@Override
public String getSender() {
    String sender = null;
    Invite firstInvite = getDefaultInviteOrNull();
    if (firstInvite != null) {
        ZOrganizer org = firstInvite.getOrganizer();
        if (org != null)
            sender = org.getIndexString();
    }
    return Strings.nullToEmpty(sender);
}
Also used : ZOrganizer(com.zimbra.cs.mailbox.calendar.ZOrganizer) Invite(com.zimbra.cs.mailbox.calendar.Invite)

Aggregations

Invite (com.zimbra.cs.mailbox.calendar.Invite)103 Account (com.zimbra.cs.account.Account)30 Element (com.zimbra.common.soap.Element)26 ServiceException (com.zimbra.common.service.ServiceException)23 CalendarItem (com.zimbra.cs.mailbox.CalendarItem)23 Mailbox (com.zimbra.cs.mailbox.Mailbox)23 MimeMessage (javax.mail.internet.MimeMessage)23 ZVCalendar (com.zimbra.common.calendar.ZCalendar.ZVCalendar)22 ParsedDateTime (com.zimbra.common.calendar.ParsedDateTime)20 ItemId (com.zimbra.cs.service.util.ItemId)20 ArrayList (java.util.ArrayList)19 IOException (java.io.IOException)18 ZOrganizer (com.zimbra.cs.mailbox.calendar.ZOrganizer)16 TimeZoneMap (com.zimbra.common.calendar.TimeZoneMap)15 ZAttendee (com.zimbra.cs.mailbox.calendar.ZAttendee)15 OperationContext (com.zimbra.cs.mailbox.OperationContext)14 RecurId (com.zimbra.cs.mailbox.calendar.RecurId)14 MessagingException (javax.mail.MessagingException)12 MailServiceException (com.zimbra.cs.mailbox.MailServiceException)11 ParsedMessage (com.zimbra.cs.mime.ParsedMessage)11