Thu Feb 5 16:25:37 2009

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: 165889 $")
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' in an optional : delimited list.\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' in an optional : delimited list.\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;
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    if (ast_write(chan, f)) {
00190       ast_frfree(f);
00191       return -1;
00192    }
00193 
00194    if (csth->fd) {
00195       if (write(csth->fd, f->data, f->datalen) < 0) {
00196          ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
00197       }
00198    }
00199 
00200    ast_frfree(f);
00201 
00202    return 0;
00203 }
00204 
00205 static struct ast_generator spygen = {
00206    .alloc = spy_alloc,
00207    .release = spy_release,
00208    .generate = spy_generate, 
00209 };
00210 
00211 static int start_spying(struct ast_channel *chan, const char *spychan_name, struct ast_audiohook *audiohook) 
00212 {
00213    int res;
00214    struct ast_channel *peer;
00215 
00216    ast_log(LOG_NOTICE, "Attaching %s to %s\n", spychan_name, chan->name);
00217 
00218    res = ast_audiohook_attach(chan, audiohook);
00219 
00220    if (!res && ast_test_flag(chan, AST_FLAG_NBRIDGE) && (peer = ast_bridged_channel(chan))) { 
00221       ast_softhangup(peer, AST_SOFTHANGUP_UNBRIDGE);  
00222    }
00223    return res;
00224 }
00225 
00226 struct chanspy_ds {
00227    struct ast_channel *chan;
00228    char unique_id[20];
00229    ast_mutex_t lock;
00230 };
00231 
00232 static int channel_spy(struct ast_channel *chan, struct chanspy_ds *spyee_chanspy_ds, 
00233    int *volfactor, int fd, const struct ast_flags *flags) 
00234 {
00235    struct chanspy_translation_helper csth;
00236    int running = 0, res, x = 0;
00237    char inp[24] = {0};
00238    char *name;
00239    struct ast_frame *f;
00240    struct ast_silence_generator *silgen = NULL;
00241    struct ast_channel *spyee = NULL;
00242    const char *spyer_name;
00243 
00244    ast_channel_lock(chan);
00245    spyer_name = ast_strdupa(chan->name);
00246    ast_channel_unlock(chan);
00247 
00248    ast_mutex_lock(&spyee_chanspy_ds->lock);
00249    if (spyee_chanspy_ds->chan) {
00250       spyee = spyee_chanspy_ds->chan;
00251       ast_channel_lock(spyee);
00252    }
00253    ast_mutex_unlock(&spyee_chanspy_ds->lock);
00254 
00255    if (!spyee)
00256       return 0;
00257 
00258    /* We now hold the channel lock on spyee */
00259 
00260    if (ast_check_hangup(chan) || ast_check_hangup(spyee)) {
00261       ast_channel_unlock(spyee);
00262       return 0;
00263    }
00264 
00265    name = ast_strdupa(spyee->name);
00266    if (option_verbose >= 2)
00267       ast_verbose(VERBOSE_PREFIX_2 "Spying on channel %s\n", name);
00268 
00269    memset(&csth, 0, sizeof(csth));
00270    
00271    ast_audiohook_init(&csth.spy_audiohook, AST_AUDIOHOOK_TYPE_SPY, "ChanSpy");
00272 
00273    if (start_spying(spyee, spyer_name, &csth.spy_audiohook)) {
00274       ast_audiohook_destroy(&csth.spy_audiohook);
00275       ast_channel_unlock(spyee);
00276       return 0;
00277    }
00278    
00279    if (ast_test_flag(flags, OPTION_WHISPER)) {
00280       ast_audiohook_init(&csth.whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "ChanSpy");
00281       start_spying(spyee, spyer_name, &csth.whisper_audiohook);
00282    }
00283 
00284    ast_channel_unlock(spyee);
00285    spyee = NULL;
00286 
00287    csth.volfactor = *volfactor;
00288    
00289    if (csth.volfactor) {
00290       csth.spy_audiohook.options.read_volume = csth.volfactor;
00291       csth.spy_audiohook.options.write_volume = csth.volfactor;
00292    }
00293    
00294    csth.fd = fd;
00295 
00296    if (ast_test_flag(flags, OPTION_PRIVATE))
00297       silgen = ast_channel_start_silence_generator(chan);
00298    else
00299       ast_activate_generator(chan, &spygen, &csth);
00300 
00301    /* We can no longer rely on 'spyee' being an actual channel;
00302       it can be hung up and freed out from under us. However, the
00303       channel destructor will put NULL into our csth.spy.chan
00304       field when that happens, so that is our signal that the spyee
00305       channel has gone away.
00306    */
00307 
00308    /* Note: it is very important that the ast_waitfor() be the first
00309       condition in this expression, so that if we wait for some period
00310       of time before receiving a frame from our spying channel, we check
00311       for hangup on the spied-on channel _after_ knowing that a frame
00312       has arrived, since the spied-on channel could have gone away while
00313       we were waiting
00314    */
00315    while ((res = ast_waitfor(chan, -1) > -1) && csth.spy_audiohook.status == AST_AUDIOHOOK_STATUS_RUNNING) {
00316       if (!(f = ast_read(chan)) || ast_check_hangup(chan)) {
00317          running = -1;
00318          break;
00319       }
00320 
00321       if (ast_test_flag(flags, OPTION_WHISPER) && (f->frametype == AST_FRAME_VOICE)) {
00322          ast_audiohook_lock(&csth.whisper_audiohook);
00323          ast_audiohook_write_frame(&csth.whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f);
00324          ast_audiohook_unlock(&csth.whisper_audiohook);
00325          ast_frfree(f);
00326          continue;
00327       }
00328 
00329       res = (f->frametype == AST_FRAME_DTMF) ? f->subclass : 0;
00330       ast_frfree(f);
00331       if (!res)
00332          continue;
00333 
00334       if (x == sizeof(inp))
00335          x = 0;
00336 
00337       if (res < 0) {
00338          running = -1;
00339          break;
00340       }
00341 
00342       if (res == '*') {
00343          running = 0;
00344          break;
00345       } else if (res == '#') {
00346          if (!ast_strlen_zero(inp)) {
00347             running = atoi(inp);
00348             break;
00349          }
00350 
00351          (*volfactor)++;
00352          if (*volfactor > 4)
00353             *volfactor = -4;
00354          if (option_verbose > 2)
00355             ast_verbose(VERBOSE_PREFIX_3 "Setting spy volume on %s to %d\n", chan->name, *volfactor);
00356          csth.volfactor = *volfactor;
00357          csth.spy_audiohook.options.read_volume = csth.volfactor;
00358          csth.spy_audiohook.options.write_volume = csth.volfactor;
00359       } else if (res >= '0' && res <= '9') {
00360          inp[x++] = res;
00361       }
00362    }
00363 
00364    if (ast_test_flag(flags, OPTION_PRIVATE))
00365       ast_channel_stop_silence_generator(chan, silgen);
00366    else
00367       ast_deactivate_generator(chan);
00368 
00369    if (ast_test_flag(flags, OPTION_WHISPER)) {
00370       ast_audiohook_lock(&csth.whisper_audiohook);
00371       ast_audiohook_detach(&csth.whisper_audiohook);
00372       ast_audiohook_unlock(&csth.whisper_audiohook);
00373       ast_audiohook_destroy(&csth.whisper_audiohook);
00374    }
00375    
00376    ast_audiohook_lock(&csth.spy_audiohook);
00377    ast_audiohook_detach(&csth.spy_audiohook);
00378    ast_audiohook_unlock(&csth.spy_audiohook);
00379    ast_audiohook_destroy(&csth.spy_audiohook);
00380    
00381    if (option_verbose >= 2)
00382       ast_verbose(VERBOSE_PREFIX_2 "Done Spying on channel %s\n", name);
00383    
00384    return running;
00385 }
00386 
00387 /*!
00388  * \note This relies on the embedded lock to be recursive, as it may be called
00389  * due to a call to chanspy_ds_free with the lock held there.
00390  */
00391 static void chanspy_ds_destroy(void *data)
00392 {
00393    struct chanspy_ds *chanspy_ds = data;
00394 
00395    /* Setting chan to be NULL is an atomic operation, but we don't want this
00396     * value to change while this lock is held.  The lock is held elsewhere
00397     * while it performs non-atomic operations with this channel pointer */
00398 
00399    ast_mutex_lock(&chanspy_ds->lock);
00400    chanspy_ds->chan = NULL;
00401    ast_mutex_unlock(&chanspy_ds->lock);
00402 }
00403 
00404 static void chanspy_ds_chan_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
00405 {
00406    struct chanspy_ds *chanspy_ds = data;
00407    
00408    ast_mutex_lock(&chanspy_ds->lock);
00409    chanspy_ds->chan = new_chan;
00410    ast_mutex_unlock(&chanspy_ds->lock);
00411 }
00412 
00413 static const struct ast_datastore_info chanspy_ds_info = {
00414    .type = "chanspy",
00415    .destroy = chanspy_ds_destroy,
00416    .chan_fixup = chanspy_ds_chan_fixup,
00417 };
00418 
00419 static struct chanspy_ds *chanspy_ds_free(struct chanspy_ds *chanspy_ds)
00420 {
00421    if (!chanspy_ds)
00422       return NULL;
00423 
00424    ast_mutex_lock(&chanspy_ds->lock);
00425    if (chanspy_ds->chan) {
00426       struct ast_datastore *datastore;
00427       struct ast_channel *chan;
00428 
00429       chan = chanspy_ds->chan;
00430 
00431       ast_channel_lock(chan);
00432       if ((datastore = ast_channel_datastore_find(chan, &chanspy_ds_info, chanspy_ds->unique_id))) {
00433          ast_channel_datastore_remove(chan, datastore);
00434          /* chanspy_ds->chan is NULL after this call */
00435          chanspy_ds_destroy(datastore->data);
00436          datastore->data = NULL;
00437          ast_channel_datastore_free(datastore);
00438       }
00439       ast_channel_unlock(chan);
00440    }
00441    ast_mutex_unlock(&chanspy_ds->lock);
00442 
00443    return NULL;
00444 }
00445 
00446 /*! \note Returns the channel in the chanspy_ds locked as well as the chanspy_ds locked */
00447 static struct chanspy_ds *setup_chanspy_ds(struct ast_channel *chan, struct chanspy_ds *chanspy_ds)
00448 {
00449    struct ast_datastore *datastore = NULL;
00450 
00451    ast_mutex_lock(&chanspy_ds->lock);
00452 
00453    if (!(datastore = ast_channel_datastore_alloc(&chanspy_ds_info, chanspy_ds->unique_id))) {
00454       ast_mutex_unlock(&chanspy_ds->lock);
00455       chanspy_ds = chanspy_ds_free(chanspy_ds);
00456       ast_channel_unlock(chan);
00457       return NULL;
00458    }
00459    
00460    chanspy_ds->chan = chan;
00461    datastore->data = chanspy_ds;
00462    ast_channel_datastore_add(chan, datastore);
00463 
00464    return chanspy_ds;
00465 }
00466 
00467 static struct chanspy_ds *next_channel(struct ast_channel *chan,
00468    const struct ast_channel *last, const char *spec,
00469    const char *exten, const char *context, struct chanspy_ds *chanspy_ds)
00470 {
00471    struct ast_channel *this;
00472    char channel_name[AST_CHANNEL_NAME];
00473    static size_t PSEUDO_CHAN_LEN = 0;
00474 
00475    if (!PSEUDO_CHAN_LEN) {
00476       PSEUDO_CHAN_LEN = *dahdi_chan_name_len + strlen("/pseudo");
00477    }
00478 
00479 redo:
00480    if (spec)
00481       this = ast_walk_channel_by_name_prefix_locked(last, spec, strlen(spec));
00482    else if (exten)
00483       this = ast_walk_channel_by_exten_locked(last, exten, context);
00484    else
00485       this = ast_channel_walk_locked(last);
00486 
00487    if (!this)
00488       return NULL;
00489 
00490    snprintf(channel_name, AST_CHANNEL_NAME, "%s/pseudo", dahdi_chan_name);
00491    if (!strncmp(this->name, channel_name, PSEUDO_CHAN_LEN)) {
00492       last = this;
00493       ast_channel_unlock(this);
00494       goto redo;
00495    } else if (this == chan) {
00496       last = this;
00497       ast_channel_unlock(this);
00498       goto redo;
00499    }
00500 
00501    return setup_chanspy_ds(this, chanspy_ds);
00502 }
00503 
00504 static int common_exec(struct ast_channel *chan, const struct ast_flags *flags,
00505              int volfactor, const int fd, const char *mygroup, const char *spec,
00506              const char *exten, const char *context)
00507 {
00508    char nameprefix[AST_NAME_STRLEN];
00509    char peer_name[AST_NAME_STRLEN + 5];
00510    signed char zero_volume = 0;
00511    int waitms;
00512    int res;
00513    char *ptr;
00514    int num;
00515    int num_spyed_upon = 1;
00516    struct chanspy_ds chanspy_ds = { 0, };
00517 
00518    ast_mutex_init(&chanspy_ds.lock);
00519 
00520    snprintf(chanspy_ds.unique_id, sizeof(chanspy_ds.unique_id), "%d", ast_atomic_fetchadd_int(&next_unique_id_to_use, +1));
00521 
00522    if (chan->_state != AST_STATE_UP)
00523       ast_answer(chan);
00524 
00525    ast_set_flag(chan, AST_FLAG_SPYING); /* so nobody can spy on us while we are spying */
00526 
00527    waitms = 100;
00528 
00529    for (;;) {
00530       struct chanspy_ds *peer_chanspy_ds = NULL, *next_chanspy_ds = NULL;
00531       struct ast_channel *prev = NULL, *peer = NULL;
00532 
00533       if (!ast_test_flag(flags, OPTION_QUIET) && num_spyed_upon) {
00534          res = ast_streamfile(chan, "beep", chan->language);
00535          if (!res)
00536             res = ast_waitstream(chan, "");
00537          else if (res < 0) {
00538             ast_clear_flag(chan, AST_FLAG_SPYING);
00539             break;
00540          }
00541       }
00542 
00543       res = ast_waitfordigit(chan, waitms);
00544       if (res < 0) {
00545          ast_clear_flag(chan, AST_FLAG_SPYING);
00546          break;
00547       }
00548             
00549       /* reset for the next loop around, unless overridden later */
00550       waitms = 100;
00551       num_spyed_upon = 0;
00552 
00553       for (peer_chanspy_ds = next_channel(chan, prev, spec, exten, context, &chanspy_ds);
00554            peer_chanspy_ds;
00555           chanspy_ds_free(peer_chanspy_ds), prev = peer,
00556            peer_chanspy_ds = next_chanspy_ds ? next_chanspy_ds : 
00557             next_channel(chan, prev, spec, exten, context, &chanspy_ds), next_chanspy_ds = NULL) {
00558          const char *group;
00559          int igrp = !mygroup;
00560          char *groups[25];
00561          int num_groups = 0;
00562          char dup_group[512];
00563          int x;
00564          char *s;
00565 
00566          peer = peer_chanspy_ds->chan;
00567 
00568          ast_mutex_unlock(&peer_chanspy_ds->lock);
00569 
00570          if (peer == prev) {
00571             ast_channel_unlock(peer);
00572             chanspy_ds_free(peer_chanspy_ds);
00573             break;
00574          }
00575 
00576          if (ast_check_hangup(chan)) {
00577             ast_channel_unlock(peer);
00578             chanspy_ds_free(peer_chanspy_ds);
00579             break;
00580          }
00581 
00582          if (ast_test_flag(flags, OPTION_BRIDGED) && !ast_bridged_channel(peer)) {
00583             ast_channel_unlock(peer);
00584             continue;
00585          }
00586 
00587          if (ast_check_hangup(peer) || ast_test_flag(peer, AST_FLAG_SPYING)) {
00588             ast_channel_unlock(peer);
00589             continue;
00590          }
00591 
00592          if (mygroup) {
00593             if ((group = pbx_builtin_getvar_helper(peer, "SPYGROUP"))) {
00594                ast_copy_string(dup_group, group, sizeof(dup_group));
00595                num_groups = ast_app_separate_args(dup_group, ':', groups,
00596                               sizeof(groups) / sizeof(groups[0]));
00597             }
00598             
00599             for (x = 0; x < num_groups; x++) {
00600                if (!strcmp(mygroup, groups[x])) {
00601                   igrp = 1;
00602                   break;
00603                }
00604             }
00605          }
00606          
00607          if (!igrp) {
00608             ast_channel_unlock(peer);
00609             continue;
00610          }
00611 
00612          strcpy(peer_name, "spy-");
00613          strncat(peer_name, peer->name, AST_NAME_STRLEN - 4 - 1);
00614          ptr = strchr(peer_name, '/');
00615          *ptr++ = '\0';
00616          
00617          for (s = peer_name; s < ptr; s++)
00618             *s = tolower(*s);
00619 
00620          /* We have to unlock the peer channel here to avoid a deadlock.
00621           * So, when we need to dereference it again, we have to lock the 
00622           * datastore and get the pointer from there to see if the channel 
00623           * is still valid. */
00624          ast_channel_unlock(peer);
00625 
00626          if (!ast_test_flag(flags, OPTION_QUIET)) {
00627             if (ast_fileexists(peer_name, NULL, NULL) != -1) {
00628                res = ast_streamfile(chan, peer_name, chan->language);
00629                if (!res)
00630                   res = ast_waitstream(chan, "");
00631                if (res) {
00632                   chanspy_ds_free(peer_chanspy_ds);
00633                   break;
00634                }
00635             } else
00636                res = ast_say_character_str(chan, peer_name, "", chan->language);
00637             if ((num = atoi(ptr))) 
00638                ast_say_digits(chan, atoi(ptr), "", chan->language);
00639          }
00640          
00641          res = channel_spy(chan, peer_chanspy_ds, &volfactor, fd, flags);
00642          num_spyed_upon++; 
00643 
00644          if (res == -1) {
00645             chanspy_ds_free(peer_chanspy_ds);
00646             break;
00647          } else if (res > 1 && spec) {
00648             struct ast_channel *next;
00649 
00650             snprintf(nameprefix, AST_NAME_STRLEN, "%s/%d", spec, res);
00651 
00652             if ((next = ast_get_channel_by_name_prefix_locked(nameprefix, strlen(nameprefix)))) {
00653                peer_chanspy_ds = chanspy_ds_free(peer_chanspy_ds);
00654                next_chanspy_ds = setup_chanspy_ds(next, &chanspy_ds);
00655             } else {
00656                /* stay on this channel, if it is still valid */
00657 
00658                ast_mutex_lock(&peer_chanspy_ds->lock);
00659                if (peer_chanspy_ds->chan) {
00660                   ast_channel_lock(peer_chanspy_ds->chan);
00661                   next_chanspy_ds = peer_chanspy_ds;
00662                   peer_chanspy_ds = NULL;
00663                } else {
00664                   /* the channel is gone */
00665                   ast_mutex_unlock(&peer_chanspy_ds->lock);
00666                   next_chanspy_ds = NULL;
00667                }
00668             }
00669 
00670             peer = NULL;
00671          }
00672       }
00673       if (res == -1 || ast_check_hangup(chan))
00674          break;
00675    }
00676    
00677    ast_clear_flag(chan, AST_FLAG_SPYING);
00678 
00679    ast_channel_setoption(chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);
00680 
00681    ast_mutex_lock(&chanspy_ds.lock);
00682    ast_mutex_unlock(&chanspy_ds.lock);
00683    ast_mutex_destroy(&chanspy_ds.lock);
00684 
00685    return res;
00686 }
00687 
00688 static int chanspy_exec(struct ast_channel *chan, void *data)
00689 {
00690    struct ast_module_user *u;
00691    char *options = NULL;
00692    char *spec = NULL;
00693    char *argv[2];
00694    char *mygroup = NULL;
00695    char *recbase = NULL;
00696    int fd = 0;
00697    struct ast_flags flags;
00698    int oldwf = 0;
00699    int argc = 0;
00700    int volfactor = 0;
00701    int res;
00702 
00703    data = ast_strdupa(data);
00704 
00705    u = ast_module_user_add(chan);
00706 
00707    if ((argc = ast_app_separate_args(data, '|', argv, sizeof(argv) / sizeof(argv[0])))) {
00708       spec = argv[0];
00709       if (argc > 1)
00710          options = argv[1];
00711 
00712       if (ast_strlen_zero(spec) || !strcmp(spec, "all"))
00713          spec = NULL;
00714    }
00715 
00716    if (options) {
00717       char *opts[OPT_ARG_ARRAY_SIZE];
00718       
00719       ast_app_parse_options(spy_opts, &flags, opts, options);
00720       if (ast_test_flag(&flags, OPTION_GROUP))
00721          mygroup = opts[OPT_ARG_GROUP];
00722 
00723       if (ast_test_flag(&flags, OPTION_RECORD) &&
00724           !(recbase = opts[OPT_ARG_RECORD]))
00725          recbase = "chanspy";
00726 
00727       if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) {
00728          int vol;
00729 
00730          if ((sscanf(opts[OPT_ARG_VOLUME], "%d", &vol) != 1) || (vol > 4) || (vol < -4))
00731             ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n");
00732          else
00733             volfactor = vol;
00734       }
00735 
00736       if (ast_test_flag(&flags, OPTION_PRIVATE))
00737          ast_set_flag(&flags, OPTION_WHISPER);
00738    } else
00739       ast_clear_flag(&flags, AST_FLAGS_ALL);
00740 
00741    oldwf = chan->writeformat;
00742    if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
00743       ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
00744       ast_module_user_remove(u);
00745       return -1;
00746    }
00747 
00748    if (recbase) {
00749       char filename[PATH_MAX];
00750 
00751       snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL));
00752       if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0644)) <= 0) {
00753          ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename);
00754          fd = 0;
00755       }
00756    }
00757 
00758    res = common_exec(chan, &flags, volfactor, fd, mygroup, spec, NULL, NULL);
00759 
00760    if (fd)
00761       close(fd);
00762 
00763    if (oldwf && ast_set_write_format(chan, oldwf) < 0)
00764       ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
00765 
00766    ast_module_user_remove(u);
00767 
00768    return res;
00769 }
00770 
00771 static int extenspy_exec(struct ast_channel *chan, void *data)
00772 {
00773    struct ast_module_user *u;
00774    char *options = NULL;
00775    char *exten = NULL;
00776    char *context = NULL;
00777    char *argv[2];
00778    char *mygroup = NULL;
00779    char *recbase = NULL;
00780    int fd = 0;
00781    struct ast_flags flags;
00782    int oldwf = 0;
00783    int argc = 0;
00784    int volfactor = 0;
00785    int res;
00786 
00787    data = ast_strdupa(data);
00788 
00789    u = ast_module_user_add(chan);
00790 
00791    if ((argc = ast_app_separate_args(data, '|', argv, sizeof(argv) / sizeof(argv[0])))) {
00792       context = argv[0];
00793       if (!ast_strlen_zero(argv[0]))
00794          exten = strsep(&context, "@");
00795       if (ast_strlen_zero(context))
00796          context = ast_strdupa(chan->context);
00797       if (argc > 1)
00798          options = argv[1];
00799    }
00800 
00801    if (options) {
00802       char *opts[OPT_ARG_ARRAY_SIZE];
00803       
00804       ast_app_parse_options(spy_opts, &flags, opts, options);
00805       if (ast_test_flag(&flags, OPTION_GROUP))
00806          mygroup = opts[OPT_ARG_GROUP];
00807 
00808       if (ast_test_flag(&flags, OPTION_RECORD) &&
00809           !(recbase = opts[OPT_ARG_RECORD]))
00810          recbase = "chanspy";
00811 
00812       if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) {
00813          int vol;
00814 
00815          if ((sscanf(opts[OPT_ARG_VOLUME], "%d", &vol) != 1) || (vol > 4) || (vol < -4))
00816             ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n");
00817          else
00818             volfactor = vol;
00819       }
00820 
00821       if (ast_test_flag(&flags, OPTION_PRIVATE))
00822          ast_set_flag(&flags, OPTION_WHISPER);
00823    } else
00824       ast_clear_flag(&flags, AST_FLAGS_ALL);
00825 
00826    oldwf = chan->writeformat;
00827    if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
00828       ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
00829       ast_module_user_remove(u);
00830       return -1;
00831    }
00832 
00833    if (recbase) {
00834       char filename[PATH_MAX];
00835 
00836       snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL));
00837       if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0644)) <= 0) {
00838          ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename);
00839          fd = 0;
00840       }
00841    }
00842 
00843    res = common_exec(chan, &flags, volfactor, fd, mygroup, NULL, exten, context);
00844 
00845    if (fd)
00846       close(fd);
00847 
00848    if (oldwf && ast_set_write_format(chan, oldwf) < 0)
00849       ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
00850 
00851    ast_module_user_remove(u);
00852 
00853    return res;
00854 }
00855 
00856 static int unload_module(void)
00857 {
00858    int res = 0;
00859 
00860    res |= ast_unregister_application(app_chan);
00861    res |= ast_unregister_application(app_ext);
00862 
00863    ast_module_user_hangup_all();
00864 
00865    return res;
00866 }
00867 
00868 static int load_module(void)
00869 {
00870    int res = 0;
00871 
00872    res |= ast_register_application(app_chan, chanspy_exec, tdesc, desc_chan);
00873    res |= ast_register_application(app_ext, extenspy_exec, tdesc, desc_ext);
00874 
00875    return res;
00876 }
00877 
00878 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Listen to the audio of an active channel");

Generated on Thu Feb 5 16:25:37 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7