fix permissions of created recordings (issue #6067)
[asterisk/asterisk.git] / apps / app_chanspy.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2005 Anthony Minessale II (anthmct@yahoo.com)
5  *
6  * Disclaimed to Digium
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  * \brief ChanSpy: Listen in on any channel.
21  * 
22  * \ingroup applications
23  */
24
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <unistd.h>
29 #include <ctype.h>
30
31 #include "asterisk.h"
32
33 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
34
35 #include "asterisk/file.h"
36 #include "asterisk/logger.h"
37 #include "asterisk/channel.h"
38 #include "asterisk/chanspy.h"
39 #include "asterisk/features.h"
40 #include "asterisk/options.h"
41 #include "asterisk/app.h"
42 #include "asterisk/utils.h"
43 #include "asterisk/say.h"
44 #include "asterisk/pbx.h"
45 #include "asterisk/translate.h"
46 #include "asterisk/module.h"
47 #include "asterisk/lock.h"
48
49 AST_MUTEX_DEFINE_STATIC(modlock);
50
51 #define AST_NAME_STRLEN 256
52 #define ALL_DONE(u, ret) LOCAL_USER_REMOVE(u); return ret;
53 #define get_volfactor(x) x ? ((x > 0) ? (1 << x) : ((1 << abs(x)) * -1)) : 0
54
55 static const char *synopsis = "Listen to the audio of an active channel\n";
56 static const char *app = "ChanSpy";
57 static const char *desc = 
58 "  ChanSpy([chanprefix][|options]): This application is used to listen to the\n"
59 "audio from an active Asterisk channel. This includes the audio coming in and\n"
60 "out of the channel being spied on. If the 'chanprefix' parameter is specified,\n"
61 "only channels beginning with this string will be spied upon.\n"
62 "  While Spying, the following actions may be performed:\n"
63 "    - Dialing # cycles the volume level.\n"
64 "    - Dialing * will stop spying and look for another channel to spy on.\n"
65 "    - Dialing a series of digits followed by # builds a channel name to append\n"
66 "      to 'chanprefix'. For example, executing ChanSpy(Agent) and then dialing\n"
67 "      the digits '1234#' while spying will begin spying on the channel,\n"
68 "      'Agent/1234'.\n"
69 "  Options:\n"
70 "    b - Only spy on channels involved in a bridged call.\n"
71 "    g(grp) - Match only channels where their ${SPYGROUP} variable is set to\n"
72 "             'grp'.\n"
73 "    q - Don't play a beep when beginning to spy on a channel.\n"
74 "    r[(basename)] - Record the session to the monitor spool directory. An\n"
75 "                    optional base for the filename may be specified. The\n"
76 "                    default is 'chanspy'.\n"
77 "    v([value]) - Adjust the initial volume in the range from -4 to 4. A\n"
78 "                 negative value refers to a quieter setting.\n"
79 ;
80
81 static const char *chanspy_spy_type = "ChanSpy";
82
83 enum {
84         OPTION_QUIET     = (1 << 0),    /* Quiet, no announcement */
85         OPTION_BRIDGED   = (1 << 1),    /* Only look at bridged calls */
86         OPTION_VOLUME    = (1 << 2),    /* Specify initial volume */
87         OPTION_GROUP     = (1 << 3),    /* Only look at channels in group */
88         OPTION_RECORD    = (1 << 4),    /* Record */
89 } chanspy_opt_flags;
90
91 enum {
92         OPT_ARG_VOLUME = 0,
93         OPT_ARG_GROUP,
94         OPT_ARG_RECORD,
95         OPT_ARG_ARRAY_SIZE,
96 } chanspy_opt_args;
97
98 AST_APP_OPTIONS(chanspy_opts, {
99         AST_APP_OPTION('q', OPTION_QUIET),
100         AST_APP_OPTION('b', OPTION_BRIDGED),
101         AST_APP_OPTION_ARG('v', OPTION_VOLUME, OPT_ARG_VOLUME),
102         AST_APP_OPTION_ARG('g', OPTION_GROUP, OPT_ARG_GROUP),
103         AST_APP_OPTION_ARG('r', OPTION_RECORD, OPT_ARG_RECORD),
104 });
105
106 STANDARD_LOCAL_USER;
107 LOCAL_USER_DECL;
108
109 struct chanspy_translation_helper {
110         /* spy data */
111         struct ast_channel_spy spy;
112         int fd;
113         int volfactor;
114 };
115
116 static struct ast_channel *local_channel_walk(struct ast_channel *chan) 
117 {
118         struct ast_channel *ret;
119         ast_mutex_lock(&modlock);       
120         if ((ret = ast_channel_walk_locked(chan))) {
121                 ast_mutex_unlock(&ret->lock);
122         }
123         ast_mutex_unlock(&modlock);                     
124         return ret;
125 }
126
127 static struct ast_channel *local_get_channel_begin_name(char *name) 
128 {
129         struct ast_channel *chan, *ret = NULL;
130         ast_mutex_lock(&modlock);
131         chan = local_channel_walk(NULL);
132         while (chan) {
133                 if (!strncmp(chan->name, name, strlen(name))) {
134                         ret = chan;
135                         break;
136                 }
137                 chan = local_channel_walk(chan);
138         }
139         ast_mutex_unlock(&modlock);
140         
141         return ret;
142 }
143
144 static void *spy_alloc(struct ast_channel *chan, void *data)
145 {
146         /* just store the data pointer in the channel structure */
147         return data;
148 }
149
150 static void spy_release(struct ast_channel *chan, void *data)
151 {
152         /* nothing to do */
153 }
154
155 static int spy_generate(struct ast_channel *chan, void *data, int len, int samples) 
156 {
157         struct chanspy_translation_helper *csth = data;
158         struct ast_frame *f;
159                 
160         if (csth->spy.status != CHANSPY_RUNNING)
161                 /* Channel is already gone more than likely */
162                 return -1;
163
164         ast_mutex_lock(&csth->spy.lock);
165         f = ast_channel_spy_read_frame(&csth->spy, samples);
166         ast_mutex_unlock(&csth->spy.lock);
167                 
168         if (!f)
169                 return 0;
170                 
171         if (ast_write(chan, f)) {
172                 ast_frfree(f);
173                 return -1;
174         }
175
176         if (csth->fd)
177                 write(csth->fd, f->data, f->datalen);
178
179         ast_frfree(f);
180
181         return 0;
182 }
183
184
185 static struct ast_generator spygen = {
186         .alloc = spy_alloc,
187         .release = spy_release,
188         .generate = spy_generate, 
189 };
190
191 static int start_spying(struct ast_channel *chan, struct ast_channel *spychan, struct ast_channel_spy *spy) 
192 {
193         int res;
194         struct ast_channel *peer;
195
196         ast_log(LOG_NOTICE, "Attaching %s to %s\n", spychan->name, chan->name);
197
198         ast_mutex_lock(&chan->lock);
199         res = ast_channel_spy_add(chan, spy);
200         ast_mutex_unlock(&chan->lock);
201
202         if (!res && ast_test_flag(chan, AST_FLAG_NBRIDGE) && (peer = ast_bridged_channel(chan))) {
203                 ast_softhangup(peer, AST_SOFTHANGUP_UNBRIDGE);  
204         }
205
206         return res;
207 }
208
209 static void stop_spying(struct ast_channel *chan, struct ast_channel_spy *spy) 
210 {
211         /* If our status has changed, then the channel we're spying on is gone....
212            DON'T TOUCH IT!!!  RUN AWAY!!! */
213         if (spy->status != CHANSPY_RUNNING)
214                 return;
215
216         if (!chan)
217                 return;
218
219         ast_mutex_lock(&chan->lock);
220         ast_channel_spy_remove(chan, spy);
221         ast_mutex_unlock(&chan->lock);
222 };
223
224 /* Map 'volume' levels from -4 through +4 into
225    decibel (dB) settings for channel drivers
226 */
227 static signed char volfactor_map[] = {
228         -24,
229         -18,
230         -12,
231         -6,
232         0,
233         6,
234         12,
235         18,
236         24,
237 };
238
239 /* attempt to set the desired gain adjustment via the channel driver;
240    if successful, clear it out of the csth structure so the
241    generator will not attempt to do the adjustment itself
242 */
243 static void set_volume(struct ast_channel *chan, struct chanspy_translation_helper *csth)
244 {
245         signed char volume_adjust = volfactor_map[csth->volfactor + 4];
246
247         if (!ast_channel_setoption(chan, AST_OPTION_TXGAIN, &volume_adjust, sizeof(volume_adjust), 0))
248                 csth->volfactor = 0;
249 }
250
251 static int channel_spy(struct ast_channel *chan, struct ast_channel *spyee, int *volfactor, int fd) 
252 {
253         struct chanspy_translation_helper csth;
254         int running, res = 0, x = 0;
255         char inp[24];
256         char *name=NULL;
257         struct ast_frame *f;
258
259         running = (chan && !ast_check_hangup(chan) && spyee && !ast_check_hangup(spyee));
260
261         if (running) {
262                 memset(inp, 0, sizeof(inp));
263                 name = ast_strdupa(spyee->name);
264                 if (option_verbose >= 2)
265                         ast_verbose(VERBOSE_PREFIX_2 "Spying on channel %s\n", name);
266
267                 memset(&csth, 0, sizeof(csth));
268                 ast_set_flag(&csth.spy, CHANSPY_FORMAT_AUDIO);
269                 ast_set_flag(&csth.spy, CHANSPY_TRIGGER_NONE);
270                 ast_set_flag(&csth.spy, CHANSPY_MIXAUDIO);
271                 csth.spy.type = chanspy_spy_type;
272                 csth.spy.status = CHANSPY_RUNNING;
273                 csth.spy.read_queue.format = AST_FORMAT_SLINEAR;
274                 csth.spy.write_queue.format = AST_FORMAT_SLINEAR;
275                 ast_mutex_init(&csth.spy.lock);
276                 csth.volfactor = *volfactor;
277                 set_volume(chan, &csth);
278                 csth.spy.read_vol_adjustment = csth.volfactor;
279                 csth.spy.write_vol_adjustment = csth.volfactor;
280                 csth.fd = fd;
281
282                 if (start_spying(spyee, chan, &csth.spy))
283                         running = 0;
284         }
285
286         if (running) {
287                 running = 1;
288                 ast_activate_generator(chan, &spygen, &csth);
289
290                 while (csth.spy.status == CHANSPY_RUNNING &&
291                        chan && !ast_check_hangup(chan) &&
292                        spyee &&
293                        !ast_check_hangup(spyee) &&
294                        running == 1 &&
295                        (res = ast_waitfor(chan, -1) > -1)) {
296                         if ((f = ast_read(chan))) {
297                                 res = 0;
298                                 if (f->frametype == AST_FRAME_DTMF) {
299                                         res = f->subclass;
300                                 }
301                                 ast_frfree(f);
302                                 if (!res) {
303                                         continue;
304                                 }
305                         } else {
306                                 break;
307                         }
308                         if (x == sizeof(inp)) {
309                                 x = 0;
310                         }
311                         if (res < 0) {
312                                 running = -1;
313                         }
314                         if (res == 0) {
315                                 continue;
316                         } else if (res == '*') {
317                                 running = 0; 
318                         } else if (res == '#') {
319                                 if (!ast_strlen_zero(inp)) {
320                                         running = x ? atoi(inp) : -1;
321                                         break;
322                                 } else {
323                                         (*volfactor)++;
324                                         if (*volfactor > 4) {
325                                                 *volfactor = -4;
326                                         }
327                                         if (option_verbose > 2) {
328                                                 ast_verbose(VERBOSE_PREFIX_3 "Setting spy volume on %s to %d\n", chan->name, *volfactor);
329                                         }
330                                         csth.volfactor = *volfactor;
331                                         set_volume(chan, &csth);
332                                         csth.spy.read_vol_adjustment = csth.volfactor;
333                                         csth.spy.write_vol_adjustment = csth.volfactor;
334                                 }
335                         } else if (res >= 48 && res <= 57) {
336                                 inp[x++] = res;
337                         }
338                 }
339                 ast_deactivate_generator(chan);
340                 stop_spying(spyee, &csth.spy);
341
342                 if (option_verbose >= 2) {
343                         ast_verbose(VERBOSE_PREFIX_2 "Done Spying on channel %s\n", name);
344                 }
345         } else {
346                 running = 0;
347         }
348
349         ast_mutex_destroy(&csth.spy.lock);
350
351         return running;
352 }
353
354 static int chanspy_exec(struct ast_channel *chan, void *data)
355 {
356         struct localuser *u;
357         struct ast_channel *peer=NULL, *prev=NULL;
358         char name[AST_NAME_STRLEN],
359                 peer_name[AST_NAME_STRLEN + 5],
360                 *args,
361                 *ptr = NULL,
362                 *options = NULL,
363                 *spec = NULL,
364                 *argv[5],
365                 *mygroup = NULL,
366                 *recbase = NULL;
367         int res = -1,
368                 volfactor = 0,
369                 silent = 0,
370                 argc = 0,
371                 bronly = 0,
372                 chosen = 0,
373                 count=0,
374                 waitms = 100,
375                 num = 0,
376                 oldrf = 0,
377                 oldwf = 0,
378                 fd = 0;
379         struct ast_flags flags;
380         signed char zero_volume = 0;
381
382         if (!(args = ast_strdupa((char *)data))) {
383                 ast_log(LOG_ERROR, "Out of memory!\n");
384                 return -1;
385         }
386
387         LOCAL_USER_ADD(u);
388
389         oldrf = chan->readformat;
390         oldwf = chan->writeformat;
391         if (ast_set_read_format(chan, AST_FORMAT_SLINEAR) < 0) {
392                 ast_log(LOG_ERROR, "Could Not Set Read Format.\n");
393                 LOCAL_USER_REMOVE(u);
394                 return -1;
395         }
396         
397         if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
398                 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
399                 LOCAL_USER_REMOVE(u);
400                 return -1;
401         }
402
403         ast_answer(chan);
404
405         ast_set_flag(chan, AST_FLAG_SPYING); /* so nobody can spy on us while we are spying */
406
407         if ((argc = ast_app_separate_args(args, '|', argv, sizeof(argv) / sizeof(argv[0])))) {
408                 spec = argv[0];
409                 if ( argc > 1) {
410                         options = argv[1];
411                 }
412                 if (ast_strlen_zero(spec) || !strcmp(spec, "all")) {
413                         spec = NULL;
414                 }
415         }
416         
417         if (options) {
418                 char *opts[OPT_ARG_ARRAY_SIZE];
419                 ast_app_parse_options(chanspy_opts, &flags, opts, options);
420                 if (ast_test_flag(&flags, OPTION_GROUP)) {
421                         mygroup = opts[1];
422                 }
423                 if (ast_test_flag(&flags, OPTION_RECORD)) {
424                         if (!(recbase = opts[2])) {
425                                 recbase = "chanspy";
426                         }
427                 }
428                 silent = ast_test_flag(&flags, OPTION_QUIET);
429                 bronly = ast_test_flag(&flags, OPTION_BRIDGED);
430                 if (ast_test_flag(&flags, OPTION_VOLUME) && opts[1]) {
431                         int vol;
432
433                         if ((sscanf(opts[0], "%d", &vol) != 1) || (vol > 4) || (vol < -4))
434                                 ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n");
435                         else
436                                 volfactor = vol;
437                         }
438         }
439
440         if (recbase) {
441                 char filename[512];
442                 snprintf(filename,sizeof(filename),"%s/%s.%d.raw",ast_config_AST_MONITOR_DIR, recbase, (int)time(NULL));
443                 if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0644)) <= 0) {
444                         ast_log(LOG_WARNING, "Cannot open %s for recording\n", filename);
445                         fd = 0;
446                 }
447         }
448
449         for(;;) {
450                 if (!silent) {
451                         res = ast_streamfile(chan, "beep", chan->language);
452                         if (!res)
453                                 res = ast_waitstream(chan, "");
454                         if (res < 0) {
455                                 ast_clear_flag(chan, AST_FLAG_SPYING);
456                                 break;
457                         }
458                 }
459
460                 count = 0;
461                 res = ast_waitfordigit(chan, waitms);
462                 if (res < 0) {
463                         ast_clear_flag(chan, AST_FLAG_SPYING);
464                         break;
465                 }
466                                 
467                 peer = local_channel_walk(NULL);
468                 prev=NULL;
469                 while(peer) {
470                         if (peer != chan) {
471                                 const char *group = NULL;
472                                 int igrp = 1;
473
474                                 if (peer == prev && !chosen) {
475                                         break;
476                                 }
477                                 chosen = 0;
478                                 group = pbx_builtin_getvar_helper(peer, "SPYGROUP");
479                                 if (mygroup) {
480                                         if (!group || strcmp(mygroup, group)) {
481                                                 igrp = 0;
482                                         }
483                                 }
484                                 
485                                 if (igrp && (!spec || ((strlen(spec) <= strlen(peer->name) &&
486                                                         !strncasecmp(peer->name, spec, strlen(spec)))))) {
487                                         if (peer && (!bronly || ast_bridged_channel(peer)) &&
488                                             !ast_check_hangup(peer) && !ast_test_flag(peer, AST_FLAG_SPYING)) {
489                                                 int x = 0;
490                                                 strncpy(peer_name, "spy-", 5);
491                                                 strncpy(peer_name + strlen(peer_name), peer->name, AST_NAME_STRLEN);
492                                                 ptr = strchr(peer_name, '/');
493                                                 *ptr = '\0';
494                                                 ptr++;
495                                                 for (x = 0 ; x < strlen(peer_name) ; x++) {
496                                                         if (peer_name[x] == '/') {
497                                                                 break;
498                                                         }
499                                                         peer_name[x] = tolower(peer_name[x]);
500                                                 }
501
502                                                 if (!silent) {
503                                                         if (ast_fileexists(peer_name, NULL, NULL) != -1) {
504                                                                 res = ast_streamfile(chan, peer_name, chan->language);
505                                                                 if (!res)
506                                                                         res = ast_waitstream(chan, "");
507                                                                 if (res)
508                                                                         break;
509                                                         } else
510                                                                 res = ast_say_character_str(chan, peer_name, "", chan->language);
511                                                         if ((num=atoi(ptr))) 
512                                                                 ast_say_digits(chan, atoi(ptr), "", chan->language);
513                                                 }
514                                                 count++;
515                                                 prev = peer;
516                                                 res = channel_spy(chan, peer, &volfactor, fd);
517                                                 if (res == -1) {
518                                                         break;
519                                                 } else if (res > 1 && spec) {
520                                                         snprintf(name, AST_NAME_STRLEN, "%s/%d", spec, res);
521                                                         if ((peer = local_get_channel_begin_name(name))) {
522                                                                 chosen = 1;
523                                                         }
524                                                         continue;
525                                                 }
526                                         }
527                                 }
528                         }
529                         if ((peer = local_channel_walk(peer)) == NULL) {
530                                 break;
531                         }
532                 }
533                 waitms = count ? 100 : 5000;
534         }
535         
536
537         if (fd > 0) {
538                 close(fd);
539         }
540
541         if (oldrf && ast_set_read_format(chan, oldrf) < 0) {
542                 ast_log(LOG_ERROR, "Could Not Set Read Format.\n");
543         }
544         
545         if (oldwf && ast_set_write_format(chan, oldwf) < 0) {
546                 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
547         }
548
549         ast_clear_flag(chan, AST_FLAG_SPYING);
550
551         ast_channel_setoption(chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);
552
553         ALL_DONE(u, res);
554 }
555
556 int unload_module(void)
557 {
558         int res;
559
560         res = ast_unregister_application(app);
561
562         STANDARD_HANGUP_LOCALUSERS;
563
564         return res;
565 }
566
567 int load_module(void)
568 {
569         return ast_register_application(app, chanspy_exec, synopsis, desc);
570 }
571
572 char *description(void)
573 {
574         return (char *) synopsis;
575 }
576
577 int usecount(void)
578 {
579         int res;
580         STANDARD_USECOUNT(res);
581         return res;
582 }
583
584 char *key()
585 {
586         return ASTERISK_GPL_KEY;
587 }