New silcconfig library and server parser. Merged silc-newconfig-final.patch.
authorGiovanni Giacobbi <johnny@silcnet.org>
Wed, 13 Feb 2002 11:56:01 +0000 (11:56 +0000)
committerGiovanni Giacobbi <johnny@silcnet.org>
Wed, 13 Feb 2002 11:56:01 +0000 (11:56 +0000)
14 files changed:
CHANGES
apps/silcd/command.c
apps/silcd/packet_receive.c
apps/silcd/packet_send.c
apps/silcd/protocol.c
apps/silcd/server.c
apps/silcd/server_backup.c
apps/silcd/serverconfig.c
apps/silcd/serverconfig.h
apps/silcd/silcd.c
doc/example_silcd.conf.in
lib/silcutil/silcconfig.c
lib/silcutil/silcconfig.h
lib/silcutil/silclog.h

diff --git a/CHANGES b/CHANGES
index 65d6f219f68dd8c9b0a8adf5fed58f62761c3821..f3617b11b2e10d5f8d45abfe4e17c6211a4ed18b 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,16 @@
+Wed Feb 13 12:46:25 CET 2002  Johnny Mnemonic <johnny@themnemonic.org>
+
+       * Merged the new SILC Config library, with the server parsing
+         support.  Read the header file silcconfig.h or the toolkit
+         documentation for the news.  Affected files are
+         doc/example_silcd.conf.in lib/silcutil/silcconfig.[ch]
+         silcd/command.c silcd/packet_receive.c silcd/packet_send.c
+         silcd/protocol.c silcd/server.c silcd/server_backup.c
+         silcd/serverconfig.[ch] silcd/silcd.c.
+
+       * Fixed some silclog documentation.  Affected file is
+         lib/silcutil/silclog.h.
+
 Sun Feb 10 18:11:30 EET 2002  Pekka Riikonen <priikone@silcnet.org>
 
        * The silc_cipher_register, silc_hash_register and
index 3b3a8b5cde781038304a90332b5747b2c7c69bf9..b4d5bcee37adf53669b7e5e77dde3ac515eb6dae 100644 (file)
@@ -2849,10 +2849,10 @@ SILC_SERVER_CMD_FUNC(info)
     memset(info_string, 0, sizeof(info_string));
     snprintf(info_string, sizeof(info_string), 
             "location: %s server: %s admin: %s <%s>",
-            server->config->admin_info->location,
-            server->config->admin_info->server_type,
-            server->config->admin_info->admin_name,
-            server->config->admin_info->admin_email);
+            server->config->server_info->location,
+            server->config->server_info->server_type,
+            server->config->server_info->admin,
+            server->config->server_info->email);
 
     server_info = info_string;
     entry = server->id_entry;
@@ -3526,10 +3526,10 @@ SILC_SERVER_CMD_FUNC(motd)
 
     idp = silc_id_payload_encode(server->id_entry->id, SILC_ID_SERVER);
 
