Sat Apr 12 07:12:16 2008

Asterisk developer's documentation


app_chanspy.c

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

Generated on Sat Apr 12 07:12:16 2008 for Asterisk - the Open Source PBX by  doxygen 1.5.5