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