ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/channel_mode.c
Revision: 572
Committed: Sun Apr 30 16:57:48 2006 UTC (19 years, 4 months ago) by michael
Content type: text/x-csrc
Original Path: ircd-hybrid-7.2/src/channel_mode.c
File size: 47894 byte(s)
Log Message:
- Backported changes made in HEAD to get rid of Channel::locmembers.
  This is mainly to save about 5megs of ram on networks like efnet where
  we have about 600k allocated Membership structures.

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 michael 572 DLINK_FOREACH(ptr, chptr->members.head)
884 adx 30 {
885     struct Membership *ms = ptr->data;
886 michael 572
887     if (MyConnect(ms->client_p))
888     ms->flags &= ~(CHFL_BAN_SILENCED|CHFL_BAN_CHECKED);
889 adx 30 }
890     }
891    
892     static void
893     chm_op(struct Client *client_p, struct Client *source_p,
894     struct Channel *chptr, int parc, int *parn,
895     char **parv, int *errors, int alev, int dir, char c, void *d,
896     const char *chname)
897     {
898     char *opnick;
899     struct Client *targ_p;
900     struct Membership *member;
901 adx 356 int caps = 0;
902 adx 30
903     if (alev < CHACCESS_CHANOP)
904     {
905     if (!(*errors & SM_ERR_NOOPS))
906     sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ?
907     ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED),
908     me.name, source_p->name, chname);
909     *errors |= SM_ERR_NOOPS;
910     return;
911     }
912    
913     if ((dir == MODE_QUERY) || (parc <= *parn))
914     return;
915    
916     opnick = parv[(*parn)++];
917    
918     if ((targ_p = find_chasing(client_p, source_p, opnick, NULL)) == NULL)
919     return;
920     if (!IsClient(targ_p))
921     return;
922    
923     if ((member = find_channel_link(targ_p, chptr)) == NULL)
924     {
925     if (!(*errors & SM_ERR_NOTONCHANNEL))
926     sendto_one(source_p, form_str(ERR_USERNOTINCHANNEL),
927     me.name, source_p->name, opnick, chname);
928     *errors |= SM_ERR_NOTONCHANNEL;
929     return;
930     }
931    
932     if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
933     return;
934    
935     /* no redundant mode changes */
936     if (dir == MODE_ADD && has_member_flags(member, CHFL_CHANOP))
937     return;
938     if (dir == MODE_DEL && !has_member_flags(member, CHFL_CHANOP))
939 adx 356 {
940     #ifdef HALFOPS
941     if (has_member_flags(member, CHFL_HALFOP))
942     chm_hop(client_p, source_p, chptr, parc, parn, parv, errors, alev,
943     dir, c, d, chname);
944     #endif
945 adx 30 return;
946 adx 356 }
947 adx 30
948 adx 356 #ifdef HALFOPS
949     if (dir == MODE_ADD && has_member_flags(member, CHFL_HALFOP))
950     {
951     /* promoting from % to @ is visible only to CAP_HOPS servers */
952     mode_changes[mode_count].letter = 'h';
953     mode_changes[mode_count].dir = MODE_DEL;
954     mode_changes[mode_count].caps = caps = CAP_HOPS;
955     mode_changes[mode_count].nocaps = 0;
956     mode_changes[mode_count].mems = ALL_MEMBERS;
957     mode_changes[mode_count].id = NULL;
958     mode_changes[mode_count].arg = targ_p->name;
959     mode_changes[mode_count++].client = targ_p;
960     }
961     #endif
962    
963 adx 30 mode_changes[mode_count].letter = 'o';
964     mode_changes[mode_count].dir = dir;
965 adx 356 mode_changes[mode_count].caps = caps;
966 adx 30 mode_changes[mode_count].nocaps = 0;
967     mode_changes[mode_count].mems = ALL_MEMBERS;
968     mode_changes[mode_count].id = targ_p->id;
969     mode_changes[mode_count].arg = targ_p->name;
970     mode_changes[mode_count++].client = targ_p;
971    
972     if (dir == MODE_ADD)
973     {
974     AddMemberFlag(member, CHFL_CHANOP);
975 adx 356 DelMemberFlag(member, CHFL_DEOPPED | CHFL_HALFOP);
976 adx 30 }
977     else
978     DelMemberFlag(member, CHFL_CHANOP);
979     }
980    
981     #ifdef HALFOPS
982     static void
983     chm_hop(struct Client *client_p, struct Client *source_p,
984     struct Channel *chptr, int parc, int *parn,
985     char **parv, int *errors, int alev, int dir, char c, void *d,
986     const char *chname)
987     {
988     char *opnick;
989     struct Client *targ_p;
990     struct Membership *member;
991    
992     /* *sigh* - dont allow halfops to set +/-h, they could fully control a
993     * channel if there were no ops - it doesnt solve anything.. MODE_PRIVATE
994     * when used with MODE_SECRET is paranoid - cant use +p
995     *
996     * it needs to be optional per channel - but not via +p, that or remove
997     * paranoid.. -- fl_
998     *
999     * +p means paranoid, it is useless for anything else on modern IRC, as
1000     * list isn't really usable. If you want to have a private channel these
1001     * days, you set it +s. Halfops can no longer remove simple modes when
1002     * +p is set (although they can set +p) so it is safe to use this to
1003     * control whether they can (de)halfop...
1004     */
1005     if (alev <
1006     ((chptr->mode.mode & MODE_PRIVATE) ? CHACCESS_CHANOP : CHACCESS_HALFOP))
1007     {
1008     if (!(*errors & SM_ERR_NOOPS))
1009     sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ?
1010     ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED),
1011     me.name, source_p->name, chname);
1012     *errors |= SM_ERR_NOOPS;
1013     return;
1014     }
1015    
1016     if ((dir == MODE_QUERY) || (parc <= *parn))
1017     return;
1018    
1019     opnick = parv[(*parn)++];
1020    
1021     if ((targ_p = find_chasing(client_p, source_p, opnick, NULL)) == NULL)
1022     return;
1023     if (!IsClient(targ_p))
1024     return;
1025    
1026     if ((member = find_channel_link(targ_p, chptr)) == NULL)
1027     {
1028     if (!(*errors & SM_ERR_NOTONCHANNEL))
1029     sendto_one(source_p, form_str(ERR_USERNOTINCHANNEL),
1030     me.name, source_p->name, opnick, chname);
1031     *errors |= SM_ERR_NOTONCHANNEL;
1032     return;
1033     }
1034    
1035     if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
1036     return;
1037    
1038     /* no redundant mode changes */
1039 adx 356 if (dir == MODE_ADD && has_member_flags(member, CHFL_HALFOP | CHFL_CHANOP))
1040 adx 30 return;
1041     if (dir == MODE_DEL && !has_member_flags(member, CHFL_HALFOP))
1042     return;
1043    
1044     mode_changes[mode_count].letter = 'h';
1045     mode_changes[mode_count].dir = dir;
1046 adx 356 mode_changes[mode_count].caps = CAP_HOPS;
1047 adx 30 mode_changes[mode_count].nocaps = 0;
1048     mode_changes[mode_count].mems = ALL_MEMBERS;
1049     mode_changes[mode_count].id = targ_p->id;
1050     mode_changes[mode_count].arg = targ_p->name;
1051     mode_changes[mode_count++].client = targ_p;
1052    
1053 adx 356 mode_changes[mode_count].letter = 'o';
1054     mode_changes[mode_count].dir = dir;
1055     mode_changes[mode_count].caps = 0;
1056     mode_changes[mode_count].nocaps = CAP_HOPS;
1057     mode_changes[mode_count].mems = ONLY_SERVERS;
1058     mode_changes[mode_count].id = targ_p->id;
1059     mode_changes[mode_count].arg = targ_p->name;
1060     mode_changes[mode_count++].client = targ_p;
1061    
1062 adx 30 if (dir == MODE_ADD)
1063     {
1064     AddMemberFlag(member, CHFL_HALFOP);
1065     DelMemberFlag(member, CHFL_DEOPPED);
1066     }
1067     else
1068     DelMemberFlag(member, CHFL_HALFOP);
1069     }
1070     #endif
1071    
1072     static void
1073     chm_voice(struct Client *client_p, struct Client *source_p,
1074     struct Channel *chptr, int parc, int *parn,
1075     char **parv, int *errors, int alev, int dir, char c, void *d,
1076     const char *chname)
1077     {
1078     char *opnick;
1079     struct Client *targ_p;
1080     struct Membership *member;
1081    
1082     if (alev < CHACCESS_HALFOP)
1083     {
1084     if (!(*errors & SM_ERR_NOOPS))
1085     sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ?
1086     ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED),
1087     me.name, source_p->name, chname);
1088     *errors |= SM_ERR_NOOPS;
1089     return;
1090     }
1091    
1092     if ((dir == MODE_QUERY) || parc <= *parn)
1093     return;
1094    
1095     opnick = parv[(*parn)++];
1096    
1097     if ((targ_p = find_chasing(client_p, source_p, opnick, NULL)) == NULL)
1098     return;
1099     if (!IsClient(targ_p))
1100     return;
1101    
1102     if ((member = find_channel_link(targ_p, chptr)) == NULL)
1103     {
1104     if (!(*errors & SM_ERR_NOTONCHANNEL))
1105     sendto_one(source_p, form_str(ERR_USERNOTINCHANNEL),
1106     me.name, source_p->name, opnick, chname);
1107     *errors |= SM_ERR_NOTONCHANNEL;
1108     return;
1109     }
1110    
1111     if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
1112     return;
1113    
1114     /* no redundant mode changes */
1115     if (dir == MODE_ADD && has_member_flags(member, CHFL_VOICE))
1116     return;
1117     if (dir == MODE_DEL && !has_member_flags(member, CHFL_VOICE))
1118     return;
1119    
1120     mode_changes[mode_count].letter = 'v';
1121     mode_changes[mode_count].dir = dir;
1122     mode_changes[mode_count].caps = 0;
1123     mode_changes[mode_count].nocaps = 0;
1124     mode_changes[mode_count].mems = ALL_MEMBERS;
1125     mode_changes[mode_count].id = targ_p->id;
1126     mode_changes[mode_count].arg = targ_p->name;
1127     mode_changes[mode_count++].client = targ_p;
1128    
1129     if (dir == MODE_ADD)
1130     AddMemberFlag(member, CHFL_VOICE);
1131     else
1132     DelMemberFlag(member, CHFL_VOICE);
1133     }
1134    
1135     static void
1136     chm_limit(struct Client *client_p, struct Client *source_p,
1137     struct Channel *chptr, int parc, int *parn,
1138     char **parv, int *errors, int alev, int dir, char c, void *d,
1139     const char *chname)
1140     {
1141     int i, limit;
1142     char *lstr;
1143    
1144     if (alev < CHACCESS_HALFOP)
1145     {
1146     if (!(*errors & SM_ERR_NOOPS))
1147     sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ?
1148     ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED),
1149     me.name, source_p->name, chname);
1150     *errors |= SM_ERR_NOOPS;
1151     return;
1152     }
1153    
1154     if (dir == MODE_QUERY)
1155     return;
1156    
1157     if ((dir == MODE_ADD) && parc > *parn)
1158     {
1159     lstr = parv[(*parn)++];
1160    
1161     if ((limit = atoi(lstr)) <= 0)
1162     return;
1163    
1164     ircsprintf(lstr, "%d", limit);
1165    
1166     /* if somebody sets MODE #channel +ll 1 2, accept latter --fl */
1167     for (i = 0; i < mode_count; i++)
1168     {
1169     if (mode_changes[i].letter == c && mode_changes[i].dir == MODE_ADD)
1170     mode_changes[i].letter = 0;
1171     }
1172    
1173     mode_changes[mode_count].letter = c;
1174     mode_changes[mode_count].dir = MODE_ADD;
1175     mode_changes[mode_count].caps = 0;
1176     mode_changes[mode_count].nocaps = 0;
1177     mode_changes[mode_count].mems = ALL_MEMBERS;
1178     mode_changes[mode_count].id = NULL;
1179     mode_changes[mode_count++].arg = lstr;
1180    
1181     chptr->mode.limit = limit;
1182     }
1183     else if (dir == MODE_DEL)
1184     {
1185     if (!chptr->mode.limit)
1186     return;
1187    
1188     chptr->mode.limit = 0;
1189    
1190     mode_changes[mode_count].letter = c;
1191     mode_changes[mode_count].dir = MODE_DEL;
1192     mode_changes[mode_count].caps = 0;
1193     mode_changes[mode_count].nocaps = 0;
1194     mode_changes[mode_count].mems = ALL_MEMBERS;
1195     mode_changes[mode_count].id = NULL;
1196     mode_changes[mode_count++].arg = NULL;
1197     }
1198     }
1199    
1200     static void
1201     chm_key(struct Client *client_p, struct Client *source_p,
1202     struct Channel *chptr, int parc, int *parn,
1203     char **parv, int *errors, int alev, int dir, char c, void *d,
1204     const char *chname)
1205     {
1206     int i;
1207     char *key;
1208    
1209     if (alev < CHACCESS_HALFOP)
1210     {
1211     if (!(*errors & SM_ERR_NOOPS))
1212     sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ?
1213     ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED),
1214     me.name, source_p->name, chname);
1215     *errors |= SM_ERR_NOOPS;
1216     return;
1217     }
1218    
1219     if (dir == MODE_QUERY)
1220     return;
1221    
1222     if ((dir == MODE_ADD) && parc > *parn)
1223     {
1224     key = parv[(*parn)++];
1225    
1226     if (MyClient(source_p))
1227     fix_key(key);
1228     else
1229     fix_key_old(key);
1230    
1231     if (*key == '\0')
1232     return;
1233    
1234     assert(key[0] != ' ');
1235     strlcpy(chptr->mode.key, key, sizeof(chptr->mode.key));
1236    
1237     /* if somebody does MODE #channel +kk a b, accept latter --fl */
1238     for (i = 0; i < mode_count; i++)
1239     {
1240     if (mode_changes[i].letter == c && mode_changes[i].dir == MODE_ADD)
1241     mode_changes[i].letter = 0;
1242     }
1243    
1244     mode_changes[mode_count].letter = c;
1245     mode_changes[mode_count].dir = MODE_ADD;
1246     mode_changes[mode_count].caps = 0;
1247     mode_changes[mode_count].nocaps = 0;
1248     mode_changes[mode_count].mems = ALL_MEMBERS;
1249     mode_changes[mode_count].id = NULL;
1250     mode_changes[mode_count++].arg = chptr->mode.key;
1251     }
1252     else if (dir == MODE_DEL)
1253     {
1254     if (parc > *parn)
1255     (*parn)++;
1256    
1257     if (chptr->mode.key[0] == '\0')
1258     return;
1259    
1260     chptr->mode.key[0] = '\0';
1261    
1262     mode_changes[mode_count].letter = c;
1263     mode_changes[mode_count].dir = MODE_DEL;
1264     mode_changes[mode_count].caps = 0;
1265     mode_changes[mode_count].nocaps = 0;
1266     mode_changes[mode_count].mems = ALL_MEMBERS;
1267     mode_changes[mode_count].id = NULL;
1268     mode_changes[mode_count++].arg = "*";
1269     }
1270     }
1271    
1272     struct ChannelMode
1273     {
1274     void (*func) (struct Client *client_p, struct Client *source_p,
1275     struct Channel *chptr, int parc, int *parn, char **parv,
1276     int *errors, int alev, int dir, char c, void *d,
1277     const char *chname);
1278     void *d;
1279     };
1280    
1281     /* *INDENT-OFF* */
1282     static struct ChannelMode ModeTable[255] =
1283     {
1284     {chm_nosuch, NULL},
1285     {chm_nosuch, NULL}, /* A */
1286     {chm_nosuch, NULL}, /* B */
1287     {chm_nosuch, NULL}, /* C */
1288     {chm_nosuch, NULL}, /* D */
1289     {chm_nosuch, NULL}, /* E */
1290     {chm_nosuch, NULL}, /* F */
1291     {chm_nosuch, NULL}, /* G */
1292     {chm_nosuch, NULL}, /* H */
1293     {chm_invex, NULL}, /* I */
1294     {chm_nosuch, NULL}, /* J */
1295     {chm_nosuch, NULL}, /* K */
1296     {chm_nosuch, NULL}, /* L */
1297     {chm_nosuch, NULL}, /* M */
1298     {chm_nosuch, NULL}, /* N */
1299     {chm_nosuch, NULL}, /* O */
1300     {chm_nosuch, NULL}, /* P */
1301     {chm_nosuch, NULL}, /* Q */
1302     {chm_nosuch, NULL}, /* R */
1303     {chm_nosuch, NULL}, /* S */
1304     {chm_nosuch, NULL}, /* T */
1305     {chm_nosuch, NULL}, /* U */
1306     {chm_nosuch, NULL}, /* V */
1307     {chm_nosuch, NULL}, /* W */
1308     {chm_nosuch, NULL}, /* X */
1309     {chm_nosuch, NULL}, /* Y */
1310     {chm_nosuch, NULL}, /* Z */
1311     {chm_nosuch, NULL},
1312     {chm_nosuch, NULL},
1313     {chm_nosuch, NULL},
1314     {chm_nosuch, NULL},
1315     {chm_nosuch, NULL},
1316     {chm_nosuch, NULL},
1317     {chm_nosuch, NULL}, /* a */
1318     {chm_ban, NULL}, /* b */
1319     {chm_nosuch, NULL}, /* c */
1320     {chm_nosuch, NULL}, /* d */
1321     {chm_except, NULL}, /* e */
1322     {chm_nosuch, NULL}, /* f */
1323     {chm_nosuch, NULL}, /* g */
1324     #ifdef HALFOPS
1325     {chm_hop, NULL}, /* h */
1326     #else
1327     {chm_nosuch, NULL}, /* h */
1328     #endif
1329     {chm_simple, (void *) MODE_INVITEONLY}, /* i */
1330     {chm_nosuch, NULL}, /* j */
1331     {chm_key, NULL}, /* k */
1332     {chm_limit, NULL}, /* l */
1333     {chm_simple, (void *) MODE_MODERATED}, /* m */
1334     {chm_simple, (void *) MODE_NOPRIVMSGS}, /* n */
1335     {chm_op, NULL}, /* o */
1336     {chm_simple, (void *) MODE_PRIVATE}, /* p */
1337     {chm_nosuch, NULL}, /* q */
1338     {chm_nosuch, NULL}, /* r */
1339     {chm_simple, (void *) MODE_SECRET}, /* s */
1340     {chm_simple, (void *) MODE_TOPICLIMIT}, /* t */
1341     {chm_nosuch, NULL}, /* u */
1342     {chm_voice, NULL}, /* v */
1343     {chm_nosuch, NULL}, /* w */
1344     {chm_nosuch, NULL}, /* x */
1345     {chm_nosuch, NULL}, /* y */
1346     {chm_nosuch, NULL}, /* z */
1347     };
1348     /* *INDENT-ON* */
1349    
1350     /* get_channel_access()
1351     *
1352     * inputs - pointer to Client struct
1353     * - pointer to Membership struct
1354     * output - CHACCESS_CHANOP if we should let them have
1355     * chanop level access, 0 for peon level access.
1356     * side effects - NONE
1357     */
1358     static int
1359     get_channel_access(struct Client *source_p, struct Membership *member)
1360     {
1361     /* Let hacked servers in for now... */
1362     if (!MyClient(source_p))
1363     return CHACCESS_CHANOP;
1364    
1365     if (member == NULL)
1366     return CHACCESS_NOTONCHAN;
1367    
1368     /* just to be sure.. */
1369     assert(source_p == member->client_p);
1370    
1371     if (has_member_flags(member, CHFL_CHANOP))
1372     return CHACCESS_CHANOP;
1373    
1374     #ifdef HALFOPS
1375     if (has_member_flags(member, CHFL_HALFOP))
1376     return CHACCESS_HALFOP;
1377     #endif
1378    
1379     return CHACCESS_PEON;
1380     }
1381    
1382     /* void send_cap_mode_changes(struct Client *client_p,
1383     * struct Client *source_p,
1384     * struct Channel *chptr, int cap, int nocap)
1385     * Input: The client sending(client_p), the source client(source_p),
1386     * the channel to send mode changes for(chptr)
1387     * Output: None.
1388     * Side-effects: Sends the appropriate mode changes to capable servers.
1389     *
1390     * send_cap_mode_changes() will loop the server list itself, because
1391     * at this point in time we have 4 capabs for channels, CAP_IE, CAP_EX,
1392     * and a server could support any number of these..
1393     * so we make the modebufs per server, tailoring them to each servers
1394     * specific demand. Its not very pretty, but its one of the few realistic
1395     * ways to handle having this many capabs for channel modes.. --fl_
1396     *
1397     * Reverted back to my original design, except that we now keep a count
1398     * of the number of servers which each combination as an optimisation, so
1399     * the capabs combinations which are not needed are not worked out. -A1kmm
1400     */
1401     /* rewritten to ensure parabuf < MODEBUFLEN -db */
1402    
1403     static void
1404     send_cap_mode_changes(struct Client *client_p, struct Client *source_p,
1405     struct Channel *chptr, int cap, int nocap)
1406     {
1407     int i, mbl, pbl, arglen, nc, mc;
1408     int len;
1409     const char *arg = NULL;
1410     char *parptr;
1411     int dir = MODE_QUERY;
1412    
1413     mc = 0;
1414     nc = 0;
1415     pbl = 0;
1416    
1417     parabuf[0] = '\0';
1418     parptr = parabuf;
1419    
1420     if ((cap & CAP_TS6) && source_p->id[0] != '\0')
1421     mbl = ircsprintf(modebuf, ":%s TMODE %lu %s ", source_p->id,
1422     (unsigned long)chptr->channelts, chptr->chname);
1423     else
1424     mbl = ircsprintf(modebuf, ":%s MODE %s ", source_p->name,
1425     chptr->chname);
1426    
1427     /* loop the list of - modes we have */
1428     for (i = 0; i < mode_count; i++)
1429     {
1430     /* if they dont support the cap we need, or they do support a cap they
1431     * cant have, then dont add it to the modebuf.. that way they wont see
1432     * the mode
1433     */
1434     if ((mode_changes[i].letter == 0) ||
1435     ((cap & mode_changes[i].caps) != mode_changes[i].caps)
1436     || ((nocap & mode_changes[i].nocaps) != mode_changes[i].nocaps))
1437     continue;
1438    
1439     arg = "";
1440    
1441     if ((cap & CAP_TS6) && mode_changes[i].id)
1442     arg = mode_changes[i].id;
1443     if (*arg == '\0')
1444     arg = mode_changes[i].arg;
1445    
1446     /* if we're creeping past the buf size, we need to send it and make
1447     * another line for the other modes
1448     * XXX - this could give away server topology with uids being
1449     * different lengths, but not much we can do, except possibly break
1450     * them as if they were the longest of the nick or uid at all times,
1451     * which even then won't work as we don't always know the uid -A1kmm.
1452     */
1453     if (arg != NULL)
1454     arglen = strlen(arg);
1455     else
1456     arglen = 0;
1457    
1458     if ((mc == MAXMODEPARAMS) ||
1459     ((arglen + mbl + pbl + 2) > IRCD_BUFSIZE) ||
1460     (pbl + arglen + BAN_FUDGE) >= MODEBUFLEN)
1461     {
1462     if (nc != 0)
1463     sendto_server(client_p, source_p, chptr, cap, nocap,
1464     LL_ICHAN | LL_ICLIENT, "%s %s",
1465     modebuf, parabuf);
1466     nc = 0;
1467     mc = 0;
1468    
1469     if ((cap & CAP_TS6) && source_p->id[0] != '\0')
1470     mbl = ircsprintf(modebuf, ":%s MODE %s ", source_p->id,
1471     chptr->chname);
1472     else
1473     mbl = ircsprintf(modebuf, ":%s MODE %s ", source_p->name,
1474     chptr->chname);
1475    
1476     pbl = 0;
1477     parabuf[0] = '\0';
1478     parptr = parabuf;
1479     dir = MODE_QUERY;
1480     }
1481    
1482     if (dir != mode_changes[i].dir)
1483     {
1484     modebuf[mbl++] = (mode_changes[i].dir == MODE_ADD) ? '+' : '-';
1485     dir = mode_changes[i].dir;
1486     }
1487    
1488     modebuf[mbl++] = mode_changes[i].letter;
1489     modebuf[mbl] = '\0';
1490     nc++;
1491    
1492     if (arg != NULL)
1493     {
1494     len = ircsprintf(parptr, "%s ", arg);
1495     pbl += len;
1496     parptr += len;
1497     mc++;
1498     }
1499     }
1500    
1501     if (pbl && parabuf[pbl - 1] == ' ')
1502     parabuf[pbl - 1] = 0;
1503    
1504     if (nc != 0)
1505     sendto_server(client_p, source_p, chptr, cap, nocap,
1506     LL_ICLIENT, "%s %s", modebuf, parabuf);
1507     }
1508    
1509     /* void send_mode_changes(struct Client *client_p,
1510     * struct Client *source_p,
1511     * struct Channel *chptr)
1512     * Input: The client sending(client_p), the source client(source_p),
1513     * the channel to send mode changes for(chptr),
1514     * mode change globals.
1515     * Output: None.
1516     * Side-effects: Sends the appropriate mode changes to other clients
1517     * and propagates to servers.
1518     */
1519     /* ensure parabuf < MODEBUFLEN -db */
1520     static void
1521     send_mode_changes(struct Client *client_p, struct Client *source_p,
1522     struct Channel *chptr, char *chname)
1523     {
1524     int i, mbl, pbl, arglen, nc, mc;
1525     int len;
1526     const char *arg = NULL;
1527     char *parptr;
1528     int dir = MODE_QUERY;
1529    
1530     /* bail out if we have nothing to do... */
1531     if (!mode_count)
1532     return;
1533    
1534     if (IsServer(source_p))
1535     mbl = ircsprintf(modebuf, ":%s MODE %s ", (IsHidden(source_p) ||
1536     ConfigServerHide.hide_servers) ?
1537     me.name : source_p->name, chname);
1538     else
1539     mbl = ircsprintf(modebuf, ":%s!%s@%s MODE %s ", source_p->name,
1540     source_p->username, source_p->host, chname);
1541    
1542     mc = 0;
1543     nc = 0;
1544     pbl = 0;
1545    
1546     parabuf[0] = '\0';
1547     parptr = parabuf;
1548    
1549     for (i = 0; i < mode_count; i++)
1550     {
1551     if (mode_changes[i].letter == 0 ||
1552     mode_changes[i].mems == NON_CHANOPS ||
1553     mode_changes[i].mems == ONLY_SERVERS)
1554     continue;
1555    
1556     arg = mode_changes[i].arg;
1557     if (arg != NULL)
1558     arglen = strlen(arg);
1559     else
1560     arglen = 0;
1561    
1562     if ((mc == MAXMODEPARAMS) ||
1563     ((arglen + mbl + pbl + 2) > IRCD_BUFSIZE) ||
1564     ((arglen + pbl + BAN_FUDGE) >= MODEBUFLEN))
1565     {
1566     if (mbl && modebuf[mbl - 1] == '-')
1567     modebuf[mbl - 1] = '\0';
1568    
1569     if (nc != 0)
1570     sendto_channel_local(ALL_MEMBERS, NO, chptr, "%s %s", modebuf, parabuf);
1571    
1572     nc = 0;
1573     mc = 0;
1574    
1575     if (IsServer(source_p))
1576     mbl = ircsprintf(modebuf, ":%s MODE %s ", me.name, chname);
1577     else
1578     mbl = ircsprintf(modebuf, ":%s!%s@%s MODE %s ", source_p->name,
1579     source_p->username, source_p->host, chname);
1580    
1581     pbl = 0;
1582     parabuf[0] = '\0';
1583     parptr = parabuf;
1584     dir = MODE_QUERY;
1585     }
1586    
1587     if (dir != mode_changes[i].dir)
1588     {
1589     modebuf[mbl++] = (mode_changes[i].dir == MODE_ADD) ? '+' : '-';
1590     dir = mode_changes[i].dir;
1591     }
1592    
1593     modebuf[mbl++] = mode_changes[i].letter;
1594     modebuf[mbl] = '\0';
1595     nc++;
1596    
1597     if (arg != NULL)
1598     {
1599     len = ircsprintf(parptr, "%s ", arg);
1600     pbl += len;
1601     parptr += len;
1602     mc++;
1603     }
1604     }
1605    
1606     if (pbl && parabuf[pbl - 1] == ' ')
1607     parabuf[pbl - 1] = 0;
1608    
1609     if (nc != 0)
1610     sendto_channel_local(ALL_MEMBERS, NO, chptr, "%s %s", modebuf, parabuf);
1611    
1612     nc = 0;
1613     mc = 0;
1614    
1615     /* Now send to servers... */
1616     for (i = 0; i < NCHCAP_COMBOS; i++)
1617     if (chcap_combos[i].count != 0)
1618     send_cap_mode_changes(client_p, source_p, chptr,
1619     chcap_combos[i].cap_yes,
1620     chcap_combos[i].cap_no);
1621     }
1622    
1623     /* void set_channel_mode(struct Client *client_p, struct Client *source_p,
1624     * struct Channel *chptr, int parc, char **parv,
1625     * char *chname)
1626     * Input: The client we received this from, the client this originated
1627     * from, the channel, the parameter count starting at the modes,
1628     * the parameters, the channel name.
1629     * Output: None.
1630     * Side-effects: Changes the channel membership and modes appropriately,
1631     * sends the appropriate MODE messages to the appropriate
1632     * clients.
1633     */
1634     void
1635     set_channel_mode(struct Client *client_p, struct Client *source_p, struct Channel *chptr,
1636     struct Membership *member, int parc, char *parv[], char *chname)
1637     {
1638     int dir = MODE_ADD;
1639     int parn = 1;
1640     int alevel, errors = 0;
1641     char *ml = parv[0], c;
1642     int table_position;
1643    
1644     mode_count = 0;
1645     mode_limit = 0;
1646     simple_modes_mask = 0;
1647    
1648     alevel = get_channel_access(source_p, member);
1649    
1650     for (; (c = *ml) != '\0'; ml++)
1651     {
1652     #if 0
1653     if(mode_count > 20)
1654     break;
1655     #endif
1656     switch (c)
1657     {
1658     case '+':
1659     dir = MODE_ADD;
1660     break;
1661     case '-':
1662     dir = MODE_DEL;
1663     break;
1664     case '=':
1665     dir = MODE_QUERY;
1666     break;
1667     default:
1668     if (c < 'A' || c > 'z')
1669     table_position = 0;
1670     else
1671     table_position = c - 'A' + 1;
1672     ModeTable[table_position].func(client_p, source_p, chptr,
1673     parc, &parn,
1674     parv, &errors, alevel, dir, c,
1675     ModeTable[table_position].d,
1676     chname);
1677     break;
1678     }
1679     }
1680    
1681     send_mode_changes(client_p, source_p, chptr, chname);
1682     }

Properties

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