/* this parses the mail file */

/*

Copyright (C) 1995 Andrew Tefft. I liked Henry Spencer's terms so:

        Permission is granted to anyone to use this software for any
        purpose on any computer system, and to redistribute it freely,
        subject to the following restrictions:

        1. The author is not responsible for the consequences of use of
                this software, no matter how awful, even if they arise
                from defects in it.

        2. The origin of this software must not be misrepresented, either
                by explicit claim or by omission.

        3. Altered versions must be plainly marked as such, and must not
                be misrepresented as being the original software.

*/

#include "mr.h"
#include "externs.h"
#include "regexp.h"

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <malloc.h>
#include <time.h>


extern time_t get_date();

#ifdef linux
extern long int timezone;
#endif

struct message *firstmsg;

void copyto();
int makehdr();
void getit();
void parse_from();
char *skip_whitespace();

void parse_file(file,buf,new) 
     char *file, *buf;
     int new;
{
  int fd;
  struct stat fileinfo;
  char *p,*x,hdr[512],subj[512],tmphdr[512],date[512];
  struct message *thismsg,*lastmsg;
  int i;

  fd=open(file,O_RDONLY);
  
  if (fd==-1) {
    printf("Error %d opening %s\n",errno,file); 
    return;
  }

  fstat(fd,&fileinfo);

  if (!S_ISREG(fileinfo.st_mode) && !S_ISLNK(fileinfo.st_mode)) {
    printf("%s is not a plain file\n",file);
    close(fd);
    return;
  }
  if (!fileinfo.st_size) {
    printf("%s is empty\n",file);
    close(fd);
    return;
  }

  buf=mmap(0,fileinfo.st_size,PROT_READ|PROT_WRITE,MAP_PRIVATE,fd,0);

  close(fd); /* apparently doesn't close it? */

  p=buf;
  
  if (new) {
    if (number) {
      for (i=0; i<mbox_number; i++) {
	free(mboxes[i]->filename);
	munmap(mboxes[i]->buf, strlen(mboxes[i]->buf));
	free(mboxes[i]);
      }
    /* also need to free up malloc'ed headers and message pointers */
      for (i=0; i<number; i++) {
	free(messages[i]->hdr);
	free(messages[i]);
      }
      number=0;
    }
    i=0;
    mbox_number = 0;
  }
  else {
    i=number;
    mbox_number++;
  }

  mboxes[mbox_number]=(struct mbox *)malloc(sizeof(struct mbox));
  if (mboxes[mbox_number] == NULL) {
    fprintf(stderr,"Error mallocing for mboxes\n");
    exit (-3);
  }
  mboxes[mbox_number]->buf = buf;
  mboxes[mbox_number]->filename = malloc(strlen(file)+1);
  strcpy(mboxes[mbox_number]->filename, file);

  if (!strncmp("From ",p,5)) {
    thismsg=(struct message *)malloc(sizeof(struct message));
    messages[i] = thismsg;
    messages[i]->mbox = mbox_number;
    thismsg->begin=p;
    thismsg->hits=0;
    thismsg->deleted = 0;
    thismsg->sequence=i;
    *subj = '\0';
    
    copyto(hdr,p+5,'\n');
#if 0
    printf("%s\n",hdr);
#endif
  }
  else {
    printf("%s not a mail file.\n",file);
    munmap(buf,strlen(buf));
    return;
  }
  
  while ((x = strchr(p,'\n')) != NULL && (number < MAXMSG)) {
      p=x+1;

/* for some reason, eliminating this section makes it
   miss some */

    if (*p != 'F' && *p != 'D' && *p != 'S') {
      continue;  /* quick */
    }

/* I don't understand why. But i need that out of there
 so that I can parse subject too! */

    if (!strncmp("From ",p,5)) {

/* first take care of previous subj+from */
      messages[i]->end=p-1;
      messages[i]->mbox = mbox_number;
      messages[i]->hdr=malloc(HDR_SUBJ + HDR_SUBSTART +1);
      messages[i]->date = makehdr(messages[i]->hdr,hdr,
				  skip_whitespace(subj),
				  skip_whitespace(date));
/*
      messages[i]->date = 11;
      strcpy(messages[i]->hdr,"fred");
*/

      thismsg=(struct message *)malloc(sizeof(struct message));
      messages[++i]=thismsg;
      thismsg->sequence=i;
      thismsg->begin=p;
      thismsg->hits=0;
      thismsg->deleted=0;
#if 0
      printf("%s\n", hdr);
#endif
      copyto(hdr,p+5,'\n');
      p += strlen(hdr);

/* now need default subject */
      *subj = '\0';
      *date = '\0';
    }
    else if (!strncmp("Subject: ",p,9) && *subj == '\0') {
      copyto(subj,p+9,'\n');
      p += strlen(subj) + 9;
    }
    else if (!strncmp("Date: ",p,6) && *date == '\0') {
      copyto(date,p+6,'\n');
      p += strlen(date) + 6;
    }
    else p++;
    }

/* fill in for last message */
  messages[i]->end=p-1;
  messages[i]->mbox = mbox_number;
  messages[i]->hdr=malloc(HDR_SUBJ + HDR_SUBSTART +1);
  messages[i]->date = makehdr(messages[i]->hdr,hdr,
			      skip_whitespace(subj),
			      skip_whitespace(date));
  
  thismsg->end=strchr(p,'\0');
  number = i+1;
}

