[tpop3d-discuss] bulletin support

Chris Lightfoot chris at ex-parrot.com
Tue, 5 Aug 2003 18:55:07 +0100


An off-list correspondent suggested that tpop3d should
have support for `server bulletins'. Personally I think
these are an ugly hack, but it turns out that a minor
change to tpop3d will enable them to be implemented with a
small perl script. The change is an option and support to
enable tpop3d to run an onlogin handler, and wait until it
has completed before opening (and locking) the user
mailbox.

I attach a description of this (from CVS); comments would
be appreciated:


Implementing POP3 server bulletins using tpop3d
$Id: README.bulletins,v 1.1 2003/08/01 12:11:38 chris Exp $

At many large sites it is useful to be able to distribute a `bulletin' message
to all mail users. tpop3d can provide this functionality by having user login
trigger delivery of any outstanding bulletin messages via the onlogin
handler mechanism, as for POP-before-SMTP.

This is new and untested functionality, but the basic idea is that you specify

    onlogin-child-wait: yes

in tpop3d.conf, then write an auth-perl or auth-other onlogin action to handle
bulletin delivery. Here is a sketch of a perl subroutine that could be used
for this:

    # onlogin_bulletins_handler REQUEST
    # Deliver any bulletins which are pending for the authenticated user
    # identified in the REQUEST. This subroutine is called by tpop3d, which
    # will set REQUEST->{local_part} and REQUEST->{domain} to the proper
    # values. Bulletins should be complete RFC822 messages stored in flat
    # text files under /etc/mail/bulletins, each with the extension .msg.
    # This function will use a GDBM database for each bulletin to record the
    # addresses of users to whom it has been delivered, so as to ensure that
    # each user receives only one copy of each bulletin. Bulletins are
    # delivered to user mailboxes using the local mail transport agent, though
    # this behaviour could be changed if required.
    sub onlogin_bulletins_handler ($) {
        my $req = shift;
        my $resp = { };
        
        #
        # Iterate over list of bulletins.
        #
        foreach my $bull (glob("/etc/mail/bulletins/*.msg")) {
            my $recips = $bull;
            
            # Obtain and tie delivery database, creating it if it does not
            # already exist.

            $recips =~ s/msg$/db/;
            my $r = "$req->{local_part}@$req->{domain}";
            my %rr;
            tie(%rr, 'GDBM_File', $recips, &GDBM_WRCREAT, 0600);a

            # Attempt delivery if this user has not already been sent a copy
            # of this message.

            if (!exists($rr{$r})) {

                # Invoke sendmail. There are better ways of doing this, but
                # this is simplest. Note that it wouldn't usually be safe to
                # call sendmail in this way, but tpop3d has already
                # authenticated somebody using the given local-part and
                # domain, so they're presumably safe strings.

                system("sendmail -oi '$r' < $bull");
                if ($? == 0) {

                    # Sendmail exits with code 0 on success.

                    $recips{$r} = 1;
                } else {

                    # Sendmail (or system(3)) failed. There's not a whole lot
                    # we can do here, but we log a message and abort sending
                    # any other bulletins to this user for the moment.

                    untie(%rr);
                    return { logmsg => "sendmail failed; error code $?" };
                }
            }
            untie(%rr);
        }
        
        # Don't log anything in case of success; we might want to note how
        # many bulletins were delivered or something, of course.
        return { };
    }

-- 
``WATCH A REAL WAR from a glass-bottomed helicopter...
  More Realistic than DVD.'' (from `TV Go Home')