mirror of
https://github.com/unrealircd/unrealircd.git
synced 2026-06-29 01:06:36 +02:00
940 lines
25 KiB
C
940 lines
25 KiB
C
/*
|
|
* IRC - Internet Relay Chat, src/modules/m_sjoin.c
|
|
* (C) 2004 The UnrealIRCd Team
|
|
*
|
|
* See file AUTHORS in IRC package for additional names of
|
|
* the programmers.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 1, or (at your option)
|
|
* any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*/
|
|
#include "config.h"
|
|
#include "struct.h"
|
|
#include "common.h"
|
|
#include "sys.h"
|
|
#include "numeric.h"
|
|
#include "msg.h"
|
|
#include "proto.h"
|
|
#include "channel.h"
|
|
#include <time.h>
|
|
#include <sys/stat.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#ifdef _WIN32
|
|
#include <io.h>
|
|
#endif
|
|
#include <fcntl.h>
|
|
#include "h.h"
|
|
#ifdef STRIPBADWORDS
|
|
#include "badwords.h"
|
|
#endif
|
|
#ifdef _WIN32
|
|
#include "version.h"
|
|
#endif
|
|
|
|
DLLFUNC int m_sjoin(aClient *cptr, aClient *sptr, int parc, char *parv[]);
|
|
|
|
#define MSG_SJOIN "SJOIN"
|
|
#define TOK_SJOIN "~"
|
|
|
|
ModuleHeader MOD_HEADER(m_sjoin)
|
|
= {
|
|
"m_sjoin",
|
|
"$Id$",
|
|
"command /sjoin",
|
|
"3.2-b8-1",
|
|
NULL
|
|
};
|
|
|
|
DLLFUNC int MOD_INIT(m_sjoin)(ModuleInfo *modinfo)
|
|
{
|
|
add_Command(MSG_SJOIN, TOK_SJOIN, m_sjoin, MAXPARA);
|
|
MARK_AS_OFFICIAL_MODULE(modinfo);
|
|
return MOD_SUCCESS;
|
|
}
|
|
|
|
DLLFUNC int MOD_LOAD(m_sjoin)(int module_load)
|
|
{
|
|
return MOD_SUCCESS;
|
|
}
|
|
|
|
DLLFUNC int MOD_UNLOAD(m_sjoin)(int module_unload)
|
|
{
|
|
if (del_Command(MSG_SJOIN, TOK_SJOIN, m_sjoin) < 0)
|
|
{
|
|
sendto_realops("Failed to delete commands when unloading %s",
|
|
MOD_HEADER(m_sjoin).name);
|
|
}
|
|
return MOD_SUCCESS;
|
|
}
|
|
|
|
typedef struct xParv aParv;
|
|
struct xParv {
|
|
int parc;
|
|
char *parv[256];
|
|
};
|
|
|
|
aParv pparv;
|
|
|
|
aParv *mp2parv(char *xmbuf, char *parmbuf)
|
|
{
|
|
int c;
|
|
char *p, *s;
|
|
|
|
pparv.parv[0] = xmbuf;
|
|
c = 1;
|
|
|
|
for (s = (char *)strtoken(&p, parmbuf, " "); s;
|
|
s = (char *)strtoken(&p, NULL, " "))
|
|
{
|
|
pparv.parv[c] = s;
|
|
c++; /* in my dreams */
|
|
}
|
|
pparv.parv[c] = NULL;
|
|
pparv.parc = c;
|
|
return (&pparv);
|
|
}
|
|
|
|
/* Checks if 2 ChanFloodProt modes (chmode +f) are different.
|
|
* This is a bit more complicated than 1 simple memcmp(a,b,..) because
|
|
* counters are also stored in this struct so we have to do
|
|
* it manually :( -- Syzop.
|
|
*/
|
|
static int compare_floodprot_modes(ChanFloodProt *a, ChanFloodProt *b)
|
|
{
|
|
if (memcmp(a->l, b->l, sizeof(a->l)) ||
|
|
memcmp(a->a, b->a, sizeof(a->a)) ||
|
|
memcmp(a->r, b->r, sizeof(a->r)))
|
|
return 1;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
** m_sjoin
|
|
**
|
|
** SJOIN will synch channels and channelmodes using the new STS1 protocol
|
|
** that is based on the EFnet TS3 protocol.
|
|
** -GZ (gz@starchat.net)
|
|
**
|
|
** Modified for UnrealIRCd by Stskeeps
|
|
** Recoded by Stskeeps
|
|
** parv[0] = sender prefix
|
|
** parv[1] aChannel *chptr;
|
|
aClient *cptr;
|
|
int parc;
|
|
u_int *pcount;
|
|
char bounce;
|
|
char *parv[], pvar[MAXMODEPARAMS][MODEBUFLEN + 3];
|
|
= channel timestamp
|
|
** parv[2] = channel name
|
|
**
|
|
** if (parc == 3)
|
|
** parv[3] = nick names + modes - all in one parameter
|
|
** if (parc == 4)
|
|
** parv[3] = channel modes
|
|
** parv[4] = nick names + modes - all in one parameter
|
|
** if (parc > 4)
|
|
** parv[3] = channel modes
|
|
** parv[4 to parc - 2] = mode parameters
|
|
** parv[parc - 1] = nick names + modes
|
|
*/
|
|
|
|
/* Some ugly macros, but useful */
|
|
#define Addit(mode,param) if ((strlen(parabuf) + strlen(param) + 11 < MODEBUFLEN) && (b <= MAXMODEPARAMS)) { \
|
|
if (*parabuf) \
|
|
strcat(parabuf, " ");\
|
|
strcat(parabuf, param);\
|
|
modebuf[b++] = mode;\
|
|
modebuf[b] = 0;\
|
|
}\
|
|
else {\
|
|
sendto_serv_butone_sjoin(cptr, ":%s MODE %s %s %s %lu", sptr->name, chptr->chname,\
|
|
modebuf, parabuf, chptr->creationtime); \
|
|
sendto_channel_butserv(chptr, sptr, ":%s MODE %s %s %s", sptr->name, chptr->chname,\
|
|
modebuf, parabuf);\
|
|
strcpy(parabuf,param);\
|
|
/* modebuf[0] should stay what it was ('+' or '-') */ \
|
|
modebuf[1] = mode;\
|
|
modebuf[2] = '\0';\
|
|
b = 2;\
|
|
}
|
|
#define Addsingle(x) modebuf[b] = x; b++; modebuf[b] = '\0'
|
|
#define CheckStatus(x,y) if (modeflags & (y)) { Addit((x), nick); }
|
|
#define AddBan(x) strlcat(banbuf, x, sizeof banbuf); strlcat(banbuf, " ", sizeof banbuf);
|
|
#define AddEx(x) strlcat(exbuf, x, sizeof exbuf); strlcat(exbuf, " ", sizeof exbuf);
|
|
#define AddInvex(x) strlcat(invexbuf, x, sizeof invexbuf); strlcat(invexbuf, " ", sizeof invexbuf);
|
|
|
|
CMD_FUNC(m_sjoin)
|
|
{
|
|
unsigned short nopara;
|
|
unsigned short nomode;
|
|
unsigned short removeours;
|
|
unsigned short removetheirs;
|
|
unsigned short merge; /* same timestamp */
|
|
char pvar[MAXMODEPARAMS][MODEBUFLEN + 3];
|
|
char paraback[1024];
|
|
#ifndef NEWCHFLOODPROT
|
|
char modeback[1024];
|
|
#endif
|
|
char banbuf[1024];
|
|
char exbuf[1024];
|
|
char invexbuf[1024];
|
|
char cbuf[1024];
|
|
char buf[1024];
|
|
char nick[NICKLEN + 1];
|
|
char *s = NULL;
|
|
aClient *acptr;
|
|
aChannel *chptr;
|
|
Member *lp;
|
|
Membership *lp2;
|
|
aParv *ap;
|
|
int pcount, i, f;
|
|
time_t ts, oldts;
|
|
unsigned short b=0,c;
|
|
Mode oldmode;
|
|
char *t, *bp, *tp, *p = NULL;
|
|
char *s0 = NULL;
|
|
long modeflags;
|
|
Ban *ban=NULL;
|
|
if (IsClient(sptr) || parc < 3 || !IsServer(sptr))
|
|
return 0;
|
|
|
|
if (!IsChannelName(parv[2]))
|
|
return 0;
|
|
|
|
merge = nopara = nomode = removeours = removetheirs = 0;
|
|
|
|
if (SupportSJOIN(cptr) && !SupportSJ3(cptr) &&
|
|
!strncmp(parv[4], "<none>", 6))
|
|
nopara = 1;
|
|
if (SupportSJOIN2(cptr) && !SupportSJ3(cptr) &&
|
|
!strncmp(parv[4], "<->", 6))
|
|
nopara = 1;
|
|
if (SupportSJ3(cptr) && (parc < 6))
|
|
nopara = 1;
|
|
|
|
if (SupportSJ3(cptr))
|
|
{
|
|
if (parc < 5)
|
|
nomode = 1;
|
|
}
|
|
else
|
|
{
|
|
if (parv[3][1] == '\0')
|
|
nomode = 1;
|
|
}
|
|
chptr = get_channel(cptr, parv[2], CREATE);
|
|
|
|
if (*parv[1] != '!')
|
|
ts = (time_t)atol(parv[1]);
|
|
else
|
|
ts = (time_t)base64dec(parv[1] + 1);
|
|
|
|
if (chptr->creationtime > ts)
|
|
{
|
|
removeours = 1;
|
|
oldts = chptr->creationtime;
|
|
chptr->creationtime = ts;
|
|
}
|
|
else if ((chptr->creationtime < ts) && (chptr->creationtime != 0))
|
|
removetheirs = 1;
|
|
else if (chptr->creationtime == ts)
|
|
merge = 1;
|
|
|
|
if (chptr->creationtime == 0)
|
|
{
|
|
oldts = -1;
|
|
chptr->creationtime = ts;
|
|
}
|
|
else
|
|
oldts = chptr->creationtime;
|
|
|
|
if (ts < 750000)
|
|
if (ts != 0)
|
|
sendto_ops
|
|
("Warning! Possible desynch: SJOIN for channel %s has a fishy timestamp (%ld) [%s/%s]",
|
|
chptr->chname, ts, sptr->name, cptr->name);
|
|
parabuf[0] = '\0';
|
|
modebuf[0] = '+';
|
|
modebuf[1] = '\0';
|
|
banbuf[0] = '\0';
|
|
exbuf[0] = '\0';
|
|
invexbuf[0] = '\0';
|
|
channel_modes(cptr, modebuf, parabuf, chptr);
|
|
if (removeours)
|
|
{
|
|
modebuf[0] = '-';
|
|
/* remove our modes if any */
|
|
if (modebuf[1] != '\0')
|
|
{
|
|
|
|
ap = mp2parv(modebuf, parabuf);
|
|
set_mode(chptr, cptr, ap->parc, ap->parv, &pcount,
|
|
pvar, 0);
|
|
sendto_serv_butone_sjoin(cptr,
|
|
":%s MODE %s %s %s %lu",
|
|
sptr->name, chptr->chname, modebuf, parabuf,
|
|
chptr->creationtime);
|
|
sendto_channel_butserv(chptr, sptr, ":%s MODE %s %s %s",
|
|
sptr->name, chptr->chname, modebuf, parabuf);
|
|
|
|
}
|
|
/* remove bans */
|
|
/* reset the buffers */
|
|
modebuf[0] = '-';
|
|
modebuf[1] = '\0';
|
|
parabuf[0] = '\0';
|
|
b = 1;
|
|
while(chptr->banlist)
|
|
{
|
|
ban = chptr->banlist;
|
|
Addit('b', ban->banstr);
|
|
chptr->banlist = ban->next;
|
|
MyFree(ban->banstr);
|
|
MyFree(ban->who);
|
|
free_ban(ban);
|
|
}
|
|
while(chptr->exlist)
|
|
{
|
|
ban = chptr->exlist;
|
|
Addit('e', ban->banstr);
|
|
chptr->exlist = ban->next;
|
|
MyFree(ban->banstr);
|
|
MyFree(ban->who);
|
|
free_ban(ban);
|
|
}
|
|
while(chptr->invexlist)
|
|
{
|
|
ban = chptr->invexlist;
|
|
Addit('I', ban->banstr);
|
|
chptr->invexlist = ban->next;
|
|
MyFree(ban->banstr);
|
|
MyFree(ban->who);
|
|
free_ban(ban);
|
|
}
|
|
for (lp = chptr->members; lp; lp = lp->next)
|
|
{
|
|
lp2 = find_membership_link(lp->cptr->user->channel, chptr);
|
|
if (!lp2)
|
|
{
|
|
sendto_realops("Oops! chptr->members && !find_membership_link");
|
|
continue;
|
|
}
|
|
if (lp->flags & MODE_CHANOWNER)
|
|
{
|
|
lp->flags &= ~MODE_CHANOWNER;
|
|
Addit('q', lp->cptr->name);
|
|
}
|
|
if (lp->flags & MODE_CHANPROT)
|
|
{
|
|
lp->flags &= ~MODE_CHANPROT;
|
|
Addit('a', lp->cptr->name);
|
|
}
|
|
if (lp->flags & MODE_CHANOP)
|
|
{
|
|
lp->flags &= ~MODE_CHANOP;
|
|
Addit('o', lp->cptr->name);
|
|
}
|
|
if (lp->flags & MODE_HALFOP)
|
|
{
|
|
lp->flags &= ~MODE_HALFOP;
|
|
Addit('h', lp->cptr->name);
|
|
}
|
|
if (lp->flags & MODE_VOICE)
|
|
{
|
|
lp->flags &= ~MODE_VOICE;
|
|
Addit('v', lp->cptr->name);
|
|
}
|
|
/* Those should always match anyways */
|
|
lp2->flags = lp->flags;
|
|
}
|
|
if (b > 1)
|
|
{
|
|
modebuf[b] = '\0';
|
|
sendto_serv_butone_sjoin(cptr,
|
|
":%s MODE %s %s %s %lu",
|
|
sptr->name, chptr->chname,
|
|
modebuf, parabuf, chptr->creationtime);
|
|
sendto_channel_butserv(chptr,
|
|
sptr, ":%s MODE %s %s %s",
|
|
sptr->name, chptr->chname, modebuf, parabuf);
|
|
|
|
}
|
|
}
|
|
/* Mode setting done :), now for our beloved clients */
|
|
parabuf[0] = 0;
|
|
modebuf[0] = '+';
|
|
modebuf[1] = '\0';
|
|
t = parv[parc - 1];
|
|
f = 1;
|
|
b = 1;
|
|
c = 0;
|
|
bp = buf;
|
|
strlcpy(cbuf, parv[parc-1], sizeof cbuf);
|
|
for (s = s0 = strtoken(&p, cbuf, " "); s; s = s0 = strtoken(&p, (char *)NULL, " "))
|
|
{
|
|
|
|
c = f = 0;
|
|
modeflags = 0;
|
|
i = 0;
|
|
tp = s;
|
|
while (
|
|
(*tp == '@') || (*tp == '+') || (*tp == '%')
|
|
|| (*tp == '*') || (*tp == '~') || (*tp == '&')
|
|
|| (*tp == '"') || (*tp == '\''))
|
|
{
|
|
switch (*(tp++))
|
|
{
|
|
case '@':
|
|
modeflags |= CHFL_CHANOP;
|
|
break;
|
|
case '%':
|
|
modeflags |= CHFL_HALFOP;
|
|
break;
|
|
case '+':
|
|
modeflags |= CHFL_VOICE;
|
|
break;
|
|
case '*':
|
|
modeflags |= CHFL_CHANOWNER;
|
|
break;
|
|
case '~':
|
|
modeflags |= CHFL_CHANPROT;
|
|
break;
|
|
case '&':
|
|
modeflags |= CHFL_BAN;
|
|
goto getnick;
|
|
break;
|
|
case '"':
|
|
modeflags |= CHFL_EXCEPT;
|
|
goto getnick;
|
|
break;
|
|
case '\'':
|
|
modeflags |= CHFL_INVEX;
|
|
goto getnick;
|
|
break;
|
|
}
|
|
}
|
|
getnick:
|
|
i = 0;
|
|
while ((*tp != ' ') && (*tp != '\0'))
|
|
nick[i++] = *(tp++); /* get nick */
|
|
nick[i] = '\0';
|
|
if (nick[0] == ' ')
|
|
continue;
|
|
if (nick[0] == '\0')
|
|
continue;
|
|
Debug((DEBUG_DEBUG, "Got nick: %s", nick));
|
|
if (!(modeflags & CHFL_BAN) && !(modeflags & CHFL_EXCEPT) && !(modeflags & CHFL_INVEX))
|
|
{
|
|
if (!(acptr = find_person(nick, NULL)))
|
|
{
|
|
sendto_snomask
|
|
(SNO_JUNK, "Missing user %s in SJOIN for %s from %s (%s)",
|
|
nick, chptr->chname, sptr->name,
|
|
backupbuf);
|
|
continue;
|
|
}
|
|
if (acptr->from != sptr->from)
|
|
{
|
|
if (IsMember(acptr, chptr))
|
|
{
|
|
/* Nick collision, don't kick or it desynchs -Griever*/
|
|
continue;
|
|
}
|
|
|
|
sendto_one(sptr,
|
|
":%s KICK %s %s :Fake direction",
|
|
me.name, chptr->chname,
|
|
acptr->name);
|
|
sendto_realops
|
|
("Fake direction from user %s in SJOIN from %s(%s) at %s",
|
|
nick, sptr->srvptr->name,
|
|
sptr->name, chptr->chname);
|
|
continue;
|
|
}
|
|
if (removetheirs)
|
|
{
|
|
modeflags = 0;
|
|
}
|
|
/* [old: temporarely added for tracing user-twice-in-channel bugs -- Syzop, 2003-01-24.]
|
|
* 2003-05-29: now traced this bug down: it's possible to get 2 joins if persons
|
|
* at 2 different servers kick a target on a 3rd server. This will require >3 servers
|
|
* most of the time but is also possible with only 3 if there's asynchronic lag.
|
|
* The general rule here (and at other places as well! see kick etc) is we ignore it
|
|
* locally (dont send a join to the chan) but propagate it to the other servers.
|
|
* I'm not sure if the propagation is needed however -- Syzop.
|
|
*/
|
|
if (IsMember(acptr, chptr)) {
|
|
#if 0
|
|
int i;
|
|
sendto_realops("[BUG] Duplicate user entry in SJOIN! Please report at http://bugs.unrealircd.org !!! Chan='%s', User='%s', modeflags=%ld",
|
|
chptr->chname ? chptr->chname : "<NULL>", acptr->name ? acptr->name : "<NULL>", modeflags);
|
|
ircd_log(LOG_ERROR, "[BUG] Duplicate user entry in SJOIN! Please report to UnrealIrcd team!! Chan='%s', User='%s', modeflags=%ld",
|
|
chptr->chname ? chptr->chname : "<NULL>", acptr->name ? acptr->name : "<NULL>", modeflags);
|
|
ircd_log(LOG_ERROR, "--- Dump of parameters ---");
|
|
for (i=0; i < parc; i++)
|
|
ircd_log(LOG_ERROR, "parv[%d] = '%s'", i, BadPtr(parv[i]) ? "<NULL-or-empty>" : parv[i]);
|
|
ircd_log(LOG_ERROR, "--- End of dump ---");
|
|
#endif
|
|
} else {
|
|
add_user_to_channel(chptr, acptr, modeflags);
|
|
RunHook4(HOOKTYPE_REMOTE_JOIN, cptr, acptr, chptr, NULL);
|
|
if (chptr->mode.mode & MODE_AUDITORIUM)
|
|
{
|
|
if (modeflags & (CHFL_CHANOP|CHFL_CHANPROT|CHFL_CHANOWNER))
|
|
sendto_channel_butserv(chptr, acptr, ":%s JOIN :%s", nick, chptr->chname);
|
|
else
|
|
sendto_chanops_butone(NULL, chptr, ":%s!%s@%s JOIN :%s",
|
|
acptr->name, acptr->user->username, GetHost(acptr), chptr->chname);
|
|
} else
|
|
sendto_channel_butserv(chptr, acptr, ":%s JOIN :%s", nick, chptr->chname);
|
|
#ifdef NEWCHFLOODPROT
|
|
if (chptr->mode.floodprot && sptr->serv->flags.synced && !IsULine(sptr))
|
|
do_chanflood(chptr->mode.floodprot, FLD_JOIN);
|
|
#endif
|
|
}
|
|
sendto_serv_butone_sjoin(cptr, ":%s JOIN %s",
|
|
nick, chptr->chname);
|
|
CheckStatus('q', CHFL_CHANOWNER);
|
|
CheckStatus('a', CHFL_CHANPROT);
|
|
CheckStatus('o', CHFL_CHANOP);
|
|
CheckStatus('h', CHFL_HALFOP);
|
|
CheckStatus('v', CHFL_VOICE);
|
|
}
|
|
else
|
|
{
|
|
if (removetheirs)
|
|
continue;
|
|
if (modeflags & CHFL_BAN)
|
|
{
|
|
f = add_listmode(&chptr->banlist, sptr, chptr, nick);
|
|
if (f != -1)
|
|
{
|
|
Addit('b', nick);
|
|
AddBan(nick);
|
|
}
|
|
}
|
|
if (modeflags & CHFL_EXCEPT)
|
|
{
|
|
f = add_listmode(&chptr->exlist, sptr, chptr, nick);
|
|
if (f != -1)
|
|
{
|
|
Addit('e', nick);
|
|
AddEx(nick);
|
|
}
|
|
}
|
|
if (modeflags & CHFL_INVEX)
|
|
{
|
|
|
|
f = add_listmode(&chptr->invexlist, sptr, chptr, nick);
|
|
if (f != -1)
|
|
{
|
|
Addit('I', nick);
|
|
AddInvex(nick);
|
|
}
|
|
}
|
|
}
|
|
docontinue:
|
|
continue;
|
|
}
|
|
|
|
if (modebuf[1])
|
|
{
|
|
modebuf[b] = '\0';
|
|
sendto_serv_butone_sjoin(cptr,
|
|
":%s MODE %s %s %s %lu",
|
|
sptr->name, chptr->chname, modebuf, parabuf,
|
|
chptr->creationtime);
|
|
sendto_channel_butserv(chptr, sptr, ":%s MODE %s %s %s",
|
|
sptr->name, chptr->chname, modebuf, parabuf);
|
|
}
|
|
|
|
if (!merge && !removetheirs && !nomode)
|
|
{
|
|
strlcpy(modebuf, parv[3], sizeof modebuf);
|
|
parabuf[0] = '\0';
|
|
if (!nopara)
|
|
for (b = 4; b <= (parc - 2); b++)
|
|
{
|
|
strlcat(parabuf, parv[b], sizeof parabuf);
|
|
strlcat(parabuf, " ", sizeof parabuf);
|
|
}
|
|
strlcpy(paraback, parabuf, sizeof paraback);
|
|
ap = mp2parv(modebuf, parabuf);
|
|
set_mode(chptr, cptr, ap->parc, ap->parv, &pcount, pvar, 0);
|
|
sendto_serv_butone_sjoin(cptr,
|
|
":%s MODE %s %s %s %lu",
|
|
sptr->name, chptr->chname, modebuf, paraback,
|
|
chptr->creationtime);
|
|
sendto_channel_butserv(chptr, sptr, ":%s MODE %s %s %s",
|
|
sptr->name, chptr->chname, modebuf, paraback);
|
|
}
|
|
if (merge && !nomode)
|
|
{
|
|
aCtab *acp;
|
|
bcopy(&chptr->mode, &oldmode, sizeof(Mode));
|
|
#ifdef EXTCMODE
|
|
/* Fun.. we have to duplicate all extended modes too... */
|
|
oldmode.extmodeparam = NULL;
|
|
oldmode.extmodeparam = extcmode_duplicate_paramlist(chptr->mode.extmodeparam);
|
|
#endif
|
|
#ifdef NEWCHFLOODPROT
|
|
if (chptr->mode.floodprot)
|
|
{
|
|
oldmode.floodprot = MyMalloc(sizeof(ChanFloodProt));
|
|
memcpy(oldmode.floodprot, chptr->mode.floodprot, sizeof(ChanFloodProt));
|
|
}
|
|
#endif
|
|
/* merge the modes */
|
|
strlcpy(modebuf, parv[3], sizeof modebuf);
|
|
parabuf[0] = '\0';
|
|
if (!nopara)
|
|
for (b = 4; b <= (parc - 2); b++)
|
|
{
|
|
strlcat(parabuf, parv[b], sizeof parabuf);
|
|
strlcat(parabuf, " ", sizeof parabuf);
|
|
}
|
|
ap = mp2parv(modebuf, parabuf);
|
|
set_mode(chptr, cptr, ap->parc, ap->parv, &pcount, pvar, 0);
|
|
|
|
/* Good, now we got modes, now for the differencing and outputting of modes
|
|
We first see if any para modes are set
|
|
|
|
*/
|
|
strlcpy(modebuf, "-", sizeof modebuf);
|
|
parabuf[0] = '\0';
|
|
b = 1;
|
|
/* however, is this really going to happen at all? may be unneeded */
|
|
if (oldmode.limit && !chptr->mode.limit)
|
|
{
|
|
Addit('l', (char *)my_itoa(oldmode.limit));
|
|
}
|
|
if (oldmode.key[0] && !chptr->mode.key[0])
|
|
{
|
|
Addit('k', oldmode.key);
|
|
}
|
|
if (oldmode.link[0] && !chptr->mode.link[0])
|
|
{
|
|
Addit('L', oldmode.link);
|
|
}
|
|
#ifdef NEWCHFLOODPROT
|
|
if (oldmode.floodprot && !chptr->mode.floodprot)
|
|
{
|
|
char *x = channel_modef_string(oldmode.floodprot);
|
|
Addit('f', x);
|
|
}
|
|
#else
|
|
if ((oldmode.msgs || oldmode.per || oldmode.kmode)
|
|
&& ((chptr->mode.msgs == 0) && (chptr->mode.per == 0)
|
|
&& (chptr->mode.kmode == 0)))
|
|
{
|
|
ircsprintf(modeback, "%s%i:%i",
|
|
(oldmode.kmode == 1 ? "*" : ""),
|
|
oldmode.msgs, oldmode.per);
|
|
Addit('f', modeback);
|
|
}
|
|
#endif
|
|
|
|
#ifdef EXTCMODE
|
|
/* First, check if we have something they don't have..
|
|
* note that: oldmode.* = us, chptr->mode.* = them.
|
|
*/
|
|
for (i=0; i <= Channelmode_highest; i++)
|
|
{
|
|
if ((Channelmode_Table[i].flag) &&
|
|
(oldmode.extmode & Channelmode_Table[i].mode) &&
|
|
!(chptr->mode.extmode & Channelmode_Table[i].mode))
|
|
{
|
|
if (Channelmode_Table[i].paracount)
|
|
{
|
|
char *parax = Channelmode_Table[i].get_param(extcmode_get_struct(oldmode.extmodeparam, Channelmode_Table[i].flag));
|
|
Addit(Channelmode_Table[i].flag, parax);
|
|
} else {
|
|
Addsingle(Channelmode_Table[i].flag);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
/* Add single char modes... */
|
|
for (acp = cFlagTab; acp->mode; acp++)
|
|
{
|
|
if ((oldmode.mode & acp->mode) &&
|
|
!(chptr->mode.mode & acp->mode) && !acp->parameters)
|
|
{
|
|
Addsingle(acp->flag);
|
|
}
|
|
}
|
|
if (b > 1)
|
|
{
|
|
Addsingle('+');
|
|
}
|
|
else
|
|
{
|
|
strlcpy(modebuf, "+", sizeof modebuf);
|
|
b = 1;
|
|
}
|
|
for (acp = cFlagTab; acp->mode; acp++)
|
|
{
|
|
if (!(oldmode.mode & acp->mode) &&
|
|
(chptr->mode.mode & acp->mode) && !acp->parameters)
|
|
{
|
|
Addsingle(acp->flag);
|
|
}
|
|
}
|
|
/* first we check if it has been set, we did unset longer up */
|
|
if (!oldmode.limit && chptr->mode.limit)
|
|
{
|
|
Addit('l', (char *)my_itoa(chptr->mode.limit));
|
|
}
|
|
if (!oldmode.key[0] && chptr->mode.key[0])
|
|
{
|
|
Addit('k', chptr->mode.key);
|
|
}
|
|
if (!oldmode.link[0] && chptr->mode.link[0])
|
|
{
|
|
Addit('L', chptr->mode.link);
|
|
}
|
|
#ifdef NEWCHFLOODPROT
|
|
if (chptr->mode.floodprot && !oldmode.floodprot)
|
|
{
|
|
char *x = channel_modef_string(chptr->mode.floodprot);
|
|
Addit('f', x);
|
|
}
|
|
#else
|
|
if (!(oldmode.msgs || oldmode.per || oldmode.kmode)
|
|
&& (chptr->mode.msgs || chptr->mode.per
|
|
|| chptr->mode.kmode))
|
|
{
|
|
ircsprintf(modeback, "%s%i:%i",
|
|
(chptr->mode.kmode == 1 ? "*" : ""),
|
|
chptr->mode.msgs, chptr->mode.per);
|
|
Addit('f', modeback);
|
|
}
|
|
#endif
|
|
|
|
#ifdef EXTCMODE
|
|
/* Now, check if they have something we don't have..
|
|
* note that: oldmode.* = us, chptr->mode.* = them.
|
|
*/
|
|
for (i=0; i <= Channelmode_highest; i++)
|
|
{
|
|
if ((Channelmode_Table[i].flag) &&
|
|
!(oldmode.extmode & Channelmode_Table[i].mode) &&
|
|
(chptr->mode.extmode & Channelmode_Table[i].mode))
|
|
{
|
|
if (Channelmode_Table[i].paracount)
|
|
{
|
|
char *parax = Channelmode_Table[i].get_param(extcmode_get_struct(chptr->mode.extmodeparam,Channelmode_Table[i].flag));
|
|
Addit(Channelmode_Table[i].flag, parax);
|
|
} else {
|
|
Addsingle(Channelmode_Table[i].flag);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/* now, if we had diffent para modes - this loop really could be done better, but */
|
|
|
|
/* do we have an difference? */
|
|
if (oldmode.limit && chptr->mode.limit
|
|
&& (oldmode.limit != chptr->mode.limit))
|
|
{
|
|
chptr->mode.limit =
|
|
MAX(oldmode.limit, chptr->mode.limit);
|
|
if (oldmode.limit != chptr->mode.limit)
|
|
{
|
|
Addit('l', (char *)my_itoa(chptr->mode.limit));
|
|
}
|
|
}
|
|
/* sketch, longest key wins */
|
|
if (oldmode.key[0] && chptr->mode.key[0]
|
|
&& strcmp(oldmode.key, chptr->mode.key))
|
|
{
|
|
if (strcmp(oldmode.key, chptr->mode.key) > 0)
|
|
{
|
|
strlcpy(chptr->mode.key, oldmode.key, sizeof chptr->mode.key);
|
|
}
|
|
else
|
|
{
|
|
Addit('k', chptr->mode.key);
|
|
}
|
|
}
|
|
/* same as above (except case insensitive #test == #TEST -- codemastr) */
|
|
if (oldmode.link[0] && chptr->mode.link[0]
|
|
&& stricmp(oldmode.link, chptr->mode.link))
|
|
{
|
|
if (strcmp(oldmode.link, chptr->mode.link) > 0)
|
|
{
|
|
strlcpy(chptr->mode.link, oldmode.link, sizeof(chptr->mode.link));
|
|
}
|
|
else
|
|
{
|
|
Addit('L', chptr->mode.link);
|
|
}
|
|
}
|
|
/*
|
|
* run a max on each?
|
|
*/
|
|
#ifdef NEWCHFLOODPROT
|
|
if (chptr->mode.floodprot && oldmode.floodprot)
|
|
{
|
|
char *x;
|
|
int i;
|
|
|
|
if (compare_floodprot_modes(chptr->mode.floodprot, oldmode.floodprot))
|
|
{
|
|
chptr->mode.floodprot->per = MAX(chptr->mode.floodprot->per, oldmode.floodprot->per);
|
|
for (i=0; i < NUMFLD; i++)
|
|
{
|
|
chptr->mode.floodprot->l[i] = MAX(chptr->mode.floodprot->l[i], oldmode.floodprot->l[i]);
|
|
chptr->mode.floodprot->a[i] = MAX(chptr->mode.floodprot->a[i], oldmode.floodprot->a[i]);
|
|
chptr->mode.floodprot->r[i] = MAX(chptr->mode.floodprot->r[i], oldmode.floodprot->r[i]);
|
|
}
|
|
x = channel_modef_string(chptr->mode.floodprot);
|
|
Addit('f', x);
|
|
}
|
|
}
|
|
#else
|
|
if ((oldmode.kmode != chptr->mode.kmode)
|
|
|| (oldmode.msgs != chptr->mode.msgs)
|
|
|| (oldmode.per != chptr->mode.per))
|
|
{
|
|
chptr->mode.kmode =
|
|
MAX(chptr->mode.kmode, oldmode.kmode);
|
|
chptr->mode.msgs = MAX(chptr->mode.msgs, oldmode.msgs);
|
|
chptr->mode.per = MAX(chptr->mode.per, oldmode.per);
|
|
if ((oldmode.kmode != chptr->mode.kmode)
|
|
|| (oldmode.msgs != chptr->mode.msgs)
|
|
|| (oldmode.per != chptr->mode.per))
|
|
{
|
|
ircsprintf(modeback, "%s%i:%i",
|
|
(chptr->mode.kmode == 1 ? "*" : ""),
|
|
chptr->mode.msgs, chptr->mode.per);
|
|
Addit('f', modeback);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifdef EXTCMODE
|
|
/* Now, check for any param differences in extended channel modes..
|
|
* note that: oldmode.* = us, chptr->mode.* = them.
|
|
* if we win: copy oldmode to chptr mode, if they win: send the mode
|
|
*/
|
|
for (i=0; i <= Channelmode_highest; i++)
|
|
{
|
|
if (Channelmode_Table[i].flag && Channelmode_Table[i].paracount &&
|
|
(oldmode.extmode & Channelmode_Table[i].mode) &&
|
|
(chptr->mode.extmode & Channelmode_Table[i].mode))
|
|
{
|
|
int r;
|
|
char *parax;
|
|
CmodeParam *ourm = extcmode_get_struct(oldmode.extmodeparam,Channelmode_Table[i].flag);
|
|
CmodeParam *theirm = extcmode_get_struct(chptr->mode.extmodeparam, Channelmode_Table[i].flag);
|
|
|
|
r = Channelmode_Table[i].sjoin_check(chptr, ourm, theirm);
|
|
switch (r)
|
|
{
|
|
case EXSJ_WEWON:
|
|
{
|
|
CmodeParam *r;
|
|
parax = Channelmode_Table[i].get_param(ourm);
|
|
Debug((DEBUG_DEBUG, "sjoin: we won: '%s'", parax));
|
|
r = Channelmode_Table[i].put_param(theirm, parax);
|
|
if (r != theirm) /* confusing eh ;) */
|
|
AddListItem(r, chptr->mode.extmodeparam);
|
|
break;
|
|
}
|
|
case EXSJ_THEYWON:
|
|
parax = Channelmode_Table[i].get_param(theirm);
|
|
Debug((DEBUG_DEBUG, "sjoin: they won: '%s'", parax));
|
|
Addit(Channelmode_Table[i].flag, parax);
|
|
break;
|
|
case EXSJ_SAME:
|
|
Debug((DEBUG_DEBUG, "sjoin: equal"));
|
|
break;
|
|
default:
|
|
ircd_log(LOG_ERROR, "channel.c:m_sjoin:param diff checker: got unk. retval 0x%x??", r);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
Addsingle('\0');
|
|
|
|
if (modebuf[1])
|
|
{
|
|
sendto_serv_butone_sjoin(cptr,
|
|
":%s MODE %s %s %s %lu",
|
|
sptr->name, chptr->chname, modebuf, parabuf,
|
|
chptr->creationtime);
|
|
sendto_channel_butserv(chptr, sptr, ":%s MODE %s %s %s",
|
|
sptr->name, chptr->chname, modebuf, parabuf);
|
|
}
|
|
#ifdef EXTCMODE
|
|
/* free the oldmode.* crap :( */
|
|
extcmode_free_paramlist(oldmode.extmodeparam);
|
|
oldmode.extmodeparam = NULL; /* just to be sure ;) */
|
|
#endif
|
|
#ifdef NEWCHFLOODPROT
|
|
/* and the oldmode.floodprot struct too... :/ */
|
|
if (oldmode.floodprot)
|
|
{
|
|
free(oldmode.floodprot);
|
|
oldmode.floodprot = NULL;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/* we should be synched by now, */
|
|
if (oldts != -1)
|
|
if (oldts != chptr->creationtime)
|
|
sendto_channel_butserv(chptr, &me,
|
|
":%s NOTICE %s :*** Notice -- TS for %s changed from %ld to %ld",
|
|
me.name, chptr->chname, chptr->chname,
|
|
oldts, chptr->creationtime);
|
|
|
|
|
|
strlcpy(parabuf, "", sizeof parabuf);
|
|
for (i = 2; i <= (parc - 2); i++)
|
|
{
|
|
if (!parv[i])
|
|
{
|
|
sendto_ops("Got null parv in SJ3 code");
|
|
continue;
|
|
}
|
|
strlcat(parabuf, parv[i], sizeof parabuf);
|
|
if (((i + 1) <= (parc - 2)))
|
|
strlcat(parabuf, " ", sizeof parabuf);
|
|
}
|
|
if (!chptr->users)
|
|
{
|
|
sub1_from_channel(chptr);
|
|
return -1;
|
|
}
|
|
/* This sends out to SJ3 servers .. */
|
|
Debug((DEBUG_DEBUG, "Sending '%li %s :%s' to sj3-!sjb64", ts, parabuf,
|
|
parv[parc - 1]));
|
|
sendto_serv_butone_token_opt(cptr, OPT_SJOIN | OPT_SJ3 | OPT_NOT_SJB64, sptr->name,
|
|
MSG_SJOIN, TOK_SJOIN, "%li %s :%s", ts, parabuf, parv[parc - 1]);
|
|
Debug((DEBUG_DEBUG, "Sending '%B %s :%s' to sj3-sjb64", ts, parabuf,
|
|
parv[parc - 1]));
|
|
sendto_serv_butone_token_opt(cptr, OPT_SJOIN | OPT_SJ3 | OPT_SJB64, sptr->name,
|
|
MSG_SJOIN, TOK_SJOIN, "%B %s :%s", ts, parabuf, parv[parc - 1]);
|
|
|
|
return 0;
|
|
}
|