#!/usr/bin/perl -w

#
#          ******* Module A and C ********
# 
# Program reads the RTFLOP file and for each system it:
#   1.  Creates directories
#   2.  Creates a new password file
#   3.  Creates a group file
#   4.  Creates an adds file containing new accounts
#   5.  Creates an inactive file containing inactive accounts
#   6.  Creates a change file containing changes
#   7.  Creates a mailing list file containing system's users
#   8.  Creates backup copies of the above files in each system's archive directory
#
# Initially, the users portion of each systems password file will 
# be copied to the CSA system.
#
# The following exceptions file are manually created for each system:
# - password exceptions file: contains local system accounts and entity accounts 
#       that are registered in NWIS
# - group exceptions file: contains local system groups
#

#
# FILES in Program:
#   rtfile             = RTFLOP file 
#   prev_rtfile        = Previous RTFLOP file
#   <system>_passwd    = Password file
#   <system>_groups    = Group file
#   <system>_prev_passwd = Previous password file
#   <system>_adds      = Contains new accounts
#   <system>_inactive  = Contains inactive accountis 
#   <system>_changes   = Contains account changes
#   <system>_prev_shadow = Previous shadow file
#

#
# Subroutines in program:
#   read_rtflop     = Reads the rtflop file and stores information in two hashes: user and systems
#   system_defaults = Determines systems default home directory path and shell
#   adds_changes    = Creates an adds/changes files for each system
#   inactive        = Creates an inactive file for each system
#   expiration      = Emails user if account is expiring or has expired
#   mail_admin      = Emails system admin if program did not run
#   print_file      = Print user info for the add and changes file
#    

#
# April 2001 Sophia Corwell - main program
# April 2001 Paula McAllister - groups 
# April 2001 Sophia Corwell - modified groups subroutine to exclude users in a group
#    that are not in the system's password file.  Added foreign account mapping.
# April 2001 Barbara Jennings - created mailing lists for each system
#

# --------------------------------------------------------------------------


$manual_override = shift;
#use lib '/home/bjjenni/perllib';
use File::stat;   # The stat call retrieves file information  
use Time::Local;
use Date::Calc qw(Delta_Days
                  Month_to_Text
                  Today);

$system_admin = "secorwe\@sandia.gov donjohn\@sandia.gov rpalmer\@sandia.gov";
$base_dir = "/opt/accounting";

$rtflop = "/.../dce.sandia.gov/fs/proj/nwis/tflop/Rtflop";
$rtfile = "$base_dir/rtflop/Rtflop";
$prev_rtfile = "$base_dir/rtflop/Rtflop_prev";
$systems_dir = "$base_dir/systems";
$web_group = "/$base_dir/web_group";
$foreign_acct = "$base_dir/foreign_acct/foreign_acct_mapping";
$error_size = "Rtflop file size difference greater than 10%";
$error_update = "Rtflop file was not updated in NWIS";
$error_copy = "Rtflop file not copied successfully";
$not_first_time = 0;

$dcecp = "/usr/bin/dcecp";

%systems = ();    # Systems hash (Key: system; Values: uids)
%user = () ;      # User Information hash (Key: uid; Values: name, username, dept, ms, phone)
%users = () ;     # Users hash (Key: username) Used for the group subroutine only
%prev_data = ();  # Previous password file hash
%formaps = ();    # Foreign account mapping hash (Key: foreign username; Values: Sandia assigned username
%nodfs = ();
@add_list = ();
@inactive_list = ();
@change_list = ();                                  

# Compilers
#
%compilers = (
   west => "eiger",
   ross => "angara",
   alaska => "lucern",
);
$compiler_shell = "/bin/ksh";
$compiler_passwd_field = "*K";

#
# CSA hostname
#
$hostname = `hostname`;
chomp $hostname;

#
# Checking for manual override flag
#
#$flag = " ";
#if ($#ARGV == 0) { chomp($flag=shift); }  # $flag used for manual override   

#
# Stop program if file size difference greater than 10%
#   
$file_size_diff = (abs(stat($rtflop)->size - stat($rtfile)->size) / stat($rtfile)->size);
mail_admin($error_size,1) unless ($manual_override or ($file_size_diff < 0.1)); 

#
# Stop program if rtflop mod date is less than or equal to rtfile mod date
# (rtflop file was not updated)
#
mail_admin($error_update,1) unless ((stat($rtflop)->mtime > stat($rtfile)->mtime) or $manual_override);

