Changeset 803 for trunk


Ignore:
Timestamp:
05/31/07 15:15:23 (5 years ago)
Author:
wd
Message:

Many more changes:

  • Moved the 'core' addon code into various places in the main ircd module.
  • Split channel/user modes out of channel.c/client.c and into chanmode.c/usermode.c respectively.
  • Added init/teardown routines for channel/usermodes.
  • Changed the INVIS and OPER macros to have longer(:/) and more descriptive names.
Location:
trunk/ithildin/modules/ircd
Files:
20 edited
4 copied

Legend:

Unmodified
Added
Removed
  • trunk/ithildin/modules/ircd/addons/cmode_operonly.c

    r613 r803  
    5252    struct channel_check_args *ccap = (struct channel_check_args *)data; 
    5353 
    54     if (chanmode_isset(ccap->chan, chanmode_operonly) && !OPER(ccap->cli)) { 
     54    if (chanmode_isset(ccap->chan, chanmode_operonly) && 
     55            !CLIENT_OPERATOR(ccap->cli)) { 
    5556        /* send them the error and return. */ 
    5657        sendto_one(ccap->cli, RPL_FMT(ccap->cli, ERR_NOPRIVILEGES)); 
  • trunk/ithildin/modules/ircd/addons/cmode_private.c

    r787 r803  
    5555        return (void *)HOOK_COND_OK; 
    5656    else if (chanmode_isset(ccap->chan, chanmode_private)) { 
    57         if (OPER(ccap->cli) && BPRIV(ccap->cli, core.privs.see_hidden_chan)) 
     57        if (CLIENT_OPERATOR(ccap->cli) && 
     58                BPRIV(ccap->cli, ircd.privileges.priv_shc)) 
    5859            return (void *)HOOK_COND_ALWAYSOK; /* okay, but sketchy.  */ 
    5960        else 
  • trunk/ithildin/modules/ircd/addons/hostcrypt.c

    r787 r803  
    258258static void hostcrypt_encrypt(client_t *cli) { 
    259259 
    260     if (OPER(cli) && hostcrypt.operhost != NULL) 
     260    if (CLIENT_OPERATOR(cli) && hostcrypt.operhost != NULL) 
    261261        strlcpy(cli->host, hostcrypt.operhost, HOSTLEN + 1); 
    262262    else 
  • trunk/ithildin/modules/ircd/addons/umode_helper.c

    r579 r803  
    7575USERMODE_FUNC(helper_usermode_handler) { 
    7676 
    77     if (set && !CLIENT_MASTER(cli) && !OPER(cli) && 
     77    if (set && !CLIENT_MASTER(cli) && !CLIENT_OPERATOR(cli) && 
    7878            (by != NULL && !CLIENT_MASTER(by))) 
    7979        return 0; 
  • trunk/ithildin/modules/ircd/chanmode.c

    r801 r803  
    11/* 
    2  * channel.c: channel structure management code 
     2 * chanmode.c: channel mode management code 
    33 *  
    4  * Copyright 2002 the Ithildin Project. 
     4 * Copyright 2002-2007 the Ithildin Project. 
    55 * See the COPYING file for more information on licensing and use. 
    66 *  
    7  * This file provides the basic functions necessary to create/destroy/manage 
    8  * channel structures, and lists of people with channels.  It also provides the 
    9  * basics of channel mode management. 
     7 * This file provides both the basic functions necessary to manage channel 
     8 * modes and some of the intrinsic channel modes for IRC (mostly as defined 
     9 * in rfc1459).  Additional modes can be created through other modules. 
    1010 */ 
    1111 
     
    1616IDSTRING(rcsid, "$Id$"); 
    1717 
    18 channel_t *create_channel(char *name) { 
    19     channel_t *chan = calloc(1, sizeof(channel_t)); 
    20  
    21     /* allocate space for mode data too */ 
    22     chan->mdext = mdext_alloc(ircd.mdext.channel); 
    23  
    24     strncpy(chan->name, name, ircd.limits.chanlen); 
    25     chan->created = me.now; 
    26  
    27     LIST_INSERT_HEAD(ircd.lists.channels, chan, lp); 
    28     hash_insert(ircd.hashes.channel, chan); 
    29  
    30     ircd.stats.channels++; 
    31  
    32     hook_event(ircd.events.channel_create, chan); 
    33  
    34     return chan; 
    35 } 
    36  
    37 void add_to_channel(client_t *cli, channel_t *chan, bool hook) { 
    38     struct chanlink *clp; 
    39  
    40     /* insert user to channel list, and vice versa */ 
    41     clp = malloc(sizeof(struct chanlink)); 
    42     clp->cli = cli; 
    43     clp->chan = chan; 
    44     clp->flags = clp->bans = 0; 
    45     LIST_INSERT_HEAD(&chan->users, clp, lpchan); 
    46     LIST_INSERT_HEAD(&cli->chans, clp, lpcli); 
    47  
    48     chan->onchannel++; 
    49  
    50     if (hook) 
    51         hook_event(ircd.events.channel_add, clp); 
    52 } 
    53  
    54 void del_from_channel(client_t *cli, channel_t *chan, bool hook) { 
    55     struct chanlink *clp = clp = find_chan_link(cli, chan); 
    56  
    57     if (clp != NULL) { 
    58         /* hook the del call first */ 
    59         if (hook) 
    60             hook_event(ircd.events.channel_del, clp); 
    61  
    62         /* remove from channel/client lists */ 
    63         LIST_REMOVE(clp, lpchan); 
    64         LIST_REMOVE(clp, lpcli); 
    65         free(clp); 
    66         chan->onchannel--; 
    67     } 
    68  
    69     if (chan->onchannel == 0) 
    70         destroy_channel(chan); 
    71 } 
    72  
    73 void destroy_channel(channel_t *chan) { 
    74     unsigned char *s; 
    75     int dummy; 
    76  
    77     hook_event(ircd.events.channel_destroy, chan); 
    78      
    79     /* clear out all the data possibly left over from channel modes. */ 
    80     s = ircd.cmodes.avail; 
    81     while (*s) { 
    82         ircd.cmodes.modes[*s].changefunc(NULL, chan, *s, CHANMODE_CLEAR, NULL, &dummy); 
    83         s++; 
    84     } 
    85  
    86     /* we only expect to be called on an empty channel! */ 
    87     hash_delete(ircd.hashes.channel, chan); 
    88     LIST_REMOVE(chan, lp); 
    89     ircd.stats.channels--; 
    90     mdext_free(ircd.mdext.channel, chan->mdext); 
    91     free(chan); 
    92 } 
    93  
    94 struct chanlink *find_chan_link(client_t *cli, channel_t *chan) { 
    95     struct chanlink *clp; 
    96  
    97     LIST_FOREACH(clp, &cli->chans, lpcli) { 
    98         if (clp->chan == chan) 
    99             return clp; 
    100     } 
    101  
    102     return NULL; 
    103 } 
    104  
    105 int channel_check_access(client_t *cli, channel_t *chan, char *ext, 
    106         event_t *ep) { 
    107     struct channel_check_args cca; 
    108  
    109     cca.cli = cli; 
    110     cca.chan = chan; 
    111     cca.clp = find_chan_link(cli, chan); 
    112     cca.extra = ext; 
    113  
    114     return hook_cond_event(ep, &cca); 
    115 } 
    116  
    117 /******************************************************************************* 
    118  * channel mode goodies here. 
    119  ******************************************************************************/ 
     18/* lots of static functions here */ 
    12019static void chanmode_build_lists(void); 
     20static int check_bans(const struct channel_ban_list *, const char *, 
     21        const char *, const char *, const char *, const char *); 
     22static CHANMODE_FUNC(chanmode_ban); 
     23static CHANMODE_QUERY_FUNC(chanmode_ban_query); 
     24static HOOK_FUNCTION(can_join_mode_b); 
     25static HOOK_FUNCTION(can_send_mode_b); 
     26static HOOK_FUNCTION(can_nick_mode_b); 
     27 
     28static HOOK_FUNCTION(can_send_mode_m); 
     29static HOOK_FUNCTION(can_send_mode_n); 
     30static HOOK_FUNCTION(can_show_mode_s); 
     31 
     32static HOOK_FUNCTION(can_act_mode_ov); 
     33 
     34static CHANMODE_FUNC(chanmode_key); 
     35static CHANMODE_QUERY_FUNC(chanmode_key_query); 
     36static HOOK_FUNCTION(can_join_mode_k); 
     37 
     38static CHANMODE_FUNC(chanmode_limit); 
     39static CHANMODE_QUERY_FUNC(chanmode_limit_query); 
     40static HOOK_FUNCTION(can_join_mode_l); 
     41 
     42/* This function either initializes the chanmode system or handles updates 
     43 * in the case of a reload. */ 
     44void chanmode_init(bool reload) { 
     45    uint64_t ui64 = 1; 
     46    unsigned char c; 
     47 
     48#define MODELOOP(from, to) do {                                               \ 
     49    for (c = from;c <= to;c++, ui64 <<= 1) {                                  \ 
     50        ircd.cmodes.modes[c].mode = c;                                        \ 
     51        ircd.cmodes.modes[c].mask = ui64;                                     \ 
     52        ircd.cmodes.modes[c].avail = 1;                                       \ 
     53    }                                                                         \ 
     54} while (0) 
     55 
     56    if (reload == false) { 
     57        MODELOOP('a', 'z'); /* set a-z modes */ 
     58        MODELOOP('A', 'Z'); /* and A-Z modes */ 
     59        MODELOOP('0', '9'); /* and 0-9 modes */ 
     60 
     61        /* now allocate our various channel modes */ 
     62        ui64 = 0; 
     63        ircd.cmodes.mode_ban = chanmode_request('b', &c, CHANMODE_FL_A, 
     64                chanmode_ban, chanmode_ban_query, 
     65                sizeof(struct channel_ban_list), NULL); 
     66        ircd.cmodes.mode_key = chanmode_request('k', &c, CHANMODE_FL_B, 
     67                chanmode_key, chanmode_key_query, PASSWDLEN + 1, NULL); 
     68        ircd.cmodes.mode_limit = chanmode_request('l', &c, CHANMODE_FL_C, 
     69                chanmode_limit, chanmode_limit_query, sizeof(uint32_t), NULL); 
     70        ircd.cmodes.mode_mod = chanmode_request('m', &c, CHANMODE_FL_D, 
     71                chanmode_flag, chanmode_flag_query, 0, NULL); 
     72        ircd.cmodes.mode_nextern = chanmode_request('n', &c, CHANMODE_FL_D, 
     73                chanmode_flag, chanmode_flag_query, 0, NULL); 
     74        ircd.cmodes.mode_op = chanmode_request('o', &c, CHANMODE_FL_PREFIX, 
     75                chanmode_uflag, chanmode_uflag_query, 0, "@"); 
     76        ircd.cmodes.mode_secret = chanmode_request('s', &c, CHANMODE_FL_D, 
     77                chanmode_flag, chanmode_flag_query, 0, NULL); 
     78        ircd.cmodes.mode_voice = chanmode_request('v', &c, CHANMODE_FL_PREFIX, 
     79                chanmode_uflag, chanmode_uflag_query, 0, "+"); 
     80    } else { 
     81        chanmode_update_funcs(ircd.cmodes.mode_ban, chanmode_ban, 
     82                chanmode_ban_query); 
     83        chanmode_update_funcs(ircd.cmodes.mode_key, chanmode_key, 
     84                chanmode_key_query); 
     85        chanmode_update_funcs(ircd.cmodes.mode_limit, chanmode_limit, 
     86                chanmode_limit_query); 
     87        chanmode_update_funcs(ircd.cmodes.mode_mod, chanmode_flag, 
     88                chanmode_flag_query); 
     89        chanmode_update_funcs(ircd.cmodes.mode_nextern, chanmode_flag, 
     90                chanmode_flag_query); 
     91        chanmode_update_funcs(ircd.cmodes.mode_op, chanmode_uflag, 
     92                chanmode_uflag_query); 
     93        chanmode_update_funcs(ircd.cmodes.mode_mod, chanmode_flag, 
     94                chanmode_flag_query); 
     95        chanmode_update_funcs(ircd.cmodes.mode_voice, chanmode_uflag, 
     96                chanmode_uflag_query); 
     97    } 
     98 
     99    add_hook(ircd.events.can_join_channel, can_join_mode_b); 
     100    add_hook(ircd.events.can_send_channel, can_send_mode_b); 
     101    add_hook(ircd.events.can_nick_channel, can_nick_mode_b); 
     102 
     103    add_hook(ircd.events.can_send_channel, can_send_mode_m); 
     104 
     105    add_hook(ircd.events.can_send_channel, can_send_mode_n); 
     106 
     107    add_hook(ircd.events.can_see_channel, can_show_mode_s); 
     108 
     109    add_hook(ircd.events.can_join_channel, can_join_mode_k); 
     110    add_hook(ircd.events.can_join_channel, can_join_mode_l); 
     111 
     112    add_hook(ircd.events.can_send_channel, can_act_mode_ov); 
     113    add_hook(ircd.events.can_nick_channel, can_act_mode_ov); 
     114 
     115    ui64 = MAX_BANS_PER_CHANNEL; 
     116    add_isupport("MAXBANS", ISUPPORT_FL_INT, (char *)&ui64); 
     117} 
     118 
     119void chanmode_deinit(bool reload) { 
     120 
     121    if (reload == false) { 
     122        chanmode_release(ircd.cmodes.mode_ban); 
     123        chanmode_release(ircd.cmodes.mode_key); 
     124        chanmode_release(ircd.cmodes.mode_limit); 
     125        chanmode_release(ircd.cmodes.mode_mod); 
     126        chanmode_release(ircd.cmodes.mode_nextern); 
     127        chanmode_release(ircd.cmodes.mode_op); 
     128        chanmode_release(ircd.cmodes.mode_secret); 
     129        chanmode_release(ircd.cmodes.mode_voice); 
     130    } 
     131 
     132    remove_hook(ircd.events.can_join_channel, can_join_mode_b); 
     133    remove_hook(ircd.events.can_send_channel, can_send_mode_b); 
     134    remove_hook(ircd.events.can_nick_channel, can_nick_mode_b); 
     135 
     136    remove_hook(ircd.events.can_send_channel, can_send_mode_m); 
     137 
     138    remove_hook(ircd.events.can_send_channel, can_send_mode_n); 
     139 
     140    remove_hook(ircd.events.can_see_channel, can_show_mode_s); 
     141 
     142    remove_hook(ircd.events.can_join_channel, can_join_mode_k); 
     143    remove_hook(ircd.events.can_join_channel, can_join_mode_l); 
     144 
     145    remove_hook(ircd.events.can_send_channel, can_act_mode_ov); 
     146    remove_hook(ircd.events.can_nick_channel, can_act_mode_ov); 
     147 
     148    del_isupport(find_isupport("MAXBANS")); 
     149} 
    121150 
    122151uint64_t chanmode_request(unsigned char suggested, unsigned char *actual, 
     
    431460} 
    432461 
    433 char **channel_mdext_iter(char **last) { 
    434     static int started = 0; 
    435     channel_t *cp = *(channel_t **)last; 
    436  
     462/* Below are four convenience functions for modes which fit the generic 
     463 * category of either channel 'flags' (on/off or type 'D') or channel user 
     464 * 'prefixes' (uflags like +o/+v).  If your flags don't need special 
     465 * behavior to be set/unset use these. */ 
     466CHANMODE_FUNC(chanmode_flag) { 
     467     
     468    *argused = 0; 
     469    if (cli != NULL && !CHANOP(cli, chan) && !CLIENT_MASTER(cli)) 
     470        return ERR_CHANOPRIVSNEEDED; 
     471 
     472    switch (set) { 
     473        case CHANMODE_SET: 
     474            chanmode_setflag(chan, mode); 
     475            break; 
     476        case CHANMODE_UNSET: 
     477            chanmode_unsetflag(chan, mode); 
     478            break; 
     479    } 
     480    return CHANMODE_OK; 
     481} 
     482 
     483CHANMODE_QUERY_FUNC(chanmode_flag_query) { 
     484    *argused = 0; 
     485 
     486    if (*state == NULL) 
     487        *state = (void *)0x1; /* dummy pointer to nowhere */ 
     488    else 
     489        return CHANMODE_FAIL; /* they already asked */ 
     490 
     491    if (!chanmode_isset(chan, mode)) 
     492        return CHANMODE_FAIL; /* not set */ 
     493    return CHANMODE_OK; /* it's set */ 
     494} 
     495 
     496CHANMODE_FUNC(chanmode_uflag) { 
     497    struct chanlink *clp; 
     498    client_t *cp; 
     499 
     500    if (cli != NULL && !CHANOP(cli, chan) && !CLIENT_MASTER(cli)) 
     501        return ERR_CHANOPRIVSNEEDED; 
     502 
     503    /* error check stuff first */ 
     504    if (set != CHANMODE_CLEAR) { 
     505        if (arg == NULL) 
     506            return CHANMODE_NOARG; 
     507        *argused = 1; /* otherwise we use the argument */ 
     508    } else 
     509        return CHANMODE_OK; /* we don't have anything to clear */ 
     510 
     511    /* chase for +o/+v to avoid desynchs */ 
     512    cp = client_get_history(arg, 0); 
    437513    if (cp == NULL) { 
    438         if (started) { 
    439             started = 0; 
    440             return NULL; 
     514        if (cli != NULL) 
     515            sendto_one(cli, RPL_FMT(cli, ERR_NOSUCHNICK), arg); 
     516        return CHANMODE_FAIL; 
     517    } 
     518    if (arg != cp->nick) 
     519        strcpy(arg, cp->nick); /* Maintain exact case of nickname if the arg 
     520                                  came from somewhere but the client's nick */ 
     521 
     522    clp = find_chan_link(cp, chan); 
     523    if (clp == NULL) { 
     524        if (cli != NULL) 
     525            sendto_one(cli, RPL_FMT(cli, ERR_USERNOTINCHANNEL), cp->nick, 
     526                    chan->name); 
     527        return CHANMODE_FAIL; 
     528    } 
     529 
     530    switch (set) { 
     531        case CHANMODE_SET: 
     532            clp->flags |= ircd.cmodes.modes[mode].umask; 
     533            return CHANMODE_OK; 
     534        case CHANMODE_UNSET: 
     535            clp->flags &= ~ircd.cmodes.modes[mode].umask; 
     536            return CHANMODE_OK; 
     537    } 
     538     
     539    return CHANMODE_FAIL; 
     540} 
     541 
     542CHANMODE_QUERY_FUNC(chanmode_uflag_query) { 
     543    *argused = 0; 
     544 
     545    return CHANMODE_FAIL; /* you can't query these.. */ 
     546} 
     547 
     548/******************************************************************************* 
     549 * RFC1459 mode functions here 
     550 ******************************************************************************/ 
     551 
     552/* Function to count how many bans in a channel a user matches against.   
     553 * We try to do the least number of comparisons possible (always 2, 
     554 * maybe 3). */ 
     555 
     556static int check_bans(const struct channel_ban_list *list, const char *nick, 
     557        const char *user, const char *host, const char *ip, 
     558        const char *orighost) { 
     559    struct channel_ban *cbp; 
     560    bool check_orighost = false; 
     561    int bans = 0; 
     562 
     563    if (orighost != NULL && *orighost != '\0' && strcasecmp(host, orighost)) 
     564        check_orighost = true; 
     565 
     566    /* Walk the list only once, checking each ban against the various 
     567     * pieces of data provided.  If the nick or username don't match we skip 
     568     * right away, then do two (or three) host checks.  First we check the 
     569     * "display" host, then we do ip matching on the ip, and then we check 
     570     * the orighost if required. */ 
     571 
     572    LIST_FOREACH(cbp, list, lp) { 
     573        if (!match(cbp->nick, nick) || !match(cbp->user, user)) 
     574            continue; /* not a match */ 
     575        if (match(cbp->host, host) || ipmatch(cbp->host, ip)) { 
     576            bans++; 
     577            continue; 
     578        } else if (check_orighost && match(cbp->host, orighost)) { 
     579            bans++; 
     580            continue; 
    441581        } 
    442         cp = LIST_FIRST(ircd.lists.channels); 
    443         started = 1; 
    444     } 
    445     if (cp == NULL) 
    446         return NULL; 
    447  
    448     *(channel_t **)last = LIST_NEXT(cp, lp); 
    449     return (char **)&cp->mdext; 
    450 } 
    451  
    452 int chancmp(char *one, char *two, size_t len __UNUSED) { 
    453     return istrcmp(ircd.maps.channel, one, two); 
    454 } 
     582    } 
     583 
     584    return bans; 
     585} 
     586 
     587/* bans.  rather complicated! */ 
     588static CHANMODE_FUNC(chanmode_ban) { 
     589    struct channel_ban_list *banlist = 
     590        (struct channel_ban_list *)chanmode_getdata(chan, mode); 
     591    struct channel_ban *cbp; 
     592    struct chanlink *clp; 
     593    char nick[NICKLEN + 1]; 
     594    char user[USERLEN + 1]; 
     595    char host[HOSTLEN + 1]; 
     596 
     597    int cnt = 0; 
     598 
     599    /* if we're not just clearing the data, check arg, and make sure they know 
     600     * the argument is being used. */ 
     601    if (set != CHANMODE_CLEAR) { 
     602        char *bang, *at; 
     603        size_t nicklen, userlen, hostlen; 
     604 
     605        if (arg == NULL) { 
     606            /* if this is a client, send them the list of bans. */ 
     607            if (cli != NULL && MYCLIENT(cli)) { 
     608                LIST_FOREACH(cbp, banlist, lp) { 
     609                    sendto_one(cli, RPL_FMT(cli, RPL_BANLIST), chan->name, 
     610                            cbp->nick, cbp->user, cbp->host, cbp->who, 
     611                            cbp->when); 
     612                } 
     613                sendto_one(cli, RPL_FMT(cli, RPL_ENDOFBANLIST), chan->name); 
     614            } 
     615            return CHANMODE_NOP; 
     616        } 
     617 
     618        *argused = 1; 
     619        /* if they're not ops, deny deny deny. */ 
     620        if (cli != NULL && !CHANOP(cli, chan) && !CLIENT_MASTER(cli)) 
     621            return ERR_CHANOPRIVSNEEDED; 
     622 
     623        bang = strchr(arg, '!'); 
     624        at = strchr(arg, '@'); 
     625        /* here's the scoop: the bang can't be the first character of the 
     626         * mask.  the at can't be the last character, and there has to be 
     627         * something between the bang and the at. */ 
     628        if (bang == NULL || at == NULL || bang == arg || 
     629                *(at + 1) == '\0' || (bang + 1) == at || at < bang) 
     630            return CHANMODE_FAIL; /* bogus mask */ 
     631 
     632        nicklen = bang - arg; /* length of text from beginning of the string 
     633                                 to the '!' symbol. */ 
     634        userlen = at - (bang + 1); /* length from after the '!' to the '@' 
     635                                    symbol */ 
     636        hostlen = strlen(at + 1); /* length from after the '@' to the end */ 
     637 
     638        /* Make sure nothing is too long, too */ 
     639        if (nicklen > NICKLEN || userlen > USERLEN || hostlen > HOSTLEN) 
     640            return CHANMODE_FAIL; /* arguments are too long */ 
     641 
     642        strlcpy(nick, arg, nicklen + 1); 
     643        strlcpy(user, bang + 1, userlen + 1); 
     644        strlcpy(host, at + 1, hostlen + 1); 
     645    } 
     646 
     647    switch (set) { 
     648        case CHANMODE_SET: 
     649            LIST_FOREACH(cbp, banlist, lp) { 
     650                if (++cnt > MAX_BANS_PER_CHANNEL && cli != NULL && 
     651                        MYCLIENT(cli)) { 
     652                    sendto_one(cli, RPL_FMT(cli, ERR_BANLISTFULL), 
     653                            chan->name, arg); 
     654                    return CHANMODE_FAIL; /* no siree bob */ 
     655                } 
     656                /* Previously I had tried to match the ban being set against 
     657                 * other bans, but I'm not sure this behavior is desired so 
     658                 * I'm taking it out for now... */ 
     659#if 0 
     660                /* we only want to know if current bans cover this ban, not 
     661                 * if this ban covers current ones, since it may cover 
     662                 * other things too. */ 
     663                if (match(cbp->nick, nick) && match(cbp->user, user) && 
     664                        match(cbp->host, host)) 
     665                    return CHANMODE_FAIL; /* already set. */ 
     666#else 
     667                if (!strcasecmp(cbp->nick, nick) && 
     668                        !strcasecmp(cbp->user, user) && 
     669                        !strcasecmp(cbp->host, host)) 
     670                    return CHANMODE_FAIL; 
     671#endif 
     672            } 
     673             
     674            cbp = calloc(1, sizeof(struct channel_ban)); 
     675            strlcpy(cbp->nick, nick, NICKLEN + 1); 
     676            strlcpy(cbp->user, user, USERLEN + 1); 
     677            strlcpy(cbp->host, host, HOSTLEN + 1); 
     678            if (cli != NULL) 
     679                sprintf(cbp->who, "%s!%s@%s", cli->nick, cli->user, cli->host); 
     680            else 
     681                strcpy(cbp->who, ircd.me->name); 
     682            cbp->when = me.now; 
     683            cbp->type = CHANNEL_BAN_BAN; 
     684 
     685            LIST_INSERT_HEAD(banlist, cbp, lp); 
     686 
     687            /* count bans against all users in the channel. */ 
     688            LIST_FOREACH(clp, &chan->users, lpchan) { 
     689                clp->bans = check_bans(banlist, clp->cli->nick, 
     690                        clp->cli->user, clp->cli->host, clp->cli->ip, 
     691                        clp->cli->orighost); 
     692            } 
     693             
     694            break; 
     695        case CHANMODE_UNSET: 
     696            LIST_FOREACH(cbp, banlist, lp) { 
     697                if (!strcasecmp(cbp->nick, nick) && 
     698                        !strcasecmp(cbp->user, user) && 
     699                        !strcasecmp(cbp->host, host)) { 
     700                    /* a winner. */ 
     701                    LIST_REMOVE(cbp, lp); 
     702                    free(cbp); 
     703 
     704                    /* count bans against all users in the channel. */ 
     705                    LIST_FOREACH(clp, &chan->users, lpchan) { 
     706                        clp->bans = check_bans(banlist, clp->cli->nick, 
     707                                clp->cli->user, clp->cli->host, clp->cli->ip, 
     708                                clp->cli->orighost); 
     709                    } 
     710                    break; 
     711                } 
     712            } 
     713            break; 
     714        case CHANMODE_CLEAR: 
     715            while ((cbp = LIST_FIRST(banlist)) != NULL) { 
     716                LIST_REMOVE(cbp, lp); 
     717                free(cbp); 
     718            } 
     719            break; 
     720    } 
     721 
     722    return CHANMODE_OK; /* a-okay. */ 
     723} 
     724 
     725struct ban_query_state { 
     726    bool started; 
     727    struct channel_ban *curban; 
     728}; 
     729 
     730CHANMODE_QUERY_FUNC(chanmode_ban_query) { 
     731    struct channel_ban_list *banlist = 
     732        (struct channel_ban_list *)chanmode_getdata(chan, mode); 
     733    struct channel_ban *cbp; 
     734    struct ban_query_state *bqs; 
     735    char mask[BAN_MASK_LEN]; 
     736    size_t len; 
     737 
     738    if (*state == NULL) 
     739        *state = calloc(1, sizeof(struct ban_query_state)); 
     740    bqs = *state; 
     741 
     742    if (bqs->started == false) { 
     743        bqs->curban = LIST_FIRST(banlist); 
     744        bqs->started = true; 
     745    } 
     746     
     747    /* always run this check because we might be done when we start.. */ 
     748    if (bqs->curban == NULL) { 
     749        /* we're done here.. free bqs and let them leave the loop */ 
     750        free(bqs); 
     751        *argused = 0; 
     752        return CHANMODE_FAIL; /* all done! */ 
     753    } 
     754 
     755    /* okay, we know we've either started or we finished and went home.. */ 
     756    cbp = bqs->curban; 
     757 
     758    len = sprintf(mask, "%s!%s@%s", cbp->nick, cbp->user, cbp->host); 
     759    if (len > (size_t)*argused) { 
     760        *argused = -(len - *argused); 
     761        /* do not advance the list as the consumer is expected not to use 
     762         * this mode since they have no room for it. */ 
     763    } else { 
     764        strcpy(arg, mask); 
     765        *argused = len; 
     766        /* advance the list since they promised us enough space! */ 
     767        bqs->curban = LIST_NEXT(cbp, lp); 
     768    } 
     769 
     770    return CHANMODE_OK; 
     771} 
     772 
     773static HOOK_FUNCTION(can_join_mode_b) { 
     774    struct channel_check_args *ccap = (struct channel_check_args *)data; 
     775    struct channel_ban_list *banlist = 
     776        (struct channel_ban_list *)chanmode_getdata(ccap->chan, 
     777                                                    ircd.cmodes.mode_ban); 
     778    void *ret = (void *)HOOK_COND_OK; /* deny by default. */ 
     779 
     780    ccap->clp->bans = check_bans(banlist, ccap->cli->nick, ccap->cli->user, 
     781            ccap->cli->host, ccap->cli->ip, ccap->cli->orighost); 
     782 
     783    if (ccap->clp->bans) 
     784        return (void *)ERR_BANNEDFROMCHAN; 
     785 
     786    return ret; /* and return.. */ 
     787} 
     788 
     789static HOOK_FUNCTION(can_send_mode_b) { 
     790    struct channel_check_args *ccap = (struct channel_check_args *)data; 
     791 
     792    if (ccap->clp == NULL) 
     793        return (void *)HOOK_COND_NEUTRAL; /* doesn't effect us */ 
     794    if (ccap->clp->bans) 
     795        return (void *)ERR_CANNOTSENDTOCHAN; /* banned, cannot send */ 
     796 
     797    return (void *)HOOK_COND_NEUTRAL; 
     798} 
     799 
     800static HOOK_FUNCTION(can_nick_mode_b) { 
     801    struct channel_check_args *ccap = (struct channel_check_args *)data; 
     802    struct channel_ban_list *banlist = 
     803        (struct channel_ban_list *)chanmode_getdata(ccap->chan, 
     804                                                    ircd.cmodes.mode_ban); 
     805 
     806    if (ccap->clp == NULL) { 
     807        log_debug("can_nick_mode_b() called when client wasn't in channel!"); 
     808        return (void *)HOOK_COND_NEUTRAL; /* not interested.. */ 
     809    } 
     810    if (ccap->clp->bans) 
     811       return (void *)ERR_BANNICKCHANGE; /* hope they handle this right. :) */ 
     812 
     813    /* if they're not banned, make sure the nickname change wouldn't result in 
     814     * a ban either. */ 
     815    if (check_bans(banlist, ccap->extra, ccap->cli->user, ccap->cli->host, 
     816                ccap->cli->ip, ccap->cli->orighost)) 
     817        return (void *)ERR_BANONCHAN; 
     818 
     819    return (void *)HOOK_COND_NEUTRAL; /* eh. */ 
     820} 
     821 
     822static HOOK_FUNCTION(can_send_mode_m) { 
     823    struct channel_check_args *ccap = (struct channel_check_args *)data; 
     824 
     825    if (chanmode_isset(ccap->chan, ircd.cmodes.mode_mod)) 
     826        return (void *)ERR_CANNOTSENDTOCHAN; /* unless overriden, no. */ 
     827    return (void *)HOOK_COND_NEUTRAL; 
     828} 
     829 
     830static HOOK_FUNCTION(can_send_mode_n) { 
     831    struct channel_check_args *ccap = (struct channel_check_args *)data; 
     832 
     833    /* if we're +n and they're not in the channel, don't let them send. */ 
     834    if (chanmode_isset(ccap->chan, ircd.cmodes.mode_nextern) && 
     835            ccap->clp == NULL) 
     836        return (void *)ERR_CANNOTSENDTOCHAN; 
     837    return (void *)HOOK_COND_NEUTRAL; 
     838} 
     839 
     840static HOOK_FUNCTION(can_show_mode_s) { 
     841    struct channel_check_args *ccap = (struct channel_check_args *)data; 
     842 
     843    /* if they're in the channel, it's always okay.  if the channel is +s it's 
     844     * not okay unless they've got the see-hidden-channels privilege, and then 
     845     * it's okay if they're opered.  if the channel isn't +s it's always okay 
     846     * too. */ 
     847    if (ccap->clp != NULL) 
     848        return (void *)HOOK_COND_OK; /* s'not a problem. */ 
     849    else if (chanmode_isset(ccap->chan, ircd.cmodes.mode_secret)) { 
     850        if (CLIENT_OPERATOR(ccap->cli) && 
     851                BPRIV(ccap->cli, ircd.privileges.priv_shc)) 
     852            return (void *)HOOK_COND_ALWAYSOK; /* okay, but sketchy. */ 
     853        else 
     854            return (void *)ERR_NOTONCHANNEL; 
     855    } else 
     856        return (void *)HOOK_COND_OK; /* it's not +s, okay by us. */ 
     857} 
     858 
     859static CHANMODE_FUNC(chanmode_key) { 
     860 
     861    if (set != CHANMODE_CLEAR) { 
     862        if (arg == NULL) 
     863            return CHANMODE_NOARG; 
     864        if (cli != NULL && !CHANOP(cli, chan) && !CLIENT_MASTER(cli)) 
     865            return ERR_CHANOPRIVSNEEDED; 
     866        *argused = 1; 
     867    } 
     868 
     869    switch (set) { 
     870        case CHANMODE_SET: 
     871            if (strchr(arg, ' ') != NULL || strchr(arg, ',') != NULL) 
     872                return CHANMODE_FAIL; /* no spaces or commas in keys */ 
     873            if (cli == NULL && chanmode_isset(chan, mode)) { 
     874                /* this is coming from a server... we do something silly here. 
     875                 * if we have a key currently, we compare the two keys and use 
     876                 * the one which is lexocographically greater (pretty 
     877                 * arbitrary, eh?) */ 
     878                if (strcmp(arg, chanmode_getstrdata(chan, mode)) <= 0) 
     879                    strncpy(chanmode_getstrdata(chan, mode), arg, PASSWDLEN); 
     880                return CHANMODE_OK; 
     881            } 
     882 
     883            strncpy(chanmode_getstrdata(chan, mode), arg, PASSWDLEN); 
     884            chanmode_setflag(chan, mode); 
     885            break; 
     886        case CHANMODE_UNSET: 
     887            memset(chanmode_getstrdata(chan, mode), 0, PASSWDLEN + 1); 
     888            chanmode_unsetflag(chan, mode); 
     889            break; 
     890    } 
     891 
     892    return CHANMODE_OK; 
     893} 
     894static CHANMODE_QUERY_FUNC(chanmode_key_query) { 
     895    size_t len; 
     896 
     897    if (*state == NULL) 
     898        *state = (void *)0x1; /* set it so we don't return more than once */ 
     899    else 
     900        return CHANMODE_FAIL; /* already queried */ 
     901 
     902    if (!chanmode_isset(chan, mode)) { 
     903        *argused = 0; 
     904        return CHANMODE_FAIL; /* not set */ 
     905    } else { 
     906        if ((len = strlen(chanmode_getstrdata(chan, mode))) > 
     907                (size_t)*argused) { 
     908            *argused = -(len - *argused); 
     909            *state = NULL; /* they will have to ask again.. */ 
     910        } else { 
     911            strncpy(arg, chanmode_getstrdata(chan, mode), PASSWDLEN); 
     912            *argused = len; 
     913        } 
     914    } 
     915    return CHANMODE_OK; /* it's set */ 
     916} 
     917 
     918 
     919/* this function is hooked by the can_join event.  just compare the arg (if 
     920 * any) to the key, and see if it's okay. */ 
     921static HOOK_FUNCTION(can_join_mode_k) { 
     922    struct channel_check_args *ccap = (struct channel_check_args *)data; 
     923    char *key = chanmode_getstrdata(ccap->chan, ircd.cmodes.mode_key); 
     924    char *next, *cur; 
     925 
     926    /* ccap->extra should be a comma separated list of keys (or NULL).  we try 
     927     * each one in succession. */ 
     928    if (*key != '\0') { 
     929        if (ccap->extra == NULL || *ccap->extra == '\0') 
     930            return (void *)ERR_BADCHANNELKEY; 
     931        cur = ccap->extra; 
     932        next = strchr(cur, ','); 
     933        while (cur != NULL) { 
     934            if (!strncasecmp(key, cur, 
     935                        (next == NULL ? PASSWDLEN : next - cur))) 
     936                return (void *)HOOK_COND_OK; /* a match */ 
     937            if (next != NULL && *(next + 1) != '\0') { 
     938                cur = next + 1; 
     939                next = strchr(cur, ','); 
     940            } else 
     941                break; 
     942        } 
     943        return (void *)ERR_BADCHANNELKEY; /* no match, or no key */ 
     944    } 
     945 
     946    return (void *)HOOK_COND_OK; /* okay to join. */ 
     947} 
     948 
     949static CHANMODE_FUNC(chanmode_limit) { 
     950    uint32_t limit; 
     951    uint32_t *chl = (uint32_t *)chanmode_getdata(chan, mode); 
     952 
     953    if (cli != NULL && !CHANOP(cli, chan) && !CLIENT_MASTER(cli)) 
     954        return ERR_CHANOPRIVSNEEDED; 
     955    switch (set) { 
     956        case CHANMODE_SET: 
     957            if (arg == NULL) 
     958                return CHANMODE_NOARG; 
     959            *argused = 1; 
     960            limit = str_conv_int(arg, 0); 
     961 
     962            /* if the limit is bogus don't bother. */ 
     963            if (limit == 0) 
     964                return CHANMODE_FAIL; /* bad number */ 
     965             
     966            *chl = limit; 
     967            chanmode_setflag(chan, mode); 
     968            break; 
     969        case CHANMODE_UNSET: 
     970            *chl = 0; 
     971            chanmode_unsetflag(chan, mode); 
     972            *argused = 0; 
     973    } 
     974   
     975    return CHANMODE_OK; 
     976} 
     977 
     978static CHANMODE_QUERY_FUNC(chanmode_limit_query) { 
     979    char buf[16]; 
     980    size_t len; 
     981    uint32_t *chl = (uint32_t *)chanmode_getdata(chan, mode); 
     982 
     983    if (*state == NULL) 
     984        *state = (void *)0x1; /* set it so we don't return more than once */ 
     985    else 
     986        return CHANMODE_FAIL; /* already queried */ 
     987    if (!chanmode_isset(chan, mode)) 
     988        return CHANMODE_FAIL; /* not set */ 
     989    len = sprintf(buf, "%u", *chl); 
     990    if (len > (uint32_t)*argused) { 
     991        *argused = -(len - *argused); 
     992        *state = NULL; /* they must ask again */ 
     993        return CHANMODE_OK; 
     994    } 
     995    strcpy(arg, buf); 
     996    *argused = len; 
     997    return CHANMODE_OK; /* it's set */ 
     998} 
     999 
     1000 
     1001static HOOK_FUNCTION(can_join_mode_l) { 
     1002    struct channel_check_args *ccap = (struct channel_check_args *)data; 
     1003 
     1004    /* if a limit is set and the number of people in the channel is greater 
     1005     * than the limit, don't let them in. */ 
     1006    if (chanmode_getintdata(ccap->chan, ircd.cmodes.mode_limit) && 
     1007            ccap->chan->onchannel > 
     1008            chanmode_getintdata(ccap->chan, ircd.cmodes.mode_limit)) 
     1009        return (void *)ERR_CHANNELISFULL; 
     1010 
     1011    return (void *)HOOK_COND_OK; 
     1012} 
     1013 
     1014static HOOK_FUNCTION(can_act_mode_ov) { 
     1015    struct channel_check_args *ccap = (struct channel_check_args *)data; 
     1016 
     1017    if (ccap->clp == NULL) 
     1018        return (void *)HOOK_COND_NEUTRAL; 
     1019    if (CLINKOP(ccap->clp) || CLINKVOICE(ccap->clp)) 
     1020        return (void *)HOOK_COND_ALWAYSOK;  /* if they're op'd or voiced, 
     1021                                               they can always change nicks 
     1022                                               or send. */ 
     1023    return (void *)HOOK_COND_NEUTRAL; /* not interested. */ 
     1024} 
     1025 
    4551026/* vi:set ts=8 sts=4 sw=4 tw=76 et: */ 
  • trunk/ithildin/modules/ircd/chanmode.h

    r801 r803  
    11/* 
    2  * channel.h: channel (mode) structures and prototypes 
     2 * chanmode.h: channel mode structures and prototypes 
    33 *  
    4  * Copyright 2002 the Ithildin Project. 
     4 * Copyright 2002-2007 the Ithildin Project. 
    55 * See the COPYING file for more information on licensing and use. 
    66 *  
     
    88 */ 
    99 
    10 #ifndef IRCD_CHANNEL_H 
    11 #define IRCD_CHANNEL_H 
     10#ifndef IRCD_CHANMODE_H 
     11#define IRCD_CHANMODE_H 
    1212 
    1313/* 
     
    7676        int *, void **); 
    7777 
    78 #define CHANMODE_FL_A            0x01 
    79 #define CHANMODE_FL_B            0x02 
    80 #define CHANMODE_FL_C            0x04 
    81 #define CHANMODE_FL_D            0x08 
    82 #define CHANMODE_FL_E            0x10 
     78#define CHANMODE_FL_A       0x01 
     79#define CHANMODE_FL_B       0x02 
     80#define CHANMODE_FL_C       0x04 
     81#define CHANMODE_FL_D       0x08 
     82#define CHANMODE_FL_E       0x10 
    8383#define CHANMODE_FL_PREFIX  0x20 
    8484 
    85 #define CHANMODE_SET            1 
    86 #define CHANMODE_UNSET            0 
    87 #define CHANMODE_CLEAR            -1 
     85#define CHANMODE_SET        1 
     86#define CHANMODE_UNSET      0 
     87#define CHANMODE_CLEAR     -1 
    8888 
    8989#define CHANMODE_OK         0 
    90 #define CHANMODE_FAIL       -1 
    91 #define CHANMODE_NOP        -2 
    92 #define CHANMODE_NONEX      -3 
    93 #define CHANMODE_NOARG      -4 
    94  
     90#define CHANMODE_FAIL      -1 
     91#define CHANMODE_NOP       -2 
     92#define CHANMODE_NONEX     -3 
     93#define CHANMODE_NOARG     -4 
     94 
     95void chanmode_init(bool); 
     96void chanmode_deinit(bool); 
    9597uint64_t chanmode_request(unsigned char, unsigned char *, int, 
    9698        chanmode_func, chanmode_query_func, size_t, void *); 
     
    183185}; 
    184186 
    185 LIST_HEAD(chanusers, chanlink); 
    186 LIST_HEAD(userchans, chanlink); 
    187  
    188 /* this structure is used to glue users and channels together.  one structure 
    189  * is allocated per user/chan relationship, and is saved in a linked list on 
    190  * the user's side, and on the channel's side. */ 
    191 struct chanlink { 
    192     client_t  *cli; 
    193     channel_t *chan; 
    194     short   flags; 
    195     short   bans; /* for users only, stores how many bans they have against 
    196                      them */ 
    197  
    198     LIST_ENTRY(chanlink) lpcli; 
    199     LIST_ENTRY(chanlink) lpchan; 
     187/* some functions for generic channel mode handling */ 
     188CHANMODE_FUNC(chanmode_flag); 
     189CHANMODE_QUERY_FUNC(chanmode_flag_query); 
     190CHANMODE_FUNC(chanmode_uflag); 
     191CHANMODE_QUERY_FUNC(chanmode_uflag_query); 
     192 
     193/* this structure is used to hold bans on a channel. */ 
     194#define MAX_BANS_PER_CHANNEL 100 
     195#define BAN_MASK_LEN NICKLEN + USERLEN + HOSTLEN + 3 
     196LIST_HEAD(channel_ban_list, channel_ban); 
     197struct channel_ban { 
     198    char nick[NICKLEN + 1]; /* the three components of ban, split up for easier 
     199                               processing. */ 
     200    char user[USERLEN + 1]; 
     201    char host[HOSTLEN + 1]; 
     202    char who[BAN_MASK_LEN + 1]; 
     203    time_t  when;       /* when the ban was set */ 
     204#define CHANNEL_BAN_BAN 0x01 
     205    unsigned char type; /* reserved for various uses */ 
     206 
     207    LIST_ENTRY(channel_ban) lp; 
    200208}; 
    201209 
    202 char **channel_mdext_iter(char **); 
    203  
    204 struct channel { 
    205     char    name[CHANLEN + 1];         /* our channel's name. */ 
    206     time_t  created;                   /* the timestamp as well as creation time */ 
    207  
    208     unsigned int onchannel;            /* number of people on channel */ 
    209     int            flags; 
    210     struct chanusers users;            /* list of users in channel */ 
    211     uint64_t modes;                    /* the flag-modes for the channel. */ 
    212     char    *mdext;                    /* mdext data */ 
    213  
    214     LIST_ENTRY(channel) lp; 
    215 }; 
    216  
    217 /* create a channel.  give it a name, initially the channel will be empty, 
    218  * so you use...*/ 
    219 channel_t *create_channel(char *); 
    220  
    221 /* add_to_channel.  adds the given client to the given channel, fixes up all 
    222  * structures properly.  the third argument is set if the caller wishes the 
    223  * channel_add event to be hooked.  this is *almost* always the case. */ 
    224 void add_to_channel(client_t *, channel_t *, bool); 
    225  
    226 /* del_from_channel.  removes the user from the given channel, if the 
    227  * channel becomes empty, it is destroyed with...  the third argument is the 
    228  * same as above. */ 
    229 void del_from_channel(client_t *, channel_t *, bool); 
    230  
    231 /* destroy_channel.  destroys a channel and returns all the good stuff to 
    232  * memory */ 
    233 void destroy_channel(channel_t *); 
    234  
    235 /* find a channel by name */ 
    236 #define find_channel(name) hash_find(ircd.hashes.channel, name) 
    237  
    238 /* finds a channel/user's chanlink entity and returns it (or NULL if it doesn't 
    239  * exist).  Also, onchannel() is a wraparound checker to give a boolean return 
    240  * based on this info. */ 
    241 struct chanlink *find_chan_link(client_t *, channel_t *); 
    242 #define onchannel(cli, chan)                                               \ 
    243     (find_chan_link(cli, chan) != NULL ? 1 : 0) 
    244  
    245 #define check_channame(name)                                               \ 
    246     (name && (*name == '#') &&                                             \ 
    247      istr_okay(ircd.maps.channel, name)) 
    248  
    249 /* this structure is used by channel_check_access to pass to its various hook 
    250  * functions when checking if a channel can have an action performed on it (or 
    251  * something.. */ 
    252 struct channel_check_args { 
    253     channel_t *chan;            /* the channel */ 
    254     client_t *cli;            /* the client */ 
    255     struct chanlink *clp;   /* if they're in the channel, this is the link. */ 
    256     char    *extra;            /* extra data */ 
    257 }; 
    258  
    259 /* this function determines whether a client (cli) can perform some action 
    260  * related to a channel (chan).  it can be used in various manners and with 
    261  * various events.  it calls the hooks for the specified event, which should 
    262  * return one of the five CHANNEL_ statuses above, or an error numeric to send 
    263  * to the user (which should be of the format '%s :...' unless your function is 
    264  * going to have some special handling). */ 
    265  
    266 /* these three are synonyms for the definitions in event.h */ 
    267 #define CHANNEL_CHECK_OVERRIDE        HOOK_COND_SPASS 
    268 #define CHANNEL_CHECK_OK        HOOK_COND_PASS 
    269 #define CHANNEL_CHECK_NO        HOOK_COND_FAIL 
    270 int channel_check_access(client_t *, channel_t *, char *, event_t *); 
    271  
    272 /* this lets you check to see if a user can enter a channel. */ 
    273 #define can_can_join_channel(cli, chan, arg)                                \ 
    274 channel_check_access(cli, chan, arg, ircd.events.can_join_channel) 
    275 /* this lets you check to see if a user can see a channel's details. */ 
    276 #define can_can_see_channel(cli, chan)                                        \ 
    277 channel_check_access(cli, chan, NULL, ircd.events.can_see_channel) 
    278  
    279 /* this is like the above two, except that you also pass the message the user 
    280  * is attempting to send to the channel. */ 
    281 #define can_can_send_channel(cli, chan, msg)                                \ 
    282 channel_check_access(cli, chan, msg, ircd.events.can_send_channel) 
    283  
    284 /* this is like the above three, except for nick changes in the channel. 
    285  * hopefully this is it. :) */ 
    286 #define can_can_nick_channel(cli, chan, nick)                                \ 
    287 channel_check_access(cli, chan, nick, ircd.events.can_nick_channel); 
    288  
    289 /* chancmp, like nickcmp in client.c */ 
    290 int chancmp(char *, char *, size_t); 
     210/* some macros... the link variety are a lot faster if you've already taken 
     211 * the time to see if they're in the channel (and have saved the chanlink 
     212 * entry). */ 
     213#define CHANOP(cli, chan) chanmode_isprefix(chan, cli, '@') 
     214#define CLINKOP(clp) chanlink_ismode(clp, ircd.cmodes.mode_op) 
     215#define CHANVOICE(cli, chan) chanmode_isprefix(chan, cli, '+') 
     216#define CLINKVOICE(clp) chanlink_ismode(clp, ircd.cmodes.mode_voice) 
    291217 
    292218#endif 
  • trunk/ithildin/modules/ircd/channel.c

    r801 r803  
    22 * channel.c: channel structure management code 
    33 *  
    4  * Copyright 2002 the Ithildin Project. 
     4 * Copyright 2002-2007 the Ithildin Project. 
    55 * See the COPYING file for more information on licensing and use. 
    66 *  
    77 * This file provides the basic functions necessary to create/destroy/manage 
    8  * channel structures, and lists of people with channels.  It also provides the 
    9  * basics of channel mode management. 
     8 * channel structures, and lists of people with channels. 
    109 */ 
    1110 
     
    115114} 
    116115 
    117 /******************************************************************************* 
    118  * channel mode goodies here. 
    119  ******************************************************************************/ 
    120 static void chanmode_build_lists(void); 
    121  
    122 uint64_t chanmode_request(unsigned char suggested, unsigned char *actual, 
    123         int flags, chanmode_func changefn, chanmode_query_func queryfn, 
    124         size_t extra, void *extdata) { 
    125     struct chanmode *md = NULL; 
    126     int i, j; 
    127     unsigned char c; 
    128  
    129     /* try and find the first/best available mode */ 
    130     if (ircd.cmodes.modes[suggested].avail) 
    131         md = &ircd.cmodes.modes[suggested]; 
    132     else { 
    133         if (islower(suggested)) 
    134             c = toupper(suggested); 
    135         else 
    136             c = tolower(suggested); 
    137  
    138         if (ircd.cmodes.modes[c].avail) 
    139             md = &ircd.cmodes.modes[c]; 
    140         else { 
    141             for (i = 0;i < 256;i++) { 
    142                 if (ircd.cmodes.modes[i].avail && ircd.umodes.modes[i].mask) { 
    143                     md = &ircd.cmodes.modes[i]; 
    144                     break; 
    145                 } 
    146             } 
    147  
    148             if (md == NULL) 
    149                 return 0; 
    150         } 
    151     } 
    152  
    153     /* fill in the stuff */ 
    154     md->avail = 0; 
    155     md->umask = 0; 
    156     md->prefix = '\0'; 
    157     md->changefunc = changefn; 
    158     md->queryfunc = queryfn; 
    159     md->flags = flags; 
    160     md->mdi = NULL; 
    161  
    162     if (flags == CHANMODE_FL_PREFIX) { 
    163         /* we have to find the first free flag, if any, to use.  to do 
    164          * this, for each value from 0x1 to 0x80 moving in powers of two, 
    165          * we have to check if any of the channel modes are using it.  fun 
    166          * stuff. */ 
    167         for (i = 0;i < 16;i++) { 
    168             for (j = 0;j < 256;j++) { 
    169                 if (ircd.cmodes.modes[j].umask == 1 << i) 
    170                     break; 
    171             } 
    172             if (j == 256) 
    173                 break; /* we have a weiner */ 
    174         } 
    175         if (i == 16) { 
    176             /* couldn't get a mode.  yuck. */ 
    177             md->avail = 1; 
    178             return 0; 
    179         } 
    180         md->umask = 1 << i; 
    181         md->prefix = *(unsigned char *)extdata; 
    182         ircd.cmodes.pfxmap[md->prefix] = md; /* map back */ 
    183     } 
    184  
    185     if (extra > 0) 
    186         md->mdi = create_mdext_item(ircd.mdext.channel, extra); 
    187      
    188     chanmode_build_lists(); 
    189  
    190     *actual = md->mode; 
    191     return md->mask; 
    192 } 
    193  
    194 /* this function very simply releases a mode and calls the list rebuilder. */ 
    195 void chanmode_release(unsigned char mode) { 
    196     channel_t *chan; 
    197     int dummy; 
    198      
    199     /* clear the mode from all the channels .. */ 
    200     LIST_FOREACH(chan, ircd.lists.channels, lp) 
    201         ircd.cmodes.modes[mode].changefunc(NULL, chan, mode, CHANMODE_CLEAR, NULL, &dummy); 
    202  
    203     /* we don't touch the mode or mask members because those are set elsewhere 
    204      * and need to be kept the way they are. */ 
    205     ircd.cmodes.modes[mode].avail = 1; /* mark it as available */ 
    206  
    207     ircd.cmodes.modes[mode].umask = 0; 
    208     if (ircd.cmodes.modes[mode].prefix != '\0') { 
    209         ircd.cmodes.pfxmap[ircd.cmodes.modes[mode].prefix] = NULL; 
    210         ircd.cmodes.modes[mode].prefix = '\0'; 
    211     } 
    212     ircd.cmodes.modes[mode].changefunc = NULL; 
    213     ircd.cmodes.modes[mode].queryfunc = NULL; 
    214     ircd.cmodes.modes[mode].flags = 0; 
    215     if (ircd.cmodes.modes[mode].mdi != NULL) 
    216         destroy_mdext_item(ircd.mdext.channel, ircd.cmodes.modes[mode].mdi); 
    217     chanmode_build_lists(); 
    218 } 
    219  
    220 void chanmode_update_funcs(unsigned char mode, chanmode_func changefunc, 
    221         chanmode_query_func queryfunc) { 
    222     struct chanmode *cmp = &ircd.cmodes.modes[mode]; 
    223  
    224     if (cmp->avail || !cmp->mask) /* only if it exists.. */ 
    225         return; 
    226  
    227     cmp->changefunc = changefunc; 
    228     cmp->queryfunc = queryfunc; 
    229 } 
    230  
    231 static void chanmode_build_lists(void) { 
    232     int i; 
    233     unsigned char imodes[256]; 
    234     unsigned char *s; 
    235  
    236     /* fill in the 'avail' modestring thing. */ 
    237     s = ircd.cmodes.avail; 
    238     for (i = 0;i < 256;i++) { 
    239         if (!ircd.cmodes.modes[i].avail && ircd.cmodes.modes[i].mask) 
    240             *s++ = ircd.cmodes.modes[i].mode; 
    241     } 
    242     *s = '\0'; 
    243  
    244     /* now do the prefix thing.  we make two passes to make it easier. */ 
    245     s = ircd.cmodes.pmodes; 
    246     for (i = 0;i < 256;i++) { 
    247         if (!ircd.cmodes.modes[i].avail && ircd.cmodes.modes[i].prefix) 
    248             *s++ = ircd.cmodes.modes[i].mode; 
    249     } 
    250     *s = '\0'; 
    251  
    252     s = ircd.cmodes.prefix; 
    253     *s++ = '('; 
    254     for (i = 0;i < 256;i++) { 
    255         if (!ircd.cmodes.modes[i].avail && ircd.cmodes.modes[i].prefix) 
    256             *s++ = ircd.cmodes.modes[i].mode; 
    257     } 
    258     *s++ = ')'; 
    259     for (i = 0;i < 256;i++) { 
    260         if (!ircd.cmodes.modes[i].avail && ircd.cmodes.modes[i].prefix) 
    261             *s++ = ircd.cmodes.modes[i].prefix; 
    262     } 
    263     *s = '\0'; 
    264  
    265     /* now do a/b/c/d/e */ 
    266     s = imodes; 
    267 #define CHANMODE_BUILD_TYPE(_flg) do {                                        \ 
    268     for (i = 0;i < 256;i++) {                                                 \ 
    269         if (!ircd.cmodes.modes[i].avail &&                                    \ 
    270                 ircd.cmodes.modes[i].flags & _flg)                            \ 
    271             *s++ = ircd.cmodes.modes[i].mode;                                 \ 
    272     }                                                                         \ 
    273     *s++ = ',';                                                               \ 
    274 } while (0) 
    275  
    276     CHANMODE_BUILD_TYPE(CHANMODE_FL_A); 
    277     CHANMODE_BUILD_TYPE(CHANMODE_FL_B); 
    278     CHANMODE_BUILD_TYPE(CHANMODE_FL_C); 
    279     CHANMODE_BUILD_TYPE(CHANMODE_FL_D); 
    280     CHANMODE_BUILD_TYPE(CHANMODE_FL_E); 
    281     *--s = '\0'; /* wipe out that last comma */ 
    282     /* also, if s - 1 is a comma (meaning we have no 'E' modes, delete that 
    283      * comma since 'E' is non-standard */ 
    284     if (*(s - 1) == ',') 
    285         *--s = '\0'; 
    286  
    287     /* add these two in for special mode support stuff */ 
    288     add_isupport("PREFIX", ISUPPORT_FL_STR, (char *)ircd.cmodes.prefix); 
    289     add_isupport("CHANMODES", ISUPPORT_FL_STR, (char *)imodes); 
    290 } 
    291  
    292 int chanmode_set(unsigned char mode, client_t *cli, channel_t *chan, char *arg, 
    293         int *argused) { 
    294     struct chanmode *cmp = &ircd.cmodes.modes[mode]; 
    295  
    296     if (cmp->avail || !cmp->mask) /* only if it exists.. */ 
    297         return CHANMODE_NONEX; 
    298  
    299     /* otherwise, just try and set the mode with the given functions, returning 
    300      * the value as requested */ 
    301     return cmp->changefunc(cli, chan, mode, CHANMODE_SET, arg, argused); 
    302 } 
    303  
    304 int chanmode_setprefix(unsigned char prefix, channel_t *chan, char *arg, 
    305         int *argused) { 
    306     struct chanmode *cmp = ircd.cmodes.pfxmap[prefix]; 
    307  
    308     if (cmp == NULL) 
    309         return CHANMODE_NONEX; 
    310  
    311     /* found it, now set it */ 
    312     return cmp->changefunc(NULL, chan, cmp->mode, CHANMODE_SET, arg, argused); 
    313 } 
    314  
    315 int chanmode_unset(unsigned char mode, client_t *cli, channel_t *chan, 
    316         char *arg, int *argused) { 
    317     struct chanmode *cmp = &ircd.cmodes.modes[mode]; 
    318  
    319     if (cmp->avail || !cmp->mask) /* only if it exists.. */ 
    320         return CHANMODE_NONEX; 
    321  
    322     /* otherwise, just try and set the mode with the given functions, returning 
    323      * the value as requested */ 
    324     return cmp->changefunc(cli, chan, mode, CHANMODE_UNSET, arg, argused); 
    325 } 
    326  
    327 int chanmode_unsetprefix(unsigned char prefix, channel_t *chan, char *arg, 
    328         int *argused) { 
    329     struct chanmode *cmp = ircd.cmodes.pfxmap[prefix]; 
    330  
    331     if (cmp == NULL) 
    332         return CHANMODE_NONEX; 
    333  
    334     /* found it, now unset it */ 
    335     return cmp->changefunc(NULL, chan, cmp->mode, CHANMODE_UNSET, arg, argused); 
    336 } 
    337  
    338 int chanmode_query(unsigned char mode, channel_t *chan, char *arg, 
    339         int *argused, void **state) { 
    340     struct chanmode *cmp = &ircd.cmodes.modes[mode]; 
    341  
    342     if (cmp->avail || !cmp->mask) /* only if it exists.. */ 
    343         return CHANMODE_NONEX; 
    344  
    345     /* let's ask 'em about it. */ 
    346     return cmp->queryfunc(chan, mode, arg, argused, state); 
    347 } 
    348  
    349 int chanmode_isprefix(channel_t *chan, client_t *cli, unsigned char prefix) { 
    350     struct chanlink *clp; 
    351     struct chanmode *cmp = ircd.cmodes.pfxmap[prefix]; 
    352  
    353     if (cmp == NULL) 
    354         return 0; /* no such mode. */ 
    355  
    356     /* found it, now see if it's set */ 
    357     LIST_FOREACH(clp, &chan->users, lpchan) { 
    358         if (clp->cli == cli) 
    359             return chanlink_ismode(clp, cmp->mode); 
    360     } 
    361  
    362     /* not found, no status */ 
    363     return 0; 
    364 } 
    365  
    366 char *chanmode_getprefixes(channel_t *chan, client_t *cli) { 
    367     static unsigned char pfx[64]; 
    368     struct chanlink *clp = find_chan_link(cli, chan); 
    369     unsigned char *s = ircd.cmodes.pmodes; 
    370     int i = 0; 
    371  
    372     if (clp != NULL) { 
    373         while (*s != '\0') { 
    374             if (clp->flags & ircd.cmodes.modes[*s].umask) 
    375                 pfx[i++] = ircd.cmodes.modes[*s].prefix; 
    376             s++; 
    377         } 
    378     } 
    379  
    380     pfx[i] = '\0'; 
    381     return (char *)pfx; 
    382 } 
    383  
    384 /* this function returns two strings.  the first is all the modes set on the 
    385  * channel.  the second is any arguments for the modes, but may or may not be 
    386  * truncated. */ 
    387 const char **chanmode_getmodes(channel_t *chan) { 
    388     static const char *ret[2]; 
    389     static unsigned char modes[64]; 
    390     static char *modebuf = NULL; 
    391     static size_t mbsize = 64; 
    392     int optused, len = 0, m = 1; 
    393     unsigned char *i = ircd.cmodes.avail; 
    394     void *state; 
    395  
    396     if (modebuf == NULL) 
    397         modebuf = malloc(mbsize); 
    398  
    399     modes[0] = '+'; 
    400     *modebuf = '\0'; 
    401  
    402     while (*i != '\0') { 
    403         state = NULL; 
    404  
    405         if (chan->modes & ircd.cmodes.modes[*i].mask) { 
    406             optused = mbsize - len; 
    407             while (!chanmode_query(*i, chan, modebuf + len, &optused, &state)) { 
    408                 if (optused < 0) { 
    409                     mbsize += -optused + 2; 
    410                     modebuf = realloc(modebuf, mbsize); 
    411                     optused = mbsize - len; 
    412                     continue; 
    413                 } 
    414                 modes[m++] = *i; 
    415                 if (optused > 0) { 
    416                     len += optused; 
    417                     modebuf[len++] = ' '; 
    418                     modebuf[len] = '\0'; 
    419                 } 
    420             } 
    421         } 
    422         i++; 
    423     } 
    424     modes[m] = '\0'; 
    425     if (len > 0) 
    426         modebuf[--len] = '\0'; /* nerf that extra space */ 
    427  
    428     ret[0] = (char *)modes; 
    429     ret[1] = modebuf; 
    430     return ret; 
    431 } 
    432  
    433116char **channel_mdext_iter(char **last) { 
    434117    static int started = 0; 
  • trunk/ithildin/modules/ircd/channel.h

    r801 r803  
    22 * channel.h: channel (mode) structures and prototypes 
    33 *  
    4  * Copyright 2002 the Ithildin Project. 
     4 * Copyright 2002-2007 the Ithildin Project. 
    55 * See the COPYING file for more information on licensing and use. 
    66 *  
     
    1010#ifndef IRCD_CHANNEL_H 
    1111#define IRCD_CHANNEL_H 
    12  
    13 /* 
    14  * channel mode fun.  this is a lot like the usermode request/release system, 
    15  * except that it's a bit more complicated.  There are effectively six (yes, 
    16  * six) types of channel modes.  The first are types A-E, and work as follows: 
    17  * Modes of type A add or remove an item from a list.  They always have 
    18  * parameters.  Modes of type B change a setting.  They always have a 
    19  * parameter.  Modes of type C change a setting, but only have a parameter when 
    20  * being set.  Modes of type E (yes E) change a setting, but only have a 
    21  * parameter when being *unset*, and modes of type D change a boolean setting 
    22  * and never take a parameter.  Last but not least are 'PREFIX' modes which 
    23  * change a flag on a user in the channel.  All modes should take handler 
    24  * functions which will be called when the mode is set/unset.  The handler 
    25  * functions should be: 
    26  * int func(client *, channel *, unsigned char, int, char *, int *) 
    27  * the first argument should be the client changing the mode (if any, there 
    28  * won't always be one!) this is handy for passing errors or providing custom 
    29  * behavior. 
    30  * the next argument is the channel on which the mode is being set, the third 
    31  * is the mode character given (this allows several modes to all coalesce into 
    32  * one function if that behavior is desired), the fourth will be one of five 
    33  * values: 
    34  * - CHANMODE_SET to set the mode normally 
    35  * - CHANMODE_UNSET to unset the * mode normally 
    36  * - CHANMODE_CLEAR to clear any data held by the mode (free allocated data, 
    37  *   etc.  called when a channel or mode is being destroyed/release) 
    38  * the fifth argument is the next argument in the mode command. the final holds 
    39  * a return value which specifies whether the argument was used or not.  the 
    40  * int should be set to 1 if the argument is used, and 0 if it isn't.  
    41  * 
    42  * return values: 
    43  * CHANMODE_OK: Change/request was successfully made 
    44  * CHANMODE_NOP: This was an n-op (nothing happened) 
    45  * CHANMODE_FAIL: The change or request failed 
    46  * CHANMODE_NONEX: The mode does not exist 
    47  * CHANMODE_NOARG: The mode needed an argument and none was given 
    48  * number > 0: Equivalent to CHANMODE_FAIL with the value of a numeric to 
    49  *             return to the user. 
    50  */ 
    51  
    52 #define CHANMODE_FUNC(x)                                                    \ 
    53     int x(client_t *cli, channel_t *chan, unsigned char mode, int set,      \ 
    54             char *arg __UNUSED, int *argused __UNUSED) 
    55 typedef int (*chanmode_func)(client_t *, channel_t *, unsigned char, 
    56         int, char *, int *); 
    57  
    58 /* 
    59  * Channel mode queries:  These work a lot like the chanmode_func stuff but 
    60  * do not expect a client.  They exist simply to return state to people who 
    61  * want to know.  The important item is the fifth argument, a private state 
    62  * variable.  When querying begins the pointer value pointed to be state 
    63  * must be NULL.  The value may never be changed, and any memory allocations 
    64  * occuring on behalf of the queryer will be freed on the final query when 
    65  * no more data can be reset/queried. 
    66  * 
    67  * return values: 
    68  * CHANMODE_OK: Change/request was successfully made 
    69  * CHANMODE_FAIL: The change or request failed 
    70  * CHANMODE_NONEX: The mode does not exist 
    71  */ 
    72 #define CHANMODE_QUERY_FUNC(x)                                              \ 
    73    int x(channel_t *chan, unsigned char mode, char *arg __UNUSED,           \ 
    74            int *argused __UNUSED, void **state) 
    75 typedef int (*chanmode_query_func)(channel_t *, unsigned char, char *, 
    76         int *, void **); 
    77  
    78 #define CHANMODE_FL_A            0x01 
    79 #define CHANMODE_FL_B            0x02 
    80 #define CHANMODE_FL_C            0x04 
    81 #define CHANMODE_FL_D            0x08 
    82 #define CHANMODE_FL_E            0x10 
    83 #define CHANMODE_FL_PREFIX  0x20 
    84  
    85 #define CHANMODE_SET            1 
    86 #define CHANMODE_UNSET            0 
    87 #define CHANMODE_CLEAR            -1 
    88  
    89 #define CHANMODE_OK         0 
    90 #define CHANMODE_FAIL       -1 
    91 #define CHANMODE_NOP        -2 
    92 #define CHANMODE_NONEX      -3 
    93 #define CHANMODE_NOARG      -4 
    94  
    95 uint64_t chanmode_request(unsigned char, unsigned char *, int, 
    96         chanmode_func, chanmode_query_func, size_t, void *); 
    97 void chanmode_release(unsigned char); 
    98 void chanmode_update_funcs(unsigned char, chanmode_func, 
    99         chanmode_query_func); 
    100 /* ways to set and unset channel modes.  channel modes are typically set by 
    101  * their mode character, but can also be set by prefix in the case of userflag 
    102  * types. */ 
    103 int chanmode_set(unsigned char, client_t *, channel_t *, char *, int *); 
    104 int chanmode_setprefix(unsigned char, channel_t *, char *, int *); 
    105  
    106 int chanmode_unset(unsigned char, client_t *, channel_t *, char *, int *); 
    107 int chanmode_unsetprefix(unsigned char, channel_t *, char *, int *); 
    108  
    109 int chanmode_query(unsigned char, channel_t *, char *, int *, void **); 
    110  
    111 #define chanmode_setflag(chan, themode)                                       \ 
    112 (chan->modes |= ircd.cmodes.modes[themode].mask) 
    113 #define chanmode_unsetflag(chan, themode)                                     \ 
    114 (chan->modes &= ~ircd.cmodes.modes[themode].mask) 
    115  
    116 /* various checks to see if channel modes are set in specific ways.  you can 
    117  * check to see if a flag-type mode is set on a channel, or you can check to 
    118  * see if a user has a certain prefix.  lastly, you can get the data for a 
    119  * specific mode (data type) */ 
    120 #define chanmode_isset(chan, themode) \ 
    121 ((ircd.cmodes.modes[themode].avail == 0 &&                                \ 
    122   ircd.cmodes.modes[themode].mask) ?                                      \ 
    123  (chan->modes & ircd.cmodes.modes[themode].mask) :                        \ 
    124  0) 
    125  
    126 int chanmode_isprefix(channel_t *, client_t *, unsigned char); 
    127  
    128 #define chanlink_ismode(clp, mode)                                        \ 
    129 (clp->flags & ircd.cmodes.modes[mode].umask) 
    130  
    131 #define chanmode_getdata(chan, themode)                                   \ 
    132 ((ircd.cmodes.modes[themode].avail == 0 &&                                \ 
    133   ircd.cmodes.modes[themode].mdi != NULL) ?                               \ 
    134  (chan->mdext + ircd.cmodes.modes[themode].mdi->offset) :                 \ 
    135  NULL) 
    136  
    137 #define chanmode_getintdata(chan, themode)                                \ 
    138 ((ircd.cmodes.modes[themode].avail == 0 &&                                \ 
    139   ircd.cmodes.modes[themode].mdi != NULL) ?                               \ 
    140  *(((uint32_t *)(chan->mdext +                                           \ 
    141              ircd.cmodes.modes[themode].mdi->offset))) :                  \ 
    142  0xFFFFFFFF) 
    143  
    144 #define chanmode_getstrdata(chan, themode)                                \ 
    145 ((ircd.cmodes.modes[themode].avail == 0 &&                                \ 
    146   ircd.cmodes.modes[themode].mdi != NULL) ?                               \ 
    147  ((char *)chan->mdext) + ircd.cmodes.modes[themode].mdi->offset :         \ 
    148  NULL) 
    149  
    150 /* this function returns a \0 terminated list of a client's prefixes in a 
    151  * channel, in a static character array. */ 
    152 char *chanmode_getprefixes(channel_t *, client_t *); 
    153  
    154 /* These two map prefixes to channel modes and vice versa. */ 
    155 #define chanmode_prefixtomode(c)                                          \ 
    156 (ircd.cmodes.pfxmap[(unsigned char)c] != NULL ?                           \ 
    157  ircd.cmodes.pfxmap[(unsigned char)c]->mode : '\0')                        
    158   
    159 #define chanmode_modetoprefix(c)                                          \ 
    160 (ircd.cmodes.modes[(unsigned char)c].umask ?                              \ 
    161  ircd.cmodes.modes[(unsigned char)c].prefix : '\0') 
    162  
    163 const char **chanmode_getmodes(channel_t *); 
    164  
    165 /* grab the offset of a mode. */ 
    166 #define modeoffset(mode) ircd.cmodes.modes[mode].mdi->offset 
    167  
    168 struct chanmode { 
    169     unsigned char mode;         /* the mode character */ 
    170     char    avail;              /* whether it is available or not */ 
    171  
    172     uint64_t mask;              /* the mask for this mode */ 
    173     short   umask;              /* the mask for a chanlink setting, if this is a 
    174                                    chanuser mode */ 
    175     unsigned char prefix;       /* if this is a user-flag, it has a prefix, this is 
    176                                    the prefix (specified by the caller in extdata). 
    177                                    no error checking is done on this value. */ 
    178     chanmode_func changefunc;  /* the symbol/function to change the mode */ 
    179     chanmode_query_func queryfunc; /* the symbol/function to query the mode */ 
    180     int            flags;       /* flags given for this mode */ 
    181     struct mdext_item *mdi;     /* the mdext_item which describes the channel mode. 
    182                                    allocated automatically.  */ 
    183 }; 
    18412 
    18513LIST_HEAD(chanusers, chanlink); 
     
    20735 
    20836    unsigned int onchannel;            /* number of people on channel */ 
    209     int            flags; 
     37    int     flags; 
    21038    struct chanusers users;            /* list of users in channel */ 
    21139    uint64_t modes;                    /* the flag-modes for the channel. */ 
  • trunk/ithildin/modules/ircd/client.c

    r801 r803  
    22 * client.c: client structure management functions 
    33 *  
    4  * Copyright 2002 the Ithildin Project. 
     4 * Copyright 2002-2007 the Ithildin Project. 
    55 * See the COPYING file for more information on licensing and use. 
    66 *  
    7  * This file provides mechanisms for creating/destroy client structures, as 
    8  * well as registering them on the server and setting/unsetting user modes on 
    9  * them. 
     7 * This file provides mechanisms for creating/destroying/manipulating 
     8 * user structures as well as registering them on the server.  In addition 
     9 * the client history is kept here. 
    1010 */ 
    1111 
     
    313313} 
    314314 
    315 /* mode goodies below here */ 
    316 uint64_t usermode_request(unsigned char suggested, unsigned char *actual, 
    317         int flags, int sflag, usermode_func changefunc) { 
    318     struct usermode *md = NULL; 
    319     uint64_t allmodes = 0; 
    320     int i; 
    321     unsigned char c; 
    322  
    323     /* build a list of all our currently in-use modes (some modes are 
    324      * inaccessible, so only do it for modes which have been initialized and 
    325      * are unavailable */ 
    326     for (i = 0;i < 256;i++) { 
    327         if (!ircd.umodes.modes[i].avail && ircd.umodes.modes[i].mask) 
    328             allmodes |= ircd.umodes.modes[i].mask; 
    329     } 
    330  
    331     if (ircd.umodes.modes[suggested].avail) 
    332         md = &ircd.umodes.modes[suggested]; 
    333     else { 
    334         if (islower(suggested)) 
    335             c = toupper(suggested); 
    336         else 
    337             c = tolower(suggested); 
    338  
    339         if (ircd.umodes.modes[c].avail) 
    340             md = &ircd.umodes.modes[c]; 
    341         else { 
    342             for (i = 0;i < 256;i++) { 
    343                 if (ircd.umodes.modes[i].avail && ircd.umodes.modes[i].mask) { 
    344                     md = &ircd.umodes.modes[i]; 
    345                     break; 
    346                 } 
    347             } 
    348  
    349             /* *still* NULL?  nothing free */ 
    350             if (md == NULL) 
    351                 return 0; 
    352         } 
    353     } 
    354  
    355     md->avail = 0; /* mark it used */ 
    356     md->flags = flags; 
    357     md->changefunc = changefunc; 
    358     md->sflag = sflag; 
    359     *actual = md->mode; 
    360  
    361     allmodes |= md->mask; 
    362  
    363     /* rebuild our mode string */ 
    364     strcpy(ircd.umodes.avail, usermode_getstr(allmodes, 0) + 1); 
    365      
    366     return md->mask; 
    367 } 
    368  
    369 void usermode_release(unsigned char mode) { 
    370     uint64_t allmodes = 0; 
    371     int i; 
    372  
    373     /* same as above, see what is available to rebuild the modestring */ 
    374     for (i = 0;i < 256;i++) { 
    375         if (!ircd.umodes.modes[i].avail && ircd.umodes.modes[i].mask) 
    376             allmodes |= ircd.umodes.modes[i].mask; 
    377     } 
    378      
    379     /* mark our released mode available, and remove it from the potential list 
    380      * of modes */ 
    381     ircd.umodes.modes[mode].avail = 1; 
    382     ircd.umodes.modes[mode].flags = 0; 
    383     ircd.umodes.modes[mode].changefunc = NULL; 
    384     allmodes &= ~ircd.umodes.modes[mode].mask; 
    385  
    386     strcpy(ircd.umodes.avail, usermode_getstr(allmodes, 0) + 1); 
    387 } 
    388  
    389 void usermode_update_func(unsigned char mode, usermode_func changefunc) { 
    390     struct usermode *md = &ircd.umodes.modes[mode]; 
    391  
    392     if (md->avail || !md->mask) 
    393         return 0; 
    394  
    395     md->changefunc = changefunc; 
    396 } 
    397  
    398 unsigned char *usermode_getstr(uint64_t modes, char global) { 
    399     int i; 
    400     int si; /* index to string */ 
    401     static unsigned char string[66]; 
    402  
    403     string[0] = '+'; /* prefix with a + */ 
    404  
    405     for (i = 0, si = 1;i < 256;i++) { 
    406         if (modes & ircd.umodes.modes[i].mask && 
    407                 (!global || ircd.umodes.modes[i].flags & USERMODE_FL_GLOBAL)) 
    408             string[si++] = ircd.umodes.modes[i].mode; 
    409     } 
    410     string[si] = '\0'; 
    411  
    412     return string; 
    413 } 
    414  
    415 uint64_t usermode_getmask(unsigned char *str, char global) { 
    416     uint64_t mask = 0; 
    417     unsigned char *s = str; 
    418  
    419     while (*s) { 
    420         if (!global || ircd.umodes.modes[*s].flags & USERMODE_FL_GLOBAL) 
    421            mask |= ircd.umodes.modes[*s++].mask; 
    422         else 
    423             s++; 
    424     } 
    425      
    426  
    427     return mask; 
    428 } 
    429  
    430 void usermode_diff(uint64_t old, uint64_t new, char *result, char global) { 
    431     int i; 
    432     char *s = result; 
    433  
    434     /* first see if they set anything */ 
    435     *s++ = '+'; 
    436     for (i = 0;i < 256;i++) { 
    437         /* if this is a valid mode, see if it changed positively */ 
    438         if ((!global || ircd.umodes.modes[i].flags & USERMODE_FL_GLOBAL) && 
    439                 !(old & ircd.umodes.modes[i].mask) &&  
    440                 (new & ircd.umodes.modes[i].mask)) 
    441             *s++ = ircd.umodes.modes[i].mode; 
    442     } 
    443     /* see if any changes were done positively, if not, dike the '+' */ 
    444     if (*(s - 1) == '+') 
    445         s = s - 1; 
    446     /* now see if they unset anything */ 
    447     *s++ = '-'; 
    448     for (i = 0;i < 256;i++) { 
    449         /* if this is a valid mode, see if it changed negatively */ 
    450         if ((!global || ircd.umodes.modes[i].flags & USERMODE_FL_GLOBAL) && 
    451                 (old & ircd.umodes.modes[i].mask) &&  
    452                 !(new & ircd.umodes.modes[i].mask)) 
    453             *s++ = ircd.umodes.modes[i].mode; 
    454     } 
    455     /* see if any changes were done negatively, if not, dike the '-' as done 
    456      * above. */ 
    457     if (*(s - 1) == '-') 
    458         s = s - 1; 
    459  
    460     *s = '\0'; /* and terminate. */ 
    461 } 
    462  
    463 int usermode_set(unsigned char mode, client_t *cli, client_t *on, char *arg, 
    464         int *argused) { 
    465     struct usermode *md = &ircd.umodes.modes[mode]; 
    466  
    467     if (md->avail || !md->mask) 
    468         return 0; 
    469  
    470     if (on->modes & md->mask) 
    471         return 1; /* they already did it... */ 
    472  
    473     /* always call the set function.  if they're not our client, we ignore the 
    474      * return value. */ 
    475     if ((md->changefunc != NULL && 
    476                 !md->changefunc(cli, on, mode, 1, arg, argused)) && MYCLIENT(on)) 
    477         return 0; 
    478     /* if they're local, not opered, and the mode is an oper mode, don't let 
    479      * them set it. */ 
    480     if (MYCLIENT(on) && !OPER(on) && md->flags & USERMODE_FL_OPER) 
    481         return 0; /* no no. */ 
    482  
    483     /* okay, so, it's fine then, add away */ 
    484     on->modes |= md->mask; 
    485  
    486     /* if the mode has a send flag, add them to the group for it (force the add 
    487      * no matter what the settings for the sflag) */ 
    488     if (md->sflag > -1 && MYCLIENT(on)) 
    489         add_to_send_flag(md->sflag, on, true); 
    490  
    491     return 1; 
    492 } 
    493  
    494  
    495 int usermode_unset(unsigned char mode, client_t *cli, client_t *on, char *arg, 
    496         int *argused) { 
    497     struct usermode *md = &ircd.umodes.modes[mode]; 
    498  
    499     if (md->avail || !md->mask) 
    500         return 0; 
    501  
    502     if (!(on->modes & md->mask)) 
    503         return 1; /* they're not set to that mode */ 
    504  
    505     /* always call the unset function.  if they're not our client, we ignore 
    506      * the return value. */ 
    507     if ((md->changefunc != NULL && 
    508                 !md->changefunc(cli, on, mode, 0, arg, argused)) && MYCLIENT(on)) 
    509         return 0; 
    510  
    511     /* approved for removal */ 
    512     on->modes &= ~md->mask; 
    513  
    514     /* if the mode has a send flag, remove them from the group for it */ 
    515     if (md->sflag > -1 && MYCLIENT(on)) 
    516         remove_from_send_flag(md->sflag, on, true); 
    517  
    518     return 1; 
    519 } 
    520  
    521315static void client_remove_history(client_t *); 
    522316 
  • trunk/ithildin/modules/ircd/client.h

    r801 r803  
    22 * client.h: client structure declarations 
    33 *  
    4  * Copyright 2002 the Ithildin Project. 
     4 * Copyright 2002-2007 the Ithildin Project. 
    55 * See the COPYING file for more information on licensing and use. 
    66 *  
     
    7878char *make_client_mask(char *mask); 
    7979 
    80 /* mode stuff here.  modules/systems should acquire and release modes as they 
    81  * need them.  You may not get the mode you asked for, if something else is 
    82  * already using it, so don't assume that you did.  The function will return 
    83  * the bitmask used to check for the mode on a user's structure, and also place 
    84  * the actual mode letter in a character, passed as a pointer.  If you don't 
    85  * care what mode you get specify '\0' as the suggested field.  Also, if you 
    86  * want all users who set your specific mode to be placed in a 'send flag' 
    87  * group (see send.[ch]) pass the value of the flag to use, if not pass -1. 
    88  * The last argument is the name of the function used to determine whether a 
    89  * user can set/unset the node.  The arguments are the client setting the mode, 
    90  * the client on which the mode is being set, the mode character, an integer 
    91  * specifying whether the mode is being set or unset, a pointer to an argument 
    92  * (may be NULL), and a pointer to allow the function to specify whether the 
    93  * mode used the argument or not. */ 
    94 #define USERMODE_FUNC(x)                                                   \ 
    95 int x(client_t *by __UNUSED, client_t *cli, unsigned char mode __UNUSED,   \ 
    96         int set __UNUSED, char *arg __UNUSED, int *argused __UNUSED) 
    97 typedef int (*usermode_func)(client_t *, client_t *, unsigned char, int, 
    98         char *, int *); 
    99  
    100 uint64_t usermode_request(unsigned char, unsigned char *, int, int, 
    101         usermode_func); 
    102  
    103 /* use this function to release a mode if you no longer care about it being set 
    104  * on users.  You are still responsible for clearing out the group if the mode 
    105  * had one */ 
    106 void usermode_release(unsigned char); 
    107  
    108 /* this function provides a way to update the assigned function for a 
    109  * usermode */ 
    110 void usermode_update_func(unsigned char, usermode_func); 
    111  
    112 /* this function returns a mode string from the passed 64bit integer. the 
    113  * string is statically allocated inside the function, if global is unset, get 
    114  * all usermodes, otherwise, get only global modes */ 
    115 unsigned char *usermode_getstr(uint64_t, char); 
    116  
    117 /* this does the opposite of the above, it returns a mask from a given string 
    118  * of modes, if global is non-false, the mask will only contain 'global' flags, 
    119  * otherwise, all flags are returned.  */ 
    120 uint64_t usermode_getmask(unsigned char *, char); 
    121  
    122 /* this performs a 'diff' on the modes, and returns a string reflecting the 
    123  * change from old modes to new modes, and places the result in 'result' */ 
    124 void usermode_diff(uint64_t, uint64_t, char *, char); 
    125  
    126 /* this does all the work to set a mode on a user.  it checks to see if they 
    127  * can set it, and places them in any appropriate groups.  if the function 
    128  * succeeds it returns 1, if the user cannot set the mode it returns 0 */ 
    129 int usermode_set(unsigned char, client_t *, client_t *, char *, int *); 
    130  
    131 /* this does like above, but unsetting instead of setting. */ 
    132 int usermode_unset(unsigned char, client_t *, client_t *, char *, int *); 
    133  
    134 /* returns positive if a given mode is valid and set on a client */ 
    135 #define usermode_isset(client, themode)                                       \ 
    136     ((ircd.umodes.modes[themode].avail == 0) ?                                \ 
    137      (client->modes & ircd.umodes.modes[themode].mask) :                      \ 
    138      0) 
    139  
    140 /* we know we will create some modes, create special macros to check them */ 
    141 #define INVIS(client) (client->modes & ircd.umodes.modes['i'].mask) 
    142 #define OPER(client) (client->modes & ircd.umodes.modes['o'].mask) 
    143  
    144 struct usermode { 
    145     unsigned char mode;             /* the actual mode */ 
    146     char    avail;                  /* 1 if available, 0 otherwise */ 
    147 #define USERMODE_FL_GLOBAL  0x1     /* the usermode is spread across the 
    148                                        network */ 
    149 #define USERMODE_FL_OPER    0x2     /* the usermode is operator only */ 
    150 #define USERMODE_FL_PRESERVE 0x4    /* preserve the mode once set unless 
    151                                        explicitly unset by the user */ 
    152     int     flags;                  /* flags for the usermode */ 
    153     uint64_t mask;                  /* the bitmask for the mode */ 
    154     usermode_func changefunc;       /* the changer function for the mode */ 
    155     int     sflag;                  /* send flag (if any) for this mode. */ 
    156 }; 
    157  
    15880TAILQ_HEAD(client_history_list, client_history); 
    15981struct client_history { 
  • trunk/ithildin/modules/ircd/command.c

    r787 r803  
    267267} 
    268268 
    269  
    270  
    271269int command_add_hook(char *name, int client, hook_function_t hook, 
    272270        int flags) { 
     
    406404         * is.  Without a distributed privilege understanding we have to 
    407405         * assume positive intent. */ 
    408         if ((cmd->client.flags & COMMAND_FL_OPERATOR && !OPER(cli)) || 
    409                 !BPRIV(cli, cmd->priv)) { 
     406        if ((cmd->client.flags & COMMAND_FL_OPERATOR && 
     407                    !CLIENT_OPERATOR(cli)) || !BPRIV(cli, cmd->priv)) { 
    410408            sendto_one(cli, RPL_FMT(cli, ERR_NOPRIVILEGES)); 
    411409            return ERR_NOPRIVILEGES; 
  • trunk/ithildin/modules/ircd/commands/names.c

    r579 r803  
    8080     * command for large channels :/ */ 
    8181    LIST_FOREACH(clp, &chan->users, lpchan) { 
    82         if (INVIS(clp->cli) && !see) 
     82        if (CLIENT_INVISIBLE(clp->cli) && !see) 
    8383            continue; 
    8484        if (NAMEBUFLEN < len + ircd.limits.nicklen) { 
  • trunk/ithildin/modules/ircd/commands/notice.c

    r579 r803  
    170170     */ 
    171171    if (*to == '$') { 
    172         if (cli != NULL && MYCLIENT(cli) && !OPER(cli)) 
     172        if (cli != NULL && MYCLIENT(cli) && !CLIENT_OPERATOR(cli)) 
    173173            sendto_one(cli, RPL_FMT(cli, ERR_NOPRIVILEGES)); 
    174174        else 
  • trunk/ithildin/modules/ircd/commands/trace.c

    r801 r803  
    100100    /* non-operator traces must specify an exact client.  other traces might do 
    101101     * this too.  if you remember we found cp up above. ;) */ 
    102     if (!OPER(cli) || cp != NULL) { 
     102    if (!CLIENT_OPERATOR(cli) || cp != NULL) { 
    103103        if (cp != NULL) { 
    104104            /* found a client.  Send the info */ 
    105             if (OPER(cp)) 
     105            if (CLIENT_OPERATOR(cp)) 
    106106                sendto_one(cli, RPL_FMT(cli, RPL_TRACEOPERATOR), 
    107107                        (cp->conn != NULL ? cp->conn->cls->name : "*"), 
     
    133133    LIST_FOREACH(connp, ircd.connections.clients, lp) { 
    134134        cp = connp->cli; 
    135         if (OPER(cp)) 
     135        if (CLIENT_OPERATOR(cp)) 
    136136            sendto_one(cli, RPL_FMT(cli, RPL_TRACEOPERATOR), connp->cls->name, 
    137137                    cli->nick, me.now - connp->last); 
  • trunk/ithildin/modules/ircd/commands/userhost.c

    r579 r803  
    5858        if ((target = find_client(cur)) != NULL) 
    5959            len += snprintf(buf + len,  512 - len, "%s%s=%c%s@%s ", 
    60                     target->nick, OPER(target) ? "*" : "",  
     60                    target->nick, CLIENT_OPERATOR(target) ? "*" : "",  
    6161                    AWAYMSG(target) ? '-' : '+', target->user, target->host); 
    6262 
  • trunk/ithildin/modules/ircd/commands/who.c

    r579 r803  
    212212                break; 
    213213            case 'g': /* gcos field search */ 
    214                 if (!OPER(cli) || oarg >= argc) 
     214                if (!CLIENT_OPERATOR(cli) || oarg >= argc) 
    215215                    WHO_PARSE_SERROR(argv[0]); 
    216216                who_opts.gcos = argv[oarg++]; 
     
    224224                break; 
    225225            case 'i': /* IP address search */ 
    226                 if (!OPER(cli) || oarg >= argc) 
     226                if (!CLIENT_OPERATOR(cli) || oarg >= argc) 
    227227                    WHO_PARSE_SERROR(argv[0]); 
    228228                who_opts.ip = argv[oarg++]; 
     
    239239                    s++; 
    240240                } 
    241                 if (!OPER(cli)) /* restrict them to only +o */ 
     241                if (!CLIENT_OPERATOR(cli)) /* restrict them to only +o */ 
    242242                    who_opts.usermodes = (who_opts.usermodes & 
    243243                            ircd.umodes.modes['o'].mask); 
     
    325325static int who_check(client_t *cli, int showall) { 
    326326 
    327     if (INVIS(cli) && !showall) 
     327    if (CLIENT_INVISIBLE(cli) && !showall) 
    328328        return 0; /* can't see them.  sneak sneak. */ 
    329329    if (who_opts.flags.check_umode) { 
     
    460460                continue; /* don't show them */ 
    461461            sprintf(status, "%c%s%s", AWAYMSG(cp) != NULL ? 'G' : 'H', 
    462                     OPER(cp) ? "*" : (INVIS(cp) && OPER(cli) ? "%" : ""), 
     462                    CLIENT_OPERATOR(cp) ? "*" : 
     463                    (CLIENT_INVISIBLE(cp) && CLIENT_OPERATOR(cli) ? "%" : ""), 
    463464                    chanmode_getprefixes(who_opts.channel, cp)); 
    464465            sendto_one(cli, RPL_FMT(cli, RPL_WHOREPLY), 
     
    481482        if (cp != NULL && who_check(cp, 1)) { 
    482483            sprintf(status, "%c%s", AWAYMSG(cp) != NULL ? 'G' : 'H', 
    483                     OPER(cp) ? "*" : (INVIS(cp) && OPER(cli) ? "%" : "")); 
     484                    CLIENT_OPERATOR(cp) ? "*" : 
     485                    (CLIENT_INVISIBLE(cp) && CLIENT_OPERATOR(cli) ? "%" : "")); 
    484486            sendto_one(cli, RPL_FMT(cli, RPL_WHOREPLY), 
    485487                    who_opts.flags.show_chan ? who_first_visible(cli, cp) : 
     
    509511                } else { 
    510512                    sprintf(status, "%c%s%s", AWAYMSG(cp) != NULL ? 'G' : 'H', 
    511                             OPER(cp) ? "*" : (INVIS(cp) && 
    512                                 OPER(cli) ? "%" : ""), 
     513                            CLIENT_OPERATOR(cp) ? "*" : 
     514                            (CLIENT_INVISIBLE(cp) && 
     515                             CLIENT_OPERATOR(cli) ? "%" : ""), 
    513516                            chanmode_getprefixes(who_opts.channel, cp)); 
    514517                    sendto_one(cli, RPL_FMT(cli, RPL_WHOREPLY), 
     
    535538            } else { 
    536539                sprintf(status, "%c%s", AWAYMSG(cp) != NULL ? 'G' : 'H', 
    537                         OPER(cp) ? "*" : (INVIS(cp) && OPER(cli) ? "%" : "")); 
     540                        CLIENT_OPERATOR(cp) ? "*" : 
     541                        (CLIENT_INVISIBLE(cp) && 
     542                         CLIENT_OPERATOR(cli) ? "%" : "")); 
    538543                sendto_one(cli, RPL_FMT(cli, RPL_WHOREPLY), 
    539544                        who_opts.flags.show_chan ? who_first_visible(cli, cp) : 
  • trunk/ithildin/modules/ircd/commands/whois.c

    r787 r803  
    113113    sendto_one(cli, RPL_FMT(cli, RPL_WHOISSERVER), target->nick, 
    114114            target->server->name, target->server->info); 
    115     if (OPER(target)) 
     115    if (CLIENT_OPERATOR(target)) 
    116116        sendto_one(cli, RPL_FMT(cli, RPL_WHOISOPERATOR), target->nick); 
    117117 
  • trunk/ithildin/modules/ircd/commands/xinfo.c

    r787 r803  
    135135    if (xhp->flags & XINFO_HANDLER_LOCAL && !MYCLIENT(cli)) 
    136136        return COMMAND_WEIGHT_LOW; /* silently ignore these */ 
    137     if ((xhp->flags & XINFO_HANDLER_OPER && !OPER(cli)) || 
     137    if ((xhp->flags & XINFO_HANDLER_OPER && !CLIENT_OPERATOR(cli)) || 
    138138            !BPRIV(cli, xhp->priv)) { 
    139139        sendto_one(cli, RPL_FMT(cli, ERR_NOPRIVILEGES)); 
     
    399399            sendto_one(cli, RPL_FMT(cli, RPL_XINFO), "UPTIME",  
    400400                    time_conv_str(me.now - me.started)); 
    401         } else if (sp->conn != NULL && OPER(cli)) { 
     401        } else if (sp->conn != NULL && CLIENT_OPERATOR(cli)) { 
    402402            sendto_one(cli, RPL_FMT(cli, RPL_XINFO), "CONNECTED", 
    403403                    int_conv_str(sp->conn->signon)); 
     
    408408    /* I'm restricting info about server connects to operators.  I'm not sure 
    409409     * what else would be amicable. */ 
    410     if (OPER(cli) && scp != NULL) { 
     410    if (CLIENT_OPERATOR(cli) && scp != NULL) { 
    411411        sent++; 
    412412        snprintf(rpl, XINFO_LEN, "ADDRESS %s PORT %s LAST %d INTERVAL %s", 
     
    419419    /* last, but not least, report on interesting configuration bits about the 
    420420     * server, if it has interesting configuration bits. */ 
    421     if (OPER(cli) && clp != NULL) { 
     421    if (CLIENT_OPERATOR(cli) && clp != NULL) { 
    422422        char *s; 
    423423        if (sp == NULL && (s = conf_find_entry("protocol", clp, 1)) != NULL) 
     
    440440        if (xhp->flags & XINFO_HANDLER_LOCAL && !MYCLIENT(cli)) 
    441441            continue; /* non-local */ 
    442         if ((xhp->flags & XINFO_HANDLER_OPER && !OPER(cli)) || 
     442        if ((xhp->flags & XINFO_HANDLER_OPER && !CLIENT_OPERATOR(cli)) || 
    443443                !BPRIV(cli, xhp->priv)) 
    444444            continue; /* not privileged */ 
  • trunk/ithildin/modules/ircd/ircd.c

    r801 r803  
    2525HOOK_FUNCTION(ircd_reload_hook); 
    2626HOOK_FUNCTION(ircd_loadmodule_hook); 
    27  
    28 /* this handles counting the default modes for stats, and ensuring +o is 
    29  * maintained correctly. */ 
    30 USERMODE_FUNC(mode_set_counter); 
    3127 
    3228struct ircd_struct ircd; 
     
    115111        else if ((now - cp->last) > (int)((float)cp->cls->freq * 0.5) && 
    116112                !CONN_PINGSENT(cp)) { 
    117             /* use sendto_one_from here so that there is no prefix added, 
    118              * apparently most clients balk at the prefix */ 
    119113            sendto_serv_from(cp->srv, NULL, NULL, NULL, "PING", ":%s", 
    120114                    ircd.me->name); 
     
    179173} 
    180174 
    181 /* the i/o counter goodies */ 
    182 USERMODE_FUNC(mode_set_counter) { 
    183     int i; 
    184  
    185     switch (mode) { 
    186         case 'i': 
    187             if (set) 
    188                 ircd.stats.net.visclients--; 
    189             else 
    190                 ircd.stats.net.visclients++; 
    191             break; 
    192         case 'o': 
    193             /* if this is our client, isn't set +o, and doesn't have the 
    194              * privilege to do, deny. */ 
    195             if (MYCLIENT(cli) && by == cli && !OPER(cli) && 
    196                     !BPRIV(cli, ircd.privileges.priv_operator)) 
    197                 return 0; 
    198             if (set) { 
    199                 ircd.stats.opers++; 
    200                 if (!MYCLIENT(cli)) 
    201                     /* change them to the default operator privilege set */ 
    202                     cli->pset = ircd.privileges.oper_set; 
    203                 hook_event(ircd.events.client_oper, cli); 
    204             } else { 
    205                 /* remove them from any operator-only send flags, also remove 
    206                  * any operator-only modes they might have set */ 
    207                 if (MYCLIENT(cli)) { 
    208                     unsigned char *s; 
    209                     for (s = ircd.umodes.avail;*s != '\0';s++) { 
    210                         if (ircd.umodes.modes[*s].flags & USERMODE_FL_OPER && 
    211                                 !(ircd.umodes.modes[*s].flags & 
    212                                     USERMODE_FL_PRESERVE)) 
    213                             usermode_unset(*s, cli, cli, NULL, NULL); 
    214                     } 
    215                     for (i = 0;i < ircd.sflag.size;i++) { 
    216                         if (ircd.sflag.flags[i].flags & 
    217                                 SEND_LEVEL_OPERATOR && 
    218                             !(ircd.sflag.flags[i].flags & 
    219                                 SEND_LEVEL_PRESERVE)) 
    220                             remove_from_send_flag(i, cli, true); 
    221                     } 
    222                 } 
    223                 ircd.stats.opers--; 
    224                 hook_event(ircd.events.client_deoper, cli); 
    225             } 
    226             break; 
    227     } 
    228  
    229     return 1; 
    230 } 
    231  
    232175MODULE_LOADER(ircd) { 
    233176    conf_list_t *conf = *confdata; 
    234177    int i; 
    235     unsigned char c; 
    236178    uint64_t ui64; 
    237179    struct tm *tmtime; 
     
    330272        ircd.privileges.priv_shs = create_privilege("see-hidden-servers", 
    331273                PRIVILEGE_FL_BOOL, &ui64, NULL); 
     274        ircd.privileges.priv_shc = create_privilege("see-hidden-channels", 
     275                PRIVILEGE_FL_BOOL, &ui64, NULL); 
    332276        ircd.privileges.priv_srch = create_privilege("see-real-client-host", 
    333                 PRIVILEGE_FL_BOOL, &ui64, NULL); 
    334     } 
    335  
    336     /* set up our mode structures and acquire some modes */ 
    337 #define MODELOOP(from, to, array) do {                                        \ 
    338     for (c = from;c <= to;c++, ui64 <<= 1) {                                  \ 
    339         ircd.array.modes[c].mode = c;                                         \ 
    340         ircd.array.modes[c].mask = ui64;                                      \ 
    341         ircd.array.modes[c].avail = 1;                                        \ 
    342     }                                                                         \ 
    343 } while (0) 
    344  
    345     if (!get_module_savedata(savelist, "ircd.umodes", &ircd.umodes)) { 
    346         ui64 = 1; 
    347         MODELOOP('a', 'z', umodes); /* set a-z modes */ 
    348         MODELOOP('A', 'Z', umodes); /* and A-Z modes */ 
    349         MODELOOP('0', '9', umodes); /* and 0-9 modes */ 
    350  
    351         /* we know that all modes are free.  grab i, o, and s */ 
    352         ircd.umodes.i = usermode_request('i', &c, USERMODE_FL_GLOBAL, -1, 
    353                 mode_set_counter); 
    354         ircd.umodes.o = usermode_request('o', &c, USERMODE_FL_GLOBAL, 
    355                 ircd.sflag.ops, mode_set_counter); 
    356         ircd.umodes.s = usermode_request('s', &c, 0, ircd.sflag.servmsg, 
    357                 NULL); 
    358     } else { 
    359         /* Be sure to update the function address for this channel mode in 
    360          * case it moved.. */ 
    361         usermode_update_func(ircd.umodes.i, mode_set_counter); 
    362         usermode_update_func(ircd.umodes.o, mode_set_counter); 
    363         usermode_update_func(ircd.umodes.s, mode_set_counter); 
    364     } 
    365  
    366     if (!get_module_savedata(savelist, "ircd.cmodes", &ircd.cmodes)) { 
    367         ui64 = 1; 
    368         MODELOOP('a', 'z', cmodes); /* do the same for channel modes */ 
    369         MODELOOP('A', 'Z', cmodes); 
    370         MODELOOP('0', '9', cmodes); 
    371     } 
     277                PRIVILEGE_FL_BOOL, &ui64,  NULL); 
     278    } 
     279 
     280    /* Initialize our modes.  Pass the success of the savedata request in to 
     281     * the loader to tell it what to do. */ 
     282    usermode_init(get_module_savedata(savelist, "ircd.umodes", 
     283                &ircd.umodes)); 
     284    chanmode_init(get_module_savedata(savelist, "ircd.cmodes", 
     285                &ircd.cmodes)); 
    372286 
    373287    /* setup our events.  started is always created, since it is destroyed 
     
    455369        /* create numerics for messages (lazy-style) */ 
    456370        /* common numerics */ 
    457         CMSG("001", ":Welcome to %s %s!%s@%s");                    /* rpl_welcome */ 
     371        CMSG("001", ":Welcome to %s %s!%s@%s");             /* rpl_welcome */ 
    458372        CMSG("002", ":Your host is %s, running version %s");/* rpl_yourhost */ 
    459373        CMSG("003", ":This server was created %s");         /* rpl_created */ 
     
    465379                "while and try again."); /* rpl_loadtoohigh */ 
    466380 
    467        /* the error numerics */ 
     381        CMSG("334", ":%s");                     /* rpl_commandsyntax */ 
     382        CMSG("367", "%s %s!%s@%s %s %lu");      /* rpl_banlist */ 
     383        CMSG("368", "%s :End of Channel Ban List"); /* rpl_endofbanlist */ 
     384 
     385        /* the error numerics */ 
    468386        CMSG("401", "%s :No such nick/channel"); /* err_nosuchnick */ 
    469387        CMSG("402", "%s :No such server");       /* err_nosuchserver */ 
    470388        CMSG("403", "%s :No such channel");      /* err_nosuchchannel */ 
     389        CMSG("404", "%s :Cannot send to channel"); /* err_cannotsendtochan */ 
    471390        /* err_toomanytargets */ 
    472391        CMSG("407", "%s :Duplicate recipients, no message delivered."); 
    473392        CMSG("421", "%s :Unknown command.");     /* err_unknowncommand */ 
    474393        CMSG("432", "%s :%s [%s]"); /* err_erroneousnickname */ 
     394        /* err_banonchan */ 
     395        CMSG("435", "%s %s :Cannot change to a banned nickname"); 
     396        /* err_bannickchange */ 
     397        CMSG("437", "%s :Cannot change nickname while banned or moderated on " 
     398                "channel."); 
    475399        CMSG("441", "%s %s :They aren't on that channel."); 
    476400        CMSG("442", "%s :You're not on that channel"); /* err_notonchannel */ 
     
    479403        CMSG("462", ":You may not reregister"); /* err_alreadyregistered */ 
    480404        CMSG("464", ":Password Incorrect"); /* err_passwdmismatch */ 
     405        CMSG("471", "%s :Cannot join channel (+l)"); /* err_channelisfull */ 
     406        CMSG("474", "%s :Cannot join channel (+b)"); /* err_bannedfromchan */ 
     407        CMSG("475", "%s :Cannot join channel (+k)"); /* err_badchannelkey */ 
     408        CMSG("478", "%s %s :Channel ban list is full"); /* err_banlistfull */ 
    481409        CMSG("479", "%s :Channel name contains illegal characters"); 
     410        /* err_noprivileges */ 
    482411        CMSG("481", ":Permission denied.  " 
    483412                "You do not have the correct privileges"); 
     413        /* err_chanoprivsneeded */ 
     414        CMSG("482", "%s :You're not a channel operator"); 
     415        /* err_chanbanreason */ 
    484416        CMSG("485", "%s :Cannot %s channel (%s)"); 
    485417 
     418        /* rpl_xinfo */ 
    486419        CMSG("771", "%s :%s"); 
    487420    } 
     
    608541        isp = isp2; 
    609542    } 
     543 
     544    usermode_deinit(reload); 
     545    chanmode_deinit(reload); 
    610546 
    611547    /* if we're reloading, do lots of preservation (we could just preserve the 
  • trunk/ithildin/modules/ircd/ircd.h

    r801 r803  
    33 * holder 
    44 *  
    5  * Copyright 2002 the Ithildin Project. 
     5 * Copyright 2002-2007 the Ithildin Project. 
    66 * See the COPYING file for more information on licensing and use. 
    77 *  
     
    3636 
    3737#include "channel.h" 
     38#include "chanmode.h" 
    3839#include "class.h" 
    3940#include "client.h" 
     
    4748#include "server.h" 
    4849#include "support.h" 
     50#include "usermode.h" 
    4951 
    5052HOOK_FUNCTION(ircd_listen_hook); 
     
    5759    server_t *me; /* our server structure, not linked anywhere! */ 
    5860 
    59     char    address[HOSTLEN + 1];   /* our server's address (for listen()) */ 
    60     char    network[GCOSLEN + 1];   /* the name of our network */ 
    61     char    network_full[TOPICLEN + 1];/* the full network name. */ 
    62     const char *realversion;            /* the version number in the module. */ 
    63     char    version[GCOSLEN + 1];   /* user defined server version */ 
    64     char    vercomment[TOPICLEN + 1];/* user defined version 'comment' */ 
    65     char    statsfile[PATH_MAX];    /* stats file */ 
    66     int            started;                    /* this is set to 1 once the daemon has 
     61    char address[HOSTLEN + 1];      /* our server's address (for listen()) */ 
     62    char network[GCOSLEN + 1];      /* the name of our network */ 
     63    char network_full[TOPICLEN + 1];/* the full network name. */ 
     64    const char *realversion;        /* the version number in the module. */ 
     65    char version[GCOSLEN + 1];      /* user defined server version */ 
     66    char vercomment[TOPICLEN + 1];  /* user defined version 'comment' */ 
     67    char statsfile[PATH_MAX];       /* stats file */ 
     68    int started;                    /* this is set to 1 once the daemon has 
    6769                                       actually started */ 
    68     char    ascstart[48];            /* time started, used in RPL_CREATED and 
     70    char ascstart[48];              /* time started, used in RPL_CREATED and 
    6971                                       others, made once to save time */ 
    70     conf_list_t **confhead;            /* the head of our configuration tree */ 
    71  
    72     char    **argv;                    /* argv/argc for commands */ 
    73     int            argc; 
     72    conf_list_t **confhead;         /* the head of our configuration tree */ 
     73 
     74    char **argv;                    /* argv/argc for commands */ 
     75    int argc; 
    7476 
    7577    /* XXX(?):  (see 'triple-x inre 'tmpmsg' in the protocol structure, too). 
     
    8688    struct { 
    8789        struct { 
    88             int            curclients;        /* network-wide current/max clients */ 
    89             int            maxclients; 
    90             int            visclients; /* -i clients */ 
     90            int curclients;         /* network-wide current/max clients */ 
     91            int maxclients; 
     92            int visclients;        /* -i clients */ 
    9193        } net; 
    9294        struct { 
    93             int            curclients; /* server current/max clients */ 
    94             int            maxclients; 
    95             int            unkclients; /* unknown clients */ 
    96             int            servers;        /* servers we have on us */ 
     95            int curclients;        /* server current/max clients */ 
     96            int maxclients; 
     97            int unkclients;        /* unknown clients */ 
     98            int servers;            /* servers we have on us */ 
    9799        } serv; 
    98         int        channels; 
    99         int        servers; 
    100         int        opers; 
     100        int channels; 
     101        int servers; 
     102        int opers; 
    101103    } stats; 
    102104 
    103105    struct { 
    104         char        line1[GCOSLEN + 1]; 
    105         char        line2[GCOSLEN + 1]; 
    106         char        line3[GCOSLEN + 3]; 
     106        char line1[GCOSLEN + 1]; 
     107        char line2[GCOSLEN + 1]; 
     108        char line3[GCOSLEN + 3]; 
    107109    } admininfo; 
    108110 
    109111    struct { 
    110         int        nicklen; 
    111         int        chanlen; 
     112        int nicklen; 
     113        int chanlen; 
    112114    } limits; 
    113115 
    114116    /* usermode data */ 
    115117    struct { 
    116         unsigned char avail[64];        /* the available usermodes in string 
    117                                            form (available for use, not for 
    118                                            registering new modes with ;) */ 
    119         uint64_t i;                        /* the mask for +i */ 
    120         uint64_t o;                        /* the mask for +o */ 
    121         uint64_t s;                        /* the mask for +s */ 
    122  
    123         struct        usermode modes[256];        /* mode structures.  a mode can be 
    124                                            found by doing ircd.umodes.modes[c], 
    125                                            where 'c' is the mode character 
    126                                            you're after */ 
     118        unsigned char avail[64];    /* the available usermodes in string 
     119                                       form (available for use, not for 
     120                                       registering new modes with ;) */ 
     121        uint64_t mode_invis;        /* the mask for +i */ 
     122        uint64_t mode_oper;         /* the mask for +o */ 
     123        uint64_t mode_servmsg;      /* the mask for +s */ 
     124 
     125        struct usermode modes[256]; /* mode structures.  a mode can be 
     126                                       found by doing ircd.umodes.modes[c], 
     127                                       where 'c' is the mode character 
     128                                       you're after */ 
    127129    } umodes; 
    128130 
    129131    /* channel mode data */ 
    130132    struct { 
    131         unsigned char avail[64 + 5];        /* available channel modes */ 
    132         unsigned char prefix[64];        /* available prefix goodies */ 
    133         unsigned char pmodes[32];        /* modes which are prefixes, this is 
    134                                            mostly for internal use */ 
    135  
    136         struct        chanmode modes[256];        /* mode structures.  a mode can be 
    137                                            found by doing ircd.cmodes.modes[c], 
    138                                            where 'c' is the mode character 
    139                                            you're after. */ 
    140         struct        chanmode *pfxmap[256];        /* map to chanmodes from their 
    141                                            prefixes.  useful for fast lookups 
    142                                            and such. */ 
     133        unsigned char avail[64 + 5];/* available channel modes */ 
     134        unsigned char prefix[64];   /* available prefix goodies */ 
     135        unsigned char pmodes[32];   /* modes which are prefixes, this is 
     136                                       mostly for internal use */ 
     137 
     138        struct chanmode modes[256]; /* mode structures.  a mode can be 
     139                                       found by doing ircd.cmodes.modes[c], 
     140                                       where 'c' is the mode character 
     141                                       you're after. */ 
     142        struct chanmode *pfxmap[256];/* map to chanmodes from their 
     143                                       prefixes.  useful for fast lookups 
     144                                       and such. */ 
     145 
     146        unsigned char mode_ban;     /* +b (ban) */ 
     147        unsigned char mode_key;     /* +k (key) */ 
     148        unsigned char mode_limit;   /* +l (limit) */ 
     149        unsigned char mode_mod;     /* +m (moderated) */ 
     150        unsigned char mode_nextern; /* +n (no external msgs) */ 
     151        unsigned char mode_op;      /* +o (chanop) */ 
     152        unsigned char mode_secret;  /* +s (secret) */ 
     153        unsigned char mode_voice;   /* +v (chan 'voice') */ 
    143154    } cmodes; 
    144155 
     
    146157        /* called once when the server is completely started, this allows 
    147158         * necessary functions to be called when everything is ready */ 
    148         event_t        *started; 
     159        event_t *started; 
    149160 
    150161        /* the three connection stage events, used by the acl system, and 
    151162         * maybe others.   connection_registered only fires for CLIENTS 
    152163         * which are registered. */ 
    153         event_t        *connection_connected; 
    154         event_t        *connection_unregistered; 
    155         event_t        *connection_registered; 
     164        event_t *connection_connected; 
     165        event_t *connection_unregistered; 
     166        event_t *connection_registered; 
    156167 
    157168        /* other events */ 
     
    164175        event_t *unregister_client; /* called from destroy_client() for all 
    165176                                       clients being destroyed */ 
    166         event_t *client_nick;            /* hooked when a client changes its 
     177        event_t *client_nick;       /* hooked when a client changes its 
    167178                                       nickname. */ 
    168         event_t *client_oper;            /* hooked when a client goes +o */ 
    169         event_t *client_deoper;            /* hooked when a client goes -o */ 
     179        event_t *client_oper;       /* hooked when a client goes +o */ 
     180        event_t *client_deoper;     /* hooked when a client goes -o */ 
    170181        event_t *channel_create;    /* hooked when a channel record is 
    171182                                       initially created. */ 
    172183        event_t *channel_destroy;   /* same, but for destruction. */ 
    173         event_t *channel_add;            /* hooked when a client joins a channel */ 
    174         event_t *channel_del;            /* same, but with part */ 
     184        event_t *channel_add;       /* hooked when a client joins a channel */ 
     185        event_t *channel_del;       /* same, but with part */ 
    175186 
    176187        event_t *server_introduce;  /* called when server_introduce() is 
     
    233244 
    234245    struct { 
    235         LIST_HEAD(, message_set) *sets; /* our list of message sets */ 
    236         message_t *msgs; /* array of different messages */ 
    237         int        count; 
    238         int        size; /* size of the 'msgs' array */ 
     246        LIST_HEAD(, message_set) *sets;/* our list of message sets */ 
     247        message_t *msgs;            /* array of different messages */ 
     248        int count; 
     249        int size;                  /* size of the 'msgs' array */ 
    239250    } messages; 
    240251 
    241252    struct { 
    242253        struct send_flag *flags;    /* array of 'send_flag' structures */ 
    243         int size;                    /* size of the array */ 
     254        int size;                   /* size of the array */ 
    244255 
    245256        int ops;                    /* +o users */ 
    246         int servmsg;                    /* +s users */ 
     257        int servmsg;                /* +s users */ 
    247258    } sflag; 
    248259 
    249260    struct { 
    250         LIST_HEAD(, privilege_set) *sets; /* our list of privilege sets */ 
     261        LIST_HEAD(, privilege_set) *sets;/* our list of privilege sets */ 
    251262        privilege_set_t *oper_set;  /* default operator privileges */ 
    252         privilege_t *privs;            /* array of privileges */ 
    253         int        count; 
    254         int        size;                    /* size of the privs array */ 
     263        privilege_t *privs;         /* array of privileges */ 
     264        int count; 
     265        int size;                   /* size of the privs array */ 
    255266 
    256267        /* actual privileges created by the daemon are here */ 
    257         int        priv_operator;            /* the 'operator' privilege, allows 
     268        int priv_operator;          /* the 'operator' privilege, allows 
    258269                                       changing of the 'o' usermode */ 
    259         int        priv_shs;            /* this privilege allows users to see 
     270        int priv_shs;               /* this privilege allows users to see 
    260271                                       information about hidden servers */ 
    261         int        priv_srch;            /* this privilege allows users to see the 
     272        int priv_shc;               /* this privilege allows users to see 
     273                                       hidden channels */ 
     274        int priv_srch;              /* this privilege allows users to see the 
    262275                                       original host of users (if it has been 
    263                                        changed) */ 
     276                                       changed) (see real client host) */ 
    264277#define CAN_SEE_SERVER(cli, srv)                                        \ 
    265278 (srv->flags & IRCD_SERVER_HIDDEN ? BPRIV(cli, ircd.privileges.priv_shs) : 1) 
  • trunk/ithildin/modules/ircd/send.c

    r787 r803  
    140140/* this macro is used below to clear out temporary structures after doing a 
    141141 * round of sends. */ 
    142 #define CLEAR_SEND_TEMPS() do {                                                \ 
    143     protocol_t *_pp;                                                        \ 
    144     LIST_FOREACH(_pp, ircd.lists.protocols, lp) {                        \ 
    145         _pp->tmpmsg = NULL;                                                \ 
    146     }                                                                        \ 
     142#define CLEAR_SEND_TEMPS() do {                                               \ 
     143    protocol_t *_pp;                                                          \ 
     144    LIST_FOREACH(_pp, ircd.lists.protocols, lp) {                             \ 
     145        _pp->tmpmsg = NULL;                                                   \ 
     146    }                                                                         \ 
    147147    memset(ircd.sends, 0, maxsockets);                                        \ 
    148148} while (0) 
     
    629629              !BPRIV(cli, ircd.sflag.flags[flg].priv)) || 
    630630             (ircd.sflag.flags[flg].flags & SEND_LEVEL_OPERATOR && 
    631               !OPER(cli)))) 
     631              !CLIENT_OPERATOR(cli)))) 
    632632        return ERR_NOPRIVILEGES; 
    633633 
  • trunk/ithildin/modules/ircd/send.h

    r787 r803  
    177177#define RPL_LOADTOOHIGH 263 
    178178 
     179#define RPL_COMMANDSYNTAX 334 
     180#define RPL_BANLIST 367 
     181#define RPL_ENDOFBANLIST 368 
     182 
    179183#define ERR_NOSUCHNICK 401 
    180184#define ERR_NOSUCHSERVER 402 
    181185#define ERR_NOSUCHCHANNEL 403 
     186#define ERR_CANNOTSENDTOCHAN 404 
    182187#define ERR_TOOMANYTARGETS 407 
    183188#define ERR_UNKNOWNCOMMAND 421 
    184189#define ERR_ERRONEOUSNICKNAME 432 
     190#define ERR_BANONCHAN 435 
     191#define ERR_BANNICKCHANGE 437 
    185192#define ERR_USERNOTINCHANNEL 441 
    186193#define ERR_NOTONCHANNEL 442 
     
    189196#define ERR_ALREADYREGISTERED 462 
    190197#define ERR_PASSWDMISMATCH 464 
     198#define ERR_CHANNELISFULL 471 
     199#define ERR_BANNEDFROMCHAN 474 
     200#define ERR_BADCHANNELKEY 475 
     201#define ERR_BANLISTFULL 478 
    191202#define ERR_BADCHANNAME 479 
    192203#define ERR_NOPRIVILEGES 481 
     204#define ERR_CHANOPRIVSNEEDED 482 
    193205#define ERR_CHANBANREASON 485 
    194206 
  • trunk/ithildin/modules/ircd/usermode.c

    r801 r803  
    11/* 
    2  * client.c: client structure management functions 
     2 * usermode.c: client (user) mode management functions 
    33 *  
    4  * Copyright 2002 the Ithildin Project. 
     4 * Copyright 2002-2007 the Ithildin Project. 
    55 * See the COPYING file for more information on licensing and use. 
    66 *  
    7  * This file provides mechanisms for creating/destroy client structures, as 
    8  * well as registering them on the server and setting/unsetting user modes on 
    9  * them. 
     7 * This file contains the generic code for manipulating user modes, as well 
     8 * as some base usermodes supported by the server. 
    109 */ 
    1110 
     
    1615IDSTRING(rcsid, "$Id$"); 
    1716 
    18 /* this creates a new client structure and places it in the 'conn' structure 
    19  * passed, if any.  If there is no conn structure, then this is either a remote 
    20  * client or a pseudo-client. */ 
    21 client_t *create_client(connection_t *conn) { 
    22     client_t *cp = calloc(1, sizeof(client_t)); 
    23     cp->conn = conn; 
    24  
    25     /* set connection time/etc */ 
    26     cp->ts = cp->last = me.now; 
    27     cp->orighost = cp->host; /* don't forget this one */ 
    28  
    29     cp->mdext = mdext_alloc(ircd.mdext.client); 
    30  
    31     if (conn != NULL) { 
    32         conn->cli = cp; 
    33         cp->pset = conn->cls->pset; 
    34         get_socket_address(isock_raddr(conn->sock), cp->ip, IPADDR_MAXLEN + 1, 
    35                 NULL); 
    36         ircd.stats.serv.unkclients++; 
    37     } else 
    38         cp->pset = LIST_FIRST(ircd.privileges.sets); 
    39  
    40     LIST_INSERT_HEAD(ircd.lists.clients, cp, lp); 
    41     return cp; 
    42 } 
    43  
    44 /* this destroys a client, and if it is our connection, also destroys the 
    45  * client's connection.  do *NOT* try to destroy connections after 
    46  * destroying their clients. */ 
    47 void destroy_client(client_t *cli, char *msg) { 
    48     struct chanlink *clp; 
    49     unsigned char *s; 
    50  
    51     if (cli->flags & IRCD_CLIENT_HISTORY) { 
    52         /* just return the memory */ 
    53         mdext_free(ircd.mdext.client, cli->mdext); 
    54         free(cli); 
    55         return; 
    56     } 
    57  
    58     if (CLIENT_REGISTERED(cli)) { /* only do this stuff for registered 
    59                                      clients */ 
    60         if (MYCLIENT(cli)) 
    61             hook_event(ircd.events.client_disconnect, cli); 
    62         hook_event(ircd.events.unregister_client, cli); 
    63  
    64         /* if the client hasn't been flagged as 'killed' (that is, destroyed by 
    65          * some other action) we propogate the quit message to other servers. 
    66          * whatever betide we send the quit to all local users! */ 
    67         if (!(cli->flags & IRCD_CLIENT_KILLED)) 
    68             sendto_serv_butone(cli->server, cli, NULL, NULL, "QUIT", ":%s", 
    69                     msg); 
    70  
    71         clp = LIST_FIRST(&cli->chans); 
    72         if (clp != NULL) { 
    73             /* if we are in channels */ 
    74             /* don't send a message to our user */ 
    75             if (MYCLIENT(cli)) 
    76                 ircd.sends[cli->conn->sock->fd] = 1; 
    77             sendto_common_channels(cli, NULL, "QUIT", ":%s", msg); 
    78             while (clp != NULL) { 
    79                 del_from_channel(cli, clp->chan, true); 
    80                 clp = LIST_FIRST(&cli->chans); 
    81             } 
    82         } 
    83  
    84         /* add them to the client history, and also sign them off. */ 
    85         client_add_history(cli); 
    86         /* and mark the client structure as a 'history' structure */ 
    87         cli->flags |= IRCD_CLIENT_HISTORY; 
    88  
    89         /* unset all their modes.  this allows any resource cleanup to be 
    90          * handled by individual mode handlers. */ 
    91         s = ircd.umodes.avail; 
    92         while (*s) 
    93             usermode_unset(*s++, cli, cli, NULL, NULL); 
    94  
    95         if (MYCLIENT(cli)) { 
    96             int i; 
    97  
    98             ircd.stats.serv.curclients--; 
    99             for (i = 0;i < ircd.sflag.size;i++) 
    100                 remove_from_send_flag(i, cli, true); 
    101