use of com.zimbra.common.mailbox.FolderStore 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.FolderStore in project zm-mailbox by Zimbra.
the class ImapHandler method doSUBSCRIBE.
private boolean doSUBSCRIBE(String tag, ImapPath path) throws IOException {
if (!checkState(tag, State.AUTHENTICATED)) {
return true;
}
try {
// canonicalizing the path also throws exceptions when the folder doesn't exist
path.canonicalize();
if (path.belongsTo(credentials)) {
if (!path.isVisible()) {
throw ImapServiceException.FOLDER_NOT_VISIBLE(path.asImapPath());
}
FolderStore folder = path.getFolder();
if (!folder.isIMAPSubscribed()) {
path.getOwnerMailbox().flagFolderAsSubscribed(getContext(), folder);
}
} else {
credentials.subscribe(path);
}
} catch (ServiceException e) {
if (e.getCode().equals(MailServiceException.NO_SUCH_FOLDER)) {
ZimbraLog.imap.info("SUBSCRIBE failed: no such folder: %s", path);
} else if (e.getCode().equals(ServiceException.PERM_DENIED)) {
ZimbraLog.imap.info("SUBSCRIBE failed: permission denied on folder: %s", path);
} else if (e.getCode().equals(ImapServiceException.FOLDER_NOT_VISIBLE)) {
ZimbraLog.imap.info("SUBSCRIBE failed: folder not visible: %s", path);
} else {
ZimbraLog.imap.warn("SUBSCRIBE failed", e);
}
sendNO(tag, "SUBSCRIBE failed");
return canContinue(e);
}
sendNotifications(true, false);
sendOK(tag, "SUBSCRIBE completed");
return true;
}
use of com.zimbra.common.mailbox.FolderStore in project zm-mailbox by Zimbra.
the class ImapSessionManager method openFolder.
protected FolderDetails openFolder(ImapPath path, byte params, ImapHandler handler) throws ServiceException {
ZimbraLog.imap.debug("opening folder: %s", path);
if (!path.isSelectable()) {
throw ServiceException.PERM_DENIED("cannot select folder: " + path);
}
if ((params & ImapFolder.SELECT_CONDSTORE) != 0) {
handler.activateExtension(ImapExtension.CONDSTORE);
}
FolderStore folder = path.getFolder();
String folderIdAsString = folder.getFolderIdAsString();
int folderId = folder.getFolderIdInOwnerMailbox();
MailboxStore mbox = folder.getMailboxStore();
ImapMailboxStore imapStore = ImapMailboxStore.get(mbox);
// don't have a session when the folder is loaded...
OperationContext octxt = handler.getCredentials().getContext();
List<ImapMessage> i4list = null;
// *always* recalculate the contents of search folders
if (folder instanceof SearchFolderStore) {
i4list = loadVirtualFolder(octxt, (SearchFolderStore) folder);
} else {
waitForWaitSetNotifications(imapStore, folder);
}
mbox.lock(true);
try {
// need mInitialRecent to be set *before* loading the folder so we can determine what's \Recent
if (!(folder instanceof ZSharedFolder)) {
folder = mbox.getFolderById(octxt, folderIdAsString);
if (folder == null) {
throw MailServiceException.NO_SUCH_FOLDER(path.asImapPath());
}
}
int recentCutoff = imapStore.getImapRECENTCutoff(folder);
if (i4list == null) {
List<ImapListener> listners = imapStore.getListeners(folder);
// first option is to duplicate an existing registered session
// (could try to just activate an inactive session, but this logic is simpler for now)
i4list = duplicateExistingSession(folderId, listners);
// no matching session means we next check for serialized folder data
if (i4list == null) {
i4list = duplicateSerializedFolder(folder);
} else if (CONSISTENCY_CHECK) {
Collections.sort(i4list);
// sort only if using list from duplicated session which may be out of order
// if loaded from serialized folder order _should_ already be OK since no changes have occurred
}
// do the consistency check, if requested
if (CONSISTENCY_CHECK) {
i4list = consistencyCheck(i4list, imapStore, octxt, folder);
}
// no matching serialized session means we have to go to the DB to get the messages
if (i4list == null) {
ItemIdentifier ident;
if (folder instanceof MountpointStore) {
ident = ((MountpointStore) folder).getTargetItemIdentifier();
} else {
ident = folder.getFolderItemIdentifier();
}
i4list = imapStore.openImapFolder(octxt, ident);
}
}
Collections.sort(i4list);
// check messages for imapUid <= 0 and assign new IMAP IDs if necessary
renumberMessages(octxt, mbox, i4list);
ImapFolder i4folder = new ImapFolder(path, params, handler);
// don't rely on the <code>Folder</code> object being updated in place
if (!(folder instanceof ZSharedFolder)) {
folder = mbox.getFolderById(octxt, folderIdAsString);
}
// can't set these until *after* loading the folder because UID renumbering affects them
InitialFolderValues initial = new InitialFolderValues(folder);
for (ImapMessage i4msg : i4list) {
i4folder.cache(i4msg, i4msg.imapUid > recentCutoff);
if (initial.firstUnread == -1 && (i4msg.flags & Flag.BITMASK_UNREAD) != 0) {
initial.firstUnread = i4msg.sequence;
}
}
i4folder.setInitialSize();
ZimbraLog.imap.debug("ImapSessionManager.openFolder. Folder with id=%s added message list %s", folderIdAsString, i4list);
ImapListener session = null;
try {
session = imapStore.createListener(i4folder, handler);
session.register();
sessions.put(session, session);
imapStore.registerWithImapServerListener(session);
return new FolderDetails(session, initial);
} catch (ServiceException e) {
if (session != null) {
session.unregister();
}
throw e;
}
} finally {
mbox.unlock();
}
}
use of com.zimbra.common.mailbox.FolderStore in project zm-mailbox by Zimbra.
the class ImapPath method getReferent.
/**
* @return If the folder is a mountpoint (i.e. an accepted share), may return an ImapPath representing
* that, otherwise, the value is this.
*/
@VisibleForTesting
public ImapPath getReferent() throws ServiceException {
if (mReferent != null) {
return mReferent;
}
// while calculating, use the base
mReferent = this;
// only follow the authenticated user's own mountpoints
if (mScope == Scope.REFERENCE || mScope == Scope.UNPARSED || !belongsTo(mCredentials)) {
return mReferent;
}
ImapMailboxStore ownerImapMailboxStore = getOwnerImapMailboxStore();
if (null == ownerImapMailboxStore) {
return mReferent;
}
ItemId iidRemote;
String subpathRemote = null;
if (folder == null) {
try {
ExistingParentFolderStoreAndUnmatchedPart info = ownerImapMailboxStore.getMailboxStore().getParentFolderStoreAndUnmatchedPart(getContext(), asZimbraPath());
subpathRemote = info.unmatchedPart;
if (info.parentFolderStore instanceof MountpointStore || Strings.isNullOrEmpty(subpathRemote)) {
folder = info.parentFolderStore;
mItemId = new ItemId(ItemIdentifier.fromOwnerAndFolder(accountIdFromCredentials(), folder));
}
if (!(info.parentFolderStore instanceof MountpointStore)) {
return mReferent;
}
} catch (ServiceException e) {
return mReferent;
}
}
if (!(folder instanceof MountpointStore)) {
return mReferent;
}
// somewhere along the specified path is a visible mountpoint owned by the user
iidRemote = new ItemId(((MountpointStore) folder).getTargetItemIdentifier());
// don't allow mountpoints that point at the same mailbox (as it can cause infinite loops)
if (belongsTo(iidRemote.getAccountId())) {
return mReferent;
}
Account target = Provisioning.getInstance().get(AccountBy.id, iidRemote.getAccountId());
if (target == null) {
return mReferent;
}
ImapMailboxStore imapMailboxStore = setupMailboxStoreForTarget(target, iidRemote);
if (null == imapMailboxStore) {
return mReferent;
}
FolderStore fldr = imapMailboxStore.getMailboxStore().getFolderById(getContext(), Integer.toString(iidRemote.getId()));
if (fldr == null) {
return mReferent;
}
String owner = getOwner(target);
if (Strings.isNullOrEmpty(subpathRemote)) {
mReferent = new ImapPath(owner, fldr, mCredentials);
} else {
mReferent = ImapPath.get(owner, fldr.getPath() + (fldr.getPath().equals("/") ? "" : "/") + subpathRemote, mCredentials, imapMailboxStore);
}
if (mReferent != this) {
mReferent.mScope = Scope.REFERENCE;
}
return mReferent;
}
use of com.zimbra.common.mailbox.FolderStore in project zm-mailbox by Zimbra.
the class LocalImapMailboxStore method getVisibleFolders.
@Override
public Collection<FolderStore> getVisibleFolders(OperationContext octxt, ImapCredentials credentials, String owner, ImapPath relativeTo) throws ServiceException {
Collection<Folder> folders = mailbox.getVisibleFolders(octxt);
if (folders == null) {
folders = mailbox.getFolderById(octxt, relativeTo == null ? Mailbox.ID_FOLDER_USER_ROOT : relativeTo.asItemId().getId()).getSubfolderHierarchy();
}
String root = relativeTo == null ? "" : "/" + relativeTo.asResolvedPath();
Collection<FolderStore> fStores = Sets.newHashSetWithExpectedSize(folders.size());
for (Folder folder : folders) {
if (!folder.getPath().startsWith(root) || folder.getPath().equals(root)) {
continue;
}
fStores.add(folder);
}
return fStores;
}
Aggregations