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