| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2012-10-14 21:45:16 +00:00
										 |  |  |  * Asterisk -- An open source telephony toolkit. | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  |  * | 
					
						
							|  |  |  |  * A full-featured Find-Me/Follow-Me Application | 
					
						
							| 
									
										
										
										
											2017-12-22 09:23:22 -05:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  |  * Copyright (C) 2005-2006, BJ Weschke All Rights Reserved. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * BJ Weschke <bweschke@btwtech.com> | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This code is released by the author with no restrictions on usage. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * 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. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*! \file
 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \brief Find-Me Follow-Me application | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \author BJ Weschke <bweschke@btwtech.com> | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \ingroup applications | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-14 21:45:16 +00:00
										 |  |  | /*! \li \ref app_followme.c uses the configuration file \ref followme.conf
 | 
					
						
							| 
									
										
										
										
											2012-10-01 23:22:50 +00:00
										 |  |  |  * \addtogroup configuration_file Configuration Files | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-22 09:23:22 -05:00
										 |  |  | /*!
 | 
					
						
							| 
									
										
										
										
											2012-10-01 23:22:50 +00:00
										 |  |  |  * \page followme.conf followme.conf | 
					
						
							|  |  |  |  * \verbinclude followme.conf.sample | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-01-22 17:46:43 +00:00
										 |  |  | /*** MODULEINFO
 | 
					
						
							| 
									
										
										
										
											2011-07-14 20:28:54 +00:00
										 |  |  | 	<support_level>core</support_level> | 
					
						
							| 
									
										
										
										
											2008-01-22 17:46:43 +00:00
										 |  |  |  ***/ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-06-07 18:54:56 +00:00
										 |  |  | #include "asterisk.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | #include <signal.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-20 23:16:15 +00:00
										 |  |  | #include "asterisk/paths.h"	/* use ast_config_AST_SPOOL_DIR */
 | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | #include "asterisk/lock.h"
 | 
					
						
							|  |  |  | #include "asterisk/file.h"
 | 
					
						
							|  |  |  | #include "asterisk/channel.h"
 | 
					
						
							|  |  |  | #include "asterisk/pbx.h"
 | 
					
						
							|  |  |  | #include "asterisk/module.h"
 | 
					
						
							|  |  |  | #include "asterisk/translate.h"
 | 
					
						
							|  |  |  | #include "asterisk/say.h"
 | 
					
						
							|  |  |  | #include "asterisk/features.h"
 | 
					
						
							|  |  |  | #include "asterisk/musiconhold.h"
 | 
					
						
							|  |  |  | #include "asterisk/cli.h"
 | 
					
						
							|  |  |  | #include "asterisk/manager.h"
 | 
					
						
							|  |  |  | #include "asterisk/config.h"
 | 
					
						
							|  |  |  | #include "asterisk/utils.h"
 | 
					
						
							|  |  |  | #include "asterisk/causes.h"
 | 
					
						
							|  |  |  | #include "asterisk/astdb.h"
 | 
					
						
							| 
									
										
										
										
											2008-03-05 16:23:44 +00:00
										 |  |  | #include "asterisk/dsp.h"
 | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | #include "asterisk/app.h"
 | 
					
						
							| 
									
										
										
										
											2013-05-22 18:11:57 +00:00
										 |  |  | #include "asterisk/stasis_channels.h"
 | 
					
						
							| 
									
										
										
										
											2015-04-15 10:38:02 -05:00
										 |  |  | #include "asterisk/max_forwards.h"
 | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-10 16:17:29 +03:00
										 |  |  | #define REC_FORMAT "sln"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-11-05 02:08:39 +00:00
										 |  |  | /*** DOCUMENTATION
 | 
					
						
							|  |  |  | 	<application name="FollowMe" language="en_US"> | 
					
						
							|  |  |  | 		<synopsis> | 
					
						
							|  |  |  | 			Find-Me/Follow-Me application. | 
					
						
							|  |  |  | 		</synopsis> | 
					
						
							|  |  |  | 		<syntax> | 
					
						
							|  |  |  | 			<parameter name="followmeid" required="true" /> | 
					
						
							|  |  |  | 			<parameter name="options"> | 
					
						
							|  |  |  | 				<optionlist> | 
					
						
							|  |  |  | 					<option name="a"> | 
					
						
							|  |  |  | 						<para>Record the caller's name so it can be announced to the | 
					
						
							|  |  |  | 						callee on each step.</para> | 
					
						
							|  |  |  | 					</option> | 
					
						
							| 
									
										
										
										
											2012-05-15 16:53:09 +00:00
										 |  |  | 					<option name="B" argsep="^"> | 
					
						
							|  |  |  | 						<para>Before initiating the outgoing call(s), Gosub to the specified | 
					
						
							|  |  |  | 						location using the current channel.</para> | 
					
						
							|  |  |  | 						<argument name="context" required="false" /> | 
					
						
							|  |  |  | 						<argument name="exten" required="false" /> | 
					
						
							|  |  |  | 						<argument name="priority" required="true" hasparams="optional" argsep="^"> | 
					
						
							|  |  |  | 							<argument name="arg1" multiple="true" required="true" /> | 
					
						
							|  |  |  | 							<argument name="argN" /> | 
					
						
							|  |  |  | 						</argument> | 
					
						
							|  |  |  | 					</option> | 
					
						
							|  |  |  | 					<option name="b" argsep="^"> | 
					
						
							|  |  |  | 						<para>Before initiating an outgoing call, Gosub to the specified | 
					
						
							|  |  |  | 						location using the newly created channel.  The Gosub will be | 
					
						
							|  |  |  | 						executed for each destination channel.</para> | 
					
						
							|  |  |  | 						<argument name="context" required="false" /> | 
					
						
							|  |  |  | 						<argument name="exten" required="false" /> | 
					
						
							|  |  |  | 						<argument name="priority" required="true" hasparams="optional" argsep="^"> | 
					
						
							|  |  |  | 							<argument name="arg1" multiple="true" required="true" /> | 
					
						
							|  |  |  | 							<argument name="argN" /> | 
					
						
							|  |  |  | 						</argument> | 
					
						
							|  |  |  | 					</option> | 
					
						
							| 
									
										
										
										
											2009-11-23 22:37:39 +00:00
										 |  |  | 					<option name="d"> | 
					
						
							|  |  |  | 						<para>Disable the 'Please hold while we try to connect your call' announcement.</para> | 
					
						
							|  |  |  | 					</option> | 
					
						
							| 
									
										
										
										
											2012-01-11 21:56:12 +00:00
										 |  |  | 					<option name="I"> | 
					
						
							|  |  |  | 						<para>Asterisk will ignore any connected line update requests | 
					
						
							|  |  |  | 						it may receive on this dial attempt.</para> | 
					
						
							|  |  |  | 					</option> | 
					
						
							| 
									
										
										
										
											2011-03-18 19:05:20 +00:00
										 |  |  | 					<option name="l"> | 
					
						
							|  |  |  | 						<para>Disable local call optimization so that applications with | 
					
						
							|  |  |  | 						audio hooks between the local bridge don't get dropped when the | 
					
						
							|  |  |  | 						calls get joined directly.</para> | 
					
						
							|  |  |  | 					</option> | 
					
						
							| 
									
										
										
										
											2012-01-11 21:56:12 +00:00
										 |  |  | 					<option name="N"> | 
					
						
							|  |  |  | 						<para>Don't answer the incoming call until we're ready to | 
					
						
							|  |  |  | 						connect the caller or give up.</para> | 
					
						
							|  |  |  | 						<note> | 
					
						
							|  |  |  | 	 						<para>This option is ignored if the call is already answered.</para> | 
					
						
							|  |  |  |  						</note> | 
					
						
							|  |  |  | 						<note> | 
					
						
							|  |  |  | 							<para>If the call is not already answered, the 'a' and 's' | 
					
						
							|  |  |  | 							options are ignored while the 'd' option is implicitly enabled.</para> | 
					
						
							|  |  |  |  						</note> | 
					
						
							|  |  |  | 					</option> | 
					
						
							|  |  |  | 					<option name="n"> | 
					
						
							|  |  |  | 						<para>Playback the unreachable status message if we've run out | 
					
						
							|  |  |  | 						of steps or the callee has elected not to be reachable.</para> | 
					
						
							|  |  |  | 					</option> | 
					
						
							|  |  |  | 					<option name="s"> | 
					
						
							|  |  |  | 						<para>Playback the incoming status message prior to starting | 
					
						
							|  |  |  | 						the follow-me step(s)</para> | 
					
						
							|  |  |  | 					</option> | 
					
						
							| 
									
										
										
										
											2008-11-05 02:08:39 +00:00
										 |  |  | 				</optionlist> | 
					
						
							|  |  |  | 			</parameter> | 
					
						
							|  |  |  | 		</syntax> | 
					
						
							|  |  |  | 		<description> | 
					
						
							|  |  |  | 			<para>This application performs Find-Me/Follow-Me functionality for the caller | 
					
						
							|  |  |  | 			as defined in the profile matching the <replaceable>followmeid</replaceable> parameter in | 
					
						
							|  |  |  | 			<filename>followme.conf</filename>. If the specified <replaceable>followmeid</replaceable> | 
					
						
							|  |  |  | 			profile doesn't exist in <filename>followme.conf</filename>, execution will be returned | 
					
						
							|  |  |  | 			to the dialplan and call execution will continue at the next priority.</para> | 
					
						
							|  |  |  | 			<para>Returns -1 on hangup.</para> | 
					
						
							|  |  |  | 		</description> | 
					
						
							|  |  |  | 	</application> | 
					
						
							|  |  |  |  ***/ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | static char *app = "FollowMe"; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-08 18:16:04 +00:00
										 |  |  | /*! Maximum accept/decline DTMF string plus terminator. */ | 
					
						
							|  |  |  | #define MAX_YN_STRING		20
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-09-05 20:36:27 +00:00
										 |  |  | /*! \brief Number structure */ | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | struct number { | 
					
						
							|  |  |  | 	char number[512];	/*!< Phone Number(s) and/or Extension(s) */ | 
					
						
							|  |  |  | 	long timeout;		/*!< Dial Timeout, if used. */ | 
					
						
							|  |  |  | 	int order;		/*!< The order to dial in */ | 
					
						
							|  |  |  | 	AST_LIST_ENTRY(number) entry; /*!< Next Number record */ | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-09-05 20:36:27 +00:00
										 |  |  | /*! \brief Data structure for followme scripts */ | 
					
						
							|  |  |  | struct call_followme { | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 	ast_mutex_t lock; | 
					
						
							|  |  |  | 	char name[AST_MAX_EXTENSION];	/*!< Name - FollowMeID */ | 
					
						
							| 
									
										
										
										
											2012-04-25 10:49:13 +00:00
										 |  |  | 	char moh[MAX_MUSICCLASS];	/*!< Music On Hold Class to be used */ | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 	char context[AST_MAX_CONTEXT];  /*!< Context to dial from */ | 
					
						
							|  |  |  | 	unsigned int active;		/*!< Profile is active (1), or disabled (0). */ | 
					
						
							| 
									
										
										
										
											2008-08-25 16:02:56 +00:00
										 |  |  | 	int realtime;           /*!< Cached from realtime */ | 
					
						
							| 
									
										
										
										
											2016-05-03 19:11:20 +03:00
										 |  |  | 	/*! Allow callees to accept/reject the forwarded call */ | 
					
						
							|  |  |  | 	unsigned int enable_callee_prompt:1; | 
					
						
							| 
									
										
										
										
											2012-05-08 18:16:04 +00:00
										 |  |  | 	char takecall[MAX_YN_STRING];	/*!< Digit mapping to take a call */ | 
					
						
							|  |  |  | 	char nextindp[MAX_YN_STRING];	/*!< Digit mapping to decline a call */ | 
					
						
							| 
									
										
										
										
											2006-09-05 20:36:27 +00:00
										 |  |  | 	char callfromprompt[PATH_MAX];	/*!< Sound prompt name and path */ | 
					
						
							|  |  |  | 	char norecordingprompt[PATH_MAX];	/*!< Sound prompt name and path */ | 
					
						
							|  |  |  | 	char optionsprompt[PATH_MAX];	/*!< Sound prompt name and path */ | 
					
						
							|  |  |  | 	char plsholdprompt[PATH_MAX];	/*!< Sound prompt name and path */ | 
					
						
							|  |  |  | 	char statusprompt[PATH_MAX];	/*!< Sound prompt name and path */ | 
					
						
							|  |  |  | 	char sorryprompt[PATH_MAX];	/*!< Sound prompt name and path */ | 
					
						
							| 
									
										
										
										
											2017-12-27 18:44:31 -05:00
										 |  |  | 	char connprompt[PATH_MAX];	/*!< Sound prompt name and path */ | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	AST_LIST_HEAD_NOLOCK(numbers, number) numbers;	   /*!< Head of the list of follow-me numbers */ | 
					
						
							|  |  |  | 	AST_LIST_HEAD_NOLOCK(blnumbers, number) blnumbers; /*!< Head of the list of black-listed numbers */ | 
					
						
							|  |  |  | 	AST_LIST_HEAD_NOLOCK(wlnumbers, number) wlnumbers; /*!< Head of the list of white-listed numbers */ | 
					
						
							| 
									
										
										
										
											2006-09-05 20:36:27 +00:00
										 |  |  | 	AST_LIST_ENTRY(call_followme) entry;           /*!< Next Follow-Me record */ | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct fm_args { | 
					
						
							|  |  |  | 	char *mohclass; | 
					
						
							|  |  |  | 	AST_LIST_HEAD_NOLOCK(cnumbers, number) cnumbers; | 
					
						
							| 
									
										
										
										
											2012-05-15 16:53:09 +00:00
										 |  |  | 	/*! Gosub app arguments for outgoing calls.  NULL if not supplied. */ | 
					
						
							|  |  |  | 	const char *predial_callee; | 
					
						
							| 
									
										
										
										
											2012-01-11 21:56:12 +00:00
										 |  |  | 	/*! Accumulated connected line information from inbound call. */ | 
					
						
							|  |  |  | 	struct ast_party_connected_line connected_in; | 
					
						
							|  |  |  | 	/*! Accumulated connected line information from outbound call. */ | 
					
						
							|  |  |  | 	struct ast_party_connected_line connected_out; | 
					
						
							|  |  |  | 	/*! TRUE if connected line information from inbound call changed. */ | 
					
						
							| 
									
										
										
										
											2012-05-08 18:16:04 +00:00
										 |  |  | 	unsigned int pending_in_connected_update:1; | 
					
						
							| 
									
										
										
										
											2012-01-11 21:56:12 +00:00
										 |  |  | 	/*! TRUE if connected line information from outbound call is available. */ | 
					
						
							| 
									
										
										
										
											2012-05-08 18:16:04 +00:00
										 |  |  | 	unsigned int pending_out_connected_update:1; | 
					
						
							| 
									
										
										
										
											2012-05-09 01:59:14 +00:00
										 |  |  | 	/*! TRUE if caller has a pending hold request for the winning call. */ | 
					
						
							|  |  |  | 	unsigned int pending_hold:1; | 
					
						
							| 
									
										
										
										
											2016-05-03 19:11:20 +03:00
										 |  |  | 	/*! TRUE if callees will be prompted to answer */ | 
					
						
							|  |  |  | 	unsigned int enable_callee_prompt:1; | 
					
						
							| 
									
										
										
										
											2012-05-09 01:59:14 +00:00
										 |  |  | 	/*! Music On Hold Class suggested by caller hold for winning call. */ | 
					
						
							|  |  |  | 	char suggested_moh[MAX_MUSICCLASS]; | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 	char context[AST_MAX_CONTEXT]; | 
					
						
							| 
									
										
										
										
											2012-05-08 20:32:11 +00:00
										 |  |  | 	char namerecloc[PATH_MAX]; | 
					
						
							| 
									
										
										
										
											2012-05-08 18:16:04 +00:00
										 |  |  | 	char takecall[MAX_YN_STRING];	/*!< Digit mapping to take a call */ | 
					
						
							|  |  |  | 	char nextindp[MAX_YN_STRING];	/*!< Digit mapping to decline a call */ | 
					
						
							| 
									
										
										
										
											2006-09-05 20:36:27 +00:00
										 |  |  | 	char callfromprompt[PATH_MAX];	/*!< Sound prompt name and path */ | 
					
						
							|  |  |  | 	char norecordingprompt[PATH_MAX];	/*!< Sound prompt name and path */ | 
					
						
							|  |  |  | 	char optionsprompt[PATH_MAX];	/*!< Sound prompt name and path */ | 
					
						
							|  |  |  | 	char plsholdprompt[PATH_MAX];	/*!< Sound prompt name and path */ | 
					
						
							|  |  |  | 	char statusprompt[PATH_MAX];	/*!< Sound prompt name and path */ | 
					
						
							|  |  |  | 	char sorryprompt[PATH_MAX];	/*!< Sound prompt name and path */ | 
					
						
							| 
									
										
										
										
											2017-12-27 18:44:31 -05:00
										 |  |  | 	char connprompt[PATH_MAX];	/*!< Sound prompt name and path */ | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 	struct ast_flags followmeflags; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct findme_user { | 
					
						
							|  |  |  | 	struct ast_channel *ochan; | 
					
						
							| 
									
										
										
										
											2012-01-11 21:56:12 +00:00
										 |  |  | 	/*! Accumulated connected line information from outgoing call. */ | 
					
						
							|  |  |  | 	struct ast_party_connected_line connected; | 
					
						
							|  |  |  | 	long digts; | 
					
						
							|  |  |  | 	int ynidx; | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 	int state; | 
					
						
							| 
									
										
										
										
											2019-05-10 09:48:28 -06:00
										 |  |  | 	char dialarg[768]; | 
					
						
							| 
									
										
										
										
											2012-05-08 18:16:04 +00:00
										 |  |  | 	/*! Collected digits to accept/decline the call. */ | 
					
						
							|  |  |  | 	char yn[MAX_YN_STRING]; | 
					
						
							| 
									
										
										
										
											2012-05-09 02:35:29 +00:00
										 |  |  | 	/*! TRUE if the outgoing call is answered. */ | 
					
						
							|  |  |  | 	unsigned int answered:1; | 
					
						
							| 
									
										
										
										
											2012-01-11 21:56:12 +00:00
										 |  |  | 	/*! TRUE if connected line information is available. */ | 
					
						
							| 
									
										
										
										
											2012-05-08 18:16:04 +00:00
										 |  |  | 	unsigned int pending_connected_update:1; | 
					
						
							| 
									
										
										
										
											2008-03-05 16:23:44 +00:00
										 |  |  | 	AST_LIST_ENTRY(findme_user) entry; | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | enum { | 
					
						
							|  |  |  | 	FOLLOWMEFLAG_STATUSMSG = (1 << 0), | 
					
						
							|  |  |  | 	FOLLOWMEFLAG_RECORDNAME = (1 << 1), | 
					
						
							| 
									
										
										
										
											2009-11-23 22:37:39 +00:00
										 |  |  | 	FOLLOWMEFLAG_UNREACHABLEMSG = (1 << 2), | 
					
						
							| 
									
										
										
										
											2011-01-26 23:41:55 +00:00
										 |  |  | 	FOLLOWMEFLAG_DISABLEHOLDPROMPT = (1 << 3), | 
					
						
							| 
									
										
										
										
											2011-03-18 19:05:20 +00:00
										 |  |  | 	FOLLOWMEFLAG_NOANSWER = (1 << 4), | 
					
						
							|  |  |  | 	FOLLOWMEFLAG_DISABLEOPTIMIZATION = (1 << 5), | 
					
						
							| 
									
										
										
										
											2012-01-11 21:56:12 +00:00
										 |  |  | 	FOLLOWMEFLAG_IGNORE_CONNECTEDLINE = (1 << 6), | 
					
						
							| 
									
										
										
										
											2012-05-15 16:53:09 +00:00
										 |  |  | 	FOLLOWMEFLAG_PREDIAL_CALLER = (1 << 7), | 
					
						
							|  |  |  | 	FOLLOWMEFLAG_PREDIAL_CALLEE = (1 << 8), | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | enum { | 
					
						
							|  |  |  | 	FOLLOWMEFLAG_ARG_PREDIAL_CALLER, | 
					
						
							|  |  |  | 	FOLLOWMEFLAG_ARG_PREDIAL_CALLEE, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* note: this entry _MUST_ be the last one in the enum */ | 
					
						
							|  |  |  | 	FOLLOWMEFLAG_ARG_ARRAY_SIZE | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | AST_APP_OPTIONS(followme_opts, { | 
					
						
							| 
									
										
										
										
											2012-01-11 21:56:12 +00:00
										 |  |  | 	AST_APP_OPTION('a', FOLLOWMEFLAG_RECORDNAME), | 
					
						
							| 
									
										
										
										
											2012-05-15 16:53:09 +00:00
										 |  |  | 	AST_APP_OPTION_ARG('B', FOLLOWMEFLAG_PREDIAL_CALLER, FOLLOWMEFLAG_ARG_PREDIAL_CALLER), | 
					
						
							|  |  |  | 	AST_APP_OPTION_ARG('b', FOLLOWMEFLAG_PREDIAL_CALLEE, FOLLOWMEFLAG_ARG_PREDIAL_CALLEE), | 
					
						
							| 
									
										
										
										
											2012-01-11 21:56:12 +00:00
										 |  |  | 	AST_APP_OPTION('d', FOLLOWMEFLAG_DISABLEHOLDPROMPT), | 
					
						
							|  |  |  | 	AST_APP_OPTION('I', FOLLOWMEFLAG_IGNORE_CONNECTEDLINE), | 
					
						
							|  |  |  | 	AST_APP_OPTION('l', FOLLOWMEFLAG_DISABLEOPTIMIZATION), | 
					
						
							|  |  |  | 	AST_APP_OPTION('N', FOLLOWMEFLAG_NOANSWER), | 
					
						
							|  |  |  | 	AST_APP_OPTION('n', FOLLOWMEFLAG_UNREACHABLEMSG), | 
					
						
							|  |  |  | 	AST_APP_OPTION('s', FOLLOWMEFLAG_STATUSMSG), | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-09-20 20:57:57 +00:00
										 |  |  | static const char *featuredigittostr; | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | static int featuredigittimeout = 5000;		/*!< Feature Digit Timeout */ | 
					
						
							|  |  |  | static const char *defaultmoh = "default";    	/*!< Default Music-On-Hold Class */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-08 18:16:04 +00:00
										 |  |  | static char takecall[MAX_YN_STRING] = "1"; | 
					
						
							|  |  |  | static char nextindp[MAX_YN_STRING] = "2"; | 
					
						
							| 
									
										
										
										
											2016-05-03 19:11:20 +03:00
										 |  |  | static int enable_callee_prompt = 1; | 
					
						
							| 
									
										
										
										
											2006-06-09 20:40:10 +00:00
										 |  |  | static char callfromprompt[PATH_MAX] = "followme/call-from"; | 
					
						
							|  |  |  | static char norecordingprompt[PATH_MAX] = "followme/no-recording"; | 
					
						
							| 
									
										
										
										
											2006-08-07 18:47:33 +00:00
										 |  |  | static char optionsprompt[PATH_MAX] = "followme/options"; | 
					
						
							| 
									
										
										
										
											2006-06-09 20:40:10 +00:00
										 |  |  | static char plsholdprompt[PATH_MAX] = "followme/pls-hold-while-try"; | 
					
						
							| 
									
										
										
										
											2006-08-07 18:47:33 +00:00
										 |  |  | static char statusprompt[PATH_MAX] = "followme/status"; | 
					
						
							|  |  |  | static char sorryprompt[PATH_MAX] = "followme/sorry"; | 
					
						
							| 
									
										
										
										
											2017-12-27 18:44:31 -05:00
										 |  |  | static char connprompt[PATH_MAX] = ""; | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-07-30 16:02:01 +00:00
										 |  |  | static AST_RWLIST_HEAD_STATIC(followmes, call_followme); | 
					
						
							| 
									
										
										
										
											2006-06-06 21:03:18 +00:00
										 |  |  | AST_LIST_HEAD_NOLOCK(findme_user_listptr, findme_user); | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-09-05 20:36:27 +00:00
										 |  |  | static void free_numbers(struct call_followme *f) | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	/* Free numbers attached to the profile */ | 
					
						
							|  |  |  | 	struct number *prev; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	while ((prev = AST_LIST_REMOVE_HEAD(&f->numbers, entry))) | 
					
						
							|  |  |  | 		/* Free the number */ | 
					
						
							| 
									
										
										
										
											2007-06-06 21:20:11 +00:00
										 |  |  | 		ast_free(prev); | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 	AST_LIST_HEAD_INIT_NOLOCK(&f->numbers); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	while ((prev = AST_LIST_REMOVE_HEAD(&f->blnumbers, entry))) | 
					
						
							|  |  |  | 		/* Free the blacklisted number */ | 
					
						
							| 
									
										
										
										
											2007-06-06 21:20:11 +00:00
										 |  |  | 		ast_free(prev); | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 	AST_LIST_HEAD_INIT_NOLOCK(&f->blnumbers); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	while ((prev = AST_LIST_REMOVE_HEAD(&f->wlnumbers, entry))) | 
					
						
							|  |  |  | 		/* Free the whitelisted number */ | 
					
						
							| 
									
										
										
										
											2007-06-06 21:20:11 +00:00
										 |  |  | 		ast_free(prev); | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 	AST_LIST_HEAD_INIT_NOLOCK(&f->wlnumbers); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-09-05 20:36:27 +00:00
										 |  |  | /*! \brief Allocate and initialize followme profile */ | 
					
						
							|  |  |  | static struct call_followme *alloc_profile(const char *fmname) | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2006-09-05 20:36:27 +00:00
										 |  |  | 	struct call_followme *f; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!(f = ast_calloc(1, sizeof(*f)))) | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ast_mutex_init(&f->lock); | 
					
						
							|  |  |  | 	ast_copy_string(f->name, fmname, sizeof(f->name)); | 
					
						
							| 
									
										
										
										
											2016-08-11 20:10:44 +03:00
										 |  |  | 	AST_LIST_HEAD_INIT_NOLOCK(&f->numbers); | 
					
						
							|  |  |  | 	AST_LIST_HEAD_INIT_NOLOCK(&f->blnumbers); | 
					
						
							|  |  |  | 	AST_LIST_HEAD_INIT_NOLOCK(&f->wlnumbers); | 
					
						
							|  |  |  | 	return f; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void init_profile(struct call_followme *f, int activate) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-05-03 19:11:20 +03:00
										 |  |  | 	f->enable_callee_prompt = enable_callee_prompt; | 
					
						
							| 
									
										
										
										
											2016-08-11 20:10:44 +03:00
										 |  |  | 	f->context[0] = '\0'; | 
					
						
							|  |  |  | 	ast_copy_string(f->moh, defaultmoh, sizeof(f->moh)); | 
					
						
							| 
									
										
										
										
											2006-09-05 20:36:27 +00:00
										 |  |  | 	ast_copy_string(f->takecall, takecall, sizeof(f->takecall)); | 
					
						
							|  |  |  | 	ast_copy_string(f->nextindp, nextindp, sizeof(f->nextindp)); | 
					
						
							|  |  |  | 	ast_copy_string(f->callfromprompt, callfromprompt, sizeof(f->callfromprompt)); | 
					
						
							|  |  |  | 	ast_copy_string(f->norecordingprompt, norecordingprompt, sizeof(f->norecordingprompt)); | 
					
						
							|  |  |  | 	ast_copy_string(f->optionsprompt, optionsprompt, sizeof(f->optionsprompt)); | 
					
						
							|  |  |  | 	ast_copy_string(f->plsholdprompt, plsholdprompt, sizeof(f->plsholdprompt)); | 
					
						
							|  |  |  | 	ast_copy_string(f->statusprompt, statusprompt, sizeof(f->statusprompt)); | 
					
						
							|  |  |  | 	ast_copy_string(f->sorryprompt, sorryprompt, sizeof(f->sorryprompt)); | 
					
						
							| 
									
										
										
										
											2017-12-27 18:44:31 -05:00
										 |  |  | 	ast_copy_string(f->connprompt, connprompt, sizeof(f->connprompt)); | 
					
						
							| 
									
										
										
										
											2016-08-11 20:10:44 +03:00
										 |  |  | 	if (activate) { | 
					
						
							|  |  |  | 		f->active = 1; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-22 09:23:22 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-09-05 20:36:27 +00:00
										 |  |  | /*! \brief Set parameter in profile from configuration file */ | 
					
						
							|  |  |  | static void profile_set_param(struct call_followme *f, const char *param, const char *val, int linenum, int failunknown) | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-22 09:23:22 -05:00
										 |  |  | 	if (!strcasecmp(param, "musicclass") || !strcasecmp(param, "musiconhold") || !strcasecmp(param, "music")) | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 		ast_copy_string(f->moh, val, sizeof(f->moh)); | 
					
						
							| 
									
										
										
										
											2017-12-22 09:23:22 -05:00
										 |  |  | 	else if (!strcasecmp(param, "context")) | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 		ast_copy_string(f->context, val, sizeof(f->context)); | 
					
						
							| 
									
										
										
										
											2016-05-03 19:11:20 +03:00
										 |  |  | 	else if (!strcasecmp(param, "enable_callee_prompt")) | 
					
						
							|  |  |  | 		f->enable_callee_prompt = ast_true(val); | 
					
						
							| 
									
										
										
										
											2006-09-05 20:36:27 +00:00
										 |  |  | 	else if (!strcasecmp(param, "takecall")) | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 		ast_copy_string(f->takecall, val, sizeof(f->takecall)); | 
					
						
							| 
									
										
										
										
											2006-09-05 20:36:27 +00:00
										 |  |  | 	else if (!strcasecmp(param, "declinecall")) | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 		ast_copy_string(f->nextindp, val, sizeof(f->nextindp)); | 
					
						
							| 
									
										
										
										
											2008-08-25 16:02:56 +00:00
										 |  |  | 	else if (!strcasecmp(param, "call-from-prompt") || !strcasecmp(param, "call_from_prompt")) | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 		ast_copy_string(f->callfromprompt, val, sizeof(f->callfromprompt)); | 
					
						
							| 
									
										
										
										
											2017-12-22 09:23:22 -05:00
										 |  |  | 	else if (!strcasecmp(param, "followme-norecording-prompt") || !strcasecmp(param, "norecording_prompt")) | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 		ast_copy_string(f->norecordingprompt, val, sizeof(f->norecordingprompt)); | 
					
						
							| 
									
										
										
										
											2017-12-22 09:23:22 -05:00
										 |  |  | 	else if (!strcasecmp(param, "followme-options-prompt") || !strcasecmp(param, "options_prompt")) | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 		ast_copy_string(f->optionsprompt, val, sizeof(f->optionsprompt)); | 
					
						
							| 
									
										
										
										
											2008-11-25 21:49:42 +00:00
										 |  |  | 	else if (!strcasecmp(param, "followme-pls-hold-prompt") || !strcasecmp(param, "pls_hold_prompt")) | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 		ast_copy_string(f->plsholdprompt, val, sizeof(f->plsholdprompt)); | 
					
						
							| 
									
										
										
										
											2017-12-22 09:23:22 -05:00
										 |  |  | 	else if (!strcasecmp(param, "followme-status-prompt") || !strcasecmp(param, "status_prompt")) | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 		ast_copy_string(f->statusprompt, val, sizeof(f->statusprompt)); | 
					
						
							| 
									
										
										
										
											2017-12-22 09:23:22 -05:00
										 |  |  | 	else if (!strcasecmp(param, "followme-sorry-prompt") || !strcasecmp(param, "sorry_prompt")) | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 		ast_copy_string(f->sorryprompt, val, sizeof(f->sorryprompt)); | 
					
						
							| 
									
										
										
										
											2017-12-27 18:44:31 -05:00
										 |  |  | 	else if (!strcasecmp(param, "followme-connecting-prompt") || !strcasecmp(param, "connecting_prompt")) { | 
					
						
							|  |  |  | 		ast_copy_string(f->connprompt, val, sizeof(f->connprompt)); | 
					
						
							|  |  |  | 	} else if (failunknown) { | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 		if (linenum >= 0) | 
					
						
							|  |  |  | 			ast_log(LOG_WARNING, "Unknown keyword in profile '%s': %s at line %d of followme.conf\n", f->name, param, linenum); | 
					
						
							|  |  |  | 		else | 
					
						
							|  |  |  | 			ast_log(LOG_WARNING, "Unknown keyword in profile '%s': %s\n", f->name, param); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-09-05 20:36:27 +00:00
										 |  |  | /*! \brief Add a new number */ | 
					
						
							| 
									
										
										
										
											2009-05-21 21:13:09 +00:00
										 |  |  | static struct number *create_followme_number(const char *number, int timeout, int numorder) | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct number *cur; | 
					
						
							| 
									
										
										
										
											2009-05-21 21:13:09 +00:00
										 |  |  | 	char *buf = ast_strdupa(number); | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 	char *tmp; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-09-05 20:36:27 +00:00
										 |  |  | 	if (!(cur = ast_calloc(1, sizeof(*cur)))) | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-09-05 20:36:27 +00:00
										 |  |  | 	cur->timeout = timeout; | 
					
						
							| 
									
										
										
										
											2009-05-21 21:13:09 +00:00
										 |  |  | 	if ((tmp = strchr(buf, ','))) | 
					
						
							| 
									
										
										
										
											2006-09-05 20:36:27 +00:00
										 |  |  | 		*tmp = '\0'; | 
					
						
							| 
									
										
										
										
											2009-05-21 21:13:09 +00:00
										 |  |  | 	ast_copy_string(cur->number, buf, sizeof(cur->number)); | 
					
						
							| 
									
										
										
										
											2006-09-05 20:36:27 +00:00
										 |  |  | 	cur->order = numorder; | 
					
						
							| 
									
										
										
										
											2007-06-14 19:39:12 +00:00
										 |  |  | 	ast_debug(1, "Created a number, %s, order of , %d, with a timeout of %ld.\n", cur->number, cur->order, cur->timeout); | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return cur; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-09-05 20:36:27 +00:00
										 |  |  | /*! \brief Reload followme application module */ | 
					
						
							| 
									
										
										
										
											2007-08-16 21:09:46 +00:00
										 |  |  | static int reload_followme(int reload) | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2006-09-05 20:36:27 +00:00
										 |  |  | 	struct call_followme *f; | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 	struct ast_config *cfg; | 
					
						
							| 
									
										
										
										
											2006-06-07 20:02:07 +00:00
										 |  |  | 	char *cat = NULL, *tmp; | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 	struct ast_variable *var; | 
					
						
							|  |  |  | 	struct number *cur, *nm; | 
					
						
							|  |  |  | 	int timeout; | 
					
						
							| 
									
										
										
										
											2008-03-05 16:23:44 +00:00
										 |  |  | 	int numorder; | 
					
						
							| 
									
										
										
										
											2016-05-03 19:11:20 +03:00
										 |  |  | 	const char* enable_callee_prompt_str; | 
					
						
							| 
									
										
										
										
											2006-09-20 20:57:57 +00:00
										 |  |  | 	const char *takecallstr; | 
					
						
							|  |  |  | 	const char *declinecallstr; | 
					
						
							|  |  |  | 	const char *tmpstr; | 
					
						
							| 
									
										
										
										
											2007-08-16 21:09:46 +00:00
										 |  |  | 	struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 }; | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-08-16 21:09:46 +00:00
										 |  |  | 	if (!(cfg = ast_config_load("followme.conf", config_flags))) { | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 		ast_log(LOG_WARNING, "No follow me config file (followme.conf), so no follow me\n"); | 
					
						
							|  |  |  | 		return 0; | 
					
						
							| 
									
										
										
										
											2008-09-12 23:30:03 +00:00
										 |  |  | 	} else if (cfg == CONFIG_STATUS_FILEUNCHANGED) { | 
					
						
							| 
									
										
										
										
											2007-08-16 21:09:46 +00:00
										 |  |  | 		return 0; | 
					
						
							| 
									
										
										
										
											2008-09-12 23:30:03 +00:00
										 |  |  | 	} else if (cfg == CONFIG_STATUS_FILEINVALID) { | 
					
						
							|  |  |  | 		ast_log(LOG_ERROR, "Config file followme.conf is in an invalid format.  Aborting.\n"); | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-07-30 16:02:01 +00:00
										 |  |  | 	AST_RWLIST_WRLOCK(&followmes); | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* Reset Global Var Values */ | 
					
						
							|  |  |  | 	featuredigittimeout = 5000; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Mark all profiles as inactive for the moment */ | 
					
						
							| 
									
										
										
										
											2007-07-30 16:02:01 +00:00
										 |  |  | 	AST_RWLIST_TRAVERSE(&followmes, f, entry) { | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 		f->active = 0; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2007-07-30 16:02:01 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 	featuredigittostr = ast_variable_retrieve(cfg, "general", "featuredigittimeout"); | 
					
						
							| 
									
										
										
										
											2008-03-05 16:23:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-06-07 19:42:37 +00:00
										 |  |  | 	if (!ast_strlen_zero(featuredigittostr)) { | 
					
						
							| 
									
										
										
										
											2009-08-10 19:20:57 +00:00
										 |  |  | 		if (!sscanf(featuredigittostr, "%30d", &featuredigittimeout)) | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 			featuredigittimeout = 5000; | 
					
						
							| 
									
										
										
										
											2006-06-07 19:42:37 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-03 19:11:20 +03:00
										 |  |  | 	if ((enable_callee_prompt_str = ast_variable_retrieve(cfg, "general", | 
					
						
							|  |  |  | 					"enable_callee_prompt")) && | 
					
						
							|  |  |  | 			!ast_strlen_zero(enable_callee_prompt_str)) { | 
					
						
							|  |  |  | 		enable_callee_prompt = ast_true(enable_callee_prompt_str); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-08-26 18:05:58 +00:00
										 |  |  | 	if ((takecallstr = ast_variable_retrieve(cfg, "general", "takecall")) && !ast_strlen_zero(takecallstr)) { | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 		ast_copy_string(takecall, takecallstr, sizeof(takecall)); | 
					
						
							| 
									
										
										
										
											2008-08-26 18:05:58 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2008-03-05 16:23:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-08-26 18:05:58 +00:00
										 |  |  | 	if ((declinecallstr = ast_variable_retrieve(cfg, "general", "declinecall")) && !ast_strlen_zero(declinecallstr)) { | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 		ast_copy_string(nextindp, declinecallstr, sizeof(nextindp)); | 
					
						
							| 
									
										
										
										
											2008-08-26 18:05:58 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-08-26 18:05:58 +00:00
										 |  |  | 	if ((tmpstr = ast_variable_retrieve(cfg, "general", "call-from-prompt")) && !ast_strlen_zero(tmpstr)) { | 
					
						
							|  |  |  | 		ast_copy_string(callfromprompt, tmpstr, sizeof(callfromprompt)); | 
					
						
							|  |  |  | 	} else if ((tmpstr = ast_variable_retrieve(cfg, "general", "call_from_prompt")) && !ast_strlen_zero(tmpstr)) { | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 		ast_copy_string(callfromprompt, tmpstr, sizeof(callfromprompt)); | 
					
						
							| 
									
										
										
										
											2008-08-26 18:05:58 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-08-26 18:05:58 +00:00
										 |  |  | 	if ((tmpstr = ast_variable_retrieve(cfg, "general", "norecording-prompt")) && !ast_strlen_zero(tmpstr)) { | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 		ast_copy_string(norecordingprompt, tmpstr, sizeof(norecordingprompt)); | 
					
						
							| 
									
										
										
										
											2008-08-26 18:05:58 +00:00
										 |  |  | 	} else if ((tmpstr = ast_variable_retrieve(cfg, "general", "norecording_prompt")) && !ast_strlen_zero(tmpstr)) { | 
					
						
							| 
									
										
										
										
											2010-03-05 19:10:47 +00:00
										 |  |  | 		ast_copy_string(norecordingprompt, tmpstr, sizeof(norecordingprompt)); | 
					
						
							| 
									
										
										
										
											2008-08-26 18:05:58 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-08-26 18:05:58 +00:00
										 |  |  | 	if ((tmpstr = ast_variable_retrieve(cfg, "general", "options-prompt")) && !ast_strlen_zero(tmpstr)) { | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 		ast_copy_string(optionsprompt, tmpstr, sizeof(optionsprompt)); | 
					
						
							| 
									
										
										
										
											2008-08-26 18:05:58 +00:00
										 |  |  | 	} else if ((tmpstr = ast_variable_retrieve(cfg, "general", "options_prompt")) && !ast_strlen_zero(tmpstr)) { | 
					
						
							|  |  |  | 		ast_copy_string(optionsprompt, tmpstr, sizeof(optionsprompt)); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-08-26 18:05:58 +00:00
										 |  |  | 	if ((tmpstr = ast_variable_retrieve(cfg, "general", "pls-hold-prompt")) && !ast_strlen_zero(tmpstr)) { | 
					
						
							| 
									
										
										
										
											2010-03-05 19:10:47 +00:00
										 |  |  | 		ast_copy_string(plsholdprompt, tmpstr, sizeof(plsholdprompt)); | 
					
						
							| 
									
										
										
										
											2008-08-26 18:05:58 +00:00
										 |  |  | 	} else if ((tmpstr = ast_variable_retrieve(cfg, "general", "pls_hold_prompt")) && !ast_strlen_zero(tmpstr)) { | 
					
						
							| 
									
										
										
										
											2010-03-05 19:10:47 +00:00
										 |  |  | 		ast_copy_string(plsholdprompt, tmpstr, sizeof(plsholdprompt)); | 
					
						
							| 
									
										
										
										
											2008-08-26 18:05:58 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-08-26 18:05:58 +00:00
										 |  |  | 	if ((tmpstr = ast_variable_retrieve(cfg, "general", "status-prompt")) && !ast_strlen_zero(tmpstr)) { | 
					
						
							| 
									
										
										
										
											2010-03-05 19:10:47 +00:00
										 |  |  | 		ast_copy_string(statusprompt, tmpstr, sizeof(statusprompt)); | 
					
						
							| 
									
										
										
										
											2008-08-26 18:05:58 +00:00
										 |  |  | 	} else if ((tmpstr = ast_variable_retrieve(cfg, "general", "status_prompt")) && !ast_strlen_zero(tmpstr)) { | 
					
						
							| 
									
										
										
										
											2010-03-05 19:10:47 +00:00
										 |  |  | 		ast_copy_string(statusprompt, tmpstr, sizeof(statusprompt)); | 
					
						
							| 
									
										
										
										
											2008-08-26 18:05:58 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-08-26 18:05:58 +00:00
										 |  |  | 	if ((tmpstr = ast_variable_retrieve(cfg, "general", "sorry-prompt")) && !ast_strlen_zero(tmpstr)) { | 
					
						
							| 
									
										
										
										
											2010-03-05 19:10:47 +00:00
										 |  |  | 		ast_copy_string(sorryprompt, tmpstr, sizeof(sorryprompt)); | 
					
						
							| 
									
										
										
										
											2008-08-26 18:05:58 +00:00
										 |  |  | 	} else if ((tmpstr = ast_variable_retrieve(cfg, "general", "sorry_prompt")) && !ast_strlen_zero(tmpstr)) { | 
					
						
							| 
									
										
										
										
											2010-03-05 19:10:47 +00:00
										 |  |  | 		ast_copy_string(sorryprompt, tmpstr, sizeof(sorryprompt)); | 
					
						
							| 
									
										
										
										
											2008-08-26 18:05:58 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-27 18:44:31 -05:00
										 |  |  | 	if ((tmpstr = ast_variable_retrieve(cfg, "general", "connecting-prompt")) && !ast_strlen_zero(tmpstr)) { | 
					
						
							|  |  |  | 		ast_copy_string(connprompt, tmpstr, sizeof(connprompt)); | 
					
						
							|  |  |  | 	} else if ((tmpstr = ast_variable_retrieve(cfg, "general", "connecting_prompt")) && !ast_strlen_zero(tmpstr)) { | 
					
						
							|  |  |  | 		ast_copy_string(connprompt, tmpstr, sizeof(connprompt)); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 	/* Chug through config file */ | 
					
						
							| 
									
										
										
										
											2006-06-07 20:02:07 +00:00
										 |  |  | 	while ((cat = ast_category_browse(cfg, cat))) { | 
					
						
							| 
									
										
										
										
											2007-07-30 16:02:01 +00:00
										 |  |  | 		int new = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-06-07 20:02:07 +00:00
										 |  |  | 		if (!strcasecmp(cat, "general")) | 
					
						
							|  |  |  | 			continue; | 
					
						
							| 
									
										
										
										
											2007-07-30 16:02:01 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 		/* Look for an existing one */ | 
					
						
							|  |  |  | 		AST_LIST_TRAVERSE(&followmes, f, entry) { | 
					
						
							|  |  |  | 			if (!strcasecmp(f->name, cat)) | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2007-07-30 16:02:01 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-06-14 19:39:12 +00:00
										 |  |  | 		ast_debug(1, "New profile %s.\n", cat); | 
					
						
							| 
									
										
										
										
											2007-07-30 16:02:01 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 		if (!f) { | 
					
						
							|  |  |  | 			/* Make one then */ | 
					
						
							|  |  |  | 			f = alloc_profile(cat); | 
					
						
							|  |  |  | 			new = 1; | 
					
						
							| 
									
										
										
										
											2007-07-30 16:02:01 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/* Totally fail if we fail to find/create an entry */ | 
					
						
							|  |  |  | 		if (!f) | 
					
						
							|  |  |  | 			continue; | 
					
						
							| 
									
										
										
										
											2008-03-05 16:23:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-07-30 16:02:01 +00:00
										 |  |  | 		if (!new) | 
					
						
							|  |  |  | 			ast_mutex_lock(&f->lock); | 
					
						
							|  |  |  | 		/* Re-initialize the profile */ | 
					
						
							| 
									
										
										
										
											2016-08-11 20:10:44 +03:00
										 |  |  | 		init_profile(f, 1); | 
					
						
							| 
									
										
										
										
											2007-07-30 16:02:01 +00:00
										 |  |  | 		free_numbers(f); | 
					
						
							|  |  |  | 		var = ast_variable_browse(cfg, cat); | 
					
						
							| 
									
										
										
										
											2008-08-26 18:05:58 +00:00
										 |  |  | 		while (var) { | 
					
						
							| 
									
										
										
										
											2007-07-30 16:02:01 +00:00
										 |  |  | 			if (!strcasecmp(var->name, "number")) { | 
					
						
							|  |  |  | 				int idx = 0; | 
					
						
							| 
									
										
										
										
											2019-10-23 12:36:17 -05:00
										 |  |  | 				char copy[strlen(var->value) + 1]; | 
					
						
							|  |  |  | 				char *numberstr; | 
					
						
							| 
									
										
										
										
											2007-07-30 16:02:01 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 				/* Add a new number */ | 
					
						
							| 
									
										
										
										
											2019-10-23 12:36:17 -05:00
										 |  |  | 				strcpy(copy, var->value); /* safe */ | 
					
						
							|  |  |  | 				numberstr = copy; | 
					
						
							| 
									
										
										
										
											2007-07-30 16:02:01 +00:00
										 |  |  | 				if ((tmp = strchr(numberstr, ','))) { | 
					
						
							|  |  |  | 					*tmp++ = '\0'; | 
					
						
							| 
									
										
										
										
											2011-12-13 23:10:42 +00:00
										 |  |  | 					timeout = atoi(tmp); | 
					
						
							|  |  |  | 					if (timeout < 0) { | 
					
						
							|  |  |  | 						timeout = 25; | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 					if ((tmp = strchr(tmp, ','))) { | 
					
						
							| 
									
										
										
										
											2007-07-30 16:02:01 +00:00
										 |  |  | 						*tmp++ = '\0'; | 
					
						
							|  |  |  | 						numorder = atoi(tmp); | 
					
						
							|  |  |  | 						if (numorder < 0) | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 							numorder = 0; | 
					
						
							| 
									
										
										
										
											2017-12-22 09:23:22 -05:00
										 |  |  | 					} else | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 						numorder = 0; | 
					
						
							|  |  |  | 				} else { | 
					
						
							| 
									
										
										
										
											2007-07-30 16:02:01 +00:00
										 |  |  | 					timeout = 25; | 
					
						
							|  |  |  | 					numorder = 0; | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2008-03-05 16:23:44 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 				if (!numorder) { | 
					
						
							| 
									
										
										
										
											2007-07-30 16:02:01 +00:00
										 |  |  | 					idx = 1; | 
					
						
							| 
									
										
										
										
											2017-12-22 09:23:22 -05:00
										 |  |  | 					AST_LIST_TRAVERSE(&f->numbers, nm, entry) | 
					
						
							| 
									
										
										
										
											2007-07-30 16:02:01 +00:00
										 |  |  | 						idx++; | 
					
						
							|  |  |  | 					numorder = idx; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				cur = create_followme_number(numberstr, timeout, numorder); | 
					
						
							| 
									
										
										
										
											2011-12-13 23:10:42 +00:00
										 |  |  | 				if (cur) { | 
					
						
							|  |  |  | 					AST_LIST_INSERT_TAIL(&f->numbers, cur, entry); | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2007-07-30 16:02:01 +00:00
										 |  |  | 			} else { | 
					
						
							|  |  |  | 				profile_set_param(f, var->name, var->value, var->lineno, 1); | 
					
						
							|  |  |  | 				ast_debug(2, "Logging parameter %s with value %s from lineno %d\n", var->name, var->value, var->lineno); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			var = var->next; | 
					
						
							|  |  |  | 		} /* End while(var) loop */ | 
					
						
							| 
									
										
										
										
											2008-03-05 16:23:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-22 09:23:22 -05:00
										 |  |  | 		if (!new) | 
					
						
							| 
									
										
										
										
											2007-07-30 16:02:01 +00:00
										 |  |  | 			ast_mutex_unlock(&f->lock); | 
					
						
							|  |  |  | 		else | 
					
						
							|  |  |  | 			AST_RWLIST_INSERT_HEAD(&followmes, f, entry); | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2007-07-30 16:02:01 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 	ast_config_destroy(cfg); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-07-30 16:02:01 +00:00
										 |  |  | 	AST_RWLIST_UNLOCK(&followmes); | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-22 18:11:57 +00:00
										 |  |  | static void publish_dial_end_event(struct ast_channel *in, struct findme_user_listptr *findme_user_list, struct ast_channel *exception, const char *status) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct findme_user *tmpuser; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	AST_LIST_TRAVERSE(findme_user_list, tmpuser, entry) { | 
					
						
							|  |  |  | 		if (tmpuser->ochan && tmpuser->ochan != exception) { | 
					
						
							|  |  |  | 			ast_channel_publish_dial(in, tmpuser->ochan, NULL, status); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | static void clear_caller(struct findme_user *tmpuser) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct ast_channel *outbound; | 
					
						
							| 
									
										
										
										
											2008-03-05 16:23:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-09 01:36:07 +00:00
										 |  |  | 	if (!tmpuser->ochan) { | 
					
						
							|  |  |  | 		/* Call already cleared. */ | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	outbound = tmpuser->ochan; | 
					
						
							|  |  |  | 	ast_hangup(outbound); | 
					
						
							|  |  |  | 	tmpuser->ochan = NULL; | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-22 09:23:22 -05:00
										 |  |  | static void clear_unanswered_calls(struct findme_user_listptr *findme_user_list) | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct findme_user *tmpuser; | 
					
						
							| 
									
										
										
										
											2008-03-05 16:23:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 	AST_LIST_TRAVERSE(findme_user_list, tmpuser, entry) { | 
					
						
							| 
									
										
										
										
											2012-05-09 02:35:29 +00:00
										 |  |  | 		if (!tmpuser->answered) { | 
					
						
							|  |  |  | 			clear_caller(tmpuser); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-09 01:36:07 +00:00
										 |  |  | static void destroy_calling_node(struct findme_user *node) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	clear_caller(node); | 
					
						
							|  |  |  | 	ast_party_connected_line_free(&node->connected); | 
					
						
							|  |  |  | 	ast_free(node); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-12-13 23:10:42 +00:00
										 |  |  | static void destroy_calling_tree(struct findme_user_listptr *findme_user_list) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct findme_user *fmuser; | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-12-13 23:10:42 +00:00
										 |  |  | 	while ((fmuser = AST_LIST_REMOVE_HEAD(findme_user_list, entry))) { | 
					
						
							| 
									
										
										
										
											2012-05-09 01:36:07 +00:00
										 |  |  | 		destroy_calling_node(fmuser); | 
					
						
							| 
									
										
										
										
											2011-12-13 23:10:42 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-09 01:36:07 +00:00
										 |  |  | static struct ast_channel *wait_for_winner(struct findme_user_listptr *findme_user_list, struct number *nm, struct ast_channel *caller, struct fm_args *tpargs) | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2012-01-11 21:56:12 +00:00
										 |  |  | 	struct ast_party_connected_line connected; | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 	struct ast_channel *watchers[256]; | 
					
						
							|  |  |  | 	int pos; | 
					
						
							|  |  |  | 	struct ast_channel *winner; | 
					
						
							|  |  |  | 	struct ast_frame *f; | 
					
						
							|  |  |  | 	struct findme_user *tmpuser; | 
					
						
							| 
									
										
										
										
											2006-06-06 20:18:01 +00:00
										 |  |  | 	int to = 0; | 
					
						
							| 
									
										
										
										
											2012-05-09 01:36:07 +00:00
										 |  |  | 	int livechannels; | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 	int tmpto; | 
					
						
							| 
									
										
										
										
											2007-07-30 16:02:01 +00:00
										 |  |  | 	long totalwait = 0, wtd = 0, towas = 0; | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 	char *callfromname; | 
					
						
							|  |  |  | 	char *pressbuttonname; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-22 09:23:22 -05:00
										 |  |  | 	/* ------------ wait_for_winner_channel start --------------- */ | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	callfromname = ast_strdupa(tpargs->callfromprompt); | 
					
						
							| 
									
										
										
										
											2008-03-05 16:23:44 +00:00
										 |  |  | 	pressbuttonname = ast_strdupa(tpargs->optionsprompt); | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-07-30 16:02:01 +00:00
										 |  |  | 	totalwait = nm->timeout * 1000; | 
					
						
							| 
									
										
										
										
											2008-03-05 16:23:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-09 01:36:07 +00:00
										 |  |  | 	for (;;) { | 
					
						
							| 
									
										
										
										
											2007-07-30 16:02:01 +00:00
										 |  |  | 		to = 1000; | 
					
						
							| 
									
										
										
										
											2017-12-22 09:23:22 -05:00
										 |  |  | 		pos = 1; | 
					
						
							| 
									
										
										
										
											2007-07-30 16:02:01 +00:00
										 |  |  | 		livechannels = 0; | 
					
						
							|  |  |  | 		watchers[0] = caller; | 
					
						
							| 
									
										
										
										
											2008-03-05 16:23:44 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		winner = NULL; | 
					
						
							| 
									
										
										
										
											2007-07-30 16:02:01 +00:00
										 |  |  | 		AST_LIST_TRAVERSE(findme_user_list, tmpuser, entry) { | 
					
						
							| 
									
										
										
										
											2012-05-09 01:36:07 +00:00
										 |  |  | 			if (!tmpuser->ochan) { | 
					
						
							|  |  |  | 				continue; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if (tmpuser->state == 3) { | 
					
						
							|  |  |  | 				tmpuser->digts += (towas - wtd); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if (tmpuser->digts && (tmpuser->digts > featuredigittimeout)) { | 
					
						
							|  |  |  | 				ast_verb(3, "<%s> We've been waiting for digits longer than we should have.\n", | 
					
						
							|  |  |  | 					ast_channel_name(tmpuser->ochan)); | 
					
						
							| 
									
										
										
										
											2016-05-03 19:11:20 +03:00
										 |  |  | 				if (tpargs->enable_callee_prompt) { | 
					
						
							|  |  |  | 					if (!ast_strlen_zero(tpargs->namerecloc)) { | 
					
						
							|  |  |  | 						tmpuser->state = 1; | 
					
						
							|  |  |  | 						tmpuser->digts = 0; | 
					
						
							|  |  |  | 						if (!ast_streamfile(tmpuser->ochan, callfromname, ast_channel_language(tmpuser->ochan))) { | 
					
						
							|  |  |  | 							ast_sched_runq(ast_channel_sched(tmpuser->ochan)); | 
					
						
							|  |  |  | 						} else { | 
					
						
							|  |  |  | 							ast_log(LOG_WARNING, "Unable to playback %s.\n", callfromname); | 
					
						
							|  |  |  | 							clear_caller(tmpuser); | 
					
						
							|  |  |  | 							continue; | 
					
						
							|  |  |  | 						} | 
					
						
							| 
									
										
										
										
											2007-07-30 16:02:01 +00:00
										 |  |  | 					} else { | 
					
						
							| 
									
										
										
										
											2016-05-03 19:11:20 +03:00
										 |  |  | 						tmpuser->state = 2; | 
					
						
							|  |  |  | 						tmpuser->digts = 0; | 
					
						
							|  |  |  | 						if (!ast_streamfile(tmpuser->ochan, tpargs->norecordingprompt, ast_channel_language(tmpuser->ochan))) | 
					
						
							|  |  |  | 							ast_sched_runq(ast_channel_sched(tmpuser->ochan)); | 
					
						
							|  |  |  | 						else { | 
					
						
							|  |  |  | 							ast_log(LOG_WARNING, "Unable to playback %s.\n", tpargs->norecordingprompt); | 
					
						
							|  |  |  | 							clear_caller(tmpuser); | 
					
						
							|  |  |  | 							continue; | 
					
						
							|  |  |  | 						} | 
					
						
							| 
									
										
										
										
											2012-05-09 01:36:07 +00:00
										 |  |  | 					} | 
					
						
							|  |  |  | 				} else { | 
					
						
							| 
									
										
										
										
											2016-05-03 19:11:20 +03:00
										 |  |  | 					tmpuser->state = 3; | 
					
						
							| 
									
										
										
										
											2007-07-30 16:02:01 +00:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2012-05-09 01:36:07 +00:00
										 |  |  | 			} | 
					
						
							|  |  |  | 			if (ast_channel_stream(tmpuser->ochan)) { | 
					
						
							|  |  |  | 				ast_sched_runq(ast_channel_sched(tmpuser->ochan)); | 
					
						
							|  |  |  | 				tmpto = ast_sched_wait(ast_channel_sched(tmpuser->ochan)); | 
					
						
							|  |  |  | 				if (tmpto > 0 && tmpto < to) | 
					
						
							|  |  |  | 					to = tmpto; | 
					
						
							|  |  |  | 				else if (tmpto < 0 && !ast_channel_timingfunc(tmpuser->ochan)) { | 
					
						
							|  |  |  | 					ast_stopstream(tmpuser->ochan); | 
					
						
							|  |  |  | 					switch (tmpuser->state) { | 
					
						
							|  |  |  | 					case 1: | 
					
						
							|  |  |  | 						ast_verb(3, "<%s> Playback of the call-from file appears to be done.\n", | 
					
						
							|  |  |  | 							ast_channel_name(tmpuser->ochan)); | 
					
						
							|  |  |  | 						if (!ast_streamfile(tmpuser->ochan, tpargs->namerecloc, ast_channel_language(tmpuser->ochan))) { | 
					
						
							|  |  |  | 							tmpuser->state = 2; | 
					
						
							|  |  |  | 						} else { | 
					
						
							|  |  |  | 							ast_log(LOG_NOTICE, "<%s> Unable to playback %s. Maybe the caller didn't record their name?\n", | 
					
						
							|  |  |  | 								ast_channel_name(tmpuser->ochan), tpargs->namerecloc); | 
					
						
							| 
									
										
										
										
											2007-07-30 16:02:01 +00:00
										 |  |  | 							memset(tmpuser->yn, 0, sizeof(tmpuser->yn)); | 
					
						
							|  |  |  | 							tmpuser->ynidx = 0; | 
					
						
							| 
									
										
										
										
											2012-05-09 01:36:07 +00:00
										 |  |  | 							if (!ast_streamfile(tmpuser->ochan, pressbuttonname, ast_channel_language(tmpuser->ochan))) | 
					
						
							| 
									
										
										
										
											2007-07-30 16:02:01 +00:00
										 |  |  | 								tmpuser->state = 3; | 
					
						
							| 
									
										
										
										
											2012-05-09 01:36:07 +00:00
										 |  |  | 							else { | 
					
						
							|  |  |  | 								ast_log(LOG_WARNING, "Unable to playback %s.\n", pressbuttonname); | 
					
						
							|  |  |  | 								clear_caller(tmpuser); | 
					
						
							|  |  |  | 								continue; | 
					
						
							|  |  |  | 							} | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 						} | 
					
						
							| 
									
										
										
										
											2012-05-09 01:36:07 +00:00
										 |  |  | 						break; | 
					
						
							|  |  |  | 					case 2: | 
					
						
							|  |  |  | 						ast_verb(3, "<%s> Playback of name file appears to be done.\n", | 
					
						
							|  |  |  | 							ast_channel_name(tmpuser->ochan)); | 
					
						
							|  |  |  | 						memset(tmpuser->yn, 0, sizeof(tmpuser->yn)); | 
					
						
							|  |  |  | 						tmpuser->ynidx = 0; | 
					
						
							|  |  |  | 						if (!ast_streamfile(tmpuser->ochan, pressbuttonname, ast_channel_language(tmpuser->ochan))) { | 
					
						
							|  |  |  | 							tmpuser->state = 3; | 
					
						
							|  |  |  | 						} else { | 
					
						
							|  |  |  | 							clear_caller(tmpuser); | 
					
						
							|  |  |  | 							continue; | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 						break; | 
					
						
							|  |  |  | 					case 3: | 
					
						
							|  |  |  | 						ast_verb(3, "<%s> Playback of the next step file appears to be done.\n", | 
					
						
							|  |  |  | 							ast_channel_name(tmpuser->ochan)); | 
					
						
							|  |  |  | 						tmpuser->digts = 0; | 
					
						
							|  |  |  | 						break; | 
					
						
							|  |  |  | 					default: | 
					
						
							|  |  |  | 						break; | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2012-05-09 01:36:07 +00:00
										 |  |  | 			watchers[pos++] = tmpuser->ochan; | 
					
						
							|  |  |  | 			livechannels++; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if (!livechannels) { | 
					
						
							|  |  |  | 			ast_verb(3, "No live channels left for this step.\n"); | 
					
						
							|  |  |  | 			return NULL; | 
					
						
							| 
									
										
										
										
											2007-07-30 16:02:01 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2008-03-05 16:23:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-07-30 16:02:01 +00:00
										 |  |  | 		tmpto = to; | 
					
						
							|  |  |  | 		towas = to; | 
					
						
							|  |  |  | 		winner = ast_waitfor_n(watchers, pos, &to); | 
					
						
							|  |  |  | 		tmpto -= to; | 
					
						
							|  |  |  | 		totalwait -= tmpto; | 
					
						
							| 
									
										
										
										
											2008-03-05 16:23:44 +00:00
										 |  |  | 		wtd = to; | 
					
						
							| 
									
										
										
										
											2007-07-30 16:02:01 +00:00
										 |  |  | 		if (totalwait <= 0) { | 
					
						
							| 
									
										
										
										
											2012-05-09 02:35:29 +00:00
										 |  |  | 			ast_verb(3, "We've hit our timeout for this step. Dropping unanswered calls and starting the next step.\n"); | 
					
						
							|  |  |  | 			clear_unanswered_calls(findme_user_list); | 
					
						
							| 
									
										
										
										
											2007-07-30 16:02:01 +00:00
										 |  |  | 			return NULL; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if (winner) { | 
					
						
							|  |  |  | 			/* Need to find out which channel this is */ | 
					
						
							| 
									
										
										
										
											2012-05-09 01:36:07 +00:00
										 |  |  | 			if (winner != caller) { | 
					
						
							| 
									
										
										
										
											2012-01-11 21:56:12 +00:00
										 |  |  | 				/* The winner is an outgoing channel. */ | 
					
						
							|  |  |  | 				AST_LIST_TRAVERSE(findme_user_list, tmpuser, entry) { | 
					
						
							|  |  |  | 					if (tmpuser->ochan == winner) { | 
					
						
							|  |  |  | 						break; | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				tmpuser = NULL; | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2012-05-09 01:36:07 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-07-30 16:02:01 +00:00
										 |  |  | 			f = ast_read(winner); | 
					
						
							|  |  |  | 			if (f) { | 
					
						
							|  |  |  | 				if (f->frametype == AST_FRAME_CONTROL) { | 
					
						
							| 
									
										
										
										
											2009-11-04 14:05:12 +00:00
										 |  |  | 					switch (f->subclass.integer) { | 
					
						
							| 
									
										
										
										
											2007-07-30 16:02:01 +00:00
										 |  |  | 					case AST_CONTROL_HANGUP: | 
					
						
							| 
									
										
										
										
											2012-01-09 22:15:50 +00:00
										 |  |  | 						ast_verb(3, "%s received a hangup frame.\n", ast_channel_name(winner)); | 
					
						
							| 
									
										
										
										
											2008-05-22 16:29:54 +00:00
										 |  |  | 						if (f->data.uint32) { | 
					
						
							| 
									
										
										
										
											2012-02-20 23:43:27 +00:00
										 |  |  | 							ast_channel_hangupcause_set(winner, f->data.uint32); | 
					
						
							| 
									
										
										
										
											2008-04-24 22:16:48 +00:00
										 |  |  | 						} | 
					
						
							| 
									
										
										
										
											2012-05-09 01:36:07 +00:00
										 |  |  | 						if (!tmpuser) { | 
					
						
							|  |  |  | 							ast_verb(3, "The calling channel hungup. Need to drop everyone.\n"); | 
					
						
							| 
									
										
										
										
											2013-05-22 18:11:57 +00:00
										 |  |  | 							publish_dial_end_event(caller, findme_user_list, NULL, "CANCEL"); | 
					
						
							| 
									
										
										
										
											2012-05-09 01:36:07 +00:00
										 |  |  | 							ast_frfree(f); | 
					
						
							|  |  |  | 							return NULL; | 
					
						
							| 
									
										
										
										
											2007-07-30 16:02:01 +00:00
										 |  |  | 						} | 
					
						
							| 
									
										
										
										
											2012-05-09 01:36:07 +00:00
										 |  |  | 						clear_caller(tmpuser); | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 						break; | 
					
						
							| 
									
										
										
										
											2007-07-30 16:02:01 +00:00
										 |  |  | 					case AST_CONTROL_ANSWER: | 
					
						
							| 
									
										
										
										
											2012-05-09 01:36:07 +00:00
										 |  |  | 						if (!tmpuser) { | 
					
						
							|  |  |  | 							/* The caller answered?  We want an outgoing channel to answer. */ | 
					
						
							|  |  |  | 							break; | 
					
						
							|  |  |  | 						} | 
					
						
							| 
									
										
										
										
											2012-01-09 22:15:50 +00:00
										 |  |  | 						ast_verb(3, "%s answered %s\n", ast_channel_name(winner), ast_channel_name(caller)); | 
					
						
							| 
									
										
										
										
											2013-05-22 18:11:57 +00:00
										 |  |  | 						ast_channel_publish_dial(caller, winner, NULL, "ANSWER"); | 
					
						
							|  |  |  | 						publish_dial_end_event(caller, findme_user_list, winner, "CANCEL"); | 
					
						
							| 
									
										
										
										
											2012-05-09 02:35:29 +00:00
										 |  |  | 						tmpuser->answered = 1; | 
					
						
							| 
									
										
										
										
											2017-12-22 09:23:22 -05:00
										 |  |  | 						/* If call has been answered, then the eventual hangup is likely to be normal hangup */ | 
					
						
							| 
									
										
										
										
											2012-02-20 23:43:27 +00:00
										 |  |  | 						ast_channel_hangupcause_set(winner, AST_CAUSE_NORMAL_CLEARING); | 
					
						
							|  |  |  | 						ast_channel_hangupcause_set(caller, AST_CAUSE_NORMAL_CLEARING); | 
					
						
							| 
									
										
										
										
											2016-05-03 19:11:20 +03:00
										 |  |  | 						if (tpargs->enable_callee_prompt) { | 
					
						
							|  |  |  | 							ast_verb(3, "Starting playback of %s\n", callfromname); | 
					
						
							|  |  |  | 							if (!ast_strlen_zero(tpargs->namerecloc)) { | 
					
						
							|  |  |  | 								if (!ast_streamfile(winner, callfromname, ast_channel_language(winner))) { | 
					
						
							|  |  |  | 									ast_sched_runq(ast_channel_sched(winner)); | 
					
						
							|  |  |  | 									tmpuser->state = 1; | 
					
						
							|  |  |  | 								} else { | 
					
						
							|  |  |  | 									ast_log(LOG_WARNING, "Unable to playback %s.\n", callfromname); | 
					
						
							|  |  |  | 									clear_caller(tmpuser); | 
					
						
							|  |  |  | 								} | 
					
						
							| 
									
										
										
										
											2008-03-05 16:23:44 +00:00
										 |  |  | 							} else { | 
					
						
							| 
									
										
										
										
											2016-05-03 19:11:20 +03:00
										 |  |  | 								tmpuser->state = 2; | 
					
						
							|  |  |  | 								if (!ast_streamfile(tmpuser->ochan, tpargs->norecordingprompt, ast_channel_language(tmpuser->ochan))) | 
					
						
							|  |  |  | 									ast_sched_runq(ast_channel_sched(tmpuser->ochan)); | 
					
						
							|  |  |  | 								else { | 
					
						
							|  |  |  | 									ast_log(LOG_WARNING, "Unable to playback %s.\n", tpargs->norecordingprompt); | 
					
						
							|  |  |  | 									clear_caller(tmpuser); | 
					
						
							|  |  |  | 								} | 
					
						
							| 
									
										
										
										
											2012-05-09 01:36:07 +00:00
										 |  |  | 							} | 
					
						
							|  |  |  | 						} else { | 
					
						
							| 
									
										
										
										
											2016-05-03 19:11:20 +03:00
										 |  |  | 							ast_verb(3, "Skip playback of caller name / norecording\n"); | 
					
						
							| 
									
										
										
										
											2012-05-09 01:36:07 +00:00
										 |  |  | 							tmpuser->state = 2; | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 						} | 
					
						
							| 
									
										
										
										
											2007-07-30 16:02:01 +00:00
										 |  |  | 						break; | 
					
						
							|  |  |  | 					case AST_CONTROL_BUSY: | 
					
						
							| 
									
										
										
										
											2012-01-09 22:15:50 +00:00
										 |  |  | 						ast_verb(3, "%s is busy\n", ast_channel_name(winner)); | 
					
						
							| 
									
										
										
										
											2012-05-09 01:36:07 +00:00
										 |  |  | 						if (tmpuser) { | 
					
						
							|  |  |  | 							/* Outbound call was busy.  Drop it. */ | 
					
						
							| 
									
										
										
										
											2013-05-22 18:11:57 +00:00
										 |  |  | 							ast_channel_publish_dial(caller, winner, NULL, "BUSY"); | 
					
						
							| 
									
										
										
										
											2012-05-09 01:36:07 +00:00
										 |  |  | 							clear_caller(tmpuser); | 
					
						
							|  |  |  | 						} | 
					
						
							| 
									
										
										
										
											2007-07-30 16:02:01 +00:00
										 |  |  | 						break; | 
					
						
							|  |  |  | 					case AST_CONTROL_CONGESTION: | 
					
						
							| 
									
										
										
										
											2012-01-09 22:15:50 +00:00
										 |  |  | 						ast_verb(3, "%s is circuit-busy\n", ast_channel_name(winner)); | 
					
						
							| 
									
										
										
										
											2012-05-09 01:36:07 +00:00
										 |  |  | 						if (tmpuser) { | 
					
						
							|  |  |  | 							/* Outbound call was congested.  Drop it. */ | 
					
						
							| 
									
										
										
										
											2013-05-22 18:11:57 +00:00
										 |  |  | 							ast_channel_publish_dial(caller, winner, NULL, "CONGESTION"); | 
					
						
							| 
									
										
										
										
											2012-05-09 01:36:07 +00:00
										 |  |  | 							clear_caller(tmpuser); | 
					
						
							|  |  |  | 						} | 
					
						
							| 
									
										
										
										
											2007-07-30 16:02:01 +00:00
										 |  |  | 						break; | 
					
						
							|  |  |  | 					case AST_CONTROL_RINGING: | 
					
						
							| 
									
										
										
										
											2012-01-09 22:15:50 +00:00
										 |  |  | 						ast_verb(3, "%s is ringing\n", ast_channel_name(winner)); | 
					
						
							| 
									
										
										
										
											2016-05-09 15:00:56 -05:00
										 |  |  | 						ast_channel_publish_dial(caller, winner, NULL, "RINGING"); | 
					
						
							| 
									
										
										
										
											2007-07-30 16:02:01 +00:00
										 |  |  | 						break; | 
					
						
							|  |  |  | 					case AST_CONTROL_PROGRESS: | 
					
						
							| 
									
										
										
										
											2012-01-11 21:56:12 +00:00
										 |  |  | 						ast_verb(3, "%s is making progress\n", ast_channel_name(winner)); | 
					
						
							| 
									
										
										
										
											2016-05-09 15:00:56 -05:00
										 |  |  | 						ast_channel_publish_dial(caller, winner, NULL, "PROGRESS"); | 
					
						
							| 
									
										
										
										
											2007-07-30 16:02:01 +00:00
										 |  |  | 						break; | 
					
						
							|  |  |  | 					case AST_CONTROL_VIDUPDATE: | 
					
						
							| 
									
										
										
										
											2012-01-11 21:56:12 +00:00
										 |  |  | 						ast_verb(3, "%s requested a video update\n", ast_channel_name(winner)); | 
					
						
							| 
									
										
										
										
											2007-07-30 16:02:01 +00:00
										 |  |  | 						break; | 
					
						
							| 
									
										
										
										
											2008-03-05 22:43:22 +00:00
										 |  |  | 					case AST_CONTROL_SRCUPDATE: | 
					
						
							| 
									
										
										
										
											2012-01-11 21:56:12 +00:00
										 |  |  | 						ast_verb(3, "%s requested a source update\n", ast_channel_name(winner)); | 
					
						
							| 
									
										
										
										
											2008-03-05 22:43:22 +00:00
										 |  |  | 						break; | 
					
						
							| 
									
										
										
										
											2007-07-30 16:02:01 +00:00
										 |  |  | 					case AST_CONTROL_PROCEEDING: | 
					
						
							| 
									
										
										
										
											2012-01-11 21:56:12 +00:00
										 |  |  | 						ast_verb(3, "%s is proceeding\n", ast_channel_name(winner)); | 
					
						
							| 
									
										
										
										
											2016-05-09 15:00:56 -05:00
										 |  |  | 						ast_channel_publish_dial(caller, winner, NULL, "PROCEEDING"); | 
					
						
							| 
									
										
										
										
											2007-07-30 16:02:01 +00:00
										 |  |  | 						break; | 
					
						
							|  |  |  | 					case AST_CONTROL_HOLD: | 
					
						
							| 
									
										
										
										
											2012-01-11 21:56:12 +00:00
										 |  |  | 						ast_verb(3, "%s placed call on hold\n", ast_channel_name(winner)); | 
					
						
							| 
									
										
										
										
											2012-05-09 01:59:14 +00:00
										 |  |  | 						if (!tmpuser) { | 
					
						
							|  |  |  | 							/* Caller placed outgoing calls on hold. */ | 
					
						
							|  |  |  | 							tpargs->pending_hold = 1; | 
					
						
							|  |  |  | 							if (f->data.ptr) { | 
					
						
							|  |  |  | 								ast_copy_string(tpargs->suggested_moh, f->data.ptr, | 
					
						
							|  |  |  | 									sizeof(tpargs->suggested_moh)); | 
					
						
							|  |  |  | 							} else { | 
					
						
							|  |  |  | 								tpargs->suggested_moh[0] = '\0'; | 
					
						
							|  |  |  | 							} | 
					
						
							|  |  |  | 						} else { | 
					
						
							|  |  |  | 							/*
 | 
					
						
							|  |  |  | 							 * Outgoing call placed caller on hold. | 
					
						
							|  |  |  | 							 * | 
					
						
							|  |  |  | 							 * Ignore because the outgoing call should not be able to place | 
					
						
							|  |  |  | 							 * the caller on hold until after they are bridged. | 
					
						
							|  |  |  | 							 */ | 
					
						
							|  |  |  | 						} | 
					
						
							| 
									
										
										
										
											2007-07-30 16:02:01 +00:00
										 |  |  | 						break; | 
					
						
							|  |  |  | 					case AST_CONTROL_UNHOLD: | 
					
						
							| 
									
										
										
										
											2012-01-11 21:56:12 +00:00
										 |  |  | 						ast_verb(3, "%s removed call from hold\n", ast_channel_name(winner)); | 
					
						
							| 
									
										
										
										
											2012-05-09 01:59:14 +00:00
										 |  |  | 						if (!tmpuser) { | 
					
						
							|  |  |  | 							/* Caller removed outgoing calls from hold. */ | 
					
						
							|  |  |  | 							tpargs->pending_hold = 0; | 
					
						
							|  |  |  | 						} else { | 
					
						
							|  |  |  | 							/*
 | 
					
						
							|  |  |  | 							 * Outgoing call removed caller from hold. | 
					
						
							|  |  |  | 							 * | 
					
						
							|  |  |  | 							 * Ignore because the outgoing call should not be able to place | 
					
						
							|  |  |  | 							 * the caller on hold until after they are bridged. | 
					
						
							|  |  |  | 							 */ | 
					
						
							|  |  |  | 						} | 
					
						
							| 
									
										
										
										
											2007-07-30 16:02:01 +00:00
										 |  |  | 						break; | 
					
						
							|  |  |  | 					case AST_CONTROL_OFFHOOK: | 
					
						
							|  |  |  | 					case AST_CONTROL_FLASH: | 
					
						
							|  |  |  | 						/* Ignore going off hook and flash */ | 
					
						
							|  |  |  | 						break; | 
					
						
							| 
									
										
										
										
											2012-01-11 21:56:12 +00:00
										 |  |  | 					case AST_CONTROL_CONNECTED_LINE: | 
					
						
							| 
									
										
										
										
											2018-09-26 16:05:59 -04:00
										 |  |  | 						if (ast_test_flag(&tpargs->followmeflags, FOLLOWMEFLAG_IGNORE_CONNECTEDLINE)) { | 
					
						
							|  |  |  | 							ast_verb(3, "Connected line update from %s prevented.\n", | 
					
						
							|  |  |  | 								ast_channel_name(winner)); | 
					
						
							|  |  |  | 							break; | 
					
						
							|  |  |  | 						} | 
					
						
							| 
									
										
										
										
											2012-01-11 21:56:12 +00:00
										 |  |  | 						if (!tmpuser) { | 
					
						
							|  |  |  | 							/*
 | 
					
						
							|  |  |  | 							 * Hold connected line update from caller until we have a | 
					
						
							|  |  |  | 							 * winner. | 
					
						
							|  |  |  | 							 */ | 
					
						
							|  |  |  | 							ast_verb(3, | 
					
						
							|  |  |  | 								"%s connected line has changed. Saving it until we have a winner.\n", | 
					
						
							|  |  |  | 								ast_channel_name(winner)); | 
					
						
							|  |  |  | 							ast_party_connected_line_set_init(&connected, &tpargs->connected_in); | 
					
						
							|  |  |  | 							if (!ast_connected_line_parse_data(f->data.ptr, f->datalen, &connected)) { | 
					
						
							|  |  |  | 								ast_party_connected_line_set(&tpargs->connected_in, | 
					
						
							|  |  |  | 									&connected, NULL); | 
					
						
							|  |  |  | 								tpargs->pending_in_connected_update = 1; | 
					
						
							|  |  |  | 							} | 
					
						
							|  |  |  | 							ast_party_connected_line_free(&connected); | 
					
						
							|  |  |  | 						} else { | 
					
						
							|  |  |  | 							ast_verb(3, | 
					
						
							|  |  |  | 								"%s connected line has changed. Saving it until answer.\n", | 
					
						
							|  |  |  | 								ast_channel_name(winner)); | 
					
						
							|  |  |  | 							ast_party_connected_line_set_init(&connected, &tmpuser->connected); | 
					
						
							|  |  |  | 							if (!ast_connected_line_parse_data(f->data.ptr, f->datalen, &connected)) { | 
					
						
							|  |  |  | 								ast_party_connected_line_set(&tmpuser->connected, | 
					
						
							|  |  |  | 									&connected, NULL); | 
					
						
							|  |  |  | 								tmpuser->pending_connected_update = 1; | 
					
						
							|  |  |  | 							} | 
					
						
							|  |  |  | 							ast_party_connected_line_free(&connected); | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 						break; | 
					
						
							|  |  |  | 					case AST_CONTROL_REDIRECTING: | 
					
						
							|  |  |  | 						/*
 | 
					
						
							|  |  |  | 						 * Ignore because we are masking the FollowMe search progress to | 
					
						
							|  |  |  | 						 * the caller. | 
					
						
							|  |  |  | 						 */ | 
					
						
							|  |  |  | 						break; | 
					
						
							| 
									
										
										
										
											2012-05-14 19:44:27 +00:00
										 |  |  | 					case AST_CONTROL_PVT_CAUSE_CODE: | 
					
						
							|  |  |  | 						ast_indicate_data(caller, f->subclass.integer, f->data.ptr, f->datalen); | 
					
						
							|  |  |  | 						break; | 
					
						
							| 
									
										
										
										
											2007-07-30 16:02:01 +00:00
										 |  |  | 					case -1: | 
					
						
							| 
									
										
										
										
											2012-01-09 22:15:50 +00:00
										 |  |  | 						ast_verb(3, "%s stopped sounds\n", ast_channel_name(winner)); | 
					
						
							| 
									
										
										
										
											2007-07-30 16:02:01 +00:00
										 |  |  | 						break; | 
					
						
							|  |  |  | 					default: | 
					
						
							| 
									
										
										
										
											2012-01-11 21:56:12 +00:00
										 |  |  | 						ast_debug(1, "Dunno what to do with control type %d from %s\n", | 
					
						
							|  |  |  | 							f->subclass.integer, ast_channel_name(winner)); | 
					
						
							| 
									
										
										
										
											2007-07-30 16:02:01 +00:00
										 |  |  | 						break; | 
					
						
							|  |  |  | 					} | 
					
						
							| 
									
										
										
										
											2017-12-22 09:23:22 -05:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2016-05-03 19:11:20 +03:00
										 |  |  | 				if (!tpargs->enable_callee_prompt && tmpuser) { | 
					
						
							|  |  |  | 					ast_debug(1, "Taking call with no prompt\n"); | 
					
						
							|  |  |  | 					ast_frfree(f); | 
					
						
							|  |  |  | 					return tmpuser->ochan; | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2007-07-30 16:02:01 +00:00
										 |  |  | 				if (tmpuser && tmpuser->state == 3 && f->frametype == AST_FRAME_DTMF) { | 
					
						
							| 
									
										
										
										
											2012-05-09 17:58:11 +00:00
										 |  |  | 					int cmp_len; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-02-20 23:43:27 +00:00
										 |  |  | 					if (ast_channel_stream(winner)) | 
					
						
							| 
									
										
										
										
											2007-07-30 16:02:01 +00:00
										 |  |  | 						ast_stopstream(winner); | 
					
						
							|  |  |  | 					tmpuser->digts = 0; | 
					
						
							| 
									
										
										
										
											2009-11-04 14:05:12 +00:00
										 |  |  | 					ast_debug(1, "DTMF received: %c\n", (char) f->subclass.integer); | 
					
						
							| 
									
										
										
										
											2012-05-08 18:16:04 +00:00
										 |  |  | 					if (tmpuser->ynidx < ARRAY_LEN(tmpuser->yn) - 1) { | 
					
						
							| 
									
										
										
										
											2012-05-09 17:58:11 +00:00
										 |  |  | 						tmpuser->yn[tmpuser->ynidx++] = f->subclass.integer; | 
					
						
							|  |  |  | 					} else { | 
					
						
							|  |  |  | 						/* Discard oldest digit. */ | 
					
						
							|  |  |  | 						memmove(tmpuser->yn, tmpuser->yn + 1, | 
					
						
							|  |  |  | 							sizeof(tmpuser->yn) - 2 * sizeof(tmpuser->yn[0])); | 
					
						
							|  |  |  | 						tmpuser->yn[ARRAY_LEN(tmpuser->yn) - 2] = f->subclass.integer; | 
					
						
							| 
									
										
										
										
											2012-05-08 18:16:04 +00:00
										 |  |  | 					} | 
					
						
							| 
									
										
										
										
											2007-07-30 16:02:01 +00:00
										 |  |  | 					ast_debug(1, "DTMF string: %s\n", tmpuser->yn); | 
					
						
							| 
									
										
										
										
											2012-05-09 17:58:11 +00:00
										 |  |  | 					cmp_len = strlen(tpargs->takecall); | 
					
						
							|  |  |  | 					if (cmp_len <= tmpuser->ynidx | 
					
						
							|  |  |  | 						&& !strcmp(tmpuser->yn + (tmpuser->ynidx - cmp_len), tpargs->takecall)) { | 
					
						
							| 
									
										
										
										
											2012-05-08 18:16:04 +00:00
										 |  |  | 						ast_debug(1, "Match to take the call!\n"); | 
					
						
							|  |  |  | 						ast_frfree(f); | 
					
						
							|  |  |  | 						return tmpuser->ochan; | 
					
						
							|  |  |  | 					} | 
					
						
							| 
									
										
										
										
											2012-05-09 17:58:11 +00:00
										 |  |  | 					cmp_len = strlen(tpargs->nextindp); | 
					
						
							|  |  |  | 					if (cmp_len <= tmpuser->ynidx | 
					
						
							|  |  |  | 						&& !strcmp(tmpuser->yn + (tmpuser->ynidx - cmp_len), tpargs->nextindp)) { | 
					
						
							| 
									
										
										
										
											2012-05-09 01:36:07 +00:00
										 |  |  | 						ast_debug(1, "Declined to take the call.\n"); | 
					
						
							|  |  |  | 						clear_caller(tmpuser); | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 					} | 
					
						
							| 
									
										
										
										
											2007-07-30 16:02:01 +00:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2008-03-05 16:23:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-07-30 16:02:01 +00:00
										 |  |  | 				ast_frfree(f); | 
					
						
							|  |  |  | 			} else { | 
					
						
							| 
									
										
										
										
											2012-05-09 01:36:07 +00:00
										 |  |  | 				ast_debug(1, "we didn't get a frame. hanging up.\n"); | 
					
						
							|  |  |  | 				if (!tmpuser) { | 
					
						
							| 
									
										
										
										
											2012-01-11 21:56:12 +00:00
										 |  |  | 					/* Caller hung up. */ | 
					
						
							| 
									
										
										
										
											2012-05-09 01:36:07 +00:00
										 |  |  | 					ast_verb(3, "The calling channel hungup. Need to drop everyone.\n"); | 
					
						
							| 
									
										
										
										
											2012-01-11 21:56:12 +00:00
										 |  |  | 					return NULL; | 
					
						
							| 
									
										
										
										
											2007-07-30 16:02:01 +00:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2012-05-09 01:36:07 +00:00
										 |  |  | 				/* Outgoing channel hung up. */ | 
					
						
							| 
									
										
										
										
											2013-05-22 18:11:57 +00:00
										 |  |  | 				ast_channel_publish_dial(caller, winner, NULL, "NOANSWER"); | 
					
						
							| 
									
										
										
										
											2012-05-09 01:36:07 +00:00
										 |  |  | 				clear_caller(tmpuser); | 
					
						
							| 
									
										
										
										
											2008-03-05 16:23:44 +00:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2012-01-11 21:56:12 +00:00
										 |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2007-07-30 16:02:01 +00:00
										 |  |  | 			ast_debug(1, "timed out waiting for action\n"); | 
					
						
							| 
									
										
										
										
											2012-01-11 21:56:12 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2008-03-05 16:23:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-09 01:36:07 +00:00
										 |  |  | 	/* Unreachable. */ | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-08 21:15:58 +00:00
										 |  |  | /*!
 | 
					
						
							|  |  |  |  * \internal | 
					
						
							|  |  |  |  * \brief Find an extension willing to take the call. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \param tpargs Active Followme config. | 
					
						
							|  |  |  |  * \param caller Channel initiating the outgoing calls. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \retval winner Winning outgoing call. | 
					
						
							|  |  |  |  * \retval NULL if could not find someone to take the call. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static struct ast_channel *findmeexec(struct fm_args *tpargs, struct ast_channel *caller) | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct number *nm; | 
					
						
							| 
									
										
										
										
											2006-06-06 16:54:52 +00:00
										 |  |  | 	struct ast_channel *winner = NULL; | 
					
						
							| 
									
										
										
										
											2011-12-13 23:10:42 +00:00
										 |  |  | 	char num[512]; | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 	int dg, idx; | 
					
						
							|  |  |  | 	char *rest, *number; | 
					
						
							|  |  |  | 	struct findme_user *tmpuser; | 
					
						
							|  |  |  | 	struct findme_user *fmuser; | 
					
						
							| 
									
										
										
										
											2012-05-08 22:25:42 +00:00
										 |  |  | 	struct findme_user_listptr findme_user_list = AST_LIST_HEAD_NOLOCK_INIT_VALUE; | 
					
						
							| 
									
										
										
										
											2012-05-09 01:36:07 +00:00
										 |  |  | 	struct findme_user_listptr new_user_list = AST_LIST_HEAD_NOLOCK_INIT_VALUE; | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-01-11 21:56:12 +00:00
										 |  |  | 	for (idx = 1; !ast_check_hangup(caller); ++idx) { | 
					
						
							| 
									
										
										
										
											2011-12-13 23:10:42 +00:00
										 |  |  | 		/* Find next followme numbers to dial. */ | 
					
						
							|  |  |  | 		AST_LIST_TRAVERSE(&tpargs->cnumbers, nm, entry) { | 
					
						
							|  |  |  | 			if (nm->order == idx) { | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if (!nm) { | 
					
						
							| 
									
										
										
										
											2012-05-09 01:36:07 +00:00
										 |  |  | 			ast_verb(3, "No more steps left.\n"); | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 			break; | 
					
						
							| 
									
										
										
										
											2011-12-13 23:10:42 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-09 01:36:07 +00:00
										 |  |  | 		ast_debug(2, "Number(s) %s timeout %ld\n", nm->number, nm->timeout); | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-09 02:35:29 +00:00
										 |  |  | 		/*
 | 
					
						
							|  |  |  | 		 * Put all active outgoing channels into autoservice. | 
					
						
							|  |  |  | 		 * | 
					
						
							|  |  |  | 		 * This needs to be done because ast_exists_extension() may put | 
					
						
							|  |  |  | 		 * the caller into autoservice. | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		AST_LIST_TRAVERSE(&findme_user_list, tmpuser, entry) { | 
					
						
							|  |  |  | 			if (tmpuser->ochan) { | 
					
						
							|  |  |  | 				ast_autoservice_start(tmpuser->ochan); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/* Create all new outgoing calls */ | 
					
						
							| 
									
										
										
										
											2011-12-13 23:10:42 +00:00
										 |  |  | 		ast_copy_string(num, nm->number, sizeof(num)); | 
					
						
							|  |  |  | 		for (number = num; number; number = rest) { | 
					
						
							| 
									
										
										
										
											2012-05-09 01:36:07 +00:00
										 |  |  | 			struct ast_channel *outbound; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 			rest = strchr(number, '&'); | 
					
						
							|  |  |  | 			if (rest) { | 
					
						
							| 
									
										
										
										
											2011-12-13 23:10:42 +00:00
										 |  |  | 				*rest++ = 0; | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-12-13 23:10:42 +00:00
										 |  |  | 			/* We check if the extension exists, before creating the ast_channel struct */ | 
					
						
							| 
									
										
										
										
											2012-02-29 16:52:47 +00:00
										 |  |  | 			if (!ast_exists_extension(caller, tpargs->context, number, 1, S_COR(ast_channel_caller(caller)->id.number.valid, ast_channel_caller(caller)->id.number.str, NULL))) { | 
					
						
							| 
									
										
										
										
											2010-12-07 00:31:20 +00:00
										 |  |  | 				ast_log(LOG_ERROR, "Extension '%s@%s' doesn't exist\n", number, tpargs->context); | 
					
						
							| 
									
										
										
										
											2011-12-13 23:10:42 +00:00
										 |  |  | 				continue; | 
					
						
							| 
									
										
										
										
											2010-12-07 00:31:20 +00:00
										 |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 			tmpuser = ast_calloc(1, sizeof(*tmpuser)); | 
					
						
							|  |  |  | 			if (!tmpuser) { | 
					
						
							| 
									
										
										
										
											2011-12-13 23:10:42 +00:00
										 |  |  | 				continue; | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2008-03-05 16:23:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-09 01:36:07 +00:00
										 |  |  | 			if (ast_strlen_zero(tpargs->context)) { | 
					
						
							|  |  |  | 				snprintf(tmpuser->dialarg, sizeof(tmpuser->dialarg), "%s%s", | 
					
						
							|  |  |  | 					number, | 
					
						
							|  |  |  | 					ast_test_flag(&tpargs->followmeflags, FOLLOWMEFLAG_DISABLEOPTIMIZATION) | 
					
						
							| 
									
										
										
										
											2012-05-09 01:59:14 +00:00
										 |  |  | 						? "/n" : "/m"); | 
					
						
							| 
									
										
										
										
											2011-12-13 23:10:42 +00:00
										 |  |  | 			} else { | 
					
						
							| 
									
										
										
										
											2012-05-09 01:36:07 +00:00
										 |  |  | 				snprintf(tmpuser->dialarg, sizeof(tmpuser->dialarg), "%s@%s%s", | 
					
						
							|  |  |  | 					number, tpargs->context, | 
					
						
							|  |  |  | 					ast_test_flag(&tpargs->followmeflags, FOLLOWMEFLAG_DISABLEOPTIMIZATION) | 
					
						
							| 
									
										
										
										
											2012-05-09 01:59:14 +00:00
										 |  |  | 						? "/n" : "/m"); | 
					
						
							| 
									
										
										
										
											2012-05-09 01:36:07 +00:00
										 |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
											  
											
												uniqueid: channel linkedid, ami, ari object creation with id's
Much needed was a way to assign id to objects on creation, and
much change was necessary to accomplish it.  Channel uniqueids
and linkedids are split into separate string and creation time
components without breaking linkedid propgation.  This allowed
the uniqueid to be specified by the user interface - and those
values are now carried through to channel creation, adding the
assignedids value to every function in the chain including the
channel drivers. For local channels, the second channel can be
specified or left to default to a ;2 suffix of first.  In ARI,
bridge, playback, and snoop objects can also be created with a
specified uniqueid.
Along the way, the args order to allocating channels was fixed
in chan_mgcp and chan_gtalk, and linkedid is no longer lost as
masquerade occurs.
(closes issue ASTERISK-23120)
Review: https://reviewboard.asterisk.org/r/3191/
........
Merged revisions 410157 from http://svn.asterisk.org/svn/asterisk/branches/12
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@410158 65c4cc65-6c06-0410-ace0-fbb531ad65f3
											
										 
											2014-03-07 15:47:55 +00:00
										 |  |  | 			outbound = ast_request("Local", ast_channel_nativeformats(caller), NULL, caller, | 
					
						
							| 
									
										
										
										
											2012-05-09 01:36:07 +00:00
										 |  |  | 				tmpuser->dialarg, &dg); | 
					
						
							|  |  |  | 			if (!outbound) { | 
					
						
							|  |  |  | 				ast_log(LOG_WARNING, "Unable to allocate a channel for Local/%s cause: %s\n", | 
					
						
							|  |  |  | 					tmpuser->dialarg, ast_cause2str(dg)); | 
					
						
							| 
									
										
										
										
											2011-12-13 23:10:42 +00:00
										 |  |  | 				ast_free(tmpuser); | 
					
						
							| 
									
										
										
										
											2012-05-09 01:36:07 +00:00
										 |  |  | 				continue; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			ast_channel_lock_both(caller, outbound); | 
					
						
							|  |  |  | 			ast_connected_line_copy_from_caller(ast_channel_connected(outbound), ast_channel_caller(caller)); | 
					
						
							|  |  |  | 			ast_channel_inherit_variables(caller, outbound); | 
					
						
							|  |  |  | 			ast_channel_datastore_inherit(caller, outbound); | 
					
						
							| 
									
										
										
										
											2015-04-15 10:38:02 -05:00
										 |  |  | 			ast_max_forwards_decrement(outbound); | 
					
						
							| 
									
										
										
										
											2012-05-09 01:36:07 +00:00
										 |  |  | 			ast_channel_language_set(outbound, ast_channel_language(caller)); | 
					
						
							| 
									
										
											  
											
												accountcode: Slightly change accountcode propagation.
The previous behavior was to simply set the accountcode of an outgoing
channel to the accountcode of the channel initiating the call.  It was
done this way a long time ago to allow the accountcode set on the SIP/100
channel to be propagated to a local channel so the dialplan execution on
the Local;2 channel would have the SIP/100 accountcode available.
SIP/100 -> Local;1/Local;2 -> SIP/200
Propagating the SIP/100 accountcode to the local channels is very useful.
Without any dialplan manipulation, all channels in this call would have
the same accountcode.
Using dialplan, you can set a different accountcode on the SIP/200 channel
either by setting the accountcode on the Local;2 channel or by the Dial
application's b(pre-dial), M(macro) or U(gosub) options, or by the
FollowMe application's b(pre-dial) option, or by the Queue application's
macro or gosub options.  Before Asterisk v12, the altered accountcode on
SIP/200 will remain until the local channels optimize out and the
accountcode would change to the SIP/100 accountcode.
Asterisk v1.8 attempted to add peeraccount support but ultimately had to
punt on the support.  The peeraccount support was rendered useless because
of how the CDR code needed to unconditionally force the caller's
accountcode onto the peer channel's accountcode.  The CEL events were thus
intentionally made to always use the channel's accountcode as the
peeraccount value.
With the arrival of Asterisk v12, the situation has improved somewhat so
peeraccount support can be made to work.  Using the indicated example, the
the accountcode values become as follows when the peeraccount is set on
SIP/100 before calling SIP/200:
SIP/100 ---> Local;1 ---- Local;2 ---> SIP/200
acct: 100 \/ acct: 200 \/ acct: 100 \/ acct: 200
peer: 200 /\ peer: 100 /\ peer: 200 /\ peer: 100
If a channel already has an accountcode it can only change by the
following explicit user actions:
1) A channel originate method that can specify an accountcode to use.
2) The calling channel propagating its non-empty peeraccount or its
non-empty accountcode if the peeraccount was empty to the outgoing
channel's accountcode before initiating the dial.  e.g., Dial and
FollowMe.  The exception to this propagation method is Queue.  Queue will
only propagate peeraccounts this way only if the outgoing channel does not
have an accountcode.
3) Dialplan using CHANNEL(accountcode).
4) Dialplan using CHANNEL(peeraccount) on the other end of a local
channel pair.
If a channel does not have an accountcode it can get one from the
following places:
1) The channel driver's configuration at channel creation.
2) Explicit user action as already indicated.
3) Entering a basic or stasis-mixing bridge from a peer channel's
peeraccount value.
You can specify the accountcode for an outgoing channel by setting the
CHANNEL(peeraccount) before using the Dial, FollowMe, and Queue
applications.  Queue adds the wrinkle that it will not overwrite an
existing accountcode on the outgoing channel with the calling channels
values.
Accountcode and peeraccount values propagate to an outgoing channel before
dialing.  Accountcodes also propagate when channels enter or leave a basic
or stasis-mixing bridge.  The peeraccount value only makes sense for
mixing bridges with two channels; it is meaningless otherwise.
* Made peeraccount functional by changing accountcode propagation as
described above.
* Fixed CEL extracting the wrong ie value for the peeraccount.  This was
done intentionally in Asterisk v1.8 when that version had to punt on
peeraccount.
* Fixed a few places dealing with accountcodes that were reading from
channels without the lock held.
AFS-65 #close
Review: https://reviewboard.asterisk.org/r/3601/
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@419520 65c4cc65-6c06-0410-ace0-fbb531ad65f3
											
										 
											2014-07-24 22:48:38 +00:00
										 |  |  | 			ast_channel_req_accountcodes(outbound, caller, AST_CHANNEL_REQUESTOR_BRIDGE_PEER); | 
					
						
							| 
									
										
										
										
											2012-05-09 01:36:07 +00:00
										 |  |  | 			ast_channel_musicclass_set(outbound, ast_channel_musicclass(caller)); | 
					
						
							|  |  |  | 			ast_channel_unlock(outbound); | 
					
						
							|  |  |  | 			ast_channel_unlock(caller); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			tmpuser->ochan = outbound; | 
					
						
							|  |  |  | 			tmpuser->state = 0; | 
					
						
							| 
									
										
										
										
											2012-05-09 02:35:29 +00:00
										 |  |  | 			AST_LIST_INSERT_TAIL(&new_user_list, tmpuser, entry); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2012-05-09 01:36:07 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-15 16:53:09 +00:00
										 |  |  | 		/*
 | 
					
						
							|  |  |  | 		 * PREDIAL: Run gosub on all of the new callee channels | 
					
						
							|  |  |  | 		 * | 
					
						
							|  |  |  | 		 * We run the callee predial before ast_call() in case the user | 
					
						
							|  |  |  | 		 * wishes to do something on the newly created channels before | 
					
						
							|  |  |  | 		 * the channel does anything important. | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		if (tpargs->predial_callee && !AST_LIST_EMPTY(&new_user_list)) { | 
					
						
							|  |  |  | 			/* Put caller into autoservice. */ | 
					
						
							|  |  |  | 			ast_autoservice_start(caller); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			/* Run predial on all new outgoing calls. */ | 
					
						
							|  |  |  | 			AST_LIST_TRAVERSE(&new_user_list, tmpuser, entry) { | 
					
						
							|  |  |  | 				ast_pre_call(tmpuser->ochan, tpargs->predial_callee); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			/* Take caller out of autoservice. */ | 
					
						
							|  |  |  | 			if (ast_autoservice_stop(caller)) { | 
					
						
							|  |  |  | 				/*
 | 
					
						
							|  |  |  | 				 * Caller hungup. | 
					
						
							|  |  |  | 				 * | 
					
						
							|  |  |  | 				 * Destoy all new outgoing calls. | 
					
						
							|  |  |  | 				 */ | 
					
						
							|  |  |  | 				while ((tmpuser = AST_LIST_REMOVE_HEAD(&new_user_list, entry))) { | 
					
						
							|  |  |  | 					destroy_calling_node(tmpuser); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				/* Take all active outgoing channels out of autoservice. */ | 
					
						
							|  |  |  | 				AST_LIST_TRAVERSE(&findme_user_list, tmpuser, entry) { | 
					
						
							|  |  |  | 					if (tmpuser->ochan) { | 
					
						
							|  |  |  | 						ast_autoservice_stop(tmpuser->ochan); | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-09 02:35:29 +00:00
										 |  |  | 		/* Start all new outgoing calls */ | 
					
						
							|  |  |  | 		AST_LIST_TRAVERSE_SAFE_BEGIN(&new_user_list, tmpuser, entry) { | 
					
						
							| 
									
										
										
										
											2012-05-09 01:36:07 +00:00
										 |  |  | 			ast_verb(3, "calling Local/%s\n", tmpuser->dialarg); | 
					
						
							| 
									
										
										
										
											2012-05-09 02:35:29 +00:00
										 |  |  | 			if (ast_call(tmpuser->ochan, tmpuser->dialarg, 0)) { | 
					
						
							| 
									
										
										
										
											2012-05-09 01:36:07 +00:00
										 |  |  | 				ast_verb(3, "couldn't reach at this number.\n"); | 
					
						
							| 
									
										
										
										
											2012-05-09 02:35:29 +00:00
										 |  |  | 				AST_LIST_REMOVE_CURRENT(entry); | 
					
						
							| 
									
										
										
										
											2012-05-09 01:36:07 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 				/* Destroy this failed new outgoing call. */ | 
					
						
							|  |  |  | 				destroy_calling_node(tmpuser); | 
					
						
							| 
									
										
										
										
											2013-05-22 18:11:57 +00:00
										 |  |  | 				continue; | 
					
						
							| 
									
										
										
										
											2011-12-13 23:10:42 +00:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2013-05-22 18:11:57 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			ast_channel_publish_dial(caller, tmpuser->ochan, tmpuser->dialarg, NULL); | 
					
						
							| 
									
										
										
										
											2011-12-13 23:10:42 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2012-05-09 02:35:29 +00:00
										 |  |  | 		AST_LIST_TRAVERSE_SAFE_END; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/* Take all active outgoing channels out of autoservice. */ | 
					
						
							|  |  |  | 		AST_LIST_TRAVERSE_SAFE_BEGIN(&findme_user_list, tmpuser, entry) { | 
					
						
							|  |  |  | 			if (tmpuser->ochan && ast_autoservice_stop(tmpuser->ochan)) { | 
					
						
							|  |  |  | 				/* Existing outgoing call hungup. */ | 
					
						
							|  |  |  | 				AST_LIST_REMOVE_CURRENT(entry); | 
					
						
							|  |  |  | 				destroy_calling_node(tmpuser); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		AST_LIST_TRAVERSE_SAFE_END; | 
					
						
							| 
									
										
										
										
											2008-03-05 16:23:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-09 01:36:07 +00:00
										 |  |  | 		if (AST_LIST_EMPTY(&new_user_list)) { | 
					
						
							|  |  |  | 			/* No new channels remain at this order level.  If there were any at all. */ | 
					
						
							| 
									
										
										
										
											2011-12-13 23:10:42 +00:00
										 |  |  | 			continue; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2008-03-05 16:23:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-09 01:36:07 +00:00
										 |  |  | 		/* Add new outgoing channels to the findme list. */ | 
					
						
							|  |  |  | 		AST_LIST_APPEND_LIST(&findme_user_list, &new_user_list, entry); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		winner = wait_for_winner(&findme_user_list, nm, caller, tpargs); | 
					
						
							| 
									
										
										
										
											2012-01-11 21:56:12 +00:00
										 |  |  | 		if (!winner) { | 
					
						
							| 
									
										
										
										
											2012-05-09 02:35:29 +00:00
										 |  |  | 			/* Remove all dead outgoing nodes. */ | 
					
						
							|  |  |  | 			AST_LIST_TRAVERSE_SAFE_BEGIN(&findme_user_list, tmpuser, entry) { | 
					
						
							|  |  |  | 				if (!tmpuser->ochan) { | 
					
						
							|  |  |  | 					AST_LIST_REMOVE_CURRENT(entry); | 
					
						
							|  |  |  | 					destroy_calling_node(tmpuser); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			AST_LIST_TRAVERSE_SAFE_END; | 
					
						
							| 
									
										
										
										
											2012-01-11 21:56:12 +00:00
										 |  |  | 			continue; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2008-03-05 16:23:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-01-11 21:56:12 +00:00
										 |  |  | 		/* Destroy losing calls up to the winner.  The rest will be destroyed later. */ | 
					
						
							| 
									
										
										
										
											2012-05-08 22:25:42 +00:00
										 |  |  | 		while ((fmuser = AST_LIST_REMOVE_HEAD(&findme_user_list, entry))) { | 
					
						
							| 
									
										
										
										
											2012-01-11 21:56:12 +00:00
										 |  |  | 			if (fmuser->ochan == winner) { | 
					
						
							| 
									
										
										
										
											2012-05-09 01:36:07 +00:00
										 |  |  | 				/*
 | 
					
						
							|  |  |  | 				 * Pass any connected line info up. | 
					
						
							|  |  |  | 				 * | 
					
						
							|  |  |  | 				 * NOTE: This code must be in line with destroy_calling_node(). | 
					
						
							|  |  |  | 				 */ | 
					
						
							| 
									
										
										
										
											2012-01-11 21:56:12 +00:00
										 |  |  | 				tpargs->connected_out = fmuser->connected; | 
					
						
							|  |  |  | 				tpargs->pending_out_connected_update = fmuser->pending_connected_update; | 
					
						
							|  |  |  | 				ast_free(fmuser); | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				/* Destroy losing call. */ | 
					
						
							| 
									
										
										
										
											2012-05-09 01:36:07 +00:00
										 |  |  | 				destroy_calling_node(fmuser); | 
					
						
							| 
									
										
										
										
											2011-12-13 23:10:42 +00:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2012-01-11 21:56:12 +00:00
										 |  |  | 		break; | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2012-05-08 22:25:42 +00:00
										 |  |  | 	destroy_calling_tree(&findme_user_list); | 
					
						
							| 
									
										
										
										
											2012-05-08 21:15:58 +00:00
										 |  |  | 	return winner; | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-08-25 16:02:56 +00:00
										 |  |  | static struct call_followme *find_realtime(const char *name) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2012-01-06 16:50:08 +00:00
										 |  |  | 	struct ast_variable *var; | 
					
						
							|  |  |  | 	struct ast_variable *v; | 
					
						
							| 
									
										
										
										
											2008-08-25 16:02:56 +00:00
										 |  |  | 	struct ast_config *cfg; | 
					
						
							|  |  |  | 	const char *catg; | 
					
						
							| 
									
										
										
										
											2012-01-06 16:50:08 +00:00
										 |  |  | 	struct call_followme *new_follower; | 
					
						
							|  |  |  | 	struct ast_str *str; | 
					
						
							| 
									
										
										
										
											2008-08-25 16:02:56 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-01-06 16:50:08 +00:00
										 |  |  | 	str = ast_str_create(16); | 
					
						
							|  |  |  | 	if (!str) { | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var = ast_load_realtime("followme", "name", name, SENTINEL); | 
					
						
							| 
									
										
										
										
											2008-08-25 16:02:56 +00:00
										 |  |  | 	if (!var) { | 
					
						
							| 
									
										
										
										
											2012-01-06 16:50:08 +00:00
										 |  |  | 		ast_free(str); | 
					
						
							| 
									
										
										
										
											2008-08-25 16:02:56 +00:00
										 |  |  | 		return NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-01-06 16:50:08 +00:00
										 |  |  | 	if (!(new_follower = alloc_profile(name))) { | 
					
						
							|  |  |  | 		ast_variables_destroy(var); | 
					
						
							|  |  |  | 		ast_free(str); | 
					
						
							| 
									
										
										
										
											2008-08-25 16:02:56 +00:00
										 |  |  | 		return NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-08-11 20:10:44 +03:00
										 |  |  | 	init_profile(new_follower, 0); | 
					
						
							| 
									
										
										
										
											2008-08-25 16:02:56 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	for (v = var; v; v = v->next) { | 
					
						
							|  |  |  | 		if (!strcasecmp(v->name, "active")) { | 
					
						
							|  |  |  | 			if (ast_false(v->value)) { | 
					
						
							| 
									
										
										
										
											2012-01-06 16:50:08 +00:00
										 |  |  | 				ast_mutex_destroy(&new_follower->lock); | 
					
						
							|  |  |  | 				ast_free(new_follower); | 
					
						
							|  |  |  | 				ast_variables_destroy(var); | 
					
						
							|  |  |  | 				ast_free(str); | 
					
						
							| 
									
										
										
										
											2008-08-25 16:02:56 +00:00
										 |  |  | 				return NULL; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2012-01-06 16:50:08 +00:00
										 |  |  | 			profile_set_param(new_follower, v->name, v->value, 0, 0); | 
					
						
							| 
									
										
										
										
											2008-08-25 16:02:56 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ast_variables_destroy(var); | 
					
						
							| 
									
										
										
										
											2012-01-06 16:50:08 +00:00
										 |  |  | 	new_follower->realtime = 1; | 
					
						
							| 
									
										
										
										
											2008-08-25 16:02:56 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* Load numbers */ | 
					
						
							| 
									
										
										
										
											2012-01-06 16:50:08 +00:00
										 |  |  | 	cfg = ast_load_realtime_multientry("followme_numbers", "ordinal LIKE", "%", "name", | 
					
						
							|  |  |  | 		name, SENTINEL); | 
					
						
							|  |  |  | 	if (!cfg) { | 
					
						
							|  |  |  | 		ast_mutex_destroy(&new_follower->lock); | 
					
						
							|  |  |  | 		ast_free(new_follower); | 
					
						
							|  |  |  | 		ast_free(str); | 
					
						
							| 
									
										
										
										
											2008-08-25 16:02:56 +00:00
										 |  |  | 		return NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (catg = ast_category_browse(cfg, NULL); catg; catg = ast_category_browse(cfg, catg)) { | 
					
						
							| 
									
										
										
										
											2012-01-06 16:50:08 +00:00
										 |  |  | 		const char *numstr; | 
					
						
							|  |  |  | 		const char *timeoutstr; | 
					
						
							|  |  |  | 		const char *ordstr; | 
					
						
							| 
									
										
										
										
											2008-08-25 16:02:56 +00:00
										 |  |  | 		int timeout; | 
					
						
							|  |  |  | 		struct number *cur; | 
					
						
							| 
									
										
										
										
											2012-01-06 16:50:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-08-25 16:02:56 +00:00
										 |  |  | 		if (!(numstr = ast_variable_retrieve(cfg, catg, "phonenumber"))) { | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2012-01-06 16:50:08 +00:00
										 |  |  | 		if (!(timeoutstr = ast_variable_retrieve(cfg, catg, "timeout")) | 
					
						
							|  |  |  | 			|| sscanf(timeoutstr, "%30d", &timeout) != 1 | 
					
						
							|  |  |  | 			|| timeout < 1) { | 
					
						
							| 
									
										
										
										
											2008-08-25 16:02:56 +00:00
										 |  |  | 			timeout = 25; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		/* This one has to exist; it was part of the query */ | 
					
						
							|  |  |  | 		ordstr = ast_variable_retrieve(cfg, catg, "ordinal"); | 
					
						
							| 
									
										
										
										
											2008-12-13 08:36:35 +00:00
										 |  |  | 		ast_str_set(&str, 0, "%s", numstr); | 
					
						
							|  |  |  | 		if ((cur = create_followme_number(ast_str_buffer(str), timeout, atoi(ordstr)))) { | 
					
						
							| 
									
										
										
										
											2012-01-06 16:50:08 +00:00
										 |  |  | 			AST_LIST_INSERT_TAIL(&new_follower->numbers, cur, entry); | 
					
						
							| 
									
										
										
										
											2008-08-25 16:02:56 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	ast_config_destroy(cfg); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-01-06 16:50:08 +00:00
										 |  |  | 	ast_free(str); | 
					
						
							|  |  |  | 	return new_follower; | 
					
						
							| 
									
										
										
										
											2008-08-25 16:02:56 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-11-09 01:27:00 +00:00
										 |  |  | static void end_bridge_callback(void *data) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	char buf[80]; | 
					
						
							|  |  |  | 	time_t end; | 
					
						
							|  |  |  | 	struct ast_channel *chan = data; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	time(&end); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ast_channel_lock(chan); | 
					
						
							| 
									
										
										
										
											2013-06-17 03:00:38 +00:00
										 |  |  | 	snprintf(buf, sizeof(buf), "%d", ast_channel_get_up_time(chan)); | 
					
						
							|  |  |  | 	pbx_builtin_setvar_helper(chan, "ANSWEREDTIME", buf); | 
					
						
							|  |  |  | 	snprintf(buf, sizeof(buf), "%d", ast_channel_get_duration(chan)); | 
					
						
							|  |  |  | 	pbx_builtin_setvar_helper(chan, "DIALEDTIME", buf); | 
					
						
							| 
									
										
										
										
											2008-11-09 01:27:00 +00:00
										 |  |  | 	ast_channel_unlock(chan); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-11-18 18:31:08 +00:00
										 |  |  | static void end_bridge_callback_data_fixup(struct ast_bridge_config *bconfig, struct ast_channel *originator, struct ast_channel *terminator) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	bconfig->end_bridge_callback_data = originator; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-05-21 21:13:09 +00:00
										 |  |  | static int app_exec(struct ast_channel *chan, const char *data) | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2012-05-08 21:41:58 +00:00
										 |  |  | 	struct fm_args *targs; | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 	struct ast_bridge_config config; | 
					
						
							| 
									
										
										
										
											2006-09-05 20:36:27 +00:00
										 |  |  | 	struct call_followme *f; | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 	struct number *nm, *newnm; | 
					
						
							|  |  |  | 	int res = 0; | 
					
						
							|  |  |  | 	char *argstr; | 
					
						
							|  |  |  | 	struct ast_channel *caller; | 
					
						
							|  |  |  | 	struct ast_channel *outbound; | 
					
						
							|  |  |  | 	AST_DECLARE_APP_ARGS(args, | 
					
						
							|  |  |  | 		AST_APP_ARG(followmeid); | 
					
						
							|  |  |  | 		AST_APP_ARG(options); | 
					
						
							|  |  |  | 	); | 
					
						
							| 
									
										
										
										
											2012-05-15 16:53:09 +00:00
										 |  |  | 	char *opt_args[FOLLOWMEFLAG_ARG_ARRAY_SIZE]; | 
					
						
							| 
									
										
										
										
											2015-04-15 10:38:02 -05:00
										 |  |  | 	int max_forwards; | 
					
						
							| 
									
										
										
										
											2007-07-30 16:02:01 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (ast_strlen_zero(data)) { | 
					
						
							|  |  |  | 		ast_log(LOG_WARNING, "%s requires an argument (followmeid)\n", app); | 
					
						
							|  |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2008-03-05 16:23:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-15 10:38:02 -05:00
										 |  |  | 	ast_channel_lock(chan); | 
					
						
							|  |  |  | 	max_forwards = ast_max_forwards_get(chan); | 
					
						
							|  |  |  | 	ast_channel_unlock(chan); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (max_forwards <= 0) { | 
					
						
							|  |  |  | 		ast_log(LOG_WARNING, "Unable to execute FollowMe on channel %s. Max forwards exceeded\n", | 
					
						
							|  |  |  | 				ast_channel_name(chan)); | 
					
						
							|  |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-12-13 23:10:42 +00:00
										 |  |  | 	argstr = ast_strdupa((char *) data); | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-07-30 16:02:01 +00:00
										 |  |  | 	AST_STANDARD_APP_ARGS(args, argstr); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (ast_strlen_zero(args.followmeid)) { | 
					
						
							|  |  |  | 		ast_log(LOG_WARNING, "%s requires an argument (followmeid)\n", app); | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-08 21:41:58 +00:00
										 |  |  | 	targs = ast_calloc(1, sizeof(*targs)); | 
					
						
							|  |  |  | 	if (!targs) { | 
					
						
							|  |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-07-30 16:02:01 +00:00
										 |  |  | 	AST_RWLIST_RDLOCK(&followmes); | 
					
						
							|  |  |  | 	AST_RWLIST_TRAVERSE(&followmes, f, entry) { | 
					
						
							| 
									
										
										
										
											2006-09-05 20:36:27 +00:00
										 |  |  | 		if (!strcasecmp(f->name, args.followmeid) && (f->active)) | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2007-07-30 16:02:01 +00:00
										 |  |  | 	AST_RWLIST_UNLOCK(&followmes); | 
					
						
							| 
									
										
										
										
											2008-03-05 16:23:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-06-14 19:39:12 +00:00
										 |  |  | 	ast_debug(1, "New profile %s.\n", args.followmeid); | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-08-25 16:02:56 +00:00
										 |  |  | 	if (!f) { | 
					
						
							|  |  |  | 		f = find_realtime(args.followmeid); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-07-30 16:02:01 +00:00
										 |  |  | 	if (!f) { | 
					
						
							|  |  |  | 		ast_log(LOG_WARNING, "Profile requested, %s, not found in the configuration.\n", args.followmeid); | 
					
						
							| 
									
										
										
										
											2012-05-08 21:41:58 +00:00
										 |  |  | 		ast_free(targs); | 
					
						
							| 
									
										
										
										
											2007-07-30 16:02:01 +00:00
										 |  |  | 		return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-07-30 16:02:01 +00:00
										 |  |  | 	/* XXX TODO: Reinsert the db check value to see whether or not follow-me is on or off */ | 
					
						
							| 
									
										
										
										
											2012-05-08 21:41:58 +00:00
										 |  |  | 	if (args.options) { | 
					
						
							| 
									
										
										
										
											2012-05-15 16:53:09 +00:00
										 |  |  | 		ast_app_parse_options(followme_opts, &targs->followmeflags, opt_args, args.options); | 
					
						
							| 
									
										
										
										
											2012-05-08 21:41:58 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2008-03-05 16:23:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-07-30 16:02:01 +00:00
										 |  |  | 	/* Lock the profile lock and copy out everything we need to run with before unlocking it again */ | 
					
						
							|  |  |  | 	ast_mutex_lock(&f->lock); | 
					
						
							| 
									
										
										
										
											2016-05-03 19:11:20 +03:00
										 |  |  | 	targs->enable_callee_prompt = f->enable_callee_prompt; | 
					
						
							| 
									
										
										
										
											2012-05-08 21:41:58 +00:00
										 |  |  | 	targs->mohclass = ast_strdupa(f->moh); | 
					
						
							|  |  |  | 	ast_copy_string(targs->context, f->context, sizeof(targs->context)); | 
					
						
							|  |  |  | 	ast_copy_string(targs->takecall, f->takecall, sizeof(targs->takecall)); | 
					
						
							|  |  |  | 	ast_copy_string(targs->nextindp, f->nextindp, sizeof(targs->nextindp)); | 
					
						
							|  |  |  | 	ast_copy_string(targs->callfromprompt, f->callfromprompt, sizeof(targs->callfromprompt)); | 
					
						
							|  |  |  | 	ast_copy_string(targs->norecordingprompt, f->norecordingprompt, sizeof(targs->norecordingprompt)); | 
					
						
							|  |  |  | 	ast_copy_string(targs->optionsprompt, f->optionsprompt, sizeof(targs->optionsprompt)); | 
					
						
							|  |  |  | 	ast_copy_string(targs->plsholdprompt, f->plsholdprompt, sizeof(targs->plsholdprompt)); | 
					
						
							|  |  |  | 	ast_copy_string(targs->statusprompt, f->statusprompt, sizeof(targs->statusprompt)); | 
					
						
							|  |  |  | 	ast_copy_string(targs->sorryprompt, f->sorryprompt, sizeof(targs->sorryprompt)); | 
					
						
							| 
									
										
										
										
											2017-12-27 18:44:31 -05:00
										 |  |  | 	ast_copy_string(targs->connprompt, f->connprompt, sizeof(targs->connprompt)); | 
					
						
							| 
									
										
										
										
											2017-12-22 09:23:22 -05:00
										 |  |  | 	/* Copy the numbers we're going to use into another list in case the master list should get modified
 | 
					
						
							| 
									
										
										
										
											2007-07-30 16:02:01 +00:00
										 |  |  | 	   (and locked) while we're trying to do a follow-me */ | 
					
						
							| 
									
										
										
										
											2012-05-08 21:41:58 +00:00
										 |  |  | 	AST_LIST_HEAD_INIT_NOLOCK(&targs->cnumbers); | 
					
						
							| 
									
										
										
										
											2007-07-30 16:02:01 +00:00
										 |  |  | 	AST_LIST_TRAVERSE(&f->numbers, nm, entry) { | 
					
						
							|  |  |  | 		newnm = create_followme_number(nm->number, nm->timeout, nm->order); | 
					
						
							| 
									
										
										
										
											2011-12-13 23:10:42 +00:00
										 |  |  | 		if (newnm) { | 
					
						
							| 
									
										
										
										
											2012-05-08 21:41:58 +00:00
										 |  |  | 			AST_LIST_INSERT_TAIL(&targs->cnumbers, newnm, entry); | 
					
						
							| 
									
										
										
										
											2011-12-13 23:10:42 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2007-07-30 16:02:01 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	ast_mutex_unlock(&f->lock); | 
					
						
							| 
									
										
										
										
											2008-03-05 16:23:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-15 16:53:09 +00:00
										 |  |  | 	/* PREDIAL: Preprocess any callee gosub arguments. */ | 
					
						
							|  |  |  | 	if (ast_test_flag(&targs->followmeflags, FOLLOWMEFLAG_PREDIAL_CALLEE) | 
					
						
							|  |  |  | 		&& !ast_strlen_zero(opt_args[FOLLOWMEFLAG_ARG_PREDIAL_CALLEE])) { | 
					
						
							|  |  |  | 		ast_replace_subargument_delimiter(opt_args[FOLLOWMEFLAG_ARG_PREDIAL_CALLEE]); | 
					
						
							| 
									
										
										
										
											2012-06-14 23:22:53 +00:00
										 |  |  | 		targs->predial_callee = | 
					
						
							|  |  |  | 			ast_app_expand_sub_args(chan, opt_args[FOLLOWMEFLAG_ARG_PREDIAL_CALLEE]); | 
					
						
							| 
									
										
										
										
											2012-05-15 16:53:09 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* PREDIAL: Run gosub on the caller's channel */ | 
					
						
							|  |  |  | 	if (ast_test_flag(&targs->followmeflags, FOLLOWMEFLAG_PREDIAL_CALLER) | 
					
						
							|  |  |  | 		&& !ast_strlen_zero(opt_args[FOLLOWMEFLAG_ARG_PREDIAL_CALLER])) { | 
					
						
							|  |  |  | 		ast_replace_subargument_delimiter(opt_args[FOLLOWMEFLAG_ARG_PREDIAL_CALLER]); | 
					
						
							| 
									
										
										
										
											2012-06-14 23:22:53 +00:00
										 |  |  | 		ast_app_exec_sub(NULL, chan, opt_args[FOLLOWMEFLAG_ARG_PREDIAL_CALLER], 0); | 
					
						
							| 
									
										
										
										
											2012-05-15 16:53:09 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-01-11 21:56:12 +00:00
										 |  |  | 	/* Forget the 'N' option if the call is already up. */ | 
					
						
							| 
									
										
										
										
											2012-02-20 23:43:27 +00:00
										 |  |  | 	if (ast_channel_state(chan) == AST_STATE_UP) { | 
					
						
							| 
									
										
										
										
											2012-05-08 21:41:58 +00:00
										 |  |  | 		ast_clear_flag(&targs->followmeflags, FOLLOWMEFLAG_NOANSWER); | 
					
						
							| 
									
										
										
										
											2012-01-11 21:56:12 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2011-01-26 23:41:55 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-08 21:41:58 +00:00
										 |  |  | 	if (ast_test_flag(&targs->followmeflags, FOLLOWMEFLAG_NOANSWER)) { | 
					
						
							| 
									
										
										
										
											2012-01-11 21:56:12 +00:00
										 |  |  | 		ast_indicate(chan, AST_CONTROL_RINGING); | 
					
						
							| 
									
										
										
										
											2011-01-26 23:41:55 +00:00
										 |  |  | 	} else { | 
					
						
							|  |  |  | 		/* Answer the call */ | 
					
						
							| 
									
										
										
										
											2012-02-20 23:43:27 +00:00
										 |  |  | 		if (ast_channel_state(chan) != AST_STATE_UP) { | 
					
						
							| 
									
										
										
										
											2011-01-26 23:41:55 +00:00
										 |  |  | 			ast_answer(chan); | 
					
						
							| 
									
										
										
										
											2012-01-11 21:56:12 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2011-01-26 23:41:55 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-08 21:41:58 +00:00
										 |  |  | 		if (ast_test_flag(&targs->followmeflags, FOLLOWMEFLAG_STATUSMSG)) { | 
					
						
							|  |  |  | 			ast_stream_and_wait(chan, targs->statusprompt, ""); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2011-01-26 23:41:55 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-08 21:41:58 +00:00
										 |  |  | 		if (ast_test_flag(&targs->followmeflags, FOLLOWMEFLAG_RECORDNAME)) { | 
					
						
							| 
									
										
										
										
											2012-01-11 21:56:12 +00:00
										 |  |  | 			int duration = 5; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-08 21:41:58 +00:00
										 |  |  | 			snprintf(targs->namerecloc, sizeof(targs->namerecloc), "%s/followme.%s", | 
					
						
							| 
									
										
										
										
											2012-01-24 20:12:09 +00:00
										 |  |  | 				ast_config_AST_SPOOL_DIR, ast_channel_uniqueid(chan)); | 
					
						
							| 
									
										
										
										
											2016-05-10 16:17:29 +03:00
										 |  |  | 			if (ast_play_and_record(chan, "vm-rec-name", targs->namerecloc, 5, REC_FORMAT, &duration, | 
					
						
							| 
									
										
										
										
											2012-01-11 21:56:12 +00:00
										 |  |  | 				NULL, ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE), 0, NULL) < 0) { | 
					
						
							| 
									
										
										
										
											2011-01-26 23:41:55 +00:00
										 |  |  | 				goto outrun; | 
					
						
							| 
									
										
										
										
											2012-01-11 21:56:12 +00:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2012-05-08 21:41:58 +00:00
										 |  |  | 			if (!ast_fileexists(targs->namerecloc, NULL, ast_channel_language(chan))) { | 
					
						
							|  |  |  | 				targs->namerecloc[0] = '\0'; | 
					
						
							| 
									
										
										
										
											2012-01-11 21:56:12 +00:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2011-01-26 23:41:55 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-08 21:41:58 +00:00
										 |  |  | 		if (!ast_test_flag(&targs->followmeflags, FOLLOWMEFLAG_DISABLEHOLDPROMPT)) { | 
					
						
							|  |  |  | 			if (ast_streamfile(chan, targs->plsholdprompt, ast_channel_language(chan))) { | 
					
						
							| 
									
										
										
										
											2011-01-26 23:41:55 +00:00
										 |  |  | 				goto outrun; | 
					
						
							| 
									
										
										
										
											2012-05-08 21:41:58 +00:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2011-01-26 23:41:55 +00:00
										 |  |  | 			if (ast_waitstream(chan, "") < 0) | 
					
						
							|  |  |  | 				goto outrun; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2013-08-22 23:15:14 +00:00
										 |  |  | 		ast_moh_start(chan, targs->mohclass, NULL); | 
					
						
							| 
									
										
										
										
											2009-11-23 22:37:39 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2008-03-05 16:23:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-01-11 21:56:12 +00:00
										 |  |  | 	ast_channel_lock(chan); | 
					
						
							| 
									
										
										
										
											2012-05-08 21:41:58 +00:00
										 |  |  | 	ast_connected_line_copy_from_caller(&targs->connected_in, ast_channel_caller(chan)); | 
					
						
							| 
									
										
										
										
											2012-01-11 21:56:12 +00:00
										 |  |  | 	ast_channel_unlock(chan); | 
					
						
							| 
									
										
										
										
											2008-03-05 16:23:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-08 21:41:58 +00:00
										 |  |  | 	outbound = findmeexec(targs, chan); | 
					
						
							| 
									
										
										
										
											2012-05-08 21:15:58 +00:00
										 |  |  | 	if (!outbound) { | 
					
						
							| 
									
										
										
										
											2012-05-08 21:41:58 +00:00
										 |  |  | 		if (ast_test_flag(&targs->followmeflags, FOLLOWMEFLAG_NOANSWER)) { | 
					
						
							| 
									
										
										
										
											2012-02-20 23:43:27 +00:00
										 |  |  | 			if (ast_channel_state(chan) != AST_STATE_UP) { | 
					
						
							| 
									
										
										
										
											2012-01-11 21:56:12 +00:00
										 |  |  | 				ast_answer(chan); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			ast_moh_stop(chan); | 
					
						
							| 
									
										
										
										
											2011-01-26 23:41:55 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-08 21:41:58 +00:00
										 |  |  | 		if (ast_test_flag(&targs->followmeflags, FOLLOWMEFLAG_UNREACHABLEMSG)) { | 
					
						
							|  |  |  | 			ast_stream_and_wait(chan, targs->sorryprompt, ""); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2007-07-30 16:02:01 +00:00
										 |  |  | 		res = 0; | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		caller = chan; | 
					
						
							| 
									
										
										
										
											2017-12-27 18:44:31 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		/* Play "connecting" message to the winner, if configured. */ | 
					
						
							|  |  |  | 		if (!ast_strlen_zero(targs->connprompt)) { | 
					
						
							|  |  |  | 			ast_autoservice_start(caller); | 
					
						
							|  |  |  | 			ast_stream_and_wait(outbound, targs->connprompt, ""); | 
					
						
							|  |  |  | 			ast_autoservice_stop(caller); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-07-30 16:02:01 +00:00
										 |  |  | 		/* Bridge the two channels. */ | 
					
						
							| 
									
										
										
										
											2008-03-05 16:23:44 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		memset(&config, 0, sizeof(config)); | 
					
						
							| 
									
										
										
										
											2007-07-30 16:02:01 +00:00
										 |  |  | 		ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT); | 
					
						
							|  |  |  | 		ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMON); | 
					
						
							|  |  |  | 		ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMON); | 
					
						
							| 
									
										
										
										
											2008-10-31 18:55:33 +00:00
										 |  |  | 		config.end_bridge_callback = end_bridge_callback; | 
					
						
							| 
									
										
										
										
											2008-11-09 01:27:00 +00:00
										 |  |  | 		config.end_bridge_callback_data = chan; | 
					
						
							| 
									
										
										
										
											2008-11-18 18:31:08 +00:00
										 |  |  | 		config.end_bridge_callback_data_fixup = end_bridge_callback_data_fixup; | 
					
						
							| 
									
										
										
										
											2008-03-05 16:23:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-01-11 21:56:12 +00:00
										 |  |  | 		/* Update connected line to caller if available. */ | 
					
						
							| 
									
										
										
										
											2012-05-08 21:41:58 +00:00
										 |  |  | 		if (targs->pending_out_connected_update) { | 
					
						
							|  |  |  | 			if (ast_channel_connected_line_sub(outbound, caller, &targs->connected_out, 0) && | 
					
						
							|  |  |  | 				ast_channel_connected_line_macro(outbound, caller, &targs->connected_out, 1, 0)) { | 
					
						
							|  |  |  | 				ast_channel_update_connected_line(caller, &targs->connected_out, NULL); | 
					
						
							| 
									
										
										
										
											2012-01-11 21:56:12 +00:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-08 21:41:58 +00:00
										 |  |  | 		if (ast_test_flag(&targs->followmeflags, FOLLOWMEFLAG_NOANSWER)) { | 
					
						
							| 
									
										
										
										
											2012-02-20 23:43:27 +00:00
										 |  |  | 			if (ast_channel_state(caller) != AST_STATE_UP) { | 
					
						
							| 
									
										
										
										
											2012-01-11 21:56:12 +00:00
										 |  |  | 				ast_answer(caller); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			ast_moh_stop(caller); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-07-30 16:02:01 +00:00
										 |  |  | 		/* Be sure no generators are left on it */ | 
					
						
							|  |  |  | 		ast_deactivate_generator(caller); | 
					
						
							|  |  |  | 		/* Make sure channels are compatible */ | 
					
						
							|  |  |  | 		res = ast_channel_make_compatible(caller, outbound); | 
					
						
							|  |  |  | 		if (res < 0) { | 
					
						
							| 
									
										
										
										
											2012-01-09 22:15:50 +00:00
										 |  |  | 			ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", ast_channel_name(caller), ast_channel_name(outbound)); | 
					
						
							| 
									
										
										
										
											2012-06-29 17:02:32 +00:00
										 |  |  | 			ast_autoservice_chan_hangup_peer(caller, outbound); | 
					
						
							| 
									
										
										
										
											2007-07-30 16:02:01 +00:00
										 |  |  | 			goto outrun; | 
					
						
							| 
									
										
										
										
											2006-09-05 20:36:27 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2012-01-11 21:56:12 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		/* Update connected line to winner if changed. */ | 
					
						
							| 
									
										
										
										
											2012-05-08 21:41:58 +00:00
										 |  |  | 		if (targs->pending_in_connected_update) { | 
					
						
							|  |  |  | 			if (ast_channel_connected_line_sub(caller, outbound, &targs->connected_in, 0) && | 
					
						
							|  |  |  | 				ast_channel_connected_line_macro(caller, outbound, &targs->connected_in, 0, 0)) { | 
					
						
							|  |  |  | 				ast_channel_update_connected_line(outbound, &targs->connected_in, NULL); | 
					
						
							| 
									
										
										
										
											2012-01-11 21:56:12 +00:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-09 01:59:14 +00:00
										 |  |  | 		/* Put winner on hold if caller requested. */ | 
					
						
							|  |  |  | 		if (targs->pending_hold) { | 
					
						
							|  |  |  | 			if (ast_strlen_zero(targs->suggested_moh)) { | 
					
						
							|  |  |  | 				ast_indicate_data(outbound, AST_CONTROL_HOLD, NULL, 0); | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				ast_indicate_data(outbound, AST_CONTROL_HOLD, | 
					
						
							|  |  |  | 					targs->suggested_moh, strlen(targs->suggested_moh) + 1); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-03-05 16:23:44 +00:00
										 |  |  | 		res = ast_bridge_call(caller, outbound, &config); | 
					
						
							| 
									
										
										
										
											2006-09-05 20:36:27 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2007-07-30 16:02:01 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-12-13 23:10:42 +00:00
										 |  |  | outrun: | 
					
						
							| 
									
										
										
										
											2012-05-08 21:41:58 +00:00
										 |  |  | 	while ((nm = AST_LIST_REMOVE_HEAD(&targs->cnumbers, entry))) { | 
					
						
							| 
									
										
										
										
											2012-05-08 20:32:11 +00:00
										 |  |  | 		ast_free(nm); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2012-05-08 21:41:58 +00:00
										 |  |  | 	if (!ast_strlen_zero(targs->namerecloc)) { | 
					
						
							| 
									
										
										
										
											2016-05-10 16:17:29 +03:00
										 |  |  | 		int ret; | 
					
						
							| 
									
										
										
										
											2017-07-27 21:58:22 -04:00
										 |  |  | 		char fn[PATH_MAX + sizeof(REC_FORMAT)]; | 
					
						
							| 
									
										
										
										
											2016-05-10 16:17:29 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		snprintf(fn, sizeof(fn), "%s.%s", targs->namerecloc, | 
					
						
							|  |  |  | 			     REC_FORMAT); | 
					
						
							|  |  |  | 		ret = unlink(fn); | 
					
						
							|  |  |  | 		if (ret != 0) { | 
					
						
							|  |  |  | 			ast_log(LOG_NOTICE, "Failed to delete recorded name file %s: %d (%s)\n", | 
					
						
							|  |  |  | 					fn, errno, strerror(errno)); | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			ast_debug(2, "deleted recorded prompt %s.\n", fn); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2012-05-08 20:32:11 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2012-06-14 23:22:53 +00:00
										 |  |  | 	ast_free((char *) targs->predial_callee); | 
					
						
							| 
									
										
										
										
											2012-05-08 21:41:58 +00:00
										 |  |  | 	ast_party_connected_line_free(&targs->connected_in); | 
					
						
							|  |  |  | 	ast_party_connected_line_free(&targs->connected_out); | 
					
						
							|  |  |  | 	ast_free(targs); | 
					
						
							| 
									
										
										
										
											2012-05-08 20:32:11 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-08-25 16:02:56 +00:00
										 |  |  | 	if (f->realtime) { | 
					
						
							|  |  |  | 		/* Not in list */ | 
					
						
							|  |  |  | 		free_numbers(f); | 
					
						
							|  |  |  | 		ast_free(f); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 	return res; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | static int unload_module(void) | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2006-09-05 20:36:27 +00:00
										 |  |  | 	struct call_followme *f; | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-06-06 20:44:50 +00:00
										 |  |  | 	ast_unregister_application(app); | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 	/* Free Memory. Yeah! I'm free! */ | 
					
						
							| 
									
										
										
										
											2007-07-30 16:02:01 +00:00
										 |  |  | 	AST_RWLIST_WRLOCK(&followmes); | 
					
						
							|  |  |  | 	while ((f = AST_RWLIST_REMOVE_HEAD(&followmes, entry))) { | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 		free_numbers(f); | 
					
						
							| 
									
										
										
										
											2007-06-06 21:20:11 +00:00
										 |  |  | 		ast_free(f); | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-07-30 16:02:01 +00:00
										 |  |  | 	AST_RWLIST_UNLOCK(&followmes); | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-06-06 20:44:50 +00:00
										 |  |  | 	return 0; | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-01 23:22:50 +00:00
										 |  |  | /*!
 | 
					
						
							|  |  |  |  * \brief Load the module | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Module loading including tests for configuration or dependencies. | 
					
						
							|  |  |  |  * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE, | 
					
						
							|  |  |  |  * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails | 
					
						
							| 
									
										
										
										
											2017-12-22 09:23:22 -05:00
										 |  |  |  * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the | 
					
						
							|  |  |  |  * configuration file or other non-critical problem return | 
					
						
							| 
									
										
										
										
											2012-10-01 23:22:50 +00:00
										 |  |  |  * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | static int load_module(void) | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2007-08-16 21:09:46 +00:00
										 |  |  | 	if(!reload_followme(0)) | 
					
						
							| 
									
										
										
										
											2006-08-31 21:00:20 +00:00
										 |  |  | 		return AST_MODULE_LOAD_DECLINE; | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-11-05 02:08:39 +00:00
										 |  |  | 	return ast_register_application_xml(app, app_exec); | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | static int reload(void) | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2007-08-16 21:09:46 +00:00
										 |  |  | 	reload_followme(1); | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-03-05 16:23:44 +00:00
										 |  |  | 	return 0; | 
					
						
							| 
									
										
										
										
											2006-06-06 07:29:57 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Find-Me/Follow-Me Application", | 
					
						
							| 
									
										
										
										
											2015-05-05 20:49:04 -04:00
										 |  |  | 	.support_level = AST_MODULE_SUPPORT_CORE, | 
					
						
							|  |  |  | 	.load = load_module, | 
					
						
							|  |  |  | 	.unload = unload_module, | 
					
						
							|  |  |  | 	.reload = reload, | 
					
						
							|  |  |  | ); |