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