2003-02-04 15:48:42 +00:00
/*
2005-09-14 20:46:50 +00:00
* Asterisk - - An open source telephony toolkit .
2003-02-04 15:48:42 +00:00
*
2005-09-14 20:46:50 +00:00
* Copyright ( C ) 1999 - 2005 , Digium , Inc .
2003-02-04 15:48:42 +00:00
*
* Mark Spencer < markster @ digium . com >
*
2005-09-14 20:46:50 +00:00
* See http : //www.asterisk.org for more information about
* the Asterisk project . Please do not directly contact
* any of the maintainers of this project for assistance ;
* the project provides a web site , mailing lists and IRC
* channels for your use .
*
2003-02-04 15:48:42 +00:00
* This program is free software , distributed under the terms of
2005-09-14 20:46:50 +00:00
* the GNU General Public License Version 2. See the LICENSE file
* at the top of the source tree .
*/
2005-10-24 20:12:06 +00:00
/*! \file
2005-09-14 20:46:50 +00:00
*
2005-10-24 20:12:06 +00:00
* \ brief Full - featured outgoing call spool support
2005-09-14 20:46:50 +00:00
*
2003-02-04 15:48:42 +00:00
*/
2006-06-07 18:54:56 +00:00
# include "asterisk.h"
ASTERISK_FILE_VERSION ( __FILE__ , " $Revision$ " )
2003-02-04 15:48:42 +00:00
# include <sys/stat.h>
# include <errno.h>
# include <time.h>
# include <utime.h>
# include <stdlib.h>
# include <unistd.h>
# include <dirent.h>
# include <string.h>
# include <string.h>
# include <stdio.h>
# include <unistd.h>
2005-06-06 22:12:19 +00:00
# include "asterisk/lock.h"
# include "asterisk/file.h"
# include "asterisk/logger.h"
# include "asterisk/channel.h"
# include "asterisk/callerid.h"
# include "asterisk/pbx.h"
# include "asterisk/module.h"
# include "asterisk/options.h"
# include "asterisk/utils.h"
2003-02-04 15:48:42 +00:00
/*
* pbx_spool is similar in spirit to qcall , but with substantially enhanced functionality . . .
* The spool file contains a header
*/
2006-05-19 22:51:44 +00:00
enum {
/*! Always delete the call file after a call succeeds or the
* maximum number of retries is exceeded , even if the
* modification time of the call file is in the future .
*/
2006-05-25 17:58:55 +00:00
SPOOL_FLAG_ALWAYS_DELETE = ( 1 < < 0 ) ,
/* Don't unlink the call file after processing, move in qdonedir */
SPOOL_FLAG_ARCHIVE = ( 1 < < 1 )
2006-05-19 22:51:44 +00:00
} ;
2003-02-04 15:48:42 +00:00
static char qdir [ 255 ] ;
2006-05-25 17:58:55 +00:00
static char qdonedir [ 255 ] ;
2003-02-04 15:48:42 +00:00
struct outgoing {
2006-02-24 10:50:43 +00:00
char fn [ 256 ] ;
2003-02-04 15:48:42 +00:00
/* Current number of retries */
int retries ;
/* Maximum number of retries permitted */
int maxretries ;
/* How long to wait between retries (in seconds) */
int retrytime ;
/* How long to wait for an answer */
int waittime ;
2004-03-20 21:13:12 +00:00
/* PID which is currently calling */
2006-05-08 12:32:44 +00:00
long callingpid ;
2003-02-04 15:48:42 +00:00
/* What to connect to outgoing */
char tech [ 256 ] ;
char dest [ 256 ] ;
/* If application */
char app [ 256 ] ;
char data [ 256 ] ;
/* If extension/context/priority */
2006-02-24 10:50:43 +00:00
char exten [ 256 ] ;
char context [ 256 ] ;
2003-02-04 15:48:42 +00:00
int priority ;
/* CallerID Information */
2004-10-02 00:58:31 +00:00
char cid_num [ 256 ] ;
char cid_name [ 256 ] ;
2003-02-04 15:48:42 +00:00
2006-02-11 18:31:59 +00:00
/* account code */
char account [ AST_MAX_ACCOUNT_CODE ] ;
2005-07-15 23:24:51 +00:00
/* Variables and Functions */
struct ast_variable * vars ;
2003-02-04 15:48:42 +00:00
/* Maximum length of call */
int maxlen ;
2006-05-19 22:51:44 +00:00
/* options */
struct ast_flags options ;
2003-02-04 15:48:42 +00:00
} ;
static void init_outgoing ( struct outgoing * o )
{
memset ( o , 0 , sizeof ( struct outgoing ) ) ;
o - > priority = 1 ;
o - > retrytime = 300 ;
o - > waittime = 45 ;
2006-05-19 22:51:44 +00:00
ast_set_flag ( & o - > options , SPOOL_FLAG_ALWAYS_DELETE ) ;
2003-02-04 15:48:42 +00:00
}
2005-10-11 20:44:23 +00:00
static void free_outgoing ( struct outgoing * o )
{
free ( o ) ;
}
2003-02-04 15:48:42 +00:00
static int apply_outgoing ( struct outgoing * o , char * fn , FILE * f )
{
char buf [ 256 ] ;
char * c , * c2 ;
int lineno = 0 ;
2005-07-15 23:24:51 +00:00
struct ast_variable * var ;
2005-04-01 21:31:12 +00:00
while ( fgets ( buf , sizeof ( buf ) , f ) ) {
2003-02-04 15:48:42 +00:00
lineno + + ;
2005-07-15 00:15:14 +00:00
/* Trim comments */
c = buf ;
while ( ( c = strchr ( c , ' # ' ) ) ) {
if ( ( c = = buf ) | | ( * ( c - 1 ) = = ' ' ) | | ( * ( c - 1 ) = = ' \t ' ) )
* c = ' \0 ' ;
else
c + + ;
}
2005-10-11 20:52:37 +00:00
c = buf ;
while ( ( c = strchr ( c , ' ; ' ) ) ) {
if ( ( c > buf ) & & ( c [ - 1 ] = = ' \\ ' ) ) {
memmove ( c - 1 , c , strlen ( c ) + 1 ) ;
c + + ;
} else {
* c = ' \0 ' ;
break ;
}
}
2003-02-04 15:48:42 +00:00
2005-07-15 00:15:14 +00:00
/* Trim trailing white space */
while ( ! ast_strlen_zero ( buf ) & & buf [ strlen ( buf ) - 1 ] < 33 )
buf [ strlen ( buf ) - 1 ] = ' \0 ' ;
if ( ! ast_strlen_zero ( buf ) ) {
c = strchr ( buf , ' : ' ) ;
if ( c ) {
* c = ' \0 ' ;
c + + ;
while ( ( * c ) & & ( * c < 33 ) )
2003-02-04 15:48:42 +00:00
c + + ;
#if 0
2005-07-15 00:15:14 +00:00
printf ( " '%s' is '%s' at line %d \n " , buf , c , lineno ) ;
# endif
if ( ! strcasecmp ( buf , " channel " ) ) {
2006-10-25 14:44:50 +00:00
ast_copy_string ( o - > tech , c , sizeof ( o - > tech ) ) ;
2005-07-15 00:15:14 +00:00
if ( ( c2 = strchr ( o - > tech , ' / ' ) ) ) {
* c2 = ' \0 ' ;
c2 + + ;
2006-10-25 14:44:50 +00:00
ast_copy_string ( o - > dest , c2 , sizeof ( o - > dest ) ) ;
2003-02-04 15:48:42 +00:00
} else {
2005-07-15 00:15:14 +00:00
ast_log ( LOG_NOTICE , " Channel should be in form Tech/Dest at line %d of %s \n " , lineno , fn ) ;
o - > tech [ 0 ] = ' \0 ' ;
}
} else if ( ! strcasecmp ( buf , " callerid " ) ) {
ast_callerid_split ( c , o - > cid_name , sizeof ( o - > cid_name ) , o - > cid_num , sizeof ( o - > cid_num ) ) ;
} else if ( ! strcasecmp ( buf , " application " ) ) {
2006-10-25 14:44:50 +00:00
ast_copy_string ( o - > app , c , sizeof ( o - > app ) ) ;
2005-07-15 00:15:14 +00:00
} else if ( ! strcasecmp ( buf , " data " ) ) {
2006-10-25 14:44:50 +00:00
ast_copy_string ( o - > data , c , sizeof ( o - > data ) ) ;
2005-07-15 00:15:14 +00:00
} else if ( ! strcasecmp ( buf , " maxretries " ) ) {
if ( sscanf ( c , " %d " , & o - > maxretries ) ! = 1 ) {
ast_log ( LOG_WARNING , " Invalid max retries at line %d of %s \n " , lineno , fn ) ;
o - > maxretries = 0 ;
}
} else if ( ! strcasecmp ( buf , " context " ) ) {
2006-10-25 14:44:50 +00:00
ast_copy_string ( o - > context , c , sizeof ( o - > context ) ) ;
2005-07-15 00:15:14 +00:00
} else if ( ! strcasecmp ( buf , " extension " ) ) {
2006-10-25 14:44:50 +00:00
ast_copy_string ( o - > exten , c , sizeof ( o - > exten ) ) ;
2005-07-15 00:15:14 +00:00
} else if ( ! strcasecmp ( buf , " priority " ) ) {
if ( ( sscanf ( c , " %d " , & o - > priority ) ! = 1 ) | | ( o - > priority < 1 ) ) {
ast_log ( LOG_WARNING , " Invalid priority at line %d of %s \n " , lineno , fn ) ;
o - > priority = 1 ;
}
} else if ( ! strcasecmp ( buf , " retrytime " ) ) {
if ( ( sscanf ( c , " %d " , & o - > retrytime ) ! = 1 ) | | ( o - > retrytime < 1 ) ) {
ast_log ( LOG_WARNING , " Invalid retrytime at line %d of %s \n " , lineno , fn ) ;
o - > retrytime = 300 ;
2003-02-04 15:48:42 +00:00
}
2005-07-15 00:15:14 +00:00
} else if ( ! strcasecmp ( buf , " waittime " ) ) {
if ( ( sscanf ( c , " %d " , & o - > waittime ) ! = 1 ) | | ( o - > waittime < 1 ) ) {
ast_log ( LOG_WARNING , " Invalid retrytime at line %d of %s \n " , lineno , fn ) ;
o - > waittime = 45 ;
}
} else if ( ! strcasecmp ( buf , " retry " ) ) {
o - > retries + + ;
} else if ( ! strcasecmp ( buf , " startretry " ) ) {
2006-05-08 12:32:44 +00:00
if ( sscanf ( c , " %ld " , & o - > callingpid ) ! = 1 ) {
2005-07-15 00:15:14 +00:00
ast_log ( LOG_WARNING , " Unable to retrieve calling PID! \n " ) ;
o - > callingpid = 0 ;
}
} else if ( ! strcasecmp ( buf , " endretry " ) | | ! strcasecmp ( buf , " abortretry " ) ) {
o - > callingpid = 0 ;
o - > retries + + ;
} else if ( ! strcasecmp ( buf , " delayedretry " ) ) {
2005-07-15 23:24:51 +00:00
} else if ( ! strcasecmp ( buf , " setvar " ) | | ! strcasecmp ( buf , " set " ) ) {
c2 = c ;
strsep ( & c2 , " = " ) ;
2005-11-20 10:32:28 +00:00
if ( c2 ) {
2005-11-20 06:59:42 +00:00
var = ast_variable_new ( c , c2 ) ;
if ( var ) {
var - > next = o - > vars ;
o - > vars = var ;
}
2005-11-20 10:32:28 +00:00
} else
2005-11-20 06:59:42 +00:00
ast_log ( LOG_WARNING , " Malformed \" %s \" argument. Should be \" %s: variable=value \" \n " , buf , buf ) ;
2005-07-15 00:15:14 +00:00
} else if ( ! strcasecmp ( buf , " account " ) ) {
2006-02-11 18:31:59 +00:00
ast_copy_string ( o - > account , c , sizeof ( o - > account ) ) ;
2006-05-19 22:51:44 +00:00
} else if ( ! strcasecmp ( buf , " alwaysdelete " ) ) {
ast_set2_flag ( & o - > options , ast_true ( c ) , SPOOL_FLAG_ALWAYS_DELETE ) ;
2006-05-25 17:58:55 +00:00
} else if ( ! strcasecmp ( buf , " archive " ) ) {
ast_set2_flag ( & o - > options , ast_true ( c ) , SPOOL_FLAG_ARCHIVE ) ;
2005-07-15 00:15:14 +00:00
} else {
ast_log ( LOG_WARNING , " Unknown keyword '%s' at line %d of %s \n " , buf , lineno , fn ) ;
}
} else
ast_log ( LOG_NOTICE , " Syntax error at line %d of %s \n " , lineno , fn ) ;
}
2003-02-04 15:48:42 +00:00
}
2006-10-25 14:44:50 +00:00
ast_copy_string ( o - > fn , fn , sizeof ( o - > fn ) ) ;
2004-05-08 08:07:47 +00:00
if ( ast_strlen_zero ( o - > tech ) | | ast_strlen_zero ( o - > dest ) | | ( ast_strlen_zero ( o - > app ) & & ast_strlen_zero ( o - > exten ) ) ) {
2003-02-04 15:48:42 +00:00
ast_log ( LOG_WARNING , " At least one of app or extension must be specified, along with tech and dest in file %s \n " , fn ) ;
return - 1 ;
}
return 0 ;
}
2004-03-20 21:13:12 +00:00
static void safe_append ( struct outgoing * o , time_t now , char * s )
{
int fd ;
FILE * f ;
2004-04-05 00:00:23 +00:00
struct utimbuf tbuf ;
2004-03-20 21:13:12 +00:00
fd = open ( o - > fn , O_WRONLY | O_APPEND ) ;
if ( fd > - 1 ) {
f = fdopen ( fd , " a " ) ;
if ( f ) {
2004-04-05 00:00:23 +00:00
fprintf ( f , " %s: %ld %d (%ld) \n " , s , ( long ) ast_mainpid , o - > retries , ( long ) now ) ;
2004-03-20 21:13:12 +00:00
fclose ( f ) ;
} else
close ( fd ) ;
2004-04-05 02:47:48 +00:00
/* Update the file time */
tbuf . actime = now ;
tbuf . modtime = now + o - > retrytime ;
if ( utime ( o - > fn , & tbuf ) )
ast_log ( LOG_WARNING , " Unable to set utime on %s: %s \n " , o - > fn , strerror ( errno ) ) ;
2004-03-20 21:13:12 +00:00
}
}
2006-05-25 17:58:55 +00:00
/*!
* \ brief Remove a call file from the outgoing queue optionally moving it in the archive dir
*
* \ param o the pointer to outgoing struct
* \ param status the exit status of the call . Can be " Completed " , " Failed " or " Expired "
*/
static int remove_from_queue ( struct outgoing * o , const char * status )
2006-05-19 22:51:44 +00:00
{
2006-05-25 17:58:55 +00:00
int fd ;
FILE * f ;
char newfn [ 256 ] ;
const char * bname ;
if ( ! ast_test_flag ( & o - > options , SPOOL_FLAG_ALWAYS_DELETE ) ) {
2006-05-19 22:51:44 +00:00
struct stat current_file_status ;
2006-05-25 17:58:55 +00:00
2006-05-19 22:51:44 +00:00
if ( ! stat ( o - > fn , & current_file_status ) )
2006-05-25 17:58:55 +00:00
if ( time ( NULL ) < current_file_status . st_mtime )
return 0 ;
}
if ( ! ast_test_flag ( & o - > options , SPOOL_FLAG_ARCHIVE ) ) {
unlink ( o - > fn ) ;
return 0 ;
}
if ( mkdir ( qdonedir , 0700 ) & & ( errno ! = EEXIST ) ) {
ast_log ( LOG_WARNING , " Unable to create queue directory %s -- outgoing spool archiving disabled \n " , qdonedir ) ;
unlink ( o - > fn ) ;
return - 1 ;
}
fd = open ( o - > fn , O_WRONLY | O_APPEND ) ;
if ( fd > - 1 ) {
f = fdopen ( fd , " a " ) ;
if ( f ) {
fprintf ( f , " Status: %s \n " , status ) ;
fclose ( f ) ;
} else
close ( fd ) ;
2006-05-19 22:51:44 +00:00
}
2006-05-25 17:58:55 +00:00
bname = strrchr ( o - > fn , ' / ' ) ;
if ( bname = = NULL )
bname = o - > fn ;
else
bname + + ;
snprintf ( newfn , sizeof ( newfn ) , " %s/%s " , qdonedir , bname ) ;
/* a existing call file the archive dir is overwritten */
unlink ( newfn ) ;
if ( rename ( o - > fn , newfn ) ! = 0 ) {
unlink ( o - > fn ) ;
return - 1 ;
} else
return 0 ;
2006-05-19 22:51:44 +00:00
}
2003-02-04 15:48:42 +00:00
static void * attempt_thread ( void * data )
{
struct outgoing * o = data ;
int res , reason ;
2004-05-08 08:07:47 +00:00
if ( ! ast_strlen_zero ( o - > app ) ) {
2003-02-04 15:48:42 +00:00
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Attempting call on %s/%s for application %s(%s) (Retry %d) \n " , o - > tech , o - > dest , o - > app , o - > data , o - > retries ) ;
2006-02-11 18:31:59 +00:00
res = ast_pbx_outgoing_app ( o - > tech , AST_FORMAT_SLINEAR , o - > dest , o - > waittime * 1000 , o - > app , o - > data , & reason , 2 /* wait to finish */ , o - > cid_num , o - > cid_name , o - > vars , o - > account , NULL ) ;
2003-02-04 15:48:42 +00:00
} else {
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Attempting call on %s/%s for %s@%s:%d (Retry %d) \n " , o - > tech , o - > dest , o - > exten , o - > context , o - > priority , o - > retries ) ;
2006-02-11 18:31:59 +00:00
res = ast_pbx_outgoing_exten ( o - > tech , AST_FORMAT_SLINEAR , o - > dest , o - > waittime * 1000 , o - > context , o - > exten , o - > priority , & reason , 2 /* wait to finish */ , o - > cid_num , o - > cid_name , o - > vars , o - > account , NULL ) ;
2003-02-04 15:48:42 +00:00
}
if ( res ) {
ast_log ( LOG_NOTICE , " Call failed to go through, reason %d \n " , reason ) ;
if ( o - > retries > = o - > maxretries + 1 ) {
/* Max retries exceeded */
2005-07-07 22:32:20 +00:00
ast_log ( LOG_EVENT , " Queued call to %s/%s expired without completion after %d attempt%s \n " , o - > tech , o - > dest , o - > retries - 1 , ( ( o - > retries - 1 ) ! = 1 ) ? " s " : " " ) ;
2006-05-25 17:58:55 +00:00
remove_from_queue ( o , " Expired " ) ;
2004-03-20 21:13:12 +00:00
} else {
/* Notate that the call is still active */
safe_append ( o , time ( NULL ) , " EndRetry " ) ;
2003-02-04 15:48:42 +00:00
}
} else {
ast_log ( LOG_NOTICE , " Call completed to %s/%s \n " , o - > tech , o - > dest ) ;
ast_log ( LOG_EVENT , " Queued call to %s/%s completed \n " , o - > tech , o - > dest ) ;
2006-05-25 17:58:55 +00:00
remove_from_queue ( o , " Completed " ) ;
2003-02-04 15:48:42 +00:00
}
2005-10-11 20:44:23 +00:00
free_outgoing ( o ) ;
2003-02-04 15:48:42 +00:00
return NULL ;
}
static void launch_service ( struct outgoing * o )
{
pthread_t t ;
pthread_attr_t attr ;
2006-01-07 07:31:08 +00:00
int ret ;
2003-02-04 15:48:42 +00:00
pthread_attr_init ( & attr ) ;
pthread_attr_setdetachstate ( & attr , PTHREAD_CREATE_DETACHED ) ;
2006-01-07 07:31:08 +00:00
if ( ( ret = ast_pthread_create ( & t , & attr , attempt_thread , o ) ) ! = 0 ) {
ast_log ( LOG_WARNING , " Unable to create thread :( (returned error: %d) \n " , ret ) ;
2005-10-11 20:44:23 +00:00
free_outgoing ( o ) ;
2003-02-04 15:48:42 +00:00
}
}
static int scan_service ( char * fn , time_t now , time_t atime )
{
struct outgoing * o ;
FILE * f ;
o = malloc ( sizeof ( struct outgoing ) ) ;
if ( o ) {
init_outgoing ( o ) ;
f = fopen ( fn , " r+ " ) ;
if ( f ) {
if ( ! apply_outgoing ( o , fn , f ) ) {
#if 0
2004-04-05 00:00:23 +00:00
printf ( " Filename: %s, Retries: %d, max: %d \n " , fn , o - > retries , o - > maxretries ) ;
2003-02-04 15:48:42 +00:00
# endif
2004-04-05 00:00:23 +00:00
fclose ( f ) ;
2004-03-20 21:13:12 +00:00
if ( o - > retries < = o - > maxretries ) {
2006-01-09 20:12:07 +00:00
now + = o - > retrytime ;
2004-03-20 21:13:12 +00:00
if ( o - > callingpid & & ( o - > callingpid = = ast_mainpid ) ) {
2004-04-05 00:00:23 +00:00
safe_append ( o , time ( NULL ) , " DelayedRetry " ) ;
2006-01-09 20:12:07 +00:00
free_outgoing ( o ) ;
2004-03-20 21:13:12 +00:00
ast_log ( LOG_DEBUG , " Delaying retry since we're currently running '%s' \n " , o - > fn ) ;
} else {
/* Increment retries */
o - > retries + + ;
/* If someone else was calling, they're presumably gone now
so abort their retry and continue as we were . . . */
if ( o - > callingpid )
safe_append ( o , time ( NULL ) , " AbortRetry " ) ;
2004-04-05 00:00:23 +00:00
safe_append ( o , now , " StartRetry " ) ;
2004-03-20 21:13:12 +00:00
launch_service ( o ) ;
}
2003-02-04 15:48:42 +00:00
return now ;
} else {
2005-07-07 22:32:20 +00:00
ast_log ( LOG_EVENT , " Queued call to %s/%s expired without completion after %d attempt%s \n " , o - > tech , o - > dest , o - > retries - 1 , ( ( o - > retries - 1 ) ! = 1 ) ? " s " : " " ) ;
2005-10-11 20:44:23 +00:00
free_outgoing ( o ) ;
2006-05-25 17:58:55 +00:00
remove_from_queue ( o , " Expired " ) ;
2003-02-04 15:48:42 +00:00
return 0 ;
}
} else {
2005-10-11 20:44:23 +00:00
free_outgoing ( o ) ;
2003-02-04 15:48:42 +00:00
ast_log ( LOG_WARNING , " Invalid file contents in %s, deleting \n " , fn ) ;
fclose ( f ) ;
2006-05-25 17:58:55 +00:00
remove_from_queue ( o , " Failed " ) ;
2003-02-04 15:48:42 +00:00
}
} else {
2005-10-11 20:44:23 +00:00
free_outgoing ( o ) ;
2003-02-04 15:48:42 +00:00
ast_log ( LOG_WARNING , " Unable to open %s: %s, deleting \n " , fn , strerror ( errno ) ) ;
2006-05-25 17:58:55 +00:00
remove_from_queue ( o , " Failed " ) ;
2003-02-04 15:48:42 +00:00
}
} else
ast_log ( LOG_WARNING , " Out of memory :( \n " ) ;
return - 1 ;
}
static void * scan_thread ( void * unused )
{
struct stat st ;
DIR * dir ;
struct dirent * de ;
2006-02-24 10:50:43 +00:00
char fn [ 256 ] ;
2003-02-04 15:48:42 +00:00
int res ;
time_t last = 0 , next = 0 , now ;
for ( ; ; ) {
/* Wait a sec */
sleep ( 1 ) ;
time ( & now ) ;
if ( ! stat ( qdir , & st ) ) {
if ( ( st . st_mtime ! = last ) | | ( next & & ( now > next ) ) ) {
#if 0
printf ( " atime: %ld, mtime: %ld, ctime: %ld \n " , st . st_atime , st . st_mtime , st . st_ctime ) ;
printf ( " Ooh, something changed / timeout \n " ) ;
# endif
next = 0 ;
last = st . st_mtime ;
dir = opendir ( qdir ) ;
if ( dir ) {
while ( ( de = readdir ( dir ) ) ) {
snprintf ( fn , sizeof ( fn ) , " %s/%s " , qdir , de - > d_name ) ;
if ( ! stat ( fn , & st ) ) {
if ( S_ISREG ( st . st_mode ) ) {
if ( st . st_mtime < = now ) {
res = scan_service ( fn , now , st . st_atime ) ;
if ( res > 0 ) {
/* Update next service time */
if ( ! next | | ( res < next ) ) {
next = res ;
}
} else if ( res )
ast_log ( LOG_WARNING , " Failed to scan service '%s' \n " , fn ) ;
} else {
/* Update "next" update if necessary */
if ( ! next | | ( st . st_mtime < next ) )
next = st . st_mtime ;
}
}
} else
ast_log ( LOG_WARNING , " Unable to stat %s: %s \n " , fn , strerror ( errno ) ) ;
}
closedir ( dir ) ;
} else
ast_log ( LOG_WARNING , " Unable to open directory %s: %s \n " , qdir , strerror ( errno ) ) ;
}
} else
ast_log ( LOG_WARNING , " Unable to stat %s \n " , qdir ) ;
}
return NULL ;
}
2006-08-21 02:11:39 +00:00
static int unload_module ( void )
2003-02-04 15:48:42 +00:00
{
return - 1 ;
}
2006-08-21 02:11:39 +00:00
static int load_module ( void )
2003-02-04 15:48:42 +00:00
{
pthread_t thread ;
pthread_attr_t attr ;
2006-01-07 07:31:08 +00:00
int ret ;
2004-07-14 13:57:15 +00:00
snprintf ( qdir , sizeof ( qdir ) , " %s/%s " , ast_config_AST_SPOOL_DIR , " outgoing " ) ;
2004-01-28 21:32:48 +00:00
if ( mkdir ( qdir , 0700 ) & & ( errno ! = EEXIST ) ) {
2003-02-04 15:48:42 +00:00
ast_log ( LOG_WARNING , " Unable to create queue directory %s -- outgoing spool disabled \n " , qdir ) ;
return 0 ;
}
2006-05-25 17:58:55 +00:00
snprintf ( qdonedir , sizeof ( qdir ) , " %s/%s " , ast_config_AST_SPOOL_DIR , " outgoing_done " ) ;
2003-02-04 15:48:42 +00:00
pthread_attr_init ( & attr ) ;
pthread_attr_setdetachstate ( & attr , PTHREAD_CREATE_DETACHED ) ;
2006-10-04 19:51:38 +00:00
if ( ( ret = ast_pthread_create_background ( & thread , & attr , scan_thread , NULL ) ) ! = 0 ) {
2006-01-07 07:31:08 +00:00
ast_log ( LOG_WARNING , " Unable to create thread :( (returned error: %d) \n " , ret ) ;
2003-02-04 15:48:42 +00:00
return - 1 ;
}
return 0 ;
}
2006-08-21 02:11:39 +00:00
AST_MODULE_INFO_STANDARD ( ASTERISK_GPL_KEY , " Outgoing Spool Support " ) ;