#include "bbs.h"
#include "io.h"

#include <fcntl.h>
#include <sys/types.h>
#include <sys/file.h>
#ifndef XINU
#include <sys/stat.h>
#endif

extern char saveboard[STRLEN] ;
extern int mot ;

struct fileheader fh ;

read_boards(fptr,mode)
struct fileheader *fptr ;
int mode ;
{
    register int i, offset ;
    register long numfiles ;
    int fd ;
    unsigned char ch ;
    struct stat st ;
    
    if(mode&FILE_READ)
      return 0 ;  /* Board has been zapped from New List */
    offset =  ((int)&(fh.accessed[usernum%MAXUSERS]) - (int)&(fh)) ;
    sprintf(genbuf,"boards/%s/%s",fptr->filename,DIR) ;
    if((fd = open(genbuf, O_RDWR)) < 0)
      return 0 ;
    fstat(fd,&st) ;
    numfiles = st.st_size ;
    numfiles = numfiles/sizeof(fh) ;
    if(numfiles <= 0) {
        close(fd) ;
        return 0 ;
    }
    lseek(fd,offset,L_SET) ;
    for(i = 0 ; i < numfiles ; i++,lseek(fd,offset+i*sizeof(fh),L_SET)) {
        read(fd,&ch,1) ;
        if(!(ch & SHIFTMODE(usernum,FILE_READ))) {
            mot = 1 ;
            lseek(fd,i*sizeof(fh),L_SET) ;
            read(fd,&fh,((int)&(fh.accessed[0])-(int)&(fh))) ;
            clear() ;
            prints("Read Message on board '%s' entitled:\n\"%s\"\n",
                   fptr->filename,fh.title) ;
            prints("Posted by: %s.\n",fh.owner) ;
            getdata(3,0,"(Yes or No or Quit or SkipBoard): ",
                    genbuf,12,DOECHO,NULL) ;
            if(genbuf[0] != 'y' && genbuf[0] != 'Y' && genbuf[0] != '\0') {
                if(genbuf[0] == 'q' || genbuf[0] == 'Q') {
                    move(3,0) ;
                    clrtoeol() ;
                    refresh() ;
                    close(fd) ;
                    return QUIT ;
                }
                if(genbuf[0] == 's' || genbuf[0] == 'S') {
                    move(3,0) ;
                    clrtoeol() ;
                    refresh() ;
                    close(fd) ;
                    return 0 ;
                }
                continue ;
            }
            sprintf(genbuf,"boards/%s/%s",fptr->filename,fh.filename) ;
            more(genbuf,YEA) ;
            clear() ;
            lseek(fd,offset+i*sizeof(fh),L_SET) ;
            ch |= SHIFTMODE(usernum,FILE_READ) ;
            ch &= ~SHIFTMODE(usernum,FILE_VISIT) ;
            write(fd,&ch,1) ;
        }
    }
    close(fd) ;
    return 0 ;
}

New()
{
    extern struct user_info uinfo ;

    report("New") ;
    clear() ;
    mot = 0 ;

    uinfo.mode = READNEW ;
    substitute_record(ULIST,(void *)&uinfo,sizeof(uinfo),utmpent) ;
    apply_boards(read_boards);
    clear() ;
    uinfo.mode = IDLE ;
    substitute_record(ULIST,(void *)&uinfo,sizeof(uinfo),utmpent) ;
    if(mot)
      prints("No more messages\n\n\n") ;
    else
      prints("No new messages\n\n\n") ;
    pressreturn() ;
    clear() ;
    return -1 ;
}

visit_boards(fptr,mode)
struct fileheader *fptr ;
int mode ;
{
    register int i, offset ;
    register long numfiles ;
    int fd ;
    unsigned char ch ;
    struct stat st ;
    
    if(mode&FILE_READ)
      return 0 ; /* board has been zapped */
    offset = ((int)&(fh.accessed[usernum%MAXUSERS]) - (int)&(fh)) ;
    sprintf(genbuf,"boards/%s/%s",fptr->filename,DIR) ;
    if((fd = open(genbuf, O_RDWR)) < 0)
      return 0 ;
    fstat(fd,&st) ;
    numfiles = st.st_size ;
    numfiles = numfiles/sizeof(fh) ;
    if(numfiles <= 0) {
        close(fd) ;
        return 0 ;
    }
    lseek(fd,offset,L_SET) ;
    for(i = 0 ; i < numfiles ; i++,lseek(fd,offset+i*sizeof(fh),L_SET)) {
        read(fd,&ch,1) ;
        if(!(ch & SHIFTMODE(usernum,FILE_READ))) {
            lseek(fd,offset+i*sizeof(fh),L_SET) ;
            ch |= SHIFTMODE(usernum,FILE_READ) ;
            ch |= SHIFTMODE(usernum,FILE_VISIT) ;
            write(fd,&ch,1) ;
        }
    }
    close(fd) ;
    prints(".") ;
    refresh() ;
    return 0 ;
}


Visit()
{
    report("Visit") ;
    clear() ;
    refresh() ;
    apply_boards(visit_boards) ;
    pressreturn() ;
    clear() ;
    return -1 ;
}

chkmail()
{
    static long lasttime = 0;
    static ismail = 0 ;
    struct stat st ;
    int fd ;
    register int i, offset ;
    register long numfiles ;
    unsigned char ch ;
    extern char currmaildir[4096] ;

    offset = ((int)&(fh.accessed[0]) - (int)&(fh)) ;
    if((fd = open(currmaildir,O_RDONLY)) < 0)
      return (ismail = 0) ;
    fstat(fd,&st) ;
    if(lasttime >= st.st_mtime) {
        close(fd) ;
        return ismail ;
    }
    lasttime = st.st_mtime ;
    numfiles = st.st_size ;
    numfiles = numfiles/sizeof(fh) ;
    if(numfiles <= 0) {
      close(fd) ;
      return (ismail = 0) ;
    }
    lseek(fd,offset,L_SET) ;
    for(i = 0 ; i < numfiles ; i++,lseek(fd,offset+i*sizeof(fh),L_SET)) {
        read(fd,&ch,1) ;
        if(!ch) {
            close(fd) ;
            return(ismail = 1) ;
        }
    }
    close(fd) ;
    return(ismail = 0) ;
}

