Merged revisions 34087 via svnmerge from
[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  * A license has been granted to Digium (via disclaimer) for the use of
8  * this code.
9  *
10  * See http://www.asterisk.org for more information about
11  * the Asterisk project. Please do not directly contact
12  * any of the maintainers of this project for assistance;
13  * the project provides a web site, mailing lists and IRC
14  * channels for your use.
15  *
16  * This program is free software, distributed under the terms of
17  * the GNU General Public License Version 2. See the LICENSE file
18  * at the top of the source tree.
19  */
20
21 /*! \file
22  *
23  * \brief ChanSpy: Listen in on any channel.
24  *
25  * \author Anthony Minessale II <anthmct@yahoo.com>
26  *
27  * \ingroup applications
28  */
29
30 #include "asterisk.h"
31
32 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
33
34 #include <stdlib.h>
35 #include <stdio.h>
36 #include <string.h>
37 #include <unistd.h>
38 #include <ctype.h>
39
40 #include "asterisk/file.h"
41 #include "asterisk/logger.h"
42 #include "asterisk/channel.h"
43 #include "asterisk/chanspy.h"
44 #include "asterisk/features.h"
45 #include "asterisk/options.h"
46 #include "asterisk/app.h"
47 #include "asterisk/utils.h"
48 #include "asterisk/say.h"
49 #include "asterisk/pbx.h"
50 #include "asterisk/translate.h"
51 #include "asterisk/module.h"
52 #include "asterisk/lock.h"
53
54 AST_MUTEX_DEFINE_STATIC(modlock);
55
56 #define AST_NAME_STRLEN 256
57 #define ALL_DONE(u, ret) LOCAL_USER_REMOVE(u); return ret;
58 #define get_volfactor(x) x ? ((x > 0) ? (1 << x) : ((1 << abs(x)) * -1)) : 0
59
60 static const char *tdesc = "Listen to the audio of an active channel";
61 static const char *app = "ChanSpy";
62 static const char *desc = 
63 "  ChanSpy([chanprefix][|options]): This application is used to listen to the\n"
64 "audio from an active Asterisk channel. This includes the audio coming in and\n"
65 "out of the channel being spied on. If the 'chanprefix' parameter is specified,\n"
66 "only channels beginning with this string will be spied upon.\n"
67 "  While Spying, the following actions may be performed:\n"
68 "    - Dialing # cycles the volume level.\n"
69 "    - Dialing * will stop spying and look for another channel to spy on.\n"
70 "    - Dialing a series of digits followed by # builds a channel name to append\n"
71 "      to 'chanprefix'. For example, executing ChanSpy(Agent) and then dialing\n"
72 "      the digits '1234#' while spying will begin spying on the channel,\n"
73 "      'Agent/1234'.\n"
74 "  Options:\n"
75 "    b - Only spy on channels involved in a bridged call.\n"
76 "    g(grp) - Match only channels where their ${SPYGROUP} variable is set to\n"
77 "             contain 'grp' in an optional : delimited list.\n"
78 "    q - Don't play a beep when beginning to spy on a channel.\n"
79 "    r[(basename)] - Record the session to the monitor spool directory. An\n"
80 "                    optional base for the filename may be specified. The\n"
81 "                    default is 'chanspy'.\n"
82 "    v([value]) - Adjust the initial volume in the range from -4 to 4. A\n"
83 "                 negative value refers to a quieter setting.\n"
84 ;
85
86 static const char *chanspy_spy_type = "ChanSpy";
87
88 enum {
89         OPTION_QUIET     = (1 << 0),    /* Quiet, no announcement */
90         OPTION_BRIDGED   = (1 << 1),    /* Only look at bridged calls */
91         OPTION_VOLUME    = (1 << 2),    /* Specify initial volume */
92         OPTION_GROUP     = (1 << 3),    /* Only look at channels in group */
93         OPTION_RECORD    = (1 << 4),    /* Record */
94 } chanspy_opt_flags;
95
96 enum {
97         OPT_ARG_VOLUME = 0,
98         OPT_ARG_GROUP,
99         OPT_ARG_RECORD,
100         OPT_ARG_ARRAY_SIZE,
101 } chanspy_opt_args;
102
103 AST_APP_OPTIONS(chanspy_opts, {
104         AST_APP_OPTION('q', OPTION_QUIET),
105         AST_APP_OPTION('b', OPTION_BRIDGED),
106         AST_APP_OPTION_ARG('v', OPTION_VOLUME, OPT_ARG_VOLUME),
107         AST_APP_OPTION_ARG('g', OPTION_GROUP, OPT_ARG_GROUP),
108         AST_APP_OPTION_ARG('r', OPTION_RECORD, OPT_ARG_RECORD),
109 });
110
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_channel_lock(chan);
203         res = ast_channel_spy_add(chan, spy);
204         ast_channel_unlock(chan);
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_channel_lock(chan);
224         ast_channel_spy_remove(chan, spy);
225         ast_channel_unlock(chan);
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                                 char *groups[25] = {0};
476                                 int num_groups = 0;
477                                 char *dup_group;
478                                 
479                                 if (peer == prev && !chosen) {
480                                         break;
481                                 }
482                                 chosen = 0;
483
484                                 if (mygroup) {
485                                         int x;
486
487                                         if ((group = pbx_builtin_getvar_helper(peer, "SPYGROUP"))) {
488                                                 dup_group = ast_strdupa(group);
489                                                 num_groups = ast_app_separate_args(dup_group, ':', groups, sizeof(groups) / sizeof(groups[0]));
490                                         }
491
492                                         igrp = 0;
493                                         if (num_groups) {
494                                                 for (x = 0; x < num_groups; x++) {
495                                                         if (!strcmp(mygroup, groups[x])) {
496                                                                 igrp = 1;
497                                                                 break;
498                                                         }
499                                                 }
500                                         } 
501                                 }
502
503                                 if (igrp && (!spec || ((strlen(spec) <= strlen(peer->name) &&
504                                                         !strncasecmp(peer->name, spec, strlen(spec)))))) {
505                                         if (peer && (!bronly || ast_bridged_channel(peer)) &&
506                                             !ast_check_hangup(peer) && !ast_test_flag(peer, AST_FLAG_SPYING)) {
507                                                 int x = 0;
508                                                 strncpy(peer_name, "spy-", 5);
509                                                 strncpy(peer_name + strlen(peer_name), peer->name, AST_NAME_STRLEN);
510                                                 ptr = strchr(peer_name, '/');
511                                                 *ptr = '\0';
512                                                 ptr++;
513                                                 for (x = 0 ; x < strlen(peer_name) ; x++) {
514                                                         if (peer_name[x] == '/') {
515                                                                 break;
516                                                         }
517                                                         peer_name[x] = tolower(peer_name[x]);
518                                                 }
519
520                                                 if (!silent) {
521                                                         if (ast_fileexists(peer_name, NULL, NULL) != -1) {
522                                                                 res = ast_streamfile(chan, peer_name, chan->language);
523                                                                 if (!res)
524                                                                         res = ast_waitstream(chan, "");
525                                                                 if (res)
526                                                                         break;
527                                                         } else
528                                                                 res = ast_say_character_str(chan, peer_name, "", chan->language);
529                                                         if ((num=atoi(ptr))) 
530                                                                 ast_say_digits(chan, atoi(ptr), "", chan->language);
531                                                 }
532                                                 count++;
533                                                 prev = peer;
534                                                 res = channel_spy(chan, peer, &volfactor, fd);
535                                                 if (res == -1) {
536                                                         break;
537                                                 } else if (res > 1 && spec) {
538                                                         snprintf(name, AST_NAME_STRLEN, "%s/%d", spec, res);
539                                                         if ((peer = local_get_channel_begin_name(name))) {
540                                                                 chosen = 1;
541                                                         }
542                                                         continue;
543                                                 }
544                                         }
545                                 }
546                         }
547                         if ((peer = local_channel_walk(peer)) == NULL) {
548                                 break;
549                         }
550                 }
551                 waitms = count ? 100 : 5000;
552         }
553         
554
555         if (fd > 0) {
556                 close(fd);
557         }
558
559         if (oldrf && ast_set_read_format(chan, oldrf) < 0) {
560                 ast_log(LOG_ERROR, "Could Not Set Read Format.\n");
561         }
562         
563         if (oldwf && ast_set_write_format(chan, oldwf) < 0) {
564                 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
565         }
566
567         ast_clear_flag(chan, AST_FLAG_SPYING);
568
569         ast_channel_setoption(chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);
570
571         ALL_DONE(u, res);
572 }
573
574 static int unload_module(void *mod)
575 {
576         int res;
577
578         res = ast_unregister_application(app);
579
580         STANDARD_HANGUP_LOCALUSERS;
581
582         return res;
583 }
584
585 static int load_module(void *mod)
586 {
587         __mod_desc = mod;
588         return ast_register_application(app, chanspy_exec, tdesc, desc);
589 }
590
591 static const char *description(void)
592 {
593         return (char *) tdesc;
594 }
595
596 static const char *key(void)
597 {
598         return ASTERISK_GPL_KEY;
599 }
600
601 STD_MOD(MOD_1, NULL, NULL, NULL);