* 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.
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.
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);
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,
#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">
<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 */
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.
/* 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
}
}
+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)
#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);
}
}
}
}
+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;
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);
}
}
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
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;
}
ast_cond_destroy(&ss_thread_complete);
dahdi_tech.capabilities = ast_format_cap_destroy(dahdi_tech.capabilities);
+ STASIS_MESSAGE_TYPE_CLEANUP(dahdichannel_type);
return 0;
}
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;
}
#include "asterisk/jabber.h"
#include "asterisk/jingle.h"
#include "asterisk/features.h"
+#include "asterisk/stasis_channels.h"
#define GOOGLE_CONFIG "gtalk.conf"
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;
}
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;
}
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,
{
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);
}
}
return NULL;
}
- iax2_ami_channelupdate(i);
if (!tmp) {
return NULL;
}
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]);
}
#include "asterisk/app.h"
#include "asterisk/bridging.h"
#include "asterisk/stasis_endpoints.h"
+#include "asterisk/stasis_channels.h"
#include "asterisk/features_config.h"
/*** DOCUMENTATION
<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">
<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 */
/*! \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.
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;
}
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[])
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) {
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)));
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);
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
*
}
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);
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);
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);
/* 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;
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")) {
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));
{
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;
}
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;
}
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;
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) {
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);
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) {
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;
}
/*** 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
}
#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.
*
* \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.
*/
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.
*/
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) */
*/
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,
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 */
#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
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 */
;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,
*/
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 */
return _priv_ ## 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.
*
#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">
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";
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.
*/
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)
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;
}
#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>
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);
+}
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,