app_chanspy: Documentation Update To Clarify "x" Option
[asterisk/asterisk.git] / apps / app_chanspy.c
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 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
39
40 #include <ctype.h>
41 #include <errno.h>
42
43 #include "asterisk/paths.h" /* use ast_config_AST_MONITOR_DIR */
44 #include "asterisk/file.h"
45 #include "asterisk/channel.h"
46 #include "asterisk/audiohook.h"
47 #include "asterisk/features.h"
48 #include "asterisk/app.h"
49 #include "asterisk/utils.h"
50 #include "asterisk/say.h"
51 #include "asterisk/pbx.h"
52 #include "asterisk/translate.h"
53 #include "asterisk/manager.h"
54 #include "asterisk/module.h"
55 #include "asterisk/lock.h"
56 #include "asterisk/options.h"
57 #include "asterisk/autochan.h"
58 #include "asterisk/stasis_channels.h"
59 #include "asterisk/json.h"
60
61 #define AST_NAME_STRLEN 256
62 #define NUM_SPYGROUPS 128
63
64 /*** DOCUMENTATION
65         <application name="ChanSpy" language="en_US">
66                 <synopsis>
67                         Listen to a channel, and optionally whisper into it.
68                 </synopsis>
69                 <syntax>
70                         <parameter name="chanprefix" />
71                         <parameter name="options">
72                                 <optionlist>
73                                         <option name="b">
74                                                 <para>Only spy on channels involved in a bridged call.</para>
75                                         </option>
76                                         <option name="B">
77                                                 <para>Instead of whispering on a single channel barge in on both
78                                                 channels involved in the call.</para>
79                                         </option>
80                                         <option name="c">
81                                                 <argument name="digit" required="true">
82                                                         <para>Specify a DTMF digit that can be used to spy on the next available channel.</para>
83                                                 </argument>
84                                         </option>
85                                         <option name="d">
86                                                 <para>Override the typical numeric DTMF functionality and instead
87                                                 use DTMF to switch between spy modes.</para>
88                                                 <enumlist>
89                                                         <enum name="4">
90                                                                 <para>spy mode</para>
91                                                         </enum>
92                                                         <enum name="5">
93                                                                 <para>whisper mode</para>
94                                                         </enum>
95                                                         <enum name="6">
96                                                                 <para>barge mode</para>
97                                                         </enum>
98                                                 </enumlist>
99                                         </option>
100                                         <option name="e">
101                                                 <argument name="ext" required="true" />
102                                                 <para>Enable <emphasis>enforced</emphasis> mode, so the spying channel can
103                                                 only monitor extensions whose name is in the <replaceable>ext</replaceable> : delimited 
104                                                 list.</para>
105                                         </option>
106                                         <option name="E">
107                                                 <para>Exit when the spied-on channel hangs up.</para>
108                                         </option>
109                                         <option name="g">
110                                                 <argument name="grp" required="true">
111                                                         <para>Only spy on channels in which one or more of the groups
112                                                         listed in <replaceable>grp</replaceable> matches one or more groups from the
113                                                         <variable>SPYGROUP</variable> variable set on the channel to be spied upon.</para>
114                                                 </argument>
115                                                 <note><para>both <replaceable>grp</replaceable> and <variable>SPYGROUP</variable> can contain 
116                                                 either a single group or a colon-delimited list of groups, such
117                                                 as <literal>sales:support:accounting</literal>.</para></note>
118                                         </option>
119                                         <option name="n" argsep="@">
120                                                 <para>Say the name of the person being spied on if that person has recorded
121                                                 his/her name. If a context is specified, then that voicemail context will
122                                                 be searched when retrieving the name, otherwise the <literal>default</literal> context
123                                                 be used when searching for the name (i.e. if SIP/1000 is the channel being
124                                                 spied on and no mailbox is specified, then <literal>1000</literal> will be used when searching
125                                                 for the name).</para>
126                                                 <argument name="mailbox" />
127                                                 <argument name="context" />
128                                         </option>
129                                         <option name="o">
130                                                 <para>Only listen to audio coming from this channel.</para>
131                                         </option>
132                                         <option name="q">
133                                                 <para>Don't play a beep when beginning to spy on a channel, or speak the
134                                                 selected channel name.</para>
135                                         </option>
136                                         <option name="r">
137                                                 <para>Record the session to the monitor spool directory. An optional base for the filename 
138                                                 may be specified. The default is <literal>chanspy</literal>.</para>
139                                                 <argument name="basename" />
140                                         </option>
141                                         <option name="s">
142                                                 <para>Skip the playback of the channel type (i.e. SIP, IAX, etc) when
143                                                 speaking the selected channel name.</para>
144                                         </option>
145                                         <option name="S">
146                                                 <para>Stop when no more channels are left to spy on.</para>
147                                         </option>
148                                         <option name="u">
149                                                 <para>The <literal>chanprefix</literal> parameter is a channel uniqueid
150                                                 or fully specified channel name.</para>
151                                         </option>
152                                         <option name="v">
153                                                 <argument name="value" />
154                                                 <para>Adjust the initial volume in the range from <literal>-4</literal> 
155                                                 to <literal>4</literal>. A negative value refers to a quieter setting.</para>
156                                         </option>
157                                         <option name="w">
158                                                 <para>Enable <literal>whisper</literal> mode, so the spying channel can talk to
159                                                 the spied-on channel.</para>
160                                         </option>
161                                         <option name="W">
162                                                 <para>Enable <literal>private whisper</literal> mode, so the spying channel can
163                                                 talk to the spied-on channel but cannot listen to that channel.</para>
164                                         </option>
165                                         <option name="x">
166                                                 <argument name="digit" required="true">
167                                                         <para>Specify a DTMF digit that can be used to exit the application while actively
168                                                         spying on a channel. If there is no channel being spied on, the DTMF digit will be
169                                                         ignored.</para>
170                                                 </argument>
171                                         </option>
172                                         <option name="X">
173                                                 <para>Allow the user to exit ChanSpy to a valid single digit
174                                                 numeric extension in the current context or the context
175                                                 specified by the <variable>SPY_EXIT_CONTEXT</variable> channel variable. The
176                                                 name of the last channel that was spied on will be stored
177                                                 in the <variable>SPY_CHANNEL</variable> variable.</para>
178                                         </option>
179                                 </optionlist>           
180                         </parameter>
181                 </syntax>
182                 <description>
183                         <para>This application is used to listen to the audio from an Asterisk channel. This includes the audio 
184                         coming in and out of the channel being spied on. If the <literal>chanprefix</literal> parameter is specified,
185                         only channels beginning with this string will be spied upon.</para>
186                         <para>While spying, the following actions may be performed:</para>
187                         <para> - Dialing <literal>#</literal> cycles the volume level.</para>
188                         <para> - Dialing <literal>*</literal> will stop spying and look for another channel to spy on.</para>
189                         <para> - Dialing a series of digits followed by <literal>#</literal> builds a channel name to append
190                         to <literal>chanprefix</literal>. For example, executing ChanSpy(Agent) and then dialing the digits '1234#'
191                         while spying will begin spying on the channel 'Agent/1234'. Note that this feature will be overridden
192                         if the 'd' or 'u' options are used.</para>
193                         <note><para>The <replaceable>X</replaceable> option supersedes the three features above in that if a valid
194                         single digit extension exists in the correct context ChanSpy will exit to it.
195                         This also disables choosing a channel based on <literal>chanprefix</literal> and a digit sequence.</para></note>
196                 </description>
197                 <see-also>
198                         <ref type="application">ExtenSpy</ref>
199                         <ref type="managerEvent">ChanSpyStart</ref>
200                         <ref type="managerEvent">ChanSpyStop</ref>
201                 </see-also>
202         </application>
203         <application name="ExtenSpy" language="en_US">
204                 <synopsis>
205                         Listen to a channel, and optionally whisper into it.
206                 </synopsis>
207                 <syntax>
208                         <parameter name="exten" required="true" argsep="@">
209                                 <argument name="exten" required="true">
210                                         <para>Specify extension.</para>
211                                 </argument>
212                                 <argument name="context">
213                                         <para>Optionally specify a context, defaults to <literal>default</literal>.</para>
214                                 </argument>
215                         </parameter>
216                         <parameter name="options">
217                                 <optionlist>
218                                         <option name="b">
219                                                 <para>Only spy on channels involved in a bridged call.</para>
220                                         </option>
221                                         <option name="B">
222                                                 <para>Instead of whispering on a single channel barge in on both
223                                                 channels involved in the call.</para>
224                                         </option>
225                                         <option name="c">
226                                                 <argument name="digit" required="true">
227                                                         <para>Specify a DTMF digit that can be used to spy on the next available channel.</para>
228                                                 </argument>
229                                         </option>
230                                         <option name="d">
231                                                 <para>Override the typical numeric DTMF functionality and instead
232                                                 use DTMF to switch between spy modes.</para>
233                                                 <enumlist>
234                                                         <enum name="4">
235                                                                 <para>spy mode</para>
236                                                         </enum>
237                                                         <enum name="5">
238                                                                 <para>whisper mode</para>
239                                                         </enum>
240                                                         <enum name="6">
241                                                                 <para>barge mode</para>
242                                                         </enum>
243                                                 </enumlist>
244                                         </option>
245                                         <option name="e">
246                                                 <argument name="ext" required="true" />
247                                                 <para>Enable <emphasis>enforced</emphasis> mode, so the spying channel can
248                                                 only monitor extensions whose name is in the <replaceable>ext</replaceable> : delimited 
249                                                 list.</para>
250                                         </option>
251                                         <option name="E">
252                                                 <para>Exit when the spied-on channel hangs up.</para>
253                                         </option>
254                                         <option name="g">
255                                                 <argument name="grp" required="true">
256                                                         <para>Only spy on channels in which one or more of the groups
257                                                         listed in <replaceable>grp</replaceable> matches one or more groups from the
258                                                         <variable>SPYGROUP</variable> variable set on the channel to be spied upon.</para>
259                                                 </argument>
260                                                 <note><para>both <replaceable>grp</replaceable> and <variable>SPYGROUP</variable> can contain 
261                                                 either a single group or a colon-delimited list of groups, such
262                                                 as <literal>sales:support:accounting</literal>.</para></note>
263                                         </option>
264                                         <option name="n" argsep="@">
265                                                 <para>Say the name of the person being spied on if that person has recorded
266                                                 his/her name. If a context is specified, then that voicemail context will
267                                                 be searched when retrieving the name, otherwise the <literal>default</literal> context
268                                                 be used when searching for the name (i.e. if SIP/1000 is the channel being
269                                                 spied on and no mailbox is specified, then <literal>1000</literal> will be used when searching
270                                                 for the name).</para>
271                                                 <argument name="mailbox" />
272                                                 <argument name="context" />
273                                         </option>
274                                         <option name="o">
275                                                 <para>Only listen to audio coming from this channel.</para>
276                                         </option>
277                                         <option name="q">
278                                                 <para>Don't play a beep when beginning to spy on a channel, or speak the
279                                                 selected channel name.</para>
280                                         </option>
281                                         <option name="r">
282                                                 <para>Record the session to the monitor spool directory. An optional base for the filename 
283                                                 may be specified. The default is <literal>chanspy</literal>.</para>
284                                                 <argument name="basename" />
285                                         </option>
286                                         <option name="s">
287                                                 <para>Skip the playback of the channel type (i.e. SIP, IAX, etc) when
288                                                 speaking the selected channel name.</para>
289                                         </option>
290                                         <option name="S">
291                                                 <para>Stop when there are no more extensions left to spy on.</para>
292                                         </option>
293                                         <option name="v">
294                                                 <argument name="value" />
295                                                 <para>Adjust the initial volume in the range from <literal>-4</literal> 
296                                                 to <literal>4</literal>. A negative value refers to a quieter setting.</para>
297                                         </option>
298                                         <option name="w">
299                                                 <para>Enable <literal>whisper</literal> mode, so the spying channel can talk to
300                                                 the spied-on channel.</para>
301                                         </option>
302                                         <option name="W">
303                                                 <para>Enable <literal>private whisper</literal> mode, so the spying channel can
304                                                 talk to the spied-on channel but cannot listen to that channel.</para>
305                                         </option>
306                                         <option name="x">
307                                                 <argument name="digit" required="true">
308                                                         <para>Specify a DTMF digit that can be used to exit the application while actively
309                                                         spying on a channel. If there is no channel being spied on, the DTMF digit will be
310                                                         ignored.</para>
311                                                 </argument>
312                                         </option>
313                                         <option name="X">
314                                                 <para>Allow the user to exit ChanSpy to a valid single digit
315                                                 numeric extension in the current context or the context
316                                                 specified by the <variable>SPY_EXIT_CONTEXT</variable> channel variable. The
317                                                 name of the last channel that was spied on will be stored
318                                                 in the <variable>SPY_CHANNEL</variable> variable.</para>
319                                         </option>
320                                 </optionlist>   
321                         </parameter>
322                 </syntax>
323                 <description>
324                         <para>This application is used to listen to the audio from an Asterisk channel. This includes 
325                         the audio coming in and out of the channel being spied on. Only channels created by outgoing calls for the
326                         specified extension will be selected for spying. If the optional context is not supplied, 
327                         the current channel's context will be used.</para>
328                         <para>While spying, the following actions may be performed:</para>
329                         <para> - Dialing <literal>#</literal> cycles the volume level.</para>
330                         <para> - Dialing <literal>*</literal> will stop spying and look for another channel to spy on.</para>
331                         <note><para>The <replaceable>X</replaceable> option supersedes the three features above in that if a valid
332                         single digit extension exists in the correct context ChanSpy will exit to it.
333                         This also disables choosing a channel based on <literal>chanprefix</literal> and a digit sequence.</para></note>
334                 </description>
335                 <see-also>
336                         <ref type="application">ChanSpy</ref>
337                         <ref type="managerEvent">ChanSpyStart</ref>
338                         <ref type="managerEvent">ChanSpyStop</ref>
339                 </see-also>
340         </application>
341         <application name="DAHDIScan" language="en_US">
342                 <synopsis>
343                         Scan DAHDI channels to monitor calls.
344                 </synopsis>
345                 <syntax>
346                         <parameter name="group">
347                                 <para>Limit scanning to a channel <replaceable>group</replaceable> by setting this option.</para>
348                         </parameter>
349                 </syntax>
350                 <description>
351                         <para>Allows a call center manager to monitor DAHDI channels in a
352                         convenient way.  Use <literal>#</literal> to select the next channel and use <literal>*</literal> to exit.</para>
353                 </description>
354                 <see-also>
355                         <ref type="managerEvent">ChanSpyStart</ref>
356                         <ref type="managerEvent">ChanSpyStop</ref>
357                 </see-also>
358         </application>
359  ***/
360
361 static const char app_chan[] = "ChanSpy";
362
363 static const char app_ext[] = "ExtenSpy";
364
365 static const char app_dahdiscan[] = "DAHDIScan";
366
367 enum {
368         OPTION_QUIET             = (1 << 0),    /* Quiet, no announcement */
369         OPTION_BRIDGED           = (1 << 1),    /* Only look at bridged calls */
370         OPTION_VOLUME            = (1 << 2),    /* Specify initial volume */
371         OPTION_GROUP             = (1 << 3),    /* Only look at channels in group */
372         OPTION_RECORD            = (1 << 4),
373         OPTION_WHISPER           = (1 << 5),
374         OPTION_PRIVATE           = (1 << 6),    /* Private Whisper mode */
375         OPTION_READONLY          = (1 << 7),    /* Don't mix the two channels */
376         OPTION_EXIT              = (1 << 8),    /* Exit to a valid single digit extension */
377         OPTION_ENFORCED          = (1 << 9),    /* Enforced mode */
378         OPTION_NOTECH            = (1 << 10),   /* Skip technology name playback */
379         OPTION_BARGE             = (1 << 11),   /* Barge mode (whisper to both channels) */
380         OPTION_NAME              = (1 << 12),   /* Say the name of the person on whom we will spy */
381         OPTION_DTMF_SWITCH_MODES = (1 << 13),   /* Allow numeric DTMF to switch between chanspy modes */
382         OPTION_DTMF_EXIT         = (1 << 14),   /* Set DTMF to exit, added for DAHDIScan integration */
383         OPTION_DTMF_CYCLE        = (1 << 15),   /* Custom DTMF for cycling next available channel, (default is '*') */
384         OPTION_DAHDI_SCAN        = (1 << 16),   /* Scan groups in DAHDIScan mode */
385         OPTION_STOP              = (1 << 17),
386         OPTION_EXITONHANGUP      = (1 << 18),   /* Hang up when the spied-on channel hangs up. */
387         OPTION_UNIQUEID          = (1 << 19),   /* The chanprefix is a channel uniqueid or fully specified channel name. */
388 };
389
390 enum {
391         OPT_ARG_VOLUME = 0,
392         OPT_ARG_GROUP,
393         OPT_ARG_RECORD,
394         OPT_ARG_ENFORCED,
395         OPT_ARG_NAME,
396         OPT_ARG_EXIT,
397         OPT_ARG_CYCLE,
398         OPT_ARG_ARRAY_SIZE,
399 };
400
401 AST_APP_OPTIONS(spy_opts, {
402         AST_APP_OPTION('b', OPTION_BRIDGED),
403         AST_APP_OPTION('B', OPTION_BARGE),
404         AST_APP_OPTION_ARG('c', OPTION_DTMF_CYCLE, OPT_ARG_CYCLE),
405         AST_APP_OPTION('d', OPTION_DTMF_SWITCH_MODES),
406         AST_APP_OPTION_ARG('e', OPTION_ENFORCED, OPT_ARG_ENFORCED),
407         AST_APP_OPTION('E', OPTION_EXITONHANGUP),
408         AST_APP_OPTION_ARG('g', OPTION_GROUP, OPT_ARG_GROUP),
409         AST_APP_OPTION_ARG('n', OPTION_NAME, OPT_ARG_NAME),
410         AST_APP_OPTION('o', OPTION_READONLY),
411         AST_APP_OPTION('q', OPTION_QUIET),
412         AST_APP_OPTION_ARG('r', OPTION_RECORD, OPT_ARG_RECORD),
413         AST_APP_OPTION('s', OPTION_NOTECH),
414         AST_APP_OPTION('S', OPTION_STOP),
415         AST_APP_OPTION('u', OPTION_UNIQUEID),
416         AST_APP_OPTION_ARG('v', OPTION_VOLUME, OPT_ARG_VOLUME),
417         AST_APP_OPTION('w', OPTION_WHISPER),
418         AST_APP_OPTION('W', OPTION_PRIVATE),
419         AST_APP_OPTION_ARG('x', OPTION_DTMF_EXIT, OPT_ARG_EXIT),
420         AST_APP_OPTION('X', OPTION_EXIT),
421 });
422
423 struct chanspy_translation_helper {
424         /* spy data */
425         struct ast_audiohook spy_audiohook;
426         struct ast_audiohook whisper_audiohook;
427         struct ast_audiohook bridge_whisper_audiohook;
428         int fd;
429         int volfactor;
430         struct ast_flags flags;
431 };
432
433 struct spy_dtmf_options {
434         char exit;
435         char cycle;
436         char volume;
437 };
438
439 static void *spy_alloc(struct ast_channel *chan, void *data)
440 {
441         /* just store the data pointer in the channel structure */
442         return data;
443 }
444
445 static void spy_release(struct ast_channel *chan, void *data)
446 {
447         /* nothing to do */
448 }
449
450 static int spy_generate(struct ast_channel *chan, void *data, int len, int samples)
451 {
452         struct chanspy_translation_helper *csth = data;
453         struct ast_frame *f, *cur;
454         struct ast_format format_slin;
455
456         ast_format_set(&format_slin, AST_FORMAT_SLINEAR, 0);
457
458         ast_audiohook_lock(&csth->spy_audiohook);
459         if (csth->spy_audiohook.status != AST_AUDIOHOOK_STATUS_RUNNING) {
460                 /* Channel is already gone more than likely */
461                 ast_audiohook_unlock(&csth->spy_audiohook);
462                 return -1;
463         }
464
465         if (ast_test_flag(&csth->flags, OPTION_READONLY)) {
466                 /* Option 'o' was set, so don't mix channel audio */
467                 f = ast_audiohook_read_frame(&csth->spy_audiohook, samples, AST_AUDIOHOOK_DIRECTION_READ, &format_slin);
468         } else {
469                 f = ast_audiohook_read_frame(&csth->spy_audiohook, samples, AST_AUDIOHOOK_DIRECTION_BOTH, &format_slin);
470         }
471
472         ast_audiohook_unlock(&csth->spy_audiohook);
473
474         if (!f)
475                 return 0;
476
477         for (cur = f; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
478                 if (ast_write(chan, cur)) {
479                         ast_frfree(f);
480                         return -1;
481                 }
482
483                 if (csth->fd) {
484                         if (write(csth->fd, cur->data.ptr, cur->datalen) < 0) {
485                                 ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
486                         }
487                 }
488         }
489
490         ast_frfree(f);
491
492         return 0;
493 }
494
495 static struct ast_generator spygen = {
496         .alloc = spy_alloc,
497         .release = spy_release,
498         .generate = spy_generate,
499 };
500
501 static int start_spying(struct ast_autochan *autochan, const char *spychan_name, struct ast_audiohook *audiohook)
502 {
503         int res = 0;
504
505         ast_log(LOG_NOTICE, "Attaching %s to %s\n", spychan_name, ast_channel_name(autochan->chan));
506
507         ast_set_flag(audiohook, AST_AUDIOHOOK_TRIGGER_SYNC | AST_AUDIOHOOK_SMALL_QUEUE);
508         res = ast_audiohook_attach(autochan->chan, audiohook);
509
510         if (!res) {
511                 ast_channel_lock(autochan->chan);
512                 if (ast_channel_is_bridged(autochan->chan)) {
513                         ast_softhangup_nolock(autochan->chan, AST_SOFTHANGUP_UNBRIDGE);
514                 }
515                 ast_channel_unlock(autochan->chan);
516         }
517         return res;
518 }
519
520 static void change_spy_mode(const char digit, struct ast_flags *flags)
521 {
522         if (digit == '4') {
523                 ast_clear_flag(flags, OPTION_WHISPER);
524                 ast_clear_flag(flags, OPTION_BARGE);
525         } else if (digit == '5') {
526                 ast_clear_flag(flags, OPTION_BARGE);
527                 ast_set_flag(flags, OPTION_WHISPER);
528         } else if (digit == '6') {
529                 ast_clear_flag(flags, OPTION_WHISPER);
530                 ast_set_flag(flags, OPTION_BARGE);
531         }
532 }
533
534 static int pack_channel_into_message(struct ast_channel *chan, const char *role,
535                                                                          struct ast_multi_channel_blob *payload)
536 {
537         RAII_VAR(struct ast_channel_snapshot *, snapshot,
538                         ast_channel_snapshot_get_latest(ast_channel_uniqueid(chan)),
539                         ao2_cleanup);
540
541         if (!snapshot) {
542                 return -1;
543         }
544         ast_multi_channel_blob_add_channel(payload, role, snapshot);
545         return 0;
546 }
547
548 /*! \internal
549  * \brief Publish the chanspy message over Stasis-Core
550  * \param spyer The channel doing the spying
551  * \param spyee Who is being spied upon
552  * \start start If non-zero, the spying is starting. Otherwise, the spyer is
553  * finishing
554  */
555 static void publish_chanspy_message(struct ast_channel *spyer,
556                                                                         struct ast_channel *spyee,
557                                                                         int start)
558 {
559         RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
560         RAII_VAR(struct ast_multi_channel_blob *, payload, NULL, ao2_cleanup);
561         RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
562
563         if (!spyer) {
564                 ast_log(AST_LOG_WARNING, "Attempt to publish ChanSpy message for NULL spyer channel\n");
565                 return;
566         }
567         blob = ast_json_null();
568         if (!blob) {
569                 return;
570         }
571
572         payload = ast_multi_channel_blob_create(blob);
573         if (!payload) {
574                 return;
575         }
576
577         if (pack_channel_into_message(spyer, "spyer_channel", payload)) {
578                 return;
579         }
580
581         if (spyee) {
582                 if (pack_channel_into_message(spyee, "spyee_channel", payload)) {
583                         return;
584                 }
585         }
586
587         message = stasis_message_create(
588                         start ? ast_channel_chanspy_start_type(): ast_channel_chanspy_stop_type(),
589                                         payload);
590         if (!message) {
591                 return;
592         }
593         stasis_publish(ast_channel_topic(spyer), message);
594 }
595
596 static int channel_spy(struct ast_channel *chan, struct ast_autochan *spyee_autochan,
597         int *volfactor, int fd, struct spy_dtmf_options *user_options, struct ast_flags *flags,
598         char *exitcontext)
599 {
600         struct chanspy_translation_helper csth;
601         int running = 0, res, x = 0;
602         char inp[24] = {0};
603         char *name;
604         struct ast_frame *f;
605         struct ast_silence_generator *silgen = NULL;
606         struct ast_autochan *spyee_bridge_autochan = NULL;
607         const char *spyer_name;
608
609         if (ast_check_hangup(chan) || ast_check_hangup(spyee_autochan->chan) ||
610                         ast_test_flag(ast_channel_flags(spyee_autochan->chan), AST_FLAG_ZOMBIE)) {
611                 return 0;
612         }
613
614         ast_channel_lock(chan);
615         spyer_name = ast_strdupa(ast_channel_name(chan));
616         ast_channel_unlock(chan);
617
618         ast_channel_lock(spyee_autochan->chan);
619         name = ast_strdupa(ast_channel_name(spyee_autochan->chan));
620         ast_channel_unlock(spyee_autochan->chan);
621
622         ast_verb(2, "Spying on channel %s\n", name);
623         publish_chanspy_message(chan, spyee_autochan->chan, 1);
624
625         memset(&csth, 0, sizeof(csth));
626         ast_copy_flags(&csth.flags, flags, AST_FLAGS_ALL);
627
628         /* This is the audiohook which gives us the audio off the channel we are
629            spying on.
630         */
631         ast_audiohook_init(&csth.spy_audiohook, AST_AUDIOHOOK_TYPE_SPY, "ChanSpy", 0);
632
633         if (start_spying(spyee_autochan, spyer_name, &csth.spy_audiohook)) {
634                 ast_audiohook_destroy(&csth.spy_audiohook);
635                 return 0;
636         }
637
638         if (ast_test_flag(flags, OPTION_WHISPER | OPTION_BARGE | OPTION_DTMF_SWITCH_MODES)) {
639                 /* This audiohook will let us inject audio from our channel into the
640                    channel we are currently spying on.
641                 */
642                 ast_audiohook_init(&csth.whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "ChanSpy", 0);
643
644                 if (start_spying(spyee_autochan, spyer_name, &csth.whisper_audiohook)) {
645                         ast_log(LOG_WARNING, "Unable to attach whisper audiohook to spyee %s. Whisper mode disabled!\n", name);
646                 }
647         }
648
649         if (ast_test_flag(flags, OPTION_BARGE | OPTION_DTMF_SWITCH_MODES)) {
650                 RAII_VAR(struct ast_channel *, bridged, ast_channel_bridge_peer(spyee_autochan->chan), ast_channel_cleanup);
651
652                 /* And this hook lets us inject audio into the channel that the spied on
653                    channel is currently bridged with.
654                 */
655                 ast_audiohook_init(&csth.bridge_whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "Chanspy", 0);
656
657                 if ((spyee_bridge_autochan = ast_autochan_setup(bridged))) {
658                         ast_channel_lock(spyee_bridge_autochan->chan);
659                         if (start_spying(spyee_bridge_autochan, spyer_name, &csth.bridge_whisper_audiohook)) {
660                                 ast_log(LOG_WARNING, "Unable to attach barge audiohook on spyee %s. Barge mode disabled!\n", name);
661                         }
662                         ast_channel_unlock(spyee_bridge_autochan->chan);
663                 }
664         }
665
666         ast_channel_lock(chan);
667         ast_set_flag(ast_channel_flags(chan), AST_FLAG_END_DTMF_ONLY);
668         ast_channel_unlock(chan);
669
670         csth.volfactor = *volfactor;
671
672         if (csth.volfactor) {
673                 csth.spy_audiohook.options.read_volume = csth.volfactor;
674                 csth.spy_audiohook.options.write_volume = csth.volfactor;
675         }
676
677         csth.fd = fd;
678
679         if (ast_test_flag(flags, OPTION_PRIVATE))
680                 silgen = ast_channel_start_silence_generator(chan);
681         else
682                 ast_activate_generator(chan, &spygen, &csth);
683
684         /* We can no longer rely on 'spyee' being an actual channel;
685            it can be hung up and freed out from under us. However, the
686            channel destructor will put NULL into our csth.spy.chan
687            field when that happens, so that is our signal that the spyee
688            channel has gone away.
689         */
690
691         /* Note: it is very important that the ast_waitfor() be the first
692            condition in this expression, so that if we wait for some period
693            of time before receiving a frame from our spying channel, we check
694            for hangup on the spied-on channel _after_ knowing that a frame
695            has arrived, since the spied-on channel could have gone away while
696            we were waiting
697         */
698         while (ast_waitfor(chan, -1) > -1 && csth.spy_audiohook.status == AST_AUDIOHOOK_STATUS_RUNNING) {
699                 if (!(f = ast_read(chan)) || ast_check_hangup(chan)) {
700                         running = -1;
701                         break;
702                 }
703
704                 if (ast_test_flag(flags, OPTION_BARGE) && f->frametype == AST_FRAME_VOICE) {
705                         ast_audiohook_lock(&csth.whisper_audiohook);
706                         ast_audiohook_lock(&csth.bridge_whisper_audiohook);
707                         ast_audiohook_write_frame(&csth.whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f);
708                         ast_audiohook_write_frame(&csth.bridge_whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f);
709                         ast_audiohook_unlock(&csth.whisper_audiohook);
710                         ast_audiohook_unlock(&csth.bridge_whisper_audiohook);
711                         ast_frfree(f);
712                         continue;
713                 } else if (ast_test_flag(flags, OPTION_WHISPER) && f->frametype == AST_FRAME_VOICE) {
714                         ast_audiohook_lock(&csth.whisper_audiohook);
715                         ast_audiohook_write_frame(&csth.whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f);
716                         ast_audiohook_unlock(&csth.whisper_audiohook);
717                         ast_frfree(f);
718                         continue;
719                 }
720                 
721                 res = (f->frametype == AST_FRAME_DTMF) ? f->subclass.integer : 0;
722                 ast_frfree(f);
723                 if (!res)
724                         continue;
725
726                 if (x == sizeof(inp))
727                         x = 0;
728
729                 if (res < 0) {
730                         running = -1;
731                         break;
732                 }
733
734                 if (ast_test_flag(flags, OPTION_EXIT)) {
735                         char tmp[2];
736                         tmp[0] = res;
737                         tmp[1] = '\0';
738                         if (!ast_goto_if_exists(chan, exitcontext, tmp, 1)) {
739                                 ast_debug(1, "Got DTMF %c, goto context %s\n", tmp[0], exitcontext);
740                                 pbx_builtin_setvar_helper(chan, "SPY_CHANNEL", name);
741                                 running = -2;
742                                 break;
743                         } else {
744                                 ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
745                         }
746                 } else if (res >= '0' && res <= '9') {
747                         if (ast_test_flag(flags, OPTION_DTMF_SWITCH_MODES)) {
748                                 change_spy_mode(res, flags);
749                         } else {
750                                 inp[x++] = res;
751                         }
752                 }
753
754                 if (res == user_options->cycle) {
755                         running = 0;
756                         break;
757                 } else if (res == user_options->exit) {
758                         running = -2;
759                         break;
760                 } else if (res == user_options->volume) {
761                         if (!ast_strlen_zero(inp)) {
762                                 running = atoi(inp);
763                                 break;
764                         }
765
766                         (*volfactor)++;
767                         if (*volfactor > 4)
768                                 *volfactor = -4;
769                         ast_verb(3, "Setting spy volume on %s to %d\n", ast_channel_name(chan), *volfactor);
770
771                         csth.volfactor = *volfactor;
772                         csth.spy_audiohook.options.read_volume = csth.volfactor;
773                         csth.spy_audiohook.options.write_volume = csth.volfactor;
774                 }
775         }
776
777         if (ast_test_flag(flags, OPTION_PRIVATE))
778                 ast_channel_stop_silence_generator(chan, silgen);
779         else
780                 ast_deactivate_generator(chan);
781
782         ast_channel_lock(chan);
783         ast_clear_flag(ast_channel_flags(chan), AST_FLAG_END_DTMF_ONLY);
784         ast_channel_unlock(chan);
785
786         if (ast_test_flag(flags, OPTION_WHISPER | OPTION_BARGE | OPTION_DTMF_SWITCH_MODES)) {
787                 ast_audiohook_lock(&csth.whisper_audiohook);
788                 ast_audiohook_detach(&csth.whisper_audiohook);
789                 ast_audiohook_unlock(&csth.whisper_audiohook);
790                 ast_audiohook_destroy(&csth.whisper_audiohook);
791         }
792
793         if (ast_test_flag(flags, OPTION_BARGE | OPTION_DTMF_SWITCH_MODES)) {
794                 ast_audiohook_lock(&csth.bridge_whisper_audiohook);
795                 ast_audiohook_detach(&csth.bridge_whisper_audiohook);
796                 ast_audiohook_unlock(&csth.bridge_whisper_audiohook);
797                 ast_audiohook_destroy(&csth.bridge_whisper_audiohook);
798         }
799
800         ast_audiohook_lock(&csth.spy_audiohook);
801         ast_audiohook_detach(&csth.spy_audiohook);
802         ast_audiohook_unlock(&csth.spy_audiohook);
803         ast_audiohook_destroy(&csth.spy_audiohook);
804
805         if (spyee_bridge_autochan) {
806                 ast_autochan_destroy(spyee_bridge_autochan);
807         }
808
809         ast_verb(2, "Done Spying on channel %s\n", name);
810         publish_chanspy_message(chan, NULL, 0);
811
812         return running;
813 }
814
815 static struct ast_autochan *next_channel(struct ast_channel_iterator *iter,
816                 struct ast_autochan *autochan, struct ast_channel *chan)
817 {
818         struct ast_channel *next;
819         struct ast_autochan *autochan_store;
820         const size_t pseudo_len = strlen("DAHDI/pseudo");
821
822         if (!iter) {
823                 return NULL;
824         }
825
826         for (; (next = ast_channel_iterator_next(iter)); ast_channel_unref(next)) {
827                 if (!strncmp(ast_channel_name(next), "DAHDI/pseudo", pseudo_len)
828                         || next == chan) {
829                         continue;
830                 }
831
832                 autochan_store = ast_autochan_setup(next);
833                 ast_channel_unref(next);
834
835                 return autochan_store;
836         }
837         return NULL;
838 }
839
840 static int common_exec(struct ast_channel *chan, struct ast_flags *flags,
841         int volfactor, const int fd, struct spy_dtmf_options *user_options,
842         const char *mygroup, const char *myenforced, const char *spec, const char *exten,
843         const char *context, const char *mailbox, const char *name_context)
844 {
845         char nameprefix[AST_NAME_STRLEN];
846         char exitcontext[AST_MAX_CONTEXT] = "";
847         signed char zero_volume = 0;
848         int waitms;
849         int res;
850         int num_spyed_upon = 1;
851         struct ast_channel_iterator *iter = NULL;
852
853         if (ast_test_flag(flags, OPTION_EXIT)) {
854                 const char *c;
855                 ast_channel_lock(chan);
856                 if ((c = pbx_builtin_getvar_helper(chan, "SPY_EXIT_CONTEXT"))) {
857                         ast_copy_string(exitcontext, c, sizeof(exitcontext));
858                 } else if (!ast_strlen_zero(ast_channel_macrocontext(chan))) {
859                         ast_copy_string(exitcontext, ast_channel_macrocontext(chan), sizeof(exitcontext));
860                 } else {
861                         ast_copy_string(exitcontext, ast_channel_context(chan), sizeof(exitcontext));
862                 }
863                 ast_channel_unlock(chan);
864         }
865
866         if (ast_channel_state(chan) != AST_STATE_UP)
867                 ast_answer(chan);
868
869         ast_set_flag(ast_channel_flags(chan), AST_FLAG_SPYING); /* so nobody can spy on us while we are spying */
870
871         waitms = 100;
872
873         for (;;) {
874                 struct ast_autochan *autochan = NULL, *next_autochan = NULL;
875                 struct ast_channel *prev = NULL;
876
877                 if (!ast_test_flag(flags, OPTION_QUIET) && num_spyed_upon) {
878                         res = ast_streamfile(chan, "beep", ast_channel_language(chan));
879                         if (!res)
880                                 res = ast_waitstream(chan, "");
881                         else if (res < 0) {
882                                 ast_clear_flag(ast_channel_flags(chan), AST_FLAG_SPYING);
883                                 break;
884                         }
885                         if (!ast_strlen_zero(exitcontext)) {
886                                 char tmp[2];
887                                 tmp[0] = res;
888                                 tmp[1] = '\0';
889                                 if (!ast_goto_if_exists(chan, exitcontext, tmp, 1))
890                                         goto exit;
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                 }
895
896                 /* Set up the iterator we'll be using during this call */
897                 if (!ast_strlen_zero(spec)) {
898                         if (ast_test_flag(flags, OPTION_UNIQUEID)) {
899                                 struct ast_channel *unique_chan;
900
901                                 unique_chan = ast_channel_get_by_name(spec);
902                                 if (!unique_chan) {
903                                         res = -1;
904                                         goto exit;
905                                 }
906                                 iter = ast_channel_iterator_by_name_new(ast_channel_name(unique_chan), 0);
907                                 ast_channel_unref(unique_chan);
908                         } else {
909                                 iter = ast_channel_iterator_by_name_new(spec, strlen(spec));
910                         }
911                 } else if (!ast_strlen_zero(exten)) {
912                         iter = ast_channel_iterator_by_exten_new(exten, context);
913                 } else {
914                         iter = ast_channel_iterator_all_new();
915                 }
916
917                 if (!iter) {
918                         res = -1;
919                         goto exit;
920                 }
921
922                 res = ast_waitfordigit(chan, waitms);
923                 if (res < 0) {
924                         iter = ast_channel_iterator_destroy(iter);
925                         ast_clear_flag(ast_channel_flags(chan), AST_FLAG_SPYING);
926                         break;
927                 }
928                 if (!ast_strlen_zero(exitcontext)) {
929                         char tmp[2];
930                         tmp[0] = res;
931                         tmp[1] = '\0';
932                         if (!ast_goto_if_exists(chan, exitcontext, tmp, 1)) {
933                                 iter = ast_channel_iterator_destroy(iter);
934                                 goto exit;
935                         } else {
936                                 ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
937                         }
938                 }
939
940                 /* reset for the next loop around, unless overridden later */
941                 waitms = 100;
942                 num_spyed_upon = 0;
943
944                 for (autochan = next_channel(iter, autochan, chan);
945                      autochan;
946                          prev = autochan->chan, ast_autochan_destroy(autochan),
947                      autochan = next_autochan ? next_autochan : 
948                                 next_channel(iter, autochan, chan), next_autochan = NULL) {
949                         int igrp = !mygroup;
950                         int ienf = !myenforced;
951
952                         if (autochan->chan == prev) {
953                                 ast_autochan_destroy(autochan);
954                                 break;
955                         }
956
957                         if (ast_check_hangup(chan)) {
958                                 ast_autochan_destroy(autochan);
959                                 break;
960                         }
961
962                         if (ast_test_flag(flags, OPTION_BRIDGED) && !ast_channel_is_bridged(autochan->chan)) {
963                                 continue;
964                         }
965
966                         if (ast_check_hangup(autochan->chan) || ast_test_flag(ast_channel_flags(autochan->chan), AST_FLAG_SPYING)) {
967                                 continue;
968                         }
969
970                         if (mygroup) {
971                                 int num_groups = 0;
972                                 int num_mygroups = 0;
973                                 char dup_group[512];
974                                 char dup_mygroup[512];
975                                 char *groups[NUM_SPYGROUPS];
976                                 char *mygroups[NUM_SPYGROUPS];
977                                 const char *group = NULL;
978                                 int x;
979                                 int y;
980                                 ast_copy_string(dup_mygroup, mygroup, sizeof(dup_mygroup));
981                                 num_mygroups = ast_app_separate_args(dup_mygroup, ':', mygroups,
982                                         ARRAY_LEN(mygroups));
983
984                                 /* Before dahdi scan was part of chanspy, it would use the "GROUP" variable 
985                                  * rather than "SPYGROUP", this check is done to preserve expected behavior */
986                                 if (ast_test_flag(flags, OPTION_DAHDI_SCAN)) {
987                                         group = pbx_builtin_getvar_helper(autochan->chan, "GROUP");
988                                 } else {
989                                         group = pbx_builtin_getvar_helper(autochan->chan, "SPYGROUP");
990                                 }
991
992                                 if (!ast_strlen_zero(group)) {
993                                         ast_copy_string(dup_group, group, sizeof(dup_group));
994                                         num_groups = ast_app_separate_args(dup_group, ':', groups,
995                                                 ARRAY_LEN(groups));
996                                 }
997
998                                 for (y = 0; y < num_mygroups; y++) {
999                                         for (x = 0; x < num_groups; x++) {
1000                                                 if (!strcmp(mygroups[y], groups[x])) {
1001                                                         igrp = 1;
1002                                                         break;
1003                                                 }
1004                                         }
1005                                 }
1006                         }
1007
1008                         if (!igrp) {
1009                                 continue;
1010                         }
1011                         if (myenforced) {
1012                                 char ext[AST_CHANNEL_NAME + 3];
1013                                 char buffer[512];
1014                                 char *end;
1015
1016                                 snprintf(buffer, sizeof(buffer) - 1, ":%s:", myenforced);
1017
1018                                 ast_copy_string(ext + 1, ast_channel_name(autochan->chan), sizeof(ext) - 1);
1019                                 if ((end = strchr(ext, '-'))) {
1020                                         *end++ = ':';
1021                                         *end = '\0';
1022                                 }
1023
1024                                 ext[0] = ':';
1025
1026                                 if (strcasestr(buffer, ext)) {
1027                                         ienf = 1;
1028                                 }
1029                         }
1030
1031                         if (!ienf) {
1032                                 continue;
1033                         }
1034
1035                         if (!ast_test_flag(flags, OPTION_QUIET)) {
1036                                 char peer_name[AST_NAME_STRLEN + 5];
1037                                 char *ptr, *s;
1038
1039                                 strcpy(peer_name, "spy-");
1040                                 strncat(peer_name, ast_channel_name(autochan->chan), AST_NAME_STRLEN - 4 - 1);
1041                                 if ((ptr = strchr(peer_name, '/'))) {
1042                                         *ptr++ = '\0';
1043                                         for (s = peer_name; s < ptr; s++) {
1044                                                 *s = tolower(*s);
1045                                         }
1046                                         if ((s = strchr(ptr, '-'))) {
1047                                                 *s = '\0';
1048                                         }
1049                                 }
1050
1051                                 if (ast_test_flag(flags, OPTION_NAME)) {
1052                                         const char *local_context = S_OR(name_context, "default");
1053                                         const char *local_mailbox = S_OR(mailbox, ptr);
1054                                         if (local_mailbox) {
1055                                                 res = ast_app_sayname(chan, local_mailbox, local_context);
1056                                         } else {
1057                                                 res = -1;
1058                                         }
1059                                 }
1060                                 if (!ast_test_flag(flags, OPTION_NAME) || res < 0) {
1061                                         int num;
1062                                         if (!ast_test_flag(flags, OPTION_NOTECH)) {
1063                                                 if (ast_fileexists(peer_name, NULL, NULL) > 0) {
1064                                                         res = ast_streamfile(chan, peer_name, ast_channel_language(chan));
1065                                                         if (!res) {
1066                                                                 res = ast_waitstream(chan, "");
1067                                                         }
1068                                                         if (res) {
1069                                                                 ast_autochan_destroy(autochan);
1070                                                                 break;
1071                                                         }
1072                                                 } else {
1073                                                         res = ast_say_character_str(chan, peer_name, "", ast_channel_language(chan), AST_SAY_CASE_NONE);
1074                                                 }
1075                                         }
1076                                         if (ptr && (num = atoi(ptr))) {
1077                                                 ast_say_digits(chan, num, "", ast_channel_language(chan));
1078                                         }
1079                                 }
1080                         }
1081
1082                         res = channel_spy(chan, autochan, &volfactor, fd, user_options, flags, exitcontext);
1083                         num_spyed_upon++;
1084
1085                         if (res == -1) {
1086                                 ast_autochan_destroy(autochan);
1087                                 iter = ast_channel_iterator_destroy(iter);
1088                                 goto exit;
1089                         } else if (res == -2) {
1090                                 res = 0;
1091                                 ast_autochan_destroy(autochan);
1092                                 iter = ast_channel_iterator_destroy(iter);
1093                                 goto exit;
1094                         } else if (res > 1 && spec && !ast_test_flag(flags, OPTION_UNIQUEID)) {
1095                                 struct ast_channel *next;
1096
1097                                 snprintf(nameprefix, AST_NAME_STRLEN, "%s/%d", spec, res);
1098
1099                                 if ((next = ast_channel_get_by_name_prefix(nameprefix, strlen(nameprefix)))) {
1100                                         next_autochan = ast_autochan_setup(next);
1101                                         next = ast_channel_unref(next);
1102                                 } else {
1103                                         /* stay on this channel, if it is still valid */
1104                                         if (!ast_check_hangup(autochan->chan)) {
1105                                                 next_autochan = ast_autochan_setup(autochan->chan);
1106                                         } else {
1107                                                 /* the channel is gone */
1108                                                 next_autochan = NULL;
1109                                         }
1110                                 }
1111                         } else if (res == 0 && ast_test_flag(flags, OPTION_EXITONHANGUP)) {
1112                                 ast_autochan_destroy(autochan);
1113                                 iter = ast_channel_iterator_destroy(iter);
1114                                 goto exit;
1115                         }
1116                 }
1117
1118                 iter = ast_channel_iterator_destroy(iter);
1119
1120                 if (res == -1 || ast_check_hangup(chan))
1121                         break;
1122                 if (ast_test_flag(flags, OPTION_STOP) && !next_autochan) {
1123                         break;
1124                 }
1125         }
1126 exit:
1127
1128         ast_clear_flag(ast_channel_flags(chan), AST_FLAG_SPYING);
1129
1130         ast_channel_setoption(chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);
1131
1132         return res;
1133 }
1134
1135 static int chanspy_exec(struct ast_channel *chan, const char *data)
1136 {
1137         char *myenforced = NULL;
1138         char *mygroup = NULL;
1139         char *recbase = NULL;
1140         int fd = 0;
1141         struct ast_flags flags;
1142         struct spy_dtmf_options user_options = {
1143                 .cycle = '*',
1144                 .volume = '#',
1145                 .exit = '\0',
1146         };
1147         struct ast_format oldwf;
1148         int volfactor = 0;
1149         int res;
1150         char *mailbox = NULL;
1151         char *name_context = NULL;
1152         AST_DECLARE_APP_ARGS(args,
1153                 AST_APP_ARG(spec);
1154                 AST_APP_ARG(options);
1155         );
1156         char *opts[OPT_ARG_ARRAY_SIZE];
1157         char *parse = ast_strdupa(data);
1158
1159         AST_STANDARD_APP_ARGS(args, parse);
1160         ast_format_clear(&oldwf);
1161
1162         if (args.spec && !strcmp(args.spec, "all"))
1163                 args.spec = NULL;
1164
1165         if (args.options) {
1166                 char tmp;
1167                 ast_app_parse_options(spy_opts, &flags, opts, args.options);
1168                 if (ast_test_flag(&flags, OPTION_GROUP))
1169                         mygroup = opts[OPT_ARG_GROUP];
1170
1171                 if (ast_test_flag(&flags, OPTION_RECORD) &&
1172                         !(recbase = opts[OPT_ARG_RECORD]))
1173                         recbase = "chanspy";
1174
1175                 if (ast_test_flag(&flags, OPTION_DTMF_EXIT) && opts[OPT_ARG_EXIT]) {
1176                         tmp = opts[OPT_ARG_EXIT][0];
1177                         if (strchr("0123456789*#", tmp) && tmp != '\0') {
1178                                 user_options.exit = tmp;
1179                         } else {
1180                                 ast_log(LOG_NOTICE, "Argument for option 'x' must be a valid DTMF digit.\n");
1181                         }
1182                 }
1183
1184                 if (ast_test_flag(&flags, OPTION_DTMF_CYCLE) && opts[OPT_ARG_CYCLE]) {
1185                         tmp = opts[OPT_ARG_CYCLE][0];
1186                         if (strchr("0123456789*#", tmp) && tmp != '\0') {
1187                                 user_options.cycle = tmp;
1188                         } else {
1189                                 ast_log(LOG_NOTICE, "Argument for option 'c' must be a valid DTMF digit.\n");
1190                         }
1191                 }
1192
1193                 if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) {
1194                         int vol;
1195
1196                         if ((sscanf(opts[OPT_ARG_VOLUME], "%30d", &vol) != 1) || (vol > 4) || (vol < -4))
1197                                 ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n");
1198                         else
1199                                 volfactor = vol;
1200                 }
1201
1202                 if (ast_test_flag(&flags, OPTION_PRIVATE))
1203                         ast_set_flag(&flags, OPTION_WHISPER);
1204
1205                 if (ast_test_flag(&flags, OPTION_ENFORCED))
1206                         myenforced = opts[OPT_ARG_ENFORCED];
1207
1208                 if (ast_test_flag(&flags, OPTION_NAME)) {
1209                         if (!ast_strlen_zero(opts[OPT_ARG_NAME])) {
1210                                 char *delimiter;
1211                                 if ((delimiter = strchr(opts[OPT_ARG_NAME], '@'))) {
1212                                         mailbox = opts[OPT_ARG_NAME];
1213                                         *delimiter++ = '\0';
1214                                         name_context = delimiter;
1215                                 } else {
1216                                         mailbox = opts[OPT_ARG_NAME];
1217                                 }
1218                         }
1219                 }
1220         } else {
1221                 ast_clear_flag(&flags, AST_FLAGS_ALL);
1222         }
1223
1224         ast_format_copy(&oldwf, ast_channel_writeformat(chan));
1225         if (ast_set_write_format_by_id(chan, AST_FORMAT_SLINEAR) < 0) {
1226                 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
1227                 return -1;
1228         }
1229
1230         if (recbase) {
1231                 char filename[PATH_MAX];
1232
1233                 snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL));
1234                 if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, AST_FILE_MODE)) <= 0) {
1235                         ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename);
1236                         fd = 0;
1237                 }
1238         }
1239
1240         res = common_exec(chan, &flags, volfactor, fd, &user_options, mygroup, myenforced, args.spec, NULL, NULL, mailbox, name_context);
1241
1242         if (fd)
1243                 close(fd);
1244
1245         if (oldwf.id && ast_set_write_format(chan, &oldwf) < 0)
1246                 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
1247
1248         if (ast_test_flag(&flags, OPTION_EXITONHANGUP)) {
1249                 ast_verb(3, "Stopped spying due to the spied-on channel hanging up.\n");
1250         }
1251
1252         return res;
1253 }
1254
1255 static int extenspy_exec(struct ast_channel *chan, const char *data)
1256 {
1257         char *ptr, *exten = NULL;
1258         char *mygroup = NULL;
1259         char *recbase = NULL;
1260         int fd = 0;
1261         struct ast_flags flags;
1262         struct spy_dtmf_options user_options = {
1263                 .cycle = '*',
1264                 .volume = '#',
1265                 .exit = '\0',
1266         };
1267         struct ast_format oldwf;
1268         int volfactor = 0;
1269         int res;
1270         char *mailbox = NULL;
1271         char *name_context = NULL;
1272         AST_DECLARE_APP_ARGS(args,
1273                 AST_APP_ARG(context);
1274                 AST_APP_ARG(options);
1275         );
1276         char *parse = ast_strdupa(data);
1277
1278         AST_STANDARD_APP_ARGS(args, parse);
1279         ast_format_clear(&oldwf);
1280
1281         if (!ast_strlen_zero(args.context) && (ptr = strchr(args.context, '@'))) {
1282                 exten = args.context;
1283                 *ptr++ = '\0';
1284                 args.context = ptr;
1285         }
1286         if (ast_strlen_zero(args.context))
1287                 args.context = ast_strdupa(ast_channel_context(chan));
1288
1289         if (args.options) {
1290                 char *opts[OPT_ARG_ARRAY_SIZE];
1291                 char tmp;
1292
1293                 ast_app_parse_options(spy_opts, &flags, opts, args.options);
1294                 if (ast_test_flag(&flags, OPTION_GROUP))
1295                         mygroup = opts[OPT_ARG_GROUP];
1296
1297                 if (ast_test_flag(&flags, OPTION_RECORD) &&
1298                         !(recbase = opts[OPT_ARG_RECORD]))
1299                         recbase = "chanspy";
1300
1301                 if (ast_test_flag(&flags, OPTION_DTMF_EXIT) && opts[OPT_ARG_EXIT]) {
1302                         tmp = opts[OPT_ARG_EXIT][0];
1303                         if (strchr("0123456789*#", tmp) && tmp != '\0') {
1304                                 user_options.exit = tmp;
1305                         } else {
1306                                 ast_log(LOG_NOTICE, "Argument for option 'x' must be a valid DTMF digit.\n");
1307                         }
1308                 }
1309
1310                 if (ast_test_flag(&flags, OPTION_DTMF_CYCLE) && opts[OPT_ARG_CYCLE]) {
1311                         tmp = opts[OPT_ARG_CYCLE][0];
1312                         if (strchr("0123456789*#", tmp) && tmp != '\0') {
1313                                 user_options.cycle = tmp;
1314                         } else {
1315                                 ast_log(LOG_NOTICE, "Argument for option 'c' must be a valid DTMF digit.\n");
1316                         }
1317                 }
1318
1319                 if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) {
1320                         int vol;
1321
1322                         if ((sscanf(opts[OPT_ARG_VOLUME], "%30d", &vol) != 1) || (vol > 4) || (vol < -4))
1323                                 ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n");
1324                         else
1325                                 volfactor = vol;
1326                 }
1327
1328                 if (ast_test_flag(&flags, OPTION_PRIVATE))
1329                         ast_set_flag(&flags, OPTION_WHISPER);
1330
1331                 if (ast_test_flag(&flags, OPTION_NAME)) {
1332                         if (!ast_strlen_zero(opts[OPT_ARG_NAME])) {
1333                                 char *delimiter;
1334                                 if ((delimiter = strchr(opts[OPT_ARG_NAME], '@'))) {
1335                                         mailbox = opts[OPT_ARG_NAME];
1336                                         *delimiter++ = '\0';
1337                                         name_context = delimiter;
1338                                 } else {
1339                                         mailbox = opts[OPT_ARG_NAME];
1340                                 }
1341                         }
1342                 }
1343
1344         } else {
1345                 /* Coverity - This uninit_use should be ignored since this macro initializes the flags */
1346                 ast_clear_flag(&flags, AST_FLAGS_ALL);
1347         }
1348
1349         ast_format_copy(&oldwf, ast_channel_writeformat(chan));
1350         if (ast_set_write_format_by_id(chan, AST_FORMAT_SLINEAR) < 0) {
1351                 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
1352                 return -1;
1353         }
1354
1355         if (recbase) {
1356                 char filename[PATH_MAX];
1357
1358                 snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL));
1359                 if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, AST_FILE_MODE)) <= 0) {
1360                         ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename);
1361                         fd = 0;
1362                 }
1363         }
1364
1365
1366         res = common_exec(chan, &flags, volfactor, fd, &user_options, mygroup, NULL, NULL, exten, args.context, mailbox, name_context);
1367
1368         if (fd)
1369                 close(fd);
1370
1371         if (oldwf.id && ast_set_write_format(chan, &oldwf) < 0)
1372                 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
1373
1374         return res;
1375 }
1376
1377 static int dahdiscan_exec(struct ast_channel *chan, const char *data)
1378 {
1379         const char *spec = "DAHDI";
1380         struct ast_flags flags;
1381         struct spy_dtmf_options user_options = {
1382                 .cycle = '#',
1383                 .volume = '\0',
1384                 .exit = '*',
1385         };
1386         struct ast_format oldwf;
1387         int res;
1388         char *mygroup = NULL;
1389
1390         /* Coverity - This uninit_use should be ignored since this macro initializes the flags */
1391         ast_clear_flag(&flags, AST_FLAGS_ALL);
1392         ast_format_clear(&oldwf);
1393         if (!ast_strlen_zero(data)) {
1394                 mygroup = ast_strdupa(data);
1395         }
1396         ast_set_flag(&flags, OPTION_DTMF_EXIT);
1397         ast_set_flag(&flags, OPTION_DTMF_CYCLE);
1398         ast_set_flag(&flags, OPTION_DAHDI_SCAN);
1399
1400         ast_format_copy(&oldwf, ast_channel_writeformat(chan));
1401         if (ast_set_write_format_by_id(chan, AST_FORMAT_SLINEAR) < 0) {
1402                 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
1403                 return -1;
1404         }
1405
1406         res = common_exec(chan, &flags, 0, 0, &user_options, mygroup, NULL, spec, NULL, NULL, NULL, NULL);
1407
1408         if (oldwf.id && ast_set_write_format(chan, &oldwf) < 0)
1409                 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
1410
1411         return res;
1412 }
1413
1414 static int unload_module(void)
1415 {
1416         int res = 0;
1417
1418         res |= ast_unregister_application(app_chan);
1419         res |= ast_unregister_application(app_ext);
1420         res |= ast_unregister_application(app_dahdiscan);
1421
1422         return res;
1423 }
1424
1425 static int load_module(void)
1426 {
1427         int res = 0;
1428
1429         res |= ast_register_application_xml(app_chan, chanspy_exec);
1430         res |= ast_register_application_xml(app_ext, extenspy_exec);
1431         res |= ast_register_application_xml(app_dahdiscan, dahdiscan_exec);
1432
1433         return res;
1434 }
1435
1436 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Listen to the audio of an active channel");