Search in sources :

Example 51 with Invite

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

the class CalendarCollection method createItemFromInvites.

/**
     * @param name Preferred DAV basename for the new item - including ".ics" if appropriate.
     * @param allowUpdate - PUTs are allowed to update a pre-existing item.  POSTs to the containing collection are not.
     */
public DavResource createItemFromInvites(DavContext ctxt, Account account, String name, List<Invite> invites, boolean allowUpdate) throws DavException, IOException {
    boolean useEtag = allowUpdate;
    try {
        String user = account.getName();
        /*
             * Some of the CalDAV clients do not behave very well when it comes to etags.
             *     chandler doesn't set User-Agent header, doesn't understand If-None-Match or If-Match headers.
             *     evolution 2.8 always sets If-None-Match although we return etag in REPORT.
             *     ical correctly understands etag and sets If-Match for existing etags, but does not use If-None-Match
             *     for new resource creation.
             */
        HttpServletRequest req = ctxt.getRequest();
        String etag = null;
        if (useEtag) {
            etag = req.getHeader(DavProtocol.HEADER_IF_MATCH);
            useEtag = (etag != null);
        }
        String baseName = HttpUtil.urlUnescape(name);
        boolean acceptableClientChosenBasename = DebugConfig.enableDAVclientCanChooseResourceBaseName && baseName.equals(name);
        if (name.endsWith(CalendarObject.CAL_EXTENSION)) {
            name = name.substring(0, name.length() - CalendarObject.CAL_EXTENSION.length());
            // Unescape the name (It was encoded in DavContext intentionally)
            name = HttpUtil.urlUnescape(name);
        }
        String uid = findEventUid(invites);
        Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account);
        CalendarItem origCalItem = null;
        // Is the basename of the path client assigned rather than following the standard pattern?
        Integer itemId = null;
        if (acceptableClientChosenBasename) {
            itemId = DavNames.get(this.mMailboxId, this.mId, baseName);
        }
        if (itemId != null) {
            try {
                MailItem mailItem = mbox.getItemById(ctxt.getOperationContext(), itemId, MailItem.Type.UNKNOWN);
                if (mailItem != null && mailItem instanceof CalendarItem) {
                    origCalItem = (CalendarItem) mailItem;
                }
            } catch (ServiceException se) {
            }
        }
        if (origCalItem == null) {
            if (uid.equals(name)) {
                origCalItem = mbox.getCalendarItemByUid(ctxt.getOperationContext(), name);
            } else {
                /* the basename of the path doesn't fit our preferred naming convention. */
                origCalItem = mbox.getCalendarItemByUid(ctxt.getOperationContext(), uid);
                String redirectUrl = null;
                if (origCalItem != null) {
                    if (this.mId != origCalItem.getFolderId()) {
                        // In another folder, ignore
                        origCalItem = null;
                    } else {
                        // The item exists, but doesn't have this name - UID conflict.
                        if (acceptableClientChosenBasename) {
                            redirectUrl = hrefForCalendarItem(origCalItem, user, uid);
                        } else {
                            redirectUrl = defaultUrlForCalendarItem(user, uid);
                        }
                        throw new DavException.UidConflict("An item with the same UID already exists in the calendar", redirectUrl);
                    }
                }
                if ((origCalItem == null) && (!DebugConfig.enableDAVclientCanChooseResourceBaseName)) {
                    redirectUrl = defaultUrlForCalendarItem(user, uid);
                }
                if (allowUpdate && (redirectUrl != null)) {
                    /* SC_FOUND - Status code (302) indicating that the resource reside temporarily under a
                         * different URI. Since the redirection might be altered on occasion, the client should
                         * continue to use the Request-URI for future requests.(HTTP/1.1) To represent the status code
                         * (302), it is recommended to use this variable.  Used to be called SC_MOVED_TEMPORARILY
                         */
                    // sets status to SC_FOUND
                    ctxt.getResponse().sendRedirect(redirectUrl);
                    StringBuilder wrongUrlMsg = new StringBuilder();
                    wrongUrlMsg.append("wrong url - redirecting to:\n").append(redirectUrl);
                    throw new DavException(wrongUrlMsg.toString(), HttpServletResponse.SC_FOUND, null);
                }
            }
        }
        if (origCalItem == null && useEtag) {
            throw new DavException("event not found", HttpServletResponse.SC_NOT_FOUND, null);
        }
        if (origCalItem != null && !allowUpdate) {
            throw new DavException.UidConflict("An item with the same UID already exists in the calendar", hrefForCalendarItem(origCalItem, user, uid));
        }
        boolean isNewItem = true;
        if (useEtag) {
            String itemEtag = MailItemResource.getEtag(origCalItem);
            if (!itemEtag.equals(etag)) {
                throw new DavException(String.format("CalDAV client has stale event: event has different etag (%s) vs %s", itemEtag, etag), HttpServletResponse.SC_PRECONDITION_FAILED);
            }
            isNewItem = false;
        }
        // prepare to call Mailbox.setCalendarItem()
        int flags = 0;
        String[] tags = null;
        List<ReplyInfo> replies = null;
        Invite[] origInvites = null;
        if (origCalItem != null) {
            flags = origCalItem.getFlagBitmask();
            tags = origCalItem.getTags();
            replies = origCalItem.getAllReplies();
            origInvites = origCalItem.getInvites();
        }
        SetCalendarItemData scidDefault = new SetCalendarItemData();
        SetCalendarItemData[] scidExceptions = null;
        int idxExceptions = 0;
        boolean first = true;
        for (Invite i : invites) {
            // check for valid uid.
            if (i.getUid() == null)
                i.setUid(uid);
            adjustOrganizer(ctxt, i);
            // Carry over the MimeMessage/ParsedMessage to preserve any attachments.
            // CalDAV clients don't support attachments, and on edit we have to either
            // retain existing attachments or drop them.  Retaining is better.
            ParsedMessage oldPm = null;
            if (origCalItem != null) {
                Invite oldInv = origCalItem.getInvite(i.getRecurId());
                if (oldInv == null && i.hasRecurId()) {
                    // It's a new exception instance.  Inherit from series.
                    oldInv = origCalItem.getInvite((RecurId) null);
                }
                if (oldInv != null) {
                    MimeMessage mmInv = origCalItem.getSubpartMessage(oldInv.getMailItemId());
                    oldPm = mmInv != null ? new ParsedMessage(mmInv, false) : null;
                }
            }
            if (first) {
                scidDefault.invite = i;
                scidDefault.message = oldPm;
                first = false;
            } else {
                SetCalendarItemData scid = new SetCalendarItemData();
                scid.invite = i;
                scid.message = oldPm;
                if (scidExceptions == null) {
                    scidExceptions = new SetCalendarItemData[invites.size() - 1];
                }
                scidExceptions[idxExceptions++] = scid;
            }
            // For attendee case, update replies list with matching ATTENDEE from the invite.
            if (!i.isOrganizer() && replies != null) {
                ZAttendee at = i.getMatchingAttendee(account);
                if (at != null) {
                    AccountAddressMatcher acctMatcher = new AccountAddressMatcher(account);
                    ReplyInfo newReply = null;
                    for (Iterator<ReplyInfo> replyIter = replies.iterator(); replyIter.hasNext(); ) {
                        ReplyInfo reply = replyIter.next();
                        if (acctMatcher.matches(reply.getAttendee().getAddress())) {
                            RecurId ridR = reply.getRecurId(), ridI = i.getRecurId();
                            if ((ridR == null && ridI == null) || (ridR != null && ridR.equals(ridI))) {
                                // matching RECURRENCE-ID
                                // No need to compare SEQUENCE and DTSTAMP of existing reply and new invite.
                                // We're just going to take what the caldav client sent, even if it's older
                                // than the existing reply.
                                replyIter.remove();
                                if (!IcalXmlStrMap.PARTSTAT_NEEDS_ACTION.equalsIgnoreCase(at.getPartStat())) {
                                    newReply = new ReplyInfo(at, i.getSeqNo(), i.getDTStamp(), ridI);
                                }
                                break;
                            }
                        }
                    }
                    if (newReply != null) {
                        replies.add(newReply);
                    }
                }
            }
        }
        CalendarItem newCalItem = null;
        AutoScheduler autoScheduler = AutoScheduler.getAutoScheduler(mbox, this.getCalendarMailbox(ctxt), origInvites, mId, flags, tags, scidDefault, scidExceptions, replies, ctxt);
        if (autoScheduler == null) {
            newCalItem = mbox.setCalendarItem(ctxt.getOperationContext(), mId, flags, tags, scidDefault, scidExceptions, replies, CalendarItem.NEXT_ALARM_KEEP_CURRENT);
        } else {
            // Note: This also sets the calendar item
            newCalItem = autoScheduler.doSchedulingActions();
        }
        if (newCalItem == null) {
            throw new DavException("cannot create icalendar item - corrupt ICAL?", HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
        }
        if (!uid.equals(name)) {
            if (acceptableClientChosenBasename) {
                DavNames.put(DavNames.DavName.create(this.mMailboxId, newCalItem.getFolderId(), baseName), newCalItem.getId());
            }
        }
        return new CalendarObject.LocalCalendarObject(ctxt, newCalItem, isNewItem);
    } catch (BadOrganizerException.DiffOrganizerInComponentsException e) {
        throw new DavException.NeedSameOrganizerInAllComponents(e.getMessage());
    } catch (BadOrganizerException e) {
        // FORBIDDEN if we aren't going to be able to cope with the data
        throw new DavException(e.getMessage(), HttpServletResponse.SC_FORBIDDEN, e);
    } catch (ServiceException e) {
        if (e.getCode().equals(ServiceException.FORBIDDEN)) {
            throw new DavException(e.getMessage(), HttpServletResponse.SC_FORBIDDEN, e);
        } else {
            throw new DavException("cannot create icalendar item", HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e);
        }
    }
}
Also used : RecurId(com.zimbra.cs.mailbox.calendar.RecurId) ReplyInfo(com.zimbra.cs.mailbox.CalendarItem.ReplyInfo) SetCalendarItemData(com.zimbra.cs.mailbox.Mailbox.SetCalendarItemData) HttpServletRequest(javax.servlet.http.HttpServletRequest) CalendarItem(com.zimbra.cs.mailbox.CalendarItem) Mailbox(com.zimbra.cs.mailbox.Mailbox) MimeMessage(javax.mail.internet.MimeMessage) BadOrganizerException(com.zimbra.cs.mailbox.BadOrganizerException) AutoScheduler(com.zimbra.cs.dav.caldav.AutoScheduler) DavException(com.zimbra.cs.dav.DavException) ParsedMessage(com.zimbra.cs.mime.ParsedMessage) MailItem(com.zimbra.cs.mailbox.MailItem) ServiceException(com.zimbra.common.service.ServiceException) AccountAddressMatcher(com.zimbra.cs.util.AccountUtil.AccountAddressMatcher) ZAttendee(com.zimbra.cs.mailbox.calendar.ZAttendee) Invite(com.zimbra.cs.mailbox.calendar.Invite)

