0bf6768919b85bf9a41c2e66f73f3cd4069c09c2
[asterisk/asterisk.git] / apps / app_chanspy.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2005 Anthony Minessale II (anthmct@yahoo.com)
5  * Copyright (C) 2005 - 2006, Digium, Inc.
6  *
7  * A license has been granted to Digium (via disclaimer) for the use of
8  * this code.
9  *
10  * See http://www.asterisk.org for more information about
11  * the Asterisk project. Please do not directly contact
12  * any of the maintainers of this project for assistance;
13  * the project provides a web site, mailing lists and IRC
14  * channels for your use.
15  *
16  * This program is free software, distributed under the terms of
17  * the GNU General Public License Version 2. See the LICENSE file
18  * at the top of the source tree.
19  */
20
21 /*! \file
22  *
23  * \brief ChanSpy: Listen in on any channel.
24  *
25  * \author Anthony Minessale II <anthmct@yahoo.com>
26  *
27  * \ingroup applications
28  */
29
30 #include "asterisk.h"
31
32 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
33
34 #include <ctype.h>
35
36 #include "asterisk/paths.h" /* use ast_config_AST_MONITOR_DIR */
37 #include "asterisk/file.h"
38 #include "asterisk/channel.h"
39 #include "asterisk/audiohook.h"
40 #include "asterisk/features.h"
41 #include "asterisk/app.h"
42 #include "asterisk/utils.h"
43 #include "asterisk/say.h"
44 #include "asterisk/pbx.h"
45 #include "asterisk/translate.h"
46 #include "asterisk/module.h"
47 #include "asterisk/lock.h"
48
49 #define AST_NAME_STRLEN 256
50
51 static const char *tdesc = "Listen to a channel, and optionally whisper into it";
52 static const char *app_chan = "ChanSpy";
53 static const char *desc_chan =
54 "  ChanSpy([chanprefix][,options]): This application is used to listen to the\n"
55 "audio from an Asterisk channel. This includes the audio coming in and\n"
56 "out of the channel being spied on. If the 'chanprefix' parameter is specified,\n"
57 "only channels beginning with this string will be spied upon.\n"
58 "  While spying, the following actions may be performed:\n"
59 "    - Dialing # cycles the volume level.\n"
60 "    - Dialing * will stop spying and look for another channel to spy on.\n"
61 "    - Dialing a series of digits followed by # builds a channel name to append\n"
62 "      to 'chanprefix'. For example, executing ChanSpy(Agent) and then dialing\n"
63 "      the digits '1234#' while spying will begin spying on the channel\n"
64 "      'Agent/1234'.\n"
65 "  Note: The X option supersedes the three features above in that if a valid\n"
66 "        single digit extension exists in the correct context ChanSpy will\n"
67 "        exit to it. This also disables choosing a channel based on 'chanprefix'\n"
68 "        and a digit sequence.\n"
69 "  Options:\n"
70 "    b             - Only spy on channels involved in a bridged call.\n"
71 "    g(grp)        - Match only channels where their SPYGROUP variable is set to\n"
72 "                    contain 'grp' in an optional : delimited list.\n"
73 "    q             - Don't play a beep when beginning to spy on a channel, or speak the\n"
74 "                    selected channel name.\n"
75 "    r[(basename)] - Record the session to the monitor spool directory. An\n"
76 "                    optional base for the filename may be specified. The\n"
77 "                    default is 'chanspy'.\n"
78 "    v([value])    - Adjust the initial volume in the range from -4 to 4. A\n"
79 "                    negative value refers to a quieter setting.\n"
80 "    w             - Enable 'whisper' mode, so the spying channel can talk to\n"
81 "                    the spied-on channel.\n"
82 "    W             - Enable 'private whisper' mode, so the spying channel can\n"
83 "                    talk to the spied-on channel but cannot listen to that\n"
84 "                    channel.\n"
85 "    o             - Only listen to audio coming from this channel.\n"
86 "    X             - Allow the user to exit ChanSpy to a valid single digit\n"
87 "                    numeric extension in the current context or the context\n"
88 "                    specified by the SPY_EXIT_CONTEXT channel variable. The\n"
89 "                    name of the last channel that was spied on will be stored\n"
90 "                    in the SPY_CHANNEL variable.\n"
91 "    e(ext)        - Enable 'enforced' mode, so the spying channel can\n"
92 "                    only monitor extensions whose name is in the 'ext' : \n"
93 "                    delimited list.\n"
94 ;
95
96 static const char *app_ext = "ExtenSpy";
97 static const char *desc_ext =
98 "  ExtenSpy(exten[@context][,options]): This application is used to listen to the\n"
99 "audio from an Asterisk channel. This includes the audio coming in and\n"
100 "out of the channel being spied on. Only channels created by outgoing calls for the\n"
101 "specified extension will be selected for spying. If the optional context is not\n"
102 "supplied, the current channel's context will be used.\n"
103 "  While spying, the following actions may be performed:\n"
104 "    - Dialing # cycles the volume level.\n"
105 "    - Dialing * will stop spying and look for another channel to spy on.\n"
106 "  Note: The X option superseeds the two features above in that if a valid\n"
107 "        single digit extension exists in the correct context it ChanSpy will\n"
108 "        exit to it.\n"
109 "  Options:\n"
110 "    b             - Only spy on channels involved in a bridged call.\n"
111 "    g(grp)        - Match only channels where their ${SPYGROUP} variable is set to\n"
112 "                    contain 'grp' in an optional : delimited list.\n"
113 "    q             - Don't play a beep when beginning to spy on a channel, or speak the\n"
114 "                    selected channel name.\n"
115 "    r[(basename)] - Record the session to the monitor spool directory. An\n"
116 "                    optional base for the filename may be specified. The\n"
117 "                    default is 'chanspy'.\n"
118 "    v([value])    - Adjust the initial volume in the range from -4 to 4. A\n"
119 "                    negative value refers to a quieter setting.\n"
120 "    w             - Enable 'whisper' mode, so the spying channel can talk to\n"
121 "                    the spied-on channel.\n"
122 "    W             - Enable 'private whisper' mode, so the spying channel can\n"
123 "                    talk to the spied-on channel but cannot listen to that\n"
124 "                    channel.\n"
125 "    o             - Only listen to audio coming from this channel.\n"
126 "    X             - Allow the user to exit ChanSpy to a valid single digit\n"
127 "                    numeric extension in the current context or the context\n"
128 "                    specified by the SPY_EXIT_CONTEXT channel variable. The\n"
129 "                    name of the last channel that was spied on will be stored\n"
130 "                    in the SPY_CHANNEL variable.\n"
131 ;
132
133 enum {
134         OPTION_QUIET     = (1 << 0),    /* Quiet, no announcement */
135         OPTION_BRIDGED   = (1 << 1),    /* Only look at bridged calls */
136         OPTION_VOLUME    = (1 << 2),    /* Specify initial volume */
137         OPTION_GROUP     = (1 << 3),    /* Only look at channels in group */
138         OPTION_RECORD    = (1 << 4),
139         OPTION_WHISPER   = (1 << 5),
140         OPTION_PRIVATE   = (1 << 6),    /* Private Whisper mode */
141         OPTION_READONLY  = (1 << 7),    /* Don't mix the two channels */
142         OPTION_EXIT      = (1 << 8),    /* Exit to a valid single digit extension */
143         OPTION_ENFORCED  = (1 << 9),    /* Enforced mode */
144 } chanspy_opt_flags;
145
146 enum {
147         OPT_ARG_VOLUME = 0,
148         OPT_ARG_GROUP,
149         OPT_ARG_RECORD,
150         OPT_ARG_ENFORCED,
151         OPT_ARG_ARRAY_SIZE,
152 } chanspy_opt_args;
153
154 AST_APP_OPTIONS(spy_opts, {
155         AST_APP_OPTION('q', OPTION_QUIET),
156         AST_APP_OPTION('b', OPTION_BRIDGED),
157         AST_APP_OPTION('w', OPTION_WHISPER),
158         AST_APP_OPTION('W', OPTION_PRIVATE),
159         AST_APP_OPTION_ARG('v', OPTION_VOLUME, OPT_ARG_VOLUME),
160         AST_APP_OPTION_ARG('g', OPTION_GROUP, OPT_ARG_GROUP),
161         AST_APP_OPTION_ARG('r', OPTION_RECORD, OPT_ARG_RECORD),
162         AST_APP_OPTION_ARG('e', OPTION_ENFORCED, OPT_ARG_ENFORCED),
163         AST_APP_OPTION('o', OPTION_READONLY),
164         AST_APP_OPTION('X', OPTION_EXIT),
165 });
166
167
168 struct chanspy_translation_helper {
169         /* spy data */
170         struct ast_audiohook spy_audiohook;
171         struct ast_audiohook whisper_audiohook;
172         int fd;
173         int volfactor;
174 };
175
176 static void *spy_alloc(struct ast_channel *chan, void *data)
177 {
178         /* just store the data pointer in the channel structure */
179         return data;
180 }
181
182 static void spy_release(struct ast_channel *chan, void *data)
183 {
184         /* nothing to do */
185 }
186
187 static int spy_generate(struct ast_channel *chan, void *data, int len, int samples)
188 {
189         struct chanspy_translation_helper *csth = data;
190         struct ast_frame *f = NULL;
191
192         ast_audiohook_lock(&csth->spy_audiohook);
193         if (csth->spy_audiohook.status != AST_AUDIOHOOK_STATUS_RUNNING) {
194                 /* Channel is already gone more than likely */
195                 ast_audiohook_unlock(&csth->spy_audiohook);
196                 return -1;
197         }
198
199         f = ast_audiohook_read_frame(&csth->spy_audiohook, samples, AST_AUDIOHOOK_DIRECTION_BOTH, AST_FORMAT_SLINEAR);
200
201         ast_audiohook_unlock(&csth->spy_audiohook);
202
203         if (!f)
204                 return 0;
205
206         if (ast_write(chan, f)) {
207                 ast_frfree(f);
208                 return -1;
209         }
210
211         if (csth->fd)
212                 write(csth->fd, f->data, f->datalen);
213
214         ast_frfree(f);
215
216         return 0;
217 }
218
219 static struct ast_generator spygen = {
220         .alloc = spy_alloc,
221         .release = spy_release,
222         .generate = spy_generate,
223 };
224
225 static int start_spying(struct ast_channel *chan, const char *spychan_name, struct ast_audiohook *audiohook) 
226 {
227         int res = 0;
228         struct ast_channel *peer = NULL;
229
230         ast_log(LOG_NOTICE, "Attaching %s to %s\n", spychan_name, chan->name);
231
232         res = ast_audiohook_attach(chan, audiohook);
233
234         if (!res && ast_test_flag(chan, AST_FLAG_NBRIDGE) && (peer = ast_bridged_channel(chan))) {
235                 ast_channel_unlock(chan);
236                 ast_softhangup(peer, AST_SOFTHANGUP_UNBRIDGE);
237         } else
238                 ast_channel_unlock(chan);
239
240         return res;
241 }
242
243 struct chanspy_ds {
244         struct ast_channel *chan;
245         ast_mutex_t lock;
246 };
247
248 static int channel_spy(struct ast_channel *chan, struct chanspy_ds *spyee_chanspy_ds, 
249         int *volfactor, int fd, const struct ast_flags *flags, char *exitcontext) 
250 {
251         struct chanspy_translation_helper csth;
252         int running = 0, res, x = 0;
253         char inp[24] = {0};
254         char *name;
255         struct ast_frame *f;
256         struct ast_silence_generator *silgen = NULL;
257         struct ast_channel *spyee = NULL;
258         const char *spyer_name;
259
260         ast_channel_lock(chan);
261         spyer_name = ast_strdupa(chan->name);
262         ast_channel_unlock(chan);
263
264         ast_mutex_lock(&spyee_chanspy_ds->lock);
265         if (spyee_chanspy_ds->chan) {
266                 spyee = spyee_chanspy_ds->chan;
267                 ast_channel_lock(spyee);
268         }
269         ast_mutex_unlock(&spyee_chanspy_ds->lock);
270
271         if (!spyee)
272                 return 0;
273
274         /* We now hold the channel lock on spyee */
275
276         if (ast_check_hangup(chan) || ast_check_hangup(spyee))
277                 return 0;
278
279         name = ast_strdupa(spyee->name);
280         ast_verb(2, "Spying on channel %s\n", name);
281
282         memset(&csth, 0, sizeof(csth));
283
284         ast_audiohook_init(&csth.spy_audiohook, AST_AUDIOHOOK_TYPE_SPY, "ChanSpy");
285
286         if (start_spying(spyee, spyer_name, &csth.spy_audiohook)) { /* Unlocks spyee */
287                 ast_audiohook_destroy(&csth.spy_audiohook);
288                 return 0;
289         }
290
291         if (ast_test_flag(flags, OPTION_WHISPER)) {
292                 ast_audiohook_init(&csth.whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "ChanSpy");
293                 start_spying(spyee, spyer_name, &csth.whisper_audiohook); /* Unlocks spyee */
294         }
295
296         spyee = NULL;
297
298         csth.volfactor = *volfactor;
299
300         if (csth.volfactor) {
301                 csth.spy_audiohook.options.read_volume = csth.volfactor;
302                 csth.spy_audiohook.options.write_volume = csth.volfactor;
303         }
304
305         csth.fd = fd;
306
307         if (ast_test_flag(flags, OPTION_PRIVATE))
308                 silgen = ast_channel_start_silence_generator(chan);
309         else
310                 ast_activate_generator(chan, &spygen, &csth);
311
312         /* We can no longer rely on 'spyee' being an actual channel;
313            it can be hung up and freed out from under us. However, the
314            channel destructor will put NULL into our csth.spy.chan
315            field when that happens, so that is our signal that the spyee
316            channel has gone away.
317         */
318
319         /* Note: it is very important that the ast_waitfor() be the first
320            condition in this expression, so that if we wait for some period
321            of time before receiving a frame from our spying channel, we check
322            for hangup on the spied-on channel _after_ knowing that a frame
323            has arrived, since the spied-on channel could have gone away while
324            we were waiting
325         */
326         while ((res = ast_waitfor(chan, -1) > -1) && csth.spy_audiohook.status == AST_AUDIOHOOK_STATUS_RUNNING) {
327                 if (!(f = ast_read(chan)) || ast_check_hangup(chan)) {
328                         running = -1;
329                         break;
330                 }
331
332                 if (ast_test_flag(flags, OPTION_WHISPER) && f->frametype == AST_FRAME_VOICE) {
333                         ast_audiohook_lock(&csth.whisper_audiohook);
334                         ast_audiohook_write_frame(&csth.whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f);
335                         ast_audiohook_unlock(&csth.whisper_audiohook);
336                         ast_frfree(f);
337                         continue;
338                 }
339                 
340                 res = (f->frametype == AST_FRAME_DTMF) ? f->subclass : 0;
341                 ast_frfree(f);
342                 if (!res)
343                         continue;
344
345                 if (x == sizeof(inp))
346                         x = 0;
347
348                 if (res < 0) {
349                         running = -1;
350                         break;
351                 }
352
353                 if (ast_test_flag(flags, OPTION_EXIT)) {
354                         char tmp[2];
355                         tmp[0] = res;
356                         tmp[1] = '\0';
357                         if (!ast_goto_if_exists(chan, exitcontext, tmp, 1)) {
358                                 ast_debug(1, "Got DTMF %c, goto context %s\n", tmp[0], exitcontext);
359                                 pbx_builtin_setvar_helper(chan, "SPY_CHANNEL", name);
360                                 running = -2;
361                                 break;
362                         } else {
363                                 ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
364                         }
365                 } else if (res >= '0' && res <= '9') {
366                         inp[x++] = res;
367                 }
368
369                 if (res == '*') {
370                         running = 0;
371                         break;
372                 } else if (res == '#') {
373                         if (!ast_strlen_zero(inp)) {
374                                 running = atoi(inp);
375                                 break;
376                         }
377
378                         (*volfactor)++;
379                         if (*volfactor > 4)
380                                 *volfactor = -4;
381                         ast_verb(3, "Setting spy volume on %s to %d\n", chan->name, *volfactor);
382
383                         csth.volfactor = *volfactor;
384                         csth.spy_audiohook.options.read_volume = csth.volfactor;
385                         csth.spy_audiohook.options.write_volume = csth.volfactor;
386                 }
387         }
388
389         if (ast_test_flag(flags, OPTION_PRIVATE))
390                 ast_channel_stop_silence_generator(chan, silgen);
391         else
392                 ast_deactivate_generator(chan);
393
394         if (ast_test_flag(flags, OPTION_WHISPER)) {
395                 ast_audiohook_lock(&csth.whisper_audiohook);
396                 ast_audiohook_detach(&csth.whisper_audiohook);
397                 ast_audiohook_unlock(&csth.whisper_audiohook);
398                 ast_audiohook_destroy(&csth.whisper_audiohook);
399         }
400
401         ast_audiohook_lock(&csth.spy_audiohook);
402         ast_audiohook_detach(&csth.spy_audiohook);
403         ast_audiohook_unlock(&csth.spy_audiohook);
404         ast_audiohook_destroy(&csth.spy_audiohook);
405         
406         ast_verb(2, "Done Spying on channel %s\n", name);
407
408         return running;
409 }
410
411 /*!
412  * \note This relies on the embedded lock to be recursive, as it may be called
413  * due to a call to chanspy_ds_free with the lock held there.
414  */
415 static void chanspy_ds_destroy(void *data)
416 {
417         struct chanspy_ds *chanspy_ds = data;
418
419         /* Setting chan to be NULL is an atomic operation, but we don't want this
420          * value to change while this lock is held.  The lock is held elsewhere
421          * while it performs non-atomic operations with this channel pointer */
422
423         ast_mutex_lock(&chanspy_ds->lock);
424         chanspy_ds->chan = NULL;
425         ast_mutex_unlock(&chanspy_ds->lock);
426 }
427
428 static const struct ast_datastore_info chanspy_ds_info = {
429         .type = "chanspy",
430         .destroy = chanspy_ds_destroy,
431 };
432
433 static struct chanspy_ds *chanspy_ds_free(struct chanspy_ds *chanspy_ds)
434 {
435         if (!chanspy_ds)
436                 return NULL;
437
438         ast_mutex_lock(&chanspy_ds->lock);
439         if (chanspy_ds->chan) {
440                 struct ast_datastore *datastore;
441                 struct ast_channel *chan;
442
443                 chan = chanspy_ds->chan;
444
445                 ast_channel_lock(chan);
446                 if ((datastore = ast_channel_datastore_find(chan, &chanspy_ds_info, NULL))) {
447                         ast_channel_datastore_remove(chan, datastore);
448                         /* chanspy_ds->chan is NULL after this call */
449                         chanspy_ds_destroy(datastore->data);
450                         datastore->data = NULL;
451                         ast_channel_datastore_free(datastore);
452                 }
453                 ast_channel_unlock(chan);
454         }
455         ast_mutex_unlock(&chanspy_ds->lock);
456
457         return NULL;
458 }
459
460 /*! \note Returns the channel in the chanspy_ds locked as well as the chanspy_ds locked */
461 static struct chanspy_ds *setup_chanspy_ds(struct ast_channel *chan, struct chanspy_ds *chanspy_ds)
462 {
463         struct ast_datastore *datastore = NULL;
464
465         ast_mutex_lock(&chanspy_ds->lock);
466
467         chanspy_ds->chan = chan;
468
469         if (!(datastore = ast_channel_datastore_alloc(&chanspy_ds_info, NULL))) {
470                 chanspy_ds = chanspy_ds_free(chanspy_ds);
471                 ast_channel_unlock(chan);
472                 return NULL;
473         }
474
475         datastore->data = chanspy_ds;
476
477         ast_channel_datastore_add(chan, datastore);
478
479         return chanspy_ds;
480 }
481
482 static struct chanspy_ds *next_channel(struct ast_channel *chan,
483         const struct ast_channel *last, const char *spec,
484         const char *exten, const char *context, struct chanspy_ds *chanspy_ds)
485 {
486         struct ast_channel *this;
487
488 redo:
489         if (!ast_strlen_zero(spec))
490                 this = ast_walk_channel_by_name_prefix_locked(last, spec, strlen(spec));
491
492         else if (!ast_strlen_zero(exten))
493                 this = ast_walk_channel_by_exten_locked(last, exten, context);
494         else
495                 this = ast_channel_walk_locked(last);
496
497         if (!this)
498                 return NULL;
499
500         if (!strncmp(this->name, "Zap/pseudo", 10)) {
501                 ast_channel_unlock(this);
502                 goto redo;
503         } else if (this == chan) {
504                 last = this;
505                 ast_channel_unlock(this);
506                 goto redo;
507         }
508
509         return setup_chanspy_ds(this, chanspy_ds);
510 }
511
512 static int common_exec(struct ast_channel *chan, const struct ast_flags *flags,
513         int volfactor, const int fd, const char *mygroup, const char *myenforced,
514         const char *spec, const char *exten, const char *context)
515 {
516         char nameprefix[AST_NAME_STRLEN];
517         char peer_name[AST_NAME_STRLEN + 5];
518         char exitcontext[AST_MAX_CONTEXT] = "";
519         signed char zero_volume = 0;
520         int waitms;
521         int res;
522         char *ptr;
523         int num;
524         int num_spyed_upon = 1;
525         struct chanspy_ds chanspy_ds;
526
527         if (ast_test_flag(flags, OPTION_EXIT)) {
528                 const char *c;
529                 if ((c = pbx_builtin_getvar_helper(chan, "SPY_EXIT_CONTEXT")))
530                         ast_copy_string(exitcontext, c, sizeof(exitcontext));
531                 else if (!ast_strlen_zero(chan->macrocontext))
532                         ast_copy_string(exitcontext, chan->macrocontext, sizeof(exitcontext));
533                 else
534                         ast_copy_string(exitcontext, chan->context, sizeof(exitcontext));
535         }
536
537         ast_mutex_init(&chanspy_ds.lock);
538
539         if (chan->_state != AST_STATE_UP)
540                 ast_answer(chan);
541
542         ast_set_flag(chan, AST_FLAG_SPYING); /* so nobody can spy on us while we are spying */
543
544         waitms = 100;
545
546         for (;;) {
547                 struct chanspy_ds *peer_chanspy_ds = NULL, *next_chanspy_ds = NULL;
548                 struct ast_channel *prev = NULL, *peer = NULL;
549
550                 if (!ast_test_flag(flags, OPTION_QUIET) && num_spyed_upon) {
551                         res = ast_streamfile(chan, "beep", chan->language);
552                         if (!res)
553                                 res = ast_waitstream(chan, "");
554                         else if (res < 0) {
555                                 ast_clear_flag(chan, AST_FLAG_SPYING);
556                                 break;
557                         }
558                         if (!ast_strlen_zero(exitcontext)) {
559                                 char tmp[2];
560                                 tmp[0] = res;
561                                 tmp[1] = '\0';
562                                 if (!ast_goto_if_exists(chan, exitcontext, tmp, 1))
563                                         goto exit;
564                                 else
565                                         ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
566                         }
567                 }
568
569                 res = ast_waitfordigit(chan, waitms);
570                 if (res < 0) {
571                         ast_clear_flag(chan, AST_FLAG_SPYING);
572                         break;
573                 }
574                 if (!ast_strlen_zero(exitcontext)) {
575                         char tmp[2];
576                         tmp[0] = res;
577                         tmp[1] = '\0';
578                         if (!ast_goto_if_exists(chan, exitcontext, tmp, 1))
579                                 goto exit;
580                         else
581                                 ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
582                 }
583
584                 /* reset for the next loop around, unless overridden later */
585                 waitms = 100;
586                 num_spyed_upon = 0;
587
588                 for (peer_chanspy_ds = next_channel(chan, prev, spec, exten, context, &chanspy_ds);
589                      peer_chanspy_ds;
590                          chanspy_ds_free(peer_chanspy_ds), prev = peer,
591                      peer_chanspy_ds = next_chanspy_ds ? next_chanspy_ds : 
592                                 next_channel(chan, prev, spec, exten, context, &chanspy_ds), next_chanspy_ds = NULL) {
593                         const char *group;
594                         int igrp = !mygroup;
595                         char *groups[25];
596                         int num_groups = 0;
597                         char *dup_group;
598                         int x;
599                         char *s;
600                         char *buffer;
601                         char *end;
602                         char *ext;
603                         char *form_enforced;
604                         int ienf = !myenforced;
605                         struct ast_channel *peer;
606
607                         peer = peer_chanspy_ds->chan;
608
609                         ast_mutex_unlock(&peer_chanspy_ds->lock);
610
611                         if (peer == prev) {
612                                 ast_channel_unlock(peer);
613                                 chanspy_ds_free(peer_chanspy_ds);
614                                 break;
615                         }
616
617                         if (ast_check_hangup(chan)) {
618                                 ast_channel_unlock(peer);
619                                 chanspy_ds_free(peer_chanspy_ds);
620                                 break;
621                         }
622
623                         if (ast_test_flag(flags, OPTION_BRIDGED) && !ast_bridged_channel(peer)) {
624                                 ast_channel_unlock(peer);
625                                 continue;
626                         }
627
628                         if (ast_check_hangup(peer) || ast_test_flag(peer, AST_FLAG_SPYING)) {
629                                 ast_channel_unlock(peer);
630                                 continue;
631                         }
632
633                         if (mygroup) {
634                                 if ((group = pbx_builtin_getvar_helper(peer, "SPYGROUP"))) {
635                                         dup_group = ast_strdupa(group);
636                                         num_groups = ast_app_separate_args(dup_group, ':', groups,
637                                                 sizeof(groups) / sizeof(groups[0]));
638                                 }
639
640                                 for (x = 0; x < num_groups; x++) {
641                                         if (!strcmp(mygroup, groups[x])) {
642                                                 igrp = 1;
643                                                 break;
644                                         }
645                                 }
646                         }
647
648                         if (!igrp) {
649                                 ast_channel_unlock(peer);
650                                 continue;
651                         }
652
653                         if (myenforced) {
654
655                                 /* We don't need to allocate more space than just the
656                                 length of (peer->name) for ext as we will cut the
657                                 channel name's ending before copying into ext */
658
659                                 ext = alloca(strlen(peer->name));
660
661                                 form_enforced = alloca(strlen(myenforced) + 3);
662
663                                 strcpy(form_enforced, ":");
664                                 strcat(form_enforced, myenforced);
665                                 strcat(form_enforced, ":");
666
667                                 buffer = ast_strdupa(peer->name);
668                                 
669                                 if ((end = strchr(buffer, '-'))) {
670                                         *end++ = ':';
671                                         *end = '\0';
672                                 }
673
674                                 strcpy(ext, ":");
675                                 strcat(ext, buffer);
676
677                                 if (strcasestr(form_enforced, ext))
678                                         ienf = 1;
679                         }
680
681                         if (!ienf)
682                                 continue;
683
684                         strcpy(peer_name, "spy-");
685                         strncat(peer_name, peer->name, AST_NAME_STRLEN - 4 - 1);
686                         ptr = strchr(peer_name, '/');
687                         *ptr++ = '\0';
688
689                         for (s = peer_name; s < ptr; s++)
690                                 *s = tolower(*s);
691                 
692                         /* We have to unlock the peer channel here to avoid a deadlock.
693                          * So, when we need it again, we have to lock the datastore and get
694                          * the pointer from there to see if the channel is still valid. */
695                         ast_channel_unlock(peer);
696                         peer = NULL;
697
698                         if (!ast_test_flag(flags, OPTION_QUIET)) {
699                                 if (ast_fileexists(peer_name, NULL, NULL) != -1) {
700                                         res = ast_streamfile(chan, peer_name, chan->language);
701                                         if (!res)
702                                                 res = ast_waitstream(chan, "");
703                                         if (res)
704                                                 break;
705                                 } else
706                                         res = ast_say_character_str(chan, peer_name, "", chan->language);
707                                 if ((num = atoi(ptr)))
708                                         ast_say_digits(chan, atoi(ptr), "", chan->language);
709                         }
710
711                         waitms = 5000;
712                         res = channel_spy(chan, peer_chanspy_ds, &volfactor, fd, flags, exitcontext);
713                         num_spyed_upon++;       
714
715                         if (res == -1) {
716                                 chanspy_ds_free(peer_chanspy_ds);
717                                 goto exit;
718                         } else if (res == -2) {
719                                 res = 0;
720                                 goto exit;
721                         } else if (res > 1 && spec) {
722                                 struct ast_channel *next;
723
724                                 snprintf(nameprefix, AST_NAME_STRLEN, "%s/%d", spec, res);
725
726                                 if ((next = ast_get_channel_by_name_prefix_locked(nameprefix, strlen(nameprefix)))) {
727                                         peer_chanspy_ds = chanspy_ds_free(peer_chanspy_ds);
728                                         next_chanspy_ds = setup_chanspy_ds(next, &chanspy_ds);
729                                 } else {
730                                         /* stay on this channel, if it is still valid */
731
732                                         ast_mutex_lock(&peer_chanspy_ds->lock);
733                                         if (peer_chanspy_ds->chan) {
734                                                 ast_channel_lock(peer_chanspy_ds->chan);
735                                                 next_chanspy_ds = peer_chanspy_ds;
736                                                 peer_chanspy_ds = NULL;
737                                         } else {
738                                                 /* the channel is gone */
739                                                 ast_mutex_unlock(&peer_chanspy_ds->lock);
740                                                 next_chanspy_ds = NULL;
741                                         }
742                                 }
743
744                                 peer = NULL;
745                         }
746                 }
747                 if (res == -1 || ast_check_hangup(chan))
748                         break;
749         }
750 exit:
751
752         ast_clear_flag(chan, AST_FLAG_SPYING);
753
754         ast_channel_setoption(chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);
755
756         ast_mutex_destroy(&chanspy_ds.lock);
757
758         return res;
759 }
760
761 static int chanspy_exec(struct ast_channel *chan, void *data)
762 {
763         char *myenforced = NULL;
764         char *mygroup = NULL;
765         char *recbase = NULL;
766         int fd = 0;
767         struct ast_flags flags;
768         int oldwf = 0;
769         int volfactor = 0;
770         int res;
771         AST_DECLARE_APP_ARGS(args,
772                 AST_APP_ARG(spec);
773                 AST_APP_ARG(options);
774         );
775         char *opts[OPT_ARG_ARRAY_SIZE];
776
777         data = ast_strdupa(data);
778         AST_STANDARD_APP_ARGS(args, data);
779
780         if (args.spec && !strcmp(args.spec, "all"))
781                 args.spec = NULL;
782
783         if (args.options) {
784                 ast_app_parse_options(spy_opts, &flags, opts, args.options);
785                 if (ast_test_flag(&flags, OPTION_GROUP))
786                         mygroup = opts[OPT_ARG_GROUP];
787
788                 if (ast_test_flag(&flags, OPTION_RECORD) &&
789                         !(recbase = opts[OPT_ARG_RECORD]))
790                         recbase = "chanspy";
791
792                 if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) {
793                         int vol;
794
795                         if ((sscanf(opts[OPT_ARG_VOLUME], "%d", &vol) != 1) || (vol > 4) || (vol < -4))
796                                 ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n");
797                         else
798                                 volfactor = vol;
799                 }
800
801                 if (ast_test_flag(&flags, OPTION_PRIVATE))
802                         ast_set_flag(&flags, OPTION_WHISPER);
803
804                 if (ast_test_flag(&flags, OPTION_ENFORCED))
805                         myenforced = opts[OPT_ARG_ENFORCED];
806
807         } else
808                 ast_clear_flag(&flags, AST_FLAGS_ALL);
809
810         oldwf = chan->writeformat;
811         if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
812                 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
813                 return -1;
814         }
815
816         if (recbase) {
817                 char filename[512];
818
819                 snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL));
820                 if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, AST_FILE_MODE)) <= 0) {
821                         ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename);
822                         fd = 0;
823                 }
824         }
825
826         res = common_exec(chan, &flags, volfactor, fd, mygroup, myenforced, args.spec, NULL, NULL);
827
828         if (fd)
829                 close(fd);
830
831         if (oldwf && ast_set_write_format(chan, oldwf) < 0)
832                 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
833
834         return res;
835 }
836
837 static int extenspy_exec(struct ast_channel *chan, void *data)
838 {
839         char *ptr, *exten = NULL;
840         char *mygroup = NULL;
841         char *recbase = NULL;
842         int fd = 0;
843         struct ast_flags flags;
844         int oldwf = 0;
845         int volfactor = 0;
846         int res;
847         AST_DECLARE_APP_ARGS(args,
848                 AST_APP_ARG(context);
849                 AST_APP_ARG(options);
850         );
851
852         data = ast_strdupa(data);
853
854         AST_STANDARD_APP_ARGS(args, data);
855         if (!ast_strlen_zero(args.context) && (ptr = strchr(args.context, '@'))) {
856                 exten = args.context;
857                 *ptr++ = '\0';
858                 args.context = ptr;
859         }
860
861         if (ast_strlen_zero(args.context))
862                 args.context = ast_strdupa(chan->context);
863
864         if (args.options) {
865                 char *opts[OPT_ARG_ARRAY_SIZE];
866
867                 ast_app_parse_options(spy_opts, &flags, opts, args.options);
868                 if (ast_test_flag(&flags, OPTION_GROUP))
869                         mygroup = opts[OPT_ARG_GROUP];
870
871                 if (ast_test_flag(&flags, OPTION_RECORD) &&
872                         !(recbase = opts[OPT_ARG_RECORD]))
873                         recbase = "chanspy";
874
875                 if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) {
876                         int vol;
877
878                         if ((sscanf(opts[OPT_ARG_VOLUME], "%d", &vol) != 1) || (vol > 4) || (vol < -4))
879                                 ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n");
880                         else
881                                 volfactor = vol;
882                 }
883
884                 if (ast_test_flag(&flags, OPTION_PRIVATE))
885                         ast_set_flag(&flags, OPTION_WHISPER);
886         } else
887                 ast_clear_flag(&flags, AST_FLAGS_ALL);
888
889         oldwf = chan->writeformat;
890         if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
891                 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
892                 return -1;
893         }
894
895         if (recbase) {
896                 char filename[512];
897
898                 snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL));
899                 if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, AST_FILE_MODE)) <= 0) {
900                         ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename);
901                         fd = 0;
902                 }
903         }
904
905
906         res = common_exec(chan, &flags, volfactor, fd, mygroup, NULL, NULL, exten, args.context);
907
908         if (fd)
909                 close(fd);
910
911         if (oldwf && ast_set_write_format(chan, oldwf) < 0)
912                 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
913
914         return res;
915 }
916
917 static int unload_module(void)
918 {
919         int res = 0;
920
921         res |= ast_unregister_application(app_chan);
922         res |= ast_unregister_application(app_ext);
923
924         return res;
925 }
926
927 static int load_module(void)
928 {
929         int res = 0;
930
931         res |= ast_register_application(app_chan, chanspy_exec, tdesc, desc_chan);
932         res |= ast_register_application(app_ext, extenspy_exec, tdesc, desc_ext);
933
934         return res;
935 }
936
937 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Listen to the audio of an active channel");