summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES20
-rw-r--r--apps/app_chanspy.c109
-rw-r--r--apps/app_fax.c50
-rw-r--r--apps/app_minivm.c53
-rw-r--r--apps/app_voicemail.c51
-rw-r--r--channels/chan_dahdi.c8
-rw-r--r--channels/chan_iax2.c6
-rw-r--r--channels/chan_mgcp.c6
-rw-r--r--channels/chan_sip.c10
-rw-r--r--channels/chan_skinny.c6
-rw-r--r--channels/chan_unistim.c4
-rw-r--r--channels/sig_pri.c10
-rw-r--r--include/asterisk/_private.h23
-rw-r--r--include/asterisk/app.h116
-rw-r--r--include/asterisk/json.h28
-rw-r--r--include/asterisk/manager.h90
-rw-r--r--include/asterisk/stasis_channels.h98
-rw-r--r--main/app.c132
-rw-r--r--main/asterisk.c137
-rw-r--r--main/cdr.c1
-rw-r--r--main/cli.c26
-rw-r--r--main/dnsmgr.c1
-rw-r--r--main/enum.c1
-rw-r--r--main/json.c7
-rw-r--r--main/loader.c138
-rw-r--r--main/manager.c171
-rw-r--r--main/manager_channels.c688
-rw-r--r--main/manager_mwi.c202
-rw-r--r--main/pbx.c94
-rw-r--r--main/stasis_channels.c112
-rw-r--r--res/parking/parking_manager.c6
-rw-r--r--res/res_fax.c291
-rw-r--r--res/res_jabber.c12
-rw-r--r--res/res_monitor.c29
-rw-r--r--res/res_musiconhold.c37
-rw-r--r--res/res_sip_mwi.c8
-rw-r--r--res/res_xmpp.c12
37 files changed, 2088 insertions, 705 deletions
diff --git a/CHANGES b/CHANGES
index ec85f5ded..273a470e7 100644
--- a/CHANGES
+++ b/CHANGES
@@ -72,6 +72,26 @@ AMI (Asterisk Manager Interface)
event, the various ChanVariable fields will contain a suffix that specifies
which channel they correspond to.
+ * All "Reload" events have been consolidated into a single event type. This
+ event will always contain a Module field specifying the name of the module
+ and a Status field denoting the result of the reload. All modules now issue
+ this event when being reloaded.
+
+ * The "ModuleLoadReport" event has been removed. Most AMI connections would
+ fail to receive this event due to being connected after modules have loaded.
+ AMI connections that want to know when Asterisk is ready should listen for
+ the "FullyBooted" event.
+
+ * app_fax now sends the same send fax/receive fax events as res_fax. The
+ "FaxSent" event is now the "SendFAX" event, and the "FaxReceived" event is
+ now the "ReceiveFAX" event.
+
+ * The MusicOnHold event is now two events: MusicOnHoldStart and
+ MusicOnHoldStop. The sub type field has been removed.
+
+ * The JabberEvent event has been removed. It is not AMI's purpose to be a
+ carrier for another protocol.
+
* The AMI 'Status' response event to the AMI Status action replaces the
BridgedChannel and BridgedUniqueid headers with the BridgeID header to
indicate what bridge the channel is currently in.
diff --git a/apps/app_chanspy.c b/apps/app_chanspy.c
index 8e4590781..4e241b96f 100644
--- a/apps/app_chanspy.c
+++ b/apps/app_chanspy.c
@@ -55,6 +55,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/lock.h"
#include "asterisk/options.h"
#include "asterisk/autochan.h"
+#include "asterisk/stasis_channels.h"
+#include "asterisk/json.h"
#define AST_NAME_STRLEN 256
#define NUM_SPYGROUPS 128
@@ -188,6 +190,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
</description>
<see-also>
<ref type="application">ExtenSpy</ref>
+ <ref type="managerEvent">ChanSpyStart</ref>
+ <ref type="managerEvent">ChanSpyStop</ref>
</see-also>
</application>
<application name="ExtenSpy" language="en_US">
@@ -322,9 +326,10 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
</description>
<see-also>
<ref type="application">ChanSpy</ref>
+ <ref type="managerEvent">ChanSpyStart</ref>
+ <ref type="managerEvent">ChanSpyStop</ref>
</see-also>
</application>
-
<application name="DAHDIScan" language="en_US">
<synopsis>
Scan DAHDI channels to monitor calls.
@@ -338,6 +343,10 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
<para>Allows a call center manager to monitor DAHDI channels in a
convenient way. Use <literal>#</literal> to select the next channel and use <literal>*</literal> to exit.</para>
</description>
+ <see-also>
+ <ref type="managerEvent">ChanSpyStart</ref>
+ <ref type="managerEvent">ChanSpyStop</ref>
+ </see-also>
</application>
***/
@@ -512,6 +521,68 @@ static void change_spy_mode(const char digit, struct ast_flags *flags)
}
}
+static int pack_channel_into_message(struct ast_channel *chan, const char *role,
+ struct ast_multi_channel_blob *payload)
+{
+ RAII_VAR(struct ast_channel_snapshot *, snapshot,
+ ast_channel_snapshot_get_latest(ast_channel_uniqueid(chan)),
+ ao2_cleanup);
+
+ if (!snapshot) {
+ return -1;
+ }
+ ast_multi_channel_blob_add_channel(payload, role, snapshot);
+ return 0;
+}
+
+/*! \internal
+ * \brief Publish the chanspy message over Stasis-Core
+ * \param spyer The channel doing the spying
+ * \param spyee Who is being spied upon
+ * \start start If non-zero, the spying is starting. Otherwise, the spyer is
+ * finishing
+ */
+static void publish_chanspy_message(struct ast_channel *spyer,
+ struct ast_channel *spyee,
+ int start)
+{
+ RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
+ RAII_VAR(struct ast_multi_channel_blob *, payload, NULL, ao2_cleanup);
+ RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
+
+ if (!spyer) {
+ ast_log(AST_LOG_WARNING, "Attempt to publish ChanSpy message for NULL spyer channel\n");
+ return;
+ }
+ blob = ast_json_null();
+ if (!blob) {
+ return;
+ }
+
+ payload = ast_multi_channel_blob_create(blob);
+ if (!payload) {
+ return;
+ }
+
+ if (pack_channel_into_message(spyer, "spyer_channel", payload)) {
+ return;
+ }
+
+ if (spyee) {
+ if (pack_channel_into_message(spyee, "spyee_channel", payload)) {
+ return;
+ }
+ }
+
+ message = stasis_message_create(
+ start ? ast_channel_chanspy_start_type(): ast_channel_chanspy_stop_type(),
+ payload);
+ if (!message) {
+ return;
+ }
+ stasis_publish(ast_channel_topic(spyer), message);
+}
+
static int channel_spy(struct ast_channel *chan, struct ast_autochan *spyee_autochan,
int *volfactor, int fd, struct spy_dtmf_options *user_options, struct ast_flags *flags,
char *exitcontext)
@@ -524,38 +595,22 @@ static int channel_spy(struct ast_channel *chan, struct ast_autochan *spyee_auto
struct ast_silence_generator *silgen = NULL;
struct ast_autochan *spyee_bridge_autochan = NULL;
const char *spyer_name;
- struct ast_channel *chans[] = { chan, spyee_autochan->chan };
-
- ast_channel_lock(chan);
- spyer_name = ast_strdupa(ast_channel_name(chan));
- ast_channel_unlock(chan);
-
- /* We now hold the channel lock on spyee */
if (ast_check_hangup(chan) || ast_check_hangup(spyee_autochan->chan) ||
ast_test_flag(ast_channel_flags(spyee_autochan->chan), AST_FLAG_ZOMBIE)) {
return 0;
}
+ ast_channel_lock(chan);
+ spyer_name = ast_strdupa(ast_channel_name(chan));
+ ast_channel_unlock(chan);
+
ast_channel_lock(spyee_autochan->chan);
name = ast_strdupa(ast_channel_name(spyee_autochan->chan));
ast_channel_unlock(spyee_autochan->chan);
ast_verb(2, "Spying on channel %s\n", name);
- /*** DOCUMENTATION
- <managerEventInstance>
- <synopsis>Raised when a channel has started spying on another channel.</synopsis>
- <see-also>
- <ref type="application">ChanSpy</ref>
- <ref type="application">ExtenSpy</ref>
- <ref type="managerEvent">ChanSpyStop</ref>
- </see-also>
- </managerEventInstance>
- ***/
- ast_manager_event_multichan(EVENT_FLAG_CALL, "ChanSpyStart", 2, chans,
- "SpyerChannel: %s\r\n"
- "SpyeeChannel: %s\r\n",
- spyer_name, name);
+ publish_chanspy_message(chan, spyee_autochan->chan, 1);
memset(&csth, 0, sizeof(csth));
ast_copy_flags(&csth.flags, flags, AST_FLAGS_ALL);
@@ -740,15 +795,7 @@ static int channel_spy(struct ast_channel *chan, struct ast_autochan *spyee_auto
}
ast_verb(2, "Done Spying on channel %s\n", name);
- /*** DOCUMENTATION
- <managerEventInstance>
- <synopsis>Raised when a channel has stopped spying on another channel.</synopsis>
- <see-also>
- <ref type="managerEvent">ChanSpyStart</ref>
- </see-also>
- </managerEventInstance>
- ***/
- ast_manager_event(chan, EVENT_FLAG_CALL, "ChanSpyStop", "SpyeeChannel: %s\r\n", name);
+ publish_chanspy_message(chan, NULL, 0);
return running;
}
diff --git a/apps/app_fax.c b/apps/app_fax.c
index adee8f4bd..a7b9e53d1 100644
--- a/apps/app_fax.c
+++ b/apps/app_fax.c
@@ -43,7 +43,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/app.h"
#include "asterisk/dsp.h"
#include "asterisk/module.h"
-#include "asterisk/manager.h"
+#include "asterisk/stasis.h"
+#include "asterisk/stasis_channels.h"
/*** DOCUMENTATION
<application name="SendFAX" language="en_US" module="app_fax">
@@ -202,6 +203,9 @@ static int t38_tx_packet_handler(t38_core_state_t *s, void *user_data, const uin
static void phase_e_handler(t30_state_t *f, void *user_data, int result)
{
+ RAII_VAR(struct ast_json *, json_object, NULL, ast_json_unref);
+ RAII_VAR(struct ast_json *, json_filenames, NULL, ast_json_unref);
+ RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
const char *local_ident;
const char *far_ident;
char buf[20];
@@ -251,32 +255,24 @@ static void phase_e_handler(t30_state_t *f, void *user_data, int result)
ast_debug(1, " Image resolution: %d x %d\n", stat.x_resolution, stat.y_resolution);
ast_debug(1, " Transfer Rate: %d\n", stat.bit_rate);
- ast_manager_event(s->chan, EVENT_FLAG_CALL,
- s->direction ? "FaxSent" : "FaxReceived",
- "Channel: %s\r\n"
- "Exten: %s\r\n"
- "CallerID: %s\r\n"
- "CallerIDName: %s\r\n"
- "ConnectedLineNum: %s\r\n"
- "ConnectedLineName: %s\r\n"
- "RemoteStationID: %s\r\n"
- "LocalStationID: %s\r\n"
- "PagesTransferred: %d\r\n"
- "Resolution: %d\r\n"
- "TransferRate: %d\r\n"
- "FileName: %s\r\n",
- ast_channel_name(s->chan),
- ast_channel_exten(s->chan),
- S_COR(ast_channel_caller(s->chan)->id.number.valid, ast_channel_caller(s->chan)->id.number.str, ""),
- S_COR(ast_channel_caller(s->chan)->id.name.valid, ast_channel_caller(s->chan)->id.name.str, ""),
- S_COR(ast_channel_connected(s->chan)->id.number.valid, ast_channel_connected(s->chan)->id.number.str, ""),
- S_COR(ast_channel_connected(s->chan)->id.name.valid, ast_channel_connected(s->chan)->id.name.str, ""),
- far_ident,
- local_ident,
- pages_transferred,
- stat.y_resolution,
- stat.bit_rate,
- s->file_name);
+ json_filenames = ast_json_pack("[s]", s->file_name);
+ if (!json_filenames) {
+ return;
+ }
+ ast_json_ref(json_filenames);
+ json_object = ast_json_pack("{s: s, s: s, s: s, s: i, s: i, s: i, s: o}",
+ "type", s->direction ? "send" : "receive",
+ "remote_station_id", far_ident,
+ "local_station_id", local_ident,
+ "fax_pages", pages_transferred,
+ "fax_resolution", stat.y_resolution,
+ "fax_bitrate", stat.bit_rate,
+ "filenames", json_filenames);
+ message = ast_channel_cached_blob_create(s->chan, ast_channel_fax_type(), json_object);
+ if (!message) {
+ return;
+ }
+ stasis_publish(ast_channel_topic(s->chan), message);
}
/* === Helper functions to configure fax === */
diff --git a/apps/app_minivm.c b/apps/app_minivm.c
index 53c5f0937..ba6d6e5a2 100644
--- a/apps/app_minivm.c
+++ b/apps/app_minivm.c
@@ -166,14 +166,15 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/say.h"
#include "asterisk/module.h"
#include "asterisk/app.h"
-#include "asterisk/manager.h"
#include "asterisk/dsp.h"
#include "asterisk/localtime.h"
#include "asterisk/cli.h"
#include "asterisk/utils.h"
#include "asterisk/linkedlists.h"
#include "asterisk/callerid.h"
-#include "asterisk/event.h"
+#include "asterisk/stasis.h"
+#include "asterisk/stasis_channels.h"
+#include "asterisk/json.h"
/*** DOCUMENTATION
<application name="MinivmRecord" language="en_US">
@@ -495,7 +496,23 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
<ref type="function">MINIVMCOUNTER</ref>
</see-also>
</function>
-
+ <managerEvent language="en_US" name="MiniVoiceMail">
+ <managerEventInstance class="EVENT_FLAG_CALL">
+ <synopsis>Raised when a notification is sent out by a MiniVoiceMail application</synopsis>
+ <syntax>
+ <xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
+ <parameter name="Action">
+ <para>What action was taken. Currently, this will always be <literal>SentNotification</literal></para>
+ </parameter>
+ <parameter name="Mailbox">
+ <para>The mailbox that the notification was about, specified as <literal>mailbox</literal>@<literal>context</literal></para>
+ </parameter>
+ <parameter name="Counter">
+ <para>A message counter derived from the <literal>MVM_COUNTER</literal> channel variable.</para>
+ </parameter>
+ </syntax>
+ </managerEventInstance>
+ </managerEvent>
***/
#ifndef TRUE
@@ -1761,6 +1778,9 @@ static void run_externnotify(struct ast_channel *chan, struct minivm_account *vm
* \brief Send message to voicemail account owner */
static int notify_new_message(struct ast_channel *chan, const char *templatename, struct minivm_account *vmu, const char *filename, long duration, const char *format, char *cidnum, char *cidname)
{
+ RAII_VAR(struct ast_json *, json_object, NULL, ast_json_unref);
+ RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
+ RAII_VAR(struct ast_mwi_state *, mwi_state, NULL, ao2_cleanup);
char *stringp;
struct minivm_template *etemplate;
char *messageformat;
@@ -1826,8 +1846,26 @@ static int notify_new_message(struct ast_channel *chan, const char *templatename
res = sendmail(etemplate, vmu, cidnum, cidname, filename, messageformat, duration, etemplate->attachment, MVM_MESSAGE_PAGE, counter);
}
- ast_manager_event(chan, EVENT_FLAG_CALL, "MiniVoiceMail", "Action: SentNotification\rn\nMailbox: %s@%s\r\nCounter: %s\r\n", vmu->username, vmu->domain, counter);
+ mwi_state = ast_mwi_create(vmu->username, vmu->domain);
+ if (!mwi_state) {
+ goto notify_cleanup;
+ }
+ mwi_state->snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(chan));
+
+ json_object = ast_json_pack("{s: s, s: s}",
+ "Event", "MiniVoiceMail"
+ "Action", "SentNotification",
+ "Counter", counter);
+ if (!json_object) {
+ goto notify_cleanup;
+ }
+ message = ast_mwi_blob_create(mwi_state, ast_mwi_vm_app_type(), json_object);
+ if (!message) {
+ goto notify_cleanup;
+ }
+ stasis_publish(ast_mwi_topic(mwi_state->uniqueid), message);
+notify_cleanup:
run_externnotify(chan, vmu); /* Run external notification */
if (etemplate->locale) {
@@ -2011,7 +2049,7 @@ static int leave_voicemail(struct ast_channel *chan, char *username, struct leav
/*!\internal
* \brief Queue a message waiting event */
-static void queue_mwi_event(const char *mbx, const char *ctx, int urgent, int new, int old)
+static void queue_mwi_event(const char *channel_id, const char *mbx, const char *ctx, int urgent, int new, int old)
{
char *mailbox, *context;
@@ -2021,7 +2059,7 @@ static void queue_mwi_event(const char *mbx, const char *ctx, int urgent, int ne
context = "default";
}
- stasis_publish_mwi_state(mailbox, context, new + urgent, old);
+ ast_publish_mwi_state_channel(mailbox, context, new + urgent, old, channel_id);
}
/*!\internal
@@ -2056,7 +2094,7 @@ static int minivm_mwi_exec(struct ast_channel *chan, const char *data)
ast_log(LOG_ERROR, "Need mailbox@context as argument. Sorry. Argument 0 %s\n", argv[0]);
return -1;
}
- queue_mwi_event(mailbox, domain, atoi(argv[1]), atoi(argv[2]), atoi(argv[3]));
+ queue_mwi_event(ast_channel_uniqueid(chan), mailbox, domain, atoi(argv[1]), atoi(argv[2]), atoi(argv[3]));
return res;
}
@@ -2078,7 +2116,6 @@ static int minivm_notify_exec(struct ast_channel *chan, const char *data)
const char *filename;
const char *format;
const char *duration_string;
-
if (ast_strlen_zero(data)) {
ast_log(LOG_ERROR, "Minivm needs at least an account argument \n");
return -1;
diff --git a/apps/app_voicemail.c b/apps/app_voicemail.c
index b3ceeebc9..90458bb31 100644
--- a/apps/app_voicemail.c
+++ b/apps/app_voicemail.c
@@ -7741,7 +7741,7 @@ static int vm_forwardoptions(struct ast_channel *chan, struct ast_vm_user *vmu,
return cmd;
}
-static void queue_mwi_event(const char *box, int urgent, int new, int old)
+static void queue_mwi_event(const char *channel_id, const char *box, int urgent, int new, int old)
{
char *mailbox, *context;
@@ -7752,7 +7752,7 @@ static void queue_mwi_event(const char *box, int urgent, int new, int old)
context = "default";
}
- stasis_publish_mwi_state(mailbox, context, new + urgent, old);
+ ast_publish_mwi_state_channel(mailbox, context, new + urgent, old, channel_id);
}
/*!
@@ -7842,32 +7842,7 @@ static int notify_new_message(struct ast_channel *chan, struct ast_vm_user *vmu,
if (ast_app_has_voicemail(ext_context, NULL))
ast_app_inboxcount2(ext_context, &urgentmsgs, &newmsgs, &oldmsgs);
- queue_mwi_event(ext_context, urgentmsgs, newmsgs, oldmsgs);
-
- /*** DOCUMENTATION
- <managerEventInstance>
- <synopsis>Raised when a new message has been left in a voicemail mailbox.</synopsis>
- <syntax>
- <parameter name="Mailbox">
- <para>The mailbox with the new message, specified as <emphasis>mailbox</emphasis>@<emphasis>context</emphasis></para>
- </parameter>
- <parameter name="Waiting">
- <para>Whether or not the mailbox has access to a voicemail application.</para>
- </parameter>
- <parameter name="New">
- <para>The number of new messages.</para>
- </parameter>
- <parameter name="Old">
- <para>The number of old messages.</para>
- </parameter>
- </syntax>
- </managerEventInstance>
- ***/
- ast_manager_event(chan, EVENT_FLAG_CALL, "MessageWaiting",
- "Mailbox: %s@%s\r\n"
- "Waiting: %d\r\n"
- "New: %d\r\n"
- "Old: %d\r\n", vmu->mailbox, vmu->context, ast_app_has_voicemail(ext_context, NULL), newmsgs, oldmsgs);
+ queue_mwi_event(ast_channel_uniqueid(chan), ext_context, urgentmsgs, newmsgs, oldmsgs);
run_externnotify(vmu->context, vmu->mailbox, flag);
#ifdef IMAP_STORAGE
@@ -11538,16 +11513,10 @@ out:
if (valid) {
int new = 0, old = 0, urgent = 0;
snprintf(ext_context, sizeof(ext_context), "%s@%s", vms.username, vmu->context);
- /*** DOCUMENTATION
- <managerEventInstance>
- <synopsis>Raised when a user has finished listening to their messages.</synopsis>
- </managerEventInstance>
- ***/
- ast_manager_event(chan, EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s\r\nWaiting: %d\r\n", ext_context, has_voicemail(ext_context, NULL));
/* Urgent flag not passwd to externnotify here */
run_externnotify(vmu->context, vmu->mailbox, NULL);
ast_app_inboxcount2(ext_context, &urgent, &new, &old);
- queue_mwi_event(ext_context, urgent, new, old);
+ queue_mwi_event(ast_channel_uniqueid(chan), ext_context, urgent, new, old);
}
#ifdef IMAP_STORAGE
/* expunge message - use UID Expunge if supported on IMAP server*/
@@ -11766,7 +11735,7 @@ static int append_mailbox(const char *context, const char *box, const char *data
strcat(mailbox_full, context);
inboxcount2(mailbox_full, &urgent, &new, &old);
- queue_mwi_event(mailbox_full, urgent, new, old);
+ queue_mwi_event(NULL, mailbox_full, urgent, new, old);
return 0;
}
@@ -12502,7 +12471,7 @@ static void poll_subscribed_mailbox(struct mwi_sub *mwi_sub)
mwi_sub->old_urgent = urgent;
mwi_sub->old_new = new;
mwi_sub->old_old = old;
- queue_mwi_event(mwi_sub->mailbox, urgent, new, old);
+ queue_mwi_event(NULL, mwi_sub->mailbox, urgent, new, old);
run_externnotify(NULL, mwi_sub->mailbox, NULL);
}
}
@@ -12647,7 +12616,7 @@ static void mwi_event_cb(void *userdata, struct stasis_subscription *sub, struct
}
change = stasis_message_data(msg);
- if (change->topic == stasis_mwi_topic_all()) {
+ if (change->topic == ast_mwi_topic_all()) {
return;
}
@@ -12668,10 +12637,10 @@ static int dump_cache(void *obj, void *arg, int flags)
static void start_poll_thread(void)
{
int errcode;
- mwi_sub_sub = stasis_subscribe(stasis_mwi_topic_all(), mwi_event_cb, NULL);
+ mwi_sub_sub = stasis_subscribe(ast_mwi_topic_all(), mwi_event_cb, NULL);
if (mwi_sub_sub) {
- struct ao2_container *cached = stasis_cache_dump(stasis_mwi_topic_cached(), stasis_subscription_change_type());
+ struct ao2_container *cached = stasis_cache_dump(ast_mwi_topic_cached(), stasis_subscription_change_type());
if (cached) {
ao2_callback(cached, OBJ_MULTIPLE | OBJ_NODATA, dump_cache, NULL);
}
@@ -15263,7 +15232,7 @@ static void notify_new_state(struct ast_vm_user *vmu)
snprintf(ext_context, sizeof(ext_context), "%s@%s", vmu->mailbox, vmu->context);
run_externnotify(vmu->context, vmu->mailbox, NULL);
ast_app_inboxcount2(ext_context, &urgent, &new, &old);
- queue_mwi_event(ext_context, urgent, new, old);
+ queue_mwi_event(NULL, ext_context, urgent, new, old);
}
static int vm_msg_forward(const char *from_mailbox,
diff --git a/channels/chan_dahdi.c b/channels/chan_dahdi.c
index 1f9ee5a56..03279a01e 100644
--- a/channels/chan_dahdi.c
+++ b/channels/chan_dahdi.c
@@ -3762,7 +3762,7 @@ static void notify_message(char *mailbox_full, int thereornot)
if (ast_strlen_zero(context))
context = "default";
- stasis_publish_mwi_state(mailbox, context, thereornot, thereornot);
+ ast_publish_mwi_state(mailbox, context, thereornot, thereornot);
if (!ast_strlen_zero(mailbox) && !ast_strlen_zero(mwimonitornotify)) {
snprintf(s, sizeof(s), "%s %s %d", mwimonitornotify, mailbox, thereornot);
@@ -5427,10 +5427,10 @@ static int has_voicemail(struct dahdi_pvt *p)
}
ast_str_set(&uniqueid, 0, "%s@%s", mailbox, context);
- mwi_message = stasis_cache_get(stasis_mwi_topic_cached(), stasis_mwi_state_type(), ast_str_buffer(uniqueid));
+ mwi_message = stasis_cache_get(ast_mwi_topic_cached(), ast_mwi_state_type(), ast_str_buffer(uniqueid));
if (mwi_message) {
- struct stasis_mwi_state *mwi_state = stasis_message_data(mwi_message);
+ struct ast_mwi_state *mwi_state = stasis_message_data(mwi_message);
new_msgs = mwi_state->new_msgs;
} else {
new_msgs = ast_app_has_voicemail(p->mailbox, NULL);
@@ -13235,7 +13235,7 @@ static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf,
ast_str_set(&uniqueid, 0, "%s@%s", mailbox, context);
- mailbox_specific_topic = stasis_mwi_topic(ast_str_buffer(uniqueid));
+ mailbox_specific_topic = ast_mwi_topic(ast_str_buffer(uniqueid));
if (mailbox_specific_topic) {
tmp->mwi_event_sub = stasis_subscribe(mailbox_specific_topic, mwi_event_cb, NULL);
}
diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c
index 49ce66cb7..7f98159b2 100644
--- a/channels/chan_iax2.c
+++ b/channels/chan_iax2.c
@@ -8772,10 +8772,10 @@ static int update_registry(struct sockaddr_in *sin, int callno, char *devtype, i
}
ast_str_set(&uniqueid, 0, "%s@%s", mailbox, context);
- msg = stasis_cache_get(stasis_mwi_topic_cached(), stasis_mwi_state_type(), ast_str_buffer(uniqueid));
+ msg = stasis_cache_get(ast_mwi_topic_cached(), ast_mwi_state_type(), ast_str_buffer(uniqueid));
if (msg) {
- struct stasis_mwi_state *mwi_state = stasis_message_data(msg);
+ struct ast_mwi_state *mwi_state = stasis_message_data(msg);
new = mwi_state->new_msgs;
old = mwi_state->old_msgs;
} else { /* Fall back on checking the mailbox directly */
@@ -12555,7 +12555,7 @@ static struct iax2_peer *build_peer(const char *name, struct ast_variable *v, st
ast_str_set(&uniqueid, 0, "%s@%s", mailbox, context);
- mailbox_specific_topic = stasis_mwi_topic(ast_str_buffer(uniqueid));
+ mailbox_specific_topic = ast_mwi_topic(ast_str_buffer(uniqueid));
if (mailbox_specific_topic) {
peer->mwi_event_sub = stasis_subscribe(mailbox_specific_topic, mwi_event_cb, NULL);
}
diff --git a/channels/chan_mgcp.c b/channels/chan_mgcp.c
index 1f0830762..c6b441049 100644
--- a/channels/chan_mgcp.c
+++ b/channels/chan_mgcp.c
@@ -507,10 +507,10 @@ static int has_voicemail(struct mgcp_endpoint *p)
ast_str_set(&uniqueid, 0, "%s@%s", mbox, cntx);
- msg = stasis_cache_get(stasis_mwi_topic_cached(), stasis_mwi_state_type(), ast_str_buffer(uniqueid));
+ msg = stasis_cache_get(ast_mwi_topic_cached(), ast_mwi_state_type(), ast_str_buffer(uniqueid));
if (msg) {
- struct stasis_mwi_state *mwi_state = stasis_message_data(msg);
+ struct ast_mwi_state *mwi_state = stasis_message_data(msg);
new_msgs = mwi_state->new_msgs;
} else {
new_msgs = ast_app_has_voicemail(p->mailbox, NULL);
@@ -4169,7 +4169,7 @@ static struct mgcp_gateway *build_gateway(char *cat, struct ast_variable *v)
ast_str_reset(uniqueid);
ast_str_set(&uniqueid, 0, "%s@%s", mbox, cntx);
- mailbox_specific_topic = stasis_mwi_topic(ast_str_buffer(uniqueid));
+ mailbox_specific_topic = ast_mwi_topic(ast_str_buffer(uniqueid));
if (mailbox_specific_topic) {
e->mwi_event_sub = stasis_subscribe(mailbox_specific_topic, mwi_event_cb, NULL);
}
diff --git a/channels/chan_sip.c b/channels/chan_sip.c
index f7a528b68..77cd9c253 100644
--- a/channels/chan_sip.c
+++ b/channels/chan_sip.c
@@ -16724,7 +16724,7 @@ static void mwi_event_cb(void *userdata, struct stasis_subscription *sub, struct
ao2_cleanup(peer);
return;
}
- if (stasis_mwi_state_type() == stasis_message_type(msg)) {
+ if (ast_mwi_state_type() == stasis_message_type(msg)) {
sip_send_mwi_to_peer(peer, 0);
}
}
@@ -24767,7 +24767,7 @@ static int handle_request_notify(struct sip_pvt *p, struct sip_request *req, str
char *old = strsep(&c, " ");
char *new = strsep(&old, "/");
- stasis_publish_mwi_state(mailbox, "SIP_Remote", atoi(new), atoi(old));
+ ast_publish_mwi_state(mailbox, "SIP_Remote", atoi(new), atoi(old));
transmit_response(p, "200 OK", req);
} else {
@@ -27420,7 +27420,7 @@ static void add_peer_mwi_subs(struct sip_peer *peer)
ast_str_reset(uniqueid);
ast_str_set(&uniqueid, 0, "%s@%s", mailbox->mailbox, S_OR(mailbox->context, "default"));
- mailbox_specific_topic = stasis_mwi_topic(ast_str_buffer(uniqueid));
+ mailbox_specific_topic = ast_mwi_topic(ast_str_buffer(uniqueid));
if (mailbox_specific_topic) {
ao2_ref(peer, +1);
mailbox->event_sub = stasis_subscribe(mailbox_specific_topic, mwi_event_cb, peer);
@@ -28630,12 +28630,12 @@ static int get_cached_mwi(struct sip_peer *peer, int *new, int *old)
in_cache = 0;
AST_LIST_TRAVERSE(&peer->mailboxes, mailbox, entry) {
RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
- struct stasis_mwi_state *mwi_state;
+ struct ast_mwi_state *mwi_state;
ast_str_reset(uniqueid);
ast_str_set(&uniqueid, 0, "%s@%s", mailbox->mailbox, S_OR(mailbox->context, "default"));
- msg = stasis_cache_get(stasis_mwi_topic_cached(), stasis_mwi_state_type(), ast_str_buffer(uniqueid));
+ msg = stasis_cache_get(ast_mwi_topic_cached(), ast_mwi_state_type(), ast_str_buffer(uniqueid));
if (!msg) {
continue;
}
diff --git a/channels/chan_skinny.c b/channels/chan_skinny.c
index cd194d5a8..f1398049b 100644
--- a/channels/chan_skinny.c
+++ b/channels/chan_skinny.c
@@ -3535,8 +3535,8 @@ static void mwi_event_cb(void *userdata, struct stasis_subscription *sub, struct
return;
}
- if (msg && stasis_mwi_state_type() == stasis_message_type(msg)) {
- struct stasis_mwi_state *mwi_state = stasis_message_data(msg);
+ if (msg && ast_mwi_state_type() == stasis_message_type(msg)) {
+ struct ast_mwi_state *mwi_state = stasis_message_data(msg);
l->newmsgs = mwi_state->new_msgs;
}
@@ -8214,7 +8214,7 @@ static struct skinny_line *config_line(const char *lname, struct ast_variable *v
ast_str_set(&uniqueid, 0, "%s@%s", cfg_mailbox, cfg_context);
- mailbox_specific_topic = stasis_mwi_topic(ast_str_buffer(uniqueid));
+ mailbox_specific_topic = ast_mwi_topic(ast_str_buffer(uniqueid));
if (mailbox_specific_topic) {
l->mwi_event_sub = stasis_subscribe(mailbox_specific_topic, mwi_event_cb, l);
}
diff --git a/channels/chan_unistim.c b/channels/chan_unistim.c
index 88332ec9a..42a71bac3 100644
--- a/channels/chan_unistim.c
+++ b/channels/chan_unistim.c
@@ -5508,10 +5508,10 @@ static int unistim_send_mwi_to_peer(struct unistim_line *peer, unsigned int tick
ast_str_set(&uniqueid, 0, "%s@%s", mailbox, context);
- msg = stasis_cache_get(stasis_mwi_topic_cached(), stasis_mwi_state_type(), ast_str_buffer(uniqueid));
+ msg = stasis_cache_get(ast_mwi_topic_cached(), ast_mwi_state_type(), ast_str_buffer(uniqueid));
if (msg) {
- struct stasis_mwi_state *mwi_state = stasis_message_data(msg);
+ struct ast_mwi_state *mwi_state = stasis_message_data(msg);
new = mwi_state->new_msgs;
} else { /* Fall back on checking the mailbox directly */
new = ast_app_has_voicemail(peer->mailbox, "INBOX");
diff --git a/channels/sig_pri.c b/channels/sig_pri.c
index 353b7f39b..db0c92043 100644
--- a/channels/sig_pri.c
+++ b/channels/sig_pri.c
@@ -8768,9 +8768,9 @@ static void sig_pri_mwi_event_cb(void *userdata, struct stasis_subscription *sub
const char *mbox_number;
int num_messages;
int idx;
- struct stasis_mwi_state *mwi_state;
+ struct ast_mwi_state *mwi_state;
- if (stasis_mwi_state_type() != stasis_message_type(msg)) {
+ if (ast_mwi_state_type() != stasis_message_type(msg)) {
return;
}
@@ -8816,7 +8816,7 @@ static void sig_pri_mwi_cache_update(struct sig_pri_span *pri)
{
int idx;
struct ast_str *uniqueid = ast_str_alloca(AST_MAX_MAILBOX_UNIQUEID);
- struct stasis_mwi_state *mwi_state;
+ struct ast_mwi_state *mwi_state;
for (idx = 0; idx < ARRAY_LEN(pri->mbox); ++idx) {
RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
@@ -8828,7 +8828,7 @@ static void sig_pri_mwi_cache_update(struct sig_pri_span *pri)
ast_str_reset(uniqueid);
ast_str_set(&uniqueid, 0, "%s@%s", pri->mbox[idx].number, pri->mbox[idx].context);
- msg = stasis_cache_get(stasis_mwi_topic_cached(), stasis_mwi_state_type(), ast_str_buffer(uniqueid));
+ msg = stasis_cache_get(ast_mwi_topic_cached(), ast_mwi_state_type(), ast_str_buffer(uniqueid));
if (!msg) {
/* No cached event for this mailbox. */
continue;
@@ -9002,7 +9002,7 @@ int sig_pri_start_pri(struct sig_pri_span *pri)
ast_str_set(&mwi_description, -1, "%s span %d[%d] MWI mailbox %s@%s",
sig_pri_cc_type_name, pri->span, i, mbox_number, mbox_context);
- mailbox_specific_topic = stasis_mwi_topic(ast_str_buffer(uniqueid));
+ mailbox_specific_topic = ast_mwi_topic(ast_str_buffer(uniqueid));
if (mailbox_specific_topic) {
pri->mbox[i].sub = stasis_subscribe(mailbox_specific_topic, sig_pri_mwi_event_cb, pri);
}
diff --git a/include/asterisk/_private.h b/include/asterisk/_private.h
index 3fe35e58c..1d0844924 100644
--- a/include/asterisk/_private.h
+++ b/include/asterisk/_private.h
@@ -52,6 +52,20 @@ void ast_msg_shutdown(void); /*!< Provided by message.c */
int aco_init(void); /*!< Provided by config_options.c */
/*!
+ * \since 12
+ * \brief Possible return types for \ref ast_module_reload
+ */
+enum ast_module_reload_result {
+ AST_MODULE_RELOAD_SUCCESS = 0, /*!< The module was reloaded succesfully */
+ AST_MODULE_RELOAD_QUEUED, /*!< The module reload request was queued */
+ AST_MODULE_RELOAD_NOT_FOUND, /*!< The requested module was not found */
+ AST_MODULE_RELOAD_ERROR, /*!< An error occurred while reloading the module */
+ AST_MODULE_RELOAD_IN_PROGRESS, /*!< A module reload request is already in progress */
+ AST_MODULE_RELOAD_UNINITIALIZED, /*!< The module has not been initialized */
+ AST_MODULE_RELOAD_NOT_IMPLEMENTED, /*!< This module doesn't support reloading */
+};
+
+/*!
* \brief Initialize the bridging system.
* \since 12.0.0
*
@@ -78,13 +92,10 @@ int ast_local_init(void);
*
* \note Modules are reloaded using their reload() functions, not unloading
* them and loading them again.
- *
- * \return 0 if the specified module was not found.
- * \retval 1 if the module was found but cannot be reloaded.
- * \retval -1 if a reload operation is already in progress.
- * \retval 2 if the specfied module was found and reloaded.
+ *
+ * \retval The \ref ast_module_reload_result status of the module load request
*/
-int ast_module_reload(const char *name);
+enum ast_module_reload_result ast_module_reload(const char *name);
/*!
* \brief Process reload requests received during startup.
diff --git a/include/asterisk/app.h b/include/asterisk/app.h
index 6cfb38004..85c2aefb1 100644
--- a/include/asterisk/app.h
+++ b/include/asterisk/app.h
@@ -1104,8 +1104,8 @@ void ast_safe_fork_cleanup(void);
int ast_app_parse_timelen(const char *timestr, int *result, enum ast_timelen defunit);
/*!
+ * \since 12
* \brief Publish a MWI state update via stasis
- * \param[in] uniqueid A unique identifier for this mailbox (usually mailbox@context)
* \param[in] mailbox The number identifying this mailbox
* \param[in] context The context this mailbox resides in
* \param[in] new_msgs The number of new messages in this mailbox
@@ -1114,26 +1114,44 @@ int ast_app_parse_timelen(const char *timestr, int *result, enum ast_timelen def
* \retval -1 Failure
* \since 12
*/
-#define stasis_publish_mwi_state(mailbox, context, new_msgs, old_msgs) \
- stasis_publish_mwi_state_full(mailbox, context, new_msgs, old_msgs, NULL)
+#define ast_publish_mwi_state(mailbox, context, new_msgs, old_msgs) \
+ ast_publish_mwi_state_full(mailbox, context, new_msgs, old_msgs, NULL, NULL)
+
+/*!
+ * \since 12
+ * \brief Publish a MWI state update associated with some channel
+ * \param[in] mailbox The number identifying this mailbox
+ * \param[in] context The context this mailbox resides in
+ * \param[in] new_msgs The number of new messages in this mailbox
+ * \param[in] old_msgs The number of old messages in this mailbox
+ * \param[in] channel_id A unique identifier for a channel associated with this
+ * change in mailbox state
+ * \retval 0 Success
+ * \retval -1 Failure
+ * \since 12
+ */
+#define ast_publish_mwi_state_channel(mailbox, context, new_msgs, old_msgs, channel_id) \
+ ast_publish_mwi_state_full(mailbox, context, new_msgs, old_msgs, channel_id, NULL)
/*!
- * \brief Publish a MWI state update via stasis with EID
- * \param[in] uniqueid A unique identifier for this mailbox (usually mailbox@context)
+ * \since 12
+ * \brief Publish a MWI state update via stasis with all parameters
* \param[in] mailbox The number identifying this mailbox
* \param[in] context The context this mailbox resides in
* \param[in] new_msgs The number of new messages in this mailbox
* \param[in] old_msgs The number of old messages in this mailbox
+ * \param[in] channel_id A unique identifier for a channel associated with this
* \param[in] eid The EID of the server that originally published the message
* \retval 0 Success
* \retval -1 Failure
* \since 12
*/
-int stasis_publish_mwi_state_full(
+int ast_publish_mwi_state_full(
const char *mailbox,
const char *context,
int new_msgs,
int old_msgs,
+ const char *channel_id,
struct ast_eid *eid);
/*! \addtogroup StasisTopicsAndMessages
@@ -1144,49 +1162,103 @@ int stasis_publish_mwi_state_full(
* \brief The structure that contains MWI state
* \since 12
*/
-struct stasis_mwi_state {
+struct ast_mwi_state {
AST_DECLARE_STRING_FIELDS(
- AST_STRING_FIELD(uniqueid); /*!< Unique identifier for this mailbox/context */
- AST_STRING_FIELD(mailbox); /*!< Mailbox for this event */
- AST_STRING_FIELD(context); /*!< Context that this mailbox belongs to */
+ AST_STRING_FIELD(uniqueid); /*!< Unique identifier for this mailbox/context */
+ AST_STRING_FIELD(mailbox); /*!< Mailbox for this event */
+ AST_STRING_FIELD(context); /*!< Context that this mailbox belongs to */
);
- int new_msgs; /*!< The current number of new messages for this mailbox */
- int old_msgs; /*!< The current number of old messages for this mailbox */
- struct ast_eid eid; /*!< The EID of the server where this message originated */
+ int new_msgs; /*!< The current number of new messages for this mailbox */
+ int old_msgs; /*!< The current number of old messages for this mailbox */
+ /*! If applicable, a snapshot of the channel that caused this MWI change */
+ struct ast_channel_snapshot *snapshot;
+ struct ast_eid eid; /*!< The EID of the server where this message originated */
};
/*!
- * \brief Get the Stasis topic for MWI messages
+ * \brief Object that represents an MWI update with some additional application
+ * defined data
+ */
+struct ast_mwi_blob {
+ struct ast_mwi_state *mwi_state; /*!< MWI state */
+ struct ast_json *blob; /*!< JSON blob of data */
+};
+
+/*!
+ * \since 12
+ * \brief Create a \ref ast_mwi_state object
+ *
+ * \retval \ref ast_mwi_state object on success
+ * \retval NULL on error
+ */
+struct ast_mwi_state *ast_mwi_create(const char *mailbox, const char *context);
+
+/*!
+ * \since 12
+ * \brief Creates a \ref ast_mwi_blob message.
+ *
+ * The \a blob JSON object requires a \c "type" field describing the blob. It
+ * should also be treated as immutable and not modified after it is put into the
+ * message.
+ *
+ * \param mwi_state MWI state associated with the update
+ * \param message_type The type of message to create
+ * \param blob JSON object representing the data.
+ * \return \ref ast_mwi_blob message.
+ * \return \c NULL on error
+ */
+struct stasis_message *ast_mwi_blob_create(struct ast_mwi_state *mwi_state,
+ struct stasis_message_type *message_type,
+ struct ast_json *blob);
+
+/*!
+ * \brief Get the \ref stasis topic for MWI messages
* \retval The topic structure for MWI messages
* \retval NULL if it has not been allocated
* \since 12
*/
-struct stasis_topic *stasis_mwi_topic_all(void);
+struct stasis_topic *ast_mwi_topic_all(void);
/*!
- * \brief Get the Stasis topic for MWI messages on a unique ID
+ * \brief Get the \ref stasis topic for MWI messages on a unique ID
* \param uniqueid The unique id for which to get the topic
* \retval The topic structure for MWI messages for a given uniqueid
* \retval NULL if it failed to be found or allocated
* \since 12
*/
-struct stasis_topic *stasis_mwi_topic(const char *uniqueid);
+struct stasis_topic *ast_mwi_topic(const char *uniqueid);
/*!
- * \brief Get the Stasis caching topic for MWI messages
+ * \brief Get the \ref stasis caching topic for MWI messages
* \retval The caching topic structure for MWI messages
* \retval NULL if it has not been allocated
* \since 12
*/
-struct stasis_caching_topic *stasis_mwi_topic_cached(void);
+struct stasis_caching_topic *ast_mwi_topic_cached(void);
/*!
- * \brief Get the Stasis message type for MWI messages
+ * \brief Get the \ref stasis message type for MWI messages
* \retval The message type structure for MWI messages
- * \retval NULL if it has not been allocated
+ * \retval NULL on error
+ * \since 12
+ */
+struct stasis_message_type *ast_mwi_state_type(void);
+
+/*!
+ * \brief Get the \ref stasis message type for voicemail application specific messages
+ *
+ * This message type exists for those messages a voicemail application may wish to send
+ * that have no logical relationship with other voicemail applications. Voicemail apps
+ * that use this message type must pass a \ref ast_mwi_blob. Any extraneous information
+ * in the JSON blob must be packed as key/value pair tuples of strings.
+ *
+ * At least one key/value tuple must have a key value of "Event".
+ *
+ * \retval The \ref stasis_message_type for voicemail application specific messages
+ * \retval NULL on error
* \since 12
*/
-struct stasis_message_type *stasis_mwi_state_type(void);
+struct stasis_message_type *ast_mwi_vm_app_type(void);
/*! @} */
diff --git a/include/asterisk/json.h b/include/asterisk/json.h
index 978d6396a..baf8cf6a2 100644
--- a/include/asterisk/json.h
+++ b/include/asterisk/json.h
@@ -125,6 +125,8 @@ struct ast_json *ast_json_ref(struct ast_json *value);
/*!
* \brief Decrease refcount on \a value. If refcount reaches zero, \a value is freed.
* \since 12.0.0
+ *
+ * \note It is safe to pass \c NULL to this function.
*/
void ast_json_unref(struct ast_json *value);
@@ -602,6 +604,15 @@ struct ast_json_iter *ast_json_object_iter_next(struct ast_json *object, struct
const char *ast_json_object_iter_key(struct ast_json_iter *iter);
/*!
+ * \brief Retrieve the iterator object for a particular key
+ * \since 12.0.0
+ *
+ * \param key Key of the field the \c ast_json_iter points to
+ * \return \ref ast_json_iter object that points to \a key
+ */
+struct ast_json_iter *ast_json_object_key_to_iter(const char *key);
+
+/*!
* \brief Get the value from an iterator.
* \since 12.0.0
*
@@ -628,6 +639,23 @@ struct ast_json *ast_json_object_iter_value(struct ast_json_iter *iter);
*/
int ast_json_object_iter_set(struct ast_json *object, struct ast_json_iter *iter, struct ast_json *value);
+/*!
+ * \brief Iterate over key/value pairs
+ *
+ * \note This is a reproduction of the jansson library's \ref json_object_foreach
+ * using the equivalent ast_* wrapper functions. This creates a for loop using the various
+ * iteration function calls.
+ *
+ * \param object The \ref ast_json object that contains key/value tuples to iterate over
+ * \param key A \c const char pointer key for the key/value tuple
+ * \param value A \ref ast_json object for the key/value tuple
+ */
+#define ast_json_object_foreach(object, key, value) \
+ for (key = ast_json_object_iter_key(ast_json_object_iter(object)); \
+ key && (value = ast_json_object_iter_value(ast_json_object_key_to_iter(key))); \
+ key = ast_json_object_iter_key(ast_json_object_iter_next(object, ast_json_object_key_to_iter(key))))
+
+
/*!@}*/
/*!@{*/
diff --git a/include/asterisk/manager.h b/include/asterisk/manager.h
index 4e9b8d14a..6b1402bc3 100644
--- a/include/asterisk/manager.h
+++ b/include/asterisk/manager.h
@@ -330,7 +330,7 @@ struct ast_channel_snapshot;
* \retval NULL on error
* \retval ast_str* on success (must be ast_freed by caller)
*/
-struct ast_str *ast_manager_build_channel_state_string_suffix(
+struct ast_str *ast_manager_build_channel_state_string_prefix(
const struct ast_channel_snapshot *snapshot,
const char *suffix);
@@ -351,6 +351,32 @@ struct ast_str *ast_manager_build_channel_state_string(
struct ast_bridge_snapshot;
/*!
+ * \since 12
+ * \brief Callback used to determine whether a key should be skipped when converting a
+ * JSON object to a manager blob
+ * \param key Key from JSON blob to be evaluated
+ * \retval non-zero if the key should be excluded
+ * \retval zero if the key should not be excluded
+ */
+typedef int (*key_exclusion_cb)(const char *key);
+
+struct ast_json;
+
+/*!
+ * \since 12
+ * \brief Convert a JSON object into an AMI compatible string
+ *
+ * \param blob The JSON blob containing key/value pairs to convert
+ * \param exclusion_cb A \ref key_exclusion_cb pointer to a function that will exclude
+ * keys from the final AMI string
+ *
+ * \retval A malloc'd \ref ast_str object. Callers of this function should free
+ * the returned \ref ast_str object
+ * \retval NULL on error
+ */
+struct ast_str *ast_manager_str_from_json_object(struct ast_json *blob, key_exclusion_cb exclusion_cb);
+
+/*!
* \brief Generate the AMI message body from a bridge snapshot
* \since 12
*
@@ -398,13 +424,21 @@ ast_manager_event_blob_create(
/*!
* \brief Initialize support for AMI channel events.
- * \return 0 on success.
- * \return non-zero on error.
+ * \retval 0 on success.
+ * \retval non-zero on error.
* \since 12
*/
int manager_channels_init(void);
/*!
+ * \since 12
+ * \brief Initialize support for AMI MWI events.
+ * \retval 0 on success
+ * \retval non-zero on error
+ */
+int manager_mwi_init(void);
+
+/*!
* \brief Initialize support for AMI channel events.
* \return 0 on success.
* \return non-zero on error.
@@ -412,4 +446,54 @@ int manager_channels_init(void);
*/
int manager_bridging_init(void);
+/*!
+ * \since 12
+ * \brief Get the \ref stasis_message_type for generic messages
+ *
+ * A generic AMI message expects a JSON only payload. The payload must have the following
+ * structure:
+ * {type: s, class_type: i, event: [ {s: s}, ...] }
+ *
+ * - type is the AMI event type
+ * - class_type is the class authorization type for the event
+ * - event is a list of key/value tuples to be sent out in the message
+ *
+ * \retval A \ref stasis_message_type for AMI messages
+ */
+struct stasis_message_type *ast_manager_get_generic_type(void);
+
+/*!
+ * \since 12
+ * \brief Get the \ref stasis topic for AMI
+ *
+ * \retval The \ref stasis topic for AMI
+ * \retval NULL on error
+ */
+struct stasis_topic *ast_manager_get_topic(void);
+
+struct ast_json;
+
+/*!
+ * \since 12
+ * \brief Publish a generic \ref stasis_message_type to the \ref stasis_topic for AMI
+ *
+ * Publishes a message to the \ref stasis message bus solely for the consumption of AMI.
+ * The message will be of the type provided by \ref ast_manager_get_type, and will be
+ * published to the topic provided by \ref ast_manager_get_topic. As such, the JSON must
+ * be constructed as defined by the \ref ast_manager_get_type message.
+ *
+ * \retval 0 on success
+ * \retval -1 on failure
+ */
+int ast_manager_publish_message(struct ast_json *json);
+
+/*!
+ * \since 12
+ * \brief Get the \ref stasis_message_router for AMI
+ *
+ * \retval The \ref stasis_message_router for AMI
+ * \retval NULL on error
+ */
+struct stasis_message_router *ast_manager_get_message_router(void);
+
#endif /* _ASTERISK_MANAGER_H */
diff --git a/include/asterisk/stasis_channels.h b/include/asterisk/stasis_channels.h
index dace99af5..7c214d5a7 100644
--- a/include/asterisk/stasis_channels.h
+++ b/include/asterisk/stasis_channels.h
@@ -125,14 +125,15 @@ struct ast_channel_snapshot *ast_channel_snapshot_create(
/*!
* \since 12
- * \brief Get the most recent snapshot for channel with the given \a uniqueid.
+ * \brief Obtain the latest \ref ast_channel_snapshot from the \ref stasis cache. This is
+ * an ao2 object, so use \ref ao2_cleanup() to deallocate.
*
- * \param uniqueid Uniqueid of the snapshot to fetch.
- * \return Most recent channel snapshot
- * \return \c NULL on error
+ * \param unique_id The channel's unique ID
+ *
+ * \retval A \ref ast_channel_snapshot on success
+ * \retval NULL on error
*/
-struct ast_channel_snapshot *ast_channel_snapshot_get_latest(
- const char *uniqueid);
+struct ast_channel_snapshot *ast_channel_snapshot_get_latest(const char *uniqueid);
/*!
* \since 12
@@ -154,6 +155,27 @@ struct stasis_message *ast_channel_blob_create(struct ast_channel *chan,
/*!
* \since 12
+ * \brief Creates a \ref ast_channel_blob message using the current cached
+ * \ref ast_channel_snapshot for the passed in \ref ast_channel
+ *
+ * The given \a blob should be treated as immutable and not modified after it is
+ * put into the message.
+ *
+ * \param chan Channel blob is associated with, or \c NULL for global/all channels.
+ * \param type Message type for this blob.
+ * \param blob JSON object representing the data, or \c NULL for no data. If
+ * \c NULL, ast_json_null() is put into the object.
+ *
+ * \param chan Channel blob is associated with
+ * \param blob JSON object representing the data.
+ * \return \ref ast_channel_blob message.
+ * \return \c NULL on error
+ */
+struct stasis_message *ast_channel_cached_blob_create(struct ast_channel *chan,
+ struct stasis_message_type *type, struct ast_json *blob);
+
+/*!
+ * \since 12
* \brief Create a \ref ast_channel_blob message, pulling channel state from
* the cache.
*
@@ -319,6 +341,70 @@ struct stasis_message_type *ast_channel_dtmf_end_type(void);
/*!
* \since 12
+ * \brief Message type for when a channel starts spying on another channel
+ *
+ * \retval A stasis message type
+ */
+struct stasis_message_type *ast_channel_chanspy_start_type(void);
+
+/*!
+ * \since 12
+ * \brief Message type for when a channel stops spying on another channel
+ *
+ * \retval A stasis message type
+ */
+struct stasis_message_type *ast_channel_chanspy_stop_type(void);
+
+/*!
+ * \since 12
+ * \brief Message type for a fax operation
+ *
+ * \retval A stasis message type
+ */
+struct stasis_message_type *ast_channel_fax_type(void);
+
+/*!
+ * \since 12
+ * \brief Message type for hangup handler related actions
+ *
+ * \retval A stasis message type
+ */
+struct stasis_message_type *ast_channel_hangup_handler_type(void);
+
+/*!
+ * \since 12
+ * \brief Message type for starting monitor on a channel
+ *
+ * \retval A stasis message type
+ */
+struct stasis_message_type *ast_channel_monitor_start_type(void);
+
+/*!
+ * \since 12
+ * \brief Message type for stopping monitor on a channel
+ *
+ * \retval A stasis message type
+ */
+struct stasis_message_type *ast_channel_monitor_stop_type(void);
+
+/*!
+ * \since 12
+ * \brief Message type for starting music on hold on a channel
+ *
+ * \retval A stasis message type
+ */
+struct stasis_message_type *ast_channel_moh_start_type(void);
+
+/*!
+ * \since 12
+ * \brief Message type for stopping music on hold on a channel
+ *
+ * \retval A stasis message type
+ */
+struct stasis_message_type *ast_channel_moh_stop_type(void);
+
+/*!
+ * \since 12
* \brief Publish in the \ref ast_channel_topic or \ref ast_channel_topic_all
* topics a stasis message for the channels involved in a dial operation.
*
diff --git a/main/app.c b/main/app.c
index 3001450e8..9fa501fe5 100644
--- a/main/app.c
+++ b/main/app.c
@@ -68,6 +68,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/module.h"
#include "asterisk/astobj2.h"
#include "asterisk/stasis.h"
+#include "asterisk/stasis_channels.h"
+#include "asterisk/json.h"
#define MWI_TOPIC_BUCKETS 57
@@ -82,11 +84,22 @@ struct zombie {
static AST_LIST_HEAD_STATIC(zombies, zombie);
+/*
+ * @{ \brief Define \ref stasis topic objects for MWI
+ */
static struct stasis_topic *mwi_topic_all;
static struct stasis_caching_topic *mwi_topic_cached;
static struct stasis_topic_pool *mwi_topic_pool;
+/* @} */
+
+/*
+ * @{ \brief Define \ref stasis message types for MWI
+ */
+STASIS_MESSAGE_TYPE_DEFN(ast_mwi_state_type);
+STASIS_MESSAGE_TYPE_DEFN(ast_mwi_vm_app_type);
+/* @} */
+
-STASIS_MESSAGE_TYPE_DEFN(stasis_mwi_state_type);
static void *shaun_of_the_dead(void *data)
{
@@ -2657,61 +2670,95 @@ int ast_app_parse_timelen(const char *timestr, int *result, enum ast_timelen uni
static void mwi_state_dtor(void *obj)
{
- struct stasis_mwi_state *mwi_state = obj;
+ struct ast_mwi_state *mwi_state = obj;
ast_string_field_free_memory(mwi_state);
+ ao2_cleanup(mwi_state->snapshot);
+ mwi_state->snapshot = NULL;
}
-struct stasis_topic *stasis_mwi_topic_all(void)
+struct stasis_topic *ast_mwi_topic_all(void)
{
return mwi_topic_all;
}
-struct stasis_caching_topic *stasis_mwi_topic_cached(void)
+struct stasis_caching_topic *ast_mwi_topic_cached(void)
{
return mwi_topic_cached;
}
-struct stasis_topic *stasis_mwi_topic(const char *uniqueid)
+struct stasis_topic *ast_mwi_topic(const char *uniqueid)
{
return stasis_topic_pool_get_topic(mwi_topic_pool, uniqueid);
}
-int stasis_publish_mwi_state_full(
+struct ast_mwi_state *ast_mwi_create(const char *mailbox, const char *context)
+{
+ RAII_VAR(struct ast_mwi_state *, mwi_state, NULL, ao2_cleanup);
+ struct ast_str *uniqueid = ast_str_alloca(AST_MAX_MAILBOX_UNIQUEID);
+
+ ast_assert(!ast_strlen_zero(mailbox));
+ ast_assert(!ast_strlen_zero(context));
+
+ mwi_state = ao2_alloc(sizeof(*mwi_state), mwi_state_dtor);
+ if (!mwi_state) {
+ return NULL;
+ }
+
+ if (ast_string_field_init(mwi_state, 256)) {
+ return NULL;
+ }
+ ast_str_set(&uniqueid, 0, "%s@%s", mailbox, context);
+ ast_string_field_set(mwi_state, uniqueid, ast_str_buffer(uniqueid));
+ ast_string_field_set(mwi_state, mailbox, mailbox);
+ ast_string_field_set(mwi_state, context, context);
+
+ ao2_ref(mwi_state, +1);
+ return mwi_state;
+}
+
+
+int ast_publish_mwi_state_full(
const char *mailbox,
const char *context,
int new_msgs,
int old_msgs,
+ const char *channel_id,
struct ast_eid *eid)
{
- RAII_VAR(struct stasis_mwi_state *, mwi_state, NULL, ao2_cleanup);
+ RAII_VAR(struct ast_mwi_state *, mwi_state, NULL, ao2_cleanup);
RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
struct ast_str *uniqueid = ast_str_alloca(AST_MAX_MAILBOX_UNIQUEID);
struct stasis_topic *mailbox_specific_topic;
- ast_assert(!ast_strlen_zero(mailbox));
- ast_assert(!ast_strlen_zero(context));
-
- ast_str_set(&uniqueid, 0, "%s@%s", mailbox, context);
-
- mwi_state = ao2_alloc(sizeof(*mwi_state), mwi_state_dtor);
- if (ast_string_field_init(mwi_state, 256)) {
+ mwi_state = ast_mwi_create(mailbox, context);
+ if (!mwi_state) {
return -1;
}
- ast_string_field_set(mwi_state, uniqueid, ast_str_buffer(uniqueid));
- ast_string_field_set(mwi_state, mailbox, mailbox);
- ast_string_field_set(mwi_state, context, context);
mwi_state->new_msgs = new_msgs;
mwi_state->old_msgs = old_msgs;
+
+ if (!ast_strlen_zero(channel_id)) {
+ RAII_VAR(struct stasis_message *, chan_message,
+ stasis_cache_get(ast_channel_topic_all_cached(),
+ ast_channel_snapshot_type(),
+ channel_id),
+ ao2_cleanup);
+ if (chan_message) {
+ mwi_state->snapshot = stasis_message_data(chan_message);
+ ao2_ref(mwi_state->snapshot, +1);
+ }
+ }
+
if (eid) {
mwi_state->eid = *eid;
} else {
ast_set_default_eid(&mwi_state->eid);
}
- message = stasis_message_create(stasis_mwi_state_type(), mwi_state);
+ message = stasis_message_create(ast_mwi_state_type(), mwi_state);
- mailbox_specific_topic = stasis_mwi_topic(ast_str_buffer(uniqueid));
+ mailbox_specific_topic = ast_mwi_topic(ast_str_buffer(uniqueid));
if (!mailbox_specific_topic) {
return -1;
}
@@ -2723,8 +2770,8 @@ int stasis_publish_mwi_state_full(
static const char *mwi_state_get_id(struct stasis_message *message)
{
- if (stasis_mwi_state_type() == stasis_message_type(message)) {
- struct stasis_mwi_state *mwi_state = stasis_message_data(message);
+ if (ast_mwi_state_type() == stasis_message_type(message)) {
+ struct ast_mwi_state *mwi_state = stasis_message_data(message);
return mwi_state->uniqueid;
} else if (stasis_subscription_change_type() == stasis_message_type(message)) {
struct stasis_subscription_change *change = stasis_message_data(message);
@@ -2734,19 +2781,58 @@ static const char *mwi_state_get_id(struct stasis_message *message)
return NULL;
}
+static void mwi_blob_dtor(void *obj)
+{
+ struct ast_mwi_blob *mwi_blob = obj;
+
+ ao2_cleanup(mwi_blob->mwi_state);
+ ast_json_unref(mwi_blob->blob);
+}
+
+struct stasis_message *ast_mwi_blob_create(struct ast_mwi_state *mwi_state,
+ struct stasis_message_type *message_type,
+ struct ast_json *blob)
+{
+ RAII_VAR(struct ast_mwi_blob *, obj, NULL, ao2_cleanup);
+ RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
+
+ ast_assert(blob != NULL);
+
+ obj = ao2_alloc(sizeof(*obj), mwi_blob_dtor);
+ if (!obj) {
+ return NULL;
+ }
+
+ obj->mwi_state = mwi_state;
+ ao2_ref(obj->mwi_state, +1);
+ obj->blob = ast_json_ref(blob);
+
+ msg = stasis_message_create(message_type, obj);
+ if (!msg) {
+ return NULL;
+ }
+
+ ao2_ref(msg, +1);
+ return msg;
+}
+
static void app_exit(void)
{
ao2_cleanup(mwi_topic_all);
mwi_topic_all = NULL;
mwi_topic_cached = stasis_caching_unsubscribe_and_join(mwi_topic_cached);
- STASIS_MESSAGE_TYPE_CLEANUP(stasis_mwi_state_type);
+ STASIS_MESSAGE_TYPE_CLEANUP(ast_mwi_state_type);
+ STASIS_MESSAGE_TYPE_CLEANUP(ast_mwi_vm_app_type);
ao2_cleanup(mwi_topic_pool);
mwi_topic_pool = NULL;
}
int app_init(void)
{
- if (STASIS_MESSAGE_TYPE_INIT(stasis_mwi_state_type) != 0) {
+ if (STASIS_MESSAGE_TYPE_INIT(ast_mwi_state_type) != 0) {
+ return -1;
+ }
+ if (STASIS_MESSAGE_TYPE_INIT(ast_mwi_vm_app_type) != 0) {
return -1;
}
mwi_topic_all = stasis_topic_create("stasis_mwi_topic");
diff --git a/main/asterisk.c b/main/asterisk.c
index d8062d3b1..9407338ed 100644
--- a/main/asterisk.c
+++ b/main/asterisk.c
@@ -242,12 +242,44 @@ int daemon(int, int); /* defined in libresolv of all places */
#include "asterisk/sorcery.h"
#include "asterisk/stasis.h"
#include "asterisk/json.h"
-#include "asterisk/security_events.h"
#include "asterisk/stasis_endpoints.h"
#include "../defaults.h"
/*** DOCUMENTATION
+ <managerEvent language="en_US" name="FullyBooted">
+ <managerEventInstance class="EVENT_FLAG_SYSTEM">
+ <synopsis>Raised when all Asterisk initialization procedures have finished.</synopsis>
+ <syntax>
+ <parameter name="Status">
+ <para>Informational message</para>
+ </parameter>
+ </syntax>
+ </managerEventInstance>
+ </managerEvent>
+ <managerEvent language="en_US" name="Shutdown">
+ <managerEventInstance class="EVENT_FLAG_SYSTEM">
+ <synopsis>Raised when Asterisk is shutdown or restarted.</synopsis>
+ <syntax>
+ <parameter name="Shutdown">
+ <para>Whether the shutdown is proceeding cleanly (all channels
+ were hungup successfully) or uncleanly (channels will be
+ terminated)</para>
+ <enumlist>
+ <enum name="Uncleanly"/>
+ <enum name="Cleanly"/>
+ </enumlist>
+ </parameter>
+ <parameter name="Restart">
+ <para>Whether or not a restart will occur.</para>
+ <enumlist>
+ <enum name="True"/>
+ <enum name="False"/>
+ </enumlist>
+ </parameter>
+ </syntax>
+ </managerEventInstance>
+ </managerEvent>
***/
#ifndef AF_LOCAL
@@ -425,6 +457,9 @@ struct file_version {
char *version;
};
+/*! \brief The \ref stasis topic for system level changes */
+static struct stasis_topic *system_topic;
+
static AST_RWLIST_HEAD_STATIC(file_versions, file_version);
void ast_register_file_version(const char *file, const char *version)
@@ -1067,7 +1102,7 @@ struct stasis_topic *ast_system_topic(void)
/*! \brief Cleanup the \ref stasis system level items */
static void stasis_system_topic_cleanup(void)
{
- ao2_ref(system_topic, -1);
+ ao2_cleanup(system_topic);
system_topic = NULL;
STASIS_MESSAGE_TYPE_CLEANUP(ast_network_change_type);
}
@@ -1085,9 +1120,54 @@ static int stasis_system_topic_init(void)
if (STASIS_MESSAGE_TYPE_INIT(ast_network_change_type) != 0) {
return -1;
}
+
return 0;
}
+/*!
+ * \brief Publish a \ref system_status_type message over \ref stasis
+ *
+ * \param payload The JSON payload to send with the message
+ */
+static void publish_system_message(const char *message_type, struct ast_json *obj)
+{
+ RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
+ RAII_VAR(struct ast_json_payload *, payload, NULL, ao2_cleanup);
+ RAII_VAR(struct ast_json *, event_info, NULL, ast_json_unref);
+
+ if (!obj) {
+ return;
+ }
+
+ event_info = ast_json_pack("{s: s, s: i, s: o}",
+ "type", message_type,
+ "class_type", EVENT_FLAG_SYSTEM,
+ "event", obj);
+ if (!event_info) {
+ return;
+ }
+
+ payload = ast_json_payload_create(event_info);
+ if (!payload) {
+ return;
+ }
+
+ message = stasis_message_create(ast_manager_get_generic_type(), payload);
+ if (!message) {
+ return;
+ }
+ stasis_publish(ast_manager_get_topic(), message);
+}
+
+static void publish_fully_booted(void)
+{
+ RAII_VAR(struct ast_json *, json_object, NULL, ast_json_unref);
+
+ json_object = ast_json_pack("{s: s}",
+ "Status", "Fully Booted");
+ publish_system_message("FullyBooted", json_object);
+}
+
static void ast_run_atexits(void)
{
struct ast_atexit *ae;
@@ -1897,6 +1977,7 @@ static int can_safely_quit(shutdown_nice_t niceness, int restart)
static void really_quit(int num, shutdown_nice_t niceness, int restart)
{
int active_channels;
+ RAII_VAR(struct ast_json *, json_object, NULL, ast_json_unref);
if (niceness >= SHUTDOWN_NICE) {
ast_module_shutdown();
@@ -1925,33 +2006,10 @@ static void really_quit(int num, shutdown_nice_t niceness, int restart)
}
}
active_channels = ast_active_channels();
- /* The manager event for shutdown must happen prior to ast_run_atexits, as
- * the manager interface will dispose of its sessions as part of its
- * shutdown.
- */
- /*** DOCUMENTATION
- <managerEventInstance>
- <synopsis>Raised when Asterisk is shutdown or restarted.</synopsis>
- <syntax>
- <parameter name="Shutdown">
- <enumlist>
- <enum name="Uncleanly"/>
- <enum name="Cleanly"/>
- </enumlist>
- </parameter>
- <parameter name="Restart">
- <enumlist>
- <enum name="True"/>
- <enum name="False"/>
- </enumlist>
- </parameter>
- </syntax>
- </managerEventInstance>
- ***/
- manager_event(EVENT_FLAG_SYSTEM, "Shutdown", "Shutdown: %s\r\n"
- "Restart: %s\r\n",
- active_channels ? "Uncleanly" : "Cleanly",
- restart ? "True" : "False");
+ json_object = ast_json_pack("{s: s, s: s}",
+ "Shutdown", active_channels ? "Uncleanly" : "Cleanly",
+ "Restart", restart ? "True" : "False");
+ publish_system_message("Shutdown", json_object);
ast_verb(0, "Asterisk %s ending (%d).\n",
active_channels ? "uncleanly" : "cleanly", num);
@@ -4226,13 +4284,13 @@ int main(int argc, char *argv[])
aco_init();
- if (devstate_init()) {
- printf("Device state core initialization failed.\n%s", term_quit());
+ if (app_init()) {
+ printf("App core initialization failed.\n%s", term_quit());
exit(1);
}
- if (app_init()) {
- printf("App core initialization failed.\n%s", term_quit());
+ if (devstate_init()) {
+ printf("Device state core initialization failed.\n%s", term_quit());
exit(1);
}
@@ -4264,12 +4322,6 @@ int main(int argc, char *argv[])
exit(1);
}
- if (ast_security_stasis_init()) { /* Initialize Security Stasis Topic and Events */
- ast_security_stasis_cleanup();
- printf("%s", term_quit());
- exit(1);
- }
-
if (ast_named_acl_init()) { /* Initialize the Named ACL system */
printf("%s", term_quit());
exit(1);
@@ -4374,12 +4426,7 @@ int main(int argc, char *argv[])
}
ast_set_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED);
- /*** DOCUMENTATION
- <managerEventInstance>
- <synopsis>Raised when all Asterisk initialization procedures have finished.</synopsis>
- </managerEventInstance>
- ***/
- manager_event(EVENT_FLAG_SYSTEM, "FullyBooted", "Status: Fully Booted\r\n");
+ publish_fully_booted();
ast_process_pending_reloads();
diff --git a/main/cdr.c b/main/cdr.c
index ff7cef207..a0560676a 100644
--- a/main/cdr.c
+++ b/main/cdr.c
@@ -1674,7 +1674,6 @@ static void do_reload(int reload)
ast_mutex_unlock(&cdr_batch_lock);
ast_config_destroy(config);
- manager_event(EVENT_FLAG_SYSTEM, "Reload", "Module: CDR\r\nMessage: CDR subsystem reload requested\r\n");
}
static void cdr_engine_shutdown(void)
diff --git a/main/cli.c b/main/cli.c
index 22232acbc..683ae9c3e 100644
--- a/main/cli.c
+++ b/main/cli.c
@@ -303,14 +303,30 @@ static char *handle_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args
return CLI_SUCCESS;
}
for (x = e->args; x < a->argc; x++) {
- int res = ast_module_reload(a->argv[x]);
- /* XXX reload has multiple error returns, including -1 on error and 2 on success */
+ enum ast_module_reload_result res = ast_module_reload(a->argv[x]);
switch (res) {
- case 0:
+ case AST_MODULE_RELOAD_NOT_FOUND:
ast_cli(a->fd, "No such module '%s'\n", a->argv[x]);
break;
- case 1:
- ast_cli(a->fd, "Module '%s' does not support reload\n", a->argv[x]);
+ case AST_MODULE_RELOAD_NOT_IMPLEMENTED:
+ ast_cli(a->fd, "The module '%s' does not support reloads\n", a->argv[x]);
+ break;
+ case AST_MODULE_RELOAD_QUEUED:
+ ast_cli(a->fd, "Asterisk cannot reload a module yet; request queued\n");
+ break;
+ case AST_MODULE_RELOAD_ERROR:
+ ast_cli(a->fd, "The module '%s' reported a reload failure\n", a->argv[x]);
+ break;
+ case AST_MODULE_RELOAD_IN_PROGRESS:
+ ast_cli(a->fd, "A module reload request is already in progress; please be patient\n");
+ break;
+ case AST_MODULE_RELOAD_UNINITIALIZED:
+ ast_cli(a->fd, "The module '%s' was not properly initialized. Before reloading"
+ " the module, you must run \"module load %s\" and fix whatever is"
+ " preventing the module from being initialized.\n", a->argv[x], a->argv[x]);
+ break;
+ case AST_MODULE_RELOAD_SUCCESS:
+ ast_cli(a->fd, "Module '%s' reloaded successfully.\n", a->argv[x]);
break;
}
}
diff --git a/main/dnsmgr.c b/main/dnsmgr.c
index bfba4714d..d642cd616 100644
--- a/main/dnsmgr.c
+++ b/main/dnsmgr.c
@@ -514,7 +514,6 @@ static int do_reload(int loading)
}
ast_mutex_unlock(&refresh_lock);
- manager_event(EVENT_FLAG_SYSTEM, "Reload", "Module: DNSmgr\r\nStatus: %s\r/nMessage: DNSmgr reload Requested\r\n", enabled ? "Enabled" : "Disabled");
return 0;
}
diff --git a/main/enum.c b/main/enum.c
index d09728889..7528092e9 100644
--- a/main/enum.c
+++ b/main/enum.c
@@ -1007,7 +1007,6 @@ static int private_enum_init(int reload)
ast_config_destroy(cfg);
}
ast_mutex_unlock(&enumlock);
- manager_event(EVENT_FLAG_SYSTEM, "Reload", "Module: Enum\r\nStatus: Enabled\r\nMessage: ENUM reload Requested\r\n");
return 0;
}
diff --git a/main/json.c b/main/json.c
index 5b69ccbaa..70830bd13 100644
--- a/main/json.c
+++ b/main/json.c
@@ -78,6 +78,9 @@ struct ast_json *ast_json_ref(struct ast_json *json)
void ast_json_unref(struct ast_json *json)
{
+ if (!json) {
+ return;
+ }
json_decref((json_t *)json);
}
@@ -327,6 +330,10 @@ const char *ast_json_object_iter_key(struct ast_json_iter *iter)
{
return json_object_iter_key(iter);
}
+struct ast_json_iter *ast_json_object_key_to_iter(const char *key)
+{
+ return (struct ast_json_iter *)json_object_key_to_iter(key);
+}
struct ast_json *ast_json_object_iter_value(struct ast_json_iter *iter)
{
return (struct ast_json *)json_object_iter_value(iter);
diff --git a/main/loader.c b/main/loader.c
index 3bcf37ca9..7e5a5ae3b 100644
--- a/main/loader.c
+++ b/main/loader.c
@@ -63,6 +63,30 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/utils.h"
/*** DOCUMENTATION
+ <managerEvent language="en_US" name="Reload">
+ <managerEventInstance class="EVENT_FLAG_SYSTEM">
+ <synopsis>Raised when a module has been reloaded in Asterisk.</synopsis>
+ <syntax>
+ <parameter name="Module">
+ <para>The name of the module that was reloaded, or
+ <literal>All</literal> if all modules were reloaded</para>
+ </parameter>
+ <parameter name="Status">
+ <para>The numeric status code denoting the success or failure
+ of the reload request.</para>
+ <enumlist>
+ <enum name="0"><para>Success</para></enum>
+ <enum name="1"><para>Request queued</para></enum>
+ <enum name="2"><para>Module not found</para></enum>
+ <enum name="3"><para>Error</para></enum>
+ <enum name="4"><para>Reload already in progress</para></enum>
+ <enum name="5"><para>Module uninitialized</para></enum>
+ <enum name="6"><para>Reload not supported</para></enum>
+ </enumlist>
+ </parameter>
+ </syntax>
+ </managerEventInstance>
+ </managerEvent>
***/
#ifndef RTLD_NOW
@@ -709,22 +733,63 @@ static void queue_reload_request(const char *module)
AST_LIST_UNLOCK(&reload_queue);
}
-int ast_module_reload(const char *name)
+/*!
+ * \since 12
+ * \internal
+ * \brief Publish a \ref stasis message regarding the reload result
+ */
+static void publish_reload_message(const char *name, enum ast_module_reload_result result)
+{
+ RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
+ RAII_VAR(struct ast_json_payload *, payload, NULL, ao2_cleanup);
+ RAII_VAR(struct ast_json *, json_object, NULL, ast_json_unref);
+ RAII_VAR(struct ast_json *, event_object, NULL, ast_json_unref);
+ char res_buffer[8];
+
+ snprintf(res_buffer, sizeof(res_buffer), "%d", result);
+ event_object = ast_json_pack("{s: s, s: s}",
+ "Module", S_OR(name, "All"),
+ "Status", res_buffer);
+ json_object = ast_json_pack("{s: s, s: i, s: o}",
+ "type", "Reload",
+ "class_type", EVENT_FLAG_SYSTEM,
+ "event", event_object);
+
+ if (!json_object) {
+ return;
+ }
+
+ payload = ast_json_payload_create(json_object);
+ if (!payload) {
+ return;
+ }
+
+ message = stasis_message_create(ast_manager_get_generic_type(), payload);
+ if (!message) {
+ return;
+ }
+
+ stasis_publish(ast_manager_get_topic(), message);
+}
+
+enum ast_module_reload_result ast_module_reload(const char *name)
{
struct ast_module *cur;
- int res = 0; /* return value. 0 = not found, others, see below */
+ enum ast_module_reload_result res = AST_MODULE_RELOAD_NOT_FOUND;
int i;
/* If we aren't fully booted, we just pretend we reloaded but we queue this
up to run once we are booted up. */
if (!ast_fully_booted) {
queue_reload_request(name);
- return 0;
+ res = AST_MODULE_RELOAD_QUEUED;
+ goto module_reload_exit;
}
if (ast_mutex_trylock(&reloadlock)) {
ast_verbose("The previous reload command didn't finish yet\n");
- return -1; /* reload already in progress */
+ res = AST_MODULE_RELOAD_IN_PROGRESS;
+ goto module_reload_exit;
}
ast_lastreloadtime = ast_tvnow();
@@ -740,26 +805,26 @@ int ast_module_reload(const char *name)
if (res != AST_LOCK_SUCCESS) {
ast_verbose("Cannot grab lock on %s\n", ast_config_AST_CONFIG_DIR);
ast_mutex_unlock(&reloadlock);
- return -1;
+ res = AST_MODULE_RELOAD_ERROR;
+ goto module_reload_exit;
}
}
/* Call "predefined" reload here first */
for (i = 0; reload_classes[i].name; i++) {
if (!name || !strcasecmp(name, reload_classes[i].name)) {
- if (!reload_classes[i].reload_fn()) {
- ast_test_suite_event_notify("MODULE_RELOAD", "Message: %s", name);
+ if (reload_classes[i].reload_fn() == AST_MODULE_LOAD_SUCCESS) {
+ res = AST_MODULE_RELOAD_SUCCESS;
}
- res = 2; /* found and reloaded */
}
}
- if (name && res) {
+ if (name && res == AST_MODULE_RELOAD_SUCCESS) {
if (ast_opt_lock_confdir) {
ast_unlock_path(ast_config_AST_CONFIG_DIR);
}
ast_mutex_unlock(&reloadlock);
- return res;
+ goto module_reload_exit;
}
AST_LIST_LOCK(&module_list);
@@ -770,28 +835,30 @@ int ast_module_reload(const char *name)
continue;
if (!cur->flags.running || cur->flags.declined) {
- if (!name)
+ if (res == AST_MODULE_RELOAD_NOT_FOUND) {
+ res = AST_MODULE_RELOAD_UNINITIALIZED;
+ }
+ if (!name) {
continue;
- ast_log(LOG_NOTICE, "The module '%s' was not properly initialized. "
- "Before reloading the module, you must run \"module load %s\" "
- "and fix whatever is preventing the module from being initialized.\n",
- name, name);
- res = 2; /* Don't report that the module was not found */
+ }
break;
}
if (!info->reload) { /* cannot be reloaded */
- /* Nothing to reload, so reload is successful */
- ast_test_suite_event_notify("MODULE_RELOAD", "Message: %s", cur->resource);
- if (res < 1) /* store result if possible */
- res = 1; /* 1 = no reload() method */
- continue;
+ if (res == AST_MODULE_RELOAD_NOT_FOUND) {
+ res = AST_MODULE_RELOAD_NOT_IMPLEMENTED;
+ }
+ if (!name) {
+ continue;
+ }
+ break;
}
-
- res = 2;
ast_verb(3, "Reloading module '%s' (%s)\n", cur->resource, info->description);
- if (!info->reload()) {
- ast_test_suite_event_notify("MODULE_RELOAD", "Message: %s", cur->resource);
+ if (info->reload() == AST_MODULE_LOAD_SUCCESS) {
+ res = AST_MODULE_RELOAD_SUCCESS;
+ }
+ if (name) {
+ break;
}
}
AST_LIST_UNLOCK(&module_list);
@@ -801,6 +868,8 @@ int ast_module_reload(const char *name)
}
ast_mutex_unlock(&reloadlock);
+module_reload_exit:
+ publish_reload_message(name, res);
return res;
}
@@ -1212,25 +1281,6 @@ done:
}
AST_LIST_UNLOCK(&module_list);
-
- /* Tell manager clients that are aggressive at logging in that we're done
- loading modules. If there's a DNS problem in chan_sip, we might not
- even reach this */
- /*** DOCUMENTATION
- <managerEventInstance>
- <synopsis>Raised when all dynamic modules have finished their initial loading.</synopsis>
- <syntax>
- <parameter name="ModuleSelection">
- <enumlist>
- <enum name="Preload"/>
- <enum name="All"/>
- </enumlist>
- </parameter>
- </syntax>
- </managerEventInstance>
- ***/
- manager_event(EVENT_FLAG_SYSTEM, "ModuleLoadReport", "ModuleLoadStatus: Done\r\nModuleSelection: %s\r\nModuleCount: %d\r\n", preload_only ? "Preload" : "All", modulecount);
-
return res;
}
diff --git a/main/manager.c b/main/manager.c
index c28e6169b..96fbdae61 100644
--- a/main/manager.c
+++ b/main/manager.c
@@ -92,6 +92,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/stringfields.h"
#include "asterisk/presencestate.h"
#include "asterisk/stasis.h"
+#include "asterisk/stasis_message_router.h"
#include "asterisk/test.h"
#include "asterisk/json.h"
#include "asterisk/bridging.h"
@@ -1062,6 +1063,12 @@ static int block_sockets;
static int unauth_sessions = 0;
static struct stasis_subscription *acl_change_sub;
+/*! \brief A \ref stasis_topic that all topics AMI cares about will be forwarded to */
+static struct stasis_topic *manager_topic;
+
+/*! \brief The \ref stasis_message_router for all \ref stasis messages */
+static struct stasis_message_router *stasis_router;
+
#define MGR_SHOW_TERMINAL_WIDTH 80
#define MAX_VARS 128
@@ -1226,6 +1233,12 @@ AO2_GLOBAL_OBJ_STATIC(event_docs);
static enum add_filter_result manager_add_filter(const char *filter_pattern, struct ao2_container *whitefilters, struct ao2_container *blackfilters);
/*!
+ * @{ \brief Define AMI message types.
+ */
+STASIS_MESSAGE_TYPE_DEFN(ast_manager_get_generic_type);
+/*! @} */
+
+/*!
* \internal
* \brief Find a registered action object.
*
@@ -1249,6 +1262,89 @@ static struct manager_action *action_find(const char *name)
return act;
}
+struct stasis_topic *ast_manager_get_topic(void)
+{
+ return manager_topic;
+}
+
+struct stasis_message_router *ast_manager_get_message_router(void)
+{
+ return stasis_router;
+}
+
+struct ast_str *ast_manager_str_from_json_object(struct ast_json *blob, key_exclusion_cb exclusion_cb)
+{
+ struct ast_str *output_str = ast_str_create(32);
+ struct ast_json *value;
+ const char *key;
+ if (!output_str) {
+ return NULL;
+ }
+
+ ast_json_object_foreach(blob, key, value) {
+ if (exclusion_cb && exclusion_cb(key)) {
+ continue;
+ }
+ ast_str_append(&output_str, 0, "%s: %s\r\n", key, ast_json_string_get(value));
+ if (!output_str) {
+ return NULL;
+ }
+ }
+
+ return output_str;
+}
+
+static void manager_generic_msg_cb(void *data, struct stasis_subscription *sub,
+ struct stasis_topic *topic,
+ struct stasis_message *message)
+{
+ struct ast_json_payload *payload = stasis_message_data(message);
+ int class_type = ast_json_integer_get(ast_json_object_get(payload->json, "class_type"));
+ const char *type = ast_json_string_get(ast_json_object_get(payload->json, "type"));
+ struct ast_json *event = ast_json_object_get(payload->json, "event");
+ RAII_VAR(struct ast_str *, event_buffer, NULL, ast_free);
+
+ event_buffer = ast_manager_str_from_json_object(event, NULL);
+ if (!event_buffer) {
+ ast_log(AST_LOG_WARNING, "Error while creating payload for event %s\n", type);
+ return;
+ }
+ manager_event(class_type, type, "%s", ast_str_buffer(event_buffer));
+}
+
+int ast_manager_publish_message(struct ast_json *obj)
+{
+ RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
+ RAII_VAR(struct ast_json_payload *, payload, NULL, ao2_cleanup);
+ struct ast_json *type = ast_json_object_get(obj, "type");
+ struct ast_json *class_type = ast_json_object_get(obj, "class_type");
+ struct ast_json *event = ast_json_object_get(obj, "event");
+
+ if (!type) {
+ ast_log(AST_LOG_ERROR, "Attempt to send generic manager event without type field\n");
+ return -1;
+ }
+ if (!class_type) {
+ ast_log(AST_LOG_ERROR, "Attempt to send generic manager event without class type field\n");
+ return -1;
+ }
+ if (!event) {
+ ast_log(AST_LOG_ERROR, "Attempt to send generic manager event without event payload\n");
+ return -1;
+ }
+
+ payload = ast_json_payload_create(obj);
+ if (!payload) {
+ return -1;
+ }
+ message = stasis_message_create(ast_manager_get_generic_type(), payload);
+ if (!message) {
+ return -1;
+ }
+ stasis_publish(ast_manager_get_topic(), message);
+ return 0;
+}
+
/*! \brief Add a custom hook to be called when an event is fired */
void ast_manager_register_hook(struct manager_custom_hook *hook)
{
@@ -5034,24 +5130,29 @@ static int action_corestatus(struct mansession *s, const struct message *m)
static int action_reload(struct mansession *s, const struct message *m)
{
const char *module = astman_get_header(m, "Module");
- int res = ast_module_reload(S_OR(module, NULL));
+ enum ast_module_reload_result res = ast_module_reload(S_OR(module, NULL));
switch (res) {
- case -1:
- astman_send_error(s, m, "A reload is in progress");
- break;
- case 0:
+ case AST_MODULE_RELOAD_NOT_FOUND:
astman_send_error(s, m, "No such module");
break;
- case 1:
+ case AST_MODULE_RELOAD_NOT_IMPLEMENTED:
astman_send_error(s, m, "Module does not support reload");
break;
- case 2:
- astman_send_ack(s, m, "Module Reloaded");
- break;
- default:
+ case AST_MODULE_RELOAD_ERROR:
astman_send_error(s, m, "An unknown error occurred");
break;
+ case AST_MODULE_RELOAD_IN_PROGRESS:
+ astman_send_error(s, m, "A reload is in progress");
+ break;
+ case AST_MODULE_RELOAD_UNINITIALIZED:
+ astman_send_error(s, m, "Module not initialized");
+ break;
+ case AST_MODULE_RELOAD_QUEUED:
+ case AST_MODULE_RELOAD_SUCCESS:
+ /* Treat a queued request as success */
+ astman_send_ack(s, m, "Module Reloaded");
+ break;
}
return 0;
}
@@ -7526,6 +7627,14 @@ static void manager_shutdown(void)
ao2_t_global_obj_release(event_docs, "Dispose of event_docs");
#endif
+ if (stasis_router) {
+ stasis_message_router_unsubscribe_and_join(stasis_router);
+ stasis_router = NULL;
+ }
+ ao2_cleanup(manager_topic);
+ manager_topic = NULL;
+ STASIS_MESSAGE_TYPE_CLEANUP(ast_manager_get_generic_type);
+
ast_tcptls_server_stop(&ami_desc);
ast_tcptls_server_stop(&amis_desc);
@@ -7552,6 +7661,31 @@ static void manager_shutdown(void)
}
}
+
+/*! \brief Initialize all \ref stasis topics and routers used by the various
+ * sub-components of AMI
+ */
+static int manager_subscriptions_init(void)
+{
+ STASIS_MESSAGE_TYPE_INIT(ast_manager_get_generic_type);
+ manager_topic = stasis_topic_create("manager_topic");
+ if (!manager_topic) {
+ return -1;
+ }
+ stasis_router = stasis_message_router_create(manager_topic);
+ if (!stasis_router) {
+ return -1;
+ }
+
+ if (stasis_message_router_add(stasis_router,
+ ast_manager_get_generic_type(),
+ manager_generic_msg_cb,
+ NULL)) {
+ return -1;
+ }
+ return 0;
+}
+
static int __init_manager(int reload, int by_external_config)
{
struct ast_config *ucfg = NULL, *cfg = NULL;
@@ -7573,8 +7707,19 @@ static int __init_manager(int reload, int by_external_config)
manager_enabled = 0;
- if (manager_channels_init()) {
- return -1;
+ if (!reload) {
+ if (manager_subscriptions_init()) {
+ ast_log(AST_LOG_ERROR, "Failed to initialize manager subscriptions\n");
+ return -1;
+ }
+ if (manager_channels_init()) {
+ ast_log(AST_LOG_ERROR, "Failed to initialize manager channel handling\n");
+ return -1;
+ }
+ if (manager_mwi_init()) {
+ ast_log(AST_LOG_ERROR, "Failed to initialize manager MWI handling\n");
+ return -1;
+ }
}
if (manager_bridging_init()) {
@@ -8025,8 +8170,6 @@ static int __init_manager(int reload, int by_external_config)
httptimeout = newhttptimeout;
}
- manager_event(EVENT_FLAG_SYSTEM, "Reload", "Module: Manager\r\nStatus: %s\r\nMessage: Manager reload Requested\r\n", manager_enabled ? "Enabled" : "Disabled");
-
ast_tcptls_server_start(&ami_desc);
if (tls_was_enabled && !ami_tls_cfg.enabled) {
ast_tcptls_server_stop(&amis_desc);
diff --git a/main/manager_channels.c b/main/manager_channels.c
index fb579dd95..f3c72ec4c 100644
--- a/main/manager_channels.c
+++ b/main/manager_channels.c
@@ -37,8 +37,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/pbx.h"
#include "asterisk/stasis_channels.h"
-static struct stasis_message_router *channel_state_router;
-
/*** DOCUMENTATION
<managerEvent language="en_US" name="Newchannel">
<managerEventInstance class="EVENT_FLAG_CALL">
@@ -160,12 +158,12 @@ static struct stasis_message_router *channel_state_router;
<synopsis>Raised when a dial action has started.</synopsis>
<syntax>
<xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
- <parameter name="ChannelDest">
+ <parameter name="DestChannel">
</parameter>
- <parameter name="ChannelStateDest">
- <para>A numeric code for the channel's current state, related to ChannelStateDescDest</para>
+ <parameter name="DestChannelState">
+ <para>A numeric code for the channel's current state, related to DestChannelStateDesc</para>
</parameter>
- <parameter name="ChannelStateDescDest">
+ <parameter name="DestChannelStateDesc">
<enumlist>
<enum name="Down"/>
<enum name="Rsrvd"/>
@@ -180,23 +178,23 @@ static struct stasis_message_router *channel_state_router;
<enum name="Unknown"/>
</enumlist>
</parameter>
- <parameter name="CallerIDNumDest">
+ <parameter name="DestCallerIDNum">
</parameter>
- <parameter name="CallerIDNameDest">
+ <parameter name="DestCallerIDName">
</parameter>
- <parameter name="ConnectedLineNumDest">
+ <parameter name="DestConnectedLineNum">
</parameter>
- <parameter name="ConnectedLineNameDest">
+ <parameter name="DestConnectedLineName">
</parameter>
- <parameter name="AccountCodeDest">
+ <parameter name="DestAccountCode">
</parameter>
- <parameter name="ContextDest">
+ <parameter name="DestContext">
</parameter>
- <parameter name="ExtenDest">
+ <parameter name="DestExten">
</parameter>
- <parameter name="PriorityDest">
+ <parameter name="DestPriority">
</parameter>
- <parameter name="UniqueidDest">
+ <parameter name="DestUniqueid">
</parameter>
<parameter name="DialString">
<para>The non-technology specific device being dialed.</para>
@@ -230,11 +228,270 @@ static struct stasis_message_router *channel_state_router;
</see-also>
</managerEventInstance>
</managerEvent>
- ***/
+ <managerEvent language="en_US" name="ChanSpyStart">
+ <managerEventInstance class="EVENT_FLAG_CALL">
+ <synopsis>Raised when one channel begins spying on another channel.</synopsis>
+ <syntax>
+ <parameter name="SpyerChannel">
+ <para>The channel performing the spying.</para>
+ </parameter>
+ <parameter name="SpyerChannelState">
+ <para>A numeric code for the channel's current state, related to SpyerChannelStateDesc</para>
+ </parameter>
+ <parameter name="SpyerChannelStateDesc">
+ <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="SpyerCallerIDNum">
+ </parameter>
+ <parameter name="SpyerCallerIDName">
+ </parameter>
+ <parameter name="SpyerConnectedLineNum">
+ </parameter>
+ <parameter name="SpyerConnectedLineName">
+ </parameter>
+ <parameter name="SpyerAccountCode">
+ </parameter>
+ <parameter name="SpyerContext">
+ </parameter>
+ <parameter name="SpyerExten">
+ </parameter>
+ <parameter name="SpyerPriority">
+ </parameter>
+ <parameter name="SpyerUniqueid">
+ </parameter>
+ <parameter name="SpyeeChannel">
+ <para>The channel being spied upon.</para>
+ </parameter>
+ <parameter name="SpyeeChannelState">
+ <para>A numeric code for the channel's current state, related to SpyeeChannelStateDesc</para>
+ </parameter>
+ <parameter name="SpyeeChannelStateDesc">
+ <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="SpyeeCallerIDNum">
+ </parameter>
+ <parameter name="SpyeeCallerIDName">
+ </parameter>
+ <parameter name="SpyeeConnectedLineNum">
+ </parameter>
+ <parameter name="SpyeeConnectedLineName">
+ </parameter>
+ <parameter name="SpyeeAccountCode">
+ </parameter>
+ <parameter name="SpyeeContext">
+ </parameter>
+ <parameter name="SpyeeExten">
+ </parameter>
+ <parameter name="SpyeePriority">
+ </parameter>
+ <parameter name="SpyeeUniqueid">
+ </parameter>
+ </syntax>
+ <see-also>
+ <ref type="application">ChanSpyStop</ref>
+ </see-also>
+ </managerEventInstance>
+ </managerEvent>
+ <managerEvent language="en_US" name="ChanSpyStop">
+ <managerEventInstance class="EVENT_FLAG_CALL">
+ <synopsis>Raised when a channel has stopped spying.</synopsis>
+ <syntax>
+ <xi:include xpointer="xpointer(/docs/managerEvent[@name='ChanSpyStart']/managerEventInstance/syntax/parameter[contains(@name, 'Spyer')])" />
+ </syntax>
+ <see-also>
+ <ref type="application">ChanSpyStart</ref>
+ </see-also>
+ </managerEventInstance>
+ </managerEvent>
+ <managerEvent language="en_US" name="HangupHandlerRun">
+ <managerEventInstance class="EVENT_FLAG_DIALPLAN">
+ <synopsis>Raised when a hangup handler is about to be called.</synopsis>
+ <syntax>
+ <xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
+ <parameter name="Handler">
+ <para>Hangup handler parameter string passed to the Gosub application.</para>
+ </parameter>
+ </syntax>
+ </managerEventInstance>
+ </managerEvent>
+ <managerEvent language="en_US" name="HangupHandlerPop">
+ <managerEventInstance class="EVENT_FLAG_DIALPLAN">
+ <synopsis>
+ Raised when a hangup handler is removed from the handler stack
+ by the CHANNEL() function.
+ </synopsis>
+ <syntax>
+ <xi:include xpointer="xpointer(/docs/managerEvent[@name='HangupHandlerRun']/managerEventInstance/syntax/parameter)" />
+ </syntax>
+ <see-also>
+ <ref type="managerEvent">HangupHandlerPush</ref>
+ <ref type="function">CHANNEL</ref>
+ </see-also>
+ </managerEventInstance>
+ </managerEvent>
+ <managerEvent language="en_US" name="HangupHandlerPush">
+ <managerEventInstance class="EVENT_FLAG_DIALPLAN">
+ <synopsis>
+ Raised when a hangup handler is added to the handler stack by
+ the CHANNEL() function.
+ </synopsis>
+ <syntax>
+ <xi:include xpointer="xpointer(/docs/managerEvent[@name='HangupHandlerRun']/managerEventInstance/syntax/parameter)" />
+ </syntax>
+ <see-also>
+ <ref type="managerEvent">HangupHandlerPop</ref>
+ <ref type="function">CHANNEL</ref>
+ </see-also>
+ </managerEventInstance>
+ </managerEvent>
+ <managerEvent language="en_US" name="FAXStatus">
+ <managerEventInstance class="EVENT_FLAG_CALL">
+ <synopsis>
+ Raised periodically during a fax transmission.
+ </synopsis>
+ <syntax>
+ <xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
+ <parameter name="Operation">
+ <enumlist>
+ <enum name="gateway"/>
+ <enum name="receive"/>
+ <enum name="send"/>
+ </enumlist>
+ </parameter>
+ <parameter name="Status">
+ <para>A text message describing the current status of the fax</para>
+ </parameter>
+ <xi:include xpointer="xpointer(/docs/managerEvent[@name='ReceiveFAX']/managerEventInstance/syntax/parameter[@name='LocalStationID'])" />
+ <xi:include xpointer="xpointer(/docs/managerEvent[@name='ReceiveFAX']/managerEventInstance/syntax/parameter[@name='FileName'])" />
+ </syntax>
+ </managerEventInstance>
+ </managerEvent>
+ <managerEvent language="en_US" name="ReceiveFAX">
+ <managerEventInstance class="EVENT_FLAG_CALL">
+ <synopsis>
+ Raised when a receive fax operation has completed.
+ </synopsis>
+ <syntax>
+ <xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
+ <parameter name="LocalStationID">
+ <para>The value of the <variable>LOCALSTATIONID</variable> channel variable</para>
+ </parameter>
+ <parameter name="RemoteStationID">
+ <para>The value of the <variable>REMOTESTATIONID</variable> channel variable</para>
+ </parameter>
+ <parameter name="PagesTransferred">
+ <para>The number of pages that have been transferred</para>
+ </parameter>
+ <parameter name="Resolution">
+ <para>The negotiated resolution</para>
+ </parameter>
+ <parameter name="TransferRate">
+ <para>The negotiated transfer rate</para>
+ </parameter>
+ <parameter name="FileName" multiple="yes">
+ <para>The files being affected by the fax operation</para>
+ </parameter>
+ </syntax>
+ </managerEventInstance>
+ </managerEvent>
+ <managerEvent language="en_US" name="SendFAX">
+ <managerEventInstance class="EVENT_FLAG_CALL">
+ <synopsis>
+ Raised when a send fax operation has completed.
+ </synopsis>
+ <syntax>
+ <xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
+ <xi:include xpointer="xpointer(/docs/managerEvent[@name='ReceiveFAX']/managerEventInstance/syntax/parameter)" />
+ </syntax>
+ </managerEventInstance>
+ </managerEvent>
+ <managerEvent language="en_US" name="MusicOnHoldStart">
+ <managerEventInstance class="EVENT_FLAG_CALL">
+ <synopsis>Raised when music on hold has started on a channel.</synopsis>
+ <syntax>
+ <xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
+ <parameter name="Class">
+ <para>The class of music being played on the channel</para>
+ </parameter>
+ </syntax>
+ <see-also>
+ <ref type="managerEvent">MusicOnHoldStop</ref>
+ <ref type="application">MusicOnHold</ref>
+ </see-also>
+ </managerEventInstance>
+ </managerEvent>
+ <managerEvent language="en_US" name="MusicOnHoldStop">
+ <managerEventInstance class="EVENT_FLAG_CALL">
+ <synopsis>Raised when music on hold has stopped on a channel.</synopsis>
+ <syntax>
+ <xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
+ </syntax>
+ <see-also>
+ <ref type="managerEvent">MusicOnHoldStart</ref>
+ <ref type="application">StopMusicOnHold</ref>
+ </see-also>
+ </managerEventInstance>
+ </managerEvent>
+ <managerEvent language="en_US" name="MonitorStart">
+ <managerEventInstance class="EVENT_FLAG_CALL">
+ <synopsis>Raised when monitoring has started on a channel.</synopsis>
+ <syntax>
+ <xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
+ </syntax>
+ <see-also>
+ <ref type="managerEvent">MonitorStop</ref>
+ <ref type="application">Monitor</ref>
+ <ref type="manager">Monitor</ref>
+ </see-also>
+ </managerEventInstance>
+ </managerEvent>
+ <managerEvent language="en_US" name="MonitorStop">
+ <managerEventInstance class="EVENT_FLAG_CALL">
+ <synopsis>Raised when monitoring has stopped on a channel.</synopsis>
+ <syntax>
+ <xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
+ </syntax>
+ <see-also>
+ <ref type="managerEvent">MonitorStart</ref>
+ <ref type="application">StopMonitor</ref>
+ <ref type="manager">StopMonitor</ref>
+ </see-also>
+ </managerEventInstance>
+ </managerEvent>
+***/
+
+/*! \brief The \ref stasis subscription returned by the forwarding of the channel topic
+ * to the manager topic
+ */
+static struct stasis_subscription *topic_forwarder;
-struct ast_str *ast_manager_build_channel_state_string_suffix(
+struct ast_str *ast_manager_build_channel_state_string_prefix(
const struct ast_channel_snapshot *snapshot,
- const char *suffix)
+ const char *prefix)
{
struct ast_str *out = ast_str_create(1024);
int res = 0;
@@ -242,30 +499,30 @@ struct ast_str *ast_manager_build_channel_state_string_suffix(
return NULL;
}
res = ast_str_set(&out, 0,
- "Channel%s: %s\r\n"
- "ChannelState%s: %d\r\n"
- "ChannelStateDesc%s: %s\r\n"
- "CallerIDNum%s: %s\r\n"
- "CallerIDName%s: %s\r\n"
- "ConnectedLineNum%s: %s\r\n"
- "ConnectedLineName%s: %s\r\n"
- "AccountCode%s: %s\r\n"
- "Context%s: %s\r\n"
- "Exten%s: %s\r\n"
- "Priority%s: %d\r\n"
- "Uniqueid%s: %s\r\n",
- suffix, snapshot->name,
- suffix, snapshot->state,
- suffix, ast_state2str(snapshot->state),
- suffix, S_OR(snapshot->caller_number, "<unknown>"),
- suffix, S_OR(snapshot->caller_name, "<unknown>"),
- suffix, S_OR(snapshot->connected_number, "<unknown>"),
- suffix, S_OR(snapshot->connected_name, "<unknown>"),
- suffix, snapshot->accountcode,
- suffix, snapshot->context,
- suffix, snapshot->exten,
- suffix, snapshot->priority,
- suffix, snapshot->uniqueid);
+ "%sChannel: %s\r\n"
+ "%sChannelState: %d\r\n"
+ "%sChannelStateDesc: %s\r\n"
+ "%sCallerIDNum: %s\r\n"
+ "%sCallerIDName: %s\r\n"
+ "%sConnectedLineNum: %s\r\n"
+ "%sConnectedLineName: %s\r\n"
+ "%sAccountCode: %s\r\n"
+ "%sContext: %s\r\n"
+ "%sExten: %s\r\n"
+ "%sPriority: %d\r\n"
+ "%sUniqueid: %s\r\n",
+ prefix, snapshot->name,
+ prefix, snapshot->state,
+ prefix, ast_state2str(snapshot->state),
+ prefix, S_OR(snapshot->caller_number, "<unknown>"),
+ prefix, S_OR(snapshot->caller_name, "<unknown>"),
+ prefix, S_OR(snapshot->connected_number, "<unknown>"),
+ prefix, S_OR(snapshot->connected_name, "<unknown>"),
+ prefix, snapshot->accountcode,
+ prefix, snapshot->context,
+ prefix, snapshot->exten,
+ prefix, snapshot->priority,
+ prefix, snapshot->uniqueid);
if (!res) {
return NULL;
@@ -274,8 +531,8 @@ struct ast_str *ast_manager_build_channel_state_string_suffix(
if (snapshot->manager_vars) {
struct ast_var_t *var;
AST_LIST_TRAVERSE(snapshot->manager_vars, var, entries) {
- ast_str_append(&out, 0, "ChanVariable%s: %s=%s\r\n",
- suffix,
+ ast_str_append(&out, 0, "%sChanVariable: %s=%s\r\n",
+ prefix,
var->name, var->value);
}
}
@@ -286,7 +543,7 @@ struct ast_str *ast_manager_build_channel_state_string_suffix(
struct ast_str *ast_manager_build_channel_state_string(
const struct ast_channel_snapshot *snapshot)
{
- return ast_manager_build_channel_state_string_suffix(snapshot, "");
+ return ast_manager_build_channel_state_string_prefix(snapshot, "");
}
/*! \brief Typedef for callbacks that get called on channel snapshot updates */
@@ -477,38 +734,6 @@ static void channel_varset_cb(void *data, struct stasis_subscription *sub,
variable, value);
}
-/*!
- * \brief Callback used to determine whether a key should be skipped when converting a JSON object to a manager blob
- * \param key Key from JSON blob to be evaluated
- * \retval non-zero if the key should be excluded
- * \retval zero if the key should not be excluded
- */
-typedef int (*key_exclusion_cb)(const char *key);
-
-static struct ast_str *manager_str_from_json_object(struct ast_json *blob, key_exclusion_cb exclusion_cb)
-{
- struct ast_str *output_str = ast_str_create(32);
- struct ast_json_iter *blob_iter = ast_json_object_iter(blob);
- if (!output_str || !blob_iter) {
- return NULL;
- }
-
- do {
- const char *key = ast_json_object_iter_key(blob_iter);
- const char *value = ast_json_string_get(ast_json_object_iter_value(blob_iter));
- if (exclusion_cb && exclusion_cb(key)) {
- continue;
- }
-
- ast_str_append(&output_str, 0, "%s: %s\r\n", key, value);
- if (!output_str) {
- return NULL;
- }
- } while ((blob_iter = ast_json_object_iter_next(blob, blob_iter)));
-
- return output_str;
-}
-
static int userevent_exclusion_cb(const char *key)
{
if (!strcmp("type", key)) {
@@ -529,7 +754,7 @@ static void channel_user_event_cb(void *data, struct stasis_subscription *sub,
const char *eventname;
eventname = ast_json_string_get(ast_json_object_get(obj->blob, "eventname"));
- body = manager_str_from_json_object(obj->blob, userevent_exclusion_cb);
+ body = ast_manager_str_from_json_object(obj->blob, userevent_exclusion_cb);
channel_event_string = ast_manager_build_channel_state_string(obj->snapshot);
if (!channel_event_string || !body) {
@@ -557,6 +782,20 @@ static void channel_user_event_cb(void *data, struct stasis_subscription *sub,
ast_str_buffer(channel_event_string), eventname, ast_str_buffer(body));
}
+static void publish_basic_channel_event(const char *event, int class, struct ast_channel_snapshot *snapshot)
+{
+ RAII_VAR(struct ast_str *, channel_event_string, NULL, ast_free);
+
+ channel_event_string = ast_manager_build_channel_state_string(snapshot);
+ if (!channel_event_string) {
+ return;
+ }
+
+ manager_event(class, event,
+ "%s",
+ ast_str_buffer(channel_event_string));
+}
+
static void channel_hangup_request_cb(void *data,
struct stasis_subscription *sub, struct stasis_topic *topic,
struct stasis_message *message)
@@ -597,6 +836,64 @@ static void channel_hangup_request_cb(void *data,
ast_str_buffer(extra));
}
+static void channel_chanspy_stop_cb(void *data, struct stasis_subscription *sub,
+ struct stasis_topic *topic, struct stasis_message *message)
+{
+ RAII_VAR(struct ast_str *, spyer_channel_string, NULL, ast_free);
+ RAII_VAR(struct ast_channel_snapshot *, spyer, NULL, ao2_cleanup);
+ struct ast_multi_channel_blob *payload = stasis_message_data(message);
+
+ spyer = ast_multi_channel_blob_get_channel(payload, "spyer_channel");
+ if (!spyer) {
+ ast_log(AST_LOG_WARNING, "Received ChanSpy Start event with no spyer channel!\n");
+ return;
+ }
+
+ spyer_channel_string = ast_manager_build_channel_state_string_prefix(spyer, "Spyer");
+ if (!spyer_channel_string) {
+ return;
+ }
+
+ manager_event(EVENT_FLAG_CALL, "ChanSpyStop",
+ "%s",
+ ast_str_buffer(spyer_channel_string));
+}
+
+static void channel_chanspy_start_cb(void *data, struct stasis_subscription *sub,
+ struct stasis_topic *topic, struct stasis_message *message)
+{
+ RAII_VAR(struct ast_str *, spyer_channel_string, NULL, ast_free);
+ RAII_VAR(struct ast_str *, spyee_channel_string, NULL, ast_free);
+ RAII_VAR(struct ast_channel_snapshot *, spyer, NULL, ao2_cleanup);
+ RAII_VAR(struct ast_channel_snapshot *, spyee, NULL, ao2_cleanup);
+ struct ast_multi_channel_blob *payload = stasis_message_data(message);
+
+ spyer = ast_multi_channel_blob_get_channel(payload, "spyer_channel");
+ if (!spyer) {
+ ast_log(AST_LOG_WARNING, "Received ChanSpy Start event with no spyer channel!\n");
+ return;
+ }
+ spyee = ast_multi_channel_blob_get_channel(payload, "spyee_channel");
+ if (!spyee) {
+ ast_log(AST_LOG_WARNING, "Received ChanSpy Start event with no spyee channel!\n");
+ return;
+ }
+
+ spyer_channel_string = ast_manager_build_channel_state_string_prefix(spyer, "Spyer");
+ if (!spyer_channel_string) {
+ return;
+ }
+ spyee_channel_string = ast_manager_build_channel_state_string_prefix(spyee, "Spyee");
+ if (!spyee_channel_string) {
+ return;
+ }
+
+ manager_event(EVENT_FLAG_CALL, "ChanSpyStart",
+ "%s%s",
+ ast_str_buffer(spyer_channel_string),
+ ast_str_buffer(spyee_channel_string));
+}
+
static void channel_dtmf_begin_cb(void *data, struct stasis_subscription *sub,
struct stasis_topic *topic, struct stasis_message *message)
{
@@ -685,6 +982,154 @@ static void channel_dtmf_end_cb(void *data, struct stasis_subscription *sub,
digit, duration_ms, direction);
}
+static void channel_hangup_handler_cb(void *data, struct stasis_subscription *sub,
+ struct stasis_topic *topic, struct stasis_message *message)
+{
+ RAII_VAR(struct ast_str *, channel_event_string, NULL, ast_free);
+ struct ast_channel_blob *payload = stasis_message_data(message);
+ const char *action = ast_json_string_get(ast_json_object_get(payload->blob, "type"));
+ const char *handler = ast_json_string_get(ast_json_object_get(payload->blob, "handler"));
+ const char *event;
+
+ channel_event_string = ast_manager_build_channel_state_string(payload->snapshot);
+
+ if (!channel_event_string) {
+ return;
+ }
+
+ if (!strcmp(action, "type")) {
+ event = "HangupHandlerRun";
+ } else if (!strcmp(action, "type")) {
+ event = "HangupHandlerPop";
+ } else if (!strcmp(action, "type")) {
+ event = "HangupHandlerPush";
+ } else {
+ return;
+ }
+ manager_event(EVENT_FLAG_DIALPLAN, event,
+ "%s"
+ "Handler: %s\r\n",
+ ast_str_buffer(channel_event_string),
+ handler);
+}
+
+static void channel_fax_cb(void *data, struct stasis_subscription *sub,
+ struct stasis_topic *topic, struct stasis_message *message)
+{
+ RAII_VAR(struct ast_str *, channel_event_string, NULL, ast_free);
+ RAII_VAR(struct ast_str *, event_buffer, ast_str_create(256), ast_free);
+ struct ast_channel_blob *payload = stasis_message_data(message);
+ const char *type = ast_json_string_get(ast_json_object_get(payload->blob, "type"));
+ struct ast_json *operation = ast_json_object_get(payload->blob, "operation");
+ struct ast_json *status = ast_json_object_get(payload->blob, "status");
+ struct ast_json *local_station_id = ast_json_object_get(payload->blob, "local_station_id");
+ struct ast_json *remote_station_id = ast_json_object_get(payload->blob, "remote_station_id");
+ struct ast_json *fax_pages = ast_json_object_get(payload->blob, "fax_pages");
+ struct ast_json *fax_resolution = ast_json_object_get(payload->blob, "fax_resolution");
+ struct ast_json *fax_bitrate = ast_json_object_get(payload->blob, "fax_bitrate");
+ struct ast_json *filenames = ast_json_object_get(payload->blob, "filenames");
+ const char *event;
+ size_t array_len;
+ size_t i;
+
+ if (!event_buffer) {
+ return;
+ }
+
+ channel_event_string = ast_manager_build_channel_state_string(payload->snapshot);
+ if (!channel_event_string) {
+ return;
+ }
+
+ if (!strcmp(type, "status")) {
+ event = "FAXStatus";
+ } else if (!strcmp(type, "receive")) {
+ event = "ReceiveFAX";
+ } else if (!strcmp(type, "send")) {
+ event = "SendFAX";
+ } else {
+ return;
+ }
+
+ if (operation) {
+ ast_str_append(&event_buffer, 0, "Operation: %s\r\n", ast_json_string_get(operation));
+ }
+ if (status) {
+ ast_str_append(&event_buffer, 0, "Status: %s\r\n", ast_json_string_get(status));
+ }
+ if (local_station_id) {
+ ast_str_append(&event_buffer, 0, "LocalStationID: %s\r\n", ast_json_string_get(local_station_id));
+ }
+ if (remote_station_id) {
+ ast_str_append(&event_buffer, 0, "RemoteStationID: %s\r\n", ast_json_string_get(remote_station_id));
+ }
+ if (fax_pages) {
+ ast_str_append(&event_buffer, 0, "PagesTransferred: %s\r\n", ast_json_string_get(fax_pages));
+ }
+ if (fax_resolution) {
+ ast_str_append(&event_buffer, 0, "Resolution: %s\r\n", ast_json_string_get(fax_resolution));
+ }
+ if (fax_bitrate) {
+ ast_str_append(&event_buffer, 0, "TransferRate: %s\r\n", ast_json_string_get(fax_bitrate));
+ }
+ if (filenames) {
+ array_len = ast_json_array_size(filenames);
+ for (i = 0; i < array_len; i++) {
+ ast_str_append(&event_buffer, 0, "FileName: %s\r\n", ast_json_string_get(ast_json_array_get(filenames, i)));
+ }
+ }
+
+ manager_event(EVENT_FLAG_CALL, event,
+ "%s"
+ "%s",
+ ast_str_buffer(channel_event_string),
+ ast_str_buffer(event_buffer));
+}
+
+static void channel_moh_start_cb(void *data, struct stasis_subscription *sub,
+ struct stasis_topic *topic, struct stasis_message *message)
+{
+ struct ast_channel_blob *payload = stasis_message_data(message);
+ struct ast_json *blob = payload->blob;
+ RAII_VAR(struct ast_str *, channel_event_string, NULL, ast_free);
+
+ channel_event_string = ast_manager_build_channel_state_string(payload->snapshot);
+ if (!channel_event_string) {
+ return;
+ }
+
+ manager_event(EVENT_FLAG_CALL, "MusicOnHoldStart",
+ "%s"
+ "Class: %s\r\n",
+ ast_str_buffer(channel_event_string),
+ ast_json_string_get(ast_json_object_get(blob, "class")));
+
+}
+
+static void channel_moh_stop_cb(void *data, struct stasis_subscription *sub,
+ struct stasis_topic *topic, struct stasis_message *message)
+{
+ struct ast_channel_blob *payload = stasis_message_data(message);
+
+ publish_basic_channel_event("MusicOnHoldStop", EVENT_FLAG_CALL, payload->snapshot);
+}
+
+static void channel_monitor_start_cb(void *data, struct stasis_subscription *sub,
+ struct stasis_topic *topic, struct stasis_message *message)
+{
+ struct ast_channel_blob *payload = stasis_message_data(message);
+
+ publish_basic_channel_event("MonitorStart", EVENT_FLAG_CALL, payload->snapshot);
+}
+
+static void channel_monitor_stop_cb(void *data, struct stasis_subscription *sub,
+ struct stasis_topic *topic, struct stasis_message *message)
+{
+ struct ast_channel_blob *payload = stasis_message_data(message);
+
+ publish_basic_channel_event("MonitorStop", EVENT_FLAG_CALL, payload->snapshot);
+}
+
/*!
* \brief Callback processing messages for channel dialing
*/
@@ -704,7 +1149,7 @@ static void channel_dial_cb(void *data, struct stasis_subscription *sub,
/* Peer is required - otherwise, who are we dialing? */
ast_assert(peer != NULL);
- peer_event_string = ast_manager_build_channel_state_string_suffix(peer, "Dest");
+ peer_event_string = ast_manager_build_channel_state_string_prefix(peer, "Dest");
if (!peer_event_string) {
return;
}
@@ -737,63 +1182,112 @@ static void channel_dial_cb(void *data, struct stasis_subscription *sub,
static void manager_channels_shutdown(void)
{
- stasis_message_router_unsubscribe_and_join(channel_state_router);
- channel_state_router = NULL;
+ stasis_unsubscribe(topic_forwarder);
+ topic_forwarder = NULL;
}
int manager_channels_init(void)
{
int ret = 0;
+ struct stasis_topic *manager_topic;
+ struct stasis_topic *channel_topic;
+ struct stasis_message_router *message_router;
- if (channel_state_router) {
- /* Already initialized */
- return 0;
+ manager_topic = ast_manager_get_topic();
+ if (!manager_topic) {
+ return -1;
+ }
+ message_router = ast_manager_get_message_router();
+ if (!message_router) {
+ return -1;
+ }
+ channel_topic = stasis_caching_get_topic(ast_channel_topic_all_cached());
+ if (!channel_topic) {
+ return -1;
}
- ast_register_atexit(manager_channels_shutdown);
-
- channel_state_router = stasis_message_router_create(
- stasis_caching_get_topic(ast_channel_topic_all_cached()));
-
- if (!channel_state_router) {
+ topic_forwarder = stasis_forward_all(channel_topic, manager_topic);
+ if (!topic_forwarder) {
return -1;
}
- ret |= stasis_message_router_add(channel_state_router,
+ ast_register_atexit(manager_channels_shutdown);
+
+ ret |= stasis_message_router_add(message_router,
stasis_cache_update_type(),
channel_snapshot_update,
NULL);
- ret |= stasis_message_router_add(channel_state_router,
+ ret |= stasis_message_router_add(message_router,
ast_channel_varset_type(),
channel_varset_cb,
NULL);
- ret |= stasis_message_router_add(channel_state_router,
+ ret |= stasis_message_router_add(message_router,
ast_channel_user_event_type(),
channel_user_event_cb,
NULL);
- ret |= stasis_message_router_add(channel_state_router,
+ ret |= stasis_message_router_add(message_router,
ast_channel_dtmf_begin_type(),
channel_dtmf_begin_cb,
NULL);
- ret |= stasis_message_router_add(channel_state_router,
+ ret |= stasis_message_router_add(message_router,
ast_channel_dtmf_end_type(),
channel_dtmf_end_cb,
NULL);
- ret |= stasis_message_router_add(channel_state_router,
+ ret |= stasis_message_router_add(message_router,
ast_channel_hangup_request_type(),
channel_hangup_request_cb,
NULL);
- ret |= stasis_message_router_add(channel_state_router,
+ ret |= stasis_message_router_add(message_router,
ast_channel_dial_type(),
channel_dial_cb,
NULL);
+ ret |= stasis_message_router_add(message_router,
+ ast_channel_fax_type(),
+ channel_fax_cb,
+ NULL);
+
+ ret |= stasis_message_router_add(message_router,
+ ast_channel_chanspy_start_type(),
+ channel_chanspy_start_cb,
+ NULL);
+
+ ret |= stasis_message_router_add(message_router,
+ ast_channel_chanspy_stop_type(),
+ channel_chanspy_stop_cb,
+ NULL);
+
+ ret |= stasis_message_router_add(message_router,
+ ast_channel_hangup_handler_type(),
+ channel_hangup_handler_cb,
+ NULL);
+
+ ret |= stasis_message_router_add(message_router,
+ ast_channel_moh_start_type(),
+ channel_moh_start_cb,
+ NULL);
+
+ ret |= stasis_message_router_add(message_router,
+ ast_channel_moh_stop_type(),
+ channel_moh_stop_cb,
+ NULL);
+
+ ret |= stasis_message_router_add(message_router,
+ ast_channel_monitor_start_type(),
+ channel_monitor_start_cb,
+ NULL);
+
+ ret |= stasis_message_router_add(message_router,
+ ast_channel_monitor_stop_type(),
+ channel_monitor_stop_cb,
+ NULL);
+
/* If somehow we failed to add any routes, just shut down the whole
* thing and fail it.
*/
diff --git a/main/manager_mwi.c b/main/manager_mwi.c
new file mode 100644
index 000000000..ac629089b
--- /dev/null
+++ b/main/manager_mwi.c
@@ -0,0 +1,202 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2013, Digium, Inc.
+ *
+ * Matt Jordan <mjordan@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief The Asterisk Management Interface - AMI (MWI event handling)
+ *
+ * \author Matt Jordan <mjordan@digium.com>
+ */
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include "asterisk/manager.h"
+#include "asterisk/app.h"
+#include "asterisk/channel.h"
+#include "asterisk/stasis_message_router.h"
+#include "asterisk/stasis.h"
+
+struct stasis_message_router *mwi_state_router;
+
+/*** DOCUMENTATION
+ ***/
+
+/*! \brief The \ref stasis subscription returned by the forwarding of the MWI topic
+ * to the manager topic
+ */
+static struct stasis_subscription *topic_forwarder;
+
+/*! \brief Callback function used by \ref mwi_app_event_cb to weed out "Event" keys */
+static int exclude_event_cb(const char *key)
+{
+ if (!strcmp(key, "Event")) {
+ return -1;
+ }
+ return 0;
+}
+
+/*! \brief Generic MWI event callback used for one-off events from voicemail modules */
+static void mwi_app_event_cb(void *data, struct stasis_subscription *sub,
+ struct stasis_topic *topic,
+ struct stasis_message *message)
+{
+ struct ast_mwi_blob *payload = stasis_message_data(message);
+ RAII_VAR(struct ast_str *, channel_event_string, NULL, ast_free);
+ RAII_VAR(struct ast_str *, event_buffer, NULL, ast_free);
+ struct ast_json *event_json = ast_json_object_get(payload->blob, "Event");
+
+ if (!event_json) {
+ return;
+ }
+
+ if (payload->mwi_state && payload->mwi_state->snapshot) {
+ channel_event_string = ast_manager_build_channel_state_string(payload->mwi_state->snapshot);
+ }
+
+ event_buffer = ast_manager_str_from_json_object(payload->blob, exclude_event_cb);
+ if (!event_buffer) {
+ ast_log(AST_LOG_WARNING, "Failed to create payload for event %s\n", ast_json_string_get(event_json));
+ return;
+ }
+
+ manager_event(EVENT_FLAG_CALL, ast_json_string_get(event_json),
+ "Mailbox: %s\r\n"
+ "%s"
+ "%s",
+ payload->mwi_state ? payload->mwi_state->uniqueid : "Unknown",
+ ast_str_buffer(event_buffer),
+ channel_event_string ? ast_str_buffer(channel_event_string) : "");
+}
+
+static void mwi_update_cb(void *data, struct stasis_subscription *sub,
+ struct stasis_topic *topic,
+ struct stasis_message *message)
+{
+ struct ast_mwi_state *mwi_state;
+ RAII_VAR(struct ast_str *, channel_event_string, NULL, ast_free);
+
+ if (ast_mwi_state_type() != stasis_message_type(message)) {
+ return;
+ }
+
+ mwi_state = stasis_message_data(message);
+ if (!mwi_state) {
+ return;
+ }
+
+ if (mwi_state->snapshot) {
+ channel_event_string = ast_manager_build_channel_state_string(mwi_state->snapshot);
+ }
+
+ /*** DOCUMENTATION
+ <managerEventInstance>
+ <synopsis>Raised when the state of messages in a voicemail mailbox
+ has changed or when a channel has finished interacting with a
+ mailbox.</synopsis>
+ <syntax>
+ <xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
+ <parameter name="Mailbox">
+ <para>The mailbox with the new message, specified as <literal>mailbox</literal>@<literal>context</literal></para>
+ </parameter>
+ <parameter name="Waiting">
+ <para>Whether or not the mailbox has messages waiting for it.</para>
+ </parameter>
+ <parameter name="New">
+ <para>The number of new messages.</para>
+ </parameter>
+ <parameter name="Old">
+ <para>The number of old messages.</para>
+ </parameter>
+ </syntax>
+ <description>
+ <note><para>The Channel related parameters are only present if a
+ channel was involved in the manipulation of a mailbox. If no
+ channel is involved, the parameters are not included with the
+ event.</para>
+ </note>
+ </description>
+ </managerEventInstance>
+ ***/
+ manager_event(EVENT_FLAG_CALL, "MessageWaiting",
+ "%s"
+ "Mailbox: %s\r\n"
+ "Waiting: %d\r\n"
+ "New: %d\r\n"
+ "Old: %d\r\n",
+ AS_OR(channel_event_string, ""),
+ mwi_state->uniqueid,
+ ast_app_has_voicemail(mwi_state->uniqueid, NULL),
+ mwi_state->new_msgs,
+ mwi_state->old_msgs);
+}
+
+static void manager_mwi_shutdown(void)
+{
+ stasis_unsubscribe(topic_forwarder);
+ topic_forwarder = NULL;
+}
+
+int manager_mwi_init(void)
+{
+ int ret = 0;
+ struct stasis_topic *manager_topic;
+ struct stasis_topic *mwi_topic;
+ struct stasis_message_router *message_router;
+
+ manager_topic = ast_manager_get_topic();
+ if (!manager_topic) {
+ return -1;
+ }
+ message_router = ast_manager_get_message_router();
+ if (!message_router) {
+ return -1;
+ }
+ mwi_topic = ast_mwi_topic_all();
+ if (!mwi_topic) {
+ return -1;
+ }
+
+ topic_forwarder = stasis_forward_all(mwi_topic, manager_topic);
+ if (!topic_forwarder) {
+ return -1;
+ }
+
+ ast_register_atexit(manager_mwi_shutdown);
+
+ ret |= stasis_message_router_add(message_router,
+ ast_mwi_state_type(),
+ mwi_update_cb,
+ NULL);
+
+ ret |= stasis_message_router_add(message_router,
+ ast_mwi_vm_app_type(),
+ mwi_app_event_cb,
+ NULL);
+
+ /* If somehow we failed to add any routes, just shut down the whole
+ * thing and fail it.
+ */
+ if (ret) {
+ manager_mwi_shutdown();
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/main/pbx.c b/main/pbx.c
index 8408048f2..1c26a9c10 100644
--- a/main/pbx.c
+++ b/main/pbx.c
@@ -5769,6 +5769,30 @@ void ast_pbx_h_exten_run(struct ast_channel *chan, const char *context)
ast_channel_unlock(chan);
}
+/*!
+ * \internal
+ * \brief Publish a hangup handler related message to \ref stasis
+ */
+static void publish_hangup_handler_message(const char *action, struct ast_channel *chan, const char *handler)
+{
+ RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
+ RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
+
+ blob = ast_json_pack("{s: s, s: s}",
+ "type", action,
+ "handler", S_OR(handler, ""));
+ if (!blob) {
+ return;
+ }
+
+ message = ast_channel_blob_create(chan, ast_channel_hangup_handler_type(), blob);
+ if (!message) {
+ return;
+ }
+
+ stasis_publish(ast_channel_topic(chan), message);
+}
+
int ast_pbx_hangup_handler_run(struct ast_channel *chan)
{
struct ast_hangup_handler_list *handlers;
@@ -5798,23 +5822,7 @@ int ast_pbx_hangup_handler_run(struct ast_channel *chan)
break;
}
- /*** DOCUMENTATION
- <managerEventInstance>
- <synopsis>Raised when a hangup handler is about to be called.</synopsis>
- <syntax>
- <parameter name="Handler">
- <para>Hangup handler parameter string passed to the Gosub application.</para>
- </parameter>
- </syntax>
- </managerEventInstance>
- ***/
- manager_event(EVENT_FLAG_DIALPLAN, "HangupHandlerRun",
- "Channel: %s\r\n"
- "Uniqueid: %s\r\n"
- "Handler: %s\r\n",
- ast_channel_name(chan),
- ast_channel_uniqueid(chan),
- h_handler->args);
+ publish_hangup_handler_message("run", chan, h_handler->args);
ast_channel_unlock(chan);
ast_app_exec_sub(NULL, chan, h_handler->args, 1);
@@ -5859,30 +5867,7 @@ int ast_pbx_hangup_handler_pop(struct ast_channel *chan)
handlers = ast_channel_hangup_handlers(chan);
h_handler = AST_LIST_REMOVE_HEAD(handlers, node);
if (h_handler) {
- /*** DOCUMENTATION
- <managerEventInstance>
- <synopsis>
- Raised when a hangup handler is removed from the handler
- stack by the CHANNEL() function.
- </synopsis>
- <syntax>
- <parameter name="Handler">
- <para>Hangup handler parameter string passed to the Gosub application.</para>
- </parameter>
- </syntax>
- <see-also>
- <ref type="managerEvent">HangupHandlerPush</ref>
- <ref type="function">CHANNEL</ref>
- </see-also>
- </managerEventInstance>
- ***/
- manager_event(EVENT_FLAG_DIALPLAN, "HangupHandlerPop",
- "Channel: %s\r\n"
- "Uniqueid: %s\r\n"
- "Handler: %s\r\n",
- ast_channel_name(chan),
- ast_channel_uniqueid(chan),
- h_handler->args);
+ publish_hangup_handler_message("pop", chan, h_handler->args);
}
ast_channel_unlock(chan);
if (h_handler) {
@@ -5918,32 +5903,7 @@ void ast_pbx_hangup_handler_push(struct ast_channel *chan, const char *handler)
handlers = ast_channel_hangup_handlers(chan);
AST_LIST_INSERT_HEAD(handlers, h_handler, node);
-
- /*** DOCUMENTATION
- <managerEventInstance>
- <synopsis>
- Raised when a hangup handler is added to the handler
- stack by the CHANNEL() function.
- </synopsis>
- <syntax>
- <parameter name="Handler">
- <para>Hangup handler parameter string passed to the Gosub application.</para>
- </parameter>
- </syntax>
- <see-also>
- <ref type="managerEvent">HangupHandlerPop</ref>
- <ref type="function">CHANNEL</ref>
- </see-also>
- </managerEventInstance>
- ***/
- manager_event(EVENT_FLAG_DIALPLAN, "HangupHandlerPush",
- "Channel: %s\r\n"
- "Uniqueid: %s\r\n"
- "Handler: %s\r\n",
- ast_channel_name(chan),
- ast_channel_uniqueid(chan),
- h_handler->args);
-
+ publish_hangup_handler_message("push", chan, h_handler->args);
ast_channel_unlock(chan);
}
diff --git a/main/stasis_channels.c b/main/stasis_channels.c
index f8c9be327..d3c543ac5 100644
--- a/main/stasis_channels.c
+++ b/main/stasis_channels.c
@@ -48,6 +48,14 @@ STASIS_MESSAGE_TYPE_DEFN(ast_channel_user_event_type);
STASIS_MESSAGE_TYPE_DEFN(ast_channel_hangup_request_type);
STASIS_MESSAGE_TYPE_DEFN(ast_channel_dtmf_begin_type);
STASIS_MESSAGE_TYPE_DEFN(ast_channel_dtmf_end_type);
+STASIS_MESSAGE_TYPE_DEFN(ast_channel_chanspy_start_type);
+STASIS_MESSAGE_TYPE_DEFN(ast_channel_chanspy_stop_type);
+STASIS_MESSAGE_TYPE_DEFN(ast_channel_fax_type);
+STASIS_MESSAGE_TYPE_DEFN(ast_channel_hangup_handler_type);
+STASIS_MESSAGE_TYPE_DEFN(ast_channel_moh_start_type);
+STASIS_MESSAGE_TYPE_DEFN(ast_channel_moh_stop_type);
+STASIS_MESSAGE_TYPE_DEFN(ast_channel_monitor_start_type);
+STASIS_MESSAGE_TYPE_DEFN(ast_channel_monitor_stop_type);
/*! @} */
/*! \brief Topic for all channels */
@@ -150,28 +158,6 @@ struct ast_channel_snapshot *ast_channel_snapshot_create(struct ast_channel *cha
return snapshot;
}
-struct ast_channel_snapshot *ast_channel_snapshot_get_latest(
- const char *uniqueid)
-{
- RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
- struct ast_channel_snapshot *snapshot;
-
- msg = stasis_cache_get(ast_channel_topic_all_cached(),
- ast_channel_snapshot_type(), uniqueid);
-
- if (!msg) {
- return NULL;
- }
-
- snapshot = stasis_message_data(msg);
- if (!snapshot) {
- return NULL;
- }
-
- ao2_ref(snapshot, +1);
- return snapshot;
-}
-
static void publish_message_for_channel_topics(struct stasis_message *message, struct ast_channel *chan)
{
if (chan) {
@@ -230,12 +216,13 @@ void ast_channel_publish_dial(struct ast_channel *caller, struct ast_channel *pe
publish_message_for_channel_topics(msg, caller);
}
-static struct stasis_message *channel_blob_create(
- struct ast_channel_snapshot *snapshot,
- struct stasis_message_type *type, struct ast_json *blob)
+static struct stasis_message *create_channel_blob_message(struct ast_channel_snapshot *snapshot,
+ struct stasis_message_type *type,
+ struct ast_json *blob)
+
{
- RAII_VAR(struct ast_channel_blob *, obj, NULL, ao2_cleanup);
RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
+ RAII_VAR(struct ast_channel_blob *, obj, NULL, ao2_cleanup);
if (blob == NULL) {
blob = ast_json_null();
@@ -247,10 +234,9 @@ static struct stasis_message *channel_blob_create(
}
if (snapshot) {
- ao2_ref(snapshot, +1);
obj->snapshot = snapshot;
+ ao2_ref(obj->snapshot, +1);
}
-
obj->blob = ast_json_ref(blob);
msg = stasis_message_create(type, obj);
@@ -262,33 +248,27 @@ static struct stasis_message *channel_blob_create(
return msg;
}
-struct stasis_message *ast_channel_blob_create(struct ast_channel *chan,
- struct stasis_message_type *type, struct ast_json *blob)
+struct stasis_message *ast_channel_cached_blob_create(struct ast_channel *chan,
+ struct stasis_message_type *type,
+ struct ast_json *blob)
{
- RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
-
- if (chan != NULL) {
- snapshot = ast_channel_snapshot_create(chan);
- if (snapshot == NULL) {
- return NULL;
- }
- }
+ RAII_VAR(struct ast_channel_snapshot *, snapshot,
+ ast_channel_snapshot_get_latest(ast_channel_uniqueid(chan)),
+ ao2_cleanup);
- return channel_blob_create(snapshot, type, blob);
+ return create_channel_blob_message(snapshot, type, blob);
}
-struct stasis_message *ast_channel_blob_create_from_cache(
- const char *uniqueid, struct stasis_message_type *type,
- struct ast_json *blob)
+struct stasis_message *ast_channel_blob_create(struct ast_channel *chan,
+ struct stasis_message_type *type, struct ast_json *blob)
{
RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
- snapshot = ast_channel_snapshot_get_latest(uniqueid);
- if (snapshot == NULL) {
- return NULL;
+ if (chan) {
+ snapshot = ast_channel_snapshot_create(chan);
}
- return channel_blob_create(snapshot, type, blob);
+ return create_channel_blob_message(snapshot, type, blob);
}
/*! \brief A channel snapshot wrapper object used in \ref ast_multi_channel_blob objects */
@@ -362,6 +342,28 @@ struct ast_multi_channel_blob *ast_multi_channel_blob_create(struct ast_json *bl
return obj;
}
+struct ast_channel_snapshot *ast_channel_snapshot_get_latest(const char *uniqueid)
+{
+ RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
+ struct ast_channel_snapshot *snapshot;
+
+ ast_assert(!ast_strlen_zero(uniqueid));
+
+ message = stasis_cache_get(ast_channel_topic_all_cached(),
+ ast_channel_snapshot_type(),
+ uniqueid);
+ if (!message) {
+ return NULL;
+ }
+
+ snapshot = stasis_message_data(message);
+ if (!snapshot) {
+ return NULL;
+ }
+ ao2_ref(snapshot, +1);
+ return snapshot;
+}
+
static void channel_role_snapshot_dtor(void *obj)
{
struct channel_role_snapshot *role_snapshot = obj;
@@ -459,7 +461,6 @@ void ast_channel_publish_snapshot(struct ast_channel *chan)
stasis_publish(ast_channel_topic(chan), message);
}
-
void ast_channel_publish_varset(struct ast_channel *chan, const char *name, const char *value)
{
RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
@@ -584,6 +585,14 @@ void ast_stasis_channels_shutdown(void)
STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_hangup_request_type);
STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_dtmf_begin_type);
STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_dtmf_end_type);
+ STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_chanspy_start_type);
+ STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_chanspy_stop_type);
+ STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_fax_type);
+ STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_hangup_handler_type);
+ STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_moh_start_type);
+ STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_moh_stop_type);
+ STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_monitor_start_type);
+ STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_monitor_stop_type);
}
void ast_stasis_channels_init(void)
@@ -595,7 +604,14 @@ void ast_stasis_channels_init(void)
STASIS_MESSAGE_TYPE_INIT(ast_channel_hangup_request_type);
STASIS_MESSAGE_TYPE_INIT(ast_channel_dtmf_begin_type);
STASIS_MESSAGE_TYPE_INIT(ast_channel_dtmf_end_type);
-
+ STASIS_MESSAGE_TYPE_INIT(ast_channel_chanspy_start_type);
+ STASIS_MESSAGE_TYPE_INIT(ast_channel_chanspy_stop_type);
+ STASIS_MESSAGE_TYPE_INIT(ast_channel_fax_type);
+ STASIS_MESSAGE_TYPE_INIT(ast_channel_hangup_handler_type);
+ STASIS_MESSAGE_TYPE_INIT(ast_channel_moh_start_type);
+ STASIS_MESSAGE_TYPE_INIT(ast_channel_moh_stop_type);
+ STASIS_MESSAGE_TYPE_INIT(ast_channel_monitor_start_type);
+ STASIS_MESSAGE_TYPE_INIT(ast_channel_monitor_stop_type);
channel_topic_all = stasis_topic_create("ast_channel_topic_all");
channel_topic_all_cached = stasis_caching_topic_create(channel_topic_all, channel_snapshot_get_id);
}
diff --git a/res/parking/parking_manager.c b/res/parking/parking_manager.c
index d6a05573f..697468eb3 100644
--- a/res/parking/parking_manager.c
+++ b/res/parking/parking_manager.c
@@ -277,14 +277,14 @@ static struct ast_str *manager_build_parked_call_string(const struct ast_parked_
return NULL;
}
- parkee_string = ast_manager_build_channel_state_string_suffix(payload->parkee, "Parkee");
+ parkee_string = ast_manager_build_channel_state_string_prefix(payload->parkee, "Parkee");
if (payload->parker) {
- parker_string = ast_manager_build_channel_state_string_suffix(payload->parker, "Parker");
+ parker_string = ast_manager_build_channel_state_string_prefix(payload->parker, "Parker");
}
if (payload->retriever) {
- retriever_string = ast_manager_build_channel_state_string_suffix(payload->retriever, "Retriever");
+ retriever_string = ast_manager_build_channel_state_string_prefix(payload->retriever, "Retriever");
}
ast_str_set(&out, 0,
diff --git a/res/res_fax.c b/res/res_fax.c
index 9afad4a19..4b8c9d7ca 100644
--- a/res/res_fax.c
+++ b/res/res_fax.c
@@ -83,11 +83,12 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/file.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
-#include "asterisk/manager.h"
#include "asterisk/dsp.h"
#include "asterisk/indications.h"
#include "asterisk/ast_version.h"
#include "asterisk/translate.h"
+#include "asterisk/stasis.h"
+#include "asterisk/stasis_channels.h"
/*** DOCUMENTATION
<application name="ReceiveFAX" language="en_US" module="res_fax">
@@ -384,12 +385,6 @@ AST_APP_OPTIONS(fax_exec_options, BEGIN_OPTIONS
AST_APP_OPTION('z', OPT_REQUEST_T38),
END_OPTIONS);
-struct manager_event_info {
- char context[AST_MAX_CONTEXT];
- char exten[AST_MAX_EXTENSION];
- char cid[128];
-};
-
static void debug_check_frame_for_silence(struct ast_fax_session *s, unsigned int c2s, struct ast_frame *frame)
{
struct debug_info_history *history = c2s ? &s->debug_info->c2s : &s->debug_info->s2c;
@@ -1091,13 +1086,39 @@ static struct ast_fax_session *fax_session_new(struct ast_fax_session_details *d
return s;
}
-static void get_manager_event_info(struct ast_channel *chan, struct manager_event_info *info)
+/*!
+ * \internal
+ * \brief Convert the filenames in a fax session into a JSON array
+ * \retval NULL on error
+ * \retval A \ref ast_json array on success
+ */
+static struct ast_json *generate_filenames_json(struct ast_fax_session_details *details)
{
- pbx_substitute_variables_helper(chan, "${CONTEXT}", info->context, sizeof(info->context));
- pbx_substitute_variables_helper(chan, "${EXTEN}", info->exten, sizeof(info->exten));
- pbx_substitute_variables_helper(chan, "${CALLERID(num)}", info->cid, sizeof(info->cid));
-}
+ RAII_VAR(struct ast_json *, json_array, ast_json_array_create(), ast_json_unref);
+ struct ast_fax_document *doc;
+
+ if (!details || !json_array) {
+ return NULL;
+ }
+
+ /* don't process empty lists */
+ if (AST_LIST_EMPTY(&details->documents)) {
+ return NULL;
+ }
+
+ AST_LIST_TRAVERSE(&details->documents, doc, next) {
+ struct ast_json *entry = ast_json_string_create(doc->filename);
+ if (!entry) {
+ return NULL;
+ }
+ if (ast_json_array_append(json_array, entry)) {
+ return NULL;
+ }
+ }
+ ast_json_ref(json_array);
+ return json_array;
+}
/* \brief Generate a string of filenames using the given prefix and separator.
* \param details the fax session details
@@ -1149,39 +1170,39 @@ static char *generate_filenames_string(struct ast_fax_session_details *details,
/*! \brief send a FAX status manager event */
static int report_fax_status(struct ast_channel *chan, struct ast_fax_session_details *details, const char *status)
{
- char *filenames = generate_filenames_string(details, "FileName: ", "\r\n");
+ RAII_VAR(struct ast_json *, json_object, NULL, ast_json_unref);
+ RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
+ RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
+ struct ast_json *json_filenames = NULL;
- ast_channel_lock(chan);
- if (details->option.statusevents) {
- struct manager_event_info info;
-
- get_manager_event_info(chan, &info);
- manager_event(EVENT_FLAG_CALL,
- "FAXStatus",
- "Operation: %s\r\n"
- "Status: %s\r\n"
- "Channel: %s\r\n"
- "Context: %s\r\n"
- "Exten: %s\r\n"
- "CallerID: %s\r\n"
- "LocalStationID: %s\r\n"
- "%s%s",
- (details->caps & AST_FAX_TECH_GATEWAY) ? "gateway" : (details->caps & AST_FAX_TECH_RECEIVE) ? "receive" : "send",
- status,
- ast_channel_name(chan),
- info.context,
- info.exten,
- info.cid,
- details->localstationid,
- S_OR(filenames, ""),
- filenames ? "\r\n" : "");
+ if (!details->option.statusevents) {
+ return 0;
}
- ast_channel_unlock(chan);
- if (filenames) {
- ast_free(filenames);
+ json_filenames = generate_filenames_json(details);
+ if (!json_filenames) {
+ return -1;
+ }
+
+ json_object = ast_json_pack("{s: s, s: s, s: s, s: s, s: s, s: o}",
+ "type", "status",
+ "operation", (details->caps & AST_FAX_TECH_GATEWAY) ? "gateway" : (details->caps & AST_FAX_TECH_RECEIVE) ? "receive" : "send",
+ "status", status,
+ "local_station_id", details->localstationid,
+ "filenames", json_filenames);
+ if (!json_object) {
+ return -1;
}
+ {
+ SCOPED_CHANNELLOCK(lock, chan);
+
+ message = ast_channel_cached_blob_create(chan, ast_channel_fax_type(), json_object);
+ if (!message) {
+ return -1;
+ }
+ stasis_publish(ast_channel_topic(chan), message);
+ }
return 0;
}
@@ -1738,13 +1759,53 @@ static int receivefax_t38_init(struct ast_channel *chan, struct ast_fax_session_
return 0;
}
+/*! \brief Report on the final state of a receive fax operation
+ * \note This will lock the \ref ast_channel
+ */
+static int report_receive_fax_status(struct ast_channel *chan, const char *filename)
+{
+ RAII_VAR(struct ast_json *, json_object, NULL, ast_json_unref);
+ RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
+ RAII_VAR(struct ast_json *, json_array, ast_json_array_create(), ast_json_unref);
+ struct ast_json *json_filename = ast_json_string_create(filename);
+
+ if (!json_array || !json_filename) {
+ return -1;
+ }
+ ast_json_array_append(json_array, json_filename);
+
+ {
+ SCOPED_CHANNELLOCK(lock, chan);
+
+ json_object = ast_json_pack("s: s, s: s, s: s, s: s, s: s, s: s, s: s, s: o",
+ "type", "receive"
+ "remote_station_id", S_OR(pbx_builtin_getvar_helper(chan, "REMOTESTATIONID"), ""),
+ "local_station_id", S_OR(pbx_builtin_getvar_helper(chan, "LOCALSTATIONID"), ""),
+ "fax_pages", S_OR(pbx_builtin_getvar_helper(chan, "FAXPAGES"), ""),
+ "fax_resolution", S_OR(pbx_builtin_getvar_helper(chan, "FAXRESOLUTION"), ""),
+ "fax_bitrate", S_OR(pbx_builtin_getvar_helper(chan, "FAXBITRATE"), ""),
+ "filenames", json_array);
+ if (!json_object) {
+ return -1;
+ }
+
+ message = ast_channel_cached_blob_create(chan, ast_channel_fax_type(), json_object);
+ if (!message) {
+ return -1;
+ }
+
+ stasis_publish(ast_channel_topic(chan), message);
+ }
+ return 0;
+}
+
/*! \brief initiate a receive FAX session */
static int receivefax_exec(struct ast_channel *chan, const char *data)
{
char *parse, modems[128] = "";
int channel_alive;
- struct ast_fax_session_details *details;
- struct ast_fax_session *s;
+ RAII_VAR(struct ast_fax_session_details *, details, NULL, ao2_cleanup);
+ RAII_VAR(struct ast_fax_session *, s, NULL, ao2_cleanup);
struct ast_fax_tech_token *token = NULL;
struct ast_fax_document *doc;
AST_DECLARE_APP_ARGS(args,
@@ -1752,7 +1813,6 @@ static int receivefax_exec(struct ast_channel *chan, const char *data)
AST_APP_ARG(options);
);
struct ast_flags opts = { 0, };
- struct manager_event_info info;
enum ast_t38_state t38state;
/* initialize output channel variables */
@@ -1780,7 +1840,6 @@ static int receivefax_exec(struct ast_channel *chan, const char *data)
ast_string_field_set(details, resultstr, "can't receive a fax on a channel with a T.38 gateway");
set_channel_variables(chan, details);
ast_log(LOG_ERROR, "executing ReceiveFAX on a channel with a T.38 Gateway is not supported\n");
- ao2_ref(details, -1);
return -1;
}
@@ -1789,7 +1848,6 @@ static int receivefax_exec(struct ast_channel *chan, const char *data)
ast_string_field_set(details, resultstr, "maxrate is less than minrate");
set_channel_variables(chan, details);
ast_log(LOG_ERROR, "maxrate %d is less than minrate %d\n", details->maxrate, details->minrate);
- ao2_ref(details, -1);
return -1;
}
@@ -1799,7 +1857,6 @@ static int receivefax_exec(struct ast_channel *chan, const char *data)
ast_string_field_set(details, error, "INVALID_ARGUMENTS");
ast_string_field_set(details, resultstr, "incompatible 'modems' and 'minrate' settings");
set_channel_variables(chan, details);
- ao2_ref(details, -1);
return -1;
}
@@ -1809,7 +1866,6 @@ static int receivefax_exec(struct ast_channel *chan, const char *data)
ast_string_field_set(details, error, "INVALID_ARGUMENTS");
ast_string_field_set(details, resultstr, "incompatible 'modems' and 'maxrate' settings");
set_channel_variables(chan, details);
- ao2_ref(details, -1);
return -1;
}
@@ -1818,7 +1874,6 @@ static int receivefax_exec(struct ast_channel *chan, const char *data)
ast_string_field_set(details, resultstr, "invalid arguments");
set_channel_variables(chan, details);
ast_log(LOG_WARNING, "%s requires an argument (filename[,options])\n", app_receivefax);
- ao2_ref(details, -1);
return -1;
}
parse = ast_strdupa(data);
@@ -1829,7 +1884,6 @@ static int receivefax_exec(struct ast_channel *chan, const char *data)
ast_string_field_set(details, error, "INVALID_ARGUMENTS");
ast_string_field_set(details, resultstr, "invalid arguments");
set_channel_variables(chan, details);
- ao2_ref(details, -1);
return -1;
}
if (ast_strlen_zero(args.filename)) {
@@ -1837,7 +1891,6 @@ static int receivefax_exec(struct ast_channel *chan, const char *data)
ast_string_field_set(details, resultstr, "invalid arguments");
set_channel_variables(chan, details);
ast_log(LOG_WARNING, "%s requires an argument (filename[,options])\n", app_receivefax);
- ao2_ref(details, -1);
return -1;
}
@@ -1847,7 +1900,6 @@ static int receivefax_exec(struct ast_channel *chan, const char *data)
ast_string_field_set(details, resultstr, "invalid arguments");
set_channel_variables(chan, details);
ast_log(LOG_WARNING, "%s does not support polling\n", app_receivefax);
- ao2_ref(details, -1);
return -1;
}
@@ -1861,7 +1913,6 @@ static int receivefax_exec(struct ast_channel *chan, const char *data)
ast_string_field_set(details, resultstr, "error allocating memory");
set_channel_variables(chan, details);
ast_log(LOG_ERROR, "System cannot provide memory for session requirements.\n");
- ao2_ref(details, -1);
return -1;
}
@@ -1894,7 +1945,6 @@ static int receivefax_exec(struct ast_channel *chan, const char *data)
ast_string_field_set(details, resultstr, "error reserving fax session");
set_channel_variables(chan, details);
ast_log(LOG_ERROR, "Unable to reserve FAX session.\n");
- ao2_ref(details, -1);
return -1;
}
@@ -1905,8 +1955,6 @@ static int receivefax_exec(struct ast_channel *chan, const char *data)
set_channel_variables(chan, details);
ast_log(LOG_WARNING, "Channel '%s' failed answer attempt.\n", ast_channel_name(chan));
fax_session_release(s, token);
- ao2_ref(s, -1);
- ao2_ref(details, -1);
return -1;
}
}
@@ -1917,8 +1965,6 @@ static int receivefax_exec(struct ast_channel *chan, const char *data)
ast_string_field_set(details, resultstr, "error negotiating T.38");
set_channel_variables(chan, details);
fax_session_release(s, token);
- ao2_ref(s, -1);
- ao2_ref(details, -1);
return -1;
}
} else {
@@ -1931,8 +1977,6 @@ static int receivefax_exec(struct ast_channel *chan, const char *data)
ast_string_field_set(details, resultstr, "error negotiating T.38");
set_channel_variables(chan, details);
fax_session_release(s, token);
- ao2_ref(s, -1);
- ao2_ref(details, -1);
ast_log(LOG_ERROR, "error initializing channel '%s' in T.38 mode\n", ast_channel_name(chan));
return -1;
}
@@ -1948,36 +1992,9 @@ static int receivefax_exec(struct ast_channel *chan, const char *data)
}
}
- /* send out the AMI completion event */
- ast_channel_lock(chan);
-
- get_manager_event_info(chan, &info);
- manager_event(EVENT_FLAG_CALL,
- "ReceiveFAX",
- "Channel: %s\r\n"
- "Context: %s\r\n"
- "Exten: %s\r\n"
- "CallerID: %s\r\n"
- "RemoteStationID: %s\r\n"
- "LocalStationID: %s\r\n"
- "PagesTransferred: %s\r\n"
- "Resolution: %s\r\n"
- "TransferRate: %s\r\n"
- "FileName: %s\r\n",
- ast_channel_name(chan),
- info.context,
- info.exten,
- info.cid,
- S_OR(pbx_builtin_getvar_helper(chan, "REMOTESTATIONID"), ""),
- S_OR(pbx_builtin_getvar_helper(chan, "LOCALSTATIONID"), ""),
- S_OR(pbx_builtin_getvar_helper(chan, "FAXPAGES"), ""),
- S_OR(pbx_builtin_getvar_helper(chan, "FAXRESOLUTION"), ""),
- S_OR(pbx_builtin_getvar_helper(chan, "FAXBITRATE"), ""),
- args.filename);
- ast_channel_unlock(chan);
-
- ao2_ref(s, -1);
- ao2_ref(details, -1);
+ if (report_receive_fax_status(chan, args.filename)) {
+ ast_log(AST_LOG_ERROR, "Error publishing ReceiveFax status message\n");
+ }
/* If the channel hungup return -1; otherwise, return 0 to continue in the dialplan */
return (!channel_alive) ? -1 : 0;
@@ -2223,14 +2240,53 @@ static int sendfax_t38_init(struct ast_channel *chan, struct ast_fax_session_det
return 0;
}
+/*!
+ * \brief Report on the status of a completed fax send attempt
+ * \note This will lock the \ref ast_channel
+ */
+static int report_send_fax_status(struct ast_channel *chan, struct ast_fax_session_details *details)
+{
+ RAII_VAR(struct ast_json *, json_obj, NULL, ao2_cleanup);
+ RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
+ struct ast_json *json_filenames;
+
+ json_filenames = generate_filenames_json(details);
+ if (!json_filenames) {
+ return -1;
+ }
+
+ {
+ SCOPED_CHANNELLOCK(lock, chan);
+ json_obj = ast_json_pack("{s: s, s: s, s: s, s: s, s: s, s: s, s: s, s: o}",
+ "type", "send"
+ "remote_station_id", S_OR(pbx_builtin_getvar_helper(chan, "REMOTESTATIONID"), ""),
+ "local_station_id", S_OR(pbx_builtin_getvar_helper(chan, "LOCALSTATIONID"), ""),
+ "fax_pages", S_OR(pbx_builtin_getvar_helper(chan, "FAXPAGES"), ""),
+ "fax_resolution", S_OR(pbx_builtin_getvar_helper(chan, "FAXRESOLUTION"), ""),
+ "fax_bitrate", S_OR(pbx_builtin_getvar_helper(chan, "FAXBITRATE"), ""),
+ "filenames", json_filenames);
+ if (!json_obj) {
+ return -1;
+ }
+
+ message = ast_channel_cached_blob_create(chan, ast_channel_fax_type(), json_obj);
+ if (!message) {
+ return -1;
+ }
+ stasis_publish(ast_channel_topic(chan), message);
+ }
+ return 0;
+}
+
+
/*! \brief initiate a send FAX session */
static int sendfax_exec(struct ast_channel *chan, const char *data)
{
char *parse, *filenames, *c, modems[128] = "";
int channel_alive, file_count;
- struct ast_fax_session_details *details;
- struct ast_fax_session *s;
+ RAII_VAR(struct ast_fax_session_details *, details, NULL, ao2_cleanup);
+ RAII_VAR(struct ast_fax_session *, s, NULL, ao2_cleanup);
struct ast_fax_tech_token *token = NULL;
struct ast_fax_document *doc;
AST_DECLARE_APP_ARGS(args,
@@ -2238,7 +2294,6 @@ static int sendfax_exec(struct ast_channel *chan, const char *data)
AST_APP_ARG(options);
);
struct ast_flags opts = { 0, };
- struct manager_event_info info;
enum ast_t38_state t38state;
/* initialize output channel variables */
@@ -2266,7 +2321,6 @@ static int sendfax_exec(struct ast_channel *chan, const char *data)
ast_string_field_set(details, resultstr, "can't send a fax on a channel with a T.38 gateway");
set_channel_variables(chan, details);
ast_log(LOG_ERROR, "executing SendFAX on a channel with a T.38 Gateway is not supported\n");
- ao2_ref(details, -1);
return -1;
}
@@ -2275,7 +2329,6 @@ static int sendfax_exec(struct ast_channel *chan, const char *data)
ast_string_field_set(details, resultstr, "maxrate is less than minrate");
set_channel_variables(chan, details);
ast_log(LOG_ERROR, "maxrate %d is less than minrate %d\n", details->maxrate, details->minrate);
- ao2_ref(details, -1);
return -1;
}
@@ -2285,7 +2338,6 @@ static int sendfax_exec(struct ast_channel *chan, const char *data)
ast_string_field_set(details, error, "INVALID_ARGUMENTS");
ast_string_field_set(details, resultstr, "incompatible 'modems' and 'minrate' settings");
set_channel_variables(chan, details);
- ao2_ref(details, -1);
return -1;
}
@@ -2295,7 +2347,6 @@ static int sendfax_exec(struct ast_channel *chan, const char *data)
ast_string_field_set(details, error, "INVALID_ARGUMENTS");
ast_string_field_set(details, resultstr, "incompatible 'modems' and 'maxrate' settings");
set_channel_variables(chan, details);
- ao2_ref(details, -1);
return -1;
}
@@ -2304,7 +2355,6 @@ static int sendfax_exec(struct ast_channel *chan, const char *data)
ast_string_field_set(details, resultstr, "invalid arguments");
set_channel_variables(chan, details);
ast_log(LOG_WARNING, "%s requires an argument (filename[&filename[&filename]][,options])\n", app_sendfax);
- ao2_ref(details, -1);
return -1;
}
parse = ast_strdupa(data);
@@ -2316,7 +2366,6 @@ static int sendfax_exec(struct ast_channel *chan, const char *data)
ast_string_field_set(details, error, "INVALID_ARGUMENTS");
ast_string_field_set(details, resultstr, "invalid arguments");
set_channel_variables(chan, details);
- ao2_ref(details, -1);
return -1;
}
if (ast_strlen_zero(args.filenames)) {
@@ -2324,7 +2373,6 @@ static int sendfax_exec(struct ast_channel *chan, const char *data)
ast_string_field_set(details, resultstr, "invalid arguments");
set_channel_variables(chan, details);
ast_log(LOG_WARNING, "%s requires an argument (filename[&filename[&filename]],options])\n", app_sendfax);
- ao2_ref(details, -1);
return -1;
}
@@ -2334,7 +2382,6 @@ static int sendfax_exec(struct ast_channel *chan, const char *data)
ast_string_field_set(details, resultstr, "invalid arguments");
set_channel_variables(chan, details);
ast_log(LOG_WARNING, "%s does not support polling\n", app_sendfax);
- ao2_ref(details, -1);
return -1;
}
@@ -2348,7 +2395,6 @@ static int sendfax_exec(struct ast_channel *chan, const char *data)
ast_string_field_set(details, resultstr, "error reading file");
set_channel_variables(chan, details);
ast_log(LOG_ERROR, "access failure. Verify '%s' exists and check permissions.\n", args.filenames);
- ao2_ref(details, -1);
return -1;
}
@@ -2357,7 +2403,6 @@ static int sendfax_exec(struct ast_channel *chan, const char *data)
ast_string_field_set(details, resultstr, "error allocating memory");
set_channel_variables(chan, details);
ast_log(LOG_ERROR, "System cannot provide memory for session requirements.\n");
- ao2_ref(details, -1);
return -1;
}
@@ -2402,7 +2447,6 @@ static int sendfax_exec(struct ast_channel *chan, const char *data)
ast_string_field_set(details, resultstr, "error reserving fax session");
set_channel_variables(chan, details);
ast_log(LOG_ERROR, "Unable to reserve FAX session.\n");
- ao2_ref(details, -1);
return -1;
}
@@ -2413,8 +2457,6 @@ static int sendfax_exec(struct ast_channel *chan, const char *data)
set_channel_variables(chan, details);
ast_log(LOG_WARNING, "Channel '%s' failed answer attempt.\n", ast_channel_name(chan));
fax_session_release(s, token);
- ao2_ref(s, -1);
- ao2_ref(details, -1);
return -1;
}
}
@@ -2425,8 +2467,6 @@ static int sendfax_exec(struct ast_channel *chan, const char *data)
ast_string_field_set(details, resultstr, "error negotiating T.38");
set_channel_variables(chan, details);
fax_session_release(s, token);
- ao2_ref(s, -1);
- ao2_ref(details, -1);
return -1;
}
} else {
@@ -2439,8 +2479,6 @@ static int sendfax_exec(struct ast_channel *chan, const char *data)
ast_string_field_set(details, resultstr, "error negotiating T.38");
set_channel_variables(chan, details);
fax_session_release(s, token);
- ao2_ref(s, -1);
- ao2_ref(details, -1);
ast_log(LOG_ERROR, "error initializing channel '%s' in T.38 mode\n", ast_channel_name(chan));
return -1;
}
@@ -2460,42 +2498,13 @@ static int sendfax_exec(struct ast_channel *chan, const char *data)
if (!(filenames = generate_filenames_string(details, "FileName: ", "\r\n"))) {
ast_log(LOG_ERROR, "Error generating SendFAX manager event\n");
- ao2_ref(s, -1);
- ao2_ref(details, -1);
return (!channel_alive) ? -1 : 0;
}
/* send out the AMI completion event */
- ast_channel_lock(chan);
- get_manager_event_info(chan, &info);
- manager_event(EVENT_FLAG_CALL,
- "SendFAX",
- "Channel: %s\r\n"
- "Context: %s\r\n"
- "Exten: %s\r\n"
- "CallerID: %s\r\n"
- "RemoteStationID: %s\r\n"
- "LocalStationID: %s\r\n"
- "PagesTransferred: %s\r\n"
- "Resolution: %s\r\n"
- "TransferRate: %s\r\n"
- "%s\r\n",
- ast_channel_name(chan),
- info.context,
- info.exten,
- info.cid,
- S_OR(pbx_builtin_getvar_helper(chan, "REMOTESTATIONID"), ""),
- S_OR(pbx_builtin_getvar_helper(chan, "LOCALSTATIONID"), ""),
- S_OR(pbx_builtin_getvar_helper(chan, "FAXPAGES"), ""),
- S_OR(pbx_builtin_getvar_helper(chan, "FAXRESOLUTION"), ""),
- S_OR(pbx_builtin_getvar_helper(chan, "FAXBITRATE"), ""),
- filenames);
- ast_channel_unlock(chan);
-
- ast_free(filenames);
-
- ao2_ref(s, -1);
- ao2_ref(details, -1);
+ if (report_send_fax_status(chan, details)) {
+ ast_log(AST_LOG_ERROR, "Error publishing SendFAX status message\n");
+ }
/* If the channel hungup return -1; otherwise, return 0 to continue in the dialplan */
return (!channel_alive) ? -1 : 0;
diff --git a/res/res_jabber.c b/res/res_jabber.c
index 2070c8024..7ca0bf81e 100644
--- a/res/res_jabber.c
+++ b/res/res_jabber.c
@@ -1536,10 +1536,6 @@ static void aji_log_hook(void *data, const char *xmpp, size_t size, int is_incom
{
struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
- if (!ast_strlen_zero(xmpp)) {
- manager_event(EVENT_FLAG_USER, "JabberEvent", "Account: %s\r\nPacket: %s\r\n", client->name, xmpp);
- }
-
if (client->debug) {
if (is_incoming) {
ast_verbose("\nJABBER: %s INCOMING: %s\n", client->name, xmpp);
@@ -3247,9 +3243,9 @@ static void aji_mwi_cb(void *data, struct stasis_subscription *sub, struct stasi
char oldmsgs[10];
char newmsgs[10];
struct aji_client *client = data;
- struct stasis_mwi_state *mwi_state;
+ struct ast_mwi_state *mwi_state;
- if (!stasis_subscription_is_subscribed(sub) || stasis_mwi_state_type() != stasis_message_type(msg)) {
+ if (!stasis_subscription_is_subscribed(sub) || ast_mwi_state_type() != stasis_message_type(msg)) {
return;
}
@@ -3308,7 +3304,7 @@ static int cached_devstate_cb(void *obj, void *arg, int flags)
static void aji_init_event_distribution(struct aji_client *client)
{
if (!mwi_sub) {
- mwi_sub = stasis_subscribe(stasis_mwi_topic_all(), aji_mwi_cb, client);
+ mwi_sub = stasis_subscribe(ast_mwi_topic_all(), aji_mwi_cb, client);
}
if (!device_state_sub) {
RAII_VAR(struct ao2_container *, cached, NULL, ao2_cleanup);
@@ -3369,7 +3365,7 @@ static int aji_handle_pubsub_event(void *data, ikspak *pak)
sscanf(iks_find_cdata(item_content, "OLDMSGS"), "%10d", &oldmsgs);
sscanf(iks_find_cdata(item_content, "NEWMSGS"), "%10d", &newmsgs);
- stasis_publish_mwi_state_full(item_id, context, newmsgs, oldmsgs, &pubsub_eid);
+ ast_publish_mwi_state_full(item_id, context, newmsgs, oldmsgs, NULL, &pubsub_eid);
return IKS_FILTER_EAT;
} else {
diff --git a/res/res_monitor.c b/res/res_monitor.c
index 9aca24a0d..72911b5b1 100644
--- a/res/res_monitor.c
+++ b/res/res_monitor.c
@@ -40,8 +40,10 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/file.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
-#include "asterisk/manager.h"
#include "asterisk/cli.h"
+#include "asterisk/manager.h"
+#include "asterisk/stasis.h"
+#include "asterisk/stasis_channels.h"
#define AST_API_MODULE
#include "asterisk/monitor.h"
#include "asterisk/app.h"
@@ -291,6 +293,7 @@ int AST_OPTIONAL_API_NAME(ast_monitor_start)(struct ast_channel *chan, const cha
const char *fname_base, int need_lock, int stream_action)
{
int res = 0;
+ RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
LOCK_IF_NEEDED(chan, need_lock);
@@ -393,11 +396,12 @@ int AST_OPTIONAL_API_NAME(ast_monitor_start)(struct ast_channel *chan, const cha
/* so we know this call has been monitored in case we need to bill for it or something */
pbx_builtin_setvar_helper(chan, "__MONITORED","true");
- ast_manager_event(chan, EVENT_FLAG_CALL, "MonitorStart",
- "Channel: %s\r\n"
- "Uniqueid: %s\r\n",
- ast_channel_name(chan),
- ast_channel_uniqueid(chan));
+ message = ast_channel_cached_blob_create(chan,
+ ast_channel_monitor_start_type(),
+ NULL);
+ if (message) {
+ stasis_publish(ast_channel_topic(chan), message);
+ }
} else {
ast_debug(1,"Cannot start monitoring %s, already monitored\n", ast_channel_name(chan));
res = -1;
@@ -437,6 +441,7 @@ static const char *get_soxmix_format(const char *format)
int AST_OPTIONAL_API_NAME(ast_monitor_stop)(struct ast_channel *chan, int need_lock)
{
int delfiles = 0;
+ RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
LOCK_IF_NEEDED(chan, need_lock);
@@ -511,12 +516,12 @@ int AST_OPTIONAL_API_NAME(ast_monitor_stop)(struct ast_channel *chan, int need_l
ast_free(ast_channel_monitor(chan));
ast_channel_monitor_set(chan, NULL);
- ast_manager_event(chan, EVENT_FLAG_CALL, "MonitorStop",
- "Channel: %s\r\n"
- "Uniqueid: %s\r\n",
- ast_channel_name(chan),
- ast_channel_uniqueid(chan)
- );
+ message = ast_channel_cached_blob_create(chan,
+ ast_channel_monitor_stop_type(),
+ NULL);
+ if (message) {
+ stasis_publish(ast_channel_topic(chan), message);
+ }
pbx_builtin_setvar_helper(chan, "MONITORED", NULL);
}
pbx_builtin_setvar_helper(chan, "AUTO_MONITOR", NULL);
diff --git a/res/res_musiconhold.c b/res/res_musiconhold.c
index 130618431..2ed7ea52b 100644
--- a/res/res_musiconhold.c
+++ b/res/res_musiconhold.c
@@ -67,7 +67,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/cli.h"
#include "asterisk/stringfields.h"
#include "asterisk/linkedlists.h"
-#include "asterisk/manager.h"
+#include "asterisk/stasis.h"
+#include "asterisk/stasis_channels.h"
#include "asterisk/paths.h"
#include "asterisk/astobj2.h"
#include "asterisk/timing.h"
@@ -1373,6 +1374,8 @@ static int local_ast_moh_start(struct ast_channel *chan, const char *mclass, con
struct mohclass *mohclass = NULL;
struct moh_files_state *state = ast_channel_music_state(chan);
struct ast_variable *var = NULL;
+ RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
+ RAII_VAR(struct ast_json *, json_object, NULL, ast_json_unref);
int res;
int realtime_possible = ast_check_realtime("musiconhold");
@@ -1567,14 +1570,6 @@ static int local_ast_moh_start(struct ast_channel *chan, const char *mclass, con
}
}
- ast_manager_event(chan, EVENT_FLAG_CALL, "MusicOnHold",
- "State: Start\r\n"
- "Channel: %s\r\n"
- "UniqueID: %s\r\n"
- "Class: %s\r\n",
- ast_channel_name(chan), ast_channel_uniqueid(chan),
- mohclass->name);
-
ast_set_flag(ast_channel_flags(chan), AST_FLAG_MOH);
if (mohclass->total_files) {
@@ -1583,6 +1578,20 @@ static int local_ast_moh_start(struct ast_channel *chan, const char *mclass, con
res = ast_activate_generator(chan, &mohgen, mohclass);
}
+ json_object = ast_json_pack("{s: s}",
+ "class", mohclass->name);
+ if (!json_object) {
+ mohclass = mohclass_unref(mohclass, "unreffing local reference to mohclass in local_ast_moh_start");
+ return -1;
+ }
+
+ message = ast_channel_cached_blob_create(chan,
+ ast_channel_moh_start_type(),
+ json_object);
+ if (message) {
+ stasis_publish(ast_channel_topic(chan), message);
+ }
+
mohclass = mohclass_unref(mohclass, "unreffing local reference to mohclass in local_ast_moh_start");
return res;
@@ -1590,6 +1599,7 @@ static int local_ast_moh_start(struct ast_channel *chan, const char *mclass, con
static void local_ast_moh_stop(struct ast_channel *chan)
{
+ RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
ast_clear_flag(ast_channel_flags(chan), AST_FLAG_MOH);
ast_deactivate_generator(chan);
@@ -1601,11 +1611,10 @@ static void local_ast_moh_stop(struct ast_channel *chan)
}
}
- ast_manager_event(chan, EVENT_FLAG_CALL, "MusicOnHold",
- "State: Stop\r\n"
- "Channel: %s\r\n"
- "UniqueID: %s\r\n",
- ast_channel_name(chan), ast_channel_uniqueid(chan));
+ message = ast_channel_cached_blob_create(chan, ast_channel_moh_stop_type(), NULL);
+ if (message) {
+ stasis_publish(ast_channel_topic(chan), message);
+ }
ast_channel_unlock(chan);
}
diff --git a/res/res_sip_mwi.c b/res/res_sip_mwi.c
index 588662f33..f18e56469 100644
--- a/res/res_sip_mwi.c
+++ b/res/res_sip_mwi.c
@@ -133,7 +133,7 @@ static struct mwi_stasis_subscription *mwi_stasis_subscription_alloc(const char
return NULL;
}
- topic = stasis_mwi_topic(mailbox);
+ topic = ast_mwi_topic(mailbox);
/* Safe strcpy */
strcpy(mwi_stasis_sub->mailbox, mailbox);
@@ -237,9 +237,9 @@ static int get_message_count(void *obj, void *arg, int flags)
RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
struct mwi_stasis_subscription *mwi_stasis = obj;
struct message_accumulator *counter = arg;
- struct stasis_mwi_state *mwi_state;
+ struct ast_mwi_state *mwi_state;
- msg = stasis_cache_get(stasis_mwi_topic_cached(), stasis_mwi_state_type(), mwi_stasis->mailbox);
+ msg = stasis_cache_get(ast_mwi_topic_cached(), ast_mwi_state_type(), mwi_stasis->mailbox);
if (!msg) {
return 0;
}
@@ -604,7 +604,7 @@ static void mwi_stasis_cb(void *userdata, struct stasis_subscription *sub,
return;
}
- if (stasis_mwi_state_type() == stasis_message_type(msg)) {
+ if (ast_mwi_state_type() == stasis_message_type(msg)) {
struct ast_taskprocessor *serializer = mwi_sub->is_solicited ? ast_sip_subscription_get_serializer(mwi_sub->sip_sub) : NULL;
ao2_ref(mwi_sub, +1);
ast_sip_push_task(serializer, serialized_notify, mwi_sub);
diff --git a/res/res_xmpp.c b/res/res_xmpp.c
index dea837204..89eb45d18 100644
--- a/res/res_xmpp.c
+++ b/res/res_xmpp.c
@@ -1324,9 +1324,9 @@ static void xmpp_pubsub_mwi_cb(void *data, struct stasis_subscription *sub, stru
struct ast_xmpp_client *client = data;
const char *mailbox, *context;
char oldmsgs[10], newmsgs[10];
- struct stasis_mwi_state *mwi_state;
+ struct ast_mwi_state *mwi_state;
- if (!stasis_subscription_is_subscribed(sub) || stasis_mwi_state_type() != stasis_message_type(msg)) {
+ if (!stasis_subscription_is_subscribed(sub) || ast_mwi_state_type() != stasis_message_type(msg)) {
return;
}
@@ -1484,7 +1484,7 @@ static int xmpp_pubsub_handle_event(void *data, ikspak *pak)
sscanf(iks_find_cdata(item_content, "OLDMSGS"), "%10d", &oldmsgs);
sscanf(iks_find_cdata(item_content, "NEWMSGS"), "%10d", &newmsgs);
- stasis_publish_mwi_state_full(item_id, context, newmsgs, oldmsgs, &pubsub_eid);
+ ast_publish_mwi_state_full(item_id, context, newmsgs, oldmsgs, NULL, &pubsub_eid);
return IKS_FILTER_EAT;
} else {
@@ -1596,7 +1596,7 @@ static void xmpp_init_event_distribution(struct ast_xmpp_client *client)
xmpp_pubsub_unsubscribe(client, "device_state");
xmpp_pubsub_unsubscribe(client, "message_waiting");
- if (!(client->mwi_sub = stasis_subscribe(stasis_mwi_topic_all(), xmpp_pubsub_mwi_cb, client))) {
+ if (!(client->mwi_sub = stasis_subscribe(ast_mwi_topic_all(), xmpp_pubsub_mwi_cb, client))) {
return;
}
@@ -2546,10 +2546,6 @@ static void xmpp_log_hook(void *data, const char *xmpp, size_t size, int incomin
RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
struct ast_xmpp_client *client = data;
- if (!ast_strlen_zero(xmpp)) {
- manager_event(EVENT_FLAG_USER, "JabberEvent", "Account: %s\r\nPacket: %s\r\n", client->name, xmpp);
- }
-
if (!debug && (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, client->name)) || !ast_test_flag(&clientcfg->flags, XMPP_DEBUG))) {
return;
}