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