use of com.zimbra.common.mailbox.MailboxStore in project zm-mailbox by Zimbra.
the class ImapHandler method doRENAME.
private boolean doRENAME(String tag, ImapPath oldPath, ImapPath newPath) throws IOException {
if (!checkState(tag, State.AUTHENTICATED)) {
return true;
}
try {
Account source = oldPath.getOwnerAccount();
Account target = newPath.getOwnerAccount();
if (source == null || target == null) {
ZimbraLog.imap.info("RENAME failed: no such account for %s or %s", oldPath, newPath);
sendNO(tag, "RENAME failed: no such account");
return true;
} else if (!source.getId().equalsIgnoreCase(target.getId())) {
ZimbraLog.imap.info("RENAME failed: cannot move folder between mailboxes");
sendNO(tag, "RENAME failed: cannot rename mailbox to other user's namespace");
return true;
} else if (!newPath.isCreatable()) {
ZimbraLog.imap.info("RENAME failed: hidden folder or parent: %s", newPath);
sendNO(tag, "RENAME failed");
return true;
} else if (!oldPath.isVisible()) {
throw MailServiceException.NO_SUCH_FOLDER(oldPath.asZimbraPath());
}
MailboxStore mboxStore = oldPath.getOwnerMailbox();
if (null != mboxStore) {
FolderStore pathFolder = oldPath.getFolder();
if (pathFolder.isInboxFolder()) {
throw ImapServiceException.CANT_RENAME_INBOX();
}
mboxStore.renameFolder(getContext(), pathFolder, "/" + newPath.asResolvedPath());
} else {
ZimbraLog.imap.info("RENAME failed: cannot get mailbox for path: " + oldPath);
sendNO(tag, "RENAME failed");
return true;
}
} catch (ServiceException e) {
if (e.getCode().equals(ImapServiceException.CANT_RENAME_INBOX)) {
ZimbraLog.imap.info("RENAME failed: RENAME of INBOX not supported");
sendNO(tag, "RENAME failed: RENAME of INBOX not supported");
return true;
} else if (e.getCode().equals(MailServiceException.NO_SUCH_FOLDER)) {
ZimbraLog.imap.info("RENAME failed: no such folder: %s", oldPath);
} else if (e.getCode().equals(MailServiceException.IMMUTABLE_OBJECT)) {
ZimbraLog.imap.info("RENAME failed: cannot rename system folder: %s", oldPath);
} else if (e.getCode().equals(MailServiceException.CANNOT_CONTAIN)) {
ZimbraLog.imap.info("RENAME failed: invalid target folder: %s", newPath);
} else {
ZimbraLog.imap.warn("RENAME failed", e);
}
sendNO(tag, "RENAME failed");
return canContinue(e);
}
// note: if ImapFolder contains a pathname, we may need to update mSelectedFolder
sendNotifications(true, false);
sendOK(tag, "RENAME completed");
return true;
}
use of com.zimbra.common.mailbox.MailboxStore in project zm-mailbox by Zimbra.
the class ImapHandler method doCOPY.
/**
* @param path of target folder
*/
protected boolean doCOPY(String tag, String sequenceSet, ImapPath path, boolean byUID) throws IOException, ImapException {
checkCommandThrottle(new CopyCommand(sequenceSet, path));
if (!checkState(tag, State.SELECTED)) {
return true;
}
String command = (byUID ? "UID COPY" : "COPY");
String copyuid = "";
ImapFolder i4folder = getSelectedFolder();
if (i4folder == null) {
throw new ImapSessionClosedException();
}
MailboxStore mbox = i4folder.getMailbox();
Set<ImapMessage> i4set;
mbox.lock(false);
try {
i4set = i4folder.getSubsequence(tag, sequenceSet, byUID);
} catch (ImapParseException ipe) {
ZimbraLog.imap.error(ipe);
throw ipe;
} finally {
mbox.unlock();
}
if (i4set.size() > LC.imap_max_items_in_copy.intValue()) {
sendNO(tag, "COPY rejected, too many items in copy request");
return true;
}
// accessed mailbox that contains expunged messages."
if (!byUID && i4set.contains(null)) {
sendNO(tag, "COPY rejected because some of the requested messages were expunged");
return true;
}
i4set.remove(null);
try {
if (!path.isVisible()) {
throw ImapServiceException.FOLDER_NOT_VISIBLE(path.asImapPath());
} else if (!path.isWritable(ACL.RIGHT_INSERT)) {
throw ImapServiceException.FOLDER_NOT_WRITABLE(path.asImapPath());
}
MailboxStore mbxStore = path.getOwnerMailbox();
if (null == mbxStore) {
throw AccountServiceException.NO_SUCH_ACCOUNT(path.getOwner());
}
FolderStore targetFolder = path.getFolder();
FolderStore selectedFolder = null;
try {
selectedFolder = i4folder.getFolder();
} catch (ServiceException e1) {
ZimbraLog.imap.error("Problem with selected folder %s during doCOPY", e1.getMessage());
return true;
}
// check target folder permissions before attempting the copy
ImapMailboxStore selectedImapMboxStore = i4folder.getImapMailboxStore();
boolean sameMailbox = selectedImapMboxStore.getAccountId().equalsIgnoreCase(mbxStore.getAccountId());
boolean selectedFolderInOtherMailbox;
ItemIdentifier fromFolderId;
if (selectedFolder instanceof MountpointStore) {
selectedFolderInOtherMailbox = true;
fromFolderId = ((MountpointStore) selectedFolder).getTargetItemIdentifier();
} else if (selectedFolder instanceof ZSharedFolder) {
selectedFolderInOtherMailbox = true;
fromFolderId = selectedFolder.getFolderItemIdentifier();
} else {
selectedFolderInOtherMailbox = false;
fromFolderId = selectedFolder.getFolderItemIdentifier();
}
int uvv = targetFolder.getUIDValidity();
ItemId iidTarget = new ItemId(targetFolder, path.getOwnerAccount().getId());
ItemIdentifier targetIdentifier = iidTarget.toItemIdentifier();
long checkpoint = System.currentTimeMillis();
List<Integer> copyUIDs = extensionEnabled("UIDPLUS") ? Lists.newArrayListWithCapacity(i4set.size()) : null;
final List<ImapMessage> i4list = Lists.newArrayList(i4set);
final List<List<ImapMessage>> batches = Lists.partition(i4list, SUGGESTED_COPY_BATCH_SIZE);
for (List<ImapMessage> batch : batches) {
if (sameMailbox && !selectedFolderInOtherMailbox) {
copyOwnItems(selectedImapMboxStore, batch, iidTarget, copyUIDs);
} else {
copyItemsBetweenMailboxes(selectedImapMboxStore, batch, fromFolderId, targetIdentifier, copyUIDs);
}
// send a gratuitous untagged response to keep pissy clients from closing the socket from inactivity
long now = System.currentTimeMillis();
if (now - checkpoint > MAXIMUM_IDLE_PROCESSING_MILLIS) {
sendIdleUntagged();
checkpoint = now;
}
}
if (uvv > 0 && copyUIDs != null && copyUIDs.size() > 0) {
List<Integer> srcUIDs = Lists.newArrayListWithCapacity(i4set.size());
for (ImapMessage i4msg : i4set) {
srcUIDs.add(i4msg.imapUid);
}
copyuid = "[COPYUID " + uvv + ' ' + ImapFolder.encodeSubsequence(srcUIDs) + ' ' + ImapFolder.encodeSubsequence(copyUIDs) + "] ";
}
} catch (IOException e) {
// 6.4.7: "If the COPY command is unsuccessful for any reason, server implementations
// MUST restore the destination mailbox to its state before the COPY attempt."
ZimbraLog.imap.warn("%s failed", command, e);
sendNO(tag, command + " failed");
return true;
} catch (ServiceException e) {
// 6.4.7: "If the COPY command is unsuccessful for any reason, server implementations
// MUST restore the destination mailbox to its state before the COPY attempt."
String rcode = "";
if (e.getCode().equals(MailServiceException.NO_SUCH_FOLDER)) {
ZimbraLog.imap.info("%s failed: no such folder: %s", command, path);
if (path.isCreatable()) {
rcode = "[TRYCREATE] ";
}
} else if (e.getCode().equals(ImapServiceException.FOLDER_NOT_VISIBLE)) {
ZimbraLog.imap.info("%s failed: folder not visible: %s", command, path);
} else if (e.getCode().equals(ImapServiceException.FOLDER_NOT_WRITABLE)) {
ZimbraLog.imap.info("%s failed: folder not writable: %s", command, path);
} else {
ZimbraLog.imap.warn("%s failed", command, e);
}
sendNO(tag, rcode + command + " failed");
return canContinue(e);
}
// RFC 2180 4.4: "COPY is the only IMAP4 sequence number command that is safe to allow
// an EXPUNGE response on. This is because a client is not permitted
// to cascade several COPY commands together."
sendNotifications(true, false);
sendOK(tag, copyuid + command + " completed");
return true;
}
use of com.zimbra.common.mailbox.MailboxStore in project zm-mailbox by Zimbra.
the class ImapHandler method copyItemsBetweenMailboxes.
private void copyItemsBetweenMailboxes(ImapMailboxStore selectedImapMboxStore, List<ImapMessage> batch, ItemIdentifier fromFolderId, ItemIdentifier targetIdentifier, List<Integer> copyUIDs) throws ServiceException {
List<ItemIdentifier> identList = Lists.newArrayListWithCapacity(batch.size());
List<Integer> createdList = Lists.newArrayListWithCapacity(batch.size());
for (ImapMessage i4msg : batch) {
identList.add(ItemIdentifier.fromAccountIdAndItemId(fromFolderId.accountId, i4msg.msgId));
}
MailboxStore selectedStore = selectedImapMboxStore.getMailboxStore();
List<String> copyIds = selectedStore.copyItemAction(getContext(), targetIdentifier, identList);
for (String copyId : copyIds) {
if (copyId.isEmpty()) {
continue;
}
// For newly created items, the UID is the same as the id in the target mailbox
ItemIdentifier itemIdentifier = new ItemIdentifier(copyId, (String) null);
createdList.add(itemIdentifier.id);
}
if (createdList.size() != identList.size()) {
throw ServiceException.FAILURE(String.format("mismatch between original (%s) and target (%s) count during IMAP COPY", identList.size(), createdList.size()), null);
}
if (copyUIDs != null) {
copyUIDs.addAll(createdList);
}
}
use of com.zimbra.common.mailbox.MailboxStore in project zm-mailbox by Zimbra.
the class ImapSessionManager method closeFolder.
protected void closeFolder(ImapListener session, boolean isUnregistering) {
// detach session from handler and jettison session state from folder
if (session.isInteractive()) {
session.inactivate();
}
// no fancy stuff for search folders since they're always recalculated on load
if (session.isVirtual()) {
session.detach();
return;
}
// checkpoint the folder data if desired
if (SERIALIZE_ON_CLOSE) {
try {
// could use session.serialize() if we want to leave it in memory...
ZimbraLog.imap.debug("Paging session during close: %s", session);
session.unload(false);
} catch (MailboxInMaintenanceException miMe) {
if (ZimbraLog.imap.isDebugEnabled()) {
ZimbraLog.imap.info("Mailbox in maintenance detected during close - will detach %s", session, miMe);
} else {
ZimbraLog.imap.info("Mailbox in maintenance detected during close - will detach %s", session);
}
session.detach();
return;
} catch (Exception e) {
ZimbraLog.imap.warn("Skipping error while trying to serialize during close %s", session, e);
}
}
if (isUnregistering) {
return;
}
// recognize if we're not configured to allow sessions to hang around after end of SELECT
if (TERMINATE_ON_CLOSE) {
session.detach();
return;
}
// if there are still other listeners on this folder, this session is unnecessary
MailboxStore mbox = session.getMailbox();
if (mbox != null) {
mbox.lock(true);
try {
for (ImapListener i4listener : session.getImapMboxStore().getListeners(session.getFolderItemIdentifier())) {
if (differentSessions(i4listener, session)) {
ZimbraLog.imap.trace("more recent listener exists for folder. Detaching %s", session);
session.detach();
recordAccess(i4listener);
return;
}
}
} finally {
mbox.unlock();
}
}
}
use of com.zimbra.common.mailbox.MailboxStore in project zm-mailbox by Zimbra.
the class ImapSessionManager method cacheKey.
private String cacheKey(FolderStore folder, boolean active) {
MailboxStore mbox = folder.getMailboxStore();
int modseq = folder instanceof SearchFolderStore ? mbox.getLastChangeID() : folder.getImapMODSEQ();
int uvv = folder instanceof SearchFolderStore ? mbox.getLastChangeID() : ImapFolder.getUIDValidity(folder);
String acctId = null;
try {
acctId = mbox.getAccountId();
} catch (ServiceException e) {
acctId = "<unknown>";
}
if (active) {
// use '_' as separator
return String.format("%s_%d_%d_%d", acctId, folder.getFolderIdInOwnerMailbox(), modseq, uvv);
} else {
// use ':' as a separator
return String.format("%s:%d:%d:%d", acctId, folder.getFolderIdInOwnerMailbox(), modseq, uvv);
}
}
Aggregations