Time-Zone Processing with Asterisk, Part II

Part II of our series on time-zone processing with Asterisk.
Making the Call

Every registration event triggers a “call” event to happen after a delay. The delay is used to collect information used to determine whether to initiate a call. The setup telephone call should be triggered only if the time-zone setup has expired or the SIP device has changed its IP address and the record is no longer valid.

Because the call state handler is placed in the queue for execution by the registration handler, it does have one argument, the extension number of the call in question. The extension can be retrieved as $_[ARG0]. All the data we have added to the heap by processing the database responses and SIP data request is also readily available:

sub call_state_handler {

  # Get extension out of arguments to function
  my $exten = $_[ARG0];

  my $hp = $_[HEAP];
  # Variables we use to determine if the call is required
  my $skew = $hp->{$exten.'-TIMESKEW'};
  my $skew_addr = $hp->{$exten.'-TIMESKEW_ADDR'};
  my $skew_start = $hp->{$exten.'-TIMESKEW_START'};
  my $skew_end = $hp->{$exten.'-TIMESKEW_END'};
  my $sip_peer_ip = $hp->{'SIP-Peer-IP'};
  my $now = time();

To determine whether the call is required, the handler compares the current time with the expiration of the time-zone offset record and the IP address of the SIP device against the IP address stored in the time-zone offset record. If the IP addresses match and the offset has not expired, no call is required. Otherwise, a call is needed and made with the makeTZSetupCall function:

 if ($now > $skew_end) {
   debug_print("Make call - offset has expired.\n");
   makeTZSetupCall($_[HEAP], $exten);
 } elsif (!($skew_addr eq $sip_peer_ip)) {
   debug_print("Make call - SIP IP addr changed\n");
   makeTZSetupCall($_[HEAP], $exten);
 } else {
   debug_print("No call -- record OK & same IP\n");

As a final step, the handler needs to remove the variables placed on the heap. The heap is used only to pass variables between state handlers, and the variables are not needed once that function is complete. Each of the variables can be undefined with the undef function:

  # Need to clean up heap
  undef $_[HEAP]->{$exten.'-TIMESKEW'};
  undef $_[HEAP]->{$exten.'-TIMESKEW_ADDR'};
  undef $_[HEAP]->{$exten.'-TIMESKEW_START'};
  undef $_[HEAP]->{$exten.'-TIMESKEW_END'};
  undef $_[HEAP]->{'SIP-Peer-IP'};

} # call_state_handler

Making the setup call uses the Asterisk Manager's Originate command, but it is protected by one final check. I've defined a set of extensions as the remote channel list. Only extensions on the remote channel list will have time-zone setup calls made to them. Initially, the list consists of my softphone and an analog telephone adapter, but I may need to add more in the future. Before originating the call, I ensure that the number is on a remote channel list, which is defined in the global array REMOTE_CHANNEL_LIST. The Originate command can take several arguments as well. The extension, priority and context must refer to where the setup menu is defined. In my case, these values are extension *89 (for *-T-Z), priority 1 and the context from-internal. I also can supply the caller-ID text of “Time Zone Setup” to the phone I am calling:

sub makeTZSetupCall {
  my $heap = $_[0];
  my $exten = $_[1];
  my $callOK = 0;

  # Check that extension to call is a remote channel
  foreach $number (@REMOTE_CHANNEL_LIST) {
    if ($number == $exten) {
      $callOK = 1;

  if ($callOK) {
                        'Action' => 'Originate',
                        'Channel' => 'SIP/'.$exten,
                        'Context' => $TZ_CONTEXT,
                        'Exten' => $TZ_EXTEN,
                        'Priority' => $TZ_PRIORITY,
                        'Callerid' => $CALLERID,

} # makeTZSetupCall

If the Originate command is triggered, the newly registered telephone rings, and I go through the voice menu described in last month's article.

Matthew Gast is the author of the leading technical book on wireless LANs, 802.11 Wireless Networks: The Definitive Guide (O'Reilly Media). He can be reached at matthew.gast@gmail.com, but only when he is close to sea level.