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