/* Mail Index File routines for JNOS and others.
 * (C) 1993, Johan. K. Reinalda, WG7J/PA3DIS
 * Free for non-commercial use if this notice is retained.
 *
 * You should be able to patch this into you mailer program easily.
 * There are two public functions.
 *
 * int MsgsInMbx(char *name);
 *      this routine returns the number of messages in a mailbox.
 *
 *      Calling convention:
 *      'char *name' is the name of the mailbox, in 'directory format'.
 *      this means that subdirectories should be represented by '/'
 *      characters, and not '.' or '\' . Also, the '.txt' extension
 *      should not be used !
 *
 *      Return value:
 *      It will return -1 if it detects an error in the index file.
 *      Otherwise the number of messages will be returned.
 *
 *      Use:
 *      JNOS uses it to dynamically size the structure that tracks messages.
 *
 * int IndexFile(char *name,int verbose);
 *      This routines creates an index file for the mailbox given.
 *
 *      Calling convention:
 *      'char *name'
 *      'char *name' is the name of the mailbox, in 'directory format'.
 *      this means that subdirectories should be represented by '/'
 *      characters, and not '.' or '\' . Also, the '.txt' extension
 *      should not be used ! The 'mailspool' directory will be pre-pended,
 *      and should not be included in the mailbox name. Eg. the file
 *      '/spool/mail/users/johan.txt' should be indexed as 'users/johan'
 *
 *      'int verbose'
 *      if set, the index will be printed before it is written.
 *
 *      Return values:
 *      0  if no error occured
 *      -2 if it can not open the mailbox for reading binary mode
 *      -3 if it can not open the index file for writing
 *      -10 on other errors
 *
 *      Notes:
 *      -you should make sure the mailbox file is properly locked before
 *       calling this routine.
 *
 *      -you need to provide the following variables:
 *       char *Mailspool, should be "/spool/mail"
 *       char *Arealist, should be "/spool/areas"
 *
 *      -you also need to provide a dummy function pwait() in your sources,
 *       to avoid getting an unknown function error when linking.
 *       void pwait(void *p) {};
 *       should do it...
 */
#ifdef MSDOS
#include <io.h>
#endif
#include <fcntl.h>
#include <sys/stat.h>
#include <ctype.h>
#include <time.h>
#include <string.h>
#ifdef MSDOS
#include <dir.h>
#include <dos.h>
#endif
#include "global.h"
#include "socket.h"
#include "index.h"
#include "mailutil.h"
#include "mailbox.h"
#include "smtp.h"
#include "files.h"
#include "bm.h"
  
#ifdef MAIL2IND
#undef fopen
#define tprintf printf
#define tputc putchar
#endif
  
/* return the number of messages in a given mailbox.
 * name needs to be in directory format.
 * Returns:
 * -1 if index file is corrupt,
 *  otherwize the number of messages in the mailbox
 */
int MsgsInMbx(char *name) {
    int ind;
    struct indexhdr hdr;
    char buf[FILE_PATH_SIZE];
  
    sprintf(buf,"%s/%s.ind",Mailspool,name);
    if((ind = open(buf,READBINARY)) == -1)
        return 0;
  
    /* Read the header */
    if(read_header(ind,&hdr) == -1)
        hdr.msgs = 0;
  
    close(ind);
    return hdr.msgs;
}
  
/* replace terminating end of line marker(s) with null */
void
rip(s)
register char *s;
{
    register char *cp;
  
    if((cp = strpbrk(s,"\r\n")) != NULLCHAR)	/* n5knx: was "\n" */
        *cp = '\0';
}
  
char *skipwhite(char *cp) {
  
    while((*cp != '\0') && (*cp == ' ' || *cp == '\t'))
        cp++;
    return cp;
}
  
char *skipnonwhite(char *cp) {
  
    while(*cp != '\0' && *cp != ' ' && *cp != '\t')
        cp++;
    return cp;
}
  
/* Given a string of the form <user@host>, extract the part inside the
 * angle brackets and return a pointer to it.
 */
