/* sipd-config - Setup config global and read configuration 
 *  file from database.
 *   Copyright 1998-2001 by Columbia University.  All rights reserved. 
*/

#include <errno.h>
#include <netdb.h>     /* gethostbyname, etc. */
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/stat.h>  /* mkdir() */
#include <regex.h>
#include <sys/param.h> /* MAXHOSTNAMELEN, MAXPATHLEN */
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include "conf-util.h" /* StartServices */
#include "thread_pool.h"
#include "error.h"
#include "fullpath.h"
#include "log.h"
#include "strdupn.h"

#include "dbapi.h"

#include "config.h"
#include "sipd.h"
#include "sipd-policy.h"

#include "sipd-config.h"
static void SetProxyAndHostNames();
static void InitSSLParameters();

/* Prototypes for external libcine functions without their own header files.
 * (They really ought to have them.) */
extern uid_t uname2id(const char *name);
extern gid_t gname2id(const char *name);
extern void setusergroup(uid_t uid, gid_t gid);
extern int InitCanonicalize();

/* Globals. */
struct commandline_t commandline;
struct config_t config;

/*
 * GetTrueFalse()
 * Get a true or false value from the string.  Print an error if it's
 * neither true nor false; in this case, return false anyway.
 */
static int GetTrueFalse(char *name, char *value)
{
  if (!strcmp(value, "true")) {
    return 1;
  }
  else if (!strcmp(value, "false")) {
    return 0;
  }
  else {
    /* print an error for any other value, but still continue */
    error("ConfigInit", "Invalid %s value %s; must be 'true' or 'false'",
          name, value);
    return 0;
  }
} /* GetTrueFalse */


/* 
 * ConfigUser()
 * Determine if user information is to be retrieved from a SQL Database or 
 * a flat text file.  If from a SQL Database, get all the necessary parameters
 * and create the connection to the SQL Database.
 */
static void ConfigUser()
{
  uri_t table_uri;
  db_err db_ret;
  char *db_ret_str;

  if (config.UserConfig == NULL) {
    fatal("ConfigUser", "No UserConfig configured\n");
  }

  /* New-style database configuration */
  config.database = new_cinema_table(config.UserConfig, &db_ret, &db_ret_str);
  if (config.database == NULL) {
    fatal("ConfigUser", "Could not open database %s: %s\n",
          config.UserConfig, db_ret_str);
  }

  /* Old-style database configuration */
  table_uri = URI_Parse(config.UserConfig);

  if (strcasecmp(table_uri.scheme, "sql") == 0 ||
      strcasecmp(table_uri.scheme, "fastsql") == 0) {
    char *password;
    char *path = "sip";
    password = table_uri.password;
    if ( password != NULL && !strcmp(password,"NULL")) {
      password = NULL;
    }
    if (table_uri.path) {
        path = table_uri.path;
    }
    if (initializeConnection(table_uri.user, password, path,
                             table_uri.host, table_uri.port) != 0) {
      fatal("ConfigUser", "Could not open database %s\n", config.UserConfig);
    }
  }
  else {
    fatal("ConfigUser",
          "Unknown database scheme %s in UserConfig pseudo-URL %s\n",
          table_uri.scheme, config.UserConfig);
  }

  URI_Free(&table_uri);

} /* ConfigUser */


/*
 * SetupConfigDefaults()
 * Setup the default values for config options.
 */
