d7fbc98ab94f7adf3fcc2a5c1b19b2b8d4210d0d
[asterisk/asterisk.git] / main / stasis_channels.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2013, Digium, Inc.
5  *
6  * Matt Jordan <mjordan@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 Stasis Messages and Data Types for Channel Objects
22  *
23  * \author \verbatim Matt Jordan <mjordan@digium.com> \endverbatim
24  *
25  */
26
27 /*** MODULEINFO
28         <support_level>core</support_level>
29  ***/
30
31 #include "asterisk.h"
32
33 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
34
35 #include "asterisk/astobj2.h"
36 #include "asterisk/json.h"
37 #include "asterisk/pbx.h"
38 #include "asterisk/bridge.h"
39 #include "asterisk/translate.h"
40 #include "asterisk/stasis.h"
41 #include "asterisk/stasis_cache_pattern.h"
42 #include "asterisk/stasis_channels.h"
43
44 /*** DOCUMENTATION
45         <managerEvent language="en_US" name="VarSet">
46                 <managerEventInstance class="EVENT_FLAG_DIALPLAN">
47                         <synopsis>Raised when a variable is set to a particular value.</synopsis>
48                         <syntax>
49                                 <channel_snapshot/>
50                                 <parameter name="Variable">
51                                         <para>The variable being set.</para>
52                                 </parameter>
53                                 <parameter name="Value">
54                                         <para>The new value of the variable.</para>
55                                 </parameter>
56                         </syntax>
57                 </managerEventInstance>
58         </managerEvent>
59         <managerEvent language="en_US" name="AgentLogin">
60                 <managerEventInstance class="EVENT_FLAG_AGENT">
61                         <synopsis>Raised when an Agent has logged in.</synopsis>
62                         <syntax>
63                                 <channel_snapshot/>
64                                 <parameter name="Agent">
65                                         <para>Agent ID of the agent.</para>
66                                 </parameter>
67                         </syntax>
68                         <see-also>
69                                 <ref type="application">AgentLogin</ref>
70                                 <ref type="managerEvent">AgentLogoff</ref>
71                         </see-also>
72                 </managerEventInstance>
73         </managerEvent>
74         <managerEvent language="en_US" name="AgentLogoff">
75                 <managerEventInstance class="EVENT_FLAG_AGENT">
76                         <synopsis>Raised when an Agent has logged off.</synopsis>
77                         <syntax>
78                                 <xi:include xpointer="xpointer(/docs/managerEvent[@name='AgentLogin']/managerEventInstance/syntax/parameter)" />
79                                 <parameter name="Logintime">
80                                         <para>The number of seconds the agent was logged in.</para>
81                                 </parameter>
82                         </syntax>
83                         <see-also>
84                                 <ref type="managerEvent">AgentLogin</ref>
85                         </see-also>
86                 </managerEventInstance>
87         </managerEvent>
88         <managerEvent language="en_US" name="ChannelTalkingStart">
89                 <managerEventInstance class="EVENT_FLAG_CLASS">
90                         <synopsis>Raised when talking is detected on a channel.</synopsis>
91                         <syntax>
92                                 <channel_snapshot/>
93                         </syntax>
94                         <see-also>
95                                 <ref type="function">TALK_DETECT</ref>
96                                 <ref type="managerEvent">ChannelTalkingStop</ref>
97                         </see-also>
98                 </managerEventInstance>
99         </managerEvent>
100         <managerEvent language="en_US" name="ChannelTalkingStop">
101                 <managerEventInstance class="EVENT_FLAG_CLASS">
102                         <synopsis>Raised when talking is no longer detected on a channel.</synopsis>
103                         <syntax>
104                                 <channel_snapshot/>
105                                 <parameter name="Duration">
106                                         <para>The length in time, in milliseconds, that talking was
107                                         detected on the channel.</para>
108                                 </parameter>
109                         </syntax>
110                         <see-also>
111                                 <ref type="function">TALK_DETECT</ref>
112                                 <ref type="managerEvent">ChannelTalkingStart</ref>
113                         </see-also>
114                 </managerEventInstance>
115         </managerEvent>
116 ***/
117
118 #define NUM_MULTI_CHANNEL_BLOB_BUCKETS 7
119
120 static struct stasis_cp_all *channel_cache_all;
121 static struct stasis_cache *channel_cache_by_name;
122 static struct stasis_caching_topic *channel_by_name_topic;
123
124 struct stasis_cp_all *ast_channel_cache_all(void)
125 {
126         return channel_cache_all;
127 }
128
129 struct stasis_cache *ast_channel_cache(void)
130 {
131         return stasis_cp_all_cache(channel_cache_all);
132 }
133
134 struct stasis_topic *ast_channel_topic_all(void)
135 {
136         return stasis_cp_all_topic(channel_cache_all);
137 }
138
139 struct stasis_topic *ast_channel_topic_all_cached(void)
140 {
141         return stasis_cp_all_topic_cached(channel_cache_all);
142 }
143
144 struct stasis_cache *ast_channel_cache_by_name(void)
145 {
146         return channel_cache_by_name;
147 }
148
149 static const char *channel_snapshot_get_id(struct stasis_message *message)
150 {
151         struct ast_channel_snapshot *snapshot;
152         if (ast_channel_snapshot_type() != stasis_message_type(message)) {
153                 return NULL;
154         }
155         snapshot = stasis_message_data(message);
156         return snapshot->uniqueid;
157 }
158
159 static const char *channel_snapshot_get_name(struct stasis_message *message)
160 {
161         struct ast_channel_snapshot *snapshot;
162         if (ast_channel_snapshot_type() != stasis_message_type(message)) {
163                 return NULL;
164         }
165         snapshot = stasis_message_data(message);
166         return snapshot->name;
167 }
168
169 /*!
170  * \internal
171  * \brief Hash function for \ref ast_channel_snapshot objects
172  */
173 static int channel_snapshot_hash_cb(const void *obj, const int flags)
174 {
175         const struct ast_channel_snapshot *snapshot = obj;
176         const char *name = (flags & OBJ_KEY) ? obj : snapshot->name;
177         return ast_str_case_hash(name);
178 }
179
180 /*!
181  * \internal
182  * \brief Comparison function for \ref ast_channel_snapshot objects
183  */
184 static int channel_snapshot_cmp_cb(void *obj, void *arg, int flags)
185 {
186         struct ast_channel_snapshot *left = obj;
187         struct ast_channel_snapshot *right = arg;
188         const char *match = (flags & OBJ_KEY) ? arg : right->name;
189         return strcasecmp(left->name, match) ? 0 : (CMP_MATCH | CMP_STOP);
190 }
191
192 static void channel_snapshot_dtor(void *obj)
193 {
194         struct ast_channel_snapshot *snapshot = obj;
195
196         ast_string_field_free_memory(snapshot);
197         ao2_cleanup(snapshot->manager_vars);
198 }
199
200 struct ast_channel_snapshot *ast_channel_snapshot_create(struct ast_channel *chan)
201 {
202         struct ast_channel_snapshot *snapshot;
203         struct ast_bridge *bridge;
204
205         /* no snapshots for dummy channels */
206         if (!ast_channel_tech(chan)) {
207                 return NULL;
208         }
209
210         snapshot = ao2_alloc(sizeof(*snapshot), channel_snapshot_dtor);
211         if (!snapshot || ast_string_field_init(snapshot, 1024)) {
212                 ao2_cleanup(snapshot);
213                 return NULL;
214         }
215
216         ast_string_field_set(snapshot, name, ast_channel_name(chan));
217         ast_string_field_set(snapshot, type, ast_channel_tech(chan)->type);
218         ast_string_field_set(snapshot, accountcode, ast_channel_accountcode(chan));
219         ast_string_field_set(snapshot, peeraccount, ast_channel_peeraccount(chan));
220         ast_string_field_set(snapshot, userfield, ast_channel_userfield(chan));
221         ast_string_field_set(snapshot, uniqueid, ast_channel_uniqueid(chan));
222         ast_string_field_set(snapshot, linkedid, ast_channel_linkedid(chan));
223         ast_string_field_set(snapshot, hangupsource, ast_channel_hangupsource(chan));
224         if (ast_channel_appl(chan)) {
225                 ast_string_field_set(snapshot, appl, ast_channel_appl(chan));
226         }
227         if (ast_channel_data(chan)) {
228                 ast_string_field_set(snapshot, data, ast_channel_data(chan));
229         }
230         ast_string_field_set(snapshot, context, ast_channel_context(chan));
231         ast_string_field_set(snapshot, exten, ast_channel_exten(chan));
232
233         ast_string_field_set(snapshot, caller_name,
234                 S_COR(ast_channel_caller(chan)->id.name.valid, ast_channel_caller(chan)->id.name.str, ""));
235         ast_string_field_set(snapshot, caller_number,
236                 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, ""));
237         ast_string_field_set(snapshot, caller_dnid, S_OR(ast_channel_dialed(chan)->number.str, ""));
238         ast_string_field_set(snapshot, caller_subaddr,
239                 S_COR(ast_channel_caller(chan)->id.subaddress.valid, ast_channel_caller(chan)->id.subaddress.str, ""));
240         ast_string_field_set(snapshot, dialed_subaddr,
241                 S_COR(ast_channel_dialed(chan)->subaddress.valid, ast_channel_dialed(chan)->subaddress.str, ""));
242         ast_string_field_set(snapshot, caller_ani,
243                 S_COR(ast_channel_caller(chan)->ani.number.valid, ast_channel_caller(chan)->ani.number.str, ""));
244         ast_string_field_set(snapshot, caller_rdnis,
245                 S_COR(ast_channel_redirecting(chan)->from.number.valid, ast_channel_redirecting(chan)->from.number.str, ""));
246         ast_string_field_set(snapshot, caller_dnid,
247                 S_OR(ast_channel_dialed(chan)->number.str, ""));
248
249         ast_string_field_set(snapshot, connected_name,
250                 S_COR(ast_channel_connected(chan)->id.name.valid, ast_channel_connected(chan)->id.name.str, ""));
251         ast_string_field_set(snapshot, connected_number,
252                 S_COR(ast_channel_connected(chan)->id.number.valid, ast_channel_connected(chan)->id.number.str, ""));
253         ast_string_field_set(snapshot, language, ast_channel_language(chan));
254
255         if ((bridge = ast_channel_get_bridge(chan))) {
256                 ast_string_field_set(snapshot, bridgeid, bridge->uniqueid);
257                 ao2_cleanup(bridge);
258         }
259
260         snapshot->creationtime = ast_channel_creationtime(chan);
261         snapshot->state = ast_channel_state(chan);
262         snapshot->priority = ast_channel_priority(chan);
263         snapshot->amaflags = ast_channel_amaflags(chan);
264         snapshot->hangupcause = ast_channel_hangupcause(chan);
265         ast_copy_flags(&snapshot->flags, ast_channel_flags(chan), 0xFFFFFFFF);
266         snapshot->caller_pres = ast_party_id_presentation(&ast_channel_caller(chan)->id);
267         ast_set_flag(&snapshot->softhangup_flags, ast_channel_softhangup_internal_flag(chan));
268
269         snapshot->manager_vars = ast_channel_get_manager_vars(chan);
270         snapshot->tech_properties = ast_channel_tech(chan)->properties;
271
272         return snapshot;
273 }
274
275 static void publish_message_for_channel_topics(struct stasis_message *message, struct ast_channel *chan)
276 {
277         if (chan) {
278                 stasis_publish(ast_channel_topic(chan), message);
279         } else {
280                 stasis_publish(ast_channel_topic_all(), message);
281         }
282 }
283
284 static void channel_blob_dtor(void *obj)
285 {
286         struct ast_channel_blob *event = obj;
287         ao2_cleanup(event->snapshot);
288         ast_json_unref(event->blob);
289 }
290
291 /*! \brief Dummy callback for receiving events */
292 static void dummy_event_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
293 {
294 }
295
296 void ast_channel_publish_dial_forward(struct ast_channel *caller, struct ast_channel *peer,
297         struct ast_channel *forwarded, const char *dialstring, const char *dialstatus,
298         const char *forward)
299 {
300         RAII_VAR(struct ast_multi_channel_blob *, payload, NULL, ao2_cleanup);
301         RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
302         RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
303         RAII_VAR(struct ast_channel_snapshot *, caller_snapshot, NULL, ao2_cleanup);
304         RAII_VAR(struct ast_channel_snapshot *, peer_snapshot, NULL, ao2_cleanup);
305         RAII_VAR(struct ast_channel_snapshot *, forwarded_snapshot, NULL, ao2_cleanup);
306
307         if (!ast_channel_dial_type()) {
308                 return;
309         }
310
311         ast_assert(peer != NULL);
312         blob = ast_json_pack("{s: s, s: s, s: s}",
313                              "dialstatus", S_OR(dialstatus, ""),
314                              "forward", S_OR(forward, ""),
315                              "dialstring", S_OR(dialstring, ""));
316         if (!blob) {
317                 return;
318         }
319         payload = ast_multi_channel_blob_create(blob);
320         if (!payload) {
321                 return;
322         }
323
324         if (caller) {
325                 ast_channel_lock(caller);
326                 if (ast_strlen_zero(dialstatus)) {
327                         caller_snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(caller));
328                 } else {
329                         caller_snapshot = ast_channel_snapshot_create(caller);
330                 }
331                 ast_channel_unlock(caller);
332                 if (!caller_snapshot) {
333                         return;
334                 }
335                 ast_multi_channel_blob_add_channel(payload, "caller", caller_snapshot);
336         }
337
338         ast_channel_lock(peer);
339         if (ast_strlen_zero(dialstatus)) {
340                 peer_snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(peer));
341         } else {
342                 peer_snapshot = ast_channel_snapshot_create(peer);
343         }
344         ast_channel_unlock(peer);
345         if (!peer_snapshot) {
346                 return;
347         }
348         ast_multi_channel_blob_add_channel(payload, "peer", peer_snapshot);
349
350         if (forwarded) {
351                 ast_channel_lock(forwarded);
352                 forwarded_snapshot = ast_channel_snapshot_create(forwarded);
353                 ast_channel_unlock(forwarded);
354                 if (!forwarded_snapshot) {
355                         return;
356                 }
357                 ast_multi_channel_blob_add_channel(payload, "forwarded", forwarded_snapshot);
358         }
359
360         msg = stasis_message_create(ast_channel_dial_type(), payload);
361         if (!msg) {
362                 return;
363         }
364
365         if (forwarded) {
366                 struct stasis_subscription *subscription = stasis_subscribe(ast_channel_topic(peer), dummy_event_cb, NULL);
367
368                 stasis_publish(ast_channel_topic(peer), msg);
369                 stasis_unsubscribe_and_join(subscription);
370         } else {
371                 publish_message_for_channel_topics(msg, caller);
372         }
373 }
374
375 void ast_channel_publish_dial(struct ast_channel *caller, struct ast_channel *peer,
376         const char *dialstring, const char *dialstatus)
377 {
378         ast_channel_publish_dial_forward(caller, peer, NULL, dialstring, dialstatus, NULL);
379 }
380
381 static struct stasis_message *create_channel_blob_message(struct ast_channel_snapshot *snapshot,
382                 struct stasis_message_type *type,
383                 struct ast_json *blob)
384 {
385         struct stasis_message *msg;
386         struct ast_channel_blob *obj;
387
388         obj = ao2_alloc(sizeof(*obj), channel_blob_dtor);
389         if (!obj) {
390                 return NULL;
391         }
392
393         if (snapshot) {
394                 obj->snapshot = snapshot;
395                 ao2_ref(obj->snapshot, +1);
396         }
397         if (!blob) {
398                 blob = ast_json_null();
399         }
400         obj->blob = ast_json_ref(blob);
401
402         msg = stasis_message_create(type, obj);
403         ao2_cleanup(obj);
404         return msg;
405 }
406
407 struct stasis_message *ast_channel_blob_create_from_cache(const char *channel_id,
408                                                struct stasis_message_type *type,
409                                                struct ast_json *blob)
410 {
411         RAII_VAR(struct ast_channel_snapshot *, snapshot,
412                         NULL,
413                         ao2_cleanup);
414
415         if (!type) {
416                 return NULL;
417         }
418
419         snapshot = ast_channel_snapshot_get_latest(channel_id);
420
421         return create_channel_blob_message(snapshot, type, blob);
422 }
423
424 struct stasis_message *ast_channel_blob_create(struct ast_channel *chan,
425         struct stasis_message_type *type, struct ast_json *blob)
426 {
427         RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
428
429         if (!type) {
430                 return NULL;
431         }
432
433         if (chan) {
434                 snapshot = ast_channel_snapshot_create(chan);
435         }
436
437         return create_channel_blob_message(snapshot, type, blob);
438 }
439
440 /*! \brief A channel snapshot wrapper object used in \ref ast_multi_channel_blob objects */
441 struct channel_role_snapshot {
442         struct ast_channel_snapshot *snapshot;  /*!< A channel snapshot */
443         char role[0];                                                   /*!< The role assigned to the channel */
444 };
445
446 /*! \brief A multi channel blob data structure for multi_channel_blob stasis messages */
447 struct ast_multi_channel_blob {
448         struct ao2_container *channel_snapshots;        /*!< A container holding the snapshots */
449         struct ast_json *blob;                                          /*< A blob of JSON data */
450 };
451
452 /*!
453  * \internal
454  * \brief Standard comparison function for \ref channel_role_snapshot objects
455  */
456 static int channel_role_single_cmp_cb(void *obj, void *arg, int flags)
457 {
458         struct channel_role_snapshot *left = obj;
459         struct channel_role_snapshot *right = arg;
460         const char *match = (flags & OBJ_KEY) ? arg : right->role;
461         return strcasecmp(left->role, match) ? 0 : (CMP_MATCH | CMP_STOP);
462 }
463
464 /*!
465  * \internal
466  * \brief Multi comparison function for \ref channel_role_snapshot objects
467  */
468 static int channel_role_multi_cmp_cb(void *obj, void *arg, int flags)
469 {
470         struct channel_role_snapshot *left = obj;
471         struct channel_role_snapshot *right = arg;
472         const char *match = (flags & OBJ_KEY) ? arg : right->role;
473         return strcasecmp(left->role, match) ? 0 : (CMP_MATCH);
474 }
475
476 /*!
477  * \internal
478  * \brief Hash function for \ref channel_role_snapshot objects
479  */
480 static int channel_role_hash_cb(const void *obj, const int flags)
481 {
482         const struct channel_role_snapshot *snapshot = obj;
483         const char *name = (flags & OBJ_KEY) ? obj : snapshot->role;
484         return ast_str_case_hash(name);
485 }
486
487 /*!
488  * \internal
489  * \brief Destructor for \ref ast_multi_channel_blob objects
490  */
491 static void multi_channel_blob_dtor(void *obj)
492 {
493         struct ast_multi_channel_blob *multi_blob = obj;
494
495         ao2_cleanup(multi_blob->channel_snapshots);
496         ast_json_unref(multi_blob->blob);
497 }
498
499 struct ast_multi_channel_blob *ast_multi_channel_blob_create(struct ast_json *blob)
500 {
501         RAII_VAR(struct ast_multi_channel_blob *, obj,
502                         ao2_alloc(sizeof(*obj), multi_channel_blob_dtor),
503                         ao2_cleanup);
504
505         ast_assert(blob != NULL);
506
507         if (!obj) {
508                 return NULL;
509         }
510
511         obj->channel_snapshots = ao2_container_alloc(NUM_MULTI_CHANNEL_BLOB_BUCKETS,
512                         channel_role_hash_cb, channel_role_single_cmp_cb);
513         if (!obj->channel_snapshots) {
514                 return NULL;
515         }
516
517         obj->blob = ast_json_ref(blob);
518
519         ao2_ref(obj, +1);
520         return obj;
521 }
522
523 struct ast_channel_snapshot *ast_channel_snapshot_get_latest(const char *uniqueid)
524 {
525         RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
526         struct ast_channel_snapshot *snapshot;
527
528         ast_assert(!ast_strlen_zero(uniqueid));
529
530         message = stasis_cache_get(ast_channel_cache(),
531                         ast_channel_snapshot_type(),
532                         uniqueid);
533         if (!message) {
534                 return NULL;
535         }
536
537         snapshot = stasis_message_data(message);
538         if (!snapshot) {
539                 return NULL;
540         }
541         ao2_ref(snapshot, +1);
542         return snapshot;
543 }
544
545 struct ast_channel_snapshot *ast_channel_snapshot_get_latest_by_name(const char *name)
546 {
547         RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
548         struct ast_channel_snapshot *snapshot;
549
550         ast_assert(!ast_strlen_zero(name));
551
552         message = stasis_cache_get(ast_channel_cache_by_name(),
553                         ast_channel_snapshot_type(),
554                         name);
555         if (!message) {
556                 return NULL;
557         }
558
559         snapshot = stasis_message_data(message);
560         if (!snapshot) {
561                 return NULL;
562         }
563         ao2_ref(snapshot, +1);
564         return snapshot;
565 }
566
567 static void channel_role_snapshot_dtor(void *obj)
568 {
569         struct channel_role_snapshot *role_snapshot = obj;
570         ao2_cleanup(role_snapshot->snapshot);
571 }
572
573 void ast_multi_channel_blob_add_channel(struct ast_multi_channel_blob *obj, const char *role, struct ast_channel_snapshot *snapshot)
574 {
575         RAII_VAR(struct channel_role_snapshot *, role_snapshot, NULL, ao2_cleanup);
576         int role_len = strlen(role) + 1;
577
578         if (!obj || ast_strlen_zero(role) || !snapshot) {
579                 return;
580         }
581
582         role_snapshot = ao2_alloc(sizeof(*role_snapshot) + role_len, channel_role_snapshot_dtor);
583         if (!role_snapshot) {
584                 return;
585         }
586         ast_copy_string(role_snapshot->role, role, role_len);
587         role_snapshot->snapshot = snapshot;
588         ao2_ref(role_snapshot->snapshot, +1);
589         ao2_link(obj->channel_snapshots, role_snapshot);
590 }
591
592 struct ast_channel_snapshot *ast_multi_channel_blob_get_channel(struct ast_multi_channel_blob *obj, const char *role)
593 {
594         struct channel_role_snapshot *role_snapshot;
595
596         if (!obj || ast_strlen_zero(role)) {
597                 return NULL;
598         }
599         role_snapshot = ao2_find(obj->channel_snapshots, role, OBJ_KEY);
600         /* Note that this function does not increase the ref count on snapshot */
601         if (!role_snapshot) {
602                 return NULL;
603         }
604         ao2_ref(role_snapshot, -1);
605         return role_snapshot->snapshot;
606 }
607
608 struct ao2_container *ast_multi_channel_blob_get_channels(struct ast_multi_channel_blob *obj, const char *role)
609 {
610         RAII_VAR(struct ao2_container *, ret_container,
611                 ao2_container_alloc(NUM_MULTI_CHANNEL_BLOB_BUCKETS, channel_snapshot_hash_cb, channel_snapshot_cmp_cb),
612                 ao2_cleanup);
613         struct ao2_iterator *it_role_snapshots;
614         struct channel_role_snapshot *role_snapshot;
615         char *arg;
616
617         if (!obj || ast_strlen_zero(role) || !ret_container) {
618                 return NULL;
619         }
620         arg = ast_strdupa(role);
621
622         it_role_snapshots = ao2_callback(obj->channel_snapshots, OBJ_MULTIPLE | OBJ_KEY, channel_role_multi_cmp_cb, arg);
623         if (!it_role_snapshots) {
624                 return NULL;
625         }
626
627         while ((role_snapshot = ao2_iterator_next(it_role_snapshots))) {
628                 ao2_link(ret_container, role_snapshot->snapshot);
629                 ao2_ref(role_snapshot, -1);
630         }
631         ao2_iterator_destroy(it_role_snapshots);
632
633         ao2_ref(ret_container, +1);
634         return ret_container;
635 }
636
637 struct ast_json *ast_multi_channel_blob_get_json(struct ast_multi_channel_blob *obj)
638 {
639         if (!obj) {
640                 return NULL;
641         }
642         return obj->blob;
643 }
644
645 void ast_channel_stage_snapshot(struct ast_channel *chan)
646 {
647         ast_set_flag(ast_channel_flags(chan), AST_FLAG_SNAPSHOT_STAGE);
648 }
649
650 void ast_channel_stage_snapshot_done(struct ast_channel *chan)
651 {
652         ast_clear_flag(ast_channel_flags(chan), AST_FLAG_SNAPSHOT_STAGE);
653         ast_channel_publish_snapshot(chan);
654 }
655
656 void ast_channel_publish_snapshot(struct ast_channel *chan)
657 {
658         RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
659         RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
660
661         if (!ast_channel_snapshot_type()) {
662                 return;
663         }
664
665         if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_SNAPSHOT_STAGE)) {
666                 return;
667         }
668
669         snapshot = ast_channel_snapshot_create(chan);
670         if (!snapshot) {
671                 return;
672         }
673
674         message = stasis_message_create(ast_channel_snapshot_type(), snapshot);
675         if (!message) {
676                 return;
677         }
678
679         ast_assert(ast_channel_topic(chan) != NULL);
680         stasis_publish(ast_channel_topic(chan), message);
681 }
682
683 void ast_channel_publish_cached_blob(struct ast_channel *chan, struct stasis_message_type *type, struct ast_json *blob)
684 {
685         struct stasis_message *message;
686
687         if (!blob) {
688                 blob = ast_json_null();
689         }
690
691         message = ast_channel_blob_create_from_cache(ast_channel_uniqueid(chan), type, blob);
692         if (message) {
693                 stasis_publish(ast_channel_topic(chan), message);
694         }
695         ao2_cleanup(message);
696 }
697
698 void ast_channel_publish_blob(struct ast_channel *chan, struct stasis_message_type *type, struct ast_json *blob)
699 {
700         struct stasis_message *message;
701
702         if (!blob) {
703                 blob = ast_json_null();
704         }
705
706         message = ast_channel_blob_create(chan, type, blob);
707         if (message) {
708                 stasis_publish(ast_channel_topic(chan), message);
709         }
710         ao2_cleanup(message);
711 }
712
713 void ast_channel_publish_varset(struct ast_channel *chan, const char *name, const char *value)
714 {
715         struct ast_json *blob;
716
717         ast_assert(name != NULL);
718         ast_assert(value != NULL);
719
720         blob = ast_json_pack("{s: s, s: s}",
721                              "variable", name,
722                              "value", value);
723         if (!blob) {
724                 ast_log(LOG_ERROR, "Error creating message\n");
725                 return;
726         }
727
728         /*! If there are manager variables, force a cache update */
729         if (chan && ast_channel_has_manager_vars()) {
730                 ast_channel_publish_snapshot(chan);
731         }
732
733         if (chan) {
734                 ast_channel_publish_cached_blob(chan, ast_channel_varset_type(), blob);
735         } else {
736                 /* This function is NULL safe for global variables */
737                 ast_channel_publish_blob(NULL, ast_channel_varset_type(), blob);
738         }
739
740         ast_json_unref(blob);
741 }
742
743 static struct ast_manager_event_blob *varset_to_ami(struct stasis_message *msg)
744 {
745         RAII_VAR(struct ast_str *, channel_event_string, NULL, ast_free);
746         struct ast_channel_blob *obj = stasis_message_data(msg);
747         const char *variable =
748                 ast_json_string_get(ast_json_object_get(obj->blob, "variable"));
749         const char *value =
750                 ast_json_string_get(ast_json_object_get(obj->blob, "value"));
751
752         if (obj->snapshot) {
753                 channel_event_string =
754                         ast_manager_build_channel_state_string(obj->snapshot);
755         } else {
756                 channel_event_string = ast_str_create(35);
757                 ast_str_set(&channel_event_string, 0,
758                             "Channel: none\r\n"
759                             "Uniqueid: none\r\n");
760         }
761
762         if (!channel_event_string) {
763                 return NULL;
764         }
765
766         return ast_manager_event_blob_create(EVENT_FLAG_DIALPLAN, "VarSet",
767                 "%s"
768                 "Variable: %s\r\n"
769                 "Value: %s\r\n",
770                 ast_str_buffer(channel_event_string), variable, value);
771 }
772
773 static struct ast_manager_event_blob *agent_login_to_ami(struct stasis_message *msg)
774 {
775         RAII_VAR(struct ast_str *, channel_string, NULL, ast_free);
776         struct ast_channel_blob *obj = stasis_message_data(msg);
777         const char *agent = ast_json_string_get(ast_json_object_get(obj->blob, "agent"));
778
779         channel_string = ast_manager_build_channel_state_string(obj->snapshot);
780         if (!channel_string) {
781                 return NULL;
782         }
783
784         return ast_manager_event_blob_create(EVENT_FLAG_AGENT, "AgentLogin",
785                 "%s"
786                 "Agent: %s\r\n",
787                 ast_str_buffer(channel_string), agent);
788 }
789
790 static struct ast_manager_event_blob *agent_logoff_to_ami(struct stasis_message *msg)
791 {
792         RAII_VAR(struct ast_str *, channel_string, NULL, ast_free);
793         struct ast_channel_blob *obj = stasis_message_data(msg);
794         const char *agent = ast_json_string_get(ast_json_object_get(obj->blob, "agent"));
795         long logintime = ast_json_integer_get(ast_json_object_get(obj->blob, "logintime"));
796
797         channel_string = ast_manager_build_channel_state_string(obj->snapshot);
798         if (!channel_string) {
799                 return NULL;
800         }
801
802         return ast_manager_event_blob_create(EVENT_FLAG_AGENT, "AgentLogoff",
803                 "%s"
804                 "Agent: %s\r\n"
805                 "Logintime: %ld\r\n",
806                 ast_str_buffer(channel_string), agent, logintime);
807 }
808
809 void ast_publish_channel_state(struct ast_channel *chan)
810 {
811         RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
812         RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
813
814         if (!ast_channel_snapshot_type()) {
815                 return;
816         }
817
818         ast_assert(chan != NULL);
819         if (!chan) {
820                 return;
821         }
822
823         snapshot = ast_channel_snapshot_create(chan);
824         if (!snapshot) {
825                 return;
826         }
827
828         message = stasis_message_create(ast_channel_snapshot_type(), snapshot);
829         if (!message) {
830                 return;
831         }
832
833         ast_assert(ast_channel_topic(chan) != NULL);
834         stasis_publish(ast_channel_topic(chan), message);
835 }
836
837 struct ast_json *ast_channel_snapshot_to_json(
838         const struct ast_channel_snapshot *snapshot,
839         const struct stasis_message_sanitizer *sanitize)
840 {
841         RAII_VAR(struct ast_json *, json_chan, NULL, ast_json_unref);
842
843         if (snapshot == NULL
844                 || (sanitize && sanitize->channel_snapshot
845                 && sanitize->channel_snapshot(snapshot))) {
846                 return NULL;
847         }
848
849         json_chan = ast_json_pack(
850                 /* Broken up into groups of three for readability */
851                 "{ s: s, s: s, s: s,"
852                 "  s: o, s: o, s: s,"
853                 "  s: o, s: o }",
854                 /* First line */
855                 "id", snapshot->uniqueid,
856                 "name", snapshot->name,
857                 "state", ast_state2str(snapshot->state),
858                 /* Second line */
859                 "caller", ast_json_name_number(
860                         snapshot->caller_name, snapshot->caller_number),
861                 "connected", ast_json_name_number(
862                         snapshot->connected_name, snapshot->connected_number),
863                 "accountcode", snapshot->accountcode,
864                 /* Third line */
865                 "dialplan", ast_json_dialplan_cep(
866                         snapshot->context, snapshot->exten, snapshot->priority),
867                 "creationtime", ast_json_timeval(snapshot->creationtime, NULL));
868
869         return ast_json_ref(json_chan);
870 }
871
872 int ast_channel_snapshot_cep_equal(
873         const struct ast_channel_snapshot *old_snapshot,
874         const struct ast_channel_snapshot *new_snapshot)
875 {
876         ast_assert(old_snapshot != NULL);
877         ast_assert(new_snapshot != NULL);
878
879         /* We actually get some snapshots with CEP set, but before the
880          * application is set. Since empty application is invalid, we treat
881          * setting the application from nothing as a CEP change.
882          */
883         if (ast_strlen_zero(old_snapshot->appl) &&
884             !ast_strlen_zero(new_snapshot->appl)) {
885                 return 0;
886         }
887
888         return old_snapshot->priority == new_snapshot->priority &&
889                 strcmp(old_snapshot->context, new_snapshot->context) == 0 &&
890                 strcmp(old_snapshot->exten, new_snapshot->exten) == 0;
891 }
892
893 int ast_channel_snapshot_caller_id_equal(
894         const struct ast_channel_snapshot *old_snapshot,
895         const struct ast_channel_snapshot *new_snapshot)
896 {
897         ast_assert(old_snapshot != NULL);
898         ast_assert(new_snapshot != NULL);
899         return strcmp(old_snapshot->caller_number, new_snapshot->caller_number) == 0 &&
900                 strcmp(old_snapshot->caller_name, new_snapshot->caller_name) == 0;
901 }
902
903 static struct ast_json *channel_blob_to_json(
904         struct stasis_message *message,
905         const char *type,
906         const struct stasis_message_sanitizer *sanitize)
907 {
908         RAII_VAR(struct ast_json *, out, NULL, ast_json_unref);
909         struct ast_channel_blob *channel_blob = stasis_message_data(message);
910         struct ast_json *blob = channel_blob->blob;
911         struct ast_channel_snapshot *snapshot = channel_blob->snapshot;
912         const struct timeval *tv = stasis_message_timestamp(message);
913         int res = 0;
914
915         if (blob == NULL || ast_json_is_null(blob)) {
916                 out = ast_json_object_create();
917         } else {
918                 /* blobs are immutable, so shallow copies are fine */
919                 out = ast_json_copy(blob);
920         }
921
922         if (!out) {
923                 return NULL;
924         }
925
926         res |= ast_json_object_set(out, "type", ast_json_string_create(type));
927         res |= ast_json_object_set(out, "timestamp",
928                 ast_json_timeval(*tv, NULL));
929
930         /* For global channel messages, the snapshot is optional */
931         if (snapshot) {
932                 struct ast_json *json_channel = ast_channel_snapshot_to_json(snapshot, sanitize);
933
934                 if (!json_channel) {
935                         return NULL;
936                 }
937
938                 res |= ast_json_object_set(out, "channel", json_channel);
939         }
940
941         if (res != 0) {
942                 return NULL;
943         }
944
945         return ast_json_ref(out);
946 }
947
948 static struct ast_json *dtmf_end_to_json(
949         struct stasis_message *message,
950         const struct stasis_message_sanitizer *sanitize)
951 {
952         struct ast_channel_blob *channel_blob = stasis_message_data(message);
953         struct ast_json *blob = channel_blob->blob;
954         struct ast_channel_snapshot *snapshot = channel_blob->snapshot;
955         const char *direction =
956                 ast_json_string_get(ast_json_object_get(blob, "direction"));
957         const struct timeval *tv = stasis_message_timestamp(message);
958         struct ast_json *json_channel = ast_channel_snapshot_to_json(snapshot, sanitize);
959
960         /* Only present received DTMF end events as JSON */
961         if (strcasecmp("Received", direction) != 0) {
962                 return NULL;
963         }
964
965         if (!json_channel) {
966                 return NULL;
967         }
968
969         return ast_json_pack("{s: s, s: o, s: O, s: O, s: o}",
970                 "type", "ChannelDtmfReceived",
971                 "timestamp", ast_json_timeval(*tv, NULL),
972                 "digit", ast_json_object_get(blob, "digit"),
973                 "duration_ms", ast_json_object_get(blob, "duration_ms"),
974                 "channel", json_channel);
975 }
976
977 static struct ast_json *varset_to_json(
978         struct stasis_message *message,
979         const struct stasis_message_sanitizer *sanitize)
980 {
981         return channel_blob_to_json(message, "ChannelVarset", sanitize);
982 }
983
984 static struct ast_json *hangup_request_to_json(
985         struct stasis_message *message,
986         const struct stasis_message_sanitizer *sanitize)
987 {
988         return channel_blob_to_json(message, "ChannelHangupRequest", sanitize);
989 }
990
991 static struct ast_json *dial_to_json(
992         struct stasis_message *message,
993         const struct stasis_message_sanitizer *sanitize)
994 {
995         struct ast_multi_channel_blob *payload = stasis_message_data(message);
996         struct ast_json *blob = ast_multi_channel_blob_get_json(payload);
997         struct ast_json *caller_json = ast_channel_snapshot_to_json(ast_multi_channel_blob_get_channel(payload, "caller"), sanitize);
998         struct ast_json *peer_json = ast_channel_snapshot_to_json(ast_multi_channel_blob_get_channel(payload, "peer"), sanitize);
999         struct ast_json *forwarded_json = ast_channel_snapshot_to_json(ast_multi_channel_blob_get_channel(payload, "forwarded"), sanitize);
1000         struct ast_json *json;
1001         const struct timeval *tv = stasis_message_timestamp(message);
1002         int res = 0;
1003
1004         json = ast_json_pack("{s: s, s: o, s: O, s: O, s: O}",
1005                 "type", "Dial",
1006                 "timestamp", ast_json_timeval(*tv, NULL),
1007                 "dialstatus", ast_json_object_get(blob, "dialstatus"),
1008                 "forward", ast_json_object_get(blob, "forward"),
1009                 "dialstring", ast_json_object_get(blob, "dialstring"));
1010         if (!json) {
1011                 ast_json_unref(caller_json);
1012                 ast_json_unref(peer_json);
1013                 ast_json_unref(forwarded_json);
1014                 return NULL;
1015         }
1016
1017         if (caller_json) {
1018                 res |= ast_json_object_set(json, "caller", caller_json);
1019         }
1020         if (peer_json) {
1021                 res |= ast_json_object_set(json, "peer", peer_json);
1022         }
1023         if (forwarded_json) {
1024                 res |= ast_json_object_set(json, "forwarded", forwarded_json);
1025         }
1026
1027         if (res) {
1028                 ast_json_unref(json);
1029                 return NULL;
1030         }
1031
1032         return json;
1033 }
1034
1035 static struct ast_manager_event_blob *talking_start_to_ami(struct stasis_message *msg)
1036 {
1037         struct ast_str *channel_string;
1038         struct ast_channel_blob *obj = stasis_message_data(msg);
1039         struct ast_manager_event_blob *blob;
1040
1041         channel_string = ast_manager_build_channel_state_string(obj->snapshot);
1042         if (!channel_string) {
1043                 return NULL;
1044         }
1045
1046         blob = ast_manager_event_blob_create(EVENT_FLAG_CALL, "ChannelTalkingStart",
1047                                              "%s", ast_str_buffer(channel_string));
1048         ast_free(channel_string);
1049
1050         return blob;
1051 }
1052
1053 static struct ast_json *talking_start_to_json(struct stasis_message *message,
1054         const struct stasis_message_sanitizer *sanitize)
1055 {
1056         return channel_blob_to_json(message, "ChannelTalkingStarted", sanitize);
1057 }
1058
1059 static struct ast_manager_event_blob *talking_stop_to_ami(struct stasis_message *msg)
1060 {
1061         struct ast_str *channel_string;
1062         struct ast_channel_blob *obj = stasis_message_data(msg);
1063         int duration = ast_json_integer_get(ast_json_object_get(obj->blob, "duration"));
1064         struct ast_manager_event_blob *blob;
1065
1066         channel_string = ast_manager_build_channel_state_string(obj->snapshot);
1067         if (!channel_string) {
1068                 return NULL;
1069         }
1070
1071         blob = ast_manager_event_blob_create(EVENT_FLAG_CALL, "ChannelTalkingStop",
1072                                              "%s"
1073                                              "Duration: %d\r\n",
1074                                              ast_str_buffer(channel_string),
1075                                              duration);
1076         ast_free(channel_string);
1077
1078         return blob;
1079 }
1080
1081 static struct ast_json *talking_stop_to_json(struct stasis_message *message,
1082         const struct stasis_message_sanitizer *sanitize)
1083 {
1084         return channel_blob_to_json(message, "ChannelTalkingFinished", sanitize);
1085 }
1086
1087 /*!
1088  * @{ \brief Define channel message types.
1089  */
1090 STASIS_MESSAGE_TYPE_DEFN(ast_channel_snapshot_type);
1091 STASIS_MESSAGE_TYPE_DEFN(ast_channel_dial_type,
1092         .to_json = dial_to_json,
1093         );
1094 STASIS_MESSAGE_TYPE_DEFN(ast_channel_varset_type,
1095         .to_ami = varset_to_ami,
1096         .to_json = varset_to_json,
1097         );
1098 STASIS_MESSAGE_TYPE_DEFN(ast_channel_hangup_request_type,
1099         .to_json = hangup_request_to_json,
1100         );
1101 STASIS_MESSAGE_TYPE_DEFN(ast_channel_dtmf_begin_type);
1102 STASIS_MESSAGE_TYPE_DEFN(ast_channel_dtmf_end_type,
1103         .to_json = dtmf_end_to_json,
1104         );
1105 STASIS_MESSAGE_TYPE_DEFN(ast_channel_hold_type);
1106 STASIS_MESSAGE_TYPE_DEFN(ast_channel_unhold_type);
1107 STASIS_MESSAGE_TYPE_DEFN(ast_channel_chanspy_start_type);
1108 STASIS_MESSAGE_TYPE_DEFN(ast_channel_chanspy_stop_type);
1109 STASIS_MESSAGE_TYPE_DEFN(ast_channel_fax_type);
1110 STASIS_MESSAGE_TYPE_DEFN(ast_channel_hangup_handler_type);
1111 STASIS_MESSAGE_TYPE_DEFN(ast_channel_moh_start_type);
1112 STASIS_MESSAGE_TYPE_DEFN(ast_channel_moh_stop_type);
1113 STASIS_MESSAGE_TYPE_DEFN(ast_channel_monitor_start_type);
1114 STASIS_MESSAGE_TYPE_DEFN(ast_channel_monitor_stop_type);
1115 STASIS_MESSAGE_TYPE_DEFN(ast_channel_agent_login_type,
1116         .to_ami = agent_login_to_ami,
1117         );
1118 STASIS_MESSAGE_TYPE_DEFN(ast_channel_agent_logoff_type,
1119         .to_ami = agent_logoff_to_ami,
1120         );
1121 STASIS_MESSAGE_TYPE_DEFN(ast_channel_talking_start,
1122         .to_ami = talking_start_to_ami,
1123         .to_json = talking_start_to_json,
1124         );
1125 STASIS_MESSAGE_TYPE_DEFN(ast_channel_talking_stop,
1126         .to_ami = talking_stop_to_ami,
1127         .to_json = talking_stop_to_json,
1128         );
1129
1130 /*! @} */
1131
1132 static void stasis_channels_cleanup(void)
1133 {
1134         stasis_caching_unsubscribe_and_join(channel_by_name_topic);
1135         channel_by_name_topic = NULL;
1136         ao2_cleanup(channel_cache_by_name);
1137         channel_cache_by_name = NULL;
1138         ao2_cleanup(channel_cache_all);
1139         channel_cache_all = NULL;
1140
1141         STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_snapshot_type);
1142         STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_dial_type);
1143         STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_varset_type);
1144         STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_hangup_request_type);
1145         STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_dtmf_begin_type);
1146         STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_dtmf_end_type);
1147         STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_hold_type);
1148         STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_unhold_type);
1149         STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_chanspy_start_type);
1150         STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_chanspy_stop_type);
1151         STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_fax_type);
1152         STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_hangup_handler_type);
1153         STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_moh_start_type);
1154         STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_moh_stop_type);
1155         STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_monitor_start_type);
1156         STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_monitor_stop_type);
1157         STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_agent_login_type);
1158         STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_agent_logoff_type);
1159         STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_talking_start);
1160         STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_talking_stop);
1161 }
1162
1163 int ast_stasis_channels_init(void)
1164 {
1165         int res = 0;
1166
1167         ast_register_cleanup(stasis_channels_cleanup);
1168
1169         channel_cache_all = stasis_cp_all_create("ast_channel_topic_all",
1170                 channel_snapshot_get_id);
1171         if (!channel_cache_all) {
1172                 return -1;
1173         }
1174         res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_agent_login_type);
1175         res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_agent_logoff_type);
1176
1177         channel_cache_by_name = stasis_cache_create(channel_snapshot_get_name);
1178         if (!channel_cache_by_name) {
1179                 return -1;
1180         }
1181
1182         /* This should be initialized before the caching topic */
1183         res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_snapshot_type);
1184
1185         channel_by_name_topic = stasis_caching_topic_create(
1186                 stasis_cp_all_topic(channel_cache_all),
1187                 channel_cache_by_name);
1188         if (!channel_by_name_topic) {
1189                 return -1;
1190         }
1191
1192         res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_dial_type);
1193         res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_varset_type);
1194         res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_hangup_request_type);
1195         res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_dtmf_begin_type);
1196         res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_dtmf_end_type);
1197         res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_hold_type);
1198         res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_unhold_type);
1199         res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_chanspy_start_type);
1200         res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_chanspy_stop_type);
1201         res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_fax_type);
1202         res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_hangup_handler_type);
1203         res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_moh_start_type);
1204         res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_moh_stop_type);
1205         res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_monitor_start_type);
1206         res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_monitor_stop_type);
1207         res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_talking_start);
1208         res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_talking_stop);
1209
1210         return res;
1211 }
1212