char *
getname(cp)
char *cp;
{
    char *cp1;
  
    if ((cp = strchr(cp,'<')) == NULLCHAR)
        return NULLCHAR;
    cp++;   /* cp -> first char of name */
    cp = skipwhite(cp);
    if((cp1 = strchr(cp,'>')) == NULLCHAR)
        return NULLCHAR;
    *cp1 = '\0';
    return cp;
}
  
/* Parse a string in the "Text: Text <user@host>" or "Text: user@host (Text)"
 * formats for the address user@host.
 */
char *
getaddress(string,cont)
char *string;
int cont;       /* true if string is a continued header line */
{
    char *cp, *ap = NULLCHAR;
    int par = 0;
  
    if((cp = getname(string)) != NULLCHAR) /* Look for <> style address */
        return cp;
  
    cp = string;
    if(!cont)
        if((cp = strchr(string,':')) == NULLCHAR)   /* Skip the token */
            return NULLCHAR;
        else
            ++cp;
    for(; *cp != '\0'; ++cp) {
        if(par && *cp == ')') {
            --par;
            continue;
        }
        if(*cp == '(')      /* Ignore text within parenthesis */
            ++par;
        if(par)
            continue;
        if(*cp == ' ' || *cp == '\t' || *cp == '\n' || *cp == ',') {
            if(ap != NULLCHAR)
                break;
            continue;
        }
        if(ap == NULLCHAR)
            ap = cp;
    }
    *cp = '\0';
    return ap;
}
  
char *Months[12] = { "Jan","Feb","Mar","Apr","May","Jun",
"Jul","Aug","Sep","Oct","Nov","Dec" };
  
char *Hdrs[] = {
    "Approved: ",
    "From: ",
    "To: ",
    "Date: ",
    "Message-Id: ",
    "Subject: ",
    "Received: ",
    "Sender: ",
    "Reply-To: ",
    "Status: ",
    "X-BBS-Msg-Type: ",
    "X-Forwarded-To: ",
    "Cc: ",
    "Return-Receipt-To: ",
    "Apparently-To: ",
    "Errors-To: ",
    "Organization: ",
    "Newsgroups: ",
    "Path: ",
    "X-BBS-Hold: ",
    NULLCHAR,
};
  
  
/* return the header type, taking into account the type of the previous header */
int
htype(s, prevtype)
char *s;
int *prevtype;
{
    register char *p;
    register int i;
  
    p = s;
    /* check to see if there is a ':' before any white space */
    while (*p > ' ' && *p < '\177' && *p != ':')
        p++;
    if (*p != ':' || p==s)  { /* continuation line, or illegal syntax */
       if (*s == ' ' || *s == '\t') return (*prevtype);  /* continuation */
       *prevtype = NOHEADER;
       return NOHEADER;
    }  
    for (i = 0; Hdrs[i] != NULLCHAR; i++) {
        if (strnicmp(Hdrs[i],s,strlen(Hdrs[i])-1) == 0) /* don't require a SP after colon */
            break;
    }
    *prevtype = i;  /* == UNKNOWN if not in Hdrs[] */
    return i;
}
  
int get_index(int msg,char *name,struct mailindex *ind) {
    int idx;
    struct indexhdr hdr;
    char buf[FILE_PATH_SIZE];
  
    sprintf(buf,"%s/%s.ind",Mailspool,name);
    if((idx=open(buf,READBINARY)) == -1) {
        return -1;
    }
  
    if((read_header(idx,&hdr) == 0) && (msg <= hdr.msgs)) {
        while(msg--) {
            default_index(name,ind);
            read_index(idx,ind);
        }
        close(idx);
        return 0;
    }
    close(idx);
    return -1;
}
  
