/** BEGIN COPYRIGHT BLOCK
 * Copyright (C) 2001 Sun Microsystems, Inc.  Used by permission.
 * Copyright (C) 2005 Red Hat, Inc.
 * All rights reserved.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; version 2
 * of the License.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 *
 * END COPYRIGHT BLOCK **/
/*
 * htmladmin.c - HTML Administration framework.
 *
 * All blame to Adam Prishtina (adam@netscape.com)
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <base/util.h>
#include "libadmin/libadmin.h"
#include "libadminutil/distadm.h"
#include "libadminutil/admutil.h"
#include "libadminutil/resource.h"
#include "libadmsslutil/admsslutil.h"
#include "libadmin/cluster.h"
#include "ldap.h"
#include "prnetdb.h"
#include "plstr.h"

#include "config.h"
     
/*
   properties file name = "htmladmin.properties"
*/
#define RESOURCE_FILE "htmladmin"

#define resource_key(a,b)   a b

/* define strings here */
#define DBT_STOP_CONFIRM                 resource_key(RESOURCE_FILE, "1")
#define DBT_ADMIN_STOP_CONFIRM           resource_key(RESOURCE_FILE, "2")
#define DBT_DIRECTORY_STOP_CONFIRM       resource_key(RESOURCE_FILE, "3")

/* html string used under main()*/
#define DBT_MAIN_CONTENT_TYPE            resource_key(RESOURCE_FILE, "10")
#define DBT_MAIN_PAGE_HEADER             resource_key(RESOURCE_FILE, "11")
#define DBT_MAIN_FRAME_HEADER            resource_key(RESOURCE_FILE, "12")
#define DBT_MAIN_FRAME_FOOTER            resource_key(RESOURCE_FILE, "13")
#define DBT_MAIN_MESSAGE_FRAME           resource_key(RESOURCE_FILE, "14")
#define DBT_MAIN_FRAMESET_HEADER         resource_key(RESOURCE_FILE, "15")
#define DBT_MAIN_FRAMESET_BODY           resource_key(RESOURCE_FILE, "16")
#define DBT_MAIN_FRAMESET_FOOTER         resource_key(RESOURCE_FILE, "17")
#define DBT_MAIN_BODY_HEADER             resource_key(RESOURCE_FILE, "18")
#define DBT_MAIN_OPTION_VALUE            resource_key(RESOURCE_FILE, "19")
#define DBT_MAIN_SELECTED                resource_key(RESOURCE_FILE, "20")
#define DBT_MAIN_DEFAULT_VIEW            resource_key(RESOURCE_FILE, "21")
#define DBT_MAIN_BODY_FOOTER             resource_key(RESOURCE_FILE, "22")
#define DBT_MAIN_TOPOLOGY_HEADER         resource_key(RESOURCE_FILE, "23")
#define DBT_MAIN_IMAP                    resource_key(RESOURCE_FILE, "24")
#define DBT_MAIN_POP                     resource_key(RESOURCE_FILE, "25")
#define DBT_MAIN_SMTP                    resource_key(RESOURCE_FILE, "26")
#define DBT_MAIN_TOPOLOGY_BODY_HEADER    resource_key(RESOURCE_FILE, "28")
#define DBT_MAIN_LDAP_ERROR              resource_key(RESOURCE_FILE, "29")
#define DBT_MAIN_TOPOLOGY_BODY_FOOTER    resource_key(RESOURCE_FILE, "30")
#define DBT_MAIN_PAGE_FOOTER             resource_key(RESOURCE_FILE, "31")

/* html string used under stop_server()*/
#define DBT_STOP_SERVER_MESSAGING        resource_key(RESOURCE_FILE, "40")
#define DBT_STOP_SERVER_CMS              resource_key(RESOURCE_FILE, "41")      
#define DBT_STOP_SERVER_AS               resource_key(RESOURCE_FILE, "42")
#define DBT_STOP_SERVER_ERROR            resource_key(RESOURCE_FILE, "43")

/* html string used under start_server()*/
#define DBT_START_SERVER_MESSAGING        resource_key(RESOURCE_FILE, "50")
#define DBT_START_SERVER_CMS              resource_key(RESOURCE_FILE, "51")      
#define DBT_START_SERVER_AS               resource_key(RESOURCE_FILE, "52")
#define DBT_START_SERVER_ERROR            resource_key(RESOURCE_FILE, "53")

/* html string used uder output_topology() */
#define DBT_OUTPUT_TOPOLOGY_JAVA_SCRIPT           resource_key(RESOURCE_FILE, "60")
#define DBT_OUTPUT_TOPOLOGY_TABLE_HEADER          resource_key(RESOURCE_FILE, "61")
#define DBT_OUTPUT_TOPOLOGY_DOMAIN_IMAGE          resource_key(RESOURCE_FILE, "62")
#define DBT_OUTPUT_TOPOLOGY_HOST_IMAGE            resource_key(RESOURCE_FILE, "63")
#define DBT_OUTPUT_TOPOLOGY_SERVER_GROUP_IMAGE    resource_key(RESOURCE_FILE, "64")
#define DBT_OUTPUT_TOPOLOGY_SERVER_IMAGE          resource_key(RESOURCE_FILE, "65")
#define DBT_OUTPUT_TOPOLOGY_LEGACY_SERVER_ID      resource_key(RESOURCE_FILE, "66")
#define DBT_OUTPUT_TOPOLOGY_SERVER_ID             resource_key(RESOURCE_FILE, "67")
#define DBT_OUTPUT_TOPOLOGY_LOCAL_SERVER_ENTRY    resource_key(RESOURCE_FILE, "68")
#define DBT_OUTPUT_TOPOLOGY_SERVER_ENTRY          resource_key(RESOURCE_FILE, "69")
#define DBT_OUTPUT_TOPOLOGY_ADMIN_INFO_LINK       resource_key(RESOURCE_FILE, "70")
#define DBT_OUTPUT_TOPOLOGY_ADMIN_LOG_LINK        resource_key(RESOURCE_FILE, "71")
#define DBT_OUTPUT_TOPOLOGY_STATUS                resource_key(RESOURCE_FILE, "72")
#define DBT_OUTPUT_TOPOLOGY_ON                    resource_key(RESOURCE_FILE, "73")
#define DBT_OUTPUT_TOPOLOGY_OFF                   resource_key(RESOURCE_FILE, "74")
#define DBT_OUTPUT_TOPOLOGY_UNKNOWN               resource_key(RESOURCE_FILE, "75")
#define DBT_OUTPUT_TOPOLOGY_SERVER_RUNNING        resource_key(RESOURCE_FILE, "76")
#define DBT_OUTPUT_TOPOLOGY_SERVER_STOP           resource_key(RESOURCE_FILE, "77")
#define DBT_OUTPUT_TOPOLOGY_DIRECTORY_INFO_LINK   resource_key(RESOURCE_FILE, "78")
#define DBT_OUTPUT_TOPOLOGY_DIRECTORY_LOG_LINK    resource_key(RESOURCE_FILE, "79")
#define DBT_OUTPUT_TOPOLOGY_MSG_INFO_LINK         resource_key(RESOURCE_FILE, "80")
#define DBT_OUTPUT_TOPOLOGY_MSG_LOG_LINK          resource_key(RESOURCE_FILE, "81")
#define DBT_OUTPUT_TOPOLOGY_MSG_LINKS             resource_key(RESOURCE_FILE, "82")
#define DBT_OUTPUT_TOPOLOGY_MSG_SERVICE           resource_key(RESOURCE_FILE, "83")
#define DBT_OUTPUT_TOPOLOGY_MSG_OFF               resource_key(RESOURCE_FILE, "84")
#define DBT_OUTPUT_TOPOLOGY_MSG_ON                resource_key(RESOURCE_FILE, "85")
#define DBT_OUTPUT_TOPOLOGY_MSG_STATUS            resource_key(RESOURCE_FILE, "86")
#define DBT_OUTPUT_TOPOLOGY_ES_ON                 resource_key(RESOURCE_FILE, "87")
#define DBT_OUTPUT_TOPOLOGY_ES_OFF                resource_key(RESOURCE_FILE, "88")
#define DBT_OUTPUT_TOPOLOGY_ES_INFO_LINK          resource_key(RESOURCE_FILE, "89")
#define DBT_OUTPUT_TOPOLOGY_ES_LOG_LINK           resource_key(RESOURCE_FILE, "90")
#define DBT_OUTPUT_TOPOLOGY_CMS_ON                resource_key(RESOURCE_FILE, "91")
#define DBT_OUTPUT_TOPOLOGY_CMS_OFF               resource_key(RESOURCE_FILE, "92")
#define DBT_OUTPUT_TOPOLOGY_CMS_INFO_LINK         resource_key(RESOURCE_FILE, "93")
#define DBT_OUTPUT_TOPOLOGY_CMS_LOG_LINK          resource_key(RESOURCE_FILE, "94")
#define DBT_OUTPUT_TOPOLOGY_OTHER_ON              resource_key(RESOURCE_FILE, "95")
#define DBT_OUTPUT_TOPOLOGY_OTHER_OFF             resource_key(RESOURCE_FILE, "96")
#define DBT_OUTPUT_TOPOLOGY_OTHER_INFO_LINK       resource_key(RESOURCE_FILE, "97")
#define DBT_OUTPUT_TOPOLOGY_OTHER_LOG_LINK        resource_key(RESOURCE_FILE, "98")
#define DBT_OUTPUT_TOPOLOGY_TABLE_FOOTER          resource_key(RESOURCE_FILE, "99")
#define DBT_OUTPUT_TOPOLOGY_STATUS_WITH_REPL      resource_key(RESOURCE_FILE,"100")
#define DBT_OUTPUT_TOPOLOGY_DIRECTORY_REPL_LINK    resource_key(RESOURCE_FILE,"101")



