dect
/
asterisk
Archived
13
0
Fork 0

Merging the work done in the queue-log-atxfer branch. The

net result of this work is that attended transfers made
by queue members will now show up in the queue_log as a 
TRANSFER message instead of COMPLETECALLER as it had been.

As far as the details go, I created a datastore which is
attached to the calling channel just prior to when the caller
is bridged with the queue member. If the calling channel
is masqueraded, then during the "fixup" portion, the TRANSFER
will be logged and the datastore will be removed.



git-svn-id: http://svn.digium.com/svn/asterisk/trunk@122228 f38db490-d61c-443f-a65b-d21fe96a405b
This commit is contained in:
mmichelson 2008-06-12 16:25:09 +00:00
parent 1a1d9a6c13
commit cfdbb7eb03
1 changed files with 96 additions and 14 deletions

View File

@ -529,6 +529,7 @@ static struct ao2_container *queues;
static void update_realtime_members(struct call_queue *q);
static int set_member_paused(const char *queuename, const char *interface, const char *reason, int paused);
static void queue_transfer_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan);
/*! \brief sets the QUEUESTATUS channel variable */
static void set_queue_result(struct ast_channel *chan, enum queue_result res)
{
@ -3042,6 +3043,82 @@ static void send_agent_complete(const struct queue_ent *qe, const char *queuenam
qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, vars_len) : "");
}
struct queue_transfer_ds {
struct queue_ent *qe;
struct member *member;
int starttime;
};
/*! \brief a datastore used to help correctly log attended transfers of queue callers
*/
static const struct ast_datastore_info queue_transfer_info = {
.type = "queue_transfer",
.chan_fixup = queue_transfer_fixup,
};
/*! \brief Log an attended transfer when a queue caller channel is masqueraded
*
* When a caller is masqueraded, we want to log a transfer. Fixup time is the closest we can come to when
* the actual transfer occurs. This happens during the masquerade after datastores are moved from old_chan
* to new_chan. This is why new_chan is referenced for exten, context, and datastore information.
*
* At the end of this, we want to remove the datastore so that this fixup function is not called on any
* future masquerades of the caller during the current call.
*/
static void queue_transfer_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
{
struct queue_transfer_ds *qtds = data;
struct queue_ent *qe = qtds->qe;
struct member *member = qtds->member;
int callstart = qtds->starttime;
struct ast_datastore *datastore;
ast_queue_log(qe->parent->name, qe->chan->uniqueid, member->membername, "TRANSFER", "%s|%s|%ld|%ld",
new_chan->exten, new_chan->context, (long) (callstart - qe->start),
(long) (time(NULL) - callstart));
if (!(datastore = ast_channel_datastore_find(new_chan, &queue_transfer_info, NULL))) {
ast_log(LOG_WARNING, "Can't find the queue_transfer datastore.\n");
return;
}
ast_channel_datastore_remove(new_chan, datastore);
}
/*! \brief mechanism to tell if a queue caller was atxferred by a queue member.
*
* When a caller is atxferred, then the queue_transfer_info datastore
* is removed from the channel. If it's still there after the bridge is
* broken, then the caller was not atxferred.
*/
static int attended_transfer_occurred(struct ast_channel *chan)
{
return ast_channel_datastore_find(chan, &queue_transfer_info, NULL) ? 0 : 1;
}
/*! \brief create a datastore for storing relevant info to log attended transfers in the queue_log
*/
static void setup_transfer_datastore(struct queue_ent *qe, struct member *member, int starttime)
{
struct ast_datastore *ds;
struct queue_transfer_ds qtds;
ast_channel_lock(qe->chan);
if (!(ds = ast_channel_datastore_alloc(&queue_transfer_info, NULL))) {
ast_channel_unlock(qe->chan);
ast_log(LOG_WARNING, "Unable to create transfer datastore. queue_log will not show attended transfer\n");
return;
}
qtds.qe = qe;
/* This member is refcounted in try_calling, so no need to add it here, too */
qtds.member = member;
qtds.starttime = starttime;
ds->data = &qtds;
ast_channel_datastore_add(qe->chan, ds);
ast_channel_unlock(qe->chan);
}
/*! \brief A large function which calls members, updates statistics, and bridges the caller and a member
*
* Here is the process of this function
@ -3681,22 +3758,27 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce
ast_copy_string(oldcontext, qe->chan->context, sizeof(oldcontext));
ast_copy_string(oldexten, qe->chan->exten, sizeof(oldexten));
time(&callstart);
setup_transfer_datastore(qe, member, callstart);
bridge = ast_bridge_call(qe->chan,peer, &bridge_config);
if (strcasecmp(oldcontext, qe->chan->context) || strcasecmp(oldexten, qe->chan->exten)) {
ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "TRANSFER", "%s|%s|%ld|%ld",
qe->chan->exten, qe->chan->context, (long) (callstart - qe->start),
(long) (time(NULL) - callstart));
send_agent_complete(qe, queuename, peer, member, callstart, vars, sizeof(vars), TRANSFER);
} else if (ast_check_hangup(qe->chan)) {
ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "COMPLETECALLER", "%ld|%ld|%d",
(long) (callstart - qe->start), (long) (time(NULL) - callstart), qe->opos);
send_agent_complete(qe, queuename, peer, member, callstart, vars, sizeof(vars), CALLER);
} else {
ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "COMPLETEAGENT", "%ld|%ld|%d",
(long) (callstart - qe->start), (long) (time(NULL) - callstart), qe->opos);
send_agent_complete(qe, queuename, peer, member, callstart, vars, sizeof(vars), AGENT);
/* If the queue member did an attended transfer, then the TRANSFER already was logged in the queue_log
* when the masquerade occurred. These other "ending" queue_log messages are unnecessary
*/
if (!attended_transfer_occurred(qe->chan)) {
if (strcasecmp(oldcontext, qe->chan->context) || strcasecmp(oldexten, qe->chan->exten)) {
ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "TRANSFER", "%s|%s|%ld|%ld",
qe->chan->exten, qe->chan->context, (long) (callstart - qe->start),
(long) (time(NULL) - callstart));
send_agent_complete(qe, queuename, peer, member, callstart, vars, sizeof(vars), TRANSFER);
} else if (ast_check_hangup(qe->chan)) {
ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "COMPLETECALLER", "%ld|%ld|%d",
(long) (callstart - qe->start), (long) (time(NULL) - callstart), qe->opos);
send_agent_complete(qe, queuename, peer, member, callstart, vars, sizeof(vars), CALLER);
} else {
ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "COMPLETEAGENT", "%ld|%ld|%d",
(long) (callstart - qe->start), (long) (time(NULL) - callstart), qe->opos);
send_agent_complete(qe, queuename, peer, member, callstart, vars, sizeof(vars), AGENT);
}
}
if (bridge != AST_PBX_NO_HANGUP_PEER)