/* 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 = strchr(s,'\n')) != NULLCHAR)
        *cp = '\0';
}
  
char *skipwhite(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 */
int
htype(s)
char *s;
{
    register char *p;
    register int i;
  
    p = s;
    /* check to see if there is a ':' before and white space */
    while (*p != '\0' && *p != ' ' && *p != ':')
        p++;
    if (*p != ':')
        return NOHEADER;
  
    for (i = 0; Hdrs[i] != NULLCHAR; i++) {
        if (strnicmp(Hdrs[i],s,strlen(Hdrs[i])) == 0)
            return i;
    }
    return UNKNOWN;
}
  
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;
}
  
void set_index(char *buf,struct mailindex *index) {
    char *s,*cp;
    struct cclist *cc;
    struct fwdbbs *bbs;
    struct tm t;
  
    switch(htype(buf)) {
        case APPARTO:
            if(index->to)
                break;
        /* Notice fall-through */
        case TO:
            free(index->to);
            index->to = strdup(getaddress(buf,0));
            break;
        case STATUS:
            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,0));
            break;
        case REPLYTO:
            free(index->replyto);
            index->replyto = strdup(getaddress(buf,0));
            break;
        case SUBJECT:
            free(index->subject);
            index->subject = strdup(&buf[9]);
        /* translate possible left over cr/lf's to spaces */
            cp = index->subject;
            while(*cp) {
                if(*cp == '\n' || *cp == 0xd){
                    *cp = '\0';
                    break;
                }
                cp++;
            }
            break;
        case BBSTYPE:
            index->type = buf[16];
            break;
        case MSGID:
            free(index->messageid);
            index->messageid = strdup(getaddress(buf,0));
            break;
        case XFORWARD:
            bbs = mallocw(sizeof(struct fwdbbs));
            strcpy(bbs->call,&buf[16]);
            bbs->next = index->bbslist;
            index->bbslist = bbs;
            break;
        case CC:
            s = &buf[4];
            while(*s) {
                if((cp=strchr(s,','))!=NULL){
                    *cp = '\0';
                } else
                    cp = s + strlen(s) - 1;
                while(*s == ' ' || *s == '\t')
                    s++;
                cc = mallocw(sizeof(struct cclist));
                cc->to = strdup(s);
                cc->next = index->cclist;
                index->cclist = cc;
                s = cp + 1;
            }
            break;
        case DATE:
        /* find age from ARPA style date */
            index->date = mydate(&buf[6]);
            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 header,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;
    }
    /* 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);
            header = 1;
            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);
            }
        }
        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(129)) == NULL) {
        return;
    }
    if((newpath = malloc(129)) == NULL) {
        free(wildcard);
        return;
    }
    if((fullname = malloc(129)) == NULL) {
        free(wildcard);
        free(newpath);
        return;
    }
  
    /* 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);
    free(newpath);
    free(fullname);
    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[129];
  
    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 */
  
