/*
* ngIRCd -- The Next Generation IRC Daemon
- * Copyright (c)2001-2008 Alexander Barton (alex@barton.de)
+ * Copyright (c)2001-2010 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
* Please read the file COPYING, README and AUTHORS for more information.
- *
- * IRC channel commands
*/
-
#include "portab.h"
+/**
+ * @file
+ * IRC channel commands
+ */
+
#include "imp.h"
#include <assert.h>
#include <stdlib.h>
#include "defines.h"
#include "conn.h"
-#include "client.h"
#include "channel.h"
#include "conn-func.h"
#include "lists.h"
#include "parse.h"
#include "irc-info.h"
#include "irc-write.h"
-#include "resolve.h"
#include "conf.h"
#include "exp.h"
}
+/**
+ * Check weather a local client is allowed to join an already existing
+ * channel or not.
+ * @param Client Client that sent the JOIN command
+ * @param chan Channel to check
+ * @param channame Name of the channel
+ * @param key Provided channel key (or NULL if none has been provided)
+ * @return true if client is allowed to join channel, false otherwise
+ */
static bool
-join_allowed(CLIENT *Client, CLIENT *target, CHANNEL *chan,
- const char *channame, const char *key)
+join_allowed(CLIENT *Client, CHANNEL *chan, const char *channame,
+ const char *key)
{
bool is_invited, is_banned;
const char *channel_modes;
if (strchr(Client_Modes(Client), 'o'))
return true;
- is_banned = Lists_Check(Channel_GetListBans(chan), target);
- is_invited = Lists_Check(Channel_GetListInvites(chan), target);
+ is_banned = Lists_Check(Channel_GetListBans(chan), Client);
+ is_invited = Lists_Check(Channel_GetListInvites(chan), Client);
if (is_banned && !is_invited) {
- IRC_WriteStrClient(Client, ERR_BANNEDFROMCHAN_MSG, Client_ID(Client), channame);
+ /* Client is banned from channel (and not on invite list) */
+ IRC_WriteStrClient(Client, ERR_BANNEDFROMCHAN_MSG,
+ Client_ID(Client), channame);
return false;
}
channel_modes = Channel_Modes(chan);
- if ((strchr(channel_modes, 'i')) && !is_invited) {
- /* Channel is "invite-only" (and Client wasn't invited) */
- IRC_WriteStrClient(Client, ERR_INVITEONLYCHAN_MSG, Client_ID(Client), channame);
+ if (strchr(channel_modes, 'i') && !is_invited) {
+ /* Channel is "invite-only" and client is not on invite list */
+ IRC_WriteStrClient(Client, ERR_INVITEONLYCHAN_MSG,
+ Client_ID(Client), channame);
return false;
}
- /* Is the channel protected by a key? */
- if (!Channel_CheckKey(chan, target, key ? key : "")) {
+ if (!Channel_CheckKey(chan, Client, key ? key : "")) {
+ /* Channel is protected by a channel key and the client
+ * didn't specify the correct one */
IRC_WriteStrClient(Client, ERR_BADCHANNELKEY_MSG,
Client_ID(Client), channame);
return false;
}
- /* Are there already too many members? */
- if ((strchr(channel_modes, 'l')) && (Channel_MaxUsers(chan) <= Channel_MemberCount(chan))) {
- IRC_WriteStrClient(Client, ERR_CHANNELISFULL_MSG, Client_ID(Client), channame);
+
+ if (strchr(channel_modes, 'l') &&
+ (Channel_MaxUsers(chan) <= Channel_MemberCount(chan))) {
+ /* There are more clints joined to this channel than allowed */
+ IRC_WriteStrClient(Client, ERR_CHANNELISFULL_MSG,
+ Client_ID(Client), channame);
+ return false;
+ }
+
+ if (strchr(channel_modes, 'z') && !Conn_UsesSSL(Client_Conn(Client))) {
+ /* Only "secure" clients are allowed, but clients doesn't
+ * use SSL encryption */
+ IRC_WriteStrClient(Client, ERR_SECURECHANNEL_MSG,
+ Client_ID(Client), channame);
+ return false;
+ }
+
+ if (strchr(channel_modes, 'O') && !Client_OperByMe(Client)) {
+ /* Only IRC operators are allowed! */
+ IRC_WriteStrClient(Client, ERR_OPONLYCHANNEL_MSG,
+ Client_ID(Client), channame);
return false;
}
+
return true;
}
/* Local client? */
if (Client_Type(Client) == CLIENT_USER) {
- /* Test if the user has reached his maximum channel count */
- if ((Conf_MaxJoins > 0) && (Channel_CountForUser(Client) >= Conf_MaxJoins))
- return IRC_WriteStrClient(Client, ERR_TOOMANYCHANNELS_MSG,
- Client_ID(Client), channame);
- if (!chan) {
- /*
- * New Channel: first user will be channel operator
- * unless this is a modeless channel.
- */
+ /* Test if the user has reached the channel limit */
+ if ((Conf_MaxJoins > 0) &&
+ (Channel_CountForUser(Client) >= Conf_MaxJoins))
+ return IRC_WriteStrClient(Client,
+ ERR_TOOMANYCHANNELS_MSG,
+ Client_ID(Client), channame);
+ if (chan) {
+ /* Already existing channel: check if the
+ * client is allowed to join */
+ if (!join_allowed(Client, chan, channame, key))
+ break;
+ } else {
+ /* New channel: first user will become channel
+ * operator unless this is a modeless channel */
if (*channame != '+')
flags = "o";
- } else
- if (!join_allowed(Client, target, chan, channame, key))
- break;
+ }
/* Local client: update idle time */
Conn_UpdateIdle(Client_Conn(Client));
* that the "one shot" entries (generated by INVITE
* commands) in this list become deleted when a user
* joins a channel this way. */
- if (chan) (void)Lists_Check(Channel_GetListInvites(chan), target);
+ if (chan)
+ (void)Lists_Check(Channel_GetListInvites(chan),
+ target);
}
/* Join channel (and create channel if it doesn't exist) */
if (!chan) { /* channel is new; it has been created above */
chan = Channel_Search(channame);
assert(chan != NULL);
- if (*channame == '+') { /* modeless channel... */
+ if (Channel_IsModeless(chan)) {
Channel_ModeAdd(chan, 't'); /* /TOPIC not allowed */
Channel_ModeAdd(chan, 'n'); /* no external msgs */
}
CHANNEL *chan;
CLIENT *from;
char *topic;
- bool r;
+ bool onchannel, topicok, use_servermode, r;
assert( Client != NULL );
assert( Req != NULL );
- if ((Req->argc < 1) || (Req->argc > 2))
- return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG, Client_ID(Client), Req->command);
+ if (Req->argc < 1 || Req->argc > 2)
+ return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG,
+ Client_ID(Client), Req->command);
- if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_Search( Req->prefix );
- else from = Client;
- if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
+ if (Client_Type(Client) == CLIENT_SERVER)
+ from = Client_Search(Req->prefix);
+ else
+ from = Client;
- /* Welcher Channel? */
- chan = Channel_Search( Req->argv[0] );
- if( ! chan ) return IRC_WriteStrClient( from, ERR_NOSUCHCHANNEL_MSG, Client_ID( from ), Req->argv[0] );
+ if (!from)
+ return IRC_WriteStrClient(Client, ERR_NOSUCHNICK_MSG,
+ Client_ID(Client), Req->prefix);
- /* Ist der User Mitglied in dem Channel? */
- if( ! Channel_IsMemberOf( chan, from )) return IRC_WriteStrClient( from, ERR_NOTONCHANNEL_MSG, Client_ID( from ), Req->argv[0] );
+ chan = Channel_Search(Req->argv[0]);
+ if (!chan)
+ return IRC_WriteStrClient(from, ERR_NOSUCHCHANNEL_MSG,
+ Client_ID(from), Req->argv[0]);
- if( Req->argc == 1 )
- {
+ Channel_CheckAdminRights(chan, Client, from,
+ &onchannel, &topicok, &use_servermode);
+
+ if (!onchannel && !topicok)
+ return IRC_WriteStrClient(from, ERR_NOTONCHANNEL_MSG,
+ Client_ID(from), Req->argv[0]);
+
+ if (Req->argc == 1) {
/* Request actual topic */
topic = Channel_Topic(chan);
if (*topic) {
r = IRC_WriteStrClient(from, RPL_TOPIC_MSG,
- Client_ID(Client), Channel_Name(chan), topic);
+ Client_ID(Client),
+ Channel_Name(chan), topic);
#ifndef STRICT_RFC
r = IRC_WriteStrClient(from, RPL_TOPICSETBY_MSG,
- Client_ID(Client), Channel_Name(chan),
- Channel_TopicWho(chan),
- Channel_TopicTime(chan));
+ Client_ID(Client),
+ Channel_Name(chan),
+ Channel_TopicWho(chan),
+ Channel_TopicTime(chan));
#endif
return r;
}
else
- return IRC_WriteStrClient(from, RPL_NOTOPIC_MSG,
- Client_ID(from), Channel_Name(chan));
+ return IRC_WriteStrClient(from, RPL_NOTOPIC_MSG,
+ Client_ID(from),
+ Channel_Name(chan));
}
- if( strchr( Channel_Modes( chan ), 't' ))
- {
- /* Topic Lock. Ist der User ein Channel Operator? */
- if( ! strchr( Channel_UserModes( chan, from ), 'o' )) return IRC_WriteStrClient( from, ERR_CHANOPRIVSNEEDED_MSG, Client_ID( from ), Channel_Name( chan ));
+ if (strchr(Channel_Modes(chan), 't')) {
+ /* Topic Lock. Is the user a channel or IRC operator? */
+ if (!topicok)
+ return IRC_WriteStrClient(from, ERR_CHANOPRIVSNEEDED_MSG,
+ Client_ID(from),
+ Channel_Name(chan));
}
/* Set new topic */
Client_TypeText(from), Client_Mask(from), Channel_Name(chan),
Req->argv[1][0] ? Req->argv[1] : "<none>");
+ if (use_servermode)
+ from = Client_ThisServer();
+
/* Update channel and forward new topic to other servers */
if (!Channel_IsLocal(chan))
IRC_WriteStrServersPrefix(Client, from, "TOPIC %s :%s",