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