static void SetupConfigDefaults(void)
{
  config.ServerRoot   = NULL;
  config.AuthMethod   = auth_none;
  config.PrivateKey   = strdup("1");      /* Must be non-null */
  config.Realm        = AFIGetOurName(0); 
  config.ErrorLog     = strdup("logs/error_log");
  config.PidFile      = strdup("logs/sipd.pid");
  config.ScriptBase   = strdup("scripts");
  config.ServerName   = strdup("");
  config.UserConfig   = NULL;
  config.expires      = 3600;  /* one hour */
  config.maxexpires   = 86400; /* 24 hours */
  config.uid          = -1;
  config.gid          = -1;
  config.port         = default_sip_port;
  config.timeout      = 30;
  config.cgi_timeout  = 15;
  config.foreign      = L_reject;
  config.defaultreg   = L_redirect;
  config.DisplayAmbiguous = 0; /* by default doesn't display contacts on
                                  ambiguous response */
  config.ProxyName    =  NULL; /* set it after init, as we need to- */
  config.ProxyName6   =  NULL; /* -know whether use_numeric_address = 1*/
  
  config.ProxyRecursion = 0;   /* by default don't recurse on 3xx's while
                                  proxying. */
  config.ThirdPartyReg = 1;    /* Allow third parties to register */
  config.StartPresenceAgent = 1; /* Allow presnece agent */
#ifdef USE_SNMP
  config.AgentxSocketPath = NULL;
  config.StartSnmp = 0;
#endif
  config.RegRespContacts = 1;  /* contact info is sent */
  config.NonceLifeTime = 60;   /* seconds */
  config.ClockSkew    = 300;   /* +- seconds */
  config.EnumRoot     = NULL;
  config.database     = NULL;
  config.TryStateless = 0;
  config.ThreadPoolSize = 128;
  config.RecordRoute = 1;
  
  config.PrimaryIP  = NULL;   /* use INADDR_ANY */
  config.PrimaryIP6 = NULL;   /* use inaddr6_any */

  config.use_canonicalize = 1;
  config.GlobalRefresh = 1800; /* 30 minutes */
  /* by default config.KeyMaterial will be all zeros...suits
   * us fine because StartSSL = false, so others can be null.
  */
  memset(&config.KeyMaterial, 0, sizeof(config.KeyMaterial));

  memset(&config.cinema, 0, sizeof(cinema_config));
} /* SetupConfigDefaults */

static char* field_names[] = { /* dont make this char[][] */
  "server_name", 
  "host_name6",
  "proxy_name",
  "proxy_name6",
  "primary_ip", 
  "primary_ip6",
  "realm",
  "port", 
  "server_root", 
  "numeric_via",
  "error_log", 
  "group_name", 
  "user",
  "pid_file", 
  "script_base",
  "auth_method",
  "private_key",
  "nonce_life_time",
  "clock_skew",
  "cgi_timeout",
  "expires",
  "max_expires",
  "timeout",
  "threadpool_size",
  "foreign_domain",
  "default_reg",
  "display_ambigous",
  "help_resolve",
  "proxy_recursion",
  "third_party_reg",
  "start_presenceagent",
#ifdef USE_SNMP
  "start_snmp",
  "agentx_socket_path",
#endif
  "start_ssl",
  "try_stateless",
  "record_route",
  "enum_root",
  "require_userparam", 
  "use_namemapper",
  "start_trip"
};


