
/*
 *	SMAILCHK.C
 *
 *	DNET (c)Copyright 1988, Matthew Dillon, All Rights Reserved
 *
 *	Check the mailbox and reports if new mail
 *	has arrived.  Connects to the Mailchk client on the Amiga.
 *	Accepts only one connection.
 *
 *	Written by S. Laroche.
 */

#include <stdio.h>
#include <sys/time.h>
#include <sys/file.h>
#include <errno.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <strings.h>
#include <sys/param.h>	  /* for definition of MAXPATHLEN */

#include "servers.h"

#define BUFLENGTH		512L  /* Should be the same as the */
#define MAILDIR   "/usr/spool/mail/"  /*  def. in mailchk.c on the Amiga */

extern int errno;
extern char *getenv();

void do_mailchk();
char delmailmsg();
char copyfiles();
char sendmail();

long numsecs;
char firstrun;
int fd;

main(ac,av)
char *av[];
{
    long chann = DListen(PORT_MAILCHK);
    char result;

    if (av[1])
	chdir(av[1]);
    signal(SIGALRM, do_mailchk);
    for (;;) {
	fd = DAccept(chann);
	if (fd < 0) {
	    if (errno == EINTR)
		continue;
	    break;
	}
	getmailpath();
	while (ggread(fd,&result,1) == 1) {
          alarm(0); 
	  Whatdoyouwant(fd,result);
          if (result > 1) do_mailchk(); 
          else alarm(numsecs);
	}
	close(fd);
	_exit(1);
    }
    perror("SMAILCHK");
}

char buf[BUFLENGTH], mname[MAXPATHLEN];

getmailpath()

{
    char *buffer;

    if ((buffer = getenv("MAIL")) == NULL) {
       strcpy(mname,MAILDIR);
    }
    else {
       strcpy(mname,buffer);
       strcat(mname,"/");
    }
    strncat(mname, getenv("USER"), MAXPATHLEN - strlen(mname));
}

Whatdoyouwant(fd,result)

int fd;
char result;

/*  This function interprets requests from the Amiga client.
    0 -> Do nothing
    1 -> Send the headers of each letter.
    2 -> Send a particular message.
    3 -> Delete a particular message.
    4 -> Initial handshake.
    5 -> Send mail using "mail".
*/

{
    char *buffer;
    unsigned char dummy;
    int temp;
    FILE *fi;

    switch(result) {
	case 1 :
	  if (fi = fopen(mname, "r")) {
	      do {
		temp = produceheader(fi,buf);
		if (temp < 0) dummy = strlen(buf);
		else if (temp == 0) break;
		     else dummy = temp;
		gwrite(fd,&dummy,1);
		gwrite(fd,buf,dummy);
	      } while (temp > 0);
	  }
	  else {
	    perror("SMAILCHK, error opening mailbox");
	    exit(0);
	  }
	  fclose(fi);
	  dummy = 0;
	  gwrite(fd,&dummy,1);
	  break;
	case 2 :
	  buffer = (char *) malloc(BUFLENGTH);
	  if (buffer == NULL) {
	      fprintf(stderr,"SMAILCHK:  error allocating memory\n");
	  }
	  else {
	      sendmailmsg(fd,mname,buffer);
	      free(buffer);
	  }
	  break;
	case 3 :
	  { char ok;

	  ok = delmailmsg(fd,mname);
	  gwrite(fd,&ok,1);
	  }
	  break;
	case 4 :
	  if ((ggread(fd,&numsecs,4)  == 4) &&
	      (ggread(fd,&firstrun,1) == 1)) {
               fprintf(stderr,"SMAILCHK, frequency = %ld seconds\n",numsecs);
               break;
          }
	  else { close(fd); _exit(1); }
        case 5 :
          { char ok = 0, *address;

	    buffer = (char *) malloc(BUFLENGTH);
	    address = (char *) malloc(BUFLENGTH);
	    if ((buffer == NULL) || (address == NULL)) {
	        fprintf(stderr,"SMAILCHK:  error allocating memory\n");
	    }
            else {
                if (ok = sendmail(fd,address,buffer)) {
                    sprintf(buf,"mail %s < %s",address,buffer);
                    ok = system(buf) >> 8;
                    unlink(buffer);
                    if (ok == 0) ok = 1;
                    else ok = 0; 
                }
                free(buffer);
                free(address);
	    }
            gwrite(fd,&ok,1);
            break;
          }
    }
}

void do_mailchk()

