]> jfr.im git - solanum.git/blobdiff - ircd/chmode.c
m_cap: simplify cap_req, remove multiline
[solanum.git] / ircd / chmode.c
index f63e74e5fd61b653eadbb4f341d83de0f7aadee5..6416a8c9107476c068b853e4e3eec0543081cae0 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  charybdis: A slightly useful ircd.
+ *  Solanum: a slightly advanced ircd
  *  chmode.c: channel mode management
  *
  * Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
  *  USA
- *
- *  $Id: chmode.c 3580 2007-11-07 23:45:14Z jilles $
  */
 
 #include "stdinc.h"
 #include "channel.h"
 #include "client.h"
-#include "common.h"
 #include "hash.h"
 #include "hook.h"
 #include "match.h"
@@ -180,21 +177,18 @@ cflag_orphan(char c_)
 }
 
 int
-get_channel_access(struct Client *source_p, struct membership *msptr, int dir, const char *modestr)
+get_channel_access(struct Client *source_p, struct Channel *chptr, struct membership *msptr, int dir, const char *modestr)
 {
        hook_data_channel_approval moduledata;
 
        if(!MyClient(source_p))
                return CHFL_CHANOP;
 
-       if (msptr == NULL)
-               return CHFL_PEON;
-
        moduledata.client = source_p;
-       moduledata.chptr = msptr->chptr;
+       moduledata.chptr = chptr;
        moduledata.msptr = msptr;
        moduledata.target = NULL;
-       moduledata.approved = is_chanop(msptr) ? CHFL_CHANOP : CHFL_PEON;
+       moduledata.approved = (msptr != NULL && is_chanop(msptr)) ? CHFL_CHANOP : CHFL_PEON;
        moduledata.dir = dir;
        moduledata.modestr = modestr;
 
@@ -208,10 +202,10 @@ get_channel_access(struct Client *source_p, struct membership *msptr, int dir, c
  * Checks if mlock and chanops permit a mode change.
  *
  * inputs      - client, channel, access level, errors pointer, mode char
- * outputs     - 0 on failure, 1 on success
+ * outputs     - false on failure, true on success
  * side effects - error message sent on failure
  */
-static int
+static bool
 allow_mode_change(struct Client *source_p, struct Channel *chptr, int alevel,
                int *errors, char c)
 {
@@ -226,26 +220,26 @@ allow_mode_change(struct Client *source_p, struct Channel *chptr, int alevel,
                                        c,
                                        chptr->mode_lock);
                *errors |= SM_ERR_MLOCK;
-               return 0;
+               return false;
        }
-       if(alevel != CHFL_CHANOP)
+       if(alevel < CHFL_CHANOP)
        {
                if(!(*errors & SM_ERR_NOOPS))
                        sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED),
                                   me.name, source_p->name, chptr->chname);
                *errors |= SM_ERR_NOOPS;
-               return 0;
+               return false;
        }
-       return 1;
+       return true;
 }
 
 /* add_id()
  *
  * inputs      - client, channel, id to add, type, forward
- * outputs     - 0 on failure, 1 on success
+ * outputs     - false on failure, true on success
  * side effects - given id is added to the appropriate list
  */
-int
+bool
 add_id(struct Client *source_p, struct Channel *chptr, const char *banid, const char *forward,
        rb_dlink_list * list, long mode_type)
 {
@@ -259,18 +253,18 @@ add_id(struct Client *source_p, struct Channel *chptr, const char *banid, const
         */
        if(MyClient(source_p))
        {
-               if((rb_dlink_list_length(&chptr->banlist) + rb_dlink_list_length(&chptr->exceptlist) + rb_dlink_list_length(&chptr->invexlist) + rb_dlink_list_length(&chptr->quietlist)) >= (unsigned long)(chptr->mode.mode & MODE_EXLIMIT ? ConfigChannel.max_bans_large : ConfigChannel.max_bans))
+               if((rb_dlink_list_length(&chptr->banlist) + rb_dlink_list_length(&chptr->exceptlist) + rb_dlink_list_length(&chptr->invexlist) + rb_dlink_list_length(&chptr->quietlist)) >= (unsigned long)((chptr->mode.mode & MODE_EXLIMIT) ? ConfigChannel.max_bans_large : ConfigChannel.max_bans))
                {
                        sendto_one(source_p, form_str(ERR_BANLISTFULL),
                                   me.name, source_p->name, chptr->chname, realban);
-                       return 0;
+                       return false;
                }
 
                RB_DLINK_FOREACH(ptr, list->head)
                {
                        actualBan = ptr->data;
                        if(mask_match(actualBan->banstr, realban))
-                               return 0;
+                               return false;
                }
        }
        /* dont let remotes set duplicates */
@@ -280,13 +274,13 @@ add_id(struct Client *source_p, struct Channel *chptr, const char *banid, const
                {
                        actualBan = ptr->data;
                        if(!irccmp(actualBan->banstr, realban))
-                               return 0;
+                               return false;
                }
        }
 
 
        if(IsPerson(source_p))
-               rb_sprintf(who, "%s!%s@%s", source_p->name, source_p->username, source_p->host);
+               sprintf(who, "%s!%s@%s", source_p->name, source_p->username, source_p->host);
        else
                rb_strlcpy(who, source_p->name, sizeof(who));
 
@@ -297,9 +291,9 @@ add_id(struct Client *source_p, struct Channel *chptr, const char *banid, const
 
        /* invalidate the can_send() cache */
        if(mode_type == CHFL_BAN || mode_type == CHFL_QUIET || mode_type == CHFL_EXCEPTION)
-               chptr->bants++;
+               chptr->bants = rb_current_time();
 
-       return 1;
+       return true;
 }
 
 /* del_id()
@@ -327,7 +321,7 @@ del_id(struct Channel *chptr, const char *banid, rb_dlink_list * list, long mode
 
                        /* invalidate the can_send() cache */
                        if(mode_type == CHFL_BAN || mode_type == CHFL_QUIET || mode_type == CHFL_EXCEPTION)
-                               chptr->bants++;
+                               chptr->bants = rb_current_time();
 
                        return banptr;
                }
@@ -406,7 +400,7 @@ pretty_mask(const char *idmask)
                        *t = '~';
                if (*t == '~')
                        t++;
-               *t = ToLower(*t);
+               *t = irctolower(*t);
                return mask_buf + old_mask_pos;
        }
 
@@ -492,43 +486,43 @@ pretty_mask(const char *idmask)
  * output      - true if forwarding should be allowed
  * side effects - numeric sent if not allowed
  */
-static int
+static bool
 check_forward(struct Client *source_p, struct Channel *chptr,
                const char *forward)
 {
-       struct Channel *targptr;
+       struct Channel *targptr = NULL;
        struct membership *msptr;
 
        if(!check_channel_name(forward) ||
                        (MyClient(source_p) && (strlen(forward) > LOC_CHANNELLEN || hash_find_resv(forward))))
        {
                sendto_one_numeric(source_p, ERR_BADCHANNAME, form_str(ERR_BADCHANNAME), forward);
-               return 0;
+               return false;
        }
        /* don't forward to inconsistent target -- jilles */
        if(chptr->chname[0] == '#' && forward[0] == '&')
        {
                sendto_one_numeric(source_p, ERR_BADCHANNAME,
                                   form_str(ERR_BADCHANNAME), forward);
-               return 0;
+               return false;
        }
        if(MyClient(source_p) && (targptr = find_channel(forward)) == NULL)
        {
                sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL,
                                   form_str(ERR_NOSUCHCHANNEL), forward);
-               return 0;
+               return false;
        }
        if(MyClient(source_p) && !(targptr->mode.mode & MODE_FREETARGET))
        {
                if((msptr = find_channel_membership(targptr, source_p)) == NULL ||
-                       get_channel_access(source_p, msptr, MODE_QUERY, NULL) != CHFL_CHANOP)
+                       get_channel_access(source_p, targptr, msptr, MODE_QUERY, NULL) < CHFL_CHANOP)
                {
                        sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED),
                                   me.name, source_p->name, targptr->chname);
-                       return 0;
+                       return false;
                }
        }
