I'm not sure why, but "this" bothers me. Ba dum dum.
[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 *next;
500
501 redo:
502         if (!ast_strlen_zero(spec))
503                 next = ast_walk_channel_by_name_prefix_locked(last, spec, strlen(spec));
504         else if (!ast_strlen_zero(exten))
505                 next = ast_walk_channel_by_exten_locked(last, exten, context);
506         else
507                 next = ast_channel_walk_locked(last);
508
509         if (!next)
510                 return NULL;
511
512         if (!strncmp(next->name, "Zap/pseudo", 10)) {
513                 ast_channel_unlock(next);
514                 goto redo;
515         } else if (next == chan) {
516                 last = next;
517                 ast_channel_unlock(next);
518                 goto redo;
519         }
520
521         return setup_chanspy_ds(next, chanspy_ds);
522 }
523
524 static int common_exec(struct ast_channel *chan, const struct ast_flags *flags,
525         int volfactor, const int fd, const char *mygroup, const char *myenforced,
526         const char *spec, const char *exten, const char *context)
527 {
528         char nameprefix[AST_NAME_STRLEN];
529         char peer_name[AST_NAME_STRLEN + 5];
530         char exitcontext[AST_MAX_CONTEXT] = "";
531         signed char zero_volume = 0;
532         int waitms;
533         int res;
534         char *ptr;
535         int num;
536         int num_spyed_upon = 1;
537         struct chanspy_ds chanspy_ds;
538
539         if (ast_test_flag(flags, OPTION_EXIT)) {
540                 const char *c;
541                 if ((c = pbx_builtin_getvar_helper(chan, "SPY_EXIT_CONTEXT")))
542                         ast_copy_string(exitcontext, c, sizeof(exitcontext));
543                 else if (!ast_strlen_zero(chan->macrocontext))
544                         ast_copy_string(exitcontext, chan->macrocontext, sizeof(exitcontext));
545                 else
546                         ast_copy_string(exitcontext, chan->context, sizeof(exitcontext));
547         }
548
549         ast_mutex_init(&chanspy_ds.lock);
550
551         if (chan->_state != AST_STATE_UP)
552                 ast_answer(chan);
553
554         ast_set_flag(chan, AST_FLAG_SPYING); /* so nobody can spy on us while we are spying */
555
556         waitms = 100;
557
558         for (;;) {
559                 struct chanspy_ds *peer_chanspy_ds = NULL, *next_chanspy_ds = NULL;
560                 struct ast_channel *prev = NULL, *peer = NULL;
561
562                 if (!ast_test_flag(flags, OPTION_QUIET) && num_spyed_upon) {
563                         res = ast_streamfile(chan, "beep", chan->language);
564                         if (!res)
565                                 res = ast_waitstream(chan, "");
566                         else if (res < 0) {
567                                 ast_clear_flag(chan, AST_FLAG_SPYING);
568                                 break;
569                         }
570                         if (!ast_strlen_zero(exitcontext)) {
571                                 char tmp[2];
572                                 tmp[0] = res;
573                                 tmp[1] = '\0';
574                                 if (!ast_goto_if_exists(chan, exitcontext, tmp, 1))
575                                         goto exit;
576                                 else
577                                         ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
578                         }
579                 }
580
581                 res = ast_waitfordigit(chan, waitms);
582                 if (res < 0) {
583                         ast_clear_flag(chan, AST_FLAG_SPYING);
584                         break;
585                 }
586                 if (!ast_strlen_zero(exitcontext)) {
587                         char tmp[2];
588                         tmp[0] = res;
589                         tmp[1] = '\0';
590                         if (!ast_goto_if_exists(chan, exitcontext, tmp, 1))
591                                 goto exit;
592                         else
593                                 ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
594                 }
595
596                 /* reset for the next loop around, unless overridden later */
597                 waitms = 100;
598                 num_spyed_upon = 0;
599
600                 for (peer_chanspy_ds = next_channel(chan, prev, spec, exten, context, &chanspy_ds);
601                      peer_chanspy_ds;
602                          chanspy_ds_free(peer_chanspy_ds), prev = peer,
603                      peer_chanspy_ds = next_chanspy_ds ? next_chanspy_ds : 
604                                 next_channel(chan, prev, spec, exten, context, &chanspy_ds), next_chanspy_ds = NULL) {
605                         const char *group;
606                         int igrp = !mygroup;
607                         char *groups[25];
608                         int num_groups = 0;
609                         char *dup_group;
610                         int x;
611                         char *s;
612                         char *buffer;
613                         char *end;
614                         char *ext;
615                         char *form_enforced;
616                         int ienf = !myenforced;
617                         struct ast_channel *peer;
618
619                         peer = peer_chanspy_ds->chan;
620
621                         ast_mutex_unlock(&peer_chanspy_ds->lock);
622
623                         if (peer == prev) {
624                                 ast_channel_unlock(peer);
625                                 chanspy_ds_free(peer_chanspy_ds);
626                                 break;
627                         }
628
629                         if (ast_check_hangup(chan)) {
630                                 ast_channel_unlock(peer);
631                                 chanspy_ds_free(peer_chanspy_ds);
632                                 break;
633                         }
634
635                         if (ast_test_flag(flags, OPTION_BRIDGED) && !ast_bridged_channel(peer)) {
636                                 ast_channel_unlock(peer);
637                                 continue;
638                         }
639
640                         if (ast_check_hangup(peer) || ast_test_flag(peer, AST_FLAG_SPYING)) {
641                                 ast_channel_unlock(peer);
642                                 continue;
643                         }
644
645                         if (mygroup) {
646                                 if ((group = pbx_builtin_getvar_helper(peer, "SPYGROUP"))) {
647                                         dup_group = ast_strdupa(group);
648                                         num_groups = ast_app_separate_args(dup_group, ':', groups,
649                                                 sizeof(groups) / sizeof(groups[0]));
650                                 }
651
652                                 for (x = 0; x < num_groups; x++) {
653                                         if (!strcmp(mygroup, groups[x])) {
654                                                 igrp = 1;
655                                                 break;
656                                         }
657                                 }
658                         }
659
660                         if (!igrp) {
661                                 ast_channel_unlock(peer);
662                                 continue;
663                         }
664
665                         if (myenforced) {
666
667                                 /* We don't need to allocate more space than just the
668                                 length of (peer->name) for ext as we will cut the
669                                 channel name's ending before copying into ext */
670
671                                 ext = alloca(strlen(peer->name));
672
673                                 form_enforced = alloca(strlen(myenforced) + 3);
674
675                                 strcpy(form_enforced, ":");
676                                 strcat(form_enforced, myenforced);
677                                 strcat(form_enforced, ":");
678
679                                 buffer = ast_strdupa(peer->name);
680                                 
681                                 if ((end = strchr(buffer, '-'))) {
682                                         *end++ = ':';
683                                         *end = '\0';
684                                 }
685
686                                 strcpy(ext, ":");
687                                 strcat(ext, buffer);
688
689                                 if (strcasestr(form_enforced, ext))
690                                         ienf = 1;
691                         }
692
693                         if (!ienf)
694                                 continue;
695
696                         strcpy(peer_name, "spy-");
697                         strncat(peer_name, peer->name, AST_NAME_STRLEN - 4 - 1);
698                         ptr = strchr(peer_name, '/');
699                         *ptr++ = '\0';
700
701                         for (s = peer_name; s < ptr; s++)
702                                 *s = tolower(*s);
703                 
704                         /* We have to unlock the peer channel here to avoid a deadlock.
705                          * So, when we need it again, we have to lock the datastore and get
706                          * the pointer from there to see if the channel is still valid. */
707                         ast_channel_unlock(peer);
708                         peer = NULL;
709
710                         if (!ast_test_flag(flags, OPTION_QUIET)) {
711                                 if (ast_fileexists(peer_name, NULL, NULL) != -1) {
712                                         res = ast_streamfile(chan, peer_name, chan->language);
713                                         if (!res)
714                                                 res = ast_waitstream(chan, "");
715                                         if (res) {
716                                                 chanspy_ds_free(peer_chanspy_ds);
717                                                 break;
718                                         }
719                                 } else
720                                         res = ast_say_character_str(chan, peer_name, "", chan->language);
721                                 if ((num = atoi(ptr)))
722                                         ast_say_digits(chan, atoi(ptr), "", chan->language);
723                         }
724
725                         waitms = 5000;
726                         res = channel_spy(chan, peer_chanspy_ds, &volfactor, fd, flags, exitcontext);
727                         num_spyed_upon++;       
728
729                         if (res == -1) {
730                                 chanspy_ds_free(peer_chanspy_ds);
731                                 goto exit;
732                         } else if (res == -2) {
733                                 res = 0;
734                                 chanspy_ds_free(peer_chanspy_ds);
735                                 goto exit;
736                         } else if (res > 1 && spec) {
737                                 struct ast_channel *next;
738
739                                 snprintf(nameprefix, AST_NAME_STRLEN, "%s/%d", spec, res);
740
741                                 if ((next = ast_get_channel_by_name_prefix_locked(nameprefix, strlen(nameprefix)))) {
742                                         peer_chanspy_ds = chanspy_ds_free(peer_chanspy_ds);
743                                         next_chanspy_ds = setup_chanspy_ds(next, &chanspy_ds);
744                                 } else {
745                                         /* stay on this channel, if it is still valid */
746
747                                         ast_mutex_lock(&peer_chanspy_ds->lock);
748                                         if (peer_chanspy_ds->chan) {
749                                                 ast_channel_lock(peer_chanspy_ds->chan);
750                                                 next_chanspy_ds = peer_chanspy_ds;
751                                                 peer_chanspy_ds = NULL;
752                                         } else {
753                                                 /* the channel is gone */
754                                                 ast_mutex_unlock(&peer_chanspy_ds->lock);
755                                                 next_chanspy_ds = NULL;
756                                         }
757                                 }
758
759                                 peer = NULL;
760                         }
761                 }
762                 if (res == -1 || ast_check_hangup(chan))
763                         break;
764         }
765 exit:
766
767         ast_clear_flag(chan, AST_FLAG_SPYING);
768
769         ast_channel_setoption(chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);
770
771         ast_mutex_destroy(&chanspy_ds.lock);
772
773         return res;
774 }
775
776 static int chanspy_exec(struct ast_channel *chan, void *data)
777 {
778         char *myenforced = NULL;
779         char *mygroup = NULL;
780         char *recbase = NULL;
781         int fd = 0;
782         struct ast_flags flags;
783         int oldwf = 0;
784         int volfactor = 0;
785         int res;
786         AST_DECLARE_APP_ARGS(args,
787                 AST_APP_ARG(spec);
788                 AST_APP_ARG(options);
789         );
790         char *opts[OPT_ARG_ARRAY_SIZE];
791
792         data = ast_strdupa(data);
793         AST_STANDARD_APP_ARGS(args, data);
794
795         if (args.spec && !strcmp(args.spec, "all"))
796                 args.spec = NULL;
797
798         if (args.options) {
799                 ast_app_parse_options(spy_opts, &flags, opts, args.options);
800                 if (ast_test_flag(&flags, OPTION_GROUP))
801                         mygroup = opts[OPT_ARG_GROUP];
802
803                 if (ast_test_flag(&flags, OPTION_RECORD) &&
804                         !(recbase = opts[OPT_ARG_RECORD]))
805                         recbase = "chanspy";
806
807                 if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) {
808                         int vol;
809
810                         if ((sscanf(opts[OPT_ARG_VOLUME], "%d", &vol) != 1) || (vol > 4) || (vol < -4))
811                                 ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n");
812                         else
813                                 volfactor = vol;
814                 }
815
816                 if (ast_test_flag(&flags, OPTION_PRIVATE))
817                         ast_set_flag(&flags, OPTION_WHISPER);
818
819                 if (ast_test_flag(&flags, OPTION_ENFORCED))
820                         myenforced = opts[OPT_ARG_ENFORCED];
821
822         } else
823                 ast_clear_flag(&flags, AST_FLAGS_ALL);
824
825         oldwf = chan->writeformat;
826         if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
827                 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
828                 return -1;
829         }
830
831         if (recbase) {
832                 char filename[512];
833
834                 snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL));
835                 if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, AST_FILE_MODE)) <= 0) {
836                         ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename);
837                         fd = 0;
838                 }
839         }
840
841         res = common_exec(chan, &flags, volfactor, fd, mygroup, myenforced, args.spec, NULL, NULL);
842
843         if (fd)
844                 close(fd);
845
846         if (oldwf && ast_set_write_format(chan, oldwf) < 0)
847                 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
848
849         return res;
850 }
851
852 static int extenspy_exec(struct ast_channel *chan, void *data)
853 {
854         char *ptr, *exten = NULL;
855         char *mygroup = NULL;
856         char *recbase = NULL;
857         int fd = 0;
858         struct ast_flags flags;
859         int oldwf = 0;
860         int volfactor = 0;
861         int res;
862         AST_DECLARE_APP_ARGS(args,
863                 AST_APP_ARG(context);
864                 AST_APP_ARG(options);
865         );
866
867         data = ast_strdupa(data);
868
869         AST_STANDARD_APP_ARGS(args, data);
870         if (!ast_strlen_zero(args.context) && (ptr = strchr(args.context, '@'))) {
871                 exten = args.context;
872                 *ptr++ = '\0';
873                 args.context = ptr;
874         }
875
876         if (ast_strlen_zero(args.context))
877                 args.context = ast_strdupa(chan->context);
878
879         if (args.options) {
880                 char *opts[OPT_ARG_ARRAY_SIZE];
881
882                 ast_app_parse_options(spy_opts, &flags, opts, args.options);
883                 if (ast_test_flag(&flags, OPTION_GROUP))
884                         mygroup = opts[OPT_ARG_GROUP];
885
886                 if (ast_test_flag(&flags, OPTION_RECORD) &&
887                         !(recbase = opts[OPT_ARG_RECORD]))
888                         recbase = "chanspy";
889
890                 if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) {
891                         int vol;
892
893                         if ((sscanf(opts[OPT_ARG_VOLUME], "%d", &vol) != 1) || (vol > 4) || (vol < -4))
894                                 ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n");
895                         else
896                                 volfactor = vol;
897                 }
898
899                 if (ast_test_flag(&flags, OPTION_PRIVATE))
900                         ast_set_flag(&flags, OPTION_WHISPER);
901         } else
902                 ast_clear_flag(&flags, AST_FLAGS_ALL);
903
904         oldwf = chan->writeformat;
905         if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
906                 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
907                 return -1;
908         }
909
910         if (recbase) {
911                 char filename[512];
912
913                 snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL));
914                 if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, AST_FILE_MODE)) <= 0) {
915                         ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename);
916                         fd = 0;
917                 }
918         }
919
920
921         res = common_exec(chan, &flags, volfactor, fd, mygroup, NULL, NULL, exten, args.context);
922
923         if (fd)
924                 close(fd);
925
926         if (oldwf && ast_set_write_format(chan, oldwf) < 0)
927                 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
928
929         return res;
930 }
931
932 static int unload_module(void)
933 {
934         int res = 0;
935
936         res |= ast_unregister_application(app_chan);
937         res |= ast_unregister_application(app_ext);
938
939         return res;
940 }
941
942 static int load_module(void)
943 {
944         int res = 0;
945
946         res |= ast_register_application(app_chan, chanspy_exec, tdesc, desc_chan);
947         res |= ast_register_application(app_ext, extenspy_exec, tdesc, desc_ext);
948
949         return res;
950 }
951
952 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Listen to the audio of an active channel");