/*
* 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
#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 (strchr(channel_modes, 'k') &&
- strcmp(Channel_Key(chan), key ? key : ""))
- {
- IRC_WriteStrClient(Client, ERR_BADCHANNELKEY_MSG, Client_ID(Client), channame);
+ 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;
+ }
+
+ 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;
}
- /* 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, '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;
}
+
return true;
}
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
/* 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 */
}
Client_TypeText(from), Client_Mask(from), Channel_Name(chan),
Req->argv[1][0] ? Req->argv[1] : "<none>");
- /* 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 */