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"
50 #include "asterisk/options.h"
52 #define AST_NAME_STRLEN 256
53 #define NUM_SPYGROUPS 128
55 static const char *tdesc
= "Listen to a channel, and optionally whisper into it";
56 static const char *app_chan
= "ChanSpy";
57 static const char *desc_chan
=
58 " ChanSpy([chanprefix][,options]): This application is used to listen to the\n"
59 "audio from an Asterisk channel. This includes the audio coming in and\n"
60 "out of the channel being spied on. If the 'chanprefix' parameter is specified,\n"
61 "only channels beginning with this string will be spied upon.\n"
62 " While spying, the following actions may be performed:\n"
63 " - Dialing # cycles the volume level.\n"
64 " - Dialing * will stop spying and look for another channel to spy on.\n"
65 " - Dialing a series of digits followed by # builds a channel name to append\n"
66 " to 'chanprefix'. For example, executing ChanSpy(Agent) and then dialing\n"
67 " the digits '1234#' while spying will begin spying on the channel\n"
68 " 'Agent/1234'. Note that this feature will be overriden if the 'd' option\n"
70 " Note: The X option supersedes the three features above in that if a valid\n"
71 " single digit extension exists in the correct context ChanSpy will\n"
72 " exit to it. This also disables choosing a channel based on 'chanprefix'\n"
73 " and a digit sequence.\n"
75 " b - Only spy on channels involved in a bridged call.\n"
76 " B - Instead of whispering on a single channel barge in on both\n"
77 " channels involved in the call.\n"
78 " d - Override the typical numeric DTMF functionality and instead\n"
79 " use DTMF to switch between spy modes.\n"
83 " g(grp) - Only spy on channels in which one or more of the groups \n"
84 " listed in 'grp' matches one or more groups from the\n"
85 " SPYGROUP variable set on the channel to be spied upon.\n"
86 " Note that both 'grp' and SPYGROUP can contain either a\n"
87 " single group or a colon-delimited list of groups, such\n"
88 " as 'sales:support:accounting'.\n"
89 " n([mailbox][@context]) - Say the name of the person being spied on if that person has recorded\n"
90 " his/her name. If a context is specified, then that voicemail context will\n"
91 " be searched when retrieving the name, otherwise the \"default\" context\n"
92 " will be searched. If no mailbox is specified, then the channel name will\n"
93 " be used when searching for the name (i.e. if SIP/1000 is the channel being\n"
94 " spied on and no mailbox is specified, then \"1000\" will be used when searching\n"
96 " q - Don't play a beep when beginning to spy on a channel, or speak the\n"
97 " selected channel name.\n"
98 " r[(basename)] - Record the session to the monitor spool directory. An\n"
99 " optional base for the filename may be specified. The\n"
100 " default is 'chanspy'.\n"
101 " s - Skip the playback of the channel type (i.e. SIP, IAX, etc) when\n"
102 " speaking the selected channel name.\n"
103 " v([value]) - Adjust the initial volume in the range from -4 to 4. A\n"
104 " negative value refers to a quieter setting.\n"
105 " w - Enable 'whisper' mode, so the spying channel can talk to\n"
106 " the spied-on channel.\n"
107 " W - Enable 'private whisper' mode, so the spying channel can\n"
108 " talk to the spied-on channel but cannot listen to that\n"
110 " o - Only listen to audio coming from this channel.\n"
111 " X - Allow the user to exit ChanSpy to a valid single digit\n"
112 " numeric extension in the current context or the context\n"
113 " specified by the SPY_EXIT_CONTEXT channel variable. The\n"
114 " name of the last channel that was spied on will be stored\n"
115 " in the SPY_CHANNEL variable.\n"
116 " e(ext) - Enable 'enforced' mode, so the spying channel can\n"
117 " only monitor extensions whose name is in the 'ext' : \n"
121 static const char *app_ext
= "ExtenSpy";
122 static const char *desc_ext
=
123 " ExtenSpy(exten[@context][,options]): This application is used to listen to the\n"
124 "audio from an Asterisk channel. This includes the audio coming in and\n"
125 "out of the channel being spied on. Only channels created by outgoing calls for the\n"
126 "specified extension will be selected for spying. If the optional context is not\n"
127 "supplied, the current channel's context will be used.\n"
128 " While spying, the following actions may be performed:\n"
129 " - Dialing # cycles the volume level.\n"
130 " - Dialing * will stop spying and look for another channel to spy on.\n"
131 " Note: The X option superseeds the two features above in that if a valid\n"
132 " single digit extension exists in the correct context it ChanSpy will\n"
135 " b - Only spy on channels involved in a bridged call.\n"
136 " B - Instead of whispering on a single channel barge in on both\n"
137 " channels involved in the call.\n"
138 " d - Override the typical numeric DTMF functionality and instead\n"
139 " use DTMF to switch between spy modes.\n"
141 " 5 = whisper mode\n"
143 " g(grp) - Only spy on channels in which one or more of the groups \n"
144 " listed in 'grp' matches one or more groups from the\n"
145 " SPYGROUP variable set on the channel to be spied upon.\n"
146 " Note that both 'grp' and SPYGROUP can contain either a\n"
147 " single group or a colon-delimited list of groups, such\n"
148 " as 'sales:support:accounting'.\n"
149 " n([mailbox][@context]) - Say the name of the person being spied on if that person has recorded\n"
150 " his/her name. If a context is specified, then that voicemail context will\n"
151 " be searched when retrieving the name, otherwise the \"default\" context\n"
152 " will be searched. If no mailbox is specified, then the channel name will\n"
153 " be used when searching for the name (i.e. if SIP/1000 is the channel being\n"
154 " spied on and no mailbox is specified, then \"1000\" will be used when searching\n"
156 " q - Don't play a beep when beginning to spy on a channel, or speak the\n"
157 " selected channel name.\n"
158 " r[(basename)] - Record the session to the monitor spool directory. An\n"
159 " optional base for the filename may be specified. The\n"
160 " default is 'chanspy'.\n"
161 " s - Skip the playback of the channel type (i.e. SIP, IAX, etc) when\n"
162 " speaking the selected channel name.\n"
163 " v([value]) - Adjust the initial volume in the range from -4 to 4. A\n"
164 " negative value refers to a quieter setting.\n"
165 " w - Enable 'whisper' mode, so the spying channel can talk to\n"
166 " the spied-on channel.\n"
167 " W - Enable 'private whisper' mode, so the spying channel can\n"
168 " talk to the spied-on channel but cannot listen to that\n"
170 " o - Only listen to audio coming from this channel.\n"
171 " X - Allow the user to exit ChanSpy to a valid single digit\n"
172 " numeric extension in the current context or the context\n"
173 " specified by the SPY_EXIT_CONTEXT channel variable. The\n"
174 " name of the last channel that was spied on will be stored\n"
175 " in the SPY_CHANNEL variable.\n"
179 OPTION_QUIET
= (1 << 0), /* Quiet, no announcement */
180 OPTION_BRIDGED
= (1 << 1), /* Only look at bridged calls */
181 OPTION_VOLUME
= (1 << 2), /* Specify initial volume */
182 OPTION_GROUP
= (1 << 3), /* Only look at channels in group */
183 OPTION_RECORD
= (1 << 4),
184 OPTION_WHISPER
= (1 << 5),
185 OPTION_PRIVATE
= (1 << 6), /* Private Whisper mode */
186 OPTION_READONLY
= (1 << 7), /* Don't mix the two channels */
187 OPTION_EXIT
= (1 << 8), /* Exit to a valid single digit extension */
188 OPTION_ENFORCED
= (1 << 9), /* Enforced mode */
189 OPTION_NOTECH
= (1 << 10), /* Skip technology name playback */
190 OPTION_BARGE
= (1 << 11), /* Barge mode (whisper to both channels) */
191 OPTION_NAME
= (1 << 12), /* Say the name of the person on whom we will spy */
192 OPTION_DTMF_SWITCH_MODES
= (1 << 13), /*Allow numeric DTMF to switch between chanspy modes */
204 AST_APP_OPTIONS(spy_opts
, {
205 AST_APP_OPTION('q', OPTION_QUIET
),
206 AST_APP_OPTION('b', OPTION_BRIDGED
),
207 AST_APP_OPTION('B', OPTION_BARGE
),
208 AST_APP_OPTION('w', OPTION_WHISPER
),
209 AST_APP_OPTION('W', OPTION_PRIVATE
),
210 AST_APP_OPTION_ARG('v', OPTION_VOLUME
, OPT_ARG_VOLUME
),
211 AST_APP_OPTION_ARG('g', OPTION_GROUP
, OPT_ARG_GROUP
),
212 AST_APP_OPTION_ARG('r', OPTION_RECORD
, OPT_ARG_RECORD
),
213 AST_APP_OPTION_ARG('e', OPTION_ENFORCED
, OPT_ARG_ENFORCED
),
214 AST_APP_OPTION('o', OPTION_READONLY
),
215 AST_APP_OPTION('X', OPTION_EXIT
),
216 AST_APP_OPTION('s', OPTION_NOTECH
),
217 AST_APP_OPTION_ARG('n', OPTION_NAME
, OPT_ARG_NAME
),
218 AST_APP_OPTION('d', OPTION_DTMF_SWITCH_MODES
),
221 int next_unique_id_to_use
= 0;
223 struct chanspy_translation_helper
{
225 struct ast_audiohook spy_audiohook
;
226 struct ast_audiohook whisper_audiohook
;
227 struct ast_audiohook bridge_whisper_audiohook
;
232 static void *spy_alloc(struct ast_channel
*chan
, void *data
)
234 /* just store the data pointer in the channel structure */
238 static void spy_release(struct ast_channel
*chan
, void *data
)
243 static int spy_generate(struct ast_channel
*chan
, void *data
, int len
, int samples
)
245 struct chanspy_translation_helper
*csth
= data
;
246 struct ast_frame
*f
= NULL
;
248 ast_audiohook_lock(&csth
->spy_audiohook
);
249 if (csth
->spy_audiohook
.status
!= AST_AUDIOHOOK_STATUS_RUNNING
) {
250 /* Channel is already gone more than likely */
251 ast_audiohook_unlock(&csth
->spy_audiohook
);
255 f
= ast_audiohook_read_frame(&csth
->spy_audiohook
, samples
, AST_AUDIOHOOK_DIRECTION_BOTH
, AST_FORMAT_SLINEAR
);
257 ast_audiohook_unlock(&csth
->spy_audiohook
);
262 if (ast_write(chan
, f
)) {
268 write(csth
->fd
, f
->data
.ptr
, f
->datalen
);
275 static struct ast_generator spygen
= {
277 .release
= spy_release
,
278 .generate
= spy_generate
,
281 static int start_spying(struct ast_channel
*chan
, const char *spychan_name
, struct ast_audiohook
*audiohook
)
284 struct ast_channel
*peer
= NULL
;
286 ast_log(LOG_NOTICE
, "Attaching %s to %s\n", spychan_name
, chan
->name
);
288 res
= ast_audiohook_attach(chan
, audiohook
);
290 if (!res
&& ast_test_flag(chan
, AST_FLAG_NBRIDGE
) && (peer
= ast_bridged_channel(chan
))) {
291 ast_softhangup(peer
, AST_SOFTHANGUP_UNBRIDGE
);
297 struct ast_channel
*chan
;
302 static void change_spy_mode(const char digit
, struct ast_flags
*flags
)
305 ast_clear_flag(flags
, OPTION_WHISPER
);
306 ast_clear_flag(flags
, OPTION_BARGE
);
307 } else if (digit
== '5') {
308 ast_clear_flag(flags
, OPTION_BARGE
);
309 ast_set_flag(flags
, OPTION_WHISPER
);
310 } else if (digit
== '6') {
311 ast_clear_flag(flags
, OPTION_WHISPER
);
312 ast_set_flag(flags
, OPTION_BARGE
);
316 static int channel_spy(struct ast_channel
*chan
, struct chanspy_ds
*spyee_chanspy_ds
,
317 int *volfactor
, int fd
, struct ast_flags
*flags
, char *exitcontext
)
319 struct chanspy_translation_helper csth
;
320 int running
= 0, res
, x
= 0;
324 struct ast_silence_generator
*silgen
= NULL
;
325 struct ast_channel
*spyee
= NULL
;
326 const char *spyer_name
;
328 ast_channel_lock(chan
);
329 spyer_name
= ast_strdupa(chan
->name
);
330 ast_channel_unlock(chan
);
332 ast_mutex_lock(&spyee_chanspy_ds
->lock
);
333 if (spyee_chanspy_ds
->chan
) {
334 spyee
= spyee_chanspy_ds
->chan
;
335 ast_channel_lock(spyee
);
337 ast_mutex_unlock(&spyee_chanspy_ds
->lock
);
342 /* We now hold the channel lock on spyee */
344 if (ast_check_hangup(chan
) || ast_check_hangup(spyee
)) {
345 ast_channel_unlock(spyee
);
349 name
= ast_strdupa(spyee
->name
);
350 ast_verb(2, "Spying on channel %s\n", name
);
352 memset(&csth
, 0, sizeof(csth
));
354 ast_audiohook_init(&csth
.spy_audiohook
, AST_AUDIOHOOK_TYPE_SPY
, "ChanSpy");
356 if (start_spying(spyee
, spyer_name
, &csth
.spy_audiohook
)) {
357 ast_audiohook_destroy(&csth
.spy_audiohook
);
358 ast_channel_unlock(spyee
);
362 ast_channel_lock(chan
);
363 ast_set_flag(chan
, AST_FLAG_END_DTMF_ONLY
);
364 ast_channel_unlock(chan
);
366 ast_audiohook_init(&csth
.whisper_audiohook
, AST_AUDIOHOOK_TYPE_WHISPER
, "ChanSpy");
367 ast_audiohook_init(&csth
.bridge_whisper_audiohook
, AST_AUDIOHOOK_TYPE_WHISPER
, "Chanspy");
368 start_spying(spyee
, spyer_name
, &csth
.whisper_audiohook
); /* Unlocks spyee */
369 start_spying(ast_bridged_channel(spyee
), spyer_name
, &csth
.bridge_whisper_audiohook
);
371 ast_channel_unlock(spyee
);
374 csth
.volfactor
= *volfactor
;
376 if (csth
.volfactor
) {
377 csth
.spy_audiohook
.options
.read_volume
= csth
.volfactor
;
378 csth
.spy_audiohook
.options
.write_volume
= csth
.volfactor
;
383 if (ast_test_flag(flags
, OPTION_PRIVATE
))
384 silgen
= ast_channel_start_silence_generator(chan
);
386 ast_activate_generator(chan
, &spygen
, &csth
);
388 /* We can no longer rely on 'spyee' being an actual channel;
389 it can be hung up and freed out from under us. However, the
390 channel destructor will put NULL into our csth.spy.chan
391 field when that happens, so that is our signal that the spyee
392 channel has gone away.
395 /* Note: it is very important that the ast_waitfor() be the first
396 condition in this expression, so that if we wait for some period
397 of time before receiving a frame from our spying channel, we check
398 for hangup on the spied-on channel _after_ knowing that a frame
399 has arrived, since the spied-on channel could have gone away while
402 while ((res
= ast_waitfor(chan
, -1) > -1) && csth
.spy_audiohook
.status
== AST_AUDIOHOOK_STATUS_RUNNING
) {
403 if (!(f
= ast_read(chan
)) || ast_check_hangup(chan
)) {
408 if (ast_test_flag(flags
, OPTION_BARGE
) && f
->frametype
== AST_FRAME_VOICE
) {
409 ast_audiohook_lock(&csth
.whisper_audiohook
);
410 ast_audiohook_lock(&csth
.bridge_whisper_audiohook
);
411 ast_audiohook_write_frame(&csth
.whisper_audiohook
, AST_AUDIOHOOK_DIRECTION_WRITE
, f
);
412 ast_audiohook_write_frame(&csth
.bridge_whisper_audiohook
, AST_AUDIOHOOK_DIRECTION_WRITE
, f
);
413 ast_audiohook_unlock(&csth
.whisper_audiohook
);
414 ast_audiohook_unlock(&csth
.bridge_whisper_audiohook
);
417 } else if (ast_test_flag(flags
, OPTION_WHISPER
) && f
->frametype
== AST_FRAME_VOICE
) {
418 ast_audiohook_lock(&csth
.whisper_audiohook
);
419 ast_audiohook_write_frame(&csth
.whisper_audiohook
, AST_AUDIOHOOK_DIRECTION_WRITE
, f
);
420 ast_audiohook_unlock(&csth
.whisper_audiohook
);
425 res
= (f
->frametype
== AST_FRAME_DTMF
) ? f
->subclass
: 0;
430 if (x
== sizeof(inp
))
438 if (ast_test_flag(flags
, OPTION_EXIT
)) {
442 if (!ast_goto_if_exists(chan
, exitcontext
, tmp
, 1)) {
443 ast_debug(1, "Got DTMF %c, goto context %s\n", tmp
[0], exitcontext
);
444 pbx_builtin_setvar_helper(chan
, "SPY_CHANNEL", name
);
448 ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp
, exitcontext
);
450 } else if (res
>= '0' && res
<= '9') {
451 if (ast_test_flag(flags
, OPTION_DTMF_SWITCH_MODES
)) {
452 change_spy_mode(res
, flags
);
461 } else if (res
== '#') {
462 if (!ast_strlen_zero(inp
)) {
470 ast_verb(3, "Setting spy volume on %s to %d\n", chan
->name
, *volfactor
);
472 csth
.volfactor
= *volfactor
;
473 csth
.spy_audiohook
.options
.read_volume
= csth
.volfactor
;
474 csth
.spy_audiohook
.options
.write_volume
= csth
.volfactor
;
478 if (ast_test_flag(flags
, OPTION_PRIVATE
))
479 ast_channel_stop_silence_generator(chan
, silgen
);
481 ast_deactivate_generator(chan
);
483 ast_channel_lock(chan
);
484 ast_clear_flag(chan
, AST_FLAG_END_DTMF_ONLY
);
485 ast_channel_unlock(chan
);
487 ast_audiohook_lock(&csth
.whisper_audiohook
);
488 ast_audiohook_detach(&csth
.whisper_audiohook
);
489 ast_audiohook_unlock(&csth
.whisper_audiohook
);
490 ast_audiohook_destroy(&csth
.whisper_audiohook
);
491 ast_audiohook_lock(&csth
.bridge_whisper_audiohook
);
492 ast_audiohook_detach(&csth
.bridge_whisper_audiohook
);
493 ast_audiohook_unlock(&csth
.bridge_whisper_audiohook
);
494 ast_audiohook_destroy(&csth
.bridge_whisper_audiohook
);
496 ast_audiohook_lock(&csth
.spy_audiohook
);
497 ast_audiohook_detach(&csth
.spy_audiohook
);
498 ast_audiohook_unlock(&csth
.spy_audiohook
);
499 ast_audiohook_destroy(&csth
.spy_audiohook
);
501 ast_verb(2, "Done Spying on channel %s\n", name
);
507 * \note This relies on the embedded lock to be recursive, as it may be called
508 * due to a call to chanspy_ds_free with the lock held there.
510 static void chanspy_ds_destroy(void *data
)
512 struct chanspy_ds
*chanspy_ds
= data
;
514 /* Setting chan to be NULL is an atomic operation, but we don't want this
515 * value to change while this lock is held. The lock is held elsewhere
516 * while it performs non-atomic operations with this channel pointer */
518 ast_mutex_lock(&chanspy_ds
->lock
);
519 chanspy_ds
->chan
= NULL
;
520 ast_mutex_unlock(&chanspy_ds
->lock
);
523 static void chanspy_ds_chan_fixup(void *data
, struct ast_channel
*old_chan
, struct ast_channel
*new_chan
)
525 struct chanspy_ds
*chanspy_ds
= data
;
527 ast_mutex_lock(&chanspy_ds
->lock
);
528 chanspy_ds
->chan
= new_chan
;
529 ast_mutex_unlock(&chanspy_ds
->lock
);
532 static const struct ast_datastore_info chanspy_ds_info
= {
534 .destroy
= chanspy_ds_destroy
,
535 .chan_fixup
= chanspy_ds_chan_fixup
,
538 static struct chanspy_ds
*chanspy_ds_free(struct chanspy_ds
*chanspy_ds
)
543 ast_mutex_lock(&chanspy_ds
->lock
);
544 if (chanspy_ds
->chan
) {
545 struct ast_datastore
*datastore
;
546 struct ast_channel
*chan
;
548 chan
= chanspy_ds
->chan
;
550 ast_channel_lock(chan
);
551 if ((datastore
= ast_channel_datastore_find(chan
, &chanspy_ds_info
, chanspy_ds
->unique_id
))) {
552 ast_channel_datastore_remove(chan
, datastore
);
553 /* chanspy_ds->chan is NULL after this call */
554 chanspy_ds_destroy(datastore
->data
);
555 datastore
->data
= NULL
;
556 ast_channel_datastore_free(datastore
);
558 ast_channel_unlock(chan
);
560 ast_mutex_unlock(&chanspy_ds
->lock
);
565 /*! \note Returns the channel in the chanspy_ds locked as well as the chanspy_ds locked */
566 static struct chanspy_ds
*setup_chanspy_ds(struct ast_channel
*chan
, struct chanspy_ds
*chanspy_ds
)
568 struct ast_datastore
*datastore
= NULL
;
570 ast_mutex_lock(&chanspy_ds
->lock
);
572 if (!(datastore
= ast_channel_datastore_alloc(&chanspy_ds_info
, chanspy_ds
->unique_id
))) {
573 ast_mutex_unlock(&chanspy_ds
->lock
);
574 chanspy_ds
= chanspy_ds_free(chanspy_ds
);
575 ast_channel_unlock(chan
);
579 chanspy_ds
->chan
= chan
;
580 datastore
->data
= chanspy_ds
;
581 ast_channel_datastore_add(chan
, datastore
);
586 static struct chanspy_ds
*next_channel(struct ast_channel
*chan
,
587 const struct ast_channel
*last
, const char *spec
,
588 const char *exten
, const char *context
, struct chanspy_ds
*chanspy_ds
)
590 struct ast_channel
*next
;
591 char channel_name
[AST_CHANNEL_NAME
];
594 if (!ast_strlen_zero(spec
))
595 next
= ast_walk_channel_by_name_prefix_locked(last
, spec
, strlen(spec
));
596 else if (!ast_strlen_zero(exten
))
597 next
= ast_walk_channel_by_exten_locked(last
, exten
, context
);
599 next
= ast_channel_walk_locked(last
);
604 snprintf(channel_name
, AST_CHANNEL_NAME
, "%s/pseudo", dahdi_chan_name
);
605 if (!strncmp(next
->name
, channel_name
, 10)) {
606 ast_channel_unlock(next
);
608 } else if (next
== chan
) {
610 ast_channel_unlock(next
);
614 return setup_chanspy_ds(next
, chanspy_ds
);
617 static int common_exec(struct ast_channel
*chan
, struct ast_flags
*flags
,
618 int volfactor
, const int fd
, const char *mygroup
, const char *myenforced
,
619 const char *spec
, const char *exten
, const char *context
, const char *mailbox
,
620 const char *name_context
)
622 char nameprefix
[AST_NAME_STRLEN
];
623 char peer_name
[AST_NAME_STRLEN
+ 5];
624 char exitcontext
[AST_MAX_CONTEXT
] = "";
625 signed char zero_volume
= 0;
630 int num_spyed_upon
= 1;
631 struct chanspy_ds chanspy_ds
;
633 if (ast_test_flag(flags
, OPTION_EXIT
)) {
635 ast_channel_lock(chan
);
636 if ((c
= pbx_builtin_getvar_helper(chan
, "SPY_EXIT_CONTEXT"))) {
637 ast_copy_string(exitcontext
, c
, sizeof(exitcontext
));
638 } else if (!ast_strlen_zero(chan
->macrocontext
)) {
639 ast_copy_string(exitcontext
, chan
->macrocontext
, sizeof(exitcontext
));
641 ast_copy_string(exitcontext
, chan
->context
, sizeof(exitcontext
));
643 ast_channel_unlock(chan
);
646 ast_mutex_init(&chanspy_ds
.lock
);
648 snprintf(chanspy_ds
.unique_id
, sizeof(chanspy_ds
.unique_id
), "%d", ast_atomic_fetchadd_int(&next_unique_id_to_use
, +1));
650 if (chan
->_state
!= AST_STATE_UP
)
653 ast_set_flag(chan
, AST_FLAG_SPYING
); /* so nobody can spy on us while we are spying */
658 struct chanspy_ds
*peer_chanspy_ds
= NULL
, *next_chanspy_ds
= NULL
;
659 struct ast_channel
*prev
= NULL
, *peer
= NULL
;
661 if (!ast_test_flag(flags
, OPTION_QUIET
) && num_spyed_upon
) {
662 res
= ast_streamfile(chan
, "beep", chan
->language
);
664 res
= ast_waitstream(chan
, "");
666 ast_clear_flag(chan
, AST_FLAG_SPYING
);
669 if (!ast_strlen_zero(exitcontext
)) {
673 if (!ast_goto_if_exists(chan
, exitcontext
, tmp
, 1))
676 ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp
, exitcontext
);
680 res
= ast_waitfordigit(chan
, waitms
);
682 ast_clear_flag(chan
, AST_FLAG_SPYING
);
685 if (!ast_strlen_zero(exitcontext
)) {
689 if (!ast_goto_if_exists(chan
, exitcontext
, tmp
, 1))
692 ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp
, exitcontext
);
695 /* reset for the next loop around, unless overridden later */
699 for (peer_chanspy_ds
= next_channel(chan
, prev
, spec
, exten
, context
, &chanspy_ds
);
701 chanspy_ds_free(peer_chanspy_ds
), prev
= peer
,
702 peer_chanspy_ds
= next_chanspy_ds
? next_chanspy_ds
:
703 next_channel(chan
, prev
, spec
, exten
, context
, &chanspy_ds
), next_chanspy_ds
= NULL
) {
706 char *groups
[NUM_SPYGROUPS
];
707 char *mygroups
[NUM_SPYGROUPS
];
710 int num_mygroups
= 0;
719 int ienf
= !myenforced
;
721 peer
= peer_chanspy_ds
->chan
;
723 ast_mutex_unlock(&peer_chanspy_ds
->lock
);
726 ast_channel_unlock(peer
);
727 chanspy_ds_free(peer_chanspy_ds
);
731 if (ast_check_hangup(chan
)) {
732 ast_channel_unlock(peer
);
733 chanspy_ds_free(peer_chanspy_ds
);
737 if (ast_test_flag(flags
, OPTION_BRIDGED
) && !ast_bridged_channel(peer
)) {
738 ast_channel_unlock(peer
);
742 if (ast_check_hangup(peer
) || ast_test_flag(peer
, AST_FLAG_SPYING
)) {
743 ast_channel_unlock(peer
);
748 dup_mygroup
= ast_strdupa(mygroup
);
749 num_mygroups
= ast_app_separate_args(dup_mygroup
, ':', mygroups
,
750 sizeof(mygroups
) / sizeof(mygroups
[0]));
752 if ((group
= pbx_builtin_getvar_helper(peer
, "SPYGROUP"))) {
753 dup_group
= ast_strdupa(group
);
754 num_groups
= ast_app_separate_args(dup_group
, ':', groups
,
755 sizeof(groups
) / sizeof(groups
[0]));
758 for (y
= 0; y
< num_mygroups
; y
++) {
759 for (x
= 0; x
< num_groups
; x
++) {
760 if (!strcmp(mygroups
[y
], groups
[x
])) {
769 ast_channel_unlock(peer
);
775 /* We don't need to allocate more space than just the
776 length of (peer->name) for ext as we will cut the
777 channel name's ending before copying into ext */
779 ext
= alloca(strlen(peer
->name
));
781 form_enforced
= alloca(strlen(myenforced
) + 3);
783 strcpy(form_enforced
, ":");
784 strcat(form_enforced
, myenforced
);
785 strcat(form_enforced
, ":");
787 buffer
= ast_strdupa(peer
->name
);
789 if ((end
= strchr(buffer
, '-'))) {
797 if (strcasestr(form_enforced
, ext
))
804 strcpy(peer_name
, "spy-");
805 strncat(peer_name
, peer
->name
, AST_NAME_STRLEN
- 4 - 1);
806 ptr
= strchr(peer_name
, '/');
808 ptr
= strsep(&ptr
, "-");
810 for (s
= peer_name
; s
< ptr
; s
++)
812 /* We have to unlock the peer channel here to avoid a deadlock.
813 * So, when we need to dereference it again, we have to lock the
814 * datastore and get the pointer from there to see if the channel
816 ast_channel_unlock(peer
);
818 if (!ast_test_flag(flags
, OPTION_QUIET
)) {
819 if (ast_test_flag(flags
, OPTION_NAME
)) {
820 const char *local_context
= S_OR(name_context
, "default");
821 const char *local_mailbox
= S_OR(mailbox
, ptr
);
822 res
= ast_app_sayname(chan
, local_mailbox
, local_context
);
824 if (!ast_test_flag(flags
, OPTION_NAME
) || res
< 0) {
825 if (!ast_test_flag(flags
, OPTION_NOTECH
)) {
826 if (ast_fileexists(peer_name
, NULL
, NULL
) != -1) {
827 res
= ast_streamfile(chan
, peer_name
, chan
->language
);
829 res
= ast_waitstream(chan
, "");
832 chanspy_ds_free(peer_chanspy_ds
);
836 res
= ast_say_character_str(chan
, peer_name
, "", chan
->language
);
839 if ((num
= atoi(ptr
)))
840 ast_say_digits(chan
, atoi(ptr
), "", chan
->language
);
844 res
= channel_spy(chan
, peer_chanspy_ds
, &volfactor
, fd
, flags
, exitcontext
);
848 chanspy_ds_free(peer_chanspy_ds
);
850 } else if (res
== -2) {
852 chanspy_ds_free(peer_chanspy_ds
);
854 } else if (res
> 1 && spec
) {
855 struct ast_channel
*next
;
857 snprintf(nameprefix
, AST_NAME_STRLEN
, "%s/%d", spec
, res
);
859 if ((next
= ast_get_channel_by_name_prefix_locked(nameprefix
, strlen(nameprefix
)))) {
860 peer_chanspy_ds
= chanspy_ds_free(peer_chanspy_ds
);
861 next_chanspy_ds
= setup_chanspy_ds(next
, &chanspy_ds
);
863 /* stay on this channel, if it is still valid */
865 ast_mutex_lock(&peer_chanspy_ds
->lock
);
866 if (peer_chanspy_ds
->chan
) {
867 ast_channel_lock(peer_chanspy_ds
->chan
);
868 next_chanspy_ds
= peer_chanspy_ds
;
869 peer_chanspy_ds
= NULL
;
871 /* the channel is gone */
872 ast_mutex_unlock(&peer_chanspy_ds
->lock
);
873 next_chanspy_ds
= NULL
;
880 if (res
== -1 || ast_check_hangup(chan
))
885 ast_clear_flag(chan
, AST_FLAG_SPYING
);
887 ast_channel_setoption(chan
, AST_OPTION_TXGAIN
, &zero_volume
, sizeof(zero_volume
), 0);
889 ast_mutex_destroy(&chanspy_ds
.lock
);
894 static int chanspy_exec(struct ast_channel
*chan
, void *data
)
896 char *myenforced
= NULL
;
897 char *mygroup
= NULL
;
898 char *recbase
= NULL
;
900 struct ast_flags flags
;
904 char *mailbox
= NULL
;
905 char *name_context
= NULL
;
906 AST_DECLARE_APP_ARGS(args
,
908 AST_APP_ARG(options
);
910 char *opts
[OPT_ARG_ARRAY_SIZE
];
912 data
= ast_strdupa(data
);
913 AST_STANDARD_APP_ARGS(args
, data
);
915 if (args
.spec
&& !strcmp(args
.spec
, "all"))
919 ast_app_parse_options(spy_opts
, &flags
, opts
, args
.options
);
920 if (ast_test_flag(&flags
, OPTION_GROUP
))
921 mygroup
= opts
[OPT_ARG_GROUP
];
923 if (ast_test_flag(&flags
, OPTION_RECORD
) &&
924 !(recbase
= opts
[OPT_ARG_RECORD
]))
927 if (ast_test_flag(&flags
, OPTION_VOLUME
) && opts
[OPT_ARG_VOLUME
]) {
930 if ((sscanf(opts
[OPT_ARG_VOLUME
], "%d", &vol
) != 1) || (vol
> 4) || (vol
< -4))
931 ast_log(LOG_NOTICE
, "Volume factor must be a number between -4 and 4\n");
936 if (ast_test_flag(&flags
, OPTION_PRIVATE
))
937 ast_set_flag(&flags
, OPTION_WHISPER
);
939 if (ast_test_flag(&flags
, OPTION_ENFORCED
))
940 myenforced
= opts
[OPT_ARG_ENFORCED
];
942 if (ast_test_flag(&flags
, OPTION_NAME
)) {
943 if (!ast_strlen_zero(opts
[OPT_ARG_NAME
])) {
945 if ((delimiter
= strchr(opts
[OPT_ARG_NAME
], '@'))) {
946 mailbox
= opts
[OPT_ARG_NAME
];
948 name_context
= delimiter
;
950 mailbox
= opts
[OPT_ARG_NAME
];
957 ast_clear_flag(&flags
, AST_FLAGS_ALL
);
959 oldwf
= chan
->writeformat
;
960 if (ast_set_write_format(chan
, AST_FORMAT_SLINEAR
) < 0) {
961 ast_log(LOG_ERROR
, "Could Not Set Write Format.\n");
966 char filename
[PATH_MAX
];
968 snprintf(filename
, sizeof(filename
), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR
, recbase
, (int) time(NULL
));
969 if ((fd
= open(filename
, O_CREAT
| O_WRONLY
| O_TRUNC
, AST_FILE_MODE
)) <= 0) {
970 ast_log(LOG_WARNING
, "Cannot open '%s' for recording\n", filename
);
975 res
= common_exec(chan
, &flags
, volfactor
, fd
, mygroup
, myenforced
, args
.spec
, NULL
, NULL
, mailbox
, name_context
);
980 if (oldwf
&& ast_set_write_format(chan
, oldwf
) < 0)
981 ast_log(LOG_ERROR
, "Could Not Set Write Format.\n");
986 static int extenspy_exec(struct ast_channel
*chan
, void *data
)
988 char *ptr
, *exten
= NULL
;
989 char *mygroup
= NULL
;
990 char *recbase
= NULL
;
992 struct ast_flags flags
;
996 char *mailbox
= NULL
;
997 char *name_context
= NULL
;
998 AST_DECLARE_APP_ARGS(args
,
999 AST_APP_ARG(context
);
1000 AST_APP_ARG(options
);
1003 data
= ast_strdupa(data
);
1005 AST_STANDARD_APP_ARGS(args
, data
);
1006 if (!ast_strlen_zero(args
.context
) && (ptr
= strchr(args
.context
, '@'))) {
1007 exten
= args
.context
;
1012 if (ast_strlen_zero(args
.context
))
1013 args
.context
= ast_strdupa(chan
->context
);
1016 char *opts
[OPT_ARG_ARRAY_SIZE
];
1018 ast_app_parse_options(spy_opts
, &flags
, opts
, args
.options
);
1019 if (ast_test_flag(&flags
, OPTION_GROUP
))
1020 mygroup
= opts
[OPT_ARG_GROUP
];
1022 if (ast_test_flag(&flags
, OPTION_RECORD
) &&
1023 !(recbase
= opts
[OPT_ARG_RECORD
]))
1024 recbase
= "chanspy";
1026 if (ast_test_flag(&flags
, OPTION_VOLUME
) && opts
[OPT_ARG_VOLUME
]) {
1029 if ((sscanf(opts
[OPT_ARG_VOLUME
], "%d", &vol
) != 1) || (vol
> 4) || (vol
< -4))
1030 ast_log(LOG_NOTICE
, "Volume factor must be a number between -4 and 4\n");
1035 if (ast_test_flag(&flags
, OPTION_PRIVATE
))
1036 ast_set_flag(&flags
, OPTION_WHISPER
);
1039 if (ast_test_flag(&flags
, OPTION_NAME
)) {
1040 if (!ast_strlen_zero(opts
[OPT_ARG_NAME
])) {
1042 if ((delimiter
= strchr(opts
[OPT_ARG_NAME
], '@'))) {
1043 mailbox
= opts
[OPT_ARG_NAME
];
1044 *delimiter
++ = '\0';
1045 name_context
= delimiter
;
1047 mailbox
= opts
[OPT_ARG_NAME
];
1053 ast_clear_flag(&flags
, AST_FLAGS_ALL
);
1055 oldwf
= chan
->writeformat
;
1056 if (ast_set_write_format(chan
, AST_FORMAT_SLINEAR
) < 0) {
1057 ast_log(LOG_ERROR
, "Could Not Set Write Format.\n");
1062 char filename
[PATH_MAX
];
1064 snprintf(filename
, sizeof(filename
), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR
, recbase
, (int) time(NULL
));
1065 if ((fd
= open(filename
, O_CREAT
| O_WRONLY
| O_TRUNC
, AST_FILE_MODE
)) <= 0) {
1066 ast_log(LOG_WARNING
, "Cannot open '%s' for recording\n", filename
);
1072 res
= common_exec(chan
, &flags
, volfactor
, fd
, mygroup
, NULL
, NULL
, exten
, args
.context
, mailbox
, name_context
);
1077 if (oldwf
&& ast_set_write_format(chan
, oldwf
) < 0)
1078 ast_log(LOG_ERROR
, "Could Not Set Write Format.\n");
1083 static int unload_module(void)
1087 res
|= ast_unregister_application(app_chan
);
1088 res
|= ast_unregister_application(app_ext
);
1093 static int load_module(void)
1097 res
|= ast_register_application(app_chan
, chanspy_exec
, tdesc
, desc_chan
);
1098 res
|= ast_register_application(app_ext
, extenspy_exec
, tdesc
, desc_ext
);
1103 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY
, "Listen to the audio of an active channel");