mirror of
				https://github.com/asterisk/asterisk.git
				synced 2025-10-31 10:47:18 +00:00 
			
		
		
		
	Fix handling of notification calls w/ the dialing api
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@223874 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
		| @@ -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
	
	Block a user