36 #include <sys/inotify.h> 37 #elif defined(HAVE_KQUEUE) 38 #include <sys/types.h> 40 #include <sys/event.h> 102 #if defined(HAVE_INOTIFY) || defined(HAVE_KQUEUE) 111 static void queue_file(
const char *filename, time_t when);
183 while ((c = strchr(c,
'#'))) {
184 if ((c == line) || (*(c-1) ==
' ') || (*(c-1) ==
'\t')) {
192 while ((c = strchr(c,
';'))) {
193 if ((c > line) && (c[-1] ==
'\\')) {
194 memmove(c - 1, c, strlen(c) + 1);
206 c = strchr(line,
':');
214 printf(
"'%s' is '%s' at line %d\n", line, c, lineno);
216 if (!strcasecmp(line,
"channel")) {
218 if ((c2 = strchr(c,
'/'))) {
224 ast_log(
LOG_NOTICE,
"Channel should be in form Tech/Dest at line %d of %s\n", lineno, o->
fn);
226 }
else if (!strcasecmp(line,
"callerid")) {
231 }
else if (!strcasecmp(line,
"application")) {
233 }
else if (!strcasecmp(line,
"data")) {
235 }
else if (!strcasecmp(line,
"maxretries")) {
240 }
else if (!strcasecmp(line,
"codecs")) {
242 }
else if (!strcasecmp(line,
"context")) {
244 }
else if (!strcasecmp(line,
"extension")) {
246 }
else if (!strcasecmp(line,
"priority")) {
251 }
else if (!strcasecmp(line,
"retrytime")) {
256 }
else if (!strcasecmp(line,
"waittime")) {
261 }
else if (!strcasecmp(line,
"retry")) {
263 }
else if (!strcasecmp(line,
"startretry")) {
264 if (sscanf(c,
"%30ld", &o->
callingpid) != 1) {
268 }
else if (!strcasecmp(line,
"endretry") || !strcasecmp(line,
"abortretry")) {
271 }
else if (!strcasecmp(line,
"delayedretry")) {
272 }
else if (!strcasecmp(line,
"setvar") || !strcasecmp(line,
"set")) {
279 ast_log(
LOG_WARNING,
"Malformed \"%s\" argument. Should be \"%s: variable=value\"\n", line, line);
281 }
else if (!strcasecmp(line,
"account")) {
283 }
else if (!strcasecmp(line,
"alwaysdelete")) {
285 }
else if (!strcasecmp(line,
"archive")) {
287 }
else if (!strcasecmp(line,
"early_media")) {
294 #define LINE_BUFFER_SIZE 1024 301 while (fgets(buf,
sizeof(buf), f)) {
302 size_t len = strlen(buf);
306 if (buf[len - 1] ==
'\n' || feof(f)) {
316 while (fgets(buf,
sizeof(buf), f)) {
318 if (buf[len - 1] ==
'\n' || feof(f)) {
328 "along with tech and dest in file %s\n", o->
fn);
332 if (snprintf(buf,
sizeof(buf),
"%d", o->
retries + 1) <
sizeof(buf)) {
342 struct utimbuf tbuf = { .actime = now, .modtime = now + o->
retrytime };
346 if ((f = fopen(o->
fn,
"a"))) {
352 if (utime(o->
fn, &tbuf)) {
369 #if defined(HAVE_INOTIFY) || defined(HAVE_KQUEUE) 374 struct stat current_file_status;
376 if (!stat(o->
fn, ¤t_file_status)) {
377 if (time(
NULL) < current_file_status.st_mtime) {
383 #if defined(HAVE_INOTIFY) || defined(HAVE_KQUEUE) 386 if (!strcmp(cur->
name, o->
fn)) {
402 ast_log(
LOG_WARNING,
"Unable to create queue directory %s -- outgoing spool archiving disabled\n", qdonedir);
407 if (!(bname = strrchr(o->
fn,
'/'))) {
413 snprintf(newfn,
sizeof(newfn),
"%s/%s", qdonedir, bname);
416 if (rename(o->
fn, newfn) != 0) {
423 if ((f = fopen(newfn,
"a"))) {
424 fprintf(f,
"Status: %s\n", status);
458 #if defined(HAVE_INOTIFY) || defined(HAVE_KQUEUE) 494 f = fopen(o->
fn,
"r");
496 #if defined(HAVE_INOTIFY) || defined(HAVE_KQUEUE) 528 ast_debug(1,
"Delaying retry since we're currently running '%s'\n", o->
fn);
544 ast_log(
LOG_NOTICE,
"Queued call to %s/%s expired without completion after %d attempt%s\n",
552 #if defined(HAVE_INOTIFY) 558 #if defined(HAVE_INOTIFY) || defined(HAVE_KQUEUE) 565 time_t now = time(
NULL);
567 if (!strchr(filename,
'/')) {
568 char *
fn =
ast_alloca(strlen(qdir) + strlen(filename) + 2);
569 sprintf(fn,
"%s/%s", qdir, filename);
574 if (stat(filename, &st)) {
579 if (!S_ISREG(st.st_mode)) {
589 if (cur->
mtime == when && !strcmp(filename, cur->
name)) {
595 if ((res = when) > now || (res =
scan_service(filename, now)) > 0) {
596 if (!(
new =
ast_calloc(1,
sizeof(*
new) + strlen(filename) + 1))) {
601 strcpy(new->name, filename);
608 if (cur->
mtime > new->mtime) {
629 if (!strcmp(cur->
name, filename)) {
634 if (!(cur =
ast_calloc(1,
sizeof(*cur) + strlen(filename) + 1))) {
637 strcpy(cur->
name, filename);
648 if (!strcmp(cur->
name, filename)) {
660 time_t now = time(
NULL);
663 if (cur->
mtime > now) {
679 if (!strcmp(cur->
name, filename)) {
695 struct timespec ts = { .tv_sec = 1 };
699 struct inotify_event *iev;
700 char buf[8192] __attribute__((aligned (
sizeof(
int))));
701 struct pollfd pfd = { .fd =
inotify_fd, .events = POLLIN };
703 struct timespec nowait = { .tv_sec = 0, .tv_nsec = 1 };
704 int inotify_fd = kqueue();
711 nanosleep(&ts,
NULL);
714 if (inotify_fd < 0) {
726 inotify_add_watch(inotify_fd, qdir, IN_CREATE | IN_OPEN | IN_CLOSE_WRITE | IN_MOVED_TO);
730 if (!(dir = opendir(qdir))) {
736 EV_SET(&kev, dirfd(dir), EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_CLEAR, NOTE_WRITE, 0,
NULL);
737 if (kevent(inotify_fd, &kev, 1, &event, 1, &nowait) < 0 &&
errno != 0) {
742 while ((de = readdir(dir))) {
761 int waittime = next == INT_MAX ? -1 : (next - now) * 1000;
766 if ((res = poll(&pfd, 1, waittime)) > 0 && (stage = 1) &&
767 (res = read(inotify_fd, &
buf,
sizeof(
buf))) >=
sizeof(*iev)) {
770 for (iev = (
void *)
buf; res >=
sizeof(*iev); iev = (
struct inotify_event *) (((
char *) iev) + len)) {
787 if (iev->mask & IN_CREATE) {
789 }
else if (iev->mask & IN_OPEN) {
791 }
else if (iev->mask & IN_CLOSE_WRITE) {
793 }
else if (iev->mask & IN_MOVED_TO) {
796 ast_log(
LOG_ERROR,
"Unexpected event %d for file '%s'\n", (
int) iev->mask, iev->name);
799 len =
sizeof(*iev) + iev->len;
802 }
else if (res < 0 &&
errno != EINTR &&
errno != EAGAIN) {
803 ast_debug(1,
"Got an error back from %s(2): %s\n", stage ?
"read" :
"poll", strerror(
errno));
811 if (next == INT_MAX) {
812 num_events = kevent(inotify_fd, &kev, 1, &event, 1,
NULL);
814 struct timespec ts2 = { .tv_sec = (
unsigned long int)(next - now), .tv_nsec = 0 };
815 num_events = kevent(inotify_fd, &kev, 1, &event, 1, &ts2);
817 if ((num_events < 0) || (event.flags == EV_ERROR)) {
820 }
else if (num_events == 0) {
826 while ((de = readdir(dir))) {
858 struct timespec ts = { .tv_sec = 1 };
861 nanosleep(&ts,
NULL);
866 nanosleep(&ts,
NULL);
869 if (stat(qdir, &st)) {
875 if (!force_poll && st.st_mtime == last && (!next || now < next)) {
884 printf(
"atime: %ld, mtime: %ld, ctime: %ld\n", st.st_atime, st.st_mtime, st.st_ctime);
885 printf(
"Ooh, something changed / timeout\n");
888 if (!(dir = opendir(qdir))) {
899 force_poll = (st.st_mtime == now);
903 while ((de = readdir(dir))) {
904 snprintf(fn,
sizeof(fn),
"%s/%s", qdir, de->d_name);
909 if (!S_ISREG(st.st_mode)) {
913 if (st.st_mtime <= now) {
917 if (!next || res < next) {
929 if (!next || st.st_mtime < next) {
952 ast_log(
LOG_WARNING,
"Unable to create queue directory %s -- outgoing spool disabled\n", qdir);
static struct outgoing * new_outgoing(const char *fn)
static int scan_service(const char *fn, time_t now)
#define AST_MODULE_INFO_STANDARD(keystr, desc)
#define AST_LIST_LOCK(head)
Locks a list.
static void queue_created_files(void)
Asterisk locking-related definitions:
Asterisk main include file. File version handling, generic pbx functions.
#define AST_LIST_FIRST(head)
Returns the first entry contained in a list.
static int apply_outgoing(struct outgoing *o, FILE *f)
int ast_callerid_split(const char *src, char *name, int namelen, char *num, int numlen)
static char qdonedir[255]
CallerID (and other GR30) management and generation Includes code and algorithms from the Zapata libr...
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
const ast_string_field cid_name
#define ast_pthread_create_detached(a, b, c, d)
#define ast_set2_flag(p, value, flag)
#define ast_test_flag(p, flag)
Time-related functions and macros.
#define ast_set_flag(p, flag)
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
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.
const ast_string_field cid_num
Structure for variables, used for configurations and for channel variables.
struct direntry::@445 list
const ast_string_field app
static void * attempt_thread(void *data)
#define AST_DECLARE_STRING_FIELDS(field_list)
Declare the fields needed in a structure.
#define AST_LIST_EMPTY(head)
Checks whether the specified list contains any entries.
static void free_outgoing(struct outgoing *o)
Generic File Format Support. Should be included by clients of the file handling routines. File service providers should instead include mod_format.h.
int ast_pbx_outgoing_exten(const char *type, struct ast_format_cap *cap, const char *addr, int timeout, const char *context, const char *exten, int priority, int *reason, int synchronous, const char *cid_num, const char *cid_name, struct ast_variable *vars, const char *account, struct ast_channel **locked_channel, int early_media, const struct ast_assigned_ids *assignedids)
Synchronously or asynchronously make an outbound call and send it to a particular extension...
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
const ast_string_field context
#define ast_pthread_create_detached_background(a, b, c, d)
#define ast_verb(level,...)
static void queue_file_write(const char *filename)
#define ast_strlen_zero(foo)
const ast_string_field exten
static void queue_file(const char *filename, time_t when)
#define ast_debug(level,...)
Log a DEBUG message.
const ast_string_field data
General Asterisk PBX channel definitions.
Asterisk file paths, configured in asterisk.conf.
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
struct ast_variable * vars
const ast_string_field account
struct sla_ringing_trunk * last
static void parse_line(char *line, unsigned int lineno, struct outgoing *o)
static void launch_service(struct outgoing *o)
#define AST_STRING_FIELD(name)
Declare a string field.
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
static void append_variable(struct outgoing *o, const char *name, const char *value)
static int load_module(void)
#define ast_variable_new(name, value, filename)
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Core PBX routines and definitions.
#define AST_LIST_HEAD_STATIC(name, type)
Defines a structure to be used to hold a list of specified type, statically initialized.
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
#define AST_LIST_HEAD_NOLOCK_STATIC(name, type)
Defines a structure to be used to hold a list of specified type, statically initialized.
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true". This function checks to see whether a string passed to it is an indication of an "true" value. It checks to see if the string is "yes", "true", "y", "t", "on" or "1".
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
char * ast_skip_blanks(const char *str)
Gets a pointer to the first non-whitespace character in a string.
char * ast_trim_blanks(char *str)
Trims trailing whitespace characters from a string.
int ast_pbx_outgoing_app(const char *type, struct ast_format_cap *cap, const char *addr, int timeout, const char *app, const char *appdata, int *reason, int synchronous, const char *cid_num, const char *cid_name, struct ast_variable *vars, const char *account, struct ast_channel **locked_channel, const struct ast_assigned_ids *assignedids)
Synchronously or asynchronously make an outbound call and execute an application on the channel...
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
#define ast_calloc(num, len)
A wrapper for calloc()
Module could not be loaded properly.
const ast_string_field fn
Module has failed to load, may be in an inconsistent state.
const char * ast_config_AST_SPOOL_DIR
Structure used to handle boolean flags.
static void queue_file_create(const char *filename)
Support for logging to various files, console and syslog Configuration in file logger.conf.
const ast_string_field dest
const ast_string_field tech
char * strsep(char **str, const char *delims)
static void safe_append(struct outgoing *o, time_t now, char *s)
struct ast_format_cap * capabilities
Options provided by main asterisk program.
static void * scan_thread(void *unused)
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
const char * ast_channel_reason2str(int reason)
return an english explanation of the code returned thru __ast_request_and_dial's 'outstate' argument ...
#define AST_LIST_INSERT_BEFORE_CURRENT(elm, field)
Inserts a list entry before the current entry during a traversal.
static void queue_file_open(const char *filename)
#define ASTERISK_GPL_KEY
The text the key() function should return.
Asterisk module definitions.
static int unload_module(void)
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
#define ast_variable_list_append(head, new_var)
int ast_mkdir(const char *path, int mode)
Recursively create directory path.
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.