Search in sources :

Example 26 with Invite

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

the class CalendarItem method requirePrivateCheck.

// If we're adding a private invite, we must make sure the authenticated user has permission to
// access private data.  If we're adding a public invite but the appointment currently has
// some private data, private access permission is not needed as long as the instance(s) being
// updated aren't currently private.
private boolean requirePrivateCheck(Invite newInvite) {
    if (!newInvite.isPublic()) {
        // adding a private invite
        return true;
    }
    if (!isPublic()) {
        RecurId rid = newInvite.getRecurId();
        // If canceling whole series, requester must have private access permission.
        if (rid == null && newInvite.isCancel())
            return true;
        Invite current = getInvite(rid);
        // If no matching recurrence-id was found, look at the current series.
        if (current == null && rid != null)
            current = getInvite((RecurId) null);
        if (current != null && !current.isPublic()) {
            // updating a currently private invite to public
            return true;
        } else {
            // no matching rid found, or current is public
            return false;
        }
    } else {
        // Both old and new are public.
        return false;
    }
}
Also used : RecurId(com.zimbra.cs.mailbox.calendar.RecurId) Invite(com.zimbra.cs.mailbox.calendar.Invite)

Example 27 with Invite

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

the class CalendarItem method createPseudoExceptionForSingleInstanceReplyIfNecessary.

/**
     * Bug 94018 - Need an exception to represent a reply to a single instance of an exception, otherwise a decline
     * to a single instance gets forgotten in some cases where the series partstat is used instead.
     * Assumption - already checked that there isn't a matching exception instance already
     * Caller is responsible for ensuring changed MetaData is written through to SQL sending notification of change.
     */
private void createPseudoExceptionForSingleInstanceReplyIfNecessary(Invite reply) throws ServiceException {
    if ((reply == null) || reply.getRecurId() == null) {
        // reply isn't to a single instance
        return;
    }
    Recurrence.RecurrenceRule recurrenceRule = null;
    if ((mRecurrence == null) || !(mRecurrence instanceof Recurrence.RecurrenceRule)) {
        return;
    }
    recurrenceRule = (Recurrence.RecurrenceRule) mRecurrence;
    Collection<Instance> instancesNear = instancesNear(reply.getRecurId());
    if (!instancesNear.isEmpty()) {
        /* we need a new exception to handle the difference in attendee status */
        for (int i = 0; i < numInvites(); i++) {
            Invite cur = getInvite(i);
            if (cur.getRecurId() == null) {
                try {
                    ParsedDateTime pdt = ParsedDateTime.parseUtcOnly(reply.getRecurId().getDtZ());
                    Invite localException = cur.makeInstanceInvite(pdt);
                    localException.setDtStamp(System.currentTimeMillis());
                    localException.updateMatchingAttendeesFromReply(reply);
                    // flag as organizer change
                    localException.setClassPropSetByMe(true);
                    mInvites.add(localException);
                    // create a fake ExceptionRule wrapper around the single-instance
                    recurrenceRule.addException(new Recurrence.ExceptionRule(reply.getRecurId(), localException.getStartTime(), localException.getEffectiveDuration(), new InviteInfo(localException)));
                } catch (ParseException e) {
                    sLog.debug("Unexpected exception - not updating calendar invite with pseudo exception", e);
                }
                break;
            }
        }
    }
}
Also used : IRecurrence(com.zimbra.cs.mailbox.calendar.Recurrence.IRecurrence) Recurrence(com.zimbra.cs.mailbox.calendar.Recurrence) InviteInfo(com.zimbra.cs.mailbox.calendar.InviteInfo) RecurrenceRule(com.zimbra.cs.mailbox.calendar.Recurrence.RecurrenceRule) ParsedDateTime(com.zimbra.common.calendar.ParsedDateTime) ParseException(java.text.ParseException) Invite(com.zimbra.cs.mailbox.calendar.Invite)

Example 28 with Invite

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

the class Appointment method makeReplyInvite.

private Invite makeReplyInvite(Account account, Account authAccount, Locale lc, boolean onBehalfOf, boolean allowPrivateAccess, Invite inv, RecurId rid, Verb verb) throws ServiceException {
    boolean hidePrivate = !inv.isPublic() && !allowPrivateAccess;
    String subject;
    if (hidePrivate)
        subject = L10nUtil.getMessage(MsgKey.calendarSubjectWithheld, lc);
    else
        subject = inv.getName();
    String replySubject = CalendarMailSender.getReplySubject(verb, subject, lc);
    ParsedDateTime ridDt = rid != null ? rid.getDt() : null;
    Invite replyInv = CalendarMailSender.replyToInvite(account, authAccount, onBehalfOf, allowPrivateAccess, inv, verb, replySubject, ridDt);
    return replyInv;
}
Also used : ParsedDateTime(com.zimbra.common.calendar.ParsedDateTime) Invite(com.zimbra.cs.mailbox.calendar.Invite)

