/** 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 **/

/*
 * Description (config.c)
 *
 *	This module contains routines used by administration CGI
 *	programs to set/get the attribute(s) of Admin server
 *
 */
#ifdef XP_UNIX
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
#endif

#ifdef XP_UNIX
#   define STRNCASECMP strncasecmp
#   define STRCASECMP  strcasecmp
#   define STRNCMP     strncmp
#   define STRDUP      strdup
#else /* XP_WIN32 */
#   define STRNCASECMP _strnicmp
#   define STRCASECMP  _stricmp
#   define STRNCMP     strncmp
#   define STRDUP      strdup
#endif




#include <prio.h>
#include <stdio.h>
#include <string.h>
#include "plstr.h"
#include "libadminutil/resource.h"
#include "libadminutil/distadm.h"
#include "libadminutil/admutil.h"
#include "libadmsslutil/psetcssl.h"
#include "libadmsslutil/admsslutil.h"

#include "libadminutil/resource.h"

#include "config.h"

static char msgbuf[BUFSIZ]; /* ok - not threaded code */

/*
  properties file name = "config.properties"
 */
#define RESOURCE_FILE "migrateconfig"

#define resource_key(a,b)   a b

#define DBT_NO_METHOD 			    resource_key(RESOURCE_FILE, "1")
#define DBT_UNKNOWN_METHOD 		    resource_key(RESOURCE_FILE, "2")
#define DBT_NO_QUERY_STRING 	    resource_key(RESOURCE_FILE, "3")
#define DBT_ERROR_OPEN_FILE 		resource_key(RESOURCE_FILE, "4")
#define DBT_ERROR_READ_FILE 		resource_key(RESOURCE_FILE, "5") 
#define DBT_ERROR_OPEN_DIR 	        resource_key(RESOURCE_FILE, "6") 
#define DBT_NO_OLD_SERVER_ROOT 	    resource_key(RESOURCE_FILE, "7") 
#define DBT_NO_SERVER_FOUND 		resource_key(RESOURCE_FILE, "8") 
#define DBT_NO_USER_NAME 			resource_key(RESOURCE_FILE, "9") 
#define DBT_NO_USER_DN 		        resource_key(RESOURCE_FILE, "10") 
#define DBT_PSET_CREATE_ERROR 	    resource_key(RESOURCE_FILE, "11") 
#define DBT_PSET_SET_ERROR 		    resource_key(RESOURCE_FILE, "12") 
#define DBT_PSET_ADD_ERROR 		    resource_key(RESOURCE_FILE, "13") 
#define DBT_SSL_INIT_ERROR 		    resource_key(RESOURCE_FILE, "14") 

#define CONVERT_NUMBER 8

char*
getAttributeName(char* oldName) {

  if (!PL_strcasecmp(oldName, "port")) return "configuration.nsServerPort";
  else if (!PL_strcasecmp(oldName, "user")) return "configuration.nsSuiteSpotUser";
  else if (!PL_strcasecmp(oldName, "servername")) return "serverhostname";
  else if (!PL_strcasecmp(oldName, "hosts")) return "configuration.nsAdminAccesshosts";
  else if (!PL_strcasecmp(oldName, "addresses")) return "configuration.nsAdminAccessaddresses";
  else if (!PL_strcasecmp(oldName, "CGIWaitPid")) return "configuration.nsAdminCGIWaitPid";
  else if (!PL_strcasecmp(oldName, "DefaultLanguage")) return "configuration.nsdefaultacceptlanguage.";
  else return NULL;
}

