Search in sources :

Example 51 with MailItem

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

the class VcfFormatter method formatCallback.

@Override
public void formatCallback(UserServletContext context) throws IOException, ServiceException {
    Charset charset = context.getCharset();
    Iterator<? extends MailItem> iterator = null;
    try {
        iterator = getMailItems(context, getDefaultStartTime(), getDefaultEndTime(), Integer.MAX_VALUE);
        String filename = context.target instanceof Contact ? ((Contact) context.target).getFileAsString() : "contacts";
        String cd = HttpUtil.createContentDisposition(context.req, Part.ATTACHMENT, filename + ".vcf");
        context.resp.addHeader("Content-Disposition", cd);
        // for backward compatibility
        context.resp.setContentType(MimeConstants.CT_TEXT_VCARD_LEGACY);
        context.resp.setCharacterEncoding(charset.name());
        int count = 0;
        while (iterator.hasNext()) {
            MailItem item = iterator.next();
            if (!(item instanceof Contact))
                continue;
            VCard vcf = VCard.formatContact((Contact) item);
            context.resp.getOutputStream().write(vcf.getFormatted().getBytes(charset));
            count++;
        }
    } finally {
        if (iterator instanceof QueryResultIterator)
            ((QueryResultIterator) iterator).finished();
    }
}
Also used : MailItem(com.zimbra.cs.mailbox.MailItem) Charset(java.nio.charset.Charset) Contact(com.zimbra.cs.mailbox.Contact)

Example 52 with MailItem

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

the class XmlFormatter method formatCallback.

@Override
public void formatCallback(UserServletContext context) throws ServiceException, IOException {
    Element elt = getFactory().createElement("items");
    ItemIdFormatter ifmt = new ItemIdFormatter(context.getAuthAccount(), context.targetMailbox, false);
    Iterator<? extends MailItem> iterator = null;
    try {
        long start = context.getStartTime();
        long end = context.getEndTime();
        boolean hasTimeRange = start != TIME_UNSPECIFIED && end != TIME_UNSPECIFIED;
        iterator = getMailItems(context, start, end, Integer.MAX_VALUE);
        // this is lame
        while (iterator.hasNext()) {
            MailItem item = iterator.next();
            if (item instanceof CalendarItem && hasTimeRange) {
                // Skip appointments that have no instance in the time range.
                CalendarItem calItem = (CalendarItem) item;
                Collection<Instance> instances = calItem.expandInstances(start, end, false);
                if (instances.isEmpty())
                    continue;
            }
            ToXML.encodeItem(elt, ifmt, context.opContext, item, ToXML.NOTIFY_FIELDS);
        }
        context.resp.getOutputStream().write(elt.toUTF8());
    } finally {
        if (iterator instanceof QueryResultIterator)
            ((QueryResultIterator) iterator).finished();
    }
}
Also used : CalendarItem(com.zimbra.cs.mailbox.CalendarItem) MailItem(com.zimbra.cs.mailbox.MailItem) ItemIdFormatter(com.zimbra.cs.service.util.ItemIdFormatter) Instance(com.zimbra.cs.mailbox.CalendarItem.Instance) Element(com.zimbra.common.soap.Element)

Example 53 with MailItem

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

the class OctopusPatchFormatter method saveCallback.

