Sat Feb 11 06:36:14 2012

Asterisk developer's documentation


pbx_spool.c File Reference

Full-featured outgoing call spool support. More...

#include "asterisk.h"
#include <sys/stat.h>
#include <time.h>
#include <utime.h>
#include <dirent.h>
#include "asterisk/paths.h"
#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/utils.h"
#include "asterisk/options.h"

Include dependency graph for pbx_spool.c:

Go to the source code of this file.

Data Structures

struct  outgoing

Enumerations

enum  { SPOOL_FLAG_ALWAYS_DELETE = (1 << 0), SPOOL_FLAG_ARCHIVE = (1 << 1) }

Functions

static void __reg_module (void)
static void __unreg_module (void)
static int apply_outgoing (struct outgoing *o, const char *fn, FILE *f)
static void * attempt_thread (void *data)
static void free_outgoing (struct outgoing *o)
static int init_outgoing (struct outgoing *o)
static void launch_service (struct outgoing *o)
static int load_module (void)
static int remove_from_queue (struct outgoing *o, const char *status)
 Remove a call file from the outgoing queue optionally moving it in the archive dir.
static void safe_append (struct outgoing *o, time_t now, char *s)
static int scan_service (const char *fn, time_t now)
static void * scan_thread (void *unused)
static int unload_module (void)

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Outgoing Spool Support" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, }
static struct ast_module_infoast_module_info = &__mod_info
static char qdir [255]
static char qdonedir [255]


Detailed Description

Full-featured outgoing call spool support.

Definition in file pbx_spool.c.


Enumeration Type Documentation

anonymous enum

Enumerator:
SPOOL_FLAG_ALWAYS_DELETE  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.
SPOOL_FLAG_ARCHIVE 

Definition at line 62 of file pbx_spool.c.

00062      {
00063    /*! Always delete the call file after a call succeeds or the
00064     * maximum number of retries is exceeded, even if the
00065     * modification time of the call file is in the future.
00066     */
00067    SPOOL_FLAG_ALWAYS_DELETE = (1 << 0),
00068    /* Don't unlink the call file after processing, move in qdonedir */
00069    SPOOL_FLAG_ARCHIVE = (1 << 1),
00070 };


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 854 of file pbx_spool.c.

static void __unreg_module ( void   )  [static]

Definition at line 854 of file pbx_spool.c.

static int apply_outgoing ( struct outgoing o,
const char *  fn,
FILE *  f 
) [static]

Definition at line 133 of file pbx_spool.c.

References outgoing::app, app, ast_callerid_split(), ast_log(), ast_parse_allow_disallow(), ast_set2_flag, ast_string_field_set, ast_strlen_zero(), ast_true(), ast_variable_new(), outgoing::callingpid, outgoing::capabilities, cid_name, cid_num, context, outgoing::dest, outgoing::exten, exten, last, LOG_NOTICE, LOG_WARNING, outgoing::maxretries, ast_variable::next, outgoing::options, outgoing::priority, outgoing::retries, outgoing::retrytime, SPOOL_FLAG_ALWAYS_DELETE, SPOOL_FLAG_ARCHIVE, strsep(), outgoing::tech, var, outgoing::vars, and outgoing::waittime.

Referenced by scan_service().

