/** BEGIN COPYRIGHT BLOCK
 * Copyright (C) 2001 Sun Microsystems, Inc.  Used by permission.
 * Copyright (C) 2005 Red Hat, Inc.
 * All rights reserved.
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation version
 * 2.1 of the License.
 *                                                                                  
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *                                                                                  
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 * END COPYRIGHT BLOCK **/

#include <string.h> 
#include <libadminutil/srvutil.h>
#include "libadminutil/admutil-int.h"

#ifdef XP_WIN32
#define strcasecmp stricmp
#define strncasecmp _strnicmp
#endif
 
PR_IMPLEMENT(AttrNameList)
getServerDNList(AdmldapInfo info)
{
  char        *domainDN = NULL, *isie = NULL, *sie = NULL;
  char        *ptr = NULL, *adminName = NULL;
  char        *host = NULL, *siepwd = NULL;
  PsetHndl    domainPset;
  int         errorCode;
  AttrNameList  nl;

  isie = admldapGetISIEDN(info);
  if (!isie) goto err;

  /*
   * ISIE sample:
   * isie: cn=<NAME> Administration Server, cn=Server Group, cn=myhost.example.com, ou=example.com, o=NetscapeRoot
   */
  ptr = strchr(isie, ',');
  if (!ptr) goto err;

  *ptr = '\0'; /* to cut out "<NAME> Administration Server" later */

  sie = admldapGetSIEDN(info);

  ptr++;

  while (*ptr == ' ' &&  *ptr != '\0') ptr++;

  if (*ptr == '\0') goto err;

  domainDN = PL_strdup(ptr);
  if (!domainDN) goto err;

  adminName = strchr(isie, '=');
  if (!adminName) goto err;
  adminName++;

  /* Use domainDN to create a pset */
  host = admldapGetHost(info);
  siepwd = admldapGetSIEPWD(info);
  domainPset = psetRealCreate(info, host,
			      admldapGetPort(info),
			      domainDN,
			      sie,
			      siepwd,
			      NULL,
			      &errorCode);

  if (!domainPset) goto err;

  nl = retrieveSIEs(domainPset, domainDN, adminName);

  psetDelete(domainPset);
  if (isie) PR_Free(isie);
  if (sie) PR_Free(sie);
  if (domainDN) PR_Free(domainDN);
  if (host) PR_Free(host);
  if (siepwd) {
    memset(siepwd, '\0', strlen(siepwd));
    PR_Free(siepwd);
  }
  return nl;

err:
  if (isie) PR_Free(isie);
  if (sie) PR_Free(sie);
  if (domainDN) PR_Free(domainDN);
  if (host) PR_Free(host);
  if (siepwd) {
    memset(siepwd, '\0', strlen(siepwd));
    PR_Free(siepwd);
  }
  return NULL;
}

