* (Note: it's unspecified whether the user name needs IMAP quoting.)
* Note: The user name shouldn't be quoted. Since the digest can't contain *   spaces, there is no ambiguity. Some servers get this wrong, we'll work *   around them when the bug report comes in. Until then, we'll remain *   blissfully RFC-compliant.
static int imap_auth_cram_md5 (IMAP_DATA* idata, const char* user,  const char* pass){  char ibuf[LONG_STRING], obuf[LONG_STRING];  unsigned char hmac_response[MD5_DIGEST_LEN];  int len;  char seq[16];  dprint (2, (debugfile, "Attempting CRAM-MD5 login...\n"));  mutt_message _("Authenticating (CRAM-MD5)...");  imap_make_sequence (seq, sizeof (seq));  snprintf (obuf, LONG_STRING, "%s AUTHENTICATE CRAM-MD5\r\n", seq);  mutt_socket_write (idata->conn, obuf);  /* From RFC 2195:   * The data encoded in the first ready response contains a presumptively   * arbitrary string of random digits, a timestamp, and the fully-qualified   * primary host name of the server. The syntax of the unencoded form must   * correspond to that of an RFC 822 'msg-id' [RFC822] as described in [POP3].   */  if (mutt_socket_read_line_d (ibuf, LONG_STRING, idata->conn) < 0)  {    dprint (1, (debugfile, "Error receiving server response.\n"));    return -1;  }  if (ibuf[0] != '+')  {    dprint (1, (debugfile, "Invalid response from server: %s\n", ibuf));    return -1;  }  if ((len = mutt_from_base64 (obuf, ibuf + 2)) == -1)  {    dprint (1, (debugfile, "Error decoding base64 response.\n"));    return -1;  }  obuf[len] = '\0';  dprint (2, (debugfile, "CRAM challenge: %s\n", obuf));  /* The client makes note of the data and then responds with a string   * consisting of the user name, a space, and a 'digest'. The latter is   * computed by applying the keyed MD5 algorithm from [KEYED-MD5] where the   * key is a shared secret and the digested text is the timestamp (including   * angle-brackets).   *    * (Note: it's unspecified whether the user name needs IMAP quoting.)   */   hmac_md5 (pass, obuf, hmac_response);   dprint (2, (debugfile, "CRAM response: %s,[%s]->", obuf, pass));   /* dubious optimisation I saw elsewhere: make the whole string in one call */  snprintf (obuf, sizeof (obuf),    "%s %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",    user,    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]);  dprint(2, (debugfile, "%s\n", obuf));  mutt_to_base64 ((unsigned char*) ibuf, (unsigned char*) obuf, strlen (obuf));  strcpy (ibuf + strlen (ibuf), "\r\n");  mutt_socket_write (idata->conn, ibuf);  if (mutt_socket_read_line_d (ibuf, LONG_STRING, idata->conn) < 0)  {    dprint (1, (debugfile, "Error receiving server response.\n"));    return -1;  }  if (imap_code (ibuf))  {    dprint (2, (debugfile, "CRAM login complete.\n"));    return 0;  }  dprint (2, (debugfile, "CRAM login failed.\n"));  return -1;}