4b671df266bb4764fd30607383a1323069ae9bdb
[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
431         ast_audiohook_lock(&csth->spy_audiohook);
432         if (csth->spy_audiohook.status != AST_AUDIOHOOK_STATUS_RUNNING) {
433                 /* Channel is already gone more than likely */
434                 ast_audiohook_unlock(&csth->spy_audiohook);
435                 return -1;
436         }
437
438         if (ast_test_flag(&csth->spy_audiohook, OPTION_READONLY)) {
439                 /* Option 'o' was set, so don't mix channel audio */
440                 f = ast_audiohook_read_frame(&csth->spy_audiohook, samples, AST_AUDIOHOOK_DIRECTION_READ, AST_FORMAT_SLINEAR);
441         } else {
442                 f = ast_audiohook_read_frame(&csth->spy_audiohook, samples, AST_AUDIOHOOK_DIRECTION_BOTH, AST_FORMAT_SLINEAR);
443         }
444
445         ast_audiohook_unlock(&csth->spy_audiohook);
446
447         if (!f)
448                 return 0;
449
450         for (cur = f; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
451                 if (ast_write(chan, cur)) {
452                         ast_frfree(f);
453                         return -1;
454                 }
455
456                 if (csth->fd) {
457                         if (write(csth->fd, cur->data.ptr, cur->datalen) < 0) {
458                                 ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
459                         }
460                 }
461         }
462
463         ast_frfree(f);
464
465         return 0;
466 }
467
468 static struct ast_generator spygen = {
469         .alloc = spy_alloc,
470         .release = spy_release,
471         .generate = spy_generate,
472 };
473
474 static int start_spying(struct ast_autochan *autochan, const char *spychan_name, struct ast_audiohook *audiohook)
475 {
476         int res = 0;
477         struct ast_channel *peer = NULL;
478
479         ast_log(LOG_NOTICE, "Attaching %s to %s\n", spychan_name, autochan->chan->name);
480
481         ast_set_flag(audiohook, AST_AUDIOHOOK_TRIGGER_SYNC | AST_AUDIOHOOK_SMALL_QUEUE);
482         res = ast_audiohook_attach(autochan->chan, audiohook);
483
484         if (!res && ast_test_flag(autochan->chan, AST_FLAG_NBRIDGE) && (peer = ast_bridged_channel(autochan->chan))) {
485                 ast_softhangup(peer, AST_SOFTHANGUP_UNBRIDGE);
486         }
487         return res;
488 }
489
490 static void change_spy_mode(const char digit, struct ast_flags *flags)
491 {
492         if (digit == '4') {
493                 ast_clear_flag(flags, OPTION_WHISPER);
494                 ast_clear_flag(flags, OPTION_BARGE);
495         } else if (digit == '5') {
496                 ast_clear_flag(flags, OPTION_BARGE);
497                 ast_set_flag(flags, OPTION_WHISPER);
498         } else if (digit == '6') {
499                 ast_clear_flag(flags, OPTION_WHISPER);
500                 ast_set_flag(flags, OPTION_BARGE);
501         }
502 }
503
504 static int channel_spy(struct ast_channel *chan, struct ast_autochan *spyee_autochan,
505         int *volfactor, int fd, struct spy_dtmf_options *user_options, struct ast_flags *flags,
506         char *exitcontext)
507 {
508         struct chanspy_translation_helper csth;
509         int running = 0, res, x = 0;
510         char inp[24] = {0};
511         char *name;
512         struct ast_frame *f;
513         struct ast_silence_generator *silgen = NULL;
514         struct ast_autochan *spyee_bridge_autochan = NULL;
515         const char *spyer_name;
516         struct ast_channel *chans[] = { chan, spyee_autochan->chan };
517
518         ast_channel_lock(chan);
519         spyer_name = ast_strdupa(chan->name);
520         ast_channel_unlock(chan);
521
522         /* We now hold the channel lock on spyee */
523
524         if (ast_check_hangup(chan) || ast_check_hangup(spyee_autochan->chan)) {
525                 return 0;
526         }
527
528         ast_channel_lock(spyee_autochan->chan);
529         name = ast_strdupa(spyee_autochan->chan->name);
530         ast_channel_unlock(spyee_autochan->chan);
531
532         ast_verb(2, "Spying on channel %s\n", name);
533         ast_manager_event_multichan(EVENT_FLAG_CALL, "ChanSpyStart", 2, chans,
534                         "SpyerChannel: %s\r\n"
535                         "SpyeeChannel: %s\r\n",
536                         spyer_name, name);
537
538         memset(&csth, 0, sizeof(csth));
539         ast_copy_flags(&csth.spy_audiohook, flags, AST_FLAGS_ALL);
540
541         ast_audiohook_init(&csth.spy_audiohook, AST_AUDIOHOOK_TYPE_SPY, "ChanSpy");
542
543         if (start_spying(spyee_autochan, spyer_name, &csth.spy_audiohook)) {
544                 ast_audiohook_destroy(&csth.spy_audiohook);
545                 return 0;
546         }
547
548         ast_audiohook_init(&csth.whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "ChanSpy");
549         ast_audiohook_init(&csth.bridge_whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "Chanspy");
550         if (start_spying(spyee_autochan, spyer_name, &csth.whisper_audiohook)) {
551                 ast_log(LOG_WARNING, "Unable to attach whisper audiohook to spyee %s. Whisper mode disabled!\n", name);
552         }
553         if ((spyee_bridge_autochan = ast_autochan_setup(ast_bridged_channel(spyee_autochan->chan)))) {
554                 ast_channel_lock(spyee_bridge_autochan->chan);
555                 if (start_spying(spyee_bridge_autochan, spyer_name, &csth.bridge_whisper_audiohook)) {
556                         ast_log(LOG_WARNING, "Unable to attach barge audiohook on spyee %s. Barge mode disabled!\n", name);
557                 }
558                 ast_channel_unlock(spyee_bridge_autochan->chan);
559         }
560
561         ast_channel_lock(chan);
562         ast_set_flag(chan, AST_FLAG_END_DTMF_ONLY);
563         ast_channel_unlock(chan);
564
565         csth.volfactor = *volfactor;
566
567         if (csth.volfactor) {
568                 csth.spy_audiohook.options.read_volume = csth.volfactor;
569                 csth.spy_audiohook.options.write_volume = csth.volfactor;
570         }
571
572         csth.fd = fd;
573
574         if (ast_test_flag(flags, OPTION_PRIVATE))
575                 silgen = ast_channel_start_silence_generator(chan);
576         else
577                 ast_activate_generator(chan, &spygen, &csth);
578
579         /* We can no longer rely on 'spyee' being an actual channel;
580            it can be hung up and freed out from under us. However, the
581            channel destructor will put NULL into our csth.spy.chan
582            field when that happens, so that is our signal that the spyee
583            channel has gone away.
584         */
585
586         /* Note: it is very important that the ast_waitfor() be the first
587            condition in this expression, so that if we wait for some period
588            of time before receiving a frame from our spying channel, we check
589            for hangup on the spied-on channel _after_ knowing that a frame
590            has arrived, since the spied-on channel could have gone away while
591            we were waiting
592         */
593         while ((res = ast_waitfor(chan, -1) > -1) && csth.spy_audiohook.status == AST_AUDIOHOOK_STATUS_RUNNING) {
594                 if (!(f = ast_read(chan)) || ast_check_hangup(chan)) {
595                         running = -1;
596                         break;
597                 }
598
599                 if (ast_test_flag(flags, OPTION_BARGE) && f->frametype == AST_FRAME_VOICE) {
600                         ast_audiohook_lock(&csth.whisper_audiohook);
601                         ast_audiohook_lock(&csth.bridge_whisper_audiohook);
602                         ast_audiohook_write_frame(&csth.whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f);
603                         ast_audiohook_write_frame(&csth.bridge_whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f);
604                         ast_audiohook_unlock(&csth.whisper_audiohook);
605                         ast_audiohook_unlock(&csth.bridge_whisper_audiohook);
606                         ast_frfree(f);
607                         continue;
608                 } else if (ast_test_flag(flags, OPTION_WHISPER) && f->frametype == AST_FRAME_VOICE) {
609                         ast_audiohook_lock(&csth.whisper_audiohook);
610                         ast_audiohook_write_frame(&csth.whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f);
611                         ast_audiohook_unlock(&csth.whisper_audiohook);
612                         ast_frfree(f);
613                         continue;
614                 }
615                 
616                 res = (f->frametype == AST_FRAME_DTMF) ? f->subclass.integer : 0;
617                 ast_frfree(f);
618                 if (!res)
619                         continue;
620
621                 if (x == sizeof(inp))
622                         x = 0;
623
624                 if (res < 0) {
625                         running = -1;
626                         break;
627                 }
628
629                 if (ast_test_flag(flags, OPTION_EXIT)) {
630                         char tmp[2];
631                         tmp[0] = res;
632                         tmp[1] = '\0';
633                         if (!ast_goto_if_exists(chan, exitcontext, tmp, 1)) {
634                                 ast_debug(1, "Got DTMF %c, goto context %s\n", tmp[0], exitcontext);
635                                 pbx_builtin_setvar_helper(chan, "SPY_CHANNEL", name);
636                                 running = -2;
637                                 break;
638                         } else {
639                                 ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
640                         }
641                 } else if (res >= '0' && res <= '9') {
642                         if (ast_test_flag(flags, OPTION_DTMF_SWITCH_MODES)) {
643                                 change_spy_mode(res, flags);
644                         } else {
645                                 inp[x++] = res;
646                         }
647                 }
648
649                 if (res == user_options->cycle) {
650                         running = 0;
651                         break;
652                 } else if (res == user_options->exit) {
653                         running = -2;
654                         break;
655                 } else if (res == user_options->volume) {
656                         if (!ast_strlen_zero(inp)) {
657                                 running = atoi(inp);
658                                 break;
659                         }
660
661                         (*volfactor)++;
662                         if (*volfactor > 4)
663                                 *volfactor = -4;
664                         ast_verb(3, "Setting spy volume on %s to %d\n", chan->name, *volfactor);
665
666                         csth.volfactor = *volfactor;
667                         csth.spy_audiohook.options.read_volume = csth.volfactor;
668                         csth.spy_audiohook.options.write_volume = csth.volfactor;
669                 }
670         }
671
672         if (ast_test_flag(flags, OPTION_PRIVATE))
673                 ast_channel_stop_silence_generator(chan, silgen);
674         else
675                 ast_deactivate_generator(chan);
676
677         ast_channel_lock(chan);
678         ast_clear_flag(chan, AST_FLAG_END_DTMF_ONLY);
679         ast_channel_unlock(chan);
680
681         ast_audiohook_lock(&csth.whisper_audiohook);
682         ast_audiohook_detach(&csth.whisper_audiohook);
683         ast_audiohook_unlock(&csth.whisper_audiohook);
684         ast_audiohook_destroy(&csth.whisper_audiohook);
685         
686         ast_audiohook_lock(&csth.bridge_whisper_audiohook);
687         ast_audiohook_detach(&csth.bridge_whisper_audiohook);
688         ast_audiohook_unlock(&csth.bridge_whisper_audiohook);
689         ast_audiohook_destroy(&csth.bridge_whisper_audiohook);
690
691         ast_audiohook_lock(&csth.spy_audiohook);
692         ast_audiohook_detach(&csth.spy_audiohook);
693         ast_audiohook_unlock(&csth.spy_audiohook);
694         ast_audiohook_destroy(&csth.spy_audiohook);
695
696         if (spyee_bridge_autochan) {
697                 ast_autochan_destroy(spyee_bridge_autochan);
698         }
699
700         ast_verb(2, "Done Spying on channel %s\n", name);
701         ast_manager_event(chan, EVENT_FLAG_CALL, "ChanSpyStop", "SpyeeChannel: %s\r\n", name);
702
703         return running;
704 }
705
706 static struct ast_autochan *next_channel(struct ast_channel_iterator *iter,
707                 struct ast_autochan *autochan, struct ast_channel *chan)
708 {
709         struct ast_channel *next;
710         const size_t pseudo_len = strlen("DAHDI/pseudo");
711
712         if (!iter) {
713                 return NULL;
714         }
715
716 redo:
717         if (!(next = ast_channel_iterator_next(iter))) {
718                 return NULL;
719         }
720
721         if (!strncmp(next->name, "DAHDI/pseudo", pseudo_len)) {
722                 goto redo;
723         } else if (next == chan) {
724                 goto redo;
725         }
726
727         return ast_autochan_setup(next);
728 }
729
730 static int common_exec(struct ast_channel *chan, struct ast_flags *flags,
731         int volfactor, const int fd, struct spy_dtmf_options *user_options,
732         const char *mygroup, const char *myenforced, const char *spec, const char *exten,
733         const char *context, const char *mailbox, const char *name_context)
734 {
735         char nameprefix[AST_NAME_STRLEN];
736         char peer_name[AST_NAME_STRLEN + 5];
737         char exitcontext[AST_MAX_CONTEXT] = "";
738         signed char zero_volume = 0;
739         int waitms;
740         int res;
741         char *ptr;
742         int num;
743         int num_spyed_upon = 1;
744         struct ast_channel_iterator *iter = NULL;
745
746         if (ast_test_flag(flags, OPTION_EXIT)) {
747                 const char *c;
748                 ast_channel_lock(chan);
749                 if ((c = pbx_builtin_getvar_helper(chan, "SPY_EXIT_CONTEXT"))) {
750                         ast_copy_string(exitcontext, c, sizeof(exitcontext));
751                 } else if (!ast_strlen_zero(chan->macrocontext)) {
752                         ast_copy_string(exitcontext, chan->macrocontext, sizeof(exitcontext));
753                 } else {
754                         ast_copy_string(exitcontext, chan->context, sizeof(exitcontext));
755                 }
756                 ast_channel_unlock(chan);
757         }
758
759         if (chan->_state != AST_STATE_UP)
760                 ast_answer(chan);
761
762         ast_set_flag(chan, AST_FLAG_SPYING); /* so nobody can spy on us while we are spying */
763
764         waitms = 100;
765
766         for (;;) {
767                 struct ast_autochan *autochan = NULL, *next_autochan = NULL;
768                 struct ast_channel *prev = NULL;
769
770                 if (!ast_test_flag(flags, OPTION_QUIET) && num_spyed_upon) {
771                         res = ast_streamfile(chan, "beep", chan->language);
772                         if (!res)
773                                 res = ast_waitstream(chan, "");
774                         else if (res < 0) {
775                                 ast_clear_flag(chan, AST_FLAG_SPYING);
776                                 break;
777                         }
778                         if (!ast_strlen_zero(exitcontext)) {
779                                 char tmp[2];
780                                 tmp[0] = res;
781                                 tmp[1] = '\0';
782                                 if (!ast_goto_if_exists(chan, exitcontext, tmp, 1))
783                                         goto exit;
784                                 else
785                                         ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
786                         }
787                 }
788
789                 /* Set up the iterator we'll be using during this call */
790                 if (!ast_strlen_zero(spec)) {
791                         iter = ast_channel_iterator_by_name_new(spec, strlen(spec));
792                 } else if (!ast_strlen_zero(exten)) {
793                         iter = ast_channel_iterator_by_exten_new(exten, context);
794                 } else {
795                         iter = ast_channel_iterator_all_new();
796                 }
797
798                 if (!iter) {
799                         return -1;
800                 }
801
802                 res = ast_waitfordigit(chan, waitms);
803                 if (res < 0) {
804                         ast_clear_flag(chan, AST_FLAG_SPYING);
805                         break;
806                 }
807                 if (!ast_strlen_zero(exitcontext)) {
808                         char tmp[2];
809                         tmp[0] = res;
810                         tmp[1] = '\0';
811                         if (!ast_goto_if_exists(chan, exitcontext, tmp, 1))
812                                 goto exit;
813                         else
814                                 ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
815                 }
816
817                 /* reset for the next loop around, unless overridden later */
818                 waitms = 100;
819                 num_spyed_upon = 0;
820
821                 for (autochan = next_channel(iter, autochan, chan);
822                      autochan;
823                          prev = autochan->chan, ast_autochan_destroy(autochan),
824                      autochan = next_autochan ? next_autochan : 
825                                 next_channel(iter, autochan, chan), next_autochan = NULL) {
826                         int igrp = !mygroup;
827                         int ienf = !myenforced;
828                         char *s;
829
830                         if (autochan->chan == prev) {
831                                 ast_autochan_destroy(autochan);
832                                 break;
833                         }
834
835                         if (ast_check_hangup(chan)) {
836                                 ast_autochan_destroy(autochan);
837                                 break;
838                         }
839
840                         if (ast_test_flag(flags, OPTION_BRIDGED) && !ast_bridged_channel(autochan->chan)) {
841                                 continue;
842                         }
843
844                         if (ast_check_hangup(autochan->chan) || ast_test_flag(autochan->chan, AST_FLAG_SPYING)) {
845                                 continue;
846                         }
847
848                         if (mygroup) {
849                                 int num_groups = 0;
850                                 int num_mygroups = 0;
851                                 char dup_group[512];
852                                 char dup_mygroup[512];
853                                 char *groups[NUM_SPYGROUPS];
854                                 char *mygroups[NUM_SPYGROUPS];
855                                 const char *group = NULL;
856                                 int x;
857                                 int y;
858                                 ast_copy_string(dup_mygroup, mygroup, sizeof(dup_mygroup));
859                                 num_mygroups = ast_app_separate_args(dup_mygroup, ':', mygroups,
860                                         ARRAY_LEN(mygroups));
861
862                                 /* Before dahdi scan was part of chanspy, it would use the "GROUP" variable 
863                                  * rather than "SPYGROUP", this check is done to preserve expected behavior */
864                                 if (ast_test_flag(flags, OPTION_DAHDI_SCAN)) {
865                                         group = pbx_builtin_getvar_helper(autochan->chan, "GROUP");
866                                 } else {
867                                         group = pbx_builtin_getvar_helper(autochan->chan, "SPYGROUP");
868                                 }
869
870                                 if (!ast_strlen_zero(group)) {
871                                         ast_copy_string(dup_group, group, sizeof(dup_group));
872                                         num_groups = ast_app_separate_args(dup_group, ':', groups,
873                                                 ARRAY_LEN(groups));
874                                 }
875
876                                 for (y = 0; y < num_mygroups; y++) {
877                                         for (x = 0; x < num_groups; x++) {
878                                                 if (!strcmp(mygroups[y], groups[x])) {
879                                                         igrp = 1;
880                                                         break;
881                                                 }
882                                         }
883                                 }
884                         }
885
886                         if (!igrp) {
887                                 continue;
888                         }
889                         if (myenforced) {
890                                 char ext[AST_CHANNEL_NAME + 3];
891                                 char buffer[512];
892                                 char *end;
893
894                                 snprintf(buffer, sizeof(buffer) - 1, ":%s:", myenforced);
895
896                                 ast_copy_string(ext + 1, autochan->chan->name, sizeof(ext) - 1);
897                                 if ((end = strchr(ext, '-'))) {
898                                         *end++ = ':';
899                                         *end = '\0';
900                                 }
901
902                                 ext[0] = ':';
903
904                                 if (strcasestr(buffer, ext)) {
905                                         ienf = 1;
906                                 }
907                         }
908
909                         if (!ienf) {
910                                 continue;
911                         }
912
913                         strcpy(peer_name, "spy-");
914                         strncat(peer_name, autochan->chan->name, AST_NAME_STRLEN - 4 - 1);
915                         ptr = strchr(peer_name, '/');
916                         *ptr++ = '\0';
917                         ptr = strsep(&ptr, "-");
918
919                         for (s = peer_name; s < ptr; s++)
920                                 *s = tolower(*s);
921
922                         if (!ast_test_flag(flags, OPTION_QUIET)) {
923                                 if (ast_test_flag(flags, OPTION_NAME)) {
924                                         const char *local_context = S_OR(name_context, "default");
925                                         const char *local_mailbox = S_OR(mailbox, ptr);
926                                         res = ast_app_sayname(chan, local_mailbox, local_context);
927                                 }
928                                 if (!ast_test_flag(flags, OPTION_NAME) || res < 0) {
929                                         if (!ast_test_flag(flags, OPTION_NOTECH)) {
930                                                 if (ast_fileexists(peer_name, NULL, NULL) > 0) {
931                                                         res = ast_streamfile(chan, peer_name, chan->language);
932                                                         if (!res) {
933                                                                 res = ast_waitstream(chan, "");
934                                                         }
935                                                         if (res) {
936                                                                 ast_autochan_destroy(autochan);
937                                                                 break;
938                                                         }
939                                                 } else {
940                                                         res = ast_say_character_str(chan, peer_name, "", chan->language);
941                                                 }
942                                         }
943                                         if ((num = atoi(ptr)))
944                                                 ast_say_digits(chan, atoi(ptr), "", chan->language);
945                                 }
946                         }
947
948                         res = channel_spy(chan, autochan, &volfactor, fd, user_options, flags, exitcontext);
949                         num_spyed_upon++;
950
951                         if (res == -1) {
952                                 ast_autochan_destroy(autochan);
953                                 goto exit;
954                         } else if (res == -2) {
955                                 res = 0;
956                                 ast_autochan_destroy(autochan);
957                                 goto exit;
958                         } else if (res > 1 && spec) {
959                                 struct ast_channel *next;
960
961                                 snprintf(nameprefix, AST_NAME_STRLEN, "%s/%d", spec, res);
962
963                                 if ((next = ast_channel_get_by_name_prefix(nameprefix, strlen(nameprefix)))) {
964                                         next_autochan = ast_autochan_setup(next);
965                                         next = ast_channel_unref(next);
966                                 } else {
967                                         /* stay on this channel, if it is still valid */
968                                         if (!ast_check_hangup(autochan->chan)) {
969                                                 next_autochan = ast_autochan_setup(autochan->chan);
970                                         } else {
971                                                 /* the channel is gone */
972                                                 next_autochan = NULL;
973                                         }
974                                 }
975                         } else if (res == 0 && ast_test_flag(flags, OPTION_EXITONHANGUP)) {
976                                 goto exit;
977                         }
978                 }
979
980                 iter = ast_channel_iterator_destroy(iter);
981
982                 if (res == -1 || ast_check_hangup(chan))
983                         break;
984                 if (ast_test_flag(flags, OPTION_STOP) && !next_autochan) {
985                         break;
986                 }
987         }
988 exit:
989
990         ast_clear_flag(chan, AST_FLAG_SPYING);
991
992         ast_channel_setoption(chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);
993
994         return res;
995 }
996
997 static int chanspy_exec(struct ast_channel *chan, const char *data)
998 {
999         char *myenforced = NULL;
1000         char *mygroup = NULL;
1001         char *recbase = NULL;
1002         int fd = 0;
1003         struct ast_flags flags;
1004         struct spy_dtmf_options user_options = {
1005                 .cycle = '*',
1006                 .volume = '#',
1007                 .exit = '\0',
1008         };
1009         int oldwf = 0;
1010         int volfactor = 0;
1011         int res;
1012         char *mailbox = NULL;
1013         char *name_context = NULL;
1014         AST_DECLARE_APP_ARGS(args,
1015                 AST_APP_ARG(spec);
1016                 AST_APP_ARG(options);
1017         );
1018         char *opts[OPT_ARG_ARRAY_SIZE];
1019         char *parse = ast_strdupa(data);
1020
1021         AST_STANDARD_APP_ARGS(args, parse);
1022
1023         if (args.spec && !strcmp(args.spec, "all"))
1024                 args.spec = NULL;
1025
1026         if (args.options) {
1027                 char tmp;
1028                 ast_app_parse_options(spy_opts, &flags, opts, args.options);
1029                 if (ast_test_flag(&flags, OPTION_GROUP))
1030                         mygroup = opts[OPT_ARG_GROUP];
1031
1032                 if (ast_test_flag(&flags, OPTION_RECORD) &&
1033                         !(recbase = opts[OPT_ARG_RECORD]))
1034                         recbase = "chanspy";
1035
1036                 if (ast_test_flag(&flags, OPTION_DTMF_EXIT) && opts[OPT_ARG_EXIT]) {
1037                         tmp = opts[OPT_ARG_EXIT][0];
1038                         if (strchr("0123456789*#", tmp) && tmp != '\0') {
1039                                 user_options.exit = tmp;
1040                         } else {
1041                                 ast_log(LOG_NOTICE, "Argument for option 'x' must be a valid DTMF digit.");
1042                         }
1043                 }
1044
1045                 if (ast_test_flag(&flags, OPTION_DTMF_CYCLE) && opts[OPT_ARG_CYCLE]) {
1046                         tmp = opts[OPT_ARG_CYCLE][0];
1047                         if (strchr("0123456789*#", tmp) && tmp != '\0') {
1048                                 user_options.cycle = tmp;
1049                         } else {
1050                                 ast_log(LOG_NOTICE, "Argument for option 'c' must be a valid DTMF digit.");
1051                         }
1052                 }
1053
1054                 if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) {
1055                         int vol;
1056
1057                         if ((sscanf(opts[OPT_ARG_VOLUME], "%30d", &vol) != 1) || (vol > 4) || (vol < -4))
1058                                 ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n");
1059                         else
1060                                 volfactor = vol;
1061                 }
1062
1063                 if (ast_test_flag(&flags, OPTION_PRIVATE))
1064                         ast_set_flag(&flags, OPTION_WHISPER);
1065
1066                 if (ast_test_flag(&flags, OPTION_ENFORCED))
1067                         myenforced = opts[OPT_ARG_ENFORCED];
1068
1069                 if (ast_test_flag(&flags, OPTION_NAME)) {
1070                         if (!ast_strlen_zero(opts[OPT_ARG_NAME])) {
1071                                 char *delimiter;
1072                                 if ((delimiter = strchr(opts[OPT_ARG_NAME], '@'))) {
1073                                         mailbox = opts[OPT_ARG_NAME];
1074                                         *delimiter++ = '\0';
1075                                         name_context = delimiter;
1076                                 } else {
1077                                         mailbox = opts[OPT_ARG_NAME];
1078                                 }
1079                         }
1080                 }
1081         } else {
1082                 ast_clear_flag(&flags, AST_FLAGS_ALL);
1083         }
1084
1085         oldwf = chan->writeformat;
1086         if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
1087                 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
1088                 return -1;
1089         }
1090
1091         if (recbase) {
1092                 char filename[PATH_MAX];
1093
1094                 snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL));
1095                 if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, AST_FILE_MODE)) <= 0) {
1096                         ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename);
1097                         fd = 0;
1098                 }
1099         }
1100
1101         res = common_exec(chan, &flags, volfactor, fd, &user_options, mygroup, myenforced, args.spec, NULL, NULL, mailbox, name_context);
1102
1103         if (fd)
1104                 close(fd);
1105
1106         if (oldwf && ast_set_write_format(chan, oldwf) < 0)
1107                 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
1108
1109         if (ast_test_flag(&flags, OPTION_EXITONHANGUP)) {
1110                 ast_verb(3, "Stopped spying due to the spied-on channel hanging up.\n");
1111         }
1112
1113         return res;
1114 }
1115
1116 static int extenspy_exec(struct ast_channel *chan, const char *data)
1117 {
1118         char *ptr, *exten = NULL;
1119         char *mygroup = NULL;
1120         char *recbase = NULL;
1121         int fd = 0;
1122         struct ast_flags flags;
1123         struct spy_dtmf_options user_options = {
1124                 .cycle = '*',
1125                 .volume = '#',
1126                 .exit = '\0',
1127         };
1128         int oldwf = 0;
1129         int volfactor = 0;
1130         int res;
1131         char *mailbox = NULL;
1132         char *name_context = NULL;
1133         AST_DECLARE_APP_ARGS(args,
1134                 AST_APP_ARG(context);
1135                 AST_APP_ARG(options);
1136         );
1137         char *parse = ast_strdupa(data);
1138
1139         AST_STANDARD_APP_ARGS(args, parse);
1140         if (!ast_strlen_zero(args.context) && (ptr = strchr(args.context, '@'))) {
1141                 exten = args.context;
1142                 *ptr++ = '\0';
1143                 args.context = ptr;
1144         }
1145
1146         if (ast_strlen_zero(args.context))
1147                 args.context = ast_strdupa(chan->context);
1148
1149         if (args.options) {
1150                 char *opts[OPT_ARG_ARRAY_SIZE];
1151                 char tmp;
1152
1153                 ast_app_parse_options(spy_opts, &flags, opts, args.options);
1154                 if (ast_test_flag(&flags, OPTION_GROUP))
1155                         mygroup = opts[OPT_ARG_GROUP];
1156
1157                 if (ast_test_flag(&flags, OPTION_RECORD) &&
1158                         !(recbase = opts[OPT_ARG_RECORD]))
1159                         recbase = "chanspy";
1160
1161                 if (ast_test_flag(&flags, OPTION_DTMF_EXIT) && opts[OPT_ARG_EXIT]) {
1162                         tmp = opts[OPT_ARG_EXIT][0];
1163                         if (strchr("0123456789*#", tmp) && tmp != '\0') {
1164                                 user_options.exit = tmp;
1165                         } else {
1166                                 ast_log(LOG_NOTICE, "Argument for option 'x' must be a valid DTMF digit.");
1167                         }
1168                 }
1169
1170                 if (ast_test_flag(&flags, OPTION_DTMF_CYCLE) && opts[OPT_ARG_CYCLE]) {
1171                         tmp = opts[OPT_ARG_CYCLE][0];
1172                         if (strchr("0123456789*#", tmp) && tmp != '\0') {
1173                                 user_options.cycle = tmp;
1174                         } else {
1175                                 ast_log(LOG_NOTICE, "Argument for option 'c' must be a valid DTMF digit.");
1176                         }
1177                 }
1178
1179                 if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) {
1180                         int vol;
1181
1182                         if ((sscanf(opts[OPT_ARG_VOLUME], "%30d", &vol) != 1) || (vol > 4) || (vol < -4))
1183                                 ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n");
1184                         else
1185                                 volfactor = vol;
1186                 }
1187
1188                 if (ast_test_flag(&flags, OPTION_PRIVATE))
1189                         ast_set_flag(&flags, OPTION_WHISPER);
1190
1191                 if (ast_test_flag(&flags, OPTION_NAME)) {
1192                         if (!ast_strlen_zero(opts[OPT_ARG_NAME])) {
1193                                 char *delimiter;
1194                                 if ((delimiter = strchr(opts[OPT_ARG_NAME], '@'))) {
1195                                         mailbox = opts[OPT_ARG_NAME];
1196                                         *delimiter++ = '\0';
1197                                         name_context = delimiter;
1198                                 } else {
1199                                         mailbox = opts[OPT_ARG_NAME];
1200                                 }
1201                         }
1202                 }
1203
1204         } else {
1205                 ast_clear_flag(&flags, AST_FLAGS_ALL);
1206         }
1207
1208         oldwf = chan->writeformat;
1209         if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
1210                 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
1211                 return -1;
1212         }
1213
1214         if (recbase) {
1215                 char filename[PATH_MAX];
1216
1217                 snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL));
1218                 if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, AST_FILE_MODE)) <= 0) {
1219                         ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename);
1220                         fd = 0;
1221                 }
1222         }
1223
1224
1225         res = common_exec(chan, &flags, volfactor, fd, &user_options, mygroup, NULL, NULL, exten, args.context, mailbox, name_context);
1226
1227         if (fd)
1228                 close(fd);
1229
1230         if (oldwf && ast_set_write_format(chan, oldwf) < 0)
1231                 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
1232
1233         return res;
1234 }
1235
1236 static int dahdiscan_exec(struct ast_channel *chan, const char *data)
1237 {
1238         const char *spec = "DAHDI";
1239         struct ast_flags flags;
1240         struct spy_dtmf_options user_options = {
1241                 .cycle = '#',
1242                 .volume = '\0',
1243                 .exit = '*',
1244         };
1245         int oldwf = 0;
1246         int res;
1247         char *mygroup = NULL;
1248
1249         ast_clear_flag(&flags, AST_FLAGS_ALL);
1250
1251         if (!ast_strlen_zero(data)) {
1252                 mygroup = ast_strdupa(data);
1253         }
1254         ast_set_flag(&flags, OPTION_DTMF_EXIT);
1255         ast_set_flag(&flags, OPTION_DTMF_CYCLE);
1256         ast_set_flag(&flags, OPTION_DAHDI_SCAN);
1257
1258         oldwf = chan->writeformat;
1259         if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
1260                 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
1261                 return -1;
1262         }
1263
1264         res = common_exec(chan, &flags, 0, 0, &user_options, mygroup, NULL, spec, NULL, NULL, NULL, NULL);
1265
1266         if (oldwf && ast_set_write_format(chan, oldwf) < 0)
1267                 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
1268
1269         return res;
1270 }
1271
1272 static int unload_module(void)
1273 {
1274         int res = 0;
1275
1276         res |= ast_unregister_application(app_chan);
1277         res |= ast_unregister_application(app_ext);
1278         res |= ast_unregister_application(app_dahdiscan);
1279
1280         return res;
1281 }
1282
1283 static int load_module(void)
1284 {
1285         int res = 0;
1286
1287         res |= ast_register_application_xml(app_chan, chanspy_exec);
1288         res |= ast_register_application_xml(app_ext, extenspy_exec);
1289         res |= ast_register_application_xml(app_dahdiscan, dahdiscan_exec);
1290
1291         return res;
1292 }
1293
1294 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Listen to the audio of an active channel");