From 2cc21caf32323ebd778c16c8a7b69cd12d6ff01f Mon Sep 17 00:00:00 2001 From: Alexander Barton Date: Fri, 14 Nov 2008 00:42:58 +0100 Subject: [PATCH] Implement local channels (prefix "&") This patch implements server-local channels, prefix "&", that are only visible to users of the same local server and not in the network. Patch written by Scott Perry (2008-06-04), see: - http://arthur.barton.de/cgi-bin/bugzilla/show_bug.cgi?id=87 - http://arthur.barton.de/cgi-bin/bugzilla/attachment.cgi?id=24&action=view --- src/ngircd/channel.c | 16 +++++++++++----- src/ngircd/channel.h | 5 +++++ src/ngircd/irc-channel.c | 40 +++++++++++++++++++++++++++------------- src/ngircd/irc-info.c | 9 ++++++++- src/ngircd/irc-mode.c | 24 ++++++++++++++++++------ src/ngircd/messages.h | 6 ++---- src/ngircd/numeric.c | 4 ++++ 7 files changed, 75 insertions(+), 29 deletions(-) diff --git a/src/ngircd/channel.c b/src/ngircd/channel.c index 0f25a190..7c3360ac 100644 --- a/src/ngircd/channel.c +++ b/src/ngircd/channel.c @@ -509,7 +509,7 @@ Channel_IsValidName( const char *Name ) if (strlen(Name) <= 1) return false; #endif - if (strchr("+#", Name[0]) == NULL) + if (strchr("#&+", Name[0]) == NULL) return false; if (strlen(Name) >= CHANNEL_NAME_LEN) return false; @@ -875,6 +875,11 @@ Remove_Client( int Type, CHANNEL *Chan, CLIENT *Client, CLIENT *Origin, const ch assert( Origin != NULL ); assert( Reason != NULL ); + /* Do not inform other servers if the channel is local to this server, + * regardless of what the caller requested! */ + if(InformServer) + InformServer = !Channel_IsLocal(Chan); + last_cl2chan = NULL; cl2chan = My_Cl2Chan; while( cl2chan ) @@ -896,14 +901,16 @@ Remove_Client( int Type, CHANNEL *Chan, CLIENT *Client, CLIENT *Origin, const ch switch( Type ) { case REMOVE_QUIT: - /* QUIT: other servers have already been notified, see Client_Destroy(); - * so only inform other clients in same channel. */ + /* QUIT: other servers have already been notified, + * see Client_Destroy(); so only inform other clients + * in same channel. */ assert( InformServer == false ); LogDebug("User \"%s\" left channel \"%s\" (%s).", Client_Mask( Client ), c->name, Reason ); break; case REMOVE_KICK: - /* User was KICKed: inform other servers and all users in channel */ + /* User was KICKed: inform other servers (public + * channels) and all users in the channel */ if( InformServer ) IRC_WriteStrServersPrefix( Client_NextHop( Origin ), Origin, "KICK %s %s :%s", c->name, Client_ID( Client ), Reason); @@ -1062,5 +1069,4 @@ Delete_Channel( CHANNEL *Chan ) return true; } /* Delete_Channel */ - /* -eof- */ diff --git a/src/ngircd/channel.h b/src/ngircd/channel.h index 792f2692..91cc278e 100644 --- a/src/ngircd/channel.h +++ b/src/ngircd/channel.h @@ -124,5 +124,10 @@ GLOBAL bool Channel_AddBan PARAMS((CHANNEL *c, const char *Mask )); GLOBAL bool Channel_ShowBans PARAMS((CLIENT *client, CHANNEL *c)); GLOBAL bool Channel_ShowInvites PARAMS((CLIENT *client, CHANNEL *c)); + +#define Channel_IsLocal(c) (Channel_Name(c)[0] == '&') + + #endif + /* -eof- */ diff --git a/src/ngircd/irc-channel.c b/src/ngircd/irc-channel.c index 586d46ca..27414d38 100644 --- a/src/ngircd/irc-channel.c +++ b/src/ngircd/irc-channel.c @@ -156,16 +156,24 @@ join_forward(CLIENT *Client, CLIENT *target, CHANNEL *chan, else modes[0] = '\0'; - /* forward to other servers */ - snprintf(str, sizeof(str), "%s%s", channame, modes); - IRC_WriteStrServersPrefixFlag_CB(Client, target, '\0', cb_join_forward, str); + /* forward to other servers (if it is not a local channel) */ + if (!Channel_IsLocal(chan)) { + snprintf(str, sizeof(str), "%s%s", channame, modes); + IRC_WriteStrServersPrefixFlag_CB(Client, target, '\0', + cb_join_forward, str); + } /* tell users in this channel about the new client */ - IRC_WriteStrChannelPrefix(Client, chan, target, false, "JOIN :%s", channame); - if (modes[1]) - IRC_WriteStrChannelPrefix(Client, chan, target, false, "MODE %s +%s %s", - channame, &modes[1], Client_ID(target)); -} + IRC_WriteStrChannelPrefix(Client, chan, target, false, + "JOIN :%s", channame); + + /* syncronize channel modes */ + if (modes[1]) { + IRC_WriteStrChannelPrefix(Client, chan, target, false, + "MODE %s +%s %s", channame, + &modes[1], Client_ID(target)); + } +} /* join_forward */ static bool @@ -423,12 +431,18 @@ IRC_TOPIC( CLIENT *Client, REQUEST *Req ) Client_TypeText(from), Client_Mask(from), Channel_Name(chan), Req->argv[1][0] ? Req->argv[1] : ""); - /* im Channel bekannt machen und an Server weiterleiten */ - IRC_WriteStrServersPrefix( Client, from, "TOPIC %s :%s", Req->argv[0], Req->argv[1] ); - IRC_WriteStrChannelPrefix( Client, chan, from, false, "TOPIC %s :%s", Req->argv[0], Req->argv[1] ); + /* Update channel and forward new topic to other servers */ + if (!Channel_IsLocal(chan)) + IRC_WriteStrServersPrefix(Client, from, "TOPIC %s :%s", + Req->argv[0], Req->argv[1]); + IRC_WriteStrChannelPrefix(Client, chan, from, false, "TOPIC %s :%s", + Req->argv[0], Req->argv[1]); - if( Client_Type( Client ) == CLIENT_USER ) return IRC_WriteStrClientPrefix( Client, Client, "TOPIC %s :%s", Req->argv[0], Req->argv[1] ); - else return CONNECTED; + if (Client_Type(Client) == CLIENT_USER) + return IRC_WriteStrClientPrefix(Client, Client, "TOPIC %s :%s", + Req->argv[0], Req->argv[1]); + else + return CONNECTED; } /* IRC_TOPIC */ diff --git a/src/ngircd/irc-info.c b/src/ngircd/irc-info.c index 34198bf3..ee60566e 100644 --- a/src/ngircd/irc-info.c +++ b/src/ngircd/irc-info.c @@ -932,7 +932,14 @@ IRC_WHOIS( CLIENT *Client, REQUEST *Req ) cl2chan = Channel_NextChannelOf( c, cl2chan ); /* Secret channel? */ - if( strchr( Channel_Modes( chan ), 's' ) && ! Channel_IsMemberOf( chan, Client )) continue; + if (strchr(Channel_Modes(chan), 's') + && !Channel_IsMemberOf(chan, Client)) + continue; + + /* Local channel and request is not from a user? */ + if (Client_Type(Client) == CLIENT_SERVER + && Channel_IsLocal(chan)) + continue; /* Concatenate channel names */ if( str[strlen( str ) - 1] != ':' ) strlcat( str, " ", sizeof( str )); diff --git a/src/ngircd/irc-mode.c b/src/ngircd/irc-mode.c index 76e3ab46..ed70a9bb 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-2005 Alexander Barton (alex@barton.de) + * Copyright (c)2001-2008 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 @@ -558,7 +558,15 @@ chan_exit: the_modes[len] = '\0'; if (Client_Type(Client) == CLIENT_SERVER) { - /* Forward mode changes to channel users and other servers */ + /* MODE requests for local channels from other servers + * are definitely invalid! */ + if (Channel_IsLocal(Channel)) { + Log(LOG_ALERT, "Got remote MODE command for local channel!? Ignored."); + return CONNECTED; + } + + /* Forward mode changes to channel users and all the + * other remote servers: */ IRC_WriteStrServersPrefix(Client, Origin, "MODE %s %s%s", Channel_Name( Channel ), the_modes, the_args); IRC_WriteStrChannelPrefix(Client, Channel, Origin, false, "MODE %s %s%s", Channel_Name(Channel), the_modes, the_args); } else { @@ -567,10 +575,14 @@ chan_exit: /* Send reply to client and inform other servers and channel users */ ok = IRC_WriteStrClientPrefix(Client, Origin, "MODE %s %s%s", Channel_Name(Channel), the_modes, the_args); - IRC_WriteStrServersPrefix(Client, Origin, "MODE %s %s%s", - Channel_Name(Channel), the_modes, the_args); - IRC_WriteStrChannelPrefix(Client, Channel, Origin, false, "MODE %s %s%s", - Channel_Name(Channel), the_modes, the_args); + /* Only forward requests for non-local channels */ + if (!Channel_IsLocal(Channel)) + IRC_WriteStrServersPrefix(Client, Origin, + "MODE %s %s%s", Channel_Name(Channel), + the_modes, the_args); + IRC_WriteStrChannelPrefix(Client, Channel, Origin, + false, "MODE %s %s%s", Channel_Name(Channel), + the_modes, the_args); } } diff --git a/src/ngircd/messages.h b/src/ngircd/messages.h index 36d6f48e..d6a92c96 100644 --- a/src/ngircd/messages.h +++ b/src/ngircd/messages.h @@ -1,6 +1,6 @@ /* * ngIRCd -- The Next Generation IRC Daemon - * Copyright (c)2001-2004 Alexander Barton + * Copyright (c)2001-2008 Alexander Barton * * 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 @@ -8,8 +8,6 @@ * (at your option) any later version. * Please read the file COPYING, README and AUTHORS for more information. * - * $Id: messages.h,v 1.75 2008/02/17 13:26:42 alex Exp $ - * * IRC numerics (Header) */ @@ -22,7 +20,7 @@ #define RPL_YOURHOST_MSG "002 %s :Your host is %s, running version ngircd-%s (%s/%s/%s)" #define RPL_CREATED_MSG "003 %s :This server has been started %s" #define RPL_MYINFO_MSG "004 %s %s ngircd-%s %s %s" -#define RPL_ISUPPORT1_MSG "005 %s RFC2812 CASEMAPPING=ascii PREFIX=(ov)@+ CHANTYPES=# CHANMODES=bI,k,l,imnPst CHANLIMIT=#:%d :are supported on this server" +#define RPL_ISUPPORT1_MSG "005 %s RFC2812 CASEMAPPING=ascii PREFIX=(ov)@+ CHANTYPES=#&+ CHANMODES=bI,k,l,imnPst CHANLIMIT=#&+:%d :are supported on this server" #define RPL_ISUPPORT2_MSG "005 %s CHANNELLEN=%d NICKLEN=%d TOPICLEN=%d AWAYLEN=%d KICKLEN=%d PENALTY :are supported on this server" #define RPL_TRACELINK_MSG "200 %s Link %s-%s %s %s V%s %ld %d %d" diff --git a/src/ngircd/numeric.c b/src/ngircd/numeric.c index fa32097d..74c5c12b 100644 --- a/src/ngircd/numeric.c +++ b/src/ngircd/numeric.c @@ -341,6 +341,10 @@ IRC_Num_ENDOFMOTD(CLIENT * Client, UNUSED REQUEST * Req) /* Announce all channels to the new server */ chan = Channel_First(); while (chan) { + if (Channel_IsLocal(chan)) { + chan = Channel_Next(chan); + continue; + } #ifdef IRCPLUS /* Send CHANINFO if the peer supports it */ if (strchr(Client_Flags(Client), 'C')) { -- 2.39.2