--- /dev/null
+/*$Id: ezmlm-split.c,v 1.6 1999/05/12 22:17:54 lindberg Exp $*/
+/*$Name: ezmlm-idx-040 $*/
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "error.h"
+#include "stralloc.h"
+#include "str.h"
+#include "env.h"
+#include "sig.h"
+#include "slurp.h"
+#include "getconf.h"
+#include "strerr.h"
+#include "byte.h"
+#include "getln.h"
+#include "case.h"
+#include "qmail.h"
+#include "substdio.h"
+#include "readwrite.h"
+#include "quote.h"
+#include "now.h"
+#include "uint32.h"
+#include "fmt.h"
+#include "errtxt.h"
+#include "idx.h"
+
+#define FATAL "ezmlm-split: fatal: "
+#define INFO "ezmlm-split: info: "
+
+int flagdo = 1; /* default is manager function */
+
+char *sender;
+char *split;
+stralloc outhost = {0};
+stralloc inlocal = {0};
+stralloc outlocal = {0};
+stralloc target = {0};
+stralloc lctarget = {0};
+stralloc line = {0};
+stralloc domain = {0};
+stralloc name = {0};
+stralloc from = {0};
+stralloc to = {0};
+char strnum[FMT_ULONG];
+unsigned long lineno;
+int flagfound;
+
+void die_usage() {
+ strerr_die1x(100,"ezmlm-split: usage: ezmlm-split [-dD] dir [splitfile]"); }
+
+void die_nomem() { strerr_die2x(111,FATAL,ERR_NOMEM); }
+
+void die_badaddr()
+{
+ strerr_die2x(100,FATAL,ERR_BAD_ADDRESS);
+}
+
+void die_syntax()
+{
+ strnum[fmt_ulong(strnum,lineno)] = '\0';
+ strerr_die6x(111,FATAL,split," syntax error line ",strnum,": ",line.s);
+}
+
+char spbuf[1024]; /* should normally hold entire file */
+substdio sssp;
+
+struct qmail qq;
+int qqwrite(fd,buf,len) int fd; char *buf; unsigned int len;
+{
+ qmail_put(&qq,buf,len);
+ return (int) len;
+}
+char qqbuf[1];
+substdio ssqq = SUBSTDIO_FDBUF(qqwrite,-1,qqbuf,(int) sizeof(qqbuf));
+
+char outbuf[1];
+substdio ssout = SUBSTDIO_FDBUF(write,1,outbuf,(int) sizeof(outbuf));
+
+char inbuf[1024];
+substdio ssin = SUBSTDIO_FDBUF(read,0,inbuf,(int) sizeof(inbuf));
+
+int findname()
+/* returns 1 if a matching line was found, 0 otherwise. name will contain */
+/* the correct list address in either case */
+{
+ char *cpat,*cp,*cpname,*cp1,*cp2,*cplast;
+ unsigned long u;
+ uint32 h;
+ unsigned char hash,hash_hi,hash_lo;
+ unsigned int pos,pos_name,pos_hi;
+ char ch;
+ int fd,match;
+
+ /* make case insensitive hash */
+ flagfound = 0; /* default */
+ cpname = ""; /* default */
+ if (!stralloc_copy(&lctarget,&target)) die_nomem();
+ case_lowerb(lctarget.s,lctarget.len -1);
+ h = 5381;
+ cp = lctarget.s;
+ while ((ch = *cp++)) {
+ h = (h + (h << 5)) ^ (uint32) ch;
+ }
+ hash = (h % 53);
+
+ /* make domain pointer */
+ cpat = lctarget.s + str_chr(lctarget.s,'@');
+ if (!*cpat)
+ strerr_die4x(100,FATAL,ERR_ADDR_AT,": ",target.s);
+ cplast = cpat + str_len(cpat) - 1;
+ if (*cplast == '.') --cplast; /* annonying special case */
+ cp1 = cpat + byte_rchr(cpat,cplast - cpat, '.');
+ if (cp1 != cplast) { /* got one '.' */
+ if (!stralloc_copyb(&domain,cp1 + 1, cplast - cp1)) die_nomem();
+ cp2 = cpat + byte_rchr(cpat, cp1 - cpat,'.');
+ if (cp2 == cp1) cp2 = cpat;
+ ++cp2;
+ if (!stralloc_append(&domain,".")) die_nomem();
+ if (!stralloc_catb(&domain,cp2, cp1 - cp2)) die_nomem();
+ } else /* no '.' */
+ if (!stralloc_copyb(&domain,cpat + 1,cplast - cpat)) die_nomem();
+ if (!stralloc_0(&domain)) die_nomem();
+
+ if ((fd = open_read(split)) == -1)
+ strerr_die4sys(111,FATAL,ERR_OPEN,split,": ");
+ substdio_fdbuf(&sssp,read,fd,spbuf,(int) sizeof(spbuf));
+ lineno = 0;
+ for (;;) { /* dom:hash_lo:hash_hi:listaddress */
+ if (getln(&sssp,&line,&match,'\n') == -1)
+ strerr_die4sys(111,FATAL,ERR_READ,split,": ");
+ lineno++;
+ if (!match)
+ break;
+ if (line.s[0] == '#') continue; /* comment */
+ line.s[line.len - 1] = '\0'; /* no need to allow \0 in lines */
+ if (!line.s[pos = str_chr(line.s,':')])
+ continue; /* usually blank line */
+ line.s[pos] = '\0';
+ if (pos == 0 || /* no domain */
+ (case_starts(domain.s,line.s))) { /* or matching domain */
+ if (!line.s[++pos]) die_syntax();
+ pos_hi = pos + str_chr(line.s + pos,':');
+ if (!line.s[pos_hi]) die_syntax();
+ pos_hi++;
+ (void) scan_ulong(line.s + pos, &u); /* scan_uint() not in ezmlm */
+ hash_lo = (unsigned char) u;
+ (void) scan_ulong(line.s + pos_hi, &u);
+ hash_hi = (unsigned char) u;
+ pos_name = pos_hi + str_chr(line.s + pos_hi,':');
+ if (pos_hi == pos_name) hash_hi = 52L; /* default hi = 52 */
+ if (line.s[pos_name]) pos_name++;
+ if (hash > hash_hi || hash < hash_lo) continue; /* not us */
+ cpname = line.s + pos_name;
+ while (*cpname && /* isolate name */
+ (*cpname == ' ' || *cpname == '\t')) cpname++;
+ pos = line.len - 2;
+ while (pos && (line.s[pos] == '\n' || line.s[pos] == ' ' ||
+ line.s[pos] == '\t')) line.s[pos--] = '\0';
+ break;
+ }
+ }
+ close(fd);
+
+ if (*cpname) {
+ if (!stralloc_copys(&name,cpname)) die_nomem();
+ if (byte_chr(name.s,name.len,'@') == name.len) { /* local sublist */
+ if (!stralloc_append(&name,"@")) die_nomem();
+ if (!stralloc_cat(&name,&outhost)) die_nomem();
+ }
+ if (!stralloc_0(&name)) die_nomem();
+ return 1;
+ } else { /* match without name or no match =>this list */
+ if (!stralloc_copy(&name,&outlocal)) die_nomem();
+ if (!stralloc_append(&name,"@")) die_nomem();
+ if (!stralloc_cat(&name,&outhost)) die_nomem();
+ if (!stralloc_0(&name)) die_nomem();
+ return 0;
+ }
+}
+
+void main(argc,argv)
+int argc;
+char **argv;
+{
+ char *dir;
+ char *local;
+ char *action;
+ char *def;
+ char *dtline;
+ char *nhost;
+ char *err;
+ unsigned int i;
+ int match;
+ int optind = 1;
+
+ sig_pipeignore();
+
+ dir = argv[optind++];
+ if (!dir) die_usage();
+ if (dir[0] == '-') {
+ if (dir[1] == 'd') flagdo = 1;
+ else if (dir[1] == 'D') flagdo = 0;
+ else die_usage();
+ if (!(dir = argv[optind++])) die_usage();
+ }
+ if (!(split = argv[optind]))
+ split = "split";
+
+ if (chdir(dir) == -1)
+ strerr_die4sys(111,FATAL,ERR_SWITCH,dir,": ");
+
+ getconf_line(&outhost,"outhost",1,FATAL,dir);
+ getconf_line(&outlocal,"outlocal",1,FATAL,dir);
+
+ if (flagdo) {
+ sender = env_get("SENDER");
+ if (!sender) strerr_die2x(100,FATAL,ERR_NOSENDER);
+ if (!*sender)
+ strerr_die2x(100,FATAL,ERR_BOUNCE);
+ if (!sender[str_chr(sender,'@')])
+ strerr_die2x(100,FATAL,ERR_ANONYMOUS);
+ if (str_equal(sender,"#@[]"))
+ strerr_die2x(100,FATAL,ERR_BOUNCE);
+
+ def = env_get("DEFAULT");
+ if (def) {
+ action = def;
+ } else {
+ local = env_get("LOCAL");
+ if (!local) strerr_die2x(100,FATAL,ERR_NOLOCAL);
+ getconf_line(&inlocal,"inlocal",1,FATAL,dir);
+ if (inlocal.len > str_len(local)) die_badaddr();
+ if (case_diffb(inlocal.s,inlocal.len,local)) die_badaddr();
+ action = local + inlocal.len + 1;
+ }
+ if (!stralloc_copys(&target,sender)) die_nomem();
+ if (action[0]) {
+ i = str_chr(action,'-');
+ if (action[i]) {
+ action[i] = '\0';
+ if (!stralloc_copys(&target,action + i + 1)) die_nomem();
+ i = byte_rchr(target.s,target.len,'=');
+ if (i < target.len)
+ target.s[i] = '@';
+ }
+ }
+ if (!stralloc_0(&target)) die_nomem();
+
+ if (case_diffs(action,ACTION_SUBSCRIBE) &&
+ case_diffs(action,ALT_SUBSCRIBE) &&
+ case_diffs(action,ACTION_UNSUBSCRIBE) &&
+ case_diffs(action,ALT_UNSUBSCRIBE))
+ _exit(0); /* not for us */
+
+ if (findname()) {
+ /* new sender */
+ if (!stralloc_copy(&from,&outlocal)) die_nomem();
+ if (!stralloc_cats(&from,"-return-@")) die_nomem();
+ if (!stralloc_cat(&from,&outhost)) die_nomem();
+ if (!stralloc_0(&from)) die_nomem();
+ if (name.s[i = str_rchr(name.s,'@')]) { /* name must have '@'*/
+ nhost = name.s + i;
+ *(nhost++) = '\0';
+ }
+ if (!stralloc_copys(&to,name.s)) die_nomem(); /* local */
+ if (!stralloc_append(&to,"-")) die_nomem(); /* - */
+ if (!stralloc_cats(&to,action)) die_nomem(); /* subscribe */
+ if (!stralloc_append(&to,"-")) die_nomem(); /* - */
+ if (target.s[i = str_rchr(target.s,'@')])
+ target.s[i] = '=';
+ if (!stralloc_cats(&to,target.s)) die_nomem(); /* target */
+ if (!stralloc_append(&to,"@")) die_nomem(); /* - */
+ if (!stralloc_cats(&to,nhost)) die_nomem(); /* host */
+ if (!stralloc_0(&to)) die_nomem();
+ dtline = env_get("DTLINE");
+ if (!dtline) strerr_die2x(100,FATAL,ERR_NODTLINE);
+
+ if (qmail_open(&qq,(stralloc *) 0) == -1)
+ strerr_die2sys(111,FATAL,ERR_QMAIL_QUEUE);
+ qmail_puts(&qq,dtline); /* delivered-to */
+ if (substdio_copy(&ssqq,&ssin) != 0)
+ strerr_die2sys(111,FATAL,ERR_READ_INPUT);
+ qmail_from(&qq,from.s);
+ qmail_to(&qq,to.s);
+
+ if (*(err = qmail_close(&qq)) != '\0')
+ strerr_die3x(111,FATAL,ERR_TMP_QMAIL_QUEUE,err + 1);
+
+ strnum[fmt_ulong(strnum,qmail_qp(&qq))] = 0;
+ strerr_die3x(99,INFO,"qp ",strnum);
+ }
+ _exit(0);
+ } else {
+
+ for (;;) {
+ if (getln(&ssin,&line,&match,'\n') == -1)
+ strerr_die2sys(111,FATAL,ERR_READ_INPUT);
+ if (!match) break;
+ if (line.len == 1) continue; /* ignore blank lines */
+ if (line.s[0] == '#') continue; /* ignore comments */
+ if (!stralloc_copy(&target,&line)) die_nomem();
+ target.s[target.len - 1] = '\0';
+ (void) findname();
+ if (!stralloc_cats(&name,": ")) die_nomem();
+ if (!stralloc_cats(&name,target.s)) die_nomem();
+ if (!stralloc_append(&name,"\n")) die_nomem();
+ if (substdio_put(&ssout,name.s,name.len) == -1)
+ strerr_die2sys(111,ERR_WRITE,"output: ");
+ }
+ if (substdio_flush(&ssout) == -1)
+ strerr_die2sys(111,ERR_FLUSH,"output: ");
+ _exit(0);
+ }
+}
+
+