ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/ermyth/src/cmode.C
Revision: 1.7
Committed: Sun Sep 9 20:05:52 2007 UTC (19 years ago) by pippijn
Content type: text/plain
Branch: MAIN
Changes since 1.6: +2 -1 lines
Log Message:
- changed configurations to the c++ stdlib
- more #defines to enum
- removed getopt.h and link.h from the system as they were unused
- reworked logstreams
- added an itoa with old syntax
- made klines objects
- moved some global variables into appropriate classes
- fixed boost.foreach's compiler workaround #if's
- allow other files to add exceptions with ADD_EXCEPTION
- changed mynick_t to c++ object
- moved servers.h out of atheme.h
- corrected PING from inspircd 1.2

File Contents

# User Rev Content
1 pippijn 1.1 /*
2     * cmode.C: Channel mode change tracking.
3 pippijn 1.2 * Rights to this code are documented in doc/pod/license.pod.
4 pippijn 1.1 *
5 pippijn 1.4 * Copyright © 2005-2007 Atheme Project (http://www.atheme.org)
6 pippijn 1.1 */
7    
8 pippijn 1.7 static char const rcsid[] = "$Id: cmode.C,v 1.6 2007-09-05 11:23:15 pippijn Exp $";
9 pippijn 1.1
10     #include "atheme.h"
11 pippijn 1.7 #include "servers.h"
12 pippijn 1.1 #include <account/chanacs.h>
13     #include <account/mychan.h>
14    
15     /* convert mode flags to a text mode string */
16     char *
17     flags_to_string (int flags)
18     {
19     static char buf[32];
20     char *s = buf;
21     int i;
22    
23     for (i = 0; mode_list[i].mode != 0; i++)
24     if (flags & mode_list[i].value)
25     *s++ = mode_list[i].mode;
26    
27     *s = 0;
28    
29     return buf;
30     }
31    
32     /* convert a mode character to a flag. */
33     int
34     mode_to_flag (char c)
35     {
36     int i;
37    
38     for (i = 0; mode_list[i].mode != 0 && mode_list[i].mode != c; i++);
39    
40     return mode_list[i].value;
41     }
42    
43     /* yeah, this should be fun. */
44     /* If source == NULL, apply a mode change from outside to our structures
45     * If source != NULL, apply the mode change and send it out from that user
46     */
47     void
48 pippijn 1.4 channel_mode (user_t *source, channel_t *chan, int parc, char const * const parv[])
49 pippijn 1.1 {
50     bool matched = false;
51     bool simple_modes_changed = false;
52 pippijn 1.6 int i, parpos = 0;
53     mtype whatt = MTYPE_NUL;
54 pippijn 1.1 unsigned int newlimit;
55 pippijn 1.4 char const *pos = parv[0];
56 pippijn 1.1 mychan_t *mc;
57     chanuser_t *cu = NULL;
58     user_t *first_deopped_service = NULL;
59     node_t *n;
60    
61     if ((!pos) || (*pos == '\0'))
62     return;
63    
64     if (!chan)
65     return;
66    
67     /* SJOIN modes of 0 means no change */
68     if (*pos == '0')
69     return;
70    
71     for (; *pos != '\0'; pos++)
72     {
73     matched = false;
74    
75     if (*pos == '+')
76     {
77     whatt = MTYPE_ADD;
78     continue;
79     }
80     if (*pos == '-')
81     {
82     whatt = MTYPE_DEL;
83     continue;
84     }
85    
86     for (i = 0; mode_list[i].mode != '\0'; i++)
87     {
88     if (*pos == mode_list[i].mode)
89     {
90     matched = true;
91    
92     if (whatt == MTYPE_ADD)
93     {
94     if (!(chan->modes & mode_list[i].value))
95     simple_modes_changed = true;
96     chan->modes |= mode_list[i].value;
97     }
98     else
99     {
100     if (chan->modes & mode_list[i].value)
101     simple_modes_changed = true;
102     chan->modes &= ~mode_list[i].value;
103     }
104    
105     if (source)
106     modestack_mode_simple (source->nick, chan, whatt, mode_list[i].value);
107    
108     break;
109     }
110     }
111     if (matched)
112     continue;
113    
114     for (i = 0; ignore_mode_list[i].mode != '\0'; i++)
115     {
116     if (*pos == ignore_mode_list[i].mode)
117     {
118     matched = true;
119     if (whatt == MTYPE_ADD)
120     {
121     if (++parpos >= parc)
122     break;
123     if (source && !ignore_mode_list[i].check (parv[parpos], chan, NULL, NULL, NULL))
124     break;
125     if (chan->extmodes[i])
126     {
127     if (strcmp (chan->extmodes[i], parv[parpos]))
128     simple_modes_changed = true;
129 pippijn 1.4 sfree (chan->extmodes[i]);
130 pippijn 1.1 }
131     else
132     simple_modes_changed = true;
133     chan->extmodes[i] = sstrdup (parv[parpos]);
134     if (source)
135     modestack_mode_ext (source->nick, chan, MTYPE_ADD, i, chan->extmodes[i]);
136     }
137     else
138     {
139     if (chan->extmodes[i])
140     {
141     simple_modes_changed = true;
142 pippijn 1.4 sfree (chan->extmodes[i]);
143 pippijn 1.1 chan->extmodes[i] = NULL;
144     }
145     if (source)
146     modestack_mode_ext (source->nick, chan, MTYPE_DEL, i, NULL);
147     }
148     break;
149     }
150     }
151     if (matched)
152     continue;
153    
154     if (*pos == 'l')
155     {
156     if (whatt == MTYPE_ADD)
157     {
158     if (++parpos >= parc)
159     continue;
160     chan->modes |= CMODE_LIMIT;
161     newlimit = atoi (parv[parpos]);
162     if (chan->limit != newlimit)
163     simple_modes_changed = true;
164     chan->limit = newlimit;
165     if (source)
166     modestack_mode_limit (source->nick, chan, MTYPE_ADD, chan->limit);
167     }
168     else
169     {
170     chan->modes &= ~CMODE_LIMIT;
171     if (chan->limit != 0)
172     simple_modes_changed = true;
173     chan->limit = 0;
174     if (source)
175     modestack_mode_limit (source->nick, chan, MTYPE_DEL, 0);
176     }
177     continue;
178     }
179    
180     if (*pos == 'k')
181     {
182     if (whatt == MTYPE_ADD)
183     {
184     if (++parpos >= parc)
185     continue;
186     chan->modes |= CMODE_KEY;
187     if (chan->key)
188     {
189     if (strcmp (chan->key, parv[parpos]))
190     simple_modes_changed = true;
191 pippijn 1.4 sfree (chan->key);
192 pippijn 1.1 }
193     else
194     simple_modes_changed = true;
195     chan->key = sstrdup (parv[parpos]);
196     if (source)
197     modestack_mode_param (source->nick, chan, MTYPE_ADD, 'k', chan->key);
198     }
199     else
200     {
201     if (chan->key)
202     simple_modes_changed = true;
203     chan->modes &= ~CMODE_KEY;
204     if (source)
205     modestack_mode_param (source->nick, chan, MTYPE_DEL, 'k', chan->key ? chan->key : "*");
206 pippijn 1.4 sfree (chan->key);
207 pippijn 1.1 chan->key = NULL;
208     /* ratbox typically sends either the key or a `*' on -k, so you
209     * should eat a parameter
210     */
211     parpos++;
212     }
213     continue;
214     }
215    
216     if (strchr (ircd->ban_like_modes, *pos))
217     {
218     if (++parpos >= parc)
219     continue;
220     if (whatt == MTYPE_ADD)
221     {
222     chanban_add (chan, parv[parpos], *pos);
223     if (source)
224     modestack_mode_param (source->nick, chan, MTYPE_ADD, *pos, parv[parpos]);
225     }
226     else
227     {
228     chanban_t *c;
229    
230     c = chanban_find (chan, parv[parpos], *pos);
231     chanban_delete (c);
232     if (source)
233     modestack_mode_param (source->nick, chan, MTYPE_DEL, *pos, parv[parpos]);
234     }
235     continue;
236     }
237    
238     for (i = 0; status_mode_list[i].mode != '\0'; i++)
239     {
240     if (*pos == status_mode_list[i].mode)
241     {
242     if (++parpos >= parc)
243     break;
244     cu = chanuser_find (chan, source ? user_find_named (parv[parpos]) : user_find (parv[parpos]));
245    
246     if (cu == NULL)
247     {
248     slog (LG_ERROR, "channel_mode(): MODE %s %c%c %s", chan->name, (whatt == MTYPE_ADD) ? '+' : '-', status_mode_list[i].mode, parv[parpos]);
249     break;
250     }
251    
252     matched = true;
253    
254     if (whatt == MTYPE_ADD)
255     {
256     cu->modes |= status_mode_list[i].value;
257    
258     if (source)
259     modestack_mode_param (source->nick, chan, MTYPE_ADD, *pos, CLIENT_NAME (cu->user));
260    
261     /* see if they did something we have to undo */
262 pippijn 1.5 if (source == NULL && cu->user->server != me.me && chansvs.me != NULL && (mc = mychan_t::find (chan->name)) && mc->flags & MC_SECURE)
263 pippijn 1.1 {
264     if (status_mode_list[i].mode == 'o' && !(chanacs_user_flags (mc, cu->user) & (CA_OP | CA_AUTOOP)))
265     {
266     /* they were opped and aren't on the list, deop them */
267     modestack_mode_param (chansvs.nick, chan, MTYPE_DEL, 'o', CLIENT_NAME (cu->user));
268     cu->modes &= ~status_mode_list[i].value;
269     }
270     else if (ircd->uses_halfops && status_mode_list[i].mode == ircd->halfops_mchar[1] && !(chanacs_user_flags (mc, cu->user) & (CA_HALFOP | CA_AUTOHALFOP)))
271     {
272     /* same for halfops -- jilles */
273     modestack_mode_param (chansvs.nick, chan, MTYPE_DEL, ircd->halfops_mchar[1], CLIENT_NAME (cu->user));
274     cu->modes &= ~status_mode_list[i].value;
275     }
276     }
277     }
278     else
279     {
280     if (cu->user->server == me.me && status_mode_list[i].value == CMODE_OP)
281     {
282     if (source == NULL)
283     {
284     if (first_deopped_service == NULL)
285     {
286     if (chan->nummembers > 1)
287     {
288     slog (LG_DEBUG, "channel_mode(): %s deopped on %s, rejoining", cu->user->nick, chan->name);
289 pippijn 1.4 phandler->part_sts (chan, cu->user);
290     phandler->join_sts (chan, cu->user, false, channel_modes (chan, true));
291 pippijn 1.1 }
292     else
293     {
294     slog (LG_DEBUG, "channel_mode(): %s deopped on %s, opping from other service", cu->user->nick, chan->name);
295     LIST_FOREACH (n, me.me->userlist.head)
296     {
297     if (n->data != cu->user)
298     {
299     modestack_mode_param (((user_t *) n->data)->nick, chan, MTYPE_ADD, *pos, CLIENT_NAME (cu->user));
300     break;
301     }
302     }
303     }
304     first_deopped_service = cu->user;
305     }
306     else if (first_deopped_service != cu->user)
307     {
308     slog (LG_DEBUG, "channel_mode(): %s deopped on %s, opping from %s", cu->user->nick, chan->name, first_deopped_service->nick);
309     modestack_mode_param (first_deopped_service->nick, chan, MTYPE_ADD, *pos, CLIENT_NAME (cu->user));
310     }
311    
312     }
313    
314     continue;
315     }
316    
317     if (source)
318     modestack_mode_param (source->nick, chan, MTYPE_DEL, *pos, CLIENT_NAME (cu->user));
319    
320     cu->modes &= ~status_mode_list[i].value;
321     }
322    
323     break;
324     }
325     }
326     if (matched)
327     continue;
328    
329     slog (LG_DEBUG, "channel_mode(): mode %c not matched", *pos);
330     }
331    
332     if (source == NULL && chansvs.me != NULL)
333     {
334 pippijn 1.5 mc = mychan_t::find (chan->name);
335 pippijn 1.1 if (mc != NULL && (simple_modes_changed || (mc->flags & MC_MLOCK_CHECK)))
336     check_modes (mc, true);
337     }
338     }
339    
340 pippijn 1.4 void
341     channel_mode (user_t *source, channel_t *chan, char const * const arg)
342     {
343     char const * const parv[] = { arg };
344     channel_mode (source, chan, 1, parv);
345     }
346    
347 pippijn 1.1 /* like channel_mode() but parv array passed as varargs */
348     void
349 pippijn 1.4 channel_mode_va (user_t *source, channel_t *chan, int parc, char const * const parv0, ...)
350 pippijn 1.1 {
351 pippijn 1.4 char const *parv[255];
352 pippijn 1.1 int i;
353     va_list va;
354    
355     if (parc == 0)
356     return;
357     #if 0
358     if (parc > sizeof parv / sizeof *parv)
359     {
360     slog (LG_DEBUG, "channel_mode_va(): parc too big (%d), truncating", parc);
361     parc = sizeof parv / sizeof *parv;
362     }
363     #endif
364     parv[0] = parv0;
365     va_start (va, parv0);
366     for (i = 1; i < parc; i++)
367     parv[i] = va_arg (va, char *);
368     va_end (va);
369     channel_mode (source, chan, parc, parv);
370     }
371    
372     static struct modestackdata
373     {
374     char source[HOSTLEN]; /* name */
375     channel_t *channel;
376     int modes_on;
377     int modes_off;
378     unsigned int limit;
379     char extmodes[MAXEXTMODES][512];
380     bool limitused, extmodesused[MAXEXTMODES];
381     char pmodes[2 * MAXMODES + 2];
382     char params[512]; /* includes leading space */
383     int totalparamslen; /* includes leading space */
384     int totallen;
385     int paramcount;
386    
387     unsigned int event;
388     } modestackdata;
389    
390     static void modestack_calclen (struct modestackdata *md);
391    
392     static void
393     modestack_debugprint (struct modestackdata *md)
394     {
395     int i;
396    
397     slog (LG_DEBUG, "modestack_debugprint(): %s MODE %s", md->source, md->channel->name);
398     slog (LG_DEBUG, "simple %x/%x", md->modes_on, md->modes_off);
399     if (md->limitused)
400     slog (LG_DEBUG, "limit %u", (unsigned) md->limit);
401     for (i = 0; i < MAXEXTMODES; i++)
402     if (md->extmodesused[i])
403     slog (LG_DEBUG, "ext %d %s", i, md->extmodes[i]);
404     slog (LG_DEBUG, "pmodes %s%s", md->pmodes, md->params);
405     modestack_calclen (md);
406     slog (LG_DEBUG, "totallen %d/%d", md->totalparamslen, md->totallen);
407     }
408    
409     /* calculates the length fields */
410     static void
411     modestack_calclen (struct modestackdata *md)
412     {
413     int i;
414 pippijn 1.4 char const *p;
415 pippijn 1.1
416     md->totallen = strlen (md->source) + USERLEN + HOSTLEN + 1 + 4 + 1 + 10 + strlen (md->channel->name) + 1;
417     md->totallen += 2 + 32 + strlen (md->pmodes);
418     md->totalparamslen = 0;
419     md->paramcount = (md->limitused != 0);
420     if (md->limitused && md->limit != 0)
421     md->totalparamslen += 11;
422     for (i = 0; i < MAXEXTMODES; i++)
423     if (md->extmodesused[i])
424     {
425     md->paramcount++;
426     if (*md->extmodes[i] != '\0')
427     md->totalparamslen += 1 + strlen (md->extmodes[i]);
428     }
429     md->totalparamslen += strlen (md->params);
430     p = md->params;
431     while (*p != '\0')
432     if (*p++ == ' ')
433     md->paramcount++;
434     md->totallen += md->totalparamslen;
435     }
436    
437     /* clears the data */
438     static void
439     modestack_clear (struct modestackdata *md)
440     {
441     int i;
442    
443     md->modes_on = 0;
444     md->modes_off = 0;
445     md->limitused = 0;
446     for (i = 0; i < MAXEXTMODES; i++)
447     md->extmodesused[i] = 0, *md->extmodes[i] = '\0';
448     md->pmodes[0] = '\0';
449     md->params[0] = '\0';
450     md->totallen = 0;
451     md->totalparamslen = 0;
452     md->paramcount = 0;
453     }
454    
455     /* sends a MODE and clears the data */
456     static void
457     modestack_flush (struct modestackdata *md)
458     {
459     char buf[512];
460     char *end, *p;
461 pippijn 1.6 mtype dir = MTYPE_NUL;
462 pippijn 1.1 int i;
463    
464     p = buf;
465     end = buf + sizeof buf;
466    
467     /* first do the mode letters */
468     if (md->modes_off)
469     {
470     if (dir != MTYPE_DEL)
471     dir = MTYPE_DEL, *p++ = '-';
472     strlcpy (p, flags_to_string (md->modes_off), end - p);
473     p += strlen (p);
474     }
475     if (md->limitused && md->limit == 0)
476     {
477     if (dir != MTYPE_DEL)
478     dir = MTYPE_DEL, *p++ = '-';
479     *p++ = 'l';
480     }
481     for (i = 0; i < MAXEXTMODES; i++)
482     {
483     if (md->extmodesused[i] && *md->extmodes[i] == '\0')
484     {
485     if (dir != MTYPE_DEL)
486     dir = MTYPE_DEL, *p++ = '-';
487     *p++ = ignore_mode_list[i].mode;
488     }
489     }
490     if (md->modes_on)
491     {
492     if (dir != MTYPE_ADD)
493     dir = MTYPE_ADD, *p++ = '+';
494     strlcpy (p, flags_to_string (md->modes_on), end - p);
495     p += strlen (p);
496     }
497     if (md->limitused && md->limit != 0)
498     {
499     if (dir != MTYPE_ADD)
500     dir = MTYPE_ADD, *p++ = '+';
501     *p++ = 'l';
502     }
503     for (i = 0; i < MAXEXTMODES; i++)
504     {
505     if (md->extmodesused[i] && *md->extmodes[i] != '\0')
506     {
507     if (dir != MTYPE_ADD)
508     dir = MTYPE_ADD, *p++ = '+';
509     *p++ = ignore_mode_list[i].mode;
510     }
511     }
512     strlcpy (p, md->pmodes + ((dir == MTYPE_ADD && *md->pmodes == '+') || (dir == MTYPE_DEL && *md->pmodes == '-') ? 1 : 0), end - p);
513     p += strlen (p);
514    
515     /* all mode letters done, now for some checks */
516     if (p == buf)
517     {
518     /*slog(LG_DEBUG, "modestack_flush(): nothing to do"); */
519     return;
520     }
521     if (p + md->totalparamslen >= end)
522     {
523     slog (LG_ERROR, "modestack_flush() overflow: %s", buf);
524     modestack_debugprint (md);
525     modestack_clear (md);
526     return;
527     }
528    
529     /* now the parameters, in the same order */
530     if (md->limitused && md->limit != 0)
531     {
532     snprintf (p, end - p, " %u", (unsigned) md->limit);
533     p += strlen (p);
534     }
535     for (i = 0; i < MAXEXTMODES; i++)
536     {
537     if (md->extmodesused[i] && *md->extmodes[i] != '\0')
538     {
539     snprintf (p, end - p, " %s", md->extmodes[i]);
540     p += strlen (p);
541     }
542     }
543     if (*md->params)
544     {
545     strlcpy (p, md->params, end - p);
546     p += strlen (p);
547     }
548 pippijn 1.4 phandler->mode_sts (md->source, md->channel, buf);
549 pippijn 1.1 modestack_clear (md);
550     }
551    
552     static struct modestackdata *
553     modestack_init (char *source, channel_t *channel)
554     {
555     if (irccasecmp (source, modestackdata.source) || channel != modestackdata.channel)
556     {
557     /*slog(LG_DEBUG, "modestack_init(): new source/channel, flushing"); */
558     modestack_flush (&modestackdata);
559     }
560     strlcpy (modestackdata.source, source, sizeof modestackdata.source);
561     modestackdata.channel = channel;
562     return &modestackdata;
563     }
564    
565     static void
566 pippijn 1.6 modestack_add_simple (struct modestackdata *md, mtype dir, int flags)
567 pippijn 1.1 {
568     if (dir == MTYPE_ADD)
569     md->modes_on |= flags, md->modes_off &= ~flags;
570     else if (dir == MTYPE_DEL)
571     md->modes_off |= flags, md->modes_on &= ~flags;
572     else
573     slog (LG_ERROR, "modestack_add_simple(): invalid direction");
574     }
575    
576     static void
577 pippijn 1.6 modestack_add_limit (struct modestackdata *md, mtype dir, unsigned int limit)
578 pippijn 1.1 {
579     md->limitused = 0;
580     modestack_calclen (md);
581     if (md->paramcount >= MAXMODES)
582     modestack_flush (md);
583     if (dir == MTYPE_ADD)
584     {
585     if (md->totallen + 11 > 512)
586     modestack_flush (md);
587     md->limit = limit;
588     }
589     else if (dir == MTYPE_DEL)
590     md->limit = 0;
591     else
592     slog (LG_ERROR, "modestack_add_limit(): invalid direction");
593     md->limitused = 1;
594     }
595    
596     static void
597 pippijn 1.6 modestack_add_ext (struct modestackdata *md, mtype dir, int i, char const * const value)
598 pippijn 1.1 {
599     md->extmodesused[i] = 0;
600     modestack_calclen (md);
601     if (md->paramcount >= MAXMODES)
602     modestack_flush (md);
603     if (dir == MTYPE_ADD)
604     {
605     if (md->totallen + 1 + strlen (value) > 512)
606     modestack_flush (md);
607     strlcpy (md->extmodes[i], value, sizeof md->extmodes[i]);
608     }
609     else if (dir == MTYPE_DEL)
610     md->extmodes[i][0] = '\0';
611     else
612     slog (LG_ERROR, "modestack_add_ext(): invalid direction");
613     md->extmodesused[i] = 1;
614     }
615    
616     static void
617 pippijn 1.6 modestack_add_param (struct modestackdata *md, mtype dir, char type, char const * const value)
618 pippijn 1.1 {
619     char *p;
620     int n = 0, i;
621     char dir2 = MTYPE_NUL;
622     char str[3];
623    
624     p = md->pmodes;
625     while (*p != '\0')
626     {
627     if (*p == '+')
628     dir2 = MTYPE_ADD;
629     else if (*p == '-')
630     dir2 = MTYPE_DEL;
631     else
632     n++;
633     p++;
634     }
635     n += (md->limitused != 0);
636     for (i = 0; i < MAXEXTMODES; i++)
637     n += (md->extmodesused[i] != 0);
638     modestack_calclen (md);
639     if (n >= MAXMODES || md->totallen + (dir != dir2) + 2 + strlen (value) > 512 || (type == 'k' && strchr (md->pmodes, 'k')))
640     {
641     modestack_flush (md);
642     dir2 = MTYPE_NUL;
643     }
644     if (dir != dir2)
645     {
646     str[0] = dir == MTYPE_ADD ? '+' : '-';
647     str[1] = type;
648     str[2] = '\0';
649     }
650     else
651     {
652     str[0] = type;
653     str[1] = '\0';
654     }
655     strlcat (md->pmodes, str, sizeof md->pmodes);
656     strlcat (md->params, " ", sizeof md->params);
657     strlcat (md->params, value, sizeof md->params);
658     }
659    
660     static void
661     modestack_flush_callback (void *arg)
662     {
663     modestack_flush ((struct modestackdata *) arg);
664     ((struct modestackdata *) arg)->event = 0;
665     }
666    
667     /* flush pending modes for a certain channel */
668     void
669     modestack_flush_channel (channel_t *channel)
670     {
671     if (channel == NULL || channel == modestackdata.channel)
672     modestack_flush (&modestackdata);
673     }
674    
675     /* forget pending modes for a certain channel */
676     void
677     modestack_forget_channel (channel_t *channel)
678     {
679     if (channel == NULL || channel == modestackdata.channel)
680     modestack_clear (&modestackdata);
681     }
682    
683     /* handle a channel that is going to be destroyed */
684     void
685     modestack_finalize_channel (channel_t *channel)
686     {
687     user_t *u;
688    
689     if (channel == modestackdata.channel)
690     {
691     if (modestackdata.modes_off & ircd->perm_mode)
692     {
693     /* A mode change is not a good way to destroy a channel */
694     slog (LG_DEBUG, "modestack_finalize_channel(): flushing modes for %s to clear perm mode", channel->name);
695     u = user_find_named (modestackdata.source);
696     if (u != NULL)
697 pippijn 1.4 phandler->join_sts (channel, u, false, channel_modes (channel, true));
698 pippijn 1.1 modestack_flush (&modestackdata);
699     if (u != NULL)
700 pippijn 1.4 phandler->part_sts (channel, u);
701 pippijn 1.1 }
702     else
703     modestack_clear (&modestackdata);
704     }
705     }
706    
707     /* stack simple modes without parameters */
708     void
709 pippijn 1.6 modestack_mode_simple (char *source, channel_t *channel, mtype dir, int flags)
710 pippijn 1.1 {
711     struct modestackdata *md;
712    
713     if (flags == 0)
714     return;
715     md = modestack_init (source, channel);
716     modestack_add_simple (md, dir, flags);
717     if (!md->event)
718     md->event = event_add_once ("flush_cmode_callback", modestack_flush_callback, md, 0);
719     }
720    
721     /* stack a limit */
722     void
723 pippijn 1.6 modestack_mode_limit (char *source, channel_t *channel, mtype dir, unsigned int limit)
724 pippijn 1.1 {
725     struct modestackdata *md;
726    
727     md = modestack_init (source, channel);
728     modestack_add_limit (md, dir, limit);
729     if (!md->event)
730     md->event = event_add_once ("flush_cmode_callback", modestack_flush_callback, md, 0);
731     }
732    
733     /* stack a non-standard type C mode */
734     void
735 pippijn 1.6 modestack_mode_ext (char *source, channel_t *channel, mtype dir, int i, char const * const value)
736 pippijn 1.1 {
737     struct modestackdata *md;
738    
739     md = modestack_init (source, channel);
740     if (i < 0 || i >= MAXEXTMODES)
741     {
742     slog (LG_ERROR, "modestack_mode_ext(): i=%d out of range (value=\"%s\")", i, value);
743     return;
744     }
745     modestack_add_ext (md, dir, i, value);
746     if (!md->event)
747     md->event = event_add_once ("flush_cmode_callback", modestack_flush_callback, md, 0);
748     }
749    
750     /* stack a type A, B or E mode */
751     void
752 pippijn 1.6 modestack_mode_param (char *source, channel_t *channel, mtype dir, char type, char const * const value)
753 pippijn 1.1 {
754     struct modestackdata *md;
755    
756     md = modestack_init (source, channel);
757     modestack_add_param (md, dir, type, value);
758     if (!md->event)
759     md->event = event_add_once ("flush_cmode_callback", modestack_flush_callback, md, 0);
760     }
761    
762     /* Clear all simple modes (+imnpstkl etc) on a channel */
763     void
764     clear_simple_modes (channel_t *c)
765     {
766     int i;
767    
768     if (c == NULL)
769     return;
770     c->modes = 0;
771     c->limit = 0;
772     if (c->key != NULL)
773 pippijn 1.4 sfree (c->key);
774 pippijn 1.1 c->key = NULL;
775     for (i = 0; i < MAXEXTMODES; i++)
776     if (c->extmodes[i] != NULL)
777     {
778 pippijn 1.4 sfree (c->extmodes[i]);
779 pippijn 1.1 c->extmodes[i] = NULL;
780     }
781     }
782    
783     char *
784     channel_modes (channel_t *c, bool doparams)
785     {
786     static char fullmode[512];
787     char params[512];
788     int i;
789     char *p;
790     char *q;
791    
792     if (c == NULL)
793     return NULL;
794    
795     p = fullmode;
796     q = params;
797     *p++ = '+';
798     *q = '\0';
799     for (i = 0; mode_list[i].mode != '\0'; i++)
800     {
801     if (c->modes & mode_list[i].value)
802     *p++ = mode_list[i].mode;
803     }
804     if (c->limit)
805     {
806     *p++ = 'l';
807     if (doparams)
808     {
809     snprintf (q, params + sizeof params - q, " %d", c->limit);
810     q += strlen (q);
811     }
812     }
813     if (c->key)
814     {
815     *p++ = 'k';
816     if (doparams)
817     {
818     *q++ = ' ';
819     strlcpy (q, c->key, params + sizeof params - q);
820     q += strlen (q);
821     }
822     }
823     for (i = 0; ignore_mode_list[i].mode != '\0'; i++)
824     {
825     if (c->extmodes[i] != NULL)
826     {
827     *p++ = ignore_mode_list[i].mode;
828     if (doparams)
829     {
830     *q++ = ' ';
831     strlcpy (q, c->extmodes[i], params + sizeof params - q);
832     q += strlen (q);
833     }
834     }
835     }
836     strlcpy (p, params, fullmode + sizeof fullmode - p);
837     return fullmode;
838     }
839    
840     void
841     check_modes (mychan_t *mychan, bool sendnow)
842     {
843     int modes;
844     int i;
845 pippijn 1.6 metadata *md;
846 pippijn 1.1 char *p, *q;
847     char str2[512];
848 pippijn 1.5
849 pippijn 1.1 if (!mychan || !mychan->chan)
850     return;
851     mychan->flags &= ~MC_MLOCK_CHECK;
852    
853     /* check what's locked on */
854     modes = ~mychan->chan->modes & mychan->mlock_on;
855     modes &= ~(CMODE_KEY | CMODE_LIMIT);
856     if (sendnow)
857     modestack_mode_simple (chansvs.nick, mychan->chan, MTYPE_ADD, modes);
858     mychan->chan->modes |= modes;
859    
860     if (mychan->mlock_limit && mychan->mlock_limit != mychan->chan->limit)
861     {
862     mychan->chan->limit = mychan->mlock_limit;
863     if (sendnow)
864     modestack_mode_limit (chansvs.nick, mychan->chan, MTYPE_ADD, mychan->mlock_limit);
865     }
866    
867     if (mychan->mlock_key)
868     {
869     if (mychan->chan->key && strcmp (mychan->chan->key, mychan->mlock_key))
870     {
871     /* some ircds still need this... :\ -- jilles */
872     if (sendnow)
873     modestack_mode_param (chansvs.nick, mychan->chan, MTYPE_DEL, 'k', mychan->chan->key);
874 pippijn 1.4 sfree (mychan->chan->key);
875 pippijn 1.1 mychan->chan->key = NULL;
876     }
877    
878     if (mychan->chan->key == NULL)
879     {
880     mychan->chan->key = sstrdup (mychan->mlock_key);
881     if (sendnow)
882     modestack_mode_param (chansvs.nick, mychan->chan, MTYPE_ADD, 'k', mychan->mlock_key);
883     }
884     }
885    
886     /* check what's locked off */
887     modes = mychan->chan->modes & mychan->mlock_off;
888     modes &= ~(CMODE_KEY | CMODE_LIMIT);
889     if (sendnow)
890     modestack_mode_simple (chansvs.nick, mychan->chan, MTYPE_DEL, modes);
891     mychan->chan->modes &= ~modes;
892    
893     if (mychan->chan->limit && (mychan->mlock_off & CMODE_LIMIT))
894     {
895     if (sendnow)
896     modestack_mode_limit (chansvs.nick, mychan->chan, MTYPE_DEL, 0);
897     mychan->chan->limit = 0;
898     }
899    
900     if (mychan->chan->key && (mychan->mlock_off & CMODE_KEY))
901     {
902     if (sendnow)
903     modestack_mode_param (chansvs.nick, mychan->chan, MTYPE_DEL, 'k', mychan->chan->key);
904 pippijn 1.4 sfree (mychan->chan->key);
905 pippijn 1.1 mychan->chan->key = NULL;
906     }
907    
908     /* non-standard type C modes separately */
909     md = mychan->find_metadata ("private:mlockext");
910     if (md != NULL)
911     {
912     p = md->value;
913     while (*p != '\0')
914     {
915     for (i = 0; ignore_mode_list[i].mode != '\0'; i++)
916     {
917     if (ignore_mode_list[i].mode == *p)
918     {
919     if ((p[1] == ' ' || p[1] == '\0') && mychan->chan->extmodes[i] != NULL)
920     {
921 pippijn 1.4 sfree (mychan->chan->extmodes[i]);
922 pippijn 1.1 mychan->chan->extmodes[i] = NULL;
923     if (sendnow)
924     modestack_mode_ext (chansvs.nick, mychan->chan, MTYPE_DEL, i, NULL);
925     }
926     else if (p[1] != ' ' && p[1] != '\0')
927     {
928     strlcpy (str2, p + 1, sizeof str2);
929     q = strchr (str2, ' ');
930     if (q != NULL)
931     *q = '\0';
932     if ((mychan->chan->extmodes[i] == NULL || strcmp (mychan->chan->extmodes[i], str2)) && ignore_mode_list[i].check (str2, mychan->chan, mychan, NULL, NULL))
933     {
934     if (mychan->chan->extmodes[i] != NULL)
935 pippijn 1.4 sfree (mychan->chan->extmodes[i]);
936 pippijn 1.1 mychan->chan->extmodes[i] = sstrdup (str2);
937     if (sendnow)
938     modestack_mode_ext (chansvs.nick, mychan->chan, MTYPE_ADD, i, mychan->chan->extmodes[i]);
939     }
940     }
941     }
942     }
943     while (*p != ' ' && *p != '\0')
944     p++;
945     while (*p == ' ')
946     p++;
947     }
948     }
949    
950     }
951    
952     /* vim:cinoptions=>s,e0,n0,f0,{0,}0,^0,=s,ps,t0,c3,+s,(2s,us,)20,*30,gs,hs
953     * vim:ts=8
954     * vim:sw=8
955     * vim:noexpandtab
956     */