📄 m_mode.c
字号:
/* * IRC - Internet Relay Chat, src/modules/m_mode.c * (C) 2005 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 "macros.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/* Forward declarations */DLLFUNC CMD_FUNC(m_mode);DLLFUNC void _do_mode(aChannel *chptr, aClient *cptr, aClient *sptr, int parc, char *parv[], time_t sendts, int samode);DLLFUNC void _set_mode(aChannel *chptr, aClient *cptr, int parc, char *parv[], u_int *pcount, char pvar[MAXMODEPARAMS][MODEBUFLEN + 3], int bounce);DLLFUNC CMD_FUNC(_m_umode);/* local: */static void bounce_mode(aChannel *, aClient *, int, char **);int do_mode_char(aChannel *chptr, long modetype, char modechar, char *param, u_int what, aClient *cptr, u_int *pcount, char pvar[MAXMODEPARAMS][MODEBUFLEN + 3], char bounce, long my_access);int do_extmode_char(aChannel *chptr, int modeindex, char *param, u_int what, aClient *cptr, u_int *pcount, char pvar[MAXMODEPARAMS][MODEBUFLEN + 3], char bounce);#ifdef EXTCMODEvoid make_mode_str(aChannel *chptr, long oldm, Cmode_t oldem, long oldl, int pcount, char pvar[MAXMODEPARAMS][MODEBUFLEN + 3], char *mode_buf, char *para_buf, char bounce);#elsevoid make_mode_str(aChannel *chptr, long oldm, long oldl, int pcount, char pvar[MAXMODEPARAMS][MODEBUFLEN + 3], char *mode_buf, char *para_buf, char bounce);#endifstatic void mode_cutoff(char *s);static int samode_in_progress = 0;#define MSG_MODE "MODE" #define TOK_MODE "G" ModuleHeader MOD_HEADER(m_mode) = { "m_mode", "$Id: m_mode.c,v 1.1.4.5 2006/12/22 21:10:33 syzop Exp $", "command /mode", "3.2-b8-1", NULL };DLLFUNC int MOD_TEST(m_mode)(ModuleInfo *modinfo){ MARK_AS_OFFICIAL_MODULE(modinfo); EfunctionAddVoid(modinfo->handle, EFUNC_DO_MODE, _do_mode); EfunctionAddVoid(modinfo->handle, EFUNC_SET_MODE, _set_mode); EfunctionAdd(modinfo->handle, EFUNC_M_UMODE, _m_umode); return MOD_SUCCESS;}DLLFUNC int MOD_INIT(m_mode)(ModuleInfo *modinfo){ CommandAdd(modinfo->handle, MSG_MODE, TOK_MODE, m_mode, MAXPARA, M_USER|M_SERVER); MARK_AS_OFFICIAL_MODULE(modinfo); return MOD_SUCCESS;}DLLFUNC int MOD_LOAD(m_mode)(int module_load){ return MOD_SUCCESS;}DLLFUNC int MOD_UNLOAD(m_mode)(int module_unload){ return MOD_SUCCESS;}/* * m_mode -- written by binary (garryb@binary.islesfan.net) * Completely rewrote it. The old mode command was 820 lines of ICKY * coding, which is a complete waste, because I wrote it in 570 lines of * *decent* coding. This is also easier to read, change, and fine-tune. Plus, * everything isn't scattered; everything's grouped where it should be. * * parv[0] - sender * parv[1] - channel */CMD_FUNC(m_mode){ long unsigned sendts = 0; Ban *ban; aChannel *chptr; /* Now, try to find the channel in question */ if (parc > 1) { if (*parv[1] == '#') { chptr = find_channel(parv[1], NullChn); if (chptr == NullChn) { return m_umode(cptr, sptr, parc, parv); } } else return m_umode(cptr, sptr, parc, parv); } else { sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "MODE"); return 0; } if (MyConnect(sptr)) clean_channelname(parv[1]); if (check_channelmask(sptr, cptr, parv[1])) return 0; if (parc < 3) { *modebuf = *parabuf = '\0'; modebuf[1] = '\0'; channel_modes(sptr, modebuf, parabuf, chptr); sendto_one(sptr, rpl_str(RPL_CHANNELMODEIS), me.name, parv[0], chptr->chname, modebuf, parabuf); sendto_one(sptr, rpl_str(RPL_CREATIONTIME), me.name, parv[0], chptr->chname, chptr->creationtime); return 0; } if (IsPerson(sptr) && parc < 4 && ((*parv[2] == 'b' && parv[2][1] == '\0') || (parv[2][1] == 'b' && parv[2][2] == '\0' && (*parv[2] == '+' || *parv[2] == '-')))) { if (!IsMember(sptr, chptr) && !IsAnOper(sptr)) return 0; /* send ban list */ for (ban = chptr->banlist; ban; ban = ban->next) sendto_one(sptr, rpl_str(RPL_BANLIST), me.name, sptr->name, chptr->chname, ban->banstr, ban->who, ban->when); sendto_one(cptr, rpl_str(RPL_ENDOFBANLIST), me.name, sptr->name, chptr->chname); return 0; } if (IsPerson(sptr) && parc < 4 && ((*parv[2] == 'e' && parv[2][1] == '\0') || (parv[2][1] == 'e' && parv[2][2] == '\0' && (*parv[2] == '+' || *parv[2] == '-')))) { if (!IsMember(sptr, chptr) && !IsAnOper(sptr)) return 0; /* send exban list */ for (ban = chptr->exlist; ban; ban = ban->next) sendto_one(sptr, rpl_str(RPL_EXLIST), me.name, sptr->name, chptr->chname, ban->banstr, ban->who, ban->when); sendto_one(cptr, rpl_str(RPL_ENDOFEXLIST), me.name, sptr->name, chptr->chname); return 0; } if (IsPerson(sptr) && parc < 4 && ((*parv[2] == 'q' && parv[2][1] == '\0') || (parv[2][1] == 'q' && parv[2][2] == '\0' && (*parv[2] == '+' || *parv[2] == '-')))) { if (!IsMember(sptr, chptr) && !IsAnOper(sptr)) return 0; { Member *member; /* send chanowner list */ /* [Whole story about bad loops removed, sorry ;)] * Now rewritten so it works (was: bad logic) -- Syzop */ for (member = chptr->members; member; member = member->next) { if (is_chanowner(member->cptr, chptr)) sendto_one(sptr, rpl_str(RPL_QLIST), me.name, sptr->name, chptr->chname, member->cptr->name); } sendto_one(cptr, rpl_str(RPL_ENDOFQLIST), me.name, sptr->name, chptr->chname); return 0; } } if (IsPerson(sptr) && parc < 4 && ((*parv[2] == 'a' && parv[2][1] == '\0') || (parv[2][1] == 'a' && parv[2][2] == '\0' && (*parv[2] == '+' || *parv[2] == '-')))) { if (!IsMember(sptr, chptr) && !IsAnOper(sptr)) return 0; { Member *member; /* send chanowner list */ /* [Whole story about bad loops removed, sorry ;)] * Now rewritten so it works (was: bad logic) -- Syzop */ for (member = chptr->members; member; member = member->next) { if (is_chanprot(member->cptr, chptr)) sendto_one(sptr, rpl_str(RPL_ALIST), me.name, sptr->name, chptr->chname, member->cptr->name); } sendto_one(cptr, rpl_str(RPL_ENDOFALIST), me.name, sptr->name, chptr->chname); return 0; } } if (IsPerson(sptr) && parc < 4 && ((*parv[2] == 'I' && parv[2][1] == '\0') || (parv[2][1] == 'I' && parv[2][2] == '\0' && (*parv[2] == '+' || *parv[2] == '-')))) { if (!IsMember(sptr, chptr) && !IsAnOper(sptr)) return 0; for (ban = chptr->invexlist; ban; ban = ban->next) sendto_one(sptr, rpl_str(RPL_INVEXLIST), me.name, sptr->name, chptr->chname, ban->banstr, ban->who, ban->when); sendto_one(sptr, rpl_str(RPL_ENDOFINVEXLIST), me.name, sptr->name, chptr->chname); return 0; } opermode = 0;#ifndef NO_OPEROVERRIDE if (IsPerson(sptr) && !IsULine(sptr) && !is_chan_op(sptr, chptr) && !is_half_op(sptr, chptr) && (MyClient(sptr) ? (IsOper(sptr) && OPCanOverride(sptr)) : IsOper(sptr))) { sendts = 0; opermode = 1; goto aftercheck; } if (IsPerson(sptr) && !IsULine(sptr) && !is_chan_op(sptr, chptr) && is_half_op(sptr, chptr) && (MyClient(sptr) ? (IsOper(sptr) && OPCanOverride(sptr)) : IsOper(sptr))) { opermode = 2; goto aftercheck; }#endif if (IsPerson(sptr) && !IsULine(sptr) && !is_chan_op(sptr, chptr) && !is_half_op(sptr, chptr) && (cptr == sptr || !IsSAdmin(sptr) || !IsOper(sptr))) { if (cptr == sptr) { sendto_one(sptr, err_str(ERR_CHANOPRIVSNEEDED), me.name, parv[0], chptr->chname); return 0; } sendto_one(cptr, ":%s MODE %s -oh %s %s 0", me.name, chptr->chname, parv[0], parv[0]); /* Tell the other server that the user is * de-opped. Fix op desyncs. */ bounce_mode(chptr, cptr, parc - 2, parv + 2); return 0; } if (IsServer(sptr) && (sendts = TS2ts(parv[parc - 1])) && !IsULine(sptr) && chptr->creationtime && sendts > chptr->creationtime) { if (!(*parv[2] == '&')) /* & denotes a bounce */ { /* !!! */ sendto_snomask(SNO_EYES, "*** TS bounce for %s - %lu(ours) %lu(theirs)", chptr->chname, chptr->creationtime, sendts); bounce_mode(chptr, cptr, parc - 2, parv + 2); } return 0; } if (IsServer(sptr) && !sendts && *parv[parc - 1] != '0') sendts = -1; if (IsServer(sptr) && sendts != -1) parc--; /* server supplied a time stamp, remove it now */ aftercheck:/* if (IsPerson(sptr) && IsOper(sptr)) { if (!is_chan_op(sptr, chptr)) { if (MyClient(sptr) && !IsULine(cptr) && mode_buf[1]) sendto_snomask(SNO_EYES, "*** OperMode [IRCop: %s] - [Channel: %s] - [Mode: %s %s]", sptr->name, chptr->chname, mode_buf, parabuf); sendts = 0; } } */ /* This is to prevent excess +<whatever> modes. -- Syzop */ if (MyClient(sptr) && parv[2]) mode_cutoff(parv[2]); /* Filter out the unprivileged FIRST. * * Now, we can actually do the mode. */ (void)do_mode(chptr, cptr, sptr, parc - 2, parv + 2, sendts, 0); opermode = 0; /* Important since sometimes forgotten. -- Syzop */ return 0;}/** Cut off mode string (eg: +abcdfjkdsgfgs) at MAXMODEPARAMS modes. * @param s The mode string (modes only, no parameters) * @notes Should only used on local clients * @author Syzop */static void mode_cutoff(char *s){unsigned short modesleft = MAXMODEPARAMS * 2; /* be generous... */ for (; *s && modesleft; s++) if ((*s != '-') && (*s != '+')) modesleft--; *s = '\0';}/* bounce_mode -- written by binary * User or server is NOT authorized to change the mode. This takes care * of making the bounce string and bounce it. Because of the 1 for the bounce * param (last param) of the calls to set_mode and make_mode_str, it will not * set the mode, but create the bounce string. */static void bounce_mode(aChannel *chptr, aClient *cptr, int parc, char *parv[]){ char pvar[MAXMODEPARAMS][MODEBUFLEN + 3]; int pcount; set_mode(chptr, cptr, parc, parv, &pcount, pvar, 1); if (chptr->creationtime) sendto_one(cptr, ":%s MODE %s &%s %s %lu", me.name, chptr->chname, modebuf, parabuf, chptr->creationtime); else sendto_one(cptr, ":%s MODE %s &%s %s", me.name, chptr->chname, modebuf, parabuf); /* the '&' denotes a bounce so servers won't bounce a bounce */}/* do_mode -- written by binary * User or server is authorized to do the mode. This takes care of * setting the mode and relaying it to other users and servers. */DLLFUNC void _do_mode(aChannel *chptr, aClient *cptr, aClient *sptr, int parc, char *parv[], time_t sendts, int samode){ char pvar[MAXMODEPARAMS][MODEBUFLEN + 3]; int pcount; char tschange = 0, isbounce = 0; /* fwd'ing bounce */ if (**parv == '&') isbounce = 1; /* Please keep the next 3 lines next to each other */ samode_in_progress = samode; set_mode(chptr, sptr, parc, parv, &pcount, pvar, 0); samode_in_progress = 0; if (IsServer(sptr)) { if (sendts > 0) { if (!chptr->creationtime || sendts < chptr->creationtime) { tschange = 1;/* if (chptr->creationtime != 0) sendto_snomask(SNO_EYES, "*** TS fix for %s - %lu(ours) %lu(theirs)", chptr->chname, chptr->creationtime, sendts); */ chptr->creationtime = sendts;#if 0 if (sendts < 750000) sendto_realops( "Warning! Possible desynch: MODE for channel %s ('%s %s') has fishy timestamp (%ld) (from %s/%s)" chptr->chname, modebuf, parabuf, sendts, cptr->name, sptr->name);#endif /* new chan or our timestamp is wrong */ /* now works for double-bounce prevention */ } if (sendts > chptr->creationtime && chptr->creationtime) { /* theirs is wrong but we let it pass anyway */ sendts = chptr->creationtime; sendto_one(cptr, ":%s MODE %s + %lu", me.name, chptr->chname, chptr->creationtime); } } if (sendts == -1 && chptr->creationtime) sendts = chptr->creationtime; } if (*modebuf == '\0' || (*(modebuf + 1) == '\0' && (*modebuf == '+' || *modebuf == '-'))) { if (tschange || isbounce) { /* relay bounce time changes */ if (chptr->creationtime) sendto_serv_butone_token(cptr, me.name, MSG_MODE, TOK_MODE, "%s %s+ %lu", chptr->chname, isbounce ? "&" : "", chptr->creationtime); else sendto_serv_butone_token(cptr, me.name, MSG_MODE, TOK_MODE, "%s %s+ ", chptr->chname, isbounce ? "&" : ""); return; /* nothing to send */ } } /* opermode for twimodesystem --sts */#ifndef NO_OPEROVERRIDE if (opermode == 1) { if (modebuf[1]) sendto_snomask(SNO_EYES, "*** OperOverride -- %s (%s@%s) MODE %s %s %s", sptr->name, sptr->user->username, sptr->user->realhost, chptr->chname, modebuf, parabuf); /* Logging Implementation added by XeRXeS */ ircd_log(LOG_OVERRIDE,"OVERRIDE: %s (%s@%s) MODE %s %s %s", sptr->name, sptr->user->username, sptr->user->realhost, chptr->chname, modebuf, parabuf); sendts = 0; }#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -