Asterisk - The Open Source Telephony Project GIT-master-a358458
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 <synopsis>
66 Listen to a channel, and optionally whisper into it.
67 </synopsis>
68 <syntax>
69 <parameter name="chanprefix" />
70 <parameter name="options">
71 <optionlist>
72 <option name="b">
73 <para>Only spy on channels involved in a bridged call.</para>
74 </option>
75 <option name="B">
76 <para>Instead of whispering on a single channel barge in on both
77 channels involved in the call.</para>
78 </option>
79 <option name="c">
80 <argument name="digit" required="true">
81 <para>Specify a DTMF digit that can be used to spy on the next available channel.</para>
82 </argument>
83 </option>
84 <option name="d">
85 <para>Override the typical numeric DTMF functionality and instead
86 use DTMF to switch between spy modes.</para>
87 <enumlist>
88 <enum name="4">
89 <para>spy mode</para>
90 </enum>
91 <enum name="5">
92 <para>whisper mode</para>
93 </enum>
94 <enum name="6">
95 <para>barge mode</para>
96 </enum>
97 </enumlist>
98 </option>
99 <option name="e">
100 <argument name="ext" required="true" />
101 <para>Enable <emphasis>enforced</emphasis> mode, so the spying channel can
102 only monitor extensions whose name is in the <replaceable>ext</replaceable> : delimited
103 list.</para>
104 </option>
105 <option name="E">
106 <para>Exit when the spied-on channel hangs up.</para>
107 </option>
108 <option name="g">
109 <argument name="grp" required="true">
110 <para>Only spy on channels in which one or more of the groups
111 listed in <replaceable>grp</replaceable> matches one or more groups from the
112 <variable>SPYGROUP</variable> variable set on the channel to be spied upon.</para>
113 </argument>
114 <note><para>both <replaceable>grp</replaceable> and <variable>SPYGROUP</variable> can contain
115 either a single group or a colon-delimited list of groups, such
116 as <literal>sales:support:accounting</literal>.</para></note>
117 </option>
118 <option name="l">
119 <para>Allow usage of a long queue to store audio frames.</para>
120 <note><para>This may introduce some delay in the received audio feed, but will improve the audio quality.</para></note>
121 </option>
122 <option name="n" argsep="@">
123 <para>Say the name of the person being spied on if that person has recorded
124 his/her name. If a context is specified, then that voicemail context will
125 be searched when retrieving the name, otherwise the <literal>default</literal> context
126 be used when searching for the name (i.e. if SIP/1000 is the channel being
127 spied on and no mailbox is specified, then <literal>1000</literal> will be used when searching
128 for the name).</para>
129 <argument name="mailbox" />
130 <argument name="context" />
131 </option>
132 <option name="o">
133 <para>Only listen to audio coming from this channel.</para>
134 </option>
135 <option name="q">
136 <para>Don't play a beep when beginning to spy on a channel, or speak the
137 selected channel name.</para>
138 </option>
139 <option name="r">
140 <para>Record the session to the monitor spool directory. An optional base for the filename
141 may be specified. The default is <literal>chanspy</literal>.</para>
142 <argument name="basename" />
143 </option>
144 <option name="s">
145 <para>Skip the playback of the channel type (i.e. SIP, IAX, etc) when
146 speaking the selected channel name.</para>
147 </option>
148 <option name="S">
149 <para>Stop when no more channels are left to spy on.</para>
150 </option>
151 <option name="u">
152 <para>The <literal>chanprefix</literal> parameter is a channel uniqueid
153 or fully specified channel name.</para>
154 </option>
155 <option name="v">
156 <argument name="value" />
157 <para>Adjust the initial volume in the range from <literal>-4</literal>
158 to <literal>4</literal>. A negative value refers to a quieter setting.</para>
159 </option>
160 <option name="w">
161 <para>Enable <literal>whisper</literal> mode, so the spying channel can talk to
162 the spied-on channel.</para>
163 </option>
164 <option name="W">
165 <para>Enable <literal>private whisper</literal> mode, so the spying channel can
166 talk to the spied-on channel but cannot listen to that channel.</para>
167 </option>
168 <option name="x">
169 <argument name="digit" required="true">
170 <para>Specify a DTMF digit that can be used to exit the application while actively
171 spying on a channel. If there is no channel being spied on, the DTMF digit will be
172 ignored.</para>
173 </argument>
174 </option>
175 <option name="X">
176 <para>Allow the user to exit ChanSpy to a valid single digit
177 numeric extension in the current context or the context
178 specified by the <variable>SPY_EXIT_CONTEXT</variable> channel variable. The
179 name of the last channel that was spied on will be stored
180 in the <variable>SPY_CHANNEL</variable> variable.</para>
181 </option>
182 </optionlist>
183 </parameter>
184 </syntax>
185 <description>
186 <para>This application is used to listen to the audio from an Asterisk channel. This includes the audio
187 coming in and out of the channel being spied on. If the <literal>chanprefix</literal> parameter is specified,
188 only channels beginning with this string will be spied upon.</para>
189 <para>While spying, the following actions may be performed:</para>
190 <para> - Dialing <literal>#</literal> cycles the volume level.</para>
191 <para> - Dialing <literal>*</literal> will stop spying and look for another channel to spy on.</para>
192 <para> - Dialing a series of digits followed by <literal>#</literal> builds a channel name to append
193 to <literal>chanprefix</literal>. For example, executing ChanSpy(Agent) and then dialing the digits '1234#'
194 while spying will begin spying on the channel 'Agent/1234'. Note that this feature will be overridden
195 if the 'd' or 'u' options are used.</para>
196 <note><para>The <replaceable>X</replaceable> option supersedes the three features above in that if a valid
197 single digit extension exists in the correct context ChanSpy will exit to it.
198 This also disables choosing a channel based on <literal>chanprefix</literal> and a digit sequence.</para></note>
199 </description>
200 <see-also>
201 <ref type="application">ExtenSpy</ref>
202 <ref type="managerEvent">ChanSpyStart</ref>
203 <ref type="managerEvent">ChanSpyStop</ref>
204 </see-also>
205 </application>
206 <application name="ExtenSpy" language="en_US">
207 <synopsis>
208 Listen to a channel, and optionally whisper into it.
209 </synopsis>
210 <syntax>
211 <parameter name="exten" required="true" argsep="@">
212 <argument name="exten" required="true">
213 <para>Specify extension.</para>
214 </argument>
215 <argument name="context">
216 <para>Optionally specify a context, defaults to <literal>default</literal>.</para>
217 </argument>
218 </parameter>
219 <parameter name="options">
220 <optionlist>
221 <option name="b">
222 <para>Only spy on channels involved in a bridged call.</para>
223 </option>
224 <option name="B">
225 <para>Instead of whispering on a single channel barge in on both
226 channels involved in the call.</para>
227 </option>
228 <option name="c">
229 <argument name="digit" required="true">
230 <para>Specify a DTMF digit that can be used to spy on the next available channel.</para>
231 </argument>
232 </option>
233 <option name="d">
234 <para>Override the typical numeric DTMF functionality and instead
235 use DTMF to switch between spy modes.</para>
236 <enumlist>
237 <enum name="4">
238 <para>spy mode</para>
239 </enum>
240 <enum name="5">
241 <para>whisper mode</para>
242 </enum>
243 <enum name="6">
244 <para>barge mode</para>
245 </enum>
246 </enumlist>
247 </option>
248 <option name="D">
249 <para>Interleave the audio coming from the channel and the audio coming to the channel in
250 the output audio as a dual channel stream, rather than mix it. Does nothing if 'o'
251 is also set.</para>
252 </option>
253 <option name="e">
254 <argument name="ext" required="true" />
255 <para>Enable <emphasis>enforced</emphasis> mode, so the spying channel can
256 only monitor extensions whose name is in the <replaceable>ext</replaceable> : delimited
257 list.</para>
258 </option>
259 <option name="E">
260 <para>Exit when the spied-on channel hangs up.</para>
261 </option>
262 <option name="g">
263 <argument name="grp" required="true">
264 <para>Only spy on channels in which one or more of the groups
265 listed in <replaceable>grp</replaceable> matches one or more groups from the
266 <variable>SPYGROUP</variable> variable set on the channel to be spied upon.</para>
267 </argument>
268 <note><para>both <replaceable>grp</replaceable> and <variable>SPYGROUP</variable> can contain
269 either a single group or a colon-delimited list of groups, such
270 as <literal>sales:support:accounting</literal>.</para></note>
271 </option>
272 <option name="l">
273 <para>Allow usage of a long queue to store audio frames.</para>
274 <note><para>This may introduce some delay in the received audio feed, but will improve the audio quality.</para></note>
275 </option>
276 <option name="n" argsep="@">
277 <para>Say the name of the person being spied on if that person has recorded
278 his/her name. If a context is specified, then that voicemail context will
279 be searched when retrieving the name, otherwise the <literal>default</literal> context
280 be used when searching for the name (i.e. if SIP/1000 is the channel being
281 spied on and no mailbox is specified, then <literal>1000</literal> will be used when searching
282 for the name).</para>
283 <argument name="mailbox" />
284 <argument name="context" />
285 </option>
286 <option name="o">
287 <para>Only listen to audio coming from this channel.</para>
288 </option>
289 <option name="q">
290 <para>Don't play a beep when beginning to spy on a channel, or speak the
291 selected channel name.</para>
292 </option>
293 <option name="r">
294 <para>Record the session to the monitor spool directory. An optional base for the filename
295 may be specified. The default is <literal>chanspy</literal>.</para>
296 <argument name="basename" />
297 </option>
298 <option name="s">
299 <para>Skip the playback of the channel type (i.e. SIP, IAX, etc) when
300 speaking the selected channel name.</para>
301 </option>
302 <option name="S">
303 <para>Stop when there are no more extensions left to spy on.</para>
304 </option>
305 <option name="v">
306 <argument name="value" />
307 <para>Adjust the initial volume in the range from <literal>-4</literal>
308 to <literal>4</literal>. A negative value refers to a quieter setting.</para>
309 </option>
310 <option name="w">
311 <para>Enable <literal>whisper</literal> mode, so the spying channel can talk to
312 the spied-on channel.</para>
313 </option>
314 <option name="W">
315 <para>Enable <literal>private whisper</literal> mode, so the spying channel can
316 talk to the spied-on channel but cannot listen to that channel.</para>
317 </option>
318 <option name="x">
319 <argument name="digit" required="true">
320 <para>Specify a DTMF digit that can be used to exit the application while actively
321 spying on a channel. If there is no channel being spied on, the DTMF digit will be
322 ignored.</para>
323 </argument>
324 </option>
325 <option name="X">
326 <para>Allow the user to exit ChanSpy to a valid single digit
327 numeric extension in the current context or the context
328 specified by the <variable>SPY_EXIT_CONTEXT</variable> channel variable. The
329 name of the last channel that was spied on will be stored
330 in the <variable>SPY_CHANNEL</variable> variable.</para>
331 </option>
332 </optionlist>
333 </parameter>
334 </syntax>
335 <description>
336 <para>This application is used to listen to the audio from an Asterisk channel. This includes
337 the audio coming in and out of the channel being spied on. Only channels created by outgoing calls for the
338 specified extension will be selected for spying. If the optional context is not supplied,
339 the current channel's context will be used.</para>
340 <para>While spying, the following actions may be performed:</para>
341 <para> - Dialing <literal>#</literal> cycles the volume level.</para>
342 <para> - Dialing <literal>*</literal> will stop spying and look for another channel to spy on.</para>
343 <note><para>The <replaceable>X</replaceable> option supersedes the three features above in that if a valid
344 single digit extension exists in the correct context ChanSpy will exit to it.
345 This also disables choosing a channel based on <literal>chanprefix</literal> and a digit sequence.</para></note>
346 </description>
347 <see-also>
348 <ref type="application">ChanSpy</ref>
349 <ref type="managerEvent">ChanSpyStart</ref>
350 <ref type="managerEvent">ChanSpyStop</ref>
351 </see-also>
352 </application>
353 <application name="DAHDIScan" language="en_US">
354 <synopsis>
355 Scan DAHDI channels to monitor calls.
356 </synopsis>
357 <syntax>
358 <parameter name="group">
359 <para>Limit scanning to a channel <replaceable>group</replaceable> by setting this option.</para>
360 </parameter>
361 </syntax>
362 <description>
363 <para>Allows a call center manager to monitor DAHDI channels in a
364 convenient way. Use <literal>#</literal> to select the next channel and use <literal>*</literal> to exit.</para>
365 </description>
366 <see-also>
367 <ref type="managerEvent">ChanSpyStart</ref>
368 <ref type="managerEvent">ChanSpyStop</ref>
369 </see-also>
370 </application>
371 ***/
372
373static const char app_chan[] = "ChanSpy";
374
375static const char app_ext[] = "ExtenSpy";
376
377static const char app_dahdiscan[] = "DAHDIScan";
378
379enum {
380 OPTION_QUIET = (1 << 0), /* Quiet, no announcement */
381 OPTION_BRIDGED = (1 << 1), /* Only look at bridged calls */
382 OPTION_VOLUME = (1 << 2), /* Specify initial volume */
383 OPTION_GROUP = (1 << 3), /* Only look at channels in group */
384 OPTION_RECORD = (1 << 4),
385 OPTION_WHISPER = (1 << 5),
386 OPTION_PRIVATE = (1 << 6), /* Private Whisper mode */
387 OPTION_READONLY = (1 << 7), /* Don't mix the two channels */
388 OPTION_EXIT = (1 << 8), /* Exit to a valid single digit extension */
389 OPTION_ENFORCED = (1 << 9), /* Enforced mode */
390 OPTION_NOTECH = (1 << 10), /* Skip technology name playback */
391 OPTION_BARGE = (1 << 11), /* Barge mode (whisper to both channels) */
392 OPTION_NAME = (1 << 12), /* Say the name of the person on whom we will spy */
393 OPTION_DTMF_SWITCH_MODES = (1 << 13), /* Allow numeric DTMF to switch between chanspy modes */
394 OPTION_DTMF_EXIT = (1 << 14), /* Set DTMF to exit, added for DAHDIScan integration */
395 OPTION_DTMF_CYCLE = (1 << 15), /* Custom DTMF for cycling next available channel, (default is '*') */
396 OPTION_DAHDI_SCAN = (1 << 16), /* Scan groups in DAHDIScan mode */
397 OPTION_STOP = (1 << 17),
398 OPTION_EXITONHANGUP = (1 << 18), /* Hang up when the spied-on channel hangs up. */
399 OPTION_UNIQUEID = (1 << 19), /* The chanprefix is a channel uniqueid or fully specified channel name. */
400 OPTION_LONG_QUEUE = (1 << 20), /* Allow usage of a long queue to store audio frames. */
401 OPTION_INTERLEAVED = (1 << 21), /* Interleave the Read and Write frames in the output frame. */
402};
403
404enum {
413};
414
437});
438
440 /* spy data */
444 int fd;
447};
448
450 char exit;
451 char cycle;
452 char volume;
453};
454
455static void *spy_alloc(struct ast_channel *chan, void *data)
456{
457 /* just store the data pointer in the channel structure */
458 return data;
459}
460
461static void spy_release(struct ast_channel *chan, void *data)
462{
463 /* nothing to do */
464}
465
466static int spy_generate(struct ast_channel *chan, void *data, int len, int samples)
467{
468 struct chanspy_translation_helper *csth = data;
469 struct ast_frame *f, *cur;
470
473 /* Channel is already gone more than likely */
475 return -1;
476 }
477
478 if (ast_test_flag(&csth->flags, OPTION_READONLY)) {
479 /* Option 'o' was set, so don't mix channel audio */
481 } else if (ast_test_flag(&csth->flags, OPTION_INTERLEAVED)) {
482 /* Option 'D' was set, so mix the spy frame as an interleaved dual channel frame. */
483 int i;
484 struct ast_frame *fr_read = NULL;
485 struct ast_frame *fr_write = NULL;
486 short read_buf[samples];
487 short write_buf[samples];
488 short stereo_buf[samples * 2];
489 struct ast_frame stereo_frame = {
491 .datalen = sizeof(stereo_buf),
492 .samples = samples,
493 };
494
495 f = ast_audiohook_read_frame_all(&csth->spy_audiohook, samples, ast_format_slin, &fr_read, &fr_write);
496 if (f) {
497 ast_frame_free(f, 0);
498 f = NULL;
499 }
500
501 if (fr_read) {
502 memcpy(read_buf, fr_read->data.ptr, sizeof(read_buf));
503 } else {
504 /* silent out the output frame if we can't read the input */
505 memset(read_buf, 0, sizeof(read_buf));
506 }
507
508 if (fr_write) {
509 memcpy(write_buf, fr_write->data.ptr, sizeof(write_buf));
510 } else {
511 memset(write_buf, 0, sizeof(write_buf));
512 }
513
514 for (i = 0; i < samples; i++) {
515 stereo_buf[i*2] = read_buf[i];
516 stereo_buf[i*2+1] = write_buf[i];
517 }
518
519 stereo_frame.data.ptr = stereo_buf;
521
522 f = ast_frdup(&stereo_frame);
523
524 if (fr_read) {
525 ast_frame_free(fr_read, 0);
526 }
527 if (fr_write) {
528 ast_frame_free(fr_write, 0);
529 }
530
531 } else {
533 }
534
536
537 if (!f)
538 return 0;
539
540 for (cur = f; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
541 if (ast_write(chan, cur)) {
542 ast_frfree(f);
543 return -1;
544 }
545
546 if (csth->fd) {
547 if (write(csth->fd, cur->data.ptr, cur->datalen) < 0) {
548 ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
549 }
550 }
551 }
552
553 ast_frfree(f);
554
555 return 0;
556}
557
558static struct ast_generator spygen = {
559 .alloc = spy_alloc,
560 .release = spy_release,
561 .generate = spy_generate,
562};
563
564static int start_spying(struct ast_autochan *autochan, const char *spychan_name, struct ast_audiohook *audiohook, struct ast_flags *flags)
565{
566 int res;
567
569 ast_verb(3, "Attaching spy channel %s to %s\n",
570 spychan_name, ast_channel_name(autochan->chan));
571
572 if (ast_test_flag(flags, OPTION_READONLY)) {
574 } else {
576 }
577 if (ast_test_flag(flags, OPTION_LONG_QUEUE)) {
578 ast_debug(9, "Using a long queue to store audio frames in spy audiohook\n");
579 } else {
581 }
582 res = ast_audiohook_attach(autochan->chan, audiohook);
584 return res;
585}
586
587static void change_spy_mode(const char digit, struct ast_flags *flags)
588{
589 if (digit == '4') {
592 } else if (digit == '5') {
595 } else if (digit == '6') {
598 }
599}
600
601static int pack_channel_into_message(struct ast_channel *chan, const char *role,
602 struct ast_multi_channel_blob *payload)
603{
604 RAII_VAR(struct ast_channel_snapshot *, snapshot,
607
608 if (!snapshot) {
609 return -1;
610 }
611 ast_multi_channel_blob_add_channel(payload, role, snapshot);
612 return 0;
613}
614
615/*! \internal
616 * \brief Publish the chanspy message over Stasis-Core
617 * \param spyer The channel doing the spying
618 * \param spyee Who is being spied upon
619 * \param start If non-zero, the spying is starting. Otherwise, the spyer is
620 * finishing
621 */
622static void publish_chanspy_message(struct ast_channel *spyer,
623 struct ast_channel *spyee,
624 int start)
625{
626 RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
627 RAII_VAR(struct ast_multi_channel_blob *, payload, NULL, ao2_cleanup);
630
631 if (!spyer) {
632 ast_log(AST_LOG_WARNING, "Attempt to publish ChanSpy message for NULL spyer channel\n");
633 return;
634 }
635 blob = ast_json_null();
636 if (!blob || !type) {
637 return;
638 }
639
640 payload = ast_multi_channel_blob_create(blob);
641 if (!payload) {
642 return;
643 }
644
645 if (pack_channel_into_message(spyer, "spyer_channel", payload)) {
646 return;
647 }
648
649 if (spyee) {
650 if (pack_channel_into_message(spyee, "spyee_channel", payload)) {
651 return;
652 }
653 }
654
656 if (!message) {
657 return;
658 }
660}
661
662static int attach_barge(struct ast_autochan *spyee_autochan,
663 struct ast_autochan **spyee_bridge_autochan, struct ast_audiohook *bridge_whisper_audiohook,
664 const char *spyer_name, const char *name, struct ast_flags *flags)
665{
666 int retval = 0;
667 struct ast_autochan *internal_bridge_autochan;
668 struct ast_channel *spyee_chan;
669 RAII_VAR(struct ast_channel *, bridged, NULL, ast_channel_cleanup);
670
671 ast_autochan_channel_lock(spyee_autochan);
672 spyee_chan = ast_channel_ref(spyee_autochan->chan);
673 ast_autochan_channel_unlock(spyee_autochan);
674 bridged = ast_channel_bridge_peer(spyee_chan);
675 ast_channel_unref(spyee_chan);
676 if (!bridged) {
677 return -1;
678 }
679
680 ast_audiohook_init(bridge_whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "Chanspy", 0);
681
682 internal_bridge_autochan = ast_autochan_setup(bridged);
683 if (!internal_bridge_autochan) {
684 return -1;
685 }
686
687 if (start_spying(internal_bridge_autochan, spyer_name, bridge_whisper_audiohook, flags)) {
688 ast_log(LOG_WARNING, "Unable to attach barge audiohook on spyee '%s'. Barge mode disabled.\n", name);
689 retval = -1;
690 }
691
692 *spyee_bridge_autochan = internal_bridge_autochan;
693
694 return retval;
695}
696
697static int channel_spy(struct ast_channel *chan, struct ast_autochan *spyee_autochan,
698 int *volfactor, int fd, struct spy_dtmf_options *user_options, struct ast_flags *flags,
699 char *exitcontext)
700{
701 struct chanspy_translation_helper csth;
702 int running = 0, bridge_connected = 0, res, x = 0;
703 char inp[24] = {0};
704 char *name;
705 struct ast_frame *f;
706 struct ast_silence_generator *silgen = NULL;
707 struct ast_autochan *spyee_bridge_autochan = NULL;
708 const char *spyer_name;
709
711 if (ast_check_hangup(chan)) {
713 return 0;
714 }
715 spyer_name = ast_strdupa(ast_channel_name(chan));
717
718 ast_autochan_channel_lock(spyee_autochan);
719 if (ast_check_hangup(spyee_autochan->chan)
720 || ast_test_flag(ast_channel_flags(spyee_autochan->chan), AST_FLAG_ZOMBIE)) {
721 ast_autochan_channel_unlock(spyee_autochan);
722 return 0;
723 }
724 name = ast_strdupa(ast_channel_name(spyee_autochan->chan));
725
726 ast_verb(2, "Spying on channel %s\n", name);
727 publish_chanspy_message(chan, spyee_autochan->chan, 1);
728 ast_autochan_channel_unlock(spyee_autochan);
729
730 memset(&csth, 0, sizeof(csth));
731 ast_copy_flags(&csth.flags, flags, AST_FLAGS_ALL);
732
733 /* This is the audiohook which gives us the audio off the channel we are
734 spying on.
735 */
737
738 if (start_spying(spyee_autochan, spyer_name, &csth.spy_audiohook, flags)) {
740 return 0;
741 }
742
744 /* This audiohook will let us inject audio from our channel into the
745 channel we are currently spying on.
746 */
748
749 if (start_spying(spyee_autochan, spyer_name, &csth.whisper_audiohook, flags)) {
750 ast_log(LOG_WARNING, "Unable to attach whisper audiohook to spyee %s. Whisper mode disabled!\n", name);
751 }
752 }
753
755
756 csth.volfactor = *volfactor;
757
758 if (csth.volfactor) {
761 }
762
763 csth.fd = fd;
764
765 if (ast_test_flag(flags, OPTION_PRIVATE))
767 else
769
770 /* We can no longer rely on 'spyee' being an actual channel;
771 it can be hung up and freed out from under us. However, the
772 channel destructor will put NULL into our csth.spy.chan
773 field when that happens, so that is our signal that the spyee
774 channel has gone away.
775 */
776
777 /* Note: it is very important that the ast_waitfor() be the first
778 condition in this expression, so that if we wait for some period
779 of time before receiving a frame from our spying channel, we check
780 for hangup on the spied-on channel _after_ knowing that a frame
781 has arrived, since the spied-on channel could have gone away while
782 we were waiting
783 */
785 if (!(f = ast_read(chan)) || ast_check_hangup(chan)) {
786 running = -1;
787 if (f) {
788 ast_frfree(f);
789 }
790 break;
791 }
792
794 /* This hook lets us inject audio into the channel that the spyee is currently
795 * bridged with. If the spyee isn't bridged with anything yet, nothing will
796 * be attached and we'll need to continue attempting to attach the barge
797 * audio hook. */
798 if (!bridge_connected && attach_barge(spyee_autochan, &spyee_bridge_autochan,
799 &csth.bridge_whisper_audiohook, spyer_name, name, flags) == 0) {
800 bridge_connected = 1;
801 }
802
806
807 if (bridge_connected) {
811 }
812
813 ast_frfree(f);
814 continue;
815 } else if (ast_test_flag(flags, OPTION_WHISPER) && f->frametype == AST_FRAME_VOICE) {
819 ast_frfree(f);
820 continue;
821 }
822
823 res = (f->frametype == AST_FRAME_DTMF) ? f->subclass.integer : 0;
824 ast_frfree(f);
825 if (!res)
826 continue;
827
828 if (x == sizeof(inp))
829 x = 0;
830
831 if (res < 0) {
832 running = -1;
833 break;
834 }
835
836 if (ast_test_flag(flags, OPTION_EXIT)) {
837 char tmp[2];
838 tmp[0] = res;
839 tmp[1] = '\0';
841 ast_debug(1, "Got DTMF %c, goto context %s\n", tmp[0], exitcontext);
842 pbx_builtin_setvar_helper(chan, "SPY_CHANNEL", name);
843 running = -2;
844 break;
845 } else {
846 ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
847 }
848 } else if (res >= '0' && res <= '9') {
850 change_spy_mode(res, flags);
851 } else {
852 inp[x++] = res;
853 }
854 }
855
856 if (res == user_options->cycle) {
857 running = 0;
858 break;
859 } else if (res == user_options->exit) {
860 running = -2;
861 break;
862 } else if (res == user_options->volume) {
863 if (!ast_strlen_zero(inp)) {
864 running = atoi(inp);
865 break;
866 }
867
868 (*volfactor)++;
869 if (*volfactor > 4)
870 *volfactor = -4;
871 ast_verb(3, "Setting spy volume on %s to %d\n", ast_channel_name(chan), *volfactor);
872
873 csth.volfactor = *volfactor;
876 }
877 }
878
879 if (ast_test_flag(flags, OPTION_PRIVATE))
881 else
883
885
891 }
892
898 }
899
904
905 ast_verb(2, "Done Spying on channel %s\n", name);
906 publish_chanspy_message(chan, spyee_autochan->chan, 0);
907
908 if (spyee_bridge_autochan) {
909 ast_autochan_destroy(spyee_bridge_autochan);
910 }
911
912 return running;
913}
914
916 struct ast_channel *chan)
917{
918 struct ast_channel *next;
919 struct ast_autochan *autochan_store;
920 const size_t pseudo_len = strlen("DAHDI/pseudo");
921
922 if (!iter) {
923 return NULL;
924 }
925
927 if (!strncmp(ast_channel_name(next), "DAHDI/pseudo", pseudo_len)
928 || next == chan) {
929 continue;
930 }
931
932 autochan_store = ast_autochan_setup(next);
934
935 return autochan_store;
936 }
937 return NULL;
938}
939
940static int spy_sayname(struct ast_channel *chan, const char *mailbox, const char *context)
941{
942 char *mailbox_id;
943
944 mailbox_id = ast_alloca(strlen(mailbox) + strlen(context) + 2);
945 sprintf(mailbox_id, "%s@%s", mailbox, context); /* Safe */
946 return ast_app_sayname(chan, mailbox_id);
947}
948
949static int common_exec(struct ast_channel *chan, struct ast_flags *flags,
950 int volfactor, const int fd, struct spy_dtmf_options *user_options,
951 const char *mygroup, const char *myenforced, const char *spec, const char *exten,
952 const char *context, const char *mailbox, const char *name_context)
953{
954 char nameprefix[AST_NAME_STRLEN];
955 char exitcontext[AST_MAX_CONTEXT] = "";
956 signed char zero_volume = 0;
957 int waitms;
958 int res;
959 int num_spied_upon = 1;
960 struct ast_channel_iterator *iter = NULL;
961
962 if (ast_test_flag(flags, OPTION_EXIT)) {
963 const char *c;
964 ast_channel_lock(chan);
965 if ((c = pbx_builtin_getvar_helper(chan, "SPY_EXIT_CONTEXT"))) {
967 } else {
969 }
970 ast_channel_unlock(chan);
971 }
972
973 if (ast_channel_state(chan) != AST_STATE_UP)
974 ast_answer(chan);
975
977
978 waitms = 100;
979
980 for (;;) {
981 struct ast_autochan *autochan = NULL, *next_autochan = NULL;
982 struct ast_channel *prev = NULL;
983
984 if (!ast_test_flag(flags, OPTION_QUIET) && num_spied_upon) {
985 res = ast_streamfile(chan, "beep", ast_channel_language(chan));
986 if (!res)
987 res = ast_waitstream(chan, "");
988 else if (res < 0) {
990 break;
991 }
993 char tmp[2];
994 tmp[0] = res;
995 tmp[1] = '\0';
996 if (!ast_goto_if_exists(chan, exitcontext, tmp, 1))
997 goto exit;
998 else
999 ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
1000 }
1001 }
1002
1003 /* Set up the iterator we'll be using during this call */
1004 if (!ast_strlen_zero(spec)) {
1006 struct ast_channel *unique_chan;
1007
1008 unique_chan = ast_channel_get_by_name(spec);
1009 if (!unique_chan) {
1010 res = -1;
1011 goto exit;
1012 }
1013 iter = ast_channel_iterator_by_name_new(ast_channel_name(unique_chan), 0);
1014 ast_channel_unref(unique_chan);
1015 } else {
1016 iter = ast_channel_iterator_by_name_new(spec, strlen(spec));
1017 }
1018 } else if (!ast_strlen_zero(exten)) {
1020 } else {
1022 }
1023
1024 if (!iter) {
1025 res = -1;
1026 goto exit;
1027 }
1028
1029 res = ast_waitfordigit(chan, waitms);
1030 if (res < 0) {
1031 iter = ast_channel_iterator_destroy(iter);
1033 break;
1034 }
1036 char tmp[2];
1037 tmp[0] = res;
1038 tmp[1] = '\0';
1039 if (!ast_goto_if_exists(chan, exitcontext, tmp, 1)) {
1040 iter = ast_channel_iterator_destroy(iter);
1041 goto exit;
1042 } else {
1043 ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
1044 }
1045 }
1046
1047 /* reset for the next loop around, unless overridden later */
1048 waitms = 100;
1049 num_spied_upon = 0;
1050
1051 for (autochan = next_channel(iter, chan);
1052 autochan;
1053 prev = autochan->chan,
1054 ast_autochan_destroy(autochan),
1055 autochan = next_autochan ?: next_channel(iter, chan),
1056 next_autochan = NULL) {
1057 int igrp = !mygroup;
1058 int ienf = !myenforced;
1059
1060 if (autochan->chan == prev) {
1061 ast_autochan_destroy(autochan);
1062 break;
1063 }
1064
1065 if (ast_check_hangup(chan)) {
1066 ast_autochan_destroy(autochan);
1067 break;
1068 }
1069
1070 ast_autochan_channel_lock(autochan);
1072 && !ast_channel_is_bridged(autochan->chan)) {
1074 continue;
1075 }
1076
1077 if (ast_check_hangup(autochan->chan)
1080 continue;
1081 }
1083
1084 if (mygroup) {
1085 int num_groups = 0;
1086 int num_mygroups = 0;
1087 char dup_group[512];
1088 char dup_mygroup[512];
1089 char *groups[NUM_SPYGROUPS];
1090 char *mygroups[NUM_SPYGROUPS];
1091 const char *group = NULL;
1092 int x;
1093 int y;
1094 ast_copy_string(dup_mygroup, mygroup, sizeof(dup_mygroup));
1095 num_mygroups = ast_app_separate_args(dup_mygroup, ':', mygroups,
1096 ARRAY_LEN(mygroups));
1097
1098 /* Before dahdi scan was part of chanspy, it would use the "GROUP" variable
1099 * rather than "SPYGROUP", this check is done to preserve expected behavior */
1100 ast_autochan_channel_lock(autochan);
1102 group = pbx_builtin_getvar_helper(autochan->chan, "GROUP");
1103 } else {
1104 group = pbx_builtin_getvar_helper(autochan->chan, "SPYGROUP");
1105 }
1107
1108 if (!ast_strlen_zero(group)) {
1109 ast_copy_string(dup_group, group, sizeof(dup_group));
1110 num_groups = ast_app_separate_args(dup_group, ':', groups,
1111 ARRAY_LEN(groups));
1112 }
1113
1114 for (y = 0; y < num_mygroups; y++) {
1115 for (x = 0; x < num_groups; x++) {
1116 if (!strcmp(mygroups[y], groups[x])) {
1117 igrp = 1;
1118 break;
1119 }
1120 }
1121 }
1122 }
1123
1124 if (!igrp) {
1125 continue;
1126 }
1127 if (myenforced) {
1128 char ext[AST_CHANNEL_NAME + 3];
1129 char buffer[512];
1130 char *end;
1131
1132 snprintf(buffer, sizeof(buffer) - 1, ":%s:", myenforced);
1133
1134 ast_autochan_channel_lock(autochan);
1135 ast_copy_string(ext + 1, ast_channel_name(autochan->chan), sizeof(ext) - 1);
1137 if ((end = strchr(ext, '-'))) {
1138 *end++ = ':';
1139 *end = '\0';
1140 }
1141
1142 ext[0] = ':';
1143
1144 if (strcasestr(buffer, ext)) {
1145 ienf = 1;
1146 }
1147 }
1148
1149 if (!ienf) {
1150 continue;
1151 }
1152
1154 char peer_name[AST_NAME_STRLEN + 5];
1155 char *ptr, *s;
1156
1157 strcpy(peer_name, "spy-");
1158 ast_autochan_channel_lock(autochan);
1159 strncat(peer_name, ast_channel_name(autochan->chan), AST_NAME_STRLEN - 4 - 1);
1161 if ((ptr = strchr(peer_name, '/'))) {
1162 *ptr++ = '\0';
1163 for (s = peer_name; s < ptr; s++) {
1164 *s = tolower(*s);
1165 }
1166 if ((s = strchr(ptr, '-'))) {
1167 *s = '\0';
1168 }
1169 }
1170
1172 const char *local_context = S_OR(name_context, "default");
1173 const char *local_mailbox = S_OR(mailbox, ptr);
1174
1175 if (local_mailbox) {
1176 res = spy_sayname(chan, local_mailbox, local_context);
1177 } else {
1178 res = -1;
1179 }
1180 }
1181 if (!ast_test_flag(flags, OPTION_NAME) || res < 0) {
1182 int num;
1184 if (ast_fileexists(peer_name, NULL, NULL) > 0) {
1185 res = ast_streamfile(chan, peer_name, ast_channel_language(chan));
1186 if (!res) {
1187 res = ast_waitstream(chan, "");
1188 }
1189 if (res) {
1190 ast_autochan_destroy(autochan);
1191 break;
1192 }
1193 } else {
1194 res = ast_say_character_str(chan, peer_name, "", ast_channel_language(chan), AST_SAY_CASE_NONE);
1195 }
1196 }
1197 if (ptr && (num = atoi(ptr))) {
1198 ast_say_digits(chan, num, "", ast_channel_language(chan));
1199 }
1200 }
1201 }
1202
1203 res = channel_spy(chan, autochan, &volfactor, fd, user_options, flags, exitcontext);
1204 num_spied_upon++;
1205
1206 if (res == -1) {
1207 ast_autochan_destroy(autochan);
1208 iter = ast_channel_iterator_destroy(iter);
1209 goto exit;
1210 } else if (res == -2) {
1211 res = 0;
1212 ast_autochan_destroy(autochan);
1213 iter = ast_channel_iterator_destroy(iter);
1214 goto exit;
1215 } else if (res > 1 && spec && !ast_test_flag(flags, OPTION_UNIQUEID)) {
1216 struct ast_channel *next;
1217
1218 snprintf(nameprefix, AST_NAME_STRLEN, "%s/%d", spec, res);
1219
1220 if ((next = ast_channel_get_by_name_prefix(nameprefix, strlen(nameprefix)))) {
1221 next_autochan = ast_autochan_setup(next);
1222 next = ast_channel_unref(next);
1223 } else {
1224 /* stay on this channel, if it is still valid */
1225 ast_autochan_channel_lock(autochan);
1226 if (!ast_check_hangup(autochan->chan)) {
1227 next_autochan = ast_autochan_setup(autochan->chan);
1228 } else {
1229 /* the channel is gone */
1230 next_autochan = NULL;
1231 }
1233 }
1234 } else if (res == 0 && ast_test_flag(flags, OPTION_EXITONHANGUP)) {
1235 ast_autochan_destroy(autochan);
1236 iter = ast_channel_iterator_destroy(iter);
1237 goto exit;
1238 }
1239 }
1240
1241 iter = ast_channel_iterator_destroy(iter);
1242
1243 if (res == -1 || ast_check_hangup(chan))
1244 break;
1245 if (ast_test_flag(flags, OPTION_STOP) && !next_autochan) {
1246 break;
1247 }
1248 }
1249exit:
1250
1252
1253 ast_channel_setoption(chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);
1254
1255 return res;
1256}
1257
1258static int chanspy_exec(struct ast_channel *chan, const char *data)
1259{
1260 char *myenforced = NULL;
1261 char *mygroup = NULL;
1262 char *recbase = NULL;
1263 int fd = 0;
1264 struct ast_flags flags;
1265 struct spy_dtmf_options user_options = {
1266 .cycle = '*',
1267 .volume = '#',
1268 .exit = '\0',
1269 };
1270 RAII_VAR(struct ast_format *, oldwf, NULL, ao2_cleanup);
1271 int volfactor = 0;
1272 int res;
1273 char *mailbox = NULL;
1274 char *name_context = NULL;
1276 AST_APP_ARG(spec);
1278 );
1279 char *opts[OPT_ARG_ARRAY_SIZE];
1280 char *parse = ast_strdupa(data);
1281
1283
1284 if (args.spec && !strcmp(args.spec, "all"))
1285 args.spec = NULL;
1286
1287 if (args.options) {
1288 char tmp;
1289 ast_app_parse_options(spy_opts, &flags, opts, args.options);
1290 if (ast_test_flag(&flags, OPTION_GROUP))
1291 mygroup = opts[OPT_ARG_GROUP];
1292
1293 if (ast_test_flag(&flags, OPTION_RECORD) &&
1294 !(recbase = opts[OPT_ARG_RECORD]))
1295 recbase = "chanspy";
1296
1297 if (ast_test_flag(&flags, OPTION_DTMF_EXIT) && opts[OPT_ARG_EXIT]) {
1298 tmp = opts[OPT_ARG_EXIT][0];
1299 if (strchr("0123456789*#", tmp) && tmp != '\0') {
1300 user_options.exit = tmp;
1301 } else {
1302 ast_log(LOG_NOTICE, "Argument for option 'x' must be a valid DTMF digit.\n");
1303 }
1304 }
1305
1306 if (ast_test_flag(&flags, OPTION_DTMF_CYCLE) && opts[OPT_ARG_CYCLE]) {
1307 tmp = opts[OPT_ARG_CYCLE][0];
1308 if (strchr("0123456789*#", tmp) && tmp != '\0') {
1309 user_options.cycle = tmp;
1310 } else {
1311 ast_log(LOG_NOTICE, "Argument for option 'c' must be a valid DTMF digit.\n");
1312 }
1313 }
1314
1315 if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) {
1316 int vol;
1317
1318 if ((sscanf(opts[OPT_ARG_VOLUME], "%30d", &vol) != 1) || (vol > 4) || (vol < -4))
1319 ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n");
1320 else
1321 volfactor = vol;
1322 }
1323
1324 if (ast_test_flag(&flags, OPTION_PRIVATE))
1326
1327 if (ast_test_flag(&flags, OPTION_ENFORCED))
1328 myenforced = opts[OPT_ARG_ENFORCED];
1329
1330 if (ast_test_flag(&flags, OPTION_NAME)) {
1331 if (!ast_strlen_zero(opts[OPT_ARG_NAME])) {
1332 char *delimiter;
1333 if ((delimiter = strchr(opts[OPT_ARG_NAME], '@'))) {
1334 mailbox = opts[OPT_ARG_NAME];
1335 *delimiter++ = '\0';
1336 name_context = delimiter;
1337 } else {
1338 mailbox = opts[OPT_ARG_NAME];
1339 }
1340 }
1341 }
1342 } else {
1344 }
1345
1346 oldwf = ao2_bump(ast_channel_writeformat(chan));
1347 if (ast_set_write_format(chan, ast_format_slin) < 0) {
1348 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
1349 return -1;
1350 }
1351
1352 if (recbase) {
1353 char filename[PATH_MAX];
1354
1355 snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL));
1356 if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, AST_FILE_MODE)) <= 0) {
1357 ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename);
1358 fd = 0;
1359 }
1360 }
1361
1362 res = common_exec(chan, &flags, volfactor, fd, &user_options, mygroup, myenforced, args.spec, NULL, NULL, mailbox, name_context);
1363
1364 if (fd)
1365 close(fd);
1366
1367 if (oldwf && ast_set_write_format(chan, oldwf) < 0)
1368 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
1369
1370 if (ast_test_flag(&flags, OPTION_EXITONHANGUP)) {
1371 ast_verb(3, "Stopped spying due to the spied-on channel hanging up.\n");
1372 }
1373
1374 return res;
1375}
1376
1377static int extenspy_exec(struct ast_channel *chan, const char *data)
1378{
1379 char *ptr, *exten = NULL;
1380 char *mygroup = NULL;
1381 char *recbase = NULL;
1382 int fd = 0;
1383 struct ast_flags flags;
1384 struct spy_dtmf_options user_options = {
1385 .cycle = '*',
1386 .volume = '#',
1387 .exit = '\0',
1388 };
1389 RAII_VAR(struct ast_format *, oldwf, NULL, ao2_cleanup);
1390 int volfactor = 0;
1391 int res;
1392 char *mailbox = NULL;
1393 char *name_context = NULL;
1397 );
1398 char *parse = ast_strdupa(data);
1399
1401
1402 if (!ast_strlen_zero(args.context) && (ptr = strchr(args.context, '@'))) {
1403 exten = args.context;
1404 *ptr++ = '\0';
1405 args.context = ptr;
1406 }
1407 if (ast_strlen_zero(args.context))
1408 args.context = ast_strdupa(ast_channel_context(chan));
1409
1410 if (args.options) {
1411 char *opts[OPT_ARG_ARRAY_SIZE];
1412 char tmp;
1413
1414 ast_app_parse_options(spy_opts, &flags, opts, args.options);
1415 if (ast_test_flag(&flags, OPTION_GROUP))
1416 mygroup = opts[OPT_ARG_GROUP];
1417
1418 if (ast_test_flag(&flags, OPTION_RECORD) &&
1419 !(recbase = opts[OPT_ARG_RECORD]))
1420 recbase = "chanspy";
1421
1422 if (ast_test_flag(&flags, OPTION_DTMF_EXIT) && opts[OPT_ARG_EXIT]) {
1423 tmp = opts[OPT_ARG_EXIT][0];
1424 if (strchr("0123456789*#", tmp) && tmp != '\0') {
1425 user_options.exit = tmp;
1426 } else {
1427 ast_log(LOG_NOTICE, "Argument for option 'x' must be a valid DTMF digit.\n");
1428 }
1429 }
1430
1431 if (ast_test_flag(&flags, OPTION_DTMF_CYCLE) && opts[OPT_ARG_CYCLE]) {
1432 tmp = opts[OPT_ARG_CYCLE][0];
1433 if (strchr("0123456789*#", tmp) && tmp != '\0') {
1434 user_options.cycle = tmp;
1435 } else {
1436 ast_log(LOG_NOTICE, "Argument for option 'c' must be a valid DTMF digit.\n");
1437 }
1438 }
1439
1440 if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) {
1441 int vol;
1442
1443 if ((sscanf(opts[OPT_ARG_VOLUME], "%30d", &vol) != 1) || (vol > 4) || (vol < -4))
1444 ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n");
1445 else
1446 volfactor = vol;
1447 }
1448
1449 if (ast_test_flag(&flags, OPTION_PRIVATE))
1451
1452 if (ast_test_flag(&flags, OPTION_NAME)) {
1453 if (!ast_strlen_zero(opts[OPT_ARG_NAME])) {
1454 char *delimiter;
1455 if ((delimiter = strchr(opts[OPT_ARG_NAME], '@'))) {
1456 mailbox = opts[OPT_ARG_NAME];
1457 *delimiter++ = '\0';
1458 name_context = delimiter;
1459 } else {
1460 mailbox = opts[OPT_ARG_NAME];
1461 }
1462 }
1463 }
1464
1465 } else {
1466 /* Coverity - This uninit_use should be ignored since this macro initializes the flags */
1468 }
1469
1470 oldwf = ao2_bump(ast_channel_writeformat(chan));
1471 if (ast_set_write_format(chan, ast_format_slin) < 0) {
1472 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
1473 return -1;
1474 }
1475
1476 if (recbase) {
1477 char filename[PATH_MAX];
1478
1479 snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL));
1480 if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, AST_FILE_MODE)) <= 0) {
1481 ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename);
1482 fd = 0;
1483 }
1484 }
1485
1486
1487 res = common_exec(chan, &flags, volfactor, fd, &user_options, mygroup, NULL, NULL, exten, args.context, mailbox, name_context);
1488
1489 if (fd)
1490 close(fd);
1491
1492 if (oldwf && ast_set_write_format(chan, oldwf) < 0)
1493 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
1494
1495 return res;
1496}
1497
1498static int dahdiscan_exec(struct ast_channel *chan, const char *data)
1499{
1500 const char *spec = "DAHDI";
1501 struct ast_flags flags = {0};
1502 struct spy_dtmf_options user_options = {
1503 .cycle = '#',
1504 .volume = '\0',
1505 .exit = '*',
1506 };
1507 struct ast_format *oldwf;
1508 int res;
1509 char *mygroup = NULL;
1510
1511 /* Coverity - This uninit_use should be ignored since this macro initializes the flags */
1513
1514 if (!ast_strlen_zero(data)) {
1515 mygroup = ast_strdupa(data);
1516 }
1520
1521 oldwf = ao2_bump(ast_channel_writeformat(chan));
1522 if (ast_set_write_format(chan, ast_format_slin) < 0) {
1523 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
1524 ao2_cleanup(oldwf);
1525 return -1;
1526 }
1527
1528 res = common_exec(chan, &flags, 0, 0, &user_options, mygroup, NULL, spec, NULL, NULL, NULL, NULL);
1529
1530 if (oldwf && ast_set_write_format(chan, oldwf) < 0)
1531 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
1532 ao2_cleanup(oldwf);
1533
1534 return res;
1535}
1536
1537static int unload_module(void)
1538{
1539 int res = 0;
1540
1544
1545 return res;
1546}
1547
1548static int load_module(void)
1549{
1550 int res = 0;
1551
1555
1556 return res;
1557}
1558
1559AST_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)
Definition: app_chanspy.c:940
#define NUM_SPYGROUPS
Definition: app_chanspy.c:61
static int chanspy_exec(struct ast_channel *chan, const char *data)
Definition: app_chanspy.c:1258
static void publish_chanspy_message(struct ast_channel *spyer, struct ast_channel *spyee, int start)
Definition: app_chanspy.c:622
static int pack_channel_into_message(struct ast_channel *chan, const char *role, struct ast_multi_channel_blob *payload)
Definition: app_chanspy.c:601
@ OPTION_PRIVATE
Definition: app_chanspy.c:386
@ OPTION_ENFORCED
Definition: app_chanspy.c:389
@ OPTION_EXIT
Definition: app_chanspy.c:388
@ OPTION_BRIDGED
Definition: app_chanspy.c:381
@ OPTION_RECORD
Definition: app_chanspy.c:384
@ OPTION_WHISPER
Definition: app_chanspy.c:385
@ OPTION_NAME
Definition: app_chanspy.c:392
@ OPTION_STOP
Definition: app_chanspy.c:397
@ OPTION_QUIET
Definition: app_chanspy.c:380
@ OPTION_READONLY
Definition: app_chanspy.c:387
@ OPTION_INTERLEAVED
Definition: app_chanspy.c:401
@ OPTION_BARGE
Definition: app_chanspy.c:391
@ OPTION_GROUP
Definition: app_chanspy.c:383
@ OPTION_UNIQUEID
Definition: app_chanspy.c:399
@ OPTION_DTMF_CYCLE
Definition: app_chanspy.c:395
@ OPTION_DAHDI_SCAN
Definition: app_chanspy.c:396
@ OPTION_DTMF_SWITCH_MODES
Definition: app_chanspy.c:393
@ OPTION_EXITONHANGUP
Definition: app_chanspy.c:398
@ OPTION_NOTECH
Definition: app_chanspy.c:390
@ OPTION_DTMF_EXIT
Definition: app_chanspy.c:394
@ OPTION_LONG_QUEUE
Definition: app_chanspy.c:400
@ OPTION_VOLUME
Definition: app_chanspy.c:382
static void * spy_alloc(struct ast_channel *chan, void *data)
Definition: app_chanspy.c:455
static int dahdiscan_exec(struct ast_channel *chan, const char *data)
Definition: app_chanspy.c:1498
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)
Definition: app_chanspy.c:697
static void change_spy_mode(const char digit, struct ast_flags *flags)
Definition: app_chanspy.c:587
static const struct ast_app_option spy_opts[128]
Definition: app_chanspy.c:437
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)
Definition: app_chanspy.c:949
static struct ast_autochan * next_channel(struct ast_channel_iterator *iter, struct ast_channel *chan)
Definition: app_chanspy.c:915
static int extenspy_exec(struct ast_channel *chan, const char *data)
Definition: app_chanspy.c:1377
static const char app_dahdiscan[]
Definition: app_chanspy.c:377
static int start_spying(struct ast_autochan *autochan, const char *spychan_name, struct ast_audiohook *audiohook, struct ast_flags *flags)
Definition: app_chanspy.c:564
@ OPT_ARG_CYCLE
Definition: app_chanspy.c:411
@ OPT_ARG_RECORD
Definition: app_chanspy.c:407
@ OPT_ARG_EXIT
Definition: app_chanspy.c:410
@ OPT_ARG_NAME
Definition: app_chanspy.c:409
@ OPT_ARG_VOLUME
Definition: app_chanspy.c:405
@ OPT_ARG_ENFORCED
Definition: app_chanspy.c:408
@ OPT_ARG_ARRAY_SIZE
Definition: app_chanspy.c:412
@ OPT_ARG_GROUP
Definition: app_chanspy.c:406
static int load_module(void)
Definition: app_chanspy.c:1548
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)
Definition: app_chanspy.c:662
static const char app_ext[]
Definition: app_chanspy.c:375
static int unload_module(void)
Definition: app_chanspy.c:1537
static void spy_release(struct ast_channel *chan, void *data)
Definition: app_chanspy.c:461
#define AST_NAME_STRLEN
Definition: app_chanspy.c:60
static const char app_chan[]
Definition: app_chanspy.c:373
static int spy_generate(struct ast_channel *chan, void *data, int len, int samples)
Definition: app_chanspy.c:466
static struct ast_generator spygen
Definition: app_chanspy.c:558
static char exitcontext[AST_MAX_CONTEXT]
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:451
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:100
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:446
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:167
@ 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:313
@ 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:550
int ast_audiohook_attach(struct ast_channel *chan, struct ast_audiohook *audiohook)
Attach audiohook to channel.
Definition: audiohook.c:484
int ast_audiohook_destroy(struct ast_audiohook *audiohook)
Destroys an audiohook structure.
Definition: audiohook.c:124
#define ast_audiohook_unlock(ah)
Unlock an audiohook.
Definition: audiohook.h:318
@ AST_AUDIOHOOK_TYPE_SPY
Definition: audiohook.h:36
@ AST_AUDIOHOOK_TYPE_WHISPER
Definition: audiohook.h:37
@ AST_AUDIOHOOK_STATUS_RUNNING
Definition: audiohook.h:43
"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 int tmp()
Definition: bt_open.c:389
static const char type[]
Definition: chan_ooh323.c:109
General Asterisk PBX channel definitions.
int ast_waitfordigit(struct ast_channel *c, int ms)
Waits for a digit.
Definition: channel.c:3175
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:2951
void ast_channel_clear_flag(struct ast_channel *chan, unsigned int flag)
Clear a flag on a channel.
Definition: channel.c:11034
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:1388
struct ast_channel_iterator * ast_channel_iterator_destroy(struct ast_channel_iterator *i)
Destroy a channel iterator.
Definition: channel.c:1360
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:10564
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:2922
struct ast_channel * ast_channel_iterator_next(struct ast_channel_iterator *i)
Get the next channel for a channel iterator.
Definition: channel.c:1422
struct ast_silence_generator * ast_channel_start_silence_generator(struct ast_channel *chan)
Starts a silence generator on the given channel.
Definition: channel.c:8164
int ast_waitfor(struct ast_channel *chan, int ms)
Wait for input on a channel.
Definition: channel.c:3162
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:8210
#define ast_channel_ref(c)
Increase channel reference count.
Definition: channel.h:2947
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:2893
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:1368
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:1434
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:5144
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition: channel.c:4257
int ast_check_hangup(struct ast_channel *chan)
Check to see if a channel is needing hang up.
Definition: channel.c:445
int ast_channel_is_bridged(const struct ast_channel *chan)
Determine if a channel is in a bridge.
Definition: channel.c:10545
void ast_channel_set_flag(struct ast_channel *chan, unsigned int flag)
Set a flag on a channel.
Definition: channel.c:11027
#define AST_CHANNEL_NAME
Definition: channel.h:171
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:2958
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:5803
#define AST_MAX_CONTEXT
Definition: channel.h:135
const char * ast_channel_language(const struct ast_channel *chan)
@ AST_FLAG_ZOMBIE
Definition: channel.h:987
@ AST_FLAG_END_DTMF_ONLY
Definition: channel.h:1007
@ AST_FLAG_SPYING
Definition: channel.h:993
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:7422
#define ast_channel_cleanup(c)
Cleanup a channel reference.
Definition: channel.h:2969
struct ast_channel * ast_channel_get_by_name(const char *name)
Find a channel by name.
Definition: channel.c:1454
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:1408
#define ast_channel_unlock(chan)
Definition: channel.h:2923
ast_channel_state
ast_channel states
Definition: channelstate.h:35
@ AST_STATE_UP
Definition: channelstate.h:42
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:1293
int ast_fileexists(const char *filename, const char *fmt, const char *preflang)
Checks for the existence of a given file.
Definition: file.c:1129
int ast_waitstream(struct ast_channel *c, const char *breakon)
Waits for a stream to stop or digit to be pressed.
Definition: file.c:1840
Media Format Cache API.
struct ast_format * ast_format_slin
Built-in cached signed linear 8kHz format.
Definition: format_cache.c:41
struct ast_format * ast_format_cache_get_slin_by_rate(unsigned int rate)
Retrieve the best signed linear format given a sample rate.
Definition: format_cache.c:512
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.
static ENTRY retval
Definition: hsearch.c:50
const char * ext
Definition: http.c:150
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:3056
char * strcasestr(const char *, const char *)
#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
@ AST_FRAME_VOICE
#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.
Definition: linkedlists.h:439
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:567
#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:392
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition: module.h:626
Options provided by main asterisk program.
Asterisk file paths, configured in asterisk.conf.
const char * ast_config_AST_MONITOR_DIR
Definition: options.c:155
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:8781
#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:8271
int ast_say_digits(struct ast_channel *chan, int num, const char *ints, const char *lang)
says digits
Definition: channel.c:8253
@ 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:1511
#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 x
Definition: extconf.c:81
struct ast_flags flags
Structure used to handle boolean flags.
Definition: utils.h:199
unsigned int flags
Definition: utils.h:200
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
union ast_frame::@226 data
enum ast_frame_type frametype
void *(* alloc)(struct ast_channel *chan, void *params)
Definition: channel.h:226
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
Definition: app_chanspy.c:443
struct ast_audiohook whisper_audiohook
Definition: app_chanspy.c:442
struct ast_audiohook spy_audiohook
Definition: app_chanspy.c:441
struct ast_flags flags
Definition: app_chanspy.c:446
const char * args
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:63
#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:941
#define ast_clear_flag(p, flag)
Definition: utils.h:77
#define ast_set_flag(p, flag)
Definition: utils.h:70
#define ARRAY_LEN(a)
Definition: utils.h:666
#define ast_copy_flags(dest, src, flagz)
Definition: utils.h:84
#define AST_FLAGS_ALL
Definition: utils.h:196