Resource       *i18nResource;
char           *acceptLanguage;

char*
getResourceString(char *key) {
  return (char *)(res_getstring(i18nResource, key, acceptLanguage, NULL, 0, NULL));
}

/*
 * Define constants for topology tree in DS.
 */

#define NETSCAPE_ROOT "o=NetscapeRoot"

#define DOMAIN_OBJTYPE "(objectclass=nsadmindomain)"
#define DOMAIN_ATTR "nsadmindomainname"

#define HOST_OBJTYPE "(objectclass=nshost)"
#define HOST_ATTR "serverhostname"

#define SERVERGROUP_OBJTYPE "(|(objectclass=nsadmingroup)(objectclass=nslegacyadmingroup))"
#define SERVERGROUP_ATTR "nsadmingroupname"

#define ISIE_OBJTYPE "(|(objectclass=nsapplication)(objectclass=nslegacyapplication))"
#define ISIE_PRODNAME_ATTR "nsproductname"
#define ISIE_PRODVER_ATTR "nsproductversion"

#define SIE_OBJTYPE "(|(objectclass=netscapeserver)(objectclass=nslegacyserver))"
#define SIE_SERVERID_ATTR "nsserverid"

#define ADMIN_OBJTYPE "(|(objectclass=nsadminserver)(objectclass=nslegacyadminserver))"
#define ADMIN_HOST "serverhostname"
#define ADMIN_LEGACY_URL "url"

#define ADMINCONF_OBJTYPE "(objectclass=nsadminconfig)"
#define ADMINCONF_SECURITY "nsserversecurity"
#define ADMINCONF_PORT "nsserverport"
#define ADMINCONF_ACCESSLOG "nsaccesslog"
#define ADMINCONF_ERRORLOG "nserrorlog"

#define MSGCONF_OBJTYPE "(objectclass=nsmsgcfglog)"
#define MSGCONF_LOGDIR "nsmsglogdir"
#define MSGCONF_PORT "nsmsgport"

#define MY_PAGE "htmladmin.html"

#define NBUF_SIZE 1024

#define SERVER_PING_RATE 5

/* stolen from ldapserver util.c - need to escape values that may go into
   ldap search filters */
#define UTIL_ESCAPE_NONE      0
#define UTIL_ESCAPE_HEX       1
#define UTIL_ESCAPE_BACKSLASH 2

static int special_filter(unsigned char c)
{
    /*
     * Escape all non-printing chars and double-quotes in addition 
     * to those required by RFC 2254
     */
    return (c < 32 || 
            c > 126 || 
            c == '*' || 
            c == '(' || 
            c == ')' || 
            c == '\\' || 
            c == '"') ? UTIL_ESCAPE_HEX : UTIL_ESCAPE_NONE;
}

static const char*
do_escape_string (
    const char* str, 
    int len,                    /* -1 means str is nul-terminated */
    char buf[BIG_LINE],
    int (*special)(unsigned char)
)
{
    const char* s;
    const char* last;
    int esc;

    if (str == NULL) {
        *buf = '\0'; 
        return buf;
    }

    if (len == -1) len = strlen (str);
    if (len == 0) return str;

    last = str + len - 1;
    for (s = str; s <= last; ++s) {
	if ( (esc = (*special)((unsigned char)*s))) {
	    const char* first = str;
	    char* bufNext = buf;
	    int bufSpace = BIG_LINE - 4;
	    while (1) {
		if (bufSpace < (s - first)) s = first + bufSpace - 1;
		if (s > first) {
		    memcpy (bufNext, first, s - first);
		    bufNext  += (s - first);
		    bufSpace -= (s - first);
		}
		if (s > last) {
		    break;
		}
		do {
		    *bufNext++ = '\\'; --bufSpace;
		    if (bufSpace < 2) {
			memcpy (bufNext, "..", 2);
			bufNext += 2;
			goto bail;
		    }
		    if (esc == UTIL_ESCAPE_BACKSLASH) {
			*bufNext++ = *s; --bufSpace;
		    } else {    /* UTIL_ESCAPE_HEX */
			sprintf (bufNext, "%02x", (unsigned)*(unsigned char*)s);
			bufNext += 2; bufSpace -= 2;
		    }
	        } while (++s <= last && 
                         (esc = (*special)((unsigned char)*s)));
		if (s > last) break;
		first = s;
		while ( (esc = (*special)((unsigned char)*s)) == UTIL_ESCAPE_NONE && s <= last) ++s;
	    }
	  bail:
	    *bufNext = '\0';
	    return buf;
	}
    } 
    return str;
}

const char*
escape_filter_value(const char* str, int len, char buf[BIG_LINE])
{
    return do_escape_string(str,len,buf,special_filter);
}

/* 
 * Get bind DN and bind PW info. 
 */

int get_bindinfo(char **binddn, char **bindpw) {

  int rv;
  int err;
  char *username = 0;
  char *localAdmin = 0;

  rv = ADM_GetUserDNString(&err, binddn); /* & of (*binddn) */
  if (rv < 0 || !*binddn || !**binddn) {
    rv = ADM_GetCurrentUsername(&err, &username);
    if (rv < 0 || !username || !*username)
      exit(0);
    else {
      /* No DN, maybe it is local super */
      localAdmin = admGetLocalAdmin(NULL, &rv);
      if (localAdmin) {
	if (strcmp(username, localAdmin))
	  exit(0);
	else {
	  *binddn = NULL;
	  *bindpw = NULL;
	}
      }
      else
	exit(0);
    }
  }
  
  if (*binddn) rv = ADM_GetCurrentPassword(&err, bindpw);
  return 1;
}


/*
 * Get the AdmldapInfo struct for ldap SDK API.
 */

AdmldapInfo get_adm_ldapinfo(const char *configdir, const char *securitydir) {

  AdmldapInfo ldapInfo = NULL;
  int rv;
  
  ldapInfo = admldapBuildInfo((char *)configdir, &rv);
  if(!ldapInfo)
    exit(0);
  
  rv = ADMSSL_InitSimple((char *)configdir, (char *)securitydir, 1);
  if(rv)
    exit(0);
  
  return(ldapInfo);
}

int sorted_search( char *sortattr, LDAP *ld, const char *base, int scope,
		   const char *filter, char **attrs, int attrsonly, LDAPMessage **res ) {

  int rv;
#if defined(USE_OPENLDAP)
  LDAPSortKey **key;
#else
  LDAPsortkey **key;
#endif
  LDAPControl *control;
  LDAPControl **controls;

  struct timeval tv;

  tv.tv_sec=600;
  tv.tv_usec=600;

  if((rv = ldap_create_sort_keylist(&key, sortattr)) != LDAP_SUCCESS)
    return rv;

  if((rv = ldap_create_sort_control(ld, key, 0, &control)) != LDAP_SUCCESS)
    return rv;

  controls = (LDAPControl **)malloc(2*sizeof(LDAPControl *));
  controls[0] = control;
  controls[1] = NULL;

  ldap_free_sort_keylist(key);

  rv = ldap_search_ext_s(ld, base, scope, filter, attrs, attrsonly,
			 controls, NULL, &tv, 1000, res);
  
  /* free the controls */
  ldap_controls_free(controls);

  return rv;
}

