#!/bin/bash ######################################################################## # # NAME # gen-combined-list - create a mailman list with members from other lists # # SYNOPSIS # gen-combined-list [--match pattern] [--except pattern] combined_list # # DESCRIPTION # This script updates the mailman list combined_list to contain all # the members present in all the other lists on the server. It # ignores members set to nomail and preserves regular vs. digest # subscriptions. Have cron run this script hourly and the combined # member list will be updated automatically every hour. # # OPTIONS # --match pattern # Only look for members in lists with names matching the pattern. # --except pattern # Ignore looking for members from lists with names matching the # pattern. # # EXAMPLE # Update the membership of a list called psas-all, based on all lists # that have a name starting with psas- except for the psas-announce # list: # # gen-combined-list --match "^psas-" --except "^psas-announce$" psas-all # # CAVEATS # Most member options are not preserved, including digest type, password # and the like. # # Tested only on Mailman version 2.1.2. # # AUTHOR # James T Perkins, james@loowit.net, 09 Oct 2003 # Originally inspired by an example script on www.list.org, contributed # by Mark Merlins, Jon Carnes, and Shane Beasley # ######################################################################## MAILMAN=/var/lib/mailman # location of mailman LIST_PAT= # original list names match this pattern EXCEPT_PAT= # except this pattern COMBINED_LIST= # combined membership output list name # temporary files TMP_LOC=${TMPDIR:-/tmp}/list$$ # directory for all temp files LISTS_ORIG=$TMP_LOC/lists # lists from which output is created LISTS_TMP=$TMP_LOC/lists_tmp # lists from which output is created REGULAR_MEMBERS=$TMP_LOC/plain # sorted/unduped plain list recipients DIGEST_MEMBERS=$TMP_LOC/digest # sorted/unduped digest list recipients # set up execution PATH PATH=$MAILMAN/bin:/bin:/usr/bin # print out script usage message usage() { echo "usage: gen-combined-list [--match=pattern] [--except=pattern] combined_list" >&2 exit 1 } # parse options while [ $# -gt 0 ]; do case $1 in --match=*) LIST_PAT="$(expr substr "$1" 9 999)" ;; --except=*) EXCEPT_PAT="$(expr substr "$1" 10 999)" ;; -*) usage ;; *) if [ -n "$COMBINED_LIST" ]; then usage fi COMBINED_LIST="$1" ;; esac shift done if [ -z "$COMBINED_LIST" ]; then usage fi # clean up temp files on exit: normal, hangup, interrupt and terminate trap 'status=$?; rm -rf $TMP_LOC; exit $status' 0 1 2 15 # create temp dir mkdir $TMP_LOC || exit 1 # validate that the combined_list exists list_lists --bare | grep "^$COMBINED_LIST$" > $LISTS_TMP if [ ! -s $LISTS_TMP ]; then echo "gen-combined-list: combined list $COMBINED_LIST does not exist" >&2 exit 1 fi # find all input lists list_lists --bare | grep -v "^$COMBINED_LIST$" > $LISTS_ORIG if [ -n "$LIST_PAT" ]; then grep "$LIST_PAT" $LISTS_ORIG > $LISTS_TMP mv $LISTS_TMP $LISTS_ORIG fi if [ -n "$EXCEPT_PAT" ]; then grep -v "$EXCEPT_PAT" $LISTS_ORIG > $LISTS_TMP mv $LISTS_TMP $LISTS_ORIG fi if [ ! -s $LISTS_ORIG ]; then echo "gen-combined-list: found no input lists" >&2 exit 1 fi # create list of plain members getting mail, sort & remove duplicates while read list; do list_members --regular --nomail=enabled $list done < $LISTS_ORIG | sort -u > $REGULAR_MEMBERS # create list of digest members getting mail, sort & remove duplicates while read list; do list_members --digest --nomail=enabled $list done < $LISTS_ORIG | sort -u > $DIGEST_MEMBERS # note: "sync_members" will sort and remove dups, but its nice to do anyway # put all members into the combined list. sync_members sets the plain # subscribers, and add_members appends the digest members. # ignore stdout because we don't need a who-was-subscribed report sync_members --welcome-msg=no --goodbye-msg=no --notifyadmin=no \ -f $REGULAR_MEMBERS $COMBINED_LIST >/dev/null add_members --welcome-msg=no --admin-notify=no \ --digest-members-file=$DIGEST_MEMBERS $COMBINED_LIST >/dev/null # all done, trap will clean up temp files exit 0