remove lots of useless 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         args = ast_strdupa(data);
387
388         LOCAL_USER_ADD(u);
389
390         oldrf = chan->readformat;
391         oldwf = chan->writeformat;
392         if (ast_set_read_format(chan, AST_FORMAT_SLINEAR) < 0) {
393                 ast_log(LOG_ERROR, "Could Not Set Read Format.\n");
394                 LOCAL_USER_REMOVE(u);
395                 return -1;
396         }
397         
398         if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
399                 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
400                 LOCAL_USER_REMOVE(u);
401                 return -1;
402         }
403
404         ast_answer(chan);
405
406         ast_set_flag(chan, AST_FLAG_SPYING); /* so nobody can spy on us while we are spying */
407
408         if ((argc = ast_app_separate_args(args, '|', argv, sizeof(argv) / sizeof(argv[0])))) {
409                 spec = argv[0];
410                 if ( argc > 1) {
411                         options = argv[1];
412                 }
413                 if (ast_strlen_zero(spec) || !strcmp(spec, "all")) {
414                         spec = NULL;
415                 }
416         }
417         
418         if (options) {
419                 char *opts[OPT_ARG_ARRAY_SIZE];
420                 ast_app_parse_options(chanspy_opts, &flags, opts, options);
421                 if (ast_test_flag(&flags, OPTION_GROUP)) {
422                         mygroup = opts[1];
423                 }
424                 if (ast_test_flag(&flags, OPTION_RECORD)) {
425                         if (!(recbase = opts[2])) {
426                                 recbase = "chanspy";
427                         }
428                 }
429                 silent = ast_test_flag(&flags, OPTION_QUIET);
430                 bronly = ast_test_flag(&flags, OPTION_BRIDGED);
431                 if (ast_test_flag(&flags, OPTION_VOLUME) && opts[1]) {
432                         int vol;
433
434                         if ((sscanf(opts[0], "%d", &vol) != 1) || (vol > 4) || (vol < -4))
435                                 ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n");
436                         else
437                                 volfactor = vol;
438                         }
439         }
440
441         if (recbase) {
442                 char filename[512];
443                 snprintf(filename,sizeof(filename),"%s/%s.%d.raw",ast_config_AST_MONITOR_DIR, recbase, (int)time(NULL));
444                 if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0644)) <= 0) {
445                         ast_log(LOG_WARNING, "Cannot open %s for recording\n", filename);
446                         fd = 0;
447                 }
448         }
449
450         for(;;) {
451                 if (!silent) {
452                         res = ast_streamfile(chan, "beep", chan->language);
453                         if (!res)
454                                 res = ast_waitstream(chan, "");
455                         if (res < 0) {
456                                 ast_clear_flag(chan, AST_FLAG_SPYING);
457                                 break;
458                         }
459                 }
460
461                 count = 0;
462                 res = ast_waitfordigit(chan, waitms);
463                 if (res < 0) {
464                         ast_clear_flag(chan, AST_FLAG_SPYING);
465                         break;
466                 }
467                                 
468                 peer = local_channel_walk(NULL);
469                 prev=NULL;
470                 while(peer) {
471                         if (peer != chan) {
472                                 const char *group = NULL;
473                                 int igrp = 1;
474
475                                 if (peer == prev && !chosen) {
476                                         break;
477                                 }
478                                 chosen = 0;
479                                 group = pbx_builtin_getvar_helper(peer, "SPYGROUP");
480                                 if (mygroup) {
481                                         if (!group || strcmp(mygroup, group)) {
482                                                 igrp = 0;
483                                         }
484                                 }
485                                 
486                                 if (igrp && (!spec || ((strlen(spec) <= strlen(peer->name) &&
487                                                         !strncasecmp(peer->name, spec, strlen(spec)))))) {
488                                         if (peer && (!bronly || ast_bridged_channel(peer)) &&
489                                             !ast_check_hangup(peer) && !ast_test_flag(peer, AST_FLAG_SPYING)) {
490                                                 int x = 0;
491                                                 strncpy(peer_name, "spy-", 5);
492                                                 strncpy(peer_name + strlen(peer_name), peer->name, AST_NAME_STRLEN);
493                                                 ptr = strchr(peer_name, '/');
494                                                 *ptr = '\0';
495                                                 ptr++;
496                                                 for (x = 0 ; x < strlen(peer_name) ; x++) {
497                                                         if (peer_name[x] == '/') {
498                                                                 break;
499                                                         }
500                                                         peer_name[x] = tolower(peer_name[x]);
501                                                 }
502
503                                                 if (!silent) {
504                                                         if (ast_fileexists(peer_name, NULL, NULL) != -1) {
505                                                                 res = ast_streamfile(chan, peer_name, chan->language);
506                                                                 if (!res)
507                                                                         res = ast_waitstream(chan, "");
508                                                                 if (res)
509                                                                         break;
510                                                         } else
511                                                                 res = ast_say_character_str(chan, peer_name, "", chan->language);
512                                                         if ((num=atoi(ptr))) 
513                                                                 ast_say_digits(chan, atoi(ptr), "", chan->language);
514                                                 }
515                                                 count++;
516                                                 prev = peer;
517                                                 res = channel_spy(chan, peer, &volfactor, fd);
518                                                 if (res == -1) {
519                                                         break;
520                                                 } else if (res > 1 && spec) {
521                                                         snprintf(name, AST_NAME_STRLEN, "%s/%d", spec, res);
522                                                         if ((peer = local_get_channel_begin_name(name))) {
523                                                                 chosen = 1;
524                                                         }
525                                                         continue;
526                                                 }
527                                         }
528                                 }
529                         }
530                         if ((peer = local_channel_walk(peer)) == NULL) {
531                                 break;
532                         }
533                 }
534                 waitms = count ? 100 : 5000;
535         }
536         
537
538         if (fd > 0) {
539                 close(fd);
540         }
541
542         if (oldrf && ast_set_read_format(chan, oldrf) < 0) {
543                 ast_log(LOG_ERROR, "Could Not Set Read Format.\n");
544         }
545         
546         if (oldwf && ast_set_write_format(chan, oldwf) < 0) {
547                 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
548         }
549
550         ast_clear_flag(chan, AST_FLAG_SPYING);
551
552         ast_channel_setoption(chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);
553
554         ALL_DONE(u, res);
555 }
556
557 int unload_module(void)
558 {
559         int res;
560
561         res = ast_unregister_application(app);
562
563         STANDARD_HANGUP_LOCALUSERS;
564
565         return res;
566 }
567
568 int load_module(void)
569 {
570         return ast_register_application(app, chanspy_exec, synopsis, desc);
571 }
572
573 char *description(void)
574 {
575         return (char *) synopsis;
576 }
577
578 int usecount(void)
579 {
580         int res;
581         STANDARD_USECOUNT(res);
582         return res;
583 }
584
585 char *key()
586 {
587         return ASTERISK_GPL_KEY;
588 }