ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/channel_mode.c
(Generate patch)

Comparing ircd-hybrid/trunk/src/channel_mode.c (file contents):
Revision 4800 by michael, Tue Oct 28 13:59:43 2014 UTC vs.
Revision 8091 by michael, Wed Mar 29 12:50:17 2017 UTC

# Line 1 | Line 1
1   /*
2   *  ircd-hybrid: an advanced, lightweight Internet Relay Chat Daemon (ircd)
3   *
4 < *  Copyright (c) 1997-2014 ircd-hybrid development team
4 > *  Copyright (c) 1997-2017 ircd-hybrid development team
5   *
6   *  This program is free software; you can redistribute it and/or modify
7   *  it under the terms of the GNU General Public License as published by
# Line 40 | Line 40
40   #include "mempool.h"
41   #include "parse.h"
42  
43 – /* 10 is a magic number in hybrid 6 NFI where it comes from -db */
44 – #define BAN_FUDGE       10
43  
44   static char nuh_mask[MAXPARA][IRCD_BUFSIZE];
47 – /* some buffers for rebuilding channel/nick lists with ,'s */
48 – static char modebuf[IRCD_BUFSIZE];
49 – static char parabuf[MODEBUFLEN];
45   static struct ChModeChange mode_changes[IRCD_BUFSIZE];
46   static unsigned int mode_count;
47   static unsigned int mode_limit;  /* number of modes set other than simple */
48   static unsigned int simple_modes_mask;  /* bit mask of simple modes already set */
49   extern mp_pool_t *ban_pool;
50  
56 – const struct mode_letter chan_modes[] =
57 – {
58 –  { MODE_NOCTRL,     'c' },
59 –  { MODE_INVITEONLY, 'i' },
60 –  { MODE_MODERATED,  'm' },
61 –  { MODE_NOPRIVMSGS, 'n' },
62 –  { MODE_PRIVATE,    'p' },
63 –  { MODE_REGISTERED, 'r' },
64 –  { MODE_SECRET,     's' },
65 –  { MODE_TOPICLIMIT, 't' },
66 –  { MODE_MODREG,     'M' },
67 –  { MODE_OPERONLY,   'O' },
68 –  { MODE_REGONLY,    'R' },
69 –  { MODE_SSLONLY,    'S' },
70 –  { 0, '\0' }
71 – };
72 –
51  
52   /* check_string()
53   *
# Line 83 | Line 61 | const struct mode_letter chan_modes[] =
61   static char *
62   check_string(char *s)
63   {
64 <  char *str = s;
64 >  char *const str = s;
65    static char star[] = "*";
66  
67    if (EmptyString(str))
# Line 102 | Line 80 | check_string(char *s)
80   }
81  
82   /*
83 < * Ban functions to work with mode +b/e/d/I
83 > * Ban functions to work with mode +b/e/I
84   */
85   /* add the specified ID to the channel.
86   *   -is 8/9/00
# Line 111 | Line 89 | check_string(char *s)
89   int
90   add_id(struct Client *client_p, struct Channel *chptr, char *banid, unsigned int type)
91   {
92 <  dlink_list *list = NULL;
93 <  dlink_node *node = NULL;
116 <  struct Ban *banptr = NULL;
117 <  size_t len = 0;
92 >  dlink_list *list;
93 >  dlink_node *node;
94    char name[NICKLEN + 1] = "";
95    char user[USERLEN + 1] = "";
96    char host[HOSTLEN + 1] = "";
97    struct split_nuh_item nuh;
98  
123 –  /* Don't let local clients overflow the b/e/I lists */
99    if (MyClient(client_p))
100    {
101      unsigned int num_mask = dlink_list_length(&chptr->banlist) +
102                              dlink_list_length(&chptr->exceptlist) +
103                              dlink_list_length(&chptr->invexlist);
104  
105 <    if (num_mask >= ConfigChannel.max_bans)
105 >    /* Don't let local clients overflow the b/e/I lists */
106 >    if (num_mask >= ((HasCMode(chptr, MODE_EXTLIMIT)) ? ConfigChannel.max_bans_large :
107 >                                                        ConfigChannel.max_bans))
108      {
109        sendto_one_numeric(client_p, &me, ERR_BANLISTFULL, chptr->name, banid);
110        return 0;
# Line 151 | Line 128 | add_id(struct Client *client_p, struct C
128     * Re-assemble a new n!u@h and print it back to banid for sending
129     * the mode to the channel.
130     */
131 <  len = sprintf(banid, "%s!%s@%s", name, user, host);
131 >  size_t len = snprintf(banid, IRCD_BUFSIZE, "%s!%s@%s", name, user, host);
132  
133    switch (type)
134    {
135      case CHFL_BAN:
136        list = &chptr->banlist;
137 <      clear_ban_cache(chptr);
137 >      clear_ban_cache_list(&chptr->locmembers);
138        break;
139      case CHFL_EXCEPTION:
140        list = &chptr->exceptlist;
141 <      clear_ban_cache(chptr);
141 >      clear_ban_cache_list(&chptr->locmembers);
142        break;
143      case CHFL_INVEX:
144        list = &chptr->invexlist;
145        break;
146      default:
147 <      assert(0);
171 <      return 0;
147 >      list = NULL;  /* Let it crash */
148    }
149  
150    DLINK_FOREACH(node, list->head)
151    {
152 <    banptr = node->data;
152 >    const struct Ban *ban = node->data;
153  
154 <    if (!irccmp(banptr->name, name) &&
155 <        !irccmp(banptr->user, user) &&
156 <        !irccmp(banptr->host, host))
154 >    if (!irccmp(ban->name, name) &&
155 >        !irccmp(ban->user, user) &&
156 >        !irccmp(ban->host, host))
157        return 0;
158    }
159  
160 <  banptr = mp_pool_get(ban_pool);
161 <  banptr->name = xstrdup(name);
162 <  banptr->user = xstrdup(user);
163 <  banptr->host = xstrdup(host);
164 <  banptr->when = CurrentTime;
165 <  banptr->len = len - 2;  /* -2 for ! + @ */
166 <  banptr->type = parse_netmask(host, &banptr->addr, &banptr->bits);
160 >  struct Ban *ban = mp_pool_get(ban_pool);
161 >  ban->when = CurrentTime;
162 >  ban->len = len - 2;  /* -2 for ! + @ */
163 >  ban->type = parse_netmask(host, &ban->addr, &ban->bits);
164 >  strlcpy(ban->name, name, sizeof(ban->name));
165 >  strlcpy(ban->user, user, sizeof(ban->user));
166 >  strlcpy(ban->host, host, sizeof(ban->host));
167  
168    if (IsClient(client_p))
169 <  {
170 <    banptr->who = MyCalloc(strlen(client_p->name) +
171 <                           strlen(client_p->username) +
172 <                           strlen(client_p->host) + 3);
197 <    sprintf(banptr->who, "%s!%s@%s", client_p->name,
198 <            client_p->username, client_p->host);
199 <  }
200 <  else if (IsHidden(client_p) || (IsServer(client_p) && ConfigServerHide.hide_servers))
201 <    banptr->who = xstrdup(me.name);
169 >    snprintf(ban->who, sizeof(ban->who), "%s!%s@%s", client_p->name,
170 >             client_p->username, client_p->host);
171 >  else if (IsHidden(client_p) || ConfigServerHide.hide_servers)
172 >    strlcpy(ban->who, me.name, sizeof(ban->who));
173    else
174 <    banptr->who = xstrdup(client_p->name);
174 >    strlcpy(ban->who, client_p->name, sizeof(ban->who));
175  
176 <  dlinkAdd(banptr, &banptr->node, list);
176 >  dlinkAdd(ban, &ban->node, list);
177  
178    return 1;
179   }
# Line 217 | Line 188 | add_id(struct Client *client_p, struct C
188   static int
189   del_id(struct Channel *chptr, char *banid, unsigned int type)
190   {
191 <  dlink_list *list = NULL;
192 <  dlink_node *node = NULL;
191 >  dlink_list *list;
192 >  dlink_node *node;
193    char name[NICKLEN + 1] = "";
194    char user[USERLEN + 1] = "";
195    char host[HOSTLEN + 1] = "";
# Line 241 | Line 212 | del_id(struct Channel *chptr, char *bani
212     * Re-assemble a new n!u@h and print it back to banid for sending
213     * the mode to the channel.
214     */
215 <  sprintf(banid, "%s!%s@%s", name, user, host);
215 >  snprintf(banid, IRCD_BUFSIZE, "%s!%s@%s", name, user, host);
216  
217    switch (type)
218    {
219      case CHFL_BAN:
220        list = &chptr->banlist;
221 <      clear_ban_cache(chptr);
221 >      clear_ban_cache_list(&chptr->locmembers);
222        break;
223      case CHFL_EXCEPTION:
224        list = &chptr->exceptlist;
225 <      clear_ban_cache(chptr);
225 >      clear_ban_cache_list(&chptr->locmembers);
226        break;
227      case CHFL_INVEX:
228        list = &chptr->invexlist;
229        break;
230      default:
231 <      assert(0);
261 <      return 0;
231 >      list = NULL;  /* Let it crash */
232    }
233  
234    DLINK_FOREACH(node, list->head)
235    {
236 <    struct Ban *banptr = node->data;
236 >    struct Ban *ban = node->data;
237  
238 <    if (!irccmp(name, banptr->name) &&
239 <        !irccmp(user, banptr->user) &&
240 <        !irccmp(host, banptr->host))
238 >    if (!irccmp(name, ban->name) &&
239 >        !irccmp(user, ban->user) &&
240 >        !irccmp(host, ban->host))
241      {
242 <      remove_ban(banptr, list);
242 >      remove_ban(ban, list);
243        return 1;
244      }
245    }
# Line 293 | Line 263 | channel_modes(struct Channel *chptr, str
263    *mbuf++ = '+';
264    *pbuf = '\0';
265  
266 <  for (const struct mode_letter *tab = chan_modes; tab->mode; ++tab)
267 <    if (chptr->mode.mode & tab->mode)
266 >  for (const struct chan_mode *tab = cmode_tab; tab->mode; ++tab)
267 >    if (tab->mode && HasCMode(chptr, tab->mode))
268        *mbuf++ = tab->letter;
269  
270    if (chptr->mode.limit)
271    {
272      *mbuf++ = 'l';
273  
274 <    if (IsServer(client_p) || HasFlag(client_p, FLAGS_SERVICE) || IsMember(client_p, chptr))
275 <      pbuf += sprintf(pbuf, "%d ", chptr->mode.limit);
274 >    if (IsServer(client_p) || IsMember(client_p, chptr))
275 >      pbuf += sprintf(pbuf, "%u ", chptr->mode.limit);
276    }
277  
278    if (chptr->mode.key[0])
279    {
280      *mbuf++ = 'k';
281  
282 <    if (IsServer(client_p) || HasFlag(client_p, FLAGS_SERVICE) || IsMember(client_p, chptr))
282 >    if (IsServer(client_p) || IsMember(client_p, chptr))
283        sprintf(pbuf, "%s ", chptr->mode.key);
284    }
285  
# Line 329 | Line 299 | fix_key(char *arg)
299   {
300    unsigned char *s, *t, c;
301  
302 <  for (s = t = (unsigned char *)arg; (c = *s); ++s)
302 >  for (s = t = (unsigned char *)arg; (c = *s) && s - (unsigned char *)arg < KEYLEN; ++s)
303    {
304      c &= 0x7f;
305  
# Line 347 | Line 317 | fix_key(char *arg)
317   * side effects - clear ban cache
318   */
319   void
320 < clear_ban_cache(struct Channel *chptr)
320 > clear_ban_cache_list(dlink_list *list)
321   {
322 <  dlink_node *node = NULL;
322 >  dlink_node *node;
323  
324 <  DLINK_FOREACH(node, chptr->locmembers.head)
355 <  {
356 <    struct Membership *ms = node->data;
357 <    ms->flags &= ~(CHFL_BAN_SILENCED|CHFL_BAN_CHECKED);
358 <  }
359 < }
360 <
361 < void
362 < clear_ban_cache_client(struct Client *client_p)
363 < {
364 <  dlink_node *node = NULL;
365 <
366 <  DLINK_FOREACH(node, client_p->channel.head)
324 >  DLINK_FOREACH(node, list->head)
325    {
326 <    struct Membership *ms = node->data;
327 <    ms->flags &= ~(CHFL_BAN_SILENCED|CHFL_BAN_CHECKED);
326 >    struct Membership *member = node->data;
327 >    member->flags &= ~(CHFL_BAN_SILENCED | CHFL_BAN_CHECKED);
328    }
329   }
330  
# Line 382 | Line 340 | enum
340    SM_ERR_RPL_E        = 1 << 3,
341    SM_ERR_RPL_I        = 1 << 4,
342    SM_ERR_NOTONCHANNEL = 1 << 5,  /* Client is not on channel */
343 <  SM_ERR_NOTOPER      = 1 << 6,
344 <  SM_ERR_ONLYSERVER   = 1 << 7
343 >  SM_ERR_NOTOPER      = 1 << 6,  /* Only irc-operators can change that mode */
344 >  SM_ERR_ONLYSERVER   = 1 << 7   /* Only servers or services can change that mode */
345   };
346  
347   /* Mode functions handle mode changes for a particular mode... */
348   static void
349 < chm_nosuch(struct Client *source_p, struct Channel *chptr, int parc, int *parn,
350 <           char **parv, int *errors, int alev, int dir, char c, unsigned int d)
349 > chm_nosuch(struct Client *source_p, struct Channel *chptr, int parc, int *parn, char **parv,
350 >           int *errors, int alev, int dir, const struct chan_mode *mode)
351   {
352    if (*errors & SM_ERR_UNKNOWN)
353      return;
354  
355    *errors |= SM_ERR_UNKNOWN;
356 <  sendto_one_numeric(source_p, &me, ERR_UNKNOWNMODE, c);
356 >  sendto_one_numeric(source_p, &me, ERR_UNKNOWNMODE, mode->letter);
357   }
358  
359   static void
360 < chm_simple(struct Client *source_p, struct Channel *chptr, int parc, int *parn,
361 <           char **parv, int *errors, int alev, int dir, char c, unsigned int d)
360 > chm_simple(struct Client *source_p, struct Channel *chptr, int parc, int *parn, char **parv,
361 >           int *errors, int alev, int dir, const struct chan_mode *mode)
362   {
363 <  if (alev < CHACCESS_HALFOP)
406 <  {
407 <    if (!(*errors & SM_ERR_NOOPS))
408 <      sendto_one_numeric(source_p, &me,
409 <                         alev == CHACCESS_NOTONCHAN ? ERR_NOTONCHANNEL :
410 <                         ERR_CHANOPRIVSNEEDED, chptr->name);
411 <    *errors |= SM_ERR_NOOPS;
412 <    return;
413 <  }
414 <
415 <  /* If have already dealt with this simple mode, ignore it */
416 <  if (simple_modes_mask & d)
417 <    return;
418 <
419 <  simple_modes_mask |= d;
420 <
421 <  /* setting + */
422 <  /* Apparently, (though no one has ever told the hybrid group directly)
423 <   * admins don't like redundant mode checking. ok. It would have been nice
424 <   * if you had have told us directly. I've left the original code snippets
425 <   * in place.
426 <   *
427 <   * -Dianora
428 <   */
429 <  if (dir == MODE_ADD) /* && !(chptr->mode.mode & d)) */
430 <  {
431 <    chptr->mode.mode |= d;
432 <
433 <    mode_changes[mode_count].letter = c;
434 <    mode_changes[mode_count].arg = NULL;
435 <    mode_changes[mode_count].id = NULL;
436 <    mode_changes[mode_count++].dir = dir;
437 <  }
438 <  else if (dir == MODE_DEL) /* && (chptr->mode.mode & d)) */
363 >  if (mode->only_opers)
364    {
365 <    /* setting - */
366 <
367 <    chptr->mode.mode &= ~d;
368 <
444 <    mode_changes[mode_count].letter = c;
445 <    mode_changes[mode_count].arg = NULL;
446 <    mode_changes[mode_count].id = NULL;
447 <    mode_changes[mode_count++].dir = dir;
448 <  }
449 < }
365 >    if (MyClient(source_p) && !HasUMode(source_p, UMODE_OPER))
366 >    {
367 >      if (!(*errors & SM_ERR_NOTOPER))
368 >        sendto_one_numeric(source_p, &me, ERR_NOPRIVILEGES);
369  
370 < static void
371 < chm_registered(struct Client *source_p, struct Channel *chptr, int parc, int *parn,
372 <               char **parv, int *errors, int alev, int dir, char c, unsigned int d)
454 < {
455 <  if (!IsServer(source_p) && !HasFlag(source_p, FLAGS_SERVICE))
456 <  {
457 <    if (!(*errors & SM_ERR_ONLYSERVER))
458 <      sendto_one_numeric(source_p, &me,
459 <                         alev == CHACCESS_NOTONCHAN ? ERR_NOTONCHANNEL :
460 <                         ERR_ONLYSERVERSCANCHANGE, chptr->name);
461 <    *errors |= SM_ERR_ONLYSERVER;
462 <    return;
370 >      *errors |= SM_ERR_NOTOPER;
371 >      return;
372 >    }
373    }
374  
375 <  /* If have already dealt with this simple mode, ignore it */
466 <  if (simple_modes_mask & d)
467 <    return;
468 <
469 <  simple_modes_mask |= d;
470 <
471 <  /* setting + */
472 <  /* Apparently, (though no one has ever told the hybrid group directly)
473 <   * admins don't like redundant mode checking. ok. It would have been nice
474 <   * if you had have told us directly. I've left the original code snippets
475 <   * in place.
476 <   *
477 <   * -Dianora
478 <   */
479 <  if (dir == MODE_ADD) /* && !(chptr->mode.mode & d)) */
375 >  if (mode->only_servers)
376    {
377 <    chptr->mode.mode |= d;
378 <
379 <    mode_changes[mode_count].letter = c;
380 <    mode_changes[mode_count].arg = NULL;
381 <    mode_changes[mode_count].id = NULL;
382 <    mode_changes[mode_count++].dir = dir;
487 <  }
488 <  else if (dir == MODE_DEL) /* && (chptr->mode.mode & d)) */
489 <  {
490 <    /* setting - */
491 <
492 <    chptr->mode.mode &= ~d;
377 >    if (!IsServer(source_p) && !HasFlag(source_p, FLAGS_SERVICE))
378 >    {
379 >      if (!(*errors & SM_ERR_ONLYSERVER))
380 >        sendto_one_numeric(source_p, &me,
381 >                           alev == CHACCESS_NOTONCHAN ? ERR_NOTONCHANNEL :
382 >                           ERR_ONLYSERVERSCANCHANGE, chptr->name);
383  
384 <    mode_changes[mode_count].letter = c;
385 <    mode_changes[mode_count].arg = NULL;
386 <    mode_changes[mode_count].id = NULL;
497 <    mode_changes[mode_count++].dir = dir;
384 >      *errors |= SM_ERR_ONLYSERVER;
385 >      return;
386 >    }
387    }
499 – }
388  
389 < static void
502 < chm_operonly(struct Client *source_p, struct Channel *chptr, int parc, int *parn,
503 <             char **parv, int *errors, int alev, int dir, char c, unsigned int d)
504 < {
505 <  if (alev < CHACCESS_CHANOP)
389 >  if (alev < CHACCESS_HALFOP)
390    {
391      if (!(*errors & SM_ERR_NOOPS))
392        sendto_one_numeric(source_p, &me,
# Line 513 | Line 397 | chm_operonly(struct Client *source_p, st
397      return;
398    }
399  
516 –  if (MyClient(source_p) && !HasUMode(source_p, UMODE_OPER))
517 –  {
518 –    if (!(*errors & SM_ERR_NOTOPER))
519 –      sendto_one_numeric(source_p, &me, ERR_NOPRIVILEGES);
520 –
521 –    *errors |= SM_ERR_NOTOPER;
522 –    return;
523 –  }
524 –
400    /* If have already dealt with this simple mode, ignore it */
401 <  if (simple_modes_mask & d)
401 >  if (simple_modes_mask & mode->mode)
402      return;
403  
404 <  simple_modes_mask |= d;
404 >  simple_modes_mask |= mode->mode;
405  
406 +  /* setting + */
407    if (dir == MODE_ADD) /* && !(chptr->mode.mode & d)) */
408    {
409 <    chptr->mode.mode |= d;
409 >    AddCMode(chptr, mode->mode);
410  
411 <    mode_changes[mode_count].letter = c;
411 >    mode_changes[mode_count].letter = mode->letter;
412      mode_changes[mode_count].arg = NULL;
413      mode_changes[mode_count].id = NULL;
414 +    mode_changes[mode_count].flags = 0;
415      mode_changes[mode_count++].dir = dir;
416    }
417    else if (dir == MODE_DEL) /* && (chptr->mode.mode & d)) */
418    {
419      /* setting - */
420 +    DelCMode(chptr, mode->mode);
421  
422 <    chptr->mode.mode &= ~d;
545 <
546 <    mode_changes[mode_count].letter = c;
422 >    mode_changes[mode_count].letter = mode->letter;
423      mode_changes[mode_count].arg = NULL;
424      mode_changes[mode_count].id = NULL;
425 +    mode_changes[mode_count].flags = 0;
426      mode_changes[mode_count++].dir = dir;
427    }
428   }
429  
430   static void
431 < chm_ban(struct Client *source_p, struct Channel *chptr, int parc, int *parn,
432 <        char **parv, int *errors, int alev, int dir, char c, unsigned int d)
431 > chm_ban(struct Client *source_p, struct Channel *chptr, int parc, int *parn, char **parv,
432 >        int *errors, int alev, int dir, const struct chan_mode *mode)
433   {
557 –  char *mask = NULL;
558 –
434    if (dir == MODE_QUERY || parc <= *parn)
435    {
436 <    dlink_node *node = NULL;
436 >    dlink_node *node;
437  
438      if (*errors & SM_ERR_RPL_B)
439        return;
# Line 567 | Line 442 | chm_ban(struct Client *source_p, struct
442  
443      DLINK_FOREACH(node, chptr->banlist.head)
444      {
445 <      const struct Ban *banptr = node->data;
446 <      sendto_one_numeric(source_p, &me, RPL_BANLIST, chptr->name,
447 <                         banptr->name, banptr->user, banptr->host,
448 <                         banptr->who, banptr->when);
445 >      const struct Ban *ban = node->data;
446 >
447 >      if (!HasCMode(chptr, MODE_HIDEBMASKS) || alev >= CHACCESS_HALFOP)
448 >        sendto_one_numeric(source_p, &me, RPL_BANLIST, chptr->name,
449 >                           ban->name, ban->user, ban->host,
450 >                           ban->who, ban->when);
451      }
452  
453      sendto_one_numeric(source_p, &me, RPL_ENDOFBANLIST, chptr->name);
# Line 583 | Line 460 | chm_ban(struct Client *source_p, struct
460        sendto_one_numeric(source_p, &me,
461                           alev == CHACCESS_NOTONCHAN ? ERR_NOTONCHANNEL :
462                           ERR_CHANOPRIVSNEEDED, chptr->name);
463 +
464      *errors |= SM_ERR_NOOPS;
465      return;
466    }
# Line 590 | Line 468 | chm_ban(struct Client *source_p, struct
468    if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
469      return;
470  
471 <  mask = nuh_mask[*parn];
472 <  memcpy(mask, parv[*parn], sizeof(nuh_mask[*parn]));
471 >  char *const mask = nuh_mask[*parn];
472 >  strlcpy(mask, parv[*parn], sizeof(nuh_mask[*parn]));
473    ++(*parn);
474  
475 <  if (!MyConnect(source_p))
476 <    if (strchr(mask, ' '))
599 <      return;
475 >  if (*mask == ':' || (!MyConnect(source_p) && strchr(mask, ' ')))
476 >    return;
477  
478    switch (dir)
479    {
# Line 612 | Line 489 | chm_ban(struct Client *source_p, struct
489        assert(0);
490    }
491  
492 <  mode_changes[mode_count].letter = c;
493 <  mode_changes[mode_count].arg = mask;
492 >  mode_changes[mode_count].letter = mode->letter;
493 >  mode_changes[mode_count].arg = mask;  /* At this point 'mask' is no longer than NICKLEN + USERLEN + HOSTLEN + 3 */
494    mode_changes[mode_count].id = NULL;
495 +  if (HasCMode(chptr, MODE_HIDEBMASKS))
496 +    mode_changes[mode_count].flags = CHFL_CHANOP | CHFL_HALFOP;
497 +  else
498 +    mode_changes[mode_count].flags = 0;
499    mode_changes[mode_count++].dir = dir;
500   }
501  
502   static void
503 < chm_except(struct Client *source_p, struct Channel *chptr, int parc, int *parn,
504 <           char **parv, int *errors, int alev, int dir, char c, unsigned int d)
503 > chm_except(struct Client *source_p, struct Channel *chptr, int parc, int *parn, char **parv,
504 >           int *errors, int alev, int dir, const struct chan_mode *mode)
505   {
625 –  char *mask = NULL;
626 –
506    if (dir == MODE_QUERY || parc <= *parn)
507    {
508 <    dlink_node *node = NULL;
508 >    dlink_node *node;
509  
510      if (*errors & SM_ERR_RPL_E)
511        return;
# Line 635 | Line 514 | chm_except(struct Client *source_p, stru
514  
515      DLINK_FOREACH(node, chptr->exceptlist.head)
516      {
517 <      const struct Ban *banptr = node->data;
517 >      const struct Ban *ban = node->data;
518  
519 <      sendto_one_numeric(source_p, &me, RPL_EXCEPTLIST, chptr->name,
520 <                         banptr->name, banptr->user, banptr->host,
521 <                         banptr->who, banptr->when);
519 >      if (!HasCMode(chptr, MODE_HIDEBMASKS) || alev >= CHACCESS_HALFOP)
520 >        sendto_one_numeric(source_p, &me, RPL_EXCEPTLIST, chptr->name,
521 >                           ban->name, ban->user, ban->host,
522 >                           ban->who, ban->when);
523      }
524  
525      sendto_one_numeric(source_p, &me, RPL_ENDOFEXCEPTLIST, chptr->name);
# Line 652 | Line 532 | chm_except(struct Client *source_p, stru
532        sendto_one_numeric(source_p, &me,
533                           alev == CHACCESS_NOTONCHAN ? ERR_NOTONCHANNEL :
534                           ERR_CHANOPRIVSNEEDED, chptr->name);
535 +
536      *errors |= SM_ERR_NOOPS;
537      return;
538    }
# Line 659 | Line 540 | chm_except(struct Client *source_p, stru
540    if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
541      return;
542  
543 <  mask = nuh_mask[*parn];
544 <  memcpy(mask, parv[*parn], sizeof(nuh_mask[*parn]));
543 >  char *const mask = nuh_mask[*parn];
544 >  strlcpy(mask, parv[*parn], sizeof(nuh_mask[*parn]));
545    ++(*parn);
546  
547 <  if (!MyConnect(source_p))
548 <    if (strchr(mask, ' '))
668 <      return;
547 >  if (*mask == ':' || (!MyConnect(source_p) && strchr(mask, ' ')))
548 >    return;
549  
550    switch (dir)
551    {
# Line 681 | Line 561 | chm_except(struct Client *source_p, stru
561        assert(0);
562    }
563  
564 <  mode_changes[mode_count].letter = c;
565 <  mode_changes[mode_count].arg = mask;
564 >  mode_changes[mode_count].letter = mode->letter;
565 >  mode_changes[mode_count].arg = mask;  /* At this point 'mask' is no longer than NICKLEN + USERLEN + HOSTLEN + 3 */
566    mode_changes[mode_count].id = NULL;
567 +  if (HasCMode(chptr, MODE_HIDEBMASKS))
568 +    mode_changes[mode_count].flags = CHFL_CHANOP | CHFL_HALFOP;
569 +  else
570 +    mode_changes[mode_count].flags = 0;
571    mode_changes[mode_count++].dir = dir;
572   }
573  
574   static void
575 < chm_invex(struct Client *source_p, struct Channel *chptr, int parc, int *parn,
576 <          char **parv, int *errors, int alev, int dir, char c, unsigned int d)
575 > chm_invex(struct Client *source_p, struct Channel *chptr, int parc, int *parn, char **parv,
576 >          int *errors, int alev, int dir, const struct chan_mode *mode)
577   {
694 –  char *mask = NULL;
695 –
578    if (dir == MODE_QUERY || parc <= *parn)
579    {
580 <    dlink_node *node = NULL;
580 >    dlink_node *node;
581  
582      if (*errors & SM_ERR_RPL_I)
583        return;
# Line 704 | Line 586 | chm_invex(struct Client *source_p, struc
586  
587      DLINK_FOREACH(node, chptr->invexlist.head)
588      {
589 <      const struct Ban *banptr = node->data;
589 >      const struct Ban *ban = node->data;
590  
591 <      sendto_one_numeric(source_p, &me, RPL_INVEXLIST, chptr->name,
592 <                         banptr->name, banptr->user, banptr->host,
593 <                         banptr->who, banptr->when);
591 >      if (!HasCMode(chptr, MODE_HIDEBMASKS) || alev >= CHACCESS_HALFOP)
592 >        sendto_one_numeric(source_p, &me, RPL_INVEXLIST, chptr->name,
593 >                           ban->name, ban->user, ban->host,
594 >                           ban->who, ban->when);
595      }
596  
597      sendto_one_numeric(source_p, &me, RPL_ENDOFINVEXLIST, chptr->name);
# Line 721 | Line 604 | chm_invex(struct Client *source_p, struc
604        sendto_one_numeric(source_p, &me,
605                           alev == CHACCESS_NOTONCHAN ? ERR_NOTONCHANNEL :
606                           ERR_CHANOPRIVSNEEDED, chptr->name);
607 +
608      *errors |= SM_ERR_NOOPS;
609      return;
610    }
# Line 728 | Line 612 | chm_invex(struct Client *source_p, struc
612    if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
613      return;
614  
615 <  mask = nuh_mask[*parn];
616 <  memcpy(mask, parv[*parn], sizeof(nuh_mask[*parn]));
615 >  char *const mask = nuh_mask[*parn];
616 >  strlcpy(mask, parv[*parn], sizeof(nuh_mask[*parn]));
617    ++(*parn);
618  
619 <  if (!MyConnect(source_p))
620 <    if (strchr(mask, ' '))
737 <      return;
619 >  if (*mask == ':' || (!MyConnect(source_p) && strchr(mask, ' ')))
620 >    return;
621  
622    switch (dir)
623    {
# Line 750 | Line 633 | chm_invex(struct Client *source_p, struc
633        assert(0);
634    }
635  
636 <  mode_changes[mode_count].letter = c;
637 <  mode_changes[mode_count].arg = mask;
636 >  mode_changes[mode_count].letter = mode->letter;
637 >  mode_changes[mode_count].arg = mask;  /* At this point 'mask' is no longer than NICKLEN + USERLEN + HOSTLEN + 3 */
638    mode_changes[mode_count].id = NULL;
639 +  if (HasCMode(chptr, MODE_HIDEBMASKS))
640 +    mode_changes[mode_count].flags = CHFL_CHANOP | CHFL_HALFOP;
641 +  else
642 +    mode_changes[mode_count].flags = 0;
643    mode_changes[mode_count++].dir = dir;
644   }
645  
646   static void
647 < chm_voice(struct Client *source_p, struct Channel *chptr, int parc, int *parn,
648 <          char **parv, int *errors, int alev, int dir, char c, unsigned int d)
647 > chm_voice(struct Client *source_p, struct Channel *chptr, int parc, int *parn, char **parv,
648 >          int *errors, int alev, int dir, const struct chan_mode *mode)
649   {
650    struct Client *target_p;
651    struct Membership *member;
# Line 769 | Line 656 | chm_voice(struct Client *source_p, struc
656        sendto_one_numeric(source_p, &me,
657                           alev == CHACCESS_NOTONCHAN ? ERR_NOTONCHANNEL :
658                           ERR_CHANOPRIVSNEEDED, chptr->name);
659 +
660      *errors |= SM_ERR_NOOPS;
661      return;
662    }
# Line 783 | Line 671 | chm_voice(struct Client *source_p, struc
671    {
672      if (!(*errors & SM_ERR_NOTONCHANNEL))
673        sendto_one_numeric(source_p, &me, ERR_USERNOTINCHANNEL, target_p->name, chptr->name);
674 +
675      *errors |= SM_ERR_NOTONCHANNEL;
676      return;
677    }
# Line 790 | Line 679 | chm_voice(struct Client *source_p, struc
679    if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
680      return;
681  
682 <  /* no redundant mode changes */
683 <  if (dir == MODE_ADD &&  has_member_flags(member, CHFL_VOICE))
684 <    return;
685 <  if (dir == MODE_DEL && !has_member_flags(member, CHFL_VOICE))
686 <    return;
682 >  switch (dir)
683 >  {
684 >    case MODE_ADD:
685 >      if (has_member_flags(member, CHFL_VOICE))
686 >        return;  /* No redundant mode changes */
687 >
688 >      AddMemberFlag(member, CHFL_VOICE);
689 >      break;
690 >    case MODE_DEL:
691 >      if (!has_member_flags(member, CHFL_VOICE))
692 >        return;  /* No redundant mode changes */
693 >
694 >      DelMemberFlag(member, CHFL_VOICE);
695 >      break;
696 >  }
697  
698 <  mode_changes[mode_count].letter = c;
698 >  mode_changes[mode_count].letter = mode->letter;
699    mode_changes[mode_count].arg = target_p->name;
700    mode_changes[mode_count].id = target_p->id;
701 +  mode_changes[mode_count].flags = 0;
702    mode_changes[mode_count++].dir = dir;
803 –
804 –  if (dir == MODE_ADD)
805 –    AddMemberFlag(member, CHFL_VOICE);
806 –  else
807 –    DelMemberFlag(member, CHFL_VOICE);
703   }
704  
705   static void
706 < chm_hop(struct Client *source_p, struct Channel *chptr, int parc, int *parn,
707 <        char **parv, int *errors, int alev, int dir, char c, unsigned int d)
706 > chm_hop(struct Client *source_p, struct Channel *chptr, int parc, int *parn, char **parv,
707 >        int *errors, int alev, int dir, const struct chan_mode *mode)
708   {
709    struct Client *target_p;
710    struct Membership *member;
# Line 820 | Line 715 | chm_hop(struct Client *source_p, struct
715        sendto_one_numeric(source_p, &me,
716                           alev == CHACCESS_NOTONCHAN ? ERR_NOTONCHANNEL :
717                           ERR_CHANOPRIVSNEEDED, chptr->name);
718 +
719      *errors |= SM_ERR_NOOPS;
720      return;
721    }
# Line 834 | Line 730 | chm_hop(struct Client *source_p, struct
730    {
731      if (!(*errors & SM_ERR_NOTONCHANNEL))
732        sendto_one_numeric(source_p, &me, ERR_USERNOTINCHANNEL, target_p->name, chptr->name);
733 +
734      *errors |= SM_ERR_NOTONCHANNEL;
735      return;
736    }
# Line 841 | Line 738 | chm_hop(struct Client *source_p, struct
738    if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
739      return;
740  
741 <  /* no redundant mode changes */
742 <  if (dir == MODE_ADD &&  has_member_flags(member, CHFL_HALFOP))
743 <    return;
744 <  if (dir == MODE_DEL && !has_member_flags(member, CHFL_HALFOP))
745 <    return;
741 >  switch (dir)
742 >  {
743 >    case MODE_ADD:
744 >      if (has_member_flags(member, CHFL_HALFOP))
745 >        return;  /* No redundant mode changes */
746 >
747 >      AddMemberFlag(member, CHFL_HALFOP);
748 >      break;
749 >    case MODE_DEL:
750 >      if (!has_member_flags(member, CHFL_HALFOP))
751 >        return;  /* No redundant mode changes */
752  
753 <  mode_changes[mode_count].letter = c;
753 >      DelMemberFlag(member, CHFL_HALFOP);
754 >      break;
755 >  }
756 >
757 >  mode_changes[mode_count].letter = mode->letter;
758    mode_changes[mode_count].arg = target_p->name;
759    mode_changes[mode_count].id = target_p->id;
760 +  mode_changes[mode_count].flags = 0;
761    mode_changes[mode_count++].dir = dir;
854 –
855 –  if (dir == MODE_ADD)
856 –    AddMemberFlag(member, CHFL_HALFOP);
857 –  else
858 –    DelMemberFlag(member, CHFL_HALFOP);
762   }
763  
764   static void
765 < chm_op(struct Client *source_p, struct Channel *chptr, int parc, int *parn,
766 <       char **parv, int *errors, int alev, int dir, char c, unsigned int d)
765 > chm_op(struct Client *source_p, struct Channel *chptr, int parc, int *parn, char **parv,
766 >       int *errors, int alev, int dir, const struct chan_mode *mode)
767   {
768    struct Client *target_p;
769    struct Membership *member;
# Line 871 | Line 774 | chm_op(struct Client *source_p, struct C
774        sendto_one_numeric(source_p, &me,
775                           alev == CHACCESS_NOTONCHAN ? ERR_NOTONCHANNEL :
776                           ERR_CHANOPRIVSNEEDED, chptr->name);
777 +
778      *errors |= SM_ERR_NOOPS;
779      return;
780    }
# Line 885 | Line 789 | chm_op(struct Client *source_p, struct C
789    {
790      if (!(*errors & SM_ERR_NOTONCHANNEL))
791        sendto_one_numeric(source_p, &me, ERR_USERNOTINCHANNEL, target_p->name, chptr->name);
792 +
793      *errors |= SM_ERR_NOTONCHANNEL;
794      return;
795    }
# Line 892 | Line 797 | chm_op(struct Client *source_p, struct C
797    if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
798      return;
799  
800 <  /* no redundant mode changes */
801 <  if (dir == MODE_ADD &&  has_member_flags(member, CHFL_CHANOP))
802 <    return;
803 <  if (dir == MODE_DEL && !has_member_flags(member, CHFL_CHANOP))
804 <    return;
800 >  switch (dir)
801 >  {
802 >    case MODE_ADD:
803 >      if (has_member_flags(member, CHFL_CHANOP))
804 >        return;  /* No redundant mode changes */
805 >
806 >      AddMemberFlag(member, CHFL_CHANOP);
807 >      break;
808 >    case MODE_DEL:
809 >      if (!has_member_flags(member, CHFL_CHANOP))
810 >        return;  /* No redundant mode changes */
811 >
812 >      DelMemberFlag(member, CHFL_CHANOP);
813 >      break;
814 >  }
815  
816 <  mode_changes[mode_count].letter = c;
816 >  mode_changes[mode_count].letter = mode->letter;
817    mode_changes[mode_count].arg = target_p->name;
818    mode_changes[mode_count].id = target_p->id;
819 +  mode_changes[mode_count].flags = 0;
820    mode_changes[mode_count++].dir = dir;
905 –
906 –  if (dir == MODE_ADD)
907 –    AddMemberFlag(member, CHFL_CHANOP);
908 –  else
909 –    DelMemberFlag(member, CHFL_CHANOP);
821   }
822  
823   static void
824 < chm_limit(struct Client *source_p, struct Channel *chptr, int parc, int *parn,
825 <          char **parv, int *errors, int alev, int dir, char c, unsigned int d)
824 > chm_limit(struct Client *source_p, struct Channel *chptr, int parc, int *parn, char **parv,
825 >          int *errors, int alev, int dir, const struct chan_mode *mode)
826   {
916 –  int limit = 0;
917 –
827    if (alev < CHACCESS_HALFOP)
828    {
829      if (!(*errors & SM_ERR_NOOPS))
# Line 930 | Line 839 | chm_limit(struct Client *source_p, struc
839  
840    if (dir == MODE_ADD && parc > *parn)
841    {
842 <    char *lstr = parv[(*parn)++];
842 >    char *const lstr = parv[(*parn)++];
843 >    int limit = 0;
844  
845      if (EmptyString(lstr) || (limit = atoi(lstr)) <= 0)
846        return;
# Line 939 | Line 849 | chm_limit(struct Client *source_p, struc
849  
850      /* If somebody sets MODE #channel +ll 1 2, accept latter --fl */
851      for (unsigned int i = 0; i < mode_count; ++i)
852 <      if (mode_changes[i].letter == c && mode_changes[i].dir == MODE_ADD)
852 >      if (mode_changes[i].letter == mode->letter && mode_changes[i].dir == MODE_ADD)
853          mode_changes[i].letter = 0;
854  
855 <    mode_changes[mode_count].letter = c;
855 >    mode_changes[mode_count].letter = mode->letter;
856      mode_changes[mode_count].arg = lstr;
857      mode_changes[mode_count].id = NULL;
858 +    mode_changes[mode_count].flags = 0;
859      mode_changes[mode_count++].dir = dir;
860  
861      chptr->mode.limit = limit;
# Line 956 | Line 867 | chm_limit(struct Client *source_p, struc
867  
868      chptr->mode.limit = 0;
869  
870 <    mode_changes[mode_count].letter = c;
870 >    mode_changes[mode_count].letter = mode->letter;
871      mode_changes[mode_count].arg = NULL;
872      mode_changes[mode_count].id = NULL;
873 +    mode_changes[mode_count].flags = 0;
874      mode_changes[mode_count++].dir = dir;
875    }
876   }
877  
878   static void
879 < chm_key(struct Client *source_p, struct Channel *chptr, int parc, int *parn,
880 <        char **parv, int *errors, int alev, int dir, char c, unsigned int d)
879 > chm_key(struct Client *source_p, struct Channel *chptr, int parc, int *parn, char **parv,
880 >        int *errors, int alev, int dir, const struct chan_mode *mode)
881   {
882    if (alev < CHACCESS_HALFOP)
883    {
# Line 982 | Line 894 | chm_key(struct Client *source_p, struct
894  
895    if (dir == MODE_ADD && parc > *parn)
896    {
897 <    char *key = fix_key(parv[(*parn)++]);
897 >    char *const key = fix_key(parv[(*parn)++]);
898  
899      if (EmptyString(key))
900        return;
# Line 992 | Line 904 | chm_key(struct Client *source_p, struct
904  
905      /* If somebody does MODE #channel +kk a b, accept latter --fl */
906      for (unsigned int i = 0; i < mode_count; ++i)
907 <      if (mode_changes[i].letter == c && mode_changes[i].dir == MODE_ADD)
907 >      if (mode_changes[i].letter == mode->letter && mode_changes[i].dir == MODE_ADD)
908          mode_changes[i].letter = 0;
909  
910 <    mode_changes[mode_count].letter = c;
911 <    mode_changes[mode_count].arg = chptr->mode.key;
910 >    mode_changes[mode_count].letter = mode->letter;
911 >    mode_changes[mode_count].arg = key;
912      mode_changes[mode_count].id = NULL;
913 +    mode_changes[mode_count].flags = 0;
914      mode_changes[mode_count++].dir = dir;
915    }
916    else if (dir == MODE_DEL)
# Line 1010 | Line 923 | chm_key(struct Client *source_p, struct
923  
924      chptr->mode.key[0] = '\0';
925  
926 <    mode_changes[mode_count].letter = c;
926 >    mode_changes[mode_count].letter = mode->letter;
927      mode_changes[mode_count].arg = "*";
928      mode_changes[mode_count].id = NULL;
929 +    mode_changes[mode_count].flags = 0;
930      mode_changes[mode_count++].dir = dir;
931    }
932   }
933  
1020 – const struct ChannelMode ModeTable[256] =
1021 – {
1022 –  { chm_nosuch,  0 },                   /* 0x00 */
1023 –  { chm_nosuch,  0 },                   /* 0x01 */
1024 –  { chm_nosuch,  0 },                   /* 0x02 */
1025 –  { chm_nosuch,  0 },                   /* 0x03 */
1026 –  { chm_nosuch,  0 },                   /* 0x04 */
1027 –  { chm_nosuch,  0 },                   /* 0x05 */
1028 –  { chm_nosuch,  0 },                   /* 0x06 */
1029 –  { chm_nosuch,  0 },                   /* 0x07 */
1030 –  { chm_nosuch,  0 },                   /* 0x08 */
1031 –  { chm_nosuch,  0 },                   /* 0x09 */
1032 –  { chm_nosuch,  0 },                   /* 0x0a */
1033 –  { chm_nosuch,  0 },                   /* 0x0b */
1034 –  { chm_nosuch,  0 },                   /* 0x0c */
1035 –  { chm_nosuch,  0 },                   /* 0x0d */
1036 –  { chm_nosuch,  0 },                   /* 0x0e */
1037 –  { chm_nosuch,  0 },                   /* 0x0f */
1038 –  { chm_nosuch,  0 },                   /* 0x10 */
1039 –  { chm_nosuch,  0 },                   /* 0x11 */
1040 –  { chm_nosuch,  0 },                   /* 0x12 */
1041 –  { chm_nosuch,  0 },                   /* 0x13 */
1042 –  { chm_nosuch,  0 },                   /* 0x14 */
1043 –  { chm_nosuch,  0 },                   /* 0x15 */
1044 –  { chm_nosuch,  0 },                   /* 0x16 */
1045 –  { chm_nosuch,  0 },                   /* 0x17 */
1046 –  { chm_nosuch,  0 },                   /* 0x18 */
1047 –  { chm_nosuch,  0 },                   /* 0x19 */
1048 –  { chm_nosuch,  0 },                   /* 0x1a */
1049 –  { chm_nosuch,  0 },                   /* 0x1b */
1050 –  { chm_nosuch,  0 },                   /* 0x1c */
1051 –  { chm_nosuch,  0 },                   /* 0x1d */
1052 –  { chm_nosuch,  0 },                   /* 0x1e */
1053 –  { chm_nosuch,  0 },                   /* 0x1f */
1054 –  { chm_nosuch,  0 },                   /* 0x20 */
1055 –  { chm_nosuch,  0 },                   /* 0x21 */
1056 –  { chm_nosuch,  0 },                   /* 0x22 */
1057 –  { chm_nosuch,  0 },                   /* 0x23 */
1058 –  { chm_nosuch,  0 },                   /* 0x24 */
1059 –  { chm_nosuch,  0 },                   /* 0x25 */
1060 –  { chm_nosuch,  0 },                   /* 0x26 */
1061 –  { chm_nosuch,  0 },                   /* 0x27 */
1062 –  { chm_nosuch,  0 },                   /* 0x28 */
1063 –  { chm_nosuch,  0 },                   /* 0x29 */
1064 –  { chm_nosuch,  0 },                   /* 0x2a */
1065 –  { chm_nosuch,  0 },                   /* 0x2b */
1066 –  { chm_nosuch,  0 },                   /* 0x2c */
1067 –  { chm_nosuch,  0 },                   /* 0x2d */
1068 –  { chm_nosuch,  0 },                   /* 0x2e */
1069 –  { chm_nosuch,  0 },                   /* 0x2f */
1070 –  { chm_nosuch,  0 },                   /* 0x30 */
1071 –  { chm_nosuch,  0 },                   /* 0x31 */
1072 –  { chm_nosuch,  0 },                   /* 0x32 */
1073 –  { chm_nosuch,  0 },                   /* 0x33 */
1074 –  { chm_nosuch,  0 },                   /* 0x34 */
1075 –  { chm_nosuch,  0 },                   /* 0x35 */
1076 –  { chm_nosuch,  0 },                   /* 0x36 */
1077 –  { chm_nosuch,  0 },                   /* 0x37 */
1078 –  { chm_nosuch,  0 },                   /* 0x38 */
1079 –  { chm_nosuch,  0 },                   /* 0x39 */
1080 –  { chm_nosuch,  0 },                   /* 0x3a */
1081 –  { chm_nosuch,  0 },                   /* 0x3b */
1082 –  { chm_nosuch,  0 },                   /* 0x3c */
1083 –  { chm_nosuch,  0 },                   /* 0x3d */
1084 –  { chm_nosuch,  0 },                   /* 0x3e */
1085 –  { chm_nosuch,  0 },                   /* 0x3f */
1086 –  { chm_nosuch,  0 },                   /* @ */
1087 –  { chm_nosuch,  0 },                   /* A */
1088 –  { chm_nosuch,  0 },                   /* B */
1089 –  { chm_nosuch,  0 },                   /* C */
1090 –  { chm_nosuch,  0 },                   /* D */
1091 –  { chm_nosuch,  0 },                   /* E */
1092 –  { chm_nosuch,  0 },                   /* F */
1093 –  { chm_nosuch,  0 },                   /* G */
1094 –  { chm_nosuch,  0 },                   /* H */
1095 –  { chm_invex,   0 },                   /* I */
1096 –  { chm_nosuch,  0 },                   /* J */
1097 –  { chm_nosuch,  0 },                   /* K */
1098 –  { chm_nosuch,  0 },                   /* L */
1099 –  { chm_simple, MODE_MODREG},           /* M */
1100 –  { chm_nosuch,  0 },                   /* N */
1101 –  { chm_operonly, MODE_OPERONLY},       /* O */
1102 –  { chm_nosuch,  0 },                   /* P */
1103 –  { chm_nosuch,  0 },                   /* Q */
1104 –  { chm_simple, MODE_REGONLY},          /* R */
1105 –  { chm_simple, MODE_SSLONLY},          /* S */
1106 –  { chm_nosuch,  0 },                   /* T */
1107 –  { chm_nosuch,  0 },                   /* U */
1108 –  { chm_nosuch,  0 },                   /* V */
1109 –  { chm_nosuch,  0 },                   /* W */
1110 –  { chm_nosuch,  0 },                   /* X */
1111 –  { chm_nosuch,  0 },                   /* Y */
1112 –  { chm_nosuch,  0 },                   /* Z */
1113 –  { chm_nosuch,  0 },
1114 –  { chm_nosuch,  0 },
1115 –  { chm_nosuch,  0 },
1116 –  { chm_nosuch,  0 },
1117 –  { chm_nosuch,  0 },
1118 –  { chm_nosuch,  0 },
1119 –  { chm_nosuch,  0 },                   /* a */
1120 –  { chm_ban,     0 },                   /* b */
1121 –  { chm_simple, MODE_NOCTRL},           /* c */
1122 –  { chm_nosuch,  0 },                   /* d */
1123 –  { chm_except,  0 },                   /* e */
1124 –  { chm_nosuch,  0 },                   /* f */
1125 –  { chm_nosuch,  0 },                   /* g */
1126 –  { chm_hop,     0 },                   /* h */
1127 –  { chm_simple,     MODE_INVITEONLY },  /* i */
1128 –  { chm_nosuch,     0               },  /* j */
1129 –  { chm_key,        0               },  /* k */
1130 –  { chm_limit,      0               },  /* l */
1131 –  { chm_simple,     MODE_MODERATED  },  /* m */
1132 –  { chm_simple,     MODE_NOPRIVMSGS },  /* n */
1133 –  { chm_op,         0               },  /* o */
1134 –  { chm_simple,     MODE_PRIVATE    },  /* p */
1135 –  { chm_nosuch,     0               },  /* q */
1136 –  { chm_registered, MODE_REGISTERED },  /* r */
1137 –  { chm_simple,     MODE_SECRET     },  /* s */
1138 –  { chm_simple,     MODE_TOPICLIMIT },  /* t */
1139 –  { chm_nosuch,     0               },  /* u */
1140 –  { chm_voice,      0               },  /* v */
1141 –  { chm_nosuch,     0               },  /* w */
1142 –  { chm_nosuch,     0               },  /* x */
1143 –  { chm_nosuch,     0               },  /* y */
1144 –  { chm_nosuch,     0               },  /* z */
1145 –  { chm_nosuch,  0 },                   /* 0x7b */
1146 –  { chm_nosuch,  0 },                   /* 0x7c */
1147 –  { chm_nosuch,  0 },                   /* 0x7d */
1148 –  { chm_nosuch,  0 },                   /* 0x7e */
1149 –  { chm_nosuch,  0 },                   /* 0x7f */
1150 –  { chm_nosuch,  0 },                   /* 0x80 */
1151 –  { chm_nosuch,  0 },                   /* 0x81 */
1152 –  { chm_nosuch,  0 },                   /* 0x82 */
1153 –  { chm_nosuch,  0 },                   /* 0x83 */
1154 –  { chm_nosuch,  0 },                   /* 0x84 */
1155 –  { chm_nosuch,  0 },                   /* 0x85 */
1156 –  { chm_nosuch,  0 },                   /* 0x86 */
1157 –  { chm_nosuch,  0 },                   /* 0x87 */
1158 –  { chm_nosuch,  0 },                   /* 0x88 */
1159 –  { chm_nosuch,  0 },                   /* 0x89 */
1160 –  { chm_nosuch,  0 },                   /* 0x8a */
1161 –  { chm_nosuch,  0 },                   /* 0x8b */
1162 –  { chm_nosuch,  0 },                   /* 0x8c */
1163 –  { chm_nosuch,  0 },                   /* 0x8d */
1164 –  { chm_nosuch,  0 },                   /* 0x8e */
1165 –  { chm_nosuch,  0 },                   /* 0x8f */
1166 –  { chm_nosuch,  0 },                   /* 0x90 */
1167 –  { chm_nosuch,  0 },                   /* 0x91 */
1168 –  { chm_nosuch,  0 },                   /* 0x92 */
1169 –  { chm_nosuch,  0 },                   /* 0x93 */
1170 –  { chm_nosuch,  0 },                   /* 0x94 */
1171 –  { chm_nosuch,  0 },                   /* 0x95 */
1172 –  { chm_nosuch,  0 },                   /* 0x96 */
1173 –  { chm_nosuch,  0 },                   /* 0x97 */
1174 –  { chm_nosuch,  0 },                   /* 0x98 */
1175 –  { chm_nosuch,  0 },                   /* 0x99 */
1176 –  { chm_nosuch,  0 },                   /* 0x9a */
1177 –  { chm_nosuch,  0 },                   /* 0x9b */
1178 –  { chm_nosuch,  0 },                   /* 0x9c */
1179 –  { chm_nosuch,  0 },                   /* 0x9d */
1180 –  { chm_nosuch,  0 },                   /* 0x9e */
1181 –  { chm_nosuch,  0 },                   /* 0x9f */
1182 –  { chm_nosuch,  0 },                   /* 0xa0 */
1183 –  { chm_nosuch,  0 },                   /* 0xa1 */
1184 –  { chm_nosuch,  0 },                   /* 0xa2 */
1185 –  { chm_nosuch,  0 },                   /* 0xa3 */
1186 –  { chm_nosuch,  0 },                   /* 0xa4 */
1187 –  { chm_nosuch,  0 },                   /* 0xa5 */
1188 –  { chm_nosuch,  0 },                   /* 0xa6 */
1189 –  { chm_nosuch,  0 },                   /* 0xa7 */
1190 –  { chm_nosuch,  0 },                   /* 0xa8 */
1191 –  { chm_nosuch,  0 },                   /* 0xa9 */
1192 –  { chm_nosuch,  0 },                   /* 0xaa */
1193 –  { chm_nosuch,  0 },                   /* 0xab */
1194 –  { chm_nosuch,  0 },                   /* 0xac */
1195 –  { chm_nosuch,  0 },                   /* 0xad */
1196 –  { chm_nosuch,  0 },                   /* 0xae */
1197 –  { chm_nosuch,  0 },                   /* 0xaf */
1198 –  { chm_nosuch,  0 },                   /* 0xb0 */
1199 –  { chm_nosuch,  0 },                   /* 0xb1 */
1200 –  { chm_nosuch,  0 },                   /* 0xb2 */
1201 –  { chm_nosuch,  0 },                   /* 0xb3 */
1202 –  { chm_nosuch,  0 },                   /* 0xb4 */
1203 –  { chm_nosuch,  0 },                   /* 0xb5 */
1204 –  { chm_nosuch,  0 },                   /* 0xb6 */
1205 –  { chm_nosuch,  0 },                   /* 0xb7 */
1206 –  { chm_nosuch,  0 },                   /* 0xb8 */
1207 –  { chm_nosuch,  0 },                   /* 0xb9 */
1208 –  { chm_nosuch,  0 },                   /* 0xba */
1209 –  { chm_nosuch,  0 },                   /* 0xbb */
1210 –  { chm_nosuch,  0 },                   /* 0xbc */
1211 –  { chm_nosuch,  0 },                   /* 0xbd */
1212 –  { chm_nosuch,  0 },                   /* 0xbe */
1213 –  { chm_nosuch,  0 },                   /* 0xbf */
1214 –  { chm_nosuch,  0 },                   /* 0xc0 */
1215 –  { chm_nosuch,  0 },                   /* 0xc1 */
1216 –  { chm_nosuch,  0 },                   /* 0xc2 */
1217 –  { chm_nosuch,  0 },                   /* 0xc3 */
1218 –  { chm_nosuch,  0 },                   /* 0xc4 */
1219 –  { chm_nosuch,  0 },                   /* 0xc5 */
1220 –  { chm_nosuch,  0 },                   /* 0xc6 */
1221 –  { chm_nosuch,  0 },                   /* 0xc7 */
1222 –  { chm_nosuch,  0 },                   /* 0xc8 */
1223 –  { chm_nosuch,  0 },                   /* 0xc9 */
1224 –  { chm_nosuch,  0 },                   /* 0xca */
1225 –  { chm_nosuch,  0 },                   /* 0xcb */
1226 –  { chm_nosuch,  0 },                   /* 0xcc */
1227 –  { chm_nosuch,  0 },                   /* 0xcd */
1228 –  { chm_nosuch,  0 },                   /* 0xce */
1229 –  { chm_nosuch,  0 },                   /* 0xcf */
1230 –  { chm_nosuch,  0 },                   /* 0xd0 */
1231 –  { chm_nosuch,  0 },                   /* 0xd1 */
1232 –  { chm_nosuch,  0 },                   /* 0xd2 */
1233 –  { chm_nosuch,  0 },                   /* 0xd3 */
1234 –  { chm_nosuch,  0 },                   /* 0xd4 */
1235 –  { chm_nosuch,  0 },                   /* 0xd5 */
1236 –  { chm_nosuch,  0 },                   /* 0xd6 */
1237 –  { chm_nosuch,  0 },                   /* 0xd7 */
1238 –  { chm_nosuch,  0 },                   /* 0xd8 */
1239 –  { chm_nosuch,  0 },                   /* 0xd9 */
1240 –  { chm_nosuch,  0 },                   /* 0xda */
1241 –  { chm_nosuch,  0 },                   /* 0xdb */
1242 –  { chm_nosuch,  0 },                   /* 0xdc */
1243 –  { chm_nosuch,  0 },                   /* 0xdd */
1244 –  { chm_nosuch,  0 },                   /* 0xde */
1245 –  { chm_nosuch,  0 },                   /* 0xdf */
1246 –  { chm_nosuch,  0 },                   /* 0xe0 */
1247 –  { chm_nosuch,  0 },                   /* 0xe1 */
1248 –  { chm_nosuch,  0 },                   /* 0xe2 */
1249 –  { chm_nosuch,  0 },                   /* 0xe3 */
1250 –  { chm_nosuch,  0 },                   /* 0xe4 */
1251 –  { chm_nosuch,  0 },                   /* 0xe5 */
1252 –  { chm_nosuch,  0 },                   /* 0xe6 */
1253 –  { chm_nosuch,  0 },                   /* 0xe7 */
1254 –  { chm_nosuch,  0 },                   /* 0xe8 */
1255 –  { chm_nosuch,  0 },                   /* 0xe9 */
1256 –  { chm_nosuch,  0 },                   /* 0xea */
1257 –  { chm_nosuch,  0 },                   /* 0xeb */
1258 –  { chm_nosuch,  0 },                   /* 0xec */
1259 –  { chm_nosuch,  0 },                   /* 0xed */
1260 –  { chm_nosuch,  0 },                   /* 0xee */
1261 –  { chm_nosuch,  0 },                   /* 0xef */
1262 –  { chm_nosuch,  0 },                   /* 0xf0 */
1263 –  { chm_nosuch,  0 },                   /* 0xf1 */
1264 –  { chm_nosuch,  0 },                   /* 0xf2 */
1265 –  { chm_nosuch,  0 },                   /* 0xf3 */
1266 –  { chm_nosuch,  0 },                   /* 0xf4 */
1267 –  { chm_nosuch,  0 },                   /* 0xf5 */
1268 –  { chm_nosuch,  0 },                   /* 0xf6 */
1269 –  { chm_nosuch,  0 },                   /* 0xf7 */
1270 –  { chm_nosuch,  0 },                   /* 0xf8 */
1271 –  { chm_nosuch,  0 },                   /* 0xf9 */
1272 –  { chm_nosuch,  0 },                   /* 0xfa */
1273 –  { chm_nosuch,  0 },                   /* 0xfb */
1274 –  { chm_nosuch,  0 },                   /* 0xfc */
1275 –  { chm_nosuch,  0 },                   /* 0xfd */
1276 –  { chm_nosuch,  0 },                   /* 0xfe */
1277 –  { chm_nosuch,  0 },                   /* 0xff */
1278 – };
1279 –
934   /* get_channel_access()
935   *
936   * inputs       - pointer to Client struct
# Line 1318 | Line 972 | get_channel_access(const struct Client *
972   static void
973   send_mode_changes_server(struct Client *source_p, struct Channel *chptr)
974   {
975 <  int mbl = 0, pbl = 0, arglen = 0, nc = 0, mc = 0;
976 <  int len = 0;
977 <  int dir = MODE_QUERY;
978 <  const char *arg = NULL;
979 <  char *parptr = NULL;
975 >  char modebuf[IRCD_BUFSIZE] = "";
976 >  char parabuf[IRCD_BUFSIZE] = "";
977 >  char *parptr = parabuf;
978 >  unsigned int mbl = 0, pbl = 0, arglen = 0, modecount = 0, paracount = 0;
979 >  unsigned int dir = MODE_QUERY;
980  
981 <  parabuf[0] = '\0';
982 <  parptr = parabuf;
1329 <
1330 <  mbl = snprintf(modebuf, sizeof(modebuf), ":%s TMODE %lu %s ", source_p->id,
1331 <                 (unsigned long)chptr->channelts, chptr->name);
981 >  mbl = snprintf(modebuf, sizeof(modebuf), ":%s TMODE %ju %s ",
982 >                 source_p->id, chptr->creationtime, chptr->name);
983  
984    /* Loop the list of modes we have */
985 <  for (unsigned i = 0; i < mode_count; ++i)
985 >  for (unsigned int i = 0; i < mode_count; ++i)
986    {
987      if (mode_changes[i].letter == 0)
988        continue;
989  
990 +    const char *arg;
991      if (mode_changes[i].id)
992        arg = mode_changes[i].id;
993      else
# Line 1350 | Line 1002 | send_mode_changes_server(struct Client *
1002       * If we're creeping past the buf size, we need to send it and make
1003       * another line for the other modes
1004       */
1005 <    if ((mc == MAXMODEPARAMS) ||
1006 <        ((arglen + mbl + pbl + 2) > IRCD_BUFSIZE) ||
1355 <        (pbl + arglen + BAN_FUDGE) >= MODEBUFLEN)
1005 >    if ((paracount == MAXMODEPARAMS) ||
1006 >        ((arglen + mbl + pbl + 2 /* +2 for /r/n */ ) > IRCD_BUFSIZE))
1007      {
1008 <      if (nc)
1009 <        sendto_server(source_p, NOCAPS, NOCAPS, "%s %s", modebuf, parabuf);
1008 >      if (modecount)
1009 >        sendto_server(source_p, 0, 0, "%s %s", modebuf, parabuf);
1010  
1011 <      nc = 0;
1012 <      mc = 0;
1011 >      modecount = 0;
1012 >      paracount = 0;
1013  
1014 <      mbl = snprintf(modebuf, sizeof(modebuf), ":%s TMODE %lu %s ", source_p->id,
1015 <                     (unsigned long)chptr->channelts, chptr->name);
1014 >      mbl = snprintf(modebuf, sizeof(modebuf), ":%s TMODE %ju %s ",
1015 >                     source_p->id, chptr->creationtime, chptr->name);
1016  
1017        pbl = 0;
1018        parabuf[0] = '\0';
# Line 1377 | Line 1028 | send_mode_changes_server(struct Client *
1028  
1029      modebuf[mbl++] = mode_changes[i].letter;
1030      modebuf[mbl] = '\0';
1031 <    ++nc;
1031 >    ++modecount;
1032  
1033      if (arg)
1034      {
1035 <      len = sprintf(parptr, "%s ", arg);
1035 >      int len = sprintf(parptr, (pbl == 0) ? "%s" : " %s", arg);
1036        pbl += len;
1037        parptr += len;
1038 <      ++mc;
1038 >      ++paracount;
1039      }
1040    }
1041  
1042 <  if (pbl && parabuf[pbl - 1] == ' ')
1043 <    parabuf[pbl - 1] = '\0';
1393 <
1394 <  if (nc)
1395 <    sendto_server(source_p, NOCAPS, NOCAPS, "%s %s", modebuf, parabuf);
1042 >  if (modecount)
1043 >    sendto_server(source_p, 0, 0, "%s %s", modebuf, parabuf);
1044   }
1045  
1046   /* void send_mode_changes(struct Client *client_p,
# Line 1405 | Line 1053 | send_mode_changes_server(struct Client *
1053   * Side-effects: Sends the appropriate mode changes to other clients
1054   *               and propagates to servers.
1055   */
1408 – /* ensure parabuf < MODEBUFLEN -db */
1056   static void
1057 < send_mode_changes(struct Client *source_p, struct Channel *chptr)
1057 > send_mode_changes_client(struct Client *source_p, struct Channel *chptr)
1058   {
1059 <  int mbl = 0, pbl = 0, arglen = 0, nc = 0, mc = 0;
1413 <  int len = 0;
1414 <  int dir = MODE_QUERY;
1415 <  const char *arg = NULL;
1416 <  char *parptr = NULL;
1059 >  unsigned int flags = 0;
1060  
1061 <  /* Bail out if we have nothing to do... */
1419 <  if (!mode_count)
1420 <    return;
1421 <
1422 <  if (IsServer(source_p))
1423 <    mbl = snprintf(modebuf, sizeof(modebuf), ":%s MODE %s ", (IsHidden(source_p) ||
1424 <                   ConfigServerHide.hide_servers) ?
1425 <                   me.name : source_p->name, chptr->name);
1426 <  else
1427 <    mbl = snprintf(modebuf, sizeof(modebuf), ":%s!%s@%s MODE %s ", source_p->name,
1428 <                   source_p->username, source_p->host, chptr->name);
1429 <
1430 <  parabuf[0] = '\0';
1431 <  parptr = parabuf;
1432 <
1433 <  for (unsigned int i = 0; i < mode_count; ++i)
1061 >  for (unsigned int pass = 2; pass--; flags = CHFL_CHANOP | CHFL_HALFOP)
1062    {
1063 <    if (mode_changes[i].letter == 0)
1064 <      continue;
1065 <
1066 <    arg = mode_changes[i].arg;
1067 <    if (arg)
1068 <      arglen = strlen(arg);
1063 >    char modebuf[IRCD_BUFSIZE] = "";
1064 >    char parabuf[IRCD_BUFSIZE] = "";
1065 >    char *parptr = parabuf;
1066 >    unsigned int mbl = 0, pbl = 0, arglen = 0, modecount = 0, paracount = 0;
1067 >    unsigned int dir = MODE_QUERY;
1068 >
1069 >    if (IsServer(source_p))
1070 >      mbl = snprintf(modebuf, sizeof(modebuf), ":%s MODE %s ", (IsHidden(source_p) ||
1071 >                     ConfigServerHide.hide_servers) ?
1072 >                     me.name : source_p->name, chptr->name);
1073      else
1074 <      arglen = 0;
1074 >      mbl = snprintf(modebuf, sizeof(modebuf), ":%s!%s@%s MODE %s ", source_p->name,
1075 >                     source_p->username, source_p->host, chptr->name);
1076  
1077 <    if ((mc == MAXMODEPARAMS) ||
1445 <        ((arglen + mbl + pbl + 2) > IRCD_BUFSIZE) ||
1446 <        ((arglen + pbl + BAN_FUDGE) >= MODEBUFLEN))
1077 >    for (unsigned int i = 0; i < mode_count; ++i)
1078      {
1079 <      if (mbl && modebuf[mbl - 1] == '-')
1080 <        modebuf[mbl - 1] = '\0';
1079 >      if (mode_changes[i].letter == 0 || mode_changes[i].flags != flags)
1080 >        continue;
1081  
1082 <      if (nc)
1083 <        sendto_channel_local(0, chptr, "%s %s", modebuf, parabuf);
1082 >      const char *arg = mode_changes[i].arg;
1083 >      if (arg)
1084 >        arglen = strlen(arg);
1085 >      else
1086 >        arglen = 0;
1087  
1088 <      nc = 0;
1089 <      mc = 0;
1088 >      if ((paracount == MAXMODEPARAMS) ||
1089 >          ((arglen + mbl + pbl + 2 /* +2 for /r/n */ ) > IRCD_BUFSIZE))
1090 >      {
1091 >        if (modecount)
1092 >          sendto_channel_local(NULL, chptr, flags, 0, 0, "%s %s", modebuf, parabuf);
1093  
1094 <      if (IsServer(source_p))
1095 <        mbl = snprintf(modebuf, sizeof(modebuf), ":%s MODE %s ", (IsHidden(source_p) ||
1459 <                       ConfigServerHide.hide_servers) ?
1460 <                       me.name : source_p->name, chptr->name);
1461 <      else
1462 <        mbl = snprintf(modebuf, sizeof(modebuf), ":%s!%s@%s MODE %s ", source_p->name,
1463 <                       source_p->username, source_p->host, chptr->name);
1094 >        modecount = 0;
1095 >        paracount = 0;
1096  
1097 <      pbl = 0;
1098 <      parabuf[0] = '\0';
1099 <      parptr = parabuf;
1100 <      dir = MODE_QUERY;
1101 <    }
1097 >        if (IsServer(source_p))
1098 >          mbl = snprintf(modebuf, sizeof(modebuf), ":%s MODE %s ", (IsHidden(source_p) ||
1099 >                         ConfigServerHide.hide_servers) ?
1100 >                         me.name : source_p->name, chptr->name);
1101 >        else
1102 >          mbl = snprintf(modebuf, sizeof(modebuf), ":%s!%s@%s MODE %s ", source_p->name,
1103 >                         source_p->username, source_p->host, chptr->name);
1104 >
1105 >        pbl = 0;
1106 >        parabuf[0] = '\0';
1107 >        parptr = parabuf;
1108 >        dir = MODE_QUERY;
1109 >      }
1110  
1111 <    if (dir != mode_changes[i].dir)
1112 <    {
1113 <      modebuf[mbl++] = (mode_changes[i].dir == MODE_ADD) ? '+' : '-';
1114 <      dir = mode_changes[i].dir;
1115 <    }
1111 >      if (dir != mode_changes[i].dir)
1112 >      {
1113 >        modebuf[mbl++] = (mode_changes[i].dir == MODE_ADD) ? '+' : '-';
1114 >        dir = mode_changes[i].dir;
1115 >      }
1116  
1117 <    modebuf[mbl++] = mode_changes[i].letter;
1118 <    modebuf[mbl] = '\0';
1119 <    ++nc;
1117 >      modebuf[mbl++] = mode_changes[i].letter;
1118 >      modebuf[mbl] = '\0';
1119 >      ++modecount;
1120  
1121 <    if (arg)
1122 <    {
1123 <      len = sprintf(parptr, "%s ", arg);
1124 <      pbl += len;
1125 <      parptr += len;
1126 <      ++mc;
1121 >      if (arg)
1122 >      {
1123 >        int len = sprintf(parptr, (pbl == 0) ? "%s" : " %s", arg);
1124 >        pbl += len;
1125 >        parptr += len;
1126 >        ++paracount;
1127 >      }
1128      }
1488 –  }
1129  
1130 <  if (pbl && parabuf[pbl - 1] == ' ')
1131 <    parabuf[pbl - 1] = '\0';
1130 >    if (modecount)
1131 >      sendto_channel_local(NULL, chptr, flags, 0, 0, "%s %s", modebuf, parabuf);
1132 >  }
1133 > }
1134  
1135 <  if (nc)
1136 <    sendto_channel_local(0, chptr, "%s %s", modebuf, parabuf);
1135 > const struct chan_mode *cmode_map[256];
1136 > const struct chan_mode  cmode_tab[] =
1137 > {
1138 >  { 'b', 0, 0, 0, chm_ban },
1139 >  { 'c', MODE_NOCTRL, 0, 0, chm_simple },
1140 >  { 'e', 0, 0, 0, chm_except },
1141 >  { 'h', 0, 0, 0, chm_hop },
1142 >  { 'i', MODE_INVITEONLY, 0, 0, chm_simple },
1143 >  { 'k', 0, 0, 0, chm_key },
1144 >  { 'l', 0, 0, 0, chm_limit },
1145 >  { 'm', MODE_MODERATED, 0, 0, chm_simple },
1146 >  { 'n', MODE_NOPRIVMSGS, 0, 0, chm_simple },
1147 >  { 'o', 0, 0, 0, chm_op },
1148 >  { 'p', MODE_PRIVATE, 0, 0, chm_simple },
1149 >  { 'r', MODE_REGISTERED, 0, 1, chm_simple },
1150 >  { 's', MODE_SECRET, 0, 0, chm_simple },
1151 >  { 't', MODE_TOPICLIMIT, 0, 0, chm_simple },
1152 >  { 'u', MODE_HIDEBMASKS, 0, 0, chm_simple },
1153 >  { 'v', 0, 0, 0, chm_voice },
1154 >  { 'C', MODE_NOCTCP, 0, 0, chm_simple },
1155 >  { 'I', 0, 0, 0, chm_invex },
1156 >  { 'L', MODE_EXTLIMIT, 1, 0, chm_simple },
1157 >  { 'M', MODE_MODREG, 0, 0, chm_simple },
1158 >  { 'O', MODE_OPERONLY, 1, 0, chm_simple },
1159 >  { 'R', MODE_REGONLY, 0, 0, chm_simple },
1160 >  { 'S', MODE_SSLONLY, 0, 0, chm_simple },
1161 >  { 'T', MODE_NONOTICE, 0, 0, chm_simple },
1162 >  { '\0', 0, 0, 0, NULL }
1163 > };
1164  
1165 <  send_mode_changes_server(source_p, chptr);
1165 > void
1166 > channel_mode_init(void)
1167 > {
1168 >  for (const struct chan_mode *tab = cmode_tab; tab->letter; ++tab)
1169 >    cmode_map[tab->letter] = tab;
1170   }
1171  
1172   /*
# Line 1534 | Line 1207 | set_channel_mode(struct Client *source_p
1207          break;
1208        default:
1209        {
1210 <        const struct ChannelMode *tptr = &ModeTable[(unsigned char)*ml];
1210 >        const struct chan_mode *mode = cmode_map[(unsigned char)*ml];
1211  
1212 <        tptr->func(source_p, chptr, parc, &parn, parv,
1213 <                   &errors, alevel, dir, *ml, tptr->d);
1212 >        if (mode)
1213 >          mode->func(source_p, chptr, parc, &parn, parv, &errors, alevel, dir, mode);
1214 >        else
1215 >          chm_nosuch(source_p, chptr, parc, &parn, parv, &errors, alevel, dir, mode);
1216          break;
1217        }
1218      }
1219    }
1220  
1221 <  send_mode_changes(source_p, chptr);
1221 >  /* Bail out if we have nothing to do... */
1222 >  if (!mode_count)
1223 >    return;
1224 >
1225 >  send_mode_changes_client(source_p, chptr);
1226 >  send_mode_changes_server(source_p, chptr);
1227   }

Comparing ircd-hybrid/trunk/src/channel_mode.c (property svn:keywords):
Revision 4800 by michael, Tue Oct 28 13:59:43 2014 UTC vs.
Revision 8091 by michael, Wed Mar 29 12:50:17 2017 UTC

# Line 1 | Line 1
1 < Id Revision
1 > Id

Diff Legend

– Removed lines
+ Added lines
< Changed lines (old)
> Changed lines (new)