diff options
| author | rob rob@31f1291d-b8d6-0310-a050-a5561fc1590b <rob rob@31f1291d-b8d6-0310-a050-a5561fc1590b@5417fbe8-f217-4b02-8779-1006273d7864> | 2004-07-19 14:08:30 +0000 |
|---|---|---|
| committer | rob rob@31f1291d-b8d6-0310-a050-a5561fc1590b <rob rob@31f1291d-b8d6-0310-a050-a5561fc1590b@5417fbe8-f217-4b02-8779-1006273d7864> | 2004-07-19 14:08:30 +0000 |
| commit | a1479a87757fb5e9b48f3c8bb5dd9cc247406f1a (patch) | |
| tree | 06d23a51082a398c512ed8f1e39bdac60d4dd658 /src/channels.c | |
| parent | 7fffea77edbe72cd66f7a55f41a3966204f9cf86 (diff) | |
BUILD : 1.7.4 (264) BUGS : N/A NOTES : Switched to autoconf - try to commit part 1
git-svn-id: svn://svn.anope.org/anope/trunk@264 31f1291d-b8d6-0310-a050-a5561fc1590b
git-svn-id: http://anope.svn.sourceforge.net/svnroot/anope/trunk@169 5417fbe8-f217-4b02-8779-1006273d7864
Diffstat (limited to 'src/channels.c')
| -rw-r--r-- | src/channels.c | 1633 |
1 files changed, 1633 insertions, 0 deletions
diff --git a/src/channels.c b/src/channels.c new file mode 100644 index 000000000..9fff738b4 --- /dev/null +++ b/src/channels.c @@ -0,0 +1,1633 @@ +/* Channel-handling routines. + * + * (C) 2003 Anope Team + * Contact us at info@anope.org + * + * Please read COPYING and README for furhter 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) + +static void add_ban(Channel * chan, char *mask); +#ifdef HAS_EXCEPT +static void add_exception(Channel * chan, char *mask); +#endif +static void chan_adduser2(User * user, Channel * c); +static Channel *chan_create(const char *chan); +static void chan_delete(Channel * c); +static void del_ban(Channel * chan, char *mask); +#ifdef HAS_EXCEPT +static void del_exception(Channel * chan, char *mask); +#endif +#ifdef HAS_FMODE +static char *get_flood(Channel * chan); +#endif +static char *get_key(Channel * chan); +static char *get_limit(Channel * chan); +#ifdef HAS_LMODE +static char *get_redirect(Channel * chan); +#endif +static Channel *join_user_update(User * user, Channel * chan, char *name); +#ifdef HAS_FMODE +static void set_flood(Channel * chan, char *value); +#endif +static void set_key(Channel * chan, char *value); +static void set_limit(Channel * chan, char *value); +#ifdef HAS_LMODE +static void set_redirect(Channel * chan, char *value); +#endif +void do_mass_mode(char *modes); + +/*************************************************************************/ +/* *INDENT-OFF* */ + +CBMode cbmodes[128] = { + { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, + { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, + { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, + { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, + { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, + { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, + { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, + { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, + { 0 }, +#if defined(IRC_ULTIMATE) || defined(IRC_UNREAL) || defined(IRC_ULTIMATE3) || defined(IRC_RAGE2) + { CMODE_A, CBM_NO_USER_MLOCK, NULL, NULL }, +#else + { 0 }, /* A */ +#endif + { 0 }, /* B */ +#if defined(IRC_UNREAL) || defined(IRC_RAGE2) + { CMODE_C, 0, NULL, NULL }, +#else + { 0 }, /* C */ +#endif + { 0 }, /* D */ + { 0 }, /* E */ + { 0 }, /* F */ +#ifdef IRC_UNREAL + { CMODE_G, 0, NULL, NULL }, + { CMODE_H, CBM_NO_USER_MLOCK, NULL, NULL }, +#else + { 0 }, /* G */ + { 0 }, /* H */ +#endif +#ifdef IRC_ULTIMATE + { CMODE_I }, +#else + { 0 }, /* I */ +#endif + { 0 }, /* J */ +#if defined(IRC_ULTIMATE) || defined(IRC_ULTIMATE3) || defined(IRC_UNREAL) + { CMODE_K, 0, NULL, NULL }, +#else + { 0 }, /* K */ +#endif +#ifdef HAS_LMODE + { CMODE_L, 0, set_redirect, cs_set_redirect }, +#else + { 0 }, /* L */ +#endif +#ifdef IRC_BAHAMUT + { CMODE_M }, +#else + { 0 }, /* M */ +#endif +#if defined (IRC_UNREAL) || defined (IRC_ULTIMATE3) || defined (IRC_PTLINK) || defined(IRC_RAGE2) + { CMODE_N, 0, NULL, NULL }, +#else + { 0 }, /* N */ +#endif +#if defined(IRC_BAHAMUT) || defined(IRC_ULTIMATE) || defined(IRC_UNREAL) || defined(IRC_ULTIMATE3) || defined(IRC_RAGE2) + { CMODE_O, CBM_NO_USER_MLOCK, NULL, NULL }, +#else + { 0 }, /* O */ +#endif + { 0 }, /* P */ +#ifdef IRC_UNREAL + { CMODE_Q, 0, NULL, NULL }, +#else + { 0 }, /* Q */ +#endif +#ifndef IRC_HYBRID + { CMODE_R, 0, NULL, NULL }, /* R */ +#else + { 0 }, +#endif +#if defined(IRC_ULTIMATE) || defined(IRC_UNREAL) || defined (IRC_ULTIMATE3) || defined (IRC_PTLINK) || defined(IRC_RAGE2) + { CMODE_S, 0, NULL, NULL }, +#else + { 0 }, /* S */ +#endif + { 0 }, /* T */ + { 0 }, /* U */ +#ifdef IRC_UNREAL + { CMODE_V, 0, NULL, NULL }, +#else + { 0 }, /* V */ +#endif + { 0 }, /* W */ + { 0 }, /* X */ + { 0 }, /* Y */ + { 0 }, /* Z */ + { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, +#ifdef IRC_HYBRID + { CMODE_a, 0, NULL, NULL }, +#else + { 0 }, /* a */ +#endif + { 0 }, /* b */ +#if defined(IRC_BAHAMUT) || defined(IRC_UNREAL) || defined (IRC_PTLINK) + { CMODE_c, 0, NULL, NULL }, +#else + { 0 }, /* c */ +#endif +#ifdef IRC_PTLINK + { CMODE_d, 0, NULL, NULL }, +#else + { 0 }, /* d */ +#endif + { 0 }, /* e */ +#ifdef HAS_FMODE + { CMODE_f, 0, set_flood, cs_set_flood }, +#else + { 0 }, /* f */ +#endif + { 0 }, /* g */ + { 0 }, /* h */ + { CMODE_i, 0, NULL, NULL }, + { 0 }, /* j */ + { CMODE_k, 0, set_key, cs_set_key }, + { CMODE_l, CBM_MINUS_NO_ARG, set_limit, cs_set_limit }, + { CMODE_m, 0, NULL, NULL }, + { CMODE_n, 0, NULL, NULL }, + { 0 }, /* o */ + { CMODE_p, 0, NULL, NULL }, +#ifdef IRC_PTLINK + { CMODE_q, 0, NULL, NULL }, +#else + { 0 }, /* q */ +#endif +#ifndef IRC_HYBRID + { CMODE_r, CBM_NO_MLOCK, NULL, NULL }, +#else + { 0 }, +#endif + { CMODE_s, 0, NULL, NULL }, + { CMODE_t, 0, NULL, NULL }, +#ifdef IRC_UNREAL + { CMODE_u, 0, NULL, NULL }, +#else + { 0 }, +#endif + { 0 }, /* v */ + { 0 }, /* w */ +#ifdef IRC_ULTIMATE + { CMODE_x }, +#else + { 0 }, /* x */ +#endif + { 0 }, /* y */ +#ifdef IRC_UNREAL + { CMODE_z, 0, NULL, NULL }, +#else + { 0 }, /* z */ +#endif + { 0 }, { 0 }, { 0 }, { 0 } +}; + +CBModeInfo cbmodeinfos[] = { +#if defined(IRC_HYBRID) + { 'a', CMODE_a, 0, NULL, NULL }, +#endif +#if defined(IRC_BAHAMUT) || defined(IRC_UNREAL) || defined(IRC_PTLINK) || defined(IRC_RAGE2) + { 'c', CMODE_c, 0, NULL, NULL }, +#endif +#if defined(IRC_PTLINK) + { 'd', CMODE_d, 0, NULL, NULL }, +#endif +#ifdef HAS_FMODE + { 'f', CMODE_f, 0, get_flood, cs_get_flood }, +#endif + { 'i', CMODE_i, 0, NULL, NULL }, + { 'k', CMODE_k, 0, get_key, cs_get_key }, + { 'l', CMODE_l, CBM_MINUS_NO_ARG, get_limit, cs_get_limit }, + { 'm', CMODE_m, 0, NULL, NULL }, + { 'n', CMODE_n, 0, NULL, NULL }, + { 'p', CMODE_p, 0, NULL, NULL }, +#ifdef IRC_PTLINK + { 'q', CMODE_q, 0, NULL, NULL }, +#endif +#ifndef IRC_HYBRID + { 'r', CMODE_r, 0, NULL, NULL }, +#endif + { 's', CMODE_s, 0, NULL, NULL }, + { 't', CMODE_t, 0, NULL, NULL }, +#ifdef IRC_UNREAL + { 'u', CMODE_u, 0, NULL, NULL }, +#endif +#ifdef IRC_ULTIMATE + { 'x', CMODE_x, 0, NULL, NULL }, +#endif +#ifdef IRC_UNREAL + { 'z', CMODE_z, 0, NULL, NULL }, +#endif +#if defined(IRC_ULTIMATE) || defined(IRC_UNREAL) || defined(IRC_ULTIMATE3) || defined(IRC_PTLINK) || defined(IRC_RAGE2) + { 'A', CMODE_A, 0, NULL, NULL }, +#endif +#if defined(IRC_UNREAL) || defined(IRC_RAGE2) + { 'C', CMODE_C, 0, NULL, NULL }, +#endif +#ifdef IRC_UNREAL + { 'G', CMODE_G, 0, NULL, NULL }, + { 'H', CMODE_H, 0, NULL, NULL }, +#endif +#ifdef IRC_ULTIMATE + { 'I', CMODE_I, 0, NULL, NULL }, +#endif +#if defined(IRC_ULTIMATE) || defined(IRC_UNREAL) || defined(IRC_PTLINK) || defined(IRC_ULTIMATE3) + { 'K', CMODE_K, 0, NULL, NULL }, +#endif +#ifdef HAS_LMODE + { 'L', CMODE_L, 0, get_redirect, cs_get_redirect }, +#endif +#ifdef IRC_BAHAMUT +#ifndef IRC_ULTIMATE3 + { 'M', CMODE_M, 0, NULL, NULL }, +#endif +#endif +#if defined(IRC_UNREAL) || defined(IRC_ULTIMATE3) || defined(IRC_PTLINK) || defined(IRC_RAGE2) + { 'N', CMODE_N, 0, NULL, NULL }, +#endif +#if defined(IRC_BAHAMUT) || defined(IRC_ULTIMATE) || defined(IRC_UNREAL) || defined(IRC_ULTIMATE3) || defined(IRC_RAGE2) + { 'O', CMODE_O, 0, NULL, NULL }, +#endif +#ifdef IRC_UNREAL + { 'Q', CMODE_Q, 0, NULL, NULL }, +#endif +#ifndef IRC_HYBRID + { 'R', CMODE_R, 0, NULL, NULL }, +#endif +#if defined(IRC_ULTIMATE) || defined(IRC_UNREAL) || defined(IRC_ULTIMATE3) || defined(IRC_PTLINK) || defined(IRC_RAGE2) + { 'S', CMODE_S, 0, NULL, NULL }, +#endif +#ifdef IRC_UNREAL + { 'V', CMODE_V, 0, NULL, NULL }, +#endif + { 0 } +}; + +static CMMode cmmodes[128] = { + { NULL }, { NULL }, { NULL }, { NULL }, { NULL }, { NULL }, { NULL }, { NULL }, + { NULL }, { NULL }, { NULL }, { NULL }, { NULL }, { NULL }, { NULL }, { NULL }, + { NULL }, { NULL }, { NULL }, { NULL }, { NULL }, { NULL }, { NULL }, { NULL }, + { NULL }, { NULL }, { NULL }, { NULL }, { NULL }, { NULL }, { NULL }, { NULL }, + { NULL }, { NULL }, { NULL }, { NULL }, { NULL }, { NULL }, { NULL }, { NULL }, + { NULL }, { NULL }, { NULL }, { NULL }, { NULL }, { NULL }, { NULL }, { NULL }, + { NULL }, { NULL }, { NULL }, { NULL }, { NULL }, { NULL }, { NULL }, { NULL }, + { NULL }, { NULL }, { NULL }, { NULL }, { NULL }, { NULL }, { NULL }, { NULL }, + { NULL }, { NULL }, { NULL }, { NULL }, { NULL }, { NULL }, { NULL }, { NULL }, + { NULL }, { NULL }, { NULL }, { NULL }, { NULL }, { NULL }, { NULL }, { NULL }, + { NULL }, { NULL }, { NULL }, { NULL }, { NULL }, { NULL }, { NULL }, { NULL }, + { NULL }, { NULL }, { NULL }, { NULL }, { NULL }, { NULL }, { NULL }, { NULL }, + { NULL }, + { NULL }, + { add_ban, del_ban }, + { NULL }, + { NULL }, +#ifdef HAS_EXCEPT + { add_exception, del_exception }, +#endif + { NULL }, + { NULL }, + { NULL }, { NULL }, { NULL }, { NULL }, { NULL }, { NULL }, { NULL }, { NULL }, + { NULL }, { NULL }, { NULL }, { NULL }, { NULL }, { NULL }, { NULL }, { NULL }, + { NULL }, { NULL }, { NULL }, { NULL }, { NULL }, { NULL }, { NULL }, { NULL } +}; + +#if defined(IRC_BAHAMUT) || defined(IRC_HYBRID) || defined(IRC_PTLINK) + +static char csmodes[128] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + 0, + #if defined(IRC_ULTIMATE3) || defined(IRC_HYBRID) + 'a', /* (33) ! Channel Admins */ + #else + 0, + #endif + 0, 0, 0, + #if defined(IRC_ULTIMATE3) || defined(IRC_RAGE2) + 'h', /* (37) % Channel halfops */ + #else + 0, + #endif + 0, 0, 0, 0, + #if defined(IRC_RAGE2) + 'a', /* * Channel Admins */ + #else + 0, + #endif + + 'v', 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + 'o', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +#endif + +static CUMode cumodes[128] = { + { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, + { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, + { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, + { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, + + { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, + { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, + { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, + { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, + + { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, + { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, + { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, + { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, + + { 0 }, + +#if defined(IRC_UNREAL) || defined(IRC_VIAGRA) + { CUS_PROTECT, CUF_PROTECT_BOTSERV, check_valid_op }, +#else +#if defined(IRC_ULTIMATE3) || defined(IRC_RAGE2) + { CUS_PROTECT, CUF_PROTECT_BOTSERV, check_valid_admin }, +#else + { 0 }, /* a */ +#endif +#endif + { 0 }, /* b */ + { 0 }, /* c */ + { 0 }, /* d */ + { 0 }, /* e */ + { 0 }, /* f */ + { 0 }, /* g */ +#ifdef HAS_HALFOP + { CUS_HALFOP, 0, check_valid_op }, +#else + { 0 }, /* h */ +#endif + { 0 }, /* i */ + { 0 }, /* j */ + { 0 }, /* k */ + { 0 }, /* l */ + { 0 }, /* m */ + { 0 }, /* n */ + { CUS_OP, CUF_PROTECT_BOTSERV, check_valid_op }, + { 0 }, /* p */ +#if defined(IRC_UNREAL) || defined(IRC_VIAGRA) + { CUS_OWNER, 0, check_valid_op }, +#else + { 0 }, /* q */ +#endif + { 0 }, /* r */ + { 0 }, /* s */ + { 0 }, /* t */ + { 0 }, /* u */ + { CUS_VOICE, 0, NULL }, + { 0 }, /* w */ + { 0 }, /* x */ + { 0 }, /* y */ + { 0 }, /* z */ + { 0 }, { 0 }, { 0 }, { 0 }, { 0 } +}; + +/* *INDENT-ON* */ +/*************************************************************************/ +/**************************** 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) { + send_cmd(c->ci->bi->nick, "PART %s", c->name); + } + + 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) + 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; + + 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) { + BotInfo *bi; + + if ((bi = findbot(*av))) { + send_mode(bi->nick, chan->name, "+%c %s", mode, + bi->nick); + continue; + } + } + + if (!(user = finduser(*av))) { + alog("channel: MODE %s %c%c for nonexistent user %s", + chan->name, (add ? '+' : '-'), mode, *av); + continue; + } + + if (debug) + alog("debug: Setting %c%c on %s for %s", (add ? '+' : '-'), + mode, chan->name, user->nick); + + if (add) { + if (check && cum->is_valid + && !cum->is_valid(user, chan, servermode)) + continue; + chan_set_user_status(chan, user, cum->status); + } else { + chan_remove_user_status(chan, user, cum->status); + } + } else if ((cbm = &cbmodes[(int) mode])->flag != 0) { + if (add) + chan->mode |= cbm->flag; + else + chan->mode &= ~cbm->flag; + + if (cbm->setvalue) { + if (add || !(cbm->flags & CBM_MINUS_NO_ARG)) { + if (ac == 0) { + alog("channel: mode %c%c with no parameter (?) for channel %s", add ? '+' : '-', mode, chan->name); + continue; + } + ac--; + av++; + } + cbm->setvalue(chan, add ? *av : NULL); + } + } else if ((cmm = &cmmodes[(int) mode])->addmask) { + if (ac == 0) { + alog("channel: mode %c%c with no parameter (?) for channel %s", add ? '+' : '-', mode, chan->name); + continue; + } + + ac--; + av++; + add ? cmm->addmask(chan, *av) : cmm->delmask(chan, *av); + } + } + + if (check) + check_modes(chan); +} + +/*************************************************************************/ + +/* Set the status of an user on a channel */ + +void chan_set_user_status(Channel * chan, User * user, int16 status) +{ + struct u_chanlist *uc; + + if (HelpChannel && status == CUS_OP + && !stricmp(chan->name, HelpChannel)) + change_user_mode(user, "+h", NULL); + + for (uc = user->chans; uc; uc = uc->next) { + if (uc->chan == chan) { + uc->status |= status; + break; + } + } +} + +/*************************************************************************/ + +/* Return the Channel structure corresponding to the named channel, or NULL + * if the channel was not found. chan is assumed to be non-NULL and valid + * (i.e. pointing to a channel name of 2 or more characters). */ + +Channel *findchan(const char *chan) +{ + Channel *c; + + if (debug >= 3) + alog("debug: findchan(%p)", chan); + c = chanlist[HASH(chan)]; + while (c) { + if (stricmp(c->name, chan) == 0) + return c; + c = c->next; + } + if (debug >= 3) + alog("debug: findchan(%s) -> %p", chan, c); + return NULL; +} + +/*************************************************************************/ + +/* Iterate over all channels in the channel list. Return NULL at end of + * list. + */ + +static Channel *current; +static int next_index; + +Channel *firstchan(void) +{ + next_index = 0; + while (next_index < 1024 && current == NULL) + current = chanlist[next_index++]; + if (debug >= 3) + alog("debug: firstchan() returning %s", + current ? current->name : "NULL (end of list)"); + return current; +} + +Channel *nextchan(void) +{ + if (current) + current = current->next; + if (!current && next_index < 1024) { + while (next_index < 1024 && current == NULL) + current = chanlist[next_index++]; + } + if (debug >= 3) + alog("debug: nextchan() returning %s", + current ? current->name : "NULL (end of list)"); + return current; +} + +/*************************************************************************/ + +/* Return statistics. Pointers are assumed to be valid. */ + +void get_channel_stats(long *nrec, long *memuse) +{ + long count = 0, mem = 0; + Channel *chan; + struct c_userlist *cu; + BanData *bd; + int i, j; + + for (i = 0; i < 1024; i++) { + for (chan = chanlist[i]; chan; chan = chan->next) { + count++; + mem += sizeof(*chan); + if (chan->topic) + mem += strlen(chan->topic) + 1; + if (chan->key) + mem += strlen(chan->key) + 1; +#ifdef HAS_FMODE + if (chan->flood) + mem += strlen(chan->flood) + 1; +#endif +#ifdef HAS_LMODE + if (chan->redirect) + mem += strlen(chan->redirect) + 1; +#endif + mem += sizeof(char *) * chan->bansize; + for (j = 0; j < chan->bancount; j++) { + if (chan->bans[j]) + mem += strlen(chan->bans[j]) + 1; + } +#ifdef HAS_EXCEPT + mem += sizeof(char *) * chan->exceptsize; + for (j = 0; j < chan->exceptcount; j++) { + if (chan->excepts[j]) + mem += strlen(chan->excepts[j]) + 1; + } +#endif + for (cu = chan->users; cu; cu = cu->next) { + mem += sizeof(*cu); + if (cu->ud) { + mem += sizeof(*cu->ud); + if (cu->ud->lastline) + mem += strlen(cu->ud->lastline) + 1; + } + } + for (bd = chan->bd; bd; bd = bd->next) { + if (bd->mask) + mem += strlen(bd->mask) + 1; + mem += sizeof(*bd); + } + } + } + *nrec = count; + *memuse = mem; +} + +/*************************************************************************/ + +/* Is the given nick on the given channel? */ + +int is_on_chan(Channel * c, User * u) +{ + struct u_chanlist *uc; + + for (uc = u->chans; uc; uc = uc->next) + if (uc->chan == c) + return 1; + + return 0; +} + +/*************************************************************************/ + +/* Is the given nick on the given channel? + This function supports links. */ + +User *nc_on_chan(Channel * c, NickCore * nc) +{ + struct c_userlist *u; + + if (!c || !nc) + return NULL; + + for (u = c->users; u; u = u->next) { + if (u->user->na && u->user->na->nc == nc + && nick_recognized(u->user)) + return u->user; + } + return NULL; +} + +/*************************************************************************/ +/*************************** Message Handling ****************************/ +/*************************************************************************/ + +/* Handle a JOIN command. + * av[0] = channels to join + */ + +void do_join(const char *source, int ac, char **av) +{ + User *user; + char *s, *t; + struct u_chanlist *c, *nextc; + + user = finduser(source); + if (!user) { + alog("user: JOIN from nonexistent user %s: %s", source, + merge_args(ac, av)); + return; + } + + t = av[0]; + while (*(s = t)) { + t = s + strcspn(s, ","); + if (*t) + *t++ = 0; + if (debug) + alog("debug: %s joins %s", source, s); + + if (*s == '0') { + c = user->chans; + while (c) { + nextc = c->next; + chan_deluser(user, c->chan); + free(c); + c = nextc; + } + user->chans = NULL; + continue; + } + + /* Make sure check_kick comes before chan_adduser, so banned users + * don't get to see things like channel keys. */ + if (check_kick(user, s)) + continue; + +/* chan_adduser(user, s); */ + join_user_update(user, findchan(s), s); + + +/* c = scalloc(sizeof(*c), 1); + c->next = user->chans; + if (user->chans) + user->chans->prev = c; + user->chans = c; + c->chan = findchan(s); */ + } +} + +/*************************************************************************/ + +/* Handle a KICK command. + * av[0] = channel + * av[1] = nick(s) being kicked + * av[2] = reason + */ + +void do_kick(const char *source, int ac, char **av) +{ + BotInfo *bi; + ChannelInfo *ci; + User *user; + char *s, *t; + struct u_chanlist *c; + + t = av[1]; + while (*(s = t)) { + t = s + strcspn(s, ","); + if (*t) + *t++ = 0; + + /* If it is the bot that is being kicked, we make it rejoin the + * channel and stop immediately. + * --lara + */ + if (s_BotServ && (bi = findbot(s)) && (ci = cs_findchan(av[0]))) { + bot_join(ci); + continue; + } + + user = finduser(s); + if (!user) { + alog("user: KICK for nonexistent user %s on %s: %s", s, av[0], + merge_args(ac - 2, av + 2)); + continue; + } + if (debug) + alog("debug: kicking %s from %s", s, av[0]); + for (c = user->chans; c && stricmp(av[0], c->chan->name) != 0; + c = c->next); + if (c) { + chan_deluser(user, c->chan); + if (c->next) + c->next->prev = c->prev; + if (c->prev) + c->prev->next = c->next; + else + user->chans = c->next; + free(c); + } + } +} + +/*************************************************************************/ + +/* Handle a PART command. + * av[0] = channels to leave + * av[1] = reason (optional) + */ + +void do_part(const char *source, int ac, char **av) +{ + User *user; + char *s, *t; + struct u_chanlist *c; + + user = finduser(source); + if (!user) { + alog("user: PART from nonexistent user %s: %s", source, + merge_args(ac, av)); + return; + } + t = av[0]; + while (*(s = t)) { + t = s + strcspn(s, ","); + if (*t) + *t++ = 0; + if (debug) + alog("debug: %s leaves %s", source, s); + for (c = user->chans; c && stricmp(s, c->chan->name) != 0; + c = c->next); + if (c) { + if (!c->chan) { + alog("user: BUG parting %s: channel entry found but c->chan NULL", s); + return; + } + chan_deluser(user, c->chan); + if (c->next) + c->next->prev = c->prev; + if (c->prev) + c->prev->next = c->next; + else + user->chans = c->next; + free(c); + } + } +} + +/*************************************************************************/ + +#if defined(IRC_BAHAMUT) || defined(IRC_HYBRID) || defined(IRC_PTLINK) + +/* Handle a SJOIN command. + + On channel creation, syntax is: + + av[0] = timestamp + av[1] = channel name + av[2|3|4] = modes \ depends of whether the modes k and l + av[3|4|5] = users / are set or not. + + When a single user joins an (existing) channel, it is: + + av[0] = timestamp + av[1] = user + +*/ + +void do_sjoin(const char *source, int ac, char **av) +{ + Channel *c; + User *user; + + int is_sqlined = 0; + + /* Double check to avoid unknown modes that need parameters */ + if (ac >= 4 && ac <= 6) { + char *s, *end, cubuf[CHAN_MAX_SYMBOLS + 2], *end2, + *cumodes[CHAN_MAX_SYMBOLS + 1]; + + c = findchan(av[1]); +#ifndef IRC_HYBRID +#ifndef IRC_PTLINK + if (!c) + is_sqlined = check_chan_sqline(av[1]); +#endif +#endif + + cubuf[0] = '+'; + cumodes[0] = cubuf; + + /* We make all the users join */ + s = av[ac - 1]; /* Users are always the last element */ + + while (*s) { + end = strchr(s, ' '); + if (end) + *end = 0; + + end2 = cubuf + 1; + while (csmodes[(int) *s] != 0) + *end2++ = csmodes[(int) *s++]; + *end2 = 0; + + user = finduser(s); + if (!user) { + alog("user: SJOIN for nonexistent user %s on %s", s, + av[1]); + return; + } + + if (is_sqlined && !is_oper(user)) { + send_cmd(s_OperServ, "KICK %s %s :Q-Lined", av[1], s); + } else { + if (!check_kick(user, av[1])) { + /* Make the user join; if the channel does not exist it + * will be created there. This ensures that the channel + * is not created to be immediately destroyed, and + * that the locked key or topic is not shown to anyone + * who joins the channel when empty. + */ + c = join_user_update(user, c, av[1]); + + /* We update user mode on the channel */ + if (end2 - cubuf > 1) { + int i; + + for (i = 1; i < end2 - cubuf; i++) + cumodes[i] = user->nick; + chan_set_modes(source, c, 1 + (end2 - cubuf - 1), + cumodes, 1); + } + } + } + + if (!end) + break; + s = end + 1; + } + + if (c) { + /* Set the timestamp */ + c->creation_time = strtoul(av[0], NULL, 10); + /* We now update the channel mode. */ + chan_set_modes(source, c, ac - 3, &av[2], 1); + } + } else if (ac == 2) { + user = finduser(source); + if (!user) { + alog("user: SJOIN for nonexistent user %s on %s", source, + av[1]); + return; + } + + if (check_kick(user, av[1])) + return; + + c = findchan(av[1]); +#ifndef IRC_HYBRID +#ifndef IRC_PTLINK + if (!c) + is_sqlined = check_chan_sqline(av[1]); +#endif +#endif + if (is_sqlined && !is_oper(user)) { + send_cmd(s_OperServ, "KICK %s %s :Q-Lined", av[1], user->nick); + } else { + c = join_user_update(user, c, av[1]); + c->creation_time = strtoul(av[0], NULL, 10); + } + } +} + +#endif + +/*************************************************************************/ + +/* Handle a channel MODE command. */ + +void do_cmode(const char *source, int ac, char **av) +{ + Channel *chan; + ChannelInfo *ci = NULL; +#ifdef IRC_BAHAMUT + int i; + char *t; + + /* TSMODE for bahamut - leave this code out to break MODEs. -GD */ + if (uplink_capab & CAPAB_TSMODE) { + for (i = 0; i < strlen(av[1]); i++) { + if (!isdigit(av[1][i])) + break; + } + if (av[1][i] == '\0') { + /* We have a valid TS field in av[1] now, so we can strip it off */ + /* After we swap av[0] and av[1] ofcourse to not break stuff! :) */ + t = av[0]; + av[0] = av[1]; + av[1] = t; + ac--; + av++; + } else { + alog("TSMODE enabled but MODE has no valid TS"); + } + } +#endif + + chan = findchan(av[0]); + if (!chan) { + ci = cs_findchan(av[0]); + if (!(ci && (ci->flags & CI_VERBOTEN))) + alog("channel: MODE %s for nonexistent channel %s", + merge_args(ac - 1, av + 1), av[0]); + return; + } + + /* This shoul |