Example 29 with Invite

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

the class CalendarItem method organizerChangeCheck.

/**
     * Check to make sure the new invite doesn't change the organizer in a disallowed way.
     * @param newInvite
     * @return true if organizer change was detected, false if no change
     * @throws ServiceException
     */
private boolean organizerChangeCheck(Invite newInvite, boolean denyChange) throws ServiceException {
    Invite originalInvite = null;
    if (!newInvite.hasRecurId()) {
        // New invite is not for an exception.
        originalInvite = getDefaultInviteOrNull();
    } else {
        // New invite is for an exception.
        boolean found = false;
        RecurId newRid = newInvite.getRecurId();
        for (Invite inv : mInvites) {
            if (inv.hasRecurId() && newRid.equals(inv.getRecurId())) {
                originalInvite = inv;
                found = true;
                break;
            }
        }
        if (!found) {
            // If no invite with matching RECURRENCE-ID was found, use the default invite.
            originalInvite = getDefaultInviteOrNull();
        }
    }
    if (originalInvite == null) {
        // If no "default" invite was found, use the first one.
        if (mInvites.size() > 0)
            originalInvite = mInvites.get(0);
        if (originalInvite == null) {
            // checks in this method.
            return false;
        }
    }
    boolean updatingSameComponent = true;
    if (newInvite.hasRecurId()) {
        if (originalInvite.hasRecurId()) {
            updatingSameComponent = newInvite.getRecurId().equals(originalInvite.getRecurId());
        } else {
            updatingSameComponent = false;
        }
    }
    boolean changed = false;
    ZOrganizer originalOrganizer = originalInvite.getOrganizer();
    if (!originalInvite.isOrganizer()) {
        // This account WAS NOT the organizer.  Prevent organizer change.
        if (newInvite.hasOrganizer()) {
            String newOrgAddr = newInvite.getOrganizer().getAddress();
            if (originalOrganizer == null) {
                if (denyChange) {
                    newInvite.isTodo();
                    if (updatingSameComponent) {
                        throw BadOrganizerException.ADD_ORGANIZER_NOT_ALLOWED(newOrgAddr, calDesc(newInvite));
                    } else {
                        throw BadOrganizerException.ORGANIZER_INTRODUCED_FOR_EXCEPTION(newOrgAddr, calDesc(newInvite));
                    }
                } else {
                    changed = true;
                }
            } else {
                // Both old and new organizers are set.  They must be the same address.
                String origOrgAddr = originalOrganizer.getAddress();
                if (newOrgAddr == null || !CalendarUtils.belongToSameAccount(origOrgAddr, newOrgAddr)) {
                    if (denyChange) {
                        if (updatingSameComponent) {
                            throw BadOrganizerException.CHANGE_ORGANIZER_NOT_ALLOWED(origOrgAddr, newOrgAddr, calDesc(newInvite));
                        } else {
                            throw BadOrganizerException.DIFF_ORGANIZER_IN_COMPONENTS(origOrgAddr, newOrgAddr, calDesc(newInvite));
                        }
                    } else {
                        changed = true;
                    }
                }
            }
        } else if (originalOrganizer != null) {
            // No organizer for new newInvite but there is one in the original
            String origOrgAddr = originalOrganizer.getAddress();
            if (denyChange) {
                if (updatingSameComponent) {
                    throw BadOrganizerException.DEL_ORGANIZER_NOT_ALLOWED(origOrgAddr, calDesc(newInvite));
                } else {
                    throw BadOrganizerException.MISSING_ORGANIZER_IN_SINGLE_INSTANCE(origOrgAddr, calDesc(newInvite));
                }
            } else {
                changed = true;
            }
        }
    } else {
        // Still don't allow changing the organizer field to an arbitrary address.
        if (newInvite.hasOrganizer()) {
            if (!newInvite.isOrganizer()) {
                String newOrgAddr = newInvite.getOrganizer().getAddress();
                String origOrgAddr = (originalOrganizer != null) ? originalOrganizer.getAddress() : null;
                if (newOrgAddr.equalsIgnoreCase(origOrgAddr)) {
                    /* Speculative fix for Bug 83261.  Had gotten to this point with the same address but
                         * thought that wasn't the organizer for the new invite even though that organizer
                         * passed the test for originalInvite.  Ideally, should track down why the value was wrong
                         * but don't have a full repro scenario.
                         */
                    newInvite.setIsOrganizer(true);
                }
                if (!newInvite.isOrganizer()) {
                    if (denyChange) {
                        if (originalOrganizer != null) {
                            if (updatingSameComponent) {
                                throw BadOrganizerException.CHANGE_ORGANIZER_NOT_ALLOWED(origOrgAddr, newOrgAddr, calDesc(newInvite));
                            } else {
                                throw BadOrganizerException.DIFF_ORGANIZER_IN_COMPONENTS(origOrgAddr, newOrgAddr, calDesc(newInvite));
                            }
                        } else {
                            if (updatingSameComponent) {
                                throw BadOrganizerException.ADD_ORGANIZER_NOT_ALLOWED(newOrgAddr, calDesc(newInvite));
                            } else {
                                throw BadOrganizerException.ORGANIZER_INTRODUCED_FOR_EXCEPTION(newOrgAddr, calDesc(newInvite));
                            }
                        }
                    } else {
                        changed = true;
                    }
                }
            }
        }
    }
    if (changed) {
        String origOrg = originalOrganizer != null ? originalOrganizer.getAddress() : null;
        ZOrganizer newOrganizer = newInvite.getOrganizer();
        String newOrg = newOrganizer != null ? newOrganizer.getAddress() : null;
        boolean wasOrganizer = originalInvite.isOrganizer();
        boolean isOrganizer = newInvite.isOrganizer();
        ZimbraLog.calendar.info("Changed organizer: old=" + origOrg + ", new=" + newOrg + ", wasOrg=" + wasOrganizer + ", isOrg=" + isOrganizer + ", UID=\"" + newInvite.getUid() + "\", invId=" + newInvite.getMailItemId());
    }
    return changed;
}
Also used : ZOrganizer(com.zimbra.cs.mailbox.calendar.ZOrganizer) RecurId(com.zimbra.cs.mailbox.calendar.RecurId) Invite(com.zimbra.cs.mailbox.calendar.Invite)

