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