Will Partain wrote:

This scenario, and ones like it, has been discussed here
before.  I've got something working, so am posting details
{in case it's useful, so you can tell me I'm an idiot:-)}.

The 'vacation' bit of sieve wasn't working, because it kept
seeing a useless 'deliver'-created Return-Path: header.
I wrote a small patch, and it works for me. Code is self-explanatory :-) Also I slightly modified deliver.c to realize some sort of DSN and to prevent losing of mail messages due to errors.
*** lmtpengine.c.orig   Sun Nov  3 17:20:10 2002
--- lmtpengine.c        Fri Dec  6 21:53:49 2002
***************
*** 1059,1067 ****
        m->id = NULL;           /* no message-id */
      }
  
!     if (!m->return_path &&
        (body = msg_getheader(m, "return-path"))) {
        /* let's grab return_path */
        m->return_path = xstrdup(body[0]);
        clean822space(m->return_path);
        clean_retpath(m->return_path);
--- 1059,1070 ----
        m->id = NULL;           /* no message-id */
      }
  
!     if (!(func->addretpath) &&
        (body = msg_getheader(m, "return-path"))) {
        /* let's grab return_path */
+       if (m->return_path) {
+           free(m->return_path);
+       }
        m->return_path = xstrdup(body[0]);
        clean822space(m->return_path);
        clean_retpath(m->return_path);
*** deliver.c.orig      Fri Aug  2 20:54:48 2002
--- deliver.c   Thu Dec  5 15:05:45 2002
***************
*** 58,63 ****
--- 58,64 ----
  #include <syslog.h>
  #include <com_err.h>
  #include <errno.h>
+ #include <sysexits.h>
  #include <pwd.h>
  #include <sys/types.h>
  
***************
*** 101,109 ****
            "421-4.3.0 usage: deliver [-C <alt_config> ] [-m mailbox]"
            " [-a auth] [-r return_path] [-l] [-D]\r\n");
      fprintf(stderr, "421 4.3.0 %s\n", CYRUS_VERSION);
!     exit(EC_USAGE);
  }
  
  void fatal(const char* s, int code)
  {
      prot_printf(deliver_out,"421 4.3.0 deliver: %s\r\n", s);
--- 102,183 ----
            "421-4.3.0 usage: deliver [-C <alt_config> ] [-m mailbox]"
            " [-a auth] [-r return_path] [-l] [-D]\r\n");
      fprintf(stderr, "421 4.3.0 %s\n", CYRUS_VERSION);
!     exit(EX_TEMPFAIL);
  }
  
