Search in sources :

Example 1 with CreateCalendarItemRecorder

use of com.zimbra.cs.redolog.op.CreateCalendarItemRecorder in project zm-mailbox by Zimbra.

the class Task method processPartStat.

@Override
protected String processPartStat(Invite invite, MimeMessage mmInv, boolean forCreate, String defaultPartStat) throws ServiceException {
    Mailbox mbox = getMailbox();
    OperationContext octxt = mbox.getOperationContext();
    CreateCalendarItemPlayer player = octxt != null ? (CreateCalendarItemPlayer) octxt.getPlayer() : null;
    String partStat = defaultPartStat;
    if (player != null) {
        String p = player.getCalendarItemPartStat();
        if (p != null)
            partStat = p;
    }
    CreateCalendarItemRecorder recorder = (CreateCalendarItemRecorder) mbox.getRedoRecorder();
    recorder.setCalendarItemPartStat(partStat);
    Account account = getMailbox().getAccount();
    invite.updateMyPartStat(account, partStat);
    if (forCreate) {
        Invite defaultInvite = getDefaultInviteOrNull();
        if (defaultInvite != null && !defaultInvite.equals(invite) && !partStat.equals(defaultInvite.getPartStat())) {
            defaultInvite.updateMyPartStat(account, partStat);
            saveMetadata();
        }
    }
    return partStat;
}
Also used : Account(com.zimbra.cs.account.Account) CreateCalendarItemRecorder(com.zimbra.cs.redolog.op.CreateCalendarItemRecorder) Invite(com.zimbra.cs.mailbox.calendar.Invite) CreateCalendarItemPlayer(com.zimbra.cs.redolog.op.CreateCalendarItemPlayer)

Example 2 with CreateCalendarItemRecorder

use of com.zimbra.cs.redolog.op.CreateCalendarItemRecorder in project zm-mailbox by Zimbra.

the class Mailbox method createCalendarItem.

CalendarItem createCalendarItem(int folderId, int flags, Tag.NormalizedTags ntags, String uid, ParsedMessage pm, Invite invite, CustomMetadata custom) throws ServiceException {
    // FIXME: assuming that we're in the middle of a AddInvite op
    CreateCalendarItemPlayer redoPlayer = (CreateCalendarItemPlayer) currentChange().getRedoPlayer();
    CreateCalendarItemRecorder redoRecorder = (CreateCalendarItemRecorder) currentChange().getRedoRecorder();
    int newCalItemId = redoPlayer == null ? Mailbox.ID_AUTO_INCREMENT : redoPlayer.getCalendarItemId();
    int createId = getNextItemId(newCalItemId);
    CalendarItem calItem = CalendarItem.create(createId, getFolderById(folderId), flags, ntags, uid, pm, invite, CalendarItem.NEXT_ALARM_FROM_NOW, custom);
    if (redoRecorder != null) {
        redoRecorder.setCalendarItemAttrs(calItem.getId(), calItem.getFolderId());
    }
    return calItem;
}
Also used : SetCalendarItem(com.zimbra.cs.redolog.op.SetCalendarItem) CreateCalendarItemRecorder(com.zimbra.cs.redolog.op.CreateCalendarItemRecorder) RefreshMountpoint(com.zimbra.cs.redolog.op.RefreshMountpoint) TargetConstraint(com.zimbra.cs.mailbox.MailItem.TargetConstraint) CreateMountpoint(com.zimbra.cs.redolog.op.CreateMountpoint) CreateCalendarItemPlayer(com.zimbra.cs.redolog.op.CreateCalendarItemPlayer)

Example 3 with CreateCalendarItemRecorder

use of com.zimbra.cs.redolog.op.CreateCalendarItemRecorder in project zm-mailbox by Zimbra.

the class Appointment method processPartStat.

