ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/channel_mode.c
Revision: 388
Committed: Wed Feb 1 12:51:45 2006 UTC (19 years, 6 months ago) by michael
Content type: text/x-csrc
Original Path: ircd-hybrid-7.2/src/channel_mode.c
File size: 47861 byte(s)
Log Message:
- Forward-port banfix from 7.2 (reported by ThaPrince)

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 michael 371 #include "hostmask.h"
33 adx 30 #include "irc_string.h"
34     #include "sprintf_irc.h"
35     #include "ircd.h"
36     #include "list.h"
37     #include "numeric.h"
38     #include "s_serv.h" /* captab */
39     #include "s_user.h"
40     #include "send.h"
41     #include "whowas.h"
42     #include "s_conf.h" /* ConfigFileEntry, ConfigChannel */
43     #include "event.h"
44     #include "memory.h"
45     #include "balloc.h"
46     #include "s_log.h"
47 michael 388 #include "msg.h"
48 adx 30
49     /* some small utility functions */
50     static char *check_string(char *);
51     static char *fix_key(char *);
52     static char *fix_key_old(char *);
53     static void chm_nosuch(struct Client *, struct Client *,
54     struct Channel *, int, int *, char **, int *, int,
55     int, char, void *, const char *);
56     static void chm_simple(struct Client *, struct Client *, struct Channel *,
57     int, int *, char **, int *, int, int, char, void *,
58     const char *);
59     static void chm_limit(struct Client *, struct Client *, struct Channel *,
60     int, int *, char **, int *, int, int, char, void *,
61     const char *);
62     static void chm_key(struct Client *, struct Client *, struct Channel *,
63     int, int *, char **, int *, int, int, char, void *,
64     const char *);
65     static void chm_op(struct Client *, struct Client *, struct Channel *, int,
66     int *, char **, int *, int, int, char, void *,
67     const char *);
68     #ifdef HALFOPS
69     static void chm_hop(struct Client *, struct Client *, struct Channel *, int,
70     int *, char **, int *, int, int, char, void *,
71     const char *);
72     #endif
73     static void chm_voice(struct Client *, struct Client *, struct Channel *,
74     int, int *, char **, int *, int, int, char, void *,
75     const char *);
76     static void chm_ban(struct Client *, struct Client *, struct Channel *, int,
77     int *, char **, int *, int, int, char, void *,
78     const char *);
79     static void chm_except(struct Client *, struct Client *, struct Channel *,
80     int, int *, char **, int *, int, int, char, void *,
81     const char *);
82     static void chm_invex(struct Client *, struct Client *, struct Channel *,
83     int, int *, char **, int *, int, int, char, void *,
84     const char *);
85     static void send_cap_mode_changes(struct Client *, struct Client *,
86     struct Channel *, int, int);
87     static void send_mode_changes(struct Client *, struct Client *,
88     struct Channel *, char *);
89    
90     /* 10 is a magic number in hybrid 6 NFI where it comes from -db */
91     #define BAN_FUDGE 10
92     #define NCHCAPS (sizeof(channel_capabs)/sizeof(int))
93     #define NCHCAP_COMBOS (1 << NCHCAPS)
94    
95 michael 388 static char nuh_mask[MAXPARA][IRCD_BUFSIZE];
96 adx 30 /* some buffers for rebuilding channel/nick lists with ,'s */
97     static char modebuf[IRCD_BUFSIZE];
98     static char parabuf[MODEBUFLEN];
99     static struct ChModeChange mode_changes[IRCD_BUFSIZE];
100     static int mode_count;
101     static int mode_limit; /* number of modes set other than simple */
102     static int simple_modes_mask; /* bit mask of simple modes already set */
103 adx 356 #ifdef HALFOPS
104     static int channel_capabs[] = { CAP_EX, CAP_IE, CAP_TS6, CAP_HOPS };
105     #else
106 adx 30 static int channel_capabs[] = { CAP_EX, CAP_IE, CAP_TS6 };
107 adx 356 #endif
108 adx 30 static struct ChCapCombo chcap_combos[NCHCAP_COMBOS];
109     extern BlockHeap *ban_heap;
110    
111    
112     /* XXX check_string is propably not longer required in add_id and del_id */
113     /* check_string()
114     *
115     * inputs - string to check
116     * output - pointer to modified string
117     * side effects - Fixes a string so that the first white space found
118     * becomes an end of string marker (`\0`).
119     * returns the 'fixed' string or "*" if the string
120     * was NULL length or a NULL pointer.
121     */
122     static char *
123     check_string(char *s)
124     {
125     char *str = s;
126     static char star[] = "*";
127    
128     if (EmptyString(s))
129     return (star);
130    
131     for (; *s; ++s)
132     {
133     if (IsSpace(*s))
134     {
135     *s = '\0';
136     break;
137     }
138     }
139    
140     return (str);
141     }
142    
143     /*
144     * Ban functions to work with mode +b/e/d/I
145     */
146     /* add the specified ID to the channel..
147     * -is 8/9/00
148     */
149    
150     int
151     add_id(struct Client *client_p, struct Channel *chptr, char *banid, int type)
152     {
153     dlink_list *list;
154     dlink_node *ban;
155     size_t len = 0;
156     struct Ban *actualBan;
157     unsigned int num_mask;
158     char *name = NULL, *user = NULL, *host = NULL;
159    
160     /* dont let local clients overflow the b/e/I lists */
161     if (MyClient(client_p))
162     {
163     num_mask = dlink_list_length(&chptr->banlist) +
164     dlink_list_length(&chptr->exceptlist) +
165     dlink_list_length(&chptr->invexlist);
166    
167     if (num_mask >= ConfigChannel.max_bans)
168     {
169     sendto_one(client_p, form_str(ERR_BANLISTFULL),
170     me.name, client_p->name, chptr->chname, banid);
171     return 0;
172     }
173    
174     collapse(banid);
175     }
176    
177     split_nuh(check_string(banid), &name, &user, &host);
178    
179     /*
180     * Assemble a n!u@h and print it back to banid for sending
181     * the mode to the channel.
182     */
183     len = ircsprintf(banid, "%s!%s@%s", name, user, host);
184    
185     switch (type)
186     {
187     case CHFL_BAN:
188     list = &chptr->banlist;
189     clear_ban_cache(chptr);
190     break;
191     case CHFL_EXCEPTION:
192     list = &chptr->exceptlist;
193     clear_ban_cache(chptr);
194     break;
195     case CHFL_INVEX:
196     list = &chptr->invexlist;
197     break;
198     default:
199     assert(0);
200     return 0;
201     }
202    
203     DLINK_FOREACH(ban, list->head)
204     {
205     actualBan = ban->data;
206     if (!irccmp(actualBan->name, name) &&
207     !irccmp(actualBan->username, user) &&
208     !irccmp(actualBan->host, host))
209     {
210     MyFree(name);
211     MyFree(user);
212     MyFree(host);
213     return 0;
214     }
215     }
216    
217     actualBan = BlockHeapAlloc(ban_heap);
218     actualBan->when = CurrentTime;
219     actualBan->name = name;
220     actualBan->username = user;
221     actualBan->host = host;
222     actualBan->len = len-2; /* -2 for @ and ! */
223 michael 371 actualBan->type = parse_netmask(host, &actualBan->addr, &actualBan->bits);
224 adx 30
225     if (IsClient(client_p))
226     {
227     actualBan->who =
228     MyMalloc(strlen(client_p->name) +
229     strlen(client_p->username) +
230     strlen(client_p->host) + 3);
231     ircsprintf(actualBan->who, "%s!%s@%s",
232     client_p->name, client_p->username, client_p->host);
233     }
234     else
235     DupString(actualBan->who, client_p->name);
236    
237     dlinkAdd(actualBan, &actualBan->node, list);
238    
239     return 1;
240     }
241    
242     /*
243     * inputs - pointer to channel
244     * - pointer to ban id
245     * - type of ban, i.e. ban, exception, invex
246     * output - 0 for failure, 1 for success
247     * side effects -
248     */
249     static int
250     del_id(struct Channel *chptr, char *banid, int type)
251     {
252     dlink_list *list;
253     dlink_node *ban;
254     struct Ban *banptr;
255     char *name = NULL, *user = NULL, *host = NULL;
256    
257     if (banid == NULL)
258     return 0;
259    
260     split_nuh(check_string(banid), &name, &user, &host);
261    
262     /*
263     * Assemble a n!u@h and print it back to banid for sending
264     * the mode to the channel.
265     */
266     ircsprintf(banid, "%s!%s@%s", name, user, host);
267    
268     switch (type)
269     {
270     case CHFL_BAN:
271     list = &chptr->banlist;
272     clear_ban_cache(chptr);
273     break;
274     case CHFL_EXCEPTION:
275     list = &chptr->exceptlist;
276     clear_ban_cache(chptr);
277     break;
278     case CHFL_INVEX:
279     list = &chptr->invexlist;
280     break;
281     default:
282     sendto_realops_flags(UMODE_ALL, L_ALL,
283     "del_id() called with unknown ban type %d!", type);
284     MyFree(name);
285     MyFree(user);
286     MyFree(host);
287     return(0);
288     }
289    
290     DLINK_FOREACH(ban, list->head)
291     {
292     banptr = ban->data;
293    
294     if (!irccmp(name, banptr->name) &&
295     !irccmp(user, banptr->username) &&
296     !irccmp(host, banptr->host))
297     {
298     remove_ban(banptr, list);
299     MyFree(name);
300     MyFree(user);
301     MyFree(host);
302     return 1;
303     }
304     }
305    
306     MyFree(name);
307     MyFree(user);
308     MyFree(host);
309     return 0;
310     }
311    
312     static const struct mode_letter
313     {
314     const unsigned int mode;
315     const unsigned char letter;
316     } flags[] = {
317     { MODE_INVITEONLY, 'i' },
318     { MODE_MODERATED, 'm' },
319     { MODE_NOPRIVMSGS, 'n' },
320     { MODE_PRIVATE, 'p' },
321     { MODE_SECRET, 's' },
322     { MODE_TOPICLIMIT, 't' },
323     { 0, '\0' }
324     };
325    
326     /* channel_modes()
327     *
328     * inputs - pointer to channel
329     * - pointer to client
330     * - pointer to mode buf
331     * - pointer to parameter buf
332     * output - NONE
333     * side effects - write the "simple" list of channel modes for channel
334     * chptr onto buffer mbuf with the parameters in pbuf.
335     */
336     void
337     channel_modes(struct Channel *chptr, struct Client *client_p,
338     char *mbuf, char *pbuf)
339     {
340     int i;
341    
342     *mbuf++ = '+';
343     *pbuf = '\0';
344    
345     for (i = 0; flags[i].mode; ++i)
346     if (chptr->mode.mode & flags[i].mode)
347     *mbuf++ = flags[i].letter;
348    
349     if (chptr->mode.limit)
350     {
351     *mbuf++ = 'l';
352    
353     if (IsMember(client_p, chptr) || IsServer(client_p))
354     pbuf += ircsprintf(pbuf, "%d ", chptr->mode.limit);
355     }
356    
357     if (chptr->mode.key[0])
358     {
359     *mbuf++ = 'k';
360    
361     if (*pbuf || IsMember(client_p, chptr) || IsServer(client_p))
362     ircsprintf(pbuf, "%s ", chptr->mode.key);
363     }
364    
365     *mbuf = '\0';
366     }
367    
368     /* fix_key()
369     *
370     * inputs - pointer to key to clean up
371     * output - pointer to cleaned up key
372     * side effects - input string is modified
373     *
374     * stolen from Undernet's ircd -orabidoo
375     */
376     static char *
377     fix_key(char *arg)
378     {
379     unsigned char *s, *t, c;
380    
381     for (s = t = (unsigned char *)arg; (c = *s); s++)
382     {
383     c &= 0x7f;
384     if (c != ':' && c > ' ' && c != ',')
385     *t++ = c;
386     }
387    
388     *t = '\0';
389     return(arg);
390     }
391    
392     /* fix_key_old()
393     *
394     * inputs - pointer to key to clean up
395     * output - pointer to cleaned up key
396     * side effects - input string is modifed
397     *
398     * Here we attempt to be compatible with older non-hybrid servers.
399     * We can't back down from the ':' issue however. --Rodder
400     */
401     static char *
402     fix_key_old(char *arg)
403     {
404     unsigned char *s, *t, c;
405    
406     for (s = t = (unsigned char *)arg; (c = *s); s++)
407     {
408     c &= 0x7f;
409     if ((c != 0x0a) && (c != ':') && (c != 0x0d) && (c != ','))
410     *t++ = c;
411     }
412    
413     *t = '\0';
414     return(arg);
415     }
416    
417     /* bitmasks for various error returns that set_channel_mode should only return
418     * once per call -orabidoo
419     */
420    
421     #define SM_ERR_NOTS 0x00000001 /* No TS on channel */
422     #define SM_ERR_NOOPS 0x00000002 /* No chan ops */
423     #define SM_ERR_UNKNOWN 0x00000004
424     #define SM_ERR_RPL_B 0x00000008
425     #define SM_ERR_RPL_E 0x00000010
426     #define SM_ERR_NOTONCHANNEL 0x00000020 /* Not on channel */
427     #define SM_ERR_RPL_I 0x00000040
428    
429     /* Now lets do some stuff to keep track of what combinations of
430     * servers exist...
431     * Note that the number of combinations doubles each time you add
432     * something to this list. Each one is only quick if no servers use that
433     * combination, but if the numbers get too high here MODE will get too
434     * slow. I suggest if you get more than 7 here, you consider getting rid
435     * of some and merging or something. If it wasn't for irc+cs we would
436     * probably not even need to bother about most of these, but unfortunately
437     * we do. -A1kmm
438     */
439    
440     /* void init_chcap_usage_counts(void)
441     *
442     * Inputs - none
443     * Output - none
444     * Side-effects - Initialises the usage counts to zero. Fills in the
445     * chcap_yes and chcap_no combination tables.
446     */
447     void
448     init_chcap_usage_counts(void)
449     {
450     unsigned long m, c, y, n;
451    
452     memset(chcap_combos, 0, sizeof(chcap_combos));
453    
454     /* For every possible combination */
455     for (m = 0; m < NCHCAP_COMBOS; m++)
456     {
457     /* Check each capab */
458     for (c = y = n = 0; c < NCHCAPS; c++)
459     {
460     if ((m & (1 << c)) == 0)
461     n |= channel_capabs[c];
462     else
463     y |= channel_capabs[c];
464     }
465     chcap_combos[m].cap_yes = y;
466     chcap_combos[m].cap_no = n;
467     }
468     }
469    
470     /* void set_chcap_usage_counts(struct Client *serv_p)
471     * Input: serv_p; The client whose capabs to register.
472     * Output: none
473     * Side-effects: Increments the usage counts for the correct capab
474     * combination.
475     */
476     void
477     set_chcap_usage_counts(struct Client *serv_p)
478     {
479     int n;
480    
481     for (n = 0; n < NCHCAP_COMBOS; n++)
482     {
483     if (((serv_p->localClient->caps & chcap_combos[n].cap_yes) ==
484     chcap_combos[n].cap_yes) &&
485     ((serv_p->localClient->caps & chcap_combos[n].cap_no) == 0))
486     {
487     chcap_combos[n].count++;
488     return;
489     }
490     }
491    
492     /* This should be impossible -A1kmm. */
493     assert(0);
494     }
495    
496     /* void set_chcap_usage_counts(struct Client *serv_p)
497     *
498     * Inputs - serv_p; The client whose capabs to register.
499     * Output - none
500     * Side-effects - Decrements the usage counts for the correct capab
501     * combination.
502     */
503     void
504     unset_chcap_usage_counts(struct Client *serv_p)
505     {
506     int n;
507    
508     for (n = 0; n < NCHCAP_COMBOS; n++)
509     {
510     if ((serv_p->localClient->caps & chcap_combos[n].cap_yes) ==
511     chcap_combos[n].cap_yes &&
512     (serv_p->localClient->caps & chcap_combos[n].cap_no) == 0)
513     {
514     /* Hopefully capabs can't change dynamically or anything... */
515     assert(chcap_combos[n].count > 0);
516     chcap_combos[n].count--;
517     return;
518     }
519     }
520    
521     /* This should be impossible -A1kmm. */
522     assert(0);
523     }
524    
525     /* Mode functions handle mode changes for a particular mode... */
526     static void
527     chm_nosuch(struct Client *client_p, struct Client *source_p,
528     struct Channel *chptr, int parc, int *parn,
529     char **parv, int *errors, int alev, int dir, char c, void *d,
530     const char *chname)
531     {
532     if (*errors & SM_ERR_UNKNOWN)
533     return;
534    
535     *errors |= SM_ERR_UNKNOWN;
536     sendto_one(source_p, form_str(ERR_UNKNOWNMODE), me.name,
537     source_p->name, c);
538     }
539    
540     static void
541     chm_simple(struct Client *client_p, struct Client *source_p, struct Channel *chptr,
542     int parc, int *parn, char **parv, int *errors, int alev, int dir,
543     char c, void *d, const char *chname)
544     {
545     long mode_type;
546    
547     mode_type = (long)d;
548    
549     if ((alev < CHACCESS_HALFOP) ||
550     ((mode_type == MODE_PRIVATE) && (alev < CHACCESS_CHANOP)))
551     {
552     if (!(*errors & SM_ERR_NOOPS))
553     sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ?
554     ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED),
555     me.name, source_p->name, chname);
556     *errors |= SM_ERR_NOOPS;
557     return;
558     }
559    
560     /* If have already dealt with this simple mode, ignore it */
561     if (simple_modes_mask & mode_type)
562     return;
563    
564     simple_modes_mask |= mode_type;
565    
566     /* setting + */
567     /* Apparently, (though no one has ever told the hybrid group directly)
568     * admins don't like redundant mode checking. ok. It would have been nice
569     * if you had have told us directly. I've left the original code snippets
570     * in place.
571     *
572     * -Dianora
573     */
574     if ((dir == MODE_ADD)) /* && !(chptr->mode.mode & mode_type)) */
575     {
576     chptr->mode.mode |= mode_type;
577    
578     mode_changes[mode_count].letter = c;
579     mode_changes[mode_count].dir = MODE_ADD;
580     mode_changes[mode_count].caps = 0;
581     mode_changes[mode_count].nocaps = 0;
582     mode_changes[mode_count].id = NULL;
583     mode_changes[mode_count].mems = ALL_MEMBERS;
584     mode_changes[mode_count++].arg = NULL;
585     }
586     else if ((dir == MODE_DEL)) /* && (chptr->mode.mode & mode_type)) */
587     {
588     /* setting - */
589    
590     chptr->mode.mode &= ~mode_type;
591    
592     mode_changes[mode_count].letter = c;
593     mode_changes[mode_count].dir = MODE_DEL;
594     mode_changes[mode_count].caps = 0;
595     mode_changes[mode_count].nocaps = 0;
596     mode_changes[mode_count].mems = ALL_MEMBERS;
597     mode_changes[mode_count].id = NULL;
598     mode_changes[mode_count++].arg = NULL;
599     }
600     }
601    
602     static void
603     chm_ban(struct Client *client_p, struct Client *source_p,
604     struct Channel *chptr, int parc, int *parn,
605     char **parv, int *errors, int alev, int dir, char c, void *d,
606     const char *chname)
607     {
608     char *mask = NULL;
609    
610     if (dir == MODE_QUERY || parc <= *parn)
611     {
612     dlink_node *ptr = NULL;
613    
614     if (*errors & SM_ERR_RPL_B)
615     return;
616    
617     *errors |= SM_ERR_RPL_B;
618    
619     DLINK_FOREACH(ptr, chptr->banlist.head)
620     {
621     const struct Ban *banptr = ptr->data;
622     sendto_one(client_p, form_str(RPL_BANLIST),
623     me.name, client_p->name, chname,
624     banptr->name, banptr->username, banptr->host,
625     banptr->who, banptr->when);
626     }
627    
628     sendto_one(source_p, form_str(RPL_ENDOFBANLIST), me.name,
629     source_p->name, chname);
630     return;
631     }
632    
633     if (alev < CHACCESS_HALFOP)
634     {
635     if (!(*errors & SM_ERR_NOOPS))
636     sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ?
637     ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED),
638     me.name, source_p->name, chname);
639     *errors |= SM_ERR_NOOPS;
640     return;
641     }
642    
643     if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
644     return;
645    
646 michael 388 mask = nuh_mask[*parn];
647     memcpy(mask, parv[*parn], sizeof(nuh_mask[*parn]));
648     ++*parn;
649    
650 adx 30 if (IsServer(client_p))
651     if (strchr(mask, ' '))
652     return;
653    
654     switch (dir)
655     {
656     case MODE_ADD:
657     if (!add_id(source_p, chptr, mask, CHFL_BAN))
658     return;
659     break;
660     case MODE_DEL:
661     /* XXX grrrrrrr */
662     #ifdef NO_BAN_COOKIE
663     if (!del_id(chptr, mask, CHFL_BAN))
664     return;
665     #else
666     /* XXX this hack allows /mode * +o-b nick ban.cookie
667     * I'd like to see this hack go away in the future.
668     */
669     del_id(chptr, mask, CHFL_BAN);
670     #endif
671     break;
672     default:
673     assert(0);
674     }
675    
676     mode_changes[mode_count].letter = c;
677     mode_changes[mode_count].dir = dir;
678     mode_changes[mode_count].caps = 0;
679     mode_changes[mode_count].nocaps = 0;
680     mode_changes[mode_count].mems = ALL_MEMBERS;
681     mode_changes[mode_count].id = NULL;
682     mode_changes[mode_count++].arg = mask;
683     }
684    
685     static void
686     chm_except(struct Client *client_p, struct Client *source_p,
687     struct Channel *chptr, int parc, int *parn,
688     char **parv, int *errors, int alev, int dir, char c, void *d,
689     const char *chname)
690     {
691     char *mask = NULL;
692    
693     /* if we have +e disabled, allow local clients to do anything but
694     * set the mode. This prevents the abuse of +e when just a few
695     * servers support it. --fl
696     */
697     if (!ConfigChannel.use_except && MyClient(source_p) &&
698     ((dir == MODE_ADD) && (parc > *parn)))
699     {
700     if (*errors & SM_ERR_RPL_E)
701     return;
702    
703     *errors |= SM_ERR_RPL_E;
704     return;
705     }
706    
707     if (alev < CHACCESS_HALFOP)
708     {
709     if (!(*errors & SM_ERR_NOOPS))
710     sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ?
711     ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED),
712     me.name, source_p->name, chname);
713     *errors |= SM_ERR_NOOPS;
714     return;
715     }
716    
717     if (dir == MODE_QUERY || parc <= *parn)
718     {
719     dlink_node *ptr = NULL;
720    
721     if (*errors & SM_ERR_RPL_E)
722     return;
723    
724     *errors |= SM_ERR_RPL_E;
725    
726     DLINK_FOREACH(ptr, chptr->exceptlist.head)
727     {
728     const struct Ban *banptr = ptr->data;
729     sendto_one(client_p, form_str(RPL_EXCEPTLIST),
730     me.name, client_p->name, chname,
731     banptr->name, banptr->username, banptr->host,
732     banptr->who, banptr->when);
733     }
734    
735     sendto_one(source_p, form_str(RPL_ENDOFEXCEPTLIST), me.name,
736     source_p->name, chname);
737     return;
738     }
739    
740     if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
741     return;
742    
743 michael 388 mask = nuh_mask[*parn];
744     memcpy(mask, parv[*parn], sizeof(nuh_mask[*parn]));
745     ++*parn;
746 adx 30
747     if (IsServer(client_p))
748     if (strchr(mask, ' '))
749     return;
750    
751     switch (dir)
752     {
753     case MODE_ADD:
754     if (!add_id(source_p, chptr, mask, CHFL_EXCEPTION))
755     return;
756     break;
757     case MODE_DEL:
758     if (!del_id(chptr, mask, CHFL_EXCEPTION))
759     return;
760     break;
761     default:
762     assert(0);
763     }
764    
765     mode_changes[mode_count].letter = c;
766     mode_changes[mode_count].dir = dir;
767     mode_changes[mode_count].caps = CAP_EX;
768     mode_changes[mode_count].nocaps = 0;
769    
770     if (ConfigChannel.use_except)
771     mode_changes[mode_count].mems = ONLY_CHANOPS;
772     else
773     mode_changes[mode_count].mems = ONLY_SERVERS;
774    
775     mode_changes[mode_count].id = NULL;
776     mode_changes[mode_count++].arg = mask;
777     }
778    
779     static void
780     chm_invex(struct Client *client_p, struct Client *source_p,
781     struct Channel *chptr, int parc, int *parn,
782     char **parv, int *errors, int alev, int dir, char c, void *d,
783     const char *chname)
784     {
785     char *mask = NULL;
786    
787     /* if we have +I disabled, allow local clients to do anything but
788     * set the mode. This prevents the abuse of +I when just a few
789     * servers support it --fl
790     */
791     if (!ConfigChannel.use_invex && MyClient(source_p) &&
792     (dir == MODE_ADD) && (parc > *parn))
793     {
794     if (*errors & SM_ERR_RPL_I)
795     return;
796    
797     *errors |= SM_ERR_RPL_I;
798     return;
799     }
800    
801     if (alev < CHACCESS_HALFOP)
802     {
803     if (!(*errors & SM_ERR_NOOPS))
804     sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ?
805     ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED),
806     me.name, source_p->name, chname);
807     *errors |= SM_ERR_NOOPS;
808     return;
809     }
810    
811     if (dir == MODE_QUERY || parc <= *parn)
812     {
813     dlink_node *ptr = NULL;
814    
815     if (*errors & SM_ERR_RPL_I)
816     return;
817    
818     *errors |= SM_ERR_RPL_I;
819    
820     DLINK_FOREACH(ptr, chptr->invexlist.head)
821     {
822     const struct Ban *banptr = ptr->data;
823     sendto_one(client_p, form_str(RPL_INVITELIST), me.name,
824     client_p->name, chname,
825     banptr->name, banptr->username, banptr->host,
826     banptr->who, banptr->when);
827     }
828    
829     sendto_one(source_p, form_str(RPL_ENDOFINVITELIST), me.name,
830     source_p->name, chname);
831     return;
832     }
833    
834     if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
835     return;
836    
837 michael 388 mask = nuh_mask[*parn];
838     memcpy(mask, parv[*parn], sizeof(nuh_mask[*parn]));
839     ++*parn;
840 adx 30
841     if (IsServer(client_p))
842     if (strchr(mask, ' '))
843     return;
844    
845     switch (dir)
846     {
847     case MODE_ADD:
848     if (!add_id(source_p, chptr, mask, CHFL_INVEX))
849     return;
850     break;
851     case MODE_DEL:
852     if (!del_id(chptr, mask, CHFL_INVEX))
853     return;
854     break;
855     default:
856     assert(0);
857     }
858    
859     mode_changes[mode_count].letter = c;
860     mode_changes[mode_count].dir = dir;
861     mode_changes[mode_count].caps = CAP_IE;
862     mode_changes[mode_count].nocaps = 0;
863    
864     if (ConfigChannel.use_invex)
865     mode_changes[mode_count].mems = ONLY_CHANOPS;
866     else
867     mode_changes[mode_count].mems = ONLY_SERVERS;
868    
869     mode_changes[mode_count].id = NULL;
870     mode_changes[mode_count++].arg = mask;
871     }
872    
873     /*
874     * inputs - pointer to channel
875     * output - none
876     * side effects - clear ban cache
877     */
878     void
879     clear_ban_cache(struct Channel *chptr)
880     {
881     dlink_node *ptr = NULL;
882    
883     DLINK_FOREACH(ptr, chptr->locmembers.head)
884     {
885     struct Membership *ms = ptr->data;
886     ms->flags &= ~(CHFL_BAN_SILENCED|CHFL_BAN_CHECKED);
887     }
888     }
889    
890     static void
891     chm_op(struct Client *client_p, struct Client *source_p,
892     struct Channel *chptr, int parc, int *parn,
893     char **parv, int *errors, int alev, int dir, char c, void *d,
894     const char *chname)
895     {
896     char *opnick;
897     struct Client *targ_p;
898     struct Membership *member;
899 adx 356 int caps = 0;
900 adx 30
901     if (alev < CHACCESS_CHANOP)
902     {
903     if (!(*errors & SM_ERR_NOOPS))
904     sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ?
905     ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED),
906     me.name, source_p->name, chname);
907     *errors |= SM_ERR_NOOPS;
908     return;
909     }
910    
911     if ((dir == MODE_QUERY) || (parc <= *parn))
912     return;
913    
914     opnick = parv[(*parn)++];
915    
916     if ((targ_p = find_chasing(client_p, source_p, opnick, NULL)) == NULL)
917     return;
918     if (!IsClient(targ_p))
919     return;
920    
921     if ((member = find_channel_link(targ_p, chptr)) == NULL)
922     {
923     if (!(*errors & SM_ERR_NOTONCHANNEL))
924     sendto_one(source_p, form_str(ERR_USERNOTINCHANNEL),
925     me.name, source_p->name, opnick, chname);
926     *errors |= SM_ERR_NOTONCHANNEL;
927     return;
928     }
929    
930     if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
931     return;
932    
933     /* no redundant mode changes */
934     if (dir == MODE_ADD && has_member_flags(member, CHFL_CHANOP))
935     return;
936     if (dir == MODE_DEL && !has_member_flags(member, CHFL_CHANOP))
937 adx 356 {
938     #ifdef HALFOPS
939     if (has_member_flags(member, CHFL_HALFOP))
940     chm_hop(client_p, source_p, chptr, parc, parn, parv, errors, alev,
941     dir, c, d, chname);
942     #endif
943 adx 30 return;
944 adx 356 }
945 adx 30
946 adx 356 #ifdef HALFOPS
947     if (dir == MODE_ADD && has_member_flags(member, CHFL_HALFOP))
948     {
949     /* promoting from % to @ is visible only to CAP_HOPS servers */
950     mode_changes[mode_count].letter = 'h';
951     mode_changes[mode_count].dir = MODE_DEL;
952     mode_changes[mode_count].caps = caps = CAP_HOPS;
953     mode_changes[mode_count].nocaps = 0;
954     mode_changes[mode_count].mems = ALL_MEMBERS;
955     mode_changes[mode_count].id = NULL;
956     mode_changes[mode_count].arg = targ_p->name;
957     mode_changes[mode_count++].client = targ_p;
958     }
959     #endif
960    
961 adx 30 mode_changes[mode_count].letter = 'o';
962     mode_changes[mode_count].dir = dir;
963 adx 356 mode_changes[mode_count].caps = caps;
964 adx 30 mode_changes[mode_count].nocaps = 0;
965     mode_changes[mode_count].mems = ALL_MEMBERS;
966     mode_changes[mode_count].id = targ_p->id;
967     mode_changes[mode_count].arg = targ_p->name;
968     mode_changes[mode_count++].client = targ_p;
969    
970     if (dir == MODE_ADD)
971     {
972     AddMemberFlag(member, CHFL_CHANOP);
973 adx 356 DelMemberFlag(member, CHFL_DEOPPED | CHFL_HALFOP);
974 adx 30 }
975     else
976     DelMemberFlag(member, CHFL_CHANOP);
977     }
978    
979     #ifdef HALFOPS
980     static void
981     chm_hop(struct Client *client_p, struct Client *source_p,
982     struct Channel *chptr, int parc, int *parn,
983     char **parv, int *errors, int alev, int dir, char c, void *d,
984     const char *chname)
985     {
986     char *opnick;
987     struct Client *targ_p;
988     struct Membership *member;
989    
990     /* *sigh* - dont allow halfops to set +/-h, they could fully control a
991     * channel if there were no ops - it doesnt solve anything.. MODE_PRIVATE
992     * when used with MODE_SECRET is paranoid - cant use +p
993     *
994     * it needs to be optional per channel - but not via +p, that or remove
995     * paranoid.. -- fl_
996     *
997     * +p means paranoid, it is useless for anything else on modern IRC, as
998     * list isn't really usable. If you want to have a private channel these
999     * days, you set it +s. Halfops can no longer remove simple modes when
1000     * +p is set (although they can set +p) so it is safe to use this to
1001     * control whether they can (de)halfop...
1002     */
1003     if (alev <
1004     ((chptr->mode.mode & MODE_PRIVATE) ? CHACCESS_CHANOP : CHACCESS_HALFOP))
1005     {
1006     if (!(*errors & SM_ERR_NOOPS))
1007     sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ?
1008     ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED),
1009     me.name, source_p->name, chname);
1010     *errors |= SM_ERR_NOOPS;
1011     return;
1012     }
1013    
1014     if ((dir == MODE_QUERY) || (parc <= *parn))
1015     return;
1016    
1017     opnick = parv[(*parn)++];
1018    
1019     if ((targ_p = find_chasing(client_p, source_p, opnick, NULL)) == NULL)
1020     return;
1021     if (!IsClient(targ_p))
1022     return;
1023    
1024     if ((member = find_channel_link(targ_p, chptr)) == NULL)
1025     {
1026     if (!(*errors & SM_ERR_NOTONCHANNEL))
1027     sendto_one(source_p, form_str(ERR_USERNOTINCHANNEL),
1028     me.name, source_p->name, opnick, chname);
1029     *errors |= SM_ERR_NOTONCHANNEL;
1030     return;
1031     }
1032    
1033     if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
1034     return;
1035    
1036     /* no redundant mode changes */
1037 adx 356 if (dir == MODE_ADD && has_member_flags(member, CHFL_HALFOP | CHFL_CHANOP))
1038 adx 30 return;
1039     if (dir == MODE_DEL && !has_member_flags(member, CHFL_HALFOP))
1040     return;
1041    
1042     mode_changes[mode_count].letter = 'h';
1043     mode_changes[mode_count].dir = dir;
1044 adx 356 mode_changes[mode_count].caps = CAP_HOPS;
1045 adx 30 mode_changes[mode_count].nocaps = 0;
1046     mode_changes[mode_count].mems = ALL_MEMBERS;
1047     mode_changes[mode_count].id = targ_p->id;
1048     mode_changes[mode_count].arg = targ_p->name;
1049     mode_changes[mode_count++].client = targ_p;
1050    
1051 adx 356 mode_changes[mode_count].letter = 'o';
1052     mode_changes[mode_count].dir = dir;
1053     mode_changes[mode_count].caps = 0;
1054     mode_changes[mode_count].nocaps = CAP_HOPS;
1055     mode_changes[mode_count].mems = ONLY_SERVERS;
1056     mode_changes[mode_count].id = targ_p->id;
1057     mode_changes[mode_count].arg = targ_p->name;
1058     mode_changes[mode_count++].client = targ_p;
1059    
1060 adx 30 if (dir == MODE_ADD)
1061     {
1062     AddMemberFlag(member, CHFL_HALFOP);
1063     DelMemberFlag(member, CHFL_DEOPPED);
1064     }
1065     else
1066     DelMemberFlag(member, CHFL_HALFOP);
1067     }
1068     #endif
1069    
1070     static void
1071     chm_voice(struct Client *client_p, struct Client *source_p,
1072     struct Channel *chptr, int parc, int *parn,
1073     char **parv, int *errors, int alev, int dir, char c, void *d,
1074     const char *chname)
1075     {
1076     char *opnick;
1077     struct Client *targ_p;
1078     struct Membership *member;
1079    
1080     if (alev < CHACCESS_HALFOP)
1081     {
1082     if (!(*errors & SM_ERR_NOOPS))
1083     sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ?
1084     ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED),
1085     me.name, source_p->name, chname);
1086     *errors |= SM_ERR_NOOPS;
1087     return;
1088     }
1089    
1090     if ((dir == MODE_QUERY) || parc <= *parn)
1091     return;
1092    
1093     opnick = parv[(*parn)++];
1094    
1095     if ((targ_p = find_chasing(client_p, source_p, opnick, NULL)) == NULL)
1096     return;
1097     if (!IsClient(targ_p))
1098     return;
1099    
1100     if ((member = find_channel_link(targ_p, chptr)) == NULL)
1101     {
1102     if (!(*errors & SM_ERR_NOTONCHANNEL))
1103     sendto_one(source_p, form_str(ERR_USERNOTINCHANNEL),
1104     me.name, source_p->name, opnick, chname);
1105     *errors |= SM_ERR_NOTONCHANNEL;
1106     return;
1107     }
1108    
1109     if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
1110     return;
1111    
1112     /* no redundant mode changes */
1113     if (dir == MODE_ADD && has_member_flags(member, CHFL_VOICE))
1114     return;
1115     if (dir == MODE_DEL && !has_member_flags(member, CHFL_VOICE))
1116     return;
1117    
1118     mode_changes[mode_count].letter = 'v';
1119     mode_changes[mode_count].dir = dir;
1120     mode_changes[mode_count].caps = 0;
1121     mode_changes[mode_count].nocaps = 0;
1122     mode_changes[mode_count].mems = ALL_MEMBERS;
1123     mode_changes[mode_count].id = targ_p->id;
1124     mode_changes[mode_count].arg = targ_p->name;
1125     mode_changes[mode_count++].client = targ_p;
1126    
1127     if (dir == MODE_ADD)
1128     AddMemberFlag(member, CHFL_VOICE);
1129     else
1130     DelMemberFlag(member, CHFL_VOICE);
1131     }
1132    
1133     static void
1134     chm_limit(struct Client *client_p, struct Client *source_p,
1135     struct Channel *chptr, int parc, int *parn,
1136     char **parv, int *errors, int alev, int dir, char c, void *d,
1137     const char *chname)
1138     {
1139     int i, limit;
1140     char *lstr;
1141    
1142     if (alev < CHACCESS_HALFOP)
1143     {
1144     if (!(*errors & SM_ERR_NOOPS))
1145     sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ?
1146     ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED),
1147     me.name, source_p->name, chname);
1148     *errors |= SM_ERR_NOOPS;
1149     return;
1150     }
1151    
1152     if (dir == MODE_QUERY)
1153     return;
1154    
1155     if ((dir == MODE_ADD) && parc > *parn)
1156     {
1157     lstr = parv[(*parn)++];
1158    
1159     if ((limit = atoi(lstr)) <= 0)
1160     return;
1161    
1162     ircsprintf(lstr, "%d", limit);
1163    
1164     /* if somebody sets MODE #channel +ll 1 2, accept latter --fl */
1165     for (i = 0; i < mode_count; i++)
1166     {
1167     if (mode_changes[i].letter == c && mode_changes[i].dir == MODE_ADD)
1168     mode_changes[i].letter = 0;
1169     }
1170    
1171     mode_changes[mode_count].letter = c;
1172     mode_changes[mode_count].dir = MODE_ADD;
1173     mode_changes[mode_count].caps = 0;
1174     mode_changes[mode_count].nocaps = 0;
1175     mode_changes[mode_count].mems = ALL_MEMBERS;
1176     mode_changes[mode_count].id = NULL;
1177     mode_changes[mode_count++].arg = lstr;
1178    
1179     chptr->mode.limit = limit;
1180     }
1181     else if (dir == MODE_DEL)
1182     {
1183     if (!chptr->mode.limit)
1184     return;
1185    
1186     chptr->mode.limit = 0;
1187    
1188     mode_changes[mode_count].letter = c;
1189     mode_changes[mode_count].dir = MODE_DEL;
1190     mode_changes[mode_count].caps = 0;
1191     mode_changes[mode_count].nocaps = 0;
1192     mode_changes[mode_count].mems = ALL_MEMBERS;
1193     mode_changes[mode_count].id = NULL;
1194     mode_changes[mode_count++].arg = NULL;
1195     }
1196     }
1197    
1198     static void
1199     chm_key(struct Client *client_p, struct Client *source_p,
1200     struct Channel *chptr, int parc, int *parn,
1201     char **parv, int *errors, int alev, int dir, char c, void *d,
1202     const char *chname)
1203     {
1204     int i;
1205     char *key;
1206    
1207     if (alev < CHACCESS_HALFOP)
1208     {
1209     if (!(*errors & SM_ERR_NOOPS))
1210     sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ?
1211     ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED),
1212     me.name, source_p->name, chname);
1213     *errors |= SM_ERR_NOOPS;
1214     return;
1215     }
1216    
1217     if (dir == MODE_QUERY)
1218     return;
1219    
1220     if ((dir == MODE_ADD) && parc > *parn)
1221     {
1222     key = parv[(*parn)++];
1223    
1224     if (MyClient(source_p))
1225     fix_key(key);
1226     else
1227     fix_key_old(key);
1228    
1229     if (*key == '\0')
1230     return;
1231    
1232     assert(key[0] != ' ');
1233     strlcpy(chptr->mode.key, key, sizeof(chptr->mode.key));
1234    
1235     /* if somebody does MODE #channel +kk a b, accept latter --fl */
1236     for (i = 0; i < mode_count; i++)
1237     {
1238     if (mode_changes[i].letter == c && mode_changes[i].dir == MODE_ADD)
1239     mode_changes[i].letter = 0;
1240     }
1241    
1242     mode_changes[mode_count].letter = c;
1243     mode_changes[mode_count].dir = MODE_ADD;
1244     mode_changes[mode_count].caps = 0;
1245     mode_changes[mode_count].nocaps = 0;
1246     mode_changes[mode_count].mems = ALL_MEMBERS;
1247     mode_changes[mode_count].id = NULL;
1248     mode_changes[mode_count++].arg = chptr->mode.key;
1249     }
1250     else if (dir == MODE_DEL)
1251     {
1252     if (parc > *parn)
1253     (*parn)++;
1254    
1255     if (chptr->mode.key[0] == '\0')
1256     return;
1257    
1258     chptr->mode.key[0] = '\0';
1259    
1260     mode_changes[mode_count].letter = c;
1261     mode_changes[mode_count].dir = MODE_DEL;
1262     mode_changes[mode_count].caps = 0;
1263     mode_changes[mode_count].nocaps = 0;
1264     mode_changes[mode_count].mems = ALL_MEMBERS;
1265     mode_changes[mode_count].id = NULL;
1266     mode_changes[mode_count++].arg = "*";
1267     }
1268     }
1269    
1270     struct ChannelMode
1271     {
1272     void (*func) (struct Client *client_p, struct Client *source_p,
1273     struct Channel *chptr, int parc, int *parn, char **parv,
1274     int *errors, int alev, int dir, char c, void *d,
1275     const char *chname);
1276     void *d;
1277     };
1278    
1279     /* *INDENT-OFF* */
1280     static struct ChannelMode ModeTable[255] =
1281     {
1282     {chm_nosuch, NULL},
1283     {chm_nosuch, NULL}, /* A */
1284     {chm_nosuch, NULL}, /* B */
1285     {chm_nosuch, NULL}, /* C */
1286     {chm_nosuch, NULL}, /* D */
1287     {chm_nosuch, NULL}, /* E */
1288     {chm_nosuch, NULL}, /* F */
1289     {chm_nosuch, NULL}, /* G */
1290     {chm_nosuch, NULL}, /* H */
1291     {chm_invex, NULL}, /* I */
1292     {chm_nosuch, NULL}, /* J */
1293     {chm_nosuch, NULL}, /* K */
1294     {chm_nosuch, NULL}, /* L */
1295     {chm_nosuch, NULL}, /* M */
1296     {chm_nosuch, NULL}, /* N */
1297     {chm_nosuch, NULL}, /* O */
1298     {chm_nosuch, NULL}, /* P */
1299     {chm_nosuch, NULL}, /* Q */
1300     {chm_nosuch, NULL}, /* R */
1301     {chm_nosuch, NULL}, /* S */
1302     {chm_nosuch, NULL}, /* T */
1303     {chm_nosuch, NULL}, /* U */
1304     {chm_nosuch, NULL}, /* V */
1305     {chm_nosuch, NULL}, /* W */
1306     {chm_nosuch, NULL}, /* X */
1307     {chm_nosuch, NULL}, /* Y */
1308     {chm_nosuch, NULL}, /* Z */
1309     {chm_nosuch, NULL},
1310     {chm_nosuch, NULL},
1311     {chm_nosuch, NULL},
1312     {chm_nosuch, NULL},
1313     {chm_nosuch, NULL},
1314     {chm_nosuch, NULL},
1315     {chm_nosuch, NULL}, /* a */
1316     {chm_ban, NULL}, /* b */
1317     {chm_nosuch, NULL}, /* c */
1318     {chm_nosuch, NULL}, /* d */
1319     {chm_except, NULL}, /* e */
1320     {chm_nosuch, NULL}, /* f */
1321     {chm_nosuch, NULL}, /* g */
1322     #ifdef HALFOPS
1323     {chm_hop, NULL}, /* h */
1324     #else
1325     {chm_nosuch, NULL}, /* h */
1326     #endif
1327     {chm_simple, (void *) MODE_INVITEONLY}, /* i */
1328     {chm_nosuch, NULL}, /* j */
1329     {chm_key, NULL}, /* k */
1330     {chm_limit, NULL}, /* l */
1331     {chm_simple, (void *) MODE_MODERATED}, /* m */
1332     {chm_simple, (void *) MODE_NOPRIVMSGS}, /* n */
1333     {chm_op, NULL}, /* o */
1334     {chm_simple, (void *) MODE_PRIVATE}, /* p */
1335     {chm_nosuch, NULL}, /* q */
1336     {chm_nosuch, NULL}, /* r */
1337     {chm_simple, (void *) MODE_SECRET}, /* s */
1338     {chm_simple, (void *) MODE_TOPICLIMIT}, /* t */
1339     {chm_nosuch, NULL}, /* u */
1340     {chm_voice, NULL}, /* v */
1341     {chm_nosuch, NULL}, /* w */
1342     {chm_nosuch, NULL}, /* x */
1343     {chm_nosuch, NULL}, /* y */
1344     {chm_nosuch, NULL}, /* z */
1345     };
1346     /* *INDENT-ON* */
1347    
1348     /* get_channel_access()
1349     *
1350     * inputs - pointer to Client struct
1351     * - pointer to Membership struct
1352     * output - CHACCESS_CHANOP if we should let them have
1353     * chanop level access, 0 for peon level access.
1354     * side effects - NONE
1355     */
1356     static int
1357     get_channel_access(struct Client *source_p, struct Membership *member)
1358     {
1359     /* Let hacked servers in for now... */
1360     if (!MyClient(source_p))
1361     return CHACCESS_CHANOP;
1362    
1363     if (member == NULL)
1364     return CHACCESS_NOTONCHAN;
1365    
1366     /* just to be sure.. */
1367     assert(source_p == member->client_p);
1368    
1369     if (has_member_flags(member, CHFL_CHANOP))
1370     return CHACCESS_CHANOP;
1371    
1372     #ifdef HALFOPS
1373     if (has_member_flags(member, CHFL_HALFOP))
1374     return CHACCESS_HALFOP;
1375     #endif
1376    
1377     return CHACCESS_PEON;
1378     }
1379    
1380     /* void send_cap_mode_changes(struct Client *client_p,
1381     * struct Client *source_p,
1382     * struct Channel *chptr, int cap, int nocap)
1383     * Input: The client sending(client_p), the source client(source_p),
1384     * the channel to send mode changes for(chptr)
1385     * Output: None.
1386     * Side-effects: Sends the appropriate mode changes to capable servers.
1387     *
1388     * send_cap_mode_changes() will loop the server list itself, because
1389     * at this point in time we have 4 capabs for channels, CAP_IE, CAP_EX,
1390     * and a server could support any number of these..
1391     * so we make the modebufs per server, tailoring them to each servers
1392     * specific demand. Its not very pretty, but its one of the few realistic
1393     * ways to handle having this many capabs for channel modes.. --fl_
1394     *
1395     * Reverted back to my original design, except that we now keep a count
1396     * of the number of servers which each combination as an optimisation, so
1397     * the capabs combinations which are not needed are not worked out. -A1kmm
1398     */
1399     /* rewritten to ensure parabuf < MODEBUFLEN -db */
1400    
1401     static void
1402     send_cap_mode_changes(struct Client *client_p, struct Client *source_p,
1403     struct Channel *chptr, int cap, int nocap)
1404     {
1405     int i, mbl, pbl, arglen, nc, mc;
1406     int len;
1407     const char *arg = NULL;
1408     char *parptr;
1409     int dir = MODE_QUERY;
1410    
1411     mc = 0;
1412     nc = 0;
1413     pbl = 0;
1414    
1415     parabuf[0] = '\0';
1416     parptr = parabuf;
1417    
1418     if ((cap & CAP_TS6) && source_p->id[0] != '\0')
1419     mbl = ircsprintf(modebuf, ":%s TMODE %lu %s ", source_p->id,
1420     (unsigned long)chptr->channelts, chptr->chname);
1421     else
1422     mbl = ircsprintf(modebuf, ":%s MODE %s ", source_p->name,
1423     chptr->chname);
1424    
1425     /* loop the list of - modes we have */
1426     for (i = 0; i < mode_count; i++)
1427     {
1428     /* if they dont support the cap we need, or they do support a cap they
1429     * cant have, then dont add it to the modebuf.. that way they wont see
1430     * the mode
1431     */
1432     if ((mode_changes[i].letter == 0) ||
1433     ((cap & mode_changes[i].caps) != mode_changes[i].caps)
1434     || ((nocap & mode_changes[i].nocaps) != mode_changes[i].nocaps))
1435     continue;
1436    
1437     arg = "";
1438    
1439     if ((cap & CAP_TS6) && mode_changes[i].id)
1440     arg = mode_changes[i].id;
1441     if (*arg == '\0')
1442     arg = mode_changes[i].arg;
1443    
1444     /* if we're creeping past the buf size, we need to send it and make
1445     * another line for the other modes
1446     * XXX - this could give away server topology with uids being
1447     * different lengths, but not much we can do, except possibly break
1448     * them as if they were the longest of the nick or uid at all times,
1449     * which even then won't work as we don't always know the uid -A1kmm.
1450     */
1451     if (arg != NULL)
1452     arglen = strlen(arg);
1453     else
1454     arglen = 0;
1455    
1456     if ((mc == MAXMODEPARAMS) ||
1457     ((arglen + mbl + pbl + 2) > IRCD_BUFSIZE) ||
1458     (pbl + arglen + BAN_FUDGE) >= MODEBUFLEN)
1459     {
1460     if (nc != 0)
1461     sendto_server(client_p, source_p, chptr, cap, nocap,
1462     LL_ICHAN | LL_ICLIENT, "%s %s",
1463     modebuf, parabuf);
1464     nc = 0;
1465     mc = 0;
1466    
1467     if ((cap & CAP_TS6) && source_p->id[0] != '\0')
1468     mbl = ircsprintf(modebuf, ":%s MODE %s ", source_p->id,
1469     chptr->chname);
1470     else
1471     mbl = ircsprintf(modebuf, ":%s MODE %s ", source_p->name,
1472     chptr->chname);
1473    
1474     pbl = 0;
1475     parabuf[0] = '\0';
1476     parptr = parabuf;
1477     dir = MODE_QUERY;
1478     }
1479    
1480     if (dir != mode_changes[i].dir)
1481     {
1482     modebuf[mbl++] = (mode_changes[i].dir == MODE_ADD) ? '+' : '-';
1483     dir = mode_changes[i].dir;
1484     }
1485    
1486     modebuf[mbl++] = mode_changes[i].letter;
1487     modebuf[mbl] = '\0';
1488     nc++;
1489    
1490     if (arg != NULL)
1491     {
1492     len = ircsprintf(parptr, "%s ", arg);
1493     pbl += len;
1494     parptr += len;
1495     mc++;
1496     }
1497     }
1498    
1499     if (pbl && parabuf[pbl - 1] == ' ')
1500     parabuf[pbl - 1] = 0;
1501    
1502     if (nc != 0)
1503     sendto_server(client_p, source_p, chptr, cap, nocap,
1504     LL_ICLIENT, "%s %s", modebuf, parabuf);
1505     }
1506    
1507     /* void send_mode_changes(struct Client *client_p,
1508     * struct Client *source_p,
1509     * struct Channel *chptr)
1510     * Input: The client sending(client_p), the source client(source_p),
1511     * the channel to send mode changes for(chptr),
1512     * mode change globals.
1513     * Output: None.
1514     * Side-effects: Sends the appropriate mode changes to other clients
1515     * and propagates to servers.
1516     */
1517     /* ensure parabuf < MODEBUFLEN -db */
1518     static void
1519     send_mode_changes(struct Client *client_p, struct Client *source_p,
1520     struct Channel *chptr, char *chname)
1521     {
1522     int i, mbl, pbl, arglen, nc, mc;
1523     int len;
1524     const char *arg = NULL;
1525     char *parptr;
1526     int dir = MODE_QUERY;
1527    
1528     /* bail out if we have nothing to do... */
1529     if (!mode_count)
1530     return;
1531    
1532     if (IsServer(source_p))
1533     mbl = ircsprintf(modebuf, ":%s MODE %s ", (IsHidden(source_p) ||
1534     ConfigServerHide.hide_servers) ?
1535     me.name : source_p->name, chname);
1536     else
1537     mbl = ircsprintf(modebuf, ":%s!%s@%s MODE %s ", source_p->name,
1538     source_p->username, source_p->host, chname);
1539    
1540     mc = 0;
1541     nc = 0;
1542     pbl = 0;
1543    
1544     parabuf[0] = '\0';
1545     parptr = parabuf;
1546    
1547     for (i = 0; i < mode_count; i++)
1548     {
1549     if (mode_changes[i].letter == 0 ||
1550     mode_changes[i].mems == NON_CHANOPS ||
1551     mode_changes[i].mems == ONLY_SERVERS)
1552     continue;
1553    
1554     arg = mode_changes[i].arg;
1555     if (arg != NULL)
1556     arglen = strlen(arg);
1557     else
1558     arglen = 0;
1559    
1560     if ((mc == MAXMODEPARAMS) ||
1561     ((arglen + mbl + pbl + 2) > IRCD_BUFSIZE) ||
1562     ((arglen + pbl + BAN_FUDGE) >= MODEBUFLEN))
1563     {
1564     if (mbl && modebuf[mbl - 1] == '-')
1565     modebuf[mbl - 1] = '\0';
1566    
1567     if (nc != 0)
1568     sendto_channel_local(ALL_MEMBERS, NO, chptr, "%s %s", modebuf, parabuf);
1569    
1570     nc = 0;
1571     mc = 0;
1572    
1573     if (IsServer(source_p))
1574     mbl = ircsprintf(modebuf, ":%s MODE %s ", me.name, chname);
1575     else
1576     mbl = ircsprintf(modebuf, ":%s!%s@%s MODE %s ", source_p->name,
1577     source_p->username, source_p->host, chname);
1578    
1579     pbl = 0;
1580     parabuf[0] = '\0';
1581     parptr = parabuf;
1582     dir = MODE_QUERY;
1583     }
1584    
1585     if (dir != mode_changes[i].dir)
1586     {
1587     modebuf[mbl++] = (mode_changes[i].dir == MODE_ADD) ? '+' : '-';
1588     dir = mode_changes[i].dir;
1589     }
1590    
1591     modebuf[mbl++] = mode_changes[i].letter;
1592     modebuf[mbl] = '\0';
1593     nc++;
1594    
1595     if (arg != NULL)
1596     {
1597     len = ircsprintf(parptr, "%s ", arg);
1598     pbl += len;
1599     parptr += len;
1600     mc++;
1601     }
1602     }
1603    
1604     if (pbl && parabuf[pbl - 1] == ' ')
1605     parabuf[pbl - 1] = 0;
1606    
1607     if (nc != 0)
1608     sendto_channel_local(ALL_MEMBERS, NO, chptr, "%s %s", modebuf, parabuf);
1609    
1610     nc = 0;
1611     mc = 0;
1612    
1613     /* Now send to servers... */
1614     for (i = 0; i < NCHCAP_COMBOS; i++)
1615     if (chcap_combos[i].count != 0)
1616     send_cap_mode_changes(client_p, source_p, chptr,
1617     chcap_combos[i].cap_yes,
1618     chcap_combos[i].cap_no);
1619     }
1620    
1621     /* void set_channel_mode(struct Client *client_p, struct Client *source_p,
1622     * struct Channel *chptr, int parc, char **parv,
1623     * char *chname)
1624     * Input: The client we received this from, the client this originated
1625     * from, the channel, the parameter count starting at the modes,
1626     * the parameters, the channel name.
1627     * Output: None.
1628     * Side-effects: Changes the channel membership and modes appropriately,
1629     * sends the appropriate MODE messages to the appropriate
1630     * clients.
1631     */
1632     void
1633     set_channel_mode(struct Client *client_p, struct Client *source_p, struct Channel *chptr,
1634     struct Membership *member, int parc, char *parv[], char *chname)
1635     {
1636     int dir = MODE_ADD;
1637     int parn = 1;
1638     int alevel, errors = 0;
1639     char *ml = parv[0], c;
1640     int table_position;
1641    
1642     mode_count = 0;
1643     mode_limit = 0;
1644     simple_modes_mask = 0;
1645    
1646     alevel = get_channel_access(source_p, member);
1647    
1648     for (; (c = *ml) != '\0'; ml++)
1649     {
1650     #if 0
1651     if(mode_count > 20)
1652     break;
1653     #endif
1654     switch (c)
1655     {
1656     case '+':
1657     dir = MODE_ADD;
1658     break;
1659     case '-':
1660     dir = MODE_DEL;
1661     break;
1662     case '=':
1663     dir = MODE_QUERY;
1664     break;
1665     default:
1666     if (c < 'A' || c > 'z')
1667     table_position = 0;
1668     else
1669     table_position = c - 'A' + 1;
1670     ModeTable[table_position].func(client_p, source_p, chptr,
1671     parc, &parn,
1672     parv, &errors, alevel, dir, c,
1673     ModeTable[table_position].d,
1674     chname);
1675     break;
1676     }
1677     }
1678    
1679     send_mode_changes(client_p, source_p, chptr, chname);
1680     }

Properties

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