#include "ircd.h"
#include "ircd_alloc.h"
#include "ircd_chattr.h"
+#include "ircd_log.h"
#include "ircd_reply.h"
#include "ircd_snprintf.h"
#include "ircd_string.h"
struct Channel* GlobalChannelList = 0;
+static unsigned int membershipAllocCount;
+static struct Membership* membershipFreeList;
+
static struct SLink *next_overlapped_ban(void);
static int del_banid(struct Channel *, char *, int);
void del_invite(struct Client *, struct Channel *);
assert(0 != chptr);
/* Servers don't have member links */
- if (IsServer(cptr))
+ if (IsServer(cptr)||IsMe(cptr))
return 0;
/* +k users are typically on a LOT of channels. So we iterate over who
int i;
for (i = 0; i <= HighestFd; i++)
{
- struct Client *acptr;
+ struct Client *acptr = 0;
if ((acptr = LocalClientArray[i]) && acptr->listing &&
acptr->listing->chptr == chptr)
{
assert(0 != who);
if (who->user) {
- struct Membership* member =
- (struct Membership*) MyMalloc(sizeof(struct Membership));
+
+ struct Membership* member = membershipFreeList;
+ if (member)
+ membershipFreeList = member->next_member;
+ else {
+ member = (struct Membership*) MyMalloc(sizeof(struct Membership));
+ ++membershipAllocCount;
+ }
+
assert(0 != member);
member->user = who;
member->channel = chptr;
member->user->user->channel = member->next_channel;
--member->user->user->joined;
- MyFree(member);
+
+ member->next_member = membershipFreeList;
+ membershipFreeList = member;
return sub1_from_channel(chptr);
}
addbuf, remstr, addstr,
mbuf->mb_channel->creationtime);
-#ifdef OPATH
- if (mbuf->mb_dest & MODEBUF_DEST_LOG) {
- write_log(OPATH, "%Tu %#C OPMODE %H %s%s%s%s%s%s\n", TStime(),
- mbuf->mb_source, mbuf->mb_channel, rembuf_i ? "-" : "", rembuf,
+ if (mbuf->mb_dest & MODEBUF_DEST_LOG)
+ log_write(LS_OPERMODE, L_INFO, LOG_NOSNOTICE,
+ "%#C OPMODE %H %s%s%s%s%s%s", mbuf->mb_source,
+ mbuf->mb_channel, rembuf_i ? "-" : "", rembuf,
addbuf_i ? "+" : "", addbuf, remstr, addstr);
- }
-#endif
if (mbuf->mb_dest & MODEBUF_DEST_CHANNEL)
sendcmdto_channel_butserv(app_source, CMD_MODE, mbuf->mb_channel,
unsigned int flags;
unsigned int dir;
unsigned int done;
+ unsigned int add;
+ unsigned int del;
int args_used;
int max_args;
int numbans;
state->chptr->mode.mode |= flag_p[0];
state->chptr->mode.limit = t_limit;
} else {
- state->chptr->mode.mode &= flag_p[0];
+ state->chptr->mode.mode &= ~flag_p[0];
state->chptr->mode.limit = 0;
}
}
if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
return;
- if (state->parc <= 0) { /* warn if not enough args */
- if (MyUser(state->sptr))
- need_more_params(state->sptr, state->dir == MODE_ADD ?
- (flag_p[0] == MODE_CHANOP ? "MODE +o" : "MODE +v") :
- (flag_p[0] == MODE_CHANOP ? "MODE -o" : "MODE -v"));
+ if (state->parc <= 0) /* return if not enough args */
return;
- }
t_str = state->parv[state->args_used++]; /* grab arg */
state->parc--;
static void
mode_parse_mode(struct ParseState *state, int *flag_p)
{
- if ((state->dir == MODE_ADD && (flag_p[0] & state->chptr->mode.mode)) ||
- (state->dir == MODE_DEL && !(flag_p[0] & state->chptr->mode.mode)))
- return; /* no change */
-
/* If they're not an oper, they can't change modes */
if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
send_notoper(state);
if (!state->mbuf)
return;
- modebuf_mode(state->mbuf, state->dir | flag_p[0]);
-
- /* make +p and +s mutually exclusive */
- if (state->dir == MODE_ADD && flag_p[0] & (MODE_SECRET | MODE_PRIVATE)) {
- if (flag_p[0] == MODE_SECRET && (state->chptr->mode.mode & MODE_PRIVATE))
- modebuf_mode(state->mbuf, MODE_DEL | MODE_PRIVATE);
- else if (flag_p[0] == MODE_PRIVATE &&
- (state->chptr->mode.mode & MODE_SECRET))
- modebuf_mode(state->mbuf, MODE_DEL | MODE_SECRET);
- }
-
- if (state->flags & MODE_PARSE_SET) { /* set the flags */
- if (state->dir == MODE_ADD) { /* add the mode to the channel */
- state->chptr->mode.mode |= flag_p[0];
-
- /* make +p and +s mutually exclusive */
- if (state->dir == MODE_ADD && flag_p[0] & (MODE_SECRET | MODE_PRIVATE)) {
- if (flag_p[0] == MODE_PRIVATE)
- state->chptr->mode.mode &= ~MODE_SECRET;
- else
- state->chptr->mode.mode &= ~MODE_PRIVATE;
- }
- } else /* remove the mode from the channel */
- state->chptr->mode.mode &= ~flag_p[0];
+ if (state->dir == MODE_ADD) {
+ state->add |= flag_p[0];
+ state->del &= ~flag_p[0];
+
+ if (flag_p[0] & MODE_SECRET) {
+ state->add &= ~MODE_PRIVATE;
+ state->del |= MODE_PRIVATE;
+ } else if (flag_p[0] & MODE_PRIVATE) {
+ state->add &= ~MODE_SECRET;
+ state->del |= MODE_SECRET;
+ }
+ } else {
+ state->add &= ~flag_p[0];
+ state->del |= flag_p[0];
}
- /* Clear out invite structures if we're removing invites */
- if (state->flags & MODE_PARSE_SET && state->dir == MODE_DEL &&
- flag_p[0] == MODE_INVITEONLY)
- mode_invite_clear(state->chptr);
+ assert(0 == (state->add & state->del));
+ assert((MODE_SECRET | MODE_PRIVATE) !=
+ (state->add & (MODE_SECRET | MODE_PRIVATE)));
}
/*
};
int i;
int *flag_p;
+ unsigned int t_mode;
char *modestr;
struct ParseState state;
state.flags = flags;
state.dir = MODE_ADD;
state.done = 0;
+ state.add = 0;
+ state.del = 0;
state.args_used = 0;
state.max_args = MAXMODEPARAMS;
state.numbans = 0;
if (!state.mbuf || state.flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER))
return state.args_used; /* tell our parent how many args we gobbled */
+ t_mode = state.chptr->mode.mode;
+
+ if (state.del & t_mode) { /* delete any modes to be deleted... */
+ modebuf_mode(state.mbuf, MODE_DEL | (state.del & t_mode));
+
+ t_mode &= ~state.del;
+ }
+ if (state.add & ~t_mode) { /* add any modes to be added... */
+ modebuf_mode(state.mbuf, MODE_ADD | (state.add & ~t_mode));
+
+ t_mode |= state.add;
+ }
+
+ if (state.flags & MODE_PARSE_SET) { /* set the channel modes */
+ if ((state.chptr->mode.mode & MODE_INVITEONLY) &&
+ !(t_mode & MODE_INVITEONLY))
+ mode_invite_clear(state.chptr);
+
+ state.chptr->mode.mode = t_mode;
+ }
+
if (state.flags & MODE_PARSE_WIPEOUT) {
if (state.chptr->mode.limit && !(state.done & DONE_LIMIT))
modebuf_mode_uint(state.mbuf, MODE_DEL | MODE_LIMIT,
assert(0 != jbuf);
- if (chan) {
- if (jbuf->jb_type == JOINBUF_TYPE_PART ||
- jbuf->jb_type == JOINBUF_TYPE_PARTALL) {
- /* Send notification to channel */
- if (!(flags & CHFL_ZOMBIE))
- sendcmdto_channel_butserv(jbuf->jb_source, CMD_PART, chan,
- (flags & CHFL_BANNED || !jbuf->jb_comment) ?
- ":%H" : "%H :%s", chan, jbuf->jb_comment);
- else if (MyUser(jbuf->jb_source))
- sendcmdto_one(jbuf->jb_source, CMD_PART, jbuf->jb_source,
- (flags & CHFL_BANNED || !jbuf->jb_comment) ?
- ":%H" : "%H :%s", chan, jbuf->jb_comment);
- /* XXX: Shouldn't we send a PART here anyway? */
- /* to users on the channel? Why? From their POV, the user isn't on
- * the channel anymore anyway. We don't send to servers until below,
- * when we gang all the channel parts together. Note that this is
- * exactly the same logic, albeit somewhat more concise, as was in
- * the original m_part.c */
-
- if (jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
- IsLocalChannel(chan->chname)) /* got to remove user here */
- remove_user_from_channel(jbuf->jb_source, chan);
- } else {
- /* Add user to channel */
- add_user_to_channel(chan, jbuf->jb_source, flags);
+ if (!chan) {
+ if (jbuf->jb_type == JOINBUF_TYPE_JOIN)
+ sendcmdto_serv_butone(jbuf->jb_source, CMD_JOIN, jbuf->jb_connect, "0");
- /* Send the notification to the channel */
- sendcmdto_channel_butserv(jbuf->jb_source, CMD_JOIN, chan, ":%H", chan);
+ return;
+ }
- /* send an op, too, if needed */
- if (!MyUser(jbuf->jb_source) && jbuf->jb_type == JOINBUF_TYPE_CREATE &&
- !IsModelessChannel(chan->chname))
- sendcmdto_channel_butserv(jbuf->jb_source, CMD_MODE, chan, "%H +o %C",
- chan, jbuf->jb_source);
- }
+ if (jbuf->jb_type == JOINBUF_TYPE_PART ||
+ jbuf->jb_type == JOINBUF_TYPE_PARTALL) {
+ /* Send notification to channel */
+ if (!(flags & CHFL_ZOMBIE))
+ sendcmdto_channel_butserv(jbuf->jb_source, CMD_PART, chan,
+ (flags & CHFL_BANNED || !jbuf->jb_comment) ?
+ ":%H" : "%H :%s", chan, jbuf->jb_comment);
+ else if (MyUser(jbuf->jb_source))
+ sendcmdto_one(jbuf->jb_source, CMD_PART, jbuf->jb_source,
+ (flags & CHFL_BANNED || !jbuf->jb_comment) ?
+ ":%H" : "%H :%s", chan, jbuf->jb_comment);
+ /* XXX: Shouldn't we send a PART here anyway? */
+ /* to users on the channel? Why? From their POV, the user isn't on
+ * the channel anymore anyway. We don't send to servers until below,
+ * when we gang all the channel parts together. Note that this is
+ * exactly the same logic, albeit somewhat more concise, as was in
+ * the original m_part.c */
+
+ if (jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
+ IsLocalChannel(chan->chname)) /* got to remove user here */
+ remove_user_from_channel(jbuf->jb_source, chan);
+ } else {
+ /* Add user to channel */
+ add_user_to_channel(chan, jbuf->jb_source, flags);
- if (jbuf->jb_type == JOINBUF_TYPE_PARTALL || IsLocalChannel(chan->chname))
- return; /* don't send to remote */
+ /* send notification to all servers */
+ if (jbuf->jb_type != JOINBUF_TYPE_CREATE && !IsLocalChannel(chan->chname))
+ sendcmdto_serv_butone(jbuf->jb_source, CMD_JOIN, jbuf->jb_connect,
+ "%H %Tu", chan, chan->creationtime);
+
+ /* Send the notification to the channel */
+ sendcmdto_channel_butserv(jbuf->jb_source, CMD_JOIN, chan, ":%H", chan);
+
+ /* send an op, too, if needed */
+ if (!MyUser(jbuf->jb_source) && jbuf->jb_type == JOINBUF_TYPE_CREATE &&
+ !IsModelessChannel(chan->chname))
+ sendcmdto_channel_butserv(jbuf->jb_source, CMD_MODE, chan, "%H +o %C",
+ chan, jbuf->jb_source);
}
+ if (jbuf->jb_type == JOINBUF_TYPE_PARTALL || IsLocalChannel(chan->chname))
+ return; /* don't send to remote */
+
/* figure out if channel name will cause buffer to be overflowed */
len = chan ? strlen(chan->chname) + 1 : 2;
if (jbuf->jb_strlen + len > IRC_BUFSIZE)
int chanlist_i = 0;
int i;
- if (!jbuf->jb_count || jbuf->jb_type == JOINBUF_TYPE_PARTALL)
+ if (!jbuf->jb_count || jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
+ jbuf->jb_type == JOINBUF_TYPE_JOIN)
return 0; /* no joins to process */
for (i = 0; i < jbuf->jb_count; i++) { /* build channel list */
}
jbuf->jb_count = 0; /* reset base counters */
- jbuf->jb_strlen = ((jbuf->jb_type == JOINBUF_TYPE_JOIN ||
- jbuf->jb_type == JOINBUF_TYPE_PART ?
+ jbuf->jb_strlen = ((jbuf->jb_type == JOINBUF_TYPE_PART ?
STARTJOINLEN : STARTCREATELEN) +
(jbuf->jb_comment ? strlen(jbuf->jb_comment) + 2 : 0));
/* and send the appropriate command */
switch (jbuf->jb_type) {
- case JOINBUF_TYPE_JOIN:
- sendcmdto_serv_butone(jbuf->jb_source, CMD_JOIN, jbuf->jb_connect,
- "%s", chanlist);
- break;
-
case JOINBUF_TYPE_CREATE:
sendcmdto_serv_butone(jbuf->jb_source, CMD_CREATE, jbuf->jb_connect,
"%s %Tu", chanlist, jbuf->jb_create);