/* set_index() will parse an input SMTP-style header line and update the
   corresponding field in the mailindex.  While continued header lines are
   recognized, they aren't always processed properly, due to insufficient
   state retained between calls to set_index.  -- n5knx
*/
void set_index(char *buf,struct mailindex *index, int hdrtype) {
    int continued;
    char *s,*cp;
    struct cclist *cc;
    struct fwdbbs *bbs;
    struct tm t;
  
    rip(buf);
    continued = (*buf == ' ' || *buf == '\t');
    if (continued) buf = skipwhite(buf);
    if (*buf) switch(hdrtype) {
        case APPARTO:
            if(index->to)
                break;
        /* Notice fall-through */
        case TO:
            free(index->to);
            index->to = strdup(getaddress(buf,continued));
            break;
        case STATUS:          /* Jnos-defined */
            if(buf[8] == 'R')
                index->status |= BM_READ;
            break;
        case XBBSHOLD:
            index->status |= BM_HOLD;
            break;
        case FROM:
            free(index->from);
            index->from = strdup(getaddress(buf,continued));
            break;
        case REPLYTO:
            free(index->replyto);
            index->replyto = strdup(getaddress(buf,continued));
            break;
        case SUBJECT:
            if (continued) {
                s = mallocw(strlen(index->subject) + strlen(buf) + 2);
                strcpy(s, index->subject);
                strcat(s, " ");
                strcat(s, buf);
                free(index->subject);
                index->subject = s;
            }
            else {
                free(index->subject);
                buf = skipwhite(buf+8);
                if (*buf) index->subject = strdup(buf);
            }
            break;
        case BBSTYPE:
            index->type = buf[16];  /* Jnos-defined */
            break;
        case MSGID:
            free(index->messageid);
            index->messageid = strdup(getaddress(buf,continued));
            break;
        case XFORWARD:              /* Jnos-defined */
            bbs = mallocw(sizeof(struct fwdbbs));
            strcpy(bbs->call,&buf[16]);
            bbs->next = index->bbslist;
            index->bbslist = bbs;
            break;
        case CC:
            if (!continued) s = skipwhite(buf+3);
            else s=buf;
            while(*s) {
                if((cp=strchr(s,','))!=NULL){
                    *cp = '\0';
                } else
                    cp = s + strlen(s) - 1;
                buf=getaddress(s, 1);
                if (buf && *buf) {  /* ignore blank fields */
                    cc = mallocw(sizeof(struct cclist));
                    cc->to = strdup(buf);
                    cc->next = index->cclist;
                    index->cclist = cc;
                }
                s = cp + 1;
            }
            break;
        case DATE:
        /* find age from ARPA style date */
            if (!continued) buf = skipwhite(buf+5);
            index->date = mydate(buf);
            break;
    } /* switch */
}
  
