/*
 * This file is part of uudeview, the simple and friendly multi-part multi-
 * file uudecoder  program  (c)  1994 by Frank Pilhofer. The author may be
 * contacted by his email address,          fp@informatik.uni-frankfurt.de
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

/*
 * Definitions for compilation within Windows. Some Windows includes
 * would complain if we were to #define _DOS globally
 */

#ifdef _WINDOWS
#ifndef _WIN
#define _WIN
#endif
#ifndef _DOS
#define _DOS
#endif
#endif

#include <sys/stat.h>
#include <ctype.h>
#include <stdio.h>
#include <time.h>

#ifndef NO_POSIX
#include <string.h>
#include <stdlib.h>
#endif

#ifndef NO_POSIX
#ifndef _DOS
#include <unistd.h>
#endif
#endif

#include "uuenview.h"
#include "toolbox.h"

/*
 * =========================================================================
 * User-configurable settings. Set them, the defaults will probably not work
 * =========================================================================
 */

/*
 * The mail program. It must read the mail from standard input and should
 * not output any messages (some elm implementation use to print out lots
 * of terminal control characters)
 * if not in /bin or /usr/bin, use the full path name
 */

#ifndef MAILPROG
#define MAILPROG 	"mail"
#endif

/*
 * If the above mail program accepts the subject as a command line option
 * as "mail -s 'The Subject'", set the following define to 1, else to 0.
 */

#ifndef MPSUBJECT
#define MPSUBJECT	0
#endif

/*
 * Inews program. The first %s is replaced by the newsgroup(s), the second
 * %s is replaced by the subject. The program must then read the article
 * from standard input. If you don't have a program of this kind, undefine
 * INEWS.
 */

#ifndef INEWS
#define INEWS		"/usr/usersb2/w93/fp/bin/minews -S -h"
#endif

/*
 * the End-Of-Line string. MIME enforces CRLF, so that's what we use. Some
 * implementations of uudecode will complain about a missing end line, since
 * they look for "end^L" but find "end^L^M". We don't care - especially be-
 * cause they still decode the file properly despite this complaint.
 * want LF only. We don't care about the latter.
 */

#ifndef EOLSTRING
#define EOLSTRING	"\015\012"
#endif

/*
 * =========================================================================
 * User-configurable settings end here. Don't spy below unless you know what
 * you're doing.
 * =========================================================================
 */

/*
 * usually set above
 */

#ifndef MAILPROG
#define MAILPROG	""
#endif

#ifndef MPSUBJECT
#define MPSUBJECT	0
#endif

#ifndef INEWS
#define INEWS		""
#endif

/*
 * Define End-Of-Line sequence
 */

#ifdef EOLSTRING
static char *eolstring = EOLSTRING;
#else
static char *eolstring = "\012";
#endif

/*
 * Define News Posting program
 */

#ifdef INEWS
static char *inewsprog = INEWS;
#else
static char *inewsprog = "";
#endif

static unsigned char UUEncodeTable[64] = {
  '`', '!', '"', '#', '$', '%', '&', '\'',
  '(', ')', '*', '+', ',', '-', '.', '/',
  '0', '1', '2', '3', '4', '5', '6', '7',
  '8', '9', ':', ';', '<', '=', '>', '?',
  '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
  'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
  'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
  'X', 'Y', 'Z', '[', '\\',']', '^', '_'
};
  

static unsigned char B64EncodeTable[64] = {
  'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
  'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
  'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
  'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
  'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
  'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
  'w', 'x', 'y', 'z', '0', '1', '2', '3',
  '4', '5', '6', '7', '8', '9', '+', '/'
};

static unsigned char XXEncodeTable[64] = {
  '+', '-', '0', '1', '2', '3', '4', '5',
  '6', '7', '8', '9', 'A', 'B', 'C', 'D',
  'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L',
  'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
  'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b',
  'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
  'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r',
  's', 't', 'u', 'v', 'w', 'x', 'y', 'z'
};

typedef struct {
	char *extension;
	char *mimetype;
	} mimemap;

int verbose=0;
char ENCerrfile[256];

