[rt-devel] Contrib: ScripCondition Crontab

Bruce Campbell bruce_campbell at ripe.net
Tue Feb 5 07:41:45 EST 2002

The attached ScripCondition will give the ability to perform certain
conditions at certain times of the day, utilising a format very similar to
crontab(5), hence the name.

Apart from this change, it is a plug-in replacement for the default

The time values are kept in the Argument of the ScripCondition.
Obviously, to have differing times of the day, you will need to create
different ScripConditions using different time ranges in the argument.
The attached insert_condition Template gives the default '* * * * *' (any

Multiple time values can be given in one Argument, by using the ':'
character to seperate them.  Multiple Transaction types can be matched by
playing with the ApplicableTransTypes field.

The main usage of this ScripCondition would be to give a different
auto-reply outside office hours.

A walkthrough of the programming of this ScripCondition will be sent to
rt-users in due course.


                             Bruce Campbell                            RIPE
                   Systems/Network Engineer                             NCC
                 www.ripe.net - PGP562C8B1B                      Operations
-------------- next part --------------
# ScripCondition: Crontab.pm
# IsApplicable returns true if the current time is within the
# range specified by the Argument, undef otherwise.

# Bruce Campbell says to always give yourself Credit, and
# to use RCS (man rcs):
# $Id: Crontab.pm,v 1.3 2002/02/05 12:15:42 bc Exp $

=head1 NAME



This is a ScripCondition to fire when 'Now' is within certain time
ranges.  The Argument supplied is the standard 'crontab' format.

Multiple crontab-style time ranges can be specified by seperating 
them with the ':' character.


Crontab format is defined as 5 fields, seperated by spaces.  The
specific fields are described in order as:

              field          allowed values
              -----          --------------
              minute         0-59
              hour           0-23
              day of month   1-31
              month          1-12
              day of week    0-7 (0 or 7 is Sun)

Any of the fields may consist of specific numbers within the allowed
values, ranges (identified by 'start-end'), lists (seperated by 
commas, eg '1,4,6,4'), steps (every 'step' value, indicated by a '/',
eg every 2nd item from 4 to 9 '4-9/2') or a wildcard ('*').

Set::Crontab also defines the following extensions:

	<N and >N

		Elements from the allowed range less than or greater
		than 'N'.


		Excludes 'N' from the set.


The following matches all times between 9am and 4:59pm (close enough
to 5pm), Monday to Friday:

	* 9-16 * * 1-5

The following (in the Argument) matches all times between 8:45am and 5:15pm
Monday to Friday (note the ':' seperations):

	45-59 8 * * 1-5:* 9-16 * * 1-5:0-15 17 * * 1-5


# Who are we?
package RT::Condition::Crontab;

# Bring all the RT Goodness into our lives.
require RT::Condition::Generic;

# and our namespace
@ISA = qw(RT::Condition::Generic);

# We're going to use this later.
use Set::Crontab;

# Override RT::Condition::Generic's IsApplicable method:

sub IsApplicable {
	# Get our OO $self.
	my $self = shift;

	# Prepare our default return value
	my $retval = undef;

	# Get the current time.
	my $cur_time = new RT::Date( $RT::Nobody );

	# Split apart the multiple time ranges.
	my @time_ranges = split( ':', $self->Argument );

	# Prepare 'now'.
	# We'll use localtime on the Unix() method of RT::Date
	# This returns a @list of time components.
	my @nowlist = localtime( $cur_time->Unix );

	# Build up a compare list.
	my @wantlist = ();

	# Names are not supported in Set::Crontab
	$wantlist[0] = $nowlist[1];	# minute 0-59
	$wantlist[1] = $nowlist[2];	# hour 0-23
	$wantlist[2] = $nowlist[3];	# day of month 1-31
	$wantlist[3] = $nowlist[4] + 1;	# month 1-12 (need to adjust)
	$wantlist[4] = $nowlist[6];	# day of week 0-7

	# What about the specific ranges?
	my @known_ranges = (
		[0..59],		# minute 0-59
		[0..23],		# hour 0-23
		[1..31],		# day of month 1-31
		[1..12],		# month 1-12
		[0..7],			# day of week 0-7

	# We loop through the various @time_ranges that we've found.

	foreach my $this_range ( @time_ranges ){

		# Remove leading or trailing space (we split() on that later)
		$this_range =~ s/^\s*//g;
		$this_range =~ s/\s*$//g;

		# $RT::Logger->debug("$self: Range is $this_range\n");

		# How many of the fields have we matched so far?
		my $matched = 0;

		# Split apart the fields based on whitespace.
		my @this_list = split( /\s+/, $this_range );

		# See if each field is in within range.
		my $loop = 0;
		while( ( $loop < scalar @wantlist ) && ( $loop < scalar @this_list ) ){
			my $tst = Set::Crontab->new( $this_list[$loop], $known_ranges[$loop] );
			# $RT::Logger->debug( "$self: Testing $wantlist[$loop] against $this_list[$loop]\n");
			if( $tst->contains( $wantlist[$loop] ) ){

			# Remember to increment the loop.

		# Now we check to see whether we matched them all.  
		# If we didn't, 'now' is obviously not within this time range.

		# Did we match them all?
		if( ( $matched == $loop ) && ( $loop == scalar @wantlist ) ){
			# We did.  Set our return value.

	# retval is undef when declared, and only incremented
	# if a time value matches.
	return( $retval );



-------------- next part --------------
#!/usr/bin/perl -w
# $Header: /raid/cvsroot/rt-addons/ScripConditions/OnOwnerChange/insert_condition.pl,v 1.1 2001/06/17 19:18:36 jesse Exp $
# RT is (c) 1996-2000 Jesse Vincent (jesse at fsck.com);
# IncomingEmail Condition by Bruce Campbell

package RT;
use strict;
use vars qw($VERSION $Handle $Nobody $SystemUser $item);

use lib "/home/rt2/lib";
use lib "/home/rt2/etc";

#This drags in  RT's config.pm
use config;
use Carp;

use RT::Handle;
use RT::User;
use RT::CurrentUser;

#connect to the db
$RT::Handle = new RT::Handle($RT::DatabaseType);

#Put together a current user object so we can create a User object
my $CurrentUser = new RT::CurrentUser();

#now that we bootstrapped that little bit, we can use the standard RT cli
# helpers  to do what we need

use RT::Interface::CLI  qw(CleanEnv LoadConfig DBConnect 
			   GetCurrentUser GetMessageContent);

#Clean out all the nasties from the environment

#Load etc/config.pm and drop privs

#Connect to the database and get RT::SystemUser and RT::Nobody loaded


# {{{ ScripConditions

# The Argument is a ':' seperated list of crontab-format ranges to determine
# whether 'Now' is within the range.
my @ScripConditions = (
			Name => 'OnCreateAnyTime',
			Description =>  'Matches at any point in time',
			ApplicableTransTypes =>  'Any',
			Argument => '* * * * *',  
			ExecModule => 'Crontab',

# }}}
print "Creating ScripConditions...";

use RT::ScripCondition;
for $item (@ScripConditions) {
    my $new_entry = new RT::ScripCondition($CurrentUser);
    my $return = $new_entry->Create(%$item);
    print $return.".";

print "done.\n";



More information about the Rt-devel mailing list