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