@Override
  public void deliver(LmtpEnvelope env, InputStream in, int sizeHint)
      throws UnrecoverableLmtpException {
    CopyInputStream cis = null;
    Blob blob = null;
    try {
      int bufLen = Provisioning.getInstance().getLocalServer().getMailDiskStreamingThreshold();
      cis = new CopyInputStream(in, sizeHint, bufLen, bufLen);
      in = cis;

      //            MimeParserInputStream mpis = null;
      //            if (ZMimeMessage.usingZimbraParser()) {
      //                mpis = new MimeParserInputStream(in);
      //                in = mpis;
      //            }

      Rfc822ValidationInputStream validator = null;
      if (LC.zimbra_lmtp_validate_messages.booleanValue()) {
        validator = new Rfc822ValidationInputStream(in, LC.zimbra_lmtp_max_line_length.longValue());
        in = validator;
      }

      try {
        blob = StoreManager.getInstance().storeIncoming(in);
      } catch (IOException ioe) {
        throw new UnrecoverableLmtpException("Error in storing incoming message", ioe);
      }

      if (validator != null && !validator.isValid()) {
        try {
          StoreManager.getInstance().delete(blob);
        } catch (IOException e) {
          ZimbraLog.lmtp.warn("Error in deleting blob %s", blob, e);
        }
        setDeliveryStatuses(env.getRecipients(), LmtpReply.INVALID_BODY_PARAMETER);
        return;
      }

      BufferStream bs = cis.getBufferStream();
      byte[] data = bs.isPartial() ? null : bs.getBuffer();

      BlobInputStream bis = null;
      MimeMessage mm = null;
      //            if (mpis != null) {
      //                try {
      //                    if (data == null) {
      //                        bis = new BlobInputStream(blob);
      //                        mpis.setSource(bis);
      //                    } else {
      //                        mpis.setSource(data);
      //                    }
      //                } catch (IOException ioe) {
      //                    throw new UnrecoverableLmtpException("Error in accessing incoming
      // message", ioe);
      //                }
      //
      //                mm = new ZMimeMessage(mpis.getMessage(null));
      //            }

      try {
        deliverMessageToLocalMailboxes(blob, bis, data, mm, env);
      } catch (Exception e) {
        ZimbraLog.lmtp.warn("Exception delivering mail (temporary failure)", e);
        setDeliveryStatuses(env.getLocalRecipients(), LmtpReply.TEMPORARY_FAILURE);
      }

      try {
        deliverMessageToRemoteMailboxes(blob, data, env);
      } catch (Exception e) {
        ZimbraLog.lmtp.warn("Exception delivering remote mail", e);
        setDeliveryStatuses(env.getRemoteRecipients(), LmtpReply.TEMPORARY_FAILURE);
      }
    } catch (ServiceException e) {
      ZimbraLog.lmtp.warn("Exception delivering mail (temporary failure)", e);
      setDeliveryStatuses(env.getRecipients(), LmtpReply.TEMPORARY_FAILURE);
    } finally {
      if (cis != null) {
        cis.release();
      }

      if (blob != null) {
        try {
          // clean up the incoming blob
          StoreManager.getInstance().delete(blob);
        } catch (IOException e) {
          ZimbraLog.lmtp.warn("Error in deleting blob %s", blob, e);
        }
      }
    }
  }
 @Override
 public Results check(
     Collection<Short> volumeIds, int mboxId, boolean checkSize, boolean reportUsedBlobs)
     throws ServiceException {
   mailboxId = mboxId;
   this.checkSize = checkSize;
   this.reportUsedBlobs = reportUsedBlobs;
   results = new Results();
   Mailbox mbox = MailboxManager.getInstance().getMailboxById(mailboxId);
   DbConnection conn = null;
   assert (StoreManager.getInstance() instanceof ExternalStoreManager);
   ExternalStoreManager sm = (ExternalStoreManager) StoreManager.getInstance();
   try {
     unexpectedBlobPaths = sm.getAllBlobPaths(mbox);
   } catch (IOException ioe) {
     log.error("IOException getting remote blob list", ioe);
   }
   try {
     conn = DbPool.getConnection();
     int mailboxMaxId = DbBlobConsistency.getMaxId(conn, mbox);
     int minId = 0;
     int maxId = CHUNK_SIZE;
     while (minId <= mailboxMaxId) {
       for (BlobInfo blobInfo :
           DbBlobConsistency.getExternalMailItemBlobInfo(conn, mbox, minId, maxId)) {
         checkExternalBlob(mbox, checkSize, blobInfo, sm);
       }
       for (BlobInfo blobInfo :
           DbBlobConsistency.getExternalMailItemDumpsterBlobInfo(conn, mbox, minId, maxId)) {
         checkExternalBlob(mbox, checkSize, blobInfo, sm);
       }
       for (BlobInfo blobInfo :
           DbBlobConsistency.getExternalRevisionBlobInfo(conn, mbox, minId, maxId)) {
         checkExternalBlob(mbox, checkSize, blobInfo, sm);
       }
       for (BlobInfo blobInfo :
           DbBlobConsistency.getExternalRevisionDumpsterBlobInfo(conn, mbox, minId, maxId)) {
         checkExternalBlob(mbox, checkSize, blobInfo, sm);
       }
       minId = maxId + 1;
       maxId += CHUNK_SIZE;
     }
   } finally {
     DbPool.quietClose(conn);
   }
   for (String unexpected : unexpectedBlobPaths) {
     BlobInfo bi = new BlobInfo();
     bi.external = true;
     bi.locator = unexpected;
     bi.path = unexpected;
     results.unexpectedBlobs.put(0, bi);
     try {
       Blob blob = sm.getLocalBlob(mbox, unexpected, false);
       bi.fileSize = blob.getFile().length();
     } catch (IOException ioe) {
       // log this?
       bi.fileSize = 0L;
       bi.fetchException = ioe;
     }
   }
   return results;
 }
  boolean renumberItem(OperationContext octxt, int id, MailItem.Type type, int newId)
      throws ServiceException {
    if (id == newId) {
      return true;
    } else if (id <= 0 || newId <= 0) {
      throw ServiceException.FAILURE(
          "invalid item id when renumbering (" + id + " => " + newId + ")", null);
    }

    lock.lock();
    try {
      boolean success = false;
      try {
        beginTransaction("renumberItem", octxt);
        MailItem item = getItemById(id, type);
        if (item.getId() == newId) {
          OfflineLog.offline.info(
              "Item already renumbered; no need to renumber (%d => %d)", id, newId);
          return true;
        } else if (item.getId() != id) {
          OfflineLog.offline.warn(
              "renumbering item which may have already been renumbered (%d => %d) : itemId = %d",
              id, newId, item.getId());
        }
        // changing a message's item id needs to purge its Conversation (virtual or real)
        if (item instanceof Message) uncacheItem(item.getParentId());

        // mark old blob as disposable, but don't reindex item because INDEX_ID should still be
        // correct
        MailboxBlob mblob = item.getBlob();
        if (mblob != null) {
          // register old blob for post-commit deletion
          item.markBlobForDeletion();
          item.mBlob = null;

          // copy blob to new id (note that item.getSavedSequence() may change again later)
          try {
            MailboxBlob newBlob =
                StoreManager.getInstance().copy(mblob, this, newId, item.getSavedSequence());
            markOtherItemDirty(newBlob);
          } catch (IOException e) {
            throw ServiceException.FAILURE(
                "could not link blob for renumbered item (" + id + " => " + newId + ")", e);
          }
        }

        // update the id in the database and in memory
        markItemDeleted(item.getType(), id);
        try {
          DbOfflineMailbox.renumberItem(item, newId);
          uncache(item);
        } catch (ServiceException se) {
          throw ServiceException.FAILURE(
              "Failure renumbering item name["
                  + item.getName()
                  + "] subject["
                  + item.getSubject()
                  + "]",
              se);
        }
        item.mId = item.mData.id = newId;
        item.markItemCreated();

        if (item instanceof Folder || item instanceof Tag) {
          // replace with the new item
          cache(item);
          if (item instanceof Folder) {
            // sub folders might have wrong id
            List<Folder> subFolders = ((Folder) item).getSubfolders(octxt);
            for (Folder subFolder : subFolders) {
              subFolder.mData.folderId = newId;
              subFolder.mData.parentId = newId;
              cache(subFolder); // make sure it's in the cache
            }
          }

          // msgs are lazy-loaded so purge is safe
          purge(MailItem.Type.MESSAGE);
        }
        success = true;
      } catch (MailServiceException.NoSuchItemException nsie) {
        // item deleted from local before sync completes renumbering
        OfflineLog.offline.info(
            "item %d deleted from local db before sync completes renumbering to %d", id, newId);
        TypedIdList tombstones = new TypedIdList();
        tombstones.add(type, newId, null);
        DbMailItem.writeTombstones(this, tombstones);
        success = true;
        return false;
      } finally {
        endTransaction(success);
      }
      mRenumbers.put(id, newId);
      return true;
    } finally {
      lock.release();
    }
  }