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 5752 by michael, Thu Apr 2 17:27:33 2015 UTC vs.
Revision 8752 by michael, Tue Jan 1 11:07:01 2019 UTC

# Line 1 | Line 1
1   /*
2   *  ircd-hybrid: an advanced, lightweight Internet Relay Chat Daemon (ircd)
3   *
4 < *  Copyright (c) 1997-2015 ircd-hybrid development team
4 > *  Copyright (c) 1997-2019 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 37 | Line 37
37   #include "server.h"
38   #include "send.h"
39   #include "memory.h"
40 – #include "mempool.h"
40   #include "parse.h"
41  
43 – /* 10 is a magic number in hybrid 6 NFI where it comes from -db */
44 – #define BAN_FUDGE       10
42  
43   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];
44   static struct ChModeChange mode_changes[IRCD_BUFSIZE];
45   static unsigned int mode_count;
46   static unsigned int mode_limit;  /* number of modes set other than simple */
47   static unsigned int simple_modes_mask;  /* bit mask of simple modes already set */
54 – extern mp_pool_t *ban_pool;
55 –
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_NOCTCP,     'C' },
67 –  { MODE_MODREG,     'M' },
68 –  { MODE_OPERONLY,   'O' },
69 –  { MODE_REGONLY,    'R' },
70 –  { MODE_SSLONLY,    'S' },
71 –  { 0, '\0' }
72 – };
48  
49  
50   /* check_string()
# Line 109 | Line 84 | check_string(char *s)
84   *   -is 8/9/00
85   */
86  
87 < int
88 < add_id(struct Client *client_p, struct Channel *chptr, char *banid, unsigned int type)
87 > bool
88 > add_id(struct Client *client_p, struct Channel *chptr, char *banid, dlink_list *list)
89   {
90 <  dlink_list *list = NULL;
116 <  dlink_node *node = NULL;
117 <  struct Ban *ban = NULL;
118 <  size_t len = 0;
90 >  dlink_node *node;
91    char name[NICKLEN + 1] = "";
92    char user[USERLEN + 1] = "";
93    char host[HOSTLEN + 1] = "";
94    struct split_nuh_item nuh;
95  
124 –  /* Don't let local clients overflow the b/e/I lists */
96    if (MyClient(client_p))
97    {
98      unsigned int num_mask = dlink_list_length(&chptr->banlist) +
99                              dlink_list_length(&chptr->exceptlist) +
100                              dlink_list_length(&chptr->invexlist);
101  
102 <    if (num_mask >= ConfigChannel.max_bans)
102 >    /* Don't let local clients overflow the b/e/I lists */
103 >    if (num_mask >= ((HasCMode(chptr, MODE_EXTLIMIT)) ? ConfigChannel.max_bans_large :
104 >                                                        ConfigChannel.max_bans))
105      {
106        sendto_one_numeric(client_p, &me, ERR_BANLISTFULL, chptr->name, banid);
107 <      return 0;
107 >      return false;
108      }
109  
110      collapse(banid);
# Line 152 | Line 125 | add_id(struct Client *client_p, struct C
125     * Re-assemble a new n!u@h and print it back to banid for sending
126     * the mode to the channel.
127     */
128 <  len = snprintf(banid, IRCD_BUFSIZE, "%s!%s@%s", name, user, host);
156 <
157 <  switch (type)
158 <  {
159 <    case CHFL_BAN:
160 <      list = &chptr->banlist;
161 <      clear_ban_cache_channel(chptr);
162 <      break;
163 <    case CHFL_EXCEPTION:
164 <      list = &chptr->exceptlist;
165 <      clear_ban_cache_channel(chptr);
166 <      break;
167 <    case CHFL_INVEX:
168 <      list = &chptr->invexlist;
169 <      break;
170 <    default:
171 <      assert(0);
172 <      return 0;
173 <  }
128 >  size_t len = snprintf(banid, IRCD_BUFSIZE, "%s!%s@%s", name, user, host);
129  
130    DLINK_FOREACH(node, list->head)
131    {
132 <    ban = node->data;
132 >    const struct Ban *ban = node->data;
133  
134 <    if (!irccmp(ban->name, name) &&
135 <        !irccmp(ban->user, user) &&
136 <        !irccmp(ban->host, host))
137 <      return 0;
134 >    if (irccmp(ban->name, name) == 0 &&
135 >        irccmp(ban->user, user) == 0 &&
136 >        irccmp(ban->host, host) == 0)
137 >      return false;
138    }
139  
140 <  ban = mp_pool_get(ban_pool);
141 <  ban->name = xstrdup(name);
142 <  ban->user = xstrdup(user);
188 <  ban->host = xstrdup(host);
140 >  clear_ban_cache_list(&chptr->members_local);
141 >
142 >  struct Ban *ban = xcalloc(sizeof(*ban));
143    ban->when = CurrentTime;
144    ban->len = len - 2;  /* -2 for ! + @ */
145    ban->type = parse_netmask(host, &ban->addr, &ban->bits);
146 +  strlcpy(ban->name, name, sizeof(ban->name));
147 +  strlcpy(ban->user, user, sizeof(ban->user));
148 +  strlcpy(ban->host, host, sizeof(ban->host));
149  
150    if (IsClient(client_p))
151 <  {
152 <    ban->who = MyCalloc(strlen(client_p->name) +
153 <                        strlen(client_p->username) +
154 <                        strlen(client_p->host) + 3);
198 <    sprintf(ban->who, "%s!%s@%s", client_p->name,
199 <            client_p->username, client_p->host);
200 <  }
201 <  else if (IsHidden(client_p) || (IsServer(client_p) && ConfigServerHide.hide_servers))
202 <    ban->who = xstrdup(me.name);
151 >    snprintf(ban->who, sizeof(ban->who), "%s!%s@%s", client_p->name,
152 >             client_p->username, client_p->host);
153 >  else if (IsHidden(client_p) || ConfigServerHide.hide_servers)
154 >    strlcpy(ban->who, me.name, sizeof(ban->who));
155    else
156 <    ban->who = xstrdup(client_p->name);
156 >    strlcpy(ban->who, client_p->name, sizeof(ban->who));
157  
158    dlinkAdd(ban, &ban->node, list);
159  
160 <  return 1;
160 >  return true;
161   }
162  
163   /*
# Line 215 | Line 167 | add_id(struct Client *client_p, struct C
167   * output       - 0 for failure, 1 for success
168   * side effects -
169   */
170 < static int
171 < del_id(struct Channel *chptr, char *banid, unsigned int type)
170 > static bool
171 > del_id(struct Channel *chptr, char *banid, dlink_list *list)
172   {
173 <  dlink_list *list = NULL;
222 <  dlink_node *node = NULL;
173 >  dlink_node *node;
174    char name[NICKLEN + 1] = "";
175    char user[USERLEN + 1] = "";
176    char host[HOSTLEN + 1] = "";
# Line 244 | Line 195 | del_id(struct Channel *chptr, char *bani
195     */
196    snprintf(banid, IRCD_BUFSIZE, "%s!%s@%s", name, user, host);
197  
247 –  switch (type)
248 –  {
249 –    case CHFL_BAN:
250 –      list = &chptr->banlist;
251 –      clear_ban_cache_channel(chptr);
252 –      break;
253 –    case CHFL_EXCEPTION:
254 –      list = &chptr->exceptlist;
255 –      clear_ban_cache_channel(chptr);
256 –      break;
257 –    case CHFL_INVEX:
258 –      list = &chptr->invexlist;
259 –      break;
260 –    default:
261 –      assert(0);
262 –      return 0;
263 –  }
264 –
198    DLINK_FOREACH(node, list->head)
199    {
200      struct Ban *ban = node->data;
201  
202 <    if (!irccmp(name, ban->name) &&
203 <        !irccmp(user, ban->user) &&
204 <        !irccmp(host, ban->host))
202 >    if (irccmp(name, ban->name) == 0 &&
203 >        irccmp(user, ban->user) == 0 &&
204 >        irccmp(host, ban->host) == 0)
205      {
206 +      clear_ban_cache_list(&chptr->members_local);
207        remove_ban(ban, list);
208 <      return 1;
208 >      return true;
209      }
210    }
211  
212 <  return 0;
212 >  return false;
213   }
214  
215   /* channel_modes()
# Line 289 | Line 223 | del_id(struct Channel *chptr, char *bani
223   * chptr onto buffer mbuf with the parameters in pbuf.
224   */
225   void
226 < channel_modes(struct Channel *chptr, struct Client *client_p, char *mbuf, char *pbuf)
226 > channel_modes(const struct Channel *chptr, const struct Client *client_p, char *mbuf, char *pbuf)
227   {
228    *mbuf++ = '+';
229    *pbuf = '\0';
230  
231 <  for (const struct mode_letter *tab = chan_modes; tab->mode; ++tab)
232 <    if (chptr->mode.mode & tab->mode)
231 >  for (const struct chan_mode *tab = cmode_tab; tab->letter; ++tab)
232 >    if (tab->mode && HasCMode(chptr, tab->mode))
233        *mbuf++ = tab->letter;
234  
235    if (chptr->mode.limit)
236    {
237      *mbuf++ = 'l';
238  
239 <    if (IsServer(client_p) || HasFlag(client_p, FLAGS_SERVICE) || IsMember(client_p, chptr))
240 <      pbuf += sprintf(pbuf, "%d ", chptr->mode.limit);
239 >    if (IsServer(client_p) || IsMember(client_p, chptr))
240 >      pbuf += sprintf(pbuf, "%u ", chptr->mode.limit);
241    }
242  
243    if (chptr->mode.key[0])
244    {
245      *mbuf++ = 'k';
246  
247 <    if (IsServer(client_p) || HasFlag(client_p, FLAGS_SERVICE) || IsMember(client_p, chptr))
247 >    if (IsServer(client_p) || IsMember(client_p, chptr))
248        sprintf(pbuf, "%s ", chptr->mode.key);
249    }
250  
# Line 330 | Line 264 | fix_key(char *arg)
264   {
265    unsigned char *s, *t, c;
266  
267 <  for (s = t = (unsigned char *)arg; (c = *s); ++s)
267 >  for (s = t = (unsigned char *)arg; (c = *s) && s - (unsigned char *)arg < KEYLEN; ++s)
268    {
269      c &= 0x7f;
270  
# Line 348 | Line 282 | fix_key(char *arg)
282   * side effects - clear ban cache
283   */
284   void
285 < clear_ban_cache_channel(struct Channel *chptr)
285 > clear_ban_cache_list(dlink_list *list)
286   {
287 <  dlink_node *node = NULL;
287 >  dlink_node *node;
288  
289 <  DLINK_FOREACH(node, chptr->locmembers.head)
356 <  {
357 <    struct Membership *member = node->data;
358 <    member->flags &= ~(CHFL_BAN_SILENCED | CHFL_BAN_CHECKED);
359 <  }
360 < }
361 <
362 < void
363 < clear_ban_cache_client(struct Client *client_p)
364 < {
365 <  dlink_node *node = NULL;
366 <
367 <  DLINK_FOREACH(node, client_p->channel.head)
289 >  DLINK_FOREACH(node, list->head)
290    {
291      struct Membership *member = node->data;
292      member->flags &= ~(CHFL_BAN_SILENCED | CHFL_BAN_CHECKED);
# Line 372 | Line 294 | clear_ban_cache_client(struct Client *cl
294   }
295  
296   /*
297 < * Bitmasks for various error returns that set_channel_mode should only return
297 > * Bitmasks for various error returns that channel_mode_set should only return
298   * once per call  -orabidoo
299   */
300   enum
# Line 383 | Line 305 | enum
305    SM_ERR_RPL_E        = 1 << 3,
306    SM_ERR_RPL_I        = 1 << 4,
307    SM_ERR_NOTONCHANNEL = 1 << 5,  /* Client is not on channel */
308 <  SM_ERR_NOTOPER      = 1 << 6,
309 <  SM_ERR_ONLYSERVER   = 1 << 7
308 >  SM_ERR_NOTOPER      = 1 << 6,  /* Only irc-operators can change that mode */
309 >  SM_ERR_ONLYSERVER   = 1 << 7   /* Only servers or services can change that mode */
310   };
311  
312   /* Mode functions handle mode changes for a particular mode... */
313   static void
314 < chm_nosuch(struct Client *source_p, struct Channel *chptr, int parc, int *parn,
315 <           char **parv, int *errors, int alev, int dir, char c, unsigned int d)
314 > chm_nosuch(struct Client *source_p, struct Channel *chptr, int parc, int *parn, char **parv,
315 >           int *errors, int alev, int dir, const char c, const struct chan_mode *mode)
316   {
317    if (*errors & SM_ERR_UNKNOWN)
318      return;
# Line 400 | Line 322 | chm_nosuch(struct Client *source_p, stru
322   }
323  
324   static void
325 < chm_simple(struct Client *source_p, struct Channel *chptr, int parc, int *parn,
326 <           char **parv, int *errors, int alev, int dir, char c, unsigned int d)
325 > chm_simple(struct Client *source_p, struct Channel *chptr, int parc, int *parn, char **parv,
326 >           int *errors, int alev, int dir, const char c, const struct chan_mode *mode)
327   {
328 <  if (alev < CHACCESS_HALFOP)
328 >  if (mode->only_opers)
329    {
330 <    if (!(*errors & SM_ERR_NOOPS))
331 <      sendto_one_numeric(source_p, &me,
332 <                         alev == CHACCESS_NOTONCHAN ? ERR_NOTONCHANNEL :
333 <                         ERR_CHANOPRIVSNEEDED, chptr->name);
412 <
413 <    *errors |= SM_ERR_NOOPS;
414 <    return;
415 <  }
416 <
417 <  /* If have already dealt with this simple mode, ignore it */
418 <  if (simple_modes_mask & d)
419 <    return;
420 <
421 <  simple_modes_mask |= d;
422 <
423 <  /* setting + */
424 <  /* Apparently, (though no one has ever told the hybrid group directly)
425 <   * admins don't like redundant mode checking. ok. It would have been nice
426 <   * if you had have told us directly. I've left the original code snippets
427 <   * in place.
428 <   *
429 <   * -Dianora
430 <   */
431 <  if (dir == MODE_ADD) /* && !(chptr->mode.mode & d)) */
432 <  {
433 <    chptr->mode.mode |= d;
434 <
435 <    mode_changes[mode_count].letter = c;
436 <    mode_changes[mode_count].arg = NULL;
437 <    mode_changes[mode_count].id = NULL;
438 <    mode_changes[mode_count++].dir = dir;
439 <  }
440 <  else if (dir == MODE_DEL) /* && (chptr->mode.mode & d)) */
441 <  {
442 <    /* setting - */
443 <
444 <    chptr->mode.mode &= ~d;
445 <
446 <    mode_changes[mode_count].letter = c;
447 <    mode_changes[mode_count].arg = NULL;
448 <    mode_changes[mode_count].id = NULL;
449 <    mode_changes[mode_count++].dir = dir;
450 <  }
451 < }
452 <
453 < static void
454 < chm_registered(struct Client *source_p, struct Channel *chptr, int parc, int *parn,
455 <               char **parv, int *errors, int alev, int dir, char c, unsigned int d)
456 < {
457 <  if (!IsServer(source_p) && !HasFlag(source_p, FLAGS_SERVICE))
458 <  {
459 <    if (!(*errors & SM_ERR_ONLYSERVER))
460 <      sendto_one_numeric(source_p, &me,
461 <                         alev == CHACCESS_NOTONCHAN ? ERR_NOTONCHANNEL :
462 <                         ERR_ONLYSERVERSCANCHANGE, chptr->name);
330 >    if (MyClient(source_p) && !HasUMode(source_p, UMODE_OPER))
331 >    {
332 >      if (!(*errors & SM_ERR_NOTOPER))
333 >        sendto_one_numeric(source_p, &me, ERR_NOPRIVILEGES);
334  
335 <    *errors |= SM_ERR_ONLYSERVER;
336 <    return;
335 >      *errors |= SM_ERR_NOTOPER;
336 >      return;
337 >    }
338    }
339  
340 <  /* If have already dealt with this simple mode, ignore it */
469 <  if (simple_modes_mask & d)
470 <    return;
471 <
472 <  simple_modes_mask |= d;
473 <
474 <  /* setting + */
475 <  /* Apparently, (though no one has ever told the hybrid group directly)
476 <   * admins don't like redundant mode checking. ok. It would have been nice
477 <   * if you had have told us directly. I've left the original code snippets
478 <   * in place.
479 <   *
480 <   * -Dianora
481 <   */
482 <  if (dir == MODE_ADD) /* && !(chptr->mode.mode & d)) */
483 <  {
484 <    chptr->mode.mode |= d;
485 <
486 <    mode_changes[mode_count].letter = c;
487 <    mode_changes[mode_count].arg = NULL;
488 <    mode_changes[mode_count].id = NULL;
489 <    mode_changes[mode_count++].dir = dir;
490 <  }
491 <  else if (dir == MODE_DEL) /* && (chptr->mode.mode & d)) */
340 >  if (mode->only_servers)
341    {
342 <    /* setting - */
343 <
344 <    chptr->mode.mode &= ~d;
342 >    if (!IsServer(source_p) && !HasFlag(source_p, FLAGS_SERVICE))
343 >    {
344 >      if (!(*errors & SM_ERR_ONLYSERVER))
345 >        sendto_one_numeric(source_p, &me,
346 >                           alev == CHACCESS_NOTONCHAN ? ERR_NOTONCHANNEL :
347 >                           ERR_ONLYSERVERSCANCHANGE, chptr->name);
348  
349 <    mode_changes[mode_count].letter = c;
350 <    mode_changes[mode_count].arg = NULL;
351 <    mode_changes[mode_count].id = NULL;
500 <    mode_changes[mode_count++].dir = dir;
349 >      *errors |= SM_ERR_ONLYSERVER;
350 >      return;
351 >    }
352    }
502 – }
353  
354 < static void
505 < chm_operonly(struct Client *source_p, struct Channel *chptr, int parc, int *parn,
506 <             char **parv, int *errors, int alev, int dir, char c, unsigned int d)
507 < {
508 <  if (alev < CHACCESS_HALFOP)
354 >  if (alev < mode->required_oplevel)
355    {
356      if (!(*errors & SM_ERR_NOOPS))
357        sendto_one_numeric(source_p, &me,
# Line 516 | Line 362 | chm_operonly(struct Client *source_p, st
362      return;
363    }
364  
519 –  if (MyClient(source_p) && !HasUMode(source_p, UMODE_OPER))
520 –  {
521 –    if (!(*errors & SM_ERR_NOTOPER))
522 –      sendto_one_numeric(source_p, &me, ERR_NOPRIVILEGES);
523 –
524 –    *errors |= SM_ERR_NOTOPER;
525 –    return;
526 –  }
527 –
365    /* If have already dealt with this simple mode, ignore it */
366 <  if (simple_modes_mask & d)
366 >  if (simple_modes_mask & mode->mode)
367      return;
368  
369 <  simple_modes_mask |= d;
369 >  simple_modes_mask |= mode->mode;
370  
371 <  if (dir == MODE_ADD) /* && !(chptr->mode.mode & d)) */
371 >  if (dir == MODE_ADD)  /* setting + */
372    {
373 <    chptr->mode.mode |= d;
537 <
538 <    mode_changes[mode_count].letter = c;
539 <    mode_changes[mode_count].arg = NULL;
540 <    mode_changes[mode_count].id = NULL;
541 <    mode_changes[mode_count++].dir = dir;
542 <  }
543 <  else if (dir == MODE_DEL) /* && (chptr->mode.mode & d)) */
544 <  {
545 <    /* setting - */
546 <
547 <    chptr->mode.mode &= ~d;
548 <
549 <    mode_changes[mode_count].letter = c;
550 <    mode_changes[mode_count].arg = NULL;
551 <    mode_changes[mode_count].id = NULL;
552 <    mode_changes[mode_count++].dir = dir;
553 <  }
554 < }
555 <
556 < static void
557 < chm_ban(struct Client *source_p, struct Channel *chptr, int parc, int *parn,
558 <        char **parv, int *errors, int alev, int dir, char c, unsigned int d)
559 < {
560 <  char *mask = NULL;
561 <
562 <  if (dir == MODE_QUERY || parc <= *parn)
563 <  {
564 <    dlink_node *node = NULL;
565 <
566 <    if (*errors & SM_ERR_RPL_B)
373 >    if (MyClient(source_p) && HasCMode(chptr, mode->mode))
374        return;
375  
376 <    *errors |= SM_ERR_RPL_B;
570 <
571 <    DLINK_FOREACH(node, chptr->banlist.head)
572 <    {
573 <      const struct Ban *ban = node->data;
574 <      sendto_one_numeric(source_p, &me, RPL_BANLIST, chptr->name,
575 <                         ban->name, ban->user, ban->host,
576 <                         ban->who, ban->when);
577 <    }
578 <
579 <    sendto_one_numeric(source_p, &me, RPL_ENDOFBANLIST, chptr->name);
580 <    return;
376 >    AddCMode(chptr, mode->mode);
377    }
378 <
583 <  if (alev < CHACCESS_HALFOP)
378 >  else if (dir == MODE_DEL)  /* setting - */
379    {
380 <    if (!(*errors & SM_ERR_NOOPS))
381 <      sendto_one_numeric(source_p, &me,
587 <                         alev == CHACCESS_NOTONCHAN ? ERR_NOTONCHANNEL :
588 <                         ERR_CHANOPRIVSNEEDED, chptr->name);
589 <
590 <    *errors |= SM_ERR_NOOPS;
591 <    return;
592 <  }
593 <
594 <  if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
595 <    return;
596 <
597 <  mask = nuh_mask[*parn];
598 <  strlcpy(mask, parv[*parn], sizeof(nuh_mask[*parn]));
599 <  ++(*parn);
600 <
601 <  if (*mask == ':' || (!MyConnect(source_p) && strchr(mask, ' ')))
602 <    return;
380 >    if (MyClient(source_p) && !HasCMode(chptr, mode->mode))
381 >      return;
382  
383 <  switch (dir)
605 <  {
606 <    case MODE_ADD:
607 <      if (!add_id(source_p, chptr, mask, CHFL_BAN))
608 <        return;
609 <      break;
610 <    case MODE_DEL:
611 <      if (!del_id(chptr, mask, CHFL_BAN))
612 <        return;
613 <      break;
614 <    default:
615 <      assert(0);
383 >    DelCMode(chptr, mode->mode);
384    }
385  
386 <  mode_changes[mode_count].letter = c;
387 <  mode_changes[mode_count].arg = mask;
386 >  mode_changes[mode_count].letter = mode->letter;
387 >  mode_changes[mode_count].arg = NULL;
388    mode_changes[mode_count].id = NULL;
389 +  mode_changes[mode_count].flags = 0;
390    mode_changes[mode_count++].dir = dir;
391   }
392  
393   static void
394 < chm_except(struct Client *source_p, struct Channel *chptr, int parc, int *parn,
395 <           char **parv, int *errors, int alev, int dir, char c, unsigned int d)
394 > chm_mask(struct Client *source_p, struct Channel *chptr, int parc, int *parn, char **parv,
395 >         int *errors, int alev, int dir, const char c, const struct chan_mode *mode)
396   {
397 <  char *mask = NULL;
397 >  dlink_list *list;
398 >  enum irc_numerics rpl_list = 0, rpl_endlist = 0;
399 >  int errtype = 0;
400  
401 <  if (dir == MODE_QUERY || parc <= *parn)
401 >  switch (mode->flag)
402    {
403 <    dlink_node *node = NULL;
404 <
405 <    if (*errors & SM_ERR_RPL_E)
406 <      return;
407 <
637 <    *errors |= SM_ERR_RPL_E;
638 <
639 <    DLINK_FOREACH(node, chptr->exceptlist.head)
640 <    {
641 <      const struct Ban *ban = node->data;
642 <
643 <      sendto_one_numeric(source_p, &me, RPL_EXCEPTLIST, chptr->name,
644 <                         ban->name, ban->user, ban->host,
645 <                         ban->who, ban->when);
646 <    }
647 <
648 <    sendto_one_numeric(source_p, &me, RPL_ENDOFEXCEPTLIST, chptr->name);
649 <    return;
650 <  }
651 <
652 <  if (alev < CHACCESS_HALFOP)
653 <  {
654 <    if (!(*errors & SM_ERR_NOOPS))
655 <      sendto_one_numeric(source_p, &me,
656 <                         alev == CHACCESS_NOTONCHAN ? ERR_NOTONCHANNEL :
657 <                         ERR_CHANOPRIVSNEEDED, chptr->name);
658 <
659 <    *errors |= SM_ERR_NOOPS;
660 <    return;
661 <  }
662 <
663 <  if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
664 <    return;
665 <
666 <  mask = nuh_mask[*parn];
667 <  strlcpy(mask, parv[*parn], sizeof(nuh_mask[*parn]));
668 <  ++(*parn);
669 <
670 <  if (*mask == ':' || (!MyConnect(source_p) && strchr(mask, ' ')))
671 <    return;
672 <
673 <  switch (dir)
674 <  {
675 <    case MODE_ADD:
676 <      if (!add_id(source_p, chptr, mask, CHFL_EXCEPTION))
677 <        return;
403 >    case CHFL_BAN:
404 >      errtype = SM_ERR_RPL_B;
405 >      list = &chptr->banlist;
406 >      rpl_list = RPL_BANLIST;
407 >      rpl_endlist = RPL_ENDOFBANLIST;
408        break;
409 <    case MODE_DEL:
410 <      if (!del_id(chptr, mask, CHFL_EXCEPTION))
411 <        return;
409 >    case CHFL_EXCEPTION:
410 >      errtype = SM_ERR_RPL_E;
411 >      list = &chptr->exceptlist;
412 >      rpl_list = RPL_EXCEPTLIST;
413 >      rpl_endlist = RPL_ENDOFEXCEPTLIST;
414 >      break;
415 >    case CHFL_INVEX:
416 >      errtype = SM_ERR_RPL_I;
417 >      list = &chptr->invexlist;
418 >      rpl_list = RPL_INVEXLIST;
419 >      rpl_endlist = RPL_ENDOFINVEXLIST;
420        break;
421      default:
422 <      assert(0);
422 >      list = NULL;  /* Let it crash */
423    }
424  
687 –  mode_changes[mode_count].letter = c;
688 –  mode_changes[mode_count].arg = mask;
689 –  mode_changes[mode_count].id = NULL;
690 –  mode_changes[mode_count++].dir = dir;
691 – }
692 –
693 – static void
694 – chm_invex(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)
696 – {
697 –  char *mask = NULL;
698 –
425    if (dir == MODE_QUERY || parc <= *parn)
426    {
427 <    dlink_node *node = NULL;
427 >    dlink_node *node;
428  
429 <    if (*errors & SM_ERR_RPL_I)
429 >    if (*errors & errtype)
430        return;
431  
432 <    *errors |= SM_ERR_RPL_I;
432 >    *errors |= errtype;
433  
434 <    DLINK_FOREACH(node, chptr->invexlist.head)
434 >    DLINK_FOREACH(node, list->head)
435      {
436        const struct Ban *ban = node->data;
437  
438 <      sendto_one_numeric(source_p, &me, RPL_INVEXLIST, chptr->name,
439 <                         ban->name, ban->user, ban->host,
440 <                         ban->who, ban->when);
438 >      if (!HasCMode(chptr, MODE_HIDEBMASKS) || alev >= mode->required_oplevel)
439 >        sendto_one_numeric(source_p, &me, rpl_list, chptr->name,
440 >                           ban->name, ban->user, ban->host,
441 >                           ban->who, ban->when);
442      }
443  
444 <    sendto_one_numeric(source_p, &me, RPL_ENDOFINVEXLIST, chptr->name);
444 >    sendto_one_numeric(source_p, &me, rpl_endlist, chptr->name);
445      return;
446    }
447  
448 <  if (alev < CHACCESS_HALFOP)
448 >  if (alev < mode->required_oplevel)
449    {
450      if (!(*errors & SM_ERR_NOOPS))
451        sendto_one_numeric(source_p, &me,
# Line 732 | Line 459 | chm_invex(struct Client *source_p, struc
459    if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
460      return;
461  
462 <  mask = nuh_mask[*parn];
462 >  char *const mask = nuh_mask[*parn];
463    strlcpy(mask, parv[*parn], sizeof(nuh_mask[*parn]));
464    ++(*parn);
465  
466    if (*mask == ':' || (!MyConnect(source_p) && strchr(mask, ' ')))
467      return;
468  
469 <  switch (dir)
743 <  {
744 <    case MODE_ADD:
745 <      if (!add_id(source_p, chptr, mask, CHFL_INVEX))
746 <        return;
747 <      break;
748 <    case MODE_DEL:
749 <      if (!del_id(chptr, mask, CHFL_INVEX))
750 <        return;
751 <      break;
752 <    default:
753 <      assert(0);
754 <  }
755 <
756 <  mode_changes[mode_count].letter = c;
757 <  mode_changes[mode_count].arg = mask;
758 <  mode_changes[mode_count].id = NULL;
759 <  mode_changes[mode_count++].dir = dir;
760 < }
761 <
762 < static void
763 < chm_voice(struct Client *source_p, struct Channel *chptr, int parc, int *parn,
764 <          char **parv, int *errors, int alev, int dir, char c, unsigned int d)
765 < {
766 <  struct Client *target_p;
767 <  struct Membership *member;
768 <
769 <  if (alev < CHACCESS_HALFOP)
469 >  if (dir == MODE_ADD)  /* setting + */
470    {
471 <    if (!(*errors & SM_ERR_NOOPS))
472 <      sendto_one_numeric(source_p, &me,
773 <                         alev == CHACCESS_NOTONCHAN ? ERR_NOTONCHANNEL :
774 <                         ERR_CHANOPRIVSNEEDED, chptr->name);
775 <
776 <    *errors |= SM_ERR_NOOPS;
777 <    return;
471 >    if (add_id(source_p, chptr, mask, list) == false)
472 >      return;
473    }
474 <
780 <  if (dir == MODE_QUERY || parc <= *parn)
781 <    return;
782 <
783 <  if ((target_p = find_chasing(source_p, parv[(*parn)++])) == NULL)
784 <    return;  /* find_chasing sends ERR_NOSUCHNICK */
785 <
786 <  if ((member = find_channel_link(target_p, chptr)) == NULL)
474 >  else if (dir == MODE_DEL)  /* setting - */
475    {
476 <    if (!(*errors & SM_ERR_NOTONCHANNEL))
477 <      sendto_one_numeric(source_p, &me, ERR_USERNOTINCHANNEL, target_p->name, chptr->name);
790 <
791 <    *errors |= SM_ERR_NOTONCHANNEL;
792 <    return;
476 >    if (del_id(chptr, mask, list) == false)
477 >      return;
478    }
479  
480 <  if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
481 <    return;
482 <
483 <  /* no redundant mode changes */
484 <  if (dir == MODE_ADD &&  has_member_flags(member, CHFL_VOICE))
800 <    return;
801 <
802 <  if (dir == MODE_DEL && !has_member_flags(member, CHFL_VOICE))
803 <    return;
804 <
805 <  mode_changes[mode_count].letter = c;
806 <  mode_changes[mode_count].arg = target_p->name;
807 <  mode_changes[mode_count].id = target_p->id;
808 <  mode_changes[mode_count++].dir = dir;
809 <
810 <  if (dir == MODE_ADD)
811 <    AddMemberFlag(member, CHFL_VOICE);
480 >  mode_changes[mode_count].letter = mode->letter;
481 >  mode_changes[mode_count].arg = mask;  /* At this point 'mask' is no longer than NICKLEN + USERLEN + HOSTLEN + 3 */
482 >  mode_changes[mode_count].id = NULL;
483 >  if (HasCMode(chptr, MODE_HIDEBMASKS))
484 >    mode_changes[mode_count].flags = CHFL_CHANOP | CHFL_HALFOP;
485    else
486 <    DelMemberFlag(member, CHFL_VOICE);
486 >    mode_changes[mode_count].flags = 0;
487 >  mode_changes[mode_count++].dir = dir;
488   }
489  
490   static void
491 < chm_hop(struct Client *source_p, struct Channel *chptr, int parc, int *parn,
492 <        char **parv, int *errors, int alev, int dir, char c, unsigned int d)
491 > chm_flag(struct Client *source_p, struct Channel *chptr, int parc, int *parn, char **parv,
492 >         int *errors, int alev, int dir, const char c, const struct chan_mode *mode)
493   {
494    struct Client *target_p;
495    struct Membership *member;
496  
497 <  if (alev < CHACCESS_CHANOP)
497 >  if (alev < mode->required_oplevel)
498    {
499      if (!(*errors & SM_ERR_NOOPS))
500        sendto_one_numeric(source_p, &me,
# Line 849 | Line 523 | chm_hop(struct Client *source_p, struct
523    if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
524      return;
525  
526 <  /* no redundant mode changes */
853 <  if (dir == MODE_ADD &&  has_member_flags(member, CHFL_HALFOP))
854 <    return;
855 <
856 <  if (dir == MODE_DEL && !has_member_flags(member, CHFL_HALFOP))
857 <    return;
858 <
859 <  mode_changes[mode_count].letter = c;
860 <  mode_changes[mode_count].arg = target_p->name;
861 <  mode_changes[mode_count].id = target_p->id;
862 <  mode_changes[mode_count++].dir = dir;
863 <
864 <  if (dir == MODE_ADD)
865 <    AddMemberFlag(member, CHFL_HALFOP);
866 <  else
867 <    DelMemberFlag(member, CHFL_HALFOP);
868 < }
869 <
870 < static void
871 < chm_op(struct Client *source_p, struct Channel *chptr, int parc, int *parn,
872 <       char **parv, int *errors, int alev, int dir, char c, unsigned int d)
873 < {
874 <  struct Client *target_p;
875 <  struct Membership *member;
876 <
877 <  if (alev < CHACCESS_CHANOP)
526 >  if (dir == MODE_ADD)  /* setting + */
527    {
528 <    if (!(*errors & SM_ERR_NOOPS))
529 <      sendto_one_numeric(source_p, &me,
881 <                         alev == CHACCESS_NOTONCHAN ? ERR_NOTONCHANNEL :
882 <                         ERR_CHANOPRIVSNEEDED, chptr->name);
528 >    if (has_member_flags(member, mode->flag))
529 >      return;  /* No redundant mode changes */
530  
531 <    *errors |= SM_ERR_NOOPS;
885 <    return;
531 >    AddMemberFlag(member, mode->flag);
532    }
533 <
888 <  if (dir == MODE_QUERY || parc <= *parn)
889 <    return;
890 <
891 <  if ((target_p = find_chasing(source_p, parv[(*parn)++])) == NULL)
892 <    return;  /* find_chasing sends ERR_NOSUCHNICK */
893 <
894 <  if ((member = find_channel_link(target_p, chptr)) == NULL)
533 >  else if (dir == MODE_DEL)  /* setting - */
534    {
535 <    if (!(*errors & SM_ERR_NOTONCHANNEL))
536 <      sendto_one_numeric(source_p, &me, ERR_USERNOTINCHANNEL, target_p->name, chptr->name);
535 >    if (has_member_flags(member, mode->flag) == 0)
536 >      return;  /* No redundant mode changes */
537  
538 <    *errors |= SM_ERR_NOTONCHANNEL;
900 <    return;
538 >    DelMemberFlag(member, mode->flag);
539    }
540  
541 <  if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
904 <    return;
905 <
906 <  /* no redundant mode changes */
907 <  if (dir == MODE_ADD &&  has_member_flags(member, CHFL_CHANOP))
908 <    return;
909 <
910 <  if (dir == MODE_DEL && !has_member_flags(member, CHFL_CHANOP))
911 <    return;
912 <
913 <  mode_changes[mode_count].letter = c;
541 >  mode_changes[mode_count].letter = mode->letter;
542    mode_changes[mode_count].arg = target_p->name;
543    mode_changes[mode_count].id = target_p->id;
544 +  mode_changes[mode_count].flags = 0;
545    mode_changes[mode_count++].dir = dir;
917 –
918 –  if (dir == MODE_ADD)
919 –    AddMemberFlag(member, CHFL_CHANOP);
920 –  else
921 –    DelMemberFlag(member, CHFL_CHANOP);
546   }
547  
548   static void
549 < chm_limit(struct Client *source_p, struct Channel *chptr, int parc, int *parn,
550 <          char **parv, int *errors, int alev, int dir, char c, unsigned int d)
549 > chm_limit(struct Client *source_p, struct Channel *chptr, int parc, int *parn, char **parv,
550 >          int *errors, int alev, int dir, const char c, const struct chan_mode *mode)
551   {
552 <  int limit = 0;
929 <
930 <  if (alev < CHACCESS_HALFOP)
552 >  if (alev < mode->required_oplevel)
553    {
554      if (!(*errors & SM_ERR_NOOPS))
555        sendto_one_numeric(source_p, &me,
# Line 943 | Line 565 | chm_limit(struct Client *source_p, struc
565    if (dir == MODE_ADD && parc > *parn)
566    {
567      char *const lstr = parv[(*parn)++];
568 +    int limit = 0;
569  
570      if (EmptyString(lstr) || (limit = atoi(lstr)) <= 0)
571        return;
# Line 951 | Line 574 | chm_limit(struct Client *source_p, struc
574  
575      /* If somebody sets MODE #channel +ll 1 2, accept latter --fl */
576      for (unsigned int i = 0; i < mode_count; ++i)
577 <      if (mode_changes[i].letter == c && mode_changes[i].dir == MODE_ADD)
577 >      if (mode_changes[i].letter == mode->letter && mode_changes[i].dir == MODE_ADD)
578          mode_changes[i].letter = 0;
579  
580 <    mode_changes[mode_count].letter = c;
580 >    mode_changes[mode_count].letter = mode->letter;
581      mode_changes[mode_count].arg = lstr;
582      mode_changes[mode_count].id = NULL;
583 +    mode_changes[mode_count].flags = 0;
584      mode_changes[mode_count++].dir = dir;
585  
586      chptr->mode.limit = limit;
587    }
588    else if (dir == MODE_DEL)
589    {
590 <    if (!chptr->mode.limit)
590 >    if (chptr->mode.limit == 0)
591        return;
592  
593      chptr->mode.limit = 0;
594  
595 <    mode_changes[mode_count].letter = c;
595 >    mode_changes[mode_count].letter = mode->letter;
596      mode_changes[mode_count].arg = NULL;
597      mode_changes[mode_count].id = NULL;
598 +    mode_changes[mode_count].flags = 0;
599      mode_changes[mode_count++].dir = dir;
600    }
601   }
602  
603   static void
604 < chm_key(struct Client *source_p, struct Channel *chptr, int parc, int *parn,
605 <        char **parv, int *errors, int alev, int dir, char c, unsigned int d)
604 > chm_key(struct Client *source_p, struct Channel *chptr, int parc, int *parn, char **parv,
605 >        int *errors, int alev, int dir, const char c, const struct chan_mode *mode)
606   {
607 <  if (alev < CHACCESS_HALFOP)
607 >  if (alev < mode->required_oplevel)
608    {
609      if (!(*errors & SM_ERR_NOOPS))
610        sendto_one_numeric(source_p, &me,
# Line 1004 | Line 629 | chm_key(struct Client *source_p, struct
629  
630      /* If somebody does MODE #channel +kk a b, accept latter --fl */
631      for (unsigned int i = 0; i < mode_count; ++i)
632 <      if (mode_changes[i].letter == c && mode_changes[i].dir == MODE_ADD)
632 >      if (mode_changes[i].letter == mode->letter && mode_changes[i].dir == MODE_ADD)
633          mode_changes[i].letter = 0;
634  
635 <    mode_changes[mode_count].letter = c;
636 <    mode_changes[mode_count].arg = chptr->mode.key;
635 >    mode_changes[mode_count].letter = mode->letter;
636 >    mode_changes[mode_count].arg = key;
637      mode_changes[mode_count].id = NULL;
638 +    mode_changes[mode_count].flags = 0;
639      mode_changes[mode_count++].dir = dir;
640    }
641    else if (dir == MODE_DEL)
# Line 1022 | Line 648 | chm_key(struct Client *source_p, struct
648  
649      chptr->mode.key[0] = '\0';
650  
651 <    mode_changes[mode_count].letter = c;
651 >    mode_changes[mode_count].letter = mode->letter;
652      mode_changes[mode_count].arg = "*";
653      mode_changes[mode_count].id = NULL;
654 +    mode_changes[mode_count].flags = 0;
655      mode_changes[mode_count++].dir = dir;
656    }
657   }
658  
1032 – const struct ChannelMode ModeTable[256] =
1033 – {
1034 –  { chm_nosuch,  0 },                   /* 0x00 */
1035 –  { chm_nosuch,  0 },                   /* 0x01 */
1036 –  { chm_nosuch,  0 },                   /* 0x02 */
1037 –  { chm_nosuch,  0 },                   /* 0x03 */
1038 –  { chm_nosuch,  0 },                   /* 0x04 */
1039 –  { chm_nosuch,  0 },                   /* 0x05 */
1040 –  { chm_nosuch,  0 },                   /* 0x06 */
1041 –  { chm_nosuch,  0 },                   /* 0x07 */
1042 –  { chm_nosuch,  0 },                   /* 0x08 */
1043 –  { chm_nosuch,  0 },                   /* 0x09 */
1044 –  { chm_nosuch,  0 },                   /* 0x0a */
1045 –  { chm_nosuch,  0 },                   /* 0x0b */
1046 –  { chm_nosuch,  0 },                   /* 0x0c */
1047 –  { chm_nosuch,  0 },                   /* 0x0d */
1048 –  { chm_nosuch,  0 },                   /* 0x0e */
1049 –  { chm_nosuch,  0 },                   /* 0x0f */
1050 –  { chm_nosuch,  0 },                   /* 0x10 */
1051 –  { chm_nosuch,  0 },                   /* 0x11 */
1052 –  { chm_nosuch,  0 },                   /* 0x12 */
1053 –  { chm_nosuch,  0 },                   /* 0x13 */
1054 –  { chm_nosuch,  0 },                   /* 0x14 */
1055 –  { chm_nosuch,  0 },                   /* 0x15 */
1056 –  { chm_nosuch,  0 },                   /* 0x16 */
1057 –  { chm_nosuch,  0 },                   /* 0x17 */
1058 –  { chm_nosuch,  0 },                   /* 0x18 */
1059 –  { chm_nosuch,  0 },                   /* 0x19 */
1060 –  { chm_nosuch,  0 },                   /* 0x1a */
1061 –  { chm_nosuch,  0 },                   /* 0x1b */
1062 –  { chm_nosuch,  0 },                   /* 0x1c */
1063 –  { chm_nosuch,  0 },                   /* 0x1d */
1064 –  { chm_nosuch,  0 },                   /* 0x1e */
1065 –  { chm_nosuch,  0 },                   /* 0x1f */
1066 –  { chm_nosuch,  0 },                   /* 0x20 */
1067 –  { chm_nosuch,  0 },                   /* 0x21 */
1068 –  { chm_nosuch,  0 },                   /* 0x22 */
1069 –  { chm_nosuch,  0 },                   /* 0x23 */
1070 –  { chm_nosuch,  0 },                   /* 0x24 */
1071 –  { chm_nosuch,  0 },                   /* 0x25 */
1072 –  { chm_nosuch,  0 },                   /* 0x26 */
1073 –  { chm_nosuch,  0 },                   /* 0x27 */
1074 –  { chm_nosuch,  0 },                   /* 0x28 */
1075 –  { chm_nosuch,  0 },                   /* 0x29 */
1076 –  { chm_nosuch,  0 },                   /* 0x2a */
1077 –  { chm_nosuch,  0 },                   /* 0x2b */
1078 –  { chm_nosuch,  0 },                   /* 0x2c */
1079 –  { chm_nosuch,  0 },                   /* 0x2d */
1080 –  { chm_nosuch,  0 },                   /* 0x2e */
1081 –  { chm_nosuch,  0 },                   /* 0x2f */
1082 –  { chm_nosuch,  0 },                   /* 0x30 */
1083 –  { chm_nosuch,  0 },                   /* 0x31 */
1084 –  { chm_nosuch,  0 },                   /* 0x32 */
1085 –  { chm_nosuch,  0 },                   /* 0x33 */
1086 –  { chm_nosuch,  0 },                   /* 0x34 */
1087 –  { chm_nosuch,  0 },                   /* 0x35 */
1088 –  { chm_nosuch,  0 },                   /* 0x36 */
1089 –  { chm_nosuch,  0 },                   /* 0x37 */
1090 –  { chm_nosuch,  0 },                   /* 0x38 */
1091 –  { chm_nosuch,  0 },                   /* 0x39 */
1092 –  { chm_nosuch,  0 },                   /* 0x3a */
1093 –  { chm_nosuch,  0 },                   /* 0x3b */
1094 –  { chm_nosuch,  0 },                   /* 0x3c */
1095 –  { chm_nosuch,  0 },                   /* 0x3d */
1096 –  { chm_nosuch,  0 },                   /* 0x3e */
1097 –  { chm_nosuch,  0 },                   /* 0x3f */
1098 –  { chm_nosuch,  0 },                   /* @ */
1099 –  { chm_nosuch,  0 },                   /* A */
1100 –  { chm_nosuch,  0 },                   /* B */
1101 –  { chm_simple,  MODE_NOCTCP },         /* C */
1102 –  { chm_nosuch,  0 },                   /* D */
1103 –  { chm_nosuch,  0 },                   /* E */
1104 –  { chm_nosuch,  0 },                   /* F */
1105 –  { chm_nosuch,  0 },                   /* G */
1106 –  { chm_nosuch,  0 },                   /* H */
1107 –  { chm_invex,   0 },                   /* I */
1108 –  { chm_nosuch,  0 },                   /* J */
1109 –  { chm_nosuch,  0 },                   /* K */
1110 –  { chm_nosuch,  0 },                   /* L */
1111 –  { chm_simple, MODE_MODREG},           /* M */
1112 –  { chm_nosuch,  0 },                   /* N */
1113 –  { chm_operonly, MODE_OPERONLY},       /* O */
1114 –  { chm_nosuch,  0 },                   /* P */
1115 –  { chm_nosuch,  0 },                   /* Q */
1116 –  { chm_simple, MODE_REGONLY},          /* R */
1117 –  { chm_simple, MODE_SSLONLY},          /* S */
1118 –  { chm_nosuch,  0 },                   /* T */
1119 –  { chm_nosuch,  0 },                   /* U */
1120 –  { chm_nosuch,  0 },                   /* V */
1121 –  { chm_nosuch,  0 },                   /* W */
1122 –  { chm_nosuch,  0 },                   /* X */
1123 –  { chm_nosuch,  0 },                   /* Y */
1124 –  { chm_nosuch,  0 },                   /* Z */
1125 –  { chm_nosuch,  0 },
1126 –  { chm_nosuch,  0 },
1127 –  { chm_nosuch,  0 },
1128 –  { chm_nosuch,  0 },
1129 –  { chm_nosuch,  0 },
1130 –  { chm_nosuch,  0 },
1131 –  { chm_nosuch,  0 },                   /* a */
1132 –  { chm_ban,     0 },                   /* b */
1133 –  { chm_simple, MODE_NOCTRL},           /* c */
1134 –  { chm_nosuch,  0 },                   /* d */
1135 –  { chm_except,  0 },                   /* e */
1136 –  { chm_nosuch,  0 },                   /* f */
1137 –  { chm_nosuch,  0 },                   /* g */
1138 –  { chm_hop,     0 },                   /* h */
1139 –  { chm_simple,     MODE_INVITEONLY },  /* i */
1140 –  { chm_nosuch,     0               },  /* j */
1141 –  { chm_key,        0               },  /* k */
1142 –  { chm_limit,      0               },  /* l */
1143 –  { chm_simple,     MODE_MODERATED  },  /* m */
1144 –  { chm_simple,     MODE_NOPRIVMSGS },  /* n */
1145 –  { chm_op,         0               },  /* o */
1146 –  { chm_simple,     MODE_PRIVATE    },  /* p */
1147 –  { chm_nosuch,     0               },  /* q */
1148 –  { chm_registered, MODE_REGISTERED },  /* r */
1149 –  { chm_simple,     MODE_SECRET     },  /* s */
1150 –  { chm_simple,     MODE_TOPICLIMIT },  /* t */
1151 –  { chm_nosuch,     0               },  /* u */
1152 –  { chm_voice,      0               },  /* v */
1153 –  { chm_nosuch,     0               },  /* w */
1154 –  { chm_nosuch,     0               },  /* x */
1155 –  { chm_nosuch,     0               },  /* y */
1156 –  { chm_nosuch,     0               },  /* z */
1157 –  { chm_nosuch,  0 },                   /* 0x7b */
1158 –  { chm_nosuch,  0 },                   /* 0x7c */
1159 –  { chm_nosuch,  0 },                   /* 0x7d */
1160 –  { chm_nosuch,  0 },                   /* 0x7e */
1161 –  { chm_nosuch,  0 },                   /* 0x7f */
1162 –  { chm_nosuch,  0 },                   /* 0x80 */
1163 –  { chm_nosuch,  0 },                   /* 0x81 */
1164 –  { chm_nosuch,  0 },                   /* 0x82 */
1165 –  { chm_nosuch,  0 },                   /* 0x83 */
1166 –  { chm_nosuch,  0 },                   /* 0x84 */
1167 –  { chm_nosuch,  0 },                   /* 0x85 */
1168 –  { chm_nosuch,  0 },                   /* 0x86 */
1169 –  { chm_nosuch,  0 },                   /* 0x87 */
1170 –  { chm_nosuch,  0 },                   /* 0x88 */
1171 –  { chm_nosuch,  0 },                   /* 0x89 */
1172 –  { chm_nosuch,  0 },                   /* 0x8a */
1173 –  { chm_nosuch,  0 },                   /* 0x8b */
1174 –  { chm_nosuch,  0 },                   /* 0x8c */
1175 –  { chm_nosuch,  0 },                   /* 0x8d */
1176 –  { chm_nosuch,  0 },                   /* 0x8e */
1177 –  { chm_nosuch,  0 },                   /* 0x8f */
1178 –  { chm_nosuch,  0 },                   /* 0x90 */
1179 –  { chm_nosuch,  0 },                   /* 0x91 */
1180 –  { chm_nosuch,  0 },                   /* 0x92 */
1181 –  { chm_nosuch,  0 },                   /* 0x93 */
1182 –  { chm_nosuch,  0 },                   /* 0x94 */
1183 –  { chm_nosuch,  0 },                   /* 0x95 */
1184 –  { chm_nosuch,  0 },                   /* 0x96 */
1185 –  { chm_nosuch,  0 },                   /* 0x97 */
1186 –  { chm_nosuch,  0 },                   /* 0x98 */
1187 –  { chm_nosuch,  0 },                   /* 0x99 */
1188 –  { chm_nosuch,  0 },                   /* 0x9a */
1189 –  { chm_nosuch,  0 },                   /* 0x9b */
1190 –  { chm_nosuch,  0 },                   /* 0x9c */
1191 –  { chm_nosuch,  0 },                   /* 0x9d */
1192 –  { chm_nosuch,  0 },                   /* 0x9e */
1193 –  { chm_nosuch,  0 },                   /* 0x9f */
1194 –  { chm_nosuch,  0 },                   /* 0xa0 */
1195 –  { chm_nosuch,  0 },                   /* 0xa1 */
1196 –  { chm_nosuch,  0 },                   /* 0xa2 */
1197 –  { chm_nosuch,  0 },                   /* 0xa3 */
1198 –  { chm_nosuch,  0 },                   /* 0xa4 */
1199 –  { chm_nosuch,  0 },                   /* 0xa5 */
1200 –  { chm_nosuch,  0 },                   /* 0xa6 */
1201 –  { chm_nosuch,  0 },                   /* 0xa7 */
1202 –  { chm_nosuch,  0 },                   /* 0xa8 */
1203 –  { chm_nosuch,  0 },                   /* 0xa9 */
1204 –  { chm_nosuch,  0 },                   /* 0xaa */
1205 –  { chm_nosuch,  0 },                   /* 0xab */
1206 –  { chm_nosuch,  0 },                   /* 0xac */
1207 –  { chm_nosuch,  0 },                   /* 0xad */
1208 –  { chm_nosuch,  0 },                   /* 0xae */
1209 –  { chm_nosuch,  0 },                   /* 0xaf */
1210 –  { chm_nosuch,  0 },                   /* 0xb0 */
1211 –  { chm_nosuch,  0 },                   /* 0xb1 */
1212 –  { chm_nosuch,  0 },                   /* 0xb2 */
1213 –  { chm_nosuch,  0 },                   /* 0xb3 */
1214 –  { chm_nosuch,  0 },                   /* 0xb4 */
1215 –  { chm_nosuch,  0 },                   /* 0xb5 */
1216 –  { chm_nosuch,  0 },                   /* 0xb6 */
1217 –  { chm_nosuch,  0 },                   /* 0xb7 */
1218 –  { chm_nosuch,  0 },                   /* 0xb8 */
1219 –  { chm_nosuch,  0 },                   /* 0xb9 */
1220 –  { chm_nosuch,  0 },                   /* 0xba */
1221 –  { chm_nosuch,  0 },                   /* 0xbb */
1222 –  { chm_nosuch,  0 },                   /* 0xbc */
1223 –  { chm_nosuch,  0 },                   /* 0xbd */
1224 –  { chm_nosuch,  0 },                   /* 0xbe */
1225 –  { chm_nosuch,  0 },                   /* 0xbf */
1226 –  { chm_nosuch,  0 },                   /* 0xc0 */
1227 –  { chm_nosuch,  0 },                   /* 0xc1 */
1228 –  { chm_nosuch,  0 },                   /* 0xc2 */
1229 –  { chm_nosuch,  0 },                   /* 0xc3 */
1230 –  { chm_nosuch,  0 },                   /* 0xc4 */
1231 –  { chm_nosuch,  0 },                   /* 0xc5 */
1232 –  { chm_nosuch,  0 },                   /* 0xc6 */
1233 –  { chm_nosuch,  0 },                   /* 0xc7 */
1234 –  { chm_nosuch,  0 },                   /* 0xc8 */
1235 –  { chm_nosuch,  0 },                   /* 0xc9 */
1236 –  { chm_nosuch,  0 },                   /* 0xca */
1237 –  { chm_nosuch,  0 },                   /* 0xcb */
1238 –  { chm_nosuch,  0 },                   /* 0xcc */
1239 –  { chm_nosuch,  0 },                   /* 0xcd */
1240 –  { chm_nosuch,  0 },                   /* 0xce */
1241 –  { chm_nosuch,  0 },                   /* 0xcf */
1242 –  { chm_nosuch,  0 },                   /* 0xd0 */
1243 –  { chm_nosuch,  0 },                   /* 0xd1 */
1244 –  { chm_nosuch,  0 },                   /* 0xd2 */
1245 –  { chm_nosuch,  0 },                   /* 0xd3 */
1246 –  { chm_nosuch,  0 },                   /* 0xd4 */
1247 –  { chm_nosuch,  0 },                   /* 0xd5 */
1248 –  { chm_nosuch,  0 },                   /* 0xd6 */
1249 –  { chm_nosuch,  0 },                   /* 0xd7 */
1250 –  { chm_nosuch,  0 },                   /* 0xd8 */
1251 –  { chm_nosuch,  0 },                   /* 0xd9 */
1252 –  { chm_nosuch,  0 },                   /* 0xda */
1253 –  { chm_nosuch,  0 },                   /* 0xdb */
1254 –  { chm_nosuch,  0 },                   /* 0xdc */
1255 –  { chm_nosuch,  0 },                   /* 0xdd */
1256 –  { chm_nosuch,  0 },                   /* 0xde */
1257 –  { chm_nosuch,  0 },                   /* 0xdf */
1258 –  { chm_nosuch,  0 },                   /* 0xe0 */
1259 –  { chm_nosuch,  0 },                   /* 0xe1 */
1260 –  { chm_nosuch,  0 },                   /* 0xe2 */
1261 –  { chm_nosuch,  0 },                   /* 0xe3 */
1262 –  { chm_nosuch,  0 },                   /* 0xe4 */
1263 –  { chm_nosuch,  0 },                   /* 0xe5 */
1264 –  { chm_nosuch,  0 },                   /* 0xe6 */
1265 –  { chm_nosuch,  0 },                   /* 0xe7 */
1266 –  { chm_nosuch,  0 },                   /* 0xe8 */
1267 –  { chm_nosuch,  0 },                   /* 0xe9 */
1268 –  { chm_nosuch,  0 },                   /* 0xea */
1269 –  { chm_nosuch,  0 },                   /* 0xeb */
1270 –  { chm_nosuch,  0 },                   /* 0xec */
1271 –  { chm_nosuch,  0 },                   /* 0xed */
1272 –  { chm_nosuch,  0 },                   /* 0xee */
1273 –  { chm_nosuch,  0 },                   /* 0xef */
1274 –  { chm_nosuch,  0 },                   /* 0xf0 */
1275 –  { chm_nosuch,  0 },                   /* 0xf1 */
1276 –  { chm_nosuch,  0 },                   /* 0xf2 */
1277 –  { chm_nosuch,  0 },                   /* 0xf3 */
1278 –  { chm_nosuch,  0 },                   /* 0xf4 */
1279 –  { chm_nosuch,  0 },                   /* 0xf5 */
1280 –  { chm_nosuch,  0 },                   /* 0xf6 */
1281 –  { chm_nosuch,  0 },                   /* 0xf7 */
1282 –  { chm_nosuch,  0 },                   /* 0xf8 */
1283 –  { chm_nosuch,  0 },                   /* 0xf9 */
1284 –  { chm_nosuch,  0 },                   /* 0xfa */
1285 –  { chm_nosuch,  0 },                   /* 0xfb */
1286 –  { chm_nosuch,  0 },                   /* 0xfc */
1287 –  { chm_nosuch,  0 },                   /* 0xfd */
1288 –  { chm_nosuch,  0 },                   /* 0xfe */
1289 –  { chm_nosuch,  0 },                   /* 0xff */
1290 – };
1291 –
659   /* get_channel_access()
660   *
661   * inputs       - pointer to Client struct
# Line 1305 | Line 672 | get_channel_access(const struct Client *
672    if (!MyClient(source_p))
673      return CHACCESS_REMOTE;
674  
675 <  if (!member)
675 >  if (member == NULL)
676      return CHACCESS_NOTONCHAN;
677  
678    /* Just to be sure.. */
# Line 1330 | Line 697 | get_channel_access(const struct Client *
697   static void
698   send_mode_changes_server(struct Client *source_p, struct Channel *chptr)
699   {
700 <  int mbl = 0, pbl = 0, arglen = 0, nc = 0, mc = 0;
701 <  int len = 0;
702 <  int dir = MODE_QUERY;
703 <  const char *arg = NULL;
704 <  char *parptr = NULL;
1338 <
1339 <  parabuf[0] = '\0';
1340 <  parptr = parabuf;
700 >  char modebuf[IRCD_BUFSIZE] = "";
701 >  char parabuf[IRCD_BUFSIZE] = "";
702 >  char *parptr = parabuf;
703 >  unsigned int mbl = 0, pbl = 0, arglen = 0, modecount = 0, paracount = 0;
704 >  unsigned int dir = MODE_QUERY;
705  
706 <  mbl = snprintf(modebuf, sizeof(modebuf), ":%s TMODE %lu %s ", source_p->id,
707 <                 (unsigned long)chptr->creationtime, chptr->name);
706 >  mbl = snprintf(modebuf, sizeof(modebuf), ":%s TMODE %ju %s ",
707 >                 source_p->id, chptr->creationtime, chptr->name);
708  
709    /* Loop the list of modes we have */
710    for (unsigned int i = 0; i < mode_count; ++i)
# Line 1348 | Line 712 | send_mode_changes_server(struct Client *
712      if (mode_changes[i].letter == 0)
713        continue;
714  
715 +    const char *arg;
716      if (mode_changes[i].id)
717        arg = mode_changes[i].id;
718      else
# Line 1362 | Line 727 | send_mode_changes_server(struct Client *
727       * If we're creeping past the buf size, we need to send it and make
728       * another line for the other modes
729       */
730 <    if ((mc == MAXMODEPARAMS) ||
731 <        ((arglen + mbl + pbl + 2) > IRCD_BUFSIZE) ||
1367 <        (pbl + arglen + BAN_FUDGE) >= MODEBUFLEN)
730 >    if ((paracount == MAXMODEPARAMS) ||
731 >        ((arglen + mbl + pbl + 2 /* +2 for /r/n */ ) > IRCD_BUFSIZE))
732      {
733 <      if (nc)
733 >      if (modecount)
734          sendto_server(source_p, 0, 0, "%s %s", modebuf, parabuf);
735  
736 <      nc = 0;
737 <      mc = 0;
736 >      modecount = 0;
737 >      paracount = 0;
738  
739 <      mbl = snprintf(modebuf, sizeof(modebuf), ":%s TMODE %lu %s ", source_p->id,
740 <                     (unsigned long)chptr->creationtime, chptr->name);
739 >      mbl = snprintf(modebuf, sizeof(modebuf), ":%s TMODE %ju %s ",
740 >                     source_p->id, chptr->creationtime, chptr->name);
741  
742        pbl = 0;
743        parabuf[0] = '\0';
# Line 1389 | Line 753 | send_mode_changes_server(struct Client *
753  
754      modebuf[mbl++] = mode_changes[i].letter;
755      modebuf[mbl] = '\0';
756 <    ++nc;
756 >    ++modecount;
757  
758      if (arg)
759      {
760 <      len = sprintf(parptr, "%s ", arg);
760 >      int len = sprintf(parptr, (pbl == 0) ? "%s" : " %s", arg);
761        pbl += len;
762        parptr += len;
763 <      ++mc;
763 >      ++paracount;
764      }
765    }
766  
767 <  if (pbl && parabuf[pbl - 1] == ' ')
1404 <    parabuf[pbl - 1] = '\0';
1405 <
1406 <  if (nc)
767 >  if (modecount)
768      sendto_server(source_p, 0, 0, "%s %s", modebuf, parabuf);
769   }
770  
# Line 1417 | Line 778 | send_mode_changes_server(struct Client *
778   * Side-effects: Sends the appropriate mode changes to other clients
779   *               and propagates to servers.
780   */
1420 – /* ensure parabuf < MODEBUFLEN -db */
781   static void
782   send_mode_changes_client(struct Client *source_p, struct Channel *chptr)
783   {
784 <  int mbl = 0, pbl = 0, arglen = 0, nc = 0, mc = 0;
1425 <  int len = 0;
1426 <  int dir = MODE_QUERY;
1427 <  const char *arg = NULL;
1428 <  char *parptr = NULL;
1429 <
1430 <  if (IsServer(source_p))
1431 <    mbl = snprintf(modebuf, sizeof(modebuf), ":%s MODE %s ", (IsHidden(source_p) ||
1432 <                   ConfigServerHide.hide_servers) ?
1433 <                   me.name : source_p->name, chptr->name);
1434 <  else
1435 <    mbl = snprintf(modebuf, sizeof(modebuf), ":%s!%s@%s MODE %s ", source_p->name,
1436 <                   source_p->username, source_p->host, chptr->name);
1437 <
1438 <  parabuf[0] = '\0';
1439 <  parptr = parabuf;
784 >  unsigned int flags = 0;
785  
786 <  for (unsigned int i = 0; i < mode_count; ++i)
786 >  for (unsigned int pass = 2; pass--; flags = CHFL_CHANOP | CHFL_HALFOP)
787    {
788 <    if (mode_changes[i].letter == 0)
789 <      continue;
790 <
791 <    arg = mode_changes[i].arg;
792 <    if (arg)
793 <      arglen = strlen(arg);
788 >    char modebuf[IRCD_BUFSIZE] = "";
789 >    char parabuf[IRCD_BUFSIZE] = "";
790 >    char *parptr = parabuf;
791 >    unsigned int mbl = 0, pbl = 0, arglen = 0, modecount = 0, paracount = 0;
792 >    unsigned int dir = MODE_QUERY;
793 >
794 >    if (IsClient(source_p))
795 >      mbl = snprintf(modebuf, sizeof(modebuf), ":%s!%s@%s MODE %s ", source_p->name,
796 >                     source_p->username, source_p->host, chptr->name);
797      else
798 <      arglen = 0;
798 >      mbl = snprintf(modebuf, sizeof(modebuf), ":%s MODE %s ", (IsHidden(source_p) ||
799 >                     ConfigServerHide.hide_servers) ?
800 >                     me.name : source_p->name, chptr->name);
801  
802 <    if ((mc == MAXMODEPARAMS) ||
1453 <        ((arglen + mbl + pbl + 2) > IRCD_BUFSIZE) ||
1454 <        ((arglen + pbl + BAN_FUDGE) >= MODEBUFLEN))
802 >    for (unsigned int i = 0; i < mode_count; ++i)
803      {
804 <      if (mbl && modebuf[mbl - 1] == '-')
805 <        modebuf[mbl - 1] = '\0';
804 >      if (mode_changes[i].letter == 0 || mode_changes[i].flags != flags)
805 >        continue;
806  
807 <      if (nc)
808 <        sendto_channel_local(0, chptr, "%s %s", modebuf, parabuf);
807 >      const char *arg = mode_changes[i].arg;
808 >      if (arg)
809 >        arglen = strlen(arg);
810 >      else
811 >        arglen = 0;
812  
813 <      nc = 0;
814 <      mc = 0;
813 >      if ((paracount == MAXMODEPARAMS) ||
814 >          ((arglen + mbl + pbl + 2 /* +2 for /r/n */ ) > IRCD_BUFSIZE))
815 >      {
816 >        if (modecount)
817 >          sendto_channel_local(NULL, chptr, flags, 0, 0, "%s %s", modebuf, parabuf);
818  
819 <      if (IsServer(source_p))
820 <        mbl = snprintf(modebuf, sizeof(modebuf), ":%s MODE %s ", (IsHidden(source_p) ||
1467 <                       ConfigServerHide.hide_servers) ?
1468 <                       me.name : source_p->name, chptr->name);
1469 <      else
1470 <        mbl = snprintf(modebuf, sizeof(modebuf), ":%s!%s@%s MODE %s ", source_p->name,
1471 <                       source_p->username, source_p->host, chptr->name);
819 >        modecount = 0;
820 >        paracount = 0;
821  
822 <      pbl = 0;
823 <      parabuf[0] = '\0';
824 <      parptr = parabuf;
825 <      dir = MODE_QUERY;
826 <    }
822 >        if (IsClient(source_p))
823 >          mbl = snprintf(modebuf, sizeof(modebuf), ":%s!%s@%s MODE %s ", source_p->name,
824 >                         source_p->username, source_p->host, chptr->name);
825 >        else
826 >          mbl = snprintf(modebuf, sizeof(modebuf), ":%s MODE %s ", (IsHidden(source_p) ||
827 >                         ConfigServerHide.hide_servers) ?
828 >                         me.name : source_p->name, chptr->name);
829 >
830 >        pbl = 0;
831 >        parabuf[0] = '\0';
832 >        parptr = parabuf;
833 >        dir = MODE_QUERY;
834 >      }
835  
836 <    if (dir != mode_changes[i].dir)
837 <    {
838 <      modebuf[mbl++] = (mode_changes[i].dir == MODE_ADD) ? '+' : '-';
839 <      dir = mode_changes[i].dir;
840 <    }
836 >      if (dir != mode_changes[i].dir)
837 >      {
838 >        modebuf[mbl++] = (mode_changes[i].dir == MODE_ADD) ? '+' : '-';
839 >        dir = mode_changes[i].dir;
840 >      }
841  
842 <    modebuf[mbl++] = mode_changes[i].letter;
843 <    modebuf[mbl] = '\0';
844 <    ++nc;
842 >      modebuf[mbl++] = mode_changes[i].letter;
843 >      modebuf[mbl] = '\0';
844 >      ++modecount;
845  
846 <    if (arg)
847 <    {
848 <      len = sprintf(parptr, "%s ", arg);
849 <      pbl += len;
850 <      parptr += len;
851 <      ++mc;
846 >      if (arg)
847 >      {
848 >        int len = sprintf(parptr, (pbl == 0) ? "%s" : " %s", arg);
849 >        pbl += len;
850 >        parptr += len;
851 >        ++paracount;
852 >      }
853      }
854 +
855 +    if (modecount)
856 +      sendto_channel_local(NULL, chptr, flags, 0, 0, "%s %s", modebuf, parabuf);
857    }
858 + }
859  
860 <  if (pbl && parabuf[pbl - 1] == ' ')
861 <    parabuf[pbl - 1] = '\0';
860 > const struct chan_mode *cmode_map[256];
861 > const struct chan_mode  cmode_tab[] =
862 > {
863 >  { .letter = 'b', .flag = CHFL_BAN, .required_oplevel = CHACCESS_HALFOP, .func = chm_mask },
864 >  { .letter = 'c', .mode = MODE_NOCTRL, .required_oplevel = CHACCESS_HALFOP, .func = chm_simple },
865 >  { .letter = 'e', .flag = CHFL_EXCEPTION, .required_oplevel = CHACCESS_HALFOP, .func = chm_mask },
866 >  { .letter = 'h', .flag = CHFL_HALFOP, .required_oplevel = CHACCESS_CHANOP, .func = chm_flag },
867 >  { .letter = 'i', .mode = MODE_INVITEONLY, .required_oplevel = CHACCESS_HALFOP, .func = chm_simple },
868 >  { .letter = 'k', .func = chm_key, .required_oplevel = CHACCESS_HALFOP },
869 >  { .letter = 'l', .func = chm_limit, .required_oplevel = CHACCESS_HALFOP },
870 >  { .letter = 'm', .mode = MODE_MODERATED, .required_oplevel = CHACCESS_HALFOP, .func = chm_simple },
871 >  { .letter = 'n', .mode = MODE_NOPRIVMSGS, .required_oplevel = CHACCESS_HALFOP, .func = chm_simple },
872 >  { .letter = 'o', .flag = CHFL_CHANOP, .required_oplevel = CHACCESS_CHANOP, .func = chm_flag },
873 >  { .letter = 'p', .mode = MODE_PRIVATE, .required_oplevel = CHACCESS_HALFOP, .func = chm_simple },
874 >  { .letter = 'r', .mode = MODE_REGISTERED, .required_oplevel = CHACCESS_REMOTE, .only_servers = true, .func = chm_simple },
875 >  { .letter = 's', .mode = MODE_SECRET, .required_oplevel = CHACCESS_HALFOP, .func = chm_simple },
876 >  { .letter = 't', .mode = MODE_TOPICLIMIT, .required_oplevel = CHACCESS_HALFOP, .func = chm_simple },
877 >  { .letter = 'u', .mode = MODE_HIDEBMASKS, .required_oplevel = CHACCESS_HALFOP, .func = chm_simple },
878 >  { .letter = 'v', .flag = CHFL_VOICE, .required_oplevel = CHACCESS_HALFOP, .func = chm_flag },
879 >  { .letter = 'C', .mode = MODE_NOCTCP, .required_oplevel = CHACCESS_HALFOP, .func = chm_simple },
880 >  { .letter = 'I', .flag = CHFL_INVEX, .required_oplevel = CHACCESS_HALFOP, .func = chm_mask },
881 >  { .letter = 'L', .mode = MODE_EXTLIMIT, .required_oplevel = CHACCESS_HALFOP, .only_opers = true, .func = chm_simple },
882 >  { .letter = 'M', .mode = MODE_MODREG, .required_oplevel = CHACCESS_HALFOP, .func = chm_simple },
883 >  { .letter = 'N', .mode = MODE_NONICKCHANGE, .required_oplevel = CHACCESS_HALFOP, .func = chm_simple },
884 >  { .letter = 'O', .mode = MODE_OPERONLY, .required_oplevel = CHACCESS_HALFOP, .only_opers = true, .func = chm_simple },
885 >  { .letter = 'R', .mode = MODE_REGONLY, .required_oplevel = CHACCESS_HALFOP, .func = chm_simple },
886 >  { .letter = 'S', .mode = MODE_SSLONLY, .required_oplevel = CHACCESS_HALFOP, .func = chm_simple },
887 >  { .letter = 'T', .mode = MODE_NONOTICE, .required_oplevel = CHACCESS_HALFOP, .func = chm_simple },
888 >  { .letter = '\0', .mode = 0 }
889 > };
890  
891 <  if (nc)
892 <    sendto_channel_local(0, chptr, "%s %s", modebuf, parabuf);
891 > void
892 > channel_mode_init(void)
893 > {
894 >  for (const struct chan_mode *tab = cmode_tab; tab->letter; ++tab)
895 >    cmode_map[tab->letter] = tab;
896   }
897  
898   /*
# Line 1512 | Line 905 | send_mode_changes_client(struct Client *
905   *               clients.
906   */
907   void
908 < set_channel_mode(struct Client *source_p, struct Channel *chptr,
908 > channel_mode_set(struct Client *source_p, struct Channel *chptr,
909                   struct Membership *member, int parc, char *parv[])
910   {
911    int dir = MODE_ADD;
# Line 1540 | Line 933 | set_channel_mode(struct Client *source_p
933          break;
934        default:
935        {
936 <        const struct ChannelMode *tptr = &ModeTable[(unsigned char)*ml];
936 >        const struct chan_mode *mode = cmode_map[(unsigned char)*ml];
937  
938 <        tptr->func(source_p, chptr, parc, &parn, parv,
939 <                   &errors, alevel, dir, *ml, tptr->d);
938 >        if (mode)
939 >          mode->func(source_p, chptr, parc, &parn, parv, &errors, alevel, dir, *ml, mode);
940 >        else
941 >          chm_nosuch(source_p, chptr, parc, &parn, parv, &errors, alevel, dir, *ml, NULL);
942          break;
943        }
944      }
945    }
946  
947    /* Bail out if we have nothing to do... */
948 <  if (!mode_count)
948 >  if (mode_count == 0)
949      return;
950  
951    send_mode_changes_client(source_p, chptr);

Comparing ircd-hybrid/trunk/src/channel_mode.c (property svn:keywords):
Revision 5752 by michael, Thu Apr 2 17:27:33 2015 UTC vs.
Revision 8752 by michael, Tue Jan 1 11:07:01 2019 UTC

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

Diff Legend

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