Exemple #1
0
static void
tcpkeepalive(struct SessionHandle *data,
             curl_socket_t sockfd)
{
  int optval = data->set.tcp_keepalive?1:0;

  /* only set IDLE and INTVL if setting KEEPALIVE is successful */
  if(setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE,
        (void *)&optval, sizeof(optval)) < 0) {
    infof(data, "Failed to set SO_KEEPALIVE on fd %d\n", sockfd);
  }
  else {
#ifdef TCP_KEEPIDLE
    optval = curlx_sltosi(data->set.tcp_keepidle);
    KEEPALIVE_FACTOR(optval);
    if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPIDLE,
          (void *)&optval, sizeof(optval)) < 0) {
      infof(data, "Failed to set TCP_KEEPIDLE on fd %d\n", sockfd);
    }
#endif
#ifdef TCP_KEEPINTVL
    optval = curlx_sltosi(data->set.tcp_keepintvl);
    KEEPALIVE_FACTOR(optval);
    if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPINTVL,
          (void *)&optval, sizeof(optval)) < 0) {
      infof(data, "Failed to set TCP_KEEPINTVL on fd %d\n", sockfd);
    }
#endif
  }
}
Exemple #2
0
static void
tcpkeepalive(struct Curl_easy *data,
             curl_socket_t sockfd)
{
    int optval = data->set.tcp_keepalive?1:0;

    /* only set IDLE and INTVL if setting KEEPALIVE is successful */
    if(setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE,
                  (void *)&optval, sizeof(optval)) < 0) {
        infof(data, "Failed to set SO_KEEPALIVE on fd %d\n", sockfd);
    }
    else {
#if defined(SIO_KEEPALIVE_VALS)
        struct tcp_keepalive vals;
        DWORD dummy;
        vals.onoff = 1;
        optval = curlx_sltosi(data->set.tcp_keepidle);
        KEEPALIVE_FACTOR(optval);
        vals.keepalivetime = optval;
        optval = curlx_sltosi(data->set.tcp_keepintvl);
        KEEPALIVE_FACTOR(optval);
        vals.keepaliveinterval = optval;
        if(WSAIoctl(sockfd, SIO_KEEPALIVE_VALS, (LPVOID) &vals, sizeof(vals),
                    NULL, 0, &dummy, NULL, NULL) != 0) {
            infof(data, "Failed to set SIO_KEEPALIVE_VALS on fd %d: %d\n",
                  (int)sockfd, WSAGetLastError());
        }
#elif defined(CURL_WINDOWS_APP)
        (void)majorVersion;
        detectOsState = DETECT_OS_VISTA_OR_LATER;
#else
#ifdef TCP_KEEPIDLE
        optval = curlx_sltosi(data->set.tcp_keepidle);
        KEEPALIVE_FACTOR(optval);
        if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPIDLE,
                      (void *)&optval, sizeof(optval)) < 0) {
            infof(data, "Failed to set TCP_KEEPIDLE on fd %d\n", sockfd);
        }
#endif
#ifdef TCP_KEEPINTVL
        optval = curlx_sltosi(data->set.tcp_keepintvl);
        KEEPALIVE_FACTOR(optval);
        if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPINTVL,
                      (void *)&optval, sizeof(optval)) < 0) {
            infof(data, "Failed to set TCP_KEEPINTVL on fd %d\n", sockfd);
        }
#endif
#ifdef TCP_KEEPALIVE
        /* Mac OS X style */
        optval = curlx_sltosi(data->set.tcp_keepidle);
        KEEPALIVE_FACTOR(optval);
        if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPALIVE,
                      (void *)&optval, sizeof(optval)) < 0) {
            infof(data, "Failed to set TCP_KEEPALIVE on fd %d\n", sockfd);
        }
#endif
#endif
    }
}
Exemple #3
0
/***********************************************************************
 *
 * smtp_endofresp()
 *
 * Checks for an ending SMTP status code at the start of the given string, but
 * also detects various capabilities from the EHLO response including the
 * supported authentication mechanisms.
 */
static bool smtp_endofresp(struct connectdata *conn, char *line, size_t len,
                           int *resp)
{
  struct smtp_conn *smtpc = &conn->proto.smtpc;
  bool result = FALSE;

  /* Nothing for us */
  if(len < 4 || !ISDIGIT(line[0]) || !ISDIGIT(line[1]) || !ISDIGIT(line[2]))
    return FALSE;

  /* Do we have a command response? This should be the response code followed
     by a space and optionally some text as per RFC-5321 and as outlined in
     Section 4. Examples of RFC-4954 but some e-mail servers ignore this and
     only send the response code instead as per Section 4.2. */
  if(line[3] == ' ' || len == 5) {
    result = TRUE;
    *resp = curlx_sltosi(strtol(line, NULL, 10));

    /* Make sure real server never sends internal value */
    if(*resp == 1)
      *resp = 0;
  }
  /* Do we have a multiline (continuation) response? */
  else if(line[3] == '-' &&
          (smtpc->state == SMTP_EHLO || smtpc->state == SMTP_COMMAND)) {
    result = TRUE;
    *resp = 1;  /* Internal response code */
  }

  return result;
}
Exemple #4
0
/* Function that checks for an ending smtp status code at the start of the
   given string.
   As a side effect, it also flags allowed authentication mechanisms according
   to EHLO AUTH response. */
