about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/ngircd/array.c8
-rw-r--r--src/ngircd/channel.c4
-rw-r--r--src/ngircd/client.c14
-rw-r--r--src/ngircd/client.h2
-rw-r--r--src/ngircd/conf.c30
-rw-r--r--src/ngircd/conf.h5
-rw-r--r--src/ngircd/conn-func.c10
-rw-r--r--src/ngircd/conn-zip.c8
-rw-r--r--src/ngircd/conn.c32
-rw-r--r--src/ngircd/conn.h2
-rw-r--r--src/ngircd/defines.h2
-rw-r--r--src/ngircd/io.c2
-rw-r--r--src/ngircd/irc-channel.c57
-rw-r--r--src/ngircd/irc-channel.h4
-rw-r--r--src/ngircd/irc-info.c9
-rw-r--r--src/ngircd/irc-login.c7
-rw-r--r--src/ngircd/irc-mode.c123
-rw-r--r--src/ngircd/irc-op.c6
-rw-r--r--src/ngircd/irc-oper.c2
-rw-r--r--src/ngircd/irc-server.c11
-rw-r--r--src/ngircd/irc.c2
-rw-r--r--src/ngircd/lists.c2
-rw-r--r--src/ngircd/log.c15
-rw-r--r--src/ngircd/log.h6
-rw-r--r--src/ngircd/login.c35
-rw-r--r--src/ngircd/login.h1
-rw-r--r--src/ngircd/messages.h4
-rw-r--r--src/ngircd/ngircd.c24
-rw-r--r--src/ngircd/ngircd.h2
-rw-r--r--src/ngircd/numeric.c2
-rw-r--r--src/ngircd/parse.c2
-rw-r--r--src/ngircd/parse.h2
-rw-r--r--src/ngircd/proc.c4
-rw-r--r--src/ngircd/resolve.c14
-rw-r--r--src/ngircd/sighandlers.c16
-rw-r--r--src/portab/portab.h2
-rw-r--r--src/portab/vsnprintf.c2
-rw-r--r--src/testsuite/README2
38 files changed, 227 insertions, 248 deletions
diff --git a/src/ngircd/array.c b/src/ngircd/array.c
index 4cc793f1..6d1ab338 100644
--- a/src/ngircd/array.c
+++ b/src/ngircd/array.c
@@ -68,7 +68,7 @@ array_alloc(array * a, size_t size, size_t pos)
 
 	if (a->allocated < alloc) {
 #if DEBUG_ARRAY
-		Log(LOG_DEBUG, "array_alloc(): changing size from %u to %u bytes.",
+		LogDebug("array_alloc(): changing size from %u to %u bytes.",
 		    a->allocated, alloc);
 #endif
 		tmp = realloc(a->mem, alloc);
@@ -169,7 +169,7 @@ array_catb(array * dest, const char *src, size_t len)
 	assert(ptr != NULL);
 
 #if DEBUG_ARRAY
-	Log(LOG_DEBUG,
+	LogDebug(
 	    "array_catb(): appending %u bytes to array (now %u bytes in array).",
 	    len, tmp);
 #endif
@@ -249,7 +249,7 @@ array_free(array * a)
 {
 	assert(a != NULL);
 #if DEBUG_ARRAY
-	Log(LOG_DEBUG,
+	LogDebug(
 	    "array_free(): %u bytes free'd (%u bytes still used at time of free()).",
 	    a->allocated, a->used);
 #endif
@@ -315,7 +315,7 @@ array_moveleft(array * a, size_t membersize, size_t pos)
 		return;	/* nothing to do */
 
 #if DEBUG_ARRAY
-	Log(LOG_DEBUG,
+	LogDebug(
 	    "array_moveleft(): %u bytes used in array, starting at position %u.",
 	    a->used, bytepos);
 #endif
diff --git a/src/ngircd/channel.c b/src/ngircd/channel.c
index 3282a8d0..03af496b 100644
--- a/src/ngircd/channel.c
+++ b/src/ngircd/channel.c
@@ -148,7 +148,7 @@ Channel_InitPredefined( void )
 			for (n = 0; n < conf_chan->modes_num; n++) {
 				Req.argc = 1;
 				strlcpy(modes, conf_chan->modes[n], sizeof(modes));
-				Log(LOG_DEBUG, "Evaluate \"MODE %s %s\".", name, modes);
+				LogDebug("Evaluate \"MODE %s %s\".", name, modes);
 				c = strtok(modes, " ");
 				while (c && Req.argc < 15) {
 					Req.argv[Req.argc++] = c;
@@ -186,8 +186,6 @@ Channel_InitPredefined( void )
 		    new_chan->name, new_chan->modes, new_chan->key,
 		    new_chan->maxusers);
 	}
-	if (channel_count)
-		array_free(&Conf_Channels);
 
 	/* Make sure the local &SERVER channel exists */
 	if (!Channel_Search("&SERVER")) {
diff --git a/src/ngircd/client.c b/src/ngircd/client.c
index 634cecdc..48768514 100644
--- a/src/ngircd/client.c
+++ b/src/ngircd/client.c
@@ -213,7 +213,7 @@ Init_New_Client(CONN_ID Idx, CLIENT *Introducer, CLIENT *TopServer,
 		Generate_MyToken(client);
 
 	if (Client_HasMode(client, 'a'))
-		client->away = strndup(DEFAULT_AWAY_MSG, CLIENT_AWAY_LEN - 1);
+		client->away = strdup(DEFAULT_AWAY_MSG);
 
 	client->next = (POINTER *)My_Clients;
 	My_Clients = client;
@@ -698,10 +698,8 @@ Client_ID( CLIENT *Client )
 {
 	assert( Client != NULL );
 
-#ifdef DEBUG
 	if(Client->type == CLIENT_USER)
 		assert(strlen(Client->id) < Conf_MaxNickLength);
-#endif
 
 	if( Client->id[0] ) return Client->id;
 	else return "*";
@@ -1499,9 +1497,7 @@ Client_RegisterWhowas( CLIENT *Client )
 	slot = Last_Whowas + 1;
 	if( slot >= MAX_WHOWAS || slot < 0 ) slot = 0;
 
-#ifdef DEBUG
-	Log( LOG_DEBUG, "Saving WHOWAS information to slot %d ...", slot );
-#endif
+	LogDebug( "Saving WHOWAS information to slot %d ...", slot );
 
 	My_Whowas[slot].time = now;
 	strlcpy( My_Whowas[slot].id, Client_ID( Client ),
@@ -1696,17 +1692,16 @@ Client_Announce(CLIENT * Client, CLIENT * Prefix, CLIENT * User)
 } /* Client_Announce */
 
 
-#ifdef DEBUG
 
 GLOBAL void
 Client_DebugDump(void)
 {
 	CLIENT *c;
 
-	Log(LOG_DEBUG, "Client status:");
+	LogDebug("Client status:");
 	c = My_Clients;
 	while (c) {
-		Log(LOG_DEBUG,
+		LogDebug(
 		    " - %s: type=%d, host=%s, user=%s, conn=%d, start=%ld, flags=%s",
                    Client_ID(c), Client_Type(c), Client_Hostname(c),
                    Client_User(c), Client_Conn(c), Client_StartTime(c),
@@ -1715,7 +1710,6 @@ Client_DebugDump(void)
 	}
 } /* Client_DumpClients */
 
-#endif
 
 
 /* -eof- */
diff --git a/src/ngircd/client.h b/src/ngircd/client.h
index 4185d217..f6f9525b 100644
--- a/src/ngircd/client.h
+++ b/src/ngircd/client.h
@@ -182,9 +182,7 @@ GLOBAL void Client_UpdateCloakedHostname PARAMS((CLIENT *Client,
 						 const char *hostname));
 
 
-#ifdef DEBUG
 GLOBAL void Client_DebugDump PARAMS((void));
-#endif
 
 #endif
 
diff --git a/src/ngircd/conf.c b/src/ngircd/conf.c
index 140d0b9f..4fd7d44d 100644
--- a/src/ngircd/conf.c
+++ b/src/ngircd/conf.c
@@ -464,13 +464,13 @@ Conf_Test( void )
 		printf( "  Host = %s\n", Conf_Server[i].host );
 		printf( "  Port = %u\n", (unsigned int)Conf_Server[i].port );
 #ifdef SSL_SUPPORT
-		printf( "  SSLConnect = %s\n", Conf_Server[i].SSLConnect?"yes":"no");
+		printf( "  SSLConnect = %s\n", yesno_to_str(Conf_Server[i].SSLConnect));
 #endif
 		printf( "  MyPassword = %s\n", Conf_Server[i].pwd_in );
 		printf( "  PeerPassword = %s\n", Conf_Server[i].pwd_out );
 		printf( "  ServiceMask = %s\n", Conf_Server[i].svs_mask);
 		printf( "  Group = %d\n", Conf_Server[i].group );
-		printf( "  Passive = %s\n\n", Conf_Server[i].flags & CONF_SFLAG_DISABLED ? "yes" : "no");
+		printf( "  Passive = %s\n\n", yesno_to_str(Conf_Server[i].flags & CONF_SFLAG_DISABLED));
 	}
 
 	predef_channel_count = array_length(&Conf_Channels, sizeof(*predef_chan));
@@ -488,6 +488,7 @@ Conf_Test( void )
 		printf("  Key = %s\n", predef_chan->key);
 		printf("  MaxUsers = %lu\n", predef_chan->maxusers);
 		printf("  Topic = %s\n", predef_chan->topic);
+		printf("  Autojoin = %s\n", yesno_to_str(predef_chan->autojoin));
 		printf("  KeyFile = %s\n\n", predef_chan->keyfile);
 	}
 
@@ -942,16 +943,13 @@ Read_Config(bool TestOnly, bool IsStarting)
 
 					if( Conf_Server[i].conn_id == Conf_Server[n].conn_id ) {
 						Init_Server_Struct( &Conf_Server[n] );
-#ifdef DEBUG
-						Log(LOG_DEBUG,"Deleted unused duplicate server %d (kept %d).",
-												n, i );
-#endif
+						LogDebug("Deleted unused duplicate server %d (kept %d).", n, i);
 					}
 				}
 			} else {
 				/* Mark server as "once" */
 				Conf_Server[i].flags |= CONF_SFLAG_ONCE;
-				Log( LOG_DEBUG, "Marked server %d as \"once\"", i );
+				LogDebug("Marked server %d as \"once\"", i);
 			}
 		}
 	}
@@ -2003,6 +2001,11 @@ Handle_CHANNEL(const char *File, int Line, char *Var, char *Arg)
 			Config_Error_TooLong(File, Line, Var);
 		return;
 	}
+	if( strcasecmp( Var, "Autojoin" ) == 0 ) {
+		/* Check autojoin */
+		chan->autojoin = Check_ArgIsTrue(Arg);
+		return;
+	}
 	if( strcasecmp( Var, "Key" ) == 0 ) {
 		/* Initial Channel Key (mode k) */
 		len = strlcpy(chan->key, Arg, sizeof(chan->key));
@@ -2049,9 +2052,7 @@ Validate_Config(bool Configtest, bool Rehash)
 {
 	/* Validate configuration settings. */
 
-#ifdef DEBUG
 	int i, servers, servers_once;
-#endif
 	bool config_valid = true;
 	char *ptr;
 
@@ -2125,7 +2126,6 @@ Validate_Config(bool Configtest, bool Rehash)
 			     "Maximum penalty increase ('MaxPenaltyTime') is set to %ld, this is not recommended!",
 			     Conf_MaxPenaltyTime);
 
-#ifdef DEBUG
 	servers = servers_once = 0;
 	for (i = 0; i < MAX_SERVERS; i++) {
 		if (Conf_Server[i].name[0]) {
@@ -2134,12 +2134,10 @@ Validate_Config(bool Configtest, bool Rehash)
 				servers_once++;
 		}
 	}
-	Log(LOG_DEBUG,
-	    "Configuration: Operators=%ld, Servers=%d[%d], Channels=%ld",
+	LogDebug("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;
 }
@@ -2226,7 +2224,6 @@ va_dcl
 		Log(Level, "%s", msg);
 }
 
-#ifdef DEBUG
 
 /**
  * Dump internal state of the "configuration module".
@@ -2236,11 +2233,11 @@ Conf_DebugDump(void)
 {
 	int i;
 
-	Log(LOG_DEBUG, "Configured servers:");
+	LogDebug("Configured servers:");
 	for (i = 0; i < MAX_SERVERS; i++) {
 		if (! Conf_Server[i].name[0])
 			continue;
-		Log(LOG_DEBUG,
+		LogDebug(
 		    " - %s: %s:%d, last=%ld, group=%d, flags=%d, conn=%d",
 		    Conf_Server[i].name, Conf_Server[i].host,
 		    Conf_Server[i].port, Conf_Server[i].lasttry,
@@ -2249,7 +2246,6 @@ Conf_DebugDump(void)
 	}
 }
 
-#endif
 
 /**
  * Initialize server configuration structure to default values.
diff --git a/src/ngircd/conf.h b/src/ngircd/conf.h
index b964c407..f3e2c5a5 100644
--- a/src/ngircd/conf.h
+++ b/src/ngircd/conf.h
@@ -87,6 +87,7 @@ struct Conf_Channel {
 	char key[CLIENT_PASS_LEN];      /**< Channel key ("password", mode "k" ) */
 	char topic[COMMAND_LEN];	/**< Initial topic */
 	char keyfile[512];		/**< Path and name of channel key file */
+	bool autojoin;			/**< 1 to make all users autojoin this channel */
 	unsigned long maxusers;		/**< User limit for this channel, mode "l" */
 	unsigned int modes_num;		/**< Number of channel modes to evaluate */
 };
@@ -222,7 +223,7 @@ GLOBAL bool Conf_ConnectIPv6;
 /** Try to connect to remote systems using the IPv4 protocol (true) */
 GLOBAL bool Conf_ConnectIPv4;
 
-/** Idle timout (seconds), after which the daemon should exit */
+/** Idle timeout (seconds), after which the daemon should exit */
 GLOBAL int Conf_IdleTimeout;
 
 /** Maximum number of simultaneous connections to this server */
@@ -280,9 +281,7 @@ GLOBAL bool Conf_SSLInUse PARAMS((void));
 /* Password required by WEBIRC command */
 GLOBAL char Conf_WebircPwd[CLIENT_PASS_LEN];
 
-#ifdef DEBUG
 GLOBAL void Conf_DebugDump PARAMS((void));
-#endif
 
 
 #endif
diff --git a/src/ngircd/conn-func.c b/src/ngircd/conn-func.c
index 3cf8a3a6..25ae1b26 100644
--- a/src/ngircd/conn-func.c
+++ b/src/ngircd/conn-func.c
@@ -21,11 +21,8 @@
 #include <assert.h>
 #include <time.h>
 
-#ifdef DEBUG
-# include "log.h"
-#endif
+#include "log.h"
 #include "conn.h"
-
 #include "conf.h"
 #include "conn-func.h"
 
@@ -116,13 +113,10 @@ Conn_SetPenalty(CONN_ID Idx, time_t Seconds)
 
 	My_Connections[Idx].delaytime += Seconds;
 
-#ifdef DEBUG
-	Log(LOG_DEBUG,
-	    "Add penalty time on connection %d: %ld second%s, total %ld second%s.",
+	LogDebug("Add penalty time on connection %d: %ld second%s, total %ld second%s.",
 	    Idx, (long)Seconds, Seconds != 1 ? "s" : "",
 	    My_Connections[Idx].delaytime - t,
 	    My_Connections[Idx].delaytime - t != 1 ? "s" : "");
-#endif
 } /* Conn_SetPenalty */
 
 GLOBAL void
diff --git a/src/ngircd/conn-zip.c b/src/ngircd/conn-zip.c
index fe7f2fb0..36816bdd 100644
--- a/src/ngircd/conn-zip.c
+++ b/src/ngircd/conn-zip.c
@@ -142,7 +142,7 @@ Zip_Flush( CONN_ID Idx )
 	out->avail_out = (uInt)sizeof zipbuf;
 
 #if DEBUG_ZIP
-	Log(LOG_DEBUG, "out->avail_in %d, out->avail_out %d",
+	LogDebug("out->avail_in %d, out->avail_out %d",
 		out->avail_in, out->avail_out);
 #endif
 	result = deflate( out, Z_SYNC_FLUSH );
@@ -165,7 +165,7 @@ Zip_Flush( CONN_ID Idx )
 
 	zipbuf_used = WRITEBUFFER_SLINK_LEN - out->avail_out;
 #if DEBUG_ZIP
-	Log(LOG_DEBUG, "zipbuf_used: %d", zipbuf_used);
+	LogDebug("zipbuf_used: %d", zipbuf_used);
 #endif
 	if (!array_catb(&My_Connections[Idx].wbuf,
 			(char *)zipbuf, (size_t) zipbuf_used)) {
@@ -217,7 +217,7 @@ Unzip_Buffer( CONN_ID Idx )
 	in->avail_out = (uInt)sizeof unzipbuf;
 
 #if DEBUG_ZIP
-	Log(LOG_DEBUG, "in->avail_in %d, in->avail_out %d",
+	LogDebug("in->avail_in %d, in->avail_out %d",
 		in->avail_in, in->avail_out);
 #endif
 	result = inflate( in, Z_SYNC_FLUSH );
@@ -232,7 +232,7 @@ Unzip_Buffer( CONN_ID Idx )
 	in_len = z_rdatalen - in->avail_in;
 	unzipbuf_used = READBUFFER_LEN - in->avail_out;
 #if DEBUG_ZIP
-	Log(LOG_DEBUG, "unzipbuf_used: %d - %d = %d", READBUFFER_LEN,
+	LogDebug("unzipbuf_used: %d - %d = %d", READBUFFER_LEN,
 		in->avail_out, unzipbuf_used);
 #endif
 	assert(unzipbuf_used <= READBUFFER_LEN);
diff --git a/src/ngircd/conn.c b/src/ngircd/conn.c
index 94c6c4a8..e8ef68f3 100644
--- a/src/ngircd/conn.c
+++ b/src/ngircd/conn.c
@@ -591,7 +591,7 @@ set_v6_only(int af, int sock)
 /**
  * Initialize new listening port.
  *
- * @param listen_addr	Local address to bind the socet to (can be 0.0.0.0).
+ * @param listen_addr	Local address to bind the socket to (can be 0.0.0.0).
  * @param Port		Port number on which the new socket should be listening.
  * @returns		file descriptor of the socket or -1 on failure.
  */
@@ -875,7 +875,7 @@ va_dcl
 
 #ifdef SNIFFER
 	if (NGIRCd_Sniffer)
-		Log(LOG_DEBUG, " -> connection %d: '%s'.", Idx, buffer);
+		LogDebug("-> connection %d: '%s'.", Idx, buffer);
 #endif
 
 	len = strlcat( buffer, "\r\n", sizeof( buffer ));
@@ -1055,8 +1055,10 @@ Conn_Close(CONN_ID Idx, const char *LogMsg, const char *FwdMsg, bool InformClien
 		}
 #endif
 		/* Send ERROR to client (see RFC 2812, section 3.1.7) */
-		if (FwdMsg)
-			Conn_WriteStr(Idx, "ERROR :%s", FwdMsg);
+		if (c)
+			Conn_WriteStr(Idx, "ERROR :Closing connection: %s[%s@%s] (%s)",
+				      Client_ID(c), Client_User(c), Client_Hostname(c),
+				      FwdMsg ? FwdMsg : "\"\"");
 		else
 			Conn_WriteStr(Idx, "ERROR :Closing connection");
 	}
@@ -1356,13 +1358,14 @@ New_Connection(int Sock, UNUSED bool IsSSL)
 	new_sock = accept(Sock, (struct sockaddr *)&new_addr,
 			  (socklen_t *)&new_sock_len);
 	if (new_sock < 0) {
-		Log(LOG_CRIT, "Can't accept connection: %s!", strerror(errno));
+		Log(LOG_CRIT, "Can't accept connection on socket %d: %s!",
+		    Sock, strerror(errno));
 		return -1;
 	}
 	NumConnectionsAccepted++;
 
 	if (!ng_ipaddr_tostr_r(&new_addr, ip_str)) {
-		Log(LOG_CRIT, "fd %d: Can't convert IP address!", new_sock);
+		Log(LOG_CRIT, "Can't convert peer IP address of socket %d!", new_sock);
 		Simple_Message(new_sock, "ERROR :Internal Server Error");
 		close(new_sock);
 		return -1;
@@ -1375,7 +1378,8 @@ New_Connection(int Sock, UNUSED bool IsSSL)
 	fromhost(&req);
 	if (!hosts_access(&req)) {
 		Log(deny_severity,
-		    "Refused connection from %s (by TCP Wrappers)!", ip_str);
+		    "Refused connection from %s on socket %d (by TCP Wrappers)!",
+		    ip_str, Sock);
 		Simple_Message(new_sock, "ERROR :Connection refused");
 		close(new_sock);
 		return -1;
@@ -1400,8 +1404,8 @@ New_Connection(int Sock, UNUSED bool IsSSL)
 	if ((Conf_MaxConnectionsIP > 0) && (cnt >= Conf_MaxConnectionsIP)) {
 		/* Access denied, too many connections from this IP address! */
 		Log(LOG_ERR,
-		    "Refused connection from %s: too may connections (%ld) from this IP address!",
-		    ip_str, cnt);
+		    "Refused connection from %s on socket %d: too may connections (%ld) from this IP address!",
+		    ip_str, Sock, cnt);
 		Simple_Message(new_sock,
 			       "ERROR :Connection refused, too many connections from your IP address");
 		close(new_sock);
@@ -1454,7 +1458,7 @@ New_Connection(int Sock, UNUSED bool IsSSL)
 	Account_Connection();
 
 #ifdef SSL_SUPPORT
-	/* Delay connection initalization until SSL handshake is finished */
+	/* Delay connection initialization until SSL handshake is finished */
 	if (!IsSSL)
 #endif
 		Conn_StartLogin(new_sock);
@@ -2341,10 +2345,8 @@ cb_Read_Resolver_Result( int r_fd, UNUSED short events )
 
 		Class_HandleServerBans(c);
 	}
-#ifdef DEBUG
 	else
 		LogDebug("Resolver: discarding result for already registered connection %d.", i);
-#endif
 } /* cb_Read_Resolver_Result */
 
 /**
@@ -2688,7 +2690,6 @@ Conn_SetCertFp(UNUSED CONN_ID Idx, UNUSED const char *fingerprint)
 
 #endif /* SSL_SUPPORT */
 
-#ifdef DEBUG
 
 /**
  * Dump internal state of the "connection module".
@@ -2698,11 +2699,11 @@ Conn_DebugDump(void)
 {
 	int i;
 
-	Log(LOG_DEBUG, "Connection status:");
+	LogDebug("Connection status:");
 	for (i = 0; i < Pool_Size; i++) {
 		if (My_Connections[i].sock == NONE)
 			continue;
-		Log(LOG_DEBUG,
+		LogDebug(
 		    " - %d: host=%s, lastdata=%ld, lastping=%ld, delaytime=%ld, flag=%d, options=%d, bps=%d, client=%s",
 		    My_Connections[i].sock, My_Connections[i].host,
 		    My_Connections[i].lastdata, My_Connections[i].lastping,
@@ -2712,6 +2713,5 @@ Conn_DebugDump(void)
 	}
 } /* Conn_DumpClients */
 
-#endif /* DEBUG */
 
 /* -eof- */
diff --git a/src/ngircd/conn.h b/src/ngircd/conn.h
index 869477f0..ca64ad20 100644
--- a/src/ngircd/conn.h
+++ b/src/ngircd/conn.h
@@ -166,9 +166,7 @@ GLOBAL long Conn_GetAuthPing PARAMS((CONN_ID Idx));
 GLOBAL void Conn_SetAuthPing PARAMS((CONN_ID Idx, long ID));
 #endif
 
-#ifdef DEBUG
 GLOBAL void Conn_DebugDump PARAMS((void));
-#endif
 
 #endif
 
diff --git a/src/ngircd/defines.h b/src/ngircd/defines.h
index ff8cd226..c5371e87 100644
--- a/src/ngircd/defines.h
+++ b/src/ngircd/defines.h
@@ -123,7 +123,7 @@
 /** Max. host name length (including NULL). */
 #define CLIENT_HOST_LEN 64
 
-/** Max. mask lenght (including NULL). */
+/** Max. mask length (including NULL). */
 #define MASK_LEN (2 * CLIENT_HOST_LEN)
 
 /** Max. length of all client modes (including NULL). */
diff --git a/src/ngircd/io.c b/src/ngircd/io.c
index 037c4afc..2a1e941e 100644
--- a/src/ngircd/io.c
+++ b/src/ngircd/io.c
@@ -148,7 +148,7 @@ static void io_docallback PARAMS((int fd, short what));
 static void
 io_debug(const char *s, int fd, int what)
 {
-	Log(LOG_DEBUG, "%s: %d, %d\n", s, fd, what);
+	LogDebug("%s: %d, %d\n", s, fd, what);
 }
 #else
 static inline void
diff --git a/src/ngircd/irc-channel.c b/src/ngircd/irc-channel.c
index 812429bb..a1bb4ef5 100644
--- a/src/ngircd/irc-channel.c
+++ b/src/ngircd/irc-channel.c
@@ -176,7 +176,7 @@ join_set_channelmodes(CHANNEL *chan, CLIENT *target, const char *flags)
  * and MODE commands.
  *
  * @param To		Forward JOIN (and MODE) command to this peer server
- * @param Prefix	Client used to prefix the genrated commands
+ * @param Prefix	Client used to prefix the generated commands
  * @param Data		Parameters of JOIN command to forward, probably
  *			containing channel modes separated by ASCII 7.
  */
@@ -209,7 +209,7 @@ cb_join_forward(CLIENT *To, CLIENT *Prefix, void *Data)
  * This function calls cb_join_forward(), which differentiates between
  * protocol implementations (e.g. RFC 2812, RFC 1459).
  *
- * @param Client	Client used to prefix the genrated commands
+ * @param Client	Client used to prefix the generated commands
  * @param target	Forward JOIN (and MODE) command to this peer server
  * @param chan		Channel structure
  * @param channame	Channel name
@@ -248,46 +248,38 @@ join_forward(CLIENT *Client, CLIENT *target, CHANNEL *chan,
 } /* join_forward */
 
 /**
- * Acknowledge user JOIN request and send "channel info" numerics.
+ * Send channel TOPIC and NAMES list to a newly (N)JOIN'ed client.
  *
- * @param Client	Client used to prefix the genrated commands
- * @param target	Forward commands/numerics to this user
- * @param chan		Channel structure
- * @param channame	Channel name
+ * @param Client	Client used to prefix the generated commands
+ * @param Chan		Channel structure
  */
-static bool
-join_send_topic(CLIENT *Client, CLIENT *target, CHANNEL *chan,
-					const char *channame)
+GLOBAL bool
+IRC_Send_Channel_Info(CLIENT *Client, CHANNEL *Chan)
 {
 	const char *topic;
 
-	if (Client_Type(Client) != CLIENT_USER)
-		return true;
-	/* acknowledge join */
-	if (!IRC_WriteStrClientPrefix(Client, target, "JOIN :%s", channame))
-		return false;
-
-	/* Send topic to client, if any */
-	topic = Channel_Topic(chan);
+	/* Send the topic (if any) to the new client: */
+	topic = Channel_Topic(Chan);
 	assert(topic != NULL);
 	if (*topic) {
 		if (!IRC_WriteStrClient(Client, RPL_TOPIC_MSG,
-			Client_ID(Client), channame, topic))
+			Client_ID(Client), Channel_Name(Chan), topic))
 				return false;
 #ifndef STRICT_RFC
 		if (!IRC_WriteStrClient(Client, RPL_TOPICSETBY_MSG,
-			Client_ID(Client), channame,
-			Channel_TopicWho(chan),
-			Channel_TopicTime(chan)))
+			Client_ID(Client), Channel_Name(Chan),
+			Channel_TopicWho(Chan),
+			Channel_TopicTime(Chan)))
 				return false;
 #endif
 	}
-	/* send list of channel members to client */
-	if (!IRC_Send_NAMES(Client, chan))
+
+	/* Send list of channel members to the new client: */
+	if (!IRC_Send_NAMES(Client, Chan))
 		return false;
-	return IRC_WriteStrClient(Client, RPL_ENDOFNAMES_MSG, Client_ID(Client),
-				  Channel_Name(chan));
-} /* join_send_topic */
+	return IRC_WriteStrClient(Client, RPL_ENDOFNAMES_MSG,
+				  Client_ID(Client), Channel_Name(Chan));
+}
 
 /**
  * Handler for the IRC "JOIN" command.
@@ -408,8 +400,15 @@ IRC_JOIN( CLIENT *Client, REQUEST *Req )
 
 		join_forward(Client, target, chan, channame);
 
-		if (!join_send_topic(Client, target, chan, channame))
-			break; /* write error */
+		if (Client_Type(Client) == CLIENT_USER) {
+			/* Acknowledge join ... */
+			if (!IRC_WriteStrClientPrefix(Client, target,
+						      "JOIN :%s", channame))
+				break; /* write error */
+			/* ... and greet new user: */
+			if (!IRC_Send_Channel_Info(Client, chan))
+				break; /* write error */
+		}
 
 	join_next:
 		/* next channel? */
diff --git a/src/ngircd/irc-channel.h b/src/ngircd/irc-channel.h
index 685ec0c3..77f00f86 100644
--- a/src/ngircd/irc-channel.h
+++ b/src/ngircd/irc-channel.h
@@ -1,6 +1,6 @@
 /*
  * ngIRCd -- The Next Generation IRC Daemon
- * Copyright (c)2001,2002 by Alexander Barton (alex@barton.de)
+ * Copyright (c)2001-2022 by Alexander Barton (alex@barton.de)
  *
  * 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
@@ -25,6 +25,8 @@ GLOBAL bool IRC_LIST PARAMS((CLIENT *Client, REQUEST *Req ));
 
 GLOBAL bool IRC_CHANINFO PARAMS((CLIENT *Client, REQUEST *Req ));
 
+GLOBAL bool IRC_Send_Channel_Info PARAMS((CLIENT *Client, CHANNEL *Chan));
+
 #endif
 
 /* -eof- */
diff --git a/src/ngircd/irc-info.c b/src/ngircd/irc-info.c
index 82bd5518..718aa990 100644
--- a/src/ngircd/irc-info.c
+++ b/src/ngircd/irc-info.c
@@ -138,7 +138,7 @@ who_flags_qualifier(CLIENT *Client, const char *chan_user_modes,
 static bool
 IRC_WHO_Channel(CLIENT *Client, CHANNEL *Chan, bool OnlyOps)
 {
-	bool is_visible, is_member, is_ircop;
+	bool is_visible, is_member, is_ircop, is_oper;
 	CL2CHAN *cl2chan;
 	char flags[10];
 	CLIENT *c;
@@ -148,9 +148,10 @@ IRC_WHO_Channel(CLIENT *Client, CHANNEL *Chan, bool OnlyOps)
 	assert( Chan != NULL );
 
 	is_member = Channel_IsMemberOf(Chan, Client);
+	is_oper = Client_HasMode(Client, 'o');
 
 	/* Secret channel? */
-	if (!is_member && Channel_HasMode(Chan, 's'))
+	if (!is_member && !is_oper && Channel_HasMode(Chan, 's'))
 		return IRC_WriteStrClient(Client, RPL_ENDOFWHO_MSG,
 					  Client_ID(Client), Channel_Name(Chan));
 
@@ -163,7 +164,7 @@ IRC_WHO_Channel(CLIENT *Client, CHANNEL *Chan, bool OnlyOps)
 			continue;
 
 		is_visible = !Client_HasMode(c, 'i');
-		if (is_member || is_visible) {
+		if (is_member || is_visible || is_oper) {
 			memset(flags, 0, sizeof(flags));
 
 			if (Client_HasMode(c, 'a'))
@@ -1264,6 +1265,8 @@ IRC_WHOIS( CLIENT *Client, REQUEST *Req )
 
 			if (Client_Type(c) != CLIENT_USER)
 				continue;
+			if (Client_HasMode(c, 'i'))
+				continue;
 			if (!MatchCaseInsensitive(query, Client_ID(c)))
 				continue;
 			if (!IRC_WHOIS_SendReply(Client, from, c))
diff --git a/src/ngircd/irc-login.c b/src/ngircd/irc-login.c
index 368a03d4..fb221922 100644
--- a/src/ngircd/irc-login.c
+++ b/src/ngircd/irc-login.c
@@ -774,7 +774,7 @@ IRC_PING(CLIENT *Client, REQUEST *Req)
 		return IRC_WriteErrClient(Client, ERR_NOSUCHSERVER_MSG,
 					Client_ID(Client), Req->prefix);
 
-	Log(LOG_DEBUG, "Connection %d: got PING, sending PONG ...",
+	LogDebug("Connection %d: got PING, sending PONG ...",
 	    Client_Conn(Client));
 
 #ifdef STRICT_RFC
@@ -877,9 +877,7 @@ IRC_PONG(CLIENT *Client, REQUEST *Req)
 		    (long)(time(NULL) - Conn_GetSignon(conn)),
 		    time(NULL) - Conn_GetSignon(conn) == 1 ? "" : "s",
 		    Client_UserCount(), Channel_CountVisible(NULL));
-	}
-#ifdef DEBUG
-	else {
+	} else {
 		if (Conn_LastPing(conn) > 1)
 			LogDebug("Connection %d: received PONG. Lag: %ld seconds.",
 				 conn, (long)(time(NULL) - Conn_LastPing(conn)));
@@ -887,7 +885,6 @@ IRC_PONG(CLIENT *Client, REQUEST *Req)
 			LogDebug("Got unexpected PONG on connection %d. Ignored.",
 				 conn);
 	}
-#endif
 
 	/* We got a PONG, so signal that none is pending on this connection. */
 	Conn_UpdatePing(conn, 1);
diff --git a/src/ngircd/irc-mode.c b/src/ngircd/irc-mode.c
index 99255df1..0ea046e5 100644
--- a/src/ngircd/irc-mode.c
+++ b/src/ngircd/irc-mode.c
@@ -1,6 +1,6 @@
 /*
  * ngIRCd -- The Next Generation IRC Daemon
- * Copyright (c)2001-2014 Alexander Barton (alex@barton.de) and Contributors.
+ * Copyright (c)2001-2023 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
@@ -281,7 +281,7 @@ Client_Mode( CLIENT *Client, REQUEST *Req, CLIENT *Origin, CLIENT *Target )
 			break;
 		default:
 			if (Client_Type(Client) != CLIENT_SERVER) {
-				Log(LOG_DEBUG,
+				LogDebug(
 				    "Unknown mode \"%c%c\" from \"%s\"!?",
 				    set ? '+' : '-', *mode_ptr,
 				    Client_ID(Origin));
@@ -292,7 +292,7 @@ Client_Mode( CLIENT *Client, REQUEST *Req, CLIENT *Origin, CLIENT *Target )
 							*mode_ptr);
 				x[0] = '\0';
 			} else {
-				Log(LOG_DEBUG,
+				LogDebug(
 				    "Handling unknown mode \"%c%c\" from \"%s\" for \"%s\" ...",
 				    set ? '+' : '-', *mode_ptr,
 				    Client_ID(Origin), Client_ID(Target));
@@ -609,33 +609,43 @@ Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel)
 						Channel_Name(Channel));
 				break;
 			}
-			if (arg_arg > mode_arg) {
-				if (is_oper || is_machine || is_owner ||
-				    is_admin || is_op || is_halfop) {
-					Channel_ModeDel(Channel, 'k');
-					Channel_SetKey(Channel,
-						       Req->argv[arg_arg]);
-					strlcpy(argadd, Channel_Key(Channel),
-						sizeof(argadd));
-					x[0] = *mode_ptr;
-				} else {
+			if (arg_arg <= mode_arg) {
+				if (is_machine)
+					Log(LOG_ERR,
+					    "Got MODE +k without key for \"%s\" from \"%s\"! Ignored.",
+					    Channel_Name(Channel), Client_ID(Origin));
+				else
 					connected = IRC_WriteErrClient(Origin,
-						ERR_CHANOPRIVSNEEDED_MSG,
+						ERR_NEEDMOREPARAMS_MSG,
+						Client_ID(Origin), Req->command);
+				goto chan_exit;
+			}
+			if (!Req->argv[arg_arg][0] || strchr(Req->argv[arg_arg], ' ')) {
+				if (is_machine)
+					Log(LOG_ERR,
+					    "Got invalid key on MODE +k for \"%s\" from \"%s\"! Ignored.",
+					    Channel_Name(Channel), Client_ID(Origin));
+				else
+					connected = IRC_WriteErrClient(Origin,
+					       ERR_INVALIDMODEPARAM_MSG,
 						Client_ID(Origin),
-						Channel_Name(Channel));
-				}
-				Req->argv[arg_arg][0] = '\0';
-				arg_arg++;
+						Channel_Name(Channel), 'k');
+				goto chan_exit;
+			}
+			if (is_oper || is_machine || is_owner ||
+			    is_admin || is_op || is_halfop) {
+				Channel_ModeDel(Channel, 'k');
+				Channel_SetKey(Channel, Req->argv[arg_arg]);
+				strlcpy(argadd, Channel_Key(Channel), sizeof(argadd));
+				x[0] = *mode_ptr;
 			} else {
-#ifdef STRICT_RFC
-				/* Only send error message in "strict" mode,
-				 * this is how ircd2.11 and others behave ... */
 				connected = IRC_WriteErrClient(Origin,
-					ERR_NEEDMOREPARAMS_MSG,
-					Client_ID(Origin), Req->command);
-#endif
-				goto chan_exit;
+					ERR_CHANOPRIVSNEEDED_MSG,
+					Client_ID(Origin),
+					Channel_Name(Channel));
 			}
+			Req->argv[arg_arg][0] = '\0';
+			arg_arg++;
 			break;
 		case 'l': /* Member limit */
 			if (Mode_Limit_Reached(Client, mode_arg_count++))
@@ -651,35 +661,44 @@ Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel)
 						Channel_Name(Channel));
 				break;
 			}