@Override
protected String processPartStat(Invite invite, MimeMessage mmInv, boolean forCreate, String defaultPartStat) throws ServiceException {
    Mailbox mbox = getMailbox();
    OperationContext octxt = mbox.getOperationContext();
    CreateCalendarItemPlayer player = octxt != null ? (CreateCalendarItemPlayer) octxt.getPlayer() : null;
    long opTime = octxt != null ? octxt.getTimestamp() : System.currentTimeMillis();
    Account account = getMailbox().getAccount();
    boolean onBehalfOf = false;
    Account authAcct = account;
    if (octxt != null) {
        Account authuser = octxt.getAuthenticatedUser();
        if (authuser != null) {
            onBehalfOf = !account.getId().equalsIgnoreCase(authuser.getId());
            if (onBehalfOf)
                authAcct = authuser;
        }
    }
    boolean asAdmin = octxt != null ? octxt.isUsingAdminPrivileges() : false;
    boolean allowPrivateAccess = allowPrivateAccess(authAcct, asAdmin);
    String partStat = defaultPartStat;
    if (player != null) {
        String p = player.getCalendarItemPartStat();
        if (p != null)
            partStat = p;
    }
    // See if we have RSVP=FALSE for the attendee.  Let's assume RSVP was requested unless it is
    // explicitly set to FALSE.
    boolean rsvpRequested = true;
    ZAttendee attendee = invite.getMatchingAttendee(account);
    if (attendee != null) {
        Boolean rsvp = attendee.getRsvp();
        if (rsvp != null)
            rsvpRequested = rsvp.booleanValue();
    }
    RedoLogProvider redoProvider = RedoLogProvider.getInstance();
    // Don't send reply emails if we're not on master (in redo-driven master/replica setup).
    // Don't send reply emails if we're replaying redo for reasons other than crash recovery.
    // In other words, we DO want to send emails during crash recovery, because we're completing
    // an interrupted transaction.  But we don't send emails during redo reply phase of restore.
    // Also don't send emails for cancel invites.  (Organizer doesn't expect reply for cancels.)
    // And don't send emails for task requests.
    // Don't send reply emails from a system account. (e.g. archiving, galsync, ham/spam)
    boolean needReplyEmail = rsvpRequested && redoProvider.isMaster() && (player == null || redoProvider.getRedoLogManager().getInCrashRecovery()) && invite.hasOrganizer() && !invite.isCancel() && !invite.isTodo() && !account.isIsSystemResource();
    if (invite.isOrganizer()) {
        // Organizer always accepts.
        partStat = IcalXmlStrMap.PARTSTAT_ACCEPTED;
    } else if (account instanceof CalendarResource && octxt == null) {
        // Auto accept/decline processing should only occur during email delivery.  In particular,
        // don't do it if we're here during ics import.  We're in email delivery if octxt == null.
        // (There needs to be a better way to determine that...)
        boolean replySent = false;
        CalendarResource resource = (CalendarResource) account;
        Locale lc;
        Account organizer = invite.getOrganizerAccount();
        if (organizer != null)
            lc = organizer.getLocale();
        else
            lc = resource.getLocale();
        if (resource.autoAcceptDecline() || resource.autoDeclineIfBusy() || resource.autoDeclineRecurring()) {
            boolean replyListUpdated = false;
            // If auto-accept is enabled, assume it'll be accepted until it gets declined.
            if (resource.autoAcceptDecline())
                partStat = IcalXmlStrMap.PARTSTAT_ACCEPTED;
            if (isRecurring() && resource.autoDeclineRecurring()) {
                // Decline because resource is configured to decline all recurring appointments.
                partStat = IcalXmlStrMap.PARTSTAT_DECLINED;
                if (needReplyEmail) {
                    String reason = L10nUtil.getMessage(MsgKey.calendarResourceDeclineReasonRecurring, lc);
                    Invite replyInv = makeReplyInvite(account, authAcct, lc, onBehalfOf, allowPrivateAccess, invite, invite.getRecurId(), CalendarMailSender.VERB_DECLINE);
                    CalendarMailSender.sendResourceAutoReply(octxt, mbox, true, CalendarMailSender.VERB_DECLINE, false, reason + "\r\n", this, invite, new Invite[] { replyInv }, mmInv);
                    replySent = true;
                }
            } else if (resource.autoDeclineIfBusy()) {
                // Auto decline is enabled.  Let's check for conflicts.
                int maxNumConflicts = resource.getMaxNumConflictsAllowed();
                int maxPctConflicts = resource.getMaxPercentConflictsAllowed();
                ConflictCheckResult checkResult = checkAvailability(opTime, invite, maxNumConflicts, maxPctConflicts);
                if (checkResult != null) {
                    List<Conflict> conflicts = checkResult.getConflicts();
                    if (conflicts.size() > 0) {
                        if (invite.isRecurrence() && !checkResult.tooManyConflicts()) {
                            // There are some conflicts, but within resource's allowed limit.
                            if (resource.autoAcceptDecline()) {
                                // Let's accept partially.  (Accept the series and decline conflicting instances.)
                                List<Invite> replyInvites = new ArrayList<Invite>();
                                // the REPLY for the ACCEPT of recurrence series
                                Invite acceptInv = makeReplyInvite(account, authAcct, lc, onBehalfOf, allowPrivateAccess, invite, invite.getRecurId(), CalendarMailSender.VERB_ACCEPT);
                                for (Conflict conflict : conflicts) {
                                    Instance inst = conflict.getInstance();
                                    InviteInfo invInfo = inst.getInviteInfo();
                                    Invite inv = getInvite(invInfo.getMsgId(), invInfo.getComponentId());
                                    RecurId rid = inst.makeRecurId(inv);
                                    // Record the decline status in reply list.
                                    getReplyList().modifyPartStat(resource, rid, null, resource.getName(), null, null, IcalXmlStrMap.PARTSTAT_DECLINED, false, invite.getSeqNo(), opTime);
                                    replyListUpdated = true;
                                    // Make REPLY VEVENT for the declined instance.
                                    Invite replyInv = makeReplyInvite(account, authAcct, lc, onBehalfOf, allowPrivateAccess, inv, rid, CalendarMailSender.VERB_DECLINE);
                                    replyInvites.add(replyInv);
                                }
                                if (needReplyEmail) {
                                    ICalTimeZone tz = chooseReplyTZ(invite);
                                    // Send one email to accept the series.
                                    String declinedInstances = getDeclinedTimesString(octxt, mbox, conflicts, invite.isAllDayEvent(), tz, lc);
                                    String msg = L10nUtil.getMessage(MsgKey.calendarResourceDeclinedInstances, lc) + "\r\n\r\n" + declinedInstances;
                                    CalendarMailSender.sendResourceAutoReply(octxt, mbox, true, CalendarMailSender.VERB_ACCEPT, true, msg, this, invite, new Invite[] { acceptInv }, mmInv);
                                    // Send another email to decline instances, all in one email.
                                    String conflictingTimes = getBusyTimesString(octxt, mbox, conflicts, tz, lc, false);
                                    msg = L10nUtil.getMessage(MsgKey.calendarResourceDeclinedInstances, lc) + "\r\n\r\n" + declinedInstances + "\r\n" + L10nUtil.getMessage(MsgKey.calendarResourceDeclineReasonConflict, lc) + "\r\n\r\n" + conflictingTimes;
                                    CalendarMailSender.sendResourceAutoReply(octxt, mbox, true, CalendarMailSender.VERB_DECLINE, true, msg, this, invite, replyInvites.toArray(new Invite[0]), mmInv);
                                    replySent = true;
                                }
                            } else {
                            // Auto-accept is not enabled.  Auto-decline is enabled, but there weren't
                            // enough conflicting instances to decline outright.  So we just stay
                            // silent and let the human admin deal with it.  This case is rather
                            // ambiguous, and can be avoided by configuring the resource to allow
                            // zero conflicting instance.
                            }
                        } else {
                            // Too many conflicts.  Decline outright.
                            partStat = IcalXmlStrMap.PARTSTAT_DECLINED;
                            if (needReplyEmail) {
                                ICalTimeZone tz = chooseReplyTZ(invite);
                                String msg = L10nUtil.getMessage(MsgKey.calendarResourceDeclineReasonConflict, lc) + "\r\n\r\n" + getBusyTimesString(octxt, mbox, conflicts, tz, lc, checkResult.hasMoreConflicts());
                                Invite replyInv = makeReplyInvite(account, authAcct, lc, onBehalfOf, allowPrivateAccess, invite, invite.getRecurId(), CalendarMailSender.VERB_DECLINE);
                                CalendarMailSender.sendResourceAutoReply(octxt, mbox, true, CalendarMailSender.VERB_DECLINE, false, msg, this, invite, new Invite[] { replyInv }, mmInv);
                                replySent = true;
                            }
                        }
                    }
                }
            }
            if (!replySent && IcalXmlStrMap.PARTSTAT_ACCEPTED.equals(partStat)) {
                if (needReplyEmail) {
                    Invite replyInv = makeReplyInvite(account, authAcct, lc, onBehalfOf, allowPrivateAccess, invite, invite.getRecurId(), CalendarMailSender.VERB_ACCEPT);
                    CalendarMailSender.sendResourceAutoReply(octxt, mbox, true, CalendarMailSender.VERB_ACCEPT, false, null, this, invite, new Invite[] { replyInv }, mmInv);
                }
            }
            // Record the final outcome in the replies list.
            if (IcalXmlStrMap.PARTSTAT_NEEDS_ACTION.equals(partStat)) {
                getReplyList().modifyPartStat(resource, invite.getRecurId(), null, resource.getName(), null, null, partStat, false, invite.getSeqNo(), opTime);
                replyListUpdated = true;
            }
            if (forCreate && replyListUpdated)
                saveMetadata();
        }
    }
    CreateCalendarItemRecorder recorder = (CreateCalendarItemRecorder) mbox.getRedoRecorder();
    recorder.setCalendarItemPartStat(partStat);
    invite.updateMyPartStat(account, partStat);
    if (forCreate) {
        Invite defaultInvite = getDefaultInviteOrNull();
        if (defaultInvite != null && !defaultInvite.equals(invite) && !partStat.equals(defaultInvite.getPartStat())) {
            defaultInvite.updateMyPartStat(account, partStat);
            saveMetadata();
        }
    }
    return partStat;
}
Also used : Locale(java.util.Locale) Account(com.zimbra.cs.account.Account) InviteInfo(com.zimbra.cs.mailbox.calendar.InviteInfo) FBInstance(com.zimbra.cs.fb.FreeBusy.FBInstance) ArrayList(java.util.ArrayList) RecurId(com.zimbra.cs.mailbox.calendar.RecurId) CreateCalendarItemPlayer(com.zimbra.cs.redolog.op.CreateCalendarItemPlayer) CreateCalendarItemRecorder(com.zimbra.cs.redolog.op.CreateCalendarItemRecorder) RedoLogProvider(com.zimbra.cs.redolog.RedoLogProvider) ZAttendee(com.zimbra.cs.mailbox.calendar.ZAttendee) CalendarResource(com.zimbra.cs.account.CalendarResource) Invite(com.zimbra.cs.mailbox.calendar.Invite) ICalTimeZone(com.zimbra.common.calendar.ICalTimeZone)

