/*
Copyright (c) 1991 Bell Communications Research, Inc. (Bellcore)

Permission to use, copy, modify, and distribute this material 
for any purpose and without fee is hereby granted, provided 
that the above copyright notice and this permission notice 
appear in all copies, and that the name of Bellcore not be 
used in advertising or publicity pertaining to this 
material without the specific, prior written permission 
of an authorized representative of Bellcore.  BELLCORE 
MAKES NO REPRESENTATIONS ABOUT THE ACCURACY OR SUITABILITY 
OF THIS MATERIAL FOR ANY PURPOSE.  IT IS PROVIDED "AS IS", 
WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES.
*/

#include <ctype.h>
#include <string.h>
#include "iso646.h"
#define Char unsigned char

#define NA 100
#define NU 101
#define HT 102
#define LF 103
#define CR 104
#define SP 105
#define EQ 106

static Char basis_base[] =
   "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

static Char index_base[256] = {
    NU,NA,NA,NA, NA,NA,NA,NA, NA,HT,LF,NA, NA,CR,NA,NA,
    NA,NA,NA,NA, NA,NA,NA,NA, NA,NA,NA,NA, NA,NA,NA,NA,
    SP,NA,NA,NA, NA,NA,NA,NA, NA,NA,NA,62, NA,NA,NA,63,
    52,53,54,55, 56,57,58,59, 60,61,NA,NA, NA,EQ,NA,NA,
    NA, 0, 1, 2,  3, 4, 5, 6,  7, 8, 9,10, 11,12,13,14,
    15,16,17,18, 19,20,21,22, 23,24,25,NA, NA,NA,NA,NA,
    NA,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40,
    41,42,43,44, 45,46,47,48, 49,50,51,NA, NA,NA,NA,NA,
    NA,NA,NA,NA, NA,NA,NA,NA, NA,NA,NA,NA, NA,NA,NA,NA,
    NA,NA,NA,NA, NA,NA,NA,NA, NA,NA,NA,NA, NA,NA,NA,NA,
    NA,NA,NA,NA, NA,NA,NA,NA, NA,NA,NA,NA, NA,NA,NA,NA,
    NA,NA,NA,NA, NA,NA,NA,NA, NA,NA,NA,NA, NA,NA,NA,NA,
    NA,NA,NA,NA, NA,NA,NA,NA, NA,NA,NA,NA, NA,NA,NA,NA,
    NA,NA,NA,NA, NA,NA,NA,NA, NA,NA,NA,NA, NA,NA,NA,NA,
    NA,NA,NA,NA, NA,NA,NA,NA, NA,NA,NA,NA, NA,NA,NA,NA,
    NA,NA,NA,NA, NA,NA,NA,NA, NA,NA,NA,NA, NA,NA,NA,NA
};

void
base4(c1, c2, c3, pads, out)
Char c1,c2,c3,*out;
int pads;
{
    *out++ =      basis_base[c1>>2];
    *out++ =      basis_base[((c1 & 0x3)<< 4) | ((int)(c2 & 0xF0) >> 4)];
    if (pads == 2) *out++ = '=';
    else *out++ = basis_base[((c2 & 0xF) << 2) | ((int)(c3 & 0xC0) >>6)];
    if (pads)      *out++ = '=';
    else *out++ = basis_base[c3 & 0x3F];
}

Char c1, c2;

Char *
binc2base(in, out, pos) 
Char in, *out; int pos;
{
    int nbr= pos%3;
    switch(nbr) {
	case 0: c1= in; break;
	case 1: c2= in; break;
	case 2: base4(c1,c2,in,0, out); out+=4;
		if (pos==53) {
    		    *out++ = '\n';
		    *out++ = '\0';
		    return NULL;
		}
    }
    return out;
}

void
bincl2base(out, pos) 
Char *out; int pos;
{
    int nbr= pos%3;
    if (nbr) {
	if (nbr == 1) c2=0;
	base4(c1,c2,0,3-nbr, out);
    	out += 4;
    }
    *out++ = '\n';
    *out++ = '\0';
}

Char *
base2bin(in, out)
Char *in, *out;
{
    Char c1, c2, c3, c4, *outmax=out+72;
    while (out < outmax and (c1 = index_base[*in++]) < NA ) {
        c2 = index_base[*in++];
        *out++ =((c1<<2) | ((int)(c2&0x30)>>4));
	if ((c3 = index_base[*in++])<NA) *out++ = ((c2&017) << 4) | ((int)(c3&0x3C) >> 2);
	if ((c4 = index_base[*in++])<NA) *out++ = ((c3&0x03)<<6) | c4;
    }
    return out;
}

static Char basis_qp[] = "0123456789ABCDEF";
static Char index1_qp[256] = {
    NA,NA,NA,NA,    NA,NA,NA,NA,    NA,NA,NA,NA,   NA,NA,NA,NA,
    NA,NA,NA,NA,    NA,NA,NA,NA,    NA,NA,NA,NA,   NA,NA,NA,NA,
    NA,NA,NA,NA,    NA,NA,NA,NA,    NA,NA,NA,NA,   NA,NA,NA,NA,
     0,16,32,48,    64,80,96,112,   128,144,NA,NA, NA,NA,NA,NA,
    NA,160,176,192, 208,224,240,NA, NA,NA,NA,NA,   NA,NA,NA,NA,
    NA,NA,NA,NA,    NA,NA,NA,NA,    NA,NA,NA,NA,   NA,NA,NA,NA,
    NA,160,176,192, 208,224,240,NA, NA,NA,NA,NA,   NA,NA,NA,NA,
    NA,NA,NA,NA,    NA,NA,NA,NA,    NA,NA,NA,NA,   NA,NA,NA,NA,
    NA,NA,NA,NA,    NA,NA,NA,NA,    NA,NA,NA,NA,   NA,NA,NA,NA,
    NA,NA,NA,NA,    NA,NA,NA,NA,    NA,NA,NA,NA,   NA,NA,NA,NA,
    NA,NA,NA,NA,    NA,NA,NA,NA,    NA,NA,NA,NA,   NA,NA,NA,NA,
    NA,NA,NA,NA,    NA,NA,NA,NA,    NA,NA,NA,NA,   NA,NA,NA,NA,
    NA,NA,NA,NA,    NA,NA,NA,NA,    NA,NA,NA,NA,   NA,NA,NA,NA,
    NA,NA,NA,NA,    NA,NA,NA,NA,    NA,NA,NA,NA,   NA,NA,NA,NA,
    NA,NA,NA,NA,    NA,NA,NA,NA,    NA,NA,NA,NA,   NA,NA,NA,NA,
    NA,NA,NA,NA,    NA,NA,NA,NA,    NA,NA,NA,NA,   NA,NA,NA,NA
};

static Char index2_qp[256] = {
    NA,NA,NA,NA, NA,NA,NA,NA, NA,NA,NA,NA, NA,NA,NA,NA,
    NA,NA,NA,NA, NA,NA,NA,NA, NA,NA,NA,NA, NA,NA,NA,NA,
    NA,NA,NA,NA, NA,NA,NA,NA, NA,NA,NA,NA, NA,NA,NA,NA,
     0, 1, 2, 3,  4, 5, 6, 7,  8, 9,NA,NA, NA,NA,NA,NA,
    NA,10,11,12, 13,14,15,NA, NA,NA,NA,NA, NA,NA,NA,NA,
    NA,NA,NA,NA, NA,NA,NA,NA, NA,NA,NA,NA, NA,NA,NA,NA,
    NA,10,11,12, 13,14,15,NA, NA,NA,NA,NA, NA,NA,NA,NA,
    NA,NA,NA,NA, NA,NA,NA,NA, NA,NA,NA,NA, NA,NA,NA,NA,
    NA,NA,NA,NA, NA,NA,NA,NA, NA,NA,NA,NA, NA,NA,NA,NA,
    NA,NA,NA,NA, NA,NA,NA,NA, NA,NA,NA,NA, NA,NA,NA,NA,
    NA,NA,NA,NA, NA,NA,NA,NA, NA,NA,NA,NA, NA,NA,NA,NA,
    NA,NA,NA,NA, NA,NA,NA,NA, NA,NA,NA,NA, NA,NA,NA,NA,
    NA,NA,NA,NA, NA,NA,NA,NA, NA,NA,NA,NA, NA,NA,NA,NA,
    NA,NA,NA,NA, NA,NA,NA,NA, NA,NA,NA,NA, NA,NA,NA,NA,
    NA,NA,NA,NA, NA,NA,NA,NA, NA,NA,NA,NA, NA,NA,NA,NA,
    NA,NA,NA,NA, NA,NA,NA,NA, NA,NA,NA,NA, NA,NA,NA,NA
};

Char *
bin2qp(in, out, inmax) 
register Char *in, *out, *inmax;
{
    register Char c, *outbeg= out, *outmax= out+72;
    if (strncmp((char *)in,"From ",5) == 0) {  /* avoid sendmail ">From " */
	strncpy((char *)out,"=46rom ",7);
        in += 5; out += 7; 
    } else if (*in == '.') {  /* avoid single period bug */
	strcpy((char *)out,"=2E");  /* hex for "." */
	in++; out +=3;
    }
    while (in<inmax) {
        c= *in++;
        if ((c < 32 and c != '\t') or c == '=' or c >= 127) {
            *out++ = '=';
            *out++ = basis_qp[c>>4];
            *out++ = basis_qp[c&15];
        } else *out++ = c;
        if (out > outmax and in < inmax) {
            *out++ = '=';
            *out++ = '\n';
            *out++ = '\0';
            return in;
        }
    }
    if (out != outbeg and ((c=(char)*(out-1)) == ' ' or c == '\t')) {
        *(out-1) = '='; /* protect trailing space and tab */
        *out++ = basis_qp[c>>4];
        *out++ = basis_qp[c&15];
    }
    *out++ = '\n';
    *out++ = '\0';
    return in;
}

Char *
qp2bin(in, out) 
Char *in, *out;
{
    Char c;
    while ((c = *in++) != 0) {
	if (c == '=') {
	    if ((c = *in++) != 0) *out++ = index1_qp[c] + index2_qp[*in++];
	    else return out; /* end of qp line */
	} else *out++ = c;
    }
    *out++ = '\n';
    *out = '\0';
    return out;
}