// Formatter API
@Override
public void saveCallback(UserServletContext context, String contentType, Folder folder, String filename) throws IOException, ServiceException, UserServletException {
    log.info("Uploading patch for " + filename);
    if (filename == null) {
        throw new UserServletException(HttpServletResponse.SC_BAD_REQUEST, "Missing filename");
    }
    MailItem item = null;
    Mailbox mbox = folder.getMailbox();
    try {
        item = mbox.getItemByPath(context.opContext, filename, folder.getId());
        if (!(item instanceof Document))
            throw new UserServletException(HttpServletResponse.SC_BAD_REQUEST, "cannot overwrite existing object at that path");
    } catch (NoSuchItemException e) {
        log.debug("No document found at " + filename + "(folder id=" + folder.getId() + "; will create new one");
    }
    PatchInputStream pis = null;
    PatchStore.IncomingPatch ip = null;
    try {
        ip = patchStore.createIncomingPatch(context.targetAccount.getId());
        int defaultFileId = 0;
        int defaultVersion = 0;
        if (item != null) {
            defaultFileId = item.getId();
            defaultVersion = item.getVersion();
        }
        pis = PatchInputStream.create(context.getRequestInputStream(), // the current (target) user's view
        context.targetMailbox, context.opContext, defaultFileId, defaultVersion, ip.getOutputStream(), ip.getManifest());
        String creator = context.getAuthAccount() == null ? null : context.getAuthAccount().getName();
        if (contentType == null) {
            contentType = MimeDetect.getMimeDetect().detect(filename);
            if (contentType == null)
                contentType = MimeConstants.CT_APPLICATION_OCTET_STREAM;
        }
        log.debug("Storing blob");
        Blob blob = StoreManager.getInstance().storeIncoming(pis);
        log.debug("Creating parsed document; filename=" + filename + ", contentType=" + contentType + ", creator=" + creator);
        ParsedDocument pd = new ParsedDocument(blob, filename, contentType, System.currentTimeMillis(), creator, context.req.getHeader("X-Zimbra-Description"), true);
        log.debug("Parsed document created " + filename);
        // scan upload for viruses
        StringBuffer info = new StringBuffer();
        UploadScanner.Result result = UploadScanner.acceptStream(pis, info);
        if (result == UploadScanner.REJECT)
            throw MailServiceException.UPLOAD_REJECTED(filename, info.toString());
        if (result == UploadScanner.ERROR)
            throw MailServiceException.SCAN_ERROR(filename);
        if (item == null) {
            log.debug("Creating new document " + filename);
            item = mbox.createDocument(context.opContext, folder.getId(), pd, MailItem.Type.DOCUMENT, 0);
        } else {
            log.debug("Creating new version of the document " + filename + ", current version: " + item.getVersion());
            item = mbox.addDocumentRevision(context.opContext, item.getId(), pd);
        }
        patchStore.acceptPatch(ip, item.getId(), item.getVersion());
        NativeFormatter.sendZimbraHeaders(context, context.resp, item);
    } catch (PatchException e) {
        log.error("Patch upload failed: " + e);
        patchStore.rejectPatch(ip);
        throw new UserServletException(HttpServletResponse.SC_CONFLICT, "patch cannot be applied, try uploading whole file", e);
    } finally {
        try {
            pis.close();
        } catch (Exception e) {
            log.error("Exception during PatchInputStream close, ignored: " + e);
        }
    }
}
Also used : Blob(com.zimbra.cs.store.Blob) UserServletException(com.zimbra.cs.service.UserServletException) PatchStore(com.zimbra.cs.octosync.store.PatchStore) Document(com.zimbra.cs.mailbox.Document) ParsedDocument(com.zimbra.cs.mime.ParsedDocument) NoSuchItemException(com.zimbra.cs.mailbox.MailServiceException.NoSuchItemException) UploadScanner(com.zimbra.cs.service.mail.UploadScanner) PatchException(com.zimbra.cs.octosync.PatchException) ServletException(javax.servlet.ServletException) ServiceException(com.zimbra.common.service.ServiceException) NoSuchItemException(com.zimbra.cs.mailbox.MailServiceException.NoSuchItemException) IOException(java.io.IOException) FileNotFoundException(java.io.FileNotFoundException) UserServletException(com.zimbra.cs.service.UserServletException) MailServiceException(com.zimbra.cs.mailbox.MailServiceException) MailItem(com.zimbra.cs.mailbox.MailItem) Mailbox(com.zimbra.cs.mailbox.Mailbox) ParsedDocument(com.zimbra.cs.mime.ParsedDocument) PatchInputStream(com.zimbra.cs.octosync.PatchInputStream) PatchException(com.zimbra.cs.octosync.PatchException)

Example 54 with MailItem

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

the class WikiDigestFixup method getWikiDigests.

