Search in sources :

Example 41 with CalendarItem

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

the class CalendarRequest method echoAddedInvite.

protected static Element echoAddedInvite(Element parent, ItemIdFormatter ifmt, OperationContext octxt, Mailbox mbox, AddInviteData aid, int maxSize, boolean wantHtml, boolean neuter) throws ServiceException {
    CalendarItem calItem = mbox.getCalendarItemById(octxt, aid.calItemId);
    Invite inv = calItem.getInvite(aid.invId, aid.compNum);
    String recurIdZ = null;
    if (inv != null && inv.getRecurId() != null)
        recurIdZ = inv.getRecurId().getDtZ();
    ItemId iid = new ItemId(calItem, aid.invId);
    Element echoElem = parent.addElement(MailConstants.E_CAL_ECHO);
    ToXML.encodeInviteAsMP(echoElem, ifmt, octxt, calItem, recurIdZ, iid, null, maxSize, wantHtml, neuter, null, false, false);
    return echoElem;
}
Also used : CalendarItem(com.zimbra.cs.mailbox.CalendarItem) Element(com.zimbra.common.soap.Element) ItemId(com.zimbra.cs.service.util.ItemId) Invite(com.zimbra.cs.mailbox.calendar.Invite)

Example 42 with CalendarItem

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

the class CompleteTaskInstance 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);
    ItemId iid = new ItemId(request.getAttribute(MailConstants.A_ID), zsc);
    Element exceptElem = request.getElement(MailConstants.E_CAL_EXCEPTION_ID);
    mbox.lock.lock();
    try {
        CalendarItem calItem = mbox.getCalendarItemById(octxt, iid.getId());
        if (calItem == null) {
            throw MailServiceException.NO_SUCH_CALITEM(iid.toString(), "Could not find calendar item");
        }
        if (!(calItem instanceof Task)) {
            throw MailServiceException.NO_SUCH_CALITEM(iid.toString(), "Calendar item is not a task");
        }
        Invite inv = calItem.getDefaultInviteOrNull();
        if (inv == null) {
            throw MailServiceException.NO_SUCH_CALITEM(iid.toString(), "No default invite found");
        }
        if (!inv.isRecurrence()) {
            throw ServiceException.INVALID_REQUEST("Task is not a recurring task", null);
        }
        ParsedDateTime recurStart = inv.getStartTime();
        if (recurStart == null) {
            throw ServiceException.INVALID_REQUEST("Recurring task is missing start time", null);
        }
        // the instance being marked complete
        TimeZoneMap tzmap = inv.getTimeZoneMap();
        Element tzElem = request.getOptionalElement(MailConstants.E_CAL_TZ);
        ICalTimeZone tz = null;
        if (tzElem != null) {
            tz = CalendarUtils.parseTzElement(tzElem);
            tzmap.add(tz);
        }
        ParsedDateTime exceptDt = CalendarUtils.parseDateTime(exceptElem, tzmap);
        if (exceptDt.getUtcTime() != recurStart.getUtcTime()) {
            throw MailServiceException.INVITE_OUT_OF_DATE(iid.toString());
        }
        // Create a new single-instance task for completed date.
        Invite completed = createCompletedInstanceInvite(inv, exceptDt);
        mbox.addInvite(octxt, completed, calItem.getFolderId());
        // Update recurrence's start date to the next instance start date.
        long oldStart = recurStart.getUtcTime();
        long newStart = -1;
        Collection<Instance> instances = calItem.expandInstances(oldStart, Long.MAX_VALUE, false);
        for (Instance inst : instances) {
            if (inst.getStart() > oldStart) {
                newStart = inst.getStart();
                break;
            }
        }
        if (newStart != -1) {
            // Update DTSTART to newStart.
            ParsedDateTime newStartDt = ParsedDateTime.fromUTCTime(newStart);
            newStartDt.toTimeZone(inv.getStartTime().getTimeZone());
            newStartDt.setHasTime(recurStart.hasTime());
            // Update DUE.
            ParsedDuration dur = inv.getEffectiveDuration();
            if (dur != null) {
                ParsedDateTime due = newStartDt.add(dur);
                inv.setDtEnd(due);
            }
            inv.setDtStart(newStartDt);
            inv.setSeqNo(inv.getSeqNo() + 1);
            inv.setDtStamp(System.currentTimeMillis());
            mbox.addInvite(octxt, inv, calItem.getFolderId());
        } else {
            // No more instance left.  Delete the recurring task.
            mbox.delete(octxt, calItem.getId(), calItem.getType());
        }
    } finally {
        mbox.lock.release();
    }
    // response
    Element response = getResponseElement(zsc);
    return response;
}
Also used : OperationContext(com.zimbra.cs.mailbox.OperationContext) Task(com.zimbra.cs.mailbox.Task) Instance(com.zimbra.cs.mailbox.CalendarItem.Instance) ParsedDuration(com.zimbra.common.calendar.ParsedDuration) Element(com.zimbra.common.soap.Element) ItemId(com.zimbra.cs.service.util.ItemId) CalendarItem(com.zimbra.cs.mailbox.CalendarItem) Mailbox(com.zimbra.cs.mailbox.Mailbox) ZimbraSoapContext(com.zimbra.soap.ZimbraSoapContext) TimeZoneMap(com.zimbra.common.calendar.TimeZoneMap) ParsedDateTime(com.zimbra.common.calendar.ParsedDateTime) Invite(com.zimbra.cs.mailbox.calendar.Invite) ICalTimeZone(com.zimbra.common.calendar.ICalTimeZone)