static mimemap mimetable[] = {
	{ "gif",  "image/gif"        },	/* rfc1341 */
	{ "jpg",  "image/jpeg"       }, /* rfc1341 */
	{ "tif",  "image/tiff"       },
	{ "bmp",  "image/bmp"        },
	{ "pcx",  "image/pcx"        },
	{ "tga",  "image/tga"        },
	{ "png",  "image/ping"       },
	{ "au",   "audio/basic"      }, /* rfc1341 */
	{ "wav",  "audio/wave"       },
	{ "voc",  "audio/voc"        },
	{ "mov",  "video/quicktime"  }, /* rfc1341 */
	{ "avi",  "video/avi"        },
	{ "mpg",  "video/mpeg"       }, /* rfc1341 */
	{ "mp2",  "video/mpeg"       }, /* rfc1341 */
	{ "mp3",  "video/mpeg"       }, /* rfc1341 */
	{ "qt",   "video/quicktime"  }, /* rfc1341 */
	{ "fli",  "video/fli"        },
	{ "gl",   "video/gl"         },
	{ "ps",   "application/PostScript" }, /* rfc1341 */
	{ NULL,   NULL               }
};

static int 
EncodeStream (int encoding, int linperfile, FILE *infile, FILE *outfile)
{
  unsigned char itemp[256], otemp[256], *optr, *table, *tptr;
  int line=0, index, count, bpl, llen;

  /*
   * UU and XX encode 45 bytes per line; Base64 encodes 57 bytes per line.
   */

  bpl = (encoding == ENC_TYPE_UU  || encoding == ENC_TYPE_XX) ? 45 : 57;

  /*
   * select charset
   */

  table = ((encoding == ENC_TYPE_UU) ? UUEncodeTable :
	   ((encoding == ENC_TYPE_XX) ? XXEncodeTable :
	    B64EncodeTable));

  while (!feof (infile) && (linperfile == 0 || line < linperfile)) {
    if ((count = fread (itemp, 1, bpl, infile)) == 0)
      break;
    optr = otemp;
    llen = 0;

    /*
     * for UU and XX, encode the number of bytes as first character
     */
    if (encoding == ENC_TYPE_UU || encoding == ENC_TYPE_XX) {
      *optr++ = table[count];
      llen++;
    }

    for (index=0; index<=count-3; index+=3, llen+=4) {
      *optr++ = table[itemp[index] >> 2];
      *optr++ = table[((itemp[index  ] & 0x03) << 4) | (itemp[index+1] >> 4)];
      *optr++ = table[((itemp[index+1] & 0x0f) << 2) | (itemp[index+2] >> 6)];
      *optr++ = table[  itemp[index+2] & 0x3f];
    }

    /*
     * Special handling for incomplete lines
     */
    if (index != count) {
      if (encoding == ENC_TYPE_B64) {
	if (count - index == 2) {
	  *optr++ = table[itemp[index] >> 2];
	  *optr++ = table[((itemp[index  ] & 0x03) << 4) | 
			  ((itemp[index+1] & 0xf0) >> 4)];
	  *optr++ = table[((itemp[index+1] & 0x0f) << 2)];
	  *optr++ = '=';
	}
	else if (count - index == 1) {
	  *optr++ = table[ itemp[index] >> 2];
	  *optr++ = table[(itemp[index] & 0x03) << 4];
	  *optr++ = '=';
	  *optr++ = '=';
	}
	llen += 4;
      }
      else {
	if (count - index == 2) {
	  *optr++ = table[itemp[index] >> 2];
	  *optr++ = table[((itemp[index  ] & 0x03) << 4) | 
			  ( itemp[index+1] >> 4)];
	  *optr++ = table[((itemp[index+1] & 0x0f) << 2)];
	  *optr++ = table[0];
	}
	else if (count - index == 1) {
	  *optr++ = table[ itemp[index] >> 2];
	  *optr++ = table[(itemp[index] & 0x03) << 4];
	  *optr++ = table[0];
	  *optr++ = table[0];
	}
	llen += 4;
      }
    }
    /*
     * end of line
     */
    tptr = eolstring;

    while (*tptr)
      *optr++ = *tptr++;

    *optr++ = '\0';
    llen   += strlen (eolstring);

    if (fwrite (otemp, 1, llen, outfile) != llen)
      return 1;
    line++;
  }
  return 0;
}