/*
 * ReadConfig()
 * Connect to the database, and read the configuration data into config global
 * struct.
 *
 * This function should *not* invoke any actions based on the content of the
 * file, since there may be inter-dependencies among config options.  Instead,
 * invoke them from DoConfigFile(), below, instead.
 *
 * From sipd v1.19+, the configuration file is in the database. so, the
 * database uri should be available in the commandline object. It will
 * be used for reading.
*/
static void ReadConfig()
{
  char *argv[10];              /* words in configuration line */
  int i;                       /* loop variable */
  char buf[2056];    /* sql buffer, field name pointer */
  ResultTable query_result;    
  int rows;
  char *debug_str[] = {"misc", "sql", "net", "sdp", "thread", "qos"};

  strassign(&config.UserConfig, commandline.DatabaseURI);
  
  if (config.UserConfig != NULL) {
    ConfigUser(); /* determine if SQL database or flat file */
  }
  else {
    /* XXX: this should never be executed. */
    fatal("ReadConfig", "Don't know how to load the config info...\n");
  }

  /* Here, database has been setup. so, load configuration information. */
  sprintf(buf, "select ");
  for (i=0; i<sizeof(field_names)/sizeof(char*); i++) {
    strcat(buf, field_names[i]);
    strcat(buf, ",");
  }
  /* remove the last , */
  buf[strlen(buf) -1] = '\0';
  strcat(buf, " from sipd_config");
  if (commandline.ServerName) {
    char temp[128];
    sprintf(temp, " where server_name='%s'", commandline.ServerName);
    strcat(buf, temp);
  }
 
  query_result = rawQuery(buf, &rows);
  
  if (!query_result || rows <= 0) {
    fatal("ReadConfig", "Error reading configuration data. No rows found\n");
  }

  if (rows != 1) {
    fatal("ReadConfig", 
          "Too many rows being returned. Specify server name to use\n");
  }

  for (i=0; i<sizeof(field_names)/sizeof(char*); i++) {
    argv[0] = field_names[i];
    argv[1] = query_result[0][i];

    if (!strcmp(argv[0], "auth_method")) {
      config.AuthMethod = HTTP_AuthenticationMethod(argv[1]);
      if (config.AuthMethod == auth_unknown &&
          strcasecmp(argv[1], "none") == 0) {
        config.AuthMethod = auth_none;
      }
    }
    else if (!strcmp(argv[0], "host_name6") && argv[1]) {
      strassign(&config.HostName6, argv[1]);
    }
    else if (!strcmp(argv[0], "private_key") && argv[1]) {
      strassign(&config.PrivateKey, argv[1]);
    }
    else if (!strcmp(argv[0], "foreign_domain")) {
      if      (!strcmp(argv[1], "proxy")) config.foreign = L_proxy;
      else if (!strcmp(argv[1], "redirect")) config.foreign = L_redirect;
      else if (!strcmp(argv[1], "reject")) config.foreign = L_reject;
      else fatal("ConfigInit", "Invalid ForeignDomain value %s", argv[1]);
    }
    else if (!strcmp(argv[0], "default_reg")) {
      if      (!strcmp(argv[1], "proxy")) config.defaultreg = L_proxy;
      else if (!strcmp(argv[1], "redirect")) config.defaultreg = L_redirect;
      else fatal("ConfigInit", "Invalid DefaultReg value %s", argv[1]);
    }
    else if (!strcmp(argv[0], "error_log") && argv[1]) {
      strassign(&config.ErrorLog, argv[1]);
    }
    else if (!strcmp(argv[0], "expires")) {
      config.expires = atoi(argv[1]);
    }
    else if (!strcmp(argv[0], "max_expires")) {
      config.maxexpires = atoi(argv[1]);
    }
    else if (!strcmp(argv[0], "group_name")) {
      config.gid = gname2id(argv[1]);
    }
    else if (!strcmp(argv[0], "port")) {
      config.port = atoi(argv[1]);
    }
    else if (!strcmp(argv[0], "pid_file") && argv[1]) {
      strassign(&config.PidFile, argv[1]); 
    }
    else if (!strcmp(argv[0], "script_base") && argv[1]) {
      strassign(&config.ScriptBase, argv[1]);
    }
    else if (!strcmp(argv[0], "primary_ip")) {
      strassign(&config.PrimaryIP, argv[1]);
    }
    else if (!strcmp(argv[0], "primary_ip6")) {
      strassign(&config.PrimaryIP6, argv[1]);
    }
    else if (!strcmp(argv[0], "server_root")) {
      strassign(&config.ServerRoot, argv[1]);
    }
    else if (!strcmp(argv[0], "server_name")) {
      strassign(&config.ServerName, argv[1]);
    }
    else if (!strcmp(argv[0], "timeout")) {
      config.timeout = atoi(argv[1]); 
    }
    else if (!strcmp(argv[0], "cgi_timeout")) {
      config.cgi_timeout = atoi(argv[1]);
    }      
    else if (!strcmp(argv[0], "user")) {
      config.uid = uname2id(argv[1]);
    }
    else if (!strcmp(argv[0], "numeric_via")) {
      config.NumericVia = 1;
    }
    else if (!strcmp(argv[0], "display_ambigous")) {
      config.DisplayAmbiguous = GetTrueFalse("DisplayAmbiguous", argv[1]);
    }
    else if (!strcmp(argv[0], "proxy_name") && argv[1]) {
      strassign(&config.ProxyName, argv[1]);
    }
    else if (!strcmp(argv[0], "proxy_name6") && argv[1]) {
      strassign(&config.ProxyName6, argv[1]);
    }
    else if (!strcmp(argv[0], "realm") && argv[1]) {
      strassign(&config.Realm, argv[1]);
    }
    else if (!strcmp(argv[0], "proxy_recursion")) {
      config.ProxyRecursion = GetTrueFalse("ProxyRecursion", argv[1]);
    }
    else if (!strcmp(argv[0], "third_party_reg")) {
      config.ThirdPartyReg = GetTrueFalse("ThirdPartyReg", argv[1]);
    }
    else if (!strcmp(argv[0], "start_presenceagent")) {
      config.StartPresenceAgent = GetTrueFalse("StartPresenceAgent", argv[1]);
    }
#ifdef USE_SNMP
    else if (!strcmp(argv[0], "agentx_socket_path")) {
      strassign(&config.AgentxSocketPath, argv[1]);
    }
    else if (!strcmp(argv[0], "start_snmp")) {
      config.StartSnmp = GetTrueFalse("StartSnmp", argv[1]);
    }
#endif
    else if (!strcmp(argv[0], "nonce_life_time")) {
      int i = atoi(argv[1]);
      if (i >= 0) {
        config.NonceLifeTime = atoi(argv[1]);
      }
    }
    else if (!strcmp(argv[0], "clock_skew")) {
      int i = atoi(argv[1]);
      if (i >= 0) {
        config.ClockSkew = atoi(argv[1]);
      }
    }
    else if (!strcmp(argv[0], "enum_root")) {
      strassign(&config.EnumRoot, argv[1]);
    }
    else if (!strcmp(argv[0], "try_stateless")) {
      config.TryStateless = GetTrueFalse("TryStateless", argv[1]);
    }
    else if (!strcmp(argv[0], "threadpool_size")) {
      config.ThreadPoolSize = atoi(argv[1]);
    }
    else if (!strcmp(argv[0], "record_route")) {
      config.RecordRoute = GetTrueFalse("RecordRoute", argv[1]);
    }
    else if (!strcmp(argv[0], "start_ssl")) {
      config.StartSSL = GetTrueFalse("StartSSL", argv[1]);
    }
    else if (!strcmp(argv[0], "start_trip")) {
      config.StartTrip = GetTrueFalse("StartTrip", argv[1]);
    }
    else if (!strcmp(argv[0], "require_userparam")) {
      config.require_userparam = GetTrueFalse("require_userparam", argv[1]);
    }
    else if (!strcmp(argv[0], "use_namemapper")) {
      config.use_namemapper = GetTrueFalse("use_namemapper", argv[1]);
    }
    else {
      fprintf(stderr, 
              "Warning: parameter %s - null or unrecognized\n",argv[0]);
    }
  } /* for */

  freeResultTable(query_result, rows, sizeof(field_names)/sizeof(char*));

  /* initialize Debug parameters */
  sprintf(buf, "select debug_misc, debug_sql, debug_net, debug_sdp, "
               " debug_thread, debug_qos from debug_config where "
               " server_name='%s'", config.ServerName);
  
  rows = -1;
  query_result = rawQuery(buf, &rows);
  if (rows > 0) {
    for (i=0; i<sizeof(debug_str)/sizeof(char*); i++) {
      DebugAllowModule(debug_str[i], GetTrueFalse("Debug", query_result[0][i]));
    }
  }
  freeResultTable(query_result, rows, 6);
  
  /* initialize the CINEMA parameters */
  sprintf(buf, "select mail_relay, administrator from cinema "
               " where server_name='%s'", config.ServerName);

  rows = -1;
  query_result = rawQuery(buf, &rows);
  if (rows > 0) {
    strassign(&config.cinema.mail_relay, query_result[0][0]);
    strassign(&config.cinema.administrator, query_result[0][1]);
  }
  freeResultTable(query_result, rows, 2);

  if (config.StartSSL) {
    InitSSLParameters();
  }

  SetProxyAndHostNames();

  /* Now, read the log files */
  sprintf(buf, 
          "select request_log, log_format, log_condition from sipd_log "
          " where server_name='%s'", config.ServerName);

  rows = 0;
  query_result = rawQuery(buf, &rows);

  for (i = 0; i<rows; i++) {
    AddLog(query_result[i][0], query_result[i][1], query_result[i][2]);
  }

  freeResultTable(query_result, rows, 3);
  
  return;
} /* ReadConfigFile */


