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