/*
 * Given an SIE, figure out what the URL of its local Admin Server is.
 */

char *get_admin_url(LDAP *server, char *sie) {

  LDAPMessage *result;
  LDAPMessage *entry;
  int ldapError;

  char *group;

  char *security = NULL;
  char *host = NULL;
  char *port = NULL;

  char **vals;
  char url[BIG_LINE];

  char *isie;
  char *temp;

  group = strtok(sie, ",");
  group = strtok(NULL, ",");
  group = strtok(NULL, "\0");
  if (!group) { /* invalid sie */
      return NULL;
  }

  while(*group == ' ')
    group++; /* eliminate spaces */

  /* 
   * Now we're at the server group level. Search for the nsAdminServer object (should only be 1 per server group).
   * Get the server host here.
   */

  if((ldapError = ldap_search_ext_s(server, group, LDAP_SCOPE_SUBTREE,
                                    ADMIN_OBJTYPE, NULL, 0,
                                    NULL, NULL, NULL, -1, &result)) != LDAP_SUCCESS)
    return NULL;

  entry = ldap_first_entry(server, result);
  if (!entry) {
      return NULL;
  }

  if((vals = util_ldap_get_values(server, entry, ADMIN_HOST)) != NULL) {
    host = strdup(vals[0]);
    util_ldap_value_free(vals);
  }

  
  temp = ldap_get_dn(server, entry);
  isie = strtok(temp, ",");
  isie = strtok(NULL, "\0");
  while(*isie == ' ')
    isie++; /* eliminate spaces */

  /*
   * Get the ISIE entry
   */

  if((ldapError = ldap_search_ext_s(server, isie, LDAP_SCOPE_BASE,
                                    "(objectclass=*)", NULL, 0,
                                    NULL, NULL, NULL, -1, &result)) != LDAP_SUCCESS)
    return NULL;

  entry = ldap_first_entry(server, result);
  if (!entry) {
      return NULL;
  }

  /* 
   * Now search the SIE's configuration object to get the port and the security status.
   */

  if((ldapError = ldap_search_ext_s(server, ldap_get_dn(server, entry), LDAP_SCOPE_SUBTREE,
                                    ADMINCONF_OBJTYPE, NULL, 0,
                                    NULL, NULL, NULL, -1, &result)) != LDAP_SUCCESS)
    return NULL;

  entry = ldap_first_entry(server, result);
  if (!entry) {
      return NULL;
  }

  if((vals = util_ldap_get_values(server, entry, ADMINCONF_PORT)) != NULL) {
    port = strdup(vals[0]);
    util_ldap_value_free(vals);
  }

  if((vals = util_ldap_get_values(server, entry, ADMINCONF_SECURITY)) != NULL) {
    security = strdup(vals[0]);
    util_ldap_value_free(vals);
  }

  /* Construct URL. */
  PR_snprintf(url, BIG_LINE, "http%s://%s:%s",
	  (security && !strcmp(security, "on")) ? "s" : "",
	  host,
	  port);

  free(security);
  free(host);
  free(port);

  return strdup(url);

}


int get_host_and_port(LDAP *server, char *sie, LDAPMessage *sie_entry, char **host, int **port) {

  LDAPMessage *result;
  LDAPMessage *entry;
  int ldapError;

  char **vals;
  char sie_conf[BIG_LINE];

  *host=NULL;
  *port=NULL;

  if((vals = util_ldap_get_values(server, sie_entry, ADMIN_HOST)) != NULL) {
    *host = strdup(vals[0]);
    util_ldap_value_free(vals);
  }

  if((vals = util_ldap_get_values(server, sie_entry, ADMINCONF_PORT)) != NULL) {
    *port = (int *)malloc(sizeof(int));
    (*port)[0] = atoi(vals[0]);
    util_ldap_value_free(vals);
  }

  if(*host && *port)
    return 1;
  
  PR_snprintf(sie_conf, BIG_LINE, "cn=configuration, %s",
	  sie);
  
  if((ldapError = ldap_search_ext_s(server, sie_conf, LDAP_SCOPE_BASE,
                                    "(objectclass=*)", NULL, 0,
                                    NULL, NULL, NULL, -1, &result)) != LDAP_SUCCESS)
    return 0;
  
  entry = ldap_first_entry(server, result);
  
  if((vals = util_ldap_get_values(server, entry, ADMIN_HOST)) != NULL) {
    *host = strdup(vals[0]);
    util_ldap_value_free(vals);
  }
  
  if((vals = util_ldap_get_values(server, entry, ADMINCONF_PORT)) != NULL) {
    *port = (int *)malloc(sizeof(int));
    (*port)[0] = atoi(vals[0]);
    util_ldap_value_free(vals);
  }
  
  if(*host && *port)
    return 1;
  else
    return 0;
}




int within_view(char **view_list, char *current_dn) {

  int i;

  /* 
   * No views? Then everything's within view. 
   */

  if(!view_list)
    return 1;

  /* 
   * First, check if current_dn is a subset of any of the dn's in the view list.
   * (i.e. we haven't gotten to the actual view area, but we're on the right path
   *  down the tree and need to print the current dn in the topology)
   * If so, we're within the view.
   */

  i=0;
  while(view_list[i] != NULL) {
    if(strstr(view_list[i], current_dn))
      return 1;
    i++;
  }

  /*
   * If we got here, we're not on our way - check if we're already within the actual view area.
   * Check if any of the view list are a subset of the current dn, 
   * and if so we're within the view.
   */

  i=0;
  while(view_list[i] != NULL) {
    if(strstr(current_dn, view_list[i]))
      return 1;
    i++;
  }

  /* We're completely outside of the view */

  return 0;
}


/*
 * Gets all of a user's "private" views, in addition to all the "public" views.
 */

