/* MIME.C */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#define TEXT004 "converting %s...\n"

#define TEXT050 "Cannot open input file %s \n"
#define TEXT902 "usage:\n%s from to subject inputfile [inputfile...]\n\n"
#define BOUNDARY "----=Andreas_Graf_mail_converter"

/*
 * prototypes for internal functions
 */
int encode(FILE *source,char *srcname);
int b64encode(char *target,unsigned char *source,int length);

/**************** main program *****************************/

int main(argc, argv) int argc; char *argv[];
{

  time_t oldtime;
  static char ifn[128];   
  char *s,*d;
  FILE *ifile;
  int retval,i;

  if(argc<5) { printf(TEXT902,argv[0]); exit(1); } /* usage */

  /* mail header */
  time(&oldtime);
  printf("From: %s\nTo: %s\nSubject: %s\nX-Mailer: Andreas Graf mail converter\n",
    argv[1],argv[2],argv[3]);
  printf("MIME-Version: 1.0\nContent-Type: multipart/mixed; boundary=\042%s\042\n\n\n",BOUNDARY);

  for(i=4;i<argc;i++)
  {
    s=argv[i]; d=ifn; while((*d++=*s++)!=0) continue;
    fprintf(stderr,TEXT004,ifn); /* converting... */
    if(*ifn == '-')
    {
        ifile = stdin;
        s = ifn + 1;
    }
    else
    {
        if((ifile=fopen(ifn,"rb")) == 0)
        {
          fprintf(stderr,TEXT050,ifn);  /*cannot open input file!\n*/
          exit(1);
        }
        /* cut off path information */
        s=ifn+strlen(ifn);
        while(s!=ifn && s[-1]!='\\' && s[-1]!=':' && s[-1]!='/') s--;  
    }
    /* coding one file */
    retval=encode(ifile,s); 
    //if(retval) break;
    fclose(ifile);
  }  

  /* mail trailer */
  printf("--%s\n",BOUNDARY);

  return(retval);
} /* end main */



/************* encoding one file ******************/

int encode(FILE *in,char *source)
{
  size_t len;
  char txt_buf[128];
  unsigned char bin_buf[100];

  /* create header lines */
  printf("--%s\nContent-Type: application/octet-stream; name=\042%s\042\n",BOUNDARY,source);
  printf("Content-Transfer-Encoding: base64\n\n");

  /* encode the file */
  do
  {
    len = fread(bin_buf, 1, 54, in);    /* read 54 bytes (at most) */
    b64encode(txt_buf, bin_buf,(int)len);
    printf("%s\n", txt_buf);
  } while (len == 54);

  /* end the file */
  printf("\n\n");
  return 0;
}



/************** single character encode *****************/

static char BaseTable[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','+','/'
    };

#define ENC(c)  BaseTable[(c) & 0x3f]

int b64encode(char *target, unsigned char *source, int length)
{
  int split[4];
  if (length > 0x3f)  return 0;         /* can only encode up to 63 chars 
                                           = 84+cr/lf+1(for \0) = 87 encoded */
  while (length > 0)
  {
    split[0] = source[0] >> 2;          /* split first byte to char. 0 & 1 */
    split[1] = source[0] << 4;
    if (length > 1)
    {
      split[1] |= source[1] >> 4;       /* split 2nd byte to char. 1 & 2 */
      split[2] = source[1] << 2;
      if (length > 2)
      {
        split[2] |= source[2] >> 6;     /* split 3rd byte to char. 2 & 3 */
        split[3] = source[2];
      } /* if */
    } /* if */

    *target++ = ENC(split[0]);
    *target++ = ENC(split[1]);
    if (length > 1) *target++ = ENC(split[2]); else *target++ = '=';
    if (length > 2) *target++ = ENC(split[3]); else *target++ = '=';
    source += 3;
    length -= 3;
  } /* while */

  *target = '\0';                       /* end string */
  return 1;
}