PR_IMPLEMENT(AttrNameList)
retrieveSIEs(PsetHndl domainPset, char* domainDN, char *adminName)
{
  char          *sieDN = NULL, *name, *sieName, *attrName;
  int           errorCode, i, isieLen;
  ListNodePtr   dnList=NULL, node=NULL;
  AttrNameList  nl, nl1, sieList, childrenList;

  childrenList = psetGetChildren(domainPset, "", &errorCode);
  if (errorCode) return NULL;

  nl = childrenList;
  while ((name = *nl++)) {
    if (strcasecmp(name, adminName)) {
      sieList = psetGetChildren(domainPset, name, &errorCode);
      nl1 = sieList;
      isieLen = PL_strlen(name);
      while ((sieName = *nl1++)) {
	attrName = sieName+isieLen+1;
	if (strcasecmp(attrName, "tasks")) {
	  sieDN = attrName2dn(sieName, domainDN);
	  node = createListNode(sieDN, NULL, 0);
	  if (dnList) listCat(dnList, node);
	  else dnList = node;
	  PR_Free(sieDN);
	  sieDN = NULL;
	}
      }
      if (sieList) deleteAttrNameList(sieList);
    }
  }
  deleteAttrNameList(childrenList);
  /* Construct the returned name list  */
  if (!dnList) return NULL;
  nl = createAttrNameList(listCount(dnList));
  i=0;
  node = dnList;
  while(node) {
    addName(nl, i++, node->name);
    node=node->next;
  }

  listDestroy(dnList);
  return nl;
}

  
PR_IMPLEMENT(AttributeList)
getInstalledServerDNList(AdmldapInfo info)
{
  char          *domainDN = NULL, *isie = NULL, *sie = NULL;
  char          *host = NULL, *siepwd = NULL;
  PsetHndl      domainPset = NULL;
  AttributeList resultList = NULL;
  int           errorCode = 0;

  isie = admldapGetISIEDN(info);
  if (!isie) goto done;

  domainDN=strchr(isie, ',');
  if (!domainDN) goto done;

  domainDN++;

  while (*domainDN == ' ' &&  *domainDN != '\0') domainDN++;

  if (*domainDN == '\0') goto done;

  /* Use domainDN to create a pset */

  host = admldapGetHost(info);
  sie = admldapGetSIEDN(info);
  siepwd = admldapGetSIEPWD(info);
  domainPset = psetRealCreate(info, host,
			      admldapGetPort(info),
			      domainDN,
			      sie,
			      siepwd,
			      NULL,
			      &errorCode);

  if (!domainPset) goto done;

  resultList = retrieveISIEs(domainPset, domainDN);

done:
  psetDelete(domainPset);
  PL_strfree(host);
  PL_strfree(sie);
  if (siepwd) {
    memset(siepwd, '\0', strlen(siepwd));
    PL_strfree(siepwd);
  }
  PL_strfree(isie);

  return resultList;
}

PR_IMPLEMENT(AttributeList)
retrieveISIEs(PsetHndl domainPset, char* domainDN)
{
  char          *name;
  int           errorCode, i, cnt = 0;
  ListNodePtr   dnList=NULL, node=NULL;
  AttributeList resultList = NULL;
  AttrNameList  childrenList, nl;
  char          *nickName;

  childrenList = psetGetChildren(domainPset, "", &errorCode);
  if (errorCode) return NULL;

  nl = childrenList;
  while ((name = *nl++)) {
    char *attrName = PR_smprintf("%s.nsNickName", name);
    nickName = psetGetAttrSingleValue(domainPset, attrName, &errorCode);
    if (nickName) {
      ValueType val;
      char *dn = PR_smprintf("cn=%s, %s", name, domainDN);
      val = (ValueType)PR_Calloc(2, sizeof(char *));
      val[0] = dn;
      node = createListNode(nickName, val, 1);
      if (dnList)  listCat(dnList, node);
      else dnList = node;
      PR_Free(nickName);
    }
    PR_smprintf_free(attrName);
  }
  deleteAttrNameList(childrenList);

  cnt = listCount(dnList);
  node = dnList;
  i = 0;
  if (cnt > 0) {
    resultList = createAttributeList(cnt);
    while (node) {
      addSingleValueAttribute(resultList, 
			      i++, 
			      node->name,
			      ((char**)node->val)[0]);
      node = node->next;
    }
  }

  listDestroy(dnList);

  return resultList;
}

#define IS_A_DELIMITER(x) ((x == ',') || (x == ' ') || (x == '+') || (x == '\0'))

PR_IMPLEMENT(char *)
findSIEDNByID(AdmldapInfo info, const char *serverID)
{
  char *retval = NULL;
  AttrNameList nl = getServerDNList(info);

  if (nl) {
    size_t len = strlen(serverID);
    AttrNameList nlptr = nl;
    while ((retval = *nlptr++)) {
      /* nl is a list of DNs like this:
	 cn=slapd-foo, ...
	 cn=slapd-bar,...
	 cn=admin-serv-localhost,
	 ...
	 serverID is the value of the cn - we have to look for the trailing
	 delimiter to distinguish between slapd-foo slapd-foo2
      */
      if ((len <= strlen(retval+3)) &&
	  !PL_strncasecmp(retval+3, serverID, len) &&
	  (IS_A_DELIMITER(retval[3+len]))) {
	retval = PL_strdup(retval);
	break;
      }
    }
    deleteAttrNameList(nl);
  }

  return retval;
}
