/*
* ngIRCd -- The Next Generation IRC Daemon
- * Copyright (c)2001-2009 Alexander Barton (alex@barton.de)
+ * Copyright (c)2001-2012 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
* 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.
- *
- * Channel management
*/
-
#define __channel_c__
-
#include "portab.h"
+/**
+ * @file
+ * Channel management
+ */
+
#include "imp.h"
#include <assert.h>
#include <stdlib.h>
}
+GLOBAL struct list_head *
+Channel_GetListExcepts(CHANNEL *c)
+{
+ assert(c != NULL);
+ return &c->list_excepts;
+}
+
+
GLOBAL struct list_head *
Channel_GetListInvites(CHANNEL *c)
{
assert(channel_count == 0 || conf_chan != NULL);
for (i = 0; i < channel_count; i++, conf_chan++) {
- if (!conf_chan->name[0] || !Channel_IsValidName(conf_chan->name)) {
- Log(LOG_ERR, "Can't create pre-defined channel: invalid name: \"%s\"",
- conf_chan->name);
+ if (!conf_chan->name[0])
+ continue;
+ if (!Channel_IsValidName(conf_chan->name)) {
+ Log(LOG_ERR,
+ "Can't create pre-defined channel: invalid name: \"%s\"",
+ conf_chan->name);
continue;
}
array_free(&chan->topic);
array_free(&chan->keyfile);
Lists_Free(&chan->list_bans);
+ Lists_Free(&chan->list_excepts);
Lists_Free(&chan->list_invites);
free(chan);
return false;
}
+ if (Conf_MorePrivacy)
+ Reason = "";
+
/* Part client from channel */
if (!Remove_Client(REMOVE_PART, chan, Client, Origin, Reason, true))
return false;
assert( Client != NULL );
assert( Reason != NULL );
+ if (Conf_MorePrivacy)
+ Reason = "";
+
IRC_WriteStrRelatedPrefix( Client, Client, false, "QUIT :%s", Reason );
c = My_Channels;
} /* Channel_Quit */
+/**
+ * Get number of channels this server knows and that are "visible" to
+ * the given client. If no client is given, all channels will be counted.
+ *
+ * @param Client The client to check or NULL.
+ * @return Number of channels visible to the client.
+ */
GLOBAL unsigned long
-Channel_Count( void )
+Channel_CountVisible (CLIENT *Client)
{
CHANNEL *c;
unsigned long count = 0;
c = My_Channels;
- while( c )
- {
- count++;
+ while(c) {
+ if (Client) {
+ if (!strchr(Channel_Modes(c), 's')
+ || Channel_IsMemberOf(c, Client))
+ count++;
+ } else
+ count++;
c = c->next;
}
return count;
-} /* Channel_Count */
+}
GLOBAL unsigned long
} /* Channel_SetMaxUsers */
+/**
+ * Check if a client is allowed to send to a specific channel.
+ *
+ * @param Chan The channel to check.
+ * @param From The client that wants to send.
+ * @return true if the client is allowed to send, false otherwise.
+ */
static bool
Can_Send_To_Channel(CHANNEL *Chan, CLIENT *From)
{
if (strchr(Channel_Modes(Chan), 'm'))
return false;
+ if (Lists_Check(&Chan->list_excepts, From))
+ return true;
+
return !Lists_Check(&Chan->list_bans, From);
}
Client_Mask( Client ), c->name, Client_ID(Origin), Reason);
break;
default: /* PART */
+ if (Conf_MorePrivacy)
+ Reason = "";
+
if (InformServer)
IRC_WriteStrServersPrefix(Origin, Client, "PART %s :%s", c->name, Reason);
Channel_AddBan(CHANNEL *c, const char *mask )
{
struct list_head *h = Channel_GetListBans(c);
- return Lists_Add(h, mask, false);
+ LogDebug("Adding \"%s\" to \"%s\" ban list", mask, Channel_Name(c));
+ return Lists_Add(h, mask, false, NULL);
+}
+
+
+GLOBAL bool
+Channel_AddExcept(CHANNEL *c, const char *mask )
+{
+ 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);
}
Channel_AddInvite(CHANNEL *c, const char *mask, bool onlyonce)
{
struct list_head *h = Channel_GetListInvites(c);
- return Lists_Add(h, mask, onlyonce);
+ LogDebug("Adding \"%s\" to \"%s\" invite list", mask, Channel_Name(c));
+ return Lists_Add(h, mask, onlyonce, NULL);
}
static bool
-ShowInvitesBans(struct list_head *head, CLIENT *Client, CHANNEL *Channel, bool invite)
+ShowChannelList(struct list_head *head, CLIENT *Client, CHANNEL *Channel,
+ char *msg, char *msg_end)
{
struct list_elem *e;
- char *msg = invite ? RPL_INVITELIST_MSG : RPL_BANLIST_MSG;
- char *msg_end;
- assert( Client != NULL );
- assert( Channel != NULL );
+ assert (Client != NULL);
+ assert (Channel != NULL);
e = Lists_GetFirst(head);
while (e) {
- if( ! IRC_WriteStrClient( Client, msg, Client_ID( Client ),
- Channel_Name( Channel ), Lists_GetMask(e) )) return DISCONNECTED;
+ if (!IRC_WriteStrClient(Client, msg, Client_ID(Client),
+ Channel_Name(Channel),
+ Lists_GetMask(e)))
+ return DISCONNECTED;
e = Lists_GetNext(e);
}
- msg_end = invite ? RPL_ENDOFINVITELIST_MSG : RPL_ENDOFBANLIST_MSG;
- return IRC_WriteStrClient( Client, msg_end, Client_ID( Client ), Channel_Name( Channel ));
+ return IRC_WriteStrClient(Client, msg_end, Client_ID(Client),
+ Channel_Name(Channel));
}
assert( Channel != NULL );
h = Channel_GetListBans(Channel);
- return ShowInvitesBans(h, Client, Channel, false);
+ return ShowChannelList(h, Client, Channel, RPL_BANLIST_MSG,
+ RPL_ENDOFBANLIST_MSG);
+}
+
+
+GLOBAL bool
+Channel_ShowExcepts( CLIENT *Client, CHANNEL *Channel )
+{
+ struct list_head *h;
+
+ assert( Channel != NULL );
+
+ h = Channel_GetListExcepts(Channel);
+ return ShowChannelList(h, Client, Channel, RPL_EXCEPTLIST_MSG,
+ RPL_ENDOFEXCEPTLIST_MSG);
}
assert( Channel != NULL );
h = Channel_GetListInvites(Channel);
- return ShowInvitesBans(h, Client, Channel, true);
+ return ShowChannelList(h, Client, Channel, RPL_INVITELIST_MSG,
+ RPL_ENDOFINVITELIST_MSG);
}
if (!strchr(Chan->modes, 'k'))
return true;
- if (strcmp(Chan->key, Key) == 0)
- return true;
if (*Key == '\0')
return false;
+ if (strcmp(Chan->key, Key) == 0)
+ return true;
file_name = array_start(&Chan->keyfile);
if (!file_name)
} /* Channel_CheckKey */
+/**
+ * Check wether a client is allowed to administer a channel or not.
+ *
+ * @param Chan The channel to test.
+ * @param Client The client from which the command has been received.
+ * @param Origin The originator of the command (or NULL).
+ * @param OnChannel Set to true if the originator is member of the channel.
+ * @param AdminOk Set to true if the client is allowed to do
+ * administrative tasks on this channel.
+ * @param UseServerMode Set to true if ngIRCd should emulate "server mode",
+ * that is send commands as if originating from a server
+ * and not the originator of the command.
+ */
+GLOBAL void
+Channel_CheckAdminRights(CHANNEL *Chan, CLIENT *Client, CLIENT *Origin,
+ bool *OnChannel, bool *AdminOk, bool *UseServerMode)
+{
+ assert (Chan != NULL);
+ assert (Client != NULL);
+ assert (OnChannel != NULL);
+ assert (AdminOk != NULL);
+ assert (UseServerMode != NULL);
+
+ /* Use the client as origin, if no origin has been given (no prefix?) */
+ if (!Origin)
+ Origin = Client;
+
+ *OnChannel = false;
+ *AdminOk = false;
+ *UseServerMode = false;
+
+ if (Client_Type(Client) != CLIENT_USER
+ && Client_Type(Client) != CLIENT_SERVER
+ && Client_Type(Client) != CLIENT_SERVICE)
+ return;
+
+ /* Allow channel administration if the client is a server or service */
+ if (Client_Type(Client) != CLIENT_USER) {
+ *AdminOk = true;
+ return;
+ }
+
+ *OnChannel = Channel_IsMemberOf(Chan, Origin);
+
+ if (*OnChannel && strchr(Channel_UserModes(Chan, Origin), 'o')) {
+ /* User is a channel operator */
+ *AdminOk = true;
+ } else if (Conf_OperCanMode) {
+ /* IRC operators are allowed to administer channels as well */
+ if (Client_OperByMe(Origin)) {
+ *AdminOk = true;
+ if (Conf_OperServerMode)
+ *UseServerMode = true;
+ }
+ }
+} /* Channel_CheckAdminRights */
+
+
static CL2CHAN *
Get_First_Cl2Chan( CLIENT *Client, CHANNEL *Chan )
{