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:
fishwaldo 2002-08-14 05:47:41 +00:00
parent f44ee87a91
commit 72729d1cda
13 changed files with 5051 additions and 0 deletions

12
.gitattributes vendored
View file

@ -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
View 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
View 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
View 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
View 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
View 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(&notice_msgtab);
}
void
_moddeinit(void)
{
mod_del_cmd(&privmsg_msgtab);
mod_del_cmd(&notice_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
View 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
View 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
View 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
View 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
View 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
View 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
View 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 );
}