/*
 * DoConfigFile()
 * For items in the configuration file which require actions to be taken,
 * at startup/reload time, invoke them.
 */
static void DoConfigFile(void)
{
  FILE *f;                     /* PID file */

  StartServices(config.ThreadPoolSize);
  if (config.TryStateless) {
    /* Normally the queue size is pool size * 2.
     * We try 6 because in fast stateless mode, we will
     * get 1xx, 2xx, ACK, BYE, and 200 in a short timescale.
    */
    SetQueueSize(config.ThreadPoolSize * 6);
  }

  /*
   * Set the actual ServerRoot.
   * If the ServerRoot is null, DEFAULT_SERVER_ROOT
   * (normally /usr/local/sipd/) is the server root.  
  */ 
  if (config.ServerRoot == NULL) {
      strassign(&config.ServerRoot, DEFAULT_SERVER_ROOT);
  }

  /* Change directories to the deduced ServerRoot.
   * All relative pathnames in the config file are relative to this directory.
   */
  debug(DEBUG_MISC, "DoConfigFile", "Changing directory to %s\n", config.ServerRoot);
  if (chdir(config.ServerRoot) != 0) {
    fatal("DoConfigFile", "Couldn't change directory to %s (from %s)\n",
          config.ServerRoot, getcwd(NULL, MAXPATHLEN));
  }

  if (strcmp(config.ErrorLog, "syslog") == 0) ErrorInit(0);
  /* without the line below, we can't force log to use stderr */
  else ErrorInit(config.ErrorLog);

  debug(DEBUG_MISC, "DoConfigFile", "Writing pid file %s\n", config.PidFile);

  if (!(f = fopen(config.PidFile, "w"))) {
    fatal("ConfigInit", "Could not write pid file %s", config.PidFile);
  }
  else {
    fprintf(f, "%d\n", (int)getpid());
    fclose(f);
  }

  /* Make sure that, if we're running as root, "User" and "Group" have been
   * set. */
  if (geteuid() == 0 && (config.uid == -1 || config.gid == -1)) {
    fatal("DoConfigFile",
          "Running as UID 0, but User and Group not set in %s/sipd_config.",
          config.UserConfig);
  }

#ifdef USE_XERCES_C
  /* Set up CPL */
  cpl_initialize();
#endif

  /* Do this after opening files. Probably can't be reversed. */
  setusergroup(config.uid, config.gid);

  /* Start the loggers */
  StartLogs();

  /* This must be done after database is in. Careful. Dont change order */
  if (InitCanonicalize() != 0) {
    fatal("ConfigInit", "Error executing canonicalizer");
  }

} /* DoConfigFile */


