--- popcheck.c.orig	Tue Sep 11 03:34:42 2001
+++ popcheck.c	Tue Sep 11 03:33:39 2001
@@ -20,6 +20,14 @@
 
 #include "popcheck.h"
 
+//! drew's headers:
+#define strfcpy(A,B,C) strncpy(A,B,C), *(A+(C)-1)=0
+#include "base64.c"
+#define MD5_BLOCK_LEN 64
+#define MD5_DIGEST_LEN 16
+#include "md5.h"
+#include "md5c.c"
+
 #define TIMEOUT 5
 static int get_server_port(const char *);
 static char* get_server_hostname(const char *);
@@ -243,7 +251,8 @@
   int i = 10; /* read not more than 10 lines */
   
   while (i--)
-   {
+    //while (1)//! 
+  {
     p = read_line(s);
     if (!p) return 0;
     if (strncmp(p, tag, strlen(tag)) == 0) return p;
@@ -252,74 +261,203 @@
   return 0; 
  }
 
+
+/* hmac_md5: produce CRAM-MD5 challenge response. */
+static void hmac_md5 (const char* password, char* challenge,
+  unsigned char* response)
+{
+  MD5_CTX ctx;
+  unsigned char ipad[MD5_BLOCK_LEN], opad[MD5_BLOCK_LEN];
+  unsigned char secret[MD5_BLOCK_LEN+1];
+  unsigned char hash_passwd[MD5_DIGEST_LEN];
+  unsigned int secret_len, chal_len;
+  int i;
+
+  secret_len = strlen (password);
+  chal_len = strlen (challenge);
+
+  /* passwords longer than MD5_BLOCK_LEN bytes are substituted with their MD5
+   * digests */
+  if (secret_len > MD5_BLOCK_LEN)
+  {
+    MD5Init (&ctx);
+    MD5Update (&ctx, (unsigned char*) password, secret_len);
+    MD5Final (hash_passwd, &ctx);
+    strfcpy ((char*) secret, (char*) hash_passwd, MD5_DIGEST_LEN);
+    secret_len = MD5_DIGEST_LEN;
+  }
+  else
+    strfcpy ((char *) secret, password, sizeof (secret));
+
+  memset (ipad, 0, sizeof (ipad));
+  memset (opad, 0, sizeof (opad));
+  memcpy (ipad, secret, secret_len);
+  memcpy (opad, secret, secret_len);
+
+  for (i = 0; i < MD5_BLOCK_LEN; i++)
+  {
+    ipad[i] ^= 0x36;
+    opad[i] ^= 0x5c;
+  }
+
+  /* inner hash: challenge and ipadded secret */
+  MD5Init (&ctx);
+  MD5Update (&ctx, ipad, MD5_BLOCK_LEN);
+  MD5Update (&ctx, (unsigned char*) challenge, chal_len);
+  MD5Final (response, &ctx);
+
+  /* outer hash: inner hash and opadded secret */
+  MD5Init (&ctx);
+  MD5Update (&ctx, opad, MD5_BLOCK_LEN);
+  MD5Update (&ctx, response, MD5_DIGEST_LEN);
+  MD5Final (response, &ctx);
+}
+
+
+
 int 
-imap_check(const char *h, const char* n, const char* e, const char* f)
+imap_check (const char *h,  //remote_server
+	   const char* n, //remote_username
+	   const char* e,  //real_password 
+	   const char *f) //remote_folder
 {
-	int s;
-	char *c = NULL;
-	char *x;
-	unsigned int r = (unsigned int) -1;
-	int total = 0, unseen = 0;
-	int count = 0;
-	
-	if (!h || !n || !e) return -1;
-	
-	if (f == NULL ||
-	    f[0] == '\0')
-		f = "INBOX";
-	
-	s = connect_socket(h, 143);
-	
-	if (s < 0)
-		return r;
-	
-	x = read_line(s);
-	/* The greeting us untagged */
-	if (!is_imap_answer_untagged(x))
-		goto return_from_imap_check;
-	
-	if (!is_imap_answer_ok(x))
-		goto return_from_imap_check;
-	
-	
-	c = g_strdup_printf("A1 LOGIN \"%s\" \"%s\"", n, e);
-	if (!write_line(s, c))
-		goto return_from_imap_check;
-	
-	if (!is_imap_answer_ok(wait_for_imap_answer(s, "A1")))
-		goto return_from_imap_check;
-	
-	
-	c = g_strdup_printf("A2 STATUS \"%s\" (MESSAGES UNSEEN)",f);
-	if (!write_line(s, c))
-		goto return_from_imap_check;
-	
-	/* We only loop 5 times if more than that this is
-	 * probably a bogus reply */
-	for (count = 0, x = read_line(s);
-	     count < 5 && x != NULL;
-	     count++, x = read_line(s)) {
-		char tmpstr[4096];
-		
-		if (sscanf(x, "%*s %*s %*s %*s %d %4095s %d",
-			   &total, tmpstr, &unseen) != 3)
-			continue;
-		if (strcmp(tmpstr, "UNSEEN") == 0)
-			break;
-		
-	}
+  int s; //temp variable
+  char *c = NULL; //stores outgoing messages
+  char *x; //stores incoming messages
+  unsigned int r = (unsigned int) -1; //number of messages
+  int total = 0, unseen = 0;
+  int count = 0;
+	
+  if (!h || !n || !e) return -1; //must have server, user, and password
+  //!should we perhaps allow a null password?
+	
+  if (f == NULL ||
+      f[0] == '\0')
+    f = "INBOX";
+	
+  s = connect_socket(h, 143);
+	
+  if (s < 0) //connection to server failed
+    return r;
+	
+  x = wait_for_imap_answer(s, ""); 
+  //  x = read_line(s); //read greeting from server
+  if (!is_imap_answer_untagged(x))
+    goto return_from_imap_check;
+	
+  if (!is_imap_answer_ok(x))
+    goto return_from_imap_check;
+
+  //check to see what auth methods are supported
+  c = g_strdup_printf("A0 CAPABILITY");
+  if (!write_line(s, c))
+    goto return_from_imap_check;
+
+  x = wait_for_imap_answer(s, "\*");  //! unknown escape char
+    //  x = read_line(s); //read capability response
+
+  g_warning("capability response:%s",x); //!
+
+
+
+  if (strstr(x, "CRAM-MD5")) //!
+    {  //perform cram-md5 auth
+      char decoded[400]; //stores decoded challenge
+      char ibuf[900]; //stores incoming messages //!
+
+      unsigned char hmac_response[MD5_DIGEST_LEN]; //response for md5 stuff //!
+
+      g_warning("doing cram-md5 auth"); //!
+
+      x = wait_for_imap_answer(s, "A0"); 
+	//x = read_line(s); //remove "A0 OK CAPABILITY completed" from response
+
+
+      c = g_strdup_printf("A1 AUTHENTICATE CRAM-MD5");
+      if (!write_line(s, c))
+       	goto return_from_imap_check;
+
+      //      x = wait_for_imap_answer(s, '+'); 
+      x = wait_for_imap_answer(s, ""); 
+      //      x = read_line(s); //get challenge string (it's base64 encoded)
+
+      //      if ( *strchr(x+2, '+') != strlen(x+2) ) //! what was I thinking here?
+      if (13 == x[strlen(x) - 1])
+	x[strlen(x) - 1] = 0; //replace char[\13] with null
+
+
+
+      decoded[mutt_from_base64 (decoded, x+2)] = '\0'; //decode from base64
+      //* (strchr(decoded, '>') + 1) = 0; //put null after > //!
+
+      
+
+      hmac_md5 (e, decoded, hmac_response); //e is password
+
+      snprintf (decoded, sizeof (decoded),
+		"%s %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
+		n, //user name
+		hmac_response[0], hmac_response[1], 
+		hmac_response[2], hmac_response[3],
+		hmac_response[4], hmac_response[5], 
+		hmac_response[6], hmac_response[7],
+		hmac_response[8], hmac_response[9], 
+		hmac_response[10], hmac_response[11],
+		hmac_response[12], hmac_response[13], 
+		hmac_response[14], hmac_response[15]);
+
+ 
+            mutt_to_base64 ((unsigned char*) ibuf, (unsigned char*) decoded, strlen (decoded), sizeof (ibuf) - 2);
+
+
+
+      c = g_strdup_printf("%s",ibuf);
+      if (!write_line(s, c))
+	goto return_from_imap_check;
+     
+    }
+  else
+    { //perform plaintext auth
+      x = read_line(s); //remove "A0 OK CAPABILITY completed" from response 
+      c = g_strdup_printf("A1 LOGIN \"%s\" \"%s\"", n, e);
+      if (!write_line(s, c))
+	goto return_from_imap_check;
+    }
+
+
+  if (!is_imap_answer_ok(wait_for_imap_answer(s, "A1")))
+    goto return_from_imap_check;
+	
+  c = g_strdup_printf("A2 STATUS \"%s\" (MESSAGES UNSEEN)",f);
+  if (!write_line(s, c))
+    goto return_from_imap_check;
+	
+  /* We only loop 5 times if more than that this is
+   * probably a bogus reply */
+  for (count = 0, x = read_line(s);
+       count < 5 && x != NULL;
+       count++, x = read_line(s)) {
+    char tmpstr[4096];
+    
+    if (sscanf(x, "%*s %*s %*s %*s %d %4095s %d",
+	       &total, tmpstr, &unseen) != 3)
+      continue;
+    if (strcmp(tmpstr, "UNSEEN") == 0)
+      break;
+    
+  }
 	
-	r = (((unsigned int) unseen ) << 16) | /* lt unseen only */
-		((unsigned int) total & 0x0000FFFFL);
+  r = (((unsigned int) unseen ) << 16) | /* lt unseen only */
+    ((unsigned int) total & 0x0000FFFFL);
 	
-	if (write_line(s, "A3 LOGOUT"))
-		read_line(s);
+  if (write_line(s, "A3 LOGOUT"))
+    read_line(s);
 
  return_from_imap_check:
 
-	g_free (c);
-	close (s);
+  g_free (c);
+  close (s);
 	
-	return r; 
+  return r; 
  }
 
