📄 m_sjoin.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"#endifDLLFUNC 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: m_sjoin.c,v 1.1.6.8 2006/12/22 21:10:33 syzop Exp $", "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) do { modebuf[b] = x; b++; modebuf[b] = '\0'; } while(0)#define CheckStatus(x,y) do { if (modeflags & (y)) { Addit((x), nick); } } while(0)#define AddBan(x) do { strlcat(banbuf, x, sizeof banbuf); strlcat(banbuf, " ", sizeof banbuf); } while(0)#define AddEx(x) do { strlcat(exbuf, x, sizeof exbuf); strlcat(exbuf, " ", sizeof exbuf); } while(0)#define AddInvex(x) do { strlcat(invexbuf, x, sizeof invexbuf); strlcat(invexbuf, " ", sizeof invexbuf); } while(0)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[1024]; 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; char queue_s=0, queue_c=0; /* oh this is soooooo ugly :p */ 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -