66a2d214e84e6d321bf47ccb81f2152ce0b1585c
[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 - 2008, 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  * \author Joshua Colp <jcolp@digium.com>
27  * \author Russell Bryant <russell@digium.com>
28  *
29  * \ingroup applications
30  */
31
32 #include "asterisk.h"
33
34 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
35
36 #include <ctype.h>
37
38 #include "asterisk/paths.h" /* use ast_config_AST_MONITOR_DIR */
39 #include "asterisk/file.h"
40 #include "asterisk/channel.h"
41 #include "asterisk/audiohook.h"
42 #include "asterisk/features.h"
43 #include "asterisk/app.h"
44 #include "asterisk/utils.h"
45 #include "asterisk/say.h"
46 #include "asterisk/pbx.h"
47 #include "asterisk/translate.h"
48 #include "asterisk/module.h"
49 #include "asterisk/lock.h"
50
51 #define AST_NAME_STRLEN 256
52
53 static const char *tdesc = "Listen to a channel, and optionally whisper into it";
54 static const char *app_chan = "ChanSpy";
55 static const char *desc_chan =
56 "  ChanSpy([chanprefix][,options]): This application is used to listen to the\n"
57 "audio from an Asterisk channel. This includes the audio coming in and\n"
58 "out of the channel being spied on. If the 'chanprefix' parameter is specified,\n"
59 "only channels beginning with this string will be spied upon.\n"
60 "  While spying, the following actions may be performed:\n"
61 "    - Dialing # cycles the volume level.\n"
62 "    - Dialing * will stop spying and look for another channel to spy on.\n"
63 "    - Dialing a series of digits followed by # builds a channel name to append\n"
64 "      to 'chanprefix'. For example, executing ChanSpy(Agent) and then dialing\n"
65 "      the digits '1234#' while spying will begin spying on the channel\n"
66 "      'Agent/1234'.\n"
67 "  Note: The X option supersedes the three features above in that if a valid\n"
68 "        single digit extension exists in the correct context ChanSpy will\n"
69 "        exit to it. This also disables choosing a channel based on 'chanprefix'\n"
70 "        and a digit sequence.\n"
71 "  Options:\n"
72 "    b             - Only spy on channels involved in a bridged call.\n"
73 "    g(grp)        - Match only channels where their SPYGROUP variable is set to\n"
74 "                    contain 'grp' in an optional : delimited list.\n"
75 "    q             - Don't play a beep when beginning to spy on a channel, or speak the\n"
76 "                    selected channel name.\n"
77 "    r[(basename)] - Record the session to the monitor spool directory. An\n"
78 "                    optional base for the filename may be specified. The\n"
79 "                    default is 'chanspy'.\n"
80 "    v([value])    - Adjust the initial volume in the range from -4 to 4. A\n"
81 "                    negative value refers to a quieter setting.\n"
82 "    w             - Enable 'whisper' mode, so the spying channel can talk to\n"
83 "                    the spied-on channel.\n"
84 "    W             - Enable 'private whisper' mode, so the spying channel can\n"
85 "                    talk to the spied-on channel but cannot listen to that\n"
86 "                    channel.\n"
87 "    o             - Only listen to audio coming from this channel.\n"
88 "    X             - Allow the user to exit ChanSpy to a valid single digit\n"
89 "                    numeric extension in the current context or the context\n"
90 "                    specified by the SPY_EXIT_CONTEXT channel variable. The\n"
91 "                    name of the last channel that was spied on will be stored\n"
92 "                    in the SPY_CHANNEL variable.\n"
93 "    e(ext)        - Enable 'enforced' mode, so the spying channel can\n"
94 "                    only monitor extensions whose name is in the 'ext' : \n"
95 "                    delimited list.\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         OPTION_ENFORCED  = (1 << 9),    /* Enforced mode */
146 } chanspy_opt_flags;
147
148 enum {
149         OPT_ARG_VOLUME = 0,
150         OPT_ARG_GROUP,
151         OPT_ARG_RECORD,
152         OPT_ARG_ENFORCED,
153         OPT_ARG_ARRAY_SIZE,
154 } chanspy_opt_args;
155
156 AST_APP_OPTIONS(spy_opts, {
157         AST_APP_OPTION('q', OPTION_QUIET),
158         AST_APP_OPTION('b', OPTION_BRIDGED),
159         AST_APP_OPTION('w', OPTION_WHISPER),
160         AST_APP_OPTION('W', OPTION_PRIVATE),
161         AST_APP_OPTION_ARG('v', OPTION_VOLUME, OPT_ARG_VOLUME),
162         AST_APP_OPTION_ARG('g', OPTION_GROUP, OPT_ARG_GROUP),
163         AST_APP_OPTION_ARG('r', OPTION_RECORD, OPT_ARG_RECORD),
164         AST_APP_OPTION_ARG('e', OPTION_ENFORCED, OPT_ARG_ENFORCED),
165         AST_APP_OPTION('o', OPTION_READONLY),
166         AST_APP_OPTION('X', OPTION_EXIT),
167 });
168
169
170 struct chanspy_translation_helper {
171         /* spy data */
172         struct ast_audiohook spy_audiohook;
173         struct ast_audiohook whisper_audiohook;
174         int fd;
175         int volfactor;
176 };
177
178 static void *spy_alloc(struct ast_channel *chan, void *data)
179 {
180         /* just store the data pointer in the channel structure */
181         return data;
182 }
183
184 static void spy_release(struct ast_channel *chan, void *data)
185 {
186         /* nothing to do */
187 }
188
189 static int spy_generate(struct ast_channel *chan, void *data, int len, int samples)
190 {
191         struct chanspy_translation_helper *csth = data;
192         struct ast_frame *f = NULL;
193
194         ast_audiohook_lock(&csth->spy_audiohook);
195         if (csth->spy_audiohook.status != AST_AUDIOHOOK_STATUS_RUNNING) {
196                 /* Channel is already gone more than likely */
197                 ast_audiohook_unlock(&csth->spy_audiohook);
198                 return -1;
199         }
200
201         f = ast_audiohook_read_frame(&csth->spy_audiohook, samples, AST_AUDIOHOOK_DIRECTION_BOTH, AST_FORMAT_SLINEAR);
202
203         ast_audiohook_unlock(&csth->spy_audiohook);
204
205         if (!f)
206                 return 0;
207
208         if (ast_write(chan, f)) {
209                 ast_frfree(f);
210                 return -1;
211         }
212
213         if (csth->fd)
214                 write(csth->fd, f->data, f->datalen);
215
216         ast_frfree(f);
217
218         return 0;
219 }
220
221 static struct ast_generator spygen = {
222         .alloc = spy_alloc,
223         .release = spy_release,
224         .generate = spy_generate,
225 };
226
227 static int start_spying(struct ast_channel *chan, const char *spychan_name, struct ast_audiohook *audiohook) 
228 {
229         int res = 0;
230         struct ast_channel *peer = NULL;
231
232         ast_log(LOG_NOTICE, "Attaching %s to %s\n", spychan_name, chan->name);
233
234         res = ast_audiohook_attach(chan, audiohook);
235
236         if (!res && ast_test_flag(chan, AST_FLAG_NBRIDGE) && (peer = ast_bridged_channel(chan))) {
237                 ast_channel_unlock(chan);
238                 ast_softhangup(peer, AST_SOFTHANGUP_UNBRIDGE);
239         } else
240                 ast_channel_unlock(chan);
241
242         return res;
243 }
244
245 struct chanspy_ds {
246         struct ast_channel *chan;
247         ast_mutex_t lock;
248 };
249
250 static int channel_spy(struct ast_channel *chan, struct chanspy_ds *spyee_chanspy_ds, 
251         int *volfactor, int fd, const struct ast_flags *flags, char *exitcontext) 
252 {
253         struct chanspy_translation_helper csth;
254         int running = 0, res, x = 0;
255         char inp[24] = {0};
256         char *name;
257         struct ast_frame *f;
258         struct ast_silence_generator *silgen = NULL;
259         struct ast_channel *spyee = NULL;
260         const char *spyer_name;
261
262         ast_channel_lock(chan);
263         spyer_name = ast_strdupa(chan->name);
264         ast_channel_unlock(chan);
265
266         ast_mutex_lock(&spyee_chanspy_ds->lock);
267         if (spyee_chanspy_ds->chan) {
268                 spyee = spyee_chanspy_ds->chan;
269                 ast_channel_lock(spyee);
270         }
271         ast_mutex_unlock(&spyee_chanspy_ds->lock);
272
273         if (!spyee)
274                 return 0;
275
276         /* We now hold the channel lock on spyee */
277
278         if (ast_check_hangup(chan) || ast_check_hangup(spyee)) {
279                 ast_channel_unlock(spyee);
280                 return 0;
281         }
282
283         name = ast_strdupa(spyee->name);
284         ast_verb(2, "Spying on channel %s\n", name);
285
286         memset(&csth, 0, sizeof(csth));
287
288         ast_audiohook_init(&csth.spy_audiohook, AST_AUDIOHOOK_TYPE_SPY, "ChanSpy");
289
290         if (start_spying(spyee, spyer_name, &csth.spy_audiohook)) { /* Unlocks spyee */
291                 ast_audiohook_destroy(&csth.spy_audiohook);
292                 return 0;
293         }
294
295         if (ast_test_flag(flags, OPTION_WHISPER)) {
296                 ast_audiohook_init(&csth.whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "ChanSpy");
297                 start_spying(spyee, spyer_name, &csth.whisper_audiohook); /* Unlocks spyee */
298         }
299
300         spyee = NULL;
301
302         csth.volfactor = *volfactor;
303
304         if (csth.volfactor) {
305                 csth.spy_audiohook.options.read_volume = csth.volfactor;
306                 csth.spy_audiohook.options.write_volume = csth.volfactor;
307         }
308
309         csth.fd = fd;
310
311         if (ast_test_flag(flags, OPTION_PRIVATE))
312                 silgen = ast_channel_start_silence_generator(chan);
313         else
314                 ast_activate_generator(chan, &spygen, &csth);
315
316         /* We can no longer rely on 'spyee' being an actual channel;
317            it can be hung up and freed out from under us. However, the
318            channel destructor will put NULL into our csth.spy.chan
319            field when that happens, so that is our signal that the spyee
320            channel has gone away.
321         */
322
323         /* Note: it is very important that the ast_waitfor() be the first
324            condition in this expression, so that if we wait for some period
325            of time before receiving a frame from our spying channel, we check
326            for hangup on the spied-on channel _after_ knowing that a frame
327            has arrived, since the spied-on channel could have gone away while
328            we were waiting
329         */
330         while ((res = ast_waitfor(chan, -1) > -1) && csth.spy_audiohook.status == AST_AUDIOHOOK_STATUS_RUNNING) {
331                 if (!(f = ast_read(chan)) || ast_check_hangup(chan)) {
332                         running = -1;
333                         break;
334                 }
335
336                 if (ast_test_flag(flags, OPTION_WHISPER) && f->frametype == AST_FRAME_VOICE) {
337                         ast_audiohook_lock(&csth.whisper_audiohook);
338                         ast_audiohook_write_frame(&csth.whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f);
339                         ast_audiohook_unlock(&csth.whisper_audiohook);
340                         ast_frfree(f);
341                         continue;
342                 }
343                 
344                 res = (f->frametype == AST_FRAME_DTMF) ? f->subclass : 0;
345                 ast_frfree(f);
346                 if (!res)
347                         continue;
348
349                 if (x == sizeof(inp))
350                         x = 0;
351
352                 if (res < 0) {
353                         running = -1;
354                         break;
355                 }
356
357                 if (ast_test_flag(flags, OPTION_EXIT)) {
358                         char tmp[2];
359                         tmp[0] = res;
360                         tmp[1] = '\0';
361                         if (!ast_goto_if_exists(chan, exitcontext, tmp, 1)) {
362                                 ast_debug(1, "Got DTMF %c, goto context %s\n", tmp[0], exitcontext);
363                                 pbx_builtin_setvar_helper(chan, "SPY_CHANNEL", name);
364                                 running = -2;
365                                 break;
366                         } else {
367                                 ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
368                         }
369                 } else if (res >= '0' && res <= '9') {
370                         inp[x++] = res;
371                 }
372
373                 if (res == '*') {
374                         running = 0;
375                         break;
376                 } else if (res == '#') {
377                         if (!ast_strlen_zero(inp)) {
378                                 running = atoi(inp);
379                                 break;
380                         }
381
382                         (*volfactor)++;
383                         if (*volfactor > 4)
384                                 *volfactor = -4;
385                         ast_verb(3, "Setting spy volume on %s to %d\n", chan->name, *volfactor);
386
387                         csth.volfactor = *volfactor;
388                         csth.spy_audiohook.options.read_volume = csth.volfactor;
389                         csth.spy_audiohook.options.write_volume = csth.volfactor;
390                 }
391         }
392
393         if (ast_test_flag(flags, OPTION_PRIVATE))
394                 ast_channel_stop_silence_generator(chan, silgen);
395         else
396                 ast_deactivate_generator(chan);
397
398         if (ast_test_flag(flags, OPTION_WHISPER)) {
399                 ast_audiohook_lock(&csth.whisper_audiohook);
400                 ast_audiohook_detach(&csth.whisper_audiohook);
401                 ast_audiohook_unlock(&csth.whisper_audiohook);
402                 ast_audiohook_destroy(&csth.whisper_audiohook);
403         }
404
405         ast_audiohook_lock(&csth.spy_audiohook);
406         ast_audiohook_detach(&csth.spy_audiohook);
407         ast_audiohook_unlock(&csth.spy_audiohook);
408         ast_audiohook_destroy(&csth.spy_audiohook);
409         
410         ast_verb(2, "Done Spying on channel %s\n", name);
411
412         return running;
413 }
414
415 /*!
416  * \note This relies on the embedded lock to be recursive, as it may be called
417  * due to a call to chanspy_ds_free with the lock held there.
418  */
419 static void chanspy_ds_destroy(void *data)
420 {
421         struct chanspy_ds *chanspy_ds = data;
422
423         /* Setting chan to be NULL is an atomic operation, but we don't want this
424          * value to change while this lock is held.  The lock is held elsewhere
425          * while it performs non-atomic operations with this channel pointer */
426
427         ast_mutex_lock(&chanspy_ds->lock);
428         chanspy_ds->chan = NULL;
429         ast_mutex_unlock(&chanspy_ds->lock);
430 }
431
432 static void chanspy_ds_chan_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
433 {
434         struct chanspy_ds *chanspy_ds = data;
435         
436         ast_mutex_lock(&chanspy_ds->lock);
437         chanspy_ds->chan = new_chan;
438         ast_mutex_unlock(&chanspy_ds->lock);
439 }
440
441 static const struct ast_datastore_info chanspy_ds_info = {
442         .type = "chanspy",
443         .destroy = chanspy_ds_destroy,
444         .chan_fixup = chanspy_ds_chan_fixup,
445 };
446
447 static struct chanspy_ds *chanspy_ds_free(struct chanspy_ds *chanspy_ds)
448 {
449         if (!chanspy_ds)
450                 return NULL;
451
452         ast_mutex_lock(&chanspy_ds->lock);
453         if (chanspy_ds->chan) {
454                 struct ast_datastore *datastore;
455                 struct ast_channel *chan;
456
457                 chan = chanspy_ds->chan;
458
459                 ast_channel_lock(chan);
460                 if ((datastore = ast_channel_datastore_find(chan, &chanspy_ds_info, NULL))) {
461                         ast_channel_datastore_remove(chan, datastore);
462                         /* chanspy_ds->chan is NULL after this call */
463                         chanspy_ds_destroy(datastore->data);
464                         datastore->data = NULL;
465                         ast_channel_datastore_free(datastore);
466                 }
467                 ast_channel_unlock(chan);
468         }
469         ast_mutex_unlock(&chanspy_ds->lock);
470
471         return NULL;
472 }
473
474 /*! \note Returns the channel in the chanspy_ds locked as well as the chanspy_ds locked */
475 static struct chanspy_ds *setup_chanspy_ds(struct ast_channel *chan, struct chanspy_ds *chanspy_ds)
476 {
477         struct ast_datastore *datastore = NULL;
478
479         ast_mutex_lock(&chanspy_ds->lock);
480
481         if (!(datastore = ast_channel_datastore_alloc(&chanspy_ds_info, NULL))) {
482                 ast_mutex_unlock(&chanspy_ds->lock);
483                 chanspy_ds = chanspy_ds_free(chanspy_ds);
484                 ast_channel_unlock(chan);
485                 return NULL;
486         }
487         
488         chanspy_ds->chan = chan;
489         datastore->data = chanspy_ds;
490         ast_channel_datastore_add(chan, datastore);
491
492         return chanspy_ds;
493 }
494
495 static struct chanspy_ds *next_channel(struct ast_channel *chan,
496         const struct ast_channel *last, const char *spec,
497         const char *exten, const char *context, struct chanspy_ds *chanspy_ds)
498 {
499         struct ast_channel *this;
500
501 redo:
502         if (!ast_strlen_zero(spec))
503                 this = ast_walk_channel_by_name_prefix_locked(last, spec, strlen(spec));
504
505         else if (!ast_strlen_zero(exten))
506                 this = ast_walk_channel_by_exten_locked(last, exten, context);
507         else
508                 this = ast_channel_walk_locked(last);
509
510         if (!this)
511                 return NULL;
512
513         if (!strncmp(this->name, "Zap/pseudo", 10)) {
514                 ast_channel_unlock(this);
515                 goto redo;
516         } else if (this == chan) {
517                 last = this;
518                 ast_channel_unlock(this);
519                 goto redo;
520         }
521
522         return setup_chanspy_ds(this, chanspy_ds);
523 }
524
525 static int common_exec(struct ast_channel *chan, const struct ast_flags *flags,
526         int volfactor, const int fd, const char *mygroup, const char *myenforced,
527         const char *spec, const char *exten, const char *context)
528 {
529         char nameprefix[AST_NAME_STRLEN];
530         char peer_name[AST_NAME_STRLEN + 5];
531         char exitcontext[AST_MAX_CONTEXT] = "";
532         signed char zero_volume = 0;
533         int waitms;
534         int res;
535         char *ptr;
536         int num;
537         int num_spyed_upon = 1;
538         struct chanspy_ds chanspy_ds;
539
540         if (ast_test_flag(flags, OPTION_EXIT)) {
541                 const char *c;
542                 if ((c = pbx_builtin_getvar_helper(chan, "SPY_EXIT_CONTEXT")))
543                         ast_copy_string(exitcontext, c, sizeof(exitcontext));
544                 else if (!ast_strlen_zero(chan->macrocontext))
545                         ast_copy_string(exitcontext, chan->macrocontext, sizeof(exitcontext));
546                 else
547                         ast_copy_string(exitcontext, chan->context, sizeof(exitcontext));
548         }
549
550         ast_mutex_init(&chanspy_ds.lock);
551
552         if (chan->_state != AST_STATE_UP)
553                 ast_answer(chan);
554
555         ast_set_flag(chan, AST_FLAG_SPYING); /* so nobody can spy on us while we are spying */
556
557         waitms = 100;
558
559         for (;;) {
560                 struct chanspy_ds *peer_chanspy_ds = NULL, *next_chanspy_ds = NULL;
561                 struct ast_channel *prev = NULL, *peer = NULL;
562
563                 if (!ast_test_flag(flags, OPTION_QUIET) && num_spyed_upon) {
564                         res = ast_streamfile(chan, "beep", chan->language);
565                         if (!res)
566                                 res = ast_waitstream(chan, "");
567                         else if (res < 0) {
568                                 ast_clear_flag(chan, AST_FLAG_SPYING);
569                                 break;
570                         }
571                         if (!ast_strlen_zero(exitcontext)) {
572                                 char tmp[2];
573                                 tmp[0] = res;
574                                 tmp[1] = '\0';
575                                 if (!ast_goto_if_exists(chan, exitcontext, tmp, 1))
576                                         goto exit;
577                                 else
578                                         ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
579                         }
580                 }
581
582                 res = ast_waitfordigit(chan, waitms);
583                 if (res < 0) {
584                         ast_clear_flag(chan, AST_FLAG_SPYING);
585                         break;
586                 }
587                 if (!ast_strlen_zero(exitcontext)) {
588                         char tmp[2];
589                         tmp[0] = res;
590                         tmp[1] = '\0';
591                         if (!ast_goto_if_exists(chan, exitcontext, tmp, 1))
592                                 goto exit;
593                         else
594                                 ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
595                 }
596
597                 /* reset for the next loop around, unless overridden later */
598                 waitms = 100;
599                 num_spyed_upon = 0;
600
601                 for (peer_chanspy_ds = next_channel(chan, prev, spec, exten, context, &chanspy_ds);
602                      peer_chanspy_ds;
603                          chanspy_ds_free(peer_chanspy_ds), prev = peer,
604                      peer_chanspy_ds = next_chanspy_ds ? next_chanspy_ds : 
605                                 next_channel(chan, prev, spec, exten, context, &chanspy_ds), next_chanspy_ds = NULL) {
606                         const char *group;
607                         int igrp = !mygroup;
608                         char *groups[25];
609                         int num_groups = 0;
610                         char *dup_group;
611                         int x;
612                         char *s;
613                         char *buffer;
614                         char *end;
615                         char *ext;
616                         char *form_enforced;
617                         int ienf = !myenforced;
618                         struct ast_channel *peer;
619
620                         peer = peer_chanspy_ds->chan;
621
622                         ast_mutex_unlock(&peer_chanspy_ds->lock);
623
624                         if (peer == prev) {
625                                 ast_channel_unlock(peer);
626                                 chanspy_ds_free(peer_chanspy_ds);
627                                 break;
628                         }
629
630                         if (ast_check_hangup(chan)) {
631                                 ast_channel_unlock(peer);
632                                 chanspy_ds_free(peer_chanspy_ds);
633                                 break;
634                         }
635
636                         if (ast_test_flag(flags, OPTION_BRIDGED) && !ast_bridged_channel(peer)) {
637                                 ast_channel_unlock(peer);
638                                 continue;
639                         }
640
641                         if (ast_check_hangup(peer) || ast_test_flag(peer, AST_FLAG_SPYING)) {
642                                 ast_channel_unlock(peer);
643                                 continue;
644                         }
645
646                         if (mygroup) {
647                                 if ((group = pbx_builtin_getvar_helper(peer, "SPYGROUP"))) {
648                                         dup_group = ast_strdupa(group);
649                                         num_groups = ast_app_separate_args(dup_group, ':', groups,
650                                                 sizeof(groups) / sizeof(groups[0]));
651                                 }
652
653                                 for (x = 0; x < num_groups; x++) {
654                                         if (!strcmp(mygroup, groups[x])) {
655                                                 igrp = 1;
656                                                 break;
657                                         }
658                                 }
659                         }
660
661                         if (!igrp) {
662                                 ast_channel_unlock(peer);
663                                 continue;
664                         }
665
666                         if (myenforced) {
667
668                                 /* We don't need to allocate more space than just the
669                                 length of (peer->name) for ext as we will cut the
670                                 channel name's ending before copying into ext */
671
672                                 ext = alloca(strlen(peer->name));
673
674                                 form_enforced = alloca(strlen(myenforced) + 3);
675
676                                 strcpy(form_enforced, ":");
677                                 strcat(form_enforced, myenforced);
678                                 strcat(form_enforced, ":");
679
680                                 buffer = ast_strdupa(peer->name);
681                                 
682                                 if ((end = strchr(buffer, '-'))) {
683                                         *end++ = ':';
684                                         *end = '\0';
685                                 }
686
687                                 strcpy(ext, ":");
688                                 strcat(ext, buffer);
689
690                                 if (strcasestr(form_enforced, ext))
691                                         ienf = 1;
692                         }
693
694                         if (!ienf)
695                                 continue;
696
697                         strcpy(peer_name, "spy-");
698                         strncat(peer_name, peer->name, AST_NAME_STRLEN - 4 - 1);
699                         ptr = strchr(peer_name, '/');
700                         *ptr++ = '\0';
701
702                         for (s = peer_name; s < ptr; s++)
703                                 *s = tolower(*s);
704                 
705                         /* We have to unlock the peer channel here to avoid a deadlock.
706                          * So, when we need it again, we have to lock the datastore and get
707                          * the pointer from there to see if the channel is still valid. */
708                         ast_channel_unlock(peer);
709                         peer = NULL;
710
711                         if (!ast_test_flag(flags, OPTION_QUIET)) {
712                                 if (ast_fileexists(peer_name, NULL, NULL) != -1) {
713                                         res = ast_streamfile(chan, peer_name, chan->language);
714                                         if (!res)
715                                                 res = ast_waitstream(chan, "");
716                                         if (res) {
717                                                 chanspy_ds_free(peer_chanspy_ds);
718                                                 break;
719                                         }
720                                 } else
721                                         res = ast_say_character_str(chan, peer_name, "", chan->language);
722                                 if ((num = atoi(ptr)))
723                                         ast_say_digits(chan, atoi(ptr), "", chan->language);
724                         }
725
726                         waitms = 5000;
727                         res = channel_spy(chan, peer_chanspy_ds, &volfactor, fd, flags, exitcontext);
728                         num_spyed_upon++;       
729
730                         if (res == -1) {
731                                 chanspy_ds_free(peer_chanspy_ds);
732                                 goto exit;
733                         } else if (res == -2) {
734                                 res = 0;
735                                 chanspy_ds_free(peer_chanspy_ds);
736                                 goto exit;
737                         } else if (res > 1 && spec) {
738                                 struct ast_channel *next;
739
740                                 snprintf(nameprefix, AST_NAME_STRLEN, "%s/%d", spec, res);
741
742                                 if ((next = ast_get_channel_by_name_prefix_locked(nameprefix, strlen(nameprefix)))) {
743                                         peer_chanspy_ds = chanspy_ds_free(peer_chanspy_ds);
744                                         next_chanspy_ds = setup_chanspy_ds(next, &chanspy_ds);
745                                 } else {
746                                         /* stay on this channel, if it is still valid */
747
748                                         ast_mutex_lock(&peer_chanspy_ds->lock);
749                                         if (peer_chanspy_ds->chan) {
750                                                 ast_channel_lock(peer_chanspy_ds->chan);
751                                                 next_chanspy_ds = peer_chanspy_ds;
752                                                 peer_chanspy_ds = NULL;
753                                         } else {
754                                                 /* the channel is gone */
755                                                 ast_mutex_unlock(&peer_chanspy_ds->lock);
756                                                 next_chanspy_ds = NULL;
757                                         }
758                                 }
759
760                                 peer = NULL;
761                         }
762                 }
763                 if (res == -1 || ast_check_hangup(chan))
764                         break;
765         }
766 exit:
767
768         ast_clear_flag(chan, AST_FLAG_SPYING);
769
770         ast_channel_setoption(chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);
771
772         ast_mutex_destroy(&chanspy_ds.lock);
773
774         return res;
775 }
776
777 static int chanspy_exec(struct ast_channel *chan, void *data)
778 {
779         char *myenforced = NULL;
780         char *mygroup = NULL;
781         char *recbase = NULL;
782         int fd = 0;
783         struct ast_flags flags;
784         int oldwf = 0;
785         int volfactor = 0;
786         int res;
787         AST_DECLARE_APP_ARGS(args,
788                 AST_APP_ARG(spec);
789                 AST_APP_ARG(options);
790         );
791         char *opts[OPT_ARG_ARRAY_SIZE];
792
793         data = ast_strdupa(data);
794         AST_STANDARD_APP_ARGS(args, data);
795
796         if (args.spec && !strcmp(args.spec, "all"))
797                 args.spec = NULL;
798
799         if (args.options) {
800                 ast_app_parse_options(spy_opts, &flags, opts, args.options);
801                 if (ast_test_flag(&flags, OPTION_GROUP))
802                         mygroup = opts[OPT_ARG_GROUP];
803
804                 if (ast_test_flag(&flags, OPTION_RECORD) &&
805                         !(recbase = opts[OPT_ARG_RECORD]))
806                         recbase = "chanspy";
807
808                 if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) {
809                         int vol;
810
811                         if ((sscanf(opts[OPT_ARG_VOLUME], "%d", &vol) != 1) || (vol > 4) || (vol < -4))
812                                 ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n");
813                         else
814                                 volfactor = vol;
815                 }
816
817                 if (ast_test_flag(&flags, OPTION_PRIVATE))
818                         ast_set_flag(&flags, OPTION_WHISPER);
819
820                 if (ast_test_flag(&flags, OPTION_ENFORCED))
821                         myenforced = opts[OPT_ARG_ENFORCED];
822
823         } else
824                 ast_clear_flag(&flags, AST_FLAGS_ALL);
825
826         oldwf = chan->writeformat;
827         if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
828                 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
829                 return -1;
830         }
831
832         if (recbase) {
833                 char filename[512];
834
835                 snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL));
836                 if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, AST_FILE_MODE)) <= 0) {
837                         ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename);
838                         fd = 0;
839                 }
840         }
841
842         res = common_exec(chan, &flags, volfactor, fd, mygroup, myenforced, args.spec, NULL, NULL);
843
844         if (fd)
845                 close(fd);
846
847         if (oldwf && ast_set_write_format(chan, oldwf) < 0)
848                 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
849
850         return res;
851 }
852
853 static int extenspy_exec(struct ast_channel *chan, void *data)
854 {
855         char *ptr, *exten = NULL;
856         char *mygroup = NULL;
857         char *recbase = NULL;
858         int fd = 0;
859         struct ast_flags flags;
860         int oldwf = 0;
861         int volfactor = 0;
862         int res;
863         AST_DECLARE_APP_ARGS(args,
864                 AST_APP_ARG(context);
865                 AST_APP_ARG(options);
866         );
867
868         data = ast_strdupa(data);
869
870         AST_STANDARD_APP_ARGS(args, data);
871         if (!ast_strlen_zero(args.context) && (ptr = strchr(args.context, '@'))) {
872                 exten = args.context;
873                 *ptr++ = '\0';
874                 args.context = ptr;
875         }
876
877         if (ast_strlen_zero(args.context))
878                 args.context = ast_strdupa(chan->context);
879
880         if (args.options) {
881                 char *opts[OPT_ARG_ARRAY_SIZE];
882
883                 ast_app_parse_options(spy_opts, &flags, opts, args.options);
884                 if (ast_test_flag(&flags, OPTION_GROUP))
885                         mygroup = opts[OPT_ARG_GROUP];
886
887                 if (ast_test_flag(&flags, OPTION_RECORD) &&
888                         !(recbase = opts[OPT_ARG_RECORD]))
889                         recbase = "chanspy";
890
891                 if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) {
892                         int vol;
893
894                         if ((sscanf(opts[OPT_ARG_VOLUME], "%d", &vol) != 1) || (vol > 4) || (vol < -4))
895                                 ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n");
896                         else
897                                 volfactor = vol;
898                 }
899
900                 if (ast_test_flag(&flags, OPTION_PRIVATE))
901                         ast_set_flag(&flags, OPTION_WHISPER);
902         } else
903                 ast_clear_flag(&flags, AST_FLAGS_ALL);
904
905         oldwf = chan->writeformat;
906         if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
907                 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
908                 return -1;
909         }
910
911         if (recbase) {
912                 char filename[512];
913
914                 snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL));
915                 if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, AST_FILE_MODE)) <= 0) {
916                         ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename);
917                         fd = 0;
918                 }
919         }
920
921
922         res = common_exec(chan, &flags, volfactor, fd, mygroup, NULL, NULL, exten, args.context);
923
924         if (fd)
925                 close(fd);
926
927         if (oldwf && ast_set_write_format(chan, oldwf) < 0)
928                 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
929
930         return res;
931 }
932
933 static int unload_module(void)
934 {
935         int res = 0;
936
937         res |= ast_unregister_application(app_chan);
938         res |= ast_unregister_application(app_ext);
939
940         return res;
941 }
942
943 static int load_module(void)
944 {
945         int res = 0;
946
947         res |= ast_register_application(app_chan, chanspy_exec, tdesc, desc_chan);
948         res |= ast_register_application(app_ext, extenspy_exec, tdesc, desc_ext);
949
950         return res;
951 }
952
953 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Listen to the audio of an active channel");