2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 2005 Anthony Minessale II (anthmct@yahoo.com)
5 * Copyright (C) 2005 - 2008, Digium, Inc.
7 * A license has been granted to Digium (via disclaimer) for the use of
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.
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.
23 * \brief ChanSpy: Listen in on any channel.
25 * \author Anthony Minessale II <anthmct@yahoo.com>
26 * \author Joshua Colp <jcolp@digium.com>
27 * \author Russell Bryant <russell@digium.com>
29 * \ingroup applications
34 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
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"
51 #define AST_NAME_STRLEN 256
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"
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"
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 " n([mailbox][@context]) - Say the name of the person being spied on if that person has recorded\n"
76 " his/her name. If a context is specified, then that voicemail context will\n"
77 " be searched when retrieving the name, otherwise the \"default\" context\n"
78 " will be searched. If no mailbox is specified, then the channel name will\n"
79 " be used when searching for the name (i.e. if SIP/1000 is the channel being\n"
80 " spied on and no mailbox is specified, then \"1000\" will be used when searching\n"
82 " q - Don't play a beep when beginning to spy on a channel, or speak the\n"
83 " selected channel name.\n"
84 " r[(basename)] - Record the session to the monitor spool directory. An\n"
85 " optional base for the filename may be specified. The\n"
86 " default is 'chanspy'.\n"
87 " s - Skip the playback of the channel type (i.e. SIP, IAX, etc) when\n"
88 " speaking the selected channel name.\n"
89 " v([value]) - Adjust the initial volume in the range from -4 to 4. A\n"
90 " negative value refers to a quieter setting.\n"
91 " w - Enable 'whisper' mode, so the spying channel can talk to\n"
92 " the spied-on channel.\n"
93 " W - Enable 'private whisper' mode, so the spying channel can\n"
94 " talk to the spied-on channel but cannot listen to that\n"
96 " o - Only listen to audio coming from this channel.\n"
97 " X - Allow the user to exit ChanSpy to a valid single digit\n"
98 " numeric extension in the current context or the context\n"
99 " specified by the SPY_EXIT_CONTEXT channel variable. The\n"
100 " name of the last channel that was spied on will be stored\n"
101 " in the SPY_CHANNEL variable.\n"
102 " e(ext) - Enable 'enforced' mode, so the spying channel can\n"
103 " only monitor extensions whose name is in the 'ext' : \n"
107 static const char *app_ext = "ExtenSpy";
108 static const char *desc_ext =
109 " ExtenSpy(exten[@context][,options]): This application is used to listen to the\n"
110 "audio from an Asterisk channel. This includes the audio coming in and\n"
111 "out of the channel being spied on. Only channels created by outgoing calls for the\n"
112 "specified extension will be selected for spying. If the optional context is not\n"
113 "supplied, the current channel's context will be used.\n"
114 " While spying, the following actions may be performed:\n"
115 " - Dialing # cycles the volume level.\n"
116 " - Dialing * will stop spying and look for another channel to spy on.\n"
117 " Note: The X option superseeds the two features above in that if a valid\n"
118 " single digit extension exists in the correct context it ChanSpy will\n"
121 " b - Only spy on channels involved in a bridged call.\n"
122 " g(grp) - Match only channels where their ${SPYGROUP} variable is set to\n"
123 " contain 'grp' in an optional : delimited list.\n"
124 " n([mailbox][@context]) - Say the name of the person being spied on if that person has recorded\n"
125 " his/her name. If a context is specified, then that voicemail context will\n"
126 " be searched when retrieving the name, otherwise the \"default\" context\n"
127 " will be searched. If no mailbox is specified, then the channel name will\n"
128 " be used when searching for the name (i.e. if SIP/1000 is the channel being\n"
129 " spied on and no mailbox is specified, then \"1000\" will be used when searching\n"
131 " q - Don't play a beep when beginning to spy on a channel, or speak the\n"
132 " selected channel name.\n"
133 " r[(basename)] - Record the session to the monitor spool directory. An\n"
134 " optional base for the filename may be specified. The\n"
135 " default is 'chanspy'.\n"
136 " s - Skip the playback of the channel type (i.e. SIP, IAX, etc) when\n"
137 " speaking the selected channel name.\n"
138 " v([value]) - Adjust the initial volume in the range from -4 to 4. A\n"
139 " negative value refers to a quieter setting.\n"
140 " w - Enable 'whisper' mode, so the spying channel can talk to\n"
141 " the spied-on channel.\n"
142 " W - Enable 'private whisper' mode, so the spying channel can\n"
143 " talk to the spied-on channel but cannot listen to that\n"
145 " o - Only listen to audio coming from this channel.\n"
146 " X - Allow the user to exit ChanSpy to a valid single digit\n"
147 " numeric extension in the current context or the context\n"
148 " specified by the SPY_EXIT_CONTEXT channel variable. The\n"
149 " name of the last channel that was spied on will be stored\n"
150 " in the SPY_CHANNEL variable.\n"
154 OPTION_QUIET = (1 << 0), /* Quiet, no announcement */
155 OPTION_BRIDGED = (1 << 1), /* Only look at bridged calls */
156 OPTION_VOLUME = (1 << 2), /* Specify initial volume */
157 OPTION_GROUP = (1 << 3), /* Only look at channels in group */
158 OPTION_RECORD = (1 << 4),
159 OPTION_WHISPER = (1 << 5),
160 OPTION_PRIVATE = (1 << 6), /* Private Whisper mode */
161 OPTION_READONLY = (1 << 7), /* Don't mix the two channels */
162 OPTION_EXIT = (1 << 8), /* Exit to a valid single digit extension */
163 OPTION_ENFORCED = (1 << 9), /* Enforced mode */
164 OPTION_NOTECH = (1 << 10), /* Skip technology name playback */
165 OPTION_BARGE = (1 << 11), /* Barge mode (whisper to both channels) */
166 OPTION_NAME = (1 << 12), /* Say the name of the person on whom we will spy */
178 AST_APP_OPTIONS(spy_opts, {
179 AST_APP_OPTION('q', OPTION_QUIET),
180 AST_APP_OPTION('b', OPTION_BRIDGED),
181 AST_APP_OPTION('B', OPTION_BARGE),
182 AST_APP_OPTION('w', OPTION_WHISPER),
183 AST_APP_OPTION('W', OPTION_PRIVATE),
184 AST_APP_OPTION_ARG('v', OPTION_VOLUME, OPT_ARG_VOLUME),
185 AST_APP_OPTION_ARG('g', OPTION_GROUP, OPT_ARG_GROUP),
186 AST_APP_OPTION_ARG('r', OPTION_RECORD, OPT_ARG_RECORD),
187 AST_APP_OPTION_ARG('e', OPTION_ENFORCED, OPT_ARG_ENFORCED),
188 AST_APP_OPTION('o', OPTION_READONLY),
189 AST_APP_OPTION('X', OPTION_EXIT),
190 AST_APP_OPTION('s', OPTION_NOTECH),
191 AST_APP_OPTION_ARG('n', OPTION_NAME, OPT_ARG_NAME),
195 struct chanspy_translation_helper {
197 struct ast_audiohook spy_audiohook;
198 struct ast_audiohook whisper_audiohook;
199 struct ast_audiohook bridge_whisper_audiohook;
204 static void *spy_alloc(struct ast_channel *chan, void *data)
206 /* just store the data pointer in the channel structure */
210 static void spy_release(struct ast_channel *chan, void *data)
215 static int spy_generate(struct ast_channel *chan, void *data, int len, int samples)
217 struct chanspy_translation_helper *csth = data;
218 struct ast_frame *f = NULL;
220 ast_audiohook_lock(&csth->spy_audiohook);
221 if (csth->spy_audiohook.status != AST_AUDIOHOOK_STATUS_RUNNING) {
222 /* Channel is already gone more than likely */
223 ast_audiohook_unlock(&csth->spy_audiohook);
227 f = ast_audiohook_read_frame(&csth->spy_audiohook, samples, AST_AUDIOHOOK_DIRECTION_BOTH, AST_FORMAT_SLINEAR);
229 ast_audiohook_unlock(&csth->spy_audiohook);
234 if (ast_write(chan, f)) {
240 write(csth->fd, f->data, f->datalen);
247 static struct ast_generator spygen = {
249 .release = spy_release,
250 .generate = spy_generate,
253 static int start_spying(struct ast_channel *chan, const char *spychan_name, struct ast_audiohook *audiohook)
256 struct ast_channel *peer = NULL;
258 ast_log(LOG_NOTICE, "Attaching %s to %s\n", spychan_name, chan->name);
260 res = ast_audiohook_attach(chan, audiohook);
262 if (!res && ast_test_flag(chan, AST_FLAG_NBRIDGE) && (peer = ast_bridged_channel(chan))) {
263 ast_softhangup(peer, AST_SOFTHANGUP_UNBRIDGE);
269 struct ast_channel *chan;
273 static int channel_spy(struct ast_channel *chan, struct chanspy_ds *spyee_chanspy_ds,
274 int *volfactor, int fd, const struct ast_flags *flags, char *exitcontext)
276 struct chanspy_translation_helper csth;
277 int running = 0, res, x = 0;
281 struct ast_silence_generator *silgen = NULL;
282 struct ast_channel *spyee = NULL;
283 const char *spyer_name;
285 ast_channel_lock(chan);
286 spyer_name = ast_strdupa(chan->name);
287 ast_channel_unlock(chan);
289 ast_mutex_lock(&spyee_chanspy_ds->lock);
290 if (spyee_chanspy_ds->chan) {
291 spyee = spyee_chanspy_ds->chan;
292 ast_channel_lock(spyee);
294 ast_mutex_unlock(&spyee_chanspy_ds->lock);
299 /* We now hold the channel lock on spyee */
301 if (ast_check_hangup(chan) || ast_check_hangup(spyee)) {
302 ast_channel_unlock(spyee);
306 name = ast_strdupa(spyee->name);
307 ast_verb(2, "Spying on channel %s\n", name);
309 memset(&csth, 0, sizeof(csth));
311 ast_audiohook_init(&csth.spy_audiohook, AST_AUDIOHOOK_TYPE_SPY, "ChanSpy");
313 if (start_spying(spyee, spyer_name, &csth.spy_audiohook)) {
314 ast_audiohook_destroy(&csth.spy_audiohook);
315 ast_channel_unlock(spyee);
319 if (ast_test_flag(flags, OPTION_BARGE)) {
320 ast_audiohook_init(&csth.whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "ChanSpy");
321 ast_audiohook_init(&csth.bridge_whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "Chanspy");
322 start_spying(spyee, spyer_name, &csth.whisper_audiohook); /* Unlocks spyee */
323 start_spying(ast_bridged_channel(spyee), spyer_name, &csth.bridge_whisper_audiohook);
324 } else if (ast_test_flag(flags, OPTION_WHISPER)) {
325 ast_audiohook_init(&csth.whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "ChanSpy");
326 start_spying(spyee, spyer_name, &csth.whisper_audiohook); /* Unlocks spyee */
329 ast_channel_unlock(spyee);
332 csth.volfactor = *volfactor;
334 if (csth.volfactor) {
335 csth.spy_audiohook.options.read_volume = csth.volfactor;
336 csth.spy_audiohook.options.write_volume = csth.volfactor;
341 if (ast_test_flag(flags, OPTION_PRIVATE))
342 silgen = ast_channel_start_silence_generator(chan);
344 ast_activate_generator(chan, &spygen, &csth);
346 /* We can no longer rely on 'spyee' being an actual channel;
347 it can be hung up and freed out from under us. However, the
348 channel destructor will put NULL into our csth.spy.chan
349 field when that happens, so that is our signal that the spyee
350 channel has gone away.
353 /* Note: it is very important that the ast_waitfor() be the first
354 condition in this expression, so that if we wait for some period
355 of time before receiving a frame from our spying channel, we check
356 for hangup on the spied-on channel _after_ knowing that a frame
357 has arrived, since the spied-on channel could have gone away while
360 while ((res = ast_waitfor(chan, -1) > -1) && csth.spy_audiohook.status == AST_AUDIOHOOK_STATUS_RUNNING) {
361 if (!(f = ast_read(chan)) || ast_check_hangup(chan)) {
366 if (ast_test_flag(flags, OPTION_BARGE) && f->frametype == AST_FRAME_VOICE) {
367 ast_audiohook_lock(&csth.whisper_audiohook);
368 ast_audiohook_lock(&csth.bridge_whisper_audiohook);
369 ast_audiohook_write_frame(&csth.whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f);
370 ast_audiohook_write_frame(&csth.bridge_whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f);
371 ast_audiohook_unlock(&csth.whisper_audiohook);
372 ast_audiohook_unlock(&csth.bridge_whisper_audiohook);
375 } else if (ast_test_flag(flags, OPTION_WHISPER) && f->frametype == AST_FRAME_VOICE) {
376 ast_audiohook_lock(&csth.whisper_audiohook);
377 ast_audiohook_write_frame(&csth.whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f);
378 ast_audiohook_unlock(&csth.whisper_audiohook);
383 res = (f->frametype == AST_FRAME_DTMF) ? f->subclass : 0;
388 if (x == sizeof(inp))
396 if (ast_test_flag(flags, OPTION_EXIT)) {
400 if (!ast_goto_if_exists(chan, exitcontext, tmp, 1)) {
401 ast_debug(1, "Got DTMF %c, goto context %s\n", tmp[0], exitcontext);
402 pbx_builtin_setvar_helper(chan, "SPY_CHANNEL", name);
406 ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
408 } else if (res >= '0' && res <= '9') {
415 } else if (res == '#') {
416 if (!ast_strlen_zero(inp)) {
424 ast_verb(3, "Setting spy volume on %s to %d\n", chan->name, *volfactor);
426 csth.volfactor = *volfactor;
427 csth.spy_audiohook.options.read_volume = csth.volfactor;
428 csth.spy_audiohook.options.write_volume = csth.volfactor;
432 if (ast_test_flag(flags, OPTION_PRIVATE))
433 ast_channel_stop_silence_generator(chan, silgen);
435 ast_deactivate_generator(chan);
437 if (ast_test_flag(flags, OPTION_BARGE)) {
438 ast_audiohook_lock(&csth.whisper_audiohook);
439 ast_audiohook_detach(&csth.whisper_audiohook);
440 ast_audiohook_unlock(&csth.whisper_audiohook);
441 ast_audiohook_destroy(&csth.whisper_audiohook);
442 ast_audiohook_lock(&csth.bridge_whisper_audiohook);
443 ast_audiohook_detach(&csth.bridge_whisper_audiohook);
444 ast_audiohook_unlock(&csth.bridge_whisper_audiohook);
445 ast_audiohook_destroy(&csth.bridge_whisper_audiohook);
446 } else if (ast_test_flag(flags, OPTION_WHISPER)) {
447 ast_audiohook_lock(&csth.whisper_audiohook);
448 ast_audiohook_detach(&csth.whisper_audiohook);
449 ast_audiohook_unlock(&csth.whisper_audiohook);
450 ast_audiohook_destroy(&csth.whisper_audiohook);
453 ast_audiohook_lock(&csth.spy_audiohook);
454 ast_audiohook_detach(&csth.spy_audiohook);
455 ast_audiohook_unlock(&csth.spy_audiohook);
456 ast_audiohook_destroy(&csth.spy_audiohook);
458 ast_verb(2, "Done Spying on channel %s\n", name);
464 * \note This relies on the embedded lock to be recursive, as it may be called
465 * due to a call to chanspy_ds_free with the lock held there.
467 static void chanspy_ds_destroy(void *data)
469 struct chanspy_ds *chanspy_ds = data;
471 /* Setting chan to be NULL is an atomic operation, but we don't want this
472 * value to change while this lock is held. The lock is held elsewhere
473 * while it performs non-atomic operations with this channel pointer */
475 ast_mutex_lock(&chanspy_ds->lock);
476 chanspy_ds->chan = NULL;
477 ast_mutex_unlock(&chanspy_ds->lock);
480 static void chanspy_ds_chan_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
482 struct chanspy_ds *chanspy_ds = data;
484 ast_mutex_lock(&chanspy_ds->lock);
485 chanspy_ds->chan = new_chan;
486 ast_mutex_unlock(&chanspy_ds->lock);
489 static const struct ast_datastore_info chanspy_ds_info = {
491 .destroy = chanspy_ds_destroy,
492 .chan_fixup = chanspy_ds_chan_fixup,
495 static struct chanspy_ds *chanspy_ds_free(struct chanspy_ds *chanspy_ds)
500 ast_mutex_lock(&chanspy_ds->lock);
501 if (chanspy_ds->chan) {
502 struct ast_datastore *datastore;
503 struct ast_channel *chan;
505 chan = chanspy_ds->chan;
507 ast_channel_lock(chan);
508 if ((datastore = ast_channel_datastore_find(chan, &chanspy_ds_info, NULL))) {
509 ast_channel_datastore_remove(chan, datastore);
510 /* chanspy_ds->chan is NULL after this call */
511 chanspy_ds_destroy(datastore->data);
512 datastore->data = NULL;
513 ast_channel_datastore_free(datastore);
515 ast_channel_unlock(chan);
517 ast_mutex_unlock(&chanspy_ds->lock);
522 /*! \note Returns the channel in the chanspy_ds locked as well as the chanspy_ds locked */
523 static struct chanspy_ds *setup_chanspy_ds(struct ast_channel *chan, struct chanspy_ds *chanspy_ds)
525 struct ast_datastore *datastore = NULL;
527 ast_mutex_lock(&chanspy_ds->lock);
529 if (!(datastore = ast_channel_datastore_alloc(&chanspy_ds_info, NULL))) {
530 ast_mutex_unlock(&chanspy_ds->lock);
531 chanspy_ds = chanspy_ds_free(chanspy_ds);
532 ast_channel_unlock(chan);
536 chanspy_ds->chan = chan;
537 datastore->data = chanspy_ds;
538 ast_channel_datastore_add(chan, datastore);
543 static struct chanspy_ds *next_channel(struct ast_channel *chan,
544 const struct ast_channel *last, const char *spec,
545 const char *exten, const char *context, struct chanspy_ds *chanspy_ds)
547 struct ast_channel *next;
550 if (!ast_strlen_zero(spec))
551 next = ast_walk_channel_by_name_prefix_locked(last, spec, strlen(spec));
552 else if (!ast_strlen_zero(exten))
553 next = ast_walk_channel_by_exten_locked(last, exten, context);
555 next = ast_channel_walk_locked(last);
560 if (!strncmp(next->name, "Zap/pseudo", 10)) {
561 ast_channel_unlock(next);
563 } else if (next == chan) {
565 ast_channel_unlock(next);
569 return setup_chanspy_ds(next, chanspy_ds);
572 static int common_exec(struct ast_channel *chan, const struct ast_flags *flags,
573 int volfactor, const int fd, const char *mygroup, const char *myenforced,
574 const char *spec, const char *exten, const char *context, const char *mailbox,
575 const char *name_context)
577 char nameprefix[AST_NAME_STRLEN];
578 char peer_name[AST_NAME_STRLEN + 5];
579 char exitcontext[AST_MAX_CONTEXT] = "";
580 signed char zero_volume = 0;
585 int num_spyed_upon = 1;
586 struct chanspy_ds chanspy_ds;
588 if (ast_test_flag(flags, OPTION_EXIT)) {
590 if ((c = pbx_builtin_getvar_helper(chan, "SPY_EXIT_CONTEXT")))
591 ast_copy_string(exitcontext, c, sizeof(exitcontext));
592 else if (!ast_strlen_zero(chan->macrocontext))
593 ast_copy_string(exitcontext, chan->macrocontext, sizeof(exitcontext));
595 ast_copy_string(exitcontext, chan->context, sizeof(exitcontext));
598 ast_mutex_init(&chanspy_ds.lock);
600 if (chan->_state != AST_STATE_UP)
603 ast_set_flag(chan, AST_FLAG_SPYING); /* so nobody can spy on us while we are spying */
608 struct chanspy_ds *peer_chanspy_ds = NULL, *next_chanspy_ds = NULL;
609 struct ast_channel *prev = NULL, *peer = NULL;
611 if (!ast_test_flag(flags, OPTION_QUIET) && num_spyed_upon) {
612 res = ast_streamfile(chan, "beep", chan->language);
614 res = ast_waitstream(chan, "");
616 ast_clear_flag(chan, AST_FLAG_SPYING);
619 if (!ast_strlen_zero(exitcontext)) {
623 if (!ast_goto_if_exists(chan, exitcontext, tmp, 1))
626 ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
630 res = ast_waitfordigit(chan, waitms);
632 ast_clear_flag(chan, AST_FLAG_SPYING);
635 if (!ast_strlen_zero(exitcontext)) {
639 if (!ast_goto_if_exists(chan, exitcontext, tmp, 1))
642 ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
645 /* reset for the next loop around, unless overridden later */
649 for (peer_chanspy_ds = next_channel(chan, prev, spec, exten, context, &chanspy_ds);
651 chanspy_ds_free(peer_chanspy_ds), prev = peer,
652 peer_chanspy_ds = next_chanspy_ds ? next_chanspy_ds :
653 next_channel(chan, prev, spec, exten, context, &chanspy_ds), next_chanspy_ds = NULL) {
665 int ienf = !myenforced;
667 peer = peer_chanspy_ds->chan;
669 ast_mutex_unlock(&peer_chanspy_ds->lock);
672 ast_channel_unlock(peer);
673 chanspy_ds_free(peer_chanspy_ds);
677 if (ast_check_hangup(chan)) {
678 ast_channel_unlock(peer);
679 chanspy_ds_free(peer_chanspy_ds);
683 if (ast_test_flag(flags, OPTION_BRIDGED) && !ast_bridged_channel(peer)) {
684 ast_channel_unlock(peer);
688 if (ast_check_hangup(peer) || ast_test_flag(peer, AST_FLAG_SPYING)) {
689 ast_channel_unlock(peer);
694 if ((group = pbx_builtin_getvar_helper(peer, "SPYGROUP"))) {
695 dup_group = ast_strdupa(group);
696 num_groups = ast_app_separate_args(dup_group, ':', groups,
697 sizeof(groups) / sizeof(groups[0]));
700 for (x = 0; x < num_groups; x++) {
701 if (!strcmp(mygroup, groups[x])) {
709 ast_channel_unlock(peer);
715 /* We don't need to allocate more space than just the
716 length of (peer->name) for ext as we will cut the
717 channel name's ending before copying into ext */
719 ext = alloca(strlen(peer->name));
721 form_enforced = alloca(strlen(myenforced) + 3);
723 strcpy(form_enforced, ":");
724 strcat(form_enforced, myenforced);
725 strcat(form_enforced, ":");
727 buffer = ast_strdupa(peer->name);
729 if ((end = strchr(buffer, '-'))) {
737 if (strcasestr(form_enforced, ext))
744 strcpy(peer_name, "spy-");
745 strncat(peer_name, peer->name, AST_NAME_STRLEN - 4 - 1);
746 ptr = strchr(peer_name, '/');
748 ptr = strsep(&ptr, "-");
750 for (s = peer_name; s < ptr; s++)
752 /* We have to unlock the peer channel here to avoid a deadlock.
753 * So, when we need to dereference it again, we have to lock the
754 * datastore and get the pointer from there to see if the channel
756 ast_channel_unlock(peer);
758 if (!ast_test_flag(flags, OPTION_QUIET)) {
759 if (ast_test_flag(flags, OPTION_NAME)) {
760 const char *local_context = S_OR(name_context, "default");
761 const char *local_mailbox = S_OR(mailbox, ptr);
762 res = ast_app_sayname(chan, local_mailbox, local_context);
764 if (!ast_test_flag(flags, OPTION_NAME) || res < 0) {
765 if (!ast_test_flag(flags, OPTION_NOTECH)) {
766 if (ast_fileexists(peer_name, NULL, NULL) != -1) {
767 res = ast_streamfile(chan, peer_name, chan->language);
769 res = ast_waitstream(chan, "");
772 chanspy_ds_free(peer_chanspy_ds);
776 res = ast_say_character_str(chan, peer_name, "", chan->language);
779 if ((num = atoi(ptr)))
780 ast_say_digits(chan, atoi(ptr), "", chan->language);
784 res = channel_spy(chan, peer_chanspy_ds, &volfactor, fd, flags, exitcontext);
788 chanspy_ds_free(peer_chanspy_ds);
790 } else if (res == -2) {
792 chanspy_ds_free(peer_chanspy_ds);
794 } else if (res > 1 && spec) {
795 struct ast_channel *next;
797 snprintf(nameprefix, AST_NAME_STRLEN, "%s/%d", spec, res);
799 if ((next = ast_get_channel_by_name_prefix_locked(nameprefix, strlen(nameprefix)))) {
800 peer_chanspy_ds = chanspy_ds_free(peer_chanspy_ds);
801 next_chanspy_ds = setup_chanspy_ds(next, &chanspy_ds);
803 /* stay on this channel, if it is still valid */
805 ast_mutex_lock(&peer_chanspy_ds->lock);
806 if (peer_chanspy_ds->chan) {
807 ast_channel_lock(peer_chanspy_ds->chan);
808 next_chanspy_ds = peer_chanspy_ds;
809 peer_chanspy_ds = NULL;
811 /* the channel is gone */
812 ast_mutex_unlock(&peer_chanspy_ds->lock);
813 next_chanspy_ds = NULL;
820 if (res == -1 || ast_check_hangup(chan))
825 ast_clear_flag(chan, AST_FLAG_SPYING);
827 ast_channel_setoption(chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);
829 ast_mutex_destroy(&chanspy_ds.lock);
834 static int chanspy_exec(struct ast_channel *chan, void *data)
836 char *myenforced = NULL;
837 char *mygroup = NULL;
838 char *recbase = NULL;
840 struct ast_flags flags;
844 char *mailbox = NULL;
845 char *name_context = NULL;
846 AST_DECLARE_APP_ARGS(args,
848 AST_APP_ARG(options);
850 char *opts[OPT_ARG_ARRAY_SIZE];
852 data = ast_strdupa(data);
853 AST_STANDARD_APP_ARGS(args, data);
855 if (args.spec && !strcmp(args.spec, "all"))
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];
863 if (ast_test_flag(&flags, OPTION_RECORD) &&
864 !(recbase = opts[OPT_ARG_RECORD]))
867 if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) {
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");
876 if (ast_test_flag(&flags, OPTION_PRIVATE))
877 ast_set_flag(&flags, OPTION_WHISPER);
879 if (ast_test_flag(&flags, OPTION_ENFORCED))
880 myenforced = opts[OPT_ARG_ENFORCED];
882 if (ast_test_flag(&flags, OPTION_NAME)) {
883 if (!ast_strlen_zero(opts[OPT_ARG_NAME])) {
885 if ((delimiter = strchr(opts[OPT_ARG_NAME], '@'))) {
886 mailbox = opts[OPT_ARG_NAME];
888 name_context = delimiter;
890 mailbox = opts[OPT_ARG_NAME];
897 ast_clear_flag(&flags, AST_FLAGS_ALL);
899 oldwf = chan->writeformat;
900 if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
901 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
906 char filename[PATH_MAX];
908 snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL));
909 if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, AST_FILE_MODE)) <= 0) {
910 ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename);
915 res = common_exec(chan, &flags, volfactor, fd, mygroup, myenforced, args.spec, NULL, NULL, mailbox, name_context);
920 if (oldwf && ast_set_write_format(chan, oldwf) < 0)
921 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
926 static int extenspy_exec(struct ast_channel *chan, void *data)
928 char *ptr, *exten = NULL;
929 char *mygroup = NULL;
930 char *recbase = NULL;
932 struct ast_flags flags;
936 char *mailbox = NULL;
937 char *name_context = NULL;
938 AST_DECLARE_APP_ARGS(args,
939 AST_APP_ARG(context);
940 AST_APP_ARG(options);
943 data = ast_strdupa(data);
945 AST_STANDARD_APP_ARGS(args, data);
946 if (!ast_strlen_zero(args.context) && (ptr = strchr(args.context, '@'))) {
947 exten = args.context;
952 if (ast_strlen_zero(args.context))
953 args.context = ast_strdupa(chan->context);
956 char *opts[OPT_ARG_ARRAY_SIZE];
958 ast_app_parse_options(spy_opts, &flags, opts, args.options);
959 if (ast_test_flag(&flags, OPTION_GROUP))
960 mygroup = opts[OPT_ARG_GROUP];
962 if (ast_test_flag(&flags, OPTION_RECORD) &&
963 !(recbase = opts[OPT_ARG_RECORD]))
966 if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) {
969 if ((sscanf(opts[OPT_ARG_VOLUME], "%d", &vol) != 1) || (vol > 4) || (vol < -4))
970 ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n");
975 if (ast_test_flag(&flags, OPTION_PRIVATE))
976 ast_set_flag(&flags, OPTION_WHISPER);
979 if (ast_test_flag(&flags, OPTION_NAME)) {
980 if (!ast_strlen_zero(opts[OPT_ARG_NAME])) {
982 if ((delimiter = strchr(opts[OPT_ARG_NAME], '@'))) {
983 mailbox = opts[OPT_ARG_NAME];
985 name_context = delimiter;
987 mailbox = opts[OPT_ARG_NAME];
993 ast_clear_flag(&flags, AST_FLAGS_ALL);
995 oldwf = chan->writeformat;
996 if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
997 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
1002 char filename[PATH_MAX];
1004 snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL));
1005 if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, AST_FILE_MODE)) <= 0) {
1006 ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename);
1012 res = common_exec(chan, &flags, volfactor, fd, mygroup, NULL, NULL, exten, args.context, mailbox, name_context);
1017 if (oldwf && ast_set_write_format(chan, oldwf) < 0)
1018 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
1023 static int unload_module(void)
1027 res |= ast_unregister_application(app_chan);
1028 res |= ast_unregister_application(app_ext);
1033 static int load_module(void)
1037 res |= ast_register_application(app_chan, chanspy_exec, tdesc, desc_chan);
1038 res |= ast_register_application(app_ext, extenspy_exec, tdesc, desc_ext);
1043 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Listen to the audio of an active channel");