Search in sources :

Example 36 with MailItem

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

the class TestItemCache method cacheHit.

/**
     * Re-gets the same message 10 times and makes sure we don't hit the database.
     */
@Test
public void cacheHit() throws Exception {
    ZimbraLog.test.debug("Starting %s", testInfo.getMethodName());
    TestUtil.addMessage(mMbox, String.format("%s-%s", PREFIX, "missive in inbox"));
    TestUtil.addMessage(mMbox, String.format("%s-%s", PREFIX, "2nd missive in inbox"));
    List<MailItem> messages = mMbox.getItemList(null, MailItem.Type.MESSAGE, Mailbox.ID_FOLDER_INBOX);
    assertNotNull("List returned by mMbox.getItemList", messages);
    assertEquals("Expected number of messages in the inbox", 2, messages.size());
    Message msg = (Message) messages.get(0);
    mMbox.getItemById(null, msg.getId(), msg.getType());
    int prepareCount = ZimbraPerf.getPrepareCount();
    for (int i = 1; i <= 10; i++) {
        mMbox.getItemById(null, msg.getId(), msg.getType());
    }
    prepareCount = ZimbraPerf.getPrepareCount() - prepareCount;
    assertEquals("Detected unexpected SQL statements.", 0, prepareCount);
}
Also used : MailItem(com.zimbra.cs.mailbox.MailItem) Message(com.zimbra.cs.mailbox.Message) Test(org.junit.Test)

Example 37 with MailItem

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

the class GetCustomMetadata method handle.

@Override
public Element handle(Element request, Map<String, Object> context) throws ServiceException {
    ZimbraSoapContext zsc = getZimbraSoapContext(context);
    Mailbox mbox = getRequestedMailbox(zsc);
    OperationContext octxt = getOperationContext(zsc, context);
    ItemIdFormatter ifmt = new ItemIdFormatter(zsc);
    Element meta = request.getElement(MailConstants.E_METADATA);
    String section = meta.getAttribute(MailConstants.A_SECTION);
    ItemId iid = new ItemId(request.getAttribute(MailConstants.A_ID), zsc);
    MailItem item = mbox.getItemById(octxt, iid.getId(), MailItem.Type.UNKNOWN);
    CustomMetadata custom = item.getCustomData(section);
    Element response = zsc.createElement(MailConstants.GET_METADATA_RESPONSE);
    response.addAttribute(MailConstants.A_ID, ifmt.formatItemId(item));
    ToXML.encodeCustomMetadata(response, custom);
    return response;
}
Also used : OperationContext(com.zimbra.cs.mailbox.OperationContext) MailItem(com.zimbra.cs.mailbox.MailItem) Mailbox(com.zimbra.cs.mailbox.Mailbox) ItemIdFormatter(com.zimbra.cs.service.util.ItemIdFormatter) ZimbraSoapContext(com.zimbra.soap.ZimbraSoapContext) Element(com.zimbra.common.soap.Element) ItemId(com.zimbra.cs.service.util.ItemId) CustomMetadata(com.zimbra.cs.mailbox.MailItem.CustomMetadata)

Example 38 with MailItem

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

the class GetItem method handle.

@Override
public Element handle(Element request, Map<String, Object> context) throws ServiceException {
    ZimbraSoapContext zsc = getZimbraSoapContext(context);
    Mailbox mbox = getRequestedMailbox(zsc);
    OperationContext octxt = getOperationContext(zsc, context);
    ItemIdFormatter ifmt = new ItemIdFormatter(zsc);
    Element target = request.getElement(MailConstants.E_ITEM);
    String id = target.getAttribute(MailConstants.A_ID, null);
    String folderStr = target.getAttribute(MailConstants.A_FOLDER, null);
    String path = target.getAttribute(MailConstants.A_PATH, target.getAttribute(MailConstants.A_NAME, null));
    if (folderStr != null && path == null)
        throw ServiceException.INVALID_REQUEST("missing required attribute: " + MailConstants.A_PATH, null);
    MailItem item;
    if (id != null) {
        // get item by id
        item = mbox.getItemById(octxt, new ItemId(id, zsc).getId(), MailItem.Type.UNKNOWN);
    } else if (path != null) {
        // get item by name within containing folder id (from root by default)
        int folderId = folderStr == null ? Mailbox.ID_FOLDER_USER_ROOT : new ItemId(folderStr, zsc).getId();
        try {
            item = mbox.getItemByPath(octxt, path, folderId);
        } catch (MailServiceException.NoSuchItemException nsie) {
            Pair<Folder, String> match = mbox.getFolderByPathLongestMatch(octxt, folderId, path);
            if (match.getFirst() instanceof Mountpoint) {
                Mountpoint mpt = (Mountpoint) match.getFirst();
                target.addAttribute(MailConstants.A_FOLDER, mpt.getRemoteId()).addAttribute(MailConstants.A_PATH, match.getSecond());
                return proxyRequest(request, context, mpt.getOwnerId());
            }
            throw nsie;
        }
    } else {
        throw ServiceException.INVALID_REQUEST("must specify 'id' or 'path'", null);
    }
    Element response = zsc.createElement(MailConstants.GET_ITEM_RESPONSE);
    ToXML.encodeItem(response, ifmt, octxt, item, ToXML.NOTIFY_FIELDS);
    return response;
}
Also used : OperationContext(com.zimbra.cs.mailbox.OperationContext) MailItem(com.zimbra.cs.mailbox.MailItem) Mailbox(com.zimbra.cs.mailbox.Mailbox) ItemIdFormatter(com.zimbra.cs.service.util.ItemIdFormatter) ZimbraSoapContext(com.zimbra.soap.ZimbraSoapContext) Element(com.zimbra.common.soap.Element) Folder(com.zimbra.cs.mailbox.Folder) ItemId(com.zimbra.cs.service.util.ItemId) Mountpoint(com.zimbra.cs.mailbox.Mountpoint)