-			if (arg_arg > mode_arg) {
-				if (is_oper || is_machine || is_owner ||
-				    is_admin || is_op || is_halfop) {
-					l = atol(Req->argv[arg_arg]);
-					if (l > 0 && l < 0xFFFF) {
-						Channel_ModeDel(Channel, 'l');
-						Channel_SetMaxUsers(Channel, l);
-						snprintf(argadd, sizeof(argadd),
-							 "%ld", l);
-						x[0] = *mode_ptr;
-					}
-				} else {
+			if (arg_arg <= mode_arg) {
+				if (is_machine)
+					Log(LOG_ERR,
+					    "Got MODE +l without limit for \"%s\" from \"%s\"! Ignored.",
+					    Channel_Name(Channel), Client_ID(Origin));
+				else
 					connected = IRC_WriteErrClient(Origin,
-						ERR_CHANOPRIVSNEEDED_MSG,
+						ERR_NEEDMOREPARAMS_MSG,
+						Client_ID(Origin), Req->command);
+				goto chan_exit;
+			}
+			l = atol(Req->argv[arg_arg]);
+			if (l <= 0 || l >= 0xFFFF) {
+				if (is_machine)
+					Log(LOG_ERR,
+					    "Got MODE +l with invalid limit for \"%s\" from \"%s\"! Ignored.",
+					    Channel_Name(Channel), Client_ID(Origin));
+				else
+					connected = IRC_WriteErrClient(Origin,
+						ERR_INVALIDMODEPARAM_MSG,
 						Client_ID(Origin),
-						Channel_Name(Channel));
-				}
-				Req->argv[arg_arg][0] = '\0';
-				arg_arg++;
+						Channel_Name(Channel), 'l');
+				goto chan_exit;
+			}
+			if (is_oper || is_machine || is_owner ||
+			    is_admin || is_op || is_halfop) {
+				Channel_ModeDel(Channel, 'l');
+				Channel_SetMaxUsers(Channel, l);
+				snprintf(argadd, sizeof(argadd), "%ld", l);
+				x[0] = *mode_ptr;
 			} else {
-#ifdef STRICT_RFC
-				/* Only send error message in "strict" mode,
-				 * this is how ircd2.11 and others behave ... */
 				connected = IRC_WriteErrClient(Origin,
-					ERR_NEEDMOREPARAMS_MSG,
-					Client_ID(Origin), Req->command);
-#endif
-				goto chan_exit;
+					ERR_CHANOPRIVSNEEDED_MSG,
+					Client_ID(Origin),
+					Channel_Name(Channel));
 			}
