ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/src/channel_mode.c
Revision: 69
Committed: Tue Oct 4 16:09:51 2005 UTC (20 years, 10 months ago) by adx
Content type: text/x-csrc
File size: 46524 byte(s)
Log Message:
- splitted ircd/libio, all headers connected with libio sources have been
  moved for internal use only. To use libio interface, include "libio.h"
  (which is already done in "stdinc.h")


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

Properties

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