#include <config.h>
#include <stdio.h>
#ifdef HAVE_PWENT
#include <pwd.h>
#endif
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif

#include "IMSvrCfg.hh"
#include "IMUtil.hh"
#include "IMLog.hh"

bool
IMSvrCfg::get_home_dir(
    string &dir
)
{

#ifdef HAVE_PWENT
    struct passwd *pass;
#  if defined (HAVE_POSIX_GETPWUID_R) || defined (HAVE_NONPOSIX_GETPWUID_R)
#ifndef NSS_BUFLEN_PASSWD
#define NSS_BUFLEN_PASSWD 1024
#endif
    struct passwd pass_buf;
    char buf[NSS_BUFLEN_PASSWD];

#    ifdef HAVE_POSIX_GETPWUID_R
    if (getpwuid_r(geteuid(), &pass_buf, buf, NSS_BUFLEN_PASSWD, &pass) != 0) {
        return false;
    }
#else
    if ((pass = getpwuid_r(geteuid(), &pass_buf, buf, NSS_BUFLEN_PASSWD))
	!= NULL) {
        return false;
    }
#endif
#else /* !HAVE_GETPWUID_R || !HAVE_NONPOSIX_GETPWUID_R */
    if ((pass = getpwuid(geteuid())) == NULL) {
        return false;
    } 
#endif
    dir = string(pass->pw_dir);
    return true;
#else
    return false;
#endif
}
bool
IMSvrCfg::get_process_user(
     string &username
)
{

#ifdef HAVE_PWENT
    struct passwd *pass;
#  if defined (HAVE_POSIX_GETPWUID_R) || defined (HAVE_NONPOSIX_GETPWUID_R)
#ifndef NSS_BUFLEN_PASSWD
#define NSS_BUFLEN_PASSWD 1024
#endif
    struct passwd pass_buf;
    char buf[NSS_BUFLEN_PASSWD];

#    ifdef HAVE_POSIX_GETPWUID_R
    if (getpwuid_r(geteuid(), &pass_buf, buf, NSS_BUFLEN_PASSWD, &pass) != 0) {
        return false;
    }
#else
    if ((pass = getpwuid_r(geteuid(), &pass_buf, buf, NSS_BUFLEN_PASSWD))
	!= NULL) {
        return false;
    }
#endif
#else /* !HAVE_GETPWUID_R || !HAVE_NONPOSIX_GETPWUID_R */
    if ((pass = getpwuid(geteuid())) == NULL) {
        return false;
    } 
#endif
    username = string(pass->pw_name);
    return true;
#else
    return false;
#endif
}

void
IMSvrCfg::initialize()
{
    initstr(IMDIR, "IM main directory.", IIIMLIBDIR);
    initstr(BASICLOCALE, "Locale used by default", "C");
#ifdef WIN32
    initstr(IFPATHNAME, "Language Engine module directory",
	   "D:\\WINNT\\System32\\iiimf");
#else
    initstr(IFPATHNAME, "Language Engine module directory",
	   IIIMLEDIR);
#endif
    initstr(IFNAME, "Language Engine name", "");
    initstr(PORT, "Port or service name", "9010");
    initstr(HOSTNAME, "host name", "localhost");
    initstr(NSMAP_CFG_FILE, "Config file for Namespace Mapping", XMLCONFDIR "/ns_map.cfg");
#ifdef WIN32
    initstr(CONFIGFILE, "Configuration file", "D:\\WINNT\\System32\\iiimd.xml.conf");
#else
    initstr(CONFIGFILE, "Configuration file", XMLCONFDIR "/iiimd.xml.conf");
#endif
#ifdef WIN32
    initstr(LECONFFILE, "LE-specific Configuration file", "D:\\WINNT\\System32\\le.xml.conf");
#else
    initstr(LECONFFILE, "LE-specific Configuration file", XMLCONFDIR "/le.xml.conf");
#endif
    initstr(CONVERSIONKEYS, "Conversion ON keys", "<Ctrl>space");
    initstr(LABEL, "Label type", "numeric");
    initbool(SETTRIGGEROFFKEYS, "set trigger off keys", false);
    // initstr(IMCONFIG, "/usr/lib/iiim/etc/im.config");
    // initbool(DIRECT_XSUNIM, true);
    initstr(LOG_FACILITY, "syslog facility", "USER");
    initstr(LOG_LEVEL, "log level", "NORMAL");
    initstr(MESSAGE_LOCALE, "message locale", "C");
    initnum(LOOKUPROW, "The number of lookup-choice rows.", 4);
    initnum(LOOKUPCOL, "The number of lookup-choice columns.", 4);
    initbool(NODAEMON, "Don't transit to daemon mode", false);
    initbool(USER, "behave as a per-user server", false);
    initbool(DEBUGFLAG, "debug mode", false);
    initstr(VARDIR, "IIIM volatile data directory", "");
#if defined(HAVE_UNIX_SOCKET)
    initstr(UDSFILE, "Use specified unix domain socket", "");
#endif /* HAVE_UNIX_SOCKET */
    initbool(DESKTOP, "exit if no desktop exists", false);
    initbool(PREFERRED_LOADING, "load LEs only you prefer", false);
}