Example 30 with Invite

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

the class CalendarItem method create.

static CalendarItem create(int id, Folder folder, int flags, Tag.NormalizedTags ntags, String uid, ParsedMessage pm, Invite firstInvite, long nextAlarm, CustomMetadata custom) throws ServiceException {
    firstInvite.sanitize(false);
    if (!folder.canAccess(ACL.RIGHT_INSERT)) {
        throw ServiceException.PERM_DENIED("you do not have the required rights on the folder");
    }
    if (!firstInvite.isPublic() && !folder.canAccess(ACL.RIGHT_PRIVATE)) {
        throw ServiceException.PERM_DENIED("you do not have permission to create private calendar item in this folder");
    }
    Mailbox mbox = folder.getMailbox();
    if (pm != null && pm.hasAttachments()) {
        firstInvite.setHasAttachment(true);
        flags |= Flag.BITMASK_ATTACHED;
    } else {
        firstInvite.setHasAttachment(false);
        flags &= ~Flag.BITMASK_ATTACHED;
    }
    if (firstInvite.isDraft()) {
        flags |= Flag.BITMASK_DRAFT;
    } else {
        flags &= ~Flag.BITMASK_DRAFT;
    }
    if (firstInvite.isHighPriority()) {
        flags |= Flag.BITMASK_HIGH_PRIORITY;
    } else {
        flags &= ~Flag.BITMASK_HIGH_PRIORITY;
    }
    if (firstInvite.isLowPriority()) {
        flags |= Flag.BITMASK_LOW_PRIORITY;
    } else {
        flags &= ~Flag.BITMASK_LOW_PRIORITY;
    }
    MailItem.Type type = firstInvite.isEvent() ? Type.APPOINTMENT : Type.TASK;
    String sender = null;
    ZOrganizer org = firstInvite.getOrganizer();
    if (org != null) {
        sender = org.getIndexString();
    }
    sender = Strings.nullToEmpty(sender);
    String subject = Strings.nullToEmpty(firstInvite.getName());
    List<Invite> invites = new ArrayList<Invite>();
    invites.add(firstInvite);
    Recurrence.IRecurrence recur = firstInvite.getRecurrence();
    long startTime, endTime;
    if (recur != null) {
        ParsedDateTime dtStart = recur.getStartTime();
        startTime = dtStart != null ? dtStart.getUtcTime() : 0;
        ParsedDateTime dtEnd = recur.getEndTime();
        endTime = dtEnd != null ? dtEnd.getUtcTime() : 0;
    } else {
        ParsedDateTime dtStart = firstInvite.getStartTime();
        startTime = dtStart != null ? dtStart.getUtcTime() : 0;
        ParsedDateTime dtEnd = firstInvite.getEffectiveEndTime();
        endTime = dtEnd != null ? dtEnd.getUtcTime() : startTime;
    }
    Account account = mbox.getAccount();
    firstInvite.updateMyPartStat(account, firstInvite.getPartStat());
    UnderlyingData data = new UnderlyingData();
    data.id = id;
    data.type = type.toByte();
    data.folderId = folder.getId();
    if (!folder.inSpam() || mbox.getAccount().getBooleanAttr(Provisioning.A_zimbraJunkMessagesIndexingEnabled, false)) {
        data.indexId = IndexStatus.DEFERRED.id();
    }
    data.imapId = id;
    data.date = mbox.getOperationTimestamp();
    data.setFlags(flags & (Flag.FLAGS_CALITEM | Flag.FLAGS_GENERIC));
    data.setTags(ntags);
    data.setSubject(subject);
    data.metadata = encodeMetadata(DEFAULT_COLOR_RGB, 1, 1, custom, uid, startTime, endTime, recur, invites, firstInvite.getTimeZoneMap(), new ReplyList(), null);
    data.contentChanged(mbox, false);
    if (!firstInvite.hasRecurId()) {
        ZimbraLog.calendar.info("Adding CalendarItem: id=%d, Message-ID=\"%s\", folderId=%d, subject=\"%s\", UID=%s", data.id, pm != null ? pm.getMessageID() : "(none)", folder.getId(), firstInvite.isPublic() ? firstInvite.getName() : "(private)", firstInvite.getUid());
    } else {
        ZimbraLog.calendar.info("Adding CalendarItem: id=%d, Message-ID=\"%s\", folderId=%d, subject=\"%s\", UID=%s, recurId=%s", data.id, pm != null ? pm.getMessageID() : "(none)", folder.getId(), firstInvite.isPublic() ? firstInvite.getName() : "(private)", firstInvite.getUid(), firstInvite.getRecurId().getDtZ());
    }
    new DbMailItem(mbox).setSender(sender).create(data);
    CalendarItem item = type == Type.APPOINTMENT ? new Appointment(mbox, data) : new Task(mbox, data);
    Invite defInvite = item.getDefaultInviteOrNull();
    if (defInvite != null) {
        Collection<Instance> instances = item.expandInstances(CalendarUtils.MICROSOFT_EPOC_START_MS_SINCE_EPOC, Long.MAX_VALUE, false);
        if (instances.isEmpty()) {
            ZimbraLog.calendar.info("CalendarItem has effectively zero instances: id=%d, folderId=%d, subject=\"%s\", UID=%s ", data.id, folder.getId(), firstInvite.isPublic() ? firstInvite.getName() : "(private)", firstInvite.getUid());
            item.delete();
            throw ServiceException.FORBIDDEN("Recurring series has effectively zero instances");
        }
    }
    // If we're creating an invite during email delivery, always default to NEEDS_ACTION state.
    // If not email delivery, we assume the requesting client knows what it's doing and has set the
    // correct partstat in the invite.
    String defaultPartStat;
    if (mbox.getOperationContext() == null) {
        // octxt == null implies we're in email delivery.  (There needs to be better way to determine this...)
        defaultPartStat = IcalXmlStrMap.PARTSTAT_NEEDS_ACTION;
    } else {
        defaultPartStat = firstInvite.getPartStat();
    }
    item.processPartStat(firstInvite, pm != null ? pm.getMimeMessage() : null, true, defaultPartStat);
    item.finishCreation(null);
    folder.updateHighestMODSEQ();
    if (pm != null) {
        item.createBlob(pm, firstInvite);
    }
    item.mEndTime = item.recomputeRecurrenceEndTime(item.mEndTime);
    if (firstInvite.hasAlarm()) {
        item.recomputeNextAlarm(nextAlarm, false, false);
        item.saveMetadata();
        AlarmData alarmData = item.getAlarmData();
        if (alarmData != null) {
            long newNextAlarm = alarmData.getNextAtBase();
            if (newNextAlarm > 0 && newNextAlarm < item.mStartTime) {
                item.mStartTime = newNextAlarm;
            }
        }
    }
    DbMailItem.addToCalendarItemTable(item);
    Callback cb = getCallback();
    if (cb != null) {
        cb.created(item);
    }
    return item;
}
Also used : IRecurrence(com.zimbra.cs.mailbox.calendar.Recurrence.IRecurrence) Recurrence(com.zimbra.cs.mailbox.calendar.Recurrence) Account(com.zimbra.cs.account.Account) IRecurrence(com.zimbra.cs.mailbox.calendar.Recurrence.IRecurrence) DbMailItem(com.zimbra.cs.db.DbMailItem) ZOrganizer(com.zimbra.cs.mailbox.calendar.ZOrganizer) ArrayList(java.util.ArrayList) DbMailItem(com.zimbra.cs.db.DbMailItem) ParsedDateTime(com.zimbra.common.calendar.ParsedDateTime) 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