Find documentation etc. on this patch under
	http://free.acrconsulting.co.uk/
diff -Nru mess822-0.58/base64.c mess822-0.58_ofmipd-plus-2.0/base64.c
--- mess822-0.58/base64.c	1970-01-01 01:00:00.000000000 +0100
+++ mess822-0.58_ofmipd-plus-2.0/base64.c	2010-07-22 18:25:48.000000000 +0100
@@ -0,0 +1,90 @@
+#include "base64.h"
+#include "stralloc.h"
+#include "substdio.h"
+#include "str.h"
+
+static char *b64alpha =
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+#define B64PAD '='
+
+/* returns 0 ok, 1 illegal, -1 problem */
+
+int b64decode(in,l,out)
+const unsigned char *in;
+int l;
+stralloc *out; /* not null terminated */
+{
+  int i, j;
+  unsigned char a[4];
+  unsigned char b[3];
+  char *s;
+
+  if (l == 0)
+  {
+    if (!stralloc_copys(out,"")) return -1;
+    return 0;
+  }
+
+  if (!stralloc_ready(out,l + 2)) return -1; /* XXX generous */
+  s = out->s;
+
+  for (i = 0;i < l;i += 4) {
+    for (j = 0;j < 4;j++)
+      if ((i + j) < l && in[i + j] != B64PAD)
+      {
+        a[j] = str_chr(b64alpha,in[i + j]);
+        if (a[j] > 63) return 1;
+      }
+      else a[j] = 0;
+
+    b[0] = (a[0] << 2) | (a[1] >> 4);
+    b[1] = (a[1] << 4) | (a[2] >> 2);
+    b[2] = (a[2] << 6) | (a[3]);
+
+    *s++ = b[0];
+
+    if (in[i + 1] == B64PAD) break;
+    *s++ = b[1];
+
+    if (in[i + 2] == B64PAD) break;
+    *s++ = b[2];
+  }
+  out->len = s - out->s;
+  while (out->len && !out->s[out->len - 1]) --out->len; /* XXX avoid? */
+  return 0;
+}
+
+int b64encode(in,out)
+stralloc *in;
+stralloc *out; /* not null terminated */
+{
+  unsigned char a, b, c;
+  int i;
+  char *s;
+
+  if (in->len == 0)
+  {
+    if (!stralloc_copys(out,"")) return -1;
+    return 0;
+  }
+
+  if (!stralloc_ready(out,in->len / 3 * 4 + 4)) return -1;
+  s = out->s;
+
+  for (i = 0;i < in->len;i += 3) {
+    a = in->s[i];
+    b = i + 1 < in->len ? in->s[i + 1] : 0;
+    c = i + 2 < in->len ? in->s[i + 2] : 0;
+
+    *s++ = b64alpha[a >> 2];
+    *s++ = b64alpha[((a & 3 ) << 4) | (b >> 4)];
+
+    if (i + 1 >= in->len) *s++ = B64PAD;
+    else *s++ = b64alpha[((b & 15) << 2) | (c >> 6)];
+
+    if (i + 2 >= in->len) *s++ = B64PAD;
+    else *s++ = b64alpha[c & 63];
+  }
+  out->len = s - out->s;
+  return 0;
+}
diff -Nru mess822-0.58/base64.h mess822-0.58_ofmipd-plus-2.0/base64.h
--- mess822-0.58/base64.h	1970-01-01 01:00:00.000000000 +0100
+++ mess822-0.58_ofmipd-plus-2.0/base64.h	2010-07-22 18:25:48.000000000 +0100
@@ -0,0 +1,7 @@
+#ifndef BASE64_H
+#define BASE64_H
+
+extern int b64decode();
+extern int b64encode();
+
+#endif
diff -Nru mess822-0.58/byte.h mess822-0.58_ofmipd-plus-2.0/byte.h
--- mess822-0.58/byte.h	1998-09-05 03:33:37.000000000 +0100
+++ mess822-0.58_ofmipd-plus-2.0/byte.h	2010-07-22 18:25:48.000000000 +0100
@@ -1,13 +1,6 @@
 #ifndef BYTE_H
 #define BYTE_H
 
-extern unsigned int byte_chr();
-extern unsigned int byte_rchr();
-extern void byte_copy();
-extern void byte_copyr();
-extern int byte_diff();
 extern void byte_zero();
 
-#define byte_equal(s,n,t) (!byte_diff((s),(n),(t)))
-
 #endif
diff -Nru mess822-0.58/byte_zero.c mess822-0.58_ofmipd-plus-2.0/byte_zero.c
--- mess822-0.58/byte_zero.c	1970-01-01 01:00:00.000000000 +0100
+++ mess822-0.58_ofmipd-plus-2.0/byte_zero.c	1998-06-15 11:53:16.000000000 +0100
@@ -0,0 +1,13 @@
+#include "byte.h"
+
+void byte_zero(s,n)
+char *s;
+register unsigned int n;
+{
+  for (;;) {
+    if (!n) break; *s++ = 0; --n;
+    if (!n) break; *s++ = 0; --n;
+    if (!n) break; *s++ = 0; --n;
+    if (!n) break; *s++ = 0; --n;
+  }
+}
diff -Nru mess822-0.58/conf-cc mess822-0.58_ofmipd-plus-2.0/conf-cc
--- mess822-0.58/conf-cc	1998-09-05 03:33:37.000000000 +0100
+++ mess822-0.58_ofmipd-plus-2.0/conf-cc	2010-07-22 18:25:48.000000000 +0100
@@ -1,3 +1,3 @@
-gcc -O2
+gcc -O2 -include /usr/include/errno.h
 
 This will be used to compile .c files.
diff -Nru mess822-0.58/env.c mess822-0.58_ofmipd-plus-2.0/env.c
--- mess822-0.58/env.c	1998-09-05 03:33:37.000000000 +0100
+++ mess822-0.58_ofmipd-plus-2.0/env.c	1998-06-15 11:53:16.000000000 +0100
@@ -1,16 +1,113 @@
+/* env.c, envread.c, env.h: environ library
+Daniel J. Bernstein, djb@silverton.berkeley.edu.
+Depends on str.h, alloc.h.
+Requires environ.
+19960113: rewrite. warning: interface is different.
+No known patent problems.
+*/
+
 #include "str.h"
+#include "alloc.h"
 #include "env.h"
 
-extern /*@null@*/char *env_get(s)
-char *s;
+int env_isinit = 0; /* if env_isinit: */
+static int ea; /* environ is a pointer to ea+1 char*'s. */
+static int en; /* the first en of those are ALLOCATED. environ[en] is 0. */
+
+static void env_goodbye(i) int i;
+{
+ alloc_free(environ[i]);
+ environ[i] = environ[--en];
+ environ[en] = 0;
+}
+
+static char *null = 0;
+
+void env_clear()
 {
-  int i;
-  unsigned int len;
+ if (env_isinit) while (en) env_goodbye(0);
+ else environ = &null;
+}
+
+static void env_unsetlen(s,len) char *s; int len;
+{
+ int i;
+ for (i = en - 1;i >= 0;--i)
+   if (!str_diffn(s,environ[i],len))
+     if (environ[i][len] == '=')
+       env_goodbye(i);
+}
 
