Merged revisions 108135 via svnmerge from
[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                 return 0;
280
281         name = ast_strdupa(spyee->name);
282         ast_verb(2, "Spying on channel %s\n", name);
283
284         memset(&csth, 0, sizeof(csth));
285
286         ast_audiohook_init(&csth.spy_audiohook, AST_AUDIOHOOK_TYPE_SPY, "ChanSpy");
287
288         if (start_spying(spyee, spyer_name, &csth.spy_audiohook)) { /* Unlocks spyee */
289                 ast_audiohook_destroy(&csth.spy_audiohook);
290                 return 0;
291         }
292
293         if (ast_test_flag(flags, OPTION_WHISPER)) {
294                 ast_audiohook_init(&csth.whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "ChanSpy");
295                 start_spying(spyee, spyer_name, &csth.whisper_audiohook); /* Unlocks spyee */
296         }
297
298         spyee = NULL;
299
300         csth.volfactor = *volfactor;
301
302         if (csth.volfactor) {
303                 csth.spy_audiohook.options.read_volume = csth.volfactor;
304                 csth.spy_audiohook.options.write_volume = csth.volfactor;
305         }
306
307         csth.fd = fd;
308
309         if (ast_test_flag(flags, OPTION_PRIVATE))
310                 silgen = ast_channel_start_silence_generator(chan);
311         else
312                 ast_activate_generator(chan, &spygen, &csth);
313
314         /* We can no longer rely on 'spyee' being an actual channel;
315            it can be hung up and freed out from under us. However, the
316            channel destructor will put NULL into our csth.spy.chan
317            field when that happens, so that is our signal that the spyee
318            channel has gone away.
319         */
320
321         /* Note: it is very important that the ast_waitfor() be the first
322            condition in this expression, so that if we wait for some period
323            of time before receiving a frame from our spying channel, we check
324            for hangup on the spied-on channel _after_ knowing that a frame
325            has arrived, since the spied-on channel could have gone away while
326            we were waiting
327         */
328         while ((res = ast_waitfor(chan, -1) > -1) && csth.spy_audiohook.status == AST_AUDIOHOOK_STATUS_RUNNING) {
329                 if (!(f = ast_read(chan)) || ast_check_hangup(chan)) {
330                         running = -1;
331                         break;
332                 }
333
334                 if (ast_test_flag(flags, OPTION_WHISPER) && f->frametype == AST_FRAME_VOICE) {
335                         ast_audiohook_lock(&csth.whisper_audiohook);
336                         ast_audiohook_write_frame(&csth.whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f);
337                         ast_audiohook_unlock(&csth.whisper_audiohook);
338                         ast_frfree(f);
339                         continue;
340                 }
341                 
342                 res = (f->frametype == AST_FRAME_DTMF) ? f->subclass : 0;
343                 ast_frfree(f);
344                 if (!res)
345                         continue;
346
347                 if (x == sizeof(inp))
348                         x = 0;
349
350                 if (res < 0) {
351                         running = -1;
352                         break;
353                 }
354
355                 if (ast_test_flag(flags, OPTION_EXIT)) {
356                         char tmp[2];
357                         tmp[0] = res;
358                         tmp[1] = '\0';
359                         if (!ast_goto_if_exists(chan, exitcontext, tmp, 1)) {
360                                 ast_debug(1, "Got DTMF %c, goto context %s\n", tmp[0], exitcontext);
361                                 pbx_builtin_setvar_helper(chan, "SPY_CHANNEL", name);
362                                 running = -2;
363                                 break;
364                         } else {
365                                 ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
366                         }
367                 } else if (res >= '0' && res <= '9') {
368                         inp[x++] = res;
369                 }
370
371                 if (res == '*') {
372                         running = 0;
373                         break;
374                 } else if (res == '#') {
375                         if (!ast_strlen_zero(inp)) {
376                                 running = atoi(inp);
377                                 break;
378                         }
379
380                         (*volfactor)++;
381                         if (*volfactor > 4)
382                                 *volfactor = -4;
383                         ast_verb(3, "Setting spy volume on %s to %d\n", chan->name, *volfactor);
384
385                         csth.volfactor = *volfactor;
386                         csth.spy_audiohook.options.read_volume = csth.volfactor;
387                         csth.spy_audiohook.options.write_volume = csth.volfactor;
388                 }
389         }
390
391         if (ast_test_flag(flags, OPTION_PRIVATE))
392                 ast_channel_stop_silence_generator(chan, silgen);
393         else
394                 ast_deactivate_generator(chan);
395
396         if (ast_test_flag(flags, OPTION_WHISPER)) {
397                 ast_audiohook_lock(&csth.whisper_audiohook);
398                 ast_audiohook_detach(&csth.whisper_audiohook);
399                 ast_audiohook_unlock(&csth.whisper_audiohook);
400                 ast_audiohook_destroy(&csth.whisper_audiohook);
401         }
402
403         ast_audiohook_lock(&csth.spy_audiohook);
404         ast_audiohook_detach(&csth.spy_audiohook);
405         ast_audiohook_unlock(&csth.spy_audiohook);
406         ast_audiohook_destroy(&csth.spy_audiohook);
407         
408         ast_verb(2, "Done Spying on channel %s\n", name);
409
410         return running;
411 }
412
413 /*!
414  * \note This relies on the embedded lock to be recursive, as it may be called
415  * due to a call to chanspy_ds_free with the lock held there.
416  */
417 static void chanspy_ds_destroy(void *data)
418 {
419         struct chanspy_ds *chanspy_ds = data;
420
421         /* Setting chan to be NULL is an atomic operation, but we don't want this
422          * value to change while this lock is held.  The lock is held elsewhere
423          * while it performs non-atomic operations with this channel pointer */
424
425         ast_mutex_lock(&chanspy_ds->lock);
426         chanspy_ds->chan = NULL;
427         ast_mutex_unlock(&chanspy_ds->lock);
428 }
429
430 static const struct ast_datastore_info chanspy_ds_info = {
431         .type = "chanspy",
432         .destroy = chanspy_ds_destroy,
433 };
434
435 static struct chanspy_ds *chanspy_ds_free(struct chanspy_ds *chanspy_ds)
436 {
437         if (!chanspy_ds)
438                 return NULL;
439
440         ast_mutex_lock(&chanspy_ds->lock);
441         if (chanspy_ds->chan) {
442                 struct ast_datastore *datastore;
443                 struct ast_channel *chan;
444
445                 chan = chanspy_ds->chan;
446
447                 ast_channel_lock(chan);
448                 if ((datastore = ast_channel_datastore_find(chan, &chanspy_ds_info, NULL))) {
449                         ast_channel_datastore_remove(chan, datastore);
450                         /* chanspy_ds->chan is NULL after this call */
451                         chanspy_ds_destroy(datastore->data);
452                         datastore->data = NULL;
453                         ast_channel_datastore_free(datastore);
454                 }
455                 ast_channel_unlock(chan);
456         }
457         ast_mutex_unlock(&chanspy_ds->lock);
458
459         return NULL;
460 }
461
462 /*! \note Returns the channel in the chanspy_ds locked as well as the chanspy_ds locked */
463 static struct chanspy_ds *setup_chanspy_ds(struct ast_channel *chan, struct chanspy_ds *chanspy_ds)
464 {
465         struct ast_datastore *datastore = NULL;
466
467         ast_mutex_lock(&chanspy_ds->lock);
468
469         chanspy_ds->chan = chan;
470
471         if (!(datastore = ast_channel_datastore_alloc(&chanspy_ds_info, NULL))) {
472                 chanspy_ds = chanspy_ds_free(chanspy_ds);
473                 ast_channel_unlock(chan);
474                 return NULL;
475         }
476
477         datastore->data = chanspy_ds;
478
479         ast_channel_datastore_add(chan, datastore);
480
481         return chanspy_ds;
482 }
483
484 static struct chanspy_ds *next_channel(struct ast_channel *chan,
485         const struct ast_channel *last, const char *spec,
486         const char *exten, const char *context, struct chanspy_ds *chanspy_ds)
487 {
488         struct ast_channel *this;
489
490 redo:
491         if (!ast_strlen_zero(spec))
492                 this = ast_walk_channel_by_name_prefix_locked(last, spec, strlen(spec));
493
494         else if (!ast_strlen_zero(exten))
495                 this = ast_walk_channel_by_exten_locked(last, exten, context);
496         else
497                 this = ast_channel_walk_locked(last);
498
499         if (!this)
500                 return NULL;
501
502         if (!strncmp(this->name, "Zap/pseudo", 10)) {
503                 ast_channel_unlock(this);
504                 goto redo;
505         } else if (this == chan) {
506                 last = this;
507                 ast_channel_unlock(this);
508                 goto redo;
509         }
510
511         return setup_chanspy_ds(this, chanspy_ds);
512 }
513
514 static int common_exec(struct ast_channel *chan, const struct ast_flags *flags,
515         int volfactor, const int fd, const char *mygroup, const char *myenforced,
516         const char *spec, const char *exten, const char *context)
517 {
518         char nameprefix[AST_NAME_STRLEN];
519         char peer_name[AST_NAME_STRLEN + 5];
520         char exitcontext[AST_MAX_CONTEXT] = "";
521         signed char zero_volume = 0;
522         int waitms;
523         int res;
524         char *ptr;
525         int num;
526         int num_spyed_upon = 1;
527         struct chanspy_ds chanspy_ds;
528
529         if (ast_test_flag(flags, OPTION_EXIT)) {
530                 const char *c;
531                 if ((c = pbx_builtin_getvar_helper(chan, "SPY_EXIT_CONTEXT")))
532                         ast_copy_string(exitcontext, c, sizeof(exitcontext));
533                 else if (!ast_strlen_zero(chan->macrocontext))
534                         ast_copy_string(exitcontext, chan->macrocontext, sizeof(exitcontext));
535                 else
536                         ast_copy_string(exitcontext, chan->context, sizeof(exitcontext));
537         }
538
539         ast_mutex_init(&chanspy_ds.lock);
540
541         if (chan->_state != AST_STATE_UP)
542                 ast_answer(chan);
543
544         ast_set_flag(chan, AST_FLAG_SPYING); /* so nobody can spy on us while we are spying */
545
546         waitms = 100;
547
548         for (;;) {
549                 struct chanspy_ds *peer_chanspy_ds = NULL, *next_chanspy_ds = NULL;
550                 struct ast_channel *prev = NULL, *peer = NULL;
551
552                 if (!ast_test_flag(flags, OPTION_QUIET) && num_spyed_upon) {
553                         res = ast_streamfile(chan, "beep", chan->language);
554                         if (!res)
555                                 res = ast_waitstream(chan, "");
556                         else if (res < 0) {
557                                 ast_clear_flag(chan, AST_FLAG_SPYING);
558                                 break;
559                         }
560                         if (!ast_strlen_zero(exitcontext)) {
561                                 char tmp[2];
562                                 tmp[0] = res;
563                                 tmp[1] = '\0';
564                                 if (!ast_goto_if_exists(chan, exitcontext, tmp, 1))
565                                         goto exit;
566                                 else
567                                         ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
568                         }
569                 }
570
571                 res = ast_waitfordigit(chan, waitms);
572                 if (res < 0) {
573                         ast_clear_flag(chan, AST_FLAG_SPYING);
574                         break;
575                 }
576                 if (!ast_strlen_zero(exitcontext)) {
577                         char tmp[2];
578                         tmp[0] = res;
579                         tmp[1] = '\0';
580                         if (!ast_goto_if_exists(chan, exitcontext, tmp, 1))
581                                 goto exit;
582                         else
583                                 ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
584                 }
585
586                 /* reset for the next loop around, unless overridden later */
587                 waitms = 100;
588                 num_spyed_upon = 0;
589
590                 for (peer_chanspy_ds = next_channel(chan, prev, spec, exten, context, &chanspy_ds);
591                      peer_chanspy_ds;
592                          chanspy_ds_free(peer_chanspy_ds), prev = peer,
593                      peer_chanspy_ds = next_chanspy_ds ? next_chanspy_ds : 
594                                 next_channel(chan, prev, spec, exten, context, &chanspy_ds), next_chanspy_ds = NULL) {
595                         const char *group;
596                         int igrp = !mygroup;
597                         char *groups[25];
598                         int num_groups = 0;
599                         char *dup_group;
600                         int x;
601                         char *s;
602                         char *buffer;
603                         char *end;
604                         char *ext;
605                         char *form_enforced;
606                         int ienf = !myenforced;
607                         struct ast_channel *peer;
608
609                         peer = peer_chanspy_ds->chan;
610
611                         ast_mutex_unlock(&peer_chanspy_ds->lock);
612
613                         if (peer == prev) {
614                                 ast_channel_unlock(peer);
615                                 chanspy_ds_free(peer_chanspy_ds);
616                                 break;
617                         }
618
619                         if (ast_check_hangup(chan)) {
620                                 ast_channel_unlock(peer);
621                                 chanspy_ds_free(peer_chanspy_ds);
622                                 break;
623                         }
624
625                         if (ast_test_flag(flags, OPTION_BRIDGED) && !ast_bridged_channel(peer)) {
626                                 ast_channel_unlock(peer);
627                                 continue;
628                         }
629
630                         if (ast_check_hangup(peer) || ast_test_flag(peer, AST_FLAG_SPYING)) {
631                                 ast_channel_unlock(peer);
632                                 continue;
633                         }
634
635                         if (mygroup) {
636                                 if ((group = pbx_builtin_getvar_helper(peer, "SPYGROUP"))) {
637                                         dup_group = ast_strdupa(group);
638                                         num_groups = ast_app_separate_args(dup_group, ':', groups,
639                                                 sizeof(groups) / sizeof(groups[0]));
640                                 }
641
642                                 for (x = 0; x < num_groups; x++) {
643                                         if (!strcmp(mygroup, groups[x])) {
644                                                 igrp = 1;
645                                                 break;
646                                         }
647                                 }
648                         }
649
650                         if (!igrp) {
651                                 ast_channel_unlock(peer);
652                                 continue;
653                         }
654
655                         if (myenforced) {
656
657                                 /* We don't need to allocate more space than just the
658                                 length of (peer->name) for ext as we will cut the
659                                 channel name's ending before copying into ext */
660
661                                 ext = alloca(strlen(peer->name));
662
663                                 form_enforced = alloca(strlen(myenforced) + 3);
664
665                                 strcpy(form_enforced, ":");
666                                 strcat(form_enforced, myenforced);
667                                 strcat(form_enforced, ":");
668
669                                 buffer = ast_strdupa(peer->name);
670                                 
671                                 if ((end = strchr(buffer, '-'))) {
672                                         *end++ = ':';
673                                         *end = '\0';
674                                 }
675
676                                 strcpy(ext, ":");
677                                 strcat(ext, buffer);
678
679                                 if (strcasestr(form_enforced, ext))
680                                         ienf = 1;
681                         }
682
683                         if (!ienf)
684                                 continue;
685
686                         strcpy(peer_name, "spy-");
687                         strncat(peer_name, peer->name, AST_NAME_STRLEN - 4 - 1);
688                         ptr = strchr(peer_name, '/');
689                         *ptr++ = '\0';
690
691                         for (s = peer_name; s < ptr; s++)
692                                 *s = tolower(*s);
693                 
694                         /* We have to unlock the peer channel here to avoid a deadlock.
695                          * So, when we need it again, we have to lock the datastore and get
696                          * the pointer from there to see if the channel is still valid. */
697                         ast_channel_unlock(peer);
698                         peer = NULL;
699
700                         if (!ast_test_flag(flags, OPTION_QUIET)) {
701                                 if (ast_fileexists(peer_name, NULL, NULL) != -1) {
702                                         res = ast_streamfile(chan, peer_name, chan->language);
703                                         if (!res)
704                                                 res = ast_waitstream(chan, "");
705                                         if (res)
706                                                 break;
707                                 } else
708                                         res = ast_say_character_str(chan, peer_name, "", chan->language);
709                                 if ((num = atoi(ptr)))
710                                         ast_say_digits(chan, atoi(ptr), "", chan->language);
711                         }
712
713                         waitms = 5000;
714                         res = channel_spy(chan, peer_chanspy_ds, &volfactor, fd, flags, exitcontext);
715                         num_spyed_upon++;       
716
717                         if (res == -1) {
718                                 chanspy_ds_free(peer_chanspy_ds);
719                                 goto exit;
720                         } else if (res == -2) {
721                                 res = 0;
722                                 goto exit;
723                         } else if (res > 1 && spec) {
724                                 struct ast_channel *next;
725
726                                 snprintf(nameprefix, AST_NAME_STRLEN, "%s/%d", spec, res);
727
728                                 if ((next = ast_get_channel_by_name_prefix_locked(nameprefix, strlen(nameprefix)))) {
729                                         peer_chanspy_ds = chanspy_ds_free(peer_chanspy_ds);
730                                         next_chanspy_ds = setup_chanspy_ds(next, &chanspy_ds);
731                                 } else {
732                                         /* stay on this channel, if it is still valid */
733
734                                         ast_mutex_lock(&peer_chanspy_ds->lock);
735                                         if (peer_chanspy_ds->chan) {
736                                                 ast_channel_lock(peer_chanspy_ds->chan);
737                                                 next_chanspy_ds = peer_chanspy_ds;
738                                                 peer_chanspy_ds = NULL;
739                                         } else {
740                                                 /* the channel is gone */
741                                                 ast_mutex_unlock(&peer_chanspy_ds->lock);
742                                                 next_chanspy_ds = NULL;
743                                         }
744                                 }
745
746                                 peer = NULL;
747                         }
748                 }
749                 if (res == -1 || ast_check_hangup(chan))
750                         break;
751         }
752 exit:
753
754         ast_clear_flag(chan, AST_FLAG_SPYING);
755
756         ast_channel_setoption(chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);
757
758         ast_mutex_destroy(&chanspy_ds.lock);
759
760         return res;
761 }
762
763 static int chanspy_exec(struct ast_channel *chan, void *data)
764 {
765         char *myenforced = NULL;
766         char *mygroup = NULL;
767         char *recbase = NULL;
768         int fd = 0;
769         struct ast_flags flags;
770         int oldwf = 0;
771         int volfactor = 0;
772         int res;
773         AST_DECLARE_APP_ARGS(args,
774                 AST_APP_ARG(spec);
775                 AST_APP_ARG(options);
776         );
777         char *opts[OPT_ARG_ARRAY_SIZE];
778
779         data = ast_strdupa(data);
780         AST_STANDARD_APP_ARGS(args, data);
781
782         if (args.spec && !strcmp(args.spec, "all"))
783                 args.spec = NULL;
784
785         if (args.options) {
786                 ast_app_parse_options(spy_opts, &flags, opts, args.options);
787                 if (ast_test_flag(&flags, OPTION_GROUP))
788                         mygroup = opts[OPT_ARG_GROUP];
789
790                 if (ast_test_flag(&flags, OPTION_RECORD) &&
791                         !(recbase = opts[OPT_ARG_RECORD]))
792                         recbase = "chanspy";
793
794                 if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) {
795                         int vol;
796
797                         if ((sscanf(opts[OPT_ARG_VOLUME], "%d", &vol) != 1) || (vol > 4) || (vol < -4))
798                                 ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n");
799                         else
800                                 volfactor = vol;
801                 }
802
803                 if (ast_test_flag(&flags, OPTION_PRIVATE))
804                         ast_set_flag(&flags, OPTION_WHISPER);
805
806                 if (ast_test_flag(&flags, OPTION_ENFORCED))
807                         myenforced = opts[OPT_ARG_ENFORCED];
808
809         } else
810                 ast_clear_flag(&flags, AST_FLAGS_ALL);
811
812         oldwf = chan->writeformat;
813         if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
814                 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
815                 return -1;
816         }
817
818         if (recbase) {
819                 char filename[512];
820
821                 snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL));
822                 if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, AST_FILE_MODE)) <= 0) {
823                         ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename);
824                         fd = 0;
825                 }
826         }
827
828         res = common_exec(chan, &flags, volfactor, fd, mygroup, myenforced, args.spec, NULL, NULL);
829
830         if (fd)
831                 close(fd);
832
833         if (oldwf && ast_set_write_format(chan, oldwf) < 0)
834                 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
835
836         return res;
837 }
838
839 static int extenspy_exec(struct ast_channel *chan, void *data)
840 {
841         char *ptr, *exten = NULL;
842         char *mygroup = NULL;
843         char *recbase = NULL;
844         int fd = 0;
845         struct ast_flags flags;
846         int oldwf = 0;
847         int volfactor = 0;
848         int res;
849         AST_DECLARE_APP_ARGS(args,
850                 AST_APP_ARG(context);
851                 AST_APP_ARG(options);
852         );
853
854         data = ast_strdupa(data);
855
856         AST_STANDARD_APP_ARGS(args, data);
857         if (!ast_strlen_zero(args.context) && (ptr = strchr(args.context, '@'))) {
858                 exten = args.context;
859                 *ptr++ = '\0';
860                 args.context = ptr;
861         }
862
863         if (ast_strlen_zero(args.context))
864                 args.context = ast_strdupa(chan->context);
865
866         if (args.options) {
867                 char *opts[OPT_ARG_ARRAY_SIZE];
868
869                 ast_app_parse_options(spy_opts, &flags, opts, args.options);
870                 if (ast_test_flag(&flags, OPTION_GROUP))
871                         mygroup = opts[OPT_ARG_GROUP];
872
873                 if (ast_test_flag(&flags, OPTION_RECORD) &&
874                         !(recbase = opts[OPT_ARG_RECORD]))
875                         recbase = "chanspy";
876
877                 if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) {
878                         int vol;
879
880                         if ((sscanf(opts[OPT_ARG_VOLUME], "%d", &vol) != 1) || (vol > 4) || (vol < -4))
881                                 ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n");
882                         else
883                                 volfactor = vol;
884                 }
885
886                 if (ast_test_flag(&flags, OPTION_PRIVATE))
887                         ast_set_flag(&flags, OPTION_WHISPER);
888         } else
889                 ast_clear_flag(&flags, AST_FLAGS_ALL);
890
891         oldwf = chan->writeformat;
892         if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
893                 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
894                 return -1;
895         }
896
897         if (recbase) {
898                 char filename[512];
899
900                 snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL));
901                 if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, AST_FILE_MODE)) <= 0) {
902                         ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename);
903                         fd = 0;
904                 }
905         }
906
907
908         res = common_exec(chan, &flags, volfactor, fd, mygroup, NULL, NULL, exten, args.context);
909
910         if (fd)
911                 close(fd);
912
913         if (oldwf && ast_set_write_format(chan, oldwf) < 0)
914                 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
915
916         return res;
917 }
918
919 static int unload_module(void)
920 {
921         int res = 0;
922
923         res |= ast_unregister_application(app_chan);
924         res |= ast_unregister_application(app_ext);
925
926         return res;
927 }
928
929 static int load_module(void)
930 {
931         int res = 0;
932
933         res |= ast_register_application(app_chan, chanspy_exec, tdesc, desc_chan);
934         res |= ast_register_application(app_ext, extenspy_exec, tdesc, desc_ext);
935
936         return res;
937 }
938
939 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Listen to the audio of an active channel");