Remove the unsafe bridge parameter from ast_bridge_hook_callback's.
[asterisk/asterisk.git] / bridges / bridge_builtin_features.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2009, Digium, Inc.
5  *
6  * Joshua Colp <jcolp@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 Built in bridging features
22  *
23  * \author Joshua Colp <jcolp@digium.com>
24  *
25  * \ingroup bridges
26  */
27
28 /*** MODULEINFO
29         <support_level>core</support_level>
30  ***/
31
32 #include "asterisk.h"
33
34 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
35
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <sys/types.h>
40 #include <sys/stat.h>
41
42 #include "asterisk/module.h"
43 #include "asterisk/channel.h"
44 #include "asterisk/bridge.h"
45 #include "asterisk/bridge_technology.h"
46 #include "asterisk/frame.h"
47 #include "asterisk/file.h"
48 #include "asterisk/app.h"
49 #include "asterisk/astobj2.h"
50 #include "asterisk/pbx.h"
51 #include "asterisk/parking.h"
52 #include "asterisk/features_config.h"
53 #include "asterisk/monitor.h"
54 #include "asterisk/mixmonitor.h"
55 #include "asterisk/audiohook.h"
56
57 enum set_touch_variables_res {
58         SET_TOUCH_SUCCESS,
59         SET_TOUCH_UNSET,
60         SET_TOUCH_ALLOC_FAILURE,
61 };
62
63 static void set_touch_variable(enum set_touch_variables_res *res, struct ast_channel *chan, const char *var_name, char **touch)
64 {
65         const char *c_touch;
66
67         if (*res == SET_TOUCH_ALLOC_FAILURE) {
68                 return;
69         }
70         c_touch = pbx_builtin_getvar_helper(chan, var_name);
71         if (!ast_strlen_zero(c_touch)) {
72                 *touch = ast_strdup(c_touch);
73                 if (!*touch) {
74                         *res = SET_TOUCH_ALLOC_FAILURE;
75                 } else {
76                         *res = SET_TOUCH_SUCCESS;
77                 }
78         }
79 }
80
81 static enum set_touch_variables_res set_touch_variables(struct ast_channel *chan, int is_mixmonitor, char **touch_format, char **touch_monitor, char **touch_monitor_prefix)
82 {
83         enum set_touch_variables_res res = SET_TOUCH_UNSET;
84         const char *var_format;
85         const char *var_monitor;
86         const char *var_prefix;
87
88         SCOPED_CHANNELLOCK(lock, chan);
89
90         if (is_mixmonitor) {
91                 var_format = "TOUCH_MIXMONITOR_FORMAT";
92                 var_monitor = "TOUCH_MIXMONITOR";
93                 var_prefix = "TOUCH_MIXMONITOR_PREFIX";
94         } else {
95                 var_format = "TOUCH_MONITOR_FORMAT";
96                 var_monitor = "TOUCH_MONITOR";
97                 var_prefix = "TOUCH_MONITOR_PREFIX";
98         }
99         set_touch_variable(&res, chan, var_format, touch_format);
100         set_touch_variable(&res, chan, var_monitor, touch_monitor);
101         set_touch_variable(&res, chan, var_prefix, touch_monitor_prefix);
102
103         return res;
104 }
105
106 static void stop_automonitor(struct ast_bridge_channel *bridge_channel, struct ast_channel *peer_chan, struct ast_features_general_config *features_cfg, const char *stop_message)
107 {
108         ast_verb(3, "AutoMonitor used to stop recording call.\n");
109
110         ast_channel_lock(peer_chan);
111         if (ast_channel_monitor(peer_chan)) {
112                 if (ast_channel_monitor(peer_chan)->stop(peer_chan, 1)) {
113                         ast_verb(3, "Cannot stop AutoMonitor for %s\n", ast_channel_name(bridge_channel->chan));
114                         if (features_cfg && !(ast_strlen_zero(features_cfg->recordingfailsound))) {
115                                 ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->recordingfailsound, NULL);
116                         }
117                         ast_channel_unlock(peer_chan);
118                         return;
119                 }
120         } else {
121                 /* Something else removed the Monitor before we got to it. */
122                 ast_channel_unlock(peer_chan);
123                 return;
124         }
125
126         ast_channel_unlock(peer_chan);
127
128         if (features_cfg && !(ast_strlen_zero(features_cfg->courtesytone))) {
129                 ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->courtesytone, NULL);
130                 ast_bridge_channel_write_playfile(bridge_channel, NULL, features_cfg->courtesytone, NULL);
131         }
132
133         if (!ast_strlen_zero(stop_message)) {
134                 ast_bridge_channel_queue_playfile(bridge_channel, NULL, stop_message, NULL);
135                 ast_bridge_channel_write_playfile(bridge_channel, NULL, stop_message, NULL);
136         }
137 }
138
139 static void start_automonitor(struct ast_bridge_channel *bridge_channel, struct ast_channel *peer_chan, struct ast_features_general_config *features_cfg, const char *start_message)
140 {
141         char *touch_filename;
142         size_t len;
143         int x;
144         enum set_touch_variables_res set_touch_res;
145
146         RAII_VAR(char *, touch_format, NULL, ast_free);
147         RAII_VAR(char *, touch_monitor, NULL, ast_free);
148         RAII_VAR(char *, touch_monitor_prefix, NULL, ast_free);
149
150         set_touch_res = set_touch_variables(bridge_channel->chan, 0, &touch_format,
151                 &touch_monitor, &touch_monitor_prefix);
152         switch (set_touch_res) {
153         case SET_TOUCH_SUCCESS:
154                 break;
155         case SET_TOUCH_UNSET:
156                 set_touch_res = set_touch_variables(peer_chan, 0, &touch_format, &touch_monitor,
157                         &touch_monitor_prefix);
158                 if (set_touch_res == SET_TOUCH_ALLOC_FAILURE) {
159                         return;
160                 }
161                 break;
162         case SET_TOUCH_ALLOC_FAILURE:
163                 return;
164         }
165
166         if (!ast_strlen_zero(touch_monitor)) {
167                 len = strlen(touch_monitor) + 50;
168                 touch_filename = ast_alloca(len);
169                 snprintf(touch_filename, len, "%s-%ld-%s",
170                         S_OR(touch_monitor_prefix, "auto"),
171                         (long) time(NULL),
172                         touch_monitor);
173         } else {
174                 char *caller_chan_id;
175                 char *peer_chan_id;
176
177                 caller_chan_id = ast_strdupa(S_COR(ast_channel_caller(bridge_channel->chan)->id.number.valid,
178                         ast_channel_caller(bridge_channel->chan)->id.number.str, ast_channel_name(bridge_channel->chan)));
179                 peer_chan_id = ast_strdupa(S_COR(ast_channel_caller(peer_chan)->id.number.valid,
180                         ast_channel_caller(peer_chan)->id.number.str, ast_channel_name(peer_chan)));
181                 len = strlen(caller_chan_id) + strlen(peer_chan_id) + 50;
182                 touch_filename = ast_alloca(len);
183                 snprintf(touch_filename, len, "%s-%ld-%s-%s",
184                         S_OR(touch_monitor_prefix, "auto"),
185                         (long) time(NULL),
186                         caller_chan_id,
187                         peer_chan_id);
188         }
189
190         for (x = 0; x < strlen(touch_filename); x++) {
191                 if (touch_filename[x] == '/') {
192                         touch_filename[x] = '-';
193                 }
194         }
195
196         ast_verb(3, "AutoMonitor used to record call. Filename: %s\n", touch_filename);
197
198         if (ast_monitor_start(peer_chan, touch_format, touch_filename, 1, X_REC_IN | X_REC_OUT)) {
199                 ast_verb(3, "automon feature was tried by '%s' but monitor failed to start.\n",
200                         ast_channel_name(bridge_channel->chan));
201                 return;
202         }
203
204         if (features_cfg && !ast_strlen_zero(features_cfg->courtesytone)) {
205                 ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->courtesytone, NULL);
206                 ast_bridge_channel_write_playfile(bridge_channel, NULL, features_cfg->courtesytone, NULL);
207         }
208
209         if (!ast_strlen_zero(start_message)) {
210                 ast_bridge_channel_queue_playfile(bridge_channel, NULL, start_message, NULL);
211                 ast_bridge_channel_write_playfile(bridge_channel, NULL, start_message, NULL);
212         }
213
214         pbx_builtin_setvar_helper(peer_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
215 }
216
217 static int feature_automonitor(struct ast_bridge_channel *bridge_channel, void *hook_pvt)
218 {
219         const char *start_message;
220         const char *stop_message;
221         struct ast_bridge_features_automonitor *options = hook_pvt;
222         enum ast_bridge_features_monitor start_stop = options ? options->start_stop : AUTO_MONITOR_TOGGLE;
223         int is_monitoring;
224
225         RAII_VAR(struct ast_channel *, peer_chan, NULL, ast_channel_cleanup);
226         RAII_VAR(struct ast_features_general_config *, features_cfg, NULL, ao2_cleanup);
227
228         features_cfg = ast_get_chan_features_general_config(bridge_channel->chan);
229         ast_bridge_channel_lock_bridge(bridge_channel);
230         peer_chan = ast_bridge_peer_nolock(bridge_channel->bridge, bridge_channel->chan);
231         ast_bridge_unlock(bridge_channel->bridge);
232
233         if (!peer_chan) {
234                 ast_verb(3, "Cannot start AutoMonitor for %s - can not determine peer in bridge.\n",
235                         ast_channel_name(bridge_channel->chan));
236                 if (features_cfg && !ast_strlen_zero(features_cfg->recordingfailsound)) {
237                         ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->recordingfailsound, NULL);
238                 }
239                 return 0;
240         }
241
242         ast_channel_lock(bridge_channel->chan);
243         start_message = pbx_builtin_getvar_helper(bridge_channel->chan,
244                 "TOUCH_MONITOR_MESSAGE_START");
245         start_message = ast_strdupa(S_OR(start_message, ""));
246         stop_message = pbx_builtin_getvar_helper(bridge_channel->chan,
247                 "TOUCH_MONITOR_MESSAGE_STOP");
248         stop_message = ast_strdupa(S_OR(stop_message, ""));
249         ast_channel_unlock(bridge_channel->chan);
250
251         is_monitoring = ast_channel_monitor(peer_chan) != NULL;
252         switch (start_stop) {
253         case AUTO_MONITOR_TOGGLE:
254                 if (is_monitoring) {
255                         stop_automonitor(bridge_channel, peer_chan, features_cfg, stop_message);
256                 } else {
257                         start_automonitor(bridge_channel, peer_chan, features_cfg, start_message);
258                 }
259                 return 0;
260         case AUTO_MONITOR_START:
261                 if (!is_monitoring) {
262                         start_automonitor(bridge_channel, peer_chan, features_cfg, start_message);
263                         return 0;
264                 }
265                 ast_verb(3, "AutoMonitor already recording call.\n");
266                 break;
267         case AUTO_MONITOR_STOP:
268                 if (is_monitoring) {
269                         stop_automonitor(bridge_channel, peer_chan, features_cfg, stop_message);
270                         return 0;
271                 }
272                 ast_verb(3, "AutoMonitor already not recording call.\n");
273                 break;
274         }
275
276         /*
277          * Fake start/stop to invoker so will think it did something but
278          * was already in that mode.
279          */
280         if (features_cfg && !ast_strlen_zero(features_cfg->courtesytone)) {
281                 ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->courtesytone, NULL);
282         }
283         if (is_monitoring) {
284                 if (!ast_strlen_zero(start_message)) {
285                         ast_bridge_channel_queue_playfile(bridge_channel, NULL, start_message, NULL);
286                 }
287         } else {
288                 if (!ast_strlen_zero(stop_message)) {
289                         ast_bridge_channel_queue_playfile(bridge_channel, NULL, stop_message, NULL);
290                 }
291         }
292         return 0;
293 }
294
295 static void stop_automixmonitor(struct ast_bridge_channel *bridge_channel, struct ast_channel *peer_chan, struct ast_features_general_config *features_cfg, const char *stop_message)
296 {
297         ast_verb(3, "AutoMixMonitor used to stop recording call.\n");
298
299         if (ast_stop_mixmonitor(peer_chan, NULL)) {
300                 ast_verb(3, "Failed to stop Mixmonitor for %s.\n", ast_channel_name(bridge_channel->chan));
301                 if (features_cfg && !(ast_strlen_zero(features_cfg->recordingfailsound))) {
302                         ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->recordingfailsound, NULL);
303                 }
304                 return;
305         }
306
307         if (features_cfg && !ast_strlen_zero(features_cfg->courtesytone)) {
308                 ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->courtesytone, NULL);
309                 ast_bridge_channel_write_playfile(bridge_channel, NULL, features_cfg->courtesytone, NULL);
310         }
311
312         if (!ast_strlen_zero(stop_message)) {
313                 ast_bridge_channel_queue_playfile(bridge_channel, NULL, stop_message, NULL);
314                 ast_bridge_channel_write_playfile(bridge_channel, NULL, stop_message, NULL);
315         }
316 }
317
318 static void start_automixmonitor(struct ast_bridge_channel *bridge_channel, struct ast_channel *peer_chan, struct ast_features_general_config *features_cfg, const char *start_message)
319 {
320         char *touch_filename;
321         size_t len;
322         int x;
323         enum set_touch_variables_res set_touch_res;
324
325         RAII_VAR(char *, touch_format, NULL, ast_free);
326         RAII_VAR(char *, touch_monitor, NULL, ast_free);
327         RAII_VAR(char *, touch_monitor_prefix, NULL, ast_free);
328
329         set_touch_res = set_touch_variables(bridge_channel->chan, 1, &touch_format,
330                 &touch_monitor, &touch_monitor_prefix);
331         switch (set_touch_res) {
332         case SET_TOUCH_SUCCESS:
333                 break;
334         case SET_TOUCH_UNSET:
335                 set_touch_res = set_touch_variables(peer_chan, 1, &touch_format, &touch_monitor,
336                         &touch_monitor_prefix);
337                 if (set_touch_res == SET_TOUCH_ALLOC_FAILURE) {
338                         return;
339                 }
340                 break;
341         case SET_TOUCH_ALLOC_FAILURE:
342                 return;
343         }
344
345         if (!ast_strlen_zero(touch_monitor)) {
346                 len = strlen(touch_monitor) + 50;
347                 touch_filename = ast_alloca(len);
348                 snprintf(touch_filename, len, "%s-%ld-%s.%s",
349                         S_OR(touch_monitor_prefix, "auto"),
350                         (long) time(NULL),
351                         touch_monitor,
352                         S_OR(touch_format, "wav"));
353         } else {
354                 char *caller_chan_id;
355                 char *peer_chan_id;
356
357                 caller_chan_id = ast_strdupa(S_COR(ast_channel_caller(bridge_channel->chan)->id.number.valid,
358                         ast_channel_caller(bridge_channel->chan)->id.number.str, ast_channel_name(bridge_channel->chan)));
359                 peer_chan_id = ast_strdupa(S_COR(ast_channel_caller(peer_chan)->id.number.valid,
360                         ast_channel_caller(peer_chan)->id.number.str, ast_channel_name(peer_chan)));
361                 len = strlen(caller_chan_id) + strlen(peer_chan_id) + 50;
362                 touch_filename = ast_alloca(len);
363                 snprintf(touch_filename, len, "%s-%ld-%s-%s.%s",
364                         S_OR(touch_monitor_prefix, "auto"),
365                         (long) time(NULL),
366                         caller_chan_id,
367                         peer_chan_id,
368                         S_OR(touch_format, "wav"));
369         }
370
371         for (x = 0; x < strlen(touch_filename); x++) {
372                 if (touch_filename[x] == '/') {
373                         touch_filename[x] = '-';
374                 }
375         }
376
377         ast_verb(3, "AutoMixMonitor used to record call. Filename: %s\n", touch_filename);
378
379         if (ast_start_mixmonitor(peer_chan, touch_filename, "b")) {
380                 ast_verb(3, "automixmon feature was tried by '%s' but mixmonitor failed to start.\n",
381                         ast_channel_name(bridge_channel->chan));
382
383                 if (features_cfg && !ast_strlen_zero(features_cfg->recordingfailsound)) {
384                         ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->recordingfailsound, NULL);
385                 }
386                 return;
387         }
388
389         if (features_cfg && !ast_strlen_zero(features_cfg->courtesytone)) {
390                 ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->courtesytone, NULL);
391                 ast_bridge_channel_write_playfile(bridge_channel, NULL, features_cfg->courtesytone, NULL);
392         }
393
394         if (!ast_strlen_zero(start_message)) {
395                 ast_bridge_channel_queue_playfile(bridge_channel, NULL, start_message, NULL);
396                 ast_bridge_channel_write_playfile(bridge_channel, NULL, start_message, NULL);
397         }
398
399         pbx_builtin_setvar_helper(peer_chan, "TOUCH_MIXMONITOR_OUTPUT", touch_filename);
400 }
401
402 static int feature_automixmonitor(struct ast_bridge_channel *bridge_channel, void *hook_pvt)
403 {
404         static const char *mixmonitor_spy_type = "MixMonitor";
405         const char *stop_message;
406         const char *start_message;
407         struct ast_bridge_features_automixmonitor *options = hook_pvt;
408         enum ast_bridge_features_monitor start_stop = options ? options->start_stop : AUTO_MONITOR_TOGGLE;
409         int is_monitoring;
410
411         RAII_VAR(struct ast_channel *, peer_chan, NULL, ast_channel_cleanup);
412         RAII_VAR(struct ast_features_general_config *, features_cfg, NULL, ao2_cleanup);
413
414         features_cfg = ast_get_chan_features_general_config(bridge_channel->chan);
415         ast_bridge_channel_lock_bridge(bridge_channel);
416         peer_chan = ast_bridge_peer_nolock(bridge_channel->bridge, bridge_channel->chan);
417         ast_bridge_unlock(bridge_channel->bridge);
418
419         if (!peer_chan) {
420                 ast_verb(3, "Cannot do AutoMixMonitor for %s - cannot determine peer in bridge.\n",
421                         ast_channel_name(bridge_channel->chan));
422                 if (features_cfg && !ast_strlen_zero(features_cfg->recordingfailsound)) {
423                         ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->recordingfailsound, NULL);
424                 }
425                 return 0;
426         }
427
428         ast_channel_lock(bridge_channel->chan);
429         start_message = pbx_builtin_getvar_helper(bridge_channel->chan,
430                 "TOUCH_MIXMONITOR_MESSAGE_START");
431         start_message = ast_strdupa(S_OR(start_message, ""));
432         stop_message = pbx_builtin_getvar_helper(bridge_channel->chan,
433                 "TOUCH_MIXMONITOR_MESSAGE_STOP");
434         stop_message = ast_strdupa(S_OR(stop_message, ""));
435         ast_channel_unlock(bridge_channel->chan);
436
437         is_monitoring =
438                 0 < ast_channel_audiohook_count_by_source(peer_chan, mixmonitor_spy_type, AST_AUDIOHOOK_TYPE_SPY);
439         switch (start_stop) {
440         case AUTO_MONITOR_TOGGLE:
441                 if (is_monitoring) {
442                         stop_automixmonitor(bridge_channel, peer_chan, features_cfg, stop_message);
443                 } else {
444                         start_automixmonitor(bridge_channel, peer_chan, features_cfg, start_message);
445                 }
446                 return 0;
447         case AUTO_MONITOR_START:
448                 if (!is_monitoring) {
449                         start_automixmonitor(bridge_channel, peer_chan, features_cfg, start_message);
450                         return 0;
451                 }
452                 ast_verb(3, "AutoMixMonitor already recording call.\n");
453                 break;
454         case AUTO_MONITOR_STOP:
455                 if (is_monitoring) {
456                         stop_automixmonitor(bridge_channel, peer_chan, features_cfg, stop_message);
457                         return 0;
458                 }
459                 ast_verb(3, "AutoMixMonitor already not recording call.\n");
460                 break;
461         }
462
463         /*
464          * Fake start/stop to invoker so will think it did something but
465          * was already in that mode.
466          */
467         if (features_cfg && !ast_strlen_zero(features_cfg->courtesytone)) {
468                 ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->courtesytone, NULL);
469         }
470         if (is_monitoring) {
471                 if (!ast_strlen_zero(start_message)) {
472                         ast_bridge_channel_queue_playfile(bridge_channel, NULL, start_message, NULL);
473                 }
474         } else {
475                 if (!ast_strlen_zero(stop_message)) {
476                         ast_bridge_channel_queue_playfile(bridge_channel, NULL, stop_message, NULL);
477                 }
478         }
479         return 0;
480 }
481
482 /*! \brief Internal built in feature for hangup */
483 static int feature_hangup(struct ast_bridge_channel *bridge_channel, void *hook_pvt)
484 {
485         /*
486          * This is very simple, we simply change the state on the
487          * bridge_channel to force the channel out of the bridge and the
488          * core takes care of the rest.
489          */
490         ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END);
491         return 0;
492 }
493
494 static int unload_module(void)
495 {
496         return 0;
497 }
498
499 static int load_module(void)
500 {
501         ast_bridge_features_register(AST_BRIDGE_BUILTIN_HANGUP, feature_hangup, NULL);
502         ast_bridge_features_register(AST_BRIDGE_BUILTIN_AUTOMON, feature_automonitor, NULL);
503         ast_bridge_features_register(AST_BRIDGE_BUILTIN_AUTOMIXMON, feature_automixmonitor, NULL);
504
505         /* Bump up our reference count so we can't be unloaded */
506         ast_module_ref(ast_module_info->self);
507
508         return AST_MODULE_LOAD_SUCCESS;
509 }
510
511 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Built in bridging features");