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/src/channel_mode.c (file contents), Revision 30 by adx, Sun Oct 2 20:03:27 2005 UTC vs.
ircd-hybrid/trunk/src/channel_mode.c (file contents), Revision 5031 by michael, Sat Dec 13 15:13:16 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: channel_mode.c,v 7.165 2005/09/18 12:43:45 michael Exp $
20 > */
21 >
22 > /*! \file channel_mode.c
23 > * \brief Controls modes on channels.
24 > * \version $Id$
25   */
26  
27   #include "stdinc.h"
28 < #include "tools.h"
28 > #include "list.h"
29   #include "channel.h"
30   #include "channel_mode.h"
31   #include "client.h"
32 < #include "common.h"
33 < #include "hash.h"
32 > #include "conf.h"
33 > #include "hostmask.h"
34   #include "irc_string.h"
33 – #include "sprintf_irc.h"
35   #include "ircd.h"
35 – #include "list.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 <
47 < /* some small utility functions */
48 < static char *check_string(char *);
49 < static char *fix_key(char *);
50 < static char *fix_key_old(char *);
51 < static void chm_nosuch(struct Client *, struct Client *,
52 <                       struct Channel *, int, int *, char **, int *, int,
53 <                       int, char, void *, const char *);
54 < static void chm_simple(struct Client *, struct Client *, struct Channel *,
55 <                       int, int *, char **, int *, int, int, char, void *,
56 <                       const char *);
57 < static void chm_limit(struct Client *, struct Client *, struct Channel *,
58 <                      int, int *, char **, int *, int, int, char, void *,
59 <                      const char *);
60 < static void chm_key(struct Client *, struct Client *, struct Channel *,
61 <                    int, int *, char **, int *, int, int, char, void *,
62 <                    const char *);
63 < static void chm_op(struct Client *, struct Client *, struct Channel *, int,
64 <                   int *, char **, int *, int, int, char, void *,
65 <                   const char *);
66 < #ifdef HALFOPS
67 < static void chm_hop(struct Client *, struct Client *, struct Channel *, int,
68 <                   int *, char **, int *, int, int, char, void *,
69 <                   const char *);
70 < #endif
71 < static void chm_voice(struct Client *, struct Client *, struct Channel *,
72 <                      int, int *, char **, int *, int, int, char, void *,
73 <                      const char *);
74 < static void chm_ban(struct Client *, struct Client *, struct Channel *, int,
75 <                    int *, char **, int *, int, int, char, void *,
76 <                    const char *);
77 < static void chm_except(struct Client *, struct Client *, struct Channel *,
78 <                       int, int *, char **, int *, int, int, char, void *,
79 <                       const char *);
80 < static void chm_invex(struct Client *, struct Client *, struct Channel *,
81 <                      int, int *, char **, int *, int, int, char, void *,
82 <                      const char *);
83 < static void send_cap_mode_changes(struct Client *, struct Client *,
84 <                                  struct Channel *, int, int);
85 < static void send_mode_changes(struct Client *, struct Client *,
86 <                              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
90 < #define NCHCAPS         (sizeof(channel_capabs)/sizeof(int))
91 < #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 < static int channel_capabs[] = { CAP_EX, CAP_IE, CAP_TS6 };
55 < static struct ChCapCombo chcap_combos[NCHCAP_COMBOS];
56 < 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  
105 – /* XXX check_string is propably not longer required in add_id and del_id */
74   /* check_string()
75   *
76   * inputs       - string to check
# Line 115 | Line 83 | extern BlockHeap *ban_heap;
83   static char *
84   check_string(char *s)
85   {
86 <  char *str = s;
86 >  char *const str = s;
87    static char star[] = "*";
88  
89 <  if (EmptyString(s))
90 <    return (star);
89 >  if (EmptyString(str))
90 >    return star;
91  
92    for (; *s; ++s)
93    {
# Line 130 | 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;
115 <  dlink_node *ban;
114 >  dlink_list *list = NULL;
115 >  dlink_node *node = NULL;
116 >  struct Ban *ban = NULL;
117    size_t len = 0;
118 <  struct Ban *actualBan;
119 <  unsigned int num_mask;
120 <  char *name = NULL, *user = NULL, *host = NULL;
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),
163 <                 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  
136      collapse(banid);
137    }
138  
139 <  split_nuh(check_string(banid), &name, &user, &host);
139 >  nuh.nuhmask  = check_string(banid);
140 >  nuh.nickptr  = name;
141 >  nuh.userptr  = user;
142 >  nuh.hostptr  = host;
143 >
144 >  nuh.nicksize = sizeof(name);
145 >  nuh.usersize = sizeof(user);
146 >  nuh.hostsize = sizeof(host);
147 >
148 >  split_nuh(&nuh);
149  
150    /*
151 <   * Assemble a n!u@h and print it back to banid for sending
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 = snprintf(banid, IRCD_BUFSIZE, "%s!%s@%s", name, user, host);
155  
156    switch (type)
157    {
158      case CHFL_BAN:
159        list = &chptr->banlist;
160 <      clear_ban_cache(chptr);
160 >      clear_ban_cache_channel(chptr);
161        break;
162      case CHFL_EXCEPTION:
163        list = &chptr->exceptlist;
164 <      clear_ban_cache(chptr);
164 >      clear_ban_cache_channel(chptr);
165        break;
166      case CHFL_INVEX:
167        list = &chptr->invexlist;
# Line 193 | 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 <    actualBan = ban->data;
177 <    if (!irccmp(actualBan->name, name) &&
178 <        !irccmp(actualBan->username, user) &&
179 <        !irccmp(actualBan->host, host))
180 <    {
203 <      MyFree(name);
204 <      MyFree(user);
205 <      MyFree(host);
176 >    ban = node->data;
177 >
178 >    if (!irccmp(ban->name, name) &&
179 >        !irccmp(ban->user, user) &&
180 >        !irccmp(ban->host, host))
181        return 0;
207 –    }
182    }
183  
184 <  actualBan = BlockHeapAlloc(ban_heap);
185 <  actualBan->when = CurrentTime;
186 <  actualBan->name = name;
187 <  actualBan->username = user;
188 <  actualBan->host = host;
189 <  actualBan->len = len-2; /* -2 for @ and ! */
184 >  ban = mp_pool_get(ban_pool);
185 >  ban->name = xstrdup(name);
186 >  ban->user = xstrdup(user);
187 >  ban->host = xstrdup(host);
188 >  ban->when = CurrentTime;
189 >  ban->len = len - 2;  /* -2 for ! + @ */
190 >  ban->type = parse_netmask(host, &ban->addr, &ban->bits);
191  
192    if (IsClient(client_p))
193    {
194 <    actualBan->who =
195 <      MyMalloc(strlen(client_p->name) +
196 <               strlen(client_p->username) +
197 <               strlen(client_p->host) + 3);
198 <    ircsprintf(actualBan->who, "%s!%s@%s",
224 <               client_p->name, client_p->username, client_p->host);
194 >    ban->who = MyCalloc(strlen(client_p->name) +
195 >                        strlen(client_p->username) +
196 >                        strlen(client_p->host) + 3);
197 >    sprintf(ban->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 +    ban->who = xstrdup(me.name);
202    else
203 <    DupString(actualBan->who, client_p->name);
203 >    ban->who = xstrdup(client_p->name);
204  
205 <  dlinkAdd(actualBan, &actualBan->node, list);
205 >  dlinkAdd(ban, &ban->node, list);
206  
207    return 1;
208   }
# Line 239 | 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 = NULL, *user = NULL, *host = NULL;
224 <
225 <  if (banid == NULL)
226 <    return 0;
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 >  assert(banid);
228 >
229 >  nuh.nuhmask  = check_string(banid);
230 >  nuh.nickptr  = name;
231 >  nuh.userptr  = user;
232 >  nuh.hostptr  = host;
233 >
234 >  nuh.nicksize = sizeof(name);
235 >  nuh.usersize = sizeof(user);
236 >  nuh.hostsize = sizeof(host);
237  
238 <  split_nuh(check_string(banid), &name, &user, &host);
238 >  split_nuh(&nuh);
239  
240    /*
241 <   * Assemble a n!u@h and print it back to banid for sending
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 >  snprintf(banid, IRCD_BUFSIZE, "%s!%s@%s", name, user, host);
245  
246    switch (type)
247    {
248      case CHFL_BAN:
249        list = &chptr->banlist;
250 <      clear_ban_cache(chptr);
250 >      clear_ban_cache_channel(chptr);
251        break;
252      case CHFL_EXCEPTION:
253        list = &chptr->exceptlist;
254 <      clear_ban_cache(chptr);
254 >      clear_ban_cache_channel(chptr);
255        break;
256      case CHFL_INVEX:
257        list = &chptr->invexlist;
258        break;
259      default:
260 <      sendto_realops_flags(UMODE_ALL, L_ALL,
261 <                           "del_id() called with unknown ban type %d!", type);
276 <      MyFree(name);
277 <      MyFree(user);
278 <      MyFree(host);
279 <      return(0);
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 *ban = node->data;
267  
268 <    if (!irccmp(name, banptr->name) &&
269 <        !irccmp(user, banptr->username) &&
270 <        !irccmp(host, banptr->host))
268 >    if (!irccmp(name, ban->name) &&
269 >        !irccmp(user, ban->user) &&
270 >        !irccmp(host, ban->host))
271      {
272 <      remove_ban(banptr, list);
291 <      MyFree(name);
292 <      MyFree(user);
293 <      MyFree(host);
272 >      remove_ban(ban, list);
273        return 1;
274      }
275    }
276  
298 –  MyFree(name);
299 –  MyFree(user);
300 –  MyFree(host);
277    return 0;
278   }
279  
304 – static const struct mode_letter
305 – {
306 –  const unsigned int mode;
307 –  const unsigned char letter;
308 – } flags[] = {
309 –  { MODE_INVITEONLY, 'i' },
310 –  { MODE_MODERATED,  'm' },
311 –  { MODE_NOPRIVMSGS, 'n' },
312 –  { MODE_PRIVATE,    'p' },
313 –  { MODE_SECRET,     's' },
314 –  { MODE_TOPICLIMIT, 't' },
315 –  { 0, '\0' }
316 – };
317 –
280   /* channel_modes()
281   *
282   * inputs       - pointer to channel
# Line 326 | 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,
330 <              char *mbuf, char *pbuf)
291 > channel_modes(struct Channel *chptr, struct Client *client_p, char *mbuf, char *pbuf)
292   {
332 –  int i;
333 –
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 370 | 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;
335 +
336      if (c != ':' && c > ' ' && c != ',')
337        *t++ = c;
338    }
339  
340    *t = '\0';
341 <  return(arg);
341 >  return arg;
342   }
343  
344 < /* fix_key_old()
345 < *
346 < * inputs       - pointer to key to clean up
347 < * output       - pointer to cleaned up key
388 < * side effects - input string is modifed
389 < *
390 < * Here we attempt to be compatible with older non-hybrid servers.
391 < * We can't back down from the ':' issue however.  --Rodder
344 > /*
345 > * inputs       - pointer to channel
346 > * output       - none
347 > * side effects - clear ban cache
348   */
349 < static char *
350 < fix_key_old(char *arg)
349 > void
350 > clear_ban_cache_channel(struct Channel *chptr)
351   {
352 <  unsigned char *s, *t, c;
352 >  dlink_node *node = NULL;
353  
354 <  for (s = t = (unsigned char *)arg; (c = *s); s++)
354 >  DLINK_FOREACH(node, chptr->locmembers.head)
355    {
356 <    c &= 0x7f;
357 <    if ((c != 0x0a) && (c != ':') && (c != 0x0d) && (c != ','))
402 <      *t++ = c;
356 >    struct Membership *member = node->data;
357 >    member->flags &= ~(CHFL_BAN_SILENCED|CHFL_BAN_CHECKED);
358    }
404 –
405 –  *t = '\0';
406 –  return(arg);
359   }
360  
409 – /* bitmasks for various error returns that set_channel_mode should only return
410 – * once per call  -orabidoo
411 – */
412 –
413 – #define SM_ERR_NOTS         0x00000001 /* No TS on channel  */
414 – #define SM_ERR_NOOPS        0x00000002 /* No chan ops       */
415 – #define SM_ERR_UNKNOWN      0x00000004
416 – #define SM_ERR_RPL_B        0x00000008
417 – #define SM_ERR_RPL_E        0x00000010
418 – #define SM_ERR_NOTONCHANNEL 0x00000020 /* Not on channel    */
419 – #define SM_ERR_RPL_I        0x00000040
420 –
421 – /* Now lets do some stuff to keep track of what combinations of
422 – * servers exist...
423 – * Note that the number of combinations doubles each time you add
424 – * something to this list. Each one is only quick if no servers use that
425 – * combination, but if the numbers get too high here MODE will get too
426 – * slow. I suggest if you get more than 7 here, you consider getting rid
427 – * of some and merging or something. If it wasn't for irc+cs we would
428 – * probably not even need to bother about most of these, but unfortunately
429 – * we do. -A1kmm
430 – */
431 –
432 – /* void init_chcap_usage_counts(void)
433 – *
434 – * Inputs       - none
435 – * Output       - none
436 – * Side-effects - Initialises the usage counts to zero. Fills in the
437 – *                chcap_yes and chcap_no combination tables.
438 – */
361   void
362 < init_chcap_usage_counts(void)
362 > clear_ban_cache_client(struct Client *client_p)
363   {
364 <  unsigned long m, c, y, n;
364 >  dlink_node *node = NULL;
365  
366 <  memset(chcap_combos, 0, sizeof(chcap_combos));
445 <
446 <  /* For every possible combination */
447 <  for (m = 0; m < NCHCAP_COMBOS; m++)
366 >  DLINK_FOREACH(node, client_p->channel.head)
367    {
368 <    /* Check each capab */
369 <    for (c = y = n = 0; c < NCHCAPS; c++)
451 <    {
452 <      if ((m & (1 << c)) == 0)
453 <        n |= channel_capabs[c];
454 <      else
455 <        y |= channel_capabs[c];
456 <    }
457 <    chcap_combos[m].cap_yes = y;
458 <    chcap_combos[m].cap_no  = n;
368 >    struct Membership *member = node->data;
369 >    member->flags &= ~(CHFL_BAN_SILENCED|CHFL_BAN_CHECKED);
370    }
371   }
372  
373 < /* void set_chcap_usage_counts(struct Client *serv_p)
374 < * Input: serv_p; The client whose capabs to register.
375 < * Output: none
465 < * Side-effects: Increments the usage counts for the correct capab
466 < *               combination.
373 > /*
374 > * Bitmasks for various error returns that set_channel_mode should only return
375 > * once per call  -orabidoo
376   */
377 < void
469 < set_chcap_usage_counts(struct Client *serv_p)
377 > enum
378   {
379 <  int n;
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 <  for (n = 0; n < NCHCAP_COMBOS; n++)
390 <  {
391 <    if (((serv_p->localClient->caps & chcap_combos[n].cap_yes) ==
392 <         chcap_combos[n].cap_yes) &&
393 <        ((serv_p->localClient->caps & chcap_combos[n].cap_no) == 0))
394 <    {
395 <      chcap_combos[n].count++;
480 <      return;
481 <    }
482 <  }
389 > /* Mode functions handle mode changes for a particular mode... */
390 > static void
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 <  /* This should be impossible -A1kmm. */
398 <  assert(0);
397 >  *errors |= SM_ERR_UNKNOWN;
398 >  sendto_one_numeric(source_p, &me, ERR_UNKNOWNMODE, c);
399   }
400  
401 < /* void set_chcap_usage_counts(struct Client *serv_p)
402 < *
403 < * Inputs       - serv_p; The client whose capabs to register.
491 < * Output       - none
492 < * Side-effects - Decrements the usage counts for the correct capab
493 < *                combination.
494 < */
495 < void
496 < unset_chcap_usage_counts(struct Client *serv_p)
401 > static void
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 <  int n;
405 >  if (alev < CHACCESS_HALFOP)
406 >  {
407 >    if (!(*errors & SM_ERR_NOOPS))
408 >      sendto_one_numeric(source_p, &me,
409 >                         alev == CHACCESS_NOTONCHAN ? ERR_NOTONCHANNEL :
410 >                         ERR_CHANOPRIVSNEEDED, chptr->name);
411 >
412 >    *errors |= SM_ERR_NOOPS;
413 >    return;
414 >  }
415  
416 <  for (n = 0; n < NCHCAP_COMBOS; n++)
416 >  /* If have already dealt with this simple mode, ignore it */
417 >  if (simple_modes_mask & d)
418 >    return;
419 >
420 >  simple_modes_mask |= d;
421 >
422 >  /* setting + */
423 >  /* Apparently, (though no one has ever told the hybrid group directly)
424 >   * admins don't like redundant mode checking. ok. It would have been nice
425 >   * if you had have told us directly. I've left the original code snippets
426 >   * in place.
427 >   *
428 >   * -Dianora
429 >   */
430 >  if (dir == MODE_ADD) /* && !(chptr->mode.mode & d)) */
431    {
432 <    if ((serv_p->localClient->caps & chcap_combos[n].cap_yes) ==
433 <        chcap_combos[n].cap_yes &&
434 <        (serv_p->localClient->caps & chcap_combos[n].cap_no) == 0)
435 <    {
436 <      /* Hopefully capabs can't change dynamically or anything... */
437 <      assert(chcap_combos[n].count > 0);
508 <      chcap_combos[n].count--;
509 <      return;
510 <    }
432 >    chptr->mode.mode |= d;
433 >
434 >    mode_changes[mode_count].letter = c;
435 >    mode_changes[mode_count].arg = NULL;
436 >    mode_changes[mode_count].id = NULL;
437 >    mode_changes[mode_count++].dir = dir;
438    }
439 +  else if (dir == MODE_DEL) /* && (chptr->mode.mode & d)) */
440 +  {
441 +    /* setting - */
442 +
443 +    chptr->mode.mode &= ~d;
444  
445 <  /* This should be impossible -A1kmm. */
446 <  assert(0);
445 >    mode_changes[mode_count].letter = c;
446 >    mode_changes[mode_count].arg = NULL;
447 >    mode_changes[mode_count].id = NULL;
448 >    mode_changes[mode_count++].dir = dir;
449 >  }
450   }
451  
517 – /* Mode functions handle mode changes for a particular mode... */
452   static void
453 < chm_nosuch(struct Client *client_p, struct Client *source_p,
454 <           struct Channel *chptr, int parc, int *parn,
521 <           char **parv, int *errors, int alev, int dir, char c, void *d,
522 <           const char *chname)
453 > chm_registered(struct Client *source_p, struct Channel *chptr, int parc, int *parn,
454 >               char **parv, int *errors, int alev, int dir, char c, unsigned int d)
455   {
456 <  if (*errors & SM_ERR_UNKNOWN)
456 >  if (!IsServer(source_p) && !HasFlag(source_p, FLAGS_SERVICE))
457 >  {
458 >    if (!(*errors & SM_ERR_ONLYSERVER))
459 >      sendto_one_numeric(source_p, &me,
460 >                         alev == CHACCESS_NOTONCHAN ? ERR_NOTONCHANNEL :
461 >                         ERR_ONLYSERVERSCANCHANGE, chptr->name);
462 >
463 >    *errors |= SM_ERR_ONLYSERVER;
464      return;
465 +  }
466  
467 <  *errors |= SM_ERR_UNKNOWN;
468 <  sendto_one(source_p, form_str(ERR_UNKNOWNMODE), me.name,
469 <             source_p->name, c);
467 >  /* If have already dealt with this simple mode, ignore it */
468 >  if (simple_modes_mask & d)
469 >    return;
470 >
471 >  simple_modes_mask |= d;
472 >
473 >  /* setting + */
474 >  /* Apparently, (though no one has ever told the hybrid group directly)
475 >   * admins don't like redundant mode checking. ok. It would have been nice
476 >   * if you had have told us directly. I've left the original code snippets
477 >   * in place.
478 >   *
479 >   * -Dianora
480 >   */
481 >  if (dir == MODE_ADD) /* && !(chptr->mode.mode & d)) */
482 >  {
483 >    chptr->mode.mode |= d;
484 >
485 >    mode_changes[mode_count].letter = c;
486 >    mode_changes[mode_count].arg = NULL;
487 >    mode_changes[mode_count].id = NULL;
488 >    mode_changes[mode_count++].dir = dir;
489 >  }
490 >  else if (dir == MODE_DEL) /* && (chptr->mode.mode & d)) */
491 >  {
492 >    /* setting - */
493 >
494 >    chptr->mode.mode &= ~d;
495 >
496 >    mode_changes[mode_count].letter = c;
497 >    mode_changes[mode_count].arg = NULL;
498 >    mode_changes[mode_count].id = NULL;
499 >    mode_changes[mode_count++].dir = dir;
500 >  }
501   }
502  
503   static void
504 < chm_simple(struct Client *client_p, struct Client *source_p, struct Channel *chptr,
505 <           int parc, int *parn, char **parv, int *errors, int alev, int dir,
535 <           char c, void *d, const char *chname)
504 > chm_operonly(struct Client *source_p, struct Channel *chptr, int parc, int *parn,
505 >             char **parv, int *errors, int alev, int dir, char c, unsigned int d)
506   {
507 <  long mode_type;
538 <
539 <  mode_type = (long)d;
540 <
541 <  if ((alev < CHACCESS_HALFOP) ||
542 <      ((mode_type == MODE_PRIVATE) && (alev < CHACCESS_CHANOP)))
507 >  if (alev < CHACCESS_CHANOP)
508    {
509      if (!(*errors & SM_ERR_NOOPS))
510 <      sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ?
511 <                                    ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED),
512 <                 me.name, source_p->name, chname);
510 >      sendto_one_numeric(source_p, &me,
511 >                         alev == CHACCESS_NOTONCHAN ? ERR_NOTONCHANNEL :
512 >                         ERR_CHANOPRIVSNEEDED, chptr->name);
513 >
514      *errors |= SM_ERR_NOOPS;
515      return;
516    }
517  
518 +  if (MyClient(source_p) && !HasUMode(source_p, UMODE_OPER))
519 +  {
520 +    if (!(*errors & SM_ERR_NOTOPER))
521 +      sendto_one_numeric(source_p, &me, ERR_NOPRIVILEGES);
522 +
523 +    *errors |= SM_ERR_NOTOPER;
524 +    return;
525 +  }
526 +
527    /* If have already dealt with this simple mode, ignore it */
528 <  if (simple_modes_mask & mode_type)
528 >  if (simple_modes_mask & d)
529      return;
530  
531 <  simple_modes_mask |= mode_type;
531 >  simple_modes_mask |= d;
532  
533 <  /* setting + */
559 <  /* Apparently, (though no one has ever told the hybrid group directly)
560 <   * admins don't like redundant mode checking. ok. It would have been nice
561 <   * if you had have told us directly. I've left the original code snippets
562 <   * in place.
563 <   *
564 <   * -Dianora
565 <   */
566 <  if ((dir == MODE_ADD)) /* && !(chptr->mode.mode & mode_type)) */
533 >  if (dir == MODE_ADD) /* && !(chptr->mode.mode & d)) */
534    {
535 <    chptr->mode.mode |= mode_type;
535 >    chptr->mode.mode |= d;
536  
537      mode_changes[mode_count].letter = c;
538 <    mode_changes[mode_count].dir = MODE_ADD;
572 <    mode_changes[mode_count].caps = 0;
573 <    mode_changes[mode_count].nocaps = 0;
538 >    mode_changes[mode_count].arg = NULL;
539      mode_changes[mode_count].id = NULL;
540 <    mode_changes[mode_count].mems = ALL_MEMBERS;
576 <    mode_changes[mode_count++].arg = NULL;
540 >    mode_changes[mode_count++].dir = dir;
541    }
542 <  else if ((dir == MODE_DEL)) /* && (chptr->mode.mode & mode_type)) */
542 >  else if (dir == MODE_DEL) /* && (chptr->mode.mode & d)) */
543    {
544      /* setting - */
545  
546 <    chptr->mode.mode &= ~mode_type;
546 >    chptr->mode.mode &= ~d;
547  
548      mode_changes[mode_count].letter = c;
549 <    mode_changes[mode_count].dir = MODE_DEL;
586 <    mode_changes[mode_count].caps = 0;
587 <    mode_changes[mode_count].nocaps = 0;
588 <    mode_changes[mode_count].mems = ALL_MEMBERS;
549 >    mode_changes[mode_count].arg = NULL;
550      mode_changes[mode_count].id = NULL;
551 <    mode_changes[mode_count++].arg = NULL;
551 >    mode_changes[mode_count++].dir = dir;
552    }
553   }
554  
555   static void
556 < chm_ban(struct Client *client_p, struct Client *source_p,
557 <        struct Channel *chptr, int parc, int *parn,
597 <        char **parv, int *errors, int alev, int dir, char c, void *d,
598 <        const char *chname)
556 > chm_ban(struct Client *source_p, struct Channel *chptr, int parc, int *parn,
557 >        char **parv, int *errors, int alev, int dir, char c, unsigned int d)
558   {
559    char *mask = NULL;
560  
561    if (dir == MODE_QUERY || parc <= *parn)
562    {
563 <    dlink_node *ptr = NULL;
563 >    dlink_node *node = NULL;
564  
565      if (*errors & SM_ERR_RPL_B)
566        return;
567  
568      *errors |= SM_ERR_RPL_B;
569  
570 <    DLINK_FOREACH(ptr, chptr->banlist.head)
570 >    DLINK_FOREACH(node, chptr->banlist.head)
571      {
572 <      const struct Ban *banptr = ptr->data;
573 <      sendto_one(client_p, form_str(RPL_BANLIST),
574 <                 me.name, client_p->name, chname,
575 <                 banptr->name, banptr->username, banptr->host,
617 <                 banptr->who, banptr->when);
572 >      const struct Ban *ban = node->data;
573 >      sendto_one_numeric(source_p, &me, RPL_BANLIST, chptr->name,
574 >                         ban->name, ban->user, ban->host,
575 >                         ban->who, ban->when);
576      }
577  
578 <    sendto_one(source_p, form_str(RPL_ENDOFBANLIST), me.name,
621 <               source_p->name, chname);
578 >    sendto_one_numeric(source_p, &me, RPL_ENDOFBANLIST, chptr->name);
579      return;
580    }
581  
582    if (alev < CHACCESS_HALFOP)
583    {
584      if (!(*errors & SM_ERR_NOOPS))
585 <      sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ?
586 <                                    ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED),
587 <                 me.name, source_p->name, chname);
585 >      sendto_one_numeric(source_p, &me,
586 >                         alev == CHACCESS_NOTONCHAN ? ERR_NOTONCHANNEL :
587 >                         ERR_CHANOPRIVSNEEDED, chptr->name);
588 >
589      *errors |= SM_ERR_NOOPS;
590      return;
591    }
# Line 635 | Line 593 | chm_ban(struct Client *client_p, struct
593    if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
594      return;
595  
596 <  mask = parv[(*parn)++];
597 <  
598 <  if (IsServer(client_p))
599 <    if (strchr(mask, ' '))
600 <      return;
596 >  mask = nuh_mask[*parn];
597 >  memcpy(mask, parv[*parn], sizeof(nuh_mask[*parn]));
598 >  ++(*parn);
599 >
600 >  if (*mask == ':' || (!MyConnect(source_p) && strchr(mask, ' ')))
601 >    return;
602  
603    switch (dir)
604    {
# Line 648 | Line 607 | chm_ban(struct Client *client_p, struct
607          return;
608        break;
609      case MODE_DEL:
651 – /* XXX grrrrrrr */
652 – #ifdef NO_BAN_COOKIE
610        if (!del_id(chptr, mask, CHFL_BAN))
611          return;
655 – #else
656 –     /* XXX this hack allows /mode * +o-b nick ban.cookie
657 –      * I'd like to see this hack go away in the future.
658 –      */
659 –      del_id(chptr, mask, CHFL_BAN);
660 – #endif
612        break;
613      default:
614        assert(0);
615    }
616  
617    mode_changes[mode_count].letter = c;
618 <  mode_changes[mode_count].dir = dir;
668 <  mode_changes[mode_count].caps = 0;
669 <  mode_changes[mode_count].nocaps = 0;
670 <  mode_changes[mode_count].mems = ALL_MEMBERS;
618 >  mode_changes[mode_count].arg = mask;
619    mode_changes[mode_count].id = NULL;
620 <  mode_changes[mode_count++].arg = mask;
620 >  mode_changes[mode_count++].dir = dir;
621   }
622  
623   static void
624 < chm_except(struct Client *client_p, struct Client *source_p,
625 <           struct Channel *chptr, int parc, int *parn,
678 <           char **parv, int *errors, int alev, int dir, char c, void *d,
679 <           const char *chname)
624 > chm_except(struct Client *source_p, struct Channel *chptr, int parc, int *parn,
625 >           char **parv, int *errors, int alev, int dir, char c, unsigned int d)
626   {
627    char *mask = NULL;
628  
629 <  /* if we have +e disabled, allow local clients to do anything but
684 <   * set the mode.  This prevents the abuse of +e when just a few
685 <   * servers support it. --fl
686 <   */
687 <  if (!ConfigChannel.use_except && MyClient(source_p) &&
688 <      ((dir == MODE_ADD) && (parc > *parn)))
629 >  if (dir == MODE_QUERY || parc <= *parn)
630    {
631 +    dlink_node *node = NULL;
632 +
633      if (*errors & SM_ERR_RPL_E)
634        return;
635  
636      *errors |= SM_ERR_RPL_E;
637 +
638 +    DLINK_FOREACH(node, chptr->exceptlist.head)
639 +    {
640 +      const struct Ban *ban = node->data;
641 +
642 +      sendto_one_numeric(source_p, &me, RPL_EXCEPTLIST, chptr->name,
643 +                         ban->name, ban->user, ban->host,
644 +                         ban->who, ban->when);
645 +    }
646 +
647 +    sendto_one_numeric(source_p, &me, RPL_ENDOFEXCEPTLIST, chptr->name);
648      return;
649    }
650  
651    if (alev < CHACCESS_HALFOP)
652    {
653      if (!(*errors & SM_ERR_NOOPS))
654 <      sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ?
655 <                                    ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED),
656 <                 me.name, source_p->name, chname);
703 <    *errors |= SM_ERR_NOOPS;
704 <    return;
705 <  }
654 >      sendto_one_numeric(source_p, &me,
655 >                         alev == CHACCESS_NOTONCHAN ? ERR_NOTONCHANNEL :
656 >                         ERR_CHANOPRIVSNEEDED, chptr->name);
657  
658 <  if (dir == MODE_QUERY || parc <= *parn)
708 <  {
709 <    dlink_node *ptr = NULL;
710 <
711 <    if (*errors & SM_ERR_RPL_E)
712 <      return;
713 <
714 <    *errors |= SM_ERR_RPL_E;
715 <
716 <    DLINK_FOREACH(ptr, chptr->exceptlist.head)
717 <    {
718 <      const struct Ban *banptr = ptr->data;
719 <      sendto_one(client_p, form_str(RPL_EXCEPTLIST),
720 <                 me.name, client_p->name, chname,
721 <                 banptr->name, banptr->username, banptr->host,
722 <                 banptr->who, banptr->when);
723 <    }
724 <
725 <    sendto_one(source_p, form_str(RPL_ENDOFEXCEPTLIST), me.name,
726 <               source_p->name, chname);
658 >    *errors |= SM_ERR_NOOPS;
659      return;
660    }
661  
662    if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
663      return;
664  
665 <  mask = parv[(*parn)++];
665 >  mask = nuh_mask[*parn];
666 >  memcpy(mask, parv[*parn], sizeof(nuh_mask[*parn]));
667 >  ++(*parn);
668  
669 <  if (IsServer(client_p))
670 <    if (strchr(mask, ' '))
737 <      return;
669 >  if (*mask == ':' || (!MyConnect(source_p) && strchr(mask, ' ')))
670 >    return;
671  
672    switch (dir)
673    {
# Line 751 | Line 684 | chm_except(struct Client *client_p, stru
684    }
685  
686    mode_changes[mode_count].letter = c;
687 <  mode_changes[mode_count].dir = dir;
755 <  mode_changes[mode_count].caps = CAP_EX;
756 <  mode_changes[mode_count].nocaps = 0;
757 <
758 <  if (ConfigChannel.use_except)
759 <    mode_changes[mode_count].mems = ONLY_CHANOPS;
760 <  else
761 <    mode_changes[mode_count].mems = ONLY_SERVERS;
762 <
687 >  mode_changes[mode_count].arg = mask;
688    mode_changes[mode_count].id = NULL;
689 <  mode_changes[mode_count++].arg = mask;
689 >  mode_changes[mode_count++].dir = dir;
690   }
691  
692   static void
693 < chm_invex(struct Client *client_p, struct Client *source_p,
694 <          struct Channel *chptr, int parc, int *parn,
770 <          char **parv, int *errors, int alev, int dir, char c, void *d,
771 <          const char *chname)
693 > chm_invex(struct Client *source_p, struct Channel *chptr, int parc, int *parn,
694 >          char **parv, int *errors, int alev, int dir, char c, unsigned int d)
695   {
696    char *mask = NULL;
697  
775 –  /* if we have +I disabled, allow local clients to do anything but
776 –   * set the mode.  This prevents the abuse of +I when just a few
777 –   * servers support it --fl
778 –   */
779 –  if (!ConfigChannel.use_invex && MyClient(source_p) &&
780 –      (dir == MODE_ADD) && (parc > *parn))
781 –  {
782 –    if (*errors & SM_ERR_RPL_I)
783 –      return;
784 –    
785 –    *errors |= SM_ERR_RPL_I;
786 –    return;
787 –  }
788 –
789 –  if (alev < CHACCESS_HALFOP)
790 –  {
791 –    if (!(*errors & SM_ERR_NOOPS))
792 –      sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ?
793 –                                    ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED),
794 –                 me.name, source_p->name, chname);
795 –    *errors |= SM_ERR_NOOPS;
796 –    return;
797 –  }
798 –
698    if (dir == MODE_QUERY || parc <= *parn)
699    {
700 <    dlink_node *ptr = NULL;
700 >    dlink_node *node = NULL;
701  
702      if (*errors & SM_ERR_RPL_I)
703        return;
704  
705      *errors |= SM_ERR_RPL_I;
706  
707 <    DLINK_FOREACH(ptr, chptr->invexlist.head)
707 >    DLINK_FOREACH(node, chptr->invexlist.head)
708      {
709 <      const struct Ban *banptr = ptr->data;
710 <      sendto_one(client_p, form_str(RPL_INVITELIST), me.name,
711 <                 client_p->name, chname,
712 <                 banptr->name, banptr->username, banptr->host,
713 <                 banptr->who, banptr->when);
709 >      const struct Ban *ban = node->data;
710 >
711 >      sendto_one_numeric(source_p, &me, RPL_INVEXLIST, chptr->name,
712 >                         ban->name, ban->user, ban->host,
713 >                         ban->who, ban->when);
714      }
715  
716 <    sendto_one(source_p, form_str(RPL_ENDOFINVITELIST), me.name,
717 <               source_p->name, chname);
716 >    sendto_one_numeric(source_p, &me, RPL_ENDOFINVEXLIST, chptr->name);
717 >    return;
718 >  }
719 >
720 >  if (alev < CHACCESS_HALFOP)
721 >  {
722 >    if (!(*errors & SM_ERR_NOOPS))
723 >      sendto_one_numeric(source_p, &me,
724 >                         alev == CHACCESS_NOTONCHAN ? ERR_NOTONCHANNEL :
725 >                         ERR_CHANOPRIVSNEEDED, chptr->name);
726 >
727 >    *errors |= SM_ERR_NOOPS;
728      return;
729    }
730  
731    if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
732      return;
733  
734 <  mask = parv[(*parn)++];
734 >  mask = nuh_mask[*parn];
735 >  memcpy(mask, parv[*parn], sizeof(nuh_mask[*parn]));
736 >  ++(*parn);
737  
738 <  if (IsServer(client_p))
739 <    if (strchr(mask, ' '))
829 <      return;
738 >  if (*mask == ':' || (!MyConnect(source_p) && strchr(mask, ' ')))
739 >    return;
740  
741    switch (dir)
742    {
# Line 843 | Line 753 | chm_invex(struct Client *client_p, struc
753    }
754  
755    mode_changes[mode_count].letter = c;
756 <  mode_changes[mode_count].dir = dir;
847 <  mode_changes[mode_count].caps = CAP_IE;
848 <  mode_changes[mode_count].nocaps = 0;
849 <
850 <  if (ConfigChannel.use_invex)
851 <    mode_changes[mode_count].mems = ONLY_CHANOPS;
852 <  else
853 <    mode_changes[mode_count].mems = ONLY_SERVERS;
854 <
756 >  mode_changes[mode_count].arg = mask;
757    mode_changes[mode_count].id = NULL;
758 <  mode_changes[mode_count++].arg = mask;
857 < }
858 <
859 < /*
860 < * inputs       - pointer to channel
861 < * output       - none
862 < * side effects - clear ban cache
863 < */
864 < void
865 < clear_ban_cache(struct Channel *chptr)
866 < {
867 <  dlink_node *ptr = NULL;
868 <
869 <  DLINK_FOREACH(ptr, chptr->locmembers.head)
870 <  {
871 <    struct Membership *ms = ptr->data;
872 <    ms->flags &= ~(CHFL_BAN_SILENCED|CHFL_BAN_CHECKED);
873 <  }
758 >  mode_changes[mode_count++].dir = dir;
759   }
760  
761   static void
762 < chm_op(struct Client *client_p, struct Client *source_p,
763 <       struct Channel *chptr, int parc, int *parn,
879 <       char **parv, int *errors, int alev, int dir, char c, void *d,
880 <       const char *chname)
762 > chm_voice(struct Client *source_p, struct Channel *chptr, int parc, int *parn,
763 >          char **parv, int *errors, int alev, int dir, char c, unsigned int d)
764   {
765 <  char *opnick;
883 <  struct Client *targ_p;
765 >  struct Client *target_p;
766    struct Membership *member;
767  
768 <  if (alev < CHACCESS_CHANOP)
768 >  if (alev < CHACCESS_HALFOP)
769    {
770      if (!(*errors & SM_ERR_NOOPS))
771 <      sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ?
772 <                                    ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED),
773 <                 me.name, source_p->name, chname);
771 >      sendto_one_numeric(source_p, &me,
772 >                         alev == CHACCESS_NOTONCHAN ? ERR_NOTONCHANNEL :
773 >                         ERR_CHANOPRIVSNEEDED, chptr->name);
774 >
775      *errors |= SM_ERR_NOOPS;
776      return;
777    }
778  
779 <  if ((dir == MODE_QUERY) || (parc <= *parn))
779 >  if (dir == MODE_QUERY || parc <= *parn)
780      return;
781  
782 <  opnick = parv[(*parn)++];
783 <
901 <  if ((targ_p = find_chasing(client_p, source_p, opnick, NULL)) == NULL)
902 <    return;
903 <  if (!IsClient(targ_p))
904 <    return;
782 >  if ((target_p = find_chasing(source_p, parv[(*parn)++])) == NULL)
783 >    return;  /* find_chasing sends ERR_NOSUCHNICK */
784  
785 <  if ((member = find_channel_link(targ_p, chptr)) == NULL)
785 >  if ((member = find_channel_link(target_p, chptr)) == NULL)
786    {
787      if (!(*errors & SM_ERR_NOTONCHANNEL))
788 <      sendto_one(source_p, form_str(ERR_USERNOTINCHANNEL),
789 <                 me.name, source_p->name, opnick, chname);
788 >      sendto_one_numeric(source_p, &me, ERR_USERNOTINCHANNEL, target_p->name, chptr->name);
789 >
790      *errors |= SM_ERR_NOTONCHANNEL;
791      return;
792    }
# Line 916 | Line 795 | chm_op(struct Client *client_p, struct C
795      return;
796  
797    /* no redundant mode changes */
798 <  if (dir == MODE_ADD &&  has_member_flags(member, CHFL_CHANOP))
798 >  if (dir == MODE_ADD &&  has_member_flags(member, CHFL_VOICE))
799      return;
800 <  if (dir == MODE_DEL && !has_member_flags(member, CHFL_CHANOP))
800 >
801 >  if (dir == MODE_DEL && !has_member_flags(member, CHFL_VOICE))
802      return;
803  
804 <  mode_changes[mode_count].letter = 'o';
805 <  mode_changes[mode_count].dir = dir;
806 <  mode_changes[mode_count].caps = 0;
807 <  mode_changes[mode_count].nocaps = 0;
928 <  mode_changes[mode_count].mems = ALL_MEMBERS;
929 <  mode_changes[mode_count].id = targ_p->id;
930 <  mode_changes[mode_count].arg = targ_p->name;
931 <  mode_changes[mode_count++].client = targ_p;
804 >  mode_changes[mode_count].letter = c;
805 >  mode_changes[mode_count].arg = target_p->name;
806 >  mode_changes[mode_count].id = target_p->id;
807 >  mode_changes[mode_count++].dir = dir;
808  
809    if (dir == MODE_ADD)
810 <  {
935 <    AddMemberFlag(member, CHFL_CHANOP);
936 <    DelMemberFlag(member, CHFL_DEOPPED);
937 <  }
810 >    AddMemberFlag(member, CHFL_VOICE);
811    else
812 <    DelMemberFlag(member, CHFL_CHANOP);
812 >    DelMemberFlag(member, CHFL_VOICE);
813   }
814  
942 – #ifdef HALFOPS
815   static void
816 < chm_hop(struct Client *client_p, struct Client *source_p,
817 <       struct Channel *chptr, int parc, int *parn,
946 <       char **parv, int *errors, int alev, int dir, char c, void *d,
947 <       const char *chname)
816 > chm_hop(struct Client *source_p, struct Channel *chptr, int parc, int *parn,
817 >        char **parv, int *errors, int alev, int dir, char c, unsigned int d)
818   {
819 <  char *opnick;
950 <  struct Client *targ_p;
819 >  struct Client *target_p;
820    struct Membership *member;
821  
822 <  /* *sigh* - dont allow halfops to set +/-h, they could fully control a
954 <   * channel if there were no ops - it doesnt solve anything.. MODE_PRIVATE
955 <   * when used with MODE_SECRET is paranoid - cant use +p
956 <   *
957 <   * it needs to be optional per channel - but not via +p, that or remove
958 <   * paranoid.. -- fl_
959 <   *
960 <   * +p means paranoid, it is useless for anything else on modern IRC, as
961 <   * list isn't really usable. If you want to have a private channel these
962 <   * days, you set it +s. Halfops can no longer remove simple modes when
963 <   * +p is set (although they can set +p) so it is safe to use this to
964 <   * control whether they can (de)halfop...
965 <   */
966 <  if (alev <
967 <      ((chptr->mode.mode & MODE_PRIVATE) ? CHACCESS_CHANOP : CHACCESS_HALFOP))
822 >  if (alev < CHACCESS_CHANOP)
823    {
824      if (!(*errors & SM_ERR_NOOPS))
825 <      sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ?
826 <                                    ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED),
827 <                 me.name, source_p->name, chname);
825 >      sendto_one_numeric(source_p, &me,
826 >                         alev == CHACCESS_NOTONCHAN ? ERR_NOTONCHANNEL :
827 >                         ERR_CHANOPRIVSNEEDED, chptr->name);
828 >
829      *errors |= SM_ERR_NOOPS;
830      return;
831    }
832  
833 <  if ((dir == MODE_QUERY) || (parc <= *parn))
833 >  if (dir == MODE_QUERY || parc <= *parn)
834      return;
835  
836 <  opnick = parv[(*parn)++];
837 <
982 <  if ((targ_p = find_chasing(client_p, source_p, opnick, NULL)) == NULL)
983 <    return;
984 <  if (!IsClient(targ_p))
985 <    return;
836 >  if ((target_p = find_chasing(source_p, parv[(*parn)++])) == NULL)
837 >    return;  /* find_chasing sends ERR_NOSUCHNICK */
838  
839 <  if ((member = find_channel_link(targ_p, chptr)) == NULL)
839 >  if ((member = find_channel_link(target_p, chptr)) == NULL)
840    {
841      if (!(*errors & SM_ERR_NOTONCHANNEL))
842 <      sendto_one(source_p, form_str(ERR_USERNOTINCHANNEL),
843 <                 me.name, source_p->name, opnick, chname);
842 >      sendto_one_numeric(source_p, &me, ERR_USERNOTINCHANNEL, target_p->name, chptr->name);
843 >
844      *errors |= SM_ERR_NOTONCHANNEL;
845      return;
846    }
# Line 999 | Line 851 | chm_hop(struct Client *client_p, struct
851    /* no redundant mode changes */
852    if (dir == MODE_ADD &&  has_member_flags(member, CHFL_HALFOP))
853      return;
854 +
855    if (dir == MODE_DEL && !has_member_flags(member, CHFL_HALFOP))
856      return;
857  
858 <  mode_changes[mode_count].letter = 'h';
859 <  mode_changes[mode_count].dir = dir;
860 <  mode_changes[mode_count].caps = 0;
861 <  mode_changes[mode_count].nocaps = 0;
1009 <  mode_changes[mode_count].mems = ALL_MEMBERS;
1010 <  mode_changes[mode_count].id = targ_p->id;
1011 <  mode_changes[mode_count].arg = targ_p->name;
1012 <  mode_changes[mode_count++].client = targ_p;
858 >  mode_changes[mode_count].letter = c;
859 >  mode_changes[mode_count].arg = target_p->name;
860 >  mode_changes[mode_count].id = target_p->id;
861 >  mode_changes[mode_count++].dir = dir;
862  
863    if (dir == MODE_ADD)
1015 –  {
864      AddMemberFlag(member, CHFL_HALFOP);
1017 –    DelMemberFlag(member, CHFL_DEOPPED);
1018 –  }
865    else
866      DelMemberFlag(member, CHFL_HALFOP);
867   }
1022 – #endif
868  
869   static void
870 < chm_voice(struct Client *client_p, struct Client *source_p,
871 <          struct Channel *chptr, int parc, int *parn,
1027 <          char **parv, int *errors, int alev, int dir, char c, void *d,
1028 <          const char *chname)
870 > chm_op(struct Client *source_p, struct Channel *chptr, int parc, int *parn,
871 >       char **parv, int *errors, int alev, int dir, char c, unsigned int d)
872   {
873 <  char *opnick;
1031 <  struct Client *targ_p;
873 >  struct Client *target_p;
874    struct Membership *member;
875  
876 <  if (alev < CHACCESS_HALFOP)
876 >  if (alev < CHACCESS_CHANOP)
877    {
878      if (!(*errors & SM_ERR_NOOPS))
879 <      sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ?
880 <                                    ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED),
881 <                 me.name, source_p->name, chname);
879 >      sendto_one_numeric(source_p, &me,
880 >                         alev == CHACCESS_NOTONCHAN ? ERR_NOTONCHANNEL :
881 >                         ERR_CHANOPRIVSNEEDED, chptr->name);
882 >
883      *errors |= SM_ERR_NOOPS;
884      return;
885    }
886  
887 <  if ((dir == MODE_QUERY) || parc <= *parn)
887 >  if (dir == MODE_QUERY || parc <= *parn)
888      return;
889  
890 <  opnick = parv[(*parn)++];
890 >  if ((target_p = find_chasing(source_p, parv[(*parn)++])) == NULL)
891 >    return;  /* find_chasing sends ERR_NOSUCHNICK */
892  
893 <  if ((targ_p = find_chasing(client_p, source_p, opnick, NULL)) == NULL)
1050 <    return;
1051 <  if (!IsClient(targ_p))
1052 <    return;
1053 <
1054 <  if ((member = find_channel_link(targ_p, chptr)) == NULL)
893 >  if ((member = find_channel_link(target_p, chptr)) == NULL)
894    {
895      if (!(*errors & SM_ERR_NOTONCHANNEL))
896 <      sendto_one(source_p, form_str(ERR_USERNOTINCHANNEL),
897 <                 me.name, source_p->name, opnick, chname);
896 >      sendto_one_numeric(source_p, &me, ERR_USERNOTINCHANNEL, target_p->name, chptr->name);
897 >
898      *errors |= SM_ERR_NOTONCHANNEL;
899      return;
900    }
# Line 1064 | Line 903 | chm_voice(struct Client *client_p, struc
903      return;
904  
905    /* no redundant mode changes */
906 <  if (dir == MODE_ADD &&  has_member_flags(member, CHFL_VOICE))
906 >  if (dir == MODE_ADD &&  has_member_flags(member, CHFL_CHANOP))
907      return;
908 <  if (dir == MODE_DEL && !has_member_flags(member, CHFL_VOICE))
908 >
909 >  if (dir == MODE_DEL && !has_member_flags(member, CHFL_CHANOP))
910      return;
911  
912 <  mode_changes[mode_count].letter = 'v';
913 <  mode_changes[mode_count].dir = dir;
914 <  mode_changes[mode_count].caps = 0;
915 <  mode_changes[mode_count].nocaps = 0;
1076 <  mode_changes[mode_count].mems = ALL_MEMBERS;
1077 <  mode_changes[mode_count].id = targ_p->id;
1078 <  mode_changes[mode_count].arg = targ_p->name;
1079 <  mode_changes[mode_count++].client = targ_p;
912 >  mode_changes[mode_count].letter = c;
913 >  mode_changes[mode_count].arg = target_p->name;
914 >  mode_changes[mode_count].id = target_p->id;
915 >  mode_changes[mode_count++].dir = dir;
916  
917    if (dir == MODE_ADD)
918 <    AddMemberFlag(member, CHFL_VOICE);
918 >    AddMemberFlag(member, CHFL_CHANOP);
919    else
920 <    DelMemberFlag(member, CHFL_VOICE);
920 >    DelMemberFlag(member, CHFL_CHANOP);
921   }
922  
923   static void
924 < chm_limit(struct Client *client_p, struct Client *source_p,
925 <          struct Channel *chptr, int parc, int *parn,
1090 <          char **parv, int *errors, int alev, int dir, char c, void *d,
1091 <          const char *chname)
924 > chm_limit(struct Client *source_p, struct Channel *chptr, int parc, int *parn,
925 >          char **parv, int *errors, int alev, int dir, char c, unsigned int d)
926   {
927 <  int i, limit;
1094 <  char *lstr;
927 >  int limit = 0;
928  
929    if (alev < CHACCESS_HALFOP)
930    {
931      if (!(*errors & SM_ERR_NOOPS))
932 <      sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ?
933 <                                    ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED),
934 <                 me.name, source_p->name, chname);
932 >      sendto_one_numeric(source_p, &me,
933 >                         alev == CHACCESS_NOTONCHAN ? ERR_NOTONCHANNEL :
934 >                         ERR_CHANOPRIVSNEEDED, chptr->name);
935      *errors |= SM_ERR_NOOPS;
936      return;
937    }
# Line 1106 | Line 939 | chm_limit(struct Client *client_p, struc
939    if (dir == MODE_QUERY)
940      return;
941  
942 <  if ((dir == MODE_ADD) && parc > *parn)
942 >  if (dir == MODE_ADD && parc > *parn)
943    {
944 <    lstr = parv[(*parn)++];
944 >    char *const lstr = parv[(*parn)++];
945  
946 <    if ((limit = atoi(lstr)) <= 0)
946 >    if (EmptyString(lstr) || (limit = atoi(lstr)) <= 0)
947        return;
948  
949 <    ircsprintf(lstr, "%d", limit);
949 >    sprintf(lstr, "%d", limit);
950  
951 <    /* if somebody sets MODE #channel +ll 1 2, accept latter --fl */
952 <    for (i = 0; i < mode_count; i++)
1120 <    {
951 >    /* If somebody sets MODE #channel +ll 1 2, accept latter --fl */
952 >    for (unsigned int i = 0; i < mode_count; ++i)
953        if (mode_changes[i].letter == c && mode_changes[i].dir == MODE_ADD)
954          mode_changes[i].letter = 0;
1123 –    }
955  
956      mode_changes[mode_count].letter = c;
957 <    mode_changes[mode_count].dir = MODE_ADD;
1127 <    mode_changes[mode_count].caps = 0;
1128 <    mode_changes[mode_count].nocaps = 0;
1129 <    mode_changes[mode_count].mems = ALL_MEMBERS;
957 >    mode_changes[mode_count].arg = lstr;
958      mode_changes[mode_count].id = NULL;
959 <    mode_changes[mode_count++].arg = lstr;
959 >    mode_changes[mode_count++].dir = dir;
960  
961      chptr->mode.limit = limit;
962    }
# Line 1140 | Line 968 | chm_limit(struct Client *client_p, struc
968      chptr->mode.limit = 0;
969  
970      mode_changes[mode_count].letter = c;
971 <    mode_changes[mode_count].dir = MODE_DEL;
1144 <    mode_changes[mode_count].caps = 0;
1145 <    mode_changes[mode_count].nocaps = 0;
1146 <    mode_changes[mode_count].mems = ALL_MEMBERS;
971 >    mode_changes[mode_count].arg = NULL;
972      mode_changes[mode_count].id = NULL;
973 <    mode_changes[mode_count++].arg = NULL;
973 >    mode_changes[mode_count++].dir = dir;
974    }
975   }
976  
977   static void
978 < chm_key(struct Client *client_p, struct Client *source_p,
979 <        struct Channel *chptr, int parc, int *parn,
1155 <        char **parv, int *errors, int alev, int dir, char c, void *d,
1156 <        const char *chname)
978 > chm_key(struct Client *source_p, struct Channel *chptr, int parc, int *parn,
979 >        char **parv, int *errors, int alev, int dir, char c, unsigned int d)
980   {
1158 –  int i;
1159 –  char *key;
1160 –
981    if (alev < CHACCESS_HALFOP)
982    {
983      if (!(*errors & SM_ERR_NOOPS))
984 <      sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ?
985 <                                    ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED),
986 <                 me.name, source_p->name, chname);
984 >      sendto_one_numeric(source_p, &me,
985 >                         alev == CHACCESS_NOTONCHAN ? ERR_NOTONCHANNEL :
986 >                         ERR_CHANOPRIVSNEEDED, chptr->name);
987      *errors |= SM_ERR_NOOPS;
988      return;
989    }
# Line 1171 | Line 991 | chm_key(struct Client *client_p, struct
991    if (dir == MODE_QUERY)
992      return;
993  
994 <  if ((dir == MODE_ADD) && parc > *parn)
994 >  if (dir == MODE_ADD && parc > *parn)
995    {
996 <    key = parv[(*parn)++];
1177 <
1178 <    if (MyClient(source_p))
1179 <      fix_key(key);
1180 <    else
1181 <      fix_key_old(key);
996 >    char *const key = fix_key(parv[(*parn)++]);
997  
998 <    if (*key == '\0')
998 >    if (EmptyString(key))
999        return;
1000  
1001      assert(key[0] != ' ');
1002      strlcpy(chptr->mode.key, key, sizeof(chptr->mode.key));
1003  
1004 <    /* if somebody does MODE #channel +kk a b, accept latter --fl */
1005 <    for (i = 0; i < mode_count; i++)
1191 <    {
1004 >    /* If somebody does MODE #channel +kk a b, accept latter --fl */
1005 >    for (unsigned int i = 0; i < mode_count; ++i)
1006        if (mode_changes[i].letter == c && mode_changes[i].dir == MODE_ADD)
1007          mode_changes[i].letter = 0;
1194 –    }
1008  
1009      mode_changes[mode_count].letter = c;
1010 <    mode_changes[mode_count].dir = MODE_ADD;
1198 <    mode_changes[mode_count].caps = 0;
1199 <    mode_changes[mode_count].nocaps = 0;
1200 <    mode_changes[mode_count].mems = ALL_MEMBERS;
1010 >    mode_changes[mode_count].arg = chptr->mode.key;
1011      mode_changes[mode_count].id = NULL;
1012 <    mode_changes[mode_count++].arg = chptr->mode.key;
1012 >    mode_changes[mode_count++].dir = dir;
1013    }
1014    else if (dir == MODE_DEL)
1015    {
1016      if (parc > *parn)
1017 <      (*parn)++;
1017 >      ++(*parn);
1018  
1019      if (chptr->mode.key[0] == '\0')
1020        return;
# Line 1212 | Line 1022 | chm_key(struct Client *client_p, struct
1022      chptr->mode.key[0] = '\0';
1023  
1024      mode_changes[mode_count].letter = c;
1025 <    mode_changes[mode_count].dir = MODE_DEL;
1216 <    mode_changes[mode_count].caps = 0;
1217 <    mode_changes[mode_count].nocaps = 0;
1218 <    mode_changes[mode_count].mems = ALL_MEMBERS;
1025 >    mode_changes[mode_count].arg = "*";
1026      mode_changes[mode_count].id = NULL;
1027 <    mode_changes[mode_count++].arg = "*";
1027 >    mode_changes[mode_count++].dir = dir;
1028    }
1029   }
1030  
1031 < struct ChannelMode
1031 > const struct ChannelMode ModeTable[256] =
1032   {
1033 <  void (*func) (struct Client *client_p, struct Client *source_p,
1034 <                struct Channel *chptr, int parc, int *parn, char **parv,
1035 <                int *errors, int alev, int dir, char c, void *d,
1036 <                const char *chname);
1037 <  void *d;
1033 >  { chm_nosuch,  0 },                   /* 0x00 */
1034 >  { chm_nosuch,  0 },                   /* 0x01 */
1035 >  { chm_nosuch,  0 },                   /* 0x02 */
1036 >  { chm_nosuch,  0 },                   /* 0x03 */
1037 >  { chm_nosuch,  0 },                   /* 0x04 */
1038 >  { chm_nosuch,  0 },                   /* 0x05 */
1039 >  { chm_nosuch,  0 },                   /* 0x06 */
1040 >  { chm_nosuch,  0 },                   /* 0x07 */
1041 >  { chm_nosuch,  0 },                   /* 0x08 */
1042 >  { chm_nosuch,  0 },                   /* 0x09 */
1043 >  { chm_nosuch,  0 },                   /* 0x0a */
1044 >  { chm_nosuch,  0 },                   /* 0x0b */
1045 >  { chm_nosuch,  0 },                   /* 0x0c */
1046 >  { chm_nosuch,  0 },                   /* 0x0d */
1047 >  { chm_nosuch,  0 },                   /* 0x0e */
1048 >  { chm_nosuch,  0 },                   /* 0x0f */
1049 >  { chm_nosuch,  0 },                   /* 0x10 */
1050 >  { chm_nosuch,  0 },                   /* 0x11 */
1051 >  { chm_nosuch,  0 },                   /* 0x12 */
1052 >  { chm_nosuch,  0 },                   /* 0x13 */
1053 >  { chm_nosuch,  0 },                   /* 0x14 */
1054 >  { chm_nosuch,  0 },                   /* 0x15 */
1055 >  { chm_nosuch,  0 },                   /* 0x16 */
1056 >  { chm_nosuch,  0 },                   /* 0x17 */
1057 >  { chm_nosuch,  0 },                   /* 0x18 */
1058 >  { chm_nosuch,  0 },                   /* 0x19 */
1059 >  { chm_nosuch,  0 },                   /* 0x1a */
1060 >  { chm_nosuch,  0 },                   /* 0x1b */
1061 >  { chm_nosuch,  0 },                   /* 0x1c */
1062 >  { chm_nosuch,  0 },                   /* 0x1d */
1063 >  { chm_nosuch,  0 },                   /* 0x1e */
1064 >  { chm_nosuch,  0 },                   /* 0x1f */
1065 >  { chm_nosuch,  0 },                   /* 0x20 */
1066 >  { chm_nosuch,  0 },                   /* 0x21 */
1067 >  { chm_nosuch,  0 },                   /* 0x22 */
1068 >  { chm_nosuch,  0 },                   /* 0x23 */
1069 >  { chm_nosuch,  0 },                   /* 0x24 */
1070 >  { chm_nosuch,  0 },                   /* 0x25 */
1071 >  { chm_nosuch,  0 },                   /* 0x26 */
1072 >  { chm_nosuch,  0 },                   /* 0x27 */
1073 >  { chm_nosuch,  0 },                   /* 0x28 */
1074 >  { chm_nosuch,  0 },                   /* 0x29 */
1075 >  { chm_nosuch,  0 },                   /* 0x2a */
1076 >  { chm_nosuch,  0 },                   /* 0x2b */
1077 >  { chm_nosuch,  0 },                   /* 0x2c */
1078 >  { chm_nosuch,  0 },                   /* 0x2d */
1079 >  { chm_nosuch,  0 },                   /* 0x2e */
1080 >  { chm_nosuch,  0 },                   /* 0x2f */
1081 >  { chm_nosuch,  0 },                   /* 0x30 */
1082 >  { chm_nosuch,  0 },                   /* 0x31 */
1083 >  { chm_nosuch,  0 },                   /* 0x32 */
1084 >  { chm_nosuch,  0 },                   /* 0x33 */
1085 >  { chm_nosuch,  0 },                   /* 0x34 */
1086 >  { chm_nosuch,  0 },                   /* 0x35 */
1087 >  { chm_nosuch,  0 },                   /* 0x36 */
1088 >  { chm_nosuch,  0 },                   /* 0x37 */
1089 >  { chm_nosuch,  0 },                   /* 0x38 */
1090 >  { chm_nosuch,  0 },                   /* 0x39 */
1091 >  { chm_nosuch,  0 },                   /* 0x3a */
1092 >  { chm_nosuch,  0 },                   /* 0x3b */
1093 >  { chm_nosuch,  0 },                   /* 0x3c */
1094 >  { chm_nosuch,  0 },                   /* 0x3d */
1095 >  { chm_nosuch,  0 },                   /* 0x3e */
1096 >  { chm_nosuch,  0 },                   /* 0x3f */
1097 >  { chm_nosuch,  0 },                   /* @ */
1098 >  { chm_nosuch,  0 },                   /* A */
1099 >  { chm_nosuch,  0 },                   /* B */
1100 >  { chm_nosuch,  0 },                   /* C */
1101 >  { chm_nosuch,  0 },                   /* D */
1102 >  { chm_nosuch,  0 },                   /* E */
1103 >  { chm_nosuch,  0 },                   /* F */
1104 >  { chm_nosuch,  0 },                   /* G */
1105 >  { chm_nosuch,  0 },                   /* H */
1106 >  { chm_invex,   0 },                   /* I */
1107 >  { chm_nosuch,  0 },                   /* J */
1108 >  { chm_nosuch,  0 },                   /* K */
1109 >  { chm_nosuch,  0 },                   /* L */
1110 >  { chm_simple, MODE_MODREG},           /* M */
1111 >  { chm_nosuch,  0 },                   /* N */
1112 >  { chm_operonly, MODE_OPERONLY},       /* O */
1113 >  { chm_nosuch,  0 },                   /* P */
1114 >  { chm_nosuch,  0 },                   /* Q */
1115 >  { chm_simple, MODE_REGONLY},          /* R */
1116 >  { chm_simple, MODE_SSLONLY},          /* S */
1117 >  { chm_nosuch,  0 },                   /* T */
1118 >  { chm_nosuch,  0 },                   /* U */
1119 >  { chm_nosuch,  0 },                   /* V */
1120 >  { chm_nosuch,  0 },                   /* W */
1121 >  { chm_nosuch,  0 },                   /* X */
1122 >  { chm_nosuch,  0 },                   /* Y */
1123 >  { chm_nosuch,  0 },                   /* Z */
1124 >  { chm_nosuch,  0 },
1125 >  { chm_nosuch,  0 },
1126 >  { chm_nosuch,  0 },
1127 >  { chm_nosuch,  0 },
1128 >  { chm_nosuch,  0 },
1129 >  { chm_nosuch,  0 },
1130 >  { chm_nosuch,  0 },                   /* a */
1131 >  { chm_ban,     0 },                   /* b */
1132 >  { chm_simple, MODE_NOCTRL},           /* c */
1133 >  { chm_nosuch,  0 },                   /* d */
1134 >  { chm_except,  0 },                   /* e */
1135 >  { chm_nosuch,  0 },                   /* f */
1136 >  { chm_nosuch,  0 },                   /* g */
1137 >  { chm_hop,     0 },                   /* h */
1138 >  { chm_simple,     MODE_INVITEONLY },  /* i */
1139 >  { chm_nosuch,     0               },  /* j */
1140 >  { chm_key,        0               },  /* k */
1141 >  { chm_limit,      0               },  /* l */
1142 >  { chm_simple,     MODE_MODERATED  },  /* m */
1143 >  { chm_simple,     MODE_NOPRIVMSGS },  /* n */
1144 >  { chm_op,         0               },  /* o */
1145 >  { chm_simple,     MODE_PRIVATE    },  /* p */
1146 >  { chm_nosuch,     0               },  /* q */
1147 >  { chm_registered, MODE_REGISTERED },  /* r */
1148 >  { chm_simple,     MODE_SECRET     },  /* s */
1149 >  { chm_simple,     MODE_TOPICLIMIT },  /* t */
1150 >  { chm_nosuch,     0               },  /* u */
1151 >  { chm_voice,      0               },  /* v */
1152 >  { chm_nosuch,     0               },  /* w */
1153 >  { chm_nosuch,     0               },  /* x */
1154 >  { chm_nosuch,     0               },  /* y */
1155 >  { chm_nosuch,     0               },  /* z */
1156 >  { chm_nosuch,  0 },                   /* 0x7b */
1157 >  { chm_nosuch,  0 },                   /* 0x7c */
1158 >  { chm_nosuch,  0 },                   /* 0x7d */
1159 >  { chm_nosuch,  0 },                   /* 0x7e */
1160 >  { chm_nosuch,  0 },                   /* 0x7f */
1161 >  { chm_nosuch,  0 },                   /* 0x80 */
1162 >  { chm_nosuch,  0 },                   /* 0x81 */
1163 >  { chm_nosuch,  0 },                   /* 0x82 */
1164 >  { chm_nosuch,  0 },                   /* 0x83 */
1165 >  { chm_nosuch,  0 },                   /* 0x84 */
1166 >  { chm_nosuch,  0 },                   /* 0x85 */
1167 >  { chm_nosuch,  0 },                   /* 0x86 */
1168 >  { chm_nosuch,  0 },                   /* 0x87 */
1169 >  { chm_nosuch,  0 },                   /* 0x88 */
1170 >  { chm_nosuch,  0 },                   /* 0x89 */
1171 >  { chm_nosuch,  0 },                   /* 0x8a */
1172 >  { chm_nosuch,  0 },                   /* 0x8b */
1173 >  { chm_nosuch,  0 },                   /* 0x8c */
1174 >  { chm_nosuch,  0 },                   /* 0x8d */
1175 >  { chm_nosuch,  0 },                   /* 0x8e */
1176 >  { chm_nosuch,  0 },                   /* 0x8f */
1177 >  { chm_nosuch,  0 },                   /* 0x90 */
1178 >  { chm_nosuch,  0 },                   /* 0x91 */
1179 >  { chm_nosuch,  0 },                   /* 0x92 */
1180 >  { chm_nosuch,  0 },                   /* 0x93 */
1181 >  { chm_nosuch,  0 },                   /* 0x94 */
1182 >  { chm_nosuch,  0 },                   /* 0x95 */
1183 >  { chm_nosuch,  0 },                   /* 0x96 */
1184 >  { chm_nosuch,  0 },                   /* 0x97 */
1185 >  { chm_nosuch,  0 },                   /* 0x98 */
1186 >  { chm_nosuch,  0 },                   /* 0x99 */
1187 >  { chm_nosuch,  0 },                   /* 0x9a */
1188 >  { chm_nosuch,  0 },                   /* 0x9b */
1189 >  { chm_nosuch,  0 },                   /* 0x9c */
1190 >  { chm_nosuch,  0 },                   /* 0x9d */
1191 >  { chm_nosuch,  0 },                   /* 0x9e */
1192 >  { chm_nosuch,  0 },                   /* 0x9f */
1193 >  { chm_nosuch,  0 },                   /* 0xa0 */
1194 >  { chm_nosuch,  0 },                   /* 0xa1 */
1195 >  { chm_nosuch,  0 },                   /* 0xa2 */
1196 >  { chm_nosuch,  0 },                   /* 0xa3 */
1197 >  { chm_nosuch,  0 },                   /* 0xa4 */
1198 >  { chm_nosuch,  0 },                   /* 0xa5 */
1199 >  { chm_nosuch,  0 },                   /* 0xa6 */
1200 >  { chm_nosuch,  0 },                   /* 0xa7 */
1201 >  { chm_nosuch,  0 },                   /* 0xa8 */
1202 >  { chm_nosuch,  0 },                   /* 0xa9 */
1203 >  { chm_nosuch,  0 },                   /* 0xaa */
1204 >  { chm_nosuch,  0 },                   /* 0xab */
1205 >  { chm_nosuch,  0 },                   /* 0xac */
1206 >  { chm_nosuch,  0 },                   /* 0xad */
1207 >  { chm_nosuch,  0 },                   /* 0xae */
1208 >  { chm_nosuch,  0 },                   /* 0xaf */
1209 >  { chm_nosuch,  0 },                   /* 0xb0 */
1210 >  { chm_nosuch,  0 },                   /* 0xb1 */
1211 >  { chm_nosuch,  0 },                   /* 0xb2 */
1212 >  { chm_nosuch,  0 },                   /* 0xb3 */
1213 >  { chm_nosuch,  0 },                   /* 0xb4 */
1214 >  { chm_nosuch,  0 },                   /* 0xb5 */
1215 >  { chm_nosuch,  0 },                   /* 0xb6 */
1216 >  { chm_nosuch,  0 },                   /* 0xb7 */
1217 >  { chm_nosuch,  0 },                   /* 0xb8 */
1218 >  { chm_nosuch,  0 },                   /* 0xb9 */
1219 >  { chm_nosuch,  0 },                   /* 0xba */
1220 >  { chm_nosuch,  0 },                   /* 0xbb */
1221 >  { chm_nosuch,  0 },                   /* 0xbc */
1222 >  { chm_nosuch,  0 },                   /* 0xbd */
1223 >  { chm_nosuch,  0 },                   /* 0xbe */
1224 >  { chm_nosuch,  0 },                   /* 0xbf */
1225 >  { chm_nosuch,  0 },                   /* 0xc0 */
1226 >  { chm_nosuch,  0 },                   /* 0xc1 */
1227 >  { chm_nosuch,  0 },                   /* 0xc2 */
1228 >  { chm_nosuch,  0 },                   /* 0xc3 */
1229 >  { chm_nosuch,  0 },                   /* 0xc4 */
1230 >  { chm_nosuch,  0 },                   /* 0xc5 */
1231 >  { chm_nosuch,  0 },                   /* 0xc6 */
1232 >  { chm_nosuch,  0 },                   /* 0xc7 */
1233 >  { chm_nosuch,  0 },                   /* 0xc8 */
1234 >  { chm_nosuch,  0 },                   /* 0xc9 */
1235 >  { chm_nosuch,  0 },                   /* 0xca */
1236 >  { chm_nosuch,  0 },                   /* 0xcb */
1237 >  { chm_nosuch,  0 },                   /* 0xcc */
1238 >  { chm_nosuch,  0 },                   /* 0xcd */
1239 >  { chm_nosuch,  0 },                   /* 0xce */
1240 >  { chm_nosuch,  0 },                   /* 0xcf */
1241 >  { chm_nosuch,  0 },                   /* 0xd0 */
1242 >  { chm_nosuch,  0 },                   /* 0xd1 */
1243 >  { chm_nosuch,  0 },                   /* 0xd2 */
1244 >  { chm_nosuch,  0 },                   /* 0xd3 */
1245 >  { chm_nosuch,  0 },                   /* 0xd4 */
1246 >  { chm_nosuch,  0 },                   /* 0xd5 */
1247 >  { chm_nosuch,  0 },                   /* 0xd6 */
1248 >  { chm_nosuch,  0 },                   /* 0xd7 */
1249 >  { chm_nosuch,  0 },                   /* 0xd8 */
1250 >  { chm_nosuch,  0 },                   /* 0xd9 */
1251 >  { chm_nosuch,  0 },                   /* 0xda */
1252 >  { chm_nosuch,  0 },                   /* 0xdb */
1253 >  { chm_nosuch,  0 },                   /* 0xdc */
1254 >  { chm_nosuch,  0 },                   /* 0xdd */
1255 >  { chm_nosuch,  0 },                   /* 0xde */
1256 >  { chm_nosuch,  0 },                   /* 0xdf */
1257 >  { chm_nosuch,  0 },                   /* 0xe0 */
1258 >  { chm_nosuch,  0 },                   /* 0xe1 */
1259 >  { chm_nosuch,  0 },                   /* 0xe2 */
1260 >  { chm_nosuch,  0 },                   /* 0xe3 */
1261 >  { chm_nosuch,  0 },                   /* 0xe4 */
1262 >  { chm_nosuch,  0 },                   /* 0xe5 */
1263 >  { chm_nosuch,  0 },                   /* 0xe6 */
1264 >  { chm_nosuch,  0 },                   /* 0xe7 */
1265 >  { chm_nosuch,  0 },                   /* 0xe8 */
1266 >  { chm_nosuch,  0 },                   /* 0xe9 */
1267 >  { chm_nosuch,  0 },                   /* 0xea */
1268 >  { chm_nosuch,  0 },                   /* 0xeb */
1269 >  { chm_nosuch,  0 },                   /* 0xec */
1270 >  { chm_nosuch,  0 },                   /* 0xed */
1271 >  { chm_nosuch,  0 },                   /* 0xee */
1272 >  { chm_nosuch,  0 },                   /* 0xef */
1273 >  { chm_nosuch,  0 },                   /* 0xf0 */
1274 >  { chm_nosuch,  0 },                   /* 0xf1 */
1275 >  { chm_nosuch,  0 },                   /* 0xf2 */
1276 >  { chm_nosuch,  0 },                   /* 0xf3 */
1277 >  { chm_nosuch,  0 },                   /* 0xf4 */
1278 >  { chm_nosuch,  0 },                   /* 0xf5 */
1279 >  { chm_nosuch,  0 },                   /* 0xf6 */
1280 >  { chm_nosuch,  0 },                   /* 0xf7 */
1281 >  { chm_nosuch,  0 },                   /* 0xf8 */
1282 >  { chm_nosuch,  0 },                   /* 0xf9 */
1283 >  { chm_nosuch,  0 },                   /* 0xfa */
1284 >  { chm_nosuch,  0 },                   /* 0xfb */
1285 >  { chm_nosuch,  0 },                   /* 0xfc */
1286 >  { chm_nosuch,  0 },                   /* 0xfd */
1287 >  { chm_nosuch,  0 },                   /* 0xfe */
1288 >  { chm_nosuch,  0 },                   /* 0xff */
1289   };
1290  
1233 – /* *INDENT-OFF* */
1234 – static struct ChannelMode ModeTable[255] =
1235 – {
1236 –  {chm_nosuch, NULL},
1237 –  {chm_nosuch, NULL},                             /* A */
1238 –  {chm_nosuch, NULL},                             /* B */
1239 –  {chm_nosuch, NULL},                             /* C */
1240 –  {chm_nosuch, NULL},                             /* D */
1241 –  {chm_nosuch, NULL},                             /* E */
1242 –  {chm_nosuch, NULL},                             /* F */
1243 –  {chm_nosuch, NULL},                             /* G */
1244 –  {chm_nosuch, NULL},                             /* H */
1245 –  {chm_invex, NULL},                              /* I */
1246 –  {chm_nosuch, NULL},                             /* J */
1247 –  {chm_nosuch, NULL},                             /* K */
1248 –  {chm_nosuch, NULL},                             /* L */
1249 –  {chm_nosuch, NULL},                             /* M */
1250 –  {chm_nosuch, NULL},                             /* N */
1251 –  {chm_nosuch, NULL},                             /* O */
1252 –  {chm_nosuch, NULL},                             /* P */
1253 –  {chm_nosuch, NULL},                             /* Q */
1254 –  {chm_nosuch, NULL},                             /* R */
1255 –  {chm_nosuch, NULL},                             /* S */
1256 –  {chm_nosuch, NULL},                             /* T */
1257 –  {chm_nosuch, NULL},                             /* U */
1258 –  {chm_nosuch, NULL},                             /* V */
1259 –  {chm_nosuch, NULL},                             /* W */
1260 –  {chm_nosuch, NULL},                             /* X */
1261 –  {chm_nosuch, NULL},                             /* Y */
1262 –  {chm_nosuch, NULL},                             /* Z */
1263 –  {chm_nosuch, NULL},
1264 –  {chm_nosuch, NULL},
1265 –  {chm_nosuch, NULL},
1266 –  {chm_nosuch, NULL},
1267 –  {chm_nosuch, NULL},
1268 –  {chm_nosuch, NULL},
1269 –  {chm_nosuch, NULL},                             /* a */
1270 –  {chm_ban, NULL},                                /* b */
1271 –  {chm_nosuch, NULL},                             /* c */
1272 –  {chm_nosuch, NULL},                             /* d */
1273 –  {chm_except, NULL},                             /* e */
1274 –  {chm_nosuch, NULL},                             /* f */
1275 –  {chm_nosuch, NULL},                             /* g */
1276 – #ifdef HALFOPS
1277 –  {chm_hop, NULL},                                /* h */
1278 – #else
1279 –  {chm_nosuch, NULL},                             /* h */
1280 – #endif
1281 –  {chm_simple, (void *) MODE_INVITEONLY},         /* i */
1282 –  {chm_nosuch, NULL},                             /* j */
1283 –  {chm_key, NULL},                                /* k */
1284 –  {chm_limit, NULL},                              /* l */
1285 –  {chm_simple, (void *) MODE_MODERATED},          /* m */
1286 –  {chm_simple, (void *) MODE_NOPRIVMSGS},         /* n */
1287 –  {chm_op, NULL},                                 /* o */
1288 –  {chm_simple, (void *) MODE_PRIVATE},            /* p */
1289 –  {chm_nosuch, NULL},                             /* q */
1290 –  {chm_nosuch, NULL},                             /* r */
1291 –  {chm_simple, (void *) MODE_SECRET},             /* s */
1292 –  {chm_simple, (void *) MODE_TOPICLIMIT},         /* t */
1293 –  {chm_nosuch, NULL},                             /* u */
1294 –  {chm_voice, NULL},                              /* v */
1295 –  {chm_nosuch, NULL},                             /* w */
1296 –  {chm_nosuch, NULL},                             /* x */
1297 –  {chm_nosuch, NULL},                             /* y */
1298 –  {chm_nosuch, NULL},                             /* z */
1299 – };
1300 – /* *INDENT-ON* */
1301 –
1291   /* get_channel_access()
1292   *
1293   * inputs       - pointer to Client struct
# Line 1308 | Line 1297 | static struct ChannelMode ModeTable[255]
1297   * side effects - NONE
1298   */
1299   static int
1300 < get_channel_access(struct Client *source_p, struct Membership *member)
1300 > get_channel_access(const struct Client *source_p,
1301 >                   const struct Membership *member)
1302   {
1303    /* Let hacked servers in for now... */
1304    if (!MyClient(source_p))
1305 <    return CHACCESS_CHANOP;
1305 >    return CHACCESS_REMOTE;
1306  
1307 <  if (member == NULL)
1307 >  if (!member)
1308      return CHACCESS_NOTONCHAN;
1309  
1310 <  /* just to be sure.. */
1310 >  /* Just to be sure.. */
1311    assert(source_p == member->client_p);
1312  
1313    if (has_member_flags(member, CHFL_CHANOP))
1314      return CHACCESS_CHANOP;
1315  
1326 – #ifdef HALFOPS
1316    if (has_member_flags(member, CHFL_HALFOP))
1317      return CHACCESS_HALFOP;
1329 – #endif
1318  
1319    return CHACCESS_PEON;
1320   }
1321  
1322 < /* void send_cap_mode_changes(struct Client *client_p,
1323 < *                        struct Client *source_p,
1336 < *                        struct Channel *chptr, int cap, int nocap)
1337 < * Input: The client sending(client_p), the source client(source_p),
1322 > /* send_mode_changes_server()
1323 > * Input: the source client(source_p),
1324   *        the channel to send mode changes for(chptr)
1325   * Output: None.
1326 < * Side-effects: Sends the appropriate mode changes to capable servers.
1341 < *
1342 < * send_cap_mode_changes() will loop the server list itself, because
1343 < * at this point in time we have 4 capabs for channels, CAP_IE, CAP_EX,
1344 < * and a server could support any number of these..
1345 < * so we make the modebufs per server, tailoring them to each servers
1346 < * specific demand.  Its not very pretty, but its one of the few realistic
1347 < * ways to handle having this many capabs for channel modes.. --fl_
1326 > * Side-effects: Sends the appropriate mode changes to servers.
1327   *
1349 – * Reverted back to my original design, except that we now keep a count
1350 – * of the number of servers which each combination as an optimisation, so
1351 – * the capabs combinations which are not needed are not worked out. -A1kmm
1328   */
1353 – /* rewritten to ensure parabuf < MODEBUFLEN -db */
1354 –
1329   static void
1330 < send_cap_mode_changes(struct Client *client_p, struct Client *source_p,
1357 <                      struct Channel *chptr, int cap, int nocap)
1330 > send_mode_changes_server(struct Client *source_p, struct Channel *chptr)
1331   {
1332 <  int i, mbl, pbl, arglen, nc, mc;
1333 <  int len;
1361 <  const char *arg = NULL;
1362 <  char *parptr;
1332 >  int mbl = 0, pbl = 0, arglen = 0, nc = 0, mc = 0;
1333 >  int len = 0;
1334    int dir = MODE_QUERY;
1335 <
1336 <  mc = 0;
1366 <  nc = 0;
1367 <  pbl = 0;
1335 >  const char *arg = NULL;
1336 >  char *parptr = NULL;
1337  
1338    parabuf[0] = '\0';
1339    parptr = parabuf;
1340  
1341 <  if ((cap & CAP_TS6) && source_p->id[0] != '\0')
1342 <    mbl = ircsprintf(modebuf, ":%s TMODE %lu %s ", source_p->id,
1374 <                     (unsigned long)chptr->channelts, chptr->chname);
1375 <  else
1376 <    mbl = ircsprintf(modebuf, ":%s MODE %s ", source_p->name,
1377 <                     chptr->chname);
1341 >  mbl = snprintf(modebuf, sizeof(modebuf), ":%s TMODE %lu %s ", source_p->id,
1342 >                 (unsigned long)chptr->creationtime, chptr->name);
1343  
1344 <  /* loop the list of - modes we have */
1345 <  for (i = 0; i < mode_count; i++)
1344 >  /* Loop the list of modes we have */
1345 >  for (unsigned i = 0; i < mode_count; ++i)
1346    {
1347 <    /* if they dont support the cap we need, or they do support a cap they
1383 <     * cant have, then dont add it to the modebuf.. that way they wont see
1384 <     * the mode
1385 <     */
1386 <    if ((mode_changes[i].letter == 0) ||
1387 <        ((cap & mode_changes[i].caps) != mode_changes[i].caps)
1388 <        || ((nocap & mode_changes[i].nocaps) != mode_changes[i].nocaps))
1347 >    if (mode_changes[i].letter == 0)
1348        continue;
1349  
1350 <    arg = "";
1392 <
1393 <    if ((cap & CAP_TS6) && mode_changes[i].id)
1350 >    if (mode_changes[i].id)
1351        arg = mode_changes[i].id;
1352 <    if (*arg == '\0')
1352 >    else
1353        arg = mode_changes[i].arg;
1354  
1355 <    /* if we're creeping past the buf size, we need to send it and make
1399 <     * another line for the other modes
1400 <     * XXX - this could give away server topology with uids being
1401 <     * different lengths, but not much we can do, except possibly break
1402 <     * them as if they were the longest of the nick or uid at all times,
1403 <     * which even then won't work as we don't always know the uid -A1kmm.
1404 <     */
1405 <    if (arg != NULL)
1355 >    if (arg)
1356        arglen = strlen(arg);
1357      else
1358        arglen = 0;
1359  
1360 +    /*
1361 +     * If we're creeping past the buf size, we need to send it and make
1362 +     * another line for the other modes
1363 +     */
1364      if ((mc == MAXMODEPARAMS) ||
1365          ((arglen + mbl + pbl + 2) > IRCD_BUFSIZE) ||
1366          (pbl + arglen + BAN_FUDGE) >= MODEBUFLEN)
1367      {
1368 <      if (nc != 0)
1369 <        sendto_server(client_p, source_p, chptr, cap, nocap,
1370 <                      LL_ICHAN | LL_ICLIENT, "%s %s",
1417 <                      modebuf, parabuf);
1368 >      if (nc)
1369 >        sendto_server(source_p, 0, 0, "%s %s", modebuf, parabuf);
1370 >
1371        nc = 0;
1372        mc = 0;
1373  
1374 <      if ((cap & CAP_TS6) && source_p->id[0] != '\0')
1375 <        mbl = ircsprintf(modebuf, ":%s MODE %s ", source_p->id,
1423 <                         chptr->chname);
1424 <      else
1425 <        mbl = ircsprintf(modebuf, ":%s MODE %s ", source_p->name,
1426 <                         chptr->chname);
1374 >      mbl = snprintf(modebuf, sizeof(modebuf), ":%s TMODE %lu %s ", source_p->id,
1375 >                     (unsigned long)chptr->creationtime, chptr->name);
1376  
1377        pbl = 0;
1378        parabuf[0] = '\0';
# Line 1439 | Line 1388 | send_cap_mode_changes(struct Client *cli
1388  
1389      modebuf[mbl++] = mode_changes[i].letter;
1390      modebuf[mbl] = '\0';
1391 <    nc++;
1391 >    ++nc;
1392  
1393 <    if (arg != NULL)
1393 >    if (arg)
1394      {
1395 <      len = ircsprintf(parptr, "%s ", arg);
1395 >      len = sprintf(parptr, "%s ", arg);
1396        pbl += len;
1397        parptr += len;
1398 <      mc++;
1398 >      ++mc;
1399      }
1400    }
1401  
1402    if (pbl && parabuf[pbl - 1] == ' ')
1403 <    parabuf[pbl - 1] = 0;
1403 >    parabuf[pbl - 1] = '\0';
1404  
1405 <  if (nc != 0)
1406 <    sendto_server(client_p, source_p, chptr, cap, nocap,
1458 <                  LL_ICLIENT, "%s %s", modebuf, parabuf);
1405 >  if (nc)
1406 >    sendto_server(source_p, 0, 0, "%s %s", modebuf, parabuf);
1407   }
1408  
1409   /* void send_mode_changes(struct Client *client_p,
# Line 1470 | Line 1418 | send_cap_mode_changes(struct Client *cli
1418   */
1419   /* ensure parabuf < MODEBUFLEN -db */
1420   static void
1421 < send_mode_changes(struct Client *client_p, struct Client *source_p,
1474 <                  struct Channel *chptr, char *chname)
1421 > send_mode_changes(struct Client *source_p, struct Channel *chptr)
1422   {
1423 <  int i, mbl, pbl, arglen, nc, mc;
1424 <  int len;
1478 <  const char *arg = NULL;
1479 <  char *parptr;
1423 >  int mbl = 0, pbl = 0, arglen = 0, nc = 0, mc = 0;
1424 >  int len = 0;
1425    int dir = MODE_QUERY;
1426 +  const char *arg = NULL;
1427 +  char *parptr = NULL;
1428  
1429 <  /* bail out if we have nothing to do... */
1429 >  /* Bail out if we have nothing to do... */
1430    if (!mode_count)
1431      return;
1432  
1433    if (IsServer(source_p))
1434 <    mbl = ircsprintf(modebuf, ":%s MODE %s ", (IsHidden(source_p) ||
1435 <                     ConfigServerHide.hide_servers) ?
1436 <                     me.name : source_p->name, chname);
1434 >    mbl = snprintf(modebuf, sizeof(modebuf), ":%s MODE %s ", (IsHidden(source_p) ||
1435 >                   ConfigServerHide.hide_servers) ?
1436 >                   me.name : source_p->name, chptr->name);
1437    else
1438 <    mbl = ircsprintf(modebuf, ":%s!%s@%s MODE %s ", source_p->name,
1439 <                     source_p->username, source_p->host, chname);
1493 <
1494 <  mc = 0;
1495 <  nc = 0;
1496 <  pbl = 0;
1438 >    mbl = snprintf(modebuf, sizeof(modebuf), ":%s!%s@%s MODE %s ", source_p->name,
1439 >                   source_p->username, source_p->host, chptr->name);
1440  
1441    parabuf[0] = '\0';
1442    parptr = parabuf;
1443  
1444 <  for (i = 0; i < mode_count; i++)
1444 >  for (unsigned int i = 0; i < mode_count; ++i)
1445    {
1446 <    if (mode_changes[i].letter == 0 ||
1504 <        mode_changes[i].mems == NON_CHANOPS ||
1505 <        mode_changes[i].mems == ONLY_SERVERS)
1446 >    if (mode_changes[i].letter == 0)
1447        continue;
1448  
1449      arg = mode_changes[i].arg;
1450 <    if (arg != NULL)
1450 >    if (arg)
1451        arglen = strlen(arg);
1452      else
1453        arglen = 0;
1454  
1455 <    if ((mc == MAXMODEPARAMS)  ||
1455 >    if ((mc == MAXMODEPARAMS) ||
1456          ((arglen + mbl + pbl + 2) > IRCD_BUFSIZE) ||
1457 <        ((arglen + pbl + BAN_FUDGE) >= MODEBUFLEN))
1457 >        ((arglen + pbl + BAN_FUDGE) >= MODEBUFLEN))
1458      {
1459        if (mbl && modebuf[mbl - 1] == '-')
1460          modebuf[mbl - 1] = '\0';
1461  
1462 <      if (nc != 0)
1463 <        sendto_channel_local(ALL_MEMBERS, NO, chptr, "%s %s", modebuf, parabuf);
1462 >      if (nc)
1463 >        sendto_channel_local(0, chptr, "%s %s", modebuf, parabuf);
1464  
1465        nc = 0;
1466        mc = 0;
1467  
1468        if (IsServer(source_p))
1469 <        mbl = ircsprintf(modebuf, ":%s MODE %s ", me.name, chname);
1469 >        mbl = snprintf(modebuf, sizeof(modebuf), ":%s MODE %s ", (IsHidden(source_p) ||
1470 >                       ConfigServerHide.hide_servers) ?
1471 >                       me.name : source_p->name, chptr->name);
1472        else
1473 <        mbl = ircsprintf(modebuf, ":%s!%s@%s MODE %s ", source_p->name,
1474 <                         source_p->username, source_p->host, chname);
1473 >        mbl = snprintf(modebuf, sizeof(modebuf), ":%s!%s@%s MODE %s ", source_p->name,
1474 >                       source_p->username, source_p->host, chptr->name);
1475  
1476        pbl = 0;
1477        parabuf[0] = '\0';
# Line 1544 | Line 1487 | send_mode_changes(struct Client *client_
1487  
1488      modebuf[mbl++] = mode_changes[i].letter;
1489      modebuf[mbl] = '\0';
1490 <    nc++;
1490 >    ++nc;
1491  
1492 <    if (arg != NULL)
1492 >    if (arg)
1493      {
1494 <      len = ircsprintf(parptr, "%s ", arg);
1494 >      len = sprintf(parptr, "%s ", arg);
1495        pbl += len;
1496        parptr += len;
1497 <      mc++;
1497 >      ++mc;
1498      }
1499    }
1500  
1501    if (pbl && parabuf[pbl - 1] == ' ')
1502 <    parabuf[pbl - 1] = 0;
1502 >    parabuf[pbl - 1] = '\0';
1503  
1504 <  if (nc != 0)
1505 <    sendto_channel_local(ALL_MEMBERS, NO, chptr, "%s %s", modebuf, parabuf);
1504 >  if (nc)
1505 >    sendto_channel_local(0, chptr, "%s %s", modebuf, parabuf);
1506  
1507 <  nc = 0;
1508 <  mc = 0;
1507 >  send_mode_changes_server(source_p, chptr);
1508 > }
1509  
1510 <  /* Now send to servers... */
1511 <  for (i = 0; i < NCHCAP_COMBOS; i++)
1569 <    if (chcap_combos[i].count != 0)
1570 <      send_cap_mode_changes(client_p, source_p, chptr,
1571 <                            chcap_combos[i].cap_yes,
1572 <                            chcap_combos[i].cap_no);
1573 < }
1574 <
1575 < /* void set_channel_mode(struct Client *client_p, struct Client *source_p,
1576 < *               struct Channel *chptr, int parc, char **parv,
1577 < *               char *chname)
1578 < * Input: The client we received this from, the client this originated
1510 > /*
1511 > * Input: The the client this originated
1512   *        from, the channel, the parameter count starting at the modes,
1513   *        the parameters, the channel name.
1514   * Output: None.
# Line 1584 | Line 1517 | send_mode_changes(struct Client *client_
1517   *               clients.
1518   */
1519   void
1520 < set_channel_mode(struct Client *client_p, struct Client *source_p, struct Channel *chptr,
1521 <                 struct Membership *member, int parc, char *parv[], char *chname)
1520 > set_channel_mode(struct Client *source_p, struct Channel *chptr,
1521 >                 struct Membership *member, int parc, char *parv[])
1522   {
1523    int dir = MODE_ADD;
1524    int parn = 1;
1525 <  int alevel, errors = 0;
1593 <  char *ml = parv[0], c;
1594 <  int table_position;
1525 >  int alevel = 0, errors = 0;
1526  
1527    mode_count = 0;
1528    mode_limit = 0;
# Line 1599 | Line 1530 | set_channel_mode(struct Client *client_p
1530  
1531    alevel = get_channel_access(source_p, member);
1532  
1533 <  for (; (c = *ml) != '\0'; ml++)
1533 >  for (const char *ml = parv[0]; *ml; ++ml)
1534    {
1535 < #if 0
1605 <    if(mode_count > 20)
1606 <      break;
1607 < #endif
1608 <    switch (c)
1535 >    switch (*ml)
1536      {
1537        case '+':
1538          dir = MODE_ADD;
# Line 1617 | Line 1544 | set_channel_mode(struct Client *client_p
1544          dir = MODE_QUERY;
1545          break;
1546        default:
1547 <        if (c < 'A' || c > 'z')
1548 <          table_position = 0;
1549 <        else
1550 <          table_position = c - 'A' + 1;
1551 <        ModeTable[table_position].func(client_p, source_p, chptr,
1625 <                                       parc, &parn,
1626 <                                       parv, &errors, alevel, dir, c,
1627 <                                       ModeTable[table_position].d,
1628 <                                       chname);
1547 >      {
1548 >        const struct ChannelMode *tptr = &ModeTable[(unsigned char)*ml];
1549 >
1550 >        tptr->func(source_p, chptr, parc, &parn, parv,
1551 >                   &errors, alevel, dir, *ml, tptr->d);
1552          break;
1553 +      }
1554      }
1555    }
1556  
1557 <  send_mode_changes(client_p, source_p, chptr, chname);
1557 >  send_mode_changes(source_p, chptr);
1558   }

Comparing:
ircd-hybrid/src/channel_mode.c (property svn:keywords), Revision 30 by adx, Sun Oct 2 20:03:27 2005 UTC vs.
ircd-hybrid/trunk/src/channel_mode.c (property svn:keywords), Revision 5031 by michael, Sat Dec 13 15:13:16 2014 UTC

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

Diff Legend

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