shit shit shit. cvs didnt add core modules, and I deleted what I had already done.
Time to redo them
This commit is contained in:
parent
f44ee87a91
commit
72729d1cda
13 changed files with 5051 additions and 0 deletions
12
.gitattributes
vendored
12
.gitattributes
vendored
|
@ -322,6 +322,18 @@ messages/translations/ircd-swedish.po -text
|
|||
modules/.cvsignore -text
|
||||
modules/.depend -text
|
||||
modules/Makefile.in -text
|
||||
modules/core/descrip.mms -text
|
||||
modules/core/m_die.c -text
|
||||
modules/core/m_kick.c -text
|
||||
modules/core/m_kill.c -text
|
||||
modules/core/m_message.c -text
|
||||
modules/core/m_mode.c -text
|
||||
modules/core/m_nick.c -text
|
||||
modules/core/m_part.c -text
|
||||
modules/core/m_quit.c -text
|
||||
modules/core/m_server.c -text
|
||||
modules/core/m_sjoin.c -text
|
||||
modules/core/m_squit.c -text
|
||||
modules/descrip.mms -text
|
||||
modules/m_accept.c -text
|
||||
modules/m_admin.c -text
|
||||
|
|
18
modules/core/descrip.mms
Normal file
18
modules/core/descrip.mms
Normal file
|
@ -0,0 +1,18 @@
|
|||
# MMS/MMK Makefile for OpenVMS
|
||||
# Copyright (c) 2001 Edward Brocklesby
|
||||
# $Id: descrip.mms,v 1.1 2002/08/14 05:47:41 fishwaldo Exp $
|
||||
|
||||
CC= CC
|
||||
CFLAGS= /INCLUDE_DIRECTORY=([-.-.INCLUDE],[-.-.ADNS])/STANDARD=ISOC94
|
||||
LDFLAGS=
|
||||
|
||||
OBJECTS= M_DIE.OBJ,M_KICK.OBJ,M_KILL.OBJ,M_MESSAGE.OBJ,M_MODE.OBJ,M_NICK.OBJ,-
|
||||
M_PART.OBJ,M_QUIT.OBJ,M_SERVER.OBJ,M_SJOIN.OBJ,M_SQUIT.OBJ
|
||||
|
||||
ALL : CORE.OLB($(OBJECTS))
|
||||
COPY CORE.OLB [-]
|
||||
|
||||
CLEAN :
|
||||
DELETE *.OLB;*
|
||||
DELETE *.OBJ;*
|
||||
|
123
modules/core/m_die.c
Normal file
123
modules/core/m_die.c
Normal file
|
@ -0,0 +1,123 @@
|
|||
/*
|
||||
* ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
|
||||
* m_die.c: Kills off this server.
|
||||
*
|
||||
* Copyright (C) 2002 by the past and present ircd coders, and others.
|
||||
*
|
||||
* 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 2 of the License, 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
* USA
|
||||
*
|
||||
* $Id: m_die.c,v 1.1 2002/08/14 05:47:41 fishwaldo Exp $
|
||||
*/
|
||||
|
||||
#include "stdinc.h"
|
||||
#include "tools.h"
|
||||
#include "handlers.h"
|
||||
#include "client.h"
|
||||
#include "ircd.h"
|
||||
#include "irc_string.h"
|
||||
#include "numeric.h"
|
||||
#include "fdlist.h"
|
||||
#include "s_bsd.h"
|
||||
#include "s_log.h"
|
||||
#include "s_conf.h"
|
||||
#include "send.h"
|
||||
#include "msg.h"
|
||||
#include "parse.h"
|
||||
#include "modules.h"
|
||||
|
||||
static void mo_die(struct Client*, struct Client*, int, char**);
|
||||
|
||||
struct Message die_msgtab = {
|
||||
"DIE", 0, 0, 1, 0, MFLG_SLOW, 0,
|
||||
{m_unregistered, m_not_oper, m_ignore, mo_die}
|
||||
};
|
||||
#ifndef STATIC_MODULES
|
||||
void
|
||||
_modinit(void)
|
||||
{
|
||||
mod_add_cmd(&die_msgtab);
|
||||
}
|
||||
|
||||
void
|
||||
_moddeinit(void)
|
||||
{
|
||||
mod_del_cmd(&die_msgtab);
|
||||
}
|
||||
|
||||
const char *_version = "$Revision: 1.1 $";
|
||||
#endif
|
||||
/*
|
||||
* mo_die - DIE command handler
|
||||
*/
|
||||
static void mo_die(struct Client *client_p, struct Client *source_p,
|
||||
int parc, char *parv[])
|
||||
{
|
||||
struct Client* target_p;
|
||||
dlink_node *ptr;
|
||||
|
||||
if (!IsOperDie(source_p))
|
||||
{
|
||||
sendto_one(source_p,":%s NOTICE %s :You need die = yes;", me.name, parv[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
if (parc < 2)
|
||||
{
|
||||
sendto_one(source_p,":%s NOTICE %s :Need server name /die %s",
|
||||
me.name,source_p->name,me.name);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (irccmp(parv[1], me.name))
|
||||
{
|
||||
sendto_one(source_p,":%s NOTICE %s :Mismatch on /die %s",
|
||||
me.name,source_p->name,me.name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for(ptr = lclient_list.head; ptr; ptr = ptr->next)
|
||||
{
|
||||
target_p = ptr->data;
|
||||
|
||||
sendto_one(target_p,
|
||||
":%s NOTICE %s :Server Terminating. %s",
|
||||
me.name, target_p->name,
|
||||
get_client_name(source_p, HIDE_IP));
|
||||
}
|
||||
|
||||
for(ptr = serv_list.head; ptr; ptr = ptr->next)
|
||||
{
|
||||
target_p = ptr->data;
|
||||
|
||||
sendto_one(target_p, ":%s ERROR :Terminated by %s",
|
||||
me.name, get_client_name(source_p, HIDE_IP));
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX we called flush_connections() here. Read server_reboot()
|
||||
* for an explanation as to what we should do.
|
||||
* -- adrian
|
||||
*/
|
||||
ilog(L_NOTICE, "Server terminated by %s", get_oper_name(source_p));
|
||||
/*
|
||||
* this is a normal exit, tell the os it's ok
|
||||
*/
|
||||
exit(0);
|
||||
/* NOT REACHED */
|
||||
}
|
||||
|
255
modules/core/m_kick.c
Normal file
255
modules/core/m_kick.c
Normal file
|
@ -0,0 +1,255 @@
|
|||
/*
|
||||
* ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
|
||||
* m_kick.c: Kicks a user from a channel.
|
||||
*
|
||||
* Copyright (C) 2002 by the past and present ircd coders, and others.
|
||||
*
|
||||
* 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 2 of the License, 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
* USA
|
||||
*
|
||||
* $Id: m_kick.c,v 1.1 2002/08/14 05:47:41 fishwaldo Exp $
|
||||
*/
|
||||
|
||||
#include "stdinc.h"
|
||||
#include "tools.h"
|
||||
#include "handlers.h"
|
||||
#include "channel.h"
|
||||
#include "channel_mode.h"
|
||||
#include "vchannel.h"
|
||||
#include "client.h"
|
||||
#include "irc_string.h"
|
||||
#include "ircd.h"
|
||||
#include "numeric.h"
|
||||
#include "send.h"
|
||||
#include "msg.h"
|
||||
#include "modules.h"
|
||||
#include "parse.h"
|
||||
#include "hash.h"
|
||||
|
||||
|
||||
static void m_kick(struct Client*, struct Client*, int, char**);
|
||||
static void ms_kick(struct Client*, struct Client*, int, char**);
|
||||
|
||||
struct Message kick_msgtab = {
|
||||
"KICK", 0, 0, 3, 0, MFLG_SLOW, 0,
|
||||
{m_unregistered, m_kick, ms_kick, m_kick}
|
||||
};
|
||||
#ifndef STATIC_MODULES
|
||||
void
|
||||
_modinit(void)
|
||||
{
|
||||
mod_add_cmd(&kick_msgtab);
|
||||
}
|
||||
|
||||
void
|
||||
_moddeinit(void)
|
||||
{
|
||||
mod_del_cmd(&kick_msgtab);
|
||||
}
|
||||
|
||||
const char *_version = "$Revision: 1.1 $";
|
||||
#endif
|
||||
/*
|
||||
** m_kick
|
||||
** parv[0] = sender prefix
|
||||
** parv[1] = channel
|
||||
** parv[2] = client to kick
|
||||
** parv[3] = kick comment
|
||||
*/
|
||||
static void m_kick(struct Client *client_p,
|
||||
struct Client *source_p,
|
||||
int parc,
|
||||
char *parv[])
|
||||
{
|
||||
struct Client *who;
|
||||
struct Channel *chptr;
|
||||
#ifdef VCHANS
|
||||
struct Channel *vchan;
|
||||
#endif
|
||||
int chasing = 0;
|
||||
char *comment;
|
||||
char *name;
|
||||
char *p = (char *)NULL;
|
||||
char *user;
|
||||
static char buf[BUFSIZE];
|
||||
|
||||
if (*parv[2] == '\0')
|
||||
{
|
||||
sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
|
||||
me.name, parv[0], "KICK");
|
||||
return;
|
||||
}
|
||||
|
||||
comment = (BadPtr(parv[3])) ? parv[2] : parv[3];
|
||||
if (strlen(comment) > (size_t) TOPICLEN)
|
||||
comment[TOPICLEN] = '\0';
|
||||
|
||||
*buf = '\0';
|
||||
if( (p = strchr(parv[1],',')) )
|
||||
*p = '\0';
|
||||
|
||||
name = parv[1];
|
||||
|
||||
chptr = hash_find_channel(name);
|
||||
if (!chptr)
|
||||
{
|
||||
sendto_one(source_p, form_str(ERR_NOSUCHCHANNEL),
|
||||
me.name, parv[0], name);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef VCHANS
|
||||
if (HasVchans(chptr))
|
||||
{
|
||||
vchan = map_vchan(chptr,source_p);
|
||||
if(vchan != 0)
|
||||
{
|
||||
chptr = vchan;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!IsServer(source_p) && !is_any_op(chptr, source_p) )
|
||||
{
|
||||
/* was a user, not a server, and user isn't seen as a chanop here */
|
||||
|
||||
if(MyConnect(source_p))
|
||||
{
|
||||
/* user on _my_ server, with no chanops.. so go away */
|
||||
|
||||
sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED),
|
||||
me.name, parv[0], name);
|
||||
return;
|
||||
}
|
||||
|
||||
if(chptr->channelts == 0)
|
||||
{
|
||||
/* If its a TS 0 channel, do it the old way */
|
||||
|
||||
sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED),
|
||||
me.name, parv[0], name);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Its a user doing a kick, but is not showing as chanop locally
|
||||
* its also not a user ON -my- server, and the channel has a TS.
|
||||
* There are two cases we can get to this point then...
|
||||
*
|
||||
* 1) connect burst is happening, and for some reason a legit
|
||||
* op has sent a KICK, but the SJOIN hasn't happened yet or
|
||||
* been seen. (who knows.. due to lag...)
|
||||
*
|
||||
* 2) The channel is desynced. That can STILL happen with TS
|
||||
*
|
||||
* Now, the old code roger wrote, would allow the KICK to
|
||||
* go through. Thats quite legit, but lets weird things like
|
||||
* KICKS by users who appear not to be chanopped happen,
|
||||
* or even neater, they appear not to be on the channel.
|
||||
* This fits every definition of a desync, doesn't it? ;-)
|
||||
* So I will allow the KICK, otherwise, things are MUCH worse.
|
||||
* But I will warn it as a possible desync.
|
||||
*
|
||||
* -Dianora
|
||||
*/
|
||||
}
|
||||
|
||||
if( (p = strchr(parv[2],',')) )
|
||||
*p = '\0';
|
||||
|
||||
user = parv[2]; /* strtoken(&p2, parv[2], ","); */
|
||||
|
||||
if (!(who = find_chasing(source_p, user, &chasing)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsMember(who, chptr))
|
||||
{
|
||||
/* half ops cannot kick full chanops */
|
||||
#ifdef HALFOPS
|
||||
if (is_half_op(chptr,source_p) && is_any_op(chptr,who))
|
||||
{
|
||||
sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED),
|
||||
me.name, parv[0], name);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
/* jdc
|
||||
* - In the case of a server kicking a user (i.e. CLEARCHAN),
|
||||
* the kick should show up as coming from the server which did
|
||||
* the kick.
|
||||
* - Personally, flame and I believe that server kicks shouldn't
|
||||
* be sent anyways. Just waiting for some oper to abuse it...
|
||||
*/
|
||||
if (IsServer(source_p))
|
||||
{
|
||||
sendto_channel_local(ALL_MEMBERS, chptr, ":%s KICK %s %s :%s",
|
||||
source_p->name, name, who->name, comment);
|
||||
}
|
||||
#ifdef ANONOPS
|
||||
else if(chptr->mode.mode & MODE_HIDEOPS)
|
||||
{
|
||||
/* jdc -- Non-chanops get kicked from me.name, not
|
||||
* who->name (themselves).
|
||||
*/
|
||||
sendto_channel_local(NON_CHANOPS, chptr,
|
||||
":%s KICK %s %s :%s",
|
||||
me.name,
|
||||
name, who->name, comment);
|
||||
|
||||
sendto_channel_local(ONLY_CHANOPS_HALFOPS, chptr,
|
||||
":%s!%s@%s KICK %s %s :%s",
|
||||
source_p->name,
|
||||
source_p->username,
|
||||
source_p->host,
|
||||
name,
|
||||
who->name, comment);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
sendto_channel_local(ALL_MEMBERS, chptr,
|
||||
":%s!%s@%s KICK %s %s :%s",
|
||||
source_p->name,
|
||||
source_p->username,
|
||||
source_p->host,
|
||||
name, who->name, comment);
|
||||
}
|
||||
|
||||
sendto_server(client_p, NULL, chptr, NOCAPS, NOCAPS, NOFLAGS,
|
||||
":%s KICK %s %s :%s",
|
||||
parv[0], chptr->chname,
|
||||
who->name, comment);
|
||||
remove_user_from_channel(chptr, who);
|
||||
}
|
||||
else
|
||||
sendto_one(source_p, form_str(ERR_USERNOTINCHANNEL),
|
||||
me.name, parv[0], user, name);
|
||||
}
|
||||
|
||||
static void ms_kick(struct Client *client_p,
|
||||
struct Client *source_p,
|
||||
int parc,
|
||||
char *parv[])
|
||||
{
|
||||
if (*parv[2] == '\0')
|
||||
{
|
||||
sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
|
||||
me.name, parv[0], "KICK");
|
||||
return;
|
||||
}
|
||||
|
||||
m_kick(client_p, source_p, parc, parv);
|
||||
}
|
368
modules/core/m_kill.c
Normal file
368
modules/core/m_kill.c
Normal file
|
@ -0,0 +1,368 @@
|
|||
/*
|
||||
* ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
|
||||
* m_kill.c: Kills a user.
|
||||
*
|
||||
* Copyright (C) 2002 by the past and present ircd coders, and others.
|
||||
*
|
||||
* 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 2 of the License, 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
* USA
|
||||
*
|
||||
* $Id: m_kill.c,v 1.1 2002/08/14 05:47:41 fishwaldo Exp $
|
||||
*/
|
||||
|
||||
#include "stdinc.h"
|
||||
#include "handlers.h"
|
||||
#include "client.h"
|
||||
#include "hash.h" /* for find_client() */
|
||||
#include "ircd.h"
|
||||
#include "numeric.h"
|
||||
#include "s_log.h"
|
||||
#include "s_serv.h"
|
||||
#include "s_conf.h"
|
||||
#include "send.h"
|
||||
#include "whowas.h"
|
||||
#include "irc_string.h"
|
||||
#include "msg.h"
|
||||
#include "parse.h"
|
||||
#include "modules.h"
|
||||
|
||||
|
||||
static char buf[BUFSIZE];
|
||||
|
||||
static void ms_kill(struct Client*, struct Client*, int, char**);
|
||||
static void mo_kill(struct Client*, struct Client*, int, char**);
|
||||
static void relay_kill(struct Client *, struct Client *, struct Client *,
|
||||
const char *, const char *);
|
||||
|
||||
struct Message kill_msgtab = {
|
||||
"KILL", 0, 0, 2, 0, MFLG_SLOW, 0,
|
||||
{m_unregistered, m_not_oper, ms_kill, mo_kill}
|
||||
};
|
||||
#ifndef STATIC_MODULES
|
||||
|
||||
void
|
||||
_modinit(void)
|
||||
{
|
||||
mod_add_cmd(&kill_msgtab);
|
||||
}
|
||||
|
||||
void
|
||||
_moddeinit(void)
|
||||
{
|
||||
mod_del_cmd(&kill_msgtab);
|
||||
}
|
||||
|
||||
const char *_version = "$Revision: 1.1 $";
|
||||
#endif
|
||||
/*
|
||||
** mo_kill
|
||||
** parv[0] = sender prefix
|
||||
** parv[1] = kill victim
|
||||
** parv[2] = kill path
|
||||
*/
|
||||
static void mo_kill(struct Client *client_p, struct Client *source_p,
|
||||
int parc, char *parv[])
|
||||
{
|
||||
struct Client* target_p;
|
||||
const char* inpath = client_p->name;
|
||||
char* user;
|
||||
char* reason;
|
||||
|
||||
user = parv[1];
|
||||
reason = parv[2]; /* Either defined or NULL (parc >= 2!!) */
|
||||
|
||||
if (!IsOperGlobalKill(source_p))
|
||||
{
|
||||
sendto_one(source_p,":%s NOTICE %s :You need global_kill = yes;",me.name,parv[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!BadPtr(reason))
|
||||
{
|
||||
if(strlen(reason) > (size_t) KILLLEN)
|
||||
reason[KILLLEN] = '\0';
|
||||
}
|
||||
else
|
||||
reason = "<No reason given>";
|
||||
|
||||
if ((target_p = find_client(user)) == NULL)
|
||||
{
|
||||
/*
|
||||
** If the user has recently changed nick, automatically
|
||||
** rewrite the KILL for this new nickname--this keeps
|
||||
** servers in synch when nick change and kill collide
|
||||
*/
|
||||
if ((target_p = get_history(user, (long)KILLCHASETIMELIMIT)) == NULL)
|
||||
{
|
||||
sendto_one(source_p, form_str(ERR_NOSUCHNICK),
|
||||
me.name, parv[0], user);
|
||||
return;
|
||||
}
|
||||
sendto_one(source_p,":%s NOTICE %s :KILL changed from %s to %s",
|
||||
me.name, parv[0], user, target_p->name);
|
||||
}
|
||||
if (IsServer(target_p) || IsMe(target_p))
|
||||
{
|
||||
sendto_one(source_p, form_str(ERR_CANTKILLSERVER),
|
||||
me.name, parv[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!MyConnect(target_p) && (!IsOperGlobalKill(source_p)))
|
||||
{
|
||||
sendto_one(source_p, ":%s NOTICE %s :Nick %s isnt on your server",
|
||||
me.name, parv[0], target_p->name);
|
||||
return;
|
||||
}
|
||||
|
||||
if(MyConnect(target_p))
|
||||
sendto_one(target_p, ":%s!%s@%s KILL %s :%s",
|
||||
source_p->name, source_p->username, source_p->host,
|
||||
target_p->name, reason);
|
||||
|
||||
/* Do not change the format of this message. There's no point in changing messages
|
||||
* that have been around for ever, for no reason.. */
|
||||
sendto_realops_flags(FLAGS_ALL, L_ALL,
|
||||
"Received KILL message for %s. From %s Path: %s (%s)",
|
||||
target_p->name, parv[0], me.name, reason);
|
||||
|
||||
ilog(L_INFO,"KILL From %s For %s Path %s (%s)",
|
||||
parv[0], target_p->name, me.name, reason);
|
||||
|
||||
|
||||
/*
|
||||
** And pass on the message to other servers. Note, that if KILL
|
||||
** was changed, the message has to be sent to all links, also
|
||||
** back.
|
||||
** Suicide kills are NOT passed on --SRB
|
||||
*/
|
||||
if (!MyConnect(target_p))
|
||||
{
|
||||
relay_kill(client_p, source_p, target_p, inpath, reason);
|
||||
/*
|
||||
** Set FLAGS_KILLED. This prevents exit_one_client from sending
|
||||
** the unnecessary QUIT for this. (This flag should never be
|
||||
** set in any other place)
|
||||
*/
|
||||
target_p->flags |= FLAGS_KILLED;
|
||||
}
|
||||
|
||||
ircsprintf(buf, "Killed (%s (%s))", source_p->name, reason);
|
||||
|
||||
exit_client(client_p, target_p, source_p, buf);
|
||||
}
|
||||
|
||||
/*
|
||||
* ms_kill
|
||||
* parv[0] = sender prefix
|
||||
* parv[1] = kill victim
|
||||
* parv[2] = kill path and reason
|
||||
*/
|
||||
static void ms_kill(struct Client *client_p, struct Client *source_p,
|
||||
int parc, char *parv[])
|
||||
{
|
||||
struct Client *target_p;
|
||||
char *user;
|
||||
char *reason;
|
||||
char *path;
|
||||
int chasing = 0;
|
||||
|
||||
*buf = '\0';
|
||||
|
||||
if (*parv[1] == '\0')
|
||||
{
|
||||
sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
|
||||
me.name, parv[0], "KILL");
|
||||
return;
|
||||
}
|
||||
|
||||
user = parv[1];
|
||||
|
||||
if(BadPtr(parv[2]))
|
||||
{
|
||||
reason = "<No reason given>";
|
||||
|
||||
/* hyb6 takes the nick of the killer from the path *sigh* --fl_ */
|
||||
path = source_p->name;
|
||||
}
|
||||
else
|
||||
{
|
||||
reason = strchr(parv[2], ' ');
|
||||
|
||||
if(reason)
|
||||
{
|
||||
*reason = '\0';
|
||||
reason++;
|
||||
}
|
||||
else
|
||||
reason = "<No reason given>";
|
||||
|
||||
path = parv[2];
|
||||
}
|
||||
|
||||
if ((target_p = find_client(user)) == NULL)
|
||||
{
|
||||
/*
|
||||
* If the user has recently changed nick, but only if its
|
||||
* not an uid, automatically rewrite the KILL for this new nickname.
|
||||
* --this keeps servers in synch when nick change and kill collide
|
||||
*/
|
||||
if( (*user == '.') ||
|
||||
(!(target_p = get_history(user, (long)KILLCHASETIMELIMIT))))
|
||||
{
|
||||
sendto_one(source_p, form_str(ERR_NOSUCHNICK),
|
||||
me.name, parv[0], user);
|
||||
return;
|
||||
}
|
||||
sendto_one(source_p,":%s NOTICE %s :KILL changed from %s to %s",
|
||||
me.name, parv[0], user, target_p->name);
|
||||
chasing = 1;
|
||||
}
|
||||
|
||||
if (IsServer(target_p) || IsMe(target_p))
|
||||
{
|
||||
sendto_one(source_p, form_str(ERR_CANTKILLSERVER),
|
||||
me.name, parv[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
if(MyConnect(target_p))
|
||||
{
|
||||
if(IsServer(source_p))
|
||||
{
|
||||
/* dont send clients kills from a hidden server */
|
||||
if(ConfigServerHide.hide_servers && !IsOper(target_p))
|
||||
sendto_one(target_p, ":%s KILL %s :%s",
|
||||
me.name, target_p->name, reason);
|
||||
else
|
||||
sendto_one(target_p, ":%s KILL %s :%s",
|
||||
source_p->name, target_p->name, reason);
|
||||
}
|
||||
else
|
||||
sendto_one(target_p, ":%s!%s@%s KILL %s :%s",
|
||||
source_p->name, source_p->username, source_p->host,
|
||||
target_p->name, reason);
|
||||
}
|
||||
|
||||
/* Be warned, this message must be From %s, or it confuses clients
|
||||
* so dont change it to From: or the case or anything! -- fl -- db */
|
||||
if (IsOper(source_p)) /* send it normally */
|
||||
{
|
||||
sendto_realops_flags(FLAGS_ALL, L_ALL,
|
||||
"Received KILL message for %s. From %s Path: %s %s",
|
||||
target_p->name, parv[0], source_p->user->server, reason);
|
||||
}
|
||||
else
|
||||
{
|
||||
sendto_realops_flags(FLAGS_SKILL, L_ALL,
|
||||
"Received KILL message for %s. From %s %s",
|
||||
target_p->name, parv[0], reason);
|
||||
}
|
||||
|
||||
ilog(L_INFO,"KILL From %s For %s Path %s %s",
|
||||
parv[0], target_p->name, parv[0], reason);
|
||||
|
||||
relay_kill(client_p, source_p, target_p, path, reason);
|
||||
|
||||
/* FLAGS_KILLED prevents a quit being sent out */
|
||||
target_p->flags |= FLAGS_KILLED;
|
||||
|
||||
/* reason comes supplied with its own ()'s */
|
||||
if(ConfigServerHide.hide_servers && IsServer(source_p))
|
||||
ircsprintf(buf, "Killed (%s %s)", me.name, reason);
|
||||
else
|
||||
ircsprintf(buf, "Killed (%s %s)", source_p->name, reason);
|
||||
|
||||
exit_client(client_p, target_p, source_p, buf);
|
||||
}
|
||||
|
||||
static void relay_kill(struct Client *one, struct Client *source_p,
|
||||
struct Client *target_p,
|
||||
const char *inpath,
|
||||
const char *reason)
|
||||
{
|
||||
dlink_node *ptr;
|
||||
struct Client *client_p;
|
||||
int introduce_killed_client;
|
||||
char* user;
|
||||
|
||||
/* LazyLinks:
|
||||
* Check if each lazylink knows about target_p.
|
||||
* If it does, send the kill, introducing source_p if required.
|
||||
* If it doesn't either:
|
||||
* a) don't send the kill (risk ghosts)
|
||||
* b) introduce the client (and source_p, if required)
|
||||
* [rather redundant]
|
||||
*
|
||||
* Use a) if IsServer(source_p), but if an oper kills someone,
|
||||
* ensure we blow away any ghosts.
|
||||
*
|
||||
* -davidt
|
||||
*/
|
||||
|
||||
if(IsServer(source_p))
|
||||
introduce_killed_client = 0;
|
||||
else
|
||||
introduce_killed_client = 1;
|
||||
|
||||
for( ptr = serv_list.head; ptr; ptr = ptr->next )
|
||||
{
|
||||
client_p = (struct Client *) ptr->data;
|
||||
|
||||
if( !client_p || client_p == one )
|
||||
continue;
|
||||
|
||||
if( !introduce_killed_client )
|
||||
{
|
||||
if( ServerInfo.hub && IsCapable(client_p, CAP_LL) )
|
||||
{
|
||||
if(((client_p->localClient->serverMask &
|
||||
target_p->lazyLinkClientExists) == 0))
|
||||
{
|
||||
/* target isn't known to lazy leaf, skip it */
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* force introduction of killed client but check that
|
||||
* its not on the server we're bursting too.. */
|
||||
else if(strcmp(target_p->user->server,client_p->name))
|
||||
client_burst_if_needed(client_p, target_p);
|
||||
|
||||
/* introduce source of kill */
|
||||
client_burst_if_needed(client_p, source_p);
|
||||
|
||||
/* check the server supports UID */
|
||||
if (IsCapable(client_p, CAP_UID))
|
||||
user = ID(target_p);
|
||||
else
|
||||
user = target_p->name;
|
||||
|
||||
if(MyClient(source_p))
|
||||
{
|
||||
sendto_one(client_p, ":%s KILL %s :%s!%s!%s!%s (%s)",
|
||||
source_p->name, user,
|
||||
me.name, source_p->host, source_p->username,
|
||||
source_p->name, reason);
|
||||
}
|
||||
else
|
||||
{
|
||||
sendto_one(client_p, ":%s KILL %s :%s %s",
|
||||
source_p->name, user,
|
||||
inpath, reason);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
931
modules/core/m_message.c
Normal file
931
modules/core/m_message.c
Normal file
|
@ -0,0 +1,931 @@
|
|||
/*
|
||||
* ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
|
||||
* m_message.c: Sends a (PRIVMSG|NOTICE) message to a user or channel.
|
||||
*
|
||||
* Copyright (C) 2002 by the past and present ircd coders, and others.
|
||||
*
|
||||
* 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 2 of the License, 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
* USA
|
||||
*
|
||||
* $Id: m_message.c,v 1.1 2002/08/14 05:47:41 fishwaldo Exp $
|
||||
*/
|
||||
|
||||
#include "stdinc.h"
|
||||
#include "handlers.h"
|
||||
#include "client.h"
|
||||
#include "ircd.h"
|
||||
#include "numeric.h"
|
||||
#include "common.h"
|
||||
#include "s_conf.h"
|
||||
#include "s_serv.h"
|
||||
#include "send.h"
|
||||
#include "msg.h"
|
||||
#include "parse.h"
|
||||
#include "modules.h"
|
||||
|
||||
#include "channel.h"
|
||||
#include "channel_mode.h"
|
||||
#include "vchannel.h"
|
||||
#include "irc_string.h"
|
||||
#include "hash.h"
|
||||
#include "class.h"
|
||||
#include "msg.h"
|
||||
#include "packet.h"
|
||||
|
||||
|
||||
struct entity
|
||||
{
|
||||
void *ptr;
|
||||
int type;
|
||||
int flags;
|
||||
};
|
||||
|
||||
static int build_target_list(int p_or_n, char *command,
|
||||
struct Client *client_p,
|
||||
struct Client *source_p,
|
||||
char *nicks_channels, char *text);
|
||||
|
||||
static int flood_attack_client(int p_or_n, struct Client *source_p,
|
||||
struct Client *target_p);
|
||||
static int flood_attack_channel(int p_or_n, struct Client *source_p,
|
||||
struct Channel *chptr, char *chname);
|
||||
static struct Client* find_userhost (char *, char *, int *);
|
||||
|
||||
#define ENTITY_NONE 0
|
||||
#define ENTITY_CHANNEL 1
|
||||
#define ENTITY_CHANOPS_ON_CHANNEL 2
|
||||
#define ENTITY_CLIENT 3
|
||||
|
||||
static struct entity targets[512];
|
||||
static int ntargets = 0;
|
||||
|
||||
static int duplicate_ptr(void *);
|
||||
|
||||
static void m_message(int, char *, struct Client *,
|
||||
struct Client *, int, char **);
|
||||
|
||||
static void m_privmsg(struct Client *, struct Client *, int, char **);
|
||||
static void m_notice(struct Client *, struct Client *, int, char **);
|
||||
|
||||
static void msg_channel(int p_or_n, char *command,
|
||||
struct Client *client_p,
|
||||
struct Client *source_p,
|
||||
struct Channel *chptr, char *text);
|
||||
|
||||
static void msg_channel_flags(int p_or_n, char *command,
|
||||
struct Client *client_p,
|
||||
struct Client *source_p,
|
||||
struct Channel *chptr, int flags, char *text);
|
||||
|
||||
static void msg_client(int p_or_n, char *command,
|
||||
struct Client *source_p, struct Client *target_p,
|
||||
char *text);
|
||||
|
||||
static void handle_opers(int p_or_n, char *command,
|
||||
struct Client *client_p,
|
||||
struct Client *source_p, char *nick, char *text);
|
||||
|
||||
struct Message privmsg_msgtab = {
|
||||
"PRIVMSG", 0, 0, 1, 0, MFLG_SLOW | MFLG_UNREG, 0L,
|
||||
{m_unregistered, m_privmsg, m_privmsg, m_privmsg}
|
||||
};
|
||||
|
||||
struct Message notice_msgtab = {
|
||||
"NOTICE", 0, 0, 1, 0, MFLG_SLOW, 0L,
|
||||
{m_unregistered, m_notice, m_notice, m_notice}
|
||||
};
|
||||
|
||||
#ifndef STATIC_MODULES
|
||||
|
||||
void
|
||||
_modinit(void)
|
||||
{
|
||||
mod_add_cmd(&privmsg_msgtab);
|
||||
mod_add_cmd(¬ice_msgtab);
|
||||
}
|
||||
|
||||
void
|
||||
_moddeinit(void)
|
||||
{
|
||||
mod_del_cmd(&privmsg_msgtab);
|
||||
mod_del_cmd(¬ice_msgtab);
|
||||
}
|
||||
|
||||
const char *_version = "$Revision: 1.1 $";
|
||||
#endif
|
||||
|
||||
/*
|
||||
** m_privmsg
|
||||
**
|
||||
** massive cleanup
|
||||
** rev argv 6/91
|
||||
**
|
||||
** Another massive cleanup Nov, 2000
|
||||
** (I don't think there is a single line left from 6/91. Maybe.)
|
||||
** m_privmsg and m_notice do basically the same thing.
|
||||
** in the original 2.8.2 code base, they were the same function
|
||||
** "m_message.c." When we did the great cleanup in conjuncton with bleep
|
||||
** of ircu fame, we split m_privmsg.c and m_notice.c.
|
||||
** I don't see the point of that now. Its harder to maintain, its
|
||||
** easier to introduce bugs into one version and not the other etc.
|
||||
** Really, the penalty of an extra function call isn't that big a deal folks.
|
||||
** -db Nov 13, 2000
|
||||
**
|
||||
*/
|
||||
|
||||
#define PRIVMSG 0
|
||||
#define NOTICE 1
|
||||
|
||||
static void
|
||||
m_privmsg(struct Client *client_p,
|
||||
struct Client *source_p, int parc, char *parv[])
|
||||
{
|
||||
/* servers have no reason to send privmsgs, yet sometimes there is cause
|
||||
* for a notice.. (for example remote kline replies) --fl_
|
||||
*/
|
||||
if (!IsPerson(source_p))
|
||||
return;
|
||||
|
||||
m_message(PRIVMSG, "PRIVMSG", client_p, source_p, parc, parv);
|
||||
}
|
||||
|
||||
static void
|
||||
m_notice(struct Client *client_p,
|
||||
struct Client *source_p, int parc, char *parv[])
|
||||
{
|
||||
m_message(NOTICE, "NOTICE", client_p, source_p, parc, parv);
|
||||
}
|
||||
|
||||
/*
|
||||
* inputs - flag privmsg or notice
|
||||
* - pointer to command "PRIVMSG" or "NOTICE"
|
||||
* - pointer to client_p
|
||||
* - pointer to source_p
|
||||
* - pointer to channel
|
||||
*/
|
||||
static void
|
||||
m_message(int p_or_n,
|
||||
char *command,
|
||||
struct Client *client_p,
|
||||
struct Client *source_p, int parc, char *parv[])
|
||||
{
|
||||
int i;
|
||||
|
||||
if (parc < 2 || *parv[1] == '\0')
|
||||
{
|
||||
if (p_or_n != NOTICE)
|
||||
sendto_one(source_p, form_str(ERR_NORECIPIENT), me.name,
|
||||
source_p->name, command);
|
||||
return;
|
||||
}
|
||||
|
||||
if (parc < 3 || *parv[2] == '\0')
|
||||
{
|
||||
if (p_or_n != NOTICE)
|
||||
sendto_one(source_p, form_str(ERR_NOTEXTTOSEND), me.name,
|
||||
source_p->name);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Finish the flood grace period... */
|
||||
if(MyClient(source_p) && !IsFloodDone(source_p))
|
||||
flood_endgrace(source_p);
|
||||
|
||||
if (build_target_list(p_or_n, command, client_p, source_p, parv[1],
|
||||
parv[2]) < 0)
|
||||
{
|
||||
/* Sigh. We need to relay this command to the hub */
|
||||
if (!ServerInfo.hub && (uplink != NULL))
|
||||
sendto_one(uplink, ":%s %s %s :%s",
|
||||
source_p->name, command, parv[1], parv[2]);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < ntargets; i++)
|
||||
{
|
||||
switch (targets[i].type)
|
||||
{
|
||||
case ENTITY_CHANNEL:
|
||||
msg_channel(p_or_n, command, client_p, source_p,
|
||||
(struct Channel *)targets[i].ptr, parv[2]);
|
||||
break;
|
||||
|
||||
case ENTITY_CHANOPS_ON_CHANNEL:
|
||||
msg_channel_flags(p_or_n, command, client_p, source_p,
|
||||
(struct Channel *)targets[i].ptr,
|
||||
targets[i].flags, parv[2]);
|
||||
break;
|
||||
|
||||
case ENTITY_CLIENT:
|
||||
msg_client(p_or_n, command, source_p,
|
||||
(struct Client *)targets[i].ptr, parv[2]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* build_target_list
|
||||
*
|
||||
* inputs - pointer to given client_p (server)
|
||||
* - pointer to given source (oper/client etc.)
|
||||
* - pointer to list of nicks/channels
|
||||
* - pointer to table to place results
|
||||
* - pointer to text (only used if source_p is an oper)
|
||||
* output - number of valid entities
|
||||
* side effects - target_table is modified to contain a list of
|
||||
* pointers to channels or clients
|
||||
* if source client is an oper
|
||||
* all the classic old bizzare oper privmsg tricks
|
||||
* are parsed and sent as is, if prefixed with $
|
||||
* to disambiguate.
|
||||
*
|
||||
*/
|
||||
|
||||
static int
|
||||
build_target_list(int p_or_n, char *command, struct Client *client_p,
|
||||
struct Client *source_p, char *nicks_channels,
|
||||
char *text)
|
||||
{
|
||||
int type;
|
||||
char *p, *nick, *target_list, ncbuf[BUFSIZE];
|
||||
struct Channel *chptr=NULL;
|
||||
struct Client *target_p;
|
||||
|
||||
/* Sigh, we can't mutilate parv[1] incase we need it to send to a hub */
|
||||
if (!ServerInfo.hub && (uplink != NULL) && IsCapable(uplink, CAP_LL))
|
||||
{
|
||||
strncpy(ncbuf, nicks_channels, BUFSIZE);
|
||||
target_list = ncbuf;
|
||||
}
|
||||
else
|
||||
target_list = nicks_channels; /* skip strcpy for non-lazyleafs */
|
||||
|
||||
ntargets = 0;
|
||||
|
||||
for (nick = strtoken(&p, target_list, ","); nick;
|
||||
nick = strtoken(&p, (char *)NULL, ","))
|
||||
{
|
||||
char *with_prefix;
|
||||
/*
|
||||
* channels are privmsg'd a lot more than other clients, moved up
|
||||
* here plain old channel msg?
|
||||
*/
|
||||
|
||||
if (IsChanPrefix(*nick))
|
||||
{
|
||||
/* ignore send of local channel to a server (should not happen) */
|
||||
if (IsServer(client_p) && *nick == '&')
|
||||
continue;
|
||||
|
||||
if ((chptr = hash_find_channel(nick)) != NULL)
|
||||
{
|
||||
if (!duplicate_ptr(chptr))
|
||||
{
|
||||
if (ntargets >= ConfigFileEntry.max_targets)
|
||||
{
|
||||
sendto_one(source_p, form_str(ERR_TOOMANYTARGETS),
|
||||
me.name, source_p->name, nick);
|
||||
return (1);
|
||||
}
|
||||
targets[ntargets].ptr = (void *)chptr;
|
||||
targets[ntargets++].type = ENTITY_CHANNEL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!ServerInfo.hub && (uplink != NULL) && IsCapable(uplink, CAP_LL))
|
||||
return -1;
|
||||
else if (p_or_n != NOTICE)
|
||||
sendto_one(source_p, form_str(ERR_NOSUCHNICK), me.name,
|
||||
source_p->name, nick);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
/* look for a privmsg to another client */
|
||||
if ((target_p = find_person(nick)) != NULL)
|
||||
{
|
||||
if (!duplicate_ptr(target_p))
|
||||
{
|
||||
if (ntargets >= ConfigFileEntry.max_targets)
|
||||
{
|
||||
sendto_one(source_p, form_str(ERR_TOOMANYTARGETS),
|
||||
me.name, source_p->name, nick);
|
||||
return (1);
|
||||
}
|
||||
targets[ntargets].ptr = (void *)target_p;
|
||||
targets[ntargets].type = ENTITY_CLIENT;
|
||||
targets[ntargets++].flags = 0;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
/* @#channel or +#channel message ? */
|
||||
|
||||
type = 0;
|
||||
with_prefix = nick;
|
||||
/* allow %+@ if someone wants to do that */
|
||||
for (;;)
|
||||
{
|
||||
if (*nick == '@')
|
||||
type |= MODE_CHANOP;
|
||||
else if (*nick == '%')
|
||||
type |= MODE_CHANOP | MODE_HALFOP;
|
||||
else if (*nick == '+')
|
||||
type |= MODE_CHANOP | MODE_HALFOP | MODE_VOICE;
|
||||
else
|
||||
break;
|
||||
nick++;
|
||||
}
|
||||
|
||||
if (type != 0)
|
||||
{
|
||||
/* suggested by Mortiis */
|
||||
if (*nick == '\0') /* if its a '\0' dump it, there is no recipient */
|
||||
{
|
||||
sendto_one(source_p, form_str(ERR_NORECIPIENT),
|
||||
me.name, source_p->name, command);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* At this point, nick+1 should be a channel name i.e. #foo or &foo
|
||||
* if the channel is found, fine, if not report an error
|
||||
*/
|
||||
|
||||
if ((chptr = hash_find_channel(nick)) != NULL)
|
||||
{
|
||||
if(!is_any_op(chptr, source_p) && !is_voiced(chptr, source_p))
|
||||
{
|
||||
sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED), me.name,
|
||||
source_p->name, with_prefix);
|
||||
return(-1);
|
||||
}
|
||||
|
||||
if (!duplicate_ptr(chptr))
|
||||
{
|
||||
if (ntargets >= ConfigFileEntry.max_targets)
|
||||
{
|
||||
sendto_one(source_p, form_str(ERR_TOOMANYTARGETS),
|
||||
me.name, source_p->name, nick);
|
||||
return (1);
|
||||
}
|
||||
targets[ntargets].ptr = (void *)chptr;
|
||||
targets[ntargets].type = ENTITY_CHANOPS_ON_CHANNEL;
|
||||
targets[ntargets++].flags = type;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!ServerInfo.hub && (uplink != NULL) && IsCapable(uplink, CAP_LL))
|
||||
return -1;
|
||||
else if (p_or_n != NOTICE)
|
||||
sendto_one(source_p, form_str(ERR_NOSUCHNICK), me.name,
|
||||
source_p->name, nick);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if(IsOper(source_p) && ((*nick == '$') || strchr(nick, '@')))
|
||||
{
|
||||
handle_opers(p_or_n, command, client_p, source_p, nick, text);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!ServerInfo.hub && (uplink != NULL) && IsCapable(uplink, CAP_LL))
|
||||
return -1;
|
||||
else if(p_or_n != NOTICE)
|
||||
sendto_one(source_p, form_str(ERR_NOSUCHNICK),
|
||||
me.name, source_p->name, nick);
|
||||
}
|
||||
/* continue; */
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* duplicate_ptr
|
||||
*
|
||||
* inputs - pointer to check
|
||||
* - pointer to table of entities
|
||||
* - number of valid entities so far
|
||||
* output - YES if duplicate pointer in table, NO if not.
|
||||
* note, this does the canonize using pointers
|
||||
* side effects - NONE
|
||||
*/
|
||||
static int
|
||||
duplicate_ptr(void *ptr)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < ntargets; i++)
|
||||
if (targets[i].ptr == ptr)
|
||||
return YES;
|
||||
return NO;
|
||||
}
|
||||
|
||||
/*
|
||||
* msg_channel
|
||||
*
|
||||
* inputs - flag privmsg or notice
|
||||
* - pointer to command "PRIVMSG" or "NOTICE"
|
||||
* - pointer to client_p
|
||||
* - pointer to source_p
|
||||
* - pointer to channel
|
||||
* output - NONE
|
||||
* side effects - message given channel
|
||||
*/
|
||||
static void
|
||||
msg_channel(int p_or_n, char *command,
|
||||
struct Client *client_p,
|
||||
struct Client *source_p, struct Channel *chptr, char *text)
|
||||
{
|
||||
struct Channel *vchan = NULL;
|
||||
char *chname = NULL;
|
||||
int result;
|
||||
|
||||
chname = RootChan(chptr)->chname;
|
||||
|
||||
#ifdef VCHANS
|
||||
if (HasVchans(chptr))
|
||||
vchan = map_vchan(chptr, source_p);
|
||||
#endif
|
||||
|
||||
if (!vchan)
|
||||
vchan = chptr;
|
||||
|
||||
if (MyClient(source_p))
|
||||
{
|
||||
/* idle time shouldnt be reset by notices --fl */
|
||||
if ((p_or_n != NOTICE) && source_p->user)
|
||||
source_p->user->last = CurrentTime;
|
||||
}
|
||||
|
||||
/* chanops and voiced can flood their own channel with impunity */
|
||||
if ((result = can_send(vchan, source_p)))
|
||||
{
|
||||
if (result == CAN_SEND_OPV ||
|
||||
!flood_attack_channel(p_or_n, source_p, vchan, chname))
|
||||
{
|
||||
sendto_channel_butone(client_p, source_p, vchan, command, ":%s", text);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (p_or_n != NOTICE)
|
||||
sendto_one(source_p, form_str(ERR_CANNOTSENDTOCHAN),
|
||||
me.name, source_p->name, chname);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* msg_channel_flags
|
||||
*
|
||||
* inputs - flag 0 if PRIVMSG 1 if NOTICE. RFC
|
||||
* say NOTICE must not auto reply
|
||||
* - pointer to command, "PRIVMSG" or "NOTICE"
|
||||
* - pointer to client_p
|
||||
* - pointer to source_p
|
||||
* - pointer to channel
|
||||
* - flags
|
||||
* - pointer to text to send
|
||||
* output - NONE
|
||||
* side effects - message given channel either chanop or voice
|
||||
*/
|
||||
static void
|
||||
msg_channel_flags(int p_or_n, char *command, struct Client *client_p,
|
||||
struct Client *source_p, struct Channel *chptr,
|
||||
int flags, char *text)
|
||||
{
|
||||
struct Channel *vchan = NULL;
|
||||
char *chname = NULL;
|
||||
int type;
|
||||
char c;
|
||||
|
||||
if (flags & MODE_VOICE)
|
||||
{
|
||||
type = ONLY_CHANOPS_HALFOPS_VOICED;
|
||||
c = '+';
|
||||
}
|
||||
else if (flags & MODE_HALFOP)
|
||||
{
|
||||
type = ONLY_CHANOPS_HALFOPS;
|
||||
c = '%';
|
||||
}
|
||||
else
|
||||
{
|
||||
type = ONLY_CHANOPS;
|
||||
c = '@';
|
||||
}
|
||||
|
||||
chname = RootChan(chptr)->chname;
|
||||
|
||||
#ifdef VCHANS
|
||||
if (HasVchans(chptr))
|
||||
vchan = map_vchan(chptr, source_p);
|
||||
#endif
|
||||
|
||||
if (!vchan)
|
||||
vchan = chptr;
|
||||
|
||||
if (MyClient(source_p))
|
||||
{
|
||||
/* idletime shouldnt be reset by notice --fl */
|
||||
if ((p_or_n != NOTICE) && source_p->user)
|
||||
source_p->user->last = CurrentTime;
|
||||
}
|
||||
|
||||
sendto_channel_local(type, vchan, ":%s!%s@%s %s %c%s :%s",
|
||||
source_p->name, source_p->username,
|
||||
source_p->host, command, c, chname, text);
|
||||
|
||||
if (chptr->chname[0] == '&')
|
||||
return;
|
||||
|
||||
sendto_channel_remote(source_p, client_p, type, CAP_CHW, CAP_UID, vchan,
|
||||
":%s %s %c%s :%s", source_p->name, command, c,
|
||||
vchan->chname, text);
|
||||
sendto_channel_remote(source_p, client_p, type, CAP_CHW|CAP_UID, NOCAPS, vchan,
|
||||
":%s %s %c%s :%s", ID(source_p), command, c,
|
||||
vchan->chname, text);
|
||||
|
||||
/* non CAP_CHW servers? */
|
||||
}
|
||||
|
||||
/*
|
||||
* msg_client
|
||||
*
|
||||
* inputs - flag 0 if PRIVMSG 1 if NOTICE. RFC
|
||||
* say NOTICE must not auto reply
|
||||
* - pointer to command, "PRIVMSG" or "NOTICE"
|
||||
* - pointer to source_p source (struct Client *)
|
||||
* - pointer to target_p target (struct Client *)
|
||||
* - pointer to text
|
||||
* output - NONE
|
||||
* side effects - message given channel either chanop or voice
|
||||
*/
|
||||
static void
|
||||
msg_client(int p_or_n, char *command,
|
||||
struct Client *source_p, struct Client *target_p, char *text)
|
||||
{
|
||||
if (MyClient(source_p))
|
||||
{
|
||||
/* reset idle time for message only if its not to self
|
||||
* and its not a notice */
|
||||
if ((p_or_n != NOTICE) && (source_p != target_p) && source_p->user)
|
||||
source_p->user->last = CurrentTime;
|
||||
}
|
||||
|
||||
if (MyConnect(source_p) && (p_or_n != NOTICE) &&
|
||||
target_p->user && target_p->user->away)
|
||||
sendto_one(source_p, form_str(RPL_AWAY), me.name,
|
||||
source_p->name, target_p->name, target_p->user->away);
|
||||
|
||||
if (MyClient(target_p))
|
||||
{
|
||||
/* XXX Controversial? allow opers always to send through a +g */
|
||||
if (!IsServer(source_p) && IsSetCallerId(target_p))
|
||||
{
|
||||
/* Here is the anti-flood bot/spambot code -db */
|
||||
if (accept_message(source_p, target_p) || IsOper(source_p))
|
||||
{
|
||||
sendto_one(target_p, ":%s!%s@%s %s %s :%s",
|
||||
source_p->name,
|
||||
source_p->username,
|
||||
source_p->host, command, target_p->name, text);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* check for accept, flag recipient incoming message */
|
||||
if (p_or_n != NOTICE)
|
||||
sendto_anywhere(source_p, target_p,
|
||||
"NOTICE %s :*** I'm in +g mode (server side ignore).",
|
||||
source_p->name);
|
||||
|
||||
if ((target_p->localClient->last_caller_id_time +
|
||||
ConfigFileEntry.caller_id_wait) < CurrentTime)
|
||||
{
|
||||
if (p_or_n != NOTICE)
|
||||
sendto_anywhere(source_p, target_p,
|
||||
"NOTICE %s :*** I've been informed you messaged me.",
|
||||
source_p->name);
|
||||
|
||||
sendto_one(target_p,
|
||||
":%s NOTICE %s :*** Client %s [%s@%s] is messaging you and you are +g",
|
||||
me.name, target_p->name,
|
||||
source_p->name, source_p->username, source_p->host);
|
||||
|
||||
target_p->localClient->last_caller_id_time = CurrentTime;
|
||||
|
||||
}
|
||||
/* Only so opers can watch for floods */
|
||||
(void)flood_attack_client(p_or_n, source_p, target_p);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* If the client is remote, we dont perform a special check for
|
||||
* flooding.. as we wouldnt block their message anyway.. this means
|
||||
* we dont give warnings.. we then check if theyre opered
|
||||
* (to avoid flood warnings), lastly if theyre our client
|
||||
* and flooding -- fl */
|
||||
if (!MyClient(source_p) || IsOper(source_p) ||
|
||||
(MyClient(source_p) &&
|
||||
!flood_attack_client(p_or_n, source_p, target_p)))
|
||||
sendto_anywhere(target_p, source_p, "%s %s :%s",
|
||||
command, target_p->name, text);
|
||||
}
|
||||
}
|
||||
else
|
||||
/* The target is a remote user.. same things apply -- fl */
|
||||
if (!MyClient(source_p) || IsOper(source_p) ||
|
||||
(MyClient(source_p)
|
||||
&& !flood_attack_client(p_or_n, source_p, target_p)))
|
||||
sendto_anywhere(target_p, source_p, "%s %s :%s", command, target_p->name,
|
||||
text);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* flood_attack_client
|
||||
* inputs - flag 0 if PRIVMSG 1 if NOTICE. RFC
|
||||
* say NOTICE must not auto reply
|
||||
* - pointer to source Client
|
||||
* - pointer to target Client
|
||||
* output - 1 if target is under flood attack
|
||||
* side effects - check for flood attack on target target_p
|
||||
*/
|
||||
static int
|
||||
flood_attack_client(int p_or_n, struct Client *source_p,
|
||||
struct Client *target_p)
|
||||
{
|
||||
int delta;
|
||||
|
||||
if (GlobalSetOptions.floodcount && MyConnect(target_p)
|
||||
&& IsClient(source_p))
|
||||
{
|
||||
if ((target_p->localClient->first_received_message_time + 1)
|
||||
< CurrentTime)
|
||||
{
|
||||
delta =
|
||||
CurrentTime - target_p->localClient->first_received_message_time;
|
||||
target_p->localClient->received_number_of_privmsgs -= delta;
|
||||
target_p->localClient->first_received_message_time = CurrentTime;
|
||||
if (target_p->localClient->received_number_of_privmsgs <= 0)
|
||||
{
|
||||
target_p->localClient->received_number_of_privmsgs = 0;
|
||||
target_p->localClient->flood_noticed = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if ((target_p->localClient->received_number_of_privmsgs >=
|
||||
GlobalSetOptions.floodcount) || target_p->localClient->flood_noticed)
|
||||
{
|
||||
if (target_p->localClient->flood_noticed == 0)
|
||||
{
|
||||
sendto_realops_flags(FLAGS_BOTS, L_ALL,
|
||||
"Possible Flooder %s [%s@%s] on %s target: %s",
|
||||
source_p->name, source_p->username,
|
||||
source_p->host,
|
||||
source_p->user->server, target_p->name);
|
||||
target_p->localClient->flood_noticed = 1;
|
||||
/* add a bit of penalty */
|
||||
target_p->localClient->received_number_of_privmsgs += 2;
|
||||
}
|
||||
if (MyClient(source_p) && (p_or_n != NOTICE))
|
||||
sendto_one(source_p,
|
||||
":%s NOTICE %s :*** Message to %s throttled due to flooding",
|
||||
me.name, source_p->name, target_p->name);
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
target_p->localClient->received_number_of_privmsgs++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* flood_attack_channel
|
||||
* inputs - flag 0 if PRIVMSG 1 if NOTICE. RFC
|
||||
* says NOTICE must not auto reply
|
||||
* - pointer to source Client
|
||||
* - pointer to target channel
|
||||
* output - 1 if target is under flood attack
|
||||
* side effects - check for flood attack on target chptr
|
||||
*/
|
||||
static int
|
||||
flood_attack_channel(int p_or_n, struct Client *source_p,
|
||||
struct Channel *chptr, char *chname)
|
||||
{
|
||||
int delta;
|
||||
|
||||
if (GlobalSetOptions.floodcount)
|
||||
{
|
||||
if ((chptr->first_received_message_time + 1) < CurrentTime)
|
||||
{
|
||||
delta = CurrentTime - chptr->first_received_message_time;
|
||||
chptr->received_number_of_privmsgs -= delta;
|
||||
chptr->first_received_message_time = CurrentTime;
|
||||
if (chptr->received_number_of_privmsgs <= 0)
|
||||
{
|
||||
chptr->received_number_of_privmsgs = 0;
|
||||
chptr->flood_noticed = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if ((chptr->received_number_of_privmsgs >= GlobalSetOptions.floodcount)
|
||||
|| chptr->flood_noticed)
|
||||
{
|
||||
if (chptr->flood_noticed == 0)
|
||||
{
|
||||
sendto_realops_flags(FLAGS_BOTS, L_ALL,
|
||||
"Possible Flooder %s [%s@%s] on %s target: %s",
|
||||
source_p->name, source_p->username,
|
||||
source_p->host,
|
||||
source_p->user->server, chptr->chname);
|
||||
chptr->flood_noticed = 1;
|
||||
|
||||
/* Add a bit of penalty */
|
||||
chptr->received_number_of_privmsgs += 2;
|
||||
}
|
||||
if (MyClient(source_p) && (p_or_n != NOTICE))
|
||||
sendto_one(source_p,
|
||||
":%s NOTICE %s :*** Message to %s throttled due to flooding",
|
||||
me.name, source_p->name, chname);
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
chptr->received_number_of_privmsgs++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* handle_opers
|
||||
*
|
||||
* inputs - server pointer
|
||||
* - client pointer
|
||||
* - nick stuff to grok for opers
|
||||
* - text to send if grok
|
||||
* output - none
|
||||
* side effects - all the traditional oper type messages are parsed here.
|
||||
* i.e. "/msg #some.host."
|
||||
* However, syntax has been changed.
|
||||
* previous syntax "/msg #some.host.mask"
|
||||
* now becomes "/msg $#some.host.mask"
|
||||
* previous syntax of: "/msg $some.server.mask" remains
|
||||
* This disambiguates the syntax.
|
||||
*/
|
||||
static void
|
||||
handle_opers(int p_or_n, char *command, struct Client *client_p,
|
||||
struct Client *source_p, char *nick, char *text)
|
||||
{
|
||||
struct Client *target_p;
|
||||
char *host;
|
||||
char *server;
|
||||
char *s;
|
||||
int count;
|
||||
|
||||
/*
|
||||
* the following two cases allow masks in NOTICEs
|
||||
* (for OPERs only)
|
||||
*
|
||||
* Armin, 8Jun90 (gruner@informatik.tu-muenchen.de)
|
||||
*/
|
||||
if(*nick == '$')
|
||||
{
|
||||
if((*(nick+1) == '$' || *(nick+1) == '#'))
|
||||
nick++;
|
||||
else if(MyOper(source_p))
|
||||
{
|
||||
sendto_one(source_p,
|
||||
":%s NOTICE %s :The command %s %s is no longer supported, please use $%s",
|
||||
me.name, source_p->name, command, nick, nick);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((s = strrchr(nick, '.')) == NULL)
|
||||
{
|
||||
sendto_one(source_p, form_str(ERR_NOTOPLEVEL),
|
||||
me.name, source_p->name, nick);
|
||||
return;
|
||||
}
|
||||
while (*++s)
|
||||
if (*s == '.' || *s == '*' || *s == '?')
|
||||
break;
|
||||
if (*s == '*' || *s == '?')
|
||||
{
|
||||
sendto_one(source_p, form_str(ERR_WILDTOPLEVEL),
|
||||
me.name, source_p->name, nick);
|
||||
return;
|
||||
}
|
||||
|
||||
sendto_match_butone(IsServer(client_p) ? client_p : NULL, source_p,
|
||||
nick + 1,
|
||||
(*nick == '#') ? MATCH_HOST : MATCH_SERVER,
|
||||
"%s $%s :%s", command, nick, text);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* user[%host]@server addressed?
|
||||
*/
|
||||
if ((server = strchr(nick, '@')) && (target_p = find_server(server + 1)))
|
||||
{
|
||||
count = 0;
|
||||
|
||||
/*
|
||||
* Not destined for a user on me :-(
|
||||
*/
|
||||
|
||||
if (!IsMe(target_p))
|
||||
{
|
||||
sendto_one(target_p, ":%s %s %s :%s", source_p->name,
|
||||
"PRIVMSG", nick, text);
|
||||
return;
|
||||
}
|
||||
|
||||
*server = '\0';
|
||||
|
||||
if ((host = strchr(nick, '%')) != NULL)
|
||||
*host++ = '\0';
|
||||
|
||||
/* Check if someones msg'ing opers@our.server */
|
||||
if (strcmp(nick, "opers") == 0)
|
||||
{
|
||||
sendto_realops_flags(FLAGS_ALL, L_ALL, "To opers: From: %s: %s",
|
||||
source_p->name, text);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Look for users which match the destination host
|
||||
* (no host == wildcard) and if one and one only is
|
||||
* found connected to me, deliver message!
|
||||
*/
|
||||
target_p = find_userhost(nick, host, &count);
|
||||
|
||||
if (target_p != NULL)
|
||||
{
|
||||
if (server != NULL)
|
||||
*server = '@';
|
||||
if (host != NULL)
|
||||
*--host = '%';
|
||||
|
||||
if (count == 1)
|
||||
sendto_anywhere(target_p, source_p, "%s %s :%s", "PRIVMSG",
|
||||
nick, text);
|
||||
else
|
||||
sendto_one(source_p, form_str(ERR_TOOMANYTARGETS),
|
||||
me.name, source_p->name, nick);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* find_userhost - find a user@host (server or user).
|
||||
* inputs - user name to look for
|
||||
* - host name to look for
|
||||
* - pointer to count of number of matches found
|
||||
* outputs - pointer to client if found
|
||||
* - count is updated
|
||||
* side effects - none
|
||||
*
|
||||
*/
|
||||
static struct Client *
|
||||
find_userhost(char *user, char *host, int *count)
|
||||
{
|
||||
struct Client *c2ptr;
|
||||
struct Client *res = NULL;
|
||||
|
||||
*count = 0;
|
||||
if (collapse(user) != NULL)
|
||||
{
|
||||
for (c2ptr = GlobalClientList; c2ptr; c2ptr = c2ptr->next)
|
||||
{
|
||||
if (!MyClient(c2ptr)) /* implies mine and an user */
|
||||
continue;
|
||||
if ((!host || match(host, c2ptr->host)) &&
|
||||
irccmp(user, c2ptr->username) == 0)
|
||||
{
|
||||
(*count)++;
|
||||
res = c2ptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
return (res);
|
||||
}
|
223
modules/core/m_mode.c
Normal file
223
modules/core/m_mode.c
Normal file
|
@ -0,0 +1,223 @@
|
|||
/*
|
||||
* ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
|
||||
* m_mode.c: Sets a user or channel mode.
|
||||
*
|
||||
* Copyright (C) 2002 by the past and present ircd coders, and others.
|
||||
*
|
||||
* 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 2 of the License, 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
* USA
|
||||
*
|
||||
* $Id: m_mode.c,v 1.1 2002/08/14 05:47:41 fishwaldo Exp $
|
||||
*/
|
||||
|
||||
#include "stdinc.h"
|
||||
#include "tools.h"
|
||||
#include "handlers.h"
|
||||
#include "channel.h"
|
||||
#include "channel_mode.h"
|
||||
#include "vchannel.h"
|
||||
#include "client.h"
|
||||
#include "hash.h"
|
||||
#include "irc_string.h"
|
||||
#include "ircd.h"
|
||||
#include "numeric.h"
|
||||
#include "s_user.h"
|
||||
#include "s_conf.h"
|
||||
#include "s_serv.h"
|
||||
#include "send.h"
|
||||
#include "msg.h"
|
||||
#include "parse.h"
|
||||
#include "modules.h"
|
||||
#include "packet.h"
|
||||
|
||||
static void m_mode(struct Client*, struct Client*, int, char**);
|
||||
|
||||
struct Message mode_msgtab = {
|
||||
"MODE", 0, 0, 2, 0, MFLG_SLOW, 0,
|
||||
{m_unregistered, m_mode, m_mode, m_mode}
|
||||
};
|
||||
#ifndef STATIC_MODULES
|
||||
|
||||
void
|
||||
_modinit(void)
|
||||
{
|
||||
mod_add_cmd(&mode_msgtab);
|
||||
}
|
||||
|
||||
void
|
||||
_moddeinit(void)
|
||||
{
|
||||
mod_del_cmd(&mode_msgtab);
|
||||
}
|
||||
|
||||
|
||||
const char *_version = "$Revision: 1.1 $";
|
||||
#endif
|
||||
/*
|
||||
* m_mode - MODE command handler
|
||||
* parv[0] - sender
|
||||
* parv[1] - channel
|
||||
*/
|
||||
static void m_mode(struct Client *client_p, struct Client *source_p,
|
||||
int parc, char *parv[])
|
||||
{
|
||||
struct Channel* chptr=NULL;
|
||||
struct Channel* root;
|
||||
static char modebuf[MODEBUFLEN];
|
||||
static char parabuf[MODEBUFLEN];
|
||||
dlink_node *ptr;
|
||||
int n = 2;
|
||||
#ifdef VCHANS
|
||||
struct Channel* vchan;
|
||||
#endif
|
||||
|
||||
/* Now, try to find the channel in question */
|
||||
if (!IsChanPrefix(parv[1][0]))
|
||||
{
|
||||
/* if here, it has to be a non-channel name */
|
||||
user_mode(client_p, source_p, parc, parv);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!check_channel_name(parv[1]))
|
||||
{
|
||||
sendto_one(source_p, form_str(ERR_BADCHANNAME),
|
||||
me.name, parv[0], (unsigned char *)parv[1]);
|
||||
return;
|
||||
}
|
||||
|
||||
chptr = hash_find_channel(parv[1]);
|
||||
|
||||
if (chptr == NULL)
|
||||
{
|
||||
/* if chptr isn't found locally, it =could= exist
|
||||
* on the uplink. So ask.
|
||||
*/
|
||||
|
||||
/* LazyLinks */
|
||||
/* this was segfaulting if we had no servers linked.
|
||||
* -pro
|
||||
*/
|
||||
/* only send a mode upstream if a local client sent this request
|
||||
* -davidt
|
||||
*/
|
||||
if (MyClient(source_p) && !ServerInfo.hub && uplink &&
|
||||
IsCapable(uplink, CAP_LL))
|
||||
{
|
||||
#if 0
|
||||
/* cache the channel if it exists on uplink
|
||||
* If the channel as seen by the uplink, has vchans,
|
||||
* the uplink will have to SJOIN all of those.
|
||||
*/
|
||||
/* Lets not for now -db */
|
||||
|
||||
sendto_one(uplink, ":%s CBURST %s",
|
||||
me.name, parv[1]);
|
||||
|
||||
#endif
|
||||
sendto_one(uplink, ":%s MODE %s %s",
|
||||
source_p->name, parv[1], (parv[2] ? parv[2] : ""));
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
sendto_one(source_p, form_str(ERR_NOSUCHCHANNEL),
|
||||
me.name, parv[0], parv[1]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now known the channel exists */
|
||||
|
||||
root = chptr;
|
||||
|
||||
#ifdef VCHANS
|
||||
if ((parc > 2) && parv[2][0] == '!')
|
||||
{
|
||||
struct Client *target_p;
|
||||
if (!(target_p = find_client(++parv[2])))
|
||||
{
|
||||
sendto_one(source_p, form_str(ERR_NOSUCHCHANNEL), me.name,
|
||||
parv[0], root->chname);
|
||||
return;
|
||||
}
|
||||
if ((chptr = map_vchan(root, target_p)) == NULL)
|
||||
{
|
||||
sendto_one(source_p, form_str(ERR_NOSUCHCHANNEL), me.name,
|
||||
parv[0], root->chname);
|
||||
return;
|
||||
}
|
||||
n++;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
if (HasVchans(chptr))
|
||||
{
|
||||
if ((vchan = map_vchan(chptr,source_p)) != NULL)
|
||||
chptr = vchan; /* root = chptr, chptr = vchan */
|
||||
|
||||
/* XXX - else? the user isn't on any vchan, so we
|
||||
* end up giving them the mode of the root
|
||||
* channel. MODE #vchan !nick ? (ugh)
|
||||
*/
|
||||
}
|
||||
else if (IsVchan(chptr))
|
||||
{
|
||||
vchan = find_bchan(chptr);
|
||||
root = vchan; /* root = vchan, chptr = chptr */
|
||||
|
||||
/* XXX - else? the user isn't on any vchan,
|
||||
* but they asked for MODE ##vchan_12345
|
||||
* we send MODE #vchan
|
||||
*/
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (parc < n+1)
|
||||
{
|
||||
channel_modes(chptr, source_p, modebuf, parabuf);
|
||||
sendto_one(source_p, form_str(RPL_CHANNELMODEIS),
|
||||
me.name, parv[0], parv[1],
|
||||
modebuf, parabuf);
|
||||
|
||||
/* Let opers see the "true" TS everyone else see's
|
||||
* the top root chan TS
|
||||
*/
|
||||
if (!IsOper(source_p))
|
||||
sendto_one(source_p, form_str(RPL_CREATIONTIME),
|
||||
me.name, parv[0],
|
||||
parv[1], root->channelts);
|
||||
else
|
||||
sendto_one(source_p, form_str(RPL_CREATIONTIME),
|
||||
me.name, parv[0],
|
||||
parv[1], chptr->channelts);
|
||||
}
|
||||
/* bounce all modes from people we deop on sjoin */
|
||||
else if((ptr = find_user_link(&chptr->deopped, source_p)) == NULL)
|
||||
{
|
||||
/* Finish the flood grace period... */
|
||||
if(MyClient(source_p) && !IsFloodDone(source_p))
|
||||
flood_endgrace(source_p);
|
||||
|
||||
set_channel_mode(client_p, source_p, chptr, parc - n, parv + n,
|
||||
root->chname);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
979
modules/core/m_nick.c
Normal file
979
modules/core/m_nick.c
Normal file
|
@ -0,0 +1,979 @@
|
|||
/*
|
||||
* ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
|
||||
* m_nick.c: Sets a users nick.
|
||||
*
|
||||
* Copyright (C) 2002 by the past and present ircd coders, and others.
|
||||
*
|
||||
* 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 2 of the License, 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
* USA
|
||||
*
|
||||
* $Id: m_nick.c,v 1.1 2002/08/14 05:47:41 fishwaldo Exp $
|
||||
*/
|
||||
|
||||
#include "stdinc.h"
|
||||
#include "handlers.h"
|
||||
#include "client.h"
|
||||
#include "hash.h"
|
||||
#include "fdlist.h"
|
||||
#include "irc_string.h"
|
||||
#include "ircd.h"
|
||||
#include "numeric.h"
|
||||
#include "s_conf.h"
|
||||
#include "s_stats.h"
|
||||
#include "s_user.h"
|
||||
#include "hash.h"
|
||||
#include "whowas.h"
|
||||
#include "s_serv.h"
|
||||
#include "send.h"
|
||||
#include "list.h"
|
||||
#include "channel.h"
|
||||
#include "s_log.h"
|
||||
#include "resv.h"
|
||||
#include "msg.h"
|
||||
#include "parse.h"
|
||||
#include "modules.h"
|
||||
#include "common.h"
|
||||
#include "packet.h"
|
||||
|
||||
|
||||
static void mr_nick(struct Client *, struct Client *, int, char**);
|
||||
static void m_nick(struct Client *, struct Client *, int, char**);
|
||||
static void ms_nick(struct Client *, struct Client *, int, char**);
|
||||
|
||||
static void ms_client(struct Client *, struct Client *, int, char**);
|
||||
|
||||
static int nick_from_server(struct Client *, struct Client *, int, char **,
|
||||
time_t, char *);
|
||||
static int client_from_server(struct Client *, struct Client *, int, char **,
|
||||
time_t, char *);
|
||||
|
||||
static int check_clean_nick(struct Client *, struct Client *,
|
||||
char *, char *, char *);
|
||||
static int check_clean_user(struct Client *, char *, char *, char *);
|
||||
static int check_clean_host(struct Client *, char *, char *, char *);
|
||||
|
||||
static int clean_nick_name(char *);
|
||||
static int clean_user_name(char *);
|
||||
static int clean_host_name(char *);
|
||||
|
||||
static int perform_nick_collides(struct Client *, struct Client *,
|
||||
struct Client *, int, char **, time_t, char *);
|
||||
|
||||
|
||||
struct Message nick_msgtab = {
|
||||
"NICK", 0, 0, 1, 0, MFLG_SLOW, 0,
|
||||
{mr_nick, m_nick, ms_nick, m_nick}
|
||||
};
|
||||
|
||||
struct Message client_msgtab = {
|
||||
"CLIENT", 0, 0, 10, 0, MFLG_SLOW, 0,
|
||||
{m_ignore, m_ignore, ms_client, m_ignore}
|
||||
};
|
||||
|
||||
#ifndef STATIC_MODULES
|
||||
void
|
||||
_modinit(void)
|
||||
{
|
||||
mod_add_cmd(&nick_msgtab);
|
||||
mod_add_cmd(&client_msgtab);
|
||||
}
|
||||
|
||||
void
|
||||
_moddeinit(void)
|
||||
{
|
||||
mod_del_cmd(&nick_msgtab);
|
||||
mod_del_cmd(&client_msgtab);
|
||||
}
|
||||
|
||||
const char *_version = "$Revision: 1.1 $";
|
||||
#endif
|
||||
|
||||
/*
|
||||
* mr_nick()
|
||||
*
|
||||
* parv[0] = sender prefix
|
||||
* parv[1] = nickname
|
||||
*/
|
||||
static void mr_nick(struct Client *client_p, struct Client *source_p,
|
||||
int parc, char *parv[])
|
||||
{
|
||||
struct Client *target_p, *uclient_p;
|
||||
char nick[NICKLEN];
|
||||
char* s;
|
||||
dlink_node *ptr;
|
||||
|
||||
if(parc < 2)
|
||||
{
|
||||
sendto_one(source_p, form_str(ERR_NONICKNAMEGIVEN),
|
||||
me.name, BadPtr(parv[0]) ? "*" : parv[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Terminate the nick at the first ~ */
|
||||
if ((s = strchr(parv[1], '~')))
|
||||
*s = '\0';
|
||||
|
||||
/* copy the nick and terminate it */
|
||||
strlcpy(nick, parv[1], NICKLEN);
|
||||
|
||||
/* check the nickname is ok */
|
||||
if(!clean_nick_name(nick))
|
||||
{
|
||||
sendto_one(source_p, form_str(ERR_ERRONEUSNICKNAME),
|
||||
me.name, BadPtr(parv[0]) ? "*" : parv[0], parv[1]);
|
||||
return;
|
||||
}
|
||||
|
||||
/* check if the nick is resv'd */
|
||||
if(find_nick_resv(nick))
|
||||
{
|
||||
sendto_one(source_p, form_str(ERR_UNAVAILRESOURCE),
|
||||
me.name, BadPtr(parv[0]) ? "*" : parv[0], nick);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((target_p = find_client(nick)) == NULL)
|
||||
{
|
||||
if(!ServerInfo.hub && uplink && IsCapable(uplink, CAP_LL))
|
||||
{
|
||||
/* We don't know anyone called nick, but our hub might */
|
||||
for(ptr = unknown_list.head; ptr; ptr = ptr->next)
|
||||
{
|
||||
uclient_p = ptr->data;
|
||||
|
||||
if(!strcmp(nick, uclient_p->llname))
|
||||
{
|
||||
|
||||
/* We're already waiting for a reply about this nick
|
||||
* for someone else. */
|
||||
|
||||
sendto_one(source_p, form_str(ERR_NICKNAMEINUSE), me.name, "*", nick);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Set their llname so we can find them later */
|
||||
strcpy(source_p->llname, nick);
|
||||
|
||||
/* Ask the hub about their requested name */
|
||||
sendto_one(uplink, ":%s NBURST %s %s !%s", me.name, nick,
|
||||
nick, nick);
|
||||
|
||||
/* wait for LLNICK */
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
set_initial_nick(client_p, source_p, nick);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if(source_p == target_p)
|
||||
{
|
||||
strcpy(source_p->name, nick);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
sendto_one(source_p, form_str(ERR_NICKNAMEINUSE), me.name, "*", nick);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* m_nick()
|
||||
*
|
||||
* parv[0] = sender prefix
|
||||
* parv[1] = nickname
|
||||
*/
|
||||
static void m_nick(struct Client *client_p, struct Client *source_p,
|
||||
int parc, char *parv[])
|
||||
{
|
||||
char nick[NICKLEN];
|
||||
struct Client *target_p;
|
||||
|
||||
if(parc < 2)
|
||||
{
|
||||
sendto_one(source_p, form_str(ERR_NONICKNAMEGIVEN),
|
||||
me.name, parv[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
/* mark end of grace period, to prevent nickflooding */
|
||||
if(!IsFloodDone(source_p))
|
||||
flood_endgrace(source_p);
|
||||
|
||||
/* terminate nick to NICKLEN */
|
||||
strlcpy(nick, parv[1], NICKLEN);
|
||||
|
||||
/* check the nickname is ok */
|
||||
if(!clean_nick_name(nick))
|
||||
{
|
||||
sendto_one(source_p, form_str(ERR_ERRONEUSNICKNAME),
|
||||
me.name, parv[0], nick);
|
||||
return;
|
||||
}
|
||||
|
||||
if(find_nick_resv(nick))
|
||||
{
|
||||
sendto_one(source_p, form_str(ERR_UNAVAILRESOURCE),
|
||||
me.name, parv[0], nick);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((target_p = find_client(nick)))
|
||||
{
|
||||
/* If(target_p == source_p) the client is changing nicks between
|
||||
* equivalent nicknames ie: [nick] -> {nick}
|
||||
*/
|
||||
|
||||
if(target_p == source_p)
|
||||
{
|
||||
/* check the nick isnt exactly the same */
|
||||
if(strcmp(target_p->name, nick))
|
||||
{
|
||||
change_local_nick(client_p, source_p, nick);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* client is doing :old NICK old
|
||||
* ignore it..
|
||||
*/
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* if the client that has the nick isnt registered yet (nick but no
|
||||
* user) then drop the unregged client
|
||||
*/
|
||||
if(IsUnknown(target_p))
|
||||
{
|
||||
/* the old code had an if(MyConnect(target_p)) here.. but I cant see
|
||||
* how that can happen, m_nick() is local only --fl_
|
||||
*/
|
||||
|
||||
exit_client(NULL, target_p, &me, "Overridden");
|
||||
change_local_nick(client_p, source_p, nick);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
sendto_one(source_p, form_str(ERR_NICKNAMEINUSE), me.name,
|
||||
parv[0], nick);
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!ServerInfo.hub && uplink && IsCapable(uplink, CAP_LL))
|
||||
{
|
||||
/* The uplink might know someone by this name already. */
|
||||
sendto_one(uplink, ":%s NBURST %s %s %s", me.name, nick,
|
||||
nick, source_p->name);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
change_local_nick(client_p,source_p,nick);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ms_nick()
|
||||
*
|
||||
* server -> server nick change
|
||||
* parv[0] = sender prefix
|
||||
* parv[1] = nickname
|
||||
* parv[2] = TS when nick change
|
||||
*
|
||||
* server introducing new nick
|
||||
* parv[0] = sender prefix
|
||||
* parv[1] = nickname
|
||||
* parv[2] = hop count
|
||||
* parv[3] = TS
|
||||
* parv[4] = umode
|
||||
* parv[5] = username
|
||||
* parv[6] = hostname
|
||||
* parv[7] = server
|
||||
* parv[8] = ircname
|
||||
*/
|
||||
static void ms_nick(struct Client *client_p, struct Client *source_p,
|
||||
int parc, char *parv[])
|
||||
{
|
||||
struct Client* target_p;
|
||||
char nick[NICKLEN];
|
||||
time_t newts = 0;
|
||||
|
||||
if(parc < 2)
|
||||
{
|
||||
sendto_one(source_p, form_str(ERR_NONICKNAMEGIVEN), me.name, parv[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
/* parc == 3 on nickchange, parc == 9 on new nick */
|
||||
if((parc != 3) && (parc != 9))
|
||||
return;
|
||||
|
||||
/* fix the length of the nick */
|
||||
strlcpy(nick, parv[1], NICKLEN);
|
||||
|
||||
if(check_clean_nick(client_p, source_p, nick, parv[1], parv[7]))
|
||||
return;
|
||||
|
||||
if (parc == 9)
|
||||
{
|
||||
if (check_clean_user(client_p, nick, parv[5], parv[7]) ||
|
||||
check_clean_host(client_p, nick, parv[6], parv[7]))
|
||||
return;
|
||||
|
||||
/* check the length of the clients gecos */
|
||||
if(strlen(parv[8]) > REALLEN)
|
||||
{
|
||||
sendto_realops_flags(FLAGS_ALL, L_ALL, "Long realname from server %s for %s",
|
||||
parv[7], parv[1]);
|
||||
parv[8][REALLEN] = '\0';
|
||||
}
|
||||
|
||||
if (IsServer(source_p))
|
||||
newts = atol(parv[3]);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!IsServer(source_p))
|
||||
newts = atol(parv[2]);
|
||||
}
|
||||
|
||||
/* if the nick doesnt exist, allow it and process like normal */
|
||||
if (!(target_p = find_client(nick)))
|
||||
{
|
||||
nick_from_server(client_p,source_p,parc,parv,newts,nick);
|
||||
return;
|
||||
}
|
||||
|
||||
/* we're not living in the past anymore, an unknown client is local only. */
|
||||
if(IsUnknown(target_p))
|
||||
{
|
||||
exit_client(NULL, target_p, &me, "Overridden");
|
||||
nick_from_server(client_p,source_p,parc,parv,newts,nick);
|
||||
return;
|
||||
}
|
||||
|
||||
if(target_p == source_p)
|
||||
{
|
||||
if(strcmp(target_p->name, nick))
|
||||
{
|
||||
/* client changing case of nick */
|
||||
nick_from_server(client_p,source_p,parc,parv,newts,nick);
|
||||
return;
|
||||
}
|
||||
else
|
||||
/* client not changing nicks at all */
|
||||
return;
|
||||
}
|
||||
|
||||
perform_nick_collides(source_p, client_p, target_p,
|
||||
parc, parv, newts, nick);
|
||||
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* ms_client()
|
||||
*/
|
||||
static void ms_client(struct Client *client_p, struct Client *source_p,
|
||||
int parc, char *parv[])
|
||||
{
|
||||
struct Client* target_p;
|
||||
char nick[NICKLEN];
|
||||
time_t newts = 0;
|
||||
char *id;
|
||||
char *name;
|
||||
|
||||
id = parv[8];
|
||||
name = parv[9];
|
||||
|
||||
/* parse the nickname */
|
||||
strlcpy(nick, parv[1], NICKLEN);
|
||||
|
||||
/* check the nicknames, usernames and hostnames are ok */
|
||||
if(check_clean_nick(client_p, source_p, nick, parv[1], parv[7]) ||
|
||||
check_clean_user(client_p, nick, parv[5], parv[7]) ||
|
||||
check_clean_host(client_p, nick, parv[6], parv[7]))
|
||||
return;
|
||||
|
||||
/* check length of clients gecos */
|
||||
if (strlen(name) > REALLEN)
|
||||
{
|
||||
sendto_realops_flags(FLAGS_ALL, L_ALL, "Long realname from server %s for %s",
|
||||
parv[0], parv[1]);
|
||||
name[REALLEN] = '\0';
|
||||
}
|
||||
|
||||
newts = atol(parv[3]);
|
||||
|
||||
/* if there is an ID collision, kill our client, and kill theirs.
|
||||
* this may generate 401's, but it ensures that both clients always
|
||||
* go, even if the other server refuses to do the right thing.
|
||||
*/
|
||||
if((target_p = find_id(id)))
|
||||
{
|
||||
sendto_realops_flags(FLAGS_ALL, L_ALL,
|
||||
"ID collision on %s(%s <- %s)(both killed)",
|
||||
target_p->name, target_p->from->name,
|
||||
client_p->name);
|
||||
|
||||
if(ServerInfo.hub && IsCapable(client_p, CAP_LL))
|
||||
add_lazylinkclient(client_p, source_p);
|
||||
|
||||
kill_client_ll_serv_butone(NULL, target_p, "%s (ID collision)",
|
||||
me.name);
|
||||
|
||||
ServerStats->is_kill++;
|
||||
|
||||
target_p->flags |= FLAGS_KILLED;
|
||||
exit_client(client_p, target_p, &me, "ID Collision");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(target_p = find_client(nick)))
|
||||
{
|
||||
client_from_server(client_p,source_p,parc,parv,newts,nick);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if(IsUnknown(target_p))
|
||||
{
|
||||
exit_client(NULL, target_p, &me, "Overridden");
|
||||
client_from_server(client_p,source_p,parc,parv,newts,nick);
|
||||
return;
|
||||
}
|
||||
|
||||
perform_nick_collides(source_p, client_p, target_p,
|
||||
parc, parv, newts, nick);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* check_clean_nick()
|
||||
*
|
||||
* input - pointer to source
|
||||
* - nickname
|
||||
* - truncated nickname
|
||||
* - origin of client
|
||||
* output - none
|
||||
* side effects - if nickname is erroneous, or a different length to
|
||||
* truncated nickname, return 1
|
||||
*/
|
||||
static int check_clean_nick(struct Client *client_p, struct Client *source_p,
|
||||
char *nick, char *newnick, char *server)
|
||||
{
|
||||
/* the old code did some wacky stuff here, if the nick is invalid, kill it
|
||||
* and dont bother messing at all
|
||||
*/
|
||||
|
||||
if(!clean_nick_name(nick) || strcmp(nick, newnick))
|
||||
{
|
||||
ServerStats->is_kill++;
|
||||
sendto_realops_flags(FLAGS_DEBUG, L_ALL,
|
||||
"Bad Nick: %s From: %s(via %s)",
|
||||
nick, server, client_p->name);
|
||||
|
||||
sendto_one(client_p, ":%s KILL %s :%s (Bad Nickname)",
|
||||
me.name, newnick, me.name);
|
||||
|
||||
/* bad nick change */
|
||||
if(source_p != client_p)
|
||||
{
|
||||
kill_client_ll_serv_butone(client_p, source_p,
|
||||
"%s (Bad Nickname)",
|
||||
me.name);
|
||||
source_p->flags |= FLAGS_KILLED;
|
||||
exit_client(client_p, source_p, &me, "Bad Nickname");
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* check_clean_user()
|
||||
*
|
||||
* input - pointer to client sending data
|
||||
* - nickname
|
||||
* - username to check
|
||||
* - origin of NICK
|
||||
* output - none
|
||||
* side effects - if username is erroneous, return 1
|
||||
*/
|
||||
static int check_clean_user(struct Client *client_p, char *nick,
|
||||
char *user, char *server)
|
||||
{
|
||||
if(strlen(user) > USERLEN)
|
||||
{
|
||||
ServerStats->is_kill++;
|
||||
sendto_realops_flags(FLAGS_DEBUG, L_ALL,
|
||||
"Long Username: %s Nickname: %s From: %s(via %s)",
|
||||
user, nick, server, client_p->name);
|
||||
|
||||
sendto_one(client_p, ":%s KILL %s :%s (Bad Username)",
|
||||
me.name, nick, me.name);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(!clean_user_name(user))
|
||||
sendto_realops_flags(FLAGS_DEBUG, L_ALL,
|
||||
"Bad Username: %s Nickname: %s From: %s(via %s)",
|
||||
user, nick, server, client_p->name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* check_clean_host()
|
||||
*
|
||||
* input - pointer to client sending us data
|
||||
* - nickname
|
||||
* - hostname to check
|
||||
* - source name
|
||||
* output - none
|
||||
* side effects - if hostname is erroneous, return 1
|
||||
*/
|
||||
static int check_clean_host(struct Client *client_p, char *nick,
|
||||
char *host, char *server)
|
||||
{
|
||||
if(strlen(host) > HOSTLEN)
|
||||
{
|
||||
ServerStats->is_kill++;
|
||||
sendto_realops_flags(FLAGS_DEBUG, L_ALL,
|
||||
"Long Hostname: %s Nickname: %s From: %s(via %s)",
|
||||
host, nick, server, client_p->name);
|
||||
|
||||
sendto_one(client_p, ":%s KILL %s :%s (Bad Hostname)",
|
||||
me.name, nick, me.name);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(!clean_host_name(host))
|
||||
sendto_realops_flags(FLAGS_DEBUG, L_ALL,
|
||||
"Bad Hostname: %s Nickname: %s From: %s(via %s)",
|
||||
host, nick, server, client_p->name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* clean_nick_name()
|
||||
*
|
||||
* input - nickname
|
||||
* output - none
|
||||
* side effects - walks through the nickname, returning 0 if erroneous
|
||||
*/
|
||||
static int clean_nick_name(char *nick)
|
||||
{
|
||||
assert(nick);
|
||||
if(nick == NULL)
|
||||
return 0;
|
||||
|
||||
/* nicks cant start with a digit or - */
|
||||
if (*nick == '-' || IsDigit(*nick))
|
||||
return 0;
|
||||
|
||||
for(; *nick; nick++)
|
||||
{
|
||||
if(!IsNickChar(*nick))
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* clean_user_name()
|
||||
*
|
||||
* input - username
|
||||
* output - none
|
||||
* side effects - walks through the username, returning 0 if erroneous
|
||||
*/
|
||||
static int clean_user_name(char *user)
|
||||
{
|
||||
assert(user);
|
||||
if(user == NULL)
|
||||
return 0;
|
||||
|
||||
for(; *user; user++)
|
||||
{
|
||||
if(!IsUserChar(*user))
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* clean_host_name()
|
||||
* input - hostname
|
||||
* output - none
|
||||
* side effects - walks through the hostname, returning 0 if erroneous
|
||||
*/
|
||||
static int clean_host_name(char *host)
|
||||
{
|
||||
assert(host);
|
||||
if(host == NULL)
|
||||
return 0;
|
||||
for(; *host; host++)
|
||||
{
|
||||
if(!IsHostChar(*host))
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* nick_from_server()
|
||||
*/
|
||||
static int
|
||||
nick_from_server(struct Client *client_p, struct Client *source_p, int parc,
|
||||
char *parv[], time_t newts,char *nick)
|
||||
{
|
||||
if(IsServer(source_p))
|
||||
{
|
||||
/* A server introducing a new client, change source */
|
||||
source_p = make_client(client_p);
|
||||
add_client_to_list(source_p);
|
||||
|
||||
/* We don't need to introduce leafs clients back to them! */
|
||||
if (ConfigFileEntry.hub && IsCapable(client_p, CAP_LL))
|
||||
add_lazylinkclient(client_p, source_p);
|
||||
|
||||
if(parc > 2)
|
||||
source_p->hopcount = atoi(parv[2]);
|
||||
if(newts)
|
||||
source_p->tsinfo = newts;
|
||||
else
|
||||
{
|
||||
newts = source_p->tsinfo = CurrentTime;
|
||||
ts_warn("Remote nick %s (%s) introduced without a TS", nick, parv[0]);
|
||||
}
|
||||
|
||||
/* copy the nick in place */
|
||||
(void)strcpy(source_p->name, nick);
|
||||
(void)add_to_client_hash_table(nick, source_p);
|
||||
|
||||
if (parc > 8)
|
||||
{
|
||||
int flag;
|
||||
char *m;
|
||||
|
||||
/* parse usermodes */
|
||||
m = &parv[4][1];
|
||||
while (*m)
|
||||
{
|
||||
flag = user_modes_from_c_to_bitmask[(unsigned char)*m];
|
||||
if(!(source_p->umodes & FLAGS_INVISIBLE) && (flag & FLAGS_INVISIBLE))
|
||||
Count.invisi++;
|
||||
if(!(source_p->umodes & FLAGS_OPER) && (flag & FLAGS_OPER))
|
||||
Count.oper++;
|
||||
|
||||
source_p->umodes |= flag & SEND_UMODES;
|
||||
m++;
|
||||
}
|
||||
|
||||
return do_remote_user(nick, client_p, source_p, parv[5], parv[6],
|
||||
parv[7], parv[8], NULL);
|
||||
}
|
||||
}
|
||||
else if(source_p->name[0])
|
||||
{
|
||||
/* client changing their nick */
|
||||
if(irccmp(parv[0], nick))
|
||||
source_p->tsinfo = newts ? newts : CurrentTime;
|
||||
|
||||
sendto_common_channels_local(source_p, ":%s!%s@%s NICK :%s",
|
||||
source_p->name,source_p->username,source_p->host,
|
||||
nick);
|
||||
|
||||
if (source_p->user)
|
||||
{
|
||||
add_history(source_p,1);
|
||||
sendto_server(client_p, source_p, NULL, NOCAPS, NOCAPS, NOFLAGS,
|
||||
":%s NICK %s :%lu",
|
||||
parv[0], nick, (unsigned long) source_p->tsinfo);
|
||||
}
|
||||
}
|
||||
|
||||
/* set the new nick name */
|
||||
if(source_p->name[0])
|
||||
del_from_client_hash_table(source_p->name, source_p);
|
||||
|
||||
strcpy(source_p->name, nick);
|
||||
add_to_client_hash_table(nick, source_p);
|
||||
|
||||
/* remove all accepts pointing to the client */
|
||||
del_all_accepts(source_p);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* client_from_server()
|
||||
*/
|
||||
static int
|
||||
client_from_server(struct Client *client_p, struct Client *source_p, int parc,
|
||||
char *parv[], time_t newts,char *nick)
|
||||
{
|
||||
char *name;
|
||||
char *id;
|
||||
int flag;
|
||||
char *m;
|
||||
|
||||
id = parv[8];
|
||||
name = parv[9];
|
||||
|
||||
source_p = make_client(client_p);
|
||||
add_client_to_list(source_p);
|
||||
|
||||
/* We don't need to introduce leafs clients back to them! */
|
||||
if (ConfigFileEntry.hub && IsCapable(client_p, CAP_LL))
|
||||
add_lazylinkclient(client_p, source_p);
|
||||
|
||||
source_p->hopcount = atoi(parv[2]);
|
||||
source_p->tsinfo = newts;
|
||||
|
||||
/* copy the nick in place */
|
||||
(void)strcpy(source_p->name, nick);
|
||||
(void)add_to_client_hash_table(nick, source_p);
|
||||
add_to_id_hash_table(id, source_p);
|
||||
|
||||
/* parse usermodes */
|
||||
m = &parv[4][1];
|
||||
while (*m)
|
||||
{
|
||||
flag = user_modes_from_c_to_bitmask[(unsigned char)*m];
|
||||
if(flag & FLAGS_INVISIBLE)
|
||||
Count.invisi++;
|
||||
if(flag & FLAGS_OPER)
|
||||
Count.oper++;
|
||||
|
||||
source_p->umodes |= flag & SEND_UMODES;
|
||||
m++;
|
||||
|
||||
}
|
||||
|
||||
return do_remote_user(nick, client_p, source_p, parv[5], parv[6],
|
||||
parv[7], name, id);
|
||||
}
|
||||
|
||||
static int
|
||||
perform_nick_collides(struct Client *source_p, struct Client *client_p,
|
||||
struct Client *target_p, int parc, char *parv[],
|
||||
time_t newts, char *nick)
|
||||
{
|
||||
int sameuser;
|
||||
|
||||
/* server introducing new nick */
|
||||
if(IsServer(source_p))
|
||||
{
|
||||
/* if we dont have a ts, or their TS's are the same, kill both */
|
||||
if(!newts || !target_p->tsinfo ||
|
||||
(newts == target_p->tsinfo))
|
||||
{
|
||||
sendto_realops_flags(FLAGS_ALL, L_ALL,
|
||||
"Nick collision on %s(%s <- %s)(both killed)",
|
||||
target_p->name, target_p->from->name,
|
||||
client_p->name);
|
||||
|
||||
if(ServerInfo.hub && IsCapable(client_p,CAP_LL))
|
||||
add_lazylinkclient(client_p, target_p);
|
||||
|
||||
kill_client_ll_serv_butone(NULL, target_p,
|
||||
"%s (Nick collision (new))",
|
||||
me.name);
|
||||
ServerStats->is_kill++;
|
||||
sendto_one(target_p, form_str(ERR_NICKCOLLISION),
|
||||
me.name, target_p->name, target_p->name);
|
||||
|
||||
target_p->flags |= FLAGS_KILLED;
|
||||
exit_client(client_p, target_p, &me, "Nick collision (new)");
|
||||
return 0;
|
||||
}
|
||||
/* the timestamps are different */
|
||||
else
|
||||
{
|
||||
sameuser = (target_p->user) && !irccmp(target_p->username, parv[5])
|
||||
&& !irccmp(target_p->host, parv[6]);
|
||||
|
||||
/* if the users are the same (loaded a client on a different server)
|
||||
* and the new users ts is older, or the users are different and the
|
||||
* new users ts is newer, ignore the new client and let it do the kill
|
||||
*/
|
||||
if ((sameuser && newts < target_p->tsinfo) ||
|
||||
(!sameuser && newts > target_p->tsinfo))
|
||||
{
|
||||
client_burst_if_needed(client_p, target_p);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(sameuser)
|
||||
sendto_realops_flags(FLAGS_ALL, L_ALL,
|
||||
"Nick collision on %s(%s <- %s)(older killed)",
|
||||
target_p->name, target_p->from->name,
|
||||
client_p->name);
|
||||
else
|
||||
sendto_realops_flags(FLAGS_ALL, L_ALL,
|
||||
"Nick collision on %s(%s <- %s)(newer killed)",
|
||||
target_p->name, target_p->from->name,
|
||||
client_p->name);
|
||||
|
||||
ServerStats->is_kill++;
|
||||
sendto_one(target_p, form_str(ERR_NICKCOLLISION),
|
||||
me.name, target_p->name, target_p->name);
|
||||
|
||||
/* if it came from a LL server, itd have been source_p,
|
||||
* so we dont need to mark target_p as known
|
||||
*/
|
||||
kill_client_ll_serv_butone(source_p, target_p,
|
||||
"%s (Nick collision (new))",
|
||||
me.name);
|
||||
|
||||
target_p->flags |= FLAGS_KILLED;
|
||||
(void)exit_client(client_p, target_p, &me, "Nick collision");
|
||||
|
||||
if(parc == 9)
|
||||
nick_from_server(client_p,source_p,parc,parv,newts,nick);
|
||||
else if(parc == 10)
|
||||
client_from_server(client_p,source_p,parc,parv,newts,nick);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* its a client changing nick and causing a collide */
|
||||
if(!newts || !target_p->tsinfo || (newts == target_p->tsinfo) ||
|
||||
!source_p->user)
|
||||
{
|
||||
sendto_realops_flags(FLAGS_ALL, L_ALL,
|
||||
"Nick change collision from %s to %s(%s <- %s)(both killed)",
|
||||
source_p->name, target_p->name, target_p->from->name,
|
||||
client_p->name);
|
||||
|
||||
ServerStats->is_kill++;
|
||||
sendto_one(target_p, form_str(ERR_NICKCOLLISION),
|
||||
me.name, target_p->name, target_p->name);
|
||||
|
||||
/* if we got the message from a LL, it knows about source_p */
|
||||
kill_client_ll_serv_butone(NULL, source_p,
|
||||
"%s (Nick change collision)",
|
||||
me.name);
|
||||
|
||||
ServerStats->is_kill++;
|
||||
/* If we got the message from a LL, ensure it gets the kill */
|
||||
if(ServerInfo.hub && IsCapable(client_p,CAP_LL))
|
||||
add_lazylinkclient(client_p, target_p);
|
||||
|
||||
kill_client_ll_serv_butone(NULL, target_p,
|
||||
"%s (Nick change collision)",
|
||||
me.name);
|
||||
|
||||
target_p->flags |= FLAGS_KILLED;
|
||||
exit_client(NULL, target_p, &me, "Nick collision(new)");
|
||||
source_p->flags |= FLAGS_KILLED;
|
||||
exit_client(client_p, source_p, &me, "Nick collision(old)");
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
sameuser = !irccmp(target_p->username, source_p->username) &&
|
||||
!irccmp(target_p->host, source_p->host);
|
||||
|
||||
if ((sameuser && newts < target_p->tsinfo) ||
|
||||
(!sameuser && newts > target_p->tsinfo))
|
||||
{
|
||||
if(sameuser)
|
||||
sendto_realops_flags(FLAGS_ALL, L_ALL,
|
||||
"Nick change collision from %s to %s(%s <- %s)(older killed)",
|
||||
source_p->name, target_p->name, target_p->from->name,
|
||||
client_p->name);
|
||||
else
|
||||
sendto_realops_flags(FLAGS_ALL, L_ALL,
|
||||
"Nick change collision from %s to %s(%s <- %s)(newer killed)",
|
||||
source_p->name, target_p->name, target_p->from->name,
|
||||
client_p->name);
|
||||
|
||||
ServerStats->is_kill++;
|
||||
|
||||
/* this won't go back to the incoming link, so LL doesnt matter */
|
||||
kill_client_ll_serv_butone(client_p, source_p,
|
||||
"%s (Nick change collision)",
|
||||
me.name);
|
||||
|
||||
source_p->flags |= FLAGS_KILLED;
|
||||
|
||||
if(sameuser)
|
||||
exit_client(client_p, source_p, &me, "Nick collision(old)");
|
||||
else
|
||||
exit_client(client_p, source_p, &me, "Nick collision(new)");
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(sameuser)
|
||||
sendto_realops_flags(FLAGS_ALL, L_ALL,
|
||||
"Nick collision on %s(%s <- %s)(older killed)",
|
||||
target_p->name, target_p->from->name,
|
||||
client_p->name);
|
||||
else
|
||||
sendto_realops_flags(FLAGS_ALL, L_ALL,
|
||||
"Nick collision on %s(%s <- %s)(newer killed)",
|
||||
target_p->name, target_p->from->name,
|
||||
client_p->name);
|
||||
|
||||
kill_client_ll_serv_butone(source_p, target_p,
|
||||
"%s (Nick collision)",
|
||||
me.name);
|
||||
|
||||
ServerStats->is_kill++;
|
||||
sendto_one(target_p, form_str(ERR_NICKCOLLISION),
|
||||
me.name, target_p->name, target_p->name);
|
||||
|
||||
target_p->flags |= FLAGS_KILLED;
|
||||
(void)exit_client(client_p, target_p, &me, "Nick collision");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
if(HasID(source_p))
|
||||
client_from_server(client_p,source_p,parc,parv,newts,nick);
|
||||
else
|
||||
*/
|
||||
|
||||
/* we should only ever call nick_from_server() here, as
|
||||
* this is a client changing nick, not a new client
|
||||
*/
|
||||
nick_from_server(client_p,source_p,parc,parv,newts,nick);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
202
modules/core/m_part.c
Normal file
202
modules/core/m_part.c
Normal file
|
@ -0,0 +1,202 @@
|
|||
/*
|
||||
* ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
|
||||
* m_part.c: Parts a user from a channel.
|
||||
*
|
||||
* Copyright (C) 2002 by the past and present ircd coders, and others.
|
||||
*
|
||||
* 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 2 of the License, 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
* USA
|
||||
*
|
||||
* $Id: m_part.c,v 1.1 2002/08/14 05:47:41 fishwaldo Exp $
|
||||
*/
|
||||
|
||||
#include "stdinc.h"
|
||||
#include "tools.h"
|
||||
#include "handlers.h"
|
||||
#include "channel.h"
|
||||
#include "vchannel.h"
|
||||
#include "client.h"
|
||||
#include "common.h"
|
||||
#include "hash.h"
|
||||
#include "irc_string.h"
|
||||
#include "ircd.h"
|
||||
#include "list.h"
|
||||
#include "numeric.h"
|
||||
#include "send.h"
|
||||
#include "s_serv.h"
|
||||
#include "msg.h"
|
||||
#include "parse.h"
|
||||
#include "modules.h"
|
||||
#include "s_conf.h"
|
||||
#include "packet.h"
|
||||
|
||||
static void m_part(struct Client*, struct Client*, int, char**);
|
||||
void check_spambot_warning(struct Client *source_p, const char *name);
|
||||
|
||||
struct Message part_msgtab = {
|
||||
"PART", 0, 0, 2, 0, MFLG_SLOW, 0,
|
||||
{m_unregistered, m_part, m_part, m_part}
|
||||
};
|
||||
|
||||
#ifndef STATIC_MODULES
|
||||
void
|
||||
_modinit(void)
|
||||
{
|
||||
mod_add_cmd(&part_msgtab);
|
||||
}
|
||||
|
||||
void
|
||||
_moddeinit(void)
|
||||
{
|
||||
mod_del_cmd(&part_msgtab);
|
||||
}
|
||||
const char *_version = "$Revision: 1.1 $";
|
||||
#endif
|
||||
|
||||
static void part_one_client(struct Client *client_p,
|
||||
struct Client *source_p,
|
||||
char *name, char *reason);
|
||||
|
||||
|
||||
/*
|
||||
** m_part
|
||||
** parv[0] = sender prefix
|
||||
** parv[1] = channel
|
||||
** parv[2] = reason
|
||||
*/
|
||||
static void m_part(struct Client *client_p,
|
||||
struct Client *source_p,
|
||||
int parc,
|
||||
char *parv[])
|
||||
{
|
||||
char *p, *name;
|
||||
char reason[TOPICLEN+1];
|
||||
|
||||
if (*parv[1] == '\0')
|
||||
{
|
||||
sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
|
||||
me.name, parv[0], "PART");
|
||||
return;
|
||||
}
|
||||
|
||||
reason[0] = '\0';
|
||||
|
||||
if (parc > 2)
|
||||
strlcpy(reason, parv[2], TOPICLEN);
|
||||
|
||||
name = strtoken( &p, parv[1], ",");
|
||||
|
||||
/* Finish the flood grace period... */
|
||||
if(MyClient(source_p) && !IsFloodDone(source_p))
|
||||
flood_endgrace(source_p);
|
||||
|
||||
while(name)
|
||||
{
|
||||
part_one_client(client_p, source_p, name, reason);
|
||||
name = strtoken(&p, (char *)NULL, ",");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* part_one_client
|
||||
*
|
||||
* inputs - pointer to server
|
||||
* - pointer to source client to remove
|
||||
* - char pointer of name of channel to remove from
|
||||
* output - none
|
||||
* side effects - remove ONE client given the channel name
|
||||
*/
|
||||
static void part_one_client(struct Client *client_p,
|
||||
struct Client *source_p,
|
||||
char *name,
|
||||
char *reason)
|
||||
{
|
||||
struct Channel *chptr;
|
||||
struct Channel *bchan;
|
||||
|
||||
if ((chptr = hash_find_channel(name)) == NULL)
|
||||
{
|
||||
sendto_one(source_p, form_str(ERR_NOSUCHCHANNEL),
|
||||
me.name, source_p->name, name);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef VCHANS
|
||||
if (IsVchan(chptr) || HasVchans(chptr))
|
||||
{
|
||||
if(HasVchans(chptr))
|
||||
{
|
||||
/* Set chptr to actual channel, bchan to the base channel */
|
||||
bchan = chptr;
|
||||
chptr = map_vchan(bchan,source_p);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* chptr = chptr; */
|
||||
bchan = find_bchan(chptr);
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
bchan = chptr; /* not a vchan */
|
||||
|
||||
if (!chptr || !bchan || !IsMember(source_p, chptr))
|
||||
{
|
||||
sendto_one(source_p, form_str(ERR_NOTONCHANNEL),
|
||||
me.name, source_p->name, name);
|
||||
return;
|
||||
}
|
||||
if (MyConnect(source_p) && !IsOper(source_p))
|
||||
check_spambot_warning(source_p, NULL);
|
||||
|
||||
/*
|
||||
* Remove user from the old channel (if any)
|
||||
* only allow /part reasons in -m chans
|
||||
*/
|
||||
if(reason[0] && (is_any_op(chptr, source_p) || !MyConnect(source_p) ||
|
||||
((can_send(chptr, source_p) > 0 &&
|
||||
(source_p->firsttime + ConfigFileEntry.anti_spam_exit_message_time)
|
||||
< CurrentTime))))
|
||||
{
|
||||
sendto_server(client_p, NULL, chptr, CAP_UID, NOCAPS, NOFLAGS,
|
||||
":%s PART %s :%s", ID(source_p), chptr->chname,
|
||||
reason);
|
||||
sendto_server(client_p, NULL, chptr, NOCAPS, CAP_UID, NOFLAGS,
|
||||
":%s PART %s :%s", source_p->name, chptr->chname,
|
||||
reason);
|
||||
sendto_channel_local(ALL_MEMBERS,
|
||||
chptr, ":%s!%s@%s PART %s :%s",
|
||||
source_p->name,
|
||||
source_p->username,
|
||||
source_p->host,
|
||||
bchan->chname,
|
||||
reason);
|
||||
}
|
||||
else
|
||||
{
|
||||
sendto_server(client_p, NULL, chptr, CAP_UID, NOCAPS, NOFLAGS,
|
||||
":%s PART %s", ID(source_p), chptr->chname);
|
||||
sendto_server(client_p, NULL, chptr, NOCAPS, CAP_UID, NOFLAGS,
|
||||
":%s PART %s", source_p->name, chptr->chname);
|
||||
sendto_channel_local(ALL_MEMBERS,
|
||||
chptr, ":%s!%s@%s PART %s",
|
||||
source_p->name,
|
||||
source_p->username,
|
||||
source_p->host,
|
||||
bchan->chname);
|
||||
}
|
||||
remove_user_from_channel(chptr, source_p);
|
||||
}
|
115
modules/core/m_quit.c
Normal file
115
modules/core/m_quit.c
Normal file
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
* ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
|
||||
* m_quit.c: Makes a user quit from IRC.
|
||||
*
|
||||
* Copyright (C) 2002 by the past and present ircd coders, and others.
|
||||
*
|
||||
* 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 2 of the License, 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
* USA
|
||||
*
|
||||
* $Id: m_quit.c,v 1.1 2002/08/14 05:47:41 fishwaldo Exp $
|
||||
*/
|
||||
|
||||
#include "stdinc.h"
|
||||
#include "handlers.h"
|
||||
#include "client.h"
|
||||
#include "ircd.h"
|
||||
#include "numeric.h"
|
||||
#include "s_serv.h"
|
||||
#include "send.h"
|
||||
#include "msg.h"
|
||||
#include "parse.h"
|
||||
#include "modules.h"
|
||||
#include "s_conf.h"
|
||||
|
||||
static void m_quit(struct Client*, struct Client*, int, char**);
|
||||
static void ms_quit(struct Client*, struct Client*, int, char**);
|
||||
|
||||
struct Message quit_msgtab = {
|
||||
"QUIT", 0, 0, 0, 0, MFLG_SLOW | MFLG_UNREG, 0,
|
||||
{m_quit, m_quit, ms_quit, m_quit}
|
||||
};
|
||||
|
||||
#ifndef STATIC_MODULES
|
||||
void
|
||||
_modinit(void)
|
||||
{
|
||||
mod_add_cmd(&quit_msgtab);
|
||||
}
|
||||
|
||||
void
|
||||
_moddeinit(void)
|
||||
{
|
||||
mod_del_cmd(&quit_msgtab);
|
||||
}
|
||||
|
||||
const char *_version = "$Revision: 1.1 $";
|
||||
#endif
|
||||
/*
|
||||
** m_quit
|
||||
** parv[0] = sender prefix
|
||||
** parv[1] = comment
|
||||
*/
|
||||
static void m_quit(struct Client *client_p,
|
||||
struct Client *source_p,
|
||||
int parc,
|
||||
char *parv[])
|
||||
{
|
||||
char *comment = (parc > 1 && parv[1]) ? parv[1] : client_p->name;
|
||||
char reason [TOPICLEN + 1];
|
||||
|
||||
source_p->flags |= FLAGS_NORMALEX;
|
||||
if (strlen(comment) > (size_t) TOPICLEN)
|
||||
comment[TOPICLEN] = '\0';
|
||||
|
||||
if (ConfigFileEntry.client_exit && comment[0])
|
||||
{
|
||||
#ifndef VMS
|
||||
snprintf(reason, TOPICLEN, "Quit: %s", comment);
|
||||
#else
|
||||
sprintf(reason, "Quit: %s", comment);
|
||||
#endif
|
||||
comment = reason;
|
||||
}
|
||||
|
||||
if(!IsOper(source_p) &&
|
||||
(source_p->firsttime + ConfigFileEntry.anti_spam_exit_message_time)
|
||||
> CurrentTime)
|
||||
{
|
||||
comment = "Client Quit";
|
||||
}
|
||||
|
||||
exit_client(client_p, source_p, source_p, comment);
|
||||
}
|
||||
|
||||
/*
|
||||
** ms_quit
|
||||
** parv[0] = sender prefix
|
||||
** parv[1] = comment
|
||||
*/
|
||||
static void ms_quit(struct Client *client_p,
|
||||
struct Client *source_p,
|
||||
int parc,
|
||||
char *parv[])
|
||||
{
|
||||
char *comment = (parc > 1 && parv[1]) ? parv[1] : client_p->name;
|
||||
|
||||
source_p->flags |= FLAGS_NORMALEX;
|
||||
if (strlen(comment) > (size_t) TOPICLEN)
|
||||
comment[TOPICLEN] = '\0';
|
||||
|
||||
exit_client(client_p, source_p, source_p, comment);
|
||||
}
|
||||
|
654
modules/core/m_server.c
Normal file
654
modules/core/m_server.c
Normal file
|
@ -0,0 +1,654 @@
|
|||
/*
|
||||
* ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
|
||||
* m_server.c: Introduces a server.
|
||||
*
|
||||
* Copyright (C) 2002 by the past and present ircd coders, and others.
|
||||
*
|
||||
* 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 2 of the License, 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
* USA
|
||||
*
|
||||
* $Id: m_server.c,v 1.1 2002/08/14 05:47:41 fishwaldo Exp $
|
||||
*/
|
||||
|
||||
#include "stdinc.h"
|
||||
#include "tools.h"
|
||||
#include "handlers.h" /* m_server prototype */
|
||||
#include "client.h" /* client struct */
|
||||
#include "common.h" /* TRUE bleah */
|
||||
#include "event.h"
|
||||
#include "hash.h" /* add_to_client_hash_table */
|
||||
#include "irc_string.h"
|
||||
#include "ircd.h" /* me */
|
||||
#include "list.h" /* make_server */
|
||||
#include "numeric.h" /* ERR_xxx */
|
||||
#include "s_conf.h" /* struct ConfItem */
|
||||
#include "s_log.h" /* log level defines */
|
||||
#include "s_serv.h" /* server_estab, check_server, my_name_for_link */
|
||||
#include "s_stats.h" /* ServerStats */
|
||||
#include "scache.h" /* find_or_add */
|
||||
#include "send.h" /* sendto_one */
|
||||
#include "motd.h"
|
||||
#include "msg.h"
|
||||
#include "parse.h"
|
||||
#include "modules.h"
|
||||
|
||||
|
||||
static void mr_server(struct Client*, struct Client*, int, char **);
|
||||
static void ms_server(struct Client*, struct Client*, int, char **);
|
||||
|
||||
static int set_server_gecos(struct Client *, char *);
|
||||
|
||||
struct Message server_msgtab = {
|
||||
"SERVER", 0, 0, 3, 0, MFLG_SLOW | MFLG_UNREG, 0,
|
||||
{mr_server, m_registered, ms_server, m_registered}
|
||||
};
|
||||
|
||||
#ifndef STATIC_MODULES
|
||||
void
|
||||
_modinit(void)
|
||||
{
|
||||
mod_add_cmd(&server_msgtab);
|
||||
}
|
||||
|
||||
void
|
||||
_moddeinit(void)
|
||||
{
|
||||
mod_del_cmd(&server_msgtab);
|
||||
}
|
||||
const char *_version = "$Revision: 1.1 $";
|
||||
#endif
|
||||
|
||||
int bogus_host(char *host);
|
||||
struct Client *server_exists(char *);
|
||||
|
||||
/*
|
||||
* mr_server - SERVER message handler
|
||||
* parv[0] = sender prefix
|
||||
* parv[1] = servername
|
||||
* parv[2] = serverinfo/hopcount
|
||||
* parv[3] = serverinfo
|
||||
*/
|
||||
static void mr_server(struct Client *client_p, struct Client *source_p,
|
||||
int parc, char *parv[])
|
||||
{
|
||||
char info[REALLEN + 1];
|
||||
char *name;
|
||||
struct Client *target_p;
|
||||
int hop;
|
||||
|
||||
if (parc < 4)
|
||||
{
|
||||
sendto_one(client_p,"ERROR :No servername");
|
||||
exit_client(client_p, client_p, client_p, "Wrong number of args");
|
||||
return;
|
||||
}
|
||||
|
||||
name = parv[1];
|
||||
hop = atoi(parv[2]);
|
||||
strlcpy(info, parv[3], REALLEN);
|
||||
|
||||
/*
|
||||
* Reject a direct nonTS server connection if we're TS_ONLY -orabidoo
|
||||
*/
|
||||
if (!DoesTS(client_p))
|
||||
{
|
||||
sendto_realops_flags(FLAGS_ALL, L_ADMIN,"Link %s dropped, non-TS server",
|
||||
get_client_name(client_p, HIDE_IP));
|
||||
sendto_realops_flags(FLAGS_ALL, L_OPER,"Link %s dropped, non-TS server",
|
||||
get_client_name(client_p, MASK_IP));
|
||||
exit_client(client_p, client_p, client_p, "Non-TS server");
|
||||
return;
|
||||
}
|
||||
|
||||
if (bogus_host(name))
|
||||
{
|
||||
exit_client(client_p, client_p, client_p, "Bogus server name");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Now we just have to call check_server and everything should be
|
||||
* check for us... -A1kmm. */
|
||||
switch (check_server(name, client_p, CHECK_SERVER_NOCRYPTLINK))
|
||||
{
|
||||
case -1:
|
||||
if (ConfigFileEntry.warn_no_nline)
|
||||
{
|
||||
sendto_realops_flags(FLAGS_ALL, L_ADMIN,
|
||||
"Unauthorized server connection attempt from %s: No entry for "
|
||||
"servername %s", get_client_name(client_p, HIDE_IP), name);
|
||||
|
||||
sendto_realops_flags(FLAGS_ALL, L_OPER,
|
||||
"Unauthorized server connection attempt from %s: No entry for "
|
||||
"servername %s", get_client_name(client_p, MASK_IP), name);
|
||||
}
|
||||
|
||||
exit_client(client_p, client_p, client_p, "Invalid servername.");
|
||||
return;
|
||||
/* NOT REACHED */
|
||||
break;
|
||||
|
||||
case -2:
|
||||
sendto_realops_flags(FLAGS_ALL, L_ADMIN,
|
||||
"Unauthorized server connection attempt from %s: Bad password "
|
||||
"for server %s", get_client_name(client_p, HIDE_IP), name);
|
||||
|
||||
sendto_realops_flags(FLAGS_ALL, L_OPER,
|
||||
"Unauthorized server connection attempt from %s: Bad password "
|
||||
"for server %s", get_client_name(client_p, MASK_IP), name);
|
||||
|
||||
exit_client(client_p, client_p, client_p, "Invalid password.");
|
||||
return;
|
||||
/* NOT REACHED */
|
||||
break;
|
||||
|
||||
case -3:
|
||||
sendto_realops_flags(FLAGS_ALL, L_ADMIN,
|
||||
"Unauthorized server connection attempt from %s: Invalid host "
|
||||
"for server %s", get_client_name(client_p, HIDE_IP), name);
|
||||
|
||||
sendto_realops_flags(FLAGS_ALL, L_OPER,
|
||||
"Unauthorized server connection attempt from %s: Invalid host "
|
||||
"for server %s", get_client_name(client_p, MASK_IP), name);
|
||||
|
||||
exit_client(client_p, client_p, client_p, "Invalid host.");
|
||||
return;
|
||||
/* NOT REACHED */
|
||||
break;
|
||||
|
||||
/* servername is > HOSTLEN */
|
||||
case -4:
|
||||
sendto_realops_flags(FLAGS_ALL, L_ADMIN,
|
||||
"Invalid servername %s from %s",
|
||||
name, get_client_name(client_p, HIDE_IP));
|
||||
sendto_realops_flags(FLAGS_ALL, L_OPER,
|
||||
"Invalid servername %s from %s",
|
||||
name, get_client_name(client_p, MASK_IP));
|
||||
|
||||
exit_client(client_p, client_p, client_p, "Invalid servername.");
|
||||
return;
|
||||
/* NOT REACHED */
|
||||
break;
|
||||
}
|
||||
|
||||
if ((target_p = server_exists(name)))
|
||||
{
|
||||
/*
|
||||
* This link is trying feed me a server that I already have
|
||||
* access through another path -- multiple paths not accepted
|
||||
* currently, kill this link immediately!!
|
||||
*
|
||||
* Rather than KILL the link which introduced it, KILL the
|
||||
* youngest of the two links. -avalon
|
||||
*
|
||||
* Definitely don't do that here. This is from an unregistered
|
||||
* connect - A1kmm.
|
||||
*/
|
||||
sendto_realops_flags(FLAGS_ALL, L_ADMIN,
|
||||
"Attempt to re-introduce server %s from %s", name,
|
||||
get_client_name(client_p, HIDE_IP));
|
||||
|
||||
sendto_realops_flags(FLAGS_ALL, L_OPER,
|
||||
"Attempt to re-introduce server %s from %s", name,
|
||||
get_client_name(client_p, MASK_IP));
|
||||
|
||||
sendto_one(client_p, "ERROR :Server already exists.");
|
||||
exit_client(client_p, client_p, client_p, "Server Exists");
|
||||
return;
|
||||
}
|
||||
|
||||
if(ServerInfo.hub && IsCapable(client_p, CAP_LL))
|
||||
{
|
||||
if(IsCapable(client_p, CAP_HUB))
|
||||
{
|
||||
ClearCap(client_p,CAP_LL);
|
||||
sendto_realops_flags(FLAGS_ALL, L_ALL,
|
||||
"*** LazyLinks to a hub from a hub, thats a no-no.");
|
||||
}
|
||||
else
|
||||
{
|
||||
client_p->localClient->serverMask = nextFreeMask();
|
||||
|
||||
if(!client_p->localClient->serverMask)
|
||||
{
|
||||
sendto_realops_flags(FLAGS_ALL, L_ALL,
|
||||
"serverMask is full!");
|
||||
/* try and negotiate a non LL connect */
|
||||
ClearCap(client_p,CAP_LL);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (IsCapable(client_p, CAP_LL))
|
||||
{
|
||||
if(!IsCapable(client_p, CAP_HUB))
|
||||
{
|
||||
ClearCap(client_p,CAP_LL);
|
||||
sendto_realops_flags(FLAGS_ALL, L_ALL,
|
||||
"*** LazyLinks to a leaf from a leaf, thats a no-no.");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* if we are connecting (Handshake), we already have the name from the
|
||||
* C:line in client_p->name
|
||||
*/
|
||||
|
||||
strlcpy(client_p->name, name, HOSTLEN+1);
|
||||
set_server_gecos(client_p, info);
|
||||
client_p->hopcount = hop;
|
||||
server_estab(client_p);
|
||||
}
|
||||
|
||||
/*
|
||||
* ms_server - SERVER message handler
|
||||
* parv[0] = sender prefix
|
||||
* parv[1] = servername
|
||||
* parv[2] = serverinfo/hopcount
|
||||
* parv[3] = serverinfo
|
||||
*/
|
||||
static void ms_server(struct Client *client_p, struct Client *source_p,
|
||||
int parc, char *parv[])
|
||||
{
|
||||
char info[REALLEN + 1];
|
||||
/* same size as in s_misc.c */
|
||||
char* name;
|
||||
struct Client* target_p;
|
||||
struct Client* bclient_p;
|
||||
struct ConfItem* aconf;
|
||||
int hop;
|
||||
int hlined = 0;
|
||||
int llined = 0;
|
||||
dlink_node *ptr;
|
||||
|
||||
/* Just to be sure -A1kmm. */
|
||||
if (!IsServer(source_p))
|
||||
return;
|
||||
|
||||
if (parc < 4)
|
||||
{
|
||||
sendto_one(client_p,"ERROR :No servername");
|
||||
return;
|
||||
}
|
||||
|
||||
name = parv[1];
|
||||
hop = atoi(parv[2]);
|
||||
strlcpy(info, parv[3], REALLEN);
|
||||
|
||||
if ((target_p = server_exists(name)))
|
||||
{
|
||||
/*
|
||||
* This link is trying feed me a server that I already have
|
||||
* access through another path -- multiple paths not accepted
|
||||
* currently, kill this link immediately!!
|
||||
*
|
||||
* Rather than KILL the link which introduced it, KILL the
|
||||
* youngest of the two links. -avalon
|
||||
*
|
||||
* I think that we should exit the link itself, not the introducer,
|
||||
* and we should always exit the most recently received(i.e. the
|
||||
* one we are receiving this SERVER for. -A1kmm
|
||||
*
|
||||
* You *cant* do this, if you link somewhere, it bursts you a server
|
||||
* that already exists, then sends you a client burst, you squit the
|
||||
* server, but you keep getting the burst of clients on a server that
|
||||
* doesnt exist, although ircd can handle it, its not a realistic
|
||||
* solution.. --fl_
|
||||
*/
|
||||
/* It is behind a host-masked server. Completely ignore the
|
||||
* server message(don't propagate or we will delink from whoever
|
||||
* we propagate to). -A1kmm */
|
||||
if (irccmp(target_p->name, name) && target_p->from==client_p)
|
||||
return;
|
||||
|
||||
sendto_one(client_p, "ERROR :Server %s already exists", name);
|
||||
|
||||
sendto_realops_flags(FLAGS_ALL, L_ADMIN,
|
||||
"Link %s cancelled, server %s already exists",
|
||||
get_client_name(client_p, SHOW_IP), name);
|
||||
sendto_realops_flags(FLAGS_ALL, L_OPER,
|
||||
"Link %s cancelled, server %s already exists",
|
||||
client_p->name, name);
|
||||
|
||||
exit_client(client_p, client_p, &me, "Server Exists");
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* User nicks never have '.' in them and server names
|
||||
* must always have '.' in them.
|
||||
*/
|
||||
if (strchr(name,'.') == NULL)
|
||||
{
|
||||
/*
|
||||
* Server trying to use the same name as a person. Would
|
||||
* cause a fair bit of confusion. Enough to make it hellish
|
||||
* for a while and servers to send stuff to the wrong place.
|
||||
*/
|
||||
sendto_one(client_p,"ERROR :Nickname %s already exists!", name);
|
||||
sendto_realops_flags(FLAGS_ALL, L_ADMIN,
|
||||
"Link %s cancelled: Server/nick collision on %s",
|
||||
/* inpath */ get_client_name(client_p, HIDE_IP), name);
|
||||
sendto_realops_flags(FLAGS_ALL, L_OPER,
|
||||
"Link %s cancelled: Server/nick collision on %s",
|
||||
get_client_name(client_p, MASK_IP), name);
|
||||
exit_client(client_p, client_p, client_p, "Nick as Server");
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Server is informing about a new server behind
|
||||
* this link. Create REMOTE server structure,
|
||||
* add it to list and propagate word to my other
|
||||
* server links...
|
||||
*/
|
||||
if (parc == 1 || info[0] == '\0')
|
||||
{
|
||||
sendto_one(client_p, "ERROR :No server info specified for %s", name);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* See if the newly found server is behind a guaranteed
|
||||
* leaf. If so, close the link.
|
||||
*
|
||||
*/
|
||||
|
||||
for (aconf = ConfigItemList; aconf; aconf=aconf->next)
|
||||
{
|
||||
if ((aconf->status & (CONF_LEAF|CONF_HUB)) == 0)
|
||||
continue;
|
||||
|
||||
if (match(aconf->name, client_p->name))
|
||||
{
|
||||
if (aconf->status == CONF_HUB)
|
||||
{
|
||||
if(match(aconf->host, name))
|
||||
hlined++;
|
||||
}
|
||||
else if (aconf->status == CONF_LEAF)
|
||||
{
|
||||
if(match(aconf->host, name))
|
||||
llined++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Ok, this way this works is
|
||||
*
|
||||
* A server can have a CONF_HUB allowing it to introduce servers
|
||||
* behind it.
|
||||
*
|
||||
* connect {
|
||||
* name = "irc.bighub.net";
|
||||
* hub_mask="*";
|
||||
* ...
|
||||
*
|
||||
* That would allow "irc.bighub.net" to introduce anything it wanted..
|
||||
*
|
||||
* However
|
||||
*
|
||||
* connect {
|
||||
* name = "irc.somehub.fi";
|
||||
* hub_mask="*";
|
||||
* leaf_mask="*.edu";
|
||||
*...
|
||||
* Would allow this server in finland to hub anything but
|
||||
* .edu's
|
||||
*/
|
||||
|
||||
/* Ok, check client_p can hub the new server, and make sure it's not a LL */
|
||||
if (!hlined || (IsCapable(client_p, CAP_LL) && !IsCapable(client_p, CAP_HUB)))
|
||||
{
|
||||
/* OOOPs nope can't HUB */
|
||||
sendto_realops_flags(FLAGS_ALL, L_ADMIN, "Non-Hub link %s introduced %s.",
|
||||
get_client_name(client_p, HIDE_IP), name);
|
||||
|
||||
sendto_realops_flags(FLAGS_ALL, L_OPER,
|
||||
"Non-Hub link %s introduced %s.",
|
||||
get_client_name(client_p, MASK_IP), name);
|
||||
|
||||
exit_client(NULL, source_p, &me, "No matching hub_mask.");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check for the new server being leafed behind this HUB */
|
||||
if (llined)
|
||||
{
|
||||
/* OOOPs nope can't HUB this leaf */
|
||||
sendto_realops_flags(FLAGS_ALL, L_ADMIN,
|
||||
"Link %s introduced leafed server %s.",
|
||||
get_client_name(client_p, HIDE_IP), name);
|
||||
sendto_realops_flags(FLAGS_ALL, L_OPER,
|
||||
"Link %s introduced leafed server %s.",
|
||||
client_p->name, name);
|
||||
/* If it is new, we are probably misconfigured, so split the
|
||||
* non-hub server introducing this. Otherwise, split the new
|
||||
* server. -A1kmm.
|
||||
*/
|
||||
/* wastes too much bandwidth, generates too many errors on
|
||||
* larger networks, dont bother. --fl_
|
||||
*/
|
||||
#if 0
|
||||
if ((CurrentTime - source_p->firsttime) < 20)
|
||||
{
|
||||
exit_client(NULL, source_p, &me, "Leafed Server.");
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
sendto_one(source_p, ":%s SQUIT %s :Sorry, Leafed server.",
|
||||
me.name, name);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
exit_client(NULL, client_p, &me, "Leafed Server.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
target_p = make_client(client_p);
|
||||
make_server(target_p);
|
||||
target_p->hopcount = hop;
|
||||
|
||||
if(strlen(name) > HOSTLEN)
|
||||
{
|
||||
sendto_realops_flags(FLAGS_ALL, L_ADMIN,
|
||||
"Link %s introduced server with invalid servername %s",
|
||||
get_client_name(client_p, HIDE_IP), name);
|
||||
sendto_realops_flags(FLAGS_ALL, L_OPER,
|
||||
"Link %s introduced server with invalid servername %s",
|
||||
client_p->name, name);
|
||||
|
||||
exit_client(NULL, client_p, &me, "Invalid servername introduced.");
|
||||
return;
|
||||
}
|
||||
|
||||
strlcpy(target_p->name, name, HOSTLEN+1);
|
||||
|
||||
set_server_gecos(target_p, info);
|
||||
|
||||
target_p->serv->up = find_or_add(parv[0]);
|
||||
target_p->servptr = source_p;
|
||||
|
||||
SetServer(target_p);
|
||||
|
||||
Count.server++;
|
||||
|
||||
add_client_to_list(target_p);
|
||||
add_server_to_list(target_p);
|
||||
add_to_client_hash_table(target_p->name, target_p);
|
||||
add_client_to_llist(&(target_p->servptr->serv->servers), target_p);
|
||||
|
||||
|
||||
/*
|
||||
* Old sendto_serv_but_one() call removed because we now
|
||||
* need to send different names to different servers
|
||||
* (domain name matching)
|
||||
*/
|
||||
for (ptr = serv_list.head; ptr; ptr = ptr->next)
|
||||
{
|
||||
bclient_p = ptr->data;
|
||||
|
||||
if (bclient_p == client_p)
|
||||
continue;
|
||||
if (!(aconf = bclient_p->serv->sconf))
|
||||
{
|
||||
sendto_realops_flags(FLAGS_ALL, L_ADMIN,
|
||||
"Lost N-line for %s on %s. Closing",
|
||||
get_client_name(client_p, HIDE_IP), name);
|
||||
sendto_realops_flags(FLAGS_ALL, L_OPER,
|
||||
"Lost N-line for %s on %s. Closing",
|
||||
get_client_name(client_p, MASK_IP), name);
|
||||
exit_client(client_p, client_p, client_p, "Lost N line");
|
||||
return;
|
||||
}
|
||||
if (match(my_name_for_link(me.name, aconf), target_p->name))
|
||||
continue;
|
||||
|
||||
sendto_one(bclient_p, ":%s SERVER %s %d :%s%s",
|
||||
parv[0], target_p->name, hop + 1,
|
||||
target_p->hidden_server ? "(H) " : "",
|
||||
target_p->info);
|
||||
}
|
||||
|
||||
sendto_realops_flags(FLAGS_EXTERNAL, L_ALL,
|
||||
"Server %s being introduced by %s",
|
||||
target_p->name, source_p->name);
|
||||
|
||||
}
|
||||
|
||||
/* set_server_gecos()
|
||||
*
|
||||
* input - pointer to client
|
||||
* output - none
|
||||
* side effects - servers gecos field is set
|
||||
*/
|
||||
static int set_server_gecos(struct Client *client_p, char *info)
|
||||
{
|
||||
/* check the info for [IP] */
|
||||
if(info[0])
|
||||
{
|
||||
char *p;
|
||||
char *s;
|
||||
char *t;
|
||||
|
||||
s = info;
|
||||
|
||||
/* we should only check the first word for an ip */
|
||||
if((p = strchr(s, ' ')))
|
||||
*p = '\0';
|
||||
|
||||
/* check for a ] which would symbolise an [IP] */
|
||||
if((t = strchr(s, ']')))
|
||||
{
|
||||
/* set s to after the first space */
|
||||
if(p)
|
||||
s = ++p;
|
||||
else
|
||||
s = NULL;
|
||||
}
|
||||
/* no ], put the space back */
|
||||
else if(p)
|
||||
*p = ' ';
|
||||
|
||||
/* p may have been set to a trailing space, so check s exists and that
|
||||
* it isnt \0 */
|
||||
if(s && (*s != '\0'))
|
||||
{
|
||||
/* a space? if not (H) could be the last part of info.. */
|
||||
if((p = strchr(s, ' ')))
|
||||
*p = '\0';
|
||||
|
||||
/* check for (H) which is a hidden server */
|
||||
if(!strcmp(s, "(H)"))
|
||||
{
|
||||
client_p->hidden_server = 1;
|
||||
|
||||
/* if there was no space.. theres nothing to set info to */
|
||||
if(p)
|
||||
s = ++p;
|
||||
else
|
||||
s = NULL;
|
||||
}
|
||||
else if(p)
|
||||
*p = ' ';
|
||||
|
||||
/* if there was a trailing space, s could point to \0, so check */
|
||||
if(s && (*s != '\0'))
|
||||
strlcpy(client_p->info, s, REALLEN);
|
||||
else
|
||||
strlcpy(client_p->info, "(Unknown Location)", REALLEN);
|
||||
}
|
||||
else
|
||||
strlcpy(client_p->info, "(Unknown Location)", REALLEN);
|
||||
}
|
||||
else
|
||||
strlcpy(client_p->info, "(Unknown Location)", REALLEN);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* bogus_host
|
||||
*
|
||||
* inputs - hostname
|
||||
* output - 1 if a bogus hostname input, 0 if its valid
|
||||
* side effects - none
|
||||
*/
|
||||
int bogus_host(char *host)
|
||||
{
|
||||
int bogus_server = 0;
|
||||
char *s;
|
||||
int dots = 0;
|
||||
|
||||
for( s = host; *s; s++ )
|
||||
{
|
||||
if (!IsServChar(*s))
|
||||
{
|
||||
bogus_server = 1;
|
||||
break;
|
||||
}
|
||||
if ('.' == *s)
|
||||
++dots;
|
||||
}
|
||||
|
||||
if (!dots || bogus_server )
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* server_exists()
|
||||
*
|
||||
* inputs - servername
|
||||
* output - 1 if server exists, 0 if doesnt exist
|
||||
*/
|
||||
struct Client *server_exists(char *servername)
|
||||
{
|
||||
struct Client *target_p;
|
||||
dlink_node *ptr;
|
||||
|
||||
for(ptr = global_serv_list.head; ptr; ptr = ptr->next)
|
||||
{
|
||||
target_p = ptr->data;
|
||||
|
||||
if(match(target_p->name, servername) ||
|
||||
match(servername, target_p->name))
|
||||
return target_p;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
935
modules/core/m_sjoin.c
Normal file
935
modules/core/m_sjoin.c
Normal file
|
@ -0,0 +1,935 @@
|
|||
/*
|
||||
* ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
|
||||
* m_sjoin.c: Joins a user to a channel.
|
||||
*
|
||||
* Copyright (C) 2002 by the past and present ircd coders, and others.
|
||||
*
|
||||
* 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 2 of the License, 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
* USA
|
||||
*
|
||||
* $Id: m_sjoin.c,v 1.1 2002/08/14 05:47:41 fishwaldo Exp $
|
||||
*/
|
||||
|
||||
#include "stdinc.h"
|
||||
#include "tools.h"
|
||||
#include "handlers.h"
|
||||
#include "channel.h"
|
||||
#include "channel_mode.h"
|
||||
#include "vchannel.h"
|
||||
#include "client.h"
|
||||
#include "hash.h"
|
||||
#include "irc_string.h"
|
||||
#include "ircd.h"
|
||||
#include "list.h"
|
||||
#include "numeric.h"
|
||||
#include "send.h"
|
||||
#include "common.h"
|
||||
#include "msg.h"
|
||||
#include "parse.h"
|
||||
#include "modules.h"
|
||||
#include "s_serv.h"
|
||||
#include "s_conf.h"
|
||||
|
||||
|
||||
static void ms_sjoin(struct Client*, struct Client*, int, char**);
|
||||
|
||||
struct Message sjoin_msgtab = {
|
||||
"SJOIN", 0, 0, 0, 0, MFLG_SLOW, 0,
|
||||
{m_unregistered, m_ignore, ms_sjoin, m_ignore}
|
||||
};
|
||||
|
||||
#ifndef STATIC_MODULES
|
||||
void
|
||||
_modinit(void)
|
||||
{
|
||||
mod_add_cmd(&sjoin_msgtab);
|
||||
}
|
||||
|
||||
void
|
||||
_moddeinit(void)
|
||||
{
|
||||
mod_del_cmd(&sjoin_msgtab);
|
||||
}
|
||||
|
||||
const char *_version = "$Revision: 1.1 $";
|
||||
#endif
|
||||
/*
|
||||
* ms_sjoin
|
||||
* parv[0] - sender
|
||||
* parv[1] - TS
|
||||
* parv[2] - channel
|
||||
* parv[3] - modes + n arguments (key and/or limit)
|
||||
* parv[4+n] - flags+nick list (all in one parameter)
|
||||
*
|
||||
* process a SJOIN, taking the TS's into account to either ignore the
|
||||
* incoming modes or undo the existing ones or merge them, and JOIN
|
||||
* all the specified users while sending JOIN/MODEs to local clients
|
||||
*/
|
||||
|
||||
static char modebuf[MODEBUFLEN];
|
||||
static char parabuf[MODEBUFLEN];
|
||||
static char *para[MAXMODEPARAMS];
|
||||
static char *mbuf;
|
||||
static int pargs;
|
||||
|
||||
static void set_final_mode(struct Mode *mode,struct Mode *oldmode);
|
||||
static void remove_our_modes(int type,
|
||||
struct Channel *chptr, struct Channel *top_chptr,
|
||||
struct Client *source_p);
|
||||
|
||||
static void remove_a_mode(int hide_or_not,
|
||||
struct Channel *chptr, struct Channel *top_chptr,
|
||||
struct Client *source_p, dlink_list *list, char flag);
|
||||
|
||||
|
||||
static void ms_sjoin(struct Client *client_p,
|
||||
struct Client *source_p,
|
||||
int parc,
|
||||
char *parv[])
|
||||
{
|
||||
struct Channel *chptr;
|
||||
struct Channel *top_chptr=NULL; /* XXX vchans */
|
||||
struct Client *target_p, *lclient_p;
|
||||
time_t newts;
|
||||
time_t oldts;
|
||||
time_t tstosend;
|
||||
static struct Mode mode, *oldmode;
|
||||
int args = 0;
|
||||
int keep_our_modes = 1;
|
||||
int keep_new_modes = 1;
|
||||
int doesop = 0;
|
||||
int fl;
|
||||
int people = 0;
|
||||
int num_prefix=0;
|
||||
int isnew;
|
||||
int buflen = 0;
|
||||
register char *s, *nhops;
|
||||
static char buf[2*BUFSIZE]; /* buffer for modes and prefix */
|
||||
static char sjbuf_nhops[BUFSIZE]; /* buffer with halfops as @ */
|
||||
char *p; /* pointer used making sjbuf */
|
||||
int hide_or_not;
|
||||
int i;
|
||||
dlink_node *m;
|
||||
#ifdef HALFOPS
|
||||
static char sjbuf_hops[BUFSIZE]; /* buffer with halfops as % */
|
||||
register char *hops;
|
||||
#endif
|
||||
#ifdef VCHANS
|
||||
int vc_ts = 0;
|
||||
#endif
|
||||
|
||||
*buf = '\0';
|
||||
#ifdef HALFOPS
|
||||
*sjbuf_hops = '\0';
|
||||
#endif
|
||||
*sjbuf_nhops = '\0';
|
||||
|
||||
if (IsClient(source_p) || parc < 5)
|
||||
return;
|
||||
|
||||
if (!IsChannelName(parv[2]))
|
||||
return;
|
||||
if (!check_channel_name(parv[2]))
|
||||
return;
|
||||
|
||||
/* SJOIN's for local channels can't happen. */
|
||||
if (*parv[2] == '&')
|
||||
return;
|
||||
|
||||
mbuf = modebuf;
|
||||
*mbuf = '\0';
|
||||
pargs = 0;
|
||||
newts = atol(parv[1]);
|
||||
|
||||
mode.mode = 0;
|
||||
mode.limit = 0;
|
||||
mode.key[0] = '\0';;
|
||||
s = parv[3];
|
||||
while (*s)
|
||||
switch(*(s++))
|
||||
{
|
||||
case 'i':
|
||||
mode.mode |= MODE_INVITEONLY;
|
||||
break;
|
||||
case 'n':
|
||||
mode.mode |= MODE_NOPRIVMSGS;
|
||||
break;
|
||||
case 'p':
|
||||
mode.mode |= MODE_PRIVATE;
|
||||
break;
|
||||
case 's':
|
||||
mode.mode |= MODE_SECRET;
|
||||
break;
|
||||
case 'm':
|
||||
mode.mode |= MODE_MODERATED;
|
||||
break;
|
||||
case 't':
|
||||
mode.mode |= MODE_TOPICLIMIT;
|
||||
break;
|
||||
#ifdef ANONOPS
|
||||
case 'a':
|
||||
if(ConfigChannel.use_anonops)
|
||||
mode.mode |= MODE_HIDEOPS;
|
||||
break;
|
||||
#endif
|
||||
case 'k':
|
||||
strlcpy(mode.key, parv[4 + args], KEYLEN);
|
||||
args++;
|
||||
if (parc < 5+args)
|
||||
return;
|
||||
break;
|
||||
case 'l':
|
||||
mode.limit = atoi(parv[4+args]);
|
||||
args++;
|
||||
if (parc < 5+args)
|
||||
return;
|
||||
break;
|
||||
}
|
||||
|
||||
*parabuf = '\0';
|
||||
|
||||
if ((chptr = get_or_create_channel(source_p, parv[2], &isnew)) == NULL)
|
||||
return; /* channel name too long? */
|
||||
|
||||
/* XXX vchan cruft */
|
||||
/* vchans are encoded as "##mainchanname_timestamp" */
|
||||
|
||||
#ifdef VCHANS
|
||||
if ( (parv[2][1] == '#') && (ConfigChannel.use_vchans) )
|
||||
{
|
||||
char *subp;
|
||||
|
||||
/* possible sub vchan being sent along ? */
|
||||
if ((subp = strrchr(parv[2],'_')))
|
||||
{
|
||||
vc_ts = atol(subp+1);
|
||||
/*
|
||||
* XXX - Could be a vchan, but we can't be _sure_
|
||||
*
|
||||
* We now test the timestamp matches below,
|
||||
* but that can still be faked.
|
||||
*
|
||||
* If there was some way to pass an extra bit of
|
||||
* information over non-hybrid-7 servers, through SJOIN,
|
||||
* we could tell other servers that it's a vchan.
|
||||
* That's probably not possible, unfortunately :(
|
||||
*/
|
||||
|
||||
*subp = '\0'; /* fugly hack for now ... */
|
||||
|
||||
/* + 1 skip the extra '#' in the name */
|
||||
if ((top_chptr = hash_find_channel(parv[2] + 1)) != NULL)
|
||||
{
|
||||
/* If the vchan is already in the vchan_list for this
|
||||
* root, don't re-add it.
|
||||
*/
|
||||
/* Compare timestamps too */
|
||||
if (dlinkFind(&top_chptr->vchan_list,chptr) == NULL &&
|
||||
newts == vc_ts)
|
||||
{
|
||||
m = make_dlink_node();
|
||||
dlinkAdd(chptr, m, &top_chptr->vchan_list);
|
||||
chptr->root_chptr=top_chptr;
|
||||
}
|
||||
}
|
||||
/* check TS before creating a root channel */
|
||||
else if (newts == vc_ts)
|
||||
{
|
||||
top_chptr = get_or_create_channel(source_p, (parv[2] + 1), NULL);
|
||||
m = make_dlink_node();
|
||||
dlinkAdd(chptr, m, &top_chptr->vchan_list);
|
||||
chptr->root_chptr=top_chptr;
|
||||
/* let users access it somehow... */
|
||||
chptr->vchan_id[0] = '!';
|
||||
chptr->vchan_id[1] = '\0';
|
||||
}
|
||||
|
||||
*subp = '_'; /* fugly hack, restore '_' */
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
oldts = chptr->channelts;
|
||||
|
||||
doesop = (parv[4+args][0] == '@' || parv[4+args][1] == '@');
|
||||
|
||||
oldmode = &chptr->mode;
|
||||
|
||||
#ifdef IGNORE_BOGUS_TS
|
||||
if (newts < 800000000)
|
||||
{
|
||||
sendto_realops_flags(FLAGS_DEBUG, L_ALL,
|
||||
"*** Bogus TS %lu on %s ignored from %s",
|
||||
(unsigned long) newts,
|
||||
chptr->chname,
|
||||
client_p->name);
|
||||
|
||||
newts = (oldts==0) ? oldts : 800000000;
|
||||
}
|
||||
#else
|
||||
|
||||
if(!isnew && !newts && oldts)
|
||||
{
|
||||
sendto_channel_local(ALL_MEMBERS, chptr,
|
||||
":%s NOTICE %s :*** Notice -- TS for %s changed from %lu to 0",
|
||||
me.name, chptr->chname, chptr->chname, oldts);
|
||||
sendto_realops_flags(FLAGS_ALL, L_ALL,
|
||||
"Server %s changing TS on %s from %lu to 0",
|
||||
source_p->name, chptr->chname, oldts);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* XXX - this no doubt destroys vchans
|
||||
*/
|
||||
if (isnew)
|
||||
chptr->channelts = tstosend = newts;
|
||||
/* Remote is sending users to a permanent channel.. we need to drop our
|
||||
* version and use theirs, to keep compatibility -- fl */
|
||||
else if (chptr->users == 0 && parv[4+args][0])
|
||||
{
|
||||
keep_our_modes = NO;
|
||||
chptr->channelts = tstosend = newts;
|
||||
}
|
||||
/* They're not sending users, lets just ignore it and carry on */
|
||||
else if (chptr->users == 0 && !parv[4+args][0])
|
||||
return;
|
||||
|
||||
/* It isnt a perm channel, do normal timestamp rules */
|
||||
else if (newts == 0 || oldts == 0)
|
||||
chptr->channelts = tstosend = 0;
|
||||
else if (!newts)
|
||||
chptr->channelts = tstosend = oldts;
|
||||
else if (newts == oldts)
|
||||
tstosend = oldts;
|
||||
else if (newts < oldts)
|
||||
{
|
||||
keep_our_modes = NO;
|
||||
chptr->channelts = tstosend = newts;
|
||||
}
|
||||
else
|
||||
{
|
||||
keep_new_modes = NO;
|
||||
tstosend = oldts;
|
||||
}
|
||||
|
||||
if (!keep_new_modes)
|
||||
mode = *oldmode;
|
||||
else if (keep_our_modes)
|
||||
{
|
||||
mode.mode |= oldmode->mode;
|
||||
if (oldmode->limit > mode.limit)
|
||||
mode.limit = oldmode->limit;
|
||||
if (strcmp(mode.key, oldmode->key) < 0)
|
||||
strcpy(mode.key, oldmode->key);
|
||||
}
|
||||
|
||||
#ifdef ANONOPS
|
||||
if (mode.mode & MODE_HIDEOPS)
|
||||
hide_or_not = ONLY_CHANOPS_HALFOPS;
|
||||
else
|
||||
#endif
|
||||
hide_or_not = ALL_MEMBERS;
|
||||
|
||||
#ifdef ANONOPS
|
||||
if ((MODE_HIDEOPS & mode.mode) && !(MODE_HIDEOPS & oldmode->mode))
|
||||
sync_channel_oplists(chptr, MODE_DEL);
|
||||
|
||||
/* Don't reveal the ops, only to remove them all */
|
||||
if (keep_our_modes)
|
||||
if (!(MODE_HIDEOPS & mode.mode) && (MODE_HIDEOPS & oldmode->mode))
|
||||
sync_channel_oplists(chptr, MODE_ADD);
|
||||
#endif
|
||||
|
||||
set_final_mode(&mode,oldmode);
|
||||
chptr->mode = mode;
|
||||
|
||||
/* Lost the TS, other side wins, so remove modes on this side */
|
||||
if (!keep_our_modes)
|
||||
{
|
||||
remove_our_modes(hide_or_not, chptr, top_chptr, source_p);
|
||||
sendto_channel_local(ALL_MEMBERS, chptr,
|
||||
":%s NOTICE %s :*** Notice -- TS for %s changed from %lu to %lu",
|
||||
me.name, chptr->chname, chptr->chname, oldts, newts);
|
||||
}
|
||||
|
||||
if (*modebuf != '\0')
|
||||
{
|
||||
/* This _SHOULD_ be to ALL_MEMBERS
|
||||
* It contains only +aimnstlki, etc */
|
||||
if (top_chptr != NULL)
|
||||
sendto_channel_local(ALL_MEMBERS,
|
||||
chptr, ":%s MODE %s %s %s",
|
||||
me.name,
|
||||
top_chptr->chname, modebuf, parabuf);
|
||||
else
|
||||
sendto_channel_local(ALL_MEMBERS,
|
||||
chptr, ":%s MODE %s %s %s",
|
||||
me.name,
|
||||
chptr->chname, modebuf, parabuf);
|
||||
}
|
||||
|
||||
*modebuf = *parabuf = '\0';
|
||||
if (parv[3][0] != '0' && keep_new_modes)
|
||||
{
|
||||
channel_modes(chptr, source_p, modebuf, parabuf);
|
||||
}
|
||||
else
|
||||
{
|
||||
modebuf[0] = '0';
|
||||
modebuf[1] = '\0';
|
||||
}
|
||||
|
||||
buflen = ircsprintf(buf, ":%s SJOIN %lu %s %s %s:",
|
||||
parv[0],
|
||||
(unsigned long) tstosend,
|
||||
parv[2], modebuf, parabuf);
|
||||
|
||||
/* check we can fit a nick on the end, as well as \r\n\0 and a prefix "
|
||||
* @+".
|
||||
*/
|
||||
if (buflen >= (BUFSIZE - 6 - NICKLEN))
|
||||
{
|
||||
sendto_realops_flags(FLAGS_ALL, L_ALL,
|
||||
"Long SJOIN from server: %s(via %s) (ignored)",
|
||||
source_p->name, client_p->name);
|
||||
return;
|
||||
}
|
||||
|
||||
mbuf = modebuf;
|
||||
para[0] = para[1] = para[2] = para[3] = "";
|
||||
pargs = 0;
|
||||
|
||||
*mbuf++ = '+';
|
||||
|
||||
#ifdef HALFOPS
|
||||
hops = sjbuf_hops;
|
||||
#endif
|
||||
nhops = sjbuf_nhops;
|
||||
|
||||
s = parv[args+4];
|
||||
|
||||
/* remove any leading spaces */
|
||||
while(*s == ' ')
|
||||
{
|
||||
s++;
|
||||
}
|
||||
|
||||
/* if theres a space, theres going to be more than one nick, change the
|
||||
* first space to \0, so s is just the first nick, and point p to the
|
||||
* second nick
|
||||
*/
|
||||
if ((p = strchr(s, ' ')) != NULL)
|
||||
{
|
||||
*p++ = '\0';
|
||||
}
|
||||
|
||||
while (s)
|
||||
{
|
||||
fl = 0;
|
||||
num_prefix = 0;
|
||||
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
if (*s == '@')
|
||||
{
|
||||
fl |= MODE_CHANOP;
|
||||
if (keep_new_modes)
|
||||
{
|
||||
#ifdef HALFOPS
|
||||
*hops++ = *s;
|
||||
#endif
|
||||
*nhops++ = *s;
|
||||
num_prefix++;
|
||||
}
|
||||
|
||||
s++;
|
||||
}
|
||||
else if (*s == '+')
|
||||
{
|
||||
fl |= MODE_VOICE;
|
||||
if (keep_new_modes)
|
||||
{
|
||||
#ifdef HALFOPS
|
||||
*hops++ = *s;
|
||||
#endif
|
||||
*nhops++ = *s;
|
||||
num_prefix++;
|
||||
}
|
||||
|
||||
s++;
|
||||
}
|
||||
else if (*s == '%')
|
||||
{
|
||||
#ifdef HALFOPS
|
||||
fl |= MODE_HALFOP;
|
||||
#else
|
||||
fl |= MODE_CHANOP;
|
||||
#endif
|
||||
if (keep_new_modes)
|
||||
{
|
||||
#ifdef HALFOPS
|
||||
*hops++ = *s;
|
||||
#endif
|
||||
*nhops++ = '@';
|
||||
num_prefix++;
|
||||
}
|
||||
|
||||
s++;
|
||||
}
|
||||
}
|
||||
|
||||
/* if the client doesnt exist, backtrack over the prefix (@%+) that we
|
||||
* just added and skip to the next nick
|
||||
*/
|
||||
/* also do this if its fake direction or a server */
|
||||
if (!(target_p = find_client(s)) ||
|
||||
(target_p->from != client_p) || !IsPerson(target_p))
|
||||
{
|
||||
sendto_one(source_p, form_str(ERR_NOSUCHNICK), me.name,
|
||||
source_p->name, s);
|
||||
|
||||
#ifdef HALFOPS
|
||||
hops -= num_prefix;
|
||||
*hops = '\0';
|
||||
#endif
|
||||
|
||||
nhops -= num_prefix;
|
||||
*nhops = '\0';
|
||||
|
||||
goto nextnick;
|
||||
}
|
||||
|
||||
/* copy the nick to the two buffers */
|
||||
#ifdef HALFOPS
|
||||
hops += ircsprintf(hops, "%s ", s);
|
||||
assert((hops - sjbuf_hops) < sizeof(sjbuf_hops));
|
||||
#endif
|
||||
|
||||
nhops += ircsprintf(nhops, "%s ", s);
|
||||
assert((nhops-sjbuf_nhops) < sizeof(sjbuf_nhops));
|
||||
|
||||
if (!keep_new_modes)
|
||||
{
|
||||
if ((fl & MODE_CHANOP) || (fl & MODE_HALFOP))
|
||||
{
|
||||
fl = MODE_DEOPPED;
|
||||
}
|
||||
else
|
||||
{
|
||||
fl = 0;
|
||||
}
|
||||
}
|
||||
|
||||
people++;
|
||||
|
||||
/* LazyLinks - Introduce unknown clients before sending the sjoin */
|
||||
if (ServerInfo.hub)
|
||||
{
|
||||
for (m = serv_list.head; m; m = m->next)
|
||||
{
|
||||
lclient_p = m->data;
|
||||
|
||||
/* Hopefully, the server knows about it's own clients. */
|
||||
if (client_p == lclient_p)
|
||||
continue;
|
||||
|
||||
/* Ignore non lazylinks */
|
||||
if (!IsCapable(lclient_p,CAP_LL))
|
||||
continue;
|
||||
|
||||
/* Ignore servers we won't tell anyway */
|
||||
if (!(RootChan(chptr)->lazyLinkChannelExists &
|
||||
lclient_p->localClient->serverMask) )
|
||||
continue;
|
||||
|
||||
/* Ignore servers that already know target_p */
|
||||
if (!(target_p->lazyLinkClientExists &
|
||||
lclient_p->localClient->serverMask) )
|
||||
{
|
||||
/* Tell LazyLink Leaf about client_p,
|
||||
* as the leaf is about to get a SJOIN */
|
||||
sendnick_TS( lclient_p, target_p );
|
||||
add_lazylinkclient(lclient_p,target_p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!IsMember(target_p, chptr))
|
||||
{
|
||||
add_user_to_channel(chptr, target_p, fl);
|
||||
/* XXX vchan stuff */
|
||||
|
||||
#ifdef VCHANS
|
||||
if (top_chptr)
|
||||
{
|
||||
add_vchan_to_client_cache(target_p,top_chptr, chptr);
|
||||
sendto_channel_local(ALL_MEMBERS,chptr, ":%s!%s@%s JOIN :%s",
|
||||
target_p->name,
|
||||
target_p->username,
|
||||
target_p->host,
|
||||
top_chptr->chname);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
sendto_channel_local(ALL_MEMBERS,chptr, ":%s!%s@%s JOIN :%s",
|
||||
target_p->name,
|
||||
target_p->username,
|
||||
target_p->host,
|
||||
parv[2]);
|
||||
}
|
||||
}
|
||||
|
||||
if (fl & MODE_CHANOP)
|
||||
{
|
||||
*mbuf++ = 'o';
|
||||
para[pargs++] = s;
|
||||
|
||||
#ifdef REQUIRE_OANDV
|
||||
/* a +ov user.. bleh */
|
||||
if(fl & MODE_VOICE)
|
||||
{
|
||||
/* its possible the +o has filled up MAXMODEPARAMS, if so, start
|
||||
* a new buffer
|
||||
*/
|
||||
if(pargs >= MAXMODEPARAMS)
|
||||
{
|
||||
*mbuf = '\0';
|
||||
sendto_channel_local(hide_or_not, chptr,
|
||||
":%s MODE %s %s %s %s %s %s",
|
||||
me.name, RootChan(chptr)->chname,
|
||||
modebuf,
|
||||
para[0], para[1], para[2], para[3]);
|
||||
mbuf = modebuf;
|
||||
*mbuf++ = '+';
|
||||
para[0] = para[1] = para[2] = para[3] = "";
|
||||
pargs = 0;
|
||||
}
|
||||
|
||||
*mbuf++ = 'v';
|
||||
para[pargs++] = s;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else if (fl & MODE_VOICE)
|
||||
{
|
||||
*mbuf++ = 'v';
|
||||
para[pargs++] = s;
|
||||
}
|
||||
#ifdef HALFOPS
|
||||
else if (fl & MODE_HALFOP)
|
||||
{
|
||||
*mbuf++ = 'h';
|
||||
para[pargs++] = s;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (pargs >= MAXMODEPARAMS)
|
||||
{
|
||||
*mbuf = '\0';
|
||||
sendto_channel_local(hide_or_not, chptr,
|
||||
":%s MODE %s %s %s %s %s %s",
|
||||
me.name,
|
||||
RootChan(chptr)->chname,
|
||||
modebuf,
|
||||
para[0],para[1],para[2],para[3]);
|
||||
mbuf = modebuf;
|
||||
*mbuf++ = '+';
|
||||
para[0] = para[1] = para[2] = para[3] = "";
|
||||
pargs = 0;
|
||||
}
|
||||
|
||||
nextnick:
|
||||
/* p points to the next nick */
|
||||
s = p;
|
||||
|
||||
/* if there was a trailing space and p was pointing to it, then we
|
||||
* need to exit.. this has the side effect of breaking double spaces
|
||||
* in an sjoin.. but that shouldnt happen anyway
|
||||
*/
|
||||
if (s && (*s == '\0'))
|
||||
s = p = NULL;
|
||||
|
||||
/* if p was NULL due to no spaces, s wont exist due to the above, so
|
||||
* we cant check it for spaces.. if there are no spaces, then when
|
||||
* we next get here, s will be NULL
|
||||
*/
|
||||
if (s && ((p = strchr(s, ' ')) != NULL))
|
||||
{
|
||||
*p++ = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
*mbuf = '\0';
|
||||
if (pargs)
|
||||
{
|
||||
sendto_channel_local(hide_or_not, chptr,
|
||||
":%s MODE %s %s %s %s %s %s",
|
||||
me.name,
|
||||
RootChan(chptr)->chname,
|
||||
modebuf,
|
||||
para[0], para[1], para[2], para[3]);
|
||||
}
|
||||
|
||||
if (!people)
|
||||
return;
|
||||
|
||||
/* relay the SJOIN to other servers */
|
||||
for(m = serv_list.head; m; m = m->next)
|
||||
{
|
||||
target_p = m->data;
|
||||
|
||||
if (target_p == client_p->from)
|
||||
continue;
|
||||
|
||||
/* skip lazylinks that don't know about this server */
|
||||
if (ServerInfo.hub && IsCapable(target_p,CAP_LL))
|
||||
{
|
||||
if (!(RootChan(chptr)->lazyLinkChannelExists &
|
||||
target_p->localClient->serverMask) )
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Its a blank sjoin, ugh */
|
||||
if (!parv[4+args][0])
|
||||
return;
|
||||
|
||||
#ifdef HALFOPS
|
||||
if (IsCapable(target_p, CAP_HOPS))
|
||||
sendto_one(target_p, "%s%s", buf, sjbuf_hops);
|
||||
else
|
||||
#endif
|
||||
sendto_one(target_p, "%s%s", buf, sjbuf_nhops);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* set_final_mode
|
||||
*
|
||||
* inputs - pointer to mode to setup
|
||||
* - pointer to old mode
|
||||
* output - NONE
|
||||
* side effects -
|
||||
*/
|
||||
|
||||
struct mode_letter {
|
||||
int mode;
|
||||
char letter;
|
||||
};
|
||||
|
||||
struct mode_letter flags[] = {
|
||||
{ MODE_NOPRIVMSGS, 'n' },
|
||||
{ MODE_TOPICLIMIT, 't' },
|
||||
{ MODE_SECRET, 's' },
|
||||
{ MODE_MODERATED, 'm' },
|
||||
{ MODE_INVITEONLY, 'i' },
|
||||
{ MODE_PRIVATE, 'p' },
|
||||
#ifdef ANONOPS
|
||||
{ MODE_HIDEOPS, 'a' },
|
||||
#endif
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
static void set_final_mode(struct Mode *mode,struct Mode *oldmode)
|
||||
{
|
||||
int what = 0;
|
||||
char *pbuf=parabuf;
|
||||
int len;
|
||||
int i;
|
||||
|
||||
for (i = 0; flags[i].letter; i++)
|
||||
{
|
||||
if ((flags[i].mode & mode->mode) && !(flags[i].mode & oldmode->mode))
|
||||
{
|
||||
if (what != 1)
|
||||
{
|
||||
*mbuf++ = '+';
|
||||
what = 1;
|
||||
}
|
||||
*mbuf++ = flags[i].letter;
|
||||
}
|
||||
}
|
||||
for (i = 0; flags[i].letter; i++)
|
||||
{
|
||||
if ((flags[i].mode & oldmode->mode) && !(flags[i].mode & mode->mode))
|
||||
{
|
||||
if (what != -1)
|
||||
{
|
||||
*mbuf++ = '-';
|
||||
what = -1;
|
||||
}
|
||||
*mbuf++ = flags[i].letter;
|
||||
}
|
||||
}
|
||||
if (oldmode->limit && !mode->limit)
|
||||
{
|
||||
if (what != -1)
|
||||
{
|
||||
*mbuf++ = '-';
|
||||
what = -1;
|
||||
}
|
||||
*mbuf++ = 'l';
|
||||
}
|
||||
if (oldmode->key[0] && !mode->key[0])
|
||||
{
|
||||
if (what != -1)
|
||||
{
|
||||
*mbuf++ = '-';
|
||||
what = -1;
|
||||
}
|
||||
*mbuf++ = 'k';
|
||||
len = ircsprintf(pbuf,"%s ", oldmode->key);
|
||||
pbuf += len;
|
||||
pargs++;
|
||||
}
|
||||
if (mode->limit && oldmode->limit != mode->limit)
|
||||
{
|
||||
if (what != 1)
|
||||
{
|
||||
*mbuf++ = '+';
|
||||
what = 1;
|
||||
}
|
||||
*mbuf++ = 'l';
|
||||
len = ircsprintf(pbuf, "%d ", mode->limit);
|
||||
pbuf += len;
|
||||
pargs++;
|
||||
}
|
||||
if (mode->key[0] && strcmp(oldmode->key, mode->key))
|
||||
{
|
||||
if (what != 1)
|
||||
{
|
||||
*mbuf++ = '+';
|
||||
what = 1;
|
||||
}
|
||||
*mbuf++ = 'k';
|
||||
len = ircsprintf(pbuf, "%s ", mode->key);
|
||||
pbuf += len;
|
||||
pargs++;
|
||||
}
|
||||
*mbuf = '\0';
|
||||
}
|
||||
|
||||
/*
|
||||
* remove_our_modes
|
||||
*
|
||||
* inputs - hide from ops or not int flag
|
||||
* - pointer to channel to remove modes from
|
||||
* - if vchan basechannel pointer
|
||||
* - client pointer
|
||||
* output - NONE
|
||||
* side effects - Go through the local members, remove all their
|
||||
* chanop modes etc., this side lost the TS.
|
||||
*/
|
||||
static void remove_our_modes( int hide_or_not,
|
||||
struct Channel *chptr, struct Channel *top_chptr,
|
||||
struct Client *source_p)
|
||||
{
|
||||
remove_a_mode(hide_or_not, chptr, top_chptr, source_p, &chptr->chanops, 'o');
|
||||
remove_a_mode(hide_or_not, chptr, top_chptr, source_p, &chptr->voiced, 'v');
|
||||
|
||||
/* Move all voice/ops etc. to non opped list */
|
||||
dlinkMoveList(&chptr->chanops, &chptr->peons);
|
||||
dlinkMoveList(&chptr->voiced, &chptr->peons);
|
||||
|
||||
dlinkMoveList(&chptr->locchanops, &chptr->locpeons);
|
||||
dlinkMoveList(&chptr->locvoiced, &chptr->locpeons);
|
||||
|
||||
#ifdef REQUIRE_OANDV
|
||||
remove_a_mode(hide_or_not, chptr, top_chptr, source_p,
|
||||
&chptr->chanops_voiced, 'o');
|
||||
remove_a_mode(hide_or_not, chptr, top_chptr, source_p,
|
||||
&chptr->chanops_voiced, 'v');
|
||||
dlinkMoveList(&chptr->chanops_voiced, &chptr->peons);
|
||||
dlinkMoveList(&chptr->locchanops_voiced, &chptr->locpeons);
|
||||
#endif
|
||||
|
||||
#ifdef HALFOPS
|
||||
remove_a_mode(hide_or_not, chptr, top_chptr, source_p, &chptr->halfops, 'h');
|
||||
dlinkMoveList(&chptr->halfops, &chptr->peons);
|
||||
dlinkMoveList(&chptr->lochalfops, &chptr->locpeons);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* remove_a_mode
|
||||
*
|
||||
* inputs -
|
||||
* output - NONE
|
||||
* side effects - remove ONE mode from a channel
|
||||
*/
|
||||
static void remove_a_mode( int hide_or_not,
|
||||
struct Channel *chptr, struct Channel *top_chptr,
|
||||
struct Client *source_p, dlink_list *list, char flag)
|
||||
{
|
||||
dlink_node *ptr;
|
||||
struct Client *target_p;
|
||||
char buf[BUFSIZE];
|
||||
char lmodebuf[MODEBUFLEN];
|
||||
char *lpara[MAXMODEPARAMS];
|
||||
char *chname;
|
||||
int count = 0;
|
||||
|
||||
mbuf = lmodebuf;
|
||||
*mbuf++ = '-';
|
||||
|
||||
lpara[0] = lpara[1] = lpara[2] = lpara[3] = "";
|
||||
|
||||
chname = chptr->chname;
|
||||
|
||||
#ifdef VCHANS
|
||||
if (IsVchan(chptr) && top_chptr)
|
||||
chname = top_chptr->chname;
|
||||
#endif
|
||||
|
||||
ircsprintf(buf,":%s MODE %s ", me.name, chname);
|
||||
|
||||
for (ptr = list->head; ptr && ptr->data; ptr = ptr->next)
|
||||
{
|
||||
target_p = ptr->data;
|
||||
lpara[count++] = target_p->name;
|
||||
|
||||
*mbuf++ = flag;
|
||||
|
||||
if (count >= MAXMODEPARAMS)
|
||||
{
|
||||
*mbuf = '\0';
|
||||
sendto_channel_local(hide_or_not, chptr,
|
||||
":%s MODE %s %s %s %s %s %s",
|
||||
me.name,
|
||||
chname,
|
||||
lmodebuf,
|
||||
lpara[0], lpara[1], lpara[2], lpara[3] );
|
||||
|
||||
mbuf = lmodebuf;
|
||||
*mbuf++ = '-';
|
||||
count = 0;
|
||||
lpara[0] = lpara[1] = lpara[2] = lpara[3] = "";
|
||||
}
|
||||
}
|
||||
|
||||
if (count != 0)
|
||||
{
|
||||
*mbuf = '\0';
|
||||
sendto_channel_local(hide_or_not, chptr,
|
||||
":%s MODE %s %s %s %s %s %s",
|
||||
me.name,
|
||||
chname,
|
||||
lmodebuf,
|
||||
lpara[0], lpara[1], lpara[2], lpara[3] );
|
||||
|
||||
}
|
||||
}
|
236
modules/core/m_squit.c
Normal file
236
modules/core/m_squit.c
Normal file
|
@ -0,0 +1,236 @@
|
|||
/*
|
||||
* ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
|
||||
* m_squit.c: Makes a server quit.
|
||||
*
|
||||
* Copyright (C) 2002 by the past and present ircd coders, and others.
|
||||
*
|
||||
* 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 2 of the License, 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
* USA
|
||||
*
|
||||
* $Id: m_squit.c,v 1.1 2002/08/14 05:47:41 fishwaldo Exp $
|
||||
*/
|
||||
|
||||
#include "stdinc.h"
|
||||
#include "handlers.h"
|
||||
#include "client.h"
|
||||
#include "common.h" /* FALSE bleah */
|
||||
#include "irc_string.h"
|
||||
#include "ircd.h"
|
||||
#include "numeric.h"
|
||||
#include "s_conf.h"
|
||||
#include "s_log.h"
|
||||
#include "s_serv.h"
|
||||
#include "send.h"
|
||||
#include "msg.h"
|
||||
#include "parse.h"
|
||||
#include "modules.h"
|
||||
|
||||
|
||||
static void ms_squit(struct Client*, struct Client*, int, char**);
|
||||
static void mo_squit(struct Client*, struct Client*, int, char**);
|
||||
|
||||
struct Message squit_msgtab = {
|
||||
"SQUIT", 0, 0, 1, 0, MFLG_SLOW, 0,
|
||||
{m_unregistered, m_not_oper, ms_squit, mo_squit}
|
||||
};
|
||||
|
||||
#ifndef STATIC_MODULES
|
||||
void
|
||||
_modinit(void)
|
||||
{
|
||||
mod_add_cmd(&squit_msgtab);
|
||||
}
|
||||
|
||||
void
|
||||
_moddeinit(void)
|
||||
{
|
||||
mod_del_cmd(&squit_msgtab);
|
||||
}
|
||||
const char *_version = "$Revision: 1.1 $";
|
||||
#endif
|
||||
struct squit_parms
|
||||
{
|
||||
char *server_name;
|
||||
struct Client *target_p;
|
||||
};
|
||||
|
||||
static struct squit_parms *find_squit(struct Client *client_p,
|
||||
struct Client *source_p,
|
||||
char *server);
|
||||
|
||||
|
||||
/*
|
||||
* mo_squit - SQUIT message handler
|
||||
* parv[0] = sender prefix
|
||||
* parv[1] = server name
|
||||
* parv[2] = comment
|
||||
*/
|
||||
static void mo_squit(struct Client *client_p, struct Client *source_p,
|
||||
int parc, char *parv[])
|
||||
{
|
||||
struct squit_parms *found_squit;
|
||||
char *comment = (parc > 2 && parv[2]) ? parv[2] : client_p->name;
|
||||
|
||||
if (!IsOperRemote(source_p))
|
||||
{
|
||||
sendto_one(source_p,":%s NOTICE %s :You need remote = yes;",me.name,parv[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
if(parc < 2)
|
||||
{
|
||||
sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
|
||||
me.name, parv[0], "SQUIT");
|
||||
return;
|
||||
}
|
||||
|
||||
if( (found_squit = find_squit(client_p,source_p,parv[1])) )
|
||||
{
|
||||
if(MyConnect(found_squit->target_p))
|
||||
{
|
||||
sendto_realops_flags(FLAGS_ALL, L_ALL,
|
||||
"Received SQUIT %s from %s (%s)",
|
||||
found_squit->target_p->name,
|
||||
get_client_name(source_p, HIDE_IP), comment);
|
||||
ilog(L_NOTICE, "Received SQUIT %s from %s (%s)",
|
||||
found_squit->target_p->name, get_client_name(source_p, HIDE_IP),
|
||||
comment);
|
||||
}
|
||||
exit_client(client_p, found_squit->target_p, source_p, comment);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
sendto_one(source_p, form_str(ERR_NOSUCHSERVER),
|
||||
me.name, parv[0], parv[1]);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ms_squit - SQUIT message handler
|
||||
* parv[0] = sender prefix
|
||||
* parv[1] = server name
|
||||
* parv[2] = comment
|
||||
*/
|
||||
static void ms_squit(struct Client *client_p, struct Client *source_p,
|
||||
int parc, char *parv[])
|
||||
{
|
||||
struct squit_parms *found_squit;
|
||||
char *comment = (parc > 2 && parv[2]) ? parv[2] : client_p->name;
|
||||
|
||||
if(parc < 2)
|
||||
{
|
||||
exit_client(client_p, client_p, source_p, comment);
|
||||
return;
|
||||
}
|
||||
|
||||
if( (found_squit = find_squit(client_p, source_p, parv[1])) )
|
||||
{
|
||||
/*
|
||||
** Notify all opers, if my local link is remotely squitted
|
||||
*/
|
||||
if (MyConnect(found_squit->target_p))
|
||||
{
|
||||
sendto_wallops_flags(FLAGS_WALLOP, &me,
|
||||
"Remote SQUIT %s from %s (%s)",
|
||||
found_squit->server_name,
|
||||
source_p->name, comment);
|
||||
|
||||
sendto_server(NULL, NULL, NULL, NOCAPS, NOCAPS, NOFLAGS,
|
||||
":%s WALLOPS :Remote SQUIT %s from %s (%s)",
|
||||
me.name, found_squit->server_name,
|
||||
source_p->name, comment);
|
||||
|
||||
ilog(L_TRACE, "SQUIT From %s : %s (%s)", parv[0],
|
||||
found_squit->server_name, comment);
|
||||
|
||||
}
|
||||
exit_client(client_p, found_squit->target_p, source_p, comment);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* find_squit
|
||||
* inputs - local server connection
|
||||
* -
|
||||
* -
|
||||
* output - pointer to struct containing found squit or none if not found
|
||||
* side effects -
|
||||
*/
|
||||
static struct squit_parms *find_squit(struct Client *client_p,
|
||||
struct Client *source_p,
|
||||
char *server)
|
||||
{
|
||||
static struct squit_parms found_squit;
|
||||
static struct Client *target_p;
|
||||
struct ConfItem *aconf;
|
||||
|
||||
found_squit.target_p = NULL;
|
||||
found_squit.server_name = NULL;
|
||||
|
||||
/*
|
||||
** To accomodate host masking, a squit for a masked server
|
||||
** name is expanded if the incoming mask is the same as
|
||||
** the server name for that link to the name of link.
|
||||
*/
|
||||
if ((*server == '*') && IsServer(client_p))
|
||||
{
|
||||
aconf = client_p->serv->sconf;
|
||||
if (aconf)
|
||||
{
|
||||
if (!irccmp(server, my_name_for_link(me.name, aconf)))
|
||||
{
|
||||
found_squit.server_name = client_p->name;
|
||||
found_squit.target_p = client_p;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** The following allows wild cards in SQUIT. Only useful
|
||||
** when the command is issued by an oper.
|
||||
*/
|
||||
for (target_p = GlobalClientList; (target_p = next_client(target_p, server));
|
||||
target_p = target_p->next)
|
||||
{
|
||||
if (IsServer(target_p) || IsMe(target_p))
|
||||
break;
|
||||
}
|
||||
|
||||
found_squit.target_p = target_p;
|
||||
found_squit.server_name = server;
|
||||
|
||||
if (target_p && IsMe(target_p))
|
||||
{
|
||||
if (IsClient(client_p))
|
||||
{
|
||||
sendto_one(source_p,":%s NOTICE %s :You are trying to squit me.",me.name,client_p->name);
|
||||
found_squit.target_p = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
found_squit.target_p = client_p;
|
||||
found_squit.server_name = client_p->name;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if(found_squit.target_p != NULL)
|
||||
return &found_squit;
|
||||
else
|
||||
return( NULL );
|
||||
}
|
Reference in a new issue