/* Update the index file */
int WriteIndex(int idx, struct mailindex *ind) {
    long startoffset,length;
    int len, xlen;
    struct indexhdr hdr;
    struct fwdbbs *bbs;
    struct cclist *cc;
    char null = '\0';
  
    if ((startoffset = lseek(idx,0,SEEK_CUR)) == -1L) return -1;
  
    /* write length bytes */
    write(idx,&len,sizeof(len));
  
    /* write message id */
    write(idx,&ind->msgid,sizeof(ind->msgid));
    xlen = sizeof(ind->msgid);
  
    /* write message type */
    write(idx,&ind->type,sizeof(ind->type));
    xlen += sizeof(ind->type);
  
    /* write message status */
    write(idx,&ind->status,sizeof(ind->status));
    xlen += sizeof(ind->status);
  
    /* write message size */
    write(idx,&ind->size,sizeof(ind->size));
    xlen += sizeof(ind->size);
  
    /* write to-address */
    if(ind->to) {
        write(idx,ind->to,strlen(ind->to));
        xlen += strlen(ind->to);
    }
    write(idx,&null,sizeof(null));
    xlen += sizeof(null);
  
    /* write from-address */
    if(ind->from){
        write(idx,ind->from,strlen(ind->from));
        xlen += strlen(ind->from);
    }
    write(idx,&null,sizeof(null));
    xlen += sizeof(null);
  
    /* write subject field */
    if(ind->subject){
        write(idx,ind->subject,strlen(ind->subject));
        xlen += strlen(ind->subject);
    }
    write(idx,&null,sizeof(null));
    xlen += sizeof(null);
  
    /* write reply-to field */
    if(ind->replyto){
        write(idx,ind->replyto,strlen(ind->replyto));
        xlen += strlen(ind->replyto);
    }
    write(idx,&null,sizeof(null));
    xlen += sizeof(null);
  
    /* write message-id field */
    if(ind->messageid){
        write(idx,ind->messageid,strlen(ind->messageid));
        xlen += strlen(ind->messageid);
    }
    write(idx,&null,sizeof(null));
    xlen += sizeof(null);
  
    /* write received date */
    write(idx,&ind->mydate,sizeof(ind->mydate));
    xlen += sizeof(ind->mydate);
  
    /* write date */
    write(idx,&ind->date,sizeof(ind->date));
    xlen += sizeof(ind->date);
  
    /* write all Cc addressees */
    for(cc=ind->cclist;cc;cc=cc->next){
        write(idx,cc->to,strlen(cc->to)+1);
        xlen += strlen(cc->to)+1;
    }
    write(idx,&null,sizeof(null));
    xlen += sizeof(null);
  
    /* write all forwarded bbs's */
    for(bbs=ind->bbslist;bbs;bbs = bbs->next){
        write(idx,bbs->call,strlen(bbs->call)+1);
        xlen += strlen(bbs->call)+1;
    }
    /* terminate with null character */
    write(idx,&null,sizeof(null));
    xlen += sizeof(null);
  
    /* Now update the length */
    len = (int) (lseek(idx,0,SEEK_CUR) - startoffset - sizeof(len));
    lseek(idx,startoffset,SEEK_SET);    /* regain start pos */
    if (len != xlen) {        /* serious write or seek error */
        write(idx, &null, 0);    /* truncate index */
        return -1;
    }
        
    if (write(idx,&len,sizeof(len)) != sizeof(len)) return -1;
  
    /* Now update the number of records */
    if (read_header(idx,&hdr) == 0) {
        hdr.msgs++;
        if(!(ind->status & BM_HOLD+BM_READ))
            hdr.unread++;
        xlen=write_header(idx,&hdr);
    }
    else xlen = -1;
  
    /* Go to end of file again */
    lseek(idx,0,SEEK_END);
  
    return xlen;
}
  
void default_header(struct indexhdr *hdr) {
    hdr->msgs = 0;
    hdr->unread = 0;
}
  
void default_index(char *name, struct mailindex *ind) {
    struct fwdbbs *cbbs,*nbbs;
    struct cclist *cc,*ncc;
  
    ind->msgid = 0;
  
#ifdef MAILCMDS
#ifdef MAILBOX
    if(isarea(name))
        ind->type = 'B';
    else
#endif
#endif
        ind->type = 'P';
  
    ind->status = 0;
  
    ind->size = 0;
  
    free(ind->to);
    ind->to = NULL;
  
    free(ind->from);
    ind->from = NULL;
  
    free(ind->subject);
    ind->subject = NULL;
  
    free(ind->replyto);
    ind->replyto = NULL;
  
    free(ind->messageid);
    ind->messageid = NULL;
  
    ind->mydate = 0;
    ind->date = 0;
  
    for(cbbs = ind->bbslist;cbbs;cbbs = nbbs) {
        nbbs = cbbs->next;
        free(cbbs);
    }
    ind->bbslist = NULL;
  
    for(cc = ind->cclist;cc;cc = ncc) {
        ncc = cc->next;
        free(cc->to);
        free(cc);
    }
    ind->cclist = NULL;
  
}
  
long mydate(char *s) {
    struct tm t;
    char *cp;
  
    while(*s == ' ')
        s++;
    /* check to see if there is a "Day, " field */
    if((cp=strchr(s,',')) != NULL)  {
        /* probably standard ARPA style header */
        cp += 2; /* get past header and DAY field */
    } else {
        /* probably a NNTP style message, that has no
         * "Day, " part in the date line
         */
        cp = s;
    }
  
    while(*cp == ' ')
        cp++;
    /* now we should be at the start of the
     * "14 Apr 92 08:14:32" string
     */
    if(strlen(cp) < 17)
        return 0;
    t.tm_mday = atoi(cp);
    /* Find month */
    while(*cp != ' ')
        ++cp;
    while(*cp == ' ')
        ++cp;
    for(t.tm_mon=0; t.tm_mon < 12; t.tm_mon++)
        if(strnicmp(Months[t.tm_mon],cp,3) == 0)
            break;
    if(t.tm_mon == 12)
        return 0; /* invalid */
    t.tm_year = atoi(cp+4);
    /* Modification by VE4WTS for 4-character year string */
    if(t.tm_year>100) {
        t.tm_year=t.tm_year%100;
        t.tm_hour=atoi(cp+9);
        t.tm_min=atoi(cp+12);
        t.tm_sec=atoi(cp+15);
    } else {
        t.tm_hour = atoi(cp+7);
        t.tm_min = atoi(cp+10);
        t.tm_sec = atoi(cp+13);
    }
    /*
    tprintf("DATE: %d %d %d, %d %d %d\n",
            t.tm_mday,t.tm_mon,t.tm_year,t.tm_hour,t.tm_min,t.tm_sec);
    */
    return mktime(&t);
  
}
  
/* Read a file containing messages,
 * and build the index file from scratch from the smtp headers.
 * Parameters:
 *    char *name should be the full area filename in dir format,
 *       without ending '.txt' ! Eg: '/spool/mail/johan'
 *    int verbose ; if set, the index is printed before written
 */
int IndexFile(char *name,int verbose) {
    FILE *fp;
    int ptype=NOHEADER, previous;
    long start,pos;
    char *cp;
    int idx;
    struct indexhdr hdr;
    struct mailindex ind;
    char buf[FILE_PATH_SIZE];
  
    sprintf(buf,"%s/%s.txt",Mailspool,name);
    if((fp = fopen(buf,READ_BINARY)) == NULL)
        return NOMBX;
  
    /* Create new index file */
    sprintf(buf,"%s/%s.ind",Mailspool,name);
    if((idx = open(buf,CREATETRUNCATEBINARY,CREATEMODE)) == -1) {
        fclose(fp);
        return NOIND;
    }

    setvbuf(fp, NULLCHAR, _IOFBF, 2048);       /* N5KNX: use bigger input buffer if possible */

    /* set number of msgs to 0 */
    default_header(&hdr);
    if (write_header(idx,&hdr) == -1) return ERROR;
  
    start = pos = 0;
    previous = 0;
    memset(&ind,0,sizeof(ind));
    default_index(name,&ind);
  
    while(bgets(buf, sizeof(buf), fp) != NULL) {
        pwait(NULL);    /* Be nice to others :-) */
        /* search 'From ' line */
        if(!strncmp(buf,"From ",5)) {
            /* Start of next message */
            if(previous) {
                /* Write index for previous message */
                ind.size = pos - start;
                if(verbose)
                    print_index(&ind);
                if(WriteIndex(idx,&ind) == -1) {
                    default_index("",&ind);
                    fclose(fp);
                    close(idx);
                    return ERROR;
                }
            } else
                previous = 1;
  
            /* Clear the index for this message */
            default_index(name,&ind);
            start = pos;
  
            /* Read the 'Received...' and 'ID... lines'
             * to get the msgid - WG7J
             */
            if(bgets(buf, sizeof(buf), fp) == NULL) {   /* "Received " line */
                default_index("",&ind);
                fclose(fp);
                close(idx);
                return ERROR;
            }
            if(bgets(buf, sizeof(buf), fp) == NULL) {   /* 'id' line */
                default_index("",&ind);
                fclose(fp);
                close(idx);
                return ERROR;
            }
            if((cp=strstr(buf,"AA")) != NULL)
                /* what follows is the message-number */
                ind.msgid = atol(cp+2);
            if((cp=strchr(buf,';')) != NULL)
                ind.mydate = mydate(cp+2);
            pos = ftell(fp);
            /* While in the SMTP header, set index fields */
            while(bgets(buf,sizeof(buf),fp) != NULLCHAR ) {
                if(*buf == '\0')
                    break;
                set_index(buf,&ind,htype(buf, &ptype));
            }
        }
        pos = ftell(fp);
    }
    if(ferror(fp)) {
        default_index("",&ind);
        fclose(fp);
        close(idx);
        return ERROR;
    }
    if(previous) {
        ind.size = pos - start;
        if(verbose)
            print_index(&ind);
        if(WriteIndex(idx,&ind) == -1) {/* Write index for previous message */
            default_index("",&ind);
            fclose(fp);
            close(idx);
            return ERROR;
        }
    }
    default_index("",&ind);
    fclose(fp);
    close(idx);
    return 0;
}
  
