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