Refactor extraneous channel events
authorKinsey Moore <kmoore@digium.com>
Mon, 1 Jul 2013 13:16:09 +0000 (13:16 +0000)
committerKinsey Moore <kmoore@digium.com>
Mon, 1 Jul 2013 13:16:09 +0000 (13:16 +0000)
This change removes JitterBufStats, ChannelReload, and ChannelUpdate
and refactors the following events to travel over Stasis-Core:
* LocalBridge
* DAHDIChannel
* AlarmClear
* SpanAlarmClear
* Alarm
* SpanAlarm
* DNDState
* MCID
* SIPQualifyPeerDone
* SessionTimeout

Review: https://reviewboard.asterisk.org/r/2627/
(closes issue ASTERISK-21476)

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@393284 65c4cc65-6c06-0410-ace0-fbb531ad65f3

16 files changed:
CHANGES
apps/app_meetme.c
apps/app_queue.c
channels/chan_dahdi.c
channels/chan_gtalk.c
channels/chan_iax2.c
channels/chan_sip.c
channels/sig_analog.c
channels/sig_pri.c
channels/sip/include/sip.h
configs/sip.conf.sample
include/asterisk/json.h
include/asterisk/stasis.h
main/core_local.c
main/json.c
res/res_agi.c

diff --git a/CHANGES b/CHANGES
index 0d46498..8c12974 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -143,7 +143,7 @@ AMI (Asterisk Manager Interface)
 
  * The SIPqualifypeer action now acknowledges the request once it has established
    that the request is against a known peer. It also issues a new event,
-   'SIPqualifypeerdone', once the qualify action has been completed.
+   'SIPQualifyPeerDone', once the qualify action has been completed.
 
  * The PlayDTMF action now supports an optional 'Duration' parameter.  This
    specifies the duration of the digit to be played, in milliseconds.
@@ -238,6 +238,20 @@ AMI (Asterisk Manager Interface)
    information about each channel.  The (infamous) "Join" and "Leave" AMI
    events have been changed to "QueueCallerJoin" and "QueueCallerLeave".
 
+ * The MCID AMI event now publishes a channel snapshot when available and
+   its non-channel-snapshot parameters now use either the "MCallerID" or
+   "MConnectedID" prefixes with Subaddr*, Name*, and Num* suffixes instead
+   of "CallerID" and "ConnectedID" to avoid confusion with similarly named
+   parameters in the channel snapshot.
+
+ * The "Agentlogin" and "Agentlogoff" events have been renamed "AgentLogin" and
+   "AgentLogoff" respectively.
+
+ * The "Channel" key used in the "AlarmClear", "Alarm", and "DNDState" has been
+   renamed "DAHDIChannel" since it does not convey an Asterisk channel name.
+
+ * "ChannelUpdate" events have been removed.
+
 AGI (Asterisk Gateway Interface)
 ------------------
  * The manager event AGIExec has been split into AGIExecStart and AGIExecEnd.
index 4bd732b..b79ab63 100644 (file)
@@ -1117,75 +1117,15 @@ static const char gain_map[] = {
        15,
 };
 
-/*!
- * \internal
- * \brief accessor for join message type
- * \since 12.0.0
- *
- * \retval pointer to the stasis message type
- * \retval NULL if not initialized
- */
-static struct stasis_message_type *meetme_join_type(void);
-
-/*!
- * \internal
- * \brief accessor for leave message type
- * \since 12.0.0
- *
- * \retval pointer to the stasis message type
- * \retval NULL if not initialized
- */
-static struct stasis_message_type *meetme_leave_type(void);
-
-/*!
- * \internal
- * \brief accessor for end message type
- * \since 12.0.0
- *
- * \retval pointer to the stasis message type
- * \retval NULL if not initialized
- */
-static struct stasis_message_type *meetme_end_type(void);
-
-/*!
- * \internal
- * \brief accessor for mute message type
- * \since 12.0.0
- *
- * \retval pointer to the stasis message type
- * \retval NULL if not initialized
- */
-static struct stasis_message_type *meetme_mute_type(void);
-
-/*!
- * \internal
- * \brief accessor for talking message type
- * \since 12.0.0
- *
- * \retval pointer to the stasis message type
- * \retval NULL if not initialized
- */
-static struct stasis_message_type *meetme_talking_type(void);
-
-/*!
- * \internal
- * \brief accessor for talk request message type
- * \since 12.0.0
- *
- * \retval pointer to the stasis message type
- * \retval NULL if not initialized
- */
-static struct stasis_message_type *meetme_talk_request_type(void);
-
 /* Routes the various meetme message types to the meetme stasis callback function to turn them into events */
 static struct stasis_message_router *meetme_event_message_router;
 
-STASIS_MESSAGE_TYPE_DEFN(meetme_join_type);
-STASIS_MESSAGE_TYPE_DEFN(meetme_leave_type);
-STASIS_MESSAGE_TYPE_DEFN(meetme_end_type);
-STASIS_MESSAGE_TYPE_DEFN(meetme_mute_type);
-STASIS_MESSAGE_TYPE_DEFN(meetme_talking_type);
-STASIS_MESSAGE_TYPE_DEFN(meetme_talk_request_type);
+STASIS_MESSAGE_TYPE_DEFN_LOCAL(meetme_join_type);
+STASIS_MESSAGE_TYPE_DEFN_LOCAL(meetme_leave_type);
+STASIS_MESSAGE_TYPE_DEFN_LOCAL(meetme_end_type);
+STASIS_MESSAGE_TYPE_DEFN_LOCAL(meetme_mute_type);
+STASIS_MESSAGE_TYPE_DEFN_LOCAL(meetme_talking_type);
+STASIS_MESSAGE_TYPE_DEFN_LOCAL(meetme_talk_request_type);
 
 static void meetme_stasis_cb(void *data, struct stasis_subscription *sub,
        struct stasis_topic *topic, struct stasis_message *message);
index 7ff94c6..660b877 100644 (file)
@@ -1811,39 +1811,22 @@ 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);
+STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_caller_join_type);
+STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_caller_leave_type);
+STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_caller_abandon_type);
+
+STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_member_status_type);
+STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_member_added_type);
+STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_member_removed_type);
+STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_member_pause_type);
+STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_member_penalty_type);
+STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_member_ringinuse_type);
+
+STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_agent_called_type);
+STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_agent_connect_type);
+STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_agent_complete_type);
+STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_agent_dump_type);
+STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_agent_ringnoanswer_type);
 
 static void queue_channel_manager_event(void *data,
        struct stasis_subscription *sub, struct stasis_topic *topic,
index 24337e3..b22e738 100644 (file)
@@ -131,6 +131,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/data.h"
 #include "asterisk/features_config.h"
 #include "asterisk/bridging.h"
+#include "asterisk/stasis_channels.h"
 
 /*** DOCUMENTATION
        <application name="DAHDISendKeypadFacility" language="en_US">
@@ -296,6 +297,85 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                        <para>Similar to the CLI command "pri show spans".</para>
                </description>
        </manager>
+       <managerEvent language="en_US" name="AlarmClear">
+               <managerEventInstance class="EVENT_FLAG_SYSTEM">
+                       <synopsis>Raised when an alarm is cleared on a DAHDI channel.</synopsis>
+                       <syntax>
+                               <parameter name="DAHDIChannel">
+                                       <para>The DAHDI channel on which the alarm was cleared.</para>
+                                       <note><para>This is not an Asterisk channel identifier.</para></note>
+                               </parameter>
+                       </syntax>
+               </managerEventInstance>
+       </managerEvent>
+       <managerEvent language="en_US" name="SpanAlarmClear">
+               <managerEventInstance class="EVENT_FLAG_SYSTEM">
+                       <synopsis>Raised when an alarm is cleared on a DAHDI span.</synopsis>
+                       <syntax>
+                               <parameter name="Span">
+                                       <para>The span on which the alarm was cleared.</para>
+                               </parameter>
+                       </syntax>
+               </managerEventInstance>
+       </managerEvent>
+       <managerEvent language="en_US" name="DNDState">
+               <managerEventInstance class="EVENT_FLAG_SYSTEM">
+                       <synopsis>Raised when the Do Not Disturb state is changed on a DAHDI channel.</synopsis>
+                       <syntax>
+                               <parameter name="DAHDIChannel">
+                                       <para>The DAHDI channel on which DND status changed.</para>
+                                       <note><para>This is not an Asterisk channel identifier.</para></note>
+                               </parameter>
+                               <parameter name="Status">
+                                       <enumlist>
+                                               <enum name="enabled"/>
+                                               <enum name="disabled"/>
+                                       </enumlist>
+                               </parameter>
+                       </syntax>
+               </managerEventInstance>
+       </managerEvent>
+       <managerEvent language="en_US" name="Alarm">
+               <managerEventInstance class="EVENT_FLAG_SYSTEM">
+                       <synopsis>Raised when an alarm is set on a DAHDI channel.</synopsis>
+                       <syntax>
+                               <parameter name="DAHDIChannel">
+                                       <para>The channel on which the alarm occurred.</para>
+                                       <note><para>This is not an Asterisk channel identifier.</para></note>
+                               </parameter>
+                               <parameter name="Alarm">
+                                       <para>A textual description of the alarm that occurred.</para>
+                               </parameter>
+                       </syntax>
+               </managerEventInstance>
+       </managerEvent>
+       <managerEvent language="en_US" name="SpanAlarm">
+               <managerEventInstance class="EVENT_FLAG_SYSTEM">
+                       <synopsis>Raised when an alarm is set on a DAHDI span.</synopsis>
+                       <syntax>
+                               <parameter name="Span">
+                                       <para>The span on which the alarm occurred.</para>
+                               </parameter>
+                               <parameter name="Alarm">
+                                       <para>A textual description of the alarm that occurred.</para>
+                               </parameter>
+                       </syntax>
+               </managerEventInstance>
+       </managerEvent>
+       <managerEvent language="en_US" name="DAHDIChannel">
+               <managerEventInstance class="EVENT_FLAG_CALL">
+                       <synopsis>Raised when a DAHDI channel is created or an underlying technology is associated with a DAHDI channel.</synopsis>
+                       <syntax>
+                               <xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
+                               <parameter name="DAHDISpan">
+                                       <para>The DAHDI span associated with this channel.</para>
+                               </parameter>
+                               <parameter name="DAHDIChannel">
+                                       <para>The DAHDI channel associated with this channel.</para>
+                               </parameter>
+                       </syntax>
+               </managerEventInstance>
+       </managerEvent>
  ***/
 
 #define SMDI_MD_WAIT_TIMEOUT 1500 /* 1.5 seconds */
@@ -2270,6 +2350,50 @@ static void my_deadlock_avoidance_private(void *pvt)
        DEADLOCK_AVOIDANCE(&p->lock);
 }
 
+static struct ast_manager_event_blob *dahdichannel_to_ami(struct stasis_message *msg)
+{
+       RAII_VAR(struct ast_str *, channel_string, NULL, ast_free);
+       struct ast_channel_blob *obj = stasis_message_data(msg);
+       struct ast_json *span, *channel;
+
+       channel_string = ast_manager_build_channel_state_string(obj->snapshot);
+       if (!channel_string) {
+               return NULL;
+       }
+
+       span = ast_json_object_get(obj->blob, "span");
+       channel = ast_json_object_get(obj->blob, "channel");
+
+       return ast_manager_event_blob_create(EVENT_FLAG_CALL, "DAHDIChannel",
+               "%s"
+               "DAHDISpan: %d\r\n"
+               "DAHDIChannel: %s\r\n",
+               ast_str_buffer(channel_string),
+               (unsigned int)ast_json_integer_get(span),
+               ast_json_string_get(channel));
+}
+
+STASIS_MESSAGE_TYPE_DEFN_LOCAL(dahdichannel_type,
+       .to_ami = dahdichannel_to_ami,
+       );
+
+/*! \brief Sends a DAHDIChannel channel blob used to produce DAHDIChannel AMI messages */
+static void publish_dahdichannel(struct ast_channel *chan, int span, const char *dahdi_channel)
+{
+       RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
+
+       ast_assert(dahdi_channel != NULL);
+
+       blob = ast_json_pack("{s: i, s: s}",
+               "span", span,
+               "channel", dahdi_channel);
+       if (!blob) {
+               return;
+       }
+
+       ast_channel_publish_blob(chan, dahdichannel_type(), blob);
+}
+
 /*!
  * \internal
  * \brief Post an AMI DAHDI channel association event.
@@ -2294,20 +2418,7 @@ static void dahdi_ami_channel_event(struct dahdi_pvt *p, struct ast_channel *cha
                /* Real channel */
                snprintf(ch_name, sizeof(ch_name), "%d", p->channel);
        }
-       /*** DOCUMENTATION
-               <managerEventInstance>
-                       <synopsis>Raised when a DAHDI channel is created or an underlying technology is associated with a DAHDI channel.</synopsis>
-               </managerEventInstance>
-       ***/
-       ast_manager_event(chan, EVENT_FLAG_CALL, "DAHDIChannel",
-               "Channel: %s\r\n"
-               "Uniqueid: %s\r\n"
-               "DAHDISpan: %d\r\n"
-               "DAHDIChannel: %s\r\n",
-               ast_channel_name(chan),
-               ast_channel_uniqueid(chan),
-               p->span,
-               ch_name);
+       publish_dahdichannel(chan, p->span, ch_name);
 }
 
 #ifdef HAVE_PRI
@@ -3956,6 +4067,37 @@ static void dahdi_queue_frame(struct dahdi_pvt *p, struct ast_frame *f)
        }
 }
 
+static void publish_channel_alarm_clear(int channel)
+{
+       RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
+       RAII_VAR(struct ast_str *, dahdi_chan, ast_str_create(32), ast_free);
+       if (!dahdi_chan) {
+               return;
+       }
+
+       ast_str_set(&dahdi_chan, 0, "%d", channel);
+       ast_log(LOG_NOTICE, "Alarm cleared on channel DAHDI/%d\n", channel);
+       body = ast_json_pack("{s: s}", "DAHDIChannel", ast_str_buffer(dahdi_chan));
+       if (!body) {
+               return;
+       }
+
+       ast_manager_publish_event("AlarmClear", EVENT_FLAG_SYSTEM, body);
+}
+
+static void publish_span_alarm_clear(int span)
+{
+       RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
+
+       ast_log(LOG_NOTICE, "Alarm cleared on span %d\n", span);
+       body = ast_json_pack("{s: i}", "Span", span);
+       if (!body) {
+               return;
+       }
+
+       ast_manager_publish_event("SpanAlarmClear", EVENT_FLAG_SYSTEM, body);
+}
+
 static void handle_clear_alarms(struct dahdi_pvt *p)
 {
 #if defined(HAVE_PRI)
@@ -3965,22 +4107,10 @@ static void handle_clear_alarms(struct dahdi_pvt *p)
 #endif /* defined(HAVE_PRI) */
 
        if (report_alarms & REPORT_CHANNEL_ALARMS) {
-               ast_log(LOG_NOTICE, "Alarm cleared on channel %d\n", p->channel);
-               /*** DOCUMENTATION
-                       <managerEventInstance>
-                               <synopsis>Raised when an alarm is cleared on a DAHDI channel.</synopsis>
-                       </managerEventInstance>
-               ***/
-               manager_event(EVENT_FLAG_SYSTEM, "AlarmClear", "Channel: %d\r\n", p->channel);
+               publish_channel_alarm_clear(p->channel);
        }
        if (report_alarms & REPORT_SPAN_ALARMS && p->manages_span_alarms) {
-               ast_log(LOG_NOTICE, "Alarm cleared on span %d\n", p->span);
-               /*** DOCUMENTATION
-                       <managerEventInstance>
-                               <synopsis>Raised when an alarm is cleared on a DAHDI span.</synopsis>
-                       </managerEventInstance>
-               ***/
-               manager_event(EVENT_FLAG_SYSTEM, "SpanAlarmClear", "Span: %d\r\n", p->span);
+               publish_span_alarm_clear(p->span);
        }
 }
 
@@ -8037,6 +8167,39 @@ static void dahdi_handle_dtmf(struct ast_channel *ast, int idx, struct ast_frame
        }
 }
 
+static void publish_span_alarm(int span, const char *alarm_txt)
+{
+       RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
+
+       body = ast_json_pack("{s: i, s: s}",
+               "Span", span,
+               "Alarm", alarm_txt);
+       if (!body) {
+               return;
+       }
+
+       ast_manager_publish_event("SpanAlarm", EVENT_FLAG_SYSTEM, body);
+}
+
+static void publish_channel_alarm(int channel, const char *alarm_txt)
+{
+       RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
+       RAII_VAR(struct ast_str *, dahdi_chan, ast_str_create(32), ast_free);
+       if (!dahdi_chan) {
+               return;
+       }
+
+       ast_str_set(&dahdi_chan, 0, "%d", channel);
+       body = ast_json_pack("{s: s, s: s}",
+               "DAHDIChannel", ast_str_buffer(dahdi_chan),
+               "Alarm", alarm_txt);
+       if (!body) {
+               return;
+       }
+
+       ast_manager_publish_event("Alarm", EVENT_FLAG_SYSTEM, body);
+}
+
 static void handle_alarms(struct dahdi_pvt *p, int alms)
 {
        const char *alarm_str;
@@ -8050,28 +8213,12 @@ static void handle_alarms(struct dahdi_pvt *p, int alms)
        alarm_str = alarm2str(alms);
        if (report_alarms & REPORT_CHANNEL_ALARMS) {
                ast_log(LOG_WARNING, "Detected alarm on channel %d: %s\n", p->channel, alarm_str);
-               /*** DOCUMENTATION
-                       <managerEventInstance>
-                               <synopsis>Raised when an alarm is set on a DAHDI channel.</synopsis>
-                       </managerEventInstance>
-               ***/
-               manager_event(EVENT_FLAG_SYSTEM, "Alarm",
-                                         "Alarm: %s\r\n"
-                                         "Channel: %d\r\n",
-                                         alarm_str, p->channel);
+               publish_channel_alarm(p->channel, alarm_str);
        }
 
        if (report_alarms & REPORT_SPAN_ALARMS && p->manages_span_alarms) {
                ast_log(LOG_WARNING, "Detected alarm on span %d: %s\n", p->span, alarm_str);
-               /*** DOCUMENTATION
-                       <managerEventInstance>
-                               <synopsis>Raised when an alarm is set on a DAHDI span.</synopsis>
-                       </managerEventInstance>
-               ***/
-               manager_event(EVENT_FLAG_SYSTEM, "SpanAlarm",
-                                         "Alarm: %s\r\n"
-                                         "Span: %d\r\n",
-                                         alarm_str, p->span);
+               publish_span_alarm(p->span, alarm_str);
        }
 }
 
@@ -10083,6 +10230,26 @@ static int dahdi_wink(struct dahdi_pvt *p, int idx)
        return 0;
 }
 