#
# Make copy of previous rtfile
# Copy new rtflop file down
# Check to make sure copy is successfull by checking files checksums
# Stop program if checksums total not equal
#
system("cp $rtfile $prev_rtfile");
system("cp $rtflop $rtfile");
$new_rtfile_sum = (split(/ /,`sum $rtflop`))[0]; # Check rtflop sum 
$cur_rtfile_sum = (split(/ /,`sum $rtfile`))[0]; # Check rtfile sum
mail_admin($error_copy,1) unless ($new_rtfile_sum == $cur_rtfile_sum); 

#
# Get today's date
#
($year, $month, $day) = Today();
$tmonth = substr(Month_to_Text($month),0,3);

#
# Read foreign account mapping file
#   (Key: foreign username; Values: Sandia assigned username)
#
open(FRM, "< $foreign_acct") or die "Can't open file $foreign_acct: $!\n";
while (<FRM>) {
      chomp;
      s/\s+//g ;
      # $funame = foreign username
      # $luname = local (sandia's) username
      ($funame,$luname) = split (/:/);
      $funame = (split(/%/,$funame))[0];
      push(@{$formaps{$funame}}, $luname);
}                                  

#
# Read the rtflop file and store information in two hashes:
#    user hash    = Key is uid; values are name, username, dept, ms, phone
#    systems hash = Key is system; values are uids
#
read_rtflop();

if (!opendir(DIR,"$systems_dir")) {`mkdir $systems_dir`;}
closedir(DIR);

