]>
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
) || HasSetHost(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.
710 if (IsServer(cptr
) || IsXtraOp(cptr
))
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_NOCOLOUR
)
795 if (chptr
->mode
.mode
& MODE_NOCTCP
)
797 if (chptr
->mode
.mode
& MODE_NONOTICE
)
799 if (chptr
->mode
.mode
& MODE_NOQUITPARTS
)
801 if (chptr
->mode
.mode
& MODE_DELJOINS
)
803 else if (MyUser(cptr
) && (chptr
->mode
.mode
& MODE_WASDELJOINS
))
805 if (chptr
->mode
.limit
) {
807 ircd_snprintf(0, pbuf
, buflen
, "%u", chptr
->mode
.limit
);
808 previous_parameter
= 1;
811 if (*chptr
->mode
.key
) {
813 if (previous_parameter
)
815 if (is_chan_op(cptr
, chptr
) || IsServer(cptr
) || IsOper(cptr
)) {
816 strcat(pbuf
, chptr
->mode
.key
);
819 previous_parameter
= 1;
821 if (*chptr
->mode
.apass
) {
823 if (previous_parameter
)
825 if (IsServer(cptr
)) {
826 strcat(pbuf
, chptr
->mode
.apass
);
829 previous_parameter
= 1;
831 if (*chptr
->mode
.upass
) {
833 if (previous_parameter
)
835 if (IsServer(cptr
) || (member
&& IsChanOp(member
) && OpLevel(member
) == 0)) {
836 strcat(pbuf
, chptr
->mode
.upass
);
843 /** Compare two members oplevel
845 * @param mp1 Pointer to a pointer to a membership
846 * @param mp2 Pointer to a pointer to a membership
848 * @returns 0 if equal, -1 if mp1 is lower, +1 otherwise.
852 int compare_member_oplevel(const void *mp1
, const void *mp2
)
854 struct Membership
const* member1
= *(struct Membership
const**)mp1
;
855 struct Membership
const* member2
= *(struct Membership
const**)mp2
;
856 if (member1
->oplevel
== member2
->oplevel
)
858 return (member1
->oplevel
< member2
->oplevel
) ? -1 : 1;
861 /* send "cptr" a full list of the modes for channel chptr.
863 * Sends a BURST line to cptr, bursting all the modes for the channel.
865 * @param cptr Client pointer
866 * @param chptr Channel pointer
868 void send_channel_modes(struct Client
*cptr
, struct Channel
*chptr
)
870 /* The order in which modes are generated is now mandatory */
871 static unsigned int current_flags
[4] =
872 { 0, CHFL_VOICE
, CHFL_CHANOP
, CHFL_CHANOP
| CHFL_VOICE
};
878 struct Membership
* member
;
880 char modebuf
[MODEBUFLEN
];
881 char parabuf
[MODEBUFLEN
];
883 int number_of_ops
= 0;
884 int opped_members_index
= 0;
885 struct Membership
** opped_members
= NULL
;
886 int last_oplevel
= 0;
887 int feat_oplevels
= (chptr
->mode
.apass
[0]) != '\0';
892 if (IsLocalChannel(chptr
->chname
))
895 member
= chptr
->members
;
896 lp2
= chptr
->banlist
;
898 *modebuf
= *parabuf
= '\0';
899 channel_modes(cptr
, modebuf
, parabuf
, sizeof(parabuf
), chptr
, 0);
901 for (first
= 1; full
; first
= 0) /* Loop for multiple messages */
903 full
= 0; /* Assume by default we get it
904 all in one message */
906 /* (Continued) prefix: "<Y> B <channel> <TS>" */
907 /* is there any better way we can do this? */
908 mb
= msgq_make(&me
, "%C " TOK_BURST
" %H %Tu", &me
, chptr
,
909 chptr
->creationtime
);
911 if (first
&& modebuf
[1]) /* Add simple modes (Aiklmnpstu)
914 /* prefix: "<Y> B <channel> <TS>[ <modes>[ <params>]]" */
915 msgq_append(&me
, mb
, " %s", modebuf
);
918 msgq_append(&me
, mb
, " %s", parabuf
);
922 * Attach nicks, comma separated " nick[:modes],nick[:modes],..."
924 * First find all opless members.
925 * Run 2 times over all members, to group the members with
926 * and without voice together.
927 * Then run 2 times over all opped members (which are ordered
928 * by op-level) to also group voice and non-voice together.
930 for (first
= 1; flag_cnt
< 4; new_mode
= 1, ++flag_cnt
)
934 if (flag_cnt
< 2 && IsChanOp(member
))
937 * The first loop (to find all non-voice/op), we count the ops.
938 * The second loop (to find all voiced non-ops), store the ops
939 * in a dynamic array.
944 opped_members
[opped_members_index
++] = member
;
946 /* Only handle the members with the flags that we are interested in. */
947 if ((member
->status
& CHFL_VOICED_OR_OPPED
) == current_flags
[flag_cnt
])
949 if (msgq_bufleft(mb
) < NUMNICKLEN
+ 3 + MAXOPLEVELDIGITS
)
950 /* The 3 + MAXOPLEVELDIGITS is a possible ",:v999". */
952 full
= 1; /* Make sure we continue after
954 /* Ensure the new BURST line contains the current
955 * ":mode", except when there is no mode yet. */
956 new_mode
= (flag_cnt
> 0) ? 1 : 0;
957 break; /* Do not add this member to this message */
959 msgq_append(&me
, mb
, "%c%C", first
? ' ' : ',', member
->user
);
960 first
= 0; /* From now on, use commas to add new nicks */
963 * Do we have a nick with a new mode ?
964 * Or are we starting a new BURST line?
969 * This means we are at the _first_ member that has only
970 * voice, or the first member that has only ops, or the
971 * first member that has voice and ops (so we get here
972 * at most three times, plus once for every start of
973 * a continued BURST line where only these modes is current.
974 * In the two cases where the current mode includes ops,
975 * we need to add the _absolute_ value of the oplevel to the mode.
977 char tbuf
[3 + MAXOPLEVELDIGITS
] = ":";
980 if (HasVoice(member
)) /* flag_cnt == 1 or 3 */
982 if (IsChanOp(member
)) /* flag_cnt == 2 or 3 */
984 /* append the absolute value of the oplevel */
986 loc
+= ircd_snprintf(0, tbuf
+ loc
, sizeof(tbuf
) - loc
, "%u", last_oplevel
= member
->oplevel
);
991 msgq_append(&me
, mb
, tbuf
);
994 else if (feat_oplevels
&& flag_cnt
> 1 && last_oplevel
!= member
->oplevel
)
997 * This can't be the first member of a (continued) BURST
998 * message because then either flag_cnt == 0 or new_mode == 1
999 * Now we need to append the incremental value of the oplevel.
1001 char tbuf
[2 + MAXOPLEVELDIGITS
];
1002 ircd_snprintf(0, tbuf
, sizeof(tbuf
), ":%u", member
->oplevel
- last_oplevel
);
1003 last_oplevel
= member
->oplevel
;
1004 msgq_append(&me
, mb
, tbuf
);
1007 /* Go to the next `member'. */
1009 member
= member
->next_member
;
1011 member
= opped_members
[++opped_members_index
];
1016 /* Point `member' at the start of the list again. */
1019 member
= chptr
->members
;
1020 /* Now, after one loop, we know the number of ops and can
1021 * allocate the dynamic array with pointer to the ops. */
1022 opped_members
= (struct Membership
**)
1023 MyMalloc((number_of_ops
+ 1) * sizeof(struct Membership
*));
1024 opped_members
[number_of_ops
] = NULL
; /* Needed for loop termination */
1028 /* At the end of the second loop, sort the opped members with
1029 * increasing op-level, so that we will output them in the
1030 * correct order (and all op-level increments stay positive) */
1032 qsort(opped_members
, number_of_ops
,
1033 sizeof(struct Membership
*), compare_member_oplevel
);
1034 /* The third and fourth loop run only over the opped members. */
1035 member
= opped_members
[(opped_members_index
= 0)];
1038 } /* loop over 0,+v,+o,+ov */
1042 /* Attach all bans, space separated " :%ban ban ..." */
1043 for (first
= 2; lp2
; lp2
= lp2
->next
)
1045 len
= strlen(lp2
->banstr
);
1046 if (msgq_bufleft(mb
) < len
+ 1 + first
)
1047 /* The +1 stands for the added ' '.
1048 * The +first stands for the added ":%".
1054 msgq_append(&me
, mb
, " %s%s", first
? ":%" : "",
1060 send_buffer(cptr
, mb
, 0); /* Send this message */
1062 } /* Continue when there was something
1063 that didn't fit (full==1) */
1065 MyFree(opped_members
);
1066 if (feature_bool(FEAT_TOPIC_BURST
) && (chptr
->topic
[0] != '\0'))
1067 sendcmdto_one(&me
, CMD_TOPIC
, cptr
, "%H %Tu %Tu :%s", chptr
,
1068 chptr
->creationtime
, chptr
->topic_time
, chptr
->topic
);
1071 /** Canonify a mask.
1074 * @author Carlo Wood (Run),
1077 * When the nick is longer then NICKLEN, it is cut off (its an error of course).
1078 * When the user name or host name are too long (USERLEN and HOSTLEN
1079 * respectively) then they are cut off at the start with a '*'.
1081 * The following transformations are made:
1083 * 1) xxx -> nick!*@*
1084 * 2) xxx.xxx -> *!*\@host
1085 * 3) xxx\!yyy -> nick!user\@*
1086 * 4) xxx\@yyy -> *!user\@host
1087 * 5) xxx!yyy\@zzz -> nick!user\@host
1089 * @param mask The uncanonified mask.
1090 * @returns The updated mask in a static buffer.
1092 char *pretty_mask(char *mask
)
1094 static char star
[2] = { '*', 0 };
1095 static char retmask
[NICKLEN
+ USERLEN
+ HOSTLEN
+ 3];
1096 char *last_dot
= NULL
;
1099 /* Case 1: default */
1104 /* Do a _single_ pass through the characters of the mask: */
1105 for (ptr
= mask
; *ptr
; ++ptr
)
1109 /* Case 3 or 5: Found first '!' (without finding a '@' yet) */
1113 else if (*ptr
== '@')
1115 /* Case 4: Found last '@' (without finding a '!' yet) */
1120 else if (*ptr
== '.' || *ptr
== ':')
1122 /* Case 2: Found character specific to IP or hostname (without
1123 * finding a '!' or '@' yet) */
1133 /* Case 4 or 5: Found last '@' */
1139 if (user
== star
&& last_dot
)
1149 char *nick_end
= (user
!= star
) ? user
- 1 : ptr
;
1150 if (nick_end
- nick
> NICKLEN
)
1156 char *user_end
= (host
!= star
) ? host
- 1 : ptr
;
1157 if (user_end
- user
> USERLEN
)
1159 user
= user_end
- USERLEN
;
1164 if (host
!= star
&& ptr
- host
> HOSTLEN
)
1166 host
= ptr
- HOSTLEN
;
1169 ircd_snprintf(0, retmask
, sizeof(retmask
), "%s!%s@%s", nick
, user
, host
);
1173 /** send a banlist to a client for a channel
1175 * @param cptr Client to send the banlist to.
1176 * @param chptr Channel whose banlist to send.
1178 static void send_ban_list(struct Client
* cptr
, struct Channel
* chptr
)
1185 for (lp
= chptr
->banlist
; lp
; lp
= lp
->next
)
1186 send_reply(cptr
, RPL_BANLIST
, chptr
->chname
, lp
->banstr
,
1189 send_reply(cptr
, RPL_ENDOFBANLIST
, chptr
->chname
);
1192 /** Remove bells and commas from channel name
1194 * @param cn Channel name to clean, modified in place.
1196 void clean_channelname(char *cn
)
1200 for (i
= 0; cn
[i
]; i
++) {
1201 if (i
>= IRCD_MIN(CHANNELLEN
, feature_int(FEAT_CHANNELLEN
))
1202 || !IsChannelChar(cn
[i
])) {
1206 if (IsChannelLower(cn
[i
])) {
1207 cn
[i
] = ToLower(cn
[i
]);
1213 if ((unsigned char)(cn
[i
]) == 0xd0)
1214 cn
[i
] = (char) 0xf0;
1220 /** Get a channel block, creating if necessary.
1221 * Get Channel block for chname (and allocate a new channel
1222 * block, if it didn't exists before).
1224 * @param cptr Client joining the channel.
1225 * @param chname The name of the channel to join.
1226 * @param flag set to CGT_CREATE to create the channel if it doesn't
1229 * @returns NULL if the channel is invalid, doesn't exist and CGT_CREATE
1230 * wasn't specified or a pointer to the channel structure
1232 struct Channel
*get_channel(struct Client
*cptr
, char *chname
, ChannelGetType flag
)
1234 struct Channel
*chptr
;
1237 if (EmptyString(chname
))
1240 len
= strlen(chname
);
1241 if (MyUser(cptr
) && len
> CHANNELLEN
)
1244 *(chname
+ CHANNELLEN
) = '\0';
1246 if ((chptr
= FindChannel(chname
)))
1248 if (flag
== CGT_CREATE
)
1250 chptr
= (struct Channel
*) MyMalloc(sizeof(struct Channel
) + len
);
1252 ++UserStats
.channels
;
1253 memset(chptr
, 0, sizeof(struct Channel
));
1254 strcpy(chptr
->chname
, chname
);
1255 if (GlobalChannelList
)
1256 GlobalChannelList
->prev
= chptr
;
1258 chptr
->next
= GlobalChannelList
;
1259 chptr
->creationtime
= MyUser(cptr
) ? TStime() : (time_t) 0;
1260 GlobalChannelList
= chptr
;
1266 int SetAutoChanModes(struct Channel
*chptr
)
1268 static int chan_flags
[] = {
1271 MODE_MODERATED
, 'm',
1272 MODE_TOPICLIMIT
, 't',
1273 MODE_INVITEONLY
, 'i',
1274 MODE_NOPRIVMSGS
, 'n',
1276 /* MODE_NOCOLOUR, 'c',
1278 MODE_NONOTICE, 'N',*/
1280 MODE_NOQUITPARTS
, 'u'
1283 unsigned int *flag_p
;
1284 unsigned int t_mode
;
1285 const char *modestr
;
1291 if (!feature_bool(FEAT_AUTOCHANMODES
) || !feature_str(FEAT_AUTOCHANMODES_LIST
) || strlen(feature_str(FEAT_AUTOCHANMODES_LIST
)) <= 1)
1294 modestr
= feature_str(FEAT_AUTOCHANMODES_LIST
);
1296 for (; *modestr
; modestr
++) {
1297 for (flag_p
= chan_flags
; flag_p
[0]; flag_p
+= 2) /* look up flag */
1298 if (flag_p
[1] == *modestr
)
1301 if (!flag_p
[0]) /* didn't find it */
1304 t_mode
|= flag_p
[0];
1306 } /* for (; *modestr; modestr++) { */
1309 chptr
->mode
.mode
= t_mode
;
1313 /** invite a user to a channel.
1315 * Adds an invite for a user to a channel. Limits the number of invites
1316 * to FEAT_MAXCHANNELSPERUSER. Does not sent notification to the user.
1318 * @param cptr The client to be invited.
1319 * @param chptr The channel to be invited to.
1321 void add_invite(struct Client
*cptr
, struct Channel
*chptr
)
1323 struct SLink
*inv
, **tmp
;
1325 del_invite(cptr
, chptr
);
1327 * Delete last link in chain if the list is max length
1329 assert(list_length((cli_user(cptr
))->invited
) == (cli_user(cptr
))->invites
);
1330 if ((cli_user(cptr
))->invites
>= feature_int(FEAT_MAXCHANNELSPERUSER
))
1331 del_invite(cptr
, (cli_user(cptr
))->invited
->value
.chptr
);
1333 * Add client to channel invite list
1336 inv
->value
.cptr
= cptr
;
1337 inv
->next
= chptr
->invites
;
1338 chptr
->invites
= inv
;
1340 * Add channel to the end of the client invite list
1342 for (tmp
= &((cli_user(cptr
))->invited
); *tmp
; tmp
= &((*tmp
)->next
));
1344 inv
->value
.chptr
= chptr
;
1347 (cli_user(cptr
))->invites
++;
1350 /** Delete an invite
1351 * Delete Invite block from channel invite list and client invite list
1353 * @param cptr Client pointer
1354 * @param chptr Channel pointer
1356 void del_invite(struct Client
*cptr
, struct Channel
*chptr
)
1358 struct SLink
**inv
, *tmp
;
1360 for (inv
= &(chptr
->invites
); (tmp
= *inv
); inv
= &tmp
->next
)
1361 if (tmp
->value
.cptr
== cptr
)
1366 (cli_user(cptr
))->invites
--;
1370 for (inv
= &((cli_user(cptr
))->invited
); (tmp
= *inv
); inv
= &tmp
->next
)
1371 if (tmp
->value
.chptr
== chptr
)
1380 /** @page zombie Explanation of Zombies
1384 * A channel member is turned into a zombie when he is kicked from a
1385 * channel but his server has not acknowledged the kick. Servers that
1386 * see the member as a zombie can accept actions he performed before
1387 * being kicked, without allowing chanop operations from outsiders or
1388 * desyncing the network.
1396 * X --a--> A --b--> B --d--> D
1401 * Where `who' is being KICK-ed by a "KICK" message received by server 'A'
1402 * via 'a', or on server 'B' via either 'b' or 'c', or on server D via 'd'.
1404 * a) On server A : set CHFL_ZOMBIE for `who' (lp) and pass on the KICK.
1405 * Remove the user immediately when no users are left on the channel.
1406 * b) On server B : remove the user (who/lp) from the channel, send a
1407 * PART upstream (to A) and pass on the KICK.
1408 * c) KICKed by `client'; On server B : remove the user (who/lp) from the
1409 * channel, and pass on the KICK.
1410 * d) On server D : remove the user (who/lp) from the channel, and pass on
1414 * - Setting the ZOMBIE flag never hurts, we either remove the
1415 * client after that or we don't.
1416 * - The KICK message was already passed on, as should be in all cases.
1417 * - `who' is removed in all cases except case a) when users are left.
1418 * - A PART is only sent upstream in case b).
1424 * 1 --- 2 --- 3 --- 4 --- 5
1429 * We also need to turn 'who' into a zombie on servers 1 and 6,
1430 * because a KICK from 'who' (kicking someone else in that direction)
1431 * can arrive there afterward - which should not be bounced itself.
1432 * Therefore case a) also applies for servers 1 and 6.
1437 /** Turn a user on a channel into a zombie
1438 * This function turns a user into a zombie (see \ref zombie)
1440 * @param member The structure representing this user on this channel.
1441 * @param who The client that is being kicked.
1442 * @param cptr The connection the kick came from.
1443 * @param sptr The client that is doing the kicking.
1444 * @param chptr The channel the user is being kicked from.
1446 void make_zombie(struct Membership
* member
, struct Client
* who
,
1447 struct Client
* cptr
, struct Client
* sptr
, struct Channel
* chptr
)
1449 assert(0 != member
);
1454 /* Default for case a): */
1457 /* Case b) or c) ?: */
1458 if (MyUser(who
)) /* server 4 */
1460 if (IsServer(cptr
)) /* Case b) ? */
1461 sendcmdto_one(who
, CMD_PART
, cptr
, "%H", chptr
);
1462 remove_user_from_channel(who
, chptr
);
1465 if (cli_from(who
) == cptr
) /* True on servers 1, 5 and 6 */
1467 struct Client
*acptr
= IsServer(sptr
) ? sptr
: (cli_user(sptr
))->server
;
1468 for (; acptr
!= &me
; acptr
= (cli_serv(acptr
))->up
)
1469 if (acptr
== (cli_user(who
))->server
) /* Case d) (server 5) */
1471 remove_user_from_channel(who
, chptr
);
1476 /* Case a) (servers 1, 2, 3 and 6) */
1477 if (channel_all_zombies(chptr
))
1478 remove_user_from_channel(who
, chptr
);
1480 /* XXX Can't actually call Debug here; if the channel is all zombies,
1481 * chptr will no longer exist when we get here.
1482 Debug((DEBUG_INFO, "%s is now a zombie on %s", who->name, chptr->chname));
1486 /** returns the number of zombies on a channel
1487 * @param chptr Channel to count zombies in.
1489 * @returns The number of zombies on the channel.
1491 int number_of_zombies(struct Channel
*chptr
)
1493 struct Membership
* member
;
1497 for (member
= chptr
->members
; member
; member
= member
->next_member
) {
1498 if (IsZombie(member
))
1504 /** Concatenate some strings together.
1505 * This helper function builds an argument string in strptr, consisting
1506 * of the original string, a space, and str1 and str2 concatenated (if,
1507 * of course, str2 is not NULL)
1509 * @param strptr The buffer to concatenate into
1510 * @param strptr_i modified offset to the position to modify
1511 * @param str1 The string to concatenate from.
1512 * @param str2 The second string to contatenate from.
1513 * @param c Charactor to separate the string from str1 and str2.
1516 build_string(char *strptr
, int *strptr_i
, const char *str1
,
1517 const char *str2
, char c
)
1520 strptr
[(*strptr_i
)++] = c
;
1523 strptr
[(*strptr_i
)++] = *(str1
++);
1527 strptr
[(*strptr_i
)++] = *(str2
++);
1529 strptr
[(*strptr_i
)] = '\0';
1532 /** Flush out the modes
1533 * This is the workhorse of our ModeBuf suite; this actually generates the
1534 * output MODE commands, HACK notices, or whatever. It's pretty complicated.
1536 * @param mbuf The mode buffer to flush
1537 * @param all If true, flush all modes, otherwise leave partial modes in the
1543 modebuf_flush_int(struct ModeBuf
*mbuf
, int all
)
1545 /* we only need the flags that don't take args right now */
1546 static int flags
[] = {
1547 /* MODE_CHANOP, 'o', */
1548 /* MODE_VOICE, 'v', */
1551 MODE_MODERATED
, 'm',
1552 MODE_TOPICLIMIT
, 't',
1553 MODE_INVITEONLY
, 'i',
1554 MODE_NOPRIVMSGS
, 'n',
1557 MODE_WASDELJOINS
, 'd',
1558 /* MODE_KEY, 'k', */
1559 /* MODE_BAN, 'b', */
1561 /* MODE_APASS, 'A', */
1562 /* MODE_UPASS, 'U', */
1563 MODE_NOQUITPARTS
, 'u',
1572 struct Client
*app_source
; /* where the MODE appears to come from */
1574 char addbuf
[20]; /* accumulates +psmtin, etc. */
1576 char rembuf
[20]; /* accumulates -psmtin, etc. */
1578 char *bufptr
; /* we make use of indirection to simplify the code */
1581 char addstr
[BUFSIZE
]; /* accumulates MODE parameters to add */
1583 char remstr
[BUFSIZE
]; /* accumulates MODE parameters to remove */
1585 char *strptr
; /* more indirection to simplify the code */
1588 int totalbuflen
= BUFSIZE
- 200; /* fuzz factor -- don't overrun buffer! */
1591 char limitbuf
[20]; /* convert limits to strings */
1593 unsigned int limitdel
= MODE_LIMIT
;
1597 /* If the ModeBuf is empty, we have nothing to do */
1598 if (mbuf
->mb_add
== 0 && mbuf
->mb_rem
== 0 && mbuf
->mb_count
== 0)
1601 /* Ok, if we were given the OPMODE flag, or its a server, hide the source.
1603 if (mbuf
->mb_dest
& MODEBUF_DEST_OPMODE
|| IsServer(mbuf
->mb_source
) || IsMe(mbuf
->mb_source
))
1606 app_source
= mbuf
->mb_source
;
1609 * Account for user we're bouncing; we have to get it in on the first
1610 * bounced MODE, or we could have problems
1612 if (mbuf
->mb_dest
& MODEBUF_DEST_DEOP
)
1613 totalbuflen
-= 6; /* numeric nick == 5, plus one space */
1615 /* Calculate the simple flags */
1616 for (flag_p
= flags
; flag_p
[0]; flag_p
+= 2) {
1617 if (*flag_p
& mbuf
->mb_add
)
1618 addbuf
[addbuf_i
++] = flag_p
[1];
1619 else if (*flag_p
& mbuf
->mb_rem
)
1620 rembuf
[rembuf_i
++] = flag_p
[1];
1623 /* Now go through the modes with arguments... */
1624 for (i
= 0; i
< mbuf
->mb_count
; i
++) {
1625 if (MB_TYPE(mbuf
, i
) & MODE_ADD
) { /* adding or removing? */
1627 bufptr_i
= &addbuf_i
;
1630 bufptr_i
= &rembuf_i
;
1633 if (MB_TYPE(mbuf
, i
) & (MODE_CHANOP
| MODE_VOICE
)) {
1634 tmp
= strlen(cli_name(MB_CLIENT(mbuf
, i
)));
1636 if ((totalbuflen
- IRCD_MAX(9, tmp
)) <= 0) /* don't overflow buffer */
1637 MB_TYPE(mbuf
, i
) |= MODE_SAVE
; /* save for later */
1639 bufptr
[(*bufptr_i
)++] = MB_TYPE(mbuf
, i
) & MODE_CHANOP
? 'o' : 'v';
1640 totalbuflen
-= IRCD_MAX(9, tmp
) + 1;
1642 } else if (MB_TYPE(mbuf
, i
) & (MODE_BAN
| MODE_APASS
| MODE_UPASS
)) {
1643 tmp
= strlen(MB_STRING(mbuf
, i
));
1645 if ((totalbuflen
- tmp
) <= 0) /* don't overflow buffer */
1646 MB_TYPE(mbuf
, i
) |= MODE_SAVE
; /* save for later */
1649 switch(MB_TYPE(mbuf
, i
) & (MODE_BAN
| MODE_APASS
| MODE_UPASS
))
1661 bufptr
[(*bufptr_i
)++] = mode_char
;
1662 totalbuflen
-= tmp
+ 1;
1664 } else if (MB_TYPE(mbuf
, i
) & MODE_KEY
) {
1665 tmp
= (mbuf
->mb_dest
& MODEBUF_DEST_NOKEY
? 1 :
1666 strlen(MB_STRING(mbuf
, i
)));
1668 if ((totalbuflen
- tmp
) <= 0) /* don't overflow buffer */
1669 MB_TYPE(mbuf
, i
) |= MODE_SAVE
; /* save for later */
1671 bufptr
[(*bufptr_i
)++] = 'k';
1672 totalbuflen
-= tmp
+ 1;
1674 } else if (MB_TYPE(mbuf
, i
) & MODE_LIMIT
) {
1675 /* if it's a limit, we also format the number */
1676 ircd_snprintf(0, limitbuf
, sizeof(limitbuf
), "%u", MB_UINT(mbuf
, i
));
1678 tmp
= strlen(limitbuf
);
1680 if ((totalbuflen
- tmp
) <= 0) /* don't overflow buffer */
1681 MB_TYPE(mbuf
, i
) |= MODE_SAVE
; /* save for later */
1683 bufptr
[(*bufptr_i
)++] = 'l';
1684 totalbuflen
-= tmp
+ 1;
1689 /* terminate the mode strings */
1690 addbuf
[addbuf_i
] = '\0';
1691 rembuf
[rembuf_i
] = '\0';
1693 /* If we're building a user visible MODE or HACK... */
1694 if (mbuf
->mb_dest
& (MODEBUF_DEST_CHANNEL
| MODEBUF_DEST_HACK2
|
1695 MODEBUF_DEST_HACK3
| MODEBUF_DEST_HACK4
|
1696 MODEBUF_DEST_LOG
)) {
1697 /* Set up the parameter strings */
1703 for (i
= 0; i
< mbuf
->mb_count
; i
++) {
1704 if (MB_TYPE(mbuf
, i
) & MODE_SAVE
)
1707 if (MB_TYPE(mbuf
, i
) & MODE_ADD
) { /* adding or removing? */
1709 strptr_i
= &addstr_i
;
1712 strptr_i
= &remstr_i
;
1715 /* deal with clients... */
1716 if (MB_TYPE(mbuf
, i
) & (MODE_CHANOP
| MODE_VOICE
))
1717 build_string(strptr
, strptr_i
, cli_name(MB_CLIENT(mbuf
, i
)), 0, ' ');
1719 /* deal with bans... */
1720 else if (MB_TYPE(mbuf
, i
) & MODE_BAN
)
1721 build_string(strptr
, strptr_i
, MB_STRING(mbuf
, i
), 0, ' ');
1723 /* deal with keys... */
1724 else if (MB_TYPE(mbuf
, i
) & MODE_KEY
)
1725 build_string(strptr
, strptr_i
, mbuf
->mb_dest
& MODEBUF_DEST_NOKEY
?
1726 "*" : MB_STRING(mbuf
, i
), 0, ' ');
1728 /* deal with invisible passwords */
1729 else if (MB_TYPE(mbuf
, i
) & (MODE_APASS
| MODE_UPASS
))
1730 build_string(strptr
, strptr_i
, "*", 0, ' ');
1733 * deal with limit; note we cannot include the limit parameter if we're
1736 else if ((MB_TYPE(mbuf
, i
) & (MODE_ADD
| MODE_LIMIT
)) ==
1737 (MODE_ADD
| MODE_LIMIT
))
1738 build_string(strptr
, strptr_i
, limitbuf
, 0, ' ');
1741 /* send the messages off to their destination */
1742 if (mbuf
->mb_dest
& MODEBUF_DEST_HACK2
)
1743 sendto_opmask_butone(0, SNO_HACK2
, "HACK(2): %s MODE %s %s%s%s%s%s%s "
1745 cli_name(feature_bool(FEAT_HIS_SNOTICES
) ?
1746 mbuf
->mb_source
: app_source
),
1747 mbuf
->mb_channel
->chname
,
1748 rembuf_i
? "-" : "", rembuf
, addbuf_i
? "+" : "",
1749 addbuf
, remstr
, addstr
,
1750 mbuf
->mb_channel
->creationtime
);
1752 if (mbuf
->mb_dest
& MODEBUF_DEST_HACK3
)
1753 sendto_opmask_butone(0, SNO_HACK3
, "BOUNCE or HACK(3): %s MODE %s "
1754 "%s%s%s%s%s%s [%Tu]",
1755 cli_name(feature_bool(FEAT_HIS_SNOTICES
) ?
1756 mbuf
->mb_source
: app_source
),
1757 mbuf
->mb_channel
->chname
, rembuf_i
? "-" : "",
1758 rembuf
, addbuf_i
? "+" : "", addbuf
, remstr
, addstr
,
1759 mbuf
->mb_channel
->creationtime
);
1761 if (mbuf
->mb_dest
& MODEBUF_DEST_HACK4
)
1762 sendto_opmask_butone(0, SNO_HACK4
, "HACK(4): %s MODE %s %s%s%s%s%s%s "
1764 cli_name(feature_bool(FEAT_HIS_SNOTICES
) ?
1765 mbuf
->mb_source
: app_source
),
1766 mbuf
->mb_channel
->chname
,
1767 rembuf_i
? "-" : "", rembuf
, addbuf_i
? "+" : "",
1768 addbuf
, remstr
, addstr
,
1769 mbuf
->mb_channel
->creationtime
);
1771 if (mbuf
->mb_dest
& MODEBUF_DEST_LOG
)
1772 log_write(LS_OPERMODE
, L_INFO
, LOG_NOSNOTICE
,
1773 "%#C OPMODE %H %s%s%s%s%s%s", mbuf
->mb_source
,
1774 mbuf
->mb_channel
, rembuf_i
? "-" : "", rembuf
,
1775 addbuf_i
? "+" : "", addbuf
, remstr
, addstr
);
1777 if (mbuf
->mb_dest
& MODEBUF_DEST_CHANNEL
)
1778 sendcmdto_channel_butserv_butone(app_source
, CMD_MODE
, mbuf
->mb_channel
, NULL
, 0,
1779 "%H %s%s%s%s%s%s", mbuf
->mb_channel
,
1780 rembuf_i
? "-" : "", rembuf
,
1781 addbuf_i
? "+" : "", addbuf
, remstr
, addstr
);
1784 /* Now are we supposed to propagate to other servers? */
1785 if (mbuf
->mb_dest
& MODEBUF_DEST_SERVER
) {
1786 /* set up parameter string */
1793 * limit is supressed if we're removing it; we have to figure out which
1794 * direction is the direction for it to be removed, though...
1796 limitdel
|= (mbuf
->mb_dest
& MODEBUF_DEST_HACK2
) ? MODE_DEL
: MODE_ADD
;
1798 for (i
= 0; i
< mbuf
->mb_count
; i
++) {
1799 if (MB_TYPE(mbuf
, i
) & MODE_SAVE
)
1802 if (MB_TYPE(mbuf
, i
) & MODE_ADD
) { /* adding or removing? */
1804 strptr_i
= &addstr_i
;
1807 strptr_i
= &remstr_i
;
1810 /* if we're changing oplevels we know the oplevel, pass it on */
1811 if (mbuf
->mb_channel
->mode
.apass
[0]
1812 && (MB_TYPE(mbuf
, i
) & MODE_CHANOP
)
1813 && MB_OPLEVEL(mbuf
, i
) < MAXOPLEVEL
)
1814 *strptr_i
+= ircd_snprintf(0, strptr
+ *strptr_i
, BUFSIZE
- *strptr_i
,
1816 NumNick(MB_CLIENT(mbuf
, i
)),
1817 MB_OPLEVEL(mbuf
, i
));
1819 /* deal with other modes that take clients */
1820 else if (MB_TYPE(mbuf
, i
) & (MODE_CHANOP
| MODE_VOICE
))
1821 build_string(strptr
, strptr_i
, NumNick(MB_CLIENT(mbuf
, i
)), ' ');
1823 /* deal with modes that take strings */
1824 else if (MB_TYPE(mbuf
, i
) & (MODE_KEY
| MODE_BAN
| MODE_APASS
| MODE_UPASS
))
1825 build_string(strptr
, strptr_i
, MB_STRING(mbuf
, i
), 0, ' ');
1828 * deal with the limit. Logic here is complicated; if HACK2 is set,
1829 * we're bouncing the mode, so sense is reversed, and we have to
1830 * include the original limit if it looks like it's being removed
1832 else if ((MB_TYPE(mbuf
, i
) & limitdel
) == limitdel
)
1833 build_string(strptr
, strptr_i
, limitbuf
, 0, ' ');
1836 /* we were told to deop the source */
1837 if (mbuf
->mb_dest
& MODEBUF_DEST_DEOP
) {
1838 addbuf
[addbuf_i
++] = 'o'; /* remember, sense is reversed */
1839 addbuf
[addbuf_i
] = '\0'; /* terminate the string... */
1840 build_string(addstr
, &addstr_i
, NumNick(mbuf
->mb_source
), ' ');
1842 /* mark that we've done this, so we don't do it again */
1843 mbuf
->mb_dest
&= ~MODEBUF_DEST_DEOP
;
1846 if (mbuf
->mb_dest
& MODEBUF_DEST_OPMODE
) {
1847 /* If OPMODE was set, we're propagating the mode as an OPMODE message */
1848 sendcmdto_serv_butone(mbuf
->mb_source
, CMD_OPMODE
, mbuf
->mb_connect
,
1849 "%H %s%s%s%s%s%s", mbuf
->mb_channel
,
1850 rembuf_i
? "-" : "", rembuf
, addbuf_i
? "+" : "",
1851 addbuf
, remstr
, addstr
);
1852 } else if (mbuf
->mb_dest
& MODEBUF_DEST_BOUNCE
) {
1854 * If HACK2 was set, we're bouncing; we send the MODE back to the
1855 * connection we got it from with the senses reversed and a TS of 0;
1858 sendcmdto_one(&me
, CMD_MODE
, mbuf
->mb_connect
, "%H %s%s%s%s%s%s %Tu",
1859 mbuf
->mb_channel
, addbuf_i
? "-" : "", addbuf
,
1860 rembuf_i
? "+" : "", rembuf
, addstr
, remstr
,
1861 mbuf
->mb_channel
->creationtime
);
1864 * We're propagating a normal MODE command to the rest of the network;
1865 * we send the actual channel TS unless this is a HACK3 or a HACK4
1867 if (IsServer(mbuf
->mb_source
))
1868 sendcmdto_serv_butone(mbuf
->mb_source
, CMD_MODE
, mbuf
->mb_connect
,
1869 "%H %s%s%s%s%s%s %Tu", mbuf
->mb_channel
,
1870 rembuf_i
? "-" : "", rembuf
, addbuf_i
? "+" : "",
1871 addbuf
, remstr
, addstr
,
1872 (mbuf
->mb_dest
& MODEBUF_DEST_HACK4
) ? 0 :
1873 mbuf
->mb_channel
->creationtime
);
1875 sendcmdto_serv_butone(mbuf
->mb_source
, CMD_MODE
, mbuf
->mb_connect
,
1876 "%H %s%s%s%s%s%s", mbuf
->mb_channel
,
1877 rembuf_i
? "-" : "", rembuf
, addbuf_i
? "+" : "",
1878 addbuf
, remstr
, addstr
);
1882 /* We've drained the ModeBuf... */
1887 /* reinitialize the mode-with-arg slots */
1888 for (i
= 0; i
< MAXMODEPARAMS
; i
++) {
1889 /* If we saved any, pack them down */
1890 if (MB_TYPE(mbuf
, i
) & MODE_SAVE
) {
1891 mbuf
->mb_modeargs
[mbuf
->mb_count
] = mbuf
->mb_modeargs
[i
];
1892 MB_TYPE(mbuf
, mbuf
->mb_count
) &= ~MODE_SAVE
; /* don't save anymore */
1894 if (mbuf
->mb_count
++ == i
) /* don't overwrite our hard work */
1896 } else if (MB_TYPE(mbuf
, i
) & MODE_FREE
)
1897 MyFree(MB_STRING(mbuf
, i
)); /* free string if needed */
1899 MB_TYPE(mbuf
, i
) = 0;
1900 MB_UINT(mbuf
, i
) = 0;
1903 /* If we're supposed to flush it all, do so--all hail tail recursion */
1904 if (all
&& mbuf
->mb_count
)
1905 return modebuf_flush_int(mbuf
, 1);
1910 /** Initialise a modebuf
1911 * This routine just initializes a ModeBuf structure with the information
1912 * needed and the options given.
1914 * @param mbuf The mode buffer to initialise.
1915 * @param source The client that is performing the mode.
1917 * @param chan The channel that the mode is being performed upon.
1921 modebuf_init(struct ModeBuf
*mbuf
, struct Client
*source
,
1922 struct Client
*connect
, struct Channel
*chan
, unsigned int dest
)
1927 assert(0 != source
);
1931 if (IsLocalChannel(chan
->chname
)) dest
&= ~MODEBUF_DEST_SERVER
;
1935 mbuf
->mb_source
= source
;
1936 mbuf
->mb_connect
= connect
;
1937 mbuf
->mb_channel
= chan
;
1938 mbuf
->mb_dest
= dest
;
1941 /* clear each mode-with-parameter slot */
1942 for (i
= 0; i
< MAXMODEPARAMS
; i
++) {
1943 MB_TYPE(mbuf
, i
) = 0;
1944 MB_UINT(mbuf
, i
) = 0;
1948 /** Append a new mode to a modebuf
1949 * This routine simply adds modes to be added or deleted; do a binary OR
1950 * with either MODE_ADD or MODE_DEL
1952 * @param mbuf Mode buffer
1953 * @param mode MODE_ADD or MODE_DEL OR'd with MODE_PRIVATE etc.
1956 modebuf_mode(struct ModeBuf
*mbuf
, unsigned int mode
)
1959 assert(0 != (mode
& (MODE_ADD
| MODE_DEL
)));
1961 mode
&= (MODE_ADD
| MODE_DEL
| MODE_PRIVATE
| MODE_SECRET
| MODE_MODERATED
|
1962 MODE_TOPICLIMIT
| MODE_INVITEONLY
| MODE_NOPRIVMSGS
| MODE_REGONLY
|
1963 MODE_DELJOINS
| MODE_WASDELJOINS
| MODE_NOQUITPARTS
| MODE_NOCOLOUR
|
1964 MODE_NOCTCP
| MODE_NONOTICE
);
1966 if (!(mode
& ~(MODE_ADD
| MODE_DEL
))) /* don't add empty modes... */
1969 if (mode
& MODE_ADD
) {
1970 mbuf
->mb_rem
&= ~mode
;
1971 mbuf
->mb_add
|= mode
;
1973 mbuf
->mb_add
&= ~mode
;
1974 mbuf
->mb_rem
|= mode
;
1978 /** Append a mode that takes an int argument to the modebuf
1980 * This routine adds a mode to be added or deleted that takes a unsigned
1981 * int parameter; mode may *only* be the relevant mode flag ORed with one
1982 * of MODE_ADD or MODE_DEL
1984 * @param mbuf The mode buffer to append to.
1985 * @param mode The mode to append.
1986 * @param uint The argument to the mode.
1989 modebuf_mode_uint(struct ModeBuf
*mbuf
, unsigned int mode
, unsigned int uint
)
1992 assert(0 != (mode
& (MODE_ADD
| MODE_DEL
)));
1994 if (mode
== (MODE_LIMIT
| MODE_DEL
)) {
1995 mbuf
->mb_rem
|= mode
;
1998 MB_TYPE(mbuf
, mbuf
->mb_count
) = mode
;
1999 MB_UINT(mbuf
, mbuf
->mb_count
) = uint
;
2001 /* when we've reached the maximal count, flush the buffer */
2002 if (++mbuf
->mb_count
>=
2003 (MAXMODEPARAMS
- (mbuf
->mb_dest
& MODEBUF_DEST_DEOP
? 1 : 0)))
2004 modebuf_flush_int(mbuf
, 0);
2007 /** append a string mode
2008 * This routine adds a mode to be added or deleted that takes a string
2009 * parameter; mode may *only* be the relevant mode flag ORed with one of
2010 * MODE_ADD or MODE_DEL
2012 * @param mbuf The mode buffer to append to.
2013 * @param mode The mode to append.
2014 * @param string The string parameter to append.
2015 * @param free If the string should be free'd later.
2018 modebuf_mode_string(struct ModeBuf
*mbuf
, unsigned int mode
, char *string
,
2022 assert(0 != (mode
& (MODE_ADD
| MODE_DEL
)));
2024 MB_TYPE(mbuf
, mbuf
->mb_count
) = mode
| (free
? MODE_FREE
: 0);
2025 MB_STRING(mbuf
, mbuf
->mb_count
) = string
;
2027 /* when we've reached the maximal count, flush the buffer */
2028 if (++mbuf
->mb_count
>=
2029 (MAXMODEPARAMS
- (mbuf
->mb_dest
& MODEBUF_DEST_DEOP
? 1 : 0)))
2030 modebuf_flush_int(mbuf
, 0);
2033 /** Append a mode on a client to a modebuf.
2034 * This routine adds a mode to be added or deleted that takes a client
2035 * parameter; mode may *only* be the relevant mode flag ORed with one of
2036 * MODE_ADD or MODE_DEL
2038 * @param mbuf The modebuf to append the mode to.
2039 * @param mode The mode to append.
2040 * @param client The client argument to append.
2041 * @param oplevel The oplevel the user had or will have
2044 modebuf_mode_client(struct ModeBuf
*mbuf
, unsigned int mode
,
2045 struct Client
*client
, int oplevel
)
2048 assert(0 != (mode
& (MODE_ADD
| MODE_DEL
)));
2050 MB_TYPE(mbuf
, mbuf
->mb_count
) = mode
;
2051 MB_CLIENT(mbuf
, mbuf
->mb_count
) = client
;
2052 MB_OPLEVEL(mbuf
, mbuf
->mb_count
) = oplevel
;
2054 /* when we've reached the maximal count, flush the buffer */
2055 if (++mbuf
->mb_count
>=
2056 (MAXMODEPARAMS
- (mbuf
->mb_dest
& MODEBUF_DEST_DEOP
? 1 : 0)))
2057 modebuf_flush_int(mbuf
, 0);
2060 /** The exported binding for modebuf_flush()
2062 * @param mbuf The mode buffer to flush.
2064 * @see modebuf_flush_int()
2067 modebuf_flush(struct ModeBuf
*mbuf
)
2069 struct Membership
*memb
;
2071 /* Check if MODE_WASDELJOINS should be set */
2072 if (!(mbuf
->mb_channel
->mode
.mode
& (MODE_DELJOINS
| MODE_WASDELJOINS
))
2073 && (mbuf
->mb_rem
& MODE_DELJOINS
)) {
2074 for (memb
= mbuf
->mb_channel
->members
; memb
; memb
= memb
->next_member
) {
2075 if (IsDelayedJoin(memb
)) {
2076 mbuf
->mb_channel
->mode
.mode
|= MODE_WASDELJOINS
;
2077 mbuf
->mb_add
|= MODE_WASDELJOINS
;
2078 mbuf
->mb_rem
&= ~MODE_WASDELJOINS
;
2084 return modebuf_flush_int(mbuf
, 1);
2087 /* This extracts the simple modes contained in mbuf
2089 * @param mbuf The mode buffer to extract the modes from.
2090 * @param buf The string buffer to write the modes into.
2093 modebuf_extract(struct ModeBuf
*mbuf
, char *buf
)
2095 static int flags
[] = {
2096 /* MODE_CHANOP, 'o', */
2097 /* MODE_VOICE, 'v', */
2100 MODE_MODERATED
, 'm',
2101 MODE_TOPICLIMIT
, 't',
2102 MODE_INVITEONLY
, 'i',
2103 MODE_NOPRIVMSGS
, 'n',
2107 /* MODE_BAN, 'b', */
2111 MODE_NOQUITPARTS
, 'u',
2118 int i
, bufpos
= 0, len
;
2120 char *key
= 0, limitbuf
[20];
2121 char *apass
= 0, *upass
= 0;
2130 for (i
= 0; i
< mbuf
->mb_count
; i
++) { /* find keys and limits */
2131 if (MB_TYPE(mbuf
, i
) & MODE_ADD
) {
2132 add
|= MB_TYPE(mbuf
, i
) & (MODE_KEY
| MODE_LIMIT
| MODE_APASS
| MODE_UPASS
);
2134 if (MB_TYPE(mbuf
, i
) & MODE_KEY
) /* keep strings */
2135 key
= MB_STRING(mbuf
, i
);
2136 else if (MB_TYPE(mbuf
, i
) & MODE_LIMIT
)
2137 ircd_snprintf(0, limitbuf
, sizeof(limitbuf
), "%u", MB_UINT(mbuf
, i
));
2138 else if (MB_TYPE(mbuf
, i
) & MODE_UPASS
)
2139 upass
= MB_STRING(mbuf
, i
);
2140 else if (MB_TYPE(mbuf
, i
) & MODE_APASS
)
2141 apass
= MB_STRING(mbuf
, i
);
2148 buf
[bufpos
++] = '+'; /* start building buffer */
2150 for (flag_p
= flags
; flag_p
[0]; flag_p
+= 2)
2152 buf
[bufpos
++] = flag_p
[1];
2154 for (i
= 0, len
= bufpos
; i
< len
; i
++) {
2156 build_string(buf
, &bufpos
, key
, 0, ' ');
2157 else if (buf
[i
] == 'l')
2158 build_string(buf
, &bufpos
, limitbuf
, 0, ' ');
2159 else if (buf
[i
] == 'U')
2160 build_string(buf
, &bufpos
, upass
, 0, ' ');
2161 else if (buf
[i
] == 'A')
2162 build_string(buf
, &bufpos
, apass
, 0, ' ');
2170 /** Simple function to invalidate bans
2172 * This function sets all bans as being valid.
2174 * @param chan The channel to operate on.
2177 mode_ban_invalidate(struct Channel
*chan
)
2179 struct Membership
*member
;
2181 for (member
= chan
->members
; member
; member
= member
->next_member
)
2182 ClearBanValid(member
);
2185 /** Simple function to drop invite structures
2187 * Remove all the invites on the channel.
2189 * @param chan Channel to remove invites from.
2193 mode_invite_clear(struct Channel
*chan
)
2195 while (chan
->invites
)
2196 del_invite(chan
->invites
->value
.cptr
, chan
);
2199 /* What we've done for mode_parse so far... */
2200 #define DONE_LIMIT 0x01 /**< We've set the limit */
2201 #define DONE_KEY 0x02 /**< We've set the key */
2202 #define DONE_BANLIST 0x04 /**< We've sent the ban list */
2203 #define DONE_NOTOPER 0x08 /**< We've sent a "Not oper" error */
2204 #define DONE_BANCLEAN 0x10 /**< We've cleaned bans... */
2205 #define DONE_UPASS 0x20 /**< We've set user pass */
2206 #define DONE_APASS 0x40 /**< We've set admin pass */
2209 struct ModeBuf
*mbuf
;
2210 struct Client
*cptr
;
2211 struct Client
*sptr
;
2212 struct Channel
*chptr
;
2213 struct Membership
*member
;
2224 struct Ban banlist
[MAXPARA
];
2227 unsigned short oplevel
;
2228 struct Client
*client
;
2229 } cli_change
[MAXPARA
];
2232 /** Helper function to send "Not oper" or "Not member" messages
2233 * Here's a helper function to deal with sending along "Not oper" or
2234 * "Not member" messages
2236 * @param state Parsing State object
2239 send_notoper(struct ParseState
*state
)
2241 if (state
->done
& DONE_NOTOPER
)
2244 send_reply(state
->sptr
, (state
->flags
& MODE_PARSE_NOTOPER
) ?
2245 ERR_CHANOPRIVSNEEDED
: ERR_NOTONCHANNEL
, state
->chptr
->chname
);
2247 state
->done
|= DONE_NOTOPER
;
2251 * Helper function to convert limits
2253 * @param state Parsing state object.
2257 mode_parse_limit(struct ParseState
*state
, int *flag_p
)
2259 unsigned int t_limit
;
2261 if (state
->dir
== MODE_ADD
) { /* convert arg only if adding limit */
2262 if (MyUser(state
->sptr
) && state
->max_args
<= 0) /* too many args? */
2265 if (state
->parc
<= 0) { /* warn if not enough args */
2266 if (MyUser(state
->sptr
))
2267 need_more_params(state
->sptr
, "MODE +l");
2271 t_limit
= strtoul(state
->parv
[state
->args_used
++], 0, 10); /* grab arg */
2275 if ((int)t_limit
<0) /* don't permit a negative limit */
2278 if (!(state
->flags
& MODE_PARSE_WIPEOUT
) &&
2279 (!t_limit
|| t_limit
== state
->chptr
->mode
.limit
))
2282 t_limit
= state
->chptr
->mode
.limit
;
2284 /* If they're not an oper, they can't change modes */
2285 if (state
->flags
& (MODE_PARSE_NOTOPER
| MODE_PARSE_NOTMEMBER
)) {
2286 send_notoper(state
);
2290 /* Can't remove a limit that's not there */
2291 if (state
->dir
== MODE_DEL
&& !state
->chptr
->mode
.limit
)
2294 /* Skip if this is a burst and a lower limit than this is set already */
2295 if ((state
->flags
& MODE_PARSE_BURST
) &&
2296 (state
->chptr
->mode
.mode
& flag_p
[0]) &&
2297 (state
->chptr
->mode
.limit
< t_limit
))
2300 if (state
->done
& DONE_LIMIT
) /* allow limit to be set only once */
2302 state
->done
|= DONE_LIMIT
;
2307 modebuf_mode_uint(state
->mbuf
, state
->dir
| flag_p
[0], t_limit
);
2309 if (state
->flags
& MODE_PARSE_SET
) { /* set the limit */
2310 if (state
->dir
& MODE_ADD
) {
2311 state
->chptr
->mode
.mode
|= flag_p
[0];
2312 state
->chptr
->mode
.limit
= t_limit
;
2314 state
->chptr
->mode
.mode
&= ~flag_p
[0];
2315 state
->chptr
->mode
.limit
= 0;
2320 /** Helper function to clean key-like parameters. */
2326 while (*s
> ' ' && *s
!= ':' && *s
!= ',' && t_len
--)
2332 * Helper function to convert keys
2335 mode_parse_key(struct ParseState
*state
, int *flag_p
)
2339 if (MyUser(state
->sptr
) && state
->max_args
<= 0) /* drop if too many args */
2342 if (state
->parc
<= 0) { /* warn if not enough args */
2343 if (MyUser(state
->sptr
))
2344 need_more_params(state
->sptr
, state
->dir
== MODE_ADD
? "MODE +k" :
2349 t_str
= state
->parv
[state
->args_used
++]; /* grab arg */
2353 /* If they're not an oper, they can't change modes */
2354 if (state
->flags
& (MODE_PARSE_NOTOPER
| MODE_PARSE_NOTMEMBER
)) {
2355 send_notoper(state
);
2359 if (state
->done
& DONE_KEY
) /* allow key to be set only once */
2361 state
->done
|= DONE_KEY
;
2363 /* clean up the key string */
2365 if (!*t_str
|| *t_str
== ':') { /* warn if empty */
2366 if (MyUser(state
->sptr
))
2367 need_more_params(state
->sptr
, state
->dir
== MODE_ADD
? "MODE +k" :
2375 /* Skip if this is a burst, we have a key already and the new key is
2376 * after the old one alphabetically */
2377 if ((state
->flags
& MODE_PARSE_BURST
) &&
2378 *(state
->chptr
->mode
.key
) &&
2379 ircd_strcmp(state
->chptr
->mode
.key
, t_str
) <= 0)
2382 /* can't add a key if one is set, nor can one remove the wrong key */
2383 if (!(state
->flags
& MODE_PARSE_FORCE
))
2384 if ((state
->dir
== MODE_ADD
&& *state
->chptr
->mode
.key
) ||
2385 (state
->dir
== MODE_DEL
&&
2386 ircd_strcmp(state
->chptr
->mode
.key
, t_str
))) {
2387 send_reply(state
->sptr
, ERR_KEYSET
, state
->chptr
->chname
);
2391 if (!(state
->flags
& MODE_PARSE_WIPEOUT
) && state
->dir
== MODE_ADD
&&
2392 !ircd_strcmp(state
->chptr
->mode
.key
, t_str
))
2393 return; /* no key change */
2395 if (state
->flags
& MODE_PARSE_BOUNCE
) {
2396 if (*state
->chptr
->mode
.key
) /* reset old key */
2397 modebuf_mode_string(state
->mbuf
, MODE_DEL
| flag_p
[0],
2398 state
->chptr
->mode
.key
, 0);
2399 else /* remove new bogus key */
2400 modebuf_mode_string(state
->mbuf
, MODE_ADD
| flag_p
[0], t_str
, 0);
2401 } else /* send new key */
2402 modebuf_mode_string(state
->mbuf
, state
->dir
| flag_p
[0], t_str
, 0);
2404 if (state
->flags
& MODE_PARSE_SET
) {
2405 if (state
->dir
== MODE_DEL
) /* remove the old key */
2406 *state
->chptr
->mode
.key
= '\0';
2407 else if (!state
->chptr
->mode
.key
[0]
2408 || ircd_strcmp(t_str
, state
->chptr
->mode
.key
) < 0)
2409 ircd_strncpy(state
->chptr
->mode
.key
, t_str
, KEYLEN
);
2414 * Helper function to convert user passes
2417 mode_parse_upass(struct ParseState
*state
, int *flag_p
)
2421 if (MyUser(state
->sptr
) && state
->max_args
<= 0) /* drop if too many args */
2424 if (state
->parc
<= 0) { /* warn if not enough args */
2425 if (MyUser(state
->sptr
))
2426 need_more_params(state
->sptr
, state
->dir
== MODE_ADD
? "MODE +U" :
2431 t_str
= state
->parv
[state
->args_used
++]; /* grab arg */
2435 /* If they're not an oper, they can't change modes */
2436 if (state
->flags
& (MODE_PARSE_NOTOPER
| MODE_PARSE_NOTMEMBER
)) {
2437 send_notoper(state
);
2441 /* If a non-service user is trying to force it, refuse. */
2442 if (state
->flags
& MODE_PARSE_FORCE
&& MyUser(state
->sptr
)
2443 && !HasPriv(state
->sptr
, PRIV_APASS_OPMODE
)) {
2444 send_reply(state
->sptr
, ERR_NOTMANAGER
, state
->chptr
->chname
,
2445 state
->chptr
->chname
);
2449 /* If they are not the channel manager, they are not allowed to change it */
2450 if (MyUser(state
->sptr
) && !(state
->flags
& MODE_PARSE_FORCE
|| IsChannelManager(state
->member
))) {
2451 if (*state
->chptr
->mode
.apass
) {
2452 send_reply(state
->sptr
, ERR_NOTMANAGER
, state
->chptr
->chname
,
2453 state
->chptr
->chname
);
2455 send_reply(state
->sptr
, ERR_NOMANAGER
, state
->chptr
->chname
);
2460 if (state
->done
& DONE_UPASS
) /* allow upass to be set only once */
2462 state
->done
|= DONE_UPASS
;
2464 /* clean up the upass string */
2466 if (!*t_str
|| *t_str
== ':') { /* warn if empty */
2467 if (MyUser(state
->sptr
))
2468 need_more_params(state
->sptr
, state
->dir
== MODE_ADD
? "MODE +U" :
2476 if (!(state
->flags
& MODE_PARSE_FORCE
)) {
2477 /* can't add the upass while apass is not set */
2478 if (state
->dir
== MODE_ADD
&& !*state
->chptr
->mode
.apass
) {
2479 send_reply(state
->sptr
, ERR_UPASSNOTSET
, state
->chptr
->chname
, state
->chptr
->chname
);
2482 /* cannot set a +U password that is the same as +A */
2483 if (state
->dir
== MODE_ADD
&& !ircd_strcmp(state
->chptr
->mode
.apass
, t_str
)) {
2484 send_reply(state
->sptr
, ERR_UPASS_SAME_APASS
, state
->chptr
->chname
);
2487 /* can't add a upass if one is set, nor can one remove the wrong upass */
2488 if ((state
->dir
== MODE_ADD
&& *state
->chptr
->mode
.upass
) ||
2489 (state
->dir
== MODE_DEL
&&
2490 ircd_strcmp(state
->chptr
->mode
.upass
, t_str
))) {
2491 send_reply(state
->sptr
, ERR_KEYSET
, state
->chptr
->chname
);
2496 if (!(state
->flags
& MODE_PARSE_WIPEOUT
) && state
->dir
== MODE_ADD
&&
2497 !ircd_strcmp(state
->chptr
->mode
.upass
, t_str
))
2498 return; /* no upass change */
2500 if (state
->flags
& MODE_PARSE_BOUNCE
) {
2501 if (*state
->chptr
->mode
.upass
) /* reset old upass */
2502 modebuf_mode_string(state
->mbuf
, MODE_DEL
| flag_p
[0],
2503 state
->chptr
->mode
.upass
, 0);
2504 else /* remove new bogus upass */
2505 modebuf_mode_string(state
->mbuf
, MODE_ADD
| flag_p
[0], t_str
, 0);
2506 } else /* send new upass */
2507 modebuf_mode_string(state
->mbuf
, state
->dir
| flag_p
[0], t_str
, 0);
2509 if (state
->flags
& MODE_PARSE_SET
) {
2510 if (state
->dir
== MODE_DEL
) /* remove the old upass */
2511 *state
->chptr
->mode
.upass
= '\0';
2512 else if (state
->chptr
->mode
.upass
[0] == '\0'
2513 || ircd_strcmp(t_str
, state
->chptr
->mode
.upass
) < 0)
2514 ircd_strncpy(state
->chptr
->mode
.upass
, t_str
, KEYLEN
);
2519 * Helper function to convert admin passes
2522 mode_parse_apass(struct ParseState
*state
, int *flag_p
)
2524 struct Membership
*memb
;
2527 if (MyUser(state
->sptr
) && state
->max_args
<= 0) /* drop if too many args */
2530 if (state
->parc
<= 0) { /* warn if not enough args */
2531 if (MyUser(state
->sptr
))
2532 need_more_params(state
->sptr
, state
->dir
== MODE_ADD
? "MODE +A" :
2537 t_str
= state
->parv
[state
->args_used
++]; /* grab arg */
2541 /* If they're not an oper, they can't change modes */
2542 if (state
->flags
& (MODE_PARSE_NOTOPER
| MODE_PARSE_NOTMEMBER
)) {
2543 send_notoper(state
);
2547 /* If a non-service user is trying to force it, refuse. */
2548 if (state
->flags
& MODE_PARSE_FORCE
&& MyUser(state
->sptr
)
2549 && !HasPriv(state
->sptr
, PRIV_APASS_OPMODE
)) {
2550 send_reply(state
->sptr
, ERR_NOTMANAGER
, state
->chptr
->chname
,
2551 state
->chptr
->chname
);
2555 /* Don't allow to change the Apass if the channel is older than 48 hours. */
2556 if (MyUser(state
->sptr
)
2557 && TStime() - state
->chptr
->creationtime
>= 172800
2558 && !IsAnOper(state
->sptr
)) {
2559 send_reply(state
->sptr
, ERR_CHANSECURED
, state
->chptr
->chname
);
2563 /* If they are not the channel manager, they are not allowed to change it */
2564 if (MyUser(state
->sptr
) && !(state
->flags
& MODE_PARSE_FORCE
|| IsChannelManager(state
->member
))) {
2565 if (*state
->chptr
->mode
.apass
) {
2566 send_reply(state
->sptr
, ERR_NOTMANAGER
, state
->chptr
->chname
,
2567 state
->chptr
->chname
);
2569 send_reply(state
->sptr
, ERR_NOMANAGER
, state
->chptr
->chname
);
2574 if (state
->done
& DONE_APASS
) /* allow apass to be set only once */
2576 state
->done
|= DONE_APASS
;
2578 /* clean up the apass string */
2580 if (!*t_str
|| *t_str
== ':') { /* warn if empty */
2581 if (MyUser(state
->sptr
))
2582 need_more_params(state
->sptr
, state
->dir
== MODE_ADD
? "MODE +A" :
2590 if (!(state
->flags
& MODE_PARSE_FORCE
)) {
2591 /* can't remove the apass while upass is still set */
2592 if (state
->dir
== MODE_DEL
&& *state
->chptr
->mode
.upass
) {
2593 send_reply(state
->sptr
, ERR_UPASSSET
, state
->chptr
->chname
, state
->chptr
->chname
);
2596 /* can't add an apass if one is set, nor can one remove the wrong apass */
2597 if ((state
->dir
== MODE_ADD
&& *state
->chptr
->mode
.apass
) ||
2598 (state
->dir
== MODE_DEL
&& ircd_strcmp(state
->chptr
->mode
.apass
, t_str
))) {
2599 send_reply(state
->sptr
, ERR_KEYSET
, state
->chptr
->chname
);
2604 if (!(state
->flags
& MODE_PARSE_WIPEOUT
) && state
->dir
== MODE_ADD
&&
2605 !ircd_strcmp(state
->chptr
->mode
.apass
, t_str
))
2606 return; /* no apass change */
2608 if (state
->flags
& MODE_PARSE_BOUNCE
) {
2609 if (*state
->chptr
->mode
.apass
) /* reset old apass */
2610 modebuf_mode_string(state
->mbuf
, MODE_DEL
| flag_p
[0],
2611 state
->chptr
->mode
.apass
, 0);
2612 else /* remove new bogus apass */
2613 modebuf_mode_string(state
->mbuf
, MODE_ADD
| flag_p
[0], t_str
, 0);
2614 } else /* send new apass */
2615 modebuf_mode_string(state
->mbuf
, state
->dir
| flag_p
[0], t_str
, 0);
2617 if (state
->flags
& MODE_PARSE_SET
) {
2618 if (state
->dir
== MODE_ADD
) { /* set the new apass */
2619 /* Only accept the new apass if there is no current apass
2620 * (e.g. when a user sets it) or the new one is "less" than the
2621 * old (for resolving conflicts during burst).
2623 if (state
->chptr
->mode
.apass
[0] == '\0'
2624 || ircd_strcmp(t_str
, state
->chptr
->mode
.apass
) < 0)
2625 ircd_strncpy(state
->chptr
->mode
.apass
, t_str
, KEYLEN
);
2626 /* Make it VERY clear to the user that this is a one-time password */
2627 if (MyUser(state
->sptr
)) {
2628 send_reply(state
->sptr
, RPL_APASSWARN_SET
, state
->chptr
->mode
.apass
);
2629 send_reply(state
->sptr
, RPL_APASSWARN_SECRET
, state
->chptr
->chname
,
2630 state
->chptr
->mode
.apass
);
2632 /* Give the channel manager level 0 ops. */
2633 if (!(state
->flags
& MODE_PARSE_FORCE
) && IsChannelManager(state
->member
))
2634 SetOpLevel(state
->member
, 0);
2635 } else { /* remove the old apass */
2636 *state
->chptr
->mode
.apass
= '\0';
2637 if (MyUser(state
->sptr
))
2638 send_reply(state
->sptr
, RPL_APASSWARN_CLEAR
);
2639 /* Revert everyone to MAXOPLEVEL. */
2640 for (memb
= state
->chptr
->members
; memb
; memb
= memb
->next_member
) {
2641 if (memb
->status
& MODE_CHANOP
)
2642 SetOpLevel(memb
, MAXOPLEVEL
);
2648 /** Compare one ban's extent to another.
2649 * This works very similarly to mmatch() but it knows about CIDR masks
2650 * and ban exceptions. If both bans are CIDR-based, compare their
2651 * address bits; otherwise, use mmatch().
2652 * @param[in] old_ban One ban.
2653 * @param[in] new_ban Another ban.
2654 * @return Zero if \a old_ban is a superset of \a new_ban, non-zero otherwise.
2657 bmatch(struct Ban
*old_ban
, struct Ban
*new_ban
)
2660 assert(old_ban
!= NULL
);
2661 assert(new_ban
!= NULL
);
2662 /* A ban is never treated as a superset of an exception. */
2663 if (!(old_ban
->flags
& BAN_EXCEPTION
)
2664 && (new_ban
->flags
& BAN_EXCEPTION
))
2666 /* If either is not an address mask, match the text masks. */
2667 if ((old_ban
->flags
& new_ban
->flags
& BAN_IPMASK
) == 0)
2668 return mmatch(old_ban
->banstr
, new_ban
->banstr
);
2669 /* If the old ban has a longer prefix than new, it cannot be a superset. */
2670 if (old_ban
->addrbits
> new_ban
->addrbits
)
2672 /* Compare the masks before the hostname part. */
2673 old_ban
->banstr
[old_ban
->nu_len
] = new_ban
->banstr
[new_ban
->nu_len
] = '\0';
2674 res
= mmatch(old_ban
->banstr
, new_ban
->banstr
);
2675 old_ban
->banstr
[old_ban
->nu_len
] = new_ban
->banstr
[new_ban
->nu_len
] = '@';
2678 /* Compare the addresses. */
2679 return !ipmask_check(&new_ban
->address
, &old_ban
->address
, old_ban
->addrbits
);
2682 /** Add a ban from a ban list and mark bans that should be removed
2683 * because they overlap.
2685 * There are three invariants for a ban list. First, no ban may be
2686 * more specific than another ban. Second, no exception may be more
2687 * specific than another exception. Finally, no ban may be more
2688 * specific than any exception.
2690 * @param[in,out] banlist Pointer to head of list.
2691 * @param[in] newban Ban (or exception) to add (or remove).
2692 * @param[in] do_free If non-zero, free \a newban on failure.
2693 * @return Zero if \a newban could be applied, non-zero if not.
2695 int apply_ban(struct Ban
**banlist
, struct Ban
*newban
, int do_free
)
2700 assert(newban
->flags
& (BAN_ADD
|BAN_DEL
));
2701 if (newban
->flags
& BAN_ADD
) {
2703 /* If a less specific entry is found, fail. */
2704 for (ban
= *banlist
; ban
; ban
= ban
->next
) {
2705 if (!bmatch(ban
, newban
)) {
2710 if (!(ban
->flags
& (BAN_OVERLAPPED
|BAN_DEL
))) {
2712 totlen
+= strlen(ban
->banstr
);
2715 /* Mark more specific entries and add this one to the end of the list. */
2716 while ((ban
= *banlist
) != NULL
) {
2717 if (!bmatch(newban
, ban
)) {
2718 ban
->flags
|= BAN_OVERLAPPED
| BAN_DEL
;
2720 banlist
= &ban
->next
;
2724 } else if (newban
->flags
& BAN_DEL
) {
2725 size_t remove_count
= 0;
2726 /* Mark more specific entries. */
2727 for (ban
= *banlist
; ban
; ban
= ban
->next
) {
2728 if (!bmatch(newban
, ban
)) {
2729 ban
->flags
|= BAN_OVERLAPPED
| BAN_DEL
;
2735 /* If no matches were found, fail. */
2746 * Helper function to convert bans
2749 mode_parse_ban(struct ParseState
*state
, int *flag_p
)
2752 struct Ban
*ban
, *newban
;
2754 if (state
->parc
<= 0) { /* Not enough args, send ban list */
2755 if (MyUser(state
->sptr
) && !(state
->done
& DONE_BANLIST
)) {
2756 send_ban_list(state
->sptr
, state
->chptr
);
2757 state
->done
|= DONE_BANLIST
;
2763 if (MyUser(state
->sptr
) && state
->max_args
<= 0) /* drop if too many args */
2766 t_str
= state
->parv
[state
->args_used
++]; /* grab arg */
2770 /* If they're not an oper, they can't change modes */
2771 if (state
->flags
& (MODE_PARSE_NOTOPER
| MODE_PARSE_NOTMEMBER
)) {
2772 send_notoper(state
);
2776 if ((s
= strchr(t_str
, ' ')))
2779 if (!*t_str
|| *t_str
== ':') { /* warn if empty */
2780 if (MyUser(state
->sptr
))
2781 need_more_params(state
->sptr
, state
->dir
== MODE_ADD
? "MODE +b" :
2786 /* Clear all ADD/DEL/OVERLAPPED flags from ban list. */
2787 if (!(state
->done
& DONE_BANCLEAN
)) {
2788 for (ban
= state
->chptr
->banlist
; ban
; ban
= ban
->next
)
2789 ban
->flags
&= ~(BAN_ADD
| BAN_DEL
| BAN_OVERLAPPED
);
2790 state
->done
|= DONE_BANCLEAN
;
2793 /* remember the ban for the moment... */
2794 newban
= state
->banlist
+ (state
->numbans
++);
2796 newban
->flags
= ((state
->dir
== MODE_ADD
) ? BAN_ADD
: BAN_DEL
)
2797 | (*flag_p
== MODE_BAN
? 0 : BAN_EXCEPTION
);
2798 set_ban_mask(newban
, collapse(pretty_mask(t_str
)));
2799 ircd_strncpy(newban
->who
, IsUser(state
->sptr
) ? cli_name(state
->sptr
) : "*", NICKLEN
);
2800 newban
->when
= TStime();
2801 apply_ban(&state
->chptr
->banlist
, newban
, 0);
2805 * This is the bottom half of the ban processor
2808 mode_process_bans(struct ParseState
*state
)
2810 struct Ban
*ban
, *newban
, *prevban
, *nextban
;
2816 for (prevban
= 0, ban
= state
->chptr
->banlist
; ban
; ban
= nextban
) {
2818 banlen
= strlen(ban
->banstr
);
2820 nextban
= ban
->next
;
2822 if ((ban
->flags
& (BAN_DEL
| BAN_ADD
)) == (BAN_DEL
| BAN_ADD
)) {
2824 prevban
->next
= 0; /* Break the list; ban isn't a real ban */
2826 state
->chptr
->banlist
= 0;
2832 } else if (ban
->flags
& BAN_DEL
) { /* Deleted a ban? */
2834 DupString(bandup
, ban
->banstr
);
2835 modebuf_mode_string(state
->mbuf
, MODE_DEL
| MODE_BAN
,
2838 if (state
->flags
& MODE_PARSE_SET
) { /* Ok, make it take effect */
2839 if (prevban
) /* clip it out of the list... */
2840 prevban
->next
= ban
->next
;
2842 state
->chptr
->banlist
= ban
->next
;
2849 continue; /* next ban; keep prevban like it is */
2851 ban
->flags
&= BAN_IPMASK
; /* unset other flags */
2852 } else if (ban
->flags
& BAN_ADD
) { /* adding a ban? */
2854 prevban
->next
= 0; /* Break the list; ban isn't a real ban */
2856 state
->chptr
->banlist
= 0;
2858 /* If we're supposed to ignore it, do so. */
2859 if (ban
->flags
& BAN_OVERLAPPED
&&
2860 !(state
->flags
& MODE_PARSE_BOUNCE
)) {
2864 if (state
->flags
& MODE_PARSE_SET
&& MyUser(state
->sptr
) &&
2865 (len
> (feature_int(FEAT_AVBANLEN
) * feature_int(FEAT_MAXBANS
)) ||
2866 count
> feature_int(FEAT_MAXBANS
))) {
2867 send_reply(state
->sptr
, ERR_BANLISTFULL
, state
->chptr
->chname
,
2873 /* add the ban to the buffer */
2874 DupString(bandup
, ban
->banstr
);
2875 modebuf_mode_string(state
->mbuf
, MODE_ADD
| MODE_BAN
,
2878 if (state
->flags
& MODE_PARSE_SET
) { /* create a new ban */
2879 newban
= make_ban(ban
->banstr
);
2880 strcpy(newban
->who
, ban
->who
);
2881 newban
->when
= ban
->when
;
2882 newban
->flags
= ban
->flags
& BAN_IPMASK
;
2884 newban
->next
= state
->chptr
->banlist
; /* and link it in */
2885 state
->chptr
->banlist
= newban
;
2894 } /* for (prevban = 0, ban = state->chptr->banlist; ban; ban = nextban) { */
2896 if (changed
) /* if we changed the ban list, we must invalidate the bans */
2897 mode_ban_invalidate(state
->chptr
);
2901 * Helper function to process client changes
2904 mode_parse_client(struct ParseState
*state
, int *flag_p
)
2907 struct Client
*acptr
;
2908 struct Membership
*member
;
2909 int oplevel
= MAXOPLEVEL
+ 1;
2912 if (MyUser(state
->sptr
) && state
->max_args
<= 0) /* drop if too many args */
2915 if (state
->parc
<= 0) /* return if not enough args */
2918 t_str
= state
->parv
[state
->args_used
++]; /* grab arg */
2922 /* If they're not an oper, they can't change modes */
2923 if (state
->flags
& (MODE_PARSE_NOTOPER
| MODE_PARSE_NOTMEMBER
)) {
2924 send_notoper(state
);
2928 if (MyUser(state
->sptr
)) /* find client we're manipulating */
2929 acptr
= find_chasing(state
->sptr
, t_str
, NULL
);
2931 if (t_str
[5] == ':') {
2933 oplevel
= atoi(t_str
+ 6);
2935 acptr
= findNUser(t_str
);
2939 return; /* find_chasing() already reported an error to the user */
2941 for (i
= 0; i
< MAXPARA
; i
++) /* find an element to stick them in */
2942 if (!state
->cli_change
[i
].flag
|| (state
->cli_change
[i
].client
== acptr
&&
2943 state
->cli_change
[i
].flag
& flag_p
[0]))
2944 break; /* found a slot */
2946 /* If we are going to bounce this deop, mark the correct oplevel. */
2947 if (state
->flags
& MODE_PARSE_BOUNCE
2948 && state
->dir
== MODE_DEL
2949 && flag_p
[0] == MODE_CHANOP
2950 && (member
= find_member_link(state
->chptr
, acptr
)))
2951 oplevel
= OpLevel(member
);
2953 /* Store what we're doing to them */
2954 state
->cli_change
[i
].flag
= state
->dir
| flag_p
[0];
2955 state
->cli_change
[i
].oplevel
= oplevel
;
2956 state
->cli_change
[i
].client
= acptr
;
2960 * Helper function to process the changed client list
2963 mode_process_clients(struct ParseState
*state
)
2966 struct Membership
*member
;
2968 for (i
= 0; state
->cli_change
[i
].flag
; i
++) {
2969 assert(0 != state
->cli_change
[i
].client
);
2971 /* look up member link */
2972 if (!(member
= find_member_link(state
->chptr
,
2973 state
->cli_change
[i
].client
)) ||
2974 (MyUser(state
->sptr
) && IsZombie(member
))) {
2975 if (MyUser(state
->sptr
))
2976 send_reply(state
->sptr
, ERR_USERNOTINCHANNEL
,
2977 cli_name(state
->cli_change
[i
].client
),
2978 state
->chptr
->chname
);
2982 if ((state
->cli_change
[i
].flag
& MODE_ADD
&&
2983 (state
->cli_change
[i
].flag
& member
->status
)) ||
2984 (state
->cli_change
[i
].flag
& MODE_DEL
&&
2985 !(state
->cli_change
[i
].flag
& member
->status
)))
2986 continue; /* no change made, don't do anything */
2988 /* see if the deop is allowed */
2989 if ((state
->cli_change
[i
].flag
& (MODE_DEL
| MODE_CHANOP
)) ==
2990 (MODE_DEL
| MODE_CHANOP
)) {
2991 /* prevent +k users from being deopped */
2994 * Allow +X'ed users to mess with +k'ed.
2997 if ((IsChannelService(state
->cli_change
[i
].client
) && IsService(cli_user(state
->cli_change
[i
].client
)->server
)) || (IsChannelService(state
->cli_change
[i
].client
) && !IsXtraOp(state
->sptr
))) {
2998 if (state
->flags
& MODE_PARSE_FORCE
) /* it was forced */
2999 sendto_opmask_butone(0, SNO_HACK4
, "Deop of +k user on %H by %s",
3001 (IsServer(state
->sptr
) ? cli_name(state
->sptr
) :
3002 cli_name((cli_user(state
->sptr
))->server
)));
3004 else if (MyUser(state
->sptr
) && state
->flags
& MODE_PARSE_SET
&& (state
->sptr
!= state
->cli_change
[i
].client
)) {
3005 if(IsService(cli_user(state
->cli_change
[i
].client
)->server
) && IsChannelService(state
->cli_change
[i
].client
)){
3006 send_reply(state
->sptr
, ERR_ISREALSERVICE
,
3007 cli_name(state
->cli_change
[i
].client
),
3008 state
->chptr
->chname
);
3010 send_reply(state
->sptr
, ERR_ISCHANSERVICE
,
3011 cli_name(state
->cli_change
[i
].client
),
3012 state
->chptr
->chname
);
3019 /* check deop for local user */
3020 if (MyUser(state
->sptr
)) {
3022 /* don't allow local opers to be deopped on local channels */
3023 if (state
->cli_change
[i
].client
!= state
->sptr
&&
3024 IsLocalChannel(state
->chptr
->chname
) &&
3025 HasPriv(state
->cli_change
[i
].client
, PRIV_DEOP_LCHAN
)) {
3026 send_reply(state
->sptr
, ERR_ISOPERLCHAN
,
3027 cli_name(state
->cli_change
[i
].client
),
3028 state
->chptr
->chname
);
3032 /* don't allow to deop members with an op level that is <= our own level */
3033 if (state
->sptr
!= state
->cli_change
[i
].client
/* but allow to deop oneself */
3034 && state
->chptr
->mode
.apass
[0]
3036 && OpLevel(member
) <= OpLevel(state
->member
)) {
3037 int equal
= (OpLevel(member
) == OpLevel(state
->member
));
3038 send_reply(state
->sptr
, ERR_NOTLOWEROPLEVEL
,
3039 cli_name(state
->cli_change
[i
].client
),
3040 state
->chptr
->chname
,
3041 OpLevel(state
->member
), OpLevel(member
),
3042 "deop", equal
? "the same" : "a higher");
3048 /* set op-level of member being opped */
3049 if ((state
->cli_change
[i
].flag
& (MODE_ADD
| MODE_CHANOP
)) ==
3050 (MODE_ADD
| MODE_CHANOP
)) {
3051 /* If a valid oplevel was specified, use it.
3052 * Otherwise, if being opped by an outsider, get MAXOPLEVEL.
3053 * Otherwise, if not an apass channel, or state->member has
3054 * MAXOPLEVEL, get oplevel MAXOPLEVEL.
3055 * Otherwise, get state->member's oplevel+1.
3057 if (state
->cli_change
[i
].oplevel
<= MAXOPLEVEL
)
3058 SetOpLevel(member
, state
->cli_change
[i
].oplevel
);
3059 else if (!state
->member
)
3060 SetOpLevel(member
, MAXOPLEVEL
);
3061 else if (!state
->chptr
->mode
.apass
[0] || OpLevel(state
->member
) == MAXOPLEVEL
)
3062 SetOpLevel(member
, MAXOPLEVEL
);
3064 SetOpLevel(member
, OpLevel(state
->member
) + 1);
3067 /* actually effect the change */
3068 if (state
->flags
& MODE_PARSE_SET
) {
3069 if (state
->cli_change
[i
].flag
& MODE_ADD
) {
3070 if (IsDelayedJoin(member
))
3071 RevealDelayedJoin(member
);
3072 member
->status
|= (state
->cli_change
[i
].flag
&
3073 (MODE_CHANOP
| MODE_VOICE
));
3074 if (state
->cli_change
[i
].flag
& MODE_CHANOP
)
3075 ClearDeopped(member
);
3077 member
->status
&= ~(state
->cli_change
[i
].flag
&
3078 (MODE_CHANOP
| MODE_VOICE
));
3081 /* accumulate the change */
3082 modebuf_mode_client(state
->mbuf
, state
->cli_change
[i
].flag
,
3083 state
->cli_change
[i
].client
,
3084 state
->cli_change
[i
].oplevel
);
3085 } /* for (i = 0; state->cli_change[i].flags; i++) */
3089 * Helper function to process the simple modes
3092 mode_parse_mode(struct ParseState
*state
, int *flag_p
)
3094 /* If they're not an oper, they can't change modes */
3095 if (state
->flags
& (MODE_PARSE_NOTOPER
| MODE_PARSE_NOTMEMBER
)) {
3096 send_notoper(state
);
3103 if (state
->dir
== MODE_ADD
) {
3104 state
->add
|= flag_p
[0];
3105 state
->del
&= ~flag_p
[0];
3107 if (flag_p
[0] & MODE_SECRET
) {
3108 state
->add
&= ~MODE_PRIVATE
;
3109 state
->del
|= MODE_PRIVATE
;
3110 } else if (flag_p
[0] & MODE_PRIVATE
) {
3111 state
->add
&= ~MODE_SECRET
;
3112 state
->del
|= MODE_SECRET
;
3114 if (flag_p
[0] & MODE_DELJOINS
) {
3115 state
->add
&= ~MODE_WASDELJOINS
;
3116 state
->del
|= MODE_WASDELJOINS
;
3119 state
->add
&= ~flag_p
[0];
3120 state
->del
|= flag_p
[0];
3123 assert(0 == (state
->add
& state
->del
));
3124 assert((MODE_SECRET
| MODE_PRIVATE
) !=
3125 (state
->add
& (MODE_SECRET
| MODE_PRIVATE
)));
3129 * This routine is intended to parse MODE or OPMODE commands and effect the
3130 * changes (or just build the bounce buffer). We pass the starting offset
3134 mode_parse(struct ModeBuf
*mbuf
, struct Client
*cptr
, struct Client
*sptr
,
3135 struct Channel
*chptr
, int parc
, char *parv
[], unsigned int flags
,
3136 struct Membership
* member
)
3138 static int chan_flags
[] = {
3143 MODE_MODERATED
, 'm',
3144 MODE_TOPICLIMIT
, 't',
3145 MODE_INVITEONLY
, 'i',
3146 MODE_NOPRIVMSGS
, 'n',
3154 MODE_NOQUITPARTS
, 'u',
3164 unsigned int t_mode
;
3166 struct ParseState state
;
3177 state
.chptr
= chptr
;
3178 state
.member
= member
;
3181 state
.flags
= flags
;
3182 state
.dir
= MODE_ADD
;
3186 state
.args_used
= 0;
3187 state
.max_args
= MAXMODEPARAMS
;
3190 for (i
= 0; i
< MAXPARA
; i
++) { /* initialize ops/voices arrays */
3191 state
.banlist
[i
].next
= 0;
3192 state
.banlist
[i
].who
[0] = '\0';
3193 state
.banlist
[i
].when
= 0;
3194 state
.banlist
[i
].flags
= 0;
3195 state
.cli_change
[i
].flag
= 0;
3196 state
.cli_change
[i
].client
= 0;
3199 modestr
= state
.parv
[state
.args_used
++];
3203 for (; *modestr
; modestr
++) {
3204 for (flag_p
= chan_flags
; flag_p
[0]; flag_p
+= 2) /* look up flag */
3205 if (flag_p
[1] == *modestr
)
3208 if (!flag_p
[0]) { /* didn't find it? complain and continue */
3209 if (MyUser(state
.sptr
))
3210 send_reply(state
.sptr
, ERR_UNKNOWNMODE
, *modestr
);
3215 case '+': /* switch direction to MODE_ADD */
3216 case '-': /* switch direction to MODE_DEL */
3217 state
.dir
= flag_p
[0];
3220 case 'l': /* deal with limits */
3221 mode_parse_limit(&state
, flag_p
);
3224 case 'k': /* deal with keys */
3225 mode_parse_key(&state
, flag_p
);
3228 case 'A': /* deal with Admin passes */
3229 if (IsServer(cptr
) || feature_bool(FEAT_OPLEVELS
))
3230 mode_parse_apass(&state
, flag_p
);
3233 case 'U': /* deal with user passes */
3234 if (IsServer(cptr
) || feature_bool(FEAT_OPLEVELS
))
3235 mode_parse_upass(&state
, flag_p
);
3238 case 'b': /* deal with bans */
3239 mode_parse_ban(&state
, flag_p
);
3242 case 'o': /* deal with ops/voice */
3244 mode_parse_client(&state
, flag_p
);
3247 default: /* deal with other modes */
3248 mode_parse_mode(&state
, flag_p
);
3250 } /* switch (*modestr) */
3251 } /* for (; *modestr; modestr++) */
3253 if (state
.flags
& MODE_PARSE_BURST
)
3254 break; /* don't interpret any more arguments */
3256 if (state
.parc
> 0) { /* process next argument in string */
3257 modestr
= state
.parv
[state
.args_used
++];
3261 if (IsServer(state
.sptr
) && !state
.parc
&& IsDigit(*modestr
)) {
3264 if (!(state
.flags
& MODE_PARSE_SET
)) /* don't set earlier TS if */
3265 break; /* we're then going to bounce the mode! */
3267 recv_ts
= atoi(modestr
);
3269 if (recv_ts
&& recv_ts
< state
.chptr
->creationtime
)
3270 state
.chptr
->creationtime
= recv_ts
; /* respect earlier TS */
3272 break; /* break out of while loop */
3273 } else if (state
.flags
& MODE_PARSE_STRICT
||
3274 (MyUser(state
.sptr
) && state
.max_args
<= 0)) {
3275 state
.parc
++; /* we didn't actually gobble the argument */
3277 break; /* break out of while loop */
3280 } /* while (*modestr) */
3283 * the rest of the function finishes building resultant MODEs; if the
3284 * origin isn't a member or an oper, skip it.
3286 if (!state
.mbuf
|| state
.flags
& (MODE_PARSE_NOTOPER
| MODE_PARSE_NOTMEMBER
))
3287 return state
.args_used
; /* tell our parent how many args we gobbled */
3289 t_mode
= state
.chptr
->mode
.mode
;
3291 if (state
.del
& t_mode
) { /* delete any modes to be deleted... */
3292 modebuf_mode(state
.mbuf
, MODE_DEL
| (state
.del
& t_mode
));
3294 t_mode
&= ~state
.del
;
3296 if (state
.add
& ~t_mode
) { /* add any modes to be added... */
3297 modebuf_mode(state
.mbuf
, MODE_ADD
| (state
.add
& ~t_mode
));
3299 t_mode
|= state
.add
;
3302 if (state
.flags
& MODE_PARSE_SET
) { /* set the channel modes */
3303 if ((state
.chptr
->mode
.mode
& MODE_INVITEONLY
) &&
3304 !(t_mode
& MODE_INVITEONLY
))
3305 mode_invite_clear(state
.chptr
);
3307 state
.chptr
->mode
.mode
= t_mode
;
3310 if (state
.flags
& MODE_PARSE_WIPEOUT
) {
3311 if (state
.chptr
->mode
.limit
&& !(state
.done
& DONE_LIMIT
))
3312 modebuf_mode_uint(state
.mbuf
, MODE_DEL
| MODE_LIMIT
,
3313 state
.chptr
->mode
.limit
);
3314 if (*state
.chptr
->mode
.key
&& !(state
.done
& DONE_KEY
))
3315 modebuf_mode_string(state
.mbuf
, MODE_DEL
| MODE_KEY
,
3316 state
.chptr
->mode
.key
, 0);
3317 if (*state
.chptr
->mode
.upass
&& !(state
.done
& DONE_UPASS
))
3318 modebuf_mode_string(state
.mbuf
, MODE_DEL
| MODE_UPASS
,
3319 state
.chptr
->mode
.upass
, 0);
3320 if (*state
.chptr
->mode
.apass
&& !(state
.done
& DONE_APASS
))
3321 modebuf_mode_string(state
.mbuf
, MODE_DEL
| MODE_APASS
,
3322 state
.chptr
->mode
.apass
, 0);
3325 if (state
.done
& DONE_BANCLEAN
) /* process bans */
3326 mode_process_bans(&state
);
3328 /* process client changes */
3329 if (state
.cli_change
[0].flag
)
3330 mode_process_clients(&state
);
3332 return state
.args_used
; /* tell our parent how many args we gobbled */
3336 * Initialize a join buffer
3339 joinbuf_init(struct JoinBuf
*jbuf
, struct Client
*source
,
3340 struct Client
*connect
, unsigned int type
, char *comment
,
3346 assert(0 != source
);
3347 assert(0 != connect
);
3349 jbuf
->jb_source
= source
; /* just initialize struct JoinBuf */
3350 jbuf
->jb_connect
= connect
;
3351 jbuf
->jb_type
= type
;
3352 jbuf
->jb_comment
= comment
;
3353 jbuf
->jb_create
= create
;
3355 jbuf
->jb_strlen
= (((type
== JOINBUF_TYPE_JOIN
||
3356 type
== JOINBUF_TYPE_PART
||
3357 type
== JOINBUF_TYPE_PARTALL
) ?
3358 STARTJOINLEN
: STARTCREATELEN
) +
3359 (comment
? strlen(comment
) + 2 : 0));
3361 for (i
= 0; i
< MAXJOINARGS
; i
++)
3362 jbuf
->jb_channels
[i
] = 0;
3366 * Add a channel to the join buffer
3369 joinbuf_join(struct JoinBuf
*jbuf
, struct Channel
*chan
, unsigned int flags
)
3377 sendcmdto_serv_butone(jbuf
->jb_source
, CMD_JOIN
, jbuf
->jb_connect
, "0");
3381 is_local
= IsLocalChannel(chan
->chname
);
3383 if (jbuf
->jb_type
== JOINBUF_TYPE_PART
||
3384 jbuf
->jb_type
== JOINBUF_TYPE_PARTALL
) {
3385 struct Membership
*member
= find_member_link(chan
, jbuf
->jb_source
);
3386 if (IsUserParting(member
))
3388 SetUserParting(member
);
3390 /* Send notification to channel */
3391 if (!(flags
& (CHFL_ZOMBIE
| CHFL_DELAYED
)))
3392 sendcmdto_channel_butserv_butone(jbuf
->jb_source
, CMD_PART
, chan
, NULL
, 0,
3393 ((flags
& CHFL_BANNED
) || ((chan
->mode
.mode
& MODE_NOQUITPARTS
)
3394 && !IsChannelService(member
->user
)) || !jbuf
->jb_comment
) ?
3395 "%H" : "%H :%s", chan
, jbuf
->jb_comment
);
3396 else if (MyUser(jbuf
->jb_source
))
3397 sendcmdto_one(jbuf
->jb_source
, CMD_PART
, jbuf
->jb_source
,
3398 ((flags
& CHFL_BANNED
) || (chan
->mode
.mode
& MODE_NOQUITPARTS
)
3399 || !jbuf
->jb_comment
) ?
3400 ":%H" : "%H :%s", chan
, jbuf
->jb_comment
);
3401 /* XXX: Shouldn't we send a PART here anyway? */
3402 /* to users on the channel? Why? From their POV, the user isn't on
3403 * the channel anymore anyway. We don't send to servers until below,
3404 * when we gang all the channel parts together. Note that this is
3405 * exactly the same logic, albeit somewhat more concise, as was in
3406 * the original m_part.c */
3408 if (jbuf
->jb_type
== JOINBUF_TYPE_PARTALL
||
3409 is_local
) /* got to remove user here */
3410 remove_user_from_channel(jbuf
->jb_source
, chan
);
3412 int oplevel
= !chan
->mode
.apass
[0] ? MAXOPLEVEL
3413 : (flags
& CHFL_CHANNEL_MANAGER
) ? 0
3415 /* Add user to channel */
3416 if ((chan
->mode
.mode
& MODE_DELJOINS
) && !(flags
& CHFL_VOICED_OR_OPPED
))
3417 add_user_to_channel(chan
, jbuf
->jb_source
, flags
| CHFL_DELAYED
, oplevel
);
3419 add_user_to_channel(chan
, jbuf
->jb_source
, flags
, oplevel
);
3421 /* send notification to all servers */
3422 if (jbuf
->jb_type
!= JOINBUF_TYPE_CREATE
&& !is_local
)
3424 if (flags
& CHFL_CHANOP
) {
3425 assert(oplevel
== 0 || oplevel
== 1);
3426 sendcmdto_serv_butone(jbuf
->jb_source
, CMD_JOIN
, jbuf
->jb_connect
,
3427 "%u:%H %Tu", oplevel
, chan
, chan
->creationtime
);
3429 sendcmdto_serv_butone(jbuf
->jb_source
, CMD_JOIN
, jbuf
->jb_connect
,
3430 "%H %Tu", chan
, chan
->creationtime
);
3433 if (!((chan
->mode
.mode
& MODE_DELJOINS
) && !(flags
& CHFL_VOICED_OR_OPPED
))) {
3434 /* Send the notification to the channel */
3435 sendcmdto_channel_butserv_butone(jbuf
->jb_source
, CMD_JOIN
, chan
, NULL
, 0, "%H", chan
);
3437 /* send an op, too, if needed */
3438 if (flags
& CHFL_CHANOP
&& (oplevel
< MAXOPLEVEL
|| !MyUser(jbuf
->jb_source
)))
3439 sendcmdto_channel_butserv_butone((chan
->mode
.apass
[0] ? &his
: jbuf
->jb_source
),
3440 CMD_MODE
, chan
, NULL
, 0, "%H +o %C",
3441 chan
, jbuf
->jb_source
);
3442 } else if (MyUser(jbuf
->jb_source
))
3443 sendcmdto_one(jbuf
->jb_source
, CMD_JOIN
, jbuf
->jb_source
, ":%H", chan
);
3446 if (jbuf
->jb_type
== JOINBUF_TYPE_PARTALL
||
3447 jbuf
->jb_type
== JOINBUF_TYPE_JOIN
|| is_local
)
3448 return; /* don't send to remote */
3450 /* figure out if channel name will cause buffer to be overflowed */
3451 len
= chan
? strlen(chan
->chname
) + 1 : 2;
3452 if (jbuf
->jb_strlen
+ len
> BUFSIZE
)
3453 joinbuf_flush(jbuf
);
3455 /* add channel to list of channels to send and update counts */
3456 jbuf
->jb_channels
[jbuf
->jb_count
++] = chan
;
3457 jbuf
->jb_strlen
+= len
;
3459 /* if we've used up all slots, flush */
3460 if (jbuf
->jb_count
>= MAXJOINARGS
)
3461 joinbuf_flush(jbuf
);
3465 * Flush the channel list to remote servers
3468 joinbuf_flush(struct JoinBuf
*jbuf
)
3470 char chanlist
[BUFSIZE
];
3474 if (!jbuf
->jb_count
|| jbuf
->jb_type
== JOINBUF_TYPE_PARTALL
||
3475 jbuf
->jb_type
== JOINBUF_TYPE_JOIN
)
3476 return 0; /* no joins to process */
3478 for (i
= 0; i
< jbuf
->jb_count
; i
++) { /* build channel list */
3479 build_string(chanlist
, &chanlist_i
,
3480 jbuf
->jb_channels
[i
] ? jbuf
->jb_channels
[i
]->chname
: "0", 0,
3481 i
== 0 ? '\0' : ',');
3482 if (JOINBUF_TYPE_PART
== jbuf
->jb_type
)
3483 /* Remove user from channel */
3484 remove_user_from_channel(jbuf
->jb_source
, jbuf
->jb_channels
[i
]);
3486 jbuf
->jb_channels
[i
] = 0; /* mark slot empty */
3489 jbuf
->jb_count
= 0; /* reset base counters */
3490 jbuf
->jb_strlen
= ((jbuf
->jb_type
== JOINBUF_TYPE_PART
?
3491 STARTJOINLEN
: STARTCREATELEN
) +
3492 (jbuf
->jb_comment
? strlen(jbuf
->jb_comment
) + 2 : 0));
3494 /* and send the appropriate command */
3495 switch (jbuf
->jb_type
) {
3496 case JOINBUF_TYPE_CREATE
:
3497 sendcmdto_serv_butone(jbuf
->jb_source
, CMD_CREATE
, jbuf
->jb_connect
,
3498 "%s %Tu", chanlist
, jbuf
->jb_create
);
3499 if (MyUser(jbuf
->jb_source
) && (feature_bool(FEAT_AUTOCHANMODES
) &&
3500 feature_str(FEAT_AUTOCHANMODES_LIST
) && (strlen(feature_str(FEAT_AUTOCHANMODES_LIST
)) > 0))) {
3503 for (name
= ircd_strtok(&p
, chanlist
, ","); name
; name
= ircd_strtok(&p
, 0, ",")) {
3504 sendcmdto_serv_butone(jbuf
->jb_source
, CMD_MODE
, jbuf
->jb_connect
,
3505 "%s %s%s", name
, "+", feature_str(FEAT_AUTOCHANMODES_LIST
));
3510 case JOINBUF_TYPE_PART
:
3511 sendcmdto_serv_butone(jbuf
->jb_source
, CMD_PART
, jbuf
->jb_connect
,
3512 jbuf
->jb_comment
? "%s :%s" : "%s", chanlist
,
3520 /* Returns TRUE (1) if client is invited, FALSE (0) if not */
3521 int IsInvited(struct Client
* cptr
, const void* chptr
)
3525 for (lp
= (cli_user(cptr
))->invited
; lp
; lp
= lp
->next
)
3526 if (lp
->value
.chptr
== chptr
)
3531 /* RevealDelayedJoin: sends a join for a hidden user */
3533 void RevealDelayedJoin(struct Membership
*member
)
3535 ClearDelayedJoin(member
);
3536 sendcmdto_channel_butserv_butone(member
->user
, CMD_JOIN
, member
->channel
, member
->user
, 0, ":%H",
3538 CheckDelayedJoins(member
->channel
);
3541 /* CheckDelayedJoins: checks and clear +d if necessary */
3543 void CheckDelayedJoins(struct Channel
*chan
)
3545 struct Membership
*memb2
;
3547 if (chan
->mode
.mode
& MODE_WASDELJOINS
) {
3548 for (memb2
=chan
->members
;memb2
;memb2
=memb2
->next_member
)
3549 if (IsDelayedJoin(memb2
))
3554 chan
->mode
.mode
&= ~MODE_WASDELJOINS
;
3555 sendcmdto_channel_butserv_butone(&his
, CMD_MODE
, chan
, NULL
, 0,