/**
   * Collects data about external IMAP accounts from XML
   *
   * @param is
   * @return ExternalIMAPAccount list of account data containers
   * @throws DocumentException
   * @throws IOException
   * @throws ServiceException
   */
  private Map<accountState, List<ExternalIMAPAccount>> parseExternalIMAPAccounts(
      org.dom4j.Element root, ZimbraSoapContext zsc)
      throws DocumentException, IOException, ServiceException {
    List<ExternalIMAPAccount> idleAccts = new ArrayList<ExternalIMAPAccount>();
    List<ExternalIMAPAccount> runningAccts = new ArrayList<ExternalIMAPAccount>();
    List<ExternalIMAPAccount> finishedAccts = new ArrayList<ExternalIMAPAccount>();
    Map<accountState, List<ExternalIMAPAccount>> accts =
        new HashMap<accountState, List<ExternalIMAPAccount>>();
    Provisioning prov = Provisioning.getInstance();

    for (Iterator userIter = root.elementIterator(AdminExtConstants.E_User); userIter.hasNext(); ) {
      org.dom4j.Element elUser = (org.dom4j.Element) userIter.next();
      String userEmail = "";
      String userLogin = "";
      String userPassword = "";

      for (Iterator userPropsIter = elUser.elementIterator(); userPropsIter.hasNext(); ) {
        org.dom4j.Element el = (org.dom4j.Element) userPropsIter.next();
        /*
         * We support <ExchangeMail> element for compatibility with
         * desktop based Exchange Migration utility <RemoteEmailAddress>
         * takes prevalence over <ExchangeMail> element
         */
        if (AdminExtConstants.E_ExchangeMail.equalsIgnoreCase(el.getName())) {
          userEmail = el.getTextTrim();
        }
        if (AdminExtConstants.E_remoteEmail.equalsIgnoreCase(el.getName())) {
          userEmail = el.getTextTrim();
        }
        if (AdminExtConstants.E_remoteIMAPLogin.equalsIgnoreCase(el.getName())) {
          userLogin = el.getTextTrim();
        }
        if (AdminExtConstants.E_remoteIMAPPassword.equalsIgnoreCase(el.getName())) {
          userPassword = el.getTextTrim();
        }
      }

      Account localAccount = null;
      try {
        localAccount = prov.get(AccountBy.name, userEmail, zsc.getAuthToken());
      } catch (ServiceException se) {
        ZimbraLog.gal.warn("error looking up account", se);
      }

      if (localAccount == null) {
        throw AccountServiceException.NO_SUCH_ACCOUNT(userEmail);
      }
      checkAdminLoginAsRight(zsc, prov, localAccount);

      if (userLogin.length() == 0) {
        userLogin = userEmail;
      }
      // Check if an import is running on this account already
      boolean isRunning = false;
      boolean hasRun = false;
      List<DataSource> sources = Provisioning.getInstance().getAllDataSources(localAccount);
      for (DataSource ds : sources) {
        if (ZimbraBulkProvisionExt.IMAP_IMPORT_DS_NAME.equalsIgnoreCase(ds.getName())
            && ds.getType() == DataSourceType.imap
            && ds.isImportOnly()
            && "1".equalsIgnoreCase(ds.getAttr(Provisioning.A_zimbraDataSourceFolderId))) {
          ImportStatus importStatus = DataSourceManager.getImportStatus(localAccount, ds);
          if (!isRunning) {
            synchronized (importStatus) {
              isRunning = importStatus.isRunning();
              hasRun = importStatus.hasRun();
            }
          }

          if (!hasRun) {
            synchronized (importStatus) {
              hasRun = importStatus.hasRun();
            }
          }

          if (!isRunning) {
            runningAccts.add(
                new ExternalIMAPAccount(userEmail, userLogin, userPassword, localAccount));
            break;
          } else if (hasRun) {
            finishedAccts.add(
                new ExternalIMAPAccount(userEmail, userLogin, userPassword, localAccount));
            break;
          }
        }
      }
      if (!isRunning && !hasRun) {
        idleAccts.add(new ExternalIMAPAccount(userEmail, userLogin, userPassword, localAccount));
      }
    }
    accts.put(accountState.idle, idleAccts);
    accts.put(accountState.running, runningAccts);
    accts.put(accountState.finished, finishedAccts);
    return accts;
  }
  private Map<accountState, List<ExternalIMAPAccount>> getZimbraAccounts(
      Element request, ZimbraSoapContext zsc) throws ServiceException {
    List<Element> acctElems = request.listElements(AdminConstants.E_ACCOUNT);
    Provisioning prov = Provisioning.getInstance();
    List<ExternalIMAPAccount> idleAccts = new ArrayList<ExternalIMAPAccount>();
    List<ExternalIMAPAccount> runningAccts = new ArrayList<ExternalIMAPAccount>();
    List<ExternalIMAPAccount> finishedAccts = new ArrayList<ExternalIMAPAccount>();
    Map<accountState, List<ExternalIMAPAccount>> accts =
        new HashMap<accountState, List<ExternalIMAPAccount>>();
    if (acctElems != null && acctElems.size() > 0) {
      for (Element elem : acctElems) {
        String emailAddress = elem.getAttribute(AdminConstants.A_NAME);
        Account localAccount = null;
        try {
          localAccount = prov.get(AccountBy.name, emailAddress);
        } catch (ServiceException se) {
          ZimbraLog.gal.warn("error looking up account", se);
        }

        if (localAccount == null) {
          throw AccountServiceException.NO_SUCH_ACCOUNT(emailAddress);
        }
        checkAdminLoginAsRight(zsc, prov, localAccount);
        // Check if an import is running on this account already
        boolean isRunning = false;
        boolean hasRun = false;
        List<DataSource> sources = Provisioning.getInstance().getAllDataSources(localAccount);
        for (DataSource ds : sources) {
          if (ZimbraBulkProvisionExt.IMAP_IMPORT_DS_NAME.equalsIgnoreCase(ds.getName())
              && ds.getType() == DataSourceType.imap
              && ds.isImportOnly()
              && "1".equalsIgnoreCase(ds.getAttr(Provisioning.A_zimbraDataSourceFolderId))) {
            ImportStatus importStatus = DataSourceManager.getImportStatus(localAccount, ds);
            if (!isRunning) {
              synchronized (importStatus) {
                isRunning = importStatus.isRunning();
                hasRun = importStatus.hasRun();
              }
            }

            if (!hasRun) {
              synchronized (importStatus) {
                hasRun = importStatus.hasRun();
              }
            }

            if (!isRunning) {
              runningAccts.add(
                  new ExternalIMAPAccount(emailAddress, emailAddress, "", localAccount));
              break;
            } else if (hasRun) {
              finishedAccts.add(
                  new ExternalIMAPAccount(emailAddress, emailAddress, "", localAccount));
              break;
            }
          }
        }
        if (!isRunning && !hasRun) {
          idleAccts.add(new ExternalIMAPAccount(emailAddress, emailAddress, "", localAccount));
        }
      }
    }
    accts.put(accountState.idle, idleAccts);
    accts.put(accountState.running, runningAccts);
    accts.put(accountState.finished, finishedAccts);
    return accts;
  }