Hi all,

here is a patch against the 20041101 release that will enhance the bounce
handling of qmail-group dramatically.
In short: until now qmail-group blasted out everything without looking at
$EXT. So mails catched by the catchall account was suddenly sent to the
list instead of being handled in some special way. Now qmail-group will
differ between mails sent to the main address and mails received by the
catchall address.
The qmailGroup objectclass has now a aditional bounceadmin field where one
or multiple rfc822 mailaddresses can be specified who will get bounces
forwarded -- both form subscribed users and moderators. If no bounce admin
is set all mails will bounce back to the sender or on case of a bad
moderator address will be logged and ignored.
Additionally mails to $LOCAL-moderators are automatically forwarded to all
moderators.

This should fix most issues people had with qmail-group.
Please test and report any regression so that we can ship this in the
20041201 release.
-- 
:wq Claudio

Index: qmail-group.c
===================================================================
RCS file: /home/cvs-djbware/CVS/qmail-ldap/qmail-group.c,v
retrieving revision 1.15
diff -u -p -r1.15 qmail-group.c
--- qmail-group.c       11 Jun 2004 12:58:09 -0000      1.15
+++ qmail-group.c       18 Nov 2004 10:50:11 -0000
@@ -66,7 +66,7 @@
 void
 temp_nomem(void)
 {
-       strerr_die2x(111, FATAL, "Out of memory.");
+       strerr_die2x(111, FATAL, "Out of memory. (#4.3.0)");
 }
 void
 temp_qmail(char *fn)
@@ -76,12 +76,12 @@ temp_qmail(char *fn)
 void
 temp_rewind(void)
 {
-       strerr_die2x(111, FATAL, "Unable to rewind message.");
+       strerr_die2x(111, FATAL, "Unable to rewind message. (#4.3.0)");
 }
 void
 temp_read(void)
 {
-       strerr_die2x(111, FATAL, "Unable to read message.");
+       strerr_die2x(111, FATAL, "Unable to read message. (#4.3.0)");
 }
 void
 temp_fork(void)
@@ -95,17 +95,28 @@ void usage(void)
 
 void init(void);
 void bouncefx(void);
-void blast(void);
+void blast(stralloc *, int);
 void reopen(void);
 void trydelete(void);
 void secretary(char *, int);
 void explode(qldap *);
 void subscribed(qldap *, int);
-qldap *ldapgroup(char *, int *, int *, int *, int *);
+qldap *ldapgroup(char *, int *, int *, int *);
 
+char *local;
+char *host;
 char *sender;
+stralloc base = {0};
+stralloc action = {0};
+char *ext;
 char *dname;
 
+stralloc recips = {0};
+stralloc bounceadmin = {0};
+stralloc moderators = {0};
+unsigned int nummoderators;
+
+
 int
 main(int argc, char **argv)
 {
@@ -122,21 +133,43 @@ main(int argc, char **argv)
        bouncefx();
        
        flagc = flags = flagS = flagm = 0;
-       qlc = ldapgroup(dname, &flagc, &flags, &flagS, &flagm);
-       /* need to distinguish between new messages and responses */
+       qlc = ldapgroup(dname, &flagc, &flags, &flagS);
 
-       if (flagc)
-               secretary(maildir, 0);
-       if (flags)
-               subscribed(qlc, flagS);
-       if (flagm)
-               secretary(maildir, 1);
+       /* need to distinguish between new messages and responses */
+       if (action.s) {
+               if (!case_diffs(action.s, "confirm") ||
+                   !case_diffs(action.s, "approve") ||
+                   !case_diffs(action.s, "reject"))
+                       secretary(maildir, flagc);
+               else if (moderators.s && moderators.len &&
+                   !case_diffs(action.s, "moderators") && !(ext && *ext)) {
+                       /* mail to moderators */
+                       blast(&moderators, 0);
+               } else if (!case_diffs(action.s, "return") && ext && *ext) {
+                       /* bounce form subscribed user */
+                       blast(&bounceadmin, 0);
+               } else if (!case_diffs(action.s, "bounce") && ext && *ext) {
+                       /* bounce from moderator */
+                       if (bounceadmin.s && bounceadmin.len)
+                               blast(&bounceadmin, 0);
+                       secretary(maildir, flagc);
+               } else
+                       /* bad address */
+                       strerr_die2x(100, FATAL, "Sorry, no mailbox here "
+                           "by that name. (#5.1.1)");
+       } else {
+               if (flags)
+                       subscribed(qlc, flagS);
+               if (flagc || nummoderators)
+                       secretary(maildir, flagc);
+       }
 
+       reopen();
        explode(qlc);
        qldap_free(qlc);
        
        /* does not return */
-       blast();
+       blast(&recips, 1);
        return 111;
 }
 
