static int common_exec(struct ast_channel *chan, struct ast_flags *flags, int volfactor, const int fd, struct spy_dtmf_options *user_options, const char *mygroup, const char *myenforced, const char *spec, const char *exten, const char *context, const char *mailbox, const char *name_context) { char nameprefix[AST_NAME_STRLEN]; char peer_name[AST_NAME_STRLEN + 5]; char exitcontext[AST_MAX_CONTEXT] = ""; signed char zero_volume = 0; int waitms; int res; char *ptr; int num; int num_spyed_upon = 1; struct ast_channel_iterator *iter = NULL; if (ast_test_flag(flags, OPTION_EXIT)) { const char *c; ast_channel_lock(chan); if ((c = pbx_builtin_getvar_helper(chan, "SPY_EXIT_CONTEXT"))) { ast_copy_string(exitcontext, c, sizeof(exitcontext)); } else if (!ast_strlen_zero(chan->macrocontext)) { ast_copy_string(exitcontext, chan->macrocontext, sizeof(exitcontext)); } else { ast_copy_string(exitcontext, chan->context, sizeof(exitcontext)); } ast_channel_unlock(chan); } if (chan->_state != AST_STATE_UP) ast_answer(chan); ast_set_flag(chan, AST_FLAG_SPYING); /* so nobody can spy on us while we are spying */ waitms = 100; for (;;) { struct ast_autochan *autochan = NULL, *next_autochan = NULL; struct ast_channel *prev = NULL; if (!ast_test_flag(flags, OPTION_QUIET) && num_spyed_upon) { res = ast_streamfile(chan, "beep", chan->language); if (!res) res = ast_waitstream(chan, ""); else if (res < 0) { ast_clear_flag(chan, AST_FLAG_SPYING); break; } if (!ast_strlen_zero(exitcontext)) { char tmp[2]; tmp[0] = res; tmp[1] = '\0'; if (!ast_goto_if_exists(chan, exitcontext, tmp, 1)) goto exit; else ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext); } } /* Set up the iterator we'll be using during this call */ if (!ast_strlen_zero(spec)) { iter = ast_channel_iterator_by_name_new(spec, strlen(spec)); } else if (!ast_strlen_zero(exten)) { iter = ast_channel_iterator_by_exten_new(exten, context); } else { iter = ast_channel_iterator_all_new(); } if (!iter) { return -1; } res = ast_waitfordigit(chan, waitms); if (res < 0) { ast_clear_flag(chan, AST_FLAG_SPYING); break; } if (!ast_strlen_zero(exitcontext)) { char tmp[2]; tmp[0] = res; tmp[1] = '\0'; if (!ast_goto_if_exists(chan, exitcontext, tmp, 1)) goto exit; else ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext); } /* reset for the next loop around, unless overridden later */ waitms = 100; num_spyed_upon = 0; for (autochan = next_channel(iter, autochan, chan); autochan; prev = autochan->chan, ast_autochan_destroy(autochan), autochan = next_autochan ? next_autochan : next_channel(iter, autochan, chan), next_autochan = NULL) { int igrp = !mygroup; int ienf = !myenforced; char *s; if (autochan->chan == prev) { ast_autochan_destroy(autochan); break; } if (ast_check_hangup(chan)) { ast_autochan_destroy(autochan); break; } if (ast_test_flag(flags, OPTION_BRIDGED) && !ast_bridged_channel(autochan->chan)) { continue; } if (ast_check_hangup(autochan->chan) || ast_test_flag(autochan->chan, AST_FLAG_SPYING)) { continue; } if (mygroup) { int num_groups = 0; int num_mygroups = 0; char dup_group[512]; char dup_mygroup[512]; char *groups[NUM_SPYGROUPS]; char *mygroups[NUM_SPYGROUPS]; const char *group = NULL; int x; int y; ast_copy_string(dup_mygroup, mygroup, sizeof(dup_mygroup)); num_mygroups = ast_app_separate_args(dup_mygroup, ':', mygroups, ARRAY_LEN(mygroups)); /* Before dahdi scan was part of chanspy, it would use the "GROUP" variable * rather than "SPYGROUP", this check is done to preserve expected behavior */ if (ast_test_flag(flags, OPTION_DAHDI_SCAN)) { group = pbx_builtin_getvar_helper(autochan->chan, "GROUP"); } else { group = pbx_builtin_getvar_helper(autochan->chan, "SPYGROUP"); } if (!ast_strlen_zero(group)) { ast_copy_string(dup_group, group, sizeof(dup_group)); num_groups = ast_app_separate_args(dup_group, ':', groups, ARRAY_LEN(groups)); } for (y = 0; y < num_mygroups; y++) { for (x = 0; x < num_groups; x++) { if (!strcmp(mygroups[y], groups[x])) { igrp = 1; break; } } } } if (!igrp) { continue; } if (myenforced) { char ext[AST_CHANNEL_NAME + 3]; char buffer[512]; char *end; snprintf(buffer, sizeof(buffer) - 1, ":%s:", myenforced); ast_copy_string(ext + 1, autochan->chan->name, sizeof(ext) - 1); if ((end = strchr(ext, '-'))) { *end++ = ':'; *end = '\0'; } ext[0] = ':'; if (strcasestr(buffer, ext)) { ienf = 1; } } if (!ienf) { continue; } strcpy(peer_name, "spy-"); strncat(peer_name, autochan->chan->name, AST_NAME_STRLEN - 4 - 1); ptr = strchr(peer_name, '/'); *ptr++ = '\0'; ptr = strsep(&ptr, "-"); for (s = peer_name; s < ptr; s++) *s = tolower(*s); if (!ast_test_flag(flags, OPTION_QUIET)) { if (ast_test_flag(flags, OPTION_NAME)) { const char *local_context = S_OR(name_context, "default"); const char *local_mailbox = S_OR(mailbox, ptr); res = ast_app_sayname(chan, local_mailbox, local_context); } if (!ast_test_flag(flags, OPTION_NAME) || res < 0) { if (!ast_test_flag(flags, OPTION_NOTECH)) { if (ast_fileexists(peer_name, NULL, NULL) > 0) { res = ast_streamfile(chan, peer_name, chan->language); if (!res) { res = ast_waitstream(chan, ""); } if (res) { ast_autochan_destroy(autochan); break; } } else { res = ast_say_character_str(chan, peer_name, "", chan->language); } } if ((num = atoi(ptr))) ast_say_digits(chan, atoi(ptr), "", chan->language); } } res = channel_spy(chan, autochan, &volfactor, fd, user_options, flags, exitcontext); num_spyed_upon++; if (res == -1) { ast_autochan_destroy(autochan); goto exit; } else if (res == -2) { res = 0; ast_autochan_destroy(autochan); goto exit; } else if (res > 1 && spec) { struct ast_channel *next; snprintf(nameprefix, AST_NAME_STRLEN, "%s/%d", spec, res); if ((next = ast_channel_get_by_name_prefix(nameprefix, strlen(nameprefix)))) { next_autochan = ast_autochan_setup(next); next = ast_channel_unref(next); } else { /* stay on this channel, if it is still valid */ if (!ast_check_hangup(autochan->chan)) { next_autochan = ast_autochan_setup(autochan->chan); } else { /* the channel is gone */ next_autochan = NULL; } } } else if (res == 0 && ast_test_flag(flags, OPTION_EXITONHANGUP)) { goto exit; } } iter = ast_channel_iterator_destroy(iter); if (res == -1 || ast_check_hangup(chan)) break; if (ast_test_flag(flags, OPTION_STOP) && !next_autochan) { break; } } exit: ast_clear_flag(chan, AST_FLAG_SPYING); ast_channel_setoption(chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0); return res; }
/* play name of mailbox owner. * returns: -1 for bad or missing extension * '1' for selected entry from directory * '*' for skipped entry from directory */ static int play_mailbox_owner(struct ast_channel *chan, char *context, char *dialcontext, char *ext, char *name, int readext, int fromappvm) { int res = 0; int loop; char fn[256]; /* Check for the VoiceMail2 greeting first */ snprintf(fn, sizeof(fn), "%s/voicemail/%s/%s/greet", ast_config_AST_SPOOL_DIR, context, ext); #ifdef ODBC_STORAGE retrieve_file(fn); #endif if (ast_fileexists(fn, NULL, chan->language) <= 0) { /* no file, check for an old-style Voicemail greeting */ snprintf(fn, sizeof(fn), "%s/vm/%s/greet", ast_config_AST_SPOOL_DIR, ext); } #ifdef ODBC_STORAGE retrieve_file(fn); #endif if (ast_fileexists(fn, NULL, chan->language) > 0) { res = ast_stream_and_wait(chan, fn, chan->language, AST_DIGIT_ANY); ast_stopstream(chan); /* If Option 'e' was specified, also read the extension number with the name */ if (readext) { ast_stream_and_wait(chan, "vm-extension", chan->language, AST_DIGIT_ANY); res = ast_say_character_str(chan, ext, AST_DIGIT_ANY, chan->language); } } else { res = ast_say_character_str(chan, S_OR(name, ext), AST_DIGIT_ANY, chan->language); if (!ast_strlen_zero(name) && readext) { ast_stream_and_wait(chan, "vm-extension", chan->language, AST_DIGIT_ANY); res = ast_say_character_str(chan, ext, AST_DIGIT_ANY, chan->language); } } #ifdef ODBC_STORAGE ast_filedelete(fn, NULL); #endif for (loop = 3 ; loop > 0; loop--) { if (!res) res = ast_stream_and_wait(chan, "dir-instr", chan->language, AST_DIGIT_ANY); if (!res) res = ast_waitfordigit(chan, 3000); ast_stopstream(chan); if (res < 0) /* User hungup, so jump out now */ break; if (res == '1') { /* Name selected */ if (fromappvm) { /* We still want to set the exten though */ ast_copy_string(chan->exten, ext, sizeof(chan->exten)); } else { if (ast_goto_if_exists(chan, dialcontext, ext, 1)) { ast_log(LOG_WARNING, "Can't find extension '%s' in context '%s'. " "Did you pass the wrong context to Directory?\n", ext, dialcontext); res = -1; } } break; } if (res == '*') /* Skip to next match in list */ break; /* Not '1', or '*', so decrement number of tries */ res = 0; } return(res); }
/* play name of mailbox owner. * returns: -1 for bad or missing extension * '1' for selected entry from directory * '*' for skipped entry from directory */ static int play_mailbox_owner(struct ast_channel *chan, char *context, char *dialcontext, char *ext, char *name, int fromappvm) { int res = 0; int loop = 3; char fn[256]; char fn2[256]; /* Check for the VoiceMail2 greeting first */ snprintf(fn, sizeof(fn), "%s/voicemail/%s/%s/greet", (char *)ast_config_AST_SPOOL_DIR, context, ext); #ifdef USE_ODBC_STORAGE retrieve_file(fn); #endif /* Otherwise, check for an old-style Voicemail greeting */ snprintf(fn2, sizeof(fn2), "%s/vm/%s/greet", (char *)ast_config_AST_SPOOL_DIR, ext); #ifdef USE_ODBC_STORAGE retrieve_file(fn2); #endif if (ast_fileexists(fn, NULL, chan->language) > 0) { res = ast_streamfile(chan, fn, chan->language); if (!res) { res = ast_waitstream(chan, AST_DIGIT_ANY); } ast_stopstream(chan); } else if (ast_fileexists(fn2, NULL, chan->language) > 0) { res = ast_streamfile(chan, fn2, chan->language); if (!res) { res = ast_waitstream(chan, AST_DIGIT_ANY); } ast_stopstream(chan); } else { res = ast_say_character_str(chan, !ast_strlen_zero(name) ? name : ext, AST_DIGIT_ANY, chan->language); } #ifdef USE_ODBC_STORAGE ast_filedelete(fn, NULL); ast_filedelete(fn2, NULL); #endif while (loop) { if (!res) { res = ast_streamfile(chan, "dir-instr", chan->language); } if (!res) { res = ast_waitstream(chan, AST_DIGIT_ANY); } if (!res) { res = ast_waitfordigit(chan, 3000); } ast_stopstream(chan); if (res > -1) { switch (res) { case '1': /* Name selected */ loop = 0; if (fromappvm) { /* We still want to set the exten */ ast_copy_string(chan->exten, ext, sizeof(chan->exten)); } else { if (ast_goto_if_exists(chan, dialcontext, ext, 1)) { ast_log(LOG_WARNING, "Can't find extension '%s' in context '%s'. " "Did you pass the wrong context to Directory?\n", ext, dialcontext); res = -1; } } break; case '*': /* Skip to next match in list */ loop = 0; break; default: /* Not '1', or '*', so decrement number of tries */ res = 0; loop--; break; } /* end switch */ } /* end if */ else { /* User hungup, so jump out now */ loop = 0; } } /* end while */ return(res); }
static int common_exec(struct ast_channel *chan, const struct ast_flags *flags, int volfactor, const int fd, const char *mygroup, const char *myenforced, const char *spec, const char *exten, const char *context) { char nameprefix[AST_NAME_STRLEN]; char peer_name[AST_NAME_STRLEN + 5]; char exitcontext[AST_MAX_CONTEXT] = ""; signed char zero_volume = 0; int waitms; int res; char *ptr; int num; int num_spyed_upon = 1; struct chanspy_ds chanspy_ds; if (ast_test_flag(flags, OPTION_EXIT)) { const char *c; if ((c = pbx_builtin_getvar_helper(chan, "SPY_EXIT_CONTEXT"))) ast_copy_string(exitcontext, c, sizeof(exitcontext)); else if (!ast_strlen_zero(chan->macrocontext)) ast_copy_string(exitcontext, chan->macrocontext, sizeof(exitcontext)); else ast_copy_string(exitcontext, chan->context, sizeof(exitcontext)); } ast_mutex_init(&chanspy_ds.lock); snprintf(chanspy_ds.unique_id, sizeof(chanspy_ds.unique_id), "%d", ast_atomic_fetchadd_int(&next_unique_id_to_use, +1)); if (chan->_state != AST_STATE_UP) ast_answer(chan); ast_set_flag(chan, AST_FLAG_SPYING); /* so nobody can spy on us while we are spying */ waitms = 100; for (;;) { struct chanspy_ds *peer_chanspy_ds = NULL, *next_chanspy_ds = NULL; struct ast_channel *prev = NULL, *peer = NULL; if (!ast_test_flag(flags, OPTION_QUIET) && num_spyed_upon) { res = ast_streamfile(chan, "beep", chan->language); if (!res) res = ast_waitstream(chan, ""); else if (res < 0) { ast_clear_flag(chan, AST_FLAG_SPYING); break; } if (!ast_strlen_zero(exitcontext)) { char tmp[2]; tmp[0] = res; tmp[1] = '\0'; if (!ast_goto_if_exists(chan, exitcontext, tmp, 1)) goto exit; else ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext); } } res = ast_waitfordigit(chan, waitms); if (res < 0) { ast_clear_flag(chan, AST_FLAG_SPYING); break; } if (!ast_strlen_zero(exitcontext)) { char tmp[2]; tmp[0] = res; tmp[1] = '\0'; if (!ast_goto_if_exists(chan, exitcontext, tmp, 1)) goto exit; else ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext); } /* reset for the next loop around, unless overridden later */ waitms = 100; num_spyed_upon = 0; for (peer_chanspy_ds = next_channel(chan, prev, spec, exten, context, &chanspy_ds); peer_chanspy_ds; chanspy_ds_free(peer_chanspy_ds), prev = peer, peer_chanspy_ds = next_chanspy_ds ? next_chanspy_ds : next_channel(chan, prev, spec, exten, context, &chanspy_ds), next_chanspy_ds = NULL) { const char *group; int igrp = !mygroup; char *groups[25]; int num_groups = 0; char dup_group[512]; int x; char *s; char *buffer; char *end; char *ext; char *form_enforced; int ienf = !myenforced; peer = peer_chanspy_ds->chan; ast_mutex_unlock(&peer_chanspy_ds->lock); if (peer == prev) { ast_channel_unlock(peer); chanspy_ds_free(peer_chanspy_ds); break; } if (ast_check_hangup(chan)) { ast_channel_unlock(peer); chanspy_ds_free(peer_chanspy_ds); break; } if (ast_test_flag(flags, OPTION_BRIDGED) && !ast_bridged_channel(peer)) { ast_channel_unlock(peer); continue; } if (ast_check_hangup(peer) || ast_test_flag(peer, AST_FLAG_SPYING)) { ast_channel_unlock(peer); continue; } if (mygroup) { if ((group = pbx_builtin_getvar_helper(peer, "SPYGROUP"))) { ast_copy_string(dup_group, group, sizeof(dup_group)); num_groups = ast_app_separate_args(dup_group, ':', groups, ARRAY_LEN(groups)); } for (x = 0; x < num_groups; x++) { if (!strcmp(mygroup, groups[x])) { igrp = 1; break; } } } if (!igrp) { ast_channel_unlock(peer); continue; } if (myenforced) { /* We don't need to allocate more space than just the length of (peer->name) for ext as we will cut the channel name's ending before copying into ext */ ext = alloca(strlen(peer->name)); form_enforced = alloca(strlen(myenforced) + 3); strcpy(form_enforced, ":"); strcat(form_enforced, myenforced); strcat(form_enforced, ":"); buffer = ast_strdupa(peer->name); if ((end = strchr(buffer, '-'))) { *end++ = ':'; *end = '\0'; } strcpy(ext, ":"); strcat(ext, buffer); if (strcasestr(form_enforced, ext)) ienf = 1; } if (!ienf) continue; strcpy(peer_name, "spy-"); strncat(peer_name, peer->name, AST_NAME_STRLEN - 4 - 1); ptr = strchr(peer_name, '/'); *ptr++ = '\0'; for (s = peer_name; s < ptr; s++) *s = tolower(*s); /* We have to unlock the peer channel here to avoid a deadlock. * So, when we need to dereference it again, we have to lock the * datastore and get the pointer from there to see if the channel * is still valid. */ ast_channel_unlock(peer); if (!ast_test_flag(flags, OPTION_QUIET)) { if (ast_fileexists(peer_name, NULL, NULL) != -1) { res = ast_streamfile(chan, peer_name, chan->language); if (!res) res = ast_waitstream(chan, ""); if (res) { chanspy_ds_free(peer_chanspy_ds); break; } } else res = ast_say_character_str(chan, peer_name, "", chan->language); if ((num = atoi(ptr))) ast_say_digits(chan, atoi(ptr), "", chan->language); } res = channel_spy(chan, peer_chanspy_ds, &volfactor, fd, flags, exitcontext); num_spyed_upon++; if (res == -1) { chanspy_ds_free(peer_chanspy_ds); goto exit; } else if (res == -2) { res = 0; chanspy_ds_free(peer_chanspy_ds); goto exit; } else if (res > 1 && spec) { struct ast_channel *next; snprintf(nameprefix, AST_NAME_STRLEN, "%s/%d", spec, res); if ((next = ast_get_channel_by_name_prefix_locked(nameprefix, strlen(nameprefix)))) { peer_chanspy_ds = chanspy_ds_free(peer_chanspy_ds); next_chanspy_ds = setup_chanspy_ds(next, &chanspy_ds); } else { /* stay on this channel, if it is still valid */ ast_mutex_lock(&peer_chanspy_ds->lock); if (peer_chanspy_ds->chan) { ast_channel_lock(peer_chanspy_ds->chan); next_chanspy_ds = peer_chanspy_ds; peer_chanspy_ds = NULL; } else { /* the channel is gone */ ast_mutex_unlock(&peer_chanspy_ds->lock); next_chanspy_ds = NULL; } } peer = NULL; } } if (res == -1 || ast_check_hangup(chan)) break; } exit: ast_clear_flag(chan, AST_FLAG_SPYING); ast_channel_setoption(chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0); ast_mutex_lock(&chanspy_ds.lock); ast_mutex_unlock(&chanspy_ds.lock); ast_mutex_destroy(&chanspy_ds.lock); return res; }
static int chanspy_exec(struct ast_channel *chan, void *data) { struct localuser *u; struct ast_channel *peer=NULL, *prev=NULL; char name[AST_NAME_STRLEN], peer_name[AST_NAME_STRLEN + 5], *args, *ptr = NULL, *options = NULL, *spec = NULL, *argv[5], *mygroup = NULL, *recbase = NULL; int res = -1, volfactor = 0, silent = 0, argc = 0, bronly = 0, chosen = 0, count=0, waitms = 100, num = 0, oldrf = 0, oldwf = 0, fd = 0; struct ast_flags flags; signed char zero_volume = 0; if (!(args = ast_strdupa((char *)data))) { ast_log(LOG_ERROR, "Out of memory!\n"); return -1; } 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); return -1; } ast_answer(chan); 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])))) { spec = argv[0]; if ( argc > 1) { options = argv[1]; } if (ast_strlen_zero(spec) || !strcmp(spec, "all")) { spec = NULL; } } 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[OPT_ARG_GROUP]; } if (ast_test_flag(&flags, OPTION_RECORD)) { if (!(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[OPT_ARG_VOLUME]) { int vol; 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; } } else ast_clear_flag(&flags, AST_FLAGS_ALL); if (recbase) { char filename[512]; 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); fd = 0; } } for(;;) { if (!silent) { res = ast_streamfile(chan, "beep", chan->language); if (!res) res = ast_waitstream(chan, ""); 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) { char *group = NULL; int igrp = 1; if (peer == prev && !chosen) { break; } chosen = 0; group = pbx_builtin_getvar_helper(peer, "SPYGROUP"); if (mygroup) { if (!group || strcmp(mygroup, group)) { igrp = 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) { 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) { break; } } waitms = count ? 100 : 5000; } if (fd > 0) { 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) { 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); }
static int common_exec(struct ast_channel *chan, const struct ast_flags *flags, int volfactor, const int fd, const char *mygroup, const char *spec, const char *exten, const char *context) { char nameprefix[AST_NAME_STRLEN]; char peer_name[AST_NAME_STRLEN + 5]; signed char zero_volume = 0; int waitms; int res; char *ptr; int num; int num_spyed_upon = 1; struct chanspy_ds chanspy_ds = { 0, }; ast_mutex_init(&chanspy_ds.lock); snprintf(chanspy_ds.unique_id, sizeof(chanspy_ds.unique_id), "%d", ast_atomic_fetchadd_int(&next_unique_id_to_use, +1)); if (chan->_state != AST_STATE_UP) ast_answer(chan); ast_set_flag(chan, AST_FLAG_SPYING); /* so nobody can spy on us while we are spying */ waitms = 100; for (;;) { struct chanspy_ds *peer_chanspy_ds = NULL, *next_chanspy_ds = NULL; struct ast_channel *prev = NULL, *peer = NULL; if (!ast_test_flag(flags, OPTION_QUIET) && num_spyed_upon) { res = ast_streamfile(chan, "beep", chan->language); if (!res) res = ast_waitstream(chan, ""); else if (res < 0) { ast_clear_flag(chan, AST_FLAG_SPYING); break; } } res = ast_waitfordigit(chan, waitms); if (res < 0) { ast_clear_flag(chan, AST_FLAG_SPYING); break; } /* reset for the next loop around, unless overridden later */ waitms = 100; num_spyed_upon = 0; for (peer_chanspy_ds = next_channel(chan, prev, spec, exten, context, &chanspy_ds); peer_chanspy_ds; chanspy_ds_free(peer_chanspy_ds), prev = peer, peer_chanspy_ds = next_chanspy_ds ? next_chanspy_ds : next_channel(chan, prev, spec, exten, context, &chanspy_ds), next_chanspy_ds = NULL) { const char *group; int igrp = !mygroup; char *groups[25]; int num_groups = 0; char dup_group[512]; int x; char *s; peer = peer_chanspy_ds->chan; ast_mutex_unlock(&peer_chanspy_ds->lock); if (peer == prev) { ast_channel_unlock(peer); chanspy_ds_free(peer_chanspy_ds); break; } if (ast_check_hangup(chan)) { ast_channel_unlock(peer); chanspy_ds_free(peer_chanspy_ds); break; } if (ast_test_flag(flags, OPTION_BRIDGED) && !ast_bridged_channel(peer)) { ast_channel_unlock(peer); continue; } if (ast_check_hangup(peer) || ast_test_flag(peer, AST_FLAG_SPYING)) { ast_channel_unlock(peer); continue; } if (mygroup) { if ((group = pbx_builtin_getvar_helper(peer, "SPYGROUP"))) { ast_copy_string(dup_group, group, sizeof(dup_group)); num_groups = ast_app_separate_args(dup_group, ':', groups, sizeof(groups) / sizeof(groups[0])); } for (x = 0; x < num_groups; x++) { if (!strcmp(mygroup, groups[x])) { igrp = 1; break; } } } if (!igrp) { ast_channel_unlock(peer); continue; } strcpy(peer_name, "spy-"); strncat(peer_name, peer->name, AST_NAME_STRLEN - 4 - 1); ptr = strchr(peer_name, '/'); *ptr++ = '\0'; for (s = peer_name; s < ptr; s++) *s = tolower(*s); /* We have to unlock the peer channel here to avoid a deadlock. * So, when we need to dereference it again, we have to lock the * datastore and get the pointer from there to see if the channel * is still valid. */ ast_channel_unlock(peer); if (!ast_test_flag(flags, OPTION_QUIET)) { if (ast_fileexists(peer_name, NULL, NULL) != -1) { res = ast_streamfile(chan, peer_name, chan->language); if (!res) res = ast_waitstream(chan, ""); if (res) { chanspy_ds_free(peer_chanspy_ds); break; } } else res = ast_say_character_str(chan, peer_name, "", chan->language); if ((num = atoi(ptr))) ast_say_digits(chan, atoi(ptr), "", chan->language); } res = channel_spy(chan, peer_chanspy_ds, &volfactor, fd, flags); num_spyed_upon++; if (res == -1) { chanspy_ds_free(peer_chanspy_ds); break; } else if (res > 1 && spec) { struct ast_channel *next; snprintf(nameprefix, AST_NAME_STRLEN, "%s/%d", spec, res); if ((next = ast_get_channel_by_name_prefix_locked(nameprefix, strlen(nameprefix)))) { peer_chanspy_ds = chanspy_ds_free(peer_chanspy_ds); next_chanspy_ds = setup_chanspy_ds(next, &chanspy_ds); } else { /* stay on this channel, if it is still valid */ ast_mutex_lock(&peer_chanspy_ds->lock); if (peer_chanspy_ds->chan) { ast_channel_lock(peer_chanspy_ds->chan); next_chanspy_ds = peer_chanspy_ds; peer_chanspy_ds = NULL; } else { /* the channel is gone */ ast_mutex_unlock(&peer_chanspy_ds->lock); next_chanspy_ds = NULL; } } peer = NULL; } } if (res == -1 || ast_check_hangup(chan)) break; } ast_clear_flag(chan, AST_FLAG_SPYING); ast_channel_setoption(chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0); ast_mutex_lock(&chanspy_ds.lock); ast_mutex_unlock(&chanspy_ds.lock); ast_mutex_destroy(&chanspy_ds.lock); return res; }