ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/ermyth/src/cmode.C
Revision: 1.6
Committed: Wed Sep 5 11:23:15 2007 UTC (16 years, 8 months ago) by pippijn
Content type: text/plain
Branch: MAIN
Changes since 1.5: +13 -12 lines
Log Message:
removed GPLed code and put license back to BSD

File Contents

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