int
getnewuserid()
{
    int fd ;
    int i ;
    struct user utmp ;

    if((fd = open(PASSFILE,O_RDWR|O_CREAT,0600)) == -1) {
        perror("open") ;
        return -1 ;
    }
    fcntl(fd,F_WRLCK) ;
    i = 0 ;
    while(read(fd,&utmp,sizeof(utmp)) == sizeof(utmp)) {
        if(utmp.userid[0] == '\0')
            break ;
        i++ ;
    }
    if(i >= MAXUSERS*2)
      return -1 ;
    strcpy(utmp.userid,"new") ;
    if(lseek(fd,sizeof(utmp)*i,L_SET) == -1) {
        fcntl(fd,F_UNLCK) ;
        close(fd) ;
        return -1 ;
    }
    write(fd,&utmp,sizeof(utmp)) ;
    fcntl(fd,F_UNLCK) ;
    close(fd) ;
    return i+1 ;
}

int
getnewutmpent(up)
struct user_info *up ;
{
    int fd ;
    int i ;
    struct user_info utmp ;

    if((fd = open(ULIST,O_RDWR|O_CREAT,0600)) == -1) {
        perror("open") ;
        return -1 ;
    }
    fcntl(fd,F_WRLCK) ;
    i = 0 ;
    while(read(fd,&utmp,sizeof(utmp)) == sizeof(utmp)) {
        if(!utmp.active || !utmp.pid)
          break ;
        if(kill(utmp.pid,0) == -1)
          break ;
        i++ ;
    }
    if(lseek(fd,sizeof(utmp)*i,L_SET) == -1) {
        fcntl(fd,F_UNLCK) ;
        close(fd) ;
        return -1 ;
    }
    write(fd,up,sizeof(utmp)) ;
    fcntl(fd,F_UNLCK) ;
    close(fd) ;
    return i+1 ;
}


unsigned char uarray[MAXUSERS*2] ;

genuarray(s)
char *s ;
{
    int id ;

    if(*s == '*')
      return 0 ;
    if(!(id = searchuser(s)))
      return 0 ;
    uarray[id] = 1 ;
    return 0 ;
}

mass_delete(fptr,mode)
struct fileheader *fptr ;
int mode ;
{
    register int i,j, offset ;
    register long numfiles ;
    int fd ;
    unsigned char ch ;
    struct stat st ;

    offset = ((int)&(fh.accessed[usernum%MAXUSERS]) - (int)&(fh)) ;
    sprintf(genbuf,"boards/%s/%s",fptr->filename,DIR) ;
    if((fd = open(genbuf, O_RDWR)) < 0)
      return 0 ;
    fstat(fd,&st) ;
    numfiles = st.st_size ;
    numfiles = numfiles/sizeof(fh) ;
    if(numfiles <= 0) {
        close(fd) ;
        return 0 ;
    }
    ch = 0 ;
    for(i=0; i < numfiles; i++) {
        for(j=0; j<MAXUSERS*2; j++) {
            if(uarray[j]) {
                offset = ((int)&(fh.accessed[j%MAXUSERS]) - (int)&(fh)) ;
                lseek(fd,offset+i*sizeof(fh),L_SET) ;
                read(fd,&ch,1) ;
                lseek(fd,offset+i*sizeof(fh),L_SET) ;
                ch &= ~SHIFTMODE(j,0xf) ;
                write(fd,&ch,1) ;
            }
        }
    }
    close(fd) ;
    return 0 ;
}

mass_delmail(s)
char *s ;
{
    struct stat st ;
    
    if(*s == '*')
      return 0 ;
    if(*s == '\0')
      return 0 ;
    sprintf(genbuf,"mail/%s",s) ;
    if(stat(genbuf,&st) < 0)
      return 0 ;
    sprintf(genbuf,"rm -fr mail/%s",s) ;
    do_exec(genbuf,NULL) ;

    return 0 ;
}
    
mass_delusers(s)
char *s ;
{
    int id ;

    if(*s == '*')
      return 0 ;
    if(!(id = searchuser(s)))
      return 0 ;
    substitute_record(PASSFILE,&lookupuser,sizeof(lookupuser),id) ;
    return 0 ;
}

newclean(s,id)
char *s ;
{
    if(strcmp(s,"new"))
      return 0 ;
    substitute_record(PASSFILE,&lookupuser,sizeof(lookupuser),id) ;
    return 0 ;
}


fastdelete()
{
    bzero(uarray,sizeof(uarray)) ;
    ApplyToNameList(genuarray) ;
    prints("Begin Delete...\n") ;
    refresh() ;
    apply_boards(mass_delete) ;
    clear_board_zaps() ;
    prints("Users files Info Deleted....\n") ;
    refresh() ;
    ApplyToNameList(mass_delmail) ;
    prints("Mail Queues Cleaned....\n") ;
    refresh() ;
    bzero(&lookupuser,sizeof(lookupuser)) ;
    ApplyToNameList(mass_delusers) ;
    prints("Users Cleaned....\n") ;
    refresh() ;
    apply_users(newclean) ;
    truncate(PASSFILE,MAXUSERS*2*sizeof(lookupuser)) ;
    prints("Mass delete complete.\n") ;
    refresh() ;
    touchnew() ;
}
