]> git.ipfire.org Git - thirdparty/mlmmj.git/commitdiff
Add ability to subscribe to 'both' and avoid a deadlock when switching.
authorBen Schmidt <none@none>
Wed, 25 Jan 2012 11:34:57 +0000 (22:34 +1100)
committerBen Schmidt <none@none>
Wed, 25 Jan 2012 11:34:57 +0000 (22:34 +1100)
- 'both' means normal and digest versions simultaneously; information about
  this feature is not included in the default list texts, but a few power users
  find it helpful.
- Only take out locks when actually performing a subscription, not before
  checking whether the address is already subscribed; we only really need it
  when we are actually changing the file, and there is a potential deadlock
  which could occur while waiting for unsubscription to complete as part of a
  switch if the lock is taken earlier.
- Also moved code which sends unsubscription confirmations so that it only runs
  once, after unsubsciption has been completed, not every time the address is
  removed; this is only really important when 'both' is a realistic
  subscription option, but it could avoid other double-sends as well.

ChangeLog
README.listtexts
include/mlmmj.h
include/subscriberfuncs.h
src/listcontrol.c
src/mlmmj-bounce.c
src/mlmmj-process.c
src/mlmmj-sub.c
src/mlmmj-unsub.c
src/subscriberfuncs.c

index 87f37d4e30703afa799ca09a59bdcabe40523dfa..d45b1fcb66d76b6bd9a07416e99596002d17f831 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,4 @@
+ o Add ability to subscribe to both (normal and digest).
  o Fix access logic so subonlypost doesn't override a send access rule.
  o Make +unsubscribe remove the requester from all versions of the list.
  o Make mlmmj-unsub default to removing the requester from all versions of the
index 87006456ef09a4765e034703c81021401bdf8ff4..84f872bf86e5b7d809b9a8de2013e4173eac9d91 100644 (file)
@@ -79,9 +79,9 @@ is given in brackets. Those with asterisks (*) are not yet used.
   sent to a person requesting subscription when they need to wait for
   gatekeeping for permission to join
 
-- deny-sub-disabled-digest (sub-deny-digest)
+- deny-sub-disabled-{digest|both} (sub-deny-digest)
 - deny-sub-disabled-nomail (sub-deny-nomail)
-- deny-sub-subbed-{normal|digest|nomail} (sub-subscribed)
+- deny-sub-subbed-{normal|digest|nomail|both} (sub-subscribed)
 - deny-sub-closed *
 - deny-sub-expired *
 - deny-sub-obstruct *
index c98ccc3f7b13bc95bd74653568100d57d2218e90..4db3339fdfb306580cad61605259752e395b4f4e 100644 (file)
@@ -77,10 +77,11 @@ enum subtype {
        SUB_NOMAIL,
        SUB_FILE, /* For single files (moderator, owner etc.) */
        SUB_ALL, /* For listing or unsubscribing all kinds of subscribers */
+       SUB_BOTH, /* For normal+digest subscription */
        SUB_NONE /* For when an address is not subscribed at all */
 };
 
