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