]> granicus.if.org Git - curl/commitdiff
smtp: Added support for NOOP and RSET commands
authorSteve Holme <steve_holme@hotmail.com>
Fri, 15 Nov 2013 16:10:05 +0000 (16:10 +0000)
committerSteve Holme <steve_holme@hotmail.com>
Fri, 15 Nov 2013 16:14:01 +0000 (16:14 +0000)
lib/smtp.c
lib/smtp.h

index e18947ec1d4329ea02e0d4cf62561444b435c799..82ef3f2ede1a80df32233ee12613959191f2fbcc 100644 (file)
@@ -104,6 +104,7 @@ static CURLcode smtp_doing(struct connectdata *conn, bool *dophase_done);
 static CURLcode smtp_setup_connection(struct connectdata *conn);
 static CURLcode smtp_parse_url_options(struct connectdata *conn);
 static CURLcode smtp_parse_url_path(struct connectdata *conn);
+static CURLcode smtp_parse_custom_request(struct connectdata *conn);
 
 /*
  * SMTP protocol handler.
@@ -314,6 +315,7 @@ static void state(struct connectdata *conn, smtpstate newstate)
     "AUTH_XOAUTH2",
     "AUTH_CANCEL",
     "AUTH_FINAL",
+    "COMMAND",
     "MAIL",
     "RCPT",
     "DATA",
@@ -548,6 +550,28 @@ static CURLcode smtp_perform_authenticate(struct connectdata *conn)
   return result;
 }
 
+/***********************************************************************
+ *
+ * smtp_perform_command()
+ *
+ * Sends a SMTP based command.
+ */
+static CURLcode smtp_perform_command(struct connectdata *conn)
+{
+  CURLcode result = CURLE_OK;
+  struct SessionHandle *data = conn->data;
+  struct SMTP *smtp = data->req.protop;
+
+  /* Send the command */
+  result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s",
+                         smtp->custom && smtp->custom[0] != '\0' ?
+                         smtp->custom : "NOOP");
+  if(!result)
+    state(conn, SMTP_COMMAND);
+
+  return result;
+}
+
 /***********************************************************************
  *
  * smtp_perform_mail()
@@ -1231,6 +1255,29 @@ static CURLcode smtp_state_auth_final_resp(struct connectdata *conn,
   return result;
 }
 
+/* For command responses */
+static CURLcode smtp_state_command_resp(struct connectdata *conn, int smtpcode,
+                                        smtpstate instate)
+{
+  CURLcode result = CURLE_OK;
+  struct SessionHandle *data = conn->data;
+  struct SMTP *smtp = data->req.protop;
+
+  (void)instate; /* no use for this yet */
+
+  if(smtpcode/100 != 2) {
+    failf(data, "%s failed: %d",
+          smtp->custom && smtp->custom[0] != '\0' ? smtp->custom : "NOOP",
+          smtpcode);
+    result = CURLE_RECV_ERROR;
+  }
+
+  /* End of DO phase */
+  state(conn, SMTP_STOP);
+
+  return result;
+}
+
 /* For MAIL responses */
 static CURLcode smtp_state_mail_resp(struct connectdata *conn, int smtpcode,
                                      smtpstate instate)
@@ -1433,6 +1480,10 @@ static CURLcode smtp_statemach_act(struct connectdata *conn)
       result = smtp_state_auth_final_resp(conn, smtpcode, smtpc->state);
       break;
 
+    case SMTP_COMMAND:
+      result = smtp_state_command_resp(conn, smtpcode, smtpc->state);
+      break;
+
     case SMTP_MAIL:
       result = smtp_state_mail_resp(conn, smtpcode, smtpc->state);
       break;
@@ -1596,7 +1647,7 @@ static CURLcode smtp_done(struct connectdata *conn, CURLcode status,
     conn->bits.close = TRUE; /* marked for closure */
     result = status;         /* use the already set error code */
   }
