join_allowed(CLIENT *Client, CHANNEL *chan, const char *channame,
const char *key)
{
- bool is_invited, is_banned;
+ bool is_invited, is_banned, is_exception;
const char *channel_modes;
/* Allow IRC operators to overwrite channel limits */
return true;
is_banned = Lists_Check(Channel_GetListBans(chan), Client);
+ is_exception = Lists_Check(Channel_GetListExcepts(chan), Client);
is_invited = Lists_Check(Channel_GetListInvites(chan), Client);
- if (is_banned && !is_invited) {
+ if (is_banned && !is_invited && !is_exception) {
/* Client is banned from channel (and not on invite list) */
IRC_WriteStrClient(Client, ERR_BANNEDFROMCHAN_MSG,
Client_ID(Client), channame);
}
}
- /* If channel persistent and client is ircop: make client chanop */
- if (strchr(Channel_Modes(chan), 'P') && strchr(Client_Modes(target), 'o'))
+ /* If the channel is persistent (+P) and client is an IRC op:
+ * make client chanop, if not disabled in configuration. */
+ if (strchr(Channel_Modes(chan), 'P') && Conf_OperChanPAutoOp
+ && strchr(Client_Modes(target), 'o'))
Channel_UserModeAdd(chan, target, 'o');
} /* join_set_channelmodes */
/* channel must be created, but forbidden by config */
IRC_WriteStrClient(Client, ERR_BANNEDFROMCHAN_MSG,
Client_ID(Client), channame);
- break;
+ goto join_next;
}
/* Local client? */
if (Client_Type(Client) == CLIENT_USER) {
+ if (chan) {
+ /* Already existing channel: already member? */
+ if (Channel_IsMemberOf(chan, Client))
+ goto join_next;
+ }
+
/* Test if the user has reached the channel limit */
if ((Conf_MaxJoins > 0) &&
- (Channel_CountForUser(Client) >= Conf_MaxJoins))
- return IRC_WriteStrClient(Client,
+ (Channel_CountForUser(Client) >= Conf_MaxJoins)) {
+ if (!IRC_WriteStrClient(Client,
ERR_TOOMANYCHANNELS_MSG,
- Client_ID(Client), channame);
+ Client_ID(Client), channame))
+ return DISCONNECTED;
+ goto join_next;
+ }
+
if (chan) {
/* Already existing channel: check if the
* client is allowed to join */
if (!join_allowed(Client, chan, channame, key))
- break;
+ goto join_next;
} else {
/* New channel: first user will become channel
* operator unless this is a modeless channel */
CHANNEL *chan;
CLIENT *from;
char *topic;
- bool onchannel, topicok, use_servermode, r;
+ bool r, is_oper;
assert( Client != NULL );
assert( Req != NULL );
return IRC_WriteStrClient(from, ERR_NOSUCHCHANNEL_MSG,
Client_ID(from), Req->argv[0]);
- Channel_CheckAdminRights(chan, Client, from,
- &onchannel, &topicok, &use_servermode);
-
- if (!onchannel && !topicok)
+ /* Only IRC opers and channel members allowed */
+ is_oper = Client_OperByMe(from);
+ if (!Channel_IsMemberOf(chan, from) && !is_oper)
return IRC_WriteStrClient(from, ERR_NOTONCHANNEL_MSG,
Client_ID(from), Req->argv[0]);
}
if (strchr(Channel_Modes(chan), 't')) {
- /* Topic Lock. Is the user a channel or IRC operator? */
- if (!topicok)
+ /* Topic Lock. Is the user a channel op or IRC operator? */
+ if(!strchr(Channel_UserModes(chan, from), 'h') &&
+ !strchr(Channel_UserModes(chan, from), 'o') &&
+ !strchr(Channel_UserModes(chan, from), 'a') &&
+ !strchr(Channel_UserModes(chan, from), 'q') &&
+ !is_oper)
return IRC_WriteStrClient(from, ERR_CHANOPRIVSNEEDED_MSG,
Client_ID(from),
Channel_Name(chan));
Client_TypeText(from), Client_Mask(from), Channel_Name(chan),
Req->argv[1][0] ? Req->argv[1] : "<none>");
- if (use_servermode)
+ if (Conf_OperServerMode)
from = Client_ThisServer();
/* Update channel and forward new topic to other servers */
/* Target is indeed an other server, forward it! */
return IRC_WriteStrClientPrefix(target, from,
"LIST %s :%s",
- Client_ID(from),
+ Req->argv[0],
Req->argv[1]);
}
}
if (MatchCaseInsensitive(pattern, Channel_Name(chan))) {
/* Gotcha! */
if (!strchr(Channel_Modes(chan), 's')
- || Channel_IsMemberOf(chan, from)) {
+ || Channel_IsMemberOf(chan, from)
+ || (!Conf_MorePrivacy && Client_OperByMe(Client))) {
if (IRC_CheckListTooBig(from, count,
MAX_RPL_LIST,
"LIST"))