+2000-04-29 Kevin L. Mitchell <klmitch@mit.edu>
+
+ * ircd/m_join.c: reimplement JOIN in terms of struct JoinBuf
+
+ * ircd/channel.c (clean_channelname): make clean_channelname also
+ truncate long channel names
+
+2000-04-28 Kevin L. Mitchell <klmitch@mit.edu>
+
+ * ircd/m_create.c: reimplement CREATE in terms of struct JoinBuf
+
+ * ircd/channel.c: implemented joinbuf_init, joinbuf_join,
+ joinbuf_flush
+
+ * include/channel.h: definitions and declarations for the struct
+ JoinBuf abstraction
+
2000-04-29 Perry Lorier <isomer@coders.net>
* include/s_bsd.c: Ok, so I thought I compiled and tested this...
#
# ChangeLog for ircu2.10.11
#
-# $Id: ChangeLog,v 1.114 2000-04-29 05:30:05 isomer Exp $
+# $Id: ChangeLog,v 1.115 2000-04-30 01:33:27 kev Exp $
#
# Insert new changes at beginning of the change list.
#
#define MAXBANS 30
#define MAXBANLENGTH 1024
+#define MAXJOINARGS 15 /* number of slots for join buffer */
+#define STARTJOINLEN 10 /* fuzzy numbers */
+#define STARTCREATELEN 20
+
/*
* Macro's
*/
#define MB_STRING(mb, i) ((mb)->mb_modeargs[(i)].mbm_arg.mbma_string)
#define MB_CLIENT(mb, i) ((mb)->mb_modeargs[(i)].mbm_arg.mbma_client)
+struct JoinBuf {
+ struct Client *jb_source; /* Source of joins (ie, joiner) */
+ struct Client *jb_connect; /* Connection of joiner */
+ unsigned int jb_type; /* Type of join (JOIN or CREATE) */
+ char *jb_comment; /* part comment */
+ time_t jb_create; /* Creation timestamp */
+ unsigned int jb_count; /* Number of channels */
+ unsigned int jb_strlen; /* length so far */
+ struct Channel *jb_channels[MAXJOINARGS];
+ /* channels joined or whatever */
+};
+
+#define JOINBUF_TYPE_JOIN 0 /* send JOINs */
+#define JOINBUF_TYPE_CREATE 1 /* send CREATEs */
+#define JOINBUF_TYPE_PART 2 /* send PARTs */
+#define JOINBUF_TYPE_PARTALL 3 /* send local PARTs, but not remote */
+
extern struct Channel* GlobalChannelList;
extern int LocalChanOperMode;
#define MODE_PARSE_NOTOPER 0x10 /* send "not chanop" to user */
#define MODE_PARSE_NOTMEMBER 0x20 /* send "not member" to user */
+extern void joinbuf_init(struct JoinBuf *jbuf, struct Client *source,
+ struct Client *connect, unsigned int type,
+ char *comment, time_t create);
+extern void joinbuf_join(struct JoinBuf *jbuf, struct Channel *chan,
+ unsigned int flags);
+extern int joinbuf_flush(struct JoinBuf *jbuf);
+
#endif /* INCLUDED_channel_h */
*/
void clean_channelname(char *cn)
{
- for (; *cn; ++cn) {
- if (!IsChannelChar(*cn)) {
- *cn = '\0';
+ int i;
+
+ for (i = 0; cn[i]; i++) {
+ if (i >= CHANNELLEN || !IsChannelChar(cn[i])) {
+ cn[i] = '\0';
return;
}
- if (IsChannelLower(*cn)) {
- *cn = ToLower(*cn);
+ if (IsChannelLower(cn[i])) {
+ cn[i] = ToLower(cn[i]);
#ifndef FIXME
/*
* Remove for .08+
* toupper(0xd0)
*/
- if ((unsigned char)(*cn) == 0xd0)
- *cn = (char) 0xf0;
+ if ((unsigned char)(cn[i]) == 0xd0)
+ cn[i] = (char) 0xf0;
#endif
}
}
* of course, str2 is not NULL)
*/
static void
-build_string(char *strptr, int *strptr_i, char *str1, char *str2)
+build_string(char *strptr, int *strptr_i, char *str1, char *str2, char c)
{
- strptr[(*strptr_i)++] = ' ';
+ if (c)
+ strptr[(*strptr_i)++] = c;
while (*str1)
strptr[(*strptr_i)++] = *(str1++);
/* deal with clients... */
if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE))
- build_string(strptr, strptr_i, MB_CLIENT(mbuf, i)->name, 0);
+ build_string(strptr, strptr_i, MB_CLIENT(mbuf, i)->name, 0, ' ');
/* deal with strings... */
else if (MB_TYPE(mbuf, i) & (MODE_KEY | MODE_BAN))
- build_string(strptr, strptr_i, MB_STRING(mbuf, i), 0);
+ build_string(strptr, strptr_i, MB_STRING(mbuf, i), 0, ' ');
/*
* deal with limit; note we cannot include the limit parameter if we're
*/
else if ((MB_TYPE(mbuf, i) & (MODE_ADD | MODE_LIMIT)) ==
(MODE_ADD | MODE_LIMIT))
- build_string(strptr, strptr_i, limitbuf, 0);
+ build_string(strptr, strptr_i, limitbuf, 0, ' ');
}
/* send the messages off to their destination */
/* deal with modes that take clients */
if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE))
- build_string(strptr, strptr_i, NumNick(MB_CLIENT(mbuf, i)));
+ build_string(strptr, strptr_i, NumNick(MB_CLIENT(mbuf, i)), ' ');
/* deal with modes that take strings */
else if (MB_TYPE(mbuf, i) & (MODE_KEY | MODE_BAN))
- build_string(strptr, strptr_i, MB_STRING(mbuf, i), 0);
+ build_string(strptr, strptr_i, MB_STRING(mbuf, i), 0, ' ');
/*
* deal with the limit. Logic here is complicated; if HACK2 is set,
* include the original limit if it looks like it's being removed
*/
else if ((MB_TYPE(mbuf, i) & limitdel) == limitdel)
- build_string(strptr, strptr_i, limitbuf, 0);
+ build_string(strptr, strptr_i, limitbuf, 0, ' ');
}
/* we were told to deop the source */
if (mbuf->mb_dest & MODEBUF_DEST_DEOP) {
addbuf[addbuf_i++] = 'o'; /* remember, sense is reversed */
addbuf[addbuf_i] = '\0'; /* terminate the string... */
- build_string(addstr, &addstr_i, NumNick(mbuf->mb_source)); /* add user */
+ build_string(addstr, &addstr_i, NumNick(mbuf->mb_source), ' ');
/* mark that we've done this, so we don't do it again */
mbuf->mb_dest &= ~MODEBUF_DEST_DEOP;
return state.args_used; /* tell our parent how many args we gobbled */
}
+
+/*
+ * Initialize a join buffer
+ */
+void
+joinbuf_init(struct JoinBuf *jbuf, struct Client *source,
+ struct Client *connect, unsigned int type, char *comment,
+ time_t create)
+{
+ int i;
+
+ assert(0 != jbuf);
+ assert(0 != source);
+ assert(0 != connect);
+
+ jbuf->jb_source = source; /* just initialize struct JoinBuf */
+ jbuf->jb_connect = connect;
+ jbuf->jb_type = type;
+ jbuf->jb_comment = comment;
+ jbuf->jb_create = create;
+ jbuf->jb_count = 0;
+ jbuf->jb_strlen = (((type == JOINBUF_TYPE_JOIN ||
+ type == JOINBUF_TYPE_PART ||
+ type == JOINBUF_TYPE_PARTALL) ?
+ STARTJOINLEN : STARTCREATELEN) +
+ (comment ? strlen(comment) + 2 : 0));
+
+ for (i = 0; i < MAXJOINARGS; i++)
+ jbuf->jb_channels[i] = 0;
+}
+
+/*
+ * Add a channel to the join buffer
+ */
+void
+joinbuf_join(struct JoinBuf *jbuf, struct Channel *chan, unsigned int flags)
+{
+ unsigned int len;
+
+ 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);
+
+ /* Remove user from channel */
+ remove_user_from_channel(jbuf->jb_source, chan);
+ } else {
+ /* Add user to channel */
+ add_user_to_channel(chan, jbuf->jb_source, flags);
+
+ /* Send the notification to the channel */
+ sendcmdto_channel_butserv(jbuf->jb_source, CMD_JOIN, chan, ":%H", chan);
+
+ /* send an op, too, if needed */
+ if (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)
+ joinbuf_flush(jbuf);
+
+ /* add channel to list of channels to send and update counts */
+ jbuf->jb_channels[jbuf->jb_count++] = chan;
+ jbuf->jb_strlen += len;
+
+ /* if we've used up all slots, flush */
+ if (jbuf->jb_count >= MAXJOINARGS)
+ joinbuf_flush(jbuf);
+}
+
+/*
+ * Flush the channel list to remote servers
+ */
+int
+joinbuf_flush(struct JoinBuf *jbuf)
+{
+ char chanlist[IRC_BUFSIZE];
+ int chanlist_i = 0;
+ int i;
+
+ if (!jbuf->jb_count || jbuf->jb_type == JOINBUF_TYPE_PARTALL)
+ return 0; /* no joins to process */
+
+ for (i = 0; i < jbuf->jb_count; i++) { /* build channel list */
+ build_string(chanlist, &chanlist_i,
+ jbuf->jb_channels[i] ? jbuf->jb_channels[i]->chname : "0", 0,
+ i == 0 ? '\0' : ',');
+
+ jbuf->jb_channels[i] = 0; /* mark slot empty */
+ }
+
+ jbuf->jb_count = 0; /* reset base counters */
+ jbuf->jb_strlen = ((jbuf->jb_type == JOINBUF_TYPE_JOIN ||
+ 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);
+ break;
+
+ case JOINBUF_TYPE_PART:
+ sendcmdto_serv_butone(jbuf->jb_source, CMD_PART, jbuf->jb_connect,
+ jbuf->jb_comment ? "%s :%s" : "%s", chanlist,
+ jbuf->jb_comment);
+ break;
+ }
+
+ return 0;
+}
#include "msg.h"
#include "numeric.h"
#include "numnicks.h"
+#include "s_debug.h"
#include "send.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>
-/*
- * m_create - generic message handler
- */
-int m_create(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
-{
- return 0;
-}
-
/*
* ms_create - server message handler
*/
int ms_create(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
{
- char cbuf[BUFSIZE]; /* Buffer for list with channels
- that `sptr' really creates */
- time_t chanTS; /* Creation time for all channels
- in the comma seperated list */
- char* p;
- char* name;
- struct Channel* chptr;
- int badop;
+ time_t chanTS; /* channel creation time */
+ char *p; /* strtok state */
+ char *name; /* channel name */
+ struct Channel *chptr; /* channel */
+ struct JoinBuf join; /* join and create buffers */
+ struct JoinBuf create;
+ struct ModeBuf mbuf; /* a mode buffer */
+ int badop; /* a flag */
if (IsServer(sptr)) {
- /* PROTOCOL WARNING */
- /* bail, don't core */
+ Debug((DEBUG_ERROR, "%s tried to CREATE a channel", sptr->name));
return 0;
}
+
/* sanity checks: Only accept CREATE messages from servers */
if (!IsServer(cptr) || parc < 3 || *parv[2] == '\0')
return 0;
chanTS = atoi(parv[2]);
+ joinbuf_init(&join, sptr, cptr, JOINBUF_TYPE_JOIN, 0, 0);
+ joinbuf_init(&create, sptr, cptr, JOINBUF_TYPE_CREATE, 0, chanTS);
+
/* A create that didn't appear during a burst has that servers idea of
* the current time. Use it for lag calculations.
*/
- if (!IsBurstOrBurstAck(sptr) && 0 != chanTS && MAGIC_REMOTE_JOIN_TS != chanTS)
+ if (!IsBurstOrBurstAck(sptr) && 0 != chanTS &&
+ MAGIC_REMOTE_JOIN_TS != chanTS)
sptr->user->server->serv->lag = TStime() - chanTS;
- *cbuf = '\0'; /* Start with empty buffer */
-
/* For each channel in the comma seperated list: */
- for (name = ircd_strtok(&p, parv[1], ","); name; name = ircd_strtok(&p, 0, ","))
- {
- badop = 0; /* Default is to accept the op */
- if ((chptr = FindChannel(name)))
- {
- name = chptr->chname;
- if (TStime() - chanTS > TS_LAG_TIME)
- {
- /* A bounce would not be accepted anyway - if we get here something
- is wrong with the TS clock syncing (or we have more then
- TS_LAG_TIME lag, or an admin is hacking */
- badop = 2;
- /* This causes a HACK notice on all upstream servers: */
- sendto_one(cptr, "%s " TOK_MODE " %s -o %s%s 0", NumServ(&me), name, NumNick(sptr));
- /* This causes a WALLOPS on all downstream servers and a notice to our
- own opers: */
- parv[1] = name; /* Corrupt parv[1], it is not used anymore anyway */
- send_hack_notice(cptr, sptr, parc, parv, badop, 2);
- }
- else if (chptr->creationtime && chanTS > chptr->creationtime &&
- chptr->creationtime != MAGIC_REMOTE_JOIN_TS)
- {
- /* We (try) to bounce the mode, because the CREATE is used on an older
- channel, probably a net.ride */
- badop = 1;
- /* Send a deop upstream: */
- sendto_one(cptr, "%s " TOK_MODE " %s -o %s%s " TIME_T_FMT, NumServ(&me),
- name, NumNick(sptr), chptr->creationtime);
- }
- }
- else /* Channel doesn't exist: create it */
- chptr = get_channel(sptr, name, CGT_CREATE);
-
- /* Add and mark ops */
- add_user_to_channel(chptr, sptr,
- (badop || IsModelessChannel(name)) ? CHFL_DEOPPED : CHFL_CHANOP);
-
- /* Send user join to the local clients (if any) */
- sendto_channel_butserv(chptr, sptr, ":%s " MSG_JOIN " :%s", parv[0], name);
-
- if (badop) /* handle badop: convert CREATE into JOIN */
- sendto_serv_butone(cptr, "%s%s " TOK_JOIN " %s " TIME_T_FMT,
- NumNick(sptr), name, chptr->creationtime);
- else
- {
- /* Send the op to local clients:
- (if any; extremely unlikely, but it CAN happen) */
- if (!IsModelessChannel(name))
- sendto_channel_butserv(chptr, sptr, ":%s MODE %s +o %s",
- sptr->user->server->name, name, parv[0]);
-
- /* Set/correct TS and add the channel to the
- buffer for accepted channels: */
- chptr->creationtime = chanTS;
- if (*cbuf)
- strcat(cbuf, ",");
- strcat(cbuf, name);
- }
- }
-
- if (*cbuf) /* Any channel accepted with ops ? */
- {
- sendto_serv_butone(cptr, "%s%s " TOK_CREATE " %s " TIME_T_FMT,
- NumNick(sptr), cbuf, chanTS);
- }
-
- return 0;
-}
+ for (name = ircd_strtok(&p, parv[1], ","); name;
+ name = ircd_strtok(&p, 0, ",")) {
+ badop = 0;
-#if 0
-/*
- * m_create
- *
- * parv[0] = sender prefix
- * parv[1] = channel names
- * parv[2] = channel time stamp
- */
-int m_create(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
-{
- char cbuf[BUFSIZE]; /* Buffer for list with channels
- that `sptr' really creates */
- time_t chanTS; /* Creation time for all channels
- in the comma seperated list */
- char* p;
- char* name;
- struct Channel* chptr;
- int badop;
+ if (IsLocalChannel(name))
+ continue;
- /* sanity checks: Only accept CREATE messages from servers */
- if (!IsServer(cptr) || parc < 3 || *parv[2] == '\0')
- return 0;
+ if ((chptr = FindChannel(name))) {
+ name = chptr->chname;
- chanTS = atoi(parv[2]);
+ /* Check if we need to bounce a mode */
+ if (TStime() - chanTS > TS_LAG_TIME ||
+ (chptr->creationtime && chanTS > chptr->creationtime &&
+ chptr->creationtime != MAGIC_REMOTE_JOIN_TS)) {
+ modebuf_init(&mbuf, sptr, cptr, chptr,
+ (MODEBUF_DEST_SERVER | /* Send mode to server */
+ MODEBUF_DEST_HACK2 | /* Send a HACK(2) message */
+ MODEBUF_DEST_BOUNCE)); /* And bounce the mode */
- /* A create that didn't appear during a burst has that servers idea of
- * the current time. Use it for lag calculations.
- */
- if (!IsBurstOrBurstAck(sptr) && 0 != chanTS && MAGIC_REMOTE_JOIN_TS != chanTS)
- sptr->user->server->serv->lag = TStime() - chanTS;
+ modebuf_mode_client(&mbuf, MODE_ADD | MODE_CHANOP, sptr);
- *cbuf = '\0'; /* Start with empty buffer */
+ modebuf_flush(&mbuf);
- /* For each channel in the comma seperated list: */
- for (name = ircd_strtok(&p, parv[1], ","); name; name = ircd_strtok(&p, 0, ","))
- {
- badop = 0; /* Default is to accept the op */
- if ((chptr = FindChannel(name)))
- {
- name = chptr->chname;
- if (TStime() - chanTS > TS_LAG_TIME)
- {
- /* A bounce would not be accepted anyway - if we get here something
- is wrong with the TS clock syncing (or we have more then
- TS_LAG_TIME lag, or an admin is hacking */
- badop = 2;
- /* This causes a HACK notice on all upstream servers: */
- sendto_one(cptr, "%s " TOK_MODE " %s -o %s%s 0", NumServ(&me), name, NumNick(sptr));
- /* This causes a WALLOPS on all downstream servers and a notice to our
- own opers: */
- parv[1] = name; /* Corrupt parv[1], it is not used anymore anyway */
- send_hack_notice(cptr, sptr, parc, parv, badop, 2);
- }
- else if (chptr->creationtime && chanTS > chptr->creationtime &&
- chptr->creationtime != MAGIC_REMOTE_JOIN_TS)
- {
- /* We (try) to bounce the mode, because the CREATE is used on an older
- channel, probably a net.ride */
- badop = 1;
- /* Send a deop upstream: */
- sendto_one(cptr, "%s " TOK_MODE " %s -o %s%s " TIME_T_FMT, NumServ(&me),
- name, NumNick(sptr), chptr->creationtime);
+ badop = 1;
}
- }
- else /* Channel doesn't exist: create it */
+ } else /* Channel doesn't exist: create it */
chptr = get_channel(sptr, name, CGT_CREATE);
- /* Add and mark ops */
- add_user_to_channel(chptr, sptr,
- (badop || IsModelessChannel(name)) ? CHFL_DEOPPED : CHFL_CHANOP);
-
- /* Send user join to the local clients (if any) */
- sendto_channel_butserv(chptr, sptr, ":%s " MSG_JOIN " :%s", parv[0], name);
-
- if (badop) /* handle badop: convert CREATE into JOIN */
- sendto_serv_butone(cptr, "%s%s " TOK_JOIN " %s " TIME_T_FMT,
- NumNick(sptr), name, chptr->creationtime);
- else
- {
- /* Send the op to local clients:
- (if any; extremely unlikely, but it CAN happen) */
- if (!IsModelessChannel(name))
- sendto_channel_butserv(chptr, sptr, ":%s MODE %s +o %s",
- sptr->user->server->name, name, parv[0]);
-
- /* Set/correct TS and add the channel to the
- buffer for accepted channels: */
+ if (!badop) /* Set/correct TS */
chptr->creationtime = chanTS;
- if (*cbuf)
- strcat(cbuf, ",");
- strcat(cbuf, name);
- }
- }
- if (*cbuf) /* Any channel accepted with ops ? */
- {
- sendto_serv_butone(cptr, "%s%s " TOK_CREATE " %s " TIME_T_FMT,
- NumNick(sptr), cbuf, chanTS);
+ joinbuf_join(badop ? &join : &create, chptr,
+ (badop || IsModelessChannel(name)) ?
+ CHFL_DEOPPED : CHFL_CHANOP);
}
+ joinbuf_flush(&join); /* flush out the joins and creates */
+ joinbuf_flush(&create);
+
return 0;
}
-#endif /* 0 */
-
#include "msg.h"
#include "numeric.h"
#include "numnicks.h"
+#include "s_debug.h"
#include "s_user.h"
#include "send.h"
#endif
/*
- * m_join - generic message handler
+ * Helper function to find last 0 in a comma-separated list of
+ * channel names.
*/
-int m_join(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+static char *
+last0(char *chanlist)
{
- static char jbuf[BUFSIZE];
- static char mbuf[BUFSIZE];
- struct Membership* member;
- struct Channel* chptr;
- char* name;
- char* keysOrTS = NULL;
- int i = 0;
- int zombie = 0;
- int sendcreate = 0;
- unsigned int flags = 0;
- size_t jlen = 0;
- size_t mlen = 0;
- size_t* buflen;
- char* p = NULL;
- char* bufptr;
+ char *p;
+ for (p = chanlist; p[0]; p++) /* find last "JOIN 0" */
+ if (p[0] == '0' && (p[1] == ',' || p[1] == '\0' || !IsChannelChar(p[1]))) {
+ chanlist = p; /* we'll start parsing here */
- if (parc < 2 || *parv[1] == '\0')
- return need_more_params(sptr, "JOIN");
+ if (!p[1]) /* hit the end */
+ break;
- for (p = parv[1]; *p; p++) /* find the last "JOIN 0" in the line -Kev */
- if (*p == '0'
- && (*(p + 1) == ',' || *(p + 1) == '\0' || !IsChannelChar(*(p + 1))))
- {
- /* If it's a single "0", remember the place; we will start parsing
- the channels after the last 0 in the line -Kev */
- parv[1] = p;
- if (!*(p + 1))
- break;
p++;
- }
- else
- { /* Step through to the next comma or until the
- end of the line, in an attempt to save CPU
- -Kev */
- while (*p != ',' && *p != '\0')
- p++;
- if (!*p)
- break;
- }
+ } else {
+ while (p[0] != ',' && p[0] != '\0') /* skip past channel name */
+ p++;
- keysOrTS = parv[2]; /* Remember where our keys are or the TS is;
- parv[2] needs to be NULL for the call to
- m_names below -Kev */
- parv[2] = p = NULL;
-
- *jbuf = *mbuf = '\0'; /* clear both join and mode buffers -Kev */
- /*
- * Rebuild list of channels joined to be the actual result of the
- * JOIN. Note that "JOIN 0" is the destructive problem.
- */
- for (name = ircd_strtok(&p, parv[1], ","); name; name = ircd_strtok(&p, NULL, ","))
- {
- size_t len;
- if (MyConnect(sptr))
- clean_channelname(name);
- else if (IsLocalChannel(name))
- continue;
- if (*name == '0' && *(name + 1) == '\0')
- {
- /* Remove the user from all his channels -Kev */
- while ((member = sptr->user->channel))
- {
- chptr = member->channel;
- if (!IsZombie(member))
- sendto_channel_butserv(chptr, sptr, PartFmt2,
- parv[0], chptr->chname, "Left all channels");
- remove_user_from_channel(sptr, chptr);
- }
- /* Just in case */
- *mbuf = *jbuf = '\0';
- mlen = jlen = 0;
+ if (!p[0]) /* hit the end */
+ break;
}
- else
- { /* not a /join 0, so treat it as
- a /join #channel -Kev */
- if (!IsChannelName(name))
- {
- if (MyUser(sptr))
- sendto_one(sptr, err_str(ERR_NOSUCHCHANNEL), me.name, parv[0], name);
- continue;
- }
-
- if (MyConnect(sptr))
- {
-#ifdef BADCHAN
- struct Gline *gline;
-
- if ((gline = gline_find(name, GLINE_BADCHAN | GLINE_EXACT)) &&
- GlineIsActive(gline) && !IsAnOper(sptr))
- {
- sendto_one(sptr, err_str(ERR_BADCHANNAME), me.name, parv[0], name);
- continue;
- }
-#endif
- /*
- * Local client is first to enter previously nonexistant
- * channel so make them (rightfully) the Channel Operator.
- * This looks kind of ugly because we try to avoid calling the strlen()
- */
- if (ChannelExists(name))
- {
- flags = CHFL_DEOPPED;
- sendcreate = 0;
- }
- else if (strlen(name) > CHANNELLEN)
- {
- *(name + CHANNELLEN) = '\0';
- if (ChannelExists(name))
- {
- flags = CHFL_DEOPPED;
- sendcreate = 0;
- }
- else
- {
- flags = IsModelessChannel(name) ? CHFL_DEOPPED : CHFL_CHANOP;
- sendcreate = 1;
- }
- }
- else
- {
- flags = IsModelessChannel(name) ? CHFL_DEOPPED : CHFL_CHANOP;
- sendcreate = 1;
- }
-#ifdef OPER_NO_CHAN_LIMIT
- /*
- * Opers are allowed to join any number of channels
- */
- if (sptr->user->joined >= MAXCHANNELSPERUSER && !IsAnOper(sptr))
-#else
- if (sptr->user->joined >= MAXCHANNELSPERUSER)
-#endif
- {
- chptr = get_channel(sptr, name, CGT_NO_CREATE);
- sendto_one(sptr, err_str(ERR_TOOMANYCHANNELS),
- me.name, parv[0], chptr ? chptr->chname : name);
- /*
- * Can't return, else he won't get on ANY channels!
- * Break out of the for loop instead. -Kev
- */
- break;
- }
- }
- chptr = get_channel(sptr, name, CGT_CREATE);
- if (chptr && (member = find_member_link(chptr, sptr)))
- {
- if (IsZombie(member))
- {
- zombie = 1;
- flags = member->status & (CHFL_DEOPPED | CHFL_SERVOPOK);
- remove_user_from_channel(sptr, chptr);
- chptr = get_channel(sptr, name, CGT_CREATE);
- }
- else
- continue;
- }
- name = chptr->chname;
- if (!chptr->creationtime) /* A remote JOIN created this channel ? */
- chptr->creationtime = MAGIC_REMOTE_JOIN_TS;
- if (parc > 2)
- {
- if (chptr->creationtime == MAGIC_REMOTE_JOIN_TS)
- chptr->creationtime = atoi(keysOrTS);
- else
- parc = 2; /* Don't pass it on */
- }
- if (!zombie)
- {
- if (!MyConnect(sptr))
- flags = CHFL_DEOPPED;
- if (sptr->flags & FLAGS_TS8)
- flags |= CHFL_SERVOPOK;
- }
- if (MyConnect(sptr))
- {
- int created = chptr->users == 0;
- if (check_target_limit(sptr, chptr, chptr->chname, created))
- {
- if (created) /* Did we create the channel? */
- sub1_from_channel(chptr); /* Remove it again! */
- continue;
- }
- if ((i = can_join(sptr, chptr, keysOrTS)))
- {
-#ifdef OPER_WALK_THROUGH_LMODES
- if (i > MAGIC_OPER_OVERRIDE)
- {
- switch(i - MAGIC_OPER_OVERRIDE)
- {
- case ERR_CHANNELISFULL: i = 'l'; break;
- case ERR_INVITEONLYCHAN: i = 'i'; break;
- case ERR_BANNEDFROMCHAN: i = 'b'; break;
- case ERR_BADCHANNELKEY: i = 'k'; break;
- }
- sendto_op_mask(SNO_HACK4,"OPER JOIN: %s JOIN %s (overriding +%c)",sptr->name,chptr->chname,i);
- }
- else
- {
- sendto_one(sptr, err_str(i), me.name, parv[0], chptr->chname);
- continue;
- }
-#else
- sendto_one(sptr, err_str(i), me.name, parv[0], chptr->chname);
- continue;
-#endif
- }
- }
- /*
- * Complete user entry to the new channel (if any)
- */
- add_user_to_channel(chptr, sptr, flags);
-
- /*
- * Notify all other users on the new channel
- */
- sendto_channel_butserv(chptr, sptr, ":%s JOIN :%s", parv[0], name);
-
- if (MyUser(sptr))
- {
- del_invite(sptr, chptr);
- if (chptr->topic[0] != '\0')
- {
- sendto_one(sptr, rpl_str(RPL_TOPIC), me.name,
- parv[0], name, chptr->topic);
- sendto_one(sptr, rpl_str(RPL_TOPICWHOTIME), me.name, parv[0], name,
- chptr->topic_nick, chptr->topic_time);
- }
- parv[1] = name;
- m_names(cptr, sptr, 2, parv);
- }
- }
+ return chanlist;
+}
- /* Select proper buffer; mbuf for creation, jbuf otherwise */
-
- if (*name == '&')
- continue; /* Head off local channels at the pass */
-
- bufptr = (sendcreate == 0) ? jbuf : mbuf;
- buflen = (sendcreate == 0) ? &jlen : &mlen;
- len = strlen(name);
- if (*buflen < BUFSIZE - len - 2)
- {
- if (*bufptr)
- {
- strcat(bufptr, ","); /* Add to join buf */
- *buflen += 1;
- }
- strncat(bufptr, name, BUFSIZE - *buflen - 1);
- *buflen += len;
- }
- sendcreate = 0; /* Reset sendcreate */
- }
+/*
+ * Helper function to perform a JOIN 0 if needed; returns 0 if channel
+ * name is not 0, else removes user from all channels and returns 1.
+ */
+static int
+join0(struct JoinBuf *join, struct Client *cptr, struct Client *sptr,
+ char *chan)
+{
+ struct Membership *member;
+ struct JoinBuf part;
- if (*jbuf) /* Propgate joins to P10 servers */
- sendto_serv_butone(cptr,
- parc > 2 ? "%s%s " TOK_JOIN " %s %s" : "%s%s " TOK_JOIN " %s", NumNick(sptr), jbuf, keysOrTS);
- if (*mbuf) /* and now creation events */
- sendto_serv_butone(cptr, "%s%s " TOK_CREATE " %s " TIME_T_FMT,
- NumNick(sptr), mbuf, TStime());
-
- if (MyUser(sptr))
- { /* shouldn't ever set TS for remote JOIN's */
- if (*jbuf)
- { /* check for channels that need TS's */
- p = NULL;
- for (name = ircd_strtok(&p, jbuf, ","); name; name = ircd_strtok(&p, NULL, ","))
- {
- chptr = get_channel(sptr, name, CGT_NO_CREATE);
- if (chptr && chptr->mode.mode & MODE_SENDTS)
- { /* send a TS? */
- sendto_serv_butone(cptr, "%s " TOK_MODE " %s + " TIME_T_FMT, NumServ(&me),
- chptr->chname, chptr->creationtime); /* ok, send TS */
- chptr->mode.mode &= ~MODE_SENDTS; /* reset flag */
- }
- }
- }
- }
- return 0;
+ /* is it a JOIN 0? */
+ if (chan[0] != '0' || chan[1] != '\0')
+ return 0;
+
+ joinbuf_join(join, 0, 0); /* join special channel 0 */
+
+ /* leave all channels */
+ joinbuf_init(&part, sptr, cptr, JOINBUF_TYPE_PARTALL,
+ "Left all channels", 0);
+
+ while ((member = sptr->user->channel))
+ joinbuf_join(&part, member->channel,
+ IsZombie(member) ? CHFL_ZOMBIE : 0);
+
+ joinbuf_flush(&part);
+
+ return 1;
}
/*
- * ms_join - server message handler
+ * m_join - generic message handler
*/
-int ms_join(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+int m_join(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
{
- static char jbuf[BUFSIZE];
- static char mbuf[BUFSIZE];
- struct Membership* member;
- struct Channel* chptr;
- char* name;
- char* keysOrTS = NULL;
- int zombie = 0;
- int sendcreate = 0;
- unsigned int flags = 0;
- size_t jlen = 0;
- size_t mlen = 0;
- size_t* buflen;
- char* p = NULL;
- char* bufptr;
-
- /*
- * Doesn't make sense having a server join a channel, and besides
- * the server cores.
- */
- if (IsServer(sptr))
- return 0;
+ struct Channel *chptr;
+ struct JoinBuf join;
+ struct JoinBuf create;
+#ifdef BADCHAN
+ struct Gline *gline;
+#endif
+ unsigned int flags = 0;
+ int i;
+ char *p = 0;
+ char *chanlist;
+ char *name;
+ char *keys;
if (parc < 2 || *parv[1] == '\0')
return need_more_params(sptr, "JOIN");
- keysOrTS = parv[2]; /* Remember where our keys are or the TS is;
- parv[2] needs to be NULL for the call to
- m_names below -Kev */
- parv[2] = p = NULL;
-
- *jbuf = *mbuf = '\0'; /* clear both join and mode buffers -Kev */
- /*
- * Rebuild list of channels joined to be the actual result of the
- * JOIN. Note that "JOIN 0" is the destructive problem.
- */
- for (name = ircd_strtok(&p, parv[1], ","); name; name = ircd_strtok(&p, NULL, ","))
- {
- size_t len;
- if (IsLocalChannel(name))
+ joinbuf_init(&join, sptr, cptr, JOINBUF_TYPE_JOIN, 0, 0);
+ joinbuf_init(&create, sptr, cptr, JOINBUF_TYPE_CREATE, 0, TStime());
+
+ chanlist = last0(parv[1]); /* find last "JOIN 0" */
+
+ keys = parv[2]; /* remember where keys are */
+
+ parv[2] = 0; /* for call to m_names below */
+
+ for (name = ircd_strtok(&p, chanlist, ","); name;
+ name = ircd_strtok(&p, 0, ",")) {
+ clean_channelname(name);
+
+ if (join0(&join, cptr, sptr, name)) /* did client do a JOIN 0? */
continue;
- if (!IsChannelName(name))
- {
- sendto_one(sptr, err_str(ERR_NOSUCHCHANNEL), me.name, parv[0], name);
+ if (!IsChannelName(name)) { /* bad channel name */
+ send_reply(sptr, ERR_NOSUCHCHANNEL, name);
continue;
}
- chptr = get_channel(sptr, name, CGT_CREATE);
- if (chptr && (member = find_member_link(chptr, sptr)))
- {
- if (!IsZombie(member))
- continue;
-
- /* If they are a zombie, make them really part
- * and rejoin
- */
- zombie = 1;
- flags = member->status & (CHFL_DEOPPED | CHFL_SERVOPOK);
- remove_user_from_channel(sptr, chptr);
- chptr = get_channel(sptr, name, CGT_CREATE);
-
- }
-
- name = chptr->chname;
-
- if (!chptr->creationtime) /* A remote JOIN created this channel ? */
- chptr->creationtime = MAGIC_REMOTE_JOIN_TS;
-
- if (parc > 2)
- {
- if (chptr->creationtime == MAGIC_REMOTE_JOIN_TS)
- chptr->creationtime = atoi(keysOrTS);
- else
- parc = 2; /* Don't pass it on */
+#ifdef BADCHAN
+ /* BADCHANed channel */
+ if ((gline = gline_find(name, GLINE_BADCHAN | GLINE_EXACT)) &&
+ GlineIsActive(gline) && !IsAnOper(sptr)) {
+ send_reply(sptr, ERR_BADCHANNAME, name);
+ continue;
}
-
- if (!zombie)
- {
- if (sptr->flags & FLAGS_TS8)
- flags |= CHFL_SERVOPOK;
+#endif
+
+ if ((chptr = FindChannel(name))) {
+ if (find_member_link(chptr, sptr))
+ continue; /* already on channel */
+
+ flags = CHFL_DEOPPED;
+ } else
+ flags = IsModelessChannel(name) ? CHFL_DEOPPED : CHFL_CHANOP;
+
+ if (sptr->user->joined >= MAXCHANNELSPERUSER
+#ifdef OPER_NO_CHAN_LIMIT
+ /* Opers are allowed to join any number of channels */
+ && !IsAnOper(sptr)
+#endif
+ ) {
+ send_reply(sptr, ERR_TOOMANYCHANNELS, chptr ? chptr->chname : name);
+ break; /* no point processing the other channels */
}
-
- /*
- * Complete user entry to the new channel (if any)
- */
- add_user_to_channel(chptr, sptr, flags);
- /*
- * Notify all other users on the new channel
- */
- sendto_channel_butserv(chptr, sptr, ":%s JOIN :%s", parv[0], name);
-
- /* Select proper buffer; mbuf for creation, jbuf otherwise */
-
- if (*name == '&')
- continue; /* Head off local channels at the pass */
-
- bufptr = (sendcreate == 0) ? jbuf : mbuf;
- buflen = (sendcreate == 0) ? &jlen : &mlen;
- len = strlen(name);
-
- if (*buflen < BUFSIZE - len - 2)
- {
- if (*bufptr)
- {
- strcat(bufptr, ","); /* Add to join buf */
- *buflen += 1;
- }
- strncat(bufptr, name, BUFSIZE - *buflen - 1);
- *buflen += len;
+ if (chptr) {
+ if (check_target_limit(sptr, chptr, chptr->chname, 0))
+ continue; /* exceeded target limit */
+ else if ((i = can_join(sptr, chptr, keys))) {
+#ifdef OPER_WALK_THROUGH_LMODES
+ if (i > MAGIC_OPER_OVERRIDE) { /* oper overrode mode */
+ switch (i - MAGIC_OPER_OVERRIDE) {
+ case ERR_CHANNELISFULL: /* figure out which mode */
+ i = 'l';
+ break;
+
+ case ERR_INVITEONLYCHAN:
+ i = 'i';
+ break;
+
+ case ERR_BANNEDFROMCHAN:
+ i = 'b';
+ break;
+
+ case ERR_BADCHANNELKEY:
+ i = 'k';
+ break;
+ }
+
+ /* send accountability notice */
+ sendto_opmask_butone(0, SNO_HACK4, "OPER JOIN: %C JOIN %H "
+ "(overriding +%c)", sptr, chptr, i);
+ } else {
+ send_reply(sptr, i, chptr->chname);
+ continue;
+ }
+#else
+ send_reply(sptr, i, chptr->chname);
+ continue;
+#endif
+ } /* else if ((i = can_join(sptr, chptr, keys))) { */
+
+ joinbuf_join(&join, chptr, flags);
+ } else if (!(chptr = get_channel(sptr, name, CGT_CREATE)))
+ continue; /* couldn't get channel */
+ else if (check_target_limit(sptr, chptr, chptr->chname, 1)) {
+ /* Note: check_target_limit will only ever return 0 here */
+ sub1_from_channel(chptr); /* created it... */
+ continue;
+ } else
+ joinbuf_join(&create, chptr, flags);
+
+ del_invite(sptr, chptr);
+
+ if (chptr->topic[0]) {
+ send_reply(sptr, RPL_TOPIC, chptr->chname, chptr->topic);
+ send_reply(sptr, RPL_TOPICWHOTIME, chptr->chname, chptr->topic_nick,
+ chptr->topic_time);
}
- sendcreate = 0; /* Reset sendcreate */
+
+ parv[1] = name;
+ m_names(cptr, sptr, 2, parv); /* XXX find a better way */
}
- if (*jbuf) /* Propgate joins to P10 servers */
- sendto_serv_butone(cptr,
- parc > 2 ? "%s%s " TOK_JOIN " %s %s" : "%s%s " TOK_JOIN " %s", NumNick(sptr), jbuf, keysOrTS);
- if (*mbuf) /* and now creation events */
- sendto_serv_butone(cptr, "%s%s " TOK_CREATE " %s " TIME_T_FMT,
- NumNick(sptr), mbuf, TStime());
+ joinbuf_flush(&join); /* must be first, if there's a JOIN 0 */
+ joinbuf_flush(&create);
return 0;
}
-
-#if 0
/*
- * m_join
- *
- * parv[0] = sender prefix
- * parv[1] = channel
- * parv[2] = channel keys (client), or channel TS (server)
+ * ms_join - server message handler
*/
-int m_join(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
+int ms_join(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
{
- static char jbuf[BUFSIZE];
- static char mbuf[BUFSIZE];
- struct Membership* member;
- struct Channel* chptr;
- char* name;
- char* keysOrTS = NULL;
- int i = 0;
- int zombie = 0;
- int sendcreate = 0;
- unsigned int flags = 0;
- size_t jlen = 0;
- size_t mlen = 0;
- size_t* buflen;
- char* p = NULL;
- char* bufptr;
-
- /*
- * Doesn't make sense having a server join a channel, and besides
- * the server cores.
- */
- if (IsServer(sptr))
+ struct Membership *member;
+ struct Channel *chptr;
+ struct JoinBuf join;
+ struct JoinBuf create;
+ unsigned int flags = 0;
+ char *p = 0;
+ char *chanlist;
+ char *name;
+
+ if (IsServer(sptr)) {
+ Debug((DEBUG_ERROR, "%s tried to JOIN a channel", sptr->name));
return 0;
+ }
if (parc < 2 || *parv[1] == '\0')
return need_more_params(sptr, "JOIN");
- for (p = parv[1]; *p; p++) /* find the last "JOIN 0" in the line -Kev */
- if (*p == '0'
- && (*(p + 1) == ',' || *(p + 1) == '\0' || !IsChannelChar(*(p + 1))))
- {
- /* If it's a single "0", remember the place; we will start parsing
- the channels after the last 0 in the line -Kev */
- parv[1] = p;
- if (!*(p + 1))
- break;
- p++;
- }
- else
- { /* Step through to the next comma or until the
- end of the line, in an attempt to save CPU
- -Kev */
- while (*p != ',' && *p != '\0')
- p++;
- if (!*p)
- break;
- }
+ joinbuf_init(&join, sptr, cptr, JOINBUF_TYPE_JOIN, 0, 0);
+ joinbuf_init(&create, sptr, cptr, JOINBUF_TYPE_CREATE, 0, TStime());
+
+ chanlist = last0(parv[1]); /* find last "JOIN 0" */
+
+ for (name = ircd_strtok(&p, chanlist, ","); name;
+ name = ircd_strtok(&p, 0, ",")) {
+ clean_channelname(name);
- keysOrTS = parv[2]; /* Remember where our keys are or the TS is;
- parv[2] needs to be NULL for the call to
- m_names below -Kev */
- parv[2] = p = NULL;
-
- *jbuf = *mbuf = '\0'; /* clear both join and mode buffers -Kev */
- /*
- * Rebuild list of channels joined to be the actual result of the
- * JOIN. Note that "JOIN 0" is the destructive problem.
- */
- for (name = ircd_strtok(&p, parv[1], ","); name; name = ircd_strtok(&p, NULL, ","))
- {
- size_t len;
- if (MyConnect(sptr))
- clean_channelname(name);
- else if (IsLocalChannel(name))
+ if (join0(&join, cptr, sptr, name)) /* did client do a JOIN 0? */
continue;
- if (*name == '0' && *(name + 1) == '\0')
- {
- /* Remove the user from all his channels -Kev */
- while ((member = sptr->user->channel))
- {
- chptr = member->channel;
- if (!IsZombie(member))
- sendto_channel_butserv(chptr, sptr, PartFmt2,
- parv[0], chptr->chname, "Left all channels");
- remove_user_from_channel(sptr, chptr);
- }
- /* Just in case */
- *mbuf = *jbuf = '\0';
- mlen = jlen = 0;
- }
- else
- { /* not a /join 0, so treat it as
- a /join #channel -Kev */
- if (!IsChannelName(name))
- {
- if (MyUser(sptr))
- sendto_one(sptr, err_str(ERR_NOSUCHCHANNEL), me.name, parv[0], name);
- continue;
- }
-
- if (MyConnect(sptr))
- {
-#ifdef BADCHAN
- struct Gline *gline;
-
- if ((gline = gline_find(name, GLINE_BADCHAN | GLINE_EXACT)) &&
- GlineIsActive(gline) && !IsAnOper(sptr))
- {
- sendto_one(sptr, err_str(ERR_BADCHANNAME), me.name, parv[0], name);
- continue;
- }
-#endif
- /*
- * Local client is first to enter previously nonexistant
- * channel so make them (rightfully) the Channel Operator.
- * This looks kind of ugly because we try to avoid calling the strlen()
- */
- if (ChannelExists(name))
- {
- flags = CHFL_DEOPPED;
- sendcreate = 0;
- }
- else if (strlen(name) > CHANNELLEN)
- {
- *(name + CHANNELLEN) = '\0';
- if (ChannelExists(name))
- {
- flags = CHFL_DEOPPED;
- sendcreate = 0;
- }
- else
- {
- flags = IsModelessChannel(name) ? CHFL_DEOPPED : CHFL_CHANOP;
- sendcreate = 1;
- }
- }
- else
- {
- flags = IsModelessChannel(name) ? CHFL_DEOPPED : CHFL_CHANOP;
- sendcreate = 1;
- }
-#ifdef OPER_NO_CHAN_LIMIT
- /*
- * Opers are allowed to join any number of channels
- */
- if (sptr->user->joined >= MAXCHANNELSPERUSER && !IsAnOper(sptr))
-#else
- if (sptr->user->joined >= MAXCHANNELSPERUSER)
-#endif
- {
- chptr = get_channel(sptr, name, CGT_NO_CREATE);
- sendto_one(sptr, err_str(ERR_TOOMANYCHANNELS),
- me.name, parv[0], chptr ? chptr->chname : name);
- /*
- * Can't return, else he won't get on ANY channels!
- * Break out of the for loop instead. -Kev
- */
- break;
- }
- }
- chptr = get_channel(sptr, name, CGT_CREATE);
- if (chptr && (member = find_member_link(chptr, sptr)))
- {
- if (IsZombie(member))
- {
- zombie = 1;
- flags = member->status & (CHFL_DEOPPED | CHFL_SERVOPOK);
- remove_user_from_channel(sptr, chptr);
- chptr = get_channel(sptr, name, CGT_CREATE);
- }
- else
- continue;
- }
- name = chptr->chname;
- if (!chptr->creationtime) /* A remote JOIN created this channel ? */
- chptr->creationtime = MAGIC_REMOTE_JOIN_TS;
- if (parc > 2)
- {
- if (chptr->creationtime == MAGIC_REMOTE_JOIN_TS)
- chptr->creationtime = atoi(keysOrTS);
- else
- parc = 2; /* Don't pass it on */
- }
- if (!zombie)
- {
- if (!MyConnect(sptr))
- flags = CHFL_DEOPPED;
- if (sptr->flags & FLAGS_TS8)
- flags |= CHFL_SERVOPOK;
- }
- if (MyConnect(sptr))
- {
- int created = chptr->users == 0;
- if (check_target_limit(sptr, chptr, chptr->chname, created))
- {
- if (created) /* Did we create the channel? */
- sub1_from_channel(chptr); /* Remove it again! */
- continue;
- }
- if ((i = can_join(sptr, chptr, keysOrTS)))
- {
- sendto_one(sptr, err_str(i), me.name, parv[0], chptr->chname);
-#ifdef OPER_WALK_THROUGH_LMODES
- if (i > MAGIC_OPER_OVERRIDE)
- {
- switch(i - MAGIC_OPER_OVERRIDE)
- {
- case ERR_CHANNELISFULL: i = 'l'; break;
- case ERR_INVITEONLYCHAN: i = 'i'; break;
- case ERR_BANNEDFROMCHAN: i = 'b'; break;
- case ERR_BADCHANNELKEY: i = 'k'; break;
- }
- sendto_op_mask(SNO_HACK4,"OPER JOIN: %s JOIN %s (overriding +%c)",sptr->name,chptr->chname,i);
- }
- else
- continue;
-#else
- continue;
-#endif
- }
- }
- /*
- * Complete user entry to the new channel (if any)
- */
- add_user_to_channel(chptr, sptr, flags);
-
- /*
- * Notify all other users on the new channel
- */
- sendto_channel_butserv(chptr, sptr, ":%s JOIN :%s", parv[0], name);
-
- if (MyUser(sptr))
- {
- del_invite(sptr, chptr);
- if (chptr->topic[0] != '\0')
- {
- sendto_one(sptr, rpl_str(RPL_TOPIC), me.name,
- parv[0], name, chptr->topic);
- sendto_one(sptr, rpl_str(RPL_TOPICWHOTIME), me.name, parv[0], name,
- chptr->topic_nick, chptr->topic_time);
- }
- parv[1] = name;
- m_names(cptr, sptr, 2, parv);
- }
- }
+ if (IsLocalChannel(name) || !IsChannelName(name))
+ continue;
- /* Select proper buffer; mbuf for creation, jbuf otherwise */
-
- if (*name == '&')
- continue; /* Head off local channels at the pass */
-
- bufptr = (sendcreate == 0) ? jbuf : mbuf;
- buflen = (sendcreate == 0) ? &jlen : &mlen;
- len = strlen(name);
- if (*buflen < BUFSIZE - len - 2)
- {
- if (*bufptr)
- {
- strcat(bufptr, ","); /* Add to join buf */
- *buflen += 1;
- }
- strncat(bufptr, name, BUFSIZE - *buflen - 1);
- *buflen += len;
+ if ((chptr = FindChannel(name))) {
+ if ((member = find_member_link(chptr, sptr))) {
+ if (!IsZombie(member)) /* already on channel */
+ continue;
+
+ flags = member->status & (CHFL_DEOPPED | CHFL_SERVOPOK);
+ remove_user_from_channel(sptr, chptr);
+ chptr = FindChannel(name);
+ } else
+ flags = CHFL_DEOPPED | ((sptr->flags & FLAGS_TS8) ? CHFL_SERVOPOK : 0);
+ } else
+ flags = IsModelessChannel(name) ? CHFL_DEOPPED : CHFL_CHANOP;
+
+ if (chptr)
+ joinbuf_join(&join, chptr, flags);
+ /* Strange that a channel should get created by a JOIN, but as long
+ * as there are desynchs, we have to assume it's possible. Previous
+ * solutions involved sending a TS with the JOIN, but that seems
+ * unworkable to me; my solution is to transmute the JOIN into a
+ * CREATE, and let the next BURST try to fix the problem. Another
+ * solution would be to simply issue an upstream KICK, but that
+ * won't currently be accepted. Is this what DESTRUCT is for?
+ */
+ else if (!(chptr = get_channel(sptr, name, CGT_CREATE)))
+ continue; /* couldn't get channel */
+ else {
+ chptr->creationtime = TStime(); /* have to set the creation TS */
+ joinbuf_join(&create, chptr, flags);
}
- sendcreate = 0; /* Reset sendcreate */
}
- if (*jbuf) /* Propgate joins to P10 servers */
- sendto_serv_butone(cptr,
- parc > 2 ? "%s%s " TOK_JOIN " %s %s" : "%s%s " TOK_JOIN " %s", NumNick(sptr), jbuf, keysOrTS);
- if (*mbuf) /* and now creation events */
- sendto_serv_butone(cptr, "%s%s " TOK_CREATE " %s " TIME_T_FMT,
- NumNick(sptr), mbuf, TStime());
-
- if (MyUser(sptr))
- { /* shouldn't ever set TS for remote JOIN's */
- if (*jbuf)
- { /* check for channels that need TS's */
- p = NULL;
- for (name = ircd_strtok(&p, jbuf, ","); name; name = ircd_strtok(&p, NULL, ","))
- {
- chptr = get_channel(sptr, name, CGT_NO_CREATE);
- if (chptr && chptr->mode.mode & MODE_SENDTS)
- { /* send a TS? */
- sendto_serv_butone(cptr, "%s " TOK_MODE " %s + " TIME_T_FMT, NumServ(&me),
- chptr->chname, chptr->creationtime); /* ok, send TS */
- chptr->mode.mode &= ~MODE_SENDTS; /* reset flag */
- }
- }
- }
- }
+ joinbuf_flush(&join); /* must be first, if there's a JOIN 0 */
+ joinbuf_flush(&create);
+
return 0;
}
-#endif /* 0 */
*/
int m_part(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
{
- struct Channel* chptr;
- struct Membership* member;
- char* p = 0;
- char* name;
- char pbuf[BUFSIZE];
- char* comment = (parc > 2 && !EmptyString(parv[parc - 1])) ? parv[parc - 1] : 0;
-
- *pbuf = '\0'; /* Initialize the part buffer... -Kev */
+ struct Channel *chptr;
+ struct Membership *member;
+ struct JoinBuf parts;
+ char *p = 0;
+ char *name;
sptr->flags &= ~FLAGS_TS8;
+ /* check number of arguments */
if (parc < 2 || parv[1][0] == '\0')
return need_more_params(sptr, "PART");
- for (; (name = ircd_strtok(&p, parv[1], ",")); parv[1] = 0)
- {
- chptr = get_channel(sptr, name, CGT_NO_CREATE);
- if (!chptr) {
- sendto_one(sptr, err_str(ERR_NOSUCHCHANNEL), me.name, parv[0], name);
+ /* init join/part buffer */
+ joinbuf_init(&parts, sptr, cptr, JOINBUF_TYPE_PART,
+ (parc > 2 && !EmptyString(parv[parc - 1])) ? parv[parc - 1] : 0,
+ 0);
+
+ /* scan through channel list */
+ for (name = ircd_strtok(&p, parv[1], ","); name;
+ name = ircd_strtok(&p, 0, ",")) {
+
+ chptr = get_channel(sptr, name, CGT_NO_CREATE); /* look up channel */
+
+ if (!chptr) { /* complain if there isn't such a channel */
+ send_reply(sptr, ERR_NOSUCHCHANNEL, name);
continue;
}
- if (*name == '&' && !MyUser(sptr))
- continue;
- /*
- * Do not use find_channel_member here: zombies must be able to part too
- */
- if (!(member = find_member_link(chptr, sptr)))
- {
- /* Normal to get when our client did a kick
- * for a remote client (who sends back a PART),
- * so check for remote client or not --Run
- */
- if (MyUser(sptr))
- sendto_one(sptr, err_str(ERR_NOTONCHANNEL), me.name, parv[0],
- chptr->chname);
+
+ if (!(member = find_member_link(chptr, sptr))) { /* complain if not on */
+ send_reply(sptr, ERR_NOTONCHANNEL, chptr->chname);
continue;
}
- /* Recreate the /part list for sending to servers */
- if (*name != '&')
- {
- if (*pbuf)
- strcat(pbuf, ",");
- strcat(pbuf, name);
- }
- if (IsZombie(member)
- || !member_can_send_to_channel(member)) /* Returns 1 if we CAN send */
- comment = 0;
- /* Send part to all clients */
- if (!IsZombie(member))
- {
- if (comment)
- sendto_channel_butserv(chptr, sptr, PartFmt2, parv[0], chptr->chname,
- comment);
- else
- sendto_channel_butserv(chptr, sptr, PartFmt1, parv[0], chptr->chname);
- }
- else if (MyUser(sptr))
- {
- if (comment)
- sendto_one(sptr, PartFmt2, parv[0], chptr->chname, comment);
- else
- sendto_one(sptr, PartFmt1, parv[0], chptr->chname);
- }
- remove_user_from_channel(sptr, chptr);
- }
- /* Send out the parts to all servers... -Kev */
- if (*pbuf)
- {
- if (comment)
- sendto_serv_butone(cptr, PartFmt2serv, NumNick(sptr), pbuf, comment);
- else
- sendto_serv_butone(cptr, PartFmt1serv, NumNick(sptr), pbuf);
+
+ assert(!IsZombie(member)); /* Local users should never zombie */
+
+ joinbuf_join(&parts, chptr, /* part client from channel */
+ member_can_send_to_channel(member) ? 0 : CHFL_BANNED);
}
- return 0;
+
+ return joinbuf_flush(&parts); /* flush channel parts */
}
/*
*/
int ms_part(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
{
- struct Channel* chptr;
- struct Membership* member;
- char* p = 0;
- char* name;
- char pbuf[BUFSIZE];
- char* comment = (parc > 2 && !EmptyString(parv[parc - 1])) ? parv[parc - 1] : 0;
-
- *pbuf = '\0'; /* Initialize the part buffer... -Kev */
+ struct Channel *chptr;
+ struct Membership *member;
+ struct JoinBuf parts;
+ unsigned int flags;
+ char *p = 0;
+ char *name;
sptr->flags &= ~FLAGS_TS8;
+ /* check number of arguments */
if (parc < 2 || parv[1][0] == '\0')
return need_more_params(sptr, "PART");
- for (; (name = ircd_strtok(&p, parv[1], ",")); parv[1] = 0)
- {
- chptr = get_channel(sptr, name, CGT_NO_CREATE);
- if (!chptr) {
- sendto_one(sptr, err_str(ERR_NOSUCHCHANNEL), me.name, parv[0], name);
- continue;
- }
- if (*name == '&' && !MyUser(sptr))
- continue;
- /*
- * Do not use find_channel_member here: zombies must be able to part too
- */
- if (!(member = find_member_link(chptr, sptr)))
- {
- /* Normal to get when our client did a kick
- * for a remote client (who sends back a PART),
- * so check for remote client or not --Run
- */
- if (MyUser(sptr))
- sendto_one(sptr, err_str(ERR_NOTONCHANNEL), me.name, parv[0],
- chptr->chname);
- continue;
- }
- /* Recreate the /part list for sending to servers */
- if (*name != '&')
- {
- if (*pbuf)
- strcat(pbuf, ",");
- strcat(pbuf, name);
- }
- if (IsZombie(member)
- || !member_can_send_to_channel(member)) /* Returns 1 if we CAN send */
- comment = 0;
- /* Send part to all clients */
- if (!IsZombie(member))
- {
- if (comment)
- sendto_channel_butserv(chptr, sptr, PartFmt2, parv[0], chptr->chname,
- comment);
- else
- sendto_channel_butserv(chptr, sptr, PartFmt1, parv[0], chptr->chname);
- }
- else if (MyUser(sptr))
- {
- if (comment)
- sendto_one(sptr, PartFmt2, parv[0], chptr->chname, comment);
- else
- sendto_one(sptr, PartFmt1, parv[0], chptr->chname);
- }
- remove_user_from_channel(sptr, chptr);
- }
- /* Send out the parts to all servers... -Kev */
- if (*pbuf)
- {
- if (comment)
- sendto_serv_butone(cptr, PartFmt2serv, NumNick(sptr), pbuf, comment);
- else
- sendto_serv_butone(cptr, PartFmt1serv, NumNick(sptr), pbuf);
- }
- return 0;
-}
+ /* init join/part buffer */
+ joinbuf_init(&parts, sptr, cptr, JOINBUF_TYPE_PART,
+ (parc > 2 && !EmptyString(parv[parc - 1])) ? parv[parc - 1] : 0,
+ 0);
-#if 0
-/*
- * m_part
- *
- * parv[0] = sender prefix
- * parv[1] = channel
- * parv[parc - 1] = comment
- */
-int m_part(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
-{
- struct Channel* chptr;
- struct Membership* member;
- char* p = 0;
- char* name;
- char pbuf[BUFSIZE];
- char* comment = (parc > 2 && !EmptyString(parv[parc - 1])) ? parv[parc - 1] : 0;
+ /* scan through channel list */
+ for (name = ircd_strtok(&p, parv[1], ","); name;
+ name = ircd_strtok(&p, 0, ",")) {
- *pbuf = '\0'; /* Initialize the part buffer... -Kev */
+ flags = 0;
- sptr->flags &= ~FLAGS_TS8;
+ chptr = get_channel(sptr, name, CGT_NO_CREATE); /* look up channel */
- if (parc < 2 || parv[1][0] == '\0')
- return need_more_params(sptr, "PART");
+ if (!chptr || IsLocalChannel(name) ||
+ !(member = find_member_link(chptr, sptr)))
+ continue; /* ignore from remote clients */
- for (; (name = ircd_strtok(&p, parv[1], ",")); parv[1] = 0)
- {
- chptr = get_channel(sptr, name, CGT_NO_CREATE);
- if (!chptr) {
- sendto_one(sptr, err_str(ERR_NOSUCHCHANNEL), me.name, parv[0], name);
- continue;
- }
- if (*name == '&' && !MyUser(sptr))
- continue;
+ if (IsZombie(member)) /* figure out special flags... */
+ flags |= CHFL_ZOMBIE;
/*
- * Do not use find_channel_member here: zombies must be able to part too
+ * XXX BUG: If a client /part's with a part notice, on channels where
+ * he's banned, local clients will not see the part notice, but remote
+ * clients will.
*/
- if (!(member = find_member_link(chptr, sptr)))
- {
- /* Normal to get when our client did a kick
- * for a remote client (who sends back a PART),
- * so check for remote client or not --Run
- */
- if (MyUser(sptr))
- sendto_one(sptr, err_str(ERR_NOTONCHANNEL), me.name, parv[0],
- chptr->chname);
- continue;
- }
- /* Recreate the /part list for sending to servers */
- if (*name != '&')
- {
- if (*pbuf)
- strcat(pbuf, ",");
- strcat(pbuf, name);
- }
- if (IsZombie(member)
- || !member_can_send_to_channel(member)) /* Returns 1 if we CAN send */
- comment = 0;
- /* Send part to all clients */
- if (!IsZombie(member))
- {
- if (comment)
- sendto_channel_butserv(chptr, sptr, PartFmt2, parv[0], chptr->chname,
- comment);
- else
- sendto_channel_butserv(chptr, sptr, PartFmt1, parv[0], chptr->chname);
- }
- else if (MyUser(sptr))
- {
- if (comment)
- sendto_one(sptr, PartFmt2, parv[0], chptr->chname, comment);
- else
- sendto_one(sptr, PartFmt1, parv[0], chptr->chname);
- }
- remove_user_from_channel(sptr, chptr);
- }
- /* Send out the parts to all servers... -Kev */
- if (*pbuf)
- {
- if (comment)
- sendto_serv_butone(cptr, PartFmt2serv, NumNick(sptr), pbuf, comment);
- else
- sendto_serv_butone(cptr, PartFmt1serv, NumNick(sptr), pbuf);
+ if (!member_can_send_to_channel(member))
+ flags |= CHFL_BANNED;
+
+ /* part user from channel */
+ joinbuf_join(&parts, chptr, flags);
}
- return 0;
+
+ return joinbuf_flush(&parts); /* flush channel parts */
}
-#endif /* 0 */