#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 <stdio.h>
#include "asterisk.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/options.h"
#include "asterisk/utils.h"
Include dependency graph for pbx_spool.c:
Go to the source code of this file.
Data Structures | |
struct | outgoing |
Functions | |
static int | apply_outgoing (struct outgoing *o, char *fn, FILE *f) |
static void * | attempt_thread (void *data) |
char * | description (void) |
Provides a description of the module. | |
static void | free_outgoing (struct outgoing *o) |
static void | init_outgoing (struct outgoing *o) |
char * | key () |
Returns the ASTERISK_GPL_KEY. | |
static void | launch_service (struct outgoing *o) |
int | load_module (void) |
Initialize the module. | |
static void | safe_append (struct outgoing *o, time_t now, char *s) |
static int | scan_service (char *fn, time_t now, time_t atime) |
static void * | scan_thread (void *unused) |
int | unload_module (void) |
Cleanup all module structures, sockets, etc. | |
int | usecount (void) |
Provides a usecount. | |
Variables | |
static char | qdir [255] |
static char * | tdesc = "Outgoing Spool Support" |
Definition in file pbx_spool.c.
static int apply_outgoing | ( | struct outgoing * | o, | |
char * | fn, | |||
FILE * | f | |||
) | [static] |
Definition at line 112 of file pbx_spool.c.
References outgoing::account, outgoing::app, ast_callerid_split(), ast_log(), ast_strlen_zero(), ast_variable_new(), outgoing::callingpid, outgoing::cid_name, outgoing::cid_num, outgoing::context, outgoing::data, outgoing::dest, outgoing::exten, outgoing::fn, ast_variable::lineno, LOG_NOTICE, LOG_WARNING, outgoing::maxretries, outgoing::priority, outgoing::retries, outgoing::retrytime, strsep(), outgoing::tech, var, outgoing::vars, and outgoing::waittime.
Referenced by scan_service().
00113 { 00114 char buf[256]; 00115 char *c, *c2; 00116 int lineno = 0; 00117 struct ast_variable *var; 00118 00119 while(fgets(buf, sizeof(buf), f)) { 00120 lineno++; 00121 /* Trim comments */ 00122 c = buf; 00123 while ((c = strchr(c, '#'))) { 00124 if ((c == buf) || (*(c-1) == ' ') || (*(c-1) == '\t')) 00125 *c = '\0'; 00126 else 00127 c++; 00128 } 00129 00130 c = buf; 00131 while ((c = strchr(c, ';'))) { 00132 if ((c > buf) && (c[-1] == '\\')) { 00133 memmove(c - 1, c, strlen(c) + 1); 00134 c++; 00135 } else { 00136 *c = '\0'; 00137 break; 00138 } 00139 } 00140 00141 /* Trim trailing white space */ 00142 while(!ast_strlen_zero(buf) && buf[strlen(buf) - 1] < 33) 00143 buf[strlen(buf) - 1] = '\0'; 00144 if (!ast_strlen_zero(buf)) { 00145 c = strchr(buf, ':'); 00146 if (c) { 00147 *c = '\0'; 00148 c++; 00149 while ((*c) && (*c < 33)) 00150 c++; 00151 #if 0 00152 printf("'%s' is '%s' at line %d\n", buf, c, lineno); 00153 #endif 00154 if (!strcasecmp(buf, "channel")) { 00155 strncpy(o->tech, c, sizeof(o->tech) - 1); 00156 if ((c2 = strchr(o->tech, '/'))) { 00157 *c2 = '\0'; 00158 c2++; 00159 strncpy(o->dest, c2, sizeof(o->dest) - 1); 00160 } else { 00161 ast_log(LOG_NOTICE, "Channel should be in form Tech/Dest at line %d of %s\n", lineno, fn); 00162 o->tech[0] = '\0'; 00163 } 00164 } else if (!strcasecmp(buf, "callerid")) { 00165 ast_callerid_split(c, o->cid_name, sizeof(o->cid_name), o->cid_num, sizeof(o->cid_num)); 00166 } else if (!strcasecmp(buf, "application")) { 00167 strncpy(o->app, c, sizeof(o->app) - 1); 00168 } else if (!strcasecmp(buf, "data")) { 00169 strncpy(o->data, c, sizeof(o->data) - 1); 00170 } else if (!strcasecmp(buf, "maxretries")) { 00171 if (sscanf(c, "%d", &o->maxretries) != 1) { 00172 ast_log(LOG_WARNING, "Invalid max retries at line %d of %s\n", lineno, fn); 00173 o->maxretries = 0; 00174 } 00175 } else if (!strcasecmp(buf, "context")) { 00176 strncpy(o->context, c, sizeof(o->context) - 1); 00177 } else if (!strcasecmp(buf, "extension")) { 00178 strncpy(o->exten, c, sizeof(o->exten) - 1); 00179 } else if (!strcasecmp(buf, "priority")) { 00180 if ((sscanf(c, "%d", &o->priority) != 1) || (o->priority < 1)) { 00181 ast_log(LOG_WARNING, "Invalid priority at line %d of %s\n", lineno, fn); 00182 o->priority = 1; 00183 } 00184 } else if (!strcasecmp(buf, "retrytime")) { 00185 if ((sscanf(c, "%d", &o->retrytime) != 1) || (o->retrytime < 1)) { 00186 ast_log(LOG_WARNING, "Invalid retrytime at line %d of %s\n", lineno, fn); 00187 o->retrytime = 300; 00188 } 00189 } else if (!strcasecmp(buf, "waittime")) { 00190 if ((sscanf(c, "%d", &o->waittime) != 1) || (o->waittime < 1)) { 00191 ast_log(LOG_WARNING, "Invalid retrytime at line %d of %s\n", lineno, fn); 00192 o->waittime = 45; 00193 } 00194 } else if (!strcasecmp(buf, "retry")) { 00195 o->retries++; 00196 } else if (!strcasecmp(buf, "startretry")) { 00197 if (sscanf(c, "%d", &o->callingpid) != 1) { 00198 ast_log(LOG_WARNING, "Unable to retrieve calling PID!\n"); 00199 o->callingpid = 0; 00200 } 00201 } else if (!strcasecmp(buf, "endretry") || !strcasecmp(buf, "abortretry")) { 00202 o->callingpid = 0; 00203 o->retries++; 00204 } else if (!strcasecmp(buf, "delayedretry")) { 00205 } else if (!strcasecmp(buf, "setvar") || !strcasecmp(buf, "set")) { 00206 c2 = c; 00207 strsep(&c2, "="); 00208 if (c2) { 00209 var = ast_variable_new(c, c2); 00210 if (var) { 00211 var->next = o->vars; 00212 o->vars = var; 00213 } 00214 } else { 00215 ast_log(LOG_WARNING, "Malformed Set: argument! Should be Set: Variable=value\n"); 00216 } 00217 } else if (!strcasecmp(buf, "account")) { 00218 ast_copy_string(o->account, c, sizeof(o->account)); 00219 } else { 00220 ast_log(LOG_WARNING, "Unknown keyword '%s' at line %d of %s\n", buf, lineno, fn); 00221 } 00222 } else 00223 ast_log(LOG_NOTICE, "Syntax error at line %d of %s\n", lineno, fn); 00224 } 00225 } 00226 strncpy(o->fn, fn, sizeof(o->fn) - 1); 00227 if (ast_strlen_zero(o->tech) || ast_strlen_zero(o->dest) || (ast_strlen_zero(o->app) && ast_strlen_zero(o->exten))) { 00228 ast_log(LOG_WARNING, "At least one of app or extension must be specified, along with tech and dest in file %s\n", fn); 00229 return -1; 00230 } 00231 return 0; 00232 }
static void* attempt_thread | ( | void * | data | ) | [static] |
Definition at line 255 of file pbx_spool.c.
References outgoing::account, outgoing::app, AST_FORMAT_SLINEAR, ast_log(), ast_pbx_outgoing_app(), ast_pbx_outgoing_exten(), ast_strlen_zero(), ast_verbose(), outgoing::cid_name, outgoing::cid_num, outgoing::context, outgoing::data, outgoing::dest, outgoing::exten, outgoing::fn, free_outgoing(), LOG_EVENT, LOG_NOTICE, outgoing::maxretries, option_verbose, outgoing::priority, outgoing::retries, safe_append(), outgoing::tech, outgoing::vars, VERBOSE_PREFIX_3, and outgoing::waittime.
Referenced by launch_service().
00256 { 00257 struct outgoing *o = data; 00258 int res, reason; 00259 if (!ast_strlen_zero(o->app)) { 00260 if (option_verbose > 2) 00261 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); 00262 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); 00263 } else { 00264 if (option_verbose > 2) 00265 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); 00266 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); 00267 } 00268 if (res) { 00269 ast_log(LOG_NOTICE, "Call failed to go through, reason %d\n", reason); 00270 if (o->retries >= o->maxretries + 1) { 00271 /* Max retries exceeded */ 00272 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" : ""); 00273 unlink(o->fn); 00274 } else { 00275 /* Notate that the call is still active */ 00276 safe_append(o, time(NULL), "EndRetry"); 00277 } 00278 } else { 00279 ast_log(LOG_NOTICE, "Call completed to %s/%s\n", o->tech, o->dest); 00280 ast_log(LOG_EVENT, "Queued call to %s/%s completed\n", o->tech, o->dest); 00281 unlink(o->fn); 00282 } 00283 free_outgoing(o); 00284 return NULL; 00285 }
char* description | ( | void | ) |
Provides a description of the module.
Definition at line 432 of file pbx_spool.c.
00433 { 00434 return tdesc; 00435 }
static void free_outgoing | ( | struct outgoing * | o | ) | [static] |
Definition at line 107 of file pbx_spool.c.
References free.
Referenced by attempt_thread(), launch_service(), and scan_service().
00108 { 00109 free(o); 00110 }
static void init_outgoing | ( | struct outgoing * | o | ) | [static] |
Definition at line 99 of file pbx_spool.c.
References outgoing::priority, outgoing::retrytime, and outgoing::waittime.
Referenced by scan_service().
00100 { 00101 memset(o, 0, sizeof(struct outgoing)); 00102 o->priority = 1; 00103 o->retrytime = 300; 00104 o->waittime = 45; 00105 }
char* key | ( | void | ) |
Returns the ASTERISK_GPL_KEY.
This returns the ASTERISK_GPL_KEY, signifiying that you agree to the terms of the GPL stated in the ASTERISK_GPL_KEY. Your module will not load if it does not return the EXACT message:
char *key(void) { return ASTERISK_GPL_KEY; }
Definition at line 442 of file pbx_spool.c.
References ASTERISK_GPL_KEY.
00443 { 00444 return ASTERISK_GPL_KEY; 00445 }
static void launch_service | ( | struct outgoing * | o | ) | [static] |
Definition at line 287 of file pbx_spool.c.
References ast_log(), ast_pthread_create, attempt_thread(), free_outgoing(), LOG_WARNING, and t.
Referenced by scan_service().
00288 { 00289 pthread_t t; 00290 pthread_attr_t attr; 00291 int ret; 00292 pthread_attr_init(&attr); 00293 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 00294 if ((ret = ast_pthread_create(&t,&attr,attempt_thread, o)) != 0) { 00295 ast_log(LOG_WARNING, "Unable to create thread :( (returned error: %d)\n", ret); 00296 free_outgoing(o); 00297 } 00298 }
int load_module | ( | void | ) |
Initialize the module.
Initialize the Agents module. This function is being called by Asterisk when loading the module. Among other thing it registers applications, cli commands and reads the cofiguration file.
Definition at line 413 of file pbx_spool.c.
References ast_config_AST_SPOOL_DIR, ast_log(), ast_pthread_create, LOG_WARNING, and scan_thread().
00414 { 00415 pthread_t thread; 00416 pthread_attr_t attr; 00417 int ret; 00418 snprintf(qdir, sizeof(qdir), "%s/%s", ast_config_AST_SPOOL_DIR, "outgoing"); 00419 if (mkdir(qdir, 0700) && (errno != EEXIST)) { 00420 ast_log(LOG_WARNING, "Unable to create queue directory %s -- outgoing spool disabled\n", qdir); 00421 return 0; 00422 } 00423 pthread_attr_init(&attr); 00424 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 00425 if ((ret = ast_pthread_create(&thread,&attr,scan_thread, NULL)) != 0) { 00426 ast_log(LOG_WARNING, "Unable to create thread :( (returned error: %d)\n", ret); 00427 return -1; 00428 } 00429 return 0; 00430 }
static void safe_append | ( | struct outgoing * | o, | |
time_t | now, | |||
char * | s | |||
) | [static] |
Definition at line 234 of file pbx_spool.c.
References ast_log(), ast_mainpid, outgoing::fn, LOG_WARNING, outgoing::retries, and outgoing::retrytime.
Referenced by attempt_thread(), and scan_service().
00235 { 00236 int fd; 00237 FILE *f; 00238 struct utimbuf tbuf; 00239 fd = open(o->fn, O_WRONLY|O_APPEND); 00240 if (fd > -1) { 00241 f = fdopen(fd, "a"); 00242 if (f) { 00243 fprintf(f, "%s: %ld %d (%ld)\n", s, (long)ast_mainpid, o->retries, (long) now); 00244 fclose(f); 00245 } else 00246 close(fd); 00247 /* Update the file time */ 00248 tbuf.actime = now; 00249 tbuf.modtime = now + o->retrytime; 00250 if (utime(o->fn, &tbuf)) 00251 ast_log(LOG_WARNING, "Unable to set utime on %s: %s\n", o->fn, strerror(errno)); 00252 } 00253 }
static int scan_service | ( | char * | fn, | |
time_t | now, | |||
time_t | atime | |||
) | [static] |
Definition at line 300 of file pbx_spool.c.
References apply_outgoing(), ast_log(), ast_mainpid, free_outgoing(), init_outgoing(), launch_service(), LOG_DEBUG, LOG_EVENT, LOG_WARNING, malloc, and safe_append().
Referenced by scan_thread().
00301 { 00302 struct outgoing *o; 00303 FILE *f; 00304 o = malloc(sizeof(struct outgoing)); 00305 if (o) { 00306 init_outgoing(o); 00307 f = fopen(fn, "r+"); 00308 if (f) { 00309 if (!apply_outgoing(o, fn, f)) { 00310 #if 0 00311 printf("Filename: %s, Retries: %d, max: %d\n", fn, o->retries, o->maxretries); 00312 #endif 00313 fclose(f); 00314 if (o->retries <= o->maxretries) { 00315 now += o->retrytime; 00316 if (o->callingpid && (o->callingpid == ast_mainpid)) { 00317 safe_append(o, time(NULL), "DelayedRetry"); 00318 free_outgoing(o); 00319 ast_log(LOG_DEBUG, "Delaying retry since we're currently running '%s'\n", o->fn); 00320 } else { 00321 /* Increment retries */ 00322 o->retries++; 00323 /* If someone else was calling, they're presumably gone now 00324 so abort their retry and continue as we were... */ 00325 if (o->callingpid) 00326 safe_append(o, time(NULL), "AbortRetry"); 00327 00328 safe_append(o, now, "StartRetry"); 00329 launch_service(o); 00330 } 00331 return now; 00332 } else { 00333 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" : ""); 00334 free_outgoing(o); 00335 unlink(fn); 00336 return 0; 00337 } 00338 } else { 00339 free_outgoing(o); 00340 ast_log(LOG_WARNING, "Invalid file contents in %s, deleting\n", fn); 00341 fclose(f); 00342 unlink(fn); 00343 } 00344 } else { 00345 free_outgoing(o); 00346 ast_log(LOG_WARNING, "Unable to open %s: %s, deleting\n", fn, strerror(errno)); 00347 unlink(fn); 00348 } 00349 } else 00350 ast_log(LOG_WARNING, "Out of memory :(\n"); 00351 return -1; 00352 }
static void* scan_thread | ( | void * | unused | ) | [static] |
Definition at line 354 of file pbx_spool.c.
References ast_log(), last, LOG_WARNING, and scan_service().
Referenced by load_module().
00355 { 00356 struct stat st; 00357 DIR *dir; 00358 struct dirent *de; 00359 char fn[256]; 00360 int res; 00361 time_t last = 0, next = 0, now; 00362 for(;;) { 00363 /* Wait a sec */ 00364 sleep(1); 00365 time(&now); 00366 if (!stat(qdir, &st)) { 00367 if ((st.st_mtime != last) || (next && (now > next))) { 00368 #if 0 00369 printf("atime: %ld, mtime: %ld, ctime: %ld\n", st.st_atime, st.st_mtime, st.st_ctime); 00370 printf("Ooh, something changed / timeout\n"); 00371 #endif 00372 next = 0; 00373 last = st.st_mtime; 00374 dir = opendir(qdir); 00375 if (dir) { 00376 while((de = readdir(dir))) { 00377 snprintf(fn, sizeof(fn), "%s/%s", qdir, de->d_name); 00378 if (!stat(fn, &st)) { 00379 if (S_ISREG(st.st_mode)) { 00380 if (st.st_mtime <= now) { 00381 res = scan_service(fn, now, st.st_atime); 00382 if (res > 0) { 00383 /* Update next service time */ 00384 if (!next || (res < next)) { 00385 next = res; 00386 } 00387 } else if (res) 00388 ast_log(LOG_WARNING, "Failed to scan service '%s'\n", fn); 00389 } else { 00390 /* Update "next" update if necessary */ 00391 if (!next || (st.st_mtime < next)) 00392 next = st.st_mtime; 00393 } 00394 } 00395 } else 00396 ast_log(LOG_WARNING, "Unable to stat %s: %s\n", fn, strerror(errno)); 00397 } 00398 closedir(dir); 00399 } else 00400 ast_log(LOG_WARNING, "Unable to open directory %s: %s\n", qdir, strerror(errno)); 00401 } 00402 } else 00403 ast_log(LOG_WARNING, "Unable to stat %s\n", qdir); 00404 } 00405 return NULL; 00406 }
int unload_module | ( | void | ) |
Cleanup all module structures, sockets, etc.
Standard module functions ...
Definition at line 408 of file pbx_spool.c.
int usecount | ( | void | ) |
Provides a usecount.
This function will be called by various parts of asterisk. Basically, all it has to do is to return a usecount when called. You will need to maintain your usecount within the module somewhere. The usecount should be how many channels provided by this module are in use.
Definition at line 437 of file pbx_spool.c.
char qdir[255] [static] |
Definition at line 57 of file pbx_spool.c.
char* tdesc = "Outgoing Spool Support" [static] |
Definition at line 56 of file pbx_spool.c.