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