+static void publish_dnd_state(int channel, const char *status)
+{
+       RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
+       RAII_VAR(struct ast_str *, dahdichan, ast_str_create(32), ast_free);
+       if (!dahdichan) {
+               return;
+       }
+
+       ast_str_set(&dahdichan, 0, "%d", channel);
+
+       body = ast_json_pack("{s: s, s: s}",
+               "DAHDIChannel", ast_str_buffer(dahdichan),
+               "Status", status);
+       if (!body) {
+               return;
+       }
+
+       ast_manager_publish_event("DNDState", EVENT_FLAG_SYSTEM, body);
+}
+
 /*! \brief enable or disable the chan_dahdi Do-Not-Disturb mode for a DAHDI channel
  * \param dahdichan "Physical" DAHDI channel (e.g: DAHDI/5)
  * \param flag on 1 to enable, 0 to disable, -1 return dnd value
@@ -10107,24 +10274,7 @@ static int dahdi_dnd(struct dahdi_pvt *dahdichan, int flag)
        ast_verb(3, "%s DND on channel %d\n",
                        flag? "Enabled" : "Disabled",
                        dahdichan->channel);
-       /*** DOCUMENTATION
-               <managerEventInstance>
-                       <synopsis>Raised when the Do Not Disturb state is changed on a DAHDI channel.</synopsis>
-                       <syntax>
-                               <parameter name="Status">
-                                       <enumlist>
-                                               <enum name="enabled"/>
-                                               <enum name="disabled"/>
-                                       </enumlist>
-                               </parameter>
-                       </syntax>
-               </managerEventInstance>
-       ***/
-       manager_event(EVENT_FLAG_SYSTEM, "DNDState",
-                       "Channel: DAHDI/%d\r\n"
-                       "Status: %s\r\n", dahdichan->channel,
-                       flag? "enabled" : "disabled");
-
+       publish_dnd_state(dahdichan->channel, flag ? "enabled" : "disabled");
        return 0;
 }
 
@@ -17154,6 +17304,7 @@ static int __unload_module(void)
        ast_cond_destroy(&ss_thread_complete);
 
        dahdi_tech.capabilities = ast_format_cap_destroy(dahdi_tech.capabilities);
+       STASIS_MESSAGE_TYPE_CLEANUP(dahdichannel_type);
        return 0;
 }
 
@@ -19154,6 +19305,10 @@ static int load_module(void)
        int y;
 #endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
 
+       if (STASIS_MESSAGE_TYPE_INIT(dahdichannel_type)) {
+               return AST_MODULE_LOAD_FAILURE;
+       }
+
        if (!(dahdi_tech.capabilities = ast_format_cap_alloc())) {
                return AST_MODULE_LOAD_FAILURE;
        }
index 49e7ce8..a0aa0b9 100644 (file)
@@ -86,6 +86,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/jabber.h"
 #include "asterisk/jingle.h"
 #include "asterisk/features.h"
+#include "asterisk/stasis_channels.h"
 
 #define GOOGLE_CONFIG          "gtalk.conf"
 
@@ -546,8 +547,6 @@ static int gtalk_answer(struct ast_channel *ast)
        ast_debug(1, "Answer!\n");
        ast_mutex_lock(&p->lock);
        gtalk_invite(p, p->them, p->us,p->sid, 0);
-       manager_event(EVENT_FLAG_SYSTEM, "ChannelUpdate", "Channel: %s\r\nChanneltype: %s\r\nGtalk-SID: %s\r\n",
-               ast_channel_name(ast), "GTALK", p->sid);
        ast_mutex_unlock(&p->lock);
        return res;
 }
@@ -1216,9 +1215,7 @@ static struct ast_channel *gtalk_new(struct gtalk *client, struct gtalk_pvt *i,
                ast_hangup(tmp);
                tmp = NULL;
        } else {
-               manager_event(EVENT_FLAG_SYSTEM, "ChannelUpdate",
-                       "Channel: %s\r\nChanneltype: %s\r\nGtalk-SID: %s\r\n",
-                       i->owner ? ast_channel_name(i->owner) : "", "Gtalk", i->sid);
+               send_channel_update(i->owner, i->sid);
        }
        return tmp;
 }
index 46d1f7d..2300636 100644 (file)
@@ -1392,17 +1392,6 @@ static void acl_change_stasis_cb(void *data, struct stasis_subscription *sub,
        reload_config(1);
 }
 
-
-/*! \brief Send manager event at call setup to link between Asterisk channel name
-       and IAX2 call identifiers */
-static void iax2_ami_channelupdate(struct chan_iax2_pvt *pvt)
-{
-       manager_event(EVENT_FLAG_SYSTEM, "ChannelUpdate",
-               "Channel: %s\r\nChanneltype: IAX2\r\nIAX2-callno-local: %d\r\nIAX2-callno-remote: %d\r\nIAX2-peer: %s\r\n",
-               pvt->owner ? ast_channel_name(pvt->owner) : "",
-               pvt->callno, pvt->peercallno, pvt->peer ? pvt->peer : "");
-}
-
 static const struct ast_datastore_info iax2_variable_datastore_info = {
        .type = "IAX2_VARIABLE",
        .duplicate = iax2_dup_variable_datastore,
@@ -5552,10 +5541,6 @@ static int iax2_answer(struct ast_channel *c)
 {
        unsigned short callno = PTR_TO_CALLNO(ast_channel_tech_pvt(c));
        ast_debug(1, "Answering IAX2 call\n");
-       ast_mutex_lock(&iaxsl[callno]);
-       if (iaxs[callno])
-               iax2_ami_channelupdate(iaxs[callno]);
-       ast_mutex_unlock(&iaxsl[callno]);
        return send_command_locked(callno, AST_FRAME_CONTROL, AST_CONTROL_ANSWER, 0, NULL, 0, -1);
 }
 
@@ -5678,7 +5663,6 @@ static struct ast_channel *ast_iax2_new(int callno, int state, iax2_format capab
                }
                return NULL;
        }
-       iax2_ami_channelupdate(i);
        if (!tmp) {
                return NULL;
        }
@@ -9367,23 +9351,6 @@ static void log_jitterstats(unsigned short callno)
                        iaxs[callno]->remote_rr.dropped,
                        iaxs[callno]->remote_rr.ooo,
                        iaxs[callno]->remote_rr.packets);
-               manager_event(EVENT_FLAG_REPORTING, "JitterBufStats", "Owner: %s\r\nPing: %d\r\nLocalJitter: %d\r\nLocalJBDelay: %d\r\nLocalTotalLost: %d\r\nLocalLossPercent: %d\r\nLocalDropped: %d\r\nLocalooo: %d\r\nLocalReceived: %d\r\nRemoteJitter: %d\r\nRemoteJBDelay: %d\r\nRemoteTotalLost: %d\r\nRemoteLossPercent: %d\r\nRemoteDropped: %d\r\nRemoteooo: %d\r\nRemoteReceived: %d\r\n",
-                       ast_channel_name(iaxs[callno]->owner),
-                       iaxs[callno]->pingtime,
-                       localjitter,
-                       localdelay,
-                       locallost,
-                       locallosspct,
-                       localdropped,
-                       localooo,
-                       localpackets,
-                       iaxs[callno]->remote_rr.jitter,
-                       iaxs[callno]->remote_rr.delay,
-                       iaxs[callno]->remote_rr.losscnt,
-                       iaxs[callno]->remote_rr.losspct/1000,
-                       iaxs[callno]->remote_rr.dropped,
-                       iaxs[callno]->remote_rr.ooo,
-                       iaxs[callno]->remote_rr.packets);
        }
        ast_mutex_unlock(&iaxsl[callno]);
 }
index 4b79552..9a5f086 100644 (file)
@@ -295,6 +295,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/app.h"
 #include "asterisk/bridging.h"
 #include "asterisk/stasis_endpoints.h"
+#include "asterisk/stasis_channels.h"
 #include "asterisk/features_config.h"
 
 /*** DOCUMENTATION
@@ -563,7 +564,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                        <para>Qualify a SIP peer.</para>
                </description>
                <see-also>
-                       <ref type="managerEvent">SIPqualifypeerdone</ref>
+                       <ref type="managerEvent">SIPQualifyPeerDone</ref>
                </see-also>
        </manager>
        <manager name="SIPshowregistry" language="en_US">
@@ -621,6 +622,37 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                <para>Specifying a prefix of <literal>sip:</literal> will send the
                message as a SIP MESSAGE request.</para>
        </info>
+       <managerEvent language="en_US" name="SIPQualifyPeerDone">
+               <managerEventInstance class="EVENT_FLAG_CALL">
+                       <synopsis>Raised when SIPQualifyPeer has finished qualifying the specified peer.</synopsis>
+                       <syntax>
+                               <parameter name="Peer">
+                                       <para>The name of the peer.</para>
+                               </parameter>
+                               <parameter name="ActionID">
+                                       <para>This is only included if an ActionID Header was sent with the action request, in which case it will be that ActionID.</para>
+                               </parameter>
+                       </syntax>
+                       <see-also>
+                               <ref type="manager">SIPqualifypeer</ref>
+                       </see-also>
+               </managerEventInstance>
+       </managerEvent>
+       <managerEvent language="en_US" name="SessionTimeout">
+               <managerEventInstance class="EVENT_FLAG_CALL">
+                       <synopsis>Raised when a SIP session times out.</synopsis>
+                       <syntax>
+                               <xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
+                               <parameter name="Source">
+                                       <para>The source of the session timeout.</para>
+                                       <enumlist>
+                                               <enum name="RTPTimeout" />
+                                               <enum name="SIPSessionTimer" />
+                                       </enumlist>
+                               </parameter>
+                       </syntax>
+               </managerEventInstance>
+       </managerEvent>
  ***/
 
 static int min_expiry = DEFAULT_MIN_EXPIRY;        /*!< Minimum accepted registration time */
@@ -1042,6 +1074,11 @@ static struct sip_auth_container *authl = NULL;
 /*! \brief Global authentication container protection while adjusting the references. */
 AST_MUTEX_DEFINE_STATIC(authl_lock);
 