/* Update the index file */
int write_index(char *name, struct mailindex *ind) {
    int idx, err;
    struct indexhdr hdr;
    char buf[FILE_PATH_SIZE];
  
    sprintf(buf,"%s/%s.ind",Mailspool,name);
    if((idx=open(buf,READWRITEBINARY)) == -1) {
        /* Index file doesn't exist, create it */
        if((idx=open(buf,CREATETRUNCATEBINARY,CREATEMODE)) != -1){
            default_header(&hdr);
            if (write_header(idx,&hdr) == -1) return -1;
        } else
            return -1;
    }
    lseek(idx,0,SEEK_END);
    err=WriteIndex(idx,ind);
    close(idx);
    return err;
}
  
void delete_index(char *filename) {
    char idxfile[FILE_PATH_SIZE];
  
    sprintf(idxfile,"%s/%s.ind",Mailspool,filename);
    unlink(idxfile);
}
  
int write_header(int idx,struct indexhdr *hdr) {
  
    lseek(idx,0,SEEK_SET);
    hdr->version = INDEXVERSION;
    return (write(idx,hdr,sizeof(struct indexhdr)) == sizeof(struct indexhdr) ? 0 : -1);
}
  
int read_header(int idx,struct indexhdr *hdr) {
    int val;
  
    lseek(idx,0,SEEK_SET);
    val = read(idx,hdr,sizeof(struct indexhdr));
    if(val != sizeof(struct indexhdr) || hdr->version != INDEXVERSION)
        return -1;
    return 0;
}
  
/* Read an index from the index file. Assumes the file is opened
 * for binary reads, and that the filepointer is pointing to the
 * start of the message to read...
 * Returns 0 if valid, -1 if error
 */
int read_index(int idx,struct mailindex *ind) {
    int len;
    char *buf,*curr;
    struct cclist *newcc;
    struct fwdbbs *newbbs;
  
    /* Get the size of this index */
    if(read(idx,&len,sizeof(len)) != sizeof(len))
        return -1;
  
    /* Now read the index */
    if((buf = mallocw(len)) == NULL)
        return -1;
  
    if(read(idx,buf,len) != len) {
        free(buf);
        return -1;
    }
  
    /* And copy all elements to the index */
    curr = buf;
  
    /* Get the message id */
    ind->msgid = *(long *)curr;
    curr += sizeof(ind->msgid);
  
    ind->type = *curr++;
    ind->status = *curr++;
  
    ind->size = *(long*)curr;
    curr += sizeof(ind->size);
  
    ind->to = strdup(curr);
    curr += strlen(curr) + 1;
  
    ind->from = strdup(curr);
    curr += strlen(curr) + 1;
  
    ind->subject = strdup(curr);
    curr += strlen(curr) + 1;
  
    ind->replyto = strdup(curr);
    curr += strlen(curr) + 1;
  
    ind->messageid = strdup(curr);
    curr += strlen(curr) + 1;
  
    ind->mydate = *(long *)curr;
    curr += sizeof(ind->mydate);
  
    ind->date = *(long *)curr;
    curr += sizeof(ind->date);
  
    while(*curr) {
        newcc = mallocw(sizeof(struct cclist));
        newcc->to = strdup(curr);
        newcc->next = ind->cclist;
        ind->cclist = newcc;
        curr += strlen(curr) + 1;
    }
    curr++;
  
    while(*curr) {
        newbbs = mallocw(sizeof(struct fwdbbs));
        strcpy(newbbs->call,curr);
        newbbs->next = ind->bbslist;
        ind->bbslist = newbbs;
        curr += strlen(curr) + 1;
    }
  
    free(buf);
    return 0;
  
};
  
