38 #include <sys/inotify.h>
39 #elif defined(HAVE_KQUEUE)
40 #include <sys/types.h>
42 #include <sys/event.h>
100 #if defined(HAVE_INOTIFY) || defined(HAVE_KQUEUE)
101 static void queue_file(
const char *filename, time_t when);
154 while (last && last->
next) {
158 while(fgets(buf,
sizeof(buf), f)) {
162 while ((c = strchr(c,
'#'))) {
163 if ((c == buf) || (*(c-1) ==
' ') || (*(c-1) ==
'\t'))
170 while ((c = strchr(c,
';'))) {
171 if ((c > buf) && (c[-1] ==
'\\')) {
172 memmove(c - 1, c, strlen(c) + 1);
185 c = strchr(buf,
':');
193 printf(
"'%s' is '%s' at line %d\n", buf, c, lineno);
195 if (!strcasecmp(buf,
"channel")) {
196 if ((c2 = strchr(c,
'/'))) {
202 ast_log(
LOG_NOTICE,
"Channel should be in form Tech/Dest at line %d of %s\n", lineno, o->
fn);
204 }
else if (!strcasecmp(buf,
"callerid")) {
209 }
else if (!strcasecmp(buf,
"application")) {
211 }
else if (!strcasecmp(buf,
"data")) {
213 }
else if (!strcasecmp(buf,
"maxretries")) {
218 }
else if (!strcasecmp(buf,
"codecs")) {
220 }
else if (!strcasecmp(buf,
"context")) {
222 }
else if (!strcasecmp(buf,
"extension")) {
224 }
else if (!strcasecmp(buf,
"priority")) {
229 }
else if (!strcasecmp(buf,
"retrytime")) {
234 }
else if (!strcasecmp(buf,
"waittime")) {
239 }
else if (!strcasecmp(buf,
"retry")) {
241 }
else if (!strcasecmp(buf,
"startretry")) {
242 if (sscanf(c,
"%30ld", &o->
callingpid) != 1) {
246 }
else if (!strcasecmp(buf,
"endretry") || !strcasecmp(buf,
"abortretry")) {
249 }
else if (!strcasecmp(buf,
"delayedretry")) {
250 }
else if (!strcasecmp(buf,
"setvar") || !strcasecmp(buf,
"set")) {
265 ast_log(
LOG_WARNING,
"Malformed \"%s\" argument. Should be \"%s: variable=value\"\n", buf, buf);
266 }
else if (!strcasecmp(buf,
"account")) {
268 }
else if (!strcasecmp(buf,
"alwaysdelete")) {
270 }
else if (!strcasecmp(buf,
"archive")) {
277 ast_log(
LOG_WARNING,
"At least one of app or extension must be specified, along with tech and dest in file %s\n", o->
fn);
286 struct utimbuf tbuf = { .actime = now, .modtime = now + o->
retrytime };
290 if ((f = fopen(o->
fn,
"a"))) {
296 if (utime(o->
fn, &tbuf)) {
314 struct stat current_file_status;
316 if (!stat(o->
fn, ¤t_file_status)) {
317 if (time(NULL) < current_file_status.st_mtime) {
329 ast_log(
LOG_WARNING,
"Unable to create queue directory %s -- outgoing spool archiving disabled\n", qdonedir);
334 if (!(bname = strrchr(o->
fn,
'/'))) {
340 snprintf(newfn,
sizeof(newfn),
"%s/%s", qdonedir, bname);
343 if (rename(o->
fn, newfn) != 0) {
350 if ((f = fopen(newfn,
"a"))) {
351 fprintf(f,
"Status: %s\n", status);
364 res =
ast_pbx_outgoing_app(o->
tech, o->
format, (
void *) o->
dest, o->
waittime * 1000, o->
app, o->
data, &reason, 2 , o->
cid_num, o->
cid_name, o->
vars, o->
account, NULL);
368 res =
ast_pbx_outgoing_exten(o->
tech, o->
format, (
void *) o->
dest, o->
waittime * 1000, o->
context, o->
exten, o->
priority, &reason, 2 , o->
cid_num, o->
cid_name, o->
vars, o->
account, NULL);
380 #if defined(HAVE_INOTIFY) || defined(HAVE_KQUEUE)
416 f = fopen(o->
fn,
"r");
418 #if defined(HAVE_INOTIFY) || defined(HAVE_KQUEUE)
466 ast_log(
LOG_NOTICE,
"Queued call to %s/%s expired without completion after %d attempt%s\n",
473 #if defined(HAVE_INOTIFY) || defined(HAVE_KQUEUE)
482 #if defined(HAVE_INOTIFY)
491 struct direntry *cur, *
new;
493 time_t now = time(NULL);
495 if (!strchr(filename,
'/')) {
496 char *fn =
ast_alloca(strlen(qdir) + strlen(filename) + 2);
497 sprintf(fn,
"%s/%s", qdir, filename);
502 if (stat(filename, &st)) {
507 if (!S_ISREG(st.st_mode)) {
517 if (cur->
mtime == when && !strcmp(filename, cur->
name)) {
523 if ((res = when) > now || (res =
scan_service(filename, now)) > 0) {
524 if (!(
new =
ast_calloc(1,
sizeof(*
new) + strlen(filename) + 1))) {
529 strcpy(new->name, filename);
536 if (cur->
mtime > new->mtime) {
554 struct direntry *cur;
557 if (!strcmp(cur->
name, filename)) {
562 if (!(cur =
ast_calloc(1,
sizeof(*cur) + strlen(filename) + 1))) {
565 strcpy(cur->
name, filename);
567 cur->
mtime = time(NULL) + 2;
573 struct direntry *cur;
576 if (!strcmp(cur->
name, filename)) {
587 struct direntry *cur;
588 time_t now = time(NULL);
591 if (cur->
mtime > now) {
604 struct direntry *cur;
607 if (!strcmp(cur->
name, filename)) {
623 struct timespec ts = { .tv_sec = 1 };
627 struct inotify_event *iev;
628 char buf[8192] __attribute__((aligned (
sizeof(
int))));
629 struct pollfd pfd = { .fd =
inotify_fd, .events = POLLIN };
631 struct timespec nowait = { .tv_sec = 0, .tv_nsec = 1 };
632 int inotify_fd = kqueue();
636 struct direntry *cur;
639 nanosleep(&ts, NULL);
642 if (inotify_fd < 0) {
654 inotify_add_watch(inotify_fd, qdir, IN_CREATE | IN_OPEN | IN_CLOSE_WRITE | IN_MOVED_TO);
658 if (!(dir = opendir(qdir))) {
664 EV_SET(&kev, dirfd(dir), EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_CLEAR, NOTE_WRITE, 0, NULL);
665 if (kevent(inotify_fd, &kev, 1, &event, 1, &nowait) < 0 &&
errno != 0) {
670 while ((de = readdir(dir))) {
689 int waittime = next == INT_MAX ? -1 : (next - now) * 1000;
694 if ((res = poll(&pfd, 1, waittime)) > 0 && (stage = 1) &&
695 (res = read(inotify_fd, &buf,
sizeof(buf))) >=
sizeof(*iev)) {
698 for (iev = (
void *) buf; res >=
sizeof(*iev); iev = (
struct inotify_event *) (((
char *) iev) + len)) {
715 if (iev->mask & IN_CREATE) {
717 }
else if (iev->mask & IN_OPEN) {
719 }
else if (iev->mask & IN_CLOSE_WRITE) {
721 }
else if (iev->mask & IN_MOVED_TO) {
724 ast_log(
LOG_ERROR,
"Unexpected event %d for file '%s'\n", (
int) iev->mask, iev->name);
727 len =
sizeof(*iev) + iev->len;
730 }
else if (res < 0 &&
errno != EINTR &&
errno != EAGAIN) {
731 ast_debug(1,
"Got an error back from %s(2): %s\n", stage ?
"read" :
"poll", strerror(
errno));
739 if (next == INT_MAX) {
740 num_events = kevent(inotify_fd, &kev, 1, &event, 1, NULL);
742 struct timespec ts2 = { .tv_sec = (
unsigned long int)(next - now), .tv_nsec = 0 };
743 num_events = kevent(inotify_fd, &kev, 1, &event, 1, &ts2);
745 if ((num_events < 0) || (event.flags == EV_ERROR)) {
748 }
else if (num_events == 0) {
754 while ((de = readdir(dir))) {
786 struct timespec ts = { .tv_sec = 1 };
789 nanosleep(&ts, NULL);
794 nanosleep(&ts, NULL);
797 if (stat(qdir, &st)) {
803 if (!force_poll && st.st_mtime == last && (!next || now < next)) {
812 printf(
"atime: %ld, mtime: %ld, ctime: %ld\n", st.st_atime, st.st_mtime, st.st_ctime);
813 printf(
"Ooh, something changed / timeout\n");
816 if (!(dir = opendir(qdir))) {
827 force_poll = (st.st_mtime == now);
831 while ((de = readdir(dir))) {
832 snprintf(fn,
sizeof(fn),
"%s/%s", qdir, de->d_name);
837 if (!S_ISREG(st.st_mode)) {
841 if (st.st_mtime <= now) {
845 if (!next || res < next) {
857 if (!next || st.st_mtime < next) {
880 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)
static char exten[AST_MAX_EXTENSION]
#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)
char * strsep(char **str, const char *delims)
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...
const ast_string_field cid_name
#define ast_pthread_create_detached(a, b, c, d)
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
#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.
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)
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Generic File Format Support. Should be included by clients of the file handling routines. File service providers should instead include mod_format.h.
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
static char cid_num[AST_MAX_EXTENSION]
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)
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
static force_inline int attribute_pure ast_strlen_zero(const char *s)
const ast_string_field account
struct sla_ringing_trunk * last
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 int load_module(void)
#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_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 ast_pbx_outgoing_exten(const char *type, format_t format, void *data, int timeout, const char *context, const char *exten, int priority, int *reason, int sync, const char *cid_num, const char *cid_name, struct ast_variable *vars, const char *account, struct ast_channel **locked_channel)
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.
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
char * ast_trim_blanks(char *str)
Trims trailing whitespace characters from a string.
#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.
struct direntry::@320 list
const ast_string_field fn
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.
static char cid_name[AST_MAX_EXTENSION]
const ast_string_field dest
const ast_string_field tech
#define AST_FORMAT_SLINEAR
static void safe_append(struct outgoing *o, time_t now, char *s)
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.
struct ast_variable * next
const char * ast_channel_reason2str(int reason)
return an english explanation of the code returned thru __ast_request_and_dial's 'outstate' argument ...
static char context[AST_MAX_CONTEXT]
int ast_pbx_outgoing_app(const char *type, format_t format, void *data, int timeout, const char *app, const char *appdata, int *reason, int sync, const char *cid_num, const char *cid_name, struct ast_variable *vars, const char *account, struct ast_channel **locked_channel)
#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
struct ast_variable * ast_variable_new(const char *name, const char *value, const char *filename)
int ast_parse_allow_disallow(struct ast_codec_pref *pref, format_t *mask, const char *list, int allowing)
Parse an "allow" or "deny" line in a channel or device configuration and update the capabilities mask...
#define ASTERISK_FILE_VERSION(file, version)
Register/unregister a source code file with the core.
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.