+static struct ast_manager_event_blob *session_timeout_to_ami(struct stasis_message *msg);
+STASIS_MESSAGE_TYPE_DEFN_LOCAL(session_timeout_type,
+       .to_ami = session_timeout_to_ami,
+       );
+
 /* --- Sockets and networking --------------*/
 
 /*! \brief Main socket for UDP SIP communication.
@@ -8212,13 +8249,6 @@ static struct ast_channel *sip_new(struct sip_pvt *i, int state, const char *tit
                append_history(i, "NewChan", "Channel %s - from %s", ast_channel_name(tmp), i->callid);
        }
 
-       /* Inform manager user about new channel and their SIP call ID */
-       if (sip_cfg.callevents) {
-               manager_event(EVENT_FLAG_SYSTEM, "ChannelUpdate",
-                       "Channel: %s\r\nUniqueid: %s\r\nChanneltype: %s\r\nSIPcallid: %s\r\nSIPfullcontact: %s\r\n",
-                       ast_channel_name(tmp), ast_channel_uniqueid(tmp), "SIP", i->callid, i->fullcontact);
-       }
-
        return tmp;
 }
 
@@ -20007,6 +20037,21 @@ static int manager_sip_peer_status(struct mansession *s, const struct message *m
        return 0;
 }
 
+static void publish_qualify_peer_done(const char *id, const char *peer)
+{
+       RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
+
+       if (ast_strlen_zero(id)) {
+               body = ast_json_pack("{s: s}", "Peer", peer);
+       } else {
+               body = ast_json_pack("{s: s, s: s}", "Peer", peer, "ActionID", id);
+       }
+       if (!body) {
+               return;
+       }
+
+       ast_manager_publish_event("SIPQualifyPeerDone", EVENT_FLAG_CALL, body);
+}
 
 /*! \brief Send qualify message to peer from cli or manager. Mostly for debugging. */
 static char *_sip_qualify_peer(int type, int fd, struct mansession *s, const struct message *m, int argc, const char *argv[])
