- Make +unsubscribe remove the requester from all versions of the list.
- Make mlmmj-unsub default to removing the requester from all versions of the
list.
- Make mlmmj-sub and +subscribe[-digest|-nomail] switch existing subscriptions.
- Add a switch to bypass notifying the owner on subscribe/unsubscribe.
- Make type available in finish list texts.
+ 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
+ list.
+ o Make mlmmj-sub and +subscribe[-digest|-nomail] switch existing
+ subscriptions.
+ o Add a switch to bypass notifying the owner on subscribe/unsubscribe.
o Introduce \<space> to indicate line-break positions to enable sensible
wrapping of Chinese and similar text.
o Allow lines to be longer than the wrapping width if there are no spaces,
- deny-sub-disabled-digest (sub-deny-digest)
- deny-sub-disabled-nomail (sub-deny-nomail)
-- deny-sub-subbed (sub-subscribed)
+- deny-sub-subbed-{normal|digest|nomail} (sub-subscribed)
- deny-sub-closed *
- deny-sub-expired *
- deny-sub-obstruct *
-- deny-unsub-unsubbed (unsub-notsubscribed)
+- deny-unsub-unsubbed-{normal|digest|nomail|all} (unsub-notsubscribed)
- deny-post-subonlypost (subonlypost)
- deny-post-access (access)
- deny-post-maxmailsize (maxmailsize)
if the rejection fails; but deny-post-reject will go to the person requesting
the post if the rejection succeeds, causing the post to fail)
-- finish-sub-{request|confirm|admin|permit}-normal (sub-ok)
-- finish-sub-{request|confirm|admin|permit}-digest (sub-ok-digest)
-- finish-sub-{request|confirm|admin|permit}-nomail (sub-ok-nomail)
+- finish-sub-{request|confirm|admin|permit|switch}-normal (sub-ok)
+- finish-sub-{request|confirm|admin|permit|switch}-digest (sub-ok-digest)
+- finish-sub-{request|confirm|admin|permit|switch}-nomail (sub-ok-nomail)
- finish-unsub-{request|confirm|admin}-normal (unsub-ok)
- finish-unsub-{request|confirm|admin}-digest (unsub-ok-digest)
- finish-unsub-{request|confirm|admin}-nomail (unsub-ok-nomail)
SUB_DIGEST,
SUB_NOMAIL,
SUB_FILE, /* For single files (moderator, owner etc.) */
- SUB_ALL /* For listing all kinds of subscribers */
+ SUB_ALL, /* For listing or unsubscribing all kinds of subscribers */
+ SUB_NONE /* For when an address is not subscribed at all */
};
-char *subtype_strs[5]; /* count matches enum above; defined in mlmmj-sub.c */
+char *subtype_strs[6]; /* count matches enum above; defined in mlmmj-sub.c */
enum subreason {
SUB_REQUEST,
SUB_CONFIRM,
SUB_PERMIT,
SUB_ADMIN,
- SUB_BOUNCING
+ SUB_BOUNCING,
+ SUB_SWITCH
};
-char * subreason_strs[5]; /* count matches enum above; defined in mlmmj-sub.c */
+char * subreason_strs[6]; /* count matches enum above; defined in mlmmj-sub.c */
void print_version(const char *prg);
off_t find_subscriber(int fd, const char *address);
int is_subbed_in(const char *subddirname, const char *address);
-int is_subbed(const char *listdir, const char *address);
+enum subtype is_subbed(const char *listdir, const char *address);
#endif /* SUBSCRIBERFUNC_H */
.SH SYNOPSIS
.B mlmmj-sub
\fI\-L /path/to/list\fR [\fI\-a john@doe.org\fR | \fI\-m str\fR]
-[\fI\-c\fR | \fI\-C\fR] [\fI\-d\fR | \fI\-n\fR] [\fI\-f\fR] [\fI\-h\fR] \fR[\fI\-r\fR | \fI\-R\fR] [\fI\-s\fR] [\fI\-U\fR] [\fI\-V\fR]
+[\fI\-c\fR] [\fI\-C\fR] [\fI\-d\fR | \fI\-n\fR] [\fI\-f\fR] [\fI\-h\fR] [\fI\-q\fR] \fR[\fI\-r\fR | \fI\-R\fR] [\fI\-s\fR] [\fI\-U\fR] [\fI\-V\fR]
.HP
\fB\-a\fR: Email address to subscribe
.HP
-\fB\-c\fR: Send welcome mail
+\fB\-c\fR: Send welcome mail (unless requesting confirmation)
.HP
-\fB\-C\fR: Request mail confirmation
+\fB\-C\fR: Request mail confirmation (unless switching versions)
.HP
\fB\-d\fR: Subscribe to digest version of the list
.HP
.HP
\fB\-n\fR: Subscribe to nomail version of the list
.HP
+\fB\-q\fR: Be quiet (don't notify owner about the subscription)
+.HP
\fB\-r\fR: Behave as if request arrived via email (internal use)
.HP
\fB\-R\fR: Behave as if confirmation arrived via email (internal use)
write the email address in a file with the name of the beginning letter of the
email address getting subscribed in the <listdir>/subscribers.d/ directory.
-Unless the \fB\-U\fR switch is used it will switch its user id to the user id
-owning the list directory. This is done to make sure that new files created are
-having correct permissions.
+The digest version of the list is a list version where people receive postings
+to the list periodically (e.g. once a day) or when a large number of posts have
+accumulated. Digest subscribers are in the <listdir>/digesters.d/ directory.
The nomail version of the list is a list version where people are subscribed
like usual, but they won't receive any postings to the list. This is useful for
people who read the mailinglist through a news gateway, but want to be able to
-post to the list.
+post to the list. Nomail subscribers are in the <listdir>/nomailsubs.d/
+directory.
+
+Unless the \fB\-U\fR switch is used it will switch its user id to the user id
+owning the list directory. This is done to make sure that new files created are
+having correct permissions.
-Normally a mail is sent to the subscriber if the address is already subscribed
-to the list. If the \fB\-s\fR switch is used such a mail will not be sent.
+If the given address is already subscribed to the list, but to a different
+version, the subscription is switched to that version, and confirmation and
+moderation are bypassed. If the address is already subscribed to the version
+requested, a mail is sent to the subscriber, unless the \fB\-s\fR switch is
+used.
Subscription may be moderated (if <listdir>/control/submod exists) unless the
-\fB\-f\fR switch is given.
+\fB\-f\fR switch is given. When a subscription is permitted by a gatekeeper,
+welcome messages are sent to the subscriber as usual, regardless of options
+given now.
-To ensure a silent subscription, use \fB\-f\fR, but neither \fB\-c\fR
-nor \fB\-C\fR.
+To ensure subscription is silent from the point of view of the subscriber, use
+\fB\-f\fR, but neither \fB\-c\fR nor \fB\-C\fR. To inhibit notification of the
+owner, use \fB\-q\fR. Use of \fB\-s\fR is recommended to ensure you don't spam
+already-subscribed addresses by accident.
.SH "SEE ALSO"
mlmmj-unsub(1), setuid(2)
.SH AUTHORS
.SH SYNOPSIS
.B mlmmj-unsub
\fI\-L /path/to/list \-a john@doe.org\fR [\fI\-b\fR] [\fI\-c\fR | \fI\-C\fR]
-[\fI\-d\fR | \fI\-n\fR] [\fI\-h\fR] [\fI\-r\fR | \fI\-R\fR] [\fI\-s\fR] [\fI\-U\fR] [\fI\-V\fR]
+[\fI\-d\fR | \fI\-n\fR | \fI\-N\fR] [\fI\-h\fR] [\fI\-q\fR] [\fI\-r\fR | \fI\-R\fR] [\fI\-s\fR] [\fI\-U\fR] [\fI\-V\fR]
.HP
\fB\-a\fR: Email address to unsubscribe
.HP
.HP
\fB\-n\fR: Unsubscribe from the nomail version of the list
.HP
+\fB\-N\fR: Unsubscribe from the normal version of the list
+.HP
+\fB\-q\fR: Be quiet (don't notify owner about the unsubscribe)
+.HP
\fB\-r\fR: Behave as if request arrived via email (internal use)
.HP
\fB\-R\fR: Behave as if confirmation arrived via email (internal use)
.SH DESCRIPTION
This utility is used to unsubscribe people from the specified mailinglist. It
will remove the specified email address from every file in the
-<listdir>/subscribers.d/ directory.
+<listdir>/subscribers.d/, <listdir>/digesters.d/ and <listdir>/nomailsubs.d/
+directories (or if the \-d, \-n or \-N switch is given, only the one relevant
+directory).
Unless the \fB\-U\fR switch is used it will switch its user id to the user id
owning the list directory. This is done to make sure that new files created are
subscribed to the list. If the \fB\-s\fR switch is used such a mail will not be
sent.
-When neither \fB\-c\fR nor \fB\-C\fR are specified, unsubscription silently
-happens.
+When neither \fB\-c\fR nor \fB\-C\fR is specified, unsubscription happens
+silently from the point of view of the subscriber. When \fB\-q\fR is specified,
+unsubscription happens silently from the point of view of the list owner. Use
+of \fB\-s\fR is recommended to ensure you don't spam unsubscribed addresses by
+accident.
.SH "SEE ALSO"
mlmmj-sub(1)
.SH AUTHORS
char *omitfilename;
char *omit = NULL;
char *c, *archivefilename, *sendfilename;
- const char *subswitch;
struct stat stbuf;
int closedlist, nosubconfirm, tmpfd, noget, i, closedlistsub,
subonlyget = 0;
closedlistsub = statctrl(listdir, "closedlistsub");
nosubconfirm = statctrl(listdir, "nosubconfirm");
- if(nosubconfirm)
- subswitch = "-c";
- else
- subswitch = "-C";
#if 0
log_error(LOG_ARGS, "controlstr = [%s]\n", controlstr);
"-L", listdir,
"-a", fromemails->emaillist[0],
"-d",
- "-r", subswitch, (char *)NULL);
+ "-r", "-c",
+ (nosubconfirm ? (char *)NULL : "-C"),
+ (char *)NULL);
log_error(LOG_ARGS, "execlp() of '%s' failed",
mlmmjsub);
exit(EXIT_FAILURE);
"-L", listdir,
"-a", fromemails->emaillist[0],
"-n",
- "-r", subswitch, (char *)NULL);
+ "-r", "-c",
+ (nosubconfirm ? (char *)NULL : "-C"),
+ (char *)NULL);
log_error(LOG_ARGS, "execlp() of '%s' failed",
mlmmjsub);
exit(EXIT_FAILURE);
execlp(mlmmjsub, mlmmjsub,
"-L", listdir,
"-a", fromemails->emaillist[0],
- "-r", subswitch, (char *)NULL);
+ "-r", "-c",
+ (nosubconfirm ? (char *)NULL : "-C"),
+ (char *)NULL);
log_error(LOG_ARGS, "execlp() of '%s' failed",
mlmmjsub);
exit(EXIT_FAILURE);
exit(EXIT_FAILURE);
break;
- /* listname+unsubscribe-digest@domain.tld */
+ /* DEPRECATED: listname+unsubscribe-digest@domain.tld */
case CTRL_UNSUBSCRIBE_DIGEST:
- if (closedlist) {
- errno = 0;
- log_error(LOG_ARGS, "An unsubscribe-digest 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, "An unsubscribe-digest request was"
- " sent with an invalid From: header."
- " Ignoring mail");
- return -1;
- }
- log_oper(listdir, OPLOGFNAME, "mlmmj-unsub: %s requests"
- " unsubscribe from digest",
- fromemails->emaillist[0]);
- execlp(mlmmjunsub, mlmmjunsub,
- "-L", listdir,
- "-a", fromemails->emaillist[0],
- "-d",
- "-r", subswitch, (char *)NULL);
- log_error(LOG_ARGS, "execlp() of '%s' failed",
- mlmmjunsub);
- exit(EXIT_FAILURE);
- break;
-
- /* listname+unsubscribe-nomail@domain.tld */
+ /* DEPRECATED: listname+unsubscribe-nomail@domain.tld */
case CTRL_UNSUBSCRIBE_NOMAIL:
- if (closedlist) {
- errno = 0;
- log_error(LOG_ARGS, "An unsubscribe-nomail 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, "An unsubscribe-nomail request was"
- " sent with an invalid From: header."
- " Ignoring mail");
- return -1;
- }
- log_oper(listdir, OPLOGFNAME, "mlmmj-unsub: %s requests"
- " unsubscribe from nomail",
- fromemails->emaillist[0]);
- execlp(mlmmjunsub, mlmmjunsub,
- "-L", listdir,
- "-a", fromemails->emaillist[0],
- "-n",
- "-r", subswitch, (char *)NULL);
- log_error(LOG_ARGS, "execlp() of '%s' failed",
- mlmmjunsub);
- exit(EXIT_FAILURE);
- break;
-
/* listname+unsubscribe@domain.tld */
case CTRL_UNSUBSCRIBE:
if (closedlist) {
return -1;
}
log_oper(listdir, OPLOGFNAME, "mlmmj-unsub: %s requests"
- " unsubscribe from regular list",
+ " unsubscribe",
fromemails->emaillist[0]);
execlp(mlmmjunsub, mlmmjunsub,
"-L", listdir,
"-a", fromemails->emaillist[0],
- "-r", subswitch, (char *)NULL);
+ "-r", (nosubconfirm ? "-c" : "-C"),
+ (char *)NULL);
log_error(LOG_ARGS, "execlp() of '%s' failed",
mlmmjunsub);
exit(EXIT_FAILURE);
}
subonlyget = statctrl(listdir, "subonlyget");
if(subonlyget) {
- if(is_subbed(listdir, fromemails->emaillist[0]) != 0) {
+ if(is_subbed(listdir, fromemails->emaillist[0]) ==
+ SUB_NONE) {
errno = 0;
log_error(LOG_ARGS, "A get request was sent"
" from a non-subscribed address to a"
*a = '@';
/* make sure it's a subscribed address */
- if(is_subbed(listdir, address)) {
+ if(is_subbed(listdir, address) == SUB_NONE) {
log_error(LOG_ARGS, "%s is bouncing but not subscribed?",
address);
if(mailname)
myfree(donemailname);
exit(EXIT_SUCCESS);
}
- if(is_subbed(listdir, posteraddr) != 0) {
+ if(is_subbed(listdir, posteraddr) == SUB_NONE) {
modnonsubposts = statctrl(listdir,
"modnonsubposts");
if(modnonsubposts) {
"digest",
"nomail",
"file",
- "all"
+ "all",
+ "none"
};
char * subreason_strs[] = {
"confirm",
"permit",
"admin",
- "bouncing"
+ "bouncing",
+ "switch"
};
static void moderate_sub(const char *listdir, const char *listaddr,
static void print_help(const char *prg)
{
printf("Usage: %s -L /path/to/list {-a john@doe.org | -m str}\n"
- " [-c | -C] [-f] [-h] [-L] [-d | -n] [-r | -R] [-s] [-U] [-V]\n"
+ " [-c] [-C] [-f] [-h] [-L] [-d | -n] [-q] [-r | -R] [-s] [-U] [-V]\n"
" -a: Email address to subscribe \n"
- " -c: Send welcome mail\n"
- " -C: Request mail confirmation\n"
+ " -c: Send welcome mail (unless requesting confirmation)\n"
+ " -C: Request mail confirmation (unless switching versions)\n"
" -d: Subscribe to digest of list\n"
" -f: Force subscription (do not moderate)\n"
" -h: This help\n"
" -L: Full path to list directory\n"
" -m: moderation string\n"
" -n: Subscribe to no mail version of list\n", prg);
- printf(" -r: Behave as if request arrived via email (internal use)\n"
+ printf(" -q: Be quiet (don't notify owner about the subscription)\n"
+ " -r: Behave as if request arrived via email (internal use)\n"
" -R: Behave as if confirmation arrived via email (internal use)\n"
" -s: Don't send a mail to subscriber if already subscribed\n"
" -U: Don't switch to the user id of the listdir owner\n"
" -V: Print version\n"
- "When no options are specified, subscription may be "
- "moderated;\nto ensure a silent subscription, use -f\n");
+ "To ensure a silent subscription, use -f -q -s\n");
exit(EXIT_SUCCESS);
}
void generate_subscribed(const char *listdir, const char *subaddr,
- const char *mlmmjsend)
+ const char *mlmmjsend, enum subtype typesub)
{
text *txt;
char *queuefilename, *fromaddr, *listname, *listfqdn, *listaddr;
myfree(listdelim);
txt = open_text(listdir,
- "deny", "sub", "subbed", NULL, "sub-subscribed");
+ "deny", "sub", "subbed", subtype_strs[typesub],
+ "sub-subscribed");
MY_ASSERT(txt);
register_unformatted(txt, "subaddr", subaddr);
queuefilename = prepstdreply(txt, listdir,
int main(int argc, char **argv)
{
char *listaddr, *listdelim, *listdir = NULL, *address = NULL;
- char *subfilename = NULL, *mlmmjsend, *bindir, chstr[2], *subdir;
+ 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, subbed;
- int force = 0;
+ int groupwritable = 0, sublock, sublockfd, nogensubscribed = 0;
+ int force = 0, quiet = 0;
+ enum subtype subbed;
size_t len;
struct stat st;
- pid_t pid, childpid;
+ pid_t pid, childpid = 0;
uid_t uid;
enum subtype typesub = SUB_NORMAL;
enum subreason reasonsub = SUB_ADMIN;
bindir = mydirname(argv[0]);
mlmmjsend = concatstr(2, bindir, "/mlmmj-send");
+ mlmmjunsub = concatstr(2, bindir, "/mlmmj-unsub");
myfree(bindir);
- while ((opt = getopt(argc, argv, "hcCdfm:nsVUL:a:rR")) != -1) {
+ while ((opt = getopt(argc, argv, "hcCdfm:nsVUL:a:qrR")) != -1) {
switch(opt) {
case 'a':
address = optarg;
case 'n':
nomail = 1;
break;
+ case 'q':
+ quiet = 1;
+ break;
case 'r':
reasonsub = SUB_REQUEST;
break;
}
if(digest && nomail) {
- fprintf(stderr, "Specify either -d or -n, not both\n");
+ fprintf(stderr, "Specify at most one of -d and -n\n");
fprintf(stderr, "%s -h for help\n", argv[0]);
exit(EXIT_FAILURE);
}
if(nomail)
typesub = SUB_NOMAIL;
- if(confirmsub && subconfirm) {
- fprintf(stderr, "Cannot specify both -C and -c\n");
- fprintf(stderr, "%s -h for help\n", argv[0]);
- exit(EXIT_FAILURE);
- }
-
if(reasonsub == SUB_CONFIRM && subconfirm) {
fprintf(stderr, "Cannot specify both -C and -R\n");
fprintf(stderr, "%s -h for help\n", argv[0]);
myfree(sublockname);
exit(EXIT_FAILURE);
}
- subbed = is_subbed_in(subddirname, address);
+ subbed = is_subbed(listdir, address);
listdelim = getlistdelim(listdir);
- if(subbed) {
- if(subconfirm) {
- close(subfilefd);
- close(sublockfd);
- unlink(sublockname);
- myfree(sublockname);
- generate_subconfirm(listdir, listaddr, listdelim,
- address, mlmmjsend, typesub, reasonsub);
- } else {
- if(modstr == NULL)
- submod = !force && statctrl(listdir, "submod");
- if(submod) {
- close(subfilefd);
- close(sublockfd);
- unlink(sublockname);
- myfree(sublockname);
- 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);
- }
- } else {
+ if(subbed == typesub) {
close(subfilefd);
myfree(subfilename);
close(sublockfd);
myfree(sublockname);
if(!nogensubscribed)
- generate_subscribed(listdir, address, mlmmjsend);
+ generate_subscribed(listdir, address, mlmmjsend,
+ typesub);
return EXIT_SUCCESS;
+ } else if(subbed != SUB_NONE) {
+ reasonsub = SUB_SWITCH;
+ 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) {
+ do /* Parent waits for the child */
+ pid = waitpid(childpid, &status, 0);
+ 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,
+ 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);
mlmmjsend, typesub, reasonsub);
}
- notifysub = statctrl(listdir, "notifysub");
+ notifysub = !quiet && reasonsub != SUB_SWITCH &&
+ statctrl(listdir, "notifysub");
/* Notify list owner about subscription */
if (notifysub)
static void print_help(const char *prg)
{
printf("Usage: %s -L /path/to/list -a john@doe.org\n"
- " [-b] [-c | -C] [-h] [-L] [-d | -n] [-r | -R] [-s] [-V]\n"
+ " [-b] [-c | -C] [-h] [-L] [-d | -n | -N] [-q] [-r | -R] [-s] [-V]\n"
" -a: Email address to unsubscribe \n"
" -b: Behave as if unsubscription is due to bouncing (internal use)\n"
" -c: Send goodbye mail\n"
" -d: Unsubscribe from digest of list\n"
" -h: This help\n"
" -L: Full path to list directory\n"
- " -n: Unsubscribe from no mail version of list\n", prg);
- printf(" -r: Behave as if request arrived via email (internal use)\n"
+ " -n: Unsubscribe from no mail version of list\n"
+ " -N: Unsubscribe from normal version of list\n", prg);
+ printf(" -q: Be quiet (don't notify owner about the subscription)\n"
+ " -r: Behave as if request arrived via email (internal use)\n"
" -R: Behave as if confirmation arrived via email (internal use)\n"
" -s: Don't send a mail to the address if not subscribed\n"
" -U: Don't switch to the user id of the listdir owner\n"
" -V: Print version\n"
- "When no options are specified, unsubscription silently "
- "happens\n");
+ "To ensure a silent unsubscription, use -q -s\n");
exit(EXIT_SUCCESS);
}
-void generate_notsubscribed(const char *listdir, const char *subaddr,
- const char *mlmmjsend)
+static void generate_notsubscribed(const char *listdir, const char *subaddr,
+ const char *mlmmjsend, enum subtype typesub)
{
text *txt;
char *queuefilename, *fromaddr, *listname, *listfqdn, *listaddr;
myfree(listdelim);
txt = open_text(listdir,
- "deny", "unsub", "unsubbed", NULL,
+ "deny", "unsub", "unsubbed", subtype_strs[typesub],
"unsub-notsubscribed");
MY_ASSERT(txt);
register_unformatted(txt, "subaddr", subaddr);
exit(EXIT_FAILURE);
}
-
-int main(int argc, char **argv)
-{
- int subread, subwrite, rlock, wlock, opt, unsubres, status, nomail = 0;
- int confirmunsub = 0, unsubconfirm = 0, notifysub = 0, digest = 0;
- int changeuid = 1, groupwritable = 0, sublock, sublockfd;
- int nogennotsubscribed = 0, i = 0;
- char *listaddr, *listdelim, *listdir = NULL, *address = NULL;
- char *subreadname = NULL, *subwritename, *mlmmjsend, *bindir, *subdir;
- char *subddirname, *sublockname, *lowcaseaddr;
- off_t suboff;
+static void unsubscribe_type(char *listdir, char *listaddr, char *listdelim,
+ char *address, char *mlmmjsend, int confirmunsub,
+ 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;
+ struct stat st;
DIR *subddir;
struct dirent *dp;
+ off_t suboff;
pid_t pid, childpid;
- enum subtype typesub = SUB_NORMAL;
- enum subreason reasonsub = SUB_ADMIN;
- uid_t uid;
- struct stat st;
-
- CHECKFULLPATH(argv[0]);
-
- log_set_name(argv[0]);
-
- bindir = mydirname(argv[0]);
- mlmmjsend = concatstr(2, bindir, "/mlmmj-send");
- myfree(bindir);
-
- while ((opt = getopt(argc, argv, "hcCdnVUL:a:sbrR")) != -1) {
- switch(opt) {
- case 'L':
- listdir = optarg;
- break;
- case 'n':
- nomail = 1;
- break;
- case 'a':
- address = optarg;
- break;
- case 'b':
- reasonsub = SUB_BOUNCING;
- break;
- case 'c':
- confirmunsub = 1;
- break;
- case 'C':
- unsubconfirm = 1;
- break;
- case 'd':
- digest = 1;
- break;
- case 'h':
- print_help(argv[0]);
- break;
- case 'r':
- reasonsub = SUB_REQUEST;
- break;
- case 'R':
- reasonsub = SUB_CONFIRM;
- break;
- case 's':
- nogennotsubscribed = 1;
- break;
- case 'U':
- changeuid = 0;
- break;
- case 'V':
- print_version(argv[0]);
- exit(0);
- }
- }
- if(listdir == 0 || address == 0) {
- fprintf(stderr, "You have to specify -L and -a\n");
- fprintf(stderr, "%s -h for help\n", argv[0]);
- exit(EXIT_FAILURE);
- }
-
- if(digest && nomail) {
- fprintf(stderr, "Specify either -d or -n, not both\n");
- fprintf(stderr, "%s -h for help\n", argv[0]);
- exit(EXIT_FAILURE);
- }
-
- if(digest)
- typesub = SUB_DIGEST;
- if(nomail)
- typesub = SUB_NOMAIL;
-
- if(confirmunsub && unsubconfirm) {
- fprintf(stderr, "Cannot specify both -C and -c\n");
- fprintf(stderr, "%s -h for help\n", argv[0]);
- exit(EXIT_FAILURE);
- }
-
- if(reasonsub == SUB_CONFIRM && unsubconfirm) {
- fprintf(stderr, "Cannot specify both -C and -R\n");
- fprintf(stderr, "%s -h for help\n", argv[0]);
- exit(EXIT_FAILURE);
- }
-
- if(reasonsub == SUB_BOUNCING && unsubconfirm) {
- fprintf(stderr, "Cannot specify both -C and -b\n");
- fprintf(stderr, "%s -h for help\n", argv[0]);
- exit(EXIT_FAILURE);
- }
-
- /* Make the address lowercase */
- lowcaseaddr = mystrdup(address);
- i = 0;
- while(lowcaseaddr[i]) {
- lowcaseaddr[i] = tolower(lowcaseaddr[i]);
- i++;
- }
- address = lowcaseaddr;
-
- /* get the list address */
- listaddr = getlistaddr(listdir);
-
- if(changeuid) {
- uid = getuid();
- if(!uid && stat(listdir, &st) == 0) {
- printf("Changing to uid %d, owner of %s.\n",
- (int)st.st_uid, listdir);
- if(setuid(st.st_uid) < 0) {
- perror("setuid");
- fprintf(stderr, "Continuing as uid %d\n",
- (int)uid);
- }
- }
- }
switch(typesub) {
default:
subdir = "/nomailsubs.d/";
break;
}
-
+
subddirname = concatstr(2, listdir, subdir);
if (stat(subddirname, &st) == 0) {
if(st.st_mode & S_IWGRP) {
}
}
- if(is_subbed_in(subddirname, address)) {
- /* Address is not subscribed */
- myfree(subddirname);
- myfree(listaddr);
-
- if(!nogennotsubscribed) {
- generate_notsubscribed(listdir, address, mlmmjsend);
- }
-
- exit(EXIT_SUCCESS);
- }
-
- listdelim = getlistdelim(listdir);
- if(unsubconfirm)
- generate_unsubconfirm(listdir, listaddr, listdelim, address,
- mlmmjsend, typesub, reasonsub);
-
if((subddir = opendir(subddirname)) == NULL) {
log_error(LOG_ARGS, "Could not opendir(%s)",
subddirname);
myfree(subddirname);
- myfree(listaddr);
- myfree(listdelim);
exit(EXIT_FAILURE);
}
}
closedir(subddir);
+}
+
+
+int main(int argc, char **argv)
+{
+ int opt;
+ int normal = 0, digest = 0, nomail = 0, subbed;
+ int confirmunsub = 0, unsubconfirm = 0, notifysub = 0;
+ int changeuid = 1, quiet = 0;
+ int nogennotsubscribed = 0, i = 0;
+ char *listaddr, *listdelim, *listdir = NULL, *address = NULL;
+ char *mlmmjsend, *bindir, *subdir, *subddirname;
+ char *lowcaseaddr;
+ enum subtype typesub = SUB_ALL;
+ enum subreason reasonsub = SUB_ADMIN;
+ uid_t uid;
+ struct stat st;
+
+ CHECKFULLPATH(argv[0]);
+
+ log_set_name(argv[0]);
+
+ bindir = mydirname(argv[0]);
+ mlmmjsend = concatstr(2, bindir, "/mlmmj-send");
+ myfree(bindir);
+
+ while ((opt = getopt(argc, argv, "hcCdenNVUL:a:sbqrR")) != -1) {
+ switch(opt) {
+ case 'L':
+ listdir = optarg;
+ break;
+ case 'a':
+ address = optarg;
+ break;
+ case 'b':
+ reasonsub = SUB_BOUNCING;
+ break;
+ case 'c':
+ confirmunsub = 1;
+ break;
+ case 'C':
+ unsubconfirm = 1;
+ break;
+ case 'd':
+ digest = 1;
+ break;
+ case 'h':
+ print_help(argv[0]);
+ break;
+ case 'n':
+ nomail = 1;
+ break;
+ case 'N':
+ normal = 1;
+ break;
+ case 'q':
+ quiet = 1;
+ break;
+ case 'r':
+ reasonsub = SUB_REQUEST;
+ break;
+ case 'R':
+ reasonsub = SUB_CONFIRM;
+ break;
+ case 's':
+ nogennotsubscribed = 1;
+ break;
+ case 'U':
+ changeuid = 0;
+ break;
+ case 'V':
+ print_version(argv[0]);
+ exit(0);
+ }
+ }
+ if(listdir == 0 || address == 0) {
+ fprintf(stderr, "You have to specify -L and -a\n");
+ fprintf(stderr, "%s -h for help\n", argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ if(digest + nomail + normal > 1) {
+ fprintf(stderr, "Specify at most one of -d, -n and -N\n");
+ fprintf(stderr, "%s -h for help\n", argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ if(digest)
+ typesub = SUB_DIGEST;
+ if(nomail)
+ typesub = SUB_NOMAIL;
+ if(normal)
+ typesub = SUB_NORMAL;
+
+ if(confirmunsub && unsubconfirm) {
+ fprintf(stderr, "Cannot specify both -C and -c\n");
+ fprintf(stderr, "%s -h for help\n", argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ if(reasonsub == SUB_CONFIRM && unsubconfirm) {
+ fprintf(stderr, "Cannot specify both -C and -R\n");
+ fprintf(stderr, "%s -h for help\n", argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ if(reasonsub == SUB_BOUNCING && unsubconfirm) {
+ fprintf(stderr, "Cannot specify both -C and -b\n");
+ fprintf(stderr, "%s -h for help\n", argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ /* Make the address lowercase */
+ lowcaseaddr = mystrdup(address);
+ i = 0;
+ while(lowcaseaddr[i]) {
+ lowcaseaddr[i] = tolower(lowcaseaddr[i]);
+ i++;
+ }
+ address = lowcaseaddr;
+
+ /* get the list address */
+ listaddr = getlistaddr(listdir);
+ listdelim = getlistdelim(listdir);
+
+ if(changeuid) {
+ uid = getuid();
+ if(!uid && stat(listdir, &st) == 0) {
+ printf("Changing to uid %d, owner of %s.\n",
+ (int)st.st_uid, listdir);
+ if(setuid(st.st_uid) < 0) {
+ perror("setuid");
+ fprintf(stderr, "Continuing as uid %d\n",
+ (int)uid);
+ }
+ }
+ }
+
+ if (typesub == SUB_ALL) {
+ subbed = is_subbed(listdir, address) != SUB_NONE;
+ } else {
+ 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);
+ subbed = is_subbed_in(subddirname, address);
+ myfree(subddirname);
+ }
+
+ if(!subbed) {
+ /* Address is not subscribed */
+ myfree(listaddr);
+ myfree(listdelim);
+
+ if(!nogennotsubscribed) {
+ generate_notsubscribed(listdir, address, mlmmjsend,
+ typesub);
+ }
+
+ exit(EXIT_SUCCESS);
+ }
+
+ if(unsubconfirm)
+ generate_unsubconfirm(listdir, listaddr, listdelim, address,
+ mlmmjsend, typesub, reasonsub);
+
+ if (typesub == SUB_ALL) {
+ unsubscribe_type(listdir, listaddr, listdelim, address,
+ mlmmjsend, confirmunsub, SUB_NORMAL, reasonsub);
+ unsubscribe_type(listdir, listaddr, listdelim, address,
+ mlmmjsend, confirmunsub, SUB_DIGEST, reasonsub);
+ unsubscribe_type(listdir, listaddr, listdelim, address,
+ mlmmjsend, confirmunsub, SUB_NOMAIL, reasonsub);
+ } else {
+ unsubscribe_type(listdir, listaddr, listdelim, address,
+ mlmmjsend, confirmunsub, typesub, reasonsub);
+ }
- notifysub = statctrl(listdir, "notifysub");
+ notifysub = !quiet && statctrl(listdir, "notifysub");
/* Notify list owner about subscription */
if (notifysub)
int is_subbed_in(const char *subddirname, const char *address)
{
- int retval = 1, subread;
+ int retval = 0, subread;
char *subreadname;
off_t suboff;
DIR *subddir;
if(suboff == -1) {
continue;
} else {
- retval = 0;
+ retval = 1;
break;
}
}
return retval;
}
-int is_subbed(const char *listdir, const char *address)
+enum subtype is_subbed(const char *listdir, const char *address)
{
int retval;
char *subddirname;
subddirname = concatstr(2, listdir, "/subscribers.d/");
retval = is_subbed_in(subddirname, address);
myfree(subddirname);
- if (retval == 0)
- return 0;
+ if (retval) return SUB_NORMAL;
subddirname = concatstr(2, listdir, "/digesters.d/");
retval = is_subbed_in(subddirname, address);
myfree(subddirname);
- if (retval == 0)
- return 0;
+ if (retval) return SUB_DIGEST;
subddirname = concatstr(2, listdir, "/nomailsubs.d/");
retval = is_subbed_in(subddirname, address);
myfree(subddirname);
- if (retval == 0)
- return 0;
+ if (retval) return SUB_NOMAIL;
- return 1;
+ return SUB_NONE;
}