Example 43 with CalendarItem

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

the class CreateCalendarItemException method handle.

@Override
public Element handle(Element request, Map<String, Object> context) throws ServiceException {
    ZimbraSoapContext zsc = getZimbraSoapContext(context);
    Account acct = getRequestedAccount(zsc);
    Mailbox mbox = getRequestedMailbox(zsc);
    OperationContext octxt = getOperationContext(zsc, context);
    ItemIdFormatter ifmt = new ItemIdFormatter(zsc);
    // proxy handling
    Element msgElem = request.getElement(MailConstants.E_MSG);
    String folderStr = msgElem.getAttribute(MailConstants.A_FOLDER, null);
    ItemId iid = new ItemId(request.getAttribute(MailConstants.A_ID), zsc);
    if (!iid.belongsTo(acct)) {
        // Proxy it.
        if (folderStr != null) {
            // make sure that the folder ID is fully qualified
            ItemId folderFQ = new ItemId(folderStr, zsc);
            msgElem.addAttribute(MailConstants.A_FOLDER, folderFQ.toString());
        }
        return proxyRequest(request, context, iid.getAccountId());
    }
    // Check if moving to a different mailbox.
    boolean isInterMboxMove = false;
    ItemId iidFolder = null;
    if (folderStr != null) {
        iidFolder = new ItemId(folderStr, zsc);
        isInterMboxMove = !iidFolder.belongsTo(mbox);
    }
    int compNum = (int) request.getAttributeLong(MailConstants.E_INVITE_COMPONENT);
    MailSendQueue sendQueue = new MailSendQueue();
    Element response = getResponseElement(zsc);
    mbox.lock.lock();
    try {
        CalendarItem calItem = mbox.getCalendarItemById(octxt, iid.getId());
        if (calItem == null)
            throw MailServiceException.NO_SUCH_CALITEM(iid.getId(), " for CreateCalendarItemExceptionRequest(" + iid + "," + compNum + ")");
        // Reject the request if calendar item is under trash or is being moved to trash.
        if (calItem.inTrash())
            throw ServiceException.INVALID_REQUEST("cannot modify a calendar item under trash", null);
        if (!isInterMboxMove && iidFolder != null) {
            if (iidFolder.getId() != calItem.getFolderId()) {
                Folder destFolder = mbox.getFolderById(octxt, iidFolder.getId());
                if (destFolder.inTrash())
                    throw ServiceException.INVALID_REQUEST("cannot combine with a move to trash", null);
            }
        }
        // Conflict detection.  Do it only if requested by client.  (for backward compat)
        int modSeq = (int) request.getAttributeLong(MailConstants.A_MODIFIED_SEQUENCE, 0);
        int revision = (int) request.getAttributeLong(MailConstants.A_REVISION, 0);
        if (modSeq != 0 && revision != 0 && (modSeq < calItem.getModifiedSequence() || revision < calItem.getSavedSequence()))
            throw MailServiceException.INVITE_OUT_OF_DATE(iid.toString());
        Invite inv = calItem.getInvite(iid.getSubpartId(), compNum);
        if (inv == null)
            throw MailServiceException.INVITE_OUT_OF_DATE(iid.toString());
        if (inv.hasRecurId())
            throw MailServiceException.INVITE_OUT_OF_DATE("Invite id=" + ifmt.formatItemId(iid) + " comp=" + compNum + " is not the default invite");
        if (!calItem.isRecurring())
            throw ServiceException.INVALID_REQUEST("CalendarItem " + calItem.getId() + " is not a recurring calendar item", null);
        CreateCalendarItemExceptionInviteParser parser = new CreateCalendarItemExceptionInviteParser(calItem.getUid(), inv, sendQueue);
        CalSendData dat = handleMsgElement(zsc, octxt, msgElem, acct, mbox, parser);
        dat.mDontNotifyAttendees = isInterMboxMove;
        int folderId = calItem.getFolderId();
        if (!isInterMboxMove && iidFolder != null)
            folderId = iidFolder.getId();
        // trace logging
        if (!dat.mInvite.hasRecurId())
            ZimbraLog.calendar.info("<CreateCalendarItemException> id=%d, folderId=%d, subject=\"%s\", UID=%s", iid.getId(), folderId, dat.mInvite.isPublic() ? dat.mInvite.getName() : "(private)", dat.mInvite.getUid());
        else
            ZimbraLog.calendar.info("<CreateCalendarItemException> id=%d, folderId=%d, subject=\"%s\", UID=%s, recurId=%s", iid.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("CreateCalendarItemException");
        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.
            // Set neverSent to false, but only if it isn't already set to true on the series.
            // !series.isNeverSent() ? false : true ==> series.isNeverSent()
            dat.mInvite.setNeverSent(inv.isNeverSent());
        }
        boolean forceSend = request.getAttributeBool(MailConstants.A_CAL_FORCESEND, true);
        sendCalendarMessage(zsc, octxt, folderId, acct, mbox, dat, response, true, forceSend, sendQueue);
        boolean echo = request.getAttributeBool(MailConstants.A_CAL_ECHO, false);
        if (echo && dat.mAddInvData != null) {
            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);
            echoAddedInvite(response, ifmt, octxt, mbox, dat.mAddInvData, maxSize, wantHTML, neuter);
        }
    } finally {
        mbox.lock.release();
        sendQueue.send();
    }
    // Inter-mailbox move if necessary.
    if (isInterMboxMove) {
        CalendarItem calItem = mbox.getCalendarItemById(octxt, iid.getId());
        List<Integer> ids = new ArrayList<Integer>(1);
        ids.add(calItem.getId());
        ItemActionHelper.MOVE(octxt, mbox, zsc.getResponseProtocol(), ids, calItem.getType(), null, iidFolder);
    }
    return response;
}
Also used : OperationContext(com.zimbra.cs.mailbox.OperationContext) Account(com.zimbra.cs.account.Account) Address(javax.mail.Address) ItemIdFormatter(com.zimbra.cs.service.util.ItemIdFormatter) MessagingException(javax.mail.MessagingException) Element(com.zimbra.common.soap.Element) ArrayList(java.util.ArrayList) Folder(com.zimbra.cs.mailbox.Folder) ItemId(com.zimbra.cs.service.util.ItemId) CalendarItem(com.zimbra.cs.mailbox.CalendarItem) Mailbox(com.zimbra.cs.mailbox.Mailbox) ZimbraSoapContext(com.zimbra.soap.ZimbraSoapContext) Invite(com.zimbra.cs.mailbox.calendar.Invite)

