Sat Aug 6 00:39:19 2011

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

Generated on Sat Aug 6 00:39:19 2011 for Asterisk - the Open Source PBX by  doxygen 1.4.7