[svn-commits] branch bweschke/polycom_acd_functions - r7723 in
/team/bweschke/polycom_acd_f...
svn-commits at lists.digium.com
svn-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 *)®seconds) != 1)
+ if (sscanf(v->value, "%ld", (time_t *)®seconds) != 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 svn-commits
mailing list