/*
 * popmail.c: interface between independent POP routines and the UCB
 * mail program
 *
 * Copyright (c) 1991 by Jonathan Kamens.
 *
 * Distribution and use of this file is governed by the GNU Public
 * License (version 1 or any later version).
 */

#include <stdio.h>
#include <errno.h>
#include <string.h>
#if __STDC__
#include <stdlib.h>
#else
extern char *malloc (), *calloc (), *realloc ();
#endif
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#ifndef BSD43
#include <time.h>
#endif
#include "rcv.h"
#include "pop.h"
#include <regexp.h>

#ifdef LOCAL_STRSTR
extern char *strstr(/* char *, char * */);
#endif

static char *filename;
static int mbox_size, mbox_count;

static char *header(msg, tag)
char *msg;
char *tag;
{
     char *val, *ptr, *eoh;

     val = malloc(strlen(tag) + 3);
     if (! val)
	  return(0);

     sprintf(val, "\n%s:", tag);
     
     eoh = strstr(msg, "\n\n");
     if (! eoh)
	  eoh = strchr(msg, '\0');

     ptr = strstr(msg, tag);

     if ((! ptr) || (ptr > eoh)) {
	  sprintf(val, "%s:", tag);
	  if (! strncmp(val, msg, strlen(val)))
	       ptr = msg;
	  else
	       ptr = 0;
     }

     if (! ptr) {
	  free(val);
	  return(0);
     }

     ptr += strlen(val);

     while (*ptr && ((*ptr == ' ') || (*ptr == '\t')))
	    ptr++;

     eoh = strchr(ptr, '\n');
     if (! eoh)
	  eoh = strchr(ptr, '\0');
     
     val = realloc(val, (eoh - ptr) + 1);
     strncpy(val, ptr, (eoh - ptr));
     val[eoh - ptr] = '\0';

     return(val);
}

static char *date(msg)
char *msg;
{
     char *real = 0, *machine = 0;
     time_t t;
     int size;

     real = header(msg, "Date");

     if (real) {
	  t = get_date(real);
	  free(real);
	  if (t != -1) {
	       machine = ctime(&t);
	  }
     }

     if (! machine) {
	  t = time(0);
	  machine = ctime(&t);
     }

     size = strlen(machine);
     machine[size-1] = '\0'; /* get rid of newline */
     real = malloc(size);
     if (! real)
	  return(0);
     strcpy(real, machine);

     return(real);
}

char *patterns[] = {
     /*
      * <address>
      * or
      * Name <address>
      */
     "^.*<([^ \t]+)>[ \t]*$",
     /*
      * address
      * or
      * address (Name)
      */
     "^[ \t]*([^ \t\\(]+)",
     0
};

static char *from_line(msg)
char *msg;
{
     char *real = header(msg, "From"), *real2;
     char **ptr;
     regexp *exp;
     int retval;

     if (real) for (ptr = patterns; *ptr; ptr++) {
	  exp = regcomp(*ptr);
	  if (! exp) {
	       free(real);
	       return(0);
	  }
	  retval = regexec(exp, real);
	  if (retval) {
	       real2 = malloc(exp->endp[1] - exp->startp[1] + 1);
	       if (! real2) {
		    free(exp);
		    free(real);
		    return(0);
	       }
	       strncpy(real2, exp->startp[1], exp->endp[1] - exp->startp[1]);
	       real2[exp->endp[1] - exp->startp[1]] = '\0';
	       free(real);
	       free(exp);
	       return(real2);
	  }
     }

     if (real)
	  real = realloc(real, 8);
     else
	  real = malloc(8);
     if (! real)
	  return(0);
     strcpy(real, "unknown");
     return(real);
}
	       
static void out_error(server)
PopServer server;
{
     fprintf(stderr, "mail: writing %d messages (%d bytes) to ",
	     mbox_count, mbox_size);
     perror (filename);
     pop_close(server);
}

static int do_message(server, outfile, message)
PopServer server;
FILE *outfile;
int message;
{
     char *msg, *dt, *frm;

     msg = pop_retrieve(server, message, 1);
     if (! msg) {
	  /* not checking fclose because we already have one error and */
	  /* the connection has already been reset		       */
	  fprintf(stderr, "mail: retrieving POP message: %s\n", pop_error);
	  (void) fclose(outfile);
	  return(-1);
     }

     if (pop_delete(server, message)) {
	  /* not checking fclose because we already have one error and */
	  /* the connection has already been reset		       */
	  (void) fclose(outfile);
	  return(-1);
     }

     dt = date(msg);
     frm = from_line(msg);

     if (! (dt && frm)) {
	  if (dt)
	       free(dt);
	  if (frm)
	       free(frm);
	  free(msg);
	  if (fclose(outfile) == EOF) {
	       out_error(server);
	  }
	  else {
	       if (pop_quit(server)) {
		    fprintf(stderr, "mail: closing POP connection: %s\n",
			    pop_error);
	       }
	  }
	  return(-1);
     }

     if ((fprintf(outfile, "From %s %s\n", frm, dt) == EOF) ||
	 (fwrite(msg, sizeof(char), strlen(msg), outfile) == 0) ||
	 (fputc('\n', outfile) == EOF && ferror(outfile))) {
	  out_error(server);
	  free(msg);
	  free(dt);
	  free(frm);
	  /* Not checking fclose because we already have a file error */
	  (void) fclose(outfile);
	  return(-1);
     }

     free(msg);
     free(dt);
     free(frm);

     return(0);
}
	  
int popmail_tofile(fname, who)
char *fname;
char *who;
{
     PopServer server;
     FILE *outfile;
     int i, flags = 0;
     int verbose = value("interactive") && value("verbose-pop");

     filename = fname;

#ifdef KERBEROS
     if (value("nokerberos"))
	  flags |= POP_NO_KERBEROS;
#endif

     server = pop_open(0, 0, 0, flags);
     if (! server) {
	  fprintf(stderr, "mail: opening pop connection: %s\n", pop_error);
	  return(-1);
     }

     if (pop_stat(server, &mbox_count, &mbox_size)) {
	  fprintf(stderr, "mail: getting mailbox stats: %s\n", pop_error);
	  return(-1);
     }

     if (mbox_count == 0) {
	  struct stat statbuf;
	  if (stat(filename, &statbuf) && (errno == ENOENT)) {
	       fprintf(stderr, "No mail for %s\n", who);
	       return(-1);
	  }
     }

     if (verbose) {
	  fputs("Getting new mail from post office....", stdout);
	  fflush(stdout);
     }

     outfile = fopen(filename, "a");
     if (! outfile) {
	  fprintf(stderr, "mail: opening ");
	  perror (filename);
	  return(-1);
     }

     for (i = 1; i <= mbox_count; i++) {
	  if (do_message(server, outfile, i)) 
	       return(-1);
	  if (verbose) {
	       fputc('.', stdout);
	       fflush(stdout);
	  }
     }

     if (verbose) {
	  fputc('\n', stdout);
     }

     if (fclose(outfile) == EOF) {
	  out_error(server);
	  return(-1);
     }
     else if (pop_quit(server)) {
	  fprintf(stderr, "mail: closing POP connection: %s\n", pop_error);
	  return(-1);
     }
     else
	  return(0);
}     
