Mon May 14 04:42:50 2007

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 - 2006, 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  *
00027  * \ingroup applications
00028  */
00029 
00030 #include "asterisk.h"
00031 
00032 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
00033 
00034 #include <stdlib.h>
00035 #include <stdio.h>
00036 #include <string.h>
00037 #include <unistd.h>
00038 #include <ctype.h>
00039 
00040 #include "asterisk/file.h"
00041 #include "asterisk/logger.h"
00042 #include "asterisk/channel.h"
00043 #include "asterisk/chanspy.h"
00044 #include "asterisk/features.h"
00045 #include "asterisk/options.h"
00046 #include "asterisk/app.h"
00047 #include "asterisk/utils.h"
00048 #include "asterisk/say.h"
00049 #include "asterisk/pbx.h"
00050 #include "asterisk/translate.h"
00051 #include "asterisk/module.h"
00052 #include "asterisk/lock.h"
00053 
00054 #define AST_NAME_STRLEN 256
00055 
00056 static const char *tdesc = "Listen to a channel, and optionally whisper into it";
00057 static const char *app_chan = "ChanSpy";
00058 static const char *desc_chan = 
00059 "  ChanSpy([chanprefix][|options]): This application is used to listen to the\n"
00060 "audio from an Asterisk channel. This includes the audio coming in and\n"
00061 "out of the channel being spied on. If the 'chanprefix' parameter is specified,\n"
00062 "only channels beginning with this string will be spied upon.\n"
00063 "  While spying, the following actions may be performed:\n"
00064 "    - Dialing # cycles the volume level.\n"
00065 "    - Dialing * will stop spying and look for another channel to spy on.\n"
00066 "    - Dialing a series of digits followed by # builds a channel name to append\n"
00067 "      to 'chanprefix'. For example, executing ChanSpy(Agent) and then dialing\n"
00068 "      the digits '1234#' while spying will begin spying on the channel\n"
00069 "      'Agent/1234'.\n"
00070 "  Options:\n"
00071 "    b             - Only spy on channels involved in a bridged call.\n"
00072 "    g(grp)        - Match only channels where their ${SPYGROUP} variable is set to\n"
00073 "                    contain 'grp' in an optional : delimited list.\n"
00074 "    q             - Don't play a beep when beginning to spy on a channel, or speak the\n"
00075 "                    selected channel name.\n"
00076 "    r[(basename)] - Record the session to the monitor spool directory. An\n"
00077 "                    optional base for the filename may be specified. The\n"
00078 "                    default is 'chanspy'.\n"
00079 "    v([value])    - Adjust the initial volume in the range from -4 to 4. A\n"
00080 "                    negative value refers to a quieter setting.\n"
00081 "    w             - Enable 'whisper' mode, so the spying channel can talk to\n"
00082 "                    the spied-on channel.\n"
00083 "    W             - Enable 'private whisper' mode, so the spying channel can\n"
00084 "                    talk to the spied-on channel but cannot listen to that\n"
00085 "                    channel.\n"
00086 ;
00087 
00088 static const char *app_ext = "ExtenSpy";
00089 static const char *desc_ext = 
00090 "  ExtenSpy(exten[@context][|options]): This application is used to listen to the\n"
00091 "audio from an Asterisk channel. This includes the audio coming in and\n"
00092 "out of the channel being spied on. Only channels created by outgoing calls for the\n"
00093 "specified extension will be selected for spying. If the optional context is not\n"
00094 "supplied, the current channel's context will be used.\n"
00095 "  While spying, the following actions may be performed:\n"
00096 "    - Dialing # cycles the volume level.\n"
00097 "    - Dialing * will stop spying and look for another channel to spy on.\n"
00098 "  Options:\n"
00099 "    b             - Only spy on channels involved in a bridged call.\n"
00100 "    g(grp)        - Match only channels where their ${SPYGROUP} variable is set to\n"
00101 "                    contain 'grp' in an optional : delimited list.\n"
00102 "    q             - Don't play a beep when beginning to spy on a channel, or speak the\n"
00103 "                    selected channel name.\n"
00104 "    r[(basename)] - Record the session to the monitor spool directory. An\n"
00105 "                    optional base for the filename may be specified. The\n"
00106 "                    default is 'chanspy'.\n"
00107 "    v([value])    - Adjust the initial volume in the range from -4 to 4. A\n"
00108 "                    negative value refers to a quieter setting.\n"
00109 "    w             - Enable 'whisper' mode, so the spying channel can talk to\n"
00110 "                    the spied-on channel.\n"
00111 "    W             - Enable 'private whisper' mode, so the spying channel can\n"
00112 "                    talk to the spied-on channel but cannot listen to that\n"
00113 "                    channel.\n"
00114 ;
00115 
00116 enum {
00117    OPTION_QUIET    = (1 << 0),   /* Quiet, no announcement */
00118    OPTION_BRIDGED   = (1 << 1),  /* Only look at bridged calls */
00119    OPTION_VOLUME    = (1 << 2),  /* Specify initial volume */
00120    OPTION_GROUP     = (1 << 3),  /* Only look at channels in group */
00121    OPTION_RECORD    = (1 << 4),
00122    OPTION_WHISPER  = (1 << 5),
00123    OPTION_PRIVATE   = (1 << 6),  /* Private Whisper mode */
00124 } chanspy_opt_flags;
00125 
00126 enum {
00127    OPT_ARG_VOLUME = 0,
00128    OPT_ARG_GROUP,
00129    OPT_ARG_RECORD,
00130    OPT_ARG_ARRAY_SIZE,
00131 } chanspy_opt_args;
00132 
00133 AST_APP_OPTIONS(spy_opts, {
00134    AST_APP_OPTION('q', OPTION_QUIET),
00135    AST_APP_OPTION('b', OPTION_BRIDGED),
00136    AST_APP_OPTION('w', OPTION_WHISPER),
00137    AST_APP_OPTION('W', OPTION_PRIVATE),
00138    AST_APP_OPTION_ARG('v', OPTION_VOLUME, OPT_ARG_VOLUME),
00139    AST_APP_OPTION_ARG('g', OPTION_GROUP, OPT_ARG_GROUP),
00140    AST_APP_OPTION_ARG('r', OPTION_RECORD, OPT_ARG_RECORD),
00141 });
00142 
00143 
00144 struct chanspy_translation_helper {
00145    /* spy data */
00146    struct ast_channel_spy spy;
00147    int fd;
00148    int volfactor;
00149 };
00150 
00151 static void *spy_alloc(struct ast_channel *chan, void *data)
00152 {
00153    /* just store the data pointer in the channel structure */
00154    return data;
00155 }
00156 
00157 static void spy_release(struct ast_channel *chan, void *data)
00158 {
00159    /* nothing to do */
00160 }
00161 
00162 static int spy_generate(struct ast_channel *chan, void *data, int len, int samples) 
00163 {
00164    struct chanspy_translation_helper *csth = data;
00165    struct ast_frame *f;
00166       
00167    if (csth->spy.status != CHANSPY_RUNNING)
00168       /* Channel is already gone more than likely */
00169       return -1;
00170 
00171    ast_mutex_lock(&csth->spy.lock);
00172    f = ast_channel_spy_read_frame(&csth->spy, samples);
00173    ast_mutex_unlock(&csth->spy.lock);
00174       
00175    if (!f)
00176       return 0;
00177       
00178    if (ast_write(chan, f)) {
00179       ast_frfree(f);
00180       return -1;
00181    }
00182 
00183    if (csth->fd)
00184       write(csth->fd, f->data, f->datalen);
00185 
00186    ast_frfree(f);
00187 
00188    return 0;
00189 }
00190 
00191 static struct ast_generator spygen = {
00192    .alloc = spy_alloc,
00193    .release = spy_release,
00194    .generate = spy_generate, 
00195 };
00196 
00197 static int start_spying(struct ast_channel *chan, struct ast_channel *spychan, struct ast_channel_spy *spy) 
00198 {
00199    int res;
00200    struct ast_channel *peer;
00201 
00202    ast_log(LOG_NOTICE, "Attaching %s to %s\n", spychan->name, chan->name);
00203 
00204    ast_channel_lock(chan);
00205    res = ast_channel_spy_add(chan, spy);
00206    ast_channel_unlock(chan);
00207 
00208    if (!res && ast_test_flag(chan, AST_FLAG_NBRIDGE) && (peer = ast_bridged_channel(chan)))
00209       ast_softhangup(peer, AST_SOFTHANGUP_UNBRIDGE);  
00210 
00211    return res;
00212 }
00213 
00214 /* Map 'volume' levels from -4 through +4 into
00215    decibel (dB) settings for channel drivers
00216 */
00217 static signed char volfactor_map[] = {
00218    -24,
00219    -18,
00220    -12,
00221    -6,
00222    0,
00223    6,
00224    12,
00225    18,
00226    24,
00227 };
00228 
00229 /* attempt to set the desired gain adjustment via the channel driver;
00230    if successful, clear it out of the csth structure so the
00231    generator will not attempt to do the adjustment itself
00232 */
00233 static void set_volume(struct ast_channel *chan, struct chanspy_translation_helper *csth)
00234 {
00235    signed char volume_adjust = volfactor_map[csth->volfactor + 4];
00236 
00237    if (!ast_channel_setoption(chan, AST_OPTION_TXGAIN, &volume_adjust, sizeof(volume_adjust), 0))
00238       csth->volfactor = 0;
00239    csth->spy.read_vol_adjustment = csth->volfactor;
00240    csth->spy.write_vol_adjustment = csth->volfactor;
00241 }
00242 
00243 static int channel_spy(struct ast_channel *chan, struct ast_channel *spyee, int *volfactor, int fd,
00244              const struct ast_flags *flags) 
00245 {
00246    struct chanspy_translation_helper csth;
00247    int running = 0, res, x = 0;
00248    char inp[24] = {0};
00249    char *name;
00250    struct ast_frame *f;
00251    struct ast_silence_generator *silgen = NULL;
00252 
00253    if (ast_check_hangup(chan) || ast_check_hangup(spyee))
00254       return 0;
00255 
00256    name = ast_strdupa(spyee->name);
00257    if (option_verbose >= 2)
00258       ast_verbose(VERBOSE_PREFIX_2 "Spying on channel %s\n", name);
00259 
00260    memset(&csth, 0, sizeof(csth));
00261    ast_set_flag(&csth.spy, CHANSPY_FORMAT_AUDIO);
00262    ast_set_flag(&csth.spy, CHANSPY_TRIGGER_NONE);
00263    ast_set_flag(&csth.spy, CHANSPY_MIXAUDIO);
00264    csth.spy.type = "ChanSpy";
00265    csth.spy.status = CHANSPY_RUNNING;
00266    csth.spy.read_queue.format = AST_FORMAT_SLINEAR;
00267    csth.spy.write_queue.format = AST_FORMAT_SLINEAR;
00268    ast_mutex_init(&csth.spy.lock);
00269    csth.volfactor = *volfactor;
00270    set_volume(chan, &csth);
00271    if (csth.volfactor) {
00272       ast_set_flag(&csth.spy, CHANSPY_READ_VOLADJUST);
00273       csth.spy.read_vol_adjustment = csth.volfactor;
00274       ast_set_flag(&csth.spy, CHANSPY_WRITE_VOLADJUST);
00275       csth.spy.write_vol_adjustment = csth.volfactor;
00276    }
00277    csth.fd = fd;
00278    
00279    if (start_spying(spyee, chan, &csth.spy)) {
00280       ast_mutex_destroy(&csth.spy.lock);
00281       return 0;
00282    }
00283 
00284    if (ast_test_flag(flags, OPTION_WHISPER)) {
00285       struct ast_filestream *beepstream;
00286       int old_write_format = 0;
00287 
00288       ast_channel_whisper_start(csth.spy.chan);
00289       old_write_format = chan->writeformat;
00290       if ((beepstream = ast_openstream_full(chan, "beep", chan->language, 1))) {
00291          struct ast_frame *f;
00292 
00293          while ((f = ast_readframe(beepstream))) {
00294             ast_channel_whisper_feed(csth.spy.chan, f);
00295             ast_frfree(f);
00296          }
00297 
00298          ast_closestream(beepstream);
00299          chan->stream = NULL;
00300       }
00301       if (old_write_format)
00302          ast_set_write_format(chan, old_write_format);
00303    }
00304 
00305    if (ast_test_flag(flags, OPTION_PRIVATE))
00306       silgen = ast_channel_start_silence_generator(chan);
00307    else
00308       ast_activate_generator(chan, &spygen, &csth);
00309 
00310    /* We can no longer rely on 'spyee' being an actual channel;
00311       it can be hung up and freed out from under us. However, the
00312       channel destructor will put NULL into our csth.spy.chan
00313       field when that happens, so that is our signal that the spyee
00314       channel has gone away.
00315    */
00316 
00317    /* Note: it is very important that the ast_waitfor() be the first
00318       condition in this expression, so that if we wait for some period
00319       of time before receiving a frame from our spying channel, we check
00320       for hangup on the spied-on channel _after_ knowing that a frame
00321       has arrived, since the spied-on channel could have gone away while
00322       we were waiting
00323    */
00324    while ((res = ast_waitfor(chan, -1) > -1) &&
00325           csth.spy.status == CHANSPY_RUNNING &&
00326           csth.spy.chan) {
00327       if (!(f = ast_read(chan)) || ast_check_hangup(chan)) {
00328          running = -1;
00329          break;
00330       }
00331 
00332       if (ast_test_flag(flags, OPTION_WHISPER) &&
00333           (f->frametype == AST_FRAME_VOICE)) {
00334          ast_channel_whisper_feed(csth.spy.chan, f);
00335          ast_frfree(f);
00336          continue;
00337       }
00338 
00339       res = (f->frametype == AST_FRAME_DTMF) ? f->subclass : 0;
00340       ast_frfree(f);
00341       if (!res)
00342          continue;
00343 
00344       if (x == sizeof(inp))
00345          x = 0;
00346 
00347       if (res < 0) {
00348          running = -1;
00349          break;
00350       }
00351 
00352       if (res == '*') {
00353          running = 0;
00354          break;
00355       } else if (res == '#') {
00356          if (!ast_strlen_zero(inp)) {
00357             running = atoi(inp);
00358             break;
00359          }
00360 
00361          (*volfactor)++;
00362          if (*volfactor > 4)
00363             *volfactor = -4;
00364          if (option_verbose > 2)
00365             ast_verbose(VERBOSE_PREFIX_3 "Setting spy volume on %s to %d\n", chan->name, *volfactor);
00366          csth.volfactor = *volfactor;
00367          set_volume(chan, &csth);
00368          if (csth.volfactor) {
00369             ast_set_flag(&csth.spy, CHANSPY_READ_VOLADJUST);
00370             csth.spy.read_vol_adjustment = csth.volfactor;
00371             ast_set_flag(&csth.spy, CHANSPY_WRITE_VOLADJUST);
00372             csth.spy.write_vol_adjustment = csth.volfactor;
00373          } else {
00374             ast_clear_flag(&csth.spy, CHANSPY_READ_VOLADJUST);
00375             ast_clear_flag(&csth.spy, CHANSPY_WRITE_VOLADJUST);
00376          }
00377       } else if (res >= '0' && res <= '9') {
00378          inp[x++] = res;
00379       }
00380    }
00381 
00382    if (ast_test_flag(flags, OPTION_WHISPER) && csth.spy.chan)
00383       ast_channel_whisper_stop(csth.spy.chan);
00384 
00385    if (ast_test_flag(flags, OPTION_PRIVATE))
00386       ast_channel_stop_silence_generator(chan, silgen);
00387    else
00388       ast_deactivate_generator(chan);
00389 
00390    /* If a channel still exists on our spy structure then we need to remove ourselves */
00391    if (csth.spy.chan) {
00392       csth.spy.status = CHANSPY_DONE;
00393       ast_channel_lock(csth.spy.chan);
00394       ast_channel_spy_remove(csth.spy.chan, &csth.spy);
00395       ast_channel_unlock(csth.spy.chan);
00396    }
00397    ast_channel_spy_free(&csth.spy);
00398    
00399    if (option_verbose >= 2)
00400       ast_verbose(VERBOSE_PREFIX_2 "Done Spying on channel %s\n", name);
00401    
00402    return running;
00403 }
00404 
00405 static struct ast_channel *next_channel(const struct ast_channel *last, const char *spec,
00406                const char *exten, const char *context)
00407 {
00408    struct ast_channel *this;
00409 
00410    redo:
00411    if (spec)
00412       this = ast_walk_channel_by_name_prefix_locked(last, spec, strlen(spec));
00413    else if (exten)
00414       this = ast_walk_channel_by_exten_locked(last, exten, context);
00415    else
00416       this = ast_channel_walk_locked(last);
00417 
00418    if (this) {
00419       ast_channel_unlock(this);
00420       if (!strncmp(this->name, "Zap/pseudo", 10))
00421          goto redo;
00422    }
00423 
00424    return this;
00425 }
00426 
00427 static int common_exec(struct ast_channel *chan, const struct ast_flags *flags,
00428              int volfactor, const int fd, const char *mygroup, const char *spec,
00429              const char *exten, const char *context)
00430 {
00431    struct ast_channel *peer, *prev, *next;
00432    char nameprefix[AST_NAME_STRLEN];
00433    char peer_name[AST_NAME_STRLEN + 5];
00434    signed char zero_volume = 0;
00435    int waitms;
00436    int res;
00437    char *ptr;
00438    int num;
00439 
00440    if (chan->_state != AST_STATE_UP)
00441       ast_answer(chan);
00442 
00443    ast_set_flag(chan, AST_FLAG_SPYING); /* so nobody can spy on us while we are spying */
00444 
00445    waitms = 100;
00446 
00447    for (;;) {
00448       if (!ast_test_flag(flags, OPTION_QUIET)) {
00449          res = ast_streamfile(chan, "beep", chan->language);
00450          if (!res)
00451             res = ast_waitstream(chan, "");
00452          else if (res < 0) {
00453             ast_clear_flag(chan, AST_FLAG_SPYING);
00454             break;
00455          }
00456       }
00457 
00458       res = ast_waitfordigit(chan, waitms);
00459       if (res < 0) {
00460          ast_clear_flag(chan, AST_FLAG_SPYING);
00461          break;
00462       }
00463             
00464       /* reset for the next loop around, unless overridden later */
00465       waitms = 100;
00466       peer = prev = next = NULL;
00467 
00468       for (peer = next_channel(peer, spec, exten, context);
00469            peer;
00470            prev = peer, peer = next ? next : next_channel(peer, spec, exten, context), next = NULL) {
00471          const char *group;
00472          int igrp = !mygroup;
00473          char *groups[25];
00474          int num_groups = 0;
00475          char *dup_group;
00476          int x;
00477          char *s;
00478             
00479          if (peer == prev)
00480             break;
00481 
00482          if (peer == chan)
00483             continue;
00484 
00485          if (ast_test_flag(flags, OPTION_BRIDGED) && !ast_bridged_channel(peer))
00486             continue;
00487 
00488          if (ast_check_hangup(peer) || ast_test_flag(peer, AST_FLAG_SPYING))
00489             continue;
00490 
00491          if (mygroup) {
00492             if ((group = pbx_builtin_getvar_helper(peer, "SPYGROUP"))) {
00493                dup_group = ast_strdupa(group);
00494                num_groups = ast_app_separate_args(dup_group, ':', groups,
00495                               sizeof(groups) / sizeof(groups[0]));
00496             }
00497             
00498             for (x = 0; x < num_groups; x++) {
00499                if (!strcmp(mygroup, groups[x])) {
00500                   igrp = 1;
00501                   break;
00502                }
00503             }
00504          }
00505          
00506          if (!igrp)
00507             continue;
00508 
00509          strcpy(peer_name, "spy-");
00510          strncat(peer_name, peer->name, AST_NAME_STRLEN);
00511          ptr = strchr(peer_name, '/');
00512          *ptr++ = '\0';
00513          
00514          for (s = peer_name; s < ptr; s++)
00515             *s = tolower(*s);
00516          
00517          if (!ast_test_flag(flags, OPTION_QUIET)) {
00518             if (ast_fileexists(peer_name, NULL, NULL) != -1) {
00519                res = ast_streamfile(chan, peer_name, chan->language);
00520                if (!res)
00521                   res = ast_waitstream(chan, "");
00522                if (res)
00523                   break;
00524             } else
00525                res = ast_say_character_str(chan, peer_name, "", chan->language);
00526             if ((num = atoi(ptr))) 
00527                ast_say_digits(chan, atoi(ptr), "", chan->language);
00528          }
00529          
00530          waitms = 5000;
00531          res = channel_spy(chan, peer, &volfactor, fd, flags);
00532          
00533          if (res == -1) {
00534             break;
00535          } else if (res > 1 && spec) {
00536             snprintf(nameprefix, AST_NAME_STRLEN, "%s/%d", spec, res);
00537             if ((next = ast_get_channel_by_name_prefix_locked(nameprefix, strlen(nameprefix)))) {
00538                ast_channel_unlock(next);
00539             } else {
00540                /* stay on this channel */
00541                next = peer;
00542             }
00543             peer = NULL;
00544          }
00545       }
00546       if (res == -1)
00547          break;
00548    }
00549    
00550    ast_clear_flag(chan, AST_FLAG_SPYING);
00551 
00552    ast_channel_setoption(chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);
00553 
00554    return res;
00555 }
00556 
00557 static int chanspy_exec(struct ast_channel *chan, void *data)
00558 {
00559    struct ast_module_user *u;
00560    char *options = NULL;
00561    char *spec = NULL;
00562    char *argv[2];
00563    char *mygroup = NULL;
00564    char *recbase = NULL;
00565    int fd = 0;
00566    struct ast_flags flags;
00567    int oldwf = 0;
00568    int argc = 0;
00569    int volfactor = 0;
00570    int res;
00571 
00572    data = ast_strdupa(data);
00573 
00574    u = ast_module_user_add(chan);
00575 
00576    if ((argc = ast_app_separate_args(data, '|', argv, sizeof(argv) / sizeof(argv[0])))) {
00577       spec = argv[0];
00578       if (argc > 1)
00579          options = argv[1];
00580 
00581       if (ast_strlen_zero(spec) || !strcmp(spec, "all"))
00582          spec = NULL;
00583    }
00584 
00585    if (options) {
00586       char *opts[OPT_ARG_ARRAY_SIZE];
00587       
00588       ast_app_parse_options(spy_opts, &flags, opts, options);
00589       if (ast_test_flag(&flags, OPTION_GROUP))
00590          mygroup = opts[OPT_ARG_GROUP];
00591 
00592       if (ast_test_flag(&flags, OPTION_RECORD) &&
00593           !(recbase = opts[OPT_ARG_RECORD]))
00594          recbase = "chanspy";
00595 
00596       if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) {
00597          int vol;
00598 
00599          if ((sscanf(opts[OPT_ARG_VOLUME], "%d", &vol) != 1) || (vol > 4) || (vol < -4))
00600             ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n");
00601          else
00602             volfactor = vol;
00603       }
00604 
00605       if (ast_test_flag(&flags, OPTION_PRIVATE))
00606          ast_set_flag(&flags, OPTION_WHISPER);
00607    }
00608 
00609    oldwf = chan->writeformat;
00610    if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
00611       ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
00612       ast_module_user_remove(u);
00613       return -1;
00614    }
00615 
00616    if (recbase) {
00617       char filename[512];
00618 
00619       snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL));
00620       if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0644)) <= 0) {
00621          ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename);
00622          fd = 0;
00623       }
00624    }
00625 
00626    res = common_exec(chan, &flags, volfactor, fd, mygroup, spec, NULL, NULL);
00627 
00628    if (fd)
00629       close(fd);
00630 
00631    if (oldwf && ast_set_write_format(chan, oldwf) < 0)
00632       ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
00633 
00634    ast_module_user_remove(u);
00635 
00636    return res;
00637 }
00638 
00639 static int extenspy_exec(struct ast_channel *chan, void *data)
00640 {
00641    struct ast_module_user *u;
00642    char *options = NULL;
00643    char *exten = NULL;
00644    char *context = NULL;
00645    char *argv[2];
00646    char *mygroup = NULL;
00647    char *recbase = NULL;
00648    int fd = 0;
00649    struct ast_flags flags;
00650    int oldwf = 0;
00651    int argc = 0;
00652    int volfactor = 0;
00653    int res;
00654 
00655    data = ast_strdupa(data);
00656 
00657    u = ast_module_user_add(chan);
00658 
00659    if ((argc = ast_app_separate_args(data, '|', argv, sizeof(argv) / sizeof(argv[0])))) {
00660       context = argv[0];
00661       if (!ast_strlen_zero(argv[0]))
00662          exten = strsep(&context, "@");
00663       if (ast_strlen_zero(context))
00664          context = ast_strdupa(chan->context);
00665       if (argc > 1)
00666          options = argv[1];
00667    }
00668 
00669    if (options) {
00670       char *opts[OPT_ARG_ARRAY_SIZE];
00671       
00672       ast_app_parse_options(spy_opts, &flags, opts, options);
00673       if (ast_test_flag(&flags, OPTION_GROUP))
00674          mygroup = opts[OPT_ARG_GROUP];
00675 
00676       if (ast_test_flag(&flags, OPTION_RECORD) &&
00677           !(recbase = opts[OPT_ARG_RECORD]))
00678          recbase = "chanspy";
00679 
00680       if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) {
00681          int vol;
00682 
00683          if ((sscanf(opts[OPT_ARG_VOLUME], "%d", &vol) != 1) || (vol > 4) || (vol < -4))
00684             ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n");
00685          else
00686             volfactor = vol;
00687       }
00688 
00689       if (ast_test_flag(&flags, OPTION_PRIVATE))
00690          ast_set_flag(&flags, OPTION_WHISPER);
00691    }
00692 
00693    oldwf = chan->writeformat;
00694    if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
00695       ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
00696       ast_module_user_remove(u);
00697       return -1;
00698    }
00699 
00700    if (recbase) {
00701       char filename[512];
00702 
00703       snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL));
00704       if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0644)) <= 0) {
00705          ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename);
00706          fd = 0;
00707       }
00708    }
00709 
00710    res = common_exec(chan, &flags, volfactor, fd, mygroup, NULL, exten, context);
00711 
00712    if (fd)
00713       close(fd);
00714 
00715    if (oldwf && ast_set_write_format(chan, oldwf) < 0)
00716       ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
00717 
00718    ast_module_user_remove(u);
00719 
00720    return res;
00721 }
00722 
00723 static int unload_module(void)
00724 {
00725    int res = 0;
00726 
00727    res |= ast_unregister_application(app_chan);
00728    res |= ast_unregister_application(app_ext);
00729 
00730    ast_module_user_hangup_all();
00731 
00732    return res;
00733 }
00734 
00735 static int load_module(void)
00736 {
00737    int res = 0;
00738 
00739    res |= ast_register_application(app_chan, chanspy_exec, tdesc, desc_chan);
00740    res |= ast_register_application(app_ext, extenspy_exec, tdesc, desc_ext);
00741 
00742    return res;
00743 }
00744 
00745 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Listen to the audio of an active channel");

Generated on Mon May 14 04:42:50 2007 for Asterisk - the Open Source PBX by  doxygen 1.5.1