+ char *convert_lmtp(int r)
+ {
+     switch (r) {
+     case 0:
+       return "250 2.1.5 Ok";
+       
+     case IMAP_IOERROR:
+       return "451 4.3.0 System I/O error";
+ 
+     case IMAP_SERVER_UNAVAILABLE:
+       return "451 4.4.0 Remote server unavailable";
+ 
+     case IMAP_NOSPACE:
+       return "451 4.3.1 cannot create file: out of space";
+ 
+     case IMAP_AGAIN:
+       return "451 4.3.0 transient system error";
+               
+     case IMAP_PERMISSION_DENIED:
+       return "550 5.7.1 Permission denied";
+ 
+     case IMAP_QUOTA_EXCEEDED:
+       return "552 5.2.2 Over quota";
+ 
+     case IMAP_MAILBOX_BADFORMAT:
+     case IMAP_MAILBOX_NOTSUPPORTED:
+       return "451 4.2.0 Mailbox has an invalid format";
+ 
+     case IMAP_MESSAGE_CONTAINSNULL:
+       return "554 5.6.0 Message contains NUL characters";
+       
+     case IMAP_MESSAGE_CONTAINSNL:
+       return "554 5.6.0 Message contains bare newlines";
+ 
+     case IMAP_MESSAGE_CONTAINS8BIT:
+       return "554 5.6.0 Message contains non-ASCII characters in headers";
+ 
+     case IMAP_MESSAGE_BADHEADER:
+       return "554 5.6.0 Message contains invalid header";
+ 
+     case IMAP_MESSAGE_NOBLANKLINE:
+       return "554 5.6.0 Message has no header/body separator";
+ 
+     case IMAP_MAILBOX_NONEXISTENT:
+       /* XXX Might have been moved to other server */
+       return "550 5.1.1 User unknown";
+     }
+ 
+     /* Some error we're not expecting. */
+     return "554 5.0.0 Unexpected internal error";
+ }
+ 
+ /* This will always return fatal error codes due to call in RCPT_PERMFAIL state */
+ static int convert_sysexit_fatal (int r)
+ {
+     switch (r) {
+       case IMAP_MESSAGE_CONTAINSNULL:
+       case IMAP_MESSAGE_CONTAINSNL:
+       case IMAP_MESSAGE_CONTAINS8BIT:
+       case IMAP_MESSAGE_BADHEADER:
+       case IMAP_MESSAGE_NOBLANKLINE:
+           return EX_DATAERR;
+           
+       case IMAP_QUOTA_EXCEEDED:
+           return EX_UNAVAILABLE;
+       
+       case IMAP_MAILBOX_NONEXISTENT:
+           return EX_NOUSER;
+     }
+     
+     return EX_UNAVAILABLE;
+ }
+ 
  void fatal(const char* s, int code)
  {
      prot_printf(deliver_out,"421 4.3.0 deliver: %s\r\n", s);
***************
*** 120,126 ****
  
      len = read(in, buf, sizeof(buf)-1);
      if (len == -1) {
!       exit(EC_IOERR);
      }
      if (len == 0) {
        exit(0);
--- 194,200 ----
  
      len = read(in, buf, sizeof(buf)-1);
      if (len == -1) {
!       exit(EX_TEMPFAIL);
      }
      if (len == 0) {
        exit(0);
***************
*** 130,136 ****
         xxx can cause deadlock??? */
      do {
        cnt = write(out, buf+amnt,len-amnt);
!       if (cnt == -1) exit(EC_IOERR);
        amnt += cnt;
      } while (amnt<len);
  
--- 204,210 ----
         xxx can cause deadlock??? */
      do {
        cnt = write(out, buf+amnt,len-amnt);
!       if (cnt == -1) exit(EX_TEMPFAIL);
        amnt += cnt;
      } while (amnt<len);
  
***************
*** 166,172 ****
        nfound = select(highest, &rset, &wset, NULL, NULL);
        if (nfound < 0) {
            if (errno == EINTR) continue;
!           exit(EC_IOERR);
        }
  
        if ((FD_ISSET(lmtp_in,&rset))  && (FD_ISSET(local_out,&wset))) {
--- 240,246 ----
        nfound = select(highest, &rset, &wset, NULL, NULL);
        if (nfound < 0) {
            if (errno == EINTR) continue;
!           exit(EX_TEMPFAIL);
        }
  
        if ((FD_ISSET(lmtp_in,&rset))  && (FD_ISSET(local_out,&wset))) {
***************
*** 289,295 ****
  {
      com_err(msg, 0, error_message(errno));
  
!     fatal(msg, EC_CONFIG);
  }
  
  /* initialize the network 
--- 363,369 ----
  {
      com_err(msg, 0, error_message(errno));
  
!     fatal(msg, EX_TEMPFAIL);
  }
  
  /* initialize the network 
***************
*** 369,375 ****
      lmtp_disconnect(conn);
  
      /* examine txn for error state */
!     r = 0;
      for (j = 0; j < txn->rcpt_num; j++) {
        switch (txn->rcpt[j].result) {
        case RCPT_GOOD:
--- 443,449 ----
      lmtp_disconnect(conn);
  
      /* examine txn for error state */
!     r = EX_OK;
      for (j = 0; j < txn->rcpt_num; j++) {
        switch (txn->rcpt[j].result) {
        case RCPT_GOOD:
***************
*** 376,391 ****
            break;
  
        case RCPT_TEMPFAIL:
!           r = EC_TEMPFAIL;
            break;
  
        case RCPT_PERMFAIL:
!           /* we just need any permanent failure, though we should
!              probably return data from the client-side LMTP info */
!           printf("%s: %s\n", 
!                  txn->rcpt[j].addr, error_message(txn->rcpt[j].r));
!           if (r != EC_TEMPFAIL) {
!               r = EC_DATAERR;
            }
            break;
        }
--- 450,465 ----
            break;
  
        case RCPT_TEMPFAIL:
!           printf(">>> RCPT TO: %s\n", txn->rcpt[j].addr);
!           printf("<<< %s\n", convert_lmtp(txn->rcpt[j].r));
!           r = EX_TEMPFAIL;
            break;
  
        case RCPT_PERMFAIL:
!           printf(">>> RCPT TO: %s\n", txn->rcpt[j].addr);
!           printf("<<< %s\n", convert_lmtp(txn->rcpt[j].r));
!           if (r != EX_TEMPFAIL) {
!               r = convert_sysexit_fatal(txn->rcpt[j].r);
            }
            break;
        }

Reply via email to