00134 {
00135    char buf[256];
00136    char *c, *c2;
00137    int lineno = 0;
00138    struct ast_variable *var, *last = o->vars;
00139 
00140    while (last && last->next) {
00141       last = last->next;
00142    }
00143 
00144    while(fgets(buf, sizeof(buf), f)) {
00145       lineno++;
00146       /* Trim comments */
00147       c = buf;
00148       while ((c = strchr(c, '#'))) {
00149          if ((c == buf) || (*(c-1) == ' ') || (*(c-1) == '\t'))
00150             *c = '\0';
00151          else
00152             c++;
00153       }
00154 
00155       c = buf;
00156       while ((c = strchr(c, ';'))) {
00157          if ((c > buf) && (c[-1] == '\\')) {
00158             memmove(c - 1, c, strlen(c) + 1);
00159             c++;
00160          } else {
00161             *c = '\0';
00162             break;
00163          }
00164       }
00165 
00166       /* Trim trailing white space */
00167       while(!ast_strlen_zero(buf) && buf[strlen(buf) - 1] < 33)
00168          buf[strlen(buf) - 1] = '\0';
00169       if (!ast_strlen_zero(buf)) {
00170          c = strchr(buf, ':');
00171          if (c) {
00172             *c = '\0';
00173             c++;
00174             while ((*c) && (*c < 33))
00175                c++;
00176 #if 0
00177             printf("'%s' is '%s' at line %d\n", buf, c, lineno);
00178 #endif
00179             if (!strcasecmp(buf, "channel")) {
00180                if ((c2 = strchr(c, '/'))) {
00181                   *c2 = '\0';
00182                   c2++;
00183                   ast_string_field_set(o, tech, c);
00184                   ast_string_field_set(o, dest, c2);
00185                } else {
00186                   ast_log(LOG_NOTICE, "Channel should be in form Tech/Dest at line %d of %s\n", lineno, fn);
00187                }
00188             } else if (!strcasecmp(buf, "callerid")) {
00189                char cid_name[80] = {0}, cid_num[80] = {0};
00190                ast_callerid_split(c, cid_name, sizeof(cid_name), cid_num, sizeof(cid_num));
00191                ast_string_field_set(o, cid_num, cid_num);
00192                ast_string_field_set(o, cid_name, cid_name);
00193             } else if (!strcasecmp(buf, "application")) {
00194                ast_string_field_set(o, app, c);
00195             } else if (!strcasecmp(buf, "data")) {
00196                ast_string_field_set(o, data, c);
00197             } else if (!strcasecmp(buf, "maxretries")) {
00198                if (sscanf(c, "%30d", &o->maxretries) != 1) {
00199                   ast_log(LOG_WARNING, "Invalid max retries at line %d of %s\n", lineno, fn);
00200                   o->maxretries = 0;
00201                }
00202             } else if (!strcasecmp(buf, "codecs")) {
00203                ast_parse_allow_disallow(NULL, o->capabilities, c, 1);
00204             } else if (!strcasecmp(buf, "context")) {
00205                ast_string_field_set(o, context, c);
00206             } else if (!strcasecmp(buf, "extension")) {
00207                ast_string_field_set(o, exten, c);
00208             } else if (!strcasecmp(buf, "priority")) {
00209                if ((sscanf(c, "%30d", &o->priority) != 1) || (o->priority < 1)) {
00210                   ast_log(LOG_WARNING, "Invalid priority at line %d of %s\n", lineno, fn);
00211                   o->priority = 1;
00212                }
00213             } else if (!strcasecmp(buf, "retrytime")) {
00214                if ((sscanf(c, "%30d", &o->retrytime) != 1) || (o->retrytime < 1)) {
00215                   ast_log(LOG_WARNING, "Invalid retrytime at line %d of %s\n", lineno, fn);
00216                   o->retrytime = 300;
00217                }
00218             } else if (!strcasecmp(buf, "waittime")) {
00219                if ((sscanf(c, "%30d", &o->waittime) != 1) || (o->waittime < 1)) {
00220                   ast_log(LOG_WARNING, "Invalid waittime at line %d of %s\n", lineno, fn);
00221                   o->waittime = 45;
00222                }
00223             } else if (!strcasecmp(buf, "retry")) {
00224                o->retries++;
00225             } else if (!strcasecmp(buf, "startretry")) {
00226                if (sscanf(c, "%30ld", &o->callingpid) != 1) {
00227                   ast_log(LOG_WARNING, "Unable to retrieve calling PID!\n");
00228                   o->callingpid = 0;
00229                }
00230             } else if (!strcasecmp(buf, "endretry") || !strcasecmp(buf, "abortretry")) {
00231                o->callingpid = 0;
00232                o->retries++;
00233             } else if (!strcasecmp(buf, "delayedretry")) {
00234             } else if (!strcasecmp(buf, "setvar") || !strcasecmp(buf, "set")) {
00235                c2 = c;
00236                strsep(&c2, "=");
00237                if (c2) {
00238                   var = ast_variable_new(c, c2, fn);
00239                   if (var) {
00240                      /* Always insert at the end, because some people want to treat the spool file as a script */
00241                      if (last) {
00242                         last->next = var;
00243                      } else {
00244                         o->vars = var;
00245                      }
00246                      last = var;
00247                   }
00248                } else
00249                   ast_log(LOG_WARNING, "Malformed \"%s\" argument.  Should be \"%s: variable=value\"\n", buf, buf);
00250             } else if (!strcasecmp(buf, "account")) {
00251                ast_string_field_set(o, account, c);
00252             } else if (!strcasecmp(buf, "alwaysdelete")) {
00253                ast_set2_flag(&o->options, ast_true(c), SPOOL_FLAG_ALWAYS_DELETE);
00254             } else if (!strcasecmp(buf, "archive")) {
00255                ast_set2_flag(&o->options, ast_true(c), SPOOL_FLAG_ARCHIVE);
00256             } else {
00257                ast_log(LOG_WARNING, "Unknown keyword '%s' at line %d of %s\n", buf, lineno, fn);
00258             }
00259          } else
00260             ast_log(LOG_NOTICE, "Syntax error at line %d of %s\n", lineno, fn);
00261       }
00262    }
00263    ast_string_field_set(o, fn, fn);
00264    if (ast_strlen_zero(o->tech) || ast_strlen_zero(o->dest) || (ast_strlen_zero(o->app) && ast_strlen_zero(o->exten))) {
00265       ast_log(LOG_WARNING, "At least one of app or extension must be specified, along with tech and dest in file %s\n", fn);
00266       return -1;
00267    }
00268    return 0;
00269 }

