--- smtpserver/smtpserver.c.orig	Thu Oct 17 20:33:38 1996
+++ smtpserver/smtpserver.c	Wed Nov  6 16:09:38 1996
@@ -85,6 +85,9 @@
 # include <syslog.h>
 #endif	/* HAVE_SYSLOG */
 #include <identuser.h>
+#ifdef USE_TRANSLATION
+# include "libtrans.h"
+#endif /* USE_TRANSLATION */
 
 #ifndef	SIGCHLD
 #define	SIGCHLD	SIGCLD
@@ -190,6 +193,11 @@
 int	pid, routerpid;
 FILE	*logfp = NULL;
 int	D_alloc = 0;
+#ifdef USE_TRANSLATION
+int     X_translation=0;
+int     X_8bit=0;
+int	X_settrrc=9;
+#endif /* USE_TRANSLATION */
 
 static char *m200 = "2.0.0";
 static char *m400 = "4.0.0";
@@ -369,7 +377,11 @@
 	  exit(1);
 	}
 	/* optarg = NULL; */
+#ifdef USE_TRANSLATION
+	while ((c = getopt(argc, argv, "aBighl:np:L:M:P:R:s:VvX8")) != EOF) {
+#else /* USE_TRANSLATION */
 	while ((c = getopt(argc, argv, "aBighl:np:L:M:P:R:s:Vv")) != EOF) {
+#endif /* USE_TRANSLATION */
 	  switch (c) {
 	    case 'a':
 		ident_flag = 1;
@@ -424,6 +436,14 @@
 		prversion("smtpserver");
 		exit(0);
 		break;	/* paranoia */
+#ifdef USE_TRANSLATION
+	    case 'X':
+		X_translation=1;
+		break;
+	    case '8':
+		X_8bit=1;
+		break;
+#endif /* USE_TRANSLATION */
 	    default:
 		fprintf(stderr,
 			"%s: Unknown option, c=%d ('%c')\n",progname,c,c);
@@ -444,6 +464,17 @@
 	  }
 #endif	/* CHECK42INETD */
 	if (errflg || optind != argc) {
+#ifdef USE_TRANSLATION
+#ifdef	USE_INET
+	  fprintf(stderr,
+		  "Usage: %s [-aBivgnVX8] [-s xx] [-L maxLoadAvg] [-M SMTPmaxsize] [-R rtrprog] [-p port#] [-P postoffice] [-l logfile]\n",
+		  progname);
+#else	/* !USE_INET */
+	  fprintf(stderr,
+		  "Usage: %s [-aBivgnVX8] [-s xx] [-L maxLoadAvg] [-M SMTPmaxsize] [-R rtrprog] [-P postoffice] [-l logfile]\n",
+		  progname);
+#endif	/* USE_INET */
+#else /* USE_TRANSLATION */
 #ifdef	USE_INET
 	  fprintf(stderr,
 		  "Usage: %s [-aBivgnV] [-s xx] [-L maxLoadAvg] [-M SMTPmaxsize] [-R rtrprog] [-p port#] [-P postoffice] [-l logfile]\n",
@@ -453,6 +484,7 @@
 		  "Usage: %s [-aBivgnV] [-s xx] [-L maxLoadAvg] [-M SMTPmaxsize] [-R rtrprog] [-P postoffice] [-l logfile]\n",
 		  progname);
 #endif	/* USE_INET */
+#endif /* USE_TRANSLATION */
 	  exit(1);
 	}
 
@@ -1701,6 +1733,11 @@
 	int localsocksize;
 
 	int VerboseCommand = 0;
+#ifdef USE_TRANSLATION
+	char lang[4];
+
+	lang[0]='\0';
+#endif
 
 	pid = getpid();
 	if (!logfp)
@@ -1724,8 +1761,19 @@
 	  /* Success with it :) */
 	  struct hostent *hostent = gethostbyaddr((void*)&localsock.sin_addr,4,
 						  localsock.sin_family);
-	  if (hostent)
+	  if (hostent) {
 	    strcpy(myhostname,hostent->h_name);
+#ifdef USE_TRANSLATION
+	    strncpy(lang,hostent->h_name,3);
+	    lang[3]='\0';
+	    X_settrrc=settrtab_byname(lang);
+	  }
+	  if (!(*lang) || (X_settrrc < 0)) {
+		/* we don't know our codetable, hush client away */
+	    type(451, "Server could not setup translation.", NULL);
+	    return;
+#endif /* USE_TRANSLATION */
+	  }
 	}
 
 	/* re-opening the log ?? */
@@ -1751,8 +1799,14 @@
 	}
 #endif
 
+#ifdef USE_TRANSLATION
+	type(220, NULL, "%s ZMailer Server %s ESMTP%s (%s) ready at %s",
+	     myhostname, VersionNumb, ident_flag ? "+IDENT":"",
+	     *lang?lang:"nulltrans", cp);
+#else /* USE_TRANSLATION */
 	type(220, NULL, "%s ZMailer Server %s ESMTP%s ready at %s",
 	     myhostname, VersionNumb, ident_flag ? "+IDENT":"", cp);
+#endif /* USE_TRANSLATION */
 	fflush(stdout);
 
 	state = Hello;
@@ -2701,6 +2755,16 @@
 	/* XXX: HEADERS -> MIME-2 */
 }
 
+#ifdef USE_TRANSLATION
+static void header_from_mime(buf, lenptr, maxlen)
+	char *buf;
+	int *lenptr;
+	int maxlen;
+{
+	/* XXX: HEADERS -> MIME-2 */
+}
+#endif /* USE_TRANSLATION */
+
 /* Implement SMTP DATA filter */
 
 /*
@@ -2793,6 +2857,31 @@
 	int from__err = 0;
 	int linecnt = 0;
 	int was8bit = 0;
+#ifdef USE_TRANSLATION
+	int wi;
+	char hdr_cte[4000],hdr_ct[4000];
+	int delay_cte = 0, delay_ct = 0;
+	int ct_is_text = 1;
+#define CTE_8BIT 0
+#define CTE_BASE64 1
+#define CTE_QP 2
+	int cte = CTE_8BIT;
+	int do_decode=0,do_translate=0;
+	int qp_chars=0,qp_hex=0;
+	int b64decoding=1,b64eod=0,b64i=0;
+	char b64c[4];
+	static char index_64[128] = {
+		-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
+		-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
+		-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63,
+		52,53,54,55, 56,57,58,59, 60,61,-1,-1, -1,-1,-1,-1,
+		-1, 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,-1, -1,-1,-1,-1,
+		-1,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,-1, -1,-1,-1,-1
+	};
+#define char64(c)  (((c) < 0 || (c) > 127) ? -1 : index_64[(c)])
+#endif /* USE_TRANSLATION */
 
 	fflush(stdout);
 
@@ -2828,9 +2917,18 @@
 		  if (state & O_) {
 		    if (state == endstate) {
 		      if (col > 0) {
+#ifdef USE_TRANSLATION
+			if (has8bit && !X_8bit)
+			  header_to_mime(linebuf,&col,sizeof(linebuf));
+			else
+			  header_from_mime(linebuf,&col,sizeof(linebuf));
+			for (wi=0;wi<col;wi++)
+			  putc(TR_IN(linebuf[wi]),out);
+#else /* USE_TRANSLATION */
 			if (has8bit)
 			  header_to_mime(linebuf,&col,sizeof(linebuf));
 			fwrite(linebuf,1,col,out);
+#endif /* USE_TRANSLATION */
 		      }
 		      return cnt;
 		    }
@@ -2869,17 +2967,72 @@
 		      *s != '\r' && *s != '\n')
 		    break;
 		if (s == eol) {	/* All-blank line */
+#ifdef USE_TRANSLATION
+		  /* We have all info from the headers, time to make decision */
+		  if (X_8bit && ct_is_text && cte)
+		    do_decode=cte;
+		  if (X_translation && X_8bit && ct_is_text && (X_settrrc == 0))
+		    do_translate=1;
+		  if (logfp)
+		    fprintf(logfp,"%d#\t(8bit decode: %s, translate: %s) [%s%s,%s]\n",pid,
+		      do_decode?"YES":"NO",do_translate?"YES":"NO",
+		      X_translation?"-X ":"",
+		      X_8bit?"-8":"",
+		      ct_is_text?"text":"non-text");
+		  /* write out content-type and content-transfer-encoding */
+		  if (delay_ct) {
+		    if (do_translate) {
+		      /* Remove "charset=xxx".  It is mismatching anyway */
+		      char *p,*q,*r;
+		      p=hdr_ct;
+		      while (*p && (*p != ';')) p++; /* skip to attrs */
+		      q=p;
+		      while (*p == ';') { /* check attributes */
+			r=p+1;
+			while (*r && ((*r == ' ') || (*r == '\t'))) r++;
+			if (CISTREQN(r,"CHARSET=",8)) { /* skip it */
+			  p++;
+			  while (*p && (*p != ';') && (*p != '\n')) p++;
+			} else { /* copy it */
+			  *(q++)=*(p++);
+			  while (*p && (*p != ';')) *(q++)=*(p++);
+			}
+		      }
+		      while (*p) *(q++)=*(p++);
+		      *q='\0';
+		    }
+		    fwrite(hdr_ct,1,strlen(hdr_ct),out);
+		  }
+		  if (delay_cte) {
+		    if (do_decode) {
+		      /* Transfer-encoding changed to 8bit */
+		      fputs("Content-Transfer-Encoding: 8bit\n",out);
+		    } else {
+		      fwrite(hdr_cte,1,strlen(hdr_cte),out);
+		    }
+		  }
+#endif /* USE_TRANSLATION */
 		  if (col > 0)
 		    fwrite(linebuf,1,col,out);
 		  break;	/* Into the body processing */
 		}
 		++linecnt;
 		if (*linebuf == ' ' || *linebuf == '\t') {
+#ifdef USE_TRANSLATION
+		  if (has8bit && !X_8bit)
+		    header_to_mime(linebuf,&col,sizeof(linebuf));
+		  else
+		    header_from_mime(linebuf,&col,sizeof(linebuf));
+		  if (col > 0)
+		    for (wi=0;wi<col;wi++)
+		      putc(TR_IN(linebuf[wi]),out);
+#else /* USE_TRANSLATION */
 		  if (has8bit)
 		    header_to_mime(linebuf,&col,sizeof(linebuf));
-		  has8bit = 0;
 		  if (col > 0)
 		    fwrite(linebuf,1,col,out);
+#endif /* USE_TRANSLATION */
+		  has8bit = 0;
 		  col = 0;
 		  continue;	/* continuation line.. */
 		}
@@ -2896,6 +3049,60 @@
 		    has8bitsum += has8bit;
 		  }
 		}
+
+		if (CISTREQN(linebuf,"Precedence:",11)) {
+		  s = linebuf+11;
+		  while (*s == ' ' || *s == '\t') ++s;
+		  if ((eol - s) < 4) continue; /* Hmm.. */
+		  if (CISTREQN("junk",s,4)) {
+		    mail_priority = _MAILPRIO_JUNK;
+		  } else if (CISTREQN("bulk",s,4)) {
+		    mail_priority = _MAILPRIO_BULK;
+		  }
+		}
+
+#ifdef USE_TRANSLATION
+		if (X_translation && (X_settrrc == 0)) {
+		  if (CISTREQN(linebuf,"Content-Transfer-Encoding:",26)) {
+		    if (1) {
+		      strcpy(hdr_cte,linebuf);
+		      delay_cte = 1;
+		      col=0;
+		      has8bit = 0;
+		      s = linebuf+26;
+		      while (*s == ' ' || *s == '\t') ++s;
+		      if ((eol - s) < 4) continue; /* Hmm.. */
+		      if (CISTREQN("8bit",s,4)) {
+			cte=CTE_8BIT;
+		      } else if (CISTREQN("base64",s,6)) {
+			cte=CTE_BASE64;
+		      } else if (CISTREQN("quoted-printable",s,16)) {
+			cte=CTE_QP;
+		      }
+		      continue; /* do not write out this one */
+		    }
+		  } else if (CISTREQN(linebuf,"Content-Type:",13)) {
+		    if (1) {
+		      strcpy(hdr_ct,linebuf);
+		      delay_ct = 1;
+		      col=0;
+		      has8bit = 0;
+		      s = linebuf+13;
+		      while (*s == ' ' || *s == '\t') ++s;
+		      if ((eol - s) < 10) continue; /* Hmm.. */
+#ifdef PARANOID_TRANSLATION
+		      if (CISTREQN("text",s,4)) {
+			ct_is_text=1;
+		      } else {
+			ct_is_text=0;
+		      }
+#endif /* PARANOID_TRANSLATION */
+		      continue; /* do not write out this one */
+		    }
+		  }
+		}
+#endif /* USE_TRANSLATION */
+
 		if (linecnt == 1 && (strncmp("From ",linebuf,5)==0 ||
 				     strncmp(">From ",linebuf,6)==0)) {
 #if 0
@@ -2907,25 +3114,24 @@
 		  has8bit = 0;
 		  continue;
 		}
+#ifdef USE_TRANSLATION
+		if (has8bit && !X_8bit)
+		  header_to_mime(linebuf,&col,sizeof(linebuf));
+		else
+		  header_from_mime(linebuf,&col,sizeof(linebuf));
+		/* Write the line out */
+		if (col > 0)
+		  for (wi=0;wi<col;wi++)
+		    putc(TR_IN(linebuf[wi]),out);
+#else /* USE_TRANSLATION */
 		if (has8bit)
 		  header_to_mime(linebuf,&col,sizeof(linebuf));
-		has8bit = 0;
 		/* Write the line out */
 		if (col > 0)
 		  fwrite(linebuf,1,col,out);
-		col = 0;
-
+#endif /* USE_TRANSLATION */
 		has8bit = 0;
-		if (CISTREQN(linebuf,"Precedence:",11)) {
-		  s = linebuf+11;
-		  while (*s == ' ' || *s == '\t') ++s;
-		  if ((eol - s) < 4) continue; /* Hmm.. */
-		  if (CISTREQN("junk",s,4)) {
-		    mail_priority = _MAILPRIO_JUNK;
-		  } else if (CISTREQN("bulk",s,5)) {
-		    mail_priority = _MAILPRIO_BULK;
-		  }
-		}
+		col = 0;
 	}
 	if (logfp && verbose)
 	  fprintf(logfp,"%d#\t(mail_priority=%d)\n",pid,mail_priority);
@@ -2956,8 +3162,67 @@
 			  putc((state>>8), out);
 			state = (char)state;
 		}
-		if (!ferror(out))
-			putc(c, out);
+		if (!ferror(out)) {
+#ifdef USE_TRANSLATION
+			if (do_decode == CTE_QP) {
+				if (!qp_chars && c == '=') {
+					qp_chars = 2;
+					qp_hex = 0;
+					continue;
+				}
+				if (qp_chars && c == '\n') {
+					qp_chars = 0;
+					continue;
+				}
+				if (qp_chars == 2 && (c == ' ' || c == '\t')) {
+					continue;
+				}
+				if (qp_chars && ((c >= '0' && c <= '9') ||
+						 (c >= 'A' && c <= 'F') ||
+						 (c >= 'a' && c <= 'f'))) {
+					qp_hex <<= 4;
+					if (c >= '0' && c <= '9')
+						qp_hex += (c - '0');
+					if (c >= 'A' && c <= 'F')
+						qp_hex += (c - 'A' + 10);
+					if (c >= 'a' && c <= 'f')
+						qp_hex += (c - 'a' + 10);
+					--qp_chars;
+					if (!qp_chars) c = qp_hex;
+					else continue;
+				} else if (qp_chars)
+					qp_chars = 0;
+			} else if (do_decode == CTE_BASE64) {
+				if (b64decoding) {
+					if ((c == ' ') || (c == '\t') ||
+					    (c == '\n') || (c == '\r'))
+						continue;
+					b64c[b64i++]=char64(c);
+					if (c == '=') {
+						b64eod=1;
+						continue;
+					}
+					if (b64i < 2) continue;
+					if (b64i == 2) {
+						c=(b64c[0]<<2) |
+						  ((b64c[1]&0x30)>>4);
+					} else if (b64i == 3) {
+						c=((b64c[1]&0x0f)<<4) |
+						  ((b64c[2]&0x3c)>>2);
+					} else {
+						c=(b64c[2]<<6) |
+						  b64c[3];
+						b64i=0;
+						if (b64eod) b64decoding=0;
+					}
+				}
+			}
+			if (do_translate)
+				putc(TR_IN(c), out);
+			else
+#endif /* USE_TRANSLATION */
+				putc(c, out);
+		}
 	}
 	fflush(stdout);
 	return cnt;
