/*
 *    mkms: create a shell script to mail a specified list
 *          of files to a specified list of addresses with
 *          a specified list of subjects. with aliases in
 *          an rc file.  do I sound confused?
 *
 *    history:
 *	      30SEP94: begun, first usage, basically refitted 'mkfscript'
 *		            to deal with the mail script instead of ftp.
 *	      05OCT94: added ability to have aliases for user@address
 *	      06OCT94: added the 'find single alias', 'list aliases'
 *                and the 'echo' options.
 *
 *    Copyright (c)1994 by Eric R. Augustine.  Absolute freeware -  do
 *    with it what you wish except sell it or remove this copyright notice.
 *
 *    I may be contacted via internet e-mail: gort@shell.portal.com
 */

#include <nlist.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>

#define VERSION "1.35"

#define TRUE  1
#define FALSE 0

char *progname = "mkms";
char *rcfile   = "/.mkmsrc";

typedef int bool;

bool listal = FALSE;

struct filestr {
   char  *destination;
   char  *message;
   char  *subject;
};

struct alias {
	char  *name;
	char  *real;
};


main(int argc, char *argv[]) {
   FILE 	  *ifp,*tfp,*ofp;
   bool 	  mkecho	= FALSE;
   bool 	  geta = FALSE;
   bool 	  prout = FALSE;
   bool 	  stdprt = FALSE;
   bool 	  rdstdin = FALSE;
   bool 	  addlns = FALSE;
   bool 	  ignore = FALSE;
   bool 	  fsalias = FALSE;
   bool    mkftp = FALSE;
   bool    fdesc = FALSE;
   char 	  *infile,*outfile,*curstring,*filenm;
   char 	  *tempname, *site, *dstring, *repstr = NULL;
   char    *aliasf;
   char 	  buffer[BUFSIZ];
   char    *getalias(char *);
   extern  char *optarg;
   extern  int  optind;
   extern  int  opterr;
   int     c,d,cc,length,elength,flength,linecount,rcerror;
   int     scount = 0,fdelay = 1;
   struct  filestr entry;
   struct  stat stbuf,rcbuf;
   struct  alias al;
   struct  tm *local_time;
   size_t  dlen = 0;
   time_t  now, time();
   void    usage(void);
   void    error(char *, char *);
   void    listrc(void);
   void    findsinglealias(char *);
   void    pversion(void);

   progname = argv[0];                           /* whatever program renamed to */

   if(argc < 2 ) {                               /* make sure minimal usage valid */
      usage();
      exit(1);
   }

   while((d = getopt(argc, argv, "acdelnsvFIf:o:i:S:")) != EOF) {
         switch(d) {
            case 'I':                            /* count output and print count */
			      ignore = TRUE;
			      break;
            case 'l':                            /* list all the aliases */
               listal = TRUE;
               break;
            case 'c':                            /* print to stdout */
               ofp = stdout;
               stdprt = TRUE;
               break;
            case 'e':                            /* add lines to make script echo */
               mkecho= TRUE;
               break;
            case 'f':                            /* find an alias in the rc */
               aliasf = optarg;
               fsalias = TRUE;
               break;
            case 'n':                            /* how many lines and chars written */ 
               prout = TRUE;
               break;
            case 's':                            /* read from stdin */
               ifp = stdin;
               rdstdin = TRUE;
               break;
            case 'a':                            /* append more lines */
               addlns = TRUE;
               break;
            case 'F':                            /* make an ncftp script */
               mkftp = TRUE;
               break;
            case 'v':                            /* print version and copyright info */
               pversion();
               exit(0);
               break;
            case 'o':                            /* get outfile */
               outfile = optarg;
               break;
            case 'i':                            /* get infile */
               infile = optarg;
               break;
            case 'd':                            /* add file descriptions for ftp scripts */
               fdesc = TRUE;
               break;
            case 'S':                            /* get ftp site */
               site = optarg;
               break;
            default:                             /* user error */
               fprintf(stderr,"%s: unknown option '%c'\n",progname,d);
               usage();
               exit(2);
               break;
         }
   }
argc -= optind;
argv += optind;

/*  catch a few possible problems
 */
   if(addlns)
      stdprt = FALSE;
   if(mkftp == FALSE)
      fdesc = FALSE;
      

/*  stat rcfile and set geta accordingly
 */
   rcfile = strcat(getenv("HOME"),rcfile);
   rcerror = stat(rcfile,&rcbuf);
   if(rcerror == 0) {
      geta = TRUE;
      if((rcbuf.st_mode & S_IFMT) == S_IFDIR) {
         error("your rc file is a directory, ignoring",rcfile);
         if(listal)
            exit(1);
         geta = FALSE;
      }
   }

/*  get the user's desired delay for ncftp scripts
 */
   if((geta) && (mkftp)) {
   	repstr = getalias("fdelay");
   	if(repstr != NULL)
   	   fdelay = atoi(strdup(repstr));
   }       

/*  now that we have the user's delay time we
 *  can ignore the rc file.
 */
   if(ignore)
      geta = FALSE;


/*  switch site for entry in rc file if exists
 */
   if((geta) && (mkftp)) {
      repstr = getalias(site);
      if(repstr != NULL)
         site = strdup(repstr);
   }

/*  list contents of rc file
 */
   if(listal) {
      if(geta) {
         listrc();
         exit(0);
      }
      else {
         error("unable to access rc file.","");
         exit(1);
      }
   }

/*  find a single alias in the rcfile
 */
   if(fsalias) {
      if(geta) {
         findsinglealias(aliasf);
         exit(0);
      }
      else {
      	error("unable to access rc file.","");
      	exit(1);
      }
   }


/*  open needed files for preprocess
 */
   if(rdstdin);
   else {
      stat(infile,&stbuf);                           /* get file status */
      if((stbuf.st_mode & S_IFMT) == S_IFDIR) {      /* ooops, file is a directory */
         error("named infile is a directory","");
         exit(4);                                    /* goon warrior */
      }
      if(!(ifp = fopen(infile,"r"))) {               /* source file */
         error("unable to open file",infile);
         exit(2);                                    /* user error */
      }
   }
   tempname = tmpnam(NULL);                          /* create temp file */
   if(!(tfp = fopen(tempname,"w"))) {
      error("unable to open temporary file stream","");
      exit(3);                                       /* system error */
   }

/*  preprocess source file - remove all tabs and reduce
 *  multiple spaces to single spaces.  this makes all 
 *  input files equivalent.
 */
	while((c = fgetc(ifp)) != EOF) {
		if(c == '\t') {
			if(scount < 1)
				putc(' ',tfp);
			scount++;
		}
		else if(c == ' ') {
			if(scount < 1)
				putc(' ',tfp);
			scount++;
		}
		else if(c == '\n') {
			scount = 0;
			putc(c,tfp);
		}
		else {
			scount = 0;
			putc(c,tfp);
		}
	}

   if(rdstdin);
   else
      fclose(ifp);                                   /* close source file */
   fclose(tfp);                                      /* reopen temp stream */
   if(!(tfp = fopen(tempname,"r"))) {                /* with mode "read" */
      error("unable to open temporary file stream","");
      exit(3);
   }

/*  open output file based on command line opts
 */
   if(stdprt);                                       /* print to terminal */
   else

/*  append new lines to end of pre-existing file
 */
   if(addlns) {
      if(stat(outfile,&stbuf) == -1)                 /* is old file there? */
        addlns = FALSE;					                 /* no -> reset flag */
      if((stbuf.st_mode & S_IFMT) == S_IFDIR) {      /* ooops, file is a directory */
        error("named outfile is a directory","");
        exit(5);                                     /* goon error */
      }
      if(!(ofp = fopen(outfile,"a"))) {              /* open file mode append */
        error("unable to open old file",outfile);
        exit(1);
      }
    }
    else {
       stat(outfile,&stbuf);                         /* check filetype */
       if((stbuf.st_mode & S_IFMT) == S_IFDIR) {     /* file is a directory */
          error("named outfile is a directory","");
          exit(5);                                   /* goon alert */
       }
       if(!(ofp = fopen(outfile,"w"))) {             /* print to a new file */
         error("unable to open outfile",outfile);
         exit(1);
       }
    }

/*  make the script file
 */
   (void)time(&now);                                 /* get date info for header */
   local_time = localtime(&now);
   dstring = asctime(local_time);
   if(addlns == FALSE) {
      cc = fprintf(ofp,"#!/bin/sh -f\n# generated by %s %s %s",progname,VERSION,dstring);
      linecount = 2;
   }
   else if(addlns) {
      cc = fprintf(ofp,"# added %s",dstring);
      linecount = 2;
   }
   while((curstring = fgets(buffer,BUFSIZ,tfp)) != NULL) { /* parse lines */
      entry.destination = strsep(&curstring," ");
      entry.message		= strsep(&curstring," ");
      entry.subject	   = strsep(&curstring,"\n\0");
      if(geta) {
         repstr = getalias(entry.destination);
      if(repstr != NULL)
         entry.destination = strdup(repstr);
      }
      if((mkftp) && (fdesc))
         flength = fprintf(ofp,"# %s: %s\n",entry.destination,entry.subject);
      if((mkecho) && (mkftp == FALSE))
         elength = fprintf(ofp,"echo \"sending %s to %s\" ;\n",entry.message,entry.destination);
      if((mkecho) && (mkftp)) 
         elength = fprintf(ofp,"echo \"getting %s/%s\" ;\n",site,entry.destination);   
      if(mkftp == FALSE) 
         length = fprintf(ofp,"mail -s \"%s\" %s < %s ;\n",entry.subject,entry.destination,entry.message);
      if(mkftp) {
         filenm = strdup(entry.destination);
         filenm = strsep(&filenm,".");
         length = fprintf(ofp,"ncftp >& ./%s.ncftp -d %d -r %s/%s/%s & ;\n",filenm,fdelay,site,entry.message,entry.destination);
      }
      if((prout) && (mkecho))
         length += elength;
      if((prout) && (fdesc))
         length += flength;
      if(prout) {
         linecount ++;
         if(fdesc)
            linecount++;
         if(mkecho)
            linecount++;
         cc += length + dlen;
      }
   }
   if((prout) && (addlns == FALSE))                  /* print info on made file */
      fprintf(stderr,"characters: %d\n     lines: %d\n",cc,linecount);
   else 
      if((addlns == TRUE) && (prout == TRUE))
         fprintf(stderr,"characters added: %d\n  lines appended: %d\n",cc,linecount);
      if(stdprt == FALSE)                            /* don't try to close stout */
         fclose(ofp);                                /* close out file */
      fclose(tfp);
      remove(tempname);
}

