Newer
Older
/* Synchronet user data-related routines (exported) */
/* $Id$ */
/****************************************************************************
* @format.tab-size 4 (Plain Text/Source Code File Header) *
* @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) *
* *
* Copyright Rob Swindell - http://www.synchro.net/copyright.html *
* *
* 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. *
* See the GNU General Public License for more details: gpl.txt or *
* http://www.fsf.org/copyleft/gpl.html *
* *
* Anonymous FTP access to the most recent released source is available at *
* ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net *
* *
* Anonymous CVS access to the development source and modification history *
* is available at cvs.synchro.net:/cvsroot/sbbs, example: *
* cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login *
* (just hit return, no password is necessary) *
* cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src *
* *
* For Synchronet coding style and modification guidelines, see *
* http://www.synchro.net/source.html *
* *
* You are encouraged to submit any modifications (preferably in Unix diff *
* format) via e-mail to mods@synchro.net *
* *
* Note: If this box doesn't appear square, then you need to fix your tabs. *
****************************************************************************/
#include "sbbs.h"
#include "cmdshell.h"
/* convenient space-saving global variables */
char* crlf="\r\n";
char* nulstr="";
static const char* strIpFilterExemptConfigFile = "ipfilter_exempt.cfg";
#define VALID_CFG(cfg) (cfg!=NULL && cfg->size==sizeof(scfg_t))
/****************************************************************************/
/* Looks for a perfect match among all usernames (not deleted users) */
/* Makes dots and underscores synonymous with spaces for comparisons */
/* Returns the number of the perfect matched username or 0 if no match */
/****************************************************************************/
uint DLLCALL matchuser(scfg_t* cfg, const char *name, BOOL sysop_alias)
int file,c;
char* p;
char dat[LEN_ALIAS+2];
char str[256];
char tmp[256];
ulong l,length;
FILE* stream;
if(!VALID_CFG(cfg) || name==NULL)
return(0);
if(sysop_alias &&
(!stricmp(name,"SYSOP") || !stricmp(name,"POSTMASTER") || !stricmp(name,cfg->sys_id)))
SAFEPRINTF(str,"%suser/name.dat",cfg->data_dir);
if((stream=fnopen(&file,str,O_RDONLY))==NULL)
length=(long)filelength(file);
for(l=0;l<length;l+=LEN_ALIAS+2) {
fread(dat,sizeof(dat),1,stream);
if(dat[c]==ETX) break;
dat[c]=0;
if(!stricmp(dat,name))
break;
/* convert dots to spaces */
strcpy(str,dat);
REPLACE_CHARS(str,'.',' ',p);
if(!stricmp(str,name))
break;
/* convert spaces to dots */
strcpy(str,dat);
REPLACE_CHARS(str,' ','.',p);
if(!stricmp(str,name))
break;
/* convert dots to underscores */
strcpy(str,dat);
REPLACE_CHARS(str,'.','_',p);
if(!stricmp(str,name))
break;
/* convert underscores to dots */
strcpy(str,dat);
REPLACE_CHARS(str,'_','.',p);
if(!stricmp(str,name))
break;
/* convert spaces to underscores */
strcpy(str,dat);
REPLACE_CHARS(str,' ','_',p);
if(!stricmp(str,name))
break;
/* convert underscores to spaces */
strcpy(str,dat);
REPLACE_CHARS(str,'_',' ',p);
if(!stricmp(str,name))
break;
/* strip spaces (from both) */
strip_space(name,tmp);
if(!stricmp(str,tmp))
if(l<length)
return((l/(LEN_ALIAS+2))+1);
/****************************************************************************/
uint DLLCALL total_users(scfg_t* cfg)
{
char str[MAX_PATH+1];
uint total_users=0;
int file;
long l,length;
if(!VALID_CFG(cfg))
return(0);
if((file=openuserdat(cfg, /* for_modify: */FALSE)) < 0)
return(0);
length=(long)filelength(file);
for(l=0;l<length;l+=U_LEN) {
lseek(file,l+U_MISC,SEEK_SET);
if(read(file,str,8)!=8)
continue;
getrec(str,0,8,str);
if(ahtoul(str)&(DELETED|INACTIVE))
continue;
total_users++;
}
close(file);
return(total_users);
}
/****************************************************************************/

rswindell
committed
/* Returns the number of the last user in user.dat (deleted ones too) */
/****************************************************************************/
uint DLLCALL lastuser(scfg_t* cfg)
{
char str[256];
long length;
if(!VALID_CFG(cfg))
return(0);
SAFEPRINTF(str,"%suser/user.dat", cfg->data_dir);
if((length=(long)flength(str))>0)
return((uint)(length/U_LEN));
return(0);
}
/****************************************************************************/
/* Deletes (completely removes) last user record in user.dat */
/****************************************************************************/
BOOL DLLCALL del_lastuser(scfg_t* cfg)
{
int file;
long length;
if(!VALID_CFG(cfg))
return(FALSE);
if((file=openuserdat(cfg, /* for_modify: */TRUE)) < 0)
length=(long)filelength(file);
if(length<U_LEN) {
close(file);
return(FALSE);
}
chsize(file,length-U_LEN);
close(file);
return(TRUE);
}
/****************************************************************************/
/* Opens the user database returning the file descriptor or -1 on error */
/****************************************************************************/
int DLLCALL openuserdat(scfg_t* cfg, BOOL for_modify)
SAFEPRINTF(path,"%suser/user.dat",cfg->data_dir);
return nopen(path, for_modify ? (O_RDWR|O_CREAT|O_DENYNONE) : (O_RDONLY|O_DENYNONE));
int DLLCALL closeuserdat(int file)
{
return close(file);
}
/****************************************************************************/
/* Locks and reads a single user record from an open user.dat file into a */
/* buffer of U_LEN+1 in size. */
/* Returns 0 on success. */
/****************************************************************************/
int DLLCALL readuserdat(scfg_t* cfg, unsigned user_number, char* userdat, int infile)
{
int i,file;
if(!VALID_CFG(cfg) || user_number<1)
if(infile >= 0)
if((file = openuserdat(cfg, /* for_modify: */FALSE)) < 0)
if(user_number > (unsigned)(filelength(file)/U_LEN)) {

rswindell
committed
return(-1); /* no such user record */
}
lseek(file,(long)((long)(user_number-1)*U_LEN),SEEK_SET);
&& lock(file,(long)((long)(user_number-1)*U_LEN),U_LEN)==-1) {
if(i)
mswait(100);
i++;
}
if(i>=LOOP_NODEDAB) {
return(-2);
}
if(read(file,userdat,U_LEN)!=U_LEN) {
unlock(file,(long)((long)(user_number-1)*U_LEN),U_LEN);
unlock(file,(long)((long)(user_number-1)*U_LEN),U_LEN);
if(file != infile)
close(file);
return 0;
}
/****************************************************************************/
/* Fills the structure 'user' with info for user.number from userdat */
/* (a buffer representing a single user 'record' from the user.dat file */
/****************************************************************************/
int DLLCALL parseuserdat(scfg_t* cfg, char *userdat, user_t *user)
{
char str[U_LEN+1];
int i;
unsigned user_number;
if(user==NULL)
return(-1);
user_number=user->number;
memset(user,0,sizeof(user_t));
if(!VALID_CFG(cfg) || user_number < 1)
return(-1);
/* The user number needs to be set here
before calling chk_ar() below for user-number comparisons in AR strings to function correctly */
user->number=user_number; /* Signal of success */
/* order of these function calls is irrelevant */
getrec(userdat,U_ALIAS,LEN_ALIAS,user->alias);
getrec(userdat,U_NAME,LEN_NAME,user->name);
getrec(userdat,U_HANDLE,LEN_HANDLE,user->handle);
getrec(userdat,U_NOTE,LEN_NOTE,user->note);
getrec(userdat,U_COMP,LEN_COMP,user->comp);
getrec(userdat,U_COMMENT,LEN_COMMENT,user->comment);
getrec(userdat,U_NETMAIL,LEN_NETMAIL,user->netmail);
getrec(userdat,U_ADDRESS,LEN_ADDRESS,user->address);
getrec(userdat,U_LOCATION,LEN_LOCATION,user->location);
getrec(userdat,U_ZIPCODE,LEN_ZIPCODE,user->zipcode);
getrec(userdat,U_PASS,LEN_PASS,user->pass);
getrec(userdat,U_PHONE,LEN_PHONE,user->phone);
getrec(userdat,U_BIRTH,LEN_BIRTH,user->birth);
getrec(userdat,U_MODEM,LEN_MODEM,user->modem);
getrec(userdat,U_LASTON,8,str); user->laston=ahtoul(str);
getrec(userdat,U_FIRSTON,8,str); user->firston=ahtoul(str);
getrec(userdat,U_EXPIRE,8,str); user->expire=ahtoul(str);
getrec(userdat,U_PWMOD,8,str); user->pwmod=ahtoul(str);
getrec(userdat,U_NS_TIME,8,str);
user->ns_time=ahtoul(str);
if(user->ns_time<0x20000000L)
user->ns_time=user->laston; /* Fix for v2.00->v2.10 */
getrec(userdat,U_LOGONTIME,8,str); user->logontime=ahtoul(str);
getrec(userdat,U_LOGONS,5,str); user->logons=atoi(str);
getrec(userdat,U_LTODAY,5,str); user->ltoday=atoi(str);
getrec(userdat,U_TIMEON,5,str); user->timeon=atoi(str);
getrec(userdat,U_TEXTRA,5,str); user->textra=atoi(str);
getrec(userdat,U_TTODAY,5,str); user->ttoday=atoi(str);
getrec(userdat,U_TLAST,5,str); user->tlast=atoi(str);
getrec(userdat,U_POSTS,5,str); user->posts=atoi(str);
getrec(userdat,U_EMAILS,5,str); user->emails=atoi(str);
getrec(userdat,U_FBACKS,5,str); user->fbacks=atoi(str);
getrec(userdat,U_ETODAY,5,str); user->etoday=atoi(str);
getrec(userdat,U_PTODAY,5,str); user->ptoday=atoi(str);
getrec(userdat,U_ULB,10,str); user->ulb=atol(str);
getrec(userdat,U_ULS,5,str); user->uls=atoi(str);
getrec(userdat,U_DLB,10,str); user->dlb=atol(str);
getrec(userdat,U_DLS,5,str); user->dls=atoi(str);
getrec(userdat,U_CDT,10,str); user->cdt=atol(str);
getrec(userdat,U_MIN,10,str); user->min=atol(str);
getrec(userdat,U_LEVEL,2,str); user->level=atoi(str);
getrec(userdat,U_FLAGS1,8,str); user->flags1=ahtoul(str);
getrec(userdat,U_FLAGS2,8,str); user->flags2=ahtoul(str);
getrec(userdat,U_FLAGS3,8,str); user->flags3=ahtoul(str);
getrec(userdat,U_FLAGS4,8,str); user->flags4=ahtoul(str);
getrec(userdat,U_EXEMPT,8,str); user->exempt=ahtoul(str);
getrec(userdat,U_REST,8,str); user->rest=ahtoul(str);
getrec(userdat,U_ROWS,2,str); user->rows=atoi(str);
if(user->rows && user->rows<10)
user->rows=10;
user->sex=userdat[U_SEX];
if(!user->sex)
user->sex=' '; /* fix for v1b04 that could save as 0 */
if(user->prot<' ')
user->prot=' ';
getrec(userdat,U_MISC,8,str); user->misc=ahtoul(str);
if(user->rest&FLAG('Q'))
user->misc&=~SPIN;
getrec(userdat,U_LEECH,2,str);
user->leech=(uchar)ahtoul(str);
getrec(userdat,U_CURSUB,sizeof(user->cursub)-1,user->cursub);
getrec(userdat,U_CURDIR,sizeof(user->curdir)-1,user->curdir);
getrec(userdat,U_CURXTRN,8,user->curxtrn);
getrec(userdat,U_FREECDT,10,str);
user->freecdt=atol(str);
getrec(userdat,U_XEDIT,8,str);
for(i=0;i<cfg->total_xedits;i++)
if(!stricmp(str,cfg->xedit[i]->code))
break;
user->xedit=i+1;
if(user->xedit>cfg->total_xedits)
user->xedit=0;
getrec(userdat,U_SHELL,8,str);
for(i=0;i<cfg->total_shells;i++)
if(!stricmp(str,cfg->shell[i]->code))
break;
if(i==cfg->total_shells)
i=0;
user->shell=i;
getrec(userdat,U_QWK,8,str);
if(str[0]<' ') { /* v1c, so set defaults */
else
user->qwk=ahtoul(str);
getrec(userdat,U_TMPEXT,3,user->tmpext);
if((!user->tmpext[0] || !strcmp(user->tmpext,"0")) && cfg->total_fcomps)
strcpy(user->tmpext,cfg->fcomp[0]->ext); /* For v1x to v2x conversion */
getrec(userdat,U_CHAT,8,str);
user->chat=ahtoul(str);
/* Reset daily stats if not already logged on today */
if(user->ltoday || user->etoday || user->ptoday || user->ttoday) {
time_t now;
struct tm now_tm;
struct tm logon_tm;
now=time(NULL);
if(localtime_r(&now, &now_tm)!=NULL
&& localtime32(&user->logontime, &logon_tm)!=NULL) {
if(now_tm.tm_year!=logon_tm.tm_year
|| now_tm.tm_mon!=logon_tm.tm_mon
|| now_tm.tm_mday!=logon_tm.tm_mday)
resetdailyuserdat(cfg,user,/* write: */FALSE);
}
/****************************************************************************/
/* Fills the structure 'user' with info for user.number from user.dat file */
/****************************************************************************/
int DLLCALL getuserdat(scfg_t* cfg, user_t *user)
{
int retval;
int file;
char userdat[U_LEN+1];
if(!VALID_CFG(cfg) || user==NULL || user->number < 1)
return(-1);
if((file = openuserdat(cfg, /* for_modify: */FALSE)) < 0) {
user->number = 0;
}
memset(userdat, 0, sizeof(userdat));
if((retval = readuserdat(cfg, user->number, userdat, file)) != 0) {
close(file);
user->number = 0;
return retval;
}
retval = parseuserdat(cfg, userdat, user);
close(file);
return retval;
}
/* Fast getuserdat() (leaves user.dat file open) */
int DLLCALL fgetuserdat(scfg_t* cfg, user_t *user, int file)
{
int retval;
char userdat[U_LEN+1];
if(!VALID_CFG(cfg) || user==NULL || user->number < 1)
return(-1);
memset(userdat, 0, sizeof(userdat));
if((retval = readuserdat(cfg, user->number, userdat, file)) != 0) {
user->number = 0;
return parseuserdat(cfg, userdat, user);
}
/****************************************************************************/
/****************************************************************************/
static void dirtyuserdat(scfg_t* cfg, uint usernumber)
{
int i,file;
node_t node;
for(i=1;i<=cfg->sys_nodes;i++) { /* instant user data update */
// if(i==cfg->node_num)
// continue;
if(getnodedat(cfg, i,&node,NULL) != 0)
continue;
if(node.useron==usernumber && (node.status==NODE_INUSE
|| node.status==NODE_QUIET)) {
if(getnodedat(cfg, i,&node,&file) == 0) {
node.misc|=NODE_UDAT;
putnodedat(cfg, i,&node,file);
}
break;
}
}
}
/****************************************************************************/
/****************************************************************************/
int DLLCALL is_user_online(scfg_t* cfg, uint usernumber)
{
int i;
node_t node;
for(i=1; i<=cfg->sys_nodes; i++) {
getnodedat(cfg, i, &node, 0);
if((node.status==NODE_INUSE || node.status==NODE_QUIET
|| node.status==NODE_LOGON) && node.useron==usernumber)
return i;
}
return 0;
}
/****************************************************************************/

rswindell
committed
/* Writes into user.number's slot in user.dat data in structure 'user' */
/* Called from functions newuser, useredit and main */
/****************************************************************************/
int DLLCALL putuserdat(scfg_t* cfg, user_t* user)
int i,file;
if(user==NULL)
return(-1);
if(!VALID_CFG(cfg) || user->number<1)
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
return(-1);
memset(userdat,ETX,U_LEN);
putrec(userdat,U_ALIAS,LEN_ALIAS+5,user->alias);
putrec(userdat,U_NAME,LEN_NAME,user->name);
putrec(userdat,U_HANDLE,LEN_HANDLE,user->handle);
putrec(userdat,U_HANDLE+LEN_HANDLE,2,crlf);
putrec(userdat,U_NOTE,LEN_NOTE,user->note);
putrec(userdat,U_COMP,LEN_COMP,user->comp);
putrec(userdat,U_COMP+LEN_COMP,2,crlf);
putrec(userdat,U_COMMENT,LEN_COMMENT,user->comment);
putrec(userdat,U_COMMENT+LEN_COMMENT,2,crlf);
putrec(userdat,U_NETMAIL,LEN_NETMAIL,user->netmail);
putrec(userdat,U_NETMAIL+LEN_NETMAIL,2,crlf);
putrec(userdat,U_ADDRESS,LEN_ADDRESS,user->address);
putrec(userdat,U_LOCATION,LEN_LOCATION,user->location);
putrec(userdat,U_ZIPCODE,LEN_ZIPCODE,user->zipcode);
putrec(userdat,U_ZIPCODE+LEN_ZIPCODE,2,crlf);
putrec(userdat,U_PASS,LEN_PASS,user->pass);
putrec(userdat,U_PHONE,LEN_PHONE,user->phone);
putrec(userdat,U_BIRTH,LEN_BIRTH,user->birth);
putrec(userdat,U_MODEM,LEN_MODEM,user->modem);
putrec(userdat,U_IPADDR,LEN_IPADDR,user->ipaddr);
putrec(userdat,U_LASTON,8,ultoa((ulong)user->laston,str,16));
putrec(userdat,U_FIRSTON,8,ultoa((ulong)user->firston,str,16));
putrec(userdat,U_EXPIRE,8,ultoa((ulong)user->expire,str,16));
putrec(userdat,U_PWMOD,8,ultoa((ulong)user->pwmod,str,16));
putrec(userdat,U_PWMOD+8,2,crlf);
putrec(userdat,U_LOGONS,5,ultoa(user->logons,str,10));
putrec(userdat,U_LTODAY,5,ultoa(user->ltoday,str,10));
putrec(userdat,U_TIMEON,5,ultoa(user->timeon,str,10));
putrec(userdat,U_TEXTRA,5,ultoa(user->textra,str,10));
putrec(userdat,U_TTODAY,5,ultoa(user->ttoday,str,10));
putrec(userdat,U_TLAST,5,ultoa(user->tlast,str,10));
putrec(userdat,U_POSTS,5,ultoa(user->posts,str,10));
putrec(userdat,U_EMAILS,5,ultoa(user->emails,str,10));
putrec(userdat,U_FBACKS,5,ultoa(user->fbacks,str,10));
putrec(userdat,U_ETODAY,5,ultoa(user->etoday,str,10));
putrec(userdat,U_PTODAY,5,ultoa(user->ptoday,str,10));
putrec(userdat,U_PTODAY+5,2,crlf);
putrec(userdat,U_ULB,10,ultoa(user->ulb,str,10));
putrec(userdat,U_ULS,5,ultoa(user->uls,str,10));
putrec(userdat,U_DLB,10,ultoa(user->dlb,str,10));
putrec(userdat,U_DLS,5,ultoa(user->dls,str,10));
putrec(userdat,U_CDT,10,ultoa(user->cdt,str,10));
putrec(userdat,U_MIN,10,ultoa(user->min,str,10));
putrec(userdat,U_MIN+10,2,crlf);
putrec(userdat,U_LEVEL,2,ultoa(user->level,str,10));
putrec(userdat,U_FLAGS1,8,ultoa(user->flags1,str,16));
putrec(userdat,U_TL,2,nulstr); /* unused */
putrec(userdat,U_FLAGS2,8,ultoa(user->flags2,str,16));
putrec(userdat,U_EXEMPT,8,ultoa(user->exempt,str,16));
putrec(userdat,U_REST,8,ultoa(user->rest,str,16));
putrec(userdat,U_REST+8,2,crlf);
putrec(userdat,U_ROWS,2,ultoa(user->rows,str,10));
userdat[U_SEX]=user->sex;
userdat[U_PROT]=user->prot;
putrec(userdat,U_MISC,8,ultoa(user->misc,str,16));
putrec(userdat,U_LEECH,2,ultoa(user->leech,str,16));
putrec(userdat,U_CURSUB,sizeof(user->cursub)-1,user->cursub);
putrec(userdat,U_CURDIR,sizeof(user->curdir)-1,user->curdir);
putrec(userdat,U_CURXTRN,8,user->curxtrn);
putrec(userdat,U_CURXTRN+8,2,crlf);
putrec(userdat,U_XFER_CMD+LEN_XFER_CMD,2,crlf);
putrec(userdat,U_FREECDT,10,ultoa(user->freecdt,str,10));
putrec(userdat,U_FLAGS3,8,ultoa(user->flags3,str,16));
putrec(userdat,U_FLAGS4,8,ultoa(user->flags4,str,16));
if(user->xedit)
putrec(userdat,U_XEDIT,8,cfg->xedit[user->xedit-1]->code);
else
putrec(userdat,U_XEDIT,8,nulstr);
putrec(userdat,U_SHELL,8,cfg->shell[user->shell]->code);
putrec(userdat,U_QWK,8,ultoa(user->qwk,str,16));
putrec(userdat,U_TMPEXT,3,user->tmpext);
putrec(userdat,U_CHAT,8,ultoa(user->chat,str,16));
putrec(userdat,U_NS_TIME,8,ultoa((ulong)user->ns_time,str,16));
putrec(userdat,U_LOGONTIME,8,ultoa((ulong)user->logontime,str,16));
putrec(userdat,U_UNUSED,U_LEN-(U_UNUSED)-2,crlf);
putrec(userdat,U_UNUSED+(U_LEN-(U_UNUSED)-2),2,crlf);
if((file=openuserdat(cfg, /* for_modify: */TRUE)) < 0)
if(filelength(file)<((long)user->number-1)*U_LEN) {
close(file);
return(-4);
}
lseek(file,(long)((long)((long)user->number-1)*U_LEN),SEEK_SET);
i=0;
while(i<LOOP_NODEDAB
&& lock(file,(long)((long)(user->number-1)*U_LEN),U_LEN)==-1) {
if(i)
mswait(100);
i++;
}
if(i>=LOOP_NODEDAB) {
close(file);
return(-2);
}
if(write(file,userdat,U_LEN)!=U_LEN) {
unlock(file,(long)((long)(user->number-1)*U_LEN),U_LEN);
close(file);
return(-3);
}
unlock(file,(long)((long)(user->number-1)*U_LEN),U_LEN);
close(file);
dirtyuserdat(cfg,user->number);
return(0);
}
/****************************************************************************/
/* Returns the username in 'str' that corresponds to the 'usernumber' */
/* Called from functions everywhere */
/****************************************************************************/
char* DLLCALL username(scfg_t* cfg, int usernumber, char *name)
char str[256];
int c;
int file;
if(name==NULL)
return(NULL);
if(!VALID_CFG(cfg) || usernumber<1) {
name[0]=0;
return(name);
SAFEPRINTF(str,"%suser/name.dat",cfg->data_dir);
name[0]=0;
return(name);
if((file=nopen(str,O_RDONLY))==-1) {
name[0]=0;
return(name);
if(filelength(file)<(long)((long)usernumber*(LEN_ALIAS+2))) {
close(file);
name[0]=0;
return(name);
lseek(file,(long)((long)(usernumber-1)*(LEN_ALIAS+2)),SEEK_SET);
read(file,name,LEN_ALIAS);
close(file);
for(c=0;c<LEN_ALIAS;c++)
if(name[c]==ETX) break;
name[c]=0;
strcpy(name,"DELETED USER");
return(name);
/****************************************************************************/
/* Puts 'name' into slot 'number' in user/name.dat */
/****************************************************************************/
int DLLCALL putusername(scfg_t* cfg, int number, char *name)
{
char str[256];
int file;
uint total_users;
if(!VALID_CFG(cfg) || name==NULL || number<1)
return(-1);
SAFEPRINTF(str,"%suser/name.dat", cfg->data_dir);
if((file=nopen(str,O_RDWR|O_CREAT))==-1)
length=(long)filelength(file);
/* Truncate corrupted name.dat */
total_users=lastuser(cfg);
if((uint)(length/(LEN_ALIAS+2))>total_users)
chsize(file,total_users*(LEN_ALIAS+2));
if(length && length%(LEN_ALIAS+2)) {
close(file);
return(-3);
}
if(length<(((long)number-1)*(LEN_ALIAS+2))) {
SAFEPRINTF2(str,"%*s",LEN_ALIAS,nulstr);
memset(str,ETX,LEN_ALIAS);
strcat(str,crlf);
lseek(file,0L,SEEK_END);
while(filelength(file)<((long)number*(LEN_ALIAS+2)))
write(file,str,(LEN_ALIAS+2));
}
lseek(file,(long)(((long)number-1)*(LEN_ALIAS+2)),SEEK_SET);
putrec(str,0,LEN_ALIAS,name);
putrec(str,LEN_ALIAS,2,crlf);
close(file);
return(0);
}
/****************************************************************************/
/* Returns the age derived from the string 'birth' in the format MM/DD/YY */
/****************************************************************************/
uint DLLCALL getage(scfg_t* cfg, char *birth)
uint age;
struct tm tm;
if(!VALID_CFG(cfg) || birth==NULL)
return(0);
if(!atoi(birth) || !atoi(birth+3)) /* Invalid */
return(0);
now=time(NULL);
if(localtime_r(&now,&tm)==NULL)
age=(tm.tm_year)-(((birth[6]&0xf)*10)+(birth[7]&0xf));
age-=100;
tm.tm_mon++; /* convert to 1 based */
if(cfg->sys_misc&SM_EURODATE) { /* DD/MM/YY format */
if(atoi(birth)>31 || atoi(birth+3)>12)
return(0);
if(((birth[3]&0xf)*10)+(birth[4]&0xf)>tm.tm_mon ||
(((birth[3]&0xf)*10)+(birth[4]&0xf)==tm.tm_mon &&
((birth[0]&0xf)*10)+(birth[1]&0xf)>tm.tm_mday))
age--;
} else { /* MM/DD/YY format */
if(atoi(birth)>12 || atoi(birth+3)>31)
return(0);
if(((birth[0]&0xf)*10)+(birth[1]&0xf)>tm.tm_mon ||
(((birth[0]&0xf)*10)+(birth[1]&0xf)==tm.tm_mon &&
((birth[3]&0xf)*10)+(birth[4]&0xf)>tm.tm_mday))
return(age);
}
/****************************************************************************/
/* Reads the data for node number 'number' into the structure 'node' */

rswindell
committed
/* from node.dab */
/****************************************************************************/
int DLLCALL getnodedat(scfg_t* cfg, uint number, node_t *node, int* fdp)
char str[MAX_PATH+1];
int rd;
if(fdp!=NULL)
*fdp=-1;
if(!VALID_CFG(cfg)
|| node==NULL || number<1 || number>cfg->sys_nodes)
memset(node,0,sizeof(node_t));
SAFEPRINTF(str,"%snode.dab",cfg->ctrl_dir);
if((file=nopen(str,O_RDWR|O_DENYNONE))==-1)
if(filelength(file)>=(long)(number*sizeof(node_t))) {
number--; /* make zero based */
for(count=0;count<LOOP_NODEDAB;count++) {
if(count)
mswait(100);
lseek(file,(long)number*sizeof(node_t),SEEK_SET);
if(fdp!=NULL
&& lock(file,(long)number*sizeof(node_t),sizeof(node_t))!=0)
continue;
rd=read(file,node,sizeof(node_t));
if(rd!=sizeof(node_t))
unlock(file,(long)number*sizeof(node_t),sizeof(node_t));
if(rd==sizeof(node_t))
break;
}
if(fdp==NULL || count==LOOP_NODEDAB)
close(file);
else
*fdp=file;
if(count==LOOP_NODEDAB)
return(-2);
return(0);
}
/****************************************************************************/

rswindell
committed
/* Write the data from the structure 'node' into node.dab */
/****************************************************************************/
int DLLCALL putnodedat(scfg_t* cfg, uint number, node_t* node, int file)
size_t wr=0;
int wrerr=0;
if(file<0)
return -1;
|| node==NULL || number<1 || number>cfg->sys_nodes) {
close(file);
}
number--; /* make zero based */
for(attempts=0;attempts<10;attempts++) {
lseek(file,(long)number*sizeof(node_t),SEEK_SET);
if((wr=write(file,node,sizeof(node_t)))==sizeof(node_t))
break;
wrerr=errno; /* save write error */
mswait(100);
}
unlock(file,(long)number*sizeof(node_t),sizeof(node_t));
close(file);
if(wr!=sizeof(node_t))
return(wrerr);
/****************************************************************************/
/* Packs the password 'pass' into 5bit ASCII inside node_t. 32bits in */
/* node.extaux, and the other 8bits in the upper byte of node.aux */
/****************************************************************************/
void DLLCALL packchatpass(char *pass, node_t *node)
{
char bits;
int i,j;
if(pass==NULL || node==NULL)
return;
node->aux&=~0xff00; /* clear the password */
node->extaux=0L;
if((j=strlen(pass))==0) /* there isn't a password */
return;
node->aux|=(int)((pass[0]-64)<<8); /* 1st char goes in low 5bits of aux */
if(j==1) /* password is only one char, we're done */
return;
node->aux|=(int)((pass[1]-64)<<13); /* low 3bits of 2nd char go in aux */
node->extaux|=(long)((pass[1]-64)>>3); /* high 2bits of 2nd char go extaux */
bits=2;
for(i=2;i<j;i++) { /* now process the 3rd char through the last */
node->extaux|=(long)((long)(pass[i]-64)<<bits);
bits+=5;
}
}
/****************************************************************************/
/* Unpacks the password 'pass' from the 5bit ASCII inside node_t. 32bits in */
/* node.extaux, and the other 8bits in the upper byte of node.aux */
/****************************************************************************/
char* DLLCALL unpackchatpass(char *pass, node_t* node)
{
char bits;
int i;
if(pass==NULL || node==NULL)
return(NULL);
pass[0]=(node->aux&0x1f00)>>8;
pass[1]=(char)(((node->aux&0xe000)>>13)|((node->extaux&0x3)<<3));
bits=2;
for(i=2;i<8;i++) {
pass[i]=(char)((node->extaux>>bits)&0x1f);
bits+=5;
}
pass[8]=0;
for(i=0;i<8;i++)
if(pass[i])
pass[i]+=64;
return(pass);
}
static char* node_connection_desc(ushort conn, char* str)
{
switch(conn) {
case NODE_CONNECTION_LOCAL:
strcpy(str,"Locally");
break;
case NODE_CONNECTION_TELNET:
strcpy(str,"via telnet");
break;
case NODE_CONNECTION_RLOGIN:
strcpy(str,"via rlogin");
break;
case NODE_CONNECTION_SSH:
strcpy(str,"via ssh");
break;
default:
sprintf(str,"at %ubps",conn);
break;
}
return str;
}
char* DLLCALL nodestatus(scfg_t* cfg, node_t* node, char* buf, size_t buflen)
char str[256];
char tmp[128];
char* mer;
int hour;
strncpy(buf,"(null)",buflen);
return(buf);
str[0]=0;
switch(node->status) {
case NODE_WFC:
SAFECOPY(str,"Waiting for connection");
break;
case NODE_OFFLINE:
strcpy(str,"Offline");
break;
case NODE_NETTING: /* Obsolete */
SAFECOPY(str,"Networking");
break;
case NODE_LOGON:
SAFEPRINTF(str,"At login prompt %s"
,node_connection_desc(node->connection, tmp));
break;
case NODE_LOGOUT:
SAFEPRINTF(str,"Logging out %s", username(cfg,node->useron,tmp));
break;
case NODE_EVENT_WAITING:
SAFECOPY(str,"Waiting for all nodes to become inactive");
break;
case NODE_EVENT_LIMBO:
SAFEPRINTF(str,"Waiting for node %d to finish external event"
,node->aux);
break;
case NODE_EVENT_RUNNING:
SAFECOPY(str,"Running external event");
break;
case NODE_NEWUSER:
SAFEPRINTF(str,"New user applying for access %s"
,node_connection_desc(node->connection, tmp));
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
break;
case NODE_QUIET:
case NODE_INUSE:
username(cfg,node->useron,str);
strcat(str," ");
switch(node->action) {
case NODE_MAIN:
strcat(str,"at main menu");
break;
case NODE_RMSG:
strcat(str,"reading messages");
break;
case NODE_RMAL:
strcat(str,"reading mail");
break;
case NODE_RSML:
strcat(str,"reading sent mail");
break;
case NODE_RTXT:
strcat(str,"reading text files");
break;
case NODE_PMSG:
strcat(str,"posting message");
break;
case NODE_SMAL:
strcat(str,"sending mail");
break;
case NODE_AMSG: