Annotation of sbbs/src/sbbs3/userdat.c, revision 1.1.1.2

1.1       root        1: /* userdat.c */
                      2: 
                      3: /* Synchronet user data-related routines (exported) */
                      4: 
1.1.1.2 ! root        5: /* $Id: userdat.c,v 1.138 2011/09/23 06:53:26 rswindell Exp $ */
1.1       root        6: 
                      7: /****************************************************************************
                      8:  * @format.tab-size 4          (Plain Text/Source Code File Header)                    *
                      9:  * @format.use-tabs true       (see http://www.synchro.net/ptsc_hdr.html)              *
                     10:  *                                                                                                                                                     *
1.1.1.2 ! root       11:  * Copyright 2011 Rob Swindell - http://www.synchro.net/copyright.html         *
1.1       root       12:  *                                                                                                                                                     *
                     13:  * This program is free software; you can redistribute it and/or                       *
                     14:  * modify it under the terms of the GNU General Public License                         *
                     15:  * as published by the Free Software Foundation; either version 2                      *
                     16:  * of the License, or (at your option) any later version.                                      *
                     17:  * See the GNU General Public License for more details: gpl.txt or                     *
                     18:  * http://www.fsf.org/copyleft/gpl.html                                                                                *
                     19:  *                                                                                                                                                     *
                     20:  * Anonymous FTP access to the most recent released source is available at     *
                     21:  * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net     *
                     22:  *                                                                                                                                                     *
                     23:  * Anonymous CVS access to the development source and modification history     *
                     24:  * is available at cvs.synchro.net:/cvsroot/sbbs, example:                                     *
                     25:  * cvs -d :pserver:[email protected]:/cvsroot/sbbs login                       *
                     26:  *     (just hit return, no password is necessary)                                                     *
                     27:  * cvs -d :pserver:[email protected]:/cvsroot/sbbs checkout src                *
                     28:  *                                                                                                                                                     *
                     29:  * For Synchronet coding style and modification guidelines, see                                *
                     30:  * http://www.synchro.net/source.html                                                                          *
                     31:  *                                                                                                                                                     *
                     32:  * You are encouraged to submit any modifications (preferably in Unix diff     *
                     33:  * format) via e-mail to [email protected]                                                                      *
                     34:  *                                                                                                                                                     *
                     35:  * Note: If this box doesn't appear square, then you need to fix your tabs.    *
                     36:  ****************************************************************************/
                     37: 
                     38: #include "sbbs.h"
                     39: #include "cmdshell.h"
                     40: #ifndef USHRT_MAX
                     41:        #define USHRT_MAX ((unsigned short)~0)
                     42: #endif
                     43: 
                     44: /* convenient space-saving global variables */
                     45: char* crlf="\r\n";
                     46: char* nulstr="";
                     47: 
                     48: #define VALID_CFG(cfg) (cfg!=NULL && cfg->size==sizeof(scfg_t))
                     49: 
                     50: /****************************************************************************/
                     51: /* Looks for a perfect match amoung all usernames (not deleted users)          */
                     52: /* Makes dots and underscores synomynous with spaces for comparisions          */
                     53: /* Returns the number of the perfect matched username or 0 if no match         */
                     54: /****************************************************************************/
1.1.1.2 ! root       55: uint DLLCALL matchuser(scfg_t* cfg, const char *name, BOOL sysop_alias)
1.1       root       56: {
                     57:        int             file,c;
                     58:        char*   p;
                     59:        char    dat[LEN_ALIAS+2];
                     60:        char    str[256];
1.1.1.2 ! root       61:        char    tmp[256];
1.1       root       62:        ulong   l,length;
                     63:        FILE*   stream;
                     64: 
                     65:        if(!VALID_CFG(cfg) || name==NULL)
                     66:                return(0);
                     67: 
                     68:        if(sysop_alias &&
                     69:                (!stricmp(name,"SYSOP") || !stricmp(name,"POSTMASTER") || !stricmp(name,cfg->sys_id)))
                     70:                return(1);
                     71: 
1.1.1.2 ! root       72:        SAFEPRINTF(str,"%suser/name.dat",cfg->data_dir);
1.1       root       73:        if((file=nopen(str,O_RDONLY))==-1)
                     74:                return(0);
1.1.1.2 ! root       75:        length=(long)filelength(file);
1.1       root       76:        if((stream=fdopen(file,"rb"))==NULL)
                     77:                return(0);
                     78:        for(l=0;l<length;l+=LEN_ALIAS+2) {
                     79:                fread(dat,sizeof(dat),1,stream);
                     80:                for(c=0;c<LEN_ALIAS;c++)
                     81:                        if(dat[c]==ETX) break;
                     82:                dat[c]=0;
                     83:                if(!stricmp(dat,name)) 
                     84:                        break;
                     85:                /* convert dots to spaces */
                     86:                strcpy(str,dat);
                     87:                REPLACE_CHARS(str,'.',' ',p);
                     88:                if(!stricmp(str,name)) 
                     89:                        break;
                     90:                /* convert spaces to dots */
                     91:                strcpy(str,dat);
                     92:                REPLACE_CHARS(str,' ','.',p);
                     93:                if(!stricmp(str,name)) 
                     94:                        break;
                     95:                /* convert dots to underscores */
                     96:                strcpy(str,dat);
                     97:                REPLACE_CHARS(str,'.','_',p);
                     98:                if(!stricmp(str,name)) 
                     99:                        break;
                    100:                /* convert underscores to dots */
                    101:                strcpy(str,dat);
                    102:                REPLACE_CHARS(str,'_','.',p);
                    103:                if(!stricmp(str,name)) 
                    104:                        break;
                    105:                /* convert spaces to underscores */
                    106:                strcpy(str,dat);
                    107:                REPLACE_CHARS(str,' ','_',p);
                    108:                if(!stricmp(str,name)) 
                    109:                        break;
                    110:                /* convert underscores to spaces */
                    111:                strcpy(str,dat);
                    112:                REPLACE_CHARS(str,'_',' ',p);
                    113:                if(!stricmp(str,name)) 
                    114:                        break;
1.1.1.2 ! root      115:                /* strip spaces (from both) */
        !           116:                strip_space(dat,str);
        !           117:                strip_space(name,tmp);
        !           118:                if(!stricmp(str,tmp)) 
        !           119:                        break;
1.1       root      120:        }
                    121:        fclose(stream);
                    122:        if(l<length)
                    123:                return((l/(LEN_ALIAS+2))+1); 
                    124:        return(0);
                    125: }
                    126: 
                    127: /****************************************************************************/
                    128: uint DLLCALL total_users(scfg_t* cfg)
                    129: {
                    130:     char       str[MAX_PATH+1];
                    131:     uint       total_users=0;
                    132:        int             file;
                    133:     long       l,length;
                    134: 
                    135:        if(!VALID_CFG(cfg))
                    136:                return(0);
                    137: 
1.1.1.2 ! root      138:        SAFEPRINTF(str,"%suser/user.dat", cfg->data_dir);
1.1       root      139:        if((file=nopen(str,O_RDONLY|O_DENYNONE))==-1)
                    140:                return(0);
1.1.1.2 ! root      141:        length=(long)filelength(file);
1.1       root      142:        for(l=0;l<length;l+=U_LEN) {
                    143:                lseek(file,l+U_MISC,SEEK_SET);
                    144:                if(read(file,str,8)!=8)
                    145:                        continue;
                    146:                getrec(str,0,8,str);
                    147:                if(ahtoul(str)&(DELETED|INACTIVE))
                    148:                        continue;
                    149:                total_users++;
                    150:        }
                    151:        close(file);
                    152:        return(total_users);
                    153: }
                    154: 
                    155: 
                    156: /****************************************************************************/
                    157: /* Returns the number of the last user in user.dat (deleted ones too)          */
                    158: /****************************************************************************/
                    159: uint DLLCALL lastuser(scfg_t* cfg)
                    160: {
                    161:        char str[256];
                    162:        long length;
                    163: 
                    164:        if(!VALID_CFG(cfg))
                    165:                return(0);
                    166: 
1.1.1.2 ! root      167:        SAFEPRINTF(str,"%suser/user.dat", cfg->data_dir);
        !           168:        if((length=(long)flength(str))>0)
1.1       root      169:                return((uint)(length/U_LEN));
                    170:        return(0);
                    171: }
                    172: 
                    173: /****************************************************************************/
                    174: /* Deletes last user record in user.dat                                                                                */
                    175: /****************************************************************************/
                    176: BOOL DLLCALL del_lastuser(scfg_t* cfg)
                    177: {
                    178:        char    str[256];
                    179:        int             file;
                    180:        long    length;
                    181: 
                    182:        if(!VALID_CFG(cfg))
                    183:                return(FALSE);
                    184: 
1.1.1.2 ! root      185:        SAFEPRINTF(str,"%suser/user.dat", cfg->data_dir);
1.1       root      186:        if((file=nopen(str,O_RDWR|O_DENYNONE))==-1)
                    187:                return(FALSE);
1.1.1.2 ! root      188:        length=(long)filelength(file);
1.1       root      189:        if(length<U_LEN) {
                    190:                close(file);
                    191:                return(FALSE);
                    192:        }
                    193:        chsize(file,length-U_LEN);
                    194:        close(file);
                    195:        return(TRUE);
                    196: }
                    197: 
                    198: 
                    199: /****************************************************************************/
                    200: /* Fills the structure 'user' with info for user.number        from user.dat           */
                    201: /* Called from functions useredit, waitforcall and main_sec                                    */
                    202: /****************************************************************************/
                    203: int DLLCALL getuserdat(scfg_t* cfg, user_t *user)
                    204: {
1.1.1.2 ! root      205:        char userdat[U_LEN+1],str[U_LEN+1];
1.1       root      206:        int i,file;
                    207:        unsigned user_number;
                    208: 
                    209:        if(user==NULL)
                    210:                return(-1);
                    211: 
                    212:        user_number=user->number;
                    213:        memset(user,0,sizeof(user_t));
                    214: 
                    215:        if(!VALID_CFG(cfg) || user_number<1)
                    216:                return(-1); 
                    217: 
1.1.1.2 ! root      218:        SAFEPRINTF(userdat,"%suser/user.dat",cfg->data_dir);
1.1       root      219:        if((file=nopen(userdat,O_RDONLY|O_DENYNONE))==-1)
                    220:                return(errno); 
                    221: 
                    222:        if(user_number > (unsigned)(filelength(file)/U_LEN)) {
                    223:                close(file);
                    224:                return(-1);     /* no such user record */
                    225:        }
                    226:        lseek(file,(long)((long)(user_number-1)*U_LEN),SEEK_SET);
                    227:        i=0;
                    228:        while(i<LOOP_NODEDAB
                    229:                && lock(file,(long)((long)(user_number-1)*U_LEN),U_LEN)==-1) {
                    230:                if(i)
                    231:                        mswait(100);
                    232:                i++; 
                    233:        }
                    234: 
                    235:        if(i>=LOOP_NODEDAB) {
                    236:                close(file);
                    237:                return(-2); 
                    238:        }
                    239: 
                    240:        if(read(file,userdat,U_LEN)!=U_LEN) {
                    241:                unlock(file,(long)((long)(user_number-1)*U_LEN),U_LEN);
                    242:                close(file);
                    243:                return(-3); 
                    244:        }
                    245: 
                    246:        unlock(file,(long)((long)(user_number-1)*U_LEN),U_LEN);
                    247:        close(file);
                    248:        /* order of these function calls is irrelevant */
                    249:        getrec(userdat,U_ALIAS,LEN_ALIAS,user->alias);
                    250:        getrec(userdat,U_NAME,LEN_NAME,user->name);
                    251:        getrec(userdat,U_HANDLE,LEN_HANDLE,user->handle);
                    252:        getrec(userdat,U_NOTE,LEN_NOTE,user->note);
                    253:        getrec(userdat,U_COMP,LEN_COMP,user->comp);
                    254:        getrec(userdat,U_COMMENT,LEN_COMMENT,user->comment);
                    255:        getrec(userdat,U_NETMAIL,LEN_NETMAIL,user->netmail);
                    256:        getrec(userdat,U_ADDRESS,LEN_ADDRESS,user->address);
                    257:        getrec(userdat,U_LOCATION,LEN_LOCATION,user->location);
                    258:        getrec(userdat,U_ZIPCODE,LEN_ZIPCODE,user->zipcode);
                    259:        getrec(userdat,U_PASS,LEN_PASS,user->pass);
                    260:        getrec(userdat,U_PHONE,LEN_PHONE,user->phone);
                    261:        getrec(userdat,U_BIRTH,LEN_BIRTH,user->birth);
                    262:        getrec(userdat,U_MODEM,LEN_MODEM,user->modem);
                    263:        getrec(userdat,U_LASTON,8,str); user->laston=ahtoul(str);
                    264:        getrec(userdat,U_FIRSTON,8,str); user->firston=ahtoul(str);
                    265:        getrec(userdat,U_EXPIRE,8,str); user->expire=ahtoul(str);
                    266:        getrec(userdat,U_PWMOD,8,str); user->pwmod=ahtoul(str);
                    267:        getrec(userdat,U_NS_TIME,8,str);
                    268:        user->ns_time=ahtoul(str);
                    269:        if(user->ns_time<0x20000000L)
                    270:                user->ns_time=user->laston;  /* Fix for v2.00->v2.10 */
                    271:        getrec(userdat,U_LOGONTIME,8,str); user->logontime=ahtoul(str);
                    272: 
                    273:        getrec(userdat,U_LOGONS,5,str); user->logons=atoi(str);
                    274:        getrec(userdat,U_LTODAY,5,str); user->ltoday=atoi(str);
                    275:        getrec(userdat,U_TIMEON,5,str); user->timeon=atoi(str);
                    276:        getrec(userdat,U_TEXTRA,5,str); user->textra=atoi(str);
                    277:        getrec(userdat,U_TTODAY,5,str); user->ttoday=atoi(str);
                    278:        getrec(userdat,U_TLAST,5,str); user->tlast=atoi(str);
                    279:        getrec(userdat,U_POSTS,5,str); user->posts=atoi(str);
                    280:        getrec(userdat,U_EMAILS,5,str); user->emails=atoi(str);
                    281:        getrec(userdat,U_FBACKS,5,str); user->fbacks=atoi(str);
                    282:        getrec(userdat,U_ETODAY,5,str); user->etoday=atoi(str);
                    283:        getrec(userdat,U_PTODAY,5,str); user->ptoday=atoi(str);
                    284:        getrec(userdat,U_ULB,10,str); user->ulb=atol(str);
                    285:        getrec(userdat,U_ULS,5,str); user->uls=atoi(str);
                    286:        getrec(userdat,U_DLB,10,str); user->dlb=atol(str);
                    287:        getrec(userdat,U_DLS,5,str); user->dls=atoi(str);
                    288:        getrec(userdat,U_CDT,10,str); user->cdt=atol(str);
                    289:        getrec(userdat,U_MIN,10,str); user->min=atol(str);
                    290:        getrec(userdat,U_LEVEL,2,str); user->level=atoi(str);
                    291:        getrec(userdat,U_FLAGS1,8,str); user->flags1=ahtoul(str);
                    292:        getrec(userdat,U_FLAGS2,8,str); user->flags2=ahtoul(str);
                    293:        getrec(userdat,U_FLAGS3,8,str); user->flags3=ahtoul(str);
                    294:        getrec(userdat,U_FLAGS4,8,str); user->flags4=ahtoul(str);
                    295:        getrec(userdat,U_EXEMPT,8,str); user->exempt=ahtoul(str);
                    296:        getrec(userdat,U_REST,8,str); user->rest=ahtoul(str);
                    297:        getrec(userdat,U_ROWS,2,str); user->rows=atoi(str);
                    298:        if(user->rows && user->rows<10)
                    299:                user->rows=10;
                    300:        user->sex=userdat[U_SEX];
                    301:        if(!user->sex)
                    302:                user->sex=' ';   /* fix for v1b04 that could save as 0 */
                    303:        user->prot=userdat[U_PROT];
                    304:        if(user->prot<' ')
                    305:                user->prot=' ';
                    306:        getrec(userdat,U_MISC,8,str); user->misc=ahtoul(str);
                    307:        if(user->rest&FLAG('Q'))
                    308:                user->misc&=~SPIN;
                    309: 
                    310:        getrec(userdat,U_LEECH,2,str);
                    311:        user->leech=(uchar)ahtoul(str);
                    312:        getrec(userdat,U_CURSUB,sizeof(user->cursub)-1,user->cursub);
                    313:        getrec(userdat,U_CURDIR,sizeof(user->curdir)-1,user->curdir);
                    314:        getrec(userdat,U_CURXTRN,8,user->curxtrn);
                    315: 
                    316:        getrec(userdat,U_FREECDT,10,str);
                    317:        user->freecdt=atol(str);
                    318: 
                    319:        getrec(userdat,U_XEDIT,8,str);
                    320:        for(i=0;i<cfg->total_xedits;i++)
1.1.1.2 ! root      321:                if(!stricmp(str,cfg->xedit[i]->code) && chk_ar(cfg,cfg->xedit[i]->ar,user,/* client: */NULL))
1.1       root      322:                        break;
                    323:        user->xedit=i+1;
                    324:        if(user->xedit>cfg->total_xedits)
                    325:                user->xedit=0;
                    326: 
                    327:        getrec(userdat,U_SHELL,8,str);
                    328:        for(i=0;i<cfg->total_shells;i++)
                    329:                if(!stricmp(str,cfg->shell[i]->code))
                    330:                        break;
                    331:        if(i==cfg->total_shells)
                    332:                i=0;
                    333:        user->shell=i;
                    334: 
                    335:        getrec(userdat,U_QWK,8,str);
                    336:        if(str[0]<' ') {                           /* v1c, so set defaults */
                    337:                if(user->rest&FLAG('Q'))
                    338:                        user->qwk=QWK_DEFAULT|QWK_RETCTLA;
                    339:                else
                    340:                        user->qwk=QWK_DEFAULT; 
                    341:        }
                    342:        else
                    343:                user->qwk=ahtoul(str);
                    344: 
                    345:        getrec(userdat,U_TMPEXT,3,user->tmpext);
                    346:        if((!user->tmpext[0] || !strcmp(user->tmpext,"0")) && cfg->total_fcomps)
                    347:                strcpy(user->tmpext,cfg->fcomp[0]->ext);  /* For v1x to v2x conversion */
                    348: 
                    349:        getrec(userdat,U_CHAT,8,str);
                    350:        user->chat=ahtoul(str);
                    351: 
                    352:        user->number=user_number;       /* Signal of success */
                    353: 
1.1.1.2 ! root      354:        /* Reset daily stats if not already logged on today */
        !           355:        if(user->ltoday || user->etoday || user->ptoday || user->ttoday) {
        !           356:                time_t          now;
        !           357:                struct tm       now_tm;
        !           358:                struct tm       logon_tm;
        !           359: 
        !           360:                now=time(NULL);
        !           361:                if(localtime_r(&now, &now_tm)!=NULL 
        !           362:                        && localtime_r(&user->logontime, &logon_tm)!=NULL) {
        !           363:                        if(now_tm.tm_year!=logon_tm.tm_year
        !           364:                                || now_tm.tm_mon!=logon_tm.tm_mon
        !           365:                                || now_tm.tm_mday!=logon_tm.tm_mday)
        !           366:                                resetdailyuserdat(cfg,user,/* write: */FALSE);
        !           367:                }
        !           368:        }
        !           369: 
1.1       root      370:        return(0);
                    371: }
                    372: 
                    373: /****************************************************************************/
1.1.1.2 ! root      374: /****************************************************************************/
        !           375: static void dirtyuserdat(scfg_t* cfg, uint usernumber)
        !           376: {
        !           377:        int     i,file;
        !           378:     node_t     node;
        !           379: 
        !           380:        for(i=1;i<=cfg->sys_nodes;i++) { /* instant user data update */
        !           381: //             if(i==cfg->node_num)
        !           382: //                     continue;
        !           383:                getnodedat(cfg, i,&node,NULL);
        !           384:                if(node.useron==usernumber && (node.status==NODE_INUSE
        !           385:                        || node.status==NODE_QUIET)) {
        !           386:                        getnodedat(cfg, i,&node,&file);
        !           387:                        node.misc|=NODE_UDAT;
        !           388:                        putnodedat(cfg, i,&node,file);
        !           389:                        break; 
        !           390:                } 
        !           391:        }
        !           392: }
        !           393: 
        !           394: /****************************************************************************/
1.1       root      395: /* Writes into user.number's slot in user.dat data in structure 'user'      */
                    396: /* Called from functions newuser, useredit and main                         */
                    397: /****************************************************************************/
                    398: int DLLCALL putuserdat(scfg_t* cfg, user_t* user)
                    399: {
                    400:     int                i,file;
                    401:     char       userdat[U_LEN],str[MAX_PATH+1];
                    402: 
                    403:        if(user==NULL)
                    404:                return(-1);
                    405: 
                    406:        if(!VALID_CFG(cfg) || user->number<1)
                    407:                return(-1); 
                    408: 
                    409:        memset(userdat,ETX,U_LEN);
                    410:        putrec(userdat,U_ALIAS,LEN_ALIAS+5,user->alias);
                    411:        putrec(userdat,U_NAME,LEN_NAME,user->name);
                    412:        putrec(userdat,U_HANDLE,LEN_HANDLE,user->handle);
                    413:        putrec(userdat,U_HANDLE+LEN_HANDLE,2,crlf);
                    414: 
                    415:        putrec(userdat,U_NOTE,LEN_NOTE,user->note);
                    416:        putrec(userdat,U_COMP,LEN_COMP,user->comp);
                    417:        putrec(userdat,U_COMP+LEN_COMP,2,crlf);
                    418: 
                    419:        putrec(userdat,U_COMMENT,LEN_COMMENT,user->comment);
                    420:        putrec(userdat,U_COMMENT+LEN_COMMENT,2,crlf);
                    421: 
                    422:        putrec(userdat,U_NETMAIL,LEN_NETMAIL,user->netmail);
                    423:        putrec(userdat,U_NETMAIL+LEN_NETMAIL,2,crlf);
                    424: 
                    425:        putrec(userdat,U_ADDRESS,LEN_ADDRESS,user->address);
                    426:        putrec(userdat,U_LOCATION,LEN_LOCATION,user->location);
                    427:        putrec(userdat,U_ZIPCODE,LEN_ZIPCODE,user->zipcode);
                    428:        putrec(userdat,U_ZIPCODE+LEN_ZIPCODE,2,crlf);
                    429: 
                    430:        putrec(userdat,U_PASS,LEN_PASS,user->pass);
                    431:        putrec(userdat,U_PHONE,LEN_PHONE,user->phone);
                    432:        putrec(userdat,U_BIRTH,LEN_BIRTH,user->birth);
                    433:        putrec(userdat,U_MODEM,LEN_MODEM,user->modem);
                    434:        putrec(userdat,U_LASTON,8,ultoa(user->laston,str,16));
                    435:        putrec(userdat,U_FIRSTON,8,ultoa(user->firston,str,16));
                    436:        putrec(userdat,U_EXPIRE,8,ultoa(user->expire,str,16));
                    437:        putrec(userdat,U_PWMOD,8,ultoa(user->pwmod,str,16));
                    438:        putrec(userdat,U_PWMOD+8,2,crlf);
                    439: 
                    440:        putrec(userdat,U_LOGONS,5,ultoa(user->logons,str,10));
                    441:        putrec(userdat,U_LTODAY,5,ultoa(user->ltoday,str,10));
                    442:        putrec(userdat,U_TIMEON,5,ultoa(user->timeon,str,10));
                    443:        putrec(userdat,U_TEXTRA,5,ultoa(user->textra,str,10));
                    444:        putrec(userdat,U_TTODAY,5,ultoa(user->ttoday,str,10));
                    445:        putrec(userdat,U_TLAST,5,ultoa(user->tlast,str,10));
                    446:        putrec(userdat,U_POSTS,5,ultoa(user->posts,str,10));
                    447:        putrec(userdat,U_EMAILS,5,ultoa(user->emails,str,10));
                    448:        putrec(userdat,U_FBACKS,5,ultoa(user->fbacks,str,10));
                    449:        putrec(userdat,U_ETODAY,5,ultoa(user->etoday,str,10));
                    450:        putrec(userdat,U_PTODAY,5,ultoa(user->ptoday,str,10));
                    451:        putrec(userdat,U_PTODAY+5,2,crlf);
                    452: 
                    453:        putrec(userdat,U_ULB,10,ultoa(user->ulb,str,10));
                    454:        putrec(userdat,U_ULS,5,ultoa(user->uls,str,10));
                    455:        putrec(userdat,U_DLB,10,ultoa(user->dlb,str,10));
                    456:        putrec(userdat,U_DLS,5,ultoa(user->dls,str,10));
                    457:        putrec(userdat,U_CDT,10,ultoa(user->cdt,str,10));
                    458:        putrec(userdat,U_MIN,10,ultoa(user->min,str,10));
                    459:        putrec(userdat,U_MIN+10,2,crlf);
                    460: 
                    461:        putrec(userdat,U_LEVEL,2,ultoa(user->level,str,10));
                    462:        putrec(userdat,U_FLAGS1,8,ultoa(user->flags1,str,16));
                    463:        putrec(userdat,U_TL,2,nulstr);  /* unused */
                    464:        putrec(userdat,U_FLAGS2,8,ultoa(user->flags2,str,16));
                    465:        putrec(userdat,U_EXEMPT,8,ultoa(user->exempt,str,16));
                    466:        putrec(userdat,U_REST,8,ultoa(user->rest,str,16));
                    467:        putrec(userdat,U_REST+8,2,crlf);
                    468: 
                    469:        putrec(userdat,U_ROWS,2,ultoa(user->rows,str,10));
                    470:        userdat[U_SEX]=user->sex;
                    471:        userdat[U_PROT]=user->prot;
                    472:        putrec(userdat,U_MISC,8,ultoa(user->misc,str,16));
                    473:        putrec(userdat,U_LEECH,2,ultoa(user->leech,str,16));
                    474: 
                    475:        putrec(userdat,U_CURSUB,sizeof(user->cursub)-1,user->cursub);
                    476:        putrec(userdat,U_CURDIR,sizeof(user->curdir)-1,user->curdir);
                    477:        putrec(userdat,U_CURXTRN,8,user->curxtrn);
                    478:        putrec(userdat,U_CURXTRN+8,2,crlf);
                    479: 
                    480:        putrec(userdat,U_XFER_CMD+LEN_XFER_CMD,2,crlf);
                    481: 
                    482:        putrec(userdat,U_MAIL_CMD+LEN_MAIL_CMD,2,crlf);
                    483: 
                    484:        putrec(userdat,U_FREECDT,10,ultoa(user->freecdt,str,10));
                    485: 
                    486:        putrec(userdat,U_FLAGS3,8,ultoa(user->flags3,str,16));
                    487:        putrec(userdat,U_FLAGS4,8,ultoa(user->flags4,str,16));
                    488: 
                    489:        if(user->xedit)
                    490:                putrec(userdat,U_XEDIT,8,cfg->xedit[user->xedit-1]->code);
                    491:        else
                    492:                putrec(userdat,U_XEDIT,8,nulstr);
                    493: 
                    494:        putrec(userdat,U_SHELL,8,cfg->shell[user->shell]->code);
                    495: 
                    496:        putrec(userdat,U_QWK,8,ultoa(user->qwk,str,16));
                    497:        putrec(userdat,U_TMPEXT,3,user->tmpext);
                    498:        putrec(userdat,U_CHAT,8,ultoa(user->chat,str,16));
                    499:        putrec(userdat,U_NS_TIME,8,ultoa(user->ns_time,str,16));
                    500:        putrec(userdat,U_LOGONTIME,8,ultoa(user->logontime,str,16));
                    501: 
                    502:        putrec(userdat,U_UNUSED,U_LEN-(U_UNUSED)-2,crlf);
                    503:        putrec(userdat,U_UNUSED+(U_LEN-(U_UNUSED)-2),2,crlf);
                    504: 
1.1.1.2 ! root      505:        SAFEPRINTF(str,"%suser/user.dat", cfg->data_dir);
1.1       root      506:        if((file=nopen(str,O_RDWR|O_CREAT|O_DENYNONE))==-1) {
                    507:                return(errno);
                    508:        }
                    509: 
                    510:        if(filelength(file)<((long)user->number-1)*U_LEN) {
                    511:                close(file);
                    512:                return(-4);
                    513:        }
                    514: 
                    515:        lseek(file,(long)((long)((long)user->number-1)*U_LEN),SEEK_SET);
                    516: 
                    517:        i=0;
                    518:        while(i<LOOP_NODEDAB
                    519:                && lock(file,(long)((long)(user->number-1)*U_LEN),U_LEN)==-1) {
                    520:                if(i)
                    521:                        mswait(100);
                    522:                i++; 
                    523:        }
                    524: 
                    525:        if(i>=LOOP_NODEDAB) {
                    526:                close(file);
                    527:                return(-2); 
                    528:        }
                    529: 
                    530:        if(write(file,userdat,U_LEN)!=U_LEN) {
                    531:                unlock(file,(long)((long)(user->number-1)*U_LEN),U_LEN);
                    532:                close(file);
                    533:                return(-3); 
                    534:        }
                    535:        unlock(file,(long)((long)(user->number-1)*U_LEN),U_LEN);
                    536:        close(file);
1.1.1.2 ! root      537:        dirtyuserdat(cfg,user->number);
1.1       root      538:        return(0);
                    539: }
                    540: 
                    541: 
                    542: /****************************************************************************/
                    543: /* Returns the username in 'str' that corresponds to the 'usernumber'       */
                    544: /* Called from functions everywhere                                         */
                    545: /****************************************************************************/
                    546: char* DLLCALL username(scfg_t* cfg, int usernumber, char *name)
                    547: {
                    548:     char       str[256];
                    549:     int                c;
                    550:     int                file;
                    551: 
                    552:        if(name==NULL)
                    553:                return(NULL);
                    554: 
                    555:        if(!VALID_CFG(cfg) || usernumber<1) {
                    556:                name[0]=0;
                    557:                return(name); 
                    558:        }
1.1.1.2 ! root      559:        SAFEPRINTF(str,"%suser/name.dat",cfg->data_dir);
1.1       root      560:        if(flength(str)<1L) {
                    561:                name[0]=0;
                    562:                return(name); 
                    563:        }
                    564:        if((file=nopen(str,O_RDONLY))==-1) {
                    565:                name[0]=0;
                    566:                return(name); 
                    567:        }
                    568:        if(filelength(file)<(long)((long)usernumber*(LEN_ALIAS+2))) {
                    569:                close(file);
                    570:                name[0]=0;
                    571:                return(name); 
                    572:        }
                    573:        lseek(file,(long)((long)(usernumber-1)*(LEN_ALIAS+2)),SEEK_SET);
                    574:        read(file,name,LEN_ALIAS);
                    575:        close(file);
                    576:        for(c=0;c<LEN_ALIAS;c++)
                    577:                if(name[c]==ETX) break;
                    578:        name[c]=0;
                    579:        if(!c)
                    580:                strcpy(name,"DELETED USER");
                    581:        return(name);
                    582: }
                    583: 
                    584: /****************************************************************************/
                    585: /* Puts 'name' into slot 'number' in user/name.dat                                                     */
                    586: /****************************************************************************/
                    587: int DLLCALL putusername(scfg_t* cfg, int number, char *name)
                    588: {
                    589:        char str[256];
                    590:        int file;
                    591:        int wr;
                    592:        long length;
                    593:        uint total_users;
                    594: 
                    595:        if(!VALID_CFG(cfg) || name==NULL || number<1) 
                    596:                return(-1);
                    597: 
1.1.1.2 ! root      598:        SAFEPRINTF(str,"%suser/name.dat", cfg->data_dir);
1.1       root      599:        if((file=nopen(str,O_RDWR|O_CREAT))==-1) 
                    600:                return(errno); 
1.1.1.2 ! root      601:        length=(long)filelength(file);
1.1       root      602: 
                    603:        /* Truncate corrupted name.dat */
                    604:        total_users=lastuser(cfg);
                    605:        if((uint)(length/(LEN_ALIAS+2))>total_users)
                    606:                chsize(file,total_users*(LEN_ALIAS+2));
                    607: 
                    608:        if(length && length%(LEN_ALIAS+2)) {
                    609:                close(file);
                    610:                return(-3); 
                    611:        }
                    612:        if(length<(((long)number-1)*(LEN_ALIAS+2))) {
1.1.1.2 ! root      613:                SAFEPRINTF2(str,"%*s",LEN_ALIAS,nulstr);
1.1       root      614:                memset(str,ETX,LEN_ALIAS);
                    615:                strcat(str,crlf);
                    616:                lseek(file,0L,SEEK_END);
                    617:                while(filelength(file)<((long)number*(LEN_ALIAS+2)))
                    618:                        write(file,str,(LEN_ALIAS+2)); 
                    619:        }
                    620:        lseek(file,(long)(((long)number-1)*(LEN_ALIAS+2)),SEEK_SET);
                    621:        putrec(str,0,LEN_ALIAS,name);
                    622:        putrec(str,LEN_ALIAS,2,crlf);
                    623:        wr=write(file,str,LEN_ALIAS+2);
                    624:        close(file);
                    625: 
                    626:        if(wr!=LEN_ALIAS+2)
                    627:                return(errno);
                    628:        return(0);
                    629: }
                    630: 
                    631: /****************************************************************************/
                    632: /* Returns the age derived from the string 'birth' in the format MM/DD/YY      */
                    633: /****************************************************************************/
1.1.1.2 ! root      634: uint DLLCALL getage(scfg_t* cfg, char *birth)
1.1       root      635: {
1.1.1.2 ! root      636:        uint    age;
1.1       root      637:        struct  tm tm;
                    638:        time_t  now;
                    639: 
                    640:        if(!VALID_CFG(cfg) || birth==NULL)
                    641:                return(0);
                    642: 
                    643:        if(!atoi(birth) || !atoi(birth+3))      /* Invalid */
                    644:                return(0);
                    645: 
                    646:        now=time(NULL);
                    647:        if(localtime_r(&now,&tm)==NULL)
                    648:                return(0);
                    649:        age=(tm.tm_year)-(((birth[6]&0xf)*10)+(birth[7]&0xf));
                    650:        if(age>105)
1.1.1.2 ! root      651:                age-=100;
1.1       root      652:        tm.tm_mon++;    /* convert to 1 based */
                    653:        if(cfg->sys_misc&SM_EURODATE) {         /* DD/MM/YY format */
                    654:                if(atoi(birth)>31 || atoi(birth+3)>12)
                    655:                        return(0);
                    656:                if(((birth[3]&0xf)*10)+(birth[4]&0xf)>tm.tm_mon ||
                    657:                        (((birth[3]&0xf)*10)+(birth[4]&0xf)==tm.tm_mon &&
                    658:                        ((birth[0]&0xf)*10)+(birth[1]&0xf)>tm.tm_mday))
                    659:                        age--; 
                    660:        } else {                                                        /* MM/DD/YY format */
                    661:                if(atoi(birth)>12 || atoi(birth+3)>31)
                    662:                        return(0);
                    663:                if(((birth[0]&0xf)*10)+(birth[1]&0xf)>tm.tm_mon ||
                    664:                        (((birth[0]&0xf)*10)+(birth[1]&0xf)==tm.tm_mon &&
                    665:                        ((birth[3]&0xf)*10)+(birth[4]&0xf)>tm.tm_mday))
                    666:                        age--; 
                    667:        }
                    668:        return(age);
                    669: }
                    670: 
                    671: /****************************************************************************/
                    672: /* Reads the data for node number 'number' into the structure 'node'        */
                    673: /* from node.dab                                                                                                                       */
                    674: /****************************************************************************/
                    675: int DLLCALL getnodedat(scfg_t* cfg, uint number, node_t *node, int* fdp)
                    676: {
                    677:        char    str[MAX_PATH+1];
                    678:        int             rd;
                    679:        int             count=0;
                    680:        int             file;
                    681: 
                    682:        if(fdp!=NULL)
                    683:                *fdp=-1;
                    684: 
                    685:        if(!VALID_CFG(cfg) 
                    686:                || node==NULL || number<1 || number>cfg->sys_nodes)
                    687:                return(-1);
                    688: 
                    689:        memset(node,0,sizeof(node_t));
1.1.1.2 ! root      690:        SAFEPRINTF(str,"%snode.dab",cfg->ctrl_dir);
1.1       root      691:        if((file=nopen(str,O_RDWR|O_DENYNONE))==-1)
                    692:                return(errno); 
                    693: 
                    694:        if(filelength(file)>=(long)(number*sizeof(node_t))) {
                    695:                number--;       /* make zero based */
                    696:                for(count=0;count<LOOP_NODEDAB;count++) {
                    697:                        if(count)
                    698:                                mswait(100);
                    699:                        lseek(file,(long)number*sizeof(node_t),SEEK_SET);
                    700:                        if(fdp!=NULL 
                    701:                                && lock(file,(long)number*sizeof(node_t),sizeof(node_t))!=0) 
                    702:                                continue; 
                    703:                        rd=read(file,node,sizeof(node_t));
                    704:                        if(fdp==NULL || rd!=sizeof(node_t))
                    705:                                unlock(file,(long)number*sizeof(node_t),sizeof(node_t));
                    706:                        if(rd==sizeof(node_t))
                    707:                                break;
                    708:                }
                    709:        }
                    710: 
                    711:        if(fdp==NULL || count==LOOP_NODEDAB)
                    712:                close(file);
                    713:        else
                    714:                *fdp=file;
                    715: 
                    716:        if(count==LOOP_NODEDAB) 
                    717:                return(-2); 
                    718:        
                    719:        return(0);
                    720: }
                    721: 
                    722: /****************************************************************************/
                    723: /* Write the data from the structure 'node' into node.dab                                      */
                    724: /****************************************************************************/
                    725: int DLLCALL putnodedat(scfg_t* cfg, uint number, node_t* node, int file)
                    726: {
                    727:        size_t  wr=0;
                    728:        int             wrerr=0;
                    729:        int             attempts;
                    730: 
                    731:        if(!VALID_CFG(cfg) 
                    732:                || node==NULL || number<1 || number>cfg->sys_nodes || file<0) {
                    733:                close(file);
                    734:                return(-1);
                    735:        }
                    736: 
                    737:        number--;       /* make zero based */
                    738:        for(attempts=0;attempts<10;attempts++) {
                    739:                lseek(file,(long)number*sizeof(node_t),SEEK_SET);
                    740:                if((wr=write(file,node,sizeof(node_t)))==sizeof(node_t))
                    741:                        break;
                    742:                wrerr=errno;    /* save write error */
                    743:                mswait(100);
                    744:        }
                    745:        unlock(file,(long)number*sizeof(node_t),sizeof(node_t));
                    746:        close(file);
                    747: 
                    748:        if(wr!=sizeof(node_t))
                    749:                return(wrerr);
                    750:        return(0);
                    751: }
                    752: 
                    753: /****************************************************************************/
                    754: /* Packs the password 'pass' into 5bit ASCII inside node_t. 32bits in          */
                    755: /* node.extaux, and the other 8bits in the upper byte of node.aux                      */
                    756: /****************************************************************************/
                    757: void DLLCALL packchatpass(char *pass, node_t *node)
                    758: {
                    759:        char    bits;
                    760:        int             i,j;
                    761: 
                    762:        if(pass==NULL || node==NULL)
                    763:                return;
                    764: 
                    765:        node->aux&=~0xff00;             /* clear the password */
                    766:        node->extaux=0L;
                    767:        if((j=strlen(pass))==0) /* there isn't a password */
                    768:                return;
                    769:        node->aux|=(int)((pass[0]-64)<<8);  /* 1st char goes in low 5bits of aux */
                    770:        if(j==1)        /* password is only one char, we're done */
                    771:                return;
                    772:        node->aux|=(int)((pass[1]-64)<<13); /* low 3bits of 2nd char go in aux */
                    773:        node->extaux|=(long)((pass[1]-64)>>3); /* high 2bits of 2nd char go extaux */
                    774:        bits=2;
                    775:        for(i=2;i<j;i++) {      /* now process the 3rd char through the last */
                    776:                node->extaux|=(long)((long)(pass[i]-64)<<bits);
                    777:                bits+=5; 
                    778:        }
                    779: }
                    780: 
                    781: /****************************************************************************/
                    782: /* Unpacks the password 'pass' from the 5bit ASCII inside node_t. 32bits in */
                    783: /* node.extaux, and the other 8bits in the upper byte of node.aux                      */
                    784: /****************************************************************************/
                    785: char* DLLCALL unpackchatpass(char *pass, node_t* node)
                    786: {
                    787:        char    bits;
                    788:        int     i;
                    789: 
                    790:        if(pass==NULL || node==NULL)
                    791:                return(NULL);
                    792: 
                    793:        pass[0]=(node->aux&0x1f00)>>8;
                    794:        pass[1]=(char)(((node->aux&0xe000)>>13)|((node->extaux&0x3)<<3));
                    795:        bits=2;
                    796:        for(i=2;i<8;i++) {
                    797:                pass[i]=(char)((node->extaux>>bits)&0x1f);
                    798:                bits+=5; 
                    799:        }
                    800:        pass[8]=0;
                    801:        for(i=0;i<8;i++)
                    802:                if(pass[i])
                    803:                        pass[i]+=64;
                    804:        return(pass);
                    805: }
                    806: 
1.1.1.2 ! root      807: static char* node_connection_desc(ushort conn, char* str)
        !           808: {
        !           809:        switch(conn) {
        !           810:                case NODE_CONNECTION_LOCAL:
        !           811:                        strcpy(str,"Locally");
        !           812:                        break;
        !           813:                case NODE_CONNECTION_TELNET:
        !           814:                        strcpy(str,"via telnet");
        !           815:                        break;
        !           816:                case NODE_CONNECTION_RLOGIN:
        !           817:                        strcpy(str,"via rlogin");
        !           818:                        break;
        !           819:                case NODE_CONNECTION_SSH:
        !           820:                        strcpy(str,"via ssh");
        !           821:                        break;
        !           822:                default:
        !           823:                        sprintf(str,"at %ubps",conn);
        !           824:                        break;
        !           825:        }
        !           826: 
        !           827:        return str;
        !           828: }
        !           829: 