Example 44 with CalendarItem

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

the class ContentServlet method getCommand.

private void getCommand(HttpServletRequest req, HttpServletResponse resp, AuthToken token) throws ServletException, IOException {
    ItemId iid = null;
    try {
        iid = new ItemId(req.getParameter(PARAM_MSGID), (String) null);
    } catch (ServiceException e) {
        resp.sendError(HttpServletResponse.SC_BAD_REQUEST, L10nUtil.getMessage(MsgKey.errInvalidId, req));
        return;
    }
    String part = req.getParameter(PARAM_PART);
    String fmt = req.getParameter(PARAM_FORMAT);
    String dumpsterParam = req.getParameter(PARAM_DUMPSTER);
    boolean fromDumpster = dumpsterParam != null && !dumpsterParam.equals("0") && !dumpsterParam.equalsIgnoreCase("false");
    try {
        // need to proxy the fetch if the mailbox lives on another server
        if (!iid.isLocal()) {
            // wrong server; proxy to the right one...
            proxyServletRequest(req, resp, iid.getAccountId());
            return;
        }
        String authId = token.getAccountId();
        String accountId = iid.getAccountId() != null ? iid.getAccountId() : authId;
        AccountUtil.addAccountToLogContext(Provisioning.getInstance(), accountId, ZimbraLog.C_NAME, ZimbraLog.C_ID, token);
        if (!accountId.equalsIgnoreCase(authId))
            ZimbraLog.addToContext(ZimbraLog.C_AID, authId);
        Mailbox mbox = MailboxManager.getInstance().getMailboxByAccountId(accountId);
        if (mbox == null) {
            resp.sendError(HttpServletResponse.SC_BAD_REQUEST, L10nUtil.getMessage(MsgKey.errMailboxNotFound, req));
            return;
        }
        ZimbraLog.addMboxToContext(mbox.getId());
        MailItem item = mbox.getItemById(new OperationContext(token), iid.getId(), MailItem.Type.UNKNOWN, fromDumpster);
        if (item == null) {
            resp.sendError(HttpServletResponse.SC_BAD_REQUEST, L10nUtil.getMessage(MsgKey.errMessageNotFound, req));
            return;
        }
        try {
            if (part == null) {
                // they want the entire message...
                boolean sync = "1".equals(req.getParameter(PARAM_SYNC));
                StringBuffer hdr = new StringBuffer();
                if (sync) {
                    // for sync, return metadata as headers to avoid extra SOAP round-trips
                    resp.addHeader("X-Zimbra-Tags", TagUtil.getTagIdString(item));
                    resp.addHeader("X-Zimbra-Tag-Names", TagUtil.encodeTags(item.getTags()));
                    resp.addHeader("X-Zimbra-Flags", item.getFlagString());
                    resp.addHeader("X-Zimbra-Received", Long.toString(item.getDate()));
                    resp.addHeader("X-Zimbra-Modified", Long.toString(item.getChangeDate()));
                    // also return metadata inline in the message content for now
                    hdr.append("X-Zimbra-Tags: ").append(TagUtil.getTagIdString(item)).append("\n");
                    hdr.append("X-Zimbra-Tag-Names: ").append(TagUtil.encodeTags(item.getTags()));
                    hdr.append("X-Zimbra-Flags: ").append(item.getFlagString()).append("\n");
                    hdr.append("X-Zimbra-Received: ").append(item.getDate()).append("\n");
                    hdr.append("X-Zimbra-Modified: ").append(item.getChangeDate()).append("\n");
                }
                if (item instanceof Message) {
                    Message msg = (Message) item;
                    if (sync) {
                        resp.addHeader("X-Zimbra-Conv", Integer.toString(msg.getConversationId()));
                        hdr.append("X-Zimbra-Conv: ").append(msg.getConversationId()).append("\n");
                        resp.getOutputStream().write(hdr.toString().getBytes());
                    }
                    resp.setContentType(MimeConstants.CT_TEXT_PLAIN);
                    InputStream is = msg.getContentStream();
                    ByteUtil.copy(is, true, resp.getOutputStream(), false);
                } else if (item instanceof CalendarItem) {
                    CalendarItem calItem = (CalendarItem) item;
                    if (sync) {
                        resp.getOutputStream().write(hdr.toString().getBytes());
                    }
                    resp.setContentType(MimeConstants.CT_TEXT_PLAIN);
                    if (iid.hasSubpart()) {
                        int invId = iid.getSubpartId();
                        MimeMessage mm = calItem.getSubpartMessage(invId);
                        if (mm == null) {
                            // Backward compatibility for pre-5.0.16 ZDesktop: Build a MIME message on the fly.
                            Invite[] invs = calItem.getInvites(invId);
                            if (invs != null && invs.length > 0) {
                                Invite invite = invs[0];
                                mm = CalendarMailSender.createCalendarMessage(invite);
                            }
                        }
                        if (mm != null)
                            mm.writeTo(resp.getOutputStream());
                    } else {
                        InputStream is = calItem.getRawMessage();
                        if (is != null)
                            ByteUtil.copy(is, true, resp.getOutputStream(), false);
                    }
                }
                return;
            } else {
                MimePart mp = null;
                if (item instanceof Message) {
                    mp = getMimePart((Message) item, part);
                } else {
                    CalendarItem calItem = (CalendarItem) item;
                    if (iid.hasSubpart()) {
                        MimeMessage mbp = calItem.getSubpartMessage(iid.getSubpartId());
                        if (mbp != null)
                            mp = Mime.getMimePart(mbp, part);
                    } else {
                        mp = getMimePart(calItem, part);
                    }
                }
                if (mp != null) {
                    String contentType = mp.getContentType();
                    if (contentType == null) {
                        contentType = MimeConstants.CT_APPLICATION_OCTET_STREAM;
                    }
                    if (contentType.toLowerCase().startsWith(MimeConstants.CT_TEXT_HTML) && (FORMAT_DEFANGED_HTML.equals(fmt) || FORMAT_DEFANGED_HTML_NOT_IMAGES.equals(fmt))) {
                        sendbackDefangedHtml(mp, contentType, resp, fmt);
                    } else {
                        if (!isTrue(Provisioning.A_zimbraAttachmentsViewInHtmlOnly, mbox.getAccountId())) {
                            sendbackOriginalDoc(mp, contentType, req, resp);
                        } else {
                            req.setAttribute(ATTR_MIMEPART, mp);
                            req.setAttribute(ATTR_MSGDIGEST, item.getDigest());
                            req.setAttribute(ATTR_CONTENTURL, req.getRequestURL().toString());
                            RequestDispatcher dispatcher = getServletContext().getRequestDispatcher(CONVERSION_PATH);
                            dispatcher.forward(req, resp);
                        }
                    }
                    return;
                }
                resp.sendError(HttpServletResponse.SC_BAD_REQUEST, L10nUtil.getMessage(MsgKey.errPartNotFound, req));
            }
        } catch (MessagingException e) {
            resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage());
        }
    } catch (NoSuchItemException e) {
        resp.sendError(HttpServletResponse.SC_NOT_FOUND, L10nUtil.getMessage(MsgKey.errNoSuchItem, req));
    } catch (ServiceException e) {
        returnError(resp, e);
    } catch (HttpException e) {
        throw new IOException("Unknown error", e);
    } finally {
        ZimbraLog.clearContext();
    }
