Commit 1ffdc505 authored by Jiri Hruska's avatar Jiri Hruska Committed by Steve Holme
Browse files

imap: Moved CAPABILITY response handling to imap_state_capability_resp()

Introduced similar handling to the FETCH responses, where even the
untagged data responses are handled by the response handler of the
individual state.
parent 0ffefefe
Loading
Loading
Loading
Loading
+75 −74
Original line number Diff line number Diff line
@@ -323,16 +323,14 @@ static char* imap_atom(const char* str)
  return newstr;
}

/* Function that checks for an ending IMAP status code at the start of the
   given string but also detects various capabilities from the CAPABILITY
   response including the supported authentication mechanisms. */
/* Function that checks whether the given string is a valid tagged, untagged
   or continuation response which can be processed by the response handler. */
static bool imap_endofresp(struct connectdata *conn, char *line, size_t len,
                           int *resp)
{
  struct imap_conn *imapc = &conn->proto.imapc;
  const char *id = imapc->resptag;
  size_t id_len = strlen(id);
  size_t wordlen;

  /* Do we have a tagged command response? */
  if(len >= id_len + 1 && !memcmp(id, line, id_len) && line[id_len] == ' ') {
@@ -355,78 +353,20 @@ static bool imap_endofresp(struct connectdata *conn, char *line, size_t len,

  /* Do we have an untagged command response */
  if(len >= 2 && !memcmp("* ", line, 2)) {
    /* Are we processing CAPABILITY command data? */
    if(imapc->state == IMAP_CAPABILITY) {
      line += 2;
      len -= 2;

      /* Loop through the data line */
      for(;;) {
        while(len &&
              (*line == ' ' || *line == '\t' ||
               *line == '\r' || *line == '\n')) {

          line++;
          len--;
        }

        if(!len)
    switch(imapc->state) {
      /* States which are interested in untagged responses */
      case IMAP_CAPABILITY:
      case IMAP_FETCH:
        *resp = '*';
        break;
 
        /* Extract the word */
        for(wordlen = 0; wordlen < len && line[wordlen] != ' ' &&
              line[wordlen] != '\t' && line[wordlen] != '\r' &&
              line[wordlen] != '\n';)
          wordlen++;

        /* Does the server support the STARTTLS capability? */
        if(wordlen == 8 && !memcmp(line, "STARTTLS", 8))
          imapc->tls_supported = TRUE;

        /* Has the server explicitly disabled clear text authentication? */
        else if(wordlen == 13 && !memcmp(line, "LOGINDISABLED", 13))
          imapc->login_disabled = TRUE;

        /* Does the server support the SASL-IR capability? */
        else if(wordlen == 7 && !memcmp(line, "SASL-IR", 7))
          imapc->ir_supported = TRUE;

        /* Do we have a SASL based authentication mechanism? */
        else if(wordlen > 5 && !memcmp(line, "AUTH=", 5)) {
          line += 5;
          len -= 5;
          wordlen -= 5;

          /* Test the word for a matching authentication mechanism */
          if(wordlen == 5 && !memcmp(line, "LOGIN", 5))
            imapc->authmechs |= SASL_MECH_LOGIN;
          if(wordlen == 5 && !memcmp(line, "PLAIN", 5))
            imapc->authmechs |= SASL_MECH_PLAIN;
          else if(wordlen == 8 && !memcmp(line, "CRAM-MD5", 8))
            imapc->authmechs |= SASL_MECH_CRAM_MD5;
          else if(wordlen == 10 && !memcmp(line, "DIGEST-MD5", 10))
            imapc->authmechs |= SASL_MECH_DIGEST_MD5;
          else if(wordlen == 6 && !memcmp(line, "GSSAPI", 6))
            imapc->authmechs |= SASL_MECH_GSSAPI;
          else if(wordlen == 8 && !memcmp(line, "EXTERNAL", 8))
            imapc->authmechs |= SASL_MECH_EXTERNAL;
          else if(wordlen == 4 && !memcmp(line, "NTLM", 4))
            imapc->authmechs |= SASL_MECH_NTLM;
        }

        line += wordlen;
        len -= wordlen;
      }

      /* Ignore other untagged responses */
      default:
        return FALSE;
    }
    /* Are we processing FETCH command responses? */
    else if(imapc->state == IMAP_FETCH) {
      *resp = '*';

    return TRUE;
  }
  }

  /* Do we have a continuation response? */
  if((len == 3 && !memcmp("+", line, 1)) ||
@@ -755,10 +695,71 @@ static CURLcode imap_state_capability_resp(struct connectdata *conn,
  CURLcode result = CURLE_OK;
  struct SessionHandle *data = conn->data;
  struct imap_conn *imapc = &conn->proto.imapc;
  const char *line = data->state.buffer;
  size_t wordlen;

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

  if(imapcode != 'O')
  /* Do we have a untagged response? */
  if(imapcode == '*') {
    line += 2;

    /* Loop through the data line */
    for(;;) {
      while(*line &&
            (*line == ' ' || *line == '\t' ||
              *line == '\r' || *line == '\n')) {

        line++;
      }

      if(!*line)
        break;

      /* Extract the word */
      for(wordlen = 0; line[wordlen] && line[wordlen] != ' ' &&
            line[wordlen] != '\t' && line[wordlen] != '\r' &&
            line[wordlen] != '\n';)
        wordlen++;

      /* Does the server support the STARTTLS capability? */
      if(wordlen == 8 && !memcmp(line, "STARTTLS", 8))
        imapc->tls_supported = TRUE;

      /* Has the server explicitly disabled clear text authentication? */
      else if(wordlen == 13 && !memcmp(line, "LOGINDISABLED", 13))
        imapc->login_disabled = TRUE;

      /* Does the server support the SASL-IR capability? */
      else if(wordlen == 7 && !memcmp(line, "SASL-IR", 7))
        imapc->ir_supported = TRUE;

      /* Do we have a SASL based authentication mechanism? */
      else if(wordlen > 5 && !memcmp(line, "AUTH=", 5)) {
        line += 5;
        wordlen -= 5;

        /* Test the word for a matching authentication mechanism */
        if(wordlen == 5 && !memcmp(line, "LOGIN", 5))
          imapc->authmechs |= SASL_MECH_LOGIN;
        if(wordlen == 5 && !memcmp(line, "PLAIN", 5))
          imapc->authmechs |= SASL_MECH_PLAIN;
        else if(wordlen == 8 && !memcmp(line, "CRAM-MD5", 8))
          imapc->authmechs |= SASL_MECH_CRAM_MD5;
        else if(wordlen == 10 && !memcmp(line, "DIGEST-MD5", 10))
          imapc->authmechs |= SASL_MECH_DIGEST_MD5;
        else if(wordlen == 6 && !memcmp(line, "GSSAPI", 6))
          imapc->authmechs |= SASL_MECH_GSSAPI;
        else if(wordlen == 8 && !memcmp(line, "EXTERNAL", 8))
          imapc->authmechs |= SASL_MECH_EXTERNAL;
        else if(wordlen == 4 && !memcmp(line, "NTLM", 4))
          imapc->authmechs |= SASL_MECH_NTLM;
      }

      line += wordlen;
    }
  }
  else if(imapcode != 'O')
    result = imap_state_login(conn);
  else if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) {
    /* We don't have a SSL/TLS connection yet, but SSL is requested */