void print_index(struct mailindex *ind) {
    struct fwdbbs *bbs;
    struct cclist *cc;
  
    tprintf("\nSize %ld, ID %ld, flags: %c%c%c\n",ind->size,ind->msgid,ind->type,
    ind->status & BM_READ ? 'R' : 'N',ind->status & BM_HOLD ? 'H' : ' ');
    tprintf("To: %s\n",ind->to);
    tprintf("Cc:");
    for(cc=ind->cclist;cc;cc=cc->next)
        tprintf(" %s",cc->to);
    tputc('\n');
    tprintf("From: %s\n",ind->from);
    tprintf("Received: %s",ctime(&ind->mydate));
    tprintf("Reply-to: %s\n",ind->replyto ? ind->replyto : "");
    tprintf("Subject: %s\n",ind->subject);
    tprintf("Message-Id: %s\n",ind->messageid);
    tprintf("Date: %s",ctime(&ind->date));
    tprintf("X-Forwarded-To:");
    for(bbs=ind->bbslist;bbs;bbs=bbs->next)
        tprintf(" %s",bbs->call);
    tputc('\n');
    tputc('\n');
}
  
  
void dotformat(char *area) {
  
    while(*area) {
        if(*area == '\\' || *area == '/')
            *area = '.';
        area++;
    }
}
  
void dirformat(char *area) {
  
    while(*area) {
        if(*area == '\\' || *area == '.')
            *area = '/';
        area++;
    }
}
  
void firsttoken(char *line) {
  
    while(*line) {
        if(*line == ' ' || *line == '\n' || *line == '\t') {
            *line = '\0';
            break;
        }
        line++;
    }
}
  
/* Returns 1 if name is a public message Area, 0 otherwise */
int
isarea(name)
char *name;
{
    FILE *fp;
    char *cp, *area;
    char buf[LINELEN];
  
    if((fp = fopen(Arealist,READ_TEXT)) == NULLFILE)
        return 0;
    area = strdup(name);
    dotformat(area);
    while(fgets(buf,sizeof(buf),fp) != NULLCHAR) {
        /* The first word on each line is all that matters */
        firsttoken(buf);
        dotformat(buf);
        if(stricmp(area,buf) == 0) {    /* found it */
            fclose(fp);
            free(area);
            return 1;
        }
    }
    fclose(fp);
    free(area);
    return 0;
}
  
/* Get a line from the text file that was opened in binary mode.
 * Delete the CR/LF at the end !
 */
char *bgets(char * buf,int size,FILE *fp) {
    char *cp;
  
    if(fgets(buf,size,fp) == NULL)
        return NULL;
    cp = buf;
    while(*cp) {
        if(*cp == 0xd || *cp == 0xa)
            *cp = '\0';
        cp++;
    }
    return buf;
}
  
#ifdef notdef
void readareas __ARGS((char *name,char *mpath));
int is_area __ARGS((char *name));
int isarea;
  
struct areas {
    struct areas *next;
    char *name;
};
struct areas *Areas = NULL;
  
void readareas(char *name,char *mpath) {
    FILE *fp;
    struct areas *ca,*na;
    char *cp,mp[FILE_PATH_SIZE],buf[FILE_PATH_SIZE];
  
    if((fp=fopen(name,READ_TEXT)) == NULL)
        return;
  
    while(fgets(buf,sizeof(buf),fp) != NULL) {
        if(buf[0] == '#')   /* comment line */
            continue;
        cp = buf;
        /* get first token on line */
        while(*cp) {
            if(*cp == '\n' || *cp == ' ' || *cp == '\t') {
                *cp = '\0';
                break;
            }
            cp++;
        }
        if(buf[0] != '\0') {
            cp = buf;
            while(*cp) {
                if(*cp == '.' || *cp == '\\')
                    *cp = '/';
                cp++;
            }
            sprintf(mp,"%s/%s.txt",mpath,buf);
            na = malloc(sizeof(struct areas));
            na->name = strdup(mp);
            na->next = NULL;
            if(Areas == NULL) {
                Areas = na;
            } else {
                ca->next = na;
            }
            ca = na;
        }
    }
    fclose(fp);
}
  
int is_area(char *name) {
    struct areas *a;
  
    a = Areas;
    while(a) {
        if(stricmp(a->name,name) == 0)
            return 1;
        a = a->next;
    }
    return 0;
}
  