/*
         out.println("hello world "+req.getParameter("id"));
         out.println("path info: "+req.getPathInfo());
         out.println("pathtrans: "+req.getPathTranslated());
         */
}
Also used : OperationContext(com.zimbra.cs.mailbox.OperationContext) Message(com.zimbra.cs.mailbox.Message) MimeMessage(javax.mail.internet.MimeMessage) MessagingException(javax.mail.MessagingException) ByteArrayInputStream(java.io.ByteArrayInputStream) InputStream(java.io.InputStream) IOException(java.io.IOException) ItemId(com.zimbra.cs.service.util.ItemId) NoSuchItemException(com.zimbra.cs.mailbox.MailServiceException.NoSuchItemException) RequestDispatcher(javax.servlet.RequestDispatcher) CalendarItem(com.zimbra.cs.mailbox.CalendarItem) MailItem(com.zimbra.cs.mailbox.MailItem) ServiceException(com.zimbra.common.service.ServiceException) Mailbox(com.zimbra.cs.mailbox.Mailbox) MimeMessage(javax.mail.internet.MimeMessage) MimePart(javax.mail.internet.MimePart) HttpException(org.apache.http.HttpException) Invite(com.zimbra.cs.mailbox.calendar.Invite)

Example 45 with CalendarItem

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