static int
EncodePart (int encoding,    int linperfile,
	    int partno,      int numparts,
	    char *basename,  int filemode,
	    char *mimeid,    char *mimetype,
	    FILE *infile,    FILE *outfile)
{
  int res;

  /*
   * print MIME headers
   */

  fprintf (outfile, "MIME-Version: 1.0%s", eolstring);
  fprintf (outfile, "Content-Type: message/partial;%s", eolstring);
  fprintf (outfile, "\t\tid=\"%s\";%s", mimeid, eolstring);
  fprintf (outfile, "\t\tnumber=%d", partno);

  if (numparts > 0)
    fprintf (outfile, "; total=%d%s", numparts, eolstring);
  else
    fprintf (outfile, "%s", eolstring);

  /*
   * Print an empty line to end the headers section when mailing or
   * posting. This must be LF only, or inews will not consider the
   * line 'empty'.
   */
  fprintf (outfile, "\n");

  /*
   * send a CRLF afterwards. We want an empty line for all systems, including
   * those strange ones that don't accept the LF only from above ...
   */
  fprintf (outfile, "%s", eolstring);

  if (mimetype)
    fprintf (outfile, "Content-Type: %s;%s", mimetype, eolstring);
  else
    fprintf (outfile, "Content-Type: Application/octet-stream;%s", eolstring);
  
  fprintf (outfile, "\t\tname=\"%s\"%s", basename, eolstring);
  fprintf (outfile, "Content-Transfer-Encoding: %s%s%s",
	   (encoding == ENC_TYPE_UU) ? "x-uue" :
	   (encoding == ENC_TYPE_XX) ? "x-xxe" :
	   (encoding == ENC_TYPE_B64)? "Base64": "x-uue",
	   eolstring, eolstring);

  if (partno == 1 && (encoding == ENC_TYPE_UU || encoding == ENC_TYPE_XX))
    fprintf (outfile, "begin %o %s%s", filemode, basename, eolstring);

  res = EncodeStream (encoding, linperfile, infile, outfile);

  if (feof (infile)) {
    if (encoding == ENC_TYPE_UU || encoding == ENC_TYPE_XX) {
      fprintf (outfile, "%c%s",    
	       (encoding == ENC_TYPE_UU)?UUEncodeTable[0]:XXEncodeTable[0], 
	       eolstring);
      fprintf (outfile, "end%s%s", eolstring,eolstring);
    }
    else
      fprintf (outfile, "%s", eolstring);
  }
  else 
    fprintf (outfile, "%s", eolstring);

  return res;
}

/*
 * outfilename is misused as
 *     email-address   if output == FLAG_MAILTO
 *     newsgroup       if output == FLAG_INEWS
 */