{
    char dummy, *s_mtime;
    struct stat tempbuf;
    static char nomail = 1;
    static long lasttime = 0;

    alarm(numsecs);
    strcpy(buf,"=");
    if (stat(mname,&tempbuf) == -1 || tempbuf.st_size == 0) {
	if (errno == ENOENT || tempbuf.st_size == 0) { 
            if (nomail) {
		strcpy(buf,"No mail.");
		nomail = 0;
            }
	}
	else perror("SMAILCHK, Unable to examine file");
    }
    else {
        if (tempbuf.st_mtime > lasttime) {
	    if (tempbuf.st_mtime >= tempbuf.st_atime) {
	         s_mtime = ctime(&tempbuf.st_mtime);
	         strcpy(buf,"New mail arrived on ");
	         strcat(buf,s_mtime);
	         nomail = 1;
	    }
	    else if (firstrun > 0) strcpy(buf,"You have mail\n");
            lasttime = tempbuf.st_mtime;
        }
    }
    dummy = strlen(buf);
    if (dummy > 2) {
	gwrite(fd, &dummy, 1);
	gwrite(fd, buf, dummy);
    }
    firstrun = 1;
}

int produceheader(fi,buf)

/* Produce a header of the form 'N sender, date, subject L/C S'
 * where N = number of the message
 *       L = number of lines in message
 *       C = number of characters in message
 *       S = number of characters in message without header
 * 
 * The function returns the # of chars in the header.  When the last
 * header is encountered, the fn returns -(# of chars).
 */

FILE *fi;
char *buf;

{
    static int mcnt = -1;
    static char from = 1, subject = 1, Date = 1;
    static unsigned long llines = 0, lch = 0, sch2, sch1;
    unsigned long lines, ch;
    char line[256], fl, *cp;
    static char date[60], olddate[60], path[80], oldpath[80];
    static char sub[80], oldsub[80];

    lines = llines;
    ch = lch;
    while (cp = fgets(line, 256, fi)) {
      lines++;
      ch += strlen(line);
      llines++;
      lch += strlen(line);
      cp[strlen(line)-1] = '\0';
      if (!strncmp(line, "From ", 5)) {
	  mcnt++;
	  from = 0;
	  subject = 0;
	  Date = 0;
	  if (mcnt > 0) {
	      strcpy(olddate,date);
	      strcpy(oldpath,path);
	      strcpy(oldsub,sub);
	      strcpy(sub,"(no subject)");
	      strcpy(date,"(no date)"); 
	      sch2 = sch1;
	      llines = 1L;
	      lch = strlen(line) + 1;
	  }
      } else
	  if (!from && ( !strncmp(line, "From: ", 6) ||
	       !strncmp(line+1, "From: ", 6) )) {
	      from = 1;
	      sch1 = ch;
	      cp = index(line,'<');
	      if (cp) *cp++;
	      else cp = index(line,' ')+1;
	      strcpy(path, cp);
	      cp = index(path,'>');
	      if (!cp) cp = index(path,' ');
	      if (cp) cp[0] = '\0';
	      if (mcnt > 0) {
		  fl = 1;
		  break;
	      }
	  } else
	      if (!subject && !strncmp(line, "Subject: ", 9)) {
		  subject = 1;
		  sch1 = ch;
		  strncpy(sub,index(line,' ')+1,80);
	      }
	      else
		if (!Date && !strncmp(line,"Date: ",6)) {
		    Date = 1;
		    sch1 = ch;
		    cp = index(line,':') + 1;
		    while (*cp == ' ' || *cp == '\t') *cp++;
		    strncpy(date,cp,60);
		}
      fl = 0;
    }
    if (fl) {
        sprintf(buf," %d %s",mcnt,oldpath);
        cp = buf + strlen(buf);
	sprintf(cp,"  %s, %s %ld/%ld %ld \0",olddate,oldsub,lines-llines,ch-lch,sch2);
    }
    else {
        sprintf(buf," %d %s",mcnt+1,path);
        cp = buf + strlen(buf);
        sprintf(cp,"  %s, %s %ld/%ld %ld \0",date,sub,lines,ch,sch1);
    }
    if (strlen(buf) > 255) buf[254] = '\0';
    if (fl) return(strlen(buf));
    else {
	mcnt = -1;
        llines = lch = 0L;
	return(-strlen(buf));
    }
}

sendmailmsg(fd,mname,buffer)

char *buffer, *mname;
int fd;

