Search in sources :

Example 16 with Invite

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

the class Mailbox method importFeedInternal.

private void importFeedInternal(OperationContext octxt, Folder folder, boolean subscription, FeedManager.SubscriptionData<?> sdata) throws ServiceException {
    assert (lock.isWriteLockedByCurrentThread());
    // If syncing a folder with calendar items, remember the current items.  After applying the new
    // appointments/tasks, we need to remove ones that were not updated because they are apparently
    // deleted from the source feed.
    boolean isCalendar = folder.getDefaultView() == MailItem.Type.APPOINTMENT || folder.getDefaultView() == MailItem.Type.TASK;
    Set<Integer> toRemove = new HashSet<Integer>();
    if (subscription && isCalendar) {
        for (int i : listItemIds(octxt, MailItem.Type.UNKNOWN, folder.getId())) {
            toRemove.add(i);
        }
    }
    // if there's nothing to add, we can short-circuit here
    List<?> items = sdata.getItems();
    if (items.isEmpty()) {
        if (subscription && isCalendar) {
            // quicker than deleting appointments one at a time
            emptyFolder(octxt, folder.getId(), false);
        }
        updateRssDataSource(folder);
        return;
    }
    // disable modification conflict checks, as we've already wiped the folder and we may hit an appoinment >1 times
    OperationContext octxtNoConflicts = null;
    if (octxt != null) {
        octxtNoConflicts = new OperationContext(octxt).unsetChangeConstraint();
    } else {
        octxtNoConflicts = new OperationContext(getAccountId()).unsetChangeConstraint();
    }
    // add the newly-fetched items to the folder
    Set<String> calUidsSeen = new HashSet<String>();
    int numSkipped = 0;
    for (Object obj : items) {
        try {
            if (obj instanceof Invite) {
                Invite inv = (Invite) obj;
                String uid = inv.getUid();
                if (uid == null) {
                    uid = UUIDUtil.generateUUID();
                    inv.setUid(uid);
                }
                // Create the event in accepted state.  (bug 41639)
                inv.setPartStat(IcalXmlStrMap.PARTSTAT_ACCEPTED);
                inv.setRsvp(false);
                boolean addRevision;
                if (!calUidsSeen.contains(uid)) {
                    addRevision = true;
                    calUidsSeen.add(uid);
                } else {
                    addRevision = false;
                }
                try {
                    boolean importIt;
                    CalendarItem calItem = getCalendarItemByUid(octxtNoConflicts, uid);
                    if (calItem == null) {
                        // New appointment.  Import it.
                        importIt = true;
                    } else {
                        toRemove.remove(calItem.getId());
                        Folder curFolder = calItem.getFolder();
                        boolean sameFolder = curFolder.getId() == folder.getId();
                        boolean inTrashOrSpam = !sameFolder && (curFolder.inTrash() || curFolder.inSpam());
                        if (inTrashOrSpam) {
                            // If appointment is under trash/spam, delete it now to allow the downloaded invite to
                            // be imported cleanly.  Appointment in trash/spam is effectively non-existent, because
                            // it will eventually get purged.
                            delete(octxtNoConflicts, calItem.getId(), MailItem.Type.UNKNOWN);
                            importIt = true;
                        } else {
                            Invite[] oldInvites = calItem.getInvites();
                            if ((oldInvites == null) || (oldInvites.length == 0)) {
                                // Something is seriously wrong with the existing calendar item.  Delete it so
                                // new invite will import cleanly
                                delete(octxtNoConflicts, calItem.getId(), MailItem.Type.UNKNOWN);
                                importIt = true;
                            } else {
                                // Don't import if item is in a different folder.  It might be a regular appointment, and
                                // should not be overwritten by a feed version. (bug 14306)
                                // Import only if downloaded version is newer.
                                boolean changed;
                                Invite curInv = calItem.getInvite(inv.getRecurId());
                                if (curInv == null) {
                                    // We have an appointment with the same UID, but don't have an invite
                                    // with the same RECURRENCE-ID.  Treat it as a changed item.
                                    changed = true;
                                } else {
                                    if (inv.getSeqNo() > curInv.getSeqNo()) {
                                        changed = true;
                                    } else if (inv.getSeqNo() == curInv.getSeqNo()) {
                                        // Compare LAST-MODIFIED rather than DTSTAMP. (bug 55735)
                                        changed = inv.getLastModified() > curInv.getLastModified();
                                    } else {
                                        changed = false;
                                    }
                                }
                                importIt = sameFolder && changed;
                                if (!importIt && ZimbraLog.calendar.isDebugEnabled()) {
                                    if (sameFolder) {
                                        ZimbraLog.calendar.debug("Skip importing UID=%s. Already present & not newer.  SEQUENCE/LAST-MODIFIED old=%s,%s new=%s,%s", uid, curInv.getSeqNo(), curInv.getLastModified(), inv.getSeqNo(), inv.getLastModified());
                                    } else {
                                        ZimbraLog.calendar.debug("Skip importing UID=%s. Already in different folder id=%d", uid, curFolder.getId());
                                    }
                                }
                            }
                        }
                    }
                    if (importIt) {
                        addInvite(octxtNoConflicts, inv, folder.getId(), true, addRevision);
                    } else {
                        numSkipped++;
                    }
                } catch (ServiceException e) {
                    ZimbraLog.calendar.warn("Skipping bad iCalendar object UID=%s during import into folder id=%d", inv.getUid(), folder.getId(), e);
                }
            } else if (obj instanceof ParsedMessage) {
                DeliveryOptions dopt = new DeliveryOptions().setFolderId(folder).setNoICal(true).setFlags(Flag.BITMASK_UNREAD);
                addMessage(octxtNoConflicts, (ParsedMessage) obj, dopt, null);
            }
        } catch (IOException e) {
            throw ServiceException.FAILURE("IOException", e);
        }
    }
    if (numSkipped > 0) {
        ZimbraLog.calendar.warn("Skipped importing %d iCalendar objects with clashing UIDs", numSkipped);
    }
    // Delete calendar items that have been deleted in the source feed.
    for (int i : toRemove) {
        delete(octxtNoConflicts, i, MailItem.Type.UNKNOWN);
    }
    // update the subscription to avoid downloading items twice
    long lastModDate = sdata.getLastModifiedDate();
    if (subscription && lastModDate > 0) {
        try {
            setSubscriptionData(octxt, folder.getId(), lastModDate, sdata.getMostRecentGuid());
        } catch (Exception e) {
            ZimbraLog.mailbox.warn("could not update feed metadata", e);
        }
    }
    updateRssDataSource(folder);
}
Also used : ParsedMessage(com.zimbra.cs.mime.ParsedMessage) IOException(java.io.IOException) CreateFolder(com.zimbra.cs.redolog.op.CreateFolder) ZFolder(com.zimbra.client.ZFolder) RefreshMountpoint(com.zimbra.cs.redolog.op.RefreshMountpoint) TargetConstraint(com.zimbra.cs.mailbox.MailItem.TargetConstraint) CreateMountpoint(com.zimbra.cs.redolog.op.CreateMountpoint) AccountServiceException(com.zimbra.cs.account.AccountServiceException) IOException(java.io.IOException) NoSuchItemException(com.zimbra.cs.mailbox.MailServiceException.NoSuchItemException) MessageChannelException(com.zimbra.cs.iochannel.MessageChannelException) ServiceException(com.zimbra.common.service.ServiceException) UnsupportedEncodingException(java.io.UnsupportedEncodingException) SetCalendarItem(com.zimbra.cs.redolog.op.SetCalendarItem) AccountServiceException(com.zimbra.cs.account.AccountServiceException) ServiceException(com.zimbra.common.service.ServiceException) CreateInvite(com.zimbra.cs.redolog.op.CreateInvite) Invite(com.zimbra.cs.mailbox.calendar.Invite) HashSet(java.util.HashSet)