static void* attempt_thread ( void *  data  )  [static]

Definition at line 346 of file pbx_spool.c.

References outgoing::account, outgoing::app, ast_channel_reason2str(), ast_log(), ast_pbx_outgoing_app(), ast_pbx_outgoing_exten(), ast_strlen_zero(), ast_verb, outgoing::capabilities, outgoing::cid_name, outgoing::cid_num, outgoing::context, outgoing::data, outgoing::dest, outgoing::exten, outgoing::fn, free_outgoing(), LOG_NOTICE, outgoing::maxretries, outgoing::priority, remove_from_queue(), outgoing::retries, outgoing::retrytime, safe_append(), outgoing::tech, outgoing::vars, and outgoing::waittime.

Referenced by launch_service().

00347 {
00348    struct outgoing *o = data;
00349    int res, reason;
00350    if (!ast_strlen_zero(o->app)) {
00351       ast_verb(3, "Attempting call on %s/%s for application %s(%s) (Retry %d)\n", o->tech, o->dest, o->app, o->data, o->retries);
00352       res = ast_pbx_outgoing_app(o->tech, o->capabilities, o->dest, o->waittime * 1000,
00353          o->app, o->data, &reason, 2 /* wait to finish */, o->cid_num, o->cid_name,
00354          o->vars, o->account, NULL);
00355       o->vars = NULL;
00356    } else {
00357       ast_verb(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);
00358       res = ast_pbx_outgoing_exten(o->tech, o->capabilities, o->dest,
00359          o->waittime * 1000, o->context, o->exten, o->priority, &reason,
00360          2 /* wait to finish */, o->cid_num, o->cid_name, o->vars, o->account, NULL);
00361       o->vars = NULL;
00362    }
00363    if (res) {
00364       ast_log(LOG_NOTICE, "Call failed to go through, reason (%d) %s\n", reason, ast_channel_reason2str(reason));
00365       if (o->retries >= o->maxretries + 1) {
00366          /* Max retries exceeded */
00367          ast_log(LOG_NOTICE, "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" : "");
00368          remove_from_queue(o, "Expired");
00369       } else {
00370          /* Notate that the call is still active */
00371          safe_append(o, time(NULL), "EndRetry");
00372 #if defined(HAVE_INOTIFY) || defined(HAVE_KQUEUE)
00373          queue_file(o->fn, time(NULL) + o->retrytime);
00374 #endif
00375       }
00376    } else {
00377       ast_log(LOG_NOTICE, "Call completed to %s/%s\n", o->tech, o->dest);
00378       remove_from_queue(o, "Completed");
00379    }
00380    free_outgoing(o);
00381    return NULL;
00382 }

