]>
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.2.12 2006/01/07 01:08:29 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
);
262 * Also channels without Apass set need to be kept alive,
263 * otherwise Bad Guys(tm) would be able to takeover
264 * existing channels too easily, and then set an Apass!
265 * However, if a channel without Apass becomes empty
266 * then we try to be kind to them and remove possible
269 chptr
->mode
.mode
&= ~MODE_INVITEONLY
;
270 chptr
->mode
.limit
= 0;
272 * We do NOT reset a possible key or bans because when
273 * the 'channel owners' can't get in because of a key
274 * or ban then apparently there was a fight/takeover
275 * on the channel and we want them to contact IRC opers
276 * who then will educate them on the use of Apass/Upass.
278 if (!chptr
->mode
.apass
[0]) /* If no Apass, reset all modes. */
280 struct Ban
*link
, *next
;
281 chptr
->mode
.mode
= 0;
282 *chptr
->mode
.key
= '\0';
283 while (chptr
->invites
)
284 del_invite(chptr
->invites
->value
.cptr
, chptr
);
285 for (link
= chptr
->banlist
; link
; link
= next
) {
289 chptr
->banlist
= NULL
;
291 /* Immediately destruct empty -A channels if not using apass. */
292 if (!feature_bool(FEAT_OPLEVELS
))
294 destruct_channel(chptr
);
298 if (TStime() - chptr
->creationtime
< 172800) /* Channel younger than 48 hours? */
299 schedule_destruct_event_1m(chptr
); /* Get rid of it in approximately 4-5 minutes */
301 schedule_destruct_event_48h(chptr
); /* Get rid of it in approximately 48 hours */
306 /** Destroy an empty channel
307 * This function destroys an empty channel, removing it from hashtables,
308 * and removing any resources it may have consumed.
310 * @param chptr The channel to destroy
312 * @returns 0 (success)
314 * FIXME: Change to return void, this function never fails.
316 int destruct_channel(struct Channel
* chptr
)
318 struct Ban
*ban
, *next
;
320 assert(0 == chptr
->members
);
323 * Now, find all invite links from channel structure
325 while (chptr
->invites
)
326 del_invite(chptr
->invites
->value
.cptr
, chptr
);
328 for (ban
= chptr
->banlist
; ban
; ban
= next
)
334 chptr
->prev
->next
= chptr
->next
;
336 GlobalChannelList
= chptr
->next
;
338 chptr
->next
->prev
= chptr
->prev
;
340 --UserStats
.channels
;
342 * make sure that channel actually got removed from hash table
344 assert(chptr
->hnext
== chptr
);
349 /** returns Membership * if a person is joined and not a zombie
351 * @param chptr Channel
352 * @returns pointer to the client's struct Membership * on the channel if that
353 * user is a full member of the channel, or NULL otherwise.
355 * @see find_member_link()
357 struct Membership
* find_channel_member(struct Client
* cptr
, struct Channel
* chptr
)
359 struct Membership
* member
;
362 member
= find_member_link(chptr
, cptr
);
363 return (member
&& !IsZombie(member
)) ? member
: 0;
366 /** Searches for a ban from a ban list that matches a user.
367 * @param[in] cptr The client to test.
368 * @param[in] banlist The list of bans to test.
369 * @return Pointer to a matching ban, or NULL if none exit.
371 struct Ban
*find_ban(struct Client
*cptr
, struct Ban
*banlist
)
373 char nu
[NICKLEN
+ USERLEN
+ 2];
374 char tmphost
[HOSTLEN
+ 1];
375 char iphost
[SOCKIPLEN
+ 1];
380 /* Build nick!user and alternate host names. */
381 ircd_snprintf(0, nu
, sizeof(nu
), "%s!%s",
382 cli_name(cptr
), cli_user(cptr
)->username
);
383 ircd_ntoa_r(iphost
, &cli_ip(cptr
));
384 if (!IsAccount(cptr
))
386 else if (HasHiddenHost(cptr
))
387 sr
= cli_user(cptr
)->realhost
;
390 ircd_snprintf(0, tmphost
, HOSTLEN
, "%s.%s",
391 cli_user(cptr
)->account
, feature_str(FEAT_HIDDEN_HOST
));
395 /* Walk through ban list. */
396 for (found
= NULL
; banlist
; banlist
= banlist
->next
) {
398 /* If we have found a positive ban already, only consider exceptions. */
399 if (found
&& !(banlist
->flags
& BAN_EXCEPTION
))
401 /* Compare nick!user portion of ban. */
402 banlist
->banstr
[banlist
->nu_len
] = '\0';
403 res
= match(banlist
->banstr
, nu
);
404 banlist
->banstr
[banlist
->nu_len
] = '@';
407 /* Compare host portion of ban. */
408 hostmask
= banlist
->banstr
+ banlist
->nu_len
+ 1;
409 if (!((banlist
->flags
& BAN_IPMASK
)
410 && ipmask_check(&cli_ip(cptr
), &banlist
->address
, banlist
->addrbits
))
411 && match(hostmask
, cli_user(cptr
)->host
)
412 && !(sr
&& !match(hostmask
, sr
)))
414 /* If an exception matches, no ban can match. */
415 if (banlist
->flags
& BAN_EXCEPTION
)
417 /* Otherwise, remember this ban but keep searching for an exception. */
424 * This function returns true if the user is banned on the said channel.
425 * This function will check the ban cache if applicable, otherwise will
426 * do the comparisons and cache the result.
428 * @param[in] member The Membership to test for banned-ness.
429 * @return Non-zero if the member is banned, zero if not.
431 static int is_banned(struct Membership
* member
)
433 if (IsBanValid(member
))
434 return IsBanned(member
);
437 if (find_ban(member
->user
, member
->channel
->banlist
)) {
446 /** add a user to a channel.
447 * adds a user to a channel by adding another link to the channels member
450 * @param chptr The channel to add to.
451 * @param who The user to add.
452 * @param flags The flags the user gets initially.
453 * @param oplevel The oplevel the user starts with.
455 void add_user_to_channel(struct Channel
* chptr
, struct Client
* who
,
456 unsigned int flags
, int oplevel
)
463 struct Membership
* member
= membershipFreeList
;
465 membershipFreeList
= member
->next_member
;
467 member
= (struct Membership
*) MyMalloc(sizeof(struct Membership
));
468 ++membershipAllocCount
;
473 member
->channel
= chptr
;
474 member
->status
= flags
;
475 SetOpLevel(member
, oplevel
);
477 member
->next_member
= chptr
->members
;
478 if (member
->next_member
)
479 member
->next_member
->prev_member
= member
;
480 member
->prev_member
= 0;
481 chptr
->members
= member
;
483 member
->next_channel
= (cli_user(who
))->channel
;
484 if (member
->next_channel
)
485 member
->next_channel
->prev_channel
= member
;
486 member
->prev_channel
= 0;
487 (cli_user(who
))->channel
= member
;
489 if (chptr
->destruct_event
)
490 remove_destruct_event(chptr
);
492 ++((cli_user(who
))->joined
);
496 /** Remove a person from a channel, given their Membership*
498 * @param member A member of a channel.
500 * @returns true if there are more people in the channel.
502 static int remove_member_from_channel(struct Membership
* member
)
504 struct Channel
* chptr
;
506 chptr
= member
->channel
;
508 * unlink channel member list
510 if (member
->next_member
)
511 member
->next_member
->prev_member
= member
->prev_member
;
512 if (member
->prev_member
)
513 member
->prev_member
->next_member
= member
->next_member
;
515 member
->channel
->members
= member
->next_member
;
518 * If this is the last delayed-join user, may have to clear WASDELJOINS.
520 if (IsDelayedJoin(member
))
521 CheckDelayedJoins(chptr
);
524 * unlink client channel list
526 if (member
->next_channel
)
527 member
->next_channel
->prev_channel
= member
->prev_channel
;
528 if (member
->prev_channel
)
529 member
->prev_channel
->next_channel
= member
->next_channel
;
531 (cli_user(member
->user
))->channel
= member
->next_channel
;
533 --(cli_user(member
->user
))->joined
;
535 member
->next_member
= membershipFreeList
;
536 membershipFreeList
= member
;
538 return sub1_from_channel(chptr
);
541 /** Check if all the remaining members on the channel are zombies
543 * @returns False if the channel has any non zombie members, True otherwise.
546 static int channel_all_zombies(struct Channel
* chptr
)
548 struct Membership
* member
;
550 for (member
= chptr
->members
; member
; member
= member
->next_member
) {
551 if (!IsZombie(member
))
558 /** Remove a user from a channel
559 * This is the generic entry point for removing a user from a channel, this
560 * function will remove the client from the channel, and destroy the channel
561 * if there are no more normal users left.
563 * @param cptr The client
564 * @param chptr The channel
566 void remove_user_from_channel(struct Client
* cptr
, struct Channel
* chptr
)
569 struct Membership
* member
;
572 if ((member
= find_member_link(chptr
, cptr
))) {
573 if (remove_member_from_channel(member
)) {
574 if (channel_all_zombies(chptr
)) {
576 * XXX - this looks dangerous but isn't if we got the referential
577 * integrity right for channels
579 while (remove_member_from_channel(chptr
->members
))
586 /** Remove a user from all channels they are on.
588 * This function removes a user from all channels they are on.
590 * @param cptr The client to remove.
592 void remove_user_from_all_channels(struct Client
* cptr
)
594 struct Membership
* chan
;
596 assert(0 != cli_user(cptr
));
598 while ((chan
= (cli_user(cptr
))->channel
))
599 remove_user_from_channel(cptr
, chan
->channel
);
602 /** Check if this user is a legitimate chanop
604 * @param cptr Client to check
605 * @param chptr Channel to check
607 * @returns True if the user is a chanop (And not a zombie), False otherwise.
610 int is_chan_op(struct Client
*cptr
, struct Channel
*chptr
)
612 struct Membership
* member
;
614 if ((member
= find_member_link(chptr
, cptr
)))
615 return (!IsZombie(member
) && IsChanOp(member
));
620 /** Check if a user is a Zombie on a specific channel.
622 * @param cptr The client to check.
623 * @param chptr The channel to check.
625 * @returns True if the client (cptr) is a zombie on the channel (chptr),
630 int is_zombie(struct Client
*cptr
, struct Channel
*chptr
)
632 struct Membership
* member
;
636 if ((member
= find_member_link(chptr
, cptr
)))
637 return IsZombie(member
);
641 /** Returns if a user has voice on a channel.
643 * @param cptr The client
644 * @param chptr The channel
646 * @returns True if the client (cptr) is voiced on (chptr) and is not a zombie.
649 int has_voice(struct Client
* cptr
, struct Channel
* chptr
)
651 struct Membership
* member
;
654 if ((member
= find_member_link(chptr
, cptr
)))
655 return (!IsZombie(member
) && HasVoice(member
));
660 /** Can this member send to a channel
662 * A user can speak on a channel iff:
664 * <li> They didn't use the Apass to gain ops.
665 * <li> They are op'd or voice'd.
666 * <li> You aren't banned.
667 * <li> The channel isn't +m
668 * <li> The channel isn't +n or you are on the channel.
671 * This function will optionally reveal a user on a delayed join channel if
672 * they are allowed to send to the channel.
674 * @param member The membership of the user
675 * @param reveal If true, the user will be "revealed" on a delayed
678 * @returns True if the client can speak on the channel.
680 int member_can_send_to_channel(struct Membership
* member
, int reveal
)
684 /* Do not check for users on other servers: This should be a
685 * temporary desynch, or maybe they are on an older server, but
686 * we do not want to send ERR_CANNOTSENDTOCHAN more than once.
688 if (!MyUser(member
->user
))
690 if (IsDelayedJoin(member
) && reveal
)
691 RevealDelayedJoin(member
);
695 /* Discourage using the Apass to get op. They should use the Upass. */
696 if (IsChannelManager(member
) && member
->channel
->mode
.apass
[0])
699 /* If you have voice or ops, you can speak. */
700 if (IsVoicedOrOpped(member
))
704 * If it's moderated, and you aren't a privileged user, you can't
707 if (member
->channel
->mode
.mode
& MODE_MODERATED
)
710 /* If only logged in users may join and you're not one, you can't speak. */
711 if (member
->channel
->mode
.mode
& MODE_REGONLY
&& !IsAccount(member
->user
))
714 /* If you're banned then you can't speak either. */
715 if (is_banned(member
))
718 if (IsDelayedJoin(member
) && reveal
)
719 RevealDelayedJoin(member
);
724 /** Check if a client can send to a channel.
726 * Has the added check over member_can_send_to_channel() of servers can
729 * @param cptr The client to check
730 * @param chptr The channel to check
731 * @param reveal If the user should be revealed (see
732 * member_can_send_to_channel())
734 * @returns true if the client is allowed to speak on the channel, false
737 * @see member_can_send_to_channel()
739 int client_can_send_to_channel(struct Client
*cptr
, struct Channel
*chptr
, int reveal
)
741 struct Membership
*member
;
744 * Servers can always speak on channels.
749 member
= find_channel_member(cptr
, chptr
);
752 * You can't speak if you're off channel, and it is +n (no external messages)
756 if ((chptr
->mode
.mode
& (MODE_NOPRIVMSGS
|MODE_MODERATED
)) ||
757 ((chptr
->mode
.mode
& MODE_REGONLY
) && !IsAccount(cptr
)))
760 return !find_ban(cptr
, chptr
->banlist
);
762 return member_can_send_to_channel(member
, reveal
);
765 /** Returns the name of a channel that prevents the user from changing nick.
766 * if a member and not (opped or voiced) and (banned or moderated), return
767 * the name of the first channel banned on.
769 * @param cptr The client
771 * @returns the name of the first channel banned on, or NULL if the user
774 const char* find_no_nickchange_channel(struct Client
* cptr
)
777 struct Membership
* member
;
778 for (member
= (cli_user(cptr
))->channel
; member
;
779 member
= member
->next_channel
) {
780 if (IsVoicedOrOpped(member
))
782 if ((member
->channel
->mode
.mode
& MODE_MODERATED
)
783 || (member
->channel
->mode
.mode
& MODE_REGONLY
&& !IsAccount(cptr
))
784 || is_banned(member
))
785 return member
->channel
->chname
;
792 /** Fill mbuf/pbuf with modes from chptr
793 * write the "simple" list of channel modes for channel chptr onto buffer mbuf
794 * with the parameters in pbuf as visible by cptr.
796 * This function will hide keys from non-op'd, non-server clients.
798 * @param cptr The client to generate the mode for.
799 * @param mbuf The buffer to write the modes into.
800 * @param pbuf The buffer to write the mode parameters into.
801 * @param buflen The length of the buffers.
802 * @param chptr The channel to get the modes from.
803 * @param member The membership of this client on this channel (or NULL
804 * if this client isn't on this channel)
807 void channel_modes(struct Client
*cptr
, char *mbuf
, char *pbuf
, int buflen
,
808 struct Channel
*chptr
, struct Membership
*member
)
810 int previous_parameter
= 0;
817 if (chptr
->mode
.mode
& MODE_SECRET
)
819 else if (chptr
->mode
.mode
& MODE_PRIVATE
)
821 if (chptr
->mode
.mode
& MODE_MODERATED
)
823 if (chptr
->mode
.mode
& MODE_TOPICLIMIT
)
825 if (chptr
->mode
.mode
& MODE_INVITEONLY
)
827 if (chptr
->mode
.mode
& MODE_NOPRIVMSGS
)
829 if (chptr
->mode
.mode
& MODE_REGONLY
)
831 if (chptr
->mode
.mode
& MODE_DELJOINS
)
833 else if (MyUser(cptr
) && (chptr
->mode
.mode
& MODE_WASDELJOINS
))
835 if (chptr
->mode
.limit
) {
837 ircd_snprintf(0, pbuf
, buflen
, "%u", chptr
->mode
.limit
);
838 previous_parameter
= 1;
841 if (*chptr
->mode
.key
) {
843 if (previous_parameter
)
845 if (is_chan_op(cptr
, chptr
) || IsServer(cptr
)) {
846 strcat(pbuf
, chptr
->mode
.key
);
849 previous_parameter
= 1;
851 if (*chptr
->mode
.apass
) {
853 if (previous_parameter
)
855 if (IsServer(cptr
)) {
856 strcat(pbuf
, chptr
->mode
.apass
);
859 previous_parameter
= 1;
861 if (*chptr
->mode
.upass
) {
863 if (previous_parameter
)
865 if (IsServer(cptr
) || (member
&& IsChanOp(member
) && OpLevel(member
) == 0)) {
866 strcat(pbuf
, chptr
->mode
.upass
);
873 /** Compare two members oplevel
875 * @param mp1 Pointer to a pointer to a membership
876 * @param mp2 Pointer to a pointer to a membership
878 * @returns 0 if equal, -1 if mp1 is lower, +1 otherwise.
882 int compare_member_oplevel(const void *mp1
, const void *mp2
)
884 struct Membership
const* member1
= *(struct Membership
const**)mp1
;
885 struct Membership
const* member2
= *(struct Membership
const**)mp2
;
886 if (member1
->oplevel
== member2
->oplevel
)
888 return (member1
->oplevel
< member2
->oplevel
) ? -1 : 1;
891 /* send "cptr" a full list of the modes for channel chptr.
893 * Sends a BURST line to cptr, bursting all the modes for the channel.
895 * @param cptr Client pointer
896 * @param chptr Channel pointer
898 void send_channel_modes(struct Client
*cptr
, struct Channel
*chptr
)
900 /* The order in which modes are generated is now mandatory */
901 static unsigned int current_flags
[4] =
902 { 0, CHFL_VOICE
, CHFL_CHANOP
, CHFL_CHANOP
| CHFL_VOICE
};
908 struct Membership
* member
;
910 char modebuf
[MODEBUFLEN
];
911 char parabuf
[MODEBUFLEN
];
913 int number_of_ops
= 0;
914 int opped_members_index
= 0;
915 struct Membership
** opped_members
= NULL
;
916 int last_oplevel
= 0;
917 int feat_oplevels
= (chptr
->mode
.apass
[0]) != '\0';
922 if (IsLocalChannel(chptr
->chname
))
925 member
= chptr
->members
;
926 lp2
= chptr
->banlist
;
928 *modebuf
= *parabuf
= '\0';
929 channel_modes(cptr
, modebuf
, parabuf
, sizeof(parabuf
), chptr
, 0);
931 for (first
= 1; full
; first
= 0) /* Loop for multiple messages */
933 full
= 0; /* Assume by default we get it
934 all in one message */
936 /* (Continued) prefix: "<Y> B <channel> <TS>" */
937 /* is there any better way we can do this? */
938 mb
= msgq_make(&me
, "%C " TOK_BURST
" %H %Tu", &me
, chptr
,
939 chptr
->creationtime
);
941 if (first
&& modebuf
[1]) /* Add simple modes (Aiklmnpstu)
944 /* prefix: "<Y> B <channel> <TS>[ <modes>[ <params>]]" */
945 msgq_append(&me
, mb
, " %s", modebuf
);
948 msgq_append(&me
, mb
, " %s", parabuf
);
952 * Attach nicks, comma separated " nick[:modes],nick[:modes],..."
954 * First find all opless members.
955 * Run 2 times over all members, to group the members with
956 * and without voice together.
957 * Then run 2 times over all opped members (which are ordered
958 * by op-level) to also group voice and non-voice together.
960 for (first
= 1; flag_cnt
< 4; new_mode
= 1, ++flag_cnt
)
964 if (flag_cnt
< 2 && IsChanOp(member
))
967 * The first loop (to find all non-voice/op), we count the ops.
968 * The second loop (to find all voiced non-ops), store the ops
969 * in a dynamic array.
974 opped_members
[opped_members_index
++] = member
;
976 /* Only handle the members with the flags that we are interested in. */
977 if ((member
->status
& CHFL_VOICED_OR_OPPED
) == current_flags
[flag_cnt
])
979 if (msgq_bufleft(mb
) < NUMNICKLEN
+ 3 + MAXOPLEVELDIGITS
)
980 /* The 3 + MAXOPLEVELDIGITS is a possible ",:v999". */
982 full
= 1; /* Make sure we continue after
984 /* Ensure the new BURST line contains the current
985 * ":mode", except when there is no mode yet. */
986 new_mode
= (flag_cnt
> 0) ? 1 : 0;
987 break; /* Do not add this member to this message */
989 msgq_append(&me
, mb
, "%c%C", first
? ' ' : ',', member
->user
);
990 first
= 0; /* From now on, use commas to add new nicks */
993 * Do we have a nick with a new mode ?
994 * Or are we starting a new BURST line?
999 * This means we are at the _first_ member that has only
1000 * voice, or the first member that has only ops, or the
1001 * first member that has voice and ops (so we get here
1002 * at most three times, plus once for every start of
1003 * a continued BURST line where only these modes is current.
1004 * In the two cases where the current mode includes ops,
1005 * we need to add the _absolute_ value of the oplevel to the mode.
1007 char tbuf
[3 + MAXOPLEVELDIGITS
] = ":";
1010 if (HasVoice(member
)) /* flag_cnt == 1 or 3 */
1012 if (IsChanOp(member
)) /* flag_cnt == 2 or 3 */
1014 /* append the absolute value of the oplevel */
1016 loc
+= ircd_snprintf(0, tbuf
+ loc
, sizeof(tbuf
) - loc
, "%u", last_oplevel
= member
->oplevel
);
1021 msgq_append(&me
, mb
, tbuf
);
1024 else if (feat_oplevels
&& flag_cnt
> 1 && last_oplevel
!= member
->oplevel
)
1027 * This can't be the first member of a (continued) BURST
1028 * message because then either flag_cnt == 0 or new_mode == 1
1029 * Now we need to append the incremental value of the oplevel.
1031 char tbuf
[2 + MAXOPLEVELDIGITS
];
1032 ircd_snprintf(0, tbuf
, sizeof(tbuf
), ":%u", member
->oplevel
- last_oplevel
);
1033 last_oplevel
= member
->oplevel
;
1034 msgq_append(&me
, mb
, tbuf
);
1037 /* Go to the next `member'. */
1039 member
= member
->next_member
;
1041 member
= opped_members
[++opped_members_index
];
1046 /* Point `member' at the start of the list again. */
1049 member
= chptr
->members
;
1050 /* Now, after one loop, we know the number of ops and can
1051 * allocate the dynamic array with pointer to the ops. */
1052 opped_members
= (struct Membership
**)
1053 MyMalloc((number_of_ops
+ 1) * sizeof(struct Membership
*));
1054 opped_members
[number_of_ops
] = NULL
; /* Needed for loop termination */
1058 /* At the end of the second loop, sort the opped members with
1059 * increasing op-level, so that we will output them in the
1060 * correct order (and all op-level increments stay positive) */
1062 qsort(opped_members
, number_of_ops
,
1063 sizeof(struct Membership
*), compare_member_oplevel
);
1064 /* The third and fourth loop run only over the opped members. */
1065 member
= opped_members
[(opped_members_index
= 0)];
1068 } /* loop over 0,+v,+o,+ov */
1072 /* Attach all bans, space separated " :%ban ban ..." */
1073 for (first
= 2; lp2
; lp2
= lp2
->next
)
1075 len
= strlen(lp2
->banstr
);
1076 if (msgq_bufleft(mb
) < len
+ 1 + first
)
1077 /* The +1 stands for the added ' '.
1078 * The +first stands for the added ":%".
1084 msgq_append(&me
, mb
, " %s%s", first
? ":%" : "",
1090 send_buffer(cptr
, mb
, 0); /* Send this message */
1092 } /* Continue when there was something
1093 that didn't fit (full==1) */
1095 MyFree(opped_members
);
1096 if (feature_bool(FEAT_TOPIC_BURST
) && (chptr
->topic
[0] != '\0'))
1097 sendcmdto_one(&me
, CMD_TOPIC
, cptr
, "%H %Tu %Tu :%s", chptr
,
1098 chptr
->creationtime
, chptr
->topic_time
, chptr
->topic
);
1101 /** Canonify a mask.
1104 * @author Carlo Wood (Run),
1107 * When the nick is longer then NICKLEN, it is cut off (its an error of course).
1108 * When the user name or host name are too long (USERLEN and HOSTLEN
1109 * respectively) then they are cut off at the start with a '*'.
1111 * The following transformations are made:
1113 * 1) xxx -> nick!*@*
1114 * 2) xxx.xxx -> *!*\@host
1115 * 3) xxx\!yyy -> nick!user\@*
1116 * 4) xxx\@yyy -> *!user\@host
1117 * 5) xxx!yyy\@zzz -> nick!user\@host
1119 * @param mask The uncanonified mask.
1120 * @returns The updated mask in a static buffer.
1122 char *pretty_mask(char *mask
)
1124 static char star
[2] = { '*', 0 };
1125 static char retmask
[NICKLEN
+ USERLEN
+ HOSTLEN
+ 3];
1126 char *last_dot
= NULL
;
1129 /* Case 1: default */
1134 /* Do a _single_ pass through the characters of the mask: */
1135 for (ptr
= mask
; *ptr
; ++ptr
)
1139 /* Case 3 or 5: Found first '!' (without finding a '@' yet) */
1143 else if (*ptr
== '@')
1145 /* Case 4: Found last '@' (without finding a '!' yet) */
1150 else if (*ptr
== '.' || *ptr
== ':')
1152 /* Case 2: Found character specific to IP or hostname (without
1153 * finding a '!' or '@' yet) */
1163 /* Case 4 or 5: Found last '@' */
1169 if (user
== star
&& last_dot
)
1179 char *nick_end
= (user
!= star
) ? user
- 1 : ptr
;
1180 if (nick_end
- nick
> NICKLEN
)
1186 char *user_end
= (host
!= star
) ? host
- 1 : ptr
;
1187 if (user_end
- user
> USERLEN
)
1189 user
= user_end
- USERLEN
;
1194 if (host
!= star
&& ptr
- host
> HOSTLEN
)
1196 host
= ptr
- HOSTLEN
;
1199 ircd_snprintf(0, retmask
, sizeof(retmask
), "%s!%s@%s", nick
, user
, host
);
1203 /** send a banlist to a client for a channel
1205 * @param cptr Client to send the banlist to.
1206 * @param chptr Channel whose banlist to send.
1208 static void send_ban_list(struct Client
* cptr
, struct Channel
* chptr
)
1215 for (lp
= chptr
->banlist
; lp
; lp
= lp
->next
)
1216 send_reply(cptr
, RPL_BANLIST
, chptr
->chname
, lp
->banstr
,
1219 send_reply(cptr
, RPL_ENDOFBANLIST
, chptr
->chname
);
1222 /** Remove bells and commas from channel name
1224 * @param cn Channel name to clean, modified in place.
1226 void clean_channelname(char *cn
)
1230 for (i
= 0; cn
[i
]; i
++) {
1231 if (i
>= IRCD_MIN(CHANNELLEN
, feature_int(FEAT_CHANNELLEN
))
1232 || !IsChannelChar(cn
[i
])) {
1236 if (IsChannelLower(cn
[i
])) {
1237 cn
[i
] = ToLower(cn
[i
]);
1243 if ((unsigned char)(cn
[i
]) == 0xd0)
1244 cn
[i
] = (char) 0xf0;
1250 /** Get a channel block, creating if necessary.
1251 * Get Channel block for chname (and allocate a new channel
1252 * block, if it didn't exists before).
1254 * @param cptr Client joining the channel.
1255 * @param chname The name of the channel to join.
1256 * @param flag set to CGT_CREATE to create the channel if it doesn't
1259 * @returns NULL if the channel is invalid, doesn't exist and CGT_CREATE
1260 * wasn't specified or a pointer to the channel structure
1262 struct Channel
*get_channel(struct Client
*cptr
, char *chname
, ChannelGetType flag
)
1264 struct Channel
*chptr
;
1267 if (EmptyString(chname
))
1270 len
= strlen(chname
);
1271 if (MyUser(cptr
) && len
> CHANNELLEN
)
1274 *(chname
+ CHANNELLEN
) = '\0';
1276 if ((chptr
= FindChannel(chname
)))
1278 if (flag
== CGT_CREATE
)
1280 chptr
= (struct Channel
*) MyMalloc(sizeof(struct Channel
) + len
);
1282 ++UserStats
.channels
;
1283 memset(chptr
, 0, sizeof(struct Channel
));
1284 strcpy(chptr
->chname
, chname
);
1285 if (GlobalChannelList
)
1286 GlobalChannelList
->prev
= chptr
;
1288 chptr
->next
= GlobalChannelList
;
1289 chptr
->creationtime
= MyUser(cptr
) ? TStime() : (time_t) 0;
1290 GlobalChannelList
= chptr
;
1296 /** invite a user to a channel.
1298 * Adds an invite for a user to a channel. Limits the number of invites
1299 * to FEAT_MAXCHANNELSPERUSER. Does not sent notification to the user.
1301 * @param cptr The client to be invited.
1302 * @param chptr The channel to be invited to.
1304 void add_invite(struct Client
*cptr
, struct Channel
*chptr
)
1306 struct SLink
*inv
, **tmp
;
1308 del_invite(cptr
, chptr
);
1310 * Delete last link in chain if the list is max length
1312 assert(list_length((cli_user(cptr
))->invited
) == (cli_user(cptr
))->invites
);
1313 if ((cli_user(cptr
))->invites
>= feature_int(FEAT_MAXCHANNELSPERUSER
))
1314 del_invite(cptr
, (cli_user(cptr
))->invited
->value
.chptr
);
1316 * Add client to channel invite list
1319 inv
->value
.cptr
= cptr
;
1320 inv
->next
= chptr
->invites
;
1321 chptr
->invites
= inv
;
1323 * Add channel to the end of the client invite list
1325 for (tmp
= &((cli_user(cptr
))->invited
); *tmp
; tmp
= &((*tmp
)->next
));
1327 inv
->value
.chptr
= chptr
;
1330 (cli_user(cptr
))->invites
++;
1333 /** Delete an invite
1334 * Delete Invite block from channel invite list and client invite list
1336 * @param cptr Client pointer
1337 * @param chptr Channel pointer
1339 void del_invite(struct Client
*cptr
, struct Channel
*chptr
)
1341 struct SLink
**inv
, *tmp
;
1343 for (inv
= &(chptr
->invites
); (tmp
= *inv
); inv
= &tmp
->next
)
1344 if (tmp
->value
.cptr
== cptr
)
1349 (cli_user(cptr
))->invites
--;
1353 for (inv
= &((cli_user(cptr
))->invited
); (tmp
= *inv
); inv
= &tmp
->next
)
1354 if (tmp
->value
.chptr
== chptr
)
1363 /** @page zombie Explanation of Zombies
1367 * A channel member is turned into a zombie when he is kicked from a
1368 * channel but his server has not acknowledged the kick. Servers that
1369 * see the member as a zombie can accept actions he performed before
1370 * being kicked, without allowing chanop operations from outsiders or
1371 * desyncing the network.
1379 * X --a--> A --b--> B --d--> D
1384 * Where `who' is being KICK-ed by a "KICK" message received by server 'A'
1385 * via 'a', or on server 'B' via either 'b' or 'c', or on server D via 'd'.
1387 * a) On server A : set CHFL_ZOMBIE for `who' (lp) and pass on the KICK.
1388 * Remove the user immediately when no users are left on the channel.
1389 * b) On server B : remove the user (who/lp) from the channel, send a
1390 * PART upstream (to A) and pass on the KICK.
1391 * c) KICKed by `client'; On server B : remove the user (who/lp) from the
1392 * channel, and pass on the KICK.
1393 * d) On server D : remove the user (who/lp) from the channel, and pass on
1397 * - Setting the ZOMBIE flag never hurts, we either remove the
1398 * client after that or we don't.
1399 * - The KICK message was already passed on, as should be in all cases.
1400 * - `who' is removed in all cases except case a) when users are left.
1401 * - A PART is only sent upstream in case b).
1407 * 1 --- 2 --- 3 --- 4 --- 5
1412 * We also need to turn 'who' into a zombie on servers 1 and 6,
1413 * because a KICK from 'who' (kicking someone else in that direction)
1414 * can arrive there afterward - which should not be bounced itself.
1415 * Therefore case a) also applies for servers 1 and 6.
1420 /** Turn a user on a channel into a zombie
1421 * This function turns a user into a zombie (see \ref zombie)
1423 * @param member The structure representing this user on this channel.
1424 * @param who The client that is being kicked.
1425 * @param cptr The connection the kick came from.
1426 * @param sptr The client that is doing the kicking.
1427 * @param chptr The channel the user is being kicked from.
1429 void make_zombie(struct Membership
* member
, struct Client
* who
,
1430 struct Client
* cptr
, struct Client
* sptr
, struct Channel
* chptr
)
1432 assert(0 != member
);
1437 /* Default for case a): */
1440 /* Case b) or c) ?: */
1441 if (MyUser(who
)) /* server 4 */
1443 if (IsServer(cptr
)) /* Case b) ? */
1444 sendcmdto_one(who
, CMD_PART
, cptr
, "%H", chptr
);
1445 remove_user_from_channel(who
, chptr
);
1448 if (cli_from(who
) == cptr
) /* True on servers 1, 5 and 6 */
1450 struct Client
*acptr
= IsServer(sptr
) ? sptr
: (cli_user(sptr
))->server
;
1451 for (; acptr
!= &me
; acptr
= (cli_serv(acptr
))->up
)
1452 if (acptr
== (cli_user(who
))->server
) /* Case d) (server 5) */
1454 remove_user_from_channel(who
, chptr
);
1459 /* Case a) (servers 1, 2, 3 and 6) */
1460 if (channel_all_zombies(chptr
))
1461 remove_user_from_channel(who
, chptr
);
1463 /* XXX Can't actually call Debug here; if the channel is all zombies,
1464 * chptr will no longer exist when we get here.
1465 Debug((DEBUG_INFO, "%s is now a zombie on %s", who->name, chptr->chname));
1469 /** returns the number of zombies on a channel
1470 * @param chptr Channel to count zombies in.
1472 * @returns The number of zombies on the channel.
1474 int number_of_zombies(struct Channel
*chptr
)
1476 struct Membership
* member
;
1480 for (member
= chptr
->members
; member
; member
= member
->next_member
) {
1481 if (IsZombie(member
))
1487 /** Concatenate some strings together.
1488 * This helper function builds an argument string in strptr, consisting
1489 * of the original string, a space, and str1 and str2 concatenated (if,
1490 * of course, str2 is not NULL)
1492 * @param strptr The buffer to concatenate into
1493 * @param strptr_i modified offset to the position to modify
1494 * @param str1 The string to concatenate from.
1495 * @param str2 The second string to contatenate from.
1496 * @param c Charactor to separate the string from str1 and str2.
1499 build_string(char *strptr
, int *strptr_i
, const char *str1
,
1500 const char *str2
, char c
)
1503 strptr
[(*strptr_i
)++] = c
;
1506 strptr
[(*strptr_i
)++] = *(str1
++);
1510 strptr
[(*strptr_i
)++] = *(str2
++);
1512 strptr
[(*strptr_i
)] = '\0';
1515 /** Flush out the modes
1516 * This is the workhorse of our ModeBuf suite; this actually generates the
1517 * output MODE commands, HACK notices, or whatever. It's pretty complicated.
1519 * @param mbuf The mode buffer to flush
1520 * @param all If true, flush all modes, otherwise leave partial modes in the
1526 modebuf_flush_int(struct ModeBuf
*mbuf
, int all
)
1528 /* we only need the flags that don't take args right now */
1529 static int flags
[] = {
1530 /* MODE_CHANOP, 'o', */
1531 /* MODE_VOICE, 'v', */
1534 MODE_MODERATED
, 'm',
1535 MODE_TOPICLIMIT
, 't',
1536 MODE_INVITEONLY
, 'i',
1537 MODE_NOPRIVMSGS
, 'n',
1540 /* MODE_KEY, 'k', */
1541 /* MODE_BAN, 'b', */
1543 /* MODE_APASS, 'A', */
1544 /* MODE_UPASS, 'U', */
1547 static int local_flags
[] = {
1548 MODE_WASDELJOINS
, 'd',
1554 struct Client
*app_source
; /* where the MODE appears to come from */
1556 char addbuf
[20], addbuf_local
[20]; /* accumulates +psmtin, etc. */
1557 int addbuf_i
= 0, addbuf_local_i
= 0;
1558 char rembuf
[20], rembuf_local
[20]; /* accumulates -psmtin, etc. */
1559 int rembuf_i
= 0, rembuf_local_i
= 0;
1560 char *bufptr
; /* we make use of indirection to simplify the code */
1563 char addstr
[BUFSIZE
]; /* accumulates MODE parameters to add */
1565 char remstr
[BUFSIZE
]; /* accumulates MODE parameters to remove */
1567 char *strptr
; /* more indirection to simplify the code */
1570 int totalbuflen
= BUFSIZE
- 200; /* fuzz factor -- don't overrun buffer! */
1573 char limitbuf
[20]; /* convert limits to strings */
1575 unsigned int limitdel
= MODE_LIMIT
;
1579 /* If the ModeBuf is empty, we have nothing to do */
1580 if (mbuf
->mb_add
== 0 && mbuf
->mb_rem
== 0 && mbuf
->mb_count
== 0)
1583 /* Ok, if we were given the OPMODE flag, or its a server, hide the source.
1585 if (feature_bool(FEAT_HIS_MODEWHO
) &&
1586 (mbuf
->mb_dest
& MODEBUF_DEST_OPMODE
||
1587 IsServer(mbuf
->mb_source
) ||
1588 IsMe(mbuf
->mb_source
)))
1591 app_source
= mbuf
->mb_source
;
1594 * Account for user we're bouncing; we have to get it in on the first
1595 * bounced MODE, or we could have problems
1597 if (mbuf
->mb_dest
& MODEBUF_DEST_DEOP
)
1598 totalbuflen
-= 6; /* numeric nick == 5, plus one space */
1600 /* Calculate the simple flags */
1601 for (flag_p
= flags
; flag_p
[0]; flag_p
+= 2) {
1602 if (*flag_p
& mbuf
->mb_add
)
1603 addbuf
[addbuf_i
++] = flag_p
[1];
1604 else if (*flag_p
& mbuf
->mb_rem
)
1605 rembuf
[rembuf_i
++] = flag_p
[1];
1608 /* Some flags may be for local display only. */
1609 for (flag_p
= local_flags
; flag_p
[0]; flag_p
+= 2) {
1610 if (*flag_p
& mbuf
->mb_add
)
1611 addbuf_local
[addbuf_local_i
++] = flag_p
[1];
1612 else if (*flag_p
& mbuf
->mb_rem
)
1613 rembuf_local
[rembuf_local_i
++] = flag_p
[1];
1616 /* Now go through the modes with arguments... */
1617 for (i
= 0; i
< mbuf
->mb_count
; i
++) {
1618 if (MB_TYPE(mbuf
, i
) & MODE_ADD
) { /* adding or removing? */
1620 bufptr_i
= &addbuf_i
;
1623 bufptr_i
= &rembuf_i
;
1626 if (MB_TYPE(mbuf
, i
) & (MODE_CHANOP
| MODE_VOICE
)) {
1627 tmp
= strlen(cli_name(MB_CLIENT(mbuf
, i
)));
1629 if ((totalbuflen
- IRCD_MAX(9, tmp
)) <= 0) /* don't overflow buffer */
1630 MB_TYPE(mbuf
, i
) |= MODE_SAVE
; /* save for later */
1632 bufptr
[(*bufptr_i
)++] = MB_TYPE(mbuf
, i
) & MODE_CHANOP
? 'o' : 'v';
1633 totalbuflen
-= IRCD_MAX(9, tmp
) + 1;
1635 } else if (MB_TYPE(mbuf
, i
) & (MODE_BAN
| MODE_APASS
| MODE_UPASS
)) {
1636 tmp
= strlen(MB_STRING(mbuf
, i
));
1638 if ((totalbuflen
- tmp
) <= 0) /* don't overflow buffer */
1639 MB_TYPE(mbuf
, i
) |= MODE_SAVE
; /* save for later */
1642 switch(MB_TYPE(mbuf
, i
) & (MODE_BAN
| MODE_APASS
| MODE_UPASS
))
1654 bufptr
[(*bufptr_i
)++] = mode_char
;
1655 totalbuflen
-= tmp
+ 1;
1657 } else if (MB_TYPE(mbuf
, i
) & MODE_KEY
) {
1658 tmp
= (mbuf
->mb_dest
& MODEBUF_DEST_NOKEY
? 1 :
1659 strlen(MB_STRING(mbuf
, i
)));
1661 if ((totalbuflen
- tmp
) <= 0) /* don't overflow buffer */
1662 MB_TYPE(mbuf
, i
) |= MODE_SAVE
; /* save for later */
1664 bufptr
[(*bufptr_i
)++] = 'k';
1665 totalbuflen
-= tmp
+ 1;
1667 } else if (MB_TYPE(mbuf
, i
) & MODE_LIMIT
) {
1668 /* if it's a limit, we also format the number */
1669 ircd_snprintf(0, limitbuf
, sizeof(limitbuf
), "%u", MB_UINT(mbuf
, i
));
1671 tmp
= strlen(limitbuf
);
1673 if ((totalbuflen
- tmp
) <= 0) /* don't overflow buffer */
1674 MB_TYPE(mbuf
, i
) |= MODE_SAVE
; /* save for later */
1676 bufptr
[(*bufptr_i
)++] = 'l';
1677 totalbuflen
-= tmp
+ 1;
1682 /* terminate the mode strings */
1683 addbuf
[addbuf_i
] = '\0';
1684 rembuf
[rembuf_i
] = '\0';
1685 addbuf_local
[addbuf_local_i
] = '\0';
1686 rembuf_local
[rembuf_local_i
] = '\0';
1688 /* If we're building a user visible MODE or HACK... */
1689 if (mbuf
->mb_dest
& (MODEBUF_DEST_CHANNEL
| MODEBUF_DEST_HACK2
|
1690 MODEBUF_DEST_HACK3
| MODEBUF_DEST_HACK4
|
1691 MODEBUF_DEST_LOG
)) {
1692 /* Set up the parameter strings */
1698 for (i
= 0; i
< mbuf
->mb_count
; i
++) {
1699 if (MB_TYPE(mbuf
, i
) & MODE_SAVE
)
1702 if (MB_TYPE(mbuf
, i
) & MODE_ADD
) { /* adding or removing? */
1704 strptr_i
= &addstr_i
;
1707 strptr_i
= &remstr_i
;
1710 /* deal with clients... */
1711 if (MB_TYPE(mbuf
, i
) & (MODE_CHANOP
| MODE_VOICE
))
1712 build_string(strptr
, strptr_i
, cli_name(MB_CLIENT(mbuf
, i
)), 0, ' ');
1714 /* deal with bans... */
1715 else if (MB_TYPE(mbuf
, i
) & MODE_BAN
)
1716 build_string(strptr
, strptr_i
, MB_STRING(mbuf
, i
), 0, ' ');
1718 /* deal with keys... */
1719 else if (MB_TYPE(mbuf
, i
) & MODE_KEY
)
1720 build_string(strptr
, strptr_i
, mbuf
->mb_dest
& MODEBUF_DEST_NOKEY
?
1721 "*" : MB_STRING(mbuf
, i
), 0, ' ');
1723 /* deal with invisible passwords */
1724 else if (MB_TYPE(mbuf
, i
) & (MODE_APASS
| MODE_UPASS
))
1725 build_string(strptr
, strptr_i
, "*", 0, ' ');
1728 * deal with limit; note we cannot include the limit parameter if we're
1731 else if ((MB_TYPE(mbuf
, i
) & (MODE_ADD
| MODE_LIMIT
)) ==
1732 (MODE_ADD
| MODE_LIMIT
))
1733 build_string(strptr
, strptr_i
, limitbuf
, 0, ' ');
1736 /* send the messages off to their destination */
1737 if (mbuf
->mb_dest
& MODEBUF_DEST_HACK2
)
1738 sendto_opmask_butone(0, SNO_HACK2
, "HACK(2): %s MODE %s %s%s%s%s%s%s "
1740 cli_name(feature_bool(FEAT_HIS_SNOTICES
) ?
1741 mbuf
->mb_source
: app_source
),
1742 mbuf
->mb_channel
->chname
,
1743 rembuf_i
? "-" : "", rembuf
, addbuf_i
? "+" : "",
1744 addbuf
, remstr
, addstr
,
1745 mbuf
->mb_channel
->creationtime
);
1747 if (mbuf
->mb_dest
& MODEBUF_DEST_HACK3
)
1748 sendto_opmask_butone(0, SNO_HACK3
, "BOUNCE or HACK(3): %s MODE %s "
1749 "%s%s%s%s%s%s [%Tu]",
1750 cli_name(feature_bool(FEAT_HIS_SNOTICES
) ?
1751 mbuf
->mb_source
: app_source
),
1752 mbuf
->mb_channel
->chname
, rembuf_i
? "-" : "",
1753 rembuf
, addbuf_i
? "+" : "", addbuf
, remstr
, addstr
,
1754 mbuf
->mb_channel
->creationtime
);
1756 if (mbuf
->mb_dest
& MODEBUF_DEST_HACK4
)
1757 sendto_opmask_butone(0, SNO_HACK4
, "HACK(4): %s MODE %s %s%s%s%s%s%s "
1759 cli_name(feature_bool(FEAT_HIS_SNOTICES
) ?
1760 mbuf
->mb_source
: app_source
),
1761 mbuf
->mb_channel
->chname
,
1762 rembuf_i
? "-" : "", rembuf
, addbuf_i
? "+" : "",
1763 addbuf
, remstr
, addstr
,
1764 mbuf
->mb_channel
->creationtime
);
1766 if (mbuf
->mb_dest
& MODEBUF_DEST_LOG
)
1767 log_write(LS_OPERMODE
, L_INFO
, LOG_NOSNOTICE
,
1768 "%#C OPMODE %H %s%s%s%s%s%s", mbuf
->mb_source
,
1769 mbuf
->mb_channel
, rembuf_i
? "-" : "", rembuf
,
1770 addbuf_i
? "+" : "", addbuf
, remstr
, addstr
);
1772 if (mbuf
->mb_dest
& MODEBUF_DEST_CHANNEL
)
1773 sendcmdto_channel_butserv_butone(app_source
, CMD_MODE
, mbuf
->mb_channel
, NULL
, 0,
1774 "%H %s%s%s%s%s%s%s%s", mbuf
->mb_channel
,
1775 rembuf_i
|| rembuf_local_i
? "-" : "",
1776 rembuf
, rembuf_local
,
1777 addbuf_i
|| addbuf_local_i
? "+" : "",
1778 addbuf
, addbuf_local
,
1782 /* Now are we supposed to propagate to other servers? */
1783 if (mbuf
->mb_dest
& MODEBUF_DEST_SERVER
) {
1784 /* set up parameter string */
1791 * limit is supressed if we're removing it; we have to figure out which
1792 * direction is the direction for it to be removed, though...
1794 limitdel
|= (mbuf
->mb_dest
& MODEBUF_DEST_BOUNCE
) ? MODE_DEL
: MODE_ADD
;
1796 for (i
= 0; i
< mbuf
->mb_count
; i
++) {
1797 if (MB_TYPE(mbuf
, i
) & MODE_SAVE
)
1800 if (MB_TYPE(mbuf
, i
) & MODE_ADD
) { /* adding or removing? */
1802 strptr_i
= &addstr_i
;
1805 strptr_i
= &remstr_i
;
1808 /* if we're changing oplevels we know the oplevel, pass it on */
1809 if (mbuf
->mb_channel
->mode
.apass
[0]
1810 && (MB_TYPE(mbuf
, i
) & MODE_CHANOP
)
1811 && MB_OPLEVEL(mbuf
, i
) < MAXOPLEVEL
)
1812 *strptr_i
+= ircd_snprintf(0, strptr
+ *strptr_i
, BUFSIZE
- *strptr_i
,
1814 NumNick(MB_CLIENT(mbuf
, i
)),
1815 MB_OPLEVEL(mbuf
, i
));
1817 /* deal with other modes that take clients */
1818 else if (MB_TYPE(mbuf
, i
) & (MODE_CHANOP
| MODE_VOICE
))
1819 build_string(strptr
, strptr_i
, NumNick(MB_CLIENT(mbuf
, i
)), ' ');
1821 /* deal with modes that take strings */
1822 else if (MB_TYPE(mbuf
, i
) & (MODE_KEY
| MODE_BAN
| MODE_APASS
| MODE_UPASS
))
1823 build_string(strptr
, strptr_i
, MB_STRING(mbuf
, i
), 0, ' ');
1826 * deal with the limit. Logic here is complicated; if HACK2 is set,
1827 * we're bouncing the mode, so sense is reversed, and we have to
1828 * include the original limit if it looks like it's being removed
1830 else if ((MB_TYPE(mbuf
, i
) & limitdel
) == limitdel
)
1831 build_string(strptr
, strptr_i
, limitbuf
, 0, ' ');
1834 /* we were told to deop the source */
1835 if (mbuf
->mb_dest
& MODEBUF_DEST_DEOP
) {
1836 addbuf
[addbuf_i
++] = 'o'; /* remember, sense is reversed */
1837 addbuf
[addbuf_i
] = '\0'; /* terminate the string... */
1838 build_string(addstr
, &addstr_i
, NumNick(mbuf
->mb_source
), ' ');
1840 /* mark that we've done this, so we don't do it again */
1841 mbuf
->mb_dest
&= ~MODEBUF_DEST_DEOP
;
1844 if (mbuf
->mb_dest
& MODEBUF_DEST_OPMODE
) {
1845 /* If OPMODE was set, we're propagating the mode as an OPMODE message */
1846 sendcmdto_serv_butone(mbuf
->mb_source
, CMD_OPMODE
, mbuf
->mb_connect
,
1847 "%H %s%s%s%s%s%s", mbuf
->mb_channel
,
1848 rembuf_i
? "-" : "", rembuf
, addbuf_i
? "+" : "",
1849 addbuf
, remstr
, addstr
);
1850 } else if (mbuf
->mb_dest
& MODEBUF_DEST_BOUNCE
) {
1852 * If HACK2 was set, we're bouncing; we send the MODE back to the
1853 * connection we got it from with the senses reversed and a TS of 0;
1856 sendcmdto_one(&me
, CMD_MODE
, mbuf
->mb_connect
, "%H %s%s%s%s%s%s %Tu",
1857 mbuf
->mb_channel
, addbuf_i
? "-" : "", addbuf
,
1858 rembuf_i
? "+" : "", rembuf
, addstr
, remstr
,
1859 mbuf
->mb_channel
->creationtime
);
1862 * We're propagating a normal MODE command to the rest of the network;
1863 * we send the actual channel TS unless this is a HACK3 or a HACK4
1865 if (IsServer(mbuf
->mb_source
) || IsMe(mbuf
->mb_source
))
1866 sendcmdto_serv_butone(mbuf
->mb_source
, CMD_MODE
, mbuf
->mb_connect
,
1867 "%H %s%s%s%s%s%s %Tu", mbuf
->mb_channel
,
1868 rembuf_i
? "-" : "", rembuf
, addbuf_i
? "+" : "",
1869 addbuf
, remstr
, addstr
,
1870 (mbuf
->mb_dest
& MODEBUF_DEST_HACK4
) ? 0 :
1871 mbuf
->mb_channel
->creationtime
);
1873 sendcmdto_serv_butone(mbuf
->mb_source
, CMD_MODE
, mbuf
->mb_connect
,
1874 "%H %s%s%s%s%s%s", mbuf
->mb_channel
,
1875 rembuf_i
? "-" : "", rembuf
, addbuf_i
? "+" : "",
1876 addbuf
, remstr
, addstr
);
1880 /* We've drained the ModeBuf... */
1885 /* reinitialize the mode-with-arg slots */
1886 for (i
= 0; i
< MAXMODEPARAMS
; i
++) {
1887 /* If we saved any, pack them down */
1888 if (MB_TYPE(mbuf
, i
) & MODE_SAVE
) {
1889 mbuf
->mb_modeargs
[mbuf
->mb_count
] = mbuf
->mb_modeargs
[i
];
1890 MB_TYPE(mbuf
, mbuf
->mb_count
) &= ~MODE_SAVE
; /* don't save anymore */
1892 if (mbuf
->mb_count
++ == i
) /* don't overwrite our hard work */
1894 } else if (MB_TYPE(mbuf
, i
) & MODE_FREE
)
1895 MyFree(MB_STRING(mbuf
, i
)); /* free string if needed */
1897 MB_TYPE(mbuf
, i
) = 0;
1898 MB_UINT(mbuf
, i
) = 0;
1901 /* If we're supposed to flush it all, do so--all hail tail recursion */
1902 if (all
&& mbuf
->mb_count
)
1903 return modebuf_flush_int(mbuf
, 1);
1908 /** Initialise a modebuf
1909 * This routine just initializes a ModeBuf structure with the information
1910 * needed and the options given.
1912 * @param mbuf The mode buffer to initialise.
1913 * @param source The client that is performing the mode.
1915 * @param chan The channel that the mode is being performed upon.
1919 modebuf_init(struct ModeBuf
*mbuf
, struct Client
*source
,
1920 struct Client
*connect
, struct Channel
*chan
, unsigned int dest
)
1925 assert(0 != source
);
1929 if (IsLocalChannel(chan
->chname
)) dest
&= ~MODEBUF_DEST_SERVER
;
1933 mbuf
->mb_source
= source
;
1934 mbuf
->mb_connect
= connect
;
1935 mbuf
->mb_channel
= chan
;
1936 mbuf
->mb_dest
= dest
;
1939 /* clear each mode-with-parameter slot */
1940 for (i
= 0; i
< MAXMODEPARAMS
; i
++) {
1941 MB_TYPE(mbuf
, i
) = 0;
1942 MB_UINT(mbuf
, i
) = 0;
1946 /** Append a new mode to a modebuf
1947 * This routine simply adds modes to be added or deleted; do a binary OR
1948 * with either MODE_ADD or MODE_DEL
1950 * @param mbuf Mode buffer
1951 * @param mode MODE_ADD or MODE_DEL OR'd with MODE_PRIVATE etc.
1954 modebuf_mode(struct ModeBuf
*mbuf
, unsigned int mode
)
1957 assert(0 != (mode
& (MODE_ADD
| MODE_DEL
)));
1959 mode
&= (MODE_ADD
| MODE_DEL
| MODE_PRIVATE
| MODE_SECRET
| MODE_MODERATED
|
1960 MODE_TOPICLIMIT
| MODE_INVITEONLY
| MODE_NOPRIVMSGS
| MODE_REGONLY
|
1961 MODE_DELJOINS
| MODE_WASDELJOINS
);
1963 if (!(mode
& ~(MODE_ADD
| MODE_DEL
))) /* don't add empty modes... */
1966 if (mode
& MODE_ADD
) {
1967 mbuf
->mb_rem
&= ~mode
;
1968 mbuf
->mb_add
|= mode
;
1970 mbuf
->mb_add
&= ~mode
;
1971 mbuf
->mb_rem
|= mode
;
1975 /** Append a mode that takes an int argument to the modebuf
1977 * This routine adds a mode to be added or deleted that takes a unsigned
1978 * int parameter; mode may *only* be the relevant mode flag ORed with one
1979 * of MODE_ADD or MODE_DEL
1981 * @param mbuf The mode buffer to append to.
1982 * @param mode The mode to append.
1983 * @param uint The argument to the mode.
1986 modebuf_mode_uint(struct ModeBuf
*mbuf
, unsigned int mode
, unsigned int uint
)
1989 assert(0 != (mode
& (MODE_ADD
| MODE_DEL
)));
1991 if (mode
== (MODE_LIMIT
| ((mbuf
->mb_dest
& MODEBUF_DEST_BOUNCE
) ? MODE_ADD
: MODE_DEL
))) {
1992 mbuf
->mb_rem
|= mode
;
1995 MB_TYPE(mbuf
, mbuf
->mb_count
) = mode
;
1996 MB_UINT(mbuf
, mbuf
->mb_count
) = uint
;
1998 /* when we've reached the maximal count, flush the buffer */
1999 if (++mbuf
->mb_count
>=
2000 (MAXMODEPARAMS
- (mbuf
->mb_dest
& MODEBUF_DEST_DEOP
? 1 : 0)))
2001 modebuf_flush_int(mbuf
, 0);
2004 /** append a string mode
2005 * This routine adds a mode to be added or deleted that takes a string
2006 * parameter; mode may *only* be the relevant mode flag ORed with one of
2007 * MODE_ADD or MODE_DEL
2009 * @param mbuf The mode buffer to append to.
2010 * @param mode The mode to append.
2011 * @param string The string parameter to append.
2012 * @param free If the string should be free'd later.
2015 modebuf_mode_string(struct ModeBuf
*mbuf
, unsigned int mode
, char *string
,
2019 assert(0 != (mode
& (MODE_ADD
| MODE_DEL
)));
2021 MB_TYPE(mbuf
, mbuf
->mb_count
) = mode
| (free
? MODE_FREE
: 0);
2022 MB_STRING(mbuf
, mbuf
->mb_count
) = string
;
2024 /* when we've reached the maximal count, flush the buffer */
2025 if (++mbuf
->mb_count
>=
2026 (MAXMODEPARAMS
- (mbuf
->mb_dest
& MODEBUF_DEST_DEOP
? 1 : 0)))
2027 modebuf_flush_int(mbuf
, 0);
2030 /** Append a mode on a client to a modebuf.
2031 * This routine adds a mode to be added or deleted that takes a client
2032 * parameter; mode may *only* be the relevant mode flag ORed with one of
2033 * MODE_ADD or MODE_DEL
2035 * @param mbuf The modebuf to append the mode to.
2036 * @param mode The mode to append.
2037 * @param client The client argument to append.
2038 * @param oplevel The oplevel the user had or will have
2041 modebuf_mode_client(struct ModeBuf
*mbuf
, unsigned int mode
,
2042 struct Client
*client
, int oplevel
)
2045 assert(0 != (mode
& (MODE_ADD
| MODE_DEL
)));
2047 MB_TYPE(mbuf
, mbuf
->mb_count
) = mode
;
2048 MB_CLIENT(mbuf
, mbuf
->mb_count
) = client
;
2049 MB_OPLEVEL(mbuf
, mbuf
->mb_count
) = oplevel
;
2051 /* when we've reached the maximal count, flush the buffer */
2052 if (++mbuf
->mb_count
>=
2053 (MAXMODEPARAMS
- (mbuf
->mb_dest
& MODEBUF_DEST_DEOP
? 1 : 0)))
2054 modebuf_flush_int(mbuf
, 0);
2057 /** The exported binding for modebuf_flush()
2059 * @param mbuf The mode buffer to flush.
2061 * @see modebuf_flush_int()
2064 modebuf_flush(struct ModeBuf
*mbuf
)
2066 struct Membership
*memb
;
2068 /* Check if MODE_WASDELJOINS should be set */
2069 if (!(mbuf
->mb_channel
->mode
.mode
& (MODE_DELJOINS
| MODE_WASDELJOINS
))
2070 && (mbuf
->mb_rem
& MODE_DELJOINS
)) {
2071 for (memb
= mbuf
->mb_channel
->members
; memb
; memb
= memb
->next_member
) {
2072 if (IsDelayedJoin(memb
)) {
2073 mbuf
->mb_channel
->mode
.mode
|= MODE_WASDELJOINS
;
2074 mbuf
->mb_add
|= MODE_WASDELJOINS
;
2075 mbuf
->mb_rem
&= ~MODE_WASDELJOINS
;
2081 return modebuf_flush_int(mbuf
, 1);
2084 /* This extracts the simple modes contained in mbuf
2086 * @param mbuf The mode buffer to extract the modes from.
2087 * @param buf The string buffer to write the modes into.
2090 modebuf_extract(struct ModeBuf
*mbuf
, char *buf
)
2092 static int flags
[] = {
2093 /* MODE_CHANOP, 'o', */
2094 /* MODE_VOICE, 'v', */
2097 MODE_MODERATED
, 'm',
2098 MODE_TOPICLIMIT
, 't',
2099 MODE_INVITEONLY
, 'i',
2100 MODE_NOPRIVMSGS
, 'n',
2104 /* MODE_BAN, 'b', */
2111 int i
, bufpos
= 0, len
;
2113 char *key
= 0, limitbuf
[20];
2114 char *apass
= 0, *upass
= 0;
2123 for (i
= 0; i
< mbuf
->mb_count
; i
++) { /* find keys and limits */
2124 if (MB_TYPE(mbuf
, i
) & MODE_ADD
) {
2125 add
|= MB_TYPE(mbuf
, i
) & (MODE_KEY
| MODE_LIMIT
| MODE_APASS
| MODE_UPASS
);
2127 if (MB_TYPE(mbuf
, i
) & MODE_KEY
) /* keep strings */
2128 key
= MB_STRING(mbuf
, i
);
2129 else if (MB_TYPE(mbuf
, i
) & MODE_LIMIT
)
2130 ircd_snprintf(0, limitbuf
, sizeof(limitbuf
), "%u", MB_UINT(mbuf
, i
));
2131 else if (MB_TYPE(mbuf
, i
) & MODE_UPASS
)
2132 upass
= MB_STRING(mbuf
, i
);
2133 else if (MB_TYPE(mbuf
, i
) & MODE_APASS
)
2134 apass
= MB_STRING(mbuf
, i
);
2141 buf
[bufpos
++] = '+'; /* start building buffer */
2143 for (flag_p
= flags
; flag_p
[0]; flag_p
+= 2)
2145 buf
[bufpos
++] = flag_p
[1];
2147 for (i
= 0, len
= bufpos
; i
< len
; i
++) {
2149 build_string(buf
, &bufpos
, key
, 0, ' ');
2150 else if (buf
[i
] == 'l')
2151 build_string(buf
, &bufpos
, limitbuf
, 0, ' ');
2152 else if (buf
[i
] == 'U')
2153 build_string(buf
, &bufpos
, upass
, 0, ' ');
2154 else if (buf
[i
] == 'A')
2155 build_string(buf
, &bufpos
, apass
, 0, ' ');
2163 /** Simple function to invalidate bans
2165 * This function sets all bans as being valid.
2167 * @param chan The channel to operate on.
2170 mode_ban_invalidate(struct Channel
*chan
)
2172 struct Membership
*member
;
2174 for (member
= chan
->members
; member
; member
= member
->next_member
)
2175 ClearBanValid(member
);
2178 /** Simple function to drop invite structures
2180 * Remove all the invites on the channel.
2182 * @param chan Channel to remove invites from.
2186 mode_invite_clear(struct Channel
*chan
)
2188 while (chan
->invites
)
2189 del_invite(chan
->invites
->value
.cptr
, chan
);
2192 /* What we've done for mode_parse so far... */
2193 #define DONE_LIMIT 0x01 /**< We've set the limit */
2194 #define DONE_KEY 0x02 /**< We've set the key */
2195 #define DONE_BANLIST 0x04 /**< We've sent the ban list */
2196 #define DONE_NOTOPER 0x08 /**< We've sent a "Not oper" error */
2197 #define DONE_BANCLEAN 0x10 /**< We've cleaned bans... */
2198 #define DONE_UPASS 0x20 /**< We've set user pass */
2199 #define DONE_APASS 0x40 /**< We've set admin pass */
2202 struct ModeBuf
*mbuf
;
2203 struct Client
*cptr
;
2204 struct Client
*sptr
;
2205 struct Channel
*chptr
;
2206 struct Membership
*member
;
2217 struct Ban banlist
[MAXPARA
];
2220 unsigned short oplevel
;
2221 struct Client
*client
;
2222 } cli_change
[MAXPARA
];
2225 /** Helper function to send "Not oper" or "Not member" messages
2226 * Here's a helper function to deal with sending along "Not oper" or
2227 * "Not member" messages
2229 * @param state Parsing State object
2232 send_notoper(struct ParseState
*state
)
2234 if (state
->done
& DONE_NOTOPER
)
2237 send_reply(state
->sptr
, (state
->flags
& MODE_PARSE_NOTOPER
) ?
2238 ERR_CHANOPRIVSNEEDED
: ERR_NOTONCHANNEL
, state
->chptr
->chname
);
2240 state
->done
|= DONE_NOTOPER
;
2244 * Helper function to convert limits
2246 * @param state Parsing state object.
2250 mode_parse_limit(struct ParseState
*state
, int *flag_p
)
2252 unsigned int t_limit
;
2254 if (state
->dir
== MODE_ADD
) { /* convert arg only if adding limit */
2255 if (MyUser(state
->sptr
) && state
->max_args
<= 0) /* too many args? */
2258 if (state
->parc
<= 0) { /* warn if not enough args */
2259 if (MyUser(state
->sptr
))
2260 need_more_params(state
->sptr
, "MODE +l");
2264 t_limit
= strtoul(state
->parv
[state
->args_used
++], 0, 10); /* grab arg */
2268 if ((int)t_limit
<0) /* don't permit a negative limit */
2271 if (!(state
->flags
& MODE_PARSE_WIPEOUT
) &&
2272 (!t_limit
|| t_limit
== state
->chptr
->mode
.limit
))
2275 t_limit
= state
->chptr
->mode
.limit
;
2277 /* If they're not an oper, they can't change modes */
2278 if (state
->flags
& (MODE_PARSE_NOTOPER
| MODE_PARSE_NOTMEMBER
)) {
2279 send_notoper(state
);
2283 /* Can't remove a limit that's not there */
2284 if (state
->dir
== MODE_DEL
&& !state
->chptr
->mode
.limit
)
2287 /* Skip if this is a burst and a lower limit than this is set already */
2288 if ((state
->flags
& MODE_PARSE_BURST
) &&
2289 (state
->chptr
->mode
.mode
& flag_p
[0]) &&
2290 (state
->chptr
->mode
.limit
< t_limit
))
2293 if (state
->done
& DONE_LIMIT
) /* allow limit to be set only once */
2295 state
->done
|= DONE_LIMIT
;
2300 modebuf_mode_uint(state
->mbuf
, state
->dir
| flag_p
[0], t_limit
);
2302 if (state
->flags
& MODE_PARSE_SET
) { /* set the limit */
2303 if (state
->dir
& MODE_ADD
) {
2304 state
->chptr
->mode
.mode
|= flag_p
[0];
2305 state
->chptr
->mode
.limit
= t_limit
;
2307 state
->chptr
->mode
.mode
&= ~flag_p
[0];
2308 state
->chptr
->mode
.limit
= 0;
2313 /** Helper function to clean key-like parameters. */
2319 while (*s
> ' ' && *s
!= ':' && *s
!= ',' && t_len
--)
2325 * Helper function to convert keys
2328 mode_parse_key(struct ParseState
*state
, int *flag_p
)
2332 if (MyUser(state
->sptr
) && state
->max_args
<= 0) /* drop if too many args */
2335 if (state
->parc
<= 0) { /* warn if not enough args */
2336 if (MyUser(state
->sptr
))
2337 need_more_params(state
->sptr
, state
->dir
== MODE_ADD
? "MODE +k" :
2342 t_str
= state
->parv
[state
->args_used
++]; /* grab arg */
2346 /* If they're not an oper, they can't change modes */
2347 if (state
->flags
& (MODE_PARSE_NOTOPER
| MODE_PARSE_NOTMEMBER
)) {
2348 send_notoper(state
);
2352 if (state
->done
& DONE_KEY
) /* allow key to be set only once */
2354 state
->done
|= DONE_KEY
;
2356 /* clean up the key string */
2358 if (!*t_str
|| *t_str
== ':') { /* warn if empty */
2359 if (MyUser(state
->sptr
))
2360 need_more_params(state
->sptr
, state
->dir
== MODE_ADD
? "MODE +k" :
2368 /* Skip if this is a burst, we have a key already and the new key is
2369 * after the old one alphabetically */
2370 if ((state
->flags
& MODE_PARSE_BURST
) &&
2371 *(state
->chptr
->mode
.key
) &&
2372 ircd_strcmp(state
->chptr
->mode
.key
, t_str
) <= 0)
2375 /* can't add a key if one is set, nor can one remove the wrong key */
2376 if (!(state
->flags
& MODE_PARSE_FORCE
))
2377 if ((state
->dir
== MODE_ADD
&& *state
->chptr
->mode
.key
) ||
2378 (state
->dir
== MODE_DEL
&&
2379 ircd_strcmp(state
->chptr
->mode
.key
, t_str
))) {
2380 send_reply(state
->sptr
, ERR_KEYSET
, state
->chptr
->chname
);
2384 if (!(state
->flags
& MODE_PARSE_WIPEOUT
) && state
->dir
== MODE_ADD
&&
2385 !ircd_strcmp(state
->chptr
->mode
.key
, t_str
))
2386 return; /* no key change */
2388 if (state
->flags
& MODE_PARSE_BOUNCE
) {
2389 if (*state
->chptr
->mode
.key
) /* reset old key */
2390 modebuf_mode_string(state
->mbuf
, MODE_DEL
| flag_p
[0],
2391 state
->chptr
->mode
.key
, 0);
2392 else /* remove new bogus key */
2393 modebuf_mode_string(state
->mbuf
, MODE_ADD
| flag_p
[0], t_str
, 0);
2394 } else /* send new key */
2395 modebuf_mode_string(state
->mbuf
, state
->dir
| flag_p
[0], t_str
, 0);
2397 if (state
->flags
& MODE_PARSE_SET
) {
2398 if (state
->dir
== MODE_DEL
) /* remove the old key */
2399 *state
->chptr
->mode
.key
= '\0';
2400 else if (!state
->chptr
->mode
.key
[0]
2401 || ircd_strcmp(t_str
, state
->chptr
->mode
.key
) < 0)
2402 ircd_strncpy(state
->chptr
->mode
.key
, t_str
, KEYLEN
);
2407 * Helper function to convert user passes
2410 mode_parse_upass(struct ParseState
*state
, int *flag_p
)
2414 if (MyUser(state
->sptr
) && state
->max_args
<= 0) /* drop if too many args */
2417 if (state
->parc
<= 0) { /* warn if not enough args */
2418 if (MyUser(state
->sptr
))
2419 need_more_params(state
->sptr
, state
->dir
== MODE_ADD
? "MODE +U" :
2424 t_str
= state
->parv
[state
->args_used
++]; /* grab arg */
2428 /* If they're not an oper, they can't change modes */
2429 if (state
->flags
& (MODE_PARSE_NOTOPER
| MODE_PARSE_NOTMEMBER
)) {
2430 send_notoper(state
);
2434 /* If a non-service user is trying to force it, refuse. */
2435 if (state
->flags
& MODE_PARSE_FORCE
&& MyUser(state
->sptr
)
2436 && !HasPriv(state
->sptr
, PRIV_APASS_OPMODE
)) {
2437 send_reply(state
->sptr
, ERR_NOTMANAGER
, state
->chptr
->chname
,
2438 state
->chptr
->chname
);
2442 /* If they are not the channel manager, they are not allowed to change it */
2443 if (MyUser(state
->sptr
) && !(state
->flags
& MODE_PARSE_FORCE
|| IsChannelManager(state
->member
))) {
2444 if (*state
->chptr
->mode
.apass
) {
2445 send_reply(state
->sptr
, ERR_NOTMANAGER
, state
->chptr
->chname
,
2446 state
->chptr
->chname
);
2448 send_reply(state
->sptr
, ERR_NOMANAGER
, state
->chptr
->chname
,
2449 (TStime() - state
->chptr
->creationtime
< 172800) ?
2450 "approximately 4-5 minutes" : "approximately 48 hours");
2455 if (state
->done
& DONE_UPASS
) /* allow upass to be set only once */
2457 state
->done
|= DONE_UPASS
;
2459 /* clean up the upass string */
2461 if (!*t_str
|| *t_str
== ':') { /* warn if empty */
2462 if (MyUser(state
->sptr
))
2463 need_more_params(state
->sptr
, state
->dir
== MODE_ADD
? "MODE +U" :
2471 if (!(state
->flags
& MODE_PARSE_FORCE
)) {
2472 /* can't add the upass while apass is not set */
2473 if (state
->dir
== MODE_ADD
&& !*state
->chptr
->mode
.apass
) {
2474 send_reply(state
->sptr
, ERR_UPASSNOTSET
, state
->chptr
->chname
, state
->chptr
->chname
);
2477 /* cannot set a +U password that is the same as +A */
2478 if (state
->dir
== MODE_ADD
&& !ircd_strcmp(state
->chptr
->mode
.apass
, t_str
)) {
2479 send_reply(state
->sptr
, ERR_UPASS_SAME_APASS
, state
->chptr
->chname
);
2482 /* can't add a upass if one is set, nor can one remove the wrong upass */
2483 if ((state
->dir
== MODE_ADD
&& *state
->chptr
->mode
.upass
) ||
2484 (state
->dir
== MODE_DEL
&&
2485 ircd_strcmp(state
->chptr
->mode
.upass
, t_str
))) {
2486 send_reply(state
->sptr
, ERR_KEYSET
, state
->chptr
->chname
);
2491 if (!(state
->flags
& MODE_PARSE_WIPEOUT
) && state
->dir
== MODE_ADD
&&
2492 !ircd_strcmp(state
->chptr
->mode
.upass
, t_str
))
2493 return; /* no upass change */
2495 if (state
->flags
& MODE_PARSE_BOUNCE
) {
2496 if (*state
->chptr
->mode
.upass
) /* reset old upass */
2497 modebuf_mode_string(state
->mbuf
, MODE_DEL
| flag_p
[0],
2498 state
->chptr
->mode
.upass
, 0);
2499 else /* remove new bogus upass */
2500 modebuf_mode_string(state
->mbuf
, MODE_ADD
| flag_p
[0], t_str
, 0);
2501 } else /* send new upass */
2502 modebuf_mode_string(state
->mbuf
, state
->dir
| flag_p
[0], t_str
, 0);
2504 if (state
->flags
& MODE_PARSE_SET
) {
2505 if (state
->dir
== MODE_DEL
) /* remove the old upass */
2506 *state
->chptr
->mode
.upass
= '\0';
2507 else if (state
->chptr
->mode
.upass
[0] == '\0'
2508 || ircd_strcmp(t_str
, state
->chptr
->mode
.upass
) < 0)
2509 ircd_strncpy(state
->chptr
->mode
.upass
, t_str
, KEYLEN
);
2514 * Helper function to convert admin passes
2517 mode_parse_apass(struct ParseState
*state
, int *flag_p
)
2519 struct Membership
*memb
;
2522 if (MyUser(state
->sptr
) && state
->max_args
<= 0) /* drop if too many args */
2525 if (state
->parc
<= 0) { /* warn if not enough args */
2526 if (MyUser(state
->sptr
))
2527 need_more_params(state
->sptr
, state
->dir
== MODE_ADD
? "MODE +A" :
2532 t_str
= state
->parv
[state
->args_used
++]; /* grab arg */
2536 /* If they're not an oper, they can't change modes */
2537 if (state
->flags
& (MODE_PARSE_NOTOPER
| MODE_PARSE_NOTMEMBER
)) {
2538 send_notoper(state
);
2542 if (MyUser(state
->sptr
)) {
2543 if (state
->flags
& MODE_PARSE_FORCE
) {
2544 /* If an unprivileged oper is trying to force it, refuse. */
2545 if (!HasPriv(state
->sptr
, PRIV_APASS_OPMODE
)) {
2546 send_reply(state
->sptr
, ERR_NOTMANAGER
, state
->chptr
->chname
,
2547 state
->chptr
->chname
);
2551 /* If they are not the channel manager, they are not allowed to change it. */
2552 if (!IsChannelManager(state
->member
)) {
2553 if (*state
->chptr
->mode
.apass
) {
2554 send_reply(state
->sptr
, ERR_NOTMANAGER
, state
->chptr
->chname
,
2555 state
->chptr
->chname
);
2557 send_reply(state
->sptr
, ERR_NOMANAGER
, state
->chptr
->chname
,
2558 (TStime() - state
->chptr
->creationtime
< 172800) ?
2559 "approximately 4-5 minutes" : "approximately 48 hours");
2563 /* Can't remove the Apass while Upass is still set. */
2564 if (state
->dir
== MODE_DEL
&& *state
->chptr
->mode
.upass
) {
2565 send_reply(state
->sptr
, ERR_UPASSSET
, state
->chptr
->chname
, state
->chptr
->chname
);
2568 /* Can't add an Apass if one is set, nor can one remove the wrong Apass. */
2569 if ((state
->dir
== MODE_ADD
&& *state
->chptr
->mode
.apass
) ||
2570 (state
->dir
== MODE_DEL
&& ircd_strcmp(state
->chptr
->mode
.apass
, t_str
))) {
2571 send_reply(state
->sptr
, ERR_KEYSET
, state
->chptr
->chname
);
2576 /* Forbid removing the Apass if the channel is older than 48 hours
2577 * unless an oper is doing it. */
2578 if (TStime() - state
->chptr
->creationtime
>= 172800
2579 && state
->dir
== MODE_DEL
2580 && !IsAnOper(state
->sptr
)) {
2581 send_reply(state
->sptr
, ERR_CHANSECURED
, state
->chptr
->chname
);
2586 if (state
->done
& DONE_APASS
) /* allow apass to be set only once */
2588 state
->done
|= DONE_APASS
;
2590 /* clean up the apass string */
2592 if (!*t_str
|| *t_str
== ':') { /* warn if empty */
2593 if (MyUser(state
->sptr
))
2594 need_more_params(state
->sptr
, state
->dir
== MODE_ADD
? "MODE +A" :
2602 if (!(state
->flags
& MODE_PARSE_WIPEOUT
) && state
->dir
== MODE_ADD
&&
2603 !ircd_strcmp(state
->chptr
->mode
.apass
, t_str
))
2604 return; /* no apass change */
2606 if (state
->flags
& MODE_PARSE_BOUNCE
) {
2607 if (*state
->chptr
->mode
.apass
) /* reset old apass */
2608 modebuf_mode_string(state
->mbuf
, MODE_DEL
| flag_p
[0],
2609 state
->chptr
->mode
.apass
, 0);
2610 else /* remove new bogus apass */
2611 modebuf_mode_string(state
->mbuf
, MODE_ADD
| flag_p
[0], t_str
, 0);
2612 } else /* send new apass */
2613 modebuf_mode_string(state
->mbuf
, state
->dir
| flag_p
[0], t_str
, 0);
2615 if (state
->flags
& MODE_PARSE_SET
) {
2616 if (state
->dir
== MODE_ADD
) { /* set the new apass */
2617 /* Only accept the new apass if there is no current apass
2618 * (e.g. when a user sets it) or the new one is "less" than the
2619 * old (for resolving conflicts during burst).
2621 if (state
->chptr
->mode
.apass
[0] == '\0'
2622 || ircd_strcmp(t_str
, state
->chptr
->mode
.apass
) < 0)
2623 ircd_strncpy(state
->chptr
->mode
.apass
, t_str
, KEYLEN
);
2624 /* Make it VERY clear to the user that this is a one-time password */
2625 if (MyUser(state
->sptr
)) {
2626 send_reply(state
->sptr
, RPL_APASSWARN_SET
, state
->chptr
->mode
.apass
);
2627 send_reply(state
->sptr
, RPL_APASSWARN_SECRET
, state
->chptr
->chname
,
2628 state
->chptr
->mode
.apass
);
2630 /* Give the channel manager level 0 ops.
2631 There should not be tested for IsChannelManager here because
2632 on the local server it is impossible to set the apass if one
2633 isn't a channel manager and remote servers might need to sync
2634 the oplevel here: when someone creates a channel (and becomes
2635 channel manager) during a net.break, and only sets the Apass
2636 after the net rejoined, they will have oplevel MAXOPLEVEL on
2637 all remote servers. */
2639 SetOpLevel(state
->member
, 0);
2640 } else { /* remove the old apass */
2641 *state
->chptr
->mode
.apass
= '\0';
2642 /* Clear Upass so that there is never a Upass set when a zannel is burst. */
2643 *state
->chptr
->mode
.upass
= '\0';
2644 if (MyUser(state
->sptr
))
2645 send_reply(state
->sptr
, RPL_APASSWARN_CLEAR
);
2646 /* Revert everyone to MAXOPLEVEL. */
2647 for (memb
= state
->chptr
->members
; memb
; memb
= memb
->next_member
) {
2648 if (memb
->status
& MODE_CHANOP
)
2649 SetOpLevel(memb
, MAXOPLEVEL
);
2655 /** Compare one ban's extent to another.
2656 * This works very similarly to mmatch() but it knows about CIDR masks
2657 * and ban exceptions. If both bans are CIDR-based, compare their
2658 * address bits; otherwise, use mmatch().
2659 * @param[in] old_ban One ban.
2660 * @param[in] new_ban Another ban.
2661 * @return Zero if \a old_ban is a superset of \a new_ban, non-zero otherwise.
2664 bmatch(struct Ban
*old_ban
, struct Ban
*new_ban
)
2667 assert(old_ban
!= NULL
);
2668 assert(new_ban
!= NULL
);
2669 /* A ban is never treated as a superset of an exception. */
2670 if (!(old_ban
->flags
& BAN_EXCEPTION
)
2671 && (new_ban
->flags
& BAN_EXCEPTION
))
2673 /* If either is not an address mask, match the text masks. */
2674 if ((old_ban
->flags
& new_ban
->flags
& BAN_IPMASK
) == 0)
2675 return mmatch(old_ban
->banstr
, new_ban
->banstr
);
2676 /* If the old ban has a longer prefix than new, it cannot be a superset. */
2677 if (old_ban
->addrbits
> new_ban
->addrbits
)
2679 /* Compare the masks before the hostname part. */
2680 old_ban
->banstr
[old_ban
->nu_len
] = new_ban
->banstr
[new_ban
->nu_len
] = '\0';
2681 res
= mmatch(old_ban
->banstr
, new_ban
->banstr
);
2682 old_ban
->banstr
[old_ban
->nu_len
] = new_ban
->banstr
[new_ban
->nu_len
] = '@';
2685 /* Compare the addresses. */
2686 return !ipmask_check(&new_ban
->address
, &old_ban
->address
, old_ban
->addrbits
);
2689 /** Add a ban from a ban list and mark bans that should be removed
2690 * because they overlap.
2692 * There are three invariants for a ban list. First, no ban may be
2693 * more specific than another ban. Second, no exception may be more
2694 * specific than another exception. Finally, no ban may be more
2695 * specific than any exception.
2697 * @param[in,out] banlist Pointer to head of list.
2698 * @param[in] newban Ban (or exception) to add (or remove).
2699 * @param[in] do_free If non-zero, free \a newban on failure.
2700 * @return Zero if \a newban could be applied, non-zero if not.
2702 int apply_ban(struct Ban
**banlist
, struct Ban
*newban
, int do_free
)
2707 assert(newban
->flags
& (BAN_ADD
|BAN_DEL
));
2708 if (newban
->flags
& BAN_ADD
) {
2710 /* If a less specific entry is found, fail. */
2711 for (ban
= *banlist
; ban
; ban
= ban
->next
) {
2712 if (!bmatch(ban
, newban
)) {
2717 if (!(ban
->flags
& (BAN_OVERLAPPED
|BAN_DEL
))) {
2719 totlen
+= strlen(ban
->banstr
);
2722 /* Mark more specific entries and add this one to the end of the list. */
2723 while ((ban
= *banlist
) != NULL
) {
2724 if (!bmatch(newban
, ban
)) {
2725 ban
->flags
|= BAN_OVERLAPPED
| BAN_DEL
;
2727 banlist
= &ban
->next
;
2731 } else if (newban
->flags
& BAN_DEL
) {
2732 size_t remove_count
= 0;
2733 /* Mark more specific entries. */
2734 for (ban
= *banlist
; ban
; ban
= ban
->next
) {
2735 if (!bmatch(newban
, ban
)) {
2736 ban
->flags
|= BAN_OVERLAPPED
| BAN_DEL
;
2742 /* If no matches were found, fail. */
2753 * Helper function to convert bans
2756 mode_parse_ban(struct ParseState
*state
, int *flag_p
)
2759 struct Ban
*ban
, *newban
;
2761 if (state
->parc
<= 0) { /* Not enough args, send ban list */
2762 if (MyUser(state
->sptr
) && !(state
->done
& DONE_BANLIST
)) {
2763 send_ban_list(state
->sptr
, state
->chptr
);
2764 state
->done
|= DONE_BANLIST
;
2770 if (MyUser(state
->sptr
) && state
->max_args
<= 0) /* drop if too many args */
2773 t_str
= state
->parv
[state
->args_used
++]; /* grab arg */
2777 /* If they're not an oper, they can't change modes */
2778 if (state
->flags
& (MODE_PARSE_NOTOPER
| MODE_PARSE_NOTMEMBER
)) {
2779 send_notoper(state
);
2783 if ((s
= strchr(t_str
, ' ')))
2786 if (!*t_str
|| *t_str
== ':') { /* warn if empty */
2787 if (MyUser(state
->sptr
))
2788 need_more_params(state
->sptr
, state
->dir
== MODE_ADD
? "MODE +b" :
2793 /* Clear all ADD/DEL/OVERLAPPED flags from ban list. */
2794 if (!(state
->done
& DONE_BANCLEAN
)) {
2795 for (ban
= state
->chptr
->banlist
; ban
; ban
= ban
->next
)
2796 ban
->flags
&= ~(BAN_ADD
| BAN_DEL
| BAN_OVERLAPPED
);
2797 state
->done
|= DONE_BANCLEAN
;
2800 /* remember the ban for the moment... */
2801 newban
= state
->banlist
+ (state
->numbans
++);
2803 newban
->flags
= ((state
->dir
== MODE_ADD
) ? BAN_ADD
: BAN_DEL
)
2804 | (*flag_p
== MODE_BAN
? 0 : BAN_EXCEPTION
);
2805 set_ban_mask(newban
, collapse(pretty_mask(t_str
)));
2806 ircd_strncpy(newban
->who
, IsUser(state
->sptr
) ? cli_name(state
->sptr
) : "*", NICKLEN
);
2807 newban
->when
= TStime();
2808 apply_ban(&state
->chptr
->banlist
, newban
, 0);
2812 * This is the bottom half of the ban processor
2815 mode_process_bans(struct ParseState
*state
)
2817 struct Ban
*ban
, *newban
, *prevban
, *nextban
;
2823 for (prevban
= 0, ban
= state
->chptr
->banlist
; ban
; ban
= nextban
) {
2825 banlen
= strlen(ban
->banstr
);
2827 nextban
= ban
->next
;
2829 if ((ban
->flags
& (BAN_DEL
| BAN_ADD
)) == (BAN_DEL
| BAN_ADD
)) {
2831 prevban
->next
= 0; /* Break the list; ban isn't a real ban */
2833 state
->chptr
->banlist
= 0;
2839 } else if (ban
->flags
& BAN_DEL
) { /* Deleted a ban? */
2841 DupString(bandup
, ban
->banstr
);
2842 modebuf_mode_string(state
->mbuf
, MODE_DEL
| MODE_BAN
,
2845 if (state
->flags
& MODE_PARSE_SET
) { /* Ok, make it take effect */
2846 if (prevban
) /* clip it out of the list... */
2847 prevban
->next
= ban
->next
;
2849 state
->chptr
->banlist
= ban
->next
;
2856 continue; /* next ban; keep prevban like it is */
2858 ban
->flags
&= BAN_IPMASK
; /* unset other flags */
2859 } else if (ban
->flags
& BAN_ADD
) { /* adding a ban? */
2861 prevban
->next
= 0; /* Break the list; ban isn't a real ban */
2863 state
->chptr
->banlist
= 0;
2865 /* If we're supposed to ignore it, do so. */
2866 if (ban
->flags
& BAN_OVERLAPPED
&&
2867 !(state
->flags
& MODE_PARSE_BOUNCE
)) {
2871 if (state
->flags
& MODE_PARSE_SET
&& MyUser(state
->sptr
) &&
2872 (len
> (feature_int(FEAT_AVBANLEN
) * feature_int(FEAT_MAXBANS
)) ||
2873 count
> feature_int(FEAT_MAXBANS
))) {
2874 send_reply(state
->sptr
, ERR_BANLISTFULL
, state
->chptr
->chname
,
2880 /* add the ban to the buffer */
2881 DupString(bandup
, ban
->banstr
);
2882 modebuf_mode_string(state
->mbuf
, MODE_ADD
| MODE_BAN
,
2885 if (state
->flags
& MODE_PARSE_SET
) { /* create a new ban */
2886 newban
= make_ban(ban
->banstr
);
2887 strcpy(newban
->who
, ban
->who
);
2888 newban
->when
= ban
->when
;
2889 newban
->flags
= ban
->flags
& BAN_IPMASK
;
2891 newban
->next
= state
->chptr
->banlist
; /* and link it in */
2892 state
->chptr
->banlist
= newban
;
2901 } /* for (prevban = 0, ban = state->chptr->banlist; ban; ban = nextban) { */
2903 if (changed
) /* if we changed the ban list, we must invalidate the bans */
2904 mode_ban_invalidate(state
->chptr
);
2908 * Helper function to process client changes
2911 mode_parse_client(struct ParseState
*state
, int *flag_p
)
2915 struct Client
*acptr
;
2916 struct Membership
*member
;
2917 int oplevel
= MAXOPLEVEL
+ 1;
2921 if (MyUser(state
->sptr
) && state
->max_args
<= 0) /* drop if too many args */
2924 if (state
->parc
<= 0) /* return if not enough args */
2927 t_str
= state
->parv
[state
->args_used
++]; /* grab arg */
2931 /* If they're not an oper, they can't change modes */
2932 if (state
->flags
& (MODE_PARSE_NOTOPER
| MODE_PARSE_NOTMEMBER
)) {
2933 send_notoper(state
);
2937 if (MyUser(state
->sptr
)) {
2938 colon
= strchr(t_str
, ':');
2939 if (colon
!= NULL
) {
2941 req_oplevel
= atoi(colon
);
2942 if (!(state
->flags
& MODE_PARSE_FORCE
)
2944 && (req_oplevel
< OpLevel(state
->member
)
2945 || (req_oplevel
== OpLevel(state
->member
)
2946 && OpLevel(state
->member
) < MAXOPLEVEL
)
2947 || req_oplevel
> MAXOPLEVEL
))
2948 send_reply(state
->sptr
, ERR_NOTLOWEROPLEVEL
,
2949 t_str
, state
->chptr
->chname
,
2950 OpLevel(state
->member
), req_oplevel
, "op",
2951 OpLevel(state
->member
) == req_oplevel
? "the same" : "a higher");
2952 else if (req_oplevel
<= MAXOPLEVEL
)
2953 oplevel
= req_oplevel
;
2955 /* find client we're manipulating */
2956 acptr
= find_chasing(state
->sptr
, t_str
, NULL
);
2958 if (t_str
[5] == ':') {
2960 oplevel
= atoi(t_str
+ 6);
2962 acptr
= findNUser(t_str
);
2966 return; /* find_chasing() already reported an error to the user */
2968 for (i
= 0; i
< MAXPARA
; i
++) /* find an element to stick them in */
2969 if (!state
->cli_change
[i
].flag
|| (state
->cli_change
[i
].client
== acptr
&&
2970 state
->cli_change
[i
].flag
& flag_p
[0]))
2971 break; /* found a slot */
2973 /* If we are going to bounce this deop, mark the correct oplevel. */
2974 if (state
->flags
& MODE_PARSE_BOUNCE
2975 && state
->dir
== MODE_DEL
2976 && flag_p
[0] == MODE_CHANOP
2977 && (member
= find_member_link(state
->chptr
, acptr
)))
2978 oplevel
= OpLevel(member
);
2980 /* Store what we're doing to them */
2981 state
->cli_change
[i
].flag
= state
->dir
| flag_p
[0];
2982 state
->cli_change
[i
].oplevel
= oplevel
;
2983 state
->cli_change
[i
].client
= acptr
;
2987 * Helper function to process the changed client list
2990 mode_process_clients(struct ParseState
*state
)
2993 struct Membership
*member
;
2995 for (i
= 0; state
->cli_change
[i
].flag
; i
++) {
2996 assert(0 != state
->cli_change
[i
].client
);
2998 /* look up member link */
2999 if (!(member
= find_member_link(state
->chptr
,
3000 state
->cli_change
[i
].client
)) ||
3001 (MyUser(state
->sptr
) && IsZombie(member
))) {
3002 if (MyUser(state
->sptr
))
3003 send_reply(state
->sptr
, ERR_USERNOTINCHANNEL
,
3004 cli_name(state
->cli_change
[i
].client
),
3005 state
->chptr
->chname
);
3009 if ((state
->cli_change
[i
].flag
& MODE_ADD
&&
3010 (state
->cli_change
[i
].flag
& member
->status
)) ||
3011 (state
->cli_change
[i
].flag
& MODE_DEL
&&
3012 !(state
->cli_change
[i
].flag
& member
->status
)))
3013 continue; /* no change made, don't do anything */
3015 /* see if the deop is allowed */
3016 if ((state
->cli_change
[i
].flag
& (MODE_DEL
| MODE_CHANOP
)) ==
3017 (MODE_DEL
| MODE_CHANOP
)) {
3018 /* prevent +k users from being deopped */
3019 if (IsChannelService(state
->cli_change
[i
].client
)) {
3020 if (state
->flags
& MODE_PARSE_FORCE
) /* it was forced */
3021 sendto_opmask_butone(0, SNO_HACK4
, "Deop of +k user on %H by %s",
3023 (IsServer(state
->sptr
) ? cli_name(state
->sptr
) :
3024 cli_name((cli_user(state
->sptr
))->server
)));
3026 else if (MyUser(state
->sptr
) && state
->flags
& MODE_PARSE_SET
) {
3027 send_reply(state
->sptr
, ERR_ISCHANSERVICE
,
3028 cli_name(state
->cli_change
[i
].client
),
3029 state
->chptr
->chname
);
3034 /* check deop for local user */
3035 if (MyUser(state
->sptr
)) {
3037 /* don't allow local opers to be deopped on local channels */
3038 if (state
->cli_change
[i
].client
!= state
->sptr
&&
3039 IsLocalChannel(state
->chptr
->chname
) &&
3040 HasPriv(state
->cli_change
[i
].client
, PRIV_DEOP_LCHAN
)) {
3041 send_reply(state
->sptr
, ERR_ISOPERLCHAN
,
3042 cli_name(state
->cli_change
[i
].client
),
3043 state
->chptr
->chname
);
3047 /* Forbid deopping other members with an oplevel less than
3048 * one's own level, and other members with an oplevel the same
3049 * as one's own unless both are at MAXOPLEVEL. */
3050 if (state
->sptr
!= state
->cli_change
[i
].client
3052 && ((OpLevel(member
) < OpLevel(state
->member
))
3053 || (OpLevel(member
) == OpLevel(state
->member
)
3054 && OpLevel(member
) < MAXOPLEVEL
))) {
3055 int equal
= (OpLevel(member
) == OpLevel(state
->member
));
3056 send_reply(state
->sptr
, ERR_NOTLOWEROPLEVEL
,
3057 cli_name(state
->cli_change
[i
].client
),
3058 state
->chptr
->chname
,
3059 OpLevel(state
->member
), OpLevel(member
),
3060 "deop", equal
? "the same" : "a higher");
3066 /* set op-level of member being opped */
3067 if ((state
->cli_change
[i
].flag
& (MODE_ADD
| MODE_CHANOP
)) ==
3068 (MODE_ADD
| MODE_CHANOP
)) {
3069 /* If a valid oplevel was specified, use it.
3070 * Otherwise, if being opped by an outsider, get MAXOPLEVEL.
3071 * Otherwise, if not an apass channel, or state->member has
3072 * MAXOPLEVEL, get oplevel MAXOPLEVEL.
3073 * Otherwise, get state->member's oplevel+1.
3075 if (state
->cli_change
[i
].oplevel
<= MAXOPLEVEL
)
3076 SetOpLevel(member
, state
->cli_change
[i
].oplevel
);
3077 else if (!state
->member
)
3078 SetOpLevel(member
, MAXOPLEVEL
);
3079 else if (!state
->chptr
->mode
.apass
[0] || OpLevel(state
->member
) == MAXOPLEVEL
)
3080 SetOpLevel(member
, MAXOPLEVEL
);
3082 SetOpLevel(member
, OpLevel(state
->member
) + 1);
3085 /* actually effect the change */
3086 if (state
->flags
& MODE_PARSE_SET
) {
3087 if (state
->cli_change
[i
].flag
& MODE_ADD
) {
3088 if (IsDelayedJoin(member
) && !IsZombie(member
))
3089 RevealDelayedJoin(member
);
3090 member
->status
|= (state
->cli_change
[i
].flag
&
3091 (MODE_CHANOP
| MODE_VOICE
));
3092 if (state
->cli_change
[i
].flag
& MODE_CHANOP
)
3093 ClearDeopped(member
);
3095 member
->status
&= ~(state
->cli_change
[i
].flag
&
3096 (MODE_CHANOP
| MODE_VOICE
));
3099 /* accumulate the change */
3100 modebuf_mode_client(state
->mbuf
, state
->cli_change
[i
].flag
,
3101 state
->cli_change
[i
].client
,
3102 state
->cli_change
[i
].oplevel
);
3103 } /* for (i = 0; state->cli_change[i].flags; i++) */
3107 * Helper function to process the simple modes
3110 mode_parse_mode(struct ParseState
*state
, int *flag_p
)
3112 /* If they're not an oper, they can't change modes */
3113 if (state
->flags
& (MODE_PARSE_NOTOPER
| MODE_PARSE_NOTMEMBER
)) {
3114 send_notoper(state
);
3121 if (state
->dir
== MODE_ADD
) {
3122 state
->add
|= flag_p
[0];
3123 state
->del
&= ~flag_p
[0];
3125 if (flag_p
[0] & MODE_SECRET
) {
3126 state
->add
&= ~MODE_PRIVATE
;
3127 state
->del
|= MODE_PRIVATE
;
3128 } else if (flag_p
[0] & MODE_PRIVATE
) {
3129 state
->add
&= ~MODE_SECRET
;
3130 state
->del
|= MODE_SECRET
;
3132 if (flag_p
[0] & MODE_DELJOINS
) {
3133 state
->add
&= ~MODE_WASDELJOINS
;
3134 state
->del
|= MODE_WASDELJOINS
;
3137 state
->add
&= ~flag_p
[0];
3138 state
->del
|= flag_p
[0];
3141 assert(0 == (state
->add
& state
->del
));
3142 assert((MODE_SECRET
| MODE_PRIVATE
) !=
3143 (state
->add
& (MODE_SECRET
| MODE_PRIVATE
)));
3147 * This routine is intended to parse MODE or OPMODE commands and effect the
3148 * changes (or just build the bounce buffer). We pass the starting offset
3152 mode_parse(struct ModeBuf
*mbuf
, struct Client
*cptr
, struct Client
*sptr
,
3153 struct Channel
*chptr
, int parc
, char *parv
[], unsigned int flags
,
3154 struct Membership
* member
)
3156 static int chan_flags
[] = {
3161 MODE_MODERATED
, 'm',
3162 MODE_TOPICLIMIT
, 't',
3163 MODE_INVITEONLY
, 'i',
3164 MODE_NOPRIVMSGS
, 'n',
3178 unsigned int t_mode
;
3180 struct ParseState state
;
3191 state
.chptr
= chptr
;
3192 state
.member
= member
;
3195 state
.flags
= flags
;
3196 state
.dir
= MODE_ADD
;
3200 state
.args_used
= 0;
3201 state
.max_args
= MAXMODEPARAMS
;
3204 for (i
= 0; i
< MAXPARA
; i
++) { /* initialize ops/voices arrays */
3205 state
.banlist
[i
].next
= 0;
3206 state
.banlist
[i
].who
[0] = '\0';
3207 state
.banlist
[i
].when
= 0;
3208 state
.banlist
[i
].flags
= 0;
3209 state
.cli_change
[i
].flag
= 0;
3210 state
.cli_change
[i
].client
= 0;
3213 modestr
= state
.parv
[state
.args_used
++];
3217 for (; *modestr
; modestr
++) {
3218 for (flag_p
= chan_flags
; flag_p
[0]; flag_p
+= 2) /* look up flag */
3219 if (flag_p
[1] == *modestr
)
3222 if (!flag_p
[0]) { /* didn't find it? complain and continue */
3223 if (MyUser(state
.sptr
))
3224 send_reply(state
.sptr
, ERR_UNKNOWNMODE
, *modestr
);
3229 case '+': /* switch direction to MODE_ADD */
3230 case '-': /* switch direction to MODE_DEL */
3231 state
.dir
= flag_p
[0];
3234 case 'l': /* deal with limits */
3235 mode_parse_limit(&state
, flag_p
);
3238 case 'k': /* deal with keys */
3239 mode_parse_key(&state
, flag_p
);
3242 case 'A': /* deal with Admin passes */
3243 if (IsServer(cptr
) || feature_bool(FEAT_OPLEVELS
))
3244 mode_parse_apass(&state
, flag_p
);
3247 case 'U': /* deal with user passes */
3248 if (IsServer(cptr
) || feature_bool(FEAT_OPLEVELS
))
3249 mode_parse_upass(&state
, flag_p
);
3252 case 'b': /* deal with bans */
3253 mode_parse_ban(&state
, flag_p
);
3256 case 'o': /* deal with ops/voice */
3258 mode_parse_client(&state
, flag_p
);
3261 default: /* deal with other modes */
3262 mode_parse_mode(&state
, flag_p
);
3264 } /* switch (*modestr) */
3265 } /* for (; *modestr; modestr++) */
3267 if (state
.flags
& MODE_PARSE_BURST
)
3268 break; /* don't interpret any more arguments */
3270 if (state
.parc
> 0) { /* process next argument in string */
3271 modestr
= state
.parv
[state
.args_used
++];
3275 if (IsServer(state
.sptr
) && !state
.parc
&& IsDigit(*modestr
)) {
3278 if (!(state
.flags
& MODE_PARSE_SET
)) /* don't set earlier TS if */
3279 break; /* we're then going to bounce the mode! */
3281 recv_ts
= atoi(modestr
);
3283 if (recv_ts
&& recv_ts
< state
.chptr
->creationtime
)
3284 state
.chptr
->creationtime
= recv_ts
; /* respect earlier TS */
3286 break; /* break out of while loop */
3287 } else if (state
.flags
& MODE_PARSE_STRICT
||
3288 (MyUser(state
.sptr
) && state
.max_args
<= 0)) {
3289 state
.parc
++; /* we didn't actually gobble the argument */
3291 break; /* break out of while loop */
3294 } /* while (*modestr) */
3297 * the rest of the function finishes building resultant MODEs; if the
3298 * origin isn't a member or an oper, skip it.
3300 if (!state
.mbuf
|| state
.flags
& (MODE_PARSE_NOTOPER
| MODE_PARSE_NOTMEMBER
))
3301 return state
.args_used
; /* tell our parent how many args we gobbled */
3303 t_mode
= state
.chptr
->mode
.mode
;
3305 if (state
.del
& t_mode
) { /* delete any modes to be deleted... */
3306 modebuf_mode(state
.mbuf
, MODE_DEL
| (state
.del
& t_mode
));
3308 t_mode
&= ~state
.del
;
3310 if (state
.add
& ~t_mode
) { /* add any modes to be added... */
3311 modebuf_mode(state
.mbuf
, MODE_ADD
| (state
.add
& ~t_mode
));
3313 t_mode
|= state
.add
;
3316 if (state
.flags
& MODE_PARSE_SET
) { /* set the channel modes */
3317 if ((state
.chptr
->mode
.mode
& MODE_INVITEONLY
) &&
3318 !(t_mode
& MODE_INVITEONLY
))
3319 mode_invite_clear(state
.chptr
);
3321 state
.chptr
->mode
.mode
= t_mode
;
3324 if (state
.flags
& MODE_PARSE_WIPEOUT
) {
3325 if (state
.chptr
->mode
.limit
&& !(state
.done
& DONE_LIMIT
))
3326 modebuf_mode_uint(state
.mbuf
, MODE_DEL
| MODE_LIMIT
,
3327 state
.chptr
->mode
.limit
);
3328 if (*state
.chptr
->mode
.key
&& !(state
.done
& DONE_KEY
))
3329 modebuf_mode_string(state
.mbuf
, MODE_DEL
| MODE_KEY
,
3330 state
.chptr
->mode
.key
, 0);
3331 if (*state
.chptr
->mode
.upass
&& !(state
.done
& DONE_UPASS
))
3332 modebuf_mode_string(state
.mbuf
, MODE_DEL
| MODE_UPASS
,
3333 state
.chptr
->mode
.upass
, 0);
3334 if (*state
.chptr
->mode
.apass
&& !(state
.done
& DONE_APASS
))
3335 modebuf_mode_string(state
.mbuf
, MODE_DEL
| MODE_APASS
,
3336 state
.chptr
->mode
.apass
, 0);
3339 if (state
.done
& DONE_BANCLEAN
) /* process bans */
3340 mode_process_bans(&state
);
3342 /* process client changes */
3343 if (state
.cli_change
[0].flag
)
3344 mode_process_clients(&state
);
3346 return state
.args_used
; /* tell our parent how many args we gobbled */
3350 * Initialize a join buffer
3353 joinbuf_init(struct JoinBuf
*jbuf
, struct Client
*source
,
3354 struct Client
*connect
, unsigned int type
, char *comment
,
3360 assert(0 != source
);
3361 assert(0 != connect
);
3363 jbuf
->jb_source
= source
; /* just initialize struct JoinBuf */
3364 jbuf
->jb_connect
= connect
;
3365 jbuf
->jb_type
= type
;
3366 jbuf
->jb_comment
= comment
;
3367 jbuf
->jb_create
= create
;
3369 jbuf
->jb_strlen
= (((type
== JOINBUF_TYPE_JOIN
||
3370 type
== JOINBUF_TYPE_PART
||
3371 type
== JOINBUF_TYPE_PARTALL
) ?
3372 STARTJOINLEN
: STARTCREATELEN
) +
3373 (comment
? strlen(comment
) + 2 : 0));
3375 for (i
= 0; i
< MAXJOINARGS
; i
++)
3376 jbuf
->jb_channels
[i
] = 0;
3380 * Add a channel to the join buffer
3383 joinbuf_join(struct JoinBuf
*jbuf
, struct Channel
*chan
, unsigned int flags
)
3391 sendcmdto_serv_butone(jbuf
->jb_source
, CMD_JOIN
, jbuf
->jb_connect
, "0");
3395 is_local
= IsLocalChannel(chan
->chname
);
3397 if (jbuf
->jb_type
== JOINBUF_TYPE_PART
||
3398 jbuf
->jb_type
== JOINBUF_TYPE_PARTALL
) {
3399 struct Membership
*member
= find_member_link(chan
, jbuf
->jb_source
);
3400 if (IsUserParting(member
))
3402 SetUserParting(member
);
3404 /* Send notification to channel */
3405 if (!(flags
& (CHFL_ZOMBIE
| CHFL_DELAYED
)))
3406 sendcmdto_channel_butserv_butone(jbuf
->jb_source
, CMD_PART
, chan
, NULL
, 0,
3407 (flags
& CHFL_BANNED
|| !jbuf
->jb_comment
) ?
3408 ":%H" : "%H :%s", chan
, jbuf
->jb_comment
);
3409 else if (MyUser(jbuf
->jb_source
))
3410 sendcmdto_one(jbuf
->jb_source
, CMD_PART
, jbuf
->jb_source
,
3411 (flags
& CHFL_BANNED
|| !jbuf
->jb_comment
) ?
3412 ":%H" : "%H :%s", chan
, jbuf
->jb_comment
);
3413 /* XXX: Shouldn't we send a PART here anyway? */
3414 /* to users on the channel? Why? From their POV, the user isn't on
3415 * the channel anymore anyway. We don't send to servers until below,
3416 * when we gang all the channel parts together. Note that this is
3417 * exactly the same logic, albeit somewhat more concise, as was in
3418 * the original m_part.c */
3420 if (jbuf
->jb_type
== JOINBUF_TYPE_PARTALL
||
3421 is_local
) /* got to remove user here */
3422 remove_user_from_channel(jbuf
->jb_source
, chan
);
3424 int oplevel
= !chan
->mode
.apass
[0] ? MAXOPLEVEL
3425 : (flags
& CHFL_CHANNEL_MANAGER
) ? 0
3427 /* Add user to channel */
3428 if ((chan
->mode
.mode
& MODE_DELJOINS
) && !(flags
& CHFL_VOICED_OR_OPPED
))
3429 add_user_to_channel(chan
, jbuf
->jb_source
, flags
| CHFL_DELAYED
, oplevel
);
3431 add_user_to_channel(chan
, jbuf
->jb_source
, flags
, oplevel
);
3433 /* send JOIN notification to all servers (CREATE is sent later). */
3434 if (jbuf
->jb_type
!= JOINBUF_TYPE_CREATE
&& !is_local
)
3435 sendcmdto_serv_butone(jbuf
->jb_source
, CMD_JOIN
, jbuf
->jb_connect
,
3436 "%H %Tu", chan
, chan
->creationtime
);
3438 if (!((chan
->mode
.mode
& MODE_DELJOINS
) && !(flags
& CHFL_VOICED_OR_OPPED
))) {
3439 /* Send the notification to the channel */
3440 sendcmdto_channel_butserv_butone(jbuf
->jb_source
, CMD_JOIN
, chan
, NULL
, 0, "%H", chan
);
3442 /* send an op, too, if needed */
3443 if (flags
& CHFL_CHANOP
&& (oplevel
< MAXOPLEVEL
|| !MyUser(jbuf
->jb_source
)))
3444 sendcmdto_channel_butserv_butone((chan
->mode
.apass
[0] ? &his
: jbuf
->jb_source
),
3445 CMD_MODE
, chan
, NULL
, 0, "%H +o %C",
3446 chan
, jbuf
->jb_source
);
3447 } else if (MyUser(jbuf
->jb_source
))
3448 sendcmdto_one(jbuf
->jb_source
, CMD_JOIN
, jbuf
->jb_source
, ":%H", chan
);
3451 if (jbuf
->jb_type
== JOINBUF_TYPE_PARTALL
||
3452 jbuf
->jb_type
== JOINBUF_TYPE_JOIN
|| is_local
)
3453 return; /* don't send to remote */
3455 /* figure out if channel name will cause buffer to be overflowed */
3456 len
= chan
? strlen(chan
->chname
) + 1 : 2;
3457 if (jbuf
->jb_strlen
+ len
> BUFSIZE
)
3458 joinbuf_flush(jbuf
);
3460 /* add channel to list of channels to send and update counts */
3461 jbuf
->jb_channels
[jbuf
->jb_count
++] = chan
;
3462 jbuf
->jb_strlen
+= len
;
3464 /* if we've used up all slots, flush */
3465 if (jbuf
->jb_count
>= MAXJOINARGS
)
3466 joinbuf_flush(jbuf
);
3470 * Flush the channel list to remote servers
3473 joinbuf_flush(struct JoinBuf
*jbuf
)
3475 char chanlist
[BUFSIZE
];
3479 if (!jbuf
->jb_count
|| jbuf
->jb_type
== JOINBUF_TYPE_PARTALL
||
3480 jbuf
->jb_type
== JOINBUF_TYPE_JOIN
)
3481 return 0; /* no joins to process */
3483 for (i
= 0; i
< jbuf
->jb_count
; i
++) { /* build channel list */
3484 build_string(chanlist
, &chanlist_i
,
3485 jbuf
->jb_channels
[i
] ? jbuf
->jb_channels
[i
]->chname
: "0", 0,
3486 i
== 0 ? '\0' : ',');
3487 if (JOINBUF_TYPE_PART
== jbuf
->jb_type
)
3488 /* Remove user from channel */
3489 remove_user_from_channel(jbuf
->jb_source
, jbuf
->jb_channels
[i
]);
3491 jbuf
->jb_channels
[i
] = 0; /* mark slot empty */
3494 jbuf
->jb_count
= 0; /* reset base counters */
3495 jbuf
->jb_strlen
= ((jbuf
->jb_type
== JOINBUF_TYPE_PART
?
3496 STARTJOINLEN
: STARTCREATELEN
) +
3497 (jbuf
->jb_comment
? strlen(jbuf
->jb_comment
) + 2 : 0));
3499 /* and send the appropriate command */
3500 switch (jbuf
->jb_type
) {
3501 case JOINBUF_TYPE_CREATE
:
3502 sendcmdto_serv_butone(jbuf
->jb_source
, CMD_CREATE
, jbuf
->jb_connect
,
3503 "%s %Tu", chanlist
, jbuf
->jb_create
);
3506 case JOINBUF_TYPE_PART
:
3507 sendcmdto_serv_butone(jbuf
->jb_source
, CMD_PART
, jbuf
->jb_connect
,
3508 jbuf
->jb_comment
? "%s :%s" : "%s", chanlist
,
3516 /* Returns TRUE (1) if client is invited, FALSE (0) if not */
3517 int IsInvited(struct Client
* cptr
, const void* chptr
)
3521 for (lp
= (cli_user(cptr
))->invited
; lp
; lp
= lp
->next
)
3522 if (lp
->value
.chptr
== chptr
)
3527 /* RevealDelayedJoin: sends a join for a hidden user */
3529 void RevealDelayedJoin(struct Membership
*member
)
3531 ClearDelayedJoin(member
);
3532 sendcmdto_channel_butserv_butone(member
->user
, CMD_JOIN
, member
->channel
, member
->user
, 0, ":%H",
3534 CheckDelayedJoins(member
->channel
);
3537 /* CheckDelayedJoins: checks and clear +d if necessary */
3539 void CheckDelayedJoins(struct Channel
*chan
)
3541 struct Membership
*memb2
;
3543 if (chan
->mode
.mode
& MODE_WASDELJOINS
) {
3544 for (memb2
=chan
->members
;memb2
;memb2
=memb2
->next_member
)
3545 if (IsDelayedJoin(memb2
))
3550 chan
->mode
.mode
&= ~MODE_WASDELJOINS
;
3551 sendcmdto_channel_butserv_butone(&his
, CMD_MODE
, chan
, NULL
, 0,