[asterisk-commits] branch bweschke/polycom_acd_functions - r7723 in /team/bweschke/polycom_acd_f...

asterisk-commits at lists.digium.com asterisk-commits at lists.digium.com
Mon Jan 2 16:27:46 CST 2006


Author: bweschke
Date: Mon Jan  2 16:27:44 2006
New Revision: 7723

URL: http://svn.digium.com/view/asterisk?rev=7723&view=rev
Log:
 Initial Agent/ACD Login/Logout Functionality Integration


Added:
    team/bweschke/polycom_acd_functions/include/asterisk/agents.h
Modified:
    team/bweschke/polycom_acd_functions/channels/chan_agent.c
    team/bweschke/polycom_acd_functions/channels/chan_sip.c

Modified: team/bweschke/polycom_acd_functions/channels/chan_agent.c
URL: http://svn.digium.com/view/asterisk/team/bweschke/polycom_acd_functions/channels/chan_agent.c?rev=7723&r1=7722&r2=7723&view=diff
==============================================================================
--- team/bweschke/polycom_acd_functions/channels/chan_agent.c (original)
+++ team/bweschke/polycom_acd_functions/channels/chan_agent.c Mon Jan  2 16:27:44 2006
@@ -2138,32 +2138,20 @@
 }
 
 /**
- * Sets an agent as logged in by callback in the Manager API.
- * It is registered on load_module() and it gets called by the manager backend.
- * @param s
- * @param m
- * @returns 
- * @sa action_agents(), action_agent_logoff(), load_module().
+ *  Called by the action_agent_callback_login function and possibly externally.
+ * 
+ * @param agent
+ * @param exten
+ * @param context
+ * @param wrapuptime
+ * @param ackcall
+ * @returns
+ * @sa action_agent_callback_login(), load_module()
  */
-static int action_agent_callback_login(struct mansession *s, struct message *m)
-{
-	char *agent = astman_get_header(m, "Agent");
-	char *exten = astman_get_header(m, "Exten");
-	char *context = astman_get_header(m, "Context");
-	char *wrapuptime_s = astman_get_header(m, "WrapupTime");
-	char *ackcall_s = astman_get_header(m, "AckCall");
-	struct agent_pvt *p;
+static int agent_callback_login(char *agent, char *exten, char *context, char *wrapuptime, char *ackcall)
+{
+	struct agent_pvt *p = NULL;
 	int login_state = 0;
-
-	if (ast_strlen_zero(agent)) {
-		astman_send_error(s, m, "No agent specified");
-		return 0;
-	}
-
-	if (ast_strlen_zero(exten)) {
-		astman_send_error(s, m, "No extension specified");
-		return 0;
-	}
 
 	ast_mutex_lock(&agentlock);
 	p = agents;
@@ -2184,13 +2172,14 @@
 		else
 			snprintf(p->loginchan, sizeof(p->loginchan), "%s@%s", exten, context);
 
-		if (!ast_strlen_zero(wrapuptime_s)) {
-			p->wrapuptime = atoi(wrapuptime_s);
+		if (!ast_strlen_zero(wrapuptime)) {
+			p->wrapuptime = atoi(wrapuptime);
 			if (p->wrapuptime < 0)
 				p->wrapuptime = 0;
-		}
-
-		if (ast_true(ackcall_s))
+		} else
+			p->wrapuptime = 0;
+
+		if (ast_true(ackcall))
 			p->ackcall = 1;
 		else
 			p->ackcall = 0;
@@ -2209,6 +2198,38 @@
 		p = p->next;
 	}
 	ast_mutex_unlock(&agentlock);
+
+	return(login_state);
+}
+
+/**
+ * Sets an agent as logged in by callback in the Manager API.
+ * It is registered on load_module() and it gets called by the manager backend.
+ * @param s
+ * @param m
+ * @returns 
+ * @sa action_agents(), action_agent_logoff(), load_module().
+ */
+static int action_agent_callback_login(struct mansession *s, struct message *m)
+{
+	char *agent = astman_get_header(m, "Agent");
+	char *exten = astman_get_header(m, "Exten");
+	char *context = astman_get_header(m, "Context");
+	char *wrapuptime_s = astman_get_header(m, "WrapupTime");
+	char *ackcall_s = astman_get_header(m, "AckCall");
+	int login_state = 0;
+
+	if (ast_strlen_zero(agent)) {
+		astman_send_error(s, m, "No agent specified");
+		return 0;
+	}
+
+	if (ast_strlen_zero(exten)) {
+		astman_send_error(s, m, "No extension specified");
+		return 0;
+	}
+
+	login_state = agent_callback_login(agent, exten, context, wrapuptime_s, ackcall_s);
 
 	if (login_state == 1)
 		astman_send_ack(s, m, "Agent logged in");

Modified: team/bweschke/polycom_acd_functions/channels/chan_sip.c
URL: http://svn.digium.com/view/asterisk/team/bweschke/polycom_acd_functions/channels/chan_sip.c?rev=7723&r1=7722&r2=7723&view=diff
==============================================================================
--- team/bweschke/polycom_acd_functions/channels/chan_sip.c (original)
+++ team/bweschke/polycom_acd_functions/channels/chan_sip.c Mon Jan  2 16:27:44 2006
@@ -86,6 +86,7 @@
 #include "asterisk/dnsmgr.h"
 #include "asterisk/devicestate.h"
 #include "asterisk/linkedlists.h"
+#include "asterisk/agents.h"
 
 #ifdef OSP_SUPPORT
 #include "asterisk/astosp.h"
@@ -148,6 +149,7 @@
 static const char channeltype[] = "SIP";
 static const char config[] = "sip.conf";
 static const char notify_config[] = "sip_notify.conf";
+static const char agentconfig[] = "agents.conf";
 
 #define RTP 	1
 #define NO_RTP	0
@@ -750,6 +752,8 @@
 	int capability;			/*!< Codec capability */
 	int inUse;			/*!< Number of calls in use */
 	int call_limit;			/*!< Limit of concurrent calls */
+	int agentlogin;			/*!<  Agent login is allowed (for phones that support it) */
+	char agentcbcontext[AST_MAX_CONTEXT]; /*!< Default context for call backs to agents */
 	struct ast_ha *ha;		/*!< ACL setting */
 	struct ast_variable *chanvars;	/*!< Variables to set for channel created by user */
 };