/*  a little instruction for the unknowing
 */
void usage() {
   fprintf(stderr,"Usage: %s [-acdelnsvFI] [-f alias] [-i input] [-S site] [-o output]\n", progname);
   return;
}

/*  print version and copyright information 
 */
void pversion(void) {
   printf("mkms is free software.  you may distribute copies of it as long as no\n");
   printf("profit is made from such distribution.  There is no warranty for mkms.\n");
   printf("mkms %s Copyright (c)1994 by Eric R. Augustine.\n",VERSION);
   return;
}

/*  simple error messages
 */
void error(char *estring, char *fstring) {
   fprintf(stderr,"%s: ERROR: %s %s\n", progname, estring, fstring);
   return;
}

/*  get aliases from rcfile
 */
char *getalias(char *s) {
   FILE   *rfp;
   bool   DONE = FALSE;
   char   buffer[BUFSIZ],*alstr,*retstr = NULL;
   struct alias al;

   if(!(rfp = fopen(rcfile,"r"))) {
      error("unable to open rc file",rcfile);
   }
   else {
      while((!feof(rfp) && (alstr = fgets(buffer,BUFSIZ,rfp)) != NULL) && !DONE) {
         if(alstr[1] == '#');  /* eat comments and other garbage */
         else 
            if(alstr[1] == ' ');  
         else 
            if(alstr[1] == '\n');
         else 
            if(alstr[1] == '\t');
         else 
            if(alstr[1] == '\0');
         else {
            al.name = strsep(&alstr," ");
            al.real = strsep(&alstr,"\n\0");
            if(strcmp(s,al.name) == 0) {
               DONE = TRUE;
               retstr = strdup(al.real);
            }
         }
      }
   }
   if(rfp)
      fclose(rfp);
   return retstr;
}

