static CURLcode smtp_state_authcram_resp(struct connectdata *conn,
                                         int smtpcode,
                                         smtpstate instate)
{
  CURLcode result = CURLE_OK;
  struct SessionHandle *data = conn->data;
  char * chlg64 = data->state.buffer;
  unsigned char * chlg;
  size_t chlglen;
  size_t len = 0;
  char *rplyb64 = NULL;
  HMAC_context *ctxt;
  unsigned char digest[16];
  char reply[MAX_CURL_USER_LENGTH + 32 /* 2 * size of MD5 digest */ + 1];

  (void)instate; /* no use for this yet */

  if(smtpcode != 334) {
    failf(data, "Access denied: %d", smtpcode);
    return CURLE_LOGIN_DENIED;
  }

  /* Get the challenge. */
  for(chlg64 += 4; *chlg64 == ' ' || *chlg64 == '\t'; chlg64++)
    ;

  chlg = (unsigned char *) NULL;
  chlglen = 0;

  if(*chlg64 != '=') {
    for(len = strlen(chlg64); len--;)
      if(chlg64[len] != '\r' && chlg64[len] != '\n' && chlg64[len] != ' ' &&
         chlg64[len] != '\t')
        break;

    if(++len) {
      chlg64[len] = '\0';

      result = Curl_base64_decode(chlg64, &chlg, &chlglen);
      if(result)
        return result;
    }
  }

  /* Compute digest. */
  ctxt = Curl_HMAC_init(Curl_HMAC_MD5,
                        (const unsigned char *) conn->passwd,
                        (unsigned int)(strlen(conn->passwd)));

  if(!ctxt) {
    Curl_safefree(chlg);
    return CURLE_OUT_OF_MEMORY;
  }

  if(chlglen > 0)
    Curl_HMAC_update(ctxt, chlg, (unsigned int)(chlglen));

  Curl_safefree(chlg);

  Curl_HMAC_final(ctxt, digest);

  /* Prepare the reply. */
  snprintf(reply, sizeof reply,
   "%s %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
           conn->user, digest[0], digest[1], digest[2], digest[3], digest[4],
           digest[5],
           digest[6], digest[7], digest[8], digest[9], digest[10], digest[11],
           digest[12], digest[13], digest[14], digest[15]);

  /* Encode it to base64 and send it. */
  result = Curl_base64_encode(data, reply, 0, &rplyb64, &len);

  if(!result) {
    if(rplyb64) {
      result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", rplyb64);

      if(!result)
        state(conn, SMTP_AUTH);
    }
    Curl_safefree(rplyb64);
  }

  return result;
}
static CURLcode smtp_state_authcram_resp(struct connectdata *conn,
                                         int smtpcode,
                                         smtpstate instate)
{
  CURLcode result = CURLE_OK;
  struct SessionHandle *data = conn->data;
  char * chlg64 = data->state.buffer;
  unsigned char * chlg;
  size_t chlglen;
  size_t len = 0;
  char *rplyb64 = NULL;
  HMAC_context *ctxt;
  unsigned char digest[16];
  char reply[MAX_CURL_USER_LENGTH + 32   + 1];

  (void)instate;  

  if(smtpcode != 334) {
    failf(data, "Access denied: %d", smtpcode);
    return CURLE_LOGIN_DENIED;
  }

   
  for(chlg64 += 4; *chlg64 == ' ' || *chlg64 == '\t'; chlg64++)
    ;

  chlg = (unsigned char *) NULL;
  chlglen = 0;

  if(*chlg64 != '=') {
    for(len = strlen(chlg64); len--;)
      if(chlg64[len] != '\r' && chlg64[len] != '\n' && chlg64[len] != ' ' &&
         chlg64[len] != '\t')
        break;

    if(++len) {
      chlg64[len] = '\0';

      result = Curl_base64_decode(chlg64, &chlg, &chlglen);
      if(result)
        return result;
    }
  }

   
  ctxt = Curl_HMAC_init(Curl_HMAC_MD5,
                        (const unsigned char *) conn->passwd,
                        (unsigned int)(strlen(conn->passwd)));

  if(!ctxt) {
    Curl_safefree(chlg);
    return CURLE_OUT_OF_MEMORY;
  }

  if(chlglen > 0)
    Curl_HMAC_update(ctxt, chlg, (unsigned int)(chlglen));

  Curl_safefree(chlg);

  Curl_HMAC_final(ctxt, digest);

   
  snprintf(reply, sizeof reply,
   "%s %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
           conn->user, digest[0], digest[1], digest[2], digest[3], digest[4],
           digest[5],
           digest[6], digest[7], digest[8], digest[9], digest[10], digest[11],
           digest[12], digest[13], digest[14], digest[15]);

   
  result = Curl_base64_encode(data, reply, 0, &rplyb64, &len);

  if(!result) {
    if(rplyb64) {
      result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", rplyb64);

      if(!result)
        state(conn, SMTP_AUTH);
    }
    Curl_safefree(rplyb64);
  }

  return result;
}