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 8160 by michael, Sun Apr 9 10:24:39 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 char c, const struct chan_mode *mode)
351   {
352    if (*errors & SM_ERR_UNKNOWN)
353      return;
# Line 399 | Line 357 | chm_nosuch(struct Client *source_p, stru
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 char c, 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)) */
363 >  if (mode->only_opers)
364    {
365 <    chptr->mode.mode |= d;
366 <
367 <    mode_changes[mode_count].letter = c;
368 <    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)) */
439 <  {
440 <    /* setting - */
441 <
442 <    chptr->mode.mode &= ~d;
443 <
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 <  if (dir == MODE_ADD) /* && !(chptr->mode.mode & d)) */
406 >  if (dir == MODE_ADD)  /* setting + */
407    {
408 <    chptr->mode.mode |= d;
408 >    if (MyClient(source_p) && HasCMode(chptr, mode->mode))
409 >      return;
410  
411 <    mode_changes[mode_count].letter = c;
536 <    mode_changes[mode_count].arg = NULL;
537 <    mode_changes[mode_count].id = NULL;
538 <    mode_changes[mode_count++].dir = dir;
411 >    AddCMode(chptr, mode->mode);
412    }
413 <  else if (dir == MODE_DEL) /* && (chptr->mode.mode & d)) */
413 >  else if (dir == MODE_DEL)  /* setting - */
414    {
415 <    /* setting - */
416 <
544 <    chptr->mode.mode &= ~d;
415 >    if (MyClient(source_p) && !HasCMode(chptr, mode->mode))
416 >      return;
417  
418 <    mode_changes[mode_count].letter = c;
547 <    mode_changes[mode_count].arg = NULL;
548 <    mode_changes[mode_count].id = NULL;
549 <    mode_changes[mode_count++].dir = dir;
418 >    DelCMode(chptr, mode->mode);
419    }
420 +
421 +  mode_changes[mode_count].letter = mode->letter;
422 +  mode_changes[mode_count].arg = NULL;
423 +  mode_changes[mode_count].id = NULL;
424 +  mode_changes[mode_count].flags = 0;
425 +  mode_changes[mode_count++].dir = dir;
426   }
427  
428   static void
429 < chm_ban(struct Client *source_p, struct Channel *chptr, int parc, int *parn,
430 <        char **parv, int *errors, int alev, int dir, char c, unsigned int d)
429 > chm_ban(struct Client *source_p, struct Channel *chptr, int parc, int *parn, char **parv,
430 >        int *errors, int alev, int dir, const char c, const struct chan_mode *mode)
431   {
557 –  char *mask = NULL;
558 –
432    if (dir == MODE_QUERY || parc <= *parn)
433    {
434 <    dlink_node *node = NULL;
434 >    dlink_node *node;
435  
436      if (*errors & SM_ERR_RPL_B)
437        return;
# Line 567 | Line 440 | chm_ban(struct Client *source_p, struct
440  
441      DLINK_FOREACH(node, chptr->banlist.head)
442      {
443 <      const struct Ban *banptr = node->data;
444 <      sendto_one_numeric(source_p, &me, RPL_BANLIST, chptr->name,
445 <                         banptr->name, banptr->user, banptr->host,
446 <                         banptr->who, banptr->when);
443 >      const struct Ban *ban = node->data;
444 >
445 >      if (!HasCMode(chptr, MODE_HIDEBMASKS) || alev >= CHACCESS_HALFOP)
446 >        sendto_one_numeric(source_p, &me, RPL_BANLIST, chptr->name,
447 >                           ban->name, ban->user, ban->host,
448 >                           ban->who, ban->when);
449      }
450  
451      sendto_one_numeric(source_p, &me, RPL_ENDOFBANLIST, chptr->name);
# Line 583 | Line 458 | chm_ban(struct Client *source_p, struct
458        sendto_one_numeric(source_p, &me,
459                           alev == CHACCESS_NOTONCHAN ? ERR_NOTONCHANNEL :
460                           ERR_CHANOPRIVSNEEDED, chptr->name);
461 +
462      *errors |= SM_ERR_NOOPS;
463      return;
464    }
# Line 590 | Line 466 | chm_ban(struct Client *source_p, struct
466    if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
467      return;
468  
469 <  mask = nuh_mask[*parn];
470 <  memcpy(mask, parv[*parn], sizeof(nuh_mask[*parn]));
469 >  char *const mask = nuh_mask[*parn];
470 >  strlcpy(mask, parv[*parn], sizeof(nuh_mask[*parn]));
471    ++(*parn);
472  
473 <  if (!MyConnect(source_p))
474 <    if (strchr(mask, ' '))
599 <      return;
473 >  if (*mask == ':' || (!MyConnect(source_p) && strchr(mask, ' ')))
474 >    return;
475  
476 <  switch (dir)
476 >  if (dir == MODE_ADD)  /* setting + */
477    {
478 <    case MODE_ADD:
479 <      if (!add_id(source_p, chptr, mask, CHFL_BAN))
480 <        return;
481 <      break;
482 <    case MODE_DEL:
483 <      if (!del_id(chptr, mask, CHFL_BAN))
484 <        return;
610 <      break;
611 <    default:
612 <      assert(0);
478 >    if (!add_id(source_p, chptr, mask, CHFL_BAN))
479 >      return;
480 >  }
481 >  else if (dir == MODE_DEL)  /* setting - */
482 >  {
483 >    if (!del_id(chptr, mask, CHFL_BAN))
484 >      return;
485    }
486  
487 <  mode_changes[mode_count].letter = c;
488 <  mode_changes[mode_count].arg = mask;
487 >  mode_changes[mode_count].letter = mode->letter;
488 >  mode_changes[mode_count].arg = mask;  /* At this point 'mask' is no longer than NICKLEN + USERLEN + HOSTLEN + 3 */
489    mode_changes[mode_count].id = NULL;
490 +  if (HasCMode(chptr, MODE_HIDEBMASKS))
491 +    mode_changes[mode_count].flags = CHFL_CHANOP | CHFL_HALFOP;
492 +  else
493 +    mode_changes[mode_count].flags = 0;
494    mode_changes[mode_count++].dir = dir;
495   }
496  
497   static void
498 < chm_except(struct Client *source_p, struct Channel *chptr, int parc, int *parn,
499 <           char **parv, int *errors, int alev, int dir, char c, unsigned int d)
498 > chm_except(struct Client *source_p, struct Channel *chptr, int parc, int *parn, char **parv,
499 >           int *errors, int alev, int dir, const char c, const struct chan_mode *mode)
500   {
625 –  char *mask = NULL;
626 –
501    if (dir == MODE_QUERY || parc <= *parn)
502    {
503 <    dlink_node *node = NULL;
503 >    dlink_node *node;
504  
505      if (*errors & SM_ERR_RPL_E)
506        return;
# Line 635 | Line 509 | chm_except(struct Client *source_p, stru
509  
510      DLINK_FOREACH(node, chptr->exceptlist.head)
511      {
512 <      const struct Ban *banptr = node->data;
512 >      const struct Ban *ban = node->data;
513  
514 <      sendto_one_numeric(source_p, &me, RPL_EXCEPTLIST, chptr->name,
515 <                         banptr->name, banptr->user, banptr->host,
516 <                         banptr->who, banptr->when);
514 >      if (!HasCMode(chptr, MODE_HIDEBMASKS) || alev >= CHACCESS_HALFOP)
515 >        sendto_one_numeric(source_p, &me, RPL_EXCEPTLIST, chptr->name,
516 >                           ban->name, ban->user, ban->host,
517 >                           ban->who, ban->when);
518      }
519  
520      sendto_one_numeric(source_p, &me, RPL_ENDOFEXCEPTLIST, chptr->name);
# Line 652 | Line 527 | chm_except(struct Client *source_p, stru
527        sendto_one_numeric(source_p, &me,
528                           alev == CHACCESS_NOTONCHAN ? ERR_NOTONCHANNEL :
529                           ERR_CHANOPRIVSNEEDED, chptr->name);
530 +
531      *errors |= SM_ERR_NOOPS;
532      return;
533    }
# Line 659 | Line 535 | chm_except(struct Client *source_p, stru
535    if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
536      return;
537  
538 <  mask = nuh_mask[*parn];
539 <  memcpy(mask, parv[*parn], sizeof(nuh_mask[*parn]));
538 >  char *const mask = nuh_mask[*parn];
539 >  strlcpy(mask, parv[*parn], sizeof(nuh_mask[*parn]));
540    ++(*parn);
541  
542 <  if (!MyConnect(source_p))
543 <    if (strchr(mask, ' '))
668 <      return;
542 >  if (*mask == ':' || (!MyConnect(source_p) && strchr(mask, ' ')))
543 >    return;
544  
545 <  switch (dir)
545 >  if (dir == MODE_ADD)  /* setting + */
546    {
547 <    case MODE_ADD:
548 <      if (!add_id(source_p, chptr, mask, CHFL_EXCEPTION))
549 <        return;
550 <      break;
551 <    case MODE_DEL:
552 <      if (!del_id(chptr, mask, CHFL_EXCEPTION))
553 <        return;
679 <      break;
680 <    default:
681 <      assert(0);
547 >    if (!add_id(source_p, chptr, mask, CHFL_EXCEPTION))
548 >      return;
549 >  }
550 >  else if (dir == MODE_DEL)  /* setting - */
551 >  {
552 >    if (!del_id(chptr, mask, CHFL_EXCEPTION))
553 >      return;
554    }
555  
556 <  mode_changes[mode_count].letter = c;
557 <  mode_changes[mode_count].arg = mask;
556 >  mode_changes[mode_count].letter = mode->letter;
557 >  mode_changes[mode_count].arg = mask;  /* At this point 'mask' is no longer than NICKLEN + USERLEN + HOSTLEN + 3 */
558    mode_changes[mode_count].id = NULL;
559 +  if (HasCMode(chptr, MODE_HIDEBMASKS))
560 +    mode_changes[mode_count].flags = CHFL_CHANOP | CHFL_HALFOP;
561 +  else
562 +    mode_changes[mode_count].flags = 0;
563    mode_changes[mode_count++].dir = dir;
564   }
565  
566   static void
567 < chm_invex(struct Client *source_p, struct Channel *chptr, int parc, int *parn,
568 <          char **parv, int *errors, int alev, int dir, char c, unsigned int d)
567 > chm_invex(struct Client *source_p, struct Channel *chptr, int parc, int *parn, char **parv,
568 >          int *errors, int alev, int dir, const char c, const struct chan_mode *mode)
569   {
694 –  char *mask = NULL;
695 –
570    if (dir == MODE_QUERY || parc <= *parn)
571    {
572 <    dlink_node *node = NULL;
572 >    dlink_node *node;
573  
574      if (*errors & SM_ERR_RPL_I)
575        return;
# Line 704 | Line 578 | chm_invex(struct Client *source_p, struc
578  
579      DLINK_FOREACH(node, chptr->invexlist.head)
580      {
581 <      const struct Ban *banptr = node->data;
581 >      const struct Ban *ban = node->data;
582  
583 <      sendto_one_numeric(source_p, &me, RPL_INVEXLIST, chptr->name,
584 <                         banptr->name, banptr->user, banptr->host,
585 <                         banptr->who, banptr->when);
583 >      if (!HasCMode(chptr, MODE_HIDEBMASKS) || alev >= CHACCESS_HALFOP)
584 >        sendto_one_numeric(source_p, &me, RPL_INVEXLIST, chptr->name,
585 >                           ban->name, ban->user, ban->host,
586 >                           ban->who, ban->when);
587      }
588  
589      sendto_one_numeric(source_p, &me, RPL_ENDOFINVEXLIST, chptr->name);
# Line 721 | Line 596 | chm_invex(struct Client *source_p, struc
596        sendto_one_numeric(source_p, &me,
597                           alev == CHACCESS_NOTONCHAN ? ERR_NOTONCHANNEL :
598                           ERR_CHANOPRIVSNEEDED, chptr->name);
599 +
600      *errors |= SM_ERR_NOOPS;
601      return;
602    }
# Line 728 | Line 604 | chm_invex(struct Client *source_p, struc
604    if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
605      return;
606  
607 <  mask = nuh_mask[*parn];
608 <  memcpy(mask, parv[*parn], sizeof(nuh_mask[*parn]));
607 >  char *const mask = nuh_mask[*parn];
608 >  strlcpy(mask, parv[*parn], sizeof(nuh_mask[*parn]));
609    ++(*parn);
610  
611 <  if (!MyConnect(source_p))
612 <    if (strchr(mask, ' '))
737 <      return;
611 >  if (*mask == ':' || (!MyConnect(source_p) && strchr(mask, ' ')))
612 >    return;
613  
614 <  switch (dir)
614 >  if (dir == MODE_ADD)  /* setting + */
615    {
616 <    case MODE_ADD:
617 <      if (!add_id(source_p, chptr, mask, CHFL_INVEX))
618 <        return;
619 <      break;
620 <    case MODE_DEL:
621 <      if (!del_id(chptr, mask, CHFL_INVEX))
622 <        return;
748 <      break;
749 <    default:
750 <      assert(0);
616 >    if (!add_id(source_p, chptr, mask, CHFL_INVEX))
617 >      return;
618 >  }
619 >  else if (dir == MODE_DEL)  /* setting - */
620 >  {
621 >    if (!del_id(chptr, mask, CHFL_INVEX))
622 >      return;
623    }
624  
625 <  mode_changes[mode_count].letter = c;
626 <  mode_changes[mode_count].arg = mask;
625 >  mode_changes[mode_count].letter = mode->letter;
626 >  mode_changes[mode_count].arg = mask;  /* At this point 'mask' is no longer than NICKLEN + USERLEN + HOSTLEN + 3 */
627    mode_changes[mode_count].id = NULL;
628 +  if (HasCMode(chptr, MODE_HIDEBMASKS))
629 +    mode_changes[mode_count].flags = CHFL_CHANOP | CHFL_HALFOP;
630 +  else
631 +    mode_changes[mode_count].flags = 0;
632    mode_changes[mode_count++].dir = dir;
633   }
634  
635   static void
636 < chm_voice(struct Client *source_p, struct Channel *chptr, int parc, int *parn,
637 <          char **parv, int *errors, int alev, int dir, char c, unsigned int d)
636 > chm_voice(struct Client *source_p, struct Channel *chptr, int parc, int *parn, char **parv,
637 >          int *errors, int alev, int dir, const char c, const struct chan_mode *mode)
638   {
639    struct Client *target_p;
640    struct Membership *member;
# Line 769 | Line 645 | chm_voice(struct Client *source_p, struc
645        sendto_one_numeric(source_p, &me,
646                           alev == CHACCESS_NOTONCHAN ? ERR_NOTONCHANNEL :
647                           ERR_CHANOPRIVSNEEDED, chptr->name);
648 +
649      *errors |= SM_ERR_NOOPS;
650      return;
651    }
# Line 783 | Line 660 | chm_voice(struct Client *source_p, struc
660    {
661      if (!(*errors & SM_ERR_NOTONCHANNEL))
662        sendto_one_numeric(source_p, &me, ERR_USERNOTINCHANNEL, target_p->name, chptr->name);
663 +
664      *errors |= SM_ERR_NOTONCHANNEL;
665      return;
666    }
# Line 790 | Line 668 | chm_voice(struct Client *source_p, struc
668    if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
669      return;
670  
671 <  /* no redundant mode changes */
672 <  if (dir == MODE_ADD &&  has_member_flags(member, CHFL_VOICE))
673 <    return;
674 <  if (dir == MODE_DEL && !has_member_flags(member, CHFL_VOICE))
797 <    return;
671 >  if (dir == MODE_ADD)  /* setting + */
672 >  {
673 >    if (has_member_flags(member, CHFL_VOICE))
674 >      return;  /* No redundant mode changes */
675  
676 <  mode_changes[mode_count].letter = c;
676 >    AddMemberFlag(member, CHFL_VOICE);
677 >  }
678 >  else if (dir == MODE_DEL)  /* setting - */
679 >  {
680 >    if (!has_member_flags(member, CHFL_VOICE))
681 >      return;  /* No redundant mode changes */
682 >
683 >    DelMemberFlag(member, CHFL_VOICE);
684 >  }
685 >
686 >  mode_changes[mode_count].letter = mode->letter;
687    mode_changes[mode_count].arg = target_p->name;
688    mode_changes[mode_count].id = target_p->id;
689 +  mode_changes[mode_count].flags = 0;
690    mode_changes[mode_count++].dir = dir;
803 –
804 –  if (dir == MODE_ADD)
805 –    AddMemberFlag(member, CHFL_VOICE);
806 –  else
807 –    DelMemberFlag(member, CHFL_VOICE);
691   }
692  
693   static void
694 < chm_hop(struct Client *source_p, struct Channel *chptr, int parc, int *parn,
695 <        char **parv, int *errors, int alev, int dir, char c, unsigned int d)
694 > chm_hop(struct Client *source_p, struct Channel *chptr, int parc, int *parn, char **parv,
695 >        int *errors, int alev, int dir, const char c, const struct chan_mode *mode)
696   {
697    struct Client *target_p;
698    struct Membership *member;
# Line 820 | Line 703 | chm_hop(struct Client *source_p, struct
703        sendto_one_numeric(source_p, &me,
704                           alev == CHACCESS_NOTONCHAN ? ERR_NOTONCHANNEL :
705                           ERR_CHANOPRIVSNEEDED, chptr->name);
706 +
707      *errors |= SM_ERR_NOOPS;
708      return;
709    }
# Line 834 | Line 718 | chm_hop(struct Client *source_p, struct
718    {
719      if (!(*errors & SM_ERR_NOTONCHANNEL))
720        sendto_one_numeric(source_p, &me, ERR_USERNOTINCHANNEL, target_p->name, chptr->name);
721 +
722      *errors |= SM_ERR_NOTONCHANNEL;
723      return;
724    }
# Line 841 | Line 726 | chm_hop(struct Client *source_p, struct
726    if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
727      return;
728  
729 <  /* no redundant mode changes */
730 <  if (dir == MODE_ADD &&  has_member_flags(member, CHFL_HALFOP))
731 <    return;
732 <  if (dir == MODE_DEL && !has_member_flags(member, CHFL_HALFOP))
733 <    return;
729 >  if (dir == MODE_ADD)  /* setting + */
730 >  {
731 >    if (has_member_flags(member, CHFL_HALFOP))
732 >      return;  /* No redundant mode changes */
733 >
734 >    AddMemberFlag(member, CHFL_HALFOP);
735 >  }
736 >  else if (dir == MODE_DEL)  /* setting - */
737 >  {
738 >    if (!has_member_flags(member, CHFL_HALFOP))
739 >      return;  /* No redundant mode changes */
740 >
741 >    DelMemberFlag(member, CHFL_HALFOP);
742 >  }
743  
744 <  mode_changes[mode_count].letter = c;
744 >  mode_changes[mode_count].letter = mode->letter;
745    mode_changes[mode_count].arg = target_p->name;
746    mode_changes[mode_count].id = target_p->id;
747 +  mode_changes[mode_count].flags = 0;
748    mode_changes[mode_count++].dir = dir;
854 –
855 –  if (dir == MODE_ADD)
856 –    AddMemberFlag(member, CHFL_HALFOP);
857 –  else
858 –    DelMemberFlag(member, CHFL_HALFOP);
749   }
750  
751   static void
752 < chm_op(struct Client *source_p, struct Channel *chptr, int parc, int *parn,
753 <       char **parv, int *errors, int alev, int dir, char c, unsigned int d)
752 > chm_op(struct Client *source_p, struct Channel *chptr, int parc, int *parn, char **parv,
753 >       int *errors, int alev, int dir, const char c, const struct chan_mode *mode)
754   {
755    struct Client *target_p;
756    struct Membership *member;
# Line 871 | Line 761 | chm_op(struct Client *source_p, struct C
761        sendto_one_numeric(source_p, &me,
762                           alev == CHACCESS_NOTONCHAN ? ERR_NOTONCHANNEL :
763                           ERR_CHANOPRIVSNEEDED, chptr->name);
764 +
765      *errors |= SM_ERR_NOOPS;
766      return;
767    }
# Line 885 | Line 776 | chm_op(struct Client *source_p, struct C
776    {
777      if (!(*errors & SM_ERR_NOTONCHANNEL))
778        sendto_one_numeric(source_p, &me, ERR_USERNOTINCHANNEL, target_p->name, chptr->name);
779 +
780      *errors |= SM_ERR_NOTONCHANNEL;
781      return;
782    }
# Line 892 | Line 784 | chm_op(struct Client *source_p, struct C
784    if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
785      return;
786  
787 <  /* no redundant mode changes */
788 <  if (dir == MODE_ADD &&  has_member_flags(member, CHFL_CHANOP))
789 <    return;
790 <  if (dir == MODE_DEL && !has_member_flags(member, CHFL_CHANOP))
791 <    return;
787 >  if (dir == MODE_ADD)  /* setting + */
788 >  {
789 >    if (has_member_flags(member, CHFL_CHANOP))
790 >      return;  /* No redundant mode changes */
791 >
792 >    AddMemberFlag(member, CHFL_CHANOP);
793 >  }
794 >  else if (dir == MODE_DEL)  /* setting - */
795 >  {
796 >    if (!has_member_flags(member, CHFL_CHANOP))
797 >      return;  /* No redundant mode changes */
798 >
799 >    DelMemberFlag(member, CHFL_CHANOP);
800 >  }
801  
802 <  mode_changes[mode_count].letter = c;
802 >  mode_changes[mode_count].letter = mode->letter;
803    mode_changes[mode_count].arg = target_p->name;
804    mode_changes[mode_count].id = target_p->id;
805 +  mode_changes[mode_count].flags = 0;
806    mode_changes[mode_count++].dir = dir;
905 –
906 –  if (dir == MODE_ADD)
907 –    AddMemberFlag(member, CHFL_CHANOP);
908 –  else
909 –    DelMemberFlag(member, CHFL_CHANOP);
807   }
808  
809   static void
810 < chm_limit(struct Client *source_p, struct Channel *chptr, int parc, int *parn,
811 <          char **parv, int *errors, int alev, int dir, char c, unsigned int d)
810 > chm_limit(struct Client *source_p, struct Channel *chptr, int parc, int *parn, char **parv,
811 >          int *errors, int alev, int dir, const char c, const struct chan_mode *mode)
812   {
916 –  int limit = 0;
917 –
813    if (alev < CHACCESS_HALFOP)
814    {
815      if (!(*errors & SM_ERR_NOOPS))
# Line 930 | Line 825 | chm_limit(struct Client *source_p, struc
825  
826    if (dir == MODE_ADD && parc > *parn)
827    {
828 <    char *lstr = parv[(*parn)++];
828 >    char *const lstr = parv[(*parn)++];
829 >    int limit = 0;
830  
831      if (EmptyString(lstr) || (limit = atoi(lstr)) <= 0)
832        return;
# Line 939 | Line 835 | chm_limit(struct Client *source_p, struc
835  
836      /* If somebody sets MODE #channel +ll 1 2, accept latter --fl */
837      for (unsigned int i = 0; i < mode_count; ++i)
838 <      if (mode_changes[i].letter == c && mode_changes[i].dir == MODE_ADD)
838 >      if (mode_changes[i].letter == mode->letter && mode_changes[i].dir == MODE_ADD)
839          mode_changes[i].letter = 0;
840  
841 <    mode_changes[mode_count].letter = c;
841 >    mode_changes[mode_count].letter = mode->letter;
842      mode_changes[mode_count].arg = lstr;
843      mode_changes[mode_count].id = NULL;
844 +    mode_changes[mode_count].flags = 0;
845      mode_changes[mode_count++].dir = dir;
846  
847      chptr->mode.limit = limit;
# Line 956 | Line 853 | chm_limit(struct Client *source_p, struc
853  
854      chptr->mode.limit = 0;
855  
856 <    mode_changes[mode_count].letter = c;
856 >    mode_changes[mode_count].letter = mode->letter;
857      mode_changes[mode_count].arg = NULL;
858      mode_changes[mode_count].id = NULL;
859 +    mode_changes[mode_count].flags = 0;
860      mode_changes[mode_count++].dir = dir;
861    }
862   }
863  
864   static void
865 < chm_key(struct Client *source_p, struct Channel *chptr, int parc, int *parn,
866 <        char **parv, int *errors, int alev, int dir, char c, unsigned int d)
865 > chm_key(struct Client *source_p, struct Channel *chptr, int parc, int *parn, char **parv,
866 >        int *errors, int alev, int dir, const char c, const struct chan_mode *mode)
867   {
868    if (alev < CHACCESS_HALFOP)
869    {
# Line 982 | Line 880 | chm_key(struct Client *source_p, struct
880  
881    if (dir == MODE_ADD && parc > *parn)
882    {
883 <    char *key = fix_key(parv[(*parn)++]);
883 >    char *const key = fix_key(parv[(*parn)++]);
884  
885      if (EmptyString(key))
886        return;
# Line 992 | Line 890 | chm_key(struct Client *source_p, struct
890  
891      /* If somebody does MODE #channel +kk a b, accept latter --fl */
892      for (unsigned int i = 0; i < mode_count; ++i)
893 <      if (mode_changes[i].letter == c && mode_changes[i].dir == MODE_ADD)
893 >      if (mode_changes[i].letter == mode->letter && mode_changes[i].dir == MODE_ADD)
894          mode_changes[i].letter = 0;
895  
896 <    mode_changes[mode_count].letter = c;
897 <    mode_changes[mode_count].arg = chptr->mode.key;
896 >    mode_changes[mode_count].letter = mode->letter;
897 >    mode_changes[mode_count].arg = key;
898      mode_changes[mode_count].id = NULL;
899 +    mode_changes[mode_count].flags = 0;
900      mode_changes[mode_count++].dir = dir;
901    }
902    else if (dir == MODE_DEL)
# Line 1010 | Line 909 | chm_key(struct Client *source_p, struct
909  
910      chptr->mode.key[0] = '\0';
911  
912 <    mode_changes[mode_count].letter = c;
912 >    mode_changes[mode_count].letter = mode->letter;
913      mode_changes[mode_count].arg = "*";
914      mode_changes[mode_count].id = NULL;
915 +    mode_changes[mode_count].flags = 0;
916      mode_changes[mode_count++].dir = dir;
917    }
918   }
919  
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 –
920   /* get_channel_access()
921   *
922   * inputs       - pointer to Client struct
# Line 1318 | Line 958 | get_channel_access(const struct Client *
958   static void
959   send_mode_changes_server(struct Client *source_p, struct Channel *chptr)
960   {
961 <  int mbl = 0, pbl = 0, arglen = 0, nc = 0, mc = 0;
962 <  int len = 0;
963 <  int dir = MODE_QUERY;
964 <  const char *arg = NULL;
965 <  char *parptr = NULL;
1326 <
1327 <  parabuf[0] = '\0';
1328 <  parptr = parabuf;
961 >  char modebuf[IRCD_BUFSIZE] = "";
962 >  char parabuf[IRCD_BUFSIZE] = "";
963 >  char *parptr = parabuf;
964 >  unsigned int mbl = 0, pbl = 0, arglen = 0, modecount = 0, paracount = 0;
965 >  unsigned int dir = MODE_QUERY;
966  
967 <  mbl = snprintf(modebuf, sizeof(modebuf), ":%s TMODE %lu %s ", source_p->id,
968 <                 (unsigned long)chptr->channelts, chptr->name);
967 >  mbl = snprintf(modebuf, sizeof(modebuf), ":%s TMODE %ju %s ",
968 >                 source_p->id, chptr->creationtime, chptr->name);
969  
970    /* Loop the list of modes we have */
971 <  for (unsigned i = 0; i < mode_count; ++i)
971 >  for (unsigned int i = 0; i < mode_count; ++i)
972    {
973      if (mode_changes[i].letter == 0)
974        continue;
975  
976 +    const char *arg;
977      if (mode_changes[i].id)
978        arg = mode_changes[i].id;
979      else
# Line 1350 | Line 988 | send_mode_changes_server(struct Client *
988       * If we're creeping past the buf size, we need to send it and make
989       * another line for the other modes
990       */
991 <    if ((mc == MAXMODEPARAMS) ||
992 <        ((arglen + mbl + pbl + 2) > IRCD_BUFSIZE) ||
1355 <        (pbl + arglen + BAN_FUDGE) >= MODEBUFLEN)
991 >    if ((paracount == MAXMODEPARAMS) ||
992 >        ((arglen + mbl + pbl + 2 /* +2 for /r/n */ ) > IRCD_BUFSIZE))
993      {
994 <      if (nc)
995 <        sendto_server(source_p, NOCAPS, NOCAPS, "%s %s", modebuf, parabuf);
994 >      if (modecount)
995 >        sendto_server(source_p, 0, 0, "%s %s", modebuf, parabuf);
996  
997 <      nc = 0;
998 <      mc = 0;
997 >      modecount = 0;
998 >      paracount = 0;
999  
1000 <      mbl = snprintf(modebuf, sizeof(modebuf), ":%s TMODE %lu %s ", source_p->id,
1001 <                     (unsigned long)chptr->channelts, chptr->name);
1000 >      mbl = snprintf(modebuf, sizeof(modebuf), ":%s TMODE %ju %s ",
1001 >                     source_p->id, chptr->creationtime, chptr->name);
1002  
1003        pbl = 0;
1004        parabuf[0] = '\0';
# Line 1377 | Line 1014 | send_mode_changes_server(struct Client *
1014  
1015      modebuf[mbl++] = mode_changes[i].letter;
1016      modebuf[mbl] = '\0';
1017 <    ++nc;
1017 >    ++modecount;
1018  
1019      if (arg)
1020      {
1021 <      len = sprintf(parptr, "%s ", arg);
1021 >      int len = sprintf(parptr, (pbl == 0) ? "%s" : " %s", arg);
1022        pbl += len;
1023        parptr += len;
1024 <      ++mc;
1024 >      ++paracount;
1025      }
1026    }
1027  
1028 <  if (pbl && parabuf[pbl - 1] == ' ')
1029 <    parabuf[pbl - 1] = '\0';
1393 <
1394 <  if (nc)
1395 <    sendto_server(source_p, NOCAPS, NOCAPS, "%s %s", modebuf, parabuf);
1028 >  if (modecount)
1029 >    sendto_server(source_p, 0, 0, "%s %s", modebuf, parabuf);
1030   }
1031  
1032   /* void send_mode_changes(struct Client *client_p,
# Line 1405 | Line 1039 | send_mode_changes_server(struct Client *
1039   * Side-effects: Sends the appropriate mode changes to other clients
1040   *               and propagates to servers.
1041   */
1408 – /* ensure parabuf < MODEBUFLEN -db */
1042   static void
1043 < send_mode_changes(struct Client *source_p, struct Channel *chptr)
1043 > send_mode_changes_client(struct Client *source_p, struct Channel *chptr)
1044   {
1045 <  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;
1045 >  unsigned int flags = 0;
1046  
1047 <  /* 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)
1047 >  for (unsigned int pass = 2; pass--; flags = CHFL_CHANOP | CHFL_HALFOP)
1048    {
1049 <    if (mode_changes[i].letter == 0)
1050 <      continue;
1051 <
1052 <    arg = mode_changes[i].arg;
1053 <    if (arg)
1054 <      arglen = strlen(arg);
1049 >    char modebuf[IRCD_BUFSIZE] = "";
1050 >    char parabuf[IRCD_BUFSIZE] = "";
1051 >    char *parptr = parabuf;
1052 >    unsigned int mbl = 0, pbl = 0, arglen = 0, modecount = 0, paracount = 0;
1053 >    unsigned int dir = MODE_QUERY;
1054 >
1055 >    if (IsServer(source_p))
1056 >      mbl = snprintf(modebuf, sizeof(modebuf), ":%s MODE %s ", (IsHidden(source_p) ||
1057 >                     ConfigServerHide.hide_servers) ?
1058 >                     me.name : source_p->name, chptr->name);
1059      else
1060 <      arglen = 0;
1060 >      mbl = snprintf(modebuf, sizeof(modebuf), ":%s!%s@%s MODE %s ", source_p->name,
1061 >                     source_p->username, source_p->host, chptr->name);
1062  
1063 <    if ((mc == MAXMODEPARAMS) ||
1445 <        ((arglen + mbl + pbl + 2) > IRCD_BUFSIZE) ||
1446 <        ((arglen + pbl + BAN_FUDGE) >= MODEBUFLEN))
1063 >    for (unsigned int i = 0; i < mode_count; ++i)
1064      {
1065 <      if (mbl && modebuf[mbl - 1] == '-')
1066 <        modebuf[mbl - 1] = '\0';
1065 >      if (mode_changes[i].letter == 0 || mode_changes[i].flags != flags)
1066 >        continue;
1067  
1068 <      if (nc)
1069 <        sendto_channel_local(0, chptr, "%s %s", modebuf, parabuf);
1068 >      const char *arg = mode_changes[i].arg;
1069 >      if (arg)
1070 >        arglen = strlen(arg);
1071 >      else
1072 >        arglen = 0;
1073  
1074 <      nc = 0;
1075 <      mc = 0;
1074 >      if ((paracount == MAXMODEPARAMS) ||
1075 >          ((arglen + mbl + pbl + 2 /* +2 for /r/n */ ) > IRCD_BUFSIZE))
1076 >      {
1077 >        if (modecount)
1078 >          sendto_channel_local(NULL, chptr, flags, 0, 0, "%s %s", modebuf, parabuf);
1079  
1080 <      if (IsServer(source_p))
1081 <        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);
1080 >        modecount = 0;
1081 >        paracount = 0;
1082  
1083 <      pbl = 0;
1084 <      parabuf[0] = '\0';
1085 <      parptr = parabuf;
1086 <      dir = MODE_QUERY;
1087 <    }
1083 >        if (IsServer(source_p))
1084 >          mbl = snprintf(modebuf, sizeof(modebuf), ":%s MODE %s ", (IsHidden(source_p) ||
1085 >                         ConfigServerHide.hide_servers) ?
1086 >                         me.name : source_p->name, chptr->name);
1087 >        else
1088 >          mbl = snprintf(modebuf, sizeof(modebuf), ":%s!%s@%s MODE %s ", source_p->name,
1089 >                         source_p->username, source_p->host, chptr->name);
1090 >
1091 >        pbl = 0;
1092 >        parabuf[0] = '\0';
1093 >        parptr = parabuf;
1094 >        dir = MODE_QUERY;
1095 >      }
1096  
1097 <    if (dir != mode_changes[i].dir)
1098 <    {
1099 <      modebuf[mbl++] = (mode_changes[i].dir == MODE_ADD) ? '+' : '-';
1100 <      dir = mode_changes[i].dir;
1101 <    }
1097 >      if (dir != mode_changes[i].dir)
1098 >      {
1099 >        modebuf[mbl++] = (mode_changes[i].dir == MODE_ADD) ? '+' : '-';
1100 >        dir = mode_changes[i].dir;
1101 >      }
1102  
1103 <    modebuf[mbl++] = mode_changes[i].letter;
1104 <    modebuf[mbl] = '\0';
1105 <    ++nc;
1103 >      modebuf[mbl++] = mode_changes[i].letter;
1104 >      modebuf[mbl] = '\0';
1105 >      ++modecount;
1106  
1107 <    if (arg)
1108 <    {
1109 <      len = sprintf(parptr, "%s ", arg);
1110 <      pbl += len;
1111 <      parptr += len;
1112 <      ++mc;
1107 >      if (arg)
1108 >      {
1109 >        int len = sprintf(parptr, (pbl == 0) ? "%s" : " %s", arg);
1110 >        pbl += len;
1111 >        parptr += len;
1112 >        ++paracount;
1113 >      }
1114      }
1488 –  }
1115  
1116 <  if (pbl && parabuf[pbl - 1] == ' ')
1117 <    parabuf[pbl - 1] = '\0';
1116 >    if (modecount)
1117 >      sendto_channel_local(NULL, chptr, flags, 0, 0, "%s %s", modebuf, parabuf);
1118 >  }
1119 > }
1120  
1121 <  if (nc)
1122 <    sendto_channel_local(0, chptr, "%s %s", modebuf, parabuf);
1121 > const struct chan_mode *cmode_map[256];
1122 > const struct chan_mode  cmode_tab[] =
1123 > {
1124 >  { .letter = 'b', .func = chm_ban },
1125 >  { .letter = 'c', .mode = MODE_NOCTRL, .func = chm_simple },
1126 >  { .letter = 'e', .func = chm_except },
1127 >  { .letter = 'h', .func = chm_hop },
1128 >  { .letter = 'i', .mode = MODE_INVITEONLY, .func = chm_simple },
1129 >  { .letter = 'k', .func = chm_key },
1130 >  { .letter = 'l', .func = chm_limit },
1131 >  { .letter = 'm', .mode = MODE_MODERATED, .func = chm_simple },
1132 >  { .letter = 'n', .mode = MODE_NOPRIVMSGS, .func = chm_simple },
1133 >  { .letter = 'o', .func = chm_op },
1134 >  { .letter = 'p', .mode = MODE_PRIVATE, .func = chm_simple },
1135 >  { .letter = 'r', .mode = MODE_REGISTERED, .only_servers = 1, .func = chm_simple },
1136 >  { .letter = 's', .mode = MODE_SECRET, .func = chm_simple },
1137 >  { .letter = 't', .mode = MODE_TOPICLIMIT, .func = chm_simple },
1138 >  { .letter = 'u', .mode = MODE_HIDEBMASKS, .func = chm_simple },
1139 >  { .letter = 'v', .func = chm_voice },
1140 >  { .letter = 'C', .mode = MODE_NOCTCP, .func = chm_simple },
1141 >  { .letter = 'I', .func = chm_invex },
1142 >  { .letter = 'L', .mode = MODE_EXTLIMIT, .only_opers = 1, .func = chm_simple },
1143 >  { .letter = 'M', .mode = MODE_MODREG, .func = chm_simple },
1144 >  { .letter = 'O', .mode = MODE_OPERONLY, .only_opers = 1, .func = chm_simple },
1145 >  { .letter = 'R', .mode = MODE_REGONLY, .func = chm_simple },
1146 >  { .letter = 'S', .mode = MODE_SSLONLY, .func = chm_simple },
1147 >  { .letter = 'T', .mode = MODE_NONOTICE, .func = chm_simple },
1148 >  { .letter = '\0', .mode = 0 }
1149 > };
1150  
1151 <  send_mode_changes_server(source_p, chptr);
1151 > void
1152 > channel_mode_init(void)
1153 > {
1154 >  for (const struct chan_mode *tab = cmode_tab; tab->letter; ++tab)
1155 >    cmode_map[tab->letter] = tab;
1156   }
1157  
1158   /*
# Line 1534 | Line 1193 | set_channel_mode(struct Client *source_p
1193          break;
1194        default:
1195        {
1196 <        const struct ChannelMode *tptr = &ModeTable[(unsigned char)*ml];
1196 >        const struct chan_mode *mode = cmode_map[(unsigned char)*ml];
1197  
1198 <        tptr->func(source_p, chptr, parc, &parn, parv,
1199 <                   &errors, alevel, dir, *ml, tptr->d);
1198 >        if (mode)
1199 >          mode->func(source_p, chptr, parc, &parn, parv, &errors, alevel, dir, *ml, mode);
1200 >        else
1201 >          chm_nosuch(source_p, chptr, parc, &parn, parv, &errors, alevel, dir, *ml, mode);
1202          break;
1203        }
1204      }
1205    }
1206  
1207 <  send_mode_changes(source_p, chptr);
1207 >  /* Bail out if we have nothing to do... */
1208 >  if (!mode_count)
1209 >    return;
1210 >
1211 >  send_mode_changes_client(source_p, chptr);
1212 >  send_mode_changes_server(source_p, chptr);
1213   }

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 8160 by michael, Sun Apr 9 10:24:39 2017 UTC

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

Diff Legend

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