Always detach and destroy the whisper and barge audiohooks. Additionally also allow...
[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         
619         ast_audiohook_lock(&csth.bridge_whisper_audiohook);
620         ast_audiohook_detach(&csth.bridge_whisper_audiohook);
621         ast_audiohook_unlock(&csth.bridge_whisper_audiohook);
622         ast_audiohook_destroy(&csth.bridge_whisper_audiohook);
623
624         ast_audiohook_lock(&csth.spy_audiohook);
625         ast_audiohook_detach(&csth.spy_audiohook);
626         ast_audiohook_unlock(&csth.spy_audiohook);
627         ast_audiohook_destroy(&csth.spy_audiohook);
628         
629         ast_verb(2, "Done Spying on channel %s\n", name);
630
631         return running;
632 }
633
634 /*!
635  * \note This relies on the embedded lock to be recursive, as it may be called
636  * due to a call to chanspy_ds_free with the lock held there.
637  */
638 static void chanspy_ds_destroy(void *data)
639 {
640         struct chanspy_ds *chanspy_ds = data;
641
642         /* Setting chan to be NULL is an atomic operation, but we don't want this
643          * value to change while this lock is held.  The lock is held elsewhere
644          * while it performs non-atomic operations with this channel pointer */
645
646         ast_mutex_lock(&chanspy_ds->lock);
647         chanspy_ds->chan = NULL;
648         ast_mutex_unlock(&chanspy_ds->lock);
649 }
650
651 static void chanspy_ds_chan_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
652 {
653         struct chanspy_ds *chanspy_ds = data;
654         
655         ast_mutex_lock(&chanspy_ds->lock);
656         chanspy_ds->chan = new_chan;
657         ast_mutex_unlock(&chanspy_ds->lock);
658 }
659
660 static const struct ast_datastore_info chanspy_ds_info = {
661         .type = "chanspy",
662         .destroy = chanspy_ds_destroy,
663         .chan_fixup = chanspy_ds_chan_fixup,
664 };
665
666 static struct chanspy_ds *chanspy_ds_free(struct chanspy_ds *chanspy_ds)
667 {
668         if (!chanspy_ds)
669                 return NULL;
670
671         ast_mutex_lock(&chanspy_ds->lock);
672         if (chanspy_ds->chan) {
673                 struct ast_datastore *datastore;
674                 struct ast_channel *chan;
675
676                 chan = chanspy_ds->chan;
677
678                 ast_channel_lock(chan);
679                 if ((datastore = ast_channel_datastore_find(chan, &chanspy_ds_info, chanspy_ds->unique_id))) {
680                         ast_channel_datastore_remove(chan, datastore);
681                         /* chanspy_ds->chan is NULL after this call */
682                         chanspy_ds_destroy(datastore->data);
683                         datastore->data = NULL;
684                         ast_datastore_free(datastore);
685                 }
686                 ast_channel_unlock(chan);
687         }
688         ast_mutex_unlock(&chanspy_ds->lock);
689
690         return NULL;
691 }
692
693 /*! \note Returns the channel in the chanspy_ds locked as well as the chanspy_ds locked */
694 static struct chanspy_ds *setup_chanspy_ds(struct ast_channel *chan, struct chanspy_ds *chanspy_ds)
695 {
696         struct ast_datastore *datastore = NULL;
697
698         ast_mutex_lock(&chanspy_ds->lock);
699
700         if (!(datastore = ast_datastore_alloc(&chanspy_ds_info, chanspy_ds->unique_id))) {
701                 ast_mutex_unlock(&chanspy_ds->lock);
702                 chanspy_ds = chanspy_ds_free(chanspy_ds);
703                 ast_channel_unlock(chan);
704                 return NULL;
705         }
706         
707         chanspy_ds->chan = chan;
708         datastore->data = chanspy_ds;
709         ast_channel_datastore_add(chan, datastore);
710
711         return chanspy_ds;
712 }
713
714 static struct chanspy_ds *next_channel(struct ast_channel *chan,
715         const struct ast_channel *last, const char *spec,
716         const char *exten, const char *context, struct chanspy_ds *chanspy_ds)
717 {
718         struct ast_channel *next;
719         const size_t pseudo_len = strlen("DAHDI/pseudo");
720
721 redo:
722         if (!ast_strlen_zero(spec))
723                 next = ast_walk_channel_by_name_prefix_locked(last, spec, strlen(spec));
724         else if (!ast_strlen_zero(exten))
725                 next = ast_walk_channel_by_exten_locked(last, exten, context);
726         else
727                 next = ast_channel_walk_locked(last);
728
729         if (!next)
730                 return NULL;
731
732         if (!strncmp(next->name, "DAHDI/pseudo", pseudo_len)) {
733                 last = next;
734                 ast_channel_unlock(next);
735                 goto redo;
736         } else if (next == chan) {
737                 last = next;
738                 ast_channel_unlock(next);
739                 goto redo;
740         }
741
742         return setup_chanspy_ds(next, chanspy_ds);
743 }
744
745 static int common_exec(struct ast_channel *chan, struct ast_flags *flags,
746         int volfactor, const int fd, const char *mygroup, const char *myenforced,
747         const char *spec, const char *exten, const char *context, const char *mailbox,
748         const char *name_context)
749 {
750         char nameprefix[AST_NAME_STRLEN];
751         char peer_name[AST_NAME_STRLEN + 5];
752         char exitcontext[AST_MAX_CONTEXT] = "";
753         signed char zero_volume = 0;
754         int waitms;
755         int res;
756         char *ptr;
757         int num;
758         int num_spyed_upon = 1;
759         struct chanspy_ds chanspy_ds = { 0, };
760
761         if (ast_test_flag(flags, OPTION_EXIT)) {
762                 const char *c;
763                 ast_channel_lock(chan);
764                 if ((c = pbx_builtin_getvar_helper(chan, "SPY_EXIT_CONTEXT"))) {
765                         ast_copy_string(exitcontext, c, sizeof(exitcontext));
766                 } else if (!ast_strlen_zero(chan->macrocontext)) {
767                         ast_copy_string(exitcontext, chan->macrocontext, sizeof(exitcontext));
768                 } else {
769                         ast_copy_string(exitcontext, chan->context, sizeof(exitcontext));
770                 }
771                 ast_channel_unlock(chan);
772         }
773
774         ast_mutex_init(&chanspy_ds.lock);
775
776         snprintf(chanspy_ds.unique_id, sizeof(chanspy_ds.unique_id), "%d", ast_atomic_fetchadd_int(&next_unique_id_to_use, +1));
777
778         if (chan->_state != AST_STATE_UP)
779                 ast_answer(chan);
780
781         ast_set_flag(chan, AST_FLAG_SPYING); /* so nobody can spy on us while we are spying */
782
783         waitms = 100;
784
785         for (;;) {
786                 struct chanspy_ds *peer_chanspy_ds = NULL, *next_chanspy_ds = NULL;
787                 struct ast_channel *prev = NULL, *peer = NULL;
788
789                 if (!ast_test_flag(flags, OPTION_QUIET) && num_spyed_upon) {
790                         res = ast_streamfile(chan, "beep", chan->language);
791                         if (!res)
792                                 res = ast_waitstream(chan, "");
793                         else if (res < 0) {
794                                 ast_clear_flag(chan, AST_FLAG_SPYING);
795                                 break;
796                         }
797                         if (!ast_strlen_zero(exitcontext)) {
798                                 char tmp[2];
799                                 tmp[0] = res;
800                                 tmp[1] = '\0';
801                                 if (!ast_goto_if_exists(chan, exitcontext, tmp, 1))
802                                         goto exit;
803                                 else
804                                         ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
805                         }
806                 }
807
808                 res = ast_waitfordigit(chan, waitms);
809                 if (res < 0) {
810                         ast_clear_flag(chan, AST_FLAG_SPYING);
811                         break;
812                 }
813                 if (!ast_strlen_zero(exitcontext)) {
814                         char tmp[2];
815                         tmp[0] = res;
816                         tmp[1] = '\0';
817                         if (!ast_goto_if_exists(chan, exitcontext, tmp, 1))
818                                 goto exit;
819                         else
820                                 ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
821                 }
822
823                 /* reset for the next loop around, unless overridden later */
824                 waitms = 100;
825                 num_spyed_upon = 0;
826
827                 for (peer_chanspy_ds = next_channel(chan, prev, spec, exten, context, &chanspy_ds);
828                      peer_chanspy_ds;
829                          chanspy_ds_free(peer_chanspy_ds), prev = peer,
830                      peer_chanspy_ds = next_chanspy_ds ? next_chanspy_ds : 
831                                 next_channel(chan, prev, spec, exten, context, &chanspy_ds), next_chanspy_ds = NULL) {
832                         const char *group;
833                         int igrp = !mygroup;
834                         char *groups[NUM_SPYGROUPS];
835                         char *mygroups[NUM_SPYGROUPS];
836                         int num_groups = 0;
837                         char dup_group[512];
838                         int num_mygroups = 0;
839                         char *dup_mygroup;
840                         int x;
841                         int y;
842                         char *s;
843                         char *buffer;
844                         char *end;
845                         char *ext;
846                         char *form_enforced;
847                         int ienf = !myenforced;
848
849                         peer = peer_chanspy_ds->chan;
850
851                         ast_mutex_unlock(&peer_chanspy_ds->lock);
852
853                         if (peer == prev) {
854                                 ast_channel_unlock(peer);
855                                 chanspy_ds_free(peer_chanspy_ds);
856                                 break;
857                         }
858
859                         if (ast_check_hangup(chan)) {
860                                 ast_channel_unlock(peer);
861                                 chanspy_ds_free(peer_chanspy_ds);
862                                 break;
863                         }
864
865                         if (ast_test_flag(flags, OPTION_BRIDGED) && !ast_bridged_channel(peer)) {
866                                 ast_channel_unlock(peer);
867                                 continue;
868                         }
869
870                         if (ast_check_hangup(peer) || ast_test_flag(peer, AST_FLAG_SPYING)) {
871                                 ast_channel_unlock(peer);
872                                 continue;
873                         }
874
875                         if (mygroup) {
876                                 dup_mygroup = ast_strdupa(mygroup);
877                                 num_mygroups = ast_app_separate_args(dup_mygroup, ':', mygroups,
878                                         ARRAY_LEN(mygroups));
879
880                                 if ((group = pbx_builtin_getvar_helper(peer, "SPYGROUP"))) {
881                                         ast_copy_string(dup_group, group, sizeof(dup_group));
882                                         num_groups = ast_app_separate_args(dup_group, ':', groups,
883                                                 ARRAY_LEN(groups));
884                                 }
885
886                                 for (y = 0; y < num_mygroups; y++) {
887                                         for (x = 0; x < num_groups; x++) {
888                                                 if (!strcmp(mygroups[y], groups[x])) {
889                                                         igrp = 1;
890                                                         break;
891                                                 }
892                                         }
893                                 }
894                         }
895
896                         if (!igrp) {
897                                 ast_channel_unlock(peer);
898                                 continue;
899                         }
900
901                         if (myenforced) {
902
903                                 /* We don't need to allocate more space than just the
904                                 length of (peer->name) for ext as we will cut the
905                                 channel name's ending before copying into ext */
906
907                                 ext = alloca(strlen(peer->name));
908
909                                 form_enforced = alloca(strlen(myenforced) + 3);
910
911                                 strcpy(form_enforced, ":");
912                                 strcat(form_enforced, myenforced);
913                                 strcat(form_enforced, ":");
914
915                                 buffer = ast_strdupa(peer->name);
916                                 
917                                 if ((end = strchr(buffer, '-'))) {
918                                         *end++ = ':';
919                                         *end = '\0';
920                                 }
921
922                                 strcpy(ext, ":");
923                                 strcat(ext, buffer);
924
925                                 if (strcasestr(form_enforced, ext))
926                                         ienf = 1;
927                         }
928
929                         if (!ienf)
930                                 continue;
931
932                         strcpy(peer_name, "spy-");
933                         strncat(peer_name, peer->name, AST_NAME_STRLEN - 4 - 1);
934                         ptr = strchr(peer_name, '/');
935                         *ptr++ = '\0';
936                         ptr = strsep(&ptr, "-");
937
938                         for (s = peer_name; s < ptr; s++)
939                                 *s = tolower(*s);
940                         /* We have to unlock the peer channel here to avoid a deadlock.
941                          * So, when we need to dereference it again, we have to lock the 
942                          * datastore and get the pointer from there to see if the channel 
943                          * is still valid. */
944                         ast_channel_unlock(peer);
945
946                         if (!ast_test_flag(flags, OPTION_QUIET)) {
947                                 if (ast_test_flag(flags, OPTION_NAME)) {
948                                         const char *local_context = S_OR(name_context, "default");
949                                         const char *local_mailbox = S_OR(mailbox, ptr);
950                                         res = ast_app_sayname(chan, local_mailbox, local_context);
951                                 }
952                                 if (!ast_test_flag(flags, OPTION_NAME) || res < 0) {
953                                         if (!ast_test_flag(flags, OPTION_NOTECH)) {
954                                                 if (ast_fileexists(peer_name, NULL, NULL) != -1) {
955                                                         res = ast_streamfile(chan, peer_name, chan->language);
956                                                         if (!res) {
957                                                                 res = ast_waitstream(chan, "");
958                                                         }
959                                                         if (res) {
960                                                                 chanspy_ds_free(peer_chanspy_ds);
961                                                                 break;
962                                                         }
963                                                 } else {
964                                                         res = ast_say_character_str(chan, peer_name, "", chan->language);
965                                                 }
966                                         }
967                                         if ((num = atoi(ptr)))
968                                                 ast_say_digits(chan, atoi(ptr), "", chan->language);
969                                 }
970                         }
971
972                         res = channel_spy(chan, peer_chanspy_ds, &volfactor, fd, flags, exitcontext);
973                         num_spyed_upon++;       
974
975                         if (res == -1) {
976                                 chanspy_ds_free(peer_chanspy_ds);
977                                 goto exit;
978                         } else if (res == -2) {
979                                 res = 0;
980                                 chanspy_ds_free(peer_chanspy_ds);
981                                 goto exit;
982                         } else if (res > 1 && spec) {
983                                 struct ast_channel *next;
984
985                                 snprintf(nameprefix, AST_NAME_STRLEN, "%s/%d", spec, res);
986
987                                 if ((next = ast_get_channel_by_name_prefix_locked(nameprefix, strlen(nameprefix)))) {
988                                         peer_chanspy_ds = chanspy_ds_free(peer_chanspy_ds);
989                                         next_chanspy_ds = setup_chanspy_ds(next, &chanspy_ds);
990                                 } else {
991                                         /* stay on this channel, if it is still valid */
992
993                                         ast_mutex_lock(&peer_chanspy_ds->lock);
994                                         if (peer_chanspy_ds->chan) {
995                                                 ast_channel_lock(peer_chanspy_ds->chan);
996                                                 next_chanspy_ds = peer_chanspy_ds;
997                                                 peer_chanspy_ds = NULL;
998                                         } else {
999                                                 /* the channel is gone */
1000                                                 ast_mutex_unlock(&peer_chanspy_ds->lock);
1001                                                 next_chanspy_ds = NULL;
1002                                         }
1003                                 }
1004
1005                                 peer = NULL;
1006                         }
1007                 }
1008                 if (res == -1 || ast_check_hangup(chan))
1009                         break;
1010         }
1011 exit:
1012
1013         ast_clear_flag(chan, AST_FLAG_SPYING);
1014
1015         ast_channel_setoption(chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);
1016
1017         ast_mutex_lock(&chanspy_ds.lock);
1018         ast_mutex_unlock(&chanspy_ds.lock);
1019         ast_mutex_destroy(&chanspy_ds.lock);
1020
1021         return res;
1022 }
1023
1024 static int chanspy_exec(struct ast_channel *chan, void *data)
1025 {
1026         char *myenforced = NULL;
1027         char *mygroup = NULL;
1028         char *recbase = NULL;
1029         int fd = 0;
1030         struct ast_flags flags;
1031         int oldwf = 0;
1032         int volfactor = 0;
1033         int res;
1034         char *mailbox = NULL;
1035         char *name_context = NULL;
1036         AST_DECLARE_APP_ARGS(args,
1037                 AST_APP_ARG(spec);
1038                 AST_APP_ARG(options);
1039         );
1040         char *opts[OPT_ARG_ARRAY_SIZE];
1041
1042         data = ast_strdupa(data);
1043         AST_STANDARD_APP_ARGS(args, data);
1044
1045         if (args.spec && !strcmp(args.spec, "all"))
1046                 args.spec = NULL;
1047
1048         if (args.options) {
1049                 ast_app_parse_options(spy_opts, &flags, opts, args.options);
1050                 if (ast_test_flag(&flags, OPTION_GROUP))
1051                         mygroup = opts[OPT_ARG_GROUP];
1052
1053                 if (ast_test_flag(&flags, OPTION_RECORD) &&
1054                         !(recbase = opts[OPT_ARG_RECORD]))
1055                         recbase = "chanspy";
1056
1057                 if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) {
1058                         int vol;
1059
1060                         if ((sscanf(opts[OPT_ARG_VOLUME], "%d", &vol) != 1) || (vol > 4) || (vol < -4))
1061                                 ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n");
1062                         else
1063                                 volfactor = vol;
1064                 }
1065
1066                 if (ast_test_flag(&flags, OPTION_PRIVATE))
1067                         ast_set_flag(&flags, OPTION_WHISPER);
1068
1069                 if (ast_test_flag(&flags, OPTION_ENFORCED))
1070                         myenforced = opts[OPT_ARG_ENFORCED];
1071                 
1072                 if (ast_test_flag(&flags, OPTION_NAME)) {
1073                         if (!ast_strlen_zero(opts[OPT_ARG_NAME])) {
1074                                 char *delimiter;
1075                                 if ((delimiter = strchr(opts[OPT_ARG_NAME], '@'))) {
1076                                         mailbox = opts[OPT_ARG_NAME];
1077                                         *delimiter++ = '\0';
1078                                         name_context = delimiter;
1079                                 } else {
1080                                         mailbox = opts[OPT_ARG_NAME];
1081                                 }
1082                         }
1083                 }
1084
1085
1086         } else
1087                 ast_clear_flag(&flags, AST_FLAGS_ALL);
1088
1089         oldwf = chan->writeformat;
1090         if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
1091                 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
1092                 return -1;
1093         }
1094
1095         if (recbase) {
1096                 char filename[PATH_MAX];
1097
1098                 snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL));
1099                 if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, AST_FILE_MODE)) <= 0) {
1100                         ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename);
1101                         fd = 0;
1102                 }
1103         }
1104
1105         res = common_exec(chan, &flags, volfactor, fd, mygroup, myenforced, args.spec, NULL, NULL, mailbox, name_context);
1106
1107         if (fd)
1108                 close(fd);
1109
1110         if (oldwf && ast_set_write_format(chan, oldwf) < 0)
1111                 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
1112
1113         return res;
1114 }
1115
1116 static int extenspy_exec(struct ast_channel *chan, void *data)
1117 {
1118         char *ptr, *exten = NULL;
1119         char *mygroup = NULL;
1120         char *recbase = NULL;
1121         int fd = 0;
1122         struct ast_flags flags;
1123         int oldwf = 0;
1124         int volfactor = 0;
1125         int res;
1126         char *mailbox = NULL;
1127         char *name_context = NULL;
1128         AST_DECLARE_APP_ARGS(args,
1129                 AST_APP_ARG(context);
1130                 AST_APP_ARG(options);
1131         );
1132
1133         data = ast_strdupa(data);
1134
1135         AST_STANDARD_APP_ARGS(args, data);
1136         if (!ast_strlen_zero(args.context) && (ptr = strchr(args.context, '@'))) {
1137                 exten = args.context;
1138                 *ptr++ = '\0';
1139                 args.context = ptr;
1140         }
1141
1142         if (ast_strlen_zero(args.context))
1143                 args.context = ast_strdupa(chan->context);
1144
1145         if (args.options) {
1146                 char *opts[OPT_ARG_ARRAY_SIZE];
1147
1148                 ast_app_parse_options(spy_opts, &flags, opts, args.options);
1149                 if (ast_test_flag(&flags, OPTION_GROUP))
1150                         mygroup = opts[OPT_ARG_GROUP];
1151
1152                 if (ast_test_flag(&flags, OPTION_RECORD) &&
1153                         !(recbase = opts[OPT_ARG_RECORD]))
1154                         recbase = "chanspy";
1155
1156                 if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) {
1157                         int vol;
1158
1159                         if ((sscanf(opts[OPT_ARG_VOLUME], "%d", &vol) != 1) || (vol > 4) || (vol < -4))
1160                                 ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n");
1161                         else
1162                                 volfactor = vol;
1163                 }
1164
1165                 if (ast_test_flag(&flags, OPTION_PRIVATE))
1166                         ast_set_flag(&flags, OPTION_WHISPER);
1167
1168                 
1169                 if (ast_test_flag(&flags, OPTION_NAME)) {
1170                         if (!ast_strlen_zero(opts[OPT_ARG_NAME])) {
1171                                 char *delimiter;
1172                                 if ((delimiter = strchr(opts[OPT_ARG_NAME], '@'))) {
1173                                         mailbox = opts[OPT_ARG_NAME];
1174                                         *delimiter++ = '\0';
1175                                         name_context = delimiter;
1176                                 } else {
1177                                         mailbox = opts[OPT_ARG_NAME];
1178                                 }
1179                         }
1180                 }
1181
1182         } else
1183                 ast_clear_flag(&flags, AST_FLAGS_ALL);
1184
1185         oldwf = chan->writeformat;
1186         if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
1187                 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
1188                 return -1;
1189         }
1190
1191         if (recbase) {
1192                 char filename[PATH_MAX];
1193
1194                 snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL));
1195                 if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, AST_FILE_MODE)) <= 0) {
1196                         ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename);
1197                         fd = 0;
1198                 }
1199         }
1200
1201
1202         res = common_exec(chan, &flags, volfactor, fd, mygroup, NULL, NULL, exten, args.context, mailbox, name_context);
1203
1204         if (fd)
1205                 close(fd);
1206
1207         if (oldwf && ast_set_write_format(chan, oldwf) < 0)
1208                 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
1209
1210         return res;
1211 }
1212
1213 static int unload_module(void)
1214 {
1215         int res = 0;
1216
1217         res |= ast_unregister_application(app_chan);
1218         res |= ast_unregister_application(app_ext);
1219
1220         return res;
1221 }
1222
1223 static int load_module(void)
1224 {
1225         int res = 0;
1226
1227         res |= ast_register_application_xml(app_chan, chanspy_exec);
1228         res |= ast_register_application_xml(app_ext, extenspy_exec);
1229
1230         return res;
1231 }
1232
1233 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Listen to the audio of an active channel");