]>
jfr.im git - irc/quakenet/snircd.git/blob - ircd/channel.c
2 * IRC - Internet Relay Chat, ircd/channel.c
3 * Copyright (C) 1990 Jarkko Oikarinen and
4 * University of Oulu, Co Center
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 1, or (at your option)
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 * @brief Channel management and maintenance
22 * @version $Id: channel.c,v 1.155 2005/09/27 02:41:57 entrope Exp $
28 #include "destruct_event.h"
31 #include "ircd_alloc.h"
32 #include "ircd_chattr.h"
33 #include "ircd_defs.h"
34 #include "ircd_features.h"
36 #include "ircd_reply.h"
37 #include "ircd_snprintf.h"
38 #include "ircd_string.h"
45 #include "querycmds.h"
56 /* #include <assert.h> -- Now using assert in ircd_log.h */
61 /** Linked list containing the full list of all channels */
62 struct Channel
* GlobalChannelList
= 0;
64 /** Number of struct Membership*'s allocated */
65 static unsigned int membershipAllocCount
;
66 /** Freelist for struct Membership*'s */
67 static struct Membership
* membershipFreeList
;
68 /** Freelist for struct Ban*'s */
69 static struct Ban
* free_bans
;
70 /** Number of ban structures allocated. */
71 static size_t bans_alloc
;
72 /** Number of ban structures in use. */
73 static size_t bans_inuse
;
76 /** return the length (>=0) of a chain of links.
77 * @param lp pointer to the start of the linked list
78 * @return the number of items in the list
80 static int list_length(struct SLink
*lp
)
84 for (; lp
; lp
= lp
->next
)
90 /** Set the mask for a ban, checking for IP masks.
91 * @param[in,out] ban Ban structure to modify.
92 * @param[in] banstr Mask to ban.
95 set_ban_mask(struct Ban
*ban
, const char *banstr
)
98 assert(banstr
!= NULL
);
99 ircd_strncpy(ban
->banstr
, banstr
, sizeof(ban
->banstr
) - 1);
100 sep
= strrchr(banstr
, '@');
102 ban
->nu_len
= sep
- banstr
;
103 if (ipmask_parse(sep
+ 1, &ban
->address
, &ban
->addrbits
))
104 ban
->flags
|= BAN_IPMASK
;
108 /** Allocate a new Ban structure.
109 * @param[in] banstr Ban mask to use.
110 * @return Newly allocated ban.
113 make_ban(const char *banstr
)
118 free_bans
= free_bans
->next
;
120 else if (!(ban
= MyMalloc(sizeof(*ban
))))
125 memset(ban
, 0, sizeof(*ban
));
126 set_ban_mask(ban
, banstr
);
130 /** Deallocate a ban structure.
131 * @param[in] ban Ban to deallocate.
134 free_ban(struct Ban
*ban
)
136 ban
->next
= free_bans
;
141 /** Report ban usage to \a cptr.
142 * @param[in] cptr Client requesting information.
144 void bans_send_meminfo(struct Client
*cptr
)
148 for (num_free
= 0, ban
= free_bans
; ban
; ban
= ban
->next
)
150 send_reply(cptr
, SND_EXPLICIT
| RPL_STATSDEBUG
, ":Bans: inuse %zu(%zu) free %zu alloc %zu",
151 bans_inuse
, bans_inuse
* sizeof(*ban
), num_free
, bans_alloc
);
154 /** return the struct Membership* that represents a client on a channel
155 * This function finds a struct Membership* which holds the state about
156 * a client on a specific channel. The code is smart enough to iterate
157 * over the channels a user is in, or the users in a channel to find the
158 * user depending on which is likely to be more efficient.
160 * @param chptr pointer to the channel struct
161 * @param cptr pointer to the client struct
163 * @returns pointer to the struct Membership representing this client on
164 * this channel. Returns NULL if the client is not on the channel.
165 * Returns NULL if the client is actually a server.
166 * @see find_channel_member()
168 struct Membership
* find_member_link(struct Channel
* chptr
, const struct Client
* cptr
)
170 struct Membership
*m
;
174 /* Servers don't have member links */
175 if (IsServer(cptr
)||IsMe(cptr
))
178 /* +k users are typically on a LOT of channels. So we iterate over who
179 * is in the channel. X/W are +k and are in about 5800 channels each.
180 * however there are typically no more than 1000 people in a channel
183 if (IsChannelService(cptr
)) {
186 assert(m
->channel
== chptr
);
192 /* Users on the other hand aren't allowed on more than 15 channels. 50%
193 * of users that are on channels are on 2 or less, 95% are on 7 or less,
194 * and 99% are on 10 or less.
197 m
= (cli_user(cptr
))->channel
;
199 assert(m
->user
== cptr
);
200 if (m
->channel
== chptr
)
208 /** Find the client structure for a nick name (user)
209 * Find the client structure for a nick name (user)
210 * using history mechanism if necessary. If the client is not found, an error
211 * message (NO SUCH NICK) is generated. If the client was found
212 * through the history, chasing will be 1 and otherwise 0.
214 * This function was used extensively in the P09 days, and since we now have
215 * numeric nicks is no longer quite as important.
217 * @param sptr Pointer to the client that has requested the search
218 * @param user a string representing the client to be found
219 * @param chasing a variable set to 0 if the user was found directly,
221 * @returns a pointer the client, or NULL if the client wasn't found.
223 struct Client
* find_chasing(struct Client
* sptr
, const char* user
, int* chasing
)
225 struct Client
* who
= FindClient(user
);
232 if (!(who
= get_history(user
, feature_int(FEAT_KILLCHASETIMELIMIT
)))) {
233 send_reply(sptr
, ERR_NOSUCHNICK
, user
);
241 /** Decrement the count of users, and free if empty.
242 * Subtract one user from channel i (and free channel * block, if channel
245 * @param chptr The channel to subtract one from.
247 * @returns true (1) if channel still has members.
248 * false (0) if the channel is now empty.
250 int sub1_from_channel(struct Channel
* chptr
)
252 if (chptr
->users
> 1) /* Can be 0, called for an empty channel too */
254 assert(0 != chptr
->members
);
261 /* There is a semantics problem here: Assuming no fragments across a
262 * split, a channel without Apass could be maliciously destroyed and
263 * recreated, and someone could set apass on the new instance.
265 * This could be fixed by preserving the empty non-Apass channel for
266 * the same time as if it had an Apass (but removing +i and +l), and
267 * reopping the first user to rejoin. However, preventing net rides
268 * requires a backwards-incompatible protocol change..
270 if (!chptr
->mode
.apass
[0]) /* If no Apass, destroy now. */
271 destruct_channel(chptr
);
272 else if (TStime() - chptr
->creationtime
< 172800) /* Channel younger than 48 hours? */
273 schedule_destruct_event_1m(chptr
); /* Get rid of it in approximately 4-5 minutes */
275 schedule_destruct_event_48h(chptr
); /* Get rid of it in approximately 48 hours */
280 /** Destroy an empty channel
281 * This function destroys an empty channel, removing it from hashtables,
282 * and removing any resources it may have consumed.
284 * @param chptr The channel to destroy
286 * @returns 0 (success)
288 * FIXME: Change to return void, this function never fails.
290 int destruct_channel(struct Channel
* chptr
)
292 struct Ban
*ban
, *next
;
294 assert(0 == chptr
->members
);
297 * Now, find all invite links from channel structure
299 while (chptr
->invites
)
300 del_invite(chptr
->invites
->value
.cptr
, chptr
);
302 for (ban
= chptr
->banlist
; ban
; ban
= next
)
308 chptr
->prev
->next
= chptr
->next
;
310 GlobalChannelList
= chptr
->next
;
312 chptr
->next
->prev
= chptr
->prev
;
314 --UserStats
.channels
;
316 * make sure that channel actually got removed from hash table
318 assert(chptr
->hnext
== chptr
);
323 /** returns Membership * if a person is joined and not a zombie
325 * @param chptr Channel
326 * @returns pointer to the client's struct Membership * on the channel if that
327 * user is a full member of the channel, or NULL otherwise.
329 * @see find_member_link()
331 struct Membership
* find_channel_member(struct Client
* cptr
, struct Channel
* chptr
)
333 struct Membership
* member
;
336 member
= find_member_link(chptr
, cptr
);
337 return (member
&& !IsZombie(member
)) ? member
: 0;
340 /** Searches for a ban from a ban list that matches a user.
341 * @param[in] cptr The client to test.
342 * @param[in] banlist The list of bans to test.
343 * @return Pointer to a matching ban, or NULL if none exit.
345 struct Ban
*find_ban(struct Client
*cptr
, struct Ban
*banlist
)
347 char nu
[NICKLEN
+ USERLEN
+ 2];
348 char tmphost
[HOSTLEN
+ 1];
349 char iphost
[SOCKIPLEN
+ 1];
354 /* Build nick!user and alternate host names. */
355 ircd_snprintf(0, nu
, sizeof(nu
), "%s!%s",
356 cli_name(cptr
), cli_user(cptr
)->username
);
357 ircd_ntoa_r(iphost
, &cli_ip(cptr
));
358 if (!IsAccount(cptr
))
360 else if (HasHiddenHost(cptr
))
361 sr
= cli_user(cptr
)->realhost
;
364 ircd_snprintf(0, tmphost
, HOSTLEN
, "%s.%s",
365 cli_user(cptr
)->account
, feature_str(FEAT_HIDDEN_HOST
));
369 /* Walk through ban list. */
370 for (found
= NULL
; banlist
; banlist
= banlist
->next
) {
372 /* If we have found a positive ban already, only consider exceptions. */
373 if (found
&& !(banlist
->flags
& BAN_EXCEPTION
))
375 /* Compare nick!user portion of ban. */
376 banlist
->banstr
[banlist
->nu_len
] = '\0';
377 res
= match(banlist
->banstr
, nu
);
378 banlist
->banstr
[banlist
->nu_len
] = '@';
381 /* Compare host portion of ban. */
382 hostmask
= banlist
->banstr
+ banlist
->nu_len
+ 1;
383 if (!((banlist
->flags
& BAN_IPMASK
)
384 && ipmask_check(&cli_ip(cptr
), &banlist
->address
, banlist
->addrbits
))
385 && match(hostmask
, cli_user(cptr
)->host
)
386 && !(sr
&& !match(hostmask
, sr
)))
388 /* If an exception matches, no ban can match. */
389 if (banlist
->flags
& BAN_EXCEPTION
)
391 /* Otherwise, remember this ban but keep searching for an exception. */
398 * This function returns true if the user is banned on the said channel.
399 * This function will check the ban cache if applicable, otherwise will
400 * do the comparisons and cache the result.
402 * @param[in] member The Membership to test for banned-ness.
403 * @return Non-zero if the member is banned, zero if not.
405 static int is_banned(struct Membership
* member
)
407 if (IsBanValid(member
))
408 return IsBanned(member
);
411 if (find_ban(member
->user
, member
->channel
->banlist
)) {
420 /** add a user to a channel.
421 * adds a user to a channel by adding another link to the channels member
424 * @param chptr The channel to add to.
425 * @param who The user to add.
426 * @param flags The flags the user gets initially.
427 * @param oplevel The oplevel the user starts with.
429 void add_user_to_channel(struct Channel
* chptr
, struct Client
* who
,
430 unsigned int flags
, int oplevel
)
437 struct Membership
* member
= membershipFreeList
;
439 membershipFreeList
= member
->next_member
;
441 member
= (struct Membership
*) MyMalloc(sizeof(struct Membership
));
442 ++membershipAllocCount
;
447 member
->channel
= chptr
;
448 member
->status
= flags
;
449 SetOpLevel(member
, oplevel
);
451 member
->next_member
= chptr
->members
;
452 if (member
->next_member
)
453 member
->next_member
->prev_member
= member
;
454 member
->prev_member
= 0;
455 chptr
->members
= member
;
457 member
->next_channel
= (cli_user(who
))->channel
;
458 if (member
->next_channel
)
459 member
->next_channel
->prev_channel
= member
;
460 member
->prev_channel
= 0;
461 (cli_user(who
))->channel
= member
;
463 if (chptr
->destruct_event
)
464 remove_destruct_event(chptr
);
466 ++((cli_user(who
))->joined
);
470 /** Remove a person from a channel, given their Membership*
472 * @param member A member of a channel.
474 * @returns true if there are more people in the channel.
476 static int remove_member_from_channel(struct Membership
* member
)
478 struct Channel
* chptr
;
480 chptr
= member
->channel
;
482 * unlink channel member list
484 if (member
->next_member
)
485 member
->next_member
->prev_member
= member
->prev_member
;
486 if (member
->prev_member
)
487 member
->prev_member
->next_member
= member
->next_member
;
489 member
->channel
->members
= member
->next_member
;
492 * If this is the last delayed-join user, may have to clear WASDELJOINS.
494 if (IsDelayedJoin(member
))
495 CheckDelayedJoins(chptr
);
498 * unlink client channel list
500 if (member
->next_channel
)
501 member
->next_channel
->prev_channel
= member
->prev_channel
;
502 if (member
->prev_channel
)
503 member
->prev_channel
->next_channel
= member
->next_channel
;
505 (cli_user(member
->user
))->channel
= member
->next_channel
;
507 --(cli_user(member
->user
))->joined
;
509 member
->next_member
= membershipFreeList
;
510 membershipFreeList
= member
;
512 return sub1_from_channel(chptr
);
515 /** Check if all the remaining members on the channel are zombies
517 * @returns False if the channel has any non zombie members, True otherwise.
520 static int channel_all_zombies(struct Channel
* chptr
)
522 struct Membership
* member
;
524 for (member
= chptr
->members
; member
; member
= member
->next_member
) {
525 if (!IsZombie(member
))
532 /** Remove a user from a channel
533 * This is the generic entry point for removing a user from a channel, this
534 * function will remove the client from the channel, and destroy the channel
535 * if there are no more normal users left.
537 * @param cptr The client
538 * @param chptr The channel
540 void remove_user_from_channel(struct Client
* cptr
, struct Channel
* chptr
)
543 struct Membership
* member
;
546 if ((member
= find_member_link(chptr
, cptr
))) {
547 if (remove_member_from_channel(member
)) {
548 if (channel_all_zombies(chptr
)) {
550 * XXX - this looks dangerous but isn't if we got the referential
551 * integrity right for channels
553 while (remove_member_from_channel(chptr
->members
))
560 /** Remove a user from all channels they are on.
562 * This function removes a user from all channels they are on.
564 * @param cptr The client to remove.
566 void remove_user_from_all_channels(struct Client
* cptr
)
568 struct Membership
* chan
;
570 assert(0 != cli_user(cptr
));
572 while ((chan
= (cli_user(cptr
))->channel
))
573 remove_user_from_channel(cptr
, chan
->channel
);
576 /** Check if this user is a legitimate chanop
578 * @param cptr Client to check
579 * @param chptr Channel to check
581 * @returns True if the user is a chanop (And not a zombie), False otherwise.
584 int is_chan_op(struct Client
*cptr
, struct Channel
*chptr
)
586 struct Membership
* member
;
588 if ((member
= find_member_link(chptr
, cptr
)))
589 return (!IsZombie(member
) && IsChanOp(member
));
594 /** Check if a user is a Zombie on a specific channel.
596 * @param cptr The client to check.
597 * @param chptr The channel to check.
599 * @returns True if the client (cptr) is a zombie on the channel (chptr),
604 int is_zombie(struct Client
*cptr
, struct Channel
*chptr
)
606 struct Membership
* member
;
610 if ((member
= find_member_link(chptr
, cptr
)))
611 return IsZombie(member
);
615 /** Returns if a user has voice on a channel.
617 * @param cptr The client
618 * @param chptr The channel
620 * @returns True if the client (cptr) is voiced on (chptr) and is not a zombie.
623 int has_voice(struct Client
* cptr
, struct Channel
* chptr
)
625 struct Membership
* member
;
628 if ((member
= find_member_link(chptr
, cptr
)))
629 return (!IsZombie(member
) && HasVoice(member
));
634 /** Can this member send to a channel
636 * A user can speak on a channel iff:
638 * <li> They didn't use the Apass to gain ops.
639 * <li> They are op'd or voice'd.
640 * <li> You aren't banned.
641 * <li> The channel isn't +m
642 * <li> The channel isn't +n or you are on the channel.
645 * This function will optionally reveal a user on a delayed join channel if
646 * they are allowed to send to the channel.
648 * @param member The membership of the user
649 * @param reveal If true, the user will be "revealed" on a delayed
652 * @returns True if the client can speak on the channel.
654 int member_can_send_to_channel(struct Membership
* member
, int reveal
)
658 /* Discourage using the Apass to get op. They should use the upass. */
659 if (IsChannelManager(member
) && member
->channel
->mode
.apass
[0])
662 if (IsVoicedOrOpped(member
))
666 * If it's moderated, and you aren't a privileged user, you can't
669 if (member
->channel
->mode
.mode
& MODE_MODERATED
)
671 /* If only logged in users may join and you're not one, you can't speak. */
672 if (member
->channel
->mode
.mode
& MODE_REGONLY
&& !IsAccount(member
->user
))
675 * If you're banned then you can't speak either.
676 * but because of the amount of CPU time that is_banned chews
677 * we only check it for our clients.
679 if (MyUser(member
->user
) && is_banned(member
))
682 if (IsDelayedJoin(member
) && reveal
)
683 RevealDelayedJoin(member
);
688 /** Check if a client can send to a channel.
690 * Has the added check over member_can_send_to_channel() of servers can
693 * @param cptr The client to check
694 * @param chptr The channel to check
695 * @param reveal If the user should be revealed (see
696 * member_can_send_to_channel())
698 * @returns true if the client is allowed to speak on the channel, false
701 * @see member_can_send_to_channel()
703 int client_can_send_to_channel(struct Client
*cptr
, struct Channel
*chptr
, int reveal
)
705 struct Membership
*member
;
708 * Servers can always speak on channels.
713 member
= find_channel_member(cptr
, chptr
);
716 * You can't speak if you're off channel, and it is +n (no external messages)
720 if ((chptr
->mode
.mode
& (MODE_NOPRIVMSGS
|MODE_MODERATED
)) ||
721 ((chptr
->mode
.mode
& MODE_REGONLY
) && !IsAccount(cptr
)))
724 return !find_ban(cptr
, chptr
->banlist
);
726 return member_can_send_to_channel(member
, reveal
);
729 /** Returns the name of a channel that prevents the user from changing nick.
730 * if a member and not (opped or voiced) and (banned or moderated), return
731 * the name of the first channel banned on.
733 * @param cptr The client
735 * @returns the name of the first channel banned on, or NULL if the user
738 const char* find_no_nickchange_channel(struct Client
* cptr
)
741 struct Membership
* member
;
742 for (member
= (cli_user(cptr
))->channel
; member
;
743 member
= member
->next_channel
) {
744 if (!IsVoicedOrOpped(member
) &&
745 (is_banned(member
) ||
746 (member
->channel
->mode
.mode
& MODE_MODERATED
)))
747 return member
->channel
->chname
;
754 /** Fill mbuf/pbuf with modes from chptr
755 * write the "simple" list of channel modes for channel chptr onto buffer mbuf
756 * with the parameters in pbuf as visible by cptr.
758 * This function will hide keys from non-op'd, non-server clients.
760 * @param cptr The client to generate the mode for.
761 * @param mbuf The buffer to write the modes into.
762 * @param pbuf The buffer to write the mode parameters into.
763 * @param buflen The length of the buffers.
764 * @param chptr The channel to get the modes from.
765 * @param member The membership of this client on this channel (or NULL
766 * if this client isn't on this channel)
769 void channel_modes(struct Client
*cptr
, char *mbuf
, char *pbuf
, int buflen
,
770 struct Channel
*chptr
, struct Membership
*member
)
772 int previous_parameter
= 0;
779 if (chptr
->mode
.mode
& MODE_SECRET
)
781 else if (chptr
->mode
.mode
& MODE_PRIVATE
)
783 if (chptr
->mode
.mode
& MODE_MODERATED
)
785 if (chptr
->mode
.mode
& MODE_TOPICLIMIT
)
787 if (chptr
->mode
.mode
& MODE_INVITEONLY
)
789 if (chptr
->mode
.mode
& MODE_NOPRIVMSGS
)
791 if (chptr
->mode
.mode
& MODE_REGONLY
)
793 if (chptr
->mode
.mode
& MODE_NOQUITPARTS
)
795 if (chptr
->mode
.mode
& MODE_DELJOINS
)
797 else if (MyUser(cptr
) && (chptr
->mode
.mode
& MODE_WASDELJOINS
))
799 if (chptr
->mode
.limit
) {
801 ircd_snprintf(0, pbuf
, buflen
, "%u", chptr
->mode
.limit
);
802 previous_parameter
= 1;
805 if (*chptr
->mode
.key
) {
807 if (previous_parameter
)
809 if (is_chan_op(cptr
, chptr
) || IsServer(cptr
) || IsOper(cptr
)) {
810 strcat(pbuf
, chptr
->mode
.key
);
813 previous_parameter
= 1;
815 if (*chptr
->mode
.apass
) {
817 if (previous_parameter
)
819 if (IsServer(cptr
)) {
820 strcat(pbuf
, chptr
->mode
.apass
);
823 previous_parameter
= 1;
825 if (*chptr
->mode
.upass
) {
827 if (previous_parameter
)
829 if (IsServer(cptr
) || (member
&& IsChanOp(member
) && OpLevel(member
) == 0)) {
830 strcat(pbuf
, chptr
->mode
.upass
);
837 /** Compare two members oplevel
839 * @param mp1 Pointer to a pointer to a membership
840 * @param mp2 Pointer to a pointer to a membership
842 * @returns 0 if equal, -1 if mp1 is lower, +1 otherwise.
846 int compare_member_oplevel(const void *mp1
, const void *mp2
)
848 struct Membership
const* member1
= *(struct Membership
const**)mp1
;
849 struct Membership
const* member2
= *(struct Membership
const**)mp2
;
850 if (member1
->oplevel
== member2
->oplevel
)
852 return (member1
->oplevel
< member2
->oplevel
) ? -1 : 1;
855 /* send "cptr" a full list of the modes for channel chptr.
857 * Sends a BURST line to cptr, bursting all the modes for the channel.
859 * @param cptr Client pointer
860 * @param chptr Channel pointer
862 void send_channel_modes(struct Client
*cptr
, struct Channel
*chptr
)
864 /* The order in which modes are generated is now mandatory */
865 static unsigned int current_flags
[4] =
866 { 0, CHFL_VOICE
, CHFL_CHANOP
, CHFL_CHANOP
| CHFL_VOICE
};
872 struct Membership
* member
;
874 char modebuf
[MODEBUFLEN
];
875 char parabuf
[MODEBUFLEN
];
877 int number_of_ops
= 0;
878 int opped_members_index
= 0;
879 struct Membership
** opped_members
= NULL
;
880 int last_oplevel
= 0;
881 int feat_oplevels
= (chptr
->mode
.apass
[0]) != '\0';
886 if (IsLocalChannel(chptr
->chname
))
889 member
= chptr
->members
;
890 lp2
= chptr
->banlist
;
892 *modebuf
= *parabuf
= '\0';
893 channel_modes(cptr
, modebuf
, parabuf
, sizeof(parabuf
), chptr
, 0);
895 for (first
= 1; full
; first
= 0) /* Loop for multiple messages */
897 full
= 0; /* Assume by default we get it
898 all in one message */
900 /* (Continued) prefix: "<Y> B <channel> <TS>" */
901 /* is there any better way we can do this? */
902 mb
= msgq_make(&me
, "%C " TOK_BURST
" %H %Tu", &me
, chptr
,
903 chptr
->creationtime
);
905 if (first
&& modebuf
[1]) /* Add simple modes (Aiklmnpstu)
908 /* prefix: "<Y> B <channel> <TS>[ <modes>[ <params>]]" */
909 msgq_append(&me
, mb
, " %s", modebuf
);
912 msgq_append(&me
, mb
, " %s", parabuf
);
916 * Attach nicks, comma separated " nick[:modes],nick[:modes],..."
918 * First find all opless members.
919 * Run 2 times over all members, to group the members with
920 * and without voice together.
921 * Then run 2 times over all opped members (which are ordered
922 * by op-level) to also group voice and non-voice together.
924 for (first
= 1; flag_cnt
< 4; new_mode
= 1, ++flag_cnt
)
928 if (flag_cnt
< 2 && IsChanOp(member
))
931 * The first loop (to find all non-voice/op), we count the ops.
932 * The second loop (to find all voiced non-ops), store the ops
933 * in a dynamic array.
938 opped_members
[opped_members_index
++] = member
;
940 /* Only handle the members with the flags that we are interested in. */
941 if ((member
->status
& CHFL_VOICED_OR_OPPED
) == current_flags
[flag_cnt
])
943 if (msgq_bufleft(mb
) < NUMNICKLEN
+ 3 + MAXOPLEVELDIGITS
)
944 /* The 3 + MAXOPLEVELDIGITS is a possible ",:v999". */
946 full
= 1; /* Make sure we continue after
948 /* Ensure the new BURST line contains the current
949 * ":mode", except when there is no mode yet. */
950 new_mode
= (flag_cnt
> 0) ? 1 : 0;
951 break; /* Do not add this member to this message */
953 msgq_append(&me
, mb
, "%c%C", first
? ' ' : ',', member
->user
);
954 first
= 0; /* From now on, use commas to add new nicks */
957 * Do we have a nick with a new mode ?
958 * Or are we starting a new BURST line?
963 * This means we are at the _first_ member that has only
964 * voice, or the first member that has only ops, or the
965 * first member that has voice and ops (so we get here
966 * at most three times, plus once for every start of
967 * a continued BURST line where only these modes is current.
968 * In the two cases where the current mode includes ops,
969 * we need to add the _absolute_ value of the oplevel to the mode.
971 char tbuf
[3 + MAXOPLEVELDIGITS
] = ":";
974 if (HasVoice(member
)) /* flag_cnt == 1 or 3 */
976 if (IsChanOp(member
)) /* flag_cnt == 2 or 3 */
978 /* append the absolute value of the oplevel */
980 loc
+= ircd_snprintf(0, tbuf
+ loc
, sizeof(tbuf
) - loc
, "%u", last_oplevel
= member
->oplevel
);
985 msgq_append(&me
, mb
, tbuf
);
988 else if (feat_oplevels
&& flag_cnt
> 1 && last_oplevel
!= member
->oplevel
)
991 * This can't be the first member of a (continued) BURST
992 * message because then either flag_cnt == 0 or new_mode == 1
993 * Now we need to append the incremental value of the oplevel.
995 char tbuf
[2 + MAXOPLEVELDIGITS
];
996 ircd_snprintf(0, tbuf
, sizeof(tbuf
), ":%u", member
->oplevel
- last_oplevel
);
997 last_oplevel
= member
->oplevel
;
998 msgq_append(&me
, mb
, tbuf
);
1001 /* Go to the next `member'. */
1003 member
= member
->next_member
;
1005 member
= opped_members
[++opped_members_index
];
1010 /* Point `member' at the start of the list again. */
1013 member
= chptr
->members
;
1014 /* Now, after one loop, we know the number of ops and can
1015 * allocate the dynamic array with pointer to the ops. */
1016 opped_members
= (struct Membership
**)
1017 MyMalloc((number_of_ops
+ 1) * sizeof(struct Membership
*));
1018 opped_members
[number_of_ops
] = NULL
; /* Needed for loop termination */
1022 /* At the end of the second loop, sort the opped members with
1023 * increasing op-level, so that we will output them in the
1024 * correct order (and all op-level increments stay positive) */
1026 qsort(opped_members
, number_of_ops
,
1027 sizeof(struct Membership
*), compare_member_oplevel
);
1028 /* The third and fourth loop run only over the opped members. */
1029 member
= opped_members
[(opped_members_index
= 0)];
1032 } /* loop over 0,+v,+o,+ov */
1036 /* Attach all bans, space separated " :%ban ban ..." */
1037 for (first
= 2; lp2
; lp2
= lp2
->next
)
1039 len
= strlen(lp2
->banstr
);
1040 if (msgq_bufleft(mb
) < len
+ 1 + first
)
1041 /* The +1 stands for the added ' '.
1042 * The +first stands for the added ":%".
1048 msgq_append(&me
, mb
, " %s%s", first
? ":%" : "",
1054 send_buffer(cptr
, mb
, 0); /* Send this message */
1056 } /* Continue when there was something
1057 that didn't fit (full==1) */
1059 MyFree(opped_members
);
1060 if (feature_bool(FEAT_TOPIC_BURST
) && (chptr
->topic
[0] != '\0'))
1061 sendcmdto_one(&me
, CMD_TOPIC
, cptr
, "%H %Tu %Tu :%s", chptr
,
1062 chptr
->creationtime
, chptr
->topic_time
, chptr
->topic
);
1065 /** Canonify a mask.
1068 * @author Carlo Wood (Run),
1071 * When the nick is longer then NICKLEN, it is cut off (its an error of course).
1072 * When the user name or host name are too long (USERLEN and HOSTLEN
1073 * respectively) then they are cut off at the start with a '*'.
1075 * The following transformations are made:
1077 * 1) xxx -> nick!*@*
1078 * 2) xxx.xxx -> *!*\@host
1079 * 3) xxx\!yyy -> nick!user\@*
1080 * 4) xxx\@yyy -> *!user\@host
1081 * 5) xxx!yyy\@zzz -> nick!user\@host
1083 * @param mask The uncanonified mask.
1084 * @returns The updated mask in a static buffer.
1086 char *pretty_mask(char *mask
)
1088 static char star
[2] = { '*', 0 };
1089 static char retmask
[NICKLEN
+ USERLEN
+ HOSTLEN
+ 3];
1090 char *last_dot
= NULL
;
1093 /* Case 1: default */
1098 /* Do a _single_ pass through the characters of the mask: */
1099 for (ptr
= mask
; *ptr
; ++ptr
)
1103 /* Case 3 or 5: Found first '!' (without finding a '@' yet) */
1107 else if (*ptr
== '@')
1109 /* Case 4: Found last '@' (without finding a '!' yet) */
1114 else if (*ptr
== '.' || *ptr
== ':')
1116 /* Case 2: Found character specific to IP or hostname (without
1117 * finding a '!' or '@' yet) */
1127 /* Case 4 or 5: Found last '@' */
1133 if (user
== star
&& last_dot
)
1143 char *nick_end
= (user
!= star
) ? user
- 1 : ptr
;
1144 if (nick_end
- nick
> NICKLEN
)
1150 char *user_end
= (host
!= star
) ? host
- 1 : ptr
;
1151 if (user_end
- user
> USERLEN
)
1153 user
= user_end
- USERLEN
;
1158 if (host
!= star
&& ptr
- host
> HOSTLEN
)
1160 host
= ptr
- HOSTLEN
;
1163 ircd_snprintf(0, retmask
, sizeof(retmask
), "%s!%s@%s", nick
, user
, host
);
1167 /** send a banlist to a client for a channel
1169 * @param cptr Client to send the banlist to.
1170 * @param chptr Channel whose banlist to send.
1172 static void send_ban_list(struct Client
* cptr
, struct Channel
* chptr
)
1179 for (lp
= chptr
->banlist
; lp
; lp
= lp
->next
)
1180 send_reply(cptr
, RPL_BANLIST
, chptr
->chname
, lp
->banstr
,
1183 send_reply(cptr
, RPL_ENDOFBANLIST
, chptr
->chname
);
1186 /** Remove bells and commas from channel name
1188 * @param cn Channel name to clean, modified in place.
1190 void clean_channelname(char *cn
)
1194 for (i
= 0; cn
[i
]; i
++) {
1195 if (i
>= IRCD_MIN(CHANNELLEN
, feature_int(FEAT_CHANNELLEN
))
1196 || !IsChannelChar(cn
[i
])) {
1200 if (IsChannelLower(cn
[i
])) {
1201 cn
[i
] = ToLower(cn
[i
]);
1207 if ((unsigned char)(cn
[i
]) == 0xd0)
1208 cn
[i
] = (char) 0xf0;
1214 /** Get a channel block, creating if necessary.
1215 * Get Channel block for chname (and allocate a new channel
1216 * block, if it didn't exists before).
1218 * @param cptr Client joining the channel.
1219 * @param chname The name of the channel to join.
1220 * @param flag set to CGT_CREATE to create the channel if it doesn't
1223 * @returns NULL if the channel is invalid, doesn't exist and CGT_CREATE
1224 * wasn't specified or a pointer to the channel structure
1226 struct Channel
*get_channel(struct Client
*cptr
, char *chname
, ChannelGetType flag
)
1228 struct Channel
*chptr
;
1231 if (EmptyString(chname
))
1234 len
= strlen(chname
);
1235 if (MyUser(cptr
) && len
> CHANNELLEN
)
1238 *(chname
+ CHANNELLEN
) = '\0';
1240 if ((chptr
= FindChannel(chname
)))
1242 if (flag
== CGT_CREATE
)
1244 chptr
= (struct Channel
*) MyMalloc(sizeof(struct Channel
) + len
);
1246 ++UserStats
.channels
;
1247 memset(chptr
, 0, sizeof(struct Channel
));
1248 strcpy(chptr
->chname
, chname
);
1249 if (GlobalChannelList
)
1250 GlobalChannelList
->prev
= chptr
;
1252 chptr
->next
= GlobalChannelList
;
1253 chptr
->creationtime
= MyUser(cptr
) ? TStime() : (time_t) 0;
1254 GlobalChannelList
= chptr
;
1260 int SetAutoChanModes(struct Channel
*chptr
)
1262 static int chan_flags
[] = {
1265 MODE_MODERATED
, 'm',
1266 MODE_TOPICLIMIT
, 't',
1267 MODE_INVITEONLY
, 'i',
1268 MODE_NOPRIVMSGS
, 'n',
1270 /* MODE_NOCOLOUR, 'c',
1272 MODE_NONOTICE, 'N',*/
1274 MODE_NOQUITPARTS
, 'u'
1277 unsigned int *flag_p
;
1278 unsigned int t_mode
;
1279 const char *modestr
;
1285 if (!feature_bool(FEAT_AUTOCHANMODES
) || !feature_str(FEAT_AUTOCHANMODES_LIST
) || strlen(feature_str(FEAT_AUTOCHANMODES_LIST
)) <= 1)
1288 modestr
= feature_str(FEAT_AUTOCHANMODES_LIST
);
1290 for (; *modestr
; modestr
++) {
1291 for (flag_p
= chan_flags
; flag_p
[0]; flag_p
+= 2) /* look up flag */
1292 if (flag_p
[1] == *modestr
)
1295 if (!flag_p
[0]) /* didn't find it */
1298 t_mode
|= flag_p
[0];
1300 } /* for (; *modestr; modestr++) { */
1303 chptr
->mode
.mode
= t_mode
;
1307 /** invite a user to a channel.
1309 * Adds an invite for a user to a channel. Limits the number of invites
1310 * to FEAT_MAXCHANNELSPERUSER. Does not sent notification to the user.
1312 * @param cptr The client to be invited.
1313 * @param chptr The channel to be invited to.
1315 void add_invite(struct Client
*cptr
, struct Channel
*chptr
)
1317 struct SLink
*inv
, **tmp
;
1319 del_invite(cptr
, chptr
);
1321 * Delete last link in chain if the list is max length
1323 assert(list_length((cli_user(cptr
))->invited
) == (cli_user(cptr
))->invites
);
1324 if ((cli_user(cptr
))->invites
>= feature_int(FEAT_MAXCHANNELSPERUSER
))
1325 del_invite(cptr
, (cli_user(cptr
))->invited
->value
.chptr
);
1327 * Add client to channel invite list
1330 inv
->value
.cptr
= cptr
;
1331 inv
->next
= chptr
->invites
;
1332 chptr
->invites
= inv
;
1334 * Add channel to the end of the client invite list
1336 for (tmp
= &((cli_user(cptr
))->invited
); *tmp
; tmp
= &((*tmp
)->next
));
1338 inv
->value
.chptr
= chptr
;
1341 (cli_user(cptr
))->invites
++;
1344 /** Delete an invite
1345 * Delete Invite block from channel invite list and client invite list
1347 * @param cptr Client pointer
1348 * @param chptr Channel pointer
1350 void del_invite(struct Client
*cptr
, struct Channel
*chptr
)
1352 struct SLink
**inv
, *tmp
;
1354 for (inv
= &(chptr
->invites
); (tmp
= *inv
); inv
= &tmp
->next
)
1355 if (tmp
->value
.cptr
== cptr
)
1360 (cli_user(cptr
))->invites
--;
1364 for (inv
= &((cli_user(cptr
))->invited
); (tmp
= *inv
); inv
= &tmp
->next
)
1365 if (tmp
->value
.chptr
== chptr
)
1374 /** @page zombie Explanation of Zombies
1378 * A channel member is turned into a zombie when he is kicked from a
1379 * channel but his server has not acknowledged the kick. Servers that
1380 * see the member as a zombie can accept actions he performed before
1381 * being kicked, without allowing chanop operations from outsiders or
1382 * desyncing the network.
1390 * X --a--> A --b--> B --d--> D
1395 * Where `who' is being KICK-ed by a "KICK" message received by server 'A'
1396 * via 'a', or on server 'B' via either 'b' or 'c', or on server D via 'd'.
1398 * a) On server A : set CHFL_ZOMBIE for `who' (lp) and pass on the KICK.
1399 * Remove the user immediately when no users are left on the channel.
1400 * b) On server B : remove the user (who/lp) from the channel, send a
1401 * PART upstream (to A) and pass on the KICK.
1402 * c) KICKed by `client'; On server B : remove the user (who/lp) from the
1403 * channel, and pass on the KICK.
1404 * d) On server D : remove the user (who/lp) from the channel, and pass on
1408 * - Setting the ZOMBIE flag never hurts, we either remove the
1409 * client after that or we don't.
1410 * - The KICK message was already passed on, as should be in all cases.
1411 * - `who' is removed in all cases except case a) when users are left.
1412 * - A PART is only sent upstream in case b).
1418 * 1 --- 2 --- 3 --- 4 --- 5
1423 * We also need to turn 'who' into a zombie on servers 1 and 6,
1424 * because a KICK from 'who' (kicking someone else in that direction)
1425 * can arrive there afterward - which should not be bounced itself.
1426 * Therefore case a) also applies for servers 1 and 6.
1431 /** Turn a user on a channel into a zombie
1432 * This function turns a user into a zombie (see \ref zombie)
1434 * @param member The structure representing this user on this channel.
1435 * @param who The client that is being kicked.
1436 * @param cptr The connection the kick came from.
1437 * @param sptr The client that is doing the kicking.
1438 * @param chptr The channel the user is being kicked from.
1440 void make_zombie(struct Membership
* member
, struct Client
* who
,
1441 struct Client
* cptr
, struct Client
* sptr
, struct Channel
* chptr
)
1443 assert(0 != member
);
1448 /* Default for case a): */
1451 /* Case b) or c) ?: */
1452 if (MyUser(who
)) /* server 4 */
1454 if (IsServer(cptr
)) /* Case b) ? */
1455 sendcmdto_one(who
, CMD_PART
, cptr
, "%H", chptr
);
1456 remove_user_from_channel(who
, chptr
);
1459 if (cli_from(who
) == cptr
) /* True on servers 1, 5 and 6 */
1461 struct Client
*acptr
= IsServer(sptr
) ? sptr
: (cli_user(sptr
))->server
;
1462 for (; acptr
!= &me
; acptr
= (cli_serv(acptr
))->up
)
1463 if (acptr
== (cli_user(who
))->server
) /* Case d) (server 5) */
1465 remove_user_from_channel(who
, chptr
);
1470 /* Case a) (servers 1, 2, 3 and 6) */
1471 if (channel_all_zombies(chptr
))
1472 remove_user_from_channel(who
, chptr
);
1474 /* XXX Can't actually call Debug here; if the channel is all zombies,
1475 * chptr will no longer exist when we get here.
1476 Debug((DEBUG_INFO, "%s is now a zombie on %s", who->name, chptr->chname));
1480 /** returns the number of zombies on a channel
1481 * @param chptr Channel to count zombies in.
1483 * @returns The number of zombies on the channel.
1485 int number_of_zombies(struct Channel
*chptr
)
1487 struct Membership
* member
;
1491 for (member
= chptr
->members
; member
; member
= member
->next_member
) {
1492 if (IsZombie(member
))
1498 /** Concatenate some strings together.
1499 * This helper function builds an argument string in strptr, consisting
1500 * of the original string, a space, and str1 and str2 concatenated (if,
1501 * of course, str2 is not NULL)
1503 * @param strptr The buffer to concatenate into
1504 * @param strptr_i modified offset to the position to modify
1505 * @param str1 The string to concatenate from.
1506 * @param str2 The second string to contatenate from.
1507 * @param c Charactor to separate the string from str1 and str2.
1510 build_string(char *strptr
, int *strptr_i
, const char *str1
,
1511 const char *str2
, char c
)
1514 strptr
[(*strptr_i
)++] = c
;
1517 strptr
[(*strptr_i
)++] = *(str1
++);
1521 strptr
[(*strptr_i
)++] = *(str2
++);
1523 strptr
[(*strptr_i
)] = '\0';
1526 /** Flush out the modes
1527 * This is the workhorse of our ModeBuf suite; this actually generates the
1528 * output MODE commands, HACK notices, or whatever. It's pretty complicated.
1530 * @param mbuf The mode buffer to flush
1531 * @param all If true, flush all modes, otherwise leave partial modes in the
1537 modebuf_flush_int(struct ModeBuf
*mbuf
, int all
)
1539 /* we only need the flags that don't take args right now */
1540 static int flags
[] = {
1541 /* MODE_CHANOP, 'o', */
1542 /* MODE_VOICE, 'v', */
1545 MODE_MODERATED
, 'm',
1546 MODE_TOPICLIMIT
, 't',
1547 MODE_INVITEONLY
, 'i',
1548 MODE_NOPRIVMSGS
, 'n',
1551 MODE_WASDELJOINS
, 'd',
1552 /* MODE_KEY, 'k', */
1553 /* MODE_BAN, 'b', */
1555 /* MODE_APASS, 'A', */
1556 /* MODE_UPASS, 'U', */
1557 MODE_NOQUITPARTS
, 'u',
1563 struct Client
*app_source
; /* where the MODE appears to come from */
1565 char addbuf
[20]; /* accumulates +psmtin, etc. */
1567 char rembuf
[20]; /* accumulates -psmtin, etc. */
1569 char *bufptr
; /* we make use of indirection to simplify the code */
1572 char addstr
[BUFSIZE
]; /* accumulates MODE parameters to add */
1574 char remstr
[BUFSIZE
]; /* accumulates MODE parameters to remove */
1576 char *strptr
; /* more indirection to simplify the code */
1579 int totalbuflen
= BUFSIZE
- 200; /* fuzz factor -- don't overrun buffer! */
1582 char limitbuf
[20]; /* convert limits to strings */
1584 unsigned int limitdel
= MODE_LIMIT
;
1588 /* If the ModeBuf is empty, we have nothing to do */
1589 if (mbuf
->mb_add
== 0 && mbuf
->mb_rem
== 0 && mbuf
->mb_count
== 0)
1592 /* Ok, if we were given the OPMODE flag, or its a server, hide the source.
1594 if (mbuf
->mb_dest
& MODEBUF_DEST_OPMODE
|| IsServer(mbuf
->mb_source
) || IsMe(mbuf
->mb_source
))
1597 app_source
= mbuf
->mb_source
;
1600 * Account for user we're bouncing; we have to get it in on the first
1601 * bounced MODE, or we could have problems
1603 if (mbuf
->mb_dest
& MODEBUF_DEST_DEOP
)
1604 totalbuflen
-= 6; /* numeric nick == 5, plus one space */
1606 /* Calculate the simple flags */
1607 for (flag_p
= flags
; flag_p
[0]; flag_p
+= 2) {
1608 if (*flag_p
& mbuf
->mb_add
)
1609 addbuf
[addbuf_i
++] = flag_p
[1];
1610 else if (*flag_p
& mbuf
->mb_rem
)
1611 rembuf
[rembuf_i
++] = flag_p
[1];
1614 /* Now go through the modes with arguments... */
1615 for (i
= 0; i
< mbuf
->mb_count
; i
++) {
1616 if (MB_TYPE(mbuf
, i
) & MODE_ADD
) { /* adding or removing? */
1618 bufptr_i
= &addbuf_i
;
1621 bufptr_i
= &rembuf_i
;
1624 if (MB_TYPE(mbuf
, i
) & (MODE_CHANOP
| MODE_VOICE
)) {
1625 tmp
= strlen(cli_name(MB_CLIENT(mbuf
, i
)));
1627 if ((totalbuflen
- IRCD_MAX(9, tmp
)) <= 0) /* don't overflow buffer */
1628 MB_TYPE(mbuf
, i
) |= MODE_SAVE
; /* save for later */
1630 bufptr
[(*bufptr_i
)++] = MB_TYPE(mbuf
, i
) & MODE_CHANOP
? 'o' : 'v';
1631 totalbuflen
-= IRCD_MAX(9, tmp
) + 1;
1633 } else if (MB_TYPE(mbuf
, i
) & (MODE_BAN
| MODE_APASS
| MODE_UPASS
)) {
1634 tmp
= strlen(MB_STRING(mbuf
, i
));
1636 if ((totalbuflen
- tmp
) <= 0) /* don't overflow buffer */
1637 MB_TYPE(mbuf
, i
) |= MODE_SAVE
; /* save for later */
1640 switch(MB_TYPE(mbuf
, i
) & (MODE_BAN
| MODE_APASS
| MODE_UPASS
))
1652 bufptr
[(*bufptr_i
)++] = mode_char
;
1653 totalbuflen
-= tmp
+ 1;
1655 } else if (MB_TYPE(mbuf
, i
) & MODE_KEY
) {
1656 tmp
= (mbuf
->mb_dest
& MODEBUF_DEST_NOKEY
? 1 :
1657 strlen(MB_STRING(mbuf
, i
)));
1659 if ((totalbuflen
- tmp
) <= 0) /* don't overflow buffer */
1660 MB_TYPE(mbuf
, i
) |= MODE_SAVE
; /* save for later */
1662 bufptr
[(*bufptr_i
)++] = 'k';
1663 totalbuflen
-= tmp
+ 1;
1665 } else if (MB_TYPE(mbuf
, i
) & MODE_LIMIT
) {
1666 /* if it's a limit, we also format the number */
1667 ircd_snprintf(0, limitbuf
, sizeof(limitbuf
), "%u", MB_UINT(mbuf
, i
));
1669 tmp
= strlen(limitbuf
);
1671 if ((totalbuflen
- tmp
) <= 0) /* don't overflow buffer */
1672 MB_TYPE(mbuf
, i
) |= MODE_SAVE
; /* save for later */
1674 bufptr
[(*bufptr_i
)++] = 'l';
1675 totalbuflen
-= tmp
+ 1;
1680 /* terminate the mode strings */
1681 addbuf
[addbuf_i
] = '\0';
1682 rembuf
[rembuf_i
] = '\0';
1684 /* If we're building a user visible MODE or HACK... */
1685 if (mbuf
->mb_dest
& (MODEBUF_DEST_CHANNEL
| MODEBUF_DEST_HACK2
|
1686 MODEBUF_DEST_HACK3
| MODEBUF_DEST_HACK4
|
1687 MODEBUF_DEST_LOG
)) {
1688 /* Set up the parameter strings */
1694 for (i
= 0; i
< mbuf
->mb_count
; i
++) {
1695 if (MB_TYPE(mbuf
, i
) & MODE_SAVE
)
1698 if (MB_TYPE(mbuf
, i
) & MODE_ADD
) { /* adding or removing? */
1700 strptr_i
= &addstr_i
;
1703 strptr_i
= &remstr_i
;
1706 /* deal with clients... */
1707 if (MB_TYPE(mbuf
, i
) & (MODE_CHANOP
| MODE_VOICE
))
1708 build_string(strptr
, strptr_i
, cli_name(MB_CLIENT(mbuf
, i
)), 0, ' ');
1710 /* deal with bans... */
1711 else if (MB_TYPE(mbuf
, i
) & MODE_BAN
)
1712 build_string(strptr
, strptr_i
, MB_STRING(mbuf
, i
), 0, ' ');
1714 /* deal with keys... */
1715 else if (MB_TYPE(mbuf
, i
) & MODE_KEY
)
1716 build_string(strptr
, strptr_i
, mbuf
->mb_dest
& MODEBUF_DEST_NOKEY
?
1717 "*" : MB_STRING(mbuf
, i
), 0, ' ');
1719 /* deal with invisible passwords */
1720 else if (MB_TYPE(mbuf
, i
) & (MODE_APASS
| MODE_UPASS
))
1721 build_string(strptr
, strptr_i
, "*", 0, ' ');
1724 * deal with limit; note we cannot include the limit parameter if we're
1727 else if ((MB_TYPE(mbuf
, i
) & (MODE_ADD
| MODE_LIMIT
)) ==
1728 (MODE_ADD
| MODE_LIMIT
))
1729 build_string(strptr
, strptr_i
, limitbuf
, 0, ' ');
1732 /* send the messages off to their destination */
1733 if (mbuf
->mb_dest
& MODEBUF_DEST_HACK2
)
1734 sendto_opmask_butone(0, SNO_HACK2
, "HACK(2): %s MODE %s %s%s%s%s%s%s "
1736 cli_name(feature_bool(FEAT_HIS_SNOTICES
) ?
1737 mbuf
->mb_source
: app_source
),
1738 mbuf
->mb_channel
->chname
,
1739 rembuf_i
? "-" : "", rembuf
, addbuf_i
? "+" : "",
1740 addbuf
, remstr
, addstr
,
1741 mbuf
->mb_channel
->creationtime
);
1743 if (mbuf
->mb_dest
& MODEBUF_DEST_HACK3
)
1744 sendto_opmask_butone(0, SNO_HACK3
, "BOUNCE or HACK(3): %s MODE %s "
1745 "%s%s%s%s%s%s [%Tu]",
1746 cli_name(feature_bool(FEAT_HIS_SNOTICES
) ?
1747 mbuf
->mb_source
: app_source
),
1748 mbuf
->mb_channel
->chname
, rembuf_i
? "-" : "",
1749 rembuf
, addbuf_i
? "+" : "", addbuf
, remstr
, addstr
,
1750 mbuf
->mb_channel
->creationtime
);
1752 if (mbuf
->mb_dest
& MODEBUF_DEST_HACK4
)
1753 sendto_opmask_butone(0, SNO_HACK4
, "HACK(4): %s MODE %s %s%s%s%s%s%s "
1755 cli_name(feature_bool(FEAT_HIS_SNOTICES
) ?
1756 mbuf
->mb_source
: app_source
),
1757 mbuf
->mb_channel
->chname
,
1758 rembuf_i
? "-" : "", rembuf
, addbuf_i
? "+" : "",
1759 addbuf
, remstr
, addstr
,
1760 mbuf
->mb_channel
->creationtime
);
1762 if (mbuf
->mb_dest
& MODEBUF_DEST_LOG
)
1763 log_write(LS_OPERMODE
, L_INFO
, LOG_NOSNOTICE
,
1764 "%#C OPMODE %H %s%s%s%s%s%s", mbuf
->mb_source
,
1765 mbuf
->mb_channel
, rembuf_i
? "-" : "", rembuf
,
1766 addbuf_i
? "+" : "", addbuf
, remstr
, addstr
);
1768 if (mbuf
->mb_dest
& MODEBUF_DEST_CHANNEL
)
1769 sendcmdto_channel_butserv_butone(app_source
, CMD_MODE
, mbuf
->mb_channel
, NULL
, 0,
1770 "%H %s%s%s%s%s%s", mbuf
->mb_channel
,
1771 rembuf_i
? "-" : "", rembuf
,
1772 addbuf_i
? "+" : "", addbuf
, remstr
, addstr
);
1775 /* Now are we supposed to propagate to other servers? */
1776 if (mbuf
->mb_dest
& MODEBUF_DEST_SERVER
) {
1777 /* set up parameter string */
1784 * limit is supressed if we're removing it; we have to figure out which
1785 * direction is the direction for it to be removed, though...
1787 limitdel
|= (mbuf
->mb_dest
& MODEBUF_DEST_HACK2
) ? MODE_DEL
: MODE_ADD
;
1789 for (i
= 0; i
< mbuf
->mb_count
; i
++) {
1790 if (MB_TYPE(mbuf
, i
) & MODE_SAVE
)
1793 if (MB_TYPE(mbuf
, i
) & MODE_ADD
) { /* adding or removing? */
1795 strptr_i
= &addstr_i
;
1798 strptr_i
= &remstr_i
;
1801 /* if we're changing oplevels we know the oplevel, pass it on */
1802 if (mbuf
->mb_channel
->mode
.apass
[0]
1803 && (MB_TYPE(mbuf
, i
) & MODE_CHANOP
)
1804 && MB_OPLEVEL(mbuf
, i
) < MAXOPLEVEL
)
1805 *strptr_i
+= ircd_snprintf(0, strptr
+ *strptr_i
, BUFSIZE
- *strptr_i
,
1807 NumNick(MB_CLIENT(mbuf
, i
)),
1808 MB_OPLEVEL(mbuf
, i
));
1810 /* deal with other modes that take clients */
1811 else if (MB_TYPE(mbuf
, i
) & (MODE_CHANOP
| MODE_VOICE
))
1812 build_string(strptr
, strptr_i
, NumNick(MB_CLIENT(mbuf
, i
)), ' ');
1814 /* deal with modes that take strings */
1815 else if (MB_TYPE(mbuf
, i
) & (MODE_KEY
| MODE_BAN
| MODE_APASS
| MODE_UPASS
))
1816 build_string(strptr
, strptr_i
, MB_STRING(mbuf
, i
), 0, ' ');
1819 * deal with the limit. Logic here is complicated; if HACK2 is set,
1820 * we're bouncing the mode, so sense is reversed, and we have to
1821 * include the original limit if it looks like it's being removed
1823 else if ((MB_TYPE(mbuf
, i
) & limitdel
) == limitdel
)
1824 build_string(strptr
, strptr_i
, limitbuf
, 0, ' ');
1827 /* we were told to deop the source */
1828 if (mbuf
->mb_dest
& MODEBUF_DEST_DEOP
) {
1829 addbuf
[addbuf_i
++] = 'o'; /* remember, sense is reversed */
1830 addbuf
[addbuf_i
] = '\0'; /* terminate the string... */
1831 build_string(addstr
, &addstr_i
, NumNick(mbuf
->mb_source
), ' ');
1833 /* mark that we've done this, so we don't do it again */
1834 mbuf
->mb_dest
&= ~MODEBUF_DEST_DEOP
;
1837 if (mbuf
->mb_dest
& MODEBUF_DEST_OPMODE
) {
1838 /* If OPMODE was set, we're propagating the mode as an OPMODE message */
1839 sendcmdto_serv_butone(mbuf
->mb_source
, CMD_OPMODE
, mbuf
->mb_connect
,
1840 "%H %s%s%s%s%s%s", mbuf
->mb_channel
,
1841 rembuf_i
? "-" : "", rembuf
, addbuf_i
? "+" : "",
1842 addbuf
, remstr
, addstr
);
1843 } else if (mbuf
->mb_dest
& MODEBUF_DEST_BOUNCE
) {
1845 * If HACK2 was set, we're bouncing; we send the MODE back to the
1846 * connection we got it from with the senses reversed and a TS of 0;
1849 sendcmdto_one(&me
, CMD_MODE
, mbuf
->mb_connect
, "%H %s%s%s%s%s%s %Tu",
1850 mbuf
->mb_channel
, addbuf_i
? "-" : "", addbuf
,
1851 rembuf_i
? "+" : "", rembuf
, addstr
, remstr
,
1852 mbuf
->mb_channel
->creationtime
);
1855 * We're propagating a normal MODE command to the rest of the network;
1856 * we send the actual channel TS unless this is a HACK3 or a HACK4
1858 if (IsServer(mbuf
->mb_source
))
1859 sendcmdto_serv_butone(mbuf
->mb_source
, CMD_MODE
, mbuf
->mb_connect
,
1860 "%H %s%s%s%s%s%s %Tu", mbuf
->mb_channel
,
1861 rembuf_i
? "-" : "", rembuf
, addbuf_i
? "+" : "",
1862 addbuf
, remstr
, addstr
,
1863 (mbuf
->mb_dest
& MODEBUF_DEST_HACK4
) ? 0 :
1864 mbuf
->mb_channel
->creationtime
);
1866 sendcmdto_serv_butone(mbuf
->mb_source
, CMD_MODE
, mbuf
->mb_connect
,
1867 "%H %s%s%s%s%s%s", mbuf
->mb_channel
,
1868 rembuf_i
? "-" : "", rembuf
, addbuf_i
? "+" : "",
1869 addbuf
, remstr
, addstr
);
1873 /* We've drained the ModeBuf... */
1878 /* reinitialize the mode-with-arg slots */
1879 for (i
= 0; i
< MAXMODEPARAMS
; i
++) {
1880 /* If we saved any, pack them down */
1881 if (MB_TYPE(mbuf
, i
) & MODE_SAVE
) {
1882 mbuf
->mb_modeargs
[mbuf
->mb_count
] = mbuf
->mb_modeargs
[i
];
1883 MB_TYPE(mbuf
, mbuf
->mb_count
) &= ~MODE_SAVE
; /* don't save anymore */
1885 if (mbuf
->mb_count
++ == i
) /* don't overwrite our hard work */
1887 } else if (MB_TYPE(mbuf
, i
) & MODE_FREE
)
1888 MyFree(MB_STRING(mbuf
, i
)); /* free string if needed */
1890 MB_TYPE(mbuf
, i
) = 0;
1891 MB_UINT(mbuf
, i
) = 0;
1894 /* If we're supposed to flush it all, do so--all hail tail recursion */
1895 if (all
&& mbuf
->mb_count
)
1896 return modebuf_flush_int(mbuf
, 1);
1901 /** Initialise a modebuf
1902 * This routine just initializes a ModeBuf structure with the information
1903 * needed and the options given.
1905 * @param mbuf The mode buffer to initialise.
1906 * @param source The client that is performing the mode.
1908 * @param chan The channel that the mode is being performed upon.
1912 modebuf_init(struct ModeBuf
*mbuf
, struct Client
*source
,
1913 struct Client
*connect
, struct Channel
*chan
, unsigned int dest
)
1918 assert(0 != source
);
1922 if (IsLocalChannel(chan
->chname
)) dest
&= ~MODEBUF_DEST_SERVER
;
1926 mbuf
->mb_source
= source
;
1927 mbuf
->mb_connect
= connect
;
1928 mbuf
->mb_channel
= chan
;
1929 mbuf
->mb_dest
= dest
;
1932 /* clear each mode-with-parameter slot */
1933 for (i
= 0; i
< MAXMODEPARAMS
; i
++) {
1934 MB_TYPE(mbuf
, i
) = 0;
1935 MB_UINT(mbuf
, i
) = 0;
1939 /** Append a new mode to a modebuf
1940 * This routine simply adds modes to be added or deleted; do a binary OR
1941 * with either MODE_ADD or MODE_DEL
1943 * @param mbuf Mode buffer
1944 * @param mode MODE_ADD or MODE_DEL OR'd with MODE_PRIVATE etc.
1947 modebuf_mode(struct ModeBuf
*mbuf
, unsigned int mode
)
1950 assert(0 != (mode
& (MODE_ADD
| MODE_DEL
)));
1952 mode
&= (MODE_ADD
| MODE_DEL
| MODE_PRIVATE
| MODE_SECRET
| MODE_MODERATED
|
1953 MODE_TOPICLIMIT
| MODE_INVITEONLY
| MODE_NOPRIVMSGS
| MODE_REGONLY
|
1954 MODE_DELJOINS
| MODE_WASDELJOINS
| MODE_NOQUITPARTS
);
1956 if (!(mode
& ~(MODE_ADD
| MODE_DEL
))) /* don't add empty modes... */
1959 if (mode
& MODE_ADD
) {
1960 mbuf
->mb_rem
&= ~mode
;
1961 mbuf
->mb_add
|= mode
;
1963 mbuf
->mb_add
&= ~mode
;
1964 mbuf
->mb_rem
|= mode
;
1968 /** Append a mode that takes an int argument to the modebuf
1970 * This routine adds a mode to be added or deleted that takes a unsigned
1971 * int parameter; mode may *only* be the relevant mode flag ORed with one
1972 * of MODE_ADD or MODE_DEL
1974 * @param mbuf The mode buffer to append to.
1975 * @param mode The mode to append.
1976 * @param uint The argument to the mode.
1979 modebuf_mode_uint(struct ModeBuf
*mbuf
, unsigned int mode
, unsigned int uint
)
1982 assert(0 != (mode
& (MODE_ADD
| MODE_DEL
)));
1984 if (mode
== (MODE_LIMIT
| MODE_DEL
)) {
1985 mbuf
->mb_rem
|= mode
;
1988 MB_TYPE(mbuf
, mbuf
->mb_count
) = mode
;
1989 MB_UINT(mbuf
, mbuf
->mb_count
) = uint
;
1991 /* when we've reached the maximal count, flush the buffer */
1992 if (++mbuf
->mb_count
>=
1993 (MAXMODEPARAMS
- (mbuf
->mb_dest
& MODEBUF_DEST_DEOP
? 1 : 0)))
1994 modebuf_flush_int(mbuf
, 0);
1997 /** append a string mode
1998 * This routine adds a mode to be added or deleted that takes a string
1999 * parameter; mode may *only* be the relevant mode flag ORed with one of
2000 * MODE_ADD or MODE_DEL
2002 * @param mbuf The mode buffer to append to.
2003 * @param mode The mode to append.
2004 * @param string The string parameter to append.
2005 * @param free If the string should be free'd later.
2008 modebuf_mode_string(struct ModeBuf
*mbuf
, unsigned int mode
, char *string
,
2012 assert(0 != (mode
& (MODE_ADD
| MODE_DEL
)));
2014 MB_TYPE(mbuf
, mbuf
->mb_count
) = mode
| (free
? MODE_FREE
: 0);
2015 MB_STRING(mbuf
, mbuf
->mb_count
) = string
;
2017 /* when we've reached the maximal count, flush the buffer */
2018 if (++mbuf
->mb_count
>=
2019 (MAXMODEPARAMS
- (mbuf
->mb_dest
& MODEBUF_DEST_DEOP
? 1 : 0)))
2020 modebuf_flush_int(mbuf
, 0);
2023 /** Append a mode on a client to a modebuf.
2024 * This routine adds a mode to be added or deleted that takes a client
2025 * parameter; mode may *only* be the relevant mode flag ORed with one of
2026 * MODE_ADD or MODE_DEL
2028 * @param mbuf The modebuf to append the mode to.
2029 * @param mode The mode to append.
2030 * @param client The client argument to append.
2031 * @param oplevel The oplevel the user had or will have
2034 modebuf_mode_client(struct ModeBuf
*mbuf
, unsigned int mode
,
2035 struct Client
*client
, int oplevel
)
2038 assert(0 != (mode
& (MODE_ADD
| MODE_DEL
)));
2040 MB_TYPE(mbuf
, mbuf
->mb_count
) = mode
;
2041 MB_CLIENT(mbuf
, mbuf
->mb_count
) = client
;
2042 MB_OPLEVEL(mbuf
, mbuf
->mb_count
) = oplevel
;
2044 /* when we've reached the maximal count, flush the buffer */
2045 if (++mbuf
->mb_count
>=
2046 (MAXMODEPARAMS
- (mbuf
->mb_dest
& MODEBUF_DEST_DEOP
? 1 : 0)))
2047 modebuf_flush_int(mbuf
, 0);
2050 /** The exported binding for modebuf_flush()
2052 * @param mbuf The mode buffer to flush.
2054 * @see modebuf_flush_int()
2057 modebuf_flush(struct ModeBuf
*mbuf
)
2059 struct Membership
*memb
;
2061 /* Check if MODE_WASDELJOINS should be set */
2062 if (!(mbuf
->mb_channel
->mode
.mode
& (MODE_DELJOINS
| MODE_WASDELJOINS
))
2063 && (mbuf
->mb_rem
& MODE_DELJOINS
)) {
2064 for (memb
= mbuf
->mb_channel
->members
; memb
; memb
= memb
->next_member
) {
2065 if (IsDelayedJoin(memb
)) {
2066 mbuf
->mb_channel
->mode
.mode
|= MODE_WASDELJOINS
;
2067 mbuf
->mb_add
|= MODE_WASDELJOINS
;
2068 mbuf
->mb_rem
&= ~MODE_WASDELJOINS
;
2074 return modebuf_flush_int(mbuf
, 1);
2077 /* This extracts the simple modes contained in mbuf
2079 * @param mbuf The mode buffer to extract the modes from.
2080 * @param buf The string buffer to write the modes into.
2083 modebuf_extract(struct ModeBuf
*mbuf
, char *buf
)
2085 static int flags
[] = {
2086 /* MODE_CHANOP, 'o', */
2087 /* MODE_VOICE, 'v', */
2090 MODE_MODERATED
, 'm',
2091 MODE_TOPICLIMIT
, 't',
2092 MODE_INVITEONLY
, 'i',
2093 MODE_NOPRIVMSGS
, 'n',
2097 /* MODE_BAN, 'b', */
2101 MODE_NOQUITPARTS
, 'u',
2105 int i
, bufpos
= 0, len
;
2107 char *key
= 0, limitbuf
[20];
2108 char *apass
= 0, *upass
= 0;
2117 for (i
= 0; i
< mbuf
->mb_count
; i
++) { /* find keys and limits */
2118 if (MB_TYPE(mbuf
, i
) & MODE_ADD
) {
2119 add
|= MB_TYPE(mbuf
, i
) & (MODE_KEY
| MODE_LIMIT
| MODE_APASS
| MODE_UPASS
);
2121 if (MB_TYPE(mbuf
, i
) & MODE_KEY
) /* keep strings */
2122 key
= MB_STRING(mbuf
, i
);
2123 else if (MB_TYPE(mbuf
, i
) & MODE_LIMIT
)
2124 ircd_snprintf(0, limitbuf
, sizeof(limitbuf
), "%u", MB_UINT(mbuf
, i
));
2125 else if (MB_TYPE(mbuf
, i
) & MODE_UPASS
)
2126 upass
= MB_STRING(mbuf
, i
);
2127 else if (MB_TYPE(mbuf
, i
) & MODE_APASS
)
2128 apass
= MB_STRING(mbuf
, i
);
2135 buf
[bufpos
++] = '+'; /* start building buffer */
2137 for (flag_p
= flags
; flag_p
[0]; flag_p
+= 2)
2139 buf
[bufpos
++] = flag_p
[1];
2141 for (i
= 0, len
= bufpos
; i
< len
; i
++) {
2143 build_string(buf
, &bufpos
, key
, 0, ' ');
2144 else if (buf
[i
] == 'l')
2145 build_string(buf
, &bufpos
, limitbuf
, 0, ' ');
2146 else if (buf
[i
] == 'U')
2147 build_string(buf
, &bufpos
, upass
, 0, ' ');
2148 else if (buf
[i
] == 'A')
2149 build_string(buf
, &bufpos
, apass
, 0, ' ');
2157 /** Simple function to invalidate bans
2159 * This function sets all bans as being valid.
2161 * @param chan The channel to operate on.
2164 mode_ban_invalidate(struct Channel
*chan
)
2166 struct Membership
*member
;
2168 for (member
= chan
->members
; member
; member
= member
->next_member
)
2169 ClearBanValid(member
);
2172 /** Simple function to drop invite structures
2174 * Remove all the invites on the channel.
2176 * @param chan Channel to remove invites from.
2180 mode_invite_clear(struct Channel
*chan
)
2182 while (chan
->invites
)
2183 del_invite(chan
->invites
->value
.cptr
, chan
);
2186 /* What we've done for mode_parse so far... */
2187 #define DONE_LIMIT 0x01 /**< We've set the limit */
2188 #define DONE_KEY 0x02 /**< We've set the key */
2189 #define DONE_BANLIST 0x04 /**< We've sent the ban list */
2190 #define DONE_NOTOPER 0x08 /**< We've sent a "Not oper" error */
2191 #define DONE_BANCLEAN 0x10 /**< We've cleaned bans... */
2192 #define DONE_UPASS 0x20 /**< We've set user pass */
2193 #define DONE_APASS 0x40 /**< We've set admin pass */
2196 struct ModeBuf
*mbuf
;
2197 struct Client
*cptr
;
2198 struct Client
*sptr
;
2199 struct Channel
*chptr
;
2200 struct Membership
*member
;
2211 struct Ban banlist
[MAXPARA
];
2214 unsigned short oplevel
;
2215 struct Client
*client
;
2216 } cli_change
[MAXPARA
];
2219 /** Helper function to send "Not oper" or "Not member" messages
2220 * Here's a helper function to deal with sending along "Not oper" or
2221 * "Not member" messages
2223 * @param state Parsing State object
2226 send_notoper(struct ParseState
*state
)
2228 if (state
->done
& DONE_NOTOPER
)
2231 send_reply(state
->sptr
, (state
->flags
& MODE_PARSE_NOTOPER
) ?
2232 ERR_CHANOPRIVSNEEDED
: ERR_NOTONCHANNEL
, state
->chptr
->chname
);
2234 state
->done
|= DONE_NOTOPER
;
2238 * Helper function to convert limits
2240 * @param state Parsing state object.
2244 mode_parse_limit(struct ParseState
*state
, int *flag_p
)
2246 unsigned int t_limit
;
2248 if (state
->dir
== MODE_ADD
) { /* convert arg only if adding limit */
2249 if (MyUser(state
->sptr
) && state
->max_args
<= 0) /* too many args? */
2252 if (state
->parc
<= 0) { /* warn if not enough args */
2253 if (MyUser(state
->sptr
))
2254 need_more_params(state
->sptr
, "MODE +l");
2258 t_limit
= strtoul(state
->parv
[state
->args_used
++], 0, 10); /* grab arg */
2262 if ((int)t_limit
<0) /* don't permit a negative limit */
2265 if (!(state
->flags
& MODE_PARSE_WIPEOUT
) &&
2266 (!t_limit
|| t_limit
== state
->chptr
->mode
.limit
))
2269 t_limit
= state
->chptr
->mode
.limit
;
2271 /* If they're not an oper, they can't change modes */
2272 if (state
->flags
& (MODE_PARSE_NOTOPER
| MODE_PARSE_NOTMEMBER
)) {
2273 send_notoper(state
);
2277 /* Can't remove a limit that's not there */
2278 if (state
->dir
== MODE_DEL
&& !state
->chptr
->mode
.limit
)
2281 /* Skip if this is a burst and a lower limit than this is set already */
2282 if ((state
->flags
& MODE_PARSE_BURST
) &&
2283 (state
->chptr
->mode
.mode
& flag_p
[0]) &&
2284 (state
->chptr
->mode
.limit
< t_limit
))
2287 if (state
->done
& DONE_LIMIT
) /* allow limit to be set only once */
2289 state
->done
|= DONE_LIMIT
;
2294 modebuf_mode_uint(state
->mbuf
, state
->dir
| flag_p
[0], t_limit
);
2296 if (state
->flags
& MODE_PARSE_SET
) { /* set the limit */
2297 if (state
->dir
& MODE_ADD
) {
2298 state
->chptr
->mode
.mode
|= flag_p
[0];
2299 state
->chptr
->mode
.limit
= t_limit
;
2301 state
->chptr
->mode
.mode
&= ~flag_p
[0];
2302 state
->chptr
->mode
.limit
= 0;
2307 /** Helper function to clean key-like parameters. */
2313 while (*s
> ' ' && *s
!= ':' && *s
!= ',' && t_len
--)
2319 * Helper function to convert keys
2322 mode_parse_key(struct ParseState
*state
, int *flag_p
)
2326 if (MyUser(state
->sptr
) && state
->max_args
<= 0) /* drop if too many args */
2329 if (state
->parc
<= 0) { /* warn if not enough args */
2330 if (MyUser(state
->sptr
))
2331 need_more_params(state
->sptr
, state
->dir
== MODE_ADD
? "MODE +k" :
2336 t_str
= state
->parv
[state
->args_used
++]; /* grab arg */
2340 /* If they're not an oper, they can't change modes */
2341 if (state
->flags
& (MODE_PARSE_NOTOPER
| MODE_PARSE_NOTMEMBER
)) {
2342 send_notoper(state
);
2346 if (state
->done
& DONE_KEY
) /* allow key to be set only once */
2348 state
->done
|= DONE_KEY
;
2350 /* clean up the key string */
2352 if (!*t_str
|| *t_str
== ':') { /* warn if empty */
2353 if (MyUser(state
->sptr
))
2354 need_more_params(state
->sptr
, state
->dir
== MODE_ADD
? "MODE +k" :
2362 /* Skip if this is a burst, we have a key already and the new key is
2363 * after the old one alphabetically */
2364 if ((state
->flags
& MODE_PARSE_BURST
) &&
2365 *(state
->chptr
->mode
.key
) &&
2366 ircd_strcmp(state
->chptr
->mode
.key
, t_str
) <= 0)
2369 /* can't add a key if one is set, nor can one remove the wrong key */
2370 if (!(state
->flags
& MODE_PARSE_FORCE
))
2371 if ((state
->dir
== MODE_ADD
&& *state
->chptr
->mode
.key
) ||
2372 (state
->dir
== MODE_DEL
&&
2373 ircd_strcmp(state
->chptr
->mode
.key
, t_str
))) {
2374 send_reply(state
->sptr
, ERR_KEYSET
, state
->chptr
->chname
);
2378 if (!(state
->flags
& MODE_PARSE_WIPEOUT
) && state
->dir
== MODE_ADD
&&
2379 !ircd_strcmp(state
->chptr
->mode
.key
, t_str
))
2380 return; /* no key change */
2382 if (state
->flags
& MODE_PARSE_BOUNCE
) {
2383 if (*state
->chptr
->mode
.key
) /* reset old key */
2384 modebuf_mode_string(state
->mbuf
, MODE_DEL
| flag_p
[0],
2385 state
->chptr
->mode
.key
, 0);
2386 else /* remove new bogus key */
2387 modebuf_mode_string(state
->mbuf
, MODE_ADD
| flag_p
[0], t_str
, 0);
2388 } else /* send new key */
2389 modebuf_mode_string(state
->mbuf
, state
->dir
| flag_p
[0], t_str
, 0);
2391 if (state
->flags
& MODE_PARSE_SET
) {
2392 if (state
->dir
== MODE_DEL
) /* remove the old key */
2393 *state
->chptr
->mode
.key
= '\0';
2394 else if (!state
->chptr
->mode
.key
[0]
2395 || ircd_strcmp(t_str
, state
->chptr
->mode
.key
) < 0)
2396 ircd_strncpy(state
->chptr
->mode
.key
, t_str
, KEYLEN
);
2401 * Helper function to convert user passes
2404 mode_parse_upass(struct ParseState
*state
, int *flag_p
)
2408 if (MyUser(state
->sptr
) && state
->max_args
<= 0) /* drop if too many args */
2411 if (state
->parc
<= 0) { /* warn if not enough args */
2412 if (MyUser(state
->sptr
))
2413 need_more_params(state
->sptr
, state
->dir
== MODE_ADD
? "MODE +U" :
2418 t_str
= state
->parv
[state
->args_used
++]; /* grab arg */
2422 /* If they're not an oper, they can't change modes */
2423 if (state
->flags
& (MODE_PARSE_NOTOPER
| MODE_PARSE_NOTMEMBER
)) {
2424 send_notoper(state
);
2428 /* If a non-service user is trying to force it, refuse. */
2429 if (state
->flags
& MODE_PARSE_FORCE
&& MyUser(state
->sptr
)
2430 && !HasPriv(state
->sptr
, PRIV_APASS_OPMODE
)) {
2431 send_reply(state
->sptr
, ERR_NOTMANAGER
, state
->chptr
->chname
,
2432 state
->chptr
->chname
);
2436 /* If they are not the channel manager, they are not allowed to change it */
2437 if (MyUser(state
->sptr
) && !(state
->flags
& MODE_PARSE_FORCE
|| IsChannelManager(state
->member
))) {
2438 if (*state
->chptr
->mode
.apass
) {
2439 send_reply(state
->sptr
, ERR_NOTMANAGER
, state
->chptr
->chname
,
2440 state
->chptr
->chname
);
2442 send_reply(state
->sptr
, ERR_NOMANAGER
, state
->chptr
->chname
);
2447 if (state
->done
& DONE_UPASS
) /* allow upass to be set only once */
2449 state
->done
|= DONE_UPASS
;
2451 /* clean up the upass string */
2453 if (!*t_str
|| *t_str
== ':') { /* warn if empty */
2454 if (MyUser(state
->sptr
))
2455 need_more_params(state
->sptr
, state
->dir
== MODE_ADD
? "MODE +U" :
2463 if (!(state
->flags
& MODE_PARSE_FORCE
)) {
2464 /* can't add the upass while apass is not set */
2465 if (state
->dir
== MODE_ADD
&& !*state
->chptr
->mode
.apass
) {
2466 send_reply(state
->sptr
, ERR_UPASSNOTSET
, state
->chptr
->chname
, state
->chptr
->chname
);
2469 /* cannot set a +U password that is the same as +A */
2470 if (state
->dir
== MODE_ADD
&& !ircd_strcmp(state
->chptr
->mode
.apass
, t_str
)) {
2471 send_reply(state
->sptr
, ERR_UPASS_SAME_APASS
, state
->chptr
->chname
);
2474 /* can't add a upass if one is set, nor can one remove the wrong upass */
2475 if ((state
->dir
== MODE_ADD
&& *state
->chptr
->mode
.upass
) ||
2476 (state
->dir
== MODE_DEL
&&
2477 ircd_strcmp(state
->chptr
->mode
.upass
, t_str
))) {
2478 send_reply(state
->sptr
, ERR_KEYSET
, state
->chptr
->chname
);
2483 if (!(state
->flags
& MODE_PARSE_WIPEOUT
) && state
->dir
== MODE_ADD
&&
2484 !ircd_strcmp(state
->chptr
->mode
.upass
, t_str
))
2485 return; /* no upass change */
2487 if (state
->flags
& MODE_PARSE_BOUNCE
) {
2488 if (*state
->chptr
->mode
.upass
) /* reset old upass */
2489 modebuf_mode_string(state
->mbuf
, MODE_DEL
| flag_p
[0],
2490 state
->chptr
->mode
.upass
, 0);
2491 else /* remove new bogus upass */
2492 modebuf_mode_string(state
->mbuf
, MODE_ADD
| flag_p
[0], t_str
, 0);
2493 } else /* send new upass */
2494 modebuf_mode_string(state
->mbuf
, state
->dir
| flag_p
[0], t_str
, 0);
2496 if (state
->flags
& MODE_PARSE_SET
) {
2497 if (state
->dir
== MODE_DEL
) /* remove the old upass */
2498 *state
->chptr
->mode
.upass
= '\0';
2499 else if (state
->chptr
->mode
.upass
[0] == '\0'
2500 || ircd_strcmp(t_str
, state
->chptr
->mode
.upass
) < 0)
2501 ircd_strncpy(state
->chptr
->mode
.upass
, t_str
, KEYLEN
);
2506 * Helper function to convert admin passes
2509 mode_parse_apass(struct ParseState
*state
, int *flag_p
)
2511 struct Membership
*memb
;
2514 if (MyUser(state
->sptr
) && state
->max_args
<= 0) /* drop if too many args */
2517 if (state
->parc
<= 0) { /* warn if not enough args */
2518 if (MyUser(state
->sptr
))
2519 need_more_params(state
->sptr
, state
->dir
== MODE_ADD
? "MODE +A" :
2524 t_str
= state
->parv
[state
->args_used
++]; /* grab arg */
2528 /* If they're not an oper, they can't change modes */
2529 if (state
->flags
& (MODE_PARSE_NOTOPER
| MODE_PARSE_NOTMEMBER
)) {
2530 send_notoper(state
);
2534 /* If a non-service user is trying to force it, refuse. */
2535 if (state
->flags
& MODE_PARSE_FORCE
&& MyUser(state
->sptr
)
2536 && !HasPriv(state
->sptr
, PRIV_APASS_OPMODE
)) {
2537 send_reply(state
->sptr
, ERR_NOTMANAGER
, state
->chptr
->chname
,
2538 state
->chptr
->chname
);
2542 /* Don't allow to change the Apass if the channel is older than 48 hours. */
2543 if (MyUser(state
->sptr
)
2544 && TStime() - state
->chptr
->creationtime
>= 172800
2545 && !IsAnOper(state
->sptr
)) {
2546 send_reply(state
->sptr
, ERR_CHANSECURED
, state
->chptr
->chname
);
2550 /* If they are not the channel manager, they are not allowed to change it */
2551 if (MyUser(state
->sptr
) && !(state
->flags
& MODE_PARSE_FORCE
|| IsChannelManager(state
->member
))) {
2552 if (*state
->chptr
->mode
.apass
) {
2553 send_reply(state
->sptr
, ERR_NOTMANAGER
, state
->chptr
->chname
,
2554 state
->chptr
->chname
);
2556 send_reply(state
->sptr
, ERR_NOMANAGER
, state
->chptr
->chname
);
2561 if (state
->done
& DONE_APASS
) /* allow apass to be set only once */
2563 state
->done
|= DONE_APASS
;
2565 /* clean up the apass string */
2567 if (!*t_str
|| *t_str
== ':') { /* warn if empty */
2568 if (MyUser(state
->sptr
))
2569 need_more_params(state
->sptr
, state
->dir
== MODE_ADD
? "MODE +A" :
2577 if (!(state
->flags
& MODE_PARSE_FORCE
)) {
2578 /* can't remove the apass while upass is still set */
2579 if (state
->dir
== MODE_DEL
&& *state
->chptr
->mode
.upass
) {
2580 send_reply(state
->sptr
, ERR_UPASSSET
, state
->chptr
->chname
, state
->chptr
->chname
);
2583 /* can't add an apass if one is set, nor can one remove the wrong apass */
2584 if ((state
->dir
== MODE_ADD
&& *state
->chptr
->mode
.apass
) ||
2585 (state
->dir
== MODE_DEL
&& ircd_strcmp(state
->chptr
->mode
.apass
, t_str
))) {
2586 send_reply(state
->sptr
, ERR_KEYSET
, state
->chptr
->chname
);
2591 if (!(state
->flags
& MODE_PARSE_WIPEOUT
) && state
->dir
== MODE_ADD
&&
2592 !ircd_strcmp(state
->chptr
->mode
.apass
, t_str
))
2593 return; /* no apass change */
2595 if (state
->flags
& MODE_PARSE_BOUNCE
) {
2596 if (*state
->chptr
->mode
.apass
) /* reset old apass */
2597 modebuf_mode_string(state
->mbuf
, MODE_DEL
| flag_p
[0],
2598 state
->chptr
->mode
.apass
, 0);
2599 else /* remove new bogus apass */
2600 modebuf_mode_string(state
->mbuf
, MODE_ADD
| flag_p
[0], t_str
, 0);
2601 } else /* send new apass */
2602 modebuf_mode_string(state
->mbuf
, state
->dir
| flag_p
[0], t_str
, 0);
2604 if (state
->flags
& MODE_PARSE_SET
) {
2605 if (state
->dir
== MODE_ADD
) { /* set the new apass */
2606 /* Only accept the new apass if there is no current apass
2607 * (e.g. when a user sets it) or the new one is "less" than the
2608 * old (for resolving conflicts during burst).
2610 if (state
->chptr
->mode
.apass
[0] == '\0'
2611 || ircd_strcmp(t_str
, state
->chptr
->mode
.apass
) < 0)
2612 ircd_strncpy(state
->chptr
->mode
.apass
, t_str
, KEYLEN
);
2613 /* Make it VERY clear to the user that this is a one-time password */
2614 if (MyUser(state
->sptr
)) {
2615 send_reply(state
->sptr
, RPL_APASSWARN_SET
, state
->chptr
->mode
.apass
);
2616 send_reply(state
->sptr
, RPL_APASSWARN_SECRET
, state
->chptr
->chname
,
2617 state
->chptr
->mode
.apass
);
2619 /* Give the channel manager level 0 ops. */
2620 if (!(state
->flags
& MODE_PARSE_FORCE
) && IsChannelManager(state
->member
))
2621 SetOpLevel(state
->member
, 0);
2622 } else { /* remove the old apass */
2623 *state
->chptr
->mode
.apass
= '\0';
2624 if (MyUser(state
->sptr
))
2625 send_reply(state
->sptr
, RPL_APASSWARN_CLEAR
);
2626 /* Revert everyone to MAXOPLEVEL. */
2627 for (memb
= state
->chptr
->members
; memb
; memb
= memb
->next_member
) {
2628 if (memb
->status
& MODE_CHANOP
)
2629 SetOpLevel(memb
, MAXOPLEVEL
);
2635 /** Compare one ban's extent to another.
2636 * This works very similarly to mmatch() but it knows about CIDR masks
2637 * and ban exceptions. If both bans are CIDR-based, compare their
2638 * address bits; otherwise, use mmatch().
2639 * @param[in] old_ban One ban.
2640 * @param[in] new_ban Another ban.
2641 * @return Zero if \a old_ban is a superset of \a new_ban, non-zero otherwise.
2644 bmatch(struct Ban
*old_ban
, struct Ban
*new_ban
)
2647 assert(old_ban
!= NULL
);
2648 assert(new_ban
!= NULL
);
2649 /* A ban is never treated as a superset of an exception. */
2650 if (!(old_ban
->flags
& BAN_EXCEPTION
)
2651 && (new_ban
->flags
& BAN_EXCEPTION
))
2653 /* If either is not an address mask, match the text masks. */
2654 if ((old_ban
->flags
& new_ban
->flags
& BAN_IPMASK
) == 0)
2655 return mmatch(old_ban
->banstr
, new_ban
->banstr
);
2656 /* If the old ban has a longer prefix than new, it cannot be a superset. */
2657 if (old_ban
->addrbits
> new_ban
->addrbits
)
2659 /* Compare the masks before the hostname part. */
2660 old_ban
->banstr
[old_ban
->nu_len
] = new_ban
->banstr
[new_ban
->nu_len
] = '\0';
2661 res
= mmatch(old_ban
->banstr
, new_ban
->banstr
);
2662 old_ban
->banstr
[old_ban
->nu_len
] = new_ban
->banstr
[new_ban
->nu_len
] = '@';
2665 /* Compare the addresses. */
2666 return !ipmask_check(&new_ban
->address
, &old_ban
->address
, old_ban
->addrbits
);
2669 /** Add a ban from a ban list and mark bans that should be removed
2670 * because they overlap.
2672 * There are three invariants for a ban list. First, no ban may be
2673 * more specific than another ban. Second, no exception may be more
2674 * specific than another exception. Finally, no ban may be more
2675 * specific than any exception.
2677 * @param[in,out] banlist Pointer to head of list.
2678 * @param[in] newban Ban (or exception) to add (or remove).
2679 * @param[in] do_free If non-zero, free \a newban on failure.
2680 * @return Zero if \a newban could be applied, non-zero if not.
2682 int apply_ban(struct Ban
**banlist
, struct Ban
*newban
, int do_free
)
2687 assert(newban
->flags
& (BAN_ADD
|BAN_DEL
));
2688 if (newban
->flags
& BAN_ADD
) {
2690 /* If a less specific entry is found, fail. */
2691 for (ban
= *banlist
; ban
; ban
= ban
->next
) {
2692 if (!bmatch(ban
, newban
)) {
2697 if (!(ban
->flags
& (BAN_OVERLAPPED
|BAN_DEL
))) {
2699 totlen
+= strlen(ban
->banstr
);
2702 /* Mark more specific entries and add this one to the end of the list. */
2703 while ((ban
= *banlist
) != NULL
) {
2704 if (!bmatch(newban
, ban
)) {
2705 ban
->flags
|= BAN_OVERLAPPED
| BAN_DEL
;
2707 banlist
= &ban
->next
;
2711 } else if (newban
->flags
& BAN_DEL
) {
2712 size_t remove_count
= 0;
2713 /* Mark more specific entries. */
2714 for (ban
= *banlist
; ban
; ban
= ban
->next
) {
2715 if (!bmatch(newban
, ban
)) {
2716 ban
->flags
|= BAN_OVERLAPPED
| BAN_DEL
;
2722 /* If no matches were found, fail. */
2733 * Helper function to convert bans
2736 mode_parse_ban(struct ParseState
*state
, int *flag_p
)
2739 struct Ban
*ban
, *newban
;
2741 if (state
->parc
<= 0) { /* Not enough args, send ban list */
2742 if (MyUser(state
->sptr
) && !(state
->done
& DONE_BANLIST
)) {
2743 send_ban_list(state
->sptr
, state
->chptr
);
2744 state
->done
|= DONE_BANLIST
;
2750 if (MyUser(state
->sptr
) && state
->max_args
<= 0) /* drop if too many args */
2753 t_str
= state
->parv
[state
->args_used
++]; /* grab arg */
2757 /* If they're not an oper, they can't change modes */
2758 if (state
->flags
& (MODE_PARSE_NOTOPER
| MODE_PARSE_NOTMEMBER
)) {
2759 send_notoper(state
);
2763 if ((s
= strchr(t_str
, ' ')))
2766 if (!*t_str
|| *t_str
== ':') { /* warn if empty */
2767 if (MyUser(state
->sptr
))
2768 need_more_params(state
->sptr
, state
->dir
== MODE_ADD
? "MODE +b" :
2773 /* Clear all ADD/DEL/OVERLAPPED flags from ban list. */
2774 if (!(state
->done
& DONE_BANCLEAN
)) {
2775 for (ban
= state
->chptr
->banlist
; ban
; ban
= ban
->next
)
2776 ban
->flags
&= ~(BAN_ADD
| BAN_DEL
| BAN_OVERLAPPED
);
2777 state
->done
|= DONE_BANCLEAN
;
2780 /* remember the ban for the moment... */
2781 newban
= state
->banlist
+ (state
->numbans
++);
2783 newban
->flags
= ((state
->dir
== MODE_ADD
) ? BAN_ADD
: BAN_DEL
)
2784 | (*flag_p
== MODE_BAN
? 0 : BAN_EXCEPTION
);
2785 set_ban_mask(newban
, collapse(pretty_mask(t_str
)));
2786 ircd_strncpy(newban
->who
, IsUser(state
->sptr
) ? cli_name(state
->sptr
) : "*", NICKLEN
);
2787 newban
->when
= TStime();
2788 apply_ban(&state
->chptr
->banlist
, newban
, 0);
2792 * This is the bottom half of the ban processor
2795 mode_process_bans(struct ParseState
*state
)
2797 struct Ban
*ban
, *newban
, *prevban
, *nextban
;
2803 for (prevban
= 0, ban
= state
->chptr
->banlist
; ban
; ban
= nextban
) {
2805 banlen
= strlen(ban
->banstr
);
2807 nextban
= ban
->next
;
2809 if ((ban
->flags
& (BAN_DEL
| BAN_ADD
)) == (BAN_DEL
| BAN_ADD
)) {
2811 prevban
->next
= 0; /* Break the list; ban isn't a real ban */
2813 state
->chptr
->banlist
= 0;
2819 } else if (ban
->flags
& BAN_DEL
) { /* Deleted a ban? */
2821 DupString(bandup
, ban
->banstr
);
2822 modebuf_mode_string(state
->mbuf
, MODE_DEL
| MODE_BAN
,
2825 if (state
->flags
& MODE_PARSE_SET
) { /* Ok, make it take effect */
2826 if (prevban
) /* clip it out of the list... */
2827 prevban
->next
= ban
->next
;
2829 state
->chptr
->banlist
= ban
->next
;
2836 continue; /* next ban; keep prevban like it is */
2838 ban
->flags
&= BAN_IPMASK
; /* unset other flags */
2839 } else if (ban
->flags
& BAN_ADD
) { /* adding a ban? */
2841 prevban
->next
= 0; /* Break the list; ban isn't a real ban */
2843 state
->chptr
->banlist
= 0;
2845 /* If we're supposed to ignore it, do so. */
2846 if (ban
->flags
& BAN_OVERLAPPED
&&
2847 !(state
->flags
& MODE_PARSE_BOUNCE
)) {
2851 if (state
->flags
& MODE_PARSE_SET
&& MyUser(state
->sptr
) &&
2852 (len
> (feature_int(FEAT_AVBANLEN
) * feature_int(FEAT_MAXBANS
)) ||
2853 count
> feature_int(FEAT_MAXBANS
))) {
2854 send_reply(state
->sptr
, ERR_BANLISTFULL
, state
->chptr
->chname
,
2860 /* add the ban to the buffer */
2861 DupString(bandup
, ban
->banstr
);
2862 modebuf_mode_string(state
->mbuf
, MODE_ADD
| MODE_BAN
,
2865 if (state
->flags
& MODE_PARSE_SET
) { /* create a new ban */
2866 newban
= make_ban(ban
->banstr
);
2867 strcpy(newban
->who
, ban
->who
);
2868 newban
->when
= ban
->when
;
2869 newban
->flags
= ban
->flags
& BAN_IPMASK
;
2871 newban
->next
= state
->chptr
->banlist
; /* and link it in */
2872 state
->chptr
->banlist
= newban
;
2881 } /* for (prevban = 0, ban = state->chptr->banlist; ban; ban = nextban) { */
2883 if (changed
) /* if we changed the ban list, we must invalidate the bans */
2884 mode_ban_invalidate(state
->chptr
);
2888 * Helper function to process client changes
2891 mode_parse_client(struct ParseState
*state
, int *flag_p
)
2894 struct Client
*acptr
;
2895 struct Membership
*member
;
2896 int oplevel
= MAXOPLEVEL
+ 1;
2899 if (MyUser(state
->sptr
) && state
->max_args
<= 0) /* drop if too many args */
2902 if (state
->parc
<= 0) /* return if not enough args */
2905 t_str
= state
->parv
[state
->args_used
++]; /* grab arg */
2909 /* If they're not an oper, they can't change modes */
2910 if (state
->flags
& (MODE_PARSE_NOTOPER
| MODE_PARSE_NOTMEMBER
)) {
2911 send_notoper(state
);
2915 if (MyUser(state
->sptr
)) /* find client we're manipulating */
2916 acptr
= find_chasing(state
->sptr
, t_str
, NULL
);
2918 if (t_str
[5] == ':') {
2920 oplevel
= atoi(t_str
+ 6);
2922 acptr
= findNUser(t_str
);
2926 return; /* find_chasing() already reported an error to the user */
2928 for (i
= 0; i
< MAXPARA
; i
++) /* find an element to stick them in */
2929 if (!state
->cli_change
[i
].flag
|| (state
->cli_change
[i
].client
== acptr
&&
2930 state
->cli_change
[i
].flag
& flag_p
[0]))
2931 break; /* found a slot */
2933 /* If we are going to bounce this deop, mark the correct oplevel. */
2934 if (state
->flags
& MODE_PARSE_BOUNCE
2935 && state
->dir
== MODE_DEL
2936 && flag_p
[0] == MODE_CHANOP
2937 && (member
= find_member_link(state
->chptr
, acptr
)))
2938 oplevel
= OpLevel(member
);
2940 /* Store what we're doing to them */
2941 state
->cli_change
[i
].flag
= state
->dir
| flag_p
[0];
2942 state
->cli_change
[i
].oplevel
= oplevel
;
2943 state
->cli_change
[i
].client
= acptr
;
2947 * Helper function to process the changed client list
2950 mode_process_clients(struct ParseState
*state
)
2953 struct Membership
*member
;
2955 for (i
= 0; state
->cli_change
[i
].flag
; i
++) {
2956 assert(0 != state
->cli_change
[i
].client
);
2958 /* look up member link */
2959 if (!(member
= find_member_link(state
->chptr
,
2960 state
->cli_change
[i
].client
)) ||
2961 (MyUser(state
->sptr
) && IsZombie(member
))) {
2962 if (MyUser(state
->sptr
))
2963 send_reply(state
->sptr
, ERR_USERNOTINCHANNEL
,
2964 cli_name(state
->cli_change
[i
].client
),
2965 state
->chptr
->chname
);
2969 if ((state
->cli_change
[i
].flag
& MODE_ADD
&&
2970 (state
->cli_change
[i
].flag
& member
->status
)) ||
2971 (state
->cli_change
[i
].flag
& MODE_DEL
&&
2972 !(state
->cli_change
[i
].flag
& member
->status
)))
2973 continue; /* no change made, don't do anything */
2975 /* see if the deop is allowed */
2976 if ((state
->cli_change
[i
].flag
& (MODE_DEL
| MODE_CHANOP
)) ==
2977 (MODE_DEL
| MODE_CHANOP
)) {
2978 /* prevent +k users from being deopped */
2979 if (IsChannelService(state
->cli_change
[i
].client
)) {
2980 if (state
->flags
& MODE_PARSE_FORCE
) /* it was forced */
2981 sendto_opmask_butone(0, SNO_HACK4
, "Deop of +k user on %H by %s",
2983 (IsServer(state
->sptr
) ? cli_name(state
->sptr
) :
2984 cli_name((cli_user(state
->sptr
))->server
)));
2986 else if (MyUser(state
->sptr
) && state
->flags
& MODE_PARSE_SET
) {
2987 send_reply(state
->sptr
, ERR_ISCHANSERVICE
,
2988 cli_name(state
->cli_change
[i
].client
),
2989 state
->chptr
->chname
);
2994 /* check deop for local user */
2995 if (MyUser(state
->sptr
)) {
2997 /* don't allow local opers to be deopped on local channels */
2998 if (state
->cli_change
[i
].client
!= state
->sptr
&&
2999 IsLocalChannel(state
->chptr
->chname
) &&
3000 HasPriv(state
->cli_change
[i
].client
, PRIV_DEOP_LCHAN
)) {
3001 send_reply(state
->sptr
, ERR_ISOPERLCHAN
,
3002 cli_name(state
->cli_change
[i
].client
),
3003 state
->chptr
->chname
);
3007 /* don't allow to deop members with an op level that is <= our own level */
3008 if (state
->sptr
!= state
->cli_change
[i
].client
/* but allow to deop oneself */
3009 && state
->chptr
->mode
.apass
[0]
3011 && OpLevel(member
) <= OpLevel(state
->member
)) {
3012 int equal
= (OpLevel(member
) == OpLevel(state
->member
));
3013 send_reply(state
->sptr
, ERR_NOTLOWEROPLEVEL
,
3014 cli_name(state
->cli_change
[i
].client
),
3015 state
->chptr
->chname
,
3016 OpLevel(state
->member
), OpLevel(member
),
3017 "deop", equal
? "the same" : "a higher");
3023 /* set op-level of member being opped */
3024 if ((state
->cli_change
[i
].flag
& (MODE_ADD
| MODE_CHANOP
)) ==
3025 (MODE_ADD
| MODE_CHANOP
)) {
3026 /* If a valid oplevel was specified, use it.
3027 * Otherwise, if being opped by an outsider, get MAXOPLEVEL.
3028 * Otherwise, if not an apass channel, or state->member has
3029 * MAXOPLEVEL, get oplevel MAXOPLEVEL.
3030 * Otherwise, get state->member's oplevel+1.
3032 if (state
->cli_change
[i
].oplevel
<= MAXOPLEVEL
)
3033 SetOpLevel(member
, state
->cli_change
[i
].oplevel
);
3034 else if (!state
->member
)
3035 SetOpLevel(member
, MAXOPLEVEL
);
3036 else if (!state
->chptr
->mode
.apass
[0] || OpLevel(state
->member
) == MAXOPLEVEL
)
3037 SetOpLevel(member
, MAXOPLEVEL
);
3039 SetOpLevel(member
, OpLevel(state
->member
) + 1);
3042 /* actually effect the change */
3043 if (state
->flags
& MODE_PARSE_SET
) {
3044 if (state
->cli_change
[i
].flag
& MODE_ADD
) {
3045 if (IsDelayedJoin(member
))
3046 RevealDelayedJoin(member
);
3047 member
->status
|= (state
->cli_change
[i
].flag
&
3048 (MODE_CHANOP
| MODE_VOICE
));
3049 if (state
->cli_change
[i
].flag
& MODE_CHANOP
)
3050 ClearDeopped(member
);
3052 member
->status
&= ~(state
->cli_change
[i
].flag
&
3053 (MODE_CHANOP
| MODE_VOICE
));
3056 /* accumulate the change */
3057 modebuf_mode_client(state
->mbuf
, state
->cli_change
[i
].flag
,
3058 state
->cli_change
[i
].client
,
3059 state
->cli_change
[i
].oplevel
);
3060 } /* for (i = 0; state->cli_change[i].flags; i++) */
3064 * Helper function to process the simple modes
3067 mode_parse_mode(struct ParseState
*state
, int *flag_p
)
3069 /* If they're not an oper, they can't change modes */
3070 if (state
->flags
& (MODE_PARSE_NOTOPER
| MODE_PARSE_NOTMEMBER
)) {
3071 send_notoper(state
);
3078 if (state
->dir
== MODE_ADD
) {
3079 state
->add
|= flag_p
[0];
3080 state
->del
&= ~flag_p
[0];
3082 if (flag_p
[0] & MODE_SECRET
) {
3083 state
->add
&= ~MODE_PRIVATE
;
3084 state
->del
|= MODE_PRIVATE
;
3085 } else if (flag_p
[0] & MODE_PRIVATE
) {
3086 state
->add
&= ~MODE_SECRET
;
3087 state
->del
|= MODE_SECRET
;
3089 if (flag_p
[0] & MODE_DELJOINS
) {
3090 state
->add
&= ~MODE_WASDELJOINS
;
3091 state
->del
|= MODE_WASDELJOINS
;
3094 state
->add
&= ~flag_p
[0];
3095 state
->del
|= flag_p
[0];
3098 assert(0 == (state
->add
& state
->del
));
3099 assert((MODE_SECRET
| MODE_PRIVATE
) !=
3100 (state
->add
& (MODE_SECRET
| MODE_PRIVATE
)));
3104 * This routine is intended to parse MODE or OPMODE commands and effect the
3105 * changes (or just build the bounce buffer). We pass the starting offset
3109 mode_parse(struct ModeBuf
*mbuf
, struct Client
*cptr
, struct Client
*sptr
,
3110 struct Channel
*chptr
, int parc
, char *parv
[], unsigned int flags
,
3111 struct Membership
* member
)
3113 static int chan_flags
[] = {
3118 MODE_MODERATED
, 'm',
3119 MODE_TOPICLIMIT
, 't',
3120 MODE_INVITEONLY
, 'i',
3121 MODE_NOPRIVMSGS
, 'n',
3129 MODE_NOQUITPARTS
, 'u',
3136 unsigned int t_mode
;
3138 struct ParseState state
;
3149 state
.chptr
= chptr
;
3150 state
.member
= member
;
3153 state
.flags
= flags
;
3154 state
.dir
= MODE_ADD
;
3158 state
.args_used
= 0;
3159 state
.max_args
= MAXMODEPARAMS
;
3162 for (i
= 0; i
< MAXPARA
; i
++) { /* initialize ops/voices arrays */
3163 state
.banlist
[i
].next
= 0;
3164 state
.banlist
[i
].who
[0] = '\0';
3165 state
.banlist
[i
].when
= 0;
3166 state
.banlist
[i
].flags
= 0;
3167 state
.cli_change
[i
].flag
= 0;
3168 state
.cli_change
[i
].client
= 0;
3171 modestr
= state
.parv
[state
.args_used
++];
3175 for (; *modestr
; modestr
++) {
3176 for (flag_p
= chan_flags
; flag_p
[0]; flag_p
+= 2) /* look up flag */
3177 if (flag_p
[1] == *modestr
)
3180 if (!flag_p
[0]) { /* didn't find it? complain and continue */
3181 if (MyUser(state
.sptr
))
3182 send_reply(state
.sptr
, ERR_UNKNOWNMODE
, *modestr
);
3187 case '+': /* switch direction to MODE_ADD */
3188 case '-': /* switch direction to MODE_DEL */
3189 state
.dir
= flag_p
[0];
3192 case 'l': /* deal with limits */
3193 mode_parse_limit(&state
, flag_p
);
3196 case 'k': /* deal with keys */
3197 mode_parse_key(&state
, flag_p
);
3200 case 'A': /* deal with Admin passes */
3201 if (IsServer(cptr
) || feature_bool(FEAT_OPLEVELS
))
3202 mode_parse_apass(&state
, flag_p
);
3205 case 'U': /* deal with user passes */
3206 if (IsServer(cptr
) || feature_bool(FEAT_OPLEVELS
))
3207 mode_parse_upass(&state
, flag_p
);
3210 case 'b': /* deal with bans */
3211 mode_parse_ban(&state
, flag_p
);
3214 case 'o': /* deal with ops/voice */
3216 mode_parse_client(&state
, flag_p
);
3219 default: /* deal with other modes */
3220 mode_parse_mode(&state
, flag_p
);
3222 } /* switch (*modestr) */
3223 } /* for (; *modestr; modestr++) */
3225 if (state
.flags
& MODE_PARSE_BURST
)
3226 break; /* don't interpret any more arguments */
3228 if (state
.parc
> 0) { /* process next argument in string */
3229 modestr
= state
.parv
[state
.args_used
++];
3233 if (IsServer(state
.sptr
) && !state
.parc
&& IsDigit(*modestr
)) {
3236 if (!(state
.flags
& MODE_PARSE_SET
)) /* don't set earlier TS if */
3237 break; /* we're then going to bounce the mode! */
3239 recv_ts
= atoi(modestr
);
3241 if (recv_ts
&& recv_ts
< state
.chptr
->creationtime
)
3242 state
.chptr
->creationtime
= recv_ts
; /* respect earlier TS */
3244 break; /* break out of while loop */
3245 } else if (state
.flags
& MODE_PARSE_STRICT
||
3246 (MyUser(state
.sptr
) && state
.max_args
<= 0)) {
3247 state
.parc
++; /* we didn't actually gobble the argument */
3249 break; /* break out of while loop */
3252 } /* while (*modestr) */
3255 * the rest of the function finishes building resultant MODEs; if the
3256 * origin isn't a member or an oper, skip it.
3258 if (!state
.mbuf
|| state
.flags
& (MODE_PARSE_NOTOPER
| MODE_PARSE_NOTMEMBER
))
3259 return state
.args_used
; /* tell our parent how many args we gobbled */
3261 t_mode
= state
.chptr
->mode
.mode
;
3263 if (state
.del
& t_mode
) { /* delete any modes to be deleted... */
3264 modebuf_mode(state
.mbuf
, MODE_DEL
| (state
.del
& t_mode
));
3266 t_mode
&= ~state
.del
;
3268 if (state
.add
& ~t_mode
) { /* add any modes to be added... */
3269 modebuf_mode(state
.mbuf
, MODE_ADD
| (state
.add
& ~t_mode
));
3271 t_mode
|= state
.add
;
3274 if (state
.flags
& MODE_PARSE_SET
) { /* set the channel modes */
3275 if ((state
.chptr
->mode
.mode
& MODE_INVITEONLY
) &&
3276 !(t_mode
& MODE_INVITEONLY
))
3277 mode_invite_clear(state
.chptr
);
3279 state
.chptr
->mode
.mode
= t_mode
;
3282 if (state
.flags
& MODE_PARSE_WIPEOUT
) {
3283 if (state
.chptr
->mode
.limit
&& !(state
.done
& DONE_LIMIT
))
3284 modebuf_mode_uint(state
.mbuf
, MODE_DEL
| MODE_LIMIT
,
3285 state
.chptr
->mode
.limit
);
3286 if (*state
.chptr
->mode
.key
&& !(state
.done
& DONE_KEY
))
3287 modebuf_mode_string(state
.mbuf
, MODE_DEL
| MODE_KEY
,
3288 state
.chptr
->mode
.key
, 0);
3289 if (*state
.chptr
->mode
.upass
&& !(state
.done
& DONE_UPASS
))
3290 modebuf_mode_string(state
.mbuf
, MODE_DEL
| MODE_UPASS
,
3291 state
.chptr
->mode
.upass
, 0);
3292 if (*state
.chptr
->mode
.apass
&& !(state
.done
& DONE_APASS
))
3293 modebuf_mode_string(state
.mbuf
, MODE_DEL
| MODE_APASS
,
3294 state
.chptr
->mode
.apass
, 0);
3297 if (state
.done
& DONE_BANCLEAN
) /* process bans */
3298 mode_process_bans(&state
);
3300 /* process client changes */
3301 if (state
.cli_change
[0].flag
)
3302 mode_process_clients(&state
);
3304 return state
.args_used
; /* tell our parent how many args we gobbled */
3308 * Initialize a join buffer
3311 joinbuf_init(struct JoinBuf
*jbuf
, struct Client
*source
,
3312 struct Client
*connect
, unsigned int type
, char *comment
,
3318 assert(0 != source
);
3319 assert(0 != connect
);
3321 jbuf
->jb_source
= source
; /* just initialize struct JoinBuf */
3322 jbuf
->jb_connect
= connect
;
3323 jbuf
->jb_type
= type
;
3324 jbuf
->jb_comment
= comment
;
3325 jbuf
->jb_create
= create
;
3327 jbuf
->jb_strlen
= (((type
== JOINBUF_TYPE_JOIN
||
3328 type
== JOINBUF_TYPE_PART
||
3329 type
== JOINBUF_TYPE_PARTALL
) ?
3330 STARTJOINLEN
: STARTCREATELEN
) +
3331 (comment
? strlen(comment
) + 2 : 0));
3333 for (i
= 0; i
< MAXJOINARGS
; i
++)
3334 jbuf
->jb_channels
[i
] = 0;
3338 * Add a channel to the join buffer
3341 joinbuf_join(struct JoinBuf
*jbuf
, struct Channel
*chan
, unsigned int flags
)
3349 sendcmdto_serv_butone(jbuf
->jb_source
, CMD_JOIN
, jbuf
->jb_connect
, "0");
3353 is_local
= IsLocalChannel(chan
->chname
);
3355 if (jbuf
->jb_type
== JOINBUF_TYPE_PART
||
3356 jbuf
->jb_type
== JOINBUF_TYPE_PARTALL
) {
3357 struct Membership
*member
= find_member_link(chan
, jbuf
->jb_source
);
3358 if (IsUserParting(member
))
3360 SetUserParting(member
);
3362 /* Send notification to channel */
3363 if (!(flags
& (CHFL_ZOMBIE
| CHFL_DELAYED
)))
3364 sendcmdto_channel_butserv_butone(jbuf
->jb_source
, CMD_PART
, chan
, NULL
, 0,
3365 ((flags
& CHFL_BANNED
) || ((chan
->mode
.mode
& MODE_NOQUITPARTS
)
3366 && !IsChannelService(member
->user
)) || !jbuf
->jb_comment
) ?
3367 "%H" : "%H :%s", chan
, jbuf
->jb_comment
);
3368 else if (MyUser(jbuf
->jb_source
))
3369 sendcmdto_one(jbuf
->jb_source
, CMD_PART
, jbuf
->jb_source
,
3370 ((flags
& CHFL_BANNED
) || (chan
->mode
.mode
& MODE_NOQUITPARTS
)
3371 || !jbuf
->jb_comment
) ?
3372 ":%H" : "%H :%s", chan
, jbuf
->jb_comment
);
3373 /* XXX: Shouldn't we send a PART here anyway? */
3374 /* to users on the channel? Why? From their POV, the user isn't on
3375 * the channel anymore anyway. We don't send to servers until below,
3376 * when we gang all the channel parts together. Note that this is
3377 * exactly the same logic, albeit somewhat more concise, as was in
3378 * the original m_part.c */
3380 if (jbuf
->jb_type
== JOINBUF_TYPE_PARTALL
||
3381 is_local
) /* got to remove user here */
3382 remove_user_from_channel(jbuf
->jb_source
, chan
);
3384 int oplevel
= !chan
->mode
.apass
[0] ? MAXOPLEVEL
3385 : (flags
& CHFL_CHANNEL_MANAGER
) ? 0
3387 /* Add user to channel */
3388 if ((chan
->mode
.mode
& MODE_DELJOINS
) && !(flags
& CHFL_VOICED_OR_OPPED
))
3389 add_user_to_channel(chan
, jbuf
->jb_source
, flags
| CHFL_DELAYED
, oplevel
);
3391 add_user_to_channel(chan
, jbuf
->jb_source
, flags
, oplevel
);
3393 /* send notification to all servers */
3394 if (jbuf
->jb_type
!= JOINBUF_TYPE_CREATE
&& !is_local
)
3396 if (flags
& CHFL_CHANOP
) {
3397 assert(oplevel
== 0 || oplevel
== 1);
3398 sendcmdto_serv_butone(jbuf
->jb_source
, CMD_JOIN
, jbuf
->jb_connect
,
3399 "%u:%H %Tu", oplevel
, chan
, chan
->creationtime
);
3401 sendcmdto_serv_butone(jbuf
->jb_source
, CMD_JOIN
, jbuf
->jb_connect
,
3402 "%H %Tu", chan
, chan
->creationtime
);
3405 if (!((chan
->mode
.mode
& MODE_DELJOINS
) && !(flags
& CHFL_VOICED_OR_OPPED
))) {
3406 /* Send the notification to the channel */
3407 sendcmdto_channel_butserv_butone(jbuf
->jb_source
, CMD_JOIN
, chan
, NULL
, 0, "%H", chan
);
3409 /* send an op, too, if needed */
3410 if (flags
& CHFL_CHANOP
&& (oplevel
< MAXOPLEVEL
|| !MyUser(jbuf
->jb_source
)))
3411 sendcmdto_channel_butserv_butone((chan
->mode
.apass
[0] ? &his
: jbuf
->jb_source
),
3412 CMD_MODE
, chan
, NULL
, 0, "%H +o %C",
3413 chan
, jbuf
->jb_source
);
3414 } else if (MyUser(jbuf
->jb_source
))
3415 sendcmdto_one(jbuf
->jb_source
, CMD_JOIN
, jbuf
->jb_source
, ":%H", chan
);
3418 if (jbuf
->jb_type
== JOINBUF_TYPE_PARTALL
||
3419 jbuf
->jb_type
== JOINBUF_TYPE_JOIN
|| is_local
)
3420 return; /* don't send to remote */
3422 /* figure out if channel name will cause buffer to be overflowed */
3423 len
= chan
? strlen(chan
->chname
) + 1 : 2;
3424 if (jbuf
->jb_strlen
+ len
> BUFSIZE
)
3425 joinbuf_flush(jbuf
);
3427 /* add channel to list of channels to send and update counts */
3428 jbuf
->jb_channels
[jbuf
->jb_count
++] = chan
;
3429 jbuf
->jb_strlen
+= len
;
3431 /* if we've used up all slots, flush */
3432 if (jbuf
->jb_count
>= MAXJOINARGS
)
3433 joinbuf_flush(jbuf
);
3437 * Flush the channel list to remote servers
3440 joinbuf_flush(struct JoinBuf
*jbuf
)
3442 char chanlist
[BUFSIZE
];
3446 if (!jbuf
->jb_count
|| jbuf
->jb_type
== JOINBUF_TYPE_PARTALL
||
3447 jbuf
->jb_type
== JOINBUF_TYPE_JOIN
)
3448 return 0; /* no joins to process */
3450 for (i
= 0; i
< jbuf
->jb_count
; i
++) { /* build channel list */
3451 build_string(chanlist
, &chanlist_i
,
3452 jbuf
->jb_channels
[i
] ? jbuf
->jb_channels
[i
]->chname
: "0", 0,
3453 i
== 0 ? '\0' : ',');
3454 if (JOINBUF_TYPE_PART
== jbuf
->jb_type
)
3455 /* Remove user from channel */
3456 remove_user_from_channel(jbuf
->jb_source
, jbuf
->jb_channels
[i
]);
3458 jbuf
->jb_channels
[i
] = 0; /* mark slot empty */
3461 jbuf
->jb_count
= 0; /* reset base counters */
3462 jbuf
->jb_strlen
= ((jbuf
->jb_type
== JOINBUF_TYPE_PART
?
3463 STARTJOINLEN
: STARTCREATELEN
) +
3464 (jbuf
->jb_comment
? strlen(jbuf
->jb_comment
) + 2 : 0));
3466 /* and send the appropriate command */
3467 switch (jbuf
->jb_type
) {
3468 case JOINBUF_TYPE_CREATE
:
3469 sendcmdto_serv_butone(jbuf
->jb_source
, CMD_CREATE
, jbuf
->jb_connect
,
3470 "%s %Tu", chanlist
, jbuf
->jb_create
);
3471 if (MyUser(jbuf
->jb_source
) && (feature_bool(FEAT_AUTOCHANMODES
) &&
3472 feature_str(FEAT_AUTOCHANMODES_LIST
) && (strlen(feature_str(FEAT_AUTOCHANMODES_LIST
)) > 0))) {
3475 for (name
= ircd_strtok(&p
, chanlist
, ","); name
; name
= ircd_strtok(&p
, 0, ",")) {
3476 sendcmdto_serv_butone(jbuf
->jb_source
, CMD_MODE
, jbuf
->jb_connect
,
3477 "%s %s%s", name
, "+", feature_str(FEAT_AUTOCHANMODES_LIST
));
3482 case JOINBUF_TYPE_PART
:
3483 sendcmdto_serv_butone(jbuf
->jb_source
, CMD_PART
, jbuf
->jb_connect
,
3484 jbuf
->jb_comment
? "%s :%s" : "%s", chanlist
,
3492 /* Returns TRUE (1) if client is invited, FALSE (0) if not */
3493 int IsInvited(struct Client
* cptr
, const void* chptr
)
3497 for (lp
= (cli_user(cptr
))->invited
; lp
; lp
= lp
->next
)
3498 if (lp
->value
.chptr
== chptr
)
3503 /* RevealDelayedJoin: sends a join for a hidden user */
3505 void RevealDelayedJoin(struct Membership
*member
)
3507 ClearDelayedJoin(member
);
3508 sendcmdto_channel_butserv_butone(member
->user
, CMD_JOIN
, member
->channel
, member
->user
, 0, ":%H",
3510 CheckDelayedJoins(member
->channel
);
3513 /* CheckDelayedJoins: checks and clear +d if necessary */
3515 void CheckDelayedJoins(struct Channel
*chan
)
3517 struct Membership
*memb2
;
3519 if (chan
->mode
.mode
& MODE_WASDELJOINS
) {
3520 for (memb2
=chan
->members
;memb2
;memb2
=memb2
->next_member
)
3521 if (IsDelayedJoin(memb2
))
3526 chan
->mode
.mode
&= ~MODE_WASDELJOINS
;
3527 sendcmdto_channel_butserv_butone(&his
, CMD_MODE
, chan
, NULL
, 0,