1.1       root      830: char* DLLCALL nodestatus(scfg_t* cfg, node_t* node, char* buf, size_t buflen)
                    831: {
                    832:        char    str[256];
1.1.1.2 ! root      833:        char    tmp[128];
1.1       root      834:        char*   mer;
                    835:        int             hour;
                    836: 
                    837:        if(node==NULL) {
                    838:                strncpy(buf,"(null)",buflen);
                    839:                return(buf);
                    840:        }
                    841: 
                    842:     switch(node->status) {
                    843:         case NODE_WFC:
1.1.1.2 ! root      844:             strcpy(str,"Waiting for connection");
1.1       root      845:             break;
                    846:         case NODE_OFFLINE:
                    847:             strcpy(str,"Offline");
                    848:             break;
1.1.1.2 ! root      849:         case NODE_NETTING:     /* Obsolete */
1.1       root      850:             strcpy(str,"Networking");
                    851:             break;
                    852:         case NODE_LOGON:
1.1.1.2 ! root      853:             SAFEPRINTF(str,"At logon prompt %s"
        !           854:                                ,node_connection_desc(node->connection, tmp));
1.1       root      855:             break;
                    856:         case NODE_EVENT_WAITING:
                    857:             strcpy(str,"Waiting for all nodes to become inactive");
                    858:             break;
                    859:         case NODE_EVENT_LIMBO:
1.1.1.2 ! root      860:             SAFEPRINTF(str,"Waiting for node %d to finish external event"
1.1       root      861:                 ,node->aux);
                    862:             break;
                    863:         case NODE_EVENT_RUNNING:
                    864:             strcpy(str,"Running external event");
                    865:             break;
                    866:         case NODE_NEWUSER:
1.1.1.2 ! root      867:             SAFEPRINTF(str,"New user applying for access %s"
        !           868:                                ,node_connection_desc(node->connection, tmp));
1.1       root      869:             break;
                    870:         case NODE_QUIET:
                    871:         case NODE_INUSE:
                    872:             username(cfg,node->useron,str);
                    873:             strcat(str," ");
                    874:             switch(node->action) {
                    875:                 case NODE_MAIN:
                    876:                     strcat(str,"at main menu");
                    877:                     break;
                    878:                 case NODE_RMSG:
                    879:                     strcat(str,"reading messages");
                    880:                     break;
                    881:                 case NODE_RMAL:
                    882:                     strcat(str,"reading mail");
                    883:                     break;
                    884:                 case NODE_RSML:
                    885:                     strcat(str,"reading sent mail");
                    886:                     break;
                    887:                 case NODE_RTXT:
                    888:                     strcat(str,"reading text files");
                    889:                     break;
                    890:                 case NODE_PMSG:
                    891:                     strcat(str,"posting message");
                    892:                     break;
                    893:                 case NODE_SMAL:
                    894:                     strcat(str,"sending mail");
                    895:                     break;
                    896:                 case NODE_AMSG:
                    897:                     strcat(str,"posting auto-message");
                    898:                     break;
                    899:                 case NODE_XTRN:
                    900:                     if(!node->aux)
                    901:                         strcat(str,"at external program menu");
                    902:                     else if(node->aux<=cfg->total_xtrns)
                    903:                         sprintf(str+strlen(str),"running %s"
                    904:                               ,cfg->xtrn[node->aux-1]->name);
                    905:                     else
                    906:                         sprintf(str+strlen(str),"running external program #%d"
                    907:                             ,node->aux);
                    908:                     break;
                    909:                 case NODE_DFLT:
                    910:                     strcat(str,"changing defaults");
                    911:                     break;
                    912:                 case NODE_XFER:
                    913:                     strcat(str,"at transfer menu");
                    914:                     break;
                    915:                 case NODE_RFSD:
                    916:                     sprintf(str+strlen(str),"retrieving from device #%d",node->aux);
                    917:                     break;
                    918:                 case NODE_DLNG:
                    919:                     strcat(str,"downloading");
                    920:                     break;
                    921:                 case NODE_ULNG:
                    922:                     strcat(str,"uploading");
                    923:                     break;
                    924:                 case NODE_BXFR:
                    925:                     strcat(str,"transferring bidirectional");
                    926:                     break;
                    927:                 case NODE_LFIL:
                    928:                     strcat(str,"listing files");
                    929:                     break;
                    930:                 case NODE_LOGN:
                    931:                     strcat(str,"logging on");
                    932:                     break;
                    933:                 case NODE_LCHT:
                    934:                     strcat(str,"in local chat with sysop");
                    935:                     break;
                    936:                 case NODE_MCHT:
                    937:                     if(node->aux) {
                    938:                         sprintf(str+strlen(str),"in multinode chat channel %d"
                    939:                             ,node->aux&0xff);
                    940:                         if(node->aux&0x1f00) { /* password */
                    941:                             strcat(str,"* ");
                    942:                             unpackchatpass(str+strlen(str),node);
                    943:                         }
                    944:                     }
                    945:                     else
                    946:                         strcat(str,"in multinode global chat channel");
                    947:                     break;
                    948:                 case NODE_PAGE:
                    949:                     sprintf(str+strlen(str)
                    950:                                                ,"paging node %u for private chat",node->aux);
                    951:                     break;
                    952:                 case NODE_PCHT:
                    953:                     if(!node->aux)
                    954:                         strcat(str,"in local chat with sysop");
                    955:                     else
                    956:                         sprintf(str+strlen(str)
                    957:                                                        ,"in private chat with node %u"
                    958:                             ,node->aux);
                    959:                     break;
                    960:                 case NODE_GCHT:
                    961:                     strcat(str,"chatting with The Guru");
                    962:                     break;
                    963:                 case NODE_CHAT:
                    964:                     strcat(str,"in chat section");
                    965:                     break;
                    966:                 case NODE_TQWK:
                    967:                     strcat(str,"transferring QWK packet");
                    968:                     break;
                    969:                 case NODE_SYSP:
                    970:                     strcat(str,"performing sysop activities");
                    971:                     break;
                    972:                 default:
                    973:                     sprintf(str+strlen(str),"%d",node->action);
                    974:                     break;  
                    975:                        }
1.1.1.2 ! root      976:                        sprintf(str+strlen(str)," %s",node_connection_desc(node->connection, tmp));
1.1       root      977:             if(node->action==NODE_DLNG) {
                    978:                 if((node->aux/60)>=12) {
                    979:                     if(node->aux/60==12)
                    980:                         hour=12;
                    981:                     else
                    982:                         hour=(node->aux/60)-12;
                    983:                     mer="pm";
                    984:                 } else {
                    985:                     if((node->aux/60)==0)    /* 12 midnite */
                    986:                         hour=12;
                    987:                     else hour=node->aux/60;
                    988:                     mer="am";
                    989:                 }
                    990:                 sprintf(str+strlen(str), " ETA %02d:%02d %s"
                    991:                     ,hour,node->aux-((node->aux/60)*60),mer);
                    992:             }
                    993:             break; 
                    994:        }
                    995:     if(node->misc&(NODE_LOCK|NODE_POFF|NODE_AOFF|NODE_MSGW|NODE_NMSG)) {
                    996:         strcat(str," (");
                    997:         if(node->misc&NODE_AOFF)
                    998:             strcat(str,"A");
                    999:         if(node->misc&NODE_LOCK)
                   1000:             strcat(str,"L");
                   1001:         if(node->misc&(NODE_MSGW|NODE_NMSG))
                   1002:             strcat(str,"M");
                   1003:         if(node->misc&NODE_POFF)
                   1004:             strcat(str,"P");
                   1005:         strcat(str,")"); 
                   1006:        }
                   1007:     if(((node->misc
                   1008:         &(NODE_ANON|NODE_UDAT|NODE_INTR|NODE_RRUN|NODE_EVENT|NODE_DOWN))
                   1009:         || node->status==NODE_QUIET)) {
                   1010:         strcat(str," [");
                   1011:         if(node->misc&NODE_ANON)
                   1012:             strcat(str,"A");
                   1013:         if(node->misc&NODE_INTR)
                   1014:             strcat(str,"I");
                   1015:         if(node->misc&NODE_RRUN)
                   1016:             strcat(str,"R");
                   1017:         if(node->misc&NODE_UDAT)
                   1018:             strcat(str,"U");
                   1019:         if(node->status==NODE_QUIET)
                   1020:             strcat(str,"Q");
                   1021:         if(node->misc&NODE_EVENT)
                   1022:             strcat(str,"E");
                   1023:         if(node->misc&NODE_DOWN)
                   1024:             strcat(str,"D");
                   1025:         if(node->misc&NODE_LCHAT)
                   1026:             strcat(str,"C");
                   1027:         strcat(str,"]"); 
                   1028:        }
                   1029:     if(node->errors)
                   1030:         sprintf(str+strlen(str)
                   1031:                        ," %d error%c",node->errors, node->errors>1 ? 's' : '\0' );
                   1032: 
                   1033:        strncpy(buf,str,buflen);
                   1034: 
                   1035:        return(buf);
                   1036: }
                   1037: 
                   1038: /****************************************************************************/
                   1039: /* Displays the information for node number 'number' contained in 'node'    */
                   1040: /****************************************************************************/
                   1041: void DLLCALL printnodedat(scfg_t* cfg, uint number, node_t* node)
                   1042: {
                   1043:        char    status[128];
                   1044: 
                   1045:        printf("Node %2d: %s\n",number,nodestatus(cfg,node,status,sizeof(status)));
                   1046: }
                   1047: 
                   1048: /****************************************************************************/
                   1049: uint DLLCALL userdatdupe(scfg_t* cfg, uint usernumber, uint offset, uint datlen
1.1.1.2 ! root     1050:                                                 ,char *dat, BOOL del, BOOL next)
1.1       root     1051: {
                   1052:     char       str[MAX_PATH+1];
                   1053:     uint       i;
                   1054:        int             file;
                   1055:     long       l,length;
                   1056: 
                   1057:        if(!VALID_CFG(cfg) || dat==NULL)
                   1058:                return(0);
                   1059: 
                   1060:        truncsp(dat);
1.1.1.2 ! root     1061:        SAFEPRINTF(str,"%suser/user.dat", cfg->data_dir);
1.1       root     1062:        if((file=nopen(str,O_RDONLY|O_DENYNONE))==-1)
                   1063:                return(0);
1.1.1.2 ! root     1064:        length=(long)filelength(file);
        !          1065:        if(usernumber && next) 
        !          1066:                l=((long)usernumber) * U_LEN;
        !          1067:        else
        !          1068:                l=0;
        !          1069:        for(;l<length;l+=U_LEN) {
        !          1070:                if(usernumber && l/U_LEN==(long)usernumber-1) 
1.1       root     1071:                        continue;
                   1072:                lseek(file,l+offset,SEEK_SET);
                   1073:                i=0;
                   1074:                while(i<LOOP_NODEDAB && lock(file,l,U_LEN)==-1) {
                   1075:                        if(i)
                   1076:                                mswait(100);
                   1077:                        i++; 
                   1078:                }
                   1079: 
                   1080:                if(i>=LOOP_NODEDAB) {
                   1081:                        close(file);
                   1082:                        return(0); 
                   1083:                }
                   1084: 
                   1085:                read(file,str,datlen);
                   1086:                for(i=0;i<datlen;i++)
                   1087:                        if(str[i]==ETX) break;
                   1088:                str[i]=0;
                   1089:                truncsp(str);
                   1090:                if(!stricmp(str,dat)) {
                   1091:                        if(!del) {      /* Don't include deleted users in search */
                   1092:                                lseek(file,l+U_MISC,SEEK_SET);
                   1093:                                read(file,str,8);
                   1094:                                getrec(str,0,8,str);
                   1095:                                if(ahtoul(str)&(DELETED|INACTIVE)) {
                   1096:                                        unlock(file,l,U_LEN);
                   1097:                                        continue; 
                   1098:                                } 
                   1099:                        }
                   1100:                        unlock(file,l,U_LEN);
                   1101:                        close(file);
                   1102:                        return((l/U_LEN)+1); 
                   1103:                } else
                   1104:                        unlock(file,l,U_LEN); 
                   1105:        }
                   1106:        close(file);
                   1107:        return(0);
                   1108: }
                   1109: 
                   1110: /****************************************************************************/
                   1111: /* Creates a short message for 'usernumber' that contains 'strin'           */
                   1112: /****************************************************************************/
                   1113: int DLLCALL putsmsg(scfg_t* cfg, int usernumber, char *strin)
                   1114: {
                   1115:     char str[256];
                   1116:     int file,i;
                   1117:     node_t node;
                   1118: 
                   1119:        if(!VALID_CFG(cfg) || usernumber<1 || strin==NULL)
                   1120:                return(-1);
                   1121: 
                   1122:        if(*strin==0)
                   1123:                return(0);
                   1124: 
1.1.1.2 ! root     1125:        SAFEPRINTF2(str,"%smsgs/%4.4u.msg",cfg->data_dir,usernumber);
1.1       root     1126:        if((file=nopen(str,O_WRONLY|O_CREAT|O_APPEND))==-1) {
                   1127:                return(errno); 
                   1128:        }
                   1129:        i=strlen(strin);
                   1130:        if(write(file,strin,i)!=i) {
                   1131:                close(file);
                   1132:                return(errno); 
                   1133:        }
                   1134:        close(file);
                   1135:        for(i=1;i<=cfg->sys_nodes;i++) {     /* flag node if user on that msg waiting */
                   1136:                getnodedat(cfg,i,&node,NULL);
                   1137:                if(node.useron==usernumber
                   1138:                        && (node.status==NODE_INUSE || node.status==NODE_QUIET)
                   1139:                        && !(node.misc&NODE_MSGW)) {
                   1140:                        getnodedat(cfg,i,&node,&file);
                   1141:                        node.misc|=NODE_MSGW;
                   1142:                        putnodedat(cfg,i,&node,file); 
                   1143:                } 
                   1144:        }
                   1145:        return(0);
                   1146: }
                   1147: 
                   1148: /****************************************************************************/
                   1149: /* Returns any short messages waiting for user number, buffer must be freed */
                   1150: /****************************************************************************/
                   1151: char* DLLCALL getsmsg(scfg_t* cfg, int usernumber)
                   1152: {
                   1153:        char    str[MAX_PATH+1], *buf;
                   1154:        int             i;
                   1155:     int                file;
                   1156:     long       length;
                   1157:        node_t  node;
                   1158: 
                   1159:        if(!VALID_CFG(cfg) || usernumber<1)
                   1160:                return(NULL);
                   1161: 
1.1.1.2 ! root     1162:        for(i=1;i<=cfg->sys_nodes;i++) {        /* clear msg waiting flag */
        !          1163:                getnodedat(cfg,i,&node,NULL);
        !          1164:                if(node.useron==usernumber
        !          1165:                        && (node.status==NODE_INUSE || node.status==NODE_QUIET)
        !          1166:                        && node.misc&NODE_MSGW) {
        !          1167:                        getnodedat(cfg,i,&node,&file);
        !          1168:                        node.misc&=~NODE_MSGW;
        !          1169:                        putnodedat(cfg,i,&node,file); 
        !          1170:                } 
        !          1171:        }
        !          1172: 
        !          1173:        SAFEPRINTF2(str,"%smsgs/%4.4u.msg",cfg->data_dir,usernumber);
1.1       root     1174:        if(flength(str)<1L)
                   1175:                return(NULL);
                   1176:        if((file=nopen(str,O_RDWR))==-1)
                   1177:                return(NULL);
1.1.1.2 ! root     1178:        length=(long)filelength(file);
1.1       root     1179:        if((buf=(char *)malloc(length+1))==NULL) {
                   1180:                close(file);
                   1181:                return(NULL);
                   1182:        }
                   1183:        if(read(file,buf,length)!=length) {
                   1184:                close(file);
                   1185:                free(buf);
                   1186:                return(NULL);
                   1187:        }
                   1188:        chsize(file,0L);
                   1189:        close(file);
                   1190:        buf[length]=0;
                   1191: 
                   1192:        return(buf);    /* caller must free */
                   1193: }
                   1194: 
                   1195: char* DLLCALL getnmsg(scfg_t* cfg, int node_num)
                   1196: {
                   1197:        char    str[MAX_PATH+1];
                   1198:        char*   buf;
                   1199:        int             file;
                   1200:        long    length;
                   1201:        node_t  node;
                   1202: 
                   1203:        if(!VALID_CFG(cfg) || node_num<1)
                   1204:                return(NULL);
                   1205: 
                   1206:        getnodedat(cfg,node_num,&node,&file);
                   1207:        node.misc&=~NODE_NMSG;          /* clear the NMSG flag */
                   1208:        putnodedat(cfg,node_num,&node,file);
                   1209: 
1.1.1.2 ! root     1210:        SAFEPRINTF2(str,"%smsgs/n%3.3u.msg",cfg->data_dir,node_num);
1.1       root     1211:        if(flength(str)<1L)
                   1212:                return(NULL);
                   1213:        if((file=nopen(str,O_RDWR))==-1)
                   1214:                return(NULL); 
1.1.1.2 ! root     1215:        length=(long)filelength(file);
1.1       root     1216:        if(!length) {
                   1217:                close(file);
                   1218:                return(NULL); 
                   1219:        }
                   1220:        if((buf=(char *)malloc(length+1))==NULL) {
                   1221:                close(file);
                   1222:                return(NULL); 
                   1223:        }
                   1224:        if(read(file,buf,length)!=length) {
                   1225:                close(file);
                   1226:                free(buf);
                   1227:                return(NULL);
                   1228:        }
                   1229:        chsize(file,0L);
                   1230:        close(file);
                   1231:        buf[length]=0;
                   1232: 
                   1233:        return(buf);    /* caller must free */
                   1234: }
                   1235: 
                   1236: /****************************************************************************/
                   1237: /* Creates a short message for node 'num' that contains 'strin'             */
                   1238: /****************************************************************************/
                   1239: int DLLCALL putnmsg(scfg_t* cfg, int num, char *strin)
                   1240: {
                   1241:     char str[256];
                   1242:     int file,i;
                   1243:     node_t node;
                   1244: 
                   1245:        if(!VALID_CFG(cfg) || num<1 || strin==NULL)
                   1246:                return(-1);
                   1247: 
                   1248:        if(*strin==0)
                   1249:                return(0);
                   1250: 
1.1.1.2 ! root     1251:        SAFEPRINTF2(str,"%smsgs/n%3.3u.msg",cfg->data_dir,num);
1.1       root     1252:        if((file=nopen(str,O_WRONLY|O_CREAT))==-1)
                   1253:                return(errno); 
                   1254:        lseek(file,0L,SEEK_END);        /* Instead of opening with O_APPEND */
                   1255:        i=strlen(strin);
                   1256:        if(write(file,strin,i)!=i) {
                   1257:                close(file);
                   1258:                return(errno); 
                   1259:        }
                   1260:        close(file);
                   1261:        getnodedat(cfg,num,&node,NULL);
                   1262:        if((node.status==NODE_INUSE || node.status==NODE_QUIET)
                   1263:                && !(node.misc&NODE_NMSG)) {
                   1264:                getnodedat(cfg,num,&node,&file);
                   1265:                node.misc|=NODE_NMSG;
                   1266:                putnodedat(cfg,num,&node,file); 
                   1267:        }
                   1268: 
                   1269:        return(0);
                   1270: }
                   1271: 
                   1272: static int getdirnum(scfg_t* cfg, char* code)
                   1273: {
                   1274:        size_t i;
                   1275: 
                   1276:        for(i=0;i<cfg->total_dirs;i++)
                   1277:                if(stricmp(cfg->dir[i]->code,code)==0)
                   1278:                        return(i);
                   1279:        return(-1);
                   1280: }
                   1281: 
                   1282: static int getlibnum(scfg_t* cfg, char* code)
                   1283: {
                   1284:        size_t i;
                   1285: 
                   1286:        for(i=0;i<cfg->total_dirs;i++)
                   1287:                if(stricmp(cfg->dir[i]->code,code)==0)
                   1288:                        return(cfg->dir[i]->lib);
                   1289:        return(-1);
                   1290: }
                   1291: 
                   1292: static int getsubnum(scfg_t* cfg, char* code)
                   1293: {
                   1294:        size_t i;
                   1295: 
                   1296:        for(i=0;i<cfg->total_subs;i++)
                   1297:                if(stricmp(cfg->sub[i]->code,code)==0)
                   1298:                        return(i);
                   1299:        return(-1);
                   1300: }
                   1301: 
                   1302: static int getgrpnum(scfg_t* cfg, char* code)
                   1303: {
                   1304:        size_t i;
                   1305: 
                   1306:        for(i=0;i<cfg->total_subs;i++)
                   1307:                if(stricmp(cfg->sub[i]->code,code)==0)
                   1308:                        return(cfg->sub[i]->grp);
                   1309:        return(-1);
                   1310: }
                   1311: 
