/*
* ngIRCd -- The Next Generation IRC Daemon
- * Copyright (c)2001-2013 Alexander Barton (alex@barton.de) and Contributors.
+ * Copyright (c)2001-2024 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
* IRC commands for server links
*/
-#include "imp.h"
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
-#include "defines.h"
-#include "conn.h"
#include "conn-func.h"
#include "conn-zip.h"
#include "conf.h"
#include "channel.h"
-#include "lists.h"
#include "log.h"
#include "messages.h"
#include "parse.h"
#include "numeric.h"
#include "ngircd.h"
+#include "irc.h"
+#include "irc-channel.h"
#include "irc-info.h"
-#include "irc-macros.h"
#include "irc-write.h"
#include "op.h"
-#include "exp.h"
#include "irc-server.h"
/**
return DISCONNECTED;
}
+#ifdef SSL_SUPPORT
+ /* Does this server require an SSL connection? */
+ if (Conf_Server[i].SSLConnect &&
+ !(Conn_Options(Client_Conn(Client)) & CONN_SSL)) {
+ Log(LOG_ERR,
+ "Connection %d: Server \"%s\" requires a secure connection!",
+ Client_Conn(Client), Req->argv[0]);
+ Conn_Close(Client_Conn(Client), NULL,
+ "Secure connection required", true);
+ return DISCONNECTED;
+ }
+#endif
+
/* Check server password */
if (strcmp(Conn_Password(Client_Conn(Client)),
Conf_Server[i].pwd_in) != 0) {
if (!Client_CheckID(Client, Req->argv[0]))
return DISCONNECTED;
+ if (!Req->prefix) {
+ /* We definitely need a prefix here! */
+ Log(LOG_ALERT, "Got SERVER command without prefix! (on connection %d)",
+ Client_Conn(Client));
+ Conn_Close(Client_Conn(Client), NULL,
+ "SERVER command without prefix", true);
+ return DISCONNECTED;
+ }
+
from = Client_Search( Req->prefix );
if (! from) {
/* Uh, Server, that introduced the new server is unknown?! */
CHANNEL *chan;
CLIENT *c;
- assert( Client != NULL );
- assert( Req != NULL );
+ assert(Client != NULL);
+ assert(Req != NULL);
- strlcpy( nick_in, Req->argv[1], sizeof( nick_in ));
- strcpy( nick_out, "" );
+ strlcpy(nick_in, Req->argv[1], sizeof(nick_in));
+ strcpy(nick_out, "");
channame = Req->argv[0];
- ptr = strtok( nick_in, "," );
- while( ptr )
- {
+
+ ptr = strtok(nick_in, ",");
+ while (ptr) {
is_owner = is_chanadmin = is_op = is_halfop = is_voiced = false;
/* cut off prefixes */
- while(( *ptr == '~') || ( *ptr == '&' ) || ( *ptr == '@' ) ||
- ( *ptr == '%') || ( *ptr == '+' ))
- {
- if( *ptr == '~' ) is_owner = true;
- if( *ptr == '&' ) is_chanadmin = true;
- if( *ptr == '@' ) is_op = true;
- if( *ptr == 'h' ) is_halfop = true;
- if( *ptr == '+' ) is_voiced = true;
+ while ((*ptr == '~') || (*ptr == '&') || (*ptr == '@') ||
+ (*ptr == '%') || (*ptr == '+')) {
+ if (*ptr == '~')
+ is_owner = true;
+ if (*ptr == '&')
+ is_chanadmin = true;
+ if (*ptr == '@')
+ is_op = true;
+ if (*ptr == '%')
+ is_halfop = true;
+ if (*ptr == '+')
+ is_voiced = true;
ptr++;
}
- c = Client_Search( ptr );
- if( c )
- {
- Channel_Join( c, channame );
- chan = Channel_Search( channame );
- assert( chan != NULL );
-
- if( is_owner ) Channel_UserModeAdd( chan, c, 'q' );
- if( is_chanadmin ) Channel_UserModeAdd( chan, c, 'a' );
- if( is_op ) Channel_UserModeAdd( chan, c, 'o' );
- if( is_halfop ) Channel_UserModeAdd( chan, c, 'h' );
- if( is_voiced ) Channel_UserModeAdd( chan, c, 'v' );
-
- /* announce to channel... */
- IRC_WriteStrChannelPrefix( Client, chan, c, false, "JOIN :%s", channame );
-
- /* set Channel-User-Modes */
- strlcpy( modes, Channel_UserModes( chan, c ), sizeof( modes ));
- if( modes[0] )
- {
- /* send modes to channel */
- IRC_WriteStrChannelPrefix( Client, chan, Client, false, "MODE %s +%s %s", channame, modes, Client_ID( c ));
- }
+ c = Client_Search(ptr);
+ if (!c) {
+ /* Client not found? */
+ Log(LOG_ERR,
+ "Got NJOIN for unknown nick \"%s\" for channel \"%s\"!",
+ ptr, channame);
+ goto skip_njoin;
+ }
- if( nick_out[0] != '\0' ) strlcat( nick_out, ",", sizeof( nick_out ));
- if( is_owner ) strlcat( nick_out, "~", sizeof( nick_out ));
- if( is_chanadmin ) strlcat( nick_out, "&", sizeof( nick_out ));
- if( is_op ) strlcat( nick_out, "@", sizeof( nick_out ));
- if( is_halfop ) strlcat( nick_out, "%", sizeof( nick_out ));
- if( is_voiced ) strlcat( nick_out, "+", sizeof( nick_out ));
- strlcat( nick_out, ptr, sizeof( nick_out ));
+ if (!Channel_Join(c, channame)) {
+ /* Failed to join channel. Ooops!? */
+ Log(LOG_ALERT,
+ "Failed to join client \"%s\" to channel \"%s\" (NJOIN): killing it!",
+ ptr, channame);
+ IRC_KillClient(NULL, NULL, ptr, "Internal NJOIN error!");
+ LogDebug("... done.");
+ goto skip_njoin;
}
- else Log( LOG_ERR, "Got NJOIN for unknown nick \"%s\" for channel \"%s\"!", ptr, channame );
- /* search for next Nick */
- ptr = strtok( NULL, "," );
+ chan = Channel_Search(channame);
+ assert(chan != NULL);
+
+ if (is_owner)
+ Channel_UserModeAdd(chan, c, 'q');
+ if (is_chanadmin)
+ Channel_UserModeAdd(chan, c, 'a');
+ if (is_op)
+ Channel_UserModeAdd(chan, c, 'o');
+ if (is_halfop)
+ Channel_UserModeAdd(chan, c, 'h');
+ if (is_voiced)
+ Channel_UserModeAdd(chan, c, 'v');
+
+ /* Announce client to the channel */
+ 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])
+ IRC_WriteStrChannelPrefix(Client, chan, Client, false,
+ "MODE %s +%s %s", channame,
+ modes, Client_ID(c));
+
+ /* Build nick list for forwarding command */
+ if (nick_out[0] != '\0')
+ strlcat(nick_out, ",", sizeof(nick_out));
+ if (is_owner)
+ strlcat(nick_out, "~", sizeof(nick_out));
+ if (is_chanadmin)
+ strlcat(nick_out, "&", sizeof(nick_out));
+ if (is_op)
+ strlcat(nick_out, "@", sizeof(nick_out));
+ if (is_halfop)
+ strlcat(nick_out, "%", sizeof(nick_out));
+ if (is_voiced)
+ strlcat(nick_out, "+", sizeof(nick_out));
+ strlcat(nick_out, ptr, sizeof(nick_out));
+
+ skip_njoin:
+ /* Get next nick, if any ... */
+ ptr = strtok(NULL, ",");
}
/* forward to other servers */
{
char msg[COMMAND_LEN], logmsg[COMMAND_LEN];
CLIENT *from, *target;
- CONN_ID con;
+ CONN_ID con, client_con;
int loglevel;
assert(Client != NULL);
return CONNECTED;
}
+ client_con = Client_Conn(Client);
con = Client_Conn(target);
if (Req->argv[1][0])
Req->argv[0], Client_ID(from),
Req->argv[1][0] ? Req->argv[1] : "-");
Conn_Close(con, NULL, msg, true);
- if (con == Client_Conn(Client))
+ if (con == client_con)
return DISCONNECTED;
} else {
/* This server is not directly connected, so the SQUIT must