-  else if(!data->set.connect_only) {
+  else if(!data->set.connect_only && data->set.upload && data->set.mail_rcpt) {
     /* Calculate the EOB taking into account any terminating CRLF from the
        previous line of the email or the CRLF of the DATA command when there
        is "no mail data". RFC-5321, sect. 4.1.1.4. */
@@ -1645,31 +1696,38 @@ static CURLcode smtp_done(struct connectdata *conn, CURLcode status,
  *
  * smtp_perform()
  *
- * This is the actual DO function for SMTP. Send a mail according to the
- * options previously setup.
+ * This is the actual DO function for SMTP. Transfer a mail or send a command
+ *  according to the options previously setup.
  */
 static CURLcode smtp_perform(struct connectdata *conn, bool *connected,
                              bool *dophase_done)
 {
   /* This is SMTP and no proxy */
   CURLcode result = CURLE_OK;
+  struct SessionHandle *data = conn->data;
 
   DEBUGF(infof(conn->data, "DO phase starts\n"));
 
-  if(conn->data->set.opt_no_body) {
+  if(data->set.opt_no_body) {
     /* Requested no body means no transfer */
-    struct SMTP *smtp = conn->data->req.protop;
+    struct SMTP *smtp = data->req.protop;
     smtp->transfer = FTPTRANSFER_INFO;
   }
 
   *dophase_done = FALSE; /* not done yet */
 
   /* Start the first command in the DO phase */
-  result = smtp_perform_mail(conn);
+  if(data->set.upload && data->set.mail_rcpt)
+    /* MAIL transfer */
+    result = smtp_perform_mail(conn);
+  else
+    /* SMTP based command (NOOP or RSET) */
+    result = smtp_perform_command(conn);
+
   if(result)
     return result;
 
-  /* run the state-machine */
+  /* Run the state-machine */
   result = smtp_multi_statemach(conn, dophase_done);
 
   *connected = conn->bits.tcpconnect[FIRSTSOCKET];
@@ -1695,6 +1753,11 @@ static CURLcode smtp_do(struct connectdata *conn, bool *done)
 
   *done = FALSE; /* default to false */
 
+  /* Parse the custom request */
+  result = smtp_parse_custom_request(conn);
+  if(result)
+    return result;
+
   result = smtp_regular_transfer(conn, done);
 
   return result;
@@ -1910,6 +1973,26 @@ static CURLcode smtp_parse_url_path(struct connectdata *conn)
   return Curl_urldecode(conn->data, path, 0, &smtpc->domain, NULL, TRUE);
 }
 
+/***********************************************************************
+ *
+ * smtp_parse_custom_request()
+ *
+ * Parse the custom request.
+ */
+static CURLcode smtp_parse_custom_request(struct connectdata *conn)
+{
+  CURLcode result = CURLE_OK;
+  struct SessionHandle *data = conn->data;
+  struct SMTP *smtp = data->req.protop;
+  const char *custom = data->set.str[STRING_CUSTOMREQUEST];
+
+  /* URL decode the custom request */
+  if(custom)
+    result = Curl_urldecode(data, custom, 0, &smtp->custom, NULL, TRUE);
+
+  return result;
+}
+
 CURLcode Curl_smtp_escape_eob(struct connectdata *conn, ssize_t nread)
 {
   /* When sending a SMTP payload we must detect CRLF. sequences making sure
index 7d91657a4fdf8d651e9eebe0c31a98121d7551e1..4100f6b6510f447c93fd11b7e99efcbc81390f2f 100644 (file)
@@ -47,6 +47,7 @@ typedef enum {
   SMTP_AUTH_XOAUTH2,
   SMTP_AUTH_CANCEL,
   SMTP_AUTH_FINAL,
+  SMTP_COMMAND,     /* NOOP and RSET */
   SMTP_MAIL,        /* MAIL FROM */
   SMTP_RCPT,        /* RCPT TO */
   SMTP_DATA,
@@ -61,6 +62,7 @@ typedef enum {
    used. */
 struct SMTP {
   curl_pp_transfer transfer;
+  char *custom;            /* Custom Request */
   struct curl_slist *rcpt; /* Recipient list */
   size_t eob;              /* Number of bytes of the EOB (End Of Body) that
                               have been received so far */