Example 39 with MailItem

use of com.zimbra.cs.mailbox.MailItem 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 40 with MailItem

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

the class AbstractProxyProperty method getMountpoints.

protected ArrayList<Pair<Mountpoint, ZFolder>> getMountpoints(DavContext ctxt) {
    ArrayList<Pair<Mountpoint, ZFolder>> mps = new ArrayList<Pair<Mountpoint, ZFolder>>();
    try {
        Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account);
        for (MailItem item : mbox.getItemList(ctxt.getOperationContext(), MailItem.Type.MOUNTPOINT)) {
            Mountpoint mp = (Mountpoint) item;
            // skip non-calendar mountpoints
            if (mp.getDefaultView() != MailItem.Type.APPOINTMENT && mp.getDefaultView() != MailItem.Type.TASK) {
                continue;
            }
            ZAuthToken zat = AuthProvider.getAuthToken(ctxt.getAuthAccount()).toZAuthToken();
            ZMailbox zmbx = RemoteCollection.getRemoteMailbox(zat, mp.getOwnerId());
            // skip dangling mountpoints
            if (zmbx == null) {
                continue;
            }
            try {
                ZFolder folder = zmbx.getFolderById(mp.getTarget().toString(account));
                // skip dangling mountpoints
                if (folder == null) {
                    continue;
                }
                mps.add(new Pair<Mountpoint, ZFolder>(mp, folder));
            } catch (ServiceException se) {
                ZimbraLog.dav.warn("can't get remote folder", se);
            }
        }
    } catch (ServiceException se) {
        ZimbraLog.dav.warn("can't get mailbox", se);
    }
    return mps;
}
Also used : MailItem(com.zimbra.cs.mailbox.MailItem) ZMailbox(com.zimbra.client.ZMailbox) Mailbox(com.zimbra.cs.mailbox.Mailbox) ZMailbox(com.zimbra.client.ZMailbox) ServiceException(com.zimbra.common.service.ServiceException) ArrayList(java.util.ArrayList) ZFolder(com.zimbra.client.ZFolder) Mountpoint(com.zimbra.cs.mailbox.Mountpoint) ZAuthToken(com.zimbra.common.auth.ZAuthToken) Pair(com.zimbra.common.util.Pair)

Aggregations

MailItem (com.zimbra.cs.mailbox.MailItem)74 Mailbox (com.zimbra.cs.mailbox.Mailbox)36 ServiceException (com.zimbra.common.service.ServiceException)30 Folder (com.zimbra.cs.mailbox.Folder)23 MailServiceException (com.zimbra.cs.mailbox.MailServiceException)23 Message (com.zimbra.cs.mailbox.Message)19 Mountpoint (com.zimbra.cs.mailbox.Mountpoint)17 ArrayList (java.util.ArrayList)17 IOException (java.io.IOException)16 OperationContext (com.zimbra.cs.mailbox.OperationContext)15 NoSuchItemException (com.zimbra.cs.mailbox.MailServiceException.NoSuchItemException)14 Element (com.zimbra.common.soap.Element)13 CalendarItem (com.zimbra.cs.mailbox.CalendarItem)13 Account (com.zimbra.cs.account.Account)12 Document (com.zimbra.cs.mailbox.Document)12 ItemId (com.zimbra.cs.service.util.ItemId)11 HashMap (java.util.HashMap)11 ZMailbox (com.zimbra.client.ZMailbox)9 Contact (com.zimbra.cs.mailbox.Contact)9 HashSet (java.util.HashSet)9