Search in sources :

Example 61 with ServiceException

use of com.zimbra.common.service.ServiceException in project zm-mailbox by Zimbra.

the class LdapProvisioning method getNamesForIds.

@Override
public Map<String, String> getNamesForIds(Set<String> ids, EntryType type) throws ServiceException {
    final Map<String, String> result = new HashMap<String, String>();
    Set<String> unresolvedIds;
    NamedEntry entry;
    final String nameAttr;
    final EntryType entryType = type;
    String base;
    String objectClass;
    switch(entryType) {
        case account:
            unresolvedIds = new HashSet<String>();
            for (String id : ids) {
                entry = accountCache.getById(id);
                if (entry != null)
                    result.put(id, entry.getName());
                else
                    unresolvedIds.add(id);
            }
            nameAttr = Provisioning.A_zimbraMailDeliveryAddress;
            base = mDIT.mailBranchBaseDN();
            objectClass = AttributeClass.OC_zimbraAccount;
            break;
        case group:
            unresolvedIds = ids;
            // see dnToEmail
            nameAttr = Provisioning.A_uid;
            base = mDIT.mailBranchBaseDN();
            objectClass = AttributeClass.OC_zimbraDistributionList;
            break;
        case cos:
            unresolvedIds = new HashSet<String>();
            for (String id : ids) {
                entry = cosCache.getById(id);
                if (entry != null)
                    result.put(id, entry.getName());
                else
                    unresolvedIds.add(id);
            }
            nameAttr = Provisioning.A_cn;
            base = mDIT.cosBaseDN();
            objectClass = AttributeClass.OC_zimbraCOS;
            break;
        case domain:
            unresolvedIds = new HashSet<String>();
            for (String id : ids) {
                entry = getFromCache(Key.DomainBy.id, id, GetFromDomainCacheOption.POSITIVE);
                if (entry != null)
                    result.put(id, entry.getName());
                else
                    unresolvedIds.add(id);
            }
            nameAttr = Provisioning.A_zimbraDomainName;
            base = mDIT.domainBaseDN();
            objectClass = AttributeClass.OC_zimbraDomain;
            break;
        default:
            throw ServiceException.FAILURE("unsupported entry type for getNamesForIds" + type.name(), null);
    }
    // we are done if all ids can be resolved in our cache
    if (unresolvedIds.size() == 0)
        return result;
    SearchLdapVisitor visitor = new SearchLdapVisitor() {

        @Override
        public void visit(String dn, Map<String, Object> attrs, IAttributes ldapAttrs) {
            String id = (String) attrs.get(Provisioning.A_zimbraId);
            String name = null;
            try {
                switch(entryType) {
                    case account:
                        name = ldapAttrs.getAttrString(Provisioning.A_zimbraMailDeliveryAddress);
                        if (name == null)
                            name = mDIT.dnToEmail(dn, ldapAttrs);
                        break;
                    case group:
                        name = mDIT.dnToEmail(dn, ldapAttrs);
                        break;
                    case cos:
                        name = ldapAttrs.getAttrString(Provisioning.A_cn);
                        break;
                    case domain:
                        name = ldapAttrs.getAttrString(Provisioning.A_zimbraDomainName);
                        break;
                }
            } catch (ServiceException e) {
                name = null;
            }
            if (name != null)
                result.put(id, name);
        }
    };
    String[] returnAttrs = new String[] { Provisioning.A_zimbraId, nameAttr };
    searchNamesForIds(unresolvedIds, base, objectClass, returnAttrs, visitor);
    return result;
}
Also used : NamedEntry(com.zimbra.cs.account.NamedEntry) SearchLdapVisitor(com.zimbra.cs.ldap.SearchLdapOptions.SearchLdapVisitor) CacheEntryType(com.zimbra.soap.admin.type.CacheEntryType) AccountServiceException(com.zimbra.cs.account.AccountServiceException) AuthFailedServiceException(com.zimbra.cs.account.AccountServiceException.AuthFailedServiceException) ServiceException(com.zimbra.common.service.ServiceException) HashMap(java.util.HashMap) IAttributes(com.zimbra.cs.ldap.IAttributes) Map(java.util.Map) TreeMap(java.util.TreeMap) HashMap(java.util.HashMap)

Example 62 with ServiceException

use of com.zimbra.common.service.ServiceException in project zm-mailbox by Zimbra.