void showareas() {
    struct areas *a;
  
    a = Areas;
    while(a) {
        tprintf("%s\n",a->name);
        a = a->next;
    }
}
#endif
  
#ifndef MAIL2IND
  
void UpdateIndex(char *path,int force) {
    char *wildcard,*newpath,*fullname;
    struct ffblk ff,iff;
    int done;
  
    if((wildcard = malloc(3*FILE_PATH_SIZE)) == NULL) {
        return;
    }
    newpath = wildcard+FILE_PATH_SIZE;
    fullname = newpath+FILE_PATH_SIZE;
  
    /* First check all the files */
    if(!path)
        sprintf(wildcard,"%s/*.txt",Mailspool);
    else
        sprintf(wildcard,"%s/%s/*.txt",Mailspool,path);
    done = findfirst(wildcard,&ff,0);
    while(!done){
        if(!path)
            strcpy(fullname,ff.ff_name);
        else
            sprintf(fullname,"%s/%s",path,ff.ff_name);
  
        /* get rid of extension */
        *(fullname+strlen(fullname)-4) = '\0';
        if(force) {
            /* Attempt to lock the mail file! */
            if(!mlock(Mailspool,fullname)) {
                IndexFile(fullname,0);
                rmlock(Mailspool,fullname);
            }
        } else {
            /* Now find the index file */
            sprintf(wildcard,"%s/%s",Mailspool,fullname);
            strcat(wildcard,".ind");
            /* If there is no index, or the index is older then the text file.
             * Go create a new index file !
             */
            if( findfirst(wildcard,&iff,0) != 0 ||
                (ff.ff_fdate > iff.ff_fdate) ||
                ((ff.ff_fdate == iff.ff_fdate) && ff.ff_ftime > iff.ff_ftime)
            ) {
                /* Attempt to lock the mail file! */
                if(!mlock(Mailspool,fullname)) {
                    IndexFile(fullname,0);
                    rmlock(Mailspool,fullname);
                }
            }
        }
        done = findnext(&ff);
    }
    /* Now check for sub-directories */
    if(!path)
        sprintf(wildcard,"%s/*.*",Mailspool);
    else
        sprintf(wildcard,"%s/%s/*.*",Mailspool,path);
    done = findfirst(wildcard,&ff,FA_DIREC);
    while(!done){
        if(strcmp(ff.ff_name,".") && strcmp(ff.ff_name,"..")) {
            /* Not the present or 'mother' directory, so create new path,
             * and recurs into it.
             */
            if(!path)
                strcpy(newpath,ff.ff_name);
            else
                sprintf(newpath,"%s/%s",path,ff.ff_name);
            UpdateIndex(newpath,force);
        }
        done = findnext(&ff);
    }
    free(wildcard);
    return;
}
  
/* Make sure the index file associated with the mailbox 'name' is current.
 * The mailbox should be locked before calling SyncIndex.
 * Parameters:
 *    char *name should be the area filename, without ending '.txt' !
 *   Eg: 'johan'
 * Returns:
 *  NOERROR (== 0) if index was current, or has been made current.
 *  others if unable to update the index file.
 */
int SyncIndex(char *name)
{
    int mail,ind;
    struct ffblk mff,iff;
    char *area;
    char buf[FILE_PATH_SIZE];
  
    area = strdup(name);    /* ensure mbox name is in dir format */
    dirformat(area);
  
    /* Check the index file */
    sprintf(buf,"%s/%s.txt",Mailspool,area);
    mail = findfirst(buf,&mff,0);
  
    sprintf(buf,"%s/%s.ind",Mailspool,area);
    ind = findfirst(buf,&iff,0);
  
    if(mail != 0 && ind == 0) {
        ind=unlink(buf);    /* remove index file if mbox nonexistent */
    }
    else if((mail == 0 && ind != 0) ||
        (mff.ff_fdate > iff.ff_fdate) ||
        ((mff.ff_fdate == iff.ff_fdate) && mff.ff_ftime > iff.ff_ftime)
    ) {
        ind=IndexFile(area,0);
    }
    else ind=NOERROR;
  
    free(area);
    return(ind);
}
  
#endif /* MAIL2IND */
  
