This patch creates a new qmail-command rrforward(1), who implements
round-robin message forwarding to a list of addresses.

#(@) Copyright Tullio Andreatta, 2001 <tullio@logicom.it> - you have
     the right to use it - free of charges.

 Tullio Andreatta <tullio@logicom.it>

diff -u --new-file qmail-1.03-orig/Makefile qmail-1.03/Makefile
--- qmail-1.03-orig/Makefile	Mon Jun 15 12:53:16 1998
+++ qmail-1.03/Makefile	Fri Apr 27 14:24:02 2001
@@ -805,7 +805,7 @@
 qmail-pop3d qmail-popup qmail-qmqpc qmail-qmqpd qmail-qmtpd \
 qmail-smtpd sendmail tcp-env qmail-newmrh config config-fast dnscname \
 dnsptr dnsip dnsmxip dnsfq hostname ipmeprint qreceipt qsmhook qbiff \
-forward preline condredirect bouncesaying except maildirmake \
+forward rrforward preline condredirect bouncesaying except maildirmake \
 maildir2mbox maildirwatch qail elq pinq idedit install-big install \
 instcheck home home+df proc proc+df binm1 binm1+df binm2 binm2+df \
 binm3 binm3+df
@@ -931,9 +931,9 @@
 qmail-pw2u.0 qmail-qread.0 qmail-qstat.0 qmail-tcpto.0 qmail-tcpok.0 \
 qmail-pop3d.0 qmail-popup.0 qmail-qmqpc.0 qmail-qmqpd.0 qmail-qmtpd.0 \
 qmail-smtpd.0 tcp-env.0 qmail-newmrh.0 qreceipt.0 qbiff.0 forward.0 \
-preline.0 condredirect.0 bouncesaying.0 except.0 maildirmake.0 \
-maildir2mbox.0 maildirwatch.0 qmail.0 qmail-limits.0 qmail-log.0 \
-qmail-control.0 qmail-header.0 qmail-users.0 dot-qmail.0 \
+rrforward.0 preline.0 condredirect.0 bouncesaying.0 except.0 \
+maildirmake.0 maildir2mbox.0 maildirwatch.0 qmail.0 qmail-limits.0 \
+qmail-log.0 qmail-control.0 qmail-header.0 qmail-users.0 dot-qmail.0 \
 qmail-command.0 tcp-environ.0 maildir.0 mbox.0 addresses.0 \
 envelopes.0 forgeries.0
 
@@ -1696,6 +1696,21 @@
 timeoutread.h timeoutwrite.h remoteinfo.h
 	./compile remoteinfo.c
 
+rrforward: \
+load rrforward.o qmail.o strerr.a alloc.a fd.a wait.a sig.a env.a \
+substdio.a error.a str.a fs.a lock.a seek.a auto_qmail.o
+	./load rrforward qmail.o strerr.a alloc.a fd.a wait.a sig.a \
+	env.a substdio.a error.a str.a fs.a lock.a seek.a auto_qmail.o
+
+rrforward.0: \
+rrforward.1
+	nroff -man rrforward.1 > rrforward.0
+
+rrforward.o: \
+compile rrforward.c sig.h readwrite.h seek.h exit.h env.h qmail.h substdio.h \
+strerr.h substdio.h fmt.h
+	./compile rrforward.c
+
 scan_8long.o: \
 compile scan_8long.c scan.h
 	./compile scan_8long.c
@@ -1763,11 +1778,11 @@
 auto_spawn.h chkspawn.c conf-split auto_split.h conf-patrn \
 auto_patrn.h conf-users conf-groups auto_uids.h auto_usera.h extra.h \
 addresses.5 except.1 bouncesaying.1 condredirect.1 dot-qmail.9 \
-envelopes.5 forgeries.7 forward.1 maildir2mbox.1 maildirmake.1 \
-maildirwatch.1 mailsubj.1 mbox.5 preline.1 qbiff.1 qmail-clean.8 \
-qmail-command.8 qmail-control.9 qmail-getpw.9 qmail-header.5 \
-qmail-inject.8 qmail-limits.9 qmail-local.8 qmail-log.5 \
-qmail-lspawn.8 qmail-newmrh.9 qmail-newu.9 qmail-pop3d.8 \
+envelopes.5 forgeries.7 forward.1 rrforward.1 maildir2mbox.1 \
+maildirmake.1 maildirwatch.1 mailsubj.1 mbox.5 preline.1 qbiff.1 \
+qmail-clean.8 \ qmail-command.8 qmail-control.9 qmail-getpw.9 \
+qmail-header.5 qmail-inject.8 qmail-limits.9 qmail-local.8 \
+qmail-log.5 qmail-lspawn.8 qmail-newmrh.9 qmail-newu.9 qmail-pop3d.8 \
 qmail-popup.8 qmail-pw2u.9 qmail-qmqpc.8 qmail-qmqpd.8 qmail-qmtpd.8 \
 qmail-qread.8 qmail-qstat.8 qmail-queue.8 qmail-remote.8 \
 qmail-rspawn.8 qmail-send.9 qmail-showctl.8 qmail-smtpd.8 \
diff -u --new-file qmail-1.03-orig/TARGETS qmail-1.03/TARGETS
--- qmail-1.03-orig/TARGETS	Mon Jun 15 12:53:16 1998
+++ qmail-1.03/TARGETS	Fri Apr 27 14:16:36 2001
@@ -284,6 +284,8 @@
 qbiff
 forward.o
 forward
+rrforward.o
+rrforward
 preline.o
 preline
 condredirect.o
@@ -357,6 +359,7 @@
 qreceipt.0
 qbiff.0
 forward.0
+rrforward.0
 preline.0
 condredirect.0
 bouncesaying.0
diff -u --new-file qmail-1.03-orig/hier.c qmail-1.03/hier.c
--- qmail-1.03-orig/hier.c	Mon Jun 15 12:53:16 1998
+++ qmail-1.03/hier.c	Fri Apr 27 10:23:50 2001
@@ -133,6 +133,7 @@
   c(auto_qmail,"bin","qsmhook",auto_uido,auto_gidq,0755);
   c(auto_qmail,"bin","qbiff",auto_uido,auto_gidq,0755);
   c(auto_qmail,"bin","forward",auto_uido,auto_gidq,0755);
+  c(auto_qmail,"bin","rrforward",auto_uido,auto_gidq,0755);
   c(auto_qmail,"bin","preline",auto_uido,auto_gidq,0755);
   c(auto_qmail,"bin","condredirect",auto_uido,auto_gidq,0755);
   c(auto_qmail,"bin","bouncesaying",auto_uido,auto_gidq,0755);
