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