diff -urN ../netqmail-1.05-unpatched/Makefile ./Makefile
--- ../netqmail-1.05-unpatched/Makefile	2004-03-03 12:03:41.000000000 +0100
+++ ./Makefile	2004-03-11 11:39:09.000000000 +0100
@@ -136,6 +136,10 @@
 compile auto_usera.c
 	./compile auto_usera.c
 
+base64.o: \
+compile base64.c base64.h stralloc.h substdio.h str.h
+	./compile base64.c
+
 binm1: \
 binm1.sh conf-qmail
 	cat binm1.sh \
@@ -1289,10 +1293,10 @@
 qmail-popup: \
 load qmail-popup.o commands.o timeoutread.o timeoutwrite.o now.o \
 case.a fd.a sig.a wait.a stralloc.a alloc.a substdio.a error.a str.a \
-fs.a socket.lib
+fs.a base64.o socket.lib
 	./load qmail-popup commands.o timeoutread.o timeoutwrite.o \
 	now.o case.a fd.a sig.a wait.a stralloc.a alloc.a \
-	substdio.a error.a str.a fs.a  `cat socket.lib`
+	substdio.a error.a str.a fs.a base64.o  `cat socket.lib`
 
 qmail-popup.0: \
 qmail-popup.8
@@ -1301,7 +1305,7 @@
 qmail-popup.o: \
 compile qmail-popup.c commands.h fd.h sig.h stralloc.h gen_alloc.h \
 substdio.h alloc.h wait.h str.h byte.h now.h datetime.h fmt.h exit.h \
-readwrite.h timeoutread.h timeoutwrite.h
+readwrite.h timeoutread.h timeoutwrite.h base64.h
 	./compile qmail-popup.c
 
 qmail-pw2u: \
diff -urN ../netqmail-1.05-unpatched/TARGETS ./TARGETS
--- ../netqmail-1.05-unpatched/TARGETS	1998-06-15 12:53:16.000000000 +0200
+++ ./TARGETS	2004-03-11 11:39:09.000000000 +0100
@@ -10,6 +10,7 @@
 qmail.o
 quote.o
 now.o
+base64.o
 gfrom.o
 myctime.o
 slurpclose.o
diff -urN ../netqmail-1.05-unpatched/base64.c ./base64.c
--- ../netqmail-1.05-unpatched/base64.c	1970-01-01 01:00:00.000000000 +0100
+++ ./base64.c	2004-03-11 11:39:09.000000000 +0100
@@ -0,0 +1,123 @@
+#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 p = 0;
+  int n;
+  unsigned int x;
+  int i, j;
+  char *s;
+  unsigned char b[3];
+
+  if (l == 0)
+  {
+    if (!stralloc_copys(out,"")) return -1;
+    return 0;
+  }
+
+  while(in[l-1] == B64PAD) {
+    p ++;
+    l--;
+  }
+
+  n = (l + p) / 4;
+  out->len = (n * 3) - p;
+  if (!stralloc_ready(out,out->len)) return -1;
+  s = out->s;
+
+  for(i = 0; i < n - 1 ; i++) {
+    x = 0;
+    for(j = 0; j < 4; j++) {
+      if(in[j] >= 'A' && in[j] <= 'Z')
+        x = (x << 6) + (unsigned int)(in[j] - 'A' + 0);
+      else if(in[j] >= 'a' && in[j] <= 'z')
+        x = (x << 6) + (unsigned int)(in[j] - 'a' + 26);
+      else if(in[j] >= '0' && in[j] <= '9')
+        x = (x << 6) + (unsigned int)(in[j] - '0' + 52);
+      else if(in[j] == '+')
+        x = (x << 6) + 62;
+      else if(in[j] == '/')
+        x = (x << 6) + 63;
+      else if(in[j] == '=')
+        x = (x << 6);
+    }
+
+    s[2] = (unsigned char)(x & 255); x >>= 8;
+    s[1] = (unsigned char)(x & 255); x >>= 8;
+    s[0] = (unsigned char)(x & 255); x >>= 8;
+    s += 3; in += 4;
+  }
+
+  x = 0;
+  for(j = 0; j < 4; j++) {
+    if(in[j] >= 'A' && in[j] <= 'Z')
+      x = (x << 6) + (unsigned int)(in[j] - 'A' + 0);
+    else if(in[j] >= 'a' && in[j] <= 'z')
+      x = (x << 6) + (unsigned int)(in[j] - 'a' + 26);
+    else if(in[j] >= '0' && in[j] <= '9')
+      x = (x << 6) + (unsigned int)(in[j] - '0' + 52);
+    else if(in[j] == '+')
+      x = (x << 6) + 62;
+    else if(in[j] == '/')
+      x = (x << 6) + 63;
+    else if(in[j] == '=')
+      x = (x << 6);
+  }
+
+  b[2] = (unsigned char)(x & 255); x >>= 8;
+  b[1] = (unsigned char)(x & 255); x >>= 8;
+  b[0] = (unsigned char)(x & 255); x >>= 8;
+
+  for(i = 0; i < 3 - p; i++)
+    s[i] = b[i];
+
+  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 -urN ../netqmail-1.05-unpatched/base64.h ./base64.h
--- ../netqmail-1.05-unpatched/base64.h	1970-01-01 01:00:00.000000000 +0100
+++ ./base64.h	2004-03-11 11:39:09.000000000 +0100
@@ -0,0 +1,7 @@
+#ifndef BASE64_H
+#define BASE64_H
+
+extern int b64decode();
+extern int b64encode();
+
+#endif
diff -urN ../netqmail-1.05-unpatched/qmail-popup.c ./qmail-popup.c
--- ../netqmail-1.05-unpatched/qmail-popup.c	2004-03-03 12:03:42.000000000 +0100
+++ ./qmail-popup.c	2004-03-11 11:41:43.000000000 +0100
@@ -14,6 +14,9 @@
 #include "timeoutread.h"
 #include "timeoutwrite.h"
 