char **get_all_users_views(LDAP *server, char *binddn, AdmldapInfo ldapInfo) {

  int ldapError;
  char **vals;
  char dn[BIG_LINE];
  char filter[BIG_LINE];
  char *ptr, *ptr2, *ptr3;
  LDAPMessage *entry;
  LDAPMessage *result;

  char **return_array = NULL;
  char **tmp = NULL;
  int i;
  int error = 0;
  char *escaped_binddn = NULL;

  if(!binddn)
    return NULL; /* anonymous bind, no user prefs, no views */

  /* get the last 2 items from SIE DN - this is the domain we'll use to search for Custom Views */
  ptr = admldapGetSIEDN(ldapInfo);
  ptr2 = strrchr(ptr, ',');
  ptr2[0] = '\0';

  ptr3 = strrchr(ptr, ',');
  ptr2[0] = ',';

  ptr3++;
  while(ptr3[0] == ' ')
    ptr3++; /* remove spaces */

  /* First, search private views */
  ldapError = escape_for_dn(binddn, &escaped_binddn);
  if (ldapError) {
    return NULL; /* failed to escape binddn; bail */
  }
  if (NULL == escaped_binddn) {
    PR_snprintf(dn, BIG_LINE, "ou=%s, ou=UserPreferences, %s",
                binddn, ptr3);
  } else {
    PR_snprintf(dn, BIG_LINE, "ou=%s, ou=UserPreferences, %s",
                escaped_binddn, ptr3);
    PR_Free(escaped_binddn);
  }
  PR_snprintf(filter, BIG_LINE, "(&(objectclass=nscustomview))");

  ldapError = ldap_search_ext_s(server, dn, LDAP_SCOPE_SUBTREE,
                                filter, NULL, 0,
                                NULL, NULL, NULL, -1, &result);

  if(ldapError != LDAP_SUCCESS) {
    /* fatal error, bail */
    error = 1;
    goto bail;
  }

  i=0;
  for(entry = ldap_first_entry(server, result);
      entry != NULL;
      entry = ldap_next_entry(server, entry)) {
    
    vals = util_ldap_get_values(server, entry, "nsdisplayname");
    
    if(!vals || !vals[0])
      break;
    
    if(!return_array) {
      return_array = (char **)malloc(sizeof(char *));
      if (!return_array) {
        error = 1;
        goto bail;
      }
      return_array[0] = strdup(vals[0]);
    } else {
      tmp = (char **)realloc(return_array, (i+1)*sizeof(char *));
      if (!tmp) {
        error = 1;
        goto bail;
      }
      return_array = tmp;
      return_array[i] = strdup(vals[0]);
    }
    i++;
  }
  tmp = (char **)realloc(return_array, (i+1)*sizeof(char *));
  if (!tmp) {
    error = 1;
    goto bail;
  }
  return_array = tmp;
  return_array[i] = NULL;

  /* Next, search public views */

  PR_snprintf(dn, BIG_LINE, "ou=Global Preferences, %s", ptr3);
  ldapError = ldap_search_ext_s(server, dn, LDAP_SCOPE_SUBTREE,
                                filter, NULL, 0,
                                NULL, NULL, NULL, -1, &result);
  if((ldapError != LDAP_SUCCESS) && (ldapError != LDAP_NO_SUCH_OBJECT)) {
    /* fatal error, free array, bail */
    for (i=0; return_array && return_array[i]; i++) {
      free((void *)return_array[i]);
    }
    free((void *)return_array);
    return NULL;
  }

  for(entry = ldap_first_entry(server, result);
      entry != NULL;
      entry = ldap_next_entry(server, entry)) {
    
    vals = util_ldap_get_values(server, entry, "nsdisplayname");
    
    if(!vals || !vals[0])
      break;
    
    tmp = (char **)realloc(return_array, (i+1)*sizeof(char *));
    if (!tmp) {
      error = 1;
      goto bail;
    }
    return_array = tmp;
    return_array[i] = strdup(vals[0]);
    i++;
  }
  tmp = (char **)realloc(return_array, (i+1)*sizeof(char *));
  if (!tmp) {
    error = 1;
    goto bail;
  }
  return_array = tmp;
  return_array[i] = NULL;

bail:
  if (error) {
    /* An error occurred, so free the array. */
    for (i=0; return_array && return_array[i]; i++) {
      free((void *)return_array[i]);
    }
    free((void *)return_array);
    return_array = NULL;
  }

  return return_array;
}


char **get_view_list(LDAP *server, char *view, char *binddn, AdmldapInfo ldapInfo) {

  int ldapError;
  char **vals;
  char dn[BIG_LINE];
  char filter[BIG_LINE];
  char escaped_filter[BIG_LINE];
  char *ptr, *ptr2, *ptr3;
  LDAPMessage *result;

  char **return_array = NULL;
  char *current_view;
  int i;

  if(!view)
    return NULL;

  /* get the last 2 items from SIE DN - this is the domain we'll use to search for Custom Views */
  ptr = admldapGetSIEDN(ldapInfo);
  ptr2 = strrchr(ptr, ',');
  ptr2[0] = '\0';

  ptr3 = strrchr(ptr, ',');
  ptr2[0] = ',';

  ptr3++;
  while(ptr3[0] == ' ')
    ptr3++; /* remove spaces */

  PR_snprintf(dn, sizeof(dn), "ou=\"%s\", ou=UserPreferences, %s", binddn, ptr3);
  PR_snprintf(filter, sizeof(filter), "(&(objectclass=nscustomview)(nsdisplayname=%s))", view);
  /* need to escape the filter value because the view value was given by the user and may
	 contain values like = () etc. */
  escape_filter_value(filter, -1, escaped_filter);

  ldapError = ldap_search_ext_s(server, dn, LDAP_SCOPE_SUBTREE,
                                escaped_filter, NULL, 0,
                                NULL, NULL, NULL, -1, &result);

  if(ldapError != LDAP_SUCCESS)
    /* fatal error, bail */
    return NULL;

  vals = util_ldap_get_values(server, result, "nsviewconfiguration");

  if(!vals || !strcmp(vals[0], "<none>")) {
    /* not in the private views, maybe in the public views? */
    
    PR_snprintf(dn, sizeof(dn), "ou=Global Preferences, %s", ptr3); 
    ldapError = ldap_search_ext_s(server, dn, LDAP_SCOPE_SUBTREE,
                                  escaped_filter, NULL, 0,
                                  NULL, NULL, NULL, -1, &result);
    if(ldapError != LDAP_SUCCESS)
      /* fatal error, bail */
      return NULL;

    vals = util_ldap_get_values(server, result, "nsviewconfiguration");    
    if(!vals || !strcmp(vals[0], "<none>"))
      return NULL;
  }

  /* Parse string and put into array. views delimited by "|" */
  current_view = strtok(vals[0], "|");
  if(current_view) {
    return_array = (char **)malloc(sizeof(char *));
    return_array[0] = strdup(current_view);

    i=1;
    while((current_view = strtok(NULL, "|"))) {
      return_array = (char **)realloc(return_array, (i+1)*sizeof(char *));
      return_array[i] = strdup(current_view);
      i++;
    }
    return_array = (char **)realloc(return_array, (i+1)*sizeof(char *));
    return_array[i] = NULL;
  }

  return return_array;
}


LDAP *server_bind(const char *securitydir, char *host, int port, int security, char *binddn, char *bindpw) {

  int ldapError;

  LDAP *server;


  if(!(server = util_ldap_init(securitydir, NULL, host, port, security, 0, NULL))) {
      return NULL;
  }

  if ((ldapError = util_ldap_bind(server, binddn, bindpw, LDAP_SASL_SIMPLE, NULL, NULL, NULL, NULL))
      != LDAP_SUCCESS ) {
    switch (ldapError) {
    case LDAP_INAPPROPRIATE_AUTH:
    case LDAP_INVALID_CREDENTIALS:
    case LDAP_INSUFFICIENT_ACCESS:
      /* authenticate failed: Should not continue */
#ifdef LDAP_DEBUG
      util_ldap_perror( ld, "util_ldap_bind:" );
#endif
      ldap_unbind_ext(server, NULL, NULL);
      return NULL;
    case LDAP_NO_SUCH_OBJECT:
    case LDAP_ALIAS_PROBLEM:
    case LDAP_INVALID_DN_SYNTAX:
#ifdef LDAP_DEBUG
      util_ldap_perror( ld, "util_ldap_bind:" );
#endif
      /* Not a good DN */
      ldap_unbind_ext(server, NULL, NULL);
      return NULL;
    default:
      ldap_unbind_ext(server, NULL, NULL);
      return NULL;
    }
  }

  return server;
}

#if 0 /* NOT USED */
/* rate is specified in seconds */
static int get_topology_refresh_rate(AdmldapInfo admInfo) {

  char *val = NULL;
  char *endptr = NULL;
  int rate = 300;

  if ((val = admldapGetExpressRefreshRate(admInfo))) {
	  rate = strtol(val, &endptr, 10);
	  PL_strfree(val);
  }

  return rate;
}
#endif

/* rate is specified in seconds */
static int get_cgi_timeout_rate(AdmldapInfo admInfo) {

  char *endptr = NULL;
  char *val = NULL;
  int rate = 60;
  
  if ((val = admldapGetExpressCGITimeout(admInfo))) {
	  rate = strtol(val, &endptr, 10);
	  PL_strfree(val);
  }

  return rate;
}



/* 
 * Given a server's host and port, try to connect to it using PR_Connect()
 * Return values:
 * 1 = running
 * 0 = stopped
 * -1 = unknown error
 */
                  