/*
 * ConfigInit()
 * Read configuration file.
 * We open the files (configuration, logs) as the user starting the
 * daemon (typically, root) and then switch to the designated user and
 * group.  User location programs are run as that user rather than root.
 * This function is invoked when SIGHUP is received, to re-load the file.
 * (It's not clear that this is thread-safe, though!)
 */
void ConfigInit(int sig)
{
  SetupConfigDefaults();

  ReadConfig();

  DoConfigFile();
} /* ConfigInit */


/*
 * ConfigCleanup()
 * Clean up before exiting.
 */
void ConfigCleanup(void)
{

  free_valid(config.AgentxSocketPath);
  free_valid(config.EnumRoot);
  free_valid(config.ErrorLog);
  free_valid(config.HostName6);
  free_valid(config.PidFile);
  free_valid(config.PrimaryIP);
  free_valid(config.PrimaryIP6);
  free_valid(config.PrivateKey);
  free_valid(config.ProxyName);
  free_valid(config.ProxyName6);
  free_valid(config.Realm);
  free_valid(config.ScriptBase);
  free_valid(config.ServerName);
  free_valid(config.ServerRoot);
  free_valid(config.UserConfig);

  free_ssl_key(&config.KeyMaterial);

  free_valid(config.cinema.mail_relay);
  free_valid(config.cinema.administrator);

  /* close old-style SQL Connection (if connection exists) */
  closeConnection(); 
  /* Close new-style database connection */
  if (config.database != NULL) {
    free_table(config.database);
  }

  memset(&config, 0, sizeof(config));

  /* Terminate canonicalizer */
  CloseCanonicalize();

#ifdef USE_XERCES_C
  /* Terminate cpl */
  cpl_terminate();
#endif

#if 0
  FreeNonceList(gNonceHead.first);
  gNonceHead.first=NULL;
  gNonceHead.last=NULL;
#endif

  LogClose();
  ErrorClose();
} /* ConfigCleanup */


