/* Channel-handling routines.
*
* (C) 2003-2005 Anope Team
* Contact us at info@anope.org
*
* Please read COPYING and README for further details.
*
* Based on the original code of Epona by Lara.
* Based on the original code of Services by Andy Church.
*
* $Id$
*
*/
#include "services.h"
#include "language.h"
Channel *chanlist[1024];
#define HASH(chan) ((chan)[1] ? ((chan)[1]&31)<<5 | ((chan)[2]&31) : 0)
void add_ban(Channel * chan, char *mask);
void add_exception(Channel * chan, char *mask);
void add_invite(Channel * chan, char *mask);
void chan_adduser2(User * user, Channel * c);
Channel *chan_create(char *chan);
void chan_delete(Channel * c);
void del_ban(Channel * chan, char *mask);
void del_exception(Channel * chan, char *mask);
void del_invite(Channel * chan, char *mask);
char *get_flood(Channel * chan);
char *get_key(Channel * chan);
char *get_limit(Channel * chan);
char *get_redirect(Channel * chan);
Channel *join_user_update(User * user, Channel * chan, char *name);
void set_flood(Channel * chan, char *value);
void set_key(Channel * chan, char *value);
void set_limit(Channel * chan, char *value);
void set_redirect(Channel * chan, char *value);
void do_mass_mode(char *modes);
/**************************** External Calls *****************************/
/*************************************************************************/
void chan_deluser(User * user, Channel * c)
{
struct c_userlist *u;
if (c->ci)
update_cs_lastseen(user, c->ci);
for (u = c->users; u && u->user != user; u = u->next);
if (!u)
return;
if (u->ud) {
if (u->ud->lastline)
free(u->ud->lastline);
free(u->ud);
}
if (u->next)
u->next->prev = u->prev;
if (u->prev)
u->prev->next = u->next;
else
c->users = u->next;
free(u);
c->usercount--;
if (s_BotServ && c->ci && c->ci->bi && c->usercount == BSMinUsers - 1) {
anope_cmd_part(c->ci->bi->nick, c->name, NULL);
}
if (!c->users)
chan_delete(c);
}
/*************************************************************************/
/* Returns a fully featured binary modes string. If complete is 0, the
* eventual parameters won't be added to the string.
*/
char *chan_get_modes(Channel * chan, int complete, int plus)
{
static char res[BUFSIZE];
char *end = res;
if (chan->mode) {
int n = 0;
CBModeInfo *cbmi = cbmodeinfos;
do {
if (chan->mode & cbmi->flag)
*end++ = cbmi->mode;
} while ((++cbmi)->flag != 0 && ++n < sizeof(res) - 1);
if (complete) {
cbmi = cbmodeinfos;
do {
if (cbmi->getvalue && (chan->mode & cbmi->flag) &&
(plus || !(cbmi->flags & CBM_MINUS_NO_ARG))) {
char *value = cbmi->getvalue(chan);
if (value) {
*end++ = ' ';
while (*value)
*end++ = *value++;
}
}
} while ((++cbmi)->flag != 0 && ++n < sizeof(res) - 1);
}
}
*end = 0;
return res;
}
/*************************************************************************/
/* Retrieves the status of an user on a channel */
int chan_get_user_status(Channel * chan, User * user)
{
struct u_chanlist *uc;
for (uc = user->chans; uc; uc = uc->next)
if (uc->chan == chan)
return uc->status;
return 0;
}
/*************************************************************************/
/* Has the given user the given status on the given channel? :p */
int chan_has_user_status(Channel * chan, User * user, int16 status)
{
struct u_chanlist *uc;
for (uc = user->chans; uc; uc = uc->next) {
if (uc->chan == chan) {
if (debug) {
alog("debug: chan_has_user_status wanted %d the user is %d", status, uc->status);
}
return (uc->status & status);
}
}
return 0;
}
/*************************************************************************/
/* Remove the status of an user on a channel */
void chan_remove_user_status(Channel * chan, User * user, int16 status)
{
struct u_chanlist *uc;
for (uc = user->chans; uc; uc = uc->next) {
if (uc->chan == chan) {
uc->status &= ~status;
break;
}
}
}
/*************************************************************************/
void chan_set_modes(const char *source, Channel * chan, int ac, char **av,
int check)
{
int add = 1;
int servermode = !!strchr(source, '.');
char *modes = av[0], mode;
CBMode *cbm;
CMMode *cmm;
CUMode *cum;
unsigned char botmode = 0;
BotInfo *bi;
if (debug)
alog("debug: Changing modes for %s to %s", chan->name,
merge_args(ac, av));
ac--;
while ((mode = *modes++)) {
switch (mode) {
case '+':
add = 1;
continue;
case '-':
add = 0;
continue;
}
if (((int) mode) < 0) {
if (debug)
alog("Debug: Malformed mode detected on %s.", chan->name);
continue;
}
if ((cum = &cumodes[(int) mode])->status != 0) {
User *user;
if (ac == 0) {
alog("channel: mode %c%c with no parameter (?) for channel %s", add ? '+' : '-', mode, chan->name);
continue;
}
ac--;
av++;
if ((cum->flags & CUF_PROTECT_BOTSERV) && !add) {
if ((bi = findbot(*av))) {
if (!botmode || botmode != mode) {
anope_cmd_mode(bi->nick, chan->name, "+%c %s",
mode, bi->nick);
botmode = mode;
continue;
} else {
botmode = mode;
continue;
}
}
} else {
if ((bi = findbot(*av))) {
continue;
}
}
if (!(user = finduser(*av))) {
alog(
|