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