-  if (!s) return 0;
-  len = str_len(s);
-  for (i = 0;environ[i];++i)
-    if (str_start(environ[i],s) && (environ[i][len] == '='))
-      return environ[i] + len + 1;
-  return 0;
+int env_unset(s) char *s;
+{
+ if (!env_isinit) if (!env_init()) return 0;
+ env_unsetlen(s,str_len(s));
+ return 1;
+}
+
+static int env_add(s) char *s;
+{
+ char *t;
+ t = env_findeq(s);
+ if (t) env_unsetlen(s,t - s);
+ if (en == ea)
+  {
+   ea += 30;
+   if (!alloc_re(&environ,(en + 1) * sizeof(char *),(ea + 1) * sizeof(char *)))
+    { ea = en; return 0; }
+  }
+ environ[en++] = s;
+ environ[en] = 0;
+ return 1;
+}
+
+int env_put(s) char *s;
+{
+ char *u;
+ if (!env_isinit) if (!env_init()) return 0;
+ u = alloc(str_len(s) + 1);
+ if (!u) return 0;
+ str_copy(u,s);
+ if (!env_add(u)) { alloc_free(u); return 0; }
+ return 1;
+}
+
+int env_put2(s,t) char *s; char *t;
+{
+ char *u;
+ int slen;
+ if (!env_isinit) if (!env_init()) return 0;
+ slen = str_len(s);
+ u = alloc(slen + str_len(t) + 2);
+ if (!u) return 0;
+ str_copy(u,s);
+ u[slen] = '=';
+ str_copy(u + slen + 1,t);
+ if (!env_add(u)) { alloc_free(u); return 0; }
+ return 1;
+}
+
+int env_init()
+{
+ char **newenviron;
+ int i;
+ for (en = 0;environ[en];++en) ;
+ ea = en + 10;
+ newenviron = (char **) alloc((ea + 1) * sizeof(char *));
+ if (!newenviron) return 0;
+ for (en = 0;environ[en];++en)
+  {
+   newenviron[en] = alloc(str_len(environ[en]) + 1);
+   if (!newenviron[en])
+    {
+     for (i = 0;i < en;++i) alloc_free(newenviron[i]);
+     alloc_free(newenviron);
+     return 0;
+    }
+   str_copy(newenviron[en],environ[en]);
+  }
+ newenviron[en] = 0;
+ environ = newenviron;
+ env_isinit = 1;
+ return 1;
 }
diff -Nru mess822-0.58/env.h mess822-0.58_ofmipd-plus-2.0/env.h
--- mess822-0.58/env.h	1998-09-05 03:33:37.000000000 +0100
+++ mess822-0.58_ofmipd-plus-2.0/env.h	2010-07-22 18:25:48.000000000 +0100
@@ -1,8 +1,17 @@
 #ifndef ENV_H
 #define ENV_H
 
-extern char **environ;
+extern int env_isinit;
 
+extern int env_init();
+extern int env_put();
+extern int env_put2();
+extern int env_unset();
 extern /*@null@*/char *env_get();
+extern char *env_pick();
+extern void env_clear();
+extern char *env_findeq();
+
+extern char **environ;
 
 #endif