static void free_outgoing ( struct outgoing o  )  [static]

static int init_outgoing ( struct outgoing o  )  [static]

Definition at line 104 of file pbx_spool.c.

References ast_format_cap_add(), ast_format_cap_alloc_nolock(), ast_format_set(), AST_FORMAT_SLINEAR, ast_set_flag, ast_string_field_init, outgoing::capabilities, outgoing::options, outgoing::priority, outgoing::retrytime, SPOOL_FLAG_ALWAYS_DELETE, and outgoing::waittime.

Referenced by scan_service().

00105 {
00106    struct ast_format tmpfmt;
00107    o->priority = 1;
00108    o->retrytime = 300;
00109    o->waittime = 45;
00110 
00111    if (!(o->capabilities = ast_format_cap_alloc_nolock())) {
00112       return -1;
00113    }
00114    ast_format_cap_add(o->capabilities, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0));
00115 
00116    ast_set_flag(&o->options, SPOOL_FLAG_ALWAYS_DELETE);
00117    if (ast_string_field_init(o, 128)) {
00118       return -1;
00119    }
00120    return 0;
00121 }

static void launch_service ( struct outgoing o  )  [static]

Definition at line 384 of file pbx_spool.c.

References ast_log(), ast_pthread_create_detached, attempt_thread(), free_outgoing(), and LOG_WARNING.

Referenced by scan_service().

00385 {
00386    pthread_t t;
00387    int ret;
00388 
00389    if ((ret = ast_pthread_create_detached(&t, NULL, attempt_thread, o))) {
00390       ast_log(LOG_WARNING, "Unable to create thread :( (returned error: %d)\n", ret);
00391       free_outgoing(o);
00392    }
00393 }

static int load_module ( void   )  [static]

Definition at line 835 of file pbx_spool.c.

References ast_config_AST_SPOOL_DIR, ast_log(), ast_mkdir(), AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_SUCCESS, ast_pthread_create_detached_background, LOG_WARNING, scan_thread(), and thread.

00836 {
00837    pthread_t thread;
00838    int ret;
00839    snprintf(qdir, sizeof(qdir), "%s/%s", ast_config_AST_SPOOL_DIR, "outgoing");
00840    if (ast_mkdir(qdir, 0777)) {
00841       ast_log(LOG_WARNING, "Unable to create queue directory %s -- outgoing spool disabled\n", qdir);
00842       return AST_MODULE_LOAD_DECLINE;
00843    }
00844    snprintf(qdonedir, sizeof(qdir), "%s/%s", ast_config_AST_SPOOL_DIR, "outgoing_done");
00845 
00846    if ((ret = ast_pthread_create_detached_background(&thread, NULL, scan_thread, NULL))) {
00847       ast_log(LOG_WARNING, "Unable to create thread :( (returned error: %d)\n", ret);
00848       return AST_MODULE_LOAD_FAILURE;
00849    }
00850 
00851    return AST_MODULE_LOAD_SUCCESS;
00852 }

static int remove_from_queue ( struct outgoing o,
const char *  status 
) [static]

Remove a call file from the outgoing queue optionally moving it in the archive dir.

Parameters:
o the pointer to outgoing struct
status the exit status of the call. Can be "Completed", "Failed" or "Expired"

Definition at line 295 of file pbx_spool.c.

References ast_log(), ast_mkdir(), ast_test_flag, f, outgoing::fn, LOG_WARNING, outgoing::options, SPOOL_FLAG_ALWAYS_DELETE, and SPOOL_FLAG_ARCHIVE.