private static List<WikiDigest> getWikiDigests(int mboxId) throws IOException, ServiceException {
    Mailbox mbox = null;
    try {
        mbox = MailboxManager.getInstance().getMailboxById(mboxId);
    } catch (ServiceException e) {
        String code = e.getCode();
        if (AccountServiceException.NO_SUCH_ACCOUNT.equals(code) || ServiceException.WRONG_HOST.equals(code))
            return null;
        else
            throw e;
    }
    OperationContext octxt = new OperationContext(mbox);
    List<MailItem> items = new ArrayList<MailItem>();
    List<MailItem> wikis = mbox.getItemList(octxt, MailItem.Type.WIKI);
    if (wikis != null && wikis.size() > 0)
        items.addAll(wikis);
    List<MailItem> documents = mbox.getItemList(octxt, MailItem.Type.DOCUMENT);
    if (documents != null && documents.size() > 0)
        items.addAll(documents);
    int len = items.size();
    List<WikiDigest> list = new ArrayList<WikiDigest>(len);
    if (len > 0) {
        for (MailItem item : items) {
            // didn't support >2GB wiki items when the bug was occurring
            if (item.getSize() > Integer.MAX_VALUE)
                continue;
            int id = item.getId();
            MailboxBlob blob = sStore.getMailboxBlob(item);
            InputStream is = null;
            try {
                is = sStore.getContent(blob);
                byte[] data = ByteUtil.getContent(is, (int) item.getSize());
                String digest = ByteUtil.getSHA1Digest(data, true);
                String currentDigest = item.getDigest();
                if (!digest.equals(currentDigest)) {
                    System.out.println("Found id " + id + ", current digest = \"" + currentDigest + "\"");
                    WikiDigest wd = new WikiDigest(mboxId, id, digest);
                    list.add(wd);
                } else {
                    System.out.println("Found id " + id + " but skipping because digest is correct.");
                }
            } finally {
                ByteUtil.closeStream(is);
            }
        }
    }
    return list;
}
Also used : OperationContext(com.zimbra.cs.mailbox.OperationContext) MailboxBlob(com.zimbra.cs.store.MailboxBlob) InputStream(java.io.InputStream) ArrayList(java.util.ArrayList) MailItem(com.zimbra.cs.mailbox.MailItem) Mailbox(com.zimbra.cs.mailbox.Mailbox) AccountServiceException(com.zimbra.cs.account.AccountServiceException) ServiceException(com.zimbra.common.service.ServiceException)

Example 55 with MailItem

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

the class Sync method deltaSync.

