more simplification, and correct a bug i introduced in the last commit
[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, const char *spec)
318 {
319         struct ast_channel *this;
320
321         if (spec)
322                 this = ast_walk_channel_by_name_prefix_locked(last, spec, strlen(spec));
323         else
324                 this = ast_channel_walk_locked(last);
325
326         if (this)
327                 ast_channel_unlock(this);
328
329         return this;
330 }
331
332 static int common_exec(struct ast_channel *chan, const int silent, const int bronly,
333                        int volfactor, const int fd, const char *spec, const char *mygroup)
334 {
335         struct ast_channel *peer, *prev, *next;
336         char nameprefix[AST_NAME_STRLEN];
337         char peer_name[AST_NAME_STRLEN + 5];
338         signed char zero_volume = 0;
339         int waitms;
340         int res;
341         char *ptr;
342         int num;
343
344         if (chan->_state != AST_STATE_UP)
345                 ast_answer(chan);
346
347         ast_set_flag(chan, AST_FLAG_SPYING); /* so nobody can spy on us while we are spying */
348
349         waitms = 100;
350
351         for (;;) {
352                 if (!silent) {
353                         res = ast_streamfile(chan, "beep", chan->language);
354                         if (!res)
355                                 res = ast_waitstream(chan, "");
356                         else if (res < 0) {
357                                 ast_clear_flag(chan, AST_FLAG_SPYING);
358                                 break;
359                         }
360                 }
361
362                 res = ast_waitfordigit(chan, waitms);
363                 if (res < 0) {
364                         ast_clear_flag(chan, AST_FLAG_SPYING);
365                         break;
366                 }
367                                 
368                 /* reset for the next loop around, unless overridden later */
369                 waitms = 100;
370                 peer = prev = next = NULL;
371
372                 for (peer = next_channel(peer, spec);
373                      peer;
374                      prev = peer, peer = next ? next : next_channel(peer, spec), next = NULL) {
375                         const char *group;
376                         int igrp = !mygroup;
377                         char *groups[25];
378                         int num_groups = 0;
379                         char *dup_group;
380                         int x;
381                         char *s;
382                                 
383                         if (peer == prev)
384                                 break;
385
386                         if (peer == chan)
387                                 continue;
388
389                         if (mygroup) {
390                                 if ((group = pbx_builtin_getvar_helper(peer, "SPYGROUP"))) {
391                                         dup_group = ast_strdupa(group);
392                                         num_groups = ast_app_separate_args(dup_group, ':', groups,
393                                                                            sizeof(groups) / sizeof(groups[0]));
394                                 }
395                                 
396                                 for (x = 0; x < num_groups; x++) {
397                                         if (!strcmp(mygroup, groups[x])) {
398                                                 igrp = 1;
399                                                 break;
400                                         }
401                                 }
402                         }
403                         
404                         if (!igrp)
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);