int
server_status(char *host, int port)
{
  PRNetAddr   *netaddr = NULL;
  PRStatus    err;
  PRFileDesc *req_socket= NULL;
  int retcode = 0;

  if (NULL == host) {
    return -1;
  }

  netaddr = (PRNetAddr *)calloc(1, sizeof(PRNetAddr));
  if (NULL == netaddr) {
    rpt_err(APP_ERROR, "Failed to allocate PRNetAddr", NULL, NULL);
    return -1;
  }
  err = PR_StringToNetAddr(host, netaddr);
  if (PR_SUCCESS == err) {
    PR_InitializeNetAddr(PR_IpAddrNull, (PRUint16)port, netaddr);
  } else {
    PRAddrInfo *infop = PR_GetAddrInfoByName(host,
                            PR_AF_UNSPEC, (PR_AI_ADDRCONFIG|PR_AI_NOCANONNAME));
    if (infop) {
      void *iter = NULL;
      memset( netaddr, 0, sizeof( PRNetAddr ));
      /* need just one address */
      iter = PR_EnumerateAddrInfo(iter, infop, (PRUint16)port, netaddr);
      if (NULL == iter) {
         rpt_err(APP_ERROR, "Failed to enumerate addrinfo", NULL, NULL);
         retcode = -1;
      }
      PR_FreeAddrInfo(infop);
    } else {
      rpt_err(APP_ERROR, "Failed to get addrinfo", NULL, NULL);
      retcode = -1;
    }
  }

  if (retcode < 0) {
    free(netaddr);
    return retcode;
  } else {
    req_socket = PR_NewTCPSocket();
    err = PR_Connect(req_socket, netaddr, 10000);
    free(netaddr);
    if (PR_SUCCESS == err) {
      return 1;
    } else {
      return 0;
    }
  }
}