the class ItemActionHelper method executeRemote.

private ItemActionResult executeRemote() throws ServiceException, IOException, HttpException {
    Account target = Provisioning.getInstance().get(Key.AccountBy.id, mIidFolder.getAccountId());
    AuthToken at = getAuthToken();
    String pxyAuthToken = Provisioning.onLocalServer(target) ? null : at.getProxyAuthToken();
    ZAuthToken zat = null;
    if (pxyAuthToken == null) {
        zat = at.toZAuthToken();
        zat.resetProxyAuthToken();
    } else {
        zat = new ZAuthToken(pxyAuthToken);
    }
    ZMailbox.Options zoptions = new ZMailbox.Options(zat, AccountUtil.getSoapUri(target));
    zoptions.setNoSession(true);
    zoptions.setTargetAccount(target.getId());
    zoptions.setTargetAccountBy(Key.AccountBy.id);
    ZMailbox zmbx = ZMailbox.getMailbox(zoptions);
    zmbx.setName(target.getName());
    /* need this when logging in using another user's auth */
    // check for mountpoints before going any further...
    ZFolder zfolder = zmbx.getFolderById(mIidFolder.toString(mAuthenticatedAccount));
    if (zfolder instanceof ZMountpoint) {
        ItemId iidTarget = new ItemId(((ZMountpoint) zfolder).getCanonicalRemoteId(), mAuthenticatedAccount.getId());
        if (!mIidFolder.equals(iidTarget)) {
            mIidFolder = iidTarget;
            if (++mHopCount > com.zimbra.soap.ZimbraSoapContext.MAX_HOP_COUNT)
                throw MailServiceException.TOO_MANY_HOPS(mIidRequestedFolder);
            schedule();
            return ItemActionResult.create(mOperation);
        }
    }
    boolean deleteOriginal = mOperation != Op.COPY;
    String folderStr = mIidFolder.toString();
    List<String> createdIds = new ArrayList<String>(itemIds.length);
    List<String> nonExistentIds = new ArrayList<String>();
    boolean toSpam = mIidFolder.getId() == Mailbox.ID_FOLDER_SPAM;
    boolean toMailbox = !toSpam && mIidFolder.getId() != Mailbox.ID_FOLDER_TRASH;
    for (MailItem item : mMailbox.getItemById(mOpCtxt, itemIds, type)) {
        if (item == null) {
            continue;
        }
        List<Message> msgs = null;
        if (item instanceof Conversation) {
            msgs = mMailbox.getMessagesByConversation(mOpCtxt, item.getId(), SortBy.DATE_ASC, -1);
        }
        if (deleteOriginal) {
            if (msgs != null) {
                // determine which of the conversation's component messages are actually able to be moved
                boolean permDenied = false;
                for (Iterator<Message> it = msgs.iterator(); it.hasNext(); ) {
                    Message msg = it.next();
                    if (!TargetConstraint.checkItem(mTargetConstraint, msg)) {
                        it.remove();
                    } else if (!canDelete(msg)) {
                        it.remove();
                        permDenied = true;
                    }
                }
                // stop here if no messages would be moved...
                if (msgs.isEmpty()) {
                    if (permDenied) {
                        throw ServiceException.PERM_DENIED("cannot delete any messages in " + item.getType() + " " + item.getId());
                    }
                    // all messages were excluded by the TargetConstraint, so there's no failure...
                    continue;
                }
            } else {
                if (!canDelete(item)) {
                    throw ServiceException.PERM_DENIED("cannot delete existing copy of " + item.getType() + " " + item.getId());
                }
            }
        }
        boolean fromSpam = item.inSpam();
        if ((fromSpam && toMailbox) || (!fromSpam && toSpam)) {
            try {
                Folder dest = mMailbox.getFolderById(mOpCtxt, mIidFolder.getId());
                SpamReport report = new SpamReport(toSpam, "remote " + mOperation, dest.getPath());
                Folder source = mMailbox.getFolderById(mOpCtxt, item.getFolderId());
                report.setSourceFolderPath(source.getPath());
                report.setDestAccountName(target.getName());
                SpamHandler.getInstance().handle(mOpCtxt, mMailbox, item.getId(), item.getType(), report);
            } catch (OutOfMemoryError e) {
                Zimbra.halt("out of memory", e);
            } catch (Throwable t) {
                ZimbraLog.mailop.info("could not train spam filter: " + new ItemId(item).toString(), t);
            }
        }
        // since we can't apply tags to a remote object, hardwiring "tags" to null below...
        String flags = (mOperation == Op.UPDATE && mFlags != null ? mFlags : item.getFlagString());
        String name = ((mOperation == Op.RENAME || mOperation == Op.UPDATE) && mName != null ? mName : item.getName());
        String createdId = null;
        InputStream in = null;
        switch(item.getType()) {
            case CONTACT:
                Contact ct = (Contact) item;
                Map<String, ZMailbox.ZAttachmentInfo> attachments = new HashMap<String, ZMailbox.ZAttachmentInfo>();
                for (Contact.Attachment att : ct.getAttachments()) {
                    String attachmentId = zmbx.uploadAttachment(att.getFilename(), att.getContent(), att.getContentType(), 0);
                    ZMailbox.ZAttachmentInfo info = new ZMailbox.ZAttachmentInfo().setAttachmentId(attachmentId);
                    attachments.put(att.getName(), info);
                }
                Map<String, String> fields = ct.getFields();
                Map<String, String> members = new HashMap<String, String>();
                for (String key : fields.keySet()) {
                    if (ContactConstants.A_groupMember.equals(key)) {
                        String memberEncoded = fields.get(key);
                        ContactGroup group = ContactGroup.init(memberEncoded);
                        for (Member m : group.getMembers()) {
                            members.put(m.getValue(), m.getType().getSoapEncoded());
                        }
                        break;
                    }
                }
                fields.remove(ContactConstants.A_groupMember);
                ZContact contact = zmbx.createContact(folderStr, null, fields, attachments, members);
                createdId = contact.getId();
                createdIds.add(createdId);
                break;
            case MESSAGE:
                try {
                    in = StoreManager.getInstance().getContent(item.getBlob());
                    createdId = zmbx.addMessage(folderStr, flags, (String) null, item.getDate(), in, item.getSize(), true);
                } finally {
                    ByteUtil.closeStream(in);
                }
                createdIds.add(createdId);
                break;
            case VIRTUAL_CONVERSATION:
            case CONVERSATION:
                for (Message msg : msgs) {
                    flags = (mOperation == Op.UPDATE && mFlags != null ? mFlags : msg.getFlagString());
                    try {
                        in = StoreManager.getInstance().getContent(msg.getBlob());
                        createdId = zmbx.addMessage(folderStr, flags, (String) null, msg.getDate(), in, msg.getSize(), true);
                    } finally {
                        ByteUtil.closeStream(in);
                    }
                    createdIds.add(createdId);
                }
                break;
            case DOCUMENT:
                Document doc = (Document) item;
                SoapHttpTransport transport = new SoapHttpTransport(zoptions.getUri());
                try {
                    in = StoreManager.getInstance().getContent(doc.getBlob());
                    String uploadId = zmbx.uploadContentAsStream(name, in, doc.getContentType(), doc.getSize(), 4000, true);
                    // instead of using convenience method from ZMailbox
                    // we need to hand marshall the request and set the
                    // response protocol explicitly to what was requested
                    // from the client.
                    Element req = new XMLElement(MailConstants.SAVE_DOCUMENT_REQUEST);
                    Element edoc = req.addUniqueElement(MailConstants.E_DOC);
                    edoc.addAttribute(MailConstants.A_NAME, name);
                    edoc.addAttribute(MailConstants.A_FOLDER, folderStr);
                    edoc.addAttribute(MailConstants.A_FLAGS, flags);
                    Element upload = edoc.addNonUniqueElement(MailConstants.E_UPLOAD);
                    upload.addAttribute(MailConstants.A_ID, uploadId);
                    transport.setResponseProtocol(mResponseProtocol);
                    transport.setAuthToken(zat);
                    Element response = transport.invoke(req);
                    createdId = response.getElement(MailConstants.E_DOC).getAttribute(MailConstants.A_ID);
                } finally {
                    ByteUtil.closeStream(in);
                    transport.shutdown();
                }
                createdIds.add(createdId);
                break;
            case APPOINTMENT:
            case TASK:
                CalendarItem cal = (CalendarItem) item;
                // private calendar item may not be moved by non-owner unless permission was granted
                if (!cal.isPublic()) {
                    boolean asAdmin = mOpCtxt != null ? mOpCtxt.isUsingAdminPrivileges() : false;
                    if (!cal.allowPrivateAccess(mAuthenticatedAccount, asAdmin))
                        throw ServiceException.PERM_DENIED("you do not have permission to move/copy a private calendar item from the current folder/mailbox");
                }
                // Move the item to remote mailbox using SetAppointmentRequest/SetTaskRequest.
                QName qname = (item.getType() == MailItem.Type.TASK ? MailConstants.SET_TASK_REQUEST : MailConstants.SET_APPOINTMENT_REQUEST);
                Element request = new Element.XMLElement(qname).addAttribute(MailConstants.A_FOLDER, folderStr).addAttribute(MailConstants.A_FLAGS, flags);
                ToXML.encodeAlarmTimes(request, cal);
                Invite invDefault = cal.getDefaultInviteOrNull();
                // Takeover as organizer if we're doing a MOVE and source mailbox is the organizer.
                // Don't takeover in a COPY operation.
                boolean takeoverAsOrganizer = false;
                boolean blockMove = false;
                if (Op.MOVE.equals(mOperation)) {
                    Invite inv = invDefault;
                    if (inv == null) {
                        // no default invite; let's use the first invite
                        Invite[] invs = cal.getInvites();
                        if (invs != null && invs.length > 0)
                            inv = invs[0];
                    }
                    takeoverAsOrganizer = inv != null && inv.isOrganizer();
                    blockMove = takeoverAsOrganizer && inv.hasOtherAttendees();
                }
                if (blockMove) {
                    throw MailServiceException.INVALID_REQUEST("This operation requires change of organizer and it is not permitted", null);
                }
                if (invDefault != null) {
                    addCalendarPart(request.addUniqueElement(MailConstants.A_DEFAULT), cal, invDefault, zmbx, target, takeoverAsOrganizer);
                }
                for (Invite inv : cal.getInvites()) {
                    if (inv == null || inv == invDefault)
                        continue;
                    String elem = inv.isCancel() ? MailConstants.E_CAL_CANCEL : MailConstants.E_CAL_EXCEPT;
                    addCalendarPart(request.addNonUniqueElement(elem), cal, inv, zmbx, target, takeoverAsOrganizer);
                }
                ToXML.encodeCalendarReplies(request, cal);
                createdId = zmbx.invoke(request).getAttribute(MailConstants.A_CAL_ID);
                createdIds.add(createdId);
                break;
            default:
                throw MailServiceException.CANNOT_COPY(item.getId());
        }
        try {
            if (deleteOriginal && !mIdFormatter.formatItemId(item).equals(createdId)) {
                List<Integer> nonExistentItems = new ArrayList<Integer>();
                if (msgs == null) {
                    mMailbox.delete(mOpCtxt, new int[] { item.getId() }, item.getType(), null, nonExistentItems);
                } else {
                    for (Message msg : msgs) {
                        mMailbox.delete(mOpCtxt, new int[] { msg.getId() }, msg.getType(), null, nonExistentItems);
                    }
                }
                for (Integer id : nonExistentItems) {
                    nonExistentIds.add(id.toString());
                }
            }
        } catch (ServiceException e) {
            if (e.getCode() != ServiceException.PERM_DENIED)
                throw e;
            // something funky happened permissions-wise between the getEffectivePermissions check and here...
            ZimbraLog.misc.info("could not delete original item " + item.getId() + "; treating operation as a copy instead");
        }
    }
    ItemActionResult result = ItemActionResult.create(mOperation);
    if (Op.HARD_DELETE.equals(mOperation)) {
        ((DeleteActionResult) result).setNonExistentIds(nonExistentIds);
    } else if (Op.COPY.equals(mOperation)) {
        ((CopyActionResult) result).setCreatedIds(createdIds);
    }
    for (int itemId : itemIds) {
        result.appendSuccessId(Integer.toString(itemId));
    }
    return result;
}
Also used : ZMountpoint(com.zimbra.client.ZMountpoint) Account(com.zimbra.cs.account.Account) Message(com.zimbra.cs.mailbox.Message) MimeMessage(javax.mail.internet.MimeMessage) HashMap(java.util.HashMap) Element(com.zimbra.common.soap.Element) XMLElement(com.zimbra.common.soap.Element.XMLElement) ArrayList(java.util.ArrayList) Conversation(com.zimbra.cs.mailbox.Conversation) Folder(com.zimbra.cs.mailbox.Folder) ZFolder(com.zimbra.client.ZFolder) Document(com.zimbra.cs.mailbox.Document) XMLElement(com.zimbra.common.soap.Element.XMLElement) ZAuthToken(com.zimbra.common.auth.ZAuthToken) ItemId(com.zimbra.cs.service.util.ItemId) CalendarItem(com.zimbra.cs.mailbox.CalendarItem) ZMailbox(com.zimbra.client.ZMailbox) ZFolder(com.zimbra.client.ZFolder) SoapHttpTransport(com.zimbra.common.soap.SoapHttpTransport) Member(com.zimbra.cs.mailbox.ContactGroup.Member) InputStream(java.io.InputStream) QName(org.dom4j.QName) ZMountpoint(com.zimbra.client.ZMountpoint) TargetConstraint(com.zimbra.cs.mailbox.MailItem.TargetConstraint) Mountpoint(com.zimbra.cs.mailbox.Mountpoint) ZContact(com.zimbra.client.ZContact) Contact(com.zimbra.cs.mailbox.Contact) MailItem(com.zimbra.cs.mailbox.MailItem) ServiceException(com.zimbra.common.service.ServiceException) MailServiceException(com.zimbra.cs.mailbox.MailServiceException) SpamReport(com.zimbra.cs.service.util.SpamHandler.SpamReport) AuthToken(com.zimbra.cs.account.AuthToken) ZAuthToken(com.zimbra.common.auth.ZAuthToken) ContactGroup(com.zimbra.cs.mailbox.ContactGroup) Invite(com.zimbra.cs.mailbox.calendar.Invite) ZContact(com.zimbra.client.ZContact)