private static String deltaSync(Element response, OperationContext octxt, ItemIdFormatter ifmt, Mailbox mbox, SyncToken syncToken, int deleteLimit, int changeLimit, boolean typedDeletes, Folder root, Set<Folder> visible, int messageSyncStart) throws ServiceException {
    int begin = syncToken.getChangeId();
    int deleteModSeqCutoff = syncToken.getDeleteModSeq();
    deleteModSeqCutoff = deleteModSeqCutoff <= 0 ? begin : deleteModSeqCutoff;
    int mboxLastChangeId = mbox.getLastChangeID();
    SyncToken newSyncToken = new SyncToken(mboxLastChangeId);
    if (begin >= mboxLastChangeId && deleteModSeqCutoff >= mboxLastChangeId) {
        return newSyncToken.toString();
    }
    int changeItemIdCutoff = syncToken.getOffsetInNext();
    int deleteItemIdCutoff = syncToken.getDeleteOffsetInNext();
    // first, fetch deleted items
    TypedIdList tombstones = mbox.getTombstones(deleteModSeqCutoff);
    Element eDeleted = response.addElement(MailConstants.E_DELETED);
    // then, put together the requested folder hierarchy in 2 different flavors
    List<Folder> hierarchy = (root == null || root.getId() == Mailbox.ID_FOLDER_USER_ROOT ? null : root.getSubfolderHierarchy());
    Set<Integer> targetIds = (root != null && root.getId() == Mailbox.ID_FOLDER_USER_ROOT ? null : new HashSet<Integer>(hierarchy == null ? 0 : hierarchy.size()));
    if (hierarchy != null) {
        for (Folder folder : hierarchy) {
            targetIds.add(folder.getId());
        }
    }
    // then, handle created/modified folders
    if (octxt.isDelegatedRequest(mbox)) {
        // first, make sure that something changed...
        if (!mbox.getModifiedFolders(begin).isEmpty() || !Collections.disjoint(tombstones.types(), FOLDER_TYPES)) {
            // special-case the folder hierarchy for delegated delta sync
            boolean anyFolders = folderSync(response, octxt, ifmt, mbox, root, visible, -1, messageSyncStart, SyncPhase.DELTA);
            // if no folders are visible, add an empty "<folder/>" as a hint
            if (!anyFolders) {
                response.addElement(MailConstants.E_FOLDER);
            }
        }
    } else {
        for (Folder folder : mbox.getModifiedFolders(begin)) {
            // no case of "synthetic tombstone" (item falling out of the tree being synced)
            if (targetIds == null || targetIds.contains(folder.getId())) {
                ToXML.encodeFolder(response, ifmt, octxt, folder, Change.ALL_FIELDS);
            } else {
                tombstones.add(folder.getType(), folder.getId(), folder.getUuid(), folder.getModifiedSequence());
            }
        }
    }
    // next, handle created/modified tags
    for (Tag tag : mbox.getModifiedTags(octxt, begin)) {
        ToXML.encodeTag(response, ifmt, octxt, tag, Change.ALL_FIELDS);
    }
    // finally, handle created/modified "other items"
    int itemCount = 0;
    Pair<List<Integer>, TypedIdList> changed = mbox.getModifiedItems(octxt, Math.min(begin, deleteModSeqCutoff), messageSyncStart, MailItem.Type.UNKNOWN, targetIds, deleteModSeqCutoff);
    List<Integer> modified = changed.getFirst();
    // items that have been altered in non-visible folders will be returned as "deleted" in order to handle moves
    if (changed.getSecond() != null) {
        tombstones.addAll(changed.getSecond());
    }
    delta: while (!modified.isEmpty()) {
        List<Integer> batch = modified.subList(0, Math.min(modified.size(), FETCH_BATCH_SIZE));
        for (MailItem item : mbox.getItemById(octxt, batch, MailItem.Type.UNKNOWN)) {
            // detect interrupted sync and resume from the appropriate place
            if ((item.getModifiedSequence() == begin + 1 && item.getId() < changeItemIdCutoff) || item.getModifiedSequence() <= begin) {
                //if interrupted delete and un-interrupted modifications.
                continue;
            }
            // if we've overflowed this sync response, set things up so that a subsequent sync starts from where we're cutting off
            if (itemCount >= changeLimit) {
                response.addAttribute(MailConstants.A_QUERY_MORE, true);
                newSyncToken.setChangeModSeq((item.getModifiedSequence() - 1));
                newSyncToken.setChangeItemId(item.getId());
                newSyncToken.setDeleteModSeq(mboxLastChangeId);
                break delta;
            }
            // For items in the system, if the content has changed since the user last sync'ed
            // (because it was edited or created), just send back the folder ID and saved date --
            // the client will request the whole object out of band -- potentially using the
            // content servlet's "include metadata in headers" hack.
            // If it's just the metadata that changed, send back the set of mutable attributes.
            boolean created = item.getSavedSequence() > begin;
            ToXML.encodeItem(response, ifmt, octxt, item, created ? Change.FOLDER | Change.CONFLICT | Change.DATE | Change.PARENT : MUTABLE_FIELDS);
            itemCount++;
        }
        batch.clear();
    }
    // cleanup: only return a <deleted> element if we're sending back deleted item ids
    if ((deleteLimit > 0 && tombstones.size() > deleteLimit) || deleteItemIdCutoff > 0) {
        PagedDelete pgDel = new PagedDelete(tombstones, typedDeletes);
        pgDel.removeBeforeCutoff(deleteItemIdCutoff, deleteModSeqCutoff);
        if (deleteLimit > 0) {
            pgDel.trimDeletesTillPageLimit(deleteLimit);
        }
        encodePagedDelete(eDeleted, pgDel, newSyncToken, tombstones, typedDeletes);
        if (pgDel.isDeleteOverFlow()) {
            response.addAttribute(MailConstants.A_QUERY_MORE, true);
            response.addAttribute(MailConstants.A_QUERY_MORE, true);
        }
    } else {
        encodeUnpagedDelete(eDeleted, tombstones, typedDeletes);
    }
    return newSyncToken.toString();
}
Also used : PagedDelete(com.zimbra.cs.mailbox.util.PagedDelete) Element(com.zimbra.common.soap.Element) Folder(com.zimbra.cs.mailbox.Folder) TypedIdList(com.zimbra.cs.mailbox.util.TypedIdList) SyncToken(com.zimbra.cs.service.util.SyncToken) MailItem(com.zimbra.cs.mailbox.MailItem) TypedIdList(com.zimbra.cs.mailbox.util.TypedIdList) List(java.util.List) Tag(com.zimbra.cs.mailbox.Tag) HashSet(java.util.HashSet)

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