static int
HandlePart (int encoding,      int linperfile, 
	    int partno,        int numparts,
	    char *basename,    char *subject,
	    char *mimeid,      char *mimetype,
	    char *outfilename, char *introfile,
	    FILE *infile,      int filemode,
	    int output)
{
  char command[256], tmpbuf[256], subline[256];
  FILE *outfile, *intro;
  int res=0, count;

  if (partno == 0 && (introfile == NULL || output == FLAG_STDOUT))
    return 0;

  /*
   * construct subject
   */
  if (numparts != -1) {
    if (subject) {
      sprintf (subline, "%s (%03d/%03d) - [ %s ]",
	       (subject) ? subject : "",
	       partno, numparts,
	       basename);
    }
    else {
      sprintf (subline, "[ %s ] (%03d/%03d)",
	       basename, partno, numparts);
    }
  }
  else {
    if (subject) {
      sprintf (subline, "%s (%03d/unknown) - [ %s ]",
	       (subject) ? subject : "",
	       partno, basename);
    }
    else {
      sprintf (subline, "[ %s ] (%03d/unknown)",
	       basename, partno);
    }
  }

  if (output == FLAG_STDOUT) {
    outfile = stdout;
  }
#ifndef _DOS
  else if (output == FLAG_MAILTO) {
    if (*MAILPROG == '\0') {
      fprintf (stderr, "error: email option not configured\n");
      fflush  (stderr);
      return 1;
    }
    if (verbose) {
      fprintf (stderr, "mailing part (%03d/%03d) to %s ... ",
	       partno, numparts, outfilename);
      fflush  (stderr);
    }
    if (MPSUBJECT)
      sprintf (command, "%s -s \"%s\" %s", MAILPROG, subline, outfilename);
    else
      sprintf (command, "%s %s", MAILPROG, outfilename);

    if ((outfile = popen (command, "w")) == NULL) {
      sprintf (ENCerrfile, "popen(\"%s\")", command);

      if (verbose)
	fprintf (stderr, "failed.\n");

      return 1;
    }
    if (!MPSUBJECT)
      fprintf (outfile, "Subject: %s\n", subline);
  }
  else if (output == FLAG_INEWS) {
    if (*inewsprog == '\0') {
      fprintf (stderr, "error: posting option not configured\n");
      fflush  (stderr);
      return 1;
    }
    if (verbose) {
      fprintf (stderr, "posting part (%03d/%03d) ... ",
	       partno, numparts);
      fflush  (stderr);
    }
    sprintf (command, inewsprog);

    if ((outfile = popen (command, "w")) == NULL) {
      sprintf (ENCerrfile, "popen(\"%s\")", command);

      if (verbose)
	fprintf (stderr, "failed.\n");

      return 1;
    }
    /*
     * print headers
     */
    fprintf (outfile, "Subject: %s\n",    subline);
    fprintf (outfile, "Newsgroups: %s\n", outfilename);
  }
#endif
  else /* if (output == FLAG_TOFILE) */ {
    if (verbose) {
      fprintf (stderr, "encoding part (%03d/%03d) into %s ... ",
	       partno, numparts, outfilename);
      fflush  (stderr);
    }
    if ((outfile = fopen (outfilename, "wb")) == NULL) {
      sprintf (ENCerrfile, "fopen(\"%s\")", outfilename);

#ifndef _WIN
      if (verbose)
	fprintf (stderr, "failed.\n");
#endif

      return 1;
    }
  }

  /*
   * if we have an introfile, we send it as the zeroeth part
   */

  if (introfile != NULL && (partno == 0 || output == FLAG_STDOUT)) {
    if ((intro = fopen (introfile, "r")) == NULL) {
#ifndef _WIN
      if (verbose)
	fprintf (stderr, "(introfile not found)");
      else if (output != FLAG_STDOUT)
	fprintf (stderr, "Warning: introfile not found (ignored)\n");
#endif
    }
    else {
      /*
       * end headers for mailing and posting
       */
      if (output == FLAG_MAILTO || output == FLAG_INEWS)
	fprintf (outfile, "\n");

      while (!feof (intro)) {
	if ((count = fread (tmpbuf, 1, 256, intro)) > 0)
	  fwrite (tmpbuf, 1, count, outfile);
      }
      fclose (intro);
    }
  }

  if (partno > 0) {
    res = EncodePart (encoding, linperfile, 
		      partno,   numparts,
		      basename, filemode, 
		      mimeid,   mimetype, 
		      infile,   outfile);
  }

  if (res) {
    sprintf (ENCerrfile, "EncodePart()");
#ifndef _WIN
    if (verbose)
      fprintf (stderr, "failed.\n");
#endif
  }
  else {
#ifndef _WIN
    if (verbose)
      fprintf (stderr, "ok.\n");
#endif
  }

  if (output == FLAG_STDOUT)
    ;
#ifndef _DOS  
  else if (output == FLAG_MAILTO)
    pclose (outfile);
  else if (output == FLAG_INEWS)
    pclose (outfile);
#endif
  else
    fclose (outfile);

  return res;
}

/*
 * destination is misused as
 *     email-address   if output == FLAG_MAILTO
 *     newsgroup       if output == FLAG_INEWS
 */

