fc3f4b920e2c4d703f0eec4814390b81ff049db3
[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 a channel, and optionally whisper into it";
57 static const char *app_chan = "ChanSpy";
58 static const char *desc_chan = 
59 "  ChanSpy([chanprefix][|options]): This application is used to listen to the\n"
60 "audio from an 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 "  Note: The X option supersedes the three features above in that if a valid\n"
71 "        single digit extension exists in the correct context ChanSpy will\n"
72 "        exit to it. This also disables choosing a channel based on 'chanprefix'\n"
73 "        and a digit sequence.\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, or speak the\n"
79 "                    selected channel name.\n"
80 "    r[(basename)] - Record the session to the monitor spool directory. An\n"
81 "                    optional base for the filename may be specified. The\n"
82 "                    default is 'chanspy'.\n"
83 "    v([value])    - Adjust the initial volume in the range from -4 to 4. A\n"
84 "                    negative value refers to a quieter setting.\n"
85 "    w             - Enable 'whisper' mode, so the spying channel can talk to\n"
86 "                    the spied-on channel.\n"
87 "    W             - Enable 'private whisper' mode, so the spying channel can\n"
88 "                    talk to the spied-on channel but cannot listen to that\n"
89 "                    channel.\n"
90 "    o             - Only listen to audio coming from this channel.\n"
91 "    X             - Allow the user to exit ChanSpy to a valid single digit\n"
92 "                    numeric extension in the current context or the context\n"
93 "                    specified by the SPY_EXIT_CONTEXT channel variable. The\n"
94 "                    name of the last channel that was spied on will be stored\n"
95 "                    in the SPY_CHANNEL variable.\n"
96 ;
97
98 static const char *app_ext = "ExtenSpy";
99 static const char *desc_ext = 
100 "  ExtenSpy(exten[@context][|options]): This application is used to listen to the\n"
101 "audio from an Asterisk channel. This includes the audio coming in and\n"
102 "out of the channel being spied on. Only channels created by outgoing calls for the\n"
103 "specified extension will be selected for spying. If the optional context is not\n"
104 "supplied, the current channel's context will be used.\n"
105 "  While spying, the following actions may be performed:\n"
106 "    - Dialing # cycles the volume level.\n"
107 "    - Dialing * will stop spying and look for another channel to spy on.\n"
108 "  Note: The X option superseeds the two features above in that if a valid\n"
109 "        single digit extension exists in the correct context it ChanSpy will\n"
110 "        exit to it.\n"
111 "  Options:\n"
112 "    b             - Only spy on channels involved in a bridged call.\n"
113 "    g(grp)        - Match only channels where their ${SPYGROUP} variable is set to\n"
114 "                    contain 'grp' in an optional : delimited list.\n"
115 "    q             - Don't play a beep when beginning to spy on a channel, or speak the\n"
116 "                    selected channel name.\n"
117 "    r[(basename)] - Record the session to the monitor spool directory. An\n"
118 "                    optional base for the filename may be specified. The\n"
119 "                    default is 'chanspy'.\n"
120 "    v([value])    - Adjust the initial volume in the range from -4 to 4. A\n"
121 "                    negative value refers to a quieter setting.\n"
122 "    w             - Enable 'whisper' mode, so the spying channel can talk to\n"
123 "                    the spied-on channel.\n"
124 "    W             - Enable 'private whisper' mode, so the spying channel can\n"
125 "                    talk to the spied-on channel but cannot listen to that\n"
126 "                    channel.\n"
127 "    o             - Only listen to audio coming from this channel.\n"
128 "    X             - Allow the user to exit ChanSpy to a valid single digit\n"
129 "                    numeric extension in the current context or the context\n"
130 "                    specified by the SPY_EXIT_CONTEXT channel variable. The\n"
131 "                    name of the last channel that was spied on will be stored\n"
132 "                    in the SPY_CHANNEL variable.\n"
133 ;
134
135 enum {
136         OPTION_QUIET     = (1 << 0),    /* Quiet, no announcement */
137         OPTION_BRIDGED   = (1 << 1),    /* Only look at bridged calls */
138         OPTION_VOLUME    = (1 << 2),    /* Specify initial volume */
139         OPTION_GROUP     = (1 << 3),    /* Only look at channels in group */
140         OPTION_RECORD    = (1 << 4),
141         OPTION_WHISPER   = (1 << 5),
142         OPTION_PRIVATE   = (1 << 6),    /* Private Whisper mode */
143         OPTION_READONLY  = (1 << 7),    /* Don't mix the two channels */
144         OPTION_EXIT      = (1 << 8),    /* Exit to a valid single digit extension */
145 } chanspy_opt_flags;
146
147 enum {
148         OPT_ARG_VOLUME = 0,
149         OPT_ARG_GROUP,
150         OPT_ARG_RECORD,
151         OPT_ARG_ARRAY_SIZE,
152 } chanspy_opt_args;
153
154 AST_APP_OPTIONS(spy_opts, {
155         AST_APP_OPTION('q', OPTION_QUIET),
156         AST_APP_OPTION('b', OPTION_BRIDGED),
157         AST_APP_OPTION('w', OPTION_WHISPER),
158         AST_APP_OPTION('W', OPTION_PRIVATE),
159         AST_APP_OPTION_ARG('v', OPTION_VOLUME, OPT_ARG_VOLUME),
160         AST_APP_OPTION_ARG('g', OPTION_GROUP, OPT_ARG_GROUP),
161         AST_APP_OPTION_ARG('r', OPTION_RECORD, OPT_ARG_RECORD),
162         AST_APP_OPTION('o', OPTION_READONLY),
163         AST_APP_OPTION('X', OPTION_EXIT),
164 });
165
166
167 struct chanspy_translation_helper {
168         /* spy data */
169         struct ast_channel_spy spy;
170         int fd;
171         int volfactor;
172 };
173
174 static void *spy_alloc(struct ast_channel *chan, void *data)
175 {
176         /* just store the data pointer in the channel structure */
177         return data;
178 }
179
180 static void spy_release(struct ast_channel *chan, void *data)
181 {
182         /* nothing to do */
183 }
184
185 static int spy_generate(struct ast_channel *chan, void *data, int len, int samples) 
186 {
187         struct chanspy_translation_helper *csth = data;
188         struct ast_frame *f;
189                 
190         if (csth->spy.status != CHANSPY_RUNNING)
191                 /* Channel is already gone more than likely */
192                 return -1;
193
194         ast_mutex_lock(&csth->spy.lock);
195         f = ast_channel_spy_read_frame(&csth->spy, samples);
196         ast_mutex_unlock(&csth->spy.lock);
197                 
198         if (!f)
199                 return 0;
200                 
201         if (ast_write(chan, f)) {
202                 ast_frfree(f);
203                 return -1;
204         }
205
206         if (csth->fd)
207                 write(csth->fd, f->data, f->datalen);
208
209         ast_frfree(f);
210
211         return 0;
212 }
213
214 static struct ast_generator spygen = {
215         .alloc = spy_alloc,
216         .release = spy_release,
217         .generate = spy_generate, 
218 };
219
220 static int start_spying(struct ast_channel *chan, struct ast_channel *spychan, struct ast_channel_spy *spy) 
221 {
222         int res;
223         struct ast_channel *peer;
224
225         ast_log(LOG_NOTICE, "Attaching %s to %s\n", spychan->name, chan->name);
226
227         ast_channel_lock(chan);
228         res = ast_channel_spy_add(chan, spy);
229         ast_channel_unlock(chan);
230
231         if (!res && ast_test_flag(chan, AST_FLAG_NBRIDGE) && (peer = ast_bridged_channel(chan)))
232                 ast_softhangup(peer, AST_SOFTHANGUP_UNBRIDGE);  
233
234         return res;
235 }
236
237 /* Map 'volume' levels from -4 through +4 into
238    decibel (dB) settings for channel drivers
239 */
240 static signed char volfactor_map[] = {
241         -24,
242         -18,
243         -12,
244         -6,
245         0,
246         6,
247         12,
248         18,
249         24,
250 };
251
252 /* attempt to set the desired gain adjustment via the channel driver;
253    if successful, clear it out of the csth structure so the
254    generator will not attempt to do the adjustment itself
255 */
256 static void set_volume(struct ast_channel *chan, struct chanspy_translation_helper *csth)
257 {
258         signed char volume_adjust = volfactor_map[csth->volfactor + 4];
259
260         if (!ast_channel_setoption(chan, AST_OPTION_TXGAIN, &volume_adjust, sizeof(volume_adjust), 0))
261                 csth->volfactor = 0;
262         csth->spy.read_vol_adjustment = csth->volfactor;
263         csth->spy.write_vol_adjustment = csth->volfactor;
264 }
265
266 static int channel_spy(struct ast_channel *chan, struct ast_channel *spyee, int *volfactor, int fd,
267                        const struct ast_flags *flags, char *exitcontext) 
268 {
269         struct chanspy_translation_helper csth;
270         int running = 0, res, x = 0;
271         char inp[24] = {0};
272         char *name;
273         struct ast_frame *f;
274         struct ast_silence_generator *silgen = NULL;
275
276         if (ast_check_hangup(chan) || ast_check_hangup(spyee))
277                 return 0;
278
279         name = ast_strdupa(spyee->name);
280         if (option_verbose >= 2)
281                 ast_verbose(VERBOSE_PREFIX_2 "Spying on channel %s\n", name);
282
283         memset(&csth, 0, sizeof(csth));
284         ast_set_flag(&csth.spy, CHANSPY_FORMAT_AUDIO);
285         ast_set_flag(&csth.spy, CHANSPY_TRIGGER_NONE);
286         if (!ast_test_flag(flags, OPTION_READONLY))
287                 ast_set_flag(&csth.spy, CHANSPY_MIXAUDIO);
288         csth.spy.type = "ChanSpy";
289         csth.spy.status = CHANSPY_RUNNING;
290         csth.spy.read_queue.format = AST_FORMAT_SLINEAR;
291         csth.spy.write_queue.format = AST_FORMAT_SLINEAR;
292         ast_mutex_init(&csth.spy.lock);
293         csth.volfactor = *volfactor;
294         set_volume(chan, &csth);
295         if (csth.volfactor) {
296                 ast_set_flag(&csth.spy, CHANSPY_READ_VOLADJUST);
297                 csth.spy.read_vol_adjustment = csth.volfactor;
298                 ast_set_flag(&csth.spy, CHANSPY_WRITE_VOLADJUST);
299                 csth.spy.write_vol_adjustment = csth.volfactor;
300         }
301         csth.fd = fd;
302         
303         if (start_spying(spyee, chan, &csth.spy)) {
304                 ast_mutex_destroy(&csth.spy.lock);
305                 return 0;
306         }
307
308         if (ast_test_flag(flags, OPTION_WHISPER)) {
309                 struct ast_filestream *beepstream;
310                 int old_write_format = 0;
311
312                 ast_channel_whisper_start(csth.spy.chan);
313                 old_write_format = chan->writeformat;
314                 if ((beepstream = ast_openstream_full(chan, "beep", chan->language, 1))) {
315                         struct ast_frame *f;
316
317                         while ((f = ast_readframe(beepstream))) {
318                                 ast_channel_whisper_feed(csth.spy.chan, f);
319                                 ast_frfree(f);
320                         }
321
322                         ast_closestream(beepstream);
323                         chan->stream = NULL;
324                 }
325                 if (old_write_format)
326                         ast_set_write_format(chan, old_write_format);
327         }
328
329         if (ast_test_flag(flags, OPTION_PRIVATE))
330                 silgen = ast_channel_start_silence_generator(chan);
331         else
332                 ast_activate_generator(chan, &spygen, &csth);
333
334         /* We can no longer rely on 'spyee' being an actual channel;
335            it can be hung up and freed out from under us. However, the
336            channel destructor will put NULL into our csth.spy.chan
337            field when that happens, so that is our signal that the spyee
338            channel has gone away.
339         */
340
341         /* Note: it is very important that the ast_waitfor() be the first
342            condition in this expression, so that if we wait for some period
343            of time before receiving a frame from our spying channel, we check
344            for hangup on the spied-on channel _after_ knowing that a frame
345            has arrived, since the spied-on channel could have gone away while
346            we were waiting
347         */
348         while ((res = ast_waitfor(chan, -1) > -1) &&
349                csth.spy.status == CHANSPY_RUNNING &&
350                csth.spy.chan) {
351                 if (!(f = ast_read(chan)) || ast_check_hangup(chan)) {
352                         running = -1;
353                         break;
354                 }
355
356                 if (ast_test_flag(flags, OPTION_WHISPER) &&
357                     (f->frametype == AST_FRAME_VOICE)) {
358                         ast_channel_whisper_feed(csth.spy.chan, f);
359                         ast_frfree(f);
360                         continue;
361                 }
362
363                 res = (f->frametype == AST_FRAME_DTMF) ? f->subclass : 0;
364                 ast_frfree(f);
365                 if (!res)
366                         continue;
367
368                 if (x == sizeof(inp))
369                         x = 0;
370
371                 if (res < 0) {
372                         running = -1;
373                         break;
374                 }
375                 
376                 if (ast_test_flag(flags, OPTION_EXIT)) {
377                         char tmp[2];
378                         tmp[0] = res;
379                         tmp[1] = '\0';
380                         if (!ast_goto_if_exists(chan, exitcontext, tmp, 1)) {
381                                 ast_debug(1, "Got DTMF %c, goto context %s\n", tmp[0], exitcontext);
382                                 pbx_builtin_setvar_helper(chan, "SPY_CHANNEL", name);
383                                 running = -2;
384                                 break;
385                         } else {
386                                 ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
387                         }
388                 } else if (res >= '0' && res <= '9') {
389                         inp[x++] = res;
390                 }
391
392                 if (res == '*') {
393                         running = 0;
394                         break;
395                 } else if (res == '#') {
396                         if (!ast_strlen_zero(inp)) {
397                                 running = atoi(inp);
398                                 break;
399                         }
400
401                         (*volfactor)++;
402                         if (*volfactor > 4)
403                                 *volfactor = -4;
404                         if (option_verbose > 2)
405                                 ast_verbose(VERBOSE_PREFIX_3 "Setting spy volume on %s to %d\n", chan->name, *volfactor);
406                         csth.volfactor = *volfactor;
407                         set_volume(chan, &csth);
408                         if (csth.volfactor) {
409                                 ast_set_flag(&csth.spy, CHANSPY_READ_VOLADJUST);
410                                 csth.spy.read_vol_adjustment = csth.volfactor;
411                                 ast_set_flag(&csth.spy, CHANSPY_WRITE_VOLADJUST);
412                                 csth.spy.write_vol_adjustment = csth.volfactor;
413                         } else {
414                                 ast_clear_flag(&csth.spy, CHANSPY_READ_VOLADJUST);
415                                 ast_clear_flag(&csth.spy, CHANSPY_WRITE_VOLADJUST);
416                         }
417                 }
418         }
419
420         if (ast_test_flag(flags, OPTION_WHISPER) && csth.spy.chan)
421                 ast_channel_whisper_stop(csth.spy.chan);
422
423         if (ast_test_flag(flags, OPTION_PRIVATE))
424                 ast_channel_stop_silence_generator(chan, silgen);
425         else
426                 ast_deactivate_generator(chan);
427
428         csth.spy.status = CHANSPY_DONE;
429
430         /* If a channel still exists on our spy structure then we need to remove ourselves */
431         if (csth.spy.chan) {
432                 ast_channel_lock(csth.spy.chan);
433                 ast_channel_spy_remove(csth.spy.chan, &csth.spy);
434                 ast_channel_unlock(csth.spy.chan);
435         }
436         ast_channel_spy_free(&csth.spy);
437         
438         if (option_verbose >= 2)
439                 ast_verbose(VERBOSE_PREFIX_2 "Done Spying on channel %s\n", name);
440         
441         return running;
442 }
443
444 static struct ast_channel *next_channel(const struct ast_channel *last, const char *spec,
445                                         const char *exten, const char *context)
446 {
447         struct ast_channel *this;
448
449         redo:
450         if (spec)
451                 this = ast_walk_channel_by_name_prefix_locked(last, spec, strlen(spec));
452         else if (exten)
453                 this = ast_walk_channel_by_exten_locked(last, exten, context);
454         else
455                 this = ast_channel_walk_locked(last);
456
457         if (this) {
458                 ast_channel_unlock(this);
459                 if (!strncmp(this->name, "Zap/pseudo", 10))
460                         goto redo;
461         }
462
463         return this;
464 }
465
466 static int common_exec(struct ast_channel *chan, const struct ast_flags *flags,
467                        int volfactor, const int fd, const char *mygroup, const char *spec,
468                        const char *exten, const char *context)
469 {
470         struct ast_channel *peer, *prev, *next;
471         char nameprefix[AST_NAME_STRLEN];
472         char peer_name[AST_NAME_STRLEN + 5];
473         char exitcontext[AST_MAX_CONTEXT] = "";
474         signed char zero_volume = 0;
475         int waitms;
476         int res;
477         char *ptr;
478         int num;
479
480         if (ast_test_flag(flags, OPTION_EXIT)) {
481                 const char *c;
482                 if ((c = pbx_builtin_getvar_helper(chan, "SPY_EXIT_CONTEXT"))) 
483                         ast_copy_string(exitcontext, c, sizeof(exitcontext));
484                 else if (!ast_strlen_zero(chan->macrocontext)) 
485                         ast_copy_string(exitcontext, chan->macrocontext, sizeof(exitcontext));
486                 else
487                         ast_copy_string(exitcontext, chan->context, sizeof(exitcontext));
488         }
489
490         if (chan->_state != AST_STATE_UP)
491                 ast_answer(chan);
492
493         ast_set_flag(chan, AST_FLAG_SPYING); /* so nobody can spy on us while we are spying */
494
495         waitms = 100;
496
497         for (;;) {
498                 if (!ast_test_flag(flags, OPTION_QUIET)) {
499                         res = ast_streamfile(chan, "beep", chan->language);
500                         if (!res)
501                                 res = ast_waitstream(chan, "");
502                         else if (res < 0) {
503                                 ast_clear_flag(chan, AST_FLAG_SPYING);
504                                 break;
505                         }
506                         if (!ast_strlen_zero(exitcontext)) {
507                                 char tmp[2];
508                                 tmp[0] = res;
509                                 tmp[1] = '\0';
510                                 if (!ast_goto_if_exists(chan, exitcontext, tmp, 1))
511                                         goto exit;
512                                 else
513                                         ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
514                         }
515                 }
516
517                 res = ast_waitfordigit(chan, waitms);
518                 if (res < 0) {
519                         ast_clear_flag(chan, AST_FLAG_SPYING);
520                         break;
521                 }
522                 if (!ast_strlen_zero(exitcontext)) {
523                         char tmp[2];
524                         tmp[0] = res;
525                         tmp[1] = '\0';
526                         if (!ast_goto_if_exists(chan, exitcontext, tmp, 1))
527                                 goto exit;
528                         else
529                                 ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
530                 }
531                                 
532                 /* reset for the next loop around, unless overridden later */
533                 waitms = 100;
534                 peer = prev = next = NULL;
535
536                 for (peer = next_channel(peer, spec, exten, context);
537                      peer;
538                      prev = peer, peer = next ? next : next_channel(peer, spec, exten, context), next = NULL) {
539                         const char *group;
540                         int igrp = !mygroup;
541                         char *groups[25];
542                         int num_groups = 0;
543                         char *dup_group;
544                         int x;
545                         char *s;
546                                 
547                         if (peer == prev)
548                                 break;
549
550                         if (peer == chan)
551                                 continue;
552
553                         if (ast_test_flag(flags, OPTION_BRIDGED) && !ast_bridged_channel(peer))
554                                 continue;
555
556                         if (ast_check_hangup(peer) || ast_test_flag(peer, AST_FLAG_SPYING))
557                                 continue;
558
559                         if (mygroup) {
560                                 if ((group = pbx_builtin_getvar_helper(peer, "SPYGROUP"))) {
561                                         dup_group = ast_strdupa(group);
562                                         num_groups = ast_app_separate_args(dup_group, ':', groups,
563                                                                            sizeof(groups) / sizeof(groups[0]));
564                                 }
565                                 
566                                 for (x = 0; x < num_groups; x++) {
567                                         if (!strcmp(mygroup, groups[x])) {
568                                                 igrp = 1;
569                                                 break;
570                                         }
571                                 }
572                         }
573                         
574                         if (!igrp)
575                                 continue;
576
577                         strcpy(peer_name, "spy-");
578                         strncat(peer_name, peer->name, AST_NAME_STRLEN);
579                         ptr = strchr(peer_name, '/');
580                         *ptr++ = '\0';
581                         
582                         for (s = peer_name; s < ptr; s++)
583                                 *s = tolower(*s);
584                         
585                         if (!ast_test_flag(flags, OPTION_QUIET)) {
586                                 if (ast_fileexists(peer_name, NULL, NULL) != -1) {
587                                         res = ast_streamfile(chan, peer_name, chan->language);
588                                         if (!res)
589                                                 res = ast_waitstream(chan, "");
590                                         if (res)
591                                                 break;
592                                 } else
593                                         res = ast_say_character_str(chan, peer_name, "", chan->language);
594                                 if ((num = atoi(ptr))) 
595                                         ast_say_digits(chan, atoi(ptr), "", chan->language);
596                         }
597                         
598                         waitms = 5000;
599                         res = channel_spy(chan, peer, &volfactor, fd, flags, exitcontext);
600                         
601                         if (res == -1) {
602                                 goto exit;
603                         } else if (res == -2) {
604                                 res = 0;
605                                 goto exit;
606                         } else if (res > 1 && spec) {
607                                 snprintf(nameprefix, AST_NAME_STRLEN, "%s/%d", spec, res);
608                                 if ((next = ast_get_channel_by_name_prefix_locked(nameprefix, strlen(nameprefix)))) {
609                                         ast_channel_unlock(next);
610                                 } else {
611                                         /* stay on this channel */
612                                         next = peer;
613                                 }
614                                 peer = NULL;
615                         }
616                 }
617         }
618 exit:
619
620         ast_clear_flag(chan, AST_FLAG_SPYING);
621
622         ast_channel_setoption(chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);
623
624         return res;
625 }
626
627 static int chanspy_exec(struct ast_channel *chan, void *data)
628 {
629         struct ast_module_user *u;
630         char *options = NULL;
631         char *spec = NULL;
632         char *argv[2];
633         char *mygroup = NULL;
634         char *recbase = NULL;
635         int fd = 0;
636         struct ast_flags flags;
637         int oldwf = 0;
638         int argc = 0;
639         int volfactor = 0;
640         int res;
641
642         data = ast_strdupa(data);
643
644         u = ast_module_user_add(chan);
645
646         if ((argc = ast_app_separate_args(data, '|', argv, sizeof(argv) / sizeof(argv[0])))) {
647                 spec = argv[0];
648                 if (argc > 1)
649                         options = argv[1];
650
651                 if (ast_strlen_zero(spec) || !strcmp(spec, "all"))
652                         spec = NULL;
653         }
654
655         if (options) {
656                 char *opts[OPT_ARG_ARRAY_SIZE];
657                 
658                 ast_app_parse_options(spy_opts, &flags, opts, options);
659                 if (ast_test_flag(&flags, OPTION_GROUP))
660                         mygroup = opts[OPT_ARG_GROUP];
661
662                 if (ast_test_flag(&flags, OPTION_RECORD) &&
663                     !(recbase = opts[OPT_ARG_RECORD]))
664                         recbase = "chanspy";
665
666                 if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) {
667                         int vol;
668
669                         if ((sscanf(opts[OPT_ARG_VOLUME], "%d", &vol) != 1) || (vol > 4) || (vol < -4))
670                                 ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n");
671                         else
672                                 volfactor = vol;
673                 }
674
675                 if (ast_test_flag(&flags, OPTION_PRIVATE))
676                         ast_set_flag(&flags, OPTION_WHISPER);
677         } else
678                 ast_clear_flag(&flags, AST_FLAGS_ALL);
679
680         oldwf = chan->writeformat;
681         if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
682                 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
683                 ast_module_user_remove(u);
684                 return -1;
685         }
686
687         if (recbase) {
688                 char filename[512];
689
690                 snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL));
691                 if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, AST_FILE_MODE)) <= 0) {
692                         ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename);
693                         fd = 0;
694                 }
695         }
696
697         res = common_exec(chan, &flags, volfactor, fd, mygroup, spec, NULL, NULL);
698
699         if (fd)
700                 close(fd);
701
702         if (oldwf && ast_set_write_format(chan, oldwf) < 0)
703                 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
704
705         ast_module_user_remove(u);
706
707         return res;
708 }
709
710 static int extenspy_exec(struct ast_channel *chan, void *data)
711 {
712         struct ast_module_user *u;
713         char *options = NULL;
714         char *exten = NULL;
715         char *context = NULL;
716         char *argv[2];
717         char *mygroup = NULL;
718         char *recbase = NULL;
719         int fd = 0;
720         struct ast_flags flags;
721         int oldwf = 0;
722         int argc = 0;
723         int volfactor = 0;
724         int res;
725
726         data = ast_strdupa(data);
727
728         u = ast_module_user_add(chan);
729
730         if ((argc = ast_app_separate_args(data, '|', argv, sizeof(argv) / sizeof(argv[0])))) {
731                 context = argv[0];
732                 if (!ast_strlen_zero(argv[0]))
733                         exten = strsep(&context, "@");
734                 if (ast_strlen_zero(context))
735                         context = ast_strdupa(chan->context);
736                 if (argc > 1)
737                         options = argv[1];
738         }
739
740         if (options) {
741                 char *opts[OPT_ARG_ARRAY_SIZE];
742                 
743                 ast_app_parse_options(spy_opts, &flags, opts, options);
744                 if (ast_test_flag(&flags, OPTION_GROUP))
745                         mygroup = opts[OPT_ARG_GROUP];
746
747                 if (ast_test_flag(&flags, OPTION_RECORD) &&
748                     !(recbase = opts[OPT_ARG_RECORD]))
749                         recbase = "chanspy";
750
751                 if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) {
752                         int vol;
753
754                         if ((sscanf(opts[OPT_ARG_VOLUME], "%d", &vol) != 1) || (vol > 4) || (vol < -4))
755                                 ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n");
756                         else
757                                 volfactor = vol;
758                 }
759
760                 if (ast_test_flag(&flags, OPTION_PRIVATE))
761                         ast_set_flag(&flags, OPTION_WHISPER);
762         } else
763                 ast_clear_flag(&flags, AST_FLAGS_ALL);
764
765         oldwf = chan->writeformat;
766         if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
767                 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
768                 ast_module_user_remove(u);
769                 return -1;
770         }
771
772         if (recbase) {
773                 char filename[512];
774
775                 snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL));
776                 if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, AST_FILE_MODE)) <= 0) {
777                         ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename);
778                         fd = 0;
779                 }
780         }
781
782         res = common_exec(chan, &flags, volfactor, fd, mygroup, NULL, exten, context);
783
784         if (fd)
785                 close(fd);
786
787         if (oldwf && ast_set_write_format(chan, oldwf) < 0)
788                 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
789
790         ast_module_user_remove(u);
791
792         return res;
793 }
794
795 static int unload_module(void)
796 {
797         int res = 0;
798
799         res |= ast_unregister_application(app_chan);
800         res |= ast_unregister_application(app_ext);
801
802         return res;
803 }
804
805 static int load_module(void)
806 {
807         int res = 0;
808
809         res |= ast_register_application(app_chan, chanspy_exec, tdesc, desc_chan);
810         res |= ast_register_application(app_ext, extenspy_exec, tdesc, desc_ext);
811
812         return res;
813 }
814
815 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Listen to the audio of an active channel");