#
# Create directories/files 
#
foreach $system (keys %systems) # Processing each distinct system found in the Rtflop file
{
  #print "***************** $system \n";
  if ($system eq "SGI_Origin_2000") {
     $system_name = "Atlantis/Discovery";
  } elsif ($system eq "SGI_Visualization") {
     $system_name = "Tesla";
  } else {
     $system_name = $system;
  }

  # 
  # If directory for system does not exists, create it
  #
  if (!opendir(DIR,"$systems_dir/$system")) {`mkdir $systems_dir/$system`;}
  closedir(DIR);
  if (!opendir(DIR,"$systems_dir/$system/archive")) {`mkdir $systems_dir/$system/archive`;}
  closedir(DIR);

  #
  # Files created
  #
  $pswd_file = "$systems_dir/$system/$system" . "_passwd";
  $prev_pswd_file = "$systems_dir/$system/archive/$system" . "_prev_passwd";
  $adds = "$systems_dir/$system/$system" . "_adds";                    
  $users = "$systems_dir/$system/$system" . "_users";                    
  $inactive = "$systems_dir/$system/$system" . "_inactive"; 
  $changes = "$systems_dir/$system/$system" . "_changes";
  $mail_list = "$systems_dir/$system/$system" . "_mail_list";
  $groups = "$systems_dir/$system/$system" . "_groups";
  $pswd_file_cp = "$systems_dir/$system/archive/$system" . "_passwd_" . $tmonth . "_" . $day;
  $adds_cp = "$systems_dir/$system/archive/$system" . "_adds_" . $tmonth . "_" . $day;
  $inactive_cp = "$systems_dir/$system/archive/$system" . "_inactive_" . $tmonth . "_" . $day;
  $changes_cp = "$systems_dir/$system/archive/$system" . "_changes_" . $tmonth . "_" . $day;
  $groups_cp = "$systems_dir/$system/archive/$system" . "_groups_" . $tmonth . "_" . $day;
  $mail_list_cp = "$systems_dir/$system/archive/$system" . "_mail_list_" . $tmonth . "_" . $day; 

  @add_list = ();
  @inactive_list = ();
  @change_list = (); 

  #
  # Read prev_pswd_file and store data in prev_data hash.  Done for comparison later on
  #
  if (-e $prev_pswd_file) {
     open(PREV_PSWD_FILE, "< $prev_pswd_file") or die "Can't open file $prev_pswd_file: $!\n";
     while (<PREV_PSWD_FILE>)
     {
        chomp;
        @prev_data = (split(/:/))[0,1,2,4,5,6];
        #   0 = username
        #   1 = password field
        #   2 = uid
        #   4 = gecos field (name, dept, ms, phone)
        #   5 = home path
        #   6 = shell path
        ($pusername, $ppswd, $puid, $pgecos, $phome, $pshell) = @prev_data;
        $pgecos =~ s/\s+$//; # Removing ending spaces
        push(@{$prev_data{$puid}}, $pusername, $ppswd, $pgecos, $phome, $pshell);
     } 
     close (PREV_PSWD_FILE) or die "Can't close file $prev_pswd_file: $!\n"; 
     $not_first_time = 1;
  }       

  #
  # Copy files to archive directory
  #
  if ($not_first_time) {
     system("cp $pswd_file $pswd_file_cp");
     system("cp $adds $adds_cp");
     system("cp $inactive $inactive_cp");
     system("cp $changes $changes_cp");         
     system("cp $groups $groups_cp");         
     system("cp $mail_list $mail_list_cp");         
  }

  # 
  # Read password file and store data in passwd_data hash
  # 
  if (-e $pswd_file) {
     open (PSWD_FILE, "< $pswd_file") or die "Can't open file $pswd_file: $!\n";
     while (<PSWD_FILE>) {
        chomp;
        @passwd_data = (split(/:/))[0,1,2,4,5,6];
        ($susername, $spswd, $suid, $sgecos, $shome, $sshell) = @passwd_data;
        push(@{$passwd_data{$suid}}, $susername, $spswd, $sgecos, $shome, $sshell);
     }
     close (PSWD_FILE) or die "Can't close file $pswd_file: $!\n";
  }

  #
  # If system is a Cplant system, compiler password needs to be read as well
  # 
  if (exists($compilers{$system})) {
     $compiler_passwd = "$systems_dir/$system/" . $compilers{$system} . "_passwd";
     $compiler_passwd_cp = "$systems_dir/$system/archive/" . $compilers{$system} . "_passwd_" . $tmonth . "_" . $day;
     system("cp $compiler_passwd $compiler_passwd_cp");
     #print "compiler passwd is $compiler_passwd \n";
     open (CMPLR_PSWD, "< $compiler_passwd") or die "Can't open file $compiler_passwd: $!\n";
     while (<CMPLR_PSWD>) {
         chomp;
         @cmplr_data = (split(/:/))[0,1,2,4,5,6];
         ($cusername, $cpswd, $cuid, $cgecos, $chome, $cshell) = @cmplr_data;
         push(@{$compiler_data{$cuid}}, $cusername, $cpswd, $cgecos, $chome, $cshell); 
     }
     close (CMPLR_PSWD) or die "Can't close file $compiler_passwd: $!\n";
     open(CMPLR_PSWD, "> $compiler_passwd") or die "Can't open file $compiler_passwd: $!\n";
  }

  # 
  # Determine default password field, home path, shell, and help email address for system
  #
  @system_defaults = system_defaults($system);
  ($passwd_field, $default_home_path, $default_shell, $help) = @system_defaults;

  #
  # Open the files for write
  #
  open(PSWD_FILE, "> $pswd_file") or die "Can't open file $pswd_file: $!\n";
  open(ADDS, "> $adds")           or die "Can't open file $adds: $!\n";
  open(USERS, "> $users")         or die "Can't open file $users: $!\n";
  open(INACTIVE, "> $inactive")   or die "Can't open file $inactive: $!\n";
  open(CHANGES, "> $changes")     or die "Can't open file $changes: $!\n";
  open(GROUPS, "> $groups")       or die "Can't open file $groups: $!\n";
  open(MAIL_LIST, "> $mail_list") or die "Can't open file $mail_list: $!\n";
 
  foreach $uid (@{$systems{$system}}) # Processing each user who has an account for system
  {
     #
     # Create a gecos field
     #
     ($name, $username, $dept, $ms, $phone, $femail) =  @{$user{$uid}};
     $name   = (split(/login /,$name))[1];
     $gecos = join(",",$name,$dept,$ms,$phone);
     chomp $gecos;
     $gecos =~ s/\s+$//; # Removing ending spaces
     #print "$username\n" if $system eq "DEC_8400";

     #
     # Create a password entry for user in the following format:
     # username:password field:uid:uid:gecos field:home path:shell path
     #
     # If user a new user, use default home path and default shell.
     # Otherwise, use home path and shell from previous passwd file
     #
     if (!exists($passwd_data{$uid}) or (!-e $prev_pswd_file)) { 
        # New user
        $home_path = $default_home_path . $username; # User's home directory
        $passwd_entry = join(':',$username,$passwd_field,$uid,$uid,$gecos,$home_path,$default_shell); 
        $compiler_entry = join(':',$username,$compiler_passwd_field,$uid,$uid,$gecos,$home_path,$compiler_shell) unless (!exists($compilers{$system}));
     } else {
        # Existing user
        # Check previous home path to see if it contains username
        # If username in path, recreate path in case username was changed.
        # Otherwise, use previous home path
        @homepath = ();
         #print "@{$passwd_data{$uid}}[3] ok\n" if $system eq "DEC_8400";
        @homepath = split(/\//,@{$passwd_data{$uid}}[3]);
        @uname_found = grep {/@{$passwd_data{$uid}}[0]/} @homepath;
        if (@uname_found) {
           $home_path = (split(/@{$passwd_data{$uid}}[0]/,@{$passwd_data{$uid}}[3]))[0] . $username; }
        else {
           $home_path = @{$passwd_data{$uid}}[3];
        } 
        $passwd_entry = join(':',$username,$passwd_field,$uid,$uid,$gecos,$home_path,@{$passwd_data{$uid}}[4]);
        $compiler_entry = join(':',$username,@{$compiler_data{$uid}}[1],$uid,$uid,$gecos,@{$compiler_data{$uid}}[3],@{$compiler_data{$uid}}[4]) unless (!exists($compilers{$system}));
        #print "$username\n" unless (!exists($compilers{$system})); 
     }

     #
     # Add user to new password file
     #
     print PSWD_FILE "$passwd_entry\n"; 
     print USERS "$username $dept\n"; 
     print CMPLR_PSWD "$compiler_entry\n" unless (!exists($compilers{$system}));

     # Add user to group file
     print GROUPS "$username:x:$uid:\n";

     # 
     # Determine adds/changes
     #
     if ($not_first_time) { adds_changes(); }

     # 
     # Create mailing list
     #
     mailing_list(*MAIL_LIST);

     #
     # Expiration module
     #
     expiration($system, $name, $username, $uid, $femail, \%expire, $year, $month, $day); 

  } # At this point the new password, adds, changes, group, & mailing list files have been created for system
      
  #
  # Create the web group portion of the group file
  group_file();      

  #
  # Create the inactive file
  #
  inactive();

  #
  # Create the adds/changes file
  #
  map { print ADDS $_ } @add_list;
  map { print INACTIVE $_ } @inactive_list;

  #
  # Email system admins system status
  #
  if (@add_list || @inactive_list || @change_list) {
     open(MAIL, "|mailx -s \"$system_name Account Status from $hostname\" $system_admin") or die "Cannot fork mail: $! \n";
     #open(MAIL, "|mailx -s \"$system_name Account Status from $hostname\" secorwe\@sandia.gov") or die "Cannot fork mail: $! \n";
     print MAIL "\t\t*** Account status for system $system_name on $tmonth-$day-$year ***\n\n";
     if (@add_list) {
        print MAIL "\n* Accounts added to system: \n";
        foreach (@add_list) { print MAIL "\t$_"; }}
     else {
        print MAIL "\n* No accounts added to system.\n\n";
     }
     if (@inactive_list) {
        print MAIL "\n* Accounts inactive on system: \n";
        foreach (@inactive_list) { print MAIL "\t$_"; }}
     else {
        print MAIL "\n* No accounts inactive on system.\n\n";
     }                        
     if (@change_list) {
        print MAIL "\n* Accounts changed on system: \n";
        map { print MAIL "\t$_"; } @change_list; }
     else {
        print MAIL "\n* No accounts changed on system.\n\n";
     }                      
     print MAIL "\n\t\t *** End of Account Status *** \n";
     close MAIL;
  }
  else {
     open(MAIL, "|mailx -s \"$system_name Account Status from $hostname\" $system_admin") or die "Cannot fork mail: $! \n";
     #open(MAIL, "|mailx -s \"$system_name Account Status from $hostname\" secorwe\@sandia.gov") or die "Cannot fork mail: $! \n";
     print MAIL "*** No Accounts Added\/Inactive\/Changed for system $system_name on $tmonth-$day-$year ***\n\n";
     close MAIL;                                                                       
  }

  if (%nodfs) {
     open(MAIL, "|mailx -s \"New users without DFS area - new acctng script\" secorwe\@sandia.gov") or die "Cannot fork mail: $! \n";
     print MAIL "\t\t*** The following new users do not have a DFS area as of $tmonth-$day-$year ***\n\n";
     map { print MAIL "\t@{$nodfs{$_}}[0]\n"; } keys %nodfs;
     close MAIL;
  }

  close (PSWD_FILE);
  close (CMPLR_PSWD);
  close (ADDS);        
  close (USERS);        
  close (INACTIVE);
  close (GROUPS);
  close (CHANGES);
  %prev_data = ();  # Previous password file data hash 
  %passwd_data = ();# Current password file data hash
  %compiler_data = (); # Compiler password file data hash
  @add_list = ();
  @inactive_list = ();
  @change_list = ();
  # Todays password file becomes tomorrows previous password file
  system("cp $pswd_file $prev_pswd_file"); # Backup current password file
}

# Push files to systems by calling script push_files.pl
`$base_dir/scripts/push_files.pl`;
print "End of Module A script\n\n";

# *********************************************************************************


sub read_rtflop {
    #
    # Reads the rtflop file and:
    #   - Removes leading/trailing spaces and leading zeros from fields
    #   - Stores login recods data into the user hash
    #   - Stores account records into the systems hash
    #   - Stores account expiration data into the expire hash
    #   - Returns the user, systems, and expire hashes
    #
    open (RTFLOP, "< $rtfile") or die "Could not open $rtfile for read ($!)"; 
    while (<RTFLOP>) { 
       @orig_data = (split(/:/))[0,1,3,4,5,6,7,8,9];
       #       if type login           if type acct
       #       0=name                  0=name
       #       1=type                  1=type
       #       3=username              3=username
       #       4=UID                   4=UID
       #       5=blank                 5=machine name
       #       6=Dept                  6=case number
       #       7=MS                    7=expiration
       #       8=femail                8=blank
       #       9=phone                 9=blank
 
       # Remove leading/trailing spaces and leading zeros from fields
       for (@data = @orig_data) {
           # If field is undefined or contains just spaces, skip.  Otherwise, remove spaces
           if (defined($_) and $_ !~ /^\s+$/) {
              s/^\s+//; # Removing leading spaces
              s/\s+$//; # Removing ending spaces
              s/^0//;   # Removing leading zeros
           }
       }
 
       ($name,$type,$username,$uid,$machine,$dept,$ms,$femail,$phone) = @data;
 
       #
       # If line is a "login" record, populate the user hash: uid as key and user's personal info as values
       # Otherwise, populate the systems hash (machine name as key and uid as values) and the expire hash
       # which is a hash of a hash ????
       #
       if ($type =~ /login/) {
          #
          # If email field is blank (undefined), append "@sandia.gov" at end of username
          # Otherwise, email field contains foreign email address
          #

          push(@{$formaps{$funame}}, $luname);
          if (exists($formaps{$username})) {
             # User is a foreign user.  Username is local username in foreing account file
             #
             $username = @{$formaps{$username}}[0];
          }
          
          $femail = "$username" . "\@sandia.gov" unless $femail; # email address
          
          push(@{$user{$uid}}, $name, $username, $dept, $ms, $phone, $femail);
          push(@{$users{$username}});
       }
       else {
          $machine =~ s/\s+/_/g; # If machine name contains spaces, replace them with an "_"
          push(@{$systems{$machine}}, $uid);
          $expire{$machine}{$uid} = $ms;  # ms is expiration date
       }
    } # rtfile has been read

    close (RTFLOP) or die "Could not close file $rtfile : ($!)"; 
    return (\%user, \%systems, \%expire);
}


sub system_defaults {
    #
    # Determine system's defaults for password field, home directory path, shell, and help mailing list
    # 
    @defaults = () ;
    if ($system eq "DEC_8400") { @defaults = ("*K","/home/", "/bin/csh", "frege-help"); }
    elsif ($system eq "RSMSS") { @defaults = ("x","/home/", "/bin/bash", "smss-help"); }
    elsif ($system eq "Restricted_TeraFlops") { @defaults = ("x","/home/", "/bin/bash", "tflan-help"); }
    elsif ($system eq "SGI_Origin_2000") { @defaults = ("x","/home/", "/bin/csh", "atlantis-help"); }
    elsif ($system eq "SGI_Visualization") { @defaults = ("x","/home/", "/bin/csh", "tesla-help"); }
    elsif ($system eq "alaska") { @defaults = ("x","/home/", "/bin/bash", "alaska-help"); }
    elsif ($system eq "siberia") { @defaults = ("x","/home/", "/bin/bash", "siberia-help"); }
    elsif ($system eq "iceberg2") { @defaults = ("x","/home/", "/bin/bash", "iceberg2-help"); }
    elsif ($system eq "west") { @defaults = ("x","/home/", "/bin/bash", "west-help"); }
    elsif ($system eq "ross") { @defaults = ("x","/home/", "/bin/bash", "ross-help"); }
    elsif ($system eq "teller") { @defaults = ("x","/home/", "/bin/csh", "teller-help"); }
    else { @defaults = ("x","/home/", "/bin/bash", "siberia-help"); }
    return @defaults;
}      


sub adds_changes {
    #
    # Determines if a user is a new user.  If not new user, it determines if
    # there were any changes made to his/her gecos field, username, home path, and/or 
    # shell path
    #
    # If uid does not exists in previous password data, uid is a new account. 
    #

    if (!exists($passwd_data{$uid})) { # new user
       push(@add_list,"username: $username \tuid: $uid \temail: $femail\n");
       push(@{$nodfs{$uid}},$username) unless (-d "/\.:/fs/\.rw/users/@{$csa_users{$uid}}[0]"); 
       #
       # Send welcome message to new user
       #
       open(MAIL, "|mailx -s \"Welcome to $system\" $femail") or die "Cannot fork mail: $! \n";
       #open(MAIL, "|mailx -s \"Welcome to $system\" secorwe\@sandia.gov")
           #or die "Cannot fork mail: $! \n";
       print MAIL "This is a system generated message.  Please do not reply to this e-mail message.\n";
       print MAIL "\n";
       print MAIL "Hi $name,\n\n";
       print MAIL "You have been added to $system.\n";
       print MAIL "\n";
       print MAIL "To get help for this platform, please e-mail to $help\@sandia.gov.\n";
       print MAIL "For information about $system, visit our website \"http://sc.sandia.gov\"\n";
       print MAIL "and click on \"Machines\".\n";
       print MAIL "Please inform us of any problems you have with the platforms, \n";
       print MAIL "or the web pages.\n";
       print MAIL "Thank you,\n";
       print MAIL "             -- Scientific Computing\n";
       close(MAIL);                            
    }
    else { # not a new user
         if ($gecos ne @{$prev_data{$uid}}[2]) {
            print CHANGES "$name :  gecos field changed from @{$prev_data{$uid}}[2] to $gecos\n";
            push(@change_list,"$name: gecos field changed from @{$prev_data{$uid}}[2] to $gecos\n");
         }
         if ($username ne @{$prev_data{$uid}}[0]) {
            print CHANGES "$name : username changed from @{$prev_data{$uid}}[0] to $username\n";
            push(@change_list,"$name: username changed from @{$prev_data{$uid}}[0] to $username\n");
         }
         if (@{$prev_data{$uid}}[3] ne @{$passwd_data{$uid}}[3]) {
            print CHANGES "$name : home path changed from @{$prev_data{$uid}}[3] to @{$passwd_data{$uid}}[3]\n";
            push(@change_list,"$name: home path changed from @{$prev_data{$uid}}[3] to @{$passwd_data{$uid}}[3]\n");
         }
         if (@{$prev_data{$uid}}[4] ne @{$passwd_data{$uid}}[4]) {
            print CHANGES "$name : shell changed from @{$prev_data{$uid}}[4] to @{$passwd_data{$uid}}[4]\n";
            push(@change_list,"$name: shell changed from @{$prev_data{$uid}}[4] to @{$passwd_data{$uid}}[4]\n");
         }
    }
    return;
}                                                                

 
sub mailing_list {
    #
    # Module adds user to system's mailing list
    #
    local(*FILE) = @_;
 
    print FILE "Machine:  $system\n";
    print FILE "Name:  $name\n";
    print FILE "Login:  $username\n";
    print FILE "UID:  $uid\n";
    print FILE "E-mail:  $femail\n";
    print FILE "Department:  $dept\n";
    print FILE "Phone:  $phone\n";
    print FILE "Expiration:  $expire{$system}{$uid}\n";
    print FILE "\n";
    return;
}                                                        


sub expiration {
    #   
    #  Module determines if user's account is expired or about to expire
    #  If account expired or about to expire, send user email with notification
    #
    $exdate = $expire{$system}{$uid};
    @datefields = split(/\//,$exdate);
    ($exmonth, $exday, $exyear) = @datefields[0,1,2];
   
    $days = Delta_Days($year, $month, $day, $exyear, $exmonth, $exday);

    if ($days <= 0 ) {
       open(MAIL, "|mailx -s \"Your account on $system has expired\" $femail") or die "Cannot fork mail: $! \n";
       #open(MAIL, "|mailx -s \"Your account on $system has expired\" secorwe\@sandia.gov")
           #or die "Cannot fork mail: $! \n";
       print MAIL "Message for $name:\n\n";
       print MAIL "This is a system generated message.  Please do not reply to this e-mail message.\n";
       print MAIL "\n";
       print MAIL "Your account on $system expired on $exdate.\n";
       print MAIL "If you still need this account, please renew this account via webcars at:\n";
       print MAIL "\n";
       print MAIL "https://workflow.sandia.gov/webcars/WebCars.html\n";
       print MAIL "\n";
       print MAIL "or, make arrangements for file disposition.  Contact your\n";
       print MAIL "system administrator if further assistance is necessary at $help\n";
       print MAIL "\n";
       print MAIL "Thank you for your prompt attention to this matter.\n";
       print MAIL "             -- Scientific Computing\n";
       close(MAIL);
    }
    if ($days < 31 && $days > 0) {
       open(MAIL, "|mailx -s \"Your account on $system is expiring\" $femail") or die "Cannot fork mail: $! \n";
       #open(MAIL, "|mailx -s \"Your account on $system is expiring\" secorwe\@sandia.gov")
           #or die "Cannot fork mail: $! \n";
       print MAIL "Message for $name:\n\n";
       print MAIL "This is a system generated message.  Please do not reply to this e-mail message.\n";
       print MAIL "\n";
       print MAIL "Your account on $system will expire in $days day(s) on $exdate.\n";
       print MAIL "If you still need this account, please renew this account via webcars at:\n";
       print MAIL "\n";
       print MAIL "https://workflow.sandia.gov/webcars/WebCars.html\n";
       print MAIL "\n";
       print MAIL "or, make arrangements for file disposition.  Contact your\n";
       print MAIL "system administrator if further assistance is necessary at $help\n";
       print MAIL "\n";
       print MAIL "Thank you for your prompt attention to this matter.\n";
       print MAIL "             -- Scientific Computing\n";
       close(MAIL);       
    }
    return;
} 


sub inactive {
    #
    # Create the inactive accounts file if necessary
    # An account is inactive if user is found in the previous password file and not in the new
    # Checks uids in previous password file with the values in the system hash.
    # If value not found, account is inactive.  Send email notification to user 
    #
    $i = 0;
    $count = 0; # Count increments if uid found
 
    @uids = @{$systems{$system}}; # saving system's uids into an array

    foreach $puid (keys %prev_data) {
      #
      # Searching the array for the value (to find if the value exists for this key)
      #
      for ($i = 0; $i < scalar(@{$systems{$system}}); $i++) {
          if ($uids[$i] eq "$puid") {$count++;}
      }
      if ($count == 0) { 
         push(@inactive_list,"username: @{$prev_data{$puid}}[0] \tuid: $puid\n");
 
         # Notify user 
         #
         open(MAIL, "|mailx -s \"Your account on $system is not active in NWIS\" @{$prev_data{$puid}}[0]\@sandia.gov");
         #open(MAIL, "|mailx -s \"Your account on $system is not active in NWIS\" $system_admin")
           #or die "Cannot fork mail: $! \n";
	 print MAIL "Message for @{$prev_data{$puid}}[0]:\n\n";
         print MAIL "This is a system generated message.  Please do not reply to this e-mail message.\n";
         print MAIL "\n";
         print MAIL "You have an account on $system but you are inactive in NWIS.\n";
         print MAIL "If you wish to keep this account, please go to the WebCARS homepage at \n";
         print MAIL "https://workflow.sandia.gov/webcars/WebCars.html to active it\n";
         print MAIL "or call password control for further assistance at (505) 845-0415.\n";
         print MAIL "\nIf you do not need this account, please email $help with information about\n";
         print MAIL "file disposition.\n"; 
         print MAIL "\n";
         print MAIL "Thank you for your prompt attention to this matter.\n";
         print MAIL "             -- Scientific Computing\n";
         close(MAIL);                                                    
      }
      $count = 0;
    }
    return;
} 


sub group_file {
    #
    # Create the web group portion of the group file for system
    #
    #  define files needed
    # inputs
    #   WEB is the web_groups.wg file in each system's directory
    #   FOREIGN is the foreign_account_mapping info for each system

    %webs = ();
    @USERS = ();

    #
    # Determine system's web_groups file
    
    if ($system eq "DEC_8400") {
       $web = "$web_group/dec8400.wg";
    } elsif ($system eq "SGI_Origin_2000") {
       $web = "$web_group/sgi_son.wg";
    } elsif (($system eq "SGI_Visualization") or ($system eq "teller")) {
       $web = "$web_group/sgi_srn.wg";
    } else { 
       $web = "$web_group/cplant.wg";
    }
 
    #
    # Avoid scrambled output buffers
    $|=1;

    open (WEB, "< $web") or die "Could not open web-group list $web: $! ";
 
    # Hash the web-groups file with null association to start
    while (<WEB>) {
        chomp;
        $webs{$_} = "";
    }

    
 
    #  get info for each web group key in hash %web
    foreach $key (sort keys (%webs)) {
        #print "***** $key *****\n" unless $web ne "$web_group/sgi_srn.wg";
        # what is in string to parse??
        # is it an error (use next;) or good data?
        @USERS = ();
 
        @USERS = `$dcecp -c group list $key`;
#        ($mess,$restofit) = split(/:/,$USERS[0]);
        $mess = (split(/:/,$USERS[0]))[0];
        if ( ($mess eq "Error") or ($mess =~ /^\s+$/) ) { next; }
        $GID = `$dcecp -c group show $key | grep gid`;
        $GID =~ s/\D//g;
        # or use =~ pattern to next or analyze like if ($USERS[0] =~ "Error")
        # next else foreach @USERS get name from back end
        for ($i=0; $i<@USERS; $i++)  {
            #print "\t$USERS[$i]\n";
            chomp $USERS[$i];
            if (($USERS[$i] =~ /^\s+$/) or ($USERS[$i] =~ /self/)) { next; }
            ($mess,$wguser) = split(/\/dce.sandia.gov\//,$USERS[$i]);
            chomp($mess);
            if (defined($wguser)) {
                chomp($wguser);
                if ($wguser =~ /\w\%\w/) {
                   # look at foreign mapping
                   $user = (split(/\%/,$wguser))[0];
                   $wguser = @{$formaps{$user}}[0];
                }
             }
             else {
               #print "look at foreign mapping for $mess\n";
               $user = (split(/\//,$mess))[3];
               $wguser = @{$formaps{$user}}[0];
             }

             # Do not add user if user doesn't exists on system
             if (!exists($users{$wguser})) { 
                 #print "User $USERS[$i] on web group $key not in $system\n"; 
                 next; }

             # print "$wguser\n" unless $web ne "$web_group/sgi_srn.wg";  
             if ($webs{$key} eq "") {
                      #first name in hash entry for this group
                      $webs{$key} = $wguser;
             }
             else {
                      # add-on name put comma in first
                      $webs{$key} .= ",";
                      $webs{$key} .= $wguser;               
             }
         }
           #now write out line if not still null
           if ($webs{$key} =~ /\w/) {
                  print GROUPS "$key"."::"."$GID:"."$webs{$key}\n";
           }
   }
   close WEB or die "Could not close web-group list";
   return;
}


sub mail_admin {
    #
    # Email system admins if program did not run
    #
    my ($mail_message, $exit) = @_;

    open(MAIL, "|mailx -s \"Accounting Program did not run on $hostname\" $system_admin") or die "Cannot fork mail: $! \n";
    #open(MAIL, "|mailx -s \"Accounting Program did not run on $hostname\" secorwe\@sandia.gov") or die "Cannot fork mail: $! \n";
    print MAIL $mail_message,"\n";
    close(MAIL);
   
    die "$mail_message\n" if $exit;
} 