the class LdapProvisioning method createAccount.

private Account createAccount(String emailAddress, String password, Map<String, Object> acctAttrs, SpecialAttrs specialAttrs, String[] additionalObjectClasses, boolean restoring, Map<String, Object> origAttrs) throws ServiceException {
    String uuid = specialAttrs.getZimbraId();
    String baseDn = specialAttrs.getLdapBaseDn();
    emailAddress = emailAddress.toLowerCase().trim();
    String[] parts = emailAddress.split("@");
    if (parts.length != 2) {
        throw ServiceException.INVALID_REQUEST("must be valid email address: " + emailAddress, null);
    }
    String localPart = parts[0];
    String domain = parts[1];
    domain = IDNUtil.toAsciiDomainName(domain);
    emailAddress = localPart + "@" + domain;
    validEmailAddress(emailAddress);
    if (restoring) {
        validate(ProvisioningValidator.CREATE_ACCOUNT, emailAddress, additionalObjectClasses, origAttrs);
        validate(ProvisioningValidator.CREATE_ACCOUNT_CHECK_DOMAIN_COS_AND_FEATURE, emailAddress, origAttrs);
    } else {
        validate(ProvisioningValidator.CREATE_ACCOUNT, emailAddress, additionalObjectClasses, acctAttrs);
        validate(ProvisioningValidator.CREATE_ACCOUNT_CHECK_DOMAIN_COS_AND_FEATURE, emailAddress, acctAttrs);
    }
    if (acctAttrs == null) {
        acctAttrs = new HashMap<String, Object>();
    }
    CallbackContext callbackContext = new CallbackContext(CallbackContext.Op.CREATE);
    callbackContext.setCreatingEntryName(emailAddress);
    AttributeManager.getInstance().preModify(acctAttrs, null, callbackContext, true);
    Account acct = null;
    String dn = null;
    ZLdapContext zlc = null;
    try {
        zlc = LdapClient.getContext(LdapServerType.MASTER, LdapUsage.CREATE_ACCOUNT);
        Domain d = getDomainByAsciiName(domain, zlc);
        if (d == null) {
            throw AccountServiceException.NO_SUCH_DOMAIN(domain);
        }
        if (!d.isLocal()) {
            throw ServiceException.INVALID_REQUEST("domain type must be local", null);
        }
        ZMutableEntry entry = LdapClient.createMutableEntry();
        entry.mapToAttrs(acctAttrs);
        for (int i = 0; i < sInvalidAccountCreateModifyAttrs.length; i++) {
            String a = sInvalidAccountCreateModifyAttrs[i];
            if (entry.hasAttribute(a))
                throw ServiceException.INVALID_REQUEST("invalid attribute for CreateAccount: " + a, null);
        }
        Set<String> ocs;
        if (additionalObjectClasses == null) {
            // We are creating a pure account object, get all object classes for account.
            //
            // If restoring, only add zimbra default object classes, do not add extra
            // ones configured.  After createAccount, the restore code will issue a
            // modifyAttrs call and all object classes in the backed up account will be
            // in the attr map passed to modifyAttrs.
            //
            ocs = LdapObjectClass.getAccountObjectClasses(this, restoring);
        } else {
            // We are creating a "subclass" of account (e.g. calendar resource), get just the
            // zimbra default object classes for account, then add extra object classes needed
            // by the subclass.  All object classes needed by the subclass (calendar resource)
            // were figured out in the createCalendarResource method: including the zimbra
            // default (zimbracalendarResource) and any extra ones configured via
            // globalconfig.zimbraCalendarResourceExtraObjectClass.
            //
            // It doesn't matter if the additionalObjectClasses already contains object classes
            // added by the getAccountObjectClasses(this, true).  When additional object classes
            // are added to the set, duplicated once will only appear once.
            //
            //
            // The "restoring" flag is ignored in this path.
            // When restoring a calendar a resource, the restoring code:
            //     - always calls createAccount, not createCalendarResource
            //     - always pass null for additionalObjectClasses
            //     - like restoring an account, it will call modifyAttrs after the
            //       entry is created, any object classes in the backed up data
            //       will be in the attr map passed to modifyAttrs.
            ocs = LdapObjectClass.getAccountObjectClasses(this, true);
            for (int i = 0; i < additionalObjectClasses.length; i++) ocs.add(additionalObjectClasses[i]);
        }
        boolean skipCountingLicenseQuota = false;
        /* bug 48226
             *
             * Check if any of the OCs in the backup is a structural OC that subclasses
             * our default OC (defined in ZIMBRA_DEFAULT_PERSON_OC).
             * If so, add that OC now while creating the account, because it cannot be modified later.
             */
        if (restoring && origAttrs != null) {
            Object ocsInBackupObj = origAttrs.get(A_objectClass);
            String[] ocsInBackup = StringUtil.toStringArray(ocsInBackupObj);
            String mostSpecificOC = LdapObjectClassHierarchy.getMostSpecificOC(this, ocsInBackup, LdapObjectClass.ZIMBRA_DEFAULT_PERSON_OC);
            if (!LdapObjectClass.ZIMBRA_DEFAULT_PERSON_OC.equalsIgnoreCase(mostSpecificOC)) {
                ocs.add(mostSpecificOC);
            }
            //calendar resource doesn't count against license quota
            if (origAttrs.get(A_zimbraCalResType) != null) {
                skipCountingLicenseQuota = true;
            }
            if (origAttrs.get(A_zimbraIsSystemResource) != null) {
                entry.setAttr(A_zimbraIsSystemResource, "TRUE");
                skipCountingLicenseQuota = true;
            }
            if (origAttrs.get(A_zimbraIsExternalVirtualAccount) != null) {
                entry.setAttr(A_zimbraIsExternalVirtualAccount, "TRUE");
                skipCountingLicenseQuota = true;
            }
        }
        entry.addAttr(A_objectClass, ocs);
        String zimbraIdStr;
        if (uuid == null) {
            zimbraIdStr = LdapUtil.generateUUID();
        } else {
            zimbraIdStr = uuid;
        }
        entry.setAttr(A_zimbraId, zimbraIdStr);
        entry.setAttr(A_zimbraCreateTimestamp, LdapDateUtil.toGeneralizedTime(new Date()));
        // default account status is active
        if (!entry.hasAttribute(Provisioning.A_zimbraAccountStatus)) {
            entry.setAttr(A_zimbraAccountStatus, Provisioning.ACCOUNT_STATUS_ACTIVE);
        }
        Cos cos = null;
        String cosId = entry.getAttrString(Provisioning.A_zimbraCOSId);
        if (cosId != null) {
            cos = lookupCos(cosId, zlc);
            if (!cos.getId().equals(cosId)) {
                cosId = cos.getId();
            }
            entry.setAttr(Provisioning.A_zimbraCOSId, cosId);
        } else {
            String domainCosId = domain != null ? isExternalVirtualAccount(entry) ? d.getDomainDefaultExternalUserCOSId() : d.getDomainDefaultCOSId() : null;
            if (domainCosId != null) {
                cos = get(Key.CosBy.id, domainCosId);
            }
            if (cos == null) {
                cos = getCosByName(isExternalVirtualAccount(entry) ? Provisioning.DEFAULT_EXTERNAL_COS_NAME : Provisioning.DEFAULT_COS_NAME, zlc);
            }
        }
        boolean hasMailTransport = entry.hasAttribute(Provisioning.A_zimbraMailTransport);
        // zimbraMailHost(and zimbraMailTransport) if it is not specified
        if (!hasMailTransport) {
            addMailHost(entry, cos, true);
        }
        // set all the mail-related attrs if zimbraMailHost or zimbraMailTransport was specified
        if (entry.hasAttribute(Provisioning.A_zimbraMailHost) || entry.hasAttribute(Provisioning.A_zimbraMailTransport)) {
            // default mail status is enabled
            if (!entry.hasAttribute(Provisioning.A_zimbraMailStatus)) {
                entry.setAttr(A_zimbraMailStatus, MAIL_STATUS_ENABLED);
            }
            // default account mail delivery address is email address
            if (!entry.hasAttribute(Provisioning.A_zimbraMailDeliveryAddress)) {
                entry.setAttr(A_zimbraMailDeliveryAddress, emailAddress);
            }
        } else {
            throw ServiceException.INVALID_REQUEST("missing " + Provisioning.A_zimbraMailHost + " or " + Provisioning.A_zimbraMailTransport + " for CreateAccount: " + emailAddress, null);
        }
        // amivisAccount requires the mail attr, so we always add it
        entry.setAttr(A_mail, emailAddress);
        // required for ZIMBRA_DEFAULT_PERSON_OC class
        if (!entry.hasAttribute(Provisioning.A_cn)) {
            String displayName = entry.getAttrString(Provisioning.A_displayName);
            if (displayName != null) {
                entry.setAttr(A_cn, displayName);
            } else {
                entry.setAttr(A_cn, localPart);
            }
        }
        // required for ZIMBRA_DEFAULT_PERSON_OC class
        if (!entry.hasAttribute(Provisioning.A_sn)) {
            entry.setAttr(A_sn, localPart);
        }
        entry.setAttr(A_uid, localPart);
        String entryPassword = entry.getAttrString(Provisioning.A_userPassword);
        if (entryPassword != null) {
            //password is a hash i.e. from autoprov; do not set with modify password
            password = null;
        } else if (password != null) {
            //user entered
            checkPasswordStrength(password, null, cos, entry);
        }
        entry.setAttr(Provisioning.A_zimbraPasswordModifiedTime, LdapDateUtil.toGeneralizedTime(new Date()));
        String ucPassword = entry.getAttrString(Provisioning.A_zimbraUCPassword);
        if (ucPassword != null) {
            String encryptedPassword = Account.encrypytUCPassword(entry.getAttrString(Provisioning.A_zimbraId), ucPassword);
            entry.setAttr(Provisioning.A_zimbraUCPassword, encryptedPassword);
        }
        dn = mDIT.accountDNCreate(baseDn, entry.getAttributes(), localPart, domain);
        entry.setDN(dn);
        zlc.createEntry(entry);
        acct = getAccountById(zimbraIdStr, zlc, true);
        if (acct == null) {
            throw ServiceException.FAILURE("unable to get account after creating LDAP account entry: " + emailAddress + ", check ldap log for possible error", null);
        }
        AttributeManager.getInstance().postModify(acctAttrs, acct, callbackContext);
        removeExternalAddrsFromAllDynamicGroups(acct.getAllAddrsSet(), zlc);
        validate(ProvisioningValidator.CREATE_ACCOUNT_SUCCEEDED, emailAddress, acct, skipCountingLicenseQuota);
        if (password != null) {
            setLdapPassword(acct, zlc, password);
        }
        return acct;
    } catch (LdapEntryAlreadyExistException e) {
        throw AccountServiceException.ACCOUNT_EXISTS(emailAddress, dn, e);
    } catch (LdapException e) {
        throw e;
    } catch (AccountServiceException e) {
        throw e;
    } catch (ServiceException e) {
        throw ServiceException.FAILURE("unable to create account: " + emailAddress, e);
    } finally {
        LdapClient.closeContext(zlc);
        if (!restoring && acct != null) {
            for (PostCreateAccountListener listener : ProvisioningExt.getPostCreateAccountListeners()) {
                if (listener.enabled()) {
                    listener.handle(acct);
                }
            }
        }
    }
}
Also used : Account(com.zimbra.cs.account.Account) GuestAccount(com.zimbra.cs.account.GuestAccount) LdapAccount(com.zimbra.cs.account.ldap.entry.LdapAccount) ZMutableEntry(com.zimbra.cs.ldap.ZMutableEntry) LdapEntryAlreadyExistException(com.zimbra.cs.ldap.LdapException.LdapEntryAlreadyExistException) ZLdapContext(com.zimbra.cs.ldap.ZLdapContext) LdapCos(com.zimbra.cs.account.ldap.entry.LdapCos) Cos(com.zimbra.cs.account.Cos) Date(java.util.Date) AccountServiceException(com.zimbra.cs.account.AccountServiceException) AccountServiceException(com.zimbra.cs.account.AccountServiceException) AuthFailedServiceException(com.zimbra.cs.account.AccountServiceException.AuthFailedServiceException) ServiceException(com.zimbra.common.service.ServiceException) CallbackContext(com.zimbra.cs.account.callback.CallbackContext) PostCreateAccountListener(com.zimbra.cs.account.ProvisioningExt.PostCreateAccountListener) LdapDomain(com.zimbra.cs.account.ldap.entry.LdapDomain) Domain(com.zimbra.cs.account.Domain) LdapException(com.zimbra.cs.ldap.LdapException)