@@ -20019,41 +20064,15 @@ static char *_sip_qualify_peer(int type, int fd, struct mansession *s, const str
 
        load_realtime = (argc == 5 && !strcmp(argv[4], "load")) ? TRUE : FALSE;
        if ((peer = sip_find_peer(argv[3], NULL, load_realtime, FINDPEERS, FALSE, 0))) {
-
                const char *id = astman_get_header(m,"ActionID");
-               char idText[256] = "";
 
                if (type != 0) {
                        astman_send_ack(s, m, "SIP peer found - will qualify");
                }
 
-               if (!ast_strlen_zero(id)) {
-                       snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
-               }
-
                sip_poke_peer(peer, 1);
 
-               /*** DOCUMENTATION
-                       <managerEventInstance>
-                               <synopsis>Raised when SIPqualifypeer has finished qualifying the specified peer.</synopsis>
-                               <syntax>
-                                       <parameter name="Peer">
-                                               <para>The name of the peer.</para>
-                                       </parameter>
-                                       <parameter name="ActionID">
-                                               <para>This is only included if an ActionID Header was sent with the action request, in which case it will be that ActionID.</para>
-                                       </parameter>
-                               </syntax>
-                               <see-also>
-                                       <ref type="manager">SIPqualifypeer</ref>
-                               </see-also>
-                       </managerEventInstance>
-               ***/
-               manager_event(EVENT_FLAG_CALL, "SIPqualifypeerdone",
-                       "Peer: %s\r\n"
-                       "%s",
-                       argv[3],
-                       idText);
+               publish_qualify_peer_done(id, argv[3]);
 
                sip_unref_peer(peer, "qualify: done with peer");
        } else if (type == 0) {
@@ -20887,7 +20906,6 @@ static char *sip_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_
                ast_cli(a->fd, "  From: Domain:           %s\n", default_fromdomain);
        }
        ast_cli(a->fd, "  Record SIP history:     %s\n", AST_CLI_ONOFF(recordhistory));
-       ast_cli(a->fd, "  Call Events:            %s\n", AST_CLI_ONOFF(sip_cfg.callevents));
        ast_cli(a->fd, "  Auth. Failure Events:   %s\n", AST_CLI_ONOFF(global_authfailureevents));
 
        ast_cli(a->fd, "  T.38 support:           %s\n", AST_CLI_YESNO(ast_test_flag(&global_flags[1], SIP_PAGE2_T38SUPPORT)));
@@ -23140,11 +23158,6 @@ static void handle_response_invite(struct sip_pvt *p, int resp, const char *rest
                if (!req->ignore && p->owner) {
                        if (!reinvite) {
                                ast_queue_control(p->owner, AST_CONTROL_ANSWER);
-                               if (sip_cfg.callevents) {
-                                       manager_event(EVENT_FLAG_SYSTEM, "ChannelUpdate",
-                                               "Channel: %s\r\nChanneltype: %s\r\nUniqueid: %s\r\nSIPcallid: %s\r\nSIPfullcontact: %s\r\nPeername: %s\r\n",
-                                               ast_channel_name(p->owner), "SIP", ast_channel_uniqueid(p->owner), p->callid, p->fullcontact, p->peername);
-                               }
                        } else {        /* RE-invite */
                                if (p->t38.state == T38_DISABLED || p->t38.state == T38_REJECTED) {
                                        ast_queue_control(p->owner, AST_CONTROL_UPDATE_RTP_PEER);
@@ -28458,6 +28471,39 @@ static int sip_send_mwi_to_peer(struct sip_peer *peer, int cache_only)
        return 0;
 }
 
+static struct ast_manager_event_blob *session_timeout_to_ami(struct stasis_message *msg)
+{
+       RAII_VAR(struct ast_str *, channel_string, NULL, ast_free);
+       struct ast_channel_blob *obj = stasis_message_data(msg);
+       const char *source = ast_json_string_get(ast_json_object_get(obj->blob, "source"));
+
+       channel_string = ast_manager_build_channel_state_string(obj->snapshot);
+       if (!channel_string) {
+               return NULL;
+       }
+
+       return ast_manager_event_blob_create(EVENT_FLAG_CALL, "SessionTimeout",
+               "%s"
+               "Source: %s\r\n",
+               ast_str_buffer(channel_string), source);
+}
+
+/*! \brief Sends a session timeout channel blob used to produce SessionTimeout AMI messages */
+static void send_session_timeout(struct ast_channel *chan, const char *source)
+{
+       RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
+
+       ast_assert(chan != NULL);
+       ast_assert(source != NULL);
+
+       blob = ast_json_pack("{s: s}", "source", source);
+       if (!blob) {
+               return;
+       }
+
+       ast_channel_publish_blob(chan, session_timeout_type(), blob);
+}
+
 /*!
  * \brief helper function for the monitoring thread -- seems to be called with the assumption that the dialog is locked
  *
@@ -28533,8 +28579,8 @@ static int check_rtp_timeout(struct sip_pvt *dialog, time_t t)
                                }
                                ast_log(LOG_NOTICE, "Disconnecting call '%s' for lack of RTP activity in %ld seconds\n",
                                        ast_channel_name(dialog->owner), (long) (t - dialog->lastrtprx));
-                               manager_event(EVENT_FLAG_CALL, "SessionTimeout", "Source: RTPTimeout\r\n"
-                                               "Channel: %s\r\nUniqueid: %s\r\n", ast_channel_name(dialog->owner), ast_channel_uniqueid(dialog->owner));
+                               send_session_timeout(dialog->owner, "RTPTimeout");
+
                                /* Issue a softhangup */
                                ast_softhangup_nolock(dialog->owner, AST_SOFTHANGUP_DEV);
                                ast_channel_unlock(dialog->owner);
@@ -28813,8 +28859,7 @@ static int proc_session_timer(const void *vp)
                        sip_pvt_lock(p);
                }
 
-               manager_event(EVENT_FLAG_CALL, "SessionTimeout", "Source: SIPSessionTimer\r\n"
-                               "Channel: %s\r\nUniqueid: %s\r\n", ast_channel_name(p->owner), ast_channel_uniqueid(p->owner));
+               send_session_timeout(p->owner, "SIPSessionTimer");
                ast_softhangup_nolock(p->owner, AST_SOFTHANGUP_DEV);
                ast_channel_unlock(p->owner);
                sip_pvt_unlock(p);
@@ -29551,10 +29596,6 @@ static struct ast_channel *sip_request_call(const char *type, struct ast_format_
                callid = ast_callid_unref(callid);
        }
 
-       if (sip_cfg.callevents)
-               manager_event(EVENT_FLAG_SYSTEM, "ChannelUpdate",
-                       "Channel: %s\r\nChanneltype: %s\r\nSIPcallid: %s\r\nSIPfullcontact: %s\r\nPeername: %s\r\n",
-                       p->owner? ast_channel_name(p->owner) : "", "SIP", p->callid, p->fullcontact, p->peername);
        sip_pvt_unlock(p);
        if (!tmpc) {
                dialog_unlink_all(p);
@@ -31160,7 +31201,6 @@ static int reload_config(enum channelreloadreason reason)
 
        /* Misc settings for the channel */
        global_relaxdtmf = FALSE;
-       sip_cfg.callevents = DEFAULT_CALLEVENTS;
        global_authfailureevents = FALSE;
        global_t1 = DEFAULT_TIMER_T1;
        global_timer_b = 64 * DEFAULT_TIMER_T1;
@@ -31641,8 +31681,6 @@ static int reload_config(enum channelreloadreason reason)
                                ast_log(LOG_WARNING, "Invalid qualifyfreq number '%s' at line %d of %s\n", v->value, v->lineno, config);
                                global_qualifyfreq = DEFAULT_QUALIFYFREQ;
                        }
-               } else if (!strcasecmp(v->name, "callevents")) {
-                       sip_cfg.callevents = ast_true(v->value);
                } else if (!strcasecmp(v->name, "authfailureevents")) {
                        global_authfailureevents = ast_true(v->value);
                } else if (!strcasecmp(v->name, "maxcallbitrate")) {
@@ -32079,8 +32117,6 @@ static int reload_config(enum channelreloadreason reason)
                notify_types = NULL;
        }
 
-       /* Done, tell the manager */
-       manager_event(EVENT_FLAG_SYSTEM, "ChannelReload", "ChannelType: SIP\r\nReloadReason: %s\r\nRegistry_Count: %d\r\nPeer_Count: %d\r\n", channelreloadreason2txt(reason), registry_count, peer_count);
        run_end = time(0);
        ast_debug(4, "SIP reload_config done...Runtime= %d sec\n", (int)(run_end-run_start));
 
@@ -34059,6 +34095,10 @@ static int load_module(void)
 {
        ast_verbose("SIP channel loading...\n");
 
+       if (STASIS_MESSAGE_TYPE_INIT(session_timeout_type)) {
+               return AST_MODULE_LOAD_FAILURE;
+       }
+
        if (!(sip_tech.capabilities = ast_format_cap_alloc())) {
                return AST_MODULE_LOAD_FAILURE;
        }
@@ -34425,6 +34465,8 @@ static int unload_module(void)
        ast_format_cap_destroy(sip_tech.capabilities);
        sip_cfg.caps = ast_format_cap_destroy(sip_cfg.caps);
 
+       STASIS_MESSAGE_TYPE_CLEANUP(session_timeout_type);
+
        return 0;
 }
 
index 9660d3f..276e0fd 100644 (file)
@@ -2622,6 +2622,19 @@ int analog_ss_thread_start(struct analog_pvt *p, struct ast_channel *chan)
        return ast_pthread_create_detached(&threadid, NULL, __analog_ss_thread, p);
 }
 
+static void analog_publish_channel_alarm_clear(int channel)
+{
+       RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
+
+       ast_log(LOG_NOTICE, "Alarm cleared on channel %d\n", channel);
+       body = ast_json_pack("{s: i}", "Channel", channel);
+       if (!body) {
+               return;
+       }
+
+       ast_manager_publish_event("AlarmClear", EVENT_FLAG_SYSTEM, body);
+}
+
 static struct ast_frame *__analog_handle_event(struct analog_pvt *p, struct ast_channel *ast)
 {
        int res, x;
@@ -3086,14 +3099,7 @@ static struct ast_frame *__analog_handle_event(struct analog_pvt *p, struct ast_
                break;
        case ANALOG_EVENT_NOALARM:
                analog_set_alarm(p, 0);
-               ast_log(LOG_NOTICE, "Alarm cleared on channel %d\n", p->channel);
-               /*** DOCUMENTATION
-                       <managerEventInstance>
-                               <synopsis>Raised when an Alarm is cleared on an Analog channel.</synopsis>
-                       </managerEventInstance>
-               ***/
-               manager_event(EVENT_FLAG_SYSTEM, "AlarmClear",
-                       "Channel: %d\r\n", p->channel);
+               analog_publish_channel_alarm_clear(p->channel);
                break;
        case ANALOG_EVENT_WINKFLASH:
                if (p->inalarm) {
@@ -3735,9 +3741,7 @@ void *analog_handle_init_event(struct analog_pvt *i, int event)
                break;
        case ANALOG_EVENT_NOALARM:
                analog_set_alarm(i, 0);
-               ast_log(LOG_NOTICE, "Alarm cleared on channel %d\n", i->channel);
-               manager_event(EVENT_FLAG_SYSTEM, "AlarmClear",
-                       "Channel: %d\r\n", i->channel);
+               analog_publish_channel_alarm_clear(i->channel);
                break;
        case ANALOG_EVENT_ALARM:
                analog_set_alarm(i, 1);
@@ -3940,6 +3944,26 @@ int analog_fixup(struct ast_channel *oldchan, struct ast_channel *newchan, void
        return 0;
 }
 
+static void analog_publish_dnd_state(int channel, const char *status)
+{
+       RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
+       RAII_VAR(struct ast_str *, dahdichan, ast_str_create(32), ast_free);
+       if (!dahdichan) {
+               return;
+       }
+
+       ast_str_set(&dahdichan, 0, "DAHDI/%d", channel);
+
+       body = ast_json_pack("{s: s, s: s}",
+               "Channel", ast_str_buffer(dahdichan),
+               "Status", status);
+       if (!body) {
+               return;
+       }
+
+       ast_manager_publish_event("DNDState", EVENT_FLAG_SYSTEM, body);
+}
+
 int analog_dnd(struct analog_pvt *p, int flag)
 {
        if (flag == -1) {
@@ -3951,23 +3975,7 @@ int analog_dnd(struct analog_pvt *p, int flag)
        ast_verb(3, "%s DND on channel %d\n",
                        flag ? "Enabled" : "Disabled",
                        p->channel);
-       /*** DOCUMENTATION
-               <managerEventInstance>
-                       <synopsis>Raised when the Do Not Disturb state is changed on an Analog channel.</synopsis>
-                       <syntax>
-                               <parameter name="Status">
-                                       <enumlist>
-                                               <enum name="enabled"/>
-                                               <enum name="disabled"/>
-                                       </enumlist>
-                               </parameter>
-                       </syntax>
-               </managerEventInstance>
-       ***/
-       manager_event(EVENT_FLAG_SYSTEM, "DNDState",
-                       "Channel: DAHDI/%d\r\n"
-                       "Status: %s\r\n", p->channel,
-                       flag ? "enabled" : "disabled");
+       analog_publish_dnd_state(p->channel, flag ? "enabled" : "disabled");
 
        return 0;
 }
index d5d6f49..5f07928 100644 (file)
 /*** MODULEINFO
        <support_level>core</support_level>
  ***/
+/*** DOCUMENTATION
+       <managerEvent language="en_US" name="MCID">
+               <managerEventInstance class="EVENT_FLAG_CALL">
+                       <synopsis>Published when a malicious call ID request arrives.</synopsis>
+                       <syntax>
+                               <xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
+                               <parameter name="MCallerIDNumValid">
+                               </parameter>
+                               <parameter name="MCallerIDNum">
+                               </parameter>
+                               <parameter name="MCallerIDton">
+                               </parameter>
+                               <parameter name="MCallerIDNumPlan">
+                               </parameter>
+                               <parameter name="MCallerIDNumPres">
+                               </parameter>
+                               <parameter name="MCallerIDNameValid">
+                               </parameter>
+                               <parameter name="MCallerIDName">
+                               </parameter>
+                               <parameter name="MCallerIDNameCharSet">
+                               </parameter>
+                               <parameter name="MCallerIDNamePres">
+                               </parameter>
+                               <parameter name="MCallerIDSubaddr">
+                               </parameter>
+                               <parameter name="MCallerIDSubaddrType">
+                               </parameter>
+                               <parameter name="MCallerIDSubaddrOdd">
+                               </parameter>
+                               <parameter name="MCallerIDPres">
+                               </parameter>
+                               <parameter name="MConnectedIDNumValid">
+                               </parameter>
+                               <parameter name="MConnectedIDNum">
+                               </parameter>
+                               <parameter name="MConnectedIDton">
+                               </parameter>
+                               <parameter name="MConnectedIDNumPlan">
+                               </parameter>
+                               <parameter name="MConnectedIDNumPres">
+                               </parameter>
+                               <parameter name="MConnectedIDNameValid">
+                               </parameter>
+                               <parameter name="MConnectedIDName">
+                               </parameter>
+                               <parameter name="MConnectedIDNameCharSet">
+                               </parameter>
+                               <parameter name="MConnectedIDNamePres">
+                               </parameter>
+                               <parameter name="MConnectedIDSubaddr">
+                               </parameter>
+                               <parameter name="MConnectedIDSubaddrType">
+                               </parameter>
+                               <parameter name="MConnectedIDSubaddrOdd">
+                               </parameter>
+                               <parameter name="MConnectedIDPres">
+                               </parameter>
+                       </syntax>
+               </managerEventInstance>
+       </managerEvent>
+ ***/
 
 #include "asterisk.h"
 
 #include "asterisk/features.h"
 #include "asterisk/aoc.h"
 #include "asterisk/bridging.h"
+#include "asterisk/stasis_channels.h"
 
 #include "sig_pri.h"
 #ifndef PRI_EVENT_FACILITY
@@ -2270,9 +2333,74 @@ static int sig_pri_msn_match(const char *msn_patterns, const char *exten)
 }
 
 #if defined(HAVE_PRI_MCID)
+static void party_number_json_to_ami(struct ast_str **msg, const char *prefix, struct ast_json *number)
+{
+       const char *num_txt, *pres_txt;
+       int plan, pres;
+       if (!number) {
+               ast_str_append(msg, 0,
+                       "%sNumValid: 0\r\n"
+                       "%sNum: \r\n"
+                       "%ston: 0\r\n",
+                       prefix, prefix, prefix);
+               return;
+       }
+
+       num_txt = ast_json_string_get(ast_json_object_get(number, "number"));
+       plan = ast_json_integer_get(ast_json_object_get(number, "plan"));
+       pres = ast_json_integer_get(ast_json_object_get(number, "presentation"));
+       pres_txt = ast_json_string_get(ast_json_object_get(number, "presentation_txt"));
+
+       ast_str_append(msg, 0, "%sNumValid: 1\r\n", prefix);
+       ast_str_append(msg, 0, "%sNum: %s\r\n", prefix, num_txt);
+       ast_str_append(msg, 0, "%ston: %d\r\n", prefix, plan);
+       ast_str_append(msg, 0, "%sNumPlan: %d\r\n", prefix, plan);
+       ast_str_append(msg, 0, "%sNumPres: %d (%s)\r\n", prefix, pres, pres_txt);
+}
+
+static void party_name_json_to_ami(struct ast_str **msg, const char *prefix, struct ast_json *name)
+{
+       const char *name_txt, *pres_txt, *charset;
+       int pres;
+       if (!name) {
+               ast_str_append(msg, 0,
+                       "%sNameValid: 0\r\n"
+                       "%sName: \r\n",
+                       prefix, prefix);
+               return;
+       }
+
+       name_txt = ast_json_string_get(ast_json_object_get(name, "name"));
+       charset = ast_json_string_get(ast_json_object_get(name, "character_set"));
+       pres = ast_json_integer_get(ast_json_object_get(name, "presentation"));
+       pres_txt = ast_json_string_get(ast_json_object_get(name, "presentation_txt"));
+
+       ast_str_append(msg, 0, "%sNameValid: 1\r\n", prefix);
+       ast_str_append(msg, 0, "%sName: %s\r\n", prefix, name_txt);
+       ast_str_append(msg, 0, "%sNameCharSet: %s\r\n", prefix, charset);
+       ast_str_append(msg, 0, "%sNamePres: %d (%s)\r\n", prefix, pres, pres_txt);
+}
+
+static void party_subaddress_json_to_ami(struct ast_str **msg, const char *prefix, struct ast_json *subaddress)
+{
+       const char *subaddress_txt, *type_txt;
+       int odd;
+       if (!subaddress) {
+               return;
+       }
+
+       subaddress_txt = ast_json_string_get(ast_json_object_get(subaddress, "subaddress"));
+       type_txt = ast_json_string_get(ast_json_object_get(subaddress, "type"));
+       odd = ast_json_is_true(ast_json_object_get(subaddress, "odd")) ? 1 : 0;
+
+       ast_str_append(msg, 0, "%sSubaddr: %s\r\n", prefix, subaddress_txt);
+       ast_str_append(msg, 0, "%sSubaddrType: %s\r\n", prefix, type_txt);
+       ast_str_append(msg, 0, "%sSubaddrOdd: %d\r\n", prefix, odd);
+}
+
 /*!
  * \internal
- * \brief Append the given party id to the event string.
+ * \brief Append the given JSON party id to the event string.
  * \since 1.8
  *
  * \param msg Event message string being built.
@@ -2281,58 +2409,72 @@ static int sig_pri_msn_match(const char *msn_patterns, const char *exten)
  *
  * \return Nothing
  */
-static void sig_pri_event_party_id(struct ast_str **msg, const char *prefix, struct ast_party_id *party)
+static void party_json_to_ami(struct ast_str **msg, const char *prefix, struct ast_json *party)
 {
-       int pres;
+       struct ast_json *presentation = ast_json_object_get(party, "presentation");
+       struct ast_json *presentation_txt = ast_json_object_get(party, "presentation_txt");
+       struct ast_json *name = ast_json_object_get(party, "name");
+       struct ast_json *number = ast_json_object_get(party, "number");
+       struct ast_json *subaddress = ast_json_object_get(party, "subaddress");
 
        /* Combined party presentation */
-       pres = ast_party_id_presentation(party);
-       ast_str_append(msg, 0, "%sPres: %d (%s)\r\n", prefix, pres,
-               ast_describe_caller_presentation(pres));
+       ast_str_append(msg, 0, "%sPres: %d (%s)\r\n", prefix,
+               (uint32_t)ast_json_integer_get(presentation),
+               ast_json_string_get(presentation_txt));
 
        /* Party number */
-       ast_str_append(msg, 0, "%sNumValid: %d\r\n", prefix,
-               (unsigned) party->number.valid);
-       ast_str_append(msg, 0, "%sNum: %s\r\n", prefix,
-               S_COR(party->number.valid, party->number.str, ""));
-       ast_str_append(msg, 0, "%ston: %d\r\n", prefix, party->number.plan);
-       if (party->number.valid) {
-               ast_str_append(msg, 0, "%sNumPlan: %d\r\n", prefix, party->number.plan);
-               ast_str_append(msg, 0, "%sNumPres: %d (%s)\r\n", prefix,
-                       party->number.presentation,
-                       ast_describe_caller_presentation(party->number.presentation));
-       }
+       party_number_json_to_ami(msg, prefix, number);
 
        /* Party name */
-       ast_str_append(msg, 0, "%sNameValid: %d\r\n", prefix,
-               (unsigned) party->name.valid);
-       ast_str_append(msg, 0, "%sName: %s\r\n", prefix,
-               S_COR(party->name.valid, party->name.str, ""));
-       if (party->name.valid) {
-               ast_str_append(msg, 0, "%sNameCharSet: %s\r\n", prefix,
-                       ast_party_name_charset_describe(party->name.char_set));
-               ast_str_append(msg, 0, "%sNamePres: %d (%s)\r\n", prefix,
-                       party->name.presentation,
-                       ast_describe_caller_presentation(party->name.presentation));
-       }
+       party_name_json_to_ami(msg, prefix, name);
 
-#if defined(HAVE_PRI_SUBADDR)
        /* Party subaddress */
-       if (party->subaddress.valid) {
-               static const char subaddress[] = "Subaddr";
+       party_subaddress_json_to_ami(msg, prefix, subaddress);
+}
+
+static struct ast_manager_event_blob *mcid_to_ami(struct stasis_message *msg)
+{
+       RAII_VAR(struct ast_str *, channel_string, NULL, ast_free);
+       RAII_VAR(struct ast_str *, party_string, ast_str_create(256), ast_free);
+       struct ast_channel_blob *obj = stasis_message_data(msg);
 
-               ast_str_append(msg, 0, "%s%s: %s\r\n", prefix, subaddress,
-                       S_OR(party->subaddress.str, ""));
-               ast_str_append(msg, 0, "%s%sType: %d\r\n", prefix, subaddress,
-                       party->subaddress.type);
-               ast_str_append(msg, 0, "%s%sOdd: %d\r\n", prefix, subaddress,
-                       party->subaddress.odd_even_indicator);
+       if (obj->snapshot) {
+               channel_string = ast_manager_build_channel_state_string(obj->snapshot);
+               if (!channel_string) {
+                       return NULL;
+               }
        }
-#endif /* defined(HAVE_PRI_SUBADDR) */
+
+       party_json_to_ami(&party_string, "MCallerID", ast_json_object_get(obj->blob, "caller"));
+       party_json_to_ami(&party_string, "MConnectedID", ast_json_object_get(obj->blob, "connected"));
+
+       return ast_manager_event_blob_create(EVENT_FLAG_CALL, "MCID",
+               "%s"
+               "%s",
+               S_COR(obj->snapshot, ast_str_buffer(channel_string), ""), ast_str_buffer(party_string));
+}
+
+STASIS_MESSAGE_TYPE_DEFN_LOCAL(mcid_type,
+       .to_ami = mcid_to_ami,
+       );
+
+static void send_mcid(struct ast_channel *chan, struct ast_party_id *caller, struct ast_party_id *connected)
+{
+       RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
+
+       ast_assert(caller != NULL);
+       ast_assert(connected != NULL);
+
+       blob = ast_json_pack("{s: o, s: o}",
+               "caller", ast_json_party_id(caller),
+               "connected", ast_json_party_id(connected));
+       if (!blob) {
+               return;
+       }
+
+       ast_channel_publish_blob(chan, mcid_type(), blob);
 }
-#endif /* defined(HAVE_PRI_MCID) */
 
-#if defined(HAVE_PRI_MCID)
 /*!
  * \internal
  * \brief Handle the MCID event.
@@ -2350,15 +2492,12 @@ static void sig_pri_event_party_id(struct ast_str **msg, const char *prefix, str
  */
 static void sig_pri_mcid_event(struct sig_pri_span *pri, const struct pri_subcmd_mcid_req *mcid, struct ast_channel *owner)
 {
-       struct ast_channel *chans[1];
-       struct ast_str *msg;
-       struct ast_party_id party;
-
-       msg = ast_str_create(4096);
-       if (!msg) {
-               return;
-       }
+       struct ast_party_id caller_party;
+       struct ast_party_id connected_party;
 
+       /* Always use libpri's called party information. */
+       ast_party_id_init(&connected_party);
+       sig_pri_party_id_convert(&connected_party, &mcid->answerer, pri);
        if (owner) {
                /*
                 * The owner channel is present.
@@ -2366,31 +2505,18 @@ static void sig_pri_mcid_event(struct sig_pri_span *pri, const struct pri_subcmd
                 */
                ast_queue_control(owner, AST_CONTROL_MCID);
 
-               ast_str_append(&msg, 0, "Channel: %s\r\n", ast_channel_name(owner));
-               ast_str_append(&msg, 0, "UniqueID: %s\r\n", ast_channel_uniqueid(owner));
-
-               sig_pri_event_party_id(&msg, "CallerID", &ast_channel_connected(owner)->id);
+               send_mcid(owner, &ast_channel_connected(owner)->id, &connected_party);
        } else {
                /*
                 * Since we no longer have an owner channel,
                 * we have to use the caller information supplied by libpri.
                 */
-               ast_party_id_init(&party);
-               sig_pri_party_id_convert(&party, &mcid->originator, pri);
-               sig_pri_event_party_id(&msg, "CallerID", &party);
-               ast_party_id_free(&party);
+               ast_party_id_init(&caller_party);
+               sig_pri_party_id_convert(&caller_party, &mcid->originator, pri);
+               send_mcid(owner, &caller_party, &connected_party);
+               ast_party_id_free(&caller_party);
        }
-
-       /* Always use libpri's called party information. */
-       ast_party_id_init(&party);
-       sig_pri_party_id_convert(&party, &mcid->answerer, pri);
-       sig_pri_event_party_id(&msg, "ConnectedID", &party);
-       ast_party_id_free(&party);
-
-       chans[0] = owner;
-       ast_manager_event_multichan(EVENT_FLAG_CALL, "MCID", owner ? 1 : 0, chans, "%s",
-               ast_str_buffer(msg));
-       ast_free(msg);
+       ast_party_id_free(&connected_party);
 }
 #endif /* defined(HAVE_PRI_MCID) */
 
@@ -10003,6 +10129,12 @@ void sig_pri_cc_monitor_destructor(void *monitor_pvt)
  */
 int sig_pri_load(const char *cc_type_name)
 {
+#if defined(HAVE_PRI_MCID)
+       if (STASIS_MESSAGE_TYPE_INIT(mcid_type)) {
+               return -1;
+       }
+#endif /* defined(HAVE_PRI_MCID) */
+
 #if defined(HAVE_PRI_CCSS)
        sig_pri_cc_type_name = cc_type_name;
        sig_pri_cc_monitors = ao2_container_alloc(37, sig_pri_cc_monitor_instance_hash_fn,
@@ -10028,6 +10160,10 @@ void sig_pri_unload(void)
                sig_pri_cc_monitors = NULL;
        }
 #endif /* defined(HAVE_PRI_CCSS) */
+
+#if defined(HAVE_PRI_MCID)
+       STASIS_MESSAGE_TYPE_CLEANUP(mcid_type);
+#endif /* defined(HAVE_PRI_MCID) */
 }
 
 #endif /* HAVE_PRI */
index 8b4672b..3029439 100644 (file)
 #define DEFAULT_QUALIFY        FALSE    /*!< Don't monitor devices */
 #define DEFAULT_KEEPALIVE      0        /*!< Don't send keep alive packets */
 #define DEFAULT_KEEPALIVE_INTERVAL 60   /*!< Send keep alive packets at 60 second intervals */
-#define DEFAULT_CALLEVENTS     FALSE    /*!< Extra manager SIP call events */
 #define DEFAULT_ALWAYSAUTHREJECT  TRUE  /*!< Don't reject authentication requests always */
 #define DEFAULT_AUTH_OPTIONS  FALSE
 #define DEFAULT_AUTH_MESSAGE  TRUE
@@ -744,7 +743,6 @@ struct sip_settings {
        int accept_outofcall_message; /*!< Accept MESSAGE outside of a call */
        int compactheaders;         /*!< send compact sip headers */
        int allow_external_domains; /*!< Accept calls to external SIP domains? */
-       int callevents;             /*!< Whether we send manager events or not */
        int regextenonqualify;      /*!< Whether to add/remove regexten when qualifying peers */
        int legacy_useroption_parsing; /*!< Whether to strip useroptions in URI via semicolons */
        int send_diversion;             /*!< Whether to Send SIP Diversion headers */
index 57692b2..70aabb9 100644 (file)
@@ -397,8 +397,6 @@ srvlookup=yes                   ; Enable DNS SRV lookups on outbound calls
 ;maxcallbitrate=384             ; Maximum bitrate for video calls (default 384 kb/s)
                                 ; Videosupport and maxcallbitrate is settable
                                 ; for peers and users as well
-;callevents=no                  ; generate manager events when sip ua
-                                ; performs events (e.g. hold)
 ;authfailureevents=no           ; generate manager "peerstatus" events when peer can't
                                 ; authenticate with Asterisk. Peerstatus will be "rejected".
 ;alwaysauthreject = yes         ; When an incoming INVITE or REGISTER is to be rejected,
index 43b4b5c..61685fd 100644 (file)
@@ -906,6 +906,18 @@ struct ast_json_payload {
  */
 struct ast_json_payload *ast_json_payload_create(struct ast_json *json);
 
+struct ast_party_id;
+/*!
+ * \brief Construct an ast_party_id as JSON.
+ * \since 12.0.0
+ *
+ * \param party The party ID to represent as JSON.
+ *
+ * \return JSON object with \c name, \c number and \c subaddress objects
+ * for those that are valid in the party ID
+ */
+struct ast_json *ast_json_party_id(struct ast_party_id *party);
+
 /*!@}*/
 
 #endif /* _ASTERISK_JSON_H */
index 19ebb41..fd51cf5 100644 (file)
@@ -736,6 +736,32 @@ void stasis_log_bad_type_access(const char *name);
        }
 
 /*!
+ * \brief Boiler-plate removing macro for defining local message types.
+ *
+ * \code
+ *     STASIS_MESSAGE_TYPE_DEFN_LOCAL(ast_foo_type,
+ *             .to_ami = foo_to_ami,
+ *             .to_json = foo_to_json,
+ *             );
+ * \endcode
+ *
+ * \param name Name of message type.
+ * \param ... Virtual table methods for messages of this type.
+ * \since 12
+ */
+#define STASIS_MESSAGE_TYPE_DEFN_LOCAL(name, ...)                      \
+       static struct stasis_message_vtable _priv_ ## name ## _v = {    \
+               __VA_ARGS__                                             \
+       };                                                              \
+       static struct stasis_message_type *_priv_ ## name;              \
+       static struct stasis_message_type *name(void) {                 \
+               if (_priv_ ## name == NULL) {                           \
+                       stasis_log_bad_type_access(#name);              \
+               }                                                       \
+               return _priv_ ## name;                                  \
+       }
+
+/*!
 * \brief Boiler-plate removing macro for initializing message types.
  *
  * \code
index 5c7a34f..16abc42 100644 (file)
@@ -47,6 +47,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/core_unreal.h"
 #include "asterisk/core_local.h"
 #include "asterisk/_private.h"
+#include "asterisk/stasis_channels.h"
 
 /*** DOCUMENTATION
        <manager name="LocalOptimizeAway" language="en_US">
@@ -65,6 +66,101 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                        it to optimize away if it's bridged or when it becomes bridged.</para>
                </description>
        </manager>
+       <managerEvent language="en_US" name="LocalBridge">
+               <managerEventInstance class="EVENT_FLAG_CALL">
+                       <synopsis>Raised when two halves of a Local Channel form a bridge.</synopsis>
+                       <syntax>
+                               <parameter name="LocalOneChannel">
+                               </parameter>
+                               <parameter name="LocalOneChannelState">
+                                       <para>A numeric code for the channel's current state, related to ChannelStateDesc</para>
+                               </parameter>
+                               <parameter name="LocalOneChannelStateDesc">
+                                       <enumlist>
+                                               <enum name="Down"/>
+                                               <enum name="Rsrvd"/>
+                                               <enum name="OffHook"/>
+                                               <enum name="Dialing"/>
+                                               <enum name="Ring"/>
+                                               <enum name="Ringing"/>
+                                               <enum name="Up"/>
+                                               <enum name="Busy"/>
+                                               <enum name="Dialing Offhook"/>
+                                               <enum name="Pre-ring"/>
+                                               <enum name="Unknown"/>
+                                       </enumlist>
+                               </parameter>
+                               <parameter name="LocalOneCallerIDNum">
+                               </parameter>
+                               <parameter name="LocalOneCallerIDName">
+                               </parameter>
+                               <parameter name="LocalOneConnectedLineNum">
+                               </parameter>
+                               <parameter name="LocalOneConnectedLineName">
+                               </parameter>
+                               <parameter name="LocalOneAccountCode">
+                               </parameter>
+                               <parameter name="LocalOneContext">
+                               </parameter>
+                               <parameter name="LocalOneExten">
+                               </parameter>
+                               <parameter name="LocalOnePriority">
+                               </parameter>
+                               <parameter name="LocalOneUniqueid">
+                               </parameter>
+                               <parameter name="LocalTwoChannel">
+                               </parameter>
+                               <parameter name="LocalTwoChannelState">
+                                       <para>A numeric code for the channel's current state, related to ChannelStateDesc</para>
+                               </parameter>
+                               <parameter name="LocalTwoChannelStateDesc">
+                                       <enumlist>
+                                               <enum name="Down"/>
+                                               <enum name="Rsrvd"/>
+                                               <enum name="OffHook"/>
+                                               <enum name="Dialing"/>
+                                               <enum name="Ring"/>
+                                               <enum name="Ringing"/>
+                                               <enum name="Up"/>
+                                               <enum name="Busy"/>
+                                               <enum name="Dialing Offhook"/>
+                                               <enum name="Pre-ring"/>
+                                               <enum name="Unknown"/>
+                                       </enumlist>
+                               </parameter>
+                               <parameter name="LocalTwoCallerIDNum">
+                               </parameter>
+                               <parameter name="LocalTwoCallerIDName">
+                               </parameter>
+                               <parameter name="LocalTwoConnectedLineNum">
+                               </parameter>
+                               <parameter name="LocalTwoConnectedLineName">
+                               </parameter>
+                               <parameter name="LocalTwoAccountCode">
+                               </parameter>
+                               <parameter name="LocalTwoContext">
+                               </parameter>
+                               <parameter name="LocalTwoExten">
+                               </parameter>
+                               <parameter name="LocalTwoPriority">
+                               </parameter>
+                               <parameter name="LocalTwoUniqueid">
+                               </parameter>
+                               <parameter name="Context">
+                                       <para>The context in the dialplan that Channel2 starts in.</para>
+                               </parameter>
+                               <parameter name="Exten">
+                                       <para>The extension in the dialplan that Channel2 starts in.</para>
+                               </parameter>
+                               <parameter name="LocalOptimization">
+                                       <enumlist>
+                                               <enum name="Yes"/>
+                                               <enum name="No"/>
+                                       </enumlist>
+                               </parameter>
+                       </syntax>
+               </managerEventInstance>
+       </managerEvent>
  ***/
 
 static const char tdesc[] = "Local Proxy Channel Driver";
@@ -230,6 +326,49 @@ static int local_devicestate(const char *data)
        return res;
 }
 
+static struct ast_manager_event_blob *local_bridge_to_ami(struct stasis_message *msg)
+{
+       RAII_VAR(struct ast_str *, channel_one_string, NULL, ast_free);
+       RAII_VAR(struct ast_str *, channel_two_string, NULL, ast_free);
+       struct ast_multi_channel_blob *obj = stasis_message_data(msg);
+       struct ast_json *blob, *context, *exten, *optimize;
+       struct ast_channel_snapshot *chan_one, *chan_two;
+
+       chan_one = ast_multi_channel_blob_get_channel(obj, "1");
+       chan_two = ast_multi_channel_blob_get_channel(obj, "2");
+       blob = ast_multi_channel_blob_get_json(obj);
+
+       channel_one_string = ast_manager_build_channel_state_string_prefix(chan_one, "LocalOne");
+       if (!channel_one_string) {
+               return NULL;
+       }
+
+       channel_two_string = ast_manager_build_channel_state_string_prefix(chan_two, "LocalTwo");
+       if (!channel_two_string) {
+               return NULL;
+       }
+
+       context = ast_json_object_get(blob, "context");
+       exten = ast_json_object_get(blob, "exten");
+       optimize = ast_json_object_get(blob, "optimize");
+
+       return ast_manager_event_blob_create(EVENT_FLAG_CALL, "LocalBridge",
+               "%s"
+               "%s"
+               "Context: %s\r\n"
+               "Exten: %s\r\n"
+               "LocalOptimization: %s\r\n",
+               ast_str_buffer(channel_one_string),
+               ast_str_buffer(channel_two_string),
+               ast_json_string_get(context),
+               ast_json_string_get(exten),
+               ast_json_is_true(optimize) ? "Yes" : "No");
+}
+
+STASIS_MESSAGE_TYPE_DEFN_LOCAL(local_bridge_type,
+       .to_ami = local_bridge_to_ami,
+       );
+
 /*!
  * \internal
  * \brief Post the LocalBridge AMI event.
@@ -241,45 +380,45 @@ static int local_devicestate(const char *data)
  */
 static void local_bridge_event(struct local_pvt *p)
 {
-       ao2_lock(p);
-       /*** DOCUMENTATION
-               <managerEventInstance>
-                       <synopsis>Raised when two halves of a Local Channel form a bridge.</synopsis>
-                       <syntax>
-                               <parameter name="Channel1">
-                                       <para>The name of the Local Channel half that bridges to another channel.</para>
-                               </parameter>
-                               <parameter name="Channel2">
-                                       <para>The name of the Local Channel half that executes the dialplan.</para>
-                               </parameter>
-                               <parameter name="Context">
-                                       <para>The context in the dialplan that Channel2 starts in.</para>
-                               </parameter>
-                               <parameter name="Exten">
-                                       <para>The extension in the dialplan that Channel2 starts in.</para>
-                               </parameter>
-                               <parameter name="LocalOptimization">
-                                       <enumlist>
-                                               <enum name="Yes"/>
-                                               <enum name="No"/>
-                                       </enumlist>
-                               </parameter>
-                       </syntax>
-               </managerEventInstance>
-       ***/
-       manager_event(EVENT_FLAG_CALL, "LocalBridge",
-               "Channel1: %s\r\n"
-               "Channel2: %s\r\n"
-               "Uniqueid1: %s\r\n"
-               "Uniqueid2: %s\r\n"
-               "Context: %s\r\n"
-               "Exten: %s\r\n"
-               "LocalOptimization: %s\r\n",
-               ast_channel_name(p->base.owner), ast_channel_name(p->base.chan),
-               ast_channel_uniqueid(p->base.owner), ast_channel_uniqueid(p->base.chan),
-               p->context, p->exten,
-               ast_test_flag(&p->base, AST_UNREAL_NO_OPTIMIZATION) ? "Yes" : "No");
-       ao2_unlock(p);
+       RAII_VAR(struct ast_multi_channel_blob *, multi_blob, NULL, ao2_cleanup);
+       RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
+       RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
+       RAII_VAR(struct ast_channel_snapshot *, one_snapshot, NULL, ao2_cleanup);
+       RAII_VAR(struct ast_channel_snapshot *, two_snapshot, NULL, ao2_cleanup);
+       SCOPED_AO2LOCK(lock, p);
+
+       blob = ast_json_pack("{s: s, s: s, s: b}",
+               "context", p->context,
+               "exten", p->exten,
+               "optimize", ast_test_flag(&p->base, AST_UNREAL_NO_OPTIMIZATION));
+       if (!blob) {
+               return;
+       }
+
+       multi_blob = ast_multi_channel_blob_create(blob);
+       if (!multi_blob) {
+               return;
+       }
+
+       one_snapshot = ast_channel_snapshot_create(p->base.owner);
+       if (!one_snapshot) {
+               return;
+       }
+
+       two_snapshot = ast_channel_snapshot_create(p->base.chan);
+       if (!two_snapshot) {
+               return;
+       }
+
+       ast_multi_channel_blob_add_channel(multi_blob, "1", one_snapshot);
+       ast_multi_channel_blob_add_channel(multi_blob, "2", two_snapshot);
+
+       msg = stasis_message_create(local_bridge_type(), multi_blob);
+       if (!msg) {
+               return;
+       }
+
+       stasis_publish(ast_channel_topic(p->base.owner), msg);
 }
 
 int ast_local_setup_bridge(struct ast_channel *ast, struct ast_bridge *bridge, struct ast_channel *swap, struct ast_bridge_features *features)
@@ -744,10 +883,15 @@ static void local_shutdown(void)
        locals = NULL;
 
        ast_format_cap_destroy(local_tech.capabilities);
+       STASIS_MESSAGE_TYPE_CLEANUP(local_bridge_type);
 }
 
 int ast_local_init(void)
 {
+       if (STASIS_MESSAGE_TYPE_INIT(local_bridge_type)) {
+               return -1;
+       }
+
        if (!(local_tech.capabilities = ast_format_cap_alloc())) {
                return -1;
        }
index a403b40..dff35db 100644 (file)
@@ -40,6 +40,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/module.h"
 #include "asterisk/utils.h"
 #include "asterisk/astobj2.h"
+#include "asterisk/channel.h"
+#include "asterisk/callerid.h"
 
 #include <jansson.h>
 #include <time.h>
@@ -599,3 +601,70 @@ struct ast_json_payload *ast_json_payload_create(struct ast_json *json)
 
        return payload;
 }
+
+static struct ast_json *json_party_number(struct ast_party_number *number)
+{
+       if (!number->valid) {
+               return NULL;
+       }
+       return ast_json_pack("{s: s, s: i, s: i, s: s}",
+               "number", number->str,
+               "plan", number->plan,
+               "presentation", number->presentation,
+               "presentation_txt", ast_describe_caller_presentation(number->presentation));
+}
+
+static struct ast_json *json_party_name(struct ast_party_name *name)
+{
+       if (!name->valid) {
+               return NULL;
+       }
+       return ast_json_pack("{s: s, s: s, s: i, s: s}",
+               "name", name->str,
+               "character_set", ast_party_name_charset_describe(name->char_set),
+               "presentation", name->presentation,
+               "presentation_txt", ast_describe_caller_presentation(name->presentation));
+}
+
+static struct ast_json *json_party_subaddress(struct ast_party_subaddress *subaddress)
+{
+       if (!subaddress->valid) {
+               return NULL;
+       }
+       return ast_json_pack("{s: s, s: i, s: b}",
+               "subaddress", subaddress->str,
+               "type", subaddress->type,
+               "odd", subaddress->odd_even_indicator);
+}
+
+struct ast_json *ast_json_party_id(struct ast_party_id *party)
+{
+       RAII_VAR(struct ast_json *, json_party_id, NULL, ast_json_unref);
+       int pres;
+
+       /* Combined party presentation */
+       pres = ast_party_id_presentation(party);
+       json_party_id = ast_json_pack("{s: i, s: s}",
+               "presentation", pres,
+               "presentation_txt", ast_describe_caller_presentation(pres));
+       if (!json_party_id) {
+               return NULL;
+       }
+
+       /* Party number */
+       if (party->number.valid && ast_json_object_set(json_party_id, "number", json_party_number(&party->number))) {
+               return NULL;
+       }
+
+       /* Party name */
+       if (party->name.valid && ast_json_object_set(json_party_id, "name", json_party_name(&party->name))) {
+               return NULL;
+       }
+
+       /* Party subaddress */
+       if (party->subaddress.valid && ast_json_object_set(json_party_id, "subaddress", json_party_subaddress(&party->subaddress))) {
+               return NULL;
+       }
+
+       return ast_json_ref(json_party_id);
+}
index a841f36..eff753e 100644 (file)
@@ -1027,17 +1027,11 @@ enum agi_result {
        AGI_RESULT_HANGUP,
 };
 
-struct stasis_message_type *agi_exec_start_type(void);
-struct stasis_message_type *agi_exec_end_type(void);
-struct stasis_message_type *agi_async_start_type(void);
-struct stasis_message_type *agi_async_exec_type(void);
-struct stasis_message_type *agi_async_end_type(void);
-
-STASIS_MESSAGE_TYPE_DEFN(agi_exec_start_type);
-STASIS_MESSAGE_TYPE_DEFN(agi_exec_end_type);
-STASIS_MESSAGE_TYPE_DEFN(agi_async_start_type);
-STASIS_MESSAGE_TYPE_DEFN(agi_async_exec_type);
-STASIS_MESSAGE_TYPE_DEFN(agi_async_end_type);
+STASIS_MESSAGE_TYPE_DEFN_LOCAL(agi_exec_start_type);
+STASIS_MESSAGE_TYPE_DEFN_LOCAL(agi_exec_end_type);
+STASIS_MESSAGE_TYPE_DEFN_LOCAL(agi_async_start_type);
+STASIS_MESSAGE_TYPE_DEFN_LOCAL(agi_async_exec_type);
+STASIS_MESSAGE_TYPE_DEFN_LOCAL(agi_async_end_type);
 
 static void agi_channel_manager_event(void *data,
        struct stasis_subscription *sub, struct stasis_topic *topic,