int output_topology(AdmldapInfo ldapInfo,
		    char *binddn,
		    char *bindpw,
		    char *view) {


  char *host = admldapGetHost(ldapInfo);
  int   port = admldapGetPort(ldapInfo);
  int   security = admldapGetSecurity(ldapInfo);
  char *securitydir = admldapGetSecurityDir(ldapInfo);

  LDAP *server;
  int ldapError;

  char **vals;
  char **vals2;

  LDAPMessage *domain_result, *host_result, *servergroup_result, *isie_result, *sie_result;
  LDAPMessage *domain_entry, *host_entry, *servergroup_entry, *isie_entry, *sie_entry;

  char viewparam[BIG_LINE];

  char **view_list;
  int first_servergroup;
  int legacy;
  int i = 0;
  int rc = 0;

  server = server_bind(securitydir, host, port, security, binddn, bindpw);
  PL_strfree(securitydir);
  securitydir = NULL;
  if(!server)
    return -1;

  fprintf(stdout, (const char*)getResourceString(DBT_OUTPUT_TOPOLOGY_JAVA_SCRIPT),
	          getResourceString(DBT_STOP_CONFIRM),
	          getResourceString(DBT_ADMIN_STOP_CONFIRM),
	          getResourceString(DBT_DIRECTORY_STOP_CONFIRM));

  /* Get the view list */
  view_list = get_view_list(server, view, binddn, ldapInfo);

  /* DOMAIN */

  if((ldapError = sorted_search(DOMAIN_ATTR, server, NETSCAPE_ROOT, LDAP_SCOPE_ONELEVEL,
				DOMAIN_OBJTYPE, NULL, 0, &domain_result)) != LDAP_SUCCESS) {
    rc = -1;
    goto bail;
  }


  fprintf(stdout, "%s", getResourceString(DBT_OUTPUT_TOPOLOGY_TABLE_HEADER));

  for(domain_entry = ldap_first_entry(server, domain_result);
      domain_entry != NULL;
      domain_entry = ldap_next_entry(server, domain_entry)) {

    if(!within_view(view_list, ldap_get_dn(server, domain_entry)))
      continue;


    if((vals = util_ldap_get_values(server, domain_entry, DOMAIN_ATTR)) != NULL) {
      fprintf(stdout, 
	      (const char*)getResourceString(DBT_OUTPUT_TOPOLOGY_DOMAIN_IMAGE),
	      vals[0]);
      util_ldap_value_free(vals);
    } else {
      rc = -1;
      goto bail;
    }

    /* HOST */

    if((ldapError = sorted_search(HOST_ATTR, server, ldap_get_dn(server, domain_entry), LDAP_SCOPE_ONELEVEL,
				  HOST_OBJTYPE, NULL, 0, &host_result)) != LDAP_SUCCESS) {
      rc = -1;
      goto bail;
    }
    
    for(host_entry = ldap_first_entry(server, host_result);
	host_entry != NULL;
	host_entry = ldap_next_entry(server, host_entry)) {

      if(!within_view(view_list, ldap_get_dn(server, host_entry)))
	continue;


      if((vals = util_ldap_get_values(server, host_entry, HOST_ATTR)) != NULL) {
	fprintf(stdout, 
		(const char*)getResourceString(DBT_OUTPUT_TOPOLOGY_HOST_IMAGE),
		vals[0]);
	util_ldap_value_free(vals);
      } else {
        rc = -1;
        goto bail;
      }
   
      /* SERVER GROUP */

      if((ldapError = sorted_search(SERVERGROUP_ATTR, server, ldap_get_dn(server, host_entry), LDAP_SCOPE_ONELEVEL,
				    SERVERGROUP_OBJTYPE, NULL, 0, &servergroup_result)) != LDAP_SUCCESS) {
        rc = -1;
        goto bail;
      }

      first_servergroup = 1;
      for(servergroup_entry = ldap_first_entry(server, servergroup_result);
	  servergroup_entry != NULL;
	  servergroup_entry = ldap_next_entry(server, servergroup_entry)) {

	if(!within_view(view_list, ldap_get_dn(server, servergroup_entry)))
	  continue;

	legacy = 0;	
	if((vals = util_ldap_get_values(server, servergroup_entry, "objectclass")) != NULL) {
	  int count=0;
	  while(vals[count]) {
	    if(!strcasecmp(vals[count], "nslegacyadmingroup")) {
	      legacy = 1;
	      break;
	    }
	    count++;
	  }
	  util_ldap_value_free(vals);
	}
	
	if((vals = util_ldap_get_values(server, servergroup_entry, SERVERGROUP_ATTR)) != NULL) {
	  if(first_servergroup) {
	    first_servergroup = 0;
	  }


	  fprintf(stdout,
		  (const char*)getResourceString(DBT_OUTPUT_TOPOLOGY_SERVER_GROUP_IMAGE),
		  vals[0]);
	  util_ldap_value_free(vals);
	} else {
          rc = -1;
          goto bail;
        }
		
	/* ISIE */
	
	if((ldapError = sorted_search(ISIE_PRODNAME_ATTR, server, ldap_get_dn(server, servergroup_entry), LDAP_SCOPE_ONELEVEL,
				      ISIE_OBJTYPE, NULL, 0, &isie_result)) != LDAP_SUCCESS) {
          rc = -1;
          goto bail;
        }
	
	for(isie_entry = ldap_first_entry(server, isie_result);
	    isie_entry != NULL;
	    isie_entry = ldap_next_entry(server, isie_entry)) {
	  
	  if(!within_view(view_list, ldap_get_dn(server, isie_entry)))
	    continue;

	  if((vals = util_ldap_get_values(server, isie_entry, ISIE_PRODNAME_ATTR)) != NULL) {
	    char *img;
	    char *version;

	    if(legacy) {
	      img = strdup("oldservic.gif");
	    }
	    else {
	      if(strstr(ldap_get_dn(server, isie_entry), "Administration"))
		img = strdup("adminics.gif");
	      else if(strstr(ldap_get_dn(server, isie_entry), "Directory"))
		img = strdup("directorysmall.gif");
	      else if(strstr(ldap_get_dn(server, isie_entry), "Messaging"))
		img = strdup("messagingic.gif");
	      else if(strstr(ldap_get_dn(server, isie_entry), "Enterprise"))
		img = strdup("enterpriseic.gif");
	      else if(strstr(ldap_get_dn(server, isie_entry), "Certificate"))
		img = strdup("cert16.gif");
	      else
		img = strdup("oldservic.gif");
	    }

	    if((vals2 = util_ldap_get_values(server, isie_entry, ISIE_PRODVER_ATTR))) {
	      version = (char *)malloc(4+strlen(vals2[0]));
	      sprintf(version, " %s", vals2[0]);
	    }
	    else {
	      version = strdup("");
	    }


	    fprintf(stdout, 
		    (const char*)getResourceString(DBT_OUTPUT_TOPOLOGY_SERVER_IMAGE),
		    img,
		    vals[0], 
		    version);
	    free(img);
	    free(version);
	    util_ldap_value_free(vals);
	    util_ldap_value_free(vals2);
	  } else {
            rc = -1;
            goto bail;
          }

	  /* SIE */
	  
	  if((ldapError = sorted_search(SIE_SERVERID_ATTR, server, ldap_get_dn(server, isie_entry), LDAP_SCOPE_ONELEVEL,
					SIE_OBJTYPE, NULL, 0, &sie_result)) != LDAP_SUCCESS) {
            rc = -1;
            goto bail;
          }
	  
	  for(sie_entry = ldap_first_entry(server, sie_result);
	      sie_entry != NULL;
	      sie_entry = ldap_next_entry(server, sie_entry)) {

	    if(!within_view(view_list, ldap_get_dn(server, sie_entry)))
	      continue;
	    
	    if(view)
	      PR_snprintf(viewparam, sizeof(viewparam), "&view=%s", view);

	    if((vals = util_ldap_get_values(server, sie_entry, SIE_SERVERID_ATTR)) != NULL) {

	      char *admin_url;
	      char *server_host;
	      int *server_port;
	      int running = 0;
	      char *href = NULL;
	      char *info_link;
	      char *log_link;

	      if(legacy) {
		/* show server id, link to 3.x Admin Server page and move on */

		if((vals2 = util_ldap_get_values(server, sie_entry, ADMIN_LEGACY_URL)) != NULL) {

		  fprintf(stdout,
			  (const char*)getResourceString(DBT_OUTPUT_TOPOLOGY_LEGACY_SERVER_ID),
			  vals[0],
			  vals2[0]
			  );
		  
		  util_ldap_value_free(vals2);
		}
		util_ldap_value_free(vals);
		continue;
	      }

	      if(!(admin_url = get_admin_url(server, ldap_get_dn(server, sie_entry))))
		continue;
	      
	      if(!get_host_and_port(server, ldap_get_dn(server, sie_entry), sie_entry, &server_host, &server_port))
		continue;


	      fprintf(stdout,
		      getResourceString(DBT_OUTPUT_TOPOLOGY_SERVER_ID),
		      vals[0]);
		  
	      /* directories to pass info log CGI based on product */
	      if(strstr(ldap_get_dn(server, sie_entry), "Administration")) {
	        char *dn_escaped = htmladmin_strdup_escaped(ldap_get_dn(server, sie_entry));
	        char *val_escaped = htmladmin_strdup_escaped(vals[0]);

		running = server_status(server_host, server_port[0]);
		if(running == 1) {
                  href = PR_smprintf(getResourceString(DBT_OUTPUT_TOPOLOGY_SERVER_ENTRY),
                                     dn_escaped, view ? viewparam : "");
		}

	        info_link = PR_smprintf(getResourceString(DBT_OUTPUT_TOPOLOGY_ADMIN_INFO_LINK),
         	                        admin_url, dn_escaped);

	        log_link = PR_smprintf(getResourceString(DBT_OUTPUT_TOPOLOGY_ADMIN_LOG_LINK),
	                               admin_url, val_escaped);

		fprintf(stdout, (const char*)getResourceString(DBT_OUTPUT_TOPOLOGY_STATUS),
	                info_link, log_link,
	                (running == 1) ? getResourceString(DBT_OUTPUT_TOPOLOGY_ON) : ((running == -1) ?  getResourceString(DBT_OUTPUT_TOPOLOGY_UNKNOWN) : getResourceString(DBT_OUTPUT_TOPOLOGY_OFF)),
			  (running == 1) ? href : "");

	        free((void *)dn_escaped);
	        free((void *)val_escaped);
	        if (running == 1) {
	          PR_smprintf_free((char *)href);
	          href = NULL;
	        }
	        PR_smprintf_free((char *)info_link);
	        PR_smprintf_free((char *)log_link);
	      } else if(strstr(ldap_get_dn(server, sie_entry), "Directory")) {
	        /* 
	         * Directory Server - local config file.
	         * Can't figure out directories from here so pass in the server id and have the CGI guess 
	         */
	      	char *repl_link;
	        char *dn_escaped = htmladmin_strdup_escaped(ldap_get_dn(server, sie_entry));
	        char *val_escaped = htmladmin_strdup_escaped(vals[0]);
	        char *host_escaped = htmladmin_strdup_escaped(host);

		running = server_status(server_host, server_port[0]);
		if(running == 1) {

	          href = PR_smprintf(getResourceString(DBT_OUTPUT_TOPOLOGY_SERVER_RUNNING),
	                             dn_escaped, view ? viewparam : "");
		}
		else if(running == 0) {
	          href = PR_smprintf(getResourceString(DBT_OUTPUT_TOPOLOGY_SERVER_STOP),
	                             dn_escaped, view ? viewparam : "");
		}

	        info_link = PR_smprintf(getResourceString(DBT_OUTPUT_TOPOLOGY_DIRECTORY_INFO_LINK),
	                                admin_url, dn_escaped);

	        log_link = PR_smprintf(getResourceString(DBT_OUTPUT_TOPOLOGY_DIRECTORY_LOG_LINK),
	                               admin_url, val_escaped);

	        repl_link = PR_smprintf(getResourceString(DBT_OUTPUT_TOPOLOGY_DIRECTORY_REPL_LINK),
	                                admin_url, host_escaped, server_port[0], admin_url);

	        fprintf(stdout, 
	                (const char*)getResourceString(DBT_OUTPUT_TOPOLOGY_STATUS_WITH_REPL),
	                repl_link,
	                info_link,
	                log_link,
	                (running == 1) ? getResourceString(DBT_OUTPUT_TOPOLOGY_ON) : ((running == 0) ? getResourceString(DBT_OUTPUT_TOPOLOGY_OFF) : getResourceString(DBT_OUTPUT_TOPOLOGY_UNKNOWN)),
	                (running == 1 || running == 0) ?  href : "");		

	        free((void *)dn_escaped);
	        free((void *)val_escaped);
	        free((void *)host_escaped);
	        if (href) {
	          PR_smprintf_free((char *)href);
	        }
	        PR_smprintf_free((char *)info_link);
	        PR_smprintf_free((char *)log_link);
	        PR_smprintf_free((char *)repl_link);
	      } else if(strstr(ldap_get_dn(server, sie_entry), "Enterprise")) {
		/* 
		 * Enterprise Server - local config file.
		 * Can't figure out directories from here so pass in the server id and have the CGI guess 
		 */
	        char *dn_escaped = htmladmin_strdup_escaped(ldap_get_dn(server, sie_entry));
	        char *val_escaped = htmladmin_strdup_escaped(vals[0]);

		running = server_status(server_host, server_port[0]);

		if(running == 1) {
	          href = PR_smprintf(getResourceString(DBT_OUTPUT_TOPOLOGY_ES_ON),
	                             dn_escaped, view ? viewparam : "");
		}
		else if(running == 0) {
	          href = PR_smprintf(getResourceString(DBT_OUTPUT_TOPOLOGY_ES_OFF),
	                             dn_escaped, view ? viewparam : "");
		}		

	        info_link = PR_smprintf(getResourceString(DBT_OUTPUT_TOPOLOGY_ES_INFO_LINK),
	                                admin_url, dn_escaped);

	        log_link = PR_smprintf(getResourceString(DBT_OUTPUT_TOPOLOGY_ES_LOG_LINK),
	                               admin_url, val_escaped);

	        fprintf(stdout, 
	                (const char*)getResourceString(DBT_OUTPUT_TOPOLOGY_STATUS),
	                info_link, log_link,
	                (running == 1) ? getResourceString(DBT_OUTPUT_TOPOLOGY_ON) : ((running == -1) ?  getResourceString(DBT_OUTPUT_TOPOLOGY_UNKNOWN) : getResourceString(DBT_OUTPUT_TOPOLOGY_OFF)),
	                (running == 1) ? href : "");

	        free((void *)dn_escaped);
	        free((void *)val_escaped);
	        PR_smprintf_free((char *)href);
	        PR_smprintf_free((char *)info_link);
	        PR_smprintf_free((char *)log_link);
	      } else if(strstr(ldap_get_dn(server, sie_entry), "Certificate")) {
		/* 
		 * Certificate Server - local config file.
		 * Can't figure out directories from here so pass in the server id and have the CGI guess 
		 */
		char *dn_escaped = htmladmin_strdup_escaped(ldap_get_dn(server, sie_entry));
		char *val_escaped = htmladmin_strdup_escaped(vals[0]);
		
		running = server_status(server_host, server_port[0]);

		if(running == 1) {
		  href = PR_smprintf(getResourceString(DBT_OUTPUT_TOPOLOGY_CMS_ON),
		                     dn_escaped, view ? viewparam : "");
		}
		else if(running == 0) {
		  href = PR_smprintf(getResourceString(DBT_OUTPUT_TOPOLOGY_CMS_OFF),
		                     dn_escaped, view ? viewparam : "");
		}

		info_link = PR_smprintf(getResourceString(DBT_OUTPUT_TOPOLOGY_CMS_INFO_LINK),
		                        admin_url, dn_escaped);

		log_link = PR_smprintf(getResourceString(DBT_OUTPUT_TOPOLOGY_CMS_LOG_LINK),
		                       admin_url, val_escaped);

		fprintf(stdout, 
		        (const char*)getResourceString(DBT_OUTPUT_TOPOLOGY_STATUS),
		        info_link,
		        log_link,
		        (running == 1) ? getResourceString(DBT_OUTPUT_TOPOLOGY_ON) : ((running == -1) ?  getResourceString(DBT_OUTPUT_TOPOLOGY_UNKNOWN) : getResourceString(DBT_OUTPUT_TOPOLOGY_OFF)),
		        (running == 1) ? href : "");

		free((void *)dn_escaped);
		free((void *)val_escaped);
		PR_smprintf_free((char *)href);
		PR_smprintf_free((char *)info_link);
		PR_smprintf_free((char *)log_link);
	      }

	      fprintf(stdout, "%s", getResourceString(DBT_OUTPUT_TOPOLOGY_TABLE_FOOTER));

	      util_ldap_value_free(vals);
	    } else {
              rc = -1;
              goto bail;
            }

	  } /* SIE LOOP */

	} /* ISIE LOOP */

      } /* SERVER GROUP LOOP */
    } /* HOST LOOP */

  } /* DOMAIN LOOP */

  fprintf(stdout, "</table>\n");

bail:
  for (i=0; view_list && view_list[i]; i++) {
    free((void *)view_list[i]);
  }
  free((void *)view_list);

  return rc;
} /* output_topology */



