Search in sources :

Example 36 with Invite

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

the class Mailbox method processICalReplies.

private void processICalReplies(OperationContext octxt, ZVCalendar cal, String sender) throws ServiceException {
    // Reply from Outlook will usually have PRODID set to the following:
    //
    // Outlook2007+ZCO: PRODID:-//Microsoft Corporation//Outlook 12.0 MIMEDIR//EN
    // Outlook2010+ZCO: PRODID:-//Microsoft Corporation//Outlook 14.0 MIMEDIR//EN
    // Outlook20xx+Exchange: PRODID:Microsoft Exchange Server 2007
    //   (if Exchange is Exchange 2007; Exchange 2010 probably works similarly)
    //
    // Lowest common denominator is "Microsoft" substring.
    String prodId = cal.getPropVal(ICalTok.PRODID, null);
    boolean fromOutlook = prodId != null && prodId.toLowerCase().contains("microsoft");
    AccountAddressMatcher acctMatcher = new AccountAddressMatcher(getAccount());
    List<Invite> components = Invite.createFromCalendar(getAccount(), null, cal, false);
    for (Invite inv : components) {
        String orgAddress;
        if (inv.hasOrganizer()) {
            ZOrganizer org = inv.getOrganizer();
            orgAddress = org.getAddress();
        } else {
            ZimbraLog.calendar.warn("No ORGANIZER found in REPLY.  Assuming current mailbox.");
            orgAddress = getAccount().getName();
        }
        if (acctMatcher.matches(orgAddress)) {
            // RECURRENCE-ID.
            if (fromOutlook && !inv.isAllDayEvent() && inv.hasRecurId()) {
                RecurId rid = inv.getRecurId();
                if (rid.getDt() != null && rid.getDt().hasZeroTime()) {
                    CalendarItem calItem = getCalendarItemByUid(octxt, inv.getUid());
                    if (calItem != null) {
                        Invite seriesInv = calItem.getDefaultInviteOrNull();
                        if (seriesInv != null) {
                            ParsedDateTime seriesDtStart = seriesInv.getStartTime();
                            if (seriesDtStart != null) {
                                ParsedDateTime fixedDt = seriesDtStart.cloneWithNewDate(rid.getDt());
                                RecurId fixedRid = new RecurId(fixedDt, rid.getRange());
                                ZimbraLog.calendar.debug("Fixed up invalid RECURRENCE-ID with zero time; before=[%s], after=[%s]", rid, fixedRid);
                                inv.setRecurId(fixedRid);
                            }
                        }
                    }
                }
            }
            processICalReply(octxt, inv, sender);
        } else {
            Account orgAccount = inv.getOrganizerAccount();
            // Unknown organizer
            if (orgAccount == null) {
                ZimbraLog.calendar.warn("Unknown organizer " + orgAddress + " in REPLY");
                continue;
            }
            if (Provisioning.onLocalServer(orgAccount)) {
                // Run in the context of organizer's mailbox.
                Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(orgAccount);
                OperationContext orgOctxt = new OperationContext(mbox);
                mbox.processICalReply(orgOctxt, inv, sender);
            } else {
                // Organizer's mailbox is on a remote server.
                String uri = AccountUtil.getSoapUri(orgAccount);
                if (uri == null) {
                    ZimbraLog.calendar.warn("Unable to determine URI for organizer account %s", orgAddress);
                    continue;
                }
                try {
                    // TODO: Get the iCalendar data from the
                    // MIME part since we already have it.
                    String ical;
                    StringWriter sr = null;
                    try {
                        sr = new StringWriter();
                        inv.setMethod(ICalTok.REPLY.toString());
                        inv.newToICalendar(true).toICalendar(sr);
                        ical = sr.toString();
                    } finally {
                        if (sr != null) {
                            sr.close();
                        }
                    }
                    Options options = new Options();
                    AuthToken authToken = AuthToken.getCsrfUnsecuredAuthToken(getAuthToken(octxt));
                    options.setAuthToken(authToken.toZAuthToken());
                    options.setTargetAccount(orgAccount.getName());
                    options.setTargetAccountBy(AccountBy.name);
                    options.setUri(uri);
                    options.setNoSession(true);
                    ZMailbox zmbox = ZMailbox.getMailbox(options);
                    zmbox.iCalReply(ical, sender);
                } catch (IOException e) {
                    throw ServiceException.FAILURE("Error while posting REPLY to organizer mailbox host", e);
                }
            }
        }
    }
}
Also used : Account(com.zimbra.cs.account.Account) ParsedMessageOptions(com.zimbra.cs.mime.ParsedMessageOptions) Options(com.zimbra.client.ZMailbox.Options) ZOrganizer(com.zimbra.cs.mailbox.calendar.ZOrganizer) RecurId(com.zimbra.cs.mailbox.calendar.RecurId) IOException(java.io.IOException) SetCalendarItem(com.zimbra.cs.redolog.op.SetCalendarItem) ZMailbox(com.zimbra.client.ZMailbox) RenameMailbox(com.zimbra.cs.redolog.op.RenameMailbox) DbMailbox(com.zimbra.cs.db.DbMailbox) CreateMailbox(com.zimbra.cs.redolog.op.CreateMailbox) ZMailbox(com.zimbra.client.ZMailbox) DeleteMailbox(com.zimbra.cs.redolog.op.DeleteMailbox) StringWriter(java.io.StringWriter) AccountAddressMatcher(com.zimbra.cs.util.AccountUtil.AccountAddressMatcher) AuthToken(com.zimbra.cs.account.AuthToken) ZAuthToken(com.zimbra.common.auth.ZAuthToken) ParsedDateTime(com.zimbra.common.calendar.ParsedDateTime) CreateInvite(com.zimbra.cs.redolog.op.CreateInvite) Invite(com.zimbra.cs.mailbox.calendar.Invite)

