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
52 #define NUM_SPYGROUPS 128
54 static const char *tdesc = "Listen to a channel, and optionally whisper into it";
55 static const char *app_chan = "ChanSpy";
56 static const char *desc_chan =
57 " ChanSpy([chanprefix][,options]): This application is used to listen to the\n"
58 "audio from an Asterisk channel. This includes the audio coming in and\n"
59 "out of the channel being spied on. If the 'chanprefix' parameter is specified,\n"
60 "only channels beginning with this string will be spied upon.\n"
61 " While spying, the following actions may be performed:\n"
62 " - Dialing # cycles the volume level.\n"
63 " - Dialing * will stop spying and look for another channel to spy on.\n"
64 " - Dialing a series of digits followed by # builds a channel name to append\n"
65 " to 'chanprefix'. For example, executing ChanSpy(Agent) and then dialing\n"
66 " the digits '1234#' while spying will begin spying on the channel\n"
68 " Note: The X option supersedes the three features above in that if a valid\n"
69 " single digit extension exists in the correct context ChanSpy will\n"
70 " exit to it. This also disables choosing a channel based on 'chanprefix'\n"
71 " and a digit sequence.\n"
73 " b - Only spy on channels involved in a bridged call.\n"
74 " g(grp) - Only spy on channels in which one or more of the groups \n"
75 " listed in 'grp' matches one or more groups from the\n"
76 " SPYGROUP variable set on the channel to be spied upon.\n"
77 " Note that both 'grp' and SPYGROUP can contain either a\n"
78 " single group or a colon-delimited list of groups, such\n"
79 " as 'sales:support:accounting'.\n"
80 " n([mailbox][@context]) - Say the name of the person being spied on if that person has recorded\n"
81 " his/her name. If a context is specified, then that voicemail context will\n"
82 " be searched when retrieving the name, otherwise the \"default\" context\n"
83 " will be searched. If no mailbox is specified, then the channel name will\n"
84 " be used when searching for the name (i.e. if SIP/1000 is the channel being\n"
85 " spied on and no mailbox is specified, then \"1000\" will be used when searching\n"
87 " q - Don't play a beep when beginning to spy on a channel, or speak the\n"
88 " selected channel name.\n"
89 " r[(basename)] - Record the session to the monitor spool directory. An\n"
90 " optional base for the filename may be specified. The\n"
91 " default is 'chanspy'.\n"
92 " s - Skip the playback of the channel type (i.e. SIP, IAX, etc) when\n"
93 " speaking the selected channel name.\n"
94 " v([value]) - Adjust the initial volume in the range from -4 to 4. A\n"
95 " negative value refers to a quieter setting.\n"
96 " w - Enable 'whisper' mode, so the spying channel can talk to\n"
97 " the spied-on channel.\n"
98 " W - Enable 'private whisper' mode, so the spying channel can\n"
99 " talk to the spied-on channel but cannot listen to that\n"
101 " o - Only listen to audio coming from this channel.\n"
102 " X - Allow the user to exit ChanSpy to a valid single digit\n"
103 " numeric extension in the current context or the context\n"
104 " specified by the SPY_EXIT_CONTEXT channel variable. The\n"
105 " name of the last channel that was spied on will be stored\n"
106 " in the SPY_CHANNEL variable.\n"
107 " e(ext) - Enable 'enforced' mode, so the spying channel can\n"
108 " only monitor extensions whose name is in the 'ext' : \n"
112 static const char *app_ext = "ExtenSpy";
113 static const char *desc_ext =
114 " ExtenSpy(exten[@context][,options]): This application is used to listen to the\n"
115 "audio from an Asterisk channel. This includes the audio coming in and\n"
116 "out of the channel being spied on. Only channels created by outgoing calls for the\n"
117 "specified extension will be selected for spying. If the optional context is not\n"
118 "supplied, the current channel's context will be used.\n"
119 " While spying, the following actions may be performed:\n"
120 " - Dialing # cycles the volume level.\n"
121 " - Dialing * will stop spying and look for another channel to spy on.\n"
122 " Note: The X option superseeds the two features above in that if a valid\n"
123 " single digit extension exists in the correct context it ChanSpy will\n"
126 " b - Only spy on channels involved in a bridged call.\n"
127 " g(grp) - Only spy on channels in which one or more of the groups \n"
128 " listed in 'grp' matches one or more groups from the\n"
129 " SPYGROUP variable set on the channel to be spied upon.\n"
130 " Note that both 'grp' and SPYGROUP can contain either a\n"
131 " single group or a colon-delimited list of groups, such\n"
132 " as 'sales:support:accounting'.\n"
133 " n([mailbox][@context]) - Say the name of the person being spied on if that person has recorded\n"
134 " his/her name. If a context is specified, then that voicemail context will\n"
135 " be searched when retrieving the name, otherwise the \"default\" context\n"
136 " will be searched. If no mailbox is specified, then the channel name will\n"
137 " be used when searching for the name (i.e. if SIP/1000 is the channel being\n"
138 " spied on and no mailbox is specified, then \"1000\" will be used when searching\n"
140 " q - Don't play a beep when beginning to spy on a channel, or speak the\n"
141 " selected channel name.\n"
142 " r[(basename)] - Record the session to the monitor spool directory. An\n"
143 " optional base for the filename may be specified. The\n"
144 " default is 'chanspy'.\n"
145 " s - Skip the playback of the channel type (i.e. SIP, IAX, etc) when\n"
146 " speaking the selected channel name.\n"
147 " v([value]) - Adjust the initial volume in the range from -4 to 4. A\n"
148 " negative value refers to a quieter setting.\n"
149 " w - Enable 'whisper' mode, so the spying channel can talk to\n"
150 " the spied-on channel.\n"
151 " W - Enable 'private whisper' mode, so the spying channel can\n"
152 " talk to the spied-on channel but cannot listen to that\n"
154 " o - Only listen to audio coming from this channel.\n"
155 " X - Allow the user to exit ChanSpy to a valid single digit\n"
156 " numeric extension in the current context or the context\n"
157 " specified by the SPY_EXIT_CONTEXT channel variable. The\n"
158 " name of the last channel that was spied on will be stored\n"
159 " in the SPY_CHANNEL variable.\n"
163 OPTION_QUIET = (1 << 0), /* Quiet, no announcement */
164 OPTION_BRIDGED = (1 << 1), /* Only look at bridged calls */
165 OPTION_VOLUME = (1 << 2), /* Specify initial volume */
166 OPTION_GROUP = (1 << 3), /* Only look at channels in group */
167 OPTION_RECORD = (1 << 4),
168 OPTION_WHISPER = (1 << 5),
169 OPTION_PRIVATE = (1 << 6), /* Private Whisper mode */
170 OPTION_READONLY = (1 << 7), /* Don't mix the two channels */
171 OPTION_EXIT = (1 << 8), /* Exit to a valid single digit extension */
172 OPTION_ENFORCED = (1 << 9), /* Enforced mode */
173 OPTION_NOTECH = (1 << 10), /* Skip technology name playback */
174 OPTION_BARGE = (1 << 11), /* Barge mode (whisper to both channels) */
175 OPTION_NAME = (1 << 12), /* Say the name of the person on whom we will spy */
187 AST_APP_OPTIONS(spy_opts, {
188 AST_APP_OPTION('q', OPTION_QUIET),
189 AST_APP_OPTION('b', OPTION_BRIDGED),
190 AST_APP_OPTION('B', OPTION_BARGE),
191 AST_APP_OPTION('w', OPTION_WHISPER),
192 AST_APP_OPTION('W', OPTION_PRIVATE),
193 AST_APP_OPTION_ARG('v', OPTION_VOLUME, OPT_ARG_VOLUME),
194 AST_APP_OPTION_ARG('g', OPTION_GROUP, OPT_ARG_GROUP),
195 AST_APP_OPTION_ARG('r', OPTION_RECORD, OPT_ARG_RECORD),
196 AST_APP_OPTION_ARG('e', OPTION_ENFORCED, OPT_ARG_ENFORCED),
197 AST_APP_OPTION('o', OPTION_READONLY),
198 AST_APP_OPTION('X', OPTION_EXIT),
199 AST_APP_OPTION('s', OPTION_NOTECH),
200 AST_APP_OPTION_ARG('n', OPTION_NAME, OPT_ARG_NAME),
204 struct chanspy_translation_helper {
206 struct ast_audiohook spy_audiohook;
207 struct ast_audiohook whisper_audiohook;
208 struct ast_audiohook bridge_whisper_audiohook;
213 static void *spy_alloc(struct ast_channel *chan, void *data)
215 /* just store the data pointer in the channel structure */
219 static void spy_release(struct ast_channel *chan, void *data)
224 static int spy_generate(struct ast_channel *chan, void *data, int len, int samples)
226 struct chanspy_translation_helper *csth = data;
227 struct ast_frame *f = NULL;
229 ast_audiohook_lock(&csth->spy_audiohook);
230 if (csth->spy_audiohook.status != AST_AUDIOHOOK_STATUS_RUNNING) {
231 /* Channel is already gone more than likely */
232 ast_audiohook_unlock(&csth->spy_audiohook);
236 f = ast_audiohook_read_frame(&csth->spy_audiohook, samples, AST_AUDIOHOOK_DIRECTION_BOTH, AST_FORMAT_SLINEAR);
238 ast_audiohook_unlock(&csth->spy_audiohook);
243 if (ast_write(chan, f)) {
249 write(csth->fd, f->data, f->datalen);
256 static struct ast_generator spygen = {
258 .release = spy_release,
259 .generate = spy_generate,
262 static int start_spying(struct ast_channel *chan, const char *spychan_name, struct ast_audiohook *audiohook)
265 struct ast_channel *peer = NULL;
267 ast_log(LOG_NOTICE, "Attaching %s to %s\n", spychan_name, chan->name);
269 res = ast_audiohook_attach(chan, audiohook);
271 if (!res && ast_test_flag(chan, AST_FLAG_NBRIDGE) && (peer = ast_bridged_channel(chan))) {
272 ast_softhangup(peer, AST_SOFTHANGUP_UNBRIDGE);
278 struct ast_channel *chan;
282 static int channel_spy(struct ast_channel *chan, struct chanspy_ds *spyee_chanspy_ds,
283 int *volfactor, int fd, const struct ast_flags *flags, char *exitcontext)
285 struct chanspy_translation_helper csth;
286 int running = 0, res, x = 0;
290 struct ast_silence_generator *silgen = NULL;
291 struct ast_channel *spyee = NULL;
292 const char *spyer_name;
294 ast_channel_lock(chan);
295 spyer_name = ast_strdupa(chan->name);
296 ast_channel_unlock(chan);
298 ast_mutex_lock(&spyee_chanspy_ds->lock);
299 if (spyee_chanspy_ds->chan) {
300 spyee = spyee_chanspy_ds->chan;
301 ast_channel_lock(spyee);
303 ast_mutex_unlock(&spyee_chanspy_ds->lock);
308 /* We now hold the channel lock on spyee */
310 if (ast_check_hangup(chan) || ast_check_hangup(spyee)) {
311 ast_channel_unlock(spyee);
315 name = ast_strdupa(spyee->name);
316 ast_verb(2, "Spying on channel %s\n", name);
318 memset(&csth, 0, sizeof(csth));
320 ast_audiohook_init(&csth.spy_audiohook, AST_AUDIOHOOK_TYPE_SPY, "ChanSpy");
322 if (start_spying(spyee, spyer_name, &csth.spy_audiohook)) {
323 ast_audiohook_destroy(&csth.spy_audiohook);
324 ast_channel_unlock(spyee);
328 if (ast_test_flag(flags, OPTION_BARGE)) {
329 ast_audiohook_init(&csth.whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "ChanSpy");
330 ast_audiohook_init(&csth.bridge_whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "Chanspy");
331 start_spying(spyee, spyer_name, &csth.whisper_audiohook); /* Unlocks spyee */
332 start_spying(ast_bridged_channel(spyee), spyer_name, &csth.bridge_whisper_audiohook);
333 } else if (ast_test_flag(flags, OPTION_WHISPER)) {
334 ast_audiohook_init(&csth.whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "ChanSpy");
335 start_spying(spyee, spyer_name, &csth.whisper_audiohook); /* Unlocks spyee */
338 ast_channel_unlock(spyee);
341 csth.volfactor = *volfactor;
343 if (csth.volfactor) {
344 csth.spy_audiohook.options.read_volume = csth.volfactor;
345 csth.spy_audiohook.options.write_volume = csth.volfactor;
350 if (ast_test_flag(flags, OPTION_PRIVATE))
351 silgen = ast_channel_start_silence_generator(chan);
353 ast_activate_generator(chan, &spygen, &csth);
355 /* We can no longer rely on 'spyee' being an actual channel;
356 it can be hung up and freed out from under us. However, the
357 channel destructor will put NULL into our csth.spy.chan
358 field when that happens, so that is our signal that the spyee
359 channel has gone away.
362 /* Note: it is very important that the ast_waitfor() be the first
363 condition in this expression, so that if we wait for some period
364 of time before receiving a frame from our spying channel, we check
365 for hangup on the spied-on channel _after_ knowing that a frame
366 has arrived, since the spied-on channel could have gone away while
369 while ((res = ast_waitfor(chan, -1) > -1) && csth.spy_audiohook.status == AST_AUDIOHOOK_STATUS_RUNNING) {
370 if (!(f = ast_read(chan)) || ast_check_hangup(chan)) {
375 if (ast_test_flag(flags, OPTION_BARGE) && f->frametype == AST_FRAME_VOICE) {
376 ast_audiohook_lock(&csth.whisper_audiohook);
377 ast_audiohook_lock(&csth.bridge_whisper_audiohook);
378 ast_audiohook_write_frame(&csth.whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f);
379 ast_audiohook_write_frame(&csth.bridge_whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f);
380 ast_audiohook_unlock(&csth.whisper_audiohook);
381 ast_audiohook_unlock(&csth.bridge_whisper_audiohook);
384 } else if (ast_test_flag(flags, OPTION_WHISPER) && f->frametype == AST_FRAME_VOICE) {
385 ast_audiohook_lock(&csth.whisper_audiohook);
386 ast_audiohook_write_frame(&csth.whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f);
387 ast_audiohook_unlock(&csth.whisper_audiohook);
392 res = (f->frametype == AST_FRAME_DTMF) ? f->subclass : 0;
397 if (x == sizeof(inp))
405 if (ast_test_flag(flags, OPTION_EXIT)) {
409 if (!ast_goto_if_exists(chan, exitcontext, tmp, 1)) {
410 ast_debug(1, "Got DTMF %c, goto context %s\n", tmp[0], exitcontext);
411 pbx_builtin_setvar_helper(chan, "SPY_CHANNEL", name);
415 ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
417 } else if (res >= '0' && res <= '9') {
424 } else if (res == '#') {
425 if (!ast_strlen_zero(inp)) {
433 ast_verb(3, "Setting spy volume on %s to %d\n", chan->name, *volfactor);
435 csth.volfactor = *volfactor;
436 csth.spy_audiohook.options.read_volume = csth.volfactor;
437 csth.spy_audiohook.options.write_volume = csth.volfactor;
441 if (ast_test_flag(flags, OPTION_PRIVATE))
442 ast_channel_stop_silence_generator(chan, silgen);
444 ast_deactivate_generator(chan);
446 if (ast_test_flag(flags, OPTION_BARGE)) {
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);
451 ast_audiohook_lock(&csth.bridge_whisper_audiohook);
452 ast_audiohook_detach(&csth.bridge_whisper_audiohook);
453 ast_audiohook_unlock(&csth.bridge_whisper_audiohook);
454 ast_audiohook_destroy(&csth.bridge_whisper_audiohook);
455 } else if (ast_test_flag(flags, OPTION_WHISPER)) {
456 ast_audiohook_lock(&csth.whisper_audiohook);
457 ast_audiohook_detach(&csth.whisper_audiohook);
458 ast_audiohook_unlock(&csth.whisper_audiohook);
459 ast_audiohook_destroy(&csth.whisper_audiohook);
462 ast_audiohook_lock(&csth.spy_audiohook);
463 ast_audiohook_detach(&csth.spy_audiohook);
464 ast_audiohook_unlock(&csth.spy_audiohook);
465 ast_audiohook_destroy(&csth.spy_audiohook);
467 ast_verb(2, "Done Spying on channel %s\n", name);
473 * \note This relies on the embedded lock to be recursive, as it may be called
474 * due to a call to chanspy_ds_free with the lock held there.
476 static void chanspy_ds_destroy(void *data)
478 struct chanspy_ds *chanspy_ds = data;
480 /* Setting chan to be NULL is an atomic operation, but we don't want this
481 * value to change while this lock is held. The lock is held elsewhere
482 * while it performs non-atomic operations with this channel pointer */
484 ast_mutex_lock(&chanspy_ds->lock);
485 chanspy_ds->chan = NULL;
486 ast_mutex_unlock(&chanspy_ds->lock);
489 static void chanspy_ds_chan_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
491 struct chanspy_ds *chanspy_ds = data;
493 ast_mutex_lock(&chanspy_ds->lock);
494 chanspy_ds->chan = new_chan;
495 ast_mutex_unlock(&chanspy_ds->lock);
498 static const struct ast_datastore_info chanspy_ds_info = {
500 .destroy = chanspy_ds_destroy,
501 .chan_fixup = chanspy_ds_chan_fixup,
504 static struct chanspy_ds *chanspy_ds_free(struct chanspy_ds *chanspy_ds)
509 ast_mutex_lock(&chanspy_ds->lock);
510 if (chanspy_ds->chan) {
511 struct ast_datastore *datastore;
512 struct ast_channel *chan;
514 chan = chanspy_ds->chan;
516 ast_channel_lock(chan);
517 if ((datastore = ast_channel_datastore_find(chan, &chanspy_ds_info, NULL))) {
518 ast_channel_datastore_remove(chan, datastore);
519 /* chanspy_ds->chan is NULL after this call */
520 chanspy_ds_destroy(datastore->data);
521 datastore->data = NULL;
522 ast_channel_datastore_free(datastore);
524 ast_channel_unlock(chan);
526 ast_mutex_unlock(&chanspy_ds->lock);
531 /*! \note Returns the channel in the chanspy_ds locked as well as the chanspy_ds locked */
532 static struct chanspy_ds *setup_chanspy_ds(struct ast_channel *chan, struct chanspy_ds *chanspy_ds)
534 struct ast_datastore *datastore = NULL;
536 ast_mutex_lock(&chanspy_ds->lock);
538 if (!(datastore = ast_channel_datastore_alloc(&chanspy_ds_info, NULL))) {
539 ast_mutex_unlock(&chanspy_ds->lock);
540 chanspy_ds = chanspy_ds_free(chanspy_ds);
541 ast_channel_unlock(chan);
545 chanspy_ds->chan = chan;
546 datastore->data = chanspy_ds;
547 ast_channel_datastore_add(chan, datastore);
552 static struct chanspy_ds *next_channel(struct ast_channel *chan,
553 const struct ast_channel *last, const char *spec,
554 const char *exten, const char *context, struct chanspy_ds *chanspy_ds)
556 struct ast_channel *next;
559 if (!ast_strlen_zero(spec))
560 next = ast_walk_channel_by_name_prefix_locked(last, spec, strlen(spec));
561 else if (!ast_strlen_zero(exten))
562 next = ast_walk_channel_by_exten_locked(last, exten, context);
564 next = ast_channel_walk_locked(last);
569 if (!strncmp(next->name, "Zap/pseudo", 10)) {
570 ast_channel_unlock(next);
572 } else if (next == chan) {
574 ast_channel_unlock(next);
578 return setup_chanspy_ds(next, chanspy_ds);
581 static int common_exec(struct ast_channel *chan, const struct ast_flags *flags,
582 int volfactor, const int fd, const char *mygroup, const char *myenforced,
583 const char *spec, const char *exten, const char *context, const char *mailbox,
584 const char *name_context)
586 char nameprefix[AST_NAME_STRLEN];
587 char peer_name[AST_NAME_STRLEN + 5];
588 char exitcontext[AST_MAX_CONTEXT] = "";
589 signed char zero_volume = 0;
594 int num_spyed_upon = 1;
595 struct chanspy_ds chanspy_ds;
597 if (ast_test_flag(flags, OPTION_EXIT)) {
599 if ((c = pbx_builtin_getvar_helper(chan, "SPY_EXIT_CONTEXT")))
600 ast_copy_string(exitcontext, c, sizeof(exitcontext));
601 else if (!ast_strlen_zero(chan->macrocontext))
602 ast_copy_string(exitcontext, chan->macrocontext, sizeof(exitcontext));
604 ast_copy_string(exitcontext, chan->context, sizeof(exitcontext));
607 ast_mutex_init(&chanspy_ds.lock);
609 if (chan->_state != AST_STATE_UP)
612 ast_set_flag(chan, AST_FLAG_SPYING); /* so nobody can spy on us while we are spying */
617 struct chanspy_ds *peer_chanspy_ds = NULL, *next_chanspy_ds = NULL;
618 struct ast_channel *prev = NULL, *peer = NULL;
620 if (!ast_test_flag(flags, OPTION_QUIET) && num_spyed_upon) {
621 res = ast_streamfile(chan, "beep", chan->language);
623 res = ast_waitstream(chan, "");
625 ast_clear_flag(chan, AST_FLAG_SPYING);
628 if (!ast_strlen_zero(exitcontext)) {
632 if (!ast_goto_if_exists(chan, exitcontext, tmp, 1))
635 ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
639 res = ast_waitfordigit(chan, waitms);
641 ast_clear_flag(chan, AST_FLAG_SPYING);
644 if (!ast_strlen_zero(exitcontext)) {
648 if (!ast_goto_if_exists(chan, exitcontext, tmp, 1))
651 ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
654 /* reset for the next loop around, unless overridden later */
658 for (peer_chanspy_ds = next_channel(chan, prev, spec, exten, context, &chanspy_ds);
660 chanspy_ds_free(peer_chanspy_ds), prev = peer,
661 peer_chanspy_ds = next_chanspy_ds ? next_chanspy_ds :
662 next_channel(chan, prev, spec, exten, context, &chanspy_ds), next_chanspy_ds = NULL) {
665 char *groups[NUM_SPYGROUPS];
666 char *mygroups[NUM_SPYGROUPS];
669 int num_mygroups = 0;
678 int ienf = !myenforced;
680 peer = peer_chanspy_ds->chan;
682 ast_mutex_unlock(&peer_chanspy_ds->lock);
685 ast_channel_unlock(peer);
686 chanspy_ds_free(peer_chanspy_ds);
690 if (ast_check_hangup(chan)) {
691 ast_channel_unlock(peer);
692 chanspy_ds_free(peer_chanspy_ds);
696 if (ast_test_flag(flags, OPTION_BRIDGED) && !ast_bridged_channel(peer)) {
697 ast_channel_unlock(peer);
701 if (ast_check_hangup(peer) || ast_test_flag(peer, AST_FLAG_SPYING)) {
702 ast_channel_unlock(peer);
707 dup_mygroup = ast_strdupa(mygroup);
708 num_mygroups = ast_app_separate_args(dup_mygroup, ':', mygroups,
709 sizeof(mygroups) / sizeof(mygroups[0]));
711 if ((group = pbx_builtin_getvar_helper(peer, "SPYGROUP"))) {
712 dup_group = ast_strdupa(group);
713 num_groups = ast_app_separate_args(dup_group, ':', groups,
714 sizeof(groups) / sizeof(groups[0]));
717 for (y = 0; y < num_mygroups; y++) {
718 for (x = 0; x < num_groups; x++) {
719 if (!strcmp(mygroups[y], groups[x])) {
728 ast_channel_unlock(peer);
734 /* We don't need to allocate more space than just the
735 length of (peer->name) for ext as we will cut the
736 channel name's ending before copying into ext */
738 ext = alloca(strlen(peer->name));
740 form_enforced = alloca(strlen(myenforced) + 3);
742 strcpy(form_enforced, ":");
743 strcat(form_enforced, myenforced);
744 strcat(form_enforced, ":");
746 buffer = ast_strdupa(peer->name);
748 if ((end = strchr(buffer, '-'))) {
756 if (strcasestr(form_enforced, ext))
763 strcpy(peer_name, "spy-");
764 strncat(peer_name, peer->name, AST_NAME_STRLEN - 4 - 1);
765 ptr = strchr(peer_name, '/');
767 ptr = strsep(&ptr, "-");
769 for (s = peer_name; s < ptr; s++)
771 /* We have to unlock the peer channel here to avoid a deadlock.
772 * So, when we need to dereference it again, we have to lock the
773 * datastore and get the pointer from there to see if the channel
775 ast_channel_unlock(peer);
777 if (!ast_test_flag(flags, OPTION_QUIET)) {
778 if (ast_test_flag(flags, OPTION_NAME)) {
779 const char *local_context = S_OR(name_context, "default");
780 const char *local_mailbox = S_OR(mailbox, ptr);
781 res = ast_app_sayname(chan, local_mailbox, local_context);
783 if (!ast_test_flag(flags, OPTION_NAME) || res < 0) {
784 if (!ast_test_flag(flags, OPTION_NOTECH)) {
785 if (ast_fileexists(peer_name, NULL, NULL) != -1) {
786 res = ast_streamfile(chan, peer_name, chan->language);
788 res = ast_waitstream(chan, "");
791 chanspy_ds_free(peer_chanspy_ds);
795 res = ast_say_character_str(chan, peer_name, "", chan->language);
798 if ((num = atoi(ptr)))
799 ast_say_digits(chan, atoi(ptr), "", chan->language);
803 res = channel_spy(chan, peer_chanspy_ds, &volfactor, fd, flags, exitcontext);
807 chanspy_ds_free(peer_chanspy_ds);
809 } else if (res == -2) {
811 chanspy_ds_free(peer_chanspy_ds);
813 } else if (res > 1 && spec) {
814 struct ast_channel *next;
816 snprintf(nameprefix, AST_NAME_STRLEN, "%s/%d", spec, res);
818 if ((next = ast_get_channel_by_name_prefix_locked(nameprefix, strlen(nameprefix)))) {
819 peer_chanspy_ds = chanspy_ds_free(peer_chanspy_ds);
820 next_chanspy_ds = setup_chanspy_ds(next, &chanspy_ds);
822 /* stay on this channel, if it is still valid */
824 ast_mutex_lock(&peer_chanspy_ds->lock);
825 if (peer_chanspy_ds->chan) {
826 ast_channel_lock(peer_chanspy_ds->chan);
827 next_chanspy_ds = peer_chanspy_ds;
828 peer_chanspy_ds = NULL;
830 /* the channel is gone */
831 ast_mutex_unlock(&peer_chanspy_ds->lock);
832 next_chanspy_ds = NULL;
839 if (res == -1 || ast_check_hangup(chan))
844 ast_clear_flag(chan, AST_FLAG_SPYING);
846 ast_channel_setoption(chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);
848 ast_mutex_destroy(&chanspy_ds.lock);
853 static int chanspy_exec(struct ast_channel *chan, void *data)
855 char *myenforced = NULL;
856 char *mygroup = NULL;
857 char *recbase = NULL;
859 struct ast_flags flags;
863 char *mailbox = NULL;
864 char *name_context = NULL;
865 AST_DECLARE_APP_ARGS(args,
867 AST_APP_ARG(options);
869 char *opts[OPT_ARG_ARRAY_SIZE];
871 data = ast_strdupa(data);
872 AST_STANDARD_APP_ARGS(args, data);
874 if (args.spec && !strcmp(args.spec, "all"))
878 ast_app_parse_options(spy_opts, &flags, opts, args.options);
879 if (ast_test_flag(&flags, OPTION_GROUP))
880 mygroup = opts[OPT_ARG_GROUP];
882 if (ast_test_flag(&flags, OPTION_RECORD) &&
883 !(recbase = opts[OPT_ARG_RECORD]))
886 if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) {
889 if ((sscanf(opts[OPT_ARG_VOLUME], "%d", &vol) != 1) || (vol > 4) || (vol < -4))
890 ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n");
895 if (ast_test_flag(&flags, OPTION_PRIVATE))
896 ast_set_flag(&flags, OPTION_WHISPER);
898 if (ast_test_flag(&flags, OPTION_ENFORCED))
899 myenforced = opts[OPT_ARG_ENFORCED];
901 if (ast_test_flag(&flags, OPTION_NAME)) {
902 if (!ast_strlen_zero(opts[OPT_ARG_NAME])) {
904 if ((delimiter = strchr(opts[OPT_ARG_NAME], '@'))) {
905 mailbox = opts[OPT_ARG_NAME];
907 name_context = delimiter;
909 mailbox = opts[OPT_ARG_NAME];
916 ast_clear_flag(&flags, AST_FLAGS_ALL);
918 oldwf = chan->writeformat;
919 if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
920 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
925 char filename[PATH_MAX];
927 snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL));
928 if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, AST_FILE_MODE)) <= 0) {
929 ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename);
934 res = common_exec(chan, &flags, volfactor, fd, mygroup, myenforced, args.spec, NULL, NULL, mailbox, name_context);
939 if (oldwf && ast_set_write_format(chan, oldwf) < 0)
940 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
945 static int extenspy_exec(struct ast_channel *chan, void *data)
947 char *ptr, *exten = NULL;
948 char *mygroup = NULL;
949 char *recbase = NULL;
951 struct ast_flags flags;
955 char *mailbox = NULL;
956 char *name_context = NULL;
957 AST_DECLARE_APP_ARGS(args,
958 AST_APP_ARG(context);
959 AST_APP_ARG(options);
962 data = ast_strdupa(data);
964 AST_STANDARD_APP_ARGS(args, data);
965 if (!ast_strlen_zero(args.context) && (ptr = strchr(args.context, '@'))) {
966 exten = args.context;
971 if (ast_strlen_zero(args.context))
972 args.context = ast_strdupa(chan->context);
975 char *opts[OPT_ARG_ARRAY_SIZE];
977 ast_app_parse_options(spy_opts, &flags, opts, args.options);
978 if (ast_test_flag(&flags, OPTION_GROUP))
979 mygroup = opts[OPT_ARG_GROUP];
981 if (ast_test_flag(&flags, OPTION_RECORD) &&
982 !(recbase = opts[OPT_ARG_RECORD]))
985 if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) {
988 if ((sscanf(opts[OPT_ARG_VOLUME], "%d", &vol) != 1) || (vol > 4) || (vol < -4))
989 ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n");
994 if (ast_test_flag(&flags, OPTION_PRIVATE))
995 ast_set_flag(&flags, OPTION_WHISPER);
998 if (ast_test_flag(&flags, OPTION_NAME)) {
999 if (!ast_strlen_zero(opts[OPT_ARG_NAME])) {
1001 if ((delimiter = strchr(opts[OPT_ARG_NAME], '@'))) {
1002 mailbox = opts[OPT_ARG_NAME];
1003 *delimiter++ = '\0';
1004 name_context = delimiter;
1006 mailbox = opts[OPT_ARG_NAME];
1012 ast_clear_flag(&flags, AST_FLAGS_ALL);
1014 oldwf = chan->writeformat;
1015 if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
1016 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
1021 char filename[PATH_MAX];
1023 snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL));
1024 if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, AST_FILE_MODE)) <= 0) {
1025 ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename);
1031 res = common_exec(chan, &flags, volfactor, fd, mygroup, NULL, NULL, exten, args.context, mailbox, name_context);
1036 if (oldwf && ast_set_write_format(chan, oldwf) < 0)
1037 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
1042 static int unload_module(void)
1046 res |= ast_unregister_application(app_chan);
1047 res |= ast_unregister_application(app_ext);
1052 static int load_module(void)
1056 res |= ast_register_application(app_chan, chanspy_exec, tdesc, desc_chan);
1057 res |= ast_register_application(app_ext, extenspy_exec, tdesc, desc_ext);
1062 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Listen to the audio of an active channel");