void start_server(char *admin_url, 
		  char *binddn, 
		  char *bindpw, 
		  char *serverid, 
		  char *service, 
		  AdmldapInfo ldapInfo) {

  PRFileDesc *sockd;
  char *admin_host = NULL; 
  char *admin_port = NULL;

  char *buf = strdup(admin_url);
  char *request = NULL;

  char *cgi_result;
  int errorcode;
  bufstruct *nbuf;

  unsigned char *tmp, *auth;

  nbuf = (bufstruct *) new_buffer(NBUF_SIZE);

  tmp = (unsigned char *)PR_smprintf("%s:%s", binddn, bindpw);
  auth = (unsigned char *)malloc(strlen((char *)tmp)*2+1);
  do_uuencode(tmp, auth, strlen((char *)tmp));
  PR_smprintf_free((char *)tmp);

  if(strstr(admin_url, "https")) {
    admin_host = strtok(buf+8, ":");
    admin_port = strtok(NULL, "\0");
  }
  else {
    admin_host = strtok(buf+7, ":");
    admin_port = strtok(NULL, "\0");
  }

  if(service) {
    /* start a messaging request */
    request = PR_smprintf(getResourceString(DBT_START_SERVER_MESSAGING),
                          serverid, service, (char *)auth);
  }
  else {
    if(!strncmp(serverid, "cert-", 5)) {
      int content_length;
      char *serverid_trimmed_escaped = htmladmin_strdup_escaped(&(serverid[5]));
      
      content_length = strlen("instanceID=") + strlen(serverid) - 5;
         /* minus "cert-" */

      /* start a CMS server - why the heck does it need all these parameters ?!?! */
      request = PR_smprintf(getResourceString(DBT_START_SERVER_CMS), serverid,
                            admin_host, atoi(admin_port), (char *)auth,
                            content_length, serverid_trimmed_escaped);

      free((void *)serverid_trimmed_escaped);
    } else {
      request = PR_smprintf(getResourceString(DBT_START_SERVER_AS),
                            serverid, (char *)auth);
    }
  }

  if(strstr(admin_url, "https")) {
    sockd = make_http_request("https", admin_host, atoi(admin_port), request, get_cgi_timeout_rate(ldapInfo), &errorcode);
  } else {
    sockd = make_http_request("http", admin_host, atoi(admin_port), request, get_cgi_timeout_rate(ldapInfo), &errorcode);    
  }

  
  if (sockd == NULL) {
    goto bail;
  }

  if (parse_http_header(sockd, nbuf, "Administrator") < 0) {
    goto bail;
  }

  while( (cgi_result = get_line_from_fd(sockd, nbuf)) != (char *) NULL)  {
  }

bail:
  free((void *)auth);
  PR_smprintf_free((char *)request);
  return;
}

void stop_server(char *admin_url, 
		 char *binddn, 
		 char *bindpw, 
		 char *serverid, 
		 char *service, 
		 AdmldapInfo ldapInfo) {

  PRFileDesc *sockd;
  char *admin_host = NULL;
  char *admin_port = NULL;

  char *buf = strdup(admin_url);
  char *request = NULL;

  char *cgi_result;
  int errorcode;
  bufstruct *nbuf;

  unsigned char *tmp, *auth;

  nbuf = (bufstruct *) new_buffer(NBUF_SIZE);

  tmp = (unsigned char *)PR_smprintf("%s:%s", binddn, bindpw);
  auth = (unsigned char *)malloc(strlen((char *)tmp)*2+1);
  do_uuencode(tmp, auth, strlen((char *)tmp));
  PR_smprintf_free((char *)tmp);

  if(strstr(admin_url, "https")) {
    admin_host = strtok(buf+8, ":");
    admin_port = strtok(NULL, "\0");
  }
  else {
    admin_host = strtok(buf+7, ":");
    admin_port = strtok(NULL, "\0");
  }


  if(service) {
    /* stop a messaging service */

    request = PR_smprintf(getResourceString(DBT_STOP_SERVER_MESSAGING),
                          serverid, service, (char *)auth);
  }
  else {
    if(!strncmp(serverid, "cert-", 5)) {
      int content_length;
      char *serverid_trimmed_escaped = htmladmin_strdup_escaped(&(serverid[5]));

      content_length = strlen("instanceID=") + strlen(serverid) - 5;
        /* minus "cert-" */

      /* stop a CMS server - why the heck does it need all these parameters ?!?! */
      request = PR_smprintf(getResourceString(DBT_STOP_SERVER_CMS),
                            serverid, admin_host, atoi(admin_port),
                            (char *)auth, content_length, serverid_trimmed_escaped);

      free((void *)serverid_trimmed_escaped);
    } else {
      request = PR_smprintf(getResourceString(DBT_STOP_SERVER_AS),
                            serverid, (char *)auth);
    }
  }

  if(strstr(admin_url, "https")) {
    sockd = make_http_request("https", admin_host, atoi(admin_port), request, get_cgi_timeout_rate(ldapInfo), &errorcode);
  } else {
    sockd = make_http_request("http", admin_host, atoi(admin_port), request, get_cgi_timeout_rate(ldapInfo), &errorcode);    
  }
  
  if (sockd == NULL) {
    goto bail;
  }

  if (parse_http_header(sockd, nbuf, "Administrator") < 0) {
    goto bail;
  }

  while( (cgi_result = get_line_from_fd(sockd, nbuf)) != (char *) NULL)  {
  }

bail:
  PR_smprintf_free((char *)request);
  free((void *)auth);
  return;
}