Example 52 with Invite

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

the class CalendarCollection method createItem.

/**
     * Creates an appointment sent in PUT request in this calendar.
     * @param name - basename (last component) of the path - i.e. the name within this collection
     */
@Override
public DavResource createItem(DavContext ctxt, String name) throws DavException, IOException {
    Provisioning prov = Provisioning.getInstance();
    try {
        String user = ctxt.getUser();
        Account account = prov.get(AccountBy.name, user);
        if (account == null) {
            // Anti-account name harvesting.
            ZimbraLog.dav.info("Failing POST to Calendar - no such account '%s'", user);
            throw new DavException("Request denied", HttpServletResponse.SC_NOT_FOUND, null);
        }
        List<Invite> invites = uploadToInvites(ctxt, account);
        return createItemFromInvites(ctxt, account, name, invites, true);
    } catch (ServiceException e) {
        if (e.getCode().equals(ServiceException.FORBIDDEN)) {
            throw new DavException(e.getMessage(), HttpServletResponse.SC_FORBIDDEN, e);
        } else {
            throw new DavException("cannot create icalendar item", HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e);
        }
    }
}
Also used : Account(com.zimbra.cs.account.Account) ServiceException(com.zimbra.common.service.ServiceException) DavException(com.zimbra.cs.dav.DavException) Provisioning(com.zimbra.cs.account.Provisioning) Invite(com.zimbra.cs.mailbox.calendar.Invite)

