527 lines
15 KiB
C
527 lines
15 KiB
C
/************************************************************************
|
|
* IRC - Internet Relay Chat, m_svscmds.c
|
|
* Copyright (C) 2002 NeoIRCd Development Team
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 1, or (at your option)
|
|
* any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*
|
|
* $Id: m_svscmds.c,v 1.10 2003/03/06 14:01:46 fishwaldo Exp $
|
|
*/
|
|
|
|
/* List of ircd includes from ../include/ */
|
|
#include "stdinc.h"
|
|
#include "handlers.h"
|
|
#include "client.h"
|
|
#include "channel.h"
|
|
#include "channel_mode.h"
|
|
#include "common.h" /* FALSE bleah */
|
|
#include "ircd.h"
|
|
#include "irc_string.h"
|
|
#include "numeric.h"
|
|
#include "fdlist.h"
|
|
#include "s_bsd.h"
|
|
#include "s_conf.h"
|
|
#include "s_log.h"
|
|
#include "s_serv.h"
|
|
#include "s_user.h"
|
|
#include "send.h"
|
|
#include "msg.h"
|
|
#include "parse.h"
|
|
#include "modules.h"
|
|
#include "hash.h"
|
|
#include "whowas.h"
|
|
|
|
/* Declare the void's initially up here, as modules dont have an
|
|
* include file, we will normally have client_p, source_p, parc
|
|
* and parv[] where:
|
|
*
|
|
* client_p == client issuing command
|
|
* source_p == where the command came from
|
|
* parc == the number of parameters
|
|
* parv == an array of the parameters
|
|
*/
|
|
static void ms_svshost(struct Client *client_p, struct Client *source_p,
|
|
int parc, char *parv[]);
|
|
|
|
static void ms_svsnick(struct Client *client_p, struct Client *source_p,
|
|
int parc, char *parv[]);
|
|
|
|
static void ms_svsid(struct Client *client_p, struct Client *source_p,
|
|
int parc, char *parv[]);
|
|
|
|
static void ms_svsjoin(struct Client *client_p, struct Client *source_p,
|
|
int parc, char *parv[]);
|
|
static void ms_svspart(struct Client *client_p, struct Client *source_p,
|
|
int parc, char *parv[]);
|
|
static void ms_svsmode(struct Client *client_p, struct Client *source_p,
|
|
int parc, char *parv[]);
|
|
|
|
|
|
|
|
static int clean_nick_name(char *);
|
|
|
|
/* Show the commands this module can handle in a msgtab
|
|
* and give the msgtab a name, here its test_msgtab
|
|
*/
|
|
struct Message svshost_msgtab = {
|
|
"SVSHOST", 0, 0, 3, 3, MFLG_SLOW, 0,
|
|
{m_ignore, m_ignore, ms_svshost, m_ignore}
|
|
};
|
|
|
|
struct Message svsnick_msgtab = {
|
|
"SVSNICK", 0, 0, 3, 3, MFLG_SLOW, 0,
|
|
{m_ignore, m_ignore, ms_svsnick, m_ignore}
|
|
};
|
|
|
|
struct Message svsid_msgtab = {
|
|
"SVSID", 0, 0, 3, 3, MFLG_SLOW, 0,
|
|
{m_ignore, m_ignore, ms_svsid, m_ignore}
|
|
};
|
|
|
|
struct Message svsjoin_msgtab = {
|
|
"SVSJOIN", 0, 0, 3, 0, MFLG_SLOW, 0,
|
|
{m_ignore, m_ignore, ms_svsjoin, m_ignore}
|
|
};
|
|
struct Message svspart_msgtab = {
|
|
"SVSPART", 0, 0, 3, 0, MFLG_SLOW, 0,
|
|
{m_ignore, m_ignore, ms_svspart, m_ignore}
|
|
};
|
|
|
|
struct Message svsmode_msgtab = {
|
|
"SVSMODE", 0, 0, 3, 0, MFLG_SLOW, 0,
|
|
{m_ignore, m_ignore, ms_svsmode, m_ignore}
|
|
};
|
|
|
|
/* Thats the msgtab finished */
|
|
|
|
#ifndef STATIC_MODULES
|
|
/* Here we tell it what to do when the module is loaded */
|
|
void
|
|
_modinit(void)
|
|
{
|
|
/* This will add the commands in test_msgtab (which is above) */
|
|
mod_add_cmd(&svshost_msgtab);
|
|
mod_add_cmd(&svsnick_msgtab);
|
|
mod_add_cmd(&svsid_msgtab);
|
|
mod_add_cmd(&svsjoin_msgtab);
|
|
mod_add_cmd(&svspart_msgtab);
|
|
mod_add_cmd(&svsmode_msgtab);
|
|
}
|
|
|
|
/* here we tell it what to do when the module is unloaded */
|
|
void
|
|
_moddeinit(void)
|
|
{
|
|
/* This will remove the commands in test_msgtab (which is above) */
|
|
mod_del_cmd(&svshost_msgtab);
|
|
mod_del_cmd(&svsnick_msgtab);
|
|
mod_del_cmd(&svsid_msgtab);
|
|
mod_del_cmd(&svsjoin_msgtab);
|
|
mod_del_cmd(&svspart_msgtab);
|
|
mod_del_cmd(&svsmode_msgtab);
|
|
}
|
|
|
|
/* When we last modified the file (shown in /modlist), this is usually:
|
|
*/
|
|
const char *_version = "$Revision: 1.10 $";
|
|
#endif
|
|
|
|
/*
|
|
* ms_svshost
|
|
* Changes the Targets Virtual Hostname, and also sets +x if its not set already on the target
|
|
* parv[0] = sender prefix
|
|
* parv[1] = target
|
|
* parv[2] = new hostname
|
|
*/
|
|
static void ms_svshost(struct Client *client_p, struct Client *source_p,
|
|
int parc, char *parv[])
|
|
{
|
|
struct Client *target_p;
|
|
|
|
|
|
target_p = find_person(parv[1]);
|
|
/* first find the target that we want to change */
|
|
if (target_p != NULL) {
|
|
if (IsServer(source_p) && IsUlined(source_p)) {
|
|
SetHidden(target_p);
|
|
strncpy(target_p->vhost, parv[2], HOSTLEN);
|
|
|
|
/* send it to the rest of the net */
|
|
sendto_server(client_p, target_p, NULL, 0, 0, LL_ICLIENT, ":%s SVSHOST %s :%s", source_p->name, target_p->name, target_p->vhost);
|
|
|
|
return;
|
|
|
|
} else {
|
|
sendto_realops_flags(FLAGS_ALL|FLAGS_REMOTE, L_ALL, "Non U-Lined Server %s is attempting to use svshost on %s", source_p->name, target_p->name);
|
|
return;
|
|
}
|
|
} else {
|
|
ilog(L_WARN, "svshost: Couldn't find target %s", parv[1]);
|
|
/* we couldn't find the target. Just exit */
|
|
return;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* ms_svsnick
|
|
* Changes the targets nickname
|
|
* parv[0] = sender prefix
|
|
* parv[1] = target
|
|
* parv[2] = new nickname
|
|
* parv[3] = ts
|
|
*
|
|
*/
|
|
static void ms_svsnick(struct Client *client_p, struct Client *source_p,
|
|
int parc, char *parv[])
|
|
{
|
|
struct Client *target_p;
|
|
|
|
|
|
target_p = find_person(parv[1]);
|
|
if (target_p == NULL) {
|
|
ilog(L_WARN, "SVSNICK from %s was invalid. Can't find the client", parv[1]);
|
|
return;
|
|
}
|
|
if (!IsClient(target_p))
|
|
return;
|
|
if (!IsUlined(source_p)) {
|
|
sendto_realops_flags(FLAGS_ALL|FLAGS_REMOTE, L_ALL, "Non U-Lined Server %s is attempting to use svsnick on %s", source_p->name, target_p->name);
|
|
return;
|
|
}
|
|
/* first find the target that we want to change */
|
|
if (MyClient(target_p)) {
|
|
if (!clean_nick_name(parv[2]) || !strcmp(target_p->name, parv[2])) {
|
|
ilog(L_WARN, "svsnick: invalid nickname");
|
|
return;
|
|
}
|
|
target_p->tsinfo = parv[4] ? atol(parv[3]) : CurrentTime;
|
|
sendto_common_channels_local(target_p, 1, ":%s!%s@%s NICK :%s", target_p->name, target_p->username, target_p->vhost, parv[2]);
|
|
/* send it to the other servers */
|
|
if (target_p->user) {
|
|
add_history(target_p, 1);
|
|
sendto_server(NULL, target_p, NULL, 0, 0, LL_ICLIENT, ":%s NICK %s :%lu", target_p->name, parv[2], target_p->tsinfo);
|
|
}
|
|
if (target_p->name[0])
|
|
del_from_client_hash_table(target_p->name, target_p);
|
|
|
|
strcpy(target_p->name, parv[2]);
|
|
add_to_client_hash_table(target_p->name, target_p);
|
|
|
|
/* del all the accept entries for this nick */
|
|
del_all_accepts(target_p);
|
|
} else {
|
|
/* just relay the svsnick to a server that has this client */
|
|
sendto_one(target_p, ":%s SVSNICK %s %s :%lu", source_p->name, target_p->name, parv[2], atol(parv[3]));
|
|
|
|
}
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
/* 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;
|
|
}
|
|
|
|
|
|
/*
|
|
* ms_svsid
|
|
* Sets/Changes the Services ID for a particular Nickname
|
|
* parv[0] = sender prefix
|
|
* parv[1] = target
|
|
* parv[2] = newsvsid
|
|
*
|
|
*/
|
|
static void ms_svsid(struct Client *client_p, struct Client *source_p,
|
|
int parc, char *parv[])
|
|
{
|
|
struct Client *target_p;
|
|
|
|
|
|
target_p = find_person(parv[1]);
|
|
if (target_p == NULL) {
|
|
ilog(L_WARN, "SVSNICK from %s was invalid. Can't find the client", parv[1]);
|
|
return;
|
|
}
|
|
if (!IsClient(target_p))
|
|
return;
|
|
if (!IsUlined(source_p)) {
|
|
sendto_realops_flags(FLAGS_ALL|FLAGS_REMOTE, L_ALL, "Non U-Lined Server %s is attempting to use svsid on %s", source_p->name, target_p->name);
|
|
return;
|
|
}
|
|
/* set the new ID */
|
|
target_p->svsid = atol(parv[2]);
|
|
|
|
/* and now send it to the rest of the network */
|
|
sendto_server(client_p, target_p, NULL, 0, 0, LL_ICLIENT, ":%s SVSID %s %lu", source_p->name, target_p->name, target_p->svsid);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
/*
|
|
* m_svsjoin
|
|
* parv[0] = sender prefix
|
|
* parv[1] = user to force
|
|
* parv[2] = channel to force them into
|
|
*/
|
|
static void ms_svsjoin(struct Client *client_p, struct Client *source_p,
|
|
int parc, char *parv[])
|
|
{
|
|
struct Client *target_p;
|
|
struct Channel *chptr;
|
|
int type;
|
|
char mode;
|
|
char sjmode;
|
|
char *newch;
|
|
|
|
/* if its from a server, and its not ulined, ignore it */
|
|
if (!IsUlined(source_p) && IsServer(source_p))
|
|
return;
|
|
|
|
if((hunt_server(client_p, source_p, ":%s SVSJOIN %s %s", 1, parc, parv)) != HUNTED_ISME)
|
|
return;
|
|
|
|
/* if target_p is not existant, print message
|
|
* to source_p and bail - scuzzy
|
|
*/
|
|
if ((target_p = find_client(parv[1])) == NULL)
|
|
{
|
|
if (IsClient(source_p)) sendto_one(source_p, form_str(ERR_NOSUCHNICK), me.name,
|
|
source_p->name, parv[1]);
|
|
return;
|
|
}
|
|
|
|
if(!IsClient(target_p))
|
|
return;
|
|
|
|
/* select our modes from parv[2] if they exist... (chanop)*/
|
|
if(*parv[2] == '!')
|
|
{
|
|
type = CHFL_ADMIN;
|
|
mode = 'a';
|
|
sjmode = '!';
|
|
}
|
|
if(*parv[2] == '@')
|
|
{
|
|
type = CHFL_CHANOP;
|
|
mode = 'o';
|
|
sjmode = '@';
|
|
}
|
|
else if(*parv[2] == '%')
|
|
{
|
|
type = CHFL_HALFOP;
|
|
mode = 'h';
|
|
sjmode = '%';
|
|
}
|
|
else if(*parv[2] == '+')
|
|
{
|
|
type = CHFL_VOICE;
|
|
mode = 'v';
|
|
sjmode = '+';
|
|
}
|
|
else
|
|
{
|
|
type = CHFL_PEON;
|
|
mode = sjmode = '\0';
|
|
}
|
|
|
|
if(mode != '\0')
|
|
parv[2]++;
|
|
|
|
if((chptr = hash_find_channel(parv[2])) != NULL)
|
|
{
|
|
if(IsMember(target_p, chptr))
|
|
{
|
|
/* debugging is fun... */
|
|
if (IsClient(source_p)) sendto_one(source_p, ":%s NOTICE %s :*** Notice -- %s is already in %s", me.name,
|
|
source_p->name, target_p->name, chptr->chname);
|
|
return;
|
|
}
|
|
|
|
add_user_to_channel(chptr, target_p, type);
|
|
|
|
if (chptr->chname[0] != '&')
|
|
sendto_server(NULL, target_p, chptr, NOCAPS, NOCAPS, LL_ICLIENT,
|
|
":%s SJOIN %lu %s + :%c%s",
|
|
me.name, (unsigned long) chptr->channelts,
|
|
chptr->chname, type ? sjmode : ' ', target_p->name);
|
|
|
|
sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s JOIN :%s",
|
|
target_p->name, target_p->username,
|
|
target_p->host, chptr->chname);
|
|
|
|
if(type)
|
|
sendto_channel_local(ALL_MEMBERS, chptr, ":%s MODE %s +%c %s",
|
|
me.name, chptr->chname, mode, target_p->name);
|
|
|
|
if(chptr->topic != NULL)
|
|
{
|
|
sendto_one(target_p, form_str(RPL_TOPIC), me.name,
|
|
target_p->name, chptr->chname, chptr->topic);
|
|
sendto_one(target_p, form_str(RPL_TOPICWHOTIME),
|
|
me.name, source_p->name, chptr->chname,
|
|
chptr->topic_info, chptr->topic_time);
|
|
}
|
|
|
|
channel_member_names(target_p, chptr, chptr->chname, 1);
|
|
}
|
|
else
|
|
{
|
|
newch = parv[2];
|
|
if (!check_channel_name(newch))
|
|
{
|
|
if (IsClient(source_p)) sendto_one(source_p, form_str(ERR_BADCHANNAME), me.name,
|
|
source_p->name, (unsigned char*)newch);
|
|
return;
|
|
}
|
|
|
|
/* channel name must begin with & or # */
|
|
if (!IsChannelName(newch))
|
|
{
|
|
if (IsClient(source_p)) sendto_one(source_p, form_str(ERR_BADCHANNAME), me.name,
|
|
source_p->name, (unsigned char*)newch);
|
|
return;
|
|
}
|
|
|
|
/* it would be interesting here to allow an oper
|
|
* to force target_p into a channel that doesn't exist
|
|
* even more so, into a local channel when we disable
|
|
* local channels... but...
|
|
* I don't want to break anything - scuzzy
|
|
*/
|
|
if (ConfigServerHide.disable_local_channels &&
|
|
(*newch == '&'))
|
|
{
|
|
if (IsClient(source_p)) sendto_one(source_p, ":%s NOTICE %s :No such channel (%s)", me.name,
|
|
source_p->name, newch);
|
|
return;
|
|
}
|
|
|
|
/* newch can't be longer than CHANNELLEN */
|
|
if (strlen(newch) > CHANNELLEN)
|
|
{
|
|
if (IsClient(source_p)) sendto_one(source_p, ":%s NOTICE %s :Channel name is too long", me.name,
|
|
source_p->name);
|
|
return;
|
|
}
|
|
|
|
chptr = get_or_create_channel(target_p, newch, NULL);
|
|
add_user_to_channel(chptr, target_p, CHFL_CHANOP);
|
|
|
|
/* send out a join, make target_p join chptr */
|
|
if (chptr->chname[0] != '&')
|
|
sendto_server(NULL, target_p, chptr, NOCAPS, NOCAPS, LL_ICLIENT,
|
|
":%s SJOIN %lu %s +nt :!%s", me.name,
|
|
(unsigned long) chptr->channelts, chptr->chname,
|
|
target_p->name);
|
|
|
|
sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s JOIN :%s",
|
|
target_p->name, target_p->username,
|
|
target_p->host, chptr->chname);
|
|
|
|
chptr->mode.mode |= MODE_TOPICLIMIT;
|
|
chptr->mode.mode |= MODE_NOPRIVMSGS;
|
|
|
|
sendto_channel_local(ALL_MEMBERS, chptr, ":%s MODE %s +nt", me.name,
|
|
chptr->chname);
|
|
|
|
target_p->localClient->last_join_time = CurrentTime;
|
|
channel_member_names(target_p, chptr, chptr->chname, 1);
|
|
|
|
}
|
|
}
|
|
|
|
|
|
static void ms_svspart(struct Client *client_p, struct Client *source_p,
|
|
int parc, char *parv[])
|
|
{
|
|
struct Client *target_p;
|
|
struct Channel *chptr;
|
|
|
|
/* if its from a server, and its not ulined, ignore it */
|
|
if (!IsUlined(source_p) && IsServer(source_p))
|
|
return;
|
|
|
|
if((hunt_server(client_p, source_p, ":%s SVSPART %s %s", 1, parc, parv)) != HUNTED_ISME)
|
|
return;
|
|
|
|
/* if target_p == NULL then let the oper know */
|
|
if ((target_p = find_client(parv[1])) == NULL)
|
|
{
|
|
if (IsClient(source_p)) sendto_one(source_p, form_str(ERR_NOSUCHNICK), me.name,
|
|
source_p->name, parv[1]);
|
|
return;
|
|
}
|
|
|
|
if(!IsClient(target_p))
|
|
return;
|
|
|
|
if((chptr = hash_find_channel(parv[2])) == NULL)
|
|
{
|
|
if (IsClient(source_p)) sendto_one(source_p, form_str(ERR_NOSUCHCHANNEL),
|
|
me.name, parv[0], parv[1]);
|
|
return;
|
|
}
|
|
|
|
if (!IsMember(target_p, chptr))
|
|
{
|
|
if (IsClient(source_p)) sendto_one(source_p, form_str(ERR_USERNOTINCHANNEL),
|
|
me.name, parv[0], parv[2], parv[1]);
|
|
return;
|
|
}
|
|
|
|
if (chptr->chname[0] != '&')
|
|
sendto_server(target_p, target_p, chptr, NOCAPS, NOCAPS, LL_ICLIENT,
|
|
":%s PART %s :%s",
|
|
target_p->name, chptr->chname,
|
|
target_p->name);
|
|
|
|
sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s PART %s :%s",
|
|
target_p->name, target_p->username,
|
|
target_p->host,chptr->chname,
|
|
target_p->name);
|
|
remove_user_from_channel(chptr, target_p);
|
|
}
|
|
|
|
static void ms_svsmode(struct Client *client_p, struct Client *source_p,
|
|
int parc, char *parv[])
|
|
{
|
|
|
|
if (!IsUlined(source_p))
|
|
return;
|
|
user_mode(client_p, source_p, parc, parv);
|
|
|
|
}
|