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