81d50ef69d0d7eb2030e9cd0d4b30917532f5f76
[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_log(LOG_DEBUG, "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 if (option_debug > 1) {
386                                 ast_log(LOG_DEBUG, "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         /* If a channel still exists on our spy structure then we need to remove ourselves */
429         if (csth.spy.chan) {
430                 csth.spy.status = CHANSPY_DONE;
431                 ast_channel_lock(csth.spy.chan);
432                 ast_channel_spy_remove(csth.spy.chan, &csth.spy);
433                 ast_channel_unlock(csth.spy.chan);
434         }
435         ast_channel_spy_free(&csth.spy);
436         
437         if (option_verbose >= 2)
438                 ast_verbose(VERBOSE_PREFIX_2 "Done Spying on channel %s\n", name);
439         
440         return running;
441 }
442
443 static struct ast_channel *next_channel(const struct ast_channel *last, const char *spec,
444                                         const char *exten, const char *context)
445 {
446         struct ast_channel *this;
447
448         redo:
449         if (spec)
450                 this = ast_walk_channel_by_name_prefix_locked(last, spec, strlen(spec));
451         else if (exten)
452                 this = ast_walk_channel_by_exten_locked(last, exten, context);
453         else
454                 this = ast_channel_walk_locked(last);
455
456         if (this) {
457                 ast_channel_unlock(this);
458                 if (!strncmp(this->name, "Zap/pseudo", 10))
459                         goto redo;
460         }
461
462         return this;
463 }
464
465 static int common_exec(struct ast_channel *chan, const struct ast_flags *flags,
466                        int volfactor, const int fd, const char *mygroup, const char *spec,
467                        const char *exten, const char *context)
468 {
469         struct ast_channel *peer, *prev, *next;
470         char nameprefix[AST_NAME_STRLEN];
471         char peer_name[AST_NAME_STRLEN + 5];
472         char exitcontext[AST_MAX_CONTEXT] = "";
473         signed char zero_volume = 0;
474         int waitms;
475         int res;
476         char *ptr;
477         int num;
478
479         if (ast_test_flag(flags, OPTION_EXIT)) {
480                 const char *c;
481                 if ((c = pbx_builtin_getvar_helper(chan, "SPY_EXIT_CONTEXT"))) 
482                         ast_copy_string(exitcontext, c, sizeof(exitcontext));
483                 else if (!ast_strlen_zero(chan->macrocontext)) 
484                         ast_copy_string(exitcontext, chan->macrocontext, sizeof(exitcontext));
485                 else
486                         ast_copy_string(exitcontext, chan->context, sizeof(exitcontext));
487         }
488
489         if (chan->_state != AST_STATE_UP)
490                 ast_answer(chan);
491
492         ast_set_flag(chan, AST_FLAG_SPYING); /* so nobody can spy on us while we are spying */
493
494         waitms = 100;
495
496         for (;;) {
497                 if (!ast_test_flag(flags, OPTION_QUIET)) {
498                         res = ast_streamfile(chan, "beep", chan->language);
499                         if (!res)
500                                 res = ast_waitstream(chan, "");
501                         else if (res < 0) {
502                                 ast_clear_flag(chan, AST_FLAG_SPYING);
503                                 break;
504                         }
505                         if (!ast_strlen_zero(exitcontext)) {
506                                 char tmp[2];
507                                 tmp[0] = res;
508                                 tmp[1] = '\0';
509                                 if (!ast_goto_if_exists(chan, exitcontext, tmp, 1))
510                                         goto exit;
511                                 else if (option_debug > 1)
512                                         ast_log(LOG_DEBUG, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
513                         }
514                 }
515
516                 res = ast_waitfordigit(chan, waitms);
517                 if (res < 0) {
518                         ast_clear_flag(chan, AST_FLAG_SPYING);
519                         break;
520                 }
521                 if (!ast_strlen_zero(exitcontext)) {
522                         char tmp[2];
523                         tmp[0] = res;
524                         tmp[1] = '\0';
525                         if (!ast_goto_if_exists(chan, exitcontext, tmp, 1))
526                                 goto exit;
527                         else if (option_debug > 1)
528                                 ast_log(LOG_DEBUG, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
529                 }
530                                 
531                 /* reset for the next loop around, unless overridden later */
532                 waitms = 100;
533                 peer = prev = next = NULL;
534
535                 for (peer = next_channel(peer, spec, exten, context);
536                      peer;
537                      prev = peer, peer = next ? next : next_channel(peer, spec, exten, context), next = NULL) {
538                         const char *group;
539                         int igrp = !mygroup;
540                         char *groups[25];
541                         int num_groups = 0;
542                         char *dup_group;
543                         int x;
544                         char *s;
545                                 
546                         if (peer == prev)
547                                 break;
548
549                         if (peer == chan)
550                                 continue;
551
552                         if (ast_test_flag(flags, OPTION_BRIDGED) && !ast_bridged_channel(peer))
553                                 continue;
554
555                         if (ast_check_hangup(peer) || ast_test_flag(peer, AST_FLAG_SPYING))
556                                 continue;
557
558                         if (mygroup) {
559                                 if ((group = pbx_builtin_getvar_helper(peer, "SPYGROUP"))) {
560                                         dup_group = ast_strdupa(group);
561                                         num_groups = ast_app_separate_args(dup_group, ':', groups,
562                                                                            sizeof(groups) / sizeof(groups[0]));
563                                 }
564                                 
565                                 for (x = 0; x < num_groups; x++) {
566                                         if (!strcmp(mygroup, groups[x])) {
567                                                 igrp = 1;
568                                                 break;
569                                         }
570                                 }
571                         }
572                         
573                         if (!igrp)
574                                 continue;
575
576                         strcpy(peer_name, "spy-");
577                         strncat(peer_name, peer->name, AST_NAME_STRLEN);
578                         ptr = strchr(peer_name, '/');
579                         *ptr++ = '\0';
580                         
581                         for (s = peer_name; s < ptr; s++)
582                                 *s = tolower(*s);
583                         
584                         if (!ast_test_flag(flags, OPTION_QUIET)) {
585                                 if (ast_fileexists(peer_name, NULL, NULL) != -1) {
586                                         res = ast_streamfile(chan, peer_name, chan->language);
587                                         if (!res)
588                                                 res = ast_waitstream(chan, "");
589                                         if (res)
590                                                 break;
591                                 } else
592                                         res = ast_say_character_str(chan, peer_name, "", chan->language);
593                                 if ((num = atoi(ptr))) 
594                                         ast_say_digits(chan, atoi(ptr), "", chan->language);
595                         }
596                         
597                         waitms = 5000;
598                         res = channel_spy(chan, peer, &volfactor, fd, flags, exitcontext);
599                         
600                         if (res == -1) {
601                                 goto exit;
602                         } else if (res == -2) {
603                                 res = 0;
604                                 goto exit;
605                         } else if (res > 1 && spec) {
606                                 snprintf(nameprefix, AST_NAME_STRLEN, "%s/%d", spec, res);
607                                 if ((next = ast_get_channel_by_name_prefix_locked(nameprefix, strlen(nameprefix)))) {
608                                         ast_channel_unlock(next);
609                                 } else {
610                                         /* stay on this channel */
611                                         next = peer;
612                                 }
613                                 peer = NULL;
614                         }
615                 }
616         }
617 exit:
618
619         ast_clear_flag(chan, AST_FLAG_SPYING);
620
621         ast_channel_setoption(chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);
622
623         return res;
624 }
625
626 static int chanspy_exec(struct ast_channel *chan, void *data)
627 {
628         struct ast_module_user *u;
629         char *options = NULL;
630         char *spec = NULL;
631         char *argv[2];
632         char *mygroup = NULL;
633         char *recbase = NULL;
634         int fd = 0;
635         struct ast_flags flags;
636         int oldwf = 0;
637         int argc = 0;
638         int volfactor = 0;
639         int res;
640
641         data = ast_strdupa(data);
642
643         u = ast_module_user_add(chan);
644
645         if ((argc = ast_app_separate_args(data, '|', argv, sizeof(argv) / sizeof(argv[0])))) {
646                 spec = argv[0];
647                 if (argc > 1)
648                         options = argv[1];
649
650                 if (ast_strlen_zero(spec) || !strcmp(spec, "all"))
651                         spec = NULL;
652         }
653
654         if (options) {
655                 char *opts[OPT_ARG_ARRAY_SIZE];
656                 
657                 ast_app_parse_options(spy_opts, &flags, opts, options);
658                 if (ast_test_flag(&flags, OPTION_GROUP))
659                         mygroup = opts[OPT_ARG_GROUP];
660
661                 if (ast_test_flag(&flags, OPTION_RECORD) &&
662                     !(recbase = opts[OPT_ARG_RECORD]))
663                         recbase = "chanspy";
664
665                 if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) {
666                         int vol;
667
668                         if ((sscanf(opts[OPT_ARG_VOLUME], "%d", &vol) != 1) || (vol > 4) || (vol < -4))
669                                 ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n");
670                         else
671                                 volfactor = vol;
672                 }
673
674                 if (ast_test_flag(&flags, OPTION_PRIVATE))
675                         ast_set_flag(&flags, OPTION_WHISPER);
676         }
677
678         oldwf = chan->writeformat;
679         if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
680                 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
681                 ast_module_user_remove(u);
682                 return -1;
683         }
684
685         if (recbase) {
686                 char filename[512];
687
688                 snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL));
689                 if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, AST_FILE_MODE)) <= 0) {
690                         ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename);
691                         fd = 0;
692                 }
693         }
694
695         res = common_exec(chan, &flags, volfactor, fd, mygroup, spec, NULL, NULL);
696
697         if (fd)
698                 close(fd);
699
700         if (oldwf && ast_set_write_format(chan, oldwf) < 0)
701                 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
702
703         ast_module_user_remove(u);
704
705         return res;
706 }
707
708 static int extenspy_exec(struct ast_channel *chan, void *data)
709 {
710         struct ast_module_user *u;
711         char *options = NULL;
712         char *exten = NULL;
713         char *context = NULL;
714         char *argv[2];
715         char *mygroup = NULL;
716         char *recbase = NULL;
717         int fd = 0;
718         struct ast_flags flags;
719         int oldwf = 0;
720         int argc = 0;
721         int volfactor = 0;
722         int res;
723
724         data = ast_strdupa(data);
725
726         u = ast_module_user_add(chan);
727
728         if ((argc = ast_app_separate_args(data, '|', argv, sizeof(argv) / sizeof(argv[0])))) {
729                 context = argv[0];
730                 if (!ast_strlen_zero(argv[0]))
731                         exten = strsep(&context, "@");
732                 if (ast_strlen_zero(context))
733                         context = ast_strdupa(chan->context);
734                 if (argc > 1)
735                         options = argv[1];
736         }
737
738         if (options) {
739                 char *opts[OPT_ARG_ARRAY_SIZE];
740                 
741                 ast_app_parse_options(spy_opts, &flags, opts, options);
742                 if (ast_test_flag(&flags, OPTION_GROUP))
743                         mygroup = opts[OPT_ARG_GROUP];
744
745                 if (ast_test_flag(&flags, OPTION_RECORD) &&
746                     !(recbase = opts[OPT_ARG_RECORD]))
747                         recbase = "chanspy";
748
749                 if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) {
750                         int vol;
751
752                         if ((sscanf(opts[OPT_ARG_VOLUME], "%d", &vol) != 1) || (vol > 4) || (vol < -4))
753                                 ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n");
754                         else
755                                 volfactor = vol;
756                 }
757
758                 if (ast_test_flag(&flags, OPTION_PRIVATE))
759                         ast_set_flag(&flags, OPTION_WHISPER);
760         }
761
762         oldwf = chan->writeformat;
763         if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
764                 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
765                 ast_module_user_remove(u);
766                 return -1;
767         }
768
769         if (recbase) {
770                 char filename[512];
771
772                 snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL));
773                 if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, AST_FILE_MODE)) <= 0) {
774                         ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename);
775                         fd = 0;
776                 }
777         }
778
779         res = common_exec(chan, &flags, volfactor, fd, mygroup, NULL, exten, context);
780
781         if (fd)
782                 close(fd);
783
784         if (oldwf && ast_set_write_format(chan, oldwf) < 0)
785                 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
786
787         ast_module_user_remove(u);
788
789         return res;
790 }
791
792 static int unload_module(void)
793 {
794         int res = 0;
795
796         res |= ast_unregister_application(app_chan);
797         res |= ast_unregister_application(app_ext);
798
799         ast_module_user_hangup_all();
800
801         return res;
802 }
803
804 static int load_module(void)
805 {
806         int res = 0;
807
808         res |= ast_register_application(app_chan, chanspy_exec, tdesc, desc_chan);
809         res |= ast_register_application(app_ext, extenspy_exec, tdesc, desc_ext);
810
811         return res;
812 }
813
814 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Listen to the audio of an active channel");