-       return 1;
+       return true;
 }
 
 /* fix_key()
@@ -541,9 +535,9 @@ check_forward(struct Client *source_p, struct Channel *chptr,
 static char *
 fix_key(char *arg)
 {
-       u_char *s, *t, c;
+       unsigned char *s, *t, c;
 
-       for(s = t = (u_char *) arg; (c = *s); s++)
+       for(s = t = (unsigned char *) arg; (c = *s); s++)
        {
                c &= 0x7f;
                if(c != ':' && c != ',' && c > ' ')
@@ -564,9 +558,9 @@ fix_key(char *arg)
 static char *
 fix_key_remote(char *arg)
 {
-       u_char *s, *t, c;
+       unsigned char *s, *t, c;
 
-       for(s = t = (u_char *) arg; (c = *s); s++)
+       for(s = t = (unsigned char *) arg; (c = *s); s++)
        {
                c &= 0x7f;
                if((c != 0x0a) && (c != ':') && (c != ',') && (c != 0x0d) && (c != ' '))
@@ -662,28 +656,72 @@ chm_orphaned(struct Client *source_p, struct Channel *chptr,
 }
 
 void
-chm_staff(struct Client *source_p, struct Channel *chptr,
+chm_hidden(struct Client *source_p, struct Channel *chptr,
          int alevel, int parc, int *parn,
          const char **parv, int *errors, int dir, char c, long mode_type)
 {
-       if(!IsOper(source_p) && !IsServer(source_p))
+       if(MyClient(source_p) && !IsOperGeneral(source_p))
        {
                if(!(*errors & SM_ERR_NOPRIVS))
                        sendto_one_numeric(source_p, ERR_NOPRIVILEGES, form_str(ERR_NOPRIVILEGES));
                *errors |= SM_ERR_NOPRIVS;
                return;
        }
-       if(MyClient(source_p) && !IsOperResv(source_p))
+       if(MyClient(source_p) && !IsOperAdmin(source_p))
        {
                if(!(*errors & SM_ERR_NOPRIVS))
                        sendto_one(source_p, form_str(ERR_NOPRIVS), me.name,
-                                       source_p->name, "resv");
+                                       source_p->name, "admin");
                *errors |= SM_ERR_NOPRIVS;
                return;
        }
 
-       if(!allow_mode_change(source_p, chptr, CHFL_CHANOP, errors, c))
+       if(MyClient(source_p) && (++mode_limit_simple > MAXMODES_SIMPLE))
+               return;
+
+       /* setting + */
+       if((dir == MODE_ADD) && !(chptr->mode.mode & mode_type))
+       {
+               chptr->mode.mode |= mode_type;
+
+               mode_changes[mode_count].letter = c;
+               mode_changes[mode_count].dir = MODE_ADD;
+               mode_changes[mode_count].id = NULL;
+               mode_changes[mode_count].mems = ONLY_OPERS;
+               mode_changes[mode_count++].arg = NULL;
+       }
+       else if((dir == MODE_DEL) && (chptr->mode.mode & mode_type))
+       {
+               chptr->mode.mode &= ~mode_type;
+
+               mode_changes[mode_count].letter = c;
+               mode_changes[mode_count].dir = MODE_DEL;
+               mode_changes[mode_count].mems = ONLY_OPERS;
+               mode_changes[mode_count].id = NULL;
+               mode_changes[mode_count++].arg = NULL;
+       }
+}
+
+void
+chm_staff(struct Client *source_p, struct Channel *chptr,
+         int alevel, int parc, int *parn,
+         const char **parv, int *errors, int dir, char c, long mode_type)
+{
+       if(MyClient(source_p) && !IsOper(source_p))
+       {
+               if(!(*errors & SM_ERR_NOPRIVS))
+                       sendto_one_numeric(source_p, ERR_NOPRIVILEGES, form_str(ERR_NOPRIVILEGES));
+               *errors |= SM_ERR_NOPRIVS;
                return;
+       }
+       if(MyClient(source_p) && !HasPrivilege(source_p, "oper:cmodes"))
+       {
+               if(!(*errors & SM_ERR_NOPRIVS))
+                       sendto_one(source_p, form_str(ERR_NOPRIVS), me.name,
+                                       source_p->name, "cmodes");
+               *errors |= SM_ERR_NOPRIVS;
+               return;
+       }
 
        if(MyClient(source_p) && (++mode_limit_simple > MAXMODES_SIMPLE))
                return;
@@ -781,7 +819,6 @@ chm_ban(struct Client *source_p, struct Channel *chptr,
        default:
                sendto_realops_snomask(SNO_GENERAL, L_ALL, "chm_ban() called with unknown type!");
                return;
-               break;
        }
 
        if(dir == 0 || parc <= *parn)
@@ -792,7 +829,7 @@ chm_ban(struct Client *source_p, struct Channel *chptr,
 
                /* non-ops cant see +eI lists.. */
                /* note that this is still permitted if +e/+I are mlocked. */
-               if(alevel != CHFL_CHANOP && mode_type != CHFL_BAN &&
+               if(alevel < CHFL_CHANOP && mode_type != CHFL_BAN &&
                                mode_type != CHFL_QUIET)
                {
                        if(!(*errors & SM_ERR_NOOPS))
@@ -807,7 +844,7 @@ chm_ban(struct Client *source_p, struct Channel *chptr,
                        char buf[BANLEN];
                        banptr = ptr->data;
                        if(banptr->forward)
-                               rb_snprintf(buf, sizeof(buf), "%s$%s", banptr->banstr, banptr->forward);
+                               snprintf(buf, sizeof(buf), "%s$%s", banptr->banstr, banptr->forward);
                        else
                                rb_strlcpy(buf, banptr->banstr, sizeof(buf));
 
@@ -847,7 +884,7 @@ chm_ban(struct Client *source_p, struct Channel *chptr,
         * also make sure it will always fit on a line with channel
         * name etc.
         */
-       if(strlen(mask) > IRCD_MIN(BANLEN, MODEBUFLEN - 5))
+       if(strlen(mask) > MIN(BANLEN, MODEBUFLEN - 5))
        {
                sendto_one_numeric(source_p, ERR_INVALIDBAN,
                                form_str(ERR_INVALIDBAN),
@@ -937,7 +974,7 @@ chm_ban(struct Client *source_p, struct Channel *chptr,
                }
 
                if(removed && removed->forward)
-                       removed_mask_pos += rb_snprintf(buf + old_removed_mask_pos, sizeof(buf), "%s$%s", removed->banstr, removed->forward) + 1;
+                       removed_mask_pos += snprintf(buf + old_removed_mask_pos, sizeof(buf), "%s$%s", removed->banstr, removed->forward) + 1;
                else
                        removed_mask_pos += rb_strlcpy(buf + old_removed_mask_pos, mask, sizeof(buf)) + 1;
                if(removed)
@@ -1122,7 +1159,7 @@ chm_limit(struct Client *source_p, struct Channel *chptr,
                if(EmptyString(lstr) || (limit = atoi(lstr)) <= 0)
                        return;
 
-               rb_sprintf(limitstr, "%d", limit);
+               sprintf(limitstr, "%d", limit);
 
                mode_changes[mode_count].letter = c;
                mode_changes[mode_count].dir = MODE_ADD;
@@ -1229,7 +1266,7 @@ chm_forward(struct Client *source_p, struct Channel *chptr,
        if(!allow_mode_change(source_p, chptr, alevel, errors, c))
                return;
 #else
-       if(!IsOper(source_p) && !IsServer(source_p))
+       if(!IsOperGeneral(source_p) && !IsServer(source_p))
        {
                if(!(*errors & SM_ERR_NOPRIVS))
                        sendto_one_numeric(source_p, ERR_NOPRIVILEGES, form_str(ERR_NOPRIVILEGES));
@@ -1644,6 +1681,7 @@ set_channel_mode(struct Client *client_p, struct Client *source_p,
        char c;
        struct Client *fakesource_p;
        int reauthorized = 0;   /* if we change from MODE_QUERY to MODE_ADD/MODE_DEL, then reauth once, ugly but it works */
+       int flags_list[3] = { ALL_MEMBERS, ONLY_CHANOPS, ONLY_OPERS };
 
        mask_pos = 0;
        removed_mask_pos = 0;
@@ -1657,7 +1695,7 @@ set_channel_mode(struct Client *client_p, struct Client *source_p,
        else
                fakesource_p = source_p;
 
-       alevel = get_channel_access(source_p, msptr, dir, reconstruct_parv(parc, parv));
+       alevel = get_channel_access(source_p, chptr, msptr, dir, reconstruct_parv(parc, parv));
 
        for(; (c = *ml) != 0; ml++)
        {
@@ -1667,7 +1705,7 @@ set_channel_mode(struct Client *client_p, struct Client *source_p,
                        dir = MODE_ADD;
                        if (!reauthorized)
                        {
-                               alevel = get_channel_access(source_p, msptr, dir, reconstruct_parv(parc, parv));
+                               alevel = get_channel_access(source_p, chptr, msptr, dir, reconstruct_parv(parc, parv));
                                reauthorized = 1;
                        }
                        break;
@@ -1675,7 +1713,7 @@ set_channel_mode(struct Client *client_p, struct Client *source_p,
                        dir = MODE_DEL;
                        if (!reauthorized)
                        {
-                               alevel = get_channel_access(source_p, msptr, dir, reconstruct_parv(parc, parv));
+                               alevel = get_channel_access(source_p, chptr, msptr, dir, reconstruct_parv(parc, parv));
                                reauthorized = 1;
                        }
                        break;
@@ -1696,14 +1734,21 @@ set_channel_mode(struct Client *client_p, struct Client *source_p,
                return;
 
        if(IsServer(source_p))
-               mlen = rb_sprintf(modebuf, ":%s MODE %s ", fakesource_p->name, chptr->chname);
+               mlen = sprintf(modebuf, ":%s MODE %s ", fakesource_p->name, chptr->chname);
        else
-               mlen = rb_sprintf(modebuf, ":%s!%s@%s MODE %s ",
+               mlen = sprintf(modebuf, ":%s!%s@%s MODE %s ",
                                  source_p->name, source_p->username,
                                  source_p->host, chptr->chname);
 
-       for(j = 0, flags = ALL_MEMBERS; j < 2; j++, flags = ONLY_CHANOPS)
+       for(j = 0; j < 3; j++)
        {
+               int send_flags = flags = flags_list[j];
+               const char *priv = NULL;
+               if (flags == ONLY_OPERS)
+               {
+                       send_flags = ALL_MEMBERS;
+                       priv = "auspex:cmodes";
+               }
                cur_len = mlen;
                mbuf = modebuf + mlen;
                pbuf = parabuf;
@@ -1736,8 +1781,8 @@ set_channel_mode(struct Client *client_p, struct Client *source_p,
                                *mbuf = '\0';
 
                                if(cur_len > mlen)
-                                       sendto_channel_local(flags, chptr, "%s %s", modebuf,
-                                                            parabuf);
+                                       sendto_channel_local_priv(IsServer(source_p) ? fakesource_p : source_p,
+                                                       send_flags, priv, chptr, "%s %s", modebuf, parabuf);
                                else
                                        continue;
 
@@ -1762,7 +1807,7 @@ set_channel_mode(struct Client *client_p, struct Client *source_p,
                        if(mode_changes[i].arg != NULL)
                        {
                                paracount++;
-                               len = rb_sprintf(pbuf, "%s ", mode_changes[i].arg);
+                               len = sprintf(pbuf, "%s ", mode_changes[i].arg);
                                pbuf += len;
                                paralen += len;
                        }
@@ -1773,7 +1818,8 @@ set_channel_mode(struct Client *client_p, struct Client *source_p,
 
                *mbuf = '\0';
                if(cur_len > mlen)
-                       sendto_channel_local(flags, chptr, "%s %s", modebuf, parabuf);
+                       sendto_channel_local_priv(IsServer(source_p) ? fakesource_p : source_p,
+                               send_flags, priv, chptr, "%s %s", modebuf, parabuf);
        }
 
        /* only propagate modes originating locally, or if we're hubbing */
@@ -1789,7 +1835,7 @@ set_channel_mode(struct Client *client_p, struct Client *source_p,
  */
 void
 set_channel_mlock(struct Client *client_p, struct Client *source_p,
-                 struct Channel *chptr, const char *newmlock, int propagate)
+                 struct Channel *chptr, const char *newmlock, bool propagate)
 {
        rb_free(chptr->mode_lock);
        chptr->mode_lock = newmlock ? rb_strdup(newmlock) : NULL;