Aggregations

CalendarItem (com.zimbra.cs.mailbox.CalendarItem)56 Mailbox (com.zimbra.cs.mailbox.Mailbox)36 Element (com.zimbra.common.soap.Element)27 OperationContext (com.zimbra.cs.mailbox.OperationContext)24 Invite (com.zimbra.cs.mailbox.calendar.Invite)23 ItemId (com.zimbra.cs.service.util.ItemId)22 Account (com.zimbra.cs.account.Account)19 ZimbraSoapContext (com.zimbra.soap.ZimbraSoapContext)17 ServiceException (com.zimbra.common.service.ServiceException)15 MailItem (com.zimbra.cs.mailbox.MailItem)14 MailServiceException (com.zimbra.cs.mailbox.MailServiceException)13 Message (com.zimbra.cs.mailbox.Message)12 ItemIdFormatter (com.zimbra.cs.service.util.ItemIdFormatter)11 Folder (com.zimbra.cs.mailbox.Folder)9 RecurId (com.zimbra.cs.mailbox.calendar.RecurId)9 Appointment (com.zimbra.cs.mailbox.Appointment)8 ArrayList (java.util.ArrayList)8 MimeMessage (javax.mail.internet.MimeMessage)8 ParsedDateTime (com.zimbra.common.calendar.ParsedDateTime)7 TimeZoneMap (com.zimbra.common.calendar.TimeZoneMap)5