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-7.3/src/channel_mode.c (file contents), Revision 1150 by michael, Wed Aug 3 01:09:49 2011 UTC vs.
ircd-hybrid/trunk/src/channel_mode.c (file contents), Revision 4800 by michael, Tue Oct 28 13:59:43 2014 UTC

# Line 1 | Line 1
1   /*
2 < *  ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
3 < *  channel_mode.c: Controls modes on channels.
2 > *  ircd-hybrid: an advanced, lightweight Internet Relay Chat Daemon (ircd)
3   *
4 < *  Copyright (C) 2005 by the past and present ircd coders, and others.
4 > *  Copyright (c) 1997-2014 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 16 | Line 15
15   *
16   *  You should have received a copy of the GNU General Public License
17   *  along with this program; if not, write to the Free Software
18 < *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
18 > *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
19   *  USA
20 < *
21 < *  $Id$
20 > */
21 >
22 > /*! \file channel_mode.c
23 > * \brief Controls modes on channels.
24 > * \version $Id$
25   */
26  
27   #include "stdinc.h"
# Line 27 | Line 29
29   #include "channel.h"
30   #include "channel_mode.h"
31   #include "client.h"
32 < #include "common.h"
31 < #include "hash.h"
32 > #include "conf.h"
33   #include "hostmask.h"
34   #include "irc_string.h"
34 – #include "sprintf_irc.h"
35   #include "ircd.h"
36   #include "numeric.h"
37 < #include "s_serv.h"             /* captab */
38 < #include "s_user.h"
37 > #include "server.h"
38   #include "send.h"
40 – #include "whowas.h"
41 – #include "s_conf.h"             /* ConfigFileEntry, ConfigChannel */
42 – #include "event.h"
39   #include "memory.h"
40 < #include "balloc.h"
41 < #include "s_log.h"
46 < #include "msg.h"
47 <
48 < /* some small utility functions */
49 < static char *check_string(char *);
50 < static char *fix_key(char *);
51 < static char *fix_key_old(char *);
52 < static void chm_nosuch(struct Client *, struct Client *,
53 <                       struct Channel *, int, int *, char **, int *, int,
54 <                       int, char, void *, const char *);
55 < static void chm_simple(struct Client *, struct Client *, struct Channel *,
56 <                       int, int *, char **, int *, int, int, char, void *,
57 <                       const char *);
58 < static void chm_limit(struct Client *, struct Client *, struct Channel *,
59 <                      int, int *, char **, int *, int, int, char, void *,
60 <                      const char *);
61 < static void chm_key(struct Client *, struct Client *, struct Channel *,
62 <                    int, int *, char **, int *, int, int, char, void *,
63 <                    const char *);
64 < static void chm_op(struct Client *, struct Client *, struct Channel *, int,
65 <                   int *, char **, int *, int, int, char, void *,
66 <                   const char *);
67 < #ifdef HALFOPS
68 < static void chm_hop(struct Client *, struct Client *, struct Channel *, int,
69 <                   int *, char **, int *, int, int, char, void *,
70 <                   const char *);
71 < #endif
72 < static void chm_voice(struct Client *, struct Client *, struct Channel *,
73 <                      int, int *, char **, int *, int, int, char, void *,
74 <                      const char *);
75 < static void chm_ban(struct Client *, struct Client *, struct Channel *, int,
76 <                    int *, char **, int *, int, int, char, void *,
77 <                    const char *);
78 < static void chm_except(struct Client *, struct Client *, struct Channel *,
79 <                       int, int *, char **, int *, int, int, char, void *,
80 <                       const char *);
81 < static void chm_invex(struct Client *, struct Client *, struct Channel *,
82 <                      int, int *, char **, int *, int, int, char, void *,
83 <                      const char *);
84 < static void send_cap_mode_changes(struct Client *, struct Client *,
85 <                                  struct Channel *, unsigned int, unsigned int);
86 < static void send_mode_changes(struct Client *, struct Client *,
87 <                              struct Channel *, char *);
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
91 < #define NCHCAPS         (sizeof(channel_capabs)/sizeof(int))
92 < #define NCHCAP_COMBOS   (1 << NCHCAPS)
44 > #define BAN_FUDGE       10
45  
46   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];
50   static struct ChModeChange mode_changes[IRCD_BUFSIZE];
51 < static int mode_count;
52 < static int mode_limit;          /* number of modes set other than simple */
53 < static int simple_modes_mask;   /* bit mask of simple modes already set */
54 < #ifdef HALFOPS
55 < static int channel_capabs[] = { CAP_EX, CAP_IE, CAP_TS6, CAP_HOPS };
56 < #else
57 < static int channel_capabs[] = { CAP_EX, CAP_IE, CAP_TS6 };
58 < #endif
59 < static struct ChCapCombo chcap_combos[NCHCAP_COMBOS];
60 < extern BlockHeap *ban_heap;
51 > static unsigned int mode_count;
52 > static unsigned int mode_limit;  /* number of modes set other than simple */
53 > 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_MODREG,     'M' },
67 >  { MODE_OPERONLY,   'O' },
68 >  { MODE_REGONLY,    'R' },
69 >  { MODE_SSLONLY,    'S' },
70 >  { 0, '\0' }
71 > };
72  
73  
111 – /* XXX check_string is propably not longer required in add_id and del_id */
74   /* check_string()
75   *
76   * inputs       - string to check
# Line 124 | Line 86 | check_string(char *s)
86    char *str = s;
87    static char star[] = "*";
88  
89 <  if (EmptyString(s))
89 >  if (EmptyString(str))
90      return star;
91  
92    for (; *s; ++s)
# Line 136 | Line 98 | check_string(char *s)
98      }
99    }
100  
101 <  return str;
101 >  return EmptyString(str) ? star : str;
102   }
103  
104   /*
105   * Ban functions to work with mode +b/e/d/I
106   */
107 < /* add the specified ID to the channel..
108 < *   -is 8/9/00
107 > /* add the specified ID to the channel.
108 > *   -is 8/9/00
109   */
110  
111   int
112 < add_id(struct Client *client_p, struct Channel *chptr, char *banid, int type)
112 > add_id(struct Client *client_p, struct Channel *chptr, char *banid, unsigned int type)
113   {
114    dlink_list *list = NULL;
115 <  dlink_node *ban = NULL;
115 >  dlink_node *node = NULL;
116 >  struct Ban *banptr = NULL;
117    size_t len = 0;
118 <  struct Ban *ban_p = NULL;
119 <  unsigned int num_mask;
120 <  char name[NICKLEN];
158 <  char user[USERLEN + 1];
159 <  char host[HOSTLEN + 1];
118 >  char name[NICKLEN + 1] = "";
119 >  char user[USERLEN + 1] = "";
120 >  char host[HOSTLEN + 1] = "";
121    struct split_nuh_item nuh;
122  
123 <  /* dont let local clients overflow the b/e/I lists */
123 >  /* Don't let local clients overflow the b/e/I lists */
124    if (MyClient(client_p))
125    {
126 <    num_mask = dlink_list_length(&chptr->banlist) +
127 <               dlink_list_length(&chptr->exceptlist) +
128 <               dlink_list_length(&chptr->invexlist);
126 >    unsigned int num_mask = dlink_list_length(&chptr->banlist) +
127 >                            dlink_list_length(&chptr->exceptlist) +
128 >                            dlink_list_length(&chptr->invexlist);
129  
130      if (num_mask >= ConfigChannel.max_bans)
131      {
132 <      sendto_one(client_p, form_str(ERR_BANLISTFULL),
172 <                 me.name, client_p->name, chptr->chname, banid);
132 >      sendto_one_numeric(client_p, &me, ERR_BANLISTFULL, chptr->name, banid);
133        return 0;
134      }
135  
# Line 191 | Line 151 | add_id(struct Client *client_p, struct C
151     * Re-assemble a new n!u@h and print it back to banid for sending
152     * the mode to the channel.
153     */
154 <  len = ircsprintf(banid, "%s!%s@%s", name, user, host);
154 >  len = sprintf(banid, "%s!%s@%s", name, user, host);
155  
156    switch (type)
157    {
# Line 211 | Line 171 | add_id(struct Client *client_p, struct C
171        return 0;
172    }
173  
174 <  DLINK_FOREACH(ban, list->head)
174 >  DLINK_FOREACH(node, list->head)
175    {
176 <    ban_p = ban->data;
177 <    if (!irccmp(ban_p->name, name) &&
178 <        !irccmp(ban_p->username, user) &&
179 <        !irccmp(ban_p->host, host))
180 <    {
176 >    banptr = node->data;
177 >
178 >    if (!irccmp(banptr->name, name) &&
179 >        !irccmp(banptr->user, user) &&
180 >        !irccmp(banptr->host, host))
181        return 0;
222 –    }
182    }
183  
184 <  ban_p = BlockHeapAlloc(ban_heap);
185 <
186 <  DupString(ban_p->name, name);
187 <  DupString(ban_p->username, user);
188 <  DupString(ban_p->host, host);
189 <
190 <  ban_p->when = CurrentTime;
232 <  ban_p->len = len - 2; /* -2 for @ and ! */
233 <  ban_p->type = parse_netmask(host, &ban_p->addr, &ban_p->bits);
184 >  banptr = mp_pool_get(ban_pool);
185 >  banptr->name = xstrdup(name);
186 >  banptr->user = xstrdup(user);
187 >  banptr->host = xstrdup(host);
188 >  banptr->when = CurrentTime;
189 >  banptr->len = len - 2;  /* -2 for ! + @ */
190 >  banptr->type = parse_netmask(host, &banptr->addr, &banptr->bits);
191  
192    if (IsClient(client_p))
193    {
194 <    ban_p->who = MyMalloc(strlen(client_p->name) +
195 <                          strlen(client_p->username) +
196 <                          strlen(client_p->host) + 3);
197 <    ircsprintf(ban_p->who, "%s!%s@%s", client_p->name,
198 <               client_p->username, client_p->host);
194 >    banptr->who = MyCalloc(strlen(client_p->name) +
195 >                           strlen(client_p->username) +
196 >                           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);
202    else
203 <    DupString(ban_p->who, client_p->name);
203 >    banptr->who = xstrdup(client_p->name);
204  
205 <  dlinkAdd(ban_p, &ban_p->node, list);
205 >  dlinkAdd(banptr, &banptr->node, list);
206  
207    return 1;
208   }
# Line 256 | Line 215 | add_id(struct Client *client_p, struct C
215   * side effects -
216   */
217   static int
218 < del_id(struct Channel *chptr, char *banid, int type)
218 > del_id(struct Channel *chptr, char *banid, unsigned int type)
219   {
220 <  dlink_list *list;
221 <  dlink_node *ban;
222 <  struct Ban *banptr;
223 <  char name[NICKLEN];
224 <  char user[USERLEN + 1];
266 <  char host[HOSTLEN + 1];
220 >  dlink_list *list = NULL;
221 >  dlink_node *node = NULL;
222 >  char name[NICKLEN + 1] = "";
223 >  char user[USERLEN + 1] = "";
224 >  char host[HOSTLEN + 1] = "";
225    struct split_nuh_item nuh;
226  
227 <  if (banid == NULL)
270 <    return 0;
227 >  assert(banid);
228  
229    nuh.nuhmask  = check_string(banid);
230    nuh.nickptr  = name;
# Line 284 | Line 241 | del_id(struct Channel *chptr, char *bani
241     * Re-assemble a new n!u@h and print it back to banid for sending
242     * the mode to the channel.
243     */
244 <  ircsprintf(banid, "%s!%s@%s", name, user, host);
244 >  sprintf(banid, "%s!%s@%s", name, user, host);
245  
246    switch (type)
247    {
# Line 300 | Line 257 | del_id(struct Channel *chptr, char *bani
257        list = &chptr->invexlist;
258        break;
259      default:
260 <      sendto_realops_flags(UMODE_ALL, L_ALL,
304 <                           "del_id() called with unknown ban type %d!", type);
260 >      assert(0);
261        return 0;
262    }
263  
264 <  DLINK_FOREACH(ban, list->head)
264 >  DLINK_FOREACH(node, list->head)
265    {
266 <    banptr = ban->data;
266 >    struct Ban *banptr = node->data;
267  
268      if (!irccmp(name, banptr->name) &&
269 <        !irccmp(user, banptr->username) &&
269 >        !irccmp(user, banptr->user) &&
270          !irccmp(host, banptr->host))
271      {
272        remove_ban(banptr, list);
# Line 321 | Line 277 | del_id(struct Channel *chptr, char *bani
277    return 0;
278   }
279  
324 – static const struct mode_letter
325 – {
326 –  const unsigned int mode;
327 –  const unsigned char letter;
328 – } flags[] = {
329 –  { MODE_INVITEONLY, 'i' },
330 –  { MODE_MODERATED,  'm' },
331 –  { MODE_NOPRIVMSGS, 'n' },
332 –  { MODE_PRIVATE,    'p' },
333 –  { MODE_SECRET,     's' },
334 –  { MODE_TOPICLIMIT, 't' },
335 –  { MODE_OPERONLY,   'O' },
336 –  { MODE_SSLONLY,    'S' },
337 –  { 0, '\0' }
338 – };
339 –
280   /* channel_modes()
281   *
282   * inputs       - pointer to channel
# Line 348 | Line 288 | static const struct mode_letter
288   * chptr onto buffer mbuf with the parameters in pbuf.
289   */
290   void
291 < channel_modes(struct Channel *chptr, struct Client *client_p,
352 <              char *mbuf, char *pbuf)
291 > channel_modes(struct Channel *chptr, struct Client *client_p, char *mbuf, char *pbuf)
292   {
354 –  int i;
355 –
293    *mbuf++ = '+';
294    *pbuf = '\0';
295  
296 <  for (i = 0; flags[i].mode; ++i)
297 <    if (chptr->mode.mode & flags[i].mode)
298 <      *mbuf++ = flags[i].letter;
296 >  for (const struct mode_letter *tab = chan_modes; tab->mode; ++tab)
297 >    if (chptr->mode.mode & tab->mode)
298 >      *mbuf++ = tab->letter;
299  
300    if (chptr->mode.limit)
301    {
302      *mbuf++ = 'l';
303  
304 <    if (IsMember(client_p, chptr) || IsServer(client_p))
305 <      pbuf += ircsprintf(pbuf, "%d ", chptr->mode.limit);
304 >    if (IsServer(client_p) || HasFlag(client_p, FLAGS_SERVICE) || IsMember(client_p, chptr))
305 >      pbuf += sprintf(pbuf, "%d ", chptr->mode.limit);
306    }
307  
308    if (chptr->mode.key[0])
309    {
310      *mbuf++ = 'k';
311  
312 <    if (*pbuf || IsMember(client_p, chptr) || IsServer(client_p))
313 <      ircsprintf(pbuf, "%s ", chptr->mode.key);
312 >    if (IsServer(client_p) || HasFlag(client_p, FLAGS_SERVICE) || IsMember(client_p, chptr))
313 >      sprintf(pbuf, "%s ", chptr->mode.key);
314    }
315  
316    *mbuf = '\0';
317   }
318  
319   /* fix_key()
320 < *
320 > *
321   * inputs       - pointer to key to clean up
322   * output       - pointer to cleaned up key
323   * side effects - input string is modified
# Line 392 | Line 329 | fix_key(char *arg)
329   {
330    unsigned char *s, *t, c;
331  
332 <  for (s = t = (unsigned char *)arg; (c = *s); s++)
332 >  for (s = t = (unsigned char *)arg; (c = *s); ++s)
333    {
334      c &= 0x7f;
398 –    if (c != ':' && c > ' ' && c != ',')
399 –      *t++ = c;
400 –  }
401 –
402 –  *t = '\0';
403 –  return(arg);
404 – }
405 –
406 – /* fix_key_old()
407 – *
408 – * inputs       - pointer to key to clean up
409 – * output       - pointer to cleaned up key
410 – * side effects - input string is modifed
411 – *
412 – * Here we attempt to be compatible with older non-hybrid servers.
413 – * We can't back down from the ':' issue however.  --Rodder
414 – */
415 – static char *
416 – fix_key_old(char *arg)
417 – {
418 –  unsigned char *s, *t, c;
335  
336 <  for (s = t = (unsigned char *)arg; (c = *s); s++)
421 <  {
422 <    c &= 0x7f;
423 <    if ((c != 0x0a) && (c != ':') && (c != 0x0d) && (c != ','))
336 >    if (c != ':' && c > ' ' && c != ',')
337        *t++ = c;
338    }
339  
340    *t = '\0';
341 <  return(arg);
341 >  return arg;
342   }
343  
344 < /* bitmasks for various error returns that set_channel_mode should only return
345 < * once per call  -orabidoo
346 < */
347 <
435 < #define SM_ERR_NOTS         0x00000001 /* No TS on channel  */
436 < #define SM_ERR_NOOPS        0x00000002 /* No chan ops       */
437 < #define SM_ERR_UNKNOWN      0x00000004
438 < #define SM_ERR_RPL_B        0x00000008
439 < #define SM_ERR_RPL_E        0x00000010
440 < #define SM_ERR_NOTONCHANNEL 0x00000020 /* Not on channel    */
441 < #define SM_ERR_RPL_I        0x00000040
442 < #define SM_ERR_NOTOPER      0x00000080
443 <
444 < /* Now lets do some stuff to keep track of what combinations of
445 < * servers exist...
446 < * Note that the number of combinations doubles each time you add
447 < * something to this list. Each one is only quick if no servers use that
448 < * combination, but if the numbers get too high here MODE will get too
449 < * slow. I suggest if you get more than 7 here, you consider getting rid
450 < * of some and merging or something. If it wasn't for irc+cs we would
451 < * probably not even need to bother about most of these, but unfortunately
452 < * we do. -A1kmm
453 < */
454 <
455 < /* void init_chcap_usage_counts(void)
456 < *
457 < * Inputs       - none
458 < * Output       - none
459 < * Side-effects - Initialises the usage counts to zero. Fills in the
460 < *                chcap_yes and chcap_no combination tables.
344 > /*
345 > * inputs       - pointer to channel
346 > * output       - none
347 > * side effects - clear ban cache
348   */
349   void
350 < init_chcap_usage_counts(void)
350 > clear_ban_cache(struct Channel *chptr)
351   {
352 <  unsigned long m, c, y, n;
352 >  dlink_node *node = NULL;
353  
354 <  memset(chcap_combos, 0, sizeof(chcap_combos));
468 <
469 <  /* For every possible combination */
470 <  for (m = 0; m < NCHCAP_COMBOS; m++)
354 >  DLINK_FOREACH(node, chptr->locmembers.head)
355    {
356 <    /* Check each capab */
357 <    for (c = y = n = 0; c < NCHCAPS; c++)
474 <    {
475 <      if ((m & (1 << c)) == 0)
476 <        n |= channel_capabs[c];
477 <      else
478 <        y |= channel_capabs[c];
479 <    }
480 <    chcap_combos[m].cap_yes = y;
481 <    chcap_combos[m].cap_no  = n;
356 >    struct Membership *ms = node->data;
357 >    ms->flags &= ~(CHFL_BAN_SILENCED|CHFL_BAN_CHECKED);
358    }
359   }
360  
485 – /* void set_chcap_usage_counts(struct Client *serv_p)
486 – * Input: serv_p; The client whose capabs to register.
487 – * Output: none
488 – * Side-effects: Increments the usage counts for the correct capab
489 – *               combination.
490 – */
361   void
362 < set_chcap_usage_counts(struct Client *serv_p)
362 > clear_ban_cache_client(struct Client *client_p)
363   {
364 <  int n;
364 >  dlink_node *node = NULL;
365  
366 <  for (n = 0; n < NCHCAP_COMBOS; n++)
366 >  DLINK_FOREACH(node, client_p->channel.head)
367    {
368 <    if (((serv_p->localClient->caps & chcap_combos[n].cap_yes) ==
369 <         chcap_combos[n].cap_yes) &&
500 <        ((serv_p->localClient->caps & chcap_combos[n].cap_no) == 0))
501 <    {
502 <      chcap_combos[n].count++;
503 <      return;
504 <    }
368 >    struct Membership *ms = node->data;
369 >    ms->flags &= ~(CHFL_BAN_SILENCED|CHFL_BAN_CHECKED);
370    }
506 –
507 –  /* This should be impossible -A1kmm. */
508 –  assert(0);
371   }
372  
373 < /* void set_chcap_usage_counts(struct Client *serv_p)
374 < *
375 < * Inputs       - serv_p; The client whose capabs to register.
514 < * Output       - none
515 < * Side-effects - Decrements the usage counts for the correct capab
516 < *                combination.
373 > /*
374 > * Bitmasks for various error returns that set_channel_mode should only return
375 > * once per call  -orabidoo
376   */
377 < void
519 < unset_chcap_usage_counts(struct Client *serv_p)
377 > enum
378   {
379 <  int n;
380 <
381 <  for (n = 0; n < NCHCAP_COMBOS; n++)
382 <  {
383 <    if ((serv_p->localClient->caps & chcap_combos[n].cap_yes) ==
384 <        chcap_combos[n].cap_yes &&
385 <        (serv_p->localClient->caps & chcap_combos[n].cap_no) == 0)
386 <    {
387 <      /* Hopefully capabs can't change dynamically or anything... */
530 <      assert(chcap_combos[n].count > 0);
531 <      chcap_combos[n].count--;
532 <      return;
533 <    }
534 <  }
535 <
536 <  /* This should be impossible -A1kmm. */
537 <  assert(0);
538 < }
379 >  SM_ERR_NOOPS        = 1 << 0,  /* No chan ops */
380 >  SM_ERR_UNKNOWN      = 1 << 1,
381 >  SM_ERR_RPL_B        = 1 << 2,
382 >  SM_ERR_RPL_E        = 1 << 3,
383 >  SM_ERR_RPL_I        = 1 << 4,
384 >  SM_ERR_NOTONCHANNEL = 1 << 5,  /* Client is not on channel */
385 >  SM_ERR_NOTOPER      = 1 << 6,
386 >  SM_ERR_ONLYSERVER   = 1 << 7
387 > };
388  
389   /* Mode functions handle mode changes for a particular mode... */
390   static void
391 < chm_nosuch(struct Client *client_p, struct Client *source_p,
392 <           struct Channel *chptr, int parc, int *parn,
544 <           char **parv, int *errors, int alev, int dir, char c, void *d,
545 <           const char *chname)
391 > chm_nosuch(struct Client *source_p, struct Channel *chptr, int parc, int *parn,
392 >           char **parv, int *errors, int alev, int dir, char c, unsigned int d)
393   {
394    if (*errors & SM_ERR_UNKNOWN)
395      return;
396  
397    *errors |= SM_ERR_UNKNOWN;
398 <  sendto_one(source_p, form_str(ERR_UNKNOWNMODE), me.name,
552 <             source_p->name, c);
398 >  sendto_one_numeric(source_p, &me, ERR_UNKNOWNMODE, c);
399   }
400  
401   static void
402 < chm_simple(struct Client *client_p, struct Client *source_p, struct Channel *chptr,
403 <           int parc, int *parn, char **parv, int *errors, int alev, int dir,
558 <           char c, void *d, const char *chname)
402 > chm_simple(struct Client *source_p, struct Channel *chptr, int parc, int *parn,
403 >           char **parv, int *errors, int alev, int dir, char c, unsigned int d)
404   {
405 <  long mode_type;
561 <
562 <  mode_type = (long)d;
563 <
564 <  if ((alev < CHACCESS_HALFOP) ||
565 <      ((mode_type == MODE_PRIVATE) && (alev < CHACCESS_CHANOP)))
405 >  if (alev < CHACCESS_HALFOP)
406    {
407      if (!(*errors & SM_ERR_NOOPS))
408 <      sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ?
409 <                                    ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED),
410 <                 me.name, source_p->name, chname);
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 & mode_type)
416 >  if (simple_modes_mask & d)
417      return;
418  
419 <  simple_modes_mask |= mode_type;
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 & mode_type)) */
422 >  /* Apparently, (though no one has ever told the hybrid group directly)
423 >   * admins don't like redundant mode checking. ok. It would have been nice
424 >   * if you had have told us directly. I've left the original code snippets
425 >   * in place.
426 >   *
427 >   * -Dianora
428 >   */
429 >  if (dir == MODE_ADD) /* && !(chptr->mode.mode & d)) */
430    {
431 <    chptr->mode.mode |= mode_type;
431 >    chptr->mode.mode |= d;
432  
433      mode_changes[mode_count].letter = c;
434 <    mode_changes[mode_count].dir = MODE_ADD;
595 <    mode_changes[mode_count].caps = 0;
596 <    mode_changes[mode_count].nocaps = 0;
434 >    mode_changes[mode_count].arg = NULL;
435      mode_changes[mode_count].id = NULL;
436 <    mode_changes[mode_count].mems = ALL_MEMBERS;
599 <    mode_changes[mode_count++].arg = NULL;
436 >    mode_changes[mode_count++].dir = dir;
437    }
438 <  else if ((dir == MODE_DEL)) /* && (chptr->mode.mode & mode_type)) */
438 >  else if (dir == MODE_DEL) /* && (chptr->mode.mode & d)) */
439    {
440      /* setting - */
441  
442 <    chptr->mode.mode &= ~mode_type;
442 >    chptr->mode.mode &= ~d;
443  
444      mode_changes[mode_count].letter = c;
445 <    mode_changes[mode_count].dir = MODE_DEL;
609 <    mode_changes[mode_count].caps = 0;
610 <    mode_changes[mode_count].nocaps = 0;
611 <    mode_changes[mode_count].mems = ALL_MEMBERS;
445 >    mode_changes[mode_count].arg = NULL;
446      mode_changes[mode_count].id = NULL;
447 <    mode_changes[mode_count++].arg = NULL;
447 >    mode_changes[mode_count++].dir = dir;
448    }
449   }
450  
451   static void
452 < chm_operonly(struct Client *client_p, struct Client *source_p, struct Channel *chptr,
453 <            int parc, int *parn, char **parv, int *errors, int alev, int dir,
620 <            char c, void *d, const char *chname)
452 > chm_registered(struct Client *source_p, struct Channel *chptr, int parc, int *parn,
453 >               char **parv, int *errors, int alev, int dir, char c, unsigned int d)
454   {
455 <  long mode_type;
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;
463 >  }
464 >
465 >  /* 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)) */
480 >  {
481 >    chptr->mode.mode |= d;
482 >
483 >    mode_changes[mode_count].letter = c;
484 >    mode_changes[mode_count].arg = NULL;
485 >    mode_changes[mode_count].id = NULL;
486 >    mode_changes[mode_count++].dir = dir;
487 >  }
488 >  else if (dir == MODE_DEL) /* && (chptr->mode.mode & d)) */
489 >  {
490 >    /* setting - */
491  
492 <  mode_type = (long)d;
492 >    chptr->mode.mode &= ~d;
493  
494 <  if ((alev < CHACCESS_HALFOP) ||
495 <      ((mode_type == MODE_PRIVATE) && (alev < CHACCESS_CHANOP)))
494 >    mode_changes[mode_count].letter = c;
495 >    mode_changes[mode_count].arg = NULL;
496 >    mode_changes[mode_count].id = NULL;
497 >    mode_changes[mode_count++].dir = dir;
498 >  }
499 > }
500 >
501 > 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)
506    {
507      if (!(*errors & SM_ERR_NOOPS))
508 <      sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ?
509 <                                    ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED),
510 <                 me.name, source_p->name, chname);
508 >      sendto_one_numeric(source_p, &me,
509 >                         alev == CHACCESS_NOTONCHAN ? ERR_NOTONCHANNEL :
510 >                         ERR_CHANOPRIVSNEEDED, chptr->name);
511 >
512      *errors |= SM_ERR_NOOPS;
513      return;
514    }
515 <  else if (MyClient(source_p) && !IsOper(source_p))
515 >
516 >  if (MyClient(source_p) && !HasUMode(source_p, UMODE_OPER))
517    {
518      if (!(*errors & SM_ERR_NOTOPER))
519 <    {
640 <      if (alev == CHACCESS_NOTONCHAN)
641 <        sendto_one(source_p, form_str(ERR_NOTONCHANNEL),
642 <                   me.name, source_p->name, chname);
643 <      else
644 <        sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
645 <                   me.name, source_p->name);
646 <    }
519 >      sendto_one_numeric(source_p, &me, ERR_NOPRIVILEGES);
520  
521      *errors |= SM_ERR_NOTOPER;
522      return;
523    }
524  
525    /* If have already dealt with this simple mode, ignore it */
526 <  if (simple_modes_mask & mode_type)
526 >  if (simple_modes_mask & d)
527      return;
528  
529 <  simple_modes_mask |= mode_type;
529 >  simple_modes_mask |= d;
530  
531 <  if ((dir == MODE_ADD)) /* && !(chptr->mode.mode & mode_type)) */
531 >  if (dir == MODE_ADD) /* && !(chptr->mode.mode & d)) */
532    {
533 <    chptr->mode.mode |= mode_type;
533 >    chptr->mode.mode |= d;
534  
535      mode_changes[mode_count].letter = c;
536 <    mode_changes[mode_count].dir = MODE_ADD;
664 <    mode_changes[mode_count].caps = 0;
665 <    mode_changes[mode_count].nocaps = 0;
536 >    mode_changes[mode_count].arg = NULL;
537      mode_changes[mode_count].id = NULL;
538 <    mode_changes[mode_count].mems = ALL_MEMBERS;
668 <    mode_changes[mode_count].mems = ALL_MEMBERS;
669 <    mode_changes[mode_count++].arg = NULL;
538 >    mode_changes[mode_count++].dir = dir;
539    }
540 <  else if ((dir == MODE_DEL)) /* && (chptr->mode.mode & mode_type)) */
540 >  else if (dir == MODE_DEL) /* && (chptr->mode.mode & d)) */
541    {
542      /* setting - */
543  
544 <    chptr->mode.mode &= ~mode_type;
544 >    chptr->mode.mode &= ~d;
545  
546      mode_changes[mode_count].letter = c;
547 <    mode_changes[mode_count].dir = MODE_DEL;
679 <    mode_changes[mode_count].caps = 0;
680 <    mode_changes[mode_count].nocaps = 0;
681 <    mode_changes[mode_count].mems = ALL_MEMBERS;
547 >    mode_changes[mode_count].arg = NULL;
548      mode_changes[mode_count].id = NULL;
549 <    mode_changes[mode_count++].arg = NULL;
549 >    mode_changes[mode_count++].dir = dir;
550    }
551   }
552  
553   static void
554 < chm_ban(struct Client *client_p, struct Client *source_p,
555 <        struct Channel *chptr, int parc, int *parn,
690 <        char **parv, int *errors, int alev, int dir, char c, void *d,
691 <        const char *chname)
554 > chm_ban(struct Client *source_p, struct Channel *chptr, int parc, int *parn,
555 >        char **parv, int *errors, int alev, int dir, char c, unsigned int d)
556   {
557    char *mask = NULL;
558  
559    if (dir == MODE_QUERY || parc <= *parn)
560    {
561 <    dlink_node *ptr = NULL;
561 >    dlink_node *node = NULL;
562  
563      if (*errors & SM_ERR_RPL_B)
564        return;
565  
566      *errors |= SM_ERR_RPL_B;
567  
568 <    DLINK_FOREACH(ptr, chptr->banlist.head)
568 >    DLINK_FOREACH(node, chptr->banlist.head)
569      {
570 <      const struct Ban *banptr = ptr->data;
571 <      sendto_one(client_p, form_str(RPL_BANLIST),
572 <                 me.name, client_p->name, chname,
573 <                 banptr->name, banptr->username, banptr->host,
710 <                 banptr->who, banptr->when);
570 >      const struct Ban *banptr = node->data;
571 >      sendto_one_numeric(source_p, &me, RPL_BANLIST, chptr->name,
572 >                         banptr->name, banptr->user, banptr->host,
573 >                         banptr->who, banptr->when);
574      }
575  
576 <    sendto_one(source_p, form_str(RPL_ENDOFBANLIST), me.name,
714 <               source_p->name, chname);
576 >    sendto_one_numeric(source_p, &me, RPL_ENDOFBANLIST, chptr->name);
577      return;
578    }
579  
580    if (alev < CHACCESS_HALFOP)
581    {
582      if (!(*errors & SM_ERR_NOOPS))
583 <      sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ?
584 <                                    ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED),
585 <                 me.name, source_p->name, chname);
583 >      sendto_one_numeric(source_p, &me,
584 >                         alev == CHACCESS_NOTONCHAN ? ERR_NOTONCHANNEL :
585 >                         ERR_CHANOPRIVSNEEDED, chptr->name);
586      *errors |= SM_ERR_NOOPS;
587      return;
588    }
# Line 730 | Line 592 | chm_ban(struct Client *client_p, struct
592  
593    mask = nuh_mask[*parn];
594    memcpy(mask, parv[*parn], sizeof(nuh_mask[*parn]));
595 <  ++*parn;
595 >  ++(*parn);
596  
597 <  if (IsServer(client_p))
597 >  if (!MyConnect(source_p))
598      if (strchr(mask, ' '))
599        return;
600  
# Line 751 | Line 613 | chm_ban(struct Client *client_p, struct
613    }
614  
615    mode_changes[mode_count].letter = c;
616 <  mode_changes[mode_count].dir = dir;
755 <  mode_changes[mode_count].caps = 0;
756 <  mode_changes[mode_count].nocaps = 0;
757 <  mode_changes[mode_count].mems = ALL_MEMBERS;
616 >  mode_changes[mode_count].arg = mask;
617    mode_changes[mode_count].id = NULL;
618 <  mode_changes[mode_count++].arg = mask;
618 >  mode_changes[mode_count++].dir = dir;
619   }
620  
621   static void
622 < chm_except(struct Client *client_p, struct Client *source_p,
623 <           struct Channel *chptr, int parc, int *parn,
765 <           char **parv, int *errors, int alev, int dir, char c, void *d,
766 <           const char *chname)
622 > chm_except(struct Client *source_p, struct Channel *chptr, int parc, int *parn,
623 >           char **parv, int *errors, int alev, int dir, char c, unsigned int d)
624   {
625    char *mask = NULL;
626  
627 <  /* if we have +e disabled, allow local clients to do anything but
771 <   * set the mode.  This prevents the abuse of +e when just a few
772 <   * servers support it. --fl
773 <   */
774 <  if (!ConfigChannel.use_except && MyClient(source_p) &&
775 <      ((dir == MODE_ADD) && (parc > *parn)))
627 >  if (dir == MODE_QUERY || parc <= *parn)
628    {
629 +    dlink_node *node = NULL;
630 +
631      if (*errors & SM_ERR_RPL_E)
632        return;
633  
634      *errors |= SM_ERR_RPL_E;
635 +
636 +    DLINK_FOREACH(node, chptr->exceptlist.head)
637 +    {
638 +      const struct Ban *banptr = node->data;
639 +
640 +      sendto_one_numeric(source_p, &me, RPL_EXCEPTLIST, chptr->name,
641 +                         banptr->name, banptr->user, banptr->host,
642 +                         banptr->who, banptr->when);
643 +    }
644 +
645 +    sendto_one_numeric(source_p, &me, RPL_ENDOFEXCEPTLIST, chptr->name);
646      return;
647    }
648  
649    if (alev < CHACCESS_HALFOP)
650    {
651      if (!(*errors & SM_ERR_NOOPS))
652 <      sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ?
653 <                                    ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED),
654 <                 me.name, source_p->name, chname);
652 >      sendto_one_numeric(source_p, &me,
653 >                         alev == CHACCESS_NOTONCHAN ? ERR_NOTONCHANNEL :
654 >                         ERR_CHANOPRIVSNEEDED, chptr->name);
655      *errors |= SM_ERR_NOOPS;
656      return;
657    }
658  
794 –  if (dir == MODE_QUERY || parc <= *parn)
795 –  {
796 –    dlink_node *ptr = NULL;
797 –
798 –    if (*errors & SM_ERR_RPL_E)
799 –      return;
800 –
801 –    *errors |= SM_ERR_RPL_E;
802 –
803 –    DLINK_FOREACH(ptr, chptr->exceptlist.head)
804 –    {
805 –      const struct Ban *banptr = ptr->data;
806 –      sendto_one(client_p, form_str(RPL_EXCEPTLIST),
807 –                 me.name, client_p->name, chname,
808 –                 banptr->name, banptr->username, banptr->host,
809 –                 banptr->who, banptr->when);
810 –    }
811 –
812 –    sendto_one(source_p, form_str(RPL_ENDOFEXCEPTLIST), me.name,
813 –               source_p->name, chname);
814 –    return;
815 –  }
816 –
659    if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
660      return;
661  
662    mask = nuh_mask[*parn];
663    memcpy(mask, parv[*parn], sizeof(nuh_mask[*parn]));
664 <  ++*parn;
664 >  ++(*parn);
665  
666 <  if (IsServer(client_p))
666 >  if (!MyConnect(source_p))
667      if (strchr(mask, ' '))
668        return;
669  
# Line 840 | Line 682 | chm_except(struct Client *client_p, stru
682    }
683  
684    mode_changes[mode_count].letter = c;
685 <  mode_changes[mode_count].dir = dir;
844 <  mode_changes[mode_count].caps = CAP_EX;
845 <  mode_changes[mode_count].nocaps = 0;
846 <
847 <  if (ConfigChannel.use_except)
848 <    mode_changes[mode_count].mems = ONLY_CHANOPS;
849 <  else
850 <    mode_changes[mode_count].mems = ONLY_SERVERS;
851 <
685 >  mode_changes[mode_count].arg = mask;
686    mode_changes[mode_count].id = NULL;
687 <  mode_changes[mode_count++].arg = mask;
687 >  mode_changes[mode_count++].dir = dir;
688   }
689  
690   static void
691 < chm_invex(struct Client *client_p, struct Client *source_p,
692 <          struct Channel *chptr, int parc, int *parn,
859 <          char **parv, int *errors, int alev, int dir, char c, void *d,
860 <          const char *chname)
691 > chm_invex(struct Client *source_p, struct Channel *chptr, int parc, int *parn,
692 >          char **parv, int *errors, int alev, int dir, char c, unsigned int d)
693   {
694    char *mask = NULL;
695  
864 –  /* if we have +I disabled, allow local clients to do anything but
865 –   * set the mode.  This prevents the abuse of +I when just a few
866 –   * servers support it --fl
867 –   */
868 –  if (!ConfigChannel.use_invex && MyClient(source_p) &&
869 –      (dir == MODE_ADD) && (parc > *parn))
870 –  {
871 –    if (*errors & SM_ERR_RPL_I)
872 –      return;
873 –    
874 –    *errors |= SM_ERR_RPL_I;
875 –    return;
876 –  }
877 –
878 –  if (alev < CHACCESS_HALFOP)
879 –  {
880 –    if (!(*errors & SM_ERR_NOOPS))
881 –      sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ?
882 –                                    ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED),
883 –                 me.name, source_p->name, chname);
884 –    *errors |= SM_ERR_NOOPS;
885 –    return;
886 –  }
887 –
696    if (dir == MODE_QUERY || parc <= *parn)
697    {
698 <    dlink_node *ptr = NULL;
698 >    dlink_node *node = NULL;
699  
700      if (*errors & SM_ERR_RPL_I)
701        return;
702  
703      *errors |= SM_ERR_RPL_I;
704  
705 <    DLINK_FOREACH(ptr, chptr->invexlist.head)
705 >    DLINK_FOREACH(node, chptr->invexlist.head)
706      {
707 <      const struct Ban *banptr = ptr->data;
708 <      sendto_one(client_p, form_str(RPL_INVITELIST), me.name,
709 <                 client_p->name, chname,
710 <                 banptr->name, banptr->username, banptr->host,
711 <                 banptr->who, banptr->when);
707 >      const struct Ban *banptr = node->data;
708 >
709 >      sendto_one_numeric(source_p, &me, RPL_INVEXLIST, chptr->name,
710 >                         banptr->name, banptr->user, banptr->host,
711 >                         banptr->who, banptr->when);
712      }
713  
714 <    sendto_one(source_p, form_str(RPL_ENDOFINVITELIST), me.name,
715 <               source_p->name, chname);
714 >    sendto_one_numeric(source_p, &me, RPL_ENDOFINVEXLIST, chptr->name);
715 >    return;
716 >  }
717 >
718 >  if (alev < CHACCESS_HALFOP)
719 >  {
720 >    if (!(*errors & SM_ERR_NOOPS))
721 >      sendto_one_numeric(source_p, &me,
722 >                         alev == CHACCESS_NOTONCHAN ? ERR_NOTONCHANNEL :
723 >                         ERR_CHANOPRIVSNEEDED, chptr->name);
724 >    *errors |= SM_ERR_NOOPS;
725      return;
726    }
727  
# Line 913 | Line 730 | chm_invex(struct Client *client_p, struc
730  
731    mask = nuh_mask[*parn];
732    memcpy(mask, parv[*parn], sizeof(nuh_mask[*parn]));
733 <  ++*parn;
733 >  ++(*parn);
734  
735 <  if (IsServer(client_p))
735 >  if (!MyConnect(source_p))
736      if (strchr(mask, ' '))
737        return;
738  
# Line 934 | Line 751 | chm_invex(struct Client *client_p, struc
751    }
752  
753    mode_changes[mode_count].letter = c;
754 <  mode_changes[mode_count].dir = dir;
938 <  mode_changes[mode_count].caps = CAP_IE;
939 <  mode_changes[mode_count].nocaps = 0;
940 <
941 <  if (ConfigChannel.use_invex)
942 <    mode_changes[mode_count].mems = ONLY_CHANOPS;
943 <  else
944 <    mode_changes[mode_count].mems = ONLY_SERVERS;
945 <
754 >  mode_changes[mode_count].arg = mask;
755    mode_changes[mode_count].id = NULL;
756 <  mode_changes[mode_count++].arg = mask;
948 < }
949 <
950 < /*
951 < * inputs       - pointer to channel
952 < * output       - none
953 < * side effects - clear ban cache
954 < */
955 < void
956 < clear_ban_cache(struct Channel *chptr)
957 < {
958 <  dlink_node *ptr = NULL;
959 <
960 <  DLINK_FOREACH(ptr, chptr->members.head)
961 <  {
962 <    struct Membership *ms = ptr->data;
963 <
964 <    if (MyConnect(ms->client_p))
965 <      ms->flags &= ~(CHFL_BAN_SILENCED|CHFL_BAN_CHECKED);
966 <  }
967 < }
968 <
969 < void
970 < clear_ban_cache_client(struct Client *client_p)
971 < {
972 <  dlink_node *ptr = NULL;
973 <
974 <  DLINK_FOREACH(ptr, client_p->channel.head)
975 <  {
976 <    struct Membership *ms = ptr->data;
977 <    ms->flags &= ~(CHFL_BAN_SILENCED|CHFL_BAN_CHECKED);
978 <  }
756 >  mode_changes[mode_count++].dir = dir;
757   }
758  
759   static void
760 < chm_op(struct Client *client_p, struct Client *source_p,
761 <       struct Channel *chptr, int parc, int *parn,
984 <       char **parv, int *errors, int alev, int dir, char c, void *d,
985 <       const char *chname)
760 > chm_voice(struct Client *source_p, struct Channel *chptr, int parc, int *parn,
761 >          char **parv, int *errors, int alev, int dir, char c, unsigned int d)
762   {
763 <  char *opnick;
988 <  struct Client *targ_p;
763 >  struct Client *target_p;
764    struct Membership *member;
990 –  int caps = 0;
765  
766 <  if (alev < CHACCESS_CHANOP)
766 >  if (alev < CHACCESS_HALFOP)
767    {
768      if (!(*errors & SM_ERR_NOOPS))
769 <      sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ?
770 <                                    ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED),
771 <                 me.name, source_p->name, chname);
769 >      sendto_one_numeric(source_p, &me,
770 >                         alev == CHACCESS_NOTONCHAN ? ERR_NOTONCHANNEL :
771 >                         ERR_CHANOPRIVSNEEDED, chptr->name);
772      *errors |= SM_ERR_NOOPS;
773      return;
774    }
775  
776 <  if ((dir == MODE_QUERY) || (parc <= *parn))
776 >  if (dir == MODE_QUERY || parc <= *parn)
777      return;
778  
779 <  opnick = parv[(*parn)++];
779 >  if ((target_p = find_chasing(source_p, parv[(*parn)++])) == NULL)
780 >    return;  /* find_chasing sends ERR_NOSUCHNICK */
781  
782 <  if ((targ_p = find_chasing(client_p, source_p, opnick, NULL)) == NULL)
1008 <    return;
1009 <  if (!IsClient(targ_p))
1010 <    return;
1011 <
1012 <  if ((member = find_channel_link(targ_p, chptr)) == NULL)
782 >  if ((member = find_channel_link(target_p, chptr)) == NULL)
783    {
784      if (!(*errors & SM_ERR_NOTONCHANNEL))
785 <      sendto_one(source_p, form_str(ERR_USERNOTINCHANNEL),
1016 <                 me.name, source_p->name, opnick, chname);
785 >      sendto_one_numeric(source_p, &me, ERR_USERNOTINCHANNEL, target_p->name, chptr->name);
786      *errors |= SM_ERR_NOTONCHANNEL;
787      return;
788    }
# Line 1022 | Line 791 | chm_op(struct Client *client_p, struct C
791      return;
792  
793    /* no redundant mode changes */
794 <  if (dir == MODE_ADD &&  has_member_flags(member, CHFL_CHANOP))
794 >  if (dir == MODE_ADD &&  has_member_flags(member, CHFL_VOICE))
795      return;
796 <  if (dir == MODE_DEL && !has_member_flags(member, CHFL_CHANOP))
1028 <  {
1029 < #ifdef HALFOPS
1030 <    if (has_member_flags(member, CHFL_HALFOP))
1031 <    {
1032 <      --*parn;
1033 <      chm_hop(client_p, source_p, chptr, parc, parn, parv, errors, alev,
1034 <              dir, c, d, chname);
1035 <    }
1036 < #endif
796 >  if (dir == MODE_DEL && !has_member_flags(member, CHFL_VOICE))
797      return;
1038 –  }
1039 –
1040 – #ifdef HALFOPS
1041 –  if (dir == MODE_ADD && has_member_flags(member, CHFL_HALFOP))
1042 –  {
1043 –    /* promoting from % to @ is visible only to CAP_HOPS servers */
1044 –    mode_changes[mode_count].letter = 'h';
1045 –    mode_changes[mode_count].dir = MODE_DEL;
1046 –    mode_changes[mode_count].caps = caps = CAP_HOPS;
1047 –    mode_changes[mode_count].nocaps = 0;
1048 –    mode_changes[mode_count].mems = ALL_MEMBERS;
1049 –    mode_changes[mode_count].id = NULL;
1050 –    mode_changes[mode_count].arg = targ_p->name;
1051 –    mode_changes[mode_count++].client = targ_p;
1052 –  }
1053 – #endif
798  
799 <  mode_changes[mode_count].letter = 'o';
800 <  mode_changes[mode_count].dir = dir;
801 <  mode_changes[mode_count].caps = caps;
802 <  mode_changes[mode_count].nocaps = 0;
1059 <  mode_changes[mode_count].mems = ALL_MEMBERS;
1060 <  mode_changes[mode_count].id = targ_p->id;
1061 <  mode_changes[mode_count].arg = targ_p->name;
1062 <  mode_changes[mode_count++].client = targ_p;
799 >  mode_changes[mode_count].letter = c;
800 >  mode_changes[mode_count].arg = target_p->name;
801 >  mode_changes[mode_count].id = target_p->id;
802 >  mode_changes[mode_count++].dir = dir;
803  
804    if (dir == MODE_ADD)
805 <  {
1066 <    AddMemberFlag(member, CHFL_CHANOP);
1067 <    DelMemberFlag(member, CHFL_DEOPPED | CHFL_HALFOP);
1068 <  }
805 >    AddMemberFlag(member, CHFL_VOICE);
806    else
807 <    DelMemberFlag(member, CHFL_CHANOP);
807 >    DelMemberFlag(member, CHFL_VOICE);
808   }
809  
1073 – #ifdef HALFOPS
810   static void
811 < chm_hop(struct Client *client_p, struct Client *source_p,
812 <       struct Channel *chptr, int parc, int *parn,
1077 <       char **parv, int *errors, int alev, int dir, char c, void *d,
1078 <       const char *chname)
811 > chm_hop(struct Client *source_p, struct Channel *chptr, int parc, int *parn,
812 >        char **parv, int *errors, int alev, int dir, char c, unsigned int d)
813   {
814 <  char *opnick;
1081 <  struct Client *targ_p;
814 >  struct Client *target_p;
815    struct Membership *member;
816  
817 <  /* *sigh* - dont allow halfops to set +/-h, they could fully control a
1085 <   * channel if there were no ops - it doesnt solve anything.. MODE_PRIVATE
1086 <   * when used with MODE_SECRET is paranoid - cant use +p
1087 <   *
1088 <   * it needs to be optional per channel - but not via +p, that or remove
1089 <   * paranoid.. -- fl_
1090 <   *
1091 <   * +p means paranoid, it is useless for anything else on modern IRC, as
1092 <   * list isn't really usable. If you want to have a private channel these
1093 <   * days, you set it +s. Halfops can no longer remove simple modes when
1094 <   * +p is set (although they can set +p) so it is safe to use this to
1095 <   * control whether they can (de)halfop...
1096 <   */
1097 <  if (alev <
1098 <      ((chptr->mode.mode & MODE_PRIVATE) ? CHACCESS_CHANOP : CHACCESS_HALFOP))
817 >  if (alev < CHACCESS_CHANOP)
818    {
819      if (!(*errors & SM_ERR_NOOPS))
820 <      sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ?
821 <                                    ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED),
822 <                 me.name, source_p->name, chname);
820 >      sendto_one_numeric(source_p, &me,
821 >                         alev == CHACCESS_NOTONCHAN ? ERR_NOTONCHANNEL :
822 >                         ERR_CHANOPRIVSNEEDED, chptr->name);
823      *errors |= SM_ERR_NOOPS;
824      return;
825    }
826  
827 <  if ((dir == MODE_QUERY) || (parc <= *parn))
827 >  if (dir == MODE_QUERY || parc <= *parn)
828      return;
829  
830 <  opnick = parv[(*parn)++];
830 >  if ((target_p = find_chasing(source_p, parv[(*parn)++])) == NULL)
831 >    return;  /* find_chasing sends ERR_NOSUCHNICK */
832  
833 <  if ((targ_p = find_chasing(client_p, source_p, opnick, NULL)) == NULL)
1114 <    return;
1115 <  if (!IsClient(targ_p))
1116 <    return;
1117 <
1118 <  if ((member = find_channel_link(targ_p, chptr)) == NULL)
833 >  if ((member = find_channel_link(target_p, chptr)) == NULL)
834    {
835      if (!(*errors & SM_ERR_NOTONCHANNEL))
836 <      sendto_one(source_p, form_str(ERR_USERNOTINCHANNEL),
1122 <                 me.name, source_p->name, opnick, chname);
836 >      sendto_one_numeric(source_p, &me, ERR_USERNOTINCHANNEL, target_p->name, chptr->name);
837      *errors |= SM_ERR_NOTONCHANNEL;
838      return;
839    }
# Line 1128 | Line 842 | chm_hop(struct Client *client_p, struct
842      return;
843  
844    /* no redundant mode changes */
845 <  if (dir == MODE_ADD &&  has_member_flags(member, CHFL_HALFOP | CHFL_CHANOP))
845 >  if (dir == MODE_ADD &&  has_member_flags(member, CHFL_HALFOP))
846      return;
847    if (dir == MODE_DEL && !has_member_flags(member, CHFL_HALFOP))
848      return;
849  
850 <  mode_changes[mode_count].letter = 'h';
851 <  mode_changes[mode_count].dir = dir;
852 <  mode_changes[mode_count].caps = CAP_HOPS;
853 <  mode_changes[mode_count].nocaps = 0;
1140 <  mode_changes[mode_count].mems = ALL_MEMBERS;
1141 <  mode_changes[mode_count].id = targ_p->id;
1142 <  mode_changes[mode_count].arg = targ_p->name;
1143 <  mode_changes[mode_count++].client = targ_p;
1144 <
1145 <  mode_changes[mode_count].letter = 'o';
1146 <  mode_changes[mode_count].dir = dir;
1147 <  mode_changes[mode_count].caps = 0;
1148 <  mode_changes[mode_count].nocaps = CAP_HOPS;
1149 <  mode_changes[mode_count].mems = ONLY_SERVERS;
1150 <  mode_changes[mode_count].id = targ_p->id;
1151 <  mode_changes[mode_count].arg = targ_p->name;
1152 <  mode_changes[mode_count++].client = targ_p;
850 >  mode_changes[mode_count].letter = c;
851 >  mode_changes[mode_count].arg = target_p->name;
852 >  mode_changes[mode_count].id = target_p->id;
853 >  mode_changes[mode_count++].dir = dir;
854  
855    if (dir == MODE_ADD)
1155 –  {
856      AddMemberFlag(member, CHFL_HALFOP);
1157 –    DelMemberFlag(member, CHFL_DEOPPED);
1158 –  }
857    else
858      DelMemberFlag(member, CHFL_HALFOP);
859   }
1162 – #endif
860  
861   static void
862 < chm_voice(struct Client *client_p, struct Client *source_p,
863 <          struct Channel *chptr, int parc, int *parn,
1167 <          char **parv, int *errors, int alev, int dir, char c, void *d,
1168 <          const char *chname)
862 > chm_op(struct Client *source_p, struct Channel *chptr, int parc, int *parn,
863 >       char **parv, int *errors, int alev, int dir, char c, unsigned int d)
864   {
865 <  char *opnick;
1171 <  struct Client *targ_p;
865 >  struct Client *target_p;
866    struct Membership *member;
867  
868 <  if (alev < CHACCESS_HALFOP)
868 >  if (alev < CHACCESS_CHANOP)
869    {
870      if (!(*errors & SM_ERR_NOOPS))
871 <      sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ?
872 <                                    ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED),
873 <                 me.name, source_p->name, chname);
871 >      sendto_one_numeric(source_p, &me,
872 >                         alev == CHACCESS_NOTONCHAN ? ERR_NOTONCHANNEL :
873 >                         ERR_CHANOPRIVSNEEDED, chptr->name);
874      *errors |= SM_ERR_NOOPS;
875      return;
876    }
877  
878 <  if ((dir == MODE_QUERY) || parc <= *parn)
878 >  if (dir == MODE_QUERY || parc <= *parn)
879      return;
880  
881 <  opnick = parv[(*parn)++];
881 >  if ((target_p = find_chasing(source_p, parv[(*parn)++])) == NULL)
882 >    return;  /* find_chasing sends ERR_NOSUCHNICK */
883  
884 <  if ((targ_p = find_chasing(client_p, source_p, opnick, NULL)) == NULL)
1190 <    return;
1191 <  if (!IsClient(targ_p))
1192 <    return;
1193 <
1194 <  if ((member = find_channel_link(targ_p, chptr)) == NULL)
884 >  if ((member = find_channel_link(target_p, chptr)) == NULL)
885    {
886      if (!(*errors & SM_ERR_NOTONCHANNEL))
887 <      sendto_one(source_p, form_str(ERR_USERNOTINCHANNEL),
1198 <                 me.name, source_p->name, opnick, chname);
887 >      sendto_one_numeric(source_p, &me, ERR_USERNOTINCHANNEL, target_p->name, chptr->name);
888      *errors |= SM_ERR_NOTONCHANNEL;
889      return;
890    }
# Line 1204 | Line 893 | chm_voice(struct Client *client_p, struc
893      return;
894  
895    /* no redundant mode changes */
896 <  if (dir == MODE_ADD &&  has_member_flags(member, CHFL_VOICE))
896 >  if (dir == MODE_ADD &&  has_member_flags(member, CHFL_CHANOP))
897      return;
898 <  if (dir == MODE_DEL && !has_member_flags(member, CHFL_VOICE))
898 >  if (dir == MODE_DEL && !has_member_flags(member, CHFL_CHANOP))
899      return;
900  
901 <  mode_changes[mode_count].letter = 'v';
902 <  mode_changes[mode_count].dir = dir;
903 <  mode_changes[mode_count].caps = 0;
904 <  mode_changes[mode_count].nocaps = 0;
1216 <  mode_changes[mode_count].mems = ALL_MEMBERS;
1217 <  mode_changes[mode_count].id = targ_p->id;
1218 <  mode_changes[mode_count].arg = targ_p->name;
1219 <  mode_changes[mode_count++].client = targ_p;
901 >  mode_changes[mode_count].letter = c;
902 >  mode_changes[mode_count].arg = target_p->name;
903 >  mode_changes[mode_count].id = target_p->id;
904 >  mode_changes[mode_count++].dir = dir;
905  
906    if (dir == MODE_ADD)
907 <    AddMemberFlag(member, CHFL_VOICE);
907 >    AddMemberFlag(member, CHFL_CHANOP);
908    else
909 <    DelMemberFlag(member, CHFL_VOICE);
909 >    DelMemberFlag(member, CHFL_CHANOP);
910   }
911  
912   static void
913 < chm_limit(struct Client *client_p, struct Client *source_p,
914 <          struct Channel *chptr, int parc, int *parn,
1230 <          char **parv, int *errors, int alev, int dir, char c, void *d,
1231 <          const char *chname)
913 > chm_limit(struct Client *source_p, struct Channel *chptr, int parc, int *parn,
914 >          char **parv, int *errors, int alev, int dir, char c, unsigned int d)
915   {
916 <  int i, limit;
1234 <  char *lstr;
916 >  int limit = 0;
917  
918    if (alev < CHACCESS_HALFOP)
919    {
920      if (!(*errors & SM_ERR_NOOPS))
921 <      sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ?
922 <                                    ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED),
923 <                 me.name, source_p->name, chname);
921 >      sendto_one_numeric(source_p, &me,
922 >                         alev == CHACCESS_NOTONCHAN ? ERR_NOTONCHANNEL :
923 >                         ERR_CHANOPRIVSNEEDED, chptr->name);
924      *errors |= SM_ERR_NOOPS;
925      return;
926    }
# Line 1246 | Line 928 | chm_limit(struct Client *client_p, struc
928    if (dir == MODE_QUERY)
929      return;
930  
931 <  if ((dir == MODE_ADD) && parc > *parn)
931 >  if (dir == MODE_ADD && parc > *parn)
932    {
933 <    lstr = parv[(*parn)++];
933 >    char *lstr = parv[(*parn)++];
934  
935 <    if ((limit = atoi(lstr)) <= 0)
935 >    if (EmptyString(lstr) || (limit = atoi(lstr)) <= 0)
936        return;
937  
938 <    ircsprintf(lstr, "%d", limit);
938 >    sprintf(lstr, "%d", limit);
939  
940 <    /* if somebody sets MODE #channel +ll 1 2, accept latter --fl */
941 <    for (i = 0; i < mode_count; i++)
1260 <    {
940 >    /* If somebody sets MODE #channel +ll 1 2, accept latter --fl */
941 >    for (unsigned int i = 0; i < mode_count; ++i)
942        if (mode_changes[i].letter == c && mode_changes[i].dir == MODE_ADD)
943          mode_changes[i].letter = 0;
1263 –    }
944  
945      mode_changes[mode_count].letter = c;
946 <    mode_changes[mode_count].dir = MODE_ADD;
1267 <    mode_changes[mode_count].caps = 0;
1268 <    mode_changes[mode_count].nocaps = 0;
1269 <    mode_changes[mode_count].mems = ALL_MEMBERS;
946 >    mode_changes[mode_count].arg = lstr;
947      mode_changes[mode_count].id = NULL;
948 <    mode_changes[mode_count++].arg = lstr;
948 >    mode_changes[mode_count++].dir = dir;
949  
950      chptr->mode.limit = limit;
951    }
# Line 1280 | Line 957 | chm_limit(struct Client *client_p, struc
957      chptr->mode.limit = 0;
958  
959      mode_changes[mode_count].letter = c;
960 <    mode_changes[mode_count].dir = MODE_DEL;
1284 <    mode_changes[mode_count].caps = 0;
1285 <    mode_changes[mode_count].nocaps = 0;
1286 <    mode_changes[mode_count].mems = ALL_MEMBERS;
960 >    mode_changes[mode_count].arg = NULL;
961      mode_changes[mode_count].id = NULL;
962 <    mode_changes[mode_count++].arg = NULL;
962 >    mode_changes[mode_count++].dir = dir;
963    }
964   }
965  
966   static void
967 < chm_key(struct Client *client_p, struct Client *source_p,
968 <        struct Channel *chptr, int parc, int *parn,
1295 <        char **parv, int *errors, int alev, int dir, char c, void *d,
1296 <        const char *chname)
967 > chm_key(struct Client *source_p, struct Channel *chptr, int parc, int *parn,
968 >        char **parv, int *errors, int alev, int dir, char c, unsigned int d)
969   {
1298 –  int i;
1299 –  char *key;
1300 –
970    if (alev < CHACCESS_HALFOP)
971    {
972      if (!(*errors & SM_ERR_NOOPS))
973 <      sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ?
974 <                                    ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED),
975 <                 me.name, source_p->name, chname);
973 >      sendto_one_numeric(source_p, &me,
974 >                         alev == CHACCESS_NOTONCHAN ? ERR_NOTONCHANNEL :
975 >                         ERR_CHANOPRIVSNEEDED, chptr->name);
976      *errors |= SM_ERR_NOOPS;
977      return;
978    }
# Line 1311 | Line 980 | chm_key(struct Client *client_p, struct
980    if (dir == MODE_QUERY)
981      return;
982  
983 <  if ((dir == MODE_ADD) && parc > *parn)
983 >  if (dir == MODE_ADD && parc > *parn)
984    {
985 <    key = parv[(*parn)++];
985 >    char *key = fix_key(parv[(*parn)++]);
986  
987 <    if (MyClient(source_p))
1319 <      fix_key(key);
1320 <    else
1321 <      fix_key_old(key);
1322 <
1323 <    if (*key == '\0')
987 >    if (EmptyString(key))
988        return;
989  
990      assert(key[0] != ' ');
991      strlcpy(chptr->mode.key, key, sizeof(chptr->mode.key));
992  
993 <    /* if somebody does MODE #channel +kk a b, accept latter --fl */
994 <    for (i = 0; i < mode_count; i++)
1331 <    {
993 >    /* If somebody does MODE #channel +kk a b, accept latter --fl */
994 >    for (unsigned int i = 0; i < mode_count; ++i)
995        if (mode_changes[i].letter == c && mode_changes[i].dir == MODE_ADD)
996          mode_changes[i].letter = 0;
1334 –    }
997  
998      mode_changes[mode_count].letter = c;
999 <    mode_changes[mode_count].dir = MODE_ADD;
1338 <    mode_changes[mode_count].caps = 0;
1339 <    mode_changes[mode_count].nocaps = 0;
1340 <    mode_changes[mode_count].mems = ALL_MEMBERS;
999 >    mode_changes[mode_count].arg = chptr->mode.key;
1000      mode_changes[mode_count].id = NULL;
1001 <    mode_changes[mode_count++].arg = chptr->mode.key;
1001 >    mode_changes[mode_count++].dir = dir;
1002    }
1003    else if (dir == MODE_DEL)
1004    {
1005      if (parc > *parn)
1006 <      (*parn)++;
1006 >      ++(*parn);
1007  
1008      if (chptr->mode.key[0] == '\0')
1009        return;
# Line 1352 | Line 1011 | chm_key(struct Client *client_p, struct
1011      chptr->mode.key[0] = '\0';
1012  
1013      mode_changes[mode_count].letter = c;
1014 <    mode_changes[mode_count].dir = MODE_DEL;
1356 <    mode_changes[mode_count].caps = 0;
1357 <    mode_changes[mode_count].nocaps = 0;
1358 <    mode_changes[mode_count].mems = ALL_MEMBERS;
1014 >    mode_changes[mode_count].arg = "*";
1015      mode_changes[mode_count].id = NULL;
1016 <    mode_changes[mode_count++].arg = "*";
1016 >    mode_changes[mode_count++].dir = dir;
1017    }
1018   }
1019  
1020 < struct ChannelMode
1365 < {
1366 <  void (*func) (struct Client *client_p, struct Client *source_p,
1367 <                struct Channel *chptr, int parc, int *parn, char **parv,
1368 <                int *errors, int alev, int dir, char c, void *d,
1369 <                const char *chname);
1370 <  void *d;
1371 < };
1372 <
1373 < static struct ChannelMode ModeTable[255] =
1020 > const struct ChannelMode ModeTable[256] =
1021   {
1022 <  {chm_nosuch, NULL},
1023 <  {chm_nosuch, NULL},                             /* A */
1024 <  {chm_nosuch, NULL},                             /* B */
1025 <  {chm_nosuch, NULL},                             /* C */
1026 <  {chm_nosuch, NULL},                             /* D */
1027 <  {chm_nosuch, NULL},                             /* E */
1028 <  {chm_nosuch, NULL},                             /* F */
1029 <  {chm_nosuch, NULL},                             /* G */
1030 <  {chm_nosuch, NULL},                             /* H */
1031 <  {chm_invex, NULL},                              /* I */
1032 <  {chm_nosuch, NULL},                             /* J */
1033 <  {chm_nosuch, NULL},                             /* K */
1034 <  {chm_nosuch, NULL},                             /* L */
1035 <  {chm_nosuch, NULL},                             /* M */
1036 <  {chm_nosuch, NULL},                             /* N */
1037 <  {chm_operonly, (void *) MODE_OPERONLY},         /* O */
1038 <  {chm_nosuch, NULL},                             /* P */
1039 <  {chm_nosuch, NULL},                             /* Q */
1040 <  {chm_nosuch, NULL},                             /* R */
1041 <  {chm_simple, (void *) MODE_SSLONLY},            /* S */
1042 <  {chm_nosuch, NULL},                             /* T */
1043 <  {chm_nosuch, NULL},                             /* U */
1044 <  {chm_nosuch, NULL},                             /* V */
1045 <  {chm_nosuch, NULL},                             /* W */
1046 <  {chm_nosuch, NULL},                             /* X */
1047 <  {chm_nosuch, NULL},                             /* Y */
1048 <  {chm_nosuch, NULL},                             /* Z */
1049 <  {chm_nosuch, NULL},
1050 <  {chm_nosuch, NULL},
1051 <  {chm_nosuch, NULL},
1052 <  {chm_nosuch, NULL},
1053 <  {chm_nosuch, NULL},
1054 <  {chm_nosuch, NULL},
1055 <  {chm_nosuch, NULL},                             /* a */
1056 <  {chm_ban, NULL},                                /* b */
1057 <  {chm_nosuch, NULL},                             /* c */
1058 <  {chm_nosuch, NULL},                             /* d */
1059 <  {chm_except, NULL},                             /* e */
1060 <  {chm_nosuch, NULL},                             /* f */
1061 <  {chm_nosuch, NULL},                             /* g */
1062 < #ifdef HALFOPS
1063 <  {chm_hop, NULL},                                /* h */
1064 < #else
1065 <  {chm_nosuch, NULL},                             /* h */
1066 < #endif
1067 <  {chm_simple, (void *) MODE_INVITEONLY},         /* i */
1068 <  {chm_nosuch, NULL},                             /* j */
1069 <  {chm_key, NULL},                                /* k */
1070 <  {chm_limit, NULL},                              /* l */
1071 <  {chm_simple, (void *) MODE_MODERATED},          /* m */
1072 <  {chm_simple, (void *) MODE_NOPRIVMSGS},         /* n */
1073 <  {chm_op, NULL},                                 /* o */
1074 <  {chm_simple, (void *) MODE_PRIVATE},            /* p */
1075 <  {chm_nosuch, NULL},                             /* q */
1076 <  {chm_nosuch, NULL},                             /* r */
1077 <  {chm_simple, (void *) MODE_SECRET},             /* s */
1078 <  {chm_simple, (void *) MODE_TOPICLIMIT},         /* t */
1079 <  {chm_nosuch, NULL},                             /* u */
1080 <  {chm_voice, NULL},                              /* v */
1081 <  {chm_nosuch, NULL},                             /* w */
1082 <  {chm_nosuch, NULL},                             /* x */
1083 <  {chm_nosuch, NULL},                             /* y */
1084 <  {chm_nosuch, NULL},                             /* z */
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  
1280   /* get_channel_access()
# Line 1446 | Line 1286 | static struct ChannelMode ModeTable[255]
1286   * side effects - NONE
1287   */
1288   static int
1289 < get_channel_access(struct Client *source_p, struct Membership *member)
1289 > get_channel_access(const struct Client *source_p,
1290 >                   const struct Membership *member)
1291   {
1292    /* Let hacked servers in for now... */
1293    if (!MyClient(source_p))
1294 <    return CHACCESS_CHANOP;
1294 >    return CHACCESS_REMOTE;
1295  
1296 <  if (member == NULL)
1296 >  if (!member)
1297      return CHACCESS_NOTONCHAN;
1298  
1299 <  /* just to be sure.. */
1299 >  /* Just to be sure.. */
1300    assert(source_p == member->client_p);
1301  
1302    if (has_member_flags(member, CHFL_CHANOP))
1303      return CHACCESS_CHANOP;
1304  
1464 – #ifdef HALFOPS
1305    if (has_member_flags(member, CHFL_HALFOP))
1306      return CHACCESS_HALFOP;
1467 – #endif
1307  
1308    return CHACCESS_PEON;
1309   }
1310  
1311 < /* void send_cap_mode_changes(struct Client *client_p,
1312 < *                        struct Client *source_p,
1474 < *                        struct Channel *chptr, int cap, int nocap)
1475 < * Input: The client sending(client_p), the source client(source_p),
1311 > /* send_mode_changes_server()
1312 > * Input: the source client(source_p),
1313   *        the channel to send mode changes for(chptr)
1314   * Output: None.
1315 < * Side-effects: Sends the appropriate mode changes to capable servers.
1315 > * Side-effects: Sends the appropriate mode changes to servers.
1316   *
1480 – * send_cap_mode_changes() will loop the server list itself, because
1481 – * at this point in time we have 4 capabs for channels, CAP_IE, CAP_EX,
1482 – * and a server could support any number of these..
1483 – * so we make the modebufs per server, tailoring them to each servers
1484 – * specific demand.  Its not very pretty, but its one of the few realistic
1485 – * ways to handle having this many capabs for channel modes.. --fl_
1486 – *
1487 – * Reverted back to my original design, except that we now keep a count
1488 – * of the number of servers which each combination as an optimisation, so
1489 – * the capabs combinations which are not needed are not worked out. -A1kmm
1317   */
1491 – /* rewritten to ensure parabuf < MODEBUFLEN -db */
1492 –
1318   static void
1319 < send_cap_mode_changes(struct Client *client_p, struct Client *source_p,
1495 <                      struct Channel *chptr, unsigned int cap, unsigned int nocap)
1319 > send_mode_changes_server(struct Client *source_p, struct Channel *chptr)
1320   {
1321 <  int i, mbl, pbl, arglen, nc, mc;
1322 <  int len;
1499 <  const char *arg = NULL;
1500 <  char *parptr;
1321 >  int mbl = 0, pbl = 0, arglen = 0, nc = 0, mc = 0;
1322 >  int len = 0;
1323    int dir = MODE_QUERY;
1324 <
1325 <  mc = 0;
1504 <  nc = 0;
1505 <  pbl = 0;
1324 >  const char *arg = NULL;
1325 >  char *parptr = NULL;
1326  
1327    parabuf[0] = '\0';
1328    parptr = parabuf;
1329  
1330 <  if ((cap & CAP_TS6) && source_p->id[0] != '\0')
1331 <    mbl = ircsprintf(modebuf, ":%s TMODE %lu %s ", source_p->id,
1512 <                     (unsigned long)chptr->channelts, chptr->chname);
1513 <  else
1514 <    mbl = ircsprintf(modebuf, ":%s MODE %s ", source_p->name,
1515 <                     chptr->chname);
1330 >  mbl = snprintf(modebuf, sizeof(modebuf), ":%s TMODE %lu %s ", source_p->id,
1331 >                 (unsigned long)chptr->channelts, chptr->name);
1332  
1333 <  /* loop the list of - modes we have */
1334 <  for (i = 0; i < mode_count; i++)
1333 >  /* Loop the list of modes we have */
1334 >  for (unsigned i = 0; i < mode_count; ++i)
1335    {
1336 <    /* if they dont support the cap we need, or they do support a cap they
1521 <     * cant have, then dont add it to the modebuf.. that way they wont see
1522 <     * the mode
1523 <     */
1524 <    if ((mode_changes[i].letter == 0) ||
1525 <        ((cap & mode_changes[i].caps) != mode_changes[i].caps)
1526 <        || ((nocap & mode_changes[i].nocaps) != mode_changes[i].nocaps))
1336 >    if (mode_changes[i].letter == 0)
1337        continue;
1338  
1339 <    arg = "";
1530 <
1531 <    if ((cap & CAP_TS6) && mode_changes[i].id)
1339 >    if (mode_changes[i].id)
1340        arg = mode_changes[i].id;
1341 <    if (*arg == '\0')
1341 >    else
1342        arg = mode_changes[i].arg;
1343  
1344 <    /* if we're creeping past the buf size, we need to send it and make
1537 <     * another line for the other modes
1538 <     * XXX - this could give away server topology with uids being
1539 <     * different lengths, but not much we can do, except possibly break
1540 <     * them as if they were the longest of the nick or uid at all times,
1541 <     * which even then won't work as we don't always know the uid -A1kmm.
1542 <     */
1543 <    if (arg != NULL)
1344 >    if (arg)
1345        arglen = strlen(arg);
1346      else
1347        arglen = 0;
1348  
1349 +    /*
1350 +     * If we're creeping past the buf size, we need to send it and make
1351 +     * another line for the other modes
1352 +     */
1353      if ((mc == MAXMODEPARAMS) ||
1354          ((arglen + mbl + pbl + 2) > IRCD_BUFSIZE) ||
1355          (pbl + arglen + BAN_FUDGE) >= MODEBUFLEN)
1356      {
1357 <      if (nc != 0)
1358 <        sendto_server(client_p, chptr, cap, nocap,
1359 <                      "%s %s",
1555 <                      modebuf, parabuf);
1357 >      if (nc)
1358 >        sendto_server(source_p, NOCAPS, NOCAPS, "%s %s", modebuf, parabuf);
1359 >
1360        nc = 0;
1361        mc = 0;
1362  
1363 <      if ((cap & CAP_TS6) && source_p->id[0] != '\0')
1364 <        mbl = ircsprintf(modebuf, ":%s MODE %s ", source_p->id,
1561 <                         chptr->chname);
1562 <      else
1563 <        mbl = ircsprintf(modebuf, ":%s MODE %s ", source_p->name,
1564 <                         chptr->chname);
1363 >      mbl = snprintf(modebuf, sizeof(modebuf), ":%s TMODE %lu %s ", source_p->id,
1364 >                     (unsigned long)chptr->channelts, chptr->name);
1365  
1366        pbl = 0;
1367        parabuf[0] = '\0';
# Line 1577 | Line 1377 | send_cap_mode_changes(struct Client *cli
1377  
1378      modebuf[mbl++] = mode_changes[i].letter;
1379      modebuf[mbl] = '\0';
1380 <    nc++;
1380 >    ++nc;
1381  
1382 <    if (arg != NULL)
1382 >    if (arg)
1383      {
1384 <      len = ircsprintf(parptr, "%s ", arg);
1384 >      len = sprintf(parptr, "%s ", arg);
1385        pbl += len;
1386        parptr += len;
1387 <      mc++;
1387 >      ++mc;
1388      }
1389    }
1390  
1391    if (pbl && parabuf[pbl - 1] == ' ')
1392 <    parabuf[pbl - 1] = 0;
1392 >    parabuf[pbl - 1] = '\0';
1393  
1394 <  if (nc != 0)
1395 <    sendto_server(client_p, chptr, cap, nocap,
1596 <                  "%s %s", modebuf, parabuf);
1394 >  if (nc)
1395 >    sendto_server(source_p, NOCAPS, NOCAPS, "%s %s", modebuf, parabuf);
1396   }
1397  
1398   /* void send_mode_changes(struct Client *client_p,
# Line 1608 | Line 1407 | send_cap_mode_changes(struct Client *cli
1407   */
1408   /* ensure parabuf < MODEBUFLEN -db */
1409   static void
1410 < send_mode_changes(struct Client *client_p, struct Client *source_p,
1612 <                  struct Channel *chptr, char *chname)
1410 > send_mode_changes(struct Client *source_p, struct Channel *chptr)
1411   {
1412 <  int i, mbl, pbl, arglen, nc, mc;
1413 <  int len;
1616 <  const char *arg = NULL;
1617 <  char *parptr;
1412 >  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;
1417  
1418 <  /* bail out if we have nothing to do... */
1418 >  /* Bail out if we have nothing to do... */
1419    if (!mode_count)
1420      return;
1421  
1422    if (IsServer(source_p))
1423 <    mbl = ircsprintf(modebuf, ":%s MODE %s ", (IsHidden(source_p) ||
1424 <                     ConfigServerHide.hide_servers) ?
1425 <                     me.name : source_p->name, chname);
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 = ircsprintf(modebuf, ":%s!%s@%s MODE %s ", source_p->name,
1428 <                     source_p->username, source_p->host, chname);
1631 <
1632 <  mc = 0;
1633 <  nc = 0;
1634 <  pbl = 0;
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 (i = 0; i < mode_count; i++)
1433 >  for (unsigned int i = 0; i < mode_count; ++i)
1434    {
1435 <    if (mode_changes[i].letter == 0 ||
1642 <        mode_changes[i].mems == NON_CHANOPS ||
1643 <        mode_changes[i].mems == ONLY_SERVERS)
1435 >    if (mode_changes[i].letter == 0)
1436        continue;
1437  
1438      arg = mode_changes[i].arg;
1439 <    if (arg != NULL)
1439 >    if (arg)
1440        arglen = strlen(arg);
1441      else
1442        arglen = 0;
1443  
1444 <    if ((mc == MAXMODEPARAMS)  ||
1444 >    if ((mc == MAXMODEPARAMS) ||
1445          ((arglen + mbl + pbl + 2) > IRCD_BUFSIZE) ||
1446 <        ((arglen + pbl + BAN_FUDGE) >= MODEBUFLEN))
1446 >        ((arglen + pbl + BAN_FUDGE) >= MODEBUFLEN))
1447      {
1448        if (mbl && modebuf[mbl - 1] == '-')
1449          modebuf[mbl - 1] = '\0';
1450  
1451 <      if (nc != 0)
1452 <        sendto_channel_local(ALL_MEMBERS, NO, chptr, "%s %s", modebuf, parabuf);
1451 >      if (nc)
1452 >        sendto_channel_local(0, chptr, "%s %s", modebuf, parabuf);
1453  
1454        nc = 0;
1455        mc = 0;
1456  
1457        if (IsServer(source_p))
1458 <        mbl = ircsprintf(modebuf, ":%s MODE %s ", me.name, chname);
1458 >        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 = ircsprintf(modebuf, ":%s!%s@%s MODE %s ", source_p->name,
1463 <                         source_p->username, source_p->host, chname);
1462 >        mbl = snprintf(modebuf, sizeof(modebuf), ":%s!%s@%s MODE %s ", source_p->name,
1463 >                       source_p->username, source_p->host, chptr->name);
1464  
1465        pbl = 0;
1466        parabuf[0] = '\0';
# Line 1682 | Line 1476 | send_mode_changes(struct Client *client_
1476  
1477      modebuf[mbl++] = mode_changes[i].letter;
1478      modebuf[mbl] = '\0';
1479 <    nc++;
1479 >    ++nc;
1480  
1481 <    if (arg != NULL)
1481 >    if (arg)
1482      {
1483 <      len = ircsprintf(parptr, "%s ", arg);
1483 >      len = sprintf(parptr, "%s ", arg);
1484        pbl += len;
1485        parptr += len;
1486 <      mc++;
1486 >      ++mc;
1487      }
1488    }
1489  
1490    if (pbl && parabuf[pbl - 1] == ' ')
1491 <    parabuf[pbl - 1] = 0;
1491 >    parabuf[pbl - 1] = '\0';
1492  
1493 <  if (nc != 0)
1494 <    sendto_channel_local(ALL_MEMBERS, NO, chptr, "%s %s", modebuf, parabuf);
1493 >  if (nc)
1494 >    sendto_channel_local(0, chptr, "%s %s", modebuf, parabuf);
1495  
1496 <  nc = 0;
1497 <  mc = 0;
1496 >  send_mode_changes_server(source_p, chptr);
1497 > }
1498  
1499 <  /* Now send to servers... */
1500 <  for (i = 0; i < NCHCAP_COMBOS; i++)
1707 <    if (chcap_combos[i].count != 0)
1708 <      send_cap_mode_changes(client_p, source_p, chptr,
1709 <                            chcap_combos[i].cap_yes,
1710 <                            chcap_combos[i].cap_no);
1711 < }
1712 <
1713 < /* void set_channel_mode(struct Client *client_p, struct Client *source_p,
1714 < *               struct Channel *chptr, int parc, char **parv,
1715 < *               char *chname)
1716 < * Input: The client we received this from, the client this originated
1499 > /*
1500 > * Input: The the client this originated
1501   *        from, the channel, the parameter count starting at the modes,
1502   *        the parameters, the channel name.
1503   * Output: None.
# Line 1722 | Line 1506 | send_mode_changes(struct Client *client_
1506   *               clients.
1507   */
1508   void
1509 < set_channel_mode(struct Client *client_p, struct Client *source_p, struct Channel *chptr,
1510 <                 struct Membership *member, int parc, char *parv[], char *chname)
1509 > set_channel_mode(struct Client *source_p, struct Channel *chptr,
1510 >                 struct Membership *member, int parc, char *parv[])
1511   {
1512    int dir = MODE_ADD;
1513    int parn = 1;
1514 <  int alevel, errors = 0;
1731 <  char *ml = parv[0], c;
1732 <  int table_position;
1514 >  int alevel = 0, errors = 0;
1515  
1516    mode_count = 0;
1517    mode_limit = 0;
# Line 1737 | Line 1519 | set_channel_mode(struct Client *client_p
1519  
1520    alevel = get_channel_access(source_p, member);
1521  
1522 <  for (; (c = *ml) != '\0'; ml++)
1522 >  for (const char *ml = parv[0]; *ml; ++ml)
1523    {
1524 < #if 0
1743 <    if(mode_count > 20)
1744 <      break;
1745 < #endif
1746 <    switch (c)
1524 >    switch (*ml)
1525      {
1526        case '+':
1527          dir = MODE_ADD;
# Line 1755 | Line 1533 | set_channel_mode(struct Client *client_p
1533          dir = MODE_QUERY;
1534          break;
1535        default:
1536 <        if (c < 'A' || c > 'z')
1537 <          table_position = 0;
1538 <        else
1539 <          table_position = c - 'A' + 1;
1540 <        ModeTable[table_position].func(client_p, source_p, chptr,
1763 <                                       parc, &parn,
1764 <                                       parv, &errors, alevel, dir, c,
1765 <                                       ModeTable[table_position].d,
1766 <                                       chname);
1536 >      {
1537 >        const struct ChannelMode *tptr = &ModeTable[(unsigned char)*ml];
1538 >
1539 >        tptr->func(source_p, chptr, parc, &parn, parv,
1540 >                   &errors, alevel, dir, *ml, tptr->d);
1541          break;
1542 +      }
1543      }
1544    }
1545  
1546 <  send_mode_changes(client_p, source_p, chptr, chname);
1546 >  send_mode_changes(source_p, chptr);
1547   }

Diff Legend

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