ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid-7.2/src/channel_mode.c
Revision: 371
Committed: Tue Jan 10 10:45:48 2006 UTC (18 years, 3 months ago) by michael
Content type: text/x-csrc
File size: 47606 byte(s)
Log Message:
- Imported recent channelban changes from HEAD which have been tested extensively.
  The match_cidr() fix didn't work in the first try, so I'm not going to bother
  with further debugging.
- Removed match_cidr() and comp_with_mask()

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

Properties

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