Asterisk - The Open Source Telephony Project GIT-master-545c459
Loading...
Searching...
No Matches
app_chanspy.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 2005 Anthony Minessale II (anthmct@yahoo.com)
5 * Copyright (C) 2005 - 2008, Digium, Inc.
6 *
7 * A license has been granted to Digium (via disclaimer) for the use of
8 * this code.
9 *
10 * See http://www.asterisk.org for more information about
11 * the Asterisk project. Please do not directly contact
12 * any of the maintainers of this project for assistance;
13 * the project provides a web site, mailing lists and IRC
14 * channels for your use.
15 *
16 * This program is free software, distributed under the terms of
17 * the GNU General Public License Version 2. See the LICENSE file
18 * at the top of the source tree.
19 */
20
21/*! \file
22 *
23 * \brief ChanSpy: Listen in on any channel.
24 *
25 * \author Anthony Minessale II <anthmct@yahoo.com>
26 * \author Joshua Colp <jcolp@digium.com>
27 * \author Russell Bryant <russell@digium.com>
28 *
29 * \ingroup applications
30 */
31
32/*** MODULEINFO
33 <support_level>core</support_level>
34 ***/
35
36#include "asterisk.h"
37
38#include <ctype.h>
39#include <errno.h>
40
41#include "asterisk/paths.h" /* use ast_config_AST_MONITOR_DIR */
42#include "asterisk/file.h"
43#include "asterisk/channel.h"
44#include "asterisk/audiohook.h"
45#include "asterisk/features.h"
46#include "asterisk/app.h"
47#include "asterisk/utils.h"
48#include "asterisk/say.h"
49#include "asterisk/pbx.h"
50#include "asterisk/translate.h"
51#include "asterisk/manager.h"
52#include "asterisk/module.h"
53#include "asterisk/lock.h"
54#include "asterisk/options.h"
55#include "asterisk/autochan.h"
57#include "asterisk/json.h"
59
60#define AST_NAME_STRLEN 256
61#define NUM_SPYGROUPS 128
62
63/*** DOCUMENTATION
64 <application name="ChanSpy" language="en_US">
65 <since>
66 <version>1.2.0</version>
67 </since>
68 <synopsis>
69 Listen to a channel, and optionally whisper into it.
70 </synopsis>
71 <syntax>
72 <parameter name="chanprefix" />
73 <parameter name="options">
74 <optionlist>
75 <option name="b">
76 <para>Only spy on channels involved in a bridged call.</para>
77 </option>
78 <option name="B">
79 <para>Instead of whispering on a single channel barge in on both
80 channels involved in the call.</para>
81 </option>
82 <option name="c">
83 <argument name="digit" required="true">
84 <para>Specify a DTMF digit that can be used to spy on the next available channel.</para>
85 </argument>
86 </option>
87 <option name="d">
88 <para>Override the typical numeric DTMF functionality and instead
89 use DTMF to switch between spy modes.</para>
90 <enumlist>
91 <enum name="4">
92 <para>spy mode</para>
93 </enum>
94 <enum name="5">
95 <para>whisper mode</para>
96 </enum>
97 <enum name="6">
98 <para>barge mode</para>
99 </enum>
100 </enumlist>
101 </option>
102 <option name="e">
103 <argument name="ext" required="true" />
104 <para>Enable <emphasis>enforced</emphasis> mode, so the spying channel can
105 only monitor extensions whose name is in the <replaceable>ext</replaceable> : delimited
106 list.</para>
107 </option>
108 <option name="E">
109 <para>Exit when the spied-on channel hangs up.</para>
110 </option>
111 <option name="g">
112 <argument name="grp" required="true">
113 <para>Only spy on channels in which one or more of the groups
114 listed in <replaceable>grp</replaceable> matches one or more groups from the
115 <variable>SPYGROUP</variable> variable set on the channel to be spied upon.</para>
116 </argument>
117 <note><para>both <replaceable>grp</replaceable> and <variable>SPYGROUP</variable> can contain
118 either a single group or a colon-delimited list of groups, such
119 as <literal>sales:support:accounting</literal>.</para></note>
120 </option>
121 <option name="l">
122 <para>Allow usage of a long queue to store audio frames.</para>
123 <note><para>This may introduce some delay in the received audio feed, but will improve the audio quality.</para></note>
124 </option>
125 <option name="n" argsep="@">
126 <para>Say the name of the person being spied on if that person has recorded
127 his/her name. If a context is specified, then that voicemail context will
128 be searched when retrieving the name, otherwise the <literal>default</literal> context
129 be used when searching for the name (i.e. if SIP/1000 is the channel being
130 spied on and no mailbox is specified, then <literal>1000</literal> will be used when searching
131 for the name).</para>
132 <argument name="mailbox" />
133 <argument name="context" />
134 </option>
135 <option name="N">
136 <para>Do not answer the channel automatically.</para>
137 </option>
138 <option name="o">
139 <para>Only listen to audio coming from this channel.</para>
140 </option>
141 <option name="q">
142 <para>Don't play a beep when beginning to spy on a channel, or speak the
143 selected channel name.</para>
144 </option>
145 <option name="r">
146 <para>Record the session to the monitor spool directory. An optional base for the filename
147 may be specified. The default is <literal>chanspy</literal>.</para>
148 <argument name="basename" />
149 </option>
150 <option name="s">
151 <para>Skip the playback of the channel type (i.e. SIP, IAX, etc) when
152 speaking the selected channel name.</para>
153 </option>
154 <option name="S">
155 <para>Stop when no more channels are left to spy on.</para>
156 </option>
157 <option name="u">
158 <para>The <literal>chanprefix</literal> parameter is a channel uniqueid
159 or fully specified channel name.</para>
160 </option>
161 <option name="v">
162 <argument name="value" />
163 <para>Adjust the initial volume in the range from <literal>-4</literal>
164 to <literal>4</literal>. A negative value refers to a quieter setting.</para>
165 </option>
166 <option name="w">
167 <para>Enable <literal>whisper</literal> mode, so the spying channel can talk to
168 the spied-on channel.</para>
169 </option>
170 <option name="W">
171 <para>Enable <literal>private whisper</literal> mode, so the spying channel can
172 talk to the spied-on channel but cannot listen to that channel.</para>
173 </option>
174 <option name="x">
175 <argument name="digit" required="true">
176 <para>Specify a DTMF digit that can be used to exit the application while actively
177 spying on a channel. If there is no channel being spied on, the DTMF digit will be
178 ignored.</para>
179 </argument>
180 </option>
181 <option name="X">
182 <para>Allow the user to exit ChanSpy to a valid single digit
183 numeric extension in the current context or the context
184 specified by the <variable>SPY_EXIT_CONTEXT</variable> channel variable. The
185 name of the last channel that was spied on will be stored
186 in the <variable>SPY_CHANNEL</variable> variable.</para>
187 </option>
188 </optionlist>
189 </parameter>
190 </syntax>
191 <description>
192 <para>This application is used to listen to the audio from an Asterisk channel. This includes the audio
193 coming in and out of the channel being spied on. If the <literal>chanprefix</literal> parameter is specified,
194 only channels beginning with this string will be spied upon.</para>
195 <para>While spying, the following actions may be performed:</para>
196 <para> - Dialing <literal>#</literal> cycles the volume level.</para>
197 <para> - Dialing <literal>*</literal> will stop spying and look for another channel to spy on.</para>
198 <para> - Dialing a series of digits followed by <literal>#</literal> builds a channel name to append
199 to <literal>chanprefix</literal>. For example, executing ChanSpy(Agent) and then dialing the digits '1234#'
200 while spying will begin spying on the channel 'Agent/1234'. Note that this feature will be overridden
201 if the 'd' or 'u' options are used.</para>
202 <note><para>The <replaceable>X</replaceable> option supersedes the three features above in that if a valid
203 single digit extension exists in the correct context ChanSpy will exit to it.
204 This also disables choosing a channel based on <literal>chanprefix</literal> and a digit sequence.</para></note>
205 </description>
206 <see-also>
207 <ref type="application">ExtenSpy</ref>
208 <ref type="managerEvent">ChanSpyStart</ref>
209 <ref type="managerEvent">ChanSpyStop</ref>
210 </see-also>
211 </application>
212 <application name="ExtenSpy" language="en_US">
213 <since>
214 <version>1.4.0</version>
215 </since>
216 <synopsis>
217 Listen to a channel, and optionally whisper into it.
218 </synopsis>
219 <syntax>
220 <parameter name="exten" required="true" argsep="@">
221 <argument name="exten" required="true">
222 <para>Specify extension.</para>
223 </argument>
224 <argument name="context">
225 <para>Optionally specify a context, defaults to <literal>default</literal>.</para>
226 </argument>
227 </parameter>
228 <parameter name="options">
229 <optionlist>
230 <option name="b">
231 <para>Only spy on channels involved in a bridged call.</para>
232 </option>
233 <option name="B">
234 <para>Instead of whispering on a single channel barge in on both
235 channels involved in the call.</para>
236 </option>
237 <option name="c">
238 <argument name="digit" required="true">
239 <para>Specify a DTMF digit that can be used to spy on the next available channel.</para>
240 </argument>
241 </option>
242 <option name="d">
243 <para>Override the typical numeric DTMF functionality and instead
244 use DTMF to switch between spy modes.</para>
245 <enumlist>
246 <enum name="4">
247 <para>spy mode</para>
248 </enum>
249 <enum name="5">
250 <para>whisper mode</para>
251 </enum>
252 <enum name="6">
253 <para>barge mode</para>
254 </enum>
255 </enumlist>
256 </option>
257 <option name="D">
258 <para>Interleave the audio coming from the channel and the audio coming to the channel in
259 the output audio as a dual channel stream, rather than mix it. Does nothing if 'o'
260 is also set.</para>
261 </option>
262 <option name="e">
263 <argument name="ext" required="true" />
264 <para>Enable <emphasis>enforced</emphasis> mode, so the spying channel can
265 only monitor extensions whose name is in the <replaceable>ext</replaceable> : delimited
266 list.</para>
267 </option>
268 <option name="E">
269 <para>Exit when the spied-on channel hangs up.</para>
270 </option>
271 <option name="g">
272 <argument name="grp" required="true">
273 <para>Only spy on channels in which one or more of the groups
274 listed in <replaceable>grp</replaceable> matches one or more groups from the
275 <variable>SPYGROUP</variable> variable set on the channel to be spied upon.</para>
276 </argument>
277 <note><para>both <replaceable>grp</replaceable> and <variable>SPYGROUP</variable> can contain
278 either a single group or a colon-delimited list of groups, such
279 as <literal>sales:support:accounting</literal>.</para></note>
280 </option>
281 <option name="l">
282 <para>Allow usage of a long queue to store audio frames.</para>
283 <note><para>This may introduce some delay in the received audio feed, but will improve the audio quality.</para></note>
284 </option>
285 <option name="n" argsep="@">
286 <para>Say the name of the person being spied on if that person has recorded
287 his/her name. If a context is specified, then that voicemail context will
288 be searched when retrieving the name, otherwise the <literal>default</literal> context
289 be used when searching for the name (i.e. if SIP/1000 is the channel being
290 spied on and no mailbox is specified, then <literal>1000</literal> will be used when searching
291 for the name).</para>
292 <argument name="mailbox" />
293 <argument name="context" />
294 </option>
295 <option name="N">
296 <para>Do not answer the channel automatically.</para>
297 </option>
298 <option name="o">
299 <para>Only listen to audio coming from this channel.</para>
300 </option>
301 <option name="q">
302 <para>Don't play a beep when beginning to spy on a channel, or speak the
303 selected channel name.</para>
304 </option>
305 <option name="r">
306 <para>Record the session to the monitor spool directory. An optional base for the filename
307 may be specified. The default is <literal>chanspy</literal>.</para>
308 <argument name="basename" />
309 </option>
310 <option name="s">
311 <para>Skip the playback of the channel type (i.e. SIP, IAX, etc) when
312 speaking the selected channel name.</para>
313 </option>
314 <option name="S">
315 <para>Stop when there are no more extensions left to spy on.</para>
316 </option>
317 <option name="v">
318 <argument name="value" />
319 <para>Adjust the initial volume in the range from <literal>-4</literal>
320 to <literal>4</literal>. A negative value refers to a quieter setting.</para>
321 </option>
322 <option name="w">
323 <para>Enable <literal>whisper</literal> mode, so the spying channel can talk to
324 the spied-on channel.</para>
325 </option>
326 <option name="W">
327 <para>Enable <literal>private whisper</literal> mode, so the spying channel can
328 talk to the spied-on channel but cannot listen to that channel.</para>
329 </option>
330 <option name="x">
331 <argument name="digit" required="true">
332 <para>Specify a DTMF digit that can be used to exit the application while actively
333 spying on a channel. If there is no channel being spied on, the DTMF digit will be
334 ignored.</para>
335 </argument>
336 </option>
337 <option name="X">
338 <para>Allow the user to exit ChanSpy to a valid single digit
339 numeric extension in the current context or the context
340 specified by the <variable>SPY_EXIT_CONTEXT</variable> channel variable. The
341 name of the last channel that was spied on will be stored
342 in the <variable>SPY_CHANNEL</variable> variable.</para>
343 </option>
344 </optionlist>
345 </parameter>
346 </syntax>
347 <description>
348 <para>This application is used to listen to the audio from an Asterisk channel. This includes
349 the audio coming in and out of the channel being spied on. Only channels created by outgoing calls for the
350 specified extension will be selected for spying. If the optional context is not supplied,
351 the current channel's context will be used.</para>
352 <para>While spying, the following actions may be performed:</para>
353 <para> - Dialing <literal>#</literal> cycles the volume level.</para>
354 <para> - Dialing <literal>*</literal> will stop spying and look for another channel to spy on.</para>
355 <note><para>The <replaceable>X</replaceable> option supersedes the three features above in that if a valid
356 single digit extension exists in the correct context ChanSpy will exit to it.
357 This also disables choosing a channel based on <literal>chanprefix</literal> and a digit sequence.</para></note>
358 </description>
359 <see-also>
360 <ref type="application">ChanSpy</ref>
361 <ref type="managerEvent">ChanSpyStart</ref>
362 <ref type="managerEvent">ChanSpyStop</ref>
363 </see-also>
364 </application>
365 <application name="DAHDIScan" language="en_US">
366 <since>
367 <version>1.4.22</version>
368 </since>
369 <synopsis>
370 Scan DAHDI channels to monitor calls.
371 </synopsis>
372 <syntax>
373 <parameter name="group">
374 <para>Limit scanning to a channel <replaceable>group</replaceable> by setting this option.</para>
375 </parameter>
376 </syntax>
377 <description>
378 <para>Allows a call center manager to monitor DAHDI channels in a
379 convenient way. Use <literal>#</literal> to select the next channel and use <literal>*</literal> to exit.</para>
380 </description>
381 <see-also>
382 <ref type="managerEvent">ChanSpyStart</ref>
383 <ref type="managerEvent">ChanSpyStop</ref>
384 </see-also>
385 </application>
386 ***/
387
388static const char app_chan[] = "ChanSpy";
389
390static const char app_ext[] = "ExtenSpy";
391
392static const char app_dahdiscan[] = "DAHDIScan";
393
394enum {
395 OPTION_QUIET = (1 << 0), /* Quiet, no announcement */
396 OPTION_BRIDGED = (1 << 1), /* Only look at bridged calls */
397 OPTION_VOLUME = (1 << 2), /* Specify initial volume */
398 OPTION_GROUP = (1 << 3), /* Only look at channels in group */
399 OPTION_RECORD = (1 << 4),
400 OPTION_WHISPER = (1 << 5),
401 OPTION_PRIVATE = (1 << 6), /* Private Whisper mode */
402 OPTION_READONLY = (1 << 7), /* Don't mix the two channels */
403 OPTION_EXIT = (1 << 8), /* Exit to a valid single digit extension */
404 OPTION_ENFORCED = (1 << 9), /* Enforced mode */
405 OPTION_NOTECH = (1 << 10), /* Skip technology name playback */
406 OPTION_BARGE = (1 << 11), /* Barge mode (whisper to both channels) */
407 OPTION_NAME = (1 << 12), /* Say the name of the person on whom we will spy */
408 OPTION_DTMF_SWITCH_MODES = (1 << 13), /* Allow numeric DTMF to switch between chanspy modes */
409 OPTION_DTMF_EXIT = (1 << 14), /* Set DTMF to exit, added for DAHDIScan integration */
410 OPTION_DTMF_CYCLE = (1 << 15), /* Custom DTMF for cycling next available channel, (default is '*') */
411 OPTION_DAHDI_SCAN = (1 << 16), /* Scan groups in DAHDIScan mode */
412 OPTION_STOP = (1 << 17),
413 OPTION_EXITONHANGUP = (1 << 18), /* Hang up when the spied-on channel hangs up. */
414 OPTION_UNIQUEID = (1 << 19), /* The chanprefix is a channel uniqueid or fully specified channel name. */
415 OPTION_LONG_QUEUE = (1 << 20), /* Allow usage of a long queue to store audio frames. */
416 OPTION_INTERLEAVED = (1 << 21), /* Interleave the Read and Write frames in the output frame. */
417 OPTION_NOANSWER = (1 << 22), /* Do not automatically answer the channel */
418};
419
420enum {
429};
430
454});
455
465
467 char exit;
468 char cycle;
469 char volume;
470};
471
472static void *spy_alloc(struct ast_channel *chan, void *data)
473{
474 /* just store the data pointer in the channel structure */
475 return data;
476}
477
478static void spy_release(struct ast_channel *chan, void *data)
479{
480 /* nothing to do */
481}
482
483static int spy_generate(struct ast_channel *chan, void *data, int len, int samples)
484{
485 struct chanspy_translation_helper *csth = data;
486 struct ast_frame *f, *cur;
487
490 /* Channel is already gone more than likely */
492 return -1;
493 }
494
495 if (ast_test_flag(&csth->flags, OPTION_READONLY)) {
496 /* Option 'o' was set, so don't mix channel audio */
498 } else if (ast_test_flag(&csth->flags, OPTION_INTERLEAVED)) {
499 /* Option 'D' was set, so mix the spy frame as an interleaved dual channel frame. */
500 int i;
501 struct ast_frame *fr_read = NULL;
502 struct ast_frame *fr_write = NULL;
503 short read_buf[samples];
504 short write_buf[samples];
505 short stereo_buf[samples * 2];
506 struct ast_frame stereo_frame = {
508 .datalen = sizeof(stereo_buf),
509 .samples = samples,
510 };
511
512 f = ast_audiohook_read_frame_all(&csth->spy_audiohook, samples, ast_format_slin, &fr_read, &fr_write);
513 if (f) {
514 ast_frame_free(f, 0);
515 f = NULL;
516 }
517
518 if (fr_read) {
519 memcpy(read_buf, fr_read->data.ptr, sizeof(read_buf));
520 } else {
521 /* silent out the output frame if we can't read the input */
522 memset(read_buf, 0, sizeof(read_buf));
523 }
524
525 if (fr_write) {
526 memcpy(write_buf, fr_write->data.ptr, sizeof(write_buf));
527 } else {
528 memset(write_buf, 0, sizeof(write_buf));
529 }
530
531 for (i = 0; i < samples; i++) {
532 stereo_buf[i*2] = read_buf[i];
533 stereo_buf[i*2+1] = write_buf[i];
534 }
535
536 stereo_frame.data.ptr = stereo_buf;
538
539 f = ast_frdup(&stereo_frame);
540
541 if (fr_read) {
542 ast_frame_free(fr_read, 0);
543 }
544 if (fr_write) {
545 ast_frame_free(fr_write, 0);
546 }
547
548 } else {
550 }
551
553
554 if (!f)
555 return 0;
556
557 for (cur = f; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
558 if (ast_write(chan, cur)) {
559 ast_frfree(f);
560 return -1;
561 }
562
563 if (csth->fd) {
564 if (write(csth->fd, cur->data.ptr, cur->datalen) < 0) {
565 ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
566 }
567 }
568 }
569
570 ast_frfree(f);
571
572 return 0;
573}
574
575static struct ast_generator spygen = {
576 .alloc = spy_alloc,
577 .release = spy_release,
578 .generate = spy_generate,
579};
580
581static int start_spying(struct ast_autochan *autochan, const char *spychan_name, struct ast_audiohook *audiohook, struct ast_flags *flags)
582{
583 int res;
584
586 ast_verb(3, "Attaching spy channel %s to %s\n",
587 spychan_name, ast_channel_name(autochan->chan));
588
589 if (ast_test_flag(flags, OPTION_READONLY)) {
592 } else {
594 }
595 if (ast_test_flag(flags, OPTION_LONG_QUEUE)) {
596 ast_debug(9, "Using a long queue to store audio frames in spy audiohook\n");
597 } else {
599 }
600 res = ast_audiohook_attach(autochan->chan, audiohook);
602 return res;
603}
604
605static int start_whispering(struct ast_autochan *autochan, const char *spychan_name, struct ast_audiohook *audiohook, struct ast_flags *flags)
606{
607 int res;
608
610 ast_verb(3, "Attaching spy channel %s to %s\n",
611 spychan_name, ast_channel_name(autochan->chan));
612
614 if (ast_test_flag(flags, OPTION_LONG_QUEUE)) {
615 ast_debug(9, "Using a long queue to store audio frames in whisper audiohook\n");
616 } else {
618 }
619 res = ast_audiohook_attach(autochan->chan, audiohook);
621 return res;
622}
623
624static void change_spy_mode(const char digit, struct ast_flags *flags)
625{
626 if (digit == '4') {
629 } else if (digit == '5') {
632 } else if (digit == '6') {
635 }
636}
637
638static int pack_channel_into_message(struct ast_channel *chan, const char *role,
639 struct ast_multi_channel_blob *payload)
640{
641 RAII_VAR(struct ast_channel_snapshot *, snapshot,
644
645 if (!snapshot) {
646 return -1;
647 }
648 ast_multi_channel_blob_add_channel(payload, role, snapshot);
649 return 0;
650}
651
652/*! \internal
653 * \brief Publish the chanspy message over Stasis-Core
654 * \param spyer The channel doing the spying
655 * \param spyee Who is being spied upon
656 * \param start If non-zero, the spying is starting. Otherwise, the spyer is
657 * finishing
658 */
659static void publish_chanspy_message(struct ast_channel *spyer,
660 struct ast_channel *spyee,
661 int start)
662{
663 RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
664 RAII_VAR(struct ast_multi_channel_blob *, payload, NULL, ao2_cleanup);
667
668 if (!spyer) {
669 ast_log(AST_LOG_WARNING, "Attempt to publish ChanSpy message for NULL spyer channel\n");
670 return;
671 }
672 blob = ast_json_null();
673 if (!blob || !type) {
674 return;
675 }
676
677 payload = ast_multi_channel_blob_create(blob);
678 if (!payload) {
679 return;
680 }
681
682 if (pack_channel_into_message(spyer, "spyer_channel", payload)) {
683 return;
684 }
685
686 if (spyee) {
687 if (pack_channel_into_message(spyee, "spyee_channel", payload)) {
688 return;
689 }
690 }
691
693 if (!message) {
694 return;
695 }
697}
698
699static int attach_barge(struct ast_autochan *spyee_autochan,
700 struct ast_autochan **spyee_bridge_autochan, struct ast_audiohook *bridge_whisper_audiohook,
701 const char *spyer_name, const char *name, struct ast_flags *flags)
702{
703 int retval = 0;
704 struct ast_autochan *internal_bridge_autochan;
705 struct ast_channel *spyee_chan;
706 RAII_VAR(struct ast_channel *, bridged, NULL, ast_channel_cleanup);
707
708 ast_autochan_channel_lock(spyee_autochan);
709 spyee_chan = ast_channel_ref(spyee_autochan->chan);
710 ast_autochan_channel_unlock(spyee_autochan);
711 bridged = ast_channel_bridge_peer(spyee_chan);
712 ast_channel_unref(spyee_chan);
713 if (!bridged) {
714 return -1;
715 }
716
717 ast_audiohook_init(bridge_whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "Chanspy", 0);
718
719 internal_bridge_autochan = ast_autochan_setup(bridged);
720 if (!internal_bridge_autochan) {
721 return -1;
722 }
723
724 if (start_whispering(internal_bridge_autochan, spyer_name, bridge_whisper_audiohook, flags)) {
725 ast_log(LOG_WARNING, "Unable to attach barge audiohook on spyee '%s'. Barge mode disabled.\n", name);
726 retval = -1;
727 }
728
729 *spyee_bridge_autochan = internal_bridge_autochan;
730
731 return retval;
732}
733
734static int channel_spy(struct ast_channel *chan, struct ast_autochan *spyee_autochan,
735 int *volfactor, int fd, struct spy_dtmf_options *user_options, struct ast_flags *flags,
736 char *exitcontext)
737{
738 struct chanspy_translation_helper csth;
739 int running = 0, bridge_connected = 0, res, x = 0;
740 char inp[24] = {0};
741 char *name;
742 struct ast_frame *f;
743 struct ast_silence_generator *silgen = NULL;
744 struct ast_autochan *spyee_bridge_autochan = NULL;
745 const char *spyer_name;
746
748 if (ast_check_hangup(chan)) {
750 return 0;
751 }
752 spyer_name = ast_strdupa(ast_channel_name(chan));
754
755 ast_autochan_channel_lock(spyee_autochan);
756 if (ast_check_hangup(spyee_autochan->chan)
757 || ast_test_flag(ast_channel_flags(spyee_autochan->chan), AST_FLAG_ZOMBIE)) {
758 ast_autochan_channel_unlock(spyee_autochan);
759 return 0;
760 }
761 name = ast_strdupa(ast_channel_name(spyee_autochan->chan));
762
763 ast_verb(2, "Spying on channel %s\n", name);
764 publish_chanspy_message(chan, spyee_autochan->chan, 1);
765 ast_autochan_channel_unlock(spyee_autochan);
766
767 memset(&csth, 0, sizeof(csth));
768 ast_copy_flags(&csth.flags, flags, AST_FLAGS_ALL);
769
770 /* This is the audiohook which gives us the audio off the channel we are
771 spying on.
772 */
774
775 if (start_spying(spyee_autochan, spyer_name, &csth.spy_audiohook, flags)) {
777 return 0;
778 }
779
781 /* This audiohook will let us inject audio from our channel into the
782 channel we are currently spying on.
783 */
785
786 if (start_whispering(spyee_autochan, spyer_name, &csth.whisper_audiohook, flags)) {
787 ast_log(LOG_WARNING, "Unable to attach whisper audiohook to spyee %s. Whisper mode disabled!\n", name);
788 }
789 }
790
792
793 csth.volfactor = *volfactor;
794
795 if (csth.volfactor) {
798 }
799
800 csth.fd = fd;
801
802 if (ast_test_flag(flags, OPTION_PRIVATE))
804 else
806
807 /* We can no longer rely on 'spyee' being an actual channel;
808 it can be hung up and freed out from under us. However, the
809 channel destructor will put NULL into our csth.spy.chan
810 field when that happens, so that is our signal that the spyee
811 channel has gone away.
812 */
813
814 /* Use a short waitfor timeout so we notice the spy audiohook leaving
815 RUNNING promptly. An indefinite wait holds an autochan ref on the
816 spyee until waitfor times out, delaying destructor / Hangup when
817 the spy channel is not readable.
818 */
820 int waitres = ast_waitfor(chan, 100);
821
822 if (waitres < 0) {
823 running = -1;
824 break;
825 }
826 if (waitres == 0) {
827 /* Timeout: re-check hook status without reading. */
828 continue;
829 }
830
831 if (!(f = ast_read(chan)) || ast_check_hangup(chan)) {
832 running = -1;
833 if (f) {
834 ast_frfree(f);
835 }
836 break;
837 }
838
840 /* This hook lets us inject audio into the channel that the spyee is currently
841 * bridged with. If the spyee isn't bridged with anything yet, nothing will
842 * be attached and we'll need to continue attempting to attach the barge
843 * audio hook. */
844 if (!bridge_connected && attach_barge(spyee_autochan, &spyee_bridge_autochan,
845 &csth.bridge_whisper_audiohook, spyer_name, name, flags) == 0) {
846 bridge_connected = 1;
847 }
848
852
853 if (bridge_connected) {
857 }
858
859 ast_frfree(f);
860 continue;
861 } else if (ast_test_flag(flags, OPTION_WHISPER) && f->frametype == AST_FRAME_VOICE) {
865 ast_frfree(f);
866 continue;
867 }
868
869 res = (f->frametype == AST_FRAME_DTMF) ? f->subclass.integer : 0;
870 ast_frfree(f);
871 if (!res)
872 continue;
873
874 if (x == sizeof(inp))
875 x = 0;
876
877 if (res < 0) {
878 running = -1;
879 break;
880 }
881
882 if (ast_test_flag(flags, OPTION_EXIT)) {
883 char tmp[2];
884 tmp[0] = res;
885 tmp[1] = '\0';
886 if (!ast_goto_if_exists(chan, exitcontext, tmp, 1)) {
887 ast_debug(1, "Got DTMF %c, goto context %s\n", tmp[0], exitcontext);
888 pbx_builtin_setvar_helper(chan, "SPY_CHANNEL", name);
889 running = -2;
890 break;
891 } else {
892 ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
893 }
894 } else if (res >= '0' && res <= '9') {
896 change_spy_mode(res, flags);
897 } else {
898 inp[x++] = res;
899 }
900 }
901
902 if (res == user_options->cycle) {
903 running = 0;
904 break;
905 } else if (res == user_options->exit) {
906 running = -2;
907 break;
908 } else if (res == user_options->volume) {
909 if (!ast_strlen_zero(inp)) {
910 running = atoi(inp);
911 break;
912 }
913
914 (*volfactor)++;
915 if (*volfactor > 4)
916 *volfactor = -4;
917 ast_verb(3, "Setting spy volume on %s to %d\n", ast_channel_name(chan), *volfactor);
918
919 csth.volfactor = *volfactor;
922 }
923 }
924
925 if (ast_test_flag(flags, OPTION_PRIVATE))
927 else
929
931
937 }
938
944 }
945
950
951 ast_verb(2, "Done Spying on channel %s\n", name);
952 publish_chanspy_message(chan, spyee_autochan->chan, 0);
953
954 if (spyee_bridge_autochan) {
955 ast_autochan_destroy(spyee_bridge_autochan);
956 }
957
958 return running;
959}
960
962 struct ast_channel *chan)
963{
964 struct ast_channel *next;
965 struct ast_autochan *autochan_store;
966 const size_t pseudo_len = strlen("DAHDI/pseudo");
967
968 if (!iter) {
969 return NULL;
970 }
971
973 if (!strncmp(ast_channel_name(next), "DAHDI/pseudo", pseudo_len)
974 || next == chan) {
975 continue;
976 }
977
978 autochan_store = ast_autochan_setup(next);
980
981 return autochan_store;
982 }
983 return NULL;
984}
985
986static int spy_sayname(struct ast_channel *chan, const char *mailbox, const char *context)
987{
988 char *mailbox_id;
989
990 mailbox_id = ast_alloca(strlen(mailbox) + strlen(context) + 2);
991 sprintf(mailbox_id, "%s@%s", mailbox, context); /* Safe */
992 return ast_app_sayname(chan, mailbox_id);
993}
994
995static int common_exec(struct ast_channel *chan, struct ast_flags *flags,
996 int volfactor, const int fd, struct spy_dtmf_options *user_options,
997 const char *mygroup, const char *myenforced, const char *spec, const char *exten,
998 const char *context, const char *mailbox, const char *name_context)
999{
1000 char nameprefix[AST_NAME_STRLEN];
1001 char exitcontext[AST_MAX_CONTEXT] = "";
1002 signed char zero_volume = 0;
1003 int waitms;
1004 int res;
1005 int num_spied_upon = 1;
1006 struct ast_channel_iterator *iter = NULL;
1007
1008 if (ast_test_flag(flags, OPTION_EXIT)) {
1009 const char *c;
1010 ast_channel_lock(chan);
1011 if ((c = pbx_builtin_getvar_helper(chan, "SPY_EXIT_CONTEXT"))) {
1013 } else {
1015 }
1016 ast_channel_unlock(chan);
1017 }
1018
1020 ast_answer(chan);
1021 }
1022
1024
1025 waitms = 100;
1026
1027 for (;;) {
1028 struct ast_autochan *autochan = NULL, *next_autochan = NULL;
1029 struct ast_channel *prev = NULL;
1030
1031 if (!ast_test_flag(flags, OPTION_QUIET) && num_spied_upon) {
1032 res = ast_streamfile(chan, "beep", ast_channel_language(chan));
1033 if (!res)
1034 res = ast_waitstream(chan, "");
1035 else if (res < 0) {
1037 break;
1038 }
1040 char tmp[2];
1041 tmp[0] = res;
1042 tmp[1] = '\0';
1043 if (!ast_goto_if_exists(chan, exitcontext, tmp, 1))
1044 goto exit;
1045 else
1046 ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
1047 }
1048 }
1049
1050 /* Set up the iterator we'll be using during this call */
1051 if (!ast_strlen_zero(spec)) {
1053 struct ast_channel *unique_chan;
1054
1055 unique_chan = ast_channel_get_by_name(spec);
1056 if (!unique_chan) {
1057 res = -1;
1058 goto exit;
1059 }
1060 iter = ast_channel_iterator_by_name_new(ast_channel_name(unique_chan), 0);
1061 ast_channel_unref(unique_chan);
1062 } else {
1063 iter = ast_channel_iterator_by_name_new(spec, strlen(spec));
1064 }
1065 } else if (!ast_strlen_zero(exten)) {
1067 } else {
1069 }
1070
1071 if (!iter) {
1072 res = -1;
1073 goto exit;
1074 }
1075
1076 res = ast_waitfordigit(chan, waitms);
1077 if (res < 0) {
1078 iter = ast_channel_iterator_destroy(iter);
1080 break;
1081 }
1083 char tmp[2];
1084 tmp[0] = res;
1085 tmp[1] = '\0';
1086 if (!ast_goto_if_exists(chan, exitcontext, tmp, 1)) {
1087 iter = ast_channel_iterator_destroy(iter);
1088 goto exit;
1089 } else {
1090 ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
1091 }
1092 }
1093
1094 /* reset for the next loop around, unless overridden later */
1095 waitms = 100;
1096 num_spied_upon = 0;
1097
1098 for (autochan = next_channel(iter, chan);
1099 autochan;
1100 prev = autochan->chan,
1101 ast_autochan_destroy(autochan),
1102 autochan = next_autochan ?: next_channel(iter, chan),
1103 next_autochan = NULL) {
1104 int igrp = !mygroup;
1105 int ienf = !myenforced;
1106
1107 if (autochan->chan == prev) {
1108 ast_autochan_destroy(autochan);
1109 break;
1110 }
1111
1112 if (ast_check_hangup(chan)) {
1113 ast_autochan_destroy(autochan);
1114 break;
1115 }
1116
1117 ast_autochan_channel_lock(autochan);
1119 && !ast_channel_is_bridged(autochan->chan)) {
1121 continue;
1122 }
1123
1124 if (ast_check_hangup(autochan->chan)
1127 continue;
1128 }
1130
1131 if (mygroup) {
1132 int num_groups = 0;
1133 int num_mygroups = 0;
1134 char dup_group[512];
1135 char dup_mygroup[512];
1136 char *groups[NUM_SPYGROUPS];
1137 char *mygroups[NUM_SPYGROUPS];
1138 const char *group = NULL;
1139 int x;
1140 int y;
1141 ast_copy_string(dup_mygroup, mygroup, sizeof(dup_mygroup));
1142 num_mygroups = ast_app_separate_args(dup_mygroup, ':', mygroups,
1143 ARRAY_LEN(mygroups));
1144
1145 /* Before dahdi scan was part of chanspy, it would use the "GROUP" variable
1146 * rather than "SPYGROUP", this check is done to preserve expected behavior */
1147 ast_autochan_channel_lock(autochan);
1149 group = pbx_builtin_getvar_helper(autochan->chan, "GROUP");
1150 } else {
1151 group = pbx_builtin_getvar_helper(autochan->chan, "SPYGROUP");
1152 }
1154
1155 if (!ast_strlen_zero(group)) {
1156 ast_copy_string(dup_group, group, sizeof(dup_group));
1157 num_groups = ast_app_separate_args(dup_group, ':', groups,
1158 ARRAY_LEN(groups));
1159 }
1160
1161 for (y = 0; y < num_mygroups; y++) {
1162 for (x = 0; x < num_groups; x++) {
1163 if (!strcmp(mygroups[y], groups[x])) {
1164 igrp = 1;
1165 break;
1166 }
1167 }
1168 }
1169 }
1170
1171 if (!igrp) {
1172 continue;
1173 }
1174 if (myenforced) {
1175 char ext[AST_CHANNEL_NAME + 3];
1176 char buffer[512];
1177 char *end;
1178
1179 snprintf(buffer, sizeof(buffer) - 1, ":%s:", myenforced);
1180
1181 ast_autochan_channel_lock(autochan);
1182 ast_copy_string(ext + 1, ast_channel_name(autochan->chan), sizeof(ext) - 1);
1184 if ((end = strchr(ext, '-'))) {
1185 *end++ = ':';
1186 *end = '\0';
1187 }
1188
1189 ext[0] = ':';
1190
1191 if (strcasestr(buffer, ext)) {
1192 ienf = 1;
1193 }
1194 }
1195
1196 if (!ienf) {
1197 continue;
1198 }
1199
1201 char peer_name[AST_NAME_STRLEN + 5];
1202 char *ptr, *s;
1203
1204 strcpy(peer_name, "spy-");
1205 ast_autochan_channel_lock(autochan);
1206 strncat(peer_name, ast_channel_name(autochan->chan), AST_NAME_STRLEN - 4 - 1);
1208 if ((ptr = strchr(peer_name, '/'))) {
1209 *ptr++ = '\0';
1210 for (s = peer_name; s < ptr; s++) {
1211 *s = tolower(*s);
1212 }
1213 if ((s = strchr(ptr, '-'))) {
1214 *s = '\0';
1215 }
1216 }
1217
1219 const char *local_context = S_OR(name_context, "default");
1220 const char *local_mailbox = S_OR(mailbox, ptr);
1221
1222 if (local_mailbox) {
1223 res = spy_sayname(chan, local_mailbox, local_context);
1224 } else {
1225 res = -1;
1226 }
1227 }
1228 if (!ast_test_flag(flags, OPTION_NAME) || res < 0) {
1229 int num;
1231 if (ast_fileexists(peer_name, NULL, NULL) > 0) {
1232 res = ast_streamfile(chan, peer_name, ast_channel_language(chan));
1233 if (!res) {
1234 res = ast_waitstream(chan, "");
1235 }
1236 if (res) {
1237 ast_autochan_destroy(autochan);
1238 break;
1239 }
1240 } else {
1241 res = ast_say_character_str(chan, peer_name, "", ast_channel_language(chan), AST_SAY_CASE_NONE);
1242 }
1243 }
1244 if (ptr && (num = atoi(ptr))) {
1245 ast_say_digits(chan, num, "", ast_channel_language(chan));
1246 }
1247 }
1248 }
1249
1250 res = channel_spy(chan, autochan, &volfactor, fd, user_options, flags, exitcontext);
1251 num_spied_upon++;
1252
1253 if (res == -1) {
1254 ast_autochan_destroy(autochan);
1255 iter = ast_channel_iterator_destroy(iter);
1256 goto exit;
1257 } else if (res == -2) {
1258 res = 0;
1259 ast_autochan_destroy(autochan);
1260 iter = ast_channel_iterator_destroy(iter);
1261 goto exit;
1262 } else if (res > 1 && spec && !ast_test_flag(flags, OPTION_UNIQUEID)) {
1263 struct ast_channel *next;
1264
1265 snprintf(nameprefix, AST_NAME_STRLEN, "%s/%d", spec, res);
1266
1267 if ((next = ast_channel_get_by_name_prefix(nameprefix, strlen(nameprefix)))) {
1268 next_autochan = ast_autochan_setup(next);
1269 next = ast_channel_unref(next);
1270 } else {
1271 /* stay on this channel, if it is still valid */
1272 ast_autochan_channel_lock(autochan);
1273 if (!ast_check_hangup(autochan->chan)) {
1274 next_autochan = ast_autochan_setup(autochan->chan);
1275 } else {
1276 /* the channel is gone */
1277 next_autochan = NULL;
1278 }
1280 }
1281 } else if (res == 0 && ast_test_flag(flags, OPTION_EXITONHANGUP)) {
1282 ast_autochan_destroy(autochan);
1283 iter = ast_channel_iterator_destroy(iter);
1284 goto exit;
1285 }
1286 }
1287
1288 iter = ast_channel_iterator_destroy(iter);
1289
1290 if (res == -1 || ast_check_hangup(chan))
1291 break;
1292 if (ast_test_flag(flags, OPTION_STOP) && !next_autochan) {
1293 break;
1294 }
1295 }
1296exit:
1297
1299
1300 ast_channel_setoption(chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);
1301
1302 return res;
1303}
1304
1305static int chanspy_exec(struct ast_channel *chan, const char *data)
1306{
1307 char *myenforced = NULL;
1308 char *mygroup = NULL;
1309 char *recbase = NULL;
1310 int fd = 0;
1311 struct ast_flags flags;
1312 struct spy_dtmf_options user_options = {
1313 .cycle = '*',
1314 .volume = '#',
1315 .exit = '\0',
1316 };
1317 RAII_VAR(struct ast_format *, oldwf, NULL, ao2_cleanup);
1318 int volfactor = 0;
1319 int res;
1320 char *mailbox = NULL;
1321 char *name_context = NULL;
1323 AST_APP_ARG(spec);
1325 );
1326 char *opts[OPT_ARG_ARRAY_SIZE];
1327 char *parse = ast_strdupa(data);
1328
1330
1331 if (args.spec && !strcmp(args.spec, "all"))
1332 args.spec = NULL;
1333
1334 if (args.options) {
1335 char tmp;
1336 ast_app_parse_options(spy_opts, &flags, opts, args.options);
1337 if (ast_test_flag(&flags, OPTION_GROUP))
1338 mygroup = opts[OPT_ARG_GROUP];
1339
1340 if (ast_test_flag(&flags, OPTION_RECORD) &&
1341 !(recbase = opts[OPT_ARG_RECORD]))
1342 recbase = "chanspy";
1343
1344 if (ast_test_flag(&flags, OPTION_DTMF_EXIT) && opts[OPT_ARG_EXIT]) {
1345 tmp = opts[OPT_ARG_EXIT][0];
1346 if (strchr("0123456789*#", tmp) && tmp != '\0') {
1347 user_options.exit = tmp;
1348 } else {
1349 ast_log(LOG_NOTICE, "Argument for option 'x' must be a valid DTMF digit.\n");
1350 }
1351 }
1352
1353 if (ast_test_flag(&flags, OPTION_DTMF_CYCLE) && opts[OPT_ARG_CYCLE]) {
1354 tmp = opts[OPT_ARG_CYCLE][0];
1355 if (strchr("0123456789*#", tmp) && tmp != '\0') {
1356 user_options.cycle = tmp;
1357 } else {
1358 ast_log(LOG_NOTICE, "Argument for option 'c' must be a valid DTMF digit.\n");
1359 }
1360 }
1361
1362 if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) {
1363 int vol;
1364
1365 if ((sscanf(opts[OPT_ARG_VOLUME], "%30d", &vol) != 1) || (vol > 4) || (vol < -4))
1366 ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n");
1367 else
1368 volfactor = vol;
1369 }
1370
1371 if (ast_test_flag(&flags, OPTION_PRIVATE))
1373
1374 if (ast_test_flag(&flags, OPTION_ENFORCED))
1375 myenforced = opts[OPT_ARG_ENFORCED];
1376
1377 if (ast_test_flag(&flags, OPTION_NAME)) {
1378 if (!ast_strlen_zero(opts[OPT_ARG_NAME])) {
1379 char *delimiter;
1380 if ((delimiter = strchr(opts[OPT_ARG_NAME], '@'))) {
1381 mailbox = opts[OPT_ARG_NAME];
1382 *delimiter++ = '\0';
1383 name_context = delimiter;
1384 } else {
1385 mailbox = opts[OPT_ARG_NAME];
1386 }
1387 }
1388 }
1389 } else {
1391 }
1392
1393 oldwf = ao2_bump(ast_channel_writeformat(chan));
1394 if (ast_set_write_format(chan, ast_format_slin) < 0) {
1395 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
1396 return -1;
1397 }
1398
1399 if (recbase) {
1400 char filename[PATH_MAX];
1401
1402 snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL));
1403 if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, AST_FILE_MODE)) <= 0) {
1404 ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename);
1405 fd = 0;
1406 }
1407 }
1408
1409 res = common_exec(chan, &flags, volfactor, fd, &user_options, mygroup, myenforced, args.spec, NULL, NULL, mailbox, name_context);
1410
1411 if (fd)
1412 close(fd);
1413
1414 if (oldwf && ast_set_write_format(chan, oldwf) < 0)
1415 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
1416
1417 if (ast_test_flag(&flags, OPTION_EXITONHANGUP)) {
1418 ast_verb(3, "Stopped spying due to the spied-on channel hanging up.\n");
1419 }
1420
1421 return res;
1422}
1423
1424static int extenspy_exec(struct ast_channel *chan, const char *data)
1425{
1426 char *ptr, *exten = NULL;
1427 char *mygroup = NULL;
1428 char *recbase = NULL;
1429 int fd = 0;
1430 struct ast_flags flags;
1431 struct spy_dtmf_options user_options = {
1432 .cycle = '*',
1433 .volume = '#',
1434 .exit = '\0',
1435 };
1436 RAII_VAR(struct ast_format *, oldwf, NULL, ao2_cleanup);
1437 int volfactor = 0;
1438 int res;
1439 char *mailbox = NULL;
1440 char *name_context = NULL;
1442 AST_APP_ARG(context);
1444 );
1445 char *parse = ast_strdupa(data);
1446
1448
1449 if (!ast_strlen_zero(args.context) && (ptr = strchr(args.context, '@'))) {
1450 exten = args.context;
1451 *ptr++ = '\0';
1452 args.context = ptr;
1453 }
1454 if (ast_strlen_zero(args.context))
1455 args.context = ast_strdupa(ast_channel_context(chan));
1456
1457 if (args.options) {
1458 char *opts[OPT_ARG_ARRAY_SIZE];
1459 char tmp;
1460
1461 ast_app_parse_options(spy_opts, &flags, opts, args.options);
1462 if (ast_test_flag(&flags, OPTION_GROUP))
1463 mygroup = opts[OPT_ARG_GROUP];
1464
1465 if (ast_test_flag(&flags, OPTION_RECORD) &&
1466 !(recbase = opts[OPT_ARG_RECORD]))
1467 recbase = "chanspy";
1468
1469 if (ast_test_flag(&flags, OPTION_DTMF_EXIT) && opts[OPT_ARG_EXIT]) {
1470 tmp = opts[OPT_ARG_EXIT][0];
1471 if (strchr("0123456789*#", tmp) && tmp != '\0') {
1472 user_options.exit = tmp;
1473 } else {
1474 ast_log(LOG_NOTICE, "Argument for option 'x' must be a valid DTMF digit.\n");
1475 }
1476 }
1477
1478 if (ast_test_flag(&flags, OPTION_DTMF_CYCLE) && opts[OPT_ARG_CYCLE]) {
1479 tmp = opts[OPT_ARG_CYCLE][0];
1480 if (strchr("0123456789*#", tmp) && tmp != '\0') {
1481 user_options.cycle = tmp;
1482 } else {
1483 ast_log(LOG_NOTICE, "Argument for option 'c' must be a valid DTMF digit.\n");
1484 }
1485 }
1486
1487 if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) {
1488 int vol;
1489
1490 if ((sscanf(opts[OPT_ARG_VOLUME], "%30d", &vol) != 1) || (vol > 4) || (vol < -4))
1491 ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n");
1492 else
1493 volfactor = vol;
1494 }
1495
1496 if (ast_test_flag(&flags, OPTION_PRIVATE))
1498
1499 if (ast_test_flag(&flags, OPTION_NAME)) {
1500 if (!ast_strlen_zero(opts[OPT_ARG_NAME])) {
1501 char *delimiter;
1502 if ((delimiter = strchr(opts[OPT_ARG_NAME], '@'))) {
1503 mailbox = opts[OPT_ARG_NAME];
1504 *delimiter++ = '\0';
1505 name_context = delimiter;
1506 } else {
1507 mailbox = opts[OPT_ARG_NAME];
1508 }
1509 }
1510 }
1511
1512 } else {
1513 /* Coverity - This uninit_use should be ignored since this macro initializes the flags */
1515 }
1516
1517 oldwf = ao2_bump(ast_channel_writeformat(chan));
1518 if (ast_set_write_format(chan, ast_format_slin) < 0) {
1519 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
1520 return -1;
1521 }
1522
1523 if (recbase) {
1524 char filename[PATH_MAX];
1525
1526 snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL));
1527 if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, AST_FILE_MODE)) <= 0) {
1528 ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename);
1529 fd = 0;
1530 }
1531 }
1532
1533
1534 res = common_exec(chan, &flags, volfactor, fd, &user_options, mygroup, NULL, NULL, exten, args.context, mailbox, name_context);
1535
1536 if (fd)
1537 close(fd);
1538
1539 if (oldwf && ast_set_write_format(chan, oldwf) < 0)
1540 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
1541
1542 return res;
1543}
1544
1545static int dahdiscan_exec(struct ast_channel *chan, const char *data)
1546{
1547 const char *spec = "DAHDI";
1548 struct ast_flags flags = {0};
1549 struct spy_dtmf_options user_options = {
1550 .cycle = '#',
1551 .volume = '\0',
1552 .exit = '*',
1553 };
1554 struct ast_format *oldwf;
1555 int res;
1556 char *mygroup = NULL;
1557
1558 /* Coverity - This uninit_use should be ignored since this macro initializes the flags */
1560
1561 if (!ast_strlen_zero(data)) {
1562 mygroup = ast_strdupa(data);
1563 }
1567
1568 oldwf = ao2_bump(ast_channel_writeformat(chan));
1569 if (ast_set_write_format(chan, ast_format_slin) < 0) {
1570 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
1571 ao2_cleanup(oldwf);
1572 return -1;
1573 }
1574
1575 res = common_exec(chan, &flags, 0, 0, &user_options, mygroup, NULL, spec, NULL, NULL, NULL, NULL);
1576
1577 if (oldwf && ast_set_write_format(chan, oldwf) < 0)
1578 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
1579 ao2_cleanup(oldwf);
1580
1581 return res;
1582}
1583
1584static int unload_module(void)
1585{
1586 int res = 0;
1587
1591
1592 return res;
1593}
1594
1595static int load_module(void)
1596{
1597 int res = 0;
1598
1602
1603 return res;
1604}
1605
1606AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Listen to the audio of an active channel");
char digit
static int spy_sayname(struct ast_channel *chan, const char *mailbox, const char *context)
#define NUM_SPYGROUPS
Definition app_chanspy.c:61
static int chanspy_exec(struct ast_channel *chan, const char *data)
static void publish_chanspy_message(struct ast_channel *spyer, struct ast_channel *spyee, int start)
static int pack_channel_into_message(struct ast_channel *chan, const char *role, struct ast_multi_channel_blob *payload)
static void * spy_alloc(struct ast_channel *chan, void *data)
static int dahdiscan_exec(struct ast_channel *chan, const char *data)
static int channel_spy(struct ast_channel *chan, struct ast_autochan *spyee_autochan, int *volfactor, int fd, struct spy_dtmf_options *user_options, struct ast_flags *flags, char *exitcontext)
static void change_spy_mode(const char digit, struct ast_flags *flags)
static const struct ast_app_option spy_opts[128]
static int start_whispering(struct ast_autochan *autochan, const char *spychan_name, struct ast_audiohook *audiohook, struct ast_flags *flags)
static int common_exec(struct ast_channel *chan, struct ast_flags *flags, int volfactor, const int fd, struct spy_dtmf_options *user_options, const char *mygroup, const char *myenforced, const char *spec, const char *exten, const char *context, const char *mailbox, const char *name_context)
static struct ast_autochan * next_channel(struct ast_channel_iterator *iter, struct ast_channel *chan)
static int extenspy_exec(struct ast_channel *chan, const char *data)
static const char app_dahdiscan[]
static int start_spying(struct ast_autochan *autochan, const char *spychan_name, struct ast_audiohook *audiohook, struct ast_flags *flags)
@ OPTION_PRIVATE
@ OPTION_ENFORCED
@ OPTION_NOANSWER
@ OPTION_EXIT
@ OPTION_BRIDGED
@ OPTION_RECORD
@ OPTION_WHISPER
@ OPTION_NAME
@ OPTION_STOP
@ OPTION_QUIET
@ OPTION_READONLY
@ OPTION_INTERLEAVED
@ OPTION_BARGE
@ OPTION_GROUP
@ OPTION_UNIQUEID
@ OPTION_DTMF_CYCLE
@ OPTION_DAHDI_SCAN
@ OPTION_DTMF_SWITCH_MODES
@ OPTION_EXITONHANGUP
@ OPTION_NOTECH
@ OPTION_DTMF_EXIT
@ OPTION_LONG_QUEUE
@ OPTION_VOLUME
static int load_module(void)
@ OPT_ARG_CYCLE
@ OPT_ARG_RECORD
@ OPT_ARG_EXIT
@ OPT_ARG_NAME
@ OPT_ARG_VOLUME
@ OPT_ARG_ENFORCED
@ OPT_ARG_ARRAY_SIZE
@ OPT_ARG_GROUP
static int attach_barge(struct ast_autochan *spyee_autochan, struct ast_autochan **spyee_bridge_autochan, struct ast_audiohook *bridge_whisper_audiohook, const char *spyer_name, const char *name, struct ast_flags *flags)
static const char app_ext[]
static int unload_module(void)
static void spy_release(struct ast_channel *chan, void *data)
#define AST_NAME_STRLEN
Definition app_chanspy.c:60
static const char app_chan[]
static int spy_generate(struct ast_channel *chan, void *data, int len, int samples)
static struct ast_generator spygen
static char exitcontext[AST_MAX_CONTEXT]
char * strcasestr(const char *, const char *)
Asterisk main include file. File version handling, generic pbx functions.
#define AST_FILE_MODE
Definition asterisk.h:32
#define PATH_MAX
Definition asterisk.h:40
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition astmm.h:288
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition astmm.h:298
#define ast_log
Definition astobj2.c:42
#define ao2_cleanup(obj)
Definition astobj2.h:1934
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
Definition astobj2.h:480
Audiohooks Architecture.
struct ast_frame * ast_audiohook_read_frame_all(struct ast_audiohook *audiohook, size_t samples, struct ast_format *format, struct ast_frame **read_frame, struct ast_frame **write_frame)
Reads a frame in from the audiohook structure in mixed audio mode and copies read and write frame dat...
Definition audiohook.c:712
int ast_audiohook_init(struct ast_audiohook *audiohook, enum ast_audiohook_type type, const char *source, enum ast_audiohook_init_flags flags)
Initialize an audiohook structure.
Definition audiohook.c:324
struct ast_frame * ast_audiohook_read_frame(struct ast_audiohook *audiohook, size_t samples, enum ast_audiohook_direction direction, struct ast_format *format)
Reads a frame in from the audiohook structure.
Definition audiohook.c:707
int ast_audiohook_write_frame(struct ast_audiohook *audiohook, enum ast_audiohook_direction direction, struct ast_frame *frame)
Writes a frame into the audiohook structure.
Definition audiohook.c:391
@ AST_AUDIOHOOK_DIRECTION_READ
Definition audiohook.h:49
@ AST_AUDIOHOOK_DIRECTION_WRITE
Definition audiohook.h:50
@ AST_AUDIOHOOK_DIRECTION_BOTH
Definition audiohook.h:51
#define ast_audiohook_lock(ah)
Lock an audiohook.
Definition audiohook.h:316
@ AST_AUDIOHOOK_MUTE_WRITE
Definition audiohook.h:65
@ AST_AUDIOHOOK_SMALL_QUEUE
Definition audiohook.h:63
@ AST_AUDIOHOOK_TRIGGER_SYNC
Definition audiohook.h:59
int ast_audiohook_detach(struct ast_audiohook *audiohook)
Detach audiohook from channel.
Definition audiohook.c:821
int ast_audiohook_attach(struct ast_channel *chan, struct ast_audiohook *audiohook)
Attach audiohook to channel.
Definition audiohook.c:745
int ast_audiohook_destroy(struct ast_audiohook *audiohook)
Destroys an audiohook structure.
Definition audiohook.c:348
#define ast_audiohook_unlock(ah)
Unlock an audiohook.
Definition audiohook.h:321
@ AST_AUDIOHOOK_TYPE_SPY
Definition audiohook.h:36
@ AST_AUDIOHOOK_TYPE_WHISPER
Definition audiohook.h:37
@ AST_AUDIOHOOK_STATUS_RUNNING
Definition audiohook.h:43
int ast_audiohook_set_frame_feed_direction(struct ast_audiohook *audiohook, enum ast_audiohook_direction direction)
Sets direction on audiohook.
Definition audiohook.c:374
"smart" channels that update automatically if a channel is masqueraded
struct ast_autochan * ast_autochan_setup(struct ast_channel *chan)
set up a new ast_autochan structure
Definition autochan.c:38
void ast_autochan_destroy(struct ast_autochan *autochan)
destroy an ast_autochan structure
Definition autochan.c:64
#define ast_autochan_channel_lock(autochan)
Lock the autochan's channel lock.
Definition autochan.h:75
#define ast_autochan_channel_unlock(autochan)
Definition autochan.h:84
static const char type[]
General Asterisk PBX channel definitions.
int ast_waitfordigit(struct ast_channel *c, int ms)
Waits for a digit.
Definition channel.c:3179
const char * ast_channel_name(const struct ast_channel *chan)
int ast_activate_generator(struct ast_channel *chan, struct ast_generator *gen, void *params)
Definition channel.c:2955
void ast_channel_clear_flag(struct ast_channel *chan, unsigned int flag)
Clear a flag on a channel.
Definition channel.c:11214
struct ast_channel_iterator * ast_channel_iterator_by_name_new(const char *name, size_t name_len)
Create a new channel iterator based on name.
Definition channel.c:1368
struct ast_channel_iterator * ast_channel_iterator_destroy(struct ast_channel_iterator *i)
Destroy a channel iterator.
Definition channel.c:1349
struct ast_channel * ast_channel_bridge_peer(struct ast_channel *chan)
Get the channel's bridge peer only if the bridge is two-party.
Definition channel.c:10744
struct stasis_topic * ast_channel_topic(struct ast_channel *chan)
A topic which publishes the events for a particular channel.
#define ast_channel_lock(chan)
Definition channel.h:2983
@ AST_FLAG_ZOMBIE
Definition channel.h:1007
@ AST_FLAG_END_DTMF_ONLY
Definition channel.h:1027
@ AST_FLAG_SPYING
Definition channel.h:1013
struct ast_channel * ast_channel_iterator_next(struct ast_channel_iterator *i)
Get the next channel for a channel iterator.
Definition channel.c:1388
struct ast_silence_generator * ast_channel_start_silence_generator(struct ast_channel *chan)
Starts a silence generator on the given channel.
Definition channel.c:8340
int ast_waitfor(struct ast_channel *chan, int ms)
Wait for input on a channel.
Definition channel.c:3166
struct ast_flags * ast_channel_flags(struct ast_channel *chan)
void ast_channel_stop_silence_generator(struct ast_channel *chan, struct ast_silence_generator *state)
Stops a previously-started silence generator on the given channel.
Definition channel.c:8386
#define ast_channel_ref(c)
Increase channel reference count.
Definition channel.h:3008
const char * ast_channel_uniqueid(const struct ast_channel *chan)
const char * ast_channel_context(const struct ast_channel *chan)
void ast_deactivate_generator(struct ast_channel *chan)
Definition channel.c:2892
struct ast_channel_iterator * ast_channel_iterator_by_exten_new(const char *exten, const char *context)
Create a new channel iterator based on extension.
Definition channel.c:1357
struct ast_channel * ast_channel_get_by_name_prefix(const char *name, size_t name_len)
Find a channel by a name prefix.
Definition channel.c:1400
int ast_write(struct ast_channel *chan, struct ast_frame *frame)
Write a frame to a channel This function writes the given frame to the indicated channel.
Definition channel.c:5167
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition channel.c:4278
struct ast_channel * ast_channel_get_by_name(const char *search)
Find a channel by name or uniqueid.
Definition channel.c:1417
int ast_check_hangup(struct ast_channel *chan)
Check to see if a channel is needing hang up.
Definition channel.c:446
int ast_channel_is_bridged(const struct ast_channel *chan)
Determine if a channel is in a bridge.
Definition channel.c:10725
void ast_channel_set_flag(struct ast_channel *chan, unsigned int flag)
Set a flag on a channel.
Definition channel.c:11207
#define AST_CHANNEL_NAME
Definition channel.h:173
#define ast_channel_unref(c)
Decrease channel reference count.
Definition channel.h:3019
struct ast_format * ast_channel_writeformat(struct ast_channel *chan)
int ast_set_write_format(struct ast_channel *chan, struct ast_format *format)
Sets write format on channel chan.
Definition channel.c:5826
#define AST_MAX_CONTEXT
Definition channel.h:135
const char * ast_channel_language(const struct ast_channel *chan)
int ast_channel_setoption(struct ast_channel *channel, int option, void *data, int datalen, int block)
Sets an option on a channel.
Definition channel.c:7458
#define ast_channel_cleanup(c)
Cleanup a channel reference.
Definition channel.h:3030
int ast_answer(struct ast_channel *chan)
Answer a channel.
Definition channel.c:2805
struct ast_channel_iterator * ast_channel_iterator_all_new(void)
Create a new channel iterator.
Definition channel.c:1380
#define ast_channel_unlock(chan)
Definition channel.h:2984
ast_channel_state
ast_channel states
@ AST_STATE_UP
char * end
Definition eagi_proxy.c:73
void write_buf(int file, char *buffer, int num)
Definition eagi_proxy.c:312
Call Parking and Pickup API Includes code and algorithms from the Zapata library.
Generic File Format Support. Should be included by clients of the file handling routines....
int ast_streamfile(struct ast_channel *c, const char *filename, const char *preflang)
Streams a file.
Definition file.c:1320
int ast_fileexists(const char *filename, const char *fmt, const char *preflang)
Checks for the existence of a given file.
Definition file.c:1156
int ast_waitstream(struct ast_channel *c, const char *breakon)
Waits for a stream to stop or digit to be pressed.
Definition file.c:1882
Media Format Cache API.
struct ast_format * ast_format_slin
Built-in cached signed linear 8kHz format.
struct ast_format * ast_format_cache_get_slin_by_rate(unsigned int rate)
Retrieve the best signed linear format given a sample rate.
static const char name[]
Definition format_mp3.c:68
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
struct ast_multi_channel_blob * ast_multi_channel_blob_create(struct ast_json *blob)
Create a ast_multi_channel_blob suitable for a stasis_message.
struct stasis_message_type * ast_channel_chanspy_start_type(void)
Message type for when a channel starts spying on another channel.
struct stasis_message_type * ast_channel_chanspy_stop_type(void)
Message type for when a channel stops spying on another channel.
struct ast_channel_snapshot * ast_channel_snapshot_get_latest(const char *uniqueid)
Obtain the latest ast_channel_snapshot from the Stasis Message Bus API cache. This is an ao2 object,...
void ast_multi_channel_blob_add_channel(struct ast_multi_channel_blob *obj, const char *role, struct ast_channel_snapshot *snapshot)
Add a ast_channel_snapshot to a ast_multi_channel_blob object.
const char * ext
Definition http.c:151
Application convenience functions, designed to give consistent look and feel to Asterisk apps.
#define AST_APP_ARG(name)
Define an application argument.
#define AST_APP_OPTIONS(holder, options...)
Declares an array of options for an application.
#define ast_app_separate_args(a, b, c, d)
#define AST_APP_OPTION_ARG(option, flagno, argno)
Declares an application option that accepts an argument.
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
int ast_app_sayname(struct ast_channel *chan, const char *mailbox_id)
Play a recorded user name for the mailbox to the specified channel.
Definition main/app.c:637
#define AST_APP_OPTION(option, flagno)
Declares an application option that does not accept an argument.
int ast_app_parse_options(const struct ast_app_option *options, struct ast_flags *flags, char **args, char *optstr)
Parses a string containing application options and sets flags/arguments.
Definition main/app.c:3067
#define AST_FRAME_DTMF
void ast_frame_free(struct ast_frame *frame, int cache)
Frees a frame or list of frames.
Definition main/frame.c:176
#define ast_frdup(fr)
Copies a frame.
#define ast_frfree(fr)
#define AST_OPTION_TXGAIN
#define AST_LOG_WARNING
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_ERROR
#define ast_verb(level,...)
#define LOG_NOTICE
#define LOG_WARNING
Asterisk JSON abstraction layer.
struct ast_json * ast_json_null(void)
Get the JSON null value.
Definition json.c:248
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition json.c:73
#define AST_LIST_NEXT(elm, field)
Returns the next entry in the list after the given entry.
Asterisk locking-related definitions:
int errno
The AMI - Asterisk Manager Interface - is a TCP protocol created to manage Asterisk with third-party ...
Asterisk module definitions.
#define AST_MODULE_INFO_STANDARD(keystr, desc)
Definition module.h:581
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition module.h:46
int ast_unregister_application(const char *app)
Unregister an application.
Definition pbx_app.c:404
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition module.h:640
Options provided by main asterisk program.
Asterisk file paths, configured in asterisk.conf.
const char * ast_config_AST_MONITOR_DIR
Definition options.c:156
Core PBX routines and definitions.
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name.
int ast_goto_if_exists(struct ast_channel *chan, const char *context, const char *exten, int priority)
Definition pbx.c:6939
static struct @523 args
#define NULL
Definition resample.c:96
Say numbers and dates (maybe words one day too)
int ast_say_character_str(struct ast_channel *chan, const char *num, const char *ints, const char *lang, enum ast_say_case_sensitivity sensitivity)
function to pronounce character and phonetic strings
Definition channel.c:8447
int ast_say_digits(struct ast_channel *chan, int num, const char *ints, const char *lang)
says digits
Definition channel.c:8429
@ AST_SAY_CASE_NONE
Definition say.h:182
struct stasis_message * stasis_message_create(struct stasis_message_type *type, void *data)
Create a new message.
void stasis_publish(struct stasis_topic *topic, struct stasis_message *message)
Publish a message to a topic's subscribers.
Definition stasis.c:1589
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one.
Definition strings.h:80
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition strings.h:65
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition strings.h:425
struct ast_audiohook_options options
Definition audiohook.h:119
enum ast_audiohook_status status
Definition audiohook.h:108
struct ast_channel * chan
Definition autochan.h:33
struct ast_autochan * next
Definition autochan.h:34
Structure representing a snapshot of channel state.
Main Channel structure associated with a channel.
char exten[AST_MAX_EXTENSION]
const char * data
char context[AST_MAX_CONTEXT]
struct ast_flags flags
Structure used to handle boolean flags.
Definition utils.h:220
unsigned int flags
Definition utils.h:221
Definition of a media format.
Definition format.c:43
struct ast_format * format
Data structure associated with a single frame of data.
struct ast_frame_subclass subclass
enum ast_frame_type frametype
union ast_frame::@237 data
void *(* alloc)(struct ast_channel *chan, void *params)
Definition channel.h:228
Abstract JSON element (object, array, string, int, ...).
A multi channel blob data structure for multi_channel_blob stasis messages.
struct ast_audiohook bridge_whisper_audiohook
struct ast_audiohook whisper_audiohook
struct ast_audiohook spy_audiohook
static struct test_options options
static struct test_val c
Support for translation of data formats. translate.c.
Utility functions.
#define ast_test_flag(p, flag)
Definition utils.h:64
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition utils.h:981
#define ast_clear_flag(p, flag)
Definition utils.h:78
#define ast_set_flag(p, flag)
Definition utils.h:71
#define ARRAY_LEN(a)
Definition utils.h:706
#define ast_copy_flags(dest, src, flagz)
Definition utils.h:85
#define AST_FLAGS_ALL
Definition utils.h:217