You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by so...@apache.org on 2006/01/27 23:27:53 UTC

svn commit: r373009 - in /httpd/mod_smtpd/trunk/src: mod_smtpd.h smtp_core.c smtp_protocol.c

Author: soc-rian
Date: Fri Jan 27 14:27:04 2006
New Revision: 373009

URL: http://svn.apache.org/viewcvs?rev=373009&view=rev
Log:
Major code refactoring!! Changes consist of:

1. shortening functions in smtp_protocol.c making code easier to read
2. changes to the hook api, now provides a pool for hooks to allocate from
   that's cleared after every command, also return data (currently only
   reply messages) is now required to be allocated by the hooks which use it.


Modified:
    httpd/mod_smtpd/trunk/src/mod_smtpd.h
    httpd/mod_smtpd/trunk/src/smtp_core.c
    httpd/mod_smtpd/trunk/src/smtp_protocol.c

Modified: httpd/mod_smtpd/trunk/src/mod_smtpd.h
URL: http://svn.apache.org/viewcvs/httpd/mod_smtpd/trunk/src/mod_smtpd.h?rev=373009&r1=373008&r2=373009&view=diff
==============================================================================
--- httpd/mod_smtpd/trunk/src/mod_smtpd.h (original)
+++ httpd/mod_smtpd/trunk/src/mod_smtpd.h Fri Jan 27 14:27:04 2006
@@ -73,7 +73,6 @@
 } smtpd_protocol_type;
 
 typedef struct smtpd_return_data {
-    apr_pool_t *p;
     /* list of messages */
     apr_array_header_t *msgs;
 } smtpd_return_data;
@@ -162,35 +161,42 @@
 
 APR_DECLARE_EXTERNAL_HOOK(smtpd, SMTPD, smtpd_retcode,
                           unrecognized_command,
-                          (smtpd_session_rec *scr, smtpd_return_data *in,
-                           char *command, char *data));
+                          (smtpd_session_rec *scr, apr_pool_t *p,
+                           char *command, char *data,
+                           smtpd_return_data **out_data));
 APR_DECLARE_EXTERNAL_HOOK(smtpd, SMTPD, smtpd_retcode, connect,
-                          (smtpd_session_rec *scr, smtpd_return_data *in));
+                          (smtpd_session_rec *scr, apr_pool_t *p,
+                           smtpd_return_data **out_data));
 APR_DECLARE_EXTERNAL_HOOK(smtpd, SMTPD, smtpd_retcode, reset_envelope,
                           (smtpd_session_rec *scr));
 APR_DECLARE_EXTERNAL_HOOK(smtpd, SMTPD, smtpd_retcode, helo,
-                          (smtpd_session_rec *scr, smtpd_return_data *in,
-                           char *str));
+                          (smtpd_session_rec *scr, apr_pool_t *p,
+                           char *str, smtpd_return_data **out_data));
 APR_DECLARE_EXTERNAL_HOOK(smtpd, SMTPD, smtpd_retcode, ehlo,
-                          (smtpd_session_rec *scr, smtpd_return_data *in,
-                           char *str));
+                          (smtpd_session_rec *scr, apr_pool_t *p,
+                           char *str, smtpd_return_data **out_data));
 APR_DECLARE_EXTERNAL_HOOK(smtpd, SMTPD, smtpd_retcode, mail,
-                          (smtpd_session_rec *scr, smtpd_return_data *in,
-                           char *str, apr_table_t *mail_parameters));
+                          (smtpd_session_rec *scr, apr_pool_t *p,
+                           char *str, apr_table_t *mail_parameters,
+                           smtpd_return_data **out_data));
 APR_DECLARE_EXTERNAL_HOOK(smtpd, SMTPD, smtpd_retcode, rcpt,
-                          (smtpd_session_rec *scr, smtpd_return_data *in,
-                           char *str, apr_table_t *rcpt_parameters));
+                          (smtpd_session_rec *scr, apr_pool_t *p,
+                           char *str, apr_table_t *rcpt_parameters,
+                           smtpd_return_data **out_data));
 APR_DECLARE_EXTERNAL_HOOK(smtpd, SMTPD, smtpd_retcode, vrfy,
-                          (smtpd_session_rec *scr, smtpd_return_data *in,
-                           char *str));
+                          (smtpd_session_rec *scr, apr_pool_t *p,
+                           char *str, smtpd_return_data **out_data));
 APR_DECLARE_EXTERNAL_HOOK(smtpd, SMTPD, smtpd_retcode, quit,
-                          (smtpd_session_rec *scr, smtpd_return_data *in));
+                          (smtpd_session_rec *scr, apr_pool_t *p));
 APR_DECLARE_EXTERNAL_HOOK(smtpd, SMTPD, smtpd_retcode, data,
-                          (smtpd_session_rec *scr, smtpd_return_data *in));
+                          (smtpd_session_rec *scr, apr_pool_t *p,
+                           smtpd_return_data **out_data));
 APR_DECLARE_EXTERNAL_HOOK(smtpd, SMTPD, smtpd_retcode, data_post,
-                          (smtpd_session_rec *scr, smtpd_return_data *in));
+                          (smtpd_session_rec *scr, apr_pool_t *p,
+                           smtpd_return_data **out_data));
 APR_DECLARE_EXTERNAL_HOOK(smtpd, SMTPD, smtpd_retcode, queue,
-                          (smtpd_session_rec *scr, smtpd_return_data *in));
+                          (smtpd_session_rec *scr, apr_pool_t *p,
+                           smtpd_return_data **out_data));
 APR_DECLARE_EXTERNAL_HOOK(smtpd, SMTPD, smtpd_retcode, headers_parsed,
                           (smtpd_session_rec *scr));
 