Example 53 with Invite

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

the class Mailbox method fixCalendarItemPriority.

public int fixCalendarItemPriority(OperationContext octxt, CalendarItem calItem) throws ServiceException {
    FixCalendarItemPriority redoRecorder = new FixCalendarItemPriority(getId(), calItem.getId());
    boolean success = false;
    try {
        beginTransaction("fixupCalendarItemPriority", octxt, redoRecorder);
        int flags = calItem.mData.getFlags() & ~(Flag.BITMASK_HIGH_PRIORITY | Flag.BITMASK_LOW_PRIORITY);
        Invite[] invs = calItem.getInvites();
        if (invs != null) {
            for (Invite cur : invs) {
                String method = cur.getMethod();
                if (method.equals(ICalTok.REQUEST.toString()) || method.equals(ICalTok.PUBLISH.toString())) {
                    if (cur.isHighPriority()) {
                        flags |= Flag.BITMASK_HIGH_PRIORITY;
                    }
                    if (cur.isLowPriority()) {
                        flags |= Flag.BITMASK_LOW_PRIORITY;
                    }
                }
            }
        }
        int numFixed = 0;
        if (flags != calItem.mData.getFlags()) {
            ZimbraLog.calendar.info("Fixed calendar item " + calItem.getId());
            markItemModified(calItem, Change.INVITE);
            calItem.mData.setFlags(flags);
            calItem.snapshotRevision();
            calItem.saveMetadata();
            success = true;
            numFixed = 1;
        }
        return numFixed;
    } finally {
        endTransaction(success);
    }
}
Also used : FixCalendarItemPriority(com.zimbra.cs.redolog.op.FixCalendarItemPriority) RefreshMountpoint(com.zimbra.cs.redolog.op.RefreshMountpoint) TargetConstraint(com.zimbra.cs.mailbox.MailItem.TargetConstraint) CreateMountpoint(com.zimbra.cs.redolog.op.CreateMountpoint) CreateInvite(com.zimbra.cs.redolog.op.CreateInvite) Invite(com.zimbra.cs.mailbox.calendar.Invite)

