use of com.zimbra.common.mailbox.FolderStore in project zm-mailbox by Zimbra.
the class ImapHandler method doLSUB.
private boolean doLSUB(String tag, String referenceName, String mailboxName) throws ImapException, IOException {
checkCommandThrottle(new LsubCommand(referenceName, mailboxName));
if (!checkState(tag, State.AUTHENTICATED)) {
return true;
}
Pair<String, Pattern> resolved = resolvePath(referenceName, mailboxName);
String resolvedPath = resolved.getFirst();
Pattern pattern = resolved.getSecond();
Pattern childPattern = Pattern.compile(pattern.pattern() + "/.*");
ImapPath patternPath = new ImapPath(resolvedPath, credentials, ImapPath.Scope.UNPARSED);
List<String> subscriptions = null;
try {
// you cannot access your own mailbox via the /home/username mechanism
String owner = patternPath.getOwner();
if (owner == null || owner.indexOf('*') != -1 || owner.indexOf('%') != -1 || !patternPath.belongsTo(credentials)) {
Map<SubscribedImapPath, Boolean> hits = new HashMap<SubscribedImapPath, Boolean>();
if (owner == null) {
MailboxStore mbox = credentials.getMailbox();
boolean isMailFolders = Provisioning.getInstance().getLocalServer().isImapDisplayMailFoldersOnly();
for (FolderStore folder : mbox.getUserRootSubfolderHierarchy(getContext())) {
// chat has item type of message.hence ignoring the chat folder by name.
if ((isMailFolders) && (folder.isChatsFolder() || (folder.getName().equals("Chats")))) {
continue;
}
String fAcctId = folder.getFolderItemIdentifier().accountId;
if ((fAcctId != null) && !fAcctId.equals(credentials.getAccountId())) {
// ignore imapSubscribed flag on remote folders - they apply to the remote acct
continue;
}
if (folder.isIMAPSubscribed()) {
checkSubscription(new SubscribedImapPath(new ImapPath(null, folder, credentials)), pattern, childPattern, hits);
}
}
}
Set<String> remoteSubscriptions = credentials.listSubscriptions();
if (remoteSubscriptions != null && !remoteSubscriptions.isEmpty()) {
for (String sub : remoteSubscriptions) {
ImapPath subscribed = new ImapPath(sub, credentials);
if ((owner == null) == (subscribed.getOwner() == null)) {
checkSubscription(new SubscribedImapPath(subscribed), pattern, childPattern, hits);
}
}
}
subscriptions = new ArrayList<String>(hits.size());
for (Entry<SubscribedImapPath, Boolean> hit : hits.entrySet()) {
String attrs = hit.getValue() ? "" : "\\NoSelect";
subscriptions.add("LSUB (" + attrs + ") \"/\" " + hit.getKey().asUtf7String());
}
}
} catch (ServiceException e) {
ZimbraLog.imap.warn("LSUB failed", e);
sendNO(tag, "LSUB failed");
return canContinue(e);
}
if (subscriptions != null) {
for (String sub : subscriptions) {
sendUntagged(sub);
}
}
sendNotifications(true, false);
sendOK(tag, "LSUB completed");
return true;
}
use of com.zimbra.common.mailbox.FolderStore in project zm-mailbox by Zimbra.
the class ImapHandler method status.
private String status(ImapPath path, byte status) throws ImapException, ServiceException {
StringBuilder data = new StringBuilder("STATUS ").append(path.asUtf7String()).append(" (");
int empty = data.length();
int messages;
int recent;
int uidnext;
int uvv;
int unread;
int modseq;
MailboxStore mboxStore = path.getOwnerMailbox();
if (mboxStore != null) {
FolderStore folder = path.getFolder();
if (folder == null) {
throw MailServiceException.NO_SUCH_FOLDER(path.asImapPath());
}
ImapFolder i4folder = getSelectedFolder();
messages = folder.getImapMessageCount();
if ((status & StatusDataItemNames.STATUS_RECENT) == 0) {
recent = -1;
} else if (messages == 0) {
recent = 0;
} else if (i4folder != null && i4folder.getItemIdentifier().sameAndFullyDefined(folder.getFolderItemIdentifier())) {
recent = i4folder.getRecentCount();
} else if (i4folder != null && path.isEquivalent(i4folder.getPath())) {
recent = i4folder.getRecentCount();
} else {
ImapMailboxStore imapStore = path.getOwnerImapMailboxStore();
recent = imapStore.getImapRECENT(this.getContext(), folder);
}
uidnext = folder.isSearchFolder() ? -1 : folder.getImapUIDNEXT();
uvv = folder.getUIDValidity();
unread = folder.getImapUnreadCount();
modseq = folder.isSearchFolder() ? 0 : folder.getImapMODSEQ();
ZimbraLog.imap.debug("STATUS for %s. unread %d, recent %d, count %d", folder.getPath(), unread, recent, messages);
} else {
throw AccountServiceException.NO_SUCH_ACCOUNT(path.getOwner());
}
if (messages >= 0 && (status & StatusDataItemNames.STATUS_MESSAGES) != 0) {
data.append(data.length() != empty ? " " : "").append("MESSAGES ").append(messages);
}
if (recent >= 0 && (status & StatusDataItemNames.STATUS_RECENT) != 0) {
data.append(data.length() != empty ? " " : "").append("RECENT ").append(recent);
}
// note: we're not supporting UIDNEXT for search folders; see the comments in selectFolder()
if (uidnext > 0 && (status & StatusDataItemNames.STATUS_UIDNEXT) != 0) {
data.append(data.length() != empty ? " " : "").append("UIDNEXT ").append(uidnext);
}
if (uvv > 0 && (status & StatusDataItemNames.STATUS_UIDVALIDITY) != 0) {
data.append(data.length() != empty ? " " : "").append("UIDVALIDITY ").append(uvv);
}
if (unread >= 0 && (status & StatusDataItemNames.STATUS_UNSEEN) != 0) {
data.append(data.length() != empty ? " " : "").append("UNSEEN ").append(unread);
}
if (modseq >= 0 && (status & StatusDataItemNames.STATUS_HIGHESTMODSEQ) != 0) {
data.append(data.length() != empty ? " " : "").append("HIGHESTMODSEQ ").append(modseq);
}
return data.append(')').toString();
}
use of com.zimbra.common.mailbox.FolderStore in project zm-mailbox by Zimbra.
the class ImapHandler method doDELETEACL.
private boolean doDELETEACL(String tag, ImapPath path, String principal) throws IOException {
if (!checkState(tag, State.AUTHENTICATED)) {
return true;
}
try {
// make sure the requester has sufficient permissions to make the request
if ((path.getFolderRights() & ACL.RIGHT_ADMIN) == 0) {
ZimbraLog.imap.info("DELETEACL failed: user does not have admin access: " + path);
sendNO(tag, "DELETEACL failed");
return true;
}
// figure out whose permissions are being revoked
GranteeIdAndType grantee = getPrincipalGranteeInfo(principal);
if (grantee.id == null) {
ZimbraLog.imap.info("DELETEACL failed: cannot resolve principal: %s", principal);
sendNO(tag, "DELETEACL failed");
return true;
}
// and revoke the permissions appropriately
MailboxStore mboxStore = path.getOwnerMailbox();
if (mboxStore != null) {
FolderStore folder = path.getFolder();
if (!folder.getACLGrants().isEmpty()) {
mboxStore.modifyFolderRevokeGrant(getContext(), folder.getFolderIdAsString(), grantee.id);
if (grantee.id == GuestAccount.GUID_AUTHUSER) {
mboxStore.modifyFolderRevokeGrant(getContext(), folder.getFolderIdAsString(), GuestAccount.GUID_PUBLIC);
}
}
}
} catch (ServiceException e) {
if (e.getCode().equals(ServiceException.PERM_DENIED)) {
ZimbraLog.imap.info("DELETEACL failed: permission denied on folder: %s", path);
} else if (e.getCode().equals(MailServiceException.NO_SUCH_FOLDER)) {
ZimbraLog.imap.info("DELETEACL failed: no such folder: %s", path);
} else if (e.getCode().equals(AccountServiceException.NO_SUCH_ACCOUNT)) {
ZimbraLog.imap.info("DELETEACL failed: no such account: %s", principal);
} else {
ZimbraLog.imap.warn("DELETEACL failed", e);
}
sendNO(tag, "DELETEACL failed");
return true;
}
sendNotifications(true, false);
sendOK(tag, "DELETEACL completed");
return true;
}
use of com.zimbra.common.mailbox.FolderStore in project zm-mailbox by Zimbra.
the class ImapHandler method doSETACL.
private boolean doSETACL(String tag, ImapPath path, String principal, String i4rights, StoreAction action) throws IOException {
if (!checkState(tag, State.AUTHENTICATED))
return true;
// RFC 4314 2: "If rights are tied in an implementation, the implementation must be
// conservative in granting rights in response to SETACL commands--unless
// all rights in a tied set are specified, none of that set should be
// included in the ACL entry for that identifier."
short rights = 0;
for (int i = 0; i < i4rights.length(); i++) {
char c = i4rights.charAt(i);
if (IMAP_READ_RIGHTS.indexOf(c) != -1) {
if (allRightsPresent(i4rights, IMAP_READ_RIGHTS))
rights |= ACL.RIGHT_READ;
} else if (IMAP_WRITE_RIGHTS.indexOf(c) != -1) {
if (allRightsPresent(i4rights, IMAP_WRITE_RIGHTS))
rights |= ACL.RIGHT_WRITE;
} else if (IMAP_INSERT_RIGHTS.indexOf(c) != -1) {
if (allRightsPresent(i4rights, IMAP_INSERT_RIGHTS))
rights |= ACL.RIGHT_INSERT;
} else if (IMAP_DELETE_RIGHTS.indexOf(c) != -1) {
if (allRightsPresent(i4rights, IMAP_DELETE_RIGHTS))
rights |= ACL.RIGHT_DELETE;
} else if (IMAP_ADMIN_RIGHTS.indexOf(c) != -1) {
if (allRightsPresent(i4rights, IMAP_ADMIN_RIGHTS))
rights |= ACL.RIGHT_ADMIN;
} else {
// RFC 4314 3.1: "Note that an unrecognized right MUST cause the command to return
// the BAD response. In particular, the server MUST NOT silently
// ignore unrecognized rights."
ZimbraLog.imap.info("SETACL failed: invalid rights string: %s", i4rights);
sendBAD(tag, "SETACL failed: invalid right");
return true;
}
}
try {
// make sure the requester has sufficient permissions to make the request
if ((path.getFolderRights() & ACL.RIGHT_ADMIN) == 0) {
ZimbraLog.imap.info("SETACL failed: user does not have admin access: %s", path);
sendNO(tag, "SETACL failed");
return true;
}
// detect a no-op early and short-circuit out here
if (action != StoreAction.REPLACE && rights == 0) {
sendNotifications(true, false);
sendOK(tag, "SETACL completed");
return true;
}
// figure out who's being granted permissions
GranteeIdAndType grantee = getPrincipalGranteeInfo(principal);
if (grantee.id == null) {
ZimbraLog.imap.info("SETACL failed: cannot resolve principal: %s", principal);
sendNO(tag, "SETACL failed");
return true;
}
// figure out the rights already granted on the folder
short oldRights = 0;
FolderStore folderStore = path.getFolder();
if (null != folderStore) {
for (ACLGrant grant : folderStore.getACLGrants()) {
if (grantee.id.equalsIgnoreCase(grant.getGranteeId()) || (grantee.type == ACL.GRANTEE_AUTHUSER && (grant.getGrantGranteeType() == GrantGranteeType.all || grant.getGrantGranteeType() == GrantGranteeType.pub))) {
oldRights |= ACL.stringToRights(grant.getPermissions());
}
}
}
// calculate the new rights we want granted on the folder
short newRights;
if (action == StoreAction.REMOVE) {
newRights = (short) (oldRights & ~rights);
} else if (action == StoreAction.ADD) {
newRights = (short) (oldRights | rights);
} else {
newRights = rights;
}
// and update the folder appropriately, if necessary
if (newRights != oldRights) {
MailboxStore mboxStore = path.getOwnerMailbox();
mboxStore.modifyFolderGrant(getContext(), folderStore, GrantGranteeType.fromByte(grantee.type), grantee.id, ACL.rightsToString(newRights), null);
}
} catch (ServiceException e) {
if (e.getCode().equals(ServiceException.PERM_DENIED)) {
ZimbraLog.imap.info("SETACL failed: permission denied on folder: %s", path);
} else if (e.getCode().equals(MailServiceException.NO_SUCH_FOLDER)) {
ZimbraLog.imap.info("SETACL failed: no such folder: %s", path);
} else if (e.getCode().equals(AccountServiceException.NO_SUCH_ACCOUNT)) {
ZimbraLog.imap.info("SETACL failed: no such account: %s", principal);
} else {
ZimbraLog.imap.warn("SETACL failed", e);
}
sendNO(tag, "SETACL failed");
return true;
}
sendNotifications(true, false);
sendOK(tag, "SETACL completed");
return true;
}
use of com.zimbra.common.mailbox.FolderStore in project zm-mailbox by Zimbra.
the class ImapHandler method doDELETE.
private boolean doDELETE(String tag, ImapPath path) throws IOException {
if (!checkState(tag, State.AUTHENTICATED)) {
return true;
}
try {
if (!path.isVisible()) {
throw ImapServiceException.FOLDER_NOT_VISIBLE(path.asImapPath());
}
// don't want the DELETE to cause *this* connection to drop if the deleted folder is currently selected
if (getState() == State.SELECTED) {
ImapListener i4selected = getCurrentImapListener();
if (i4selected != null && path.isEquivalent(i4selected.getPath())) {
unsetSelectedFolder(true);
} else if (imapProxy != null && path.isEquivalent(imapProxy.getPath())) {
unsetSelectedFolder(true);
}
}
MailboxStore mboxStore = path.getOwnerMailbox();
if (path.useReferent()) {
// when users try to remove mountpoints, the IMAP client hard-deletes the subfolders!
// deal with this by only *pretending* to delete subfolders of mountpoints
credentials.hideFolder(path);
// even pretend-deleting the folder also unsubscribes from it...
credentials.unsubscribe(path);
} else if (null != mboxStore) {
FolderStore folder = path.getFolder();
if (!folder.isDeletable()) {
throw ImapServiceException.CANNOT_DELETE_SYSTEM_FOLDER(folder.getPath());
}
if (!folder.hasSubfolders()) {
mboxStore.deleteFolder(getContext(), folder.getFolderIdAsString());
// deleting the folder also unsubscribes from it...
credentials.unsubscribe(path);
} else {
// 6.3.4: "It is permitted to delete a name that has inferior hierarchical
// names and does not have the \Noselect mailbox name attribute.
// In this case, all messages in that mailbox are removed, and the
// name will acquire the \Noselect mailbox name attribute."
mboxStore.emptyFolder(getContext(), folder.getFolderIdAsString(), false);
// FIXME: add \Deleted flag to folder
}
} else {
throw AccountServiceException.NO_SUCH_ACCOUNT(path.getOwner());
}
} catch (ServiceException e) {
if (e.getCode().equals(MailServiceException.NO_SUCH_FOLDER)) {
ZimbraLog.imap.info("DELETE failed: no such folder: %s", path);
} else if (e.getCode().equals(AccountServiceException.NO_SUCH_ACCOUNT)) {
ZimbraLog.imap.info("DELETE failed: no such account: %s", path);
} else if (e.getCode().equals(ImapServiceException.FOLDER_NOT_VISIBLE)) {
ZimbraLog.imap.info("DELETE failed: folder not visible: %s", path);
} else if (e.getCode().equals(ImapServiceException.CANT_DELETE_SYSTEM_FOLDER)) {
ZimbraLog.imap.info("DELETE failed: system folder cannot be deleted: %s", path);
} else if (e.getCode().equals(ServiceException.PERM_DENIED)) {
ZimbraLog.imap.info("DELETE failed: permission denied: %s", path);
} else {
ZimbraLog.imap.warn("DELETE failed", e);
}
sendNO(tag, "DELETE failed");
return canContinue(e);
}
sendNotifications(true, false);
sendOK(tag, "DELETE completed");
return true;
}
Aggregations