From a2d02edca596415536a24c38f3a97f4c4e1c9603 Mon Sep 17 00:00:00 2001 From: Jason Parker Date: Fri, 7 Jun 2013 19:51:19 +0000 Subject: Make app_queue AMI events more consistent. Give Join/Leave more useful names. This also removes the eventwhencalled and eventmemberstatus configuration options. These events can just be filtered via manager.conf blacklists. (closes issue ASTERISK-21469) Review: https://reviewboard.asterisk.org/r/2586/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@390901 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- CHANGES | 10 + apps/app_queue.c | 1266 ++++++++++++++++++++++++-------------------- configs/queues.conf.sample | 14 - main/manager.c | 19 +- 4 files changed, 727 insertions(+), 582 deletions(-) diff --git a/CHANGES b/CHANGES index 7aa3cb2a2..f3d420bc8 100644 --- a/CHANGES +++ b/CHANGES @@ -106,6 +106,11 @@ AMI (Asterisk Manager Interface) core, and is now two events: Hold and Unhold. The status field has been removed. + * The AMI events in app_queue have been made more consistent with each other. + Events that reference channels (QueueCaller* and Agent*) will show + information about each channel. The (infamous) "Join" and "Leave" AMI + events have been changed to "QueueCallerJoin" and "QueueCallerLeave". + AGI (Asterisk Gateway Interface) ------------------ * The manager event AGIExec has been split into AGIExecStart and AGIExecEnd. @@ -243,6 +248,11 @@ Queue Reports 'InUse' for no logged in agents or no free agents. Reports 'Idle' when an agent is free. + * The configuration options eventwhencalled and eventmemberstatus have been + removed. As a result, the AMI events QueueMemberStatus, AgentCalled, + AgentConnect, AgentComplete, AgentDump, and AgentRingNoAnswer will always be + sent. The "Variable" fields will also no longer exist on the Agent* events. + Core ------------------ * Redirecting reasons can now be set to arbitrary strings. This means diff --git a/apps/app_queue.c b/apps/app_queue.c index bc9321695..5c61d83e7 100644 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -108,6 +108,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/term.h" #include "asterisk/dial.h" #include "asterisk/stasis_channels.h" +#include "asterisk/stasis_message_router.h" #include "asterisk/bridging.h" /* Define, to debug reference counts on queues, without debugging reference counts on queue members */ @@ -827,7 +828,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") - Set the ringinuse value for a queue member. @@ -841,7 +841,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") - Queue Rules. @@ -893,6 +892,275 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") + + + + Raised when a Queue member's status has changed. + + + The name of the queue. + + + The name of the queue member. + + + The queue member's channel technology or location. + + + Channel technology or location from which to read device state changes. + + + + + + + + + + The penalty associated with the queue member. + + + The number of calls this queue member has serviced. + + + The time this member last took a call, expressed in seconds since 00:00, Jan 1, 1970 UTC. + + + The numeric device state status of the queue member. + + AST_DEVICE_UNKNOWN + AST_DEVICE_NOT_INUSE + AST_DEVICE_INUSE + AST_DEVICE_BUSY + AST_DEVICE_INVALID + AST_DEVICE_UNAVAILABLE + AST_DEVICE_RINGING + AST_DEVICE_RINGINUSE + AST_DEVICE_ONHOLD + + + + + + + + + + + + + + + + + + + + Raised when a member is added to the queue. + + + + + QueueMemberRemoved + AddQueueMember + + + + + + Raised when a member is removed from the queue. + + + + + QueueMemberAdded + RemoveQueueMember + + + + + + Raised when a member is paused/unpaused in the queue. + + + + The reason a member was paused. + + + + PauseQueueMember + UnPauseQueueMember + + + + + + Raised when a member's penalty is changed. + + + + + QUEUE_MEMBER + + + + + + Raised when a member's ringinuse setting is changed. + + + + + QUEUE_MEMBER + + + + + + Raised when a caller joins a Queue. + + + + + This channel's current position in the queue. + + + The total number of channels in the queue. + + + + QueueCallerLeave + Queue + + + + + + Raised when a caller leaves a Queue. + + + + + + + + QueueCallerJoin + + + + + + Raised when a caller abandons the queue. + + + + + + The channel's original position in the queue. + + + The time the channel was in the queue, expressed in seconds since 00:00, Jan 1, 1970 UTC. + + + + + + + Raised when an queue member is notified of a caller in the queue. + + + + + + + + + AgentRingNoAnswer + AgentComplete + AgentConnect + + + + + + Raised when a queue member is notified of a caller in the queue and fails to answer. + + + + + + + + The time the queue member was rung, expressed in seconds since 00:00, Jan 1, 1970 UTC. + + + + AgentCalled + + + + + + Raised when a queue member has finished servicing a caller in the queue. + + + + + + + + + The time the queue member talked with the caller in the queue, expressed in seconds since 00:00, Jan 1, 1970 UTC. + + + + + + + + + + + AgentCalled + AgentConnect + + + + + + Raised when a queue member hangs up on a caller in the queue. + + + + + + + + + AgentCalled + AgentConnect + + + + + + Raised when a queue member answers and is bridged to a caller in the queue. + + + + + + + + + + + AgentCalled + AgentComplete + AgentDump + + + ***/ enum { @@ -1248,7 +1516,6 @@ struct call_queue { /*! Sound files: Custom announce, no default */ struct ast_str *sound_periodicannounce[MAX_PERIODIC_ANNOUNCEMENTS]; unsigned int dead:1; - unsigned int eventwhencalled:2; unsigned int ringinuse:1; unsigned int setinterfacevar:1; unsigned int setqueuevar:1; @@ -1259,7 +1526,6 @@ struct call_queue { unsigned int announceholdtime:2; unsigned int announceposition:3; int strategy:4; - unsigned int maskmemberstatus:1; unsigned int realtime:1; unsigned int found:1; unsigned int relativeperiodicannounce:1; @@ -1512,7 +1778,7 @@ static void set_queue_variables(struct call_queue *q, struct ast_channel *chan) q->name, q->maxlen, int2strat(q->strategy), q->count, q->holdtime, q->talktime, q->callscompleted, q->callsabandoned, q->servicelevel, sl); ao2_unlock(q); - + pbx_builtin_setvar_multiple(chan, interfacevar); } else { ao2_unlock(q); @@ -1544,6 +1810,184 @@ static inline void insert_entry(struct call_queue *q, struct queue_ent *prev, st new->opos = *pos; } +struct stasis_message_type *queue_caller_join_type(void); +struct stasis_message_type *queue_caller_leave_type(void); +struct stasis_message_type *queue_caller_abandon_type(void); + +struct stasis_message_type *queue_member_status_type(void); +struct stasis_message_type *queue_member_added_type(void); +struct stasis_message_type *queue_member_removed_type(void); +struct stasis_message_type *queue_member_pause_type(void); +struct stasis_message_type *queue_member_penalty_type(void); +struct stasis_message_type *queue_member_ringinuse_type(void); + +struct stasis_message_type *queue_agent_called_type(void); +struct stasis_message_type *queue_agent_connect_type(void); +struct stasis_message_type *queue_agent_complete_type(void); +struct stasis_message_type *queue_agent_dump_type(void); +struct stasis_message_type *queue_agent_ringnoanswer_type(void); + +STASIS_MESSAGE_TYPE_DEFN(queue_caller_join_type); +STASIS_MESSAGE_TYPE_DEFN(queue_caller_leave_type); +STASIS_MESSAGE_TYPE_DEFN(queue_caller_abandon_type); + +STASIS_MESSAGE_TYPE_DEFN(queue_member_status_type); +STASIS_MESSAGE_TYPE_DEFN(queue_member_added_type); +STASIS_MESSAGE_TYPE_DEFN(queue_member_removed_type); +STASIS_MESSAGE_TYPE_DEFN(queue_member_pause_type); +STASIS_MESSAGE_TYPE_DEFN(queue_member_penalty_type); +STASIS_MESSAGE_TYPE_DEFN(queue_member_ringinuse_type); + +STASIS_MESSAGE_TYPE_DEFN(queue_agent_called_type); +STASIS_MESSAGE_TYPE_DEFN(queue_agent_connect_type); +STASIS_MESSAGE_TYPE_DEFN(queue_agent_complete_type); +STASIS_MESSAGE_TYPE_DEFN(queue_agent_dump_type); +STASIS_MESSAGE_TYPE_DEFN(queue_agent_ringnoanswer_type); + +static void queue_channel_manager_event(void *data, + struct stasis_subscription *sub, struct stasis_topic *topic, + struct stasis_message *message) +{ + const char *type = data; + struct ast_channel_blob *obj = stasis_message_data(message); + RAII_VAR(struct ast_str *, channel_event_string, NULL, ast_free); + RAII_VAR(struct ast_str *, event_string, NULL, ast_free); + + channel_event_string = ast_manager_build_channel_state_string(obj->snapshot); + if (!channel_event_string) { + return; + } + + event_string = ast_manager_str_from_json_object(obj->blob, NULL); + if (!event_string) { + return; + } + + manager_event(EVENT_FLAG_AGENT, type, + "%s" + "%s", + ast_str_buffer(channel_event_string), + ast_str_buffer(event_string)); +} + +static void queue_multi_channel_manager_event(void *data, + struct stasis_subscription *sub, struct stasis_topic *topic, + struct stasis_message *message) +{ + const char *type = data; + struct ast_multi_channel_blob *obj = stasis_message_data(message); + struct ast_channel_snapshot *caller; + struct ast_channel_snapshot *agent; + RAII_VAR(struct ast_str *, caller_event_string, NULL, ast_free); + RAII_VAR(struct ast_str *, agent_event_string, NULL, ast_free); + RAII_VAR(struct ast_str *, event_string, NULL, ast_free); + + caller = ast_multi_channel_blob_get_channel(obj, "caller"); + agent = ast_multi_channel_blob_get_channel(obj, "agent"); + + caller_event_string = ast_manager_build_channel_state_string(caller); + agent_event_string = ast_manager_build_channel_state_string_prefix(agent, "Dest"); + + if (!caller_event_string || !agent_event_string) { + return; + } + + event_string = ast_manager_str_from_json_object(ast_multi_channel_blob_get_json(obj), NULL); + if (!event_string) { + return; + } + + manager_event(EVENT_FLAG_AGENT, type, + "%s" + "%s" + "%s", + ast_str_buffer(caller_event_string), + ast_str_buffer(agent_event_string), + ast_str_buffer(event_string)); +} + +static void queue_member_manager_event(void *data, + struct stasis_subscription *sub, struct stasis_topic *topic, + struct stasis_message *message) +{ + const char *type = data; + struct ast_json_payload *payload = stasis_message_data(message); + struct ast_json *event = payload->json; + RAII_VAR(struct ast_str *, event_string, NULL, ast_free); + + event_string = ast_manager_str_from_json_object(event, NULL); + if (!event_string) { + return; + } + + manager_event(EVENT_FLAG_AGENT, type, + "%s", ast_str_buffer(event_string)); +} + +static void queue_publish_multi_channel_blob(struct ast_channel *caller, struct ast_channel *agent, struct stasis_message_type *type, struct ast_json *blob) +{ + RAII_VAR(struct ast_multi_channel_blob *, payload, NULL, ao2_cleanup); + RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup); + struct ast_channel_snapshot *caller_snapshot; + struct ast_channel_snapshot *agent_snapshot; + + payload = ast_multi_channel_blob_create(blob); + if (!payload) { + return; + } + + caller_snapshot = ast_channel_snapshot_create(caller); + agent_snapshot = ast_channel_snapshot_create(agent); + + if (!caller_snapshot || !agent_snapshot) { + return; + } + + ast_multi_channel_blob_add_channel(payload, "caller", caller_snapshot); + ast_multi_channel_blob_add_channel(payload, "agent", agent_snapshot); + + msg = stasis_message_create(type, payload); + if (!msg) { + return; + } + + stasis_publish(ast_channel_topic(caller), msg); +} + +static void queue_publish_member_blob(struct stasis_message_type *type, struct ast_json *blob) +{ + RAII_VAR(struct ast_json_payload *, payload, NULL, ao2_cleanup); + RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup); + + payload = ast_json_payload_create(blob); + if (!payload) { + return; + } + + msg = stasis_message_create(type, payload); + if (!msg) { + return; + } + + stasis_publish(ast_manager_get_topic(), msg); +} + +static struct ast_json *queue_member_blob_create(struct call_queue *q, struct member *mem) +{ + return ast_json_pack("{s: s, s: s, s: s, s: s, s: s, s: i, s: i, s: i, s: i, s: i, s: i}", + "Queue", q->name, + "MemberName", mem->membername, + "Interface", mem->interface, + "StateInterface", mem->state_interface, + "Membership", (mem->dynamic ? "dynamic" : (mem->realtime ? "realtime" : "static")), + "Penalty", mem->penalty, + "CallsTaken", mem->calls, + "LastCall", (int)mem->lastcall, + "Status", mem->status, + "Paused", mem->paused, + "Ringinuse", mem->ringinuse); +} + /*! \brief Check if members are available * * This function checks to see if members are available to be called. If any member @@ -1629,79 +2073,7 @@ static void update_status(struct call_queue *q, struct member *m, const int stat { m->status = status; - if (q->maskmemberstatus) { - return; - } - - /*** DOCUMENTATION - - Raised when a Queue member's status has changed. - - - The name of the queue. - - - The queue member's channel technology or location. - - - The name of the queue member. - - - Channel technology or location from which to read device state changes. - - - - - - - - - - The penalty associated with the queue member. - - - The number of calls this queue member has serviced. - - - The time this member last took call, expressed in seconds since 00:00, Jan 1, 1970 UTC. - - - The numeric device state status of the queue member. - - AST_DEVICE_UNKNOWN - AST_DEVICE_NOT_INUSE - AST_DEVICE_INUSE - AST_DEVICE_BUSY - AST_DEVICE_INVALID - AST_DEVICE_UNAVAILABLE - AST_DEVICE_RINGING - AST_DEVICE_RINGINUSE - AST_DEVICE_ONHOLD - - - - - - - - - - - ***/ - manager_event(EVENT_FLAG_AGENT, "QueueMemberStatus", - "Queue: %s\r\n" - "Location: %s\r\n" - "MemberName: %s\r\n" - "StateInterface: %s\r\n" - "Membership: %s\r\n" - "Penalty: %d\r\n" - "CallsTaken: %d\r\n" - "LastCall: %d\r\n" - "Status: %d\r\n" - "Paused: %d\r\n", - q->name, m->interface, m->membername, m->state_interface, m->dynamic ? "dynamic" : m->realtime ? "realtime" : "static", - m->penalty, m->calls, (int)m->lastcall, m->status, m->paused - ); + queue_publish_member_blob(queue_member_status_type(), queue_member_blob_create(q, m)); } /*! @@ -2010,8 +2382,6 @@ static void init_queue(struct call_queue *q) q->joinempty = 0; q->leavewhenempty = 0; q->memberdelay = 0; - q->maskmemberstatus = 0; - q->eventwhencalled = 0; q->weight = 0; q->timeoutrestart = 0; q->periodicannouncefrequency = 0; @@ -2399,14 +2769,6 @@ static void queue_set_param(struct call_queue *q, const char *param, const char parse_empty_options(val, &q->joinempty, 1); } else if (!strcasecmp(param, "leavewhenempty")) { parse_empty_options(val, &q->leavewhenempty, 0); - } else if (!strcasecmp(param, "eventmemberstatus")) { - q->maskmemberstatus = !ast_true(val); - } else if (!strcasecmp(param, "eventwhencalled")) { - if (!strcasecmp(val, "vars")) { - q->eventwhencalled = QUEUE_EVENT_VARIABLES; - } else { - q->eventwhencalled = ast_true(val) ? 1 : 0; - } } else if (!strcasecmp(param, "reportholdtime")) { q->reportholdtime = ast_true(val); } else if (!strcasecmp(param, "memberdelay")) { @@ -2909,6 +3271,8 @@ static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result * if (*reason == QUEUE_UNKNOWN && q->maxlen && (q->count >= q->maxlen)) { *reason = QUEUE_FULL; } else if (*reason == QUEUE_UNKNOWN) { + RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref); + /* There's space for us, put us at the right position inside * the queue. * Take into account the priority of the calling user */ @@ -2951,40 +3315,12 @@ static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result * } res = 0; - /*** DOCUMENTATION - - Raised when a channel joins a Queue. - - - - This channel's current position in the queue. - - - The total number of channels in the queue. - - - - Leave - Queue - - - ***/ - ast_manager_event(qe->chan, EVENT_FLAG_CALL, "Join", - "Channel: %s\r\n" - "CallerIDNum: %s\r\n" - "CallerIDName: %s\r\n" - "ConnectedLineNum: %s\r\n" - "ConnectedLineName: %s\r\n" - "Queue: %s\r\n" - "Position: %d\r\n" - "Count: %d\r\n" - "Uniqueid: %s\r\n", - ast_channel_name(qe->chan), - S_COR(ast_channel_caller(qe->chan)->id.number.valid, ast_channel_caller(qe->chan)->id.number.str, "unknown"),/* XXX somewhere else it is */ - S_COR(ast_channel_caller(qe->chan)->id.name.valid, ast_channel_caller(qe->chan)->id.name.str, "unknown"), - S_COR(ast_channel_connected(qe->chan)->id.number.valid, ast_channel_connected(qe->chan)->id.number.str, "unknown"),/* XXX somewhere else it is */ - S_COR(ast_channel_connected(qe->chan)->id.name.valid, ast_channel_connected(qe->chan)->id.name.str, "unknown"), - q->name, qe->pos, q->count, ast_channel_uniqueid(qe->chan)); + + blob = ast_json_pack("{s: s, s: i, s: i}", + "Queue", q->name, + "Position", qe->pos, + "Count", q->count); + ast_channel_publish_blob(qe->chan, queue_caller_join_type(), blob); ast_debug(1, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, ast_channel_name(qe->chan), qe->pos ); } ao2_unlock(q); @@ -3252,29 +3588,18 @@ static void leave_queue(struct queue_ent *qe) prev = NULL; for (current = q->head; current; current = current->next) { if (current == qe) { + RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref); char posstr[20]; q->count--; if (!q->count) { ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, "Queue:%s", q->name); } - /* Take us out of the queue */ - /*** DOCUMENTATION - - Raised when a channel leaves a Queue. - - - - - - - Join - - - ***/ - ast_manager_event(qe->chan, EVENT_FLAG_CALL, "Leave", - "Channel: %s\r\nQueue: %s\r\nCount: %d\r\nPosition: %d\r\nUniqueid: %s\r\n", - ast_channel_name(qe->chan), q->name, q->count, qe->pos, ast_channel_uniqueid(qe->chan)); + blob = ast_json_pack("{s: s, s: i, s: i}", + "Queue", q->name, + "Position", qe->pos, + "Count", q->count); + ast_channel_publish_blob(qe->chan, queue_caller_leave_type(), blob); ast_debug(1, "Queue '%s' Leave, Channel '%s'\n", q->name, ast_channel_name(qe->chan)); /* Take us out of the queue */ if (prev) { @@ -3448,46 +3773,6 @@ static void do_hang(struct callattempt *o) o->chan = NULL; } -/*! \brief convert "\n" to "\nVariable: " ready for manager to use */ -static char *vars2manager(struct ast_channel *chan, char *vars, size_t len) -{ - struct ast_str *buf = ast_str_thread_get(&ast_str_thread_global_buf, len + 1); - const char *tmp; - - if (pbx_builtin_serialize_variables(chan, &buf)) { - int i, j; - - /* convert "\n" to "\nVariable: " */ - strcpy(vars, "Variable: "); - tmp = ast_str_buffer(buf); - - for (i = 0, j = 10; (i < len - 1) && (j < len - 1); i++, j++) { - vars[j] = tmp[i]; - - if (tmp[i + 1] == '\0') { - break; - } - if (tmp[i] == '\n') { - vars[j++] = '\r'; - vars[j++] = '\n'; - - ast_copy_string(&(vars[j]), "Variable: ", len - j); - j += 9; - } - } - if (j > len - 3) { - j = len - 3; - } - vars[j++] = '\r'; - vars[j++] = '\n'; - vars[j] = '\0'; - } else { - /* there are no channel variables; leave it blank */ - *vars = '\0'; - } - return vars; -} - /*! * \internal * \brief Check if the member status is available. @@ -3615,6 +3900,7 @@ static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies char tech[256]; char *location; const char *macrocontext, *macroexten; + RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref); /* on entry here, we know that tmp->chan == NULL */ if (!can_ring_entry(qe, tmp)) { @@ -3728,54 +4014,11 @@ static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies ast_channel_lock_both(tmp->chan, qe->chan); - if (qe->parent->eventwhencalled) { - char vars[2048]; - - /*** DOCUMENTATION - - Raised when an Agent is notified of a member in the queue. - - - - The agent's technology or location. - - - The name of the agent. - - - Optional channel variables from the ChannelCalling channel - - - - AgentRingNoAnswer - AgentComplete - AgentConnect - - - ***/ - manager_event(EVENT_FLAG_AGENT, "AgentCalled", - "Queue: %s\r\n" - "AgentCalled: %s\r\n" - "AgentName: %s\r\n" - "ChannelCalling: %s\r\n" - "DestinationChannel: %s\r\n" - "CallerIDNum: %s\r\n" - "CallerIDName: %s\r\n" - "ConnectedLineNum: %s\r\n" - "ConnectedLineName: %s\r\n" - "Context: %s\r\n" - "Extension: %s\r\n" - "Priority: %d\r\n" - "Uniqueid: %s\r\n" - "%s", - qe->parent->name, tmp->interface, tmp->member->membername, ast_channel_name(qe->chan), ast_channel_name(tmp->chan), - S_COR(ast_channel_caller(qe->chan)->id.number.valid, ast_channel_caller(qe->chan)->id.number.str, "unknown"), - S_COR(ast_channel_caller(qe->chan)->id.name.valid, ast_channel_caller(qe->chan)->id.name.str, "unknown"), - S_COR(ast_channel_connected(qe->chan)->id.number.valid, ast_channel_connected(qe->chan)->id.number.str, "unknown"), - S_COR(ast_channel_connected(qe->chan)->id.name.valid, ast_channel_connected(qe->chan)->id.name.str, "unknown"), - ast_channel_context(qe->chan), ast_channel_exten(qe->chan), ast_channel_priority(qe->chan), ast_channel_uniqueid(qe->chan), - qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : ""); - } + blob = ast_json_pack("{s: s, s: s, s: s}", + "Queue", qe->parent->name, + "Interface", tmp->interface, + "MemberName", tmp->member->membername); + queue_publish_multi_channel_blob(qe->chan, tmp->chan, queue_agent_called_type(), blob); ast_channel_publish_dial(qe->chan, tmp->chan, tmp->interface, NULL); @@ -3955,45 +4198,33 @@ static int say_periodic_announcement(struct queue_ent *qe, int ringing) if (!qe->parent->randomperiodicannounce) { qe->last_periodic_announce_sound++; } - + return res; } /*! \brief Record that a caller gave up on waiting in queue */ static void record_abandoned(struct queue_ent *qe) { + RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref); + set_queue_variables(qe->parent, qe->chan); ao2_lock(qe->parent); - /*** DOCUMENTATION - - Raised when an caller abandons the queue. - - - - - The channel's original position in the queue. - - - The time the channel was in the queue, expressed in seconds since 00:00, Jan 1, 1970 UTC. - - - - ***/ - manager_event(EVENT_FLAG_AGENT, "QueueCallerAbandon", - "Queue: %s\r\n" - "Uniqueid: %s\r\n" - "Position: %d\r\n" - "OriginalPosition: %d\r\n" - "HoldTime: %d\r\n", - qe->parent->name, ast_channel_uniqueid(qe->chan), qe->pos, qe->opos, (int)(time(NULL) - qe->start)); + blob = ast_json_pack("{s: s, s: i, s: i}", + "Queue", qe->parent->name, + "Position", qe->pos, + "OriginalPosition", qe->opos, + "HoldTime", (int)(time(NULL) - qe->start)); + ast_channel_publish_blob(qe->chan, queue_caller_abandon_type(), blob); qe->parent->callsabandoned++; ao2_unlock(qe->parent); } /*! \brief RNA == Ring No Answer. Common code that is executed when we try a queue member and they don't answer. */ -static void rna(int rnatime, struct queue_ent *qe, char *interface, char *membername, int autopause) +static void rna(int rnatime, struct queue_ent *qe, struct ast_channel *peer, char *interface, char *membername, int autopause) { + RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref); + ast_verb(3, "Nobody picked up in %d ms\n", rnatime); /* Stop ringing, and resume MOH if specified */ @@ -4002,43 +4233,13 @@ static void rna(int rnatime, struct queue_ent *qe, char *interface, char *member ast_moh_start(qe->chan, qe->moh, NULL); } - if (qe->parent->eventwhencalled) { - char vars[2048]; - /*** DOCUMENTATION - - Raised when an agent is notified of a member in the queue and fails to answer. - - - - - - The queue member's channel technology or location. - - - The time the agent was rung, expressed in seconds since 00:00, Jan 1, 1970 UTC. - - - - AgentCalled - - - ***/ - manager_event(EVENT_FLAG_AGENT, "AgentRingNoAnswer", - "Queue: %s\r\n" - "Uniqueid: %s\r\n" - "Channel: %s\r\n" - "Member: %s\r\n" - "MemberName: %s\r\n" - "RingTime: %d\r\n" - "%s", - qe->parent->name, - ast_channel_uniqueid(qe->chan), - ast_channel_name(qe->chan), - interface, - membername, - rnatime, - qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : ""); - } + blob = ast_json_pack("{s: s, s: s, s: s, s: i}", + "Queue", qe->parent->name, + "Interface", interface, + "MemberName", membername, + "RingTime", rnatime); + queue_publish_multi_channel_blob(qe->chan, peer, queue_agent_ringnoanswer_type(), blob); + ast_queue_log(qe->parent->name, ast_channel_uniqueid(qe->chan), membername, "RINGNOANSWER", "%d", rnatime); if (qe->parent->autopause != QUEUE_AUTOPAUSE_OFF && autopause) { if (qe->parent->autopausedelay > 0) { @@ -4411,7 +4612,7 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte do_hang(o); endtime = (long) time(NULL); endtime -= starttime; - rna(endtime * 1000, qe, on, membername, qe->parent->autopausebusy); + rna(endtime * 1000, qe, o->chan, on, membername, qe->parent->autopausebusy); if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) { if (qe->parent->timeoutrestart) { start_time_tv = ast_tvnow(); @@ -4432,7 +4633,7 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte ast_channel_publish_dial(qe->chan, o->chan, on, "CONGESTION"); endtime = (long) time(NULL); endtime -= starttime; - rna(endtime * 1000, qe, on, membername, qe->parent->autopauseunavail); + rna(endtime * 1000, qe, o->chan, on, membername, qe->parent->autopauseunavail); do_hang(o); if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) { if (qe->parent->timeoutrestart) { @@ -4528,7 +4729,7 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte } else { /* ast_read() returned NULL */ endtime = (long) time(NULL) - starttime; ast_channel_publish_dial(qe->chan, o->chan, on, "NOANSWER"); - rna(endtime * 1000, qe, on, membername, 1); + rna(endtime * 1000, qe, o->chan, on, membername, 1); do_hang(o); if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) { if (qe->parent->timeoutrestart) { @@ -4630,7 +4831,7 @@ skip_frame:; if (!*to) { for (o = start; o; o = o->call_next) { - rna(orig, qe, o->interface, o->member->membername, 1); + rna(orig, qe, o->chan, o->interface, o->member->membername, 1); } publish_dial_end_event(qe->chan, outgoing, NULL, "NOANSWER"); @@ -4958,10 +5159,7 @@ static void send_agent_complete(const struct queue_ent *qe, const char *queuenam char *vars, size_t vars_len, enum agent_complete_reason rsn) { const char *reason = NULL; /* silence dumb compilers */ - - if (!qe->parent->eventwhencalled) { - return; - } + RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref); switch (rsn) { case CALLER: @@ -4975,45 +5173,14 @@ static void send_agent_complete(const struct queue_ent *qe, const char *queuenam break; } - /*** DOCUMENTATION - - Raised when an agent has finished servicing a member in the queue. - - - - - - - - The time the agent talked with the member in the queue, expressed in seconds since 00:00, Jan 1, 1970 UTC. - - - - - - - - - - - AgentCalled - AgentConnect - - - ***/ - manager_event(EVENT_FLAG_AGENT, "AgentComplete", - "Queue: %s\r\n" - "Uniqueid: %s\r\n" - "Channel: %s\r\n" - "Member: %s\r\n" - "MemberName: %s\r\n" - "HoldTime: %ld\r\n" - "TalkTime: %ld\r\n" - "Reason: %s\r\n" - "%s", - queuename, ast_channel_uniqueid(qe->chan), ast_channel_name(peer), member->interface, member->membername, - (long)(callstart - qe->start), (long)(time(NULL) - callstart), reason, - qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, vars_len) : ""); + blob = ast_json_pack("{s: s, s: s, s: s, s: i, s: i, s: s}", + "Queue", queuename, + "Interface", member->interface, + "MemberName", member->membername, + "HoldTime", (long)(callstart - qe->start) + "TalkTime", (long)(time(NULL) - callstart) + "Reason", reason); + queue_publish_multi_channel_blob(qe->chan, peer, queue_agent_complete_type(), blob); } #endif // BUGBUG @@ -5246,7 +5413,6 @@ static int try_calling(struct queue_ent *qe, struct ast_flags opts, char **opt_a char mixmonargs[1512]; struct ast_app *mixmonapp = NULL; char *p; - char vars[2048]; int forwardsallowed = 1; int block_connected_line = 0; #if 0 // BUGBUG @@ -5523,6 +5689,7 @@ static int try_calling(struct queue_ent *qe, struct ast_flags opts, char **opt_a } } } else { /* peer is valid */ + RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref); /* Ah ha! Someone answered within the desired timeframe. Of course after this we will always return with -1 so that it is hung up properly after the conversation. */ @@ -5586,32 +5753,13 @@ static int try_calling(struct queue_ent *qe, struct ast_flags opts, char **opt_a /* Agent must have hung up */ ast_log(LOG_WARNING, "Agent on %s hungup on the customer.\n", ast_channel_name(peer)); ast_queue_log(queuename, ast_channel_uniqueid(qe->chan), member->membername, "AGENTDUMP", "%s", ""); - if (qe->parent->eventwhencalled) { - /*** DOCUMENTATION - - Raised when an agent hangs up on a member in the queue. - - - - - - - - AgentCalled - AgentConnect - - - ***/ - manager_event(EVENT_FLAG_AGENT, "AgentDump", - "Queue: %s\r\n" - "Uniqueid: %s\r\n" - "Channel: %s\r\n" - "Member: %s\r\n" - "MemberName: %s\r\n" - "%s", - queuename, ast_channel_uniqueid(qe->chan), ast_channel_name(peer), member->interface, member->membername, - qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : ""); - } + + blob = ast_json_pack("{s: s, s: s, s: s}", + "Queue", queuename, + "Interface", member->interface, + "MemberName", member->membername); + queue_publish_multi_channel_blob(qe->chan, peer, queue_agent_dump_type(), blob); + ast_channel_publish_dial(qe->chan, peer, member->interface, ast_hangup_cause_to_dial_status(ast_channel_hangupcause(peer))); ast_autoservice_chan_hangup_peer(qe->chan, peer); ao2_ref(member, -1); @@ -5914,43 +6062,17 @@ static int try_calling(struct queue_ent *qe, struct ast_flags opts, char **opt_a } } - if (qe->parent->eventwhencalled) { - /*** DOCUMENTATION - - Raised when an agent answers and is bridged to a member in the queue. - - - - - - - - - - AgentCalled - AgentComplete - AgentDump - - - ***/ - manager_event(EVENT_FLAG_AGENT, "AgentConnect", - "Queue: %s\r\n" - "Uniqueid: %s\r\n" - "Channel: %s\r\n" - "Member: %s\r\n" - "MemberName: %s\r\n" - "HoldTime: %ld\r\n" - "BridgedChannel: %s\r\n" - "RingTime: %ld\r\n" - "%s", - queuename, ast_channel_uniqueid(qe->chan), ast_channel_name(peer), member->interface, member->membername, - (long) time(NULL) - qe->start, ast_channel_uniqueid(peer), (long)(orig - to > 0 ? (orig - to) / 1000 : 0), - qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : ""); - } + blob = ast_json_pack("{s: s, s: s, s: s, s: i, s: i}", + "Queue", queuename, + "Interface", member->interface, + "MemberName", member->membername, + "HoldTime", (long) time(NULL) - qe->start, + "RingTime", (long)(orig - to > 0 ? (orig - to) / 1000 : 0)); + queue_publish_multi_channel_blob(qe->chan, peer, queue_agent_connect_type(), blob); ast_copy_string(oldcontext, ast_channel_context(qe->chan), sizeof(oldcontext)); ast_copy_string(oldexten, ast_channel_exten(qe->chan), sizeof(oldexten)); - + if ((queue_end_bridge = ao2_alloc(sizeof(*queue_end_bridge), NULL))) { queue_end_bridge->q = qe->parent; queue_end_bridge->chan = qe->chan; @@ -6136,25 +6258,8 @@ static int remove_from_queue(const char *queuename, const char *interface) queue_t_unref(q, "Interface wasn't dynamic, expiring temporary reference"); return RES_NOT_DYNAMIC; } - /*** DOCUMENTATION - - Raised when a member is removed from the queue. - - - - - - - QueueMemberAdded - RemoveQueueMember - - - ***/ - manager_event(EVENT_FLAG_AGENT, "QueueMemberRemoved", - "Queue: %s\r\n" - "Location: %s\r\n" - "MemberName: %s\r\n", - q->name, mem->interface, mem->membername); + queue_publish_member_blob(queue_member_removed_type(), queue_member_blob_create(q, mem)); + member_remove_from_queue(q, mem); ao2_ref(mem, -1); @@ -6202,42 +6307,7 @@ static int add_to_queue(const char *queuename, const char *interface, const char new_member->ringinuse = q->ringinuse; new_member->dynamic = 1; member_add_to_queue(q, new_member); - /*** DOCUMENTATION - - Raised when a member is added to the queue. - - - - - - - - - - - - - - QueueMemberRemoved - AddQueueMember - - - ***/ - manager_event(EVENT_FLAG_AGENT, "QueueMemberAdded", - "Queue: %s\r\n" - "Location: %s\r\n" - "MemberName: %s\r\n" - "StateInterface: %s\r\n" - "Membership: %s\r\n" - "Penalty: %d\r\n" - "CallsTaken: %d\r\n" - "LastCall: %d\r\n" - "Status: %d\r\n" - "Paused: %d\r\n", - q->name, new_member->interface, new_member->membername, state_interface, - "dynamic", - new_member->penalty, new_member->calls, (int) new_member->lastcall, - new_member->status, new_member->paused); + queue_publish_member_blob(queue_member_added_type(), queue_member_blob_create(q, new_member)); if (is_member_available(new_member)) { ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, "Queue:%s_avail", q->name); @@ -6264,35 +6334,51 @@ static int add_to_queue(const char *queuename, const char *interface, const char return res; } +static int publish_queue_member_pause(struct call_queue *q, struct member *member, const char *reason) { + struct ast_json *json_blob = queue_member_blob_create(q, member); + + if (!json_blob) { + return -1; + } + + if (!ast_strlen_zero(reason)) { + ast_json_object_set(json_blob, "Reason", ast_json_string_create(reason)); + } + + queue_publish_member_blob(queue_member_pause_type(), json_blob); + + return 0; +} + static int set_member_paused(const char *queuename, const char *interface, const char *reason, int paused) { int found = 0; struct call_queue *q; - struct member *mem; struct ao2_iterator queue_iter; - int failed; queue_iter = ao2_iterator_init(queues, 0); while ((q = ao2_t_iterator_next(&queue_iter, "Iterate over queues"))) { ao2_lock(q); if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) { + struct member *mem; + if ((mem = interface_exists(q, interface))) { if (mem->paused == paused) { ast_debug(1, "%spausing already-%spaused queue member %s:%s\n", (paused ? "" : "un"), (paused ? "" : "un"), q->name, interface); } - failed = 0; if (mem->realtime) { - failed = update_realtime_member_field(mem, q->name, "paused", paused ? "1" : "0"); + if (update_realtime_member_field(mem, q->name, "paused", paused ? "1" : "0")) { + ast_log(LOG_WARNING, "Failed %spausing realtime queue member %s:%s\n", (paused ? "" : "un"), q->name, interface); + ao2_ref(mem, -1); + ao2_unlock(q); + queue_t_unref(q, "Done with iterator"); + continue; + } } - if (failed) { - ast_log(LOG_WARNING, "Failed %spausing realtime queue member %s:%s\n", (paused ? "" : "un"), q->name, interface); - ao2_ref(mem, -1); - ao2_unlock(q); - queue_t_unref(q, "Done with iterator"); - continue; - } + mem->paused = paused; + found++; /* Before we do the PAUSE/UNPAUSE log, if this was a PAUSEALL/UNPAUSEALL, log that here, but only on the first found entry. */ @@ -6304,8 +6390,6 @@ static int set_member_paused(const char *queuename, const char *interface, const } } - mem->paused = paused; - if (queue_persistent_members) { dump_queue_members(q); } @@ -6318,52 +6402,7 @@ static int set_member_paused(const char *queuename, const char *interface, const ast_queue_log(q->name, "NONE", mem->membername, (paused ? "PAUSE" : "UNPAUSE"), "%s", S_OR(reason, "")); - /*** DOCUMENTATION - - Raised when a member is paused/unpaused in the queue with a reason. - - - - - - - - PauseQueueMember - UnPauseQueueMember - - - ***/ - if (!ast_strlen_zero(reason)) { - manager_event(EVENT_FLAG_AGENT, "QueueMemberPaused", - "Queue: %s\r\n" - "Location: %s\r\n" - "MemberName: %s\r\n" - "Paused: %d\r\n" - "Reason: %s\r\n", - q->name, mem->interface, mem->membername, paused, reason); - } else { - /*** DOCUMENTATION - - Raised when a member is paused/unpaused in the queue without a reason. - - - - - - - - PauseQueueMember - UnPauseQueueMember - - - ***/ - manager_event(EVENT_FLAG_AGENT, "QueueMemberPaused", - "Queue: %s\r\n" - "Location: %s\r\n" - "MemberName: %s\r\n" - "Paused: %d\r\n", - q->name, mem->interface, mem->membername, paused); - } + publish_queue_member_pause(q, mem, reason); ao2_ref(mem, -1); } } @@ -6395,36 +6434,21 @@ static int set_member_penalty_help_members(struct call_queue *q, const char *int { struct member *mem; int foundinterface = 0; - char rtpenalty[80]; ao2_lock(q); if ((mem = interface_exists(q, interface))) { foundinterface++; - if (!mem->realtime) { - mem->penalty = penalty; - } else { + if (mem->realtime) { + char rtpenalty[80]; + sprintf(rtpenalty, "%i", penalty); update_realtime_member_field(mem, q->name, "penalty", rtpenalty); } + + mem->penalty = penalty; + ast_queue_log(q->name, "NONE", interface, "PENALTY", "%d", penalty); - /*** DOCUMENTATION - - Raised when a member's penalty is changed. - - - - - - - QUEUE_MEMBER - - - ***/ - manager_event(EVENT_FLAG_AGENT, "QueueMemberPenalty", - "Queue: %s\r\n" - "Location: %s\r\n" - "Penalty: %d\r\n", - q->name, mem->interface, penalty); + queue_publish_member_blob(queue_member_penalty_type(), queue_member_blob_create(q, mem)); ao2_ref(mem, -1); } ao2_unlock(q); @@ -6436,41 +6460,21 @@ static int set_member_ringinuse_help_members(struct call_queue *q, const char *i { struct member *mem; int foundinterface = 0; - char rtringinuse[80]; ao2_lock(q); if ((mem = interface_exists(q, interface))) { foundinterface++; - if (!mem->realtime) { - mem->ringinuse = ringinuse; - } else { + if (mem->realtime) { + char rtringinuse[80]; + sprintf(rtringinuse, "%i", ringinuse); update_realtime_member_field(mem, q->name, realtime_ringinuse_field, rtringinuse); } + + mem->ringinuse = ringinuse; + ast_queue_log(q->name, "NONE", interface, "RINGINUSE", "%d", ringinuse); - /*** DOCUMENTATION - - Raised when a member's ringinuse setting is changed. - - - - - - - - - - - - QUEUE_MEMBER - - - ***/ - manager_event(EVENT_FLAG_AGENT, "QueueMemberRinginuse", - "Queue: %s\r\n" - "Location: %s\r\n" - "Ringinuse: %d\r\n", - q->name, mem->interface, ringinuse); + queue_publish_member_blob(queue_member_ringinuse_type(), queue_member_blob_create(q, mem)); ao2_ref(mem, -1); } ao2_unlock(q); @@ -7509,15 +7513,15 @@ static int queue_function_mem_write(struct ast_channel *chan, const char *cmd, c if (!strcasecmp(args.option, "paused")) { if (m->realtime) { update_realtime_member_field(m, q->name, args.option, rtvalue); - } else { - m->paused = (memvalue <= 0) ? 0 : 1; } + + m->paused = (memvalue <= 0) ? 0 : 1; } else if ((!strcasecmp(args.option, "ignorebusy")) || (!strcasecmp(args.option, "ringinuse"))) { if (m->realtime) { update_realtime_member_field(m, q->name, args.option, rtvalue); - } else { - m->ringinuse = (memvalue <= 0) ? 0 : 1; } + + m->ringinuse = (memvalue <= 0) ? 0 : 1; } else { ast_log(LOG_ERROR, "Invalid option, only penalty , paused or ringinuse/ignorebusy are valid\n"); ao2_ref(m, -1); @@ -9656,7 +9660,6 @@ static struct ast_cli_entry cli_queue[] = { MEMBER(call_queue, sound_callerannounce, AST_DATA_STRING) \ MEMBER(call_queue, sound_reporthold, AST_DATA_STRING) \ MEMBER(call_queue, dead, AST_DATA_BOOLEAN) \ - MEMBER(call_queue, eventwhencalled, AST_DATA_BOOLEAN) \ MEMBER(call_queue, ringinuse, AST_DATA_BOOLEAN) \ MEMBER(call_queue, setinterfacevar, AST_DATA_BOOLEAN) \ MEMBER(call_queue, setqueuevar, AST_DATA_BOOLEAN) \ @@ -9665,7 +9668,6 @@ static struct ast_cli_entry cli_queue[] = { MEMBER(call_queue, wrapped, AST_DATA_BOOLEAN) \ MEMBER(call_queue, timeoutrestart, AST_DATA_BOOLEAN) \ MEMBER(call_queue, announceholdtime, AST_DATA_INTEGER) \ - MEMBER(call_queue, maskmemberstatus, AST_DATA_BOOLEAN) \ MEMBER(call_queue, realtime, AST_DATA_BOOLEAN) \ MEMBER(call_queue, found, AST_DATA_BOOLEAN) \ MEMBER(call_queue, announcepositionlimit, AST_DATA_INTEGER) \ @@ -9910,6 +9912,43 @@ static int unload_module(void) struct ao2_iterator q_iter; struct call_queue *q = NULL; + struct stasis_message_router *message_router; + + message_router = ast_manager_get_message_router(); + if (message_router) { + stasis_message_router_remove(message_router, queue_caller_join_type()); + stasis_message_router_remove(message_router, queue_caller_leave_type()); + stasis_message_router_remove(message_router, queue_caller_abandon_type()); + stasis_message_router_remove(message_router, queue_member_status_type()); + stasis_message_router_remove(message_router, queue_member_added_type()); + stasis_message_router_remove(message_router, queue_member_removed_type()); + stasis_message_router_remove(message_router, queue_member_pause_type()); + stasis_message_router_remove(message_router, queue_member_penalty_type()); + stasis_message_router_remove(message_router, queue_member_ringinuse_type()); + stasis_message_router_remove(message_router, queue_agent_called_type()); + stasis_message_router_remove(message_router, queue_agent_connect_type()); + stasis_message_router_remove(message_router, queue_agent_complete_type()); + stasis_message_router_remove(message_router, queue_agent_dump_type()); + stasis_message_router_remove(message_router, queue_agent_ringnoanswer_type()); + } + + STASIS_MESSAGE_TYPE_CLEANUP(queue_caller_join_type); + STASIS_MESSAGE_TYPE_CLEANUP(queue_caller_leave_type); + STASIS_MESSAGE_TYPE_CLEANUP(queue_caller_abandon_type); + + STASIS_MESSAGE_TYPE_CLEANUP(queue_member_status_type); + STASIS_MESSAGE_TYPE_CLEANUP(queue_member_added_type); + STASIS_MESSAGE_TYPE_CLEANUP(queue_member_removed_type); + STASIS_MESSAGE_TYPE_CLEANUP(queue_member_pause_type); + STASIS_MESSAGE_TYPE_CLEANUP(queue_member_penalty_type); + STASIS_MESSAGE_TYPE_CLEANUP(queue_member_ringinuse_type); + + STASIS_MESSAGE_TYPE_CLEANUP(queue_agent_called_type); + STASIS_MESSAGE_TYPE_CLEANUP(queue_agent_connect_type); + STASIS_MESSAGE_TYPE_CLEANUP(queue_agent_complete_type); + STASIS_MESSAGE_TYPE_CLEANUP(queue_agent_dump_type); + STASIS_MESSAGE_TYPE_CLEANUP(queue_agent_ringnoanswer_type); + ast_cli_unregister_multiple(cli_queue, ARRAY_LEN(cli_queue)); res = ast_manager_unregister("QueueStatus"); res |= ast_manager_unregister("Queues"); @@ -9960,8 +9999,8 @@ static int unload_module(void) * Module loading including tests for configuration or dependencies. * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE, * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails - * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the - * configuration file or other non-critical problem return + * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the + * configuration file or other non-critical problem return * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS. */ static int load_module(void) @@ -9969,6 +10008,7 @@ static int load_module(void) int res; struct ast_flags mask = {AST_FLAGS_ALL, }; struct ast_config *member_config; + struct stasis_message_router *message_router; queues = ao2_container_alloc(MAX_QUEUE_BUCKETS, queue_hash_cb, queue_cmp_cb); @@ -10039,6 +10079,98 @@ static int load_module(void) res = -1; } + message_router = ast_manager_get_message_router(); + if (!message_router) { + return AST_MODULE_LOAD_DECLINE; + } + + STASIS_MESSAGE_TYPE_INIT(queue_caller_join_type); + STASIS_MESSAGE_TYPE_INIT(queue_caller_leave_type); + STASIS_MESSAGE_TYPE_INIT(queue_caller_abandon_type); + + STASIS_MESSAGE_TYPE_INIT(queue_member_status_type); + STASIS_MESSAGE_TYPE_INIT(queue_member_added_type); + STASIS_MESSAGE_TYPE_INIT(queue_member_removed_type); + STASIS_MESSAGE_TYPE_INIT(queue_member_pause_type); + STASIS_MESSAGE_TYPE_INIT(queue_member_penalty_type); + STASIS_MESSAGE_TYPE_INIT(queue_member_ringinuse_type); + + STASIS_MESSAGE_TYPE_INIT(queue_agent_called_type); + STASIS_MESSAGE_TYPE_INIT(queue_agent_connect_type); + STASIS_MESSAGE_TYPE_INIT(queue_agent_complete_type); + STASIS_MESSAGE_TYPE_INIT(queue_agent_dump_type); + STASIS_MESSAGE_TYPE_INIT(queue_agent_ringnoanswer_type); + + stasis_message_router_add(message_router, + queue_caller_join_type(), + queue_channel_manager_event, + "QueueCallerJoin"); + + stasis_message_router_add(message_router, + queue_caller_leave_type(), + queue_channel_manager_event, + "QueueCallerLeave"); + + stasis_message_router_add(message_router, + queue_caller_abandon_type(), + queue_channel_manager_event, + "QueueCallerAbandon"); + + stasis_message_router_add(message_router, + queue_member_status_type(), + queue_member_manager_event, + "QueueMemberStatus"); + + stasis_message_router_add(message_router, + queue_member_added_type(), + queue_member_manager_event, + "QueueMemberAdded"); + + stasis_message_router_add(message_router, + queue_member_removed_type(), + queue_member_manager_event, + "QueueMemberRemoved"); + + stasis_message_router_add(message_router, + queue_member_pause_type(), + queue_member_manager_event, + "QueueMemberPause"); + + stasis_message_router_add(message_router, + queue_member_penalty_type(), + queue_member_manager_event, + "QueueMemberPenalty"); + + stasis_message_router_add(message_router, + queue_member_ringinuse_type(), + queue_member_manager_event, + "QueueMemberRinginuse"); + + stasis_message_router_add(message_router, + queue_agent_called_type(), + queue_multi_channel_manager_event, + "AgentCalled"); + + stasis_message_router_add(message_router, + queue_agent_connect_type(), + queue_multi_channel_manager_event, + "AgentConnect"); + + stasis_message_router_add(message_router, + queue_agent_complete_type(), + queue_multi_channel_manager_event, + "AgentComplete"); + + stasis_message_router_add(message_router, + queue_agent_dump_type(), + queue_multi_channel_manager_event, + "AgentDump"); + + stasis_message_router_add(message_router, + queue_agent_ringnoanswer_type(), + queue_multi_channel_manager_event, + "AgentRingNoAnswer"); + ast_extension_state_add(NULL, NULL, extension_state_cb, NULL); return res ? AST_MODULE_LOAD_DECLINE : 0; diff --git a/configs/queues.conf.sample b/configs/queues.conf.sample index f7c05181c..80b581f31 100644 --- a/configs/queues.conf.sample +++ b/configs/queues.conf.sample @@ -475,20 +475,6 @@ monitor-type = MixMonitor ; loose - penalty,invalid ; -; If this is set to yes, the following manager events will be generated: -; AgentCalled, AgentDump, AgentConnect, AgentComplete; setting this to -; vars also sends all channel variables with the event. -; (may generate some extra manager events, but probably ones you want) -; -; eventwhencalled = yes|no|vars -; -; If this is set to yes, the following manager events will be generated: -; QueueMemberStatus -; (may generate a WHOLE LOT of extra manager events) -; The default value is yes and this can not be set globally. -; -; eventmemberstatus = no -; ; If you wish to report the caller's hold time to the member before they are ; connected to the caller, set this to yes. ; diff --git a/main/manager.c b/main/manager.c index 95b79e22e..c2f3520a4 100644 --- a/main/manager.c +++ b/main/manager.c @@ -1287,7 +1287,24 @@ struct ast_str *ast_manager_str_from_json_object(struct ast_json *blob, key_excl if (exclusion_cb && exclusion_cb(key)) { continue; } - ast_str_append(&output_str, 0, "%s: %s\r\n", key, ast_json_string_get(value)); + switch (ast_json_typeof(value)) { + case AST_JSON_STRING: + ast_str_append(&output_str, 0, "%s: %s\r\n", key, ast_json_string_get(value)); + break; + case AST_JSON_INTEGER: + ast_str_append(&output_str, 0, "%s: %jd\r\n", key, ast_json_integer_get(value)); + break; + case AST_JSON_TRUE: + ast_str_append(&output_str, 0, "%s: True\r\n", key); + break; + case AST_JSON_FALSE: + ast_str_append(&output_str, 0, "%s: False\r\n", key); + break; + default: + ast_str_append(&output_str, 0, "%s: \r\n", key); + break; + } + if (!output_str) { return NULL; } -- cgit v1.2.3