/* copy s2 to s1 up to end of string or c (does not copy c) */

void copyto(s1,s2,c)
     char *s1,*s2,c;
{
  while (*s2 != NULL && *s2 != c) *s1++=*s2++;
  *s1='\0';
}

/* 
   hdr gets filled in (max len HDR_SUBJ+HDR_SUBSTART+1)
   from: 512 bytes max (can change)
   subj: same
   date: same
*/


/* hopefully this one will be cleaner! */

int makehdr(hdr,from,subj,date2) 
     char *hdr,*from,*subj,*date2;
{
  char ts[120],tfrom[80],tsubj[120],*date,*tdate;
  struct tm *dtime,*dtime2;
  time_t xxx;
  time_t *yyy;
  char a[1024],n[1024],d[1024]; 
  int yr;

/* dtime == today */

  xxx = time(NULL);
    dtime = localtime(&xxx);
    yr = dtime->tm_year+1900;


  parse_from(from,n,a,d);

  tdate = strrchr(d,' ');
  if (tdate != NULL)
    if (!strncmp(tdate," 199",4) || !strncmp(tdate," 198",4)) *tdate='\0';

  xxx=get_date(d,time(NULL),0);
  
  if (xxx < 0 || *d == '\0') {
    strcpy(d,date2);
    tdate = strrchr(d,' ');
    if (tdate != NULL)
      if (!strncmp(tdate," 199",4) || !strncmp(tdate," 198",4)) *tdate='\0';
    xxx = get_date(d,time(NULL),0);
  }

/* now xxx assumes this year. subtract the real years */


  if (tdate != NULL && *tdate=='\0' ) {
#if 0
    xxx -= (yr-atoi(tdate+1))*365*24*3600-5*3600; /* approximate */
#endif
    dtime = localtime(&xxx);   /* then */
    dtime->tm_year = (atoi(tdate+1)-1900);
    xxx = mktime(dtime); /* timelocal for sun */
  }


  strncpy(tsubj,subj,119);

/* now truncate to max lengths */
  if (strlen(tsubj) > HDR_SUBJ) tsubj[HDR_SUBJ]='\0';
  a[HDR_ADDR-1]='\0';
  d[HDR_SUBSTART-HDR_ADDR -2] = '\0';

strftime(d, 512, "%a %h %e %H:%M %Y",dtime);

  sprintf(hdr,HDR_FMT,a,d,tsubj);

  return (xxx > 0 ? xxx : 0);

}

char *skip_whitespace(c)
     char *c;
{
  while (isspace(*c)) c++;
  return c;
}

void parse_from(from,name,addr,date)
     char from[], name[], addr[], date[];
{
char *p;
int r1,r2,r3,r4;

/*

  r1=regexec(exp1,from);
  r2=regexec(exp2,from);
  r3=regexec(exp3,from);
  r4=regexec(exp4,from);
  
*/

  if (r3=regexec(exp3,from)) {   /* name <addr> */
#ifdef REAL_NAMES
    getit(name,exp3,1);
#endif
    getit(addr,exp3,2);
    if (r1=regexec(exp1,from)) getit(date,exp1,3);
    else date[0]='\0';
  }
  
  else if (r2=regexec(exp2,from)) { /* addr (name) date */
#ifdef REAL_NAMES
    getit(name,exp2,2);
#endif
    getit(addr,exp2,1);
    getit(date,exp2,3);
  }
  else if (r4=regexec(exp4,from)) { /* addr (name) nodate */
#ifdef REAL_NAMES
    getit(name,exp4,2); 
#endif
    getit(addr,exp4,1);
    date[0]='\0';
  }
  else { /* first word is addr, rest is date */
    name[0]='\0';
    p = strchr(from,' ');
    if (p == NULL) date[0]='\0';
    else {
      *p = '\0';
      p = skip_whitespace(p+1);
      strcpy(date,p);
      
    }
    strcpy(addr,from);
  }
    if (date[0]=='\050') date[0]='\0';
}

void getit(buf,exp,which)
     char *buf;
     struct regexp *exp;
     int which;
{
  strncpy(buf, exp->startp[which], exp->endp[which]-exp->startp[which]);
  buf[exp->endp[which]-exp->startp[which]] = '\0';
}


