
/*
 *	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 "servers.h"

#define BUFLENGTH 512

extern int errno;

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

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(SIGPIPE, SIG_IGN);
    signal(SIGALRM, do_mailchk);
    for (;;) {
	fd = DAccept(chann);
	if (fd < 0) {
	    if (errno == EINTR)
		continue;
	    break;
	}
    	getmailpath();
        while (ggread(fd,&result,1) == 1) {
          Whatdoyouwant(fd,result);
        }
    	close(fd);
    	_exit(1);
    }
    perror("SMAILCHK");
}

char buf[256], mname[256];

getmailpath()

{
    char *buffer;

    buffer = (char *) getenv("MAIL");
    if (buffer == NULL) {
       strcpy(mname,"/var/spool/mail/");
    }
    else {
       strcpy(mname,buffer);
       strcat(mname,"/");
    }
    cuserid(buf);
    strcat(mname,buf);
}

Whatdoyouwant(fd,result)

int fd;
char result;

/*  This function interprets requests from the Amiga client.
    0 -> Do nothing
    1 -> Send the mail header from Mail.
    2 -> Send a particular message.
    3 -> Delete a particular message.
    4 -> Initial handshake
*/

{
    char dummy, *buffer;
    FILE *fi;

    switch(result) {
        case 1 : 
          fi = popen("mail -H","r");
          if (fi == NULL) {
              perror("SMAILCHK, mail program not found");
              exit(0);
          }
          while (fgets(buf,256,fi) != NULL) {
            dummy = strlen(buf);
            buf[dummy-1] = 0;
            gwrite(fd,&dummy,1);
            gwrite(fd,buf,dummy);
          }
          dummy = 0;
          gwrite(fd,&dummy,1);
	  if (ferror(fi)) {
            perror("SMAILCHK, error executing mail");
	    exit(0);
          }
	  pclose(fi);
          break;
        case 2 :
          buffer = (char *) malloc(BUFLENGTH);
          if (buffer == NULL) {
              fprintf(stderr,"SMAILCHK:  not enough memory\n");
          }
          else {
              sendmailmsg(fd,mname,buffer);
              free(buffer);
          }
          break;
	case 3 :
          { char ok;
           
          ok = delmailmsg(fd,mname);
          gwrite(fd,&ok,1);
           if (ok) { alarm(0); do_mailchk();}
          }
          break;
        case 4 :
          if ((ggread(fd,&numsecs,4)  == 4) &&
              (ggread(fd,&firstrun,1) == 1)) { alarm(0); do_mailchk(); }
          else { close(fd); _exit(1); }
    }
}

void do_mailchk()

{
    char dummy, *s_mtime;
    struct stat tempbuf;
    static char nomail = 1;
    static long lasttime = 0;
    
    strcpy(buf,"=");
    alarm(numsecs);
    if (stat(mname,&tempbuf) == -1) {
        if (errno == ENOENT) { if (nomail) {
                                   strcpy(buf,"No mail.");
                                   nomail = 0;
                               }
        }
        else perror("SMAILCHK, Unable to examine file");
    }
    else {
        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 && (tempbuf.st_mtime > lasttime)) ||
                  firstrun == 2)
                 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;
}

sendmailmsg(fd,mname,buffer)

char *buffer, *mname;
int fd;

{
  int len= BUFLENGTH;
  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 = 0;
                      gwrite(fd,&nochars,4);
                  }
              }
              fclose(fi); 
           }
       }
   }
}

char delmailmsg(fd,mname)

char *mname;
int fd;

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


  if (!(tname = (char *) 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;
                              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);
}
