2005-12-16 18:05:29 +08:00
#!/usr/bin/perl -wT
#
# ==========================================================================
#
# ZoneMinder X10 Control Script, $Date$, $Revision$
# Copyright (C) 2003, 2004, 2005 Philip Coombes
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
# ==========================================================================
#
# This script controls the monitoring of the X10 interface and the consequent
# management of the ZM daemons based on the receipt of X10 signals.
#
use strict ;
use bytes ;
# ==========================================================================
#
# These are the elements you can edit to suit your installation
#
# ==========================================================================
2005-12-16 21:16:37 +08:00
use constant DBG_ID = > "zmx10" ; # Tag that appears in debug to identify source
2005-12-16 20:17:10 +08:00
use constant DBG_LEVEL = > 0 ; # 0 is errors, warnings and info only, > 0 for debug
2005-12-16 18:05:29 +08:00
# ==========================================================================
#
# Don't change anything below here
#
# ==========================================================================
use ZoneMinder ;
use POSIX ;
use Socket ;
use Getopt::Long ;
use Data::Dumper ;
2005-12-16 18:36:22 +08:00
use constant X10_SOCK_FILE = > ZM_PATH_SOCKS . '/zmx10.sock' ;
use constant X10_LOG_FILE = > ZM_PATH_LOGS . '/zmx10.log' ;
2005-12-16 18:05:29 +08:00
$| = 1 ;
$ ENV { PATH } = '/bin:/usr/bin' ;
$ ENV { SHELL } = '/bin/sh' if exists $ ENV { SHELL } ;
delete @ ENV { qw( IFS CDPATH ENV BASH_ENV ) } ;
sub Usage
{
print ( "
Usage: zmx10 . pl - c <command> , - - command = <command> [ - u < unit code > , - - unit - code = < unit code > ]
Parameters are : -
- c <command> , - - command = <command> - Command to issue , one of 'on' , 'off' , 'dim' , 'bright' , 'status' , 'shutdown'
- u < unit code > , - - unit - code = < unit code > - Unit code to act on required for all commands except 'status' ( optional ) and 'shutdown'
" ) ;
exit ( - 1 ) ;
}
2005-12-21 01:03:33 +08:00
zmDbgInit ( DBG_ID , DBG_LEVEL ) ;
2005-12-16 18:05:29 +08:00
my $ command ;
my $ unit_code ;
if ( ! GetOptions ( 'command=s' = > \ $ command , 'unit-code=i' = > \ $ unit_code ) )
{
Usage ( ) ;
}
die ( "No command given" ) unless ( $ command ) ;
die ( "No unit code given" ) unless ( $ unit_code || ( $ command =~ /(?:start|status|shutdown)/ ) ) ;
if ( $ command eq "start" )
{
X10Server:: runServer ( ) ;
exit ( ) ;
}
socket ( CLIENT , PF_UNIX , SOCK_STREAM , 0 ) or die ( "Can't open socket: $!" ) ;
my $ saddr = sockaddr_un ( X10_SOCK_FILE ) ;
if ( ! connect ( CLIENT , $ saddr ) )
{
# The server isn't there
print ( "Unable to connect, starting server\n" ) ;
close ( CLIENT ) ;
if ( my $ cpid = fork ( ) )
{
# Parent process just sleep and fall through
sleep ( 2 ) ;
socket ( CLIENT , PF_UNIX , SOCK_STREAM , 0 ) or die ( "Can't open socket: $!" ) ;
connect ( CLIENT , $ saddr ) or die ( "Can't connect: $!" ) ;
}
elsif ( defined ( $ cpid ) )
{
setpgrp ( ) ;
X10Server:: runServer ( ) ;
}
else
{
die ( "Can't fork: $!" ) ;
}
}
# The server is there, connect to it
#print( "Writing commands\n" );
CLIENT - > autoflush ( ) ;
my $ message = "$command" ;
$ message . = ";$unit_code" if ( $ unit_code ) ;
print ( CLIENT $ message ) ;
shutdown ( CLIENT , 1 ) ;
while ( my $ line = <CLIENT> )
{
chomp ( $ line ) ;
print ( "$line\n" ) ;
}
close ( CLIENT ) ;
#print( "Finished writing, bye\n" );
exit ;
#
# ==========================================================================
#
# This is the X10 Server package
#
# ==========================================================================
#
package X10Server ;
use strict ;
use bytes ;
2005-12-16 21:16:37 +08:00
use ZoneMinder ;
2005-12-16 18:05:29 +08:00
use POSIX ;
use DBI ;
use Socket ;
use X10::ActiveHome ;
use Data::Dumper ;
our $ dbh ;
our $ x10 ;
our % monitor_hash ;
our % device_hash ;
our % pending_tasks ;
sub runServer
{
my $ log_file = main:: X10_LOG_FILE ;
open ( LOG , ">>$log_file" ) or die ( "Can't open log file: $!" ) ;
open ( STDOUT , ">&LOG" ) || die ( "Can't dup stdout: $!" ) ;
select ( STDOUT ) ; $| = 1 ;
open ( STDERR , ">&LOG" ) || die ( "Can't dup stderr: $!" ) ;
select ( STDERR ) ; $| = 1 ;
select ( LOG ) ; $| = 1 ;
2005-12-16 21:36:24 +08:00
Info ( "X10 server starting\n" ) ;
2005-12-16 18:05:29 +08:00
2005-12-20 00:58:30 +08:00
socket ( SERVER , PF_UNIX , SOCK_STREAM , 0 ) or Fatal ( "Can't open socket: $!" ) ;
2005-12-16 18:05:29 +08:00
unlink ( main:: X10_SOCK_FILE ) ;
my $ saddr = sockaddr_un ( main:: X10_SOCK_FILE ) ;
2005-12-20 00:58:30 +08:00
bind ( SERVER , $ saddr ) or Fatal ( "Can't bind: $!" ) ;
listen ( SERVER , SOMAXCONN ) or Fatal ( "Can't listen: $!" ) ;
2005-12-16 18:05:29 +08:00
2005-12-23 18:45:43 +08:00
$ dbh = DBI - > connect ( "DBI:mysql:database=" . ZM_DB_NAME . ";host=" . ZM_DB_HOST , ZM_DB_USER , ZM_DB_PASS ) ;
2005-12-16 18:05:29 +08:00
2005-12-23 18:45:43 +08:00
$ x10 = new X10:: ActiveHome ( port = > ZM_X10_DEVICE , house_code = > ZM_X10_HOUSE_CODE , debug = > 1 ) ;
2005-12-16 18:05:29 +08:00
loadTasks ( ) ;
$ x10 - > register_listener ( \ & x10listen ) ;
my $ rin = '' ;
vec ( $ rin , fileno ( SERVER ) , 1 ) = 1 ;
vec ( $ rin , $ x10 - > select_fds ( ) , 1 ) = 1 ;
my $ timeout = 0.2 ;
#print( "F:".fileno(SERVER)."\n" );
my $ reload = undef ;
my $ reload_count = 0 ;
2005-12-23 18:45:43 +08:00
my $ reload_limit = & ZM_X10_DB_RELOAD_INTERVAL / $ timeout ;
2005-12-16 18:05:29 +08:00
while ( 1 )
{
my $ nfound = select ( my $ rout = $ rin , undef , undef , $ timeout ) ;
#print( "Off select, NF:$nfound, ER:$!\n" );
#print( vec( $rout, fileno(SERVER),1)."\n" );
#print( vec( $rout, $x10->select_fds(),1)."\n" );
if ( $ nfound > 0 )
{
if ( vec ( $ rout , fileno ( SERVER ) , 1 ) )
{
my $ paddr = accept ( CLIENT , SERVER ) ;
my $ message = <CLIENT> ;
my ( $ command , $ unit_code ) = split ( ';' , $ message ) ;
my $ device ;
if ( defined ( $ unit_code ) )
{
if ( $ unit_code < 1 || $ unit_code > 16 )
{
dprint ( "Error, invalid unit code '$unit_code'\n" ) ;
next ;
}
$ device = $ device_hash { $ unit_code } ;
if ( ! $ device )
{
$ device = $ device_hash { $ unit_code } = { appliance = > $ x10 - > Appliance ( unit_code = > $ unit_code ) , status = > 'unknown' } ;
}
}
my $ result ;
if ( $ command eq 'on' )
{
$ result = $ device - > { appliance } - > on ( ) ;
}
elsif ( $ command eq 'off' )
{
$ result = $ device - > { appliance } - > off ( ) ;
}
#elsif ( $command eq 'dim' )
#{
#$result = $device->{appliance}->dim();
#}
#elsif ( $command eq 'bright' )
#{
#$result = $device->{appliance}->bright();
#}
elsif ( $ command eq 'status' )
{
if ( $ device )
{
dprint ( $ unit_code . " " . $ device - > { status } . "\n" ) ;
}
else
{
foreach my $ unit_code ( sort ( keys ( % device_hash ) ) )
{
my $ device = $ device_hash { $ unit_code } ;
dprint ( $ unit_code . " " . $ device - > { status } . "\n" ) ;
}
}
}
elsif ( $ command eq 'shutdown' )
{
last ;
}
else
{
dprint ( "Error, invalid command '$command'\n" ) ;
}
if ( defined ( $ result ) )
{
if ( 1 || $ result )
{
$ device - > { status } = uc ( $ command ) ;
dprint ( $ device - > { appliance } - > address ( ) . " $command, ok\n" ) ;
#x10listen( new X10::Event( sprintf("%s %s", $device->{appliance}->address, uc($command) ) ) );
}
else
{
dprint ( $ device - > { appliance } - > address ( ) . " $command, failed\n" ) ;
}
}
close ( CLIENT ) ;
}
elsif ( vec ( $ rout , $ x10 - > select_fds ( ) , 1 ) )
{
$ x10 - > handle_input ( ) ;
}
else
{
2005-12-20 00:58:30 +08:00
Fatal ( "Bogus descriptor" ) ;
2005-12-16 18:05:29 +08:00
}
}
elsif ( $ nfound < 0 )
{
2005-12-20 00:58:30 +08:00
Fatal ( "Can't select: $!" ) ;
2005-12-16 18:05:29 +08:00
}
else
{
#print( "Select timed out\n" );
# Check for state changes
foreach my $ monitor_id ( sort ( keys ( % monitor_hash ) ) )
{
my $ monitor = $ monitor_hash { $ monitor_id } ;
2005-12-23 01:01:43 +08:00
my $ state = zmGetMonitorState ( $ monitor ) ;
if ( ! defined ( $ state ) )
2005-12-16 18:05:29 +08:00
{
$ reload = ! undef ;
next ;
}
if ( defined ( $ monitor - > { LastState } ) )
{
my $ task_list ;
2005-12-23 01:01:43 +08:00
if ( $ state == STATE_ALARM && $ monitor - > { LastState } == STATE_IDLE ) # Gone into alarm state
2005-12-16 18:05:29 +08:00
{
2005-12-16 20:17:10 +08:00
Debug ( "Applying ON_list for $monitor_id\n" ) ;
2005-12-16 18:05:29 +08:00
$ task_list = $ monitor - > { "ON_list" } ;
}
2005-12-23 01:01:43 +08:00
elsif ( $ state == STATE_IDLE && $ monitor - > { LastState } > STATE_IDLE ) # Come out of alarm state
2005-12-16 18:05:29 +08:00
{
2005-12-16 20:17:10 +08:00
Debug ( "Applying OFF_list for $monitor_id\n" ) ;
2005-12-16 18:05:29 +08:00
$ task_list = $ monitor - > { "OFF_list" } ;
}
if ( $ task_list )
{
foreach my $ task ( @$ task_list )
{
processTask ( $ task ) ;
}
}
}
$ monitor - > { LastState } = $ state ;
}
# Check for pending tasks
my $ now = time ( ) ;
foreach my $ activation_time ( sort ( keys ( % pending_tasks ) ) )
{
last if ( $ activation_time > $ now ) ;
my $ pending_list = $ pending_tasks { $ activation_time } ;
foreach my $ task ( @$ pending_list )
{
processTask ( $ task ) ;
}
delete ( $ pending_tasks { $ activation_time } ) ;
}
if ( $ reload || + + $ reload_count >= $ reload_limit )
{
loadTasks ( ) ;
$ reload = undef ;
$ reload_count = 0 ;
}
}
}
2005-12-16 21:36:24 +08:00
Info ( "X10 server exiting\n" ) ;
2005-12-16 18:05:29 +08:00
close ( LOG ) ;
close ( SERVER ) ;
exit ( ) ;
}
sub addToDeviceList
{
my $ unit_code = shift ;
my $ event = shift ;
my $ monitor = shift ;
my $ function = shift ;
my $ limit = shift ;
2005-12-16 20:17:10 +08:00
Debug ( "Adding to device list, uc:$unit_code, ev:$event, mo:$monitor, fu:$function, li:$limit\n" ) ;
2005-12-16 18:05:29 +08:00
my $ device = $ device_hash { $ unit_code } ;
if ( ! $ device )
{
$ device = $ device_hash { $ unit_code } = { appliance = > $ x10 - > Appliance ( unit_code = > $ unit_code ) , status = > 'unknown' } ;
}
my $ task = { type = > "device" , monitor = > $ monitor , function = > $ function } ;
if ( $ limit )
{
$ task - > { limit } = $ limit
}
my $ task_list = $ device - > { $ event . "_list" } ;
if ( ! $ task_list )
{
$ task_list = $ device - > { $ event . "_list" } = [] ;
}
push ( @$ task_list , $ task ) ;
}
sub addToMonitorList
{
my $ monitor = shift ;
my $ event = shift ;
my $ unit_code = shift ;
my $ function = shift ;
my $ limit = shift ;
2005-12-16 20:17:10 +08:00
Debug ( "Adding to monitor list, uc:$unit_code, ev:$event, mo:$monitor, fu:$function, li:$limit\n" ) ;
2005-12-16 18:05:29 +08:00
my $ device = $ device_hash { $ unit_code } ;
if ( ! $ device )
{
$ device = $ device_hash { $ unit_code } = { appliance = > $ x10 - > Appliance ( unit_code = > $ unit_code ) , status = > 'unknown' } ;
}
my $ task = { type = > "monitor" , device = > $ device , function = > $ function } ;
if ( $ limit )
{
$ task - > { limit } = $ limit ;
}
my $ task_list = $ monitor - > { $ event . "_list" } ;
if ( ! $ task_list )
{
$ task_list = $ monitor - > { $ event . "_list" } = [] ;
}
push ( @$ task_list , $ task ) ;
}
sub loadTasks
{
% monitor_hash = ( ) ;
2005-12-16 20:17:10 +08:00
Debug ( "Loading tasks\n" ) ;
2005-12-16 18:05:29 +08:00
# Clear out all old device task lists
foreach my $ unit_code ( sort ( keys ( % device_hash ) ) )
{
my $ device = $ device_hash { $ unit_code } ;
$ device - > { ON_list } = [] ;
$ device - > { OFF_list } = [] ;
}
2005-12-23 18:45:43 +08:00
my $ sql = "select M.*,T.* from Monitors as M inner join TriggersX10 as T on (M.Id = T.MonitorId) where find_in_set( M.Function, 'Modect,Record,Mocord,Nodect' ) and M.Enabled = 1 and find_in_set( 'X10', M.Triggers )" ;
2005-12-20 00:58:30 +08:00
my $ sth = $ dbh - > prepare_cached ( $ sql ) or Fatal ( "Can't prepare '$sql': " . $ dbh - > errstr ( ) ) ;
my $ res = $ sth - > execute ( ) or Fatal ( "Can't execute: " . $ sth - > errstr ( ) ) ;
2005-12-16 18:05:29 +08:00
while ( my $ monitor = $ sth - > fetchrow_hashref ( ) )
{
2005-12-23 01:01:43 +08:00
next if ( ! zmShmGet ( $ monitor ) ) ; # Check shared memory ok
2005-12-16 18:05:29 +08:00
$ monitor_hash { $ monitor - > { Id } } = $ monitor ;
if ( $ monitor - > { Activation } )
{
2005-12-16 20:17:10 +08:00
Debug ( "$monitor->{Name} has active string '$monitor->{Activation}'\n" ) ;
2005-12-16 18:05:29 +08:00
foreach my $ code_string ( split ( ',' , $ monitor - > { Activation } ) )
{
2005-12-16 20:17:10 +08:00
#Debug( "Code string: $code_string\n" );
2005-12-16 18:05:29 +08:00
my ( $ invert , $ unit_code , $ modifier , $ limit ) = ( $ code_string =~ /^([!~])?(\d+)(?:([+-])(\d+)?)?$/ ) ;
$ limit = 0 if ( ! $ limit ) ;
if ( $ unit_code )
{
if ( ! $ modifier || $ modifier eq '+' )
{
addToDeviceList ( $ unit_code , "ON" , $ monitor , ! $ invert ? "start_active" : "stop_active" , $ limit ) ;
}
if ( ! $ modifier || $ modifier eq '-' )
{
addToDeviceList ( $ unit_code , "OFF" , $ monitor , ! $ invert ? "stop_active" : "start_active" , $ limit ) ;
}
}
}
}
if ( $ monitor - > { AlarmInput } )
{
2005-12-16 20:17:10 +08:00
Debug ( "$monitor->{Name} has alarm input string '$monitor->{AlarmInput}'\n" ) ;
2005-12-16 18:05:29 +08:00
foreach my $ code_string ( split ( ',' , $ monitor - > { AlarmInput } ) )
{
2005-12-16 20:17:10 +08:00
#Debug( "Code string: $code_string\n" );
2005-12-16 18:05:29 +08:00
my ( $ invert , $ unit_code , $ modifier , $ limit ) = ( $ code_string =~ /^([!~])?(\d+)(?:([+-])(\d+)?)?$/ ) ;
$ limit = 0 if ( ! $ limit ) ;
if ( $ unit_code )
{
if ( ! $ modifier || $ modifier eq '+' )
{
addToDeviceList ( $ unit_code , "ON" , $ monitor , ! $ invert ? "start_alarm" : "stop_alarm" , $ limit ) ;
}
if ( ! $ modifier || $ modifier eq '-' )
{
addToDeviceList ( $ unit_code , "OFF" , $ monitor , ! $ invert ? "stop_alarm" : "start_alarm" , $ limit ) ;
}
}
}
}
if ( $ monitor - > { AlarmOutput } )
{
2005-12-16 20:17:10 +08:00
Debug ( "$monitor->{Name} has alarm output string '$monitor->{AlarmOutput}'\n" ) ;
2005-12-16 18:05:29 +08:00
foreach my $ code_string ( split ( ',' , $ monitor - > { AlarmOutput } ) )
{
2005-12-16 20:17:10 +08:00
#Debug( "Code string: $code_string\n" );
2005-12-16 18:05:29 +08:00
my ( $ invert , $ unit_code , $ modifier , $ limit ) = ( $ code_string =~ /^([!~])?(\d+)(?:([+-])(\d+)?)?$/ ) ;
$ limit = 0 if ( ! $ limit ) ;
if ( $ unit_code )
{
if ( ! $ modifier || $ modifier eq '+' )
{
addToMonitorList ( $ monitor , "ON" , $ unit_code , ! $ invert ? "on" : "off" , $ limit ) ;
}
if ( ! $ modifier || $ modifier eq '-' )
{
addToMonitorList ( $ monitor , "OFF" , $ unit_code , ! $ invert ? "off" : "on" , $ limit ) ;
}
}
}
}
}
}
sub addPendingTask
{
my $ task = shift ;
# Check whether we are just extending a previous pending task
# and remove it if it's there
foreach my $ activation_time ( sort ( keys ( % pending_tasks ) ) )
{
my $ pending_list = $ pending_tasks { $ activation_time } ;
my $ new_pending_list = [] ;
foreach my $ pending_task ( @$ pending_list )
{
if ( $ task - > { type } ne $ pending_task - > { type } )
{
push ( @$ new_pending_list , $ pending_task )
}
elsif ( $ task - > { type } eq "device" )
{
if ( ( $ task - > { monitor } - > { Id } != $ pending_task - > { monitor } - > { Id } )
|| ( $ task - > { function } ne $ pending_task - > { function } ) )
{
push ( @$ new_pending_list , $ pending_task )
}
}
elsif ( $ task - > { type } eq "monitor" )
{
if ( ( $ task - > { device } - > { appliance } - > unit_code ( ) != $ pending_task - > { device } - > { appliance } - > unit_code ( ) )
|| ( $ task - > { function } ne $ pending_task - > { function } ) )
{
push ( @$ new_pending_list , $ pending_task )
}
}
}
if ( @$ new_pending_list )
{
$ pending_tasks { $ activation_time } = $ new_pending_list ;
}
else
{
delete ( $ pending_tasks { $ activation_time } ) ;
}
}
my $ end_time = time ( ) + $ task - > { limit } ;
my $ pending_list = $ pending_tasks { $ end_time } ;
if ( ! $ pending_list )
{
$ pending_list = $ pending_tasks { $ end_time } = [] ;
}
my $ pending_task ;
if ( $ task - > { type } eq "device" )
{
$ pending_task = { type = > $ task - > { type } , monitor = > $ task - > { monitor } , function = > $ task - > { function } } ;
$ pending_task - > { function } =~ s/start/stop/ ;
}
elsif ( $ task - > { type } eq "monitor" )
{
$ pending_task = { type = > $ task - > { type } , device = > $ task - > { device } , function = > $ task - > { function } } ;
$ pending_task - > { function } =~ s/on/off/ ;
}
push ( @$ pending_list , $ pending_task ) ;
}
sub processTask
{
my $ task = shift ;
if ( $ task - > { type } eq "device" )
{
my ( $ instruction , $ class ) = ( $ task - > { function } =~ /^(.+)_(.+)$/ ) ;
if ( $ class eq "active" )
{
if ( $ instruction eq "start" )
{
2005-12-23 01:01:43 +08:00
zmMonitorEnable ( $ task - > { monitor } ) ;
2005-12-16 18:05:29 +08:00
if ( $ task - > { limit } )
{
addPendingTask ( $ task ) ;
}
}
elsif ( $ instruction eq "stop" )
{
2005-12-23 01:01:43 +08:00
zmMonitorDisable ( $ task - > { monitor } ) ;
2005-12-16 18:05:29 +08:00
}
}
elsif ( $ class eq "alarm" )
{
if ( $ instruction eq "start" )
{
2005-12-23 01:01:43 +08:00
zmTriggerEventOn ( $ task - > { monitor } , 0 , "X10" ) ;
2005-12-16 18:05:29 +08:00
if ( $ task - > { limit } )
{
addPendingTask ( $ task ) ;
}
}
elsif ( $ instruction eq "stop" )
{
2005-12-23 01:01:43 +08:00
zmTriggerEventCancel ( $ task - > { monitor } ) ;
2005-12-16 18:05:29 +08:00
}
}
}
elsif ( $ task - > { type } eq "monitor" )
{
if ( $ task - > { function } eq "on" )
{
$ task - > { device } - > { appliance } - > on ( ) ;
if ( $ task - > { limit } )
{
addPendingTask ( $ task ) ;
}
}
elsif ( $ task - > { function } eq "off" )
{
$ task - > { device } - > { appliance } - > off ( ) ;
}
}
}
sub dprint
{
if ( fileno ( CLIENT ) )
{
print CLIENT @ _
}
2005-12-16 20:17:10 +08:00
Info ( @ _ ) ;
2005-12-16 18:05:29 +08:00
}
sub x10listen
{
foreach my $ event ( @ _ )
{
#print( Data::Dumper( $_ )."\n" );
2005-12-23 18:45:43 +08:00
if ( $ event - > house_code ( ) eq ZM_X10_HOUSE_CODE )
2005-12-16 18:05:29 +08:00
{
my $ unit_code = $ event - > unit_code ( ) ;
my $ device = $ device_hash { $ unit_code } ;
if ( ! $ device )
{
$ device = $ device_hash { $ unit_code } = { appliance = > $ x10 - > Appliance ( unit_code = > $ unit_code ) , status = > 'unknown' } ;
}
next if ( $ event - > func ( ) !~ /(?:ON|OFF)/ ) ;
$ device - > { status } = $ event - > func ( ) ;
my $ task_list = $ device - > { $ event - > func ( ) . "_list" } ;
if ( $ task_list )
{
foreach my $ task ( @$ task_list )
{
processTask ( $ task ) ;
}
}
}
2005-12-16 21:36:24 +08:00
Info ( "Got event - " . $ event - > as_string ( ) . "\n" ) ;
2005-12-16 18:05:29 +08:00
}
}
1 ;