1.1.1.2 ! root     1312: static BOOL ar_exp(scfg_t* cfg, uchar **ptrptr, user_t* user, client_t* client)
1.1       root     1313: {
                   1314:        BOOL    result,not,or,equal;
                   1315:        uint    i,n,artype=AR_LEVEL,age;
                   1316:        ulong   l;
                   1317:        time_t  now;
                   1318:        struct tm tm;
1.1.1.2 ! root     1319:        const char*     p;
1.1       root     1320: 
                   1321:        result = TRUE;
                   1322: 
                   1323:        for(;(**ptrptr);(*ptrptr)++) {
                   1324: 
                   1325:                if((**ptrptr)==AR_ENDNEST)
                   1326:                        break;
                   1327: 
                   1328:                not=or=equal = FALSE;
                   1329: 
                   1330:                if((**ptrptr)==AR_OR) {
                   1331:                        or=1;
                   1332:                        (*ptrptr)++; 
                   1333:                }
                   1334:                
                   1335:                if((**ptrptr)==AR_NOT) {
                   1336:                        not=1;
                   1337:                        (*ptrptr)++; 
                   1338:                }
                   1339: 
                   1340:                if((**ptrptr)==AR_EQUAL) {
                   1341:                        equal=1;
                   1342:                        (*ptrptr)++; 
                   1343:                }
                   1344: 
                   1345:                if((result && or) || (!result && !or))
                   1346:                        break;
                   1347: 
                   1348:                if((**ptrptr)==AR_BEGNEST) {
                   1349:                        (*ptrptr)++;
1.1.1.2 ! root     1350:                        if(ar_exp(cfg,ptrptr,user,client))
1.1       root     1351:                                result=!not;
                   1352:                        else
                   1353:                                result=not;
                   1354:                        while((**ptrptr)!=AR_ENDNEST && (**ptrptr)) /* in case of early exit */
                   1355:                                (*ptrptr)++;
                   1356:                        if(!(**ptrptr))
                   1357:                                break;
                   1358:                        continue; 
                   1359:                }
                   1360: 
                   1361:                artype=(**ptrptr);
                   1362:                switch(artype) {
                   1363:                        case AR_ANSI:                           /* No arguments */
                   1364:                        case AR_RIP:
                   1365:                        case AR_WIP:
                   1366:                        case AR_LOCAL:
                   1367:                        case AR_EXPERT:
                   1368:                        case AR_SYSOP:
                   1369:                        case AR_GUEST:
                   1370:                        case AR_QNODE:
                   1371:                        case AR_QUIET:
                   1372:                        case AR_OS2:
                   1373:                        case AR_DOS:
1.1.1.2 ! root     1374:                        case AR_WIN32:
        !          1375:                        case AR_UNIX:
        !          1376:                        case AR_LINUX:
1.1       root     1377:                                break;
                   1378:                        default:
                   1379:                                (*ptrptr)++;
                   1380:                                break; 
                   1381:                }
                   1382: 
                   1383:                n=(**ptrptr);
                   1384:                i=(*(short *)*ptrptr);
                   1385:                switch(artype) {
                   1386:                        case AR_LEVEL:
                   1387:                                if(user==NULL 
                   1388:                                        || (equal && user->level!=n) 
                   1389:                                        || (!equal && user->level<n))
                   1390:                                        result=not;
                   1391:                                else
                   1392:                                        result=!not;
                   1393:                                break;
                   1394:                        case AR_AGE:
                   1395:                                if(user==NULL)
                   1396:                                        result=not;
                   1397:                                else {
                   1398:                                        age=getage(cfg,user->birth);
                   1399:                                        if((equal && age!=n) || (!equal && age<n))
                   1400:                                                result=not;
                   1401:                                        else
                   1402:                                                result=!not;
                   1403:                                }
                   1404:                                break;
                   1405:                        case AR_BPS:
                   1406:                                result=!not;
                   1407:                                (*ptrptr)++;
                   1408:                                break;
                   1409:                        case AR_ANSI:
                   1410:                                if(user==NULL || !(user->misc&ANSI))
                   1411:                                        result=not;
                   1412:                                else result=!not;
                   1413:                                break;
                   1414:                        case AR_RIP:
                   1415:                                if(user==NULL || !(user->misc&RIP))
                   1416:                                        result=not;
                   1417:                                else result=!not;
                   1418:                                break;
                   1419:                        case AR_WIP:
                   1420:                                if(user==NULL || !(user->misc&WIP))
                   1421:                                        result=not;
                   1422:                                else result=!not;
                   1423:                                break;
                   1424:                        case AR_OS2:
                   1425:                                #ifndef __OS2__
                   1426:                                        result=not;
                   1427:                                #else
                   1428:                                        result=!not;
                   1429:                                #endif
                   1430:                                break;
                   1431:                        case AR_DOS:
                   1432:                                result=not;
                   1433:                                break;
                   1434:                        case AR_WIN32:
                   1435:                                #ifndef _WIN32
                   1436:                                        result=not;
                   1437:                                #else
                   1438:                                        result=!not;
                   1439:                                #endif
                   1440:                                break;
                   1441:                        case AR_UNIX:
                   1442:                                #ifndef __unix__
                   1443:                                        result=not;
                   1444:                                #else
                   1445:                                        result=!not;
                   1446:                                #endif
                   1447:                                break;
                   1448:                        case AR_LINUX:
                   1449:                                #ifndef __linux__
                   1450:                                        result=not;
                   1451:                                #else
                   1452:                                        result=!not;
                   1453:                                #endif
                   1454:                                break;
                   1455:                        case AR_ACTIVE:
                   1456:                                if(user==NULL || user->misc&(DELETED|INACTIVE))
                   1457:                                        result=not;
                   1458:                                else result=!not;
                   1459:                                break;
                   1460:                        case AR_INACTIVE:
                   1461:                                if(user==NULL || !(user->misc&INACTIVE))
                   1462:                                        result=not;
                   1463:                                else result=!not;
                   1464:                                break;
                   1465:                        case AR_DELETED:
                   1466:                                if(user==NULL || !(user->misc&DELETED))
                   1467:                                        result=not;
                   1468:                                else result=!not;
                   1469:                                break;
                   1470:                        case AR_EXPERT:
                   1471:                                if(user==NULL || !(user->misc&EXPERT))
                   1472:                                        result=not;
                   1473:                                else result=!not;
                   1474:                                break;
                   1475:                        case AR_SYSOP:
                   1476:                                if(user==NULL || user->level<SYSOP_LEVEL)
                   1477:                                        result=not;
                   1478:                                else result=!not;
                   1479:                                break;
                   1480:                        case AR_GUEST:
                   1481:                                if(user==NULL || !(user->rest&FLAG('G')))
                   1482:                                        result=not;
                   1483:                                else result=!not;
                   1484:                                break;
                   1485:                        case AR_QNODE:
                   1486:                                if(user==NULL || !(user->rest&FLAG('Q')))
                   1487:                                        result=not;
                   1488:                                else result=!not;
                   1489:                                break;
                   1490:                        case AR_QUIET:
                   1491:                                result=not;
                   1492:                                break;
                   1493:                        case AR_LOCAL:
                   1494:                                result=not;
                   1495:                                break;
                   1496:                        case AR_DAY:
                   1497:                                now=time(NULL);
                   1498:                                localtime_r(&now,&tm);
                   1499:                                if((equal && tm.tm_wday!=(int)n) 
                   1500:                                        || (!equal && tm.tm_wday<(int)n))
                   1501:                                        result=not;
                   1502:                                else
                   1503:                                        result=!not;
                   1504:                                break;
                   1505:                        case AR_CREDIT:
                   1506:                                l=(ulong)i*1024UL;
                   1507:                                if(user==NULL
                   1508:                                        || (equal && user->cdt+user->freecdt!=l)
                   1509:                                        || (!equal && user->cdt+user->freecdt<l))
                   1510:                                        result=not;
                   1511:                                else
                   1512:                                        result=!not;
                   1513:                                (*ptrptr)++;
                   1514:                                break;
                   1515:                        case AR_NODE:
                   1516:                                if((equal && cfg->node_num!=n) || (!equal && cfg->node_num<n))
                   1517:                                        result=not;
                   1518:                                else
                   1519:                                        result=!not;
                   1520:                                break;
                   1521:                        case AR_USER:
                   1522:                                if(user==NULL
                   1523:                                        || (equal && user->number!=i) 
                   1524:                                        || (!equal && user->number<i))
                   1525:                                        result=not;
                   1526:                                else
                   1527:                                        result=!not;
                   1528:                                (*ptrptr)++;
                   1529:                                break;
                   1530:                        case AR_GROUP:
                   1531:                                if(user==NULL)
                   1532:                                        result=not;
                   1533:                                else {
                   1534:                                        l=getgrpnum(cfg,user->cursub);
                   1535:                                        if((equal && l!=i) || (!equal && l<i))
                   1536:                                                result=not;
                   1537:                                        else
                   1538:                                                result=!not;
                   1539:                                }
                   1540:                                (*ptrptr)++;
                   1541:                                break;
                   1542:                        case AR_SUB:
                   1543:                                if(user==NULL)
                   1544:                                        result=not;
                   1545:                                else {
                   1546:                                        l=getsubnum(cfg,user->cursub);
                   1547:                                        if((equal && l!=i) || (!equal && l<i))
                   1548:                                                result=not;
                   1549:                                        else
                   1550:                                                result=!not;
                   1551:                                }
                   1552:                                (*ptrptr)++;
                   1553:                                break;
                   1554:                        case AR_SUBCODE:
1.1.1.2 ! root     1555:                                if(user!=NULL && !findstr_in_string(user->cursub,(char *)*ptrptr)==0)
1.1       root     1556:                                        result=!not;
                   1557:                                else
                   1558:                                        result=not;
                   1559:                                while(*(*ptrptr))
                   1560:                                        (*ptrptr)++;
                   1561:                                break;
                   1562:                        case AR_LIB:
                   1563:                                if(user==NULL)
                   1564:                                        result=not;
                   1565:                                else {
                   1566:                                        l=getlibnum(cfg,user->curdir);
                   1567:                                        if((equal && l!=i) || (!equal && l<i))
                   1568:                                                result=not;
                   1569:                                        else
                   1570:                                                result=!not;
                   1571:                                }
                   1572:                                (*ptrptr)++;
                   1573:                                break;
                   1574:                        case AR_DIR:
                   1575:                                if(user==NULL)
                   1576:                                        result=not;
                   1577:                                else {
                   1578:                                        l=getdirnum(cfg,user->curdir);
                   1579:                                        if((equal && l!=i) || (!equal && l<i))
                   1580:                                                result=not;
                   1581:                                        else
                   1582:                                                result=!not;
                   1583:                                }
                   1584:                                (*ptrptr)++;
                   1585:                                break;
                   1586:                        case AR_DIRCODE:
1.1.1.2 ! root     1587:                                if(user!=NULL && !findstr_in_string(user->curdir,(char *)*ptrptr)==0)
1.1       root     1588:                                        result=!not;
                   1589:                                else
                   1590:                                        result=not;
                   1591:                                while(*(*ptrptr))
                   1592:                                        (*ptrptr)++;
                   1593:                                break;
                   1594:                        case AR_EXPIRE:
                   1595:                                now=time(NULL);
                   1596:                                if(user==NULL 
                   1597:                                        || user->expire==0
                   1598:                                        || now+((long)i*24L*60L*60L)>user->expire)
                   1599:                                        result=not;
                   1600:                                else
                   1601:                                        result=!not;
                   1602:                                (*ptrptr)++;
                   1603:                                break;
                   1604:                        case AR_RANDOM:
                   1605:                                n=xp_random(i+1);
                   1606:                                if((equal && n!=i) || (!equal && n<i))
                   1607:                                        result=not;
                   1608:                                else
                   1609:                                        result=!not;
                   1610:                                (*ptrptr)++;
                   1611:                                break;
                   1612:                        case AR_LASTON:
                   1613:                                now=time(NULL);
                   1614:                                if(user==NULL || (now-user->laston)/(24L*60L*60L)<(long)i)
                   1615:                                        result=not;
                   1616:                                else
                   1617:                                        result=!not;
                   1618:                                (*ptrptr)++;
                   1619:                                break;
                   1620:                        case AR_LOGONS:
                   1621:                                if(user==NULL 
                   1622:                                        || (equal && user->logons!=i) 
                   1623:                                        || (!equal && user->logons<i))
                   1624:                                        result=not;
                   1625:                                else
                   1626:                                        result=!not;
                   1627:                                (*ptrptr)++;
                   1628:                                break;
                   1629:                        case AR_MAIN_CMDS:
                   1630:                                result=not;
                   1631:                                (*ptrptr)++;
                   1632:                                break;
                   1633:                        case AR_FILE_CMDS:
                   1634:                                result=not;
                   1635:                                (*ptrptr)++;
                   1636:                                break;
                   1637:                        case AR_TLEFT:
                   1638:                                result=not;
                   1639:                                break;
                   1640:                        case AR_TUSED:
                   1641:                                result=not;
                   1642:                                break;
                   1643:                        case AR_TIME:
                   1644:                                now=time(NULL);
                   1645:                                localtime_r(&now,&tm);
                   1646:                                if((tm.tm_hour*60)+tm.tm_min<(int)i)
                   1647:                                        result=not;
                   1648:                                else
                   1649:                                        result=!not;
                   1650:                                (*ptrptr)++;
                   1651:                                break;
                   1652:                        case AR_PCR:
                   1653:                                if(user==NULL)
                   1654:                                        result=not;
                   1655:                                else if(user->logons>user->posts
                   1656:                                        && (!user->posts || 100/((float)user->logons/user->posts)<(long)n))
                   1657:                                        result=not;
                   1658:                                else
                   1659:                                        result=!not;
                   1660:                                break;
                   1661:                        case AR_UDR:    /* up/download byte ratio */
                   1662:                                if(user==NULL)
                   1663:                                        result=not;
                   1664:                                else {
                   1665:                                        l=user->dlb;
                   1666:                                        if(!l) l=1;
                   1667:                                        if(user->dlb>user->ulb
                   1668:                                                && (!user->ulb || 100/((float)l/user->ulb)<n))
                   1669:                                                result=not;
                   1670:                                        else
                   1671:                                                result=!not;
                   1672:                                }
                   1673:                                break;
                   1674:                        case AR_UDFR:   /* up/download file ratio */
                   1675:                                if(user==NULL)
                   1676:                                        result=not;
                   1677:                                else {
                   1678:                                        i=user->dls;
                   1679:                                        if(!i) i=1;
                   1680:                                        if(user->dls>user->uls
                   1681:                                                && (!user->uls || 100/((float)i/user->uls)<n))
                   1682:                                                result=not;
                   1683:                                        else
                   1684:                                                result=!not;
                   1685:                                }
                   1686:                                break;
1.1.1.2 ! root     1687:                        case AR_ULS:
        !          1688:                                if(user==NULL || (equal && user->uls!=i) || (!equal && user->uls<i))
        !          1689:                                        result=not;
        !          1690:                                else
        !          1691:                                        result=!not;
        !          1692:                                (*ptrptr)++;
        !          1693:                                break;
        !          1694:                        case AR_ULK:
        !          1695:                                if(user==NULL || (equal && user->ulb/1024!=i) || (!equal && user->ulb/1024<i))
        !          1696:                                        result=not;
        !          1697:                                else
        !          1698:                                        result=!not;
        !          1699:                                (*ptrptr)++;
        !          1700:                                break;
        !          1701:                        case AR_ULM:
        !          1702:                                if(user==NULL || (equal && user->ulb/(1024*1024)!=i) || (!equal && user->ulb/(1024*1024)<i))
        !          1703:                                        result=not;
        !          1704:                                else
        !          1705:                                        result=!not;
        !          1706:                                (*ptrptr)++;
        !          1707:                                break;
        !          1708:                        case AR_DLS:
        !          1709:                                if(user==NULL || (equal && user->dls!=i) || (!equal && user->dls<i))
        !          1710:                                        result=not;
        !          1711:                                else
        !          1712:                                        result=!not;
        !          1713:                                (*ptrptr)++;
        !          1714:                                break;
        !          1715:                        case AR_DLK:
        !          1716:                                if(user==NULL || (equal && user->dlb/1024!=i) || (!equal && user->dlb/1024<i))
        !          1717:                                        result=not;
        !          1718:                                else
        !          1719:                                        result=!not;
        !          1720:                                (*ptrptr)++;
        !          1721:                                break;
        !          1722:                        case AR_DLM:
        !          1723:                                if(user==NULL || (equal && user->dlb/(1024*1024)!=i) || (!equal && user->dlb/(1024*1024)<i))
        !          1724:                                        result=not;
        !          1725:                                else
        !          1726:                                        result=!not;
        !          1727:                                (*ptrptr)++;
        !          1728:                                break;
1.1       root     1729:                        case AR_FLAG1:
                   1730:                                if(user==NULL
                   1731:                                        || (!equal && !(user->flags1&FLAG(n)))
                   1732:                                        || (equal && user->flags1!=FLAG(n)))
                   1733:                                        result=not;
                   1734:                                else
                   1735:                                        result=!not;
                   1736:                                break;
                   1737:                        case AR_FLAG2:
                   1738:                                if(user==NULL
                   1739:                                        || (!equal && !(user->flags2&FLAG(n)))
                   1740:                                        || (equal && user->flags2!=FLAG(n)))
                   1741:                                        result=not;
                   1742:                                else
                   1743:                                        result=!not;
                   1744:                                break;
                   1745:                        case AR_FLAG3:
                   1746:                                if(user==NULL
                   1747:                                        || (!equal && !(user->flags3&FLAG(n)))
                   1748:                                        || (equal && user->flags3!=FLAG(n)))
                   1749:                                        result=not;
                   1750:                                else
                   1751:                                        result=!not;
                   1752:                                break;
                   1753:                        case AR_FLAG4:
                   1754:                                if(user==NULL
                   1755:                                        || (!equal && !(user->flags4&FLAG(n)))
                   1756:                                        || (equal && user->flags4!=FLAG(n)))
                   1757:                                        result=not;
                   1758:                                else
                   1759:                                        result=!not;
                   1760:                                break;
                   1761:                        case AR_REST:
                   1762:                                if(user==NULL
                   1763:                                        || (!equal && !(user->rest&FLAG(n)))
                   1764:                                        || (equal && user->rest!=FLAG(n)))
                   1765:                                        result=not;
                   1766:                                else
                   1767:                                        result=!not;
                   1768:                                break;
                   1769:                        case AR_EXEMPT:
                   1770:                                if(user==NULL
                   1771:                                        || (!equal && !(user->exempt&FLAG(n)))
                   1772:                                        || (equal && user->exempt!=FLAG(n)))
                   1773:                                        result=not;
                   1774:                                else
                   1775:                                        result=!not;
                   1776:                                break;
                   1777:                        case AR_SEX:
                   1778:                                if(user==NULL || user->sex!=n)
                   1779:                                        result=not;
                   1780:                                else
                   1781:                                        result=!not;
                   1782:                                break; 
                   1783:                        case AR_SHELL:
                   1784:                                if(user==NULL 
                   1785:                                        || user->shell>=cfg->total_shells
1.1.1.2 ! root     1786:                                        || !findstr_in_string(cfg->shell[user->shell]->code,(char*)*ptrptr))
1.1       root     1787:                                        result=not;
                   1788:                                else
                   1789:                                        result=!not;
                   1790:                                while(*(*ptrptr))
                   1791:                                        (*ptrptr)++;
                   1792:                                break;
                   1793:                        case AR_PROT:
1.1.1.2 ! root     1794:                                if(client!=NULL)
        !          1795:                                        p=client->protocol;
        !          1796:                                else if(user!=NULL)
        !          1797:                                        p=user->modem;
        !          1798:                                else
        !          1799:                                        p=NULL;
        !          1800:                                if(!findstr_in_string(p,(char*)*ptrptr))
        !          1801:                                        result=not;
        !          1802:                                else
        !          1803:                                        result=!not;
        !          1804:                                while(*(*ptrptr))
        !          1805:                                        (*ptrptr)++;
        !          1806:                                break;
        !          1807:                        case AR_HOST:
        !          1808:                                if(client!=NULL)
        !          1809:                                        p=client->host;
        !          1810:                                else if(user!=NULL)
        !          1811:                                        p=user->comp;
        !          1812:                                else
        !          1813:                                        p=NULL;
        !          1814:                                if(!findstr_in_string(p,(char*)*ptrptr))
        !          1815:                                        result=not;
        !          1816:                                else
        !          1817:                                        result=!not;
        !          1818:                                while(*(*ptrptr))
        !          1819:                                        (*ptrptr)++;
        !          1820:                                break;
        !          1821:                        case AR_IP:
        !          1822:                                if(client!=NULL)
        !          1823:                                        p=client->addr;
        !          1824:                                else if(user!=NULL)
        !          1825:                                        p=user->note;
        !          1826:                                else
        !          1827:                                        p=NULL;
        !          1828:                                if(!findstr_in_string(p,(char*)*ptrptr))
1.1       root     1829:                                        result=not;
                   1830:                                else
                   1831:                                        result=!not;
                   1832:                                while(*(*ptrptr))
                   1833:                                        (*ptrptr)++;
                   1834:                                break;
                   1835:                } 
                   1836:        }
                   1837:        return(result);
                   1838: }
                   1839: 
