ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/channel_mode.c
Revision: 1167
Committed: Thu Aug 11 20:13:38 2011 UTC (14 years ago) by michael
Content type: text/x-csrc
Original Path: ircd-hybrid-8/src/channel_mode.c
File size: 52505 byte(s)
Log Message:
- Improve services support
- Add channelmode +r

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

Properties

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