Modified: httpd/mod_smtpd/trunk/src/smtp_core.c
URL: http://svn.apache.org/viewcvs/httpd/mod_smtpd/trunk/src/smtp_core.c?rev=373009&r1=373008&r2=373009&view=diff
==============================================================================
--- httpd/mod_smtpd/trunk/src/smtp_core.c (original)
+++ httpd/mod_smtpd/trunk/src/smtp_core.c Fri Jan 27 14:27:04 2006
@@ -294,18 +294,18 @@
 /* Implement 'smtpd_run_unrecognized_command'. */
 APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(smtpd, SMTPD, smtpd_retcode,
                                       unrecognized_command,
-                                      (smtpd_session_rec *scr,
-                                       smtpd_return_data *in,
-                                       char *command, char *data),
-                                      (scr, in, command, data),
+                                      (smtpd_session_rec *scr, apr_pool_t *p,
+                                       char *command, char *data,
+                                       smtpd_return_data **out_data),
+                                      (scr, p, command, data, out_data),
                                       SMTPD_DECLINED);
 /* Implement 'smtpd_run_connect'. */
 /* it is an all hook because multiple plugins
    should be ale to perform actions on connect */
 APR_IMPLEMENT_EXTERNAL_HOOK_RUN_ALL(smtpd, SMTPD, smtpd_retcode, connect,
-                                    (smtpd_session_rec *scr,
-                                     smtpd_return_data *in),
-                                    (scr, in),
+                                    (smtpd_session_rec *scr, apr_pool_t *p,
+                                     smtpd_return_data **out_data),
+                                    (scr, p, out_data),
                                     SMTPD_OK, SMTPD_DECLINED);
 /* Implement 'smtpd_run_reset_envelope'. */
 /* it is an all hook because multiple plugins
@@ -317,64 +317,66 @@
                                     SMTPD_OK, SMTPD_DECLINED);
 /* Implement 'smtpd_run_helo'. */
 APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(smtpd, SMTPD, smtpd_retcode, helo,
-                                      (smtpd_session_rec *scr,
-                                       smtpd_return_data *in, char *str),
-                                      (scr, in, str),
+                                      (smtpd_session_rec *scr, apr_pool_t *p,
+                                       char *str, smtpd_return_data **out_data),
+                                      (scr, p, str, out_data),
                                       SMTPD_DECLINED);
 /* Implement 'smtpd_run_ehlo'. */
 APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(smtpd, SMTPD, smtpd_retcode, ehlo,
-                                      (smtpd_session_rec *scr,
-                                       smtpd_return_data *in, char *str),
-                                      (scr, in, str),
+                                      (smtpd_session_rec *scr, apr_pool_t *p,
+                                       char *str, smtpd_return_data **out_data),
+                                      (scr, p, str, out_data),
                                       SMTPD_DECLINED);
 /* Implement 'smtpd_run_mail'. */
 APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(smtpd, SMTPD, smtpd_retcode, mail,
-                                      (smtpd_session_rec *scr,
-                                       smtpd_return_data *in, char *str,
-                                       apr_table_t *mail_parameters),
-                                      (scr, in, str, mail_parameters),
+                                      (smtpd_session_rec *scr, apr_pool_t *p,
+                                       char *str, apr_table_t *mail_parameters,
+                                       smtpd_return_data **out_data),
+                                      (scr, p, str, mail_parameters,
+                                       out_data),
                                       SMTPD_DECLINED);
 /* Implement 'smtpd_run_rcpt'. */
 APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(smtpd, SMTPD, smtpd_retcode, rcpt,
-                                      (smtpd_session_rec *scr,
-                                       smtpd_return_data *in, char *str,
-                                       apr_table_t *rcpt_parameters),
-                                      (scr, in, str, rcpt_parameters),
+                                      (smtpd_session_rec *scr, apr_pool_t *p,
+                                       char *str, apr_table_t *rcpt_parameters,
+                                       smtpd_return_data **out_data),
+                                      (scr, p, str, rcpt_parameters,
+                                       out_data),
                                       SMTPD_DECLINED);
 /* Implement 'smtpd_run_vrfy'. */
 APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(smtpd, SMTPD, smtpd_retcode, vrfy,
-                                      (smtpd_session_rec *scr,
-                                       smtpd_return_data *in, char *str),
-                                      (scr, in, str),
+                                      (smtpd_session_rec *scr, apr_pool_t *p,
+                                       char *str, smtpd_return_data **out_data),
+                                      (scr, p, str, out_data),
                                       SMTPD_DECLINED);
 /* Implement 'smtpd_run_quit'. */
 /* it is an all hook because multiple plugins
    should be able to perform actions on quit */
 APR_IMPLEMENT_EXTERNAL_HOOK_RUN_ALL(smtpd, SMTPD, smtpd_retcode, quit,
                                     (smtpd_session_rec *scr,
-                                     smtpd_return_data *in),
-                                    (scr, in),
+                                     apr_pool_t *p),
+                                    (scr, p),
                                     SMTPD_OK, SMTPD_DECLINED);
 /* Implement 'smtpd_run_data'. */
 APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(smtpd, SMTPD, smtpd_retcode, data,
-                                      (smtpd_session_rec *scr,
-                                       smtpd_return_data *in),
-                                      (scr, in),
+                                      (smtpd_session_rec *scr, apr_pool_t *p,
+                                       smtpd_return_data **out_data),
+                                      (scr, p, out_data),
                                       SMTPD_DECLINED);
 /* Implement 'smtpd_run_data_post'. */
 APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(smtpd, SMTPD, smtpd_retcode,
                                       data_post,
-                                      (smtpd_session_rec *scr,
-                                       smtpd_return_data *in),
-                                      (scr, in),
+                                      (smtpd_session_rec *scr, apr_pool_t *p,
+                                       smtpd_return_data **out_data),
+                                      (scr, p, out_data),
                                       SMTPD_DECLINED);
 /* Implement 'smtpd_run_queue'. */
 /* it is an all hook because multiple plugins
    should be able to queue */
 APR_IMPLEMENT_EXTERNAL_HOOK_RUN_ALL(smtpd, SMTPD, smtpd_retcode, queue,
-                                    (smtpd_session_rec *scr,
-                                     smtpd_return_data *in),
-                                    (scr, in),
+                                    (smtpd_session_rec *scr, apr_pool_t *p,
+                                     smtpd_return_data **out_data),
+                                    (scr, p, out_data),
                                     SMTPD_OK, SMTPD_DECLINED);
 /* Implement 'smtpd_run_headers_parsed'. */
 /* it is an all hook because multiple plugins

Modified: httpd/mod_smtpd/trunk/src/smtp_protocol.c
URL: http://svn.apache.org/viewcvs/httpd/mod_smtpd/trunk/src/smtp_protocol.c?rev=373009&r1=373008&r2=373009&view=diff
==============================================================================
--- httpd/mod_smtpd/trunk/src/smtp_protocol.c (original)
+++ httpd/mod_smtpd/trunk/src/smtp_protocol.c Fri Jan 27 14:27:04 2006
@@ -46,78 +46,76 @@
 extern ap_regex_t *rcpt_compiled_regex;
 extern ap_regex_t *vrfy_compiled_regex;
 
-static int smtpd_handle_unrecognized_command(smtpd_session_rec *scr,
-                                             smtpd_return_data *in_data,
-                                             char *command, char *data);
-static int smtpd_handler_ehlo(smtpd_session_rec *scr, char *buffer,
-                              smtpd_return_data *out_data);
-static int smtpd_handler_helo(smtpd_session_rec *scr, char *buffer,
-                              smtpd_return_data *out_data);
-static int smtpd_handler_mail(smtpd_session_rec *scr, char *buffer,
-                              smtpd_return_data *out_data);
-static int smtpd_handler_rcpt(smtpd_session_rec *scr, char *buffer,
-                              smtpd_return_data *out_data);
-static int smtpd_handler_data(smtpd_session_rec *scr, char *buffer,
-                              smtpd_return_data *out_data);
-static int smtpd_handler_rset(smtpd_session_rec *scr, char *buffer,
-                              smtpd_return_data *out_data);
-static int smtpd_handler_quit(smtpd_session_rec *scr, char *buffer,
-                              smtpd_return_data *out_data);
-static int smtpd_handler_vrfy(smtpd_session_rec *scr, char *buffer,
-                              smtpd_return_data *out_data);
+static int smtpd_handler_helo(smtpd_session_rec *, apr_pool_t *, char *, int);
+static int smtpd_handler_mail(smtpd_session_rec *, apr_pool_t *, char *);
+static int smtpd_handler_rcpt(smtpd_session_rec *, apr_pool_t *, char *);
+static int smtpd_handler_data(smtpd_session_rec *, apr_pool_t *, char *);
+static int smtpd_handler_rset(smtpd_session_rec *, char *);
+static int smtpd_handler_quit(smtpd_session_rec *, apr_pool_t *, char *);
+static int smtpd_handler_vrfy(smtpd_session_rec *, apr_pool_t *, char *);
+static void smtpd_connection_run(smtpd_session_rec *, apr_pool_t *);
+static int smtpd_handle_unrecognized_command(smtpd_session_rec *, apr_pool_t *,
+                                             char *, char *);
+
+static void smtpd_respond(smtpd_session_rec *scr, int status,
+                          char *default_string, smtpd_return_data *hook_data)
+{
+    if (hook_data != NULL && hook_data->msgs != NULL) {
+        smtpd_respond_multiline(scr, status, hook_data->msgs);
+    }
+    else {
+        smtpd_respond_oneline(scr, status, default_string);
+    }
+}
 
-#define BUFFER_STR_LEN 1024
 void smtpd_process_connection_internal(smtpd_session_rec *scr)
 {
+    char buffer[255];
     apr_pool_t *per_command_pool;
-    char cmdbuff[BUFFER_STR_LEN];
-    char *buffer = cmdbuff;
-    char *command;
-    smtpd_return_data out_data;
     smtpd_svr_config_rec *pConfig =
       ap_get_module_config(scr->s->module_config,
                            &smtpd_module);
-    
+    smtpd_return_data *out_data;
+
     apr_pool_create(&per_command_pool, scr->p);
-    out_data.p = per_command_pool;
     
-    out_data.msgs = NULL;
-    switch(smtpd_run_connect(scr, &out_data)) {
+    switch(smtpd_run_connect(scr, per_command_pool, &out_data)) {
     case SMTPD_DENY:
         ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, scr->s,
                      "Connection Denied");
-        if (out_data.msgs) {
-            smtpd_respond_multiline(scr, 550, out_data.msgs);
-        }
-        else {
-            smtpd_respond_oneline(scr, 550,
-                                  "Connection from you denied, bye bye.");
-        }
-        goto end;
+        smtpd_respond(scr, 550, "Connection from you denied, bye bye.",
+                      out_data);
+        break;
     case SMTPD_DENYSOFT:
         ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, scr->s,
                      "Connection Denied");
-        if (out_data.msgs) {
-            smtpd_respond_multiline(scr, 450, out_data.msgs);
-        }
-        else {
-            smtpd_respond_oneline(scr, 450, "Connection from you temporarily "
-                                  "denied, bye bye.");
-        }
-        goto end;
-    case SMTPD_DONE:
+        smtpd_respond(scr, 450, "Connection from you temporarily denied, bye bye.",
+                      out_data);
         break;
     case SMTPD_DONE_DISCONNECT:
-        goto end;
+        break;
     default:
-        snprintf(buffer, BUFFER_STR_LEN, "%s %s", scr->s->server_hostname,
+        snprintf(buffer, 255, "%s %s", scr->s->server_hostname,
                  pConfig->sId);
         smtpd_respond_oneline(scr, 220, buffer);
+    case SMTPD_DONE:
+        smtpd_connection_run(scr, per_command_pool);
         break;
     }
-    
+
+    return;
+}
+
+#define BUFFER_STR_LEN 1024
+static void smtpd_connection_run(smtpd_session_rec *scr,
+                                 apr_pool_t *per_command_pool)
+{
+    char cmdbuff[BUFFER_STR_LEN];
+    char *buffer = cmdbuff;
+    char *command;
+    int disconnect;
+
     while (smtpd_getline(scr, buffer, BUFFER_STR_LEN, NULL) == APR_SUCCESS) {
-        int return_code;
         apr_pool_clear(per_command_pool);
         command = buffer;
         
@@ -129,121 +127,76 @@
 
         ap_str_tolower(command);
 
-        out_data.msgs = NULL;
-
         if (ap_strcmp_match("ehlo", command) == 0) {
-            return_code = smtpd_handler_ehlo(scr, buffer, &out_data);
+            disconnect = smtpd_handler_helo(scr, per_command_pool, buffer, 1);
         }
         else if (ap_strcmp_match("helo", command) == 0) {
-            return_code = smtpd_handler_helo(scr, buffer, &out_data);
+            disconnect = smtpd_handler_helo(scr, per_command_pool, buffer, 0);
         }
         else if (ap_strcmp_match("mail", command) == 0) {
-            return_code = smtpd_handler_mail(scr, buffer, &out_data);
+            disconnect = smtpd_handler_mail(scr, per_command_pool, buffer);
         }
         else if (ap_strcmp_match("rcpt", command) == 0) {
-            return_code = smtpd_handler_rcpt(scr, buffer, &out_data);
+            disconnect = smtpd_handler_rcpt(scr, per_command_pool, buffer);
         }
         else if (ap_strcmp_match("data", command) == 0) {
-            return_code = smtpd_handler_data(scr, buffer, &out_data);
+            disconnect = smtpd_handler_data(scr, per_command_pool, buffer);
         }
         else if (ap_strcmp_match("rset", command) == 0) {
-            return_code = smtpd_handler_rset(scr, buffer, &out_data);
+            disconnect = smtpd_handler_rset(scr, buffer);
         }
         else if (ap_strcmp_match("noop", command) == 0) {
             smtpd_respond_oneline(scr, 250, "Ok");
-            return_code = 250;
+            disconnect = 0;
         }
         else if (ap_strcmp_match("vrfy", command) == 0) {
-            return_code = smtpd_handler_vrfy(scr, buffer, &out_data);
+            disconnect = smtpd_handler_vrfy(scr, per_command_pool, buffer);
         }
         else if (ap_strcmp_match("quit", command) == 0) {
-            return_code = smtpd_handler_quit(scr, buffer, &out_data);
+            disconnect = smtpd_handler_quit(scr, per_command_pool, buffer);
         }
         else {
-            return_code =
-              smtpd_handle_unrecognized_command(scr, &out_data, command,
+            disconnect =
+              smtpd_handle_unrecognized_command(scr, per_command_pool, command,
                                                 buffer);
         }
         
-        if (!return_code)
+        if (disconnect)
             break;
 
         buffer = cmdbuff;
     }
-    
- end:
+
     return;
 }
 
 static int smtpd_handle_unrecognized_command(smtpd_session_rec *scr,
-                                             smtpd_return_data
-                                             *out_data,
-                                             char *command, char *data)
+                                             apr_pool_t *p, char *command,
+                                             char *data)
 {
-    switch(smtpd_run_unrecognized_command(scr, out_data, command, data)) {
+    int disconnect = 0;
+    smtpd_return_data *out_data;
+    
+    switch(smtpd_run_unrecognized_command(scr, p, command, data, &out_data)) {
     case SMTPD_DENY:
-        if (out_data->msgs) {
-            smtpd_respond_multiline(scr, 521, out_data->msgs);
-        }
-        else {
-            smtpd_respond_oneline(scr, 521, "Command Denied");
-        }
-        return 521;
+        smtpd_respond(scr, 521, "Command Denied", out_data);
+        break;
     case SMTPD_DONE:
-        return 1;
+        break;
     case SMTPD_DONE_DISCONNECT:
-        return 0;
+        disconnect = 1;
+        break;
     default:
         smtpd_respond_oneline(scr, 500, "Syntax error, command unrecognized");
-        return 500;
+        break;
     }
 
+    return disconnect;
 }
 
-static int smtpd_handler_ehlo(smtpd_session_rec *scr, char *buffer,
-                              smtpd_return_data *out_data)
+static int smtpd_default_ehlo(smtpd_session_rec *scr, apr_pool_t *p,
+                              char *buffer)
 {
-    int error;
-
-    if (buffer == NULL) {
-        goto syntax_error;
-    }
-
-    error = ap_regexec(ehlo_compiled_regex, buffer, 0, NULL, 0);
-
-    if (error) {
-    syntax_error:
-        smtpd_respond_oneline(scr, 501, "Syntax: EHLO hostname");
-        return 501;
-    }
-    
-    switch(smtpd_run_ehlo(scr, out_data, buffer)) {
-    case SMTPD_DONE:
-        return 1;
-    case SMTPD_DONE_DISCONNECT:
-        return 0;
-    case SMTPD_DENY:
-        if (out_data->msgs) {
-            smtpd_respond_multiline(scr, 550, out_data->msgs);
-        }
-        else {
-            smtpd_respond_oneline(scr, 550, "");
-        }
-        return 550;
-    case SMTPD_DENYSOFT:
-        if (out_data->msgs) {
-            smtpd_respond_multiline(scr, 450, out_data->msgs);
-        }
-        else {
-            smtpd_respond_oneline(scr, 450, "");
-        }
-        return 450;
-    default:
-        break;
-    }
-    
-    /* default behavior: */
-    
     /* RFC 2821 states that when ehlo or helo is received, reset */
     /* state */
     smtpd_reset_envelope(scr);
