"Fossies" - the Fresh Open Source Software Archive

Member "passwd_exp-1.2.11/passwd_exp" (3 Dec 2009, 32376 Bytes) of package /linux/privat/old/passwd_exp-1.2.11.tar.gz:


As a special service "Fossies" has tried to format the requested text file into HTML format (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file.

    1 #! @PERL@
    2 # PROGRAM	: passwd_exp @VERSION@
    3 # PURPOSE	: warns of account expiration via email
    4 # AUTHOR	: Samuel Behan <samkob(at)gmail(dot)com> (c) 2000-2009
    5 # HOMEPAGE	: http://devel.dob.sk/passwd_exp
    6 # LICENSE	: GNU GPL v2, NO WARRANTY VOID (see file LICENSE)
    7 ################################################################################
    8 
    9 #requirements
   10 use Getopt::Long 	qw(:config no_ignore_case);
   11 use POSIX	 	qw(uname strftime);
   12 use Text::Tokenizer	qw(:all);
   13 @HAVE_LOCALE{use Locale::gettext;}@
   14 
   15 #pragmas
   16 use strict;
   17 use integer;
   18 use vars qw($VERSION $AUTHOR $AUTHOR_EMAIL $AGENT $SCRIPT $BANNER);
   19 
   20 #script info
   21 $AUTHOR		= 'Samuel Behan';
   22 $AUTHOR_EMAIL	= 'samkob(at)gmail.com';
   23 $VERSION	= '@VERSION@';
   24 $SCRIPT		= 'passwd_exp';
   25 $AGENT		= 'Password expiration agent';
   26 $BANNER		= "This message was produced by passwd_exp version $VERSION";
   27 
   28 ##
   29 $|	= 1;
   30 my (%CONFIG, %UENV, $TIME);
   31 $TIME		= time();
   32 
   33 #gettext shortcut
   34 sub _($)	{ return @HAVE_LOCALE{gettext}@($_[0]);	}
   35 
   36 ##
   37 # BASIC ENVIROMENT
   38 my($prefix, $exec_prefix, $datarootdir);
   39 $prefix			= "@prefix@";
   40 $exec_prefix		= "@exec_prefix@";
   41 $datarootdir		= "@datarootdir@";
   42 $CONFIG{-cfg_dir}	= "@sysconfdir@";
   43 $CONFIG{-mod_dir}	= "@pw_moddir@";
   44 $CONFIG{-data_dir}	= "@datadir@";
   45 $CONFIG{-mail_dirs}	= ("$CONFIG{-cfg_dir}/mail", "$CONFIG{-data_dir}/mail");
   46 $CONFIG{-conf_file}	= $CONFIG{-cfg_dir}.'/passwd_exp.conf';
   47 $CONFIG{-lock_file}	= "@libdir@/passwd_exp";
   48 $CONFIG{-lock_time}	= 22 * 3600;	#22 hours only lock time
   49 $CONFIG{-module}	= '@DB_MODULE@';
   50 $CONFIG{-module_opt}	= ();
   51 $CONFIG{-force}		= 0;
   52 $CONFIG{-const}		= ();
   53 $CONFIG{-conf_set}	= ();
   54 $CONFIG{-mode}		= 0;
   55 $CONFIG{-test_user}	= undef;
   56 $CONFIG{-test_mode}	= 0;
   57 $CONFIG{-check_mode}	= 0;
   58 $CONFIG{-verbose}	= 0;
   59 $CONFIG{-domain}	= (uname())[1];	$CONFIG{-domain} =~ s/^[^\.]+\.?//o;
   60 $ENV{'PATH'}		= $CONFIG{-mod_dir}.':/sbin:/usr/sbin:/usr/local/sbin:/usr/bin:/bin:/usr/local/bin';
   61 #config file defauls
   62 $CONFIG{'locale'}	= $ENV{'LANG'} || 'C';
   63 $CONFIG{'banner'}	= 1;
   64 $CONFIG{'expired_warn'}	= 1;
   65 $CONFIG{'msg_w_in'}	= _('\'%user%\' [%ustate%] will expire in %expire_days% days on %expire_date%');
   66 $CONFIG{'msg_w_done'}	= _('\'%user%\' [%ustate%] has expired on %expire_date% (%expire_days% days ago)');
   67 $CONFIG{'msg_e_in'}	= _('\'%user%\' [%ustate%] will become inactive in %inactive_days% days on %inactive_date%');
   68 $CONFIG{'msg_e_done'}	= _('\'%user%\' [%ustate%] has been inactived on %inactive_date% (%inactive_days% days ago)');
   69 $CONFIG{'msg_d_in'}	= _('\'%user%\' [%ustate%] will be disabled in %account_days% days on %account_date%');
   70 $CONFIG{'msg_d_done'}	= _('\'%user%\' [%ustate%] has been disabled on %account_date% (%account_days% days ago)');
   71 
   72 ##
   73 # USER ENVIROMENT
   74 $UENV{'locale'}		= \$CONFIG{'locale'};
   75 $UENV{'recipient'}	= \$UENV{'user'};
   76 $UENV{'user_name'}	= $UENV{'username'}	= \$UENV{'fullname'};
   77 $UENV{'mail_addr'}	= $UENV{'email_addr'}	= \$UENV{'email'};
   78 $UENV{'expire_in'}	= $UENV{'expire_days'}	= \$UENV{'edays'};
   79 $UENV{'expire_date'}	= \$UENV{'edate'};
   80 $UENV{'inactive_in'}	= $UENV{'inactive_days'}	= \$UENV{'idays'};
   81 $UENV{'inactive_date'}	= \$UENV{'idate'};
   82 $UENV{'account_days'}	= \$UENV{'adays'};
   83 $UENV{'account_date'}	= \$UENV{'adate'};
   84 $UENV{'today'}		= $UENV{'date'}		= \(strftime("%A %e %B %Y",localtime($TIME)));
   85 $UENV{'ltoday'}		= $UENV{'locale_date'}	= $UENV{'ldate'}
   86 				= \(strftime("%x",localtime($TIME)));
   87 $UENV{'now'}		= $UENV{'time'}		= \(strftime("%H:%M:%S",localtime($TIME)));
   88 $UENV{'lnow'}		= $UENV{'locale_time'}	= $UENV{'ltime'}
   89 				= \(strftime("%X",localtime($TIME)));
   90 $UENV{'unix_time'}	= $UENV{'utime'}	= \(strftime("%s",localtime($TIME)));
   91 $UENV{'host_name'}	= $UENV{'hostname'} 	= $UENV{'host'}	= \(uname())[1];
   92 $UENV{'host_domain'}	= \$UENV{'domain'};	$UENV{'domain'}	= $CONFIG{-domain};
   93 $UENV{'host_os'}	= $UENV{'os'}		= \(uname())[0];
   94 $UENV{'host_osver'}	= $UENV{'osver'}	= \(uname())[2];
   95 $UENV{'host_machine'}	= $UENV{'machine'}	= 
   96 	$UENV{'arch'}	= $UENV{'host_arch'}	= \(uname())[4];
   97 #special vars (not aliasesed)
   98 $UENV{'agent'}		= $UENV{'sender'}	= $AGENT;
   99 $UENV{'version'}	= $UENV{'ver'}		= $VERSION;
  100 
  101 ##
  102 # Constants
  103 sub C_NAME ()		{	0;	};
  104 sub C_FULLNAME ()	{	1;	};
  105 sub C_EMAIL ()		{	2;	};
  106 sub C_EDATE ()		{	3;	};
  107 sub C_ADATE ()		{	4;	};
  108 sub C_WDAYS ()		{	5;	};
  109 sub C_IDAYS ()		{	6;	};
  110 sub C_NOSEND ()		{	7;	};
  111 
  112 ##
  113 # Configuration map
  114 my %t_cfg_map	= (
  115 	qr/^var(iable)?\[([\w-]+)\](\[([\w\*\?]+)\])?$/	=>
  116 			q/my $l	=	_localize($4, $opt_val);
  117 			  set_var($2, $l) if(defined($l));/,
  118 	qr/^locale$/			=> q/$CONFIG{"locale"} = $opt_val if(defined($opt_val) && ($opt_val ne "auto"))/,
  119 	qr/^direct(\s*|_)mta$/		=> q/$CONFIG{"direct_mta"} = _isbool($opt_val);/,
  120 	qr/^(mail((er)|(\s*|_)sender)?)$/	=> 
  121 			q/ return (-1, "mailer_recp_miss") if($opt_val !~ \/\%(recp|recipient)\%\/o);
  122 			  $CONFIG{"mailer"} = $opt_val;/,
  123 	qr/^module$/	=> q/$CONFIG{"module"} = $opt_val;/,
  124 	qr/^mod(ule)?(\s*|_)?opt(s|ion)?(\[(\w*)\])$/ =>
  125 			q/${ $CONFIG{-module_opt} }{$5} = $opt_val if(!exists(${ $CONFIG{-module_opt} }{$5}));/,
  126 	qr/^mta|mail(\s*|_)agent$/	=>
  127 			q/$CONFIG{"mta"} = $opt_val;/,
  128 	qr/^reply(\s*|_|-)to$/		=> q/$CONFIG{-mailh}{"Reply-To"} = $opt_val;/,
  129 	qr/^send(\s*|_|-)from$/		=> q/$CONFIG{-mailh}{"From"} = $opt_val;/,
  130 	qr/^mail((\s*|_|-)header)?\[([\w-]+)\]?$/	=>
  131 			q/$CONFIG{-mailh}{$3} = $opt_val if(defined($3));/,
  132 	qr/^(print(\s*|_))?banner$/	=> q/$CONFIG{"banner"}	= _isbool($opt_val);/,
  133   	qr/^(meg|mexpiring)(\[([\w\*\?]+)\])?$/=> q/$CONFIG{"msg_w_in"} = _localize($3, $opt_val) || $CONFIG{"msg_w_in"};/,
  134 	qr/^(med|mexpired)(\[([\w\*\?]+)\])?$/	=> q/$CONFIG{"msg_w_done"} = _localize($3, $opt_val) || $CONFIG{"msg_w_done"};/,
  135 	qr/^(mig|minactiving)(\[([\w\*\?]+)\])?$/	=> q/$CONFIG{"msg_e_in"} = _localize($3, $opt_val) || $CONFIG{"msg_e_in"};/,
  136 	qr/^(mid|minactived)(\[([\w\*\?]+)\])?$/	=> q/$CONFIG{"msg_e_done"} = _localize($3, $opt_val) || $CONFIG{"msg_e_done"};/,
  137 	qr/^(mdig|mdinactiving)(\[([\w\*\?]+)\])?$/	=> q/$CONFIG{"msg_d_in"} = _localize($3, $opt_val) || $CONFIG{"msg_d_in"};/,
  138 	qr/^(mdid|mdinactived)(\[([\w\*\?]+)\])?$/	=> q/$CONFIG{"msg_d_done"} = _localize($3, $opt_val) || $CONFIG{"msg_d_done"};/,
  139 	qr/^(no(\s*|_)warnings?|ignore(\s*|_)users)(\s*(\.|\+))?$/	=>
  140 			q/return (-1, "obsoleted");/,
  141   	qr/^(no(\s*|_)check((\s*|_)file)?|ignore(\s*|_)file)$/	=>
  142   			q/return (-1, "obsoleted");/,
  143 	qr/^(warn(\s*|_)days)$/		=>
  144 			q/if($opt_val =~ \/^\d+$\/o) { $CONFIG{"warn_days"} = $opt_val; }
  145 			else	{ return (-2, 'digit');	}/,
  146 	qr/^(warn(\s*|_)days(\s*|_)step)$/		=>
  147 			q/if($opt_val =~ \/^\d+$\/o) { $CONFIG{"warn_days_step"} = $opt_val; }
  148 			else	{ return (-2, 'digit');	}/,
  149 	qr/^(mail(\s*|_)days(\s*|_)only)$/	=>
  150 			q/$CONFIG{"w_days"}	= $CONFIG{"e_days"} = $CONFIG{"d_days"} = $opt_val;/,
  151 	qr/^(wo|warn(ing)?(\s*|_)days(\s*|_)only)$/	=>
  152 			q/$CONFIG{"w_days"}	= $opt_val;/,
  153 	qr/^(ws|warn(ing)?(\s*|_)subject)(\[([\w\*\?]+)\])?$/	=>
  154  			q/$CONFIG{"w_subject"} = _localize($5, $opt_val) || $CONFIG{"w_subject"};
  155     			return (-3, 'mail subject') if(length($opt_val) > 50);/,
  156 	qr/^(wb|warn(ing)?(\s*|_)body)(\[([\w\*\?]+)\])?$/	=>
  157  			q/$CONFIG{"w_body"} = _localize($5, $opt_val) || $CONFIG{"w_body"};/,
  158 	qr/^(wf|warn(ing)?(\s*|_)file)(\[([\w\*\?]+)\])?$/	=>
  159 			q/$CONFIG{"w_file"} = _localize($5, $opt_val) || $CONFIG{"w_file"};/,
  160 	qr/^warn(\s*|_)expired$/	=> q/$CONFIG{"expired_warn"} = _isbool($opt_val);/,
  161 	qr/^(eo|expired(\s*|_)days(\s*|_)only)$/	=>
  162 			q/$CONFIG{"e_days"}	= $opt_val;/,
  163 	qr/^(es|expired(\s*|_)subject)(\[([\w\*\?]+)\])?$/	=>
  164 			q/$CONFIG{"e_subject"} = _localize($4, $opt_val) || $CONFIG{"e_subject"};
  165 			return (-3, 'expired mail subject') if(length($opt_val) > 50);/,
  166 	qr/^(eb|expired(\s*|_)body)(\[([\w\*\?]+)\])?$/	=>
  167   			q/$CONFIG{"e_body"} = _localize($4, $opt_val) || $CONFIG{"e_body"};/,
  168 	qr/^(ef|expired(\s*|_)file)(\[([\w\*\?]+)\])?$/	=>
  169   			q/$CONFIG{"e_file"} = _localize($4, $opt_val) || $CONFIG{"e_file"};/,
  170 	qr/^(warn(\s*|_))?date(\s*|_)(expired)?$/	=>
  171 			q/$CONFIG{"date_warn"}	= _isbool($opt_val);/,
  172 	qr/^(ao|account(\s*|_)days(\s*|_)only)$/	=>
  173 			q/$CONFIG{"d_days"}	= $opt_val;/,
  174 	qr/^(as|account(\s*|_)?subject)(\[([\w\*\?]+)\])?$/	=>
  175 			q/$CONFIG{"d_subject"} = _localize($4, $opt_val) || $CONFIG{"d_subject"};
  176 			return (-3, 'date expired mail subject') if(length($opt_val) > 50);/,
  177 	qr/^(ab|account?(\s*|_)?body)(\[([\w\*\?]+)\])?$/	=>
  178  			q/$CONFIG{"d_body"}	= _localize($4, $opt_val) || $CONFIG{"d_body"};/,
  179 	qr/^(af|account?(\s*|_)?file)(\[([\w\*\?]+)\])?$/	=>
  180  			q/$CONFIG{"d_file"}	= _localize($4, $opt_val) || $CONFIG{"d_file"};/,
  181 );
  182 ##
  183 # Configuration error map
  184 my %t_cfg_error	= (
  185 	"mailer_recp_miss"	=> _("destination user recipient missing (see mailer config reference)"),
  186 	"obsoleted"		=> _("directive was obsoleted, remove it"),
  187 );
  188 
  189 ###
  190 # print error msg
  191 sub _error($;$)
  192 {
  193 	print STDERR $_[0]."\n";
  194 	return (defined($_[1]) ? $_[1] : -1);
  195 }
  196 
  197 ##
  198 # Print version info
  199 sub cmd_print_version()
  200 {
  201 	print STDOUT _("passwd_exp version")." ".$VERSION."  $AUTHOR (c) 2000-2009\n";
  202 	return 0;
  203 }
  204 
  205 ##
  206 # Print usage help
  207 sub cmd_print_help(;$)
  208 {
  209 	my $help_f	= *STDOUT;
  210 	my $err		= shift;
  211 	my $err_str	= "";
  212 	my ($k);
  213 	my %t_help_opts	= (
  214 		"-m MODULE"	=> _('use module to gather account data (try \'list\')'),
  215 		"-mi"		=> "\t"._('print active module informations'),
  216 		"-mo OPT=VALUE"	=> ""._('set module options'),
  217 		"-s DIR=VALUE"	=> ""._('set config file directive'),
  218 		"-l"		=> "\t"._('list expired/inactivated acounts'),
  219 		"-i"		=> "\t"._('ignore nocheck file'),
  220 		"-f"		=> "\t"._('force, ignore \'run once per day\' limit'),
  221 		"-t"		=> "\t"._('test mode, print e-mail(s) to stdout (use with -u)'),
  222 		"-T"		=> "\t"._('test mode, check config file only'),
  223 		"-w DAYS"	=> "\t"._('minimum warn days for checks'),
  224 		"-ws DAYS"	=> _('minimum warn days step for checks (increment warn days)'),
  225 		"-u USER"	=> "\t"._('check only this user'),
  226 		"-c FILE"	=> "\t"._('path to config file'),
  227 		"-v"		=> "\t"._('verbose mode (repeat for more verbosity)'),
  228 		"-V"		=> "\t"._('print version information'),
  229 		"-h"		=> "\t"._('print this help'),
  230 		"-d VAR=VALUE"	=> _('define variable'),
  231 		);
  232 
  233 	if(defined($err))
  234 	{	$help_f	= *STDERR;
  235 		$err_str	= _("Error").": ".$err;
  236 		chomp($err_str);$err_str .= "\n";	}
  237 
  238 	#print usage
  239 	print $help_f _("usage").": $SCRIPT [options] [ USER ]\n";
  240 	print $help_f "      -- passwd_exp $VERSION by $AUTHOR\n";
  241 
  242 	#print error
  243 	print $help_f $err_str;
  244 
  245 	#print options
  246 	print $help_f _("[options]")."\n";
  247 	foreach $k (sort(keys(%t_help_opts)))
  248 	{	print $help_f "\t".$k."\t".$t_help_opts{$k}."\n";	}
  249 
  250 	exit(!defined($err));
  251 }
  252 
  253 ##
  254 # Print verbose messages
  255 sub verbose($$)
  256 {
  257 	syswrite(STDERR, $_[1]."\n")
  258 		if(defined($CONFIG{-verbose}) && $_[0] <= $CONFIG{-verbose});
  259 	return 1;
  260 }
  261 
  262 ##
  263 # Set var
  264 sub set_var($$)
  265 {
  266 	my $var	= shift;
  267 	my $val	= shift;
  268 	my $refv;
  269 
  270 	return if(!defined($var) && $var ne '');
  271 	#check for reference
  272 	if(ref($CONFIG{-const}{$var}) eq 'SCALAR')
  273 			{ $refv = $CONFIG{-const}{$var}; }
  274 	else		{ $refv = \$CONFIG{-const}{$var}; }
  275 	${ $refv }  = $val;
  276 	return 1;
  277 }
  278 
  279 ## 
  280 # Load configuration from file
  281 # ERRORS: -1 error message
  282 #	  -2 bad format
  283 #	  -3 too long
  284 #
  285 my $EXEC_CODE;
  286 sub cmd_load_cfg($)
  287 {
  288 	my $file = shift;
  289 
  290 	sub _isbool($)
  291 	{	return 0 if(!defined($_[0]));
  292 		return 1 if($_[0] =~ /^yes|ok|allow|enable|1|true|oui|siano|jo|hej|da|ja|si$/oi);
  293 		return 0 if($_[0] =~ /^non?|deny|disable|0|false|ne|nicht|never$/oi);
  294 		return undef;	}
  295 	sub _localize($$)
  296 	{	defined($_[0]) || return $_[1];
  297 		my $q	= $_[0];
  298  		$q	=~ s/(\*)|(\?)|(\W)/${
  299     				defined($1) ? \('.*') : (
  300 				defined($2) ? \('.')  : \("\\$3"))
  301 				}/og;
  302 		return $_[1] if(defined($CONFIG{'locale'}) &&
  303 					$CONFIG{'locale'} =~ /^$q$/);
  304 		return undef;	}
  305 	sub _configure($$$$)
  306 	{
  307 		my $opt_key	= shift;
  308 		my $opt_val	= shift;
  309 		my $file	= shift;
  310 		my $line	= shift;
  311 		my($k, @do_ret);
  312 
  313 		#find config definition
  314 		foreach $k (keys(%t_cfg_map))
  315 		{	next if($opt_key	!~ /$k/);
  316 			$EXEC_CODE	= $t_cfg_map{$k};
  317 
  318 			#do configure
  319 			@do_ret		= eval($EXEC_CODE);
  320 			#check for eval error
  321 			if($@ ne '')
  322 			{	print STDERR "$0: [programming error]\n\tCODE: $EXEC_CODE\n--- DIE ---\n$@-----------\n";
  323 				exit(1);	}
  324 			#report config error
  325 			if(defined($do_ret[0]) 
  326 				&& substr($do_ret[0], 0, 1) eq '-'
  327 						&& $do_ret[0] < 0)
  328 			{
  329 				if($do_ret[0] == -1)
  330 				{	return _error("[$file:$line] <$opt_key> ".$t_cfg_error{$do_ret[1]}, 0);	}
  331 				elsif($do_ret[0] == -2)
  332 				{	return _error("[$file:$line] <$opt_key> "._("bad input value format, expecting")." '$do_ret[1]'");	}
  333 				elsif($do_ret[0] == -3)
  334 				{	return _error("[$file:$line] <$opt_key> "._("input value too long")." ".$do_ret[1]);	}
  335 				else
  336 				{	print STDERR "$0: [programming error]\n\tCODE: $EXEC_CODE\n--- DIE ---\n Unhandled error code '$do_ret[0]' -----------\n";
  337 					exit(1);	}
  338 			}
  339 			return 1;
  340 		}
  341 		_error("[$file:$line] ".
  342 			_("unknown configuration directive")." '$opt_key'");
  343 		return undef;
  344 	}
  345 
  346 	no strict 'subs';
  347 
  348 	#open cfg file
  349 	return _error("$SCRIPT: "._("failed opening config file")." `$file' ($!)", 0)
  350 		if(!open(F_CFG, $file));
  351 
  352 	#setup tokenizer
  353 	my ($tokid);
  354 	$tokid	= tokenizer_new(F_CFG);
  355 	tokenizer_options(TOK_OPT_UNESCAPE_LINES);
  356 	use strict;
  357 
  358 	#read conf
  359 	my (@opt_str, $opt_data, $opt_ign, $opt_key);
  360 	my ($tok_str, $tok_type, $tok_line, $tok_err, $tok_errline);
  361 	while(1)
  362 	{
  363 SCAN:
  364 		($tok_str, $tok_type, $tok_line, $tok_err, $tok_errline) =
  365 				tokenizer_scan();
  366 		last if($tok_type == TOK_EOF || $tok_type == TOK_ERROR ||
  367 				$tok_type == TOK_UNDEF);
  368 
  369 		#do conf
  370 		if($tok_type == TOK_EOL)
  371 		{	goto RESET if($#opt_str == -1 && !defined($opt_data));
  372 			push(@opt_str, $opt_data);
  373 			goto CONFIG;	}
  374 
  375 		#divide by =
  376 		if($tok_type == TOK_TEXT && $tok_str =~ /^([^=]*)\s*=\s*(.*)$/o)
  377 		{	$opt_data .= $1;
  378 			push(@opt_str, $opt_data);
  379 			$opt_data = $2;
  380 			goto SCAN;	}
  381 
  382 		#XXX: possible bug here, i don't check token type of adding
  383 		#	string so we can add something bad in
  384 
  385 		#load data
  386 		$opt_data .= $tok_str;
  387 		goto SCAN;
  388 CONFIG:
  389 		my ($opt_val);
  390 
  391 		#fix file pos
  392 		$tok_line--;
  393 
  394 		#get option value
  395 		$opt_val	= pop(@opt_str) if($#opt_str != 0);
  396 		$opt_val	= $1	if(defined($opt_val) &&
  397 						$opt_val =~ /^\s*(.*?)\s*$/o);
  398 		$opt_val	= ''	if(!defined($opt_val));
  399 		foreach $opt_key (@opt_str)
  400 		{	
  401 			#trim white spaces
  402 			$opt_key	= $1	if($opt_key =~ /^\s*(.*?)\s*$/o);
  403 			#ignore blank key
  404 			next	if(defined($opt_key) && $opt_key eq '');
  405 			#preform configure
  406 			_configure($opt_key, $opt_val, $file, $tok_line) ||
  407 				return 0;
  408 
  409 			#clean
  410 			$EXEC_CODE	= undef;
  411 		}
  412 RESET:
  413 		undef @opt_str;
  414 		$opt_data = undef;
  415 	}
  416 	close(F_CFG);
  417 	undef $EXEC_CODE;
  418 	return 1;
  419 }
  420 
  421 ##
  422 # Check lock file
  423 sub cmd_check_lock($)
  424 {
  425 	my $file	= shift;
  426 	my @finfo;
  427 
  428 	#stat lock file
  429 	@finfo	= stat($file);
  430 	if($#finfo != -1) {	#lock file not found, create new one
  431 	#check time
  432 	return _error("$SCRIPT: "._("trying to perform expiration check too soon (use -f to override). Check should be perfomed only once a day !!!"), 0)
  433 			if($finfo[9] > ($TIME - $CONFIG{-lock_time}));	}
  434 	#update lock file
  435 	open(LOCK, ">".$CONFIG{-lock_file}) ||
  436 		return _error("$SCRIPT: "._("failed to update lock file")." '$file' ($!)", -1);
  437 	my $data;
  438 
  439 	$data	.= strftime("%s\n",localtime($TIME));
  440 	$data	.= strftime("%a %b %e %H:%M:%S %Y",localtime($TIME));
  441 	syswrite(LOCK, $data);
  442 	close(LOCK);
  443 	return 1;
  444 }
  445 
  446 
  447 # special vars
  448 my (@udata, @usdata, %days);
  449 #$expire_days == w, $inactive_days == e , $datexp_days == d);
  450 
  451 ##
  452 # Apply message enviroment
  453 # XXX: this is what i call POWERFULL REGEXP or EXTREME HACK
  454 sub eval_vars($\%\%)
  455 {
  456 	my $str		= shift;
  457 	my $evar_h	= shift;
  458 	my %evar	= %{ $evar_h };
  459 	my $env_h	= shift;
  460 	my %env		= %{ $env_h };
  461 
  462 	# replace user vars
  463 	$str	=~ s/(%([\w-]+)(\[(\w+)\])?%)/${
  464 		(!exists($evar{$2})) ?		\$1		:
  465 #		!defined($evar{$2}) ?		\('UNDEF')	:
  466 		(ref($evar{$2}) eq '') ?	\$evar{$2}	:
  467 		(ref($evar{$2}) eq 'SCALAR') ?	
  468 #			((defined(${ $evar{$2} })) ?
  469 #				$evar{$2}	: \('UNDEF'))	:
  470 						$evar{$2}	:
  471 		(ref($evar{$2}) eq 'ARRAY') ?
  472 			((!defined($4) || !exists(${ $evar{$2} }[$4])) ?
  473 				\$1	: \${ $evar{$2} }[$4])	:
  474 		die('[programming error]')
  475 			}/og;
  476 
  477 	# evalute special vars
  478  	$str	=~ s/%((w|warn(ing)?)|(e|expire)|(a|account)|(c|curr?(ent)?))(_|\.|-|->|=>)%?
  479   		([aAbBcCdDeEgGhHIjkmMOpPrsStTuUVwWxXyYzZ\+])%/${
  480   		(defined($2)) ?
  481 			\strftime("%$9", localtime($TIME + $days{'w'} * 86400))
  482 								:
  483 		(defined($4)) ?
  484 			\strftime("%$9", localtime($TIME + $days{'e'} * 86400))
  485 								:
  486 		(defined($5)) ?
  487 			\strftime("%$9", localtime($TIME + $days{'d'} * 86400))
  488 								:
  489 	 		\strftime("%$9", localtime($TIME))
  490 			}/oxg;
  491 
  492 	# evalute enviroment vars
  493 	$str	=~ s/(\$((\w+)|\{(\w+)\}))/${
  494 			exists($env{$3 || $4}) ? \$env{$3 || $4} : \$1
  495 			}/og;
  496 	#evalute special chars
  497 	$str	=~ s/\\([tnrfae]|x[[:xdigit:]]{1,4}|x\{[[:xdigit:]]{1,4}\})/${
  498 			eval('return \("\\'.$1.'");') }/og;
  499 	return $str;
  500 }
  501 
  502 ##
  503 # Setup variables
  504 sub setup_vars()
  505 {
  506 	$UENV{'user'}		= $udata[C_NAME];
  507 	$UENV{'fullname'}	= $udata[C_FULLNAME] || $udata[C_NAME];
  508 	$UENV{'email'}		= $udata[C_EMAIL];
  509 	$UENV{'edays'}		= abs($days{'w'});
  510 	$UENV{'edate'}		= strftime("%a %e %B %Y",localtime($TIME + $days{'w'} * 86400));
  511 	$UENV{'idays'}		= abs($days{'e'});
  512 	$UENV{'idate'}		= strftime("%a %e %B %Y",localtime($TIME + $days{'e'} * 86400));
  513 	$UENV{'adays'}		= abs($days{'d'});
  514 	$UENV{'adate'}		= strftime("%a %e %B %Y",localtime($TIME + $days{'d'} * 86400));
  515 
  516 	#eval user constants
  517 	my $k;
  518 	foreach $k (keys(%{ $CONFIG{-const} }))
  519 	{	next if(!defined(${ $CONFIG{-const} }{$k}));
  520 		#some calls might get saved here
  521 		$UENV{$k} = eval_vars(${ $CONFIG{-const} }{$k}, %UENV, %ENV);	}
  522 	return 1;
  523 }
  524 
  525 ##
  526 # Return mail data
  527 sub get_mail_data($)
  528 {
  529 	my $mode = shift;
  530 	my $file = $CONFIG{$mode.'_file'};
  531 
  532 	#mail file not defined
  533 	return ($CONFIG{$mode.'_subject'}, $CONFIG{$mode.'_body'})
  534 				if(!defined($file));
  535 
  536 	#eval file
  537 	my $found;
  538 	$file	= eval_vars($file, %UENV, %ENV);
  539 	#test path absolutness
  540 	if(!substr($file, 0, 1) eq '/')
  541 	{	my $dir;
  542 		#check if file exists
  543 		foreach $dir ($CONFIG{-mail_dirs})
  544 		{	if( -e "$dir/$file" )
  545 			{	$file	= "$dir/$file";
  546 				last;	}	}	}
  547 	#final existance
  548 	if(! -e $file)
  549 	{	_error("$SCRIPT: ".sprintf(_("Mail file '%s' not found, skipping..."), $file));
  550 		#we die if mail file not found
  551 		return (undef, 1) if($file eq $CONFIG{$mode.'_file'});
  552 		return (undef, 0);		}
  553 
  554 	#parse file
  555 	if(!open(MAILF, $file))
  556 	{	_error("$SCRIPT: ".sprintf(_("Failed to open mail file, skipping..."), $file));
  557 		#we die if mail file not found
  558 		return (undef, 1) if($file eq $CONFIG{$mode.'_file'});
  559 		return (undef, 0);		}
  560 
  561 	my ($subj, $body);
  562 
  563 	#read subj (first line of file)
  564 	$subj	= <MAILF>;
  565 	chomp($subj);
  566 
  567 	#read body (rest of file, or to the dot line)
  568 	my $line;
  569 	while(defined($line = <MAILF>) && $line !~ /^\.$/o)
  570 	{	$body .= $line;		}
  571 
  572 	close(MAILF);
  573 	return ($subj, $body);
  574 }
  575 
  576 ##
  577 # Send email
  578 # sub cmd_sendmail($recp, $subj, $messg)
  579 sub cmd_sendmail($$$)
  580 {
  581 	my $mail_recp	= shift;
  582 	my $mail_subj	= shift;
  583 	my $mail_msg	= shift;
  584 	my (@mail_head, $mail, $k);
  585 
  586 	#personalize messages
  587 	$mail_recp	= eval_vars($mail_recp, %UENV, %ENV);
  588 	$mail_subj	= eval_vars($mail_subj, %UENV, %ENV);
  589 	$mail_msg	= eval_vars($mail_msg, %UENV, %ENV);
  590 
  591 	#check input
  592 	exit(_error("$SCRIPT: Mail body not defined, exiting..", 1))
  593 			if(!defined($mail_msg) || $mail_msg eq '');
  594 	$mail_subj	= $AGENT." email"
  595 			if(!defined($mail_subj) || $mail_subj eq '');
  596 
  597 	#create mail head
  598 	push(@mail_head, "From: ".(exists($CONFIG{-mailh}{'From'}) ? $CONFIG{-mailh}{'From'} : "$AGENT <root\@localhost.localdomain>" ));
  599 	push(@mail_head, "Reply-To: ".$CONFIG{-mailh}{'Reply-To'}) if(exists($CONFIG{-mailh}{'Reply-To'}));
  600 #FIXME: delete mail headers
  601 	push(@mail_head, "To: ".$mail_recp);
  602 	push(@mail_head, "Subject: ".$mail_subj);	
  603 	push(@mail_head, "Full-Name: ".$UENV{'fullname'});
  604 	push(@mail_head, "X-Mailer: $SCRIPT $VERSION");
  605 	#add user headers
  606 	foreach $k (keys(%{ $CONFIG{-mailh} }))
  607 	{	#ignore already set headers
  608 		next if(grep (/^$k$/, ("From", "Reply-To", "To", "Subject", "Full-Name", "X-Mailer")));
  609 		push(@mail_head, "$k: ".eval_vars($CONFIG{-mailh}{$k}, %UENV, %ENV));	}
  610 	#assemble mail
  611 	foreach $k (@mail_head)
  612 	{	$mail	.= "$k\n";	}
  613 
  614 	#open destination + print headers (if needed)
  615 	if($CONFIG{-test_mode} == 1)
  616 	{	open(MAIL, ">&STDOUT");
  617 		syswrite(MAIL, "--- EMAIL($mail_recp) --------\n");
  618 		syswrite(MAIL, $mail);	}
  619 	elsif(defined($CONFIG{"direct_mta"}) && $CONFIG{"direct_mta"} == 1)
  620 	{	open(MAIL, "| $CONFIG{mta} -i '$mail_recp'") ||
  621 			return _error("$SCRIPT: "._("(mta) mail transport agent was unable send e-mail using")." '$CONFIG{mta}' ($!)", 0);
  622 		syswrite(MAIL, $mail);	}
  623 	elsif(defined($CONFIG{"mailer"}))
  624 	{	my $cmd;
  625 
  626 		#assemble command
  627 		$cmd	= eval_vars($CONFIG{"mailer"}, 
  628 					%{ { "recipient"=> $mail_recp,
  629 					  "user"	=> $UENV{'user'},
  630 					  "subject"	=> $mail_subj,
  631 					  "recp"	=> \$mail_recp,
  632 					  "subj"	=> \$mail_subj	} },
  633 					%ENV);
  634 		open(MAIL, "| $cmd") ||
  635 			return _error("$SCRIPT: "._("(mailer) unable to send e-mail via '$cmd'")." ($!)", 0);	}
  636 	else
  637 	{	exit(_error("$SCRIPT: No sending agent defined, exiting...", 1));	}
  638 
  639 	#now print message to email
  640 	syswrite(MAIL, $mail_msg."\n");
  641 	syswrite(MAIL, "\n---\n".$BANNER."\n")
  642 		if(defined($CONFIG{"banner"}) && $CONFIG{"banner"} == 1);
  643 	close(MAIL) ||
  644 		exit(_error("$SCRIPT: "._("Sending agent returned error retval")." ($!)",1));
  645 	return 1;
  646 }
  647 
  648 ##
  649 # Match day to pattern
  650 # sub match_day($pattern, $value)
  651 sub match_day($$)
  652 {
  653 	my @ar	= split(' ', shift);
  654 	my $val  = shift;
  655 
  656 	my $patt;
  657 	foreach $patt (@ar)
  658 	{	#easy test for *
  659 		return 1 if($patt eq '*');
  660 		#test for digit
  661 		return 1 if($patt == $val);
  662 		#test for range
  663 		return 1 if(($patt =~ /^(\d+)-(\d+)?$/o)
  664 				&& ($val >= $1)
  665 				&& (!defined($2) || ($val <= $2)));
  666 		#test for repeat pattern
  667 		return 1 if($patt =~ /^\*\/(\d+)$/o
  668 				&& ($1 != 0) && ($val % $1 == 0));
  669 	}
  670 	return 0;
  671 }
  672 
  673 ################
  674 # MAIN PROGRAM #
  675 ################
  676 my ($cmd);
  677 
  678 #parse command line
  679 $SIG{__WARN__}	= sub { exit(cmd_print_help($_[0])); };
  680 $cmd	= Getopt::Long::GetOptions(
  681 		"c|config=s"	=> \$CONFIG{-conf_file},
  682 		"u|user=s"	=> \$CONFIG{-test_user},
  683 		"l|list"	=> sub { $CONFIG{-mode} = 1; },
  684 		"f|force!"	=> \$CONFIG{-force},
  685 		"t|test"	=> \$CONFIG{-test_mode},
  686 		"T|configcheck"	=> \$CONFIG{-check_mode},
  687 		"v|verbose+"	=> \$CONFIG{-verbose},
  688 		"V|Version"	=> sub { exit(cmd_print_version()); },
  689 		"h|help"	=> sub { exit(cmd_print_help()); },
  690 		"w|warn-days=i"		=> \$CONFIG{-warn_days},
  691 		"ws|warn-days-step=i"	=> \$CONFIG{-warn_days_step},
  692 		"d|define=s%"	=> \$CONFIG{-const},
  693 		"m|module=s"	=> \$CONFIG{-module},
  694 		"mi|module-info"   => \$CONFIG{-module_info},
  695 		"mo|module-opt=s%" => \$CONFIG{-module_opt},
  696 		"s|set=s%"	=> \$CONFIG{-conf_set},
  697 		"<>"		=> sub { $CONFIG{-test_user} = $_[0]; },
  698 	);
  699 exit(1)	if(!$cmd);	#Bad imput
  700 $SIG{__WARN__}	= 'DEFAULT';
  701 
  702 #list avaible modules
  703 if(defined($CONFIG{-module}) && $CONFIG{-module} eq 'list')
  704 {	
  705 	opendir(DIR, $CONFIG{-mod_dir})
  706 		|| exit(_error("$SCRIPT: "._("can not list modules")." ($!)",1));
  707 	print _("Modules").":\n";
  708 	while(defined(($cmd = readdir(DIR))))
  709 	{	next if(substr($cmd, 0, 1) eq '.' ||
  710 				! -x $CONFIG{-mod_dir}.'/'.$cmd);
  711 		next if(substr($cmd, -5) eq '.info');	#ignore info files
  712 		next if(substr($cmd, 0, 1) eq '-');	#ignore helper mods
  713 		printf("\t%-20s", $cmd);
  714 		if(-r $CONFIG{-mod_dir}.'/'.$cmd.'.info')
  715 		{	open(F_INFO, $CONFIG{-mod_dir}.'/'.$cmd.'.info');
  716 			$cmd	= <F_INFO>;
  717 			chomp($cmd);
  718 			print substr($cmd, 0, 52);
  719 			close(F_INFO);	}
  720 		print "\n";
  721 	}
  722 	closedir(DIR);
  723 	exit(0);	}
  724 
  725 #load config file
  726 verbose(1, "Loading config file `$CONFIG{-conf_file}'...");
  727 cmd_load_cfg($CONFIG{-conf_file}) || exit(1);
  728 
  729 #config check mode
  730 if($CONFIG{-check_mode} == 1)
  731 {	print _("Syntax OK")."\n";
  732 	exit(0);	}
  733 
  734 # fix config
  735 #remove bad mail headers
  736 foreach $cmd (qw(To Subject Full-Name X-Mailer))
  737 {	delete $CONFIG{-mailh}{$cmd};	}
  738 
  739 #setup command line config
  740 foreach $cmd (sort(keys(%{ $CONFIG{-conf_set} })))
  741 {	_configure($cmd, ${ $CONFIG{-conf_set} }{$cmd}, "<-s>", 0) || exit(1);	}
  742 
  743 #check lock file
  744 verbose(1, "Checking lock file `$CONFIG{-lock_file}'...");
  745 exit(1) if((exists($CONFIG{-test_mode}) && $CONFIG{-test_mode} != 1)
  746 		&& (exists($CONFIG{-force}) && $CONFIG{-force} != 1)
  747 		&& (!defined($CONFIG{-test_user}))
  748 		&& ($CONFIG{-mode} != 1)
  749 		&& (exists($CONFIG{-module_info}) && $CONFIG{-module_info} != 1)
  750 		&& cmd_check_lock($CONFIG{-lock_file}) != 1);
  751 
  752 #get user database (via submodule)
  753 my ($line, $linenum, $mode, $days);
  754 $days		= int($TIME / 86400);
  755 $UENV{'data'}		= \@udata;
  756 $UENV{'userdata'}	= $UENV{'udata'}	= \@usdata;
  757 
  758 $CONFIG{-module}	= $CONFIG{"module"};
  759 exit(_error("$SCRIPT: No data module defined (see -m argument)", 1))
  760 		if(!defined($CONFIG{-module}) || $CONFIG{-module} eq '');
  761 $CONFIG{-module}	.= ' info'
  762 		if(defined($CONFIG{-module_info}) && $CONFIG{-module_info} == 1);
  763 foreach $cmd (sort(keys(%{ $CONFIG{-module_opt}})))
  764 {	$CONFIG{-module}	.= " '$cmd=${ $CONFIG{-module_opt} }{$cmd}'";	}
  765 
  766 verbose(1, "Executing data module `$CONFIG{-module}'...");
  767 open(USERS, "-|", $CONFIG{-module})
  768 		|| exit(_error("$SCRIPT: "._("failed to retreive user list data"). " ($!)", 1));
  769 while(defined(($line = <USERS>)))
  770 {
  771 	$linenum++;
  772 	#ignore commented lines + remove eol
  773 	next	if(substr($line, 0, 1) eq '#');	
  774 	chomp($line);
  775 
  776 	#split data & check them
  777 	verbose(2, "[line $linenum] Parsing input data");
  778 	@udata	= split(/(?<!\\):/o, $line);
  779 	#find out our sys/special separator
  780 	@usdata	= @udata;
  781 	foreach $_ (@udata)
  782 	{	shift(@usdata); last if($_ eq '*');	}
  783 
  784 	#check only specific user
  785 	next if(defined($CONFIG{-test_user}) && 
  786 			$udata[C_NAME] ne $CONFIG{-test_user});
  787 
  788 	#complete data
  789 	$udata[C_WDAYS]	= $CONFIG{-warn_days}
  790 				if(defined($CONFIG{-warn_days}) && $udata[C_WDAYS] < $CONFIG{'warn_days'});
  791 	$udata[C_WDAYS]	= $CONFIG{'warn_days'}
  792 				if(defined($CONFIG{'warn_days'}) && $udata[C_WDAYS] < $CONFIG{'warn_days'} 
  793 					&& !defined($CONFIG{-warn_days}));
  794 	#warn days step
  795  	$udata[C_WDAYS]	+= $CONFIG{-warn_days_step}
  796 				if(defined($CONFIG{-warn_days_step}));
  797 	$udata[C_WDAYS]	+= $CONFIG{'warn_days_step'}
  798 				if(defined($CONFIG{'warn_days_step'}) && !defined($CONFIG{-warn_days_step}));
  799 	$udata[C_WDAYS]	= 0	if(!defined($udata[C_WDAYS]) || $udata[C_WDAYS] eq '');
  800 	$udata[C_IDAYS]	= 0	if(!defined($udata[C_IDAYS]) || $udata[C_IDAYS] eq '');
  801 	$udata[C_ADATE] = 0	if(!defined($udata[C_ADATE]) || $udata[C_ADATE] eq '');
  802 	$udata[C_EDATE] = 0	if(!defined($udata[C_EDATE]) || $udata[C_EDATE] eq '');
  803 
  804 	#check input data format
  805 	verbose(2, "[line $linenum] [user $udata[0]] Checking input data format");
  806 	foreach $cmd (@{ [C_WDAYS, C_IDAYS, C_EDATE, C_ADATE] })
  807 	{	exit(_error("[$CONFIG{-module}:$linenum:<".($cmd).">] ".
  808 				_("element should be an integer value"), 1))
  809 			if(!($udata[$cmd]	=~ /^\d+|$/o));	}
  810 
  811 	exit(_error("[$CONFIG{-module}:$linenum:<".(C_NOSEND).">] ".
  812 				_("element should be an bool value (1/0)"), 1))
  813 			if(!($udata[C_NOSEND]	=~ /^1|0|$/o));
  814 	exit(_error("[$CONFIG{-module}:$linenum:<".(C_NAME).">] ".
  815 				_("element should be an word value"), 1))
  816 			if(!($udata[C_NAME]	=~ /^\S+$/o));
  817 	exit(_error("[$CONFIG{-module}:$linenum:<".(C_EMAIL).">] ".
  818 				_("element should be an email address"), 1))
  819 			if(!($udata[C_EMAIL]	=~ /^\S+(\@\S+)?$/o));
  820 
  821 	#create enviroment
  822 	verbose(2, "[line $linenum] [user $udata[0]] Computing values");
  823 	$days{'w'}	= $udata[C_EDATE]  - $days;
  824 	$days{'e'}	= ($udata[C_EDATE] + $udata[C_IDAYS]) - $days;
  825 	$days{'d'}	= $udata[C_ADATE]  - $days;
  826 	verbose(3, "[line $linenum] [user $udata[0]] w:$days{w} e:$days{e} d:$days{d}");
  827 
  828 	#make %ustate%
  829 	$UENV{'ustate'}	= undef;
  830 	$UENV{'ustate'} .= 'C'
  831 		if(defined($udata[C_NOSEND]) && $udata[C_NOSEND] == 1);
  832 
  833 	#check if any action required
  834 	verbose(2, "[line $linenum] [user $udata[0]] Determining warning mode");
  835 	if($udata[C_WDAYS] != 0 && abs($days{'d'}) <= $udata[C_WDAYS])
  836 	{	$mode = 'd';	
  837 		$UENV{'ustate'}	.= 'D';	}		#date expiration
  838 	elsif((($udata[C_IDAYS] != 0 && abs($days{'e'}) <= $udata[C_IDAYS])
  839 			|| (abs($days{'e'}) < abs($days{'w'})))	#inactivation takes precedence
  840 			&& (($CONFIG{-mode} == 1) || ($CONFIG{"expired_warn"})))
  841 	{	$mode = 'e';	}			#expired (inactivation)
  842 	elsif($udata[C_WDAYS] != 0 && (abs($days{'w'}) <= $udata[C_WDAYS]
  843 				|| ($CONFIG{-mode} == 1) && $days{'w'} < 0))
  844 	{	$mode = 'w';	}		 	#expiration
  845 	else
  846 	{	$mode = undef;	}			#no mode
  847 
  848 	#not in any state
  849 	next if(!defined($mode));
  850 	next if($CONFIG{-mode} == 0 && $days{$mode} < 0);
  851 
  852 	#make %ustate%
  853 	$UENV{'ustate'} .= 'N' if(!defined($UENV{'ustate'}));
  854 
  855 	#inform
  856 	verbose(1, "[line $linenum] [user $udata[0]] `".
  857 				${{'w'=>'Expiration',
  858 				   'e'=>'Inactivation',
  859 				   'd'=>'Date Expiration'}}{$mode}."' mode, taking actions...");
  860 
  861 	#test if we realy should send email
  862 	my $send_pattern = $CONFIG{$mode."_days"};
  863 	if($CONFIG{-mode} == 0
  864 		&& defined($days{$mode}) && defined($send_pattern) && !($send_pattern eq '*') 
  865 			&& !match_day($send_pattern,$days{$mode}))
  866 	{	verbose(1, "[line $linenum] [user $udata[0]] mail will be not sent today");
  867 		next;	}
  868 
  869 	#get domain name from email address
  870 	if($udata[C_EMAIL] =~ /^\S+\@(\S+)$/o)
  871 		{	$UENV{"domain"}	= $1;	}
  872 	else	{	$UENV{"domain"}	= $CONFIG{-domain};	}
  873 
  874 	#do it
  875 	setup_vars();
  876 	if($CONFIG{-mode} == 0)		#mail send
  877 	{	next if(defined($udata[C_NOSEND]) && $udata[C_NOSEND] == 1);
  878 
  879 		my ($subj, $body) = get_mail_data($mode);
  880 
  881 		#test mail data errors
  882 		if(!defined($subj))
  883 		{	next	if($body = 0);
  884 			exit(1)	if($body = 1);	}
  885 		#error something failed
  886 		exit(1)	if(!cmd_sendmail($udata[C_EMAIL], $subj, $body));
  887 	}
  888 	elsif($CONFIG{-mode} == 1)	#list users
  889 	{	my $msg	= $CONFIG{'msg_'.$mode.'_'.(($days{$mode} >= 0) ? 'in' : 'done')};
  890 
  891 		$msg	= eval_vars($msg, %UENV, %ENV);
  892 		syswrite(STDOUT, $msg."\n");	}
  893 	else				#unknown mode
  894 	{	die("[programming error]");	}
  895 
  896 	#clear variables
  897 	undef $mode;
  898 	undef @udata;
  899 }
  900 my $x=<USERS>;
  901 close(USERS) ||
  902 	exit(_error("$SCRIPT: "._("data module returned error retval")." ($?)", 1));
  903 verbose(1, "Finished.");
  904 
  905 __END__
  906 
  907 =head1 NAME
  908 
  909 passwd_exp - password/account expiration checking tool
  910 
  911 =head1 SYNOPSIS
  912 
  913 passwd_exp [options] [USERNAME]
  914 
  915 
  916 =head1 DESCRIPTION
  917 
  918 B<passwd_exp> warns users of password/account expiration via email. It extends similar function of login process, 
  919 that prints such a messages at login time, but many users do not login for a long (long) time and only 
  920 download/forward their email, so they have absolutely no chance to find out what's happening with their account.
  921 
  922 This script will warn them (via email), and save you from request to re-enable users accounts that has 
  923 been 'magicaly' disabled by that BAD BAD man called Linux or whatever :) (And be sure there will be some if you have 
  924 system with many users forcing them to change their passwords to get just a little more security).
  925 
  926 Extra feature of this script is listing of expired user accounts so you will have some more info about your system.
  927 
  928 
  929 =head1 OPTIONS
  930 
  931 =over 4
  932 
  933 =item	-c FILE			config file
  934 
  935 =item	-u USERNAME		username to check
  936 
  937 =item	-l				list users, do not send mails
  938 
  939 =item	-f				override `run once per day' restriction
  940 
  941 =item	-t				test mode, print generated emails instead of sending them
  942 
  943 =item	-T				test configuration file validity
  944 
  945 =item	-v				verbose mode, more times for more verbosity
  946 
  947 =item	-d var=value		define variable for message enviroment
  948 
  949 =item	-m MODULE			module to use (can be module name or program path)
  950 
  951 =item	-mi				print module informations
  952 
  953 =item	-mo option=value	set module option (argument)
  954 
  955 =item	-s  option=value	override config file option
  956 
  957 =back
  958 
  959 =head1 FILES
  960 
  961 =over 4
  962 
  963 =item	/etc/passwd_exp/passwd_exp.conf			- config file
  964 
  965 =item	/etc/passwd_exp/mail				- mail files search dir
  966 
  967 =item	/usr/share/passwd_exp/mail			- mail files search dir
  968 
  969 =item	/usr/share/passwd_exp/mod			- input modules dir
  970 
  971 =item	/etc/cron.daily/passwd_exp.cron			- daily cron check script
  972 
  973 =item	/etc/cron.weekly/passwd_exp-admin.cron		- admin weekly cron check script
  974 
  975 =head1 BUGS
  976 
  977 None found (yet).
  978 
  979 =head1 SEE ALSO
  980 
  981 =over 4
  982 
  983 =item	B<Text-Tokenizer>
  984 
  985 perl module for fast text analyzation at B<http://devel.dob.sk/Text-Tokenizer>
  986 
  987 =item	B<pfadmin>
  988 
  989 postfix virtual email accounts managment tools (for vmail.pfadmin data module)
  990 B<http://devel.dob.sk/pfadmin>
  991 
  992 =back
  993 
  994 =head1 AUTHOR
  995 
  996 Samuel Behan, E<lt>samkob(at)gmail(dot)comE<gt>
  997 
  998 =head1 COPYRIGHT AND LICENSE
  999 
 1000 Copyright 2003-2005 by Samuel Behan
 1001 
 1002 This library is free software; you can redistribute it and/or modify
 1003 it under the same terms of GNU/GPL v2. 
 1004 
 1005 =cut
 1006 
 1007 
 1008 #EOF (c) by UN*X 1970-$EOD (End of Days) [ EOD (c) by God ]