@@ -171,10 +204,7 @@ ctrlfunc ctrls[] = {
        0
 };
 
-stralloc base = {0};
 stralloc dtline = {0};
-char *local;
-char *host;
 
 void
 init(void)
@@ -201,8 +231,14 @@ init(void)
                if (!stralloc_copyb(&base, local,
                            str_len(local) - str_len(t) - 1))
                        temp_nomem();
+               ext = t;
+               ext += str_chr(ext, '-');
+               if (!stralloc_copyb(&action, t, ext - t)) temp_nomem();
+               if (!stralloc_0(&action)) temp_nomem();
+               if (*ext) ++ext;
        } else {
                if (!stralloc_copys(&base, local)) temp_nomem();
+               ext = 0;
        }
        if (!stralloc_copys(&dtline, "Delivered-To: ")) temp_nomem();
        if (!stralloc_cat(&dtline, &base)) temp_nomem();
@@ -239,12 +275,11 @@ bouncefx(void)
        }
 }
 
-stralloc recips = {0};
 char strnum1[FMT_ULONG];
 char strnum2[FMT_ULONG];
 
 void
-blast(void)
+blast(stralloc *r, int flagb)
 {
        struct qmail qqt;
        substdio ss;
@@ -254,7 +289,7 @@ blast(void)
        datetime_sec when;
        int match;
 
-       if (recips.s == NULL || recips.len == 0)
+       if (r->s == (char *)0 || r->len == 0)
                strerr_die2x(100, FATAL, "no recipients found in this group.");
 
        if (seek_begin(0) == -1) temp_rewind();
@@ -273,22 +308,18 @@ blast(void)
                qmail_put(&qqt, line.s, line.len);
        } while (match);
 
-#if 0
-       /*
-        * XXX this needs to be fixed. qmail-group should acctualy bounce
-        * messages to -return- to a special bounce admin.
-        */
-       if (!stralloc_copy(&line,&base)) temp_nomem();
-       if (!stralloc_cats(&line,"-return-@")) temp_nomem();
-       if (!stralloc_cats(&line,host)) temp_nomem();
-       if (!stralloc_cats(&line,"[EMAIL PROTECTED]")) temp_nomem();
-       if (!stralloc_0(&line)) temp_nomem();
-       qmail_from(&qqt, line.s);
-#else
-       qmail_from(&qqt, sender);
-#endif
-       for (s = recips.s, smax = recips.s + recips.len; s < smax;
-           s += str_len(s) + 1)
+       if (flagb && bounceadmin.s && bounceadmin.len) {
+               if (!stralloc_copy(&line,&base)) temp_nomem();
+               if (!stralloc_cats(&line,"-return-@")) temp_nomem();
+               if (!stralloc_cats(&line,host)) temp_nomem();
+               if (!stralloc_cats(&line,"[EMAIL PROTECTED]")) temp_nomem();
+               if (!stralloc_0(&line)) temp_nomem();
+               qmail_from(&qqt, line.s);
+       } else
+               /* if no bounce admin specified forward with sender address */
+               qmail_from(&qqt, sender);
+
+       for (s = r->s, smax = r->s + r->len; s < smax; s += str_len(s) + 1)
                qmail_to(&qqt,s);
        qqx = qmail_close(&qqt);
        if (*qqx)