static int smtp_endofresp(struct pingpong *pp, int *resp)
{
  char *line = pp->linestart_resp;
  size_t len = pp->nread_resp;
  struct connectdata *conn = pp->conn;
  struct smtp_conn *smtpc = &conn->proto.smtpc;
  int result;
  size_t wordlen;

  if(len < 4 || !ISDIGIT(line[0]) || !ISDIGIT(line[1]) || !ISDIGIT(line[2]))
    return FALSE;       /* Nothing for us. */

  if((result = (line[3] == ' ')) != 0)
    *resp = curlx_sltosi(strtol(line, NULL, 10));

  line += 4;
  len -= 4;

  if(smtpc->state == SMTP_EHLO && len >= 5 && !memcmp(line, "AUTH ", 5)) {
    line += 5;
    len -= 5;

    for(;;) {
      while(len &&
            (*line == ' ' || *line == '\t' ||
             *line == '\r' || *line == '\n')) {
        line++;
        len--;
      }

      if(!len)
        break;

      for(wordlen = 0; wordlen < len && line[wordlen] != ' ' &&
            line[wordlen] != '\t' && line[wordlen] != '\r' &&
            line[wordlen] != '\n';)
        wordlen++;

      if(wordlen == 5 && !memcmp(line, "LOGIN", 5))
        smtpc->authmechs |= SMTP_AUTH_LOGIN;
      else if(wordlen == 5 && !memcmp(line, "PLAIN", 5))
        smtpc->authmechs |= SMTP_AUTH_PLAIN;
      else if(wordlen == 8 && !memcmp(line, "CRAM-MD5", 8))
        smtpc->authmechs |= SMTP_AUTH_CRAM_MD5;
      else if(wordlen == 10 && !memcmp(line, "DIGEST-MD5", 10))
        smtpc->authmechs |= SMTP_AUTH_DIGEST_MD5;
      else if(wordlen == 6 && !memcmp(line, "GSSAPI", 6))
        smtpc->authmechs |= SMTP_AUTH_GSSAPI;
      else if(wordlen == 8 && !memcmp(line, "EXTERNAL", 8))
        smtpc->authmechs |= SMTP_AUTH_EXTERNAL;
      else if(wordlen == 4 && !memcmp(line, "NTLM", 4))
        smtpc->authmechs |= SMTP_AUTH_NTLM;

      line += wordlen;
      len -= wordlen;
    }
  }

  return result;
}
Exemple #5
0
int Curl_parsedate(const char *date, time_t *output)
{
  time_t t = 0;
  int wdaynum=-1;  /* day of the week number, 0-6 (mon-sun) */
  int monnum=-1;   /* month of the year number, 0-11 */
  int mdaynum=-1; /* day of month, 1 - 31 */
  int hournum=-1;
  int minnum=-1;
  int secnum=-1;
  int yearnum=-1;
  int tzoff=-1;
  struct my_tm tm;
  enum assume dignext = DATE_MDAY;
  const char *indate = date; /* save the original pointer */
  int part = 0; /* max 6 parts */

  while(*date && (part < 6)) {
    bool found=FALSE;

    skip(&date);

    if(ISALPHA(*date)) {
      /* a name coming up */
      char buf[32]="";
      size_t len;
      sscanf(date, "%31[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz]",
             buf);
      len = strlen(buf);

      if(wdaynum == -1) {
        wdaynum = checkday(buf, len);
        if(wdaynum != -1)
          found = TRUE;
      }
      if(!found && (monnum == -1)) {
        monnum = checkmonth(buf);
        if(monnum != -1)
          found = TRUE;
      }

      if(!found && (tzoff == -1)) {
        /* this just must be a time zone string */
        tzoff = checktz(buf);
        if(tzoff != -1)
          found = TRUE;
      }

      if(!found)
        return PARSEDATE_FAIL; /* bad string */

      date += len;
    }
    else if(ISDIGIT(*date)) {
      /* a digit */
      int val;
      char *end;
      if((secnum == -1) &&
         (3 == sscanf(date, "%02d:%02d:%02d", &hournum, &minnum, &secnum))) {
        /* time stamp! */
        date += 8;
      }
      else if((secnum == -1) &&
              (2 == sscanf(date, "%02d:%02d", &hournum, &minnum))) {
        /* time stamp without seconds */
        date += 5;
        secnum = 0;
      }
      else {
        val = curlx_sltosi(strtol(date, &end, 10));

        if((tzoff == -1) &&
           ((end - date) == 4) &&
           (val <= 1400) &&
           (indate< date) &&
           ((date[-1] == '+' || date[-1] == '-'))) {
          /* four digits and a value less than or equal to 1400 (to take into
             account all sorts of funny time zone diffs) and it is preceeded
             with a plus or minus. This is a time zone indication.  1400 is
             picked since +1300 is frequently used and +1400 is mentioned as
             an edge number in the document "ISO C 200X Proposal: Timezone
             Functions" at http://david.tribble.com/text/c0xtimezone.html If
             anyone has a more authoritative source for the exact maximum time
             zone offsets, please speak up! */
          found = TRUE;
          tzoff = (val/100 * 60 + val%100)*60;

          /* the + and - prefix indicates the local time compared to GMT,
             this we need ther reversed math to get what we want */
          tzoff = date[-1]=='+'?-tzoff:tzoff;
        }

        if(((end - date) == 8) &&
           (yearnum == -1) &&
           (monnum == -1) &&
           (mdaynum == -1)) {
          /* 8 digits, no year, month or day yet. This is YYYYMMDD */
          found = TRUE;
          yearnum = val/10000;
          monnum = (val%10000)/100-1; /* month is 0 - 11 */
          mdaynum = val%100;
        }

        if(!found && (dignext == DATE_MDAY) && (mdaynum == -1)) {
          if((val > 0) && (val<32)) {
            mdaynum = val;
            found = TRUE;
          }
          dignext = DATE_YEAR;
        }

        if(!found && (dignext == DATE_YEAR) && (yearnum == -1)) {
          yearnum = val;
          found = TRUE;
          if(yearnum < 1900) {
            if(yearnum > 70)
              yearnum += 1900;
            else
              yearnum += 2000;
          }
          if(mdaynum == -1)
            dignext = DATE_MDAY;
        }

        if(!found)
          return PARSEDATE_FAIL;

        date = end;
      }
    }

    part++;
  }

  if(-1 == secnum)
    secnum = minnum = hournum = 0; /* no time, make it zero */

  if((-1 == mdaynum) ||
     (-1 == monnum) ||
     (-1 == yearnum))
    /* lacks vital info, fail */
    return PARSEDATE_FAIL;

#if SIZEOF_TIME_T < 5
  /* 32 bit time_t can only hold dates to the beginning of 2038 */
  if(yearnum > 2037) {
    *output = 0x7fffffff;
    return PARSEDATE_LATER;
  }
#endif

  if(yearnum < 1970) {
    *output = 0;
    return PARSEDATE_SOONER;
  }

  tm.tm_sec = secnum;
  tm.tm_min = minnum;
  tm.tm_hour = hournum;
  tm.tm_mday = mdaynum;
  tm.tm_mon = monnum;
  tm.tm_year = yearnum - 1900;

  /* my_timegm() returns a time_t. time_t is often 32 bits, even on many
     architectures that feature 64 bit 'long'.

     Some systems have 64 bit time_t and deal with years beyond 2038. However,
     even on some of the systems with 64 bit time_t mktime() returns -1 for
     dates beyond 03:14:07 UTC, January 19, 2038. (Such as AIX 5100-06)
  */
  t = my_timegm(&tm);

  /* time zone adjust (cast t to int to compare to negative one) */
  if(-1 != (int)t) {

    /* Add the time zone diff between local time zone and GMT. */
    long delta = (long)(tzoff!=-1?tzoff:0);

    if((delta>0) && (t + delta < t))
      return -1; /* time_t overflow */

    t += delta;
  }

  *output = t;

  return PARSEDATE_OK;
}
Exemple #6
0
/* Function that checks for an ending SMTP status code at the start of the
   given string, but also detects various capabilities from the EHLO response
   including the supported authentication mechanisms. */
