07b8d8d608dcb24fd4161a6be09d536b5191184b
[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  *
6  * Disclaimed to Digium
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*! \file
20  * \brief ChanSpy: Listen in on any channel.
21  * 
22  * \ingroup applications
23  */
24
25 #include <stdlib.h>
26 #include <unistd.h>
27 #include <string.h>
28 #include <ctype.h>
29
30 #include "asterisk.h"
31
32 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
33
34 #include "asterisk/file.h"
35 #include "asterisk/logger.h"
36 #include "asterisk/channel.h"
37 #include "asterisk/features.h"
38 #include "asterisk/options.h"
39 #include "asterisk/app.h"
40 #include "asterisk/utils.h"
41 #include "asterisk/say.h"
42 #include "asterisk/pbx.h"
43 #include "asterisk/translate.h"
44 #include "asterisk/module.h"
45 #include "asterisk/lock.h"
46
47 AST_MUTEX_DEFINE_STATIC(modlock);
48
49 #define AST_NAME_STRLEN 256
50 #define ALL_DONE(u, ret) LOCAL_USER_REMOVE(u); return ret;
51 #define get_volfactor(x) x ? ((x > 0) ? (1 << x) : ((1 << abs(x)) * -1)) : 0
52
53 static const char *synopsis = "Tap into any type of asterisk channel and listen to audio";
54 static const char *app = "ChanSpy";
55 static const char *desc = "   Chanspy([<scanspec>][|<options>])\n\n"
56 "Valid Options:\n"
57 " - b: bridged, only spy on channels involved in a bridged call.\n"
58 " - g(grp): enforce group.  Match only calls where their ${SPYGROUP} is 'grp'.\n"
59 " - q: quiet, don't announce channels beep, etc.\n"
60 " - r[(basename)]: Record session to monitor spool dir (with optional basename, default is 'chanspy')\n\n"
61 " - v([-4..4]): adjust the initial volume. (negative is quieter)\n"
62 "If <scanspec> is specified, only channel names *beginning* with that string will be scanned.\n"
63 "('all' or an empty string are also both valid <scanspec>)\n\n"
64 "While Spying:\n\n"
65 "Dialing # cycles the volume level.\n"
66 "Dialing * will stop spying and look for another channel to spy on.\n"
67 "Dialing a series of digits followed by # builds a channel name to append to <scanspec>\n"
68 "(e.g. run Chanspy(Agent) and dial 1234# while spying to jump to channel Agent/1234)\n\n"
69 "";
70
71 static const char *chanspy_spy_type = "ChanSpy";
72
73 enum {
74         OPTION_QUIET     = (1 << 0),    /* Quiet, no announcement */
75         OPTION_BRIDGED   = (1 << 1),    /* Only look at bridged calls */
76         OPTION_VOLUME    = (1 << 2),    /* Specify initial volume */
77         OPTION_GROUP     = (1 << 3),    /* Only look at channels in group */
78         OPTION_RECORD    = (1 << 4),    /* Record */
79 } chanspy_opt_flags;
80
81 enum {
82         OPT_ARG_VOLUME = 0,
83         OPT_ARG_GROUP,
84         OPT_ARG_RECORD,
85         OPT_ARG_ARRAY_SIZE,
86 } chanspy_opt_args;
87
88 AST_APP_OPTIONS(chanspy_opts, {
89         AST_APP_OPTION('q', OPTION_QUIET),
90         AST_APP_OPTION('b', OPTION_BRIDGED),
91         AST_APP_OPTION_ARG('v', OPTION_VOLUME, OPT_ARG_VOLUME),
92         AST_APP_OPTION_ARG('g', OPTION_GROUP, OPT_ARG_GROUP),
93         AST_APP_OPTION_ARG('r', OPTION_RECORD, OPT_ARG_RECORD),
94 });
95
96 STANDARD_LOCAL_USER;
97 LOCAL_USER_DECL;
98
99 struct chanspy_translation_helper {
100         /* spy data */
101         struct ast_channel_spy spy;
102         int fd;
103         int volfactor;
104 };
105
106 static struct ast_channel *local_channel_walk(struct ast_channel *chan) 
107 {
108         struct ast_channel *ret;
109         ast_mutex_lock(&modlock);       
110         if ((ret = ast_channel_walk_locked(chan))) {
111                 ast_mutex_unlock(&ret->lock);
112         }
113         ast_mutex_unlock(&modlock);                     
114         return ret;
115 }
116
117 static struct ast_channel *local_get_channel_begin_name(char *name) 
118 {
119         struct ast_channel *chan, *ret = NULL;
120         ast_mutex_lock(&modlock);
121         chan = local_channel_walk(NULL);
122         while (chan) {
123                 if (!strncmp(chan->name, name, strlen(name))) {
124                         ret = chan;
125                         break;
126                 }
127                 chan = local_channel_walk(chan);
128         }
129         ast_mutex_unlock(&modlock);
130         
131         return ret;
132 }
133
134 static void *spy_alloc(struct ast_channel *chan, void *data)
135 {
136         /* just store the data pointer in the channel structure */
137         return data;
138 }
139
140 static void spy_release(struct ast_channel *chan, void *data)
141 {
142         /* nothing to do */
143 }
144
145 static int spy_generate(struct ast_channel *chan, void *data, int len, int samples) 
146 {
147         struct chanspy_translation_helper *csth = data;
148         struct ast_frame *f;
149                 
150         if (csth->spy.status != CHANSPY_RUNNING)
151                 /* Channel is already gone more than likely */
152                 return -1;
153
154         ast_mutex_lock(&csth->spy.lock);
155         f = ast_channel_spy_read_frame(&csth->spy, samples);
156         ast_mutex_unlock(&csth->spy.lock);
157                 
158         if (!f)
159                 return 0;
160                 
161         if (ast_write(chan, f)) {
162                 ast_frfree(f);
163                 return -1;
164         }
165
166         if (csth->fd)
167                 write(csth->fd, f->data, f->datalen);
168
169         ast_frfree(f);
170
171         return 0;
172 }
173
174
175 static struct ast_generator spygen = {
176         .alloc = spy_alloc,
177         .release = spy_release,
178         .generate = spy_generate, 
179 };
180
181 static int start_spying(struct ast_channel *chan, struct ast_channel *spychan, struct ast_channel_spy *spy) 
182 {
183         int res;
184         struct ast_channel *peer;
185
186         ast_log(LOG_NOTICE, "Attaching %s to %s\n", spychan->name, chan->name);
187
188         ast_mutex_lock(&chan->lock);
189         res = ast_channel_spy_add(chan, spy);
190         ast_mutex_unlock(&chan->lock);
191
192         if (!res && ast_test_flag(chan, AST_FLAG_NBRIDGE) && (peer = ast_bridged_channel(chan))) {
193                 ast_softhangup(peer, AST_SOFTHANGUP_UNBRIDGE);  
194         }
195
196         return res;
197 }
198
199 static void stop_spying(struct ast_channel *chan, struct ast_channel_spy *spy) 
200 {
201         /* If our status has changed, then the channel we're spying on is gone....
202            DON'T TOUCH IT!!!  RUN AWAY!!! */
203         if (spy->status != CHANSPY_RUNNING)
204                 return;
205
206         if (!chan)
207                 return;
208
209         ast_mutex_lock(&chan->lock);
210         ast_channel_spy_remove(chan, spy);
211         ast_mutex_unlock(&chan->lock);
212 };
213
214 /* Map 'volume' levels from -4 through +4 into
215    decibel (dB) settings for channel drivers
216 */
217 static signed char volfactor_map[] = {
218         -24,
219         -18,
220         -12,
221         -6,
222         0,
223         6,
224         12,
225         18,
226         24,
227 };
228
229 /* attempt to set the desired gain adjustment via the channel driver;
230    if successful, clear it out of the csth structure so the
231    generator will not attempt to do the adjustment itself
232 */
233 static void set_volume(struct ast_channel *chan, struct chanspy_translation_helper *csth)
234 {
235         signed char volume_adjust = volfactor_map[csth->volfactor + 4];
236
237         if (!ast_channel_setoption(chan, AST_OPTION_TXGAIN, &volume_adjust, sizeof(volume_adjust), 0))
238                 csth->volfactor = 0;
239 }
240
241 static int channel_spy(struct ast_channel *chan, struct ast_channel *spyee, int *volfactor, int fd) 
242 {
243         struct chanspy_translation_helper csth;
244         int running, res = 0, x = 0;
245         char inp[24];
246         char *name=NULL;
247         struct ast_frame *f;
248
249         running = (chan && !ast_check_hangup(chan) && spyee && !ast_check_hangup(spyee));
250
251         if (running) {
252                 memset(inp, 0, sizeof(inp));
253                 name = ast_strdupa(spyee->name);
254                 if (option_verbose >= 2)
255                         ast_verbose(VERBOSE_PREFIX_2 "Spying on channel %s\n", name);
256
257                 memset(&csth, 0, sizeof(csth));
258                 ast_set_flag(&csth.spy, CHANSPY_FORMAT_AUDIO);
259                 ast_set_flag(&csth.spy, CHANSPY_TRIGGER_NONE);
260                 ast_set_flag(&csth.spy, CHANSPY_MIXAUDIO);
261                 csth.spy.type = chanspy_spy_type;
262                 csth.spy.status = CHANSPY_RUNNING;
263                 csth.spy.read_queue.format = AST_FORMAT_SLINEAR;
264                 csth.spy.write_queue.format = AST_FORMAT_SLINEAR;
265                 ast_mutex_init(&csth.spy.lock);
266                 csth.volfactor = *volfactor;
267                 set_volume(chan, &csth);
268                 csth.spy.read_vol_adjustment = csth.volfactor;
269                 csth.spy.write_vol_adjustment = csth.volfactor;
270                 csth.fd = fd;
271
272                 if (start_spying(spyee, chan, &csth.spy))
273                         running = 0;
274         }
275
276         if (running) {
277                 running = 1;
278                 ast_activate_generator(chan, &spygen, &csth);
279
280                 while (csth.spy.status == CHANSPY_RUNNING &&
281                        chan && !ast_check_hangup(chan) &&
282                        spyee &&
283                        !ast_check_hangup(spyee) &&
284                        running == 1 &&
285                        (res = ast_waitfor(chan, -1) > -1)) {
286                         if ((f = ast_read(chan))) {
287                                 res = 0;
288                                 if (f->frametype == AST_FRAME_DTMF) {
289                                         res = f->subclass;
290                                 }
291                                 ast_frfree(f);
292                                 if (!res) {
293                                         continue;
294                                 }
295                         } else {
296                                 break;
297                         }
298                         if (x == sizeof(inp)) {
299                                 x = 0;
300                         }
301                         if (res < 0) {
302                                 running = -1;
303                         }
304                         if (res == 0) {
305                                 continue;
306                         } else if (res == '*') {
307                                 running = 0; 
308                         } else if (res == '#') {
309                                 if (!ast_strlen_zero(inp)) {
310                                         running = x ? atoi(inp) : -1;
311                                         break;
312                                 } else {
313                                         (*volfactor)++;
314                                         if (*volfactor > 4) {
315                                                 *volfactor = -4;
316                                         }
317                                         if (option_verbose > 2) {
318                                                 ast_verbose(VERBOSE_PREFIX_3 "Setting spy volume on %s to %d\n", chan->name, *volfactor);
319                                         }
320                                         csth.volfactor = *volfactor;
321                                         set_volume(chan, &csth);
322                                         csth.spy.read_vol_adjustment = csth.volfactor;
323                                         csth.spy.write_vol_adjustment = csth.volfactor;
324                                 }
325                         } else if (res >= 48 && res <= 57) {
326                                 inp[x++] = res;
327                         }
328                 }
329                 ast_deactivate_generator(chan);
330                 stop_spying(spyee, &csth.spy);
331
332                 if (option_verbose >= 2) {
333                         ast_verbose(VERBOSE_PREFIX_2 "Done Spying on channel %s\n", name);
334                 }
335         } else {
336                 running = 0;
337         }
338
339         ast_mutex_destroy(&csth.spy.lock);
340
341         return running;
342 }
343
344 static int chanspy_exec(struct ast_channel *chan, void *data)
345 {
346         struct localuser *u;
347         struct ast_channel *peer=NULL, *prev=NULL;
348         char name[AST_NAME_STRLEN],
349                 peer_name[AST_NAME_STRLEN + 5],
350                 *args,
351                 *ptr = NULL,
352                 *options = NULL,
353                 *spec = NULL,
354                 *argv[5],
355                 *mygroup = NULL,
356                 *recbase = NULL;
357         int res = -1,
358                 volfactor = 0,
359                 silent = 0,
360                 argc = 0,
361                 bronly = 0,
362                 chosen = 0,
363                 count=0,
364                 waitms = 100,
365                 num = 0,
366                 oldrf = 0,
367                 oldwf = 0,
368                 fd = 0;
369         struct ast_flags flags;
370         signed char zero_volume = 0;
371
372         if (!(args = ast_strdupa((char *)data))) {
373                 ast_log(LOG_ERROR, "Out of memory!\n");
374                 return -1;
375         }
376
377         LOCAL_USER_ADD(u);
378
379         oldrf = chan->readformat;
380         oldwf = chan->writeformat;
381         if (ast_set_read_format(chan, AST_FORMAT_SLINEAR) < 0) {
382                 ast_log(LOG_ERROR, "Could Not Set Read Format.\n");
383                 LOCAL_USER_REMOVE(u);
384                 return -1;
385         }
386         
387         if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
388                 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
389                 LOCAL_USER_REMOVE(u);
390                 return -1;
391         }
392
393         ast_answer(chan);
394
395         ast_set_flag(chan, AST_FLAG_SPYING); /* so nobody can spy on us while we are spying */
396
397         if ((argc = ast_app_separate_args(args, '|', argv, sizeof(argv) / sizeof(argv[0])))) {
398                 spec = argv[0];
399                 if ( argc > 1) {
400                         options = argv[1];
401                 }
402                 if (ast_strlen_zero(spec) || !strcmp(spec, "all")) {
403                         spec = NULL;
404                 }
405         }
406         
407         if (options) {
408                 char *opts[OPT_ARG_ARRAY_SIZE];
409                 ast_app_parse_options(chanspy_opts, &flags, opts, options);
410                 if (ast_test_flag(&flags, OPTION_GROUP)) {
411                         mygroup = opts[1];
412                 }
413                 if (ast_test_flag(&flags, OPTION_RECORD)) {
414                         if (!(recbase = opts[2])) {
415                                 recbase = "chanspy";
416                         }
417                 }
418                 silent = ast_test_flag(&flags, OPTION_QUIET);
419                 bronly = ast_test_flag(&flags, OPTION_BRIDGED);
420                 if (ast_test_flag(&flags, OPTION_VOLUME) && opts[1]) {
421                         int vol;
422
423                         if ((sscanf(opts[0], "%d", &vol) != 1) || (vol > 4) || (vol < -4))
424                                 ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n");
425                         else
426                                 volfactor = vol;
427                         }
428         }
429
430         if (recbase) {
431                 char filename[512];
432                 snprintf(filename,sizeof(filename),"%s/%s.%ld.raw",ast_config_AST_MONITOR_DIR, recbase, time(NULL));
433                 if ((fd = open(filename, O_CREAT | O_WRONLY, O_TRUNC)) <= 0) {
434                         ast_log(LOG_WARNING, "Cannot open %s for recording\n", filename);
435                         fd = 0;
436                 }
437         }
438
439         for(;;) {
440                 if (!silent) {
441                         res = ast_streamfile(chan, "beep", chan->language);
442                         if (!res)
443                                 res = ast_waitstream(chan, "");
444                         if (res < 0) {
445                                 ast_clear_flag(chan, AST_FLAG_SPYING);
446                                 break;
447                         }
448                 }
449
450                 count = 0;
451                 res = ast_waitfordigit(chan, waitms);
452                 if (res < 0) {
453                         ast_clear_flag(chan, AST_FLAG_SPYING);
454                         break;
455                 }
456                                 
457                 peer = local_channel_walk(NULL);
458                 prev=NULL;
459                 while(peer) {
460                         if (peer != chan) {
461                                 char *group = NULL;
462                                 int igrp = 1;
463
464                                 if (peer == prev && !chosen) {
465                                         break;
466                                 }
467                                 chosen = 0;
468                                 group = pbx_builtin_getvar_helper(peer, "SPYGROUP");
469                                 if (mygroup) {
470                                         if (!group || strcmp(mygroup, group)) {
471                                                 igrp = 0;
472                                         }
473                                 }
474                                 
475                                 if (igrp && (!spec || ((strlen(spec) < strlen(peer->name) &&
476                                                         !strncasecmp(peer->name, spec, strlen(spec)))))) {
477                                         if (peer && (!bronly || ast_bridged_channel(peer)) &&
478                                             !ast_check_hangup(peer) && !ast_test_flag(peer, AST_FLAG_SPYING)) {
479                                                 int x = 0;
480                                                 strncpy(peer_name, "spy-", 5);
481                                                 strncpy(peer_name + strlen(peer_name), peer->name, AST_NAME_STRLEN);
482                                                 ptr = strchr(peer_name, '/');
483                                                 *ptr = '\0';
484                                                 ptr++;
485                                                 for (x = 0 ; x < strlen(peer_name) ; x++) {
486                                                         if (peer_name[x] == '/') {
487                                                                 break;
488                                                         }
489                                                         peer_name[x] = tolower(peer_name[x]);
490                                                 }
491
492                                                 if (!silent) {
493                                                         if (ast_fileexists(peer_name, NULL, NULL) != -1) {
494                                                                 res = ast_streamfile(chan, peer_name, chan->language);
495                                                                 if (!res)
496                                                                         res = ast_waitstream(chan, "");
497                                                                 if (res)
498                                                                         break;
499                                                         } else
500                                                                 res = ast_say_character_str(chan, peer_name, "", chan->language);
501                                                         if ((num=atoi(ptr))) 
502                                                                 ast_say_digits(chan, atoi(ptr), "", chan->language);
503                                                 }
504                                                 count++;
505                                                 prev = peer;
506                                                 res = channel_spy(chan, peer, &volfactor, fd);
507                                                 if (res == -1) {
508                                                         break;
509                                                 } else if (res > 1 && spec) {
510                                                         snprintf(name, AST_NAME_STRLEN, "%s/%d", spec, res);
511                                                         if ((peer = local_get_channel_begin_name(name))) {
512                                                                 chosen = 1;
513                                                         }
514                                                         continue;
515                                                 }
516                                         }
517                                 }
518                         }
519                         if ((peer = local_channel_walk(peer)) == NULL) {
520                                 break;
521                         }
522                 }
523                 waitms = count ? 100 : 5000;
524         }
525         
526
527         if (fd > 0) {
528                 close(fd);
529         }
530
531         if (oldrf && ast_set_read_format(chan, oldrf) < 0) {
532                 ast_log(LOG_ERROR, "Could Not Set Read Format.\n");
533         }
534         
535         if (oldwf && ast_set_write_format(chan, oldwf) < 0) {
536                 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
537         }
538
539         ast_clear_flag(chan, AST_FLAG_SPYING);
540
541         ast_channel_setoption(chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);
542
543         ALL_DONE(u, res);
544 }
545
546 int unload_module(void)
547 {
548         int res;
549
550         res = ast_unregister_application(app);
551
552         STANDARD_HANGUP_LOCALUSERS;
553
554         return res;
555 }
556
557 int load_module(void)
558 {
559         return ast_register_application(app, chanspy_exec, synopsis, desc);
560 }
561
562 char *description(void)
563 {
564         return (char *) synopsis;
565 }
566
567 int usecount(void)
568 {
569         int res;
570         STANDARD_USECOUNT(res);
571         return res;
572 }
573
574 char *key()
575 {
576         return ASTERISK_GPL_KEY;
577 }