Move more channel events to Stasis; move res_json.c to main/json.c.
[asterisk/asterisk.git] / main / manager_channels.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2013, Digium, Inc.
5  *
6  * David M. Lee, II <dlee@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*! \file
20  *
21  * \brief The Asterisk Management Interface - AMI (channel event handling)
22  *
23  * \author David M. Lee, II <dlee@digium.com>
24  *
25  * AMI generated many per-channel and global-channel events by converting Stasis
26  * messages to AMI events. It makes sense to simply put them into a single file.
27  */
28
29 #include "asterisk.h"
30
31 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
32
33 #include "asterisk/channel.h"
34 #include "asterisk/manager.h"
35 #include "asterisk/stasis_message_router.h"
36 #include "asterisk/pbx.h"
37
38 static struct stasis_message_router *channel_state_router;
39
40 /*** DOCUMENTATION
41         <managerEvent language="en_US" name="Newchannel">
42                 <managerEventInstance class="EVENT_FLAG_CALL">
43                         <synopsis>Raised when a new channel is created.</synopsis>
44                         <syntax>
45                                 <parameter name="Channel">
46                                 </parameter>
47                                 <parameter name="ChannelState">
48                                         <para>A numeric code for the channel's current state, related to ChannelStateDesc</para>
49                                 </parameter>
50                                 <parameter name="ChannelStateDesc">
51                                         <enumlist>
52                                                 <enum name="Down"/>
53                                                 <enum name="Rsrvd"/>
54                                                 <enum name="OffHook"/>
55                                                 <enum name="Dialing"/>
56                                                 <enum name="Ring"/>
57                                                 <enum name="Ringing"/>
58                                                 <enum name="Up"/>
59                                                 <enum name="Busy"/>
60                                                 <enum name="Dialing Offhook"/>
61                                                 <enum name="Pre-ring"/>
62                                                 <enum name="Unknown"/>
63                                         </enumlist>
64                                 </parameter>
65                                 <parameter name="CallerIDNum">
66                                 </parameter>
67                                 <parameter name="CallerIDName">
68                                 </parameter>
69                                 <parameter name="ConnectedLineNum">
70                                 </parameter>
71                                 <parameter name="ConnectedLineName">
72                                 </parameter>
73                                 <parameter name="AccountCode">
74                                 </parameter>
75                                 <parameter name="Context">
76                                 </parameter>
77                                 <parameter name="Exten">
78                                 </parameter>
79                                 <parameter name="Priority">
80                                 </parameter>
81                                 <parameter name="Uniqueid">
82                                 </parameter>
83                                 <parameter name="Cause">
84                                         <para>A numeric cause code for why the channel was hung up.</para>
85                                 </parameter>
86                                 <parameter name="Cause-txt">
87                                         <para>A description of why the channel was hung up.</para>
88                                 </parameter>
89                         </syntax>
90                 </managerEventInstance>
91         </managerEvent>
92         <managerEvent language="en_US" name="Newstate">
93                 <managerEventInstance class="EVENT_FLAG_CALL">
94                         <synopsis>Raised when a channel's state changes.</synopsis>
95                         <syntax>
96                                 <xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
97                         </syntax>
98                 </managerEventInstance>
99         </managerEvent>
100         <managerEvent language="en_US" name="Hangup">
101                 <managerEventInstance class="EVENT_FLAG_CALL">
102                         <synopsis>Raised when a channel is hung up.</synopsis>
103                         <syntax>
104                                 <xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
105                         </syntax>
106                 </managerEventInstance>
107         </managerEvent>
108  ***/
109
110 /*!
111  * \brief Generate the AMI message body from a channel snapshot
112  * \internal
113  *
114  * \param snapshot the channel snapshot for which to generate an AMI message
115  *                 body
116  *
117  * \retval NULL on error
118  * \retval ast_str* on success (must be ast_freed by caller)
119  */
120 static struct ast_str *manager_build_channel_state_string(
121         const struct ast_channel_snapshot *snapshot)
122 {
123         struct ast_str *out = ast_str_create(1024);
124         int res = 0;
125         if (!out) {
126                 return NULL;
127         }
128         res = ast_str_set(&out, 0,
129                 "Channel: %s\r\n"
130                 "ChannelState: %d\r\n"
131                 "ChannelStateDesc: %s\r\n"
132                 "CallerIDNum: %s\r\n"
133                 "CallerIDName: %s\r\n"
134                 "ConnectedLineNum: %s\r\n"
135                 "ConnectedLineName: %s\r\n"
136                 "AccountCode: %s\r\n"
137                 "Context: %s\r\n"
138                 "Exten: %s\r\n"
139                 "Priority: %d\r\n"
140                 "Uniqueid: %s\r\n"
141                 "Cause: %d\r\n"
142                 "Cause-txt: %s\r\n",
143                 snapshot->name,
144                 snapshot->state,
145                 ast_state2str(snapshot->state),
146                 snapshot->caller_number,
147                 snapshot->caller_name,
148                 snapshot->connected_number,
149                 snapshot->connected_name,
150                 snapshot->accountcode,
151                 snapshot->context,
152                 snapshot->exten,
153                 snapshot->priority,
154                 snapshot->uniqueid,
155                 snapshot->hangupcause,
156                 ast_cause2str(snapshot->hangupcause));
157
158         if (!res) {
159                 return NULL;
160         }
161
162         return out;
163 }
164
165 static inline int cep_has_changed(
166         const struct ast_channel_snapshot *old_snapshot,
167         const struct ast_channel_snapshot *new_snapshot)
168 {
169         ast_assert(old_snapshot != NULL);
170         ast_assert(new_snapshot != NULL);
171         return old_snapshot->priority != new_snapshot->priority ||
172                 strcmp(old_snapshot->context, new_snapshot->context) != 0 ||
173                 strcmp(old_snapshot->exten, new_snapshot->exten) != 0;
174 }
175
176 static void channel_snapshot_update(void *data, struct stasis_subscription *sub,
177                                     struct stasis_topic *topic,
178                                     struct stasis_message *message)
179 {
180         RAII_VAR(struct ast_str *, channel_event_string, NULL, ast_free);
181         struct stasis_cache_update *update = stasis_message_data(message);
182         struct ast_channel_snapshot *old_snapshot;
183         struct ast_channel_snapshot *new_snapshot;
184         int is_hungup, was_hungup;
185         char *manager_event = NULL;
186         int new_exten;
187
188         if (ast_channel_snapshot() != update->type) {
189                 return;
190         }
191
192         old_snapshot = stasis_message_data(update->old_snapshot);
193         new_snapshot = stasis_message_data(update->new_snapshot);
194
195         if (!new_snapshot) {
196                 /* Ignore cache clearing events; we'll see the hangup first */
197                 return;
198         }
199
200         was_hungup = (old_snapshot && ast_test_flag(&old_snapshot->flags, AST_FLAG_ZOMBIE)) ? 1 : 0;
201         is_hungup = ast_test_flag(&new_snapshot->flags, AST_FLAG_ZOMBIE) ? 1 : 0;
202
203         if (!old_snapshot) {
204                 manager_event = "Newchannel";
205         }
206
207         if (old_snapshot && old_snapshot->state != new_snapshot->state) {
208                 manager_event = "Newstate";
209         }
210
211         if (!was_hungup && is_hungup) {
212                 manager_event = "Hangup";
213         }
214
215         /* Detect Newexten transitions
216          *  - if new snapshot has an application set AND
217          *    - first snapshot OR
218          *    - if the old snapshot has no application (first Newexten) OR
219          *    - if the context/priority/exten changes
220          */
221         new_exten = !ast_strlen_zero(new_snapshot->appl) && (
222                 !old_snapshot ||
223                 ast_strlen_zero(old_snapshot->appl) ||
224                 cep_has_changed(old_snapshot, new_snapshot));
225
226         if (manager_event || new_exten) {
227                 channel_event_string =
228                         manager_build_channel_state_string(new_snapshot);
229         }
230
231         if (!channel_event_string) {
232                 return;
233         }
234
235         /* Channel state change events */
236         if (manager_event) {
237                 manager_event(EVENT_FLAG_CALL, manager_event, "%s",
238                               ast_str_buffer(channel_event_string));
239         }
240
241         if (new_exten) {
242                 /* DEPRECATED: Extension field deprecated in 12; remove in 14 */
243                 /*** DOCUMENTATION
244                         <managerEventInstance>
245                                 <synopsis>Raised when a channel enters a new context, extension, priority.</synopsis>
246                                 <syntax>
247                                         <xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
248                                         <parameter name="Extension">
249                                                 <para>Deprecated in 12, but kept for
250                                                 backward compatability. Please use
251                                                 'Exten' instead.</para>
252                                         </parameter>
253                                         <parameter name="Application">
254                                                 <para>The application about to be executed.</para>
255                                         </parameter>
256                                         <parameter name="AppData">
257                                                 <para>The data to be passed to the application.</para>
258                                         </parameter>
259                                 </syntax>
260                         </managerEventInstance>
261                 ***/
262                 manager_event(EVENT_FLAG_DIALPLAN, "Newexten",
263                               "%s"
264                               "Extension: %s\r\n"
265                               "Application: %s\r\n"
266                               "AppData: %s\r\n",
267                               ast_str_buffer(channel_event_string),
268                               new_snapshot->exten,
269                               new_snapshot->appl,
270                               new_snapshot->data);
271         }
272 }
273
274 static void channel_varset(struct ast_channel_blob *obj)
275 {
276         RAII_VAR(struct ast_str *, channel_event_string, NULL, ast_free);
277         const char *variable = ast_json_string_get(ast_json_object_get(obj->blob, "variable"));
278         const char *value = ast_json_string_get(ast_json_object_get(obj->blob, "value"));
279
280         if (obj->snapshot) {
281                 channel_event_string = manager_build_channel_state_string(obj->snapshot);
282         } else {
283                 channel_event_string = ast_str_create(35);
284                 ast_str_set(&channel_event_string, 0,
285                             "Channel: none\r\n"
286                             "Uniqueid: none\r\n");
287         }
288
289         if (!channel_event_string) {
290                 return;
291         }
292
293         /*** DOCUMENTATION
294                 <managerEventInstance>
295                         <synopsis>Raised when a variable is set to a particular value.</synopsis>
296                         <syntax>
297                                 <xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
298                                 <parameter name="Variable">
299                                         <para>The variable being set.</para>
300                                 </parameter>
301                                 <parameter name="Value">
302                                         <para>The new value of the variable.</para>
303                                 </parameter>
304                         </syntax>
305                 </managerEventInstance>
306         ***/
307         manager_event(EVENT_FLAG_DIALPLAN, "VarSet",
308                       "%s"
309                       "Variable: %s\r\n"
310                       "Value: %s\r\n",
311                       ast_str_buffer(channel_event_string),
312                       variable, value);
313 }
314
315 static void channel_userevent(struct ast_channel_blob *obj)
316 {
317         RAII_VAR(struct ast_str *, channel_event_string, NULL, ast_free);
318         const char *eventname;
319         const char *body;
320
321         eventname = ast_json_string_get(ast_json_object_get(obj->blob, "eventname"));
322         body = ast_json_string_get(ast_json_object_get(obj->blob, "body"));
323         channel_event_string = manager_build_channel_state_string(obj->snapshot);
324
325         if (!channel_event_string) {
326                 return;
327         }
328
329         /*** DOCUMENTATION
330                 <managerEventInstance>
331                         <synopsis>A user defined event raised from the dialplan.</synopsis>
332                         <syntax>
333                                 <xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
334                                 <parameter name="UserEvent">
335                                         <para>The event name, as specified in the dialplan.</para>
336                                 </parameter>
337                         </syntax>
338                         <see-also>
339                                 <ref type="application">UserEvent</ref>
340                         </see-also>
341                 </managerEventInstance>
342         ***/
343         manager_event(EVENT_FLAG_USER, "UserEvent",
344                       "%s"
345                       "UserEvent: %s\r\n"
346                       "%s",
347                       ast_str_buffer(channel_event_string), eventname, body);
348 }
349
350 /*!
351  * \brief Callback processing messages on the channel topic.
352  */
353 static void channel_blob_cb(void *data, struct stasis_subscription *sub,
354                             struct stasis_topic *topic,
355                             struct stasis_message *message)
356 {
357         struct ast_channel_blob *obj = stasis_message_data(message);
358
359         if (strcmp("varset", ast_channel_blob_type(obj)) == 0) {
360                 channel_varset(obj);
361         } else if (strcmp("userevent", ast_channel_blob_type(obj)) == 0) {
362                 channel_userevent(obj);
363         }
364 }
365
366 static void manager_channels_shutdown(void)
367 {
368         stasis_message_router_unsubscribe(channel_state_router);
369         channel_state_router = NULL;
370 }
371
372 int manager_channels_init(void)
373 {
374         int ret = 0;
375
376         if (channel_state_router) {
377                 /* Already initialized */
378                 return 0;
379         }
380
381         ast_register_atexit(manager_channels_shutdown);
382
383         channel_state_router = stasis_message_router_create(
384                 stasis_caching_get_topic(ast_channel_topic_all_cached()));
385
386         if (!channel_state_router) {
387                 return -1;
388         }
389
390         ret |= stasis_message_router_add(channel_state_router,
391                                          stasis_cache_update(),
392                                          channel_snapshot_update,
393                                          NULL);
394
395         ret |= stasis_message_router_add(channel_state_router,
396                                          ast_channel_blob(),
397                                          channel_blob_cb,
398                                          NULL);
399
400         /* If somehow we failed to add any routes, just shut down the whole
401          * things and fail it.
402          */
403         if (ret) {
404                 manager_channels_shutdown();
405                 return -1;
406         }
407
408         return 0;
409 }