| 
									
										
										
										
											2005-08-10 23:24:39 +00:00
										 |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2005-09-14 20:46:50 +00:00
										 |  |  |  * Asterisk -- An open source telephony toolkit. | 
					
						
							| 
									
										
										
										
											2005-08-10 23:24:39 +00:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2005-09-14 20:46:50 +00:00
										 |  |  |  * Copyright (C) 1999 - 2005, Digium, Inc. | 
					
						
							| 
									
										
										
										
											2005-08-10 23:24:39 +00:00
										 |  |  |  * | 
					
						
							|  |  |  |  * Kevin P. Fleming <kpfleming@digium.com> | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Portions taken from the file-based music-on-hold work | 
					
						
							|  |  |  |  * created by Anthony Minessale II in res_musiconhold.c | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2005-09-14 20:46:50 +00:00
										 |  |  |  * See http://www.asterisk.org for more information about
 | 
					
						
							|  |  |  |  * the Asterisk project. Please do not directly contact | 
					
						
							|  |  |  |  * any of the maintainers of this project for assistance; | 
					
						
							|  |  |  |  * the project provides a web site, mailing lists and IRC | 
					
						
							|  |  |  |  * channels for your use. | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2005-08-10 23:24:39 +00:00
										 |  |  |  * This program is free software, distributed under the terms of | 
					
						
							| 
									
										
										
										
											2005-09-14 20:46:50 +00:00
										 |  |  |  * the GNU General Public License Version 2. See the LICENSE file | 
					
						
							|  |  |  |  * at the top of the source tree. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-10-24 20:12:06 +00:00
										 |  |  | /*! \file
 | 
					
						
							| 
									
										
										
										
											2005-09-14 20:46:50 +00:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2005-10-24 20:12:06 +00:00
										 |  |  |  * \brief External IVR application interface | 
					
						
							| 
									
										
										
										
											2005-12-30 21:18:06 +00:00
										 |  |  |  * | 
					
						
							|  |  |  |  * \author Kevin P. Fleming <kpfleming@digium.com> | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \note Portions taken from the file-based music-on-hold work | 
					
						
							|  |  |  |  * created by Anthony Minessale II in res_musiconhold.c | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2005-11-06 15:09:47 +00:00
										 |  |  |  * \ingroup applications | 
					
						
							| 
									
										
										
										
											2005-08-10 23:24:39 +00:00
										 |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-14 20:28:54 +00:00
										 |  |  | /*** MODULEINFO
 | 
					
						
							|  |  |  | 	<support_level>extended</support_level> | 
					
						
							|  |  |  |  ***/ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-06-07 18:54:56 +00:00
										 |  |  | #include "asterisk.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-12-11 00:52:19 +00:00
										 |  |  | #include <signal.h>
 | 
					
						
							| 
									
										
										
										
											2005-08-10 23:24:39 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | #include "asterisk/lock.h"
 | 
					
						
							|  |  |  | #include "asterisk/file.h"
 | 
					
						
							|  |  |  | #include "asterisk/channel.h"
 | 
					
						
							|  |  |  | #include "asterisk/pbx.h"
 | 
					
						
							|  |  |  | #include "asterisk/module.h"
 | 
					
						
							|  |  |  | #include "asterisk/linkedlists.h"
 | 
					
						
							| 
									
										
										
										
											2005-12-01 02:32:10 +00:00
										 |  |  | #include "asterisk/app.h"
 | 
					
						
							| 
									
										
										
										
											2006-01-11 22:41:34 +00:00
										 |  |  | #include "asterisk/utils.h"
 | 
					
						
							| 
									
										
										
										
											2008-03-13 18:59:04 +00:00
										 |  |  | #include "asterisk/tcptls.h"
 | 
					
						
							| 
									
										
										
										
											2008-10-19 19:11:28 +00:00
										 |  |  | #include "asterisk/astobj2.h"
 | 
					
						
							| 
									
										
										
										
											2005-08-10 23:24:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-06-07 17:29:44 +00:00
										 |  |  | /*** DOCUMENTATION
 | 
					
						
							|  |  |  | 	<application name="ExternalIVR" language="en_US"> | 
					
						
							|  |  |  | 		<synopsis> | 
					
						
							|  |  |  | 			Interfaces with an external IVR application. | 
					
						
							|  |  |  | 		</synopsis> | 
					
						
							|  |  |  | 		<syntax> | 
					
						
							|  |  |  | 			<parameter name="command|ivr://host" required="true" hasparams="true"> | 
					
						
							|  |  |  | 				<argument name="arg1" /> | 
					
						
							|  |  |  | 				<argument name="arg2" multiple="yes" /> | 
					
						
							|  |  |  | 			</parameter> | 
					
						
							|  |  |  | 			<parameter name="options"> | 
					
						
							|  |  |  | 				<optionlist> | 
					
						
							|  |  |  | 					<option name="n"> | 
					
						
							|  |  |  | 						<para>Tells ExternalIVR() not to answer the channel.</para> | 
					
						
							|  |  |  | 					</option> | 
					
						
							|  |  |  | 					<option name="i"> | 
					
						
							|  |  |  | 						<para>Tells ExternalIVR() not to send a hangup and exit when the | 
					
						
							|  |  |  | 						channel receives a hangup, instead it sends an <literal>I</literal> | 
					
						
							|  |  |  | 						informative message meaning that the external application MUST hang | 
					
						
							|  |  |  | 						up the call with an <literal>H</literal> command.</para> | 
					
						
							|  |  |  | 					</option> | 
					
						
							|  |  |  | 					<option name="d"> | 
					
						
							|  |  |  | 						<para>Tells ExternalIVR() to run on a channel that has been hung up | 
					
						
							|  |  |  | 						and will not look for hangups. The external application must exit with | 
					
						
							|  |  |  | 						an <literal>E</literal> command.</para> | 
					
						
							|  |  |  | 					</option> | 
					
						
							|  |  |  | 				</optionlist> | 
					
						
							|  |  |  | 			</parameter> | 
					
						
							|  |  |  | 		</syntax> | 
					
						
							|  |  |  | 		<description> | 
					
						
							|  |  |  | 			<para>Either forks a process to run given command or makes a socket to connect | 
					
						
							|  |  |  | 			to given host and starts a generator on the channel. The generator's play list | 
					
						
							|  |  |  | 			is controlled by the external application, which can add and clear entries via | 
					
						
							|  |  |  | 			simple commands issued over its stdout. The external application will receive | 
					
						
							|  |  |  | 			all DTMF events received on the channel, and notification if the channel is | 
					
						
							|  |  |  | 			hung up. The received on the channel, and notification if the channel is hung | 
					
						
							|  |  |  | 			up. The application will not be forcibly terminated when the channel is hung up. | 
					
						
							| 
									
										
										
										
											2011-02-02 19:30:49 +00:00
										 |  |  | 			For more information see <filename>doc/AST.pdf</filename>.</para> | 
					
						
							| 
									
										
										
										
											2009-06-07 17:29:44 +00:00
										 |  |  | 		</description> | 
					
						
							|  |  |  | 	</application> | 
					
						
							|  |  |  |  ***/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const char app[] = "ExternalIVR"; | 
					
						
							| 
									
										
										
										
											2005-08-10 23:24:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-11-06 14:30:53 +00:00
										 |  |  | /* XXX the parser in gcc 2.95 gets confused if you don't put a space between 'name' and the comma */ | 
					
						
							| 
									
										
										
										
											2012-01-09 22:15:50 +00:00
										 |  |  | #define ast_chan_log(level, channel, format, ...) ast_log(level, "%s: " format, ast_channel_name(channel) , ## __VA_ARGS__)
 | 
					
						
							| 
									
										
										
										
											2005-08-24 14:24:55 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-19 14:53:58 +00:00
										 |  |  | /* Commands */ | 
					
						
							|  |  |  | #define EIVR_CMD_APND 'A' /* append to prompt queue */
 | 
					
						
							| 
									
										
										
										
											2010-01-22 16:20:43 +00:00
										 |  |  | #define EIVR_CMD_DTMF 'D' /* send DTMF */
 | 
					
						
							| 
									
										
										
										
											2009-11-19 14:53:58 +00:00
										 |  |  | #define EIVR_CMD_EXIT 'E' /* exit */
 | 
					
						
							| 
									
										
										
										
											2010-01-22 16:20:43 +00:00
										 |  |  | #define EIVR_CMD_GET  'G' /* get channel varable(s) */
 | 
					
						
							| 
									
										
										
										
											2009-11-19 14:53:58 +00:00
										 |  |  | #define EIVR_CMD_HGUP 'H' /* hangup */
 | 
					
						
							| 
									
										
										
										
											2012-05-08 21:46:21 +00:00
										 |  |  | #define EIVR_CMD_IRPT 'I' /* interrupt */
 | 
					
						
							| 
									
										
										
										
											2010-01-22 16:20:43 +00:00
										 |  |  | #define EIVR_CMD_LOG  'L' /* log message */
 | 
					
						
							|  |  |  | #define EIVR_CMD_OPT  'O' /* option */
 | 
					
						
							|  |  |  | #define EIVR_CMD_PARM 'P' /* return supplied params */
 | 
					
						
							|  |  |  | #define EIVR_CMD_SQUE 'S' /* (re)set prompt queue */
 | 
					
						
							|  |  |  | #define EIVR_CMD_ANS  'T' /* answer channel */
 | 
					
						
							|  |  |  | #define EIVR_CMD_SVAR 'V' /* set channel varable(s) */
 | 
					
						
							|  |  |  | #define EIVR_CMD_XIT  'X' /* exit **depricated** */
 | 
					
						
							| 
									
										
										
										
											2009-11-19 14:53:58 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-03 14:47:58 +00:00
										 |  |  | #define EXTERNALIVR_PORT 2949
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-06-15 19:10:10 +00:00
										 |  |  | enum options_flags { | 
					
						
							| 
									
										
										
										
											2008-05-22 05:10:01 +00:00
										 |  |  | 	noanswer = (1 << 0), | 
					
						
							|  |  |  | 	ignore_hangup = (1 << 1), | 
					
						
							|  |  |  | 	run_dead = (1 << 2), | 
					
						
							| 
									
										
										
										
											2009-06-15 19:10:10 +00:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2008-05-22 05:10:01 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | AST_APP_OPTIONS(app_opts, { | 
					
						
							|  |  |  | 	AST_APP_OPTION('n', noanswer), | 
					
						
							|  |  |  | 	AST_APP_OPTION('i', ignore_hangup), | 
					
						
							|  |  |  | 	AST_APP_OPTION('d', run_dead), | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-08-10 23:24:39 +00:00
										 |  |  | struct playlist_entry { | 
					
						
							|  |  |  | 	AST_LIST_ENTRY(playlist_entry) list; | 
					
						
							|  |  |  | 	char filename[1]; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-01-27 00:31:05 +00:00
										 |  |  | struct ivr_localuser { | 
					
						
							| 
									
										
										
										
											2005-08-10 23:24:39 +00:00
										 |  |  | 	struct ast_channel *chan; | 
					
						
							|  |  |  | 	AST_LIST_HEAD(playlist, playlist_entry) playlist; | 
					
						
							| 
									
										
										
										
											2005-08-24 14:24:55 +00:00
										 |  |  | 	AST_LIST_HEAD(finishlist, playlist_entry) finishlist; | 
					
						
							| 
									
										
										
										
											2005-09-07 15:32:01 +00:00
										 |  |  | 	int abort_current_sound; | 
					
						
							| 
									
										
										
										
											2005-08-24 14:24:55 +00:00
										 |  |  | 	int playing_silence; | 
					
						
							|  |  |  | 	int option_autoclear; | 
					
						
							| 
									
										
										
										
											2008-05-22 05:10:01 +00:00
										 |  |  | 	int gen_active; | 
					
						
							| 
									
										
										
										
											2005-08-10 23:24:39 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct gen_state { | 
					
						
							| 
									
										
										
										
											2006-01-27 00:31:05 +00:00
										 |  |  | 	struct ivr_localuser *u; | 
					
						
							| 
									
										
										
										
											2005-08-10 23:24:39 +00:00
										 |  |  | 	struct ast_filestream *stream; | 
					
						
							| 
									
										
										
										
											2005-08-24 14:24:55 +00:00
										 |  |  | 	struct playlist_entry *current; | 
					
						
							| 
									
										
										
										
											2005-08-10 23:24:39 +00:00
										 |  |  | 	int sample_queue; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-22 09:23:22 -05:00
										 |  |  | static int eivr_comm(struct ast_channel *chan, struct ivr_localuser *u, | 
					
						
							| 
									
										
										
										
											2016-06-02 22:10:06 +03:00
										 |  |  | 	struct ast_iostream *eivr_events, | 
					
						
							|  |  |  | 	struct ast_iostream *eivr_commands, | 
					
						
							|  |  |  | 	struct ast_iostream *eivr_errors, | 
					
						
							| 
									
										
										
										
											2008-05-22 05:10:01 +00:00
										 |  |  | 	const struct ast_str *args, const struct ast_flags flags); | 
					
						
							| 
									
										
										
										
											2008-02-13 21:04:31 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-02 22:10:06 +03:00
										 |  |  | static void send_eivr_event(struct ast_iostream *stream, const char event, const char *data, | 
					
						
							| 
									
										
										
										
											2008-02-09 11:27:10 +00:00
										 |  |  | 	const struct ast_channel *chan) | 
					
						
							| 
									
										
										
										
											2005-08-24 23:10:55 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2008-05-22 05:10:01 +00:00
										 |  |  | 	struct ast_str *tmp = ast_str_create(12); | 
					
						
							| 
									
										
										
										
											2005-08-24 23:10:55 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-22 05:10:01 +00:00
										 |  |  | 	ast_str_append(&tmp, 0, "%c,%10d", event, (int)time(NULL)); | 
					
						
							|  |  |  | 	if (data) { | 
					
						
							| 
									
										
										
										
											2008-06-19 15:52:17 +00:00
										 |  |  | 		ast_str_append(&tmp, 0, ",%s", data); | 
					
						
							| 
									
										
										
										
											2005-08-24 23:10:55 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-06-02 22:10:06 +03:00
										 |  |  | 	ast_str_append(&tmp, 0, "\n"); | 
					
						
							|  |  |  | 	ast_iostream_write(stream, ast_str_buffer(tmp), strlen(ast_str_buffer(tmp))); | 
					
						
							|  |  |  | 	ast_str_truncate(tmp, -1); | 
					
						
							| 
									
										
										
										
											2005-08-24 23:10:55 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-02 22:10:06 +03:00
										 |  |  | 	ast_debug(1, "sent '%s'", ast_str_buffer(tmp)); | 
					
						
							| 
									
										
										
										
											2011-03-04 01:52:21 +00:00
										 |  |  | 	ast_free(tmp); | 
					
						
							| 
									
										
										
										
											2005-08-24 23:10:55 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-08-10 23:24:39 +00:00
										 |  |  | static void *gen_alloc(struct ast_channel *chan, void *params) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2006-01-27 00:31:05 +00:00
										 |  |  | 	struct ivr_localuser *u = params; | 
					
						
							| 
									
										
										
										
											2005-08-10 23:24:39 +00:00
										 |  |  | 	struct gen_state *state; | 
					
						
							| 
									
										
										
										
											2008-02-09 11:27:10 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-01-11 22:41:34 +00:00
										 |  |  | 	if (!(state = ast_calloc(1, sizeof(*state)))) | 
					
						
							| 
									
										
										
										
											2005-08-10 23:24:39 +00:00
										 |  |  | 		return NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	state->u = u; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return state; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void gen_closestream(struct gen_state *state) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (!state->stream) | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ast_closestream(state->stream); | 
					
						
							| 
									
										
										
										
											2012-02-20 23:43:27 +00:00
										 |  |  | 	ast_channel_stream_set(state->u->chan, NULL); | 
					
						
							| 
									
										
										
										
											2005-08-10 23:24:39 +00:00
										 |  |  | 	state->stream = NULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void gen_release(struct ast_channel *chan, void *data) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct gen_state *state = data; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	gen_closestream(state); | 
					
						
							| 
									
										
										
										
											2007-06-06 21:20:11 +00:00
										 |  |  | 	ast_free(data); | 
					
						
							| 
									
										
										
										
											2005-08-10 23:24:39 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* caller has the playlist locked */ | 
					
						
							|  |  |  | static int gen_nextfile(struct gen_state *state) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2006-01-27 00:31:05 +00:00
										 |  |  | 	struct ivr_localuser *u = state->u; | 
					
						
							| 
									
										
										
										
											2005-08-10 23:24:39 +00:00
										 |  |  | 	char *file_to_stream; | 
					
						
							| 
									
										
										
										
											2008-02-09 11:27:10 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-09-07 15:32:01 +00:00
										 |  |  | 	u->abort_current_sound = 0; | 
					
						
							| 
									
										
										
										
											2005-08-24 14:24:55 +00:00
										 |  |  | 	u->playing_silence = 0; | 
					
						
							| 
									
										
										
										
											2005-08-10 23:24:39 +00:00
										 |  |  | 	gen_closestream(state); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	while (!state->stream) { | 
					
						
							| 
									
										
										
										
											2010-01-18 17:41:44 +00:00
										 |  |  | 		state->current = AST_LIST_FIRST(&u->playlist); | 
					
						
							| 
									
										
										
										
											2005-08-24 23:10:55 +00:00
										 |  |  | 		if (state->current) { | 
					
						
							|  |  |  | 			file_to_stream = state->current->filename; | 
					
						
							| 
									
										
										
										
											2005-08-10 23:24:39 +00:00
										 |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2006-12-11 22:31:20 +00:00
										 |  |  | 			file_to_stream = "silence/10"; | 
					
						
							| 
									
										
										
										
											2005-08-24 14:24:55 +00:00
										 |  |  | 			u->playing_silence = 1; | 
					
						
							| 
									
										
										
										
											2005-08-10 23:24:39 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-01-24 20:12:09 +00:00
										 |  |  | 		if (!(state->stream = ast_openstream_full(u->chan, file_to_stream, ast_channel_language(u->chan), 1))) { | 
					
						
							| 
									
										
										
										
											2005-08-24 23:10:55 +00:00
										 |  |  | 			ast_chan_log(LOG_WARNING, u->chan, "File '%s' could not be opened: %s\n", file_to_stream, strerror(errno)); | 
					
						
							| 
									
										
										
										
											2010-01-18 17:41:44 +00:00
										 |  |  | 			AST_LIST_LOCK(&u->playlist); | 
					
						
							|  |  |  | 			AST_LIST_REMOVE_HEAD(&u->playlist, list); | 
					
						
							|  |  |  | 			AST_LIST_UNLOCK(&u->playlist); | 
					
						
							| 
									
										
										
										
											2005-08-24 14:24:55 +00:00
										 |  |  | 			if (!u->playing_silence) { | 
					
						
							| 
									
										
										
										
											2005-08-10 23:24:39 +00:00
										 |  |  | 				continue; | 
					
						
							| 
									
										
										
										
											2008-02-09 11:27:10 +00:00
										 |  |  | 			} else { | 
					
						
							| 
									
										
										
										
											2005-08-10 23:24:39 +00:00
										 |  |  | 				break; | 
					
						
							| 
									
										
										
										
											2005-08-24 14:24:55 +00:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2005-08-10 23:24:39 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return (!state->stream); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct ast_frame *gen_readframe(struct gen_state *state) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct ast_frame *f = NULL; | 
					
						
							| 
									
										
										
										
											2006-01-27 00:31:05 +00:00
										 |  |  | 	struct ivr_localuser *u = state->u; | 
					
						
							| 
									
										
										
										
											2008-02-09 11:27:10 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-09-07 15:32:01 +00:00
										 |  |  | 	if (u->abort_current_sound || | 
					
						
							| 
									
										
										
										
											2008-02-09 11:27:10 +00:00
										 |  |  | 		(u->playing_silence && AST_LIST_FIRST(&u->playlist))) { | 
					
						
							| 
									
										
										
										
											2005-08-10 23:24:39 +00:00
										 |  |  | 		gen_closestream(state); | 
					
						
							| 
									
										
										
										
											2005-08-24 14:24:55 +00:00
										 |  |  | 		AST_LIST_LOCK(&u->playlist); | 
					
						
							| 
									
										
										
										
											2005-08-10 23:24:39 +00:00
										 |  |  | 		gen_nextfile(state); | 
					
						
							| 
									
										
										
										
											2005-08-24 14:24:55 +00:00
										 |  |  | 		AST_LIST_UNLOCK(&u->playlist); | 
					
						
							| 
									
										
										
										
											2005-08-10 23:24:39 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!(state->stream && (f = ast_readframe(state->stream)))) { | 
					
						
							| 
									
										
										
										
											2005-08-24 23:10:55 +00:00
										 |  |  | 		if (state->current) { | 
					
						
							| 
									
										
										
										
											2010-01-18 17:41:44 +00:00
										 |  |  | 			/* remove finished file from playlist */ | 
					
						
							| 
									
										
										
										
											2021-09-17 11:57:44 -04:00
										 |  |  | 			AST_LIST_LOCK(&u->playlist); | 
					
						
							|  |  |  | 			AST_LIST_REMOVE_HEAD(&u->playlist, list); | 
					
						
							|  |  |  | 			AST_LIST_UNLOCK(&u->playlist); | 
					
						
							| 
									
										
										
										
											2010-01-18 17:41:44 +00:00
										 |  |  | 			/* add finished file to finishlist */ | 
					
						
							| 
									
										
										
										
											2005-08-24 23:10:55 +00:00
										 |  |  | 			AST_LIST_LOCK(&u->finishlist); | 
					
						
							|  |  |  | 			AST_LIST_INSERT_TAIL(&u->finishlist, state->current, list); | 
					
						
							|  |  |  | 			AST_LIST_UNLOCK(&u->finishlist); | 
					
						
							|  |  |  | 			state->current = NULL; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2005-08-10 23:24:39 +00:00
										 |  |  | 		if (!gen_nextfile(state)) | 
					
						
							|  |  |  | 			f = ast_readframe(state->stream); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return f; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int gen_generate(struct ast_channel *chan, void *data, int len, int samples) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct gen_state *state = data; | 
					
						
							|  |  |  | 	struct ast_frame *f = NULL; | 
					
						
							|  |  |  | 	int res = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	state->sample_queue += samples; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	while (state->sample_queue > 0) { | 
					
						
							|  |  |  | 		if (!(f = gen_readframe(state))) | 
					
						
							|  |  |  | 			return -1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		res = ast_write(chan, f); | 
					
						
							|  |  |  | 		ast_frfree(f); | 
					
						
							|  |  |  | 		if (res < 0) { | 
					
						
							| 
									
										
										
										
											2005-08-24 23:10:55 +00:00
										 |  |  | 			ast_chan_log(LOG_WARNING, chan, "Failed to write frame: %s\n", strerror(errno)); | 
					
						
							| 
									
										
										
										
											2005-08-10 23:24:39 +00:00
										 |  |  | 			return -1; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		state->sample_queue -= f->samples; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return res; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct ast_generator gen = | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2012-04-04 18:08:28 +00:00
										 |  |  | 	.alloc = gen_alloc, | 
					
						
							|  |  |  | 	.release = gen_release, | 
					
						
							|  |  |  | 	.generate = gen_generate, | 
					
						
							| 
									
										
										
										
											2005-08-10 23:24:39 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-13 21:04:31 +00:00
										 |  |  | static void ast_eivr_getvariable(struct ast_channel *chan, char *data, char *outbuf, int outbuflen) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2008-02-14 10:19:09 +00:00
										 |  |  | 	/* original input data: "G,var1,var2," */ | 
					
						
							|  |  |  | 	/* data passed as "data":  "var1,var2" */ | 
					
						
							| 
									
										
										
										
											2008-02-13 21:04:31 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-14 19:47:39 +00:00
										 |  |  | 	char *inbuf, *variable; | 
					
						
							| 
									
										
										
										
											2008-02-13 21:04:31 +00:00
										 |  |  | 	const char *value; | 
					
						
							|  |  |  | 	int j; | 
					
						
							| 
									
										
										
										
											2017-12-22 09:23:22 -05:00
										 |  |  | 	struct ast_str *newstring = ast_str_alloca(outbuflen); | 
					
						
							| 
									
										
										
										
											2008-02-13 21:04:31 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-14 19:47:39 +00:00
										 |  |  | 	outbuf[0] = '\0'; | 
					
						
							| 
									
										
										
										
											2008-02-13 21:04:31 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-14 19:47:39 +00:00
										 |  |  | 	for (j = 1, inbuf = data; ; j++) { | 
					
						
							|  |  |  | 		variable = strsep(&inbuf, ","); | 
					
						
							| 
									
										
										
										
											2008-02-13 21:04:31 +00:00
										 |  |  | 		if (variable == NULL) { | 
					
						
							|  |  |  | 			int outstrlen = strlen(outbuf); | 
					
						
							| 
									
										
										
										
											2008-05-22 05:10:01 +00:00
										 |  |  | 			if (outstrlen && outbuf[outstrlen - 1] == ',') { | 
					
						
							| 
									
										
										
										
											2008-02-13 21:04:31 +00:00
										 |  |  | 				outbuf[outstrlen - 1] = 0; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-12-22 09:23:22 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-04-30 19:21:04 +00:00
										 |  |  | 		ast_channel_lock(chan); | 
					
						
							|  |  |  | 		if (!(value = pbx_builtin_getvar_helper(chan, variable))) { | 
					
						
							| 
									
										
										
										
											2008-02-13 21:04:31 +00:00
										 |  |  | 			value = ""; | 
					
						
							| 
									
										
										
										
											2008-04-30 19:21:04 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-14 19:47:39 +00:00
										 |  |  | 		ast_str_append(&newstring, 0, "%s=%s,", variable, value); | 
					
						
							| 
									
										
										
										
											2008-04-30 19:21:04 +00:00
										 |  |  | 		ast_channel_unlock(chan); | 
					
						
							| 
									
										
										
										
											2008-12-13 08:36:35 +00:00
										 |  |  | 		ast_copy_string(outbuf, ast_str_buffer(newstring), outbuflen); | 
					
						
							| 
									
										
										
										
											2008-02-13 21:04:31 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2008-05-22 05:10:01 +00:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2008-02-13 21:04:31 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | static void ast_eivr_setvariable(struct ast_channel *chan, char *data) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	char *value; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-05-18 18:58:26 +00:00
										 |  |  | 	char *inbuf = ast_strdupa(data), *variable; | 
					
						
							| 
									
										
										
										
											2008-02-13 21:04:31 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-05-18 18:58:26 +00:00
										 |  |  | 	for (variable = strsep(&inbuf, ","); variable; variable = strsep(&inbuf, ",")) { | 
					
						
							| 
									
										
										
										
											2008-05-22 05:10:01 +00:00
										 |  |  | 		ast_debug(1, "Setting up a variable: %s\n", variable); | 
					
						
							| 
									
										
										
										
											2009-05-18 18:58:26 +00:00
										 |  |  | 		/* variable contains "varname=value" */ | 
					
						
							|  |  |  | 		value = strchr(variable, '='); | 
					
						
							|  |  |  | 		if (!value) { | 
					
						
							|  |  |  | 			value = ""; | 
					
						
							| 
									
										
										
										
											2008-05-22 05:10:01 +00:00
										 |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2009-05-18 18:58:26 +00:00
										 |  |  | 			*value++ = '\0'; | 
					
						
							| 
									
										
										
										
											2008-05-22 05:10:01 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2009-05-18 18:58:26 +00:00
										 |  |  | 		pbx_builtin_setvar_helper(chan, variable, value); | 
					
						
							| 
									
										
										
										
											2008-02-13 21:04:31 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2008-05-22 05:10:01 +00:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2008-02-13 21:04:31 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-01-22 16:20:43 +00:00
										 |  |  | static void ast_eivr_senddtmf(struct ast_channel *chan, char *vdata) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	char *data; | 
					
						
							|  |  |  | 	int dinterval = 0, duration = 0; | 
					
						
							|  |  |  | 	AST_DECLARE_APP_ARGS(args, | 
					
						
							|  |  |  | 		AST_APP_ARG(digits); | 
					
						
							|  |  |  | 		AST_APP_ARG(dinterval); | 
					
						
							|  |  |  | 		AST_APP_ARG(duration); | 
					
						
							|  |  |  | 	); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	data = ast_strdupa(vdata); | 
					
						
							|  |  |  | 	AST_STANDARD_APP_ARGS(args, data); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!ast_strlen_zero(args.dinterval)) { | 
					
						
							|  |  |  | 		ast_app_parse_timelen(args.dinterval, &dinterval, TIMELEN_MILLISECONDS); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (!ast_strlen_zero(args.duration)) { | 
					
						
							|  |  |  | 		ast_app_parse_timelen(args.duration, &duration, TIMELEN_MILLISECONDS); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	ast_verb(4, "Sending DTMF: %s %d %d\n", args.digits, dinterval <= 0 ? 250 : dinterval, duration); | 
					
						
							|  |  |  | 	ast_dtmf_stream(chan, NULL, args.digits, dinterval <= 0 ? 250 : dinterval, duration); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-08-10 23:24:39 +00:00
										 |  |  | static struct playlist_entry *make_entry(const char *filename) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct playlist_entry *entry; | 
					
						
							| 
									
										
										
										
											2008-02-09 11:27:10 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-01-27 00:31:05 +00:00
										 |  |  | 	if (!(entry = ast_calloc(1, sizeof(*entry) + strlen(filename) + 10))) /* XXX why 10 ? */ | 
					
						
							| 
									
										
										
										
											2005-08-10 23:24:39 +00:00
										 |  |  | 		return NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	strcpy(entry->filename, filename); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return entry; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-05-21 21:13:09 +00:00
										 |  |  | static int app_exec(struct ast_channel *chan, const char *data) | 
					
						
							| 
									
										
										
										
											2005-08-10 23:24:39 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2009-02-09 17:26:02 +00:00
										 |  |  | 	struct ast_flags flags = { 0, }; | 
					
						
							| 
									
										
										
										
											2008-05-22 05:10:01 +00:00
										 |  |  | 	char *opts[0]; | 
					
						
							| 
									
										
										
										
											2005-08-10 23:24:39 +00:00
										 |  |  | 	struct playlist_entry *entry; | 
					
						
							| 
									
										
										
										
											2009-12-02 22:17:22 +00:00
										 |  |  | 	int child_stdin[2] = { -1, -1 }; | 
					
						
							|  |  |  | 	int child_stdout[2] = { -1, -1 }; | 
					
						
							|  |  |  | 	int child_stderr[2] = { -1, -1 }; | 
					
						
							| 
									
										
										
										
											2016-06-02 22:10:06 +03:00
										 |  |  | 	struct ast_iostream *stream_stdin = NULL, *stream_stdout = NULL, | 
					
						
							|  |  |  | 		*stream_stderr = NULL; | 
					
						
							| 
									
										
										
										
											2005-08-10 23:24:39 +00:00
										 |  |  | 	int res = -1; | 
					
						
							|  |  |  | 	int pid; | 
					
						
							| 
									
										
										
										
											2008-03-13 18:59:04 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-03-13 20:38:56 +00:00
										 |  |  | 	struct ast_tcptls_session_instance *ser = NULL; | 
					
						
							| 
									
										
										
										
											2008-03-13 18:59:04 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-05-11 20:07:44 +00:00
										 |  |  | 	struct ivr_localuser foo = { | 
					
						
							|  |  |  | 		.playlist = AST_LIST_HEAD_INIT_VALUE, | 
					
						
							|  |  |  | 		.finishlist = AST_LIST_HEAD_INIT_VALUE, | 
					
						
							| 
									
										
										
										
											2008-05-22 05:10:01 +00:00
										 |  |  | 		.gen_active = 0, | 
					
						
							| 
									
										
										
										
											2011-01-03 14:09:29 +00:00
										 |  |  | 		.playing_silence = 1, | 
					
						
							| 
									
										
										
										
											2006-05-11 20:07:44 +00:00
										 |  |  | 	}; | 
					
						
							|  |  |  | 	struct ivr_localuser *u = &foo; | 
					
						
							| 
									
										
										
										
											2008-05-22 05:10:01 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	char *buf; | 
					
						
							|  |  |  | 	int j; | 
					
						
							| 
									
										
										
										
											2017-12-22 09:23:22 -05:00
										 |  |  | 	char *s, **app_args, *e; | 
					
						
							| 
									
										
										
										
											2009-11-19 14:53:58 +00:00
										 |  |  | 	struct ast_str *comma_delim_args = ast_str_alloca(100); | 
					
						
							| 
									
										
										
										
											2008-05-22 05:10:01 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	AST_DECLARE_APP_ARGS(eivr_args, | 
					
						
							| 
									
										
										
										
											2009-11-19 14:53:58 +00:00
										 |  |  | 		AST_APP_ARG(application); | 
					
						
							|  |  |  | 		AST_APP_ARG(options); | 
					
						
							| 
									
										
										
										
											2008-05-22 05:10:01 +00:00
										 |  |  | 	); | 
					
						
							|  |  |  | 	AST_DECLARE_APP_ARGS(application_args, | 
					
						
							| 
									
										
										
										
											2007-07-23 19:51:41 +00:00
										 |  |  | 		AST_APP_ARG(cmd)[32]; | 
					
						
							|  |  |  | 	); | 
					
						
							| 
									
										
										
										
											2006-01-27 00:31:05 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-10-19 18:19:02 +00:00
										 |  |  | 	u->abort_current_sound = 0; | 
					
						
							| 
									
										
										
										
											2006-02-16 22:59:38 +00:00
										 |  |  | 	u->chan = chan; | 
					
						
							| 
									
										
										
										
											2008-02-09 11:27:10 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-05 17:08:02 +00:00
										 |  |  | 	if (ast_strlen_zero(data)) { | 
					
						
							| 
									
										
										
										
											2009-11-19 14:53:58 +00:00
										 |  |  | 		ast_log(LOG_ERROR, "ExternalIVR requires a command to execute\n"); | 
					
						
							|  |  |  | 		goto exit; | 
					
						
							| 
									
										
										
										
											2009-11-05 17:08:02 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-22 05:10:01 +00:00
										 |  |  | 	buf = ast_strdupa(data); | 
					
						
							|  |  |  | 	AST_STANDARD_APP_ARGS(eivr_args, buf); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-19 14:53:58 +00:00
										 |  |  | 	ast_verb(4, "ExternalIVR received application and arguments: %s\n", eivr_args.application); | 
					
						
							|  |  |  | 	ast_verb(4, "ExternalIVR received options: %s\n", eivr_args.options); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Parse out any application arguments */ | 
					
						
							|  |  |  | 	if ((s = strchr(eivr_args.application, '('))) { | 
					
						
							| 
									
										
										
										
											2008-05-22 05:10:01 +00:00
										 |  |  | 		s[0] = ','; | 
					
						
							| 
									
										
										
										
											2009-11-19 14:53:58 +00:00
										 |  |  | 		if ((e = strrchr(s, ')'))) { | 
					
						
							| 
									
										
										
										
											2008-05-22 05:10:01 +00:00
										 |  |  | 			*e = '\0'; | 
					
						
							|  |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2009-11-19 14:53:58 +00:00
										 |  |  | 			ast_log(LOG_ERROR, "Parse error, missing closing parenthesis\n"); | 
					
						
							|  |  |  | 			goto exit; | 
					
						
							| 
									
										
										
										
											2008-05-22 05:10:01 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2009-11-19 14:53:58 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2008-05-22 05:10:01 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-19 14:53:58 +00:00
										 |  |  | 	AST_STANDARD_APP_ARGS(application_args, eivr_args.application); | 
					
						
							|  |  |  | 	app_args = application_args.argv; | 
					
						
							| 
									
										
										
										
											2008-05-22 05:10:01 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-19 14:53:58 +00:00
										 |  |  | 	/* Put the application + the arguments in a , delimited list */ | 
					
						
							|  |  |  | 	ast_str_reset(comma_delim_args); | 
					
						
							|  |  |  | 	for (j = 0; application_args.cmd[j] != NULL; j++) { | 
					
						
							|  |  |  | 		ast_str_append(&comma_delim_args, 0, "%s%s", j == 0 ? "" : ",", application_args.cmd[j]); | 
					
						
							| 
									
										
										
										
											2008-05-22 05:10:01 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2009-11-19 14:53:58 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* Get rid of any extraneous arguments */ | 
					
						
							| 
									
										
										
										
											2009-12-07 19:48:14 +00:00
										 |  |  | 	if (eivr_args.options && (s = strchr(eivr_args.options, ','))) { | 
					
						
							| 
									
										
										
										
											2009-11-19 14:53:58 +00:00
										 |  |  | 		*s = '\0'; | 
					
						
							| 
									
										
										
										
											2005-08-10 23:24:39 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-19 14:53:58 +00:00
										 |  |  | 	/* Parse the ExternalIVR() arguments */ | 
					
						
							|  |  |  | 	ast_verb(4, "Parsing options from: [%s]\n", eivr_args.options); | 
					
						
							|  |  |  | 	ast_app_parse_options(app_opts, &flags, opts, eivr_args.options); | 
					
						
							|  |  |  | 	if (ast_test_flag(&flags, noanswer)) { | 
					
						
							|  |  |  | 		ast_verb(4, "noanswer is set\n"); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (ast_test_flag(&flags, ignore_hangup)) { | 
					
						
							|  |  |  | 		ast_verb(4, "ignore_hangup is set\n"); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (ast_test_flag(&flags, run_dead)) { | 
					
						
							|  |  |  | 		ast_verb(4, "run_dead is set\n"); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-12-22 09:23:22 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-22 05:10:01 +00:00
										 |  |  | 	if (!(ast_test_flag(&flags, noanswer))) { | 
					
						
							| 
									
										
										
										
											2009-11-19 14:53:58 +00:00
										 |  |  | 		ast_verb(3, "Answering channel and starting generator\n"); | 
					
						
							| 
									
										
										
										
											2012-02-20 23:43:27 +00:00
										 |  |  | 		if (ast_channel_state(chan) != AST_STATE_UP) { | 
					
						
							| 
									
										
										
										
											2008-05-22 05:10:01 +00:00
										 |  |  | 			if (ast_test_flag(&flags, run_dead)) { | 
					
						
							| 
									
										
										
										
											2009-11-19 14:53:58 +00:00
										 |  |  | 				ast_chan_log(LOG_ERROR, chan, "Running ExternalIVR with 'd'ead flag on non-hungup channel isn't supported\n"); | 
					
						
							| 
									
										
										
										
											2008-05-22 05:10:01 +00:00
										 |  |  | 				goto exit; | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2008-03-13 18:59:04 +00:00
										 |  |  | 			ast_answer(chan); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if (ast_activate_generator(chan, &gen, u) < 0) { | 
					
						
							| 
									
										
										
										
											2009-11-19 14:53:58 +00:00
										 |  |  | 			ast_chan_log(LOG_ERROR, chan, "Failed to activate generator\n"); | 
					
						
							| 
									
										
										
										
											2008-03-13 18:59:04 +00:00
										 |  |  | 			goto exit; | 
					
						
							|  |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2008-05-22 05:10:01 +00:00
										 |  |  | 			u->gen_active = 1; | 
					
						
							| 
									
										
										
										
											2008-03-13 18:59:04 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2008-05-22 05:10:01 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-03 14:47:58 +00:00
										 |  |  | 	if (!strncmp(app_args[0], "ivr://", sizeof("ivr://") - 1)) { | 
					
						
							| 
									
										
										
										
											2008-10-19 19:11:28 +00:00
										 |  |  | 		struct ast_tcptls_session_args ivr_desc = { | 
					
						
							| 
									
										
										
										
											2008-05-22 05:10:01 +00:00
										 |  |  | 			.accept_fd = -1, | 
					
						
							|  |  |  | 			.name = "IVR", | 
					
						
							|  |  |  | 		}; | 
					
						
							| 
									
										
										
										
											2012-05-03 14:47:58 +00:00
										 |  |  | 		struct ast_sockaddr *addrs; | 
					
						
							|  |  |  | 		int num_addrs = 0, i = 0; | 
					
						
							|  |  |  | 		char *host = app_args[0] + sizeof("ivr://") - 1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/* Communicate through socket to server */ | 
					
						
							|  |  |  | 		ast_debug(1, "Parsing hostname/port for socket connect from \"%s\"\n", host); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (!(num_addrs = ast_sockaddr_resolve(&addrs, host, 0, AST_AF_UNSPEC))) { | 
					
						
							|  |  |  | 			ast_chan_log(LOG_ERROR, chan, "Unable to locate host '%s'\n", host); | 
					
						
							|  |  |  | 			goto exit; | 
					
						
							| 
									
										
										
										
											2008-03-13 18:59:04 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2012-05-03 14:47:58 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		for (i = 0; i < num_addrs; i++) { | 
					
						
							|  |  |  | 			if (!ast_sockaddr_port(&addrs[i])) { | 
					
						
							|  |  |  | 				/* Default port if not specified */ | 
					
						
							|  |  |  | 				ast_sockaddr_set_port(&addrs[i], EXTERNALIVR_PORT); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			ast_sockaddr_copy(&ivr_desc.remote_address, &addrs[i]); | 
					
						
							|  |  |  | 			if (!(ser = ast_tcptls_client_create(&ivr_desc)) || !(ser = ast_tcptls_client_start(ser))) { | 
					
						
							|  |  |  | 				continue; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			break; | 
					
						
							| 
									
										
										
										
											2008-05-22 05:10:01 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2008-03-13 18:59:04 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-17 21:52:47 +00:00
										 |  |  | 		ast_free(addrs); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-03 14:47:58 +00:00
										 |  |  | 		if (i == num_addrs) { | 
					
						
							|  |  |  | 			ast_chan_log(LOG_ERROR, chan, "Could not connect to any host.  ExternalIVR failed.\n"); | 
					
						
							| 
									
										
										
										
											2008-03-13 18:59:04 +00:00
										 |  |  | 			goto exit; | 
					
						
							| 
									
										
										
										
											2008-05-22 05:10:01 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2012-05-03 14:47:58 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-02 22:10:06 +03:00
										 |  |  | 		res = eivr_comm(chan, u, ser->stream, ser->stream, NULL, comma_delim_args, flags); | 
					
						
							| 
									
										
										
										
											2008-05-22 05:10:01 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-08-10 23:24:39 +00:00
										 |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2008-03-13 18:59:04 +00:00
										 |  |  | 		if (pipe(child_stdin)) { | 
					
						
							| 
									
										
										
										
											2009-11-19 14:53:58 +00:00
										 |  |  | 			ast_chan_log(LOG_ERROR, chan, "Could not create pipe for child input: %s\n", strerror(errno)); | 
					
						
							| 
									
										
										
										
											2008-03-13 18:59:04 +00:00
										 |  |  | 			goto exit; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if (pipe(child_stdout)) { | 
					
						
							| 
									
										
										
										
											2009-11-19 14:53:58 +00:00
										 |  |  | 			ast_chan_log(LOG_ERROR, chan, "Could not create pipe for child output: %s\n", strerror(errno)); | 
					
						
							| 
									
										
										
										
											2008-03-13 18:59:04 +00:00
										 |  |  | 			goto exit; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if (pipe(child_stderr)) { | 
					
						
							| 
									
										
										
										
											2009-11-19 14:53:58 +00:00
										 |  |  | 			ast_chan_log(LOG_ERROR, chan, "Could not create pipe for child errors: %s\n", strerror(errno)); | 
					
						
							| 
									
										
										
										
											2008-03-13 18:59:04 +00:00
										 |  |  | 			goto exit; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-12-22 09:23:22 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-04-16 22:57:54 +00:00
										 |  |  | 		pid = ast_safe_fork(0); | 
					
						
							| 
									
										
										
										
											2008-03-13 18:59:04 +00:00
										 |  |  | 		if (pid < 0) { | 
					
						
							| 
									
										
										
										
											2009-11-19 14:53:58 +00:00
										 |  |  | 			ast_log(LOG_ERROR, "Failed to fork(): %s\n", strerror(errno)); | 
					
						
							| 
									
										
										
										
											2008-03-13 18:59:04 +00:00
										 |  |  | 			goto exit; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-12-22 09:23:22 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-03-13 18:59:04 +00:00
										 |  |  | 		if (!pid) { | 
					
						
							|  |  |  | 			/* child process */ | 
					
						
							|  |  |  | 			if (ast_opt_high_priority) | 
					
						
							|  |  |  | 				ast_set_priority(0); | 
					
						
							| 
									
										
										
										
											2017-12-22 09:23:22 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-03-13 18:59:04 +00:00
										 |  |  | 			dup2(child_stdin[0], STDIN_FILENO); | 
					
						
							|  |  |  | 			dup2(child_stdout[1], STDOUT_FILENO); | 
					
						
							|  |  |  | 			dup2(child_stderr[1], STDERR_FILENO); | 
					
						
							| 
									
										
										
										
											2008-04-16 22:57:54 +00:00
										 |  |  | 			ast_close_fds_above_n(STDERR_FILENO); | 
					
						
							| 
									
										
										
										
											2008-05-22 05:10:01 +00:00
										 |  |  | 			execv(app_args[0], app_args); | 
					
						
							|  |  |  | 			fprintf(stderr, "Failed to execute '%s': %s\n", app_args[0], strerror(errno)); | 
					
						
							| 
									
										
										
										
											2008-03-13 18:59:04 +00:00
										 |  |  | 			_exit(1); | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			/* parent process */ | 
					
						
							|  |  |  | 			close(child_stdin[0]); | 
					
						
							| 
									
										
										
										
											2009-12-02 22:17:22 +00:00
										 |  |  | 			child_stdin[0] = -1; | 
					
						
							| 
									
										
										
										
											2008-03-13 18:59:04 +00:00
										 |  |  | 			close(child_stdout[1]); | 
					
						
							| 
									
										
										
										
											2009-12-02 22:17:22 +00:00
										 |  |  | 			child_stdout[1] = -1; | 
					
						
							| 
									
										
										
										
											2008-03-13 18:59:04 +00:00
										 |  |  | 			close(child_stderr[1]); | 
					
						
							| 
									
										
										
										
											2009-12-02 22:17:22 +00:00
										 |  |  | 			child_stderr[1] = -1; | 
					
						
							| 
									
										
										
										
											2016-06-02 22:10:06 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			stream_stdin  = ast_iostream_from_fd(&child_stdin[1]); | 
					
						
							|  |  |  | 			stream_stdout = ast_iostream_from_fd(&child_stdout[0]); | 
					
						
							|  |  |  | 			stream_stderr = ast_iostream_from_fd(&child_stderr[0]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			res = eivr_comm(chan, u, stream_stdin, stream_stdout, stream_stderr, comma_delim_args, flags); | 
					
						
							| 
									
										
										
										
											2008-03-13 18:59:04 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2006-12-11 00:52:19 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-17 11:57:44 -04:00
										 |  |  |   exit: | 
					
						
							| 
									
										
										
										
											2009-11-19 14:53:58 +00:00
										 |  |  | 	if (u->gen_active) { | 
					
						
							| 
									
										
										
										
											2008-03-13 18:59:04 +00:00
										 |  |  | 		ast_deactivate_generator(chan); | 
					
						
							| 
									
										
										
										
											2009-11-19 14:53:58 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-06-02 22:10:06 +03:00
										 |  |  | 	if (stream_stdin) { | 
					
						
							|  |  |  | 		ast_iostream_close(stream_stdin); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (stream_stdout) { | 
					
						
							|  |  |  | 		ast_iostream_close(stream_stdout); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (stream_stderr) { | 
					
						
							|  |  |  | 		ast_iostream_close(stream_stderr); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2009-12-02 22:17:22 +00:00
										 |  |  | 	if (child_stdin[0] > -1) { | 
					
						
							| 
									
										
										
										
											2008-03-13 18:59:04 +00:00
										 |  |  | 		close(child_stdin[0]); | 
					
						
							| 
									
										
										
										
											2009-11-19 14:53:58 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2009-12-02 22:17:22 +00:00
										 |  |  | 	if (child_stdin[1] > -1) { | 
					
						
							| 
									
										
										
										
											2008-03-13 18:59:04 +00:00
										 |  |  | 		close(child_stdin[1]); | 
					
						
							| 
									
										
										
										
											2009-11-19 14:53:58 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2009-12-02 22:17:22 +00:00
										 |  |  | 	if (child_stdout[0] > -1) { | 
					
						
							| 
									
										
										
										
											2008-03-13 18:59:04 +00:00
										 |  |  | 		close(child_stdout[0]); | 
					
						
							| 
									
										
										
										
											2009-11-19 14:53:58 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2009-12-02 22:17:22 +00:00
										 |  |  | 	if (child_stdout[1] > -1) { | 
					
						
							| 
									
										
										
										
											2008-03-13 18:59:04 +00:00
										 |  |  | 		close(child_stdout[1]); | 
					
						
							| 
									
										
										
										
											2009-11-19 14:53:58 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2009-12-02 22:17:22 +00:00
										 |  |  | 	if (child_stderr[0] > -1) { | 
					
						
							| 
									
										
										
										
											2008-03-13 18:59:04 +00:00
										 |  |  | 		close(child_stderr[0]); | 
					
						
							| 
									
										
										
										
											2009-11-19 14:53:58 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2009-12-02 22:17:22 +00:00
										 |  |  | 	if (child_stderr[1] > -1) { | 
					
						
							| 
									
										
										
										
											2008-03-13 18:59:04 +00:00
										 |  |  | 		close(child_stderr[1]); | 
					
						
							| 
									
										
										
										
											2009-11-19 14:53:58 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2008-03-13 18:59:04 +00:00
										 |  |  | 	if (ser) { | 
					
						
							| 
									
										
										
										
											2008-06-17 21:46:57 +00:00
										 |  |  | 		ao2_ref(ser, -1); | 
					
						
							| 
									
										
										
										
											2008-03-13 18:59:04 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2009-11-19 14:53:58 +00:00
										 |  |  | 	while ((entry = AST_LIST_REMOVE_HEAD(&u->playlist, list))) { | 
					
						
							| 
									
										
										
										
											2008-03-13 18:59:04 +00:00
										 |  |  | 		ast_free(entry); | 
					
						
							| 
									
										
										
										
											2009-11-19 14:53:58 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2008-03-13 18:59:04 +00:00
										 |  |  | 	return res; | 
					
						
							| 
									
										
										
										
											2005-08-10 23:24:39 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-22 09:23:22 -05:00
										 |  |  | static int eivr_comm(struct ast_channel *chan, struct ivr_localuser *u, | 
					
						
							| 
									
										
										
										
											2021-09-17 11:57:44 -04:00
										 |  |  | 	struct ast_iostream *eivr_events, | 
					
						
							|  |  |  | 	struct ast_iostream *eivr_commands, | 
					
						
							|  |  |  | 	struct ast_iostream *eivr_errors, | 
					
						
							|  |  |  | 	const struct ast_str *args, const struct ast_flags flags) | 
					
						
							| 
									
										
										
										
											2008-02-13 21:04:31 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-02 22:10:06 +03:00
										 |  |  | 	char input[1024]; | 
					
						
							| 
									
										
										
										
											2008-02-13 21:04:31 +00:00
										 |  |  | 	struct playlist_entry *entry; | 
					
						
							|  |  |  | 	struct ast_frame *f; | 
					
						
							|  |  |  | 	int ms; | 
					
						
							| 
									
										
										
										
											2021-09-17 11:57:44 -04:00
										 |  |  | 	int exception; | 
					
						
							|  |  |  | 	int ready_fd; | 
					
						
							| 
									
										
										
										
											2016-06-02 22:10:06 +03:00
										 |  |  | 	int waitfds[2]; | 
					
						
							|  |  |  | 	int r; | 
					
						
							| 
									
										
										
										
											2021-09-17 11:57:44 -04:00
										 |  |  | 	struct ast_channel *rchan; | 
					
						
							|  |  |  | 	int res = -1; | 
					
						
							| 
									
										
										
										
											2008-05-22 05:10:01 +00:00
										 |  |  | 	int hangup_info_sent = 0; | 
					
						
							| 
									
										
										
										
											2008-03-13 18:59:04 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-02 22:10:06 +03:00
										 |  |  | 	waitfds[0] = ast_iostream_get_fd(eivr_commands); | 
					
						
							|  |  |  | 	waitfds[1] = eivr_errors ? ast_iostream_get_fd(eivr_errors) : -1; | 
					
						
							| 
									
										
										
										
											2008-02-13 21:04:31 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-13 16:40:00 +00:00
										 |  |  | 	while (1) { | 
					
						
							|  |  |  | 		if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_ZOMBIE)) { | 
					
						
							|  |  |  | 			ast_chan_log(LOG_ERROR, chan, "Is a zombie\n"); | 
					
						
							| 
									
										
										
										
											2021-09-17 11:57:44 -04:00
										 |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if (!hangup_info_sent && !(ast_test_flag(&flags, run_dead)) && ast_check_hangup(chan)) { | 
					
						
							| 
									
										
										
										
											2008-05-22 05:10:01 +00:00
										 |  |  | 			if (ast_test_flag(&flags, ignore_hangup)) { | 
					
						
							| 
									
										
										
										
											2009-11-19 14:53:58 +00:00
										 |  |  | 				ast_verb(3, "Got check_hangup, but ignore_hangup set so sending 'I' command\n"); | 
					
						
							| 
									
										
										
										
											2008-05-22 05:10:01 +00:00
										 |  |  | 				send_eivr_event(eivr_events, 'I', "HANGUP", chan); | 
					
						
							|  |  |  | 				hangup_info_sent = 1; | 
					
						
							|  |  |  | 			} else { | 
					
						
							| 
									
										
										
										
											2021-09-17 11:57:44 -04:00
										 |  |  | 				ast_verb(3, "Got check_hangup\n"); | 
					
						
							|  |  |  | 				send_eivr_event(eivr_events, 'H', NULL, chan); | 
					
						
							|  |  |  | 				break; | 
					
						
							| 
									
										
										
										
											2008-05-22 05:10:01 +00:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2021-09-17 11:57:44 -04:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-12-22 09:23:22 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-17 11:57:44 -04:00
										 |  |  | 		ready_fd = 0; | 
					
						
							|  |  |  | 		ms = 100; | 
					
						
							|  |  |  | 		errno = 0; | 
					
						
							|  |  |  | 		exception = 0; | 
					
						
							| 
									
										
										
										
											2017-12-22 09:23:22 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-02 22:10:06 +03:00
										 |  |  | 		rchan = ast_waitfor_nandfds(&chan, 1, waitfds, (eivr_errors) ? 2 : 1, &exception, &ready_fd, &ms); | 
					
						
							| 
									
										
										
										
											2017-12-22 09:23:22 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-17 11:57:44 -04:00
										 |  |  | 		if (ast_channel_state(chan) == AST_STATE_UP && !AST_LIST_EMPTY(&u->finishlist)) { | 
					
						
							|  |  |  | 			AST_LIST_LOCK(&u->finishlist); | 
					
						
							|  |  |  | 			while ((entry = AST_LIST_REMOVE_HEAD(&u->finishlist, list))) { | 
					
						
							|  |  |  | 				send_eivr_event(eivr_events, 'F', entry->filename, chan); | 
					
						
							|  |  |  | 				ast_free(entry); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			AST_LIST_UNLOCK(&u->finishlist); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (ast_channel_state(chan) == AST_STATE_UP && !(ast_check_hangup(chan)) && rchan) { | 
					
						
							|  |  |  | 			/* the channel has something */ | 
					
						
							|  |  |  | 			f = ast_read(chan); | 
					
						
							|  |  |  | 			if (!f) { | 
					
						
							|  |  |  | 				ast_verb(3, "Returned no frame\n"); | 
					
						
							|  |  |  | 				send_eivr_event(eivr_events, 'H', NULL, chan); | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if (f->frametype == AST_FRAME_DTMF) { | 
					
						
							|  |  |  | 				send_eivr_event(eivr_events, f->subclass.integer, NULL, chan); | 
					
						
							|  |  |  | 				if (u->option_autoclear) { | 
					
						
							|  |  |  | 					AST_LIST_LOCK(&u->playlist); | 
					
						
							|  |  |  | 					if (!u->abort_current_sound && !u->playing_silence) { | 
					
						
							| 
									
										
										
										
											2010-01-18 17:41:44 +00:00
										 |  |  | 						/* send interrupted file as T data */ | 
					
						
							| 
									
										
										
										
											2021-09-17 11:57:44 -04:00
										 |  |  | 						if ((entry = AST_LIST_REMOVE_HEAD(&u->playlist, list))) { | 
					
						
							|  |  |  | 							send_eivr_event(eivr_events, 'T', entry->filename, chan); | 
					
						
							| 
									
										
										
										
											2012-04-19 16:10:04 +00:00
										 |  |  | 							ast_free(entry); | 
					
						
							|  |  |  | 						} | 
					
						
							| 
									
										
										
										
											2010-01-18 17:41:44 +00:00
										 |  |  | 					} | 
					
						
							| 
									
										
										
										
											2021-09-17 11:57:44 -04:00
										 |  |  | 					while ((entry = AST_LIST_REMOVE_HEAD(&u->playlist, list))) { | 
					
						
							|  |  |  | 						send_eivr_event(eivr_events, 'D', entry->filename, chan); | 
					
						
							|  |  |  | 						ast_free(entry); | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 					if (!u->playing_silence) | 
					
						
							|  |  |  | 						u->abort_current_sound = 1; | 
					
						
							|  |  |  | 					AST_LIST_UNLOCK(&u->playlist); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} else if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass.integer == AST_CONTROL_HANGUP)) { | 
					
						
							|  |  |  | 				ast_verb(3, "Got AST_CONTROL_HANGUP\n"); | 
					
						
							|  |  |  | 				send_eivr_event(eivr_events, 'H', NULL, chan); | 
					
						
							| 
									
										
										
										
											2008-05-22 16:29:54 +00:00
										 |  |  | 				if (f->data.uint32) { | 
					
						
							| 
									
										
										
										
											2012-02-20 23:43:27 +00:00
										 |  |  | 					ast_channel_hangupcause_set(chan, f->data.uint32); | 
					
						
							| 
									
										
										
										
											2008-04-24 22:16:48 +00:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2021-09-17 11:57:44 -04:00
										 |  |  | 				ast_frfree(f); | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			ast_frfree(f); | 
					
						
							|  |  |  | 		} else if (ready_fd == waitfds[0]) { | 
					
						
							|  |  |  | 			if (exception) { | 
					
						
							|  |  |  | 				ast_chan_log(LOG_ERROR, chan, "Child process went away\n"); | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2017-12-22 09:23:22 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-02 22:10:06 +03:00
										 |  |  | 			r = ast_iostream_gets(eivr_commands, input, sizeof(input)); | 
					
						
							|  |  |  | 			if (r <= 0) { | 
					
						
							|  |  |  | 				if (r == 0) { | 
					
						
							|  |  |  | 					ast_chan_log(LOG_ERROR, chan, "Child process went away\n"); | 
					
						
							|  |  |  | 					break; | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2010-01-22 16:20:43 +00:00
										 |  |  | 				continue; | 
					
						
							| 
									
										
										
										
											2009-11-19 14:53:58 +00:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2010-01-22 16:20:43 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			ast_strip(input); | 
					
						
							|  |  |  | 			ast_verb(4, "got command '%s'\n", input); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if (strlen(input) < 3) { | 
					
						
							|  |  |  | 				continue; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-19 14:53:58 +00:00
										 |  |  | 			if (input[0] == EIVR_CMD_PARM) { | 
					
						
							| 
									
										
										
										
											2008-12-13 08:36:35 +00:00
										 |  |  | 				struct ast_str *tmp = (struct ast_str *) args; | 
					
						
							| 
									
										
										
										
											2010-01-22 16:20:43 +00:00
										 |  |  | 				send_eivr_event(eivr_events, 'P', ast_str_buffer(tmp), chan); | 
					
						
							|  |  |  | 			} else if (input[0] == EIVR_CMD_DTMF) { | 
					
						
							|  |  |  | 				ast_verb(4, "Sending DTMF: %s\n", &input[2]); | 
					
						
							|  |  |  | 				ast_eivr_senddtmf(chan, &input[2]); | 
					
						
							| 
									
										
										
										
											2009-11-19 14:53:58 +00:00
										 |  |  | 			} else if (input[0] == EIVR_CMD_ANS) { | 
					
						
							|  |  |  | 				ast_verb(3, "Answering channel if needed and starting generator\n"); | 
					
						
							| 
									
										
										
										
											2012-02-20 23:43:27 +00:00
										 |  |  | 				if (ast_channel_state(chan) != AST_STATE_UP) { | 
					
						
							| 
									
										
										
										
											2008-05-22 05:10:01 +00:00
										 |  |  | 					if (ast_test_flag(&flags, run_dead)) { | 
					
						
							|  |  |  | 						ast_chan_log(LOG_WARNING, chan, "Running ExternalIVR with 'd'ead flag on non-hungup channel isn't supported\n"); | 
					
						
							|  |  |  | 						send_eivr_event(eivr_events, 'Z', "ANSWER_FAILURE", chan); | 
					
						
							|  |  |  | 						continue; | 
					
						
							|  |  |  | 					} | 
					
						
							| 
									
										
										
										
											2009-11-19 14:53:58 +00:00
										 |  |  | 					if (ast_answer(chan)) { | 
					
						
							|  |  |  | 						ast_chan_log(LOG_WARNING, chan, "Failed to answer channel\n"); | 
					
						
							|  |  |  | 						send_eivr_event(eivr_events, 'Z', "ANSWER_FAILURE", chan); | 
					
						
							|  |  |  | 						continue; | 
					
						
							|  |  |  | 					} | 
					
						
							| 
									
										
										
										
											2008-05-22 05:10:01 +00:00
										 |  |  | 				} | 
					
						
							|  |  |  | 				if (!(u->gen_active)) { | 
					
						
							|  |  |  | 					if (ast_activate_generator(chan, &gen, u) < 0) { | 
					
						
							|  |  |  | 						ast_chan_log(LOG_WARNING, chan, "Failed to activate generator\n"); | 
					
						
							|  |  |  | 						send_eivr_event(eivr_events, 'Z', "GENERATOR_FAILURE", chan); | 
					
						
							|  |  |  | 					} else { | 
					
						
							|  |  |  | 						u->gen_active = 1; | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2012-05-08 21:46:21 +00:00
										 |  |  | 			} else if (input[0] == EIVR_CMD_IRPT) { | 
					
						
							|  |  |  | 				if (ast_channel_state(chan) != AST_STATE_UP || ast_check_hangup(chan)) { | 
					
						
							|  |  |  | 					ast_chan_log(LOG_WARNING, chan, "Queue 'I'nterrupt called on unanswered channel\n"); | 
					
						
							|  |  |  | 					send_eivr_event(eivr_events, 'Z', NULL, chan); | 
					
						
							|  |  |  | 					continue; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				AST_LIST_LOCK(&u->playlist); | 
					
						
							|  |  |  | 				if (!u->abort_current_sound && !u->playing_silence) { | 
					
						
							|  |  |  | 					/* send interrupted file as T data */ | 
					
						
							|  |  |  | 					if ((entry = AST_LIST_REMOVE_HEAD(&u->playlist, list))) { | 
					
						
							|  |  |  | 						send_eivr_event(eivr_events, 'T', entry->filename, chan); | 
					
						
							|  |  |  | 						ast_free(entry); | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				while ((entry = AST_LIST_REMOVE_HEAD(&u->playlist, list))) { | 
					
						
							|  |  |  | 					send_eivr_event(eivr_events, 'D', entry->filename, chan); | 
					
						
							|  |  |  | 					ast_free(entry); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				if (!u->playing_silence) { | 
					
						
							|  |  |  | 					u->abort_current_sound = 1; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				AST_LIST_UNLOCK(&u->playlist); | 
					
						
							| 
									
										
										
										
											2021-09-17 11:57:44 -04:00
										 |  |  | 			} else if (input[0] == EIVR_CMD_SQUE) { | 
					
						
							| 
									
										
										
										
											2012-02-20 23:43:27 +00:00
										 |  |  | 				if (ast_channel_state(chan) != AST_STATE_UP || ast_check_hangup(chan)) { | 
					
						
							| 
									
										
										
										
											2009-11-20 17:28:01 +00:00
										 |  |  | 					ast_chan_log(LOG_WARNING, chan, "Queue re'S'et called on unanswered channel\n"); | 
					
						
							| 
									
										
										
										
											2008-05-22 05:10:01 +00:00
										 |  |  | 					send_eivr_event(eivr_events, 'Z', NULL, chan); | 
					
						
							|  |  |  | 					continue; | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2021-09-17 11:57:44 -04:00
										 |  |  | 				if (!ast_fileexists(&input[2], NULL, ast_channel_language(u->chan))) { | 
					
						
							|  |  |  | 					ast_chan_log(LOG_WARNING, chan, "Unknown file requested '%s'\n", &input[2]); | 
					
						
							|  |  |  | 					send_eivr_event(eivr_events, 'Z', &input[2], chan); | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					AST_LIST_LOCK(&u->playlist); | 
					
						
							|  |  |  | 					if (!u->abort_current_sound && !u->playing_silence) { | 
					
						
							| 
									
										
										
										
											2010-01-18 17:41:44 +00:00
										 |  |  | 						/* send interrupted file as T data */ | 
					
						
							| 
									
										
										
										
											2021-09-17 11:57:44 -04:00
										 |  |  | 						if ((entry = AST_LIST_REMOVE_HEAD(&u->playlist, list))) { | 
					
						
							|  |  |  | 							send_eivr_event(eivr_events, 'T', entry->filename, chan); | 
					
						
							| 
									
										
										
										
											2012-04-19 16:10:04 +00:00
										 |  |  | 							ast_free(entry); | 
					
						
							|  |  |  | 						} | 
					
						
							| 
									
										
										
										
											2010-01-18 17:41:44 +00:00
										 |  |  | 					} | 
					
						
							| 
									
										
										
										
											2021-09-17 11:57:44 -04:00
										 |  |  | 					while ((entry = AST_LIST_REMOVE_HEAD(&u->playlist, list))) { | 
					
						
							|  |  |  | 						send_eivr_event(eivr_events, 'D', entry->filename, chan); | 
					
						
							|  |  |  | 						ast_free(entry); | 
					
						
							| 
									
										
										
										
											2009-11-20 17:28:01 +00:00
										 |  |  | 					} | 
					
						
							| 
									
										
										
										
											2021-09-17 11:57:44 -04:00
										 |  |  | 					if (!u->playing_silence) { | 
					
						
							|  |  |  | 						u->abort_current_sound = 1; | 
					
						
							| 
									
										
										
										
											2010-01-18 17:41:44 +00:00
										 |  |  | 					} | 
					
						
							| 
									
										
										
										
											2021-09-17 11:57:44 -04:00
										 |  |  | 					entry = make_entry(&input[2]); | 
					
						
							|  |  |  | 					if (entry) { | 
					
						
							|  |  |  | 						AST_LIST_INSERT_TAIL(&u->playlist, entry, list); | 
					
						
							| 
									
										
										
										
											2010-01-18 17:41:44 +00:00
										 |  |  | 					} | 
					
						
							| 
									
										
										
										
											2021-09-17 11:57:44 -04:00
										 |  |  | 					AST_LIST_UNLOCK(&u->playlist); | 
					
						
							| 
									
										
										
										
											2010-01-18 17:41:44 +00:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2021-09-17 11:57:44 -04:00
										 |  |  | 			} else if (input[0] == EIVR_CMD_APND) { | 
					
						
							| 
									
										
										
										
											2012-02-20 23:43:27 +00:00
										 |  |  | 				if (ast_channel_state(chan) != AST_STATE_UP || ast_check_hangup(chan)) { | 
					
						
							| 
									
										
										
										
											2008-05-22 05:10:01 +00:00
										 |  |  | 					ast_chan_log(LOG_WARNING, chan, "Queue 'A'ppend called on unanswered channel\n"); | 
					
						
							|  |  |  | 					send_eivr_event(eivr_events, 'Z', NULL, chan); | 
					
						
							|  |  |  | 					continue; | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2021-09-17 11:57:44 -04:00
										 |  |  | 				if (!ast_fileexists(&input[2], NULL, ast_channel_language(u->chan))) { | 
					
						
							|  |  |  | 					ast_chan_log(LOG_WARNING, chan, "Unknown file requested '%s'\n", &input[2]); | 
					
						
							|  |  |  | 					send_eivr_event(eivr_events, 'Z', &input[2], chan); | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					entry = make_entry(&input[2]); | 
					
						
							|  |  |  | 					if (entry) { | 
					
						
							|  |  |  | 						AST_LIST_LOCK(&u->playlist); | 
					
						
							|  |  |  | 						AST_LIST_INSERT_TAIL(&u->playlist, entry, list); | 
					
						
							|  |  |  | 						AST_LIST_UNLOCK(&u->playlist); | 
					
						
							| 
									
										
										
										
											2009-11-20 17:28:01 +00:00
										 |  |  | 					} | 
					
						
							| 
									
										
										
										
											2021-09-17 11:57:44 -04:00
										 |  |  | 				} | 
					
						
							|  |  |  | 			} else if (input[0] == EIVR_CMD_GET) { | 
					
						
							|  |  |  | 				char response[2048]; | 
					
						
							| 
									
										
										
										
											2009-11-19 14:53:58 +00:00
										 |  |  | 				ast_verb(4, "Retriving Variables from channel: %s\n", &input[2]); | 
					
						
							| 
									
										
										
										
											2021-09-17 11:57:44 -04:00
										 |  |  | 				ast_eivr_getvariable(chan, &input[2], response, sizeof(response)); | 
					
						
							|  |  |  | 				send_eivr_event(eivr_events, 'G', response, chan); | 
					
						
							|  |  |  | 			} else if (input[0] == EIVR_CMD_SVAR) { | 
					
						
							| 
									
										
										
										
											2009-11-19 14:53:58 +00:00
										 |  |  | 				ast_verb(4, "Setting Variables in channel: %s\n", &input[2]); | 
					
						
							| 
									
										
										
										
											2021-09-17 11:57:44 -04:00
										 |  |  | 				ast_eivr_setvariable(chan, &input[2]); | 
					
						
							|  |  |  | 			} else if (input[0] == EIVR_CMD_LOG) { | 
					
						
							|  |  |  | 				ast_chan_log(LOG_NOTICE, chan, "Log message from EIVR: %s\n", &input[2]); | 
					
						
							|  |  |  | 			} else if (input[0] == EIVR_CMD_XIT) { | 
					
						
							|  |  |  | 				ast_chan_log(LOG_NOTICE, chan, "Exiting: %s\n", &input[2]); | 
					
						
							| 
									
										
										
										
											2009-11-19 14:53:58 +00:00
										 |  |  | 				ast_chan_log(LOG_WARNING, chan, "e'X'it command is depricated, use 'E'xit instead\n"); | 
					
						
							| 
									
										
										
										
											2021-09-17 11:57:44 -04:00
										 |  |  | 				res = 0; | 
					
						
							|  |  |  | 				break; | 
					
						
							| 
									
										
										
										
											2009-11-19 14:53:58 +00:00
										 |  |  | 			} else if (input[0] == EIVR_CMD_EXIT) { | 
					
						
							| 
									
										
										
										
											2021-09-17 11:57:44 -04:00
										 |  |  | 				ast_chan_log(LOG_NOTICE, chan, "Exiting: %s\n", &input[2]); | 
					
						
							|  |  |  | 				send_eivr_event(eivr_events, 'E', NULL, chan); | 
					
						
							|  |  |  | 				res = 0; | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 			} else if (input[0] == EIVR_CMD_HGUP) { | 
					
						
							|  |  |  | 				ast_chan_log(LOG_NOTICE, chan, "Hanging up: %s\n", &input[2]); | 
					
						
							|  |  |  | 				send_eivr_event(eivr_events, 'H', NULL, chan); | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 			} else if (input[0] == EIVR_CMD_OPT) { | 
					
						
							| 
									
										
										
										
											2012-02-20 23:43:27 +00:00
										 |  |  | 				if (ast_channel_state(chan) != AST_STATE_UP || ast_check_hangup(chan)) { | 
					
						
							| 
									
										
										
										
											2008-05-22 05:10:01 +00:00
										 |  |  | 					ast_chan_log(LOG_WARNING, chan, "Option called on unanswered channel\n"); | 
					
						
							|  |  |  | 					send_eivr_event(eivr_events, 'Z', NULL, chan); | 
					
						
							|  |  |  | 					continue; | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2021-09-17 11:57:44 -04:00
										 |  |  | 				if (!strcasecmp(&input[2], "autoclear")) | 
					
						
							|  |  |  | 					u->option_autoclear = 1; | 
					
						
							|  |  |  | 				else if (!strcasecmp(&input[2], "noautoclear")) | 
					
						
							|  |  |  | 					u->option_autoclear = 0; | 
					
						
							|  |  |  | 				else | 
					
						
							|  |  |  | 					ast_chan_log(LOG_WARNING, chan, "Unknown option requested: %s\n", &input[2]); | 
					
						
							| 
									
										
										
										
											2016-06-02 22:10:06 +03:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2021-09-17 11:57:44 -04:00
										 |  |  | 		} else if (ready_fd == waitfds[1]) { | 
					
						
							|  |  |  | 			if (exception) { | 
					
						
							|  |  |  | 				ast_chan_log(LOG_ERROR, chan, "Child process went away\n"); | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			r = ast_iostream_gets(eivr_errors, input, sizeof(input)); | 
					
						
							|  |  |  | 			if (r > 0) { | 
					
						
							|  |  |  | 				ast_chan_log(LOG_NOTICE, chan, "stderr: %s\n", ast_strip(input)); | 
					
						
							|  |  |  | 			} else if (r == 0) { | 
					
						
							|  |  |  | 				ast_chan_log(LOG_ERROR, chan, "Child process went away\n"); | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} else if ((ready_fd < 0) && ms) { | 
					
						
							|  |  |  | 			if (errno == 0 || errno == EINTR) | 
					
						
							|  |  |  | 				continue; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			ast_chan_log(LOG_ERROR, chan, "Wait failed (%s)\n", strerror(errno)); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-12-22 09:23:22 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-02 22:10:06 +03:00
										 |  |  | 	return res; | 
					
						
							| 
									
										
										
										
											2008-03-13 18:59:04 +00:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2008-02-13 21:04:31 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | static int unload_module(void) | 
					
						
							| 
									
										
										
										
											2005-08-10 23:24:39 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2007-07-16 13:35:20 +00:00
										 |  |  | 	return ast_unregister_application(app); | 
					
						
							| 
									
										
										
										
											2005-08-10 23:24:39 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | static int load_module(void) | 
					
						
							| 
									
										
										
										
											2005-08-10 23:24:39 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2009-06-07 17:29:44 +00:00
										 |  |  | 	return ast_register_application_xml(app, app_exec); | 
					
						
							| 
									
										
										
										
											2005-08-10 23:24:39 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-25 16:47:17 +00:00
										 |  |  | AST_MODULE_INFO_STANDARD_EXTENDED(ASTERISK_GPL_KEY, "External IVR Interface Application"); |