ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid-7.2/src/channel_mode.c
Revision: 34
Committed: Sun Oct 2 21:05:51 2005 UTC (18 years, 5 months ago) by lusky
Content type: text/x-csrc
File size: 46293 byte(s)
Log Message:
create 7.2 branch, we can move/rename it as needed.


File Contents

# User Rev Content
1 adx 30 /*
2     * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
3     * channel_mode.c: Controls modes on channels.
4     *
5     * Copyright (C) 2005 by the past and present ircd coders, and others.
6     *
7     * This program is free software; you can redistribute it and/or modify
8     * it under the terms of the GNU General Public License as published by
9     * the Free Software Foundation; either version 2 of the License, or
10     * (at your option) any later version.
11     *
12     * This program is distributed in the hope that it will be useful,
13     * but WITHOUT ANY WARRANTY; without even the implied warranty of
14     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15     * GNU General Public License for more details.
16     *
17     * You should have received a copy of the GNU General Public License
18     * along with this program; if not, write to the Free Software
19     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20     * USA
21     *
22 knight 31 * $Id$
23 adx 30 */
24    
25     #include "stdinc.h"
26     #include "tools.h"
27     #include "channel.h"
28     #include "channel_mode.h"
29     #include "client.h"
30     #include "common.h"
31     #include "hash.h"
32     #include "irc_string.h"
33     #include "sprintf_irc.h"
34     #include "ircd.h"
35     #include "list.h"
36     #include "numeric.h"
37     #include "s_serv.h" /* captab */
38     #include "s_user.h"
39     #include "send.h"
40     #include "whowas.h"
41     #include "s_conf.h" /* ConfigFileEntry, ConfigChannel */
42     #include "event.h"
43     #include "memory.h"
44     #include "balloc.h"
45     #include "s_log.h"
46    
47     /* some small utility functions */
48     static char *check_string(char *);
49     static char *fix_key(char *);
50     static char *fix_key_old(char *);
51     static void chm_nosuch(struct Client *, struct Client *,
52     struct Channel *, int, int *, char **, int *, int,
53     int, char, void *, const char *);
54     static void chm_simple(struct Client *, struct Client *, struct Channel *,
55     int, int *, char **, int *, int, int, char, void *,
56     const char *);
57     static void chm_limit(struct Client *, struct Client *, struct Channel *,
58     int, int *, char **, int *, int, int, char, void *,
59     const char *);
60     static void chm_key(struct Client *, struct Client *, struct Channel *,
61     int, int *, char **, int *, int, int, char, void *,
62     const char *);
63     static void chm_op(struct Client *, struct Client *, struct Channel *, int,
64     int *, char **, int *, int, int, char, void *,
65     const char *);
66     #ifdef HALFOPS
67     static void chm_hop(struct Client *, struct Client *, struct Channel *, int,
68     int *, char **, int *, int, int, char, void *,
69     const char *);
70     #endif
71     static void chm_voice(struct Client *, struct Client *, struct Channel *,
72     int, int *, char **, int *, int, int, char, void *,
73     const char *);
74     static void chm_ban(struct Client *, struct Client *, struct Channel *, int,
75     int *, char **, int *, int, int, char, void *,
76     const char *);
77     static void chm_except(struct Client *, struct Client *, struct Channel *,
78     int, int *, char **, int *, int, int, char, void *,
79     const char *);
80     static void chm_invex(struct Client *, struct Client *, struct Channel *,
81     int, int *, char **, int *, int, int, char, void *,
82     const char *);
83     static void send_cap_mode_changes(struct Client *, struct Client *,
84     struct Channel *, int, int);
85     static void send_mode_changes(struct Client *, struct Client *,
86     struct Channel *, char *);
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];
96     static struct ChModeChange mode_changes[IRCD_BUFSIZE];
97     static int mode_count;
98     static int mode_limit; /* number of modes set other than simple */
99     static int simple_modes_mask; /* bit mask of simple modes already set */
100     static int channel_capabs[] = { CAP_EX, CAP_IE, CAP_TS6 };
101     static struct ChCapCombo chcap_combos[NCHCAP_COMBOS];
102     extern BlockHeap *ban_heap;
103    
104    
105     /* XXX check_string is propably not longer required in add_id and del_id */
106     /* check_string()
107     *
108     * inputs - string to check
109     * output - pointer to modified string
110     * side effects - Fixes a string so that the first white space found
111     * becomes an end of string marker (`\0`).
112     * returns the 'fixed' string or "*" if the string
113     * was NULL length or a NULL pointer.
114     */
115     static char *
116     check_string(char *s)
117     {
118     char *str = s;
119     static char star[] = "*";
120    
121     if (EmptyString(s))
122     return (star);
123    
124     for (; *s; ++s)
125     {
126     if (IsSpace(*s))
127     {
128     *s = '\0';
129     break;
130     }
131     }
132    
133     return (str);
134     }
135    
136     /*
137     * Ban functions to work with mode +b/e/d/I
138     */
139     /* add the specified ID to the channel..
140     * -is 8/9/00
141     */
142    
143     int
144     add_id(struct Client *client_p, struct Channel *chptr, char *banid, int type)
145     {
146     dlink_list *list;
147     dlink_node *ban;
148     size_t len = 0;
149     struct Ban *actualBan;
150     unsigned int num_mask;
151     char *name = NULL, *user = NULL, *host = NULL;
152    
153     /* dont let local clients overflow the b/e/I lists */
154     if (MyClient(client_p))
155     {
156     num_mask = dlink_list_length(&chptr->banlist) +
157     dlink_list_length(&chptr->exceptlist) +
158     dlink_list_length(&chptr->invexlist);
159    
160     if (num_mask >= ConfigChannel.max_bans)
161     {
162     sendto_one(client_p, form_str(ERR_BANLISTFULL),
163     me.name, client_p->name, chptr->chname, banid);
164     return 0;
165     }
166    
167     collapse(banid);
168     }
169    
170     split_nuh(check_string(banid), &name, &user, &host);
171    
172     /*
173     * Assemble a n!u@h and print it back to banid for sending
174     * the mode to the channel.
175     */
176     len = ircsprintf(banid, "%s!%s@%s", name, user, host);
177    
178     switch (type)
179     {
180     case CHFL_BAN:
181     list = &chptr->banlist;
182     clear_ban_cache(chptr);
183     break;
184     case CHFL_EXCEPTION:
185     list = &chptr->exceptlist;
186     clear_ban_cache(chptr);
187     break;
188     case CHFL_INVEX:
189     list = &chptr->invexlist;
190     break;
191     default:
192     assert(0);
193     return 0;
194     }
195    
196     DLINK_FOREACH(ban, list->head)
197     {
198     actualBan = ban->data;
199     if (!irccmp(actualBan->name, name) &&
200     !irccmp(actualBan->username, user) &&
201     !irccmp(actualBan->host, host))
202     {
203     MyFree(name);
204     MyFree(user);
205     MyFree(host);
206     return 0;
207     }
208     }
209    
210     actualBan = BlockHeapAlloc(ban_heap);
211     actualBan->when = CurrentTime;
212     actualBan->name = name;
213     actualBan->username = user;
214     actualBan->host = host;
215     actualBan->len = len-2; /* -2 for @ and ! */
216    
217     if (IsClient(client_p))
218     {
219     actualBan->who =
220     MyMalloc(strlen(client_p->name) +
221     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     }
226     else
227     DupString(actualBan->who, client_p->name);
228    
229     dlinkAdd(actualBan, &actualBan->node, list);
230    
231     return 1;
232     }
233    
234     /*
235     * inputs - pointer to channel
236     * - pointer to ban id
237     * - type of ban, i.e. ban, exception, invex
238     * output - 0 for failure, 1 for success
239     * side effects -
240     */
241     static int
242     del_id(struct Channel *chptr, char *banid, int type)
243     {
244     dlink_list *list;
245     dlink_node *ban;
246     struct Ban *banptr;
247     char *name = NULL, *user = NULL, *host = NULL;
248    
249     if (banid == NULL)
250     return 0;
251    
252     split_nuh(check_string(banid), &name, &user, &host);
253    
254     /*
255     * Assemble a n!u@h and print it back to banid for sending
256     * the mode to the channel.
257     */
258     ircsprintf(banid, "%s!%s@%s", name, user, host);
259    
260     switch (type)
261     {
262     case CHFL_BAN:
263     list = &chptr->banlist;
264     clear_ban_cache(chptr);
265     break;
266     case CHFL_EXCEPTION:
267     list = &chptr->exceptlist;
268     clear_ban_cache(chptr);
269     break;
270     case CHFL_INVEX:
271     list = &chptr->invexlist;
272     break;
273     default:
274     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);
280     }
281    
282     DLINK_FOREACH(ban, list->head)
283     {
284     banptr = ban->data;
285    
286     if (!irccmp(name, banptr->name) &&
287     !irccmp(user, banptr->username) &&
288     !irccmp(host, banptr->host))
289     {
290     remove_ban(banptr, list);
291     MyFree(name);
292     MyFree(user);
293     MyFree(host);
294     return 1;
295     }
296     }
297    
298     MyFree(name);
299     MyFree(user);
300     MyFree(host);
301     return 0;
302     }
303    
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    
318     /* channel_modes()
319     *
320     * inputs - pointer to channel
321     * - pointer to client
322     * - pointer to mode buf
323     * - pointer to parameter buf
324     * output - NONE
325     * side effects - write the "simple" list of channel modes for channel
326     * chptr onto buffer mbuf with the parameters in pbuf.
327     */
328     void
329     channel_modes(struct Channel *chptr, struct Client *client_p,
330     char *mbuf, char *pbuf)
331     {
332     int i;
333    
334     *mbuf++ = '+';
335     *pbuf = '\0';
336    
337     for (i = 0; flags[i].mode; ++i)
338     if (chptr->mode.mode & flags[i].mode)
339     *mbuf++ = flags[i].letter;
340    
341     if (chptr->mode.limit)
342     {
343     *mbuf++ = 'l';
344    
345     if (IsMember(client_p, chptr) || IsServer(client_p))
346     pbuf += ircsprintf(pbuf, "%d ", chptr->mode.limit);
347     }
348    
349     if (chptr->mode.key[0])
350     {
351     *mbuf++ = 'k';
352    
353     if (*pbuf || IsMember(client_p, chptr) || IsServer(client_p))
354     ircsprintf(pbuf, "%s ", chptr->mode.key);
355     }
356    
357     *mbuf = '\0';
358     }
359    
360     /* fix_key()
361     *
362     * inputs - pointer to key to clean up
363     * output - pointer to cleaned up key
364     * side effects - input string is modified
365     *
366     * stolen from Undernet's ircd -orabidoo
367     */
368     static char *
369     fix_key(char *arg)
370     {
371     unsigned char *s, *t, c;
372    
373     for (s = t = (unsigned char *)arg; (c = *s); s++)
374     {
375     c &= 0x7f;
376     if (c != ':' && c > ' ' && c != ',')
377     *t++ = c;
378     }
379    
380     *t = '\0';
381     return(arg);
382     }
383    
384     /* fix_key_old()
385     *
386     * inputs - pointer to key to clean up
387     * 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
392     */
393     static char *
394     fix_key_old(char *arg)
395     {
396     unsigned char *s, *t, c;
397    
398     for (s = t = (unsigned char *)arg; (c = *s); s++)
399     {
400     c &= 0x7f;
401     if ((c != 0x0a) && (c != ':') && (c != 0x0d) && (c != ','))
402     *t++ = c;
403     }
404    
405     *t = '\0';
406     return(arg);
407     }
408    
409     /* bitmasks for various error returns that set_channel_mode should only return
410     * once per call -orabidoo
411     */
412    
413     #define SM_ERR_NOTS 0x00000001 /* No TS on channel */
414     #define SM_ERR_NOOPS 0x00000002 /* No chan ops */
415     #define SM_ERR_UNKNOWN 0x00000004
416     #define SM_ERR_RPL_B 0x00000008
417     #define SM_ERR_RPL_E 0x00000010
418     #define SM_ERR_NOTONCHANNEL 0x00000020 /* Not on channel */
419     #define SM_ERR_RPL_I 0x00000040
420    
421     /* Now lets do some stuff to keep track of what combinations of
422     * servers exist...
423     * Note that the number of combinations doubles each time you add
424     * something to this list. Each one is only quick if no servers use that
425     * combination, but if the numbers get too high here MODE will get too
426     * slow. I suggest if you get more than 7 here, you consider getting rid
427     * of some and merging or something. If it wasn't for irc+cs we would
428     * probably not even need to bother about most of these, but unfortunately
429     * we do. -A1kmm
430     */
431    
432     /* void init_chcap_usage_counts(void)
433     *
434     * Inputs - none
435     * Output - none
436     * Side-effects - Initialises the usage counts to zero. Fills in the
437     * chcap_yes and chcap_no combination tables.
438     */
439     void
440     init_chcap_usage_counts(void)
441     {
442     unsigned long m, c, y, n;
443    
444     memset(chcap_combos, 0, sizeof(chcap_combos));
445    
446     /* For every possible combination */
447     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     }
460     }
461    
462     /* void set_chcap_usage_counts(struct Client *serv_p)
463     * Input: serv_p; The client whose capabs to register.
464     * 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)
470     {
471     int n;
472    
473     for (n = 0; n < NCHCAP_COMBOS; n++)
474     {
475     if (((serv_p->localClient->caps & chcap_combos[n].cap_yes) ==
476     chcap_combos[n].cap_yes) &&
477     ((serv_p->localClient->caps & chcap_combos[n].cap_no) == 0))
478     {
479     chcap_combos[n].count++;
480     return;
481     }
482     }
483    
484     /* This should be impossible -A1kmm. */
485     assert(0);
486     }
487    
488     /* 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;
499    
500     for (n = 0; n < NCHCAP_COMBOS; n++)
501     {
502     if ((serv_p->localClient->caps & chcap_combos[n].cap_yes) ==
503     chcap_combos[n].cap_yes &&
504     (serv_p->localClient->caps & chcap_combos[n].cap_no) == 0)
505     {
506     /* Hopefully capabs can't change dynamically or anything... */
507     assert(chcap_combos[n].count > 0);
508     chcap_combos[n].count--;
509     return;
510     }
511     }
512    
513     /* This should be impossible -A1kmm. */
514     assert(0);
515     }
516    
517     /* Mode functions handle mode changes for a particular mode... */
518     static void
519     chm_nosuch(struct Client *client_p, struct Client *source_p,
520     struct Channel *chptr, int parc, int *parn,
521     char **parv, int *errors, int alev, int dir, char c, void *d,
522     const char *chname)
523     {
524     if (*errors & SM_ERR_UNKNOWN)
525     return;
526    
527     *errors |= SM_ERR_UNKNOWN;
528     sendto_one(source_p, form_str(ERR_UNKNOWNMODE), me.name,
529     source_p->name, c);
530     }
531    
532     static void
533     chm_simple(struct Client *client_p, struct Client *source_p, struct Channel *chptr,
534     int parc, int *parn, char **parv, int *errors, int alev, int dir,
535     char c, void *d, const char *chname)
536     {
537     long mode_type;
538    
539     mode_type = (long)d;
540    
541     if ((alev < CHACCESS_HALFOP) ||
542     ((mode_type == MODE_PRIVATE) && (alev < CHACCESS_CHANOP)))
543     {
544     if (!(*errors & SM_ERR_NOOPS))
545     sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ?
546     ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED),
547     me.name, source_p->name, chname);
548     *errors |= SM_ERR_NOOPS;
549     return;
550     }
551    
552     /* If have already dealt with this simple mode, ignore it */
553     if (simple_modes_mask & mode_type)
554     return;
555    
556     simple_modes_mask |= mode_type;
557    
558     /* 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)) */
567     {
568     chptr->mode.mode |= mode_type;
569    
570     mode_changes[mode_count].letter = c;
571     mode_changes[mode_count].dir = MODE_ADD;
572     mode_changes[mode_count].caps = 0;
573     mode_changes[mode_count].nocaps = 0;
574     mode_changes[mode_count].id = NULL;
575     mode_changes[mode_count].mems = ALL_MEMBERS;
576     mode_changes[mode_count++].arg = NULL;
577     }
578     else if ((dir == MODE_DEL)) /* && (chptr->mode.mode & mode_type)) */
579     {
580     /* setting - */
581    
582     chptr->mode.mode &= ~mode_type;
583    
584     mode_changes[mode_count].letter = c;
585     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;
589     mode_changes[mode_count].id = NULL;
590     mode_changes[mode_count++].arg = NULL;
591     }
592     }
593    
594     static void
595     chm_ban(struct Client *client_p, struct Client *source_p,
596     struct Channel *chptr, int parc, int *parn,
597     char **parv, int *errors, int alev, int dir, char c, void *d,
598     const char *chname)
599     {
600     char *mask = NULL;
601    
602     if (dir == MODE_QUERY || parc <= *parn)
603     {
604     dlink_node *ptr = NULL;
605    
606     if (*errors & SM_ERR_RPL_B)
607     return;
608    
609     *errors |= SM_ERR_RPL_B;
610    
611     DLINK_FOREACH(ptr, chptr->banlist.head)
612     {
613     const struct Ban *banptr = ptr->data;
614     sendto_one(client_p, form_str(RPL_BANLIST),
615     me.name, client_p->name, chname,
616     banptr->name, banptr->username, banptr->host,
617     banptr->who, banptr->when);
618     }
619    
620     sendto_one(source_p, form_str(RPL_ENDOFBANLIST), me.name,
621     source_p->name, chname);
622     return;
623     }
624    
625     if (alev < CHACCESS_HALFOP)
626     {
627     if (!(*errors & SM_ERR_NOOPS))
628     sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ?
629     ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED),
630     me.name, source_p->name, chname);
631     *errors |= SM_ERR_NOOPS;
632     return;
633     }
634    
635     if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
636     return;
637    
638     mask = parv[(*parn)++];
639    
640     if (IsServer(client_p))
641     if (strchr(mask, ' '))
642     return;
643    
644     switch (dir)
645     {
646     case MODE_ADD:
647     if (!add_id(source_p, chptr, mask, CHFL_BAN))
648     return;
649     break;
650     case MODE_DEL:
651     /* XXX grrrrrrr */
652     #ifdef NO_BAN_COOKIE
653     if (!del_id(chptr, mask, CHFL_BAN))
654     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
661     break;
662     default:
663     assert(0);
664     }
665    
666     mode_changes[mode_count].letter = c;
667     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;
671     mode_changes[mode_count].id = NULL;
672     mode_changes[mode_count++].arg = mask;
673     }
674    
675     static void
676     chm_except(struct Client *client_p, struct Client *source_p,
677     struct Channel *chptr, int parc, int *parn,
678     char **parv, int *errors, int alev, int dir, char c, void *d,
679     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)))
689     {
690     if (*errors & SM_ERR_RPL_E)
691     return;
692    
693     *errors |= SM_ERR_RPL_E;
694     return;
695     }
696    
697     if (alev < CHACCESS_HALFOP)
698     {
699     if (!(*errors & SM_ERR_NOOPS))
700     sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ?
701     ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED),
702     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;
710    
711     if (*errors & SM_ERR_RPL_E)
712     return;
713    
714     *errors |= SM_ERR_RPL_E;
715    
716     DLINK_FOREACH(ptr, chptr->exceptlist.head)
717     {
718     const struct Ban *banptr = ptr->data;
719     sendto_one(client_p, form_str(RPL_EXCEPTLIST),
720     me.name, client_p->name, chname,
721     banptr->name, banptr->username, banptr->host,
722     banptr->who, banptr->when);
723     }
724    
725     sendto_one(source_p, form_str(RPL_ENDOFEXCEPTLIST), me.name,
726     source_p->name, chname);
727     return;
728     }
729    
730     if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
731     return;
732    
733     mask = parv[(*parn)++];
734    
735     if (IsServer(client_p))
736     if (strchr(mask, ' '))
737     return;
738    
739     switch (dir)
740     {
741     case MODE_ADD:
742     if (!add_id(source_p, chptr, mask, CHFL_EXCEPTION))
743     return;
744     break;
745     case MODE_DEL:
746     if (!del_id(chptr, mask, CHFL_EXCEPTION))
747     return;
748     break;
749     default:
750     assert(0);
751     }
752    
753     mode_changes[mode_count].letter = c;
754     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    
763     mode_changes[mode_count].id = NULL;
764     mode_changes[mode_count++].arg = mask;
765     }
766    
767     static void
768     chm_invex(struct Client *client_p, struct Client *source_p,
769     struct Channel *chptr, int parc, int *parn,
770     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    
799     if (dir == MODE_QUERY || parc <= *parn)
800     {
801     dlink_node *ptr = NULL;
802    
803     if (*errors & SM_ERR_RPL_I)
804     return;
805    
806     *errors |= SM_ERR_RPL_I;
807    
808     DLINK_FOREACH(ptr, chptr->invexlist.head)
809     {
810     const struct Ban *banptr = ptr->data;
811     sendto_one(client_p, form_str(RPL_INVITELIST), me.name,
812     client_p->name, chname,
813     banptr->name, banptr->username, banptr->host,
814     banptr->who, banptr->when);
815     }
816    
817     sendto_one(source_p, form_str(RPL_ENDOFINVITELIST), me.name,
818     source_p->name, chname);
819     return;
820     }
821    
822     if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
823     return;
824    
825     mask = parv[(*parn)++];
826    
827     if (IsServer(client_p))
828     if (strchr(mask, ' '))
829     return;
830    
831     switch (dir)
832     {
833     case MODE_ADD:
834     if (!add_id(source_p, chptr, mask, CHFL_INVEX))
835     return;
836     break;
837     case MODE_DEL:
838     if (!del_id(chptr, mask, CHFL_INVEX))
839     return;
840     break;
841     default:
842     assert(0);
843     }
844    
845     mode_changes[mode_count].letter = c;
846     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    
855     mode_changes[mode_count].id = NULL;
856     mode_changes[mode_count++].arg = mask;
857     }
858    
859     /*
860     * inputs - pointer to channel
861     * output - none
862     * side effects - clear ban cache
863     */
864     void
865     clear_ban_cache(struct Channel *chptr)
866     {
867     dlink_node *ptr = NULL;
868    
869     DLINK_FOREACH(ptr, chptr->locmembers.head)
870     {
871     struct Membership *ms = ptr->data;
872     ms->flags &= ~(CHFL_BAN_SILENCED|CHFL_BAN_CHECKED);
873     }
874     }
875    
876     static void
877     chm_op(struct Client *client_p, struct Client *source_p,
878     struct Channel *chptr, int parc, int *parn,
879     char **parv, int *errors, int alev, int dir, char c, void *d,
880     const char *chname)
881     {
882     char *opnick;
883     struct Client *targ_p;
884     struct Membership *member;
885    
886     if (alev < CHACCESS_CHANOP)
887     {
888     if (!(*errors & SM_ERR_NOOPS))
889     sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ?
890     ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED),
891     me.name, source_p->name, chname);
892     *errors |= SM_ERR_NOOPS;
893     return;
894     }
895    
896     if ((dir == MODE_QUERY) || (parc <= *parn))
897     return;
898    
899     opnick = parv[(*parn)++];
900    
901     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)
907     {
908     if (!(*errors & SM_ERR_NOTONCHANNEL))
909     sendto_one(source_p, form_str(ERR_USERNOTINCHANNEL),
910     me.name, source_p->name, opnick, chname);
911     *errors |= SM_ERR_NOTONCHANNEL;
912     return;
913     }
914    
915     if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
916     return;
917    
918     /* no redundant mode changes */
919     if (dir == MODE_ADD && has_member_flags(member, CHFL_CHANOP))
920     return;
921     if (dir == MODE_DEL && !has_member_flags(member, CHFL_CHANOP))
922     return;
923    
924     mode_changes[mode_count].letter = 'o';
925     mode_changes[mode_count].dir = dir;
926     mode_changes[mode_count].caps = 0;
927     mode_changes[mode_count].nocaps = 0;
928     mode_changes[mode_count].mems = ALL_MEMBERS;
929     mode_changes[mode_count].id = targ_p->id;
930     mode_changes[mode_count].arg = targ_p->name;
931     mode_changes[mode_count++].client = targ_p;
932    
933     if (dir == MODE_ADD)
934     {
935     AddMemberFlag(member, CHFL_CHANOP);
936     DelMemberFlag(member, CHFL_DEOPPED);
937     }
938     else
939     DelMemberFlag(member, CHFL_CHANOP);
940     }
941    
942     #ifdef HALFOPS
943     static void
944     chm_hop(struct Client *client_p, struct Client *source_p,
945     struct Channel *chptr, int parc, int *parn,
946     char **parv, int *errors, int alev, int dir, char c, void *d,
947     const char *chname)
948     {
949     char *opnick;
950     struct Client *targ_p;
951     struct Membership *member;
952    
953     /* *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))
968     {
969     if (!(*errors & SM_ERR_NOOPS))
970     sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ?
971     ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED),
972     me.name, source_p->name, chname);
973     *errors |= SM_ERR_NOOPS;
974     return;
975     }
976    
977     if ((dir == MODE_QUERY) || (parc <= *parn))
978     return;
979    
980     opnick = parv[(*parn)++];
981    
982     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)
988     {
989     if (!(*errors & SM_ERR_NOTONCHANNEL))
990     sendto_one(source_p, form_str(ERR_USERNOTINCHANNEL),
991     me.name, source_p->name, opnick, chname);
992     *errors |= SM_ERR_NOTONCHANNEL;
993     return;
994     }
995    
996     if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
997     return;
998    
999     /* no redundant mode changes */
1000     if (dir == MODE_ADD && has_member_flags(member, CHFL_HALFOP))
1001     return;
1002     if (dir == MODE_DEL && !has_member_flags(member, CHFL_HALFOP))
1003     return;
1004    
1005     mode_changes[mode_count].letter = 'h';
1006     mode_changes[mode_count].dir = dir;
1007     mode_changes[mode_count].caps = 0;
1008     mode_changes[mode_count].nocaps = 0;
1009     mode_changes[mode_count].mems = ALL_MEMBERS;
1010     mode_changes[mode_count].id = targ_p->id;
1011     mode_changes[mode_count].arg = targ_p->name;
1012     mode_changes[mode_count++].client = targ_p;
1013    
1014     if (dir == MODE_ADD)
1015     {
1016     AddMemberFlag(member, CHFL_HALFOP);
1017     DelMemberFlag(member, CHFL_DEOPPED);
1018     }
1019     else
1020     DelMemberFlag(member, CHFL_HALFOP);
1021     }
1022     #endif
1023    
1024     static void
1025     chm_voice(struct Client *client_p, struct Client *source_p,
1026     struct Channel *chptr, int parc, int *parn,
1027     char **parv, int *errors, int alev, int dir, char c, void *d,
1028     const char *chname)
1029     {
1030     char *opnick;
1031     struct Client *targ_p;
1032     struct Membership *member;
1033    
1034     if (alev < CHACCESS_HALFOP)
1035     {
1036     if (!(*errors & SM_ERR_NOOPS))
1037     sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ?
1038     ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED),
1039     me.name, source_p->name, chname);
1040     *errors |= SM_ERR_NOOPS;
1041     return;
1042     }
1043    
1044     if ((dir == MODE_QUERY) || parc <= *parn)
1045     return;
1046    
1047     opnick = parv[(*parn)++];
1048    
1049     if ((targ_p = find_chasing(client_p, source_p, opnick, NULL)) == NULL)
1050     return;
1051     if (!IsClient(targ_p))
1052     return;
1053    
1054     if ((member = find_channel_link(targ_p, chptr)) == NULL)
1055     {
1056     if (!(*errors & SM_ERR_NOTONCHANNEL))
1057     sendto_one(source_p, form_str(ERR_USERNOTINCHANNEL),
1058     me.name, source_p->name, opnick, chname);
1059     *errors |= SM_ERR_NOTONCHANNEL;
1060     return;
1061     }
1062    
1063     if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
1064     return;
1065    
1066     /* no redundant mode changes */
1067     if (dir == MODE_ADD && has_member_flags(member, CHFL_VOICE))
1068     return;
1069     if (dir == MODE_DEL && !has_member_flags(member, CHFL_VOICE))
1070     return;
1071    
1072     mode_changes[mode_count].letter = 'v';
1073     mode_changes[mode_count].dir = dir;
1074     mode_changes[mode_count].caps = 0;
1075     mode_changes[mode_count].nocaps = 0;
1076     mode_changes[mode_count].mems = ALL_MEMBERS;
1077     mode_changes[mode_count].id = targ_p->id;
1078     mode_changes[mode_count].arg = targ_p->name;
1079     mode_changes[mode_count++].client = targ_p;
1080    
1081     if (dir == MODE_ADD)
1082     AddMemberFlag(member, CHFL_VOICE);
1083     else
1084     DelMemberFlag(member, CHFL_VOICE);
1085     }
1086    
1087     static void
1088     chm_limit(struct Client *client_p, struct Client *source_p,
1089     struct Channel *chptr, int parc, int *parn,
1090     char **parv, int *errors, int alev, int dir, char c, void *d,
1091     const char *chname)
1092     {
1093     int i, limit;
1094     char *lstr;
1095    
1096     if (alev < CHACCESS_HALFOP)
1097     {
1098     if (!(*errors & SM_ERR_NOOPS))
1099     sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ?
1100     ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED),
1101     me.name, source_p->name, chname);
1102     *errors |= SM_ERR_NOOPS;
1103     return;
1104     }
1105    
1106     if (dir == MODE_QUERY)
1107     return;
1108    
1109     if ((dir == MODE_ADD) && parc > *parn)
1110     {
1111     lstr = parv[(*parn)++];
1112    
1113     if ((limit = atoi(lstr)) <= 0)
1114     return;
1115    
1116     ircsprintf(lstr, "%d", limit);
1117    
1118     /* if somebody sets MODE #channel +ll 1 2, accept latter --fl */
1119     for (i = 0; i < mode_count; i++)
1120     {
1121     if (mode_changes[i].letter == c && mode_changes[i].dir == MODE_ADD)
1122     mode_changes[i].letter = 0;
1123     }
1124    
1125     mode_changes[mode_count].letter = c;
1126     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;
1130     mode_changes[mode_count].id = NULL;
1131     mode_changes[mode_count++].arg = lstr;
1132    
1133     chptr->mode.limit = limit;
1134     }
1135     else if (dir == MODE_DEL)
1136     {
1137     if (!chptr->mode.limit)
1138     return;
1139    
1140     chptr->mode.limit = 0;
1141    
1142     mode_changes[mode_count].letter = c;
1143     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;
1147     mode_changes[mode_count].id = NULL;
1148     mode_changes[mode_count++].arg = NULL;
1149     }
1150     }
1151    
1152     static void
1153     chm_key(struct Client *client_p, struct Client *source_p,
1154     struct Channel *chptr, int parc, int *parn,
1155     char **parv, int *errors, int alev, int dir, char c, void *d,
1156     const char *chname)
1157     {
1158     int i;
1159     char *key;
1160    
1161     if (alev < CHACCESS_HALFOP)
1162     {
1163     if (!(*errors & SM_ERR_NOOPS))
1164     sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ?
1165     ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED),
1166     me.name, source_p->name, chname);
1167     *errors |= SM_ERR_NOOPS;
1168     return;
1169     }
1170    
1171     if (dir == MODE_QUERY)
1172     return;
1173    
1174     if ((dir == MODE_ADD) && parc > *parn)
1175     {
1176     key = parv[(*parn)++];
1177    
1178     if (MyClient(source_p))
1179     fix_key(key);
1180     else
1181     fix_key_old(key);
1182    
1183     if (*key == '\0')
1184     return;
1185    
1186     assert(key[0] != ' ');
1187     strlcpy(chptr->mode.key, key, sizeof(chptr->mode.key));
1188    
1189     /* if somebody does MODE #channel +kk a b, accept latter --fl */
1190     for (i = 0; i < mode_count; i++)
1191     {
1192     if (mode_changes[i].letter == c && mode_changes[i].dir == MODE_ADD)
1193     mode_changes[i].letter = 0;
1194     }
1195    
1196     mode_changes[mode_count].letter = c;
1197     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;
1201     mode_changes[mode_count].id = NULL;
1202     mode_changes[mode_count++].arg = chptr->mode.key;
1203     }
1204     else if (dir == MODE_DEL)
1205     {
1206     if (parc > *parn)
1207     (*parn)++;
1208    
1209     if (chptr->mode.key[0] == '\0')
1210     return;
1211    
1212     chptr->mode.key[0] = '\0';
1213    
1214     mode_changes[mode_count].letter = c;
1215     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;
1219     mode_changes[mode_count].id = NULL;
1220     mode_changes[mode_count++].arg = "*";
1221     }
1222     }
1223    
1224     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] =
1235     {
1236     {chm_nosuch, NULL},
1237     {chm_nosuch, NULL}, /* A */
1238     {chm_nosuch, NULL}, /* B */
1239     {chm_nosuch, NULL}, /* C */
1240     {chm_nosuch, NULL}, /* D */
1241     {chm_nosuch, NULL}, /* E */
1242     {chm_nosuch, NULL}, /* F */
1243     {chm_nosuch, NULL}, /* G */
1244     {chm_nosuch, NULL}, /* H */
1245     {chm_invex, NULL}, /* I */
1246     {chm_nosuch, NULL}, /* J */
1247     {chm_nosuch, NULL}, /* K */
1248     {chm_nosuch, NULL}, /* L */
1249     {chm_nosuch, NULL}, /* M */
1250     {chm_nosuch, NULL}, /* N */
1251     {chm_nosuch, NULL}, /* O */
1252     {chm_nosuch, NULL}, /* P */
1253     {chm_nosuch, NULL}, /* Q */
1254     {chm_nosuch, NULL}, /* R */
1255     {chm_nosuch, NULL}, /* S */
1256     {chm_nosuch, NULL}, /* T */
1257     {chm_nosuch, NULL}, /* U */
1258     {chm_nosuch, NULL}, /* V */
1259     {chm_nosuch, NULL}, /* W */
1260     {chm_nosuch, NULL}, /* X */
1261     {chm_nosuch, NULL}, /* Y */
1262     {chm_nosuch, NULL}, /* Z */
1263     {chm_nosuch, NULL},
1264     {chm_nosuch, NULL},
1265     {chm_nosuch, NULL},
1266     {chm_nosuch, NULL},
1267     {chm_nosuch, NULL},
1268     {chm_nosuch, NULL},
1269     {chm_nosuch, NULL}, /* a */
1270     {chm_ban, NULL}, /* b */
1271     {chm_nosuch, NULL}, /* c */
1272     {chm_nosuch, NULL}, /* d */
1273     {chm_except, NULL}, /* e */
1274     {chm_nosuch, NULL}, /* f */
1275     {chm_nosuch, NULL}, /* g */
1276     #ifdef HALFOPS
1277     {chm_hop, NULL}, /* h */
1278     #else
1279     {chm_nosuch, NULL}, /* h */
1280     #endif
1281     {chm_simple, (void *) MODE_INVITEONLY}, /* i */
1282     {chm_nosuch, NULL}, /* j */
1283     {chm_key, NULL}, /* k */
1284     {chm_limit, NULL}, /* l */
1285     {chm_simple, (void *) MODE_MODERATED}, /* m */
1286     {chm_simple, (void *) MODE_NOPRIVMSGS}, /* n */
1287     {chm_op, NULL}, /* o */
1288     {chm_simple, (void *) MODE_PRIVATE}, /* p */
1289     {chm_nosuch, NULL}, /* q */
1290     {chm_nosuch, NULL}, /* r */
1291     {chm_simple, (void *) MODE_SECRET}, /* s */
1292     {chm_simple, (void *) MODE_TOPICLIMIT}, /* t */
1293     {chm_nosuch, NULL}, /* u */
1294     {chm_voice, NULL}, /* v */
1295     {chm_nosuch, NULL}, /* w */
1296     {chm_nosuch, NULL}, /* x */
1297     {chm_nosuch, NULL}, /* y */
1298     {chm_nosuch, NULL}, /* z */
1299     };
1300     /* *INDENT-ON* */
1301    
1302     /* get_channel_access()
1303     *
1304     * inputs - pointer to Client struct
1305     * - pointer to Membership struct
1306     * output - CHACCESS_CHANOP if we should let them have
1307     * chanop level access, 0 for peon level access.
1308     * side effects - NONE
1309     */
1310     static int
1311     get_channel_access(struct Client *source_p, struct Membership *member)
1312     {
1313     /* Let hacked servers in for now... */
1314     if (!MyClient(source_p))
1315     return CHACCESS_CHANOP;
1316    
1317     if (member == NULL)
1318     return CHACCESS_NOTONCHAN;
1319    
1320     /* just to be sure.. */
1321     assert(source_p == member->client_p);
1322    
1323     if (has_member_flags(member, CHFL_CHANOP))
1324     return CHACCESS_CHANOP;
1325    
1326     #ifdef HALFOPS
1327     if (has_member_flags(member, CHFL_HALFOP))
1328     return CHACCESS_HALFOP;
1329     #endif
1330    
1331     return CHACCESS_PEON;
1332     }
1333    
1334     /* void send_cap_mode_changes(struct Client *client_p,
1335     * struct Client *source_p,
1336     * struct Channel *chptr, int cap, int nocap)
1337     * Input: The client sending(client_p), the source client(source_p),
1338     * the channel to send mode changes for(chptr)
1339     * Output: None.
1340     * 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_
1348     *
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
1352     */
1353     /* rewritten to ensure parabuf < MODEBUFLEN -db */
1354    
1355     static void
1356     send_cap_mode_changes(struct Client *client_p, struct Client *source_p,
1357     struct Channel *chptr, int cap, int nocap)
1358     {
1359     int i, mbl, pbl, arglen, nc, mc;
1360     int len;
1361     const char *arg = NULL;
1362     char *parptr;
1363     int dir = MODE_QUERY;
1364    
1365     mc = 0;
1366     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);
1378    
1379     /* loop the list of - modes we have */
1380     for (i = 0; i < mode_count; i++)
1381     {
1382     /* 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))
1389     continue;
1390    
1391     arg = "";
1392    
1393     if ((cap & CAP_TS6) && mode_changes[i].id)
1394     arg = mode_changes[i].id;
1395     if (*arg == '\0')
1396     arg = mode_changes[i].arg;
1397    
1398     /* 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)
1406     arglen = strlen(arg);
1407     else
1408     arglen = 0;
1409    
1410     if ((mc == MAXMODEPARAMS) ||
1411     ((arglen + mbl + pbl + 2) > IRCD_BUFSIZE) ||
1412     (pbl + arglen + BAN_FUDGE) >= MODEBUFLEN)
1413     {
1414     if (nc != 0)
1415     sendto_server(client_p, source_p, chptr, cap, nocap,
1416     LL_ICHAN | LL_ICLIENT, "%s %s",
1417     modebuf, parabuf);
1418     nc = 0;
1419     mc = 0;
1420    
1421     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);
1427    
1428     pbl = 0;
1429     parabuf[0] = '\0';
1430     parptr = parabuf;
1431     dir = MODE_QUERY;
1432     }
1433    
1434     if (dir != mode_changes[i].dir)
1435     {
1436     modebuf[mbl++] = (mode_changes[i].dir == MODE_ADD) ? '+' : '-';
1437     dir = mode_changes[i].dir;
1438     }
1439    
1440     modebuf[mbl++] = mode_changes[i].letter;
1441     modebuf[mbl] = '\0';
1442     nc++;
1443    
1444     if (arg != NULL)
1445     {
1446     len = ircsprintf(parptr, "%s ", arg);
1447     pbl += len;
1448     parptr += len;
1449     mc++;
1450     }
1451     }
1452    
1453     if (pbl && parabuf[pbl - 1] == ' ')
1454     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);
1459     }
1460    
1461     /* void send_mode_changes(struct Client *client_p,
1462     * struct Client *source_p,
1463     * struct Channel *chptr)
1464     * Input: The client sending(client_p), the source client(source_p),
1465     * the channel to send mode changes for(chptr),
1466     * mode change globals.
1467     * Output: None.
1468     * Side-effects: Sends the appropriate mode changes to other clients
1469     * and propagates to servers.
1470     */
1471     /* ensure parabuf < MODEBUFLEN -db */
1472     static void
1473     send_mode_changes(struct Client *client_p, struct Client *source_p,
1474     struct Channel *chptr, char *chname)
1475     {
1476     int i, mbl, pbl, arglen, nc, mc;
1477     int len;
1478     const char *arg = NULL;
1479     char *parptr;
1480     int dir = MODE_QUERY;
1481    
1482     /* 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++)
1502     {
1503     if (mode_changes[i].letter == 0 ||
1504     mode_changes[i].mems == NON_CHANOPS ||
1505     mode_changes[i].mems == ONLY_SERVERS)
1506     continue;
1507    
1508     arg = mode_changes[i].arg;
1509     if (arg != NULL)
1510     arglen = strlen(arg);
1511     else
1512     arglen = 0;
1513    
1514     if ((mc == MAXMODEPARAMS) ||
1515     ((arglen + mbl + pbl + 2) > IRCD_BUFSIZE) ||
1516     ((arglen + pbl + BAN_FUDGE) >= MODEBUFLEN))
1517     {
1518     if (mbl && modebuf[mbl - 1] == '-')
1519     modebuf[mbl - 1] = '\0';
1520    
1521     if (nc != 0)
1522     sendto_channel_local(ALL_MEMBERS, NO, chptr, "%s %s", modebuf, parabuf);
1523    
1524     nc = 0;
1525     mc = 0;
1526    
1527     if (IsServer(source_p))
1528     mbl = ircsprintf(modebuf, ":%s MODE %s ", me.name, chname);
1529     else
1530     mbl = ircsprintf(modebuf, ":%s!%s@%s MODE %s ", source_p->name,
1531     source_p->username, source_p->host, chname);
1532    
1533     pbl = 0;
1534     parabuf[0] = '\0';
1535     parptr = parabuf;
1536     dir = MODE_QUERY;
1537     }
1538    
1539     if (dir != mode_changes[i].dir)
1540     {
1541     modebuf[mbl++] = (mode_changes[i].dir == MODE_ADD) ? '+' : '-';
1542     dir = mode_changes[i].dir;
1543     }
1544    
1545     modebuf[mbl++] = mode_changes[i].letter;
1546     modebuf[mbl] = '\0';
1547     nc++;
1548    
1549     if (arg != NULL)
1550     {
1551     len = ircsprintf(parptr, "%s ", arg);
1552     pbl += len;
1553     parptr += len;
1554     mc++;
1555     }
1556     }
1557    
1558     if (pbl && parabuf[pbl - 1] == ' ')
1559     parabuf[pbl - 1] = 0;
1560    
1561     if (nc != 0)
1562     sendto_channel_local(ALL_MEMBERS, NO, chptr, "%s %s", modebuf, parabuf);
1563    
1564     nc = 0;
1565     mc = 0;
1566    
1567     /* Now send to servers... */
1568     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
1579     * from, the channel, the parameter count starting at the modes,
1580     * the parameters, the channel name.
1581     * Output: None.
1582     * Side-effects: Changes the channel membership and modes appropriately,
1583     * sends the appropriate MODE messages to the appropriate
1584     * clients.
1585     */
1586     void
1587     set_channel_mode(struct Client *client_p, struct Client *source_p, struct Channel *chptr,
1588     struct Membership *member, int parc, char *parv[], char *chname)
1589     {
1590     int dir = MODE_ADD;
1591     int parn = 1;
1592     int alevel, errors = 0;
1593     char *ml = parv[0], c;
1594     int table_position;
1595    
1596     mode_count = 0;
1597     mode_limit = 0;
1598     simple_modes_mask = 0;
1599    
1600     alevel = get_channel_access(source_p, member);
1601    
1602     for (; (c = *ml) != '\0'; ml++)
1603     {
1604     #if 0
1605     if(mode_count > 20)
1606     break;
1607     #endif
1608     switch (c)
1609     {
1610     case '+':
1611     dir = MODE_ADD;
1612     break;
1613     case '-':
1614     dir = MODE_DEL;
1615     break;
1616     case '=':
1617     dir = MODE_QUERY;
1618     break;
1619     default:
1620     if (c < 'A' || c > 'z')
1621     table_position = 0;
1622     else
1623     table_position = c - 'A' + 1;
1624     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);
1629     break;
1630     }
1631     }
1632    
1633     send_mode_changes(client_p, source_p, chptr, chname);
1634     }

Properties

Name Value
svn:eol-style native
svn:keywords Id Revision