Example 63 with ServiceException

use of com.zimbra.common.service.ServiceException in project zm-mailbox by Zimbra.

the class LdapProvisioning method removeDynamicGroupMembers.

private void removeDynamicGroupMembers(LdapDynamicGroup group, String[] members, boolean externalOnly) throws ServiceException {
    if (group.isMembershipDefinedByCustomURL()) {
        throw ServiceException.INVALID_REQUEST(String.format("cannot remove members from dynamic group '%s' with custom memberURL", group.getName()), null);
    }
    String groupId = group.getId();
    List<Account> accts = new ArrayList<Account>();
    List<String> externalAddrs = new ArrayList<String>();
    HashSet<String> failed = new HashSet<String>();
    // check for errors, and put valid accts to the queue
    for (String member : members) {
        String memberName = member.toLowerCase();
        boolean isBadAddr = false;
        try {
            memberName = IDNUtil.toAsciiEmail(memberName);
        } catch (ServiceException e) {
            // if the addr is not a valid email address, maybe they want to
            // remove a bogus addr that somehow got in, just let it through.
            memberName = member;
            isBadAddr = true;
        }
        // always add all addrs to "externalAddrs".
        externalAddrs.add(memberName);
        if (!externalOnly) {
            Account acct = isBadAddr ? null : get(AccountBy.name, member);
            if (acct != null) {
                Set<String> memberOf = acct.getMultiAttrSet(Provisioning.A_zimbraMemberOf);
                if (memberOf.contains(groupId)) {
                    accts.add(acct);
                } else {
                    // else the addr is not in the group, throw exception
                    failed.add(memberName);
                }
            }
        }
    }
    if (!failed.isEmpty()) {
        StringBuilder sb = new StringBuilder();
        Iterator<String> iter = failed.iterator();
        while (true) {
            sb.append(iter.next());
            if (!iter.hasNext())
                break;
            sb.append(",");
        }
        throw AccountServiceException.NO_SUCH_MEMBER(group.getName(), sb.toString());
    }
    ZLdapContext zlc = null;
    try {
        zlc = LdapClient.getContext(LdapServerType.MASTER, LdapUsage.REMOVE_GROUP_MEMBER);
        /*
             * remove internal members
             */
        for (Account acct : accts) {
            Map<String, Object> attrs = new HashMap<String, Object>();
            attrs.put("-" + Provisioning.A_zimbraMemberOf, groupId);
            modifyLdapAttrs(acct, zlc, attrs);
            clearUpwardMembershipCache(acct);
        }
        /*
             * remove external members on the static unit
             */
        LdapDynamicGroup.StaticUnit staticUnit = group.getStaticUnit();
        Set<String> existingAddrs = staticUnit.getMembersSet();
        List<String> addrsToRemove = Lists.newArrayList();
        for (String addr : externalAddrs) {
            if (existingAddrs.contains(addr)) {
                addrsToRemove.add(addr);
            }
        }
        if (!addrsToRemove.isEmpty()) {
            Map<String, String[]> attrs = new HashMap<String, String[]>();
            attrs.put("-" + LdapDynamicGroup.StaticUnit.MEMBER_ATTR, addrsToRemove.toArray(new String[addrsToRemove.size()]));
            modifyLdapAttrs(staticUnit, zlc, attrs);
        }
    } finally {
        LdapClient.closeContext(zlc);
    }
    PermissionCache.invalidateCache();
    cleanGroupMembersCache(group);
}
Also used : Account(com.zimbra.cs.account.Account) GuestAccount(com.zimbra.cs.account.GuestAccount) LdapAccount(com.zimbra.cs.account.ldap.entry.LdapAccount) ZLdapContext(com.zimbra.cs.ldap.ZLdapContext) HashMap(java.util.HashMap) LdapDynamicGroup(com.zimbra.cs.account.ldap.entry.LdapDynamicGroup) ArrayList(java.util.ArrayList) AccountServiceException(com.zimbra.cs.account.AccountServiceException) AuthFailedServiceException(com.zimbra.cs.account.AccountServiceException.AuthFailedServiceException) ServiceException(com.zimbra.common.service.ServiceException) HashSet(java.util.HashSet)

