/* m_services.c - Because s_user.c was just crazy.
* Copyright (C) 1990 Jarkko Oikarinen and
* University of Oulu, Computing Center
*
* See file AUTHORS in IRC package for additional names of
* the programmers.
*
* This program is free softwmare; 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_services.c,v 1.5 2006/06/25 22:53:01 sheik Exp $ */
#include "struct.h"
#include "common.h"
#include "sys.h"
#include "numeric.h"
#include "msg.h"
#include "channel.h"
#include <sys/stat.h>
#include <utmp.h>
#include <fcntl.h>
#include "h.h"
#include "userban.h"
#include "clones.h"
#include "memcount.h"
/* Externally defined stuffs */
extern int user_modes[];
/*
* the services aliases. *
*
* NICKSERV - /nickserv * CHANSERV - /chanserv * OPERSERV -
* /operserv * MEMOSERV - /memoserv * SERVICES - /services *
* IDENTIFY - /identify * taz's code -mjs
*/
/* Code provided by orabidoo */
/*
* a random number generator loosely based on RC5; assumes ints are at
* least 32 bit
*/
static unsigned long
my_rand()
{
static unsigned long s = 0, t = 0, k = 12345678;
int i;
if (s == 0 && t == 0)
{
s = (unsigned long) getpid();
t = (unsigned long) time(NULL);
}
for (i = 0; i < 12; i++)
{
s = (((s ^ t) << (t & 31)) | ((s ^ t) >> (31 - (t & 31)))) + k;
k += s + t;
t = (((t ^ s) << (s & 31)) | ((t ^ s) >> (31 - (s & 31)))) + k;
k += s + t;
}
return s;
}
/* alias message handler */
int m_aliased(aClient *cptr, aClient *sptr, int parc, char *parv[], AliasInfo *ai)
{
if (parc < 2 || *parv[1] == 0)
{
sendto_one(sptr, err_str(ERR_NOTEXTTOSEND), me.name, parv[0]);
return -1;
}
/* second check is to avoid message loops when admins get stupid */
if (!ai->client || ai->client->from == sptr->from)
{
sendto_one(sptr, err_str(ERR_SERVICESDOWN), me.name, parv[0],
ai->nick);
return 0;
}
sendto_alias(ai, sptr, "%s", parv[1]);
return 0;
}
/* m_services -- see df465+taz */
int m_services(aClient *cptr, aClient *sptr, int parc, char *parv[])
{
char *tmps;
int aidx = AII_NS;
if (parc < 2 || *parv[1] == '\0')
{
sendto_one(sptr, err_str(ERR_NOTEXTTOSEND), me.name, parv[0]);
return -1;
}
if ((strlen(parv[1]) >= 4) && (!myncmp(parv[1], "help", 4)))
{
sendto_one(sptr, ":services!service@%s NOTICE %s :For ChanServ "
"help use: /chanserv help", Services_Name,
sptr->name);
sendto_one(sptr, ":services!service@%s NOTICE %s :For NickServ "
"help use: /nickserv help", Services_Name,
sptr->name);
sendto_one(sptr, ":services!service@%s NOTICE %s :For MemoServ "
"help use: /memoserv help", Services_Name,
sptr->name);
return 0;
}
if ((tmps = (char *) strchr(parv[1], ' ')))
{
for(; *tmps == ' '; tmps++); /* er.. before this for loop, the next
* comparison would always compare '#'
* with ' '.. oops. - lucas
*/
if (*tmps == '#')
aidx = AII_CS;
}
return m_aliased(cptr, sptr, parc, parv, &aliastab[aidx]);
}
/* m_identify df465+taz */
int m_identify(aClient *cptr, aClient *sptr, int parc, char *parv[])
{
int aidx = AII_NS;
if (parc < 2 || *parv[1] == '\0')
{
sendto_one(sptr, err_str(ERR_NOTEXTTOSEND), me.name, parv[0]);
return -1;
}
if (*parv[1] == '#')
aidx = AII_CS;
if (!aliastab[aidx].client)
{
sendto_one(sptr, err_str(ERR_SERVICESDOWN), me.name, parv[0],
aliastab[aidx].nick);
return 0;
}
sendto_alias(&aliastab[aidx], sptr, "IDENTIFY %s", parv[1]);
return 0;
}
/* s_svsnick - Pretty straight forward. Mostly straight outta df
* - Raistlin
* parv[0] = sender
* parv[1] = old nickname
* parv[2] = new nickname
* parv[3] = timestamp
*/
int m_svsnick(aClient *cptr, aClient *sptr, int parc, char *parv[])
{
aClient *acptr, *ocptr;
char newnick[NICKLEN + 1];
if (!IsULine(sptr)||parc < 4||(strlen(parv[2]) > NICKLEN))
return 0;
if(hunt_server(cptr, sptr, ":%s SVSNICK %s %s :%s", 1, parc, parv) != HUNTED_ISME)
return 0;
/* can't find them? oh well. */
if ((acptr = find_person(parv[1], NULL)) == NULL)
return 0;
strncpyzt(newnick, parv[2], NICKLEN+1);
/* does the nick we're changing them to already exist? */
/* Try to make a unique nickname */
if((ocptr = find_client(newnick, NULL)) != NULL)
{
int tries = 0, nprefix;
do
{
nprefix = my_rand() % 99999;
ircsnprintf(newnick, NICKLEN, "%s-%d", parv[2], nprefix);
tries++;
} while (((ocptr = find_client(newnick, NULL)) != NULL) && (tries < 10));
/* well, we tried.. */
if(ocptr)
{
if(IsUnknown(ocptr))
return exit_client(ocptr, ocptr, &me, "SVSNICK Override");
else
return exit_client(acptr, acptr, &me, "SVSNICK Collide");
}
}
if(acptr->umode & UMODE_r)
{
unsigned int oldumode;
char mbuf[BUFSIZE];
oldumode = acptr->umode;
acptr->umode &= ~UMODE_r;
send_umode(acptr, acptr, oldumode, ALL_UMODES, mbuf);
}
acptr->tsinfo = atoi(parv[3]);
#ifdef ANTI_NICK_FLOOD
acptr->last_nick_change = atoi(parv[3]);
#endif
sendto_common_channels(acptr, ":%s NICK :%s", parv[1], newnick);
add_history(acptr, 1);
sendto_serv_butone(NULL, ":%s NICK %s :%d", parv[1], newnick,
acptr->tsinfo);
if(acptr->name[0])
del_from_client_hash_table(acptr->name, acptr);
strcpy(acptr->name, newnick);
add_to_client_hash_table(acptr->name, acptr);
return 0;
}
/* channel_svsmode:
* parv[0] sender
* parv[1] channel
* parv[2] modes
* parv[3] nick
* parv[4] nickts
* currently, only a mode of -b is supported.
* services should use MODE for regular channel modes.
* 2/5/00 lucas
* preconditions: parc >= 3, sptr is ulined
*/
int channel_svsmode(aClient *cptr, aClient *sptr, int parc, char *parv[])
{
aChannel *chptr;
aClient *acptr = NULL;
char *m, *nick = NULL;
char change = '+';
ts_val nickts = 0;
int sendmsg = 1;
if(!(chptr = find_channel(parv[1], NULL)))
return 0;
if(parc >= 4)
{
nick = parv[3];
if(parc > 4)
nickts = atol(parv[4]);
}
if(nick)
{
acptr = find_person(nick, NULL);
if(!acptr || (nickts && acptr->tsinfo != nickts))
return 0;
}
for(m = parv[2]; *m; m++)
switch(*m)
{
case '+':
case '-':
change = *m;
break;
case 'b':
if(nick && MyClient(acptr) && change == '-')
{
remove_matching_bans(chptr, acptr, &me);
sendmsg--;
}
break;
#ifdef EXEMPT_LISTS
case 'e':
if (nick && MyClient(acptr) && change == '-')
{
remove_matching_exempts(chptr, acptr, &me);
sendmsg--;
}
break;
#endif
#ifdef INVITE_LISTS
case 'I':
if (nick && MyClient(acptr) && change == '-')
{
remove_matching_invites(chptr, acptr, &me);
sendmsg--;
}
break;
#endif
default:
sendmsg++;
break;
}
if(!sendmsg) return 0;
if(nick)
sendto_serv_butone(cptr, ":%s SVSMODE %s %s %s %ld", parv[0], parv[1],
parv[2], nick, acptr->tsinfo);
else
sendto_serv_butone(cptr, ":%s SVSMODE %s %s", parv[0], parv[1],
parv[2]);
return 0;
}
/* m_svsmode - df function integrated
* - Raistlin
* -- Behaviour changed - Epi (11/30/99)
* parv[0] - sender
* parv[1] - nick
* parv[2] - TS (or mode, depending on svs version)
* parv[3] - mode (or services id if old svs version)
* parv[4] - optional arguement (services id)
*/
int m_svsmode(aClient *cptr, aClient *sptr, int parc, char *parv[])
{
int flag, *s, what, oldumode;
char *m, *modes, *optarg;
aClient *acptr;
ts_val ts = 0;
if (!IsULine(sptr) || (parc < 3))
return 0;
if (parv[1][0] == '#')
return channel_svsmode(cptr, sptr, parc, parv);
if ((parc >= 4) && ((parv[3][0] == '+') || (parv[3][0] == '-')))
{
ts = atol(parv[2]);
modes = parv[3];
optarg = (parc > 4) ? parv[4] : NULL;
}
else
{
modes = parv[2];
optarg = (parc > 3) ? parv[3] : NULL;
}
if (!(acptr = find_person(parv[1], NULL)))
return 0;
if (ts && (ts != acptr->tsinfo))
return 0;
what = MODE_ADD;
oldumode = acptr->umode;
for (m = modes; *m; m++)
switch(*m)
{
case '+':
what = MODE_ADD;
break;
case '-':
what = MODE_DEL;
break;
case ' ':
case '\n':
case '\r':
case '\t':
break;
case 'd':
if (optarg && IsDigit(*optarg))
acptr->user->servicestamp = strtoul(optarg, NULL, 0);
break;
case 'T':
if (optarg && IsDigit(*optarg))
acptr->user->servicetype = strtoul(optarg, NULL, 0);
break;
default:
for (s = user_modes; (flag = *s); s += 2)
{
if (*m == (char)(*(s+1)))
{
if (what == MODE_ADD)
{
/* no opering this way */
if (flag & (UMODE_o|UMODE_O))
break;
acptr->umode |= flag;
}
else if (acptr->umode & flag)
{
acptr->umode &= ~flag;
/* deopering ok */
if (MyConnect(acptr) && (flag & (UMODE_o|UMODE_O))
&& !IsAnOper(acptr))
{
acptr->oflag = 0;
remove_from_list(&oper_list, acptr, NULL);
}
}
break;
}
}
break;
}
if (optarg)
sendto_serv_butone(cptr, ":%s SVSMODE %s %ld %s %s",
parv[0], parv[1], acptr->tsinfo, modes, optarg);
else
sendto_serv_butone(cptr, ":%s SVSMODE %s %ld %s",
parv[0], parv[1], acptr->tsinfo, modes);
if (MyClient(acptr) && (oldumode != acptr->umode))
{
char buf[BUFSIZE];
send_umode(acptr, acptr, oldumode, ALL_UMODES, buf);
}
return 0;
}
/* m_svshold
* Adds a temporary local nick ban.
* parv[0] - sender
* parv[1] - nick
* parv[2] - duration (0 to remove existing ban)
* parv[3] - optional reason
*/
int m_svshold(aClient *cptr, aClient *sptr, int parc, char *parv[])
{
struct simBan *ban, *oban;
char *reason, *mask;
int length;
if(!IsULine(sptr) || parc < 3)
return 0;
mask = parv[1];
length = strtol(parv[2], NULL, 0);
reason = (parc < 4) ? "Nickname is reserved, try again later" : parv[3];
/* marked local so netbursts don't propagate it */
ban = make_simpleban(SBAN_LOCAL|SBAN_NICK|SBAN_TEMPORARY, parv[1]);
if(!ban)
{
sendto_realops_lev(DEBUG_LEV, "make_simpleban(%s) failed on svshold", mask);
return 0;
}
ban->reason = NULL;
if((oban = find_simban_exact(ban)) != NULL)
{
simban_free(ban);
ban = NULL;
if(length <= 0)
{
remove_simban(oban);
simban_free(oban);
}
else
{
if(oban->reason)
MyFree(oban->reason);
oban->reason = (char *) MyMalloc(strlen(reason) + 1);
strcpy(oban->reason, reason);
oban->timeset = NOW;
oban->duration = length;
oban->autocap = (*parv[2] == '+') ? length : 0;
}
}
else if(length > 0)
{
ban->reason = (char *) MyMalloc(strlen(reason) + 1);
strcpy(ban->reason, reason);
ban->timeset = NOW;
ban->duration = length;
if (*parv[2] == '+')
ban->autocap = length;
add_simban(ban);
}
else
simban_free(ban);
if(parc < 4)
sendto_serv_butone(cptr, ":%s SVSHOLD %s %s", sptr->name, parv[1], parv[2]);
else
sendto_serv_butone(cptr, ":%s SVSHOLD %s %s :%s", sptr->name, parv[1], parv[2], parv[3]);
return 0;
}
/* m_svsclone
* Sets a clone limit for an IP mask (1.2.3.4 or 1.2.3.*).
* parv[0] - sender
* parv[1] - mask
* parv[2] - duration (0 to revert to default limit)
*/
int
m_svsclone(aClient *cptr, aClient *sptr, int parc, char *parv[])
{
int d;
if (parc != 3)
return 0;
if (!(IsServer(sptr) || IsULine(sptr)))
return 0;
d = atoi(parv[2]);
clones_set(parv[1], CLIM_HARD_GLOBAL, d);
sendto_serv_butone(cptr, ":%s SVSCLONE %s %s", parv[0], parv[1], parv[2]);
return 0;
}
/* This should be used by servers only! */
int
m_svhost(aClient *cptr, aClient *sptr, int parc, char *parv[])
{
aClient *acptr;
if (!IsServer(sptr))
return 0;
if ((acptr=find_client(parv[1], NULL))==NULL)
return 0;
if (!IsUmodev(acptr))
SetUmodev(acptr);
strncpyzt(acptr->user->host, parv[2], HOSTLEN+1);
sendto_serv_butone (cptr, ":%s SVHOST %s %s", parv[0],
acptr->name, acptr->user->host);
return 0;
}
/* m_chankill
* Destroy a channel completely, removing all local users
* with a kick and propegating the chankill out. The user will
* not see anyone else get kicked before they do.
* parv[0] - sender (Ulined client)
* parv[1] - channel
* parv[2] - kick reason
*/
int
m_chankill(aClient *cptr, aClient *sptr, int parc, char *parv[])
{
aChannel *chptr = NULL;
chanMember *cur = NULL, *next = NULL;
if(!IsULine(sptr) || parc < 2) /* we can kick without a reason. */
return 0;
if(!(chptr = find_channel(parv[1], NULL)))
return 0;
cur = chptr->members;
while(cur)
{
next = cur->next;
if(MyClient(cur->cptr)) /* tell our clients that the channel is gone */
sendto_prefix_one(cur->cptr, sptr, ":%s KICK %s %s :%s", parv[0],
parv[1], cur->cptr->name,
(parc == 3) ? parv[2] : "");
remove_user_from_channel(cur->cptr, chptr);
cur = next;
}
/* at this point, the channel should not exist locally */
sendto_serv_butone(cptr, ":%s CHANKILL %s :%s", parv[0], parv[1],
(parc == 3) ? parv[2] : "");
return 0;
}
u_long
memcount_m_services(MCm_services *mc)
{
mc->file = __FILE__;
return 0;
}
syntax highlighted by Code2HTML, v. 0.9.1