sendmail+procmail+cyrus, return-path, sieve
Oleg Derevenetz
oleg at vsi.ru
Mon Dec 16 12:23:05 EST 2002
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.
-------------- next part --------------
*** 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);
-------------- next part --------------
*** 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;
}
More information about the Info-cyrus
mailing list