Example 64 with ServiceException

use of com.zimbra.common.service.ServiceException in project zm-mailbox by Zimbra.

the class LdapProvisioning method getIdentitiesByQuery.

private List<Identity> getIdentitiesByQuery(LdapEntry entry, ZLdapFilter filter, ZLdapContext initZlc) throws ServiceException {
    List<Identity> result = new ArrayList<Identity>();
    try {
        String base = entry.getDN();
        ZSearchResultEnumeration ne = helper.searchDir(base, filter, ZSearchControls.SEARCH_CTLS_SUBTREE(), initZlc, LdapServerType.REPLICA);
        while (ne.hasMore()) {
            ZSearchResultEntry sr = ne.next();
            result.add(new LdapIdentity((Account) entry, sr.getDN(), sr.getAttributes(), this));
        }
        ne.close();
    } catch (ServiceException e) {
        throw ServiceException.FAILURE("unable to lookup identity via query: " + filter.toFilterString() + " message: " + e.getMessage(), e);
    }
    return result;
}
Also used : Account(com.zimbra.cs.account.Account) GuestAccount(com.zimbra.cs.account.GuestAccount) LdapAccount(com.zimbra.cs.account.ldap.entry.LdapAccount) AccountServiceException(com.zimbra.cs.account.AccountServiceException) AuthFailedServiceException(com.zimbra.cs.account.AccountServiceException.AuthFailedServiceException) ServiceException(com.zimbra.common.service.ServiceException) ZSearchResultEnumeration(com.zimbra.cs.ldap.ZSearchResultEnumeration) ArrayList(java.util.ArrayList) LdapIdentity(com.zimbra.cs.account.ldap.entry.LdapIdentity) Identity(com.zimbra.cs.account.Identity) ZSearchResultEntry(com.zimbra.cs.ldap.ZSearchResultEntry) LdapIdentity(com.zimbra.cs.account.ldap.entry.LdapIdentity)

