Mon Mar 31 07:37:54 2008

Asterisk developer's documentation


app_chanspy.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 2005 Anthony Minessale II (anthmct@yahoo.com)
00005  * Copyright (C) 2005 - 2008, Digium, Inc.
00006  *
00007  * A license has been granted to Digium (via disclaimer) for the use of
00008  * this code.
00009  *
00010  * See http://www.asterisk.org for more information about
00011  * the Asterisk project. Please do not directly contact
00012  * any of the maintainers of this project for assistance;
00013  * the project provides a web site, mailing lists and IRC
00014  * channels for your use.
00015  *
00016  * This program is free software, distributed under the terms of
00017  * the GNU General Public License Version 2. See the LICENSE file
00018  * at the top of the source tree.
00019  */
00020 
00021 /*! \file
00022  *
00023  * \brief ChanSpy: Listen in on any channel.
00024  *
00025  * \author Anthony Minessale II <anthmct@yahoo.com>
00026  * \author Joshua Colp <jcolp@digium.com>
00027  * \author Russell Bryant <russell@digium.com>
00028  *
00029  * \ingroup applications
00030  */
00031 
00032 #include "asterisk.h"
00033 
00034 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
00035 
00036 #include <stdlib.h>
00037 #include <stdio.h>
00038 #include <string.h>
00039 #include <unistd.h>
00040 #include <ctype.h>
00041 
00042 #include "asterisk/file.h"
00043 #include "asterisk/logger.h"
00044 #include "asterisk/channel.h"
00045 #include "asterisk/audiohook.h"
00046 #include "asterisk/features.h"
00047 #include "asterisk/options.h"
00048 #include "asterisk/app.h"
00049 #include "asterisk/utils.h"
00050 #include "asterisk/say.h"
00051 #include "asterisk/pbx.h"
00052 #include "asterisk/translate.h"
00053 #include "asterisk/module.h"
00054 #include "asterisk/lock.h"
00055 
00056 #define AST_NAME_STRLEN 256
00057 
00058 static const char *tdesc = "Listen to a channel, and optionally whisper into it";
00059 static const char *app_chan = "ChanSpy";
00060 static const char *desc_chan = 
00061 "  ChanSpy([chanprefix][|options]): This application is used to listen to the\n"
00062 "audio from an Asterisk channel. This includes the audio coming in and\n"
00063 "out of the channel being spied on. If the 'chanprefix' parameter is specified,\n"
00064 "only channels beginning with this string will be spied upon.\n"
00065 "  While spying, the following actions may be performed:\n"
00066 "    - Dialing # cycles the volume level.\n"
00067 "    - Dialing * will stop spying and look for another channel to spy on.\n"
00068 "    - Dialing a series of digits followed by # builds a channel name to append\n"
00069 "      to 'chanprefix'. For example, executing ChanSpy(Agent) and then dialing\n"
00070 "      the digits '1234#' while spying will begin spying on the channel\n"
00071 "      'Agent/1234'.\n"
00072 "  Options:\n"
00073 "    b             - Only spy on channels involved in a bridged call.\n"
00074 "    g(grp)        - Match only channels where their ${SPYGROUP} variable is set to\n"
00075 "                    contain 'grp' in an optional : delimited list.\n"
00076 "    q             - Don't play a beep when beginning to spy on a channel, or speak the\n"
00077 "                    selected channel name.\n"
00078 "    r[(basename)] - Record the session to the monitor spool directory. An\n"
00079 "                    optional base for the filename may be specified. The\n"
00080 "                    default is 'chanspy'.\n"
00081 "    v([value])    - Adjust the initial volume in the range from -4 to 4. A\n"
00082 "                    negative value refers to a quieter setting.\n"
00083 "    w             - Enable 'whisper' mode, so the spying channel can talk to\n"
00084 "                    the spied-on channel.\n"
00085 "    W             - Enable 'private whisper' mode, so the spying channel can\n"
00086 "                    talk to the spied-on channel but cannot listen to that\n"
00087 "                    channel.\n"
00088 ;
00089 
00090 static const char *app_ext = "ExtenSpy";
00091 static const char *desc_ext = 
00092 "  ExtenSpy(exten[@context][|options]): This application is used to listen to the\n"
00093 "audio from an Asterisk channel. This includes the audio coming in and\n"
00094 "out of the channel being spied on. Only channels created by outgoing calls for the\n"
00095 "specified extension will be selected for spying. If the optional context is not\n"
00096 "supplied, the current channel's context will be used.\n"
00097 "  While spying, the following actions may be performed:\n"
00098 "    - Dialing # cycles the volume level.\n"
00099 "    - Dialing * will stop spying and look for another channel to spy on.\n"
00100 "  Options:\n"
00101 "    b             - Only spy on channels involved in a bridged call.\n"
00102 "    g(grp)        - Match only channels where their ${SPYGROUP} variable is set to\n"
00103 "                    contain 'grp' in an optional : delimited list.\n"
00104 "    q             - Don't play a beep when beginning to spy on a channel, or speak the\n"
00105 "                    selected channel name.\n"
00106 "    r[(basename)] - Record the session to the monitor spool directory. An\n"
00107 "                    optional base for the filename may be specified. The\n"
00108 "                    default is 'chanspy'.\n"
00109 "    v([value])    - Adjust the initial volume in the range from -4 to 4. A\n"
00110 "                    negative value refers to a quieter setting.\n"
00111 "    w             - Enable 'whisper' mode, so the spying channel can talk to\n"
00112 "                    the spied-on channel.\n"
00113 "    W             - Enable 'private whisper' mode, so the spying channel can\n"
00114 "                    talk to the spied-on channel but cannot listen to that\n"
00115 "                    channel.\n"
00116 ;
00117 
00118 enum {
00119    OPTION_QUIET    = (1 << 0),   /* Quiet, no announcement */
00120    OPTION_BRIDGED   = (1 << 1),  /* Only look at bridged calls */
00121    OPTION_VOLUME    = (1 << 2),  /* Specify initial volume */
00122    OPTION_GROUP     = (1 << 3),  /* Only look at channels in group */
00123    OPTION_RECORD    = (1 << 4),
00124    OPTION_WHISPER  = (1 << 5),
00125    OPTION_PRIVATE   = (1 << 6),  /* Private Whisper mode */
00126 } chanspy_opt_flags;
00127 
00128 enum {
00129    OPT_ARG_VOLUME = 0,
00130    OPT_ARG_GROUP,
00131    OPT_ARG_RECORD,
00132    OPT_ARG_ARRAY_SIZE,
00133 } chanspy_opt_args;
00134 
00135 AST_APP_OPTIONS(spy_opts, {
00136    AST_APP_OPTION('q', OPTION_QUIET),
00137    AST_APP_OPTION('b', OPTION_BRIDGED),
00138    AST_APP_OPTION('w', OPTION_WHISPER),
00139    AST_APP_OPTION('W', OPTION_PRIVATE),
00140    AST_APP_OPTION_ARG('v', OPTION_VOLUME, OPT_ARG_VOLUME),
00141    AST_APP_OPTION_ARG('g', OPTION_GROUP, OPT_ARG_GROUP),
00142    AST_APP_OPTION_ARG('r', OPTION_RECORD, OPT_ARG_RECORD),
00143 });
00144 
00145 
00146 struct chanspy_translation_helper {
00147    /* spy data */
00148    struct ast_audiohook spy_audiohook;
00149    struct ast_audiohook whisper_audiohook;
00150    int fd;
00151    int volfactor;
00152 };
00153 
00154 static void *spy_alloc(struct ast_channel *chan, void *data)
00155 {
00156    /* just store the data pointer in the channel structure */
00157    return data;
00158 }
00159 
00160 static void spy_release(struct ast_channel *chan, void *data)
00161 {
00162    /* nothing to do */
00163 }
00164 
00165 static int spy_generate(struct ast_channel *chan, void *data, int len, int samples) 
00166 {
00167    struct chanspy_translation_helper *csth = data;
00168    struct ast_frame *f;
00169 
00170    ast_audiohook_lock(&csth->spy_audiohook);
00171    if (csth->spy_audiohook.status != AST_AUDIOHOOK_STATUS_RUNNING) {
00172       ast_audiohook_unlock(&csth->spy_audiohook);
00173       return -1;
00174    }
00175 
00176    f = ast_audiohook_read_frame(&csth->spy_audiohook, samples, AST_AUDIOHOOK_DIRECTION_BOTH, AST_FORMAT_SLINEAR);
00177 
00178    ast_audiohook_unlock(&csth->spy_audiohook);
00179 
00180    if (!f)
00181       return 0;
00182       
00183    if (ast_write(chan, f)) {
00184       ast_frfree(f);
00185       return -1;
00186    }
00187 
00188    if (csth->fd)
00189       write(csth->fd, f->data, f->datalen);
00190 
00191    ast_frfree(f);
00192 
00193    return 0;
00194 }
00195 
00196 static struct ast_generator spygen = {
00197    .alloc = spy_alloc,
00198    .release = spy_release,
00199    .generate = spy_generate, 
00200 };
00201 
00202 static int start_spying(struct ast_channel *chan, const char *spychan_name, struct ast_audiohook *audiohook) 
00203 {
00204    int res;
00205    struct ast_channel *peer;
00206 
00207    ast_log(LOG_NOTICE, "Attaching %s to %s\n", spychan_name, chan->name);
00208 
00209    res = ast_audiohook_attach(chan, audiohook);
00210 
00211    if (!res && ast_test_flag(chan, AST_FLAG_NBRIDGE) && (peer = ast_bridged_channel(chan))) {
00212       ast_channel_unlock(chan);
00213       ast_softhangup(peer, AST_SOFTHANGUP_UNBRIDGE);  
00214    } else
00215       ast_channel_unlock(chan);
00216 
00217    return res;
00218 }
00219 
00220 struct chanspy_ds {
00221    struct ast_channel *chan;
00222    ast_mutex_t lock;
00223 };
00224 
00225 static int channel_spy(struct ast_channel *chan, struct chanspy_ds *spyee_chanspy_ds, 
00226    int *volfactor, int fd, const struct ast_flags *flags) 
00227 {
00228    struct chanspy_translation_helper csth;
00229    int running = 0, res, x = 0;
00230    char inp[24] = {0};
00231    char *name;
00232    struct ast_frame *f;
00233    struct ast_silence_generator *silgen = NULL;
00234    struct ast_channel *spyee = NULL;
00235    const char *spyer_name;
00236 
00237    ast_channel_lock(chan);
00238    spyer_name = ast_strdupa(chan->name);
00239    ast_channel_unlock(chan);
00240 
00241    ast_mutex_lock(&spyee_chanspy_ds->lock);
00242    if (spyee_chanspy_ds->chan) {
00243       spyee = spyee_chanspy_ds->chan;
00244       ast_channel_lock(spyee);
00245    }
00246    ast_mutex_unlock(&spyee_chanspy_ds->lock);
00247 
00248    if (!spyee)
00249       return 0;
00250 
00251    /* We now hold the channel lock on spyee */
00252 
00253    if (ast_check_hangup(chan) || ast_check_hangup(spyee)) {
00254       ast_channel_unlock(spyee);
00255       return 0;
00256    }
00257 
00258    name = ast_strdupa(spyee->name);
00259    if (option_verbose >= 2)
00260       ast_verbose(VERBOSE_PREFIX_2 "Spying on channel %s\n", name);
00261 
00262    memset(&csth, 0, sizeof(csth));
00263    
00264    ast_audiohook_init(&csth.spy_audiohook, AST_AUDIOHOOK_TYPE_SPY, "ChanSpy");
00265 
00266    if (start_spying(spyee, spyer_name, &csth.spy_audiohook)) { /* Unlocks spyee */
00267       ast_audiohook_destroy(&csth.spy_audiohook);
00268       return 0;
00269    }
00270    
00271    if (ast_test_flag(flags, OPTION_WHISPER)) {
00272       ast_audiohook_init(&csth.whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "ChanSpy");
00273       start_spying(spyee, spyer_name, &csth.whisper_audiohook); /* Unlocks spyee */
00274    }
00275 
00276    spyee = NULL;
00277 
00278    csth.volfactor = *volfactor;
00279    
00280    if (csth.volfactor) {
00281       csth.spy_audiohook.options.read_volume = csth.volfactor;
00282       csth.spy_audiohook.options.write_volume = csth.volfactor;
00283    }
00284    
00285    csth.fd = fd;
00286 
00287    if (ast_test_flag(flags, OPTION_PRIVATE))
00288       silgen = ast_channel_start_silence_generator(chan);
00289    else
00290       ast_activate_generator(chan, &spygen, &csth);
00291 
00292    /* We can no longer rely on 'spyee' being an actual channel;
00293       it can be hung up and freed out from under us. However, the
00294       channel destructor will put NULL into our csth.spy.chan
00295       field when that happens, so that is our signal that the spyee
00296       channel has gone away.
00297    */
00298 
00299    /* Note: it is very important that the ast_waitfor() be the first
00300       condition in this expression, so that if we wait for some period
00301       of time before receiving a frame from our spying channel, we check
00302       for hangup on the spied-on channel _after_ knowing that a frame
00303       has arrived, since the spied-on channel could have gone away while
00304       we were waiting
00305    */
00306    while ((res = ast_waitfor(chan, -1) > -1) && csth.spy_audiohook.status == AST_AUDIOHOOK_STATUS_RUNNING) {
00307       if (!(f = ast_read(chan)) || ast_check_hangup(chan)) {
00308          running = -1;
00309          break;
00310       }
00311 
00312       if (ast_test_flag(flags, OPTION_WHISPER) && (f->frametype == AST_FRAME_VOICE)) {
00313          ast_audiohook_lock(&csth.whisper_audiohook);
00314          ast_audiohook_write_frame(&csth.whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f);
00315          ast_audiohook_unlock(&csth.whisper_audiohook);
00316          ast_frfree(f);
00317          continue;
00318       }
00319 
00320       res = (f->frametype == AST_FRAME_DTMF) ? f->subclass : 0;
00321       ast_frfree(f);
00322       if (!res)
00323          continue;
00324 
00325       if (x == sizeof(inp))
00326          x = 0;
00327 
00328       if (res < 0) {
00329          running = -1;
00330          break;
00331       }
00332 
00333       if (res == '*') {
00334          running = 0;
00335          break;
00336       } else if (res == '#') {
00337          if (!ast_strlen_zero(inp)) {
00338             running = atoi(inp);
00339             break;
00340          }
00341 
00342          (*volfactor)++;
00343          if (*volfactor > 4)
00344             *volfactor = -4;
00345          if (option_verbose > 2)
00346             ast_verbose(VERBOSE_PREFIX_3 "Setting spy volume on %s to %d\n", chan->name, *volfactor);
00347          csth.volfactor = *volfactor;
00348          csth.spy_audiohook.options.read_volume = csth.volfactor;
00349          csth.spy_audiohook.options.write_volume = csth.volfactor;
00350       } else if (res >= '0' && res <= '9') {
00351          inp[x++] = res;
00352       }
00353    }
00354 
00355    if (ast_test_flag(flags, OPTION_PRIVATE))
00356       ast_channel_stop_silence_generator(chan, silgen);
00357    else
00358       ast_deactivate_generator(chan);
00359 
00360    if (ast_test_flag(flags, OPTION_WHISPER)) {
00361       ast_audiohook_lock(&csth.whisper_audiohook);
00362       ast_audiohook_detach(&csth.whisper_audiohook);
00363       ast_audiohook_unlock(&csth.whisper_audiohook);
00364       ast_audiohook_destroy(&csth.whisper_audiohook);
00365    }
00366    
00367    ast_audiohook_lock(&csth.spy_audiohook);
00368    ast_audiohook_detach(&csth.spy_audiohook);
00369    ast_audiohook_unlock(&csth.spy_audiohook);
00370    ast_audiohook_destroy(&csth.spy_audiohook);
00371    
00372    if (option_verbose >= 2)
00373       ast_verbose(VERBOSE_PREFIX_2 "Done Spying on channel %s\n", name);
00374    
00375    return running;
00376 }
00377 
00378 /*!
00379  * \note This relies on the embedded lock to be recursive, as it may be called
00380  * due to a call to chanspy_ds_free with the lock held there.
00381  */
00382 static void chanspy_ds_destroy(void *data)
00383 {
00384    struct chanspy_ds *chanspy_ds = data;
00385 
00386    /* Setting chan to be NULL is an atomic operation, but we don't want this
00387     * value to change while this lock is held.  The lock is held elsewhere
00388     * while it performs non-atomic operations with this channel pointer */
00389 
00390    ast_mutex_lock(&chanspy_ds->lock);
00391    chanspy_ds->chan = NULL;
00392    ast_mutex_unlock(&chanspy_ds->lock);
00393 }
00394 
00395 static void chanspy_ds_chan_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
00396 {
00397    struct chanspy_ds *chanspy_ds = data;
00398    
00399    ast_mutex_lock(&chanspy_ds->lock);
00400    chanspy_ds->chan = new_chan;
00401    ast_mutex_unlock(&chanspy_ds->lock);
00402 }
00403 
00404 static const struct ast_datastore_info chanspy_ds_info = {
00405    .type = "chanspy",
00406    .destroy = chanspy_ds_destroy,
00407    .chan_fixup = chanspy_ds_chan_fixup,
00408 };
00409 
00410 static struct chanspy_ds *chanspy_ds_free(struct chanspy_ds *chanspy_ds)
00411 {
00412    if (!chanspy_ds)
00413       return NULL;
00414 
00415    ast_mutex_lock(&chanspy_ds->lock);
00416    if (chanspy_ds->chan) {
00417       struct ast_datastore *datastore;
00418       struct ast_channel *chan;
00419 
00420       chan = chanspy_ds->chan;
00421 
00422       ast_channel_lock(chan);
00423       if ((datastore = ast_channel_datastore_find(chan, &chanspy_ds_info, NULL))) {
00424          ast_channel_datastore_remove(chan, datastore);
00425          /* chanspy_ds->chan is NULL after this call */
00426          chanspy_ds_destroy(datastore->data);
00427          datastore->data = NULL;
00428          ast_channel_datastore_free(datastore);
00429       }
00430       ast_channel_unlock(chan);
00431    }
00432    ast_mutex_unlock(&chanspy_ds->lock);
00433 
00434    return NULL;
00435 }
00436 
00437 /*! \note Returns the channel in the chanspy_ds locked as well as the chanspy_ds locked */
00438 static struct chanspy_ds *setup_chanspy_ds(struct ast_channel *chan, struct chanspy_ds *chanspy_ds)
00439 {
00440    struct ast_datastore *datastore = NULL;
00441 
00442    ast_mutex_lock(&chanspy_ds->lock);
00443 
00444    if (!(datastore = ast_channel_datastore_alloc(&chanspy_ds_info, NULL))) {
00445       ast_mutex_unlock(&chanspy_ds->lock);
00446       chanspy_ds = chanspy_ds_free(chanspy_ds);
00447       ast_channel_unlock(chan);
00448       return NULL;
00449    }
00450    
00451    chanspy_ds->chan = chan;
00452    datastore->data = chanspy_ds;
00453    ast_channel_datastore_add(chan, datastore);
00454 
00455    return chanspy_ds;
00456 }
00457 
00458 static struct chanspy_ds *next_channel(struct ast_channel *chan,
00459    const struct ast_channel *last, const char *spec,
00460    const char *exten, const char *context, struct chanspy_ds *chanspy_ds)
00461 {
00462    struct ast_channel *this;
00463 
00464 redo:
00465    if (spec)
00466       this = ast_walk_channel_by_name_prefix_locked(last, spec, strlen(spec));
00467    else if (exten)
00468       this = ast_walk_channel_by_exten_locked(last, exten, context);
00469    else
00470       this = ast_channel_walk_locked(last);
00471 
00472    if (!this)
00473       return NULL;
00474 
00475    if (!strncmp(this->name, "Zap/pseudo", 10)) {
00476       ast_channel_unlock(this);
00477       goto redo;
00478    } else if (this == chan) {
00479       last = this;
00480       ast_channel_unlock(this);
00481       goto redo;
00482    }
00483 
00484    return setup_chanspy_ds(this, chanspy_ds);
00485 }
00486 
00487 static int common_exec(struct ast_channel *chan, const struct ast_flags *flags,
00488              int volfactor, const int fd, const char *mygroup, const char *spec,
00489              const char *exten, const char *context)
00490 {
00491    char nameprefix[AST_NAME_STRLEN];
00492    char peer_name[AST_NAME_STRLEN + 5];
00493    signed char zero_volume = 0;
00494    int waitms;
00495    int res;
00496    char *ptr;
00497    int num;
00498    int num_spyed_upon = 1;
00499    struct chanspy_ds chanspy_ds;
00500 
00501    ast_mutex_init(&chanspy_ds.lock);
00502 
00503    if (chan->_state != AST_STATE_UP)
00504       ast_answer(chan);
00505 
00506    ast_set_flag(chan, AST_FLAG_SPYING); /* so nobody can spy on us while we are spying */
00507 
00508    waitms = 100;
00509 
00510    for (;;) {
00511       struct chanspy_ds *peer_chanspy_ds = NULL, *next_chanspy_ds = NULL;
00512       struct ast_channel *prev = NULL, *peer = NULL;
00513 
00514       if (!ast_test_flag(flags, OPTION_QUIET) && num_spyed_upon) {
00515          res = ast_streamfile(chan, "beep", chan->language);
00516          if (!res)
00517             res = ast_waitstream(chan, "");
00518          else if (res < 0) {
00519             ast_clear_flag(chan, AST_FLAG_SPYING);
00520             break;
00521          }
00522       }
00523 
00524       res = ast_waitfordigit(chan, waitms);
00525       if (res < 0) {
00526          ast_clear_flag(chan, AST_FLAG_SPYING);
00527          break;
00528       }
00529             
00530       /* reset for the next loop around, unless overridden later */
00531       waitms = 100;
00532       num_spyed_upon = 0;
00533 
00534       for (peer_chanspy_ds = next_channel(chan, prev, spec, exten, context, &chanspy_ds);
00535            peer_chanspy_ds;
00536           chanspy_ds_free(peer_chanspy_ds), prev = peer,
00537            peer_chanspy_ds = next_chanspy_ds ? next_chanspy_ds : 
00538             next_channel(chan, prev, spec, exten, context, &chanspy_ds), next_chanspy_ds = NULL) {
00539          const char *group;
00540          int igrp = !mygroup;
00541          char *groups[25];
00542          int num_groups = 0;
00543          char *dup_group;
00544          int x;
00545          char *s;
00546          struct ast_channel *peer;
00547 
00548          peer = peer_chanspy_ds->chan;
00549 
00550          ast_mutex_unlock(&peer_chanspy_ds->lock);
00551 
00552          if (peer == prev) {
00553             ast_channel_unlock(peer);
00554             chanspy_ds_free(peer_chanspy_ds);
00555             break;
00556          }
00557 
00558          if (ast_check_hangup(chan)) {
00559             ast_channel_unlock(peer);
00560             chanspy_ds_free(peer_chanspy_ds);
00561             break;
00562          }
00563 
00564          if (ast_test_flag(flags, OPTION_BRIDGED) && !ast_bridged_channel(peer)) {
00565             ast_channel_unlock(peer);
00566             continue;
00567          }
00568 
00569          if (ast_check_hangup(peer) || ast_test_flag(peer, AST_FLAG_SPYING)) {
00570             ast_channel_unlock(peer);
00571             continue;
00572          }
00573 
00574          if (mygroup) {
00575             if ((group = pbx_builtin_getvar_helper(peer, "SPYGROUP"))) {
00576                dup_group = ast_strdupa(group);
00577                num_groups = ast_app_separate_args(dup_group, ':', groups,
00578                               sizeof(groups) / sizeof(groups[0]));
00579             }
00580             
00581             for (x = 0; x < num_groups; x++) {
00582                if (!strcmp(mygroup, groups[x])) {
00583                   igrp = 1;
00584                   break;
00585                }
00586             }
00587          }
00588          
00589          if (!igrp) {
00590             ast_channel_unlock(peer);
00591             continue;
00592          }
00593 
00594          strcpy(peer_name, "spy-");
00595          strncat(peer_name, peer->name, AST_NAME_STRLEN - 4 - 1);
00596          ptr = strchr(peer_name, '/');
00597          *ptr++ = '\0';
00598          
00599          for (s = peer_name; s < ptr; s++)
00600             *s = tolower(*s);
00601 
00602       
00603          /* We have to unlock the peer channel here to avoid a deadlock.
00604           * So, when we need it again, we have to lock the datastore and get
00605           * the pointer from there to see if the channel is still valid. */
00606          ast_channel_unlock(peer);
00607          peer = NULL;
00608 
00609          if (!ast_test_flag(flags, OPTION_QUIET)) {
00610             if (ast_fileexists(peer_name, NULL, NULL) != -1) {
00611                res = ast_streamfile(chan, peer_name, chan->language);
00612                if (!res)
00613                   res = ast_waitstream(chan, "");
00614                if (res) {
00615                   chanspy_ds_free(peer_chanspy_ds);
00616                   break;
00617                }
00618             } else
00619                res = ast_say_character_str(chan, peer_name, "", chan->language);
00620             if ((num = atoi(ptr))) 
00621                ast_say_digits(chan, atoi(ptr), "", chan->language);
00622          }
00623          
00624          waitms = 5000;
00625          res = channel_spy(chan, peer_chanspy_ds, &volfactor, fd, flags);
00626          num_spyed_upon++; 
00627 
00628          if (res == -1) {
00629             chanspy_ds_free(peer_chanspy_ds);
00630             break;
00631          } else if (res > 1 && spec) {
00632             struct ast_channel *next;
00633 
00634             snprintf(nameprefix, AST_NAME_STRLEN, "%s/%d", spec, res);
00635 
00636             if ((next = ast_get_channel_by_name_prefix_locked(nameprefix, strlen(nameprefix)))) {
00637                peer_chanspy_ds = chanspy_ds_free(peer_chanspy_ds);
00638                next_chanspy_ds = setup_chanspy_ds(next, &chanspy_ds);
00639             } else {
00640                /* stay on this channel, if it is still valid */
00641 
00642                ast_mutex_lock(&peer_chanspy_ds->lock);
00643                if (peer_chanspy_ds->chan) {
00644                   ast_channel_lock(peer_chanspy_ds->chan);
00645                   next_chanspy_ds = peer_chanspy_ds;
00646                   peer_chanspy_ds = NULL;
00647                } else {
00648                   /* the channel is gone */
00649                   ast_mutex_unlock(&peer_chanspy_ds->lock);
00650                   next_chanspy_ds = NULL;
00651                }
00652             }
00653 
00654             peer = NULL;
00655          }
00656       }
00657       if (res == -1 || ast_check_hangup(chan))
00658          break;
00659    }
00660    
00661    ast_clear_flag(chan, AST_FLAG_SPYING);
00662 
00663    ast_channel_setoption(chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);
00664 
00665    ast_mutex_destroy(&chanspy_ds.lock);
00666 
00667    return res;
00668 }
00669 
00670 static int chanspy_exec(struct ast_channel *chan, void *data)
00671 {
00672    struct ast_module_user *u;
00673    char *options = NULL;
00674    char *spec = NULL;
00675    char *argv[2];
00676    char *mygroup = NULL;
00677    char *recbase = NULL;
00678    int fd = 0;
00679    struct ast_flags flags;
00680    int oldwf = 0;
00681    int argc = 0;
00682    int volfactor = 0;
00683    int res;
00684 
00685    data = ast_strdupa(data);
00686 
00687    u = ast_module_user_add(chan);
00688 
00689    if ((argc = ast_app_separate_args(data, '|', argv, sizeof(argv) / sizeof(argv[0])))) {
00690       spec = argv[0];
00691       if (argc > 1)
00692          options = argv[1];
00693 
00694       if (ast_strlen_zero(spec) || !strcmp(spec, "all"))
00695          spec = NULL;
00696    }
00697 
00698    if (options) {
00699       char *opts[OPT_ARG_ARRAY_SIZE];
00700       
00701       ast_app_parse_options(spy_opts, &flags, opts, options);
00702       if (ast_test_flag(&flags, OPTION_GROUP))
00703          mygroup = opts[OPT_ARG_GROUP];
00704 
00705       if (ast_test_flag(&flags, OPTION_RECORD) &&
00706           !(recbase = opts[OPT_ARG_RECORD]))
00707          recbase = "chanspy";
00708 
00709       if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) {
00710          int vol;
00711 
00712          if ((sscanf(opts[OPT_ARG_VOLUME], "%d", &vol) != 1) || (vol > 4) || (vol < -4))
00713             ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n");
00714          else
00715             volfactor = vol;
00716       }
00717 
00718       if (ast_test_flag(&flags, OPTION_PRIVATE))
00719          ast_set_flag(&flags, OPTION_WHISPER);
00720    } else
00721       ast_clear_flag(&flags, AST_FLAGS_ALL);
00722 
00723    oldwf = chan->writeformat;
00724    if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
00725       ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
00726       ast_module_user_remove(u);
00727       return -1;
00728    }
00729 
00730    if (recbase) {
00731       char filename[512];
00732 
00733       snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL));
00734       if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0644)) <= 0) {
00735          ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename);
00736          fd = 0;
00737       }
00738    }
00739 
00740    res = common_exec(chan, &flags, volfactor, fd, mygroup, spec, NULL, NULL);
00741 
00742    if (fd)
00743       close(fd);
00744 
00745    if (oldwf && ast_set_write_format(chan, oldwf) < 0)
00746       ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
00747 
00748    ast_module_user_remove(u);
00749 
00750    return res;
00751 }
00752 
00753 static int extenspy_exec(struct ast_channel *chan, void *data)
00754 {
00755    struct ast_module_user *u;
00756    char *options = NULL;
00757    char *exten = NULL;
00758    char *context = NULL;
00759    char *argv[2];
00760    char *mygroup = NULL;
00761    char *recbase = NULL;
00762    int fd = 0;
00763    struct ast_flags flags;
00764    int oldwf = 0;
00765    int argc = 0;
00766    int volfactor = 0;
00767    int res;
00768 
00769    data = ast_strdupa(data);
00770 
00771    u = ast_module_user_add(chan);
00772 
00773    if ((argc = ast_app_separate_args(data, '|', argv, sizeof(argv) / sizeof(argv[0])))) {
00774       context = argv[0];
00775       if (!ast_strlen_zero(argv[0]))
00776          exten = strsep(&context, "@");
00777       if (ast_strlen_zero(context))
00778          context = ast_strdupa(chan->context);
00779       if (argc > 1)
00780          options = argv[1];
00781    }
00782 
00783    if (options) {
00784       char *opts[OPT_ARG_ARRAY_SIZE];
00785       
00786       ast_app_parse_options(spy_opts, &flags, opts, options);
00787       if (ast_test_flag(&flags, OPTION_GROUP))
00788          mygroup = opts[OPT_ARG_GROUP];
00789 
00790       if (ast_test_flag(&flags, OPTION_RECORD) &&
00791           !(recbase = opts[OPT_ARG_RECORD]))
00792          recbase = "chanspy";
00793 
00794       if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) {
00795          int vol;
00796 
00797          if ((sscanf(opts[OPT_ARG_VOLUME], "%d", &vol) != 1) || (vol > 4) || (vol < -4))
00798             ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n");
00799          else
00800             volfactor = vol;
00801       }
00802 
00803       if (ast_test_flag(&flags, OPTION_PRIVATE))
00804          ast_set_flag(&flags, OPTION_WHISPER);
00805    } else
00806       ast_clear_flag(&flags, AST_FLAGS_ALL);
00807 
00808    oldwf = chan->writeformat;
00809    if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
00810       ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
00811       ast_module_user_remove(u);
00812       return -1;
00813    }
00814 
00815    if (recbase) {
00816       char filename[512];
00817 
00818       snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL));
00819       if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0644)) <= 0) {
00820          ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename);
00821          fd = 0;
00822       }
00823    }
00824 
00825    res = common_exec(chan, &flags, volfactor, fd, mygroup, NULL, exten, context);
00826 
00827    if (fd)
00828       close(fd);
00829 
00830    if (oldwf && ast_set_write_format(chan, oldwf) < 0)
00831       ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
00832 
00833    ast_module_user_remove(u);
00834 
00835    return res;
00836 }
00837 
00838 static int unload_module(void)
00839 {
00840    int res = 0;
00841 
00842    res |= ast_unregister_application(app_chan);
00843    res |= ast_unregister_application(app_ext);
00844 
00845    ast_module_user_hangup_all();
00846 
00847    return res;
00848 }
00849 
00850 static int load_module(void)
00851 {
00852    int res = 0;
00853 
00854    res |= ast_register_application(app_chan, chanspy_exec, tdesc, desc_chan);
00855    res |= ast_register_application(app_ext, extenspy_exec, tdesc, desc_ext);
00856 
00857    return res;
00858 }
00859 
00860 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Listen to the audio of an active channel");

Generated on Mon Mar 31 07:37:54 2008 for Asterisk - the Open Source PBX by  doxygen 1.5.1