@@ -174,6 +175,8 @@
 
   c(auto_qmail,"man/man1","forward.1",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/cat1","forward.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man1","rrforward.1",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat1","rrforward.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man1","condredirect.1",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/cat1","condredirect.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man1","bouncesaying.1",auto_uido,auto_gidq,0644);
diff -u --new-file qmail-1.03-orig/install-big.c qmail-1.03/install-big.c
--- qmail-1.03-orig/install-big.c	Mon Jun 15 12:53:16 1998
+++ qmail-1.03/install-big.c	Thu Apr 26 16:44:54 2001
@@ -133,6 +133,7 @@
   c(auto_qmail,"bin","qsmhook",auto_uido,auto_gidq,0755);
   c(auto_qmail,"bin","qbiff",auto_uido,auto_gidq,0755);
   c(auto_qmail,"bin","forward",auto_uido,auto_gidq,0755);
+  c(auto_qmail,"bin","rrforward",auto_uido,auto_gidq,0755);
   c(auto_qmail,"bin","preline",auto_uido,auto_gidq,0755);
   c(auto_qmail,"bin","condredirect",auto_uido,auto_gidq,0755);
   c(auto_qmail,"bin","bouncesaying",auto_uido,auto_gidq,0755);
@@ -174,6 +175,8 @@
 
   c(auto_qmail,"man/man1","forward.1",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/cat1","forward.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man1","rrforward.1",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat1","rrforward.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man1","condredirect.1",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/cat1","condredirect.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man1","bouncesaying.1",auto_uido,auto_gidq,0644);
diff -u --new-file qmail-1.03-orig/qmail.7 qmail-1.03/qmail.7
--- qmail-1.03-orig/qmail.7	Mon Jun 15 12:53:16 1998
+++ qmail-1.03/qmail.7	Fri Apr 27 14:17:33 2001
@@ -14,6 +14,7 @@
 .BR qbiff (1),
 .BR qreceipt (1),
 .BR forward (1),
+.BR rrforward (1),
 .BR bouncesaying (1),
 and
 .BR condredirect (1).
diff -u --new-file qmail-1.03-orig/rrforward.1 qmail-1.03/rrforward.1
--- qmail-1.03-orig/rrforward.1	Thu Jan  1 01:00:00 1970
+++ qmail-1.03/rrforward.1	Fri Apr 27 10:38:02 2001
@@ -0,0 +1,42 @@
+.TH rrforward 1
+.SH NAME
+rrforward \- round-robin message delivery
+.SH SYNOPSIS
+in
+.BR .qmail :
+.B |rrforward
+.I .qmailrr[-extension]
+.I address ...
+.SH DESCRIPTION
+.B rrforward
+forwards each message to one address choosed from specified list of addresses.
+When local address extension part match
+.IR extension ,
+it read a sequence number from the
+.I .qmailrr-extension
+file.
+Then
+.B rrforward
+forwards message to the next
+.I address
+in sequence and update the sequence number in
+.I .qmailrr-extension
+file.
+If
+.I extension
+is empty, sequence number
+is read from
+.I .qmailrr
+file.
+
+.SH "EXIT CODES"
+0 if local address part does not match
+.IR extension ;
+99 if the delivery is completely successful;
+nonzero if any delivery instruction failed.
+Exit code 111 indicates temporary failure.
+
+.SH "SEE ALSO"
+dot-qmail(5),
+qmail-command(8),
+qmail-queue(8)
diff -u --new-file qmail-1.03-orig/rrforward.c qmail-1.03/rrforward.c
--- qmail-1.03-orig/rrforward.c	Thu Jan  1 01:00:00 1970
+++ qmail-1.03/rrforward.c	Fri Apr 27 10:20:45 2001
@@ -0,0 +1,128 @@
+#include <sys/types.h>
+#include <fcntl.h>
+
+#include "sig.h"
+#include "readwrite.h"
+#include "seek.h"
+#include "exit.h"
+#include "env.h"
+#include "qmail.h"
+#include "strerr.h"
+#include "substdio.h"
+#include "fmt.h"
+
+#define FATAL "rrforward: fatal: "
+
+#define QRR_FILE ".qmailrr"
+
+#define QRR_LEN (sizeof(QRR_FILE)-1)
+#define QRR_SEPARATOR(S) (*((S)+QRR_LEN))
+#define QRR_EXTENSION(S) ((S)+QRR_LEN+1)
+
+void die_nomem() { strerr_die2x(111,FATAL,"out of memory"); }
+
+struct qmail qqt;
+
+int qqtwrite(fd,buf,len) int fd; char *buf; int len;
+{
+  qmail_put(&qqt,buf,len);
+  return len;
+}
+
+char inbuf[SUBSTDIO_INSIZE];
+char outbuf[1];
+substdio ssin = SUBSTDIO_FDBUF(read,0,inbuf,sizeof inbuf);
+substdio ssout = SUBSTDIO_FDBUF(qqtwrite,-1,outbuf,sizeof outbuf);
+
+void rr_forward(rrto,sender,dtline,rrnum)
+char *rrto;
+char *sender;
+char *dtline;
+char *rrnum;
+{
+  char *qqx;
+  char num[FMT_ULONG];
+ 
+  sig_pipeignore();
+  if (qmail_open(&qqt) == -1)
+    strerr_die2sys(111,FATAL,"unable to fork: ");
+  qmail_puts(&qqt,dtline);
+  if (substdio_copy(&ssout,&ssin) != 0)
+    strerr_die2sys(111,FATAL,"unable to read message: ");
+  substdio_flush(&ssout);
+
+  num[fmt_ulong(num,qmail_qp(&qqt))] = 0;
+ 
+  qmail_from(&qqt,sender);
+  qmail_to(&qqt,rrto);
+  qqx = qmail_close(&qqt);
+  if (*qqx) strerr_die2x(*qqx == 'D' ? 100 : 111,FATAL,qqx + 1);
+  strerr_die4x(99,"rrforward: qp ",num," rr ",rrnum);
+}
+
+void main(argc,argv)
+int argc;
+char **argv;
+{
+  char *rrfile;
+  char *extension;
+  char *sender;
+  char *dtline;
+  int rrfd;
+  char strpos[FMT_ULONG + 2];
+  int r;
+  unsigned long pos;
+
+  extension = env_get("EXT");
+  if (!extension)
+    strerr_die2x(100,FATAL,"EXT not set");
+  sender = env_get("NEWSENDER");
+  if (!sender)
+    strerr_die2x(100,FATAL,"NEWSENDER not set");
+  dtline = env_get("DTLINE");
+  if (!dtline)
+    strerr_die2x(100,FATAL,"DTLINE not set");
+
+  if (argc < 4)
+    strerr_die2x(111,FATAL,"too few args (" QRR_FILE "[-ext] rr1@domain rr2@domain ...)");
+  rrfile = argv[1];
+  if (!str_start(rrfile, QRR_FILE))
+    strerr_die3x(111,FATAL, argv[1], " doesn't begin with " QRR_FILE);
+  if (*extension) {
+    if (QRR_SEPARATOR(rrfile) != '-')
+      _exit(0);
+    if (str_diff(extension, QRR_EXTENSION(rrfile)))
+      _exit(0);
+  } else {
+    if (QRR_SEPARATOR(rrfile) != '\0')
+      _exit(0);
+  }
+
+  rrfd = open(rrfile, O_RDWR | O_CREAT, 0600);
+  if (rrfd == -1)
+    strerr_die3sys(111,FATAL,"unable to open rr: ",rrfile);
+  if (lock_ex(rrfd) == -1)
+    strerr_die3sys(111,FATAL,"unable to lock rr: ",rrfile);
+  r = read(rrfd, strpos, FMT_ULONG);
+  if (r < 0)
+    strerr_die3sys(111,FATAL,"unable to read rr: ",rrfile);
+  strpos[r] = '\0';
+  argc-=2;
+  argv+=2;
+  if (!scan_ulong(strpos,&pos))
+    pos=0;
+  else
+    pos++;
+  if (pos>=argc)
+    pos=0;
+  r=fmt_ulong(strpos,pos);
+  strpos[r] = '\n';
+  if (seek_begin(rrfd) == -1)
+    strerr_die3sys(111,FATAL,"unable to rewind rr: ",rrfile);
+  if (write(rrfd, strpos, r+1) != r+1)
+    strerr_die3sys(111,FATAL,"unable to write rr: ",rrfile);
+  lock_un(rrfd);
+  close(rrfd);
+  strpos[r] = '\0';
+  rr_forward(argv[pos],sender,dtline,strpos);
+}


