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

Generated on Sun Jun 12 16:37:43 2011 for Asterisk - the Open Source PBX by  doxygen 1.5.6