int
HandleFile (int encoding,   int linperfile, 
	    char *filename, char *destination,
	    char *destname, char *introfile,
	    char *subject,  int output)
{
  char basename[256], mimeid[256], outfilename[256], tmext[256], *ptr;
  int part, numparts, themode;
  mimemap *miter=mimetable;
  struct stat finfo;
  long flength, bpl;
  FILE *infile;

  if (filename == NULL && destname == NULL) {
#ifndef _WIN
    fprintf (stderr, "error: filename unknown in HandleFile(?)\n");
#endif
    return 1;
  }

  if ((ptr = _FP_strrchr ((destname == NULL) ? filename : destname,
#ifdef _DOS
			  '\\'
#else
			  '/'
#endif
			  )) != NULL) {
    strcpy (basename, ptr + 1);
  }
  else
    strcpy (basename, ((destname==NULL)?filename:destname));

  /*
   * UU and XX encode 45 bytes per line; Base64 encodes 57 bytes per line.
   * Needed to calculate the number of parts.
   */

  bpl = (encoding == ENC_TYPE_UU  || encoding == ENC_TYPE_XX) ? 45 : 57;

  /*
   * determine mime-type
   */

  if ((ptr = _FP_strrchr (basename, '.')) != NULL) {
    while (miter->extension && _FP_stricmp (ptr+1, miter->extension) != 0)
      miter++;
  }
  else
    miter = NULL;

  strcpy (tmext, basename);
  if ((ptr = _FP_strrchr (tmext, '.')) != NULL)
    *ptr = '\0';

#ifdef _DOS
  if (strlen (tmext) > 8)
    tmext[8] = '\0';
#endif

  if (filename == NULL) { /* reading from stdin? */
    infile     = stdin;
    flength    = 42;       /* don't know ... */

    if (linperfile == 0)
      numparts =  1;
    else
      numparts = -1;       /* don't know, too */

    themode = 6*64+4*8+4;  /* don't know file mode, assume -rw-r--r-- */
  }
  else {
    if ((infile = fopen (filename, "rb")) == NULL) {
#ifndef _WIN
      fprintf (stderr, "error: cannot read %s\n", filename);
#endif
      return 1;
    }
#ifndef _DOS
    if (fstat (fileno(infile), &finfo) == 0)
      themode = (int) finfo.st_mode & 07777;
    else
#endif
      themode = 6*64+4*8+4; /* don't know file mode, assume -rw-r--r-- */

    /*
     * query file length. should also be in finfo.st_size, if the above
     * stat() succeeded. This works in any case.
     */

    fseek (infile, 0L, SEEK_END);
    flength = ftell (infile);
    fseek (infile, 0L, SEEK_SET);

    if (linperfile == 0)
      numparts = 1;
    else
      numparts = (int) ((flength + (linperfile*bpl-1)) / (linperfile*bpl));
  }

  /*
   * construct more or less unique mime-id
   */

  sprintf (mimeid, "UUDV-%ld.%ld.%s",
	   (long) time(NULL), flength, basename);

  if (output == FLAG_MAILTO || output == FLAG_INEWS)
    strcpy (outfilename, destination);

  /*
   * do the encoding
   */

  for (part=0; !feof (infile); part++) {
    if (output == FLAG_TOFILE) {
      if (destination && *destination) {
	sprintf (outfilename, "%s%s%s.%03d",
		 destination,
#ifndef _DOS
		 (destination[strlen(destination)-1]=='/')?"":"/",
#else
		 (destination[strlen(destination)-1]=='\\')?"":"\\",
#endif
		 tmext,
		 part);
      }
      else {
	sprintf (outfilename, "%s.%03d", 
		 tmext, part);
      }
    }

    if (HandlePart (encoding, linperfile,
		    part,     numparts,
		    basename, subject,
		    mimeid,
		    (miter && miter->mimetype) ? miter->mimetype : NULL,
		    outfilename,
		    introfile,
		    infile,
		    themode,
		    output))
      break;
  }
  fclose (infile);

  return 0;
}

int EncodeGErr (char *etext)
{
  strcpy (etext, ENCerrfile);
  return 0;
}

/*
 * define a main function for the standalone program in DOS/Unix
 */

#ifdef STANDALONE