00296 {
00297    FILE *f;
00298    char newfn[256];
00299    const char *bname;
00300 
00301    if (!ast_test_flag(&o->options, SPOOL_FLAG_ALWAYS_DELETE)) {
00302       struct stat current_file_status;
00303 
00304       if (!stat(o->fn, &current_file_status)) {
00305          if (time(NULL) < current_file_status.st_mtime) {
00306             return 0;
00307          }
00308       }
00309    }
00310 
00311    if (!ast_test_flag(&o->options, SPOOL_FLAG_ARCHIVE)) {
00312       unlink(o->fn);
00313       return 0;
00314    }
00315 
00316    if (ast_mkdir(qdonedir, 0777)) {
00317       ast_log(LOG_WARNING, "Unable to create queue directory %s -- outgoing spool archiving disabled\n", qdonedir);
00318       unlink(o->fn);
00319       return -1;
00320    }
00321 
00322    if (!(bname = strrchr(o->fn, '/'))) {
00323       bname = o->fn;
00324    } else {
00325       bname++;
00326    }
00327 
00328    snprintf(newfn, sizeof(newfn), "%s/%s", qdonedir, bname);
00329    /* a existing call file the archive dir is overwritten */
00330    unlink(newfn);
00331    if (rename(o->fn, newfn) != 0) {
00332       unlink(o->fn);
00333       return -1;
00334    }
00335 
00336    /* Only append to the file AFTER we move it out of the watched directory,
00337     * otherwise the fclose() causes another event for inotify(7) */
00338    if ((f = fopen(newfn, "a"))) {
00339       fprintf(f, "Status: %s\n", status);
00340       fclose(f);
00341    }
00342 
00343    return 0;
00344 }

static void safe_append ( struct outgoing o,
time_t  now,
char *  s 
) [static]

Definition at line 271 of file pbx_spool.c.

References ast_debug, ast_log(), ast_mainpid, outgoing::dest, errno, f, outgoing::fn, LOG_WARNING, outgoing::retries, outgoing::retrytime, and outgoing::tech.

Referenced by attempt_thread(), and scan_service().

00272 {
00273    FILE *f;
00274    struct utimbuf tbuf = { .actime = now, .modtime = now + o->retrytime };
00275 
00276    ast_debug(1, "Outgoing %s/%s: %s\n", o->tech, o->dest, s);
00277 
00278    if ((f = fopen(o->fn, "a"))) {
00279       fprintf(f, "\n%s: %ld %d (%ld)\n", s, (long)ast_mainpid, o->retries, (long) now);
00280       fclose(f);
00281    }
00282 
00283    /* Update the file time */
00284    if (utime(o->fn, &tbuf)) {
00285       ast_log(LOG_WARNING, "Unable to set utime on %s: %s\n", o->fn, strerror(errno));
00286    }
00287 }

static int scan_service ( const char *  fn,
time_t  now 
) [static]

Definition at line 396 of file pbx_spool.c.

References apply_outgoing(), ast_calloc, ast_debug, ast_free, ast_log(), ast_mainpid, outgoing::callingpid, outgoing::dest, errno, f, outgoing::fn, free_outgoing(), init_outgoing(), launch_service(), LOG_NOTICE, LOG_WARNING, outgoing::maxretries, remove_from_queue(), outgoing::retries, outgoing::retrytime, safe_append(), and outgoing::tech.

Referenced by scan_thread().

00397 {
00398    struct outgoing *o = NULL;
00399    FILE *f;
00400    int res = 0;
00401 
00402    if (!(o = ast_calloc(1, sizeof(*o)))) {
00403       ast_log(LOG_WARNING, "Out of memory ;(\n");
00404       return -1;
00405    }
00406 
00407    if (init_outgoing(o)) {
00408       /* No need to call free_outgoing here since we know the failure
00409        * was to allocate string fields and no variables have been allocated
00410        * yet.
00411        */
00412       ast_free(o);
00413       return -1;
00414    }
00415 
00416    /* Attempt to open the file */
00417    if (!(f = fopen(fn, "r"))) {
00418       remove_from_queue(o, "Failed");
00419       free_outgoing(o);
00420 #if !defined(HAVE_INOTIFY) && !defined(HAVE_KQUEUE)
00421       ast_log(LOG_WARNING, "Unable to open %s: %s, deleting\n", fn, strerror(errno));
00422 #endif
00423       return -1;
00424    }
00425 
00426    /* Read in and verify the contents */
00427    if (apply_outgoing(o, fn, f)) {
00428       remove_from_queue(o, "Failed");
00429       free_outgoing(o);
00430       ast_log(LOG_WARNING, "Invalid file contents in %s, deleting\n", fn);
00431       fclose(f);
00432       return -1;
00433    }
00434 
00435 #if 0
00436    printf("Filename: %s, Retries: %d, max: %d\n", fn, o->retries, o->maxretries);
00437 #endif
00438    fclose(f);
00439    if (o->retries <= o->maxretries) {
00440       now += o->retrytime;
00441       if (o->callingpid && (o->callingpid == ast_mainpid)) {
00442          safe_append(o, time(NULL), "DelayedRetry");
00443          ast_debug(1, "Delaying retry since we're currently running '%s'\n", o->fn);
00444          free_outgoing(o);
00445       } else {
00446          /* Increment retries */
00447          o->retries++;
00448          /* If someone else was calling, they're presumably gone now
00449             so abort their retry and continue as we were... */
00450          if (o->callingpid)
00451             safe_append(o, time(NULL), "AbortRetry");
00452 
00453          safe_append(o, now, "StartRetry");
00454          launch_service(o);
00455       }
00456       res = now;
00457    } else {
00458       ast_log(LOG_NOTICE, "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" : "");
00459       remove_from_queue(o, "Expired");
00460       free_outgoing(o);
00461    }
00462 
00463    return res;
00464 }