+#include "case.h"
+#include "base64.h"
+
 void die() { _exit(1); }
 
 int saferead(fd,buf,len) int fd; char *buf; int len;
@@ -72,7 +75,12 @@
 
 char unique[FMT_ULONG + FMT_ULONG + 3];
 char *hostname;
-stralloc username = {0};
+stralloc authin = {0};   /* input from POP3 client */
+stralloc username = {0}; /* username */
+stralloc chal = {0};     /* challenge */
+stralloc slop = {0};     /* b64 challenge */
+stralloc resp = {0};     /* b64 response */
+
 int seenuser = 0;
 char **childargs;
 substdio ssup;
@@ -133,6 +141,18 @@
   puts(">\r\n");
   flush();
 }
+void pop3_capa(arg) char *arg;
+{
+  puts("+OK Capability list follows\r\n");
+  puts("TOP\r\n");
+  puts("UIDL\r\n");
+  puts("LAST\r\n");
+  puts("USER\r\n");
+  puts("APOP\r\n");
+  puts("SASL CRAM-MD5\r\n");    
+  puts(".\r\n");
+  flush();
+}
 void pop3_user(arg) char *arg;
 {
   if (!*arg) { err_syntax(); return; }
@@ -156,11 +176,99 @@
   doanddie(arg,space - arg,space);
 }
 
+int authgetl(void) {
+  int i;
+
+  if (!stralloc_copys(&authin,"")) die_nomem();
+  for (;;) {
+    if (!stralloc_readyplus(&authin,1)) die_nomem(); /* XXX */
+    i = substdio_get(&ssin,authin.s + authin.len,1);
+    if (i != 1) die();
+    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) { die_badauth(); }
+  if (authin.len == 0) { die_badauth(); }
+  return authin.len;
+}
+
+
+void pop3_auth_cram(arg) char *arg;
+{
+  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(&chal,"<")) die_nomem();          /* generate challenge */
+  if (!stralloc_cats(&chal,unique)) die_nomem();
+  if (!stralloc_cats(&chal,hostname)) die_nomem();
+  if (!stralloc_cats(&chal,">")) die_nomem();
+  if (b64encode(&chal,&slop) < 0) die_nomem();
+  if (!stralloc_0(&slop)) die_nomem();
+
+  puts("+ ");
+  puts(slop.s);
+  puts("\r\n");
+  flush();
+
+  if (authgetl() < 0) die_badauth();                        /* got response */
+
+  if (r = b64decode(authin.s,authin.len,&resp) == 1) die_badauth();
+
+  /* if (r == -1 || !stralloc_0(&resp)) die_nomem(); */
+  if (r == -1) die_nomem();
+
+  i = str_chr(resp.s,' ');
+  s = resp.s + i;
+  while (*s == ' ') ++s;
+  resp.s[i] = 0;
+
+  if (!stralloc_copys(&username,resp.s)) die_nomem();       /* userid */
+  if (!stralloc_0(&username)) die_nomem();
+  if (!username.len || !s) die_badauth();
+
+  doanddie(username.s,username.len,s);
+}
+struct authcmd {
+  char *text;
+  void (*fun)();
+} authcmds[] = {
+  { "cram-md5",pop3_auth_cram }
+,  { 0,die_badauth }
+};
+
+void pop3_auth(arg) char *arg;
+{
+  int i;
+  char *cmd = arg;
+
+  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)) authcmds[i].fun(arg);
+
+  puts("-ERR unsupported method\r\n"); flush(); return;
+}
+
 struct commands pop3commands[] = {
   { "user", pop3_user, 0 }
 , { "pass", pop3_pass, 0 }
 , { "apop", pop3_apop, 0 }
+, { "auth", pop3_auth, 0 }
 , { "quit", pop3_quit, 0 }
+, { "capa", pop3_capa, 0 }
 , { "noop", okay, 0 }
 , { 0, err_authoriz, 0 }
 } ;