Example 37 with Invite

use of com.zimbra.cs.mailbox.calendar.Invite 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 38 with Invite

use of com.zimbra.cs.mailbox.calendar.Invite 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 39 with Invite

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

the class TimeZoneFixupRules method fixCalendarItem.

// returns the number of timezones fixed up
public int fixCalendarItem(CalendarItem calItem, Map<String, ICalTimeZone> replaced) {
    int numFixed = 0;
    TimeZoneMap tzmap = calItem.getTimeZoneMap();
    numFixed += fixTZMap(tzmap, replaced);
    Invite[] invites = calItem.getInvites();
    for (Invite inv : invites) {
        if (inv != null) {
            TimeZoneMap tzmapInv = inv.getTimeZoneMap();
            numFixed += fixTZMap(tzmapInv, replaced);
        }
    }
    return numFixed;
}
Also used : TimeZoneMap(com.zimbra.common.calendar.TimeZoneMap) Invite(com.zimbra.cs.mailbox.calendar.Invite)

Example 40 with Invite

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

the class ModifyCalendarItem method modifyCalendarItem.

private Element modifyCalendarItem(ZimbraSoapContext zsc, OperationContext octxt, Element request, Account acct, Mailbox mbox, int folderId, CalendarItem calItem, Invite inv, Invite seriesInv, Element response, boolean isInterMboxMove, MailSendQueue sendQueue) throws ServiceException {
    // <M>
    Element msgElem = request.getElement(MailConstants.E_MSG);
    ModifyCalendarItemParser parser = new ModifyCalendarItemParser(inv, seriesInv);
    CalSendData dat = handleMsgElement(zsc, octxt, msgElem, acct, mbox, parser);
    dat.mDontNotifyAttendees = isInterMboxMove;
    if (!dat.mInvite.hasRecurId())
        ZimbraLog.calendar.info("<ModifyCalendarItem> id=%d, folderId=%d, subject=\"%s\", UID=%s", calItem.getId(), folderId, dat.mInvite.isPublic() ? dat.mInvite.getName() : "(private)", dat.mInvite.getUid());
    else
        ZimbraLog.calendar.info("<ModifyCalendarItem> id=%d, folderId=%d, subject=\"%s\", UID=%s, recurId=%s", calItem.getId(), folderId, dat.mInvite.isPublic() ? dat.mInvite.getName() : "(private)", dat.mInvite.getUid(), dat.mInvite.getRecurId().getDtZ());
    boolean hasRecipients;
    try {
        Address[] rcpts = dat.mMm.getAllRecipients();
        hasRecipients = rcpts != null && rcpts.length > 0;
    } catch (MessagingException e) {
        throw ServiceException.FAILURE("Checking recipients of outgoing msg ", e);
    }
    // If we are sending this to other people, then we MUST be the organizer!
    if (!dat.mInvite.isOrganizer() && hasRecipients)
        throw MailServiceException.MUST_BE_ORGANIZER("ModifyCalendarItem");
    if (!dat.mInvite.isOrganizer()) {
        // neverSent is always false for attendee users.
        dat.mInvite.setNeverSent(false);
    } else if (!dat.mInvite.hasOtherAttendees()) {
        // neverSent is always false for appointments without attendees.
        dat.mInvite.setNeverSent(false);
    } else if (hasRecipients) {
        // neverSent is set to false when attendees are notified.
        dat.mInvite.setNeverSent(false);
    } else {
        // This is the case of organizer saving an invite with attendees, but without sending the notification.
        assert (dat.mInvite.hasOtherAttendees() && !hasRecipients);
        if (!inv.hasOtherAttendees()) {
            // Special case of going from a personal appointment (no attendees) to a draft appointment with
            // attendees.  neverSent was false for being a personal appointment, so we need to explicitly set it to true.
            // This case is essentially identical to creating a new appointment with attendees without notification.
            dat.mInvite.setNeverSent(true);
        } else {
            // Set neverSent to false, but only if it wasn't already set to true before.
            // !inv.isNeverSent() ? false : true ==> inv.isNeverSent()
            dat.mInvite.setNeverSent(inv.isNeverSent());
        }
    }
    boolean echo = request.getAttributeBool(MailConstants.A_CAL_ECHO, false);
    ItemIdFormatter ifmt = new ItemIdFormatter(zsc);
    int maxSize = (int) request.getAttributeLong(MailConstants.A_MAX_INLINED_LENGTH, 0);
    boolean wantHTML = request.getAttributeBool(MailConstants.A_WANT_HTML, false);
    boolean neuter = request.getAttributeBool(MailConstants.A_NEUTER, true);
    boolean forceSend = request.getAttributeBool(MailConstants.A_CAL_FORCESEND, true);
    if (inv.isOrganizer()) {
        // Notify removed attendees before making any changes to the appointment.
        List<ZAttendee> atsCanceled = parser.getAttendeesCanceled();
        if (!inv.isNeverSent()) {
            // No need to notify for a draft appointment.
            if (!atsCanceled.isEmpty()) {
                notifyRemovedAttendees(zsc, octxt, acct, mbox, inv.getCalendarItem(), inv, atsCanceled, sendQueue);
            }
        }
        List<ZAttendee> atsAdded = parser.getAttendeesAdded();
        // Figure out if we're notifying all attendees.  Must do this before clearing recipients from dat.mMm.
        boolean notifyAllAttendees = isNotifyingAll(dat.mMm, atsAdded);
        // If notifying all the attendees update the last sequence number otherwise retain the existing value.
        if (notifyAllAttendees) {
            dat.mInvite.setLastFullSeqNo(dat.mInvite.getSeqNo());
        } else {
            dat.mInvite.setLastFullSeqNo(inv.getLastFullSeqNo());
        }
        if (inv.isRecurrence()) {
            // Clear to/cc/bcc from the MimeMessage, so that the sendCalendarMessage call only updates the organizer's
            // own appointment without notifying any attendees.  Notifications will be sent later,
            removeAllRecipients(dat.mMm);
            // (unless they are added as new series attendees)
            if (!acct.isCalendarKeepExceptionsOnSeriesTimeChange()) {
                InviteChanges ic = new InviteChanges(seriesInv, dat.mInvite);
                if (ic.isExceptionRemovingChange()) {
                    long now = octxt != null ? octxt.getTimestamp() : System.currentTimeMillis();
                    Invite[] invites = calItem.getInvites();
                    for (Invite except : invites) {
                        if (!except.isNeverSent() && except.hasRecurId() && !except.isCancel() && inviteIsAfterTime(except, now)) {
                            List<ZAttendee> toNotify = CalendarUtils.getRemovedAttendees(except.getAttendees(), seriesInv.getAttendees(), false, acct);
                            if (!toNotify.isEmpty()) {
                                notifyRemovedAttendees(zsc, octxt, acct, mbox, calItem, except, toNotify, sendQueue);
                            }
                        }
                    }
                }
            }
            // Save the change to the series as specified by the client.
            sendCalendarMessage(zsc, octxt, folderId, acct, mbox, dat, response, true, forceSend, sendQueue);
            // Echo the updated inv in the response.
            if (echo && dat.mAddInvData != null) {
                echoAddedInvite(response, ifmt, octxt, mbox, dat.mAddInvData, maxSize, wantHTML, neuter);
            }
            boolean ignorePastExceptions = true;
            // Reflect added/removed attendees in the exception instances.
            if (!atsAdded.isEmpty() || !atsCanceled.isEmpty()) {
                addRemoveAttendeesInExceptions(octxt, mbox, inv.getCalendarItem(), atsAdded, atsCanceled, ignorePastExceptions);
            }
            // Send notifications.
            if (hasRecipients) {
                notifyCalendarItem(zsc, octxt, acct, mbox, inv.getCalendarItem(), notifyAllAttendees, atsAdded, ignorePastExceptions, sendQueue);
            }
        } else {
            // Modifying a one-off appointment or an exception instance.  There are no
            // complications like in the series update case.  Just update the invite with the
            // data supplied by the client, and let the built-in notification take place.
            sendCalendarMessage(zsc, octxt, folderId, acct, mbox, dat, response, true, forceSend, sendQueue);
            // Echo the updated inv in the response.
            if (echo && dat.mAddInvData != null) {
                echoAddedInvite(response, ifmt, octxt, mbox, dat.mAddInvData, maxSize, wantHTML, neuter);
            }
        }
    } else {
        // not organizer
        // Apply the change.
        sendCalendarMessage(zsc, octxt, folderId, acct, mbox, dat, response, true, forceSend, sendQueue);
        // Echo the updated inv in the response.
        if (echo && dat.mAddInvData != null) {
            echoAddedInvite(response, ifmt, octxt, mbox, dat.mAddInvData, maxSize, wantHTML, neuter);
        }
    }
    return response;
}
Also used : InviteChanges(com.zimbra.cs.mailbox.calendar.InviteChanges) Address(javax.mail.Address) InternetAddress(javax.mail.internet.InternetAddress) MessagingException(javax.mail.MessagingException) ItemIdFormatter(com.zimbra.cs.service.util.ItemIdFormatter) Element(com.zimbra.common.soap.Element) ZAttendee(com.zimbra.cs.mailbox.calendar.ZAttendee) 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