/* InitSSLParameters
 *  Load the ssl_config table into memory, and set all our
 *  parameters. If an error occurs in loading that table,
 *  set the Config.StartSSL flag to false.
*/
static void InitSSLParameters() {

  char buf[1024];
  int rows = 0;  
  ResultTable query_result;

  sprintf(buf, 
          "select cert_file, random_file, ssl_password, dh_param_file, "
          " ca_list_file, privkey_file from ssl_config "
          " where server_name='%s'", config.ServerName);

  query_result = rawQuery(buf, &rows);

  if (rows > 0) {
    if (query_result[0][0]) {
      strassign(&config.KeyMaterial.CertFile, query_result[0][0]);
    }
    if (query_result[0][1]) {
      strassign(&config.KeyMaterial.RandomFile, query_result[0][1]);
    }
    if (query_result[0][2]) {
      strassign(&config.KeyMaterial.Password, query_result[0][2]);
    }
    if (query_result[0][3]) {
      strassign(&config.KeyMaterial.DHParamFile, query_result[0][3]);
    }
    if (query_result[0][4]) {
      strassign(&config.KeyMaterial.CAListFile, query_result[0][4]);
    }
    if (query_result[0][5]) {
      strassign(&config.KeyMaterial.ServerPrivKey, query_result[0][5]);
    }
  } else {
    error("InitSSLParameters", 
          "Error getting ssl_config from db. Disabling SSL\n");
    config.StartSSL = 0;
    return;
  }

  freeResultTable(query_result, rows, 6);
} /* InitSSLParameters */


/* SetProxyAndHostNames
 *  We have four variables HostName4, HostName6, ProxyName4, ProxyName6.
 *  
 *  There are several possibilities:
 *   1) the database has everything.
 *   2) same as 1, but numeric via mode is on.
 *   3) nothing is there in database.
 *   4) in addition to 1,2,3 system doesnt support v6.
 *   5) in addition to 1,2,3 system has v6 but no valid address is configured.
*/
static void SetProxyAndHostNames() {

 if (config.NumericVia) {
   free_valid(config.ProxyName);
    
   if (config.PrimaryIP)
     strassign(&config.ProxyName, config.PrimaryIP);
   else
     config.ProxyName = AFIGetOurDottedAddress(AF_INET);

    debug(DEBUG_MISC, "ReadConfig", "Proxy name (IPv4) set to %s\n", config.ProxyName);
 }

 if (config.NumericVia && AFIIPv6Active()) { /* skip if ipv6 is not usable */
   char buf[512] = { 0 }; /* the IPv6 dotaddr must be enclosed in [] */
    
   if (config.PrimaryIP6) {
     sprintf(buf, "[%s]", config.PrimaryIP6);
   }
   else {
     char *p6;      
     p6 = AFIGetOurDottedAddress(AF_INET6);
     if (p6) {
       sprintf(buf, "[%s]", p6);
       free(p6);
     }
     else {
       struct sockaddr_storage sin;
       debug(DEBUG_MISC, "sipd_config", 
             "It seems your IPv4 and IPv6 hostnames are different\n");

       sin.ss_family = AF_INET6;
       if (config.HostName6) {
         if (AFIGetAddrByName(&sin, config.HostName6) == 0) {
           if ((p6 = AFIGetDottedAddress((struct sockaddr*)&sin)) != NULL) {
             sprintf(buf, "[%s]", p6);
             free(p6);
           }
         }
         else {
           error("sipd_config", "HostName %s is unresolvable."
                                "Turning off IPv6\n", config.HostName6);
           AFIUseIPv6(0);
         }
       }
       else {
         error("sipd_config", 
               "Unable to get a IPv6 address. Turning IPv6 off\n");
         AFIUseIPv6(0); 
       }
      } /* !if (p6) */
    } /* !if (config.PrimaryIP6) */
       
    if (buf[0] == '[') {
      free_valid(config.ProxyName6);
      strassign(&config.ProxyName6, buf);
      debug(DEBUG_MISC, "ReadConfig", "Proxy name (IPv6) set to %s\n", config.ProxyName6);
    }
  }  /* !(config.NumericVia && AFIIPv6Active) */ 

  if (!config.ProxyName) { /* database did not have a ProxyName and/or
                            * the numeric part was not execed. set it
                            * to hostname or IP. */
    config.ProxyName = AFIGetOurName(0);
  }

  /* no special IPv6 host name was specified. 
   * set it to canonical host name 
  */
  if (!config.HostName6) { 
    config.HostName6 = AFIGetOurName(AF_INET6);
    if (!config.HostName6) {
      if (AFIIPv6Active()) /* error only if it is active */
        error("sipd_config", 
              "Unable to get a IPv6 address. Turning IPv6 off\n");
      AFIUseIPv6(0);
      config.HostName6 = AFIGetOurName(AF_INET); /* default to v4 name */
    }
  }

  if (!config.ProxyName6) { 
    strassign(&config.ProxyName6, config.HostName6);
  }

  return;
}