int main(int argc, char *argv[])
{
    int _ai = ADMUTIL_Init();
    char *m;
    char *operation;
    char *object;
    char *view;
    char viewparam[BIG_LINE];
    char *qs=getenv("QUERY_STRING");

    char *lang=getenv("HTTP_ACCEPT_LANGUAGE");
    char line[BIG_LINE];

    AdmldapInfo ldapInfo;
    char *binddn;
    char *bindpw;
    
    int rv;
    const char *configdir = util_get_conf_dir();
    const char *secdir = util_get_security_dir();

    (void)_ai; /* get rid of unused variable warning */
    i18nResource = res_find_and_init_resource(PROPERTYDIR, RESOURCE_FILE);
    acceptLanguage = "en";
    if (lang) acceptLanguage = strdup(lang);

    m = getenv("REQUEST_METHOD");


    fprintf(stdout, "%s", getResourceString(DBT_MAIN_CONTENT_TYPE));

    if(m && !strcmp(m, "GET")) {

       get_begin(qs);

       operation = get_cgi_var("op", NULL, NULL);
       object = get_cgi_var("obj", NULL, NULL);
       view = get_cgi_var("view", NULL, NULL);

       if(view)
	 PR_snprintf(viewparam, sizeof(viewparam), "&view=%s", view);
          
       /* In all cases, get the custom view. */


       fprintf(stdout, getResourceString(DBT_MAIN_PAGE_HEADER), CAPBRAND);

       if(operation && !strcmp(operation, "index")) {

          /* 
	   * Load the frames.
	   */

	  fprintf(stdout, "%s", getResourceString(DBT_MAIN_FRAME_HEADER));
	  fprintf(stdout, "%s", view ? viewparam : "");
	  fprintf(stdout, "%s", getResourceString(DBT_MAIN_FRAME_FOOTER));

       }
       else if(operation && !strcmp(operation, "empty")) {

	 /* Message frame */
	 fprintf(stdout, "%s", getResourceString(DBT_MAIN_MESSAGE_FRAME));
       }
       else if(operation && !strcmp(operation, "topframepaint")) {
	 FILE *html = open_html_file(MY_PAGE);
	 while(next_html_line(html, line))  {
	   if(parse_line(line, NULL))  {
	     fputs(line, stdout);
	   }
	 }
       }
       else if(operation && !strcmp(operation, "framepaint")) {
	 fprintf(stdout, "%s", getResourceString(DBT_MAIN_FRAMESET_HEADER));
	 fprintf(stdout, "%s", view ? viewparam : "");
	 fprintf(stdout, "%s", getResourceString(DBT_MAIN_FRAMESET_BODY));
	 fprintf(stdout, "%s", view ? viewparam : "");
	 fprintf(stdout, "%s", getResourceString(DBT_MAIN_FRAMESET_FOOTER));
       }
       else if(operation && !strcmp(operation, "viewselect")) {
	 /*
	  * Load the custom view frame.
	  */
	 LDAP *server;
	 char **selections = NULL;
	 int i;
	 int found;
	 char *securitydir;

	 ldapInfo = get_adm_ldapinfo(configdir, secdir);
	 if(!get_bindinfo(&binddn, &bindpw))
	   exit(0);

	 securitydir = admldapGetSecurityDir(ldapInfo);
	 server = server_bind(securitydir, admldapGetHost(ldapInfo),
			      admldapGetPort(ldapInfo),
			      admldapGetSecurity(ldapInfo),
			      binddn,
			      bindpw);
	 PL_strfree(securitydir);
	 if(server)
	   selections = get_all_users_views(server, binddn, ldapInfo);

	 fprintf(stdout, "%s", getResourceString(DBT_MAIN_BODY_HEADER));

	 found=0;
	 i=0;
	 while(selections && selections[i] != NULL) {
	   fprintf(stdout, (const char*)getResourceString(DBT_MAIN_OPTION_VALUE),
		   /*"<option value=\"%s\"%s>%s</option>\n",*/
		   selections[i],
		   (view && !strcmp(selections[i], view)) ? getResourceString(DBT_MAIN_SELECTED) : "",
		   selections[i]);
	   if(view && (!strcmp(selections[i], view)))
	     found=1;
	   i++;
	 }

	 /* default view */

	 fprintf(stdout, (const char*)getResourceString(DBT_MAIN_DEFAULT_VIEW),
		 (!view || !found) ? getResourceString(DBT_MAIN_SELECTED) : "");



	 fprintf(stdout, "%s", getResourceString(DBT_MAIN_BODY_FOOTER));
       }
       else {

          /*
	   * Load the topology.
           */


	 ldapInfo = get_adm_ldapinfo(configdir, secdir);

	 /* Fixing html warning: <HEAD> is already emitted.
	 fprintf(stdout, getResourceString(DBT_MAIN_TOPOLOGY_HEADER),
		 get_topology_refresh_rate(ldapInfo), view ? viewparam : "");
	 */

	 if(!get_bindinfo(&binddn, &bindpw))
	   exit(0);

	 if(operation && !strcmp(operation, "serveractivate")) {

	   /* first turn on or off the server, then load the topology. */
	   int rv;
	   LDAP *server;
	   LDAPMessage *sie_entry, *result;
	   int ldapError;

	   char *host;
	   int *ports, active_port;
	   char *service = NULL;
	   char *admin_url;
	   char **serverid;
	   char *sie;
	   int count, max_count;
	   char *securitydir;

	   if (object) {
	     sie = strdup(object);
	   } else {
		 sie = NULL;
		 goto output_topology;
	   }

	   securitydir = admldapGetSecurityDir(ldapInfo);
	   server = server_bind(securitydir, admldapGetHost(ldapInfo),
				admldapGetPort(ldapInfo),
				admldapGetSecurity(ldapInfo),
				binddn,
				bindpw);
	   PL_strfree(securitydir);
	   if(!server)
	     goto output_topology;

	   if((ldapError = ldap_search_ext_s(server, sie, LDAP_SCOPE_BASE,
                                         SIE_OBJTYPE, NULL, 0,
                                         NULL, NULL, NULL, -1, &result)) != LDAP_SUCCESS)
	     goto output_topology;

	   sie_entry = ldap_first_entry(server, result);

	   if((serverid = util_ldap_get_values(server, sie_entry, SIE_SERVERID_ATTR)) == NULL)
	     goto output_topology;

	   if(!get_host_and_port(server, sie, sie_entry, &host, &ports))
	     goto output_topology;

	   active_port = ports[0];

	   if((admin_url = get_admin_url(server, sie)) == NULL)
	     goto output_topology;

	   count=0;
	   max_count=get_cgi_timeout_rate(ldapInfo)/SERVER_PING_RATE;

	   rv = server_status(host, active_port);
	   if(rv == 1) {
	     /* Server's running, shut it down */
	     stop_server(admin_url, binddn, bindpw, serverid[0], service, ldapInfo);
	     while((server_status(host, active_port) == 1) && (count < max_count)) {
	       sleep(SERVER_PING_RATE);
	       count++;
	     }
	     if(count == max_count) {
	       fprintf(stdout, "%s", getResourceString(DBT_MAIN_TOPOLOGY_BODY_HEADER));
	       fprintf(stdout, "%s", getResourceString(DBT_STOP_SERVER_ERROR));
	       fprintf(stdout, "%s", getResourceString(DBT_MAIN_TOPOLOGY_BODY_FOOTER));
	       fprintf(stdout, "%s", getResourceString(DBT_MAIN_PAGE_FOOTER));
	       return 1;
	     }
	   }
	   else if((rv == 0) && (!strstr(sie, "Administration"))) {
	     /* Server's down, start it up (except for Admin Servers) */
	     start_server(admin_url, binddn, bindpw, serverid[0], service,
					  ldapInfo);
	     while((server_status(host, active_port) == 0) && (count < max_count)) {
	       sleep(SERVER_PING_RATE);
	       count++;
	     }
	     if(count == max_count) {
	       fprintf(stdout, "%s", getResourceString(DBT_MAIN_TOPOLOGY_BODY_HEADER));
	       fprintf(stdout, "%s", getResourceString(DBT_START_SERVER_ERROR));
	       fprintf(stdout, "%s", getResourceString(DBT_MAIN_TOPOLOGY_BODY_FOOTER));
	       fprintf(stdout, "%s", getResourceString(DBT_MAIN_PAGE_FOOTER));
	       return 1;
	     }
	   }
	   /* if unknown, do nothing */
	 } /* turn server on/off */


output_topology:
         fprintf(stdout, "%s", getResourceString(DBT_MAIN_TOPOLOGY_BODY_HEADER));

	 rv = output_topology(ldapInfo,
			      binddn,
			      bindpw,
			      view);

	 if(rv == -1) {
	   fprintf(stdout, "%s", getResourceString(DBT_MAIN_LDAP_ERROR));
	 }

	 fprintf(stdout, "%s", getResourceString(DBT_MAIN_TOPOLOGY_BODY_FOOTER));
       }

       fprintf(stdout, "%s", getResourceString(DBT_MAIN_PAGE_FOOTER));
    }
    return 0;
}
