/*
* ngIRCd -- The Next Generation IRC Daemon
- * Copyright (c)2001-2011 Alexander Barton (alex@barton.de) and Contributors.
+ * Copyright (c)2001-2013 Alexander Barton (alex@barton.de) and Contributors.
*
* 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
#include "imp.h"
#include <assert.h>
+#include <ctype.h>
#include <errno.h>
#ifdef PROTOTYPES
# include <stdarg.h>
#include <sys/types.h>
#include <unistd.h>
-#ifdef HAVE_CTYPE_H
-# include <ctype.h>
-#endif
#include "array.h"
#include "ngircd.h"
static CONF_SERVER New_Server;
static int New_Server_Idx;
-static size_t Conf_Oper_Count;
-static size_t Conf_Channel_Count;
static char Conf_MotdFile[FNAME_LEN];
+static char Conf_HelpFile[FNAME_LEN];
static void Set_Defaults PARAMS(( bool InitServers ));
-static bool Read_Config PARAMS(( bool ngircd_starting ));
+static bool Read_Config PARAMS(( bool TestOnly, bool IsStarting ));
static bool Validate_Config PARAMS(( bool TestOnly, bool Rehash ));
static void Handle_GLOBAL PARAMS(( int Line, char *Var, char *Arg ));
free(Conf_SSLOptions.DHFile);
Conf_SSLOptions.DHFile = NULL;
array_free_wipe(&Conf_SSLOptions.KeyFilePassword);
+
+ array_free(&Conf_SSLOptions.ListenPorts);
+}
+
+/**
+ * Check if the current configuration uses/requires SSL.
+ *
+ * @returns true if SSL is used and should be initialized.
+ */
+GLOBAL bool
+Conf_SSLInUse(void)
+{
+ int i;
+
+ /* SSL listen ports configured? */
+ if (array_bytes(&Conf_SSLOptions.ListenPorts))
+ return true;
+
+ for (i = 0; i < MAX_SERVERS; i++) {
+ if (Conf_Server[i].port > 0
+ && Conf_Server[i].SSLConnect)
+ return true;
+ }
+ return false;
}
/**
GLOBAL void
Conf_Init( void )
{
- Read_Config( true );
+ Read_Config(false, true);
Validate_Config(false, false);
}
GLOBAL bool
Conf_Rehash( void )
{
- if (!Read_Config(false))
+ if (!Read_Config(false, false))
return false;
Validate_Config(false, true);
opers_puts(void)
{
struct Conf_Oper *op;
- size_t len;
+ size_t count, i;
- len = array_length(&Conf_Opers, sizeof(*op));
+ count = array_length(&Conf_Opers, sizeof(*op));
op = array_start(&Conf_Opers);
- while (len--) {
- assert(op->name[0]);
+ for (i = 0; i < count; i++, op++) {
+ if (!op->name[0])
+ continue;
puts("[OPERATOR]");
printf(" Name = %s\n", op->name);
printf(" Password = %s\n", op->pwd);
printf(" Mask = %s\n\n", op->mask ? op->mask : "");
- op++;
}
}
Use_Log = false;
- if (! Read_Config(true))
+ if (!Read_Config(true, true))
return 1;
config_valid = Validate_Config(true, false);
printf(" AdminInfo1 = %s\n", Conf_ServerAdmin1);
printf(" AdminInfo2 = %s\n", Conf_ServerAdmin2);
printf(" AdminEMail = %s\n", Conf_ServerAdminMail);
+ printf(" HelpFile = %s\n", Conf_HelpFile);
printf(" Info = %s\n", Conf_ServerInfo);
printf(" Listen = %s\n", Conf_ListenAddress);
if (Using_MotdFile) {
puts("[LIMITS]");
printf(" ConnectRetry = %d\n", Conf_ConnectRetry);
- printf(" MaxConnections = %ld\n", Conf_MaxConnections);
+ printf(" IdleTimeout = %d\n", Conf_IdleTimeout);
+ printf(" MaxConnections = %d\n", Conf_MaxConnections);
printf(" MaxConnectionsIP = %d\n", Conf_MaxConnectionsIP);
printf(" MaxJoins = %d\n", Conf_MaxJoins > 0 ? Conf_MaxJoins : -1);
printf(" MaxNickLength = %u\n", Conf_MaxNickLength - 1);
+ printf(" MaxListSize = %d\n", Conf_MaxListSize);
printf(" PingTimeout = %d\n", Conf_PingTimeout);
printf(" PongTimeout = %d\n", Conf_PongTimeout);
puts("");
printf(" AllowRemoteOper = %s\n", yesno_to_str(Conf_AllowRemoteOper));
printf(" ChrootDir = %s\n", Conf_Chroot);
printf(" CloakHost = %s\n", Conf_CloakHost);
+ printf(" CloakHostModeX = %s\n", Conf_CloakHostModeX);
+ printf(" CloakHostSalt = %s\n", Conf_CloakHostSalt);
printf(" CloakUserToNick = %s\n", yesno_to_str(Conf_CloakUserToNick));
#ifdef WANT_IPV6
printf(" ConnectIPv4 = %s\n", yesno_to_str(Conf_ConnectIPv6));
#ifdef IDENT
printf(" Ident = %s\n", yesno_to_str(Conf_Ident));
#endif
+ printf(" MorePrivacy = %s\n", yesno_to_str(Conf_MorePrivacy));
printf(" NoticeAuth = %s\n", yesno_to_str(Conf_NoticeAuth));
printf(" OperCanUseMode = %s\n", yesno_to_str(Conf_OperCanMode));
+ printf(" OperChanPAutoOp = %s\n", yesno_to_str(Conf_OperChanPAutoOp));
printf(" OperServerMode = %s\n", yesno_to_str(Conf_OperServerMode));
#ifdef PAM
printf(" PAM = %s\n", yesno_to_str(Conf_PAM));
+ printf(" PAMIsOptional = %s\n", yesno_to_str(Conf_PAMIsOptional));
#endif
printf(" PredefChannelsOnly = %s\n", yesno_to_str(Conf_PredefChannelsOnly));
#ifndef STRICT_RFC
* require the next attempt to be delayed. */
Conf_Server[i].lasttry =
t - Conf_ConnectRetry + RECONNECT_DELAY;
- } else
- Conf_Server[i].lasttry = t;
+ } else {
+ /* "Short" connection, enforce "ConnectRetry"
+ * but randomize it a little bit: 15 seconds. */
+ Conf_Server[i].lasttry =
+ t + rand() / (RAND_MAX / 15);
+ }
}
}
}
/**
* Set connection information for specified configured server.
*/
-GLOBAL void
+GLOBAL bool
Conf_SetServer( int ConfServer, CONN_ID Idx )
{
assert( ConfServer > NONE );
assert( Idx > NONE );
+ if (Conf_Server[ConfServer].conn_id > NONE &&
+ Conf_Server[ConfServer].conn_id != Idx) {
+ Log(LOG_ERR,
+ "Connection %d: Server configuration of \"%s\" already in use by connection %d!",
+ Idx, Conf_Server[ConfServer].name,
+ Conf_Server[ConfServer].conn_id);
+ Conn_Close(Idx, NULL, "Server configuration already in use", true);
+ return false;
+ }
Conf_Server[ConfServer].conn_id = Idx;
+ return true;
}
/**
}
/**
- * Check if the given nick name is an service.
+ * Check if the given nickname is reserved for services on a particular server.
+ *
+ * @param ConfServer The server index to check.
+ * @param Nick The nickname to check.
+ * @returns true if the given nickname belongs to an "IRC service".
+ */
+GLOBAL bool
+Conf_NickIsService(int ConfServer, const char *Nick)
+{
+ assert (ConfServer >= 0);
+ assert (ConfServer < MAX_SERVERS);
+
+ return MatchCaseInsensitiveList(Conf_Server[ConfServer].svs_mask,
+ Nick, ",");
+}
+
+/**
+ * Check if the given nickname is blocked for "normal client" use.
*
- * @returns true if the given nick name belongs to an "IRC service".
+ * @param ConfServer The server index or NONE to check all configured servers.
+ * @param Nick The nickname to check.
+ * @returns true if the given nickname belongs to an "IRC service".
*/
GLOBAL bool
-Conf_IsService(int ConfServer, const char *Nick)
+Conf_NickIsBlocked(const char *Nick)
{
- return MatchCaseInsensitive(Conf_Server[ConfServer].svs_mask, Nick);
+ int i;
+
+ for(i = 0; i < MAX_SERVERS; i++) {
+ if (!Conf_Server[i].name[0])
+ continue;
+ if (Conf_NickIsService(i, Nick))
+ return true;
+ }
+ return false;
}
/**
Set_Defaults(bool InitServers)
{
int i;
+ char random[RANDOM_SALT_LEN + 1];
/* Global */
strcpy(Conf_ServerName, "");
PACKAGE_NAME, PACKAGE_VERSION);
free(Conf_ListenAddress);
Conf_ListenAddress = NULL;
+ array_free(&Conf_ListenPorts);
array_free(&Conf_Motd);
+ array_free(&Conf_Helptext);
strlcpy(Conf_MotdFile, SYSCONFDIR, sizeof(Conf_MotdFile));
strlcat(Conf_MotdFile, MOTD_FILE, sizeof(Conf_MotdFile));
+ strlcpy(Conf_HelpFile, DOCDIR, sizeof(Conf_HelpFile));
+ strlcat(Conf_HelpFile, HELP_FILE, sizeof(Conf_HelpFile));
strcpy(Conf_ServerPwd, "");
strlcpy(Conf_PidFile, PID_FILE, sizeof(Conf_PidFile));
Conf_UID = Conf_GID = 0;
/* Limits */
Conf_ConnectRetry = 60;
+ Conf_IdleTimeout = 0;
Conf_MaxConnections = 0;
Conf_MaxConnectionsIP = 5;
Conf_MaxJoins = 10;
Conf_MaxNickLength = CLIENT_NICK_LEN_DEFAULT;
+ Conf_MaxListSize = 100;
Conf_PingTimeout = 120;
Conf_PongTimeout = 20;
#endif
strlcpy(Conf_Chroot, CHROOT_DIR, sizeof(Conf_Chroot));
strcpy(Conf_CloakHost, "");
+ strcpy(Conf_CloakHostModeX, "");
+ strlcpy(Conf_CloakHostSalt, ngt_RandomStr(random, RANDOM_SALT_LEN),
+ sizeof(Conf_CloakHostSalt));
Conf_CloakUserToNick = false;
Conf_ConnectIPv4 = true;
#ifdef WANT_IPV6
#else
Conf_Ident = false;
#endif
+ Conf_MorePrivacy = false;
Conf_NoticeAuth = false;
Conf_OperCanMode = false;
+ Conf_OperChanPAutoOp = true;
Conf_OperServerMode = false;
#ifdef PAM
Conf_PAM = true;
#else
Conf_PAM = false;
#endif
+ Conf_PAMIsOptional = false;
Conf_PredefChannelsOnly = false;
#ifdef SYSLOG
Conf_ScrubCTCP = false;
#endif
#endif
- /* Initialize IRC operators and channels */
- Conf_Oper_Count = 0;
- Conf_Channel_Count = 0;
-
/* Initialize server configuration structures */
if (InitServers) {
for (i = 0; i < MAX_SERVERS;
}
/**
- * Read MOTD ("message of the day") file.
+ * Read contents of a text file into an array.
+ *
+ * This function is used to read the MOTD and help text file, for exampe.
*
* @param filename Name of the file to read.
+ * @return true, when the file has been read in.
*/
-static void
-Read_Motd(const char *filename)
+static bool
+Read_TextFile(const char *Filename, const char *Name, array *Destination)
{
char line[127];
FILE *fp;
+ int line_no = 1;
- if (*filename == '\0')
- return;
+ if (*Filename == '\0')
+ return false;
- fp = fopen(filename, "r");
+ fp = fopen(Filename, "r");
if (!fp) {
- Config_Error(LOG_WARNING, "Can't read MOTD file \"%s\": %s",
- filename, strerror(errno));
- return;
+ Config_Error(LOG_ERR, "Can't read %s file \"%s\": %s",
+ Name, Filename, strerror(errno));
+ return false;
}
- array_free(&Conf_Motd);
- Using_MotdFile = true;
-
+ array_free(Destination);
while (fgets(line, (int)sizeof line, fp)) {
- ngt_TrimLastChr( line, '\n');
+ ngt_TrimLastChr(line, '\n');
/* add text including \0 */
- if (!array_catb(&Conf_Motd, line, strlen(line) + 1)) {
- Log(LOG_WARNING, "Cannot add MOTD text: %s", strerror(errno));
+ if (!array_catb(Destination, line, strlen(line) + 1)) {
+ Log(LOG_ERR, "Cannot read/add \"%s\", line %d: %s",
+ Filename, line_no, strerror(errno));
break;
}
+ line_no++;
}
fclose(fp);
+ return true;
}
/**
* successfully; false otherwise.
*/
static bool
-Read_Config( bool ngircd_starting )
+Read_Config(bool TestOnly, bool IsStarting)
{
char section[LINE_LEN], str[LINE_LEN], *var, *arg, *ptr;
const UINT16 defaultport = 6667;
int line, i, n;
+ size_t count;
FILE *fd;
/* Open configuration file */
/* No configuration file found! */
Config_Error( LOG_ALERT, "Can't read configuration \"%s\": %s",
NGIRCd_ConfFile, strerror( errno ));
- if (!ngircd_starting)
+ if (!IsStarting)
return false;
Config_Error( LOG_ALERT, "%s exiting due to fatal errors!", PACKAGE_NAME );
exit( 1 );
}
opers_free();
- Set_Defaults( ngircd_starting );
+ Set_Defaults(IsStarting);
- Config_Error( LOG_INFO, "Reading configuration from \"%s\" ...", NGIRCd_ConfFile );
+ if (TestOnly)
+ Config_Error(LOG_INFO,
+ "Reading configuration from \"%s\" ...",
+ NGIRCd_ConfFile );
/* Clean up server configuration structure: mark all already
* configured servers as "once" so that they are deleted
/* Is this the beginning of a new section? */
if(( str[0] == '[' ) && ( str[strlen( str ) - 1] == ']' )) {
strlcpy( section, str, sizeof( section ));
- if (strcasecmp(section, "[GLOBAL]") == 0 ||
- strcasecmp(section, "[LIMITS]") == 0 ||
- strcasecmp(section, "[OPTIONS]") == 0 ||
- strcasecmp(section, "[SSL]") == 0)
+ if (strcasecmp(section, "[GLOBAL]") == 0
+ || strcasecmp(section, "[LIMITS]") == 0
+ || strcasecmp(section, "[OPTIONS]") == 0
+#ifdef SSL_SUPPORT
+ || strcasecmp(section, "[SSL]") == 0
+#endif
+ )
continue;
if( strcasecmp( section, "[SERVER]" ) == 0 ) {
else New_Server_Idx = i;
continue;
}
+
if (strcasecmp(section, "[CHANNEL]") == 0) {
- Conf_Channel_Count++;
+ count = array_length(&Conf_Channels,
+ sizeof(struct Conf_Channel));
+ if (!array_alloc(&Conf_Channels,
+ sizeof(struct Conf_Channel),
+ count)) {
+ Config_Error(LOG_ERR,
+ "Could not allocate memory for new operator (line %d)",
+ line);
+ }
continue;
}
+
if (strcasecmp(section, "[OPERATOR]") == 0) {
- Conf_Oper_Count++;
+ count = array_length(&Conf_Opers,
+ sizeof(struct Conf_Oper));
+ if (!array_alloc(&Conf_Opers,
+ sizeof(struct Conf_Oper),
+ count)) {
+ Config_Error(LOG_ERR,
+ "Could not allocate memory for new channel (line &d)",
+ line);
+ }
continue;
}
}
/* No MOTD phrase configured? (re)try motd file. */
- if (array_bytes(&Conf_Motd) == 0)
- Read_Motd(Conf_MotdFile);
+ if (array_bytes(&Conf_Motd) == 0) {
+ if (Read_TextFile(Conf_MotdFile, "MOTD", &Conf_Motd))
+ Using_MotdFile = true;
+ }
+
+ /* Try to read ngIRCd help text file. */
+ (void)Read_TextFile(Conf_HelpFile, "help text", &Conf_Helptext);
+ if (!array_bytes(&Conf_Helptext))
+ Config_Error(LOG_WARNING,
+ "No help text available, HELP command will be of limited use.");
#ifdef SSL_SUPPORT
/* Make sure that all SSL-related files are readable */
}
/**
- * Check whether an string argument is true or false.
+ * Check whether a string argument is "true" or "false".
*
* @param Arg Input string.
- * @returns true if string has been parsed as "yes"/"true"/"on".
+ * @returns true if the input string has been parsed as "yes", "true"
+ * (case insensitive) or a non-zero integer value.
*/
static bool
-Check_ArgIsTrue( const char *Arg )
+Check_ArgIsTrue(const char *Arg)
{
- if( strcasecmp( Arg, "yes" ) == 0 ) return true;
- if( strcasecmp( Arg, "true" ) == 0 ) return true;
- if( atoi( Arg ) != 0 ) return true;
+ if (strcasecmp(Arg, "yes") == 0)
+ return true;
+ if (strcasecmp(Arg, "true") == 0)
+ return true;
+ if (atoi(Arg) != 0)
+ return true;
return false;
}
*
* @param Line Line number in configuration file.
* @raram Arg Input string.
- * @returns New configured maximum nick name length.
+ * @returns New configured maximum nickname length.
*/
static unsigned int
Handle_MaxNickLength(int Line, const char *Arg)
|| strcasecmp(Var, "ConnectIPv4") == 0
|| strcasecmp(Var, "ConnectIPv6") == 0
|| strcasecmp(Var, "OperCanUseMode") == 0
+ || strcasecmp(Var, "OperChanPAutoOp") == 0
|| strcasecmp(Var, "OperServerMode") == 0
|| strcasecmp(Var, "PredefChannelsOnly") == 0
|| strcasecmp(Var, "SyslogFacility") == 0
return "[Options]";
}
if (strcasecmp(Var, "ConnectRetry") == 0
+ || strcasecmp(Var, "IdleTimeout") == 0
|| strcasecmp(Var, "MaxConnections") == 0
|| strcasecmp(Var, "MaxConnectionsIP") == 0
|| strcasecmp(Var, "MaxJoins") == 0
Config_Error_TooLong(Line, Var);
return;
}
+ if (strcasecmp(Var, "HelpFile") == 0) {
+ len = strlcpy(Conf_HelpFile, Arg, sizeof(Conf_HelpFile));
+ if (len >= sizeof(Conf_HelpFile))
+ Config_Error_TooLong(Line, Var);
+ return;
+ }
if (strcasecmp(Var, "Listen") == 0) {
if (Conf_ListenAddress) {
Config_Error(LOG_ERR,
else {
Conf_GID = (unsigned int)atoi(Arg);
if (!Conf_GID && strcmp(Arg, "0"))
- Config_Error_NaN(Line, Var);
+ Config_Error(LOG_WARNING,
+ "%s, line %d: Value of \"%s\" is not a valid group name or ID!",
+ NGIRCd_ConfFile, Line, Var);
}
return;
}
else {
Conf_UID = (unsigned int)atoi(Arg);
if (!Conf_UID && strcmp(Arg, "0"))
- Config_Error_NaN(Line, Var);
+ Config_Error(LOG_WARNING,
+ "%s, line %d: Value of \"%s\" is not a valid user name or ID!",
+ NGIRCd_ConfFile, Line, Var);
}
return;
}
}
return;
}
+ if (strcasecmp(Var, "IdleTimeout") == 0) {
+ Conf_IdleTimeout = atoi(Arg);
+ if (!Conf_IdleTimeout && strcmp(Arg, "0"))
+ Config_Error_NaN(Line, Var);
+ return;
+ }
if (strcasecmp(Var, "MaxConnections") == 0) {
- Conf_MaxConnections = atol(Arg);
+ Conf_MaxConnections = atoi(Arg);
if (!Conf_MaxConnections && strcmp(Arg, "0"))
Config_Error_NaN(Line, Var);
return;
Conf_MaxNickLength = Handle_MaxNickLength(Line, Arg);
return;
}
+ if (strcasecmp(Var, "MaxListSize") == 0) {
+ Conf_MaxListSize = atoi(Arg);
+ if (!Conf_MaxListSize && strcmp(Arg, "0"))
+ Config_Error_NaN(Line, Var);
+ return;
+ }
if (strcasecmp(Var, "PingTimeout") == 0) {
Conf_PingTimeout = atoi(Arg);
if (Conf_PingTimeout < 5) {
Config_Error_TooLong(Line, Var);
return;
}
+ if (strcasecmp(Var, "CloakHostModeX") == 0) {
+ len = strlcpy(Conf_CloakHostModeX, Arg, sizeof(Conf_CloakHostModeX));
+ if (len >= sizeof(Conf_CloakHostModeX))
+ Config_Error_TooLong(Line, Var);
+ return;
+ }
+ if (strcasecmp(Var, "CloakHostSalt") == 0) {
+ len = strlcpy(Conf_CloakHostSalt, Arg, sizeof(Conf_CloakHostSalt));
+ if (len >= sizeof(Conf_CloakHostSalt))
+ Config_Error_TooLong(Line, Var);
+ return;
+ }
if (strcasecmp(Var, "CloakUserToNick") == 0) {
Conf_CloakUserToNick = Check_ArgIsTrue(Arg);
return;
WarnIdent(Line);
return;
}
+ if (strcasecmp(Var, "MorePrivacy") == 0) {
+ Conf_MorePrivacy = Check_ArgIsTrue(Arg);
+ return;
+ }
if (strcasecmp(Var, "NoticeAuth") == 0) {
Conf_NoticeAuth = Check_ArgIsTrue(Arg);
return;
Conf_OperCanMode = Check_ArgIsTrue(Arg);
return;
}
+ if (strcasecmp(Var, "OperChanPAutoOp") == 0) {
+ Conf_OperChanPAutoOp = Check_ArgIsTrue(Arg);
+ return;
+ }
if (strcasecmp(Var, "OperServerMode") == 0) {
Conf_OperServerMode = Check_ArgIsTrue(Arg);
return;
WarnPAM(Line);
return;
}
+ if (strcasecmp(Var, "PAMIsOptional") == 0 ) {
+ Conf_PAMIsOptional = Check_ArgIsTrue(Arg);
+ return;
+ }
if (strcasecmp(Var, "PredefChannelsOnly") == 0) {
Conf_PredefChannelsOnly = Check_ArgIsTrue(Arg);
return;
assert( Line > 0 );
assert( Var != NULL );
assert( Arg != NULL );
- assert( Conf_Oper_Count > 0 );
- op = array_alloc(&Conf_Opers, sizeof(*op), Conf_Oper_Count - 1);
- if (!op) {
- Config_Error(LOG_ERR, "Could not allocate memory for operator (%d:%s = %s)", Line, Var, Arg);
+ op = array_get(&Conf_Opers, sizeof(*op),
+ array_length(&Conf_Opers, sizeof(*op)) - 1);
+ if (!op)
return;
- }
if (strcasecmp(Var, "Name") == 0) {
/* Name of IRC operator */
Handle_CHANNEL(int Line, char *Var, char *Arg)
{
size_t len;
- size_t chancount;
struct Conf_Channel *chan;
assert( Line > 0 );
assert( Var != NULL );
assert( Arg != NULL );
- assert(Conf_Channel_Count > 0);
- chancount = Conf_Channel_Count - 1;
-
- chan = array_alloc(&Conf_Channels, sizeof(*chan), chancount);
- if (!chan) {
- Config_Error(LOG_ERR, "Could not allocate memory for predefined channel (%d:%s = %s)", Line, Var, Arg);
+ chan = array_get(&Conf_Channels, sizeof(*chan),
+ array_length(&Conf_Channels, sizeof(*chan)) - 1);
+ if (!chan)
return;
- }
+
if (strcasecmp(Var, "Name") == 0) {
if (!Handle_Channelname(chan, Arg))
Config_Error_TooLong(Line, Var);
bool config_valid = true;
char *ptr;
+ /* Emit a warning when the config file is not a full path name */
+ if (NGIRCd_ConfFile[0] && NGIRCd_ConfFile[0] != '/') {
+ Config_Error(LOG_WARNING,
+ "Not specifying a full path name to \"%s\" can cause problems when rehashing the server!",
+ NGIRCd_ConfFile);
+ }
+
/* Validate configured server name, see RFC 2812 section 2.3.1 */
ptr = Conf_ServerName;
do {
}
}
Log(LOG_DEBUG,
- "Configuration: Operators=%d, Servers=%d[%d], Channels=%d",
- Conf_Oper_Count, servers, servers_once, Conf_Channel_Count);
+ "Configuration: Operators=%ld, Servers=%d[%d], Channels=%ld",
+ array_length(&Conf_Opers, sizeof(struct Conf_Oper)),
+ servers, servers_once,
+ array_length(&Conf_Channels, sizeof(struct Conf_Channel)));
#endif
return config_valid;
Proc_InitStruct(&Server->res_stat);
Server->conn_id = NONE;
- memset(&Server->bind_addr, 0, sizeof(&Server->bind_addr));
+ memset(&Server->bind_addr, 0, sizeof(Server->bind_addr));
}
/* -eof- */