-    if (server->config && server->config->motd && 
-       server->config->motd->motd_file) {
+    if (server->config && server->config->server_info &&
+       server->config->server_info->motd_file) {
       /* Send motd */
-      motd = silc_file_readfile(server->config->motd->motd_file, &motd_len);
+      motd = silc_file_readfile(server->config->server_info->motd_file, &motd_len);
       if (!motd)
        goto out;
       
@@ -4583,7 +4583,7 @@ SILC_SERVER_CMD_FUNC(oper)
   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
   unsigned char *username, *auth;
   uint32 tmp_len;
-  SilcServerConfigSectionAdminConnection *admin;
+  SilcServerConfigSectionAdmin *admin;
   SilcIDListData idata = (SilcIDListData)client;
 
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_OPER, cmd, 1, 2);
@@ -4661,7 +4661,7 @@ SILC_SERVER_CMD_FUNC(silcoper)
   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
   unsigned char *username, *auth;
   uint32 tmp_len;
-  SilcServerConfigSectionAdminConnection *admin;
+  SilcServerConfigSectionAdmin *admin;
   SilcIDListData idata = (SilcIDListData)client;
 
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_SILCOPER, cmd, 1, 2);
index d1f6db8a8c391041b24b8777f72288b2c8d3d338..2f3aa2f7206a5153be05e38422658f1fcd04fba5 100644 (file)
@@ -2499,7 +2499,7 @@ void silc_server_connection_auth_request(SilcServer server,
                                         SilcSocketConnection sock,
                                         SilcPacketContext *packet)
 {
-  SilcServerConfigSectionClientConnection *client = NULL;
+  SilcServerConfigSectionClient *client = NULL;
   uint16 conn_type;
   int ret, port;
   SilcAuthMethod auth_meth;
@@ -2523,11 +2523,11 @@ void silc_server_connection_auth_request(SilcServer server,
   /* Get the authentication method for the client */
   auth_meth = SILC_AUTH_NONE;
   port = server->sockets[server->sock]->port; /* Listenning port */
-  client = silc_server_config_find_client_conn(server->config,
+  client = silc_server_config_find_client(server->config,
                                               sock->ip,
                                               port);
   if (!client)
-    client = silc_server_config_find_client_conn(server->config,
+    client = silc_server_config_find_client(server->config,
                                                 sock->hostname,
                                                 port);
   if (client)
index 2c8786c3a5ada9eafd45c8a1fb44ca8b75334be4..d2d21517068d73afe44e4b0cf78d543a2fad3669 100644 (file)
@@ -1036,13 +1036,14 @@ void silc_server_send_private_message(SilcServer server,
 void silc_server_send_motd(SilcServer server,
                           SilcSocketConnection sock)
 {
-  char *motd;
+  char *motd, *motd_file = NULL;
   uint32 motd_len;
 
-  if (server->config && server->config->motd && 
-      server->config->motd->motd_file) {
+  if (server->config)
+    motd_file = server->config->server_info->motd_file;
 
-    motd = silc_file_readfile(server->config->motd->motd_file, &motd_len);
+  if (motd_file) {
+    motd = silc_file_readfile(motd_file, &motd_len);
     if (!motd)
       return;
 
index d5a287d53275d437c322328f1f6b95d31ea73fc5..a7a1b707d7d1a39000626dbf555ac8f20a52cd2d 100644 (file)
@@ -906,7 +906,7 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth)
 
        /* Remote end is client */
        if (conn_type == SILC_SOCKET_TYPE_CLIENT) {
-         SilcServerConfigSectionClientConnection *client = ctx->cconfig;
+         SilcServerConfigSectionClient *client = ctx->cconfig;
          
          if (client) {
            switch(client->auth_meth) {
@@ -968,7 +968,7 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth)
        
        /* Remote end is server */
        if (conn_type == SILC_SOCKET_TYPE_SERVER) {
-         SilcServerConfigSectionServerConnection *serv = ctx->sconfig;
+         SilcServerConfigSectionServer *serv = ctx->sconfig;
          
          if (serv) {
            switch(serv->auth_meth) {
@@ -1030,7 +1030,7 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth)
        
        /* Remote end is router */
        if (conn_type == SILC_SOCKET_TYPE_ROUTER) {
-         SilcServerConfigSectionServerConnection *serv = ctx->rconfig;
+         SilcServerConfigSectionRouter *serv = ctx->rconfig;
 
          if (serv) {
            switch(serv->auth_meth) {
index d033284d457599c0614e9386425bcbd3794b2d38..f0ed13f8e6b1950302bfdb8045d0f1e150ffcdb1 100644 (file)
@@ -115,21 +115,20 @@ int silc_server_init(SilcServer server)
   SilcServerID *id;
   SilcServerEntry id_entry;
   SilcIDListPurge purge;
-  SilcServerConfigSectionListenPort *listen;
 
   SILC_LOG_DEBUG(("Initializing server"));
   assert(server);
   assert(server->config);
 
   /* Set public and private keys */
-  if (!server->config->server_keys ||
-      !server->config->server_keys->public_key || 
-      !server->config->server_keys->private_key) {
+  if (!server->config->server_info ||
+      !server->config->server_info->public_key || 
+      !server->config->server_info->private_key) {
     SILC_LOG_ERROR(("Server public key and/or private key does not exist"));
     return FALSE;
   }
-  server->public_key = server->config->server_keys->public_key;
-  server->private_key = server->config->server_keys->private_key;
+  server->public_key = server->config->server_info->public_key;
+  server->private_key = server->config->server_info->private_key;
 
   /* XXX After server is made as Silc Server Library this can be given
      as argument, for now this is hard coded */
@@ -141,17 +140,14 @@ int silc_server_init(SilcServer server)
   server->params->protocol_timeout = 60;
   server->params->require_reverse_mapping = FALSE;
 
-  /* Set log files where log message should be saved. */
-  server->config->server = server;
   /* Register all configured ciphers, PKCS and hash functions. */
-  if (!silc_server_config_register_ciphers(server->config))
+  if (!silc_server_config_register_ciphers(server))
     silc_cipher_register_default();
-  if (!silc_server_config_register_pkcs(server->config))
+  if (!silc_server_config_register_pkcs(server))
     silc_pkcs_register_default();
-  if (!silc_server_config_register_hashfuncs(server->config))
+  if (!silc_server_config_register_hashfuncs(server))
     silc_hash_register_default();
-  if (!silc_server_config_register_hmacs(server->config))
+  if (!silc_server_config_register_hmacs(server))
     silc_hmac_register_default();
 
   /* Initialize random number generator for the server. */
@@ -171,24 +167,23 @@ int silc_server_init(SilcServer server)
   /* Create a listening server. Note that our server can listen on multiple
      ports. All listeners are created here and now. */
   sock_count = 0;
-  listen = server->config->listen_port;
-  while(listen) {
+  while (1) {
     int tmp;
 
-    tmp = silc_net_create_server(server->config->listen_port->port,
-                                server->config->listen_port->listener_ip);
+    tmp = silc_net_create_server(server->config->server_info->port,
+                                server->config->server_info->server_ip);
 
     if (tmp < 0) {
-      SILC_LOG_ERROR(("Could not create server listener: %s on %d",
-                     server->config->listen_port->listener_ip,
-                     server->config->listen_port->port));
+      SILC_LOG_ERROR(("Could not create server listener: %s on %hd",
+                     server->config->server_info->server_ip,
+                     server->config->server_info->port));
       goto err0;
     }
 
     sock = silc_realloc(sock, sizeof(*sock) * (sock_count + 1));
     sock[sock_count] = tmp;
     sock_count++;
-    listen = listen->next;
+    break;
   }
 
   /* Initialize ID caches */
@@ -307,7 +302,7 @@ int silc_server_init(SilcServer server)
   /* If server connections has been configured then we must be router as
      normal server cannot have server connections, only router connections. */
   if (server->config->servers) {
-    SilcServerConfigSectionServerConnection *ptr = server->config->servers;
+    SilcServerConfigSectionServer *ptr = server->config->servers;
 
     server->server_type = SILC_ROUTER;
     while (ptr) {
@@ -390,8 +385,7 @@ void silc_server_drop(SilcServer server)
     struct group *gr;
     char *user, *group;
 
-    if (!server->config->identity || !server->config->identity->user || 
-       !server->config->identity->group) {
+    if (!server->config->server_info->user || !server->config->server_info->group) {
       fprintf(stderr, "Error:"
        "\tSILC server must not be run as root.  For the security of your\n"
        "\tsystem it is strongly suggested that you run SILC under dedicated\n"
@@ -401,8 +395,8 @@ void silc_server_drop(SilcServer server)
     }
 
     /* Get the values given for user and group in configuration file */
-    user=server->config->identity->user;
-    group=server->config->identity->group;
+    user=server->config->server_info->user;
+    group=server->config->server_info->group;
 
     /* Check whether the user/group information is text */ 
     if (atoi(user)!=0 || atoi(group)!=0) {
@@ -635,7 +629,7 @@ SILC_TASK_CALLBACK(silc_server_connect_router)
   server->router_connect = time(0);
 
   /* Connect to remote host */
-  sock = silc_net_create_connection(server->config->listen_port->local_ip,
+  sock = silc_net_create_connection(server->config->server_info->server_ip,
                                    sconn->remote_port, 
                                    sconn->remote_host);
   if (sock < 0) {
@@ -662,7 +656,7 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router)
 {
   SilcServer server = (SilcServer)context;
   SilcServerConnection sconn;
-  SilcServerConfigSectionServerConnection *ptr;
+  SilcServerConfigSectionRouter *ptr;
 
   SILC_LOG_DEBUG(("Connecting to router(s)"));
 
@@ -729,7 +723,7 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_second)
   SilcServerConnection sconn = (SilcServerConnection)ctx->context;
   SilcSocketConnection sock = ctx->sock;
   SilcServerConnAuthInternalContext *proto_ctx;
-  SilcServerConfigSectionServerConnection *conn = NULL;
+  SilcServerConfigSectionRouter *conn = NULL;
 
   SILC_LOG_DEBUG(("Start"));
 
@@ -1024,7 +1018,7 @@ silc_server_accept_new_connection_lookup(SilcSocketConnection sock,
   SilcServer server = (SilcServer)context;
   SilcServerKEInternalContext *proto_ctx;
   void *cconfig, *sconfig, *rconfig;
-  SilcServerConfigSectionDenyConnection *deny;
+  SilcServerConfigSectionDeny *deny;
   int port;
 
   SILC_LOG_DEBUG(("Start"));
@@ -1055,16 +1049,16 @@ silc_server_accept_new_connection_lookup(SilcSocketConnection sock,
   port = server->sockets[server->sock]->port; /* Listenning port */
 
   /* Check whether this connection is denied to connect to us. */
-  deny = silc_server_config_denied_conn(server->config, sock->ip, port);
+  deny = silc_server_config_find_denied(server->config, sock->ip, port);
   if (!deny)
-    deny = silc_server_config_denied_conn(server->config, sock->hostname,
+    deny = silc_server_config_find_denied(server->config, sock->hostname,
                                          port);
   if (deny) {
     /* The connection is denied */
     SILC_LOG_INFO(("Connection %s (%s) is denied", 
                    sock->hostname, sock->ip));
-    silc_server_disconnect_remote(server, sock, deny->comment ?
-                                 deny->comment :
+    silc_server_disconnect_remote(server, sock, deny->reason ?
+                                 deny->reason :
                                  "Server closed connection: "
                                  "Connection refused");
     server->stat.conn_failures++;
@@ -1074,9 +1068,9 @@ silc_server_accept_new_connection_lookup(SilcSocketConnection sock,
   /* Check whether we have configred this sort of connection at all. We
      have to check all configurations since we don't know what type of
      connection this is. */
-  if (!(cconfig = silc_server_config_find_client_conn(server->config,
+  if (!(cconfig = silc_server_config_find_client(server->config,
                                                      sock->ip, port)))
-    cconfig = silc_server_config_find_client_conn(server->config,
+    cconfig = silc_server_config_find_client(server->config,
                                                  sock->hostname, 
                                                  port);
   if (!(sconfig = silc_server_config_find_server_conn(server->config,
@@ -1358,7 +1352,8 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
   case SILC_SOCKET_TYPE_ROUTER:
     {
       SilcServerEntry new_server;
-      SilcServerConfigSectionServerConnection *conn = 
+      /* XXX FIXME: Now server and router has different table, so this is probably broken. */
+      SilcServerConfigSectionRouter *conn =
        ctx->conn_type == SILC_SOCKET_TYPE_SERVER ? 
        ctx->sconfig : ctx->rconfig;
 
index 4bcf0b115f09601b93a695aac91ffa397f0db79b..6b3d876a8e74999f6cf0c7be9696d10614773128 100644 (file)
@@ -524,7 +524,7 @@ SILC_TASK_CALLBACK(silc_server_backup_connect_to_router)
                  sconn->remote_port));
 
   /* Connect to remote host */
-  sock = silc_net_create_connection(server->config->listen_port->local_ip,
+  sock = silc_net_create_connection(server->config->server_info->server_ip,
                                    sconn->remote_port,
                                    sconn->remote_host);
   if (sock < 0) {
@@ -867,7 +867,7 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
       protocol->state++;
     } else {
       /* Responder of the protocol. */
-      SilcServerConfigSectionServerConnection *primary;
+      SilcServerConfigSectionRouter *primary;
 
       /* We should have received START or START_GLOBAL packet */
       if (ctx->type != SILC_SERVER_BACKUP_START &&
index 5a8f731d0b0414570a6701e05e2026a239dd21ba..e51039d619484e970556ec1c4765f1d4c85226fe 100644 (file)
@@ -2,15 +2,15 @@
 
   serverconfig.c
 
-  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+  Author: Johnny Mnemonic <johnny@themnemonic.org>
 
-  Copyright (C) 1997 - 2000 Pekka Riikonen
+  Copyright (C) 1997 - 2002 Pekka Riikonen
 
   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; either version 2 of the License, or
   (at your option) any later version.
-  
+
   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
 #include "serverincludes.h"
 #include "server_internal.h"
 
-SilcServerConfigSection silc_server_config_sections[] = {
-  { "[Cipher]",
-    SILC_CONFIG_SERVER_SECTION_TYPE_CIPHER, 4 },
-  { "[PKCS]",
-    SILC_CONFIG_SERVER_SECTION_TYPE_PKCS, 1 },
-  { "[Hash]",
-    SILC_CONFIG_SERVER_SECTION_TYPE_HASH_FUNCTION, 4 },
-  { "[hmac]",
-    SILC_CONFIG_SERVER_SECTION_TYPE_HMAC, 3 },
-  { "[ServerKeys]",
-    SILC_CONFIG_SERVER_SECTION_TYPE_SERVER_KEYS, 2 },
-  { "[ServerInfo]",
-    SILC_CONFIG_SERVER_SECTION_TYPE_SERVER_INFO, 4 },
-  { "[AdminInfo]",
-    SILC_CONFIG_SERVER_SECTION_TYPE_ADMIN_INFO, 4 },
-  { "[ListenPort]",
-    SILC_CONFIG_SERVER_SECTION_TYPE_LISTEN_PORT, 3 },
-  { "[Identity]",
-    SILC_CONFIG_SERVER_SECTION_TYPE_IDENTITY, 2 },
-  { "[Logging]",
-    SILC_CONFIG_SERVER_SECTION_TYPE_LOGGING, 3 },
-  { "[ConnectionClass]", 
-    SILC_CONFIG_SERVER_SECTION_TYPE_CONNECTION_CLASS, 4 },
-  { "[ClientConnection]", 
-    SILC_CONFIG_SERVER_SECTION_TYPE_CLIENT_CONNECTION, 5 },
-  { "[ServerConnection]", 
-    SILC_CONFIG_SERVER_SECTION_TYPE_SERVER_CONNECTION, 6 },
-  { "[RouterConnection]", 
-    SILC_CONFIG_SERVER_SECTION_TYPE_ROUTER_CONNECTION, 7 },
-  { "[AdminConnection]", 
-    SILC_CONFIG_SERVER_SECTION_TYPE_ADMIN_CONNECTION, 5 },
-  { "[DenyConnection]", 
-    SILC_CONFIG_SERVER_SECTION_TYPE_DENY_CONNECTION, 3 },
-  { "[motd]", 
-    SILC_CONFIG_SERVER_SECTION_TYPE_MOTD, 1 },
-  { "[pid]",
-    SILC_CONFIG_SERVER_SECTION_TYPE_PID, 1},
-  
-  { NULL, SILC_CONFIG_SERVER_SECTION_TYPE_NONE, 0 }
-};
-
-/* Allocates a new configuration object, opens configuration file and
-   parses the file. The parsed data is returned to the newly allocated
-   configuration object. */
+#define SILC_CONFIG_SERVER_AUTH_METH_PASSWD "passwd"
+#define SILC_CONFIG_SERVER_AUTH_METH_PUBKEY "pubkey"
 
-SilcServerConfig silc_server_config_alloc(char *filename)
-{
-  SilcServerConfig new;
-  SilcBuffer buffer;
-  SilcServerConfigParse config_parse;
-
-  SILC_LOG_DEBUG(("Allocating new configuration object"));
+#if 0
+#define SERVER_CONFIG_DEBUG(fmt) SILC_LOG_DEBUG(fmt)
+#else
+#define SERVER_CONFIG_DEBUG(fmt)
+#endif
 
-  new = silc_calloc(1, sizeof(*new));
-  if (!new) {
-    fprintf(stderr, "Could not allocate new configuration object");
-    return NULL;
+/* auto-declare needed variables for the common list parsing */
+#define SILC_SERVER_CONFIG_SECTION_INIT(__type__)                      \
+  SilcServerConfig config = (SilcServerConfig) context;                        \
+  __type__ *findtmp, *tmp = (__type__ *) config->tmp;                  \
+  int got_errno = 0
+
+/* append the tmp field to the specified list */
+#define SILC_SERVER_CONFIG_LIST_APPENDTMP(__list__)                    \
+  if (!__list__)                                                       \
+    __list__ = tmp;                                                    \
+  else {                                                               \
+    for (findtmp = __list__; findtmp->next; findtmp = findtmp->next);  \
+    findtmp->next = tmp;                                               \
   }
 
-  new->filename = filename;
-
-  SILC_LOG_DEBUG(("Loading config data from `%s'", filename));
-
-  /* Open configuration file and parse it */
-  config_parse = NULL;
-  buffer = NULL;
-  silc_config_open(filename, &buffer);
-  if (!buffer)
-    goto fail;
-  if ((silc_server_config_parse(new, buffer, &config_parse)) == FALSE)
-    goto fail;
-  if ((silc_server_config_parse_lines(new, config_parse)) == FALSE)
-    goto fail;
-
-  silc_buffer_free(buffer);
-
-  return new;
-
- fail:
-  silc_buffer_free(buffer);
-  silc_free(new);
-  return NULL;
-}
+/* loops all elements in a list and provides a di struct pointer of the
+ * specified type containing the current element */
+#define SILC_SERVER_CONFIG_LIST_DESTROY(__type__, __list__)            \
+  for (tmp = (void *) __list__; tmp;) {                                        \
+    __type__ *di = (__type__ *) tmp;                                   \
+    tmp = (void *) di->next;
 
-/* Free's a configuration object. */
-
-void silc_server_config_free(SilcServerConfig config)
+/* free an authdata according to its auth method */
+static void my_free_authdata(SilcAuthMethod auth_meth, void *auth_data)
 {
-  if (config) {
-    silc_free(config->filename);
-    silc_free(config->server_keys);
-    silc_free(config->server_info);
-    silc_free(config->admin_info);
-    silc_free(config->listen_port);
-    silc_free(config->identity);
-    silc_free(config->conn_class);
-    silc_free(config->clients);
-    silc_free(config->admins);
-    silc_free(config->servers);
-    silc_free(config->routers);
-    silc_free(config->denied);
-    silc_free(config->motd);
-    silc_free(config->pidfile);
-    silc_free(config);
+  if (auth_meth == SILC_AUTH_PASSWORD) {
+    silc_free(auth_data);
+  } else if (auth_meth == SILC_AUTH_PUBLIC_KEY) {
+    silc_pkcs_public_key_free((SilcPublicKey) auth_data);
   }
 }
 
-/* Parses the the buffer and returns the parsed lines into return_config
-   argument. The return_config argument doesn't have to be initialized 
-   before calling this. It will be initialized during the parsing. The
-   buffer sent as argument can be safely free'd after this function has
-   succesfully returned. */
-
-int silc_server_config_parse(SilcServerConfig config, SilcBuffer buffer, 
-                            SilcServerConfigParse *return_config)
+/* parse an authdata according to its auth method */
+static bool my_parse_authdata(SilcAuthMethod auth_meth, char *p, uint32 line,
+                             void **auth_data, uint32 *auth_data_len)
 {
-  int i, begin, linenum;
-  char line[1024], *cp;
-  SilcServerConfigSection *cptr = NULL;
-  SilcServerConfigParse parse = *return_config, first = NULL;
-
-  SILC_LOG_DEBUG(("Parsing configuration file"));
-
-  begin = 0;
-  linenum = 0;
-  while((begin = silc_gets(line, sizeof(line),
-                          buffer->data, buffer->len, begin)) != EOF) {
-    cp = line;
-    linenum++;
-
-    /* Check for bad line */
-    if (silc_check_line(cp))
-      continue;
-
-    /* Remove tabs and whitespaces from the line */
-    if (strchr(cp, '\t')) {
-      i = 0;
-      while(strchr(cp + i, '\t')) {
-       *strchr(cp + i, '\t') = ' ';
-       i++;
-      }
-    }
-    for (i = 0; i < strlen(cp); i++) {
-      if (cp[i] != ' ') {
-       if (i)
-         cp++;
-       break;
-      }
-      cp++;
-    }
-
-    /* Parse line */
-    switch(cp[0]) {
-    case '[':
-      /*
-       * Start of a section
-       */
-
-      /* Remove new line sign */
-      if (strchr(cp, '\n'))
-       *strchr(cp, '\n') = '\0';
-      
-      /* Check for matching sections */
-      for (cptr = silc_server_config_sections; cptr->section; cptr++)
-       if (!strncasecmp(cp, cptr->section, strlen(cptr->section)))
-         break;
-
-      if (!cptr->section) {
-       fprintf(stderr, "%s:%d: Unknown section `%s'\n", 
-                       config->filename, linenum, cp);
+  if (auth_meth == SILC_AUTH_PASSWORD) {
+    /* p is a plain text password */
+    *auth_data = (void *) strdup(p);
+    *auth_data_len = (uint32) strlen(p);
+  } else if (auth_meth == SILC_AUTH_PUBLIC_KEY) {
+    /* p is a public key */
+    SilcPublicKey public_key;
+
+    if (!silc_pkcs_load_public_key(p, &public_key, SILC_PKCS_FILE_PEM))
+      if (!silc_pkcs_load_public_key(p, &public_key, SILC_PKCS_FILE_BIN)) {
+       fprintf(stderr, "\nError while parsing config file at line %lu: "
+               "Could not load public key file!\n", line);
        return FALSE;
       }
-
-      break;
-    default:
-      /*
-       * Start of a configuration line
-       */
-
-      if (cptr->type != SILC_CONFIG_SERVER_SECTION_TYPE_NONE) {
-       
-       if (strchr(cp, '\n'))
-           *strchr(cp, '\n') = ':';
-
-       if (parse == NULL) {
-         parse = silc_calloc(1, sizeof(*parse));
-         parse->line = NULL;
-         parse->section = NULL;
-         parse->next = NULL;
-         parse->prev = NULL;
-       } else {
-         if (parse->next == NULL) {
-           parse->next = silc_calloc(1, sizeof(*parse->next));
-           parse->next->line = NULL;
-           parse->next->section = NULL;
-           parse->next->next = NULL;
-           parse->next->prev = parse;
-           parse = parse->next;
-         }
-       }
-       
-       if (first == NULL)
-         first = parse;
-
-       /* Add the line to parsing structure for further parsing. */
-       if (parse) {
-         parse->section = cptr;
-         parse->line = silc_buffer_alloc(strlen(cp) + 1);
-         parse->linenum = linenum;
-         silc_buffer_pull_tail(parse->line, strlen(cp));
-         silc_buffer_put(parse->line, cp, strlen(cp));
-       }
-      }
-      break;
-    }
+    *auth_data = (void *) public_key;
+    *auth_data_len = 0;
+  } else {
+    fprintf(stderr, "\nError while parsing config file at line %lu: Specify "
+               "the AuthMethod before specifying the AuthData.\n", line);
+    return FALSE;
   }
-  
-  /* Set the return_config argument to its first value so that further
-     parsing can be started from the first line. */
-  *return_config = first;
-
   return TRUE;
 }
 
-/* Parses the lines earlier read from configuration file. The config object
-   must not be initialized, it will be initialized in this function. The
-   parse_config argument is uninitialized automatically during this
-   function. */
+/* Callbacks */
 
-int silc_server_config_parse_lines(SilcServerConfig config, 
-                                  SilcServerConfigParse parse_config)
+SILC_CONFIG_CALLBACK(fetch_generic)
 {
-  int ret, check = FALSE;
-  uint32 checkmask;
-  char *tmp;
-  SilcServerConfigParse pc = parse_config;
-  SilcBuffer line;
-
-  SILC_LOG_DEBUG(("Parsing configuration lines"));
-  
-  if (!config)
-    return FALSE;
-  
-  checkmask = 0;
-  while(pc) {
-    check = FALSE;
-    line = pc->line;
-
-    /* Get number of tokens in line */
-    ret = silc_config_check_num_token(line);
-    if (ret < pc->section->maxfields) {
-      /* Bad line */
-      fprintf(stderr, "%s:%d: Missing tokens, %d tokens (should be %d)\n",
-             config->filename, pc->linenum, ret, 
-             pc->section->maxfields);
-      break;
-    }
-
-    /* Parse the line */
-    switch(pc->section->type) {
-    case SILC_CONFIG_SERVER_SECTION_TYPE_CIPHER:
-
-      SILC_SERVER_CONFIG_LIST_ALLOC(config->cipher);
-
-      /* Get cipher name */
-      ret = silc_config_get_token(line, &config->cipher->alg_name);
-      if (ret < 0)
-       break;
-      if (ret == 0) {
-       fprintf(stderr, "%s:%d: Cipher name not defined\n",
-               config->filename, pc->linenum);
-       break;
-      }
-
-      /* Get module name */
-      config->cipher->sim_name = NULL;
-      ret = silc_config_get_token(line, &config->cipher->sim_name);
-      if (ret < 0)
-       break;
-
-      /* Get key length */
-      ret = silc_config_get_token(line, &tmp);
-      if (ret < 0)
-       break;
-      if (ret == 0) {
-       fprintf(stderr, "%s:%d: Cipher key length not defined\n",
-               config->filename, pc->linenum);
-       break;
-      }
-      config->cipher->key_len = atoi(tmp);
-      silc_free(tmp);
-
-      /* Get block length */
-      ret = silc_config_get_token(line, &tmp);
-      if (ret < 0)
-       break;
-      if (ret == 0) {
-       fprintf(stderr, "%s:%d: Cipher block length not defined\n",
-               config->filename, pc->linenum);
-       break;
-      }
-      config->cipher->block_len = atoi(tmp);
-      silc_free(tmp);
-
-      check = TRUE;
-      checkmask |= (1L << pc->section->type);
-      break;
-
-    case SILC_CONFIG_SERVER_SECTION_TYPE_PKCS:
-
-      SILC_SERVER_CONFIG_LIST_ALLOC(config->pkcs);
-
-      /* Get PKCS name */
-      ret = silc_config_get_token(line, &config->pkcs->alg_name);
-      if (ret < 0)
-       break;
-      if (ret == 0) {
-       fprintf(stderr, "%s:%d: PKCS name not defined\n",
-               config->filename, pc->linenum);
-       break;
-      }
-
-      check = TRUE;
-      checkmask |= (1L << pc->section->type);
-      break;
-
-    case SILC_CONFIG_SERVER_SECTION_TYPE_HASH_FUNCTION:
-
-      SILC_SERVER_CONFIG_LIST_ALLOC(config->hash_func);
-
-      /* Get Hash function name */
-      ret = silc_config_get_token(line, &config->hash_func->alg_name);
-      if (ret < 0)
-       break;
-      if (ret == 0) {
-       fprintf(stderr, "%s:%d: Hash function name not defined\n",
-               config->filename, pc->linenum);
-       break;
-      }
-      
-      /* Get Hash function module name */
-      config->hash_func->sim_name = NULL;
-      ret = silc_config_get_token(line, &config->hash_func->sim_name);
-      if (ret < 0)
-       break;
-
-      /* Get block length */
-      ret = silc_config_get_token(line, &tmp);
-      if (ret < 0)
-       break;
-      if (ret == 0) {
-       fprintf(stderr, "%s:%d: Hash function block length not defined\n",
-               config->filename, pc->linenum);
-       break;
-      }
-      config->hash_func->block_len = atoi(tmp);
-      silc_free(tmp);
-
-      /* Get hash length */
-      ret = silc_config_get_token(line, &tmp);
-      if (ret < 0)
-       break;
-      if (ret == 0) {
-       fprintf(stderr, "%s:%d: Hash function hash length not defined\n",
-               config->filename, pc->linenum);
-       break;
-      }
-      config->hash_func->key_len = atoi(tmp);
-      silc_free(tmp);
-
-      check = TRUE;
-      checkmask |= (1L << pc->section->type);
-      break;
-
-    case SILC_CONFIG_SERVER_SECTION_TYPE_HMAC:
-
-      SILC_SERVER_CONFIG_LIST_ALLOC(config->hmac);
-
-      /* Get HMAC name */
-      ret = silc_config_get_token(line, &config->hmac->alg_name);
-      if (ret < 0)
-       break;
-      if (ret == 0) {
-       fprintf(stderr, "%s:%d: HMAC name not defined\n",
-               config->filename, pc->linenum);
-       break;
-      }
-
-      /* Get hash name */
-      ret = silc_config_get_token(line, &config->hmac->sim_name);
-      if (ret < 0)
-       break;
-      if (ret == 0) {
-       fprintf(stderr, "%s:%d: Hash function name not defined\n",
-               config->filename, pc->linenum);
-       break;
-      }
-      
-      /* Get MAC length */
-      ret = silc_config_get_token(line, &tmp);
-      if (ret < 0)
-       break;
-      if (ret == 0) {
-       fprintf(stderr, "%s:%d: HMAC's MAC length not defined\n",
-               config->filename, pc->linenum);
-       break;
-      }
-      config->hmac->key_len = atoi(tmp);
-      silc_free(tmp);
-
-      check = TRUE;
-      checkmask |= (1L << pc->section->type);
-      break;
-
-    case SILC_CONFIG_SERVER_SECTION_TYPE_SERVER_KEYS:
-
-      if (!config->server_keys)
-       config->server_keys = silc_calloc(1, sizeof(*config->server_keys));
-
-      ret = silc_config_get_token(line, &tmp);
-      if (ret < 0)
-       break;
-      if (ret == 0) {
-       fprintf(stderr, "%s:%d: Public key name not defined\n",
-               config->filename, pc->linenum);
-       break;
-      }
-      
-      if (!silc_pkcs_load_public_key(tmp, &config->server_keys->public_key, 
-                                    SILC_PKCS_FILE_PEM))
-       if (!silc_pkcs_load_public_key(tmp, &config->server_keys->public_key, 
-                                      SILC_PKCS_FILE_BIN)) {
-         fprintf(stderr, "%s:%d: Could not load public key file `%s'\n",
-                 config->filename, pc->linenum, tmp);
-         break;
-       }
-      silc_free(tmp);
-
-      ret = silc_config_get_token(line, &tmp);
-      if (ret < 0)
-       break;
-      if (ret == 0) {
-       fprintf(stderr, "%s:%d: Private key name not defined\n",
-               config->filename, pc->linenum);
-       break;
-      }
-      
-      if (!silc_pkcs_load_private_key(tmp, &config->server_keys->private_key, 
-                                    SILC_PKCS_FILE_BIN))
-       if (!silc_pkcs_load_private_key(tmp, 
-                                       &config->server_keys->private_key, 
-                                       SILC_PKCS_FILE_PEM)) {
-         fprintf(stderr, "%s:%d: Could not load private key file `%s'\n",
-                 config->filename, pc->linenum, tmp);
-         break;
-       }
-      silc_free(tmp);
-
-      check = TRUE;
-      checkmask |= (1L << pc->section->type);
-      break;
-
-    case SILC_CONFIG_SERVER_SECTION_TYPE_SERVER_INFO:
-
-      if (!config->server_info)
-       config->server_info = silc_calloc(1, sizeof(*config->server_info));
-
-      /* Get server name */
-      ret = silc_config_get_token(line, &config->server_info->server_name);
-      if (ret < 0)
-       break;
-      if (ret == 0) {
-       /* Server name not defined */
-
-      }
-      
-      /* Get server IP */
-      ret = silc_config_get_token(line, &config->server_info->server_ip);
-      if (ret < 0)
-       break;
-      if (ret == 0) {
-       /* Server IP not defined */
-
-      }
-
-      /* Get server location */
-      ret = silc_config_get_token(line, &config->server_info->location);
-      if (ret < 0)
-       break;
-
-      /* Get server port */
-      /* XXX: Need port here??? */
-      ret = silc_config_get_token(line, &tmp);
-      if (ret < 0)
-       break;
-      if (ret == 0) {
-       /* Port not defined */
-
-      }
-      config->server_info->port = atoi(tmp);
-      silc_free(tmp);
-
-      check = TRUE;
-      checkmask |= (1L << pc->section->type);
-      break;
-
-    case SILC_CONFIG_SERVER_SECTION_TYPE_ADMIN_INFO:
-
-      if (!config->admin_info)
-       config->admin_info = silc_calloc(1, sizeof(*config->admin_info));
-
-      /* Get location */
-      ret = silc_config_get_token(line, &config->admin_info->location);
-      if (ret < 0)
-       break;
-
-      /* Get server type */
-      ret = silc_config_get_token(line, &config->admin_info->server_type);
-      if (ret < 0)
-       break;
-
-      /* Get admins name */
-      ret = silc_config_get_token(line, &config->admin_info->admin_name);
-      if (ret < 0)
-       break;
-
-      /* Get admins email address */
-      ret = silc_config_get_token(line, &config->admin_info->admin_email);
-      if (ret < 0)
-       break;
-
-      check = TRUE;
-      checkmask |= (1L << pc->section->type);
-      break;
-
-    case SILC_CONFIG_SERVER_SECTION_TYPE_LISTEN_PORT:
-
-      SILC_SERVER_CONFIG_LIST_ALLOC(config->listen_port);
-
-      /* Get local IP */
-      ret = silc_config_get_token(line, &config->listen_port->local_ip);
-      if (ret < 0)
-       break;
-
-      /* Get listener IP */
-      ret = silc_config_get_token(line, &config->listen_port->listener_ip);
-      if (ret < 0)
-       break;
-
-      /* Get port */
-      ret = silc_config_get_token(line, &tmp);
-      if (ret < 0)
-       break;
-      if (ret == 0) {
-       /* Any port */
-       config->listen_port->port = 0;
-      } else {
-       config->listen_port->port = atoi(tmp);
-       silc_free(tmp);
-      }
-
-      check = TRUE;
-      checkmask |= (1L << pc->section->type);
-      break;
-
-    case SILC_CONFIG_SERVER_SECTION_TYPE_IDENTITY:
-
-      if (!config->identity)
-        config->identity = silc_calloc(1, sizeof(*config->identity));
-
-      /* Get user */
-      ret = silc_config_get_token(line, &config->identity->user);
-      if (ret < 0)
-        break;
-      /* Get group */
-      ret = silc_config_get_token(line, &config->identity->group);
-      if (ret < 0)
-        break;
-
-      check = TRUE;
-      checkmask |= (1L << pc->section->type);
-
-    case SILC_CONFIG_SERVER_SECTION_TYPE_CONNECTION_CLASS:
-
-      SILC_SERVER_CONFIG_LIST_ALLOC(config->conn_class);
-
-      /* Get class number */
-      ret = silc_config_get_token(line, &tmp);
-      if (ret < 0)
-       break;
-      if (ret == 0) {
-       /* Class number not defined */
-
-      }
-      config->conn_class->class = atoi(tmp);
-      silc_free(tmp);
-
-      /* Get ping frequency */
-      ret = silc_config_get_token(line, &tmp);
-      if (ret < 0)
-       break;
-      config->conn_class->ping_freq = atoi(tmp);
-      silc_free(tmp);
-
-      /* Get connect frequency */
-      ret = silc_config_get_token(line, &tmp);
-      if (ret < 0)
-       break;
-      config->conn_class->connect_freq = atoi(tmp);
-      silc_free(tmp);
-
-      /* Get max links */
-      ret = silc_config_get_token(line, &tmp);
-      if (ret < 0)
-       break;
-      config->conn_class->max_links = atoi(tmp);
-      silc_free(tmp);
-
-      check = TRUE;
-      checkmask |= (1L << pc->section->type);
-      break;
-
-    case SILC_CONFIG_SERVER_SECTION_TYPE_LOGGING:
-
-      SILC_SERVER_CONFIG_LIST_ALLOC(config->logging);
-
-      /* Get log section type and check it */
-      ret = silc_config_get_token(line, &config->logging->logtype);
-      if (ret < 0)
-       break;
-      if (ret == 0) {
-       fprintf(stderr, "%s:%d: Log file section not defined\n",
-               config->filename, pc->linenum);
-       break;
-      }
-      if (strcmp(config->logging->logtype, SILC_CONFIG_SERVER_LF_INFO)
-         && strcmp(config->logging->logtype, SILC_CONFIG_SERVER_LF_WARNING)
-         && strcmp(config->logging->logtype, SILC_CONFIG_SERVER_LF_ERROR)
-         && strcmp(config->logging->logtype, SILC_CONFIG_SERVER_LF_FATAL)
-         && strcmp(config->logging->logtype, SILC_CONFIG_SERVER_LO_QUICK)
-         && strcmp(config->logging->logtype, SILC_CONFIG_SERVER_LO_FDELAY)) {
-       fprintf(stderr, "%s:%d: Unknown log file section '%s'\n",
-               config->filename, pc->linenum, config->logging->logtype);
-       break;
-      }
-
-      /* Get log filename */
-      ret = silc_config_get_token(line, &config->logging->filename);
-      if (ret < 0)
-       break;
-      if (ret == 0) {
-       fprintf(stderr, "%s:%d: Log file name not defined\n",
-               config->filename, pc->linenum);
-       break;
-      }
-
-      /* Get max byte size */
-      ret = silc_config_get_token(line, &tmp);
-      if (ret < 0)
-       break;
-      if (ret) {
-       config->logging->maxsize = atoi(tmp);
-       silc_free(tmp);
-      }
-
-      check = TRUE;
-      checkmask |= (1L << pc->section->type);
-      break;
-
-    case SILC_CONFIG_SERVER_SECTION_TYPE_CLIENT_CONNECTION:
-
-      SILC_SERVER_CONFIG_LIST_ALLOC(config->clients);
-
-      /* Get host */
-      ret = silc_config_get_token(line, &config->clients->host);
-      if (ret < 0)
-       break;
-      if (ret == 0)
-       /* Any host */
-       config->clients->host = strdup("*");
-
-      /* Get authentication method */
-      ret = silc_config_get_token(line, &tmp);
-      if (ret < 0)
-       break;
-      if (ret) {
-       if (strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PASSWD) &&
-           strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PUBKEY)) {
-         fprintf(stderr, "%s:%d: Unknown authentication method '%s'\n",
-                 config->filename, pc->linenum, tmp);
-         break;
-       }
-
-       if (!strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PASSWD))
-         config->clients->auth_meth = SILC_AUTH_PASSWORD;
-
-       if (!strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PUBKEY))
-         config->clients->auth_meth = SILC_AUTH_PUBLIC_KEY;
-
-       silc_free(tmp);
-      }
-
-      /* Get authentication data */
-      ret = silc_config_get_token(line, (char **)&config->clients->auth_data);
-      if (ret < 0)
-       break;
-
-      if (config->clients->auth_meth == SILC_AUTH_PASSWORD) {
-       config->clients->auth_data_len = strlen(config->clients->auth_data);
-      } else if (config->clients->auth_meth == SILC_AUTH_PUBLIC_KEY) {
-       /* Get the public key */
-       SilcPublicKey public_key;
-
-       if (!silc_pkcs_load_public_key(config->clients->auth_data,
-                                      &public_key, SILC_PKCS_FILE_PEM))
-         if (!silc_pkcs_load_public_key(config->clients->auth_data,
-                                        &public_key, SILC_PKCS_FILE_BIN)) {
-           fprintf(stderr, "%s:%d: Could not load public key file `%s'\n",
-                   config->filename, pc->linenum, 
-                   (char *)config->clients->auth_data);
-           break;
-         }
-
-       silc_free(config->clients->auth_data);
-       config->clients->auth_data = (void *)public_key;
-       config->clients->auth_data_len = 0;
-      }
-
-      /* Get port */
-      ret = silc_config_get_token(line, &tmp);
-      if (ret < 0)
-       break;
-      if (ret) {
-       config->clients->port = atoi(tmp);
-       silc_free(tmp);
-      }
-
-      /* Get class number */
-      ret = silc_config_get_token(line, &tmp);
-      if (ret < 0)
-       break;
-      if (ret) {
-       config->clients->class = atoi(tmp);
-       silc_free(tmp);
-      }
-
-      check = TRUE;
-      checkmask |= (1L << pc->section->type);
-      break;
-
-    case SILC_CONFIG_SERVER_SECTION_TYPE_SERVER_CONNECTION:
-
-      SILC_SERVER_CONFIG_LIST_ALLOC(config->servers);
-
-      /* Get host */
-      ret = silc_config_get_token(line, &config->servers->host);
-      if (ret < 0)
-       break;
-      if (ret == 0)
-       /* Any host */
-       config->servers->host = strdup("*");
-
-      /* Get authentication method */
-      ret = silc_config_get_token(line, &tmp);
-      if (ret < 0)
-       break;
-      if (ret) {
-       if (strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PASSWD) &&
-           strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PUBKEY)) {
-         fprintf(stderr, "%s:%d: Unknown authentication method '%s'\n",
-                 config->filename, pc->linenum, tmp);
-         break;
-       }
-
-       if (!strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PASSWD))
-         config->servers->auth_meth = SILC_AUTH_PASSWORD;
-
-       if (!strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PUBKEY))
-         config->servers->auth_meth = SILC_AUTH_PUBLIC_KEY;
-
-       silc_free(tmp);
-      }
-
-      /* Get authentication data */
-      ret = silc_config_get_token(line, (char **)&config->servers->auth_data);
-      if (ret < 0)
-       break;
-
-      if (config->servers->auth_meth == SILC_AUTH_PASSWORD) {
-       config->servers->auth_data_len = strlen(config->servers->auth_data);
-      } else if (config->servers->auth_meth == SILC_AUTH_PUBLIC_KEY) {
-       /* Get the public key */
-       SilcPublicKey public_key;
-
-       if (!silc_pkcs_load_public_key(config->servers->auth_data,
-                                      &public_key, SILC_PKCS_FILE_PEM))
-         if (!silc_pkcs_load_public_key(config->servers->auth_data,
-                                        &public_key, SILC_PKCS_FILE_BIN)) {
-           fprintf(stderr, "%s:%d: Could not load public key file `%s'\n",
-                   config->filename, pc->linenum, 
-                   (char *)config->servers->auth_data);
-           break;
-         }
-
-       silc_free(config->servers->auth_data);
-       config->servers->auth_data = (void *)public_key;
-       config->servers->auth_data_len = 0;
-      }
-
-      /* Get port */
-      ret = silc_config_get_token(line, &tmp);
-      if (ret < 0)
-       break;
-      if (ret) {
-       config->servers->port = atoi(tmp);
-       silc_free(tmp);
-      }
-
-      /* Get version */
-      ret = silc_config_get_token(line, &config->servers->version);
-      if (ret < 0)
-       break;
+  SilcServerConfig config = (SilcServerConfig) context;
 
-      /* Get class number */
-      ret = silc_config_get_token(line, &tmp);
-      if (ret < 0)
-       break;
-      if (ret) {
-       config->servers->class = atoi(tmp);
-       silc_free(tmp);
-      }
+  if (!strcmp(name, "modulepath")) {
+    if (config->module_path) return SILC_CONFIG_EDOUBLE;
+    /* dup it only if non-empty, otherwise point it to NULL */
+    config->module_path = (*(char *)val ? strdup((char *) val) : NULL);
+  }
+  else
+    return SILC_CONFIG_EINTERNAL;
+  return SILC_CONFIG_OK;
+}
 
-      /* Check whether this connection is backup router connection */
-      ret = silc_config_get_token(line, &tmp);
-      if (ret != -1) {
-       config->servers->backup_router = atoi(tmp);
-       if (config->servers->backup_router != 0)
-         config->servers->backup_router = TRUE;
-       silc_free(tmp);
-      }
+SILC_CONFIG_CALLBACK(fetch_cipher)
+{
+  SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigSectionCipher);
+
+  SERVER_CONFIG_DEBUG(("Received CIPHER type=%d name=\"%s\" (val=%x)", type, name, context));
+  if (type == SILC_CONFIG_ARG_BLOCK) {
+    /* check the temporary struct's fields */
+    if (!tmp) /* empty sub-block? */
+      return SILC_CONFIG_OK;
+    if (!tmp->name) {
+      got_errno = SILC_CONFIG_EMISSFIELDS;
+      goto got_err;
+    }
+    /* the temporary struct is ok, append it to the list */
+    SILC_SERVER_CONFIG_LIST_APPENDTMP(config->cipher);
+    config->tmp = NULL;
+    return SILC_CONFIG_OK;
+  }
+  /* if there isn't a temporary struct alloc one */
+  if (!tmp) {
+    config->tmp = silc_calloc(1, sizeof(*findtmp));
+    tmp = (SilcServerConfigSectionCipher *) config->tmp;
+  }
 
-      check = TRUE;
-      checkmask |= (1L << pc->section->type);
-      break;
+  /* Identify and save this value */
+  if (!strcmp(name, "name")) {
+    if (tmp->name) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
+    tmp->name = strdup((char *) val);
+  }
+  else if (!strcmp(name, "module")) { /* can be empty */
+    if (tmp->module) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
+    /* dup it only if non-empty, otherwise point it to NULL */
+    tmp->module = (*(char *)val ? strdup((char *) val) : NULL);
+  }
+  else if (!strcmp(name, "key_length"))
+    tmp->key_length = *(uint32 *)val;
+  else if (!strcmp(name, "block_length"))
+    tmp->block_length = *(uint32 *)val;
+  else
+    return SILC_CONFIG_EINTERNAL;
+  return SILC_CONFIG_OK;
+
+ got_err:
+  silc_free(tmp->name);
+  silc_free(tmp->module);
+  silc_free(tmp);
+  config->tmp = NULL;
+  return got_errno;
+}
 
-    case SILC_CONFIG_SERVER_SECTION_TYPE_ROUTER_CONNECTION:
+SILC_CONFIG_CALLBACK(fetch_hash)
+{
+  SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigSectionHash);
+
+  SERVER_CONFIG_DEBUG(("Received HASH type=%d name=%s (val=%x)", type, name, context));
+  if (type == SILC_CONFIG_ARG_BLOCK) {
+    /* check the temporary struct's fields */
+    if (!tmp) /* empty sub-block? */
+      return SILC_CONFIG_OK;
+    if (!tmp->name || (tmp->block_length == 0) || (tmp->digest_length == 0)) {
+      got_errno = SILC_CONFIG_EMISSFIELDS;
+      goto got_err;
+    }
+    /* the temporary struct in tmp is ok */
+    SILC_SERVER_CONFIG_LIST_APPENDTMP(config->hash);
+    config->tmp = NULL;
+    return SILC_CONFIG_OK;
+  }
+  /* if there isn't a temporary struct alloc one */
+  if (!tmp) {
+    config->tmp = silc_calloc(1, sizeof(*findtmp));
+    tmp = (SilcServerConfigSectionHash *) config->tmp;
+  }
 
-      SILC_SERVER_CONFIG_LIST_ALLOC(config->routers);
+  /* Identify and save this value */
+  if (!strcmp(name, "name")) {
+    if (tmp->name) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
+    tmp->name = strdup((char *) val);
+  }
+  else if (!strcmp(name, "module")) { /* can be empty */
+    if (tmp->module) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
+    /* dup it only if non-empty, otherwise point it to NULL */
+    tmp->module = (*(char *)val ? strdup((char *) val) : NULL);
+  }
+  else if (!strcmp(name, "block_length"))
+    tmp->block_length = *(int *)val;
+  else if (!strcmp(name, "digest_length"))
+    tmp->digest_length = *(int *)val;
+  else
+    return SILC_CONFIG_EINTERNAL;
+  return SILC_CONFIG_OK;
+
+ got_err:
+  silc_free(tmp->name);
+  silc_free(tmp->module);
+  silc_free(tmp);
+  config->tmp = NULL;
+  return got_errno;
+}
 
-      /* Get host */
-      ret = silc_config_get_token(line, &config->routers->host);
-      if (ret < 0)
-       break;
+SILC_CONFIG_CALLBACK(fetch_hmac)
+{
+  SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigSectionHmac);
+
+  SERVER_CONFIG_DEBUG(("Received HMAC type=%d name=\"%s\" (val=%x)", type, name, context));
+  if (type == SILC_CONFIG_ARG_BLOCK) {
+    /* check the temporary struct's fields */
+    if (!tmp) /* empty sub-block? */
+      return SILC_CONFIG_OK;
+    if (!tmp->name || !tmp->hash || (tmp->mac_length == 0)) {
+      got_errno = SILC_CONFIG_EMISSFIELDS;
+      goto got_err;
+    }
+    /* the temporary struct is ok, append it to the list */
+    SILC_SERVER_CONFIG_LIST_APPENDTMP(config->hmac);
+    config->tmp = NULL;
+    return SILC_CONFIG_OK;
+  }
+  /* if there isn't a temporary struct alloc one */
+  if (!tmp) {
+    config->tmp = silc_calloc(1, sizeof(*findtmp));
+    tmp = (SilcServerConfigSectionHmac *) config->tmp;
+  }
 
-      /* Get authentication method */
-      ret = silc_config_get_token(line, &tmp);
-      if (ret < 0)
-       break;
-      if (ret) {
-       if (strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PASSWD) &&
-           strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PUBKEY)) {
-         fprintf(stderr, "%s:%d: Unknown authentication method '%s'\n",
-                 config->filename, pc->linenum, tmp);
-         break;
-       }
+  /* Identify and save this value */
+  if (!strcmp(name, "name")) {
+    if (tmp->name) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
+    tmp->name = strdup((char *) val);
+  }
+  else if (!strcmp(name, "hash")) {
+    if (tmp->hash) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
+    tmp->hash = strdup((char *) val);
+  }
+  else if (!strcmp(name, "mac_length"))
+    tmp->mac_length = *(int *)val;
+  else
+    return SILC_CONFIG_EINTERNAL;
+  return SILC_CONFIG_OK;
+
+ got_err:
+  silc_free(tmp->name);
+  silc_free(tmp->hash);
+  silc_free(tmp);
+  config->tmp = NULL;
+  return got_errno;
+}
 
-       if (!strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PASSWD))
-         config->routers->auth_meth = SILC_AUTH_PASSWORD;
+SILC_CONFIG_CALLBACK(fetch_pkcs)
+{
+  SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigSectionPkcs);
+
+  SERVER_CONFIG_DEBUG(("Received PKCS type=%d name=\"%s\" (val=%x)", type, name, context));
+  if (type == SILC_CONFIG_ARG_BLOCK) {
+    /* check the temporary struct's fields */
+    if (!tmp) /* empty sub-block? */
+      return SILC_CONFIG_OK;
+    if (!tmp->name) {
+      got_errno = SILC_CONFIG_EMISSFIELDS;
+      goto got_err;
+    }
+    /* the temporary struct is ok, append it to the list */
+    SILC_SERVER_CONFIG_LIST_APPENDTMP(config->pkcs);
+    config->tmp = NULL;
+    return SILC_CONFIG_OK;
+  }
+  /* if there isn't a temporary struct alloc one */
+  if (!tmp) {
+    config->tmp = silc_calloc(1, sizeof(*findtmp));
+    tmp = (SilcServerConfigSectionPkcs *) config->tmp;
+  }
 
-       if (!strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PUBKEY))
-         config->routers->auth_meth = SILC_AUTH_PUBLIC_KEY;
+  /* Identify and save this value */
+  if (!strcmp(name, "name")) {
+    if (tmp->name) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
+    tmp->name = strdup((char *) val);
+  }
+  else
+    return SILC_CONFIG_EINTERNAL;
+  return SILC_CONFIG_OK;
+
+ got_err:
+  silc_free(tmp->name);
+  silc_free(tmp);
+  config->tmp = NULL;
+  return got_errno;
+}
 
-       silc_free(tmp);
-      }
+SILC_CONFIG_CALLBACK(fetch_serverinfo)
+{
+  SilcServerConfig config = (SilcServerConfig) context;
+  SilcServerConfigSectionServerInfo *server_info = config->server_info;
 
-      /* Get authentication data */
-      ret = silc_config_get_token(line, (char **)&config->routers->auth_data);
-      if (ret < 0)
-       break;
+  /* if there isn't the struct alloc it */
+  if (!server_info) {
+    config->server_info = server_info = (SilcServerConfigSectionServerInfo *)
+               silc_calloc(1, sizeof(*server_info));
+  }
 
-      if (config->routers->auth_meth == SILC_AUTH_PASSWORD) {
-       config->routers->auth_data_len = strlen(config->routers->auth_data);
-      } else if (config->routers->auth_meth == SILC_AUTH_PUBLIC_KEY) {
-       /* Get the public key */
-       SilcPublicKey public_key;
-
-       if (!silc_pkcs_load_public_key(config->routers->auth_data,
-                                      &public_key, SILC_PKCS_FILE_PEM))
-         if (!silc_pkcs_load_public_key(config->routers->auth_data,
-                                        &public_key, SILC_PKCS_FILE_BIN)) {
-           fprintf(stderr, "%s:%d: Could not load public key file `%s'\n",
-                   config->filename, pc->linenum, 
-                   (char *)config->routers->auth_data);
-           break;
-         }
-
-       silc_free(config->routers->auth_data);
-       config->routers->auth_data = (void *)public_key;
-       config->routers->auth_data_len = 0;
+  if (type == SILC_CONFIG_ARG_BLOCK) {
+    /* check for mandatory inputs */
+    return SILC_CONFIG_OK;
+  }
+  if (!strcmp(name, "hostname")) {
+    if (server_info->server_name) return SILC_CONFIG_EDOUBLE;
+    server_info->server_name = strdup((char *) val);
+  }
+  else if (!strcmp(name, "ip")) {
+    if (server_info->server_ip) return SILC_CONFIG_EDOUBLE;
+    server_info->server_ip = strdup((char *) val);
+  }
+  else if (!strcmp(name, "port")) {
+    int port = *(int *)val;
+    if ((port <= 0) || (port > 65535)) {
+      fprintf(stderr, "Invalid port number!\n");
+      return SILC_CONFIG_ESILENT;
+    }
+    server_info->port = (uint16) port;
+  }
+  else if (!strcmp(name, "servertype")) {
+    if (server_info->server_type) return SILC_CONFIG_EDOUBLE;
+    server_info->server_type = strdup((char *) val);
+  }
+  else if (!strcmp(name, "admin")) {
+    if (server_info->admin) return SILC_CONFIG_EDOUBLE;
+    server_info->admin = strdup((char *) val);
+  }
+  else if (!strcmp(name, "email")) {
+    if (server_info->email) return SILC_CONFIG_EDOUBLE;
+    server_info->email = strdup((char *) val);
+  }
+  else if (!strcmp(name, "location")) {
+    if (server_info->location) return SILC_CONFIG_EDOUBLE;
+    server_info->location = strdup((char *) val);
+  }
+  else if (!strcmp(name, "user")) {
+    if (server_info->user) return SILC_CONFIG_EDOUBLE;
+    server_info->user = strdup((char *) val);
+  }
+  else if (!strcmp(name, "group")) {
+    if (server_info->group) return SILC_CONFIG_EDOUBLE;
+    server_info->group = strdup((char *) val);
+  }
+  else if (!strcmp(name, "motdfile")) {
+    if (server_info->motd_file) return SILC_CONFIG_EDOUBLE;
+    server_info->motd_file = strdup((char *) val);
+  }
+  else if (!strcmp(name, "pidfile")) {
+    if (server_info->pid_file) return SILC_CONFIG_EDOUBLE;
+    server_info->pid_file = strdup((char *) val);
+  }
+  else if (!strcmp(name, "publickey")) {
+    char *tmp = (char *) val;
+
+    /* try to load specified file, if fail stop config parsing */
+    if (!silc_pkcs_load_public_key(tmp, &server_info->public_key,
+                                  SILC_PKCS_FILE_PEM))
+      if (!silc_pkcs_load_public_key(tmp, &server_info->public_key,
+                                    SILC_PKCS_FILE_BIN)) {
+       fprintf(stderr, "\nError: Could not load public key file.");
+       fprintf(stderr, "\n  line %lu: file \"%s\"\n", line, tmp);
+       return SILC_CONFIG_ESILENT;
       }
-
-      /* Get port */
-      ret = silc_config_get_token(line, &tmp);
-      if (ret < 0)
-       break;
-      if (ret) {
-       config->routers->port = atoi(tmp);
-       silc_free(tmp);
+  }
+  else if (!strcmp(name, "privatekey")) {
+    char *tmp = (char *) val;
+
+    /* try to load specified file, if fail stop config parsing */
+    if (!silc_pkcs_load_private_key(tmp, &server_info->private_key,
+                                   SILC_PKCS_FILE_BIN))
+      if (!silc_pkcs_load_private_key(tmp, &server_info->private_key,
+                                     SILC_PKCS_FILE_PEM)) {
+       fprintf(stderr, "\nError: Could not load private key file.");
+       fprintf(stderr, "\n  line %lu: file \"%s\"\n", line, tmp);
+       return SILC_CONFIG_ESILENT;
       }
+  }
+  else
+    return SILC_CONFIG_EINTERNAL;
+  return SILC_CONFIG_OK;
+}
 
-      /* Get version */
-      ret = silc_config_get_token(line, &config->routers->version);
-      if (ret < 0)
-       break;
+SILC_CONFIG_CALLBACK(fetch_logging)
+{
+  SilcServerConfig config = (SilcServerConfig) context;
+  SilcServerConfigSectionLogging *tmp =
+       (SilcServerConfigSectionLogging *) config->tmp;
+  int got_errno;
 
-      /* Get class number */
-      ret = silc_config_get_token(line, &tmp);
-      if (ret < 0)
-       break;
-      if (ret) {
-       config->routers->class = atoi(tmp);
-       silc_free(tmp);
-      }
+  if (!strcmp(name, "quicklogs")) {
+    silc_log_quick = *(bool *)val;
+  }
+  else if (!strcmp(name, "flushdelay")) {
+    int flushdelay = *(int *)val;
+    if (flushdelay < 2) { /* this value was taken from silclog.h (min delay) */
+      fprintf(stderr, "Error: line %lu: invalid flushdelay value, use "
+               "quicklogs if you want real-time logging.\n", line);
+      return SILC_CONFIG_ESILENT;
+    }
+    silc_log_flushdelay = (long) flushdelay;
+  }
+#define FETCH_LOGGING_CHAN(__chan__, __member__)               \
+  else if (!strcmp(name, __chan__)) {                          \
+    if (!tmp) return SILC_CONFIG_OK;                           \
+    if (!tmp->file) {                                          \
+      got_errno = SILC_CONFIG_EMISSFIELDS; goto got_err;       \
+    }                                                          \
+    config->__member__ = tmp;                                  \
+    config->tmp = NULL;                                                \
+  }
+  FETCH_LOGGING_CHAN("info", logging_info)
+  FETCH_LOGGING_CHAN("warnings", logging_warnings)
+  FETCH_LOGGING_CHAN("errors", logging_errors)
+  FETCH_LOGGING_CHAN("fatals", logging_fatals)
+#undef FETCH_LOGGING_CHAN
+  else if (!strcmp(name, "file")) {
+    if (!tmp) { /* FIXME: what the fuck is this? */
+      config->tmp = silc_calloc(1, sizeof(*tmp));
+      tmp = (SilcServerConfigSectionLogging *) config->tmp;
+    }
+    if (tmp->file) {
+      got_errno = SILC_CONFIG_EMISSFIELDS; goto got_err;
+    }
+    tmp->file = strdup((char *) val);
+  }
+  else if (!strcmp(name, "size")) {
+    if (!tmp) {
+      config->tmp = silc_calloc(1, sizeof(*tmp));
+      tmp = (SilcServerConfigSectionLogging *) config->tmp;
+    }
+    tmp->maxsize = *(uint32 *) val;
+  }
+  else
+    return SILC_CONFIG_EINTERNAL;
+  return SILC_CONFIG_OK;
+
+ got_err:
+  silc_free(tmp->file);
+  silc_free(tmp);
+  config->tmp = NULL;
+  return got_errno;
+}
 
-      /* Get whether we are initiator or not */
-      ret = silc_config_get_token(line, &tmp);
-      if (ret < 0)
-       break;
-      if (ret) {
-       config->routers->initiator = atoi(tmp);
-       if (config->routers->initiator != 0)
-         config->routers->initiator = TRUE;
-       silc_free(tmp);
-      }
+SILC_CONFIG_CALLBACK(fetch_client)
+{
+  SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigSectionClient);
+
+  SERVER_CONFIG_DEBUG(("Received CLIENT type=%d name=\"%s\" (val=%x)", type, name, context));
+  if (type == SILC_CONFIG_ARG_BLOCK) {
+    if (!tmp) /* empty sub-block? */
+      return SILC_CONFIG_OK;
+    if (tmp->auth_meth && !tmp->auth_data) {
+      fprintf(stderr, "\nError: line %lu: If you specify \"AuthMethod\" field "
+               "then you must also specify the \"AuthData\" field.\n", line);
+      got_errno = SILC_CONFIG_ESILENT;
+      goto got_err;
+    }
+    SILC_SERVER_CONFIG_LIST_APPENDTMP(config->clients);
+    config->tmp = NULL;
+    return SILC_CONFIG_OK;
+  }
+  /* if there isn't a temporary struct alloc one */
+  if (!tmp) {
+    config->tmp = silc_calloc(1, sizeof(*findtmp));
+    tmp = (SilcServerConfigSectionClient *) config->tmp;
+  }
 
-      /* Get backup replace IP */
-      ret = silc_config_get_token(line, &config->routers->backup_replace_ip);
-      if (ret != -1)
-       config->routers->backup_router = TRUE;
-
-      if (config->routers->backup_router) {
-       /* Get backup replace port */
-       ret = silc_config_get_token(line, &tmp);
-       if (ret != -1) {
-         config->routers->backup_replace_port = atoi(tmp);
-         silc_free(tmp);
-       }
-       
-       /* Check whether the backup connection is local */
-       ret = silc_config_get_token(line, &tmp);
-       if (ret != -1) {
-         config->routers->backup_local = atoi(tmp);
-         if (config->routers->backup_local != 0)
-           config->routers->backup_local = TRUE;
-         silc_free(tmp);
-       }
-      }
+  /* Identify and save this value */
+  if (!strcmp(name, "host")) { /* any host (*) accepted */
+    if (tmp->host) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
+    tmp->host = (*(char *)val ? strdup((char *) val) : NULL);
+  }
+  /* get authentication method */
+  else if (!strcmp(name, "authmethod")) {
+    if (!strcmp((char *) val, SILC_CONFIG_SERVER_AUTH_METH_PASSWD))
+      tmp->auth_meth = SILC_AUTH_PASSWORD;
+    else if (!strcmp((char *) val, SILC_CONFIG_SERVER_AUTH_METH_PUBKEY))
+      tmp->auth_meth = SILC_AUTH_PUBLIC_KEY;
+    else {
+      got_errno = SILC_CONFIG_EINVALIDTEXT; goto got_err;
+    }
+  }
+  else if (!strcmp(name, "authdata")) {
+    if (!my_parse_authdata(tmp->auth_meth, (char *) val, line,
+                          &tmp->auth_data, &tmp->auth_data_len)) {
+      got_errno = SILC_CONFIG_ESILENT;
+      goto got_err; /* error outputted in my_parse_authdata */
+    }
+  }
+  else if (!strcmp(name, "port")) {
+    int port = *(int *)val;
+    if ((port <= 0) || (port > 65535)) {
+      fprintf(stderr, "Invalid port number!\n");
+      got_errno = SILC_CONFIG_ESILENT; goto got_err;
+    }
+    tmp->port = (uint16) port;
+  }
+  /* FIXME: Improvement: use a direct class struct pointer instead of num */
+  else if (!strcmp(name, "class")) {
+    /* XXX do nothing */
+  }
+  else
+    return SILC_CONFIG_EINTERNAL;
+  return SILC_CONFIG_OK;
+
+ got_err:
+  silc_free(tmp->host);
+  my_free_authdata(tmp->auth_meth, tmp->auth_data);
+  silc_free(tmp);
+  return got_errno;
+}
 
-      check = TRUE;
-      checkmask |= (1L << pc->section->type);
-      break;
+SILC_CONFIG_CALLBACK(fetch_admin)
+{
+  SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigSectionAdmin);
+
+  SERVER_CONFIG_DEBUG(("Received CLIENT type=%d name=\"%s\" (val=%x)", type, name, context));
+  if (type == SILC_CONFIG_ARG_BLOCK) {
+    /* check the temporary struct's fields */
+    if (!tmp) /* empty sub-block? */
+      return SILC_CONFIG_OK;
+    if (!tmp->auth_meth) {
+      got_errno = SILC_CONFIG_EMISSFIELDS; goto got_err;
+    }
+    SILC_SERVER_CONFIG_LIST_APPENDTMP(config->admins);
+    config->tmp = NULL;
+    return SILC_CONFIG_OK;
+  }
+  /* if there isn't a temporary struct alloc one */
+  if (!tmp) {
+    config->tmp = silc_calloc(1, sizeof(*findtmp));
+    tmp = (SilcServerConfigSectionAdmin *) config->tmp;
+  }
 
-    case SILC_CONFIG_SERVER_SECTION_TYPE_ADMIN_CONNECTION:
+  /* Identify and save this value */
+  if (!strcmp(name, "host")) { /* any host (*) accepted */
+    if (tmp->host) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
+    tmp->host = (*(char *)val ? strdup((char *) val) : NULL);
+  }
+  else if (!strcmp(name, "user")) {
+    if (tmp->user) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
+    tmp->user = (*(char *)val ? strdup((char *) val) : NULL);
+  }
+  else if (!strcmp(name, "nick")) {
+    if (tmp->nick) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
+    tmp->nick = (*(char *)val ? strdup((char *) val) : NULL);
+  }
+  /* get authentication method */
+  else if (!strcmp(name, "authmethod")) {
+    if (!strcmp((char *) val, SILC_CONFIG_SERVER_AUTH_METH_PASSWD))
+      tmp->auth_meth = SILC_AUTH_PASSWORD;
+    else if (!strcmp((char *) val, SILC_CONFIG_SERVER_AUTH_METH_PUBKEY))
+      tmp->auth_meth = SILC_AUTH_PUBLIC_KEY;
+    else {
+      got_errno = SILC_CONFIG_EINVALIDTEXT; goto got_err;
+    }
+  }
+  else if (!strcmp(name, "authdata")) {
+    if (!my_parse_authdata(tmp->auth_meth, (char *) val, line,
+                          &tmp->auth_data, &tmp->auth_data_len)) {
+      got_errno = SILC_CONFIG_ESILENT;
+      goto got_err; /* error outputted in my_parse_authdata */
+    }
+  }
+  else
+    return SILC_CONFIG_EINTERNAL;
+  return SILC_CONFIG_OK;
+
+ got_err:
+  silc_free(tmp->host);
+  silc_free(tmp->user);
+  silc_free(tmp->nick);
+  my_free_authdata(tmp->auth_meth, tmp->auth_data);
+  silc_free(tmp);
+  return got_errno;
+}
 
-      SILC_SERVER_CONFIG_LIST_ALLOC(config->admins);
+SILC_CONFIG_CALLBACK(fetch_deny)
+{
+  SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigSectionDeny);
+
+  SERVER_CONFIG_DEBUG(("Received DENY type=%d name=\"%s\" (val=%x)", type, name, context));
+  if (type == SILC_CONFIG_ARG_BLOCK) {
+    /* check the temporary struct's fields */
+    if (!tmp) /* empty sub-block? */
+      return SILC_CONFIG_OK;
+    if (!tmp->reason) {
+      got_errno = SILC_CONFIG_EMISSFIELDS;
+      goto got_err;
+    }
+    SILC_SERVER_CONFIG_LIST_APPENDTMP(config->denied);
+    config->tmp = NULL;
+    return SILC_CONFIG_OK;
+  }
+  /* if there isn't a temporary struct alloc one */
+  if (!tmp) {
+    config->tmp = silc_calloc(1, sizeof(*findtmp));
+    tmp = (SilcServerConfigSectionDeny *) config->tmp;
+  }
 
-      /* Get host */
-      ret = silc_config_get_token(line, &config->admins->host);
-      if (ret < 0)
-       break;
-      if (ret == 0)
-       /* Any host */
-       config->admins->host = strdup("*");
+  /* Identify and save this value */
+  if (!strcmp(name, "host")) { /* any host (*) accepted */
+    if (tmp->host) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
+    tmp->host = (*(char *)val ? strdup((char *) val) : strdup("*"));
+  }
+  else if (!strcmp(name, "port")) {
+    int port = *(int *)val;
+    if ((port <= 0) || (port > 65535)) {
+      fprintf(stderr, "Invalid port number!\n");
+      got_errno = SILC_CONFIG_ESILENT; goto got_err;
+    }
+    tmp->port = (uint16) port;
+  }
+  else if (!strcmp(name, "reason")) {
+    if (tmp->reason) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
+    tmp->reason = strdup((char *) val);
+  }
+  else
+    return SILC_CONFIG_EINTERNAL;
+  return SILC_CONFIG_OK;
+
+ got_err:
+  silc_free(tmp->host);
+  silc_free(tmp->reason);
+  silc_free(tmp);
+  return got_errno;
+}
 
-      /* Get username */
-      ret = silc_config_get_token(line, &config->admins->username);
-      if (ret < 0)
-       break;
-      if (ret == 0)
-       /* Any username */
-       config->admins->username = strdup("*");
+SILC_CONFIG_CALLBACK(fetch_server)
+{
+  SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigSectionServer);
+
+  SERVER_CONFIG_DEBUG(("Received SERVER type=%d name=\"%s\" (val=%x)", type, name, context));
+  if (type == SILC_CONFIG_ARG_BLOCK) {
+    /* check the temporary struct's fields */
+    if (!tmp) /* empty sub-block? */
+      return SILC_CONFIG_OK;
+    if (!tmp->auth_meth || !tmp->version) {
+      got_errno = SILC_CONFIG_EMISSFIELDS;
+      goto got_err;
+    }
+    /* the temporary struct is ok, append it to the list */
+    SILC_SERVER_CONFIG_LIST_APPENDTMP(config->servers);
+    config->tmp = NULL;
+    return SILC_CONFIG_OK;
+  }
+  /* if there isn't a temporary struct alloc one */
+  if (!tmp) {
+    config->tmp = silc_calloc(1, sizeof(*findtmp));
+    tmp = (SilcServerConfigSectionServer *) config->tmp;
+  }
 
-      /* Get nickname */
-      ret = silc_config_get_token(line, &config->admins->nickname);
-      if (ret < 0)
-       break;
-      if (ret == 0)
-       /* Any nickname */
-       config->admins->nickname = strdup("*");
+  /* Identify and save this value */
+  if (!strcmp(name, "host")) { /* any host (*) accepted */
+    if (tmp->host) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
+    tmp->host = (*(char *)val ? strdup((char *) val) : strdup("*"));
+  }
+  /* get authentication method */
+  else if (!strcmp(name, "authmethod")) {
+    if (!strcmp((char *) val, SILC_CONFIG_SERVER_AUTH_METH_PASSWD))
+      tmp->auth_meth = SILC_AUTH_PASSWORD;
+    else if (!strcmp((char *) val, SILC_CONFIG_SERVER_AUTH_METH_PUBKEY))
+      tmp->auth_meth = SILC_AUTH_PUBLIC_KEY;
+    else {
+      got_errno = SILC_CONFIG_EINVALIDTEXT; goto got_err;
+    }
+  }
+  else if (!strcmp(name, "authdata")) {
+    if (!my_parse_authdata(tmp->auth_meth, (char *) val, line,
+                          &tmp->auth_data, &tmp->auth_data_len)) {
+      got_errno = SILC_CONFIG_ESILENT;
+      goto got_err; /* error outputted in my_parse_authdata */
+    }
+  }
+  else if (!strcmp(name, "port")) {
+    int port = *(int *)val;
+    if ((port <= 0) || (port > 65535)) {
+      fprintf(stderr, "Invalid port number!\n");
+      got_errno = SILC_CONFIG_ESILENT; goto got_err;
+    }
+    tmp->port = (uint16) port;
+  }
+  else if (!strcmp(name, "versionid")) {
+    if (tmp->version) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
+    tmp->version = strdup((char *) val);
+  }
+  /* FIXME: Improvement: use a direct class struct pointer instead of num */
+  else if (!strcmp(name, "class")) {
+    /* XXX do nothing */
+  }
+  else if (!strcmp(name, "backup")) {
+    tmp->backup_router = *(bool *)val;
+  }
+  else
+    return SILC_CONFIG_EINTERNAL;
+  return SILC_CONFIG_OK;
+
+ got_err:
+  silc_free(tmp->host);
+  silc_free(tmp->version);
+  my_free_authdata(tmp->auth_meth, tmp->auth_data);
+  silc_free(tmp);
+  return got_errno;
+}
 
-      /* Get authentication method */
-      ret = silc_config_get_token(line, &tmp);
-      if (ret < 0)
-       break;
-      if (ret) {
-       if (strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PASSWD) &&
-           strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PUBKEY)) {
-         fprintf(stderr, "%s:%d: Unknown authentication method '%s'\n",
-                 config->filename, pc->linenum, tmp);
-         break;
-       }
+SILC_CONFIG_CALLBACK(fetch_router)
+{
+  SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigSectionRouter);
+
+  SERVER_CONFIG_DEBUG(("Received ROUTER type=%d name=\"%s\" (val=%x)", type, name, context));
+  if (type == SILC_CONFIG_ARG_BLOCK) {
+    if (!tmp) /* empty sub-block? */
+      return SILC_CONFIG_OK;
+    if (!tmp->auth_meth || !tmp->version) {
+      got_errno = SILC_CONFIG_EMISSFIELDS;
+      goto got_err;
+    }
+    /* the temporary struct is ok, append it to the list */
+    SILC_SERVER_CONFIG_LIST_APPENDTMP(config->routers);
+    config->tmp = NULL;
+    return SILC_CONFIG_OK;
+  }
+  /* if there isn't a temporary struct alloc one */
+  if (!tmp) {
+    config->tmp = silc_calloc(1, sizeof(*findtmp));
+    tmp = (SilcServerConfigSectionRouter *) config->tmp;
+  }
 
-       if (!strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PASSWD))
-         config->admins->auth_meth = SILC_AUTH_PASSWORD;
+  /* Identify and save this value */
+  if (!strcmp(name, "host")) {
+    if (tmp->host) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
+    tmp->host = strdup((char *) val);
+  }
+  else if (!strcmp(name, "authmethod")) {
+    if (!strcmp((char *) val, SILC_CONFIG_SERVER_AUTH_METH_PASSWD))
+      tmp->auth_meth = SILC_AUTH_PASSWORD;
+    else if (!strcmp((char *) val, SILC_CONFIG_SERVER_AUTH_METH_PUBKEY))
+      tmp->auth_meth = SILC_AUTH_PUBLIC_KEY;
+    else {
+      got_errno = SILC_CONFIG_EINVALIDTEXT; goto got_err;
+    }
+  }
+  else if (!strcmp(name, "authdata")) {
+    if (!my_parse_authdata(tmp->auth_meth, (char *) val, line,
+                          &tmp->auth_data, &tmp->auth_data_len)) {
+      got_errno = SILC_CONFIG_ESILENT;
+      goto got_err; /* error outputted in my_parse_authdata */
+    }
+  }
+  else if (!strcmp(name, "port")) {
+    int port = *(int *)val;
+    if ((port <= 0) || (port > 65535)) {
+      fprintf(stderr, "Invalid port number!\n");
+      got_errno = SILC_CONFIG_ESILENT; goto got_err;
+    }
+    tmp->port = (uint16) port;
+  }
+  else if (!strcmp(name, "versionid")) {
+    if (tmp->version) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
+    tmp->version = strdup((char *) val);
+  }
+  /* FIXME: Improvement: use a direct class struct pointer instead of num */
+  else if (!strcmp(name, "class")) {
+    /* XXX do nothing */
+  }
+  else if (!strcmp(name, "initiator"))
+    tmp->initiator = *(bool *)val;
+  else if (!strcmp(name, "backuphost")) {
+    if (tmp->backup_replace_ip) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
+    tmp->backup_replace_ip = (*(char *)val ? strdup((char *) val) : strdup("*"));
+  }
+  else
+    return SILC_CONFIG_EINTERNAL;
+  return SILC_CONFIG_OK;
+
+ got_err:
+  silc_free(tmp->host);
+  silc_free(tmp->version);
+  silc_free(tmp->backup_replace_ip);
+  my_free_authdata(tmp->auth_meth, tmp->auth_data);
+  silc_free(tmp);
+  return got_errno;
+}
 
-       if (!strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PUBKEY))
-         config->admins->auth_meth = SILC_AUTH_PUBLIC_KEY;
+/* known config options tables */
+static const SilcConfigTable table_general[] = {
+  { "modulepath",      SILC_CONFIG_ARG_STRE,   fetch_generic,  NULL },
+  { 0, 0, 0, 0 }
+};
 
-       silc_free(tmp);
-      }
+static const SilcConfigTable table_cipher[] = {
+  { "name",            SILC_CONFIG_ARG_STR,    fetch_cipher,   NULL },
+  { "module",          SILC_CONFIG_ARG_STRE,   fetch_cipher,   NULL },
+  { "key_length",      SILC_CONFIG_ARG_INT,    fetch_cipher,   NULL },
+  { "block_length",    SILC_CONFIG_ARG_INT,    fetch_cipher,   NULL },
+  { 0, 0, 0, 0 }
+};
 
-      /* Get authentication data */
-      ret = silc_config_get_token(line, (char **)&config->admins->auth_data);
-      if (ret < 0)
-       break;
+static const SilcConfigTable table_hash[] = {
+  { "name",            SILC_CONFIG_ARG_STR,    fetch_hash,     NULL },
+  { "module",          SILC_CONFIG_ARG_STRE,   fetch_hash,     NULL },
+  { "block_length",    SILC_CONFIG_ARG_INT,    fetch_hash,     NULL },
+  { "digest_length",   SILC_CONFIG_ARG_INT,    fetch_hash,     NULL },
+  { 0, 0, 0, 0 }
+};
 
-      if (config->admins->auth_meth == SILC_AUTH_PASSWORD) {
-       config->admins->auth_data_len = strlen(config->admins->auth_data);
-      } else if (config->admins->auth_meth == SILC_AUTH_PUBLIC_KEY) {
-       /* Get the public key */
-       SilcPublicKey public_key;
-
-       if (!silc_pkcs_load_public_key(config->admins->auth_data,
-                                      &public_key, SILC_PKCS_FILE_PEM))
-         if (!silc_pkcs_load_public_key(config->admins->auth_data,
-                                        &public_key, SILC_PKCS_FILE_BIN)) {
-           fprintf(stderr, "%s:%d: Could not load public key file `%s'\n",
-                   config->filename, pc->linenum, 
-                   (char *)config->admins->auth_data);
-           break;
-         }
-
-       silc_free(config->admins->auth_data);
-       config->admins->auth_data = (void *)public_key;
-       config->admins->auth_data_len = 0;
-      }
+static const SilcConfigTable table_hmac[] = {
+  { "name",            SILC_CONFIG_ARG_STR,    fetch_hmac,     NULL },
+  { "hash",            SILC_CONFIG_ARG_STR,    fetch_hmac,     NULL },
+  { "mac_length",      SILC_CONFIG_ARG_INT,    fetch_hmac,     NULL },
+  { 0, 0, 0, 0 }
+};
 
-      check = TRUE;
-      checkmask |= (1L << pc->section->type);
-      break;
+static const SilcConfigTable table_pkcs[] = {
+  { "name",            SILC_CONFIG_ARG_STR,    fetch_pkcs,     NULL },
+  { 0, 0, 0, 0 }
+};
 
-    case SILC_CONFIG_SERVER_SECTION_TYPE_DENY_CONNECTION:
+static const SilcConfigTable table_serverinfo[] = {
+  { "hostname",                SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
+  { "ip",              SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
+  { "port",            SILC_CONFIG_ARG_INT,    fetch_serverinfo, NULL},
+  { "servertype",      SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
+  { "location",                SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
+  { "admin",           SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
+  { "email",           SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
+  { "user",            SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
+  { "group",           SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
+  { "publickey",       SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
+  { "privatekey",      SILC_CONFIG_ARG_STR,    fetch_serverinfo, NULL},
+  { "motdfile",                SILC_CONFIG_ARG_STRE,   fetch_serverinfo, NULL},
+  { "pidfile",         SILC_CONFIG_ARG_STRE,   fetch_serverinfo, NULL},
+  { 0, 0, 0, 0 }
+};
 
-      SILC_SERVER_CONFIG_LIST_ALLOC(config->denied);
+static const SilcConfigTable table_logging_c[] = {
+  { "file",            SILC_CONFIG_ARG_STR,    fetch_logging,  NULL },
+  { "size",            SILC_CONFIG_ARG_SIZE,   fetch_logging,  NULL },
+/*{ "quicklog",                SILC_CONFIG_ARG_NONE,   fetch_logging,  NULL }, */
+  { 0, 0, 0, 0 }
+};
 
-      /* Get host */
-      ret = silc_config_get_token(line, &config->denied->host);
-      if (ret < 0)
-       break;
-      if (ret == 0) {
-       /* Any host */
-       config->denied->host = strdup("*");
-       fprintf(stderr, "warning: %s:%d: Denying all connections",
-               config->filename, pc->linenum);
-      }
+static const SilcConfigTable table_logging[] = {
+  { "quicklogs",       SILC_CONFIG_ARG_TOGGLE, fetch_logging,  NULL },
+  { "flushdelay",      SILC_CONFIG_ARG_INT,    fetch_logging,  NULL },
+  { "info",            SILC_CONFIG_ARG_BLOCK,  fetch_logging,  table_logging_c },
+  { "warnings",                SILC_CONFIG_ARG_BLOCK,  fetch_logging,  table_logging_c },
+  { "errors",          SILC_CONFIG_ARG_BLOCK,  fetch_logging,  table_logging_c },
+  { "fatals",          SILC_CONFIG_ARG_BLOCK,  fetch_logging,  table_logging_c },
+  { 0, 0, 0, 0 }
+};
 
-      /* Get port */
-      ret = silc_config_get_token(line, &tmp);
-      if (ret < 0)
-       break;
-      if (ret == 0) {
-       /* Any port */
-       config->denied->port = 0;
-      } else {
-       config->denied->port = atoi(tmp);
-       silc_free(tmp);
-      }
+/* still unsupported
+static const SilcConfigTable table_class[] = {
+  { "name",            SILC_CONFIG_ARG_STR,    fetch_class,    NULL },
+  { "ping",            SILC_CONFIG_ARG_INT,    fetch_class,    NULL },
+  { "connect",         SILC_CONFIG_ARG_INT,    fetch_class,    NULL },
+  { "links",           SILC_CONFIG_ARG_INT,    fetch_class,    NULL },
+  { 0, 0, 0, 0 }
+}; */
+
+static const SilcConfigTable table_client[] = {
+  { "host",            SILC_CONFIG_ARG_STRE,   fetch_client,   NULL },
+  { "authmethod",      SILC_CONFIG_ARG_STR,    fetch_client,   NULL },
+  { "authdata",                SILC_CONFIG_ARG_STR,    fetch_client,   NULL },
+  { "port",            SILC_CONFIG_ARG_INT,    fetch_client,   NULL },
+  { "class",           SILC_CONFIG_ARG_STR,    fetch_client,   NULL },
+  { 0, 0, 0, 0 }
+};
 
-      /* Get comment */
-      ret = silc_config_get_token(line, &config->denied->comment);
-      if (ret < 0)
-       break;
+static const SilcConfigTable table_admin[] = {
+  { "host",            SILC_CONFIG_ARG_STRE,   fetch_admin,    NULL },
+  { "user",            SILC_CONFIG_ARG_STRE,   fetch_admin,    NULL },
+  { "nick",            SILC_CONFIG_ARG_STRE,   fetch_admin,    NULL },
+  { "authmethod",      SILC_CONFIG_ARG_STR,    fetch_admin,    NULL },
+  { "authdata",                SILC_CONFIG_ARG_STR,    fetch_admin,    NULL },
+  { "port",            SILC_CONFIG_ARG_INT,    fetch_admin,    NULL },
+  { "class",           SILC_CONFIG_ARG_STR,    fetch_admin,    NULL },
+  { 0, 0, 0, 0 }
+};
 
-      check = TRUE;
-      checkmask |= (1L << pc->section->type);
-      break;
+static const SilcConfigTable table_deny[] = {
+  { "host",            SILC_CONFIG_ARG_STRE,   fetch_deny,     NULL },
+  { "port",            SILC_CONFIG_ARG_INT,    fetch_deny,     NULL },
+  { "reason",          SILC_CONFIG_ARG_STR,    fetch_deny,     NULL },
+  { 0, 0, 0, 0 }
+};
 
-    case SILC_CONFIG_SERVER_SECTION_TYPE_MOTD:
+static const SilcConfigTable table_serverconn[] = {
+  { "host",            SILC_CONFIG_ARG_STRE,   fetch_server,   NULL },
+  { "authmethod",      SILC_CONFIG_ARG_STR,    fetch_server,   NULL },
+  { "authdata",                SILC_CONFIG_ARG_STR,    fetch_server,   NULL },
+  { "port",            SILC_CONFIG_ARG_INT,    fetch_server,   NULL },
+  { "versionid",       SILC_CONFIG_ARG_STR,    fetch_server,   NULL },
+  { "class",           SILC_CONFIG_ARG_STR,    fetch_server,   NULL },
+  { "backup",          SILC_CONFIG_ARG_TOGGLE, fetch_server,   NULL },
+  { 0, 0, 0, 0 }
+};
 
-      if (!config->motd)
-       config->motd = silc_calloc(1, sizeof(*config->motd));
+static const SilcConfigTable table_routerconn[] = {
+  { "host",            SILC_CONFIG_ARG_STRE,   fetch_router,   NULL },
+  { "authmethod",      SILC_CONFIG_ARG_STR,    fetch_router,   NULL },
+  { "authdata",                SILC_CONFIG_ARG_STR,    fetch_router,   NULL },
+  { "port",            SILC_CONFIG_ARG_INT,    fetch_router,   NULL },
+  { "versionid",       SILC_CONFIG_ARG_STR,    fetch_router,   NULL },
+  { "class",           SILC_CONFIG_ARG_STR,    fetch_router,   NULL },
+  { "initiator",       SILC_CONFIG_ARG_TOGGLE, fetch_router,   NULL },
+  { "backuphost",      SILC_CONFIG_ARG_STRE,   fetch_router,   NULL },
+  { "backupport",      SILC_CONFIG_ARG_INT,    fetch_router,   NULL },
+  { "localbackup",     SILC_CONFIG_ARG_TOGGLE, fetch_router,   NULL },
+  { 0, 0, 0, 0 }
+};
 
-      /* Get motd file */
-      ret = silc_config_get_token(line, &config->motd->motd_file);
-      if (ret < 0)
-       break;
+static const SilcConfigTable table_main[] = {
+  { "general",         SILC_CONFIG_ARG_BLOCK,  NULL,           table_general },
+  { "cipher",          SILC_CONFIG_ARG_BLOCK,  fetch_cipher,   table_cipher },
+  { "hash",            SILC_CONFIG_ARG_BLOCK,  fetch_hash,     table_hash },
+  { "hmac",            SILC_CONFIG_ARG_BLOCK,  fetch_hmac,     table_hmac },
+  { "pkcs",            SILC_CONFIG_ARG_BLOCK,  fetch_pkcs,     table_pkcs },
+  { "serverinfo",      SILC_CONFIG_ARG_BLOCK,  fetch_serverinfo, table_serverinfo },
+  { "logging",         SILC_CONFIG_ARG_BLOCK,  NULL,           table_logging },
+/*{ "class",           SILC_CONFIG_ARG_BLOCK,  fetch_class,    table_class }, */
+  { "client",          SILC_CONFIG_ARG_BLOCK,  fetch_client,   table_client },
+  { "admin",           SILC_CONFIG_ARG_BLOCK,  fetch_admin,    table_admin },
+  { "deny",            SILC_CONFIG_ARG_BLOCK,  fetch_deny,     table_deny },
+  { "serverconnection",        SILC_CONFIG_ARG_BLOCK,  fetch_server,   table_serverconn },
+  { "routerconnection",        SILC_CONFIG_ARG_BLOCK,  fetch_router,   table_routerconn },
+  { 0, 0, 0, 0 }
+};
 
-      check = TRUE;
-      checkmask |= (1L << pc->section->type);
-      break;
+/* Allocates a new configuration object, opens configuration file and
+ * parses it. The parsed data is returned to the newly allocated
+ * configuration object. */
 
-    case SILC_CONFIG_SERVER_SECTION_TYPE_PID:
-
-       if (!config->pidfile)
-          config->pidfile = silc_calloc(1, sizeof(*config->pidfile));
-          
-       ret = silc_config_get_token(line, &config->pidfile->pid_file);
-       if (ret < 0)
-          break;
-          
-       check = TRUE;
-       checkmask |= (1L << pc->section->type);
-       break;
-
-    case SILC_CONFIG_SERVER_SECTION_TYPE_NONE:
-    default:
-      /* Error */
-      break;
-    }
+SilcServerConfig silc_server_config_alloc(char *filename)
+{
+  SilcServerConfig config;
+  SilcConfigEntity ent;
+  SilcConfigFile *file;
+  int ret;
+  SILC_LOG_DEBUG(("Loading config data from `%s'", filename));
 
-    /* Check for error */
-    if (check == FALSE) {
-      /* Line could not be parsed */
-      fprintf(stderr, "%s:%d: Parse error\n", config->filename, pc->linenum);
-      break;
+  /* alloc a config object */
+  config = (SilcServerConfig) silc_calloc(1, sizeof(*config));
+  /* obtain a config file object */
+  file = silc_config_open(filename);
+  if (!file) {
+    fprintf(stderr, "\nError: can't open config file `%s'\n", filename);
+    return NULL;
+  }
+  /* obtain a SilcConfig entity, we can use it to start the parsing */
+  ent = silc_config_init(file);
+  /* load the known configuration options, give our empty object as context */
+  silc_config_register_table(ent, table_main, (void *) config);
+  /* enter the main parsing loop.  When this returns, we have the parsing
+   * result and the object filled (or partially, in case of errors). */
+  ret = silc_config_main(ent);
+  SILC_LOG_DEBUG(("Parser returned [ret=%d]: %s", ret, silc_config_strerror(ret)));
+
+  /* Check if the parser returned errors */
+  if (ret) {
+    /* handle this special error return which asks to quietly return */
+    if (ret != SILC_CONFIG_ESILENT) {
+      char *linebuf, *filename = silc_config_get_filename(file);
+      uint32 line = silc_config_get_line(file);
+      fprintf(stderr, "\nError while parsing config file: %s.\n",
+               silc_config_strerror(ret));
+      linebuf = silc_config_read_line(file, line);
+      fprintf(stderr, "  file %s line %lu:  %s\n\n", filename, line, linebuf);
+      silc_free(linebuf);
     }
-
-    pc = pc->next;
+    return NULL;
   }
+  /* close (destroy) the file object */
+  silc_config_close(file);
 
-  if (check == FALSE)
-    return FALSE;
-
-  /* Check that all mandatory sections really were found. If not, the server
-     cannot function and we return error. */
-  ret = silc_server_config_check_sections(checkmask);
-  if (ret == FALSE) {
-    /* XXX */
-
-  }
-  
-  /* Before returning all the lists in the config object must be set
-     to their first values (the last value is first here). */
-  while (config->cipher && config->cipher->prev)
-    config->cipher = config->cipher->prev;
-  while (config->pkcs && config->pkcs->prev)
-    config->pkcs = config->pkcs->prev;
-  while (config->hash_func && config->hash_func->prev)
-    config->hash_func = config->hash_func->prev;
-  while (config->hmac && config->hmac->prev)
-    config->hmac = config->hmac->prev;
-  while (config->listen_port && config->listen_port->prev)
-    config->listen_port = config->listen_port->prev;
-  while (config->logging && config->logging->prev)
-    config->logging = config->logging->prev;
-  while (config->conn_class && config->conn_class->prev)
-    config->conn_class = config->conn_class->prev;
-  while (config->clients && config->clients->prev)
-    config->clients = config->clients->prev;
-  while (config->servers && config->servers->prev)
-    config->servers = config->servers->prev;
-  while (config->admins && config->admins->prev)
-    config->admins = config->admins->prev;
-  while (config->routers && config->routers->prev)
-    config->routers = config->routers->prev;
-  
-  SILC_LOG_DEBUG(("Done"));
-  
-  return TRUE;
+  /* XXX FIXME: check for missing mandatory fields */
+  if (!config->server_info) {
+    fprintf(stderr, "\nError: Missing mandatory block `server_info'\n");
+    return NULL;
+  }
+  return config;
 }
 
-/* This function checks that the mask sent as argument includes all the 
-   sections that are mandatory in SILC server. */
+/* ... */
 
-int silc_server_config_check_sections(uint32 checkmask)
+void silc_server_config_destroy(SilcServerConfig config)
 {
-  if (!(checkmask & (1L << SILC_CONFIG_SERVER_SECTION_TYPE_SERVER_INFO))) {
-    
-    return FALSE;
+  void *tmp;
+  silc_free(config->module_path);
+
+  /* Destroy Logging channels */
+  if (config->logging_info)
+    silc_free(config->logging_info->file);
+  if (config->logging_warnings)
+    silc_free(config->logging_warnings->file);
+  if (config->logging_errors)
+    silc_free(config->logging_errors->file);
+  if (config->logging_fatals)
+    silc_free(config->logging_fatals->file);
+
+  /* Destroy the ServerInfo struct */
+  if (config->server_info) {
+    register SilcServerConfigSectionServerInfo *si = config->server_info;
+    silc_free(si->server_name);
+    silc_free(si->server_ip);
+    silc_free(si->server_type);
+    silc_free(si->location);
+    silc_free(si->admin);
+    silc_free(si->email);
+    silc_free(si->user);
+    silc_free(si->group);
+    silc_free(si->motd_file);
+    silc_free(si->pid_file);
   }
-  if (!(checkmask & (1L << SILC_CONFIG_SERVER_SECTION_TYPE_ADMIN_INFO))) {
-    
-    return FALSE;
+
+  /* Now let's destroy the lists */
+
+  SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigSectionCipher,
+                                 config->cipher)
+    silc_free(di->name);
+    silc_free(di->module);
+    silc_free(di);
   }
-  if (!(checkmask & (1L << SILC_CONFIG_SERVER_SECTION_TYPE_LISTEN_PORT))) {
-    
-    return FALSE;
+  SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigSectionHash, config->hash)
+    silc_free(di->name);
+    silc_free(di->module);
+    silc_free(di);
   }
-  if (!(checkmask & 
-       (1L << SILC_CONFIG_SERVER_SECTION_TYPE_CLIENT_CONNECTION))) {
-    
-    return FALSE;
+  SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigSectionHmac, config->hmac)
+    silc_free(di->name);
+    silc_free(di->hash);
+    silc_free(di);
   }
-  if (!(checkmask 
-       & (1L << SILC_CONFIG_SERVER_SECTION_TYPE_SERVER_CONNECTION))) {
-    
-    return FALSE;
+  SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigSectionPkcs, config->pkcs)
+    silc_free(di->name);
+    silc_free(di);
   }
-  if (!(checkmask
-       & (1L << SILC_CONFIG_SERVER_SECTION_TYPE_ROUTER_CONNECTION))) {
-
-    return FALSE;
+  SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigSectionClient,
+                                 config->clients)
+    silc_free(di->host);
+    my_free_authdata(di->auth_meth, di->auth_data);
+    silc_free(di);
   }
-
-  return TRUE;
-}
-
-/* Sets log files where log messages is saved by the server. */
-
-void silc_server_config_setlogfiles(SilcServerConfig config, SilcSchedule sked)
-{
-  long tmp;
-  SilcServerConfigSectionLogging *log;
-
-  SILC_LOG_DEBUG(("Setting configured log file names"));
-  log = config->logging;
-  while (log) {
-    /* Logging Files */
-    if (!strcmp(log->logtype, SILC_CONFIG_SERVER_LF_INFO))
-      silc_log_set_file(SILC_LOG_INFO, log->filename, log->maxsize, sked);
-    if (!strcmp(log->logtype, SILC_CONFIG_SERVER_LF_WARNING))
-      silc_log_set_file(SILC_LOG_WARNING, log->filename, log->maxsize, sked);
-    if (!strcmp(log->logtype, SILC_CONFIG_SERVER_LF_ERROR))
-      silc_log_set_file(SILC_LOG_ERROR, log->filename, log->maxsize, sked);
-    if (!strcmp(log->logtype, SILC_CONFIG_SERVER_LF_FATAL))
-      silc_log_set_file(SILC_LOG_FATAL, log->filename, log->maxsize, sked);
-    /* Logging Options */
-    if (!strcmp(log->logtype, SILC_CONFIG_SERVER_LO_QUICK)) {
-      if (!strcasecmp(log->filename, "yes") ||
-         !strcasecmp(log->filename, "on"))
-          silc_log_quick = TRUE;
-    }
-    if (!strcmp(log->logtype, SILC_CONFIG_SERVER_LO_FDELAY)) {
-      tmp = atol(log->filename);
-      if (tmp > 0)
-        silc_log_flushdelay = tmp;
-      else {
-        fprintf(stderr, "config: invalid flushdelay value, use quicklogs if "
-               "you want real-time logging.\n");
-       exit(1);
-      }
-    }
-
-    log = log->next;
+  SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigSectionAdmin, config->admins)
+    silc_free(di->host);
+    silc_free(di->user);
+    silc_free(di->nick);
+    my_free_authdata(di->auth_meth, di->auth_data);
+    silc_free(di);
+  }
+  SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigSectionDeny, config->denied)
+    silc_free(di->host);
+    silc_free(di->reason);
+    silc_free(di);
+  }
+  SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigSectionServer,
+                                 config->servers)
+    silc_free(di->host);
+    silc_free(di->version);
+    my_free_authdata(di->auth_meth, di->auth_data);
+    silc_free(di);
+  }
+  SILC_SERVER_CONFIG_LIST_DESTROY(SilcServerConfigSectionRouter,
+                                 config->routers)
+    silc_free(di->host);
+    silc_free(di->version);
+    silc_free(di->backup_replace_ip);
+    my_free_authdata(di->auth_meth, di->auth_data);
+    silc_free(di);
   }
 }
 
 /* Registers configured ciphers. These can then be allocated by the
    server when needed. */
 
-bool silc_server_config_register_ciphers(SilcServerConfig config)
+bool silc_server_config_register_ciphers(SilcServer server)
 {
-  SilcServerConfigSectionAlg *alg;
-  SilcServer server = (SilcServer)config->server;
+  SilcServerConfig config = server->config;
+  SilcServerConfigSectionCipher *cipher = config->cipher;
+  char *module_path = config->module_path;
 
   SILC_LOG_DEBUG(("Registering configured ciphers"));
 
-  if (!config->cipher)
+  if (!cipher) /* any cipher in the config file? */
     return FALSE;
 
-  alg = config->cipher;
-  while(alg) {
-
-    if (!alg->sim_name) {
+  while (cipher) {
+    /* if there isn't a module_path OR there isn't a module sim name try to
+     * use buil-in functions */
+    if (!module_path || !cipher->module) {
       int i;
-      
       for (i = 0; silc_default_ciphers[i].name; i++)
-       if (!strcmp(silc_default_ciphers[i].name, alg->alg_name)) {
+       if (!strcmp(silc_default_ciphers[i].name, cipher->name)) {
          silc_cipher_register(&silc_default_ciphers[i]);
          break;
        }
-      
-      if (!silc_cipher_is_supported(alg->alg_name)) {
-       SILC_LOG_ERROR(("Unknown cipher `%s'", alg->alg_name));
+      if (!silc_cipher_is_supported(cipher->name)) {
+       SILC_LOG_ERROR(("Unknown cipher `%s'", cipher->name));
        silc_server_stop(server);
        exit(1);
       }
-#ifdef SILC_SIM
     } else {
+#ifdef SILC_SIM
       /* Load (try at least) the crypto SIM module */
-      SilcCipherObject cipher;
+      char buf[1023], *alg_name;
+      SilcCipherObject cipher_obj;
       SilcSimContext *sim;
-      char *alg_name;
 
-      memset(&cipher, 0, sizeof(cipher));
-      cipher.name = alg->alg_name;
-      cipher.block_len = alg->block_len;
-      cipher.key_len = alg->key_len * 8;
+      memset(&cipher_obj, 0, sizeof(cipher_obj));
+      cipher_obj.name = cipher->name;
+      cipher_obj.block_len = cipher->block_length;
+      cipher_obj.key_len = cipher->key_length * 8;
 
+      /* build the libname */
+      snprintf(buf, sizeof(buf), "%s/%s", config->module_path,
+               cipher->module);
       sim = silc_sim_alloc();
       sim->type = SILC_SIM_CIPHER;
-      sim->libname = alg->sim_name;
+      sim->libname = buf;
 
-      alg_name = strdup(alg->alg_name);
+      alg_name = strdup(cipher->name);
       if (strchr(alg_name, '-'))
        *strchr(alg_name, '-') = '\0';
 
-      if ((silc_sim_load(sim))) {
-       cipher.set_key = 
-         silc_sim_getsym(sim, silc_sim_symname(alg_name, 
+      if (silc_sim_load(sim)) {
+       cipher_obj.set_key =
+         silc_sim_getsym(sim, silc_sim_symname(alg_name,
                                                SILC_CIPHER_SIM_SET_KEY));
-       SILC_LOG_DEBUG(("set_key=%p", cipher.set_key));
-       cipher.set_key_with_string = 
-         silc_sim_getsym(sim, silc_sim_symname(alg_name, 
+       SILC_LOG_DEBUG(("set_key=%p", cipher_obj.set_key));
+       cipher_obj.set_key_with_string =
+         silc_sim_getsym(sim, silc_sim_symname(alg_name,
                                                SILC_CIPHER_SIM_SET_KEY_WITH_STRING));
-       SILC_LOG_DEBUG(("set_key_with_string=%p", cipher.set_key_with_string));
-       cipher.encrypt = 
+       SILC_LOG_DEBUG(("set_key_with_string=%p", cipher_obj.set_key_with_string));
+       cipher_obj.encrypt =
          silc_sim_getsym(sim, silc_sim_symname(alg_name,
                                                SILC_CIPHER_SIM_ENCRYPT_CBC));
-       SILC_LOG_DEBUG(("encrypt_cbc=%p", cipher.encrypt));
-        cipher.decrypt = 
+       SILC_LOG_DEBUG(("encrypt_cbc=%p", cipher_obj.encrypt));
+        cipher_obj.decrypt =
          silc_sim_getsym(sim, silc_sim_symname(alg_name,
                                                SILC_CIPHER_SIM_DECRYPT_CBC));
-       SILC_LOG_DEBUG(("decrypt_cbc=%p", cipher.decrypt));
-        cipher.context_len = 
+       SILC_LOG_DEBUG(("decrypt_cbc=%p", cipher_obj.decrypt));
+        cipher_obj.context_len =
          silc_sim_getsym(sim, silc_sim_symname(alg_name,
                                                SILC_CIPHER_SIM_CONTEXT_LEN));
-       SILC_LOG_DEBUG(("context_len=%p", cipher.context_len));
+       SILC_LOG_DEBUG(("context_len=%p", cipher_obj.context_len));
 
        /* Put the SIM to the list of all SIM's in server */
        silc_dlist_add(server->sim, sim);
@@ -1342,45 +1164,16 @@ bool silc_server_config_register_ciphers(SilcServerConfig config)
       }
 
       /* Register the cipher */
-      silc_cipher_register(&cipher);
-#endif
-    }
-
-    alg = alg->next;
-  }
-
-  return TRUE;
-}
-
-/* Registers configured PKCS's. */
-
-bool silc_server_config_register_pkcs(SilcServerConfig config)
-{
-  SilcServerConfigSectionAlg *alg = config->pkcs;
-  SilcServer server = (SilcServer)config->server;
-
-  SILC_LOG_DEBUG(("Registering configured PKCS"));
-
-  if (!config->pkcs)
-    return FALSE;
-
-  while(alg) {
-    int i;
-    
-    for (i = 0; silc_default_pkcs[i].name; i++)
-      if (!strcmp(silc_default_pkcs[i].name, alg->alg_name)) {
-       silc_pkcs_register(&silc_default_pkcs[i]);
-       break;
-      }
-      
-    if (!silc_pkcs_is_supported(alg->alg_name)) {
-      SILC_LOG_ERROR(("Unknown PKCS `%s'", alg->alg_name));
+      silc_cipher_register(&cipher_obj);
+#else
+      SILC_LOG_ERROR(("Dynamic module support not compiled, "
+                       "can't load modules!"));
       silc_server_stop(server);
       exit(1);
+#endif
     }
-
-    alg = alg->next;
-  }
+    cipher = cipher->next;
+  } /* while */
 
   return TRUE;
 }
@@ -1388,66 +1181,64 @@ bool silc_server_config_register_pkcs(SilcServerConfig config)
 /* Registers configured hash functions. These can then be allocated by the
    server when needed. */
 
-bool silc_server_config_register_hashfuncs(SilcServerConfig config)
+bool silc_server_config_register_hashfuncs(SilcServer server)
 {
-  SilcServerConfigSectionAlg *alg;
-  SilcServer server = (SilcServer)config->server;
+  SilcServerConfig config = server->config;
+  SilcServerConfigSectionHash *hash = config->hash;
+  char *module_path = config->module_path;
 
   SILC_LOG_DEBUG(("Registering configured hash functions"));
 
-  if (!config->hash_func)
+  if (!hash) /* any hash func in the config file? */
     return FALSE;
 
-  alg = config->hash_func;
-  while(alg) {
-
-    if (!alg->sim_name) {
+  while (hash) {
+    /* if there isn't a module_path OR there isn't a module sim name try to
+     * use buil-in functions */
+    if (!module_path || !hash->module) {
       int i;
-      
       for (i = 0; silc_default_hash[i].name; i++)
-       if (!strcmp(silc_default_hash[i].name, alg->alg_name)) {
+       if (!strcmp(silc_default_hash[i].name, hash->name)) {
          silc_hash_register(&silc_default_hash[i]);
          break;
        }
-      
-      if (!silc_hash_is_supported(alg->alg_name)) {
-       SILC_LOG_ERROR(("Unknown hash funtion `%s'", alg->alg_name));
+      if (!silc_hash_is_supported(hash->name)) {
+       SILC_LOG_ERROR(("Unknown hash funtion `%s'", hash->name));
        silc_server_stop(server);
        exit(1);
       }
-
-#ifdef SILC_SIM
     } else {
+#ifdef SILC_SIM
       /* Load (try at least) the hash SIM module */
-      SilcHashObject hash;
+      SilcHashObject hash_obj;
       SilcSimContext *sim;
 
-      memset(&hash, 0, sizeof(hash));
-      hash.name = alg->alg_name;
-      hash.block_len = alg->block_len;
-      hash.hash_len = alg->key_len;
+      memset(&hash_obj, 0, sizeof(hash_obj));
+      hash_obj.name = hash->name;
+      hash_obj.block_len = hash->block_length;
+      hash_obj.hash_len = hash->digest_length;
 
       sim = silc_sim_alloc();
       sim->type = SILC_SIM_HASH;
-      sim->libname = alg->sim_name;
+      sim->libname = hash->module;
 
       if ((silc_sim_load(sim))) {
-       hash.init = 
-         silc_sim_getsym(sim, silc_sim_symname(alg->alg_name, 
+       hash_obj.init =
+         silc_sim_getsym(sim, silc_sim_symname(hash->name,
                                                SILC_HASH_SIM_INIT));
-       SILC_LOG_DEBUG(("init=%p", hash.init));
-       hash.update = 
-         silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
+       SILC_LOG_DEBUG(("init=%p", hash_obj.init));
+       hash_obj.update =
+         silc_sim_getsym(sim, silc_sim_symname(hash->name,
                                                SILC_HASH_SIM_UPDATE));
-       SILC_LOG_DEBUG(("update=%p", hash.update));
-        hash.final = 
-         silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
+       SILC_LOG_DEBUG(("update=%p", hash_obj.update));
+        hash_obj.final =
+         silc_sim_getsym(sim, silc_sim_symname(hash->name,
                                                SILC_HASH_SIM_FINAL));
-       SILC_LOG_DEBUG(("final=%p", hash.final));
-        hash.context_len = 
-         silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
+       SILC_LOG_DEBUG(("final=%p", hash_obj.final));
+        hash_obj.context_len =
+         silc_sim_getsym(sim, silc_sim_symname(hash->name,
                                                SILC_HASH_SIM_CONTEXT_LEN));
-       SILC_LOG_DEBUG(("context_len=%p", hash.context_len));
+       SILC_LOG_DEBUG(("context_len=%p", hash_obj.context_len));
 
        /* Put the SIM to the table of all SIM's in server */
        silc_dlist_add(server->sim, sim);
@@ -1458,12 +1249,16 @@ bool silc_server_config_register_hashfuncs(SilcServerConfig config)
       }
 
       /* Register the hash function */
-      silc_hash_register(&hash);
+      silc_hash_register(&hash_obj);
+#else
+      SILC_LOG_ERROR(("Dynamic module support not compiled, "
+                       "can't load modules!"));
+      silc_server_stop(server);
+      exit(1);
 #endif
     }
-
-    alg = alg->next;
-  }
+    hash = hash->next;
+  } /* while */
 
   return TRUE;
 }
@@ -1471,87 +1266,180 @@ bool silc_server_config_register_hashfuncs(SilcServerConfig config)
 /* Registers configure HMACs. These can then be allocated by the server
    when needed. */
 
-bool silc_server_config_register_hmacs(SilcServerConfig config)
+bool silc_server_config_register_hmacs(SilcServer server)
 {
-  SilcServerConfigSectionAlg *alg;
-  SilcServer server = (SilcServer)config->server;
+  SilcServerConfig config = server->config;
+  SilcServerConfigSectionHmac *hmac = config->hmac;
 
   SILC_LOG_DEBUG(("Registering configured HMACs"));
 
-  if (!config->hmac)
+  if (!hmac)
     return FALSE;
 
-  alg = config->hmac;
-  while(alg) {
-    SilcHmacObject hmac;
-    
-    if (!silc_hash_is_supported(alg->sim_name)) {
-      SILC_LOG_ERROR(("Unknown hash function `%s'", alg->sim_name));
+  while (hmac) {
+    SilcHmacObject hmac_obj;
+    if (!silc_hash_is_supported(hmac->hash)) {
+      SILC_LOG_ERROR(("Unknown hash function `%s'", hmac->hash));
       silc_server_stop(server);
       exit(1);
     }
-    
     /* Register the HMAC */
-    memset(&hmac, 0, sizeof(hmac));
-    hmac.name = alg->alg_name;
-    hmac.len = alg->key_len;
-    silc_hmac_register(&hmac);
+    memset(&hmac_obj, 0, sizeof(hmac_obj));
+    hmac_obj.name = hmac->name;
+    hmac_obj.len = hmac->mac_length;
+    silc_hmac_register(&hmac_obj);
 
-    alg = alg->next;
-  }
+    hmac = hmac->next;
+  } /* while */
 
   return TRUE;
 }
 
-/* Returns client authentication information from server configuration
-   by host (name or ip). If `port' is non-null then both name or IP and 
-   the port must match. */
+/* Registers configured PKCS's. */
 
-SilcServerConfigSectionClientConnection *
-silc_server_config_find_client_conn(SilcServerConfig config, 
-                                   char *host, int port)
+bool silc_server_config_register_pkcs(SilcServer server)
 {
-  int i;
-  SilcServerConfigSectionClientConnection *client = NULL;
-  bool match = FALSE;
+  SilcServerConfig config = server->config;
+  SilcServerConfigSectionPkcs *pkcs = config->pkcs;
 
-  if (!host)
-    return NULL;
+  SILC_LOG_DEBUG(("Registering configured PKCS"));
+
+  if (!pkcs)
+    return FALSE;
+
+  while (pkcs) {
+    int i;
+    for (i = 0; silc_default_pkcs[i].name; i++)
+      if (!strcmp(silc_default_pkcs[i].name, pkcs->name)) {
+       silc_pkcs_register(&silc_default_pkcs[i]);
+       break;
+      }
+    if (!silc_pkcs_is_supported(pkcs->name)) {
+      SILC_LOG_ERROR(("Unknown PKCS `%s'", pkcs->name));
+      silc_server_stop(server);
+      exit(1);
+    }
+    pkcs = pkcs->next;
+  } /* while */
+
+  return TRUE;
+}
+
+/* Sets log files where log messages are saved by the server logger. */
+
+void silc_server_config_setlogfiles(SilcServerConfig config,
+                               SilcSchedule sked)
+{
+  SilcServerConfigSectionLogging *this;
+
+  SILC_LOG_DEBUG(("Setting configured log file names"));
 
-  if (!config->clients)
+  if ((this = config->logging_info))
+    silc_log_set_file(SILC_LOG_INFO, this->file, this->maxsize, sked);
+  if ((this = config->logging_warnings))
+    silc_log_set_file(SILC_LOG_WARNING, this->file, this->maxsize, sked);
+  if ((this = config->logging_errors))
+    silc_log_set_file(SILC_LOG_ERROR, this->file, this->maxsize, sked);
+  if ((this = config->logging_fatals))
+    silc_log_set_file(SILC_LOG_FATAL, this->file, this->maxsize, sked);
+}
+
+/* Returns client authentication information from configuration file by host
+   (name or ip) */
+
+SilcServerConfigSectionClient *
+silc_server_config_find_client(SilcServerConfig config, char *host, int port)
+{
+  SilcServerConfigSectionClient *client;
+
+  if (!config || !port) {
+    SILC_LOG_WARNING(("Bogus: config_find_client(config=0x%08x, "
+                     "host=0x%08x \"%s\", port=%hu)",
+                     (uint32) config, (uint32) host, host, port));
+    return NULL;
+  }
+  if (!host)
     return NULL;
 
-  client = config->clients;
+  for (client = config->clients; client; client = client->next) {
+    if (client->host && !silc_string_compare(client->host, host))
+      continue;
+    if (client->port && (client->port != port))
+      continue;
+    break;
+  }
+  /* if none matched, then client is already NULL */
+  return client;
+}
 
-  for (i = 0; client; i++) {
-    if (silc_string_compare(client->host, host))
-      match = TRUE;
+/* Returns admin connection configuration by host, username and/or
+   nickname. */
 
-    if (port && client->port && client->port != port)
-      match = FALSE;
+SilcServerConfigSectionAdmin *
+silc_server_config_find_admin(SilcServerConfig config,
+                             char *host, char *user, char *nick)
+{
+  SilcServerConfigSectionAdmin *admin;
 
-    if (match)
-      break;
+  /* make sure we have a value for the matching parameters */
+  if (!host)
+    host = "*";
+  if (!user)
+    user = "*";
+  if (!nick)
+    nick = "*";
 
-    client = client->next;
+  for (admin = config->admins; admin; admin = admin->next) {
+    if (admin->host && !silc_string_compare(admin->host, host))
+      continue;
+    if (admin->user && !silc_string_compare(admin->user, user))
+      continue;
+    if (admin->nick && !silc_string_compare(admin->nick, nick))
+      continue;
+    /* no checks failed -> this entry matches */
+    break;
   }
+  /* if none matched, then admin is already NULL */
+  return admin;
+}
+
+/* Returns the denied connection configuration entry by host and port. */
 
-  if (!client)
+SilcServerConfigSectionDeny *
+silc_server_config_find_denied(SilcServerConfig config,
+                              char *host, uint16 port)
+{
+  SilcServerConfigSectionDeny *deny;
+
+  /* make sure we have a value for the matching parameters */
+  if (!config || !port) {
+    SILC_LOG_WARNING(("Bogus: config_find_denied(config=0x%08x, "
+                     "host=0x%08x \"%s\", port=%hu)",
+                     (uint32) config, (uint32) host, host, port));
+    return NULL;
+  }
+  if (!host)
     return NULL;
 
-  return client;
+  for (deny = config->denied; deny; deny = deny->next) {
+    if (deny->host && !silc_string_compare(deny->host, host))
+      continue;
+    break;
+  }
+  /* if none matched, then deny is already NULL */
+  return deny;
 }
 
-/* Returns server connection info from server configuartion by host 
+/* Returns server connection info from server configuartion by host
    (name or ip). If `port' is non-null then both name or IP and the port
    must match. */
 
-SilcServerConfigSectionServerConnection *
-silc_server_config_find_server_conn(SilcServerConfig config, 
+SilcServerConfigSectionServer *
+silc_server_config_find_server_conn(SilcServerConfig config,
                                    char *host, int port)
 {
   int i;
-  SilcServerConfigSectionServerConnection *serv = NULL;
+  SilcServerConfigSectionServer *serv = NULL;
   bool match = FALSE;
 
   if (!host)
@@ -1580,15 +1468,15 @@ silc_server_config_find_server_conn(SilcServerConfig config,
   return serv;
 }
 
-/* Returns router connection info from server configuartion by
+/* Returns router connection info from server configuration by
    host (name or ip). */
 
-SilcServerConfigSectionServerConnection *
-silc_server_config_find_router_conn(SilcServerConfig config, 
+SilcServerConfigSectionRouter *
+silc_server_config_find_router_conn(SilcServerConfig config,
                                    char *host, int port)
 {
   int i;
-  SilcServerConfigSectionServerConnection *serv = NULL;
+  SilcServerConfigSectionRouter *serv = NULL;
   bool match = FALSE;
 
   if (!host)
@@ -1617,13 +1505,13 @@ silc_server_config_find_router_conn(SilcServerConfig config,
   return serv;
 }
 
-/* Returns TRUE if configuartion for a router connection that we are 
+/* Returns TRUE if configuration for a router connection that we are
    initiating exists. */
 
 bool silc_server_config_is_primary_route(SilcServerConfig config)
 {
   int i;
-  SilcServerConfigSectionServerConnection *serv = NULL;
+  SilcServerConfigSectionRouter *serv = NULL;
   bool found = FALSE;
 
   serv = config->routers;
@@ -1642,11 +1530,11 @@ bool silc_server_config_is_primary_route(SilcServerConfig config)
 /* Returns our primary connection configuration or NULL if we do not
    have primary router configured. */
 
-SilcServerConfigSectionServerConnection *
+SilcServerConfigSectionRouter *
 silc_server_config_get_primary_router(SilcServerConfig config)
 {
   int i;
-  SilcServerConfigSectionServerConnection *serv = NULL;
+  SilcServerConfigSectionRouter *serv = NULL;
 
   serv = config->routers;
   for (i = 0; serv; i++) {
@@ -1657,75 +1545,3 @@ silc_server_config_get_primary_router(SilcServerConfig config)
 
   return NULL;
 }
-
-/* Returns Admin connection configuration by host, username and/or 
-   nickname. */
-
-SilcServerConfigSectionAdminConnection *
-silc_server_config_find_admin(SilcServerConfig config,
-                             char *host, char *username, char *nickname)
-{
-  SilcServerConfigSectionAdminConnection *admin = NULL;
-  int i;
-
-  if (!config->admins)
-    return NULL;
-
-  if (!host)
-    host = "*";
-  if (!username)
-    username = "*";
-  if (!nickname)
-    nickname = "*";
-
-  admin = config->admins;
-  for (i = 0; admin; i++) {
-    if (silc_string_compare(admin->host, host) &&
-       silc_string_compare(admin->username, username) &&
-       silc_string_compare(admin->nickname, nickname))
-      break;
-
-    admin = admin->next;
-  }
-
-  if (!admin)
-    return NULL;
-
-  return admin;
-}
-
-/* Returns the Denied connection configuration by host and port. */
-
-SilcServerConfigSectionDenyConnection *
-silc_server_config_denied_conn(SilcServerConfig config, char *host,
-                              int port)
-{
-  int i;
-  SilcServerConfigSectionDenyConnection *deny = NULL;
-  bool match = FALSE;
-
-  if (!host)
-    return NULL;
-
-  if (!config->denied)
-    return NULL;
-
-  deny = config->denied;
-  for (i = 0; deny; i++) {
-    if (silc_string_compare(deny->host, host))
-      match = TRUE;
-
-    if (port && deny->port && deny->port != port)
-      match = FALSE;
-
-    if (match)
-      break;
-
-    deny = deny->next;
-  }
-
-  if (!deny)
-    return NULL;
-
-  return deny;
-}
index 4bf80bd018110b8cecece8866c9116c887be309b..8be6d7cb7ccec9fec883c62321ae4fd72e781a51 100644 (file)
@@ -2,15 +2,15 @@
 
   serverconfig.h
 
-  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+  Author: Johnny Mnemonic <johnny@themnemonic.org>
 
-  Copyright (C) 1997 - 2000 Pekka Riikonen
+  Copyright (C) 1997 - 2002 Pekka Riikonen
 
   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; either version 2 of the License, or
   (at your option) any later version.
-  
+
   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
 #ifndef SERVERCONFIG_H
 #define SERVERCONFIG_H
 
-/* Holds information of configured algorithms */
-typedef struct SilcServerConfigSectionAlgStruct {
-  char *alg_name;
-  char *sim_name;
-  uint32 block_len;
-  uint32 key_len;
-  struct SilcServerConfigSectionAlgStruct *next;
-  struct SilcServerConfigSectionAlgStruct *prev;
-#define SILC_CONFIG_SERVER_MODNAME "builtin"
-} SilcServerConfigSectionAlg;
-
-/* Holds server keys from config file */
-typedef struct {
-  SilcPublicKey public_key;
-  SilcPrivateKey private_key;
-} SilcServerConfigSectionServerKeys;
-
-/* Holds server information from config file */
-typedef struct {
+typedef struct SilcServerConfigSectionCipherStruct {
+  char *name;
+  char *module;
+  uint32 key_length;
+  uint32 block_length;
+  struct SilcServerConfigSectionCipherStruct *next;
+} SilcServerConfigSectionCipher;
+
+typedef struct SilcServerConfigSectionHashStruct {
+  char *name;
+  char *module;
+  uint32 block_length;
+  uint32 digest_length;
+  struct SilcServerConfigSectionHashStruct *next;
+} SilcServerConfigSectionHash;
+
+typedef struct SilcServerConfigSectionHmacStruct {
+  char *name;
+  char *hash;
+  uint32 mac_length;
+  struct SilcServerConfigSectionHmacStruct *next;
+} SilcServerConfigSectionHmac;
+
+typedef struct SilcServerConfigSectionPkcsStruct {
+  char *name;
+  struct SilcServerConfigSectionPkcsStruct *next;
+} SilcServerConfigSectionPkcs;
+
+typedef struct SilcServerConfigSectionServerInfoStruct {
   char *server_name;
   char *server_ip;
-  char *location;
   uint16 port;
+  char *server_type;   /* E.g. "Test Server" */
+  char *location;      /* geographic location */
+  char *admin;         /* admin full name */
+  char *email;         /* admin's email address */
+  char *user;          /* userid the server should be runned at */
+  char *group;         /* ditto, but about groupid */
+  SilcPublicKey public_key;
+  SilcPrivateKey private_key;
+  char *motd_file;     /* path to text motd file (reading only) */
+  char *pid_file;      /* path to the pid file (for reading and writing) */
 } SilcServerConfigSectionServerInfo;
 
-/* Holds server's administrative information from config file */
-typedef struct {
-  char *location;
-  char *server_type;
-  char *admin_name;
-  char *admin_email;
-} SilcServerConfigSectionAdminInfo;
-
-/* Holds all the ports the server is listenning on */
-typedef struct SilcServerConfigSectionListenPortStruct {
-  char *local_ip;
-  char *listener_ip;
-  uint16 port;
-  struct SilcServerConfigSectionListenPortStruct *next;
-  struct SilcServerConfigSectionListenPortStruct *prev;
-} SilcServerConfigSectionListenPort;
-
-/* Holds server's execution identity, or the user and group which
-   to change from root when server starts */
-typedef struct {
-  char *user;
-  char *group;
-} SilcServerConfigSectionIdentity;
-
-/* Holds all the configured log files. */
 typedef struct SilcServerConfigSectionLoggingStruct {
-  char *logtype;
-  char *filename;
+  char *file;
   uint32 maxsize;
-  struct SilcServerConfigSectionLoggingStruct *next;
-  struct SilcServerConfigSectionLoggingStruct *prev;
-
-/* Allowed <Logging> section types */
-#define SILC_CONFIG_SERVER_LF_INFO "infologfile"
-#define SILC_CONFIG_SERVER_LF_WARNING "warninglogfile"
-#define SILC_CONFIG_SERVER_LF_ERROR "errorlogfile"
-#define SILC_CONFIG_SERVER_LF_FATAL "fatallogfile"
-#define SILC_CONFIG_SERVER_LO_QUICK "quicklogs"
-#define SILC_CONFIG_SERVER_LO_FDELAY "flushdelay"
 } SilcServerConfigSectionLogging;
 
 /* Holds all configured connection classes */
-typedef struct SilcServerConfigSectionConnectionClassStruct {
+/* typedef struct SilcServerConfigSectionClassStruct {
   uint32 class;
   uint32 ping_freq;
   uint32 connect_freq;
   uint32 max_links;
-  struct SilcServerConfigSectionConnectionClassStruct *next;
-  struct SilcServerConfigSectionConnectionClassStruct *prev;
-} SilcServerConfigSectionConnectionClass;
-
-#define SILC_CONFIG_SERVER_AUTH_METH_PASSWD "passwd"
-#define SILC_CONFIG_SERVER_AUTH_METH_PUBKEY "pubkey"
+  struct SilcServerConfigSectionClassStruct *next;
+} SilcServerConfigSectionClass; */
 
 /* Holds all client authentication data from config file */
-typedef struct SilcServerConfigSectionClientConnectionStruct {
+typedef struct SilcServerConfigSectionClientStruct {
   char *host;
   SilcAuthMethod auth_meth;
   void *auth_data;
   uint32 auth_data_len;
   uint16 port;
   uint32 class;
-  struct SilcServerConfigSectionClientConnectionStruct *next;
-  struct SilcServerConfigSectionClientConnectionStruct *prev;
-} SilcServerConfigSectionClientConnection;
+  struct SilcServerConfigSectionClientStruct *next;
+} SilcServerConfigSectionClient;
+
+/* Holds all server's administrators authentication data from config file */
+typedef struct SilcServerConfigSectionAdminStruct {
+  char *host;
+  char *user;
+  char *nick;
+  SilcAuthMethod auth_meth;
+  void *auth_data;
+  uint32 auth_data_len;
+  struct SilcServerConfigSectionAdminStruct *next;
+} SilcServerConfigSectionAdmin;
+
+/* Holds all configured denied connections from config file */
+typedef struct SilcServerConfigSectionDenyStruct {
+  char *host;
+  uint16 port;
+  char *reason;
+  struct SilcServerConfigSectionDenyStruct *next;
+} SilcServerConfigSectionDeny;
 
-/* Hols all server's administrators authentication data from config file */
-typedef struct SilcServerConfigSectionAdminConnectionStruct {
+/* Holds all configured server connections from config file */
+typedef struct SilcServerConfigSectionServerStruct {
   char *host;
-  char *username;
-  char *nickname;
   SilcAuthMethod auth_meth;
   void *auth_data;
   uint32 auth_data_len;
-  struct SilcServerConfigSectionAdminConnectionStruct *next;
-  struct SilcServerConfigSectionAdminConnectionStruct *prev;
-} SilcServerConfigSectionAdminConnection;
+  uint16 port;
+  char *version;
+  uint32 class;
+  bool backup_router;
+  struct SilcServerConfigSectionServerStruct *next;
+} SilcServerConfigSectionServer;
 
-/* Holds all configured server/router connections from config file */
-typedef struct SilcServerConfigSectionServerConnectionStruct {
+/* Holds all configured router connections from config file */
+typedef struct SilcServerConfigSectionRouterStruct {
   char *host;
   SilcAuthMethod auth_meth;
   void *auth_data;
@@ -138,159 +136,65 @@ typedef struct SilcServerConfigSectionServerConnectionStruct {
   char *backup_replace_ip;
   uint16 backup_replace_port;
   bool backup_local;
-  struct SilcServerConfigSectionServerConnectionStruct *next;
-  struct SilcServerConfigSectionServerConnectionStruct *prev;
-} SilcServerConfigSectionServerConnection;
-
-/* Holds all configured denied connections from config file */
-typedef struct SilcServerConfigSectionDenyConnectionStruct {
-  char *host;
-  char *comment;
-  uint16 port;
-  struct SilcServerConfigSectionDenyConnectionStruct *next;
-  struct SilcServerConfigSectionDenyConnectionStruct *prev;
-} SilcServerConfigSectionDenyConnection;
-
-/* Holds motd file */
-typedef struct {
-  char *motd_file;
-} SilcServerConfigSectionMotd;
-
-/* holds pid file */
-typedef struct {
-   char *pid_file;
-} SilcServerConfigSectionPid;
-
-/* 
-   SILC Server Config object. 
-
-   This object holds all the data parsed from the SILC server configuration
-   file. This is mainly used at the initialization of the server.
+  struct SilcServerConfigSectionRouterStruct *next;
+} SilcServerConfigSectionRouter;
 
-*/
+/* define the SilcServerConfig object */
 typedef struct {
-  /* Pointer back to the server */
-  void *server;
-
-  /* Filename of the configuration file */
-  char *filename;
-
-  /* Configuration sections */
-  SilcServerConfigSectionAlg *cipher;
-  SilcServerConfigSectionAlg *pkcs;
-  SilcServerConfigSectionAlg *hash_func;
-  SilcServerConfigSectionAlg *hmac;
-  SilcServerConfigSectionServerKeys *server_keys;
+  void *tmp;
+  char *module_path;
+
+  SilcServerConfigSectionCipher *cipher;
+  SilcServerConfigSectionHash *hash;
+  SilcServerConfigSectionHmac *hmac;
+  SilcServerConfigSectionPkcs *pkcs;
+  SilcServerConfigSectionLogging *logging_info;
+  SilcServerConfigSectionLogging *logging_warnings;
+  SilcServerConfigSectionLogging *logging_errors;
+  SilcServerConfigSectionLogging *logging_fatals;
   SilcServerConfigSectionServerInfo *server_info;
-  SilcServerConfigSectionAdminInfo *admin_info;
-  SilcServerConfigSectionListenPort *listen_port;
-  SilcServerConfigSectionIdentity *identity;
-  SilcServerConfigSectionLogging *logging;
-  SilcServerConfigSectionConnectionClass *conn_class;
-  SilcServerConfigSectionClientConnection *clients;
-  SilcServerConfigSectionServerConnection *servers;
-  SilcServerConfigSectionServerConnection *routers;
-  SilcServerConfigSectionAdminConnection *admins;
-  SilcServerConfigSectionDenyConnection *denied;
-  SilcServerConfigSectionMotd *motd;
-  SilcServerConfigSectionPid *pidfile;
-} SilcServerConfigObject;
-
-typedef SilcServerConfigObject *SilcServerConfig;
+/*SilcServerConfigSectionClass *conn_class; */
+  SilcServerConfigSectionClient *clients;
+  SilcServerConfigSectionAdmin *admins;
+  SilcServerConfigSectionDeny *denied;
+  SilcServerConfigSectionServer *servers;
+  SilcServerConfigSectionRouter *routers;
+} *SilcServerConfig;
 
-/* Configuration section type enumerations. */
-typedef enum {
-  SILC_CONFIG_SERVER_SECTION_TYPE_NONE = 0,
-  SILC_CONFIG_SERVER_SECTION_TYPE_CIPHER,
-  SILC_CONFIG_SERVER_SECTION_TYPE_PKCS,
-  SILC_CONFIG_SERVER_SECTION_TYPE_HASH_FUNCTION,
-  SILC_CONFIG_SERVER_SECTION_TYPE_HMAC,
-  SILC_CONFIG_SERVER_SECTION_TYPE_SERVER_KEYS,
-  SILC_CONFIG_SERVER_SECTION_TYPE_SERVER_INFO,
-  SILC_CONFIG_SERVER_SECTION_TYPE_ADMIN_INFO,
-  SILC_CONFIG_SERVER_SECTION_TYPE_LISTEN_PORT,
-  SILC_CONFIG_SERVER_SECTION_TYPE_IDENTITY,
-  SILC_CONFIG_SERVER_SECTION_TYPE_LOGGING,
-  SILC_CONFIG_SERVER_SECTION_TYPE_CONNECTION_CLASS,
-  SILC_CONFIG_SERVER_SECTION_TYPE_CLIENT_CONNECTION,
-  SILC_CONFIG_SERVER_SECTION_TYPE_SERVER_CONNECTION,
-  SILC_CONFIG_SERVER_SECTION_TYPE_ROUTER_CONNECTION,
-  SILC_CONFIG_SERVER_SECTION_TYPE_ADMIN_CONNECTION,
-  SILC_CONFIG_SERVER_SECTION_TYPE_DENY_CONNECTION,
-  SILC_CONFIG_SERVER_SECTION_TYPE_MOTD,
-  SILC_CONFIG_SERVER_SECTION_TYPE_PID,
-} SilcServerConfigSectionType;
+/* Prototypes */
 
-/* SILC Configuration Section structure. */
-typedef struct {
-  const char *section;
-  SilcServerConfigSectionType type;
-  int maxfields;
-} SilcServerConfigSection;
+/* basic config operations */
+SilcServerConfig silc_server_config_alloc(char *filename);
+void silc_server_config_destroy(SilcServerConfig config);
 
-/* LIst of all possible config sections in SILC server. */
-extern SilcServerConfigSection silc_server_config_sections[];
+/* algorithm registering and reset functions */
+bool silc_server_config_register_ciphers(SilcServer server);
+bool silc_server_config_register_hashfuncs(SilcServer server);
+bool silc_server_config_register_hmacs(SilcServer server);
+bool silc_server_config_register_pkcs(SilcServer server);
+void silc_server_config_setlogfiles(SilcServerConfig config, SilcSchedule sked);
 
-/* Structure used in parsing the configuration lines. The line is read
-   from a file to this structure before parsing it further. */
-typedef struct SilcServerConfigParseStruct {
-  SilcBuffer line;
-  int linenum;
-  SilcServerConfigSection *section;
-  struct SilcServerConfigParseStruct *next;
-  struct SilcServerConfigParseStruct *prev;
-} *SilcServerConfigParse;
+/* run-time config access functions */
+SilcServerConfigSectionClient *
+silc_server_config_find_client(SilcServerConfig config, char *host, int port);
 
-/* Macros */
+SilcServerConfigSectionAdmin *
+silc_server_config_find_admin(SilcServerConfig config,
+                             char *host, char *user, char *nick);
 
-/* Allocates list entries for configuration sections. Used by all
-   config sections as this is common. */
-#define SILC_SERVER_CONFIG_LIST_ALLOC(x)               \
-do {                                                   \
-  if (!(x)) {                                          \
-    (x) = silc_calloc(1, sizeof(*(x)));                        \
-    (x)->next = NULL;                                  \
-    (x)->prev = NULL;                                  \
-  } else {                                             \
-    if (!(x)->next) {                                  \
-      (x)->next = silc_calloc(1, sizeof(*(x)->next));  \
-      (x)->next->next = NULL;                          \
-      (x)->next->prev = (x);                           \
-      (x) = (x)->next;                                 \
-    }                                                  \
-  }                                                    \
-} while(0)
+SilcServerConfigSectionDeny *
+silc_server_config_find_denied(SilcServerConfig config,
+                              char *host, uint16 port);
 
-/* Prototypes */
-SilcServerConfig silc_server_config_alloc(char *filename);
-void silc_server_config_free(SilcServerConfig config);
-int silc_server_config_parse(SilcServerConfig config, SilcBuffer buffer,
-                            SilcServerConfigParse *return_config);
-int silc_server_config_parse_lines(SilcServerConfig config, 
-                                  SilcServerConfigParse parse_config);
-int silc_server_config_check_sections(uint32 checkmask);
-void silc_server_config_setlogfiles(SilcServerConfig config, SilcSchedule sked);
-bool silc_server_config_register_ciphers(SilcServerConfig config);
-bool silc_server_config_register_pkcs(SilcServerConfig config);
-bool silc_server_config_register_hashfuncs(SilcServerConfig config);
-bool silc_server_config_register_hmacs(SilcServerConfig config);
-SilcServerConfigSectionClientConnection *
-silc_server_config_find_client_conn(SilcServerConfig config, 
-                                   char *host, int port);
-SilcServerConfigSectionServerConnection *
-silc_server_config_find_server_conn(SilcServerConfig config, 
+/* Prototypes - OLD */
+SilcServerConfigSectionServer *
+silc_server_config_find_server_conn(SilcServerConfig config,
                                    char *host, int port);
-SilcServerConfigSectionServerConnection *
-silc_server_config_find_router_conn(SilcServerConfig config, 
+SilcServerConfigSectionRouter *
+silc_server_config_find_router_conn(SilcServerConfig config,
                                    char *host, int port);
 bool silc_server_config_is_primary_route(SilcServerConfig config);
-SilcServerConfigSectionServerConnection *
+SilcServerConfigSectionRouter *
 silc_server_config_get_primary_router(SilcServerConfig config);
-SilcServerConfigSectionAdminConnection *
-silc_server_config_find_admin(SilcServerConfig config,
-                             char *host, char *username, char *nickname);
-SilcServerConfigSectionDenyConnection *
-silc_server_config_denied_conn(SilcServerConfig config, char *host,
-                              int port);
 
-#endif
+#endif /* !SERVERCONFIG_H */
index 0eadeba52974a01a48ecd14c13e5a65b47b0223d..cf3315a2cd126100a2611548ee6e1c271d797dda 100644 (file)
@@ -102,15 +102,15 @@ Usage: silcd [options]\n\
 
 /* Dies if a *valid* pid file exists already */
 
-static void silc_checkpid(SilcServer silcd)
+static void silc_server_checkpid(SilcServer silcd)
 {
-  if (silcd->config->pidfile && silcd->config->pidfile->pid_file) {
+  if (silcd->config->server_info->pid_file) {
     int oldpid;
     char *buf;
     uint32 buf_len;
 
     SILC_LOG_DEBUG(("Checking for another silcd running"));
-    buf = silc_file_readfile(silcd->config->pidfile->pid_file, &buf_len);
+    buf = silc_file_readfile(silcd->config->server_info->pid_file, &buf_len);
     if (!buf)
       return;
     oldpid = atoi(buf);
@@ -121,7 +121,7 @@ static void silc_checkpid(SilcServer silcd)
     if (errno != ESRCH) {
       fprintf(stderr, "\nI detected another daemon running with the same pid file.\n");
       fprintf(stderr, "Please change the config file, or erase the %s\n",
-       silcd->config->pidfile->pid_file);
+       silcd->config->server_info->pid_file);
       exit(1);
     }
   }
@@ -239,7 +239,7 @@ int main(int argc, char **argv)
     goto fail;
 
   /* Check for another silcd running */
-  silc_checkpid(silcd);
+  silc_server_checkpid(silcd);
 
   /* Initialize the server */
   ret = silc_server_init(silcd);
@@ -263,11 +263,11 @@ int main(int argc, char **argv)
     silc_server_daemonise(silcd);
 
   /* If set, write pid to file */
-  if (silcd->config->pidfile && silcd->config->pidfile->pid_file) {
-    char buf[10];
-    unlink(silcd->config->pidfile->pid_file);
+  if (silcd->config->server_info->pid_file) {
+    char buf[10], *pidfile = silcd->config->server_info->pid_file;
+    unlink(pidfile);
     snprintf(buf, sizeof(buf) - 1, "%d\n", getpid());
-    silc_file_writefile(silcd->config->pidfile->pid_file, buf, strlen(buf));
+    silc_file_writefile(pidfile, buf, strlen(buf));
   }
 
   /* Drop root. */
index d12a141b9d2574f34e2b0cb3188328a549106c41..afe74b3e9b0820d0ae3598160d94328bc783377d 100644 (file)
 #
 # Example configuration file.  Note that this attempts to present various
-# configuration possibilities and may not actually give any sensible 
+# configuration possibilities and may not actually give any sensible
 # configuration.  For real life example see the examples/ directory.
 #
 
 #
-# Configured ciphers.
+# General configuration options
 #
-# Format: <name>:<module path>:<key length>:<block length>
-#
-# If the cipher is builtin the <module path> maybe omitted.
-#
-[Cipher]
-aes-256-cbc:@MODULESDIR@/aes.sim.so:32:16
-aes-192-cbc:@MODULESDIR@/aes.sim.so:24:16
-aes-128-cbc:@MODULESDIR@/aes.sim.so:16:16
-twofish-256-cbc:@MODULESDIR@/twofish.sim.so:32:16
-twofish-192-cbc:@MODULESDIR@/twofish.sim.so:24:16
-twofish-128-cbc:@MODULESDIR@/twofish.sim.so:16:16
-mars-256-cbc:@MODULESDIR@/mars.sim.so:32:16
-mars-192-cbc:@MODULESDIR@/mars.sim.so:24:16
-mars-128-cbc:@MODULESDIR@/mars.sim.so:16:16
-none:@MODULESDIR@/none.sim.so:0:0
+General {
+       # This is the default path where to search modules
+       # You can comment it out to use builtin modules globally.
+       ModulePath = "@MODULESDIR@";
+};
 
 #
-# Configured hash functions.
-#
-# Format: <name>:<module path>:<block length>:<digest length>
-#
-# If the hash function is builtin the <module path> maybe omitted.
+# Configured ciphers
+#
+# The "Module" option can be either absolute or relative to the "ModulePath"
+# option.
+# If commented out forces using of built-in modules.
+#
+cipher {
+       name = "aes-256-cbc";
+       module = "aes.sim.so";
+       key_length = 32;
+       block_length = 16;
+};
+cipher {
+       name = "aes-192-cbc";
+       module = "aes.sim.so";
+       key_length = 24;
+       block_length = 16;
+};
+cipher {
+       name = "aes-128-cbc";
+       module = "aes.sim.so";
+       key_length = 16;
+       block_length = 16;
+};
+cipher {
+       name = "twofish-256-cbc";
+       module = "twofish.sim.so";
+       key_length = 32;
+       block_length = 16;
+};
+cipher {
+       name = "twofish-192-cbc";
+       module = "twofish.sim.so";
+       key_length = 24;
+       block_length = 16;
+};
+cipher {
+       name = "twofish-128-cbc";
+       module = "twofish.sim.so";
+       key_length = 16;
+       block_length = 16;
+};
+cipher {
+       name = "mars-256-cbc";
+       module = "mars.sim.so";
+       key_length = 32;
+       block_length = 16;
+};
+cipher {
+       name = "mars-192-cbc";
+       module = "mars.sim.so";
+       key_length = 24;
+       block_length = 16;
+};
+cipher {
+       name = "mars-128-cbc";
+       module = "mars.sim.so";
+       key_length = 16;
+       block_length = 16;
+};
+cipher {
+       name = "none";
+       module = "none.sim.so";
+};
+
 #
-[Hash]
-sha1::64:20
-md5::64:16
+# Configured hash functions
+#
+hash {
+       name = "sha1";
+       block_length = 64;
+       digest_length = 20;
+};
+hash {
+       name = "md5";
+       block_length = 64;
+       digest_length = 16;
+};
 
 #
 # Configured HMAC functions. The hash function used in the HMAC must
-# configured to the [hash] section.
-#
-# Format: <name>:<hash name>:<mac length>
-#
-[hmac]
-hmac-sha1-96:sha1:12
-hmac-md5-96:md5:12
-hmac-sha1:sha1:20
-hmac-md5:md5:16
+# be configured in the hash section.
+#
+hmac {
+       name = "hmac-sha1-96";
+       hash = "sha1";
+       mac_length = 12;
+};
+hmac {
+       name = "hmac-md5-96";
+       hash = "md5";
+       mac_length = 12;
+};
+hmac {
+       name = "hmac-sha1";
+       hash = "sha1";
+       mac_length = 20;
+};
+hmac {
+       name = "hmac-md5";
+       hash = "md5";
+       mac_length = 16;
+};
 
 #
-# Configured PKCS.
+# Configured PKCS
 #
-# Format: <name>
-#
-[PKCS]
-rsa
+PKCS { name = "rsa"; };
 
 #
-# Run SILC server as specific user and group. The server must be initially
-# run as root.
-#
-# Format: <user>:<group>
+# Server information
 #
-[Identity]
-nobody:nobody
+ServerInfo {
+       #
+       # Server FQDN and IP address
+       #
+       hostname = "lassi.kuo.fi.ssh.com";
+       ip = "10.2.1.6";
+       port = 706;
 
-#
-# Server's administrative information.
-#
-# Format: <location>:<server type>:<admin's name>:<admin's email address>
-#
-[AdminInfo]
-Kuopio, Finland:Test Server:Pekka Riikonen:priikone@poseidon.pspt.fi
+       #
+       # ServerType field specifies the purpose of this server
+       # This is only a descriptive field.
+       #
+       ServerType = "Test Server";
 
-#
-# Server information.
-#
-# Format: +<server FQDN>:<server IP>:<geographic location>:<port>
-#
-[ServerInfo]
-lassi.kuo.fi.ssh.com:10.2.1.6:Kuopio, Finland:706
+       #
+       # Geographic location
+       #
+       Location = "Kuopio, Finland";
 
-#
-# Server keys
-#
-# Format: +<public key>:<private key>
-#
-[ServerKeys]
-@ETCDIR@/silcd.pub:@ETCDIR@/silcd.prv
+       #
+       # Full admin name
+       #
+       Admin = "Pekka Riikonen";
 
-#
-# Listenning ports.
-#
-# Format: <local IP>:<Listener IP>:<port>
-#
-[ListenPort]
-10.2.1.6:10.2.1.6:706
+       #
+       # Admin's email address
+       #
+       EMail = "priikone@poseidon.pspt.fi";
+
+       #
+       # Run SILC server as specific user and group. The server must be initially
+       # run as root.
+       #
+       User = "nobody";
+       Group = "nobody";
+
+       #
+       # Public and private keys
+       #
+       PublicKey = "@ETCDIR@/silcd.pub";
+       PrivateKey = "@ETCDIR@/silcd.prv";
+
+       #
+       # Motd file
+       #
+       # Specifies the text file displayed on client connection
+       #
+       #MotdFile = "@ETCDIR@/motd.txt";
+
+       #
+       # Pid file
+       #
+       PidFile = "@PIDFILE@";
+};
 
 #
 # Log files.
 #
-# This section is used to set various logging files, their paths
-# and maximum sizes. There are only four defined channels allowed for
-# defining (see list below).
+# This section is used to set various logging files, their paths, maximum
+# sizes and logging options.
+# There are only four defined channels allowed for defining (see below).
 # The log channels have an importance value, and most important channels
-# are printed on the less important ones, thus setting the logging file
-# for "infologfile" will ensure logging for all channels, while setting
-# logging file for "errorlogfile" will ensure logging for channels
-# "error" and "fatal" only.
-# If a message can't find a valid output file it will be discarded, thus,
-# if you unset all files you will completely disable server logging (and
-# this is NOT recommended).
-# If maximum size is given, the logfile will be rotated to a logfile with
-# the ".old" extension added. Older logfiles are flushed.
-# There are also two options, quicklogs and flushdelay. Their values
-# must be enclosed in colons (:), see the format below.
-#
-# Format: quicklogs:<yes/no>:
-#         flushdelay:<seconds>:
-#         infologfile:<path>:<max byte size>
-#         warninglogile:<path>:<max byte size>
-#         errorlogile:<path>:<max byte size>
-#         fatallogile:<path>:<max byte size>
-#
-[Logging]
-quicklogs:no:
-flushdelay:300:
-infologfile:@LOGSDIR@/silcd.log:50000
-warninglogfile:@LOGSDIR@/silcd_warnings.log:50000
-#errorlogfile:@LOGSDIR@/silcd_errors.log:50000
-#fatallogfile:@LOGSDIR@/silcd_fatals.log:
-
-#
-# Connection classes.
-#
-# This section is used to define connection classes. These can be
-# used to optimize the server and the connections.#
+# are redirected on the less important ones, thus setting a valid logging
+# file for "infologfile" will ensure logging for all channels, while setting
+# logging file for "errorlogfile" will ensure logging for channels "error"
+# and "fatal"
+#
+Logging {
+       #
+       # If QuickLogs is true, then the logging files will be updated
+       # real-time. This causes a bit more CPU and HDD activity, but
+       # reduces memory usage. (if unsure say true).
+       #
+       QuickLogs = false;
+
+       #
+       # (Only if QuickLogs is false)
+       # FlushDelay tells log files update delay in case you have chosen
+       # buffering output.
+       #
+       FlushDelay = 180;
+
+       Info {
+               File = "@LOGSDIR@/silcd.log";
+               Size = "50k";
+       };
+       Warnings {
+               File = "@LOGSDIR@/silcd_warnings.log";
+               Size = "50k";
+       };
+       Errors {
+               File = "@LOGSDIR@/silcd_errors.log";
+               Size = "50k";
+       };
+       Fatals {
+               File = "@LOGSDIR@/silcd_fatals.log";
+               Size = "50k";
+       };
+};
+
 #
-# Format: <class number>:<ping freq>:<connect freq>:<max links>
+# Connection classes (UNSUPPORTED)
 #
-[ConnectionClass]
-1:100:100:100
-2:200:300:400
+# This section is used to define connection classes. These can be
+# used to optimize the server and the connections.
+#
+#Class {
+#      Name = "norm";
+#      Ping = 100;
+#      Connect = 100;
+#      Links = 100;
+#};
 
 #
 # Configured client connections.
 #
-# Format: <remote host>:<auth method>:<auth data>:<port>:<class>
+# All fields except Class are optional.  Omitted fields are assumed
+# to be generic (e.g. if the "Host" field is omitted all hosts will match
+# this client class).
+#
+#Client {
+#      Host = "127.0.0.1";
+#      Port = 706;
+#      Class = "local";
+#};
+Client {
+       Port = 706;
+       Class = "norm";
+};
+
 #
-# The <auth data> is either passphrase or file path to the public key
-# file.
+# Configured server administrator connections
 #
-[ClientConnection]
-:::706:1
+# The fields "Host", "User", and "Nick", are optional but you are encouraged
+# in using them to better identify your admins.
+# "AuthMethod" and "AuthData" fields are mandatory.  The "AuthMethod" field
+# can be either the special string "passwd" or "pubkey" to identify the type
+# of data specified by "AuthData".
+#
+Admin {
+       Host = "10.2.1.199";
+       User = "priikone";
+       Nick = "pekka";
+       AuthMethod = "passwd";
+       AuthData = "verysecret";
+};
 
 #
-# Configured server administrator connections
+# Denied connections
 #
-# Format: <host>:<username>:<nickname>:<auth method>:<auth data>
+# These connections are denied to connect to our server.
 #
-# The <auth data> is either passphrase or file path to the public key
-# file.
+# The "Reason" field is mandatory, while the "Host" and "Port" fields can be
+# omitted to match everything.
 #
-[AdminConnection]
-10.2.1.199:priikone:pekka:passwd:veryscret
+#Deny {
+#      Host = "10.2.1.99";
+#      Port = 706;
+#      Reason = "Go away spammer";
+#};
+#Deny {
+#      Host = "10.3.*";
+#      Reason = "You are not welcome.";
+#};
 
 #
 # Configured server connections.
 #
-# If server connections are configured it means that our server is
-# router server.  Normal server must not configure server connections.
-# Thus, if your server is not router do not configure this section.  If
+# If server connections are configured it means that this server is
+# router server.  Normal servers must not configure server connections.
+# Thus, if this server is not router do not configure this section.  If
 # your server is router, this must be configured.
 #
-# Format: <remote host>:<auth method>:<auth data>:<port>:
-#         <version ID>:<class>:<backup connection>
-#
-# The <auth data> is either passphrase or file path to the public key
-# file. If the connection is backup connection then set the <backup 
-# connection> to value 1. For normal connections set it 0. If it is
-# set to value 1 then this server will be backup router.
-#
-[ServerConnection]
-10.2.1.7:passwd:veryscret:706:1:1:0
-10.2.1.17:passwd:veryscret13:706:1:1:1   # backup connection, that host
-                                         # will use this server as backup
-                                         # router.
+# The "AuthData" option is either passphrase or file path to the public key
+# file. If the connection is backup connection then set the "Backup" option
+# to true. For normal connections set it false. If it is
+# set to true then this server will be backup router.
+#
+ServerConnection {
+       Host = "10.2.1.7";
+       AuthMethod = passwd;
+       AuthData = "verysecret";
+       Port = 706;
+       VersionID = 1;
+       Class = "norm";
+       Backup = false;
+};
 
 #
-# Configured router connections.
+# Configured router connections
 #
-# For normal server only one entry maybe configured to this section.  It
-# must be the router this server will be connected to.  For router server,
-# this sections includes all configured router connections.  The first
+# For normal servers only one entry maybe configured to this section.  It
+# must be the router this server will be connected to.  For router servers,
+# this section includes all configured router connections.  The first
 # configured connection is the primary route.
 #
-# Format: <remote host>:<auth method>:<auth data>:<port>:<version ID>:
-#         <class>:<initiator>:<backup replace IP>:<backup replace port>:
-#         <local backup>
+# The "AuthData" option is either passphrase or file path to the public key
+# file. If you are the initiator of the connection then set the "Initiator"
+# option to true.  If you are the responder of the connection (waiting for
+# incoming connection) then set it to false.
 #
-# The <auth data> is either passphrase or file path to the public key
-# file. If you are the initiator of the connection then set the <initiator>
-# to value 1.  If you are the responder of the connection (waiting for 
-# incoming connection) then set it to 0.
-#
-# If the connection is backup router connection then set the <backup
-# replace IP> to the IP address of the router that the backup router will
+# If the connection is backup router connection then set the "BackupHost"
+# option to the IP address of the router that the backup router will
 # replace if it becomes unavailable.  Set also the router's port to the
-# <backup replace port>.  For normal connection leave both empty. If this
-# backup router is in our cell then set the <local backup> to value 1.
-# If the backup router is in other cell then set it to value 0.
-#
-[RouterConnection]
-#10.2.1.100:passwd:veryverysecret:706:1:1:1
-#10.2.100.131:pubkey:/path/to/the/publickey:706:1:1:1
-#10.2.100.100:pubkey:/path/to/the/publickey:706:1:1:0:10.2.1.6:706:1
-
-#
-# Denied connections.
-#
-# These connections are denied to connect our server.
-#
-# Format: <remote host>:<port>:<comment>
-#
-[DenyConnection]
-#10.2.1.99:0:Your connection has been denied
-
-#
-# Message Of The Day
-#
-# specify the text file containing the motd:
-#
-#[motd]
-#@ETCDIR@/motd.txt
-
-#
-# Pid File
-#
-# specify the pidfile where it will be written:
-#
-[pid]
-@PIDFILE@
+# "BackupPort" option.  For normal connection leave both commented. If this
+# backup router is in our cell then set the "LocalBackup" option to true.
+# If the backup router is in other cell then set it to false.
+#
+RouterConnection {
+       Host = "10.2.1.100";
+       AuthMethod = passwd;
+       AuthData = "verysecret";
+       Port = 706;
+       VersionID = 1;
+       Class = "norm";
+       Initiator = true;
+       #BackupHost = "10.2.1.6";
+       #BackupPort = 706;
+       #LocalBackup = true;
+};
index 19ae0b975b8ce0569f2c4dfc2951e7fd5f3108f1..188ffa2b66a46e171b703db2a92162281b537d72 100644 (file)
@@ -2,15 +2,15 @@
 
   silcconfig.c
 
-  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+  Author: Johnny Mnemonic <johnny@themnemonic.org>
 
-  Copyright (C) 1997 - 2000 Pekka Riikonen
+  Copyright (C) 1997 - 2002 Pekka Riikonen
 
   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; either version 2 of the License, or
   (at your option) any later version.
-  
+
   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
 
 #include "silcincludes.h"
 
-/* Opens and reads a configuration file to a buffer. The read data is 
-   returned to the ret_buffer argument. */
+/* limit debug logging verbosity */
+#if 0
+#define SILC_CONFIG_DEBUG(fmt) SILC_LOG_DEBUG(fmt)
+#else
+#define SILC_CONFIG_DEBUG(fmt)
+#endif
+
+/* this is the option struct and currently it is only used internally to
+ * the module and other structs. */
+typedef struct SilcConfigOptionStruct {
+  char *name;                  /* *lowercase* name of the option */
+  SilcConfigType type;         /* important: the type of the returned value */
+  SilcConfigCallback cb;       /* the value handler */
+  const SilcConfigTable *subtable; /* used if type is SILC_CONFIG_ARG_BLOCK */
+  void *context;               /* context passed to the callback function */
+  struct SilcConfigOptionStruct *next;
+} SilcConfigOption;
+
+/* unique for each config file (and included ones) */
+struct SilcConfigFileObject {
+  char *filename; /* the original filename opened */
+  int level;   /* parsing level, how many nested silc_config_main we have */
+  char *base;  /* this is a fixed pointer to the base location */
+  char *p;     /* the Parser poitner */
+  uint32 len;  /* fixed length of the whole file */
+  uint32 line; /* current parsing line, strictly linked to p */
+  bool included; /* wether this file is main or included */
+};
+
+/* We need the entity to base our block-style parsing on */
+struct SilcConfigEntityObject {
+  SilcConfigOption *opts;      /* known options list */
+  SilcConfigFile *file;                /* parsing file object */
+};
+
+/* access error descriptions only with silc_config_strerror() */
+static char *errorstrs[] = {
+  "-OK",                                       /* SILC_CONFIG_OK */
+  "-SILENT",                                   /* SILC_CONFIG_ESILENT */
+  "Invalid syntax",                            /* SILC_CONFIG_EGENERIC */
+  "Internal error! Please report this bug",    /* SILC_CONFIG_EINTERNAL */
+  "Can't open specified file",                 /* SILC_CONFIG_ECANTOPEN */
+  "Expected open-brace '{'",                   /* SILC_CONFIG_EOPENBRACE */
+  "Missing close-brace '}'",                   /* SILC_CONFIG_ECLOSEBRACE */
+  "Invalid data type",                         /* SILC_CONFIG_ETYPE */
+  "Unknown option",                            /* SILC_CONFIG_EBADOPTION */
+  "Invalid text",                              /* SILC_CONFIG_EINVALIDTEXT */
+  "Double option specification",               /* SILC_CONFIG_EDOUBLE */
+  "Expected data but not found",               /* SILC_CONFIG_EEXPECTED */
+  "Expected '='",                              /* SILC_CONFIG_EEXPECTEDEQUAL */
+  "Unexpected data",                           /* SILC_CONFIG_EUNEXPECTED */
+  "Missing needed fields",                     /* SILC_CONFIG_EMISSFIELDS */
+  "Missing ';'",                               /* SILC_CONFIG_EMISSCOLON */
+};
+
+/* return string describing SilcConfig's error code */
+char *silc_config_strerror(int errnum)
+{
+  if ((errnum < 0) || (errnum >= sizeof(errorstrs)/sizeof(*errorstrs)) ||
+    (errorstrs[errnum] == NULL)) {
+    char *defret = "-INVALIDERROR";
+    return defret;
+  }
+  return errorstrs[errnum];
+}
+
+/* Begin of internal SilcConfig's text util functions */
+
+/* Points the first non-space character */
+static void my_trim_spaces(SilcConfigFile *file)
+{
+  register char *r = file->p;
+  while (isspace(*r))
+    if (*r++ == '\n') file->line++;
+  file->p = r;
+}
+/* Skips the current line until newline (lf or cr) */
+static void my_skip_line(SilcConfigFile *file)
+{
+  register char *r = file->p;
+  while (*r && (*r != '\n') && (*r != '\r')) r++;
+  file->p = (*r ? r + 1 : r);
+  file->line++;
+}
+/* Obtains a text token from the current position until first separator.
+ * a separator is any non alphanumeric character nor "_" or "-" */
+static char *my_next_token(SilcConfigFile *file, char *to)
+{
+  register char *o;
+  my_trim_spaces(file);
+  o = file->p;
+  while (isalnum(*o) || (*o == '_') || (*o == '-'))
+    *to++ = *o++;
+  *to = '\0';
+  file->p = o;
+  return to;
+}
+/* Obtains a string from the current position. The only difference from
+ * next_token() is that quoted-strings are also accepted */
+static char *my_get_string(SilcConfigFile *file, char *to)
+{
+  char *o;
+  my_trim_spaces(file);
+  o = file->p;
+  if (*o == '"') {
+    char *quot = strchr(++o, '"');
+    int len = quot - o;
+    if (!quot) { /* XXX FIXME: gotta do something here */
+      printf("Bullshit, missing matching \"");
+      exit(1);
+    }
+    if (len <= 0)
+      *to = '\0';
+    else {
+      strncpy(to, o, len);
+      to[len] = '\0';
+    }
+    /* update stream pointer */
+    file->p = quot + 1;
+    return to;
+  }
+  /* we don't need quote parsing, fall-back to token extractor */
+  my_next_token(file, to);
+  return to;
+};
+/* Skips all comment lines and spaces lines until first useful character */
+static void my_skip_comments(SilcConfigFile *file)
+{
+  while (1) {
+    my_trim_spaces(file);
+    if (*file->p != '#') return;
+    my_skip_line(file);
+  }
+}
+
+/* End of internal text functions
+ * Next section contains SilcConfig internal config utils */
 
-void silc_config_open(char *filename, SilcBuffer *ret_buffer)
+/* find an option in the list by name and returns its pointer */
+static SilcConfigOption *silc_config_find_option(SilcConfigEntity ent,
+       const char *name)
+{
+  SilcConfigOption *tmp;
+  for (tmp = ent->opts; tmp; tmp = tmp->next) {
+    if (!strcasecmp(tmp->name, name))
+      return tmp;
+  }
+  return NULL;
+}
+/* ... */
+static void *silc_config_marshall(SilcConfigType type, const char *val)
+{
+  void *pt;
+  int val_int;
+  bool val_bool;
+  char *val_tmp;
+  uint32 val_size;
+
+  switch (type) {
+    case SILC_CONFIG_ARG_TOGGLE:
+      if (!strcasecmp(val, "yes") || !strcasecmp(val, "true") ||
+               !strcasecmp(val, "on") || !strcasecmp(val, "1")) {
+       val_bool = TRUE;
+      }
+      else if (!strcasecmp(val, "no") || !strcasecmp(val, "false") ||
+               !strcasecmp(val, "off") || !strcasecmp(val, "0")) {
+       val_bool = FALSE;
+      }
+      else
+       return NULL;
+      pt = silc_calloc(1, sizeof(val_bool));
+      *(bool *)pt = (bool) val_bool;
+      return pt;
+    case SILC_CONFIG_ARG_INT:
+      val_int = (int) strtol(val, &val_tmp, 0);
+      if (*val_tmp) /* error converting string */
+       return NULL;
+      pt = silc_calloc(1, sizeof(val_int));
+      *(int *)pt = val_int;
+      return pt;
+    case SILC_CONFIG_ARG_SIZE:
+      val_size = (uint32) strtol(val, &val_tmp, 0);
+      if (val == val_tmp)
+       return NULL; /* really wrong, there must be at least one digit */
+      /* Search for a designator */
+      switch (tolower(val_tmp[0])) {
+       case '\0': /* None */
+         break;
+       case 'k': /* Kilobytes */
+         val_size *= (uint32) 1024;
+         break;
+       case 'm': /* Megabytes */
+         val_size *= (uint32) (1024 * 1024);
+         break;
+       case 'g':
+         val_size *= (uint32) (1024 * 1024 * 1024);
+         break;
+       default:
+         return NULL;
+      }
+      /* the string must die here */
+      if (val_tmp[1])
+       return NULL;
+      pt = silc_calloc(1, sizeof(val_size));
+      *(uint32 *)pt = val_size;
+      return pt;
+    case SILC_CONFIG_ARG_STR: /* the only difference between STR and STRE is */
+      if (!val[0])           /* that STR cannot be empty, while STRE can.  */
+       return NULL;
+    case SILC_CONFIG_ARG_STRE:
+      pt = (void *) strdup(val);
+      return pt;
+    /* following types are not supposed to have a return value */
+    case SILC_CONFIG_ARG_BLOCK:
+    case SILC_CONFIG_ARG_NONE:
+      return NULL;
+    default:
+      return NULL;
+  }
+
+  return NULL;
+}
+
+/* End of internal functions */
+
+
+/* Tries to open the config file and returns a valid SilcConfigFile object
+ * or NULL if failed */
+
+SilcConfigFile *silc_config_open(char *configfile)
 {
   char *buffer;
   uint32 filelen;
+  SilcConfigFile *ret;
 
-  buffer = silc_file_readfile(filename, &filelen);
-  if (buffer == NULL)
-    return;
+  if (!(buffer = silc_file_readfile(configfile, &filelen)))
+    return NULL;
 
-  /* Buffer don't have EOF, but we'll need it. */
-  buffer[filelen] = EOF;
+  ret = (SilcConfigFile *) silc_calloc(1, sizeof(*ret));
+  ret->filename = strdup(configfile);
+  ret->base = ret->p = buffer;
+  ret->len = filelen;
+  ret->line = 1; /* line count, start from first line */
+  return ret;
+}
 
-  *ret_buffer = silc_buffer_alloc(filelen + 1);
-  silc_buffer_pull_tail(*ret_buffer, filelen + 1);
-  silc_buffer_put(*ret_buffer, buffer, filelen + 1);
+/* Frees a file object */
 
-  SILC_LOG_DEBUG(("Config file `%s' opened", filename));
+void silc_config_close(SilcConfigFile *file)
+{
+  if (file) {
+    /* XXX FIXME: this check could probably be removed later */
+    uint32 my_len = (uint32) (strchr(file->base, EOF) - file->base);
+    SILC_CONFIG_DEBUG(("file=0x%x name=\"%s\" level=%d line=%lu", (uint32) file,
+                       file->filename, file->level, file->line));
+    if (my_len != file->len) {
+      fprintf(stderr, "FATAL ERROR: saved len and current len does not match!\n");
+      abort();
+    }
+    silc_free(file->filename);
+    memset(file->base, 'F', file->len);
+    silc_free(file->base);
+    memset(file, 'F', sizeof(*file));
+    silc_free(file);
+  }
 }
 
-/* Returns next token from a buffer to the dest argument. Returns the
-   length of the token. This is used to take tokens from a configuration
-   line. */
+/* initializes a SilcConfigEntity pointer allocation */
+
+SilcConfigEntity silc_config_init(SilcConfigFile *file)
+{
+  SilcConfigEntity ret;
+  if (!file)
+    return NULL;
+  SILC_CONFIG_DEBUG(("Allocating new config entity"));
+  ret = (SilcConfigEntity) silc_calloc(1, sizeof(*ret));
+  ret->file = file;
+  return ret;
+};
+
+/* Returns the original filename of the object file */
 
-int silc_config_get_token(SilcBuffer buffer, char **dest)
+char *silc_config_get_filename(SilcConfigFile *file)
 {
+  if (file)
+    return file->filename;
+  return NULL;
+}
+
+/* Returns the current line that file parsing arrived at */
+
+uint32 silc_config_get_line(SilcConfigFile *file)
+{
+  if (file)
+    return file->line;
+  return 0;
+}
+
+/* Returns a pointer to the beginning of the requested line.  If the line
+ * was not found, NULL is returned */
+
+char *silc_config_read_line(SilcConfigFile *file, uint32 line)
+{
+  register char *p;
   int len;
+  char *ret, *endbuf;
 
-  if (strchr(buffer->data, ':')) {
-    len = strcspn(buffer->data, ":");
-    if (len) {
-      *dest = silc_calloc(len + 1, sizeof(char));
-      memcpy(*dest, buffer->data, len);
-    }
-    silc_buffer_pull(buffer, len + 1);
-    return len;
+  if (!file || (line <= 0))
+    return NULL;
+  for (p = file->base; *p && (*p != EOF); p++) {
+    if (line <= 1)
+      goto found;
+    if (*p == '\n')
+      line--;
   }
+  return NULL;
 
-  return -1;
+ found:
+  if ((endbuf = strchr(p, '\n'))) {
+    len = endbuf - p;
+    ret = silc_calloc(len, sizeof(*ret));
+    strncpy(ret, p, len);
+    ret[len] = '\0';
+  }
+  else {
+    ret = silc_calloc(strlen(p), sizeof(*ret));
+    strcpy(ret, p);
+  }
+  return ret;
 }
 
-/* Returns number of tokens in a buffer. */
+/* Convenience function to read the current parsed line */
 
-int silc_config_check_num_token(SilcBuffer buffer)
+char *silc_config_read_current_line(SilcConfigFile *file)
 {
-  int len, len2, num;
+  return silc_config_read_line(file, file->line);
+}
+
+/* (Private) destroy a SilcConfigEntity */
 
-  if (strchr(buffer->data, ':')) {
-    len = 0;
-    num = 0;
-    while (strchr(buffer->data + len, ':')) {
-      num++;
-      len2 = strcspn(buffer->data + len, ":") + 1;
-      len += len2;
+static void silc_config_destroy(SilcConfigEntity ent)
+{
+  SilcConfigOption *oldopt, *nextopt;
+  SILC_CONFIG_DEBUG(("Freeing config entity [ent=0x%x] [opts=0x%x]",
+                       (uint32) ent, (uint32) ent->opts));
+  for (oldopt = ent->opts; oldopt; oldopt = nextopt) {
+    nextopt = oldopt->next;
+    memset(oldopt->name, 'F', strlen(oldopt->name) + 1);
+    silc_free(oldopt->name);
+    memset(oldopt, 'F', sizeof(*oldopt));
+    silc_free(oldopt);
+  }
+  memset(ent, 'F', sizeof(*ent));
+  silc_free(ent);
+}
+
+/* Registers a new option in the specified entity */
+
+void silc_config_register(SilcConfigEntity ent, const char *name,
+                         SilcConfigType type, SilcConfigCallback cb,
+                         const SilcConfigTable *subtable, void *context)
+{
+  SilcConfigOption *newopt;
+  SILC_CONFIG_DEBUG(("Register new option=\"%s\" type=%u cb=0x%08x context=0x%08x",
+               name, type, (uint32) cb, (uint32) context));
+
+  if (!ent || !name)
+    return;
+  /* if we are registering a block, make sure there is a specified sub-table */
+  if ((type == SILC_CONFIG_ARG_BLOCK) && !subtable)
+    return;
+  /* refuse special tag */
+  if (!strcasecmp(name, "include"))
+    return;
+  if (silc_config_find_option(ent, name)) {
+    fprintf(stderr, "Internal Error: Option double registered\n");
+    abort();
+  }
+
+  /* allocate and append the new option */
+  newopt = (SilcConfigOption *) silc_calloc(1, sizeof(*newopt));
+  newopt->name = strdup(name);
+  newopt->type = type;
+  newopt->cb = cb;
+  newopt->subtable = subtable;
+  newopt->context = context;
+
+  if (!ent->opts)
+    ent->opts = newopt;
+  else {
+    SilcConfigOption *tmp;
+    for (tmp = ent->opts; tmp->next; tmp = tmp->next);
+    tmp->next = newopt;
+  }
+}
+
+/* Register a new option table in the specified config entity */
+
+void silc_config_register_table(SilcConfigEntity ent,
+                               const SilcConfigTable table[], void *context)
+{
+  int i;
+  if (!ent || !table) return;
+  SILC_CONFIG_DEBUG(("Registering table"));
+  /* FIXME: some potability checks needed */
+  for (i = 0; table[i].name; i++) {
+    silc_config_register(ent, table[i].name, table[i].type,
+                        table[i].callback, table[i].subtable, context);
+  }
+}
+
+/* ... */
+
+static int silc_config_main_internal(SilcConfigEntity ent)
+{
+  SilcConfigFile *file = ent->file;
+  char **p = &file->p;
+
+  /* loop throught statements */
+  while (1) {
+    char buf[255];
+    SilcConfigOption *thisopt;
+
+    /* makes it pointing to the next interesting char */
+    my_skip_comments(file);
+    /* got eof? */
+    if (**p == '\0' || **p == EOF) {
+      if (file->level > 1) /* cannot get eof in a sub-level! */
+       return SILC_CONFIG_EEXPECTED;
+      goto finish;
+    }
+    /* check if we completed this (sub) section (it doesn't matter if this
+     * is the main section) */
+    if (**p == '}') {
+      if (file->level < 2) /* can't be! must be at least one sub-block */
+       return SILC_CONFIG_EUNEXPECTED;
+      (*p)++;
+      goto finish;
+    }
+    //SILC_LOG_HEXDUMP(("Preparing lookup at line=%lu", file->line), *p, 16);
+
+    /* obtain the keyword */
+    my_next_token(file, buf);
+    SILC_CONFIG_DEBUG(("Looking up keyword=\"%s\" [line=%lu]", buf, file->line));
+
+    /* handle special directive */
+    if (!strcasecmp(buf, "include")) {
+      int ret;
+      SilcConfigFile *inc_file;
+      SilcConfigEntity inc_ent;
+
+      my_trim_spaces(file); /* prepare next char */
+
+      /* Now trying to include the specified file.  The included file will
+       * be allowed to include sub-files but it will preserve the block-level
+       * of the including block. Note that the included file won't be allowed
+       * to raise the block level of the including block. */
+
+      my_get_string(file, buf); /* get the filename */
+      SILC_LOG_DEBUG(("Including file \"%s\"", buf));
+      /* before getting on, check if this row is REALLY complete */
+      if (*(*p)++ != ';')
+       return SILC_CONFIG_EMISSCOLON;
+
+      /* open the file and start the parsing */
+      inc_file = silc_config_open(buf);
+      if (!inc_file) /* does it point a valid filename? */
+        return SILC_CONFIG_ECANTOPEN;
+      inc_file->included = TRUE;
+
+      /* create a new entity and hack it to use the same options */
+      inc_ent = silc_config_init(inc_file);
+      inc_ent->opts = ent->opts;
+      ret = silc_config_main(inc_ent);
+
+      /* Cleanup.
+       * If the included file returned an error, the application will probably
+       * want to output some kind of error message. Because of this, we can't
+       * destroy THIS file object. The hack works this way: The application
+       * expects to destroy the originally created object file, so we'll swap
+       * the original file with the included file. */
+      if (ret) {
+        SilcConfigFile tmp_file;
+        SILC_CONFIG_DEBUG(("SWAPPING FILE OBJECTS"));
+        memcpy(&tmp_file, inc_file, sizeof(tmp_file));
+        memcpy(inc_file, file, sizeof(tmp_file));
+        silc_config_close(inc_file);
+        memcpy(file, &tmp_file, sizeof(tmp_file));
+        return ret;
+      }
+      /* otherwise if no errors encoured, continue normally */
+      silc_config_close(inc_file);
+      continue; /* this one is handled */
     }
 
-    return num;
+    /* we have a registered option (it can also be a sub-block) */
+    thisopt = silc_config_find_option(ent, buf);
+    if (!thisopt)
+      return SILC_CONFIG_EBADOPTION;
+
+    my_trim_spaces(file); /* prepare next char */
+
+    /* option type is a block? */
+    if (thisopt->type == SILC_CONFIG_ARG_BLOCK) {
+      int ret;
+      SilcConfigEntity sub_ent;
+
+      SILC_CONFIG_DEBUG(("Entering sub-block"));
+      if (*(*p)++ != '{')
+       return SILC_CONFIG_EOPENBRACE;
+      /* build the new entity for this sub-block */
+      sub_ent = silc_config_init(ent->file);
+      /* use the previous specified table to describe this block's options */
+      silc_config_register_table(sub_ent, thisopt->subtable, thisopt->context);
+      /* run this block! */
+      ret = silc_config_main(sub_ent);
+      SILC_CONFIG_DEBUG(("Returned from sub-block [ret=%d]", ret));
+
+      if (ret) /* now check the result */
+       return ret;
+
+      /* now call block clean-up callback (if any) */
+      if (thisopt->cb) {
+       SILC_CONFIG_DEBUG(("Now calling clean-up callback (if any)"));
+       thisopt->cb(thisopt->type, thisopt->name, file->line,
+                   NULL, thisopt->context);
+      }
+      /* Do we want ';' to be mandatory after close brace? */
+      if (*(*p)++ != ';')
+       return SILC_CONFIG_EMISSCOLON;
+    }
+    else if (thisopt->type == SILC_CONFIG_ARG_NONE) {
+      /* before getting on, check if this row is REALLY complete */
+      if (*(*p)++ != ';')
+       return SILC_CONFIG_EMISSCOLON;
+      SILC_CONFIG_DEBUG(("Triggering callback for none"));
+      if (thisopt->cb) {
+       thisopt->cb(thisopt->type, thisopt->name, file->line,
+                   NULL, thisopt->context);
+      }
+    }
+    else {
+      void *pt;
+      int ret;
+
+      if (*(*p)++ != '=')
+       return SILC_CONFIG_EEXPECTEDEQUAL;
+
+      my_get_string(file, buf); /* get the option argument */
+      SILC_CONFIG_DEBUG(("With argument=\"%s\"", buf));
+
+      /* before getting on, check if this row is REALLY complete */
+      if (*(*p)++ != ';')
+       return SILC_CONFIG_EMISSCOLON;
+
+      /* convert the option argument to the right format */
+      pt = silc_config_marshall(thisopt->type, buf);
+      if (!pt)
+       return SILC_CONFIG_EINVALIDTEXT;
+      if (thisopt->cb) {
+       ret = thisopt->cb(thisopt->type, thisopt->name, file->line,
+                         pt, thisopt->context);
+       if (ret) {
+         SILC_CONFIG_DEBUG(("Callback refused the value [ret=%d]", ret));
+         return ret;
+       }
+      }
+      silc_free(pt);
+    }
+    continue;
+
+ finish:
+    break;
   }
 
-  return 0;
+  return SILC_CONFIG_OK;
+}
+
+/* ... */
+
+int silc_config_main(SilcConfigEntity ent)
+{
+  SilcConfigFile *file = ent->file;
+  int ret;
+
+  /* don't silently accept a NULL entity */
+  if (!ent) {
+    ret = SILC_CONFIG_EGENERIC;
+    goto main_cleanup;
+  }
+
+  /* call the real main and store the result */
+  file->level++;
+  SILC_CONFIG_DEBUG(("[Lev=%d] Entering config parsing core", file->level));
+  ret = silc_config_main_internal(ent);
+  SILC_CONFIG_DEBUG(("[Lev=%d] Quitting main [ret=%d]", file->level, ret));
+  if (!file->level) /* when swap happens, we could close a file twice */
+    goto main_end;
+  file->level--;
+
+  /* If this file was included don't destroy the options set because it is
+   * the same of the including block. Although if this entity is in a
+   * sub-block created inside the included file, this options set must be
+   * destroyed. */
+ main_cleanup:
+  if ((file->level != 0) || (file->included != TRUE))
+    silc_config_destroy(ent);
+
+ main_end:
+  return ret;
 }
index 3153f256d72fc862daaf86ab3d2eb960afb828ca..87db1cf84fdaec31326dd283d39c1e159a740284 100644 (file)
@@ -2,15 +2,15 @@
 
   silcconfig.h
 
-  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+  Author: Johnny Mnemonic <johnny@themnemonic.org>
 
-  Copyright (C) 1997 - 2000 Pekka Riikonen
+  Copyright (C) 1997 - 2002 Pekka Riikonen
 
   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; either version 2 of the License, or
   (at your option) any later version.
-  
+
   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
 
 */
 
+/****h* silcutil/SilcConfigAPI
+ *
+ * DESCRIPTION
+ *
+ * The SILC Config util library is based on two main objects, SilcConfigFile
+ * (or File object) and SilcConfigEntity (or Entity).  The File objects are
+ * structs directly corresponding to the real files in the filesystem, while
+ * Entities are a little more abstract.
+ * An Entity is composed by delimited area on a File object (it can take the
+ * whole File object or just part of it), plus a group of known options.
+ *
+ * In order to parse this file, first you need to create a File object with
+ * the silc_config_open() function, and then you need to create the Entity
+ * with the silc_config_init() function.
+ * Now you can use the newly created Entity to register a group of expected
+ * known options and sub-blocks, and then you can call the main parsing loop
+ * with the silc_config_main() function.
+ * When silc_config_main() will return, if some error encoured the object file
+ * will point to the file that caused this error (this can be different from
+ * the originally opened file if it contained `Include' directives).  If no
+ * errors encoured then the File objects will still point to the original
+ * file.
+ * While silc_config_main() will take care of destroying Entities before
+ * returning, you need to take care that the File object you created is freed
+ * with the silc_config_close() function.
+ *
+ * The SILC Config library won't take care about storing the values contained
+ * in the config file.  You must take care about it with the callback
+ * functions.
+ *
+ * The config file syntax is pretty straightforward.  All lines starting
+ * with `#' will be skipped, while sub-blocks are delimited by braces (see
+ * the example below).
+ * Options with argument must have the `=' character between the option
+ * name and the value.  Simple words and numbers does not require quoting.
+ * There is a special built-in directive "Include" which allows you to include
+ * another config file in the point the directive is.  You can also Include
+ * inside a sub-block body, in this case when parsing the included config file
+ * it will be assumed that we are within this block, and the included file
+ * won't be allowed to close his root block.
+ *
+ * Example:
+ *
+ *    cipher {
+ *       name = aes-256-cbc;
+ *       module = "aes.sim.so";
+ *       key_length = 32;       # usually the default is just fine
+ *       block_length = 16;
+ *    };
+ *    Include "/etc/silc/hash_funcs.conf";
+ *
+ ***/
+
 #ifndef SILCCONFIG_H
 #define SILCCONFIG_H
 
+/****d* silcutil/SilcConfigAPI/errno
+ *
+ * NAME
+ *
+ *    enum { ... } - describe a SILC Config error
+ *
+ * DESCRIPTION
+ *
+ *    The virtual integer `errno' is returned by the silc_config_main()
+ *    function and indicates what went wrong.
+ *    You can convert it to the corresponding error string with the function
+ *    silc_config_strerror().
+ *
+ * SOURCE
+ */
+enum {
+  SILC_CONFIG_OK,              /* OK */
+  SILC_CONFIG_ESILENT,         /* Error defined by callback function */
+  SILC_CONFIG_EGENERIC,                /* Invalid syntax */
+  SILC_CONFIG_EINTERNAL,       /* Internal Error (caused by developer) */
+  SILC_CONFIG_ECANTOPEN,       /* Can't open specified file */
+  SILC_CONFIG_EOPENBRACE,      /* Expected open-brace '{' */
+  SILC_CONFIG_ECLOSEBRACE,     /* Missing close-brace '}' */
+  SILC_CONFIG_ETYPE,           /* Invalid data type */
+  SILC_CONFIG_EBADOPTION,      /* Unknown option */
+  SILC_CONFIG_EINVALIDTEXT,    /* Invalid text */
+  SILC_CONFIG_EDOUBLE,         /* Double option specification */
+  SILC_CONFIG_EEXPECTED,       /* Expected data but not found */
+  SILC_CONFIG_EEXPECTEDEQUAL,  /* Expected '=' */
+  SILC_CONFIG_EUNEXPECTED,     /* Unexpected data */
+  SILC_CONFIG_EMISSFIELDS,     /* Missing needed fields */
+  SILC_CONFIG_EMISSCOLON,      /* Missing ';' */
+};
+/***/
+
+/****d* silcutil/SilcConfigAPI/SilcConfigType
+ *
+ * NAME
+ *
+ *    typedef enum { ... } SilcConfigType;
+ *
+ * DESCRIPTION
+ *
+ *    This identifies the parameter type that an option has. This parameter
+ *    is very important because the callback's *val pointer points to a
+ *    memory location containing the previously specified data type.
+ *    For example, if you specified an option with an integer parameter
+ *    callback's *val will be a pointer to an integer.
+ *
+ * SOURCE
+ */
+typedef enum {
+  SILC_CONFIG_ARG_TOGGLE,      /* TOGGLE on,off; yes,no; true, false; */
+  SILC_CONFIG_ARG_INT,         /* callback wants an integer */
+  SILC_CONFIG_ARG_STR,         /* callback expects \0-terminated str */
+  SILC_CONFIG_ARG_STRE,                /* same as above, but can also be empty */
+  SILC_CONFIG_ARG_BLOCK,       /* this is a sub-block */
+  SILC_CONFIG_ARG_SIZE,                /* like int, but accepts suffixes kMG */
+  SILC_CONFIG_ARG_NONE,                /* does not expect any args */
+} SilcConfigType;
+/***/
+
+/****f* silcutil/SilcConfigAPI/SilcConfigCallback
+ *
+ * SYNOPSIS
+ *
+ *    typedef int (*SilcConfigCallback)(SilcConfigType type, const char *name,
+ *                                      uint32 line, void *val, void *context);
+ * DESCRIPTION
+ *
+ *    This is the callback prototype for the options handler.  The pointer
+ *    `val' points to a location of type described by `type'.  `name' points
+ *    to a null-terminated string with the name of the option which triggered
+ *    this callback, that is stated at line `line'.  `context' is the
+ *    user-specified context provided when this option was registered.
+ *
+ ***/
+typedef int (*SilcConfigCallback)(SilcConfigType type, const char *name,
+                                 uint32 line, void *val, void *context);
+
+/****s* silcutil/SilcConfigAPI/SilcConfigTable
+ *
+ * SYNOPSIS
+ *
+ *    typedef struct { ... } SilcConfigTable;
+ *
+ * DESCRIPTION
+ *
+ *    SILC Config table defines an easy and quick way of registering options
+ *    in an entity. The function silc_config_register_table() will take as
+ *    argument a SilcConfigTable array terminated by a NULL struct, it is
+ *    important thus, that the `name' field of the terminating struct is set
+ *    to NULL.
+ *
+ *    char *name
+ *
+ *       The option name lowercase. The matching is always case-insensitive,
+ *       but for convention the option specification must always be lowercase.
+ *
+ *    SilcConfigType type
+ *
+ *       This specifies what kind of parameter this option expects.  The
+ *       special cases SILC_CONFIG_ARG_BLOCK tells SILC Config that this is
+ *       not a normal option but the name of a sub-block of the current
+ *       block (there is no limit to the number of nested blocks allowed).
+ *
+ *    SilcConfigCallback callback
+ *
+ *       Normally this is the value handler of the current option. If this
+ *       field is set to NULL then the value is silently discarded. Useful
+ *       for example to support deprecated options.
+ *
+ *    SilcConfigTable *subtable
+ *
+ *       If the `type' field is set to SILC_CONFIG_ARG_BLOCK, then this field
+ *       must point to a valid sub-table NULL-terminated array. If `type' is
+ *       something else, this valued is unused.
+ *
+ ***/
+typedef struct SilcConfigTableStruct {
+  char *name;
+  SilcConfigType type;
+  SilcConfigCallback callback;
+  const struct SilcConfigTableStruct *subtable;
+} SilcConfigTable;
+
+/****s* silcutil/SilcConfigAPI/SilcConfigFile
+ *
+ * SYNOPSIS
+ *
+ *    typedef struct { ... } SilcConfigFile;
+ *
+ * DESCRIPTION
+ *
+ *    A File object holds the data contained in a previously loaded file by
+ *    the silc_config_open() function.
+ *    This is an internally allocated struct and must be used only with the
+ *    helper functions.
+ *
+ ***/
+typedef struct SilcConfigFileObject SilcConfigFile;
+
+/****s* silcutil/SilcConfigAPI/SilcConfigEntity
+ *
+ * SYNOPSIS
+ *
+ *    typedef struct { ... } SilcConfigEntity;
+ *
+ * DESCRIPTION
+ *
+ *    The SILC Config is based on config entities.  An entity contains the
+ *    SilcConfigFile object we are parsing and the registered options.
+ *
+ ***/
+typedef struct SilcConfigEntityObject *SilcConfigEntity;
+
+/* Macros */
+
+/****d* silcutil/SilcConfigAPI/SILC_CONFIG_CALLBACK
+ *
+ * NAME
+ *
+ *    #define SILC_CONFIG_CALLBACK ...
+ *
+ * DESCRIPTION
+ *
+ *    Generic macro to define SilcConfigCallback functions. This defines a
+ *    static function with name `func' as a config callback function.
+ *
+ * SOURCE
+ */
+#define SILC_CONFIG_CALLBACK(func)                             \
+static int func(SilcConfigType type, const char *name,         \
+               uint32 line, void *val, void *context)
+/***/
+
 /* Prototypes */
-void silc_config_open(char *filename, SilcBuffer *ret_buffer);
-int silc_config_get_token(SilcBuffer buffer, char **dest);
-int silc_config_check_num_token(SilcBuffer);
 
-#endif
+/****f* silcutil/SilcConfigAPI/silc_config_open
+ *
+ * SYNOPSIS
+ *
+ *    SilcConfigFile *silc_config_open(char *configfile);
+ *
+ * DESCRIPTION
+ *
+ *    Tries to open the config file `configfile' and returns a valid File
+ *    object on success, or NULL on failure.
+ *    An File object created this way must be destroyed with the function
+ *    silc_config_close().
+ *
+ ***/
+SilcConfigFile *silc_config_open(char *configfile);
+
+/****f* silcutil/SilcConfigAPI/silc_config_close
+ *
+ * SYNOPSIS
+ *
+ *    void silc_config_close(SilcConfigFile *file);
+ *
+ * DESCRIPTION
+ *
+ *    Closes and frees the File object `file', which must have been returned
+ *    by a previous call to silc_config_open().  Otherwise, or if
+ *    this function has already been called before for the same File object,
+ *    undefined behaviour occurs.
+ *    If `file' is NULL, no operation is performed.
+ *
+ ***/
+void silc_config_close(SilcConfigFile *file);
+
+/****f* silcutil/SilcConfigAPI/silc_config_init
+ *
+ * SYNOPSIS
+ *
+ *    SilcConfigEntity silc_config_init(SilcConfigFile *file);
+ *
+ * DESCRIPTION
+ *
+ *    Creates an Entity pointing to the valid File object `file', which must
+ *    be returned by a previous call to silc_config_open(), otherwise NULL
+ *    is returned.
+ *    Entities will be automatically destroyed after the call to the
+ *    silc_config_main() function, because of this no uninit functions are
+ *    provided.
+ *
+ ***/
+SilcConfigEntity silc_config_init(SilcConfigFile *file);
+
+/****f* silcutil/SilcConfigAPI/silc_config_strerror
+ *
+ * SYNOPSIS
+ *
+ *    char *silc_config_strerror(int errnum);
+ *
+ * DESCRIPTION
+ *
+ *    The silc_config_strerror() function returns a string describing the
+ *    error code passed in the argument `errnum'.
+ *
+ ***/
+char *silc_config_strerror(int errnum);
+
+/****f* silcutil/SilcConfigAPI/silc_config_get_filename
+ *
+ * SYNOPSIS
+ *
+ *    char *silc_config_get_filename(SilcConfigFile *file);
+ *
+ * DESCRIPTION
+ *
+ *    Returns the original filename of the object file.
+ *    The returned pointer points to internally allocated storage and must
+ *    not be freed, modified or stored.
+ *
+ ***/
+char *silc_config_get_filename(SilcConfigFile *file);
+
+/****f* silcutil/SilcConfigAPI/silc_config_get_line
+ *
+ * SYNOPSIS
+ *
+ *    uint32 silc_config_get_line(SilcConfigFile *file);
+ *
+ * DESCRIPTION
+ *
+ *    Returns the current line that file parsing arrived at.
+ *
+ ***/
+uint32 silc_config_get_line(SilcConfigFile *file);
+
+/****f* silcutil/SilcConfigAPI/silc_config_read_line
+ *
+ * SYNOPSIS
+ *
+ *    char *silc_config_read_line(SilcConfigFile *file, uint32 line);
+ *
+ * DESCRIPTION
+ *
+ *    Returns a dynamically allocated null-terminated buffer containing the
+ *    line `line' of `file'.
+ *    The returned pointer must be freed when it's not needed any longer.
+ *
+ * SEE ALSO
+ *    silc_config_read_current_line
+ *
+ ***/
+char *silc_config_read_line(SilcConfigFile *file, uint32 line);
+
+/****f* silcutil/SilcConfigAPI/silc_config_read_current_line
+ *
+ * SYNOPSIS
+ *
+ *    char *silc_config_read_current_line(SilcConfigFile *file);
+ *
+ * DESCRIPTION
+ *
+ *    Returns a dynamically allocated buffer containing the line that the
+ *    parser stopped at.  This is a convenience function for
+ *    silc_config_read_line.
+ *    The returned pointer must be freed when it's not needed any longer.
+ *
+ ***/
+char *silc_config_read_current_line(SilcConfigFile *file);
+
+/****f* silcutil/SilcConfigAPI/silc_config_register
+ *
+ * SYNOPSIS
+ *
+ *    void silc_config_register(SilcConfigEntity ent, const char *name,
+ *                              SilcConfigType type, SilcConfigCallback cb,
+ *                              const SilcConfigTable *subtable,
+ *                              void *context);
+ *
+ * DESCRIPTION
+ *
+ *    Register option `name' in the entity `ent'. If `cb' is not NULL, it
+ *    will be called with the *val pointer pointing to an internally
+ *    allocated storage of type described by `type'.
+ *    If `type' is SILC_CONFIG_ARG_BLOCK, then `subtable' must be a valid
+ *    pointer to a SilcConfigTable array specified the options in the
+ *    sub-block.
+ *
+ * SEE ALSO
+ *    silc_config_register_table
+ *
+ ***/
+void silc_config_register(SilcConfigEntity ent, const char *name,
+                         SilcConfigType type, SilcConfigCallback cb,
+                         const SilcConfigTable *subtable, void *context);
+
+/****f* silcutil/SilcConfigAPI/silc_config_register_table
+ *
+ * SYNOPSIS
+ *
+ *    void silc_config_register_table(SilcConfigEntity ent,
+ *                                    const SilcConfigTable table[],
+ *                                    void *context);
+ *
+ * DESCRIPTION
+ *
+ *    Register the tableset of options `table' automatically in the entity
+ *    `ent'.  If defined in the table, the callback functions will be called
+ *    all with the same context `context'.
+ *    The `table' array must be terminated with an entry with the name field
+ *    set to NULL.
+ *
+ * SEE ALSO
+ *    SilcConfigTable
+ *
+ ***/
+void silc_config_register_table(SilcConfigEntity ent,
+                               const SilcConfigTable table[], void *context);
+
+/****f* silcutil/SilcConfigAPI/silc_config_main
+ *
+ * SYNOPSIS
+ *
+ *    int silc_config_main(SilcConfigEntity ent);
+ *
+ * DESCRIPTION
+ *
+ *    Enter the main parsing loop. When this function returns the parsing
+ *    is finished in the current block (and sub-blocks).
+ *    When this function exits, the entity is already destroyed, because
+ *    of this you should set it to NULL right after the function call.
+ *
+ ***/
+int silc_config_main(SilcConfigEntity ent);
+
+#endif /* !SILCCONFIG_H */
index 76f8f67c7a8c5a8520cafa1563d1d9a5a8bd1a01..46db324914fa995737d8c07e6ad52b7fe9eb459c 100644 (file)
@@ -41,7 +41,7 @@
  *    This is the main logging channel id. There are currently four known
  *    logging channels (plus the debugging output channel), and they are
  *    ordered by importance.
- *    See the source code for SILC coding conventions about how choosing
+ *    See the source code for SILC coding conventions about how to choose
  *    the right output channel.
  *
  * SOURCE
@@ -59,7 +59,7 @@ typedef enum {
   /* Fatal messages (usually situations that will lead to a program crash */
   SILC_LOG_FATAL,
 
-  /* Total logging channels */
+  /* Total number logging channels */
   SILC_LOG_MAX
 } SilcLogType;
 /***/
@@ -122,8 +122,8 @@ typedef bool (*SilcLogDebugCb)(char *file, char *function, int line,
  * DESCRIPTION
  *
  *    The hexdump logging callback function.  The default behaviour is to
- *    print a formatted hexdump to stderr, and is commonly what you would it
- *    like to be.  `file', `function', and `line' are the corresponding
+ *    print a formatted hexdump to stderr, and is commonly what you would
+ *    like it to be.  `file', `function', and `line' are the corresponding
  *    offsets in the source files.  `data' is the begin of the buffer that
  *    should be hexdumped, which is `data_len' bytes long.
  *    The `message' parameter points to a null-terminated buffer containing
@@ -316,14 +316,12 @@ extern DLLAPI bool silc_debug_hexdump;
  * DESCRIPTION
  *
  *    This is a special wrapper to the debugging output (usually stderr).
- *    The standard behaviour is the same as SILC_LOG_INFO, but this macro
- *    also depends on the global debugging macro SILC_DEBUG.
- *    Undefining the global SILC_DEBUG define causes these functions to be
- *    defined to an empty value, thus removing all logging calls from the
- *    compiled program.
- *
- * SEE ALSO
- *    SILC_LOG_INFO
+ *    The standard behaviour is the same as SILC_LOG_INFO, with the difference
+ *    that this macro also depends on the global define SILC_DEBUG.
+ *    Undefining SILC_DEBUG causes these functions to be defined to an empty
+ *    value, thus removing all debug logging calls from the compiled
+ *    application.
+ *    This macro is also affected by the global variable silc_debug.
  *
  * SOURCE
  */
@@ -349,13 +347,13 @@ extern DLLAPI bool silc_debug_hexdump;
  *    behaves slightly differently from other logging wrappers.
  *    The first parameter, is composed by a group of parameters delimited by
  *    parenthesis.
- *    The second parameter is a (char *) pointer to the beginning of the
- *    memory section that should be hexdumped, and the third parameter is
- *    the length of this memory section.
- *    This macro is also affected by the global variable silc_debug_hexdump.
+ *    The second parameter is a `char *' pointer pointing to the beginning
+ *    of the memory section that should be hexdumped, and the third parameter
+ *    is the length of this memory section.
  *    Undefining the global SILC_DEBUG define causes these functions to be
- *    defined to an empty value, thus removing all logging calls from the
- *    compiled program.
+ *    defined to an empty value, thus removing all debug logging calls from
+ *    the compiled application.
+ *    This macro is also affected by the global variable silc_debug_hexdump.
  *
  * EXAMPLE
  *
@@ -414,7 +412,7 @@ void silc_log_output(SilcLogType type, char *string);
  *    is returned, even if the file has been previously set with
  *    silc_log_set_file().
  *    The returned pointer points to internally allocated storage and must
- *    must not be freed, modified or stored.
+ *    not be freed, modified or stored.
  *
  ***/
 char *silc_log_get_file(SilcLogType type);
@@ -461,7 +459,7 @@ bool silc_log_set_file(SilcLogType type, char *filename, uint32 maxsize,
  *    SilcLogCb.
  *
  * SEE ALSO
- *    SilcLogCb, silc_log_reset_callbacks
+ *    silc_log_reset_callbacks
  *
  ***/
 void silc_log_set_callback(SilcLogType type, SilcLogCb cb, void *context);