/*  list contents of rcfile
 */
void listrc() {
   FILE   *rfp;
   char   buffer[BUFSIZ],*alstr;
   struct alias al;

   printf("\nalias = real value\n");
   printf("--------------------------------------------------------------\n");
   if(!(rfp = fopen(rcfile,"r"))) {
      error("unable to open rc file",rcfile);
   }
   else {
      while((alstr = fgets(buffer,BUFSIZ,rfp)) != NULL) {
         if(alstr[1] == '#');  /* eat comments and other garbage */
         else 
            if(alstr[1] == ' ');
         else 
            if(alstr[1] == '\n');
         else 
            if(alstr[1] == '\t');
         else
            if(alstr[1] == '\0');
         else {
            al.name = strsep(&alstr," ");
            al.real = strsep(&alstr,"\n");
            if(strcmp(al.name,"fdelay") == 0);
            else 
               printf("%s = %s\n",al.name,al.real);
         }
      }
   }
   printf("\n");
   close((int)rfp);
   return;
}

/*  name says it all.  find a single alias in the
 *  rc file.
 */
void findsinglealias(char *alias) {
   FILE   *rfp;
   bool   found = FALSE;
   char   buffer[BUFSIZ],*alstr;
   struct alias al;

   if(!(rfp = fopen(rcfile,"r")))
      error("unable to open rc file",rcfile);
   else {
      while((alstr = fgets(buffer,BUFSIZ,rfp)) != NULL) {
         if(alstr[1] == '#');  /* eat comments and other garbage */
         else 
            if(alstr[1] == ' ');
         else 
            if(alstr[1] == '\n');
         else 
            if(alstr[1] == '\t');
         else 
            if(alstr[1] == '\0');
         else {
            al.name = strsep(&alstr," ");
            al.real = strsep(&alstr,"\n");
            if(strcmp(alias,al.name) == 0) {
               printf("%s\n",al.real);
               found = TRUE;
            }
            else
               if (strcmp(alias,al.real) == 0) {
                  printf("%s\n",al.name);
                  found = TRUE;
               }
         }
      }
      if(!found) 
         printf("%s: %s not found.\n",progname,alias);
   }
   if(rfp)
      fclose(rfp);
   return;
}


   