static void* scan_thread ( void *  unused  )  [static]

Definition at line 757 of file pbx_spool.c.

References ast_fully_booted, ast_log(), errno, last, LOG_WARNING, and scan_service().

Referenced by load_module().

00758 {
00759    struct stat st;
00760    DIR *dir;
00761    struct dirent *de;
00762    char fn[256];
00763    int res;
00764    time_t last = 0, next = 0, now;
00765    struct timespec ts = { .tv_sec = 1 };
00766 
00767    while (!ast_fully_booted) {
00768       nanosleep(&ts, NULL);
00769    }
00770 
00771    for(;;) {
00772       /* Wait a sec */
00773       nanosleep(&ts, NULL);
00774       time(&now);
00775 
00776       if (stat(qdir, &st)) {
00777          ast_log(LOG_WARNING, "Unable to stat %s\n", qdir);
00778          continue;
00779       }
00780 
00781       /* Make sure it is time for us to execute our check */
00782       if ((st.st_mtime == last) && (next && (next > now)))
00783          continue;
00784 
00785 #if 0
00786       printf("atime: %ld, mtime: %ld, ctime: %ld\n", st.st_atime, st.st_mtime, st.st_ctime);
00787       printf("Ooh, something changed / timeout\n");
00788 #endif
00789       next = 0;
00790       last = st.st_mtime;
00791 
00792       if (!(dir = opendir(qdir))) {
00793          ast_log(LOG_WARNING, "Unable to open directory %s: %s\n", qdir, strerror(errno));
00794          continue;
00795       }
00796 
00797       while ((de = readdir(dir))) {
00798          snprintf(fn, sizeof(fn), "%s/%s", qdir, de->d_name);
00799          if (stat(fn, &st)) {
00800             ast_log(LOG_WARNING, "Unable to stat %s: %s\n", fn, strerror(errno));
00801             continue;
00802          }
00803          if (!S_ISREG(st.st_mode))
00804             continue;
00805          if (st.st_mtime <= now) {
00806             res = scan_service(fn, now);
00807             if (res > 0) {
00808                /* Update next service time */
00809                if (!next || (res < next)) {
00810                   next = res;
00811                }
00812             } else if (res) {
00813                ast_log(LOG_WARNING, "Failed to scan service '%s'\n", fn);
00814             } else if (!next) {
00815                /* Expired entry: must recheck on the next go-around */
00816                next = st.st_mtime;
00817             }
00818          } else {
00819             /* Update "next" update if necessary */
00820             if (!next || (st.st_mtime < next))
00821                next = st.st_mtime;
00822          }
00823       }
00824       closedir(dir);
00825    }
00826    return NULL;
00827 }

static int unload_module ( void   )  [static]

Definition at line 830 of file pbx_spool.c.

00831 {
00832    return -1;
00833 }


Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Outgoing Spool Support" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, } [static]

Definition at line 854 of file pbx_spool.c.

Definition at line 854 of file pbx_spool.c.

char qdir[255] [static]

Definition at line 72 of file pbx_spool.c.

char qdonedir[255] [static]

Definition at line 73 of file pbx_spool.c.


Generated on Sat Feb 11 06:36:15 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6