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