1 | /* |
1 | /* |
2 | * cmode.C: Channel mode change tracking. |
2 | * cmode.C: Channel mode change tracking. |
3 | * Rights to this code are documented in doc/pod/license.pod. |
3 | * Rights to this code are documented in doc/pod/license.pod. |
4 | * |
4 | * |
5 | * Copyright © 2005-2007 Atheme Project (http://www.atheme.org) |
5 | * Copyright © 2005-2007 Atheme Project (http://www.atheme.org) |
6 | */ |
6 | */ |
7 | |
7 | |
8 | static char const rcsid[] = "$Id: cmode.C,v 1.3 2007/07/21 13:23:21 pippijn Exp $"; |
8 | static char const rcsid[] = "$Id: cmode.C,v 1.4 2007/08/28 17:08:12 pippijn Exp $"; |
9 | |
9 | |
10 | #include "atheme.h" |
10 | #include "atheme.h" |
11 | #include <account/chanacs.h> |
11 | #include <account/chanacs.h> |
12 | #include <account/mychan.h> |
12 | #include <account/mychan.h> |
13 | |
13 | |
… | |
… | |
42 | /* yeah, this should be fun. */ |
42 | /* yeah, this should be fun. */ |
43 | /* If source == NULL, apply a mode change from outside to our structures |
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 |
44 | * If source != NULL, apply the mode change and send it out from that user |
45 | */ |
45 | */ |
46 | void |
46 | void |
47 | channel_mode (user_t *source, channel_t *chan, int parc, char *parv[]) |
47 | channel_mode (user_t *source, channel_t *chan, int parc, char const * const parv[]) |
48 | { |
48 | { |
49 | bool matched = false; |
49 | bool matched = false; |
50 | bool simple_modes_changed = false; |
50 | bool simple_modes_changed = false; |
51 | int i, parpos = 0, whatt = MTYPE_NUL; |
51 | int i, parpos = 0, whatt = MTYPE_NUL; |
52 | unsigned int newlimit; |
52 | unsigned int newlimit; |
53 | const char *pos = parv[0]; |
53 | char const *pos = parv[0]; |
54 | mychan_t *mc; |
54 | mychan_t *mc; |
55 | chanuser_t *cu = NULL; |
55 | chanuser_t *cu = NULL; |
56 | user_t *first_deopped_service = NULL; |
56 | user_t *first_deopped_service = NULL; |
57 | node_t *n; |
57 | node_t *n; |
58 | |
58 | |
… | |
… | |
122 | break; |
122 | break; |
123 | if (chan->extmodes[i]) |
123 | if (chan->extmodes[i]) |
124 | { |
124 | { |
125 | if (strcmp (chan->extmodes[i], parv[parpos])) |
125 | if (strcmp (chan->extmodes[i], parv[parpos])) |
126 | simple_modes_changed = true; |
126 | simple_modes_changed = true; |
127 | free (chan->extmodes[i]); |
127 | sfree (chan->extmodes[i]); |
128 | } |
128 | } |
129 | else |
129 | else |
130 | simple_modes_changed = true; |
130 | simple_modes_changed = true; |
131 | chan->extmodes[i] = sstrdup (parv[parpos]); |
131 | chan->extmodes[i] = sstrdup (parv[parpos]); |
132 | if (source) |
132 | if (source) |
… | |
… | |
135 | else |
135 | else |
136 | { |
136 | { |
137 | if (chan->extmodes[i]) |
137 | if (chan->extmodes[i]) |
138 | { |
138 | { |
139 | simple_modes_changed = true; |
139 | simple_modes_changed = true; |
140 | free (chan->extmodes[i]); |
140 | sfree (chan->extmodes[i]); |
141 | chan->extmodes[i] = NULL; |
141 | chan->extmodes[i] = NULL; |
142 | } |
142 | } |
143 | if (source) |
143 | if (source) |
144 | modestack_mode_ext (source->nick, chan, MTYPE_DEL, i, NULL); |
144 | modestack_mode_ext (source->nick, chan, MTYPE_DEL, i, NULL); |
145 | } |
145 | } |
… | |
… | |
184 | chan->modes |= CMODE_KEY; |
184 | chan->modes |= CMODE_KEY; |
185 | if (chan->key) |
185 | if (chan->key) |
186 | { |
186 | { |
187 | if (strcmp (chan->key, parv[parpos])) |
187 | if (strcmp (chan->key, parv[parpos])) |
188 | simple_modes_changed = true; |
188 | simple_modes_changed = true; |
189 | free (chan->key); |
189 | sfree (chan->key); |
190 | } |
190 | } |
191 | else |
191 | else |
192 | simple_modes_changed = true; |
192 | simple_modes_changed = true; |
193 | chan->key = sstrdup (parv[parpos]); |
193 | chan->key = sstrdup (parv[parpos]); |
194 | if (source) |
194 | if (source) |
… | |
… | |
199 | if (chan->key) |
199 | if (chan->key) |
200 | simple_modes_changed = true; |
200 | simple_modes_changed = true; |
201 | chan->modes &= ~CMODE_KEY; |
201 | chan->modes &= ~CMODE_KEY; |
202 | if (source) |
202 | if (source) |
203 | modestack_mode_param (source->nick, chan, MTYPE_DEL, 'k', chan->key ? chan->key : "*"); |
203 | modestack_mode_param (source->nick, chan, MTYPE_DEL, 'k', chan->key ? chan->key : "*"); |
204 | free (chan->key); |
204 | sfree (chan->key); |
205 | chan->key = NULL; |
205 | chan->key = NULL; |
206 | /* ratbox typically sends either the key or a `*' on -k, so you |
206 | /* ratbox typically sends either the key or a `*' on -k, so you |
207 | * should eat a parameter |
207 | * should eat a parameter |
208 | */ |
208 | */ |
209 | parpos++; |
209 | parpos++; |
… | |
… | |
282 | if (first_deopped_service == NULL) |
282 | if (first_deopped_service == NULL) |
283 | { |
283 | { |
284 | if (chan->nummembers > 1) |
284 | if (chan->nummembers > 1) |
285 | { |
285 | { |
286 | slog (LG_DEBUG, "channel_mode(): %s deopped on %s, rejoining", cu->user->nick, chan->name); |
286 | slog (LG_DEBUG, "channel_mode(): %s deopped on %s, rejoining", cu->user->nick, chan->name); |
287 | part_sts (chan, cu->user); |
287 | phandler->part_sts (chan, cu->user); |
288 | join_sts (chan, cu->user, false, channel_modes (chan, true)); |
288 | phandler->join_sts (chan, cu->user, false, channel_modes (chan, true)); |
289 | } |
289 | } |
290 | else |
290 | else |
291 | { |
291 | { |
292 | slog (LG_DEBUG, "channel_mode(): %s deopped on %s, opping from other service", cu->user->nick, chan->name); |
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) |
293 | LIST_FOREACH (n, me.me->userlist.head) |
… | |
… | |
333 | if (mc != NULL && (simple_modes_changed || (mc->flags & MC_MLOCK_CHECK))) |
333 | if (mc != NULL && (simple_modes_changed || (mc->flags & MC_MLOCK_CHECK))) |
334 | check_modes (mc, true); |
334 | check_modes (mc, true); |
335 | } |
335 | } |
336 | } |
336 | } |
337 | |
337 | |
|
|
338 | void |
|
|
339 | channel_mode (user_t *source, channel_t *chan, char const * const arg) |
|
|
340 | { |
|
|
341 | char const * const parv[] = { arg }; |
|
|
342 | channel_mode (source, chan, 1, parv); |
|
|
343 | } |
|
|
344 | |
338 | /* like channel_mode() but parv array passed as varargs */ |
345 | /* like channel_mode() but parv array passed as varargs */ |
339 | void |
346 | void |
340 | channel_mode_va (user_t *source, channel_t *chan, int parc, char *parv0, ...) |
347 | channel_mode_va (user_t *source, channel_t *chan, int parc, char const * const parv0, ...) |
341 | { |
348 | { |
342 | char *parv[255]; |
349 | char const *parv[255]; |
343 | int i; |
350 | int i; |
344 | va_list va; |
351 | va_list va; |
345 | |
352 | |
346 | if (parc == 0) |
353 | if (parc == 0) |
347 | return; |
354 | return; |
… | |
… | |
400 | /* calculates the length fields */ |
407 | /* calculates the length fields */ |
401 | static void |
408 | static void |
402 | modestack_calclen (struct modestackdata *md) |
409 | modestack_calclen (struct modestackdata *md) |
403 | { |
410 | { |
404 | int i; |
411 | int i; |
405 | const char *p; |
412 | char const *p; |
406 | |
413 | |
407 | md->totallen = strlen (md->source) + USERLEN + HOSTLEN + 1 + 4 + 1 + 10 + strlen (md->channel->name) + 1; |
414 | md->totallen = strlen (md->source) + USERLEN + HOSTLEN + 1 + 4 + 1 + 10 + strlen (md->channel->name) + 1; |
408 | md->totallen += 2 + 32 + strlen (md->pmodes); |
415 | md->totallen += 2 + 32 + strlen (md->pmodes); |
409 | md->totalparamslen = 0; |
416 | md->totalparamslen = 0; |
410 | md->paramcount = (md->limitused != 0); |
417 | md->paramcount = (md->limitused != 0); |
… | |
… | |
534 | if (*md->params) |
541 | if (*md->params) |
535 | { |
542 | { |
536 | strlcpy (p, md->params, end - p); |
543 | strlcpy (p, md->params, end - p); |
537 | p += strlen (p); |
544 | p += strlen (p); |
538 | } |
545 | } |
539 | mode_sts (md->source, md->channel, buf); |
546 | phandler->mode_sts (md->source, md->channel, buf); |
540 | modestack_clear (md); |
547 | modestack_clear (md); |
541 | } |
548 | } |
542 | |
549 | |
543 | static struct modestackdata * |
550 | static struct modestackdata * |
544 | modestack_init (char *source, channel_t *channel) |
551 | modestack_init (char *source, channel_t *channel) |
… | |
… | |
583 | slog (LG_ERROR, "modestack_add_limit(): invalid direction"); |
590 | slog (LG_ERROR, "modestack_add_limit(): invalid direction"); |
584 | md->limitused = 1; |
591 | md->limitused = 1; |
585 | } |
592 | } |
586 | |
593 | |
587 | static void |
594 | static void |
588 | modestack_add_ext (struct modestackdata *md, int dir, int i, const char *value) |
595 | modestack_add_ext (struct modestackdata *md, int dir, int i, char const * const value) |
589 | { |
596 | { |
590 | md->extmodesused[i] = 0; |
597 | md->extmodesused[i] = 0; |
591 | modestack_calclen (md); |
598 | modestack_calclen (md); |
592 | if (md->paramcount >= MAXMODES) |
599 | if (md->paramcount >= MAXMODES) |
593 | modestack_flush (md); |
600 | modestack_flush (md); |
… | |
… | |
603 | slog (LG_ERROR, "modestack_add_ext(): invalid direction"); |
610 | slog (LG_ERROR, "modestack_add_ext(): invalid direction"); |
604 | md->extmodesused[i] = 1; |
611 | md->extmodesused[i] = 1; |
605 | } |
612 | } |
606 | |
613 | |
607 | static void |
614 | static void |
608 | modestack_add_param (struct modestackdata *md, int dir, char type, const char *value) |
615 | modestack_add_param (struct modestackdata *md, int dir, char type, char const * const value) |
609 | { |
616 | { |
610 | char *p; |
617 | char *p; |
611 | int n = 0, i; |
618 | int n = 0, i; |
612 | char dir2 = MTYPE_NUL; |
619 | char dir2 = MTYPE_NUL; |
613 | char str[3]; |
620 | char str[3]; |
… | |
… | |
683 | { |
690 | { |
684 | /* A mode change is not a good way to destroy a channel */ |
691 | /* 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); |
692 | slog (LG_DEBUG, "modestack_finalize_channel(): flushing modes for %s to clear perm mode", channel->name); |
686 | u = user_find_named (modestackdata.source); |
693 | u = user_find_named (modestackdata.source); |
687 | if (u != NULL) |
694 | if (u != NULL) |
688 | join_sts (channel, u, false, channel_modes (channel, true)); |
695 | phandler->join_sts (channel, u, false, channel_modes (channel, true)); |
689 | modestack_flush (&modestackdata); |
696 | modestack_flush (&modestackdata); |
690 | if (u != NULL) |
697 | if (u != NULL) |
691 | part_sts (channel, u); |
698 | phandler->part_sts (channel, u); |
692 | } |
699 | } |
693 | else |
700 | else |
694 | modestack_clear (&modestackdata); |
701 | modestack_clear (&modestackdata); |
695 | } |
702 | } |
696 | } |
703 | } |
… | |
… | |
721 | md->event = event_add_once ("flush_cmode_callback", modestack_flush_callback, md, 0); |
728 | md->event = event_add_once ("flush_cmode_callback", modestack_flush_callback, md, 0); |
722 | } |
729 | } |
723 | |
730 | |
724 | /* stack a non-standard type C mode */ |
731 | /* stack a non-standard type C mode */ |
725 | void |
732 | void |
726 | modestack_mode_ext (char *source, channel_t *channel, int dir, int i, const char *value) |
733 | modestack_mode_ext (char *source, channel_t *channel, int dir, int i, char const * const value) |
727 | { |
734 | { |
728 | struct modestackdata *md; |
735 | struct modestackdata *md; |
729 | |
736 | |
730 | md = modestack_init (source, channel); |
737 | md = modestack_init (source, channel); |
731 | if (i < 0 || i >= MAXEXTMODES) |
738 | if (i < 0 || i >= MAXEXTMODES) |
… | |
… | |
738 | md->event = event_add_once ("flush_cmode_callback", modestack_flush_callback, md, 0); |
745 | md->event = event_add_once ("flush_cmode_callback", modestack_flush_callback, md, 0); |
739 | } |
746 | } |
740 | |
747 | |
741 | /* stack a type A, B or E mode */ |
748 | /* stack a type A, B or E mode */ |
742 | void |
749 | void |
743 | modestack_mode_param (char *source, channel_t *channel, int dir, char type, const char *value) |
750 | modestack_mode_param (char *source, channel_t *channel, int dir, char type, char const * const value) |
744 | { |
751 | { |
745 | struct modestackdata *md; |
752 | struct modestackdata *md; |
746 | |
753 | |
747 | md = modestack_init (source, channel); |
754 | md = modestack_init (source, channel); |
748 | modestack_add_param (md, dir, type, value); |
755 | modestack_add_param (md, dir, type, value); |
… | |
… | |
759 | if (c == NULL) |
766 | if (c == NULL) |
760 | return; |
767 | return; |
761 | c->modes = 0; |
768 | c->modes = 0; |
762 | c->limit = 0; |
769 | c->limit = 0; |
763 | if (c->key != NULL) |
770 | if (c->key != NULL) |
764 | free (c->key); |
771 | sfree (c->key); |
765 | c->key = NULL; |
772 | c->key = NULL; |
766 | for (i = 0; i < MAXEXTMODES; i++) |
773 | for (i = 0; i < MAXEXTMODES; i++) |
767 | if (c->extmodes[i] != NULL) |
774 | if (c->extmodes[i] != NULL) |
768 | { |
775 | { |
769 | free (c->extmodes[i]); |
776 | sfree (c->extmodes[i]); |
770 | c->extmodes[i] = NULL; |
777 | c->extmodes[i] = NULL; |
771 | } |
778 | } |
772 | } |
779 | } |
773 | |
780 | |
774 | char * |
781 | char * |
… | |
… | |
860 | if (mychan->chan->key && strcmp (mychan->chan->key, mychan->mlock_key)) |
867 | if (mychan->chan->key && strcmp (mychan->chan->key, mychan->mlock_key)) |
861 | { |
868 | { |
862 | /* some ircds still need this... :\ -- jilles */ |
869 | /* some ircds still need this... :\ -- jilles */ |
863 | if (sendnow) |
870 | if (sendnow) |
864 | modestack_mode_param (chansvs.nick, mychan->chan, MTYPE_DEL, 'k', mychan->chan->key); |
871 | modestack_mode_param (chansvs.nick, mychan->chan, MTYPE_DEL, 'k', mychan->chan->key); |
865 | free (mychan->chan->key); |
872 | sfree (mychan->chan->key); |
866 | mychan->chan->key = NULL; |
873 | mychan->chan->key = NULL; |
867 | } |
874 | } |
868 | |
875 | |
869 | if (mychan->chan->key == NULL) |
876 | if (mychan->chan->key == NULL) |
870 | { |
877 | { |
… | |
… | |
890 | |
897 | |
891 | if (mychan->chan->key && (mychan->mlock_off & CMODE_KEY)) |
898 | if (mychan->chan->key && (mychan->mlock_off & CMODE_KEY)) |
892 | { |
899 | { |
893 | if (sendnow) |
900 | if (sendnow) |
894 | modestack_mode_param (chansvs.nick, mychan->chan, MTYPE_DEL, 'k', mychan->chan->key); |
901 | modestack_mode_param (chansvs.nick, mychan->chan, MTYPE_DEL, 'k', mychan->chan->key); |
895 | free (mychan->chan->key); |
902 | sfree (mychan->chan->key); |
896 | mychan->chan->key = NULL; |
903 | mychan->chan->key = NULL; |
897 | } |
904 | } |
898 | |
905 | |
899 | /* non-standard type C modes separately */ |
906 | /* non-standard type C modes separately */ |
900 | md = mychan->find_metadata ("private:mlockext"); |
907 | md = mychan->find_metadata ("private:mlockext"); |
… | |
… | |
907 | { |
914 | { |
908 | if (ignore_mode_list[i].mode == *p) |
915 | if (ignore_mode_list[i].mode == *p) |
909 | { |
916 | { |
910 | if ((p[1] == ' ' || p[1] == '\0') && mychan->chan->extmodes[i] != NULL) |
917 | if ((p[1] == ' ' || p[1] == '\0') && mychan->chan->extmodes[i] != NULL) |
911 | { |
918 | { |
912 | free (mychan->chan->extmodes[i]); |
919 | sfree (mychan->chan->extmodes[i]); |
913 | mychan->chan->extmodes[i] = NULL; |
920 | mychan->chan->extmodes[i] = NULL; |
914 | if (sendnow) |
921 | if (sendnow) |
915 | modestack_mode_ext (chansvs.nick, mychan->chan, MTYPE_DEL, i, NULL); |
922 | modestack_mode_ext (chansvs.nick, mychan->chan, MTYPE_DEL, i, NULL); |
916 | } |
923 | } |
917 | else if (p[1] != ' ' && p[1] != '\0') |
924 | else if (p[1] != ' ' && p[1] != '\0') |
… | |
… | |
921 | if (q != NULL) |
928 | if (q != NULL) |
922 | *q = '\0'; |
929 | *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)) |
930 | if ((mychan->chan->extmodes[i] == NULL || strcmp (mychan->chan->extmodes[i], str2)) && ignore_mode_list[i].check (str2, mychan->chan, mychan, NULL, NULL)) |
924 | { |
931 | { |
925 | if (mychan->chan->extmodes[i] != NULL) |
932 | if (mychan->chan->extmodes[i] != NULL) |
926 | free (mychan->chan->extmodes[i]); |
933 | sfree (mychan->chan->extmodes[i]); |
927 | mychan->chan->extmodes[i] = sstrdup (str2); |
934 | mychan->chan->extmodes[i] = sstrdup (str2); |
928 | if (sendnow) |
935 | if (sendnow) |
929 | modestack_mode_ext (chansvs.nick, mychan->chan, MTYPE_ADD, i, mychan->chan->extmodes[i]); |
936 | modestack_mode_ext (chansvs.nick, mychan->chan, MTYPE_ADD, i, mychan->chan->extmodes[i]); |
930 | } |
937 | } |
931 | } |
938 | } |