--- ../netqmail-1.05-smtp-auth/Makefile	2004-03-11 11:15:35.000000000 +0100
+++ Makefile	2004-03-11 11:32:04.000000000 +0100
@@ -1293,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
@@ -1305,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: \
--- ../netqmail-1.05-smtp-auth/qmail-popup.c	2004-03-03 12:03:42.000000000 +0100
+++ qmail-popup.c	2004-03-11 11:30:19.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,19 @@
   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 +177,100 @@
   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 }
 } ;
