[asterisk-commits] rmudgett: branch rmudgett/bridge_phase r392215 - in /team/rmudgett/bridge_pha...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Tue Jun 18 21:07:00 CDT 2013


Author: rmudgett
Date: Tue Jun 18 21:06:58 2013
New Revision: 392215

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=392215
Log:
* Add initial AgentLogin and AgentRequest code and documentation.

* Removed password and max_login_tries since AgentLogin will no longer
perform any agent authentication.  The dialplan must now do this.

* Deferred agent_hold bridge creation till AgentLogin or AgentRequest is
first called.  Creating the holding bridge on module load is too early for
the holding bridge technology to be loaded yet.

Modified:
    team/rmudgett/bridge_phase/CHANGES
    team/rmudgett/bridge_phase/UPGRADE.txt
    team/rmudgett/bridge_phase/apps/app_agent_pool.c
    team/rmudgett/bridge_phase/configs/agents.conf.sample

Modified: team/rmudgett/bridge_phase/CHANGES
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/bridge_phase/CHANGES?view=diff&rev=392215&r1=392214&r2=392215
==============================================================================
--- team/rmudgett/bridge_phase/CHANGES (original)
+++ team/rmudgett/bridge_phase/CHANGES Tue Jun 18 21:06:58 2013
@@ -14,6 +14,13 @@
 Applications
 ------------------
 
+AgentLogin
+------------------
+ * The application no longer does agent authentication.  The dialplan needs to
+   perform this function before running AgentLogin.  If the agent is already
+   logged in, dialplan will continue with the AGENT_STATUS channel variable
+   set to ALREADY_LOGGED_IN.
+
 AgentMonitorOutgoing
 ------------------
  * The 'c' option has been removed. It is not possible to modify the name of a
@@ -382,6 +389,12 @@
    reason as the updatecdr option.
  * The driver is no longer a Data retrieval API data provider for the
    AMI DataGet action.
+ * The endcall and enddtmf configuration options are removed.  Use the
+   dialplan function CHANNEL(dtmf-features) to set DTMF features on the agent
+   channel before calling AgentLogin.
+ * chan_agent is removed and replaced with AgentLogin and AgentRequest dialplan
+   applications.  Agents are connected with callers using the new AgentRequest
+   dialplan application.  See agents.conf.sample for valid configuration options.
 
 chan_local
 ------------------

Modified: team/rmudgett/bridge_phase/UPGRADE.txt
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/bridge_phase/UPGRADE.txt?view=diff&rev=392215&r1=392214&r2=392215
==============================================================================
--- team/rmudgett/bridge_phase/UPGRADE.txt (original)
+++ team/rmudgett/bridge_phase/UPGRADE.txt Tue Jun 18 21:06:58 2013
@@ -24,6 +24,8 @@
 AgentMonitorOutgoing
  - The 'c' option has been removed. It is not possible to modify the name of a
    channel involved in a CDR.
+ - Application removed.  It was a holdover from when AgentCallbackLogin was
+   removed.
 
 NoCDR:
  - This application is deprecated. Please use the CDR_PROP function instead.
@@ -124,6 +126,9 @@
    and pretending otherwise helps no one.
  - The AGENTUPDATECDR channel variable has also been removed, for the same
    reason as the updatecdr option.
+ - chan_agent is removed and replaced with AgentLogin and AgentRequest dialplan
+   applications.  Agents are connected with callers using the new AgentRequest
+   dialplan application.  See agents.conf.sample for valid configuration options.
 
 chan_dahdi:
  - Analog port dialing and deferred DTMF dialing for PRI now distinguishes

