/* NickServ functions.
*
* (C) 2003-2009 Anope Team
* Contact us at team@anope.org
*
* Please read COPYING and README for further details.
*
* Based on the original code of Epona by Lara.
* Based on the original code of Services by Andy Church.
*
* $Id$
*
*/
#include "services.h"
#include "pseudo.h"
/*************************************************************************/
#define HASH(nick) ((tolower((nick)[0])&31)<<5 | (tolower((nick)[1])&31))
NickAlias *nalists[1024];
NickCore *nclists[1024];
NickRequest *nrlists[1024];
unsigned int guestnum; /* Current guest number */
#define TO_COLLIDE 0 /* Collide the user with this nick */
#define TO_RELEASE 1 /* Release a collided nick */
/*************************************************************************/
static void add_ns_timeout(NickAlias * na, int type, time_t delay);
/*************************************************************************/
/* *INDENT-OFF* */
void moduleAddNickServCmds()
{
ModuleManager::LoadModuleList(NickServCoreNumber, NickServCoreModules);
}
/* *INDENT-ON* */
/*************************************************************************/
/* Return information on memory use. Assumes pointers are valid. */
void get_aliases_stats(long *nrec, long *memuse)
{
long count = 0, mem = 0;
int i;
NickAlias *na;
for (i = 0; i < 1024; i++)
{
for (na = nalists[i]; na; na = na->next)
{
count++;
mem += sizeof(*na);
if (na->nick)
mem += strlen(na->nick) + 1;
if (na->last_usermask)
mem += strlen(na->last_usermask) + 1;
if (na->last_realname)
mem += strlen(na->last_realname) + 1;
if (na->last_quit)
mem += strlen(na->last_quit) + 1;
}
}
*nrec = count;
*memuse = mem;
}
/*************************************************************************/
/* Return information on memory use. Assumes pointers are valid. */
void get_core_stats(long *nrec, long *memuse)
{
long count = 0, mem = 0;
int i, j;
NickCore *nc;
char **accptr;
for (i = 0; i < 1024; i++)
{
for (nc = nclists[i]; nc; nc = nc->next)
{
count++;
mem += sizeof(*nc);
if (nc->display)
mem += strlen(nc->display) + 1;
if (nc->pass)
mem += strlen(nc->pass) + 1;
if (nc->url)
mem += strlen(nc->url) + 1;
if (nc->email)
mem += strlen(nc->email) + 1;
if (nc->greet)
mem += strlen(nc->greet) + 1;
mem += sizeof(char *) * nc->accesscount;
for (accptr = nc->access, j = 0; j < nc->accesscount;
accptr++, j++)
{
if (*accptr)
mem += strlen(*accptr) + 1;
}
mem += nc->memos.memos.size() * sizeof(Memo);
for (j = 0; j < nc->memos.memos.size(); j++)
{
if (nc->memos.memos[j]->text)
mem += strlen(nc->memos.memos[j]->text) + 1;
}
mem += sizeof(void *) * nc->aliases.count;
}
}
*nrec = count;
*memuse = mem;
}
/*************************************************************************/
/*************************************************************************/
/* NickServ initialization. */
void ns_init()
{
moduleAddNickServCmds();
guestnum = time(NULL);
while (guestnum > 9999999)
guestnum -= 10000000;
}
/*************************************************************************/
/* Main NickServ routine. */
void nickserv(User * u, char *buf)
{
const char *cmd, *s;
cmd = strtok(buf, " ");
if (!cmd)
{
return;
}
else if (stricmp(cmd, "\1PING") == 0)
{
if (!(s = strtok(NULL, "")))
{
s = "";
}
ircdproto->SendCTCP(findbot(s_NickServ), u->nick, "PING %s", s);
}
else
{
mod_run_cmd(s_NickServ, u, NICKSERV, cmd);
}
}
/*************************************************************************/
/* Load/save data files. */
#define SAFE(x) do { \
if ((x) < 0) { \
if (!forceload) \
fatal("Read error on %s", NickDBName); \
failed = 1; \
break; \
} \
} while (0)
void load_ns_req_db()
{
dbFILE *f;
int i, c, ver;
NickRequest *nr;
uint32 tmp32;
int failed = 0, len;
char *pass;
if (!(f = open_db(s_NickServ, PreNickDBName, "r", PRE_NICK_VERSION)))
return;
ver = get_file_version(f);
for (i = 0; i < 1024 && !failed; i++)
{
while ((c = getc_db(f)) == 1)
{
if (c != 1)
fatal("Invalid format in %s", PreNickDBName);
nr = new NickRequest;
SAFE(read_string(&nr->nick, f));
SAFE(read_string(&nr->passcode, f));
if (ver < 2)
{
SAFE(read_string(&pass, f));
len = strlen(pass);
enc_encrypt(pass, len, nr->password, PASSMAX);
memset(pass, 0, len);
delete [] pass;
}
else
SAFE(read_buffer(nr->password, f));
SAFE(read_string(&nr->email, f));
SAFE(read_int32(&tmp32, f));
nr->requested = tmp32;
insert_requestnick(nr);
}
}
close_db(f);
}
void load_ns_dbase()
{
dbFILE *f;
int ver, i, j, c;
NickAlias *na, **nalast, *naprev;
NickCore *nc, **nclast, *ncprev;
int failed = 0;
uint16 tmp16;
uint32 tmp32;
char *s, *pass;
if (!(f = open_db(s_NickServ, NickDBName, "r", NICK_VERSION)))
return;
ver = get_file_version(f);
if (ver != 14)
{
close_db(f);
fatal("DB %s is too old", NickDBName);
return;
}
/* First we load nick cores */
for (i = 0; i < 1024 && !failed; i++)
{
nclast = &nclists[i];
ncprev = NULL;
while ((c = getc_db(f)) == 1)
{
if (c != 1)
fatal("Invalid format in %s", NickDBName);
nc = new NickCore();
*nclast = nc;
nclast = &nc->next;
nc->prev = ncprev;
ncprev = nc;
slist_init(&nc->aliases);
SAFE(read_string(&nc->display, f));
SAFE(read_buffer(nc->pass, f));
SAFE(read_string(&nc->email, f));
SAFE(read_string(&nc->greet, f));
SAFE(read_int32(&nc->icq, f));
SAFE(read_string(&nc->url, f));
SAFE(read_int32(&nc->flags, f));
if (!NSAllowKillImmed)
nc->flags &= ~NI_KILL_IMMED;
SAFE(read_int16(&nc->language, f));
/* Add services opers and admins to the appropriate list, but
only if the database version is more than 10. */
if (nc->flags & NI_SERVICES_ADMIN)
slist_add(&servadmins, nc);
if (nc->flags & NI_SERVICES_OPER)
slist_add(&servopers, nc);
SAFE(read_int16(&nc->accesscount, f));
if (nc->accesscount)
{
char **access;
access = static_cast<char **>(scalloc(sizeof(char *) * nc->accesscount, 1));
nc->access = access;
for (j = 0; j < nc->accesscount; j++, access++)
SAFE(read_string(access, f));
}
SAFE(read_int16(&tmp16, f));
if (tmp16) nc->memos.memos.resize(tmp16);
SAFE(read_int16(&tmp16, f));
nc->memos.memomax = static_cast<int16>(tmp16);
if (!nc->memos.memos.empty())
{
for (j = 0; j < nc->memos.memos.size(); j++)
{
nc->memos.
|