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