+			Req->argv[arg_arg][0] = '\0';
+			arg_arg++;
 			break;
 		case 'O': /* IRC operators only */
 			if (set) {
@@ -823,7 +842,7 @@ Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel)
 			break;
 		default:
 			if (Client_Type(Client) != CLIENT_SERVER) {
-				Log(LOG_DEBUG,
+				LogDebug(
 				    "Unknown mode \"%c%c\" from \"%s\" on %s!?",
 				    set ? '+' : '-', *mode_ptr,
 				    Client_ID(Origin), Channel_Name(Channel));
@@ -833,7 +852,7 @@ Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel)
 					Channel_Name(Channel));
 				x[0] = '\0';
 			} else {
-				Log(LOG_DEBUG,
+				LogDebug(
 				    "Handling unknown mode \"%c%c\" from \"%s\" on %s ...",
 				    set ? '+' : '-', *mode_ptr,
 				    Client_ID(Origin), Channel_Name(Channel));
@@ -904,7 +923,7 @@ Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel)
 		if (Client_Type(Client) == CLIENT_SERVER) {
 			/* MODE requests for local channels from other servers
 			 * are definitely invalid! */
-			if (Channel_IsLocal(Channel)) {
+			if (Channel_IsLocal(Channel) && Client != Client_ThisServer()) {
 				Log(LOG_ALERT, "Got remote MODE command for local channel!? Ignored.");
 				return CONNECTED;
 			}
diff --git a/src/ngircd/irc-op.c b/src/ngircd/irc-op.c
index a309ee9f..2bf9e349 100644
--- a/src/ngircd/irc-op.c
+++ b/src/ngircd/irc-op.c
@@ -222,9 +222,9 @@ IRC_INVITE(CLIENT *Client, REQUEST *Req)
 
 	if (Client_Conn(target) > NONE) {
 		/* The target user is local, so we have to send the status code */
-		if (!IRC_WriteStrClientPrefix(from, target, RPL_INVITING_MSG,
-					       Client_ID(from), Req->argv[0],
-					       colon_if_necessary, Req->argv[1]))
+		if (!IRC_WriteStrClient(from, RPL_INVITING_MSG,
+					Client_ID(from), Req->argv[0],
+					colon_if_necessary, Req->argv[1]))
 			return DISCONNECTED;
 
 		if (Client_HasMode(target, 'a') &&
diff --git a/src/ngircd/irc-oper.c b/src/ngircd/irc-oper.c
index ae333b10..df8e2269 100644
--- a/src/ngircd/irc-oper.c
+++ b/src/ngircd/irc-oper.c
@@ -399,7 +399,7 @@ IRC_xLINE(CLIENT *Client, REQUEST *Req)
 					  Client_ID(Client), Req->command);
 
 	if (!Conf_AllowRemoteOper && Client_Type(Client) == CLIENT_SERVER) {
-		/* Explicitely forbid remote servers to modify "x-lines" when
+		/* Explicitly forbid remote servers to modify "x-lines" when
 		 * the "AllowRemoteOper" configuration option isn't set, even
 		 * when the command seems to originate from the remote server
 		 * itself: this prevents GLINE's to become set during server
diff --git a/src/ngircd/irc-server.c b/src/ngircd/irc-server.c
index 3f9753b9..b78d0502 100644
--- a/src/ngircd/irc-server.c
+++ b/src/ngircd/irc-server.c
@@ -1,6 +1,6 @@
 /*
  * ngIRCd -- The Next Generation IRC Daemon
- * Copyright (c)2001-2014 Alexander Barton (alex@barton.de) and Contributors.
+ * Copyright (c)2001-2022 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
@@ -32,6 +32,7 @@
 #include "numeric.h"
 #include "ngircd.h"
 #include "irc.h"
+#include "irc-channel.h"
 #include "irc-info.h"
 #include "irc-write.h"
 #include "op.h"
@@ -298,7 +299,7 @@ IRC_NJOIN( CLIENT *Client, REQUEST *Req )
 			    "Failed to join client \"%s\" to channel \"%s\" (NJOIN): killing it!",
 			    ptr, channame);
 			IRC_KillClient(NULL, NULL, ptr, "Internal NJOIN error!");
-			Log(LOG_DEBUG, "... done.");
+			LogDebug("... done.");
 			goto skip_njoin;
 		}
 
@@ -320,6 +321,12 @@ IRC_NJOIN( CLIENT *Client, REQUEST *Req )
 		IRC_WriteStrChannelPrefix(Client, chan, c, false,
 					  "JOIN :%s", channame);
 
+		/* If the client is connected to this server, it was remotely
+		 * joined to the channel by another server/service: So send
+		 * TOPIC and NAMES messages like on a regular JOIN command! */
+		if(Client_Conn(c) != NONE)
+			IRC_Send_Channel_Info(c, chan);
+
 		/* Announce "channel user modes" to the channel, if any */
 		strlcpy(modes, Channel_UserModes(chan, c), sizeof(modes));
 		if (modes[0])
diff --git a/src/ngircd/irc.c b/src/ngircd/irc.c
index 3113a4ba..ba33e5ae 100644
--- a/src/ngircd/irc.c
+++ b/src/ngircd/irc.c
@@ -514,7 +514,7 @@ Option_String(UNUSED CONN_ID Idx)
 /**
  * Send a message to target(s).
  *
- * This function is used by IRC_{PRIVMSG|NOTICE|SQUERY} to actualy
+ * This function is used by IRC_{PRIVMSG|NOTICE|SQUERY} to actually
  * send the message(s).
  *
  * @param Client The client from which this command has been received.
diff --git a/src/ngircd/lists.c b/src/ngircd/lists.c
index 38b3b0e8..69ea79a4 100644
--- a/src/ngircd/lists.c
+++ b/src/ngircd/lists.c
@@ -341,7 +341,7 @@ Lists_CheckReason(struct list_head *h, CLIENT *Client, char *reason, size_t len)
 
 	while (e) {
 		next = e->next;
-		if (MatchCaseInsensitive(e->mask, Client_MaskCloaked(Client))) {
+		if (MatchCaseInsensitive(e->mask, Client_MaskCloaked(Client)) || MatchCaseInsensitive(e->mask, Client_Mask(Client))) {
 			if (len && e->reason)
 				strlcpy(reason, e->reason, len);
 			if (e->onlyonce) {
diff --git a/src/ngircd/log.c b/src/ngircd/log.c
index f2582bce..dae53f9f 100644
--- a/src/ngircd/log.c
+++ b/src/ngircd/log.c
@@ -121,7 +121,6 @@ Log_Exit( void )
  * @param Format Format string like printf().
  * @param ... Further arguments.
  */
-#ifdef DEBUG
 # ifdef PROTOTYPES
 GLOBAL void
 LogDebug( const char *Format, ... )
@@ -145,7 +144,6 @@ va_dcl
 	va_end( ap );
 	Log(LOG_DEBUG, "%s", msg);
 }
-#endif	/* DEBUG */
 
 
 /**
@@ -184,11 +182,7 @@ va_dcl
 	}
 	else snotice = false;
 
-#ifdef DEBUG
 	if(( Level == LOG_DEBUG ) && ( ! NGIRCd_Debug )) return;
-#else
-	if( Level == LOG_DEBUG ) return;
-#endif
 
 #ifdef PROTOTYPES
 	va_start( ap, Format );
@@ -215,20 +209,16 @@ Log_Init_Subprocess(char UNUSED *Name)
 #ifdef SYSLOG
 	openlog(PACKAGE, LOG_CONS|LOG_PID, Conf_SyslogFacility);
 #endif
-#ifdef DEBUG
 	Log_Subprocess(LOG_DEBUG, "%s sub-process starting, PID %ld.",
 		     Name, (long)getpid());
-#endif
 }
 
 
 GLOBAL void
 Log_Exit_Subprocess(char UNUSED *Name)
 {
-#ifdef DEBUG
 	Log_Subprocess(LOG_DEBUG, "%s sub-process %ld done.",
 		     Name, (long)getpid());
-#endif
 #ifdef SYSLOG
 	closelog( );
 #endif
@@ -251,13 +241,8 @@ va_dcl
 
 	assert(Format != NULL);
 
-#ifdef DEBUG
 	if ((Level == LOG_DEBUG) && (!NGIRCd_Debug))
 		return;
-#else
-	if (Level == LOG_DEBUG)
-		return;
-#endif
 
 #ifdef PROTOTYPES
 	va_start(ap, Format);
diff --git a/src/ngircd/log.h b/src/ngircd/log.h
index b48193f5..0ac4c4d9 100644
--- a/src/ngircd/log.h
+++ b/src/ngircd/log.h
@@ -40,20 +40,14 @@ GLOBAL void Log_ReInit PARAMS((void));
 
 GLOBAL void Log_ServerNotice PARAMS((char UserMode, const char *Format, ...));
 
-#ifdef DEBUG
 GLOBAL void LogDebug PARAMS(( const char *Format, ... ));
-#else
-static inline void LogDebug PARAMS(( UNUSED const char *Format, ... )){/* Do nothing. The compiler should optimize this out, please ;-) */}
-#endif
 
 GLOBAL void Log_Init_Subprocess PARAMS((char *Name));
 GLOBAL void Log_Exit_Subprocess PARAMS((char *Name));
 
 GLOBAL void Log_Subprocess PARAMS((const int Level, const char *Format, ...));
 
-#ifdef DEBUG
 GLOBAL void Log_InitErrorfile PARAMS(( void ));
-#endif
 
 #endif
 
diff --git a/src/ngircd/login.c b/src/ngircd/login.c
index ba9378f8..3412e337 100644
--- a/src/ngircd/login.c
+++ b/src/ngircd/login.c
@@ -31,6 +31,7 @@
 #include "log.h"
 #include "messages.h"
 #include "ngircd.h"
+#include "irc-channel.h"
 #include "irc-info.h"
 #include "irc-mode.h"
 #include "irc-write.h"
@@ -201,9 +202,41 @@ Login_User_PostAuth(CLIENT *Client)
 	} else
 		IRC_SetPenalty(Client, 1);
 
+	/* Autojoin clients to the channels */
+	Login_Autojoin(Client);
+
 	return CONNECTED;
 }
 
+/**
+ * Autojoin clients to the channels set by administrator
+ *
+ * Do nothing if autojoin is not set in the configuration or the channel is not
+ * available (any more).
+ **/
+GLOBAL void
+Login_Autojoin(CLIENT *Client)
+{
+	REQUEST Req;
+	const struct Conf_Channel *conf_chan;
+	size_t i, channel_count = array_length(&Conf_Channels, sizeof(*conf_chan));
+
+	conf_chan = array_start(&Conf_Channels);
+	assert(channel_count == 0 || conf_chan != NULL);
+
+	for (i = 0; i < channel_count; i++, conf_chan++) {
+		if(!conf_chan->autojoin)
+			continue;
+		if (!Channel_Search(conf_chan->name))
+			continue;
+		Req.prefix = Client_ID(Client_ThisServer());
+		Req.command = "JOIN";
+		Req.argc = 1;
+		Req.argv[0] = (char *)conf_chan->name;
+		IRC_JOIN(Client, &Req);
+	}
+}
+
 #ifdef PAM
 
 /**
@@ -248,7 +281,7 @@ cb_Read_Auth_Result(int r_fd, UNUSED short events)
 
 	if (result == true) {
 		/* Authentication succeeded, now set the correct user name
-		 * supplied by the client (without prepended '~' for exmaple),
+		 * supplied by the client (without prepended '~' for example),
 		 * but cut it at the first '@' character: */
 		strlcpy(user, Client_OrigUser(client), sizeof(user));
 		ptr = strchr(user, '@');
diff --git a/src/ngircd/login.h b/src/ngircd/login.h
index 6e3a21d6..b5d7be1e 100644
--- a/src/ngircd/login.h
+++ b/src/ngircd/login.h
@@ -19,6 +19,7 @@
 
 GLOBAL bool Login_User PARAMS((CLIENT * Client));
 GLOBAL bool Login_User_PostAuth PARAMS((CLIENT *Client));
+GLOBAL void Login_Autojoin PARAMS((CLIENT *Client));
 
 #endif
 
diff --git a/src/ngircd/messages.h b/src/ngircd/messages.h
index 76a04ff9..1bbfa699 100644
--- a/src/ngircd/messages.h
+++ b/src/ngircd/messages.h
@@ -1,6 +1,6 @@
 /*
  * ngIRCd -- The Next Generation IRC Daemon
- * Copyright (c)2001-2020 Alexander Barton (alex@barton.de) and Contributors.
+ * Copyright (c)2001-2023 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
@@ -162,6 +162,8 @@
 #define ERR_USERNOTONSERV_MSG		"504 %s %s :User is not on this server"
 #define ERR_NOINVITE_MSG		"518 %s :Cannot invite to %s (+V)"
 
+#define ERR_INVALIDMODEPARAM_MSG	"696 %s %s %c * :Invalid mode parameter"
+
 #ifdef ZLIB
 # define RPL_STATSLINKINFOZIP_MSG	"211 %s %s %d %ld %ld/%ld %ld %ld/%ld :%ld"
 #endif
diff --git a/src/ngircd/ngircd.c b/src/ngircd/ngircd.c
index a124e2e7..fd919e34 100644
--- a/src/ngircd/ngircd.c
+++ b/src/ngircd/ngircd.c
@@ -1,6 +1,6 @@
 /*
  * ngIRCd -- The Next Generation IRC Daemon
- * Copyright (c)2001-2022 Alexander Barton (alex@barton.de) and Contributors.
+ * Copyright (c)2001-2023 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
@@ -88,9 +88,7 @@ main(int argc, const char *argv[])
 
 	NGIRCd_SignalQuit = NGIRCd_SignalRestart = false;
 	NGIRCd_Passive = false;
-#ifdef DEBUG
 	NGIRCd_Debug = false;
-#endif
 #ifdef SNIFFER
 	NGIRCd_Sniffer = false;
 #endif
@@ -117,12 +115,10 @@ main(int argc, const char *argv[])
 				configtest = true;
 				ok = true;
 			}
-#ifdef DEBUG
 			if (strcmp(argv[i], "--debug") == 0) {
 				NGIRCd_Debug = true;
 				ok = true;
 			}
-#endif
 			if (strcmp(argv[i], "--help") == 0) {
 				Show_Version();
 				puts(""); Show_Help( ); puts( "" );
@@ -158,12 +154,10 @@ main(int argc, const char *argv[])
 			/* short option */
 			for (n = 1; n < strlen(argv[i]); n++) {
 				ok = false;
-#ifdef DEBUG
 				if (argv[i][n] == 'd') {
 					NGIRCd_Debug = true;
 					ok = true;
 				}
-#endif
 				if (argv[i][n] == 'f') {
 					if (!argv[i][n+1] && i+1 < argc) {
 						/* Ok, next character is a blank */
@@ -237,10 +231,8 @@ main(int argc, const char *argv[])
 
 	/* Debug level for "VERSION" command */
 	NGIRCd_DebugLevel[0] = '\0';
-#ifdef DEBUG
 	if (NGIRCd_Debug)
 		strcpy(NGIRCd_DebugLevel, "1");
-#endif
 #ifdef SNIFFER
 	if (NGIRCd_Sniffer) {
 		NGIRCd_Debug = true;
@@ -465,7 +457,7 @@ static void
 Show_Version( void )
 {
 	puts( NGIRCd_Version );
-	puts( "Copyright (c)2001-2022 Alexander Barton (<alex@barton.de>) and Contributors." );
+	puts( "Copyright (c)2001-2023 Alexander Barton (<alex@barton.de>) and Contributors." );
 	puts( "Homepage: <http://ngircd.barton.de/>\n" );
 	puts( "This is free software; see the source for copying conditions. There is NO" );
 	puts( "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." );
@@ -480,9 +472,7 @@ Show_Version( void )
 static void
 Show_Help( void )
 {
-#ifdef DEBUG
 	puts( "  -d, --debug        log extra debug messages" );
-#endif
 	puts( "  -f, --config <f>   use file <f> as configuration file" );
 	puts( "  -n, --nodaemon     don't fork and don't detach from controlling terminal" );
 	puts( "  -p, --passive      disable automatic connections to other servers" );
@@ -507,9 +497,7 @@ Pidfile_Delete( void )
 	/* Pidfile configured? */
 	if( ! Conf_PidFile[0] ) return;
 
-#ifdef DEBUG
-	Log( LOG_DEBUG, "Removing PID file (%s) ...", Conf_PidFile );
-#endif
+	LogDebug( "Removing PID file (%s) ...", Conf_PidFile );
 
 	if( unlink( Conf_PidFile ))
 		Log( LOG_ERR, "Error unlinking PID file (%s): %s", Conf_PidFile, strerror( errno ));
@@ -531,9 +519,7 @@ Pidfile_Create(pid_t pid)
 	/* Pidfile configured? */
 	if( ! Conf_PidFile[0] ) return;
 
-#ifdef DEBUG
-	Log( LOG_DEBUG, "Creating PID file (%s) ...", Conf_PidFile );
-#endif
+	LogDebug( "Creating PID file (%s) ...", Conf_PidFile );
 
 	pidfd = open( Conf_PidFile, O_RDWR|O_CREAT|O_EXCL, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
 	if ( pidfd < 0 ) {
@@ -834,7 +820,7 @@ NGIRCd_Init(bool NGIRCd_NoDaemon)
 
 	if (pwd) {
 		if (chdir(pwd->pw_dir) == 0)
-			Log(LOG_DEBUG,
+			LogDebug(
 			    "Changed working directory to \"%s\" ...",
 			    pwd->pw_dir);
 		else
diff --git a/src/ngircd/ngircd.h b/src/ngircd/ngircd.h
index 2efb8a94..c3ae0fee 100644
--- a/src/ngircd/ngircd.h
+++ b/src/ngircd/ngircd.h
@@ -35,10 +35,8 @@ GLOBAL char NGIRCd_Version[126];
 /** String specifying the compile-time options and target platform */
 GLOBAL char NGIRCd_VersionAddition[126];
 
-#ifdef DEBUG
 /** Flag indicating if debug mode is active (true) or not (false) */
 GLOBAL bool NGIRCd_Debug;
-#endif
 
 #ifdef SNIFFER
 /** Flag indication if sniffer is active (true) or not (false) */
diff --git a/src/ngircd/numeric.c b/src/ngircd/numeric.c
index 8edb76e2..99741068 100644
--- a/src/ngircd/numeric.c
+++ b/src/ngircd/numeric.c
@@ -217,10 +217,8 @@ Send_CHANINFO(CLIENT * Client, CHANNEL * Chan)
 	char *modes, *topic, *key;
 	bool has_k, has_l;
 
-#ifdef DEBUG
 	Log(LOG_DEBUG, "Sending CHANINFO commands for \"%s\" ...",
 	    Channel_Name(Chan));
-#endif
 
 	modes = Channel_Modes(Chan);
 	topic = Channel_Topic(Chan);
diff --git a/src/ngircd/parse.c b/src/ngircd/parse.c
index 51834133..7b5d28c2 100644
--- a/src/ngircd/parse.c
+++ b/src/ngircd/parse.c
@@ -183,7 +183,7 @@ Parse_Request( CONN_ID Idx, char *Request )
 	assert( Request != NULL );
 
 #ifdef SNIFFER
-	if( NGIRCd_Sniffer ) Log( LOG_DEBUG, " <- connection %d: '%s'.", Idx, Request );
+	if( NGIRCd_Sniffer ) LogDebug( " <- connection %d: '%s'.", Idx, Request );
 #endif
 
 	Init_Request( &req );
diff --git a/src/ngircd/parse.h b/src/ngircd/parse.h
index 859c7ce5..48260c67 100644
--- a/src/ngircd/parse.h
+++ b/src/ngircd/parse.h
@@ -25,7 +25,7 @@ typedef struct _REQUEST
 	char *prefix;			/**< Prefix */
 	char *command;			/**< IRC command */
 	char *argv[15];			/**< Parameters, at most 15 (0..14) */
-	int argc;			/**< Number of given paramaters */
+	int argc;			/**< Number of given parameters */
 } REQUEST;
 
 /** IRC command handling structure */
diff --git a/src/ngircd/proc.c b/src/ngircd/proc.c
index d68d714d..af00dd3d 100644
--- a/src/ngircd/proc.c
+++ b/src/ngircd/proc.c
@@ -114,14 +114,10 @@ Proc_GenericSignalHandler(int Signal)
 {
 	switch(Signal) {
 	case SIGTERM:
-#ifdef DEBUG
 		Log_Subprocess(LOG_DEBUG, "Child got TERM signal, exiting.");
-#endif
 		exit(1);
 	case SIGALRM:
-#ifdef DEBUG
 		Log_Subprocess(LOG_DEBUG, "Child got ALARM signal, exiting.");
-#endif
 		exit(1);
 	}
 }
diff --git a/src/ngircd/resolve.c b/src/ngircd/resolve.c
index afbef5b3..1931bc71 100644
--- a/src/ngircd/resolve.c
+++ b/src/ngircd/resolve.c
@@ -93,9 +93,7 @@ Resolve_Name( PROC_STAT *s, const char *Host, void (*cbfunc)(int, short))
 	pid = Proc_Fork(s, pipefd, cbfunc, RESOLVER_TIMEOUT);
 	if (pid > 0) {
 		/* Main process */
-#ifdef DEBUG
 		Log( LOG_DEBUG, "Resolver for \"%s\" created (PID %d).", Host, pid );
-#endif
 		return true;
 	} else if( pid == 0 ) {
 		/* Sub process */
@@ -140,15 +138,11 @@ Do_IdentQuery(int identsock, array *resolved_addr)
 	if (identsock < 0)
 		return;
 
-#ifdef DEBUG
 	Log_Subprocess(LOG_DEBUG, "Doing IDENT lookup on socket %d ...",
 		       identsock);
-#endif
 	res = ident_id( identsock, 10 );
-#ifdef DEBUG
 	Log_Subprocess(LOG_DEBUG, "Ok, IDENT lookup on socket %d done: \"%s\"",
 		       identsock, res ? res : "(NULL)");
-#endif
 	if (!res) /* no result */
 		return;
 	if (!array_cats(resolved_addr, res))
@@ -373,9 +367,7 @@ Do_ResolveAddr(const ng_ipaddr_t *Addr, int identsock, int w_fd)
 
 	array_init(&resolved_addr);
 	ng_ipaddr_tostr_r(Addr, tmp_ip_str);
-#ifdef DEBUG
 	Log_Subprocess(LOG_DEBUG, "Now resolving %s ...", tmp_ip_str);
-#endif
 	if (!ReverseLookup(Addr, hostname, sizeof(hostname)))
 		goto dns_done;
 
@@ -388,9 +380,7 @@ Do_ResolveAddr(const ng_ipaddr_t *Addr, int identsock, int w_fd)
 		Log_Forgery_NoIP(tmp_ip_str, hostname);
 		strlcpy(hostname, tmp_ip_str, sizeof(hostname));
 	}
-#ifdef DEBUG
 	Log_Subprocess(LOG_DEBUG, "Ok, translated %s to \"%s\".", tmp_ip_str, hostname);
-#endif
  dns_done:
 	len = strlen(hostname);
 	hostname[len] = '\n';
@@ -417,10 +407,8 @@ Do_ResolveName( const char *Host, int w_fd )
 	 * to parent. */
 	array IpAddrs;
 	int af;
-#ifdef DEBUG
 	ng_ipaddr_t *addr;
 	size_t len;
-#endif
 	Log_Subprocess(LOG_DEBUG, "Now resolving \"%s\" ...", Host);
 
 	array_init(&IpAddrs);
@@ -440,7 +428,6 @@ Do_ResolveName( const char *Host, int w_fd )
 		close(w_fd);
 		return;
 	}
-#ifdef DEBUG
 	len = array_length(&IpAddrs, sizeof(*addr));
 	assert(len > 0);
 	addr = array_start(&IpAddrs);
@@ -449,7 +436,6 @@ Do_ResolveName( const char *Host, int w_fd )
 		Log_Subprocess(LOG_DEBUG, "translated \"%s\" to %s.",
 					Host, ng_ipaddr_tostr(addr));
 	}
-#endif
 	/* Write result into pipe to parent */
 	ArrayWrite(w_fd, &IpAddrs);
 
diff --git a/src/ngircd/sighandlers.c b/src/ngircd/sighandlers.c
index 8275123e..4ed1a125 100644
--- a/src/ngircd/sighandlers.c
+++ b/src/ngircd/sighandlers.c
@@ -41,25 +41,23 @@ static const int signals_catch[] = {
        SIGINT, SIGQUIT, SIGTERM, SIGHUP, SIGCHLD, SIGUSR1, SIGUSR2
 };
 
-#ifdef DEBUG
 
 static void
 Dump_State(void)
 {
-	Log(LOG_DEBUG, "--- Internal server state: %s ---",
+	LogDebug("--- Internal server state: %s ---",
 	    Client_ID(Client_ThisServer()));
 #ifdef HAVE_LONG_LONG
-	Log(LOG_DEBUG, "time()=%llu", (unsigned long long)time(NULL));
+	LogDebug("time()=%llu", (unsigned long long)time(NULL));
 #else
-	Log(LOG_DEBUG, "time()=%lu", (unsigned long)time(NULL));
+	LogDebug("time()=%lu", (unsigned long)time(NULL));
 #endif
 	Conf_DebugDump();
 	Conn_DebugDump();
 	Client_DebugDump();
-	Log(LOG_DEBUG, "--- End of state dump ---");
+	LogDebug("--- End of state dump ---");
 } /* Dump_State */
 
-#endif
 
 static void
 Signal_Block(int sig)
@@ -174,7 +172,6 @@ Signal_Handler(int Signal)
 		while (waitpid( -1, NULL, WNOHANG) > 0)
 			;
 		return;
-#ifdef DEBUG
 	case SIGUSR1:
 		if (! NGIRCd_Debug) {
 			Log(LOG_INFO|LOG_snotice,
@@ -197,7 +194,6 @@ Signal_Handler(int Signal)
 #endif /* SNIFFER */
 		}
 		return;
-#endif
 	}
 
 	/*
@@ -226,7 +222,6 @@ Signal_Handler_BH(int Signal)
 		/* re-read configuration */
 		Rehash();
 		break;
-#ifdef DEBUG
 	case SIGUSR2:
 		if (NGIRCd_Debug) {
 			Log(LOG_INFO|LOG_snotice,
@@ -235,8 +230,7 @@ Signal_Handler_BH(int Signal)
 		}
 		break;
 	default:
-		Log(LOG_DEBUG, "Got signal %d! Ignored.", Signal);
-#endif
+		LogDebug("Got signal %d! Ignored.", Signal);
 	}
 	Signal_Unblock(Signal);
 }
diff --git a/src/portab/portab.h b/src/portab/portab.h
index 43f2f907..ebe81b49 100644
--- a/src/portab/portab.h
+++ b/src/portab/portab.h
@@ -19,6 +19,8 @@
 
 #include "config.h"
 
+/* remove assert() macro at compile time if DEBUG is not set. */
+
 #ifndef DEBUG
 # define NDEBUG
 #endif
diff --git a/src/portab/vsnprintf.c b/src/portab/vsnprintf.c
index 4c65db1f..d3b2a888 100644
--- a/src/portab/vsnprintf.c
+++ b/src/portab/vsnprintf.c
@@ -45,7 +45,7 @@
  *  probably requires libm on most operating systems. Don't yet
  *  support the exponent (e,E) and sigfig (g,G). Also, fmtint()
  *  was pretty badly broken, it just wasn't being exercised in ways
- *  which showed it, so that's been fixed. Also, formated the code
+ *  which showed it, so that's been fixed. Also, formatted the code
  *  to mutt conventions, and removed dead code left over from the
  *  original. Also, there is now a builtin-test, just compile with:
  *    gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm
diff --git a/src/testsuite/README b/src/testsuite/README
index 4ff5ea9f..33855fb0 100644
--- a/src/testsuite/README
+++ b/src/testsuite/README
@@ -71,7 +71,7 @@ tests.sh
 test-loop.sh [<loops> [<wait>]]
 
 	This script runs all the tests <loops> times (default: 5) and pauses
-	<wait> seconds (default: 5) betweed runs.
+	<wait> seconds (default: 5) between runs.
 	It isn't used by "make check" or "make testsuite".
 
 wait-tests.sh [<max>]