@@ -253,28 +206,45 @@
     scr->protocol_type = SMTPD_PROTOCOL_ESMTP;
     
     if (scr->extensions->nelts) {
-        apr_pool_t *p;
         apr_array_header_t *first;
         
-        apr_pool_create(&p, scr->p);
         first = apr_array_make(p, 1, sizeof(char *));
         (*((char **)apr_array_push(first))) = scr->helo;
         apr_array_cat(first, scr->extensions);
         
         smtpd_respond_multiline(scr, 250, first);
-        apr_pool_destroy(p);
     }
     else {
         smtpd_respond_oneline(scr, 250, scr->helo);
     }
+
+    return 0;
+}
+
+static int smtpd_default_helo(smtpd_session_rec *scr, apr_pool_t *p,
+                              char *buffer)
+{
+    /* RFC 2821 states that when ehlo or helo is received, reset */
+    /* state */
+    smtpd_reset_envelope(scr);
     
-    return 250;
+    strncpy(scr->helo, buffer, 255);
+    scr->helo[255] = '\0';
+    scr->protocol_type = SMTPD_PROTOCOL_SMTP;
+
+    smtpd_respond_oneline(scr, 250, scr->helo);
+
+    return 0;
 }
 
-static int smtpd_handler_helo(smtpd_session_rec *scr, char *buffer,
-                              smtpd_return_data *out_data)
+
+static int smtpd_handler_helo(smtpd_session_rec *scr,
+                              apr_pool_t *per_command_pool, char *buffer,
+                              int esmtp)
 {
     int error;
+    int disconnect = 0;
+    smtpd_return_data *out_data = NULL;
 
     if (buffer == NULL) {
         goto syntax_error;
@@ -284,49 +254,38 @@
 
     if (error) {
     syntax_error:
-        smtpd_respond_oneline(scr, 501, "Syntax: HELO hostname");
-        return 501;
+        smtpd_respond_oneline(scr, 501, esmtp
+                              ? "Syntax: EHLO hostname"
+                              : "Syntax: HELO hostname");
+        return disconnect;
     }
     
-    switch(smtpd_run_helo(scr, out_data, buffer)) {
+    switch(esmtp
+           ? smtpd_run_ehlo(scr, per_command_pool, buffer, &out_data)
+           : smtpd_run_helo(scr, per_command_pool, buffer, &out_data)) {
     case SMTPD_DONE:
-        return 1;
+        break;
     case SMTPD_DONE_DISCONNECT:
-        return 0;
+        disconnect = 1;
+        break;
     case SMTPD_DENY:
-        if (out_data->msgs) {
-            smtpd_respond_multiline(scr, 550, out_data->msgs);
-        }
-        else {
-            smtpd_respond_oneline(scr, 550, "");
-        }
-        return 550;
+        smtpd_respond(scr, 550, "Denied", out_data);
+        break;
     case SMTPD_DENYSOFT:
-        if (out_data->msgs) {
-            smtpd_respond_multiline(scr, 450, out_data->msgs);
-        }
-        else {
-            smtpd_respond_oneline(scr, 450, "");
-        }
-        return 450;
+        smtpd_respond(scr, 450, "Temporarily Denied", out_data);
+        break;
     default:
+        disconnect = esmtp
+          ? smtpd_default_helo(scr, per_command_pool, buffer)
+          : smtpd_default_ehlo(scr, per_command_pool, buffer);
         break;
     }
-    
-    /* RFC 2821 states that when ehlo or helo is received, reset */
-    /* state */
-    smtpd_reset_envelope(scr);
-    
-    strncpy(scr->helo, buffer, 255);
-    scr->helo[255] = '\0';
-    scr->protocol_type = SMTPD_PROTOCOL_SMTP;
-
-    smtpd_respond_oneline(scr, 250, scr->helo);
-    return 250;
+    return disconnect;
 }
 
 static void parse_out_parameters(apr_table_t *mail_parameters,
-                                 char *start_parameters) {
+                                 char *start_parameters)
+{
     char *end_para, *end_key;
 
     while ((start_parameters != '\0')&&
@@ -350,19 +309,39 @@
     }
 }
 
-static int smtpd_handler_mail(smtpd_session_rec *scr, char *buffer,
-                              smtpd_return_data *out_data)
+static int smtpd_default_mail(smtpd_session_rec *scr, apr_pool_t *p,
+                              char *email_address, apr_table_t *mail_parameters)
 {
     smtpd_envelope_rec *str = scr->envelope;
+
+    str->mail_from = apr_pstrdup(str->p, email_address);
+    /* REVIEW: Should we not create the str->mail_parameters at reset time
+       and just create it now with:
+       str->mail_parameters = apr_table_copy(str->p, mail_parameters);
+       or keep how it's done below?
+    */
+    mail_parameters = apr_table_copy(str->p, mail_parameters);
+    apr_table_overlap(str->mail_parameters, mail_parameters,
+                      APR_OVERLAP_TABLES_SET);
+    str->trans_state = SMTPD_STATE_GOT_MAIL;
+    smtpd_respond_oneline(scr, 250, "Ok");
+
+    return 0;
+}   
+
+static int smtpd_handler_mail(smtpd_session_rec *scr,
+                              apr_pool_t *per_command_pool, char *buffer)
+{
     char *email_address;
-    char *start_parameters;
-    apr_table_t *mail_parameters;
     int error;
+    int disconnect = 0;
+    apr_table_t *mail_parameters;
+    smtpd_return_data *out_data = NULL;
 
     /* already got mail */
-    if (str->trans_state == SMTPD_STATE_GOT_MAIL) {
+    if (scr->envelope->trans_state == SMTPD_STATE_GOT_MAIL) {
         smtpd_respond_oneline(scr, 503, "Error: Nested MAIL command");
-        return 503;
+        return disconnect;
     }
 
     if (buffer == NULL) {
@@ -375,7 +354,7 @@
     syntax_error:
         smtpd_respond_oneline(scr, 501, "Syntax: MAIL FROM:<reverse-path> "
                               "mail-parameters");
-        return 501;
+        return disconnect;
     }
 
     /* logging will be robustified later 
@@ -383,103 +362,94 @@
        "full from_parameter: %s", loc);  
     */
 
-    mail_parameters = apr_table_make(out_data->p, 5);
+    mail_parameters = apr_table_make(per_command_pool, 5);
 
-    /* parse out reverse-path*/
-    email_address = buffer + sizeof("from:<") - 1;
-    start_parameters = ap_strchr(email_address, '>');
-    start_parameters[0] = '\0';
-
-    if (start_parameters[1] != '\0') {
-        parse_out_parameters(mail_parameters, start_parameters+2);
+    /* parse out reverse-path */
+    {
+        char *start_parameters;
+
+        email_address = buffer + sizeof("from:<") - 1;
+        start_parameters = ap_strchr(email_address, '>');
+        start_parameters[0] = '\0';
+        
+        if (start_parameters[1] != '\0') {
+            parse_out_parameters(mail_parameters, start_parameters+2);
+        }
     }
 
-    switch(smtpd_run_mail(scr, out_data, email_address, mail_parameters)) {
+    switch(smtpd_run_mail(scr, per_command_pool, email_address, mail_parameters,
+                          &out_data)) {
     case SMTPD_DONE:
-        return 1;
+        break;
     case SMTPD_DONE_DISCONNECT:
-        /* zero to disconnect */
-        return 0;
+        disconnect = 1;
+        break;
     case SMTPD_DENY:
         ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, scr->s,
                      "deny mail from %s (%s)", email_address,
-                     out_data->msgs ? ((char **)out_data->msgs->elts)[0] : "");  
-        if (out_data->msgs) {
-            smtpd_respond_multiline(scr, 550, out_data->msgs);
-        }
-        else {
-            smtpd_respond_oneline(scr, 550, "denied");
-        }
-        return 550;
+                     out_data->msgs ? ((char **)out_data->msgs->elts)[0] : "");
+        smtpd_respond(scr, 550, "Denied", out_data);
+        break;
     case SMTPD_DENYSOFT:
         ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, scr->s,
                      "denysoft mail from %s (%s)", email_address,
-                     out_data->msgs ? ((char **)out_data->msgs->elts)[0] : "");  
-        if (out_data->msgs) {
-            smtpd_respond_multiline(scr, 450, out_data->msgs);
-        }
-        else {
-            smtpd_respond_oneline(scr, 450, "temporarily denied");
-        }
-        return 450;
+                     out_data->msgs ? ((char **)out_data->msgs->elts)[0] : "");
+        smtpd_respond(scr, 450, "Temporarily denied", out_data);
+        break;
     case SMTPD_DENY_DISCONNECT:
         ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, scr->s,
                      "deny mail from %s (%s)", email_address,
-                     out_data->msgs ? ((char **)out_data->msgs->elts)[0] : "");  
-        if (out_data->msgs) {
-            smtpd_respond_multiline(scr, 550, out_data->msgs);
-        }
-        else {
-            smtpd_respond_oneline(scr, 550, "denied");
-        }
-        /* zero to disconnect */
-        return 0;
+                     out_data->msgs ? ((char **)out_data->msgs->elts)[0] : "");
+        smtpd_respond(scr, 550, "Denied", out_data);
+        disconnect = 1;
+        break;
     case SMTPD_DENYSOFT_DISCONNECT:
         ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, scr->s,
                      "denysoft mail from %s (%s)", email_address,
-                     out_data->msgs ? ((char **)out_data->msgs->elts)[0] : "");  
-        if (out_data->msgs) {
-            smtpd_respond_multiline(scr, 450, out_data->msgs);
-        }
-        else {
-            smtpd_respond_oneline(scr, 450, "temporarily denied");
-        }
-        /* zero to disconnect */
-        return 0;
+                     out_data->msgs ? ((char **)out_data->msgs->elts)[0] : "");
+        smtpd_respond(scr, 450, "Temporarily denied", out_data);
+        disconnect = 1;
+        break;
     default:
+        disconnect = smtpd_default_mail(scr, per_command_pool, email_address,
+                                        mail_parameters);
         break;
     }
     
-    /* default handling */
-    str->mail_from = apr_pstrdup(str->p, email_address);
-    /* REVIEW: Should we not create the str->mail_parameters at reset time
-       and just create it now with:
-       str->mail_parameters = apr_table_copy(str->p, mail_parameters);
-       or keep how it's done below?
-    */
-    mail_parameters = apr_table_copy(str->p, mail_parameters);
-    apr_table_overlap(str->mail_parameters, mail_parameters,
+    return disconnect;
+}
+
+static int smtpd_default_rcpt(smtpd_session_rec *scr, apr_pool_t *p,
+                              char *email_address, apr_table_t *rcpt_parameters)
+{
+    smtpd_envelope_rec *str = scr->envelope;
+
+    /* add a recipient */
+    rcpt_parameters = apr_table_copy(str->p, rcpt_parameters);
+    apr_table_overlap(str->rcpt_parameters, rcpt_parameters,
                       APR_OVERLAP_TABLES_SET);
-    str->trans_state = SMTPD_STATE_GOT_MAIL;
+    (*((char **)apr_array_push(str->rcpt_to))) =
+      apr_pstrdup(str->p, email_address);
+    str->trans_state = SMTPD_STATE_GOT_RCPT;
     smtpd_respond_oneline(scr, 250, "Ok");
-    
-    return 250;
+ 
+    return 0;
 }
 