@@ -7098,7 +7102,7 @@
 				p->noncodeccapability &= ~AST_RTP_DTMF;
 		}
 		if (user && debug)
-			ast_verbose("Found user '%s'\n", user->name);
+			ast_verbose("Found user '%s' - check auth: %d\n", user->name, res);
 	} else {
 		if (user) {
 			if (!mailbox && debug)
@@ -7221,6 +7225,11 @@
 #endif
 		}
 
+	}
+
+	if (user && res == -2) {
+		if (user->agentlogin)
+			res = -3;
 	}
 
 	if (user)
@@ -10674,6 +10683,270 @@
 	}
 	return 1;
 }
+
+/*! \brief  handle_request_agentlogin: Handle incoming agent login via SUBSCRIBE ---*/
+static int handle_request_agentlogin(struct sip_pvt *p, struct sip_request *req, char *randdata, int randlen, char *uri, int debug)
+{
+	struct ast_config *cfg;
+	struct ast_variable *v;
+	char a1[256];
+	char a2[256];
+	char a1_hash[256];
+	char a2_hash[256];
+	char resp[256];
+	char resp_hash[256]="";
+	char tmp[256];
+	char *c;
+	char *z;
+	char *ua_hash ="";
+	char *resp_uri ="";
+	char *nonce = "";
+	char *digestusername = "";
+	int  wrongnonce = 0;
+	char *usednonce = randdata;
+	int argc;
+	char *argv[3];
+	char *args;
+	char *agentsecret = NULL;
+	char *agentid = NULL;
+	char *agentname = NULL;
+	char *respheader = "WWW-Authenticate";
+	char *response = "401 Unauthorized";
+	char *of = NULL;
+	struct sip_user *user = NULL;
+
+	ast_copy_string(tmp, get_header(req, "Authorization"), sizeof(tmp));
+
+	c = tmp;
+	while (c) {
+		c = ast_skip_blanks(c);
+		if (!*c)
+			break;
+		if (!strncasecmp(c, "response=", strlen("response="))) {
+			c+= strlen("response=");
+			if ((*c == '\"')) {
+				ua_hash=++c;
+				if ((c = strchr(c,'\"')))
+					*c = '\0';
+			} else {
+				ua_hash=c;
+				if ((c = strchr(c,',')))
+					*c = '\0';
+			}
+		} else if (!strncasecmp(c, "uri=", strlen("uri="))) {
+			c+= strlen("uri=");
+			if ((*c == '\"')) {
+				resp_uri=++c;
+				if ((c = strchr(c,'\"')))
+					*c = '\0';
+			} else {
+				resp_uri=c;
+				if ((c = strchr(c,',')))
+					*c = '\0';
+			}
+		} else if (!strncasecmp(c, "username=", strlen("username="))) {
+			c+= strlen("username=");
+			if ((*c == '\"')) {
+				digestusername=++c;
+				if ((c = strchr(c,'\"')))
+					*c = '\0';
+			} else {
+				digestusername=c;
+				if ((c = strchr(c,',')))
+					*c = '\0';
+			}
+		} else if (!strncasecmp(c, "nonce=", strlen("nonce="))) {
+			c+= strlen("nonce=");
+			if ((*c == '\"')) {
+				nonce=++c;
+				if ((c = strchr(c,'\"')))
+					*c = '\0';
+			} else {
+				nonce=c;
+				if ((c = strchr(c,',')))
+					*c = '\0';
+			}
+		} else
+			if ((z = strchr(c, ' ')) || (z = strchr(c,',')))
+				c=z;
+		if (c)
+			c++;
+	}
+	
+	cfg = ast_config_load(agentconfig);
+	if (!cfg) {
+		ast_log(LOG_ERROR, "Agent login requested, but not agents.conf found!\n");
+		return -1;
+	}
+	/* Read in the [agents] section */
+	v = ast_variable_browse(cfg, "agents");
+	while (v) {
+		/* Find the right "agent" in the config */
+		if (!strcasecmp(v->name, "agent")) {
+			args = ast_strdupa(v->value);
+			if ((argc = ast_app_separate_args(args, ',', argv, sizeof(argv) / sizeof(argv[0])))) {
+				agentid = argv[0];
+				if (argc > 1) {
+					agentsecret = argv[1];
+					while (*agentsecret && *agentsecret < 33) agentsecret++;
+				}
+				if (argc > 2) {
+					agentname = argv[2];
+					while (*agentname && *agentname < 33) agentname++;
+				}
+				if (!strcasecmp(agentname, digestusername)) {
+					if (debug)
+						ast_log(LOG_DEBUG, "Found agent '%s' in agent configs\n", agentname);
+					break;
+				}
+			}
+		}
+		v = v->next;
+	}
+	ast_config_destroy(cfg);
+	
+	if (!strcasecmp(agentid, digestusername)) {
+		if (strncasecmp(randdata, nonce, randlen)) {
+			wrongnonce = 1;
+			usednonce = nonce;
+		}
+		
+		snprintf(a1, sizeof(a1), "%s:%s:%s", digestusername, global_realm, agentsecret);
+
+		if (!ast_strlen_zero(resp_uri))
+			snprintf(a2, sizeof(a2), "%s:%s", sip_methods[SIP_SUBSCRIBE].text, resp_uri);
+		else
+			snprintf(a2, sizeof(a2), "%s:%s", sip_methods[SIP_SUBSCRIBE].text, uri);
+
+		ast_md5_hash(a1_hash, a1);
+
+		ast_md5_hash(a2_hash, a2);
+
+		snprintf(resp, sizeof(resp), "%s:%s:%s", a1_hash, usednonce, a2_hash);
+		
+		ast_md5_hash(resp_hash, resp);
+
+		if (wrongnonce) {
+			snprintf(randdata, randlen, "%08x", thread_safe_rand());
+			if (ua_hash && !strncasecmp(ua_hash, resp_hash, strlen(resp_hash))) {
+				if (debug)
+					ast_log(LOG_DEBUG, "stale nonce received from '%s'\n", get_header(req, "To"));
+				/* We got working auth token, based on stale nonce. */
+				transmit_response_with_auth(p, response, req, randdata, 0, respheader, 1);
+			} else {
+				/* Everything was wrong, so give the device one more try with a new challenge */
+				if (debug)
+					ast_log(LOG_NOTICE, "Bad agent authentication received from '%s'\n", get_header(req, "to"));
+				transmit_response_with_auth(p, response, req, randdata, 0, respheader, 0);
+			}
+
+			/* Schedule auto destroy in 15 seconds */
+			sip_scheddestroy(p, 15000);
+			return -3;
+		}
+
+		/* resp_hash now has the expected response, compare the two */
+		if (ua_hash && !strncasecmp(ua_hash, resp_hash, strlen(resp_hash))) {
+			/* Auth is OK */
+			if (debug)
+				ast_log(LOG_DEBUG, "Successfully authenticated agent '%s'\n", agentid);
+			of = ast_strdupa(p->from);
+			of += 4;
+			/* Get just the username part */
+			if ((c = strchr(of, '@'))) {
+				*c = '\0';
+				if ((c = strchr(of, ':')))
+					*c = '\0';
+				ast_copy_string(p->cid_num, of, sizeof(p->cid_num));
+				ast_shrink_phone_number(p->cid_num);
+			}
+			
+			user = find_user(of, 1);
+		
+			if (user) {
+				/* Setup the SIP session properly */
+				sip_cancel_destroy(p);
+				ast_copy_flags(p, user, SIP_FLAGS_TO_COPY);
+				/* Copy SIP extensions profile from INVITE */
+				if (p->sipoptions)
+					user->sipoptions = p->sipoptions;
+
+				/* If we have a call limit, set flag */
+				if (user->call_limit)
+					ast_set_flag(p, SIP_CALL_LIMIT);
+				if (!ast_strlen_zero(user->context))
+					ast_copy_string(p->context, user->context, sizeof(p->context));
+				if (!ast_strlen_zero(user->cid_num) && !ast_strlen_zero(p->cid_num))  {
+					ast_copy_string(p->cid_num, user->cid_num, sizeof(p->cid_num));
+					ast_shrink_phone_number(p->cid_num);
+				}
+				if (!ast_strlen_zero(user->cid_name) && !ast_strlen_zero(p->cid_num)) 
+					ast_copy_string(p->cid_name, user->cid_name, sizeof(p->cid_name));
+				ast_copy_string(p->username, user->name, sizeof(p->username));
+				ast_copy_string(p->peersecret, user->secret, sizeof(p->peersecret));
+				ast_copy_string(p->subscribecontext, user->subscribecontext, sizeof(p->subscribecontext));
+				ast_copy_string(p->peermd5secret, user->md5secret, sizeof(p->peermd5secret));
+				ast_copy_string(p->accountcode, user->accountcode, sizeof(p->accountcode));
+				ast_copy_string(p->language, user->language, sizeof(p->language));
+				ast_copy_string(p->musicclass, user->musicclass, sizeof(p->musicclass));
+				p->amaflags = user->amaflags;
+				p->callgroup = user->callgroup;
+				p->pickupgroup = user->pickupgroup;
+				p->callingpres = user->callingpres;
+				p->capability = user->capability;
+				p->jointcapability = user->capability;
+				if (p->peercapability)
+					p->jointcapability &= p->peercapability;
+				if ((ast_test_flag(p, SIP_DTMF) == SIP_DTMF_RFC2833) || (ast_test_flag(p, SIP_DTMF) == SIP_DTMF_AUTO))
+					p->noncodeccapability |= AST_RTP_DTMF;
+				else
+					p->noncodeccapability &= ~AST_RTP_DTMF;
+				build_contact(p);
+
+				if (p && !ast_test_flag(p, SIP_NEEDDESTROY)) {
+					p->expiry = atoi(get_header(req, "Expires"));
+
+					if (p->expiry) {
+						agent_callback_login(agentid, p->username, user->agentcbcontext, NULL, NULL);
+						if (debug)	
+							ast_log(LOG_DEBUG, "Adding agent login for agent '%s' for peer %s\n", agentid, p->username);
+					}
+
+					if (p->autokillid > -1)
+						sip_cancel_destroy(p);	/* Remove subscription expiry for renewals */
+					sip_scheddestroy(p, (p->expiry + 10) * 1000);	/* Set timer for destruction of call at expiration */
+
+					transmit_response(p, "200 OK", req);
+			
+					if (!p->expiry) {
+						ast_set_flag(p, SIP_NEEDDESTROY);
+						if (debug)
+							ast_log(LOG_DEBUG, "Removing agent login for agent '%s' for peer %s\n", agentid, p->username);	
+					}
+				}
+
+
+
+			}	
+			
+			return 0;	
+
+		} else {
+			/* Transmit a bad auth */
+			ast_log(LOG_NOTICE, "Bad agent authentication for agent '%s' from peer %s\n", agentid, p->username);
+			transmit_response_with_auth(p, response, req, randdata, 0, respheader, 0);
+			sip_scheddestroy(p, 15000);
+		}
+
+	} else {
+		ast_log(LOG_ERROR, "SIP device requested agent login for '%s' but no such agent found in agent configs\n", digestusername);
+		transmit_response(p, "404 Not Found", req);
+		ast_set_flag(p, SIP_NEEDDESTROY);	
+		return -2;
+	}
+	return 0;
+}
+
 /*! \brief  handle_request_subscribe: Handle incoming SUBSCRIBE request ---*/
 static int handle_request_subscribe(struct sip_pvt *p, struct sip_request *req, int debug, int ignore, struct sockaddr_in *sin, int seqno, char *e)
 {
@@ -10722,7 +10995,12 @@
 		/* Handle authentication if this is our first subscribe */
 		res = check_user_full(p, req, SIP_SUBSCRIBE, e, 0, sin, ignore, mailbox, mailboxsize);
 		if (res) {
-			if (res < 0) {
+			if (res == -3) {
+				if (debug) {
+					ast_log(LOG_DEBUG, "This is an agent login attempt via SUBSCRIBE\n");
+					handle_request_agentlogin(p, req, p->randdata, sizeof(p->randdata), e, debug);
+				}
+			} else if (res < 0) {
 				ast_log(LOG_NOTICE, "Failed to authenticate user %s for SUBSCRIBE\n", get_header(req, "From"));
 				ast_set_flag(p, SIP_NEEDDESTROY);	
 			}
@@ -11905,6 +12183,8 @@
 	ast_copy_flags(user, &global_flags, SIP_FLAGS_TO_COPY);
 	user->capability = global_capability;
 	user->prefs = prefs;
+	user->agentlogin = 0;
+	strcpy(user->agentcbcontext, default_context);
 	/* set default context */
 	strcpy(user->context, default_context);
 	strcpy(user->language, default_language);
@@ -11946,6 +12226,8 @@
 			ast_copy_string(user->musicclass, v->value, sizeof(user->musicclass));
 		} else if (!strcasecmp(v->name, "accountcode")) {
 			ast_copy_string(user->accountcode, v->value, sizeof(user->accountcode));
+		} else if (!strcasecmp(v->name, "agentcbcontext")) {
+			ast_copy_string(user->agentcbcontext, v->value, sizeof(user->agentcbcontext));
 		} else if (!strcasecmp(v->name, "call-limit") || !strcasecmp(v->name, "incominglimit")) {
 			user->call_limit = atoi(v->value);
 			if (user->call_limit < 0)
@@ -11961,6 +12243,12 @@
 			ast_parse_allow_disallow(&user->prefs, &user->capability, v->value, 1);
 		} else if (!strcasecmp(v->name, "disallow")) {
 			ast_parse_allow_disallow(&user->prefs, &user->capability, v->value, 0);
+		} else if (!strcasecmp(v->name, "agentlogin")) {
+			if (!strcasecmp(v->value, "no")) {
+				user->agentlogin = 0;
+			} else if (!strcasecmp(v->value, "yes")) {
+				user->agentlogin = 1;
+			}
 		} else if (!strcasecmp(v->name, "callingpres")) {
 			user->callingpres = ast_parse_caller_presentation(v->value);
 			if (user->callingpres == -1)
@@ -12098,7 +12386,7 @@
 		}
 
 		if (realtime && !strcasecmp(v->name, "regseconds")) {
-			if (sscanf(v->value, "%i", (int *)&regseconds) != 1)
+			if (sscanf(v->value, "%ld", (time_t *)&regseconds) != 1)
 				regseconds = 0;
 		} else if (realtime && !strcasecmp(v->name, "ipaddr") && !ast_strlen_zero(v->value) ) {
 			inet_aton(v->value, &(peer->addr.sin_addr));

Added: team/bweschke/polycom_acd_functions/include/asterisk/agents.h
URL: http://svn.digium.com/view/asterisk/team/bweschke/polycom_acd_functions/include/asterisk/agents.h?rev=7723&view=auto
==============================================================================
--- team/bweschke/polycom_acd_functions/include/asterisk/agents.h (added)
+++ team/bweschke/polycom_acd_functions/include/asterisk/agents.h Mon Jan  2 16:27:44 2006
@@ -1,0 +1,35 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 1999 - 2006, Digium, Inc.
+ *
+ * Mark Spencer <markster at digium.com>
+ *
+ * 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.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ * \brief Agent Channel API (For Login/Logout) 
+ */
+
+#ifndef _AST_AGENTS_H
+#define _AST_AGENTS_H
+
+/*! \brief Login an agent and params for Asterisk to callback the agent 
+ *  \param agent
+    \param exten
+    \param context
+    \param wrapuptime
+    \param ackcall
+*/
+int agent_callback_login(char *agent, char *exten, char *context, char *wrapuptime, char *ackcall);
+
+#endif /* _AST_AGENTS_H */



More information about the asterisk-commits mailing list