+/*$Id: ezmlm-return.c,v 1.26 1999/08/07 20:50:52 lindberg Exp $*/
+/*$Name: ezmlm-idx-040 $*/
+#include <sys/types.h>
+#include "direntry.h"
#include "stralloc.h"
#include "str.h"
#include "env.h"
#include "now.h"
#include "cookie.h"
#include "subscribe.h"
-#include "issub.h"
+#include "errtxt.h"
+#include "idx.h"
#define FATAL "ezmlm-return: fatal: "
-void die_usage() { strerr_die1x(100,"ezmlm-return: usage: ezmlm-return dir"); }
-void die_nomem() { strerr_die2x(111,FATAL,"out of memory"); }
+#define INFO "ezmlm-return: info: "
+void die_usage()
+{ strerr_die1x(100,"ezmlm-return: usage: ezmlm-return [-dD] dir"); }
+void die_nomem() { strerr_die2x(111,FATAL,ERR_NOMEM); }
void die_badaddr()
{
- strerr_die2x(100,FATAL,"I do not accept messages at this address (#5.1.1)");
+ strerr_die2x(100,FATAL,ERR_BAD_RETURN_ADDRESS);
}
void die_trash()
{
- strerr_die1x(0,"ezmlm-return: info: trash address");
+ strerr_die2x(99,INFO,"trash address");
}
char outbuf[1024];
char strnum[FMT_ULONG];
char hash[COOKIE];
char hashcopy[COOKIE];
+char *hashp = (char *) 0;
unsigned long cookiedate;
+unsigned long addrno = 0L;
+unsigned long addrno1 = 0L;
+stralloc fndir = {0};
stralloc fndate = {0};
stralloc fndatenew = {0};
stralloc fnhash = {0};
stralloc fnhashnew = {0};
+void *psql = (void *) 0;
stralloc quoted = {0};
+stralloc ddir = {0};
char *sender;
+char *dir;
+char *workdir;
void die_hashnew()
-{ strerr_die4sys(111,FATAL,"unable to write ",fnhashnew.s,": "); }
+{ strerr_die4sys(111,FATAL,ERR_WRITE,fnhashnew.s,": "); }
void die_datenew()
-{ strerr_die4sys(111,FATAL,"unable to write ",fndatenew.s,": "); }
+{ strerr_die4sys(111,FATAL,ERR_WRITE,fndatenew.s,": "); }
void die_msgin()
-{ strerr_die2sys(111,FATAL,"unable to read input: "); }
+{ strerr_die2sys(111,FATAL,ERR_READ_INPUT); }
+
+void makedir(s)
+char *s;
+{
+ if (mkdir(s,0755) == -1)
+ if (errno != error_exist)
+ strerr_die4x(111,FATAL,ERR_CREATE,s,": ");
+}
void dowit(addr,when,bounce)
char *addr;
stralloc *bounce;
{
int fd;
+ unsigned int wpos;
+ unsigned long wdir,wfile;
- if (!issub(addr)) return;
+ if (!issub(workdir,addr,(char *) 0,FATAL)) return;
- if (!stralloc_copys(&fndate,"bounce/w")) die_nomem();
- if (!stralloc_catb(&fndate,strnum,fmt_ulong(strnum,when))) die_nomem();
+ if (!stralloc_copys(&fndate,workdir)) die_nomem();
+ if (!stralloc_cats(&fndate,"/bounce/d")) die_nomem();
+ if (!stralloc_0(&fndate)) die_nomem();
+ fndate.s[fndate.len - 1] = '/'; /* replace '\0' */
+ wpos = fndate.len - 1;
+ wdir = when / 10000;
+ wfile = when - 10000 * wdir;
+ if (!stralloc_catb(&fndate,strnum,fmt_ulong(strnum,wdir))) die_nomem();
+ if (!stralloc_0(&fndate)) die_nomem();
+ makedir(fndate.s);
+ --fndate.len; /* remove terminal '\0' */
+ if (!stralloc_cats(&fndate,"/w")) die_nomem();
+ wpos = fndate.len - 1;
+ if (!stralloc_catb(&fndate,strnum,fmt_ulong(strnum,wfile))) die_nomem();
if (!stralloc_cats(&fndate,".")) die_nomem();
- if (!stralloc_catb(&fndate,strnum,fmt_ulong(strnum,(unsigned long) getpid()))) die_nomem();
+ if (!stralloc_catb(&fndate,strnum,fmt_ulong(strnum,(unsigned long) getpid())))
+ die_nomem();
if (!stralloc_0(&fndate)) die_nomem();
if (!stralloc_copy(&fndatenew,&fndate)) die_nomem();
- fndatenew.s[7] = 'W';
+ fndatenew.s[wpos] = 'W';
fd = open_trunc(fndatenew.s);
if (fd == -1) die_datenew();
if (close(fd) == -1) die_datenew(); /* NFS stupidity */
if (rename(fndatenew.s,fndate.s) == -1)
- strerr_die6sys(111,FATAL,"unable to rename ",fndatenew.s," to ",fndate.s,": ");
+ strerr_die6sys(111,FATAL,ERR_MOVE,fndatenew.s," to ",fndate.s,": ");
}
void doit(addr,msgnum,when,bounce)
{
int fd;
int fdnew;
+ unsigned int pos;
+ unsigned long ddir,dfile;
- if (!issub(addr)) return;
+ if (!issub(workdir,addr,(char *) 0,FATAL)) return;
- if (!stralloc_copys(&fndate,"bounce/d")) die_nomem();
- if (!stralloc_catb(&fndate,strnum,fmt_ulong(strnum,when))) die_nomem();
+ if (!stralloc_copys(&fndate,workdir)) die_nomem();
+ if (!stralloc_cats(&fndate,"/bounce/d")) die_nomem();
+ if (!stralloc_0(&fndate)) die_nomem();
+ makedir(fndate.s);
+ fndate.s[fndate.len-1] = '/'; /* replace terminal '\0' */
+ ddir = when / 10000;
+ dfile = when - 10000 * ddir;
+ if (!stralloc_catb(&fndate,strnum,fmt_ulong(strnum,ddir))) die_nomem();
+ if (!stralloc_copy(&fndir,&fndate)) die_nomem();
+ if (!stralloc_0(&fndir)) die_nomem(); /* make later if necessary (new addr)*/
+ if (!stralloc_cats(&fndate,"/d")) die_nomem();
+ pos = fndate.len - 2;
+ if (!stralloc_catb(&fndate,strnum,fmt_ulong(strnum,dfile))) die_nomem();
if (!stralloc_cats(&fndate,".")) die_nomem();
- if (!stralloc_catb(&fndate,strnum,fmt_ulong(strnum,(unsigned long) getpid()))) die_nomem();
+ if (!stralloc_catb(&fndate,strnum,fmt_ulong(strnum,(unsigned long) getpid())))
+ die_nomem();
+ if (addrno) { /* so that pre-VERP bounces make a d... file per address */
+ /* for the first one we use the std-style fname */
+ if (!stralloc_cats(&fndate,".")) die_nomem();
+ if (!stralloc_catb(&fndate,strnum,fmt_ulong(strnum,addrno))) die_nomem();
+ }
+ addrno++; /* get ready for next */
if (!stralloc_0(&fndate)) die_nomem();
if (!stralloc_copy(&fndatenew,&fndate)) die_nomem();
- fndatenew.s[7] = 'D';
+ fndatenew.s[pos] = '_'; /* fndate = bounce/d/nnnn/dmmmmmm */
+ /* fndatenew = bounce/d/nnnn_dmmmmmm */
fd = open_trunc(fndatenew.s);
if (fd == -1) die_datenew();
if (close(fd) == -1) die_datenew(); /* NFS stupidity */
cookie(hash,"",0,"",addr,"");
- if (!stralloc_copys(&fnhash,"bounce/h")) die_nomem();
- if (!stralloc_catb(&fnhash,hash,COOKIE)) die_nomem();
+ if (!stralloc_copys(&fnhash,workdir)) die_nomem();
+ if (!stralloc_cats(&fnhash,"/bounce/h")) die_nomem();
+ if (!stralloc_0(&fnhash)) die_nomem();
+ makedir(fnhash.s);
+ fnhash.s[fnhash.len - 1] = '/'; /* replace terminal '\0' */
+ if (!stralloc_catb(&fnhash,hash,1)) die_nomem();
+ if (!stralloc_0(&fnhash)) die_nomem();
+ makedir(fnhash.s);
+ --fnhash.len; /* remove terminal '\0' */
+ if (!stralloc_cats(&fnhash,"/h")) die_nomem();
+ pos = fnhash.len - 1;
+ if (!stralloc_catb(&fnhash,hash+1,COOKIE-1)) die_nomem();
if (!stralloc_0(&fnhash)) die_nomem();
if (!stralloc_copy(&fnhashnew,&fnhash)) die_nomem();
- fnhashnew.s[7] = 'H';
+ fnhashnew.s[pos] = 'H';
fdnew = open_trunc(fnhashnew.s);
if (fdnew == -1) die_hashnew();
fd = open_read(fnhash.s);
if (fd == -1) {
if (errno != error_noent)
- strerr_die4sys(111,FATAL,"unable to read ",fnhash.s,": ");
+ strerr_die4sys(111,FATAL,ERR_READ,fnhash.s,": ");
+ makedir(fndir.s);
if (rename(fndatenew.s,fndate.s) == -1)
- strerr_die6sys(111,FATAL,"unable to rename ",fndatenew.s," to ",fndate.s,": ");
+ strerr_die6sys(111,FATAL,ERR_MOVE,fndatenew.s," to ",fndate.s,": ");
}
else {
substdio_fdbuf(&ssin,read,fd,inbuf,sizeof(inbuf));
}
close(fd);
if (unlink(fndatenew.s) == -1)
- strerr_die4sys(111,FATAL,"unable to unlink ",fndatenew.s,": ");
+ strerr_die4sys(111,FATAL,ERR_DELETE,fndatenew.s,": ");
}
if (substdio_puts(&ssout," ") == -1) die_hashnew();
if (substdio_put(&ssout,strnum,fmt_ulong(strnum,msgnum)) == -1) die_hashnew();
if (close(fdnew) == -1) die_hashnew(); /* NFS stupidity */
if (rename(fnhashnew.s,fnhash.s) == -1)
- strerr_die6sys(111,FATAL,"unable to rename ",fnhashnew.s," to ",fnhash.s,": ");
+ strerr_die6sys(111,FATAL,ERR_MOVE,fnhashnew.s," to ",fnhash.s,": ");
}
stralloc bounce = {0};
stralloc intro = {0};
stralloc failure = {0};
stralloc paragraph = {0};
+int flagmasterbounce = 0;
int flaghaveheader;
int flaghaveintro;
stralloc key = {0};
-stralloc inhost = {0};
-stralloc outhost = {0};
-stralloc inlocal = {0};
-stralloc outlocal = {0};
char msginbuf[1024];
substdio ssmsgin;
int argc;
char **argv;
{
- char *dir;
- char *host;
char *local;
char *action;
+ char *def;
+ char *ret;
+ char *cp;
unsigned long msgnum;
unsigned long cookiedate;
unsigned long when;
+ unsigned long listno = 0L;
int match;
- int i;
+ unsigned int i;
+ int flagdig = 0;
+ int flagmaster = 0;
+ int flagreceipt = 0;
int fdlock;
+ register char ch;
umask(022);
sig_pipeignore();
dir = argv[1];
if (!dir) die_usage();
+ if (*dir == '-') { /* for normal use */
+ if (dir[1] == 'd') {
+ flagdig = 1;
+ } else if (dir[1] == 'D') {
+ flagdig = 0;
+ } else
+ die_usage();
+ dir = argv[2];
+ if (!dir) die_usage();
+ }
sender = env_get("SENDER");
- if (!sender) strerr_die2x(100,FATAL,"SENDER not set");
+ if (!sender) strerr_die2x(100,FATAL,ERR_NOSENDER);
local = env_get("LOCAL");
- if (!local) strerr_die2x(100,FATAL,"LOCAL not set");
- host = env_get("HOST");
- if (!host) strerr_die2x(100,FATAL,"HOST not set");
+ if (!local) strerr_die2x(100,FATAL,ERR_NOLOCAL);
+ def = env_get("DEFAULT"); /* qmail-1.02 */
if (chdir(dir) == -1)
- strerr_die4sys(111,FATAL,"unable to switch to ",dir,": ");
+ strerr_die4sys(111,FATAL,ERR_SWITCH,dir,": ");
switch(slurp("key",&key,32)) {
case -1:
- strerr_die4sys(111,FATAL,"unable to read ",dir,"/key: ");
+ strerr_die4sys(111,FATAL,ERR_READ,dir,"/key: ");
case 0:
- strerr_die3x(100,FATAL,dir,"/key does not exist");
+ strerr_die4x(100,FATAL,dir,"/key",ERR_NOEXIST);
}
- getconf_line(&inhost,"inhost",1,FATAL,dir);
- getconf_line(&inlocal,"inlocal",1,FATAL,dir);
- getconf_line(&outhost,"outhost",1,FATAL,dir);
- getconf_line(&outlocal,"outlocal",1,FATAL,dir);
-
- if (inhost.len != str_len(host)) die_badaddr();
- if (case_diffb(inhost.s,inhost.len,host)) die_badaddr();
- if (inlocal.len > str_len(local)) die_badaddr();
- if (case_diffb(inlocal.s,inlocal.len,local)) die_badaddr();
+ workdir = dir;
+ action = def;
- action = local + inlocal.len;
-
- if (!str_start(action,"-return-")) die_badaddr();
- action += 8;
+ if (str_start(action,"receipt-")) {
+ flagreceipt = 1;
+ action += 8;
+ }
+ ch = *action; /* -d -digest, -m -master, -g -getmaster */
+ if (ch && action[1] == '-') {
+ switch (ch) {
+ case 'g': flagmaster = 1; flagdig = 1; action += 2; break;
+ case 'm': flagmaster = 1; action += 2; break;
+ default: break;
+ }
+ }
+ if (flagdig) {
+ if (!stralloc_copys(&ddir,dir)) die_nomem();
+ if (!stralloc_cats(&ddir,"/digest")) die_nomem();
+ if (!stralloc_0(&ddir)) die_nomem();
+ workdir = ddir.s;
+ }
if (!*action) die_trash();
- if (str_start(action,"probe-")) {
- action += 6;
- action += scan_ulong(action,&cookiedate);
- if (now() - cookiedate > 3000000) die_trash();
- if (*action++ != '.') die_trash();
- i = str_chr(action,'-');
- if (i != COOKIE) die_trash();
- byte_copy(hashcopy,COOKIE,action);
- action += COOKIE;
- if (*action++ != '-') die_trash();
- i = str_rchr(action,'=');
- if (!stralloc_copyb(&line,action,i)) die_nomem();
- if (action[i]) {
- if (!stralloc_cats(&line,"@")) die_nomem();
- if (!stralloc_cats(&line,action + i + 1)) die_nomem();
- }
- if (!stralloc_0(&line)) die_nomem();
- strnum[fmt_ulong(strnum,cookiedate)] = 0;
- cookie(hash,key.s,key.len,strnum,line.s,"P");
- if (byte_diff(hash,COOKIE,hashcopy)) die_trash();
-
- if (subscribe(line.s,0) == 1) log("-probe",line.s);
- _exit(0);
+ if (flagreceipt || flagmaster) /* check cookie */
+ if (str_chr(action,'-') == COOKIE) {
+ action[COOKIE] = '\0';
+ hashp = action;
+ action += COOKIE + 1;
}
- fdlock = open_append("lockbounce");
- if (fdlock == -1)
- strerr_die4sys(111,FATAL,"unable to open ",dir,"/lockbounce: ");
- if (lock_ex(fdlock) == -1)
- strerr_die4sys(111,FATAL,"unable to lock ",dir,"/lockbounce: ");
-
- if (str_start(action,"warn-")) {
- action += 5;
- action += scan_ulong(action,&cookiedate);
- if (now() - cookiedate > 3000000) die_trash();
- if (*action++ != '.') die_trash();
- i = str_chr(action,'-');
- if (i != COOKIE) die_trash();
- byte_copy(hashcopy,COOKIE,action);
- action += COOKIE;
- if (*action++ != '-') die_trash();
- i = str_rchr(action,'=');
- if (!stralloc_copyb(&line,action,i)) die_nomem();
- if (action[i]) {
- if (!stralloc_cats(&line,"@")) die_nomem();
- if (!stralloc_cats(&line,action + i + 1)) die_nomem();
+ if (!flagreceipt) {
+ if (!flagmaster && str_start(action,"probe-")) {
+ action += 6;
+ action += scan_ulong(action,&cookiedate);
+ if (now() - cookiedate > 3000000) die_trash();
+ if (*action++ != '.') die_trash();
+ i = str_chr(action,'-');
+ if (i != COOKIE) die_trash();
+ byte_copy(hashcopy,COOKIE,action);
+ action += COOKIE;
+ if (*action++ != '-') die_trash();
+ i = str_rchr(action,'=');
+ if (!stralloc_copyb(&line,action,i)) die_nomem();
+ if (action[i]) {
+ if (!stralloc_cats(&line,"@")) die_nomem();
+ if (!stralloc_cats(&line,action + i + 1)) die_nomem();
+ }
+ if (!stralloc_0(&line)) die_nomem();
+ strnum[fmt_ulong(strnum,cookiedate)] = 0;
+ cookie(hash,key.s,key.len,strnum,line.s,"P");
+ if (byte_diff(hash,COOKIE,hashcopy)) die_trash();
+
+ (void) subscribe(workdir,line.s,0,"","-probe",1,-1,(char *) 0,FATAL);
+ _exit(99);
}
+
+ if (!stralloc_copys(&line,workdir)) die_nomem();
+ if (!stralloc_cats(&line,"/lockbounce")) die_nomem();
if (!stralloc_0(&line)) die_nomem();
- strnum[fmt_ulong(strnum,cookiedate)] = 0;
- cookie(hash,key.s,key.len,strnum,line.s,"W");
- if (byte_diff(hash,COOKIE,hashcopy)) die_trash();
- if (slurpclose(0,&bounce,1024) == -1) die_msgin();
- dowit(line.s,when,&bounce);
- _exit(0);
+ fdlock = open_append(line.s);
+ if (fdlock == -1)
+ strerr_die4sys(111,FATAL,ERR_OPEN,line.s,": ");
+ if (lock_ex(fdlock) == -1)
+ strerr_die4sys(111,FATAL,ERR_OBTAIN,line.s,": ");
+
+ if (!flagmaster && str_start(action,"warn-")) {
+ action += 5;
+ action += scan_ulong(action,&cookiedate);
+ if (now() - cookiedate > 3000000) die_trash();
+ if (*action++ != '.') die_trash();
+ i = str_chr(action,'-');
+ if (i != COOKIE) die_trash();
+ byte_copy(hashcopy,COOKIE,action);
+ action += COOKIE;
+ if (*action++ != '-') die_trash();
+ i = str_rchr(action,'=');
+ if (!stralloc_copyb(&line,action,i)) die_nomem();
+ if (action[i]) {
+ if (!stralloc_cats(&line,"@")) die_nomem();
+ if (!stralloc_cats(&line,action + i + 1)) die_nomem();
+ }
+ if (!stralloc_0(&line)) die_nomem();
+ strnum[fmt_ulong(strnum,cookiedate)] = 0;
+ cookie(hash,key.s,key.len,strnum,line.s,"W");
+ if (byte_diff(hash,COOKIE,hashcopy)) die_trash();
+
+ if (slurpclose(0,&bounce,1024) == -1) die_msgin();
+ dowit(line.s,when,&bounce);
+ _exit(99);
+ }
}
-
action += scan_ulong(action,&msgnum);
- if (*action != '-') die_badaddr();
- ++action;
+ if (*action++ != '-') die_badaddr();
+ cp = action;
+ if (*action >= '0' && *action <= '9') { /* listno */
+ action += scan_ulong(action,&listno);
+ listno++; /* logging is 1-53, not 0-52 */
+ }
- if (*action) {
- if (slurpclose(0,&bounce,1024) == -1) die_msgin();
+ if (hashp) { /* scrap bad cookies */
+ if ((ret = checktag(workdir,msgnum,0L,"x",(char *) 0,hashp))) {
+ if (*ret)
+ strerr_die2x(111,FATAL,*ret);
+ else
+ die_trash();
+ } else if (flagreceipt) {
+ if (!(ret = logmsg(dir,msgnum,listno,0L,5))) {
+ closesql();
+ strerr_die6x(99,INFO,"receipt:",cp," [",hashp,"]");
+ }
+ if (*ret) strerr_die2x(111,FATAL,ret);
+ else strerr_die2x(0,INFO,ERR_DONE);
+ } else if (*action) { /* post VERP master bounce */
+ if ((ret = logmsg(dir,msgnum,listno,0L,-1))) {
+ closesql();
+ strerr_die4x(0,INFO,"bounce [",hashp,"]");
+ }
+ if (*ret) strerr_die2x(111,FATAL,ret);
+ else strerr_die2x(99,INFO,ERR_DONE);
+ }
+ } else if (flagreceipt || flagmaster)
+ die_badaddr();
+ if (*action) {
i = str_rchr(action,'=');
if (!stralloc_copyb(&line,action,i)) die_nomem();
if (action[i]) {
if (!stralloc_cats(&line,action + i + 1)) die_nomem();
}
if (!stralloc_0(&line)) die_nomem();
+ if (slurpclose(0,&bounce,1024) == -1) die_msgin();
doit(line.s,msgnum,when,&bounce);
- _exit(0);
+ _exit(99);
}
- /* pre-VERP bounce, in QSBMF format */
+ /* pre-VERP bounce, in QSBMF format. Receipts are never pre-VERP */
substdio_fdbuf(&ssmsgin,read,0,msginbuf,sizeof(msginbuf));
}
if (!flaghaveintro) {
+ if (paragraph.s[0] == '-' && paragraph.s[1] == '-')
+ continue; /* skip MIME boundary if it exists */
if (paragraph.len < 15) die_trash();
if (str_diffn(paragraph.s,"Hi. This is the",15)) die_trash();
if (!stralloc_copy(&intro,¶graph)) die_nomem();
if (!stralloc_copyb(&line,failure.s + 1,i - 3)) die_nomem();
if (byte_chr(line.s,line.len,'\0') == line.len) {
if (!stralloc_0(&line)) die_nomem();
- doit(line.s,msgnum,when,&bounce);
+ if (flagmaster) { /* bounced msg slave! */
+ if ((i = str_rchr(line.s,'@')) >= 5) { /* 00_52@host */
+ line.s[i] = '\0'; /* 00_52 */
+ (void) scan_ulong(line.s + i - 5,&listno);
+ if ((ret = logmsg(dir,msgnum,listno + 1,0L,-1)) && *ret)
+ strerr_die2x(111,FATAL,ret);
+ strerr_warn3(INFO,"bounce ",line.s + i - 5,(struct strerr *) 0);
+ flagmasterbounce = 1;
+ }
+ } else
+ doit(line.s,msgnum,when,&bounce);
}
}
}
-
- _exit(0);
+ closesql();
+ if (flagmasterbounce)
+ strerr_die3x(0,"[",hashp,"]");
+ else
+ _exit(99);
}