Example 17 with Invite

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

the class Mailbox method writeICalendarForCalendarItems.

public void writeICalendarForCalendarItems(Writer writer, OperationContext octxt, Collection<CalendarItem> calItems, Folder f, boolean useOutlookCompatMode, boolean ignoreErrors, boolean needAppleICalHacks, boolean trimCalItemsList, boolean escapeHtmlTags, boolean includeAttaches) throws ServiceException {
    lock.lock();
    try {
        writer.write("BEGIN:VCALENDAR\r\n");
        if (f != null) {
            writer.write("X-WR-CALNAME:");
            writer.write(f.getName());
            writer.write("\r\n");
            writer.write("X-WR-CALID:");
            writer.write(new ItemId(f).toString());
            writer.write("\r\n");
        }
        ZProperty prop;
        prop = new ZProperty(ICalTok.PRODID, ZCalendar.sZimbraProdID);
        prop.toICalendar(writer, needAppleICalHacks);
        prop = new ZProperty(ICalTok.VERSION, ZCalendar.sIcalVersion);
        prop.toICalendar(writer, needAppleICalHacks);
        prop = new ZProperty(ICalTok.METHOD, ICalTok.PUBLISH.toString());
        prop.toICalendar(writer, needAppleICalHacks);
        // timezones
        ICalTimeZone localTz = Util.getAccountTimeZone(getAccount());
        TimeZoneMap tzmap = new TimeZoneMap(localTz);
        for (CalendarItem calItem : calItems) {
            tzmap.add(calItem.getTimeZoneMap());
        }
        // iterate the tzmap and add all the VTimeZone's
        for (Iterator<ICalTimeZone> iter = tzmap.tzIterator(); iter.hasNext(); ) {
            ICalTimeZone tz = iter.next();
            tz.newToVTimeZone().toICalendar(writer, needAppleICalHacks);
        }
        // help keep memory consumption low
        tzmap = null;
        // build all the event components and add them to the Calendar
        for (Iterator<CalendarItem> iter = calItems.iterator(); iter.hasNext(); ) {
            CalendarItem calItem = iter.next();
            boolean allowPrivateAccess = calItem.isPublic() || calItem.allowPrivateAccess(octxt.getAuthenticatedUser(), octxt.isUsingAdminPrivileges());
            if (trimCalItemsList) {
                // help keep memory consumption low
                iter.remove();
            }
            Invite[] invites = calItem.getInvites();
            if (invites != null && invites.length > 0) {
                boolean appleICalExdateHack = LC.calendar_apple_ical_compatible_canceled_instances.booleanValue();
                ZComponent[] comps = null;
                try {
                    comps = Invite.toVComponents(invites, allowPrivateAccess, useOutlookCompatMode, appleICalExdateHack, includeAttaches);
                } catch (ServiceException e) {
                    if (ignoreErrors) {
                        ZimbraLog.calendar.warn("Error retrieving iCalendar data for item %s: %s", calItem.getId(), e.getMessage(), e);
                    } else {
                        throw e;
                    }
                }
                if (comps != null) {
                    for (ZComponent comp : comps) {
                        comp.toICalendar(writer, needAppleICalHacks, escapeHtmlTags);
                    }
                }
            }
        }
        writer.write("END:VCALENDAR\r\n");
    } catch (IOException e) {
        throw ServiceException.FAILURE("Error writing iCalendar", e);
    } finally {
        lock.release();
    }
}
Also used : IOException(java.io.IOException) ItemId(com.zimbra.cs.service.util.ItemId) SetCalendarItem(com.zimbra.cs.redolog.op.SetCalendarItem) ZComponent(com.zimbra.common.calendar.ZCalendar.ZComponent) AccountServiceException(com.zimbra.cs.account.AccountServiceException) ServiceException(com.zimbra.common.service.ServiceException) ZProperty(com.zimbra.common.calendar.ZCalendar.ZProperty) TimeZoneMap(com.zimbra.common.calendar.TimeZoneMap) ICalTimeZone(com.zimbra.common.calendar.ICalTimeZone) CreateInvite(com.zimbra.cs.redolog.op.CreateInvite) Invite(com.zimbra.cs.mailbox.calendar.Invite)

Example 18 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 19 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 20 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)

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