-char *subtype_strs[6]; /* count matches enum above; defined in subscriberfuncs.c */
+char *subtype_strs[7]; /* count matches enum above; defined in subscriberfuncs.c */
 
 enum subreason {
        SUB_REQUEST,
index 2d442733b84136a927b0fb20a29b2fce568c527b..57f99cca59b9297c7feca772b2836c27e8aaff3e 100644 (file)
@@ -26,6 +26,6 @@
 
 off_t find_subscriber(int fd, const char *address);
 int is_subbed_in(const char *subddirname, const char *address);
-enum subtype is_subbed(const char *listdir, const char *address);
+enum subtype is_subbed(const char *listdir, const char *address, int both);
 
 #endif /* SUBSCRIBERFUNC_H */
index d2b7e7add5215ccfca5e91e099dae321f91ca6ef..58c22c5567ee3a65bb6a10f2a6c1b3bbe4beb16a 100644 (file)
 enum ctrl_e {
        CTRL_SUBSCRIBE_DIGEST,
        CTRL_SUBSCRIBE_NOMAIL,
+       CTRL_SUBSCRIBE_BOTH,
        CTRL_SUBSCRIBE,
        CTRL_CONFSUB_DIGEST,
        CTRL_CONFSUB_NOMAIL,
+       CTRL_CONFSUB_BOTH,
        CTRL_CONFSUB,
        CTRL_UNSUBSCRIBE_DIGEST,
        CTRL_UNSUBSCRIBE_NOMAIL,
@@ -85,9 +87,11 @@ struct ctrl_command {
 static struct ctrl_command ctrl_commands[] = {
        { "subscribe-digest",   0 },
        { "subscribe-nomail",   0 },
+       { "subscribe-both",     0 },
        { "subscribe",          0 },
        { "confsub-digest",     1 },
        { "confsub-nomail",     1 },
+       { "confsub-both",       1 },
        { "confsub",            1 },
        { "unsubscribe-digest", 0 },
        { "unsubscribe-nomail", 0 },
@@ -296,6 +300,55 @@ int listcontrol(struct email_container *fromemails, const char *listdir,
                exit(EXIT_FAILURE);
                break;
 
+       /* listname+subscribe-both@domain.tld */
+       case CTRL_SUBSCRIBE_BOTH:
+               if (closedlist || closedlistsub) {
+                       errno = 0;
+                       log_error(LOG_ARGS, "A subscribe-both request was"
+                               " sent to a closed list. Ignoring mail");
+                       return -1;
+               }
+               if (!strchr(fromemails->emaillist[0], '@')) {
+                       /* Not a valid From: address */
+                       errno = 0;
+                       log_error(LOG_ARGS, "A subscribe-both request was"
+                               " sent with an invalid From: header."
+                               " Ignoring mail");
+                       return -1;
+               }
+               if (statctrl(listdir, "nodigestsub")) {
+                       errno = 0;
+                       log_error(LOG_ARGS, "A subscribe-both request was"
+                               " denied");
+                       txt = open_text(listdir, "deny", "sub", "disabled",
+                                       "both", "sub-deny-digest");
+                       MY_ASSERT(txt);
+                       register_unformatted(txt, "subaddr",
+                                       fromemails->emaillist[0]);
+                       queuefilename = prepstdreply(txt, listdir,
+                                       "$listowner$",
+                                       fromemails->emaillist[0], NULL);
+                       MY_ASSERT(queuefilename);
+                       close_text(txt);
+                       send_help(listdir, queuefilename,
+                                       fromemails->emaillist[0], mlmmjsend);
+                       return -1;
+               }
+               log_oper(listdir, OPLOGFNAME, "mlmmj-sub: request for both"
+                                       " subscription from %s",
+                                       fromemails->emaillist[0]);
+               execlp(mlmmjsub, mlmmjsub,
+                               "-L", listdir,
+                               "-a", fromemails->emaillist[0],
+                               "-b",
+                               "-r", "-c",
+                               (nosubconfirm ? (char *)NULL : "-C"),
+                               (char *)NULL);
+               log_error(LOG_ARGS, "execlp() of '%s' failed",
+                                       mlmmjsub);
+               exit(EXIT_FAILURE);
+               break;
+
        /* listname+subscribe@domain.tld */
        case CTRL_SUBSCRIBE:
                if (closedlist || closedlistsub) {
@@ -382,6 +435,34 @@ int listcontrol(struct email_container *fromemails, const char *listdir,
                exit(EXIT_FAILURE);
                break;
 
+       /* listname+subconf-both-COOKIE@domain.tld */
+       case CTRL_CONFSUB_BOTH:
+               conffilename = concatstr(3, listdir, "/subconf/", param);
+               myfree(param);
+               if((tmpfd = open(conffilename, O_RDONLY)) < 0) {
+                       /* invalid COOKIE */
+                       errno = 0;
+                       log_error(LOG_ARGS, "A subconf-both request was"
+                               " sent with a mismatching cookie."
+                               " Ignoring mail");
+                       return -1;
+               }
+               tmpstr = mygetline(tmpfd);
+               chomp(tmpstr);
+               close(tmpfd);
+               unlink(conffilename);
+               log_oper(listdir, OPLOGFNAME, "mlmmj-sub: %s confirmed"
+                                       " subscription to both", tmpstr);
+               execlp(mlmmjsub, mlmmjsub,
+                               "-L", listdir,
+                               "-a", tmpstr,
+                               "-b",
+                               "-R", "-c", (char *)NULL);
+               log_error(LOG_ARGS, "execlp() of '%s' failed",
+                               mlmmjsub);
+               exit(EXIT_FAILURE);
+               break;
+
        /* listname+subconf-COOKIE@domain.tld */
        case CTRL_CONFSUB:
                conffilename = concatstr(3, listdir, "/subconf/", param);
@@ -763,7 +844,7 @@ permit:
                }
                subonlyget = statctrl(listdir, "subonlyget");
                if(subonlyget) {
-                       if(is_subbed(listdir, fromemails->emaillist[0]) ==
+                       if(is_subbed(listdir, fromemails->emaillist[0], 0) ==
                                        SUB_NONE) {
                                errno = 0;
                                log_error(LOG_ARGS, "A get request was sent"
index 93d1bfee80b76a0ed5589e24da2a250aa82008f6..9f9630a6faa69a15af41c59a71251abee1d3b4b7 100644 (file)
@@ -342,7 +342,7 @@ int main(int argc, char **argv)
        *a = '@';
 
        /* make sure it's a subscribed address */
-       if(is_subbed(listdir, address) == SUB_NONE) {
+       if(is_subbed(listdir, address, 0) == SUB_NONE) {
                log_error(LOG_ARGS, "%s is bouncing but not subscribed?",
                                address);
                if(mailname)
index 12f5bdf2b81e1231bba2cda8a3e90c12458628f4..dd1ccb6e8c9d6bd6d6fa0a7bb71cb8215242d09f 100644 (file)
@@ -984,7 +984,7 @@ int main(int argc, char **argv)
                        myfree(donemailname);
                        exit(EXIT_SUCCESS);
                }
-               if(is_subbed(listdir, posteraddr) == SUB_NONE) {
+               if(is_subbed(listdir, posteraddr, 0) == SUB_NONE) {
                        if(statctrl(listdir, "modnonsubposts")) {
                                moderated = 1;
                                modreason = MODNONSUBPOSTS;
index 70965f9ca35a7fa4996f7604c0b2b96773f290ff..3335817c011a2d2183348f8e04d353c45fccbcf6 100644 (file)
@@ -75,6 +75,9 @@ static void moderate_sub(const char *listdir, const char *listaddr,
                case SUB_NOMAIL:
                        str = concatstr(4, subaddr, "\n", "SUB_NOMAIL", "\n");
                        break;
+               case SUB_BOTH:
+                       str = concatstr(4, subaddr, "\n", "SUB_BOTH", "\n");
+                       break;
        }
        
        for (;;) {
@@ -270,6 +273,11 @@ void getaddrandtype(const char *listdir, const char *modstr,
                goto freedone;
        }
 
+       if(strncmp(readtype, "SUB_BOTH", 8) == 0) {
+               *subtypeptr = SUB_BOTH;
+               goto freedone;
+       }
+
        log_error(LOG_ARGS, "Type %s not valid in %s", readtype,
                        modfilename);
 
@@ -305,6 +313,10 @@ void confirm_sub(const char *listdir, const char *listaddr,
                case SUB_NOMAIL:
                        listtext = mystrdup("sub-ok-nomail");
                        break;
+               case SUB_BOTH:
+                       /* No legacy list text as feature didn't exist. */
+                       listtext = mystrdup("sub-ok");
+                       break;
        }
 
        txt = open_text(listdir, "finish", "sub",
@@ -356,6 +368,10 @@ void notify_sub(const char *listdir, const char *listaddr,
                case SUB_NOMAIL:
                        listtext = mystrdup("notifysub-nomail");
                        break;
+               case SUB_BOTH:
+                       /* No legacy list text as feature didn't exist. */
+                       listtext = mystrdup("notifysub");
+                       break;
        }
 
        txt = open_text(listdir, "notify", "sub",
@@ -441,6 +457,11 @@ void generate_subconfirm(const char *listdir, const char *listaddr,
                        listtext = mystrdup("sub-confirm-nomail");
                        tmpstr = mystrdup("confsub-nomail-");
                        break;
+               case SUB_BOTH:
+                       /* No legacy list text as feature didn't exist. */
+                       listtext = mystrdup("sub-confirm");
+                       tmpstr = mystrdup("confsub-both-");
+                       break;
        }
 
        confirmaddr = concatstr(6, listname, listdelim, tmpstr, randomstr, "@",
@@ -537,19 +558,100 @@ void generate_subscribed(const char *listdir, const char *subaddr,
        exit(EXIT_FAILURE);
 }
 
+static void subscribe_type(char *listdir, char *listaddr, char *listdelim,
+               char *address, char *mlmmjsend,
+               enum subtype typesub, enum subreason reasonsub) {
+       char *subfilename = NULL;
+       char chstr[2], *subdir;
+       char *subddirname = NULL, *sublockname;
+       int groupwritable = 0, sublock, sublockfd, lock, subfilefd;
+       struct stat st;
+       size_t len;
+
+       switch(typesub) {
+               default:
+               case SUB_NORMAL:
+                       subdir = "/subscribers.d/";
+                       break;
+               case SUB_DIGEST:
+                       subdir = "/digesters.d/";
+                       break;
+               case SUB_NOMAIL:
+                       subdir = "/nomailsubs.d/";
+                       break;
+       }
+
+       subddirname = concatstr(2, listdir, subdir);
+       if (stat(subddirname, &st) == 0) {
+               if(st.st_mode & S_IWGRP) {
+                       groupwritable = S_IRGRP|S_IWGRP;
+                       umask(S_IWOTH);
+                       setgid(st.st_gid);
+               }
+       }
+
+       chstr[0] = address[0];
+       chstr[1] = '\0';
+       
+       subfilename = concatstr(3, listdir, subdir, chstr);
+
+       sublockname = concatstr(5, listdir, subdir, ".", chstr, ".lock");
+       sublockfd = open(sublockname, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
+       if(sublockfd < 0) {
+               log_error(LOG_ARGS, "Error opening lock file %s",
+                               sublockname);
+               myfree(sublockname);
+               exit(EXIT_FAILURE);
+       }
+
+       sublock = myexcllock(sublockfd);
+       if(sublock < 0) {
+               log_error(LOG_ARGS, "Error locking '%s' file",
+                               sublockname);
+               myfree(sublockname);
+               close(sublockfd);
+               exit(EXIT_FAILURE);
+       }
+
+       subfilefd = open(subfilename, O_RDWR|O_CREAT,
+                               S_IRUSR|S_IWUSR|groupwritable);
+       if(subfilefd == -1) {
+               log_error(LOG_ARGS, "Could not open '%s'", subfilename);
+               myfree(sublockname);
+               exit(EXIT_FAILURE);
+       }
+
+       lock = myexcllock(subfilefd);
+       if(lock) {
+               log_error(LOG_ARGS, "Error locking subscriber file");
+               close(subfilefd);
+               close(sublockfd);
+               myfree(sublockname);
+               exit(EXIT_FAILURE);
+       }
+
+       lseek(subfilefd, 0L, SEEK_END);
+       len = strlen(address);
+       address[len] = '\n';
+       writen(subfilefd, address, len + 1);
+       address[len] = 0;
+       close(subfilefd);
+       close(sublockfd);
+       unlink(sublockname);
+       myfree(sublockname);
+}
+
 int main(int argc, char **argv)
 {
-       char *listaddr, *listdelim, *listdir = NULL, *address = NULL;
-       char *subfilename = NULL, *mlmmjsend, *mlmmjunsub, *bindir;
-       char chstr[2], *subdir;
-       char *subddirname = NULL, *sublockname, *lowcaseaddr;
-       char *modstr = NULL;
-       int subconfirm = 0, confirmsub = 0, opt, subfilefd, lock, notifysub;
-       int changeuid = 1, status, digest = 0, nomail = 0, i = 0, submod = 0;
-       int groupwritable = 0, sublock, sublockfd, nogensubscribed = 0;
-       int force = 0, quiet = 0;
+       char *listaddr, *listdelim, *listdir = NULL;
+       char *mlmmjsend, *mlmmjunsub, *bindir;
+       char *address = NULL, *lowcaseaddr, *modstr = NULL;
+       const char *flag = NULL;
+       int opt, subconfirm = 0, confirmsub = 0, notifysub;
+       int changeuid = 1, status, digest = 0, nomail = 0, both = 0;
+       int nogensubscribed = 0;
+       int force = 0, quiet = 0, i = 0;
        enum subtype subbed;
-       size_t len;
        struct stat st;
        pid_t pid, childpid = 0;
        uid_t uid;
@@ -565,11 +667,14 @@ int main(int argc, char **argv)
        mlmmjunsub = concatstr(2, bindir, "/mlmmj-unsub");
        myfree(bindir);
 
-       while ((opt = getopt(argc, argv, "hcCdfm:nsVUL:a:qrR")) != -1) {
+       while ((opt = getopt(argc, argv, "hbcCdfm:nsVUL:a:qrR")) != -1) {
                switch(opt) {
                case 'a':
                        address = optarg;
                        break;
+               case 'b':
+                       both = 1;
+                       break;
                case 'c':
                        confirmsub = 1;
                        break;
@@ -627,19 +732,8 @@ int main(int argc, char **argv)
                exit(EXIT_FAILURE);
        }
 
-       if(modstr) {
-               getaddrandtype(listdir, modstr, &address, &typesub);
-               reasonsub = SUB_PERMIT;
-       }
-
-       if(strchr(address, '@') == NULL) {
-               log_error(LOG_ARGS, "No '@' sign in '%s', not subscribing",
-                               address);
-               exit(EXIT_SUCCESS);
-       }
-
-       if(digest && nomail) {
-               fprintf(stderr, "Specify at most one of -d and -n\n");
+       if(both + digest + nomail > 1) {
+               fprintf(stderr, "Specify at most one of -b, -d and -n\n");
                fprintf(stderr, "%s -h for help\n", argv[0]);
                exit(EXIT_FAILURE);
        }
@@ -648,6 +742,8 @@ int main(int argc, char **argv)
                typesub = SUB_DIGEST;
        if(nomail)
                typesub = SUB_NOMAIL;
+       if(both)
+               typesub = SUB_BOTH;
 
        if(reasonsub == SUB_CONFIRM && subconfirm) {
                fprintf(stderr, "Cannot specify both -C and -R\n");
@@ -655,6 +751,17 @@ int main(int argc, char **argv)
                exit(EXIT_FAILURE);
        }
 
+       if(modstr) {
+               getaddrandtype(listdir, modstr, &address, &typesub);
+               reasonsub = SUB_PERMIT;
+       }
+
+       if(strchr(address, '@') == NULL) {
+               log_error(LOG_ARGS, "No '@' sign in '%s', not subscribing",
+                               address);
+               exit(EXIT_SUCCESS);
+       }
+
        /* Make the address lowercase */
        lowcaseaddr = mystrdup(address);
        i = 0;
@@ -671,28 +778,6 @@ int main(int argc, char **argv)
                exit(EXIT_SUCCESS);  /* XXX is this success? */
        }
 
-       switch(typesub) {
-               default:
-               case SUB_NORMAL:
-                       subdir = "/subscribers.d/";
-                       break;
-               case SUB_DIGEST:
-                       subdir = "/digesters.d/";
-                       break;
-               case SUB_NOMAIL:
-                       subdir = "/nomailsubs.d/";
-                       break;
-       }
-
-       subddirname = concatstr(2, listdir, subdir);
-       if (stat(subddirname, &st) == 0) {
-               if(st.st_mode & S_IWGRP) {
-                       groupwritable = S_IRGRP|S_IWGRP;
-                       umask(S_IWOTH);
-                       setgid(st.st_gid);
-               }
-       }
-
        if(changeuid) {
                uid = getuid();
                if(!uid && stat(listdir, &st) == 0) {
@@ -706,74 +791,37 @@ int main(int argc, char **argv)
                }
        }
 
-       chstr[0] = address[0];
-       chstr[1] = '\0';
-       
-       subfilename = concatstr(3, listdir, subdir, chstr);
-
-       sublockname = concatstr(5, listdir, subdir, ".", chstr, ".lock");
-       sublockfd = open(sublockname, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
-       if(sublockfd < 0) {
-               log_error(LOG_ARGS, "Error opening lock file %s",
-                               sublockname);
-               myfree(sublockname);
-               exit(EXIT_FAILURE);
-       }
-
-       sublock = myexcllock(sublockfd);
-       if(sublock < 0) {
-               log_error(LOG_ARGS, "Error locking '%s' file",
-                               sublockname);
-               myfree(sublockname);
-               close(sublockfd);
-               exit(EXIT_FAILURE);
-       }
-
-       subfilefd = open(subfilename, O_RDWR|O_CREAT,
-                               S_IRUSR|S_IWUSR|groupwritable);
-       if(subfilefd == -1) {
-               log_error(LOG_ARGS, "Could not open '%s'", subfilename);
-               myfree(sublockname);
-               exit(EXIT_FAILURE);
-       }
+       subbed = is_subbed(listdir, address, 1);
 
-       lock = myexcllock(subfilefd);
-       if(lock) {
-               log_error(LOG_ARGS, "Error locking subscriber file");
-               close(subfilefd);
-               close(sublockfd);
-               myfree(sublockname);
-               exit(EXIT_FAILURE);
-       }
-       subbed = is_subbed(listdir, address);
-       listdelim = getlistdelim(listdir);
-       
        if(subbed == typesub) {
-               close(subfilefd);
-               myfree(subfilename);
-               close(sublockfd);
-               unlink(sublockname);
-               myfree(sublockname);
-
                if(!nogensubscribed)
                        generate_subscribed(listdir, address, mlmmjsend,
                                        typesub);
-               
                return EXIT_SUCCESS;
        } else if(subbed != SUB_NONE) {
                reasonsub = SUB_SWITCH;
-               childpid = fork();
-               if(childpid < 0)
+               /* If we want to subscribe to both, we can just subscribe the
+                * missing version, so don't unsub. */
+               if (!(typesub == SUB_BOTH &&
+                               subbed != SUB_NOMAIL)) {
+                       childpid = fork();
+                       if(childpid < 0) {
                                log_error(LOG_ARGS, "Could not fork; "
                                "not unsubscribed from current version");
-               if (childpid == 0) {
-                       execlp(mlmmjunsub, mlmmjunsub,
-                                       "-L", listdir, "-q",
-                                       "-a", address,
-                                       (char *)NULL);
-                       log_error(LOG_ARGS, "execlp() of '%s' failed",
-                                       mlmmjunsub);
-                       exit(EXIT_FAILURE);
+                       }
+                       if (childpid == 0) {
+                               if (subbed == SUB_BOTH) {
+                                       if (typesub == SUB_NORMAL) flag = "-d";
+                                       if (typesub == SUB_DIGEST) flag = "-N";
+                               }
+                               execlp(mlmmjunsub, mlmmjunsub,
+                                               "-L", listdir, "-q",
+                                               "-a", address, flag,
+                                               (char *)NULL);
+                               log_error(LOG_ARGS, "execlp() of '%s' failed",
+                                               mlmmjunsub);
+                               exit(EXIT_FAILURE);
+                       }
                }
        }
 
@@ -783,38 +831,31 @@ int main(int argc, char **argv)
                while(pid == -1 && errno == EINTR);
        }
 
-       if(subbed == SUB_NONE && subconfirm) {
-               close(subfilefd);
-               close(sublockfd);
-               unlink(sublockname);
-               myfree(sublockname);
-               generate_subconfirm(listdir, listaddr, listdelim,
-                                   address, mlmmjsend, typesub, reasonsub);
-       } else {
-               if(modstr == NULL)
-                               submod = subbed == SUB_NONE && !force &&
-                               statctrl(listdir, "submod");
-               if(submod) {
-                       close(subfilefd);
-                       close(sublockfd);
-                       unlink(sublockname);
-                       myfree(sublockname);
-                       moderate_sub(listdir, listaddr, listdelim,
+       listdelim = getlistdelim(listdir);
+
+       if(subbed == SUB_NONE && subconfirm)
+                       generate_subconfirm(listdir, listaddr, listdelim,
+                       address, mlmmjsend, typesub, reasonsub);
+
+       if(modstr == NULL && subbed == SUB_NONE && !force &&
+                       statctrl(listdir, "submod")) {
+               moderate_sub(listdir, listaddr, listdelim,
                                address, mlmmjsend, typesub, reasonsub);
-               }
-               lseek(subfilefd, 0L, SEEK_END);
-               len = strlen(address);
-               address[len] = '\n';
-               writen(subfilefd, address, len + 1);
-               address[len] = 0;
-               close(subfilefd);
-               close(sublockfd);
-               unlink(sublockname);
        }
 
-       close(sublockfd);
-       unlink(sublockname);
-       myfree(sublockname);
+       if (typesub == SUB_BOTH) {
+               if (subbed != SUB_NORMAL) {
+                       subscribe_type(listdir, listaddr, listdelim, address,
+                                       mlmmjsend, SUB_NORMAL, reasonsub);
+               }
+               if (subbed != SUB_DIGEST) {
+                       subscribe_type(listdir, listaddr, listdelim, address,
+                                       mlmmjsend, SUB_DIGEST, reasonsub);
+               }
+       } else if (!(subbed == SUB_BOTH && typesub != SUB_NOMAIL)) {
+               subscribe_type(listdir, listaddr, listdelim, address,
+                               mlmmjsend, typesub, reasonsub);
+       }
 
        if(confirmsub) {
                childpid = fork();
index a32f5c5938575faac050edc12175e6bcf45b1b24..0fa42a1134b17e977fe2044b8a09045045c31a8f 100644 (file)
@@ -353,19 +353,18 @@ static void generate_notsubscribed(const char *listdir, const char *subaddr,
 }
 
 static void unsubscribe_type(char *listdir, char *listaddr, char *listdelim,
-               char *address, char *mlmmjsend, int confirmunsub,
+               char *address, char *mlmmjsend,
                enum subtype typesub, enum subreason reasonsub) {
        char *subdir, *subddirname, *sublockname;
        char *subreadname = NULL, *subwritename;
        int subread, subwrite, rlock, wlock;
        int sublock, sublockfd;
        int groupwritable = 0;
-       int unsubres, status;
+       int unsubres;
        struct stat st;
        DIR *subddir;
        struct dirent *dp;
        off_t suboff;
-       pid_t pid, childpid;
 
        switch(typesub) {
                default:
@@ -514,34 +513,11 @@ static void unsubscribe_type(char *listdir, char *listaddr, char *listdelim,
                unlink(sublockname);
                myfree(sublockname);
 
-               if(confirmunsub) {
-                       childpid = fork();
-
-                       if(childpid < 0) {
-                               log_error(LOG_ARGS, "Could not fork");
-                               confirm_unsub(listdir, listaddr, listdelim,
-                                               address, mlmmjsend,
-                                               typesub, reasonsub);
-                       }
-
-                       if(childpid > 0) {
-                               do /* Parent waits for the child */
-                                       pid = waitpid(childpid, &status, 0);
-                               while(pid == -1 && errno == EINTR);
-                       }
-
-                       /* child confirms subscription */
-                       if(childpid == 0)
-                               confirm_unsub(listdir, listaddr, listdelim,
-                                               address, mlmmjsend,
-                                               typesub, reasonsub);
-               }
         }
 
        closedir(subddir);
 }
 
-
 int main(int argc, char **argv)
 {
        int opt;
@@ -549,6 +525,7 @@ int main(int argc, char **argv)
        int confirmunsub = 0, unsubconfirm = 0, notifysub = 0;
        int changeuid = 1, quiet = 0;
        int nogennotsubscribed = 0, i = 0;
+       int status;
        char *listaddr, *listdelim, *listdir = NULL, *address = NULL;
        char *mlmmjsend, *bindir, *subdir, *subddirname;
        char *lowcaseaddr;
@@ -556,6 +533,7 @@ int main(int argc, char **argv)
        enum subreason reasonsub = SUB_ADMIN;
        uid_t uid;
        struct stat st;
+       pid_t pid, childpid;
 
        CHECKFULLPATH(argv[0]);
        
@@ -678,7 +656,7 @@ int main(int argc, char **argv)
        }
 
        if (typesub == SUB_ALL) {
-               subbed = is_subbed(listdir, address) != SUB_NONE;
+               subbed = is_subbed(listdir, address, 0) != SUB_NONE;
        } else {
                switch(typesub) {
                        default:
@@ -716,14 +694,37 @@ int main(int argc, char **argv)
 
        if (typesub == SUB_ALL) {
                unsubscribe_type(listdir, listaddr, listdelim, address,
-                               mlmmjsend, confirmunsub, SUB_NORMAL, reasonsub);
+                               mlmmjsend, SUB_NORMAL, reasonsub);
                unsubscribe_type(listdir, listaddr, listdelim, address,
-                               mlmmjsend, confirmunsub, SUB_DIGEST, reasonsub);
+                               mlmmjsend, SUB_DIGEST, reasonsub);
                unsubscribe_type(listdir, listaddr, listdelim, address,
-                               mlmmjsend, confirmunsub, SUB_NOMAIL, reasonsub);
+                               mlmmjsend, SUB_NOMAIL, reasonsub);
        } else {
                unsubscribe_type(listdir, listaddr, listdelim, address,
-                               mlmmjsend, confirmunsub, typesub, reasonsub);
+                               mlmmjsend, typesub, reasonsub);
+       }
+
+       if(confirmunsub) {
+               childpid = fork();
+
+               if(childpid < 0) {
+                       log_error(LOG_ARGS, "Could not fork");
+                       confirm_unsub(listdir, listaddr, listdelim,
+                                       address, mlmmjsend,
+                                       typesub, reasonsub);
+               }
+
+               if(childpid > 0) {
+                       do /* Parent waits for the child */
+                               pid = waitpid(childpid, &status, 0);
+                       while(pid == -1 && errno == EINTR);
+               }
+
+               /* child confirms subscription */
+               if(childpid == 0)
+                       confirm_unsub(listdir, listaddr, listdelim,
+                                       address, mlmmjsend,
+                                       typesub, reasonsub);
        }
 
         notifysub = !quiet && statctrl(listdir, "notifysub");
index 8e9841d42baf4e0db4bcf215afee91afbf479228..88766fec7ac9aea0b678f0e7750bf4719b7fe309 100644 (file)
@@ -46,6 +46,7 @@ char *subtype_strs[] = {
        "nomail",
        "file",
        "all",
+       "both",
        "none"
 };
 
@@ -151,20 +152,27 @@ int is_subbed_in(const char *subddirname, const char *address)
        return retval;
 }
 
-enum subtype is_subbed(const char *listdir, const char *address)
+enum subtype is_subbed(const char *listdir, const char *address, int both)
 {
        int retval;
        char *subddirname;
+       enum subtype typesub = SUB_NONE;
        
        subddirname = concatstr(2, listdir, "/subscribers.d/");
        retval = is_subbed_in(subddirname, address);
        myfree(subddirname);
-       if (retval) return SUB_NORMAL;
+       if (retval) {
+               if (!both) return SUB_NORMAL;
+               typesub = SUB_NORMAL;
+       }
 
        subddirname = concatstr(2, listdir, "/digesters.d/");
        retval = is_subbed_in(subddirname, address);
        myfree(subddirname);
-       if (retval) return SUB_DIGEST;
+       if (retval) {
+               if (typesub == SUB_NORMAL) return SUB_BOTH;
+               return SUB_DIGEST;
+       }
 
        subddirname = concatstr(2, listdir, "/nomailsubs.d/");
        retval = is_subbed_in(subddirname, address);