@@ -309,6 +340,8 @@ reopen(void)
 {
        int fd;
 
+       if (!(fname.s && fname.len > 1))
+               return;
        if (!stralloc_0(&fname)) temp_nomem();
        fd = open_read(fname.s);
        if (fd == -1)
@@ -325,11 +358,8 @@ trydelete(void)
                unlink(fname.s);
 }
 
-unsigned int nummoderators;
-stralloc moderators = {0};
-
 void
-secretary(char *maildir, int flagmoderate)
+secretary(char *maildir, int flagcheck)
 {
        const char **args;
        char *s, *smax;
@@ -342,25 +372,22 @@ secretary(char *maildir, int flagmoderat
 
        if (seek_begin(0) == -1) temp_rewind();
 
-       numargs = 4;
-       if (flagmoderate == 1)
-               numargs += 2 * nummoderators;
+       numargs = 4 + 2 * nummoderators;
        
        args = (const char **) alloc(numargs * sizeof(char *));
        if (!args) temp_nomem();
        i = 0;
        args[i++] = "qmail-secretary";
-       if (flagmoderate == 0)
+       if (flagcheck == 1)
                args[i++] = "-Zc";
-       else {
+       else 
                args[i++] = "-ZC";
-               for (s = moderators.s, smax = moderators.s + moderators.len;
-                   s < smax; s += str_len(s) + 1) {
-                       args[i++] = "-m";
-                       args[i++] = s;
-                       if (i + 2 > numargs)
-                              strerr_die2x(111, FATAL, "internal error.");     
-               }
+       for (s = moderators.s, smax = moderators.s + moderators.len;
+           s < smax; s += str_len(s) + 1) {
+               args[i++] = "-m";
+               args[i++] = s;
+               if (i + 2 > numargs)
+                      strerr_die2x(111, FATAL, "internal error.");     
        }
        args[i++] = maildir;
        args[i++] = 0;
@@ -413,7 +440,6 @@ secretary(char *maildir, int flagmoderat
                        if (!stralloc_append(&fname, &sbuf[i])) temp_nomem();
                }
                close(pi[0]);
-               reopen();
                return;
        default: _exit(111);
        }
@@ -424,7 +450,7 @@ secretary(char *maildir, int flagmoderat
 stralloc ldapval = {0};
 stralloc tmpval = {0};
 
-static int getmoderators(qldap *);
+static void getmoderators(qldap *);
 static int unescape(char *, stralloc *, unsigned int *);
 static void extract_addrs822(qldap *, const char *, stralloc *, unsigned int 
*);
 static void extract_addrsdn(qldap *, qldap *, const char *, stralloc *,
@@ -433,13 +459,13 @@ static void extract_addrsfilter(qldap *,
     unsigned int *);
 static int getentry(qldap *, char *);
 
-static int
+static void
 getmoderators(qldap *q)
 {
        qldap *sq;
        int r;
        
-       nummoderators = 0; sq = 0;
+       nummoderators = 0; sq = (qldap *)0;
        if (!stralloc_copys(&moderators, "")) { r = ERRNO; goto fail; }
 
        extract_addrs822(q, LDAP_GROUPMODERAT822,
@@ -458,7 +484,7 @@ getmoderators(qldap *q)
            &moderators, &nummoderators);
        
        qldap_free(sq);
-       return nummoderators > 0;
+       return;
        
 fail:
        if (sq) qldap_free(sq);
@@ -466,7 +492,6 @@ fail:
        strerr_die3x(111, FATAL, "expand group: moderators: ",
            qldap_err_str(r));
        /* NOTREACHED */
-       return 0;
 }
 
 void
@@ -578,7 +603,7 @@ subscribed(qldap *q, int flagS)
 
        for (s = tmpval.s, smax = tmpval.s + tmpval.len;
            s < smax; s += str_len(s) + 1) {
-               r = qldap_filter(sq, founddn.s, attrs, founddn.s, SCOPE_BASE);
+               r = qldap_filter(sq, s, attrs, founddn.s, SCOPE_BASE);
                if (r == NOSUCH) continue;
                if (r != OK) goto fail;
                if (qldap_count(sq) < 1) continue;
@@ -600,7 +625,7 @@ fail:
 
 
 qldap *
-ldapgroup(char *dn, int *flagc, int *flags, int *flagS, int *flagm)
+ldapgroup(char *dn, int *flagc, int *flags, int *flagS)
 {
        qldap *q;
        const char *attrs[] = {
@@ -616,6 +641,7 @@ ldapgroup(char *dn, int *flagc, int *fla
                LDAP_GROUPSENDERDN,
                LDAP_GROUPSENDER822,
                LDAP_GROUPSENDERFILTER,
+               LDAP_GROUPBOUNCEADMIN,
                0 };
        int r;
                
@@ -680,7 +706,20 @@ ldapgroup(char *dn, int *flagc, int *fla
                goto fail;
        }
 
-       *flagm = getmoderators(q);
+       r = qldap_get_attr(q, LDAP_GROUPBOUNCEADMIN, &ldapval, MULTI_VALUE);
+       switch (r) {
+       case OK:
+               r = unescape(ldapval.s, &bounceadmin, 0);
+               if (r != OK) goto fail;
+               break;
+       case NOSUCH:
+               break;
+       default:
+               goto fail;
+       }
+
+
+       getmoderators(q);
        
        if (*flags) {
                r = qldap_get_attr(q, LDAP_GROUPSENDERDN,
Index: qmail-ldap.h
===================================================================
RCS file: /home/cvs-djbware/CVS/qmail-ldap/qmail-ldap.h,v
retrieving revision 1.32
diff -u -p -r1.32 qmail-ldap.h
--- qmail-ldap.h        16 Apr 2004 13:24:19 -0000      1.32
+++ qmail-ldap.h        18 Nov 2004 10:50:20 -0000
@@ -153,6 +153,7 @@
 #define LDAP_GROUPSENDERDN     "dnsender"
 #define LDAP_GROUPSENDER822    "rfc822sender"
 #define LDAP_GROUPSENDERFILTER "filtersender"
+#define LDAP_GROUPBOUNCEADMIN  "bounceadmin"
 
 
 /*********************************************************************
Index: qmail.schema
===================================================================
RCS file: /home/cvs-djbware/CVS/qmail-ldap/qmail.schema,v
retrieving revision 1.18
diff -u -p -r1.18 qmail.schema
--- qmail.schema        30 Jan 2004 17:44:29 -0000      1.18
+++ qmail.schema        18 Nov 2004 10:50:20 -0000
@@ -178,6 +178,12 @@ attributetype ( 1.3.6.1.4.1.7914.1.3.1.1
        SUBSTR caseIgnoreIA5SubstringsMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{512} )
 
+attributetype ( 1.3.6.1.4.1.7914.1.3.1.13 NAME 'bounceadmin'
+       DESC 'rfc822 email address where bounces should be sent to.'
+       EQUALITY caseIgnoreIA5Match
+       SUBSTR caseIgnoreIA5SubstringsMatch
+       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256} )
+
 
 #
 # qldapAdmin Attributes
@@ -259,7 +265,8 @@ objectclass ( 1.3.6.1.4.1.7914.1.3.2.1 N
        MUST ( mail $ mailAlternateAddress $ mailMessageStore )
        MAY ( dnmember $ rfc822member $ filtermember $ senderconfirm $
              membersonly $ confirmtext $ dnmoderator $ rfc822moderator $
-             moderatortext $ dnsender $ rfc822sender $ filtersender) )
+             moderatortext $ dnsender $ rfc822sender $ filtersender $
+             bounceadmin) )
 
 objectclass ( 1.3.6.1.4.1.7914.1.4.2.1 NAME 'qldapAdmin'
        DESC 'QMail-LDAP Subtree Admin'

Reply via email to