diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/setopt.c | 6 | ||||
| -rw-r--r-- | lib/smtp.c | 50 | ||||
| -rw-r--r-- | lib/smtp.h | 5 | ||||
| -rw-r--r-- | lib/urldata.h | 2 | 
4 files changed, 53 insertions, 10 deletions
diff --git a/lib/setopt.c b/lib/setopt.c index 5f88ad3af..5a8ccac28 100644 --- a/lib/setopt.c +++ b/lib/setopt.c @@ -5,7 +5,7 @@   *                            | (__| |_| |  _ <| |___   *                             \___|\___/|_| \_\_____|   * - * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.   *   * This software is licensed as described in the file COPYING, which   * you should have received as part of this distribution. The terms @@ -2391,6 +2391,10 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)      /* Set the list of mail recipients */      data->set.mail_rcpt = va_arg(param, struct curl_slist *);      break; +  case CURLOPT_MAIL_RCPT_ALLLOWFAILS: +    /* allow RCPT TO command to fail for some recipients */ +    data->set.mail_rcpt_allowfails = (0 != va_arg(param, long)) ? TRUE : FALSE; +    break;  #endif    case CURLOPT_SASL_AUTHZID: diff --git a/lib/smtp.c b/lib/smtp.c index 65220b0f6..764a1b75e 100644 --- a/lib/smtp.c +++ b/lib/smtp.c @@ -5,7 +5,7 @@   *                            | (__| |_| |  _ <| |___   *                             \___|\___/|_| \_\_____|   * - * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.   *   * This software is licensed as described in the file COPYING, which   * you should have received as part of this distribution. The terms @@ -915,25 +915,53 @@ static CURLcode smtp_state_rcpt_resp(struct connectdata *conn, int smtpcode,    CURLcode result = CURLE_OK;    struct Curl_easy *data = conn->data;    struct SMTP *smtp = data->req.protop; +  bool is_smtp_err = FALSE; +  bool is_smtp_blocking_err = FALSE;    (void)instate; /* no use for this yet */ -  if(smtpcode/100 != 2) { -    failf(data, "RCPT failed: %d", smtpcode); -    result = CURLE_SEND_ERROR; +  is_smtp_err = (smtpcode/100 != 2) ? TRUE : FALSE; + +  /* If there's multiple RCPT TO to be issued, it's possible to ignore errors +     and proceed with only the valid addresses. */ +  is_smtp_blocking_err = +    (is_smtp_err && !data->set.mail_rcpt_allowfails) ? TRUE : FALSE; + +  if(is_smtp_err) { +    /* Remembering the last failure which we can report if all "RCPT TO" have +       failed and we cannot proceed. */ +    smtp->rcpt_last_error = smtpcode; + +    if(is_smtp_blocking_err) { +      failf(data, "RCPT failed: %d", smtpcode); +      result = CURLE_SEND_ERROR; +    }    }    else { +    /* Some RCPT TO commands have succeeded. */ +    smtp->rcpt_had_ok = TRUE; +  } + +  if(!is_smtp_blocking_err) {      smtp->rcpt = smtp->rcpt->next;      if(smtp->rcpt)        /* Send the next RCPT TO command */        result = smtp_perform_rcpt_to(conn);      else { -      /* Send the DATA command */ -      result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", "DATA"); +      /* We weren't able to issue a successful RCPT TO command while going +         over recipients (potentially multiple). Sending back last error. */ +      if(!smtp->rcpt_had_ok) { +        failf(data, "RCPT failed: %d (last error)", smtp->rcpt_last_error); +        result = CURLE_SEND_ERROR; +      } +      else { +        /* Send the DATA command */ +        result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", "DATA"); -      if(!result) -        state(conn, SMTP_DATA); +        if(!result) +          state(conn, SMTP_DATA); +      }      }    } @@ -1287,6 +1315,12 @@ static CURLcode smtp_perform(struct connectdata *conn, bool *connected,    /* Store the first recipient (or NULL if not specified) */    smtp->rcpt = data->set.mail_rcpt; +  /* Track of whether we've successfully sent at least one RCPT TO command */ +  smtp->rcpt_had_ok = FALSE; + +  /* Track of the last error we've received by sending RCPT TO command */ +  smtp->rcpt_last_error = 0; +    /* Initial data character is the first character in line: it is implicitly       preceded by a virtual CRLF. */    smtp->trailing_crlf = TRUE; diff --git a/lib/smtp.h b/lib/smtp.h index 20fc08119..0865d91e7 100644 --- a/lib/smtp.h +++ b/lib/smtp.h @@ -7,7 +7,7 @@   *                            | (__| |_| |  _ <| |___   *                             \___|\___/|_| \_\_____|   * - * Copyright (C) 2009 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2009 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.   *   * This software is licensed as described in the file COPYING, which   * you should have received as part of this distribution. The terms @@ -55,6 +55,9 @@ struct SMTP {    curl_pp_transfer transfer;    char *custom;            /* Custom Request */    struct curl_slist *rcpt; /* Recipient list */ +  bool rcpt_had_ok;        /* Whether any of RCPT TO commands (depends on +                              total number of recipients) succeeded so far */ +  int rcpt_last_error;     /* The last error received for RCPT TO command */    size_t eob;              /* Number of bytes of the EOB (End Of Body) that                                have been received so far */    bool trailing_crlf;      /* Specifies if the tailing CRLF is present */ diff --git a/lib/urldata.h b/lib/urldata.h index 6aaadca6f..6882e0a65 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -1791,6 +1791,8 @@ struct UserDefined {    BIT(doh); /* DNS-over-HTTPS enabled */    BIT(doh_get); /* use GET for DoH requests, instead of POST */    BIT(http09_allowed); /* allow HTTP/0.9 responses */ +  BIT(mail_rcpt_allowfails); /* allow RCPT TO command to fail for some +                                recipients */  };  struct Names {  | 
