@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(); } }