{
  long len= BUFLENGTH;
  unsigned long nochars, stchar;
  char dummy;
  FILE *fi;

  if (ggread(fd,&stchar,4) == 4) {
      if (ggread(fd,&nochars,4) == 4) {
	  if (fi = fopen(mname,"r")) {
	      if (fseek(fi,stchar,0) < 0) {
		  fclose(fi);
		  exit;
	      }
	      else {
		  dummy = 0;
		  while (nochars > len) {
			 fread(buffer,1,len,fi);
			 nochars -= len;
			 gwrite(fd,&len,4);
			 gwrite(fd,buffer,len);
			 ggread(fd,&dummy,1);
			 if (dummy) break;
			}
		  if (dummy == 0) {
		      if (fread(buffer,1,nochars,fi) != nochars) {
			  perror("SMAILCHK, unable to read mail file");
			  exit;
		      }
		      gwrite(fd,&nochars,4);
		      gwrite(fd,buffer,nochars);
		      ggread(fd,&dummy,1);
		      nochars = 0L;
		      gwrite(fd,&nochars,4);
		  }
	      }
	      fclose(fi);
	   }
       }
   }
}

char sendmail(fd,address,fname)

int fd;
char *address, *fname;

{
  FILE *fi;
  char ok = 0, *tname;

  if (!(tname = getenv("DNETDIR"))) return(ok);
  sprintf(fname,"%smailchk%ld",tname,getpid());
  {  short len;
     if (ggread(fd,&len,2) != 2) return(ok);
     if (ggread(fd,address,len) != len) return(ok);
  }
  {  long len;
     if (ggread(fd,&len,4) != 4) return(ok);
     if ((fi = fopen(fname, "w")) == NULL) return(ok);
     while (len > BUFLENGTH) {
         int count = BUFLENGTH;
         if (ggread(fd,buf,count) != count) goto fin;
         if (fwrite(buf,1,count,fi) != count) {
             perror("SMAILCHK, error while writing");
             goto fin;
         }
         len -= count;
     }
     if (len > 0) {
         if (ggread(fd,buf,len) != len) goto fin;
         if (fwrite(buf,1,len,fi) != len) {
             perror("SMAILCHK, error while writing");
             goto fin; 
         }
     }
     ok = 1;
fin: fclose(fi);
     if (!ok) unlink(fname);
     return(ok);
  }
}

char delmailmsg(fd,mname)

char *mname;
int fd;

{
  long nochars, stchar;
  FILE *f1, *f2;
  char ok = 0, *tname;


  if (!(tname = getenv("DNETDIR"))) return(ok);
  strcpy(buf,tname);
  strcat(buf,"MAIL0001");
  if (ggread(fd,&stchar,4) == 4)
      if (ggread(fd,&nochars,4) == 4)
	  if ((f1 = fopen(mname,"r")) && (f2 = fopen(buf,"w+"))) {
	      if (copyfiles(f1,f2,stchar))
		  if (fseek(f1,nochars,1) == 0)
		      if (ok = copyfiles(f1,f2,-1)) {
			  fclose(f1);
			  if (unlink(mname) < 0) {
			      perror("SMAILCHK, Error while removing");
			      fclose(f2);
			      unlink(buf);
			      return(0);
			  }
			  rewind(f2);
			  if (f1 = fopen(mname,"w")) {
			      fchmod(f1,0600);
			      ok = copyfiles(f2,f1,-1);
			      fclose(f1);
			      fclose(f2);
			      unlink(buf);
			  }
			  else {
			      perror("SMAILCHK, Error writing in spool dir");
			      fclose(f2);
			      return(0);
			  }
			  if (f1 = fopen(mname,"r")) { /* Touch the file */
			      char f = 0;
			      fread(f,1,1,f1);
			      fseek(f1,0,2);
			      if (ftell(f1) < 2) f = 1;
			      fclose(f1);
			      if (f) unlink(mname);
			  }
			  return(ok);
		      }
	      perror("SMAILCHK, Error while writing");
	      fclose(f1);
	      fclose(f2);
	      return(0);
	  }
  perror("SMAILCHK, Delete operation");
  return(0);
}

char copyfiles(f1,f2,n)

FILE *f1, *f2;
long n;

{
  char buffer[1024], ok = 1;
  int tmp;

  while (n > 1024 || n < 0) {
    if (n > 0) n -= 1024;
    if ((tmp = fread(buffer,1,1024,f1)) == 1024)
	if (fwrite(buffer,1,1024,f2) == 1024)
	    continue;
    ok = 0;
    break;
  }
  while (ok && n > 0) {
      if (fread(buffer,1,n,f1) == n)
	  if (fwrite(buffer,1,n,f2) == n)
	      break;
      ok = 0;
  }
  if (n >= 0) return(ok);
  if (fwrite(buffer,1,tmp,f2) == tmp) ok = 1;
  return(ok);
}
