Out-Of-Office Processing with Asterisk
Pages: 1, 2
Step 1.5: Converting Time Strings to Epoch Time
In the previous section, I assumed an AGI function that would convert a time specification into an epoch time. The current development version of Asterisk adds the STRPTIME function as a gateway to the operating system's function of the same name, but I am not using the current development version. Rather than upgrade, I chose to write a short AGI program in Perl to handle the conversion for me.
The program assumes the time string is followed by a time-string specifier beginning with the % character. To separate the time from the specifier, it joins all the arguments together and takes everything to the left of the first % as the time. It then uses the Time::Piece function to convert the string into an epoch time. Time::Piece is smart enough to process a string with trailing white space, so there is no need to clean up after it.
# Asterisk AGI program as interface to STRPTIME() C library function
#
# Matthew Gast
#
# This program takes as arguments a time string format and a specification
# in standard C function calls, split by the pipe character ("|") and
# returns the epoch as an Asterisk channel variable
use strict;
use Asterisk::AGI;
use Time::Piece;
my $AGI = new Asterisk::AGI;
my %input = $AGI->ReadParse();
$AGI->verbose("strptime AGI converter started.\n",1);
# Create time string and specifier from the arguments
my $argumentline=join(' ',@ARGV);
my @splitargs=split(/%/,$argumentline);
my $time = $splitargs[0];
my $spec = '%' . join('%',@splitargs[1..$#splitargs]);
$AGI->verbose("Will get epoch of --$time-- with specification --$spec--\n",1);
my $t = Time::Piece->strptime($time,$spec);
my $epoch = $t->epoch;
my $offset = $t->tzoffset;
$AGI->verbose("UTC epoch value is $epoch \n",1);
$AGI->verbose("Offset to local time is $offset\n",1);
$epoch = $epoch - $offset;
$AGI->verbose ("TZ-corrected value is $epoch, setting RESULT_EPOCH\n",1);
$AGI->set_variable("RESULT_EPOCH",$epoch);
exit(0);
Step 2: Checking Out-of-Office Status
Once the epoch time for the return to the office is in AstDB, it's easy to handle. Every time an extension would be dialed, the current time should be checked against the return time. For reuse purposes, I have defined a macro named checkoutofoffice that takes the extension as an argument.
The flow through the macro is straightforward. If no record in the out-of-office database exists, the extension should ring normally. It is only when a record exists and the time is in the future that the extension should be marked as out of the office. The macro sets the SILENT_RING variable as a meta-control. Different SIP devices have different ways to suppress rings, so I use the SILENT_RING channel variable to tell the final step in connecting an extension to use the appropriate method for the SIP device in question. The macro also sets the OUTOFOFFICE variable so that rather than a silent ring, the device can be prevented from ringing at all.
macro checkoutofoffice (ext) {
// This macro checks whether or not an extension users is "out of the office,"
// and therefore, should not be rung.
//
// Input: Extension number to check.
// Output: Sets the SILENT_RING and OUTOFOFFICE channel variables to true
// if the user of that extension is out of the office.
Set(NAME=macro-checkoutofoffice);
NoOp(${NAME} - started);
if ( ${DB_EXISTS(ooo/${ext})} ) {
Gosub(db-exists);
} else {
NoOp(${NAME} - No OOO record found for ${ext});
};
goto end;
db-exists:
NoOp(${NAME} - OOO record found for ${ext});
Set(OOO_UNTIL=${DB(ooo/${ext})});
if ( ${EPOCH} < ${OOO_UNTIL} ) {
NoOp(${NAME} - ${ext} is out of the office - no ring);
Set(__SILENT_RING=true);
Set(__OUTOFOFFICE=true);
} else {
NoOp(${NAME} - ${ext} is back in the office - ring active);
};
Return;
end:
// finish
NoOp(${NAME} - ended);
};
Any extension that should have out-of-office processing then needs to call the out-of-office check before connecting the call. A very simple example would be the following extension code, which checks the out-of-office status and prevents connecting the call if the extension is marked as away:
1001 => {
&checkoutofoffice(${EXTEN});
if (${ISNULL(${OUTOFOFFICE})}) {
// continue to connect call
Dial(SIP/1001,20);
} else {
NoOp(Extension ${EXTEN} is out of the office, no connection attempt);
};
Voicemail(u1001);
};
My Asterisk system implements a "follow-me" system that rings multiple extensions in turn. One of the advantages to skipping over a home extension when I am out of the office is that callers will more quickly reach me.
Matthew Gast is the director of product management at Aerohive Networks responsible for the software that powers Aerohive's networking devices.
Return to O'Reilly Emerging Telephony.









I like your approach!