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