Use tabs instead of spaces (I <3 tabs -- this is for you Qwell)
[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 - 2006, 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  *
27  * \ingroup applications
28  */
29
30 #include "asterisk.h"
31
32 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
33
34 #include <stdlib.h>
35 #include <stdio.h>
36 #include <string.h>
37 #include <unistd.h>
38 #include <ctype.h>
39
40 #include "asterisk/file.h"
41 #include "asterisk/logger.h"
42 #include "asterisk/channel.h"
43 #include "asterisk/chanspy.h"
44 #include "asterisk/features.h"
45 #include "asterisk/options.h"
46 #include "asterisk/app.h"
47 #include "asterisk/utils.h"
48 #include "asterisk/say.h"
49 #include "asterisk/pbx.h"
50 #include "asterisk/translate.h"
51 #include "asterisk/module.h"
52 #include "asterisk/lock.h"
53
54 #define AST_NAME_STRLEN 256
55
56 static const char *tdesc = "Listen to a channel, and optionally whisper into it";
57 static const char *app_chan = "ChanSpy";
58 static const char *desc_chan = 
59 "  ChanSpy([chanprefix][|options]): This application is used to listen to the\n"
60 "audio from an Asterisk channel. This includes the audio coming in and\n"
61 "out of the channel being spied on. If the 'chanprefix' parameter is specified,\n"
62 "only channels beginning with this string will be spied upon.\n"
63 "  While spying, the following actions may be performed:\n"
64 "    - Dialing # cycles the volume level.\n"
65 "    - Dialing * will stop spying and look for another channel to spy on.\n"
66 "    - Dialing a series of digits followed by # builds a channel name to append\n"
67 "      to 'chanprefix'. For example, executing ChanSpy(Agent) and then dialing\n"
68 "      the digits '1234#' while spying will begin spying on the channel\n"
69 "      'Agent/1234'.\n"
70 "  Options:\n"
71 "    b             - Only spy on channels involved in a bridged call.\n"
72 "    g(grp)        - Match only channels where their ${SPYGROUP} variable is set to\n"
73 "                    contain 'grp' in an optional : delimited list.\n"
74 "    q             - Don't play a beep when beginning to spy on a channel, or speak the\n"
75 "                    selected channel name.\n"
76 "    r[(basename)] - Record the session to the monitor spool directory. An\n"
77 "                    optional base for the filename may be specified. The\n"
78 "                    default is 'chanspy'.\n"
79 "    v([value])    - Adjust the initial volume in the range from -4 to 4. A\n"
80 "                    negative value refers to a quieter setting.\n"
81 "    w             - Enable 'whisper' mode, so the spying channel can talk to\n"
82 "                    the spied-on channel.\n"
83 "    W             - Enable 'private whisper' mode, so the spying channel can\n"
84 "                    talk to the spied-on channel but cannot listen to that\n"
85 "                    channel.\n"
86 ;
87
88 static const char *app_ext = "ExtenSpy";
89 static const char *desc_ext = 
90 "  ExtenSpy(exten[@context][|options]): This application is used to listen to the\n"
91 "audio from an Asterisk channel. This includes the audio coming in and\n"
92 "out of the channel being spied on. Only channels created by outgoing calls for the\n"
93 "specified extension will be selected for spying. If the optional context is not\n"
94 "supplied, the current channel's context will be used.\n"
95 "  While spying, the following actions may be performed:\n"
96 "    - Dialing # cycles the volume level.\n"
97 "    - Dialing * will stop spying and look for another channel to spy on.\n"
98 "  Options:\n"
99 "    b             - Only spy on channels involved in a bridged call.\n"
100 "    g(grp)        - Match only channels where their ${SPYGROUP} variable is set to\n"
101 "                    contain 'grp' in an optional : delimited list.\n"
102 "    q             - Don't play a beep when beginning to spy on a channel, or speak the\n"
103 "                    selected channel name.\n"
104 "    r[(basename)] - Record the session to the monitor spool directory. An\n"
105 "                    optional base for the filename may be specified. The\n"
106 "                    default is 'chanspy'.\n"
107 "    v([value])    - Adjust the initial volume in the range from -4 to 4. A\n"
108 "                    negative value refers to a quieter setting.\n"
109 "    w             - Enable 'whisper' mode, so the spying channel can talk to\n"
110 "                    the spied-on channel.\n"
111 "    W             - Enable 'private whisper' mode, so the spying channel can\n"
112 "                    talk to the spied-on channel but cannot listen to that\n"
113 "                    channel.\n"
114 ;
115
116 enum {
117         OPTION_QUIET     = (1 << 0),    /* Quiet, no announcement */
118         OPTION_BRIDGED   = (1 << 1),    /* Only look at bridged calls */
119         OPTION_VOLUME    = (1 << 2),    /* Specify initial volume */
120         OPTION_GROUP     = (1 << 3),    /* Only look at channels in group */
121         OPTION_RECORD    = (1 << 4),
122         OPTION_WHISPER   = (1 << 5),
123         OPTION_PRIVATE   = (1 << 6),    /* Private Whisper mode */
124 } chanspy_opt_flags;
125
126 enum {
127         OPT_ARG_VOLUME = 0,
128         OPT_ARG_GROUP,
129         OPT_ARG_RECORD,
130         OPT_ARG_ARRAY_SIZE,
131 } chanspy_opt_args;
132
133 AST_APP_OPTIONS(spy_opts, {
134         AST_APP_OPTION('q', OPTION_QUIET),
135         AST_APP_OPTION('b', OPTION_BRIDGED),
136         AST_APP_OPTION('w', OPTION_WHISPER),
137         AST_APP_OPTION('W', OPTION_PRIVATE),
138         AST_APP_OPTION_ARG('v', OPTION_VOLUME, OPT_ARG_VOLUME),
139         AST_APP_OPTION_ARG('g', OPTION_GROUP, OPT_ARG_GROUP),
140         AST_APP_OPTION_ARG('r', OPTION_RECORD, OPT_ARG_RECORD),
141 });
142
143
144 struct chanspy_translation_helper {
145         /* spy data */
146         struct ast_channel_spy spy;
147         int fd;
148         int volfactor;
149 };
150
151 static void *spy_alloc(struct ast_channel *chan, void *data)
152 {
153         /* just store the data pointer in the channel structure */
154         return data;
155 }
156
157 static void spy_release(struct ast_channel *chan, void *data)
158 {
159         /* nothing to do */
160 }
161
162 static int spy_generate(struct ast_channel *chan, void *data, int len, int samples) 
163 {
164         struct chanspy_translation_helper *csth = data;
165         struct ast_frame *f;
166                 
167         if (csth->spy.status != CHANSPY_RUNNING)
168                 /* Channel is already gone more than likely */
169                 return -1;
170
171         ast_mutex_lock(&csth->spy.lock);
172         f = ast_channel_spy_read_frame(&csth->spy, samples);
173         ast_mutex_unlock(&csth->spy.lock);
174                 
175         if (!f)
176                 return 0;
177                 
178         if (ast_write(chan, f)) {
179                 ast_frfree(f);
180                 return -1;
181         }
182
183         if (csth->fd)
184                 write(csth->fd, f->data, f->datalen);
185
186         ast_frfree(f);
187
188         return 0;
189 }
190
191 static struct ast_generator spygen = {
192         .alloc = spy_alloc,
193         .release = spy_release,
194         .generate = spy_generate, 
195 };
196
197 static int start_spying(struct ast_channel *chan, struct ast_channel *spychan, struct ast_channel_spy *spy) 
198 {
199         int res;
200         struct ast_channel *peer;
201
202         ast_log(LOG_NOTICE, "Attaching %s to %s\n", spychan->name, chan->name);
203
204         ast_channel_lock(chan);
205         res = ast_channel_spy_add(chan, spy);
206         ast_channel_unlock(chan);
207
208         if (!res && ast_test_flag(chan, AST_FLAG_NBRIDGE) && (peer = ast_bridged_channel(chan)))
209                 ast_softhangup(peer, AST_SOFTHANGUP_UNBRIDGE);  
210
211         return res;
212 }
213
214 /* Map 'volume' levels from -4 through +4 into
215    decibel (dB) settings for channel drivers
216 */
217 static signed char volfactor_map[] = {
218         -24,
219         -18,
220         -12,
221         -6,
222         0,
223         6,
224         12,
225         18,
226         24,
227 };
228
229 /* attempt to set the desired gain adjustment via the channel driver;
230    if successful, clear it out of the csth structure so the
231    generator will not attempt to do the adjustment itself
232 */
233 static void set_volume(struct ast_channel *chan, struct chanspy_translation_helper *csth)
234 {
235         signed char volume_adjust = volfactor_map[csth->volfactor + 4];
236
237         if (!ast_channel_setoption(chan, AST_OPTION_TXGAIN, &volume_adjust, sizeof(volume_adjust), 0))
238                 csth->volfactor = 0;
239         csth->spy.read_vol_adjustment = csth->volfactor;
240         csth->spy.write_vol_adjustment = csth->volfactor;
241 }
242
243 static int channel_spy(struct ast_channel *chan, struct ast_channel *spyee, int *volfactor, int fd,
244                        const struct ast_flags *flags) 
245 {
246         struct chanspy_translation_helper csth;
247         int running = 0, res, x = 0;
248         char inp[24] = {0};
249         char *name;
250         struct ast_frame *f;
251         struct ast_silence_generator *silgen = NULL;
252
253         if (ast_check_hangup(chan) || ast_check_hangup(spyee))
254                 return 0;
255
256         name = ast_strdupa(spyee->name);
257         if (option_verbose >= 2)
258                 ast_verbose(VERBOSE_PREFIX_2 "Spying on channel %s\n", name);
259
260         memset(&csth, 0, sizeof(csth));
261         ast_set_flag(&csth.spy, CHANSPY_FORMAT_AUDIO);
262         ast_set_flag(&csth.spy, CHANSPY_TRIGGER_NONE);
263         ast_set_flag(&csth.spy, CHANSPY_MIXAUDIO);
264         csth.spy.type = "ChanSpy";
265         csth.spy.status = CHANSPY_RUNNING;
266         csth.spy.read_queue.format = AST_FORMAT_SLINEAR;
267         csth.spy.write_queue.format = AST_FORMAT_SLINEAR;
268         ast_mutex_init(&csth.spy.lock);
269         csth.volfactor = *volfactor;
270         set_volume(chan, &csth);
271         csth.fd = fd;
272         
273         if (start_spying(spyee, chan, &csth.spy)) {
274                 ast_mutex_destroy(&csth.spy.lock);
275                 return 0;
276         }
277
278         if (ast_test_flag(flags, OPTION_WHISPER)) {
279                 struct ast_filestream *beepstream;
280
281                 ast_channel_whisper_start(csth.spy.chan);
282                 if ((beepstream = ast_openstream_full(chan, "beep", chan->language, 1))) {
283                         struct ast_frame *f;
284
285                         while ((f = ast_readframe(beepstream))) {
286                                 ast_channel_whisper_feed(csth.spy.chan, f);
287                                 ast_frfree(f);
288                         }
289
290                         ast_closestream(beepstream);
291                 }
292         }
293
294         if (ast_test_flag(flags, OPTION_PRIVATE))
295                 silgen = ast_channel_start_silence_generator(chan);
296         else
297                 ast_activate_generator(chan, &spygen, &csth);
298
299         /* We can no longer rely on 'spyee' being an actual channel;
300            it can be hung up and freed out from under us. However, the
301            channel destructor will put NULL into our csth.spy.chan
302            field when that happens, so that is our signal that the spyee
303            channel has gone away.
304         */
305
306         /* Note: it is very important that the ast_waitfor() be the first
307            condition in this expression, so that if we wait for some period
308            of time before receiving a frame from our spying channel, we check
309            for hangup on the spied-on channel _after_ knowing that a frame
310            has arrived, since the spied-on channel could have gone away while
311            we were waiting
312         */
313         while ((res = ast_waitfor(chan, -1) > -1) &&
314                csth.spy.status == CHANSPY_RUNNING &&
315                csth.spy.chan) {
316                 if (!(f = ast_read(chan)) || ast_check_hangup(chan)) {
317                         running = -1;
318                         break;
319                 }
320
321                 if (ast_test_flag(flags, OPTION_WHISPER) &&
322                     (f->frametype == AST_FRAME_VOICE)) {
323                         ast_channel_whisper_feed(csth.spy.chan, f);
324                         ast_frfree(f);
325                         continue;
326                 }
327
328                 res = (f->frametype == AST_FRAME_DTMF) ? f->subclass : 0;
329                 ast_frfree(f);
330                 if (!res)
331                         continue;
332
333                 if (x == sizeof(inp))
334                         x = 0;
335
336                 if (res < 0) {
337                         running = -1;
338                         break;
339                 }
340
341                 if (res == '*') {
342                         running = 0;
343                         break;
344                 } else if (res == '#') {
345                         if (!ast_strlen_zero(inp)) {
346                                 running = atoi(inp);
347                                 break;
348                         }
349
350                         (*volfactor)++;
351                         if (*volfactor > 4)
352                                 *volfactor = -4;
353                         if (option_verbose > 2)
354                                 ast_verbose(VERBOSE_PREFIX_3 "Setting spy volume on %s to %d\n", chan->name, *volfactor);
355                         csth.volfactor = *volfactor;
356                         set_volume(chan, &csth);
357                 } else if (res >= '0' && res <= '9') {
358                         inp[x++] = res;
359                 }
360         }
361
362         if (ast_test_flag(flags, OPTION_WHISPER) && csth.spy.chan)
363                 ast_channel_whisper_stop(csth.spy.chan);
364
365         if (ast_test_flag(flags, OPTION_PRIVATE))
366                 ast_channel_stop_silence_generator(chan, silgen);
367         else
368                 ast_deactivate_generator(chan);
369
370         /* If a channel still exists on our spy structure then we need to remove ourselves */
371         if (csth.spy.chan) {
372                 csth.spy.status = CHANSPY_DONE;
373                 ast_channel_spy_remove(csth.spy.chan, &csth.spy);
374         }
375         ast_channel_spy_free(&csth.spy);
376         
377         if (option_verbose >= 2)
378                 ast_verbose(VERBOSE_PREFIX_2 "Done Spying on channel %s\n", name);
379         
380         return running;
381 }
382
383 static struct ast_channel *next_channel(const struct ast_channel *last, const char *spec,
384                                         const char *exten, const char *context)
385 {
386         struct ast_channel *this;
387
388         redo:
389         if (spec)
390                 this = ast_walk_channel_by_name_prefix_locked(last, spec, strlen(spec));
391         else if (exten)
392                 this = ast_walk_channel_by_exten_locked(last, exten, context);
393         else
394                 this = ast_channel_walk_locked(last);
395
396         if (this) {
397                 ast_channel_unlock(this);
398                 if (!strncmp(this->name, "Zap/pseudo", 10))
399                         goto redo;
400         }
401
402         return this;
403 }
404
405 static int common_exec(struct ast_channel *chan, const struct ast_flags *flags,
406                        int volfactor, const int fd, const char *mygroup, const char *spec,
407                        const char *exten, const char *context)
408 {
409         struct ast_channel *peer, *prev, *next;
410         char nameprefix[AST_NAME_STRLEN];
411         char peer_name[AST_NAME_STRLEN + 5];
412         signed char zero_volume = 0;
413         int waitms;
414         int res;
415         char *ptr;
416         int num;
417
418         if (chan->_state != AST_STATE_UP)
419                 ast_answer(chan);
420
421         ast_set_flag(chan, AST_FLAG_SPYING); /* so nobody can spy on us while we are spying */
422
423         waitms = 100;
424
425         for (;;) {
426                 if (!ast_test_flag(flags, OPTION_QUIET)) {
427                         res = ast_streamfile(chan, "beep", chan->language);
428                         if (!res)
429                                 res = ast_waitstream(chan, "");
430                         else if (res < 0) {
431                                 ast_clear_flag(chan, AST_FLAG_SPYING);
432                                 break;
433                         }
434                 }
435
436                 res = ast_waitfordigit(chan, waitms);
437                 if (res < 0) {
438                         ast_clear_flag(chan, AST_FLAG_SPYING);
439                         break;
440                 }
441                                 
442                 /* reset for the next loop around, unless overridden later */
443                 waitms = 100;
444                 peer = prev = next = NULL;
445
446                 for (peer = next_channel(peer, spec, exten, context);
447                      peer;
448                      prev = peer, peer = next ? next : next_channel(peer, spec, exten, context), next = NULL) {
449                         const char *group;
450                         int igrp = !mygroup;
451                         char *groups[25];
452                         int num_groups = 0;
453                         char *dup_group;
454                         int x;
455                         char *s;
456                                 
457                         if (peer == prev)
458                                 break;
459
460                         if (peer == chan)
461                                 continue;
462
463                         if (ast_test_flag(flags, OPTION_BRIDGED) && !ast_bridged_channel(peer))
464                                 continue;
465
466                         if (ast_check_hangup(peer) || ast_test_flag(peer, AST_FLAG_SPYING))
467                                 continue;
468
469                         if (mygroup) {
470                                 if ((group = pbx_builtin_getvar_helper(peer, "SPYGROUP"))) {
471                                         dup_group = ast_strdupa(group);
472                                         num_groups = ast_app_separate_args(dup_group, ':', groups,
473                                                                            sizeof(groups) / sizeof(groups[0]));
474                                 }
475                                 
476                                 for (x = 0; x < num_groups; x++) {
477                                         if (!strcmp(mygroup, groups[x])) {
478                                                 igrp = 1;
479                                                 break;
480                                         }
481                                 }
482                         }
483                         
484                         if (!igrp)
485                                 continue;
486
487                         strcpy(peer_name, "spy-");
488                         strncat(peer_name, peer->name, AST_NAME_STRLEN);
489                         ptr = strchr(peer_name, '/');
490                         *ptr++ = '\0';
491                         
492                         for (s = peer_name; s < ptr; s++)
493                                 *s = tolower(*s);
494                         
495                         if (!ast_test_flag(flags, OPTION_QUIET)) {
496                                 if (ast_fileexists(peer_name, NULL, NULL) != -1) {
497                                         res = ast_streamfile(chan, peer_name, chan->language);
498                                         if (!res)
499                                                 res = ast_waitstream(chan, "");
500                                         if (res)
501                                                 break;
502                                 } else
503                                         res = ast_say_character_str(chan, peer_name, "", chan->language);
504                                 if ((num = atoi(ptr))) 
505                                         ast_say_digits(chan, atoi(ptr), "", chan->language);
506                         }
507                         
508                         waitms = 5000;
509                         res = channel_spy(chan, peer, &volfactor, fd, flags);
510                         
511                         if (res == -1) {
512                                 break;
513                         } else if (res > 1 && spec) {
514                                 snprintf(nameprefix, AST_NAME_STRLEN, "%s/%d", spec, res);
515                                 if ((next = ast_get_channel_by_name_prefix_locked(nameprefix, strlen(nameprefix)))) {
516                                         ast_channel_unlock(next);
517                                 } else {
518                                         /* stay on this channel */
519                                         next = peer;
520                                 }
521                                 peer = NULL;
522                         }
523                 }
524                 if (res == -1)
525                         break;
526         }
527         
528         ast_clear_flag(chan, AST_FLAG_SPYING);
529
530         ast_channel_setoption(chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);
531
532         return res;
533 }
534
535 static int chanspy_exec(struct ast_channel *chan, void *data)
536 {
537         struct ast_module_user *u;
538         char *options = NULL;
539         char *spec = NULL;
540         char *argv[2];
541         char *mygroup = NULL;
542         char *recbase = NULL;
543         int fd = 0;
544         struct ast_flags flags;
545         int oldwf = 0;
546         int argc = 0;
547         int volfactor = 0;
548         int res;
549
550         data = ast_strdupa(data);
551
552         u = ast_module_user_add(chan);
553
554         if ((argc = ast_app_separate_args(data, '|', argv, sizeof(argv) / sizeof(argv[0])))) {
555                 spec = argv[0];
556                 if (argc > 1)
557                         options = argv[1];
558
559                 if (ast_strlen_zero(spec) || !strcmp(spec, "all"))
560                         spec = NULL;
561         }
562
563         if (options) {
564                 char *opts[OPT_ARG_ARRAY_SIZE];
565                 
566                 ast_app_parse_options(spy_opts, &flags, opts, options);
567                 if (ast_test_flag(&flags, OPTION_GROUP))
568                         mygroup = opts[OPT_ARG_GROUP];
569
570                 if (ast_test_flag(&flags, OPTION_RECORD) &&
571                     !(recbase = opts[OPT_ARG_RECORD]))
572                         recbase = "chanspy";
573
574                 if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) {
575                         int vol;
576
577                         if ((sscanf(opts[OPT_ARG_VOLUME], "%d", &vol) != 1) || (vol > 4) || (vol < -4))
578                                 ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n");
579                         else
580                                 volfactor = vol;
581                 }
582
583                 if (ast_test_flag(&flags, OPTION_PRIVATE))
584                         ast_set_flag(&flags, OPTION_WHISPER);
585         }
586
587         oldwf = chan->writeformat;
588         if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
589                 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
590                 ast_module_user_remove(u);
591                 return -1;
592         }
593
594         if (recbase) {
595                 char filename[512];
596
597                 snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL));
598                 if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0644)) <= 0) {
599                         ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename);
600                         fd = 0;
601                 }
602         }
603
604         res = common_exec(chan, &flags, volfactor, fd, mygroup, spec, NULL, NULL);
605
606         if (fd)
607                 close(fd);
608
609         if (oldwf && ast_set_write_format(chan, oldwf) < 0)
610                 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
611
612         ast_module_user_remove(u);
613
614         return res;
615 }
616
617 static int extenspy_exec(struct ast_channel *chan, void *data)
618 {
619         struct ast_module_user *u;
620         char *options = NULL;
621         char *exten = NULL;
622         char *context = NULL;
623         char *argv[2];
624         char *mygroup = NULL;
625         char *recbase = NULL;
626         int fd = 0;
627         struct ast_flags flags;
628         int oldwf = 0;
629         int argc = 0;
630         int volfactor = 0;
631         int res;
632
633         data = ast_strdupa(data);
634
635         u = ast_module_user_add(chan);
636
637         if ((argc = ast_app_separate_args(data, '|', argv, sizeof(argv) / sizeof(argv[0])))) {
638                 context = argv[0];
639                 exten = strsep(&context, "@");
640                 if (ast_strlen_zero(context))
641                         context = ast_strdupa(chan->context);
642                 if (argc > 1)
643                         options = argv[1];
644         }
645
646         if (options) {
647                 char *opts[OPT_ARG_ARRAY_SIZE];
648                 
649                 ast_app_parse_options(spy_opts, &flags, opts, options);
650                 if (ast_test_flag(&flags, OPTION_GROUP))
651                         mygroup = opts[OPT_ARG_GROUP];
652
653                 if (ast_test_flag(&flags, OPTION_RECORD) &&
654                     !(recbase = opts[OPT_ARG_RECORD]))
655                         recbase = "chanspy";
656
657                 if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) {
658                         int vol;
659
660                         if ((sscanf(opts[OPT_ARG_VOLUME], "%d", &vol) != 1) || (vol > 4) || (vol < -4))
661                                 ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n");
662                         else
663                                 volfactor = vol;
664                 }
665
666                 if (ast_test_flag(&flags, OPTION_PRIVATE))
667                         ast_set_flag(&flags, OPTION_WHISPER);
668         }
669
670         oldwf = chan->writeformat;
671         if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
672                 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
673                 ast_module_user_remove(u);
674                 return -1;
675         }
676
677         if (recbase) {
678                 char filename[512];
679
680                 snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL));
681                 if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0644)) <= 0) {
682                         ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename);
683                         fd = 0;
684                 }
685         }
686
687         res = common_exec(chan, &flags, volfactor, fd, mygroup, NULL, exten, context);
688
689         if (fd)
690                 close(fd);
691
692         if (oldwf && ast_set_write_format(chan, oldwf) < 0)
693                 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
694
695         ast_module_user_remove(u);
696
697         return res;
698 }
699
700 static int unload_module(void)
701 {
702         int res = 0;
703
704         res |= ast_unregister_application(app_chan);
705         res |= ast_unregister_application(app_ext);
706
707         ast_module_user_hangup_all();
708
709         return res;
710 }
711
712 static int load_module(void)
713 {
714         int res = 0;
715
716         res |= ast_register_application(app_chan, chanspy_exec, tdesc, desc_chan);
717         res |= ast_register_application(app_ext, extenspy_exec, tdesc, desc_ext);
718
719         return res;
720 }
721
722 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Listen to the audio of an active channel");