Fix handling of notification calls w/ the dialing api
git-svn-id: http://svn.digium.com/svn/asterisk/trunk@223874 f38db490-d61c-443f-a65b-d21fe96a405b
This commit is contained in:
parent
a29053887d
commit
0e46ff9d32
|
@ -41,6 +41,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||||
#include "asterisk/pbx.h"
|
#include "asterisk/pbx.h"
|
||||||
#include "asterisk/module.h"
|
#include "asterisk/module.h"
|
||||||
#include "asterisk/app.h"
|
#include "asterisk/app.h"
|
||||||
|
#include "asterisk/dial.h"
|
||||||
|
|
||||||
static const char app_originate[] = "Originate";
|
static const char app_originate[] = "Originate";
|
||||||
|
|
||||||
|
@ -105,6 +106,9 @@ static int originate_exec(struct ast_channel *chan, const char *data)
|
||||||
int outgoing_status = 0;
|
int outgoing_status = 0;
|
||||||
static const unsigned int timeout = 30;
|
static const unsigned int timeout = 30;
|
||||||
static const char default_exten[] = "s";
|
static const char default_exten[] = "s";
|
||||||
|
struct ast_dial *dial = NULL;
|
||||||
|
struct ast_str *buf = NULL;
|
||||||
|
struct ast_channel *c = NULL;
|
||||||
|
|
||||||
ast_autoservice_start(chan);
|
ast_autoservice_start(chan);
|
||||||
|
|
||||||
|
@ -130,7 +134,30 @@ static int originate_exec(struct ast_channel *chan, const char *data)
|
||||||
goto return_cleanup;
|
goto return_cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!strcasecmp(args.type, "exten")) {
|
if (strstr(args.type, "async")) {
|
||||||
|
if (!(dial = ast_dial_create())) {
|
||||||
|
goto return_cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ast_dial_append(dial, chantech, chandata)) {
|
||||||
|
goto return_cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(buf = ast_str_create(32))) {
|
||||||
|
goto return_cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(c = ast_channel_alloc(1, AST_STATE_DOWN, 0, 0, 0, 0, 0, 0, 0, "Originate/%s-%08lx", args.arg1, ast_random()))) {
|
||||||
|
ast_free(buf);
|
||||||
|
goto return_cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
c->nativeformats = AST_FORMAT_SLINEAR;
|
||||||
|
ast_dial_set_global_timeout(dial, 30 * 1000);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strncasecmp(args.type, "exten", 5)) {
|
||||||
int priority = 1; /* Initialized in case priority not specified */
|
int priority = 1; /* Initialized in case priority not specified */
|
||||||
const char *exten = args.arg2;
|
const char *exten = args.arg2;
|
||||||
|
|
||||||
|
@ -148,16 +175,28 @@ static int originate_exec(struct ast_channel *chan, const char *data)
|
||||||
ast_debug(1, "Originating call to '%s/%s' and connecting them to extension %s,%s,%d\n",
|
ast_debug(1, "Originating call to '%s/%s' and connecting them to extension %s,%s,%d\n",
|
||||||
chantech, chandata, args.arg1, exten, priority);
|
chantech, chandata, args.arg1, exten, priority);
|
||||||
|
|
||||||
outgoing_res = ast_pbx_outgoing_exten(chantech, AST_FORMAT_SLINEAR, chandata,
|
if (!strcasecmp(args.type, "exten-async")) {
|
||||||
timeout * 1000, args.arg1, exten, priority, &outgoing_status, 0, NULL,
|
ast_str_set(&buf, 0, "Dial,Local/%s@%s", exten, args.arg1);
|
||||||
NULL, NULL, NULL, NULL);
|
ast_dial_option_global_enable(dial, AST_DIAL_OPTION_ANSWER_EXEC, ast_str_buffer(buf));
|
||||||
} else if (!strcasecmp(args.type, "app")) {
|
ast_dial_run(dial, NULL, 1);
|
||||||
|
} else {
|
||||||
|
outgoing_res = ast_pbx_outgoing_exten(chantech, AST_FORMAT_SLINEAR, chandata,
|
||||||
|
timeout * 1000, args.arg1, exten, priority, &outgoing_status, 0, NULL,
|
||||||
|
NULL, NULL, NULL, NULL);
|
||||||
|
}
|
||||||
|
} else if (!strncasecmp(args.type, "app", 3)) {
|
||||||
ast_debug(1, "Originating call to '%s/%s' and connecting them to %s(%s)\n",
|
ast_debug(1, "Originating call to '%s/%s' and connecting them to %s(%s)\n",
|
||||||
chantech, chandata, args.arg1, S_OR(args.arg2, ""));
|
chantech, chandata, args.arg1, S_OR(args.arg2, ""));
|
||||||
|
|
||||||
outgoing_res = ast_pbx_outgoing_app(chantech, AST_FORMAT_SLINEAR, chandata,
|
if (!strcasecmp(args.type, "app-async")) {
|
||||||
timeout * 1000, args.arg1, args.arg2, &outgoing_status, 0, NULL,
|
ast_str_set(&buf, 0, "%s,%s", args.arg1, args.arg2);
|
||||||
NULL, NULL, NULL, NULL);
|
ast_dial_option_global_enable(dial, AST_DIAL_OPTION_ANSWER_EXEC, ast_str_buffer(buf));
|
||||||
|
ast_dial_run(dial, c, 1);
|
||||||
|
} else {
|
||||||
|
outgoing_res = ast_pbx_outgoing_app(chantech, AST_FORMAT_SLINEAR, chandata,
|
||||||
|
timeout * 1000, args.arg1, args.arg2, &outgoing_status, 0, NULL,
|
||||||
|
NULL, NULL, NULL, NULL);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
ast_log(LOG_ERROR, "Incorrect type, it should be 'exten' or 'app': %s\n",
|
ast_log(LOG_ERROR, "Incorrect type, it should be 'exten' or 'app': %s\n",
|
||||||
args.type);
|
args.type);
|
||||||
|
@ -194,6 +233,12 @@ return_cleanup:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (buf) {
|
||||||
|
ast_free(buf);
|
||||||
|
}
|
||||||
|
if (c) {
|
||||||
|
ast_channel_release(c);
|
||||||
|
}
|
||||||
|
|
||||||
ast_autoservice_stop(chan);
|
ast_autoservice_stop(chan);
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#include "asterisk/config.h"
|
#include "asterisk/config.h"
|
||||||
#include "asterisk/linkedlists.h"
|
#include "asterisk/linkedlists.h"
|
||||||
#include "asterisk/lock.h"
|
#include "asterisk/lock.h"
|
||||||
|
#include "asterisk/dial.h"
|
||||||
|
|
||||||
/*! \file calendar.h
|
/*! \file calendar.h
|
||||||
* \brief A general API for managing calendar events with Asterisk
|
* \brief A general API for managing calendar events with Asterisk
|
||||||
|
@ -103,6 +104,8 @@ struct ast_calendar_event {
|
||||||
int notify_sched; /*!< The sched for event notification */
|
int notify_sched; /*!< The sched for event notification */
|
||||||
int bs_start_sched; /*!< The sched for changing the device state at the start of an event */
|
int bs_start_sched; /*!< The sched for changing the device state at the start of an event */
|
||||||
int bs_end_sched; /*!< The sched for changing the device state at the end of an event */
|
int bs_end_sched; /*!< The sched for changing the device state at the end of an event */
|
||||||
|
struct ast_dial *dial;
|
||||||
|
struct ast_channel *notify_chan;
|
||||||
AST_LIST_HEAD_NOLOCK(attendees, ast_calendar_attendee) attendees;
|
AST_LIST_HEAD_NOLOCK(attendees, ast_calendar_attendee) attendees;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -611,31 +611,33 @@ static char *generate_random_string(char *buf, size_t size)
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int calendar_event_notify(const void *data)
|
static int null_chan_write(struct ast_channel *chan, struct ast_frame *frame)
|
||||||
{
|
{
|
||||||
struct ast_calendar_event *event = (void *)data;
|
return 0;
|
||||||
char tech[256], dest[256], buf[8], *tmp;
|
}
|
||||||
struct ast_dial *dial = NULL;
|
|
||||||
struct ast_channel *chan = NULL;
|
static const struct ast_channel_tech null_tech = {
|
||||||
|
.type = "NULL",
|
||||||
|
.description = "Null channel (should not see this)",
|
||||||
|
.write = null_chan_write,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void *do_notify(void *data)
|
||||||
|
{
|
||||||
|
struct ast_calendar_event *event = data;
|
||||||
|
struct ast_dial *dial;
|
||||||
struct ast_str *apptext = NULL;
|
struct ast_str *apptext = NULL;
|
||||||
int res = -1;
|
|
||||||
char start[12], end[12], busystate[2];
|
|
||||||
struct ast_datastore *datastore;
|
struct ast_datastore *datastore;
|
||||||
|
enum ast_dial_result res;
|
||||||
|
struct ast_channel *chan = NULL;
|
||||||
|
char *tech, *dest;
|
||||||
|
char buf[8];
|
||||||
|
|
||||||
if (!(event && event->owner)) {
|
tech = ast_strdupa(event->owner->notify_channel);
|
||||||
ast_log(LOG_ERROR, "Extremely low-cal...in fact cal is NULL!\n");
|
|
||||||
goto notify_cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
ao2_ref(event, +1);
|
if ((dest = strchr(tech, '/'))) {
|
||||||
event->notify_sched = -1;
|
*dest = '\0';
|
||||||
|
dest++;
|
||||||
ast_copy_string(tech, event->owner->notify_channel, sizeof(tech));
|
|
||||||
|
|
||||||
if ((tmp = strchr(tech, '/'))) {
|
|
||||||
*tmp = '\0';
|
|
||||||
tmp++;
|
|
||||||
ast_copy_string(dest, tmp, sizeof(dest));
|
|
||||||
} else {
|
} else {
|
||||||
ast_log(LOG_WARNING, "Channel should be in form Tech/Dest (was '%s')\n", tech);
|
ast_log(LOG_WARNING, "Channel should be in form Tech/Dest (was '%s')\n", tech);
|
||||||
goto notify_cleanup;
|
goto notify_cleanup;
|
||||||
|
@ -653,16 +655,15 @@ static int calendar_event_notify(const void *data)
|
||||||
|
|
||||||
ast_dial_set_global_timeout(dial, event->owner->notify_waittime);
|
ast_dial_set_global_timeout(dial, event->owner->notify_waittime);
|
||||||
generate_random_string(buf, sizeof(buf));
|
generate_random_string(buf, sizeof(buf));
|
||||||
|
|
||||||
if (!(chan = ast_channel_alloc(1, AST_STATE_DOWN, 0, 0, 0, 0, 0, 0, 0, "Calendar/%s-%s", event->owner->name, buf))) {
|
if (!(chan = ast_channel_alloc(1, AST_STATE_DOWN, 0, 0, 0, 0, 0, 0, 0, "Calendar/%s-%s", event->owner->name, buf))) {
|
||||||
ast_log(LOG_ERROR, "Could not allocate notification channel\n");
|
ast_log(LOG_ERROR, "Could not allocate notification channel\n");
|
||||||
goto notify_cleanup;
|
goto notify_cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
snprintf(busystate, sizeof(busystate), "%d", event->busy_state);
|
chan->tech = &null_tech;
|
||||||
snprintf(start, sizeof(start), "%lu", (long) event->start);
|
chan->nativeformats = chan->writeformat = chan->rawwriteformat =
|
||||||
snprintf(end, sizeof(end), "%lu", (long) event->end);
|
chan->readformat = chan->rawreadformat = AST_FORMAT_SLINEAR;
|
||||||
|
|
||||||
chan->nativeformats = AST_FORMAT_SLINEAR;
|
|
||||||
|
|
||||||
if (!(datastore = ast_datastore_alloc(&event_notification_datastore, NULL))) {
|
if (!(datastore = ast_datastore_alloc(&event_notification_datastore, NULL))) {
|
||||||
ast_log(LOG_ERROR, "Could not allocate datastore, notification not being sent!\n");
|
ast_log(LOG_ERROR, "Could not allocate datastore, notification not being sent!\n");
|
||||||
|
@ -681,26 +682,64 @@ static int calendar_event_notify(const void *data)
|
||||||
|
|
||||||
if (!ast_strlen_zero(event->owner->notify_app)) {
|
if (!ast_strlen_zero(event->owner->notify_app)) {
|
||||||
ast_str_set(&apptext, 0, "%s,%s", event->owner->notify_app, event->owner->notify_appdata);
|
ast_str_set(&apptext, 0, "%s,%s", event->owner->notify_app, event->owner->notify_appdata);
|
||||||
|
ast_dial_option_global_enable(dial, AST_DIAL_OPTION_ANSWER_EXEC, ast_str_buffer(apptext));
|
||||||
} else {
|
} else {
|
||||||
ast_str_set(&apptext, 0, "Dial,Local/%s@%s", event->owner->notify_extension, event->owner->notify_context);
|
|
||||||
}
|
}
|
||||||
ast_dial_option_global_enable(dial, AST_DIAL_OPTION_ANSWER_EXEC, ast_str_buffer(apptext));
|
|
||||||
|
|
||||||
ast_dial_run(dial, chan, 1);
|
ast_verb(3, "Dialing %s for notification on calendar %s\n", event->owner->notify_channel, event->owner->name);
|
||||||
res = 0;
|
res = ast_dial_run(dial, chan, 0);
|
||||||
|
|
||||||
|
if (res != AST_DIAL_RESULT_ANSWERED) {
|
||||||
|
ast_verb(3, "Notification call for %s was not completed\n", event->owner->name);
|
||||||
|
} else {
|
||||||
|
struct ast_channel *answered;
|
||||||
|
|
||||||
|
answered = ast_dial_answered_steal(dial);
|
||||||
|
if (ast_strlen_zero(event->owner->notify_app)) {
|
||||||
|
ast_copy_string(answered->context, event->owner->notify_context, sizeof(answered->context));
|
||||||
|
ast_copy_string(answered->exten, event->owner->notify_extension, sizeof(answered->exten));
|
||||||
|
answered->priority = 1;
|
||||||
|
ast_pbx_run(answered);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
notify_cleanup:
|
notify_cleanup:
|
||||||
event = ast_calendar_unref_event(event);
|
|
||||||
if (res == -1 && dial) {
|
|
||||||
ast_dial_destroy(dial);
|
|
||||||
}
|
|
||||||
if (apptext) {
|
if (apptext) {
|
||||||
ast_free(apptext);
|
ast_free(apptext);
|
||||||
}
|
}
|
||||||
|
if (dial) {
|
||||||
|
ast_dial_destroy(dial);
|
||||||
|
}
|
||||||
if (chan) {
|
if (chan) {
|
||||||
ast_channel_release(chan);
|
ast_channel_release(chan);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
event = ast_calendar_unref_event(event);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int calendar_event_notify(const void *data)
|
||||||
|
{
|
||||||
|
struct ast_calendar_event *event = (void *)data;
|
||||||
|
int res = -1;
|
||||||
|
pthread_t notify_thread = AST_PTHREADT_NULL;
|
||||||
|
|
||||||
|
if (!(event && event->owner)) {
|
||||||
|
ast_log(LOG_ERROR, "Extremely low-cal...in fact cal is NULL!\n");
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
ao2_ref(event, +1);
|
||||||
|
event->notify_sched = -1;
|
||||||
|
|
||||||
|
if (ast_pthread_create_background(¬ify_thread, NULL, do_notify, event) < 0) {
|
||||||
|
ast_log(LOG_ERROR, "Could not create notification thread\n");
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = 0;
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1342,7 +1381,7 @@ static char *epoch_to_string(char *buf, size_t buflen, time_t epoch)
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
ast_localtime(&tv, &tm, NULL);
|
ast_localtime(&tv, &tm, NULL);
|
||||||
ast_strftime(buf, buflen, "%F %r", &tm);
|
ast_strftime(buf, buflen, "%F %r %z", &tm);
|
||||||
|
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
Reference in New Issue