Example 54 with Invite

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

the class CalSummaryCache method reloadCalendarItemOverRange.

// mSummaryCache
//
// key = "accountId:folderId"
// value = CalendarData type
//
// CalendarData = {
//   folderId, range start, range end,
//   // list of CalendarItemData objects (one for each appointment in range)
//   [
//     CalendarItemData {
//       calItemId, folderId, flags, tags, item type,
//       last modified,
//       actual range start, actual range end,
//       uid, isRecurring, isPublic, alarm,
//       default instance data (FullInstanceData type),
//       // list of instances (FullInstanceData if an exception, InstanceData if not)
//       [
//         InstanceData/FullInstanceData, ...
//       ]
//     },
//     CalendarItemData, ...
//   ]
public static CalendarItemData reloadCalendarItemOverRange(CalendarItem calItem, long rangeStart, long rangeEnd) throws ServiceException {
    CalendarItemData calItemData = null;
    try {
        boolean rangeValid = (rangeStart >= CalendarUtils.MICROSOFT_EPOC_START_MS_SINCE_EPOC && rangeEnd > CalendarUtils.MICROSOFT_EPOC_START_MS_SINCE_EPOC && rangeStart < rangeEnd);
        if (!rangeValid) {
            return null;
        }
        Invite defaultInvite = calItem.getDefaultInviteOrNull();
        if (defaultInvite == null) {
            ZimbraLog.calendar.info("Could not load defaultinfo for calendar item with id=" + calItem.getId() + "; SKIPPING");
            return null;
        }
        String defaultFba = null;
        if (calItem instanceof Appointment)
            defaultFba = ((Appointment) calItem).getEffectiveFreeBusyActual(defaultInvite, null);
        AlarmData alarm = null;
        CalendarItem.AlarmData calItemAlarmData = calItem.getAlarmData();
        long alarmTime = 0;
        long alarmInst = 0;
        if (calItemAlarmData != null) {
            alarmTime = calItemAlarmData.getNextAt();
            alarmInst = calItemAlarmData.getNextInstanceStart();
            int alarmInvId = calItemAlarmData.getInvId();
            int alarmCompNum = calItemAlarmData.getCompNum();
            String summary = null, location = null;
            Invite alarmInv = calItem.getInvite(alarmInvId, alarmCompNum);
            if (alarmInv != null) {
                summary = alarmInv.getName();
                location = alarmInv.getLocation();
            }
            alarm = new AlarmData(calItemAlarmData.getNextAt(), calItemAlarmData.getNextInstanceStart(), alarmInvId, alarmCompNum, summary, location, calItemAlarmData.getAlarm());
        }
        Long defDtStartLong = null;
        Long defDurationLong = null;
        ParsedDateTime defDtStart = defaultInvite.getStartTime();
        if (defDtStart != null) {
            defDtStartLong = Long.valueOf(defDtStart.getUtcTime());
            ParsedDateTime defDtEnd = defaultInvite.getEffectiveEndTime();
            if (defDtEnd != null)
                defDurationLong = Long.valueOf(defDtEnd.getUtcTime() - defDtStartLong.longValue());
        }
        String defaultEffectivePartStat = calItem.getEffectivePartStat(defaultInvite, null);
        FullInstanceData defaultData = new FullInstanceData(defaultInvite, null, defDtStartLong, defDurationLong, defaultEffectivePartStat, defaultFba, null);
        calItemData = new CalendarItemData(calItem.getType(), calItem.getFolderId(), calItem.getId(), calItem.getFlagString(), calItem.getTags(), TagUtil.getTagIdString(calItem), calItem.getModifiedSequence(), calItem.getSavedSequence(), calItem.getDate(), calItem.getChangeDate(), calItem.getSize(), defaultInvite.getUid(), defaultInvite.isRecurrence(), calItem.hasExceptions(), calItem.isPublic(), alarm, defaultData);
        long actualRangeStart = 0;
        long actualRangeEnd = 0;
        int numInstances = 0;
        Collection<CalendarItem.Instance> instances = calItem.expandInstances(rangeStart, rangeEnd, true);
        for (CalendarItem.Instance inst : instances) {
            try {
                long instStart = inst.getStart();
                long duration = inst.getEnd() - instStart;
                // 0 means "no DTSTART", however, note that negative numbers are valid
                Long instStartLong = instStart != 0 ? Long.valueOf(instStart) : null;
                Long durationLong = duration > 0 ? Long.valueOf(duration) : null;
                // For an instance whose alarm time is within the time range, we must
                // include it even if its start time is after the range.
                long startOrAlarm = instStart == alarmInst ? alarmTime : instStart;
                boolean hasTimes = inst.hasStart() && inst.hasEnd();
                if (hasTimes && (startOrAlarm >= rangeEnd || inst.getEnd() <= rangeStart)) {
                    continue;
                }
                numInstances++;
                if (hasTimes) {
                    if (actualRangeStart == 0 || startOrAlarm < actualRangeStart)
                        actualRangeStart = startOrAlarm;
                    if (inst.getEnd() > actualRangeEnd)
                        actualRangeEnd = inst.getEnd();
                }
                InviteInfo invId = inst.getInviteInfo();
                Invite inv = calItem.getInvite(invId.getMsgId(), invId.getComponentId());
                Long alarmAt = instStart == alarmInst ? Long.valueOf(alarmTime) : null;
                String fba = inv.getFreeBusyActual();
                if (calItem instanceof Appointment)
                    fba = ((Appointment) calItem).getEffectiveFreeBusyActual(inv, inst);
                String effectivePartStat = calItem.getEffectivePartStat(inv, inst);
                InstanceData instData;
                if (!inst.isException()) {
                    String ridZ = inst.getRecurIdZ();
                    Long tzOffset = instStartLong != null && inst.isAllDay() ? Long.valueOf(inst.getStartTzOffset()) : null;
                    instData = new InstanceData(ridZ, instStartLong, durationLong, alarmAt, tzOffset, effectivePartStat, fba, inv.getPercentComplete(), defaultData);
                } else {
                    String ridZ = null;
                    if (inv.hasRecurId())
                        ridZ = inv.getRecurId().getDtZ();
                    instData = new FullInstanceData(inv, ridZ, instStartLong, durationLong, effectivePartStat, fba, alarmAt);
                }
                calItemData.addInstance(instData);
            } catch (MailServiceException.NoSuchItemException e) {
                ZimbraLog.calendar.info("Error could not get instance " + inst.getMailItemId() + "-" + inst.getComponentNum() + " for appt " + calItem.getId(), e);
            }
        }
        if (numInstances < 1)
            return null;
        calItemData.setActualRange(actualRangeStart, actualRangeEnd);
    } catch (MailServiceException.NoSuchItemException e) {
        ZimbraLog.calendar.info("Error could not get default invite for calendar item: " + calItem.getId(), e);
    } catch (RuntimeException e) {
        ZimbraLog.calendar.info("Caught Exception " + e + " while getting summary info for calendar item: " + calItem.getId(), e);
    }
    return calItemData;
}
Also used : Appointment(com.zimbra.cs.mailbox.Appointment) InviteInfo(com.zimbra.cs.mailbox.calendar.InviteInfo) CalendarItem(com.zimbra.cs.mailbox.CalendarItem) ParsedDateTime(com.zimbra.common.calendar.ParsedDateTime) MailServiceException(com.zimbra.cs.mailbox.MailServiceException) Invite(com.zimbra.cs.mailbox.calendar.Invite)