void
IMSvrCfg::
initbool(
    enum IMSvrCfgOpt opt,
    const char* desc,
    bool boolval
)
{
    popts[opt].opt = opt;
    popts[opt].type = ARG_BOOL;
    popts[opt].description = desc;
    popts[opt].v.b = boolval;
}
 
void
IMSvrCfg::
initnum(
    enum IMSvrCfgOpt opt,
    const char* desc,
    int numval
)
{
    popts[opt].opt = opt;
    popts[opt].type = ARG_NUMBER;
    popts[opt].description = desc;
    popts[opt].v.n = numval;
}

void
IMSvrCfg::
initstr(
    enum IMSvrCfgOpt opt,
    const char* desc,
    const char* strval
)
{
    popts[opt].opt = opt;
    popts[opt].type = ARG_STRING;
    popts[opt].description = desc;
    popts[opt].v.s = strval;
}

void
IMSvrCfg::
setbool(
    enum IMSvrCfgOpt opt,
    bool boolval
)
{
    if (popts[opt].type != ARG_BOOL) {
	ERROR_INTERNAL("Invalid argument access.");
    }
    popts[opt].v.b = boolval;
}
 
void
IMSvrCfg::
setnum(
    enum IMSvrCfgOpt opt,
    int numval
)
{
    if (popts[opt].type != ARG_NUMBER) {
	ERROR_INTERNAL("Invalid argument access.");
    }
    popts[opt].v.n = numval;
}

void
IMSvrCfg::
setstr(
    enum IMSvrCfgOpt opt,
    const char* strval
)
{
    if (popts[opt].type != ARG_STRING) {
	ERROR_INTERNAL("Invalid argument access.");
    }
    popts[opt].v.s = strval;
}


bool
IMSvrCfg::
get_boolval(
    enum IMSvrCfgOpt opt
) const
{
    if ((opt >= CFGOPT_LAST)
	|| (popts[opt].type != ARG_BOOL)) {
	ERROR_INTERNAL("Invalid argument access.");
    }

    return popts[opt].v.b;
}

int
IMSvrCfg::
get_numval(
    enum IMSvrCfgOpt opt
) const
{
    if ((opt >= CFGOPT_LAST)
	|| (popts[opt].type != ARG_NUMBER)) {
	ERROR_INTERNAL("Invalid argument access.");
    }

    return popts[opt].v.n;
}

const char*
IMSvrCfg::
get_strval(
    enum IMSvrCfgOpt opt
) const
{
    if ((opt >= CFGOPT_LAST)
	|| (popts[opt].type != ARG_STRING)) {
	ERROR_INTERNAL("Invalid argument access.");
    }

    return popts[opt].v.s.c_str();
}

void
IMSvrCfg::showall() const
{
    int i;
    for (i = 0; i < CFGOPT_LAST; i++) {
	switch(popts[i].type) {
	  case ARG_BOOL:
	   if (popts[i].v.b) {
	       LOG_DEBUG("%s[%d]:true", popts[i].description.c_str(), (int)popts[i].opt);
	   } else {
	       LOG_DEBUG("%s[%d]:false", popts[i].description.c_str(), (int)popts[i].opt);
	   }
	   break;
	  case ARG_NUMBER:
	   LOG_DEBUG("%s[%d]:%d", popts[i].description.c_str(), (int)popts[i].opt, popts[i].v.n);
	   break;
	  case ARG_STRING:
	   LOG_DEBUG("%s[%d]:%s", popts[i].description.c_str(), (int)popts[i].opt, popts[i].v.s.c_str());
	   break;
	  default:
	   ERROR_INTERNAL("Invalid arg type.");
	   break;
	}
    }

    return;
}

IMSvrCfg::IMSvrCfg(
	const IMSvrCfg& base
)
{
    command_name = base.command_name;
    popts = base.popts;
    pbase = &base;
}

IMSvrCfg::IMSvrCfg(
    string cmdname
)
{
    command_name = cmdname;
    popts = new CfgVal[CFGOPT_LAST];
    pbase = NULL;
    initialize();
}

IMSvrCfg::~IMSvrCfg()
{
    if (!pbase) delete[] popts;
}

/* Local Variables: */
/* c-file-style: "iiim-project" */
/* End: */
