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 8044 by michael, Sat Mar 18 16:52:10 2017 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-2017 ircd-hybrid development team
5   *
6   *  This program is free software; you can redistribute it and/or modify
7   *  it under the terms of the GNU General Public License as published by
# Line 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"
40 > #include "mempool.h"
41 > #include "parse.h"
42 >
43  
44 < /* 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 *);
87 <
88 < /* 10 is a magic number in hybrid 6 NFI where it comes from -db */
89 < #define BAN_FUDGE       10
90 < #define NCHCAPS         (sizeof(channel_capabs)/sizeof(int))
91 < #define NCHCAP_COMBOS   (1 << NCHCAPS)
92 <
93 < /* some buffers for rebuilding channel/nick lists with ,'s */
94 < static char modebuf[IRCD_BUFSIZE];
95 < static char parabuf[MODEBUFLEN];
44 > static char nuh_mask[MAXPARA][IRCD_BUFSIZE];
45   static struct ChModeChange mode_changes[IRCD_BUFSIZE];
46 < static int mode_count;
47 < static int mode_limit;          /* number of modes set other than simple */
48 < static int simple_modes_mask;   /* bit mask of simple modes already set */
49 < static int channel_capabs[] = { CAP_EX, CAP_IE, CAP_TS6 };
50 < static struct ChCapCombo chcap_combos[NCHCAP_COMBOS];
51 < extern BlockHeap *ban_heap;
46 > static unsigned int mode_count;
47 > static unsigned int mode_limit;  /* number of modes set other than simple */
48 > static unsigned int simple_modes_mask;  /* bit mask of simple modes already set */
49 > extern mp_pool_t *ban_pool;
50 >
51 > const struct mode_letter chan_modes[] =
52 > {
53 >  { MODE_NOCTRL,     'c' },
54 >  { MODE_INVITEONLY, 'i' },
55 >  { MODE_MODERATED,  'm' },
56 >  { MODE_NOPRIVMSGS, 'n' },
57 >  { MODE_PRIVATE,    'p' },
58 >  { MODE_REGISTERED, 'r' },
59 >  { MODE_SECRET,     's' },
60 >  { MODE_TOPICLIMIT, 't' },
61 >  { MODE_HIDEBMASKS, 'u' },
62 >  { MODE_NOCTCP,     'C' },
63 >  { MODE_MODREG,     'M' },
64 >  { MODE_OPERONLY,   'O' },
65 >  { MODE_REGONLY,    'R' },
66 >  { MODE_SSLONLY,    'S' },
67 >  { MODE_NONOTICE,   'T' },
68 >  { 0, '\0' }
69 > };
70  
71  
105 – /* XXX check_string is propably not longer required in add_id and del_id */
72   /* check_string()
73   *
74   * inputs       - string to check
# Line 115 | Line 81 | extern BlockHeap *ban_heap;
81   static char *
82   check_string(char *s)
83   {
84 <  char *str = s;
84 >  char *const str = s;
85    static char star[] = "*";
86  
87 <  if (EmptyString(s))
88 <    return (star);
87 >  if (EmptyString(str))
88 >    return star;
89  
90    for (; *s; ++s)
91    {
# Line 130 | Line 96 | check_string(char *s)
96      }
97    }
98  
99 <  return (str);
99 >  return EmptyString(str) ? star : str;
100   }
101  
102   /*
103 < * Ban functions to work with mode +b/e/d/I
103 > * Ban functions to work with mode +b/e/I
104   */
105 < /* add the specified ID to the channel..
106 < *   -is 8/9/00
105 > /* add the specified ID to the channel.
106 > *   -is 8/9/00
107   */
108  
109   int
110 < add_id(struct Client *client_p, struct Channel *chptr, char *banid, int type)
110 > add_id(struct Client *client_p, struct Channel *chptr, char *banid, unsigned int type)
111   {
112    dlink_list *list;
113 <  dlink_node *ban;
114 <  size_t len = 0;
115 <  struct Ban *actualBan;
116 <  unsigned int num_mask;
117 <  char *name = NULL, *user = NULL, *host = NULL;
113 >  dlink_node *node;
114 >  char name[NICKLEN + 1] = "";
115 >  char user[USERLEN + 1] = "";
116 >  char host[HOSTLEN + 1] = "";
117 >  struct split_nuh_item nuh;
118  
119 <  /* dont let local clients overflow the b/e/I lists */
119 >  /* Don't let local clients overflow the b/e/I lists */
120    if (MyClient(client_p))
121    {
122 <    num_mask = dlink_list_length(&chptr->banlist) +
123 <               dlink_list_length(&chptr->exceptlist) +
124 <               dlink_list_length(&chptr->invexlist);
122 >    unsigned int num_mask = dlink_list_length(&chptr->banlist) +
123 >                            dlink_list_length(&chptr->exceptlist) +
124 >                            dlink_list_length(&chptr->invexlist);
125  
126      if (num_mask >= ConfigChannel.max_bans)
127      {
128 <      sendto_one(client_p, form_str(ERR_BANLISTFULL),
163 <                 me.name, client_p->name, chptr->chname, banid);
128 >      sendto_one_numeric(client_p, &me, ERR_BANLISTFULL, chptr->name, banid);
129        return 0;
130      }
131  
132      collapse(banid);
133    }
134  
135 <  split_nuh(check_string(banid), &name, &user, &host);
135 >  nuh.nuhmask  = check_string(banid);
136 >  nuh.nickptr  = name;
137 >  nuh.userptr  = user;
138 >  nuh.hostptr  = host;
139 >
140 >  nuh.nicksize = sizeof(name);
141 >  nuh.usersize = sizeof(user);
142 >  nuh.hostsize = sizeof(host);
143 >
144 >  split_nuh(&nuh);
145  
146    /*
147 <   * Assemble a n!u@h and print it back to banid for sending
147 >   * Re-assemble a new n!u@h and print it back to banid for sending
148     * the mode to the channel.
149     */
150 <  len = ircsprintf(banid, "%s!%s@%s", name, user, host);
150 >  size_t len = snprintf(banid, IRCD_BUFSIZE, "%s!%s@%s", name, user, host);
151  
152    switch (type)
153    {
154      case CHFL_BAN:
155        list = &chptr->banlist;
156 <      clear_ban_cache(chptr);
156 >      clear_ban_cache_list(&chptr->locmembers);
157        break;
158      case CHFL_EXCEPTION:
159        list = &chptr->exceptlist;
160 <      clear_ban_cache(chptr);
160 >      clear_ban_cache_list(&chptr->locmembers);
161        break;
162      case CHFL_INVEX:
163        list = &chptr->invexlist;
164        break;
165      default:
166 <      assert(0);
193 <      return 0;
166 >      list = NULL;  /* Let it crash */
167    }
168  
169 <  DLINK_FOREACH(ban, list->head)
169 >  DLINK_FOREACH(node, list->head)
170    {
171 <    actualBan = ban->data;
172 <    if (!irccmp(actualBan->name, name) &&
173 <        !irccmp(actualBan->username, user) &&
174 <        !irccmp(actualBan->host, host))
175 <    {
203 <      MyFree(name);
204 <      MyFree(user);
205 <      MyFree(host);
171 >    const struct Ban *ban = node->data;
172 >
173 >    if (!irccmp(ban->name, name) &&
174 >        !irccmp(ban->user, user) &&
175 >        !irccmp(ban->host, host))
176        return 0;
207 –    }
177    }
178  
179 <  actualBan = BlockHeapAlloc(ban_heap);
180 <  actualBan->when = CurrentTime;
181 <  actualBan->name = name;
182 <  actualBan->username = user;
183 <  actualBan->host = host;
184 <  actualBan->len = len-2; /* -2 for @ and ! */
179 >  struct Ban *ban = mp_pool_get(ban_pool);
180 >  ban->when = CurrentTime;
181 >  ban->len = len - 2;  /* -2 for ! + @ */
182 >  ban->type = parse_netmask(host, &ban->addr, &ban->bits);
183 >  strlcpy(ban->name, name, sizeof(ban->name));
184 >  strlcpy(ban->user, user, sizeof(ban->user));
185 >  strlcpy(ban->host, host, sizeof(ban->host));
186  
187    if (IsClient(client_p))
188 <  {
189 <    actualBan->who =
190 <      MyMalloc(strlen(client_p->name) +
191 <               strlen(client_p->username) +
222 <               strlen(client_p->host) + 3);
223 <    ircsprintf(actualBan->who, "%s!%s@%s",
224 <               client_p->name, client_p->username, client_p->host);
225 <  }
188 >    snprintf(ban->who, sizeof(ban->who), "%s!%s@%s", client_p->name,
189 >             client_p->username, client_p->host);
190 >  else if (IsHidden(client_p) || ConfigServerHide.hide_servers)
191 >    strlcpy(ban->who, me.name, sizeof(ban->who));
192    else
193 <    DupString(actualBan->who, client_p->name);
193 >    strlcpy(ban->who, client_p->name, sizeof(ban->who));
194  
195 <  dlinkAdd(actualBan, &actualBan->node, list);
195 >  dlinkAdd(ban, &ban->node, list);
196  
197    return 1;
198   }
# Line 239 | Line 205 | add_id(struct Client *client_p, struct C
205   * side effects -
206   */
207   static int
208 < del_id(struct Channel *chptr, char *banid, int type)
208 > del_id(struct Channel *chptr, char *banid, unsigned int type)
209   {
210    dlink_list *list;
211 <  dlink_node *ban;
212 <  struct Ban *banptr;
213 <  char *name = NULL, *user = NULL, *host = NULL;
214 <
215 <  if (banid == NULL)
216 <    return 0;
211 >  dlink_node *node;
212 >  char name[NICKLEN + 1] = "";
213 >  char user[USERLEN + 1] = "";
214 >  char host[HOSTLEN + 1] = "";
215 >  struct split_nuh_item nuh;
216 >
217 >  assert(banid);
218 >
219 >  nuh.nuhmask  = check_string(banid);
220 >  nuh.nickptr  = name;
221 >  nuh.userptr  = user;
222 >  nuh.hostptr  = host;
223 >
224 >  nuh.nicksize = sizeof(name);
225 >  nuh.usersize = sizeof(user);
226 >  nuh.hostsize = sizeof(host);
227  
228 <  split_nuh(check_string(banid), &name, &user, &host);
228 >  split_nuh(&nuh);
229  
230    /*
231 <   * Assemble a n!u@h and print it back to banid for sending
231 >   * Re-assemble a new n!u@h and print it back to banid for sending
232     * the mode to the channel.
233     */
234 <  ircsprintf(banid, "%s!%s@%s", name, user, host);
234 >  snprintf(banid, IRCD_BUFSIZE, "%s!%s@%s", name, user, host);
235  
236    switch (type)
237    {
238      case CHFL_BAN:
239        list = &chptr->banlist;
240 <      clear_ban_cache(chptr);
240 >      clear_ban_cache_list(&chptr->locmembers);
241        break;
242      case CHFL_EXCEPTION:
243        list = &chptr->exceptlist;
244 <      clear_ban_cache(chptr);
244 >      clear_ban_cache_list(&chptr->locmembers);
245        break;
246      case CHFL_INVEX:
247        list = &chptr->invexlist;
248        break;
249      default:
250 <      sendto_realops_flags(UMODE_ALL, L_ALL,
275 <                           "del_id() called with unknown ban type %d!", type);
276 <      MyFree(name);
277 <      MyFree(user);
278 <      MyFree(host);
279 <      return(0);
250 >      list = NULL;  /* Let it crash */
251    }
252  
253 <  DLINK_FOREACH(ban, list->head)
253 >  DLINK_FOREACH(node, list->head)
254    {
255 <    banptr = ban->data;
255 >    struct Ban *ban = node->data;
256  
257 <    if (!irccmp(name, banptr->name) &&
258 <        !irccmp(user, banptr->username) &&
259 <        !irccmp(host, banptr->host))
257 >    if (!irccmp(name, ban->name) &&
258 >        !irccmp(user, ban->user) &&
259 >        !irccmp(host, ban->host))
260      {
261 <      remove_ban(banptr, list);
291 <      MyFree(name);
292 <      MyFree(user);
293 <      MyFree(host);
261 >      remove_ban(ban, list);
262        return 1;
263      }
264    }
265  
298 –  MyFree(name);
299 –  MyFree(user);
300 –  MyFree(host);
266    return 0;
267   }
268  
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 –
269   /* channel_modes()
270   *
271   * inputs       - pointer to channel
# Line 326 | Line 277 | static const struct mode_letter
277   * chptr onto buffer mbuf with the parameters in pbuf.
278   */
279   void
280 < channel_modes(struct Channel *chptr, struct Client *client_p,
330 <              char *mbuf, char *pbuf)
280 > channel_modes(struct Channel *chptr, struct Client *client_p, char *mbuf, char *pbuf)
281   {
332 –  int i;
333 –
282    *mbuf++ = '+';
283    *pbuf = '\0';
284  
285 <  for (i = 0; flags[i].mode; ++i)
286 <    if (chptr->mode.mode & flags[i].mode)
287 <      *mbuf++ = flags[i].letter;
285 >  for (const struct mode_letter *tab = chan_modes; tab->mode; ++tab)
286 >    if (HasCMode(chptr, tab->mode))
287 >      *mbuf++ = tab->letter;
288  
289    if (chptr->mode.limit)
290    {
291      *mbuf++ = 'l';
292  
293 <    if (IsMember(client_p, chptr) || IsServer(client_p))
294 <      pbuf += ircsprintf(pbuf, "%d ", chptr->mode.limit);
293 >    if (IsServer(client_p) || IsMember(client_p, chptr))
294 >      pbuf += sprintf(pbuf, "%u ", chptr->mode.limit);
295    }
296  
297    if (chptr->mode.key[0])
298    {
299      *mbuf++ = 'k';
300  
301 <    if (*pbuf || IsMember(client_p, chptr) || IsServer(client_p))
302 <      ircsprintf(pbuf, "%s ", chptr->mode.key);
301 >    if (IsServer(client_p) || IsMember(client_p, chptr))
302 >      sprintf(pbuf, "%s ", chptr->mode.key);
303    }
304  
305    *mbuf = '\0';
306   }
307  
308   /* fix_key()
309 < *
309 > *
310   * inputs       - pointer to key to clean up
311   * output       - pointer to cleaned up key
312   * side effects - input string is modified
# Line 370 | Line 318 | fix_key(char *arg)
318   {
319    unsigned char *s, *t, c;
320  
321 <  for (s = t = (unsigned char *)arg; (c = *s); s++)
321 >  for (s = t = (unsigned char *)arg; (c = *s) && s - (unsigned char *)arg < KEYLEN; ++s)
322    {
323      c &= 0x7f;
324 +
325      if (c != ':' && c > ' ' && c != ',')
326        *t++ = c;
327    }
328  
329    *t = '\0';
330 <  return(arg);
330 >  return arg;
331   }
332  
333 < /* fix_key_old()
334 < *
335 < * inputs       - pointer to key to clean up
336 < * 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
333 > /*
334 > * inputs       - pointer to channel
335 > * output       - none
336 > * side effects - clear ban cache
337   */
338 < static char *
339 < fix_key_old(char *arg)
338 > void
339 > clear_ban_cache_list(dlink_list *list)
340   {
341 <  unsigned char *s, *t, c;
341 >  dlink_node *node;
342  
343 <  for (s = t = (unsigned char *)arg; (c = *s); s++)
343 >  DLINK_FOREACH(node, list->head)
344    {
345 <    c &= 0x7f;
346 <    if ((c != 0x0a) && (c != ':') && (c != 0x0d) && (c != ','))
402 <      *t++ = c;
345 >    struct Membership *member = node->data;
346 >    member->flags &= ~(CHFL_BAN_SILENCED | CHFL_BAN_CHECKED);
347    }
404 –
405 –  *t = '\0';
406 –  return(arg);
348   }
349  
350 < /* bitmasks for various error returns that set_channel_mode should only return
350 > /*
351 > * Bitmasks for various error returns that set_channel_mode should only return
352   * once per call  -orabidoo
353   */
354 <
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 < */
439 < void
440 < init_chcap_usage_counts(void)
354 > enum
355   {
356 <  unsigned long m, c, y, n;
356 >  SM_ERR_NOOPS        = 1 << 0,  /* No chan ops */
357 >  SM_ERR_UNKNOWN      = 1 << 1,
358 >  SM_ERR_RPL_B        = 1 << 2,
359 >  SM_ERR_RPL_E        = 1 << 3,
360 >  SM_ERR_RPL_I        = 1 << 4,
361 >  SM_ERR_NOTONCHANNEL = 1 << 5,  /* Client is not on channel */
362 >  SM_ERR_NOTOPER      = 1 << 6,
363 >  SM_ERR_ONLYSERVER   = 1 << 7
364 > };
365  
366 <  memset(chcap_combos, 0, sizeof(chcap_combos));
366 > /* Mode functions handle mode changes for a particular mode... */
367 > static void
368 > chm_nosuch(struct Client *source_p, struct Channel *chptr, int parc, int *parn,
369 >           char **parv, int *errors, int alev, int dir, char c, unsigned int d)
370 > {
371 >  if (*errors & SM_ERR_UNKNOWN)
372 >    return;
373  
374 <  /* For every possible combination */
375 <  for (m = 0; m < NCHCAP_COMBOS; m++)
448 <  {
449 <    /* Check each capab */
450 <    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;
459 <  }
374 >  *errors |= SM_ERR_UNKNOWN;
375 >  sendto_one_numeric(source_p, &me, ERR_UNKNOWNMODE, c);
376   }
377  
378 < /* void set_chcap_usage_counts(struct Client *serv_p)
379 < * Input: serv_p; The client whose capabs to register.
380 < * Output: none
465 < * Side-effects: Increments the usage counts for the correct capab
466 < *               combination.
467 < */
468 < void
469 < set_chcap_usage_counts(struct Client *serv_p)
378 > static void
379 > chm_simple(struct Client *source_p, struct Channel *chptr, int parc, int *parn,
380 >           char **parv, int *errors, int alev, int dir, char c, unsigned int d)
381   {
382 <  int n;
472 <
473 <  for (n = 0; n < NCHCAP_COMBOS; n++)
382 >  if (alev < CHACCESS_HALFOP)
383    {
384 <    if (((serv_p->localClient->caps & chcap_combos[n].cap_yes) ==
385 <         chcap_combos[n].cap_yes) &&
386 <        ((serv_p->localClient->caps & chcap_combos[n].cap_no) == 0))
387 <    {
388 <      chcap_combos[n].count++;
389 <      return;
390 <    }
384 >    if (!(*errors & SM_ERR_NOOPS))
385 >      sendto_one_numeric(source_p, &me,
386 >                         alev == CHACCESS_NOTONCHAN ? ERR_NOTONCHANNEL :
387 >                         ERR_CHANOPRIVSNEEDED, chptr->name);
388 >
389 >    *errors |= SM_ERR_NOOPS;
390 >    return;
391    }
392  
393 <  /* This should be impossible -A1kmm. */
394 <  assert(0);
395 < }
393 >  /* If have already dealt with this simple mode, ignore it */
394 >  if (simple_modes_mask & d)
395 >    return;
396  
397 < /* void set_chcap_usage_counts(struct Client *serv_p)
489 < *
490 < * 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)
497 < {
498 <  int n;
397 >  simple_modes_mask |= d;
398  
399 <  for (n = 0; n < NCHCAP_COMBOS; n++)
399 >  /* setting + */
400 >  /* Apparently, (though no one has ever told the hybrid group directly)
401 >   * admins don't like redundant mode checking. ok. It would have been nice
402 >   * if you had have told us directly. I've left the original code snippets
403 >   * in place.
404 >   *
405 >   * -Dianora
406 >   */
407 >  if (dir == MODE_ADD) /* && !(chptr->mode.mode & d)) */
408    {
409 <    if ((serv_p->localClient->caps & chcap_combos[n].cap_yes) ==
410 <        chcap_combos[n].cap_yes &&
411 <        (serv_p->localClient->caps & chcap_combos[n].cap_no) == 0)
412 <    {
413 <      /* Hopefully capabs can't change dynamically or anything... */
414 <      assert(chcap_combos[n].count > 0);
415 <      chcap_combos[n].count--;
509 <      return;
510 <    }
409 >    AddCMode(chptr, d);
410 >
411 >    mode_changes[mode_count].letter = c;
412 >    mode_changes[mode_count].arg = NULL;
413 >    mode_changes[mode_count].id = NULL;
414 >    mode_changes[mode_count].flags = 0;
415 >    mode_changes[mode_count++].dir = dir;
416    }
417 +  else if (dir == MODE_DEL) /* && (chptr->mode.mode & d)) */
418 +  {
419 +    /* setting - */
420 +    DelCMode(chptr, d);
421  
422 <  /* This should be impossible -A1kmm. */
423 <  assert(0);
422 >    mode_changes[mode_count].letter = c;
423 >    mode_changes[mode_count].arg = NULL;
424 >    mode_changes[mode_count].id = NULL;
425 >    mode_changes[mode_count].flags = 0;
426 >    mode_changes[mode_count++].dir = dir;
427 >  }
428   }
429  
517 – /* Mode functions handle mode changes for a particular mode... */
430   static void
431 < chm_nosuch(struct Client *client_p, struct Client *source_p,
432 <           struct Channel *chptr, int parc, int *parn,
521 <           char **parv, int *errors, int alev, int dir, char c, void *d,
522 <           const char *chname)
431 > chm_registered(struct Client *source_p, struct Channel *chptr, int parc, int *parn,
432 >               char **parv, int *errors, int alev, int dir, char c, unsigned int d)
433   {
434 <  if (*errors & SM_ERR_UNKNOWN)
434 >  if (!IsServer(source_p) && !HasFlag(source_p, FLAGS_SERVICE))
435 >  {
436 >    if (!(*errors & SM_ERR_ONLYSERVER))
437 >      sendto_one_numeric(source_p, &me,
438 >                         alev == CHACCESS_NOTONCHAN ? ERR_NOTONCHANNEL :
439 >                         ERR_ONLYSERVERSCANCHANGE, chptr->name);
440 >
441 >    *errors |= SM_ERR_ONLYSERVER;
442      return;
443 +  }
444  
445 <  *errors |= SM_ERR_UNKNOWN;
446 <  sendto_one(source_p, form_str(ERR_UNKNOWNMODE), me.name,
447 <             source_p->name, c);
445 >  /* If have already dealt with this simple mode, ignore it */
446 >  if (simple_modes_mask & d)
447 >    return;
448 >
449 >  simple_modes_mask |= d;
450 >
451 >  /* setting + */
452 >  /* Apparently, (though no one has ever told the hybrid group directly)
453 >   * admins don't like redundant mode checking. ok. It would have been nice
454 >   * if you had have told us directly. I've left the original code snippets
455 >   * in place.
456 >   *
457 >   * -Dianora
458 >   */
459 >  if (dir == MODE_ADD) /* && !(chptr->mode.mode & d)) */
460 >  {
461 >    AddCMode(chptr, d);
462 >
463 >    mode_changes[mode_count].letter = c;
464 >    mode_changes[mode_count].arg = NULL;
465 >    mode_changes[mode_count].id = NULL;
466 >    mode_changes[mode_count].flags = 0;
467 >    mode_changes[mode_count++].dir = dir;
468 >  }
469 >  else if (dir == MODE_DEL) /* && (chptr->mode.mode & d)) */
470 >  {
471 >    /* setting - */
472 >    DelCMode(chptr, d);
473 >
474 >    mode_changes[mode_count].letter = c;
475 >    mode_changes[mode_count].arg = NULL;
476 >    mode_changes[mode_count].id = NULL;
477 >    mode_changes[mode_count].flags = 0;
478 >    mode_changes[mode_count++].dir = dir;
479 >  }
480   }
481  
482   static void
483 < chm_simple(struct Client *client_p, struct Client *source_p, struct Channel *chptr,
484 <           int parc, int *parn, char **parv, int *errors, int alev, int dir,
535 <           char c, void *d, const char *chname)
483 > chm_operonly(struct Client *source_p, struct Channel *chptr, int parc, int *parn,
484 >             char **parv, int *errors, int alev, int dir, char c, unsigned int d)
485   {
486 <  long mode_type;
538 <
539 <  mode_type = (long)d;
540 <
541 <  if ((alev < CHACCESS_HALFOP) ||
542 <      ((mode_type == MODE_PRIVATE) && (alev < CHACCESS_CHANOP)))
486 >  if (alev < CHACCESS_HALFOP)
487    {
488      if (!(*errors & SM_ERR_NOOPS))
489 <      sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ?
490 <                                    ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED),
491 <                 me.name, source_p->name, chname);
489 >      sendto_one_numeric(source_p, &me,
490 >                         alev == CHACCESS_NOTONCHAN ? ERR_NOTONCHANNEL :
491 >                         ERR_CHANOPRIVSNEEDED, chptr->name);
492 >
493      *errors |= SM_ERR_NOOPS;
494      return;
495    }
496  
497 +  if (MyClient(source_p) && !HasUMode(source_p, UMODE_OPER))
498 +  {
499 +    if (!(*errors & SM_ERR_NOTOPER))
500 +      sendto_one_numeric(source_p, &me, ERR_NOPRIVILEGES);
501 +
502 +    *errors |= SM_ERR_NOTOPER;
503 +    return;
504 +  }
505 +
506    /* If have already dealt with this simple mode, ignore it */
507 <  if (simple_modes_mask & mode_type)
507 >  if (simple_modes_mask & d)
508      return;
509  
510 <  simple_modes_mask |= mode_type;
510 >  simple_modes_mask |= d;
511  
512 <  /* 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)) */
512 >  if (dir == MODE_ADD) /* && !(chptr->mode.mode & d)) */
513    {
514 <    chptr->mode.mode |= mode_type;
514 >    AddCMode(chptr, d);
515  
516      mode_changes[mode_count].letter = c;
517 <    mode_changes[mode_count].dir = MODE_ADD;
572 <    mode_changes[mode_count].caps = 0;
573 <    mode_changes[mode_count].nocaps = 0;
517 >    mode_changes[mode_count].arg = NULL;
518      mode_changes[mode_count].id = NULL;
519 <    mode_changes[mode_count].mems = ALL_MEMBERS;
520 <    mode_changes[mode_count++].arg = NULL;
519 >    mode_changes[mode_count].flags = 0;
520 >    mode_changes[mode_count++].dir = dir;
521    }
522 <  else if ((dir == MODE_DEL)) /* && (chptr->mode.mode & mode_type)) */
522 >  else if (dir == MODE_DEL) /* && (chptr->mode.mode & d)) */
523    {
524      /* setting - */
525 <
582 <    chptr->mode.mode &= ~mode_type;
525 >    DelCMode(chptr, d);
526  
527      mode_changes[mode_count].letter = c;
528 <    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;
528 >    mode_changes[mode_count].arg = NULL;
529      mode_changes[mode_count].id = NULL;
530 <    mode_changes[mode_count++].arg = NULL;
530 >    mode_changes[mode_count].flags = 0;
531 >    mode_changes[mode_count++].dir = dir;
532    }
533   }
534  
535   static void
536 < chm_ban(struct Client *client_p, struct Client *source_p,
537 <        struct Channel *chptr, int parc, int *parn,
597 <        char **parv, int *errors, int alev, int dir, char c, void *d,
598 <        const char *chname)
536 > chm_ban(struct Client *source_p, struct Channel *chptr, int parc, int *parn,
537 >        char **parv, int *errors, int alev, int dir, char c, unsigned int d)
538   {
600 –  char *mask = NULL;
601 –
539    if (dir == MODE_QUERY || parc <= *parn)
540    {
541 <    dlink_node *ptr = NULL;
541 >    dlink_node *node;
542  
543      if (*errors & SM_ERR_RPL_B)
544        return;
545  
546      *errors |= SM_ERR_RPL_B;
547  
548 <    DLINK_FOREACH(ptr, chptr->banlist.head)
548 >    DLINK_FOREACH(node, chptr->banlist.head)
549      {
550 <      const struct Ban *banptr = ptr->data;
551 <      sendto_one(client_p, form_str(RPL_BANLIST),
552 <                 me.name, client_p->name, chname,
553 <                 banptr->name, banptr->username, banptr->host,
554 <                 banptr->who, banptr->when);
550 >      const struct Ban *ban = node->data;
551 >
552 >      if (!HasCMode(chptr, MODE_HIDEBMASKS) || alev >= CHACCESS_HALFOP)
553 >        sendto_one_numeric(source_p, &me, RPL_BANLIST, chptr->name,
554 >                           ban->name, ban->user, ban->host,
555 >                           ban->who, ban->when);
556      }
557  
558 <    sendto_one(source_p, form_str(RPL_ENDOFBANLIST), me.name,
621 <               source_p->name, chname);
558 >    sendto_one_numeric(source_p, &me, RPL_ENDOFBANLIST, chptr->name);
559      return;
560    }
561  
562    if (alev < CHACCESS_HALFOP)
563    {
564      if (!(*errors & SM_ERR_NOOPS))
565 <      sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ?
566 <                                    ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED),
567 <                 me.name, source_p->name, chname);
565 >      sendto_one_numeric(source_p, &me,
566 >                         alev == CHACCESS_NOTONCHAN ? ERR_NOTONCHANNEL :
567 >                         ERR_CHANOPRIVSNEEDED, chptr->name);
568 >
569      *errors |= SM_ERR_NOOPS;
570      return;
571    }
# Line 635 | Line 573 | chm_ban(struct Client *client_p, struct
573    if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
574      return;
575  
576 <  mask = parv[(*parn)++];
577 <  
578 <  if (IsServer(client_p))
579 <    if (strchr(mask, ' '))
580 <      return;
576 >  char *mask = nuh_mask[*parn];
577 >  strlcpy(mask, parv[*parn], sizeof(nuh_mask[*parn]));
578 >  ++(*parn);
579 >
580 >  if (*mask == ':' || (!MyConnect(source_p) && strchr(mask, ' ')))
581 >    return;
582  
583    switch (dir)
584    {
# Line 648 | Line 587 | chm_ban(struct Client *client_p, struct
587          return;
588        break;
589      case MODE_DEL:
651 – /* XXX grrrrrrr */
652 – #ifdef NO_BAN_COOKIE
590        if (!del_id(chptr, mask, CHFL_BAN))
591          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
592        break;
593      default:
594        assert(0);
595    }
596  
597    mode_changes[mode_count].letter = c;
598 <  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;
598 >  mode_changes[mode_count].arg = mask;  /* At this point 'mask' is no longer than NICKLEN + USERLEN + HOSTLEN + 3 */
599    mode_changes[mode_count].id = NULL;
600 <  mode_changes[mode_count++].arg = mask;
600 >  if (HasCMode(chptr, MODE_HIDEBMASKS))
601 >    mode_changes[mode_count].flags = CHFL_CHANOP | CHFL_HALFOP;
602 >  else
603 >    mode_changes[mode_count].flags = 0;
604 >  mode_changes[mode_count++].dir = dir;
605   }
606  
607   static void
608 < chm_except(struct Client *client_p, struct Client *source_p,
609 <           struct Channel *chptr, int parc, int *parn,
610 <           char **parv, int *errors, int alev, int dir, char c, void *d,
611 <           const char *chname)
680 < {
681 <  char *mask = NULL;
682 <
683 <  /* 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)))
608 > chm_except(struct Client *source_p, struct Channel *chptr, int parc, int *parn,
609 >           char **parv, int *errors, int alev, int dir, char c, unsigned int d)
610 > {
611 >  if (dir == MODE_QUERY || parc <= *parn)
612    {
613 +    dlink_node *node;
614 +
615      if (*errors & SM_ERR_RPL_E)
616        return;
617  
618      *errors |= SM_ERR_RPL_E;
619 +
620 +    DLINK_FOREACH(node, chptr->exceptlist.head)
621 +    {
622 +      const struct Ban *ban = node->data;
623 +
624 +      if (!HasCMode(chptr, MODE_HIDEBMASKS) || alev >= CHACCESS_HALFOP)
625 +        sendto_one_numeric(source_p, &me, RPL_EXCEPTLIST, chptr->name,
626 +                           ban->name, ban->user, ban->host,
627 +                           ban->who, ban->when);
628 +    }
629 +
630 +    sendto_one_numeric(source_p, &me, RPL_ENDOFEXCEPTLIST, chptr->name);
631      return;
632    }
633  
634    if (alev < CHACCESS_HALFOP)
635    {
636      if (!(*errors & SM_ERR_NOOPS))
637 <      sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ?
638 <                                    ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED),
639 <                 me.name, source_p->name, chname);
703 <    *errors |= SM_ERR_NOOPS;
704 <    return;
705 <  }
706 <
707 <  if (dir == MODE_QUERY || parc <= *parn)
708 <  {
709 <    dlink_node *ptr = NULL;
637 >      sendto_one_numeric(source_p, &me,
638 >                         alev == CHACCESS_NOTONCHAN ? ERR_NOTONCHANNEL :
639 >                         ERR_CHANOPRIVSNEEDED, chptr->name);
640  
641 <    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);
641 >    *errors |= SM_ERR_NOOPS;
642      return;
643    }
644  
645    if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
646      return;
647  
648 <  mask = parv[(*parn)++];
648 >  char *mask = nuh_mask[*parn];
649 >  strlcpy(mask, parv[*parn], sizeof(nuh_mask[*parn]));
650 >  ++(*parn);
651  
652 <  if (IsServer(client_p))
653 <    if (strchr(mask, ' '))
737 <      return;
652 >  if (*mask == ':' || (!MyConnect(source_p) && strchr(mask, ' ')))
653 >    return;
654  
655    switch (dir)
656    {
# Line 751 | Line 667 | chm_except(struct Client *client_p, stru
667    }
668  
669    mode_changes[mode_count].letter = c;
670 <  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 <
670 >  mode_changes[mode_count].arg = mask;  /* At this point 'mask' is no longer than NICKLEN + USERLEN + HOSTLEN + 3 */
671    mode_changes[mode_count].id = NULL;
672 <  mode_changes[mode_count++].arg = mask;
672 >  if (HasCMode(chptr, MODE_HIDEBMASKS))
673 >    mode_changes[mode_count].flags = CHFL_CHANOP | CHFL_HALFOP;
674 >  else
675 >    mode_changes[mode_count].flags = 0;
676 >  mode_changes[mode_count++].dir = dir;
677   }
678  
679   static void
680 < chm_invex(struct Client *client_p, struct Client *source_p,
681 <          struct Channel *chptr, int parc, int *parn,
682 <          char **parv, int *errors, int alev, int dir, char c, void *d,
771 <          const char *chname)
772 < {
773 <  char *mask = NULL;
774 <
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 <
680 > chm_invex(struct Client *source_p, struct Channel *chptr, int parc, int *parn,
681 >          char **parv, int *errors, int alev, int dir, char c, unsigned int d)
682 > {
683    if (dir == MODE_QUERY || parc <= *parn)
684    {
685 <    dlink_node *ptr = NULL;
685 >    dlink_node *node;
686  
687      if (*errors & SM_ERR_RPL_I)
688        return;
689  
690      *errors |= SM_ERR_RPL_I;
691  
692 <    DLINK_FOREACH(ptr, chptr->invexlist.head)
692 >    DLINK_FOREACH(node, chptr->invexlist.head)
693      {
694 <      const struct Ban *banptr = ptr->data;
695 <      sendto_one(client_p, form_str(RPL_INVITELIST), me.name,
696 <                 client_p->name, chname,
697 <                 banptr->name, banptr->username, banptr->host,
698 <                 banptr->who, banptr->when);
694 >      const struct Ban *ban = node->data;
695 >
696 >      if (!HasCMode(chptr, MODE_HIDEBMASKS) || alev >= CHACCESS_HALFOP)
697 >        sendto_one_numeric(source_p, &me, RPL_INVEXLIST, chptr->name,
698 >                           ban->name, ban->user, ban->host,
699 >                           ban->who, ban->when);
700      }
701  
702 <    sendto_one(source_p, form_str(RPL_ENDOFINVITELIST), me.name,
703 <               source_p->name, chname);
702 >    sendto_one_numeric(source_p, &me, RPL_ENDOFINVEXLIST, chptr->name);
703 >    return;
704 >  }
705 >
706 >  if (alev < CHACCESS_HALFOP)
707 >  {
708 >    if (!(*errors & SM_ERR_NOOPS))
709 >      sendto_one_numeric(source_p, &me,
710 >                         alev == CHACCESS_NOTONCHAN ? ERR_NOTONCHANNEL :
711 >                         ERR_CHANOPRIVSNEEDED, chptr->name);
712 >
713 >    *errors |= SM_ERR_NOOPS;
714      return;
715    }
716  
717    if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
718      return;
719  
720 <  mask = parv[(*parn)++];
720 >  char *mask = nuh_mask[*parn];
721 >  strlcpy(mask, parv[*parn], sizeof(nuh_mask[*parn]));
722 >  ++(*parn);
723  
724 <  if (IsServer(client_p))
725 <    if (strchr(mask, ' '))
829 <      return;
724 >  if (*mask == ':' || (!MyConnect(source_p) && strchr(mask, ' ')))
725 >    return;
726  
727    switch (dir)
728    {
# Line 843 | Line 739 | chm_invex(struct Client *client_p, struc
739    }
740  
741    mode_changes[mode_count].letter = c;
742 <  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 <
742 >  mode_changes[mode_count].arg = mask;  /* At this point 'mask' is no longer than NICKLEN + USERLEN + HOSTLEN + 3 */
743    mode_changes[mode_count].id = NULL;
744 <  mode_changes[mode_count++].arg = mask;
745 < }
746 <
747 < /*
748 < * 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 <  }
744 >  if (HasCMode(chptr, MODE_HIDEBMASKS))
745 >    mode_changes[mode_count].flags = CHFL_CHANOP | CHFL_HALFOP;
746 >  else
747 >    mode_changes[mode_count].flags = 0;
748 >  mode_changes[mode_count++].dir = dir;
749   }
750  
751   static void
752 < chm_op(struct Client *client_p, struct Client *source_p,
753 <       struct Channel *chptr, int parc, int *parn,
879 <       char **parv, int *errors, int alev, int dir, char c, void *d,
880 <       const char *chname)
752 > chm_voice(struct Client *source_p, struct Channel *chptr, int parc, int *parn,
753 >          char **parv, int *errors, int alev, int dir, char c, unsigned int d)
754   {
755 <  char *opnick;
883 <  struct Client *targ_p;
755 >  struct Client *target_p;
756    struct Membership *member;
757  
758 <  if (alev < CHACCESS_CHANOP)
758 >  if (alev < CHACCESS_HALFOP)
759    {
760      if (!(*errors & SM_ERR_NOOPS))
761 <      sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ?
762 <                                    ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED),
763 <                 me.name, source_p->name, chname);
761 >      sendto_one_numeric(source_p, &me,
762 >                         alev == CHACCESS_NOTONCHAN ? ERR_NOTONCHANNEL :
763 >                         ERR_CHANOPRIVSNEEDED, chptr->name);
764 >
765      *errors |= SM_ERR_NOOPS;
766      return;
767    }
768  
769 <  if ((dir == MODE_QUERY) || (parc <= *parn))
769 >  if (dir == MODE_QUERY || parc <= *parn)
770      return;
771  
772 <  opnick = parv[(*parn)++];
772 >  if ((target_p = find_chasing(source_p, parv[(*parn)++])) == NULL)
773 >    return;  /* find_chasing sends ERR_NOSUCHNICK */
774  
775 <  if ((targ_p = find_chasing(client_p, source_p, opnick, NULL)) == NULL)
902 <    return;
903 <  if (!IsClient(targ_p))
904 <    return;
905 <
906 <  if ((member = find_channel_link(targ_p, chptr)) == NULL)
775 >  if ((member = find_channel_link(target_p, chptr)) == NULL)
776    {
777      if (!(*errors & SM_ERR_NOTONCHANNEL))
778 <      sendto_one(source_p, form_str(ERR_USERNOTINCHANNEL),
779 <                 me.name, source_p->name, opnick, chname);
778 >      sendto_one_numeric(source_p, &me, ERR_USERNOTINCHANNEL, target_p->name, chptr->name);
779 >
780      *errors |= SM_ERR_NOTONCHANNEL;
781      return;
782    }
# Line 915 | Line 784 | chm_op(struct Client *client_p, struct C
784    if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
785      return;
786  
787 <  /* no redundant mode changes */
788 <  if (dir == MODE_ADD &&  has_member_flags(member, CHFL_CHANOP))
789 <    return;
790 <  if (dir == MODE_DEL && !has_member_flags(member, CHFL_CHANOP))
791 <    return;
787 >  switch (dir)
788 >  {
789 >    case MODE_ADD:
790 >      if (has_member_flags(member, CHFL_VOICE))
791 >        return;  /* No redundant mode changes */
792  
793 <  mode_changes[mode_count].letter = 'o';
794 <  mode_changes[mode_count].dir = dir;
795 <  mode_changes[mode_count].caps = 0;
796 <  mode_changes[mode_count].nocaps = 0;
797 <  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;
793 >      AddMemberFlag(member, CHFL_VOICE);
794 >      break;
795 >    case MODE_DEL:
796 >      if (!has_member_flags(member, CHFL_VOICE))
797 >        return;  /* No redundant mode changes */
798  
799 <  if (dir == MODE_ADD)
800 <  {
935 <    AddMemberFlag(member, CHFL_CHANOP);
936 <    DelMemberFlag(member, CHFL_DEOPPED);
799 >      DelMemberFlag(member, CHFL_VOICE);
800 >      break;
801    }
802 <  else
803 <    DelMemberFlag(member, CHFL_CHANOP);
802 >
803 >  mode_changes[mode_count].letter = c;
804 >  mode_changes[mode_count].arg = target_p->name;
805 >  mode_changes[mode_count].id = target_p->id;
806 >  mode_changes[mode_count].flags = 0;
807 >  mode_changes[mode_count++].dir = dir;
808   }
809  
942 – #ifdef HALFOPS
810   static void
811 < chm_hop(struct Client *client_p, struct Client *source_p,
812 <       struct Channel *chptr, int parc, int *parn,
946 <       char **parv, int *errors, int alev, int dir, char c, void *d,
947 <       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;
950 <  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
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))
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 >
824      *errors |= SM_ERR_NOOPS;
825      return;
826    }
827  
828 <  if ((dir == MODE_QUERY) || (parc <= *parn))
828 >  if (dir == MODE_QUERY || parc <= *parn)
829      return;
830  
831 <  opnick = parv[(*parn)++];
831 >  if ((target_p = find_chasing(source_p, parv[(*parn)++])) == NULL)
832 >    return;  /* find_chasing sends ERR_NOSUCHNICK */
833  
834 <  if ((targ_p = find_chasing(client_p, source_p, opnick, NULL)) == NULL)
983 <    return;
984 <  if (!IsClient(targ_p))
985 <    return;
986 <
987 <  if ((member = find_channel_link(targ_p, chptr)) == NULL)
834 >  if ((member = find_channel_link(target_p, chptr)) == NULL)
835    {
836      if (!(*errors & SM_ERR_NOTONCHANNEL))
837 <      sendto_one(source_p, form_str(ERR_USERNOTINCHANNEL),
838 <                 me.name, source_p->name, opnick, chname);
837 >      sendto_one_numeric(source_p, &me, ERR_USERNOTINCHANNEL, target_p->name, chptr->name);
838 >
839      *errors |= SM_ERR_NOTONCHANNEL;
840      return;
841    }
# Line 996 | Line 843 | chm_hop(struct Client *client_p, struct
843    if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
844      return;
845  
846 <  /* no redundant mode changes */
847 <  if (dir == MODE_ADD &&  has_member_flags(member, CHFL_HALFOP))
848 <    return;
849 <  if (dir == MODE_DEL && !has_member_flags(member, CHFL_HALFOP))
850 <    return;
846 >  switch (dir)
847 >  {
848 >    case MODE_ADD:
849 >      if (has_member_flags(member, CHFL_HALFOP))
850 >        return;  /* No redundant mode changes */
851  
852 <  mode_changes[mode_count].letter = 'h';
853 <  mode_changes[mode_count].dir = dir;
854 <  mode_changes[mode_count].caps = 0;
855 <  mode_changes[mode_count].nocaps = 0;
856 <  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;
852 >      AddMemberFlag(member, CHFL_HALFOP);
853 >      break;
854 >    case MODE_DEL:
855 >      if (!has_member_flags(member, CHFL_HALFOP))
856 >        return;  /* No redundant mode changes */
857  
858 <  if (dir == MODE_ADD)
859 <  {
1016 <    AddMemberFlag(member, CHFL_HALFOP);
1017 <    DelMemberFlag(member, CHFL_DEOPPED);
858 >      DelMemberFlag(member, CHFL_HALFOP);
859 >      break;
860    }
861 <  else
862 <    DelMemberFlag(member, CHFL_HALFOP);
861 >
862 >  mode_changes[mode_count].letter = c;
863 >  mode_changes[mode_count].arg = target_p->name;
864 >  mode_changes[mode_count].id = target_p->id;
865 >  mode_changes[mode_count].flags = 0;
866 >  mode_changes[mode_count++].dir = dir;
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)++];
891 <
1049 <  if ((targ_p = find_chasing(client_p, source_p, opnick, NULL)) == NULL)
1050 <    return;
1051 <  if (!IsClient(targ_p))
1052 <    return;
890 >  if ((target_p = find_chasing(source_p, parv[(*parn)++])) == NULL)
891 >    return;  /* find_chasing sends ERR_NOSUCHNICK */
892  
893 <  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 1063 | Line 902 | chm_voice(struct Client *client_p, struc
902    if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
903      return;
904  
905 <  /* no redundant mode changes */
906 <  if (dir == MODE_ADD &&  has_member_flags(member, CHFL_VOICE))
907 <    return;
908 <  if (dir == MODE_DEL && !has_member_flags(member, CHFL_VOICE))
909 <    return;
905 >  switch (dir)
906 >  {
907 >    case MODE_ADD:
908 >      if (has_member_flags(member, CHFL_CHANOP))
909 >        return;  /* No redundant mode changes */
910  
911 <  mode_changes[mode_count].letter = 'v';
912 <  mode_changes[mode_count].dir = dir;
913 <  mode_changes[mode_count].caps = 0;
914 <  mode_changes[mode_count].nocaps = 0;
915 <  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;
911 >      AddMemberFlag(member, CHFL_CHANOP);
912 >      break;
913 >    case MODE_DEL:
914 >      if (!has_member_flags(member, CHFL_CHANOP))
915 >        return;  /* No redundant mode changes */
916  
917 <  if (dir == MODE_ADD)
918 <    AddMemberFlag(member, CHFL_VOICE);
919 <  else
920 <    DelMemberFlag(member, CHFL_VOICE);
917 >      DelMemberFlag(member, CHFL_CHANOP);
918 >      break;
919 >  }
920 >
921 >  mode_changes[mode_count].letter = c;
922 >  mode_changes[mode_count].arg = target_p->name;
923 >  mode_changes[mode_count].id = target_p->id;
924 >  mode_changes[mode_count].flags = 0;
925 >  mode_changes[mode_count++].dir = dir;
926   }
927  
928   static void
929 < chm_limit(struct Client *client_p, struct Client *source_p,
930 <          struct Channel *chptr, int parc, int *parn,
1090 <          char **parv, int *errors, int alev, int dir, char c, void *d,
1091 <          const char *chname)
929 > chm_limit(struct Client *source_p, struct Channel *chptr, int parc, int *parn,
930 >          char **parv, int *errors, int alev, int dir, char c, unsigned int d)
931   {
1093 –  int i, limit;
1094 –  char *lstr;
1095 –
932    if (alev < CHACCESS_HALFOP)
933    {
934      if (!(*errors & SM_ERR_NOOPS))
935 <      sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ?
936 <                                    ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED),
937 <                 me.name, source_p->name, chname);
935 >      sendto_one_numeric(source_p, &me,
936 >                         alev == CHACCESS_NOTONCHAN ? ERR_NOTONCHANNEL :
937 >                         ERR_CHANOPRIVSNEEDED, chptr->name);
938      *errors |= SM_ERR_NOOPS;
939      return;
940    }
# Line 1106 | Line 942 | chm_limit(struct Client *client_p, struc
942    if (dir == MODE_QUERY)
943      return;
944  
945 <  if ((dir == MODE_ADD) && parc > *parn)
945 >  if (dir == MODE_ADD && parc > *parn)
946    {
947 <    lstr = parv[(*parn)++];
947 >    char *const lstr = parv[(*parn)++];
948 >    int limit = 0;
949  
950 <    if ((limit = atoi(lstr)) <= 0)
950 >    if (EmptyString(lstr) || (limit = atoi(lstr)) <= 0)
951        return;
952  
953 <    ircsprintf(lstr, "%d", limit);
953 >    sprintf(lstr, "%d", limit);
954  
955 <    /* if somebody sets MODE #channel +ll 1 2, accept latter --fl */
956 <    for (i = 0; i < mode_count; i++)
1120 <    {
955 >    /* If somebody sets MODE #channel +ll 1 2, accept latter --fl */
956 >    for (unsigned int i = 0; i < mode_count; ++i)
957        if (mode_changes[i].letter == c && mode_changes[i].dir == MODE_ADD)
958          mode_changes[i].letter = 0;
1123 –    }
959  
960      mode_changes[mode_count].letter = c;
961 <    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;
961 >    mode_changes[mode_count].arg = lstr;
962      mode_changes[mode_count].id = NULL;
963 <    mode_changes[mode_count++].arg = lstr;
963 >    mode_changes[mode_count].flags = 0;
964 >    mode_changes[mode_count++].dir = dir;
965  
966      chptr->mode.limit = limit;
967    }
# Line 1140 | Line 973 | chm_limit(struct Client *client_p, struc
973      chptr->mode.limit = 0;
974  
975      mode_changes[mode_count].letter = c;
976 <    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;
976 >    mode_changes[mode_count].arg = NULL;
977      mode_changes[mode_count].id = NULL;
978 <    mode_changes[mode_count++].arg = NULL;
978 >    mode_changes[mode_count].flags = 0;
979 >    mode_changes[mode_count++].dir = dir;
980    }
981   }
982  
983   static void
984 < chm_key(struct Client *client_p, struct Client *source_p,
985 <        struct Channel *chptr, int parc, int *parn,
1155 <        char **parv, int *errors, int alev, int dir, char c, void *d,
1156 <        const char *chname)
984 > chm_key(struct Client *source_p, struct Channel *chptr, int parc, int *parn,
985 >        char **parv, int *errors, int alev, int dir, char c, unsigned int d)
986   {
1158 –  int i;
1159 –  char *key;
1160 –
987    if (alev < CHACCESS_HALFOP)
988    {
989      if (!(*errors & SM_ERR_NOOPS))
990 <      sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ?
991 <                                    ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED),
992 <                 me.name, source_p->name, chname);
990 >      sendto_one_numeric(source_p, &me,
991 >                         alev == CHACCESS_NOTONCHAN ? ERR_NOTONCHANNEL :
992 >                         ERR_CHANOPRIVSNEEDED, chptr->name);
993      *errors |= SM_ERR_NOOPS;
994      return;
995    }
# Line 1171 | Line 997 | chm_key(struct Client *client_p, struct
997    if (dir == MODE_QUERY)
998      return;
999  
1000 <  if ((dir == MODE_ADD) && parc > *parn)
1000 >  if (dir == MODE_ADD && parc > *parn)
1001    {
1002 <    key = parv[(*parn)++];
1002 >    char *const key = fix_key(parv[(*parn)++]);
1003  
1004 <    if (MyClient(source_p))
1179 <      fix_key(key);
1180 <    else
1181 <      fix_key_old(key);
1182 <
1183 <    if (*key == '\0')
1004 >    if (EmptyString(key))
1005        return;
1006  
1007      assert(key[0] != ' ');
1008      strlcpy(chptr->mode.key, key, sizeof(chptr->mode.key));
1009  
1010 <    /* if somebody does MODE #channel +kk a b, accept latter --fl */
1011 <    for (i = 0; i < mode_count; i++)
1191 <    {
1010 >    /* If somebody does MODE #channel +kk a b, accept latter --fl */
1011 >    for (unsigned int i = 0; i < mode_count; ++i)
1012        if (mode_changes[i].letter == c && mode_changes[i].dir == MODE_ADD)
1013          mode_changes[i].letter = 0;
1194 –    }
1014  
1015      mode_changes[mode_count].letter = c;
1016 <    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;
1016 >    mode_changes[mode_count].arg = key;
1017      mode_changes[mode_count].id = NULL;
1018 <    mode_changes[mode_count++].arg = chptr->mode.key;
1018 >    mode_changes[mode_count].flags = 0;
1019 >    mode_changes[mode_count++].dir = dir;
1020    }
1021    else if (dir == MODE_DEL)
1022    {
1023      if (parc > *parn)
1024 <      (*parn)++;
1024 >      ++(*parn);
1025  
1026      if (chptr->mode.key[0] == '\0')
1027        return;
# Line 1212 | Line 1029 | chm_key(struct Client *client_p, struct
1029      chptr->mode.key[0] = '\0';
1030  
1031      mode_changes[mode_count].letter = c;
1032 <    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;
1032 >    mode_changes[mode_count].arg = "*";
1033      mode_changes[mode_count].id = NULL;
1034 <    mode_changes[mode_count++].arg = "*";
1034 >    mode_changes[mode_count].flags = 0;
1035 >    mode_changes[mode_count++].dir = dir;
1036    }
1037   }
1038  
1039 < struct ChannelMode
1225 < {
1226 <  void (*func) (struct Client *client_p, struct Client *source_p,
1227 <                struct Channel *chptr, int parc, int *parn, char **parv,
1228 <                int *errors, int alev, int dir, char c, void *d,
1229 <                const char *chname);
1230 <  void *d;
1231 < };
1232 <
1233 < /* *INDENT-OFF* */
1234 < static struct ChannelMode ModeTable[255] =
1039 > const struct ChannelMode ModeTable[256] =
1040   {
1041 <  {chm_nosuch, NULL},
1042 <  {chm_nosuch, NULL},                             /* A */
1043 <  {chm_nosuch, NULL},                             /* B */
1044 <  {chm_nosuch, NULL},                             /* C */
1045 <  {chm_nosuch, NULL},                             /* D */
1046 <  {chm_nosuch, NULL},                             /* E */
1047 <  {chm_nosuch, NULL},                             /* F */
1048 <  {chm_nosuch, NULL},                             /* G */
1049 <  {chm_nosuch, NULL},                             /* H */
1050 <  {chm_invex, NULL},                              /* I */
1051 <  {chm_nosuch, NULL},                             /* J */
1052 <  {chm_nosuch, NULL},                             /* K */
1053 <  {chm_nosuch, NULL},                             /* L */
1054 <  {chm_nosuch, NULL},                             /* M */
1055 <  {chm_nosuch, NULL},                             /* N */
1056 <  {chm_nosuch, NULL},                             /* O */
1057 <  {chm_nosuch, NULL},                             /* P */
1058 <  {chm_nosuch, NULL},                             /* Q */
1059 <  {chm_nosuch, NULL},                             /* R */
1060 <  {chm_nosuch, NULL},                             /* S */
1061 <  {chm_nosuch, NULL},                             /* T */
1062 <  {chm_nosuch, NULL},                             /* U */
1063 <  {chm_nosuch, NULL},                             /* V */
1064 <  {chm_nosuch, NULL},                             /* W */
1065 <  {chm_nosuch, NULL},                             /* X */
1066 <  {chm_nosuch, NULL},                             /* Y */
1067 <  {chm_nosuch, NULL},                             /* Z */
1068 <  {chm_nosuch, NULL},
1069 <  {chm_nosuch, NULL},
1070 <  {chm_nosuch, NULL},
1071 <  {chm_nosuch, NULL},
1072 <  {chm_nosuch, NULL},
1073 <  {chm_nosuch, NULL},
1074 <  {chm_nosuch, NULL},                             /* a */
1075 <  {chm_ban, NULL},                                /* b */
1076 <  {chm_nosuch, NULL},                             /* c */
1077 <  {chm_nosuch, NULL},                             /* d */
1078 <  {chm_except, NULL},                             /* e */
1079 <  {chm_nosuch, NULL},                             /* f */
1080 <  {chm_nosuch, NULL},                             /* g */
1081 < #ifdef HALFOPS
1082 <  {chm_hop, NULL},                                /* h */
1083 < #else
1084 <  {chm_nosuch, NULL},                             /* h */
1085 < #endif
1086 <  {chm_simple, (void *) MODE_INVITEONLY},         /* i */
1087 <  {chm_nosuch, NULL},                             /* j */
1088 <  {chm_key, NULL},                                /* k */
1089 <  {chm_limit, NULL},                              /* l */
1090 <  {chm_simple, (void *) MODE_MODERATED},          /* m */
1091 <  {chm_simple, (void *) MODE_NOPRIVMSGS},         /* n */
1092 <  {chm_op, NULL},                                 /* o */
1093 <  {chm_simple, (void *) MODE_PRIVATE},            /* p */
1094 <  {chm_nosuch, NULL},                             /* q */
1095 <  {chm_nosuch, NULL},                             /* r */
1096 <  {chm_simple, (void *) MODE_SECRET},             /* s */
1097 <  {chm_simple, (void *) MODE_TOPICLIMIT},         /* t */
1098 <  {chm_nosuch, NULL},                             /* u */
1099 <  {chm_voice, NULL},                              /* v */
1100 <  {chm_nosuch, NULL},                             /* w */
1101 <  {chm_nosuch, NULL},                             /* x */
1102 <  {chm_nosuch, NULL},                             /* y */
1103 <  {chm_nosuch, NULL},                             /* z */
1041 >  { chm_nosuch,  0 },                   /* 0x00 */
1042 >  { chm_nosuch,  0 },                   /* 0x01 */
1043 >  { chm_nosuch,  0 },                   /* 0x02 */
1044 >  { chm_nosuch,  0 },                   /* 0x03 */
1045 >  { chm_nosuch,  0 },                   /* 0x04 */
1046 >  { chm_nosuch,  0 },                   /* 0x05 */
1047 >  { chm_nosuch,  0 },                   /* 0x06 */
1048 >  { chm_nosuch,  0 },                   /* 0x07 */
1049 >  { chm_nosuch,  0 },                   /* 0x08 */
1050 >  { chm_nosuch,  0 },                   /* 0x09 */
1051 >  { chm_nosuch,  0 },                   /* 0x0a */
1052 >  { chm_nosuch,  0 },                   /* 0x0b */
1053 >  { chm_nosuch,  0 },                   /* 0x0c */
1054 >  { chm_nosuch,  0 },                   /* 0x0d */
1055 >  { chm_nosuch,  0 },                   /* 0x0e */
1056 >  { chm_nosuch,  0 },                   /* 0x0f */
1057 >  { chm_nosuch,  0 },                   /* 0x10 */
1058 >  { chm_nosuch,  0 },                   /* 0x11 */
1059 >  { chm_nosuch,  0 },                   /* 0x12 */
1060 >  { chm_nosuch,  0 },                   /* 0x13 */
1061 >  { chm_nosuch,  0 },                   /* 0x14 */
1062 >  { chm_nosuch,  0 },                   /* 0x15 */
1063 >  { chm_nosuch,  0 },                   /* 0x16 */
1064 >  { chm_nosuch,  0 },                   /* 0x17 */
1065 >  { chm_nosuch,  0 },                   /* 0x18 */
1066 >  { chm_nosuch,  0 },                   /* 0x19 */
1067 >  { chm_nosuch,  0 },                   /* 0x1a */
1068 >  { chm_nosuch,  0 },                   /* 0x1b */
1069 >  { chm_nosuch,  0 },                   /* 0x1c */
1070 >  { chm_nosuch,  0 },                   /* 0x1d */
1071 >  { chm_nosuch,  0 },                   /* 0x1e */
1072 >  { chm_nosuch,  0 },                   /* 0x1f */
1073 >  { chm_nosuch,  0 },                   /* 0x20 */
1074 >  { chm_nosuch,  0 },                   /* 0x21 */
1075 >  { chm_nosuch,  0 },                   /* 0x22 */
1076 >  { chm_nosuch,  0 },                   /* 0x23 */
1077 >  { chm_nosuch,  0 },                   /* 0x24 */
1078 >  { chm_nosuch,  0 },                   /* 0x25 */
1079 >  { chm_nosuch,  0 },                   /* 0x26 */
1080 >  { chm_nosuch,  0 },                   /* 0x27 */
1081 >  { chm_nosuch,  0 },                   /* 0x28 */
1082 >  { chm_nosuch,  0 },                   /* 0x29 */
1083 >  { chm_nosuch,  0 },                   /* 0x2a */
1084 >  { chm_nosuch,  0 },                   /* 0x2b */
1085 >  { chm_nosuch,  0 },                   /* 0x2c */
1086 >  { chm_nosuch,  0 },                   /* 0x2d */
1087 >  { chm_nosuch,  0 },                   /* 0x2e */
1088 >  { chm_nosuch,  0 },                   /* 0x2f */
1089 >  { chm_nosuch,  0 },                   /* 0x30 */
1090 >  { chm_nosuch,  0 },                   /* 0x31 */
1091 >  { chm_nosuch,  0 },                   /* 0x32 */
1092 >  { chm_nosuch,  0 },                   /* 0x33 */
1093 >  { chm_nosuch,  0 },                   /* 0x34 */
1094 >  { chm_nosuch,  0 },                   /* 0x35 */
1095 >  { chm_nosuch,  0 },                   /* 0x36 */
1096 >  { chm_nosuch,  0 },                   /* 0x37 */
1097 >  { chm_nosuch,  0 },                   /* 0x38 */
1098 >  { chm_nosuch,  0 },                   /* 0x39 */
1099 >  { chm_nosuch,  0 },                   /* 0x3a */
1100 >  { chm_nosuch,  0 },                   /* 0x3b */
1101 >  { chm_nosuch,  0 },                   /* 0x3c */
1102 >  { chm_nosuch,  0 },                   /* 0x3d */
1103 >  { chm_nosuch,  0 },                   /* 0x3e */
1104 >  { chm_nosuch,  0 },                   /* 0x3f */
1105 >  { chm_nosuch,  0 },                   /* @ */
1106 >  { chm_nosuch,  0 },                   /* A */
1107 >  { chm_nosuch,  0 },                   /* B */
1108 >  { chm_simple,  MODE_NOCTCP },         /* C */
1109 >  { chm_nosuch,  0 },                   /* D */
1110 >  { chm_nosuch,  0 },                   /* E */
1111 >  { chm_nosuch,  0 },                   /* F */
1112 >  { chm_nosuch,  0 },                   /* G */
1113 >  { chm_nosuch,  0 },                   /* H */
1114 >  { chm_invex,   0 },                   /* I */
1115 >  { chm_nosuch,  0 },                   /* J */
1116 >  { chm_nosuch,  0 },                   /* K */
1117 >  { chm_nosuch,  0 },                   /* L */
1118 >  { chm_simple, MODE_MODREG},           /* M */
1119 >  { chm_nosuch,  0 },                   /* N */
1120 >  { chm_operonly, MODE_OPERONLY},       /* O */
1121 >  { chm_nosuch,  0 },                   /* P */
1122 >  { chm_nosuch,  0 },                   /* Q */
1123 >  { chm_simple, MODE_REGONLY},          /* R */
1124 >  { chm_simple, MODE_SSLONLY},          /* S */
1125 >  { chm_simple, MODE_NONOTICE},         /* T */
1126 >  { chm_nosuch,  0 },                   /* U */
1127 >  { chm_nosuch,  0 },                   /* V */
1128 >  { chm_nosuch,  0 },                   /* W */
1129 >  { chm_nosuch,  0 },                   /* X */
1130 >  { chm_nosuch,  0 },                   /* Y */
1131 >  { chm_nosuch,  0 },                   /* Z */
1132 >  { chm_nosuch,  0 },
1133 >  { chm_nosuch,  0 },
1134 >  { chm_nosuch,  0 },
1135 >  { chm_nosuch,  0 },
1136 >  { chm_nosuch,  0 },
1137 >  { chm_nosuch,  0 },
1138 >  { chm_nosuch,  0 },                   /* a */
1139 >  { chm_ban,     0 },                   /* b */
1140 >  { chm_simple, MODE_NOCTRL},           /* c */
1141 >  { chm_nosuch,  0 },                   /* d */
1142 >  { chm_except,  0 },                   /* e */
1143 >  { chm_nosuch,  0 },                   /* f */
1144 >  { chm_nosuch,  0 },                   /* g */
1145 >  { chm_hop,     0 },                   /* h */
1146 >  { chm_simple,     MODE_INVITEONLY },  /* i */
1147 >  { chm_nosuch,     0               },  /* j */
1148 >  { chm_key,        0               },  /* k */
1149 >  { chm_limit,      0               },  /* l */
1150 >  { chm_simple,     MODE_MODERATED  },  /* m */
1151 >  { chm_simple,     MODE_NOPRIVMSGS },  /* n */
1152 >  { chm_op,         0               },  /* o */
1153 >  { chm_simple,     MODE_PRIVATE    },  /* p */
1154 >  { chm_nosuch,     0               },  /* q */
1155 >  { chm_registered, MODE_REGISTERED },  /* r */
1156 >  { chm_simple,     MODE_SECRET     },  /* s */
1157 >  { chm_simple,     MODE_TOPICLIMIT },  /* t */
1158 >  { chm_simple,     MODE_HIDEBMASKS },  /* u */
1159 >  { chm_voice,      0               },  /* v */
1160 >  { chm_nosuch,     0               },  /* w */
1161 >  { chm_nosuch,     0               },  /* x */
1162 >  { chm_nosuch,     0               },  /* y */
1163 >  { chm_nosuch,     0               },  /* z */
1164 >  { chm_nosuch,  0 },                   /* 0x7b */
1165 >  { chm_nosuch,  0 },                   /* 0x7c */
1166 >  { chm_nosuch,  0 },                   /* 0x7d */
1167 >  { chm_nosuch,  0 },                   /* 0x7e */
1168 >  { chm_nosuch,  0 },                   /* 0x7f */
1169 >  { chm_nosuch,  0 },                   /* 0x80 */
1170 >  { chm_nosuch,  0 },                   /* 0x81 */
1171 >  { chm_nosuch,  0 },                   /* 0x82 */
1172 >  { chm_nosuch,  0 },                   /* 0x83 */
1173 >  { chm_nosuch,  0 },                   /* 0x84 */
1174 >  { chm_nosuch,  0 },                   /* 0x85 */
1175 >  { chm_nosuch,  0 },                   /* 0x86 */
1176 >  { chm_nosuch,  0 },                   /* 0x87 */
1177 >  { chm_nosuch,  0 },                   /* 0x88 */
1178 >  { chm_nosuch,  0 },                   /* 0x89 */
1179 >  { chm_nosuch,  0 },                   /* 0x8a */
1180 >  { chm_nosuch,  0 },                   /* 0x8b */
1181 >  { chm_nosuch,  0 },                   /* 0x8c */
1182 >  { chm_nosuch,  0 },                   /* 0x8d */
1183 >  { chm_nosuch,  0 },                   /* 0x8e */
1184 >  { chm_nosuch,  0 },                   /* 0x8f */
1185 >  { chm_nosuch,  0 },                   /* 0x90 */
1186 >  { chm_nosuch,  0 },                   /* 0x91 */
1187 >  { chm_nosuch,  0 },                   /* 0x92 */
1188 >  { chm_nosuch,  0 },                   /* 0x93 */
1189 >  { chm_nosuch,  0 },                   /* 0x94 */
1190 >  { chm_nosuch,  0 },                   /* 0x95 */
1191 >  { chm_nosuch,  0 },                   /* 0x96 */
1192 >  { chm_nosuch,  0 },                   /* 0x97 */
1193 >  { chm_nosuch,  0 },                   /* 0x98 */
1194 >  { chm_nosuch,  0 },                   /* 0x99 */
1195 >  { chm_nosuch,  0 },                   /* 0x9a */
1196 >  { chm_nosuch,  0 },                   /* 0x9b */
1197 >  { chm_nosuch,  0 },                   /* 0x9c */
1198 >  { chm_nosuch,  0 },                   /* 0x9d */
1199 >  { chm_nosuch,  0 },                   /* 0x9e */
1200 >  { chm_nosuch,  0 },                   /* 0x9f */
1201 >  { chm_nosuch,  0 },                   /* 0xa0 */
1202 >  { chm_nosuch,  0 },                   /* 0xa1 */
1203 >  { chm_nosuch,  0 },                   /* 0xa2 */
1204 >  { chm_nosuch,  0 },                   /* 0xa3 */
1205 >  { chm_nosuch,  0 },                   /* 0xa4 */
1206 >  { chm_nosuch,  0 },                   /* 0xa5 */
1207 >  { chm_nosuch,  0 },                   /* 0xa6 */
1208 >  { chm_nosuch,  0 },                   /* 0xa7 */
1209 >  { chm_nosuch,  0 },                   /* 0xa8 */
1210 >  { chm_nosuch,  0 },                   /* 0xa9 */
1211 >  { chm_nosuch,  0 },                   /* 0xaa */
1212 >  { chm_nosuch,  0 },                   /* 0xab */
1213 >  { chm_nosuch,  0 },                   /* 0xac */
1214 >  { chm_nosuch,  0 },                   /* 0xad */
1215 >  { chm_nosuch,  0 },                   /* 0xae */
1216 >  { chm_nosuch,  0 },                   /* 0xaf */
1217 >  { chm_nosuch,  0 },                   /* 0xb0 */
1218 >  { chm_nosuch,  0 },                   /* 0xb1 */
1219 >  { chm_nosuch,  0 },                   /* 0xb2 */
1220 >  { chm_nosuch,  0 },                   /* 0xb3 */
1221 >  { chm_nosuch,  0 },                   /* 0xb4 */
1222 >  { chm_nosuch,  0 },                   /* 0xb5 */
1223 >  { chm_nosuch,  0 },                   /* 0xb6 */
1224 >  { chm_nosuch,  0 },                   /* 0xb7 */
1225 >  { chm_nosuch,  0 },                   /* 0xb8 */
1226 >  { chm_nosuch,  0 },                   /* 0xb9 */
1227 >  { chm_nosuch,  0 },                   /* 0xba */
1228 >  { chm_nosuch,  0 },                   /* 0xbb */
1229 >  { chm_nosuch,  0 },                   /* 0xbc */
1230 >  { chm_nosuch,  0 },                   /* 0xbd */
1231 >  { chm_nosuch,  0 },                   /* 0xbe */
1232 >  { chm_nosuch,  0 },                   /* 0xbf */
1233 >  { chm_nosuch,  0 },                   /* 0xc0 */
1234 >  { chm_nosuch,  0 },                   /* 0xc1 */
1235 >  { chm_nosuch,  0 },                   /* 0xc2 */
1236 >  { chm_nosuch,  0 },                   /* 0xc3 */
1237 >  { chm_nosuch,  0 },                   /* 0xc4 */
1238 >  { chm_nosuch,  0 },                   /* 0xc5 */
1239 >  { chm_nosuch,  0 },                   /* 0xc6 */
1240 >  { chm_nosuch,  0 },                   /* 0xc7 */
1241 >  { chm_nosuch,  0 },                   /* 0xc8 */
1242 >  { chm_nosuch,  0 },                   /* 0xc9 */
1243 >  { chm_nosuch,  0 },                   /* 0xca */
1244 >  { chm_nosuch,  0 },                   /* 0xcb */
1245 >  { chm_nosuch,  0 },                   /* 0xcc */
1246 >  { chm_nosuch,  0 },                   /* 0xcd */
1247 >  { chm_nosuch,  0 },                   /* 0xce */
1248 >  { chm_nosuch,  0 },                   /* 0xcf */
1249 >  { chm_nosuch,  0 },                   /* 0xd0 */
1250 >  { chm_nosuch,  0 },                   /* 0xd1 */
1251 >  { chm_nosuch,  0 },                   /* 0xd2 */
1252 >  { chm_nosuch,  0 },                   /* 0xd3 */
1253 >  { chm_nosuch,  0 },                   /* 0xd4 */
1254 >  { chm_nosuch,  0 },                   /* 0xd5 */
1255 >  { chm_nosuch,  0 },                   /* 0xd6 */
1256 >  { chm_nosuch,  0 },                   /* 0xd7 */
1257 >  { chm_nosuch,  0 },                   /* 0xd8 */
1258 >  { chm_nosuch,  0 },                   /* 0xd9 */
1259 >  { chm_nosuch,  0 },                   /* 0xda */
1260 >  { chm_nosuch,  0 },                   /* 0xdb */
1261 >  { chm_nosuch,  0 },                   /* 0xdc */
1262 >  { chm_nosuch,  0 },                   /* 0xdd */
1263 >  { chm_nosuch,  0 },                   /* 0xde */
1264 >  { chm_nosuch,  0 },                   /* 0xdf */
1265 >  { chm_nosuch,  0 },                   /* 0xe0 */
1266 >  { chm_nosuch,  0 },                   /* 0xe1 */
1267 >  { chm_nosuch,  0 },                   /* 0xe2 */
1268 >  { chm_nosuch,  0 },                   /* 0xe3 */
1269 >  { chm_nosuch,  0 },                   /* 0xe4 */
1270 >  { chm_nosuch,  0 },                   /* 0xe5 */
1271 >  { chm_nosuch,  0 },                   /* 0xe6 */
1272 >  { chm_nosuch,  0 },                   /* 0xe7 */
1273 >  { chm_nosuch,  0 },                   /* 0xe8 */
1274 >  { chm_nosuch,  0 },                   /* 0xe9 */
1275 >  { chm_nosuch,  0 },                   /* 0xea */
1276 >  { chm_nosuch,  0 },                   /* 0xeb */
1277 >  { chm_nosuch,  0 },                   /* 0xec */
1278 >  { chm_nosuch,  0 },                   /* 0xed */
1279 >  { chm_nosuch,  0 },                   /* 0xee */
1280 >  { chm_nosuch,  0 },                   /* 0xef */
1281 >  { chm_nosuch,  0 },                   /* 0xf0 */
1282 >  { chm_nosuch,  0 },                   /* 0xf1 */
1283 >  { chm_nosuch,  0 },                   /* 0xf2 */
1284 >  { chm_nosuch,  0 },                   /* 0xf3 */
1285 >  { chm_nosuch,  0 },                   /* 0xf4 */
1286 >  { chm_nosuch,  0 },                   /* 0xf5 */
1287 >  { chm_nosuch,  0 },                   /* 0xf6 */
1288 >  { chm_nosuch,  0 },                   /* 0xf7 */
1289 >  { chm_nosuch,  0 },                   /* 0xf8 */
1290 >  { chm_nosuch,  0 },                   /* 0xf9 */
1291 >  { chm_nosuch,  0 },                   /* 0xfa */
1292 >  { chm_nosuch,  0 },                   /* 0xfb */
1293 >  { chm_nosuch,  0 },                   /* 0xfc */
1294 >  { chm_nosuch,  0 },                   /* 0xfd */
1295 >  { chm_nosuch,  0 },                   /* 0xfe */
1296 >  { chm_nosuch,  0 },                   /* 0xff */
1297   };
1300 – /* *INDENT-ON* */
1298  
1299   /* get_channel_access()
1300   *
# Line 1308 | Line 1305 | static struct ChannelMode ModeTable[255]
1305   * side effects - NONE
1306   */
1307   static int
1308 < get_channel_access(struct Client *source_p, struct Membership *member)
1308 > get_channel_access(const struct Client *source_p,
1309 >                   const struct Membership *member)
1310   {
1311    /* Let hacked servers in for now... */
1312    if (!MyClient(source_p))
1313 <    return CHACCESS_CHANOP;
1313 >    return CHACCESS_REMOTE;
1314  
1315 <  if (member == NULL)
1315 >  if (!member)
1316      return CHACCESS_NOTONCHAN;
1317  
1318 <  /* just to be sure.. */
1318 >  /* Just to be sure.. */
1319    assert(source_p == member->client_p);
1320  
1321    if (has_member_flags(member, CHFL_CHANOP))
1322      return CHACCESS_CHANOP;
1323  
1326 – #ifdef HALFOPS
1324    if (has_member_flags(member, CHFL_HALFOP))
1325      return CHACCESS_HALFOP;
1329 – #endif
1326  
1327    return CHACCESS_PEON;
1328   }
1329  
1330 < /* void send_cap_mode_changes(struct Client *client_p,
1331 < *                        struct Client *source_p,
1336 < *                        struct Channel *chptr, int cap, int nocap)
1337 < * Input: The client sending(client_p), the source client(source_p),
1330 > /* send_mode_changes_server()
1331 > * Input: the source client(source_p),
1332   *        the channel to send mode changes for(chptr)
1333   * Output: None.
1334 < * 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_
1334 > * Side-effects: Sends the appropriate mode changes to servers.
1335   *
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
1336   */
1353 – /* rewritten to ensure parabuf < MODEBUFLEN -db */
1354 –
1337   static void
1338 < send_cap_mode_changes(struct Client *client_p, struct Client *source_p,
1357 <                      struct Channel *chptr, int cap, int nocap)
1338 > send_mode_changes_server(struct Client *source_p, struct Channel *chptr)
1339   {
1340 <  int i, mbl, pbl, arglen, nc, mc;
1341 <  int len;
1342 <  const char *arg = NULL;
1343 <  char *parptr;
1344 <  int dir = MODE_QUERY;
1345 <
1346 <  mc = 0;
1347 <  nc = 0;
1367 <  pbl = 0;
1368 <
1369 <  parabuf[0] = '\0';
1370 <  parptr = parabuf;
1371 <
1372 <  if ((cap & CAP_TS6) && source_p->id[0] != '\0')
1373 <    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);
1340 >  char modebuf[IRCD_BUFSIZE] = "";
1341 >  char parabuf[IRCD_BUFSIZE] = "";
1342 >  char *parptr = parabuf;
1343 >  unsigned int mbl = 0, pbl = 0, arglen = 0, modecount = 0, paracount = 0;
1344 >  unsigned int dir = MODE_QUERY;
1345 >
1346 >  mbl = snprintf(modebuf, sizeof(modebuf), ":%s TMODE %ju %s ",
1347 >                 source_p->id, chptr->creationtime, chptr->name);
1348  
1349 <  /* loop the list of - modes we have */
1350 <  for (i = 0; i < mode_count; i++)
1349 >  /* Loop the list of modes we have */
1350 >  for (unsigned int i = 0; i < mode_count; ++i)
1351    {
1352 <    /* 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))
1352 >    if (mode_changes[i].letter == 0)
1353        continue;
1354  
1355 <    arg = "";
1356 <
1393 <    if ((cap & CAP_TS6) && mode_changes[i].id)
1355 >    const char *arg;
1356 >    if (mode_changes[i].id)
1357        arg = mode_changes[i].id;
1358 <    if (*arg == '\0')
1358 >    else
1359        arg = mode_changes[i].arg;
1360  
1361 <    /* 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)
1361 >    if (arg)
1362        arglen = strlen(arg);
1363      else
1364        arglen = 0;
1365  
1366 <    if ((mc == MAXMODEPARAMS) ||
1367 <        ((arglen + mbl + pbl + 2) > IRCD_BUFSIZE) ||
1368 <        (pbl + arglen + BAN_FUDGE) >= MODEBUFLEN)
1366 >    /*
1367 >     * If we're creeping past the buf size, we need to send it and make
1368 >     * another line for the other modes
1369 >     */
1370 >    if ((paracount == MAXMODEPARAMS) ||
1371 >        ((arglen + mbl + pbl + 2 /* +2 for /r/n */ ) > IRCD_BUFSIZE))
1372      {
1373 <      if (nc != 0)
1374 <        sendto_server(client_p, source_p, chptr, cap, nocap,
1375 <                      LL_ICHAN | LL_ICLIENT, "%s %s",
1376 <                      modebuf, parabuf);
1377 <      nc = 0;
1378 <      mc = 0;
1379 <
1380 <      if ((cap & CAP_TS6) && source_p->id[0] != '\0')
1422 <        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);
1373 >      if (modecount)
1374 >        sendto_server(source_p, 0, 0, "%s %s", modebuf, parabuf);
1375 >
1376 >      modecount = 0;
1377 >      paracount = 0;
1378 >
1379 >      mbl = snprintf(modebuf, sizeof(modebuf), ":%s TMODE %ju %s ",
1380 >                     source_p->id, chptr->creationtime, chptr->name);
1381  
1382        pbl = 0;
1383        parabuf[0] = '\0';
# Line 1439 | Line 1393 | send_cap_mode_changes(struct Client *cli
1393  
1394      modebuf[mbl++] = mode_changes[i].letter;
1395      modebuf[mbl] = '\0';
1396 <    nc++;
1396 >    ++modecount;
1397  
1398 <    if (arg != NULL)
1398 >    if (arg)
1399      {
1400 <      len = ircsprintf(parptr, "%s ", arg);
1400 >      int len = sprintf(parptr, (pbl == 0) ? "%s" : " %s", arg);
1401        pbl += len;
1402        parptr += len;
1403 <      mc++;
1403 >      ++paracount;
1404      }
1405    }
1406  
1407 <  if (pbl && parabuf[pbl - 1] == ' ')
1408 <    parabuf[pbl - 1] = 0;
1455 <
1456 <  if (nc != 0)
1457 <    sendto_server(client_p, source_p, chptr, cap, nocap,
1458 <                  LL_ICLIENT, "%s %s", modebuf, parabuf);
1407 >  if (modecount)
1408 >    sendto_server(source_p, 0, 0, "%s %s", modebuf, parabuf);
1409   }
1410  
1411   /* void send_mode_changes(struct Client *client_p,
# Line 1468 | Line 1418 | send_cap_mode_changes(struct Client *cli
1418   * Side-effects: Sends the appropriate mode changes to other clients
1419   *               and propagates to servers.
1420   */
1471 – /* ensure parabuf < MODEBUFLEN -db */
1421   static void
1422 < send_mode_changes(struct Client *client_p, struct Client *source_p,
1474 <                  struct Channel *chptr, char *chname)
1422 > send_mode_changes_client(struct Client *source_p, struct Channel *chptr)
1423   {
1424 <  int i, mbl, pbl, arglen, nc, mc;
1477 <  int len;
1478 <  const char *arg = NULL;
1479 <  char *parptr;
1480 <  int dir = MODE_QUERY;
1424 >  unsigned int flags = 0;
1425  
1426 <  /* bail out if we have nothing to do... */
1483 <  if (!mode_count)
1484 <    return;
1485 <
1486 <  if (IsServer(source_p))
1487 <    mbl = ircsprintf(modebuf, ":%s MODE %s ", (IsHidden(source_p) ||
1488 <                     ConfigServerHide.hide_servers) ?
1489 <                     me.name : source_p->name, chname);
1490 <  else
1491 <    mbl = ircsprintf(modebuf, ":%s!%s@%s MODE %s ", source_p->name,
1492 <                     source_p->username, source_p->host, chname);
1493 <
1494 <  mc = 0;
1495 <  nc = 0;
1496 <  pbl = 0;
1497 <
1498 <  parabuf[0] = '\0';
1499 <  parptr = parabuf;
1500 <
1501 <  for (i = 0; i < mode_count; i++)
1426 >  for (unsigned int pass = 2; pass--; flags = CHFL_CHANOP | CHFL_HALFOP)
1427    {
1428 <    if (mode_changes[i].letter == 0 ||
1429 <        mode_changes[i].mems == NON_CHANOPS ||
1430 <        mode_changes[i].mems == ONLY_SERVERS)
1431 <      continue;
1432 <
1433 <    arg = mode_changes[i].arg;
1434 <    if (arg != NULL)
1435 <      arglen = strlen(arg);
1428 >    char modebuf[IRCD_BUFSIZE] = "";
1429 >    char parabuf[IRCD_BUFSIZE] = "";
1430 >    char *parptr = parabuf;
1431 >    unsigned int mbl = 0, pbl = 0, arglen = 0, modecount = 0, paracount = 0;
1432 >    unsigned int dir = MODE_QUERY;
1433 >
1434 >    if (IsServer(source_p))
1435 >      mbl = snprintf(modebuf, sizeof(modebuf), ":%s MODE %s ", (IsHidden(source_p) ||
1436 >                     ConfigServerHide.hide_servers) ?
1437 >                     me.name : source_p->name, chptr->name);
1438      else
1439 <      arglen = 0;
1439 >      mbl = snprintf(modebuf, sizeof(modebuf), ":%s!%s@%s MODE %s ", source_p->name,
1440 >                     source_p->username, source_p->host, chptr->name);
1441  
1442 <    if ((mc == MAXMODEPARAMS)  ||
1515 <        ((arglen + mbl + pbl + 2) > IRCD_BUFSIZE) ||
1516 <        ((arglen + pbl + BAN_FUDGE) >= MODEBUFLEN))
1442 >    for (unsigned int i = 0; i < mode_count; ++i)
1443      {
1444 <      if (mbl && modebuf[mbl - 1] == '-')
1445 <        modebuf[mbl - 1] = '\0';
1444 >      if (mode_changes[i].letter == 0 || mode_changes[i].flags != flags)
1445 >        continue;
1446  
1447 <      if (nc != 0)
1448 <        sendto_channel_local(ALL_MEMBERS, NO, chptr, "%s %s", modebuf, parabuf);
1449 <
1524 <      nc = 0;
1525 <      mc = 0;
1526 <
1527 <      if (IsServer(source_p))
1528 <        mbl = ircsprintf(modebuf, ":%s MODE %s ", me.name, chname);
1447 >      const char *arg = mode_changes[i].arg;
1448 >      if (arg)
1449 >        arglen = strlen(arg);
1450        else
1451 <        mbl = ircsprintf(modebuf, ":%s!%s@%s MODE %s ", source_p->name,
1531 <                         source_p->username, source_p->host, chname);
1451 >        arglen = 0;
1452  
1453 <      pbl = 0;
1454 <      parabuf[0] = '\0';
1455 <      parptr = parabuf;
1456 <      dir = MODE_QUERY;
1457 <    }
1458 <
1459 <    if (dir != mode_changes[i].dir)
1460 <    {
1461 <      modebuf[mbl++] = (mode_changes[i].dir == MODE_ADD) ? '+' : '-';
1462 <      dir = mode_changes[i].dir;
1463 <    }
1453 >      if ((paracount == MAXMODEPARAMS) ||
1454 >          ((arglen + mbl + pbl + 2 /* +2 for /r/n */ ) > IRCD_BUFSIZE))
1455 >      {
1456 >        if (modecount)
1457 >          sendto_channel_local(NULL, chptr, flags, 0, 0, "%s %s", modebuf, parabuf);
1458 >
1459 >        modecount = 0;
1460 >        paracount = 0;
1461 >
1462 >        if (IsServer(source_p))
1463 >          mbl = snprintf(modebuf, sizeof(modebuf), ":%s MODE %s ", (IsHidden(source_p) ||
1464 >                         ConfigServerHide.hide_servers) ?
1465 >                         me.name : source_p->name, chptr->name);
1466 >        else
1467 >          mbl = snprintf(modebuf, sizeof(modebuf), ":%s!%s@%s MODE %s ", source_p->name,
1468 >                         source_p->username, source_p->host, chptr->name);
1469  
1470 <    modebuf[mbl++] = mode_changes[i].letter;
1471 <    modebuf[mbl] = '\0';
1472 <    nc++;
1470 >        pbl = 0;
1471 >        parabuf[0] = '\0';
1472 >        parptr = parabuf;
1473 >        dir = MODE_QUERY;
1474 >      }
1475  
1476 <    if (arg != NULL)
1477 <    {
1478 <      len = ircsprintf(parptr, "%s ", arg);
1479 <      pbl += len;
1480 <      parptr += len;
1481 <      mc++;
1476 >      if (dir != mode_changes[i].dir)
1477 >      {
1478 >        modebuf[mbl++] = (mode_changes[i].dir == MODE_ADD) ? '+' : '-';
1479 >        dir = mode_changes[i].dir;
1480 >      }
1481 >
1482 >      modebuf[mbl++] = mode_changes[i].letter;
1483 >      modebuf[mbl] = '\0';
1484 >      ++modecount;
1485 >
1486 >      if (arg)
1487 >      {
1488 >        int len = sprintf(parptr, (pbl == 0) ? "%s" : " %s", arg);
1489 >        pbl += len;
1490 >        parptr += len;
1491 >        ++paracount;
1492 >      }
1493      }
1556 –  }
1557 –
1558 –  if (pbl && parabuf[pbl - 1] == ' ')
1559 –    parabuf[pbl - 1] = 0;
1494  
1495 <  if (nc != 0)
1496 <    sendto_channel_local(ALL_MEMBERS, NO, chptr, "%s %s", modebuf, parabuf);
1497 <
1498 <  nc = 0;
1565 <  mc = 0;
1495 >    if (modecount)
1496 >      sendto_channel_local(NULL, chptr, flags, 0, 0, "%s %s", modebuf, parabuf);
1497 >  }
1498 > }
1499  
1500 <  /* Now send to servers... */
1501 <  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
1500 > /*
1501 > * Input: The the client this originated
1502   *        from, the channel, the parameter count starting at the modes,
1503   *        the parameters, the channel name.
1504   * Output: None.
# Line 1584 | Line 1507 | send_mode_changes(struct Client *client_
1507   *               clients.
1508   */
1509   void
1510 < set_channel_mode(struct Client *client_p, struct Client *source_p, struct Channel *chptr,
1511 <                 struct Membership *member, int parc, char *parv[], char *chname)
1510 > set_channel_mode(struct Client *source_p, struct Channel *chptr,
1511 >                 struct Membership *member, int parc, char *parv[])
1512   {
1513    int dir = MODE_ADD;
1514    int parn = 1;
1515 <  int alevel, errors = 0;
1593 <  char *ml = parv[0], c;
1594 <  int table_position;
1515 >  int alevel = 0, errors = 0;
1516  
1517    mode_count = 0;
1518    mode_limit = 0;
# Line 1599 | Line 1520 | set_channel_mode(struct Client *client_p
1520  
1521    alevel = get_channel_access(source_p, member);
1522  
1523 <  for (; (c = *ml) != '\0'; ml++)
1523 >  for (const char *ml = parv[0]; *ml; ++ml)
1524    {
1525 < #if 0
1605 <    if(mode_count > 20)
1606 <      break;
1607 < #endif
1608 <    switch (c)
1525 >    switch (*ml)
1526      {
1527        case '+':
1528          dir = MODE_ADD;
# Line 1617 | Line 1534 | set_channel_mode(struct Client *client_p
1534          dir = MODE_QUERY;
1535          break;
1536        default:
1537 <        if (c < 'A' || c > 'z')
1538 <          table_position = 0;
1539 <        else
1540 <          table_position = c - 'A' + 1;
1541 <        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);
1537 >      {
1538 >        const struct ChannelMode *tptr = &ModeTable[(unsigned char)*ml];
1539 >
1540 >        tptr->func(source_p, chptr, parc, &parn, parv,
1541 >                   &errors, alevel, dir, *ml, tptr->d);
1542          break;
1543 +      }
1544      }
1545    }
1546  
1547 <  send_mode_changes(client_p, source_p, chptr, chname);
1547 >  /* Bail out if we have nothing to do... */
1548 >  if (!mode_count)
1549 >    return;
1550 >
1551 >  send_mode_changes_client(source_p, chptr);
1552 >  send_mode_changes_server(source_p, chptr);
1553   }

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 8044 by michael, Sat Mar 18 16:52:10 2017 UTC

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

Diff Legend

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