sync_roster.pl

Here’s a Perl script that takes a dBase IV file kicked out by the Grand Lodge’s membership data system called MORI and for each record checks if the user exists, if so, updates his info, and if not, creates them:

#!/usr/bin/perl
use warnings;
use strict;
use XBase;    # dBase library
use Cwd ();
use File::Copy;
use File::Find ();

# A tool to update the system users and e-mails database from a dBase file.
use constant DEBUG => 1;
my $birthdays      = "/usr/local/etc/birthdays";
my @emails_current = `/usr/mailman/bin/list_members lakelodge189`;
my $mail_tmp       = "/tmp/mail_tmp";

# Set the variable $File::Find::dont_use_nlink if you're using AFS,
# since AFS cheats.

# for the convenience of &wanted calls, including -eval statements:
use vars qw/*name *dir *prune/;
*name  = *File::Find::name;
*dir   = *File::Find::dir;
*prune = *File::Find::prune;

sub wanted;
sub doexec ($@);

# GECOS update
sub gecos_update {
    my ( $uid, $glnum, $fname, $lname, $office, $workph, $homeph, $username ) =
      @_;
    print "Changing GECOS for UID $uid: $glnum $fname $lname\n";
    my $chfn_command =
"chfn -f \"$fname $lname\" -o \"$office\" -p \"$workph\" -h \"$homeph\" $username";
    print $chfn_command . "\n";
    print `$chfn_command`;
}

# Mail Forwarding
sub add_forward_rule {
    my ( $uid, $glnum, $fname, $lname, $procmailrc_file, $email ) = @_;

    #my $procmailrc_file = $_[0];
    print "Adding forwarding e-mail for UID $uid: $glnum $fname $lname\n";
    open PROCMAILRC, ">$procmailrc_file" or die $!;
    print PROCMAILRC ":0\n! $email\n";
    close PROCMAILRC;
}

# Add a Birthdays entry
sub add_birthday {
    my ( $username, $birthdate ) = @_;
    open BIRTHDAYS, ">>$birthdays" or die $!;
    print BIRTHDAYS "$username:$birthdate";
    close BIRTHDAYS;
}

# Back up system files
copy( "/etc/passwd", "/root/passwd." . `date +%F` ) or die($!);

my $cwd = Cwd::cwd();

# Traverse desired filesystems
File::Find::find( { wanted => \&wanted }, '/export/home' );

sub wanted {
    my ( $dev, $ino, $mode, $nlink, $uid, $gid );

    ( ( $dev, $ino, $mode, $nlink, $uid, $gid ) = lstat($_) )
      && -f _
      && /^\.procmailrc\z/s
      && doexec(
        0,    "/home/imbrius/scripts/cparch.sh",
        '{}', "/root/$File::Find::dir"
      );
}

sub doexec ($@) {
    my $ok      = shift;
    my @command = @_;      # copy so we don't try to s/// aliases to constants
    for my $word (@command) { $word =~ s#{}#$name#g }
    if ($ok) {
        my $old = select(STDOUT);
        $| = 1;
        print "@command";
        select($old);
        return 0 unless <STDIN> =~ /^y/;
    }
    chdir $cwd;            #sigh
    system @command;
    chdir $File::Find::dir;
    return !$?;
}

# Open the DBF
my $table = new XBase $ARGV[0] or die XBase->errstr;
my $cur = $table->prepare_select(
    'GLNUM', 'FNAME',     'LNAME', 'HOMEPH', 'WORKPH', 'CELLPH',
    'EMAIL', 'BIRTHDATE', 'OFFICE'
);
my (
    $glnum,  $fname, $lname,     $homeph, $workph,
    $cellph, $email, $birthdate, $office
);

# open e-mail address collector
open MAIL_TMP, ">>$mail_tmp" or die $!;

# Walk the table
while (
    (
        $glnum,  $fname, $lname,     $homeph, $workph,
        $cellph, $email, $birthdate, $office
    )
    = $cur->fetch
  )
{
    my $username = lc( substr( $fname, 0, 1 ) . $lname );
    $username =~ s/ //g; # work around bug with spaces in names
    my $uid = getpwnam($username);

    if (DEBUG) {
        if ($uid) print "Username is $username; UID is $uid.\n";
        else print "passwd entry not found for $username.\n";
    }

    if ($uid) {

        # For Existing Users

        # GECOS
        gecos_update(
            $uid,    $glnum,  $fname,  $lname,
            $office, $workph, $homeph, $username
        );

        # email
        my @pwent      = getpwnam($username);
        my $procmailrc = $pwent[7] . "/.procmailrc";
        if ( -f $procmailrc ) {
            print
              "Changing e-mail address for UID $uid: $glnum $fname $lname\n";
            open PROCMAILRC, $procmailrc or die $!;
            my @file_lines = <PROCMAILRC>;
            close PROCMAILRC;

            my $changed = 0;
            my $i       = 0;    # only for debugging
            my $found   = 0;

            foreach (@file_lines) {
                $i++ if DEBUG;

                if ( $_ =~ m/^:0/ ) {
                    print "Found blanket rule at line $i.\n" if DEBUG;
                    $found = 1;
                    next;
                }

                if ( $found && $_ =~ s/^! *.*/! $email/ ) {
                    print "Changed forward rule at line $i.\n" if DEBUG;
                    $changed = 1;
                    last;
                }

            }

            if ($changed) {
                open PROCMAILRC, ">$procmailrc" or die $!;
                print PROCMAILRC $_ foreach (@file_lines);
                close PROCMAILRC;
            }

            else {

                # forward line not found - add one
                print "Adding forward rule to .procmailrc\n";
                open PROCMAILRC, ">>$procmailrc" or die $!;
                print PROCMAILRC ":0\n! $email\n";
                close PROCMAILRC;
            }

        }

        #else {
        #}

        # Birthdays
        unless (`grep -c '^$username' $birthdays`)
          add_birthday( $username, $birthdate );

    }

    else {
        my $useradd_cmd =
"/usr/sbin/useradd -d /export/home/$username -m -s /bin/csh $username";
        die($!) unless system($useradd_cmd) == 0;
        gecos_update(
            $uid,    $glnum,  $fname,  $lname,
            $office, $workph, $homeph, $username
        );
        add_forward_rule( $uid, $glnum, $fname, $lname,
            "/export/home/$username/.procmailrc", $email );
        add_birthday( $username, $birthdate );
        my $usermod_cmd = "/usr/sbin/usermod -d /home/$username $username";
        die($!) unless system($usermod_cmd) == 0;
    }

    # add e-mails to mailing list
    my $found = 0;
    foreach (@emails_current) {
        if ( $email eq $_ ) {
            $found = 1;
            last;
        }

    }

    if ( !$found ) {

        # moving the open/close to outside of the loop
        #open MAIL_TMP, ">>$mail_tmp" or die $!;
        print MAIL_TMP $email . "\n";

        #close MAIL_TMP;
    }

    # add to the lakelodge group
    die($!) unless system("/usr/bin/gpasswd -a $username lakelodge") == 0;
    die($!) unless system("/usr/bin/gpasswd -a $username users") == 0;

}

close MAIL_TMP;

# call mailman
die($!)
  unless system("/usr/mailman/bin/add_members -r $mail_tmp lakelodge189") == 0;
Advertisements
  1. #1 by Joshua on February 17, 2012 - 7:22 PM

    I added a few lines to the end to also sync the e-mails list with mailman. 🙂

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: