コード例 #1
0
ファイル: app_chanspy.c プロジェクト: RoyalG41/Asterisk
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;
}
コード例 #2
0
/* 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);
}
コード例 #3
0
/* 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);
}
コード例 #4
0
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;
}
コード例 #5
0
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);
}
コード例 #6
0
ファイル: app_chanspy.c プロジェクト: pjalbrecht/asterisk
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;
}