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