ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/ermyth/src/cmode.C
Revision: 1.3
Committed: Sat Jul 21 13:23:21 2007 UTC (16 years, 10 months ago) by pippijn
Content type: text/plain
Branch: MAIN
Changes since 1.2: +1 -1 lines
Log Message:
- added rcsid to some files
- more documentation tweaks
- made most protocol commands local to phandler.C
- added ircd metadata (inspircd only for now)
- added inspircd swhois support

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