static bool smtp_endofresp(struct connectdata *conn, char *line, size_t len,
                           int *resp)
{
  struct smtp_conn *smtpc = &conn->proto.smtpc;
  bool result = FALSE;
  size_t wordlen;

  if(len < 4 || !ISDIGIT(line[0]) || !ISDIGIT(line[1]) || !ISDIGIT(line[2]))
    return FALSE;       /* Nothing for us */

  /* Do we have a command response? */
  result = (line[3] == ' ') ? TRUE : FALSE;
  if(result)
    *resp = curlx_sltosi(strtol(line, NULL, 10));

  /* Are we processing EHLO command data? */
  if(smtpc->state == SMTP_EHLO && (!result || (result && *resp/100 == 2))) {
    line += 4;
    len -= 4;

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

    /* Does the server support the SIZE capability? */
    else if(len >= 4 && !memcmp(line, "SIZE", 4))
      smtpc->size_supported = TRUE;

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

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

          line++;
          len--;
        }

        if(!len)
          break;

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

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

        line += wordlen;
        len -= wordlen;
      }
    }
  }

  return result;
}
Exemple #7
0
static int parsedate(const char *date, time_t *output)
{
  time_t t = 0;
  int wdaynum = -1;  /* day of the week number, 0-6 (mon-sun) */
  int monnum = -1;   /* month of the year number, 0-11 */
  int mdaynum = -1; /* day of month, 1 - 31 */
  int hournum = -1;
  int minnum = -1;
  int secnum = -1;
  int yearnum = -1;
  int tzoff = -1;
  struct my_tm tm;
  enum assume dignext = DATE_MDAY;
  const char *indate = date; /* save the original pointer */
  int part = 0; /* max 6 parts */

  while(*date && (part < 6)) {
    bool found = FALSE;

    skip(&date);

    if(ISALPHA(*date)) {
      /* a name coming up */
      char buf[32]="";
      size_t len;
      if(sscanf(date, "%31[ABCDEFGHIJKLMNOPQRSTUVWXYZ"
                          "abcdefghijklmnopqrstuvwxyz]", buf))
        len = strlen(buf);
      else
        len = 0;

      if(wdaynum == -1) {
        wdaynum = checkday(buf, len);
        if(wdaynum != -1)
          found = TRUE;
      }
      if(!found && (monnum == -1)) {
        monnum = checkmonth(buf);
        if(monnum != -1)
          found = TRUE;
      }

      if(!found && (tzoff == -1)) {
        /* this just must be a time zone string */
        tzoff = checktz(buf);
        if(tzoff != -1)
          found = TRUE;
      }

      if(!found)
        return PARSEDATE_FAIL; /* bad string */

      date += len;
    }
    else if(ISDIGIT(*date)) {
      /* a digit */
      int val;
      char *end;
      int len = 0;
      if((secnum == -1) &&
         (3 == sscanf(date, "%02d:%02d:%02d%n",
                      &hournum, &minnum, &secnum, &len))) {
        /* time stamp! */
        date += len;
      }
      else if((secnum == -1) &&
              (2 == sscanf(date, "%02d:%02d%n", &hournum, &minnum, &len))) {
        /* time stamp without seconds */
        date += len;
        secnum = 0;
      }
      else {
        long lval;
        int error;
        int old_errno;

        old_errno = errno;
        errno = 0;
        lval = strtol(date, &end, 10);
        error = errno;
        if(errno != old_errno)
          errno = old_errno;

        if(error)
          return PARSEDATE_FAIL;

#if LONG_MAX != INT_MAX
        if((lval > (long)INT_MAX) || (lval < (long)INT_MIN))
          return PARSEDATE_FAIL;
#endif

        val = curlx_sltosi(lval);

        if((tzoff == -1) &&
           ((end - date) == 4) &&
           (val <= 1400) &&
           (indate< date) &&
           ((date[-1] == '+' || date[-1] == '-'))) {
          /* four digits and a value less than or equal to 1400 (to take into
             account all sorts of funny time zone diffs) and it is preceded
             with a plus or minus. This is a time zone indication.  1400 is
             picked since +1300 is frequently used and +1400 is mentioned as
             an edge number in the document "ISO C 200X Proposal: Timezone
             Functions" at http://david.tribble.com/text/c0xtimezone.html If
             anyone has a more authoritative source for the exact maximum time
             zone offsets, please speak up! */
          found = TRUE;
          tzoff = (val/100 * 60 + val%100)*60;

          /* the + and - prefix indicates the local time compared to GMT,
             this we need their reversed math to get what we want */
          tzoff = date[-1]=='+'?-tzoff:tzoff;
        }

        if(((end - date) == 8) &&
           (yearnum == -1) &&
           (monnum == -1) &&
           (mdaynum == -1)) {
          /* 8 digits, no year, month or day yet. This is YYYYMMDD */
          found = TRUE;
          yearnum = val/10000;
          monnum = (val%10000)/100-1; /* month is 0 - 11 */
          mdaynum = val%100;
        }

        if(!found && (dignext == DATE_MDAY) && (mdaynum == -1)) {
          if((val > 0) && (val<32)) {
            mdaynum = val;
            found = TRUE;
          }
          dignext = DATE_YEAR;
        }

        if(!found && (dignext == DATE_YEAR) && (yearnum == -1)) {
          yearnum = val;
          found = TRUE;
          if(yearnum < 100) {
            if(yearnum > 70)
              yearnum += 1900;
            else
              yearnum += 2000;
          }
          if(mdaynum == -1)
            dignext = DATE_MDAY;
        }

        if(!found)
          return PARSEDATE_FAIL;

        date = end;
      }
    }

    part++;
  }

  if(-1 == secnum)
    secnum = minnum = hournum = 0; /* no time, make it zero */

  if((-1 == mdaynum) ||
     (-1 == monnum) ||
     (-1 == yearnum))
    /* lacks vital info, fail */
    return PARSEDATE_FAIL;

#ifdef HAVE_TIME_T_UNSIGNED
  if(yearnum < 1970) {
    /* only positive numbers cannot return earlier */
    *output = TIME_T_MIN;
    return PARSEDATE_SOONER;
  }
#endif

#if (SIZEOF_TIME_T < 5)

#ifdef HAVE_TIME_T_UNSIGNED
  /* an unsigned 32 bit time_t can only hold dates to 2106 */
  if(yearnum > 2105) {
    *output = TIME_T_MAX;
    return PARSEDATE_LATER;
  }
#else
  /* a signed 32 bit time_t can only hold dates to the beginning of 2038 */
  if(yearnum > 2037) {
    *output = TIME_T_MAX;
    return PARSEDATE_LATER;
  }
  if(yearnum < 1903) {
    *output = TIME_T_MIN;
    return PARSEDATE_SOONER;
  }
#endif

#else
  /* The Gregorian calendar was introduced 1582 */
  if(yearnum < 1583)
    return PARSEDATE_FAIL;
#endif

  if((mdaynum > 31) || (monnum > 11) ||
     (hournum > 23) || (minnum > 59) || (secnum > 60))
    return PARSEDATE_FAIL; /* clearly an illegal date */

  tm.tm_sec = secnum;
  tm.tm_min = minnum;
  tm.tm_hour = hournum;
  tm.tm_mday = mdaynum;
  tm.tm_mon = monnum;
  tm.tm_year = yearnum;

  /* my_timegm() returns a time_t. time_t is often 32 bits, sometimes even on
     architectures that feature 64 bit 'long' but ultimately time_t is the
     correct data type to use.
  */
  my_timegm(&tm, &t);

  /* Add the time zone diff between local time zone and GMT. */
  if(tzoff == -1)
    tzoff = 0;

  if((tzoff > 0) && (t > TIME_T_MAX - tzoff)) {
    *output = TIME_T_MAX;
    return PARSEDATE_LATER; /* time_t overflow */
  }

  t += tzoff;

  *output = t;

  return PARSEDATE_OK;
}
Exemple #8
0
/* Function that checks for an ending smtp status code at the start of the
   given string, but also detects the supported authentication mechanisms
   from  the EHLO AUTH response. */
