Files
undernet-cservice/Sources/userlist.c
2015-01-25 18:26:44 -06:00

2140 lines
48 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* @(#)$Id: userlist.c,v 1.56 2000/10/24 16:14:43 seks Exp $ */
/* Undernet Channel Service (X)
* Copyright (C) 1995-2002 Robin Thellend
*
* 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
*
* The author can be contact by email at <csfeedback@robin.pfft.net>
*
* Please note that this software is unsupported and mostly
* obsolete. It was replaced by GNUworld/CMaster. See
* http://gnuworld.sourceforge.net/ for more information.
*/
#include "h.h"
#define VALIDMASK "^.+!.*[^*?]@(((.+\\.)?[^*?]+\\.[a-z]+)|([0-9]+\\.[0-9]+\\.[0-9*]+(\\.[0-9*]+)?))$"
typedef struct OldDiskUser
{
char realname[80];
char match[80];
char passwd[20];
char channel[80];
char modif[80];
int Access;
unsigned long flags;
time_t suspend;
time_t lastseen;
}
OldDiskUser;
struct modinfo_struct
{
char source[20];
char field[80];
char newvalue[80];
};
struct showaccess_struct
{
char source[80];
char target[80];
char chaninfo[80];
char modifby[80];
int nicksearch;
int min, max;
int mask, xmask;
int modif;
};
int ul_hash(char *channel)
{
register int i, j = 0;
for (i = 1; i < strlen(channel); i++)
j += (unsigned char)toupper(channel[i]);
return (j % 1000);
}
void free_user(RegUser ** head)
{
register RegUser *tmp = *head;
if ((*head)->inuse != 0)
log("ERROR!!!! free_user(): inuse != 0");
*head = (*head)->next;
TTLALLOCMEM -= strlen(tmp->realname) + 1;
free(tmp->realname);
TTLALLOCMEM -= strlen(tmp->match) + 1;
free(tmp->match);
TTLALLOCMEM -= strlen(tmp->passwd) + 1;
free(tmp->passwd);
TTLALLOCMEM -= strlen(tmp->channel) + 1;
free(tmp->channel);
TTLALLOCMEM -= strlen(tmp->modif) + 1;
free(tmp->modif);
TTLALLOCMEM -= sizeof(RegUser);
free(tmp);
}
void LoadUserList(char *source)
{
RegUser *curr;
char fname[256];
OldDiskUser tmp;
dbuser db;
struct stat st;
int in, out, i;
/* store master info */
curr = (RegUser *) MALLOC(sizeof(RegUser));
memset(curr, 0, sizeof(RegUser));
curr->realname = (char *)MALLOC(strlen(MASTER_REALNAME) + 1);
strcpy(curr->realname, MASTER_REALNAME);
curr->access = MASTER_ACCESS;
curr->passwd = (char *)MALLOC(strlen(MASTER_PASSWD) + 1);
strcpy(curr->passwd, MASTER_PASSWD);
curr->match = (char *)MALLOC(strlen(MASTER_MATCH) + 1);
strcpy(curr->match, MASTER_MATCH);
curr->channel = (char *)MALLOC(strlen(MASTER_CHANNEL) + 1);
strcpy(curr->channel, MASTER_CHANNEL);
curr->modif = (char *)MALLOC(1);
curr->modif[0] = '\0';
curr->flags = MASTER_FLAGS;
curr->lastseen = now;
curr->suspend = (time_t) 0;
curr->modified = 0;
curr->lastused = now + now; /* Don't swap */
curr->offset = (off_t) - 1;
curr->next = UserList[0];
UserList[0] = curr;
/* We don't *load* the database anymore. But if it doesn't
* exist, we need to create it, possibly from the old userlist.dat
* file.
*/
if (stat("db/channels/0000", &st) >= 0)
return;
mkdir("db", 0700);
mkdir("db/channels", 0700);
if (stat("db/channels", &st) < 0)
return;
for (i = 0; i < 1000; i++)
{
sprintf(fname, "db/channels/%04X", i);
mkdir(fname, 0700);
}
if ((in = open(USERFILE, O_RDONLY)) < 0)
return;
while (read(in, &tmp, sizeof(tmp)) > 0)
{
if (tmp.Access == 0)
continue;
memset(&db, 0, sizeof(db));
db.header[0] = 0xff;
db.header[1] = 0xff;
db.footer[0] = 0xff;
db.footer[1] = 0xff;
strcpy(db.nick, tmp.realname);
strcpy(db.match, tmp.match);
if (strcmp(tmp.passwd, "*"))
strcpy(db.passwd, tmp.passwd);
strcpy(db.channel, tmp.channel);
strcpy(db.modif, tmp.modif);
db.access = tmp.Access;
db.flags = (tmp.flags & UFL_AUTOOP);
db.suspend = tmp.suspend;
db.lastseen = tmp.lastseen;
if ((out = open(make_dbfname(tmp.channel),
O_WRONLY | O_APPEND | O_CREAT, 0600)) >= 0)
{
write(out, &db, sizeof(db));
close(out);
}
}
}
RegUser *IsValid(aluser * luser, char *channel)
{
register avalchan *valchan;
if (luser == NULL)
return NULL;
valchan = luser->valchan;
while (valchan != NULL)
{
if (!strcasecmp(valchan->name, channel))
break;
valchan = valchan->next;
}
#ifdef DEBUG
printf("IsValid() --> %p\n", valchan);
#endif
return (valchan) ? valchan->reg : NULL;
}
void try_find(char *channel, aluser * user)
{
register RegUser *reg;
register avalchan *vchan;
char userhost[200];
sprintf(userhost, "%s!%s@%s", user->nick, user->username, user->site);
if (IsValid(user, channel))
return;
reg = UserList[ul_hash(channel)];
while (reg != NULL)
{
if (!strcasecmp(reg->channel, channel) &&
match(userhost, reg->match) &&
*reg->passwd == '\0')
{
vchan = (avalchan *) MALLOC(sizeof(avalchan));
vchan->name = (char *)MALLOC(strlen(channel) + 1);
strcpy(vchan->name, channel);
vchan->reg = reg;
reg->inuse++;
reg->lastseen = now;
reg->modified = 1;
vchan->next = user->valchan;
user->valchan = vchan;
break;
}
reg = reg->next;
}
}
int LAccess(char *channel, aluser * user)
{
register avalchan *vchan;
if (user == NULL)
return 0;
vchan = user->valchan;
while (vchan != NULL && strcasecmp(channel, vchan->name))
vchan = vchan->next;
#ifdef DEBUG
printf("LAcccess()= %d\n", (vchan != NULL) ? vchan->reg->access : 0);
#endif
if (vchan == NULL || vchan->reg->suspend >= now ||
vchan->reg->passwd[0] == '\0')
return 0;
return vchan->reg->access;
}
int Access(char *channel, char *nick)
{
return LAccess(channel, ToLuser(nick));
}
RegUser *load_dbuser(off_t offset, dbuser * dbu)
{
register RegUser *new, *scan;
register int idx;
#ifdef DEBUG
if (dbu)
printf("load: hdr: %X%X nick: %s match: %s passwd: %s channel: %s "
"modif: %s access: %d flags: %ld susp: %ld last: %ld ftr: %X%X\n",
dbu->header[0], dbu->header[1], dbu->nick, dbu->match, dbu->passwd,
dbu->channel, dbu->modif, dbu->access, dbu->flags, dbu->suspend,
dbu->lastseen, dbu->footer[0], dbu->footer[1]);
#endif
idx = ul_hash(dbu->channel);
/* Make sure that entry is not already on memory. If it is,
* there is no need to load it again.
*/
scan = UserList[idx];
while (scan && (scan->offset != offset ||
strcasecmp(scan->channel, dbu->channel)))
scan = scan->next;
if (scan != NULL)
{
if (scan->access == 0 || strcmp(dbu->nick, scan->realname))
return NULL;
return scan;
}
new = (RegUser *) MALLOC(sizeof(RegUser));
memset(new, 0, sizeof(RegUser));
new->realname = (char *)MALLOC(strlen(dbu->nick) + 1);
strcpy(new->realname, dbu->nick);
new->match = (char *)MALLOC(strlen(dbu->match) + 1);
strcpy(new->match, dbu->match);
new->channel = (char *)MALLOC(strlen(dbu->channel) + 1);
strcpy(new->channel, dbu->channel);
new->passwd = (char *)MALLOC(strlen(dbu->passwd) + 1);
strcpy(new->passwd, dbu->passwd);
new->modif = (char *)MALLOC(strlen(dbu->modif) + 1);
strcpy(new->modif, dbu->modif);
new->access = dbu->access;
new->flags = dbu->flags;
new->suspend = dbu->suspend;
new->lastseen = dbu->lastseen;
new->offset = offset;
new->inuse = 0;
new->modified = 0;
new->lastused = now;
new->next = UserList[idx];
UserList[idx] = new;
return new;
}
static void successful_auth(aluser * luser, char *channel, RegUser * reg)
{
char buffer[512];
register avalchan *vchan;
register achannel *chan;
time_t last;
vchan = (avalchan *) MALLOC(sizeof(avalchan));
vchan->name = (char *)MALLOC(strlen(channel) + 1);
strcpy(vchan->name, channel);
vchan->reg = reg;
reg->inuse++;
reg->lastseen = now;
reg->modified = 1;
vchan->next = luser->valchan;
luser->valchan = vchan;
if (reg->passwd[0] == '\0')
{
sprintf(buffer, "Passwords are now mandatory. "
"Please use the 'newpass' command now.");
}
else
{
sprintf(buffer, "AUTHENTICATION SUCCESSFUL ON %s!",
channel);
}
notice(luser->nick, buffer);
if (reg->suspend > now)
notice(luser->nick, "... however, your access is suspended!");
sprintf(buffer, "AUTH: %s!%s@%s as %s on %s",
luser->nick, luser->username, luser->site,
reg->realname, reg->channel);
log(buffer);
last = (now - reg->lastseen) / 86400;
if (last > 1)
{
sprintf(buffer, "I last saw you %ld days ago", last);
notice(luser->nick, buffer);
}
if (strcmp(channel, "*"))
{
if (!strcmp(reg->channel, "*"))
{
sprintf(buffer, "You now have access on %s", channel);
notice(luser->nick, buffer);
sprintf(buffer, "%s is getting access on %s",
luser->nick, channel);
broadcast(buffer, 1);
}
chan = ToChannel(channel);
sprintf(buffer, "%s!%s@%s", luser->nick, luser->username,
luser->site);
if (chan && chan->on && chan->AmChanOp
&& reg && (reg->flags & UFL_AUTOOP)
&& reg->suspend < now
&& !(chan->flags & CFL_NOOP)
&& IsShit(channel, buffer, NULL, NULL) < NO_OP_SHIT_LEVEL
)
{
op("", channel, luser->nick);
}
}
else
{
if (reg->access < 500)
notice(luser->nick, "You are now an authenticated helper");
else
notice(luser->nick, "You now have administrative access");
}
}
static void
validate_callback(int *fd, off_t off, int action, void *hook1, void *hook2,
dbuser * dbu, int count)
{
register aluser *luser;
register RegUser *reg;
char userhost[200];
#ifdef DEBUG
if (dbu)
printf("vall: hdr: %X%X nick: %s match: %s passwd: %s channel: %s "
"modif: %s access: %d flags: %ld susp: %ld last: %ld ftr: %X%X\n",
dbu->header[0], dbu->header[1], dbu->nick, dbu->match, dbu->passwd,
dbu->channel, dbu->modif, dbu->access, dbu->flags, dbu->suspend,
dbu->lastseen, dbu->footer[0], dbu->footer[1]);
else
printf("vall: end.\n");
#endif
if (dbu != NULL)
{
luser = ToLuser((char *)hook1);
if (luser == NULL)
{
/* It is possible the user has quit or changed his nick
* since the request for authentication was made. In
* such a situation, we load the structure anyway, but
* don't link it anywhere.
*/
return;
}
reg = load_dbuser(off, dbu);
sprintf(userhost, "%s!%s@%s", luser->nick, luser->username,
luser->site);
if (reg != NULL && match(userhost, reg->match))
{
successful_auth(luser, dbu->channel, reg);
}
else
{
char buf[200];
sprintf(buf, "AUTHENTICATION FAILED ON %s!", dbu->channel);
notice((char *)hook1, buf);
}
}
else
{
if (count == 0)
{
char buf[200];
sprintf(buf, "AUTHENTICATION FAILED ON %s!", (char *)hook2);
notice((char *)hook1, buf);
}
free(hook1);
free(hook2);
}
}
void validate(char *source, char *target, char *args)
{
char channel[80], passwd[80], userhost[200], buffer[200];
register avalchan *vchan, **pvchan;
register RegUser *ruser;
register aluser *luser;
luser = ToLuser(source);
if (*args == '#' || *args == '*')
{
GetWord(0, args, channel);
args = ToWord(1, args);
}
else
{
strcpy(channel, target);
GuessChannel(source, channel);
if (*channel != '#')
{
notice(source, "SYNTAX: login <channel> [password]");
return;
}
}
GetWord(0, args, passwd);
if (*passwd && !strchr(target, '@'))
{
sprintf(buffer, "Please use /msg %s@%s login [channel] [password]",
mynick, SERVERNAME);
notice(source, buffer);
return;
}
#ifdef DEBUG
printf("Authentication request..\nFROM: %s\nCHANNEL: %s\nPASSWORD: %s\n",
source, channel, passwd);
#endif
/* remove any existing link to a userlist structure for the
* requested channel.
*/
pvchan = &luser->valchan;
while (*pvchan != NULL && strcasecmp((*pvchan)->name, channel))
pvchan = &(*pvchan)->next;
if (*pvchan != NULL)
{
vchan = *pvchan;
*pvchan = (*pvchan)->next;
vchan->reg->inuse--;
vchan->reg->lastused = now;
TTLALLOCMEM -= strlen(vchan->name) + 1;
free(vchan->name);
TTLALLOCMEM -= sizeof(avalchan);
free(vchan);
}
sprintf(userhost, "%s!%s@%s", luser->nick, luser->username, luser->site);
ruser = UserList[ul_hash(channel)];
while (ruser != NULL)
{
if (!strcasecmp(ruser->channel, channel) &&
match(userhost, ruser->match) &&
!strcmp(ruser->passwd, passwd))
break;
ruser = ruser->next;
}
if (ruser == NULL)
{ /* hmm might be in the admin list too.. */
ruser = UserList[0];
while (ruser != NULL)
{
if (!strcasecmp(ruser->channel, "*") &&
match(userhost, ruser->match) &&
!strcmp(ruser->passwd, passwd))
break;
ruser = ruser->next;
}
}
if (ruser == NULL)
{ /* ok.. not in memory.. send db query */
char *hook1, *hook2;
hook1 = (char *)malloc(strlen(source) + 1);
hook2 = (char *)malloc(strlen(channel) + 1);
strcpy(hook1, source);
strcpy(hook2, channel);
db_fetch(channel, DBGETUHPASS, userhost, passwd, 0,
hook1, hook2, validate_callback);
}
else
{
successful_auth(luser, channel, ruser);
}
}
void DeAuth(char *source, char *chan, char *args)
{
char channel[80];
char buffer[512];
register aluser *luser;
register avalchan *vchan, **pvchan;
luser = ToLuser(source);
if (*args == '#' || *args == '*')
{
GetWord(0, args, channel);
}
else
{
strcpy(channel, chan);
GuessChannel(source, channel);
}
if (!*channel)
{
notice(source, "SYNTAX: deauth <#channel>");
return;
}
pvchan = &luser->valchan;
while (*pvchan != NULL && strcasecmp((*pvchan)->name, channel))
pvchan = &(*pvchan)->next;
if (*pvchan != NULL)
{
vchan = *pvchan;
*pvchan = (*pvchan)->next;
vchan->reg->inuse--;
vchan->reg->lastused = now;
TTLALLOCMEM -= strlen(vchan->name) + 1;
free(vchan->name);
TTLALLOCMEM -= sizeof(avalchan);
free(vchan);
sprintf(buffer, "You have been successfully deauthenticated on %s",channel);
notice(source, buffer);
}
else
{
sprintf(buffer, "You do not appear to be authenticated on %s",channel);
notice(source, buffer);
}
}
static void
adduser_callback(int *fd, off_t off, int action, void *hook1, void *hook2,
dbuser * dbu, int count)
{
RegUser *newuser = (RegUser *) hook2, *scan;
char buffer[200];
int ok = 0;
if (dbu != NULL && count > 0)
{
/* check if entry was deleted */
scan = UserList[ul_hash(dbu->channel)];
while (scan != NULL && (scan->offset != off || scan->access != 0 ||
strcasecmp(scan->channel, dbu->channel)))
{
scan = scan->next;
}
if (scan != NULL)
{
ok = 1;
}
else
{
if (load_dbuser(off, dbu) != NULL)
{
notice((char *)hook1, "This user is already present in the list.");
sprintf(buffer, "NICK: %s MATCH: %s ACCESS: %d",
dbu->nick, dbu->match, dbu->access);
notice((char *)hook1, buffer);
free_user(&newuser);
}
else
ok = 1;
}
}
else if (count == 0)
{
ok = 1;
}
if (ok)
{
/* OK, go ahead and add the new entry in the list
*/
newuser->next = UserList[ul_hash(newuser->channel)];
UserList[ul_hash(newuser->channel)] = newuser;
sprintf(buffer, "New user %s (%s) added on %s with access %d",
newuser->realname, newuser->match, newuser->channel,
newuser->access);
notice((char *)hook1, buffer);
}
if (dbu == NULL)
free(hook1);
}
void AddUser(char *source, char *ch, char *args)
{
register RegUser *newuser, *curr;
register aluser *luser, *src;
register achannel *chan;
void *hook;
char buffer[500];
char channel[80];
char realname[80];
char mask[80];
char straccess[80];
char password[80];
char *ptr, *ptr2;
int acc;
int srcacs;
RegUser *reg;
time_t now1 = now + 3600;
struct tm *tms = gmtime(&now1);
src = ToLuser(source);
if (*args == '#' || (*args == '*' && *(args + 1) == ' ' && IsValid(src, ch)))
{
GetWord(0, args, channel);
args = ToWord(1, args);
}
else
{
strcpy(channel, ch);
GuessChannel(source, channel);
}
if(CheckAdduserFlood(source, channel))
{
return;
}
GetWord(0, args, realname);
GetWord(1, args, mask);
if (isdigit(*mask) || *mask == '-')
{
strcpy(straccess, mask);
GetWord(2, args, password);
luser = ToLuser(realname);
if (luser == NULL)
{
*mask = '\0';
}
else
{
MakeBanMask(luser, mask);
}
}
else
{
GetWord(2, args, straccess);
GetWord(3, args, password);
}
ptr = strchr(mask, '@');
ptr2 = strchr(mask, '!');
if (ptr == NULL || ptr2 == NULL || ptr2 > ptr ||
strchr(ptr2 + 1, '!') || strchr(ptr + 1, '@'))
{
notice(source, "Invalid nick!user@host mask");
return;
}
for (ptr = mask; *ptr; ptr++)
{
if (*ptr <= 32)
break;
}
if (*ptr)
{
notice(source, "Invalid nick!user@host mask");
return;
}
if (!regex_cmp(VALIDMASK, mask))
{
notice(source, "Invalid nick!user@host mask");
return;
}
for (ptr = realname; *ptr; ptr++)
{
if (*ptr <= 32)
break;
}
if (*ptr)
{
notice(source, "Invalid nick!");
return;
}
if ((!strcmp(channel, "*") && !IsValid(src, channel)) ||
!*realname || !*mask || !*straccess)
{
notice(source, "SYNTAX: adduser [#channel] <nick> [mask] <access> <password>");
return;
}
srcacs = Access(channel, source);
if (srcacs < ADD_USER_LEVEL)
{
ReplyNotAccess(source, channel);
return;
}
if (*realname == '-' || strchr(realname, '*') || strchr(realname, '?'))
{
notice(source, "Can't add user.. bogus nick");
return;
}
if (strlen(straccess) > 4)
{
notice(source, "Can't add user.. bogus access");
return;
}
acc = atoi(straccess);
/* can't add a user with a higher access than his! */
if (srcacs <= acc)
{
notice(source, "Can't add a user with an access higher than or equal to yours");
return;
}
if (acc == 0 || (*channel == '#' && acc < 0))
{
notice(source, "Can't add a user with access <= 0");
return;
}
if (!*password && acc > 0)
{
notice(source, "A password must be supplied");
return;
}
/* password must be at least 6 chars long! why?.. hmm why not! ;) */
if (strlen(password) < 6)
{
notice(source, "Password must be at least 6 characters long");
return;
}
if (strlen(password) > 18)
{
notice(source, "Password cannot be longer than 18 characters");
return;
}
/* check if the user is not already in the list.. */
curr = UserList[ul_hash(channel)];
while (curr)
{
if (!strcasecmp(channel, curr->channel) &&
!strcasecmp(curr->realname, realname))
{
break;
}
else
{
curr = curr->next;
}
}
if (curr)
{
notice(source, "This user is already present in the list.");
sprintf(buffer, "NICK: %s MATCH: %s ACCESS: %d",
curr->realname, curr->match, curr->access);
notice(source, buffer);
return;
}
/* OK, there is no conflict with structures in memory. Now we
* must check in the database. Create the structure and pass it
* as a hook with the db query.
*/
newuser = (RegUser *) MALLOC(sizeof(RegUser));
memset(newuser, 0, sizeof(RegUser));
newuser->realname = (char *)MALLOC(strlen(realname) + 1);
strcpy(newuser->realname, realname);
newuser->match = (char *)MALLOC(strlen(mask) + 1);
strcpy(newuser->match, mask);
newuser->access = acc;
newuser->passwd = (char *)MALLOC(strlen(password) + 1);
strcpy(newuser->passwd, password);
newuser->channel = (char *)MALLOC(strlen(channel) + 1);
strcpy(newuser->channel, channel);
reg = IsValid(src, channel);
sprintf(buffer, "%04d%02d%02d@%03ld (%s) %s!%s@%s",
tms->tm_year + 1900, tms->tm_mon + 1, tms->tm_mday,
1000 * (now1 % 86400) / 86400,
reg ? reg->realname : "?",
src->nick, src->username, src->site);
newuser->modif = (char *)MALLOC(strlen(buffer) + 1);
strcpy(newuser->modif, buffer);
newuser->suspend = 0;
newuser->lastseen = now;
newuser->offset = (off_t) - 1;
newuser->modified = 1;
newuser->next = NULL;
if ((chan = ToChannel(channel)) != NULL)
{
newuser->flags = chan->uflags;
}
else
{
newuser->flags = 0;
}
hook = (char *)malloc(strlen(source) + 1);
strcpy(hook, source);
db_fetch(channel, DBGETNICK, newuser->realname, "", 0, hook, newuser,
adduser_callback);
}
static void
show_this_user_access_reg(char *source, RegUser * user, int modif)
{
char buffer[512];
time_t t;
int days, hours, mins, secs;
sprintf(buffer, "USER: %s (%s) ACCESS: %d L%s%s%s",
user->realname, user->match, user->access,
(user->modified == 1) ? "M" : "", (*user->passwd) ? "P" : "",
(user->inuse > 0) ? "U" : "");
notice(source, buffer);
sprintf(buffer, "CHANNEL: %s -- AUTOOP: %s",
user->channel,
(user->flags & UFL_AUTOOP) ? "ON" : "OFF");
notice(source, buffer);
if (user->suspend > now)
{
sprintf(buffer, "SUSPEND EXP: %s",
time_remaining(user->suspend - now));
notice(source, buffer);
}
if (user->lastseen + MIN_LASTSEEN < now)
{
t = now - user->lastseen;
days = (int)t / 86400;
t %= 86400;
hours = (int)t / 3600;
t %= 3600;
mins = (int)t / 60;
t %= 60;
secs = (int)t;
*buffer = '\0';
if (days > 0)
{
sprintf(buffer, "LAST SEEN: %d days, %02d:%02d:%02d ago",
days, hours, mins, secs);
}
else
{
sprintf(buffer, "LAST SEEN: %02d:%02d:%02d ago",
hours, mins, secs);
}
notice(source, buffer);
}
if (modif)
{
if (user->modif[0] == '\0')
sprintf(buffer, "LAST MODIF: unknown");
else
sprintf(buffer, "LAST MODIF: %s", user->modif);
notice(source, buffer);
}
}
static void
show_this_user_access_dbu(char *source, dbuser * dbu, int modif)
{
char buffer[512];
time_t t;
int days, hours, mins, secs;
sprintf(buffer, "USER: %s (%s) ACCESS: %d %s",
dbu->nick, dbu->match, dbu->access,
(*dbu->passwd) ? "P" : "");
notice(source, buffer);
sprintf(buffer, "CHANNEL: %s -- AUTOOP: %s",
dbu->channel,
(dbu->flags & UFL_AUTOOP) ? "ON" : "OFF");
notice(source, buffer);
if (dbu->suspend > now)
{
sprintf(buffer, "SUSPEND EXP: %s",
time_remaining(dbu->suspend - now));
notice(source, buffer);
}
if (dbu->lastseen + MIN_LASTSEEN < now)
{
t = now - dbu->lastseen;
days = (int)t / 86400;
t %= 86400;
hours = (int)t / 3600;
t %= 3600;
mins = (int)t / 60;
t %= 60;
secs = (int)t;
*buffer = '\0';
if (days > 0)
{
sprintf(buffer, "LAST SEEN: %d days, %02d:%02d:%02d ago",
days, hours, mins, secs);
}
else
{
sprintf(buffer, "LAST SEEN: %02d:%02d:%02d ago",
hours, mins, secs);
}
notice(source, buffer);
}
if (modif)
{
if (dbu->modif[0] == '\0')
sprintf(buffer, "LAST MODIF: unknown");
else
sprintf(buffer, "LAST MODIF: %s", dbu->modif);
notice(source, buffer);
}
}
static void
showaccess_callback(int *fd, off_t off, int action, void *hook1, void *hook2,
dbuser * dbu, int count)
{
struct showaccess_struct *ptr = (struct showaccess_struct *)hook1;
register RegUser *scan;
int *cnt = (int *)hook2;
if (dbu == NULL)
{
if (*cnt == 0 && count != 0)
notice(ptr->source, "No match!");
else if (*cnt != 0)
{
notice(ptr->source, "End of access list");
CheckFloodFlood(ptr->source, (*cnt) + (*cnt));
}
else
notice(ptr->source,
"That channel doesn't appear to be registered");
free(hook1);
free(hook2);
return;
}
scan = UserList[ul_hash(dbu->channel)];
while (scan != NULL && (scan->offset != off ||
strcasecmp(scan->channel, dbu->channel)))
scan = scan->next;
if (scan != NULL)
return;
if (((ptr->nicksearch && match(dbu->nick, ptr->target)) ||
(!ptr->nicksearch && compare(ptr->target, dbu->match)) ||
(ptr->nicksearch && match(ptr->chaninfo, dbu->match))) &&
dbu->access >= ptr->min && dbu->access <= ptr->max &&
(ptr->mask == 0 || (dbu->flags & ptr->mask) == ptr->mask) &&
(ptr->xmask == 0 || (dbu->flags & ptr->xmask) == 0) &&
(*ptr->modifby == '\0' || match(dbu->modif, ptr->modifby)))
{
show_this_user_access_dbu(ptr->source, dbu, ptr->modif);
(*cnt)++;
if (*cnt > 15 && ptr->source[0] != '+')
{
notice(ptr->source,
"There are more than 15 matching entries");
notice(ptr->source, "Please restrict your query");
close(*fd);
*fd = -1;
}
}
}
void showaccess(char *source, char *ch, char *args)
{
char buffer[500], argument[80], channel[80];
char realname[80], chaninfo[80] = "", modifby[80] = "";
register RegUser *scan;
register aluser *luser;
register int nicksearch;
int min = 0, max = MASTER_ACCESS, mask = 0, xmask = 0, modif = 0, srcacs,
count;
struct showaccess_struct *hook1;
int *hook2;
/* use another channel if provided as argument */
if (*args == '#' || *args == '*')
{
GetWord(0, args, channel);
args = ToWord(1, args);
}
else
{
strcpy(channel, ch);
GuessChannel(source, channel);
}
/* if no name is provided.. use source */
GetWord(0, args, realname);
if (*realname == '-')
{
strcpy(realname, "*");
}
else if (!*realname)
{
strcpy(realname, source);
}
else
{
args = ToWord(1, args);
}
luser = ToLuser(realname);
if (!strcmp(channel, "*") && !IsValid(ToLuser(source), channel))
{
notice(source, "SYNTAX: access <channel> [nick]");
return;
}
#ifdef DEBUG
printf("SHOWACCESS:\nFROM: %s\nCHANNEL: %s\nWHO: %s\n",
source, channel, args);
#endif
/* parse arguments */
while (*args)
{
GetWord(0, args, argument);
args = ToWord(1, args);
if (!strcasecmp(argument, "-min"))
{
min = atoi(args);
args = ToWord(1, args);
}
else if (!strcasecmp(argument, "-max"))
{
max = atoi(args);
args = ToWord(1, args);
}
else if (!strcasecmp(argument, "-autoop"))
{
mask |= UFL_AUTOOP;
}
else if (!strcasecmp(argument, "-noautoop"))
{
xmask |= UFL_AUTOOP;
}
else if (!strcasecmp(argument, "-modif"))
{
modif = 1;
if (*args && *args != '-')
{
GetWord(0, args, modifby);
args = ToWord(1, args);
}
}
else
{
sprintf(buffer, "\"%s\": Unknown option", argument);
notice(source, buffer);
return;
}
}
/* store the access of the person querying */
srcacs = Access(channel, source);
if (*source && srcacs < SHOW_ACCESS_LEVEL)
{
ReplyNotAccess(source, channel);
return;
}
if (CurrentSendQ > HIGHSENDQTHRESHOLD)
{
notice(source, "Cannot process your request at this time. Try again later.");
return;
}
/* if the user is online.. use his address */
if (luser != NULL)
{
sprintf(chaninfo, "%s!%s@%s",
luser->nick, luser->username, luser->site);
}
#ifdef DEBUG
printf("showaccess(): REALNAME= %s CHANINFO= %s\n", realname, chaninfo);
#endif
nicksearch = 0;
if (!strchr(realname, '@'))
{
if (strchr(realname, '!'))
strcat(realname, "@*");
else if (strchr(realname, '.'))
{
sprintf(buffer, "*!*@%s", realname);
strcpy(realname, buffer);
}
else
nicksearch = 1;
}
count = 0;
scan = UserList[ul_hash(channel)];
while (scan != NULL)
{
if (strcmp(scan->realname, "!DEL!") &&
!strcasecmp(scan->channel, channel) &&
((nicksearch && match(scan->realname, realname)) ||
(!nicksearch && compare(realname, scan->match)) ||
(nicksearch && match(chaninfo, scan->match))) &&
scan->access >= min && scan->access <= max &&
(mask == 0 || (scan->flags & mask) == mask) &&
(xmask == 0 || (scan->flags & xmask) == 0) &&
(*modifby == '\0' || match(scan->modif, modifby)))
{
if (++count > 15 && source[0] != '+')
{
notice(source,
"There are more than 15 matching entries. "
"Please restrict you search");
return;
}
show_this_user_access_reg(source, scan, modif);
}
scan = scan->next;
}
hook1 = (struct showaccess_struct *)
malloc(sizeof(struct showaccess_struct));
strcpy(hook1->source, source);
strcpy(hook1->target, realname);
strcpy(hook1->chaninfo, chaninfo);
strcpy(hook1->modifby, modifby);
hook1->nicksearch = nicksearch;
hook1->min = min;
hook1->max = max;
hook1->mask = mask;
hook1->xmask = xmask;
hook1->modif = modif;
hook2 = (int *)malloc(sizeof(int));
*hook2 = count;
db_fetch(channel, DBGETALLCMP, "", NULL, 0, hook1, hook2,
showaccess_callback);
}
static void
suspend_callback(int *fd, off_t off, int action, void *hook1, void *hook2,
dbuser * dbu, int count)
{
char buffer[512];
register aluser *lusr;
register RegUser *user;
time_t exp;
exp = action + now;
if (count == 0)
{
if (*(char *)hook1)
notice((char *)hook1, "No match!");
}
else if (dbu != NULL && (user = load_dbuser(off, dbu)) != NULL)
{
#ifdef DEBUG
printf("SUSPEND for %s till %ld\n",
user->realname, exp);
puts(ctime(&exp));
#endif
if (*(char *)hook1 &&
Access(user->channel, (char *)hook1) <= user->access)
{
sprintf(buffer, "User %s's access is higher than or equal to yours",
user->realname);
notice((char *)hook1, buffer);
}
/* If the suspension is the result of a
flood protection (in which case
source==""), I want to make sure
the user is not already suspended for
a longer time! */
else if (*(char *)hook1 || user->suspend < exp)
{
user->suspend = exp;
user->modified = 1;
if (*(char *)hook1 && (lusr = ToLuser((char *)hook1)))
{
RegUser *reg;
time_t now1 = now + 3600;
struct tm *tms = gmtime(&now1);
reg = IsValid(lusr, user->channel);
sprintf(buffer, "%04d%02d%02d@%03ld (%s) %s!%s@%s",
tms->tm_year + 1900, tms->tm_mon + 1, tms->tm_mday,
1000 * (now1 % 86400) / 86400,
reg ? reg->realname : "?",
lusr->nick, lusr->username, lusr->site);
TTLALLOCMEM -= strlen(user->modif) + 1;
free(user->modif);
user->modif = (char *)MALLOC(strlen(buffer) + 1);
strcpy(user->modif, buffer);
}
}
if (*(char *)hook1)
{
if (user->suspend > now)
{
sprintf(buffer,
"SUSPENSION for %s (%s) will expire in %s",
user->realname, user->match,
time_remaining(user->suspend - now));
notice((char *)hook1, buffer);
}
else
{
sprintf(buffer, "SUSPENSION for %s (%s) is cancelled",
user->realname, user->match);
notice((char *)hook1, buffer);
}
}
}
if (dbu == NULL)
{
notice((char *)hook1, "Done.");
free(hook1);
}
}
void unsuspend(char *source, char *ch, char *args)
{
char channel[80];
char target[100];
char out[200];
if (*args == '#' || (*args == '*' && IsValid(ToLuser(source), ch)))
{
GetWord(0, args, channel);
args = ToWord(1, args);
}
else
{
strcpy(channel, ch);
GuessChannel(source, channel);
}
GetWord(0, args, target);
if (!strcmp(channel, "*") || !*target)
{
notice(source, "SYNTAX: unsuspend [#channel] <NICK|ADDRESS>");
return;
}
sprintf(out, "%s %s 0", channel, target);
suspend(source, ch, out);
}
void suspend(char *source, char *ch, char *args)
{
char channel[80], target[80], timestring[80], *hook;
int timeint;
int acc;
if (*args == '#' || (*args == '*' && IsValid(ToLuser(source), ch)))
{
GetWord(0, args, channel);
args = ToWord(1, args);
}
else
{
strcpy(channel, ch);
GuessChannel(source, channel);
}
if (*source)
acc = Access(channel, source);
else
acc = MASTER_ACCESS + 1;
if (acc < LEVEL_SUSPEND)
{
ReplyNotAccess(source, channel);
return;
}
GetWord(0, args, target);
GetWord(1, args, timestring);
if ((!strcmp(channel, "*") && !IsValid(ToLuser(source), channel)) ||
!*target || !*timestring)
{
notice(source, "SYNTAX: suspend [channel] <nick|userhost> <duration> [s|m|d]");
return;
}
timeint = atoi(timestring);
switch (*ToWord(2, args))
{
case 's':
case 'S':
case '\0':
break;
case 'm':
case 'M':
timeint *= 60;
break;
case 'h':
case 'H':
timeint *= 3600;
break;
case 'd':
case 'D':
case 'j':
case 'J':
timeint *= 86400;
break;
default:
notice(source, "Bogus time units");
return;
}
if (timeint < 0 || timeint > 31536000)
{
notice(source, "Invalid time");
return;
}
hook = (char *)malloc(strlen(source) + 1);
strcpy(hook, source);
if (strpbrk(target, "!@") != NULL)
{
db_fetch(channel, DBGETALLCMP, target, NULL, timeint, hook, NULL,
suspend_callback);
}
else
{
db_fetch(channel, DBGETNICK, target, NULL, timeint, hook, NULL,
suspend_callback);
}
}
void SaveUserList(char *source, char *channel)
{
char global[] = "*", buffer[256];
if (*source && Access(global, source) < SAVE_USERLIST_LEVEL)
{
notice(source, "Sorry! This command is not for you");
return;
}
if (DB_Save_Status == -1)
{
notice(source, "Userlist sync initiated");
DB_Save_Status = 0;
strncpy(DB_Save_Nick, source, NICK_LENGTH - 1);
DB_Save_Nick[NICK_LENGTH - 1] = '\0';
}
else
{
sprintf(buffer, "Userlist sync is already in progress (%d%%) [%s]",
DB_Save_Status / 10, *DB_Save_Nick ? DB_Save_Nick : "auto");
notice(source, buffer);
}
/*do_cold_sync();
if(*source)
notice(source,"Userlist saved.");
*/
}
static void
remuser_callback(int *fd, off_t off, int action, void *hook1, void *hook2,
dbuser * dbu, int count)
{
register RegUser *user;
char buffer[512];
if (dbu == NULL)
{
if (count == 0)
{
notice((char *)hook1, "This user is not in my userlist");
notice((char *)hook1, "Make sure you provide a full n!u@h");
}
else
{
notice((char *)hook1, "Done.");
}
free(hook1);
}
else
{
user = load_dbuser(off, dbu);
if (user != NULL && user->access < action)
{
sprintf(buffer, "I REMOVE USER %s (%s) from %s",
user->realname, user->match, user->channel);
notice((char *)hook1, buffer);
TTLALLOCMEM -= strlen(user->realname) + 1;
free(user->realname);
user->realname = (char *)MALLOC(6);
strcpy(user->realname, "!DEL!");
TTLALLOCMEM -= strlen(user->match) + 1;
free(user->match);
user->match = (char *)MALLOC(6);
strcpy(user->match, "!DEL!");
user->access = 0;
user->flags = 0;
/* if new, don't save */
if (user->offset == (off_t) - 1)
user->modified = 0;
else
user->modified = 1;
}
}
}
void RemoveUser(char *source, char *ch, char *arg)
{
char buffer[500];
char channel[80];
char toremove[80];
register RegUser *user;
register aluser *src;
int srcacs;
int nicksearch;
src = ToLuser(source);
if (*arg == '#' || (*arg == '*' && *(arg + 1) == ' ' && IsValid(src, ch)))
{
GetWord(0, arg, channel);
arg = ToWord(1, arg);
}
else
{
strcpy(channel, ch);
GuessChannel(source, channel);
}
GetWord(0, arg, toremove);
if ((!strcmp(channel, "*") && !IsValid(src, channel)) || !*toremove)
{
notice(source, "SYNTAX: remuser [#channel] <nick|address>");
return;
}
if (*source)
srcacs = Access(channel, source);
else
srcacs = MASTER_ACCESS;
if (srcacs < REMOVE_USER_LEVEL)
{
ReplyNotAccess(source, channel);
return;
}
if (strpbrk(toremove, "!@") != NULL)
nicksearch = 0;
else
nicksearch = 1;
user = UserList[ul_hash(channel)];
while (user)
{
if (!strcasecmp(channel, user->channel) && (
(!nicksearch && !strcasecmp(toremove, user->match)) ||
(nicksearch && !strcasecmp(toremove, user->realname))))
break;
user = user->next;
}
if (user != NULL)
{
if (user->access >= srcacs)
{
notice(source, "This user's access is higher "
"than yours. Won't remove him!");
}
else
{
sprintf(buffer, "I REMOVE USER %s (%s) from %s",
user->realname, user->match, user->channel);
notice(source, buffer);
TTLALLOCMEM -= strlen(user->realname) + 1;
free(user->realname);
user->realname = (char *)MALLOC(6);
strcpy(user->realname, "!DEL!");
TTLALLOCMEM -= strlen(user->match) + 1;
free(user->match);
user->match = (char *)MALLOC(6);
strcpy(user->match, "!DEL!");
user->access = 0;
user->flags = 0;
if (user->offset == (off_t) - 1)
user->modified = 0;
else
user->modified = 1;
}
}
if ((user == NULL && nicksearch) || !nicksearch)
{
/* User entry is not found in memory. Send a database
* query for it.
*/
char *hook;
hook = (char *)malloc(strlen(source) + 1);
strcpy(hook, source);
if (nicksearch)
db_fetch(channel, DBGETNICK, toremove, NULL, srcacs, hook,
NULL, remuser_callback);
else
db_fetch(channel, DBGETALLUH, toremove, NULL, srcacs, hook,
NULL, remuser_callback);
}
else
{
notice(source, "Done.");
}
}
void purge(char *source, char *ch, char *args)
{
register ShitUser **shit, *tshit;
register RegUser *user;
register int index;
char buffer[1024];
char channel[80];
char global[] = "*";
char *comment;
if (Access(global, source) < XADMIN_LEVEL)
{
notice(source, "Sorry. This command is reserved to X-admins.");
return;
}
GetWord(0, args, channel);
comment = ToWord(1, args);
if (!*channel || *channel != '#' || !*comment)
{
notice(source, "SYNTAX: purge <channel> <comment>");
return;
}
sprintf(buffer, "%s is purging channel %s (%s)",
source, channel, comment);
broadcast(buffer, 1);
RemChan("", channel, "");
part("", channel, "");
shit = &ShitList[sl_hash(channel)];
while (*shit != NULL)
{
if (!strcasecmp((*shit)->channel, channel))
{
tshit = *shit;
*shit = (*shit)->next;
TTLALLOCMEM -= strlen(tshit->match) + 1;
free(tshit->match);
TTLALLOCMEM -= strlen(tshit->from) + 1;
free(tshit->from);
TTLALLOCMEM -= strlen(tshit->reason) + 1;
free(tshit->reason);
TTLALLOCMEM -= strlen(tshit->channel) + 1;
free(tshit->channel);
TTLALLOCMEM -= sizeof(ShitUser);
free(tshit);
}
else
shit = &(*shit)->next;
}
index = ul_hash(channel);
user = UserList[index];
while (user != NULL)
{
if (!strcasecmp(channel, user->channel))
{
user->access = 0;
user->flags = 0;
user->modified = 0; /* see the unlink() below */
TTLALLOCMEM -= strlen(user->realname) + 1;
free(user->realname);
user->realname = (char *)MALLOC(6);
strcpy(user->realname, "!DEL!");
TTLALLOCMEM -= strlen(user->match) + 1;
free(user->match);
user->match = (char *)MALLOC(6);
strcpy(user->match, "!DEL!");
}
user = user->next;
}
unlink(make_dbfname(channel));
sprintf(buffer, "Channel %s has been disintegrated.. really.", channel);
notice(source, buffer);
sprintf(buffer, "PURGE (mis)used by %s on %s (%s)",
source, channel, comment);
SpecLog(buffer);
}
static void
do_modinfo(char *source, RegUser * user, char *field, char *newvalue)
{
char buffer[512];
register aluser *luser;
register avalchan *vchan;
register char *ptr, *ptr2;
register int change = 0;
luser = ToLuser(source);
if (luser == NULL)
return;
vchan = luser->valchan;
while (vchan && strcasecmp(user->channel, vchan->name))
vchan = vchan->next;
if (vchan == NULL)
{
/* Something happened since the request was sent.
* In any case, it should be ignored now.
*/
return;
}
if (!strcasecmp(field, "NICK"))
{
notice(source, "The NICK option was disabled.");
}
else if (!strcasecmp(field, "MATCH") || !strcasecmp(field, "MASK"))
{
if (user->access < vchan->reg->access)
{
ptr = strchr(newvalue, '@');
ptr2 = strchr(newvalue, '!');
if (!ptr || !ptr2 || ptr2 > ptr || strchr(ptr2 + 1, '!') ||
strchr(ptr + 1, '@') || !regex_cmp(VALIDMASK, newvalue))
{
notice(source, "Invalid nick!user@host mask");
}
else
{
for (ptr = newvalue; *ptr; ptr++)
{
if (*ptr < 33)
break;
}
if (*ptr)
{
notice(source, "Invalid nick!user@host mask");
}
else
{
TTLALLOCMEM -= strlen(user->match) + 1;
free(user->match);
user->match = (char *)MALLOC(strlen(newvalue) + 1);
strcpy(user->match, newvalue);
sprintf(buffer, "New MATCH for %s is %s",
user->realname, user->match);
notice(source, buffer);
change = 1;
}
}
}
}
else if (!strcasecmp(field, "ACCESS"))
{
if (user->access < vchan->reg->access)
{
if (strlen(newvalue) > 4 ||
atoi(newvalue) >= vchan->reg->access ||
atoi(newvalue) < 0)
{
notice(source, "Bogus access");
}
else
{
user->access = atoi(newvalue);
sprintf(buffer, "New ACCESS for %s is %d",
user->realname, user->access);
notice(source, buffer);
change = 1;
}
}
}
else if (!strcasecmp(field, "AUTOOP"))
{
if (user->access < vchan->reg->access ||
user == vchan->reg)
{
if (!strcasecmp(newvalue, "ON") ||
!strcasecmp(newvalue, "YES"))
{
user->flags |= UFL_AUTOOP;
}
else if (!strcasecmp(newvalue, "OFF") ||
!strcasecmp(newvalue, "NO"))
{
user->flags &= ~UFL_AUTOOP;
}
else
{
notice(source, "You must specify 'yes' or 'no'");
}
sprintf(buffer, "AUTOOP for %s is %s",
user->realname, (user->flags & UFL_AUTOOP) ? "ON" : "OFF");
notice(source, buffer);
change = 1;
}
}
else if (!strcasecmp(field, "PASSWORD"))
{
if (user->access < vchan->reg->access ||
user == vchan->reg)
{
if (strlen(newvalue) < 6 || strlen(newvalue) > 18)
{
notice(source, "Password must be between 6 and 18 characters long");
}
else
{
TTLALLOCMEM -= strlen(user->passwd) + 1;
free(user->passwd);
user->passwd = (char *)MALLOC(strlen(newvalue) + 1);
strcpy(user->passwd, newvalue);
sprintf(buffer, "New PASSWORD set for %s",
user->realname);
notice(source, buffer);
change = 1;
}
}
}
else if (!strcasecmp(field, "REMPASS"))
{
notice(source, "REMPASS is no longer available. Try PASSWORD.");
}
if (change)
{
RegUser *reg;
time_t now1 = now + 3600;
struct tm *tms = gmtime(&now1);
if (strcasecmp(field, "AUTOOP"))
{
reg = IsValid(luser, user->channel);
sprintf(buffer, "%04d%02d%02d@%03ld (%s) %s!%s@%s",
tms->tm_year + 1900, tms->tm_mon + 1, tms->tm_mday,
1000 * (now1 % 86400) / 86400,
reg ? reg->realname : "?",
luser->nick, luser->username, luser->site);
TTLALLOCMEM -= strlen(user->modif) + 1;
free(user->modif);
user->modif = (char *)MALLOC(strlen(buffer) + 1);
strcpy(user->modif, buffer);
}
user->modified = 1;
user->lastused = now;
}
else
{
notice(source, "Entry was not modified");
}
}
static void
modinfo_callback(int *fd, off_t off, int action, void *hook1, void *hook2,
dbuser * dbu, int count)
{
register RegUser *user;
struct modinfo_struct *ptr = (struct modinfo_struct *)hook1;
if (count == 0)
{
notice(ptr->source, "No match.");
}
else if (dbu != NULL && (user = load_dbuser(off, dbu)) != NULL)
{
do_modinfo(ptr->source, user, ptr->field, ptr->newvalue);
}
if (dbu == NULL)
{
free(ptr);
}
}
void ModUserInfo(char *source, char *msgtarget, char *ch, char *args)
{
char channel[80];
char field[80];
char target[80];
char newvalue[80];
register RegUser *user;
register aluser *luser;
int nicksearch, srcacs, index;
luser = ToLuser(source);
if (*args == '#' || (*args == '*' && *(args + 1) == ' ' && IsValid(luser, ch)))
{
GetWord(0, args, channel);
args = ToWord(1, args);
}
else
{
strcpy(channel, ch);
GuessChannel(source, channel);
}
GetWord(0, args, field);
GetWord(1, args, target);
GetWord(2, args, newvalue);
#ifdef DEBUG
printf("ModUserInfo()\nSOURCE: \"%s\"\nFIELD: \"%s\"\nTARGET: \"%s\"\nNEWVALUE: \"%s\"\n",
source, field, target, newvalue);
#endif
if ((!strcmp(channel, "*") && !IsValid(luser, channel)) ||
!*field || !*target || !*newvalue)
{
notice(source, "SYNTAX: modinfo [#channel] <MATCH,ACCESS,AUTOOP,PASSWORD> <NICK,ADDRESS> <NEW VALUE>");
return;
}
if (!strcasecmp(field, "PASSWORD") && !strchr(msgtarget, '@'))
{
char buffer[200];
sprintf(buffer, "Please use /msg %s@%s", mynick, SERVERNAME);
notice(source, buffer);
return;
}
srcacs = LAccess(channel, luser);
if (srcacs < MOD_USERINFO_LEVEL)
{
ReplyNotAccess(source, channel);
return;
}
if (strpbrk(target, "!@") != NULL)
nicksearch = 0;
else
nicksearch = 1;
index = ul_hash(channel);
user = UserList[index];
while (user)
{
if (!strcasecmp(channel, user->channel) && (
(!nicksearch && match(target, user->match)) ||
(nicksearch && !strcasecmp(target, user->realname))))
break;
user = user->next;
}
if (user != NULL)
{
do_modinfo(source, user, field, newvalue);
}
else
{
struct modinfo_struct *hook;
hook = (struct modinfo_struct *)
malloc(sizeof(struct modinfo_struct));
strcpy(hook->source, source);
strcpy(hook->field, field);
strcpy(hook->newvalue, newvalue);
if (nicksearch)
db_fetch(channel, DBGETNICK, target, NULL, 0, hook,
NULL, modinfo_callback);
else
db_fetch(channel, DBGET1STUH, target, NULL, 0, hook,
NULL, modinfo_callback);
}
}
void ChPass(char *source, char *ch, char *args)
{
char newpassword[80];
char channel[80];
char buffer[200];
char userhost[200];
register RegUser *user;
register aluser *luser;
RegUser *reg;
time_t now1 = now + 3600;
struct tm *tms = gmtime(&now1);
if (*ch == '#')
{
notice(source, "Please DO NOT use the newpass command from a channel!");
return;
}
if (!strchr(ch, '@'))
{
sprintf(buffer, "Please use /msg %s@%s newpass [channel] <new_password>",
mynick, SERVERNAME);
notice(source, buffer);
return;
}
if (*args == '#' || *args == '*')
{
GetWord(0, args, channel);
args = ToWord(1, args);
}
else
{
strcpy(channel, ch);
GuessChannel(source, channel);
}
GetWord(0, args, newpassword);
luser = ToLuser(source);
user = IsValid(luser, channel);
if ((!strcmp(channel, "*") && !user) ||
!*newpassword || *ToWord(1,args) != '\0')
{
notice(source, "SYNTAX: newpass [channel] <new password>");
return;
}
if(user && user->suspend > now)
{
notice(source, "You are suspended. Request is ignored.");
return;
}
if (strlen(newpassword) < 6)
{
notice(source, "A password MUST be at least 6 characters long");
return;
}
if (strlen(newpassword) > 19)
{
notice(source, "Password is too long (max 19 characters)");
return;
}
sprintf(userhost, "%s!%s@%s", luser->nick, luser->username, luser->site);
if (user == NULL || user->access <= 0)
{
notice(source, "You are not authenticated on that channel");
}
else
{
TTLALLOCMEM -= strlen(user->passwd) + 1;
free(user->passwd);
user->passwd = (char *)MALLOC(strlen(newpassword) + 1);
strcpy(user->passwd, newpassword);
TTLALLOCMEM -= strlen(user->modif) + 1;
free(user->modif);
reg = IsValid(luser, user->channel);
sprintf(buffer, "%04d%02d%02d@%03ld (%s) %s!%s@%s",
tms->tm_year + 1900, tms->tm_mon + 1, tms->tm_mday,
1000 * (now1 % 86400) / 86400,
reg ? reg->realname : "?",
luser->nick, luser->username, luser->site);
user->modif = (char *)MALLOC(strlen(buffer) + 1);
strcpy(user->modif, buffer);
notice(source, "Password changed!");
sprintf(buffer, "NEWPASS %s as %s on %s",
userhost, user->realname, user->channel);
log(buffer);
}
return;
}
static void add_sync_channel(char *name)
{
register syncchan **scan = &SyncChan;
while (*scan != NULL && strcasecmp((*scan)->name, name))
scan = &(*scan)->next;
if (*scan == NULL)
{
*scan = (syncchan *) malloc(sizeof(syncchan));
strcpy((*scan)->name, name);
(*scan)->next = NULL;
}
}
void gather_sync_channels(void)
{
register RegUser *reg;
register int i;
for (i = 0; i < 1000; i++)
{
reg = UserList[i];
while (reg != NULL)
{
if (reg->modified ||
(!reg->inuse && reg->lastused + CACHE_TIMEOUT < now))
add_sync_channel(reg->channel);
reg = reg->next;
}
}
}