Example 55 with Invite

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

the class FeedManager method retrieveRemoteDatasource.

@VisibleForTesting
protected static SubscriptionData<?> retrieveRemoteDatasource(Account acct, RemoteDataInfo rdi, Folder.SyncData fsd) throws ServiceException, IOException {
    StringBuilder charset = new StringBuilder(rdi.expectedCharset);
    switch(getLeadingChar(rdi.content, charset)) {
        case -1:
            throw ServiceException.PARSE_ERROR("empty body in response when fetching remote subscription", null);
        case '<':
            return parseRssFeed(Element.parseXML(rdi.content), fsd, rdi.lastModified);
        case 'B':
        case 'b':
            List<ZVCalendar> icals = ZCalendarBuilder.buildMulti(rdi.content, charset.toString());
            List<Invite> invites = Invite.createFromCalendar(acct, null, icals, true, true, null);
            // handle missing UIDs on remote calendars by generating them as needed
            for (Invite inv : invites) {
                if (inv.getUid() == null) {
                    inv.setUid(LdapUtil.generateUUID());
                }
            }
            return new SubscriptionData<Invite>(invites, rdi.lastModified);
        default:
            throw ServiceException.PARSE_ERROR("unrecognized remote content", null);
    }
}
Also used : ZVCalendar(com.zimbra.common.calendar.ZCalendar.ZVCalendar) Invite(com.zimbra.cs.mailbox.calendar.Invite) VisibleForTesting(com.google.common.annotations.VisibleForTesting)

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