1.1.1.2 ! root     1840: BOOL DLLCALL chk_ar(scfg_t* cfg, uchar *ar, user_t* user, client_t* client)
1.1       root     1841: {
                   1842:        uchar *p;
                   1843: 
                   1844:        if(ar==NULL)
                   1845:                return(TRUE);
                   1846:        if(!VALID_CFG(cfg))
                   1847:                return(FALSE);
                   1848:        p=ar;
1.1.1.2 ! root     1849:        return(ar_exp(cfg,&p,user,client));
1.1       root     1850: }
                   1851: 
                   1852: /****************************************************************************/
                   1853: /* Fills 'str' with record for usernumber starting at start for length bytes*/
                   1854: /* Called from function ???                                                                                                    */
                   1855: /****************************************************************************/
                   1856: int DLLCALL getuserrec(scfg_t* cfg, int usernumber,int start, int length, char *str)
                   1857: {
                   1858:        char    path[256];
                   1859:        int             i,c,file;
                   1860: 
                   1861:        if(!VALID_CFG(cfg) || usernumber<1 || str==NULL)
                   1862:                return(-1);
1.1.1.2 ! root     1863:        SAFEPRINTF(path,"%suser/user.dat",cfg->data_dir);
1.1       root     1864:        if((file=nopen(path,O_RDONLY|O_DENYNONE))==-1) 
                   1865:                return(errno);
                   1866:        if(usernumber<1
                   1867:                || filelength(file)<(long)((long)(usernumber-1L)*U_LEN)+(long)start) {
                   1868:                close(file);
                   1869:                return(-2); 
                   1870:        }
                   1871:        lseek(file,(long)((long)(usernumber-1)*U_LEN)+start,SEEK_SET);
                   1872: 
                   1873:        if(length==0)   /* auto-length */
                   1874:                length=user_rec_len(start);
                   1875: 
                   1876:        i=0;
                   1877:        while(i<LOOP_NODEDAB
                   1878:                && lock(file,(long)((long)(usernumber-1)*U_LEN)+start,length)==-1) {
                   1879:                if(i)
                   1880:                        mswait(100);
                   1881:                i++; 
                   1882:        }
                   1883: 
                   1884:        if(i>=LOOP_NODEDAB) {
                   1885:                close(file);
                   1886:                return(-3); 
                   1887:        }
                   1888: 
                   1889:        if(read(file,str,length)!=length) {
                   1890:                unlock(file,(long)((long)(usernumber-1)*U_LEN)+start,length);
                   1891:                close(file);
                   1892:                return(-4); 
                   1893:        }
                   1894: 
                   1895:        unlock(file,(long)((long)(usernumber-1)*U_LEN)+start,length);
                   1896:        close(file);
                   1897:        for(c=0;c<length;c++)
                   1898:                if(str[c]==ETX || str[c]==CR) break;
                   1899:        str[c]=0;
                   1900: 
                   1901:        return(0);
                   1902: }
                   1903: 
                   1904: /****************************************************************************/
                   1905: /* Places into user.dat at the offset for usernumber+start for length bytes */
                   1906: /* Called from various locations                                                                                       */
                   1907: /****************************************************************************/
1.1.1.2 ! root     1908: int DLLCALL putuserrec(scfg_t* cfg, int usernumber,int start, uint length, const char *str)
1.1       root     1909: {
                   1910:        char    str2[256];
                   1911:        int             file;
                   1912:        uint    c,i;
                   1913: 
                   1914:        if(!VALID_CFG(cfg) || usernumber<1 || str==NULL)
                   1915:                return(-1);
                   1916: 
1.1.1.2 ! root     1917:        SAFEPRINTF(str2,"%suser/user.dat",cfg->data_dir);
1.1       root     1918:        if((file=nopen(str2,O_RDWR|O_DENYNONE))==-1)
                   1919:                return(errno);
                   1920: 
                   1921:        if(filelength(file)<((long)usernumber-1)*U_LEN) {
                   1922:                close(file);
                   1923:                return(-4);
                   1924:        }
                   1925: 
                   1926:        if(length==0)   /* auto-length */
                   1927:                length=user_rec_len(start);
                   1928: 
                   1929:        strcpy(str2,str);
                   1930:        if(strlen(str2)<length) {
                   1931:                for(c=strlen(str2);c<length;c++)
                   1932:                        str2[c]=ETX;
                   1933:                str2[c]=0; 
                   1934:        }
                   1935:        lseek(file,(long)((long)((long)((long)usernumber-1)*U_LEN)+start),SEEK_SET);
                   1936: 
                   1937:        i=0;
                   1938:        while(i<LOOP_NODEDAB
                   1939:                && lock(file,(long)((long)(usernumber-1)*U_LEN)+start,length)==-1) {
                   1940:                if(i)
                   1941:                        mswait(100);
                   1942:                i++; 
                   1943:        }
                   1944: 
                   1945:        if(i>=LOOP_NODEDAB) 
                   1946:                return(-3);
                   1947: 
                   1948:        write(file,str2,length);
                   1949:        unlock(file,(long)((long)(usernumber-1)*U_LEN)+start,length);
                   1950:        close(file);
1.1.1.2 ! root     1951:        dirtyuserdat(cfg,usernumber);
1.1       root     1952:        return(0);
                   1953: }
                   1954: 
                   1955: /****************************************************************************/
                   1956: /* Updates user 'usernumber's record (numeric string) by adding 'adj' to it */
                   1957: /* returns the new value.                                                                                                      */
                   1958: /****************************************************************************/
                   1959: ulong DLLCALL adjustuserrec(scfg_t* cfg, int usernumber, int start, int length, long adj)
                   1960: {
                   1961:        char str[256],path[256];
                   1962:        char tmp[32];
                   1963:        int i,c,file;
                   1964:        long val;
                   1965: 
                   1966:        if(!VALID_CFG(cfg) || usernumber<1) 
                   1967:                return(0); 
                   1968: 
1.1.1.2 ! root     1969:        SAFEPRINTF(path,"%suser/user.dat",cfg->data_dir);
1.1       root     1970:        if((file=nopen(path,O_RDWR|O_DENYNONE))==-1)
                   1971:                return(0); 
                   1972: 
                   1973:        if(filelength(file)<((long)usernumber-1)*U_LEN) {
                   1974:                close(file);
                   1975:                return(0);
                   1976:        }
                   1977: 
                   1978:        lseek(file,(long)((long)(usernumber-1)*U_LEN)+start,SEEK_SET);
                   1979: 
                   1980:        if(length==0)   /* auto-length */
                   1981:                length=user_rec_len(start);
                   1982: 
                   1983:        i=0;
                   1984:        while(i<LOOP_NODEDAB
                   1985:                && lock(file,(long)((long)(usernumber-1)*U_LEN)+start,length)==-1) {
                   1986:                if(i)
                   1987:                        mswait(100);
                   1988:                i++; 
                   1989:        }
                   1990: 
                   1991:        if(i>=LOOP_NODEDAB) {
                   1992:                close(file);
                   1993:                return(0); 
                   1994:        }
                   1995: 
                   1996:        if(read(file,str,length)!=length) {
                   1997:                unlock(file,(long)((long)(usernumber-1)*U_LEN)+start,length);
                   1998:                close(file);
                   1999:                return(0); 
                   2000:        }
                   2001:        for(c=0;c<length;c++)
                   2002:                if(str[c]==ETX || str[c]==CR) break;
                   2003:        str[c]=0;
                   2004:        val=atol(str);
                   2005:        if(adj<0L && val<-adj)          /* don't go negative */
                   2006:                val=0;
                   2007:        else val+=adj;
                   2008:        lseek(file,(long)((long)(usernumber-1)*U_LEN)+start,SEEK_SET);
                   2009:        putrec(str,0,length,ultoa(val,tmp,10));
                   2010:        if(write(file,str,length)!=length) {
                   2011:                unlock(file,(long)((long)(usernumber-1)*U_LEN)+start,length);
                   2012:                close(file);
                   2013:                return(val); 
                   2014:        }
                   2015:        unlock(file,(long)((long)(usernumber-1)*U_LEN)+start,length);
                   2016:        close(file);
1.1.1.2 ! root     2017:        dirtyuserdat(cfg,usernumber);
1.1       root     2018:        return(val);
                   2019: }
                   2020: 
                   2021: /****************************************************************************/
                   2022: /* Subtract credits from the current user online, accounting for the new    */
                   2023: /* "free credits" field.                                                    */
                   2024: /****************************************************************************/
                   2025: void DLLCALL subtract_cdt(scfg_t* cfg, user_t* user, long amt)
                   2026: {
                   2027:        char tmp[64];
                   2028:     long mod;
                   2029: 
                   2030:        if(!amt || user==NULL)
                   2031:                return;
                   2032:        if(user->freecdt) {
                   2033:                if((ulong)amt>user->freecdt) {      /* subtract both credits and */
                   2034:                        mod=amt-user->freecdt;   /* free credits */
                   2035:                        putuserrec(cfg, user->number,U_FREECDT,10,"0");
                   2036:                        user->freecdt=0;
                   2037:                        user->cdt=adjustuserrec(cfg, user->number,U_CDT,10,-mod); 
                   2038:                } else {                          /* subtract just free credits */
                   2039:                        user->freecdt-=amt;
                   2040:                        putuserrec(cfg, user->number,U_FREECDT,10
                   2041:                                ,ultoa(user->freecdt,tmp,10)); 
                   2042:                } 
                   2043:        }
                   2044:        else    /* no free credits */
                   2045:                user->cdt=adjustuserrec(cfg, user->number,U_CDT,10,-amt);
                   2046: }
                   2047: 
                   2048: BOOL DLLCALL user_posted_msg(scfg_t* cfg, user_t* user, int count)
                   2049: {
                   2050:        if(user==NULL)
                   2051:                return(FALSE);
                   2052: 
                   2053:        user->posts     =(ushort)adjustuserrec(cfg, user->number, U_POSTS, 5, count);
                   2054:        user->ptoday=(ushort)adjustuserrec(cfg, user->number, U_PTODAY, 5, count);
                   2055: 
                   2056:        return(TRUE);
                   2057: }
                   2058: 
                   2059: BOOL DLLCALL user_sent_email(scfg_t* cfg, user_t* user, int count, BOOL feedback)
                   2060: {
                   2061:        if(user==NULL)
                   2062:                return(FALSE);
                   2063: 
                   2064:        if(feedback)
                   2065:                user->fbacks=(ushort)adjustuserrec(cfg, user->number, U_FBACKS, 5, count);
                   2066:        else
                   2067:                user->emails=(ushort)adjustuserrec(cfg, user->number, U_EMAILS, 5, count);
                   2068:        user->etoday=(ushort)adjustuserrec(cfg, user->number, U_ETODAY, 5, count);
                   2069: 
                   2070:        return(TRUE);
                   2071: }
                   2072: 
                   2073: BOOL DLLCALL user_downloaded(scfg_t* cfg, user_t* user, int files, long bytes)
                   2074: {
                   2075:        if(user==NULL)
                   2076:                return(FALSE);
                   2077: 
                   2078:        user->dls=(ushort)adjustuserrec(cfg, user->number, U_DLS, 5, files);
                   2079:        user->dlb=adjustuserrec(cfg, user->number, U_DLB, 10, bytes);
                   2080: 
                   2081:        return(TRUE);
                   2082: }
                   2083: 
                   2084: BOOL DLLCALL user_uploaded(scfg_t* cfg, user_t* user, int files, long bytes)
                   2085: {
                   2086:        if(user==NULL)
                   2087:                return(FALSE);
                   2088: 
                   2089:        user->uls=(ushort)adjustuserrec(cfg, user->number, U_ULS, 5, files);
                   2090:        user->ulb=adjustuserrec(cfg, user->number, U_ULB, 10, bytes);
                   2091: 
                   2092:        return(TRUE);
                   2093: }
                   2094: 
                   2095: BOOL DLLCALL user_adjust_credits(scfg_t* cfg, user_t* user, long amount)
                   2096: {
                   2097:        if(user==NULL)
                   2098:                return(FALSE);
                   2099: 
                   2100:        if(amount<0)    /* subtract */
                   2101:                subtract_cdt(cfg, user, -amount);
                   2102:        else                    /* add */
                   2103:                user->cdt=adjustuserrec(cfg, user->number, U_CDT, 10, amount);
                   2104: 
                   2105:        return(TRUE);
                   2106: }
                   2107: 
                   2108: BOOL DLLCALL user_adjust_minutes(scfg_t* cfg, user_t* user, long amount)
                   2109: {
                   2110:        if(user==NULL)
                   2111:                return(FALSE);
                   2112: 
                   2113:        user->min=adjustuserrec(cfg, user->number, U_MIN, 10, amount);
                   2114: 
                   2115:        return(TRUE);
                   2116: }
                   2117: 
                   2118: /****************************************************************************/
                   2119: /****************************************************************************/
                   2120: BOOL DLLCALL logoutuserdat(scfg_t* cfg, user_t* user, time_t now, time_t logontime)
                   2121: {
                   2122:        char str[128];
                   2123:        time_t tused;
                   2124:        struct tm tm, tm_now;
                   2125: 
                   2126:        if(user==NULL)
                   2127:                return(FALSE);
                   2128: 
                   2129:        if(now==0)
                   2130:                now=time(NULL);
                   2131: 
                   2132:        tused=(now-logontime)/60;
                   2133:        user->tlast=(ushort)(tused > USHRT_MAX ? USHRT_MAX : tused);
                   2134: 
                   2135:        putuserrec(cfg,user->number,U_LASTON,8,ultoa(now,str,16));
                   2136:        putuserrec(cfg,user->number,U_TLAST,5,ultoa(user->tlast,str,10));
                   2137:        adjustuserrec(cfg,user->number,U_TIMEON,5,user->tlast);
                   2138:        adjustuserrec(cfg,user->number,U_TTODAY,5,user->tlast);
                   2139: 
                   2140:        /* Convert time_t to struct tm */
                   2141:        if(localtime_r(&now,&tm_now)==NULL)
                   2142:                return(FALSE);
                   2143: 
                   2144:        if(localtime_r(&logontime,&tm)==NULL)
                   2145:                return(FALSE);
                   2146: 
                   2147:        /* Reset daily stats if new day */
                   2148:        if(tm.tm_mday!=tm_now.tm_mday) 
1.1.1.2 ! root     2149:                resetdailyuserdat(cfg, user, /* write: */TRUE);
1.1       root     2150: 
                   2151:        return(TRUE);
                   2152: }
                   2153: 
                   2154: /****************************************************************************/
                   2155: /****************************************************************************/
1.1.1.2 ! root     2156: void DLLCALL resetdailyuserdat(scfg_t* cfg, user_t* user, BOOL write)
1.1       root     2157: {
                   2158:        char str[128];
                   2159: 
                   2160:        if(!VALID_CFG(cfg) || user==NULL)
                   2161:                return;
                   2162: 
                   2163:        /* logons today */
                   2164:        user->ltoday=0; 
1.1.1.2 ! root     2165:        if(write) putuserrec(cfg,user->number,U_LTODAY,5,"0");
1.1       root     2166:        /* e-mails today */
                   2167:        user->etoday=0; 
1.1.1.2 ! root     2168:        if(write) putuserrec(cfg,user->number,U_ETODAY,5,"0");  
1.1       root     2169:        /* posts today */
                   2170:        user->ptoday=0; 
1.1.1.2 ! root     2171:        if(write) putuserrec(cfg,user->number,U_PTODAY,5,"0");
1.1       root     2172:        /* free credits per day */                              
                   2173:        user->freecdt=cfg->level_freecdtperday[user->level];
1.1.1.2 ! root     2174:        if(write) putuserrec(cfg,user->number,U_FREECDT,10              
1.1       root     2175:                ,ultoa(user->freecdt,str,10));
                   2176:        /* time used today */
                   2177:        user->ttoday=0;
1.1.1.2 ! root     2178:        if(write) putuserrec(cfg,user->number,U_TTODAY,5,"0");
1.1       root     2179:        /* extra time today */
                   2180:        user->textra=0;
1.1.1.2 ! root     2181:        if(write) putuserrec(cfg,user->number,U_TEXTRA,5,"0");  
1.1       root     2182: }
                   2183: 
                   2184: /****************************************************************************/
                   2185: /****************************************************************************/
1.1.1.2 ! root     2186: char* DLLCALL usermailaddr(scfg_t* cfg, char* addr, const char* name)
1.1       root     2187: {
                   2188:        int i;
                   2189: 
                   2190:        if(!VALID_CFG(cfg) || addr==NULL || name==NULL)
                   2191:                return(NULL);
                   2192: 
                   2193:        if(strchr(name,'@')!=NULL) { /* Avoid double-@ */
                   2194:                strcpy(addr,name);
                   2195:                return(addr);
                   2196:        }
1.1.1.2 ! root     2197:        if(strchr(name,'.') && strchr(name,' ')) {
        !          2198:                /* convert "Dr. Seuss" to "Dr.Seuss" */
        !          2199:                strip_space(name,addr);
        !          2200:        } else if(strchr(name,'!')) {
        !          2201:                sprintf(addr,"\"%s\"",name);
        !          2202:        } else {
        !          2203:                strcpy(addr,name);
        !          2204:                /* convert "first last" to "first.last" */
1.1       root     2205:                for(i=0;addr[i];i++)
                   2206:                        if(addr[i]==' ' || addr[i]&0x80)
                   2207:                                addr[i]='.';
                   2208:                strlwr(addr);
                   2209:        }
1.1.1.2 ! root     2210:        strcat(addr,"@");
1.1       root     2211:        strcat(addr,cfg->sys_inetaddr);
                   2212:        return(addr);
                   2213: }
                   2214: 
1.1.1.2 ! root     2215: char* DLLCALL alias(scfg_t* cfg, const char* name, char* buf)
1.1       root     2216: {
                   2217:        char    line[128];
                   2218:        char*   p;
                   2219:        char*   np;
                   2220:        char*   tp;
                   2221:        char*   vp;
                   2222:        char    fname[MAX_PATH+1];
                   2223:        size_t  namelen;
                   2224:        size_t  cmplen;
                   2225:        FILE*   fp;
                   2226: 
                   2227:        if(!VALID_CFG(cfg) || name==NULL || buf==NULL)
                   2228:                return(NULL);
                   2229: 
1.1.1.2 ! root     2230:        p=(char*)name;
1.1       root     2231: 
1.1.1.2 ! root     2232:        SAFEPRINTF(fname,"%salias.cfg",cfg->ctrl_dir);
1.1       root     2233:        if((fp=fopen(fname,"r"))==NULL)
1.1.1.2 ! root     2234:                return((char*)name);
1.1       root     2235: 
                   2236:        while(!feof(fp)) {
                   2237:                if(!fgets(line,sizeof(line),fp))
                   2238:                        break;
                   2239:                np=line;
                   2240:                SKIP_WHITESPACE(np);
                   2241:                if(*np==';' || *np==0)  /* no name value, or comment */
                   2242:                        continue;
                   2243:                tp=np;
                   2244:                FIND_WHITESPACE(tp);
                   2245: 
                   2246:                if(*tp==0)      /* no alias value */
                   2247:                        continue;
                   2248:                *tp=0;
                   2249: 
                   2250:                vp=tp+1;
                   2251:                SKIP_WHITESPACE(vp);
                   2252:                truncsp(vp);
                   2253:                if(*vp==0)      /* no value */
                   2254:                        continue;
                   2255: 
                   2256:                if(*np=='*') {
                   2257:                        np++;
                   2258:                        cmplen=strlen(np);
                   2259:                        namelen=strlen(name);
                   2260:                        if(namelen<cmplen)
                   2261:                                continue;
                   2262:                        if(strnicmp(np,name+(namelen-cmplen),cmplen))
                   2263:                                continue;
                   2264:                        if(*vp=='*') 
                   2265:                                sprintf(buf,"%.*s%s",(int)(namelen-cmplen),name,vp+1);
                   2266:                        else
                   2267:                                strcpy(buf,vp);
                   2268:                        p=buf;
                   2269:                        break;
                   2270:                }
                   2271:                if(!stricmp(np,name)) {
                   2272:                        strcpy(buf,vp);
                   2273:                        p=buf;
                   2274:                        break;
                   2275:                }
                   2276:        }
                   2277:        fclose(fp);
                   2278:        return(p);
                   2279: }
                   2280: 
                   2281: int DLLCALL newuserdat(scfg_t* cfg, user_t* user)
                   2282: {
                   2283:        char    str[MAX_PATH+1];
                   2284:        char    tmp[128];
                   2285:        int             c;
                   2286:        int             i;
                   2287:        int             err;
                   2288:        int             file;
                   2289:        int             unum=1;
                   2290:        int             last;
                   2291:        long    misc;
                   2292:        FILE*   stream;
                   2293:        stats_t stats;
                   2294: 
                   2295:        if(!VALID_CFG(cfg) || user==NULL)
                   2296:                return(-1);
                   2297: 
1.1.1.2 ! root     2298:        SAFEPRINTF(str,"%suser/name.dat",cfg->data_dir);
1.1       root     2299:        if(fexist(str)) {
                   2300:                if((stream=fnopen(&file,str,O_RDONLY))==NULL) {
                   2301:                        return(errno); 
                   2302:                }
1.1.1.2 ! root     2303:                last=(long)filelength(file)/(LEN_ALIAS+2);         /* total users */
1.1       root     2304:                while(unum<=last) {
                   2305:                        fread(str,LEN_ALIAS+2,1,stream);
                   2306:                        for(c=0;c<LEN_ALIAS;c++)
                   2307:                                if(str[c]==ETX) break;
                   2308:                        str[c]=0;
                   2309:                        if(!c) {         /* should be a deleted user */
                   2310:                                getuserrec(cfg,unum,U_MISC,8,str);
                   2311:                                misc=ahtoul(str);
                   2312:                                if(misc&DELETED) {       /* deleted bit set too */
                   2313:                                        getuserrec(cfg,unum,U_LASTON,8,str);
                   2314:                                        if((time(NULL)-ahtoul(str))/86400>=cfg->sys_deldays) 
                   2315:                                                break; /* deleted long enough ? */
                   2316:                                } 
                   2317:                        }
                   2318:                        unum++; 
                   2319:                }
                   2320:                fclose(stream); 
                   2321:        }
                   2322: 
                   2323:        last=lastuser(cfg);             /* Check against data file */
                   2324: 
                   2325:        if(unum>last+1)                 /* Corrupted name.dat? */
                   2326:                unum=last+1;
                   2327:        else if(unum<=last) {   /* Overwriting existing user */
                   2328:                getuserrec(cfg,unum,U_MISC,8,str);
                   2329:                misc=ahtoul(str);
                   2330:                if(!(misc&DELETED)) /* Not deleted? Set usernumber to end+1 */
                   2331:                        unum=last+1; 
                   2332:        }
                   2333: 
                   2334:        user->number=unum;              /* store the new user number */
                   2335: 
                   2336:        if((err=putusername(cfg,user->number,user->alias))!=0)
                   2337:                return(err);
                   2338: 
                   2339:        if((err=putuserdat(cfg,user))!=0)
                   2340:                return(err);
                   2341: 
1.1.1.2 ! root     2342:        SAFEPRINTF2(str,"%sfile/%04u.in",cfg->data_dir,user->number);  /* delete any files */
1.1       root     2343:        delfiles(str,ALLFILES);                                    /* waiting for user */
                   2344:        rmdir(str);
1.1.1.2 ! root     2345:        SAFEPRINTF(tmp,"%04u.*",user->number);
        !          2346:        SAFEPRINTF(str,"%sfile",cfg->data_dir);
1.1       root     2347:        delfiles(str,tmp);
1.1.1.2 ! root     2348:        SAFEPRINTF(str,"%suser",cfg->data_dir);
1.1       root     2349:        delfiles(str,tmp);
1.1.1.2 ! root     2350:        SAFEPRINTF2(str,"%suser/%04u",cfg->data_dir,user->number);
        !          2351:        delfiles(str,ALLFILES);
        !          2352:        rmdir(str);
1.1       root     2353: 
1.1.1.2 ! root     2354:        SAFEPRINTF2(str,"%suser/ptrs/%04u.ixb",cfg->data_dir,user->number); /* msg ptrs */
1.1       root     2355:        remove(str);
1.1.1.2 ! root     2356:        SAFEPRINTF2(str,"%smsgs/%04u.msg",cfg->data_dir,user->number); /* delete short msg */
1.1       root     2357:        remove(str);
                   2358: 
                   2359:        /* Update daily statistics database (for system and node) */
                   2360: 
                   2361:        for(i=0;i<2;i++) {
1.1.1.2 ! root     2362:                SAFEPRINTF(str,"%sdsts.dab",i ? cfg->ctrl_dir : cfg->node_dir);
1.1       root     2363:                if((file=nopen(str,O_RDWR))==-1)
                   2364:                        continue; 
                   2365:                memset(&stats,0,sizeof(stats));
                   2366:                lseek(file,4L,SEEK_SET);   /* Skip timestamp */
                   2367:                read(file,&stats,sizeof(stats));  
                   2368:                stats.nusers++;
                   2369:                lseek(file,4L,SEEK_SET);
                   2370:                write(file,&stats,sizeof(stats));
                   2371:                close(file); 
                   2372:        }
                   2373: 
                   2374:        return(0);
                   2375: }
                   2376: 
                   2377: /* Returns length of specified user record 'field', or -1 if invalid */
                   2378: int DLLCALL user_rec_len(int offset)
                   2379: {
                   2380:        switch(offset) {
                   2381: 
                   2382:                /* Strings (of different lengths) */
                   2383:                case U_ALIAS:           return(LEN_ALIAS);
                   2384:                case U_NAME:            return(LEN_NAME);
                   2385:                case U_HANDLE:          return(LEN_HANDLE);
                   2386:                case U_NOTE:            return(LEN_NOTE);
                   2387:                case U_COMP:            return(LEN_COMP);
                   2388:                case U_COMMENT:         return(LEN_COMMENT);
                   2389:                case U_NETMAIL:         return(LEN_NETMAIL);
                   2390:                case U_ADDRESS:         return(LEN_ADDRESS);
                   2391:                case U_LOCATION:        return(LEN_LOCATION);
                   2392:                case U_ZIPCODE:         return(LEN_ZIPCODE);
                   2393:                case U_PASS:            return(LEN_PASS);
                   2394:                case U_PHONE:           return(LEN_PHONE);
                   2395:                case U_BIRTH:           return(LEN_BIRTH);
                   2396:                case U_MODEM:           return(LEN_MODEM);
                   2397: 
                   2398:                /* Internal codes (16 chars) */
                   2399:                case U_CURSUB:
                   2400:                case U_CURDIR:
                   2401:                        return (16);
                   2402: 
                   2403:                /* Dates in time_t format (8 hex digits) */
                   2404:                case U_LASTON:
                   2405:                case U_FIRSTON:
                   2406:                case U_EXPIRE:
                   2407:                case U_PWMOD:
                   2408:                case U_NS_TIME:
                   2409:                case U_LOGONTIME:
                   2410: 
                   2411:                /* 32-bit integers (8 hex digits) */
                   2412:                case U_FLAGS1:
                   2413:                case U_FLAGS2:
                   2414:                case U_FLAGS3:
                   2415:                case U_FLAGS4:
                   2416:                case U_EXEMPT:
                   2417:                case U_REST:
                   2418:                case U_MISC:
                   2419:                case U_QWK:
                   2420:                case U_CHAT:
                   2421: 
                   2422:                /* Internal codes (8 chars) */
                   2423:                case U_CURXTRN:
                   2424:                case U_XEDIT:
                   2425:                case U_SHELL:
                   2426:                        return(8);
                   2427: 
                   2428:                /* 16-bit integers (5 decimal digits) */
                   2429:                case U_LOGONS:
                   2430:                case U_LTODAY:
                   2431:                case U_TIMEON:
                   2432:                case U_TEXTRA:
                   2433:                case U_TTODAY:
                   2434:                case U_TLAST:
                   2435:                case U_POSTS:
                   2436:                case U_EMAILS:
                   2437:                case U_FBACKS:
                   2438:                case U_ETODAY:
                   2439:                case U_PTODAY:
                   2440:                case U_ULS:
                   2441:                case U_DLS:
                   2442:                        return(5);
                   2443: 
                   2444:                /* 32-bit integers (10 decimal digits) */
                   2445:                case U_ULB:
                   2446:                case U_DLB:
                   2447:                case U_CDT:
                   2448:                case U_MIN:
                   2449:                case U_FREECDT:
                   2450:                        return(10);
                   2451: 
                   2452:                /* 3 char strings */
                   2453:                case U_TMPEXT:
                   2454:                        return(3);
                   2455: 
                   2456:                /* 2 digits integers (0-99) */
                   2457:                case U_LEVEL:
                   2458:                case U_TL:
                   2459:                case U_ROWS:
                   2460:                case U_LEECH:   /* actually, 2 hex digits */
                   2461:                        return(2);
                   2462: 
                   2463:                /* Single digits chars */
                   2464:                case U_SEX:
                   2465:                case U_PROT:
                   2466:                        return(1);
                   2467:        }
                   2468: 
                   2469:        return(-1);
                   2470: }
                   2471: 
