use double-quotes instead of angle-brackets for non-system include files (bug #4058)
[asterisk/asterisk.git] / apps / app_chanspy.c
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * ChanSpy Listen in on any channel.
5  * 
6  * Copyright (C) 2005 Anthony Minessale II (anthmct@yahoo.com)
7  *
8  * Disclaimed to Digium
9  *
10  * This program is free software, distributed under the terms of
11  * the GNU General Public License
12  */
13
14 #include <stdlib.h>
15 #include <unistd.h>
16 #include <string.h>
17 #include <ctype.h>
18
19 #include "asterisk.h"
20 #include "asterisk/file.h"
21 #include "asterisk/logger.h"
22 #include "asterisk/channel.h"
23 #include "asterisk/features.h"
24 #include "asterisk/options.h"
25 #include "asterisk/app.h"
26 #include "asterisk/utils.h"
27 #include "asterisk/say.h"
28 #include "asterisk/pbx.h"
29 #include "asterisk/translate.h"
30 #include "asterisk/module.h"
31 #include "asterisk/lock.h"
32
33 #define AST_MONITOR_DIR AST_SPOOL_DIR "/monitor"
34
35 AST_MUTEX_DEFINE_STATIC(modlock);
36
37 #define ast_fit_in_short(in) (in < -32768 ? -32768 : in > 32767 ? 32767 : in)
38 #define AST_NAME_STRLEN 256
39 #define ALL_DONE(u, ret) LOCAL_USER_REMOVE(u); return ret;
40 #define get_volfactor(x) x ? ((x > 0) ? (1 << x) : ((1 << abs(x)) * -1)) : 0
41 #define minmax(x,y) x ? (x > y) ? y : ((x < (y * -1)) ? (y * -1) : x) : 0
42
43
44 static char *synopsis = "Tap into any type of asterisk channel and listen to audio";
45 static char *app = "ChanSpy";
46 static char *desc = "   Chanspy([<scanspec>][|<options>])\n\n"
47 "Valid Options:\n"
48 " - q: quiet, don't announce channels beep, etc.\n"
49 " - b: bridged, only spy on channels involved in a bridged call.\n"
50 " - v([-4..4]): adjust the initial volume. (negative is quieter)\n"
51 " - g(grp): enforce group.  Match only calls where their ${SPYGROUP} is 'grp'.\n"
52 " - r[(basename)]: Record session to monitor spool dir (with optional basename, default is 'chanspy')\n\n"
53 "If <scanspec> is specified, only channel names *beginning* with that string will be scanned.\n"
54 "('all' or an empty string are also both valid <scanspec>)\n\n"
55 "While Spying:\n\n"
56 "Dialing # cycles the volume level.\n"
57 "Dialing * will stop spying and look for another channel to spy on.\n"
58 "Dialing a series of digits followed by # builds a channel name to append to <scanspec>\n"
59 "(e.g. run Chanspy(Agent) and dial 1234# while spying to jump to channel Agent/1234)\n\n"
60 "";
61
62 #define OPTION_QUIET     (1 << 0)       /* Quiet, no announcement */
63 #define OPTION_BRIDGED   (1 << 1)       /* Only look at bridged calls */
64 #define OPTION_VOLUME    (1 << 2)       /* Specify initial volume */
65 #define OPTION_GROUP     (1 << 3)   /* Only look at channels in group */
66 #define OPTION_RECORD    (1 << 4)   /* Record */
67
68 AST_DECLARE_OPTIONS(chanspy_opts,{
69         ['q'] = { OPTION_QUIET },
70         ['b'] = { OPTION_BRIDGED },
71         ['v'] = { OPTION_VOLUME, 1 },
72         ['g'] = { OPTION_GROUP, 2 },
73         ['r'] = { OPTION_RECORD, 3 },
74 });
75
76 STANDARD_LOCAL_USER;
77 LOCAL_USER_DECL;
78
79 struct chanspy_translation_helper {
80         /* spy data */
81         struct ast_channel_spy spy;
82
83         /* read frame */
84         int fmt0;
85         short *buf0;
86         int len0;
87         struct ast_trans_pvt *trans0;
88
89         /* write frame */
90         int fmt1;
91         struct ast_trans_pvt *trans1;
92         short *buf1;
93         int len1;
94
95         /* muxed frame */
96         struct ast_frame frame;
97         short *buf;
98         int len;
99         
100         int samples;
101         int rsamples;
102         int volfactor;
103         int fd;
104 };
105
106 /* Prototypes */
107 static struct ast_channel *local_get_channel_by_name(char *name);
108 static struct ast_channel *local_get_channel_begin_name(char *name);
109 static struct ast_channel *local_channel_walk(struct ast_channel *chan);
110 static void spy_release(struct ast_channel *chan, void *data);
111 static void *spy_alloc(struct ast_channel *chan, void *params);
112 static struct ast_frame *spy_queue_shift(struct ast_channel_spy *spy, int qnum);
113 static void ast_flush_spy_queue(struct ast_channel_spy *spy);
114 static int spy_generate(struct ast_channel *chan, void *data, int len, int samples);
115 static void start_spying(struct ast_channel *chan, struct ast_channel *spychan, struct ast_channel_spy *spy);
116 static void stop_spying(struct ast_channel *chan, struct ast_channel_spy *spy);
117 static int channel_spy(struct ast_channel *chan, struct ast_channel *spyee, int *volfactor, int fd);
118 static int chanspy_exec(struct ast_channel *chan, void *data);
119
120
121 static struct ast_channel *local_get_channel_by_name(char *name) 
122 {
123         struct ast_channel *ret;
124         ast_mutex_lock(&modlock);
125         if ((ret = ast_get_channel_by_name_locked(name))) {
126                 ast_mutex_unlock(&ret->lock);
127         }
128         ast_mutex_unlock(&modlock);
129
130         return ret;
131 }
132
133 static struct ast_channel *local_channel_walk(struct ast_channel *chan) 
134 {
135         struct ast_channel *ret;
136         ast_mutex_lock(&modlock);       
137         if ((ret = ast_channel_walk_locked(chan))) {
138                 ast_mutex_unlock(&ret->lock);
139         }
140         ast_mutex_unlock(&modlock);                     
141         return ret;
142 }
143
144 static struct ast_channel *local_get_channel_begin_name(char *name) 
145 {
146         struct ast_channel *chan, *ret = NULL;
147         ast_mutex_lock(&modlock);
148         chan = local_channel_walk(NULL);
149         while (chan) {
150                 if (!strncmp(chan->name, name, strlen(name))) {
151                         ret = chan;
152                         break;
153                 }
154                 chan = local_channel_walk(chan);
155         }
156         ast_mutex_unlock(&modlock);
157         
158         return ret;
159 }
160
161
162 static void spy_release(struct ast_channel *chan, void *data) 
163 {
164         struct chanspy_translation_helper *csth = data;
165
166
167         if (csth->trans0) {
168                 ast_translator_free_path(csth->trans0);
169                 csth->trans0 = NULL;
170         }
171         if (csth->trans1) {
172                 ast_translator_free_path(csth->trans1);
173                 csth->trans1 = NULL;
174         }
175
176         if (csth->buf0) {
177                 free(csth->buf0);
178                 csth->buf0 = NULL;
179         }
180         if (csth->buf1) {
181                 free(csth->buf1);
182                 csth->buf1 = NULL;
183         }
184         if (csth->buf) {
185                 free(csth->buf);
186                 csth->buf = NULL;
187         }
188         return;
189 }
190
191 static void *spy_alloc(struct ast_channel *chan, void *params) 
192 {
193         return params;
194 }
195
196 static struct ast_frame *spy_queue_shift(struct ast_channel_spy *spy, int qnum) 
197 {
198         struct ast_frame *f;
199         
200         if (qnum < 0 || qnum > 1)
201                 return NULL;
202
203         f = spy->queue[qnum];
204         if (f) {
205                 spy->queue[qnum] = f->next;
206                 return f;
207         }
208         return NULL;
209 }
210
211
212 static void ast_flush_spy_queue(struct ast_channel_spy *spy) 
213 {
214         struct ast_frame *f=NULL;
215         int x = 0;
216         ast_mutex_lock(&spy->lock);
217         for(x=0;x<2;x++) {
218                 f = NULL;
219                 while((f = spy_queue_shift(spy, x))) 
220                         ast_frfree(f);
221         }
222         ast_mutex_unlock(&spy->lock);
223 }
224
225 static int spy_generate(struct ast_channel *chan, void *data, int len, int samples) 
226 {
227         struct ast_frame *f, *f0, *f1;
228         int x, vf, dlen, maxsamp, loops;
229         struct chanspy_translation_helper *csth = data;
230
231         if (csth->rsamples < csth->samples) {
232                 csth->rsamples += samples;
233                 return 0;
234         } 
235         csth->rsamples += samples;
236         loops = 0;
237         do {
238                 loops++;
239                 f = f0 = f1 = NULL;
240                 x = vf = dlen = maxsamp = 0;
241                 if (csth->rsamples == csth->samples) {
242                         csth->rsamples = csth->samples = 0;
243                 }
244
245                 ast_mutex_lock(&csth->spy.lock);
246                 f0 = spy_queue_shift(&csth->spy, 0);
247                 f1 = spy_queue_shift(&csth->spy, 1);
248                 ast_mutex_unlock(&csth->spy.lock);
249
250                 if (csth->spy.status == CHANSPY_DONE) {
251                         return -1;
252                 }
253         
254                 if (!f0 && !f1) {
255                         return 0;
256                 }
257
258                 if (f0 && csth->fmt0 && csth->fmt0 != f0->subclass) {
259                         ast_translator_free_path(csth->trans0);
260                         csth->trans0 = NULL;
261                         csth->fmt0 = f0->subclass;
262                 }
263
264                 if (f1 && csth->fmt1 && csth->fmt1 != f1->subclass) {
265                         ast_translator_free_path(csth->trans1);
266                         csth->trans1 = NULL;
267                         csth->fmt1 = f1->subclass;
268                 }
269         
270                 if (!csth->fmt0 && f0) {
271                         csth->fmt0 = f0->subclass;
272                 }
273
274                 if (!csth->fmt1 && f1) {
275                         csth->fmt1 = f1->subclass;
276                 }
277
278                 if (csth->fmt0 && csth->fmt0 != AST_FORMAT_SLINEAR && !csth->trans0) {
279                         if ((csth->trans0 = ast_translator_build_path(AST_FORMAT_SLINEAR, csth->fmt0)) == NULL) {
280                                 ast_log(LOG_WARNING, "Cannot build a path from %s to slin\n", ast_getformatname(csth->fmt0));
281                                 csth->spy.status = CHANSPY_DONE;
282                                 return -1;
283                         }
284                 }
285                 if (csth->fmt1 && csth->fmt1 != AST_FORMAT_SLINEAR && !csth->trans1) {
286                         if ((csth->trans1 = ast_translator_build_path(AST_FORMAT_SLINEAR, csth->fmt1)) == NULL) {
287                                 ast_log(LOG_WARNING, "Cannot build a path from %s to slin\n", ast_getformatname(csth->fmt1));
288                                 csth->spy.status = CHANSPY_DONE;
289                                 return -1;
290                         }
291                 }
292         
293                 if (f0) {
294                         if (csth->trans0) {
295                                 if ((f = ast_translate(csth->trans0, f0, 0))) {
296                                         if (csth->len0 < f->datalen) {
297                                                 if (!csth->len0) {
298                                                         if (!(csth->buf0 = malloc(f->datalen * 2))) {
299                                                                 csth->spy.status = CHANSPY_DONE;
300                                                                 return -1;
301                                                         }
302                                                 } else {
303                                                         if (!realloc(csth->buf0, f->datalen * 2)) {
304                                                                 csth->spy.status = CHANSPY_DONE;
305                                                                 return -1;
306                                                         }
307                                                 }
308                                                 csth->len0 = f->datalen;
309                                         }
310                                         memcpy(csth->buf0, f->data, f->datalen);
311                                         maxsamp = f->samples;
312                                         ast_frfree(f);
313                                 } else {
314                                         return 0;
315                                 }
316                         } else {
317                                 if (csth->len0 < f0->datalen) {
318                                         if (!csth->len0) {
319                                                 if (!(csth->buf0 = malloc(f0->datalen * 2))) {
320                                                         csth->spy.status = CHANSPY_DONE;
321                                                         return -1;
322                                                 }
323                                         } else {
324                                                 if (!realloc(csth->buf0, f0->datalen * 2)) {
325                                                         csth->spy.status = CHANSPY_DONE;
326                                                         return -1;
327                                                 }
328                                         }
329                                         csth->len0 = f0->datalen;
330                                 }
331                                 memcpy(csth->buf0, f0->data, f0->datalen);
332                                 maxsamp = f0->samples;
333                         }
334                 }
335         
336                 if (f1) {
337                         if (csth->trans1) {
338                                 if ((f = ast_translate(csth->trans1, f1, 0))) {
339                                         if (csth->len1 < f->datalen) {
340                                                 if (!csth->len1) {
341                                                         if (!(csth->buf1 = malloc(f->datalen * 2))) {
342                                                                 csth->spy.status = CHANSPY_DONE;
343                                                                 return -1;
344                                                         }
345                                                 } else {
346                                                         if (!realloc(csth->buf1, f->datalen * 2)) {
347                                                                 csth->spy.status = CHANSPY_DONE;
348                                                                 return -1;
349                                                         }
350                                                 }
351                                                 csth->len1 = f->datalen;
352                                         }
353                                         memcpy(csth->buf1, f->data, f->datalen);
354                                         if (f->samples > maxsamp) {
355                                                 maxsamp = f->samples;
356                                         }
357                                         ast_frfree(f);
358                                 
359                                 } else {
360                                         return 0;
361                                 }
362                         } else {
363                                 if (csth->len1 < f1->datalen) {
364                                         if (!csth->len1) {
365                                                 if (!(csth->buf1 = malloc(f1->datalen * 2))) {
366                                                         csth->spy.status = CHANSPY_DONE;
367                                                         return -1;
368                                                 }
369                                         } else {
370                                                 if (!realloc(csth->buf1, f1->datalen * 2)) {
371                                                         csth->spy.status = CHANSPY_DONE;
372                                                         return -1;
373                                                 }
374                                         }
375                                         csth->len1 = f1->datalen;
376                                 }
377                                 memcpy(csth->buf1, f1->data, f1->datalen);
378                                 if (f1->samples > maxsamp) {
379                                         maxsamp = f1->samples;
380                                 }
381                         }
382                 }
383
384                 vf = get_volfactor(csth->volfactor);
385                 vf = minmax(vf, 16);
386
387                 dlen = (csth->len0 > csth->len1) ? csth->len0 : csth->len1;
388
389                 if (csth->len < dlen) {
390                         if (!csth->len) {
391                                 if (!(csth->buf = malloc(dlen*2))) {
392                                         csth->spy.status = CHANSPY_DONE;
393                                         return -1;
394                                 }
395                         } else {
396                                 if (!realloc(csth->buf, dlen * 2)) {
397                                         csth->spy.status = CHANSPY_DONE;
398                                         return -1;
399                                 }
400                         }
401                         csth->len = dlen;
402                 }
403
404                 for(x=0; x < maxsamp; x++) {
405                         if (vf < 0) {
406                                 if (f0) {
407                                         csth->buf0[x] /= abs(vf);
408                                 }
409                                 if (f1) {
410                                         csth->buf1[x] /= abs(vf);
411                                 }
412                         } else if (vf > 0) {
413                                 if (f0) {
414                                         csth->buf0[x] *= vf;
415                                 }
416                                 if (f1) {
417                                         csth->buf1[x] *= vf;
418                                 }
419                         }
420                         if (f0 && f1) {
421                                 if (x < csth->len0 && x < csth->len1) {
422                                         csth->buf[x] = ast_fit_in_short(csth->buf0[x] + csth->buf1[x]);
423                                 } else if (x < csth->len0) {
424                                         csth->buf[x] = csth->buf0[x];
425                                 } else if (x < csth->len1) {
426                                         csth->buf[x] = csth->buf1[x];
427                                 }
428                         } else if (f0 && x < csth->len0) {
429                                 csth->buf[x] = csth->buf0[x];
430                         } else if (f1 && x < csth->len1) {
431                                 csth->buf[x] = csth->buf1[x];
432                         }
433                 }
434
435                 csth->frame.data = csth->buf;
436                 csth->frame.samples = maxsamp;
437                 csth->frame.datalen = csth->frame.samples * 2;
438                 csth->samples += csth->frame.samples;
439                 
440                 if (ast_write(chan, &csth->frame)) {
441                         csth->spy.status = CHANSPY_DONE;
442                         return -1;
443                 }
444                 if (csth->fd) {
445                         write(csth->fd, csth->frame.data, csth->frame.datalen);
446                 }
447
448                 if (f0) {
449                         ast_frfree(f0);
450                 }
451                 if (f1) {
452                         ast_frfree(f1);
453                 }
454
455                 if (loops > 10) {
456                         ast_log(LOG_WARNING, "Too Many Loops Bailing Out....");
457                         break;
458                 }
459         } while (csth->samples <  csth->rsamples);
460
461         return 0;
462 }
463
464 static struct ast_generator spygen = {
465     alloc: spy_alloc, 
466     release: spy_release, 
467     generate: spy_generate, 
468 };
469
470 static void start_spying(struct ast_channel *chan, struct ast_channel *spychan, struct ast_channel_spy *spy) 
471 {
472
473         struct ast_channel_spy *cptr=NULL;
474         struct ast_channel *peer;
475
476
477         ast_log(LOG_WARNING, "Attaching %s to %s\n", spychan->name, chan->name);
478
479
480         ast_mutex_lock(&chan->lock);
481         if (chan->spiers) {
482                 for(cptr=chan->spiers;cptr && cptr->next;cptr=cptr->next);
483                 cptr->next = spy;
484         } else {
485                 chan->spiers = spy;
486         }
487         ast_mutex_unlock(&chan->lock);
488         if ( ast_test_flag(chan, AST_FLAG_NBRIDGE) && (peer = ast_bridged_channel(chan))) {
489                 ast_softhangup(peer, AST_SOFTHANGUP_UNBRIDGE);  
490         }
491
492 }
493
494 static void stop_spying(struct ast_channel *chan, struct ast_channel_spy *spy) 
495 {
496         struct ast_channel_spy *cptr=NULL, *prev=NULL;
497         int count = 0;
498
499         while(ast_mutex_trylock(&chan->lock)) {
500                 /* if its locked already it's almost surely hanging up and we are too late 
501                    we can safely remove the head pointer if it points at us without needing a lock.
502                    since everybody spying will be in the same boat whomever is pointing at the head
503                    will surely erase it which is all we really need since it's a linked list of
504                    staticly declared structs that belong to each spy.
505                 */
506                 if (chan->spiers == spy) {
507                         chan->spiers = NULL;
508                         return;
509                 }
510                 count++;
511                 if (count > 10) {
512                         return;
513                 }
514                 sched_yield();
515         }
516
517         for(cptr=chan->spiers; cptr; cptr=cptr->next) {
518                 if (cptr == spy) {
519                         if (prev) {
520                                 prev->next = cptr->next;
521                                 cptr->next = NULL;
522                         } else
523                                 chan->spiers = NULL;
524                 }
525                 prev = cptr;
526         }
527         ast_mutex_unlock(&chan->lock);
528
529 }
530
531 static int channel_spy(struct ast_channel *chan, struct ast_channel *spyee, int *volfactor, int fd) 
532 {
533         struct chanspy_translation_helper csth;
534         int running = 1, res = 0, x = 0;
535         char inp[24];
536         char *name=NULL;
537         struct ast_frame *f;
538
539         if (chan && !ast_check_hangup(chan) && spyee && !ast_check_hangup(spyee)) {
540                 memset(inp, 0, sizeof(inp));
541                 name = ast_strdupa(spyee->name);
542                 if (option_verbose >= 2)
543                         ast_verbose(VERBOSE_PREFIX_2 "Spying on channel %s\n", name);
544
545                 memset(&csth, 0, sizeof(csth));
546                 csth.spy.status = CHANSPY_RUNNING;
547                 ast_mutex_init(&csth.spy.lock);
548                 csth.volfactor = *volfactor;
549                 csth.frame.frametype = AST_FRAME_VOICE;
550                 csth.frame.subclass = AST_FORMAT_SLINEAR;
551                 csth.frame.datalen = 320;
552                 csth.frame.samples = 160;
553                 if (fd) {
554                         csth.fd = fd;
555                 }
556                 start_spying(spyee, chan, &csth.spy);
557                 ast_activate_generator(chan, &spygen, &csth);
558
559                 while(csth.spy.status == CHANSPY_RUNNING && 
560                           chan && !ast_check_hangup(chan) && 
561                           spyee && 
562                           !ast_check_hangup(spyee) 
563                           && running == 1 && 
564                           (res = ast_waitfor(chan, -1) > -1)) {
565                         if ((f = ast_read(chan))) {
566                                 res = 0;
567                                 if (f->frametype == AST_FRAME_DTMF) {
568                                         res = f->subclass;
569                                 }
570                                 ast_frfree(f);
571                                 if (!res) {
572                                         continue;
573                                 }
574                         } else {
575                                 break;
576                         }
577                         if (x == sizeof(inp)) {
578                                 x = 0;
579                         }
580                         if (res < 0) {
581                                 running = -1;
582                         }
583                         if (res == 0) {
584                                 continue;
585                         } else if (res == '*') {
586                                 running = 0; 
587                         } else if (res == '#') {
588                                 if (!ast_strlen_zero(inp)) {
589                                         running = x ? atoi(inp) : -1;
590                                         break;
591                                 } else {
592                                         csth.volfactor++;
593                                         if (csth.volfactor > 4) {
594                                                 csth.volfactor = -4;
595                                         }
596                                         if (option_verbose > 2) {
597                                                 ast_verbose(VERBOSE_PREFIX_3"Setting spy volume on %s to %d\n", chan->name, csth.volfactor);
598                                         }
599                                         *volfactor = csth.volfactor;
600                                 }
601                         } else if (res >= 48 && res <= 57) {
602                                 inp[x++] = res;
603                         }
604                 }
605                 ast_deactivate_generator(chan);
606                 stop_spying(spyee, &csth.spy);
607
608                 if (option_verbose >= 2) {
609                         ast_verbose(VERBOSE_PREFIX_2 "Done Spying on channel %s\n", name);
610                 }
611                 ast_flush_spy_queue(&csth.spy);
612         } else {
613                 running = 0;
614         }
615         ast_mutex_destroy(&csth.spy.lock);
616         return running;
617 }
618
619
620
621 static int chanspy_exec(struct ast_channel *chan, void *data)
622 {
623         struct localuser *u;
624         struct ast_channel *peer=NULL, *prev=NULL;
625         char name[AST_NAME_STRLEN],
626                 peer_name[AST_NAME_STRLEN],
627                 *args,
628                 *ptr = NULL,
629                 *options = NULL,
630                 *spec = NULL,
631                 *argv[5],
632                 *mygroup = NULL,
633                 *recbase = NULL;
634         int res = -1,
635                 volfactor = 0,
636                 silent = 0,
637                 argc = 0,
638                 bronly = 0,
639                 chosen = 0,
640                 count=0,
641                 waitms = 100,
642                 num = 0,
643                 oldrf = 0,
644                 oldwf = 0,
645                 fd = 0;
646         struct ast_flags flags;
647
648
649         if (!(args = ast_strdupa((char *)data))) {
650                 ast_log(LOG_ERROR, "Out of memory!\n");
651                 return -1;
652         }
653
654         oldrf = chan->readformat;
655         oldwf = chan->writeformat;
656         if (ast_set_read_format(chan, AST_FORMAT_SLINEAR) < 0) {
657                 ast_log(LOG_ERROR, "Could Not Set Read Format.\n");
658                 return -1;
659         }
660         
661         if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
662                 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
663                 return -1;
664         }
665
666         LOCAL_USER_ADD(u);
667         ast_answer(chan);
668
669         ast_set_flag(chan, AST_FLAG_SPYING); /* so nobody can spy on us while we are spying */
670
671
672         if ((argc = ast_separate_app_args(args, '|', argv, sizeof(argv) / sizeof(argv[0])))) {
673                 spec = argv[0];
674                 if ( argc > 1) {
675                         options = argv[1];
676                 }
677                 if (ast_strlen_zero(spec) || !strcmp(spec, "all")) {
678                         spec = NULL;
679                 }
680         }
681         
682         if (options) {
683                 char *opts[3];
684                 ast_parseoptions(chanspy_opts, &flags, opts, options);
685                 if (ast_test_flag(&flags, OPTION_GROUP)) {
686                         mygroup = opts[1];
687                 }
688                 if (ast_test_flag(&flags, OPTION_RECORD)) {
689                         if (!(recbase = opts[2])) {
690                                 recbase = "chanspy";
691                         }
692                 }
693                 silent = ast_test_flag(&flags, OPTION_QUIET);
694                 bronly = ast_test_flag(&flags, OPTION_BRIDGED);
695                 if (ast_test_flag(&flags, OPTION_VOLUME) && opts[1]) {
696                         if (sscanf(opts[0], "%d", &volfactor) != 1)
697                                 ast_log(LOG_NOTICE, "volfactor must be a number between -4 and 4\n");
698                         else {
699                                 volfactor = minmax(volfactor, 4);
700                         }
701                 }
702         }
703
704         if (recbase) {
705                 char filename[512];
706                 snprintf(filename,sizeof(filename),"%s/%s.%ld.raw",AST_MONITOR_DIR, recbase, time(NULL));
707                 if ((fd = open(filename, O_CREAT | O_WRONLY, O_TRUNC)) <= 0) {
708                         ast_log(LOG_WARNING, "Cannot open %s for recording\n", filename);
709                         fd = 0;
710                 }
711         }
712
713         for(;;) {
714                 res = ast_streamfile(chan, "beep", chan->language);
715                 if (!res)
716                         res = ast_waitstream(chan, "");
717                 if (res < 0) {
718                         ast_clear_flag(chan, AST_FLAG_SPYING);
719                         break;
720                 }                       
721
722                 count = 0;
723                 res = ast_waitfordigit(chan, waitms);
724                 if (res < 0) {
725                         ast_clear_flag(chan, AST_FLAG_SPYING);
726                         break;
727                 }
728                                 
729                 peer = local_channel_walk(NULL);
730                 prev=NULL;
731                 while(peer) {
732                         if (peer != chan) {
733                                 char *group = NULL;
734                                 int igrp = 1;
735
736                                 if (peer == prev && !chosen) {
737                                         break;
738                                 }
739                                 chosen = 0;
740                                 group = pbx_builtin_getvar_helper(peer, "SPYGROUP");
741                                 if (mygroup) {
742                                         if (!group || strcmp(mygroup, group)) {
743                                                 igrp = 0;
744                                         }
745                                 }
746                                 
747                                 if (igrp && (!spec || ((strlen(spec) < strlen(peer->name) &&
748                                                                            !strncasecmp(peer->name, spec, strlen(spec)))))) {
749                                         if (peer && (!bronly || ast_bridged_channel(peer)) &&
750                                                 !ast_check_hangup(peer) && !ast_test_flag(peer, AST_FLAG_SPYING)) {
751                                                 int x = 0;
752
753                                                 strncpy(peer_name, peer->name, AST_NAME_STRLEN);
754                                                 ptr = strchr(peer_name, '/');
755                                                 *ptr = '\0';
756                                                 ptr++;
757                                                 for (x = 0 ; x < strlen(peer_name) ; x++) {
758                                                         if (peer_name[x] == '/') {
759                                                                 break;
760                                                         }
761                                                         peer_name[x] = tolower(peer_name[x]);
762                                                 }
763
764                                                 if (!silent) {
765                                                         if (ast_fileexists(peer_name, NULL, NULL) != -1) {
766                                                                 res = ast_streamfile(chan, peer_name, chan->language);
767                                                                 if (!res)
768                                                                         res = ast_waitstream(chan, "");
769                                                                 if (res)
770                                                                         break;
771                                                         } else
772                                                                 res = ast_say_character_str(chan, peer_name, "", chan->language);
773                                                         if ((num=atoi(ptr))) 
774                                                                 ast_say_digits(chan, atoi(ptr), "", chan->language);
775                                                 }
776                                                 count++;
777                                                 prev = peer;
778                                                 res = channel_spy(chan, peer, &volfactor, fd);
779                                                 if (res == -1) {
780                                                         break;
781                                                 } else if (res > 1 && spec) {
782                                                         snprintf(name, AST_NAME_STRLEN, "%s/%d", spec, res);
783                                                         if ((peer = local_get_channel_begin_name(name))) {
784                                                                 chosen = 1;
785                                                         }
786                                                         continue;
787                                                 }
788                                         }
789                                 }
790                         }
791                         if ((peer = local_channel_walk(peer)) == NULL) {
792                                 break;
793                         }
794                 }
795                 waitms = count ? 100 : 5000;
796         }
797         
798
799         if (fd > 0) {
800                 close(fd);
801         }
802
803         if (oldrf && ast_set_read_format(chan, oldrf) < 0) {
804                 ast_log(LOG_ERROR, "Could Not Set Read Format.\n");
805         }
806         
807         if (oldwf && ast_set_write_format(chan, oldwf) < 0) {
808                 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
809         }
810
811         ast_clear_flag(chan, AST_FLAG_SPYING);
812         ALL_DONE(u, res);
813 }
814
815 int unload_module(void)
816 {
817         STANDARD_HANGUP_LOCALUSERS;
818         return ast_unregister_application(app);
819 }
820
821 int load_module(void)
822 {
823         return ast_register_application(app, chanspy_exec, synopsis, desc);
824 }
825
826 char *description(void)
827 {
828         return synopsis;
829 }
830
831 int usecount(void)
832 {
833         int res;
834         STANDARD_USECOUNT(res);
835         return res;
836 }
837
838 char *key()
839 {
840         return ASTERISK_GPL_KEY;
841 }