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