void 
usage (char *argv0)
{
  if (_FP_stristr (argv0, "uuencode") != NULL) {
    printf ("\n\
  uuencode -- a simple encoder (w) 1995 Frank Pilhofer\n\n\
  usage:\n\
    %s [infile] remotefile\n\n\
",
	    argv0);
    printf ("\
\tinfile      the local file, where to read data from. If no infile\n\
\t            is given, or infile is a single hyphen, the standard\n\
\t            input is used instead.\n\
\tremotefile  the name as which the recepient will receive the file\n\
\n\
  For much more powerful encoding facilities, try calling this program\n\
  as 'uuenview'.\n\
\n\
");
    return;
  }
  printf ("\n\
  UUENVIEW %spl%s -- a simple encoder (w) 1995 Frank Pilhofer\n\n\
  usage:\n\
    %s [-type] [-lines] ", VERSION, PATCH, argv0);
#ifndef _DOS
  printf ("[-m address] ");
  printf ("[-p newsgroup] ");
  printf ("\n\t\t");
  printf ("[-s subject] ");
  printf ("[-i introfile] ");
  printf ("[-o[d path]] ");
#else
  printf ("[-od path] ");
#endif
  printf ("file(s)\n\n");
  printf ("\
\ttype      one of 'u', 'x', 'b' for UUencoding, XXencoding or Base64\n\
\t          encoding, respectively. Defaults to uuencoding.\n\
\tlines     sets the number of encoded lines per file. Values smaller\n\
\t          than 200 are ignored. 1000 lines encode 45kb UU/XX and 57kb\n\
\t          Base64 data. Default is unlimited.\n\
");
#ifndef _DOS
  printf ("\
\taddress   comma-separated list of email recepients.\n\
\tnewsgroup comma-separated list of newsgroups to post the file to.\n\
\tsubject   used on the subject line for emailing and posting.\n\
\tintrofile if the file exists, send/post it as zeroeth part.\n\
");
#endif
  printf ("\
\tfile(s)   one or more files to be encoded.\n\
");
#ifdef _DOS
  printf ("\
\t          The encoded files are saved to files with the same base\n\
\t          name as the original but with an extension of .001, .002\n\
\t          etc. If you give a pathname with the -od parameter, the\n\
\t          files are written to that directory, otherwise the're\n\
\t          written to the current working directory.\n\
");
#else
  printf ("\
\t          If -o is used, the encoded files will be saved to files\n\
\t          with the same base name as the original but an extension\n\
\t          of .001, .002 etc. If you use -od and give an existing\n\
\t          pathname, the encoded files are written to that directory\n\
\t          instead of the current working directory.\n\
");
  printf ("\
\t          If neither of -o, -m, -p is specified, output is sent to\n\
\t          standard output, and the maximum line count is ignored.\n\
");
#endif
  printf ("\n\
  example:\n\
");
#ifdef _DOS
  printf ("\
    %s -b -2000 -o uuenview.exe\n\
\tEncodes 'uuenview.exe' as Base64 into 2000-line chunks, and writes\n\
\tthe result to uuenview.001 and uuenview.002.\n\
\n\
",
	  argv0);
#else
  printf ("\
    %s -b -2000 -m root -o uudeview.tar.gz\n\
\tEncodes 'uudeview.tar.gz' as Base64 into 2000-line chunks. It is\n\
\tboth mailed to your system administrator and written to the files\n\
\tuudeview.001 and uudeview.002\n\
\n\
",
	  argv0);
#endif

  return;
}