Aggregations

CreateCalendarItemPlayer (com.zimbra.cs.redolog.op.CreateCalendarItemPlayer)3 CreateCalendarItemRecorder (com.zimbra.cs.redolog.op.CreateCalendarItemRecorder)3 Account (com.zimbra.cs.account.Account)2 Invite (com.zimbra.cs.mailbox.calendar.Invite)2 ICalTimeZone (com.zimbra.common.calendar.ICalTimeZone)1 CalendarResource (com.zimbra.cs.account.CalendarResource)1 FBInstance (com.zimbra.cs.fb.FreeBusy.FBInstance)1 TargetConstraint (com.zimbra.cs.mailbox.MailItem.TargetConstraint)1 InviteInfo (com.zimbra.cs.mailbox.calendar.InviteInfo)1 RecurId (com.zimbra.cs.mailbox.calendar.RecurId)1 ZAttendee (com.zimbra.cs.mailbox.calendar.ZAttendee)1 RedoLogProvider (com.zimbra.cs.redolog.RedoLogProvider)1 CreateMountpoint (com.zimbra.cs.redolog.op.CreateMountpoint)1 RefreshMountpoint (com.zimbra.cs.redolog.op.RefreshMountpoint)1 SetCalendarItem (com.zimbra.cs.redolog.op.SetCalendarItem)1 ArrayList (java.util.ArrayList)1 Locale (java.util.Locale)1