diff -Nru mess822-0.58/envread.c mess822-0.58_ofmipd-plus-2.0/envread.c
--- mess822-0.58/envread.c	1970-01-01 01:00:00.000000000 +0100
+++ mess822-0.58_ofmipd-plus-2.0/envread.c	1998-06-15 11:53:16.000000000 +0100
@@ -0,0 +1,30 @@
+#include "env.h"
+#include "str.h"
+
+extern /*@null@*/char *env_get(s)
+char *s;
+{
+  int i;
+  unsigned int slen;
+  char *envi;
+ 
+  slen = str_len(s);
+  for (i = 0;envi = environ[i];++i)
+    if ((!str_diffn(s,envi,slen)) && (envi[slen] == '='))
+      return envi + slen + 1;
+  return 0;
+}
+
+extern char *env_pick()
+{
+  return environ[0];
+}
+
+extern char *env_findeq(s)
+char *s;
+{
+  for (;*s;++s)
+    if (*s == '=')
+      return s;
+  return 0;
+}
diff -Nru mess822-0.58/errbits.c mess822-0.58_ofmipd-plus-2.0/errbits.c
--- mess822-0.58/errbits.c	1970-01-01 01:00:00.000000000 +0100
+++ mess822-0.58_ofmipd-plus-2.0/errbits.c	2010-07-22 18:25:48.000000000 +0100
@@ -0,0 +1,62 @@
+#include "stralloc.h"
+#include "readwrite.h"
+#include "errbits.h"
+#include "substdio.h"
+#include "fmt.h"
+#include "exit.h"
+
+char sserrbuf[512];
+static substdio sserr = SUBSTDIO_FDBUF(write,2,sserrbuf,sizeof sserrbuf);
+static stralloc foo = {0};
+
+static char pid_str[FMT_ULONG]="?PID?";
+
+void esetfd(fd) int fd; { sserr.fd=fd; }
+
+void eout(s1)  char *s1; {substdio_puts(&sserr,s1);}
+void eout2(s1,s2) char *s1,*s2; {substdio_puts(&sserr,s1);substdio_puts(&sserr,s2);}
+void eout3(s1,s2,s3) char *s1,*s2,*s3; {substdio_puts(&sserr,s1);substdio_puts(&sserr,s2);substdio_puts(&sserr,s3);}
+
+void epid()
+{
+  if (*pid_str == '?') /* not yet set from getpid() */
+    pid_str[fmt_ulong(pid_str,getpid())] = 0;
+  eout(pid_str);
+}
+void eflush() { substdio_flush(&sserr); }
+
+/* The functions below here come from qsutil.c with minor changes */
+void eoutsa(sa) stralloc *sa; { substdio_putflush(&sserr,sa->s,sa->len); }
+
+static void nomem() { substdio_putsflush(&sserr,"Out Of Memory: quitting.\n"); _exit(1); }
+
+static int issafe(ch) char ch;
+{ /* Differs from qsutil.c version: space and % permitted */
+ if (ch == ':') return 0; /* Replace since used as delimiter in logs */
+ if (ch == '<') return 0; /* Replace since used around addresses in logs */
+ if (ch == '>') return 0; /* Replace since used around addresses in logs */
+ if (ch < 32)   return 0; /* Note that space (32) is permitted */
+ if (ch > 126)  return 0;
+ return 1;
+}
+
+void eoutclean(s) char *s;
+{
+ int i;
+ while (!stralloc_copys(&foo,s)) nomem();
+ for (i = 0;i < foo.len;++i)
+   if (foo.s[i] == '\n')
+     foo.s[i] = '/';
+   else
+     if (!issafe(foo.s[i]))
+       foo.s[i] = '_';
+ eoutsa(&foo);
+}
+
+static char ulongstr[FMT_ULONG];
+void eoutulong(u) unsigned long u;
+{
+  ulongstr[fmt_ulong(ulongstr,u)] = 0;
+  eout(ulongstr);
+}
+
diff -Nru mess822-0.58/errbits.h mess822-0.58_ofmipd-plus-2.0/errbits.h
--- mess822-0.58/errbits.h	1970-01-01 01:00:00.000000000 +0100
+++ mess822-0.58_ofmipd-plus-2.0/errbits.h	2010-07-22 18:25:48.000000000 +0100
@@ -0,0 +1,15 @@
+extern void esetfd(); /* functions in this module default to FD 2 (stderr) for output, change with esetfd */
+extern void eout();
+extern void eout2();
+extern void eout3();
+#define eout4(s1,s2,s3,s4)		        	{ eout3(s1,s2,s3); eout(s4); }
+#define eout5(s1,s2,s3,s4,s5)		        { eout3(s1,s2,s3); eout2(s4,s5); }
+#define eout6(s1,s2,s3,s4,s5,s6)	    	{ eout3(s1,s2,s3); eout3(s4,s5,s6); }
+#define eout7(s1,s2,s3,s4,s5,s6,s7) 		{ eout3(s1,s2,s3); eout4(s4,s5,s6,s7); }
+#define eout8(s1,s2,s3,s4,s5,s6,s7,s8)		{ eout3(s1,s2,s3); eout5(s4,s5,s6,s7,s8); }
+#define eout9(s1,s2,s3,s4,s5,s6,s7,s8,s9)	{ eout3(s1,s2,s3); eout6(s4,s5,s6,s7,s8,s9); }
+extern void eoutsa();
+extern void epid();
+extern void eflush();
+extern void eoutclean();
+extern void eoutulong();
diff -Nru mess822-0.58/fmt.h mess822-0.58_ofmipd-plus-2.0/fmt.h
--- mess822-0.58/fmt.h	1970-01-01 01:00:00.000000000 +0100
+++ mess822-0.58_ofmipd-plus-2.0/fmt.h	2010-07-22 18:25:48.000000000 +0100
@@ -0,0 +1,25 @@
+#ifndef FMT_H
+#define FMT_H
+
+#define FMT_ULONG 40 /* enough space to hold 2^128 - 1 in decimal, plus \0 */
+#define FMT_LEN ((char *) 0) /* convenient abbreviation */
+
+extern unsigned int fmt_uint(char *,unsigned int);
+extern unsigned int fmt_uint0(char *,unsigned int,unsigned int);
+extern unsigned int fmt_xint(char *,unsigned int);
+extern unsigned int fmt_nbbint(char *,unsigned int,unsigned int,unsigned int,unsigned int);
+extern unsigned int fmt_ushort(char *,unsigned short);
+extern unsigned int fmt_xshort(char *,unsigned short);
+extern unsigned int fmt_nbbshort(char *,unsigned int,unsigned int,unsigned int,unsigned short);
+extern unsigned int fmt_ulong(char *,unsigned long);
+extern unsigned int fmt_xlong(char *,unsigned long);
+extern unsigned int fmt_nbblong(char *,unsigned int,unsigned int,unsigned int,unsigned long);
+
+extern unsigned int fmt_plusminus(char *,int);
+extern unsigned int fmt_minus(char *,int);
+extern unsigned int fmt_0x(char *,int);
+
+extern unsigned int fmt_str(char *,char *);
+extern unsigned int fmt_strn(char *,char *,unsigned int);
+
+#endif
diff -Nru mess822-0.58/fmt_ulong.c mess822-0.58_ofmipd-plus-2.0/fmt_ulong.c
--- mess822-0.58/fmt_ulong.c	1970-01-01 01:00:00.000000000 +0100
+++ mess822-0.58_ofmipd-plus-2.0/fmt_ulong.c	2010-07-22 18:25:48.000000000 +0100
@@ -0,0 +1,13 @@
+#include "fmt.h"
+
+unsigned int fmt_ulong(register char *s,register unsigned long u)
+{
+  register unsigned int len; register unsigned long q;
+  len = 1; q = u;
+  while (q > 9) { ++len; q /= 10; }
+  if (s) {
+    s += len;
+    do { *--s = '0' + (u % 10); u /= 10; } while(u); /* handles u == 0 */
+  }
+  return len;
+}
diff -Nru mess822-0.58/Makefile mess822-0.58_ofmipd-plus-2.0/Makefile
--- mess822-0.58/Makefile	1998-09-05 03:33:37.000000000 +0100
+++ mess822-0.58_ofmipd-plus-2.0/Makefile	2011-04-06 14:32:16.000000000 +0100
@@ -240,6 +240,10 @@
 it instcheck
 	./instcheck
 
+clean: \
+TARGETS
+	rm -f `cat TARGETS`
+
 commands.o: \
 compile commands.c commands.h substdio.h stralloc.h gen_alloc.h str.h \
 case.h
@@ -261,13 +265,21 @@
 	./compile constmap.c
 
 env.a: \
-makelib env.o
-	./makelib env.a env.o
+makelib env.o envread.o
+	./makelib env.a env.o envread.o
 
 env.o: \
-compile env.c str.h env.h
+compile env.c str.h alloc.h env.h
 	./compile env.c
 
+envread.o: \
+compile envread.c env.h str.h
+	./compile envread.c
+
+errbits.o: \
+compile errbits.c errbits.h stralloc.h gen_alloc.h fmt.h exit.h fmt.h
+	./compile errbits.c
+
 error.a: \
 makelib error.o error_str.o
 	./makelib error.a error.o error_str.o
@@ -297,6 +309,10 @@
 	cat auto-ccld.sh find-systype.sh > find-systype
 	chmod 755 find-systype
 
+fmt_ulong.o: \
+compile fmt_ulong.c fmt.h
+	./compile fmt_ulong.c
+
 fork.h: \
 compile load tryvfork.c fork.h1 fork.h2
 	( ( ./compile tryvfork.c && ./load tryvfork ) >/dev/null \
@@ -540,14 +556,16 @@
 
 ofmipd: \
 load ofmipd.o rewritehost.o rwhconfig.o config.o qmail.o auto_qmail.o \
+base64.o byte_zero.o errbits.o fmt_ulong.o \
 timeoutread.o timeoutwrite.o commands.o env.a cdb.a mess822.a \
 libtai.a getln.a strerr.a substdio.a stralloc.a alloc.a error.a \
-case.a str.a fs.a open.a wait.a sig.a fd.a
+case.a str.a fs.a open.a wait.a sig.a fd.a ucspitls.o
 	./load ofmipd rewritehost.o rwhconfig.o config.o qmail.o \
 	auto_qmail.o timeoutread.o timeoutwrite.o commands.o env.a \
+	base64.o byte_zero.o errbits.o fmt_ulong.o \
 	cdb.a mess822.a libtai.a getln.a strerr.a substdio.a \
 	stralloc.a alloc.a error.a case.a str.a fs.a open.a wait.a \
-	sig.a fd.a 
+	sig.a fd.a ucspitls.o
 
 ofmipd.0: \
 ofmipd.8
@@ -558,7 +576,7 @@
 readwrite.h timeoutread.h timeoutwrite.h stralloc.h gen_alloc.h \
 substdio.h config.h stralloc.h env.h exit.h error.h str.h mess822.h \
 stralloc.h caltime.h caldate.h tai.h uint64.h caltime.h cdb.h \
-uint32.h
+uint32.h errbits.h fmt.h
 	./compile ofmipd.c
 
 ofmipname: \
@@ -735,15 +753,19 @@
 
 str.a: \
 makelib str_len.o str_diff.o str_diffn.o str_chr.o str_rchr.o \
-str_start.o byte_chr.o byte_rchr.o byte_copy.o byte_cr.o
+str_start.o byte_chr.o byte_rchr.o byte_copy.o byte_cr.o str_cpy.o
 	./makelib str.a str_len.o str_diff.o str_diffn.o str_chr.o \
 	str_rchr.o str_start.o byte_chr.o byte_rchr.o byte_copy.o \
-	byte_cr.o
+	byte_cr.o str_cpy.o
 
 str_chr.o: \
 compile str_chr.c str.h
 	./compile str_chr.c
 
+str_cpy.o: \
+compile str_cpy.c str.h
+	./compile str_cpy.c
+
 str_diff.o: \
 compile str_diff.c str.h
 	./compile str_diff.c
diff -Nru mess822-0.58/ofmipd.8 mess822-0.58_ofmipd-plus-2.0/ofmipd.8
--- mess822-0.58/ofmipd.8	1998-09-05 03:33:37.000000000 +0100
+++ mess822-0.58_ofmipd-plus-2.0/ofmipd.8	2014-04-24 19:30:30.850659927 +0100
@@ -3,8 +3,11 @@
 ofmipd \- accept outgoing mail through OFMIP
 .SH SYNOPSIS
 .B ofmipd
-[
 .I name.cdb
+[
+.I hostname
+.I checkpasswd
+.I truepgm
 ]
 .SH DESCRIPTION
 .B ofmipd
@@ -31,15 +34,40 @@
 Some sites use port 26.
 Some sites use port 25 on an IP address that does not receive incoming mail.
 
-Note that
+The
+.I hostname
+argument is the name of the mail host, intended to create CRAM password
+challenges but currently ignored.
+The
+.I checkpasswd
+argument
+is the name of a password checker that uses the same calling conventions as
+the qmail POP3 checkpasswd.
+The
+.I truepgm
+argument is the name a program that succeeds, such as
+.B /bin/true\c
+, for POP3 checkpasswd compatibility.
+
+If the environment variable RELAYCLIENT is set,
+or the client logs in with AUTH,
 .B ofmipd
 will relay messages to any destination.
-It should be invoked
-only for connections from preauthorized users.
+If not, it will reject any MAIL FROM, RCPT TO, or DATA command with a 503
+error.
 With
 .B tcpserver
-you can deny connections
-that do not come from preauthorized IP addresses such as 127.0.0.1.
+you can set RELAYCLIENT for 
+preauthorized IP addresses such as 127.0.0.1.
+The contents of RELAYCLIENT are ignored; in particular, they are not
+appended to destnation mail addresses.
+
+If the environment variable UCSPITLS is set, ofmipd will enable TLS
+functionality if available (offering STARTTLS in the response
+to EHLO, enabling the STARTTLS command). This requires ofmipd to
+be run from ucspi-tls's sslserver (rather than tcpserver, inetd or
+xinetd). ucspi-tls is a package from Scott Gifford (www.suspectclass.com),
+in turn built upon ucspi-ssl (www.superscript.com/ucspi-ssl/).
 
 Most MUAs that claim to be ``SMTP clients''
 are actually OFMIP clients.
@@ -92,6 +120,10 @@
 See
 .BR ofmipname (8)
 for further details.
+The
+.I name.cdb
+argument must be supplied but may be a null string of no name
+transformation file is to be used.
 
 .B ofmipd
 accepts LF and CR LF as line terminators inside messages.
diff -Nru mess822-0.58/ofmipd.c mess822-0.58_ofmipd-plus-2.0/ofmipd.c
--- mess822-0.58/ofmipd.c	1998-09-05 03:33:37.000000000 +0100
+++ mess822-0.58_ofmipd-plus-2.0/ofmipd.c	2011-04-06 15:40:12.000000000 +0100
@@ -16,14 +16,36 @@
 #include "tai.h"
 #include "caltime.h"
 #include "cdb.h"
+#include "base64.h"
+#include "wait.h"
+#include "fd.h"
+#include "byte.h"
+#include "case.h"
+#include "errbits.h"
+#include "ucspitls.h"
+  
+#undef AUTHCRAM			/* don't define, not fully implemented */
 
 int timeout = 1200;
+int tls_available = 0;
+int tls_started = 0;
+
+char *remoteip="(not yet set)";
+char *relayclient;
+
+/* Choose your log format by selecting an enew() here, */
+/* void enew()     { eout3("ofmipd: ",remoteip," pid "); epid(); eout(": "); } */
+void enew()     { eout("ofmipd: pid "); epid(); eout2(" from ", remoteip); eout(": "); }
 
 int safewrite(fd,buf,len) int fd; char *buf; int len;
 {
   int r;
   r = timeoutwrite(timeout,fd,buf,len);
-  if (r <= 0) _exit(1);
+  if (r <= 0)
+  {
+    enew(); eout("Write error (disconnect?): quitting\n"); eflush();
+    _exit(1);
+  }
   return r;
 }
 
@@ -33,26 +55,125 @@
 void flush() { substdio_flush(&ssout); }
 void out(s) char *s; { substdio_puts(&ssout,s); }
 
-void die_read() { _exit(1); }
-void nomem() { out("451 out of memory (#4.3.0)\r\n"); flush(); _exit(1); }
-void die_config() { out("451 unable to read configuration (#4.3.0)\r\n"); flush(); _exit(1); }
-void smtp_quit() { out("221 ofmipd.local\r\n"); flush(); _exit(0); }
+stralloc addr = {0}; /* will be 0-terminated, if addrparse returns 1 */
+stralloc rwaddr = {0};
+
+void die_read()
+{
+  enew(); eout("Read error (disconnect?): quitting\n"); eflush();
+  _exit(1);
+}
+void nomem()
+{
+  enew(); eout("Out of memory: quitting\n"); eflush();
+  out("451 out of memory (#4.3.0)\r\n"); flush(); _exit(1);
+}
+void die_config()
+{
+  enew(); eout("Unable to read configuration: quitting\n"); eflush();
+  out("451 unable to read configuration (#4.3.0)\r\n"); flush(); _exit(1);
+}
+void smtp_quit()
+{
+  enew(); eout("Remote end QUIT: quitting\n"); eflush();
+  out("221 ofmipd.local\r\n"); flush(); _exit(0);
+}
 void smtp_help() { out("214 qmail home page: http://pobox.com/~djb/qmail.html\r\n"); }
-void smtp_noop() { out("250 ok\r\n"); }
-void smtp_vrfy() { out("252 send some mail, i'll try my best\r\n"); }
-void smtp_unimpl() { out("502 unimplemented (#5.5.1)\r\n"); }
-void err_syntax() { out("555 syntax error (#5.5.4)\r\n"); }
-void err_wantmail() { out("503 MAIL first (#5.5.1)\r\n"); }
-void err_wantrcpt() { out("503 RCPT first (#5.5.1)\r\n"); }
-void err_qqt() { out("451 qqt failure (#4.3.0)\r\n"); }
-void err_cdb() { out("451 unable to read cdb (#4.3.0)\r\n"); }
+void smtp_noop()
+{
+  enew(); eout("NOOP\n"); eflush();
+  out("250 ok\r\n");
+}
+void smtp_vrfy()
+{
+  enew(); eout("VRFY requested\n"); eflush();
+  out("252 send some mail, I'll try my best\r\n");
+}
+void smtp_unimpl()
+{
+  enew(); eout("Unimplemented command\n"); eflush();
+  out("502 unimplemented (#5.5.1)\r\n");
+}
+void err_syntax(cmd) char *cmd;
+{
+  enew(); eout2(cmd," with too long address ("); eoutulong(addr.len); eout(" bytes) given\n"); eflush();
+  out("555 syntax error (#5.5.4)\r\n");
+}
+void err_wantmail()
+{
+  enew(); eout("Attempted RCPT or DATA before MAIL\n"); eflush();
+  out("503 MAIL first (#5.5.1)\r\n");
+}
+void err_wantrcpt()
+{
+  enew(); eout("Attempted DATA before RCPT\n"); eflush();
+  out("503 RCPT first (#5.5.1)\r\n");
+}
+void err_qqt()
+{
+  enew(); eout("qqt failure\n"); eflush();
+  out("451 qqt failure (#4.3.0)\r\n");
+}
+void err_cdb()
+{
+  enew(); eout("Unable to read cdb\n"); eflush();
+  out("451 unable to read cdb (#4.3.0)\r\n");
+}
+int err_child()
+{
+  enew(); eout("problem with child, can't auth\n"); eflush();
+  out("454 oops, problem with child and I can't auth (#4.3.0)\r\n"); return -1;
+}
+int err_fork()
+{
+  enew(); eout("child won't start, can't auth\n"); eflush();
+  out("454 oops, child won't start and I can't auth (#4.3.0)\r\n"); return -1;
+}
+int err_pipe()
+{
+  enew(); eout("can't setup pipe for auth\n"); eflush();
+  out("454 oops, unable to open pipe and I can't auth (#4.3.0)\r\n"); return -1;
+}
+int err_write()
+{
+  enew(); eout("can't write pipe for auth\n"); eflush();
+  out("454 oops, unable to write pipe and I can't auth (#4.3.0)\r\n"); return -1;
+}
+void err_authd()
+{
+  enew(); eout("auth requested but already authenticated\n"); eflush();
+  out("503 you're already authenticated (#5.5.0)\r\n");
+}
+void err_authmail()
+{
+  enew(); eout("auth requested during mail transaction\n"); eflush();
+  out("503 no auth during mail transaction (#5.5.0)\r\n");
+}
+int err_noauth()
+{
+  enew(); eout("Unsupported auth type requested\n"); eflush();
+  out("504 auth type unimplemented (#5.5.1)\r\n"); return -1;
+}
+int err_authabrt()
+{
+  enew(); eout("auth auth exchange cancelled\n"); eflush();
+  out("501 auth exchange cancelled (#5.0.0)\r\n"); return -1;
+}
+int err_input() { out("501 malformed auth input (#5.5.4)\r\n"); return -1; }
+int err_notauth()
+{
+  enew(); eout("Attempted mail/rcpt before authenticating\n"); eflush();
+  out("503 authorize or check your mail before sending (#5.5.1)\r\n"); return -1;
+}
+void die_syserr()
+{
+  enew(); eout("System error occurred, exiting.\n"); eflush();
+  out("421 system error (#4.3.0)\r\n"); flush(); _exit(1);
+}
 
 config_str rewrite = CONFIG_STR;
 stralloc idappend = {0};
 
-stralloc addr = {0}; /* will be 0-terminated, if addrparse returns 1 */
-stralloc rwaddr = {0};
-
 int addrparse(arg)
 char *arg;
 {
@@ -107,25 +228,57 @@
 
 stralloc mailfrom = {0};
 stralloc rcptto = {0};
+int rcptcount;
 
 void smtp_helo(arg) char *arg;
 {
   seenmail = 0;
+  enew(); eout("Received HELO "); eoutclean(arg); eout("\n"); eflush();
   out("250 ofmipd.local\r\n");
 }
 void smtp_ehlo(arg) char *arg;
 {
   seenmail = 0;
-  out("250-ofmipd.local\r\n250-PIPELINING\r\n250 8BITMIME\r\n");
+  enew(); eout("Received EHLO "); eoutclean(arg); eout("\n"); eflush();
+  out("250-ofmipd.local");
+#ifdef AUTHCRAM
+  out("\r\n250-AUTH LOGIN CRAM-MD5 PLAIN");
+  out("\r\n250-AUTH=LOGIN CRAM-MD5 PLAIN");
+#else
+  out("\r\n250-AUTH LOGIN PLAIN");
+  out("\r\n250-AUTH=LOGIN PLAIN");
+#endif
+  if (tls_available && !tls_started) out("\r\n250-STARTTLS");
+  out("\r\n250-PIPELINING");
+  out("\r\n250 8BITMIME\r\n");
 }
 void smtp_rset()
 {
   seenmail = 0;
+  enew(); eout("Session RSET\n"); eflush();
   out("250 flushed\r\n");
 }
+void smtp_starttls(arg) char *arg;
+{
+  unsigned long long_fd;
+  int fd;
+  char *fdstr;
+  if (!tls_available || tls_started)
+    return smtp_unimpl(arg);
+  out("220 2.0.0 Ready to start TLS\r\n");
+  flush();
+
+  if (!ucspitls())
+    die_syserr();
+
+  tls_started = 1;
+  /* reset SMTP state */
+  seenmail = 0;
+}
 void smtp_mail(arg) char *arg;
 {
-  if (!addrparse(arg)) { err_syntax(); return; }
+  if (!relayclient) { err_notauth(); return; }
+  if (!addrparse(arg)) { err_syntax(arg); return; }
 
   name = 0;
   if (fncdb) {
@@ -149,21 +302,27 @@
   if (!stralloc_0(&mailfrom)) nomem();
   if (!stralloc_copys(&rcptto,"")) nomem();
   seenmail = 1;
+  rcptcount = 0;
+  enew(); eout("Sender <"); eoutclean(mailfrom.s); eout(">\n"); eflush();
   out("250 ok\r\n");
 }
 void smtp_rcpt(arg) char *arg; {
+  if (!relayclient) { err_notauth(); return; }
   if (!seenmail) { err_wantmail(); return; }
-  if (!addrparse(arg)) { err_syntax(); return; }
+  if (!addrparse(arg)) { err_syntax(arg); return; }
   if (!stralloc_0(&rwaddr)) nomem();
   if (!stralloc_cats(&rcptto,"T")) nomem();
   if (!stralloc_cats(&rcptto,rwaddr.s)) nomem();
   if (!stralloc_0(&rcptto)) nomem();
+  ++rcptcount;
+  enew(); eout("Recipient <"); eoutclean(addr.s); eout(">\n"); eflush();
   out("250 ok\r\n");
 }
 
+unsigned int messagebytes = 0;
 struct qmail qqt;
-void put(buf,len) char *buf; int len; { qmail_put(&qqt,buf,len); }
-void puts(buf) char *buf; { qmail_puts(&qqt,buf); }
+void put(buf,len) char *buf; int len; { qmail_put(&qqt,buf,len); messagebytes+=len; }
+void puts(buf) char *buf; { qmail_puts(&qqt,buf); messagebytes+=str_len(buf); }
 
 stralloc tmp = {0};
 stralloc tmp2 = {0};
@@ -345,10 +504,44 @@
     finishheader();
 }
 
+void safecats(out,in)
+stralloc *out;
+char *in;
+{
+  char ch;
+  while (ch = *in++) {
+    if (ch < 33) ch = '?';
+    if (ch > 126) ch = '?';
+    if (ch == '(') ch = '?';
+    if (ch == ')') ch = '?';
+    if (ch == '@') ch = '?';
+    if (ch == '\\') ch = '?';
+    if (!stralloc_append(out,&ch)) nomem();
+  }
+}
+
 stralloc received = {0};
+char *remoteinfo;
+
+void received_init()
+{
+  char *x;
+
+  if (!stralloc_copys(&received,"Received: (ofmipd ")) nomem();
+/* Uncomment this section if you want auth_user@IP instead of just IP in headers,
+  x = remoteinfo;
+  if (x) {
+    safecats(&received,x);
+    if (!stralloc_append(&received,"@")) nomem();
+  }
+*/
+  safecats(&received,remoteip);
+  if (!stralloc_cats(&received,"); ")) nomem();
+}
 
 void smtp_data() {
   struct tai now;
+  unsigned long qp;
   char *qqx;
 
   tai_now(&now);
@@ -356,62 +549,276 @@
   datastart.known = 1;
   if (!mess822_date(&datastamp,&datastart)) nomem();
  
+  if (!relayclient) { err_notauth(); return; }
   if (!seenmail) { err_wantmail(); return; }
   if (!rcptto.len) { err_wantrcpt(); return; }
   seenmail = 0;
+  messagebytes = 0;
   if (qmail_open(&qqt) == -1) { err_qqt(); return; }
+  qp = qmail_qp(&qqt);
   out("354 go ahead\r\n");
  
-  qmail_put(&qqt,received.s,received.len);
-  qmail_put(&qqt,datastamp.s,datastamp.len);
-  qmail_puts(&qqt,"\n");
+  received_init();
+/* messagebytes calculations below relate to the 'Received:' header line added *
+ * by ofmipd; remove them if you just want to log the incoming messagebytes,   */
+  qmail_put(&qqt,received.s,received.len);	messagebytes+=received.len;
+  qmail_put(&qqt,datastamp.s,datastamp.len);	messagebytes+=datastamp.len;
+  qmail_puts(&qqt,"\n");			messagebytes+=1;
   blast();
   qmail_from(&qqt,mailfrom.s);
   qmail_put(&qqt,rcptto.s,rcptto.len);
  
   qqx = qmail_close(&qqt);
-  if (!*qqx) { out("250 ok\r\n"); return; }
+  enew();
+  if (!*qqx)
+  {
+    eout("Message accepted, qp "); eoutulong(qp);
+    eout(" ("); eoutulong((unsigned long)rcptcount); eout(" recipients, ");
+    eoutulong(messagebytes); eout(" bytes)\n");
+    eflush();
+    out("250 ok\r\n"); return;
+  }
   if (*qqx == 'D') out("554 "); else out("451 ");
   out(qqx + 1);
   out("\r\n");
+  eout("Message rejected (");
+  if (*qqx == 'D') eout("554 "); else eout("451 ");
+  eoutclean(qqx + 1); eout(")\n");
+  eflush();
+}
+
+#ifdef AUTHCRAM
+char unique[FMT_ULONG + FMT_ULONG + 3];
+#endif
+static stralloc authin = {0};
+static stralloc user = {0};
+static stralloc pass = {0};
+static stralloc resp = {0};
+static stralloc slop = {0};
+char *hostname;
+char **childargs;
+substdio ssup;
+char upbuf[128];
+int authd = 0;
+
+int authgetl(void) {
+  int i;
+
+  if (!stralloc_copys(&authin, "")) nomem();
+
+  for (;;) {
+    if (!stralloc_readyplus(&authin,1)) nomem(); /* XXX */
+    i = substdio_get(&ssin,authin.s + authin.len,1);
+    if (i != 1) die_read();
+    if (authin.s[authin.len] == '\n') break;
+    ++authin.len;
+  }
+
+  if (authin.len > 0) if (authin.s[authin.len - 1] == '\r') --authin.len;
+  authin.s[authin.len] = 0;
+
+  if (*authin.s == '*' && *(authin.s + 1) == 0) { return err_authabrt(); }
+  if (authin.len == 0) { return err_input(); }
+  return authin.len;
+}
+
+int authenticate(void)
+{
+  int child;
+  int wstat;
+  int pi[2];
+
+  if (!stralloc_0(&user)) nomem();
+  if (!stralloc_0(&pass)) nomem();
+  if (!stralloc_0(&resp)) nomem();
+
+  if (fd_copy(2,1) == -1) return err_pipe();
+  close(3);
+  if (pipe(pi) == -1) return err_pipe();
+  if (pi[0] != 3) return err_pipe();
+  switch(child = fork()) {
+    case -1:
+      return err_fork();
+    case 0:
+      close(pi[1]);
+      sig_pipedefault();
+      execvp(*childargs, childargs);
+      _exit(1);
+  }
+  close(pi[0]);
+
+  substdio_fdbuf(&ssup,write,pi[1],upbuf,sizeof upbuf);
+  if (substdio_put(&ssup,user.s,user.len) == -1) return err_write();
+  if (substdio_put(&ssup,pass.s,pass.len) == -1) return err_write();
+  if (substdio_put(&ssup,resp.s,resp.len) == -1) return err_write();
+  if (substdio_flush(&ssup) == -1) return err_write();
+
+  close(pi[1]);
+  byte_zero(pass.s,pass.len);
+  byte_zero(upbuf,sizeof upbuf);
+  if (wait_pid(&wstat,child) == -1) return err_child();
+  if (wait_crashed(wstat)) return err_child();
+  if (wait_exitcode(wstat)) { sleep(2); return 1; } /* no */
+  return 0; /* yes */
 }
 
-void safecats(out,in)
-stralloc *out;
-char *in;
+int auth_login(arg) char *arg;
 {
-  char ch;
-  while (ch = *in++) {
-    if (ch < 33) ch = '?';
-    if (ch > 126) ch = '?';
-    if (ch == '(') ch = '?';
-    if (ch == ')') ch = '?';
-    if (ch == '@') ch = '?';
-    if (ch == '\\') ch = '?';
-    if (!stralloc_append(out,&ch)) nomem();
+  int r;
+
+  if (*arg) {
+    if (r = b64decode(arg,str_len(arg),&user) == 1) return err_input();
+  }
+  else {
+    out("334 VXNlcm5hbWU6\r\n"); flush(); /* Username: */
+    if (authgetl() < 0) return -1;
+    if (r = b64decode(authin.s,authin.len,&user) == 1) return err_input();
   }
+  if (r == -1) nomem();
+
+  out("334 UGFzc3dvcmQ6\r\n"); flush(); /* Password: */
+
+  if (authgetl() < 0) return -1;
+  if (r = b64decode(authin.s,authin.len,&pass) == 1) return err_input();
+  if (r == -1) nomem();
+
+  if (!user.len || !pass.len) return err_input();
+  return authenticate();  
 }
 
-void received_init()
+int auth_plain(arg) char *arg;
+{
+  int r, id = 0;
+
+  if (*arg) {
+    if (r = b64decode(arg,str_len(arg),&slop) == 1) return err_input();
+  }
+  else {
+    out("334 \r\n"); flush();
+    if (authgetl() < 0) return -1;
+    if (r = b64decode(authin.s,authin.len,&slop) == 1) return err_input();
+  }
+  if (r == -1 || !stralloc_0(&slop)) nomem();
+  while (slop.s[id]) id++; /* ignore authorize-id */
+
+  if (slop.len > id + 1)
+    if (!stralloc_copys(&user,slop.s + id + 1)) nomem();
+  if (slop.len > id + user.len + 2)
+    if (!stralloc_copys(&pass,slop.s + id + user.len + 2)) nomem();
+
+  if (!user.len || !pass.len) return err_input();
+  return authenticate();
+}
+
+#ifdef AUTHCRAM
+int auth_cram()
+{
+  int i, r;
+  char *s;
+
+  s = unique;
+  s += fmt_uint(s,getpid());
+  *s++ = '.';
+  s += fmt_ulong(s,(unsigned long) now());
+  *s++ = '@';
+  *s++ = 0;
+
+  if (!stralloc_copys(&pass,"<")) nomem();
+  if (!stralloc_cats(&pass,unique)) nomem();
+  if (!stralloc_cats(&pass,hostname)) nomem();
+  if (!stralloc_cats(&pass,">")) nomem();
+  if (b64encode(&pass,&slop) < 0) nomem();
+  if (!stralloc_0(&slop)) nomem();
+
+  out("334 ");
+  out(slop.s);
+  out("\r\n");
+  flush();
+
+  if (authgetl() < 0) return -1;
+  if (r = b64decode(authin.s,authin.len,&slop) == 1) return err_input();
+  if (r == -1 || !stralloc_0(&slop)) nomem();
+
+  i = str_chr(slop.s,' ');
+  s = slop.s + i;
+  while (*s == ' ') ++s;
+  slop.s[i] = 0;
+  if (!stralloc_copys(&user,slop.s)) nomem();
+  if (!stralloc_copys(&resp,s)) nomem();
+
+  if (!user.len || !resp.len) return err_input();
+  return authenticate();
+}
+#endif
+
+struct authcmd {
+  char *text;
+  int (*fun)();
+} authcmds[] = {
+  { "login", auth_login }
+, { "plain", auth_plain }
+#ifdef AUTHCRAM
+, { "cram-md5", auth_cram }
+#endif
+, { 0, err_noauth }
+};
+
+void smtp_auth(arg)
+char *arg;
 {
+  int i;
+  char *cmd = arg;
   char *x;
 
-  if (!stralloc_copys(&received,"Received: (ofmipd ")) nomem();
-  x = env_get("TCPREMOTEINFO");
-  if (x) {
-    safecats(&received,x);
-    if (!stralloc_append(&received,"@")) nomem();
+  if (!hostname || !*childargs)
+  {
+    out("503 auth not available (#5.3.3)\r\n");
+    enew(); eout("Authentication requested but not available - hostname or child args missing"); eflush();
+    return;
+  }
+  if (authd) { err_authd(); return; }
+  if (seenmail) { err_authmail(); return; }
+
+  if (!stralloc_copys(&user,"")) nomem();
+  if (!stralloc_copys(&pass,"")) nomem();
+  if (!stralloc_copys(&resp,"")) nomem();
+
+  i = str_chr(cmd,' ');   
+  arg = cmd + i;
+  while (*arg == ' ') ++arg;
+  cmd[i] = 0;
+
+  for (i = 0;authcmds[i].text;++i)
+    if (case_equals(authcmds[i].text,cmd)) break;
+
+  switch (authcmds[i].fun(arg)) {
+    case 0:
+      authd = 1;
+      relayclient = "";
+      remoteinfo = user.s;
+      if (!env_unset("TCPREMOTEINFO")) die_read();
+      if (!env_put2("TCPREMOTEINFO",remoteinfo)) nomem();
+      out("235 ok, go ahead (#2.0.0)\r\n");
+      enew(); eout3("auth ",cmd," succeeded for user '"); eoutclean(user.s); eout("'\n"); eflush();
+      break;
+
+    case 1:
+      out("535 authorization failed (#5.7.0)\r\n");
+      enew(); eout3("auth ",cmd," failed for user '"); eoutclean(user.s); eout("'.\n"); eflush();
+      break;
+
+    case -1:
+      enew(); eout("malformed auth input");
+      if (user.len) { eout(" for user '"); eoutclean(user.s); eout("'"); }
+      eout("\n"); eflush();
   }
-  x = env_get("TCPREMOTEIP");
-  if (!x) x = "unknown";
-  safecats(&received,x);
-  if (!stralloc_cats(&received,"); ")) nomem();
 }
 
 struct commands smtpcommands[] = {
   { "rcpt", smtp_rcpt, 0 }
 , { "mail", smtp_mail, 0 }
 , { "data", smtp_data, flush }
+, { "auth", smtp_auth, flush }
 , { "quit", smtp_quit, flush }
 , { "helo", smtp_helo, flush }
 , { "ehlo", smtp_ehlo, flush }
@@ -419,6 +826,7 @@
 , { "help", smtp_help, flush }
 , { "noop", smtp_noop, flush }
 , { "vrfy", smtp_vrfy, flush }
+, { "starttls", smtp_starttls, flush }
 , { 0, smtp_unimpl, flush }
 } ;
 
@@ -428,18 +836,28 @@
 {
   sig_pipeignore();
 
+  remoteip = env_get("TCPREMOTEIP");
+  if (!remoteip) remoteip = "unknown";
+  esetfd(7);	/* Can't use fd 2 (stderr) cos of how checkpassword called at present */
+
   fncdb = argv[1];
-  if (fncdb) {
+  if (fncdb && *fncdb) {
     fdcdb = open_read(fncdb);
     if (fdcdb == -1) die_config();
-  }
+  } else fncdb = 0;
+
+  hostname = argv[2];
+  childargs = argv + 3;
+  remoteinfo = env_get("TCPREMOTEINFO");
+  relayclient = env_get("RELAYCLIENT");
 
-  received_init();
   if (leapsecs_init() == -1) die_config();
   if (chdir(auto_qmail) == -1) die_config();
   if (rwhconfig(&rewrite,&idappend) == -1) die_config();
 
+  tls_available = !!env_get("UCSPITLS");
   out("220 ofmipd.local ESMTP\r\n");
   commands(&ssin,&smtpcommands);
   nomem();
 }
+
diff -Nru mess822-0.58/qmail.c mess822-0.58_ofmipd-plus-2.0/qmail.c
--- mess822-0.58/qmail.c	1998-09-05 03:33:37.000000000 +0100
+++ mess822-0.58_ofmipd-plus-2.0/qmail.c	2010-07-22 18:25:48.000000000 +0100
@@ -6,8 +6,17 @@
 #include "fd.h"
 #include "qmail.h"
 #include "auto_qmail.h"
+#include "env.h"
 
-static char *binqqargs[2] = { "bin/qmail-queue", 0 } ;
+static char *binqqargs[2] = { 0, 0 } ;
+
+static void setup_qqargs()
+{
+  if(!binqqargs[0])
+    binqqargs[0] = env_get("QMAILQUEUE");
+  if(!binqqargs[0])
+    binqqargs[0] = "bin/qmail-queue";
+}
 
 int qmail_open(qq)
 struct qmail *qq;
@@ -15,6 +24,8 @@
   int pim[2];
   int pie[2];
 
+  setup_qqargs();
+
   if (pipe(pim) == -1) return -1;
   if (pipe(pie) == -1) { close(pim[0]); close(pim[1]); return -1; }
  
diff -Nru mess822-0.58/str_cpy.c mess822-0.58_ofmipd-plus-2.0/str_cpy.c
--- mess822-0.58/str_cpy.c	1970-01-01 01:00:00.000000000 +0100
+++ mess822-0.58_ofmipd-plus-2.0/str_cpy.c	1998-06-15 11:53:16.000000000 +0100
@@ -0,0 +1,16 @@
+#include "str.h"
+
+unsigned int str_copy(s,t)
+register char *s;
+register char *t;
+{
+  register int len;
+
+  len = 0;
+  for (;;) {
+    if (!(*s = *t)) return len; ++s; ++t; ++len;
+    if (!(*s = *t)) return len; ++s; ++t; ++len;
+    if (!(*s = *t)) return len; ++s; ++t; ++len;
+    if (!(*s = *t)) return len; ++s; ++t; ++len;
+  }
+}
diff -Nru mess822-0.58/TARGETS mess822-0.58_ofmipd-plus-2.0/TARGETS
--- mess822-0.58/TARGETS	1998-09-05 03:33:37.000000000 +0100
+++ mess822-0.58_ofmipd-plus-2.0/TARGETS	2011-04-06 15:41:53.000000000 +0100
@@ -8,6 +8,8 @@
 iftocc.o
 make-makelib
 makelib
+fmt_ulong.o
+errbits.o
 mess822_date.o
 mess822_quote.o
 mess822_fold.o
@@ -153,6 +155,11 @@
 quote.o
 quote
 parsedate.o
+base64.o
+byte_zero.o
+envread.o
+str_cpy.o
+ucspitls.o
 parsedate
 prog
 iftocc.0
diff -Nru mess822-0.58/ucspitls.c mess822-0.58_ofmipd-plus-2.0/ucspitls.c
--- mess822-0.58/ucspitls.c	1970-01-01 01:00:00.000000000 +0100
+++ mess822-0.58_ofmipd-plus-2.0/ucspitls.c	2009-09-22 11:59:00.000000000 +0100
@@ -0,0 +1,31 @@
+#include "scan.h"
+#include "env.h"
+
+int ucspitls(void)
+{
+  unsigned long fd;
+  char *fdstr;
+   
+  if (!(fdstr=env_get("SSLCTLFD")))
+    return 0;
+  if (!scan_ulong(fdstr,&fd))
+    return 0;
+  if (write((int)fd, "y", 1) < 1)
+    return 0;
+ 
+  if (!(fdstr=env_get("SSLREADFD")))
+    return 0;
+  if (!scan_ulong(fdstr,&fd))
+    return 0;
+  if (dup2((int)fd,0) == -1)
+    return 0;
+ 
+  if (!(fdstr=env_get("SSLWRITEFD")))
+    return 0; 
+  if (!scan_ulong(fdstr,&fd))
+    return 0;
+  if (dup2((int)fd,1) == -1)
+    return 0;
+ 
+  return 1;
+}
diff -Nru mess822-0.58/ucspitls.h mess822-0.58_ofmipd-plus-2.0/ucspitls.h
--- mess822-0.58/ucspitls.h	1970-01-01 01:00:00.000000000 +0100
+++ mess822-0.58_ofmipd-plus-2.0/ucspitls.h	2009-09-22 11:59:00.000000000 +0100
@@ -0,0 +1 @@
+int ucspitls(void);