Example 65 with ServiceException

use of com.zimbra.common.service.ServiceException in project zm-mailbox by Zimbra.

the class LdapProvisioning method dumpLdapSchema.

@Override
public void dumpLdapSchema(PrintWriter writer) throws ServiceException {
    ZLdapContext zlc = null;
    try {
        zlc = LdapClient.getContext(LdapServerType.MASTER, LdapUsage.GET_SCHEMA);
        ZLdapSchema schema = zlc.getSchema();
        for (ZLdapSchema.ZObjectClassDefinition oc : schema.getObjectClasses()) {
            writer.println(oc.getName());
        }
    // TODO print more stuff
    } catch (ServiceException e) {
        ZimbraLog.account.warn("unable to get LDAP schema", e);
    } finally {
        LdapClient.closeContext(zlc);
    }
}
Also used : ZLdapSchema(com.zimbra.cs.ldap.ZLdapSchema) ZLdapContext(com.zimbra.cs.ldap.ZLdapContext) AccountServiceException(com.zimbra.cs.account.AccountServiceException) AuthFailedServiceException(com.zimbra.cs.account.AccountServiceException.AuthFailedServiceException) ServiceException(com.zimbra.common.service.ServiceException)

Aggregations

ServiceException (com.zimbra.common.service.ServiceException)772 AccountServiceException (com.zimbra.cs.account.AccountServiceException)220 Account (com.zimbra.cs.account.Account)193 MailServiceException (com.zimbra.cs.mailbox.MailServiceException)149 IOException (java.io.IOException)127 Mailbox (com.zimbra.cs.mailbox.Mailbox)122 ArrayList (java.util.ArrayList)107 AuthFailedServiceException (com.zimbra.cs.account.AccountServiceException.AuthFailedServiceException)100 Element (com.zimbra.common.soap.Element)97 HashMap (java.util.HashMap)93 Test (org.junit.Test)89 Provisioning (com.zimbra.cs.account.Provisioning)86 Domain (com.zimbra.cs.account.Domain)60 Folder (com.zimbra.cs.mailbox.Folder)54 Server (com.zimbra.cs.account.Server)53 ItemId (com.zimbra.cs.service.util.ItemId)52 ZLdapContext (com.zimbra.cs.ldap.ZLdapContext)51 ZMailbox (com.zimbra.client.ZMailbox)50 Mountpoint (com.zimbra.cs.mailbox.Mountpoint)46 NoSuchItemException (com.zimbra.cs.mailbox.MailServiceException.NoSuchItemException)44