static int smtp_endofresp(struct pingpong *pp, int *resp)
{
  char *line = pp->linestart_resp;
  size_t len = pp->nread_resp;
  struct connectdata *conn = pp->conn;
  struct smtp_conn *smtpc = &conn->proto.smtpc;
  int result;
  size_t wordlen;

  if(len < 4 || !ISDIGIT(line[0]) || !ISDIGIT(line[1]) || !ISDIGIT(line[2]))
    return FALSE;       /* Nothing for us */

  /* Extract the response code if necessary */
  if((result = (line[3] == ' ')) != 0)
    *resp = curlx_sltosi(strtol(line, NULL, 10));

  line += 4;
  len -= 4;

  /* Do we have a SIZE capability? */
  if(smtpc->state == SMTP_EHLO && len >= 4 && !memcmp(line, "SIZE", 4)) {
    DEBUGF(infof(conn->data, "Server supports SIZE extension.\n"));
    smtpc->size_supported = true;
  }

  /* Do we have an AUTH capability? */
  if(smtpc->state == SMTP_EHLO && len >= 5 && !memcmp(line, "AUTH ", 5)) {
    line += 5;
    len -= 5;

    for(;;) {
      while(len &&
            (*line == ' ' || *line == '\t' ||
             *line == '\r' || *line == '\n')) {
        line++;
        len--;
      }

      if(!len)
        break;

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

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

      line += wordlen;
      len -= wordlen;
    }
  }

  return result;
}