-static int smtpd_handler_rcpt(smtpd_session_rec *scr, char *buffer,
-                              smtpd_return_data *out_data)
+static int smtpd_handler_rcpt(smtpd_session_rec *scr,
+                              apr_pool_t *per_command_pool, char *buffer)
 {
-    smtpd_envelope_rec *str = scr->envelope;
     char *email_address;
-    char *start_parameters;
-    apr_table_t *rcpt_parameters;
     int error;
+    int disconnect = 0;
+    apr_table_t *rcpt_parameters;
+    smtpd_return_data *out_data = NULL;
         
     /* need mail first */
-    if ((str->trans_state != SMTPD_STATE_GOT_MAIL) &&
-        (str->trans_state != SMTPD_STATE_GOT_RCPT)) {
+    if ((scr->envelope->trans_state != SMTPD_STATE_GOT_MAIL) &&
+        (scr->envelope->trans_state != SMTPD_STATE_GOT_RCPT)) {
         smtpd_respond_oneline(scr, 503, "Error: need MAIL command");
-        return 503;
+        return disconnect;
     }
 
     if (buffer == NULL) {
@@ -492,125 +462,92 @@
     syntax_error:
         smtpd_respond_oneline(scr, 501, "Syntax: RCPT TO:<forward-path> "
                               "rcpt-parameters");
-        return 501;
+        return disconnect;
     }
 
-    rcpt_parameters = apr_table_make(out_data->p, 5);
+    rcpt_parameters = apr_table_make(per_command_pool, 5);
 
     /* parse out reverse-path*/
-    email_address = buffer + sizeof("to:<") - 1;
-    start_parameters = ap_strchr(email_address, '>');
-    start_parameters[0] = '\0';
+    {
+        char *start_parameters;
+
+        email_address = buffer + sizeof("to:<") - 1;
+        start_parameters = ap_strchr(email_address, '>');
+        start_parameters[0] = '\0';
 
-    if (start_parameters[1] != '\0') {
-        parse_out_parameters(rcpt_parameters, start_parameters+2);
+        if (start_parameters[1] != '\0') {
+            parse_out_parameters(rcpt_parameters, start_parameters+2);
+        }
     }
 
-    switch(smtpd_run_rcpt(scr, out_data, email_address, rcpt_parameters)) {
+    switch(smtpd_run_rcpt(scr, per_command_pool, email_address, rcpt_parameters,
+                          &out_data)) {
     case SMTPD_DONE:
-        return 1;
+        break;
     case SMTPD_DONE_DISCONNECT:
-        return 0;
+        disconnect = 1;
+        break;
     case SMTPD_DENY:
-        if (out_data->msgs) {
-            smtpd_respond_multiline(scr, 550, out_data->msgs);
-        }
-        else {
-            smtpd_respond_oneline(scr, 550, "relaying denied");
-        }
-        return 550;
+        smtpd_respond(scr, 550, "Relaying denied", out_data);
+        break;
     case SMTPD_DENYSOFT:
-        if (out_data->msgs) {
-            smtpd_respond_multiline(scr, 450, out_data->msgs);
-        }
-        else {
-            smtpd_respond_oneline(scr, 450, "relaying temporarily denied");
-        }
-        return 450;
+        smtpd_respond(scr, 450, "Relaying temporarily denied", out_data);
+        break;
     case SMTPD_DENY_DISCONNECT:
         ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, scr->s,
                      "delivery denied (%s)",
                      out_data->msgs ? ((char **)out_data->msgs->elts)[0] : "");
-        if (out_data->msgs) {
-            smtpd_respond_multiline(scr, 550, out_data->msgs);
-        }
-        else {
-            smtpd_respond_oneline(scr, 550, "relaying denied");
-        }
-        return 0;
+        smtpd_respond(scr, 550, "Relaying denied", out_data);
+        disconnect = 1;
+        break;
     case SMTPD_DENYSOFT_DISCONNECT:
         ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, scr->s,
                      "delivery denied (%s)",
                      out_data->msgs ? ((char **)out_data->msgs->elts)[0] : "");
-        if (out_data->msgs) {
-            smtpd_respond_multiline(scr, 450, out_data->msgs);
-        }
-        else {
-            smtpd_respond_oneline(scr, 450, "relaying temporarily denied");
-        }
-        return 0;
+        smtpd_respond(scr, 450, "Relaying temporarily denied", out_data);
+        disconnect = 1;
+        break;
     case SMTPD_OK: /* recipient is okay */
+        disconnect = smtpd_default_rcpt(scr, per_command_pool, email_address,
+                                        rcpt_parameters);
         break;
     default:
         smtpd_respond_oneline(scr, 450,
                               "No plugin decided if relaying is allowed");
-        return 450;
+        break;
     }
     
-    /* add a recipient */
-    rcpt_parameters = apr_table_copy(str->p, rcpt_parameters);
-    apr_table_overlap(str->rcpt_parameters, rcpt_parameters,
-                      APR_OVERLAP_TABLES_SET);
-    (*((char **)apr_array_push(str->rcpt_to))) = apr_pstrdup(str->p, email_address);
-    str->trans_state = SMTPD_STATE_GOT_RCPT;
-    smtpd_respond_oneline(scr, 250, "Ok");
-    
-    return 250;
+    return disconnect;
 }
 
 
-inline static int smtpd_queue(smtpd_session_rec *scr, smtpd_return_data *out_data)
+static int smtpd_queue(smtpd_session_rec *scr, apr_pool_t *p)
 {
-    switch(smtpd_run_queue(scr, out_data)) {
+    int disconnect = 0;
+    smtpd_return_data *out_data = NULL;
+
+    switch(smtpd_run_queue(scr, p, &out_data)) {
     case SMTPD_DONE:
-        return 1;
+        break;
     case SMTPD_DONE_DISCONNECT:
-        return 0;
+        disconnect = 1;
+        break;
     case SMTPD_OK:
-        if (out_data->msgs) {
-            smtpd_respond_multiline(scr, 250, out_data->msgs);
-        }
-        else {
-            smtpd_respond_oneline(scr, 250, "Queued");
-        }
-        return 250;
+        smtpd_respond(scr, 250, "Queued", out_data);
+        break;
     case SMTPD_DENY:
-        if (out_data->msgs) {
-            smtpd_respond_multiline(scr, 552, out_data->msgs);
-        }
-        else {
-            smtpd_respond_oneline(scr, 552, "Message denied");
-        }
-        return 552;
+        smtpd_respond(scr, 552, "Message denied", out_data);
+        break;
     case SMTPD_DENYSOFT:
-        if (out_data->msgs) {
-            smtpd_respond_multiline(scr, 452, out_data->msgs);
-        }
-        else {
-            smtpd_respond_oneline(scr, 452, "Message denied temporarily");
-        }
-        return 452;
+        smtpd_respond(scr, 452, "Message denied temporarily", out_data);
+        break;
     default:
-        if (out_data->msgs) {
-            smtpd_respond_multiline(scr, 451, out_data->msgs);
-        }
-        else {
-            smtpd_respond_oneline(scr, 451,
-                                  "Queuing declined or disabled; "
-                                  "try again later");
-        }
-        return 451;
+        smtpd_respond(scr, 451, "Queuing declined or disabled; try again later",
+                      out_data);
+        break;
     }
+
+    return disconnect;
 }
 
 /* for debugging
@@ -627,24 +564,26 @@
 
 static void smtpd_add_received_header(smtpd_session_rec *scr)
 {
+    const char *remote_host;
+    char time_string[80];
+    char *received_from;
+    char *protocol =
+      scr->protocol_type == SMTPD_PROTOCOL_ESMTP ? "ESMTP" : "SMTP";
+    char *heloed;
     apr_time_exp_t t;
+    apr_size_t len;
+    apr_pool_t *p;
     smtpd_envelope_rec *str = scr->envelope;
     smtpd_svr_config_rec *pConfig =
       ap_get_module_config(scr->s->module_config,
                            &smtpd_module);
-    char time_string[80];
-    apr_size_t len;
-    apr_pool_t *p;
-    char *received_from;
-    char *protocol =
-      scr->protocol_type == SMTPD_PROTOCOL_ESMTP ? "ESMTP" : "SMTP";
+
     /* XXX: For now we mandatorily do a DNS lookup,
        make it so we can do this according to the 
        config rule "HostnameLookups" */
-    const char *remote_host = ap_get_remote_host(scr->c, NULL,
-                                                 REMOTE_DOUBLE_REV, NULL);
-    char *heloed;
-
+    remote_host = ap_get_remote_host(scr->c, NULL,
+                                     REMOTE_DOUBLE_REV, NULL);
+    
     apr_pool_create(&p, scr->p);
 
     heloed = 
@@ -670,93 +609,37 @@
     apr_pool_destroy(p);
 }
 
-static int smtpd_handler_data(smtpd_session_rec *scr, char *buffer,
-                              smtpd_return_data *out_data)
+static int smtpd_default_data(smtpd_session_rec *scr, apr_pool_t *p)
 {
+    int rv;
+    int disconnect = 0;
+    apr_file_t *tfp;
     smtpd_envelope_rec *str = scr->envelope;
-    smtpd_svr_config_rec *pConfig =
-      ap_get_module_config(scr->s->module_config,
-                           &smtpd_module);
     smtpd_header_filter_ctx header_ctx = {0, scr, NULL, NULL};
-    int rv, retval = 0;
-    char *tempfile;
-    const char *string, *tempdir;
-    apr_file_t *tfp;
-    apr_size_t len, total_data = 0;
-    apr_bucket_brigade *bb;
-    apr_bucket *e;
-    apreq_parser_t *rfc822_parser;
-
-    if (buffer != NULL) {
-        smtpd_respond_oneline(scr, 501, "Syntax: DATA");
-        return 501;
-    }
-
-    switch(smtpd_run_data(scr, out_data)) {
-    case SMTPD_DONE:
-        return 1;
-    case SMTPD_DONE_DISCONNECT:
-        return 0;
-    case SMTPD_DENY:
-        /* REVIEW: should we reset state here? */
-        /* smtpd_clear_request_rec(sr); */
-        if (out_data->msgs) {
-            smtpd_respond_multiline(scr, 554, out_data->msgs);
-        }
-        else {
-            smtpd_respond_oneline(scr, 554, "Message denied");
-        }
-        return 554;
-    case SMTPD_DENYSOFT:
-        /* REVIEW: should we reset state here? */
-        /* smtpd_clear_request_rec(sr); */
-        if (out_data->msgs) {
-            smtpd_respond_multiline(scr, 451, out_data->msgs);
-        }
-        else {
-            smtpd_respond_oneline(scr, 451, "Message denied temporarily");
-        }
-        return 451;
-    case SMTPD_DENY_DISCONNECT:
-        if (out_data->msgs) {
-            smtpd_respond_multiline(scr, 554, out_data->msgs);
-        }
-        else {
-            smtpd_respond_oneline(scr, 554, "Message denied");
-        }
-        return 0;
-    case SMTPD_DENYSOFT_DISCONNECT:
-        if (out_data->msgs) {
-            smtpd_respond_multiline(scr, 451, out_data->msgs);
-        }
-        else {
-            smtpd_respond_oneline(scr, 451, "Message denied temporarily");
-        }
-        return 0;
-    default:
-        break;
-    }
-
-    if (str->trans_state != SMTPD_STATE_GOT_RCPT) {
-        smtpd_respond_oneline(scr, 503, "Error: need RCPT command");
-        return 503;
-    }
-
-    rv = apr_temp_dir_get(&tempdir, str->p);
-    if (rv) {
-        smtpd_respond_oneline(scr, 421, "Error: Internal");
-        return 0;
-    }
-
-    tempfile = apr_psprintf(str->p, "%s/tmp.XXXXXX", tempdir);
-    rv = apr_file_mktemp(&tfp, tempfile,
-                         APR_CREATE | APR_WRITE | APR_READ |
-                         APR_DELONCLOSE, scr->p);
+   
+    /* get temporary file pointer */
+    {
+        const char *tempdir;
+        char *tempfile;
+
+        rv = apr_temp_dir_get(&tempdir, p);
+        if (rv) {
+            smtpd_respond_oneline(scr, 421, "Error: Internal");
+            disconnect = 1;
+            return disconnect;
+        }
+
+        tempfile = apr_psprintf(p, "%s/tmp.XXXXXX", tempdir);
+        rv = apr_file_mktemp(&tfp, tempfile,
+                             APR_CREATE | APR_WRITE | APR_READ |
+                             APR_DELONCLOSE, str->p);
     
-    if (rv != APR_SUCCESS) {
-        smtpd_respond_oneline(scr, 421, "Error: Internal");
-        /* file error close connection */
-        return 0;
+        if (rv != APR_SUCCESS) {
+            smtpd_respond_oneline(scr, 421, "Error: Internal");
+            /* file error close connection */
+            disconnect = 1;
+            return disconnect;
+        }
     }
 
     str->tfp = tfp;
@@ -765,48 +648,61 @@
     /* add filter that translates ".\r\n" into EOS */
     smtpd_add_input_filter_handle(smtpd_data_input_filter_handle, 0, scr);
 
-    /* add filter that parses smtp headers */    
-    header_ctx.rfc822_parser = apreq_parser_make(str->p,
-                                                 scr->c->bucket_alloc,
-                                                 "text/rfc822",
-                                                 apreq_parse_headers,
-                                                 1000, NULL, NULL, NULL);
-    header_ctx.bb = apr_brigade_create(str->p, scr->c->bucket_alloc);
-    smtpd_add_input_filter_handle(smtpd_header_input_filter_handle,
-                                  &header_ctx, scr);
+    /* add filter that parses smtp headers */
+    {
+        header_ctx.rfc822_parser = apreq_parser_make(str->p,
+                                                     scr->c->bucket_alloc,
+                                                     "text/rfc822",
+                                                     apreq_parse_headers,
+                                                     1000, NULL, NULL, NULL);
+        header_ctx.bb = apr_brigade_create(str->p, scr->c->bucket_alloc);
+        smtpd_add_input_filter_handle(smtpd_header_input_filter_handle,
+                                      &header_ctx, scr);
+    }
 
-    bb = apr_brigade_create(str->p, scr->c->bucket_alloc);
-    /* wait until there is no more data
+    /* read data: wait until there is no more data
        or until we have too much data */
-    while (total_data < pConfig->max_data) {
-        rv = ap_get_brigade(scr->envelope->input_filters, bb, AP_MODE_GETLINE,
-                            APR_BLOCK_READ, 0);
-        
-        if (rv != APR_SUCCESS) {
-            goto done_spooling;
-        }
 
-        for (e = APR_BRIGADE_FIRST(bb);
-             ((e != APR_BRIGADE_SENTINEL(bb)) &&
-              (total_data < pConfig->max_data));
-             e = APR_BUCKET_NEXT(e)) {
-
-            if (APR_BUCKET_IS_EOS(e)) {
+    {
+        const char *string;
+        apr_bucket_brigade *bb =
+          apr_brigade_create(str->p, scr->c->bucket_alloc);
+        apr_size_t len, total_data = 0;
+        apr_bucket *e;
+        smtpd_svr_config_rec *pConfig =
+          ap_get_module_config(scr->s->module_config,
+                               &smtpd_module);
+
+        while (total_data < pConfig->max_data) {
+            rv = ap_get_brigade(scr->envelope->input_filters, bb,
+                                AP_MODE_GETLINE, APR_BLOCK_READ, 0);
+        
+            if (rv != APR_SUCCESS) {
                 goto done_spooling;
             }
 
-            rv = apr_bucket_read(e, &string, &len, APR_BLOCK_READ);
-            if (rv != APR_SUCCESS) {
-                len = 0;
-                break;
-            }
+            for (e = APR_BRIGADE_FIRST(bb);
+                 ((e != APR_BRIGADE_SENTINEL(bb)) &&
+                  (total_data < pConfig->max_data));
+                 e = APR_BUCKET_NEXT(e)) {
+
+                if (APR_BUCKET_IS_EOS(e)) {
+                    goto done_spooling;
+                }
+
+                rv = apr_bucket_read(e, &string, &len, APR_BLOCK_READ);
+                if (rv != APR_SUCCESS) {
+                    len = 0;
+                    break;
+                }
             
-            if (!len)
-                continue;
+                if (!len)
+                    continue;
 
-            apr_file_write(tfp, string, &len);
+                apr_file_write(tfp, string, &len);
 
-            total_data += len;
+                total_data += len;
+            }
         }
     }
 
@@ -815,44 +711,87 @@
 
     smtpd_add_received_header(scr);
 
-    switch(smtpd_run_data_post(scr, out_data)) {
+    /* run data_post hook */
+    {
+        smtpd_return_data *out_data = NULL;
+
+        switch(smtpd_run_data_post(scr, p, &out_data)) {
+        case SMTPD_DONE:
+            break;
+        case SMTPD_DONE_DISCONNECT:
+            disconnect = 1;
+            break;
+        case SMTPD_DENY:
+            smtpd_respond(scr, 552, "Message denied", out_data);
+            smtpd_reset_envelope(scr);
+            break;
+        case SMTPD_DENYSOFT:
+            smtpd_respond(scr, 452, "Message denied temporarily", out_data);
+            smtpd_reset_envelope(scr);
+            break;
+        default:
+            disconnect = smtpd_queue(scr, p);
+            smtpd_reset_envelope(scr);
+            break;
+        }
+    }
+    
+    apr_file_close(tfp);
+    return disconnect;
+}
+
+static int smtpd_handler_data(smtpd_session_rec *scr,
+                              apr_pool_t *per_command_pool, char *buffer)
+{
+    int disconnect = 0;
+    smtpd_return_data *out_data = NULL;
+
+    /* qpsmtpd does this after calling smtpd_run_data()
+       but that doesn't make sense with the rest of this code
+       so we do this check here */
+    if (scr->envelope->trans_state != SMTPD_STATE_GOT_RCPT) {
+        smtpd_respond_oneline(scr, 503, "Error: need RCPT command");
+        return disconnect;
+    }
+
+    if (buffer != NULL) {
+        smtpd_respond_oneline(scr, 501, "Syntax: DATA");
+        return disconnect;
+    }
+
+    switch(smtpd_run_data(scr, per_command_pool, &out_data)) {
     case SMTPD_DONE:
-        retval = 1;
-        goto cleanup;
+        break;
     case SMTPD_DONE_DISCONNECT:
-        retval = 0;
-        goto cleanup;
+        disconnect = 1;
+        break;
     case SMTPD_DENY:
-        retval = 552;
-        if (out_data->msgs) {
-            smtpd_respond_multiline(scr, 552, out_data->msgs);
-        }
-        else {
-            smtpd_respond_oneline(scr, 552, "Message denied");
-        }
+        /* REVIEW: should we reset state here? */
+        /* smtpd_clear_request_rec(sr); */
+        smtpd_respond(scr, 554, "Message denied", out_data);
         break;
     case SMTPD_DENYSOFT:
-        retval = 452;
-        if (out_data->msgs) {
-            smtpd_respond_multiline(scr, 452, out_data->msgs);
-        }
-        else {
-            smtpd_respond_oneline(scr, 452, "Message denied temporarily");
-        }
+        /* REVIEW: should we reset state here? */
+        /* smtpd_clear_request_rec(sr); */
+        smtpd_respond(scr, 451, "Message denied temporarily", out_data);
+        break;
+    case SMTPD_DENY_DISCONNECT:
+        smtpd_respond(scr, 554, "Message denied", out_data);
+        disconnect = 1;
+        break;
+    case SMTPD_DENYSOFT_DISCONNECT:
+        smtpd_respond(scr, 451, "Message denied temporarily", out_data);
+        disconnect = 1;
         break;
     default:
-        retval = smtpd_queue(scr, out_data);
+        disconnect = smtpd_default_data(scr, per_command_pool);
+        break;
     }
-    
-    smtpd_reset_envelope(scr);
-    
- cleanup:
-    apr_file_close(tfp);
-    return retval;
+
+    return disconnect;
 }
 
-static int smtpd_handler_rset(smtpd_session_rec *scr, char *buffer,
-                              smtpd_return_data *out_data)
+static int smtpd_handler_rset(smtpd_session_rec *scr, char *buffer)
 {
     if (buffer != NULL) {
         smtpd_respond_oneline(scr, 501, "Syntax: RSET");
@@ -865,26 +804,28 @@
     return 250;
 }
 
-static int smtpd_handler_quit(smtpd_session_rec *scr, char *buffer,
-                              smtpd_return_data *out_data)
+static int smtpd_handler_quit(smtpd_session_rec *scr,
+                              apr_pool_t *per_command_pool, char *buffer)
 {
     if (buffer != NULL) {
         smtpd_respond_oneline(scr, 501, "Syntax: QUIT");
         return 501;
     }
 
-    if (smtpd_run_quit(scr, out_data) != SMTPD_DONE) {
+    if (smtpd_run_quit(scr, per_command_pool) != SMTPD_DONE) {
         smtpd_respond_oneline(scr, 221, "Bye");
     }
-    /* zero to disconnect */
-    return 0;
+
+    return 1;
 }
 
-static int smtpd_handler_vrfy(smtpd_session_rec *scr, char *buffer,
-                              smtpd_return_data *out_data)
+static int smtpd_handler_vrfy(smtpd_session_rec *scr,
+                              apr_pool_t *per_command_pool, char *buffer)
 {
     int error;
-
+    int disconnect = 0;
+    smtpd_return_data *out_data = NULL;
+    
     if (buffer == NULL) {
         goto syntax_error;
     }
@@ -894,39 +835,27 @@
     if (error) {
     syntax_error:
         smtpd_respond_oneline(scr, 501, "Syntax: VRFY String");
-        return 501;
+        return disconnect;
     }
 
-    switch(smtpd_run_vrfy(scr, out_data, buffer)) {
+    switch(smtpd_run_vrfy(scr, per_command_pool, buffer, &out_data)) {
     case SMTPD_DONE:
-        return 1;
+        break;
     case SMTPD_DONE_DISCONNECT:
-        return 0;
+        disconnect = 1;
+        break;
     case SMTPD_DENY:
-        if (out_data->msgs) {
-            smtpd_respond_multiline(scr, 554, out_data->msgs);
-        }
-        else {
-            smtpd_respond_oneline(scr, 554, "Address denied");
-        }
-        return 554;
+        smtpd_respond(scr, 554, "Address denied", out_data);
+        break;
     case SMTPD_OK: /* user is okay */
-        if (out_data->msgs) {
-            smtpd_respond_multiline(scr, 250, out_data->msgs);
-        }
-        else {
-            smtpd_respond_oneline(scr, 250, "Address okay");
-        }
-        return 250;
+        smtpd_respond(scr, 250, "Address okay", out_data);
+        break;
     default:
-        if (out_data->msgs) {
-            smtpd_respond_multiline(scr, 252, out_data->msgs);
-        }
-        else {
-            smtpd_respond_oneline(scr, 252,
+        smtpd_respond_oneline(scr, 252,
                                   "Address seems fine, "
                                   "but we might not accept it.");
-        }
-        return 252;
+        break;
     }
+    
+    return disconnect;
 }