various cleanups:
authorKevin P. Fleming <kpfleming@digium.com>
Thu, 27 Jul 2006 22:20:52 +0000 (22:20 +0000)
committerKevin P. Fleming <kpfleming@digium.com>
Thu, 27 Jul 2006 22:20:52 +0000 (22:20 +0000)
  use API call for finding channel by name prefix
  code formatting to match guidelines (lost about half the of the indenting)
  remove useless automatic variable initializations
  don't set the spying channel's read format to SLINEAR when we don't do anything with the voice frames we read from it anyway
  use proper option argument checking for volume argument

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@38368 65c4cc65-6c06-0410-ace0-fbb531ad65f3

apps/app_chanspy.c

index 9137c7e..6a405af 100644 (file)
@@ -54,8 +54,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 AST_MUTEX_DEFINE_STATIC(modlock);
 
 #define AST_NAME_STRLEN 256
-#define ALL_DONE(u, ret) LOCAL_USER_REMOVE(u); return ret;
-#define get_volfactor(x) x ? ((x > 0) ? (1 << x) : ((1 << abs(x)) * -1)) : 0
 
 static const char *tdesc = "Listen to the audio of an active channel";
 static const char *app = "ChanSpy";
@@ -120,28 +118,28 @@ struct chanspy_translation_helper {
 static struct ast_channel *local_channel_walk(struct ast_channel *chan) 
 {
        struct ast_channel *ret;
+
        ast_mutex_lock(&modlock);       
-       if ((ret = ast_channel_walk_locked(chan))) {
+
+       if ((ret = ast_channel_walk_locked(chan)))
                ast_mutex_unlock(&ret->lock);
-       }
+
        ast_mutex_unlock(&modlock);                     
+
        return ret;
 }
 
 static struct ast_channel *local_get_channel_begin_name(char *name) 
 {
-       struct ast_channel *chan, *ret = NULL;
-       ast_mutex_lock(&modlock);
-       chan = local_channel_walk(NULL);
-       while (chan) {
-               if (!strncmp(chan->name, name, strlen(name))) {
-                       ret = chan;
-                       break;
-               }
-               chan = local_channel_walk(chan);
-       }
-       ast_mutex_unlock(&modlock);
-       
+       struct ast_channel *ret;
+
+       ast_mutex_lock(&modlock);       
+
+       if ((ret = ast_get_channel_by_name_prefix_locked(name, strlen(name))))
+               ast_mutex_unlock(&ret->lock);
+
+       ast_mutex_unlock(&modlock);                     
+
        return ret;
 }
 
@@ -185,7 +183,6 @@ static int spy_generate(struct ast_channel *chan, void *data, int len, int sampl
        return 0;
 }
 
-
 static struct ast_generator spygen = {
        .alloc = spy_alloc,
        .release = spy_release,
@@ -203,9 +200,8 @@ static int start_spying(struct ast_channel *chan, struct ast_channel *spychan, s
        res = ast_channel_spy_add(chan, spy);
        ast_channel_unlock(chan);
 
-       if (!res && ast_test_flag(chan, AST_FLAG_NBRIDGE) && (peer = ast_bridged_channel(chan))) {
+       if (!res && ast_test_flag(chan, AST_FLAG_NBRIDGE) && (peer = ast_bridged_channel(chan)))
                ast_softhangup(peer, AST_SOFTHANGUP_UNBRIDGE);  
-       }
 
        return res;
 }
@@ -250,106 +246,99 @@ static void set_volume(struct ast_channel *chan, struct chanspy_translation_help
 
        if (!ast_channel_setoption(chan, AST_OPTION_TXGAIN, &volume_adjust, sizeof(volume_adjust), 0))
                csth->volfactor = 0;
+       csth->spy.read_vol_adjustment = csth->volfactor;
+       csth->spy.write_vol_adjustment = csth->volfactor;
 }
 
 static int channel_spy(struct ast_channel *chan, struct ast_channel *spyee, int *volfactor, int fd) 
 {
        struct chanspy_translation_helper csth;
-       int running, res = 0, x = 0;
-       char inp[24];
-       char *name=NULL;
+       int running, res, x = 0;
+       char inp[24] = {0};
+       char *name;
        struct ast_frame *f;
 
-       running = (chan && !ast_check_hangup(chan) && spyee && !ast_check_hangup(spyee));
-
-       if (running) {
-               memset(inp, 0, sizeof(inp));
-               name = ast_strdupa(spyee->name);
-               if (option_verbose >= 2)
-                       ast_verbose(VERBOSE_PREFIX_2 "Spying on channel %s\n", name);
-
-               memset(&csth, 0, sizeof(csth));
-               ast_set_flag(&csth.spy, CHANSPY_FORMAT_AUDIO);
-               ast_set_flag(&csth.spy, CHANSPY_TRIGGER_NONE);
-               ast_set_flag(&csth.spy, CHANSPY_MIXAUDIO);
-               csth.spy.type = chanspy_spy_type;
-               csth.spy.status = CHANSPY_RUNNING;
-               csth.spy.read_queue.format = AST_FORMAT_SLINEAR;
-               csth.spy.write_queue.format = AST_FORMAT_SLINEAR;
-               ast_mutex_init(&csth.spy.lock);
-               csth.volfactor = *volfactor;
-               set_volume(chan, &csth);
-               csth.spy.read_vol_adjustment = csth.volfactor;
-               csth.spy.write_vol_adjustment = csth.volfactor;
-               csth.fd = fd;
-
-               if (start_spying(spyee, chan, &csth.spy))
-                       running = 0;
+       if (!(chan && !ast_check_hangup(chan) && spyee && !ast_check_hangup(spyee)))
+               return 0;
+
+       name = ast_strdupa(spyee->name);
+       if (option_verbose >= 2)
+               ast_verbose(VERBOSE_PREFIX_2 "Spying on channel %s\n", name);
+
+       memset(&csth, 0, sizeof(csth));
+       ast_set_flag(&csth.spy, CHANSPY_FORMAT_AUDIO);
+       ast_set_flag(&csth.spy, CHANSPY_TRIGGER_NONE);
+       ast_set_flag(&csth.spy, CHANSPY_MIXAUDIO);
+       csth.spy.type = chanspy_spy_type;
+       csth.spy.status = CHANSPY_RUNNING;
+       csth.spy.read_queue.format = AST_FORMAT_SLINEAR;
+       csth.spy.write_queue.format = AST_FORMAT_SLINEAR;
+       ast_mutex_init(&csth.spy.lock);
+       csth.volfactor = *volfactor;
+       set_volume(chan, &csth);
+       csth.fd = fd;
+       
+       if (start_spying(spyee, chan, &csth.spy)) {
+               ast_mutex_destroy(&csth.spy.lock);
+               return 0;
        }
 
-       if (running) {
-               running = 1;
-               ast_activate_generator(chan, &spygen, &csth);
-
-               while (csth.spy.status == CHANSPY_RUNNING &&
-                      chan && !ast_check_hangup(chan) &&
-                      spyee &&
-                      !ast_check_hangup(spyee) &&
-                      running == 1 &&
-                      (res = ast_waitfor(chan, -1) > -1)) {
-                       if ((f = ast_read(chan))) {
-                               res = 0;
-                               if (f->frametype == AST_FRAME_DTMF) {
-                                       res = f->subclass;
-                               }
-                               ast_frfree(f);
-                               if (!res) {
-                                       continue;
-                               }
-                       } else {
+       ast_activate_generator(chan, &spygen, &csth);
+
+       /* Note: it is very important that the ast_waitfor() be the first
+          condition in this expression, so that if we wait for some period
+          of time before receiving a frame from our spying channel, we check
+          for hangup on the spied-on channel _after_ knowing that frame
+          has arrived, since the spied-on channel could have gone away while
+          we were waiting
+       */
+       while ((res = ast_waitfor(chan, 500) > -1) &&
+              csth.spy.status == CHANSPY_RUNNING &&
+              !ast_check_hangup(chan) &&
+              !ast_check_hangup(spyee)) {
+               if (!(f = ast_read(chan)))
+                       break;
+
+               res = (f->frametype == AST_FRAME_DTMF) ? f->subclass : 0;
+               ast_frfree(f);
+               if (!res)
+                       continue;
+
+               if (x == sizeof(inp))
+                       x = 0;
+
+               if (res < 0) {
+                       running = -1;
+                       break;
+               }
+
+               if (res == '*') {
+                       running = 0;
+                       break;
+               } else if (res == '#') {
+                       if (!ast_strlen_zero(inp)) {
+                               running = atoi(inp);
                                break;
                        }
-                       if (x == sizeof(inp)) {
-                               x = 0;
-                       }
-                       if (res < 0) {
-                               running = -1;
-                       }
-                       if (res == 0) {
-                               continue;
-                       } else if (res == '*') {
-                               running = 0; 
-                       } else if (res == '#') {
-                               if (!ast_strlen_zero(inp)) {
-                                       running = x ? atoi(inp) : -1;
-                                       break;
-                               } else {
-                                       (*volfactor)++;
-                                       if (*volfactor > 4) {
-                                               *volfactor = -4;
-                                       }
-                                       if (option_verbose > 2) {
-                                               ast_verbose(VERBOSE_PREFIX_3 "Setting spy volume on %s to %d\n", chan->name, *volfactor);
-                                       }
-                                       csth.volfactor = *volfactor;
-                                       set_volume(chan, &csth);
-                                       csth.spy.read_vol_adjustment = csth.volfactor;
-                                       csth.spy.write_vol_adjustment = csth.volfactor;
-                               }
-                       } else if (res >= 48 && res <= 57) {
-                               inp[x++] = res;
-                       }
-               }
-               ast_deactivate_generator(chan);
-               stop_spying(spyee, &csth.spy);
 
-               if (option_verbose >= 2) {
-                       ast_verbose(VERBOSE_PREFIX_2 "Done Spying on channel %s\n", name);
+                       (*volfactor)++;
+                       if (*volfactor > 4)
+                               *volfactor = -4;
+                       if (option_verbose > 2)
+                               ast_verbose(VERBOSE_PREFIX_3 "Setting spy volume on %s to %d\n", chan->name, *volfactor);
+                       csth.volfactor = *volfactor;
+                       set_volume(chan, &csth);
+               } else if (res >= '0' && res <= '9') {
+                       inp[x++] = res;
                }
-       } else {
-               running = 0;
        }
 
+       ast_deactivate_generator(chan);
+       stop_spying(spyee, &csth.spy);
+       
+       if (option_verbose >= 2)
+               ast_verbose(VERBOSE_PREFIX_2 "Done Spying on channel %s\n", name);
+       
        ast_mutex_destroy(&csth.spy.lock);
 
        return running;
@@ -358,44 +347,32 @@ static int channel_spy(struct ast_channel *chan, struct ast_channel *spyee, int
 static int chanspy_exec(struct ast_channel *chan, void *data)
 {
        struct localuser *u;
-       struct ast_channel *peer=NULL, *prev=NULL;
+       struct ast_channel *peer, *prev;
        char name[AST_NAME_STRLEN],
                peer_name[AST_NAME_STRLEN + 5],
-               *args,
-               *ptr = NULL,
+               *ptr,
                *options = NULL,
                *spec = NULL,
                *argv[5],
                *mygroup = NULL,
                *recbase = NULL;
        int res = -1,
-               volfactor = 0,
+               volfactor,
                silent = 0,
-               argc = 0,
+               argc,
                bronly = 0,
-               chosen = 0,
-               count=0,
-               waitms = 100,
-               num = 0,
-               oldrf = 0,
-               oldwf = 0,
+               waitms,
+               num,
+               oldwf,
                fd = 0;
        struct ast_flags flags;
        signed char zero_volume = 0;
 
-       if (!(args = ast_strdupa(data)))
-               return -1;
+       data = ast_strdupa(data);
 
        LOCAL_USER_ADD(u);
 
-       oldrf = chan->readformat;
        oldwf = chan->writeformat;
-       if (ast_set_read_format(chan, AST_FORMAT_SLINEAR) < 0) {
-               ast_log(LOG_ERROR, "Could Not Set Read Format.\n");
-               LOCAL_USER_REMOVE(u);
-               return -1;
-       }
-       
        if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
                ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
                LOCAL_USER_REMOVE(u);
@@ -406,9 +383,9 @@ static int chanspy_exec(struct ast_channel *chan, void *data)
 
        ast_set_flag(chan, AST_FLAG_SPYING); /* so nobody can spy on us while we are spying */
 
-       if ((argc = ast_app_separate_args(args, '|', argv, sizeof(argv) / sizeof(argv[0])))) {
+       if ((argc = ast_app_separate_args(data, '|', argv, sizeof(argv) / sizeof(argv[0])))) {
                spec = argv[0];
-               if ( argc > 1) {
+               if (argc > 1) {
                        options = argv[1];
                }
                if (ast_strlen_zero(spec) || !strcmp(spec, "all")) {
@@ -418,157 +395,156 @@ static int chanspy_exec(struct ast_channel *chan, void *data)
 
        if (options) {
                char *opts[OPT_ARG_ARRAY_SIZE];
+               
                ast_app_parse_options(chanspy_opts, &flags, opts, options);
-               if (ast_test_flag(&flags, OPTION_GROUP)) {
-                       mygroup = opts[1];
-               }
-               if (ast_test_flag(&flags, OPTION_RECORD)) {
-                       if (!(recbase = opts[2])) {
-                               recbase = "chanspy";
-                       }
-               }
+               if (ast_test_flag(&flags, OPTION_GROUP))
+                       mygroup = opts[OPT_ARG_GROUP];
+
+               if (ast_test_flag(&flags, OPTION_RECORD) &&
+                   !(recbase = opts[OPT_ARG_RECORD]))
+                       recbase = "chanspy";
+
                silent = ast_test_flag(&flags, OPTION_QUIET);
                bronly = ast_test_flag(&flags, OPTION_BRIDGED);
-               if (ast_test_flag(&flags, OPTION_VOLUME) && opts[1]) {
+
+               if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) {
                        int vol;
 
-                       if ((sscanf(opts[0], "%d", &vol) != 1) || (vol > 4) || (vol < -4))
+                       if ((sscanf(opts[OPT_ARG_VOLUME], "%d", &vol) != 1) || (vol > 4) || (vol < -4))
                                ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n");
                        else
                                volfactor = vol;
-                       }
+               }
        }
 
        if (recbase) {
                char filename[512];
-               snprintf(filename,sizeof(filename),"%s/%s.%d.raw",ast_config_AST_MONITOR_DIR, recbase, (int)time(NULL));
+
+               snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL));
                if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0644)) <= 0) {
-                       ast_log(LOG_WARNING, "Cannot open %s for recording\n", filename);
+                       ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename);
                        fd = 0;
                }
        }
 
-       for(;;) {
+       waitms = 100;
+
+       for (;;) {
                if (!silent) {
                        res = ast_streamfile(chan, "beep", chan->language);
                        if (!res)
                                res = ast_waitstream(chan, "");
-                       if (res < 0) {
+                       else if (res < 0) {
                                ast_clear_flag(chan, AST_FLAG_SPYING);
                                break;
                        }
                }
 
-               count = 0;
                res = ast_waitfordigit(chan, waitms);
                if (res < 0) {
                        ast_clear_flag(chan, AST_FLAG_SPYING);
                        break;
                }
                                
-               peer = local_channel_walk(NULL);
-               prev=NULL;
-               while(peer) {
-                       if (peer != chan) {
-                               const char *group = NULL;
-                               int igrp = 1;
-                               char *groups[25] = {0};
-                               int num_groups = 0;
-                               char *dup_group;
+               /* reset for the next loop around, unless overridden later */
+               waitms = 100;
+
+               for (peer = local_channel_walk(NULL), prev = NULL;
+                    peer;
+                    peer = local_channel_walk(peer)) {
+                       const char *group;
+                       int igrp = 0;
+                       char *groups[25];
+                       int num_groups = 0;
+                       char *dup_group;
+                       int x;
+                       char *s;
                                
-                               if (peer == prev && !chosen) {
-                                       break;
-                               }
-                               chosen = 0;
-
-                               if (mygroup) {
-                                       int x;
+                       if (peer == chan)
+                               continue;
 
-                                       if ((group = pbx_builtin_getvar_helper(peer, "SPYGROUP"))) {
-                                               dup_group = ast_strdupa(group);
-                                               num_groups = ast_app_separate_args(dup_group, ':', groups, sizeof(groups) / sizeof(groups[0]));
-                                       }
+                       if (peer == prev)
+                               break;
 
-                                       igrp = 0;
-                                       if (num_groups) {
-                                               for (x = 0; x < num_groups; x++) {
-                                                       if (!strcmp(mygroup, groups[x])) {
-                                                               igrp = 1;
-                                                               break;
-                                                       }
-                                               }
-                                       } 
+                       if (mygroup) {
+                               if ((group = pbx_builtin_getvar_helper(peer, "SPYGROUP"))) {
+                                       dup_group = ast_strdupa(group);
+                                       num_groups = ast_app_separate_args(dup_group, ':', groups,
+                                                                          sizeof(groups) / sizeof(groups[0]));
                                }
-
-                               if (igrp && (!spec || ((strlen(spec) <= strlen(peer->name) &&
-                                                       !strncasecmp(peer->name, spec, strlen(spec)))))) {
-                                       if (peer && (!bronly || ast_bridged_channel(peer)) &&
-                                           !ast_check_hangup(peer) && !ast_test_flag(peer, AST_FLAG_SPYING)) {
-                                               int x = 0;
-                                               strncpy(peer_name, "spy-", 5);
-                                               strncpy(peer_name + strlen(peer_name), peer->name, AST_NAME_STRLEN);
-                                               ptr = strchr(peer_name, '/');
-                                               *ptr = '\0';
-                                               ptr++;
-                                               for (x = 0 ; x < strlen(peer_name) ; x++) {
-                                                       if (peer_name[x] == '/') {
-                                                               break;
-                                                       }
-                                                       peer_name[x] = tolower(peer_name[x]);
-                                               }
-
-                                               if (!silent) {
-                                                       if (ast_fileexists(peer_name, NULL, NULL) != -1) {
-                                                               res = ast_streamfile(chan, peer_name, chan->language);
-                                                               if (!res)
-                                                                       res = ast_waitstream(chan, "");
-                                                               if (res)
-                                                                       break;
-                                                       } else
-                                                               res = ast_say_character_str(chan, peer_name, "", chan->language);
-                                                       if ((num=atoi(ptr))) 
-                                                               ast_say_digits(chan, atoi(ptr), "", chan->language);
-                                               }
-                                               count++;
-                                               prev = peer;
-                                               res = channel_spy(chan, peer, &volfactor, fd);
-                                               if (res == -1) {
+                               
+                               if (num_groups) {
+                                       for (x = 0; x < num_groups; x++) {
+                                               if (!strcmp(mygroup, groups[x])) {
+                                                       igrp = 1;
                                                        break;
-                                               } else if (res > 1 && spec) {
-                                                       snprintf(name, AST_NAME_STRLEN, "%s/%d", spec, res);
-                                                       if ((peer = local_get_channel_begin_name(name))) {
-                                                               chosen = 1;
-                                                       }
-                                                       continue;
                                                }
                                        }
-                               }
+                               } 
                        }
-                       if ((peer = local_channel_walk(peer)) == NULL) {
+                       
+                       if (!igrp)
+                               continue;
+
+                       if (spec && strncasecmp(peer->name, spec, strlen(spec)))
+                               continue;
+
+                       if (bronly && !ast_bridged_channel(peer))
+                               continue;
+
+                       if (ast_check_hangup(peer) || ast_test_flag(peer, AST_FLAG_SPYING))
+                               continue;
+
+                       strcpy(peer_name, "spy-");
+                       strncat(peer_name, peer->name, AST_NAME_STRLEN);
+                       ptr = strchr(peer_name, '/');
+                       *ptr++ = '\0';
+                       
+                       for (s = peer_name; s < ptr; s++)
+                               *s = tolower(*s);
+                       
+                       if (!silent) {
+                               if (ast_fileexists(peer_name, NULL, NULL) != -1) {
+                                       res = ast_streamfile(chan, peer_name, chan->language);
+                                       if (!res)
+                                               res = ast_waitstream(chan, "");
+                                       if (res)
+                                               break;
+                               } else
+                                       res = ast_say_character_str(chan, peer_name, "", chan->language);
+                               if ((num = atoi(ptr))) 
+                                       ast_say_digits(chan, atoi(ptr), "", chan->language);
+                       }
+                       
+                       waitms = 5000;
+                       prev = peer;
+                       res = channel_spy(chan, peer, &volfactor, fd);
+                       
+                       if (res == -1) {
                                break;
+                       } else if (res > 1 && spec) {
+                               snprintf(name, AST_NAME_STRLEN, "%s/%d", spec, res);
+                               if ((peer = local_get_channel_begin_name(name)))
+                                       prev = NULL;
+                               
+                               continue;
                        }
                }
-               waitms = count ? 100 : 5000;
        }
        
-
-       if (fd > 0) {
+       if (fd)
                close(fd);
-       }
 
-       if (oldrf && ast_set_read_format(chan, oldrf) < 0) {
-               ast_log(LOG_ERROR, "Could Not Set Read Format.\n");
-       }
-       
-       if (oldwf && ast_set_write_format(chan, oldwf) < 0) {
+       if (oldwf && ast_set_write_format(chan, oldwf) < 0)
                ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
-       }
 
        ast_clear_flag(chan, AST_FLAG_SPYING);
 
        ast_channel_setoption(chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);
 
-       ALL_DONE(u, res);
+       LOCAL_USER_REMOVE(u);
+
+       return res;
 }
 
 static int unload_module(void *mod)
@@ -585,6 +561,7 @@ static int unload_module(void *mod)
 static int load_module(void *mod)
 {
        __mod_desc = mod;
+
        return ast_register_application(app, chanspy_exec, tdesc, desc);
 }