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