--- sbbs/sbbs3/userdat.c 2018/04/24 16:39:34 1.1 +++ sbbs/sbbs3/userdat.c 2018/04/24 16:39:54 1.1.1.2 @@ -2,13 +2,13 @@ /* Synchronet user data-related routines (exported) */ -/* $Id: userdat.c,v 1.1 2018/04/24 16:39:34 root Exp $ */ +/* $Id: userdat.c,v 1.1.1.2 2018/04/24 16:39:54 root Exp $ */ /**************************************************************************** * @format.tab-size 4 (Plain Text/Source Code File Header) * * @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) * * * - * Copyright 2000 Rob Swindell - http://www.synchro.net/copyright.html * + * Copyright 2003 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 * @@ -37,22 +37,36 @@ #include "sbbs.h" #include "cmdshell.h" +#ifndef USHRT_MAX + #define USHRT_MAX ((unsigned short)~0) +#endif /* convenient space-saving global variables */ char* crlf="\r\n"; char* nulstr=""; +#define VALID_CFG(cfg) (cfg!=NULL && cfg->size==sizeof(scfg_t)) + /****************************************************************************/ /* Looks for a perfect match amoung all usernames (not deleted users) */ /* Makes dots and underscores synomynous with spaces for comparisions */ /* Returns the number of the perfect matched username or 0 if no match */ /****************************************************************************/ -uint DLLCALL matchuser(scfg_t* cfg, char *name) +uint DLLCALL matchuser(scfg_t* cfg, char *name, BOOL sysop_alias) { - int file; - char str[256],c; - ulong l,length; - FILE *stream; + int file,c; + char* p; + char dat[LEN_ALIAS+2]; + char str[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))) + return(1); sprintf(str,"%suser/name.dat",cfg->data_dir); if((file=nopen(str,O_RDONLY))==-1) @@ -61,34 +75,40 @@ uint DLLCALL matchuser(scfg_t* cfg, char if((stream=fdopen(file,"rb"))==NULL) return(0); for(l=0;ldata_dir); + if((file=nopen(str,O_RDONLY|O_DENYNONE))==-1) + return(0); + length=filelength(file); + for(l=0;ldata_dir); if((length=flength(str))>0) return((uint)(length/U_LEN)); @@ -113,6 +165,32 @@ uint DLLCALL lastuser(scfg_t* cfg) } /****************************************************************************/ +/* Deletes last user record in user.dat */ +/****************************************************************************/ +BOOL DLLCALL del_lastuser(scfg_t* cfg) +{ + char str[256]; + int file; + long length; + + if(!VALID_CFG(cfg)) + return(FALSE); + + sprintf(str,"%suser/user.dat", cfg->data_dir); + if((file=nopen(str,O_RDWR|O_DENYNONE))==-1) + return(FALSE); + length=filelength(file); + if(lengthnumber || user->number>lastuser(cfg)) { + if(user==NULL) + return(-1); + + if(!VALID_CFG(cfg) || user->number<1) { memset(user,0,sizeof(user_t)); return(-1); } @@ -130,12 +211,16 @@ int DLLCALL getuserdat(scfg_t* cfg, user memset(user,0,sizeof(user_t)); return(errno); } + if(user->number > (filelength(file)/U_LEN)) { + close(file); + return(-1); /* no such user record */ + } lseek(file,(long)((long)(user->number-1)*U_LEN),SEEK_SET); i=0; while(inumber-1)*U_LEN),U_LEN)==-1) { - if(i>10) - mswait(55); + if(i) + mswait(100); i++; } @@ -154,10 +239,9 @@ int DLLCALL getuserdat(scfg_t* cfg, user unlock(file,(long)((long)(user->number-1)*U_LEN),U_LEN); close(file); + /* order of these function calls is irrelevant */ getrec(userdat,U_ALIAS,LEN_ALIAS,user->alias); - /* order of these function */ getrec(userdat,U_NAME,LEN_NAME,user->name); - /* calls is irrelevant */ getrec(userdat,U_HANDLE,LEN_HANDLE,user->handle); getrec(userdat,U_NOTE,LEN_NOTE,user->note); getrec(userdat,U_COMP,LEN_COMP,user->comp); @@ -178,6 +262,7 @@ int DLLCALL getuserdat(scfg_t* cfg, user 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); @@ -197,8 +282,7 @@ int DLLCALL getuserdat(scfg_t* cfg, user 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_TL,2,str); user->tl=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); @@ -209,25 +293,26 @@ int DLLCALL getuserdat(scfg_t* cfg, user user->rows=10; user->sex=userdat[U_SEX]; if(!user->sex) - user->sex=SP; /* fix for v1b04 that could save as 0 */ + user->sex=' '; /* fix for v1b04 that could save as 0 */ user->prot=userdat[U_PROT]; - if(user->protprot=SP; + 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,8,user->cursub); /* was useron.cursub (01/19/00) */ - getrec(userdat,U_CURDIR,8,user->curdir); /* was useron.curdir (01/19/00) */ + 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;itotal_xedits;i++) - if(!stricmp(str,cfg->xedit[i]->code) /* && chk_ar(cfg->xedit[i]->ar,user) */) + if(!stricmp(str,cfg->xedit[i]->code) && chk_ar(cfg,cfg->xedit[i]->ar,user)) break; user->xedit=i+1; if(user->xedit>cfg->total_xedits) @@ -242,11 +327,12 @@ int DLLCALL getuserdat(scfg_t* cfg, user user->shell=i; getrec(userdat,U_QWK,8,str); - if(str[0]rest&FLAG('Q')) - user->qwk=(QWK_RETCTLA); + user->qwk=QWK_DEFAULT|QWK_RETCTLA; else - user->qwk=(QWK_FILES|QWK_ATTACH|QWK_EMAIL|QWK_DELMAIL); } + user->qwk=QWK_DEFAULT; + } else user->qwk=ahtoul(str); @@ -257,13 +343,11 @@ int DLLCALL getuserdat(scfg_t* cfg, user getrec(userdat,U_CHAT,8,str); user->chat=ahtoul(str); + /* Reset daily stats if not logged on today */ unixtodstr(cfg, time(NULL),str); unixtodstr(cfg, user->laston,tmp); - if(strcmp(str,tmp) && user->ltoday) { - user->ltoday=user->ttoday=user->ptoday=user->etoday=user->textra=0; - user->freecdt=cfg->level_freecdtperday[user->level]; - } - + if(strcmp(str,tmp) && user->ltoday) + resetdailyuserdat(cfg,user); #if 0 // removed 01/19/00 if(useron.number==user->number) { @@ -277,9 +361,11 @@ int DLLCALL getuserdat(scfg_t* cfg, user getusrsubs(); #endif if(user->misc&AUTOTERM) { // was useron.misc (01/19/00) - user->misc&=~(ANSI|RIP|WIP); - user->misc|=autoterm; } - } } + user->misc&=~(ANSI|RIP|WIP|HTML); + user->misc|=autoterm; + } + } + } #endif return(0); } @@ -290,11 +376,14 @@ int DLLCALL getuserdat(scfg_t* cfg, user /****************************************************************************/ int DLLCALL putuserdat(scfg_t* cfg, user_t* user) { - int i,file; - char userdat[U_LEN+1],str[U_LEN+1]; - node_t node; + int i,file; + char userdat[U_LEN],str[MAX_PATH+1]; + node_t node; + + if(user==NULL) + return(-1); - if(!user->number) + if(!VALID_CFG(cfg) || user->number<1) return(-1); memset(userdat,ETX,U_LEN); @@ -363,11 +452,10 @@ int DLLCALL putuserdat(scfg_t* cfg, user putrec(userdat,U_MISC,8,ultoa(user->misc,str,16)); putrec(userdat,U_LEECH,2,ultoa(user->leech,str,16)); - putrec(userdat,U_CURSUB,8,user->cursub); - putrec(userdat,U_CURDIR,8,user->curdir); - - // putrec(userdat,U_CMDSET,2,ultoa(user->cmdset,str,16)); /* Unused */ - putrec(userdat,U_CMDSET+2,2,crlf); + 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); @@ -389,22 +477,28 @@ int DLLCALL putuserdat(scfg_t* cfg, user putrec(userdat,U_TMPEXT,3,user->tmpext); putrec(userdat,U_CHAT,8,ultoa(user->chat,str,16)); putrec(userdat,U_NS_TIME,8,ultoa(user->ns_time,str,16)); + putrec(userdat,U_LOGONTIME,8,ultoa(user->logontime,str,16)); - putrec(userdat,U_UNUSED,29,crlf); - putrec(userdat,U_UNUSED+29,2,crlf); + putrec(userdat,U_UNUSED,U_LEN-(U_UNUSED)-2,crlf); + putrec(userdat,U_UNUSED+(U_LEN-(U_UNUSED)-2),2,crlf); sprintf(str,"%suser/user.dat", cfg->data_dir); - if((file=nopen(str,O_WRONLY|O_CREAT|O_DENYNONE))==-1) { + if((file=nopen(str,O_RDWR|O_CREAT|O_DENYNONE))==-1) { return(errno); } + 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(inumber-1)*U_LEN),U_LEN)==-1) { - if(i>10) - mswait(55); + if(i) + mswait(100); i++; } @@ -423,12 +517,12 @@ int DLLCALL putuserdat(scfg_t* cfg, user for(i=1;i<=cfg->sys_nodes;i++) { /* instant user data update */ if(i==cfg->node_num) continue; - getnodedat(cfg, i,&node,0); + getnodedat(cfg, i,&node,NULL); if(node.useron==user->number && (node.status==NODE_INUSE || node.status==NODE_QUIET)) { - getnodedat(cfg, i,&node,1); + getnodedat(cfg, i,&node,&file); node.misc|=NODE_UDAT; - putnodedat(cfg, i,&node); + putnodedat(cfg, i,&node,file); break; } } @@ -440,106 +534,128 @@ int DLLCALL putuserdat(scfg_t* cfg, user /* Returns the username in 'str' that corresponds to the 'usernumber' */ /* Called from functions everywhere */ /****************************************************************************/ -char* DLLCALL username(scfg_t* cfg, int usernumber,char *strin) +char* DLLCALL username(scfg_t* cfg, int usernumber, char *name) { - char str[256]; - char c; - int file; + char str[256]; + int c; + int file; + + if(name==NULL) + return(NULL); - if(usernumber<1) { - strin[0]=0; - return(strin); } + if(!VALID_CFG(cfg) || usernumber<1) { + name[0]=0; + return(name); + } sprintf(str,"%suser/name.dat",cfg->data_dir); if(flength(str)<1L) { - strin[0]=0; - return(strin); } + name[0]=0; + return(name); + } if((file=nopen(str,O_RDONLY))==-1) { - strin[0]=0; - return(strin); } + name[0]=0; + return(name); + } if(filelength(file)<(long)((long)usernumber*(LEN_ALIAS+2))) { close(file); - strin[0]=0; - return(strin); } + name[0]=0; + return(name); + } lseek(file,(long)((long)(usernumber-1)*(LEN_ALIAS+2)),SEEK_SET); - read(file,strin,LEN_ALIAS); + read(file,name,LEN_ALIAS); close(file); for(c=0;cdata_dir); + if((file=nopen(str,O_RDWR|O_CREAT))==-1) + return(errno); + length=filelength(file); - j=strlen(strin); - while(itotal_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))) { + sprintf(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); + wr=write(file,str,LEN_ALIAS+2); + close(file); + + if(wr!=LEN_ALIAS+2) + return(errno); + return(0); +} /****************************************************************************/ /* Returns the age derived from the string 'birth' in the format MM/DD/YY */ -/* Called from functions statusline, main_sec, xfer_sec, useredit and */ -/* text files */ /****************************************************************************/ char DLLCALL getage(scfg_t* cfg, char *birth) { char age; - struct tm * tm; + struct tm tm; time_t now; + if(!VALID_CFG(cfg) || birth==NULL) + return(0); + if(!atoi(birth) || !atoi(birth+3)) /* Invalid */ return(0); now=time(NULL); - tm=gmtime(&now); - if(tm==NULL) + if(localtime_r(&now,&tm)==NULL) return(0); - age=(tm->tm_year)-(((birth[6]&0xf)*10)+(birth[7]&0xf)); + age=(tm.tm_year)-(((birth[6]&0xf)*10)+(birth[7]&0xf)); if(age>105) age-=105; - tm->tm_mon++; /* convert to 1 based */ + 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(((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)) - age--; } + 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)) + age--; + } if(age<0) return(0); return(age); @@ -549,37 +665,48 @@ char DLLCALL getage(scfg_t* cfg, char *b /****************************************************************************/ /* Reads the data for node number 'number' into the structure 'node' */ /* from node.dab */ -/* if lockit is non-zero, locks this node's record. putnodedat() unlocks it */ /****************************************************************************/ -int DLLCALL getnodedat(scfg_t* cfg, uint number, node_t *node, char lockit) +int DLLCALL getnodedat(scfg_t* cfg, uint number, node_t *node, int* fdp) { - char str[256]; - int count=0; - int file; + char str[MAX_PATH+1]; + int rd; + int count=0; + int file; + + if(fdp!=NULL) + *fdp=-1; - if(!number || number>cfg->sys_nodes) + if(!VALID_CFG(cfg) + || node==NULL || number<1 || number>cfg->sys_nodes) return(-1); + memset(node,0,sizeof(node_t)); sprintf(str,"%snode.dab",cfg->ctrl_dir); - if((file=nopen(str,O_RDONLY|O_DENYNONE))==-1) { - memset(node,0,sizeof(node_t)); + if((file=nopen(str,O_RDWR|O_DENYNONE))==-1) return(errno); + + if(filelength(file)>=(long)(number*sizeof(node_t))) { + number--; /* make zero based */ + for(count=0;count10) - mswait(100); - lseek(file,(long)number*sizeof(node_t),SEEK_SET); - if(lockit - && lock(file,(long)number*sizeof(node_t),sizeof(node_t))==-1) { - count++; - continue; } - if(read(file,node,sizeof(node_t))==sizeof(node_t)) - break; - count++; } + if(fdp==NULL || count==LOOP_NODEDAB) + close(file); + else + *fdp=file; - close(file); if(count==LOOP_NODEDAB) return(-2); @@ -588,45 +715,327 @@ int DLLCALL getnodedat(scfg_t* cfg, uint /****************************************************************************/ /* Write the data from the structure 'node' into node.dab */ -/* getnodedat(num,&node,1); must have been called before calling this func */ -/* NOTE: ------^ the indicates the node record has been locked */ /****************************************************************************/ -int DLLCALL putnodedat(scfg_t* cfg, uint number, node_t* node) +int DLLCALL putnodedat(scfg_t* cfg, uint number, node_t* node, int file) { - char str[256]; - int file; + size_t wr=0; + int wrerr=0; + int attempts; - if(!number || number>cfg->sys_nodes) + if(!VALID_CFG(cfg) + || node==NULL || number<1 || number>cfg->sys_nodes || file<0) { + close(file); return(-1); - - sprintf(str,"%snode.dab",cfg->ctrl_dir); - if((file=nopen(str,O_RDWR|O_CREAT|O_DENYNONE))==-1) { - memset(node,0,sizeof(node_t)); - return(errno); } number--; /* make zero based */ - lseek(file,(long)number*sizeof(node_t),SEEK_SET); - if(write(file,node,sizeof(node_t))!=sizeof(node_t)) { - unlock(file,(long)number*sizeof(node_t),sizeof(node_t)); - close(file); - return(-2); + 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); return(0); } /****************************************************************************/ -uint DLLCALL userdatdupe(scfg_t* cfg, uint usernumber, uint offset, uint datlen, char *dat - ,BOOL del) +/* 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 str[256]; + 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;iextaux|=(long)((long)(pass[i]-64)<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); +} + +char* DLLCALL nodestatus(scfg_t* cfg, node_t* node, char* buf, size_t buflen) +{ + char str[256]; + char* mer; + int hour; + + if(node==NULL) { + strncpy(buf,"(null)",buflen); + return(buf); + } + + switch(node->status) { + case NODE_WFC: + strcpy(str,"Waiting for call"); + break; + case NODE_OFFLINE: + strcpy(str,"Offline"); + break; + case NODE_NETTING: + strcpy(str,"Networking"); + break; + case NODE_LOGON: + strcpy(str,"At logon prompt"); + break; + case NODE_EVENT_WAITING: + strcpy(str,"Waiting for all nodes to become inactive"); + break; + case NODE_EVENT_LIMBO: + sprintf(str,"Waiting for node %d to finish external event" + ,node->aux); + break; + case NODE_EVENT_RUNNING: + strcpy(str,"Running external event"); + break; + case NODE_NEWUSER: + strcpy(str,"New user applying for access "); + if(!node->connection) + strcat(str,"Locally"); + else if(node->connection==0xffff) { + strcat(str,"via telnet"); + } else + sprintf(str+strlen(str),"at %ubps",node->connection); + 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: + strcat(str,"posting auto-message"); + break; + case NODE_XTRN: + if(!node->aux) + strcat(str,"at external program menu"); + else if(node->aux<=cfg->total_xtrns) + sprintf(str+strlen(str),"running %s" + ,cfg->xtrn[node->aux-1]->name); + else + sprintf(str+strlen(str),"running external program #%d" + ,node->aux); + break; + case NODE_DFLT: + strcat(str,"changing defaults"); + break; + case NODE_XFER: + strcat(str,"at transfer menu"); + break; + case NODE_RFSD: + sprintf(str+strlen(str),"retrieving from device #%d",node->aux); + break; + case NODE_DLNG: + strcat(str,"downloading"); + break; + case NODE_ULNG: + strcat(str,"uploading"); + break; + case NODE_BXFR: + strcat(str,"transferring bidirectional"); + break; + case NODE_LFIL: + strcat(str,"listing files"); + break; + case NODE_LOGN: + strcat(str,"logging on"); + break; + case NODE_LCHT: + strcat(str,"in local chat with sysop"); + break; + case NODE_MCHT: + if(node->aux) { + sprintf(str+strlen(str),"in multinode chat channel %d" + ,node->aux&0xff); + if(node->aux&0x1f00) { /* password */ + strcat(str,"* "); + unpackchatpass(str+strlen(str),node); + } + } + else + strcat(str,"in multinode global chat channel"); + break; + case NODE_PAGE: + sprintf(str+strlen(str) + ,"paging node %u for private chat",node->aux); + break; + case NODE_PCHT: + if(!node->aux) + strcat(str,"in local chat with sysop"); + else + sprintf(str+strlen(str) + ,"in private chat with node %u" + ,node->aux); + break; + case NODE_GCHT: + strcat(str,"chatting with The Guru"); + break; + case NODE_CHAT: + strcat(str,"in chat section"); + break; + case NODE_TQWK: + strcat(str,"transferring QWK packet"); + break; + case NODE_SYSP: + strcat(str,"performing sysop activities"); + break; + default: + sprintf(str+strlen(str),"%d",node->action); + break; + } + if(!node->connection) + strcat(str," locally"); + if(node->connection==0xffff) { + strcat(str," via telnet"); + } else + sprintf(str+strlen(str)," at %ubps",node->connection); + if(node->action==NODE_DLNG) { + if((node->aux/60)>=12) { + if(node->aux/60==12) + hour=12; + else + hour=(node->aux/60)-12; + mer="pm"; + } else { + if((node->aux/60)==0) /* 12 midnite */ + hour=12; + else hour=node->aux/60; + mer="am"; + } + sprintf(str+strlen(str), " ETA %02d:%02d %s" + ,hour,node->aux-((node->aux/60)*60),mer); + } + break; + } + if(node->misc&(NODE_LOCK|NODE_POFF|NODE_AOFF|NODE_MSGW|NODE_NMSG)) { + strcat(str," ("); + if(node->misc&NODE_AOFF) + strcat(str,"A"); + if(node->misc&NODE_LOCK) + strcat(str,"L"); + if(node->misc&(NODE_MSGW|NODE_NMSG)) + strcat(str,"M"); + if(node->misc&NODE_POFF) + strcat(str,"P"); + strcat(str,")"); + } + if(((node->misc + &(NODE_ANON|NODE_UDAT|NODE_INTR|NODE_RRUN|NODE_EVENT|NODE_DOWN)) + || node->status==NODE_QUIET)) { + strcat(str," ["); + if(node->misc&NODE_ANON) + strcat(str,"A"); + if(node->misc&NODE_INTR) + strcat(str,"I"); + if(node->misc&NODE_RRUN) + strcat(str,"R"); + if(node->misc&NODE_UDAT) + strcat(str,"U"); + if(node->status==NODE_QUIET) + strcat(str,"Q"); + if(node->misc&NODE_EVENT) + strcat(str,"E"); + if(node->misc&NODE_DOWN) + strcat(str,"D"); + if(node->misc&NODE_LCHAT) + strcat(str,"C"); + strcat(str,"]"); + } + if(node->errors) + sprintf(str+strlen(str) + ," %d error%c",node->errors, node->errors>1 ? 's' : '\0' ); + + strncpy(buf,str,buflen); + + return(buf); +} + +/****************************************************************************/ +/* Displays the information for node number 'number' contained in 'node' */ +/****************************************************************************/ +void DLLCALL printnodedat(scfg_t* cfg, uint number, node_t* node) +{ + char status[128]; + + printf("Node %2d: %s\n",number,nodestatus(cfg,node,status,sizeof(status))); +} + +/****************************************************************************/ +uint DLLCALL userdatdupe(scfg_t* cfg, uint usernumber, uint offset, uint datlen + ,char *dat, BOOL del) +{ + char str[MAX_PATH+1]; uint i; int file; long l,length; + if(!VALID_CFG(cfg) || dat==NULL) + return(0); + truncsp(dat); sprintf(str,"%suser/user.dat", cfg->data_dir); if((file=nopen(str,O_RDONLY|O_DENYNONE))==-1) @@ -638,13 +1047,15 @@ uint DLLCALL userdatdupe(scfg_t* cfg, ui lseek(file,l+offset,SEEK_SET); i=0; while(i10) - mswait(55); - i++; } + if(i) + mswait(100); + i++; + } if(i>=LOOP_NODEDAB) { close(file); - return(0); } + return(0); + } read(file,str,datlen); for(i=0;idata_dir,usernumber); if((file=nopen(str,O_WRONLY|O_CREAT|O_APPEND))==-1) { return(errno); @@ -688,15 +1108,139 @@ int DLLCALL putsmsg(scfg_t* cfg, int use } close(file); for(i=1;i<=cfg->sys_nodes;i++) { /* flag node if user on that msg waiting */ - getnodedat(cfg,i,&node,0); + getnodedat(cfg,i,&node,NULL); if(node.useron==usernumber && (node.status==NODE_INUSE || node.status==NODE_QUIET) && !(node.misc&NODE_MSGW)) { - getnodedat(cfg,i,&node,1); + getnodedat(cfg,i,&node,&file); node.misc|=NODE_MSGW; - putnodedat(cfg,i,&node); + putnodedat(cfg,i,&node,file); + } + } + return(0); +} + +/****************************************************************************/ +/* Returns any short messages waiting for user number, buffer must be freed */ +/****************************************************************************/ +char* DLLCALL getsmsg(scfg_t* cfg, int usernumber) +{ + char str[MAX_PATH+1], HUGE16 *buf; + int i; + int file; + long length; + node_t node; + + if(!VALID_CFG(cfg) || usernumber<1) + return(NULL); + + sprintf(str,"%smsgs/%4.4u.msg",cfg->data_dir,usernumber); + if(flength(str)<1L) + return(NULL); + if((file=nopen(str,O_RDWR))==-1) + return(NULL); + length=filelength(file); + if((buf=(char *)malloc(length+1))==NULL) { + close(file); + return(NULL); + } + if(read(file,buf,length)!=length) { + close(file); + free(buf); + return(NULL); + } + chsize(file,0L); + close(file); + buf[length]=0; + + for(i=1;i<=cfg->sys_nodes;i++) { /* clear msg waiting flag */ + getnodedat(cfg,i,&node,NULL); + if(node.useron==usernumber + && (node.status==NODE_INUSE || node.status==NODE_QUIET) + && node.misc&NODE_MSGW) { + getnodedat(cfg,i,&node,&file); + node.misc&=~NODE_MSGW; + putnodedat(cfg,i,&node,file); } } + + return(buf); /* caller must free */ +} + +char* DLLCALL getnmsg(scfg_t* cfg, int node_num) +{ + char str[MAX_PATH+1]; + char* buf; + int file; + long length; + node_t node; + + if(!VALID_CFG(cfg) || node_num<1) + return(NULL); + + getnodedat(cfg,node_num,&node,&file); + node.misc&=~NODE_NMSG; /* clear the NMSG flag */ + putnodedat(cfg,node_num,&node,file); + + sprintf(str,"%smsgs/n%3.3u.msg",cfg->data_dir,node_num); + if(flength(str)<1L) + return(NULL); + if((file=nopen(str,O_RDWR))==-1) + return(NULL); + length=filelength(file); + if(!length) { + close(file); + return(NULL); + } + if((buf=(char *)malloc(length+1))==NULL) { + close(file); + return(NULL); + } + if(read(file,buf,length)!=length) { + close(file); + free(buf); + return(NULL); + } + chsize(file,0L); + close(file); + buf[length]=0; + + return(buf); /* caller must free */ +} + +/****************************************************************************/ +/* Creates a short message for node 'num' that contains 'strin' */ +/****************************************************************************/ +int DLLCALL putnmsg(scfg_t* cfg, int num, char *strin) +{ + char str[256]; + int file,i; + node_t node; + + if(!VALID_CFG(cfg) || num<1 || strin==NULL) + return(-1); + + if(*strin==0) + return(0); + + sprintf(str,"%smsgs/n%3.3u.msg",cfg->data_dir,num); + if((file=nopen(str,O_WRONLY|O_CREAT))==-1) + return(errno); + lseek(file,0L,SEEK_END); // Instead of opening with O_APPEND + i=strlen(strin); + if(write(file,strin,i)!=i) { + close(file); + return(errno); + } + close(file); + getnodedat(cfg,num,&node,NULL); + if((node.status==NODE_INUSE || node.status==NODE_QUIET) + && !(node.misc&NODE_NMSG)) { + getnodedat(cfg,num,&node,&file); + node.misc|=NODE_NMSG; + putnodedat(cfg,num,&node,file); + } + return(0); } @@ -706,7 +1250,7 @@ static BOOL ar_exp(scfg_t* cfg, uchar ** uint i,n,artype=AR_LEVEL,age; ulong l; time_t now; - struct tm * tm; + struct tm tm; result = TRUE; @@ -719,15 +1263,18 @@ static BOOL ar_exp(scfg_t* cfg, uchar ** if((**ptrptr)==AR_OR) { or=1; - (*ptrptr)++; } + (*ptrptr)++; + } if((**ptrptr)==AR_NOT) { not=1; - (*ptrptr)++; } + (*ptrptr)++; + } if((**ptrptr)==AR_EQUAL) { equal=1; - (*ptrptr)++; } + (*ptrptr)++; + } if((result && or) || (!result && !or)) break; @@ -742,7 +1289,8 @@ static BOOL ar_exp(scfg_t* cfg, uchar ** (*ptrptr)++; if(!(**ptrptr)) break; - continue; } + continue; + } artype=(**ptrptr); switch(artype) { @@ -758,40 +1306,47 @@ static BOOL ar_exp(scfg_t* cfg, uchar ** break; default: (*ptrptr)++; - break; } + break; + } n=(**ptrptr); i=(*(short *)*ptrptr); switch(artype) { case AR_LEVEL: - if((equal && user->level!=n) || (!equal && user->levellevel!=n) + || (!equal && user->levelbirth); - if((equal && age!=n) || (!equal && agebirth); + if((equal && age!=n) || (!equal && agemisc&ANSI)) + if(user==NULL || !(user->misc&ANSI)) result=not; else result=!not; break; case AR_RIP: - if(!(user->misc&RIP)) + if(user==NULL || !(user->misc&RIP)) result=not; else result=!not; break; case AR_WIP: - if(!(user->misc&WIP)) + if(user==NULL || !(user->misc&WIP)) result=not; else result=!not; break; @@ -831,12 +1386,12 @@ static BOOL ar_exp(scfg_t* cfg, uchar ** #endif break; case AR_EXPERT: - if(!(user->misc&EXPERT)) + if(user==NULL || !(user->misc&EXPERT)) result=not; else result=!not; break; case AR_SYSOP: - if(user->levelleveltm_wday!=(int)n) - || (!equal && tm->tm_wday<(int)n)) + localtime_r(&now,&tm); + if((equal && tm.tm_wday!=(int)n) + || (!equal && tm.tm_wday<(int)n)) result=not; else result=!not; break; case AR_CREDIT: l=(ulong)i*1024UL; - if((equal && user->cdt+user->freecdt!=l) + if(user==NULL + || (equal && user->cdt+user->freecdt!=l) || (!equal && user->cdt+user->freecdtnumber!=i) || (!equal && user->numbernumber!=i) + || (!equal && user->numberexpire || now+((long)i*24L*60L*60L)>user->expire) + if(user==NULL + || user->expire==0 + || now+((long)i*24L*60L*60L)>user->expire) result=not; else result=!not; @@ -921,14 +1481,16 @@ static BOOL ar_exp(scfg_t* cfg, uchar ** break; case AR_LASTON: now=time(NULL); - if((now-user->laston)/(24L*60L*60L)<(long)i) + if(user==NULL || (now-user->laston)/(24L*60L*60L)<(long)i) result=not; else result=!not; (*ptrptr)++; break; case AR_LOGONS: - if((equal && user->logons!=i) || (!equal && user->logonslogons!=i) + || (!equal && user->logonstm_hour*60)+tm->tm_min<(int)i) + localtime_r(&now,&tm); + if((tm.tm_hour*60)+tm.tm_min<(int)i) result=not; else result=!not; (*ptrptr)++; break; case AR_PCR: - if(user->logons>user->posts - && (!user->posts || 100/(user->logons/user->posts)<(long)n)) + if(user==NULL) + result=not; + else if(user->logons>user->posts + && (!user->posts || 100/((float)user->logons/user->posts)<(long)n)) result=not; else result=!not; break; case AR_UDR: /* up/download byte ratio */ - l=user->dlb; - if(!l) l=1; - if(user->dlb>user->ulb - && (!user->ulb || 100/(l/user->ulb)dlb; + if(!l) l=1; + if(user->dlb>user->ulb + && (!user->ulb || 100/((float)l/user->ulb)dls; - if(!i) i=1; - if(user->dls>user->uls - && (!user->uls || 100/(i/user->uls)dls; + if(!i) i=1; + if(user->dls>user->uls + && (!user->uls || 100/((float)i/user->uls)flags1&FLAG(n))) + if(user==NULL + || (!equal && !(user->flags1&FLAG(n))) || (equal && user->flags1!=FLAG(n))) result=not; else result=!not; break; case AR_FLAG2: - if((!equal && !(user->flags2&FLAG(n))) + if(user==NULL + || (!equal && !(user->flags2&FLAG(n))) || (equal && user->flags2!=FLAG(n))) result=not; else result=!not; break; case AR_FLAG3: - if((!equal && !(user->flags3&FLAG(n))) + if(user==NULL + || (!equal && !(user->flags3&FLAG(n))) || (equal && user->flags3!=FLAG(n))) result=not; else result=!not; break; case AR_FLAG4: - if((!equal && !(user->flags4&FLAG(n))) + if(user==NULL + || (!equal && !(user->flags4&FLAG(n))) || (equal && user->flags4!=FLAG(n))) result=not; else result=!not; break; case AR_REST: - if((!equal && !(user->rest&FLAG(n))) + if(user==NULL + || (!equal && !(user->rest&FLAG(n))) || (equal && user->rest!=FLAG(n))) result=not; else result=!not; break; case AR_EXEMPT: - if((!equal && !(user->exempt&FLAG(n))) + if(user==NULL + || (!equal && !(user->exempt&FLAG(n))) || (equal && user->exempt!=FLAG(n))) result=not; else result=!not; break; case AR_SEX: - if(user->sex!=n) + if(user==NULL || user->sex!=n) + result=not; + else + result=!not; + break; + case AR_SHELL: + if(user==NULL + || user->shell>=cfg->total_shells + || stricmp(cfg->shell[user->shell]->code,(char*)*ptrptr)) result=not; else result=!not; - break; } } + while(*(*ptrptr)) + (*ptrptr)++; + break; + case AR_PROT: + if(user==NULL + || stricmp(user->modem,(char*)*ptrptr)) /* should this be changed to client.prot? */ + result=not; + else + result=!not; + while(*(*ptrptr)) + (*ptrptr)++; + break; + } + } return(result); } @@ -1039,6 +1638,8 @@ BOOL DLLCALL chk_ar(scfg_t* cfg, uchar * if(ar==NULL) return(TRUE); + if(!VALID_CFG(cfg)) + return(FALSE); p=ar; return(ar_exp(cfg,&p,user)); } @@ -1049,10 +1650,10 @@ BOOL DLLCALL chk_ar(scfg_t* cfg, uchar * /****************************************************************************/ int DLLCALL getuserrec(scfg_t* cfg, int usernumber,int start, int length, char *str) { - char c,path[256]; - int i,file; + char path[256]; + int i,c,file; - if(!usernumber) + if(!VALID_CFG(cfg) || usernumber<1 || str==NULL) return(-1); sprintf(path,"%suser/user.dat",cfg->data_dir); if((file=nopen(path,O_RDONLY|O_DENYNONE))==-1) @@ -1064,12 +1665,16 @@ int DLLCALL getuserrec(scfg_t* cfg, int } lseek(file,(long)((long)(usernumber-1)*U_LEN)+start,SEEK_SET); + if(length==0) /* auto-length */ + length=user_rec_len(start); + i=0; while(i10) - mswait(55); - i++; } + if(i) + mswait(100); + i++; + } if(i>=LOOP_NODEDAB) { close(file); @@ -1102,13 +1707,21 @@ int DLLCALL putuserrec(scfg_t* cfg, int uint c,i; node_t node; - if(usernumber<1) + if(!VALID_CFG(cfg) || usernumber<1 || str==NULL) return(-1); sprintf(str2,"%suser/user.dat",cfg->data_dir); - if((file=nopen(str2,O_WRONLY|O_DENYNONE))==-1) + if((file=nopen(str2,O_RDWR|O_DENYNONE))==-1) return(errno); + if(filelength(file)<((long)usernumber-1)*U_LEN) { + close(file); + return(-4); + } + + if(length==0) /* auto-length */ + length=user_rec_len(start); + strcpy(str2,str); if(strlen(str2)10) - mswait(55); - i++; } + if(i) + mswait(100); + i++; + } if(i>=LOOP_NODEDAB) return(-3); @@ -1133,12 +1747,12 @@ int DLLCALL putuserrec(scfg_t* cfg, int for(i=1;i<=cfg->sys_nodes;i++) { /* instant user data update */ if(i==cfg->node_num) continue; - getnodedat(cfg, i,&node,0); + getnodedat(cfg, i,&node,NULL); if(node.useron==usernumber && (node.status==NODE_INUSE || node.status==NODE_QUIET)) { - getnodedat(cfg, i,&node,1); + getnodedat(cfg, i,&node,&file); node.misc|=NODE_UDAT; - putnodedat(cfg, i,&node); + putnodedat(cfg, i,&node,file); break; } } @@ -1152,27 +1766,36 @@ int DLLCALL putuserrec(scfg_t* cfg, int /****************************************************************************/ ulong DLLCALL adjustuserrec(scfg_t* cfg, int usernumber, int start, int length, long adj) { - char str[256],c,path[256]; + char str[256],path[256]; char tmp[32]; - int i,file; + int i,c,file; long val; node_t node; - if(usernumber<1) - return(0UL); + if(!VALID_CFG(cfg) || usernumber<1) + return(0); sprintf(path,"%suser/user.dat",cfg->data_dir); if((file=nopen(path,O_RDWR|O_DENYNONE))==-1) - return(0UL); + return(0); + + if(filelength(file)<((long)usernumber-1)*U_LEN) { + close(file); + return(0); + } lseek(file,(long)((long)(usernumber-1)*U_LEN)+start,SEEK_SET); + if(length==0) /* auto-length */ + length=user_rec_len(start); + i=0; while(i10) - mswait(55); - i++; } + if(i) + mswait(100); + i++; + } if(i>=LOOP_NODEDAB) { close(file); @@ -1182,14 +1805,14 @@ ulong DLLCALL adjustuserrec(scfg_t* cfg, if(read(file,str,length)!=length) { unlock(file,(long)((long)(usernumber-1)*U_LEN)+start,length); close(file); - return(0UL); + return(0); } for(c=0;csys_nodes;i++) { /* instant user data update */ if(i==cfg->node_num) continue; - getnodedat(cfg, i,&node,0); + getnodedat(cfg, i,&node,NULL); if(node.useron==usernumber && (node.status==NODE_INUSE || node.status==NODE_QUIET)) { - getnodedat(cfg, i,&node,1); + getnodedat(cfg, i,&node,&file); node.misc|=NODE_UDAT; - putnodedat(cfg, i,&node); + putnodedat(cfg, i,&node,file); break; } } @@ -1224,18 +1847,425 @@ void DLLCALL subtract_cdt(scfg_t* cfg, u char tmp[64]; long mod; - if(!amt) + if(!amt || user==NULL) return; if(user->freecdt) { if((ulong)amt>user->freecdt) { /* subtract both credits and */ mod=amt-user->freecdt; /* free credits */ putuserrec(cfg, user->number,U_FREECDT,10,"0"); user->freecdt=0; - user->cdt=adjustuserrec(cfg, user->number,U_CDT,10,-mod); } - else { /* subtract just free credits */ + user->cdt=adjustuserrec(cfg, user->number,U_CDT,10,-mod); + } else { /* subtract just free credits */ user->freecdt-=amt; putuserrec(cfg, user->number,U_FREECDT,10 - ,ultoa(user->freecdt,tmp,10)); } } + ,ultoa(user->freecdt,tmp,10)); + } + } else /* no free credits */ user->cdt=adjustuserrec(cfg, user->number,U_CDT,10,-amt); } + +/****************************************************************************/ +/****************************************************************************/ +BOOL DLLCALL logoutuserdat(scfg_t* cfg, user_t* user, time_t now, time_t logontime) +{ + char str[128]; + time_t tused; + struct tm tm, tm_now; + + if(user==NULL) + return(FALSE); + + if(now==0) + now=time(NULL); + + tused=(now-logontime)/60; + user->tlast=(ushort)(tused > USHRT_MAX ? USHRT_MAX : tused); + + putuserrec(cfg,user->number,U_LASTON,8,ultoa(now,str,16)); + putuserrec(cfg,user->number,U_TLAST,5,ultoa(user->tlast,str,10)); + adjustuserrec(cfg,user->number,U_TIMEON,5,user->tlast); + adjustuserrec(cfg,user->number,U_TTODAY,5,user->tlast); + + /* Convert time_t to struct tm */ + if(localtime_r(&now,&tm_now)==NULL) + return(FALSE); + + if(localtime_r(&logontime,&tm)==NULL) + return(FALSE); + + /* Reset daily stats if new day */ + if(tm.tm_mday!=tm_now.tm_mday) + resetdailyuserdat(cfg, user); + + return(TRUE); +} + +/****************************************************************************/ +/****************************************************************************/ +void DLLCALL resetdailyuserdat(scfg_t* cfg, user_t* user) +{ + char str[128]; + + if(!VALID_CFG(cfg) || user==NULL) + return; + + /* logons today */ + user->ltoday=0; + putuserrec(cfg,user->number,U_LTODAY,5,"0"); + /* e-mails today */ + user->etoday=0; + putuserrec(cfg,user->number,U_ETODAY,5,"0"); + /* posts today */ + user->ptoday=0; + putuserrec(cfg,user->number,U_PTODAY,5,"0"); + /* free credits per day */ + user->freecdt=cfg->level_freecdtperday[user->level]; + putuserrec(cfg,user->number,U_FREECDT,10 + ,ultoa(user->freecdt,str,10)); + /* time used today */ + user->ttoday=0; + putuserrec(cfg,user->number,U_TTODAY,5,"0"); + /* extra time today */ + user->textra=0; + putuserrec(cfg,user->number,U_TEXTRA,5,"0"); +} + +/****************************************************************************/ +/****************************************************************************/ +char* DLLCALL usermailaddr(scfg_t* cfg, char* addr, char* name) +{ + int i; + + if(!VALID_CFG(cfg) || addr==NULL || name==NULL) + return(NULL); + + if(strchr(name,'@')!=NULL) { /* Avoid double-@ */ + strcpy(addr,name); + return(addr); + } + if(strchr(name,'!') || (strchr(name,'.') && strchr(name,' '))) + sprintf(addr,"\"%s\"@",name); + else { + sprintf(addr,"%s@",name); + /* convert "first last@" to "first.last@" */ + for(i=0;addr[i];i++) + if(addr[i]==' ' || addr[i]&0x80) + addr[i]='.'; + strlwr(addr); + } + strcat(addr,cfg->sys_inetaddr); + return(addr); +} + +char* DLLCALL alias(scfg_t* cfg, char* name, char* buf) +{ + int file; + char line[128]; + char* p; + char* np; + char* tp; + char fname[MAX_PATH+1]; + size_t namelen; + size_t cmplen; + FILE* fp; + + if(!VALID_CFG(cfg) || name==NULL || buf==NULL) + return(NULL); + + p=name; + + sprintf(fname,"%salias.cfg",cfg->ctrl_dir); + if((file=sopen(fname,O_RDONLY|O_BINARY,SH_DENYNO))==-1) + return(name); + + if((fp=fdopen(file,"rb"))==NULL) { + close(file); + return(name); + } + + while(!feof(fp)) { + if(!fgets(line,sizeof(line),fp)) + break; + np=line; + SKIP_WHITESPACE(np); + if(*np==';') + continue; + tp=np; + FIND_WHITESPACE(tp); + if(*tp) *tp=0; + if(*np=='*') { + np++; + cmplen=strlen(np); + namelen=strlen(name); + if(namelendata_dir); + if(fexist(str)) { + if((stream=fnopen(&file,str,O_RDONLY))==NULL) { + return(errno); + } + last=filelength(file)/(LEN_ALIAS+2); /* total users */ + while(unum<=last) { + fread(str,LEN_ALIAS+2,1,stream); + for(c=0;c=cfg->sys_deldays) + break; /* deleted long enough ? */ + } + } + unum++; + } + fclose(stream); + } + + last=lastuser(cfg); /* Check against data file */ + + if(unum>last+1) /* Corrupted name.dat? */ + unum=last+1; + else if(unum<=last) { /* Overwriting existing user */ + getuserrec(cfg,unum,U_MISC,8,str); + misc=ahtoul(str); + if(!(misc&DELETED)) /* Not deleted? Set usernumber to end+1 */ + unum=last+1; + } + + user->number=unum; /* store the new user number */ + + if((err=putusername(cfg,user->number,user->alias))!=0) + return(err); + + if((err=putuserdat(cfg,user))!=0) + return(err); + + sprintf(str,"%sfile/%04u.in",cfg->data_dir,user->number); /* delete any files */ + delfiles(str,ALLFILES); /* waiting for user */ + rmdir(str); + sprintf(tmp,"%04u.*",user->number); + sprintf(str,"%sfile",cfg->data_dir); + delfiles(str,tmp); + sprintf(str,"%suser",cfg->data_dir); + delfiles(str,tmp); + + sprintf(str,"%suser/ptrs/%04u.ixb",cfg->data_dir,user->number); /* msg ptrs */ + remove(str); + sprintf(str,"%smsgs/%04u.msg",cfg->data_dir,user->number); /* delete short msg */ + remove(str); + + /* Update daily statistics database (for system and node) */ + + for(i=0;i<2;i++) { + sprintf(str,"%sdsts.dab",i ? cfg->ctrl_dir : cfg->node_dir); + if((file=nopen(str,O_RDWR))==-1) + continue; + memset(&stats,0,sizeof(stats)); + lseek(file,4L,SEEK_SET); /* Skip timestamp */ + read(file,&stats,sizeof(stats)); + stats.nusers++; + lseek(file,4L,SEEK_SET); + write(file,&stats,sizeof(stats)); + close(file); + } + + return(0); +} + +/* Returns length of specified user record 'field', or -1 if invalid */ +int DLLCALL user_rec_len(int offset) +{ + switch(offset) { + + /* Strings (of different lengths) */ + case U_ALIAS: return(LEN_ALIAS); + case U_NAME: return(LEN_NAME); + case U_HANDLE: return(LEN_HANDLE); + case U_NOTE: return(LEN_NOTE); + case U_COMP: return(LEN_COMP); + case U_COMMENT: return(LEN_COMMENT); + case U_NETMAIL: return(LEN_NETMAIL); + case U_ADDRESS: return(LEN_ADDRESS); + case U_LOCATION: return(LEN_LOCATION); + case U_ZIPCODE: return(LEN_ZIPCODE); + case U_PASS: return(LEN_PASS); + case U_PHONE: return(LEN_PHONE); + case U_BIRTH: return(LEN_BIRTH); + case U_MODEM: return(LEN_MODEM); + + /* Internal codes (16 chars) */ + case U_CURSUB: + case U_CURDIR: + return (16); + + /* Dates in time_t format (8 hex digits) */ + case U_LASTON: + case U_FIRSTON: + case U_EXPIRE: + case U_PWMOD: + case U_NS_TIME: + case U_LOGONTIME: + + /* 32-bit integers (8 hex digits) */ + case U_FLAGS1: + case U_FLAGS2: + case U_FLAGS3: + case U_FLAGS4: + case U_EXEMPT: + case U_REST: + case U_MISC: + case U_QWK: + case U_CHAT: + + /* Internal codes (8 chars) */ + case U_CURXTRN: + case U_XEDIT: + case U_SHELL: + return(8); + + /* 16-bit integers (5 decimal digits) */ + case U_LOGONS: + case U_LTODAY: + case U_TIMEON: + case U_TEXTRA: + case U_TTODAY: + case U_TLAST: + case U_POSTS: + case U_EMAILS: + case U_FBACKS: + case U_ETODAY: + case U_PTODAY: + case U_ULS: + case U_DLS: + return(5); + + /* 32-bit integers (10 decimal digits) */ + case U_ULB: + case U_DLB: + case U_CDT: + case U_MIN: + case U_FREECDT: + return(10); + + /* 3 char strings */ + case U_TMPEXT: + return(3); + + /* 2 digits integers (0-99) */ + case U_LEVEL: + case U_TL: + case U_ROWS: + case U_LEECH: /* actually, 2 hex digits */ + return(2); + + /* Single digits chars */ + case U_SEX: + case U_PROT: + return(1); + } + + return(-1); +} + +BOOL DLLCALL is_download_free(scfg_t* cfg, uint dirnum, user_t* user) +{ + if(!VALID_CFG(cfg)) + return(FALSE); + + if(dirnum>=cfg->total_dirs) + return(FALSE); + + if(cfg->dir[dirnum]->misc&DIR_FREE) + return(TRUE); + + if(user==NULL) + return(FALSE); + + if(user->exempt&FLAG('D')) + return(TRUE); + + if(cfg->dir[dirnum]->ex_ar[0]==0) + return(FALSE); + + return(chk_ar(cfg,cfg->dir[dirnum]->ex_ar,user)); +} + +/****************************************************************************/ +/* Add an IP address (with comment) to the IP filter/trashcan file */ +/* ToDo: Move somewhere more appropriate (filter.c?) */ +/****************************************************************************/ +BOOL DLLCALL filter_ip(scfg_t* cfg, char* prot, char* reason, char* host + ,char* ip_addr, char* username, char* fname) +{ + char ip_can[MAX_PATH+1]; + char tstr[64]; + FILE* fp; + time_t now=time(NULL); + + if(ip_addr==NULL) + return(FALSE); + + sprintf(ip_can,"%sip.can",cfg->text_dir); + if(fname==NULL) + fname=ip_can; + + if((fp=fopen(fname,"a"))==NULL) + return(FALSE); + + fprintf(fp,"\n; %s %s by %s on %s\n" + ,prot,reason,username,timestr(cfg,&now,tstr)); + + if(host!=NULL) + fprintf(fp,"; Hostname: %s\n",host); + + fprintf(fp,"%s\n",ip_addr); + + fclose(fp); + return(TRUE); +}