From 4e430a8a16460f340c776dbd6f305cdf1e9dacc8 Mon Sep 17 00:00:00 2001
From: Steve Holme <steve_holme@hotmail.com>
Date: Sat, 9 Jun 2012 11:48:44 +0100
Subject: [PATCH] pop3: Enhanced the extended authentication mechanism
 detection

Enhanced the authentication type / mechanism detection in preparation
for the introduction of APOP support.
---
 lib/pop3.c | 35 +++++++++++++++++++++++++++++------
 lib/pop3.h |  8 +++++++-
 2 files changed, 36 insertions(+), 7 deletions(-)

diff --git a/lib/pop3.c b/lib/pop3.c
index a166208db..1e399a03b 100644
--- a/lib/pop3.c
+++ b/lib/pop3.c
@@ -22,6 +22,7 @@
  * RFC1939 POP3 protocol
  * RFC2195 CRAM-MD5 authentication
  * RFC2384 POP URL Scheme
+ * RFC2449 POP3 Extension Mechanism
  * RFC2595 Using TLS with IMAP, POP3 and ACAP
  * RFC2831 DIGEST-MD5 authentication
  * RFC4616 PLAIN authentication
@@ -212,8 +213,8 @@ static const struct Curl_handler Curl_handler_pop3s_proxy = {
 #endif
 
 /* Function that checks for an ending pop3 status code at the start of the
-   given string, but also detects the allowed authentication mechanisms
-   according to the CAPA response. */
+   given string, but also detects the supported authentication types as well
+   as the allowed SASL authentication mechanisms within the CAPA response. */
 static int pop3_endofresp(struct pingpong *pp, int *resp)
 {
   char *line = pp->linestart_resp;
@@ -239,11 +240,24 @@ static int pop3_endofresp(struct pingpong *pp, int *resp)
       return TRUE;
     }
 
-    /* We are only interested in the SASL line */
-    if(len < 4 || memcmp(line, "SASL", 4)) {
+    /* Does the server support clear text? */
+    if(len >= 4 && !memcmp(line, "USER", 4)) {
+      pop3c->authtypes |= POP3_TYPE_CLEARTEXT;
       return FALSE;
     }
 
+    /* Does the server support APOP? */
+    if(len >= 4 && !memcmp(line, "APOP", 4)) {
+      pop3c->authtypes |= POP3_TYPE_APOP;
+      return FALSE;
+    }
+
+    /* Does the server support SASL? */
+    if(len < 4 || memcmp(line, "SASL", 4))
+      return FALSE;
+
+    pop3c->authtypes |= POP3_TYPE_SASL;
+
     /* Advance past the SASL keyword */
     line += 4;
     len -= 4;
@@ -524,8 +538,17 @@ static CURLcode pop3_state_capa_resp(struct connectdata *conn,
 
   if(pop3code != '+')
     result = pop3_state_user(conn);
-  else
-    result = pop3_authenticate(conn);
+  else {
+    /* Check supported authentication types by decreasing order of security */
+    if(conn->proto.pop3c.authtypes & POP3_TYPE_SASL)
+      result = pop3_authenticate(conn);
+    else if(conn->proto.pop3c.authtypes & POP3_TYPE_CLEARTEXT)
+      result = pop3_state_user(conn);
+    else {
+      infof(conn->data, "No known authentication types supported!\n");
+      result = CURLE_LOGIN_DENIED; /* Other types not supported */
+    }
+  }
 
   return result;
 }
diff --git a/lib/pop3.h b/lib/pop3.h
index 949ac5059..1ca8bb289 100644
--- a/lib/pop3.h
+++ b/lib/pop3.h
@@ -57,14 +57,20 @@ struct pop3_conn {
                              have been received so far */
   size_t strip;           /* Number of bytes from the start to ignore as
                              non-body */
+  unsigned int authtypes; /* Supported authentication types */
   unsigned int authmechs; /* Accepted SASL authentication mechanisms */
-  unsigned int authused;  /* Authentication method used for the connection */
+  unsigned int authused;  /* SASL auth mechanism used for the connection */
   pop3state state;        /* Always use pop3.c:state() to change state! */
 };
 
 extern const struct Curl_handler Curl_handler_pop3;
 extern const struct Curl_handler Curl_handler_pop3s;
 
+/* Authentication type flags */
+#define POP3_TYPE_CLEARTEXT 0x0001
+#define POP3_TYPE_APOP      0x0002
+#define POP3_TYPE_SASL      0x0004
+
 /* This is the 5-bytes End-Of-Body marker for POP3 */
 #define POP3_EOB "\x0d\x0a\x2e\x0d\x0a"
 #define POP3_EOB_LEN 5