int main(int argc, char *argv[])
{
  int            _ai = ADMUTIL_Init();
  FILE           *fstream;
  char           fileName[256];
  int		 ln;
  int		 stop;
  int		 t;
  char           *oldSR = 0;
  char           error_info[128];
  PsetHndl       pset;
  char           *method;
  int            rv, cnt, i, j, x, errorCode;
  char           *url;
  int            err;
  int            *errp = &err;
  char           *username = 0;
  char           *localAdmin = 0;
  char           *binddn = 0;
  char           *bindpw = 0;
  char           **inputs = 0;
  char           *qs = 0;
  char           *nameptr, *valptr, *val;
  int            setFlag = 0, getFlag = 0, forceSetFlag = 0;
  Resource       *i18nResource = NULL;
  char           *acceptLanguage = "en", *lang=getenv("HTTP_ACCEPT_LANGUAGE");
  AttributeList  resultList, updateList=NULL, addList=NULL;
  AttrNameList   nl;
  AttributePtr   nv;
  char           buf[1024], cpcmd[1024], *tmpptr;
  const char     *errMsg = NULL;
  PRFileInfo     fileInfo;
  const char *configdir = util_get_conf_dir();
  const char *secdir = util_get_security_dir();
#if 0
  int            waitforever = 1;

  while (waitforever);
#endif

  i18nResource = res_find_and_init_resource(PROPERTYDIR, RESOURCE_FILE);

  if (lang) acceptLanguage = strdup(lang);

  memset((void *)errp, 0, sizeof(int));
  method = getenv("REQUEST_METHOD");

  /* Get new port number */
  if (!method || !*method) {
    /* non UI CGI */
    if (i18nResource &&
	(errMsg = res_getstring(i18nResource, DBT_NO_METHOD, acceptLanguage,
				msgbuf, sizeof(msgbuf), NULL))) 
      rpt_err(SYSTEM_ERROR, errMsg, NULL, NULL);
    else rpt_err(SYSTEM_ERROR, "No method is specified", NULL, NULL);
  }
  else if (!strcmp(method, "GET")) {
    /* UI CGI - either upgrade or normal admin CGI */
    qs = getenv("QUERY_STRING");
	
    if (!qs || !*qs) {
      if (i18nResource &&
	  (errMsg = res_getstring(i18nResource, 
				  DBT_NO_QUERY_STRING, 
				  acceptLanguage, msgbuf, sizeof(msgbuf), NULL)))
	rpt_err(INCORRECT_USAGE, errMsg, NULL, NULL);
      else rpt_err(INCORRECT_USAGE, "NO QUERY_STRING DATA", NULL, NULL);
    }
    else {
      get_begin(qs);
    }
  }
  else if (!strcmp(method, "POST")) {
    post_begin(stdin);
  }
  else {
    if (i18nResource &&
	(errMsg = res_getstring(i18nResource,
				DBT_UNKNOWN_METHOD, 
				acceptLanguage, msgbuf, sizeof(msgbuf), NULL)))
      PR_snprintf(error_info, sizeof(error_info), errMsg, method);
    else PR_snprintf(error_info, sizeof(error_info), "Unknown Method (%s)", method);
    rpt_err(INCORRECT_USAGE, error_info, NULL, NULL);
  }

  /* Get UserDN and User Password  */

  rv = ADM_GetUserDNString(&err, &binddn);
  if (rv < 0 || !binddn || !*binddn) {
    rv = ADM_GetCurrentUsername(&err, &username);
    if (rv < 0 || !username || !*username) {
      if (i18nResource &&
	  (errMsg = res_getstring(i18nResource,
				  DBT_NO_USER_NAME,
				  acceptLanguage, msgbuf, sizeof(msgbuf), NULL)))
	 rpt_err(ELEM_MISSING, errMsg, NULL, NULL);
      else rpt_err(ELEM_MISSING, "NO USER NAME", NULL, NULL);
    }
    else {
      /* No DN, maybe it is local super */
      localAdmin = admGetLocalAdmin(NULL, &rv);
      if (localAdmin) {
	if (strcmp(username, localAdmin)) {
	  if (i18nResource &&
	      (errMsg = res_getstring(i18nResource, 
				      DBT_NO_USER_DN,
				      acceptLanguage, msgbuf, sizeof(msgbuf), NULL)))
	    rpt_err(ELEM_MISSING,errMsg, NULL, NULL);
	  else rpt_err(ELEM_MISSING, "NO USER DN!", NULL, NULL);
	}
	else {
	  binddn = NULL;
	  bindpw = NULL;
	}
      }
      else {
	if (i18nResource &&
	    (errMsg = res_getstring(i18nResource,
				    DBT_NO_USER_DN,
				    acceptLanguage, msgbuf, sizeof(msgbuf), NULL)))
	  rpt_err(ELEM_MISSING, errMsg, NULL, NULL);
	else rpt_err(ELEM_MISSING, "NO USER DN!", NULL, NULL);
      }
    }
  }

  if (binddn) rv = ADM_GetCurrentPassword(&err, &bindpw);
  rv = ADMSSL_InitSimple(configdir, secdir, 1);
  if (rv) {
    if (i18nResource &&
	(errMsg = res_getstring(i18nResource,
				DBT_SSL_INIT_ERROR,
				acceptLanguage, msgbuf, sizeof(msgbuf), NULL)))
      rpt_err(APP_ERROR, errMsg, NULL, NULL);
    else rpt_err(APP_ERROR, "SSL related initialization failed", NULL, NULL);
  }

  /* Initialize the pset  */

  pset = psetCreateSSL("admin-serv", 
		       /* configRoot */ configdir,
		       /* userDN */ binddn, 
		       /* passwd */ bindpw,
		       /* errorcode */ &rv);

  if (!pset) {
    PR_snprintf(error_info, sizeof(error_info),
	    "PSET_ERROR_NUMBER: %d\nPSET_ERROR_INFO: %s", 
	    rv,
	    psetErrorString(rv, NULL, msgbuf, sizeof(msgbuf), NULL));
    if (i18nResource &&
	(errMsg = res_getstring(i18nResource,
				DBT_PSET_CREATE_ERROR,
				acceptLanguage, msgbuf, sizeof(msgbuf), NULL))) 
      rpt_err(APP_ERROR, errMsg, NULL, error_info);
    else rpt_err(APP_ERROR, "PSET Creation Failed", NULL, error_info);
  }

  /* Process the input  */

  inputs = get_input_ptr();

  oldSR = get_cgi_var("oldServerRoot", NULL, NULL);

  if (!oldSR) {
    if (i18nResource &&
	(errMsg = res_getstring(i18nResource,
				DBT_NO_OLD_SERVER_ROOT,
				acceptLanguage, msgbuf, sizeof(msgbuf), NULL)))
      rpt_err(INCORRECT_USAGE, errMsg, NULL, NULL);
    else rpt_err(INCORRECT_USAGE, "No old server root specified", NULL, NULL);
  }

  PR_snprintf(fileName, sizeof(fileName), "%s/admin-serv/config/ns-admin.conf", oldSR);

  if(!(fstream = fopen(fileName, "r"))) {
    psetDelete(pset);
    if (i18nResource &&
	(errMsg = res_getstring(i18nResource,
				DBT_ERROR_OPEN_FILE,
				acceptLanguage, msgbuf, sizeof(msgbuf), NULL)))
      PR_snprintf(error_info, sizeof(error_info), errMsg, fileName);
    else PR_snprintf(error_info, sizeof(error_info), "Error open file: %s", fileName);
    rpt_err(SYSTEM_ERROR, error_info, NULL, NULL);
  }

  updateList = createAttributeList(CONVERT_NUMBER);
  if (forceSetFlag) addList = createAttributeList(CONVERT_NUMBER);
  i = 0; j = 0;

  stop=0; ln=0;
  while(!stop)  {
    ++ln;
    switch( (t = admutil_getline(fstream, 1024, ln, buf))) {
    case -1:
      fclose(fstream);
      psetDelete(pset);
      if (i18nResource &&
	  (errMsg = res_getstring(i18nResource,
				  DBT_ERROR_OPEN_FILE,
				  acceptLanguage, msgbuf, sizeof(msgbuf), NULL)))
	PR_snprintf(error_info, sizeof(error_info), errMsg, fileName);
      else PR_snprintf(error_info, sizeof(error_info), "Error reading file: %s", fileName);
      rpt_err(SYSTEM_ERROR, error_info, NULL, NULL);
      return 0;
    case 1:
      fclose(fstream);
      stop=1;
      break;
 
    default:
      valptr = strchr(buf, ' ');
      if (valptr) {
	*valptr = '\0';
	valptr++;
	nameptr = getAttributeName(buf);
      
	if (nameptr) {
	  errorCode = PSET_OP_OK;
	  val = psetGetAttrSingleValue(pset, nameptr, &errorCode);
	  if (errorCode) {
	    if (forceSetFlag) {
	      addSingleValueAttribute(addList, j++, nameptr, valptr);
	    }
	    else j++;
	  }
	  else {
	    addSingleValueAttribute(updateList, i++, nameptr, valptr);
	  }
	  if (!PL_strcmp(nameptr, "configuration.nsServerPort")) {
	    val = psetGetAttrSingleValue(pset, "adminurl", &errorCode);
	    if (val) {
	      char  urlBuf[256];
	      char  *tmpptr;
	      PL_strncpyz(urlBuf, val, sizeof(urlBuf));
	      tmpptr = PL_strrchr(urlBuf, ':');
	      if (tmpptr) {
		tmpptr++;
		*tmpptr = '\0';
		PL_strcatn(urlBuf, sizeof(urlBuf), valptr);
		addSingleValueAttribute(updateList, i++, "adminurl", urlBuf);
	      }
	    }
	  }
	}
      }
    }
  }
  
  errorCode = PSET_OP_OK;
  if (i) errorCode = psetSetAttrList(pset, updateList);
  if (errorCode) {
    psetDelete(pset);
    PR_snprintf(error_info, sizeof(error_info),
	    "PSET_ERROR_NUMBER: %d\nPSET_ERROR_INFO: %s\n", 
	    errorCode,
	    psetErrorString(errorCode, NULL, msgbuf, sizeof(msgbuf), NULL));
    if (i18nResource &&
	(errMsg = res_getstring(i18nResource, 
				DBT_PSET_SET_ERROR, 
				acceptLanguage, msgbuf, sizeof(msgbuf), NULL))) 
      rpt_err(APP_ERROR, errMsg, NULL, error_info);
    else rpt_err(APP_ERROR, "PSET Set Failed", NULL, error_info);
  }

  if (j) {
    for (i=0; i < j; i++) {
      errorCode = psetAddAttribute(pset, 
				   addList[i]->attrName, 
				   addList[i]->attrVal);
      if (errorCode) {
	psetDelete(pset);
	PR_snprintf(error_info, sizeof(error_info),
		"PSET_ERROR_NUMBER: %d\nPSET_ERROR_INFO: %s\n", 
		errorCode,
		psetErrorString(errorCode, NULL, msgbuf, sizeof(msgbuf), NULL));
	if (i18nResource &&
	    (errMsg = res_getstring(i18nResource, 
				    DBT_PSET_ADD_ERROR, 
				    acceptLanguage, msgbuf, sizeof(msgbuf), NULL)))
	  rpt_err(APP_ERROR, errMsg, NULL, error_info);
	else rpt_err(APP_ERROR, "PSET Add Failed", NULL, error_info);
      }
    }
  }
  rpt_success(NULL);

  if (updateList) deleteAttributeList(updateList);
  if (addList) deleteAttributeList(addList);
  psetDelete(pset);
  if (i18nResource) res_destroy_resource(i18nResource);
}
