diff --git a/apps/app_originate.c b/apps/app_originate.c index 659ea2949f02c05bb0bb72972b520497ce112a44..22c860dcdbcdc963409d07f25b29fa2a1c895269 100644 --- a/apps/app_originate.c +++ b/apps/app_originate.c @@ -41,6 +41,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/pbx.h" #include "asterisk/module.h" #include "asterisk/app.h" +#include "asterisk/dial.h" 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; static const unsigned int timeout = 30; 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); @@ -130,7 +134,30 @@ static int originate_exec(struct ast_channel *chan, const char *data) 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 */ 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", chantech, chandata, args.arg1, exten, priority); - 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 (!strcasecmp(args.type, "app")) { + if (!strcasecmp(args.type, "exten-async")) { + ast_str_set(&buf, 0, "Dial,Local/%s@%s", exten, args.arg1); + ast_dial_option_global_enable(dial, AST_DIAL_OPTION_ANSWER_EXEC, ast_str_buffer(buf)); + 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", chantech, chandata, args.arg1, S_OR(args.arg2, "")); - 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); + if (!strcasecmp(args.type, "app-async")) { + ast_str_set(&buf, 0, "%s,%s", args.arg1, args.arg2); + 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 { ast_log(LOG_ERROR, "Incorrect type, it should be 'exten' or 'app': %s\n", args.type); @@ -194,6 +233,12 @@ return_cleanup: break; } } + if (buf) { + ast_free(buf); + } + if (c) { + ast_channel_release(c); + } ast_autoservice_stop(chan); diff --git a/include/asterisk/calendar.h b/include/asterisk/calendar.h index 29c67de17205d6a76b4651a17c8f11ec3a494d8a..13f7ce728af1abfcab4f2c993ace9508af6e600d 100644 --- a/include/asterisk/calendar.h +++ b/include/asterisk/calendar.h @@ -24,6 +24,7 @@ #include "asterisk/config.h" #include "asterisk/linkedlists.h" #include "asterisk/lock.h" +#include "asterisk/dial.h" /*! \file calendar.h * \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 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 */ + struct ast_dial *dial; + struct ast_channel *notify_chan; AST_LIST_HEAD_NOLOCK(attendees, ast_calendar_attendee) attendees; }; diff --git a/res/res_calendar.c b/res/res_calendar.c index 5239fa63317bd6e698134ccec2dcf36124ca6a4b..abbfc4d7e4a6402c8769fd90690803cbcccd902e 100644 --- a/res/res_calendar.c +++ b/res/res_calendar.c @@ -611,31 +611,33 @@ static char *generate_random_string(char *buf, size_t size) 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; - char tech[256], dest[256], buf[8], *tmp; - struct ast_dial *dial = NULL; - struct ast_channel *chan = NULL; - struct ast_str *apptext = NULL; - int res = -1; - char start[12], end[12], busystate[2]; - struct ast_datastore *datastore; + return 0; +} - if (!(event && event->owner)) { - ast_log(LOG_ERROR, "Extremely low-cal...in fact cal is NULL!\n"); - goto notify_cleanup; - } +static const struct ast_channel_tech null_tech = { + .type = "NULL", + .description = "Null channel (should not see this)", + .write = null_chan_write, +}; - ao2_ref(event, +1); - event->notify_sched = -1; +static void *do_notify(void *data) +{ + struct ast_calendar_event *event = data; + struct ast_dial *dial; + struct ast_str *apptext = NULL; + struct ast_datastore *datastore; + enum ast_dial_result res; + struct ast_channel *chan = NULL; + char *tech, *dest; + char buf[8]; - ast_copy_string(tech, event->owner->notify_channel, sizeof(tech)); + tech = ast_strdupa(event->owner->notify_channel); - if ((tmp = strchr(tech, '/'))) { - *tmp = '\0'; - tmp++; - ast_copy_string(dest, tmp, sizeof(dest)); + if ((dest = strchr(tech, '/'))) { + *dest = '\0'; + dest++; } else { ast_log(LOG_WARNING, "Channel should be in form Tech/Dest (was '%s')\n", tech); 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); 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))) { ast_log(LOG_ERROR, "Could not allocate notification channel\n"); goto notify_cleanup; } - snprintf(busystate, sizeof(busystate), "%d", event->busy_state); - snprintf(start, sizeof(start), "%lu", (long) event->start); - snprintf(end, sizeof(end), "%lu", (long) event->end); - - chan->nativeformats = AST_FORMAT_SLINEAR; + chan->tech = &null_tech; + chan->nativeformats = chan->writeformat = chan->rawwriteformat = + chan->readformat = chan->rawreadformat = AST_FORMAT_SLINEAR; if (!(datastore = ast_datastore_alloc(&event_notification_datastore, NULL))) { 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)) { 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 { - 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); - res = 0; + ast_verb(3, "Dialing %s for notification on calendar %s\n", event->owner->notify_channel, event->owner->name); + res = ast_dial_run(dial, chan, 0); -notify_cleanup: - event = ast_calendar_unref_event(event); - if (res == -1 && dial) { - ast_dial_destroy(dial); + 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: if (apptext) { ast_free(apptext); } + if (dial) { + ast_dial_destroy(dial); + } if (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; } @@ -1342,7 +1381,7 @@ static char *epoch_to_string(char *buf, size_t buflen, time_t epoch) return buf; } ast_localtime(&tv, &tm, NULL); - ast_strftime(buf, buflen, "%F %r", &tm); + ast_strftime(buf, buflen, "%F %r %z", &tm); return buf; }