X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?p=ngircd-alex.git;a=blobdiff_plain;f=src%2Fngircd%2Fchannel.c;h=3282a8d0460533301ca0c4f58675548fa35db833;hp=06b88bae1db7404693df44b298a897b8c31c55cc;hb=0dc692b1f77a147d9d5bf63c1eb7889a239420b4;hpb=08d49a8fa02ef11b22d611d11c595812ce207ac8 diff --git a/src/ngircd/channel.c b/src/ngircd/channel.c index 06b88bae..3282a8d0 100644 --- a/src/ngircd/channel.c +++ b/src/ngircd/channel.c @@ -1,6 +1,6 @@ /* * ngIRCd -- The Next Generation IRC Daemon - * Copyright (c)2001-2012 Alexander Barton (alex@barton.de) and Contributors. + * Copyright (c)2001-2014 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 @@ -18,41 +18,34 @@ * Channel management */ -#include "imp.h" #include #include #include #include #include #include +#include -#include "defines.h" #include "conn-func.h" -#include "exp.h" #include "channel.h" -#include "imp.h" #include "irc-write.h" #include "conf.h" #include "hash.h" -#include "lists.h" #include "log.h" #include "messages.h" #include "match.h" - -#include "exp.h" - +#include "parse.h" +#include "irc-mode.h" #define REMOVE_PART 0 #define REMOVE_QUIT 1 #define REMOVE_KICK 2 - static CHANNEL *My_Channels; static CL2CHAN *My_Cl2Chan; - static CL2CHAN *Get_Cl2Chan PARAMS(( CHANNEL *Chan, CLIENT *Client )); static CL2CHAN *Add_Client PARAMS(( CHANNEL *Chan, CLIENT *Client )); static bool Remove_Client PARAMS(( int Type, CHANNEL *Chan, CLIENT *Client, CLIENT *Origin, const char *Reason, bool InformServer )); @@ -102,9 +95,11 @@ GLOBAL void Channel_InitPredefined( void ) { CHANNEL *new_chan; + REQUEST Req; const struct Conf_Channel *conf_chan; - const char *c; - size_t i, channel_count = array_length(&Conf_Channels, sizeof(*conf_chan)); + char *c; + char modes[COMMAND_LEN], name[CHANNEL_NAME_LEN]; + size_t i, n, channel_count = array_length(&Conf_Channels, sizeof(*conf_chan)); conf_chan = array_start(&Conf_Channels); @@ -135,21 +130,61 @@ Channel_InitPredefined( void ) conf_chan->name); continue; } - Log(LOG_INFO, "Created pre-defined channel \"%s\".", - conf_chan->name); - Channel_ModeAdd(new_chan, 'P'); if (conf_chan->topic[0]) Channel_SetTopic(new_chan, NULL, conf_chan->topic); - c = conf_chan->modes; - while (*c) - Channel_ModeAdd(new_chan, *c++); + /* Evaluate modes strings with fake requests */ + if (conf_chan->modes_num) { + /* Prepare fake request structure */ + strlcpy(name, conf_chan->name, sizeof(name)); + Log(LOG_INFO, "Evaluating predefined channel modes for \"%s\".", name); + Req.argv[0] = name; + Req.prefix = Client_ID(Client_ThisServer()); + Req.command = "MODE"; + + /* Iterate over channel modes strings */ + 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); + c = strtok(modes, " "); + while (c && Req.argc < 15) { + Req.argv[Req.argc++] = c; + c = strtok(0, " "); + } + + if (Req.argc > 1) { + /* Handling of legacy "Key" and "MaxUsers" settings: + * Enforce setting the respective mode(s), to support + * the legacy "Mode = kl" notation, which was valid but + * is an invalid MODE string: key and limit are missing! + * So set them manually when "k" or "l" are detected in + * the first MODE parameter ... */ + if (Req.argc > 1 && strchr(Req.argv[1], 'k')) { + Channel_SetKey(new_chan, conf_chan->key); + Channel_ModeAdd(new_chan, 'k'); + } + if (strchr(Req.argv[1], 'l')) { + Channel_SetMaxUsers(new_chan, conf_chan->maxusers); + Channel_ModeAdd(new_chan, 'l'); + } + + IRC_MODE(Client_ThisServer(), &Req); + } + + /* Original channel modes srings are no longer needed */ + free(conf_chan->modes[n]); + } + } - Channel_SetKey(new_chan, conf_chan->key); - Channel_SetMaxUsers(new_chan, conf_chan->maxusers); Set_KeyFile(new_chan, conf_chan->keyfile); + + Log(LOG_INFO, + "Created pre-defined channel \"%s\", mode \"%s\" (key \"%s\", limit %d).", + new_chan->name, new_chan->modes, new_chan->key, + new_chan->maxusers); } if (channel_count) array_free(&Conf_Channels); @@ -223,7 +258,7 @@ Channel_Join( CLIENT *Client, const char *Name ) /* Check that the channel name is valid */ if (! Channel_IsValidName(Name)) { - IRC_WriteStrClient(Client, ERR_NOSUCHCHANNEL_MSG, + IRC_WriteErrClient(Client, ERR_NOSUCHCHANNEL_MSG, Client_ID(Client), Name); return false; } @@ -268,14 +303,14 @@ Channel_Part(CLIENT * Client, CLIENT * Origin, const char *Name, const char *Rea /* Check that specified channel exists */ chan = Channel_Search(Name); if (!chan) { - IRC_WriteStrClient(Client, ERR_NOSUCHCHANNEL_MSG, + IRC_WriteErrClient(Client, ERR_NOSUCHCHANNEL_MSG, Client_ID(Client), Name); return false; } /* Check that the client is in the channel */ if (!Get_Cl2Chan(chan, Client)) { - IRC_WriteStrClient(Client, ERR_NOTONCHANNEL_MSG, + IRC_WriteErrClient(Client, ERR_NOTONCHANNEL_MSG, Client_ID(Client), Name); return false; } @@ -309,9 +344,9 @@ Channel_Kick(CLIENT *Peer, CLIENT *Target, CLIENT *Origin, const char *Name, /* Check that channel exists */ chan = Channel_Search( Name ); - if( ! chan ) - { - IRC_WriteStrClient( Origin, ERR_NOSUCHCHANNEL_MSG, Client_ID( Origin ), Name ); + if (!chan) { + IRC_WriteErrClient(Origin, ERR_NOSUCHCHANNEL_MSG, + Client_ID(Origin), Name); return; } @@ -319,15 +354,15 @@ Channel_Kick(CLIENT *Peer, CLIENT *Target, CLIENT *Origin, const char *Name, Client_Type(Origin) != CLIENT_SERVICE) { /* Check that user is on the specified channel */ if (!Channel_IsMemberOf(chan, Origin)) { - IRC_WriteStrClient( Origin, ERR_NOTONCHANNEL_MSG, - Client_ID(Origin), Name); + IRC_WriteErrClient(Origin, ERR_NOTONCHANNEL_MSG, + Client_ID(Origin), Name); return; } } /* Check that the client to be kicked is on the specified channel */ if (!Channel_IsMemberOf(chan, Target)) { - IRC_WriteStrClient(Origin, ERR_USERNOTINCHANNEL_MSG, + IRC_WriteErrClient(Origin, ERR_USERNOTINCHANNEL_MSG, Client_ID(Origin), Client_ID(Target), Name ); return; } @@ -339,7 +374,7 @@ Channel_Kick(CLIENT *Peer, CLIENT *Target, CLIENT *Origin, const char *Name, || Client_HasMode(Target, 'q') || Client_Type(Target) == CLIENT_SERVICE) && !Client_HasMode(Origin, 'o')) { - IRC_WriteStrClient(Origin, ERR_KICKDENY_MSG, + IRC_WriteErrClient(Origin, ERR_KICKDENY_MSG, Client_ID(Origin), Name, Client_ID(Target)); return; @@ -361,17 +396,22 @@ Channel_Kick(CLIENT *Peer, CLIENT *Target, CLIENT *Origin, const char *Name, !Channel_UserHasMode(chan, Target, 'q') && !Channel_UserHasMode(chan, Target, 'a')) can_kick = true; - - /* Half Op can't kick owner | admin | op */ + + /* Half Op can't kick owner | admin | op */ else if (Channel_UserHasMode(chan, Peer, 'h') && !Channel_UserHasMode(chan, Target, 'q') && !Channel_UserHasMode(chan, Target, 'a') && !Channel_UserHasMode(chan, Target, 'o')) can_kick = true; + /* IRC operators & IRCd with OperCanMode enabled + * can kick anyways regardless of privilege */ + else if(Client_HasMode(Origin, 'o') && Conf_OperCanMode) + can_kick = true; + if(!can_kick) { - IRC_WriteStrClient(Origin, ERR_CHANOPPRIVTOOLOW_MSG, - Client_ID(Origin), Name); + IRC_WriteErrClient(Origin, ERR_CHANOPPRIVTOOLOW_MSG, + Client_ID(Origin), Name); return; } } @@ -921,10 +961,10 @@ Channel_Write(CHANNEL *Chan, CLIENT *From, CLIENT *Client, const char *Command, if (! SendErrors) return CONNECTED; /* no error, see RFC 2812 */ if (Channel_HasMode(Chan, 'M')) - return IRC_WriteStrClient(From, ERR_NEEDREGGEDNICK_MSG, + return IRC_WriteErrClient(From, ERR_NEEDREGGEDNICK_MSG, Client_ID(From), Channel_Name(Chan)); else - return IRC_WriteStrClient(From, ERR_CANNOTSENDTOCHAN_MSG, + return IRC_WriteErrClient(From, ERR_CANNOTSENDTOCHAN_MSG, Client_ID(From), Channel_Name(Chan)); } @@ -1048,7 +1088,7 @@ Remove_Client( int Type, CHANNEL *Chan, CLIENT *Client, CLIENT *Origin, const ch switch( Type ) { case REMOVE_QUIT: - /* QUIT: other servers have already been notified, + /* QUIT: other servers have already been notified, * see Client_Destroy(); so only inform other clients * in same channel. */ assert( InformServer == false ); @@ -1102,29 +1142,29 @@ Remove_Client( int Type, CHANNEL *Chan, CLIENT *Client, CLIENT *Origin, const ch GLOBAL bool -Channel_AddBan(CHANNEL *c, const char *mask ) +Channel_AddBan(CHANNEL *c, const char *mask, const char *who ) { struct list_head *h = Channel_GetListBans(c); LogDebug("Adding \"%s\" to \"%s\" ban list", mask, Channel_Name(c)); - return Lists_Add(h, mask, false, NULL); + return Lists_Add(h, mask, time(NULL), who, false); } GLOBAL bool -Channel_AddExcept(CHANNEL *c, const char *mask ) +Channel_AddExcept(CHANNEL *c, const char *mask, const char *who ) { struct list_head *h = Channel_GetListExcepts(c); LogDebug("Adding \"%s\" to \"%s\" exception list", mask, Channel_Name(c)); - return Lists_Add(h, mask, false, NULL); + return Lists_Add(h, mask, time(NULL), who, false); } GLOBAL bool -Channel_AddInvite(CHANNEL *c, const char *mask, bool onlyonce) +Channel_AddInvite(CHANNEL *c, const char *mask, bool onlyonce, const char *who ) { struct list_head *h = Channel_GetListInvites(c); LogDebug("Adding \"%s\" to \"%s\" invite list", mask, Channel_Name(c)); - return Lists_Add(h, mask, onlyonce, NULL); + return Lists_Add(h, mask, time(NULL), who, onlyonce); } @@ -1141,7 +1181,9 @@ ShowChannelList(struct list_head *head, CLIENT *Client, CHANNEL *Channel, while (e) { if (!IRC_WriteStrClient(Client, msg, Client_ID(Client), Channel_Name(Channel), - Lists_GetMask(e))) + Lists_GetMask(e), + Lists_GetReason(e), + Lists_GetValidity(e))) return DISCONNECTED; e = Lists_GetNext(e); }