Modified: team/rmudgett/bridge_phase/apps/app_agent_pool.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/bridge_phase/apps/app_agent_pool.c?view=diff&rev=392215&r1=392214&r2=392215
==============================================================================
--- team/rmudgett/bridge_phase/apps/app_agent_pool.c (original)
+++ team/rmudgett/bridge_phase/apps/app_agent_pool.c Tue Jun 18 21:06:58 2013
@@ -51,37 +51,65 @@
 /*** DOCUMENTATION
 	<application name="AgentLogin" language="en_US">
 		<synopsis>
-			Call agent login.
+			Login an agent.
 		</synopsis>
-		<syntax>
-			<parameter name="AgentId">
-				<para>
-	 				If not present the agent is prompted for an identifier.
-	 			</para>
-			</parameter>
+		<syntax argsep=",">
+			<parameter name="AgentId" required="true" />
 			<parameter name="options">
 				<optionlist>
 					<option name="s">
 						<para>silent login - do not announce the login ok segment after
-						agent logged on/off</para>
+						agent logged on.</para>
 					</option>
 				</optionlist>
 			</parameter>
 		</syntax>
 		<description>
-			<para>Login an agent to the system.  Always returns <literal>-1</literal>.
+			<para>Login an agent to the system.  Any agent authentication is assumed to
+			already be done by dialplan.  If the agent is already logged in, the
+			application will continue in the dialplan with <variable>AGENT_STATUS</variable>
+ 			set to <literal>ALREADY_LOGGED_IN</literal>.
 			While logged in, the agent can receive calls and will hear a <literal>beep</literal>
 			when a new call comes in.</para>
 		</description>
 		<see-also>
+			<ref type="application">Authenticate</ref>
 			<ref type="application">Queue</ref>
 			<ref type="application">AddQueueMember</ref>
 			<ref type="application">RemoveQueueMember</ref>
 			<ref type="application">PauseQueueMember</ref>
 			<ref type="application">UnpauseQueueMember</ref>
 			<ref type="function">AGENT</ref>
+			<ref type="function">CHANNEL(dtmf-features)</ref>
 			<ref type="filename">agents.conf</ref>
 			<ref type="filename">queues.conf</ref>
+		</see-also>
+	</application>
+	<application name="AgentRequest" language="en_US">
+		<synopsis>
+			Request an agent to connect with the channel.
+		</synopsis>
+		<syntax argsep=",">
+			<parameter name="Locator" required="true">
+				<para>The value can be:</para>
+				<para>1) A specific agent id.</para>
+				<para>2) Use @<replaceable>group-id</replaceable> to locate an available
+					agent in a group.</para>
+				<para>3) Use :<replaceable>group-id</replaceable> to locate an available
+					agent in a group or wait for one to become available.</para>
+			</parameter>
+			<parameter name="timeout">
+				<para>Specifies the number of seconds to wait for an available agent.</para>
+			</parameter>
+		</syntax>
+		<description>
+			<para>
+				Request a specific agent or an agent from a group to connect
+				with the channel.
+			</para>
+		</description>
+		<see-also>
+			<ref type="application">AgentLogin</ref>
 		</see-also>
 	</application>
 	<function name="AGENT" language="en_US">
@@ -89,7 +117,7 @@
 			Gets information about an Agent
 		</synopsis>
 		<syntax argsep=":">
-			<parameter name="agentid" required="true" />
+			<parameter name="AgentId" required="true" />
 			<parameter name="item">
 				<para>The valid items to retrieve are:</para>
 				<enumlist>
@@ -97,7 +125,7 @@
 						<para>(default) The status of the agent (LOGGEDIN | LOGGEDOUT)</para>
 					</enum>
 					<enum name="password">
-						<para>The password of the agent</para>
+						<para>Deprecated.  The dialplan handles any agent authentication.</para>
 					</enum>
 					<enum name="name">
 						<para>The name of the agent</para>
@@ -150,15 +178,14 @@
 
 #define AST_MAX_BUF	256
 
-/* BUGBUG Document in CHANGES that endcall and enddtmf are going away in favor of the normal bridge disconnect feature.  Override using FEATUREMAP. */
+static const char app_agent_login[] = "AgentLogin";
+static const char app_agent_request[] = "AgentRequest";
 
 /*! Agent config parameters. */
 struct agent_cfg {
 	AST_DECLARE_STRING_FIELDS(
 		/*! Identification of the agent.  (agents config container key) */
 		AST_STRING_FIELD(username);
-		/*! Password the agent needs when logging in. */
-		AST_STRING_FIELD(password);
 		/*! Name of agent for logging and querying purposes */
 		AST_STRING_FIELD(full_name);
 
@@ -179,13 +206,6 @@
 	);
 	/*! Agent groups an agent belongs to. */
 	ast_group_t group;
-	/*!
-	 * \brief Number of failed login attempts allowed.
-	 *
-	 * \note The channel variable AGENTLMAXLOGINTRIES overrides on login.
-	 * \note If zero then unlimited attempts.
-	 */
-	unsigned int max_login_tries;
 	/*!
 	 * \brief Number of seconds for agent to ack a call before being logged off.
 	 *
@@ -323,7 +343,6 @@
  * [user] <- agent-id/username
  * hasagent = yes/no
  * fullname=name
- * secret=password
  *
  *static struct aco_file users_conf = {
  *	.filename = "users.conf",
@@ -371,6 +390,10 @@
 	}
 	cfg->agents = ao2_container_alloc_rbtree(AO2_ALLOC_OPT_LOCK_NOLOCK,
 		AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT, agent_cfg_sort_cmp, NULL);
+	if (!cfg->agents) {
+		ao2_ref(cfg, -1);
+		cfg = NULL;
+	}
 	return cfg;
 }
 
@@ -472,7 +495,6 @@
 	}
 
 	/* Agent options */
-	aco_option_register(&cfg_info, "maxlogintries", ACO_EXACT, agent_types, "3", OPT_UINT_T, 0, FLDSET(struct agent_cfg, max_login_tries));
 	aco_option_register(&cfg_info, "autologoff", ACO_EXACT, agent_types, "0", OPT_UINT_T, 0, FLDSET(struct agent_cfg, auto_logoff));
 	aco_option_register(&cfg_info, "ackcall", ACO_EXACT, agent_types, "no", OPT_BOOL_T, 1, FLDSET(struct agent_cfg, ack_call));
 	aco_option_register(&cfg_info, "acceptdtmf", ACO_EXACT, agent_types, "#", OPT_STRINGFIELD_T, 0, STRFLDSET(struct agent_cfg, dtmf_accept));
@@ -483,7 +505,6 @@
 	aco_option_register(&cfg_info, "recordformat", ACO_EXACT, agent_types, "wav", OPT_STRINGFIELD_T, 0, STRFLDSET(struct agent_cfg, record_format));
 	aco_option_register_custom(&cfg_info, "savecallsin", ACO_EXACT, agent_types, "", agent_savecallsin_handler, 0);
 	aco_option_register_custom(&cfg_info, "custom_beep", ACO_EXACT, agent_types, "beep", agent_custom_beep_handler, 0);
-	aco_option_register(&cfg_info, "password", ACO_EXACT, agent_types, "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct agent_cfg, password));
 	aco_option_register(&cfg_info, "fullname", ACO_EXACT, agent_types, "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct agent_cfg, full_name));
 
 	/*! \todo BUGBUG load_config() needs users.conf handling. */
@@ -803,6 +824,15 @@
 		if (agent) {
 			agent_lock(agent);
 			agent->the_mark = 0;
+			if (!agent->logged) {
+				struct agent_cfg *cfg_old;
+
+				/* Replace the config of agents not logged in. */
+				cfg_old = agent->cfg;
+				ao2_ref(cfg, +1);
+				agent->cfg = cfg;
+				ao2_cleanup(cfg_old);
+			}
 			agent_unlock(agent);
 			continue;
 		}
@@ -843,6 +873,9 @@
 /*! Agent holding bridge instance. */
 static struct ast_bridge *agent_holding;
 
+/*! Agent holding bridge deferred creation lock. */
+AST_MUTEX_DEFINE_STATIC(agent_holding_lock);
+
 static int bridge_agent_hold_ack(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt)
 {
 	/*! \todo BUGBUG bridge_agent_hold_ack() not written */
@@ -966,6 +999,110 @@
 	bridge_agent_hold_v_table.push = bridge_agent_hold_push;
 }
 
+static int bridge_agent_hold_deferred_create(void)
+{
+	if (!agent_holding) {
+		ast_mutex_lock(&agent_holding_lock);
+		if (!agent_holding) {
+			agent_holding = bridge_agent_hold_new();
+		}
+		ast_mutex_unlock(&agent_holding_lock);
+		if (!agent_holding) {
+			ast_log(LOG_ERROR, "Could not create agent holding bridge.\n");
+			return -1;
+		}
+	}
+	return 0;
+}
+
+/*!
+ * Called by the AgentRequest application (from the dial plan).
+ *
+ * \brief Application to locate an agent to talk with.
+ *
+ * \param chan Channel wanting to talk with an agent.
+ * \param data Application parameters
+ *
+ * \retval 0 To continue in dialplan.
+ * \retval -1 To hangup.
+ */
+static int agent_request_exec(struct ast_channel *chan, const char *data)
+{
+	if (bridge_agent_hold_deferred_create()) {
+		return -1;
+	}
+
+	/*! \todo BUGBUG agent_request_exec() not written */
+	return -1;
+}
+
+enum AGENT_LOGIN_OPT_FLAGS {
+	OPT_SILENT = (1 << 0),
+};
+AST_APP_OPTIONS(agent_login_opts, BEGIN_OPTIONS
+	AST_APP_OPTION('s', OPT_SILENT),
+END_OPTIONS);
+
+/*!
+ * Called by the AgentLogin application (from the dial plan).
+ *
+ * \brief Application to log in an agent.
+ *
+ * \param chan Channel attempting to login as an agent.
+ * \param data Application parameters
+ *
+ * \retval 0 To continue in dialplan.
+ * \retval -1 To hangup.
+ */
+static int agent_login_exec(struct ast_channel *chan, const char *data)
+{
+	char *parse;
+	struct ast_flags opts;
+	AST_DECLARE_APP_ARGS(args,
+		AST_APP_ARG(agent_id);
+		AST_APP_ARG(options);
+		AST_APP_ARG(other);		/* Any remaining unused arguments */
+	);
+
+	RAII_VAR(struct agent_pvt *, agent, NULL, ao2_cleanup);
+
+	if (bridge_agent_hold_deferred_create()) {
+		return -1;
+	}
+
+	if (ast_channel_state(chan) != AST_STATE_UP && ast_answer(chan)) {
+		return -1;
+	}
+
+	parse = ast_strdupa(data ?: "");
+	AST_STANDARD_APP_ARGS(args, parse);
+
+	if (ast_strlen_zero(args.agent_id)) {
+		ast_log(LOG_WARNING, "AgentLogin requires an AgentId\n");
+		return -1;
+	}
+
+	if (ast_app_parse_options(agent_login_opts, &opts, NULL, args.options)) {
+		/* General invalid option syntax. */
+		return -1;
+	}
+
+	/* Find the agent. */
+	agent = ao2_find(agents, args.agent_id, OBJ_KEY);
+	if (!agent) {
+		ast_verb(3, "Agent '%s' does not exist.\n", args.agent_id);
+		pbx_builtin_setvar_helper(chan, "AGENT_STATUS", "UNKNOWN_AGENT");
+		return 0;
+	}
+
+
+
+
+
+	/*! \todo BUGBUG agent_login_exec() not written */
+	return -1;
+}
+
 static int agent_function_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 {
 	char *parse;
@@ -978,14 +1115,13 @@
 
 	buf[0] = '\0';
 
-	if (ast_strlen_zero(data)) {
+	parse = ast_strdupa(data ?: "");
+	AST_NONSTANDARD_APP_ARGS(args, parse, ':');
+
+	if (ast_strlen_zero(args.agentid)) {
 		ast_log(LOG_WARNING, "The AGENT function requires an argument - agentid!\n");
 		return -1;
 	}
-
-	parse = ast_strdupa(data);
-
-	AST_NONSTANDARD_APP_ARGS(args, parse, ':');
 	if (!args.item) {
 		args.item = "status";
 	}
@@ -1006,8 +1142,6 @@
 			status = "LOGGEDOUT";
 		}
 		ast_copy_string(buf, status, len);
-	} else if (!strcasecmp(args.item, "password")) {
-		ast_copy_string(buf, agent->cfg->password, len);
 	} else if (!strcasecmp(args.item, "name")) {
 		ast_copy_string(buf, agent->cfg->full_name, len);
 	} else if (!strcasecmp(args.item, "mohclass")) {
@@ -1418,6 +1552,10 @@
 
 static int unload_module(void)
 {
+	/* Unregister dialplan applications */
+	ast_unregister_application(app_agent_login);
+	ast_unregister_application(app_agent_request);
+
 	/* Unregister dialplan functions */
 	ast_custom_function_unregister(&agent_function);
 
@@ -1458,13 +1596,8 @@
 		return AST_MODULE_LOAD_DECLINE;
 	}
 
-	/* Create agent holding bridge. */
+	/* Init agent holding bridge v_table. */
 	bridging_init_agent_hold();
-	agent_holding = bridge_agent_hold_new();
-	if (!agent_holding) {
-		unload_module();
-		return AST_MODULE_LOAD_FAILURE;
-	}
 
 /* BUGBUG Agent:agent-id device state not written. */
 	/* Setup to provide Agent:agent-id device state. */
@@ -1480,9 +1613,11 @@
 	/* Dialplan Functions */
 	res |= ast_custom_function_register(&agent_function);
 
+	/* Dialplan applications */
+	res |= ast_register_application_xml(app_agent_login, agent_login_exec);
+	res |= ast_register_application_xml(app_agent_request, agent_request_exec);
+
 /* BUGBUG bridge channel swap hook not written. */
-/* BUGBUG AgentLogin dialplan application not written. */
-/* BUGBUG AgentRequest dialplan application not written. */
 
 	if (res) {
 		unload_module();

Modified: team/rmudgett/bridge_phase/configs/agents.conf.sample
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/bridge_phase/configs/agents.conf.sample?view=diff&rev=392215&r1=392214&r2=392215
==============================================================================
--- team/rmudgett/bridge_phase/configs/agents.conf.sample (original)
+++ team/rmudgett/bridge_phase/configs/agents.conf.sample Tue Jun 18 21:06:58 2013
@@ -7,25 +7,12 @@
 ; for future use.
 
 ;[agent-id]
-;
-; Define maxlogintries to allow the agent to try max logins before failed.
-; The channel variable AGENTLMAXLOGINTRIES overrides on login.
-; Default is 3.
-;maxlogintries=5
-;
 ; Set how long a call for the agent has to wait for the agent to acknowledge
 ; the call before the agent is automatically logged off (in seconds).
 ; If set to zero then the call will wait forever for the agent to acknowledge.
 ; The channel variable AGENTAUTOLOGOFF overrides on login.
 ; Default is 0.
 ;autologoff=15
-;
-;BUGBUG the following is going away: autologoffunavail
-; Define autologoffunavail to have agents automatically logged
-; out when the extension that they are at returns a CHANUNAVAIL
-; status when a call is attempted to be sent there.
-; Default is "no".
-;autologoffunavail=yes
 ;
 ; Define ackcall to require the agent to give a DTMF acknowledgement
 ; when the agent receives a call.
@@ -38,17 +25,6 @@
 ; Default is "#".
 ;acceptdtmf=#
 ;
-;BUGBUG endcall and enddtmf need to go away in favor of the normal bridge disconnect feature.
-; Define endcall to allow the agent to hangup a call with a DTMF key
-; sequence.
-; Default is "yes".
-;endcall=yes
-;
-; Set what DTMF key sequence the agent should use to end a call.
-; The channel variable AGENTENDDTMF overrides on login.
-; Default is "*".
-;enddtmf=*
-;
 ; Set the minimum amount of time after disconnecting a call before
 ; the agent can receive a new call in milliseconds.
 ; The channel variable AGENTWRAPUPTIME overrides on login.
@@ -58,17 +34,6 @@
 ; Set the musiconhold class for the agent.
 ; Default is "default".
 ;musiconhold=default
-;
-;BUGBUG the following is going away: goodbye
-; Define the default good bye sound file for agents
-; default to vm-goodbye
-;goodbye => goodbye_file
-;
-;BUGBUG the following is going away: updatecdr
-; Define updatecdr. This is whether or not to change the source
-; channel in the CDR record for this call to agent/agent_id so
-; that we know which agent generates the call
-;updatecdr=no
 ;
 ; Set the agent groups this agent belongs to.
 ; Default is "".
@@ -84,10 +49,6 @@
 ; Default is "wav".
 ;recordformat=gsm
 ;
-;BUGBUG the following is going away: urlprefix
-; The text to be added to the name of the recording. Allows forming a url link.
-;urlprefix=http://localhost/calls/
-;
 ; Set the absolute directory to save the agent's conversations in.
 ; Default is "".
 ; An empty string becomes asterisk.conf's astspooldir/monitor
@@ -97,10 +58,6 @@
 ; A custom beep sound file to play to the agent.
 ; Default is "beep".
 ;custom_beep=beep
-;
-; Set the password the agent uses to login.
-; Default is "".
-;password=1234
 ;
 ; Set the agent name used in logging messages.
 ; Default is "".
@@ -112,19 +69,14 @@
 ;
 ; Define a template called my-agents:
 ;[my-agents](!)
-;maxlogintries=5
 ;autologoff=15
 ;ackcall=yes
 ;acceptdtmf=##
-;endcall=yes
-;enddtmf=**
 ;
 ; Define agent 1001 using the my-agents template:
 ;[1001](my-agents)
-;password=1234
 ;fullname=Mark Spencer
 ;
 ; Define agent 1002 using the my-agents template:
 ;[1002](my-agents)
-;password=4321
 ;fullname=Will Meadows




More information about the asterisk-commits mailing list