1.1.1.2 ! root     2472: /****************************************************************************/
        !          2473: /* Determine if the specified user can or cannot access the specified sub      */
        !          2474: /****************************************************************************/
        !          2475: BOOL DLLCALL can_user_access_sub(scfg_t* cfg, uint subnum, user_t* user, client_t* client)
        !          2476: {
        !          2477:        if(!VALID_CFG(cfg))
        !          2478:                return FALSE;
        !          2479:        if(subnum>=cfg->total_subs)
        !          2480:                return FALSE;
        !          2481:        if(!chk_ar(cfg,cfg->grp[cfg->sub[subnum]->grp]->ar,user,client))
        !          2482:                return FALSE;
        !          2483:        if(!chk_ar(cfg,cfg->sub[subnum]->ar,user,client))
        !          2484:                return FALSE;
        !          2485: 
        !          2486:        return TRUE;
        !          2487: }
        !          2488: 
        !          2489: /****************************************************************************/
        !          2490: /* Determine if the specified user can or cannot read the specified sub                */
        !          2491: /****************************************************************************/
        !          2492: BOOL DLLCALL can_user_read_sub(scfg_t* cfg, uint subnum, user_t* user, client_t* client)
        !          2493: {
        !          2494:        if(!can_user_access_sub(cfg, subnum, user, client))
        !          2495:                return FALSE;
        !          2496:        return chk_ar(cfg,cfg->sub[subnum]->read_ar,user,client);
        !          2497: }
        !          2498: 
        !          2499: /****************************************************************************/
        !          2500: /* Determine if the specified user can or cannot post on the specified sub     */
        !          2501: /* 'reason' is an (optional) pointer to a text.dat item number, indicating     */
        !          2502: /* the reason the user cannot post, when returning FALSE.                                      */
        !          2503: /****************************************************************************/
        !          2504: BOOL DLLCALL can_user_post(scfg_t* cfg, uint subnum, user_t* user, client_t* client, uint* reason)
        !          2505: {
        !          2506:        if(reason!=NULL)
        !          2507:                *reason=NoAccessSub;
        !          2508:        if(!can_user_access_sub(cfg, subnum, user, client))
        !          2509:                return FALSE;
        !          2510:        if(reason!=NULL)
        !          2511:                *reason=CantPostOnSub;
        !          2512:        if(!chk_ar(cfg,cfg->sub[subnum]->post_ar,user,client))
        !          2513:                return FALSE;
        !          2514:        if(cfg->sub[subnum]->misc&(SUB_QNET|SUB_FIDO|SUB_PNET|SUB_INET)
        !          2515:                && user->rest&FLAG('N'))                /* network restriction? */
        !          2516:                return FALSE;
        !          2517:        if(reason!=NULL)
        !          2518:                *reason=R_Post;
        !          2519:        if(user->rest&FLAG('P'))                        /* post restriction? */
        !          2520:                return FALSE;   
        !          2521:        if(reason!=NULL)
        !          2522:                *reason=TooManyPostsToday;
        !          2523:        if(user->ptoday>=cfg->level_postsperday[user->level])
        !          2524:                return FALSE;
        !          2525: 
        !          2526:        return TRUE;
        !          2527: }
        !          2528: 
        !          2529: /****************************************************************************/
        !          2530: /* Determine if the specified user is a sub-board operator                                     */
        !          2531: /****************************************************************************/
        !          2532: BOOL DLLCALL is_user_subop(scfg_t* cfg, uint subnum, user_t* user, client_t* client)
        !          2533: {
        !          2534:        if(!can_user_access_sub(cfg, subnum, user, client))
        !          2535:                return FALSE;
        !          2536:        if(user->level>=SYSOP_LEVEL)
        !          2537:                return TRUE;
        !          2538: 
        !          2539:        return cfg->sub[subnum]->op_ar[0]!=0 && chk_ar(cfg,cfg->sub[subnum]->op_ar,user,client);
        !          2540: }
        !          2541: 
        !          2542: /****************************************************************************/
        !          2543: /* Determine if downloads from the specified directory are free for the                */
        !          2544: /* specified user                                                                                                                      */
        !          2545: /****************************************************************************/
        !          2546: BOOL DLLCALL is_download_free(scfg_t* cfg, uint dirnum, user_t* user, client_t* client)
1.1       root     2547: {
                   2548:        if(!VALID_CFG(cfg))
                   2549:                return(FALSE);
                   2550:        
                   2551:        if(dirnum>=cfg->total_dirs)
                   2552:                return(FALSE);
                   2553: 
                   2554:        if(cfg->dir[dirnum]->misc&DIR_FREE)
                   2555:                return(TRUE);
                   2556: 
                   2557:        if(user==NULL)
                   2558:                return(FALSE);
                   2559: 
                   2560:        if(user->exempt&FLAG('D'))
                   2561:                return(TRUE);
                   2562: 
                   2563:        if(cfg->dir[dirnum]->ex_ar==NULL || cfg->dir[dirnum]->ex_ar[0]==0)
                   2564:                return(FALSE);
                   2565: 
1.1.1.2 ! root     2566:        return(chk_ar(cfg,cfg->dir[dirnum]->ex_ar,user,client));
1.1       root     2567: }
                   2568: 
                   2569: /****************************************************************************/
                   2570: /* Add an IP address (with comment) to the IP filter/trashcan file                     */
                   2571: /* ToDo: Move somewhere more appropriate (filter.c?)                                           */
                   2572: /****************************************************************************/
1.1.1.2 ! root     2573: BOOL DLLCALL filter_ip(scfg_t* cfg, const char* prot, const char* reason, const char* host
        !          2574:                                           ,const char* ip_addr, const char* username, const char* fname)
1.1       root     2575: {
                   2576:        char    ip_can[MAX_PATH+1];
                   2577:        char    tstr[64];
                   2578:     FILE*      fp;
                   2579:     time_t     now=time(NULL);
                   2580: 
                   2581:        if(ip_addr==NULL)
                   2582:                return(FALSE);
                   2583: 
1.1.1.2 ! root     2584:        SAFEPRINTF(ip_can,"%sip.can",cfg->text_dir);
1.1       root     2585:        if(fname==NULL)
                   2586:                fname=ip_can;
                   2587: 
1.1.1.2 ! root     2588:        if(findstr(ip_addr, fname))     /* Already filtered? */
        !          2589:                return(TRUE);
        !          2590: 
1.1       root     2591:     if((fp=fopen(fname,"a"))==NULL)
                   2592:        return(FALSE);
                   2593: 
                   2594:     fprintf(fp,"\n; %s %s by %s on %s\n"
1.1.1.2 ! root     2595:        ,prot,reason,username,timestr(cfg,now,tstr));
1.1       root     2596: 
                   2597:        if(host!=NULL)
                   2598:                fprintf(fp,"; Hostname: %s\n",host);
                   2599:                
                   2600:        fprintf(fp,"%s\n",ip_addr);
                   2601: 
                   2602:     fclose(fp);
                   2603:        return(TRUE);
                   2604: }
1.1.1.2 ! root     2605: 
        !          2606: /****************************************************************************/
        !          2607: /* Note: This function does not account for timed events!                                      */
        !          2608: /****************************************************************************/
        !          2609: time_t DLLCALL gettimeleft(scfg_t* cfg, user_t* user, time_t starttime)
        !          2610: {
        !          2611:        time_t  now;
        !          2612:     long    tleft;
        !          2613:        time_t  timeleft;
        !          2614: 
        !          2615:        now=time(NULL);
        !          2616: 
        !          2617:        if(user->exempt&FLAG('T')) {    /* Time online exemption */
        !          2618:                timeleft=cfg->level_timepercall[user->level];
        !          2619:                if(timeleft<10)             /* never get below 10 minutes for exempt users */
        !          2620:                        timeleft=10; 
        !          2621:                timeleft*=60;                           /* convert to seconds */
        !          2622:        }
        !          2623:        else {
        !          2624:                tleft=(((long)cfg->level_timeperday[user->level]-user->ttoday)
        !          2625:                        +user->textra)*60L;
        !          2626:                if(tleft<0) tleft=0;
        !          2627:                if(tleft>cfg->level_timepercall[user->level]*60)
        !          2628:                        tleft=cfg->level_timepercall[user->level]*60;
        !          2629:                tleft+=user->min*60L;
        !          2630:                tleft-=now-starttime;
        !          2631:                if(tleft>0x7fffL)
        !          2632:                        timeleft=0x7fff;
        !          2633:                else
        !          2634:                        timeleft=tleft; 
        !          2635:        }
        !          2636: 
        !          2637:        return(timeleft);
        !          2638: }
        !          2639: 
        !          2640: /*************************************************************************/
        !          2641: /* Check a supplied name/alias and see if it's valid by our standards.   */
        !          2642: /*************************************************************************/
        !          2643: BOOL DLLCALL check_name(scfg_t* cfg, const char* name)
        !          2644: {
        !          2645:        char    tmp[512];
        !          2646:        size_t  len;
        !          2647: 
        !          2648:        len=strlen(name);
        !          2649:        if(len<1)
        !          2650:                return FALSE;
        !          2651:        if (   name[0] <= ' '                   /* begins with white-space? */
        !          2652:                || name[len-1] <= ' '           /* ends with white-space */
        !          2653:                || !isalpha(name[0])
        !          2654:                || !stricmp(name,cfg->sys_id)
        !          2655:                || strchr(name,0xff)
        !          2656:                || matchuser(cfg,name,TRUE /* sysop_alias */)
        !          2657:                || trashcan(cfg,name,"name")
        !          2658:                || alias(cfg,name,tmp)!=name
        !          2659:           )
        !          2660:                return FALSE;
        !          2661:        return TRUE;
        !          2662: } 
        !          2663: 
        !          2664: /****************************************************************************/
        !          2665: /* Login attempt/hack tracking                                                                                         */
        !          2666: /****************************************************************************/
        !          2667: 
        !          2668: /****************************************************************************/
        !          2669: link_list_t* DLLCALL loginAttemptListInit(link_list_t* list)
        !          2670: {
        !          2671:        return listInit(list, LINK_LIST_MUTEX);
        !          2672: }
        !          2673: 
        !          2674: /****************************************************************************/
        !          2675: BOOL DLLCALL loginAttemptListFree(link_list_t* list)
        !          2676: {
        !          2677:        return listFree(list);
        !          2678: }
        !          2679: 
        !          2680: /****************************************************************************/
        !          2681: long DLLCALL loginAttemptListClear(link_list_t* list)
        !          2682: {      
        !          2683:        long count;
        !          2684:        
        !          2685:        listLock(list);
        !          2686:        count=listCountNodes(list);
        !          2687:        count-=listFreeNodes(list);
        !          2688:        listUnlock(list);
        !          2689:        return count;
        !          2690: }
        !          2691: 
        !          2692: /****************************************************************************/
        !          2693: static list_node_t* login_attempted(link_list_t* list, SOCKADDR_IN* addr)
        !          2694: {
        !          2695:        list_node_t*            node;
        !          2696:        login_attempt_t*        attempt;
        !          2697: 
        !          2698:        for(node=list->first; node!=NULL; node=node->next) {
        !          2699:                attempt=node->data;
        !          2700:                if(memcmp(&attempt->addr,&addr->sin_addr,sizeof(attempt->addr))==0)
        !          2701:                        break;
        !          2702:        }
        !          2703:        return node;
        !          2704: }
        !          2705: 
        !          2706: /****************************************************************************/
        !          2707: long DLLCALL loginAttempts(link_list_t* list, SOCKADDR_IN* addr)
        !          2708: {
        !          2709:        long                            count=0;
        !          2710:        list_node_t*            node;
        !          2711: 
        !          2712:        listLock(list);
        !          2713:        if((node=login_attempted(list, addr))!=NULL)
        !          2714:                count = ((login_attempt_t*)node->data)->count - ((login_attempt_t*)node->data)->dupes;
        !          2715:        listUnlock(list);
        !          2716: 
        !          2717:        return count;
        !          2718: }
        !          2719: 
        !          2720: /****************************************************************************/
        !          2721: void DLLCALL loginSuccess(link_list_t* list, SOCKADDR_IN* addr)
        !          2722: {
        !          2723:        list_node_t*            node;
        !          2724: 
        !          2725:        listLock(list);
        !          2726:        if((node=login_attempted(list, addr)) != NULL)
        !          2727:                listRemoveNode(list, node, /* freeData: */TRUE);
        !          2728:        listUnlock(list);
        !          2729: }
        !          2730: 
        !          2731: /****************************************************************************/
        !          2732: /* Returns number of *unique* login attempts (excludes consecutive dupes)      */
        !          2733: /****************************************************************************/
        !          2734: ulong DLLCALL loginFailure(link_list_t* list, SOCKADDR_IN* addr, const char* prot, const char* user, const char* pass)
        !          2735: {
        !          2736:        list_node_t*            node;
        !          2737:        login_attempt_t         first={0};
        !          2738:        login_attempt_t*        attempt=&first;
        !          2739:        ulong                           count=0;
        !          2740: 
        !          2741:        if(list==NULL)
        !          2742:                return 0;
        !          2743: 
        !          2744:        listLock(list);
        !          2745:        if((node=login_attempted(list, addr)) != NULL) {
        !          2746:                attempt=node->data;
        !          2747:                /* Don't count consecutive duplicate attempts (same name and password): */
        !          2748:                if(strcmp(attempt->user,user)==0 && (pass==NULL || strcmp(attempt->pass,pass)==0))
        !          2749:                        attempt->dupes++;
        !          2750:        }
        !          2751:        SAFECOPY(attempt->prot,prot);
        !          2752:        attempt->time=time(NULL);
        !          2753:        attempt->addr=addr->sin_addr;
        !          2754:        SAFECOPY(attempt->user, user);
        !          2755:        SAFECOPY(attempt->pass, pass);
        !          2756:        attempt->count++;
        !          2757:        count = attempt->count-attempt->dupes;
        !          2758:        if(node==NULL)
        !          2759:                listPushNodeData(list, attempt, sizeof(login_attempt_t));
        !          2760:        listUnlock(list);
        !          2761: 
        !          2762:        return count;
        !          2763: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.