int
main (int argc, char *argv[])
{
  int outflags[4], tostdout, linperfile, uuencode, encoding;
  int index, introfile, subject, count, fileflag, stdinused;
  int iskipflag;
  char temp[512], filename[521], usename[512], *piter;
  FILE *testit;

  /*
   * set defaults
   */
  outflags[FLAG_TOFILE] = -1;
  outflags[FLAG_MAILTO] = -1;
  outflags[FLAG_INEWS]  = -1;
  subject               = -1;
  introfile             = -1;
  tostdout              =  1;
  linperfile            =  0;
  uuencode              =  0;
  encoding              =  ENC_TYPE_UU;
  count                 =  0;
  stdinused             =  0;

  if (argc < 2) {
    usage (argv[0]);
    return 1;
  }
  if (_FP_stristr (argv[0], "uuencode") != NULL)
    uuencode = 1; /* uuencode compatibility */

  /*
   * In DOS, the default is to create files, not to send it to stdout
   */

#ifdef _DOS
  outflags[FLAG_TOFILE] = -1;
  tostdout              =  1;
#endif  

#ifndef _DOS
  /*
   * Check for environment variable called INEWS and override
   * compile-time option if present
   */
  if (getenv ("INEWS") && *getenv ("INEWS"))
    inewsprog = getenv ("INEWS");
#endif

  /*
   * browse command line flags
   */
  for (index=1; index<argc; index++) {
    if (*argv[index] == '-') {
      switch (argv[index][1]) {
      case '\0':/* this is a file name */break;
      case 'b': encoding = ENC_TYPE_B64; break;
      case 'u': encoding = ENC_TYPE_UU;  break;
      case 'x': encoding = ENC_TYPE_XX;  break;
#ifndef _DOS
      case 'm': 
	if (index+1<argc && argv[index+1][0] != '-') {
	  outflags[FLAG_MAILTO] = ++index; 
	  tostdout              = 0;
	}
	else
	  fprintf (stderr, "error: -m requires a parameter\n");
	break;
      case 'p':
	if (index+1<argc && argv[index+1][0] != '-') {
	  outflags[FLAG_INEWS]  = ++index;
	  tostdout              = 0;
	}
	else
	  fprintf (stderr, "error: -p requires a parameter\n");
	break;
#endif
      case 'o':
	if (argv[index][2] == 'd') {
	  if (index+1<argc && argv[index+1][0] != '-') {
	    outflags[FLAG_TOFILE] = ++index;
	    tostdout              = 0;
	  }
	  else
	    fprintf (stderr, "error: -od requires a parameter\n");
	}
	else {
	  outflags[FLAG_TOFILE] = index;
	  tostdout              = 0;
	}
	break;
      case 'i':
	if (index+1<argc && argv[index+1][0] != '-') {
	  introfile = ++index;
	}
	else
	  fprintf (stderr, "error: -i requires a parameter\n");
	break;
      case 's':
	if (index+1<argc && argv[index+1][0] != '-') {
	  subject   = ++index;
	}
	else
	  fprintf (stderr, "error: -s requires a parameter\n");
	break;
      case 'v':
	verbose++;
	break;
      case '-':
      case 'h':
      case '?':
	usage(argv[0]);
	return 0;
	break;
      case 'V':
	fprintf (stdout, "uuenview %spl%s compiled on %s\n",
		 VERSION, PATCH, __DATE__);
	return 0;
	break;
      default: /* should be a line count from -1000 */
	if (argv[index][1]>='0' && argv[index][1]<='9') {
	  linperfile = atoi(argv[index] + 1);
	}
	else {
	  fprintf (stderr, "warning: unknown option '%s' ignored.\n",
		   argv[index]);
	}
      }
    }
  }
  /*
   * check integrity
   */

  if (linperfile != 0 && linperfile < 200) {
    fprintf (stderr, "warning: lines per file must be >= 200 (ignored).\n");
    linperfile=0;
  }
  if (linperfile != 0 && tostdout) {
    fprintf (stderr, "warning: cannot split file on standard output (use -o)\n");
    linperfile=0;
  }
  if (introfile>0 && tostdout) {
    fprintf (stderr, "warning: -i not possible on standard output (use -m or -p)\n");
    introfile=-1;
  }
  if (introfile>0) {
    if ((testit = fopen (argv[introfile], "r")) == NULL) {
      fprintf (stderr, "warning: introfile %s not readable.\n",
	       argv[introfile]);
      introfile=-1;
    }
    else
      fclose (testit);
  }
  if (subject>0 && tostdout) {
    fprintf (stderr, "warning: -s not possible on standard output\n");
    subject=-1;
  }
  if (encoding!=ENC_TYPE_UU && encoding!=ENC_TYPE_XX &&
      encoding!=ENC_TYPE_B64) {
    fprintf (stderr, "warning: unknown encoding method (%d)?\n",
	     encoding);
    encoding=ENC_TYPE_UU;
  }

#ifdef _DOS
  if (tostdout==0 && outflags[FLAG_TOFILE]==-1) {
    fprintf (stderr, "error: no output defined?\n");
    exit    (2);
  }
#endif

  /*
   * okay, now process the files
   */

  for (index=1, iskipflag=0; index<argc; index+=iskipflag+1) {
    iskipflag = 0;

    if (*argv[index] == '-' && argv[index][1] != '\0') {
      switch (argv[index][1]) {
      case 'm': /* skip parameters of options */
      case 'p':
      case 's':
      case 'i':
	if (index+1 < argc && argv[index+1][0] != '-')
	  index++;
	break;
      case 'o': /* may or may have not a parameter */
	if (argv[index][2]=='d' && index+1<argc && argv[index+1][0]!='-')
	  index++;
	break;
      default:  /* parameter without option */
	break;
      }
    }
    else /* this is a filename */ {
      if (uuencode) {
	/*
	 * we're in uuencode compatibility mode. This means the actual
	 * parameter is the file name on disk, the next parameter, if
	 * it exists and is not an option, is the name for the encoded
	 * file. If there is no next parameter, we shall read from stdin
	 * and use the given name as output filename
	 */
	if (index+1<argc && argv[index+1][0] != '-') {
	  strcpy (filename, argv[index]);
	  strcpy (usename,  argv[index+1]);
	  iskipflag = 1; /* ignore next argument */
	}
	else {
	  filename[0] = '\0';
	  strcpy (usename, argv[index]);
	}
      }
      else if (argv[index][0]=='-' && argv[index][1]=='\0') {
	/*
	 * supposed to read from stdin. we expect the next parameter to be
	 * the name to be used
	 */
	if (index+1<argc && argv[index+1][0] != '-') {
	  strcpy (usename, argv[index+1]);
	  filename[0] = '\0';
	  iskipflag = 1; /* ignore next argument */
	}
	else {
	  fprintf (stderr, "error: need additional name for file from standard input\n");
	  continue;
	}
      }
      else {
	strcpy (filename, argv[index]);
	usename[0] = '\0';
      }

      if (filename[0] == '\0') {
	if (stdinused) {
	  fprintf (stderr, "error: standard input used more than once\n");
	  continue;
	}
	stdinused++;

	if (((outflags[FLAG_INEWS]  > 0) ? 1 : 0) +
	    ((outflags[FLAG_MAILTO] > 0) ? 1 : 0) +
	    ((outflags[FLAG_TOFILE] > 0) ? 1 : 0) > 1) {
	  fprintf (stderr, "error: can use standard input only once\n");
	  continue;
	}
      }
      else if ((testit = fopen (argv[index], "r")) == NULL) {
	fprintf (stderr, "error: '%s' unreadable.\n", argv[index]);
	continue;
      }
      else
	fclose (testit);

      fileflag = 0;

#ifndef _DOS
      /*
       * post it
       */

      if (outflags[FLAG_INEWS] > 0) {
	if (HandleFile (encoding,
			linperfile,
			(filename[0]) ? filename        : NULL,
			argv[outflags[FLAG_INEWS]],
			(usename[0])  ? usename         : NULL,
			(introfile>0) ? argv[introfile] : NULL,
			(subject>0)   ? argv[subject]   : NULL,
			FLAG_INEWS) == 0)
	  fileflag++;
      }

      /*
       * mail it separately to each recepient
       */

      if (outflags[FLAG_MAILTO] > 0) {
	strcpy (temp, argv[outflags[FLAG_MAILTO]]);
	piter = strtok (temp, ", ");
	while (piter) {
	  if (HandleFile (encoding,
			  linperfile,
			  (filename[0]) ? filename        : NULL,
			  piter,
			  (usename[0])  ? usename         : NULL,
			  (introfile>0) ? argv[introfile] : NULL,
			  (subject>0)   ? argv[subject]   : NULL,
			  FLAG_MAILTO) == 0)
	    fileflag++;

	  piter = strtok (NULL, ", ");
	}
      }
#endif

      /*
       * store output into a file
       */
      if (outflags[FLAG_TOFILE] > 0) {
	if (HandleFile (encoding,
			linperfile,
			(filename[0]) ? filename        : NULL,
			(argv[outflags[FLAG_TOFILE]][0]=='-') ? NULL :
			argv[outflags[FLAG_TOFILE]],
			(usename[0])  ? usename         : NULL,
			(introfile>0) ? argv[introfile] : NULL,
			(subject>0)   ? argv[subject]   : NULL,
			FLAG_TOFILE) == 0)
	  fileflag++;
      }

      /*
       * send it to stdout
       */
      if (tostdout) {
	if (HandleFile (encoding,
			linperfile,
			(filename[0]) ? filename        : NULL,
			NULL,
			(usename[0])  ? usename         : NULL,
			NULL,
			NULL,
			FLAG_STDOUT) == 0)
	  fileflag++;
      }

      if (fileflag > 0)
	count++;

    } /* end file processing */
  } /* end loop */

  if (count==0) {
    fprintf (stderr, "error: no files.\n");
  }

  return 0;
}

#endif /* STANDALONE */

