diff --git a/src/mod/applications/mod_callcenter/conf/autoload_configs/callcenter.conf.xml b/src/mod/applications/mod_callcenter/conf/autoload_configs/callcenter.conf.xml
index 326a33fe9b..933c3f47e1 100644
--- a/src/mod/applications/mod_callcenter/conf/autoload_configs/callcenter.conf.xml
+++ b/src/mod/applications/mod_callcenter/conf/autoload_configs/callcenter.conf.xml
@@ -1,39 +1,42 @@
-
-
-
-
-
+
+
+
+
+
+
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/mod/applications/mod_callcenter/mod_callcenter.c b/src/mod/applications/mod_callcenter/mod_callcenter.c
index 18746f3829..4e4fef89db 100644
--- a/src/mod/applications/mod_callcenter/mod_callcenter.c
+++ b/src/mod/applications/mod_callcenter/mod_callcenter.c
@@ -49,8 +49,6 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_callcenter_load);
*/
SWITCH_MODULE_DEFINITION(mod_callcenter, mod_callcenter_load, mod_callcenter_shutdown, NULL);
-static switch_status_t load_agent(const char *agent_name, switch_event_t *params, switch_xml_t x_agents_cfg);
-static switch_status_t load_tiers(switch_bool_t load_all, const char *queue_name, const char *agent_name, switch_event_t *params, switch_xml_t x_tiers_cfg);
static const char *global_cf = "callcenter.conf";
struct cc_status_table {
@@ -415,14 +413,8 @@ typedef enum {
} cc_flags_t;
static struct {
- switch_hash_t *queue_hash;
- int debug;
- char *odbc_dsn;
- char *dbname;
+ switch_hash_t *profile_hash;
char *core_uuid;
- switch_bool_t reserve_agents;
- switch_bool_t truncate_tiers;
- switch_bool_t truncate_agents;
int32_t threads;
int32_t running;
switch_mutex_t *mutex;
@@ -430,11 +422,45 @@ static struct {
switch_event_node_t *node;
} globals;
+#define CC_PROFILE_CONFIGITEM_COUNT 100
+
+struct cc_profile {
+ char *name;
+
+ int debug;
+
+ switch_hash_t *queue_hash;
+
+ char *odbc_dsn;
+ char *dbname;
+
+ switch_bool_t reserve_agents;
+ switch_bool_t truncate_tiers;
+ switch_bool_t truncate_agents;
+
+ switch_mutex_t *mutex;
+
+ switch_thread_rwlock_t *rwlock;
+ switch_memory_pool_t *pool;
+
+ int32_t threads;
+
+ int AGENT_DISPATCH_THREAD_RUNNING;
+ int AGENT_DISPATCH_THREAD_STARTED;
+
+ switch_xml_config_item_t config[CC_PROFILE_CONFIGITEM_COUNT];
+ switch_xml_config_string_options_t config_str_pool;
+
+ uint32_t flags;
+};
+
+typedef struct cc_profile cc_profile_t;
+
#define CC_QUEUE_CONFIGITEM_COUNT 100
struct cc_queue {
char *name;
-
+ cc_profile_t *profile;
char *strategy;
char *moh;
char *announce;
@@ -475,60 +501,90 @@ struct cc_queue {
};
typedef struct cc_queue cc_queue_t;
-static void cc_send_presence(const char *queue_name);
+static cc_profile_t *get_profile(const char *profile_name);
+static void cc_send_presence(cc_profile_t *profile, const char *queue_name);
+static switch_status_t load_agent(cc_profile_t *profile, const char *agent_name, switch_event_t *params, switch_xml_t x_agents_cfg);
+static switch_status_t load_tiers(cc_profile_t *profile, switch_bool_t load_all, const char *queue_name, const char *agent_name, switch_event_t *params, switch_xml_t x_tiers_cfg);
+void cc_agent_dispatch_thread_start(const char *profile_name);
-static void free_queue(cc_queue_t *queue)
+cc_queue_t *free_queue(cc_queue_t *queue)
{
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Destroying Profile %s\n", queue->name);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Destroying Queue %s from profile %s\n", queue->name, queue->profile->name);
switch_core_destroy_memory_pool(&queue->pool);
+ return NULL;
}
static void queue_rwunlock(cc_queue_t *queue)
{
- switch_thread_rwlock_unlock(queue->rwlock);
- if (switch_test_flag(queue, PFLAG_DESTROY)) {
- if (switch_thread_rwlock_trywrlock(queue->rwlock) == SWITCH_STATUS_SUCCESS) {
- switch_thread_rwlock_unlock(queue->rwlock);
- free_queue(queue);
+ if (queue) {
+ switch_thread_rwlock_unlock(queue->rwlock);
+ if (switch_test_flag(queue, PFLAG_DESTROY)) {
+ if (switch_thread_rwlock_trywrlock(queue->rwlock) == SWITCH_STATUS_SUCCESS) {
+ switch_thread_rwlock_unlock(queue->rwlock);
+ free_queue(queue);
+ }
}
}
}
-static void destroy_queue(const char *queue_name)
+cc_profile_t *free_profile(cc_profile_t *profile)
+{
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Destroying Profile %s\n", profile->name);
+ switch_core_destroy_memory_pool(&profile->pool);
+ return NULL;
+}
+
+static void profile_rwunlock(cc_profile_t *profile)
+{
+ if (profile) {
+ switch_thread_rwlock_unlock(profile->rwlock);
+ if (switch_test_flag(profile, PFLAG_DESTROY)) {
+ if (switch_thread_rwlock_trywrlock(profile->rwlock) == SWITCH_STATUS_SUCCESS) {
+ switch_thread_rwlock_unlock(profile->rwlock);
+ free_profile(profile);
+ }
+ }
+ }
+}
+
+static void destroy_queue(cc_profile_t *profile, const char *queue_name)
{
cc_queue_t *queue = NULL;
- switch_mutex_lock(globals.mutex);
- if ((queue = switch_core_hash_find(globals.queue_hash, queue_name))) {
- switch_core_hash_delete(globals.queue_hash, queue_name);
+
+ switch_mutex_lock(profile->mutex);
+ if ((queue = switch_core_hash_find(profile->queue_hash, queue_name))) {
+ switch_core_hash_delete(profile->queue_hash, queue_name);
}
- switch_mutex_unlock(globals.mutex);
+ switch_mutex_unlock(profile->mutex);
if (!queue) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "[%s] Invalid queue\n", queue_name);
- return;
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "[%s/%s] Invalid queue\n", profile->name, queue_name);
+ goto done;
}
if (switch_thread_rwlock_trywrlock(queue->rwlock) != SWITCH_STATUS_SUCCESS) {
/* Lock failed, set the destroy flag so it'll be destroyed whenever its not in use anymore */
switch_set_flag(queue, PFLAG_DESTROY);
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "[%s] queue is in use, memory will be freed whenever its no longer in use\n",
- queue->name);
- return;
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "[%s/%s] queue is in use, memory will be freed whenever its no longer in use\n",
+ profile->name, queue->name);
+ goto done;
}
+ queue = free_queue(queue);
+done:
+ queue_rwunlock(queue);
- free_queue(queue);
}
-switch_cache_db_handle_t *cc_get_db_handle(void)
+switch_cache_db_handle_t *cc_get_db_handle(cc_profile_t *profile)
{
switch_cache_db_handle_t *dbh = NULL;
char *dsn;
- if (!zstr(globals.odbc_dsn)) {
- dsn = globals.odbc_dsn;
+ if (!zstr(profile->odbc_dsn)) {
+ dsn = profile->odbc_dsn;
} else {
- dsn = globals.dbname;
+ dsn = profile->dbname;
}
if (switch_cache_db_get_db_handle_dsn(&dbh, dsn) != SWITCH_STATUS_SUCCESS) {
@@ -580,11 +636,11 @@ cc_queue_t *queue_set_config(cc_queue_t *queue)
}
-static int cc_execute_sql_affected_rows(char *sql) {
+static int cc_execute_sql_affected_rows(cc_profile_t *profile, char *sql) {
switch_cache_db_handle_t *dbh = NULL;
int res = 0;
- if (!(dbh = cc_get_db_handle())) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB\n");
+ if (!(dbh = cc_get_db_handle(profile))) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB for profile %s\n", profile->name);
return -1;
}
switch_cache_db_execute_sql(dbh, sql, NULL);
@@ -593,7 +649,7 @@ static int cc_execute_sql_affected_rows(char *sql) {
return res;
}
-char *cc_execute_sql2str(cc_queue_t *queue, switch_mutex_t *mutex, char *sql, char *resbuf, size_t len)
+char *cc_execute_sql2str(cc_profile_t *profile, cc_queue_t *queue, switch_mutex_t *mutex, char *sql, char *resbuf, size_t len)
{
char *ret = NULL;
@@ -605,8 +661,8 @@ char *cc_execute_sql2str(cc_queue_t *queue, switch_mutex_t *mutex, char *sql, ch
switch_mutex_lock(globals.mutex);
}
- if (!(dbh = cc_get_db_handle())) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB\n");
+ if (!(dbh = cc_get_db_handle(profile))) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB for profile %s\n", profile->name);
goto end;
}
@@ -624,7 +680,7 @@ end:
return ret;
}
-static switch_status_t cc_execute_sql(cc_queue_t *queue, char *sql, switch_mutex_t *mutex)
+static switch_status_t cc_execute_sql(cc_profile_t *profile, cc_queue_t *queue, char *sql, switch_mutex_t *mutex)
{
switch_cache_db_handle_t *dbh = NULL;
switch_status_t status = SWITCH_STATUS_FALSE;
@@ -635,8 +691,8 @@ static switch_status_t cc_execute_sql(cc_queue_t *queue, char *sql, switch_mutex
switch_mutex_lock(globals.mutex);
}
- if (!(dbh = cc_get_db_handle())) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB\n");
+ if (!(dbh = cc_get_db_handle(profile))) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB for profile %s\n", profile->name);
goto end;
}
@@ -655,7 +711,7 @@ end:
return status;
}
-static switch_bool_t cc_execute_sql_callback(cc_queue_t *queue, switch_mutex_t *mutex, char *sql, switch_core_db_callback_func_t callback, void *pdata)
+static switch_bool_t cc_execute_sql_callback(cc_profile_t *profile, cc_queue_t *queue, switch_mutex_t *mutex, char *sql, switch_core_db_callback_func_t callback, void *pdata)
{
switch_bool_t ret = SWITCH_FALSE;
char *errmsg = NULL;
@@ -667,15 +723,15 @@ static switch_bool_t cc_execute_sql_callback(cc_queue_t *queue, switch_mutex_t *
switch_mutex_lock(globals.mutex);
}
- if (!(dbh = cc_get_db_handle())) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB\n");
+ if (!(dbh = cc_get_db_handle(profile))) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB for profile %s\n", profile->name);
goto end;
}
switch_cache_db_execute_sql_callback(dbh, sql, callback, pdata, &errmsg);
if (errmsg) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "SQL ERR: [%s] %s\n", sql, errmsg);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "SQL ERR profile %s: [%s] %s\n", profile->name, sql, errmsg);
free(errmsg);
}
@@ -692,16 +748,235 @@ end:
return ret;
}
-static cc_queue_t *load_queue(const char *queue_name, switch_bool_t request_agents, switch_bool_t request_tiers, switch_xml_t x_queues_cfg)
+static cc_queue_t *load_queue(cc_profile_t *profile, const char *queue_name, switch_bool_t request_agents, switch_bool_t request_tiers, switch_xml_t x_queues_cfg);
+
+static switch_status_t destroy_profile(const char *profile_name) {
+ cc_profile_t *profile = NULL;
+ switch_hash_index_t *hi_queue = NULL;
+ void *val = NULL;
+ const void *key;
+ switch_ssize_t keylen;
+
+ switch_mutex_lock(globals.mutex);
+ if ((profile = switch_core_hash_find(globals.profile_hash, profile_name))) {
+ switch_core_hash_delete(globals.profile_hash, profile_name);
+ }
+ switch_mutex_unlock(globals.mutex);
+
+ if (!profile) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "[%s] Invalid profile\n", profile_name);
+ goto done;
+ }
+
+ while ((hi_queue = switch_core_hash_first_iter( profile->queue_hash, hi_queue))) {
+ cc_queue_t *queue = NULL;
+
+ switch_core_hash_this(hi_queue, &key, &keylen, &val);
+ queue = (cc_queue_t *) val;
+ destroy_queue(profile, queue->name);
+
+ queue = NULL;
+ }
+ if (switch_thread_rwlock_trywrlock(profile->rwlock) != SWITCH_STATUS_SUCCESS) {
+ /* Lock failed, set the destroy flag so it'll be destroyed whenever its not in use anymore */
+ switch_set_flag(profile, PFLAG_DESTROY);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "[%s] profile is in use, memory will be freed whenever its no longer in use\n",
+ profile->name);
+ goto done;
+ }
+ profile = free_profile(profile);
+done:
+ profile_rwunlock(profile);
+ return SWITCH_STATUS_SUCCESS;
+}
+
+static cc_profile_t *load_profile(const char *profile_name) {
+ cc_profile_t *profile = NULL;
+ switch_xml_t settings, param, x_queue, x_queues, x_tiers, x_agent, x_agents, x_profiles, x_profile, cfg, xml = NULL;
+ switch_cache_db_handle_t *dbh = NULL;
+ char *sql = NULL;
+
+ switch_memory_pool_t *pool;
+
+ switch_event_t *params = NULL;
+
+ switch_event_create(¶ms, SWITCH_EVENT_REQUEST_PARAMS);
+ switch_assert(params);
+ switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "CC-Profile", profile_name);
+
+ switch_mutex_unlock(globals.mutex);
+
+ if (!(xml = switch_xml_open_cfg(global_cf, &cfg, params))) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Open of %s failed\n", global_cf);
+ goto end;
+ }
+
+ if (!(x_profiles = switch_xml_child(cfg, "profiles"))) {
+ if (!strcasecmp(profile_name, "default")) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Loading legacy mod_callcenter configs (No profiles)\n");
+ x_profile = cfg;
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing profiles configs for requesting profile other than 'default'\n");
+
+ goto end;
+ }
+
+ } else {
+ if (!(x_profile = switch_xml_find_child(x_profiles, "profile", "name", profile_name))) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Profile '%s' not found\n", profile_name);
+ goto end;
+ }
+ }
+
+ if (switch_core_new_memory_pool(&pool) != SWITCH_STATUS_SUCCESS) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Pool Failure\n");
+ goto end;
+ }
+
+ if (!(profile = switch_core_alloc(pool, sizeof(cc_profile_t)))) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Alloc Failure\n");
+ switch_core_destroy_memory_pool(&pool);
+ goto end;
+ }
+ profile->pool = pool;
+
+ switch_core_hash_init(&profile->queue_hash);
+ switch_mutex_init(&profile->mutex, SWITCH_MUTEX_NESTED, profile->pool);
+
+ switch_thread_rwlock_create(&profile->rwlock, pool);
+ profile->name = switch_core_strdup(pool, profile_name);
+
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Added Profile %s\n", profile->name);
+ switch_core_hash_insert(globals.profile_hash, profile->name, profile);
+
+ if ((settings = switch_xml_child(x_profile, "settings"))) {
+ for (param = switch_xml_child(settings, "param"); param; param = param->next) {
+ char *var = (char *) switch_xml_attr_soft(param, "name");
+ char *val = (char *) switch_xml_attr_soft(param, "value");
+
+ if (!strcasecmp(var, "debug")) {
+ profile->debug = atoi(val);
+ } else if (!strcasecmp(var, "dbname")) {
+ profile->dbname = switch_core_strdup(pool, val);
+ } else if (!strcasecmp(var, "odbc-dsn")) {
+ profile->odbc_dsn = switch_core_strdup(pool, val);
+ } else if (!strcasecmp(var, "reserve-agents")) {
+ profile->reserve_agents = switch_true(val);
+ } else if (!strcasecmp(var, "truncate-tiers-on-load")) {
+ profile->truncate_tiers = switch_true(val);
+ } else if (!strcasecmp(var, "truncate-agents-on-load")) {
+ profile->truncate_agents = switch_true(val);
+ }
+ }
+ }
+
+ if (!profile->dbname) {
+ profile->dbname = switch_core_strdup(pool, CC_SQLITE_DB_NAME);
+ }
+ if (!profile->reserve_agents) {
+ profile->reserve_agents = SWITCH_FALSE;
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Reserving Agents before offering calls on profile %s.\n", profile->name);
+ }
+
+ /* Initialize database */
+ if (!(dbh = cc_get_db_handle(profile))) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Cannot open DB on profile %s!\n", profile->name);
+ profile = free_profile(profile);
+ goto end;
+ }
+
+ switch_cache_db_test_reactive(dbh, "select count(session_uuid) from members", "drop table members", members_sql);
+ switch_cache_db_test_reactive(dbh, "select count(ready_time) from agents", NULL, "alter table agents add ready_time integer not null default 0;"
+ "alter table agents add reject_delay_time integer not null default 0;"
+ "alter table agents add busy_delay_time integer not null default 0;");
+ switch_cache_db_test_reactive(dbh, "select count(no_answer_delay_time) from agents", NULL, "alter table agents add no_answer_delay_time integer not null default 0;");
+ switch_cache_db_test_reactive(dbh, "select count(ready_time) from agents", "drop table agents", agents_sql);
+ switch_cache_db_test_reactive(dbh, "select external_calls_count from agents", NULL, "alter table agents add external_calls_count integer not null default 0;");
+ switch_cache_db_test_reactive(dbh, "select count(queue) from tiers", "drop table tiers" , tiers_sql);
+ switch_cache_db_test_reactive(dbh, "select count(last_waiting_state) FROM agents", NULL, "alter table agents add last_waiting_state integer not null default 0;");
+
+
+ switch_cache_db_release_db_handle(&dbh);
+
+ /* Reset a unclean shutdown */
+ sql = switch_mprintf("update agents set state = 'Waiting', uuid = '' where system = 'single_box';"
+ "update tiers set state = 'Ready' where agent IN (select name from agents where system = 'single_box');"
+ "update members set state = '%q', session_uuid = '' where system = '%q';"
+ "update agents set external_calls_count = 0 where system = 'single_box';",
+ cc_member_state2str(CC_MEMBER_STATE_ABANDONED), globals.core_uuid);
+ cc_execute_sql(profile, NULL, sql, NULL);
+ switch_safe_free(sql);
+
+ /* Truncating tiers if needed */
+ if (profile->truncate_tiers) {
+ sql = switch_mprintf("delete from tiers;");
+ cc_execute_sql(profile, NULL, sql, NULL);
+ switch_safe_free(sql);
+ }
+
+ /* Truncating agents if needed */
+ if (profile->truncate_agents) {
+ sql = switch_mprintf("delete from agents;");
+ cc_execute_sql(profile, NULL, sql, NULL);
+ switch_safe_free(sql);
+ }
+
+ /* Loading queue into memory struct */
+ if ((x_queues = switch_xml_child(x_profile, "queues"))) {
+ for (x_queue = switch_xml_child(x_queues, "queue"); x_queue; x_queue = x_queue->next) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Loading queue %s from profile %s\n", switch_xml_attr_soft(x_queue, "name"), profile->name);
+ load_queue(profile, switch_xml_attr_soft(x_queue, "name"), SWITCH_FALSE, SWITCH_FALSE, x_queues);
+
+ }
+ }
+
+ /* Importing from XML config Agents */
+ if ((x_agents = switch_xml_child(x_profile, "agents"))) {
+ for (x_agent = switch_xml_child(x_agents, "agent"); x_agent; x_agent = x_agent->next) {
+ const char *agent = switch_xml_attr(x_agent, "name");
+ if (agent) {
+ load_agent(profile, agent, NULL, x_agents);
+ }
+ }
+ }
+
+ /* Importing from XML config Agent Tiers */
+ if ((x_tiers = switch_xml_child(x_profile, "tiers"))) {
+ load_tiers(profile, SWITCH_TRUE, NULL, NULL, NULL, x_tiers);
+ } else {
+ load_tiers(profile, SWITCH_TRUE, NULL, NULL, NULL, NULL);
+ }
+
+
+ if (!profile->AGENT_DISPATCH_THREAD_STARTED) {
+ cc_agent_dispatch_thread_start(profile->name);
+ }
+
+end:
+ if (params) {
+ switch_event_destroy(¶ms);
+ }
+
+ switch_mutex_unlock(globals.mutex);
+
+ switch_xml_free(xml);
+
+ return profile;
+}
+
+static cc_queue_t *load_queue(cc_profile_t *profile, const char *queue_name, switch_bool_t request_agents, switch_bool_t request_tiers, switch_xml_t x_queues_cfg)
{
cc_queue_t *queue = NULL;
switch_xml_t x_queues, x_queue, cfg, x_agents, x_agent, x_tiers;
+ switch_xml_t x_profiles, x_profile = NULL;
switch_xml_t xml = NULL;
switch_event_t *event = NULL;
switch_event_t *params = NULL;
switch_event_create(¶ms, SWITCH_EVENT_REQUEST_PARAMS);
switch_assert(params);
+ switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "CC-Profile", profile->name);
switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "CC-Queue", queue_name);
if (x_queues_cfg) {
@@ -711,7 +986,25 @@ static cc_queue_t *load_queue(const char *queue_name, switch_bool_t request_agen
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Open of %s failed\n", global_cf);
goto end;
}
- if (!(x_queues = switch_xml_child(cfg, "queues"))) {
+ if (!(x_profiles = switch_xml_child(cfg, "profiles"))) {
+ if (!strcasecmp(profile->name, "default")) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Loading legacy mod_callcenter configs (No profiles)\n");
+ x_profile = cfg;
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing profiles configs for requesting profile other than 'default'\n");
+
+ goto end;
+ }
+
+ } else {
+ if (!(x_profile = switch_xml_find_child(x_profiles, "profile", "name", profile->name))) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Profile '%s' not found\n", profile->name);
+ goto end;
+ }
+ }
+
+
+ if (!(x_queues = switch_xml_child(x_profile, "queues"))) {
goto end;
}
}
@@ -732,6 +1025,7 @@ static cc_queue_t *load_queue(const char *queue_name, switch_bool_t request_agen
}
queue->pool = pool;
+ queue->profile = profile;
queue_set_config(queue);
/* Add the params to the event structure */
@@ -752,28 +1046,28 @@ static cc_queue_t *load_queue(const char *queue_name, switch_bool_t request_agen
queue->calls_abandoned = 0;
if (cc_agent_str2status(queue->agent_no_answer_status) == CC_AGENT_STATUS_UNKNOWN) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Queue %s has invalid agent-no-answer-status, setting to %s", queue->name, cc_agent_status2str(CC_AGENT_STATUS_ON_BREAK));
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Queue %s in profile %s has invalid agent-no-answer-status, setting to %s", queue->name, profile->name, cc_agent_status2str(CC_AGENT_STATUS_ON_BREAK));
queue->agent_no_answer_status = switch_core_strdup(pool, cc_agent_status2str(CC_AGENT_STATUS_ON_BREAK));
}
switch_mutex_init(&queue->mutex, SWITCH_MUTEX_NESTED, queue->pool);
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Added queue %s\n", queue->name);
- switch_core_hash_insert(globals.queue_hash, queue->name, queue);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Added queue %s in profile %s\n", queue->name, profile->name);
+ switch_core_hash_insert(profile->queue_hash, queue->name, queue);
}
/* Importing from XML config Agents */
- if (queue && request_agents && (x_agents = switch_xml_child(cfg, "agents"))) {
+ if (queue && request_agents && (x_agents = switch_xml_child(x_profile, "agents"))) {
for (x_agent = switch_xml_child(x_agents, "agent"); x_agent; x_agent = x_agent->next) {
const char *agent = switch_xml_attr(x_agent, "name");
if (agent) {
- load_agent(agent, params, x_agents);
+ load_agent(profile, agent, params, x_agents);
}
}
}
/* Importing from XML config Agent Tiers */
- if (queue && request_tiers && (x_tiers = switch_xml_child(cfg, "tiers"))) {
- load_tiers(SWITCH_TRUE, queue_name, NULL, params, x_tiers);
+ if (queue && request_tiers && (x_tiers = switch_xml_child(x_profile, "tiers"))) {
+ load_tiers(profile, SWITCH_TRUE, queue_name, NULL, params, x_tiers);
}
end:
@@ -790,25 +1084,44 @@ end:
return queue;
}
-static cc_queue_t *get_queue(const char *queue_name)
+static cc_profile_t *get_profile(const char *profile_name)
+{
+ cc_profile_t *profile = NULL;
+
+ switch_mutex_lock(globals.mutex);
+ if (!(profile = switch_core_hash_find(globals.profile_hash, profile_name))) {
+ profile = load_profile(profile_name);
+ }
+ if (profile) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG10, "[%s] rwlock\n", profile->name);
+
+ switch_thread_rwlock_rdlock(profile->rwlock);
+ }
+ switch_mutex_unlock(globals.mutex);
+
+ return profile;
+}
+
+static cc_queue_t *get_queue(cc_profile_t *profile, const char *queue_name)
{
cc_queue_t *queue = NULL;
- switch_mutex_lock(globals.mutex);
- if (!(queue = switch_core_hash_find(globals.queue_hash, queue_name))) {
- queue = load_queue(queue_name, SWITCH_FALSE, SWITCH_FALSE, NULL);
+ switch_mutex_lock(profile->mutex);
+ if (!(queue = switch_core_hash_find(profile->queue_hash, queue_name))) {
+ queue = load_queue(profile, queue_name, SWITCH_FALSE, SWITCH_FALSE, NULL);
}
if (queue) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG10, "[%s] rwlock\n", queue->name);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG10, "[%s/%s] rwlock\n", profile->name, queue->name);
switch_thread_rwlock_rdlock(queue->rwlock);
}
- switch_mutex_unlock(globals.mutex);
+ switch_mutex_unlock(profile->mutex);
return queue;
}
struct call_helper {
+ const char *profile_name;
const char *member_uuid;
const char *member_session_uuid;
const char *queue_name;
@@ -833,7 +1146,7 @@ struct call_helper {
switch_memory_pool_t *pool;
};
-int cc_queue_count(const char *queue)
+int cc_queue_count(cc_profile_t *profile, const char *queue)
{
char *sql;
int count = 0;
@@ -850,11 +1163,12 @@ int cc_queue_count(const char *queue)
sql = switch_mprintf("SELECT count(*) FROM members WHERE queue = '%q' AND (state = '%q' OR state = '%q')",
queue, cc_member_state2str(CC_MEMBER_STATE_WAITING), cc_member_state2str(CC_MEMBER_STATE_TRYING));
}
- cc_execute_sql2str(NULL, NULL, sql, res, sizeof(res));
+ cc_execute_sql2str(profile, NULL, NULL, sql, res, sizeof(res));
switch_safe_free(sql);
count = atoi(res);
if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CALLCENTER_EVENT) == SWITCH_STATUS_SUCCESS) {
+ switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Profile", profile->name);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Queue", queue);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Action", "members-count");
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Count", res);
@@ -866,7 +1180,7 @@ int cc_queue_count(const char *queue)
return count;
}
-cc_status_t cc_agent_add(const char *agent, const char *type)
+cc_status_t cc_agent_add(cc_profile_t *profile, const char *agent, const char *type)
{
switch_event_t *event;
cc_status_t result = CC_STATUS_SUCCESS;
@@ -876,7 +1190,7 @@ cc_status_t cc_agent_add(const char *agent, const char *type)
char res[256] = "";
/* Check to see if agent already exist */
sql = switch_mprintf("SELECT count(*) FROM agents WHERE name = '%q'", agent);
- cc_execute_sql2str(NULL, NULL, sql, res, sizeof(res));
+ cc_execute_sql2str(profile, NULL, NULL, sql, res, sizeof(res));
switch_safe_free(sql);
if (atoi(res) != 0) {
@@ -888,10 +1202,11 @@ cc_status_t cc_agent_add(const char *agent, const char *type)
agent, type, cc_agent_status2str(CC_AGENT_STATUS_LOGGED_OUT));
sql = switch_mprintf("INSERT INTO agents (name, system, type, status, state) VALUES('%q', 'single_box', '%q', '%q', '%q');",
agent, type, cc_agent_status2str(CC_AGENT_STATUS_LOGGED_OUT), cc_agent_state2str(CC_AGENT_STATE_WAITING));
- cc_execute_sql(NULL, sql, NULL);
+ cc_execute_sql(profile, NULL, sql, NULL);
switch_safe_free(sql);
if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CALLCENTER_EVENT) == SWITCH_STATUS_SUCCESS) {
+ switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Profile", profile->name);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent", agent);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent-Type", type);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Action", "agent-add");
@@ -906,7 +1221,7 @@ done:
return result;
}
-cc_status_t cc_agent_del(const char *agent)
+cc_status_t cc_agent_del(cc_profile_t *profile, const char *agent)
{
cc_status_t result = CC_STATUS_SUCCESS;
@@ -916,12 +1231,12 @@ cc_status_t cc_agent_del(const char *agent)
sql = switch_mprintf("DELETE FROM agents WHERE name = '%q';"
"DELETE FROM tiers WHERE agent = '%q';",
agent, agent);
- cc_execute_sql(NULL, sql, NULL);
+ cc_execute_sql(profile, NULL, sql, NULL);
switch_safe_free(sql);
return result;
}
-cc_status_t cc_agent_get(const char *key, const char *agent, char *ret_result, size_t ret_result_size)
+cc_status_t cc_agent_get(cc_profile_t *profile, const char *key, const char *agent, char *ret_result, size_t ret_result_size)
{
cc_status_t result = CC_STATUS_SUCCESS;
char *sql;
@@ -930,7 +1245,7 @@ cc_status_t cc_agent_get(const char *key, const char *agent, char *ret_result, s
/* Check to see if agent already exists */
sql = switch_mprintf("SELECT count(*) FROM agents WHERE name = '%q'", agent);
- cc_execute_sql2str(NULL, NULL, sql, res, sizeof(res));
+ cc_execute_sql2str(profile, NULL, NULL, sql, res, sizeof(res));
switch_safe_free(sql);
if (atoi(res) == 0) {
@@ -941,7 +1256,7 @@ cc_status_t cc_agent_get(const char *key, const char *agent, char *ret_result, s
if (!strcasecmp(key, "status") || !strcasecmp(key, "state") || !strcasecmp(key, "uuid") ) {
/* Check to see if agent already exists */
sql = switch_mprintf("SELECT %q FROM agents WHERE name = '%q'", key, agent);
- cc_execute_sql2str(NULL, NULL, sql, res, sizeof(res));
+ cc_execute_sql2str(profile, NULL, NULL, sql, res, sizeof(res));
switch_safe_free(sql);
switch_snprintf(ret_result, ret_result_size, "%s", res);
result = CC_STATUS_SUCCESS;
@@ -953,6 +1268,7 @@ cc_status_t cc_agent_get(const char *key, const char *agent, char *ret_result, s
} else {
switch_snprintf(tmpname, sizeof(tmpname), "CC-Agent-%c%s", (char) switch_toupper(key[0]), key+1);
}
+ switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Profile", profile->name);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent", agent);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Action", "agent-%s-get", key);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, tmpname, res);
@@ -973,7 +1289,7 @@ done:
return result;
}
-cc_status_t cc_agent_update(const char *key, const char *value, const char *agent)
+cc_status_t cc_agent_update(cc_profile_t *profile, const char *key, const char *value, const char *agent)
{
cc_status_t result = CC_STATUS_SUCCESS;
char *sql;
@@ -982,7 +1298,7 @@ cc_status_t cc_agent_update(const char *key, const char *value, const char *agen
/* Check to see if agent already exist */
sql = switch_mprintf("SELECT count(*) FROM agents WHERE name = '%q'", agent);
- cc_execute_sql2str(NULL, NULL, sql, res, sizeof(res));
+ cc_execute_sql2str(profile, NULL, NULL, sql, res, sizeof(res));
switch_safe_free(sql);
if (atoi(res) == 0) {
@@ -1002,14 +1318,14 @@ cc_status_t cc_agent_update(const char *key, const char *value, const char *agen
sql = switch_mprintf("UPDATE agents SET status = '%q', last_status_change = '%" SWITCH_TIME_T_FMT "' WHERE name = '%q'",
value, local_epoch_time_now(NULL), agent);
}
- cc_execute_sql(NULL, sql, NULL);
+ cc_execute_sql(profile, NULL, sql, NULL);
switch_safe_free(sql);
/* Used to stop any active callback */
if (cc_agent_str2status(value) != CC_AGENT_STATUS_AVAILABLE) {
sql = switch_mprintf("SELECT uuid FROM members WHERE serving_agent = '%q' AND serving_system = 'single_box' AND NOT state = 'Answered'", agent);
- cc_execute_sql2str(NULL, NULL, sql, res, sizeof(res));
+ cc_execute_sql2str(profile, NULL, NULL, sql, res, sizeof(res));
switch_safe_free(sql);
if (!switch_strlen_zero(res)) {
switch_core_session_hupall_matching_var("cc_member_pre_answer_uuid", res, SWITCH_CAUSE_ORIGINATOR_CANCEL);
@@ -1020,6 +1336,7 @@ cc_status_t cc_agent_update(const char *key, const char *value, const char *agen
result = CC_STATUS_SUCCESS;
if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CALLCENTER_EVENT) == SWITCH_STATUS_SUCCESS) {
+ switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Profile", profile->name);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent", agent);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Action", "agent-status-change");
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent-Status", value);
@@ -1038,12 +1355,13 @@ cc_status_t cc_agent_update(const char *key, const char *value, const char *agen
sql = switch_mprintf("UPDATE agents SET state = '%q', last_offered_call = '%" SWITCH_TIME_T_FMT "' WHERE name = '%q'",
value, local_epoch_time_now(NULL), agent);
}
- cc_execute_sql(NULL, sql, NULL);
+ cc_execute_sql(profile, NULL, sql, NULL);
switch_safe_free(sql);
result = CC_STATUS_SUCCESS;
if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CALLCENTER_EVENT) == SWITCH_STATUS_SUCCESS) {
+ switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Profile", profile->name);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent", agent);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Action", "agent-state-change");
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent-State", value);
@@ -1056,18 +1374,19 @@ cc_status_t cc_agent_update(const char *key, const char *value, const char *agen
}
} else if (!strcasecmp(key, "uuid")) {
sql = switch_mprintf("UPDATE agents SET uuid = '%q', system = 'single_box' WHERE name = '%q'", value, agent);
- cc_execute_sql(NULL, sql, NULL);
+ cc_execute_sql(profile, NULL, sql, NULL);
switch_safe_free(sql);
result = CC_STATUS_SUCCESS;
} else if (!strcasecmp(key, "contact")) {
sql = switch_mprintf("UPDATE agents SET contact = '%q', system = 'single_box' WHERE name = '%q'", value, agent);
- cc_execute_sql(NULL, sql, NULL);
+ cc_execute_sql(profile, NULL, sql, NULL);
switch_safe_free(sql);
result = CC_STATUS_SUCCESS;
if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CALLCENTER_EVENT) == SWITCH_STATUS_SUCCESS) {
+ switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Profile", profile->name);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent", agent);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Action", "agent-contact-change");
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent-Contact", value);
@@ -1075,25 +1394,25 @@ cc_status_t cc_agent_update(const char *key, const char *value, const char *agen
}
} else if (!strcasecmp(key, "ready_time")) {
sql = switch_mprintf("UPDATE agents SET ready_time = '%ld', system = 'single_box' WHERE name = '%q'", atol(value), agent);
- cc_execute_sql(NULL, sql, NULL);
+ cc_execute_sql(profile, NULL, sql, NULL);
switch_safe_free(sql);
result = CC_STATUS_SUCCESS;
} else if (!strcasecmp(key, "busy_delay_time")) {
sql = switch_mprintf("UPDATE agents SET busy_delay_time = '%ld', system = 'single_box' WHERE name = '%q'", atol(value), agent);
- cc_execute_sql(NULL, sql, NULL);
+ cc_execute_sql(profile, NULL, sql, NULL);
switch_safe_free(sql);
result = CC_STATUS_SUCCESS;
} else if (!strcasecmp(key, "reject_delay_time")) {
sql = switch_mprintf("UPDATE agents SET reject_delay_time = '%ld', system = 'single_box' WHERE name = '%q'", atol(value), agent);
- cc_execute_sql(NULL, sql, NULL);
+ cc_execute_sql(profile, NULL, sql, NULL);
switch_safe_free(sql);
result = CC_STATUS_SUCCESS;
} else if (!strcasecmp(key, "no_answer_delay_time")) {
sql = switch_mprintf("UPDATE agents SET no_answer_delay_time = '%ld', system = 'single_box' WHERE name = '%q'", atol(value), agent);
- cc_execute_sql(NULL, sql, NULL);
+ cc_execute_sql(profile, NULL, sql, NULL);
switch_safe_free(sql);
result = CC_STATUS_SUCCESS;
@@ -1104,21 +1423,21 @@ cc_status_t cc_agent_update(const char *key, const char *value, const char *agen
}
sql = switch_mprintf("UPDATE agents SET type = '%q' WHERE name = '%q'", value, agent);
- cc_execute_sql(NULL, sql, NULL);
+ cc_execute_sql(profile, NULL, sql, NULL);
switch_safe_free(sql);
result = CC_STATUS_SUCCESS;
} else if (!strcasecmp(key, "max_no_answer")) {
sql = switch_mprintf("UPDATE agents SET max_no_answer = '%d', system = 'single_box' WHERE name = '%q'", atoi(value), agent);
- cc_execute_sql(NULL, sql, NULL);
+ cc_execute_sql(profile, NULL, sql, NULL);
switch_safe_free(sql);
result = CC_STATUS_SUCCESS;
} else if (!strcasecmp(key, "wrap_up_time")) {
sql = switch_mprintf("UPDATE agents SET wrap_up_time = '%d', system = 'single_box' WHERE name = '%q'", atoi(value), agent);
- cc_execute_sql(NULL, sql, NULL);
+ cc_execute_sql(profile, NULL, sql, NULL);
switch_safe_free(sql);
result = CC_STATUS_SUCCESS;
@@ -1134,9 +1453,10 @@ cc_status_t cc_agent_update(const char *key, const char *value, const char *agen
cc_agent_status2str(CC_AGENT_STATUS_AVAILABLE),
cc_agent_status2str(CC_AGENT_STATUS_AVAILABLE_ON_DEMAND));
- if (cc_execute_sql_affected_rows(sql) > 0) {
+ if (cc_execute_sql_affected_rows(profile, sql) > 0) {
result = CC_STATUS_SUCCESS;
if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CALLCENTER_EVENT) == SWITCH_STATUS_SUCCESS) {
+ switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Profile", profile->name);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent", agent);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Action", "agent-state-change");
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent-State", value);
@@ -1162,12 +1482,12 @@ done:
return result;
}
-cc_status_t cc_tier_add(const char *queue_name, const char *agent, const char *state, int level, int position)
+cc_status_t cc_tier_add(cc_profile_t *profile, const char *queue_name, const char *agent, const char *state, int level, int position)
{
cc_status_t result = CC_STATUS_SUCCESS;
char *sql;
cc_queue_t *queue = NULL;
- if (!(queue = get_queue(queue_name))) {
+ if (!(queue = get_queue(profile, queue_name))) {
result = CC_STATUS_QUEUE_NOT_FOUND;
goto done;
} else {
@@ -1178,7 +1498,7 @@ cc_status_t cc_tier_add(const char *queue_name, const char *agent, const char *s
char res[256] = "";
/* Check to see if agent already exist */
sql = switch_mprintf("SELECT count(*) FROM agents WHERE name = '%q'", agent);
- cc_execute_sql2str(NULL, NULL, sql, res, sizeof(res));
+ cc_execute_sql2str(profile, NULL, NULL, sql, res, sizeof(res));
switch_safe_free(sql);
if (atoi(res) == 0) {
@@ -1188,7 +1508,7 @@ cc_status_t cc_tier_add(const char *queue_name, const char *agent, const char *s
/* Check to see if tier already exist */
sql = switch_mprintf("SELECT count(*) FROM tiers WHERE agent = '%q' AND queue = '%q'", agent, queue_name);
- cc_execute_sql2str(NULL, NULL, sql, res, sizeof(res));
+ cc_execute_sql2str(profile, NULL, NULL, sql, res, sizeof(res));
switch_safe_free(sql);
if (atoi(res) != 0) {
@@ -1200,7 +1520,7 @@ cc_status_t cc_tier_add(const char *queue_name, const char *agent, const char *s
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Adding Tier on Queue %s for Agent %s, level %d, position %d\n", queue_name, agent, level, position);
sql = switch_mprintf("INSERT INTO tiers (queue, agent, state, level, position) VALUES('%q', '%q', '%q', '%d', '%d');",
queue_name, agent, state, level, position);
- cc_execute_sql(NULL, sql, NULL);
+ cc_execute_sql(profile, NULL, sql, NULL);
switch_safe_free(sql);
result = CC_STATUS_SUCCESS;
@@ -1214,7 +1534,7 @@ done:
return result;
}
-cc_status_t cc_tier_update(const char *key, const char *value, const char *queue_name, const char *agent)
+cc_status_t cc_tier_update(cc_profile_t *profile, const char *key, const char *value, const char *queue_name, const char *agent)
{
cc_status_t result = CC_STATUS_SUCCESS;
char *sql;
@@ -1223,7 +1543,7 @@ cc_status_t cc_tier_update(const char *key, const char *value, const char *queue
/* Check to see if tier already exist */
sql = switch_mprintf("SELECT count(*) FROM tiers WHERE agent = '%q' AND queue = '%q'", agent, queue_name);
- cc_execute_sql2str(NULL, NULL, sql, res, sizeof(res));
+ cc_execute_sql2str(profile, NULL, NULL, sql, res, sizeof(res));
switch_safe_free(sql);
if (atoi(res) == 0) {
@@ -1233,7 +1553,7 @@ cc_status_t cc_tier_update(const char *key, const char *value, const char *queue
/* Check to see if agent already exist */
sql = switch_mprintf("SELECT count(*) FROM agents WHERE name = '%q'", agent);
- cc_execute_sql2str(NULL, NULL, sql, res, sizeof(res));
+ cc_execute_sql2str(profile, NULL, NULL, sql, res, sizeof(res));
switch_safe_free(sql);
if (atoi(res) == 0) {
@@ -1241,7 +1561,7 @@ cc_status_t cc_tier_update(const char *key, const char *value, const char *queue
goto done;
}
- if (!(queue = get_queue(queue_name))) {
+ if (!(queue = get_queue(profile, queue_name))) {
result = CC_STATUS_QUEUE_NOT_FOUND;
goto done;
} else {
@@ -1251,7 +1571,7 @@ cc_status_t cc_tier_update(const char *key, const char *value, const char *queue
if (!strcasecmp(key, "state")) {
if (cc_tier_str2state(value) != CC_TIER_STATE_UNKNOWN) {
sql = switch_mprintf("UPDATE tiers SET state = '%q' WHERE queue = '%q' AND agent = '%q'", value, queue_name, agent);
- cc_execute_sql(NULL, sql, NULL);
+ cc_execute_sql(profile, NULL, sql, NULL);
switch_safe_free(sql);
result = CC_STATUS_SUCCESS;
} else {
@@ -1260,14 +1580,14 @@ cc_status_t cc_tier_update(const char *key, const char *value, const char *queue
}
} else if (!strcasecmp(key, "level")) {
sql = switch_mprintf("UPDATE tiers SET level = '%d' WHERE queue = '%q' AND agent = '%q'", atoi(value), queue_name, agent);
- cc_execute_sql(NULL, sql, NULL);
+ cc_execute_sql(profile, NULL, sql, NULL);
switch_safe_free(sql);
result = CC_STATUS_SUCCESS;
} else if (!strcasecmp(key, "position")) {
sql = switch_mprintf("UPDATE tiers SET position = '%d' WHERE queue = '%q' AND agent = '%q'", atoi(value), queue_name, agent);
- cc_execute_sql(NULL, sql, NULL);
+ cc_execute_sql(profile, NULL, sql, NULL);
switch_safe_free(sql);
result = CC_STATUS_SUCCESS;
@@ -1282,14 +1602,14 @@ done:
return result;
}
-cc_status_t cc_tier_del(const char *queue_name, const char *agent)
+cc_status_t cc_tier_del(cc_profile_t *profile,const char *queue_name, const char *agent)
{
cc_status_t result = CC_STATUS_SUCCESS;
char *sql;
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Deleted tier Agent %s in Queue %s\n", agent, queue_name);
sql = switch_mprintf("DELETE FROM tiers WHERE queue = '%q' AND agent = '%q';", queue_name, agent);
- cc_execute_sql(NULL, sql, NULL);
+ cc_execute_sql(profile, NULL, sql, NULL);
switch_safe_free(sql);
result = CC_STATUS_SUCCESS;
@@ -1297,9 +1617,10 @@ cc_status_t cc_tier_del(const char *queue_name, const char *agent)
return result;
}
-static switch_status_t load_agent(const char *agent_name, switch_event_t *params, switch_xml_t x_agents_cfg)
+static switch_status_t load_agent(cc_profile_t *profile, const char *agent_name, switch_event_t *params, switch_xml_t x_agents_cfg)
{
switch_xml_t x_agents, x_agent, cfg;
+ switch_xml_t x_profiles, x_profile;
switch_xml_t xml = NULL;
if (x_agents_cfg) {
@@ -1307,9 +1628,28 @@ static switch_status_t load_agent(const char *agent_name, switch_event_t *params
} else {
if (!(xml = switch_xml_open_cfg(global_cf, &cfg, params))) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Open of %s failed\n", global_cf);
- return SWITCH_STATUS_FALSE;
+ goto end;
}
- if (!(x_agents = switch_xml_child(cfg, "agents"))) {
+
+ if (!(x_profiles = switch_xml_child(cfg, "profiles"))) {
+ if (!strcasecmp(profile->name, "default")) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Loading legacy mod_callcenter configs (No profiles)\n");
+ x_profile = cfg;
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing profiles configs for requesting profile other than 'default'\n");
+
+ goto end;
+ }
+
+ } else {
+ if (!(x_profile = switch_xml_find_child(x_profiles, "profile", "name", profile->name))) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Profile '%s' not found\n", profile->name);
+ goto end;
+ }
+ }
+
+
+ if (!(x_agents = switch_xml_child(x_profile, "agents"))) {
goto end;
}
}
@@ -1325,32 +1665,32 @@ static switch_status_t load_agent(const char *agent_name, switch_event_t *params
const char *no_answer_delay_time = switch_xml_attr(x_agent, "no-answer-delay-time");
if (type) {
- cc_status_t res = cc_agent_add(agent_name, type);
+ cc_status_t res = cc_agent_add(profile, agent_name, type);
if (res == CC_STATUS_SUCCESS || res == CC_STATUS_AGENT_ALREADY_EXIST) {
if (contact) {
- cc_agent_update("contact", contact, agent_name);
+ cc_agent_update(profile, "contact", contact, agent_name);
}
if (status) {
- cc_agent_update("status", status, agent_name);
+ cc_agent_update(profile, "status", status, agent_name);
}
if (wrap_up_time) {
- cc_agent_update("wrap_up_time", wrap_up_time, agent_name);
+ cc_agent_update(profile, "wrap_up_time", wrap_up_time, agent_name);
}
if (max_no_answer) {
- cc_agent_update("max_no_answer", max_no_answer, agent_name);
+ cc_agent_update(profile, "max_no_answer", max_no_answer, agent_name);
}
if (reject_delay_time) {
- cc_agent_update("reject_delay_time", reject_delay_time, agent_name);
+ cc_agent_update(profile, "reject_delay_time", reject_delay_time, agent_name);
}
if (busy_delay_time) {
- cc_agent_update("busy_delay_time", busy_delay_time, agent_name);
+ cc_agent_update(profile, "busy_delay_time", busy_delay_time, agent_name);
}
if (no_answer_delay_time) {
- cc_agent_update("no_answer_delay_time", no_answer_delay_time, agent_name);
+ cc_agent_update(profile, "no_answer_delay_time", no_answer_delay_time, agent_name);
}
if (type && res == CC_STATUS_AGENT_ALREADY_EXIST) {
- cc_agent_update("type", type, agent_name);
+ cc_agent_update(profile, "type", type, agent_name);
}
}
@@ -1366,38 +1706,39 @@ end:
return SWITCH_STATUS_SUCCESS;
}
-static switch_status_t load_tier(const char *queue, const char *agent, const char *level, const char *position)
+static switch_status_t load_tier(cc_profile_t *profile, const char *queue, const char *agent, const char *level, const char *position)
{
/* Hack to check if an tier already exist */
- if (cc_tier_update("unknown", "unknown", queue, agent) == CC_STATUS_TIER_NOT_FOUND) {
+ if (cc_tier_update(profile, "unknown", "unknown", queue, agent) == CC_STATUS_TIER_NOT_FOUND) {
if (!zstr(level) && !zstr(position)) {
- cc_tier_add(queue, agent, cc_tier_state2str(CC_TIER_STATE_READY), atoi(level), atoi(position));
+ cc_tier_add(profile, queue, agent, cc_tier_state2str(CC_TIER_STATE_READY), atoi(level), atoi(position));
} else if (!zstr(level) && zstr(position)) {
- cc_tier_add(queue, agent, cc_tier_state2str(CC_TIER_STATE_READY), atoi(level), 1);
+ cc_tier_add(profile, queue, agent, cc_tier_state2str(CC_TIER_STATE_READY), atoi(level), 1);
} else if (zstr(level) && !zstr(position)) {
- cc_tier_add(queue, agent, cc_tier_state2str(CC_TIER_STATE_READY), 1, atoi(position));
+ cc_tier_add(profile, queue, agent, cc_tier_state2str(CC_TIER_STATE_READY), 1, atoi(position));
} else {
/* default to level 1 and position 1 within the level */
- cc_tier_add(queue, agent, cc_tier_state2str(CC_TIER_STATE_READY), 1, 1);
+ cc_tier_add(profile, queue, agent, cc_tier_state2str(CC_TIER_STATE_READY), 1, 1);
}
} else {
if (!zstr(level)) {
- cc_tier_update("level", level, queue, agent);
+ cc_tier_update(profile, "level", level, queue, agent);
} else {
- cc_tier_update("level", "1", queue, agent);
+ cc_tier_update(profile, "level", "1", queue, agent);
}
if (!zstr(position)) {
- cc_tier_update("position", position, queue, agent);
+ cc_tier_update(profile, "position", position, queue, agent);
} else {
- cc_tier_update("position", "1", queue, agent);
+ cc_tier_update(profile, "position", "1", queue, agent);
}
}
return SWITCH_STATUS_SUCCESS;
}
-static switch_status_t load_tiers(switch_bool_t load_all, const char *queue_name, const char *agent_name, switch_event_t *params, switch_xml_t x_tiers_cfg)
+static switch_status_t load_tiers(cc_profile_t *profile, switch_bool_t load_all, const char *queue_name, const char *agent_name, switch_event_t *params, switch_xml_t x_tiers_cfg)
{
switch_xml_t x_tiers, x_tier, cfg;
+ switch_xml_t x_profiles, x_profile;
switch_xml_t xml = NULL;
switch_status_t result = SWITCH_STATUS_FALSE;
@@ -1406,10 +1747,26 @@ static switch_status_t load_tiers(switch_bool_t load_all, const char *queue_name
} else {
if (!(xml = switch_xml_open_cfg(global_cf, &cfg, params))) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Open of %s failed\n", global_cf);
- return SWITCH_STATUS_FALSE;
+ goto end;
+ }
+ if (!(x_profiles = switch_xml_child(cfg, "profiles"))) {
+ if (!strcasecmp(profile->name, "default")) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Loading legacy mod_callcenter configs (No profiles)\n");
+ x_profile = cfg;
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing profiles configs for requesting profile other than 'default'\n");
+
+ goto end;
+ }
+
+ } else {
+ if (!(x_profile = switch_xml_find_child(x_profiles, "profile", "name", profile->name))) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Profile '%s' not found\n", profile->name);
+ goto end;
+ }
}
- if (!(x_tiers = switch_xml_child(cfg, "tiers"))) {
+ if (!(x_tiers = switch_xml_child(x_profile, "tiers"))) {
goto end;
}
}
@@ -1421,13 +1778,13 @@ static switch_status_t load_tiers(switch_bool_t load_all, const char *queue_name
const char *level = switch_xml_attr(x_tier, "level");
const char *position = switch_xml_attr(x_tier, "position");
if (load_all == SWITCH_TRUE) {
- result = load_tier(queue, agent, level, position);
+ result = load_tier(profile, queue, agent, level, position);
} else if (!zstr(agent_name) && !zstr(queue_name) && !strcasecmp(agent, agent_name) && !strcasecmp(queue, queue_name)) {
- result = load_tier(queue, agent, level, position);
+ result = load_tier(profile, queue, agent, level, position);
} else if (zstr(agent_name) && !strcasecmp(queue, queue_name)) {
- result = load_tier(queue, agent, level, position);
+ result = load_tier(profile, queue, agent, level, position);
} else if (zstr(queue_name) && !strcasecmp(agent, agent_name)) {
- result = load_tier(queue, agent, level, position);
+ result = load_tier(profile, queue, agent, level, position);
}
}
@@ -1442,10 +1799,8 @@ end:
static switch_status_t load_config(void)
{
+ switch_xml_t cfg, xml, x_profile, x_profiles;
switch_status_t status = SWITCH_STATUS_SUCCESS;
- switch_xml_t cfg, xml, settings, param, x_queues, x_queue, x_agents, x_agent, x_tiers;
- switch_cache_db_handle_t *dbh = NULL;
- char *sql = NULL;
if (!(xml = switch_xml_open_cfg(global_cf, &cfg, NULL))) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Open of %s failed\n", global_cf);
@@ -1455,98 +1810,18 @@ static switch_status_t load_config(void)
switch_mutex_lock(globals.mutex);
globals.core_uuid = switch_core_get_uuid();
- if ((settings = switch_xml_child(cfg, "settings"))) {
- for (param = switch_xml_child(settings, "param"); param; param = param->next) {
- char *var = (char *) switch_xml_attr_soft(param, "name");
- char *val = (char *) switch_xml_attr_soft(param, "value");
- if (!strcasecmp(var, "debug")) {
- globals.debug = atoi(val);
- } else if (!strcasecmp(var, "dbname")) {
- globals.dbname = strdup(val);
- } else if (!strcasecmp(var, "odbc-dsn")) {
- globals.odbc_dsn = strdup(val);
- } else if (!strcasecmp(var, "reserve-agents")) {
- globals.reserve_agents = switch_true(val);
- } else if (!strcasecmp(var, "truncate-tiers-on-load")) {
- globals.truncate_tiers = switch_true(val);
- } else if (!strcasecmp(var, "truncate-agents-on-load")) {
- globals.truncate_agents = switch_true(val);
+
+ if (!(x_profiles = switch_xml_child(cfg, "profiles"))) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "LOADED LEGACY CALLCENTER CONFIG\n");
+ load_profile("default");
+ } else {
+ if ((x_profiles = switch_xml_child(cfg, "profiles"))) {
+ for (x_profile = switch_xml_child(x_profiles, "profile"); x_profile; x_profile = x_profile->next) {
+ load_profile(switch_xml_attr_soft(x_profile, "name"));
}
}
}
- if (!globals.dbname) {
- globals.dbname = strdup(CC_SQLITE_DB_NAME);
- }
- if (!globals.reserve_agents) {
- globals.reserve_agents = SWITCH_FALSE;
- } else {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Reserving Agents before offering calls.\n");
- }
- /* Initialize database */
- if (!(dbh = cc_get_db_handle())) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Cannot open DB!\n");
- status = SWITCH_STATUS_TERM;
- goto end;
- }
- switch_cache_db_test_reactive(dbh, "select count(session_uuid) from members", "drop table members", members_sql);
- switch_cache_db_test_reactive(dbh, "select count(ready_time) from agents", NULL, "alter table agents add ready_time integer not null default 0;"
- "alter table agents add reject_delay_time integer not null default 0;"
- "alter table agents add busy_delay_time integer not null default 0;");
- switch_cache_db_test_reactive(dbh, "select count(no_answer_delay_time) from agents", NULL, "alter table agents add no_answer_delay_time integer not null default 0;");
- switch_cache_db_test_reactive(dbh, "select count(ready_time) from agents", "drop table agents", agents_sql);
- switch_cache_db_test_reactive(dbh, "select external_calls_count from agents", NULL, "alter table agents add external_calls_count integer not null default 0;");
- switch_cache_db_test_reactive(dbh, "select count(queue) from tiers", "drop table tiers" , tiers_sql);
-
- switch_cache_db_release_db_handle(&dbh);
-
- /* Reset a unclean shutdown */
- sql = switch_mprintf("update agents set state = 'Waiting', uuid = '' where system = 'single_box';"
- "update tiers set state = 'Ready' where agent IN (select name from agents where system = 'single_box');"
- "update members set state = '%q', session_uuid = '' where system = '%q';"
- "update agents set external_calls_count = 0 where system = 'single_box';",
- cc_member_state2str(CC_MEMBER_STATE_ABANDONED), globals.core_uuid);
- cc_execute_sql(NULL, sql, NULL);
- switch_safe_free(sql);
-
- /* Truncating tiers if needed */
- if (globals.truncate_tiers) {
- sql = switch_mprintf("delete from tiers;");
- cc_execute_sql(NULL, sql, NULL);
- switch_safe_free(sql);
- }
-
- /* Truncating agents if needed */
- if (globals.truncate_agents) {
- sql = switch_mprintf("delete from agents;");
- cc_execute_sql(NULL, sql, NULL);
- switch_safe_free(sql);
- }
-
- /* Loading queue into memory struct */
- if ((x_queues = switch_xml_child(cfg, "queues"))) {
- for (x_queue = switch_xml_child(x_queues, "queue"); x_queue; x_queue = x_queue->next) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Loading queue %s\n", switch_xml_attr_soft(x_queue, "name"));
- load_queue(switch_xml_attr_soft(x_queue, "name"), SWITCH_FALSE, SWITCH_FALSE, x_queues);
- }
- }
-
- /* Importing from XML config Agents */
- if ((x_agents = switch_xml_child(cfg, "agents"))) {
- for (x_agent = switch_xml_child(x_agents, "agent"); x_agent; x_agent = x_agent->next) {
- const char *agent = switch_xml_attr(x_agent, "name");
- if (agent) {
- load_agent(agent, NULL, x_agents);
- }
- }
- }
-
- /* Importing from XML config Agent Tiers */
- if ((x_tiers = switch_xml_child(cfg, "tiers"))) {
- load_tiers(SWITCH_TRUE, NULL, NULL, NULL, x_tiers);
- } else {
- load_tiers(SWITCH_TRUE, NULL, NULL, NULL, NULL);
- }
end:
switch_mutex_unlock(globals.mutex);
@@ -1587,6 +1862,8 @@ static switch_status_t playback_array(switch_core_session_t *session, const char
static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *thread, void *obj)
{
struct call_helper *h = (struct call_helper *) obj;
+ const char *profile_name = h->profile_name;
+ cc_profile_t *profile = NULL;
switch_core_session_t *agent_session = NULL;
switch_call_cause_t cause = SWITCH_CAUSE_NONE;
switch_status_t status = SWITCH_STATUS_FALSE;
@@ -1605,6 +1882,16 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa
globals.threads++;
switch_mutex_unlock(globals.mutex);
+ if (!profile_name || !(profile = get_profile(profile_name))) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Profile %s not found, This is bad... Should not happen\n", profile_name);
+ goto done;
+
+ }
+
+ switch_mutex_lock(profile->mutex);
+ profile->threads++;
+ switch_mutex_unlock(profile->mutex);
+
/* member is gone before we could process it */
if (!member_session) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Member %s <%s> with uuid %s in queue %s is gone just before we assigned an agent\n", h->member_cid_name, h->member_cid_number, h->member_session_uuid, h->queue_name);
@@ -1613,7 +1900,7 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa
sql = switch_mprintf("UPDATE members SET state = '%q', session_uuid = '', abandoned_epoch = '%" SWITCH_TIME_T_FMT "' WHERE uuid = '%q' AND system = '%q' AND state != '%q'",
cc_member_state2str(CC_MEMBER_STATE_ABANDONED), local_epoch_time_now(NULL), h->member_uuid, globals.core_uuid, cc_member_state2str(CC_MEMBER_STATE_ABANDONED));
- cc_execute_sql(NULL, sql, NULL);
+ cc_execute_sql(profile, NULL, sql, NULL);
switch_safe_free(sql);
goto done;
}
@@ -1623,7 +1910,7 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa
switch_channel_t *member_channel = switch_core_session_get_channel(member_session);
switch_caller_profile_t *member_profile = switch_channel_get_caller_profile(member_channel);
const char *member_dnis = member_profile->rdnis;
-
+ switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Profile", profile->name);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Queue", h->queue_name);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Action", "agent-offering");
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent", h->agent_name);
@@ -1658,6 +1945,7 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member_session), SWITCH_LOG_DEBUG, "Setting outbound caller_id_name to: %s\n", cid_name);
switch_event_create(&ovars, SWITCH_EVENT_REQUEST_PARAMS);
+ switch_event_add_header(ovars, SWITCH_STACK_BOTTOM, "cc_profile", "%s", profile->name);
switch_event_add_header(ovars, SWITCH_STACK_BOTTOM, "cc_queue", "%s", h->queue_name);
switch_event_add_header(ovars, SWITCH_STACK_BOTTOM, "cc_queue_joined_epoch", "%s", h->member_joined_epoch);
switch_event_add_header(ovars, SWITCH_STACK_BOTTOM, "cc_member_uuid", "%s", h->member_uuid);
@@ -1777,8 +2065,8 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa
status = SWITCH_STATUS_SUCCESS;
} else {
- cc_agent_update("status", cc_agent_status2str(CC_AGENT_STATUS_LOGGED_OUT), h->agent_name);
- cc_agent_update("uuid", "", h->agent_name);
+ cc_agent_update(profile, "status", cc_agent_status2str(CC_AGENT_STATUS_LOGGED_OUT), h->agent_name);
+ cc_agent_update(profile, "uuid", "", h->agent_name);
}
} else {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member_session), SWITCH_LOG_DEBUG, "Invalid agent type '%s' for agent '%s', aborting member offering", h->agent_type, h->agent_name);
@@ -1802,7 +2090,7 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa
" WHERE state = '%q' AND uuid = '%q' AND system = '%q' AND serving_agent = '%q'",
h->agent_name, cc_member_state2str(CC_MEMBER_STATE_TRYING),
cc_member_state2str(CC_MEMBER_STATE_TRYING), h->member_uuid, globals.core_uuid, h->queue_strategy);
- cc_execute_sql(NULL, sql, NULL);
+ cc_execute_sql(profile, NULL, sql, NULL);
switch_safe_free(sql);
@@ -1810,7 +2098,7 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa
sql = switch_mprintf("SELECT count(*) FROM members"
" WHERE serving_agent = '%q' AND serving_system = 'single_box' AND uuid = '%q' AND system = '%q'",
h->agent_name, h->member_uuid, globals.core_uuid);
- cc_execute_sql2str(NULL, NULL, sql, res, sizeof(res));
+ cc_execute_sql2str(profile, NULL, NULL, sql, res, sizeof(res));
switch_safe_free(sql);
if (atoi(res) == 0) {
@@ -1828,6 +2116,7 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa
const char *member_dnis = member_profile->rdnis;
switch_channel_event_set_data(agent_channel, event);
+ switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Profile", profile->name);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Queue", h->queue_name);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Action", "bridge-agent-start");
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent", h->agent_name);
@@ -1894,7 +2183,7 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member_session), SWITCH_LOG_DEBUG, "Failed to bridge, agent %s has no session\n", h->agent_name);
/* Put back member on Waiting state, previous Trying */
sql = switch_mprintf("UPDATE members SET state = 'Waiting' WHERE uuid = '%q', system = '%q'", h->member_uuid, globals.core_uuid);
- cc_execute_sql(NULL, sql, NULL);
+ cc_execute_sql(profile, NULL, sql, NULL);
switch_safe_free(sql);
} else {
bridged = 1;
@@ -1914,11 +2203,11 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa
" WHERE name = '%q' AND system = '%q'",
agent_uuid, local_epoch_time_now(NULL),
h->agent_name, h->agent_system);
- cc_execute_sql(NULL, sql, NULL);
+ cc_execute_sql(profile, NULL, sql, NULL);
switch_safe_free(sql);
/* Change the agents Status in the tiers */
- cc_tier_update("state", cc_tier_state2str(CC_TIER_STATE_ACTIVE_INBOUND), h->queue_name, h->agent_name);
- cc_agent_update("state", cc_agent_state2str(CC_AGENT_STATE_IN_A_QUEUE_CALL), h->agent_name);
+ cc_tier_update(profile, "state", cc_tier_state2str(CC_TIER_STATE_ACTIVE_INBOUND), h->queue_name, h->agent_name);
+ cc_agent_update(profile, "state", cc_agent_state2str(CC_AGENT_STATE_IN_A_QUEUE_CALL), h->agent_name);
}
/* Wait until the agent hangup. This will quit also if the agent transfer the call */
@@ -1934,6 +2223,7 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa
if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CALLCENTER_EVENT) == SWITCH_STATUS_SUCCESS) {
switch_channel_event_set_data(agent_channel, event);
+ switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Profile", profile->name);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Queue", h->queue_name);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Action", "bridge-agent-end");
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Hangup-Cause", switch_channel_cause2str(cause));
@@ -1959,17 +2249,18 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa
/* Do not remove uuid of the agent if we are a standby agent */
sql = switch_mprintf("UPDATE agents SET %s last_bridge_end = %" SWITCH_TIME_T_FMT ", talk_time = talk_time + (%" SWITCH_TIME_T_FMT "-last_bridge_start) WHERE name = '%q' AND system = '%q';"
, (strcasecmp(h->agent_type, CC_AGENT_TYPE_UUID_STANDBY)?"uuid = '',":""), local_epoch_time_now(NULL), local_epoch_time_now(NULL), h->agent_name, h->agent_system);
- cc_execute_sql(NULL, sql, NULL);
+ cc_execute_sql(profile, NULL, sql, NULL);
switch_safe_free(sql);
/* Remove the member entry from the db (Could become optional to support latter processing) */
sql = switch_mprintf("DELETE FROM members WHERE uuid = '%q' AND system = '%q'", h->member_uuid, globals.core_uuid);
- cc_execute_sql(NULL, sql, NULL);
+ cc_execute_sql(profile, NULL, sql, NULL);
switch_safe_free(sql);
/* Caller off event */
if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CALLCENTER_EVENT) == SWITCH_STATUS_SUCCESS) {
switch_channel_event_set_data(member_channel, event);
+ switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Profile", profile->name);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Queue", h->queue_name);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Action", "member-queue-end");
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Hangup-Cause",
@@ -2004,7 +2295,7 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa
cc_member_state2str(CC_MEMBER_STATE_TRYING), /* Only switch to Waiting from Trying (state may be set to Abandoned in callcenter_function()) */
cc_member_state2str(CC_MEMBER_STATE_WAITING),
h->agent_name, h->agent_system, h->member_uuid, globals.core_uuid);
- cc_execute_sql(NULL, sql, NULL);
+ cc_execute_sql(profile, NULL, sql, NULL);
switch_safe_free(sql);
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member_session), SWITCH_LOG_DEBUG, "Agent %s Origination Canceled : %s\n", h->agent_name, switch_channel_cause2str(cause));
@@ -2036,7 +2327,7 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa
/* Update Agent NO Answer count */
sql = switch_mprintf("UPDATE agents SET no_answer_count = no_answer_count + 1 WHERE name = '%q' AND system = '%q';",
h->agent_name, h->agent_system);
- cc_execute_sql(NULL, sql, NULL);
+ cc_execute_sql(profile, NULL, sql, NULL);
switch_safe_free(sql);
/* Change Agent Status because he didn't answer often */
@@ -2045,6 +2336,7 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa
h->agent_name, h->max_no_answer, cc_agent_status2str(h->agent_no_answer_status));
if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CALLCENTER_EVENT) == SWITCH_STATUS_SUCCESS) {
+ switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Profile", profile->name);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent", h->agent_name);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Action", "agent-max-no-answer");
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Agent-No-Answer-Count", "%d", h->max_no_answer);
@@ -2054,7 +2346,7 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa
switch_event_fire(&event);
}
- cc_agent_update("status", cc_agent_status2str(h->agent_no_answer_status), h->agent_name);
+ cc_agent_update(profile, "status", cc_agent_status2str(h->agent_no_answer_status), h->agent_name);
}
break;
}
@@ -2063,12 +2355,13 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa
if (delay_next_agent_call > 0) {
char ready_epoch[64];
switch_snprintf(ready_epoch, sizeof(ready_epoch), "%" SWITCH_TIME_T_FMT, local_epoch_time_now(NULL) + delay_next_agent_call);
- cc_agent_update("ready_time", ready_epoch , h->agent_name);
+ cc_agent_update(profile, "ready_time", ready_epoch , h->agent_name);
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member_session), SWITCH_LOG_DEBUG, "Agent %s sleeping for %d seconds\n", h->agent_name, delay_next_agent_call);
}
/* Fire up event when contact agent fails */
if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CALLCENTER_EVENT) == SWITCH_STATUS_SUCCESS) {
+ switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Profile", profile->name);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Queue", h->queue_name);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Action", "bridge-agent-fail");
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Hangup-Cause", switch_channel_cause2str(cause));
@@ -2086,22 +2379,22 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa
}
done:
- /* Make Agent Available Again */
- sql = switch_mprintf(
- "UPDATE tiers SET state = '%q' WHERE agent = '%q' AND queue = '%q' AND (state = '%q' OR state = '%q' OR state = '%q');"
- "UPDATE tiers SET state = '%q' WHERE agent = '%q' AND NOT queue = '%q' AND state = '%q'"
- , cc_tier_state2str(tiers_state), h->agent_name, h->queue_name, cc_tier_state2str(CC_TIER_STATE_ACTIVE_INBOUND), cc_tier_state2str(CC_TIER_STATE_STANDBY), cc_tier_state2str(CC_TIER_STATE_OFFERING),
- cc_tier_state2str(CC_TIER_STATE_READY), h->agent_name, h->queue_name, cc_tier_state2str(CC_TIER_STATE_STANDBY));
- cc_execute_sql(NULL, sql, NULL);
- switch_safe_free(sql);
-
- /* If we are in Status Available On Demand, set state to Idle so we do not receive another call until state manually changed to Waiting */
- if (!strcasecmp(cc_agent_status2str(CC_AGENT_STATUS_AVAILABLE_ON_DEMAND), h->agent_status)) {
- cc_agent_update("state", cc_agent_state2str(CC_AGENT_STATE_IDLE), h->agent_name);
- } else {
- cc_agent_update("state", cc_agent_state2str(CC_AGENT_STATE_WAITING), h->agent_name);
+ /* Make Agent Available Again if profile is defined*/
+ if (profile) {
+ sql = switch_mprintf(
+ "UPDATE tiers SET state = '%q' WHERE agent = '%q' AND queue = '%q' AND (state = '%q' OR state = '%q' OR state = '%q');"
+ "UPDATE tiers SET state = '%q' WHERE agent = '%q' AND NOT queue = '%q' AND state = '%q'"
+ , cc_tier_state2str(tiers_state), h->agent_name, h->queue_name, cc_tier_state2str(CC_TIER_STATE_ACTIVE_INBOUND), cc_tier_state2str(CC_TIER_STATE_STANDBY), cc_tier_state2str(CC_TIER_STATE_OFFERING),
+ cc_tier_state2str(CC_TIER_STATE_READY), h->agent_name, h->queue_name, cc_tier_state2str(CC_TIER_STATE_STANDBY));
+ cc_execute_sql(profile, NULL, sql, NULL);
+ switch_safe_free(sql);
+ /* If we are in Status Available On Demand, set state to Idle so we do not receive another call until state manually changed to Waiting */
+ if (!strcasecmp(cc_agent_status2str(CC_AGENT_STATUS_AVAILABLE_ON_DEMAND), h->agent_status)) {
+ cc_agent_update(profile, "state", cc_agent_state2str(CC_AGENT_STATE_IDLE), h->agent_name);
+ } else {
+ cc_agent_update(profile, "state", cc_agent_state2str(CC_AGENT_STATE_WAITING), h->agent_name);
+ }
}
-
if (agent_session) {
switch_core_session_rwunlock(agent_session);
}
@@ -2111,6 +2404,13 @@ done:
switch_core_destroy_memory_pool(&h->pool);
+ if (profile) {
+ switch_mutex_lock(profile->mutex);
+ profile->threads--;
+ switch_mutex_unlock(profile->mutex);
+ }
+ profile_rwunlock(profile);
+
switch_mutex_lock(globals.mutex);
globals.threads--;
switch_mutex_unlock(globals.mutex);
@@ -2119,6 +2419,7 @@ done:
}
struct agent_callback {
+ cc_profile_t *profile;
const char *queue_name;
const char *system;
const char *member_uuid;
@@ -2146,6 +2447,7 @@ typedef struct agent_callback agent_callback_t;
static int agents_callback(void *pArg, int argc, char **argv, char **columnNames)
{
agent_callback_t *cbt = (agent_callback_t *) pArg;
+ cc_profile_t *profile = cbt->profile;
char *sql = NULL;
char res[256];
const char *agent_system = argv[0];
@@ -2226,10 +2528,10 @@ static int agents_callback(void *pArg, int argc, char **argv, char **columnNames
}
}
- if (globals.reserve_agents) {
+ if (profile->reserve_agents) {
/* Updating agent state to Reserved only if it was Waiting previously, this is done to avoid race conditions
when updating agents table with external applications */
- if (cc_agent_update("state_if_waiting", cc_agent_state2str(CC_AGENT_STATE_RESERVED), agent_name) == CC_STATUS_SUCCESS) {
+ if (cc_agent_update(profile, "state_if_waiting", cc_agent_state2str(CC_AGENT_STATE_RESERVED), agent_name) == CC_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Reserved Agent %s\n", agent_name);
} else {
/* Agent changed state just before we tried to update his state to Reserved. */
@@ -2241,7 +2543,7 @@ static int agents_callback(void *pArg, int argc, char **argv, char **columnNames
if (!strcasecmp(cbt->strategy,"ring-all") || !strcasecmp(cbt->strategy,"ring-progressively")) {
/* Check if member is a ring-all mode */
sql = switch_mprintf("SELECT count(*) FROM members WHERE serving_agent = '%q' AND uuid = '%q' AND system = '%q'", cbt->strategy, cbt->member_uuid, globals.core_uuid);
- cc_execute_sql2str(NULL, NULL, sql, res, sizeof(res));
+ cc_execute_sql2str(profile, NULL, NULL, sql, res, sizeof(res));
switch_safe_free(sql);
} else {
@@ -2250,13 +2552,13 @@ static int agents_callback(void *pArg, int argc, char **argv, char **columnNames
" WHERE state = '%q' AND uuid = '%q' AND system = '%q'",
agent_name, agent_system, cc_member_state2str(CC_MEMBER_STATE_TRYING),
cc_member_state2str(CC_MEMBER_STATE_WAITING), cbt->member_uuid, globals.core_uuid);
- cc_execute_sql(NULL, sql, NULL);
+ cc_execute_sql(profile, NULL, sql, NULL);
switch_safe_free(sql);
/* Check if we won the race to get the member to our selected agent (Used for Multi system purposes) */
sql = switch_mprintf("SELECT count(*) FROM members WHERE serving_agent = '%q' AND serving_system = '%q' AND uuid = '%q' AND system = '%q'",
agent_name, agent_system, cbt->member_uuid, globals.core_uuid);
- cc_execute_sql2str(NULL, NULL, sql, res, sizeof(res));
+ cc_execute_sql2str(profile, NULL, NULL, sql, res, sizeof(res));
switch_safe_free(sql);
}
@@ -2274,6 +2576,7 @@ static int agents_callback(void *pArg, int argc, char **argv, char **columnNames
switch_core_new_memory_pool(&pool);
h = switch_core_alloc(pool, sizeof(*h));
h->pool = pool;
+ h->profile_name = switch_core_strdup(h->pool, profile->name);
h->member_uuid = switch_core_strdup(h->pool, cbt->member_uuid);
h->member_session_uuid = switch_core_strdup(h->pool, cbt->member_session_uuid);
h->queue_strategy = switch_core_strdup(h->pool, cbt->strategy);
@@ -2313,14 +2616,14 @@ static int agents_callback(void *pArg, int argc, char **argv, char **columnNames
switch_core_session_rwunlock(member_session);
}
}
- cc_agent_update("state", cc_agent_state2str(CC_AGENT_STATE_RECEIVING), h->agent_name);
+ cc_agent_update(profile, "state", cc_agent_state2str(CC_AGENT_STATE_RECEIVING), h->agent_name);
sql = switch_mprintf(
"UPDATE tiers SET state = '%q' WHERE agent = '%q' AND queue = '%q';"
"UPDATE tiers SET state = '%q' WHERE agent = '%q' AND NOT queue = '%q' AND state = '%q';",
cc_tier_state2str(CC_TIER_STATE_OFFERING), h->agent_name, h->queue_name,
cc_tier_state2str(CC_TIER_STATE_STANDBY), h->agent_name, h->queue_name, cc_tier_state2str(CC_TIER_STATE_READY));
- cc_execute_sql(NULL, sql, NULL);
+ cc_execute_sql(profile, NULL, sql, NULL);
switch_safe_free(sql);
switch_threadattr_create(&thd_attr, h->pool);
@@ -2342,6 +2645,7 @@ static int agents_callback(void *pArg, int argc, char **argv, char **columnNames
static int members_callback(void *pArg, int argc, char **argv, char **columnNames)
{
cc_queue_t *queue = NULL;
+ cc_profile_t *profile = NULL;
char *sql = NULL;
char *sql_order_by = NULL;
char *queue_name = NULL;
@@ -2358,6 +2662,8 @@ static int members_callback(void *pArg, int argc, char **argv, char **columnName
const char *member_abandoned_epoch = NULL;
const char *serving_agent = NULL;
const char *last_originated_call = NULL;
+ const char *profile_name = NULL;
+
memset(&cbt, 0, sizeof(cbt));
cbt.queue_name = argv[0];
@@ -2371,8 +2677,16 @@ static int members_callback(void *pArg, int argc, char **argv, char **columnName
member_abandoned_epoch = argv[8];
serving_agent = argv[9];
cbt.member_system = argv[10];
+ profile_name = argv[11];
- if (!cbt.queue_name || !(queue = get_queue(cbt.queue_name))) {
+ if (!profile_name || !(profile = get_profile(profile_name))) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Profile %s not found locally, skip this member\n", profile_name);
+ goto end;
+
+ }
+ cbt.profile = profile;
+
+ if (!cbt.queue_name || !(queue = get_queue(profile, cbt.queue_name))) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Queue %s not found locally, delete this member\n", cbt.queue_name);
sql = switch_mprintf("DELETE FROM members WHERE uuid = '%q' AND system = '%q'", cbt.member_uuid, cbt.member_system);
cc_execute_sql(NULL, sql, NULL);
@@ -2409,7 +2723,7 @@ static int members_callback(void *pArg, int argc, char **argv, char **columnName
/* Once we pass a certain point, we want to get rid of the abandoned call */
if (abandoned_epoch + discard_abandoned_after < local_epoch_time_now(NULL)) {
sql = switch_mprintf("DELETE FROM members WHERE uuid = '%q' AND system = '%q' AND (abandoned_epoch = '%" SWITCH_TIME_T_FMT "' OR joined_epoch = '%q')", cbt.member_uuid, cbt.member_system, abandoned_epoch, cbt.member_joined_epoch);
- cc_execute_sql(NULL, sql, NULL);
+ cc_execute_sql(profile, NULL, sql, NULL);
switch_safe_free(sql);
}
/* Skip this member */
@@ -2426,7 +2740,7 @@ static int members_callback(void *pArg, int argc, char **argv, char **columnName
} else {
sql = switch_mprintf("UPDATE members SET serving_agent = '', state = '%q' WHERE uuid = '%q' AND state = '%q' AND serving_agent = 'ring-all'", cc_member_state2str(CC_MEMBER_STATE_WAITING), cbt.member_uuid, cc_member_state2str(CC_MEMBER_STATE_TRYING));
}
- cc_execute_sql(NULL, sql, NULL);
+ cc_execute_sql(profile, NULL, sql, NULL);
switch_safe_free(sql);
}
/* member is ring-progressively but not the queue */
@@ -2438,7 +2752,7 @@ static int members_callback(void *pArg, int argc, char **argv, char **columnName
} else {
sql = switch_mprintf("UPDATE members SET serving_agent = '', state = '%q' WHERE uuid = '%q' AND state = '%q' AND serving_agent = 'ring-progressively'", cc_member_state2str(CC_MEMBER_STATE_WAITING), cbt.member_uuid, cc_member_state2str(CC_MEMBER_STATE_TRYING));
}
- cc_execute_sql(NULL, sql, NULL);
+ cc_execute_sql(profile, NULL, sql, NULL);
switch_safe_free(sql);
}
/* Queue is now ring-all and not the member */
@@ -2450,7 +2764,7 @@ static int members_callback(void *pArg, int argc, char **argv, char **columnName
} else {
sql = switch_mprintf("UPDATE members SET serving_agent = 'ring-all', state = '%q' WHERE uuid = '%q' AND state = '%q' AND serving_agent = ''", cc_member_state2str(CC_MEMBER_STATE_TRYING), cbt.member_uuid, cc_member_state2str(CC_MEMBER_STATE_WAITING));
}
- cc_execute_sql(NULL, sql, NULL);
+ cc_execute_sql(profile, NULL, sql, NULL);
switch_safe_free(sql);
}
/* Queue is now ring-progressively and not the member */
@@ -2462,7 +2776,7 @@ static int members_callback(void *pArg, int argc, char **argv, char **columnName
} else {
sql = switch_mprintf("UPDATE members SET serving_agent = 'ring-progressively', state = '%q' WHERE uuid = '%q' AND state = '%q' AND serving_agent = ''", cc_member_state2str(CC_MEMBER_STATE_TRYING), cbt.member_uuid, cc_member_state2str(CC_MEMBER_STATE_WAITING));
}
- cc_execute_sql(NULL, sql, NULL);
+ cc_execute_sql(profile, NULL, sql, NULL);
switch_safe_free(sql);
}
@@ -2483,7 +2797,7 @@ static int members_callback(void *pArg, int argc, char **argv, char **columnName
cbt.record_template = queue_record_template;
cbt.agent_found = SWITCH_FALSE;
- if (!strcasecmp(queue->strategy, "top-down")) {
+ if (!strcasecmp(queue_strategy, "top-down")) {
/* WARNING this use channel variable to help dispatch... might need to be reviewed to save it in DB to make this multi server prooft in the future */
switch_core_session_t *member_session = switch_core_session_locate(cbt.member_session_uuid);
int position = 0, level = 0;
@@ -2517,7 +2831,7 @@ static int members_callback(void *pArg, int argc, char **argv, char **columnName
queue_name,
cc_agent_status2str(CC_AGENT_STATUS_AVAILABLE), cc_agent_status2str(CC_AGENT_STATUS_ON_BREAK), cc_agent_status2str(CC_AGENT_STATUS_AVAILABLE_ON_DEMAND)
);
- } else if (!strcasecmp(queue->strategy, "round-robin")) {
+ } else if (!strcasecmp(queue_strategy, "round-robin")) {
sql = switch_mprintf("SELECT system, name, status, contact, no_answer_count, max_no_answer, reject_delay_time, busy_delay_time, no_answer_delay_time, tiers.state, agents.last_bridge_end, agents.wrap_up_time, agents.state, agents.ready_time, tiers.position as tiers_position, tiers.level as tiers_level, agents.type, agents.uuid, external_calls_count, agents.last_offered_call as agents_last_offered_call, 1 as dyn_order FROM agents LEFT JOIN tiers ON (agents.name = tiers.agent)"
" WHERE tiers.queue = '%q'"
" AND (agents.status = '%q' OR agents.status = '%q' OR agents.status = '%q')"
@@ -2538,7 +2852,7 @@ static int members_callback(void *pArg, int argc, char **argv, char **columnName
} else {
- if (!strcasecmp(queue->strategy, "longest-idle-agent")) {
+ if (!strcasecmp(queue_strategy, "longest-idle-agent")) {
sql_order_by = switch_mprintf("level, agents.last_bridge_end, position");
} else if (!strcasecmp(queue_strategy, "agent-with-least-talk-time")) {
sql_order_by = switch_mprintf("level, agents.talk_time, position");
@@ -2547,7 +2861,7 @@ static int members_callback(void *pArg, int argc, char **argv, char **columnName
} else if (!strcasecmp(queue_strategy, "ring-all") || !strcasecmp(queue_strategy, "ring-progressively")) {
sql = switch_mprintf("UPDATE members SET state = '%q' WHERE state = '%q' AND uuid = '%q' AND system = '%q'",
cc_member_state2str(CC_MEMBER_STATE_TRYING), cc_member_state2str(CC_MEMBER_STATE_WAITING), cbt.member_uuid, cbt.member_system);
- cc_execute_sql(NULL, sql, NULL);
+ cc_execute_sql(profile, NULL, sql, NULL);
switch_safe_free(sql);
sql_order_by = switch_mprintf("level, position");
} else if(!strcasecmp(queue_strategy, "random")) {
@@ -2570,7 +2884,7 @@ static int members_callback(void *pArg, int argc, char **argv, char **columnName
}
- if (!strcasecmp(queue->strategy, "ring-progressively")) {
+ if (!strcasecmp(queue_strategy, "ring-progressively")) {
switch_core_session_t *member_session = switch_core_session_locate(cbt.member_session_uuid);
if (member_session) {
@@ -2588,12 +2902,12 @@ static int members_callback(void *pArg, int argc, char **argv, char **columnName
}
}
- cc_execute_sql_callback(NULL /* queue */, NULL /* mutex */, sql, agents_callback, &cbt /* Call back variables */);
+ cc_execute_sql_callback(profile, NULL /* queue */, NULL /* mutex */, sql, agents_callback, &cbt /* Call back variables */);
switch_safe_free(sql);
/* We update a field in the queue struct so we can kick caller out if waiting for too long with no agent */
- if (!cbt.queue_name || !(queue = get_queue(cbt.queue_name))) {
+ if (!cbt.queue_name || !(queue = get_queue(profile, cbt.queue_name))) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Queue %s not found locally, skip this member\n", cbt.queue_name);
goto end;
} else {
@@ -2605,6 +2919,8 @@ static int members_callback(void *pArg, int argc, char **argv, char **columnName
}
end:
+ profile_rwunlock(profile);
+
switch_safe_free(queue_name);
switch_safe_free(queue_strategy);
switch_safe_free(queue_record_template);
@@ -2612,78 +2928,120 @@ end:
return 0;
}
-static int AGENT_DISPATCH_THREAD_RUNNING = 0;
-static int AGENT_DISPATCH_THREAD_STARTED = 0;
+struct cc_agent_dispatch_thread_helper {
+ const char *profile_name;
+
+ int running;
+ switch_memory_pool_t *pool;
+};
void *SWITCH_THREAD_FUNC cc_agent_dispatch_thread_run(switch_thread_t *thread, void *obj)
{
+ struct cc_agent_dispatch_thread_helper *h = (struct cc_agent_dispatch_thread_helper *) obj;
int done = 0;
+ cc_profile_t *profile = NULL;
switch_mutex_lock(globals.mutex);
- if (!AGENT_DISPATCH_THREAD_RUNNING) {
- AGENT_DISPATCH_THREAD_RUNNING++;
- globals.threads++;
+ globals.threads++;
+ switch_mutex_unlock(globals.mutex);
+
+ if (!h->profile_name || !(profile = get_profile(h->profile_name))) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Profile %s not found\n", h->profile_name);
+ goto end;
+
+ }
+
+ switch_mutex_lock(profile->mutex);
+ if (!profile->AGENT_DISPATCH_THREAD_RUNNING) {
+ profile->AGENT_DISPATCH_THREAD_RUNNING++;
+ profile->threads++;
+
} else {
done = 1;
}
- switch_mutex_unlock(globals.mutex);
+ switch_mutex_unlock(profile->mutex);
if (done) {
- return NULL;
+ goto end;
}
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Agent Dispatch Thread Started\n");
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Agent Dispatch Thread Started for profile %s\n", profile->name);
- while (globals.running == 1) {
+ while (globals.running == 1 && !(profile->threads == 1 && switch_test_flag(profile, PFLAG_DESTROY))) {
+
char *sql = NULL;
- sql = switch_mprintf("SELECT queue,uuid,session_uuid,cid_number,cid_name,joined_epoch,(%" SWITCH_TIME_T_FMT "-joined_epoch)+base_score+skill_score AS score, state, abandoned_epoch, serving_agent, system FROM members"
+ sql = switch_mprintf("SELECT queue,uuid,session_uuid,cid_number,cid_name,joined_epoch,(%" SWITCH_TIME_T_FMT "-joined_epoch)+base_score+skill_score AS score, state, abandoned_epoch, serving_agent, system, '%q' as profile FROM members"
" WHERE (state = '%q' OR state = '%q' OR (serving_agent = 'ring-all' AND state = '%q') OR (serving_agent = 'ring-progressively' AND state = '%q')) AND system = '%q' ORDER BY score DESC",
- local_epoch_time_now(NULL),
+ local_epoch_time_now(NULL), profile->name,
cc_member_state2str(CC_MEMBER_STATE_WAITING), cc_member_state2str(CC_MEMBER_STATE_ABANDONED), cc_member_state2str(CC_MEMBER_STATE_TRYING), cc_member_state2str(CC_MEMBER_STATE_TRYING), globals.core_uuid);
- cc_execute_sql_callback(NULL /* queue */, NULL /* mutex */, sql, members_callback, NULL /* Call back variables */);
+ cc_execute_sql_callback(profile, NULL /* queue */, NULL /* mutex */, sql, members_callback, NULL /* Call back variables */);
switch_safe_free(sql);
switch_yield(100000);
}
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Agent Dispatch Thread Ended\n");
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Agent Dispatch Thread Ended for profile %s\n", profile->name);
+ switch_mutex_lock(profile->mutex);
+ profile->threads--;
+ profile->AGENT_DISPATCH_THREAD_RUNNING = profile->AGENT_DISPATCH_THREAD_STARTED = 0;
+ switch_mutex_unlock(profile->mutex);
+end:
switch_mutex_lock(globals.mutex);
globals.threads--;
- AGENT_DISPATCH_THREAD_RUNNING = AGENT_DISPATCH_THREAD_STARTED = 0;
switch_mutex_unlock(globals.mutex);
+ profile_rwunlock(profile);
+
return NULL;
}
-
-void cc_agent_dispatch_thread_start(void)
+void cc_agent_dispatch_thread_start(const char *profile_name)
{
switch_thread_t *thread;
switch_threadattr_t *thd_attr = NULL;
int done = 0;
+ cc_profile_t *profile = NULL;
+ struct cc_agent_dispatch_thread_helper *h = NULL;
+ switch_memory_pool_t *pool;
- switch_mutex_lock(globals.mutex);
+ if (!profile_name || !(profile = get_profile(profile_name))) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Profile %s not found\n", profile_name);
+ goto end;
- if (!AGENT_DISPATCH_THREAD_STARTED) {
- AGENT_DISPATCH_THREAD_STARTED++;
+ }
+
+ switch_mutex_lock(profile->mutex);
+
+ if (!profile->AGENT_DISPATCH_THREAD_STARTED) {
+ profile->AGENT_DISPATCH_THREAD_STARTED++;
} else {
done = 1;
}
- switch_mutex_unlock(globals.mutex);
+ switch_mutex_unlock(profile->mutex);
if (done) {
return;
}
- switch_threadattr_create(&thd_attr, globals.pool);
+ switch_core_new_memory_pool(&pool);
+ h = switch_core_alloc(pool, sizeof(*h));
+ h->pool = pool;
+
+ h->profile_name = switch_core_strdup(h->pool, profile->name);
+ switch_threadattr_create(&thd_attr, h->pool);
switch_threadattr_detach_set(thd_attr, 1);
switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
switch_threadattr_priority_set(thd_attr, SWITCH_PRI_REALTIME);
- switch_thread_create(&thread, thd_attr, cc_agent_dispatch_thread_run, NULL, globals.pool);
+ switch_thread_create(&thread, thd_attr, cc_agent_dispatch_thread_run, h, h->pool);
+
+end:
+ profile_rwunlock(profile);
+ return;
}
struct member_thread_helper {
+ const char *profile_name;
const char *queue_name;
const char *member_uuid;
const char *member_session_uuid;
@@ -2699,27 +3057,37 @@ struct member_thread_helper {
void *SWITCH_THREAD_FUNC cc_member_thread_run(switch_thread_t *thread, void *obj)
{
struct member_thread_helper *m = (struct member_thread_helper *) obj;
+ cc_profile_t *profile = NULL;
switch_core_session_t *member_session = switch_core_session_locate(m->member_session_uuid);
switch_channel_t *member_channel = NULL;
switch_time_t last_announce = local_epoch_time_now(NULL);
switch_bool_t announce_valid = SWITCH_TRUE;
- if (member_session) {
- member_channel = switch_core_session_get_channel(member_session);
- } else {
- switch_core_destroy_memory_pool(&m->pool);
- return NULL;
- }
-
switch_mutex_lock(globals.mutex);
globals.threads++;
switch_mutex_unlock(globals.mutex);
+ if (member_session) {
+ member_channel = switch_core_session_get_channel(member_session);
+ } else {
+ goto done;
+ }
+
+ if (!m->profile_name || !(profile = get_profile(m->profile_name))) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Profile %s not found\n", m->profile_name);
+ goto done;
+
+ }
+
+ switch_mutex_lock(profile->mutex);
+ profile->threads++;
+ switch_mutex_unlock(profile->mutex);
+
while(switch_channel_ready(member_channel) && m->running && globals.running) {
cc_queue_t *queue = NULL;
switch_time_t time_now = local_epoch_time_now(NULL);
- if (!m->queue_name || !(queue = get_queue(m->queue_name))) {
+ if (!m->queue_name || !(queue = get_queue(profile, m->queue_name))) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member_session), SWITCH_LOG_WARNING, "Queue %s not found\n", m->queue_name);
break;
}
@@ -2789,7 +3157,18 @@ void *SWITCH_THREAD_FUNC cc_member_thread_run(switch_thread_t *thread, void *obj
switch_yield(500000);
}
- switch_core_session_rwunlock(member_session);
+done:
+ if (profile) {
+ switch_mutex_lock(profile->mutex);
+ profile->threads--;
+ switch_mutex_unlock(profile->mutex);
+ }
+
+ profile_rwunlock(profile);
+
+ if (member_session) {
+ switch_core_session_rwunlock(member_session);
+ }
switch_core_destroy_memory_pool(&m->pool);
switch_mutex_lock(globals.mutex);
@@ -2857,6 +3236,10 @@ SWITCH_STANDARD_APP(callcenter_function)
switch_bool_t agent_found = SWITCH_FALSE;
switch_bool_t moh_valid = SWITCH_TRUE;
const char *p;
+ const char *profile_name = "default";
+ char *dup = NULL;
+
+ cc_profile_t *profile = NULL;
if (!zstr(data)) {
mydata = switch_core_session_strdup(member_session, data);
@@ -2867,10 +3250,26 @@ SWITCH_STANDARD_APP(callcenter_function)
}
if (argv[0]) {
- queue_name = argv[0];
+ char *p;
+
+ queue_name = dup = strdup(argv[0]);
+
+ if ((p = strchr(dup, '/'))) {
+ *p++ = '\0';
+ queue_name = p;
+ profile_name = dup;
+ }
}
- if (!queue_name || !(queue = get_queue(queue_name))) {
+ if (!profile_name || !(profile = get_profile(profile_name))) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Profile %s not found\n", profile_name);
+ goto end;
+
+ }
+
+ switch_channel_set_variable(member_channel, "cc_profile", profile_name);
+
+ if (!queue_name || !(queue = get_queue(profile, queue_name))) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member_session), SWITCH_LOG_WARNING, "Queue %s not found\n", queue_name);
goto end;
}
@@ -2889,13 +3288,13 @@ SWITCH_STANDARD_APP(callcenter_function)
/* Check to see if agent already exist */
sql = switch_mprintf("SELECT uuid FROM members WHERE queue = '%q' AND cid_number = '%q' AND state = '%q' ORDER BY abandoned_epoch DESC",
queue_name, switch_str_nil(switch_channel_get_variable(member_channel, "caller_id_number")), cc_member_state2str(CC_MEMBER_STATE_ABANDONED));
- cc_execute_sql2str(NULL, NULL, sql, res, sizeof(res));
+ cc_execute_sql2str(profile, NULL, NULL, sql, res, sizeof(res));
switch_safe_free(sql);
strncpy(member_uuid, res, sizeof(member_uuid));
if (!zstr(member_uuid)) {
sql = switch_mprintf("SELECT abandoned_epoch FROM members WHERE uuid = '%q'", member_uuid);
- cc_execute_sql2str(NULL, NULL, sql, res, sizeof(res));
+ cc_execute_sql2str(profile, NULL, NULL, sql, res, sizeof(res));
switch_safe_free(sql);
abandoned_epoch = atol(res);
}
@@ -2933,19 +3332,18 @@ SWITCH_STANDARD_APP(callcenter_function)
/* Update abandoned member */
sql = switch_mprintf("UPDATE members SET session_uuid = '%q', state = '%q', rejoined_epoch = '%" SWITCH_TIME_T_FMT "', system = '%q' WHERE uuid = '%q' AND state = '%q'",
member_session_uuid, cc_member_state2str(CC_MEMBER_STATE_WAITING), local_epoch_time_now(NULL), globals.core_uuid, member_uuid, cc_member_state2str(CC_MEMBER_STATE_ABANDONED));
- cc_execute_sql(queue, sql, NULL);
+ cc_execute_sql(profile, queue, sql, NULL);
switch_safe_free(sql);
/* Confirm we took that member in */
sql = switch_mprintf("SELECT abandoned_epoch FROM members WHERE uuid = '%q' AND session_uuid = '%q' AND state = '%q' AND queue = '%q'", member_uuid, member_session_uuid, cc_member_state2str(CC_MEMBER_STATE_WAITING), queue_name);
- cc_execute_sql2str(NULL, NULL, sql, res, sizeof(res));
+ cc_execute_sql2str(profile, NULL, NULL, sql, res, sizeof(res));
switch_safe_free(sql);
abandoned_epoch = atol(res);
if (abandoned_epoch == 0) {
/* Failed to get the member !!! */
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member_session), SWITCH_LOG_ERROR, "Member %s <%s> restoring action failed in queue %s, joining again\n", switch_str_nil(switch_channel_get_variable(member_channel, "caller_id_name")), switch_str_nil(switch_channel_get_variable(member_channel, "caller_id_number")), queue_name);
- //queue_rwunlock(queue);
} else {
}
@@ -2954,6 +3352,7 @@ SWITCH_STANDARD_APP(callcenter_function)
if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CALLCENTER_EVENT) == SWITCH_STATUS_SUCCESS) {
switch_channel_event_set_data(member_channel, event);
+ switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Profile", profile->name);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Queue", queue_name);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Action", "member-queue-%s", (abandoned_epoch==0?"start":"resume"));
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Member-UUID", member_uuid);
@@ -2963,7 +3362,6 @@ SWITCH_STANDARD_APP(callcenter_function)
switch_event_fire(&event);
}
-
if (abandoned_epoch == 0) {
char *strategy_str = NULL;
/* Add the caller to the member queue */
@@ -2991,13 +3389,13 @@ SWITCH_STANDARD_APP(callcenter_function)
switch_str_nil(switch_channel_get_variable(member_channel, "caller_id_name")),
strategy_str,
cc_member_state2str(CC_MEMBER_STATE_WAITING));
- cc_execute_sql(queue, sql, NULL);
+ cc_execute_sql(profile, queue, sql, NULL);
switch_safe_free(sql);
}
/* Send Event with queue count */
- cc_queue_count(queue_name);
- cc_send_presence(queue_name);
+ cc_queue_count(profile, queue_name);
+ cc_send_presence(profile, queue_name);
/* Start Thread that will playback different prompt to the channel */
switch_core_new_memory_pool(&pool);
@@ -3012,6 +3410,7 @@ SWITCH_STANDARD_APP(callcenter_function)
h->t_member_called = t_member_called;
h->member_cancel_reason = CC_MEMBER_CANCEL_REASON_NONE;
h->running = 1;
+ h->profile_name = switch_core_strdup(h->pool, profile->name);
switch_threadattr_create(&thd_attr, h->pool);
switch_threadattr_detach_set(thd_attr, 1);
@@ -3099,7 +3498,7 @@ SWITCH_STANDARD_APP(callcenter_function)
/* Update member state */
sql = switch_mprintf("UPDATE members SET state = '%q', session_uuid = '', abandoned_epoch = '%" SWITCH_TIME_T_FMT "' WHERE uuid = '%q' AND system = '%q'",
cc_member_state2str(CC_MEMBER_STATE_ABANDONED), local_epoch_time_now(NULL), member_uuid, globals.core_uuid);
- cc_execute_sql(NULL, sql, NULL);
+ cc_execute_sql(profile, NULL, sql, NULL);
switch_safe_free(sql);
/* Hangup any callback agents */
@@ -3108,6 +3507,7 @@ SWITCH_STANDARD_APP(callcenter_function)
/* Generate an event */
if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CALLCENTER_EVENT) == SWITCH_STATUS_SUCCESS) {
switch_channel_event_set_data(member_channel, event);
+ switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Profile", profile->name);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Queue", queue_name);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Action", "member-queue-end");
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Member-Leaving-Time", "%" SWITCH_TIME_T_FMT, local_epoch_time_now(NULL));
@@ -3131,7 +3531,7 @@ SWITCH_STANDARD_APP(callcenter_function)
switch_str_nil(switch_channel_get_variable(member_channel, "caller_id_name")),
switch_str_nil(switch_channel_get_variable(member_channel, "caller_id_number")),
queue_name, cc_member_cancel_reason2str(h->member_cancel_reason));
- if ((queue = get_queue(queue_name))) {
+ if ((queue = get_queue(profile, queue_name))) {
queue->calls_abandoned++;
queue_rwunlock(queue);
}
@@ -3141,12 +3541,12 @@ SWITCH_STANDARD_APP(callcenter_function)
/* Update member state */
sql = switch_mprintf("UPDATE members SET state = '%q', bridge_epoch = '%" SWITCH_TIME_T_FMT "' WHERE uuid = '%q' AND system = '%q'",
cc_member_state2str(CC_MEMBER_STATE_ANSWERED), local_epoch_time_now(NULL), member_uuid, globals.core_uuid);
- cc_execute_sql(NULL, sql, NULL);
+ cc_execute_sql(profile, NULL, sql, NULL);
switch_safe_free(sql);
/* Update some channel variables for xml_cdr needs */
switch_channel_set_variable_printf(member_channel, "cc_cause", "%s", "answered");
- if ((queue = get_queue(queue_name))) {
+ if ((queue = get_queue(profile, queue_name))) {
queue->calls_answered++;
queue_rwunlock(queue);
}
@@ -3154,10 +3554,12 @@ SWITCH_STANDARD_APP(callcenter_function)
}
/* Send Event with queue count */
- cc_queue_count(queue_name);
- cc_send_presence(queue_name);
+ cc_queue_count(profile, queue_name);
+ cc_send_presence(profile, queue_name);
end:
+ profile_rwunlock(profile);
+ switch_safe_free(dup);
return;
}
@@ -3169,7 +3571,20 @@ static switch_status_t cc_hook_state_run(switch_core_session_t *session)
switch_channel_t *channel = switch_core_session_get_channel(session);
switch_channel_state_t state = switch_channel_get_state(channel);
const char *agent_name = NULL;
+ const char *profile_name = NULL;
char *sql = NULL;
+ cc_profile_t *profile = NULL;
+
+ profile_name = switch_channel_get_variable(channel, "cc_profile");
+
+ if (!profile_name || !(profile = get_profile(profile_name))) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Profile %s not found\n", profile_name);
+ switch_core_event_hook_remove_state_run(session, cc_hook_state_run);
+ UNPROTECT_INTERFACE(app_interface);
+ return SWITCH_STATUS_SUCCESS;
+
+ }
+
agent_name = switch_channel_get_variable(channel, "cc_tracked_agent");
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Called cc_hook_hanguphook channel %s with state %s", switch_channel_get_name(channel), switch_channel_state_name(state));
@@ -3177,12 +3592,14 @@ static switch_status_t cc_hook_state_run(switch_core_session_t *session)
if (state == CS_HANGUP) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Tracked call for agent %s ended, decreasing external_calls_count", agent_name);
sql = switch_mprintf("UPDATE agents SET external_calls_count = external_calls_count - 1 WHERE name = '%q'", agent_name);
- cc_execute_sql(NULL, sql, NULL);
+ cc_execute_sql(profile, NULL, sql, NULL);
switch_safe_free(sql);
switch_core_event_hook_remove_state_run(session, cc_hook_state_run);
UNPROTECT_INTERFACE(app_interface);
}
+ profile_rwunlock(profile);
+
return SWITCH_STATUS_SUCCESS;
}
@@ -3192,41 +3609,61 @@ SWITCH_STANDARD_APP(callcenter_track)
char agent_status[255];
char *agent_name = NULL;
char *sql = NULL;
+ char *p, *dup;
+ char *profile_name = "default";
+ cc_profile_t *profile = NULL;
if (zstr(data)) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Missing agent name\n");
return;
}
- if (cc_agent_get("status", data, agent_status, sizeof(agent_status)) != CC_STATUS_SUCCESS) {
- switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Invalid agent %s", data);
- return;
+ agent_name = dup = switch_safe_strdup(data);
+
+ if ((p = strchr(dup, '/'))) {
+ *p++ = '\0';
+ agent_name = p;
+ profile_name = dup;
}
- agent_name = switch_safe_strdup(data);
+ if (!profile_name || !(profile = get_profile(profile_name))) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Profile %s not found\n", profile_name);
+ goto end;
+
+ }
+
+ switch_channel_set_variable(channel, "cc_profile", profile_name);
+
+ if (cc_agent_get(profile, "status", data, agent_status, sizeof(agent_status)) != CC_STATUS_SUCCESS) {
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Invalid agent %s", data);
+ goto end;
+ }
switch_channel_set_variable(channel, "cc_tracked_agent", agent_name);
sql = switch_mprintf("UPDATE agents SET external_calls_count = external_calls_count + 1 WHERE name = '%q'", agent_name);
- cc_execute_sql(NULL, sql, NULL);
+ cc_execute_sql(profile, NULL, sql, NULL);
switch_safe_free(sql);
switch_core_event_hook_add_state_run(session, cc_hook_state_run);
PROTECT_INTERFACE(app_interface);
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Tracking this call for agent %s", data);
- switch_safe_free(agent_name);
+
+end:
+ profile_rwunlock(profile);
+ switch_safe_free(dup);
return;
}
-static void cc_send_presence(const char *queue_name) {
+static void cc_send_presence(cc_profile_t *profile, const char *queue_name) {
char *sql;
char res[256] = "";
int count = 0;
switch_event_t *send_event;
sql = switch_mprintf("SELECT COUNT(*) FROM members WHERE queue = '%q' AND state = '%q'", queue_name, cc_member_state2str(CC_MEMBER_STATE_WAITING));
- cc_execute_sql2str(NULL, NULL, sql, res, sizeof(res));
+ cc_execute_sql2str(profile, NULL, NULL, sql, res, sizeof(res));
count = atoi(res);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Queue has %d waiting calls.\n", count);
@@ -3260,30 +3697,46 @@ static void cc_send_presence(const char *queue_name) {
static void cc_presence_event_handler(switch_event_t *event) {
char *to = switch_event_get_header(event, "to");
- char *dup_to = NULL, *queue_name;
+ char *queue_name;
cc_queue_t *queue;
+ char *p, *dup = NULL;
+ char *profile_name = "default";
+ cc_profile_t *profile = NULL;
if (!globals.running) {
- return;
+ goto end;
}
// DUMP_EVENT(event);
if (!to || strncasecmp(to, "callcenter+", 11) || !strchr(to, '@')) {
- return;
+ goto end;
}
- dup_to = strdup(to);
- queue_name = dup_to + 11;
+ queue_name = dup = switch_safe_strdup(to + 11);
+
+ if ((p = strchr(dup, '/'))) {
+ *p++ = '\0';
+ queue_name = p;
+ profile_name = dup;
+ }
+
+ if (!profile_name || !(profile = get_profile(profile_name))) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Profile %s not found\n", profile_name);
+ goto end;
+
+ }
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Searching queue %s\n", queue_name);
- queue = get_queue(queue_name);
+ queue = get_queue(profile, queue_name);
if (!queue) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Queue not found, exit!\n");
- return;
+ goto end;
}
- cc_send_presence(queue_name);
+ cc_send_presence(profile, queue_name);
queue_rwunlock(queue);
- switch_safe_free(dup_to);
+end:
+ profile_rwunlock(profile);
+ switch_safe_free(dup);
return;
}
@@ -3345,38 +3798,42 @@ static int list_result_json_callback(void *pArg, int argc, char **argv, char **c
}
#define CC_CONFIG_API_SYNTAX "callcenter_config ,\n"\
-"\tcallcenter_config agent add [name] [type] | \n" \
-"\tcallcenter_config agent del [name] | \n" \
-"\tcallcenter_config agent reload [name] | \n" \
-"\tcallcenter_config agent set status [agent_name] [status] | \n" \
-"\tcallcenter_config agent set state [agent_name] [state] | \n" \
-"\tcallcenter_config agent set contact [agent_name] [contact] | \n" \
-"\tcallcenter_config agent set ready_time [agent_name] [wait till epoch] | \n"\
-"\tcallcenter_config agent set reject_delay_time [agent_name] [wait second] | \n"\
-"\tcallcenter_config agent set busy_delay_time [agent_name] [wait second] | \n"\
-"\tcallcenter_config agent set no_answer_delay_time [agent_name] [wait second] | \n"\
-"\tcallcenter_config agent get status [agent_name] | \n" \
-"\tcallcenter_config agent get state [agent_name] | \n" \
-"\tcallcenter_config agent get uuid [agent_name] | \n" \
-"\tcallcenter_config agent list [[agent_name]] | \n" \
-"\tcallcenter_config tier add [queue_name] [agent_name] [[level]] [[position]] | \n" \
-"\tcallcenter_config tier set state [queue_name] [agent_name] [state] | \n" \
-"\tcallcenter_config tier set level [queue_name] [agent_name] [level] | \n" \
-"\tcallcenter_config tier set position [queue_name] [agent_name] [position] | \n" \
-"\tcallcenter_config tier del [queue_name] [agent_name] | \n" \
-"\tcallcenter_config tier reload [queue_name] [agent_name] | \n" \
-"\tcallcenter_config tier list | \n" \
-"\tcallcenter_config queue load [queue_name] | \n" \
-"\tcallcenter_config queue unload [queue_name] | \n" \
-"\tcallcenter_config queue reload [queue_name] | \n" \
-"\tcallcenter_config queue list | \n" \
-"\tcallcenter_config queue list agents [queue_name] [status] [state] | \n" \
-"\tcallcenter_config queue list members [queue_name] | \n" \
-"\tcallcenter_config queue list tiers [queue_name] | \n" \
-"\tcallcenter_config queue count | \n" \
-"\tcallcenter_config queue count agents [queue_name] [status] [state] | \n" \
-"\tcallcenter_config queue count members [queue_name] | \n" \
-"\tcallcenter_config queue count tiers [queue_name]"
+"\tcallcenter_config profile list | \n" \
+"\tcallcenter_config profile load [name] | \n" \
+"\tcallcenter_config profile unload [name] | \n" \
+"\tcallcenter_config profile reload [name] | \n" \
+"\tcallcenter_config [profile/]agent add [name] [type] | \n" \
+"\tcallcenter_config [profile/]agent del [name] | \n" \
+"\tcallcenter_config [profile/]agent reload [name] | \n" \
+"\tcallcenter_config [profile/]agent set status [agent_name] [status] | \n" \
+"\tcallcenter_config [profile/]agent set state [agent_name] [state] | \n" \
+"\tcallcenter_config [profile/]agent set contact [agent_name] [contact] | \n" \
+"\tcallcenter_config [profile/]agent set ready_time [agent_name] [wait till epoch] | \n"\
+"\tcallcenter_config [profile/]agent set reject_delay_time [agent_name] [wait second] | \n"\
+"\tcallcenter_config [profile/]agent set busy_delay_time [agent_name] [wait second] | \n"\
+"\tcallcenter_config [profile/]agent set no_answer_delay_time [agent_name] [wait second] | \n"\
+"\tcallcenter_config [profile/]agent get status [agent_name] | \n" \
+"\tcallcenter_config [profile/]agent get state [agent_name] | \n" \
+"\tcallcenter_config [profile/]agent get uuid [agent_name] | \n" \
+"\tcallcenter_config [profile/]agent list [[agent_name]] | \n" \
+"\tcallcenter_config [profile/]tier add [queue_name] [agent_name] [[level]] [[position]] | \n" \
+"\tcallcenter_config [profile/]tier set state [queue_name] [agent_name] [state] | \n" \
+"\tcallcenter_config [profile/]tier set level [queue_name] [agent_name] [level] | \n" \
+"\tcallcenter_config [profile/]tier set position [queue_name] [agent_name] [position] | \n" \
+"\tcallcenter_config [profile/]tier del [queue_name] [agent_name] | \n" \
+"\tcallcenter_config [profile/]tier reload [queue_name] [agent_name] | \n" \
+"\tcallcenter_config [profile/]tier list | \n" \
+"\tcallcenter_config [profile/]queue load [queue_name] | \n" \
+"\tcallcenter_config [profile/]queue unload [queue_name] | \n" \
+"\tcallcenter_config [profile/]queue reload [queue_name] | \n" \
+"\tcallcenter_config [profile/]queue list | \n" \
+"\tcallcenter_config [profile/]queue list agents [queue_name] [status] [state] | \n" \
+"\tcallcenter_config [profile/]queue list members [queue_name] | \n" \
+"\tcallcenter_config [profile/]queue list tiers [queue_name] | \n" \
+"\tcallcenter_config [profile/]queue count | \n" \
+"\tcallcenter_config [profile/]queue count agents [queue_name] [status] [state] | \n" \
+"\tcallcenter_config [profile/]queue count members [queue_name] | \n" \
+"\tcallcenter_config [profile/]queue count tiers [queue_name]"
SWITCH_STANDARD_API(cc_config_api_function)
{
@@ -3387,6 +3844,11 @@ SWITCH_STANDARD_API(cc_config_api_function)
int initial_argc = 2;
int argc;
+
+ char *p, *dup = NULL;
+ const char *profile_name = "default";
+ cc_profile_t *profile = NULL;
+
if (!globals.running) {
return SWITCH_STATUS_FALSE;
}
@@ -3405,10 +3867,83 @@ SWITCH_STANDARD_API(cc_config_api_function)
goto done;
}
- section = argv[0];
- action = argv[1];
+ section = dup = switch_safe_strdup(argv[0]);
+
+ if ((p = strchr(dup, '/'))) {
+ *p++ = '\0';
+ section = p;
+ profile_name = dup;
+ }
+
+ action = argv[1];
+
+ if (section && !strcasecmp(section, "profile")) {
+ if (action && !strcasecmp(action, "list")) {
+ switch_hash_index_t *hi;
+
+ stream->write_function(stream, "%s", "profile_name\n");
+ switch_mutex_lock(globals.mutex);
+ for (hi = switch_core_hash_first(globals.profile_hash); hi; hi = switch_core_hash_next(&hi)) {
+ void *val = NULL;
+ const void *key;
+ switch_ssize_t keylen;
+ cc_profile_t *profile = NULL;
+
+ switch_core_hash_this(hi, &key, &keylen, &val);
+ profile = (cc_profile_t *) val;
+ stream->write_function(stream, "%s\n", profile->name);
+ }
+ switch_mutex_unlock(globals.mutex);
+ stream->write_function(stream, "%s", "+OK\n");
+ } else if (action && !strcasecmp(action, "load")) {
+ if (argc-initial_argc < 1) {
+ stream->write_function(stream, "%s", "-ERR Invalid!\n");
+ goto done;
+ } else {
+ const char *l_profile_name = argv[0 + initial_argc];
+ cc_profile_t *l_profile = NULL;
+ if ((l_profile = load_profile(l_profile_name))) {
+ stream->write_function(stream, "%s", "+OK\n");
+ } else {
+ stream->write_function(stream, "%s", "-ERR Invalid Queue not found!\n");
+ }
+ }
+
+ } else if (action && !strcasecmp(action, "unload")) {
+ if (argc-initial_argc < 1) {
+ stream->write_function(stream, "%s", "-ERR Invalid!\n");
+ goto done;
+ } else {
+ const char *l_profile_name = argv[0 + initial_argc];
+ destroy_profile(l_profile_name);
+ stream->write_function(stream, "%s", "+OK\n");
+
+ }
+
+ } else if (action && !strcasecmp(action, "reload")) {
+ if (argc-initial_argc < 1) {
+ stream->write_function(stream, "%s", "-ERR Invalid!\n");
+ goto done;
+ } else {
+ const char *l_profile_name = argv[0 + initial_argc];
+ cc_profile_t *l_profile = NULL;
+ destroy_profile(l_profile_name);
+ if ((l_profile = load_profile(l_profile_name))) {
+ stream->write_function(stream, "%s", "+OK\n");
+ } else {
+ stream->write_function(stream, "%s", "-ERR Invalid Queue not found!\n");
+ }
+ }
+
+ }
+ } else if (section && !strcasecmp(section, "agent")) {
+ if (!profile_name || !(profile = get_profile(profile_name))) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Profile %s not found locally\n", profile_name);
+ stream->write_function(stream, "-ERR Profile '%s' not found\n", profile_name);
+ goto done;
+
+ }
- if (section && !strcasecmp(section, "agent")) {
if (action && !strcasecmp(action, "add")) {
if (argc-initial_argc < 2) {
stream->write_function(stream, "%s", "-ERR Invalid!\n");
@@ -3416,7 +3951,7 @@ SWITCH_STANDARD_API(cc_config_api_function)
} else {
const char *name = argv[0 + initial_argc];
const char *type = argv[1 + initial_argc];
- switch (cc_agent_add(name, type)) {
+ switch (cc_agent_add(profile, name, type)) {
case CC_STATUS_SUCCESS:
stream->write_function(stream, "%s", "+OK\n");
break;
@@ -3440,7 +3975,7 @@ SWITCH_STANDARD_API(cc_config_api_function)
goto done;
} else {
const char *agent = argv[0 + initial_argc];
- switch (cc_agent_del(agent)) {
+ switch (cc_agent_del(profile, agent)) {
case CC_STATUS_SUCCESS:
stream->write_function(stream, "%s", "+OK\n");
break;
@@ -3456,7 +3991,7 @@ SWITCH_STANDARD_API(cc_config_api_function)
goto done;
} else {
const char *agent = argv[0 + initial_argc];
- switch (load_agent(agent, NULL, NULL)) {
+ switch (load_agent(profile, agent, NULL, NULL)) {
case SWITCH_STATUS_SUCCESS:
stream->write_function(stream, "%s", "+OK\n");
break;
@@ -3475,7 +4010,7 @@ SWITCH_STANDARD_API(cc_config_api_function)
const char *agent = argv[1 + initial_argc];
const char *value = argv[2 + initial_argc];
- switch (cc_agent_update(key, value, agent)) {
+ switch (cc_agent_update(profile, key, value, agent)) {
case CC_STATUS_SUCCESS:
stream->write_function(stream, "%s", "+OK\n");
break;
@@ -3509,7 +4044,7 @@ SWITCH_STANDARD_API(cc_config_api_function)
const char *key = argv[0 + initial_argc];
const char *agent = argv[1 + initial_argc];
char ret[64];
- switch (cc_agent_get(key, agent, ret, sizeof(ret))) {
+ switch (cc_agent_get(profile, key, agent, ret, sizeof(ret))) {
case CC_STATUS_SUCCESS:
stream->write_function(stream, "%s", ret);
break;
@@ -3535,16 +4070,23 @@ SWITCH_STANDARD_API(cc_config_api_function)
stream->write_function(stream, "%s", "-ERR Invalid!\n");
goto done;
} else if ( argc-initial_argc == 1 ) {
- sql = switch_mprintf("SELECT * FROM agents WHERE name='%q'", argv[0 + initial_argc]);
+ const char *agent_name = argv[0 + initial_argc];
+ sql = switch_mprintf("SELECT * FROM agents WHERE name='%q'", agent_name);
} else {
sql = switch_mprintf("SELECT * FROM agents");
}
- cc_execute_sql_callback(NULL /* queue */, NULL /* mutex */, sql, list_result_callback, &cbt /* Call back variables */);
+ cc_execute_sql_callback(profile, NULL /* queue */, NULL /* mutex */, sql, list_result_callback, &cbt /* Call back variables */);
switch_safe_free(sql);
stream->write_function(stream, "%s", "+OK\n");
}
} else if (section && !strcasecmp(section, "tier")) {
+ if (!profile_name || !(profile = get_profile(profile_name))) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Profile %s not found locally\n", profile_name);
+ stream->write_function(stream, "-ERR Profile '%s' not found\n", profile_name);
+ goto done;
+
+ }
if (action && !strcasecmp(action, "add")) {
if (argc-initial_argc < 2) {
stream->write_function(stream, "%s", "-ERR Invalid!\n");
@@ -3562,7 +4104,7 @@ SWITCH_STANDARD_API(cc_config_api_function)
i_position=atoi(position);
}
- switch(cc_tier_add(queue_name, agent, cc_tier_state2str(CC_TIER_STATE_READY), i_level, i_position)) {
+ switch(cc_tier_add(profile, queue_name, agent, cc_tier_state2str(CC_TIER_STATE_READY), i_level, i_position)) {
case CC_STATUS_SUCCESS:
stream->write_function(stream, "%s", "+OK\n");
break;
@@ -3594,7 +4136,7 @@ SWITCH_STANDARD_API(cc_config_api_function)
const char *agent = argv[2 + initial_argc];
const char *value = argv[3 + initial_argc];
- switch(cc_tier_update(key, value, queue_name, agent)) {
+ switch(cc_tier_update(profile, key, value, queue_name, agent)) {
case CC_STATUS_SUCCESS:
stream->write_function(stream, "%s", "+OK\n");
break;
@@ -3627,7 +4169,7 @@ SWITCH_STANDARD_API(cc_config_api_function)
} else {
const char *queue = argv[0 + initial_argc];
const char *agent = argv[1 + initial_argc];
- switch (cc_tier_del(queue, agent)) {
+ switch (cc_tier_del(profile, queue, agent)) {
case CC_STATUS_SUCCESS:
stream->write_function(stream, "%s", "+OK\n");
break;
@@ -3649,7 +4191,7 @@ SWITCH_STANDARD_API(cc_config_api_function)
if (!strcasecmp(queue, "all")) {
load_all = SWITCH_TRUE;
}
- switch (load_tiers(load_all, queue, agent, NULL, NULL)) {
+ switch (load_tiers(profile, load_all, queue, agent, NULL, NULL)) {
case SWITCH_STATUS_SUCCESS:
stream->write_function(stream, "%s", "+OK\n");
break;
@@ -3665,11 +4207,17 @@ SWITCH_STANDARD_API(cc_config_api_function)
cbt.row_process = 0;
cbt.stream = stream;
sql = switch_mprintf("SELECT * FROM tiers ORDER BY level, position");
- cc_execute_sql_callback(NULL /* queue */, NULL /* mutex */, sql, list_result_callback, &cbt /* Call back variables */);
+ cc_execute_sql_callback(profile, NULL /* queue */, NULL /* mutex */, sql, list_result_callback, &cbt /* Call back variables */);
switch_safe_free(sql);
stream->write_function(stream, "%s", "+OK\n");
}
} else if (section && !strcasecmp(section, "queue")) {
+ if (!profile_name || !(profile = get_profile(profile_name))) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Profile %s not found locally\n", profile_name);
+ stream->write_function(stream, "-ERR Profile '%s' not found\n", profile_name);
+ goto done;
+
+ }
if (action && !strcasecmp(action, "load")) {
if (argc-initial_argc < 1) {
stream->write_function(stream, "%s", "-ERR Invalid!\n");
@@ -3677,7 +4225,7 @@ SWITCH_STANDARD_API(cc_config_api_function)
} else {
const char *queue_name = argv[0 + initial_argc];
cc_queue_t *queue = NULL;
- if ((queue = load_queue(queue_name, SWITCH_TRUE, SWITCH_TRUE, NULL))) {
+ if ((queue = load_queue(profile, queue_name, SWITCH_TRUE, SWITCH_TRUE, NULL))) {
stream->write_function(stream, "%s", "+OK\n");
} else {
stream->write_function(stream, "%s", "-ERR Invalid Queue not found!\n");
@@ -3690,7 +4238,7 @@ SWITCH_STANDARD_API(cc_config_api_function)
goto done;
} else {
const char *queue_name = argv[0 + initial_argc];
- destroy_queue(queue_name);
+ destroy_queue(profile, queue_name);
stream->write_function(stream, "%s", "+OK\n");
}
@@ -3702,8 +4250,8 @@ SWITCH_STANDARD_API(cc_config_api_function)
} else {
const char *queue_name = argv[0 + initial_argc];
cc_queue_t *queue = NULL;
- destroy_queue(queue_name);
- if ((queue = load_queue(queue_name, SWITCH_TRUE, SWITCH_TRUE, NULL))) {
+ destroy_queue(profile, queue_name);
+ if ((queue = load_queue(profile, queue_name, SWITCH_TRUE, SWITCH_TRUE, NULL))) {
stream->write_function(stream, "%s", "+OK\n");
} else {
stream->write_function(stream, "%s", "-ERR Invalid Queue not found!\n");
@@ -3720,8 +4268,8 @@ SWITCH_STANDARD_API(cc_config_api_function)
"tier_rule_no_agent_no_wait|discard_abandoned_after|"\
"abandoned_resume_allowed|max_wait_time|max_wait_time_with_no_agent|"\
"max_wait_time_with_no_agent_time_reached|record_template|calls_answered|calls_abandoned|ring_progressively_delay|skip_agents_with_external_calls|agent_no_answer_status\n");
- switch_mutex_lock(globals.mutex);
- for (hi = switch_core_hash_first(globals.queue_hash); hi; hi = switch_core_hash_next(&hi)) {
+ switch_mutex_lock(profile->mutex);
+ for (hi = switch_core_hash_first(profile->queue_hash); hi; hi = switch_core_hash_next(&hi)) {
void *val = NULL;
const void *key;
switch_ssize_t keylen;
@@ -3750,7 +4298,7 @@ SWITCH_STANDARD_API(cc_config_api_function)
queue->agent_no_answer_status);
queue = NULL;
}
- switch_mutex_unlock(globals.mutex);
+ switch_mutex_unlock(profile->mutex);
stream->write_function(stream, "%s", "+OK\n");
goto done;
} else {
@@ -3793,7 +4341,7 @@ SWITCH_STANDARD_API(cc_config_api_function)
cbt.row_process = 0;
cbt.stream = stream;
- cc_execute_sql_callback(NULL /* queue */, NULL /* mutex */, sql, list_result_callback, &cbt /* Call back variables */);
+ cc_execute_sql_callback(profile, NULL /* queue */, NULL /* mutex */, sql, list_result_callback, &cbt /* Call back variables */);
switch_safe_free(sql);
stream->write_function(stream, "%s", "+OK\n");
}
@@ -3804,7 +4352,7 @@ SWITCH_STANDARD_API(cc_config_api_function)
switch_hash_index_t *hi;
int queue_count = 0;
switch_mutex_lock(globals.mutex);
- for (hi = switch_core_hash_first(globals.queue_hash); hi; hi = switch_core_hash_next(&hi)) {
+ for (hi = switch_core_hash_first(profile->queue_hash); hi; hi = switch_core_hash_next(&hi)) {
queue_count++;
}
switch_mutex_unlock(globals.mutex);
@@ -3844,7 +4392,7 @@ SWITCH_STANDARD_API(cc_config_api_function)
goto done;
}
- cc_execute_sql2str(NULL, NULL, sql, res, sizeof(res));
+ cc_execute_sql2str(profile, NULL, NULL, sql, res, sizeof(res));
switch_safe_free(sql);
stream->write_function(stream, "%d\n", atoi(res));
}
@@ -3853,6 +4401,8 @@ SWITCH_STANDARD_API(cc_config_api_function)
goto done;
done:
+ profile_rwunlock(profile);
+ switch_safe_free(dup);
free(mydata);
@@ -3863,26 +4413,52 @@ done:
SWITCH_STANDARD_JSON_API(json_callcenter_config_function)
{
+ switch_status_t status = SWITCH_STATUS_FALSE;
cJSON *data = cJSON_GetObjectItem(json, "data");
const char *error = NULL;
- const char *arguments = cJSON_GetObjectCstr(data, "arguments");
+ const char *arguments_orig = cJSON_GetObjectCstr(data, "arguments");
+ char *p, *dup = NULL;
+ const char *arguments;
+ const char *profile_name = "default";
+ cc_profile_t *profile = NULL;
+ char *sql = NULL;
/* Validate the arguments - try to keep it similar to the CLI api */
- if(zstr(arguments)){
- return SWITCH_STATUS_FALSE;
+ if(zstr(arguments_orig)){
+ goto done;
+ }
+
+ arguments = dup = switch_safe_strdup(arguments_orig);
+
+ if ((p = strchr(dup, '/'))) {
+ *p++ = '\0';
+ arguments = p;
+ profile_name = dup;
+ }
+
+ if (!profile_name || !(profile = get_profile(profile_name))) {
+ cJSON *error_reply = cJSON_CreateObject();
+
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Profile %s not found\n", profile_name);
+
+ error = "Profile not found";
+ cJSON_AddItemToObject(error_reply, "error", cJSON_CreateString(error));
+ *json_reply = error_reply;
+ status = SWITCH_STATUS_FALSE;
+ goto done;
+
}
/* Prepare the JSON for list of agents */
if(!strcasecmp(arguments, "agent list")){
struct list_result_json cbt;
- char *sql;
cbt.row_process = 0;
cbt.json_reply = cJSON_CreateArray();
sql = switch_mprintf("SELECT * FROM agents");
- cc_execute_sql_callback(NULL /* queue */, NULL /* mutex */, sql, list_result_json_callback, &cbt /* Call back variables */);
- switch_safe_free(sql);
+ cc_execute_sql_callback(profile, NULL /* queue */, NULL /* mutex */, sql, list_result_json_callback, &cbt /* Call back variables */);
*json_reply = cbt.json_reply;
- return SWITCH_STATUS_SUCCESS;
+ status = SWITCH_STATUS_SUCCESS;
+ goto done;
}
/* Prepare the JSON for list of queues */
@@ -3891,7 +4467,7 @@ SWITCH_STANDARD_JSON_API(json_callcenter_config_function)
switch_hash_index_t *hi;
switch_mutex_lock(globals.mutex);
- for (hi = switch_core_hash_first(globals.queue_hash); hi; hi = switch_core_hash_next(&hi)) {
+ for (hi = switch_core_hash_first(profile->queue_hash); hi; hi = switch_core_hash_next(&hi)) {
cJSON *o = cJSON_CreateObject();
void *val = NULL;
const void *key;
@@ -3899,6 +4475,7 @@ SWITCH_STANDARD_JSON_API(json_callcenter_config_function)
cc_queue_t *queue;
switch_core_hash_this(hi, &key, &keylen, &val);
queue = (cc_queue_t *) val;
+ cJSON_AddItemToObject(o, "profile", cJSON_CreateString(profile->name));
cJSON_AddItemToObject(o, "name", cJSON_CreateString(queue->name));
cJSON_AddItemToObject(o, "strategy", cJSON_CreateString(queue->strategy));
cJSON_AddItemToObject(o, "moh_sound", cJSON_CreateString(queue->moh));
@@ -3920,103 +4497,106 @@ SWITCH_STANDARD_JSON_API(json_callcenter_config_function)
}
switch_mutex_unlock(globals.mutex);
*json_reply = reply;
- return SWITCH_STATUS_SUCCESS;
+ status = SWITCH_STATUS_SUCCESS;
+ goto done;
}
/* Prepare the JSON for list of agents for a queue */
if(!strcasecmp(arguments, "queue list agents")){
struct list_result_json cbt;
const char *queue_name = cJSON_GetObjectCstr(data, "queue_name");
- char *sql;
cJSON *error_reply = cJSON_CreateObject();
if (zstr(queue_name)) {
error = "Missing data attribute: queue_name";
cJSON_AddItemToObject(error_reply, "error", cJSON_CreateString(error));
*json_reply = error_reply;
- return SWITCH_STATUS_FALSE;
+ status = SWITCH_STATUS_FALSE;
+ goto done;
}
cbt.row_process = 0;
cbt.json_reply = cJSON_CreateArray();
sql = switch_mprintf("SELECT agents.* FROM agents,tiers WHERE tiers.agent = agents.name AND tiers.queue = '%q'", queue_name);
- cc_execute_sql_callback(NULL /* queue */, NULL /* mutex */, sql, list_result_json_callback, &cbt /* Call back variables */);
- switch_safe_free(sql);
+ cc_execute_sql_callback(profile, NULL /* queue */, NULL /* mutex */, sql, list_result_json_callback, &cbt /* Call back variables */);
*json_reply = cbt.json_reply;
- return SWITCH_STATUS_SUCCESS;
+ status = SWITCH_STATUS_SUCCESS;
+ goto done;
}
/* Prepare the JSON for list of callers for a queue */
if(!strcasecmp(arguments, "queue list members")){
struct list_result_json cbt;
const char *queue_name = cJSON_GetObjectCstr(data, "queue_name");
- char *sql;
cJSON *error_reply = cJSON_CreateObject();
if (zstr(queue_name)) {
error = "Missing data attribute: queue_name";
cJSON_AddItemToObject(error_reply, "error", cJSON_CreateString(error));
*json_reply = error_reply;
- return SWITCH_STATUS_FALSE;
+ status = SWITCH_STATUS_FALSE;
+ goto done;
}
cbt.row_process = 0;
cbt.json_reply = cJSON_CreateArray();
sql = switch_mprintf("SELECT *,(%" SWITCH_TIME_T_FMT "-joined_epoch)+base_score+skill_score AS score FROM members WHERE queue = '%q' ORDER BY score DESC;", local_epoch_time_now(NULL), queue_name);
- cc_execute_sql_callback(NULL /* queue */, NULL /* mutex */, sql, list_result_json_callback, &cbt /* Call back variables */);
- switch_safe_free(sql);
+ cc_execute_sql_callback(profile, NULL /* queue */, NULL /* mutex */, sql, list_result_json_callback, &cbt /* Call back variables */);
*json_reply = cbt.json_reply;
- return SWITCH_STATUS_SUCCESS;
+ status = SWITCH_STATUS_SUCCESS;
+ goto done;
}
/* Prepare the JSON for list of tiers for a queue */
if(!strcasecmp(arguments, "queue list tiers")){
struct list_result_json cbt;
const char *queue_name = cJSON_GetObjectCstr(data, "queue_name");
- char *sql;
cJSON *error_reply = cJSON_CreateObject();
if (zstr(queue_name)) {
error = "Missing data attribute: queue_name";
cJSON_AddItemToObject(error_reply, "error", cJSON_CreateString(error));
*json_reply = error_reply;
- return SWITCH_STATUS_FALSE;
+ status = SWITCH_STATUS_FALSE;
+ goto done;
}
cbt.row_process = 0;
cbt.json_reply = cJSON_CreateArray();
sql = switch_mprintf("SELECT * FROM tiers WHERE queue = '%q';", queue_name);
- cc_execute_sql_callback(NULL /* queue */, NULL /* mutex */, sql, list_result_json_callback, &cbt /* Call back variables */);
- switch_safe_free(sql);
+ cc_execute_sql_callback(profile, NULL /* queue */, NULL /* mutex */, sql, list_result_json_callback, &cbt /* Call back variables */);
*json_reply = cbt.json_reply;
- return SWITCH_STATUS_SUCCESS;
+ status = SWITCH_STATUS_SUCCESS;
+ goto done;
}
/* Prepare the JSON for list of all callers */
if(!strcasecmp(arguments, "member list")){
struct list_result_json cbt;
- char *sql;
cbt.row_process = 0;
cbt.json_reply = cJSON_CreateArray();
sql = switch_mprintf("SELECT *,(%" SWITCH_TIME_T_FMT "-joined_epoch)+base_score+skill_score AS score FROM members ORDER BY score DESC;", local_epoch_time_now(NULL));
- cc_execute_sql_callback(NULL /* queue */, NULL /* mutex */, sql, list_result_json_callback, &cbt /* Call back variables */);
- switch_safe_free(sql);
+ cc_execute_sql_callback(profile, NULL /* queue */, NULL /* mutex */, sql, list_result_json_callback, &cbt /* Call back variables */);
*json_reply = cbt.json_reply;
- return SWITCH_STATUS_SUCCESS;
+ status = SWITCH_STATUS_SUCCESS;
+ goto done;
}
/* Prepare the JSON for list of all tiers */
if(!strcasecmp(arguments, "tier list")){
struct list_result_json cbt;
- char *sql;
cbt.row_process = 0;
cbt.json_reply = cJSON_CreateArray();
sql = switch_mprintf("SELECT * FROM tiers ORDER BY level, position");
- cc_execute_sql_callback(NULL /* queue */, NULL /* mutex */, sql, list_result_json_callback, &cbt /* Call back variables */);
- switch_safe_free(sql);
+ cc_execute_sql_callback(profile, NULL /* queue */, NULL /* mutex */, sql, list_result_json_callback, &cbt /* Call back variables */);
*json_reply = cbt.json_reply;
- return SWITCH_STATUS_SUCCESS;
+ status = SWITCH_STATUS_SUCCESS;
+ goto done;
}
/* if nothing was executed from above, it should return error */
- return SWITCH_STATUS_FALSE;
+done:
+ profile_rwunlock(profile);
+ switch_safe_free(dup);
+ switch_safe_free(sql);
+ return status;
}
@@ -4036,36 +4616,47 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_callcenter_load)
memset(&globals, 0, sizeof(globals));
globals.pool = pool;
- switch_core_hash_init(&globals.queue_hash);
switch_mutex_init(&globals.mutex, SWITCH_MUTEX_NESTED, globals.pool);
- if ((status = load_config()) != SWITCH_STATUS_SUCCESS) {
- return status;
- }
-
- if (switch_event_bind_removable(modname, SWITCH_EVENT_PRESENCE_PROBE, SWITCH_EVENT_SUBCLASS_ANY,
- cc_presence_event_handler, NULL, &globals.node) != SWITCH_STATUS_SUCCESS) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to subscribe for presence events!\n");
- return SWITCH_STATUS_GENERR;
- }
+ switch_core_hash_init(&globals.profile_hash);
switch_mutex_lock(globals.mutex);
globals.running = 1;
switch_mutex_unlock(globals.mutex);
+ if ((status = load_config()) != SWITCH_STATUS_SUCCESS) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "FAILED TO LOAD CONFIG?\n");
+ switch_mutex_lock(globals.mutex);
+ globals.running = 0;
+ switch_mutex_unlock(globals.mutex);
+
+ return status;
+ }
+ if (switch_event_bind_removable(modname, SWITCH_EVENT_PRESENCE_PROBE, SWITCH_EVENT_SUBCLASS_ANY,
+ cc_presence_event_handler, NULL, &globals.node) != SWITCH_STATUS_SUCCESS) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to subscribe for presence events!\n");
+ switch_mutex_lock(globals.mutex);
+ globals.running = 0;
+ switch_mutex_unlock(globals.mutex);
+
+ return SWITCH_STATUS_GENERR;
+ }
+
+
/* connect my internal structure to the blank pointer passed to me */
*module_interface = switch_loadable_module_create_module_interface(pool, modname);
- if (!AGENT_DISPATCH_THREAD_STARTED) {
- cc_agent_dispatch_thread_start();
- }
-
SWITCH_ADD_APP(app_interface, "callcenter", "CallCenter", CC_DESC, callcenter_function, CC_USAGE, SAF_NONE);
SWITCH_ADD_APP(app_interface, "callcenter_track", "CallCenter Track Call", "Track external mod_callcenter calls to avoid place new calls", callcenter_track, CC_USAGE, SAF_NONE);
SWITCH_ADD_API(api_interface, "callcenter_config", "Config of callcenter", cc_config_api_function, CC_CONFIG_API_SYNTAX);
SWITCH_ADD_JSON_API(json_api_interface, "callcenter_config", "JSON Callcenter API", json_callcenter_config_function, "");
+ switch_console_set_complete("add callcenter_config profile list");
+ switch_console_set_complete("add callcenter_config profile load");
+ switch_console_set_complete("add callcenter_config profile reload");
+ switch_console_set_complete("add callcenter_config profile unload");
+
switch_console_set_complete("add callcenter_config agent add");
switch_console_set_complete("add callcenter_config agent del");
switch_console_set_complete("add callcenter_config agent reload");
@@ -4110,7 +4701,6 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_callcenter_load)
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_callcenter_shutdown)
{
switch_hash_index_t *hi = NULL;
- cc_queue_t *queue;
void *val = NULL;
const void *key;
switch_ssize_t keylen;
@@ -4124,6 +4714,19 @@ SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_callcenter_shutdown)
if (globals.running == 1) {
globals.running = 0;
}
+
+ while ((hi = switch_core_hash_first_iter(globals.profile_hash, hi))) {
+ cc_profile_t *profile = NULL;
+
+ switch_core_hash_this(hi, &key, &keylen, &val);
+ profile = (cc_profile_t *) val;
+
+ destroy_profile(profile->name);
+ profile = NULL;
+
+
+ }
+
switch_mutex_unlock(globals.mutex);
while (globals.threads) {
@@ -4133,26 +4736,6 @@ SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_callcenter_shutdown)
}
}
- switch_mutex_lock(globals.mutex);
- while ((hi = switch_core_hash_first_iter( globals.queue_hash, hi))) {
- switch_core_hash_this(hi, &key, &keylen, &val);
- queue = (cc_queue_t *) val;
-
- switch_core_hash_delete(globals.queue_hash, queue->name);
-
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Waiting for write lock (queue %s)\n", queue->name);
- switch_thread_rwlock_wrlock(queue->rwlock);
-
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Destroying queue %s\n", queue->name);
-
- switch_core_destroy_memory_pool(&queue->pool);
- queue = NULL;
- }
-
- switch_safe_free(globals.odbc_dsn);
- switch_safe_free(globals.dbname);
- switch_mutex_unlock(globals.mutex);
-
return SWITCH_STATUS_SUCCESS;
}